diff options
| -rw-r--r-- | include/linux/if_vlan.h | 19 | ||||
| -rw-r--r-- | include/linux/netdevice.h | 5 | ||||
| -rw-r--r-- | net/8021q/vlan.c | 64 | ||||
| -rw-r--r-- | net/8021q/vlan.h | 17 | ||||
| -rw-r--r-- | net/8021q/vlan_dev.c | 2 |
5 files changed, 34 insertions, 73 deletions
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index 494cce866564..4047781da727 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #ifdef __KERNEL__ | 16 | #ifdef __KERNEL__ |
| 17 | #include <linux/netdevice.h> | 17 | #include <linux/netdevice.h> |
| 18 | #include <linux/etherdevice.h> | 18 | #include <linux/etherdevice.h> |
| 19 | #include <linux/rtnetlink.h> | ||
| 19 | 20 | ||
| 20 | #define VLAN_HLEN 4 /* The additional bytes (on top of the Ethernet header) | 21 | #define VLAN_HLEN 4 /* The additional bytes (on top of the Ethernet header) |
| 21 | * that VLAN requires. | 22 | * that VLAN requires. |
| @@ -114,6 +115,18 @@ static inline void vlan_group_set_device(struct vlan_group *vg, | |||
| 114 | #define vlan_tx_tag_get(__skb) ((__skb)->vlan_tci & ~VLAN_TAG_PRESENT) | 115 | #define vlan_tx_tag_get(__skb) ((__skb)->vlan_tci & ~VLAN_TAG_PRESENT) |
| 115 | 116 | ||
| 116 | #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) | 117 | #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) |
| 118 | /* Must be invoked with rcu_read_lock or with RTNL. */ | ||
| 119 | static inline struct net_device *vlan_find_dev(struct net_device *real_dev, | ||
| 120 | u16 vlan_id) | ||
| 121 | { | ||
| 122 | struct vlan_group *grp = rcu_dereference_rtnl(real_dev->vlgrp); | ||
| 123 | |||
| 124 | if (grp) | ||
| 125 | return vlan_group_get_device(grp, vlan_id); | ||
| 126 | |||
| 127 | return NULL; | ||
| 128 | } | ||
| 129 | |||
| 117 | extern struct net_device *vlan_dev_real_dev(const struct net_device *dev); | 130 | extern struct net_device *vlan_dev_real_dev(const struct net_device *dev); |
| 118 | extern u16 vlan_dev_vlan_id(const struct net_device *dev); | 131 | extern u16 vlan_dev_vlan_id(const struct net_device *dev); |
| 119 | 132 | ||
| @@ -128,6 +141,12 @@ vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp, | |||
| 128 | unsigned int vlan_tci); | 141 | unsigned int vlan_tci); |
| 129 | 142 | ||
| 130 | #else | 143 | #else |
| 144 | static inline struct net_device *vlan_find_dev(struct net_device *real_dev, | ||
| 145 | u16 vlan_id) | ||
| 146 | { | ||
| 147 | return NULL; | ||
| 148 | } | ||
| 149 | |||
| 131 | static inline struct net_device *vlan_dev_real_dev(const struct net_device *dev) | 150 | static inline struct net_device *vlan_dev_real_dev(const struct net_device *dev) |
| 132 | { | 151 | { |
| 133 | BUG(); | 152 | BUG(); |
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 2861565a27d9..9c78312ce142 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
| @@ -942,7 +942,10 @@ struct net_device { | |||
| 942 | 942 | ||
| 943 | 943 | ||
| 944 | /* Protocol specific pointers */ | 944 | /* Protocol specific pointers */ |
| 945 | 945 | ||
| 946 | #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) | ||
| 947 | struct vlan_group *vlgrp; /* VLAN group */ | ||
| 948 | #endif | ||
| 946 | #ifdef CONFIG_NET_DSA | 949 | #ifdef CONFIG_NET_DSA |
| 947 | void *dsa_ptr; /* dsa specific data */ | 950 | void *dsa_ptr; /* dsa specific data */ |
| 948 | #endif | 951 | #endif |
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 54f22d820ef5..f862dccf6bb0 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c | |||
| @@ -44,9 +44,6 @@ | |||
| 44 | 44 | ||
| 45 | int vlan_net_id __read_mostly; | 45 | int vlan_net_id __read_mostly; |
| 46 | 46 | ||
| 47 | /* Our listing of VLAN group(s) */ | ||
| 48 | static struct hlist_head vlan_group_hash[VLAN_GRP_HASH_SIZE]; | ||
| 49 | |||
| 50 | const char vlan_fullname[] = "802.1Q VLAN Support"; | 47 | const char vlan_fullname[] = "802.1Q VLAN Support"; |
| 51 | const char vlan_version[] = DRV_VERSION; | 48 | const char vlan_version[] = DRV_VERSION; |
| 52 | static const char vlan_copyright[] = "Ben Greear <greearb@candelatech.com>"; | 49 | static const char vlan_copyright[] = "Ben Greear <greearb@candelatech.com>"; |
| @@ -59,40 +56,6 @@ static struct packet_type vlan_packet_type __read_mostly = { | |||
| 59 | 56 | ||
| 60 | /* End of global variables definitions. */ | 57 | /* End of global variables definitions. */ |
| 61 | 58 | ||
| 62 | static inline unsigned int vlan_grp_hashfn(unsigned int idx) | ||
| 63 | { | ||
| 64 | return ((idx >> VLAN_GRP_HASH_SHIFT) ^ idx) & VLAN_GRP_HASH_MASK; | ||
| 65 | } | ||
| 66 | |||
| 67 | /* Must be invoked with RCU read lock (no preempt) */ | ||
| 68 | static struct vlan_group *__vlan_find_group(struct net_device *real_dev) | ||
| 69 | { | ||
| 70 | struct vlan_group *grp; | ||
| 71 | struct hlist_node *n; | ||
| 72 | int hash = vlan_grp_hashfn(real_dev->ifindex); | ||
| 73 | |||
| 74 | hlist_for_each_entry_rcu(grp, n, &vlan_group_hash[hash], hlist) { | ||
| 75 | if (grp->real_dev == real_dev) | ||
| 76 | return grp; | ||
| 77 | } | ||
| 78 | |||
| 79 | return NULL; | ||
| 80 | } | ||
| 81 | |||
| 82 | /* Find the protocol handler. Assumes VID < VLAN_VID_MASK. | ||
| 83 | * | ||
| 84 | * Must be invoked with RCU read lock (no preempt) | ||
| 85 | */ | ||
| 86 | struct net_device *__find_vlan_dev(struct net_device *real_dev, u16 vlan_id) | ||
| 87 | { | ||
| 88 | struct vlan_group *grp = __vlan_find_group(real_dev); | ||
| 89 | |||
| 90 | if (grp) | ||
| 91 | return vlan_group_get_device(grp, vlan_id); | ||
| 92 | |||
| 93 | return NULL; | ||
| 94 | } | ||
| 95 | |||
| 96 | static void vlan_group_free(struct vlan_group *grp) | 59 | static void vlan_group_free(struct vlan_group *grp) |
| 97 | { | 60 | { |
| 98 | int i; | 61 | int i; |
| @@ -111,8 +74,6 @@ static struct vlan_group *vlan_group_alloc(struct net_device *real_dev) | |||
| 111 | return NULL; | 74 | return NULL; |
| 112 | 75 | ||
| 113 | grp->real_dev = real_dev; | 76 | grp->real_dev = real_dev; |
| 114 | hlist_add_head_rcu(&grp->hlist, | ||
| 115 | &vlan_group_hash[vlan_grp_hashfn(real_dev->ifindex)]); | ||
| 116 | return grp; | 77 | return grp; |
| 117 | } | 78 | } |
| 118 | 79 | ||
| @@ -151,7 +112,7 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head) | |||
| 151 | 112 | ||
| 152 | ASSERT_RTNL(); | 113 | ASSERT_RTNL(); |
| 153 | 114 | ||
| 154 | grp = __vlan_find_group(real_dev); | 115 | grp = real_dev->vlgrp; |
| 155 | BUG_ON(!grp); | 116 | BUG_ON(!grp); |
| 156 | 117 | ||
| 157 | /* Take it out of our own structures, but be sure to interlock with | 118 | /* Take it out of our own structures, but be sure to interlock with |
| @@ -173,11 +134,10 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head) | |||
| 173 | if (grp->nr_vlans == 0) { | 134 | if (grp->nr_vlans == 0) { |
| 174 | vlan_gvrp_uninit_applicant(real_dev); | 135 | vlan_gvrp_uninit_applicant(real_dev); |
| 175 | 136 | ||
| 137 | rcu_assign_pointer(real_dev->vlgrp, NULL); | ||
| 176 | if (real_dev->features & NETIF_F_HW_VLAN_RX) | 138 | if (real_dev->features & NETIF_F_HW_VLAN_RX) |
| 177 | ops->ndo_vlan_rx_register(real_dev, NULL); | 139 | ops->ndo_vlan_rx_register(real_dev, NULL); |
| 178 | 140 | ||
| 179 | hlist_del_rcu(&grp->hlist); | ||
| 180 | |||
| 181 | /* Free the group, after all cpu's are done. */ | 141 | /* Free the group, after all cpu's are done. */ |
| 182 | call_rcu(&grp->rcu, vlan_rcu_free); | 142 | call_rcu(&grp->rcu, vlan_rcu_free); |
| 183 | } | 143 | } |
| @@ -207,7 +167,7 @@ int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id) | |||
| 207 | return -EOPNOTSUPP; | 167 | return -EOPNOTSUPP; |
| 208 | } | 168 | } |
| 209 | 169 | ||
| 210 | if (__find_vlan_dev(real_dev, vlan_id) != NULL) | 170 | if (vlan_find_dev(real_dev, vlan_id) != NULL) |
| 211 | return -EEXIST; | 171 | return -EEXIST; |
| 212 | 172 | ||
| 213 | return 0; | 173 | return 0; |
| @@ -222,7 +182,7 @@ int register_vlan_dev(struct net_device *dev) | |||
| 222 | struct vlan_group *grp, *ngrp = NULL; | 182 | struct vlan_group *grp, *ngrp = NULL; |
| 223 | int err; | 183 | int err; |
| 224 | 184 | ||
| 225 | grp = __vlan_find_group(real_dev); | 185 | grp = real_dev->vlgrp; |
| 226 | if (!grp) { | 186 | if (!grp) { |
| 227 | ngrp = grp = vlan_group_alloc(real_dev); | 187 | ngrp = grp = vlan_group_alloc(real_dev); |
| 228 | if (!grp) | 188 | if (!grp) |
| @@ -252,8 +212,11 @@ int register_vlan_dev(struct net_device *dev) | |||
| 252 | vlan_group_set_device(grp, vlan_id, dev); | 212 | vlan_group_set_device(grp, vlan_id, dev); |
| 253 | grp->nr_vlans++; | 213 | grp->nr_vlans++; |
| 254 | 214 | ||
| 255 | if (ngrp && real_dev->features & NETIF_F_HW_VLAN_RX) | 215 | if (ngrp) { |
| 256 | ops->ndo_vlan_rx_register(real_dev, ngrp); | 216 | if (real_dev->features & NETIF_F_HW_VLAN_RX) |
| 217 | ops->ndo_vlan_rx_register(real_dev, ngrp); | ||
| 218 | rcu_assign_pointer(real_dev->vlgrp, ngrp); | ||
| 219 | } | ||
| 257 | if (real_dev->features & NETIF_F_HW_VLAN_FILTER) | 220 | if (real_dev->features & NETIF_F_HW_VLAN_FILTER) |
| 258 | ops->ndo_vlan_rx_add_vid(real_dev, vlan_id); | 221 | ops->ndo_vlan_rx_add_vid(real_dev, vlan_id); |
| 259 | 222 | ||
| @@ -264,7 +227,6 @@ out_uninit_applicant: | |||
| 264 | vlan_gvrp_uninit_applicant(real_dev); | 227 | vlan_gvrp_uninit_applicant(real_dev); |
| 265 | out_free_group: | 228 | out_free_group: |
| 266 | if (ngrp) { | 229 | if (ngrp) { |
| 267 | hlist_del_rcu(&ngrp->hlist); | ||
| 268 | /* Free the group, after all cpu's are done. */ | 230 | /* Free the group, after all cpu's are done. */ |
| 269 | call_rcu(&ngrp->rcu, vlan_rcu_free); | 231 | call_rcu(&ngrp->rcu, vlan_rcu_free); |
| 270 | } | 232 | } |
| @@ -428,7 +390,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
| 428 | dev->netdev_ops->ndo_vlan_rx_add_vid(dev, 0); | 390 | dev->netdev_ops->ndo_vlan_rx_add_vid(dev, 0); |
| 429 | } | 391 | } |
| 430 | 392 | ||
| 431 | grp = __vlan_find_group(dev); | 393 | grp = dev->vlgrp; |
| 432 | if (!grp) | 394 | if (!grp) |
| 433 | goto out; | 395 | goto out; |
| 434 | 396 | ||
| @@ -746,8 +708,6 @@ err0: | |||
| 746 | 708 | ||
| 747 | static void __exit vlan_cleanup_module(void) | 709 | static void __exit vlan_cleanup_module(void) |
| 748 | { | 710 | { |
| 749 | unsigned int i; | ||
| 750 | |||
| 751 | vlan_ioctl_set(NULL); | 711 | vlan_ioctl_set(NULL); |
| 752 | vlan_netlink_fini(); | 712 | vlan_netlink_fini(); |
| 753 | 713 | ||
| @@ -755,10 +715,6 @@ static void __exit vlan_cleanup_module(void) | |||
| 755 | 715 | ||
| 756 | dev_remove_pack(&vlan_packet_type); | 716 | dev_remove_pack(&vlan_packet_type); |
| 757 | 717 | ||
| 758 | /* This table must be empty if there are no module references left. */ | ||
| 759 | for (i = 0; i < VLAN_GRP_HASH_SIZE; i++) | ||
| 760 | BUG_ON(!hlist_empty(&vlan_group_hash[i])); | ||
| 761 | |||
| 762 | unregister_pernet_subsys(&vlan_net_ops); | 718 | unregister_pernet_subsys(&vlan_net_ops); |
| 763 | rcu_barrier(); /* Wait for completion of call_rcu()'s */ | 719 | rcu_barrier(); /* Wait for completion of call_rcu()'s */ |
| 764 | 720 | ||
diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h index 8d9503ad01da..db01b3181fdc 100644 --- a/net/8021q/vlan.h +++ b/net/8021q/vlan.h | |||
| @@ -72,23 +72,6 @@ static inline struct vlan_dev_info *vlan_dev_info(const struct net_device *dev) | |||
| 72 | return netdev_priv(dev); | 72 | return netdev_priv(dev); |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | #define VLAN_GRP_HASH_SHIFT 5 | ||
| 76 | #define VLAN_GRP_HASH_SIZE (1 << VLAN_GRP_HASH_SHIFT) | ||
| 77 | #define VLAN_GRP_HASH_MASK (VLAN_GRP_HASH_SIZE - 1) | ||
| 78 | |||
| 79 | /* Find a VLAN device by the MAC address of its Ethernet device, and | ||
| 80 | * it's VLAN ID. The default configuration is to have VLAN's scope | ||
| 81 | * to be box-wide, so the MAC will be ignored. The mac will only be | ||
| 82 | * looked at if we are configured to have a separate set of VLANs per | ||
| 83 | * each MAC addressable interface. Note that this latter option does | ||
| 84 | * NOT follow the spec for VLANs, but may be useful for doing very | ||
| 85 | * large quantities of VLAN MUX/DEMUX onto FrameRelay or ATM PVCs. | ||
| 86 | * | ||
| 87 | * Must be invoked with rcu_read_lock (ie preempt disabled) | ||
| 88 | * or with RTNL. | ||
| 89 | */ | ||
| 90 | struct net_device *__find_vlan_dev(struct net_device *real_dev, u16 vlan_id); | ||
| 91 | |||
| 92 | /* found in vlan_dev.c */ | 75 | /* found in vlan_dev.c */ |
| 93 | int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, | 76 | int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, |
| 94 | struct packet_type *ptype, struct net_device *orig_dev); | 77 | struct packet_type *ptype, struct net_device *orig_dev); |
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index f54251edd40d..14e3d1fa07a0 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c | |||
| @@ -158,7 +158,7 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, | |||
| 158 | vlan_id = vlan_tci & VLAN_VID_MASK; | 158 | vlan_id = vlan_tci & VLAN_VID_MASK; |
| 159 | 159 | ||
| 160 | rcu_read_lock(); | 160 | rcu_read_lock(); |
| 161 | vlan_dev = __find_vlan_dev(dev, vlan_id); | 161 | vlan_dev = vlan_find_dev(dev, vlan_id); |
| 162 | 162 | ||
| 163 | /* If the VLAN device is defined, we use it. | 163 | /* If the VLAN device is defined, we use it. |
| 164 | * If not, and the VID is 0, it is a 802.1p packet (not | 164 | * If not, and the VID is 0, it is a 802.1p packet (not |
