Commit ec87fd3b authored by Eric W. Biederman's avatar Eric W. Biederman Committed by David S. Miller

bond: Add support for multiple network namespaces

Signed-off-by: default avatarEric W. Biederman <ebiederm@aristanetworks.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 88ead977
...@@ -2445,9 +2445,6 @@ int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct pac ...@@ -2445,9 +2445,6 @@ int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct pac
struct slave *slave = NULL; struct slave *slave = NULL;
int ret = NET_RX_DROP; int ret = NET_RX_DROP;
if (dev_net(dev) != &init_net)
goto out;
if (!(dev->flags & IFF_MASTER)) if (!(dev->flags & IFF_MASTER))
goto out; goto out;
......
...@@ -355,9 +355,6 @@ static int rlb_arp_recv(struct sk_buff *skb, struct net_device *bond_dev, struct ...@@ -355,9 +355,6 @@ static int rlb_arp_recv(struct sk_buff *skb, struct net_device *bond_dev, struct
struct arp_pkt *arp = (struct arp_pkt *)skb->data; struct arp_pkt *arp = (struct arp_pkt *)skb->data;
int res = NET_RX_DROP; int res = NET_RX_DROP;
if (dev_net(bond_dev) != &init_net)
goto out;
while (bond_dev->priv_flags & IFF_802_1Q_VLAN) while (bond_dev->priv_flags & IFF_802_1Q_VLAN)
bond_dev = vlan_dev_real_dev(bond_dev); bond_dev = vlan_dev_real_dev(bond_dev);
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <net/ipv6.h> #include <net/ipv6.h>
#include <net/ndisc.h> #include <net/ndisc.h>
#include <net/addrconf.h> #include <net/addrconf.h>
#include <net/netns/generic.h>
#include "bonding.h" #include "bonding.h"
/* /*
...@@ -152,11 +153,9 @@ static int bond_inet6addr_event(struct notifier_block *this, ...@@ -152,11 +153,9 @@ static int bond_inet6addr_event(struct notifier_block *this,
struct net_device *vlan_dev, *event_dev = ifa->idev->dev; struct net_device *vlan_dev, *event_dev = ifa->idev->dev;
struct bonding *bond; struct bonding *bond;
struct vlan_entry *vlan; struct vlan_entry *vlan;
struct bond_net *bn = net_generic(dev_net(event_dev), bond_net_id);
if (dev_net(event_dev) != &init_net) list_for_each_entry(bond, &bn->dev_list, bond_list) {
return NOTIFY_DONE;
list_for_each_entry(bond, &bond_dev_list, bond_list) {
if (bond->dev == event_dev) { if (bond->dev == event_dev) {
switch (event) { switch (event) {
case NETDEV_UP: case NETDEV_UP:
......
...@@ -75,6 +75,7 @@ ...@@ -75,6 +75,7 @@
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <net/route.h> #include <net/route.h>
#include <net/net_namespace.h> #include <net/net_namespace.h>
#include <net/netns/generic.h>
#include "bonding.h" #include "bonding.h"
#include "bond_3ad.h" #include "bond_3ad.h"
#include "bond_alb.h" #include "bond_alb.h"
...@@ -157,11 +158,7 @@ MODULE_PARM_DESC(fail_over_mac, "For active-backup, do not set all slaves to the ...@@ -157,11 +158,7 @@ MODULE_PARM_DESC(fail_over_mac, "For active-backup, do not set all slaves to the
static const char * const version = static const char * const version =
DRV_DESCRIPTION ": v" DRV_VERSION " (" DRV_RELDATE ")\n"; DRV_DESCRIPTION ": v" DRV_VERSION " (" DRV_RELDATE ")\n";
LIST_HEAD(bond_dev_list); int bond_net_id;
#ifdef CONFIG_PROC_FS
static struct proc_dir_entry *bond_proc_dir;
#endif
static __be32 arp_target[BOND_MAX_ARP_TARGETS]; static __be32 arp_target[BOND_MAX_ARP_TARGETS];
static int arp_ip_count; static int arp_ip_count;
...@@ -2586,7 +2583,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) ...@@ -2586,7 +2583,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
fl.fl4_dst = targets[i]; fl.fl4_dst = targets[i];
fl.fl4_tos = RTO_ONLINK; fl.fl4_tos = RTO_ONLINK;
rv = ip_route_output_key(&init_net, &rt, &fl); rv = ip_route_output_key(dev_net(bond->dev), &rt, &fl);
if (rv) { if (rv) {
if (net_ratelimit()) { if (net_ratelimit()) {
pr_warning(DRV_NAME pr_warning(DRV_NAME
...@@ -2694,9 +2691,6 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack ...@@ -2694,9 +2691,6 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack
unsigned char *arp_ptr; unsigned char *arp_ptr;
__be32 sip, tip; __be32 sip, tip;
if (dev_net(dev) != &init_net)
goto out;
if (!(dev->priv_flags & IFF_BONDING) || !(dev->flags & IFF_MASTER)) if (!(dev->priv_flags & IFF_BONDING) || !(dev->flags & IFF_MASTER))
goto out; goto out;
...@@ -3359,10 +3353,11 @@ static const struct file_operations bond_info_fops = { ...@@ -3359,10 +3353,11 @@ static const struct file_operations bond_info_fops = {
static void bond_create_proc_entry(struct bonding *bond) static void bond_create_proc_entry(struct bonding *bond)
{ {
struct net_device *bond_dev = bond->dev; struct net_device *bond_dev = bond->dev;
struct bond_net *bn = net_generic(dev_net(bond_dev), bond_net_id);
if (bond_proc_dir) { if (bn->proc_dir) {
bond->proc_entry = proc_create_data(bond_dev->name, bond->proc_entry = proc_create_data(bond_dev->name,
S_IRUGO, bond_proc_dir, S_IRUGO, bn->proc_dir,
&bond_info_fops, bond); &bond_info_fops, bond);
if (bond->proc_entry == NULL) if (bond->proc_entry == NULL)
pr_warning(DRV_NAME pr_warning(DRV_NAME
...@@ -3375,8 +3370,11 @@ static void bond_create_proc_entry(struct bonding *bond) ...@@ -3375,8 +3370,11 @@ static void bond_create_proc_entry(struct bonding *bond)
static void bond_remove_proc_entry(struct bonding *bond) static void bond_remove_proc_entry(struct bonding *bond)
{ {
if (bond_proc_dir && bond->proc_entry) { struct net_device *bond_dev = bond->dev;
remove_proc_entry(bond->proc_file_name, bond_proc_dir); struct bond_net *bn = net_generic(dev_net(bond_dev), bond_net_id);
if (bn->proc_dir && bond->proc_entry) {
remove_proc_entry(bond->proc_file_name, bn->proc_dir);
memset(bond->proc_file_name, 0, IFNAMSIZ); memset(bond->proc_file_name, 0, IFNAMSIZ);
bond->proc_entry = NULL; bond->proc_entry = NULL;
} }
...@@ -3385,11 +3383,11 @@ static void bond_remove_proc_entry(struct bonding *bond) ...@@ -3385,11 +3383,11 @@ static void bond_remove_proc_entry(struct bonding *bond)
/* Create the bonding directory under /proc/net, if doesn't exist yet. /* Create the bonding directory under /proc/net, if doesn't exist yet.
* Caller must hold rtnl_lock. * Caller must hold rtnl_lock.
*/ */
static void bond_create_proc_dir(void) static void bond_create_proc_dir(struct bond_net *bn)
{ {
if (!bond_proc_dir) { if (!bn->proc_dir) {
bond_proc_dir = proc_mkdir(DRV_NAME, init_net.proc_net); bn->proc_dir = proc_mkdir(DRV_NAME, bn->net->proc_net);
if (!bond_proc_dir) if (!bn->proc_dir)
pr_warning(DRV_NAME pr_warning(DRV_NAME
": Warning: cannot create /proc/net/%s\n", ": Warning: cannot create /proc/net/%s\n",
DRV_NAME); DRV_NAME);
...@@ -3399,11 +3397,11 @@ static void bond_create_proc_dir(void) ...@@ -3399,11 +3397,11 @@ static void bond_create_proc_dir(void)
/* Destroy the bonding directory under /proc/net, if empty. /* Destroy the bonding directory under /proc/net, if empty.
* Caller must hold rtnl_lock. * Caller must hold rtnl_lock.
*/ */
static void bond_destroy_proc_dir(void) static void bond_destroy_proc_dir(struct bond_net *bn)
{ {
if (bond_proc_dir) { if (bn->proc_dir) {
remove_proc_entry(DRV_NAME, init_net.proc_net); remove_proc_entry(DRV_NAME, bn->net->proc_net);
bond_proc_dir = NULL; bn->proc_dir = NULL;
} }
} }
...@@ -3417,11 +3415,11 @@ static void bond_remove_proc_entry(struct bonding *bond) ...@@ -3417,11 +3415,11 @@ static void bond_remove_proc_entry(struct bonding *bond)
{ {
} }
static void bond_create_proc_dir(void) static void bond_create_proc_dir(struct bond_net *bn)
{ {
} }
static void bond_destroy_proc_dir(void) static void bond_destroy_proc_dir(struct bond_net *bn)
{ {
} }
...@@ -3540,9 +3538,6 @@ static int bond_netdev_event(struct notifier_block *this, ...@@ -3540,9 +3538,6 @@ static int bond_netdev_event(struct notifier_block *this,
{ {
struct net_device *event_dev = (struct net_device *)ptr; struct net_device *event_dev = (struct net_device *)ptr;
if (dev_net(event_dev) != &init_net)
return NOTIFY_DONE;
pr_debug("event_dev: %s, event: %lx\n", pr_debug("event_dev: %s, event: %lx\n",
(event_dev ? event_dev->name : "None"), (event_dev ? event_dev->name : "None"),
event); event);
...@@ -3575,13 +3570,11 @@ static int bond_inetaddr_event(struct notifier_block *this, unsigned long event, ...@@ -3575,13 +3570,11 @@ static int bond_inetaddr_event(struct notifier_block *this, unsigned long event,
{ {
struct in_ifaddr *ifa = ptr; struct in_ifaddr *ifa = ptr;
struct net_device *vlan_dev, *event_dev = ifa->ifa_dev->dev; struct net_device *vlan_dev, *event_dev = ifa->ifa_dev->dev;
struct bond_net *bn = net_generic(dev_net(event_dev), bond_net_id);
struct bonding *bond; struct bonding *bond;
struct vlan_entry *vlan; struct vlan_entry *vlan;
if (dev_net(ifa->ifa_dev->dev) != &init_net) list_for_each_entry(bond, &bn->dev_list, bond_list) {
return NOTIFY_DONE;
list_for_each_entry(bond, &bond_dev_list, bond_list) {
if (bond->dev == event_dev) { if (bond->dev == event_dev) {
switch (event) { switch (event) {
case NETDEV_UP: case NETDEV_UP:
...@@ -3950,7 +3943,7 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd ...@@ -3950,7 +3943,7 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
return -EPERM; return -EPERM;
slave_dev = dev_get_by_name(&init_net, ifr->ifr_slave); slave_dev = dev_get_by_name(dev_net(bond_dev), ifr->ifr_slave);
pr_debug("slave_dev=%p: \n", slave_dev); pr_debug("slave_dev=%p: \n", slave_dev);
...@@ -5031,6 +5024,7 @@ static void bond_set_lockdep_class(struct net_device *dev) ...@@ -5031,6 +5024,7 @@ static void bond_set_lockdep_class(struct net_device *dev)
static int bond_init(struct net_device *bond_dev) static int bond_init(struct net_device *bond_dev)
{ {
struct bonding *bond = netdev_priv(bond_dev); struct bonding *bond = netdev_priv(bond_dev);
struct bond_net *bn = net_generic(dev_net(bond_dev), bond_net_id);
pr_debug("Begin bond_init for %s\n", bond_dev->name); pr_debug("Begin bond_init for %s\n", bond_dev->name);
...@@ -5043,7 +5037,7 @@ static int bond_init(struct net_device *bond_dev) ...@@ -5043,7 +5037,7 @@ static int bond_init(struct net_device *bond_dev)
netif_carrier_off(bond_dev); netif_carrier_off(bond_dev);
bond_create_proc_entry(bond); bond_create_proc_entry(bond);
list_add_tail(&bond->bond_list, &bond_dev_list); list_add_tail(&bond->bond_list, &bn->dev_list);
bond_prepare_sysfs_group(bond); bond_prepare_sysfs_group(bond);
return 0; return 0;
...@@ -5071,7 +5065,7 @@ static struct rtnl_link_ops bond_link_ops __read_mostly = { ...@@ -5071,7 +5065,7 @@ static struct rtnl_link_ops bond_link_ops __read_mostly = {
* Caller must NOT hold rtnl_lock; we need to release it here before we * Caller must NOT hold rtnl_lock; we need to release it here before we
* set up our sysfs entries. * set up our sysfs entries.
*/ */
int bond_create(const char *name) int bond_create(struct net *net, const char *name)
{ {
struct net_device *bond_dev; struct net_device *bond_dev;
int res; int res;
...@@ -5087,6 +5081,7 @@ int bond_create(const char *name) ...@@ -5087,6 +5081,7 @@ int bond_create(const char *name)
goto out; goto out;
} }
dev_net_set(bond_dev, net);
bond_dev->rtnl_link_ops = &bond_link_ops; bond_dev->rtnl_link_ops = &bond_link_ops;
if (!name) { if (!name) {
...@@ -5105,6 +5100,46 @@ out_netdev: ...@@ -5105,6 +5100,46 @@ out_netdev:
goto out; goto out;
} }
static int bond_net_init(struct net *net)
{
struct bond_net *bn;
int err;
err = -ENOMEM;
bn = kzalloc(sizeof(struct bond_net), GFP_KERNEL);
if (bn == NULL)
goto out;
bn->net = net;
INIT_LIST_HEAD(&bn->dev_list);
err = net_assign_generic(net, bond_net_id, bn);
if (err)
goto out_free;
bond_create_proc_dir(bn);
out:
return err;
out_free:
kfree(bn);
goto out;
}
static void bond_net_exit(struct net *net)
{
struct bond_net *bn;
bn = net_generic(net, bond_net_id);
bond_destroy_proc_dir(bn);
kfree(bn);
}
static struct pernet_operations bond_net_ops = {
.init = bond_net_init,
.exit = bond_net_exit,
};
static int __init bonding_init(void) static int __init bonding_init(void)
{ {
int i; int i;
...@@ -5116,14 +5151,16 @@ static int __init bonding_init(void) ...@@ -5116,14 +5151,16 @@ static int __init bonding_init(void)
if (res) if (res)
goto out; goto out;
bond_create_proc_dir(); res = register_pernet_gen_subsys(&bond_net_id, &bond_net_ops);
if (res)
goto out;
res = rtnl_link_register(&bond_link_ops); res = rtnl_link_register(&bond_link_ops);
if (res) if (res)
goto err; goto err;
for (i = 0; i < max_bonds; i++) { for (i = 0; i < max_bonds; i++) {
res = bond_create(NULL); res = bond_create(&init_net, NULL);
if (res) if (res)
goto err; goto err;
} }
...@@ -5139,7 +5176,7 @@ out: ...@@ -5139,7 +5176,7 @@ out:
return res; return res;
err: err:
rtnl_link_unregister(&bond_link_ops); rtnl_link_unregister(&bond_link_ops);
bond_destroy_proc_dir(); unregister_pernet_gen_subsys(bond_net_id, &bond_net_ops);
goto out; goto out;
} }
...@@ -5153,7 +5190,7 @@ static void __exit bonding_exit(void) ...@@ -5153,7 +5190,7 @@ static void __exit bonding_exit(void)
bond_destroy_sysfs(); bond_destroy_sysfs();
rtnl_link_unregister(&bond_link_ops); rtnl_link_unregister(&bond_link_ops);
bond_destroy_proc_dir(); unregister_pernet_gen_subsys(bond_net_id, &bond_net_ops);
} }
module_init(bonding_init); module_init(bonding_init);
......
...@@ -35,6 +35,8 @@ ...@@ -35,6 +35,8 @@
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <net/net_namespace.h> #include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <linux/nsproxy.h>
#include "bonding.h" #include "bonding.h"
...@@ -47,12 +49,14 @@ ...@@ -47,12 +49,14 @@
*/ */
static ssize_t bonding_show_bonds(struct class *cls, char *buf) static ssize_t bonding_show_bonds(struct class *cls, char *buf)
{ {
struct net *net = current->nsproxy->net_ns;
struct bond_net *bn = net_generic(net, bond_net_id);
int res = 0; int res = 0;
struct bonding *bond; struct bonding *bond;
rtnl_lock(); rtnl_lock();
list_for_each_entry(bond, &bond_dev_list, bond_list) { list_for_each_entry(bond, &bn->dev_list, bond_list) {
if (res > (PAGE_SIZE - IFNAMSIZ)) { if (res > (PAGE_SIZE - IFNAMSIZ)) {
/* not enough space for another interface name */ /* not enough space for another interface name */
if ((PAGE_SIZE - res) > 10) if ((PAGE_SIZE - res) > 10)
...@@ -69,11 +73,12 @@ static ssize_t bonding_show_bonds(struct class *cls, char *buf) ...@@ -69,11 +73,12 @@ static ssize_t bonding_show_bonds(struct class *cls, char *buf)
return res; return res;
} }
static struct net_device *bond_get_by_name(const char *ifname) static struct net_device *bond_get_by_name(struct net *net, const char *ifname)
{ {
struct bond_net *bn = net_generic(net, bond_net_id);
struct bonding *bond; struct bonding *bond;
list_for_each_entry(bond, &bond_dev_list, bond_list) { list_for_each_entry(bond, &bn->dev_list, bond_list) {
if (strncmp(bond->dev->name, ifname, IFNAMSIZ) == 0) if (strncmp(bond->dev->name, ifname, IFNAMSIZ) == 0)
return bond->dev; return bond->dev;
} }
...@@ -91,6 +96,7 @@ static struct net_device *bond_get_by_name(const char *ifname) ...@@ -91,6 +96,7 @@ static struct net_device *bond_get_by_name(const char *ifname)
static ssize_t bonding_store_bonds(struct class *cls, static ssize_t bonding_store_bonds(struct class *cls,
const char *buffer, size_t count) const char *buffer, size_t count)
{ {
struct net *net = current->nsproxy->net_ns;
char command[IFNAMSIZ + 1] = {0, }; char command[IFNAMSIZ + 1] = {0, };
char *ifname; char *ifname;
int rv, res = count; int rv, res = count;
...@@ -104,7 +110,7 @@ static ssize_t bonding_store_bonds(struct class *cls, ...@@ -104,7 +110,7 @@ static ssize_t bonding_store_bonds(struct class *cls,
if (command[0] == '+') { if (command[0] == '+') {
pr_info(DRV_NAME pr_info(DRV_NAME
": %s is being created...\n", ifname); ": %s is being created...\n", ifname);
rv = bond_create(ifname); rv = bond_create(net, ifname);
if (rv) { if (rv) {
pr_info(DRV_NAME ": Bond creation failed.\n"); pr_info(DRV_NAME ": Bond creation failed.\n");
res = rv; res = rv;
...@@ -113,7 +119,7 @@ static ssize_t bonding_store_bonds(struct class *cls, ...@@ -113,7 +119,7 @@ static ssize_t bonding_store_bonds(struct class *cls,
struct net_device *bond_dev; struct net_device *bond_dev;
rtnl_lock(); rtnl_lock();
bond_dev = bond_get_by_name(ifname); bond_dev = bond_get_by_name(net, ifname);
if (bond_dev) { if (bond_dev) {
pr_info(DRV_NAME ": %s is being deleted...\n", pr_info(DRV_NAME ": %s is being deleted...\n",
ifname); ifname);
...@@ -238,8 +244,7 @@ static ssize_t bonding_store_slaves(struct device *d, ...@@ -238,8 +244,7 @@ static ssize_t bonding_store_slaves(struct device *d,
/* Got a slave name in ifname. Is it already in the list? */ /* Got a slave name in ifname. Is it already in the list? */
found = 0; found = 0;
/* FIXME: get netns from sysfs object */ dev = __dev_get_by_name(dev_net(bond->dev), ifname);
dev = __dev_get_by_name(&init_net, ifname);
if (!dev) { if (!dev) {
pr_info(DRV_NAME pr_info(DRV_NAME
": %s: Interface %s does not exist!\n", ": %s: Interface %s does not exist!\n",
......
...@@ -30,8 +30,6 @@ ...@@ -30,8 +30,6 @@
#define BOND_MAX_ARP_TARGETS 16 #define BOND_MAX_ARP_TARGETS 16
extern struct list_head bond_dev_list;
#define IS_UP(dev) \ #define IS_UP(dev) \
((((dev)->flags & IFF_UP) == IFF_UP) && \ ((((dev)->flags & IFF_UP) == IFF_UP) && \
netif_running(dev) && \ netif_running(dev) && \
...@@ -327,7 +325,7 @@ static inline void bond_unset_master_alb_flags(struct bonding *bond) ...@@ -327,7 +325,7 @@ static inline void bond_unset_master_alb_flags(struct bonding *bond)
struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr); struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr);
int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev); int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev);
int bond_create(const char *name); int bond_create(struct net *net, const char *name);
int bond_release_and_destroy(struct net_device *bond_dev, struct net_device *slave_dev); int bond_release_and_destroy(struct net_device *bond_dev, struct net_device *slave_dev);
int bond_create_sysfs(void); int bond_create_sysfs(void);
void bond_destroy_sysfs(void); void bond_destroy_sysfs(void);
...@@ -346,8 +344,16 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active); ...@@ -346,8 +344,16 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active);
void bond_register_arp(struct bonding *); void bond_register_arp(struct bonding *);
void bond_unregister_arp(struct bonding *); void bond_unregister_arp(struct bonding *);
struct bond_net {
struct net * net; /* Associated network namespace */
struct list_head dev_list;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry * proc_dir;
#endif
};
/* exported from bond_main.c */ /* exported from bond_main.c */
extern struct list_head bond_dev_list; extern int bond_net_id;
extern const struct bond_parm_tbl bond_lacp_tbl[]; extern const struct bond_parm_tbl bond_lacp_tbl[];
extern const struct bond_parm_tbl bond_mode_tbl[]; extern const struct bond_parm_tbl bond_mode_tbl[];
extern const struct bond_parm_tbl xmit_hashtype_tbl[]; extern const struct bond_parm_tbl xmit_hashtype_tbl[];
......
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