summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Kozlov <xeb@mail.ru>2016-04-04 15:20:18 +0300
committerDmitry Kozlov <xeb@mail.ru>2016-04-04 15:20:18 +0300
commitda22624da74340bc875bc54f32db3b5b4dfaac5d (patch)
tree9f74a41d3c2d0ced94f54c2c2e58adc6da47618c
parent581d4533cee479516132a089844b7fc6c32b59ae (diff)
downloadaccel-ppp-da22624da74340bc875bc54f32db3b5b4dfaac5d.tar.gz
accel-ppp-da22624da74340bc875bc54f32db3b5b4dfaac5d.zip
vlan_mon: introduced autoclean module parameter
if autoclean=1 then vlan_mon will delete all vlan interfaces created by previous accel-pppd run f.e. vlan_mon cleans created interfaces if accel-pppd restarts
-rw-r--r--accel-pppd/vlan-mon/vlan_mon.c2
-rw-r--r--drivers/vlan_mon/vlan_mon.c61
2 files changed, 58 insertions, 5 deletions
diff --git a/accel-pppd/vlan-mon/vlan_mon.c b/accel-pppd/vlan-mon/vlan_mon.c
index c243b7a9..0f1b12a9 100644
--- a/accel-pppd/vlan-mon/vlan_mon.c
+++ b/accel-pppd/vlan-mon/vlan_mon.c
@@ -190,8 +190,6 @@ void vlan_mon_clean()
ghdr = NLMSG_DATA(&req.n);
ghdr->cmd = VLAN_MON_CMD_DEL;
- addattr32(nlh, 1024, VLAN_MON_ATTR_IFINDEX, -1);
-
rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL, 0);
rtnl_close(&rth);
diff --git a/drivers/vlan_mon/vlan_mon.c b/drivers/vlan_mon/vlan_mon.c
index 9a2d211d..6f9217d2 100644
--- a/drivers/vlan_mon/vlan_mon.c
+++ b/drivers/vlan_mon/vlan_mon.c
@@ -59,6 +59,8 @@ struct vlan_notify {
int proto;
};
+static int autoclean = 0;
+
static LIST_HEAD(vlan_devices);
static LIST_HEAD(vlan_notifies);
static DEFINE_SPINLOCK(vlan_lock);
@@ -423,6 +425,32 @@ static int vlan_mon_nl_cmd_add_vlan_mon_vid(struct sk_buff *skb, struct genl_inf
return 0;
}
+static void vlan_dev_clean(struct vlan_dev *d, struct net_device *dev, struct list_head *list)
+{
+ int i;
+ struct net_device *vd;
+
+ for (i = 1; i < 4096; i++) {
+ if (d->vid[0][i / (8*sizeof(long))] & (1lu << (i % (8*sizeof(long)))) &&
+ d->vid[1][i / (8*sizeof(long))] & (1lu << (i % (8*sizeof(long)))))
+ continue;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)
+ vd = __vlan_find_dev_deep(dev, i);
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0)
+ vd = __vlan_find_dev_deep(dev, htons(ETH_P_8021Q), i);
+ if (!vd)
+ vd = __vlan_find_dev_deep(dev, htons(ETH_P_8021AD), i);
+#else
+ vd = __vlan_find_dev_deep_rcu(dev, htons(ETH_P_8021Q), i);
+ if (!vd)
+ vd = __vlan_find_dev_deep_rcu(dev, htons(ETH_P_8021AD), i);
+#endif
+
+ if (vd)
+ vd->rtnl_link_ops->dellink(vd, list);
+ }
+}
+
static int vlan_mon_nl_cmd_del_vlan_mon(struct sk_buff *skb, struct genl_info *info)
{
struct vlan_dev *d;
@@ -431,6 +459,7 @@ static int vlan_mon_nl_cmd_del_vlan_mon(struct sk_buff *skb, struct genl_info *i
unsigned long flags;
struct list_head *pos, *n;
struct net_device *dev;
+ LIST_HEAD(list_kill);
if (info->attrs[VLAN_MON_ATTR_PROTO]) {
proto = nla_get_u16(info->attrs[VLAN_MON_ATTR_PROTO]);
@@ -450,10 +479,10 @@ static int vlan_mon_nl_cmd_del_vlan_mon(struct sk_buff *skb, struct genl_info *i
down(&vlan_mon_lock);
rtnl_lock();
+ rcu_read_lock();
list_for_each_safe(pos, n, &vlan_devices) {
d = list_entry(pos, typeof(*d), entry);
if ((ifindex == -1 || d->ifindex == ifindex) && (d->proto & proto)) {
- //pr_info("del net %08x/%08x\n", n->addr, n->mask);
d->proto &= ~proto;
dev = __dev_get_by_index(&init_net, d->ifindex);
@@ -465,12 +494,21 @@ static int vlan_mon_nl_cmd_del_vlan_mon(struct sk_buff *skb, struct genl_info *i
}
if (!d->proto) {
- //pr_info("vlan_mon del %i\n", ifindex);
list_del(&d->entry);
kfree_rcu(d, rcu_head);
+
+ if (ifindex == -1 && autoclean)
+ vlan_dev_clean(d, dev, &list_kill);
}
}
}
+ rcu_read_unlock();
+
+ if (!list_empty(&list_kill)) {
+ unregister_netdevice_many(&list_kill);
+ list_del(&list_kill);
+ }
+
rtnl_unlock();
up(&vlan_mon_lock);
@@ -630,6 +668,7 @@ static void __exit vlan_mon_fini(void)
struct vlan_dev *d;
struct vlan_notify *vn;
struct net_device *dev;
+ LIST_HEAD(list_kill);
dev_remove_pack(&vlan_pt);
@@ -642,14 +681,28 @@ static void __exit vlan_mon_fini(void)
up(&vlan_mon_lock);
rtnl_lock();
+ rcu_read_lock();
while (!list_empty(&vlan_devices)) {
d = list_first_entry(&vlan_devices, typeof(*d), entry);
dev = __dev_get_by_index(&init_net, d->ifindex);
- if (dev)
+
+ if (dev) {
rcu_assign_pointer(dev->ml_priv, NULL);
+
+ if (autoclean)
+ vlan_dev_clean(d, dev, &list_kill);
+ }
+
list_del(&d->entry);
kfree_rcu(d, rcu_head);
}
+ rcu_read_unlock();
+
+ if (!list_empty(&list_kill)) {
+ unregister_netdevice_many(&list_kill);
+ list_del(&list_kill);
+ }
+
rtnl_unlock();
synchronize_net();
@@ -666,4 +719,6 @@ static void __exit vlan_mon_fini(void)
module_init(vlan_mon_init);
module_exit(vlan_mon_fini);
MODULE_LICENSE("GPL");
+module_param(autoclean, int, 0);
+//MODULE_PARAM_DESC(autoclean, "automaticaly remove created vlan interfaces on restart");