Skip to contentSkip to conversation

: Make IPIP tunnel work in net namespaces.

PATCH In review Pavel Emelyanov 2 participants 10 messages Apr 15, 2008 – Apr 16, 2008

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

cover : Make IPIP tunnel work in net namespaces.

Make yet another useful virtual device work in namespaces.

This set is also isolated from the other "make xxx device work in net namespaces" ones.

#1 lore raw

PATCH 1/8 : Introduce empty ipip_net structure and net init/exit ops.

---
 net/ipv4/ipip.c |   50 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 50 insertions(+), 0 deletions(-)
net/ipv4/ipip.c +50 -0
index 894bce9..e39a4c2 100644
@@ -115,10 +115,16 @@
 #include <net/ipip.h>
 #include <net/inet_ecn.h>
 #include <net/xfrm.h>
+#include <net/net_namespace.h>
+#include <net/netns/generic.h>
 
 #define HASH_SIZE  16
 #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF)
 
+static int ipip_net_id;
+struct ipip_net {
+};
+
 static int ipip_fb_tunnel_init(struct net_device *dev);
 static int ipip_tunnel_init(struct net_device *dev);
 static void ipip_tunnel_setup(struct net_device *dev);
@@ -867,6 +873,41 @@ static struct xfrm_tunnel ipip_handler = {
 static char banner[] __initdata =
 	KERN_INFO "IPv4 over IPv4 tunneling driver\n";
 
+static int ipip_init_net(struct net *net)
+{
+	int err;
+	struct ipip_net *ipn;
+
+	err = -ENOMEM;
+	ipn = kmalloc(sizeof(struct ipip_net), GFP_KERNEL);
+	if (ipn == NULL)
+		goto err_alloc;
+
+	err = net_assign_generic(net, ipip_net_id, ipn);
+	if (err < 0)
+		goto err_assign;
+
+	return 0;
+
+err_assign:
+	kfree(ipn);
+err_alloc:
+	return err;
+}
+
+static void ipip_exit_net(struct net *net)
+{
+	struct ipip_net *ipn;
+
+	ipn = net_generic(net, ipip_net_id);
+	kfree(ipn);
+}
+
+static struct pernet_operations ipip_net_ops = {
+	.init = ipip_init_net,
+	.exit = ipip_exit_net,
+};
+
 static int __init ipip_init(void)
 {
 	int err;
@@ -890,6 +931,10 @@ static int __init ipip_init(void)
 
 	if ((err = register_netdev(ipip_fb_tunnel_dev)))
 		goto err2;
+
+	err = register_pernet_gen_device(&ipip_net_id, &ipip_net_ops);
+	if (err)
+		goto err3;
  out:
 	return err;
  err2:
@@ -897,6 +942,9 @@ static int __init ipip_init(void)
  err1:
 	xfrm4_tunnel_deregister(&ipip_handler, AF_INET);
 	goto out;
+err3:
+	unregister_netdevice(ipip_fb_tunnel_dev);
+	goto err1;
 }
 
 static void __exit ipip_destroy_tunnels(void)
@@ -922,6 +970,8 @@ static void __exit ipip_fini(void)
 	ipip_destroy_tunnels();
 	unregister_netdevice(ipip_fb_tunnel_dev);
 	rtnl_unlock();
+
+	unregister_pernet_gen_device(ipip_net_id, &ipip_net_ops);
 }
 
 module_init(ipip_init);
Signature · 1 line
1.5.3.4
#2 lore raw

PATCH 2/8 : Make the fallback tunnel device per-net.

In reply to Pavel Emelyanov

Create on in ipip_init_net(), use it all over the code (the proper place to get the net from already exists) and destroy in ipip_net_exit().

---
 net/ipv4/ipip.c |   67 ++++++++++++++++++++++++++++--------------------------
 1 files changed, 35 insertions(+), 32 deletions(-)
net/ipv4/ipip.c +35 -32
index e39a4c2..e657a66 100644
@@ -123,14 +123,13 @@
 
 static int ipip_net_id;
 struct ipip_net {
+	struct net_device *fb_tunnel_dev;
 };
 
 static int ipip_fb_tunnel_init(struct net_device *dev);
 static int ipip_tunnel_init(struct net_device *dev);
 static void ipip_tunnel_setup(struct net_device *dev);
 
