netns bridge: allow bridges in netns!
authorAlexey Dobriyan <adobriyan@gmail.com>
Mon, 8 Sep 2008 23:19:58 +0000 (16:19 -0700)
committerDavid S. Miller <davem@davemloft.net>
Mon, 8 Sep 2008 23:19:58 +0000 (16:19 -0700)
Bridge as netdevice doesn't cross netns boundaries.

Bridge ports and bridge itself live in same netns.

Notifiers are fixed.

netns propagated from userspace socket for setup and teardown.

Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Acked-by: Stephen Hemminger <shemming@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/bridge/br_device.c
net/bridge/br_if.c
net/bridge/br_ioctl.c
net/bridge/br_netlink.c
net/bridge/br_notify.c
net/bridge/br_private.h
net/bridge/br_stp_bpdu.c

index 4f52c3d..22ba863 100644 (file)
@@ -178,5 +178,6 @@ void br_dev_setup(struct net_device *dev)
        dev->priv_flags = IFF_EBRIDGE;
 
        dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
-                       NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | NETIF_F_LLTX;
+                       NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | NETIF_F_LLTX |
+                       NETIF_F_NETNS_LOCAL;
 }
index 63c18aa..66c4f71 100644 (file)
@@ -168,7 +168,7 @@ static void del_br(struct net_bridge *br)
        unregister_netdevice(br->dev);
 }
 
-static struct net_device *new_bridge_dev(const char *name)
+static struct net_device *new_bridge_dev(struct net *net, const char *name)
 {
        struct net_bridge *br;
        struct net_device *dev;
@@ -178,6 +178,7 @@ static struct net_device *new_bridge_dev(const char *name)
 
        if (!dev)
                return NULL;
+       dev_net_set(dev, net);
 
        br = netdev_priv(dev);
        br->dev = dev;
@@ -262,12 +263,12 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br,
        return p;
 }
 
-int br_add_bridge(const char *name)
+int br_add_bridge(struct net *net, const char *name)
 {
        struct net_device *dev;
        int ret;
 
-       dev = new_bridge_dev(name);
+       dev = new_bridge_dev(net, name);
        if (!dev)
                return -ENOMEM;
 
@@ -294,13 +295,13 @@ out_free:
        goto out;
 }
 
