All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/6] netns brnetfilter: per-netns ebtables
@ 2008-08-21 22:20 adobriyan
  2008-08-21 22:41 ` adobriyan
                   ` (2 more replies)
  0 siblings, 3 replies; 17+ messages in thread
From: adobriyan @ 2008-08-21 22:20 UTC (permalink / raw)
  To: shemminger, netdev, containers, kaber

* make registered ebtables list per-netns
* for that, duplicate table at the very beginning of register,
  we can't add one table to multiple lists.
* propagate netns from userspace socket down to iterators over list,
* register individual modules only in init_net for a minute.

Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
---

 include/linux/netfilter_bridge/ebtables.h |    2 
 include/net/net_namespace.h               |    4 +
 include/net/netns/bridge.h                |    9 +++
 net/bridge/netfilter/ebtable_broute.c     |   19 +++-----
 net/bridge/netfilter/ebtable_filter.c     |   17 +++----
 net/bridge/netfilter/ebtable_nat.c        |   19 ++++----
 net/bridge/netfilter/ebtables.c           |   70 +++++++++++++++++++++---------
 7 files changed, 91 insertions(+), 49 deletions(-)

--- a/include/linux/netfilter_bridge/ebtables.h
+++ b/include/linux/netfilter_bridge/ebtables.h
@@ -286,7 +286,7 @@ struct ebt_table
 
 #define EBT_ALIGN(s) (((s) + (__alignof__(struct ebt_replace)-1)) & \
 		     ~(__alignof__(struct ebt_replace)-1))
-extern int ebt_register_table(struct ebt_table *table);
+extern struct ebt_table *ebt_register_table(struct net *net, struct ebt_table *table);
 extern void ebt_unregister_table(struct ebt_table *table);
 extern int ebt_register_match(struct ebt_match *match);
 extern void ebt_unregister_match(struct ebt_match *match);
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -19,6 +19,7 @@
 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
 #include <net/netns/conntrack.h>
 #endif
+#include <net/netns/bridge.h>
 
 struct proc_dir_entry;
 struct net_device;
@@ -73,6 +74,9 @@ struct net {
 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
 	struct netns_ct		ct;
 #endif
+#ifdef CONFIG_BRIDGE_NETFILTER
+	struct netns_br		br;
+#endif
 #endif
 	struct net_generic	*gen;
 };
new file mode 100644
--- /dev/null
+++ b/include/net/netns/bridge.h
@@ -0,0 +1,9 @@
+#ifndef __NETNS_BRIDGE_H
+#define __NETNS_BRIDGE_H
+
+#include <linux/list.h>
+
+struct netns_br {
+	struct list_head	ebt_tables;
+};
+#endif
--- a/net/bridge/netfilter/ebtable_broute.c
+++ b/net/bridge/netfilter/ebtable_broute.c
@@ -41,22 +41,23 @@ static int check(const struct ebt_table_info *info, unsigned int valid_hooks)
 	return 0;
 }
 
-static struct ebt_table broute_table =
+static struct ebt_table __broute_table =
 {
 	.name		= "broute",
 	.table		= &initial_table,
 	.valid_hooks	= 1 << NF_BR_BROUTING,
-	.lock		= __RW_LOCK_UNLOCKED(broute_table.lock),
+	.lock		= __RW_LOCK_UNLOCKED(__broute_table.lock),
 	.check		= check,
 	.me		= THIS_MODULE,
 };
+static struct ebt_table *broute_table;
 
 static int ebt_broute(struct sk_buff *skb)
 {
 	int ret;
 
 	ret = ebt_do_table(NF_BR_BROUTING, skb, skb->dev, NULL,
-	   &broute_table);
+	   broute_table);
 	if (ret == NF_DROP)
 		return 1; /* route it */
 	return 0; /* bridge it */