-static struct net_device *ipip_fb_tunnel_dev;
-
 static struct ip_tunnel *tunnels_r_l[HASH_SIZE];
 static struct ip_tunnel *tunnels_r[HASH_SIZE];
 static struct ip_tunnel *tunnels_l[HASH_SIZE];
@@ -257,7 +256,10 @@ failed_free:
 
 static void ipip_tunnel_uninit(struct net_device *dev)
 {
-	if (dev == ipip_fb_tunnel_dev) {
+	struct net *net = dev_net(dev);
+	struct ipip_net *ipn = net_generic(net, ipip_net_id);
+
+	if (dev == ipn->fb_tunnel_dev) {
 		write_lock_bh(&ipip_lock);
 		tunnels_wc[0] = NULL;
 		write_unlock_bh(&ipip_lock);
@@ -693,11 +695,13 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
 	int err = 0;
 	struct ip_tunnel_parm p;
 	struct ip_tunnel *t;
+	struct net *net = dev_net(dev);
+	struct ipip_net *ipn = net_generic(net, ipip_net_id);
 
 	switch (cmd) {
 	case SIOCGETTUNNEL:
 		t = NULL;
-		if (dev == ipip_fb_tunnel_dev) {
+		if (dev == ipn->fb_tunnel_dev) {
 			if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
 				err = -EFAULT;
 				break;
@@ -730,7 +734,7 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
 
 		t = ipip_tunnel_locate(&p, cmd == SIOCADDTUNNEL);
 
-		if (dev != ipip_fb_tunnel_dev && cmd == SIOCCHGTUNNEL) {
+		if (dev != ipn->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) {
 			if (t != NULL) {
 				if (t->dev != dev) {
 					err = -EEXIST;
@@ -776,7 +780,7 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
 		if (!capable(CAP_NET_ADMIN))
 			goto done;
 
-		if (dev == ipip_fb_tunnel_dev) {
+		if (dev == ipn->fb_tunnel_dev) {
 			err = -EFAULT;
 			if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
 				goto done;
@@ -784,7 +788,7 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
 			if ((t = ipip_tunnel_locate(&p, 0)) == NULL)
 				goto done;
 			err = -EPERM;
-			if (t->dev == ipip_fb_tunnel_dev)
+			if (t->dev == ipn->fb_tunnel_dev)
 				goto done;
 			dev = t->dev;
 		}
@@ -847,7 +851,7 @@ static int ipip_tunnel_init(struct net_device *dev)
 	return 0;
 }
 
-static int __init ipip_fb_tunnel_init(struct net_device *dev)
+static int ipip_fb_tunnel_init(struct net_device *dev)
 {
 	struct ip_tunnel *tunnel = netdev_priv(dev);
 	struct iphdr *iph = &tunnel->parms.iph;
@@ -887,8 +891,26 @@ static int ipip_init_net(struct net *net)
 	if (err < 0)
 		goto err_assign;
 
+	ipn->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel),
+					   "tunl0",
+					   ipip_tunnel_setup);
+	if (!ipn->fb_tunnel_dev) {
+		err = -ENOMEM;
+		goto err_alloc_dev;
+	}
+
+	ipn->fb_tunnel_dev->init = ipip_fb_tunnel_init;
+	dev_net_set(ipn->fb_tunnel_dev, net);
+
+	if ((err = register_netdev(ipn->fb_tunnel_dev)))
+		goto err_reg_dev;
+
 	return 0;
 
+err_reg_dev:
+	free_netdev(ipn->fb_tunnel_dev);
+err_alloc_dev:
+	/* nothing */
 err_assign:
 	kfree(ipn);
 err_alloc:
@@ -900,6 +922,9 @@ static void ipip_exit_net(struct net *net)
 	struct ipip_net *ipn;
 
 	ipn = net_generic(net, ipip_net_id);
+	rtnl_lock();
+	unregister_netdevice(ipn->fb_tunnel_dev);
+	rtnl_unlock();
 	kfree(ipn);
 }
 
@@ -919,32 +944,11 @@ static int __init ipip_init(void)
 		return -EAGAIN;
 	}
 
-	ipip_fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel),
-					   "tunl0",
-					   ipip_tunnel_setup);
-	if (!ipip_fb_tunnel_dev) {
-		err = -ENOMEM;
-		goto err1;
-	}
-
-	ipip_fb_tunnel_dev->init = ipip_fb_tunnel_init;
-
-	if ((err = register_netdev(ipip_fb_tunnel_dev)))
-		goto err2;
-
 	err = register_pernet_gen_device(&ipip_net_id, &ipip_net_ops);
 	if (err)
-		goto err3;
- out:
+		xfrm4_tunnel_deregister(&ipip_handler, AF_INET);
+
 	return err;
- err2:
-	free_netdev(ipip_fb_tunnel_dev);
- err1:
-	xfrm4_tunnel_deregister(&ipip_handler, AF_INET);
-	goto out;
-err3:
-	unregister_netdevice(ipip_fb_tunnel_dev);
-	goto err1;
 }
 
 static void __exit ipip_destroy_tunnels(void)
@@ -968,7 +972,6 @@ static void __exit ipip_fini(void)
 
 	rtnl_lock();
 	ipip_destroy_tunnels();
-	unregister_netdevice(ipip_fb_tunnel_dev);
 	rtnl_unlock();
 
 	unregister_pernet_gen_device(ipip_net_id, &ipip_net_ops);
#3 lore raw

PATCH 3/8 : Add net/ipip_net argument to some functions.

In reply to Pavel Emelyanov

The hashes of tunnels will be per-net too, so prepare all the functions that uses them for this change by adding an argument.

Use init_net temporarily in places, where the net does not exist explicitly yet.

---
 net/ipv4/ipip.c |   44 +++++++++++++++++++++++++-------------------
 1 files changed, 25 insertions(+), 19 deletions(-)
net/ipv4/ipip.c +25 -19
index e657a66..bc4d4cb 100644
@@ -138,7 +138,8 @@ static struct ip_tunnel **tunnels[4] = { tunnels_wc, tunnels_l, tunnels_r, tunne
 
 static DEFINE_RWLOCK(ipip_lock);
 
-static struct ip_tunnel * ipip_tunnel_lookup(__be32 remote, __be32 local)
+static struct ip_tunnel * ipip_tunnel_lookup(struct net *net,
+		__be32 remote, __be32 local)
 {
 	unsigned h0 = HASH(remote);
 	unsigned h1 = HASH(local);
@@ -162,7 +163,8 @@ static struct ip_tunnel * ipip_tunnel_lookup(__be32 remote, __be32 local)
 	return NULL;
 }
 
-static struct ip_tunnel **__ipip_bucket(struct ip_tunnel_parm *parms)
+static struct ip_tunnel **__ipip_bucket(struct ipip_net *ipn,
+		struct ip_tunnel_parm *parms)
 {
 	__be32 remote = parms->iph.daddr;
 	__be32 local = parms->iph.saddr;
@@ -180,16 +182,17 @@ static struct ip_tunnel **__ipip_bucket(struct ip_tunnel_parm *parms)
 	return &tunnels[prio][h];
 }
 
-static inline struct ip_tunnel **ipip_bucket(struct ip_tunnel *t)
+static inline struct ip_tunnel **ipip_bucket(struct ipip_net *ipn,
+		struct ip_tunnel *t)
 {
-	return __ipip_bucket(&t->parms);
+	return __ipip_bucket(ipn, &t->parms);
 }
 
-static void ipip_tunnel_unlink(struct ip_tunnel *t)
+static void ipip_tunnel_unlink(struct ipip_net *ipn, struct ip_tunnel *t)
 {
 	struct ip_tunnel **tp;
 
-	for (tp = ipip_bucket(t); *tp; tp = &(*tp)->next) {
+	for (tp = ipip_bucket(ipn, t); *tp; tp = &(*tp)->next) {
 		if (t == *tp) {
 			write_lock_bh(&ipip_lock);
 			*tp = t->next;
@@ -199,9 +202,9 @@ static void ipip_tunnel_unlink(struct ip_tunnel *t)
 	}
 }
 
-static void ipip_tunnel_link(struct ip_tunnel *t)
+static void ipip_tunnel_link(struct ipip_net *ipn, struct ip_tunnel *t)
 {
-	struct ip_tunnel **tp = ipip_bucket(t);
+	struct ip_tunnel **tp = ipip_bucket(ipn, t);
 
 	t->next = *tp;
 	write_lock_bh(&ipip_lock);
@@ -209,15 +212,17 @@ static void ipip_tunnel_link(struct ip_tunnel *t)
 	write_unlock_bh(&ipip_lock);
 }
 
-static struct ip_tunnel * ipip_tunnel_locate(struct ip_tunnel_parm *parms, int create)
+static struct ip_tunnel * ipip_tunnel_locate(struct net *net,
+		struct ip_tunnel_parm *parms, int create)
 {
 	__be32 remote = parms->iph.daddr;
 	__be32 local = parms->iph.saddr;
 	struct ip_tunnel *t, **tp, *nt;
 	struct net_device *dev;
 	char name[IFNAMSIZ];
+	struct ipip_net *ipn = net_generic(net, ipip_net_id);
 
-	for (tp = __ipip_bucket(parms); (t = *tp) != NULL; tp = &t->next) {
+	for (tp = __ipip_bucket(ipn, parms); (t = *tp) != NULL; tp = &t->next) {
 		if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr)
 			return t;
 	}
@@ -246,7 +251,7 @@ static struct ip_tunnel * ipip_tunnel_locate(struct ip_tunnel_parm *parms, int c
 		goto failed_free;
 
 	dev_hold(dev);
-	ipip_tunnel_link(nt);
+	ipip_tunnel_link(ipn, nt);
 	return nt;
 
 failed_free:
@@ -264,7 +269,7 @@ static void ipip_tunnel_uninit(struct net_device *dev)
 		tunnels_wc[0] = NULL;
 		write_unlock_bh(&ipip_lock);
 	} else
-		ipip_tunnel_unlink(netdev_priv(dev));
+		ipip_tunnel_unlink(ipn, netdev_priv(dev));
 	dev_put(dev);
 }
 
@@ -313,7 +318,7 @@ static int ipip_err(struct sk_buff *skb, u32 info)
 	err = -ENOENT;
 
 	read_lock(&ipip_lock);
-	t = ipip_tunnel_lookup(iph->daddr, iph->saddr);
+	t = ipip_tunnel_lookup(&init_net, iph->daddr, iph->saddr);
 	if (t == NULL || t->parms.iph.daddr == 0)
 		goto out;
 
@@ -473,7 +478,8 @@ static int ipip_rcv(struct sk_buff *skb)
 	const struct iphdr *iph = ip_hdr(skb);
 
 	read_lock(&ipip_lock);
-	if ((tunnel = ipip_tunnel_lookup(iph->saddr, iph->daddr)) != NULL) {
+	if ((tunnel = ipip_tunnel_lookup(&init_net,
+					iph->saddr, iph->daddr)) != NULL) {
 		if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
 			read_unlock(&ipip_lock);
 			kfree_skb(skb);
@@ -706,7 +712,7 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
 				err = -EFAULT;
 				break;
 			}
-			t = ipip_tunnel_locate(&p, 0);
+			t = ipip_tunnel_locate(net, &p, 0);
 		}
 		if (t == NULL)
 			t = netdev_priv(dev);
@@ -732,7 +738,7 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
 		if (p.iph.ttl)
 			p.iph.frag_off |= htons(IP_DF);
 
-		t = ipip_tunnel_locate(&p, cmd == SIOCADDTUNNEL);
+		t = ipip_tunnel_locate(net, &p, cmd == SIOCADDTUNNEL);
 
 		if (dev != ipn->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) {
 			if (t != NULL) {
@@ -747,12 +753,12 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
 					break;
 				}
 				t = netdev_priv(dev);
-				ipip_tunnel_unlink(t);
+				ipip_tunnel_unlink(ipn, t);
 				t->parms.iph.saddr = p.iph.saddr;
 				t->parms.iph.daddr = p.iph.daddr;
 				memcpy(dev->dev_addr, &p.iph.saddr, 4);
 				memcpy(dev->broadcast, &p.iph.daddr, 4);
-				ipip_tunnel_link(t);
+				ipip_tunnel_link(ipn, t);
 				netdev_state_change(dev);
 			}
 		}
@@ -785,7 +791,7 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
 			if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
 				goto done;
 			err = -ENOENT;
-			if ((t = ipip_tunnel_locate(&p, 0)) == NULL)
+			if ((t = ipip_tunnel_locate(net, &p, 0)) == NULL)
 				goto done;
 			err = -EPERM;
 			if (t->dev == ipn->fb_tunnel_dev)
Signature · 1 line
1.5.3.4
#4 lore raw

PATCH 4/8 : Use proper net in hash-lookup functions.

In reply to Pavel Emelyanov

This is the part#2 of the previous patch - get the proper net for these functions.

I make it in a separate patch, so that this change does not get lost in a large previous patch.

---
 net/ipv4/ipip.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
net/ipv4/ipip.c +2 -2
index bc4d4cb..da71470 100644
@@ -318,7 +318,7 @@ static int ipip_err(struct sk_buff *skb, u32 info)
 	err = -ENOENT;
 
 	read_lock(&ipip_lock);
-	t = ipip_tunnel_lookup(&init_net, iph->daddr, iph->saddr);
+	t = ipip_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr);
 	if (t == NULL || t->parms.iph.daddr == 0)
 		goto out;
 
@@ -478,7 +478,7 @@ static int ipip_rcv(struct sk_buff *skb)
 	const struct iphdr *iph = ip_hdr(skb);
 
 	read_lock(&ipip_lock);
-	if ((tunnel = ipip_tunnel_lookup(&init_net,
+	if ((tunnel = ipip_tunnel_lookup(dev_net(skb->dev),
 					iph->saddr, iph->daddr)) != NULL) {
 		if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
 			read_unlock(&ipip_lock);
Signature · 1 line
1.5.3.4
#5 lore raw

PATCH 5/8 : Make tunnels hashes per net.

In reply to Pavel Emelyanov

Either net or ipip_net already exists in all the required places, so just use one.

Besides, tune net_init and net_exit calls to respectively initialize the hashes and destroy devices.

---
 net/ipv4/ipip.c |   68 +++++++++++++++++++++++++++++-------------------------
 1 files changed, 36 insertions(+), 32 deletions(-)
net/ipv4/ipip.c +36 -32
index da71470..9c2939b 100644
@@ -123,6 +123,12 @@
 
 static int ipip_net_id;
 struct ipip_net {
+	struct ip_tunnel *tunnels_r_l[HASH_SIZE];
+	struct ip_tunnel *tunnels_r[HASH_SIZE];
+	struct ip_tunnel *tunnels_l[HASH_SIZE];
+	struct ip_tunnel *tunnels_wc[1];
+	struct ip_tunnel **tunnels[4];
+
 	struct net_device *fb_tunnel_dev;
 };
 
@@ -130,12 +136,6 @@ static int ipip_fb_tunnel_init(struct net_device *dev);
 static int ipip_tunnel_init(struct net_device *dev);
 static void ipip_tunnel_setup(struct net_device *dev);
 
-static struct ip_tunnel *tunnels_r_l[HASH_SIZE];
-static struct ip_tunnel *tunnels_r[HASH_SIZE];
-static struct ip_tunnel *tunnels_l[HASH_SIZE];
-static struct ip_tunnel *tunnels_wc[1];
-static struct ip_tunnel **tunnels[4] = { tunnels_wc, tunnels_l, tunnels_r, tunnels_r_l };
-
 static DEFINE_RWLOCK(ipip_lock);
 
 static struct ip_tunnel * ipip_tunnel_lookup(struct net *net,
@@ -144,21 +144,22 @@ static struct ip_tunnel * ipip_tunnel_lookup(struct net *net,
 	unsigned h0 = HASH(remote);
 	unsigned h1 = HASH(local);
 	struct ip_tunnel *t;
+	struct ipip_net *ipn = net_generic(net, ipip_net_id);
 
-	for (t = tunnels_r_l[h0^h1]; t; t = t->next) {
+	for (t = ipn->tunnels_r_l[h0^h1]; t; t = t->next) {
 		if (local == t->parms.iph.saddr &&
 		    remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP))
 			return t;
 	}
-	for (t = tunnels_r[h0]; t; t = t->next) {
+	for (t = ipn->tunnels_r[h0]; t; t = t->next) {
 		if (remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP))
 			return t;
 	}
-	for (t = tunnels_l[h1]; t; t = t->next) {
+	for (t = ipn->tunnels_l[h1]; t; t = t->next) {
 		if (local == t->parms.iph.saddr && (t->dev->flags&IFF_UP))
 			return t;
 	}
-	if ((t = tunnels_wc[0]) != NULL && (t->dev->flags&IFF_UP))
+	if ((t = ipn->tunnels_wc[0]) != NULL && (t->dev->flags&IFF_UP))
 		return t;
 	return NULL;
 }
@@ -179,7 +180,7 @@ static struct ip_tunnel **__ipip_bucket(struct ipip_net *ipn,
 		prio |= 1;
 		h ^= HASH(local);
 	}
-	return &tunnels[prio][h];
+	return &ipn->tunnels[prio][h];
 }
 
 static inline struct ip_tunnel **ipip_bucket(struct ipip_net *ipn,
@@ -266,7 +267,7 @@ static void ipip_tunnel_uninit(struct net_device *dev)
 
 	if (dev == ipn->fb_tunnel_dev) {
 		write_lock_bh(&ipip_lock);
-		tunnels_wc[0] = NULL;
+		ipn->tunnels_wc[0] = NULL;
 		write_unlock_bh(&ipip_lock);
 	} else
 		ipip_tunnel_unlink(ipn, netdev_priv(dev));
@@ -861,6 +862,7 @@ static int ipip_fb_tunnel_init(struct net_device *dev)
 {
 	struct ip_tunnel *tunnel = netdev_priv(dev);
 	struct iphdr *iph = &tunnel->parms.iph;
+	struct ipip_net *ipn = net_generic(dev_net(dev), ipip_net_id);
 
 	tunnel->dev = dev;
 	strcpy(tunnel->parms.name, dev->name);
@@ -870,7 +872,7 @@ static int ipip_fb_tunnel_init(struct net_device *dev)
 	iph->ihl		= 5;
 
 	dev_hold(dev);
-	tunnels_wc[0]		= tunnel;
+	ipn->tunnels_wc[0]	= tunnel;
 	return 0;
 }
 
@@ -883,13 +885,27 @@ static struct xfrm_tunnel ipip_handler = {
 static char banner[] __initdata =
 	KERN_INFO "IPv4 over IPv4 tunneling driver\n";
 
+static void ipip_destroy_tunnels(struct ipip_net *ipn)
+{
+	int prio;
+
+	for (prio = 1; prio < 4; prio++) {
+		int h;
+		for (h = 0; h < HASH_SIZE; h++) {
+			struct ip_tunnel *t;
+			while ((t = ipn->tunnels[prio][h]) != NULL)
+				unregister_netdevice(t->dev);
+		}
+	}
+}
+
 static int ipip_init_net(struct net *net)
 {
 	int err;
 	struct ipip_net *ipn;
 
 	err = -ENOMEM;
-	ipn = kmalloc(sizeof(struct ipip_net), GFP_KERNEL);
+	ipn = kzalloc(sizeof(struct ipip_net), GFP_KERNEL);
 	if (ipn == NULL)
 		goto err_alloc;
 
@@ -897,6 +913,11 @@ static int ipip_init_net(struct net *net)
 	if (err < 0)
 		goto err_assign;
 
+	ipn->tunnels[0] = ipn->tunnels_wc;
+	ipn->tunnels[1] = ipn->tunnels_l;
+	ipn->tunnels[2] = ipn->tunnels_r;
+	ipn->tunnels[3] = ipn->tunnels_r_l;
+
 	ipn->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel),
 					   "tunl0",
 					   ipip_tunnel_setup);
@@ -929,6 +950,7 @@ static void ipip_exit_net(struct net *net)
 
 	ipn = net_generic(net, ipip_net_id);
 	rtnl_lock();
+	ipip_destroy_tunnels(ipn);
 	unregister_netdevice(ipn->fb_tunnel_dev);
 	rtnl_unlock();
 	kfree(ipn);
@@ -957,29 +979,11 @@ static int __init ipip_init(void)
 	return err;
 }
 
-static void __exit ipip_destroy_tunnels(void)
-{
-	int prio;
-
-	for (prio = 1; prio < 4; prio++) {
-		int h;
-		for (h = 0; h < HASH_SIZE; h++) {
-			struct ip_tunnel *t;
-			while ((t = tunnels[prio][h]) != NULL)
-				unregister_netdevice(t->dev);
-		}
-	}
-}
-
 static void __exit ipip_fini(void)
 {
 	if (xfrm4_tunnel_deregister(&ipip_handler, AF_INET))
 		printk(KERN_INFO "ipip close: can't deregister tunnel\n");
 
-	rtnl_lock();
-	ipip_destroy_tunnels();
-	rtnl_unlock();
-
 	unregister_pernet_gen_device(ipip_net_id, &ipip_net_ops);
 }
 
Signature · 1 line
1.5.3.4
#6 lore raw

PATCH 6/8 : Use proper net in (mostly) routing calls.

In reply to Pavel Emelyanov

There are some ip_route_output_key() calls in there that require a proper net so give one to them.

Besides - give a proper net to a single __get_dev_by_index call in ipip_tunnel_bind_dev().

---
 net/ipv4/ipip.c |   10 +++++-----
 1 files changed, 5 insertions(+), 5 deletions(-)
net/ipv4/ipip.c +5 -5
index 9c2939b..1de39e1 100644
@@ -415,7 +415,7 @@ out:
 	fl.fl4_daddr = eiph->saddr;
 	fl.fl4_tos = RT_TOS(eiph->tos);
 	fl.proto = IPPROTO_IPIP;
-	if (ip_route_output_key(&init_net, &rt, &key)) {
+	if (ip_route_output_key(dev_net(skb->dev), &rt, &key)) {
 		kfree_skb(skb2);
 		return 0;
 	}
@@ -428,7 +428,7 @@ out:
 		fl.fl4_daddr = eiph->daddr;
 		fl.fl4_src = eiph->saddr;
 		fl.fl4_tos = eiph->tos;
-		if (ip_route_output_key(&init_net, &rt, &fl) ||
+		if (ip_route_output_key(dev_net(skb->dev), &rt, &fl) ||
 		    rt->u.dst.dev->type != ARPHRD_TUNNEL) {
 			ip_rt_put(rt);
 			kfree_skb(skb2);
@@ -558,7 +558,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 						.saddr = tiph->saddr,
 						.tos = RT_TOS(tos) } },
 				    .proto = IPPROTO_IPIP };
-		if (ip_route_output_key(&init_net, &rt, &fl)) {
+		if (ip_route_output_key(dev_net(dev), &rt, &fl)) {
 			tunnel->stat.tx_carrier_errors++;
 			goto tx_error_icmp;
 		}
@@ -679,7 +679,7 @@ static void ipip_tunnel_bind_dev(struct net_device *dev)
 						.tos = RT_TOS(iph->tos) } },
 				    .proto = IPPROTO_IPIP };
 		struct rtable *rt;
-		if (!ip_route_output_key(&init_net, &rt, &fl)) {
+		if (!ip_route_output_key(dev_net(dev), &rt, &fl)) {
 			tdev = rt->u.dst.dev;
 			ip_rt_put(rt);
 		}
@@ -687,7 +687,7 @@ static void ipip_tunnel_bind_dev(struct net_device *dev)
 	}
 
 	if (!tdev && tunnel->parms.link)
-		tdev = __dev_get_by_index(&init_net, tunnel->parms.link);
+		tdev = __dev_get_by_index(dev_net(dev), tunnel->parms.link);
 
 	if (tdev) {
 		dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr);
Signature · 1 line
1.5.3.4
#7 lore raw

PATCH 7/8 : Allow to create IPIP tunnels in net namespaces.

In reply to Pavel Emelyanov

Set the proper net before calling register_netdev and disable the tunnel device netns changing.

---
 net/ipv4/ipip.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)
net/ipv4/ipip.c +3 -0
index 1de39e1..149111f 100644
@@ -239,6 +239,8 @@ static struct ip_tunnel * ipip_tunnel_locate(struct net *net,
 	if (dev == NULL)
 		return NULL;
 
+	dev_net_set(dev, net);
+
 	if (strchr(name, '%')) {
 		if (dev_alloc_name(dev, name) < 0)
 			goto failed_free;
@@ -839,6 +841,7 @@ static void ipip_tunnel_setup(struct net_device *dev)
 	dev->flags		= IFF_NOARP;
 	dev->iflink		= 0;
 	dev->addr_len		= 4;
+	dev->features		|= NETIF_F_NETNS_LOCAL;
 }
 
 static int ipip_tunnel_init(struct net_device *dev)
Signature · 1 line
1.5.3.4
#8 lore raw

PATCH 8/8 : Allow for IPPROTO_IPIP protocol in namespaces.

In reply to Pavel Emelyanov

This one was disabled by default for sanity.

---
 net/ipv4/tunnel4.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
net/ipv4/tunnel4.c +1 -0
index 978b3fd..cc4cd0e 100644
@@ -136,6 +136,7 @@ static struct net_protocol tunnel4_protocol = {
 	.handler	=	tunnel4_rcv,
 	.err_handler	=	tunnel4_err,
 	.no_policy	=	1,
+	.netns_ok	=	1,
 };
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Signature · 1 line
1.5.3.4