From ee6b967301b4aa5d4a4b61e2f682f086266db9fb Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 5 Mar 2008 18:30:47 -0800 Subject: [IPV4]: Add 'rtable' field in struct sk_buff to alias 'dst' and avoid casts (Anonymous) unions can help us to avoid ugly casts. A common cast it the (struct rtable *)skb->dst one. Defining an union like : union { struct dst_entry *dst; struct rtable *rtable; }; permits to use skb->rtable in place. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/ipip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/ipv4/ipip.c') diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index dbaed69de06..894bce96284 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -528,7 +528,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) if (!dst) { /* NBMA tunnel */ - if ((rt = (struct rtable*)skb->dst) == NULL) { + if ((rt = skb->rtable) == NULL) { tunnel->stat.tx_fifo_errors++; goto tx_error; } -- cgit v1.2.3 From 10dc4c7bb70533d16184aaaa69e137a7d2b9a3a8 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:03:13 -0700 Subject: [IPIP]: Introduce empty ipip_net structure and net init/exit ops. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/ipip.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'net/ipv4/ipip.c') diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 894bce96284..e39a4c279a2 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -115,10 +115,16 @@ #include #include #include +#include +#include #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); -- cgit v1.2.3 From b9855c54dadc0768dcc3804df1972488783d2267 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:04:13 -0700 Subject: [IPIP]: Make the fallback tunnel device per-net. 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(). Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/ipip.c | 67 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 35 insertions(+), 32 deletions(-) (limited to 'net/ipv4/ipip.c') diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index e39a4c279a2..e657a6605e0 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -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); -- cgit v1.2.3 From b9fae5c9138086d27715a8a0f29d5b55239db35c Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:04:35 -0700 Subject: [IPIP]: Add net/ipip_net argument to some functions. 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. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/ipip.c | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) (limited to 'net/ipv4/ipip.c') diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index e657a6605e0..bc4d4cb89b0 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -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) -- cgit v1.2.3 From cec3ffae1a019f02cd6b5fa291f279c8e9f86157 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:05:03 -0700 Subject: [IPIP]: Use proper net in hash-lookup functions. 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. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/ipip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/ipv4/ipip.c') diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index bc4d4cb89b0..da7147090a1 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -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); -- cgit v1.2.3 From 44d3c299dcfee094f10e0c686ad6588fd36d4f8f Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:05:32 -0700 Subject: [IPIP]: Make tunnels hashes per net. 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. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/ipip.c | 68 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 36 insertions(+), 32 deletions(-) (limited to 'net/ipv4/ipip.c') diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index da7147090a1..9c2939ba7b9 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -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); } -- cgit v1.2.3 From b99f0152e5f96dde31d2b9060b4f1029abc11078 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:05:57 -0700 Subject: [IPIP]: Use proper net in (mostly) routing calls. 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(). Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/ipip.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'net/ipv4/ipip.c') diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 9c2939ba7b9..1de39e1dc43 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -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); -- cgit v1.2.3 From 0a826406d4adf0c4b7cd47f116cb8e8ef65b92a3 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:06:18 -0700 Subject: [IPIP]: Allow to create IPIP tunnels in net namespaces. Set the proper net before calling register_netdev and disable the tunnel device netns changing. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/ipip.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net/ipv4/ipip.c') diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 1de39e1dc43..149111f08e8 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -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) -- cgit v1.2.3