aboutsummaryrefslogtreecommitdiffstats
path: root/net/8021q
diff options
context:
space:
mode:
authorJesse Gross <jesse@nicira.com>2010-10-20 09:56:05 -0400
committerDavid S. Miller <davem@davemloft.net>2010-10-21 04:26:53 -0400
commit65ac6a5fa658b90f1be700c55e7cd72e4611015d (patch)
tree7330c3234101c6d4c952f4abec9c8064df0e685a /net/8021q
parent7b9c60903714bf0a19d746b228864bad3497284e (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')
-rw-r--r--net/8021q/vlan.c64
-rw-r--r--net/8021q/vlan.h17
-rw-r--r--net/8021q/vlan_dev.c2
3 files changed, 11 insertions, 72 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
45int vlan_net_id __read_mostly; 45int vlan_net_id __read_mostly;
46 46
47/* Our listing of VLAN group(s) */
48static struct hlist_head vlan_group_hash[VLAN_GRP_HASH_SIZE];
49
50const char vlan_fullname[] = "802.1Q VLAN Support"; 47const char vlan_fullname[] = "802.1Q VLAN Support";
51const char vlan_version[] = DRV_VERSION; 48const char vlan_version[] = DRV_VERSION;
52static const char vlan_copyright[] = "Ben Greear <greearb@candelatech.com>"; 49static 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
62static 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) */
68static 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 */
86struct 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
96static void vlan_group_free(struct vlan_group *grp) 59static 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);
265out_free_group: 228out_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
747static void __exit vlan_cleanup_module(void) 709static 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 */
90struct 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 */
93int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, 76int 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