netns: make IPv6 multicast forwarding per-namespace
Subsystems (3)
cover netns: make IPv6 multicast forwarding per-namespace
This patchset introduces the support for network namespaces in IPv6 multicast forwarding code (net/ipv6/ip6mr.c).
The first patches in the series moves global data from ip6mr.c into struct netns_ipv6 to prepare netns support. Data are still referenced in init_net only. One of these patches makes the related /proc entries per-namespace.
The last patch does the main job and enables the network namespace support by replacing all the init_net references with the proper net retrieved from sockets or net devices.
The patchset applies on top of net-next-2.6
Regards,
Benjamin
PATCH 1/8 netns: ip6mr: allocate mroute6_socket per-namespace.
Preliminary work to make IPv6 multicast forwarding netns-aware.
Make IPv6 multicast forwarding mroute6_socket per-namespace, moves it into struct netns_ipv6.
At the moment, mroute6_socket is only referenced in init_net.
--- include/linux/mroute6.h | 8 ++++++-- include/net/netns/ipv6.h | 3 +++ net/ipv6/ip6_output.c | 3 ++- net/ipv6/ip6mr.c | 22 ++++++++++------------ 4 files changed, 21 insertions(+), 15 deletions(-)
include/linux/mroute6.h +6 -2
@@ -117,6 +117,7 @@ struct sioc_mif_req6#include <linux/pim.h> #include <linux/skbuff.h> /* for struct sk_buff_head */ +#include <net/net_namespace.h> #ifdef CONFIG_IPV6_MROUTE static inline int ip6_mroute_opt (int opt)
@@ -232,10 +233,13 @@ struct rtmsg;extern int ip6mr_get_route (struct sk_buff *skb,struct rtmsg *rtm,int nowait);#ifdef CONFIG_IPV6_MROUTE -extern struct sock *mroute6_socket; +static inline struct sock *mroute6_socket (struct net *net) +{ +return net->ipv6.mroute6_sk; +}extern int ip6mr_sk_done (struct sock *sk);#else -#define mroute6_socket NULL +static inline struct sock *mroute6_socket (struct net *net) {return NULL ; }static inline int ip6mr_sk_done (struct sock *sk) {return 0 ; }#endif #endif
include/net/netns/ipv6.h +3 -0
@@ -55,5 +55,8 @@ struct netns_ipv6 {struct sock *ndisc_sk;struct sock *tcp_sk;struct sock *igmp_sk; +#ifdef CONFIG_IPV6_MROUTE +struct sock *mroute6_sk; +#endif };#endif
net/ipv6/ip6_output.c +2 -1
@@ -137,7 +137,8 @@ static int ip6_output2(struct sk_buff *skb)struct inet6_dev *idev =ip6_dst_idev (skb->dst);if (!(dev->flags &IFF_LOOPBACK ) && (!np || np->mc_loop) && - ((mroute6_socket && !(IP6CB (skb)->flags &IP6SKB_FORWARDED )) || + ((mroute6_socket (dev_net (dev)) && + !(IP6CB (skb)->flags &IP6SKB_FORWARDED )) ||ipv6_chk_mcast_addr (dev, &ipv6_hdr (skb)->daddr, &ipv6_hdr (skb)->saddr))) {struct sk_buff *newskb =skb_clone (skb,GFP_ATOMIC );
net/ipv6/ip6mr.c +10 -12
@@ -49,9 +49,6 @@#include <net/addrconf.h> #include <linux/netfilter_ipv6.h> -struct sock *mroute6_socket; - -/* Big lock, protecting vif table, mrt cache and mroute socket state. Note that the changes are semaphored via rtnl_lock. */
@@ -820,7 +817,7 @@ static int ip6mr_cache_report(struct sk_buff *pkt, mifi_t mifi, int assert)skb_pull (skb,sizeof (struct ipv6hdr )); } -if (mroute6_socket ==NULL ) { +if (init_net.ipv6.mroute6_sk ==NULL ) {kfree_skb (skb);return -EINVAL ; }
@@ -828,7 +825,8 @@ static int ip6mr_cache_report(struct sk_buff *pkt, mifi_t mifi, int assert)/* * Deliver to user space multicast routing algorithms */ -if ((ret =sock_queue_rcv_skb (mroute6_socket, skb)) <0 ) { + ret =sock_queue_rcv_skb (init_net.ipv6.mroute6_sk, skb); +if (ret <0 ) {if (net_ratelimit ())printk (KERN_WARNING "mroute6: pending queue full, dropping entries.\n" );kfree_skb (skb);
@@ -1145,8 +1143,8 @@ static int ip6mr_sk_init(struct sock *sk)rtnl_lock ();write_lock_bh (&mrt_lock); -if (likely (mroute6_socket ==NULL )) - mroute6_socket = sk; +if (likely (init_net.ipv6.mroute6_sk ==NULL )) + init_net.ipv6.mroute6_sk = sk;else err = -EADDRINUSE ;write_unlock_bh (&mrt_lock);
@@ -1161,9 +1159,9 @@ int ip6mr_sk_done(struct sock *sk)int err =0 ;rtnl_lock (); -if (sk == mroute6_socket) { +if (sk == init_net.ipv6.mroute6_sk) {write_lock_bh (&mrt_lock); - mroute6_socket =NULL ; + init_net.ipv6.mroute6_sk =NULL ;write_unlock_bh (&mrt_lock);mroute_clean_tables (sk);
@@ -1189,7 +1187,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, intmifi_t mifi;if (optname !=MRT6_INIT ) { -if (sk != mroute6_socket && !capable (CAP_NET_ADMIN )) +if (sk != init_net.ipv6.mroute6_sk && !capable (CAP_NET_ADMIN ))return -EACCES ; }
@@ -1214,7 +1212,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, intif (vif.mif6c_mifi >=MAXMIFS )return -ENFILE ;rtnl_lock (); - ret =mif6_add (&vif, sk == mroute6_socket); + ret =mif6_add (&vif, sk == init_net.ipv6.mroute6_sk);rtnl_unlock ();return ret;
@@ -1242,7 +1240,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, intif (optname ==MRT6_DEL_MFC ) ret =ip6mr_mfc_delete (&mfc);else - ret =ip6mr_mfc_add (&mfc, sk == mroute6_socket); + ret =ip6mr_mfc_add (&mfc, sk == init_net.ipv6.mroute6_sk);rtnl_unlock ();return ret;
PATCH 2/8 netns: ip6mr: dynamically allocates vif6_table
In reply to Benjamin TheryPreliminary work to make IPv6 multicast forwarding netns-aware.
Dynamically allocates interface table vif6_table and moves it to struct netns_ipv6, and updates MIF_EXISTS() macro.
At the moment, vif6_table is only referenced in init_net.
--- include/net/netns/ipv6.h | 2 + net/ipv6/ip6mr.c | 107 +++++++++++++++++++++++++++++----------------- 2 files changed, 70 insertions(+), 39 deletions(-)
include/net/netns/ipv6.h +2 -0
@@ -57,6 +57,8 @@ struct netns_ipv6 {struct sock *igmp_sk;#ifdef CONFIG_IPV6_MROUTE struct sock *mroute6_sk; +struct mif_device *vif6_table; +int maxvif; #endif };#endif
net/ipv6/ip6mr.c +68 -39
266 lines not on this page · raw message
PATCH 3/8 netns: ip6mr: Dynamically allocates mfc6_cache_array
In reply to Benjamin TheryPreliminary work to make IPv6 multicast forwarding netns-aware.
Dynamically allocates IPv6 multicast forwarding cache, mfc6_cache_array, and moves it to struct netns_ipv6.
At the moment, mfc6_cache_array is only referenced in init_net.
Replace 'ARRAY_SIZE(mfc6_cache_array)' with mfc6_cache_array size: MFC6_LINES.
--- include/net/netns/ipv6.h | 1 + net/ipv6/ip6mr.c | 47 ++++++++++++++++++++++++++++++--------------- 2 files changed, 32 insertions(+), 16 deletions(-)
include/net/netns/ipv6.h +1 -0
@@ -57,6 +57,7 @@ struct netns_ipv6 {struct sock *igmp_sk;#ifdef CONFIG_IPV6_MROUTE struct sock *mroute6_sk; +struct mfc6_cache **mfc6_cache_array;struct mif_device *vif6_table;int maxvif;#endif
net/ipv6/ip6mr.c +31 -16
117 lines not on this page · raw message
PATCH 4/8 netns: ip6mr: Declare mroute_do_assert and mroute_do_pim per-namespace
In reply to Benjamin TheryPreliminary work to make IPv6 multicast forwarding netns-aware.
Declare IPv6 multicast forwarding variables 'mroute_do_assert' and 'mroute_do_pim' per-namespace in struct netns_ipv6.
At the moment, these variables are only referenced in init_net.
--- include/net/netns/ipv6.h | 2 ++ net/ipv6/ip6mr.c | 26 ++++++++++---------------- 2 files changed, 12 insertions(+), 16 deletions(-)
include/net/netns/ipv6.h +2 -0
@@ -60,6 +60,8 @@ struct netns_ipv6 {struct mfc6_cache **mfc6_cache_array;struct mif_device *vif6_table;int maxvif; +int mroute_do_assert; +int mroute_do_pim; #endif };#endif
net/ipv6/ip6mr.c +10 -16
@@ -61,13 +61,6 @@ static DEFINE_RWLOCK(mrt_lock);#define MIF_EXISTS (_net, _idx) ((_net)->ipv6.vif6_table[_idx].dev != NULL) -static int mroute_do_assert;/* Set in PIM assert */ -#ifdef CONFIG_IPV6_PIMSM_V2 -static int mroute_do_pim; -#else -#define mroute_do_pim 0 -#endif -static struct mfc6_cache *mfc_unres_queue;/* Queue of unresolved entries */ static atomic_t cache_resolve_queue_len;/* Size of unresolved */
@@ -1296,7 +1289,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, intint v;if (get_user (v, (int __user *)optval))return -EFAULT ; - mroute_do_assert = !!v; + init_net.ipv6.mroute_do_assert = !!v;return 0 ; }
@@ -1309,10 +1302,10 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int v = !!v;rtnl_lock (); ret =0 ; -if (v != mroute_do_pim) { - mroute_do_pim = v; - mroute_do_assert = v; -if (mroute_do_pim) +if (v != init_net.ipv6.mroute_do_pim) { + init_net.ipv6.mroute_do_pim = v; + init_net.ipv6.mroute_do_assert = v; +if (init_net.ipv6.mroute_do_pim) ret =inet6_add_protocol (&pim6_protocol,IPPROTO_PIM );else
@@ -1351,11 +1344,11 @@ int ip6_mroute_getsockopt(struct sock *sk, int optname, char __user *optval,break ;#ifdef CONFIG_IPV6_PIMSM_V2 case MRT6_PIM : - val = mroute_do_pim; + val = init_net.ipv6.mroute_do_pim;break ;#endif case MRT6_ASSERT : - val = mroute_do_assert; + val = init_net.ipv6.mroute_do_assert;break ;default :return -ENOPROTOOPT ;
@@ -1543,13 +1536,14 @@ static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache) cache->mfc_un.res.wrong_if++; true_vifi =ip6mr_find_vif (skb->dev); -if (true_vifi >=0 && mroute_do_assert && +if (true_vifi >=0 && init_net.ipv6.mroute_do_assert &&/* pimsm uses asserts, when switching from RPT to SPT, so that we cannot check that packet arrived on an oif. It is bad, but otherwise we would need to move pretty large chunk of pimd to kernel. Ough... --ANK */ - (mroute_do_pim || cache->mfc_un.res.ttls[true_vifi] <255 ) && + (init_net.ipv6.mroute_do_pim || + cache->mfc_un.res.ttls[true_vifi] <255 ) &&time_after (jiffies, cache->mfc_un.res.last_assert +MFC_ASSERT_THRESH )) { cache->mfc_un.res.last_assert = jiffies;
PATCH 5/8 netns: ip6mr: store netns in struct mfc6_cache
In reply to Benjamin TheryThis patch stores into struct mfc6_cache the network namespace each mfc6_cache belongs to. The new member is mfc6_net.
mfc6_net is assigned at cache allocation and doesn't change during the rest of the cache entry life.
This will help to retrieve the current netns around the IPv6 multicast forwarding code.
At the moment, all mfc6_cache are allocated in init_net.
Changelog:
==========
* Use write_pnet()/read_pnet() to set and get mfc6_net.
--- include/linux/mroute6.h | 15 +++++++++++++++ net/ipv6/ip6mr.c | 28 +++++++++++++++++++--------- 2 files changed, 34 insertions(+), 9 deletions(-)
include/linux/mroute6.h +15 -0
@@ -188,6 +188,9 @@ struct mif_devicestruct mfc6_cache {struct mfc6_cache *next;/* Next entry on cache line */ +#ifdef CONFIG_NET_NS +struct net *mfc6_net; +#endif struct in6_addr mf6c_mcastgrp;/* Group the entry belongs to */ struct in6_addr mf6c_origin;/* Source of packet */ mifi_t mf6c_parent;/* Source interface */
@@ -210,6 +213,18 @@ struct mfc6_cache } mfc_un; }; +static inline +struct net *mfc6_net (const struct mfc6_cache *mfc) +{ +return read_pnet (&mfc->mfc6_net); +} + +static inline +void mfc6_net_set (struct mfc6_cache *mfc,struct net *net) +{ +write_pnet (&mfc->mfc6_net,hold_net (net)); +} +#define MFC_STATIC 1#define MFC_NOTIFY 2
net/ipv6/ip6mr.c +19 -9
@@ -498,6 +498,14 @@ static int mif6_delete(int vifi)return 0 ; } +static inline void ip6mr_cache_free (struct mfc6_cache *c) +{ +#ifdef CONFIG_NET_NS +release_net (c->mfc6_net); +#endif +kmem_cache_free (mrt_cachep, c); +} +/* Destroy an unresolved cache entry, killing queued skbs and reporting error to netlink readers. */
@@ -520,7 +528,7 @@ static void ip6mr_destroy_unres(struct mfc6_cache *c)kfree_skb (skb); } -kmem_cache_free (mrt_cachep, c); +ip6mr_cache_free (c); }
@@ -677,22 +685,24 @@ static struct mfc6_cache *ip6mr_cache_find(struct in6_addr *origin, struct in6_a/* * Allocate a multicast cache entry */ -static struct mfc6_cache *ip6mr_cache_alloc (void ) +static struct mfc6_cache *ip6mr_cache_alloc (struct net *net) {struct mfc6_cache *c =kmem_cache_zalloc (mrt_cachep,GFP_KERNEL );if (c ==NULL )return NULL ; c->mfc_un.res.minvif =MAXMIFS ; +mfc6_net_set (c, net);return c; } -static struct mfc6_cache *ip6mr_cache_alloc_unres (void ) +static struct mfc6_cache *ip6mr_cache_alloc_unres (struct net *net) {struct mfc6_cache *c =kmem_cache_zalloc (mrt_cachep,GFP_ATOMIC );if (c ==NULL )return NULL ;skb_queue_head_init (&c->mfc_un.unres.unresolved); c->mfc_un.unres.expires = jiffies +10 *HZ ; +mfc6_net_set (c, net);return c; }
@@ -848,7 +858,7 @@ ip6mr_cache_unresolved(mifi_t mifi, struct sk_buff *skb)*/ if (atomic_read (&cache_resolve_queue_len) >=10 || - (c =ip6mr_cache_alloc_unres ()) ==NULL ) { + (c =ip6mr_cache_alloc_unres (&init_net)) ==NULL ) {spin_unlock_bh (&mfc_unres_lock);kfree_skb (skb);
@@ -871,7 +881,7 @@ ip6mr_cache_unresolved(mifi_t mifi, struct sk_buff *skb)*/ spin_unlock_bh (&mfc_unres_lock); -kmem_cache_free (mrt_cachep, c); +ip6mr_cache_free (c);kfree_skb (skb);return err; }
@@ -917,7 +927,7 @@ static int ip6mr_mfc_delete(struct mf6cctl *mfc) *cp = c->next;write_unlock_bh (&mrt_lock); -kmem_cache_free (mrt_cachep, c); +ip6mr_cache_free (c);return 0 ; } }
@@ -1081,7 +1091,7 @@ static int ip6mr_mfc_add(struct mf6cctl *mfc, int mrtsock)if (!ipv6_addr_is_multicast (&mfc->mf6cc_mcastgrp.sin6_addr))return -EINVAL ; - c =ip6mr_cache_alloc (); + c =ip6mr_cache_alloc (&init_net);if (c ==NULL )return -ENOMEM ;
@@ -1116,7 +1126,7 @@ static int ip6mr_mfc_add(struct mf6cctl *mfc, int mrtsock)if (uc) {ip6mr_cache_resolve (uc, c); -kmem_cache_free (mrt_cachep, uc); +ip6mr_cache_free (uc); }return 0 ; }
@@ -1153,7 +1163,7 @@ static void mroute_clean_tables(struct sock *sk) *cp = c->next;write_unlock_bh (&mrt_lock); -kmem_cache_free (mrt_cachep, c); +ip6mr_cache_free (c); } }
PATCH 6/8 netns: ip6mr: declare reg_vif_num per-namespace
In reply to Benjamin TheryPreliminary work to make IPv6 multicast forwarding netns-aware.
Declare variable 'reg_vif_num' per-namespace, moves into struct netns_ipv6.
At the moment, this variable is only referenced in init_net.
--- include/net/netns/ipv6.h | 3 +++ net/ipv6/ip6mr.c | 19 +++++++++++-------- 2 files changed, 14 insertions(+), 8 deletions(-)
include/net/netns/ipv6.h +3 -0
@@ -62,6 +62,9 @@ struct netns_ipv6 {int maxvif;int mroute_do_assert;int mroute_do_pim; +#ifdef CONFIG_IPV6_PIMSM_V2 +int mroute_reg_vif_num; +#endif #endif };#endif
net/ipv6/ip6mr.c +11 -8
@@ -334,13 +334,13 @@ static struct file_operations ip6mr_mfc_fops = {#endif #ifdef CONFIG_IPV6_PIMSM_V2 -static int reg_vif_num =-1 ;static int pim6_rcv (struct sk_buff *skb) {struct pimreghdr *pim;struct ipv6hdr *encap;struct net_device *reg_dev =NULL ; +int reg_vif_num = init_net.ipv6.mroute_reg_vif_num;if (!pskb_may_pull (skb,sizeof (*pim) +sizeof (*encap))) goto drop;
@@ -402,7 +402,7 @@ static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev)read_lock (&mrt_lock); dev->stats.tx_bytes += skb->len; dev->stats.tx_packets++; -ip6mr_cache_report (skb, reg_vif_num,MRT6MSG_WHOLEPKT ); +ip6mr_cache_report (skb, init_net.ipv6.mroute_reg_vif_num,MRT6MSG_WHOLEPKT );read_unlock (&mrt_lock);kfree_skb (skb);return 0 ;
@@ -474,8 +474,8 @@ static int mif6_delete(int vifi) }#ifdef CONFIG_IPV6_PIMSM_V2 -if (vifi == reg_vif_num) - reg_vif_num =-1 ; +if (vifi == init_net.ipv6.mroute_reg_vif_num) + init_net.ipv6.mroute_reg_vif_num =-1 ;#endif if (vifi +1 == init_net.ipv6.maxvif) {
@@ -613,7 +613,7 @@ static int mif6_add(struct mif6ctl *vifc, int mrtsock)* Special Purpose VIF in PIM * All the packets will be sent to the daemon */ -if (reg_vif_num >=0 ) +if (init_net.ipv6.mroute_reg_vif_num >=0 )return -EADDRINUSE ; dev =ip6mr_reg_vif ();if (!dev)
@@ -661,7 +661,7 @@ static int mif6_add(struct mif6ctl *vifc, int mrtsock) v->dev = dev;#ifdef CONFIG_IPV6_PIMSM_V2 if (v->flags &MIFF_REGISTER ) - reg_vif_num = vifi; + init_net.ipv6.mroute_reg_vif_num = vifi;#endif if (vifi +1 > init_net.ipv6.maxvif) init_net.ipv6.maxvif = vifi +1 ;
@@ -780,7 +780,7 @@ static int ip6mr_cache_report(struct sk_buff *pkt, mifi_t mifi, int assert) msg = (struct mrt6msg *)skb_transport_header (skb); msg->im6_mbz =0 ; msg->im6_msgtype =MRT6MSG_WHOLEPKT ; - msg->im6_mif = reg_vif_num; + msg->im6_mif = init_net.ipv6.mroute_reg_vif_num; msg->im6_pad =0 ;ipv6_addr_copy (&msg->im6_src, &ipv6_hdr (pkt)->saddr);ipv6_addr_copy (&msg->im6_dst, &ipv6_hdr (pkt)->daddr);
@@ -966,7 +966,6 @@ static struct notifier_block ip6_mr_notifier = {static int __net_init ip6mr_net_init (struct net *net) {int err =0 ; - net->ipv6.vif6_table =kcalloc (MAXMIFS ,sizeof (struct mif_device ),GFP_KERNEL );if (!net->ipv6.vif6_table) {
@@ -982,6 +981,10 @@ static int __net_init ip6mr_net_init(struct net *net) err = -ENOMEM ; goto fail_mfc6_cache; } + +#ifdef CONFIG_IPV6_PIMSM_V2 + net->ipv6.mroute_reg_vif_num =-1 ; +#endif return 0 ; fail_mfc6_cache:
PATCH 7/8 netns: ip6mr: declare ip6mr /proc/net entries per-namespace
In reply to Benjamin TheryDeclare IPv6 multicast forwarding /proc/net entries per-namespace:/proc/net/ip6_mr_vif/proc/net/ip6_mr_cache
--- net/ipv6/ip6mr.c | 104 ++++++++++++++++++++++++++++++----------------------- 1 files changed, 59 insertions(+), 45 deletions(-)
net/ipv6/ip6mr.c +59 -45
@@ -91,19 +91,21 @@ static struct timer_list ipmr_expire_timer;#ifdef CONFIG_PROC_FS struct ipmr_mfc_iter { +struct seq_net_private p;struct mfc6_cache **cache;int ct; }; -static struct mfc6_cache *ipmr_mfc_seq_idx (struct ipmr_mfc_iter *it,loff_t pos) +static struct mfc6_cache *ipmr_mfc_seq_idx (struct net *net, +struct ipmr_mfc_iter *it,loff_t pos) {struct mfc6_cache *mfc; - it->cache = init_net.ipv6.mfc6_cache_array; + it->cache = net->ipv6.mfc6_cache_array;read_lock (&mrt_lock);for (it->ct =0 ; it->ct <MFC6_LINES ; it->ct++) -for (mfc = init_net.ipv6.mfc6_cache_array[it->ct]; +for (mfc = net->ipv6.mfc6_cache_array[it->ct]; mfc; mfc = mfc->next)if (pos-- ==0 )return mfc;
@@ -128,17 +130,19 @@ static struct mfc6_cache *ipmr_mfc_seq_idx(struct ipmr_mfc_iter *it, loff_t pos)*/ struct ipmr_vif_iter { +struct seq_net_private p;int ct; }; -static struct mif_device *ip6mr_vif_seq_idx (struct ipmr_vif_iter *iter, +static struct mif_device *ip6mr_vif_seq_idx (struct net *net, +struct ipmr_vif_iter *iter,loff_t pos) { -for (iter->ct =0 ; iter->ct < init_net.ipv6.maxvif; ++iter->ct) { -if (!MIF_EXISTS (&init_net, iter->ct)) +for (iter->ct =0 ; iter->ct < net->ipv6.maxvif; ++iter->ct) { +if (!MIF_EXISTS (net, iter->ct))continue ;if (pos-- ==0 ) -return &init_net.ipv6.vif6_table[iter->ct]; +return &net->ipv6.vif6_table[iter->ct]; }return NULL ; }
@@ -146,23 +150,26 @@ static struct mif_device *ip6mr_vif_seq_idx(struct ipmr_vif_iter *iter,static void *ip6mr_vif_seq_start (struct seq_file *seq,loff_t *pos)__acquires (mrt_lock) { +struct net *net =seq_file_net (seq); +read_lock (&mrt_lock); -return (*pos ?ip6mr_vif_seq_idx (seq->private, *pos -1 ) - :SEQ_START_TOKEN ); +return *pos ?ip6mr_vif_seq_idx (net, seq->private, *pos -1 ) + :SEQ_START_TOKEN ; }static void *ip6mr_vif_seq_next (struct seq_file *seq,void *v,loff_t *pos) {struct ipmr_vif_iter *iter = seq->private; +struct net *net =seq_file_net (seq); ++*pos;if (v ==SEQ_START_TOKEN ) -return ip6mr_vif_seq_idx (iter,0 ); +return ip6mr_vif_seq_idx (net, iter,0 ); -while (++iter->ct < init_net.ipv6.maxvif) { -if (!MIF_EXISTS (&init_net, iter->ct)) +while (++iter->ct < net->ipv6.maxvif) { +if (!MIF_EXISTS (net, iter->ct))continue ; -return &init_net.ipv6.vif6_table[iter->ct]; +return &net->ipv6.vif6_table[iter->ct]; }return NULL ; }
@@ -175,6 +182,8 @@ static void ip6mr_vif_seq_stop(struct seq_file *seq, void *v)static int ip6mr_vif_seq_show (struct seq_file *seq,void *v) { +struct net *net =seq_file_net (seq); +if (v ==SEQ_START_TOKEN ) {seq_puts (seq,"Interface BytesIn PktsIn BytesOut PktsOut Flags\n" );
@@ -184,7 +193,7 @@ static int ip6mr_vif_seq_show(struct seq_file *seq, void *v)seq_printf (seq,"%2td %-10s %8ld %7ld %8ld %7ld %05X\n" , - vif - init_net.ipv6.vif6_table, + vif - net->ipv6.vif6_table, name, vif->bytes_in, vif->pkt_in, vif->bytes_out, vif->pkt_out, vif->flags);
@@ -201,8 +210,8 @@ static struct seq_operations ip6mr_vif_seq_ops = {static int ip6mr_vif_open (struct inode *inode,struct file *file) { -return seq_open_private (file, &ip6mr_vif_seq_ops, -sizeof (struct ipmr_vif_iter )); +return seq_open_net (inode, file, &ip6mr_vif_seq_ops, +sizeof (struct ipmr_vif_iter )); }static struct file_operations ip6mr_vif_fops = {
@@ -210,24 +219,27 @@ static struct file_operations ip6mr_vif_fops = { .open = ip6mr_vif_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = seq_release_net, };static void *ipmr_mfc_seq_start (struct seq_file *seq,loff_t *pos) { -return (*pos ?ipmr_mfc_seq_idx (seq->private, *pos -1 ) - :SEQ_START_TOKEN ); +struct net *net =seq_file_net (seq); + +return *pos ?ipmr_mfc_seq_idx (net, seq->private, *pos -1 ) + :SEQ_START_TOKEN ; }static void *ipmr_mfc_seq_next (struct seq_file *seq,void *v,loff_t *pos) {struct mfc6_cache *mfc = v;struct ipmr_mfc_iter *it = seq->private; +struct net *net =seq_file_net (seq); ++*pos;if (v ==SEQ_START_TOKEN ) -return ipmr_mfc_seq_idx (seq->private,0 ); +return ipmr_mfc_seq_idx (net, seq->private,0 );if (mfc->next)return mfc->next;
@@ -235,10 +247,10 @@ static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)if (it->cache == &mfc_unres_queue) goto end_of_list; -BUG_ON (it->cache != init_net.ipv6.mfc6_cache_array); +BUG_ON (it->cache != net->ipv6.mfc6_cache_array);while (++it->ct <MFC6_LINES ) { - mfc = init_net.ipv6.mfc6_cache_array[it->ct]; + mfc = net->ipv6.mfc6_cache_array[it->ct];if (mfc)return mfc; }
@@ -263,16 +275,18 @@ static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)static void ipmr_mfc_seq_stop (struct seq_file *seq,void *v) {struct ipmr_mfc_iter *it = seq->private; +struct net *net =seq_file_net (seq);if (it->cache == &mfc_unres_queue)spin_unlock_bh (&mfc_unres_lock); -else if (it->cache == init_net.ipv6.mfc6_cache_array) +else if (it->cache == net->ipv6.mfc6_cache_array)read_unlock (&mrt_lock); }static int ipmr_mfc_seq_show (struct seq_file *seq,void *v) {int n; +struct net *net =seq_file_net (seq);if (v ==SEQ_START_TOKEN ) { seq_puts(seq,
@@ -294,7 +308,7 @@ static int ipmr_mfc_seq_show(struct seq_file *seq, void *v) mfc->mfc_un.res.wrong_if);for (n = mfc->mfc_un.res.minvif; n < mfc->mfc_un.res.maxvif; n++) { -if (MIF_EXISTS (&init_net, n) && +if (MIF_EXISTS (net, n) && mfc->mfc_un.res.ttls[n] <255 ) seq_printf(seq, " %2d:%-3d",
@@ -320,8 +334,8 @@ static struct seq_operations ipmr_mfc_seq_ops = {static int ipmr_mfc_open (struct inode *inode,struct file *file) { -return seq_open_private (file, &ipmr_mfc_seq_ops, -sizeof (struct ipmr_mfc_iter )); +return seq_open_net (inode, file, &ipmr_mfc_seq_ops, +sizeof (struct ipmr_mfc_iter )); }static struct file_operations ip6mr_mfc_fops = {
@@ -329,7 +343,7 @@ static struct file_operations ip6mr_mfc_fops = { .open = ipmr_mfc_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = seq_release_net, };#endif
@@ -985,8 +999,22 @@ static int __net_init ip6mr_net_init(struct net *net)#ifdef CONFIG_IPV6_PIMSM_V2 net->ipv6.mroute_reg_vif_num =-1 ;#endif + +#ifdef CONFIG_PROC_FS + err = -ENOMEM ; +if (!proc_net_fops_create (net,"ip6_mr_vif" ,0 , &ip6mr_vif_fops)) + goto proc_vif_fail; +if (!proc_net_fops_create (net,"ip6_mr_cache" ,0 , &ip6mr_mfc_fops)) + goto proc_cache_fail; +#endif return 0 ; +#ifdef CONFIG_PROC_FS +proc_cache_fail: +proc_net_remove (net,"ip6_mr_vif" ); +proc_vif_fail: +kfree (net->ipv6.mfc6_cache_array); +#endif fail_mfc6_cache:kfree (net->ipv6.vif6_table); fail:
@@ -995,6 +1023,10 @@ fail: static void __net_exit ip6mr_net_exit(struct net *net) { +#ifdef CONFIG_PROC_FS +proc_net_remove (net,"ip6_mr_cache" ); +proc_net_remove (net,"ip6_mr_vif" ); +#endif kfree (net->ipv6.mfc6_cache_array);kfree (net->ipv6.vif6_table); }
@@ -1023,21 +1055,7 @@ int __init ip6_mr_init(void) err =register_netdevice_notifier (&ip6_mr_notifier);if (err) goto reg_notif_fail; -#ifdef CONFIG_PROC_FS - err = -ENOMEM ; -if (!proc_net_fops_create (&init_net,"ip6_mr_vif" ,0 , &ip6mr_vif_fops)) - goto proc_vif_fail; -if (!proc_net_fops_create (&init_net,"ip6_mr_cache" , -0 , &ip6mr_mfc_fops)) - goto proc_cache_fail; -#endif return 0 ; -#ifdef CONFIG_PROC_FS -proc_cache_fail: -proc_net_remove (&init_net,"ip6_mr_vif" ); -proc_vif_fail: -unregister_netdevice_notifier (&ip6_mr_notifier); -#endif reg_notif_fail:del_timer (&ipmr_expire_timer);unregister_pernet_subsys (&ip6mr_net_ops);
@@ -1048,10 +1066,6 @@ reg_pernet_fail:void ip6_mr_cleanup (void ) { -#ifdef CONFIG_PROC_FS -proc_net_remove (&init_net,"ip6_mr_cache" ); -proc_net_remove (&init_net,"ip6_mr_vif" ); -#endif unregister_netdevice_notifier (&ip6_mr_notifier);del_timer (&ipmr_expire_timer);unregister_pernet_subsys (&ip6mr_net_ops);
PATCH 8/8 ipv6: netns: enable namespace support in ipv6 multicast forwarding code
In reply to Benjamin TheryThis last patch makes the appropriate changes to use and propagate the network namespace where needed in IPv6 multicast forwarding code.
This consists mainly in replacing all the remaining init_net occurences with current netns pointer retrieved from sockets, net devices or mfc6_caches depending on the routines' contexts.
Some routines receive a new 'struct net' parameter to propagate the netns:
* ip6mr_get_route
* ip6mr_cache_report
* ip6mr_cache_find
* ip6mr_cache_unresolved
* mif6_add/mif6_delete
* ip6mr_mfc_add/ip6mr_mfc_delete
All the IPv6 multicast forwarding variables moved to struct netns_ipv6 by the previous patches are now referenced in the correct namespace.
Changelog:
==========
* Take into account the net associated to mfc6_cache when matching entries in mfc_unres_queue list.
* Call mroute_clean_tables() in ip6mr_net_exit() to free memory allocated per-namespace.
* Call dev_net_set() in ip6mr_reg_vif() to initialize dev->nd_net correctly.
--- include/linux/mroute6.h | 3 +- net/ipv6/ip6mr.c | 235 ++++++++++++++++++++++++++--------------------- net/ipv6/route.c | 2 +- 3 files changed, 133 insertions(+), 107 deletions(-)
include/linux/mroute6.h +2 -1
@@ -245,7 +245,8 @@ void mfc6_net_set(struct mfc6_cache *mfc, struct net *net)#ifdef __KERNEL__struct rtmsg ; -extern int ip6mr_get_route (struct sk_buff *skb,struct rtmsg *rtm,int nowait); +extern int ip6mr_get_route (struct net *net,struct sk_buff *skb, +struct rtmsg *rtm,int nowait);#ifdef CONFIG_IPV6_MROUTE static inline struct sock *mroute6_socket (struct net *net)
net/ipv6/ip6mr.c +130 -105
695 lines not on this page · raw message
net/ipv6/route.c +1 -1
@@ -2194,7 +2194,7 @@ static int rt6_fill_node(struct net *net,if (iif) {#ifdef CONFIG_IPV6_MROUTE if (ipv6_addr_is_multicast (&rt->rt6i_dst.addr)) { -int err =ip6mr_get_route (skb, rtm, nowait); +int err =ip6mr_get_route (net, skb, rtm, nowait);if (err <=0 ) {if (!nowait) {if (err ==0 )
Dave,
While doing some more tests on the patchset I've realized that the queue of unresolved entries (mfc_unres_queue) should also be allocated per-netns (or at least counter cache_resolve_queue_len should be).
With the current patchset, the cache for unresolved entries is limited to 10 entries for all namespaces. D'oh.
I'm looking at this issue and will resend the patchset with the missing patch ASAP.
Benjamin
Quoted 18 lines · Benjamin Thery
This patchset introduces the support for network namespaces in IPv6 multicast forwarding code (
net/ipv6/ip6mr.c).The first patches in the series moves global data from
ip6mr.cinto structnetns_ipv6to prepare netns support. Data are still referenced ininit_netonly. One of these patches makes the related /proc entries
per-namespace.The last patch does the main job and enables the network namespace support by replacing all the
init_netreferences with the proper net retrieved from sockets or net devices.The patchset applies on top of net-next-2.6
Regards,
Benjamin
Signature · 3 lines
B e n j a m i n T h e r y - BULL/DT/Open Software R&D http://www.bull.com
David Miller
maintainerFrom: Benjamin Thery <[email protected]>
Date: Tue, 09 Dec 2008 17:56:03 +0100
Quoted 9 lines
While doing some more tests on the patchset I've realized that the queue of unresolved entries (
mfc_unres_queue) should also be allocated per-netns (or at least countercache_resolve_queue_lenshould be).With the current patchset, the cache for unresolved entries is limited to 10 entries for all namespaces. D'oh.
I'm looking at this issue and will resend the patchset with the missing patch ASAP.
Okie dokie.