From ce4ff76c15a877a62097807a35518fc808c1853c Mon Sep 17 00:00:00 2001 From: Gao feng Date: Wed, 25 Sep 2013 15:38:44 +0800 Subject: netfilter: ipt_CLUSTERIP: make proc directory per net namespace Create /proc/net/ipt_CLUSTERIP directory for per net namespace. Right now,only allow to create entries under the ipt_CLUSTERIP in init net namespace. Signed-off-by: Gao feng Signed-off-by: Pablo Neira Ayuso --- net/ipv4/netfilter/ipt_CLUSTERIP.c | 70 +++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 19 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index 0b732efd32e2..e66b91b92843 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -64,9 +65,16 @@ static DEFINE_SPINLOCK(clusterip_lock); #ifdef CONFIG_PROC_FS static const struct file_operations clusterip_proc_fops; -static struct proc_dir_entry *clusterip_procdir; #endif +static int clusterip_net_id __read_mostly; + +struct clusterip_net { +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *procdir; +#endif +}; + static inline void clusterip_config_get(struct clusterip_config *c) { @@ -158,6 +166,7 @@ clusterip_config_init(const struct ipt_clusterip_tgt_info *i, __be32 ip, struct net_device *dev) { struct clusterip_config *c; + struct clusterip_net *cn = net_generic(&init_net, clusterip_net_id); c = kzalloc(sizeof(*c), GFP_ATOMIC); if (!c) @@ -180,7 +189,7 @@ clusterip_config_init(const struct ipt_clusterip_tgt_info *i, __be32 ip, /* create proc dir entry */ sprintf(buffer, "%pI4", &ip); c->pde = proc_create_data(buffer, S_IWUSR|S_IRUSR, - clusterip_procdir, + cn->procdir, &clusterip_proc_fops, c); if (!c->pde) { kfree(c); @@ -698,48 +707,71 @@ static const struct file_operations clusterip_proc_fops = { #endif /* CONFIG_PROC_FS */ +static int clusterip_net_init(struct net *net) +{ +#ifdef CONFIG_PROC_FS + struct clusterip_net *cn = net_generic(net, clusterip_net_id); + + cn->procdir = proc_mkdir("ipt_CLUSTERIP", net->proc_net); + if (!cn->procdir) { + pr_err("Unable to proc dir entry\n"); + return -ENOMEM; + } +#endif /* CONFIG_PROC_FS */ + + return 0; +} + +static void clusterip_net_exit(struct net *net) +{ +#ifdef CONFIG_PROC_FS + struct clusterip_net *cn = net_generic(net, clusterip_net_id); + proc_remove(cn->procdir); +#endif +} + +static struct pernet_operations clusterip_net_ops = { + .init = clusterip_net_init, + .exit = clusterip_net_exit, + .id = &clusterip_net_id, + .size = sizeof(struct clusterip_net), +}; + static int __init clusterip_tg_init(void) { int ret; - ret = xt_register_target(&clusterip_tg_reg); + ret = register_pernet_subsys(&clusterip_net_ops); if (ret < 0) return ret; + ret = xt_register_target(&clusterip_tg_reg); + if (ret < 0) + goto cleanup_subsys; + ret = nf_register_hook(&cip_arp_ops); if (ret < 0) goto cleanup_target; -#ifdef CONFIG_PROC_FS - clusterip_procdir = proc_mkdir("ipt_CLUSTERIP", init_net.proc_net); - if (!clusterip_procdir) { - pr_err("Unable to proc dir entry\n"); - ret = -ENOMEM; - goto cleanup_hook; - } -#endif /* CONFIG_PROC_FS */ - pr_info("ClusterIP Version %s loaded successfully\n", CLUSTERIP_VERSION); + return 0; -#ifdef CONFIG_PROC_FS -cleanup_hook: - nf_unregister_hook(&cip_arp_ops); -#endif /* CONFIG_PROC_FS */ cleanup_target: xt_unregister_target(&clusterip_tg_reg); +cleanup_subsys: + unregister_pernet_subsys(&clusterip_net_ops); return ret; } static void __exit clusterip_tg_exit(void) { pr_info("ClusterIP Version %s unloading\n", CLUSTERIP_VERSION); -#ifdef CONFIG_PROC_FS - proc_remove(clusterip_procdir); -#endif + nf_unregister_hook(&cip_arp_ops); xt_unregister_target(&clusterip_tg_reg); + unregister_pernet_subsys(&clusterip_net_ops); /* Wait for completion of call_rcu_bh()'s (clusterip_config_rcu_free) */ rcu_barrier_bh(); -- cgit v1.2.3 From 26a89e435462bfdde586ad062bf190cdbfe53a49 Mon Sep 17 00:00:00 2001 From: Gao feng Date: Wed, 25 Sep 2013 15:38:45 +0800 Subject: netfilter: ipt_CLUSTERIP: make clusterip_list per net namespace clusterip_configs should be per net namespace, so operate cluster in one net namespace won't affect other net namespace. right now, only allow to operate the clusterip_configs of init net namespace. Signed-off-by: Gao feng Signed-off-by: Pablo Neira Ayuso --- net/ipv4/netfilter/ipt_CLUSTERIP.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index e66b91b92843..8ef3e6f38635 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -58,8 +58,6 @@ struct clusterip_config { struct rcu_head rcu; }; -static LIST_HEAD(clusterip_configs); - /* clusterip_lock protects the clusterip_configs list */ static DEFINE_SPINLOCK(clusterip_lock); @@ -70,6 +68,7 @@ static const struct file_operations clusterip_proc_fops; static int clusterip_net_id __read_mostly; struct clusterip_net { + struct list_head configs; #ifdef CONFIG_PROC_FS struct proc_dir_entry *procdir; #endif @@ -124,8 +123,9 @@ static struct clusterip_config * __clusterip_config_find(__be32 clusterip) { struct clusterip_config *c; + struct clusterip_net *cn = net_generic(&init_net, clusterip_net_id); - list_for_each_entry_rcu(c, &clusterip_configs, list) { + list_for_each_entry_rcu(c, &cn->configs, list) { if (c->clusterip == clusterip) return c; } @@ -199,7 +199,7 @@ clusterip_config_init(const struct ipt_clusterip_tgt_info *i, __be32 ip, #endif spin_lock_bh(&clusterip_lock); - list_add_rcu(&c->list, &clusterip_configs); + list_add_rcu(&c->list, &cn->configs); spin_unlock_bh(&clusterip_lock); return c; @@ -709,9 +709,11 @@ static const struct file_operations clusterip_proc_fops = { static int clusterip_net_init(struct net *net) { -#ifdef CONFIG_PROC_FS struct clusterip_net *cn = net_generic(net, clusterip_net_id); + INIT_LIST_HEAD(&cn->configs); + +#ifdef CONFIG_PROC_FS cn->procdir = proc_mkdir("ipt_CLUSTERIP", net->proc_net); if (!cn->procdir) { pr_err("Unable to proc dir entry\n"); -- cgit v1.2.3 From f1e8077f490cff4253b197154bf2affaa0ca08e3 Mon Sep 17 00:00:00 2001 From: Gao feng Date: Wed, 25 Sep 2013 15:38:46 +0800 Subject: netfilter: ipt_CLUSTERIP: make clusterip_lock per net namespace this lock is used for protecting clusterip_configs of per net namespace, it should be per net namespace too. Signed-off-by: Gao feng Signed-off-by: Pablo Neira Ayuso --- net/ipv4/netfilter/ipt_CLUSTERIP.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index 8ef3e6f38635..1bf5aa3096c1 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -58,9 +58,6 @@ struct clusterip_config { struct rcu_head rcu; }; -/* clusterip_lock protects the clusterip_configs list */ -static DEFINE_SPINLOCK(clusterip_lock); - #ifdef CONFIG_PROC_FS static const struct file_operations clusterip_proc_fops; #endif @@ -69,6 +66,9 @@ static int clusterip_net_id __read_mostly; struct clusterip_net { struct list_head configs; + /* lock protects the configs list */ + spinlock_t lock; + #ifdef CONFIG_PROC_FS struct proc_dir_entry *procdir; #endif @@ -99,10 +99,12 @@ clusterip_config_put(struct clusterip_config *c) static inline void clusterip_config_entry_put(struct clusterip_config *c) { + struct clusterip_net *cn = net_generic(&init_net, clusterip_net_id); + local_bh_disable(); - if (atomic_dec_and_lock(&c->entries, &clusterip_lock)) { + if (atomic_dec_and_lock(&c->entries, &cn->lock)) { list_del_rcu(&c->list); - spin_unlock(&clusterip_lock); + spin_unlock(&cn->lock); local_bh_enable(); dev_mc_del(c->dev, c->clustermac); @@ -198,9 +200,9 @@ clusterip_config_init(const struct ipt_clusterip_tgt_info *i, __be32 ip, } #endif - spin_lock_bh(&clusterip_lock); + spin_lock_bh(&cn->lock); list_add_rcu(&c->list, &cn->configs); - spin_unlock_bh(&clusterip_lock); + spin_unlock_bh(&cn->lock); return c; } @@ -713,6 +715,8 @@ static int clusterip_net_init(struct net *net) INIT_LIST_HEAD(&cn->configs); + spin_lock_init(&cn->lock); + #ifdef CONFIG_PROC_FS cn->procdir = proc_mkdir("ipt_CLUSTERIP", net->proc_net); if (!cn->procdir) { -- cgit v1.2.3 From b5ef0f85bf76986e5076cd1e0820fa4e61325772 Mon Sep 17 00:00:00 2001 From: Gao feng Date: Wed, 25 Sep 2013 15:38:47 +0800 Subject: netfilter: ipt_CLUSTERIP: add parameter net in clusterip_config_find_get Inorder to find clusterip_config in net namespace. Signed-off-by: Gao feng Signed-off-by: Pablo Neira Ayuso --- net/ipv4/netfilter/ipt_CLUSTERIP.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index 1bf5aa3096c1..b7fc9d5e06df 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -122,10 +122,10 @@ clusterip_config_entry_put(struct clusterip_config *c) } static struct clusterip_config * -__clusterip_config_find(__be32 clusterip) +__clusterip_config_find(struct net *net, __be32 clusterip) { struct clusterip_config *c; - struct clusterip_net *cn = net_generic(&init_net, clusterip_net_id); + struct clusterip_net *cn = net_generic(net, clusterip_net_id); list_for_each_entry_rcu(c, &cn->configs, list) { if (c->clusterip == clusterip) @@ -136,12 +136,12 @@ __clusterip_config_find(__be32 clusterip) } static inline struct clusterip_config * -clusterip_config_find_get(__be32 clusterip, int entry) +clusterip_config_find_get(struct net *net, __be32 clusterip, int entry) { struct clusterip_config *c; rcu_read_lock_bh(); - c = __clusterip_config_find(clusterip); + c = __clusterip_config_find(net, clusterip); if (c) { if (unlikely(!atomic_inc_not_zero(&c->refcount))) c = NULL; @@ -381,7 +381,7 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par) /* FIXME: further sanity checks */ - config = clusterip_config_find_get(e->ip.dst.s_addr, 1); + config = clusterip_config_find_get(&init_net, e->ip.dst.s_addr, 1); if (!config) { if (!(cipinfo->flags & CLUSTERIP_FLAG_NEW)) { pr_info("no config found for %pI4, need 'new'\n", @@ -519,7 +519,7 @@ arp_mangle(unsigned int hook, /* if there is no clusterip configuration for the arp reply's * source ip, we don't want to mangle it */ - c = clusterip_config_find_get(payload->src_ip, 0); + c = clusterip_config_find_get(&init_net, payload->src_ip, 0); if (!c) return NF_ACCEPT; -- cgit v1.2.3 From f58d7866018dedae7ec67e152402b8ede17ce39e Mon Sep 17 00:00:00 2001 From: Gao feng Date: Wed, 25 Sep 2013 15:38:48 +0800 Subject: netfilter: ipt_CLUSTERIP: create proc entry under proper ipt_CLUSTERIP directory Create proc entries under the ipt_CLUSTERIP directory of proper net namespace. Signed-off-by: Gao feng Signed-off-by: Pablo Neira Ayuso --- net/ipv4/netfilter/ipt_CLUSTERIP.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index b7fc9d5e06df..c93dfd2821ac 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -168,7 +168,7 @@ clusterip_config_init(const struct ipt_clusterip_tgt_info *i, __be32 ip, struct net_device *dev) { struct clusterip_config *c; - struct clusterip_net *cn = net_generic(&init_net, clusterip_net_id); + struct clusterip_net *cn = net_generic(dev_net(dev), clusterip_net_id); c = kzalloc(sizeof(*c), GFP_ATOMIC); if (!c) -- cgit v1.2.3 From d86946d2c5b4e519ffe435c2deeb2c9436ceb04f Mon Sep 17 00:00:00 2001 From: Gao feng Date: Wed, 25 Sep 2013 15:38:49 +0800 Subject: netfilter: ipt_CLUSTERIP: use proper net namespace to operate CLUSTERIP we can allow users in uninit net namespace to operate ipt_CLUSTERIP now. Signed-off-by: Gao feng Signed-off-by: Pablo Neira Ayuso --- net/ipv4/netfilter/ipt_CLUSTERIP.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'net/ipv4') diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index c93dfd2821ac..ecd808a93b63 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -99,7 +99,8 @@ clusterip_config_put(struct clusterip_config *c) static inline void clusterip_config_entry_put(struct clusterip_config *c) { - struct clusterip_net *cn = net_generic(&init_net, clusterip_net_id); + struct net *net = dev_net(c->dev); + struct clusterip_net *cn = net_generic(net, clusterip_net_id); local_bh_disable(); if (atomic_dec_and_lock(&c->entries, &cn->lock)) { @@ -381,7 +382,7 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par) /* FIXME: further sanity checks */ - config = clusterip_config_find_get(&init_net, e->ip.dst.s_addr, 1); + config = clusterip_config_find_get(par->net, e->ip.dst.s_addr, 1); if (!config) { if (!(cipinfo->flags & CLUSTERIP_FLAG_NEW)) { pr_info("no config found for %pI4, need 'new'\n", @@ -395,7 +396,7 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par) return -EINVAL; } - dev = dev_get_by_name(&init_net, e->ip.iniface); + dev = dev_get_by_name(par->net, e->ip.iniface); if (!dev) { pr_info("no such interface %s\n", e->ip.iniface); @@ -503,6 +504,7 @@ arp_mangle(unsigned int hook, struct arphdr *arp = arp_hdr(skb); struct arp_payload *payload; struct clusterip_config *c; + struct net *net = dev_net(in ? in : out); /* we don't care about non-ethernet and non-ipv4 ARP */ if (arp->ar_hrd != htons(ARPHRD_ETHER) || @@ -519,7 +521,7 @@ arp_mangle(unsigned int hook, /* if there is no clusterip configuration for the arp reply's * source ip, we don't want to mangle it */ - c = clusterip_config_find_get(&init_net, payload->src_ip, 0); + c = clusterip_config_find_get(net, payload->src_ip, 0); if (!c) return NF_ACCEPT; -- cgit v1.2.3