diff options
-rw-r--r-- | drivers/net/bonding/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/bonding/bond_options.c | 55 | ||||
-rw-r--r-- | drivers/net/bonding/bond_sysfs.c | 45 | ||||
-rw-r--r-- | drivers/net/bonding/bonding.h | 9 |
4 files changed, 74 insertions, 37 deletions
diff --git a/drivers/net/bonding/Makefile b/drivers/net/bonding/Makefile index 09e8b2c83af..5a5d720da92 100644 --- a/drivers/net/bonding/Makefile +++ b/drivers/net/bonding/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_BONDING) += bonding.o -bonding-objs := bond_main.o bond_3ad.o bond_alb.o bond_sysfs.o bond_debugfs.o bond_netlink.o +bonding-objs := bond_main.o bond_3ad.o bond_alb.o bond_sysfs.o bond_debugfs.o bond_netlink.o bond_options.o proc-$(CONFIG_PROC_FS) += bond_procfs.o bonding-objs += $(proc-y) diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c new file mode 100644 index 00000000000..294b7660b05 --- /dev/null +++ b/drivers/net/bonding/bond_options.c @@ -0,0 +1,55 @@ +/* + * drivers/net/bond/bond_options.c - bonding options + * Copyright (c) 2013 Jiri Pirko <jiri@resnulli.us> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/errno.h> +#include <linux/if.h> +#include "bonding.h" + +static bool bond_mode_is_valid(int mode) +{ + int i; + + for (i = 0; bond_mode_tbl[i].modename; i++); + + return mode >= 0 && mode < i; +} + +int bond_option_mode_set(struct bonding *bond, int mode) +{ + if (!bond_mode_is_valid(mode)) { + pr_err("invalid mode value %d.\n", mode); + return -EINVAL; + } + + if (bond->dev->flags & IFF_UP) { + pr_err("%s: unable to update mode because interface is up.\n", + bond->dev->name); + return -EPERM; + } + + if (bond_has_slaves(bond)) { + pr_err("%s: unable to update mode because bond has slaves.\n", + bond->dev->name); + return -EPERM; + } + + if (BOND_MODE_IS_LB(mode) && bond->params.arp_interval) { + pr_err("%s: %s mode is incompatible with arp monitoring.\n", + bond->dev->name, bond_mode_tbl[mode].modename); + return -EINVAL; + } + + /* don't cache arp_validate between modes */ + bond->params.arp_validate = BOND_ARP_VALIDATE_NONE; + bond->params.mode = mode; + return 0; +} diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 03bed0ca935..c234cec10e0 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -283,49 +283,26 @@ static ssize_t bonding_store_mode(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - int new_value, ret = count; + int new_value, ret; struct bonding *bond = to_bond(d); - if (!rtnl_trylock()) - return restart_syscall(); - - if (bond->dev->flags & IFF_UP) { - pr_err("unable to update mode of %s because interface is up.\n", - bond->dev->name); - ret = -EPERM; - goto out; - } - - if (bond_has_slaves(bond)) { - pr_err("unable to update mode of %s because it has slaves.\n", - bond->dev->name); - ret = -EPERM; - goto out; - } - new_value = bond_parse_parm(buf, bond_mode_tbl); if (new_value < 0) { pr_err("%s: Ignoring invalid mode value %.*s.\n", bond->dev->name, (int)strlen(buf) - 1, buf); - ret = -EINVAL; - goto out; + return -EINVAL; } - if ((new_value == BOND_MODE_ALB || - new_value == BOND_MODE_TLB) && - bond->params.arp_interval) { - pr_err("%s: %s mode is incompatible with arp monitoring.\n", - bond->dev->name, bond_mode_tbl[new_value].modename); - ret = -EINVAL; - goto out; + if (!rtnl_trylock()) + return restart_syscall(); + + ret = bond_option_mode_set(bond, new_value); + if (!ret) { + pr_info("%s: setting mode to %s (%d).\n", + bond->dev->name, bond_mode_tbl[new_value].modename, + new_value); + ret = count; } - /* don't cache arp_validate between modes */ - bond->params.arp_validate = BOND_ARP_VALIDATE_NONE; - bond->params.mode = new_value; - pr_info("%s: setting mode to %s (%d).\n", - bond->dev->name, bond_mode_tbl[new_value].modename, - new_value); -out: rtnl_unlock(); return ret; } diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index a2a353bf9ea..7446849a20c 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -58,6 +58,11 @@ #define TX_QUEUE_OVERRIDE(mode) \ (((mode) == BOND_MODE_ACTIVEBACKUP) || \ ((mode) == BOND_MODE_ROUNDROBIN)) + +#define BOND_MODE_IS_LB(mode) \ + (((mode) == BOND_MODE_TLB) || \ + ((mode) == BOND_MODE_ALB)) + /* * Less bad way to call ioctl from within the kernel; this needs to be * done some other way to get the call out of interrupt context. @@ -259,8 +264,7 @@ static inline struct bonding *bond_get_bond_by_slave(struct slave *slave) static inline bool bond_is_lb(const struct bonding *bond) { - return (bond->params.mode == BOND_MODE_TLB || - bond->params.mode == BOND_MODE_ALB); + return BOND_MODE_IS_LB(bond->params.mode); } static inline void bond_set_active_slave(struct slave *slave) @@ -422,6 +426,7 @@ void bond_setup(struct net_device *bond_dev); unsigned int bond_get_num_tx_queues(void); int bond_netlink_init(void); void bond_netlink_fini(void); +int bond_option_mode_set(struct bonding *bond, int mode); struct bond_net { struct net * net; /* Associated network namespace */ |