* 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 <[EMAIL PROTECTED]>
---

 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


_______________________________________________
Containers mailing list
[EMAIL PROTECTED]
https://lists.linux-foundation.org/mailman/listinfo/containers

_______________________________________________
Devel mailing list
Devel@openvz.org
https://openvz.org/mailman/listinfo/devel

Reply via email to