-int br_del_bridge(const char *name)
+int br_del_bridge(struct net *net, const char *name)
 {
        struct net_device *dev;
        int ret = 0;
 
        rtnl_lock();
-       dev = __dev_get_by_name(&init_net, name);
+       dev = __dev_get_by_name(net, name);
        if (dev == NULL)
                ret =  -ENXIO;  /* Could not find device */
 
index eeee218..3ec1c63 100644 (file)
 #include "br_private.h"
 
 /* called with RTNL */
-static int get_bridge_ifindices(int *indices, int num)
+static int get_bridge_ifindices(struct net *net, int *indices, int num)
 {
        struct net_device *dev;
        int i = 0;
 
-       for_each_netdev(&init_net, dev) {
+       for_each_netdev(net, dev) {
                if (i >= num)
                        break;
                if (dev->priv_flags & IFF_EBRIDGE)
@@ -89,7 +89,7 @@ static int add_del_if(struct net_bridge *br, int ifindex, int isadd)
        if (!capable(CAP_NET_ADMIN))
                return -EPERM;
 
-       dev = dev_get_by_index(&init_net, ifindex);
+       dev = dev_get_by_index(dev_net(br->dev), ifindex);
        if (dev == NULL)
                return -EINVAL;
 
@@ -309,7 +309,7 @@ static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
        return -EOPNOTSUPP;
 }
 
-static int old_deviceless(void __user *uarg)
+static int old_deviceless(struct net *net, void __user *uarg)
 {
        unsigned long args[3];
 
@@ -331,7 +331,7 @@ static int old_deviceless(void __user *uarg)
                if (indices == NULL)
                        return -ENOMEM;
 
-               args[2] = get_bridge_ifindices(indices, args[2]);
+               args[2] = get_bridge_ifindices(net, indices, args[2]);
 
                ret = copy_to_user((void __user *)args[1], indices, args[2]*sizeof(int))
                        ? -EFAULT : args[2];
@@ -354,9 +354,9 @@ static int old_deviceless(void __user *uarg)
                buf[IFNAMSIZ-1] = 0;
 
                if (args[0] == BRCTL_ADD_BRIDGE)
-                       return br_add_bridge(buf);
+                       return br_add_bridge(net, buf);
 
-               return br_del_bridge(buf);
+               return br_del_bridge(net, buf);
        }
        }
 
@@ -368,7 +368,7 @@ int br_ioctl_deviceless_stub(struct net *net, unsigned int cmd, void __user *uar
        switch (cmd) {
        case SIOCGIFBR:
        case SIOCSIFBR:
-               return old_deviceless(uarg);
+               return old_deviceless(net, uarg);
 
        case SIOCBRADDBR:
        case SIOCBRDELBR:
@@ -383,9 +383,9 @@ int br_ioctl_deviceless_stub(struct net *net, unsigned int cmd, void __user *uar
 
                buf[IFNAMSIZ-1] = 0;
                if (cmd == SIOCBRADDBR)
-                       return br_add_bridge(buf);
+                       return br_add_bridge(net, buf);
 
-               return br_del_bridge(buf);
+               return br_del_bridge(net, buf);
        }
        }
        return -EOPNOTSUPP;
index f155e6c..ba7be19 100644 (file)
@@ -82,6 +82,7 @@ nla_put_failure:
  */
 void br_ifinfo_notify(int event, struct net_bridge_port *port)
 {
+       struct net *net = dev_net(port->dev);
        struct sk_buff *skb;
        int err = -ENOBUFS;
 
@@ -97,10 +98,10 @@ void br_ifinfo_notify(int event, struct net_bridge_port *port)
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, &init_net,0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
+       err = rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
 errout:
        if (err < 0)
-               rtnl_set_sk_err(&init_net, RTNLGRP_LINK, err);
+               rtnl_set_sk_err(net, RTNLGRP_LINK, err);
 }
 
 /*
@@ -112,11 +113,8 @@ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
        struct net_device *dev;
        int idx;
 
-       if (net != &init_net)
-               return 0;
-
        idx = 0;
-       for_each_netdev(&init_net, dev) {
+       for_each_netdev(net, dev) {
                /* not a bridge port */
                if (dev->br_port == NULL || idx < cb->args[0])
                        goto skip;
@@ -147,9 +145,6 @@ static int br_rtm_setlink(struct sk_buff *skb,  struct nlmsghdr *nlh, void *arg)
        struct net_bridge_port *p;
        u8 new_state;
 
-       if (net != &init_net)
-               return -EINVAL;
-
        if (nlmsg_len(nlh) < sizeof(*ifm))
                return -EINVAL;
 
@@ -165,7 +160,7 @@ static int br_rtm_setlink(struct sk_buff *skb,  struct nlmsghdr *nlh, void *arg)
        if (new_state > BR_STATE_BLOCKING)
                return -EINVAL;
 
-       dev = __dev_get_by_index(&init_net, ifm->ifi_index);
+       dev = __dev_get_by_index(net, ifm->ifi_index);
        if (!dev)
                return -ENODEV;
 
index 76340bd..763a3ec 100644 (file)
@@ -35,9 +35,6 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
        struct net_bridge_port *p = dev->br_port;
        struct net_bridge *br;
 
-       if (!net_eq(dev_net(dev), &init_net))
-               return NOTIFY_DONE;
-
        /* not a port of a bridge */
        if (p == NULL)
                return NOTIFY_DONE;
index c3dc18d..51eaeaa 100644 (file)
@@ -178,8 +178,8 @@ extern void br_flood_forward(struct net_bridge *br, struct sk_buff *skb);
 
 /* br_if.c */
 extern void br_port_carrier_check(struct net_bridge_port *p);
-extern int br_add_bridge(const char *name);
-extern int br_del_bridge(const char *name);
+extern int br_add_bridge(struct net *net, const char *name);
+extern int br_del_bridge(struct net *net, const char *name);
 extern void br_cleanup_bridges(void);
 extern int br_add_if(struct net_bridge *br,
              struct net_device *dev);
index 8b200f9..81ae40b 100644 (file)
@@ -140,9 +140,6 @@ void br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb,
        struct net_bridge *br;
        const unsigned char *buf;
 
-       if (!net_eq(dev_net(dev), &init_net))
-               goto err;
-
        if (!p)
                goto err;