@@ -64,21 +65,19 @@ static int ebt_broute(struct sk_buff *skb)
 
 static int __init ebtable_broute_init(void)
 {
-	int ret;
-
-	ret = ebt_register_table(&broute_table);
-	if (ret < 0)
-		return ret;
+	broute_table = ebt_register_table(&init_net, &__broute_table);
+	if (IS_ERR(broute_table))
+		return PTR_ERR(broute_table);
 	/* see br_input.c */
 	rcu_assign_pointer(br_should_route_hook, ebt_broute);
-	return ret;
+	return 0;
 }
 
 static void __exit ebtable_broute_fini(void)
 {
 	rcu_assign_pointer(br_should_route_hook, NULL);
 	synchronize_net();
-	ebt_unregister_table(&broute_table);
+	ebt_unregister_table(broute_table);
 }
 
 module_init(ebtable_broute_init);
--- a/net/bridge/netfilter/ebtable_filter.c
+++ b/net/bridge/netfilter/ebtable_filter.c
@@ -50,21 +50,22 @@ static int check(const struct ebt_table_info *info, unsigned int valid_hooks)
 	return 0;
 }
 
-static struct ebt_table frame_filter =
+static struct ebt_table __frame_filter =
 {
 	.name		= "filter",
 	.table		= &initial_table,
 	.valid_hooks	= FILTER_VALID_HOOKS,
-	.lock		= __RW_LOCK_UNLOCKED(frame_filter.lock),
+	.lock		= __RW_LOCK_UNLOCKED(__frame_filter.lock),
 	.check		= check,
 	.me		= THIS_MODULE,
 };
+static struct ebt_table *frame_filter;
 
 static unsigned int
 ebt_hook(unsigned int hook, struct sk_buff *skb, const struct net_device *in,
    const struct net_device *out, int (*okfn)(struct sk_buff *))
 {
-	return ebt_do_table(hook, skb, in, out, &frame_filter);
+	return ebt_do_table(hook, skb, in, out, frame_filter);
 }
 
 static struct nf_hook_ops ebt_ops_filter[] __read_mostly = {
@@ -95,19 +96,19 @@ static int __init ebtable_filter_init(void)
 {
 	int ret;
 
-	ret = ebt_register_table(&frame_filter);
-	if (ret < 0)
-		return ret;
+	frame_filter = ebt_register_table(&init_net, &__frame_filter);
+	if (IS_ERR(frame_filter))
+		return PTR_ERR(frame_filter);
 	ret = nf_register_hooks(ebt_ops_filter, ARRAY_SIZE(ebt_ops_filter));
 	if (ret < 0)
-		ebt_unregister_table(&frame_filter);
+		ebt_unregister_table(frame_filter);
 	return ret;
 }
 
 static void __exit ebtable_filter_fini(void)
 {
 	nf_unregister_hooks(ebt_ops_filter, ARRAY_SIZE(ebt_ops_filter));
-	ebt_unregister_table(&frame_filter);
+	ebt_unregister_table(frame_filter);
 }
 
 module_init(ebtable_filter_init);
--- a/net/bridge/netfilter/ebtable_nat.c
+++ b/net/bridge/netfilter/ebtable_nat.c
@@ -50,28 +50,29 @@ static int check(const struct ebt_table_info *info, unsigned int valid_hooks)
 	return 0;
 }
 
-static struct ebt_table frame_nat =
+static struct ebt_table __frame_nat =
 {
 	.name		= "nat",
 	.table		= &initial_table,
 	.valid_hooks	= NAT_VALID_HOOKS,
-	.lock		= __RW_LOCK_UNLOCKED(frame_nat.lock),
+	.lock		= __RW_LOCK_UNLOCKED(__frame_nat.lock),
 	.check		= check,
 	.me		= THIS_MODULE,
 };
