: Make ip6tunnel work in net namespaces.
Subsystems (3)
cover : Make ip6tunnel work in net namespaces.
This is the last tunnel to virtualize.
PATCH 1/7 : Introduce empty ip6_tnl_net structure and net ops.
--- net/ipv6/ip6_tunnel.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 49 insertions(+), 0 deletions(-)
net/ipv6/ip6_tunnel.c +49 -0
@@ -52,6 +52,8 @@#include <net/xfrm.h> #include <net/dsfield.h> #include <net/inet_ecn.h> +#include <net/net_namespace.h> +#include <net/netns/generic.h> MODULE_AUTHOR ("Ville Nuorvala" );MODULE_DESCRIPTION ("IPv6 tunneling device" );
@@ -78,6 +80,10 @@ static int ip6_fb_tnl_dev_init(struct net_device *dev);static int ip6_tnl_dev_init (struct net_device *dev);static void ip6_tnl_dev_setup (struct net_device *dev); +static int ip6_tnl_net_id; +struct ip6_tnl_net { +}; +/* the IPv6 tunnel fallback device */ static struct net_device *ip6_fb_tnl_dev;
@@ -1384,6 +1390,41 @@ static struct xfrm6_tunnel ip6ip6_handler = { .priority = 1, }; +static int ip6_tnl_init_net (struct net *net) +{ +int err; +struct ip6_tnl_net *ip6n; + + err = -ENOMEM ; + ip6n =kmalloc (sizeof (struct ip6_tnl_net ),GFP_KERNEL ); +if (ip6n ==NULL ) + goto err_alloc; + + err =net_assign_generic (net, ip6_tnl_net_id, ip6n); +if (err <0 ) + goto err_assign; + +return 0 ; + +err_assign: +kfree (ip6n); +err_alloc: +return err; +} + +static void ip6_tnl_exit_net (struct net *net) +{ +struct ip6_tnl_net *ip6n; + + ip6n =net_generic (net, ip6_tnl_net_id); +kfree (ip6n); +} + +static struct pernet_operations ip6_tnl_net_ops = { + .init = ip6_tnl_init_net, + .exit = ip6_tnl_exit_net, +}; +/** * ip6_tunnel_init - register protocol and reserve needed resources *
@@ -1418,7 +1459,13 @@ static int __init ip6_tunnel_init(void)free_netdev (ip6_fb_tnl_dev); goto fail; } + + err =register_pernet_gen_device (&ip6_tnl_net_id, &ip6_tnl_net_ops); +if (err <0 ) + goto err_pernet;return 0 ; +err_pernet: +unregister_netdevice (ip6_fb_tnl_dev); fail:xfrm6_tunnel_deregister (&ip6ip6_handler,AF_INET6 ); unreg_ip4ip6:
@@ -1456,6 +1503,8 @@ static void __exit ip6_tunnel_cleanup(void)rtnl_lock ();ip6_tnl_destroy_tunnels ();rtnl_unlock (); + +unregister_pernet_gen_device (ip6_tnl_net_id, &ip6_tnl_net_ops); }module_init (ip6_tunnel_init);
Signature · 1 line
1.5.3.4
PATCH 2/7 : Add (ip6_tnl_)net argument to some calls.
In reply to Pavel EmelyanovHashes and fallback device used in them will be per-net.
--- net/ipv6/ip6_tunnel.c | 47 ++++++++++++++++++++++++++++------------------- 1 files changed, 28 insertions(+), 19 deletions(-)
net/ipv6/ip6_tunnel.c +28 -19
@@ -136,7 +136,7 @@ static inline void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst)**/ static struct ip6_tnl * -ip6_tnl_lookup (struct in6_addr *remote,struct in6_addr *local) +ip6_tnl_lookup (struct net *net,struct in6_addr *remote,struct in6_addr *local) {unsigned h0 =HASH (remote);unsigned h1 =HASH (local);
@@ -166,7 +166,7 @@ ip6_tnl_lookup(struct in6_addr *remote, struct in6_addr *local)**/ static struct ip6_tnl ** -ip6_tnl_bucket (struct ip6_tnl_parm *p) +ip6_tnl_bucket (struct ip6_tnl_net *ip6n,struct ip6_tnl_parm *p) {struct in6_addr *remote = &p->raddr;struct in6_addr *local = &p->laddr;
@@ -186,9 +186,9 @@ ip6_tnl_bucket(struct ip6_tnl_parm *p)**/ static void -ip6_tnl_link (struct ip6_tnl *t) +ip6_tnl_link (struct ip6_tnl_net *ip6n,struct ip6_tnl *t) { -struct ip6_tnl **tp =ip6_tnl_bucket (&t->parms); +struct ip6_tnl **tp =ip6_tnl_bucket (ip6n, &t->parms); t->next = *tp;write_lock_bh (&ip6_tnl_lock);
@@ -202,11 +202,11 @@ ip6_tnl_link(struct ip6_tnl *t)**/ static void -ip6_tnl_unlink (struct ip6_tnl *t) +ip6_tnl_unlink (struct ip6_tnl_net *ip6n,struct ip6_tnl *t) {struct ip6_tnl **tp; -for (tp =ip6_tnl_bucket (&t->parms); *tp; tp = &(*tp)->next) { +for (tp =ip6_tnl_bucket (ip6n, &t->parms); *tp; tp = &(*tp)->next) {if (t == *tp) {write_lock_bh (&ip6_tnl_lock); *tp = t->next;
@@ -228,12 +228,13 @@ ip6_tnl_unlink(struct ip6_tnl *t)* created tunnel or NULL **/ -static struct ip6_tnl *ip6_tnl_create (struct ip6_tnl_parm *p) +static struct ip6_tnl *ip6_tnl_create (struct net *net,struct ip6_tnl_parm *p) {struct net_device *dev;struct ip6_tnl *t;char name[IFNAMSIZ ];int err; +struct ip6_tnl_net *ip6n =net_generic (net, ip6_tnl_net_id);if (p->name[0 ])strlcpy (name, p->name,IFNAMSIZ );
@@ -257,7 +258,7 @@ static struct ip6_tnl *ip6_tnl_create(struct ip6_tnl_parm *p) goto failed_free;dev_hold (dev); -ip6_tnl_link (t); +ip6_tnl_link (ip6n, t);return t; failed_free:
@@ -280,20 +281,22 @@ failed:* matching tunnel or NULL **/ -static struct ip6_tnl *ip6_tnl_locate (struct ip6_tnl_parm *p,int create) +static struct ip6_tnl *ip6_tnl_locate (struct net *net, +struct ip6_tnl_parm *p,int create) {struct in6_addr *remote = &p->raddr;struct in6_addr *local = &p->laddr;struct ip6_tnl *t; +struct ip6_tnl_net *ip6n =net_generic (net, ip6_tnl_net_id); -for (t = *ip6_tnl_bucket (p); t; t = t->next) { +for (t = *ip6_tnl_bucket (ip6n, p); t; t = t->next) {if (ipv6_addr_equal (local, &t->parms.laddr) &&ipv6_addr_equal (remote, &t->parms.raddr))return t; }if (!create)return NULL ; -return ip6_tnl_create (p); +return ip6_tnl_create (net, p); }/**
@@ -308,13 +311,15 @@ static void ip6_tnl_dev_uninit(struct net_device *dev) {struct ip6_tnl *t =netdev_priv (dev); +struct net *net =dev_net (dev); +struct ip6_tnl_net *ip6n =net_generic (net, ip6_tnl_net_id);if (dev == ip6_fb_tnl_dev) {write_lock_bh (&ip6_tnl_lock); tnls_wc[0 ] =NULL ;write_unlock_bh (&ip6_tnl_lock); }else { -ip6_tnl_unlink (t); +ip6_tnl_unlink (ip6n, t); }ip6_tnl_dst_reset (t);dev_put (dev);
@@ -407,7 +412,8 @@ ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt,processing of the error. */ read_lock (&ip6_tnl_lock); -if ((t =ip6_tnl_lookup (&ipv6h->daddr, &ipv6h->saddr)) ==NULL ) +if ((t =ip6_tnl_lookup (&init_net, &ipv6h->daddr, + &ipv6h->saddr)) ==NULL ) goto out;if (t->parms.proto != ipproto && t->parms.proto !=0 )
@@ -690,7 +696,8 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,read_lock (&ip6_tnl_lock); -if ((t =ip6_tnl_lookup (&ipv6h->saddr, &ipv6h->daddr)) !=NULL ) { +if ((t =ip6_tnl_lookup (&init_net, &ipv6h->saddr, + &ipv6h->daddr)) !=NULL ) {if (t->parms.proto != ipproto && t->parms.proto !=0 ) {read_unlock (&ip6_tnl_lock); goto discard;
@@ -1197,6 +1204,8 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)int err =0 ;struct ip6_tnl_parm p;struct ip6_tnl *t =NULL ; +struct net *net =dev_net (dev); +struct ip6_tnl_net *ip6n =net_generic (net, ip6_tnl_net_id);switch (cmd) {case SIOCGETTUNNEL :
@@ -1205,7 +1214,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) err = -EFAULT ;break ; } - t =ip6_tnl_locate (&p,0 ); + t =ip6_tnl_locate (net, &p,0 ); }if (t ==NULL ) t =netdev_priv (dev);
@@ -1226,7 +1235,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)if (p.proto !=IPPROTO_IPV6 && p.proto !=IPPROTO_IPIP && p.proto !=0 )break ; - t =ip6_tnl_locate (&p, cmd ==SIOCADDTUNNEL ); + t =ip6_tnl_locate (net, &p, cmd ==SIOCADDTUNNEL );if (dev != ip6_fb_tnl_dev && cmd ==SIOCCHGTUNNEL ) {if (t !=NULL ) {if (t->dev != dev) {
@@ -1236,9 +1245,9 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) }else t =netdev_priv (dev); -ip6_tnl_unlink (t); +ip6_tnl_unlink (ip6n, t); err =ip6_tnl_change (t, &p); -ip6_tnl_link (t); +ip6_tnl_link (ip6n, t);netdev_state_change (dev); }if (t) {
@@ -1259,7 +1268,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)if (copy_from_user (&p, ifr->ifr_ifru.ifru_data,sizeof (p)))break ; err = -ENOENT ; -if ((t =ip6_tnl_locate (&p,0 )) ==NULL ) +if ((t =ip6_tnl_locate (net, &p,0 )) ==NULL )break ; err = -EPERM ;if (t->dev == ip6_fb_tnl_dev)
Signature · 1 line
1.5.3.4
PATCH 3/7 : Use proper net in hash-lookup functions.
In reply to Pavel EmelyanovCalls to ip6_tnl_lookup were stubbed with init_net - give them a proper one.
--- net/ipv6/ip6_tunnel.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
net/ipv6/ip6_tunnel.c +2 -2
@@ -412,7 +412,7 @@ ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt,processing of the error. */ read_lock (&ip6_tnl_lock); -if ((t =ip6_tnl_lookup (&init_net, &ipv6h->daddr, +if ((t =ip6_tnl_lookup (dev_net (skb->dev), &ipv6h->daddr, &ipv6h->saddr)) ==NULL ) goto out;
@@ -696,7 +696,7 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,read_lock (&ip6_tnl_lock); -if ((t =ip6_tnl_lookup (&init_net, &ipv6h->saddr, +if ((t =ip6_tnl_lookup (dev_net (skb->dev), &ipv6h->saddr, &ipv6h->daddr)) !=NULL ) {if (t->parms.proto != ipproto && t->parms.proto !=0 ) {read_unlock (&ip6_tnl_lock);
Signature · 1 line
1.5.3.4
PATCH 4/7 : Make the fallback tunnel device per-net.
In reply to Pavel EmelyanovAll the code, that reference it already has the ip6_tnl_net pointer, so s/ip6_fb_tnl_dev/ip6n->fb_tnl_dev/ and move creation/releasing code into net init/exit ops.
--- net/ipv6/ip6_tunnel.c | 48 ++++++++++++++++++++++++------------------------ 1 files changed, 24 insertions(+), 24 deletions(-)
net/ipv6/ip6_tunnel.c +24 -24
@@ -82,12 +82,10 @@ static void ip6_tnl_dev_setup(struct net_device *dev);static int ip6_tnl_net_id;struct ip6_tnl_net { +/* the IPv6 tunnel fallback device */ +struct net_device *fb_tnl_dev; }; -/* the IPv6 tunnel fallback device */ -static struct net_device *ip6_fb_tnl_dev; - -/* lists for storing tunnels in use */ static struct ip6_tnl *tnls_r_l[HASH_SIZE ];static struct ip6_tnl *tnls_wc[1 ];
@@ -314,7 +312,7 @@ ip6_tnl_dev_uninit(struct net_device *dev)struct net *net =dev_net (dev);struct ip6_tnl_net *ip6n =net_generic (net, ip6_tnl_net_id); -if (dev == ip6_fb_tnl_dev) { +if (dev == ip6n->fb_tnl_dev) {write_lock_bh (&ip6_tnl_lock); tnls_wc[0 ] =NULL ;write_unlock_bh (&ip6_tnl_lock);
@@ -1209,7 +1207,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)switch (cmd) {case SIOCGETTUNNEL : -if (dev == ip6_fb_tnl_dev) { +if (dev == ip6n->fb_tnl_dev) {if (copy_from_user (&p, ifr->ifr_ifru.ifru_data,sizeof (p))) { err = -EFAULT ;break ;
@@ -1236,7 +1234,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) p.proto != 0)break ; t =ip6_tnl_locate (net, &p, cmd ==SIOCADDTUNNEL ); -if (dev != ip6_fb_tnl_dev && cmd ==SIOCCHGTUNNEL ) { +if (dev != ip6n->fb_tnl_dev && cmd ==SIOCCHGTUNNEL ) {if (t !=NULL ) {if (t->dev != dev) { err = -EEXIST ;
@@ -1263,7 +1261,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)if (!capable (CAP_NET_ADMIN ))break ; -if (dev == ip6_fb_tnl_dev) { +if (dev == ip6n->fb_tnl_dev) { err = -EFAULT ;if (copy_from_user (&p, ifr->ifr_ifru.ifru_data,sizeof (p)))break ;
@@ -1271,7 +1269,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)if ((t =ip6_tnl_locate (net, &p,0 )) ==NULL )break ; err = -EPERM ; -if (t->dev == ip6_fb_tnl_dev) +if (t->dev == ip6n->fb_tnl_dev)break ; dev = t->dev; }
@@ -1413,8 +1411,25 @@ static int ip6_tnl_init_net(struct net *net)if (err <0 ) goto err_assign; + err = -ENOMEM ; + ip6n->fb_tnl_dev =alloc_netdev (sizeof (struct ip6_tnl ),"ip6tnl0" , + ip6_tnl_dev_setup); + +if (!ip6n->fb_tnl_dev) + goto err_alloc_dev; + + ip6n->fb_tnl_dev->init = ip6_fb_tnl_dev_init; +dev_net_set (ip6n->fb_tnl_dev, net); + + err =register_netdev (ip6n->fb_tnl_dev); +if (err <0 ) + goto err_register;return 0 ; +err_register: +free_netdev (ip6n->fb_tnl_dev); +err_alloc_dev: +/* nothing */ err_assign:kfree (ip6n); err_alloc:
@@ -1455,27 +1470,12 @@ static int __init ip6_tunnel_init(void) err = -EAGAIN ; goto unreg_ip4ip6; } - ip6_fb_tnl_dev =alloc_netdev (sizeof (struct ip6_tnl ),"ip6tnl0" , - ip6_tnl_dev_setup); - -if (!ip6_fb_tnl_dev) { - err = -ENOMEM ; - goto fail; - } - ip6_fb_tnl_dev->init = ip6_fb_tnl_dev_init; - -if ((err =register_netdev (ip6_fb_tnl_dev))) { -free_netdev (ip6_fb_tnl_dev); - goto fail; - } err =register_pernet_gen_device (&ip6_tnl_net_id, &ip6_tnl_net_ops);if (err <0 ) goto err_pernet;return 0 ; err_pernet: -unregister_netdevice (ip6_fb_tnl_dev); -fail:xfrm6_tunnel_deregister (&ip6ip6_handler,AF_INET6 ); unreg_ip4ip6:xfrm6_tunnel_deregister (&ip4ip6_handler,AF_INET );
Signature · 1 line
1.5.3.4
PATCH 5/7 : Make tunnels hashes per-net.
In reply to Pavel EmelyanovMove hashes in the struct ip6_tnl_net, replace tnls_xxx[] with ip6n->tnlx_xxx[] and handle init and exit appropriately.
--- net/ipv6/ip6_tunnel.c | 63 ++++++++++++++++++++++++++---------------------- 1 files changed, 34 insertions(+), 29 deletions(-)
net/ipv6/ip6_tunnel.c +34 -29
@@ -84,13 +84,12 @@ static int ip6_tnl_net_id;struct ip6_tnl_net {/* the IPv6 tunnel fallback device */ struct net_device *fb_tnl_dev; +/* lists for storing tunnels in use */ +struct ip6_tnl *tnls_r_l[HASH_SIZE ]; +struct ip6_tnl *tnls_wc[1 ]; +struct ip6_tnl **tnls[2 ]; }; -/* lists for storing tunnels in use */ -static struct ip6_tnl *tnls_r_l[HASH_SIZE ]; -static struct ip6_tnl *tnls_wc[1 ]; -static struct ip6_tnl **tnls[2 ] = { tnls_wc, tnls_r_l }; -/* lock for the tunnel lists */ static DEFINE_RWLOCK (ip6_tnl_lock);
@@ -139,14 +138,15 @@ ip6_tnl_lookup(struct net *net, struct in6_addr *remote, struct in6_addr *local)unsigned h0 =HASH (remote);unsigned h1 =HASH (local);struct ip6_tnl *t; +struct ip6_tnl_net *ip6n =net_generic (net, ip6_tnl_net_id); -for (t = tnls_r_l[h0 ^ h1]; t; t = t->next) { +for (t = ip6n->tnls_r_l[h0 ^ h1]; t; t = t->next) {if (ipv6_addr_equal (local, &t->parms.laddr) &&ipv6_addr_equal (remote, &t->parms.raddr) && (t->dev->flags &IFF_UP ))return t; } -if ((t = tnls_wc[0 ]) !=NULL && (t->dev->flags &IFF_UP )) +if ((t = ip6n->tnls_wc[0 ]) !=NULL && (t->dev->flags &IFF_UP ))return t;return NULL ;
@@ -175,7 +175,7 @@ ip6_tnl_bucket(struct ip6_tnl_net *ip6n, struct ip6_tnl_parm *p) prio =1 ; h =HASH (remote) ^HASH (local); } -return &tnls[prio][h]; +return &ip6n->tnls[prio][h]; }/**
@@ -314,7 +314,7 @@ ip6_tnl_dev_uninit(struct net_device *dev)if (dev == ip6n->fb_tnl_dev) {write_lock_bh (&ip6_tnl_lock); - tnls_wc[0 ] =NULL ; + ip6n->tnls_wc[0 ] =NULL ;write_unlock_bh (&ip6_tnl_lock); }else {ip6_tnl_unlink (ip6n, t);
@@ -1378,10 +1378,13 @@ static int ip6_fb_tnl_dev_init(struct net_device *dev) {struct ip6_tnl *t =netdev_priv (dev); +struct net *net =dev_net (dev); +struct ip6_tnl_net *ip6n =net_generic (net, ip6_tnl_net_id); +ip6_tnl_dev_init_gen (dev); t->parms.proto =IPPROTO_IPV6 ;dev_hold (dev); - tnls_wc[0 ] = t; + ip6n->tnls_wc[0 ] = t;return 0 ; }
@@ -1397,13 +1400,27 @@ static struct xfrm6_tunnel ip6ip6_handler = { .priority = 1, }; +static void ip6_tnl_destroy_tunnels (struct ip6_tnl_net *ip6n) +{ +int h; +struct ip6_tnl *t; + +for (h =0 ; h <HASH_SIZE ; h++) { +while ((t = ip6n->tnls_r_l[h]) !=NULL ) +unregister_netdevice (t->dev); + } + + t = ip6n->tnls_wc[0 ]; +unregister_netdevice (t->dev); +} +static int ip6_tnl_init_net (struct net *net) {int err;struct ip6_tnl_net *ip6n; err = -ENOMEM ; - ip6n =kmalloc (sizeof (struct ip6_tnl_net ),GFP_KERNEL ); + ip6n =kzalloc (sizeof (struct ip6_tnl_net ),GFP_KERNEL );if (ip6n ==NULL ) goto err_alloc;
@@ -1411,6 +1428,9 @@ static int ip6_tnl_init_net(struct net *net)if (err <0 ) goto err_assign; + ip6n->tnls[0 ] = ip6n->tnls_wc; + ip6n->tnls[1 ] = ip6n->tnls_r_l; + err = -ENOMEM ; ip6n->fb_tnl_dev =alloc_netdev (sizeof (struct ip6_tnl ),"ip6tnl0" , ip6_tnl_dev_setup);
@@ -1441,6 +1461,9 @@ static void ip6_tnl_exit_net(struct net *net)struct ip6_tnl_net *ip6n; ip6n =net_generic (net, ip6_tnl_net_id); +rtnl_lock (); +ip6_tnl_destroy_tunnels (ip6n); +rtnl_unlock ();kfree (ip6n); }
@@ -1483,20 +1506,6 @@ out:return err; } -static void __exit ip6_tnl_destroy_tunnels(void) -{ -int h; -struct ip6_tnl *t; - -for (h =0 ; h <HASH_SIZE ; h++) { -while ((t = tnls_r_l[h]) !=NULL ) -unregister_netdevice (t->dev); - } - - t = tnls_wc[0 ]; -unregister_netdevice (t->dev); -} -/** * ip6_tunnel_cleanup - free resources and unregister protocol **/
@@ -1509,10 +1518,6 @@ static void __exit ip6_tunnel_cleanup(void)if (xfrm6_tunnel_deregister (&ip6ip6_handler,AF_INET6 ))printk (KERN_INFO "ip6_tunnel close: can't deregister ip6ip6\n" ); -rtnl_lock (); -ip6_tnl_destroy_tunnels (); -rtnl_unlock (); -unregister_pernet_gen_device (ip6_tnl_net_id, &ip6_tnl_net_ops); }
Signature · 1 line
1.5.3.4
PATCH 6/7 : Use proper net instead of init_net stubs.
In reply to Pavel EmelyanovAll the ip_route_output_key(), dev_get_by_...() and ipv6_chk_addr() calls are now stubbed with init_net.
Fortunately, all the places already have where to get the proper net from.
--- net/ipv6/ip6_tunnel.c | 26 +++++++++++++++----------- 1 files changed, 15 insertions(+), 11 deletions(-)
net/ipv6/ip6_tunnel.c +15 -11
@@ -543,7 +543,7 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, fl.fl4_dst = eiph->saddr; fl.fl4_tos =RT_TOS (eiph->tos); fl.proto =IPPROTO_IPIP ; -if (ip_route_output_key (&init_net, &rt, &fl)) +if (ip_route_output_key (dev_net (skb->dev), &rt, &fl)) goto out; skb2->dev = rt->u.dst.dev;
@@ -555,7 +555,7 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, fl.fl4_dst = 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); goto out;
@@ -612,7 +612,8 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,skb_reset_network_header (skb2);/* Try to guess incoming interface */ - rt =rt6_lookup (&init_net, &ipv6_hdr (skb2)->saddr,NULL ,0 ,0 ); + rt =rt6_lookup (dev_net (skb->dev), &ipv6_hdr (skb2)->saddr, +NULL ,0 ,0 );if (rt && rt->rt6i_dev) skb2->dev = rt->rt6i_dev;
@@ -656,16 +657,17 @@ static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t) {struct ip6_tnl_parm *p = &t->parms;int ret =0 ; +struct net *net =dev_net (t->dev);if (p->flags &IP6_TNL_F_CAP_RCV ) {struct net_device *ldev =NULL ;if (p->link) - ldev =dev_get_by_index (&init_net, p->link); + ldev =dev_get_by_index (net, p->link);if ((ipv6_addr_is_multicast (&p->laddr) || -likely (ipv6_chk_addr (&init_net, &p->laddr, ldev,0 ))) && -likely (!ipv6_chk_addr (&init_net, &p->raddr,NULL ,0 ))) +likely (ipv6_chk_addr (net, &p->laddr, ldev,0 ))) && +likely (!ipv6_chk_addr (net, &p->raddr,NULL ,0 ))) ret =1 ;if (ldev)
@@ -793,19 +795,20 @@ static inline int ip6_tnl_xmit_ctl(struct ip6_tnl *t) {struct ip6_tnl_parm *p = &t->parms;int ret =0 ; +struct net *net =dev_net (t->dev);if (p->flags &IP6_TNL_F_CAP_XMIT ) {struct net_device *ldev =NULL ;if (p->link) - ldev =dev_get_by_index (&init_net, p->link); + ldev =dev_get_by_index (net, p->link); -if (unlikely (!ipv6_chk_addr (&init_net, &p->laddr, ldev,0 ))) +if (unlikely (!ipv6_chk_addr (net, &p->laddr, ldev,0 )))printk (KERN_WARNING "%s xmit: Local address not yet configured!\n" , p->name);else if (!ipv6_addr_is_multicast (&p->raddr) && -unlikely (ipv6_chk_addr (&init_net, &p->raddr,NULL ,0 ))) +unlikely (ipv6_chk_addr (net, &p->raddr,NULL ,0 ))) printk(KERN_WARNING "%s xmit: Routing loop! " "Remote address found on this node!\n",
@@ -858,7 +861,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,if ((dst =ip6_tnl_dst_check (t)) !=NULL )dst_hold (dst);else { - dst =ip6_route_output (&init_net,NULL , fl); + dst =ip6_route_output (dev_net (dev),NULL , fl);if (dst->error ||xfrm_lookup (&dst, fl,NULL ,0 ) <0 ) goto tx_err_link_failure;
@@ -1123,7 +1126,8 @@ static void ip6_tnl_link_config(struct ip6_tnl *t)int strict = (ipv6_addr_type (&p->raddr) & (IPV6_ADDR_MULTICAST |IPV6_ADDR_LINKLOCAL )); -struct rt6_info *rt =rt6_lookup (&init_net, &p->raddr, &p->laddr, +struct rt6_info *rt =rt6_lookup (dev_net (dev), + &p->raddr, &p->laddr, p->link, strict);if (rt ==NULL )
Signature · 1 line
1.5.3.4
PATCH 7/7 : Allow to create IP6 tunnels in net namespaces.
In reply to Pavel EmelyanovAnd no need in some IPPROTO_XXX enabling, since ipv6 code doesn't have any filtering.
So, just set proper net and mark device with NETNS_LOCAL.
--- net/ipv6/ip6_tunnel.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-)
net/ipv6/ip6_tunnel.c +3 -0
@@ -243,6 +243,8 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct ip6_tnl_parm *p)if (dev ==NULL ) goto failed; +dev_net_set (dev, net); +if (strchr (name,'%' )) {if (dev_alloc_name (dev, name) <0 ) goto failed_free;
@@ -1341,6 +1343,7 @@ static void ip6_tnl_dev_setup(struct net_device *dev) dev->mtu =ETH_DATA_LEN -sizeof (struct ipv6hdr ); dev->flags |=IFF_NOARP ; dev->addr_len =sizeof (struct in6_addr ); + dev->features |=NETIF_F_NETNS_LOCAL ; }
Signature · 1 line
1.5.3.4
David Miller
maintainerFrom: Pavel Emelyanov <[email protected]>
Date: Tue, 15 Apr 2008 17:58:16 +0400
Quoted 3 lines
This is the last tunnel to virtualize.
Signed-off-by Pavel Emelyanov <[email protected]>
All applied and pushed to net-2.6.26, thanks again.