Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

vlan: add 802.1q netpoll support

Add netpoll support to 802.1q vlan devices. Based on the netpoll support
in the bridging code. Tested on a forced_eth device with netconsole.

Signed-off-by: Benjamin LaHaise <bcrl@kvack.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Benjamin LaHaise and committed by
David S. Miller
6d4cdf47 8af2a218

+64
+5
net/8021q/vlan.h
··· 41 41 u32 tx_dropped; 42 42 }; 43 43 44 + struct netpoll; 45 + 44 46 /** 45 47 * struct vlan_dev_priv - VLAN private device data 46 48 * @nr_ingress_mappings: number of ingress priority mappings ··· 70 68 71 69 struct proc_dir_entry *dent; 72 70 struct vlan_pcpu_stats __percpu *vlan_pcpu_stats; 71 + #ifdef CONFIG_NET_POLL_CONTROLLER 72 + struct netpoll *netpoll; 73 + #endif 73 74 }; 74 75 75 76 static inline struct vlan_dev_priv *vlan_dev_priv(const struct net_device *dev)
+59
net/8021q/vlan_dev.c
··· 33 33 #include "vlan.h" 34 34 #include "vlanproc.h" 35 35 #include <linux/if_vlan.h> 36 + #include <linux/netpoll.h> 36 37 37 38 /* 38 39 * Rebuild the Ethernet MAC header. This is called after an ARP ··· 159 158 160 159 skb_set_dev(skb, vlan_dev_priv(dev)->real_dev); 161 160 len = skb->len; 161 + if (netpoll_tx_running(dev)) 162 + return skb->dev->netdev_ops->ndo_start_xmit(skb, skb->dev); 162 163 ret = dev_queue_xmit(skb); 163 164 164 165 if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) { ··· 663 660 return stats; 664 661 } 665 662 663 + #ifdef CONFIG_NET_POLL_CONTROLLER 664 + void vlan_dev_poll_controller(struct net_device *dev) 665 + { 666 + return; 667 + } 668 + 669 + int vlan_dev_netpoll_setup(struct net_device *dev, struct netpoll_info *npinfo) 670 + { 671 + struct vlan_dev_priv *info = vlan_dev_priv(dev); 672 + struct net_device *real_dev = info->real_dev; 673 + struct netpoll *netpoll; 674 + int err = 0; 675 + 676 + netpoll = kzalloc(sizeof(*netpoll), GFP_KERNEL); 677 + err = -ENOMEM; 678 + if (!netpoll) 679 + goto out; 680 + 681 + netpoll->dev = real_dev; 682 + strlcpy(netpoll->dev_name, real_dev->name, IFNAMSIZ); 683 + 684 + err = __netpoll_setup(netpoll); 685 + if (err) { 686 + kfree(netpoll); 687 + goto out; 688 + } 689 + 690 + info->netpoll = netpoll; 691 + 692 + out: 693 + return err; 694 + } 695 + 696 + void vlan_dev_netpoll_cleanup(struct net_device *dev) 697 + { 698 + struct vlan_dev_priv *info = vlan_dev_priv(dev); 699 + struct netpoll *netpoll = info->netpoll; 700 + 701 + if (!netpoll) 702 + return; 703 + 704 + info->netpoll = NULL; 705 + 706 + /* Wait for transmitting packets to finish before freeing. */ 707 + synchronize_rcu_bh(); 708 + 709 + __netpoll_cleanup(netpoll); 710 + kfree(netpoll); 711 + } 712 + #endif /* CONFIG_NET_POLL_CONTROLLER */ 713 + 666 714 static const struct ethtool_ops vlan_ethtool_ops = { 667 715 .get_settings = vlan_ethtool_get_settings, 668 716 .get_drvinfo = vlan_ethtool_get_drvinfo, ··· 741 687 .ndo_fcoe_disable = vlan_dev_fcoe_disable, 742 688 .ndo_fcoe_get_wwn = vlan_dev_fcoe_get_wwn, 743 689 .ndo_fcoe_ddp_target = vlan_dev_fcoe_ddp_target, 690 + #endif 691 + #ifdef CONFIG_NET_POLL_CONTROLLER 692 + .ndo_poll_controller = vlan_dev_poll_controller, 693 + .ndo_netpoll_setup = vlan_dev_netpoll_setup, 694 + .ndo_netpoll_cleanup = vlan_dev_netpoll_cleanup, 744 695 #endif 745 696 .ndo_fix_features = vlan_dev_fix_features, 746 697 };