+static struct ebt_table *frame_nat;
 
 static unsigned int
 ebt_nat_dst(unsigned int hook, struct sk_buff *skb, const struct net_device *in
    , const struct net_device *out, int (*okfn)(struct sk_buff *))
 {
-	return ebt_do_table(hook, skb, in, out, &frame_nat);
+	return ebt_do_table(hook, skb, in, out, frame_nat);
 }
 
 static unsigned int
 ebt_nat_src(unsigned int hook, struct sk_buff *skb, const struct net_device *in
    , const struct net_device *out, int (*okfn)(struct sk_buff *))
 {
-	return ebt_do_table(hook, skb, in, out, &frame_nat);
+	return ebt_do_table(hook, skb, in, out, frame_nat);
 }
 
 static struct nf_hook_ops ebt_ops_nat[] __read_mostly = {
@@ -102,19 +103,19 @@ static int __init ebtable_nat_init(void)
 {
 	int ret;
 
-	ret = ebt_register_table(&frame_nat);
-	if (ret < 0)
-		return ret;
+	frame_nat = ebt_register_table(&init_net, &__frame_nat);
+	if (IS_ERR(frame_nat))
+		return PTR_ERR(frame_nat);
 	ret = nf_register_hooks(ebt_ops_nat, ARRAY_SIZE(ebt_ops_nat));
 	if (ret < 0)
-		ebt_unregister_table(&frame_nat);
+		ebt_unregister_table(frame_nat);
 	return ret;
 }
 
 static void __exit ebtable_nat_fini(void)
 {
 	nf_unregister_hooks(ebt_ops_nat, ARRAY_SIZE(ebt_ops_nat));
-	ebt_unregister_table(&frame_nat);
+	ebt_unregister_table(frame_nat);
 }
 
 module_init(ebtable_nat_init);
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -54,7 +54,6 @@
 
 
 static DEFINE_MUTEX(ebt_mutex);
-static LIST_HEAD(ebt_tables);
 static LIST_HEAD(ebt_targets);
 static LIST_HEAD(ebt_matches);
 static LIST_HEAD(ebt_watchers);
@@ -307,9 +306,9 @@ find_inlist_lock(struct list_head *head, const char *name, const char *prefix,
 #endif
 
 static inline struct ebt_table *
-find_table_lock(const char *name, int *error, struct mutex *mutex)
+find_table_lock(struct net *net, const char *name, int *error, struct mutex *mutex)
 {
-	return find_inlist_lock(&ebt_tables, name, "ebtable_", error, mutex);
+	return find_inlist_lock(&net->br.ebt_tables, name, "ebtable_", error, mutex);
 }
 
 static inline struct ebt_match *
@@ -915,7 +914,7 @@ static void get_counters(struct ebt_counter *oldcounters,
 }
 
 /* replace the table */
-static int do_replace(void __user *user, unsigned int len)
+static int do_replace(struct net *net, void __user *user, unsigned int len)
 {
 	int ret, i, countersize;
 	struct ebt_table_info *newinfo;
@@ -987,7 +986,7 @@ static int do_replace(void __user *user, unsigned int len)
 	if (ret != 0)
 		goto free_counterstmp;
 
-	t = find_table_lock(tmp.name, &ret, &ebt_mutex);
+	t = find_table_lock(net, tmp.name, &ret, &ebt_mutex);
 	if (!t) {
 		ret = -ENOENT;
 		goto free_iterate;
@@ -1149,7 +1148,7 @@ void ebt_unregister_watcher(struct ebt_watcher *watcher)
 	mutex_unlock(&ebt_mutex);
 }
 
-int ebt_register_table(struct ebt_table *table)
+struct ebt_table *ebt_register_table(struct net *net, struct ebt_table *table)
 {
 	struct ebt_table_info *newinfo;
 	struct ebt_table *t;
@@ -1157,18 +1156,27 @@ int ebt_register_table(struct ebt_table *table)
 	int ret, i, countersize;
 	void *p;
 
-	if (!table || !(repl = table->table) || !repl->entries ||
+	table = kmemdup(table, sizeof(struct ebt_table), GFP_KERNEL);
+	if (!table) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	if (!(repl = table->table) || !repl->entries ||
 	    repl->entries_size == 0 ||
 	    repl->counters || table->private) {
 		BUGPRINT("Bad table data for ebt_register_table!!!\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto free_table;
 	}
 
 	countersize = COUNTER_OFFSET(repl->nentries) * nr_cpu_ids;
 	newinfo = vmalloc(sizeof(*newinfo) + countersize);
 	ret = -ENOMEM;
-	if (!newinfo)
-		return -ENOMEM;
+	if (!newinfo) {
+		ret = -ENOMEM;
+		goto free_table;
+	}
 
 	p = vmalloc(repl->entries_size);
 	if (!p)
@@ -1200,7 +1208,8 @@ int ebt_register_table(struct ebt_table *table)
 
 	if (table->check && table->check(newinfo, table->valid_hooks)) {
 		BUGPRINT("The table doesn't like its own initial data, lol\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto free_table;
 	}
 
 	table->private = newinfo;
@@ -1209,7 +1218,7 @@ int ebt_register_table(struct ebt_table *table)
 	if (ret != 0)
 		goto free_chainstack;
 
-	list_for_each_entry(t, &ebt_tables, list) {
+	list_for_each_entry(t, &net->br.ebt_tables, list) {
 		if (strcmp(t->name, table->name) == 0) {
 			ret = -EEXIST;
 			BUGPRINT("Table name already exists\n");
@@ -1222,9 +1231,9 @@ int ebt_register_table(struct ebt_table *table)
 		ret = -ENOENT;
 		goto free_unlock;
 	}
-	list_add(&table->list, &ebt_tables);
+	list_add(&table->list, &net->br.ebt_tables);
 	mutex_unlock(&ebt_mutex);
-	return 0;
+	return table;
 free_unlock:
 	mutex_unlock(&ebt_mutex);
 free_chainstack:
@@ -1236,7 +1245,10 @@ free_chainstack:
 	vfree(newinfo->entries);
 free_newinfo:
 	vfree(newinfo);
-	return ret;
+free_table:
+	kfree(table);
+out:
+	return ERR_PTR(ret);
 }
 
 void ebt_unregister_table(struct ebt_table *table)
@@ -1257,10 +1269,11 @@ void ebt_unregister_table(struct ebt_table *table)
 		vfree(table->private->chainstack);
 	}
 	vfree(table->private);
+	kfree(table);
 }
 
 /* userspace just supplied us with counters */
-static int update_counters(void __user *user, unsigned int len)
+static int update_counters(struct net *net, void __user *user, unsigned int len)
 {
 	int i, ret;
 	struct ebt_counter *tmp;
@@ -1280,7 +1293,7 @@ static int update_counters(void __user *user, unsigned int len)
 		return -ENOMEM;
 	}
 
-	t = find_table_lock(hlp.name, &ret, &ebt_mutex);
+	t = find_table_lock(net, hlp.name, &ret, &ebt_mutex);
 	if (!t)
 		goto free_tmp;
 
@@ -1434,14 +1447,15 @@ static int copy_everything_to_user(struct ebt_table *t, void __user *user,
 static int do_ebt_set_ctl(struct sock *sk,
 	int cmd, void __user *user, unsigned int len)
 {
+	struct net *net = sock_net(sk);
 	int ret;
 
 	switch(cmd) {
 	case EBT_SO_SET_ENTRIES:
-		ret = do_replace(user, len);
+		ret = do_replace(net, user, len);
 		break;
 	case EBT_SO_SET_COUNTERS:
-		ret = update_counters(user, len);
+		ret = update_counters(net, user, len);
 		break;
 	default:
 		ret = -EINVAL;
@@ -1451,6 +1465,7 @@ static int do_ebt_set_ctl(struct sock *sk,
 
 static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
 {
+	struct net *net = sock_net(sk);
 	int ret;
 	struct ebt_replace tmp;
 	struct ebt_table *t;
@@ -1458,7 +1473,7 @@ static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
 	if (copy_from_user(&tmp, user, sizeof(tmp)))
 		return -EFAULT;
 
-	t = find_table_lock(tmp.name, &ret, &ebt_mutex);
+	t = find_table_lock(net, tmp.name, &ret, &ebt_mutex);
 	if (!t)
 		return ret;
 
@@ -1514,6 +1529,16 @@ static struct nf_sockopt_ops ebt_sockopts =
 	.owner		= THIS_MODULE,
 };
 
+static int ebtables_net_init(struct net *net)
+{
+	INIT_LIST_HEAD(&net->br.ebt_tables);
+	return 0;
+}
+
+static struct pernet_operations ebtables_net_ops = {
+	.init = ebtables_net_init,
+};
+
 static int __init ebtables_init(void)
 {
 	int ret;
@@ -1523,6 +1548,9 @@ static int __init ebtables_init(void)
 	mutex_unlock(&ebt_mutex);
 	if ((ret = nf_register_sockopt(&ebt_sockopts)) < 0)
 		return ret;
+	ret = register_pernet_subsys(&ebtables_net_ops);
+	if (ret < 0)
+		nf_unregister_sockopt(&ebt_sockopts);
 
 	printk(KERN_INFO "Ebtables v2.0 registered\n");
 	return 0;
@@ -1530,6 +1558,7 @@ static int __init ebtables_init(void)
 
 static void __exit ebtables_fini(void)
 {
+	unregister_pernet_subsys(&ebtables_net_ops);
 	nf_unregister_sockopt(&ebt_sockopts);
 	printk(KERN_INFO "Ebtables v2.0 unregistered\n");
 }
-- 
1.5.6.3



^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2008-10-14 11:51 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-08-21 22:20 [PATCH 1/6] netns brnetfilter: per-netns ebtables adobriyan
2008-08-21 22:41 ` adobriyan
     [not found] ` <20080821221943.GO31136-2ev+ksY9ol182hYKe6nXyg@public.gmane.org>
2008-08-21 22:41   ` adobriyan-Re5JQEeQqe8AvxtiuMwx3w
2008-10-13  7:03   ` Ingo Molnar
2008-10-13  7:03 ` Ingo Molnar
     [not found]   ` <20081013070347.GA3813-X9Un+BFzKDI@public.gmane.org>
2008-10-13  7:09     ` Ingo Molnar
2008-10-13  7:09   ` Ingo Molnar
2008-10-13  7:35     ` Alexey Dobriyan
     [not found]       ` <20081013073501.GB4254-2ev+ksY9ol182hYKe6nXyg@public.gmane.org>
2008-10-14 10:30         ` [bug, -git] ERROR: "ebt_unregister_table" [net/bridge/netfilter/ebtable_nat.ko] undefined Ingo Molnar
2008-10-14 10:30       ` Ingo Molnar
2008-10-14 11:00         ` Patrick McHardy
2008-10-14 11:48           ` Ingo Molnar
2008-10-14 11:51             ` Patrick McHardy
     [not found]             ` <20081014114806.GA20480-X9Un+BFzKDI@public.gmane.org>
2008-10-14 11:51               ` Patrick McHardy
     [not found]           ` <48F47BB9.9090902-dcUjhNyLwpNeoWH0uzbU5w@public.gmane.org>
2008-10-14 11:48             ` Ingo Molnar
     [not found]         ` <20081014103005.GA19420-X9Un+BFzKDI@public.gmane.org>
2008-10-14 11:00           ` Patrick McHardy
     [not found]     ` <20081013070940.GA6340-X9Un+BFzKDI@public.gmane.org>
2008-10-13  7:35       ` [PATCH 1/6] netns brnetfilter: per-netns ebtables Alexey Dobriyan

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.