diff options
Diffstat (limited to 'net/8021q')
-rw-r--r-- | net/8021q/vlan.c | 18 | ||||
-rw-r--r-- | net/8021q/vlan.h | 105 | ||||
-rw-r--r-- | net/8021q/vlan_dev.c | 51 |
3 files changed, 51 insertions, 123 deletions
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 61fc573f1142..b3d17d1c49c3 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -98,14 +98,14 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head) vlan_gvrp_request_leave(dev); vlan_group_set_device(grp, vlan->vlan_proto, vlan_id, NULL); + + netdev_upper_dev_unlink(real_dev, dev); /* Because unregister_netdevice_queue() makes sure at least one rcu * grace period is respected before device freeing, * we dont need to call synchronize_net() here. */ unregister_netdevice_queue(dev, head); - netdev_upper_dev_unlink(real_dev, dev); - if (grp->nr_vlan_devs == 0) { vlan_mvrp_uninit_applicant(real_dev); vlan_gvrp_uninit_applicant(real_dev); @@ -169,13 +169,13 @@ int register_vlan_dev(struct net_device *dev) if (err < 0) goto out_uninit_mvrp; - err = netdev_upper_dev_link(real_dev, dev); - if (err) - goto out_uninit_mvrp; - err = register_netdevice(dev); if (err < 0) - goto out_upper_dev_unlink; + goto out_uninit_mvrp; + + err = netdev_upper_dev_link(real_dev, dev); + if (err) + goto out_unregister_netdev; /* Account for reference in struct vlan_dev_priv */ dev_hold(real_dev); @@ -191,8 +191,8 @@ int register_vlan_dev(struct net_device *dev) return 0; -out_upper_dev_unlink: - netdev_upper_dev_unlink(real_dev, dev); +out_unregister_netdev: + unregister_netdevice(dev); out_uninit_mvrp: if (grp->nr_vlan_devs == 0) vlan_mvrp_uninit_applicant(real_dev); diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h index ba5983f34c42..5704ed9c3a23 100644 --- a/net/8021q/vlan.h +++ b/net/8021q/vlan.h @@ -5,83 +5,6 @@ #include <linux/u64_stats_sync.h> #include <linux/list.h> - -/** - * struct vlan_priority_tci_mapping - vlan egress priority mappings - * @priority: skb priority - * @vlan_qos: vlan priority: (skb->priority << 13) & 0xE000 - * @next: pointer to next struct - */ -struct vlan_priority_tci_mapping { - u32 priority; - u16 vlan_qos; - struct vlan_priority_tci_mapping *next; -}; - - -/** - * struct vlan_pcpu_stats - VLAN percpu rx/tx stats - * @rx_packets: number of received packets - * @rx_bytes: number of received bytes - * @rx_multicast: number of received multicast packets - * @tx_packets: number of transmitted packets - * @tx_bytes: number of transmitted bytes - * @syncp: synchronization point for 64bit counters - * @rx_errors: number of rx errors - * @tx_dropped: number of tx drops - */ -struct vlan_pcpu_stats { - u64 rx_packets; - u64 rx_bytes; - u64 rx_multicast; - u64 tx_packets; - u64 tx_bytes; - struct u64_stats_sync syncp; - u32 rx_errors; - u32 tx_dropped; -}; - -struct netpoll; - -/** - * struct vlan_dev_priv - VLAN private device data - * @nr_ingress_mappings: number of ingress priority mappings - * @ingress_priority_map: ingress priority mappings - * @nr_egress_mappings: number of egress priority mappings - * @egress_priority_map: hash of egress priority mappings - * @vlan_proto: VLAN encapsulation protocol - * @vlan_id: VLAN identifier - * @flags: device flags - * @real_dev: underlying netdevice - * @real_dev_addr: address of underlying netdevice - * @dent: proc dir entry - * @vlan_pcpu_stats: ptr to percpu rx stats - */ -struct vlan_dev_priv { - unsigned int nr_ingress_mappings; - u32 ingress_priority_map[8]; - unsigned int nr_egress_mappings; - struct vlan_priority_tci_mapping *egress_priority_map[16]; - - __be16 vlan_proto; - u16 vlan_id; - u16 flags; - - struct net_device *real_dev; - unsigned char real_dev_addr[ETH_ALEN]; - - struct proc_dir_entry *dent; - struct vlan_pcpu_stats __percpu *vlan_pcpu_stats; -#ifdef CONFIG_NET_POLL_CONTROLLER - struct netpoll *netpoll; -#endif -}; - -static inline struct vlan_dev_priv *vlan_dev_priv(const struct net_device *dev) -{ - return netdev_priv(dev); -} - /* if this changes, algorithm will have to be reworked because this * depends on completely exhausting the VLAN identifier space. Thus * it gives constant time look-up, but in many cases it wastes memory. @@ -196,12 +119,12 @@ static inline u32 vlan_get_ingress_priority(struct net_device *dev, } #ifdef CONFIG_VLAN_8021Q_GVRP -extern int vlan_gvrp_request_join(const struct net_device *dev); -extern void vlan_gvrp_request_leave(const struct net_device *dev); -extern int vlan_gvrp_init_applicant(struct net_device *dev); -extern void vlan_gvrp_uninit_applicant(struct net_device *dev); -extern int vlan_gvrp_init(void); -extern void vlan_gvrp_uninit(void); +int vlan_gvrp_request_join(const struct net_device *dev); +void vlan_gvrp_request_leave(const struct net_device *dev); +int vlan_gvrp_init_applicant(struct net_device *dev); +void vlan_gvrp_uninit_applicant(struct net_device *dev); +int vlan_gvrp_init(void); +void vlan_gvrp_uninit(void); #else static inline int vlan_gvrp_request_join(const struct net_device *dev) { return 0; } static inline void vlan_gvrp_request_leave(const struct net_device *dev) {} @@ -212,12 +135,12 @@ static inline void vlan_gvrp_uninit(void) {} #endif #ifdef CONFIG_VLAN_8021Q_MVRP -extern int vlan_mvrp_request_join(const struct net_device *dev); -extern void vlan_mvrp_request_leave(const struct net_device *dev); -extern int vlan_mvrp_init_applicant(struct net_device *dev); -extern void vlan_mvrp_uninit_applicant(struct net_device *dev); -extern int vlan_mvrp_init(void); -extern void vlan_mvrp_uninit(void); +int vlan_mvrp_request_join(const struct net_device *dev); +void vlan_mvrp_request_leave(const struct net_device *dev); +int vlan_mvrp_init_applicant(struct net_device *dev); +void vlan_mvrp_uninit_applicant(struct net_device *dev); +int vlan_mvrp_init(void); +void vlan_mvrp_uninit(void); #else static inline int vlan_mvrp_request_join(const struct net_device *dev) { return 0; } static inline void vlan_mvrp_request_leave(const struct net_device *dev) {} @@ -229,8 +152,8 @@ static inline void vlan_mvrp_uninit(void) {} extern const char vlan_fullname[]; extern const char vlan_version[]; -extern int vlan_netlink_init(void); -extern void vlan_netlink_fini(void); +int vlan_netlink_init(void); +void vlan_netlink_fini(void); extern struct rtnl_link_ops vlan_link_ops; diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 09bf1c38805b..47c908f1f626 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -68,25 +68,6 @@ static int vlan_dev_rebuild_header(struct sk_buff *skb) return 0; } -static inline u16 -vlan_dev_get_egress_qos_mask(struct net_device *dev, struct sk_buff *skb) -{ - struct vlan_priority_tci_mapping *mp; - - smp_rmb(); /* coupled with smp_wmb() in vlan_dev_set_egress_priority() */ - - mp = vlan_dev_priv(dev)->egress_priority_map[(skb->priority & 0xF)]; - while (mp) { - if (mp->priority == skb->priority) { - return mp->vlan_qos; /* This should already be shifted - * to mask correctly with the - * VLAN's TCI */ - } - mp = mp->next; - } - return 0; -} - /* * Create the VLAN header for an arbitrary protocol layer * @@ -111,7 +92,7 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev, vhdr = (struct vlan_hdr *) skb_push(skb, VLAN_HLEN); vlan_tci = vlan->vlan_id; - vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb); + vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb->priority); vhdr->h_vlan_TCI = htons(vlan_tci); /* @@ -168,7 +149,7 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb, vlan->flags & VLAN_FLAG_REORDER_HDR) { u16 vlan_tci; vlan_tci = vlan->vlan_id; - vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb); + vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb->priority); skb = __vlan_hwaccel_put_tag(skb, vlan->vlan_proto, vlan_tci); } @@ -549,6 +530,23 @@ static const struct header_ops vlan_header_ops = { .parse = eth_header_parse, }; +static int vlan_passthru_hard_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, + const void *daddr, const void *saddr, + unsigned int len) +{ + struct vlan_dev_priv *vlan = vlan_dev_priv(dev); + struct net_device *real_dev = vlan->real_dev; + + return dev_hard_header(skb, real_dev, type, daddr, saddr, len); +} + +static const struct header_ops vlan_passthru_header_ops = { + .create = vlan_passthru_hard_header, + .rebuild = dev_rebuild_header, + .parse = eth_header_parse, +}; + static struct device_type vlan_type = { .name = "vlan", }; @@ -558,7 +556,7 @@ static const struct net_device_ops vlan_netdev_ops; static int vlan_dev_init(struct net_device *dev) { struct net_device *real_dev = vlan_dev_priv(dev)->real_dev; - int subclass = 0; + int subclass = 0, i; netif_carrier_off(dev); @@ -592,7 +590,7 @@ static int vlan_dev_init(struct net_device *dev) dev->needed_headroom = real_dev->needed_headroom; if (real_dev->features & NETIF_F_HW_VLAN_CTAG_TX) { - dev->header_ops = real_dev->header_ops; + dev->header_ops = &vlan_passthru_header_ops; dev->hard_header_len = real_dev->hard_header_len; } else { dev->header_ops = &vlan_header_ops; @@ -612,6 +610,13 @@ static int vlan_dev_init(struct net_device *dev) if (!vlan_dev_priv(dev)->vlan_pcpu_stats) return -ENOMEM; + for_each_possible_cpu(i) { + struct vlan_pcpu_stats *vlan_stat; + vlan_stat = per_cpu_ptr(vlan_dev_priv(dev)->vlan_pcpu_stats, i); + u64_stats_init(&vlan_stat->syncp); + } + + return 0; } |