diff options
author | Jesse Gross <jesse@nicira.com> | 2010-10-20 09:56:05 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-10-21 04:26:53 -0400 |
commit | 65ac6a5fa658b90f1be700c55e7cd72e4611015d (patch) | |
tree | 7330c3234101c6d4c952f4abec9c8064df0e685a /net/8021q/vlan.c | |
parent | 7b9c60903714bf0a19d746b228864bad3497284e (diff) |
vlan: Avoid hash table lookup to find group.
A struct net_device always maps to zero or one vlan groups and we
always know the device when we are looking up a group. We currently
do a hash table lookup on the device to find the group but it is
much simpler to just store a pointer.
Signed-off-by: Jesse Gross <jesse@nicira.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/8021q/vlan.c')
-rw-r--r-- | net/8021q/vlan.c | 64 |
1 files changed, 10 insertions, 54 deletions
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 | ||