diff options
author | Dmitry Kozlov <xeb@mail.ru> | 2014-06-27 23:24:28 +0400 |
---|---|---|
committer | Dmitry Kozlov <xeb@mail.ru> | 2014-06-27 23:24:28 +0400 |
commit | d2b65bb7c8f0e6689682daadd47770c5c40cd85d (patch) | |
tree | 9a3126c1db2b44385a0af717698515d3f7c4b0b2 /drivers/ipoe | |
parent | e2ca2a98a2708d8d03dd243d4819469c711a5d91 (diff) | |
download | accel-ppp-d2b65bb7c8f0e6689682daadd47770c5c40cd85d.tar.gz accel-ppp-d2b65bb7c8f0e6689682daadd47770c5c40cd85d.zip |
ipoe: improved vlan monitor
Previous version used linear list of vlan monitor enabled interfaces,
this caused huge overhead in packet receive path because for each
received packet it performed search on linear list to check if vlan monitor
is enabled on input device.
Current version binds internal structure to net_device->ml_priv so search is not performed more.
Diffstat (limited to 'drivers/ipoe')
-rw-r--r-- | drivers/ipoe/ipoe.c | 80 |
1 files changed, 51 insertions, 29 deletions
diff --git a/drivers/ipoe/ipoe.c b/drivers/ipoe/ipoe.c index 4a1a798b..eb8f8de1 100644 --- a/drivers/ipoe/ipoe.c +++ b/drivers/ipoe/ipoe.c @@ -38,6 +38,7 @@ #define HASH_BITS 0xff #define IPOE_MAGIC 0x55aa +#define IPOE_MAGIC2 0x67f8bc32 #define IPOE_QUEUE_LEN 100 #define IPOE_RATE_U 3000 //3s @@ -102,10 +103,11 @@ struct ipoe_entry_u { }; struct vlan_dev { + unsigned int magic; + int ifindex; struct rcu_head rcu_head; struct list_head entry; - int ifindex; spinlock_t lock; unsigned long vid[4096/8/sizeof(long)]; }; @@ -855,22 +857,19 @@ static int vlan_pt_recv(struct sk_buff *skb, struct net_device *dev, struct pack struct vlan_notify *n; int vid; + if (!dev->ml_priv) + goto out; + + d = dev->ml_priv; + if (d->magic != IPOE_MAGIC2 || d->ifindex != dev->ifindex) + goto out; + if (!vlan_tx_tag_present(skb)) goto out; vid = skb->vlan_tci & VLAN_VID_MASK; //pr_info("vid %i\n", vid); - rcu_read_lock(); - list_for_each_entry_rcu(d, &vlan_devices, entry) { - if (d->ifindex == dev->ifindex) - goto found; - } - rcu_read_unlock(); - goto out; - -found: - //pr_info("found %i\n", d->ifindex); if (d->vid[vid / (8*sizeof(long))] & (1lu << (vid % (8*sizeof(long))))) vid = -1; else { @@ -1629,15 +1628,23 @@ static int ipoe_nl_cmd_add_vlan_mon(struct sk_buff *skb, struct genl_info *info) if (!dev) return -ENODEV; + if (dev->ml_priv) { + dev_put(dev); + return -EBUSY; + } + d = kzalloc(sizeof(*d), GFP_KERNEL); if (!d) { dev_put(dev); return -ENOMEM; } + d->magic = IPOE_MAGIC2; d->ifindex = ifindex; spin_lock_init(&d->lock); + dev->ml_priv = d; + if (info->attrs[IPOE_ATTR_VLAN_MASK]) { memcpy(d->vid, nla_data(info->attrs[IPOE_ATTR_VLAN_MASK]), min((int)nla_len(info->attrs[IPOE_ATTR_VLAN_MASK]), (int)sizeof(d->vid))); @@ -1691,23 +1698,23 @@ static int ipoe_nl_cmd_add_vlan_mon_vid(struct sk_buff *skb, struct genl_info *i if (!dev) return -ENODEV; - down(&ipoe_wlock); - list_for_each_entry(d, &vlan_devices, entry) { - if (d->ifindex == ifindex) { - spin_lock_irqsave(&d->lock, flags); - d->vid[vid / (8*sizeof(long))] &= ~(1lu << (vid % (8*sizeof(long)))); - spin_unlock_irqrestore(&d->lock, flags); + if (!dev->ml_priv) { + dev_put(dev); + return -EINVAL; + } + + d = dev->ml_priv; + + spin_lock_irqsave(&d->lock, flags); + d->vid[vid / (8*sizeof(long))] &= ~(1lu << (vid % (8*sizeof(long)))); + spin_unlock_irqrestore(&d->lock, flags); #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) - if (dev->features & NETIF_F_HW_VLAN_FILTER) - dev->netdev_ops->ndo_vlan_rx_add_vid(dev, vid); + if (dev->features & NETIF_F_HW_VLAN_FILTER) + dev->netdev_ops->ndo_vlan_rx_add_vid(dev, vid); #else - if (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER) - dev->netdev_ops->ndo_vlan_rx_add_vid(dev, htons(ETH_P_8021Q), vid); + if (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER) + dev->netdev_ops->ndo_vlan_rx_add_vid(dev, htons(ETH_P_8021Q), vid); #endif - break; - } - } - up(&ipoe_wlock); dev_put(dev); @@ -1721,16 +1728,31 @@ static int ipoe_nl_cmd_del_vlan_mon(struct sk_buff *skb, struct genl_info *info) int ifindex; unsigned long flags; struct list_head *pos, *n; + struct net_device *dev; if (info->attrs[IPOE_ATTR_IFINDEX]) ifindex = nla_get_u32(info->attrs[IPOE_ATTR_IFINDEX]); else ifindex = -1; - rcu_read_lock(); - list_for_each_entry_rcu(d, &vlan_devices, entry) { + down(&ipoe_wlock); + list_for_each_entry(d, &vlan_devices, entry) { if (ifindex == -1 || d->ifindex == ifindex) { //pr_info("del net %08x/%08x\n", n->addr, n->mask); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34) + rtnl_lock(); + dev = __dev_get_by_index(&init_net, d->ifindex); + rtnl_unlock(); +#else + dev = dev_get_by_index(&init_net, d->ifindex); +#endif + + if (dev) { + if (dev->ml_priv == d) + dev->ml_priv = NULL; + dev_put(dev); + } + list_del_rcu(&d->entry); #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) kfree_rcu(d, rcu_head); @@ -1739,7 +1761,7 @@ static int ipoe_nl_cmd_del_vlan_mon(struct sk_buff *skb, struct genl_info *info) #endif } } - rcu_read_unlock(); + up(&ipoe_wlock); spin_lock_irqsave(&vlan_lock, flags); list_for_each_safe(pos, n, &vlan_notifies) { @@ -1902,7 +1924,7 @@ static int __init ipoe_init(void) { int err, i; - printk("IPoE session driver v1.8.0\n"); + printk("IPoE session driver v1.8.0.1\n"); /*err = register_pernet_device(&ipoe_net_ops); if (err < 0) |