Commit 4aa678ba authored by Alexey Dobriyan's avatar Alexey Dobriyan Committed by David S. Miller

netns bridge: allow bridges in netns!

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: default avatarAlexey Dobriyan <adobriyan@gmail.com>
Acked-by: default avatarStephen Hemminger <shemming@vyatta.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5337407c
...@@ -178,5 +178,6 @@ void br_dev_setup(struct net_device *dev) ...@@ -178,5 +178,6 @@ void br_dev_setup(struct net_device *dev)
dev->priv_flags = IFF_EBRIDGE; dev->priv_flags = IFF_EBRIDGE;
dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | 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;
} }
...@@ -168,7 +168,7 @@ static void del_br(struct net_bridge *br) ...@@ -168,7 +168,7 @@ static void del_br(struct net_bridge *br)
unregister_netdevice(br->dev); 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_bridge *br;
struct net_device *dev; struct net_device *dev;
...@@ -178,6 +178,7 @@ static struct net_device *new_bridge_dev(const char *name) ...@@ -178,6 +178,7 @@ static struct net_device *new_bridge_dev(const char *name)
if (!dev) if (!dev)
return NULL; return NULL;
dev_net_set(dev, net);
br = netdev_priv(dev); br = netdev_priv(dev);
br->dev = dev; br->dev = dev;
...@@ -262,12 +263,12 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, ...@@ -262,12 +263,12 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br,
return p; return p;
} }
int br_add_bridge(const char *name) int br_add_bridge(struct net *net, const char *name)
{ {
struct net_device *dev; struct net_device *dev;
int ret; int ret;
dev = new_bridge_dev(name); dev = new_bridge_dev(net, name);
if (!dev) if (!dev)
return -ENOMEM; return -ENOMEM;
...@@ -294,13 +295,13 @@ int br_add_bridge(const char *name) ...@@ -294,13 +295,13 @@ int br_add_bridge(const char *name)
goto out; goto out;
} }
int br_del_bridge(const char *name) int br_del_bridge(struct net *net, const char *name)
{ {
struct net_device *dev; struct net_device *dev;
int ret = 0; int ret = 0;
rtnl_lock(); rtnl_lock();
dev = __dev_get_by_name(&init_net, name); dev = __dev_get_by_name(net, name);
if (dev == NULL) if (dev == NULL)
ret = -ENXIO; /* Could not find device */ ret = -ENXIO; /* Could not find device */
......
...@@ -21,12 +21,12 @@ ...@@ -21,12 +21,12 @@
#include "br_private.h" #include "br_private.h"
/* called with RTNL */ /* 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; struct net_device *dev;
int i = 0; int i = 0;
for_each_netdev(&init_net, dev) { for_each_netdev(net, dev) {
if (i >= num) if (i >= num)
break; break;
if (dev->priv_flags & IFF_EBRIDGE) if (dev->priv_flags & IFF_EBRIDGE)
...@@ -89,7 +89,7 @@ static int add_del_if(struct net_bridge *br, int ifindex, int isadd) ...@@ -89,7 +89,7 @@ static int add_del_if(struct net_bridge *br, int ifindex, int isadd)
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
return -EPERM; return -EPERM;
dev = dev_get_by_index(&init_net, ifindex); dev = dev_get_by_index(dev_net(br->dev), ifindex);
if (dev == NULL) if (dev == NULL)
return -EINVAL; return -EINVAL;
...@@ -309,7 +309,7 @@ static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ...@@ -309,7 +309,7 @@ static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static int old_deviceless(void __user *uarg) static int old_deviceless(struct net *net, void __user *uarg)
{ {
unsigned long args[3]; unsigned long args[3];
...@@ -331,7 +331,7 @@ static int old_deviceless(void __user *uarg) ...@@ -331,7 +331,7 @@ static int old_deviceless(void __user *uarg)
if (indices == NULL) if (indices == NULL)
return -ENOMEM; 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)) ret = copy_to_user((void __user *)args[1], indices, args[2]*sizeof(int))
? -EFAULT : args[2]; ? -EFAULT : args[2];
...@@ -354,9 +354,9 @@ static int old_deviceless(void __user *uarg) ...@@ -354,9 +354,9 @@ static int old_deviceless(void __user *uarg)
buf[IFNAMSIZ-1] = 0; buf[IFNAMSIZ-1] = 0;
if (args[0] == BRCTL_ADD_BRIDGE) 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 ...@@ -368,7 +368,7 @@ int br_ioctl_deviceless_stub(struct net *net, unsigned int cmd, void __user *uar
switch (cmd) { switch (cmd) {
case SIOCGIFBR: case SIOCGIFBR:
case SIOCSIFBR: case SIOCSIFBR:
return old_deviceless(uarg); return old_deviceless(net, uarg);
case SIOCBRADDBR: case SIOCBRADDBR:
case SIOCBRDELBR: case SIOCBRDELBR:
...@@ -383,9 +383,9 @@ int br_ioctl_deviceless_stub(struct net *net, unsigned int cmd, void __user *uar ...@@ -383,9 +383,9 @@ int br_ioctl_deviceless_stub(struct net *net, unsigned int cmd, void __user *uar
buf[IFNAMSIZ-1] = 0; buf[IFNAMSIZ-1] = 0;
if (cmd == SIOCBRADDBR) 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; return -EOPNOTSUPP;
......
...@@ -82,6 +82,7 @@ static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *por ...@@ -82,6 +82,7 @@ static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *por
*/ */
void br_ifinfo_notify(int event, struct net_bridge_port *port) void br_ifinfo_notify(int event, struct net_bridge_port *port)
{ {
struct net *net = dev_net(port->dev);
struct sk_buff *skb; struct sk_buff *skb;
int err = -ENOBUFS; int err = -ENOBUFS;
...@@ -97,10 +98,10 @@ void br_ifinfo_notify(int event, struct net_bridge_port *port) ...@@ -97,10 +98,10 @@ void br_ifinfo_notify(int event, struct net_bridge_port *port)
kfree_skb(skb); kfree_skb(skb);
goto errout; 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: errout:
if (err < 0) 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) ...@@ -112,11 +113,8 @@ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
struct net_device *dev; struct net_device *dev;
int idx; int idx;
if (net != &init_net)
return 0;
idx = 0; idx = 0;
for_each_netdev(&init_net, dev) { for_each_netdev(net, dev) {
/* not a bridge port */ /* not a bridge port */
if (dev->br_port == NULL || idx < cb->args[0]) if (dev->br_port == NULL || idx < cb->args[0])
goto skip; goto skip;
...@@ -147,9 +145,6 @@ static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) ...@@ -147,9 +145,6 @@ static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
struct net_bridge_port *p; struct net_bridge_port *p;
u8 new_state; u8 new_state;
if (net != &init_net)
return -EINVAL;
if (nlmsg_len(nlh) < sizeof(*ifm)) if (nlmsg_len(nlh) < sizeof(*ifm))
return -EINVAL; return -EINVAL;
...@@ -165,7 +160,7 @@ static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) ...@@ -165,7 +160,7 @@ static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
if (new_state > BR_STATE_BLOCKING) if (new_state > BR_STATE_BLOCKING)
return -EINVAL; return -EINVAL;
dev = __dev_get_by_index(&init_net, ifm->ifi_index); dev = __dev_get_by_index(net, ifm->ifi_index);
if (!dev) if (!dev)
return -ENODEV; return -ENODEV;
......
...@@ -35,9 +35,6 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v ...@@ -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_port *p = dev->br_port;
struct net_bridge *br; struct net_bridge *br;
if (!net_eq(dev_net(dev), &init_net))
return NOTIFY_DONE;
/* not a port of a bridge */ /* not a port of a bridge */
if (p == NULL) if (p == NULL)
return NOTIFY_DONE; return NOTIFY_DONE;
......
...@@ -178,8 +178,8 @@ extern void br_flood_forward(struct net_bridge *br, struct sk_buff *skb); ...@@ -178,8 +178,8 @@ extern void br_flood_forward(struct net_bridge *br, struct sk_buff *skb);
/* br_if.c */ /* br_if.c */
extern void br_port_carrier_check(struct net_bridge_port *p); extern void br_port_carrier_check(struct net_bridge_port *p);
extern int br_add_bridge(const char *name); extern int br_add_bridge(struct net *net, const char *name);
extern int br_del_bridge(const char *name); extern int br_del_bridge(struct net *net, const char *name);
extern void br_cleanup_bridges(void); extern void br_cleanup_bridges(void);
extern int br_add_if(struct net_bridge *br, extern int br_add_if(struct net_bridge *br,
struct net_device *dev); struct net_device *dev);
......
...@@ -140,9 +140,6 @@ void br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb, ...@@ -140,9 +140,6 @@ void br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb,
struct net_bridge *br; struct net_bridge *br;
const unsigned char *buf; const unsigned char *buf;
if (!net_eq(dev_net(dev), &init_net))
goto err;
if (!p) if (!p)
goto err; goto err;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment