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>
This commit is contained in:
parent
7b9c609037
commit
65ac6a5fa6
|
@ -16,6 +16,7 @@
|
|||
#ifdef __KERNEL__
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
#define VLAN_HLEN 4 /* The additional bytes (on top of the Ethernet header)
|
||||
* that VLAN requires.
|
||||
|
@ -114,6 +115,18 @@ static inline void vlan_group_set_device(struct vlan_group *vg,
|
|||
#define vlan_tx_tag_get(__skb) ((__skb)->vlan_tci & ~VLAN_TAG_PRESENT)
|
||||
|
||||
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
|
||||
/* Must be invoked with rcu_read_lock or with RTNL. */
|
||||
static inline struct net_device *vlan_find_dev(struct net_device *real_dev,
|
||||
u16 vlan_id)
|
||||
{
|
||||
struct vlan_group *grp = rcu_dereference_rtnl(real_dev->vlgrp);
|
||||
|
||||
if (grp)
|
||||
return vlan_group_get_device(grp, vlan_id);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
extern struct net_device *vlan_dev_real_dev(const struct net_device *dev);
|
||||
extern u16 vlan_dev_vlan_id(const struct net_device *dev);
|
||||
|
||||
|
@ -128,6 +141,12 @@ vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp,
|
|||
unsigned int vlan_tci);
|
||||
|
||||
#else
|
||||
static inline struct net_device *vlan_find_dev(struct net_device *real_dev,
|
||||
u16 vlan_id)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct net_device *vlan_dev_real_dev(const struct net_device *dev)
|
||||
{
|
||||
BUG();
|
||||
|
|
|
@ -942,7 +942,10 @@ struct net_device {
|
|||
|
||||
|
||||
/* Protocol specific pointers */
|
||||
|
||||
|
||||
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
|
||||
struct vlan_group *vlgrp; /* VLAN group */
|
||||
#endif
|
||||
#ifdef CONFIG_NET_DSA
|
||||
void *dsa_ptr; /* dsa specific data */
|
||||
#endif
|
||||
|
|
|
@ -44,9 +44,6 @@
|
|||
|
||||
int vlan_net_id __read_mostly;
|
||||
|
||||
/* Our listing of VLAN group(s) */
|
||||
static struct hlist_head vlan_group_hash[VLAN_GRP_HASH_SIZE];
|
||||
|
||||
const char vlan_fullname[] = "802.1Q VLAN Support";
|
||||
const char vlan_version[] = DRV_VERSION;
|
||||
static const char vlan_copyright[] = "Ben Greear <greearb@candelatech.com>";
|
||||
|
@ -59,40 +56,6 @@ static struct packet_type vlan_packet_type __read_mostly = {
|
|||
|
||||
/* End of global variables definitions. */
|
||||
|
||||
static inline unsigned int vlan_grp_hashfn(unsigned int idx)
|
||||
{
|
||||
return ((idx >> VLAN_GRP_HASH_SHIFT) ^ idx) & VLAN_GRP_HASH_MASK;
|
||||
}
|
||||
|
||||
/* Must be invoked with RCU read lock (no preempt) */
|
||||
static struct vlan_group *__vlan_find_group(struct net_device *real_dev)
|
||||
{
|
||||
struct vlan_group *grp;
|
||||
struct hlist_node *n;
|
||||
int hash = vlan_grp_hashfn(real_dev->ifindex);
|
||||
|
||||
hlist_for_each_entry_rcu(grp, n, &vlan_group_hash[hash], hlist) {
|
||||
if (grp->real_dev == real_dev)
|
||||
return grp;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Find the protocol handler. Assumes VID < VLAN_VID_MASK.
|
||||
*
|
||||
* Must be invoked with RCU read lock (no preempt)
|
||||
*/
|
||||
struct net_device *__find_vlan_dev(struct net_device *real_dev, u16 vlan_id)
|
||||
{
|
||||
struct vlan_group *grp = __vlan_find_group(real_dev);
|
||||
|
||||
if (grp)
|
||||
return vlan_group_get_device(grp, vlan_id);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void vlan_group_free(struct vlan_group *grp)
|
||||
{
|
||||
int i;
|
||||
|
@ -111,8 +74,6 @@ static struct vlan_group *vlan_group_alloc(struct net_device *real_dev)
|
|||
return NULL;
|
||||
|
||||
grp->real_dev = real_dev;
|
||||
hlist_add_head_rcu(&grp->hlist,
|
||||
&vlan_group_hash[vlan_grp_hashfn(real_dev->ifindex)]);
|
||||
return grp;
|
||||
}
|
||||
|
||||
|
@ -151,7 +112,7 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
|
|||
|
||||
ASSERT_RTNL();
|
||||
|
||||
grp = __vlan_find_group(real_dev);
|
||||
grp = real_dev->vlgrp;
|
||||
BUG_ON(!grp);
|
||||
|
||||
/* 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)
|
|||
if (grp->nr_vlans == 0) {
|
||||
vlan_gvrp_uninit_applicant(real_dev);
|
||||
|
||||
rcu_assign_pointer(real_dev->vlgrp, NULL);
|
||||
if (real_dev->features & NETIF_F_HW_VLAN_RX)
|
||||
ops->ndo_vlan_rx_register(real_dev, NULL);
|
||||
|
||||
hlist_del_rcu(&grp->hlist);
|
||||
|
||||
/* Free the group, after all cpu's are done. */
|
||||
call_rcu(&grp->rcu, vlan_rcu_free);
|
||||
}
|
||||
|
@ -207,7 +167,7 @@ int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id)
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (__find_vlan_dev(real_dev, vlan_id) != NULL)
|
||||
if (vlan_find_dev(real_dev, vlan_id) != NULL)
|
||||
return -EEXIST;
|
||||
|
||||
return 0;
|
||||
|
@ -222,7 +182,7 @@ int register_vlan_dev(struct net_device *dev)
|
|||
struct vlan_group *grp, *ngrp = NULL;
|
||||
int err;
|
||||
|
||||
grp = __vlan_find_group(real_dev);
|
||||
grp = real_dev->vlgrp;
|
||||
if (!grp) {
|
||||
ngrp = grp = vlan_group_alloc(real_dev);
|
||||
if (!grp)
|
||||
|
@ -252,8 +212,11 @@ int register_vlan_dev(struct net_device *dev)
|
|||
vlan_group_set_device(grp, vlan_id, dev);
|
||||
grp->nr_vlans++;
|
||||
|
||||
if (ngrp && real_dev->features & NETIF_F_HW_VLAN_RX)
|
||||
ops->ndo_vlan_rx_register(real_dev, ngrp);
|
||||
if (ngrp) {
|
||||
if (real_dev->features & NETIF_F_HW_VLAN_RX)
|
||||
ops->ndo_vlan_rx_register(real_dev, ngrp);
|
||||
rcu_assign_pointer(real_dev->vlgrp, ngrp);
|
||||
}
|
||||
if (real_dev->features & NETIF_F_HW_VLAN_FILTER)
|
||||
ops->ndo_vlan_rx_add_vid(real_dev, vlan_id);
|
||||
|
||||
|
@ -264,7 +227,6 @@ out_uninit_applicant:
|
|||
vlan_gvrp_uninit_applicant(real_dev);
|
||||
out_free_group:
|
||||
if (ngrp) {
|
||||
hlist_del_rcu(&ngrp->hlist);
|
||||
/* Free the group, after all cpu's are done. */
|
||||
call_rcu(&ngrp->rcu, vlan_rcu_free);
|
||||
}
|
||||
|
@ -428,7 +390,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
|
|||
dev->netdev_ops->ndo_vlan_rx_add_vid(dev, 0);
|
||||
}
|
||||
|
||||
grp = __vlan_find_group(dev);
|
||||
grp = dev->vlgrp;
|
||||
if (!grp)
|
||||
goto out;
|
||||
|
||||
|
@ -746,8 +708,6 @@ err0:
|
|||
|
||||
static void __exit vlan_cleanup_module(void)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
vlan_ioctl_set(NULL);
|
||||
vlan_netlink_fini();
|
||||
|
||||
|
@ -755,10 +715,6 @@ static void __exit vlan_cleanup_module(void)
|
|||
|
||||
dev_remove_pack(&vlan_packet_type);
|
||||
|
||||
/* This table must be empty if there are no module references left. */
|
||||
for (i = 0; i < VLAN_GRP_HASH_SIZE; i++)
|
||||
BUG_ON(!hlist_empty(&vlan_group_hash[i]));
|
||||
|
||||
unregister_pernet_subsys(&vlan_net_ops);
|
||||
rcu_barrier(); /* Wait for completion of call_rcu()'s */
|
||||
|
||||
|
|
|
@ -72,23 +72,6 @@ static inline struct vlan_dev_info *vlan_dev_info(const struct net_device *dev)
|
|||
return netdev_priv(dev);
|
||||
}
|
||||
|
||||
#define VLAN_GRP_HASH_SHIFT 5
|
||||
#define VLAN_GRP_HASH_SIZE (1 << VLAN_GRP_HASH_SHIFT)
|
||||
#define VLAN_GRP_HASH_MASK (VLAN_GRP_HASH_SIZE - 1)
|
||||
|
||||
/* Find a VLAN device by the MAC address of its Ethernet device, and
|
||||
* it's VLAN ID. The default configuration is to have VLAN's scope
|
||||
* to be box-wide, so the MAC will be ignored. The mac will only be
|
||||
* looked at if we are configured to have a separate set of VLANs per
|
||||
* each MAC addressable interface. Note that this latter option does
|
||||
* NOT follow the spec for VLANs, but may be useful for doing very
|
||||
* large quantities of VLAN MUX/DEMUX onto FrameRelay or ATM PVCs.
|
||||
*
|
||||
* Must be invoked with rcu_read_lock (ie preempt disabled)
|
||||
* or with RTNL.
|
||||
*/
|
||||
struct net_device *__find_vlan_dev(struct net_device *real_dev, u16 vlan_id);
|
||||
|
||||
/* found in vlan_dev.c */
|
||||
int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
|
||||
struct packet_type *ptype, struct net_device *orig_dev);
|
||||
|
|
|
@ -158,7 +158,7 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
|
|||
vlan_id = vlan_tci & VLAN_VID_MASK;
|
||||
|
||||
rcu_read_lock();
|
||||
vlan_dev = __find_vlan_dev(dev, vlan_id);
|
||||
vlan_dev = vlan_find_dev(dev, vlan_id);
|
||||
|
||||
/* If the VLAN device is defined, we use it.
|
||||
* If not, and the VID is 0, it is a 802.1p packet (not
|
||||
|
|
Loading…
Reference in New Issue