diff options
author | David S. Miller <davem@davemloft.net> | 2013-10-19 18:59:25 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-10-19 18:59:25 -0400 |
commit | 97e592bd29cdadfb544f7850ad873b87d277b1ab (patch) | |
tree | 07d936d41e71ae5413b66f9b556194c0113f7a71 | |
parent | b1eda2ac3fa6bf23b27c7c70eda6885124c79ed3 (diff) | |
parent | ec76aa49855f6d6fea5e01de179fb57dd47c619d (diff) |
Merge branch 'bonding'
Jiri Pirko says:
====================
bonding: introduce bonding options Netlink support
This patchset basically allows "mode" and "active_slave" bonding options
to be propagated and set up via standart RT Netlink interface.
In future other options can be easily added as well.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/bonding/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/bonding/bond_main.c | 91 | ||||
-rw-r--r-- | drivers/net/bonding/bond_netlink.c | 131 | ||||
-rw-r--r-- | drivers/net/bonding/bond_options.c | 142 | ||||
-rw-r--r-- | drivers/net/bonding/bond_sysfs.c | 127 | ||||
-rw-r--r-- | drivers/net/bonding/bonding.h | 19 | ||||
-rw-r--r-- | include/uapi/linux/if_link.h | 11 |
7 files changed, 337 insertions, 186 deletions
diff --git a/drivers/net/bonding/Makefile b/drivers/net/bonding/Makefile index 4c21bf6b8b2f..5a5d720da929 100644 --- a/drivers/net/bonding/Makefile +++ b/drivers/net/bonding/Makefile | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_BONDING) += bonding.o | 5 | obj-$(CONFIG_BONDING) += bonding.o |
6 | 6 | ||
7 | bonding-objs := bond_main.o bond_3ad.o bond_alb.o bond_sysfs.o bond_debugfs.o | 7 | bonding-objs := bond_main.o bond_3ad.o bond_alb.o bond_sysfs.o bond_debugfs.o bond_netlink.o bond_options.o |
8 | 8 | ||
9 | proc-$(CONFIG_PROC_FS) += bond_procfs.o | 9 | proc-$(CONFIG_PROC_FS) += bond_procfs.o |
10 | bonding-objs += $(proc-y) | 10 | bonding-objs += $(proc-y) |
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index dfb4f6dd5de0..d90734fca918 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c | |||
@@ -1910,61 +1910,6 @@ static int bond_release_and_destroy(struct net_device *bond_dev, | |||
1910 | return ret; | 1910 | return ret; |
1911 | } | 1911 | } |
1912 | 1912 | ||
1913 | /* | ||
1914 | * This function changes the active slave to slave <slave_dev>. | ||
1915 | * It returns -EINVAL in the following cases. | ||
1916 | * - <slave_dev> is not found in the list. | ||
1917 | * - There is not active slave now. | ||
1918 | * - <slave_dev> is already active. | ||
1919 | * - The link state of <slave_dev> is not BOND_LINK_UP. | ||
1920 | * - <slave_dev> is not running. | ||
1921 | * In these cases, this function does nothing. | ||
1922 | * In the other cases, current_slave pointer is changed and 0 is returned. | ||
1923 | */ | ||
1924 | static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_device *slave_dev) | ||
1925 | { | ||
1926 | struct bonding *bond = netdev_priv(bond_dev); | ||
1927 | struct slave *old_active = NULL; | ||
1928 | struct slave *new_active = NULL; | ||
1929 | int res = 0; | ||
1930 | |||
1931 | if (!USES_PRIMARY(bond->params.mode)) | ||
1932 | return -EINVAL; | ||
1933 | |||
1934 | /* Verify that bond_dev is indeed the master of slave_dev */ | ||
1935 | if (!(slave_dev->flags & IFF_SLAVE) || | ||
1936 | !netdev_has_upper_dev(slave_dev, bond_dev)) | ||
1937 | return -EINVAL; | ||
1938 | |||
1939 | read_lock(&bond->lock); | ||
1940 | |||
1941 | old_active = bond->curr_active_slave; | ||
1942 | new_active = bond_get_slave_by_dev(bond, slave_dev); | ||
1943 | /* | ||
1944 | * Changing to the current active: do nothing; return success. | ||
1945 | */ | ||
1946 | if (new_active && new_active == old_active) { | ||
1947 | read_unlock(&bond->lock); | ||
1948 | return 0; | ||
1949 | } | ||
1950 | |||
1951 | if (new_active && | ||
1952 | old_active && | ||
1953 | new_active->link == BOND_LINK_UP && | ||
1954 | IS_UP(new_active->dev)) { | ||
1955 | block_netpoll_tx(); | ||
1956 | write_lock_bh(&bond->curr_slave_lock); | ||
1957 | bond_change_active_slave(bond, new_active); | ||
1958 | write_unlock_bh(&bond->curr_slave_lock); | ||
1959 | unblock_netpoll_tx(); | ||
1960 | } else | ||
1961 | res = -EINVAL; | ||
1962 | |||
1963 | read_unlock(&bond->lock); | ||
1964 | |||
1965 | return res; | ||
1966 | } | ||
1967 | |||
1968 | static int bond_info_query(struct net_device *bond_dev, struct ifbond *info) | 1913 | static int bond_info_query(struct net_device *bond_dev, struct ifbond *info) |
1969 | { | 1914 | { |
1970 | struct bonding *bond = netdev_priv(bond_dev); | 1915 | struct bonding *bond = netdev_priv(bond_dev); |
@@ -3257,6 +3202,7 @@ static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev, | |||
3257 | 3202 | ||
3258 | static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd) | 3203 | static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd) |
3259 | { | 3204 | { |
3205 | struct bonding *bond = netdev_priv(bond_dev); | ||
3260 | struct net_device *slave_dev = NULL; | 3206 | struct net_device *slave_dev = NULL; |
3261 | struct ifbond k_binfo; | 3207 | struct ifbond k_binfo; |
3262 | struct ifbond __user *u_binfo = NULL; | 3208 | struct ifbond __user *u_binfo = NULL; |
@@ -3287,7 +3233,6 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd | |||
3287 | 3233 | ||
3288 | 3234 | ||
3289 | if (mii->reg_num == 1) { | 3235 | if (mii->reg_num == 1) { |
3290 | struct bonding *bond = netdev_priv(bond_dev); | ||
3291 | mii->val_out = 0; | 3236 | mii->val_out = 0; |
3292 | read_lock(&bond->lock); | 3237 | read_lock(&bond->lock); |
3293 | read_lock(&bond->curr_slave_lock); | 3238 | read_lock(&bond->curr_slave_lock); |
@@ -3359,7 +3304,7 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd | |||
3359 | break; | 3304 | break; |
3360 | case BOND_CHANGE_ACTIVE_OLD: | 3305 | case BOND_CHANGE_ACTIVE_OLD: |
3361 | case SIOCBONDCHANGEACTIVE: | 3306 | case SIOCBONDCHANGEACTIVE: |
3362 | res = bond_ioctl_change_active(bond_dev, slave_dev); | 3307 | res = bond_option_active_slave_set(bond, slave_dev); |
3363 | break; | 3308 | break; |
3364 | default: | 3309 | default: |
3365 | res = -EOPNOTSUPP; | 3310 | res = -EOPNOTSUPP; |
@@ -3951,7 +3896,7 @@ static void bond_destructor(struct net_device *bond_dev) | |||
3951 | free_netdev(bond_dev); | 3896 | free_netdev(bond_dev); |
3952 | } | 3897 | } |
3953 | 3898 | ||
3954 | static void bond_setup(struct net_device *bond_dev) | 3899 | void bond_setup(struct net_device *bond_dev) |
3955 | { | 3900 | { |
3956 | struct bonding *bond = netdev_priv(bond_dev); | 3901 | struct bonding *bond = netdev_priv(bond_dev); |
3957 | 3902 | ||
@@ -4451,32 +4396,11 @@ static int bond_init(struct net_device *bond_dev) | |||
4451 | return 0; | 4396 | return 0; |
4452 | } | 4397 | } |
4453 | 4398 | ||
4454 | static int bond_validate(struct nlattr *tb[], struct nlattr *data[]) | 4399 | unsigned int bond_get_num_tx_queues(void) |
4455 | { | ||
4456 | if (tb[IFLA_ADDRESS]) { | ||
4457 | if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) | ||
4458 | return -EINVAL; | ||
4459 | if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) | ||
4460 | return -EADDRNOTAVAIL; | ||
4461 | } | ||
4462 | return 0; | ||
4463 | } | ||
4464 | |||
4465 | static unsigned int bond_get_num_tx_queues(void) | ||
4466 | { | 4400 | { |
4467 | return tx_queues; | 4401 | return tx_queues; |
4468 | } | 4402 | } |
4469 | 4403 | ||
4470 | static struct rtnl_link_ops bond_link_ops __read_mostly = { | ||
4471 | .kind = "bond", | ||
4472 | .priv_size = sizeof(struct bonding), | ||
4473 | .setup = bond_setup, | ||
4474 | .validate = bond_validate, | ||
4475 | .get_num_tx_queues = bond_get_num_tx_queues, | ||
4476 | .get_num_rx_queues = bond_get_num_tx_queues, /* Use the same number | ||
4477 | as for TX queues */ | ||
4478 | }; | ||
4479 | |||
4480 | /* Create a new bond based on the specified name and bonding parameters. | 4404 | /* Create a new bond based on the specified name and bonding parameters. |
4481 | * If name is NULL, obtain a suitable "bond%d" name for us. | 4405 | * If name is NULL, obtain a suitable "bond%d" name for us. |
4482 | * Caller must NOT hold rtnl_lock; we need to release it here before we | 4406 | * Caller must NOT hold rtnl_lock; we need to release it here before we |
@@ -4563,7 +4487,7 @@ static int __init bonding_init(void) | |||
4563 | if (res) | 4487 | if (res) |
4564 | goto out; | 4488 | goto out; |
4565 | 4489 | ||
4566 | res = rtnl_link_register(&bond_link_ops); | 4490 | res = bond_netlink_init(); |
4567 | if (res) | 4491 | if (res) |
4568 | goto err_link; | 4492 | goto err_link; |
4569 | 4493 | ||
@@ -4579,7 +4503,7 @@ static int __init bonding_init(void) | |||
4579 | out: | 4503 | out: |
4580 | return res; | 4504 | return res; |
4581 | err: | 4505 | err: |
4582 | rtnl_link_unregister(&bond_link_ops); | 4506 | bond_netlink_fini(); |
4583 | err_link: | 4507 | err_link: |
4584 | unregister_pernet_subsys(&bond_net_ops); | 4508 | unregister_pernet_subsys(&bond_net_ops); |
4585 | goto out; | 4509 | goto out; |
@@ -4592,7 +4516,7 @@ static void __exit bonding_exit(void) | |||
4592 | 4516 | ||
4593 | bond_destroy_debugfs(); | 4517 | bond_destroy_debugfs(); |
4594 | 4518 | ||
4595 | rtnl_link_unregister(&bond_link_ops); | 4519 | bond_netlink_fini(); |
4596 | unregister_pernet_subsys(&bond_net_ops); | 4520 | unregister_pernet_subsys(&bond_net_ops); |
4597 | 4521 | ||
4598 | #ifdef CONFIG_NET_POLL_CONTROLLER | 4522 | #ifdef CONFIG_NET_POLL_CONTROLLER |
@@ -4609,4 +4533,3 @@ MODULE_LICENSE("GPL"); | |||
4609 | MODULE_VERSION(DRV_VERSION); | 4533 | MODULE_VERSION(DRV_VERSION); |
4610 | MODULE_DESCRIPTION(DRV_DESCRIPTION ", v" DRV_VERSION); | 4534 | MODULE_DESCRIPTION(DRV_DESCRIPTION ", v" DRV_VERSION); |
4611 | MODULE_AUTHOR("Thomas Davis, tadavis@lbl.gov and many others"); | 4535 | MODULE_AUTHOR("Thomas Davis, tadavis@lbl.gov and many others"); |
4612 | MODULE_ALIAS_RTNL_LINK("bond"); | ||
diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c new file mode 100644 index 000000000000..fe3500bb34e4 --- /dev/null +++ b/drivers/net/bonding/bond_netlink.c | |||
@@ -0,0 +1,131 @@ | |||
1 | /* | ||
2 | * drivers/net/bond/bond_netlink.c - Netlink interface for bonding | ||
3 | * Copyright (c) 2013 Jiri Pirko <jiri@resnulli.us> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | */ | ||
10 | |||
11 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/errno.h> | ||
15 | #include <linux/netdevice.h> | ||
16 | #include <linux/etherdevice.h> | ||
17 | #include <linux/if_link.h> | ||
18 | #include <linux/if_ether.h> | ||
19 | #include <net/netlink.h> | ||
20 | #include <net/rtnetlink.h> | ||
21 | #include "bonding.h" | ||
22 | |||
23 | static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = { | ||
24 | [IFLA_BOND_MODE] = { .type = NLA_U8 }, | ||
25 | [IFLA_BOND_ACTIVE_SLAVE] = { .type = NLA_U32 }, | ||
26 | }; | ||
27 | |||
28 | static int bond_validate(struct nlattr *tb[], struct nlattr *data[]) | ||
29 | { | ||
30 | if (tb[IFLA_ADDRESS]) { | ||
31 | if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) | ||
32 | return -EINVAL; | ||
33 | if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) | ||
34 | return -EADDRNOTAVAIL; | ||
35 | } | ||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | static int bond_changelink(struct net_device *bond_dev, | ||
40 | struct nlattr *tb[], struct nlattr *data[]) | ||
41 | { | ||
42 | struct bonding *bond = netdev_priv(bond_dev); | ||
43 | int err; | ||
44 | |||
45 | if (data && data[IFLA_BOND_MODE]) { | ||
46 | int mode = nla_get_u8(data[IFLA_BOND_MODE]); | ||
47 | |||
48 | err = bond_option_mode_set(bond, mode); | ||
49 | if (err) | ||
50 | return err; | ||
51 | } | ||
52 | if (data && data[IFLA_BOND_ACTIVE_SLAVE]) { | ||
53 | int ifindex = nla_get_u32(data[IFLA_BOND_ACTIVE_SLAVE]); | ||
54 | struct net_device *slave_dev; | ||
55 | |||
56 | if (ifindex == 0) { | ||
57 | slave_dev = NULL; | ||
58 | } else { | ||
59 | slave_dev = __dev_get_by_index(dev_net(bond_dev), | ||
60 | ifindex); | ||
61 | if (!slave_dev) | ||
62 | return -ENODEV; | ||
63 | } | ||
64 | err = bond_option_active_slave_set(bond, slave_dev); | ||
65 | if (err) | ||
66 | return err; | ||
67 | } | ||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | static int bond_newlink(struct net *src_net, struct net_device *bond_dev, | ||
72 | struct nlattr *tb[], struct nlattr *data[]) | ||
73 | { | ||
74 | int err; | ||
75 | |||
76 | err = bond_changelink(bond_dev, tb, data); | ||
77 | if (err < 0) | ||
78 | return err; | ||
79 | |||
80 | return register_netdevice(bond_dev); | ||
81 | } | ||
82 | |||
83 | static size_t bond_get_size(const struct net_device *bond_dev) | ||
84 | { | ||
85 | return nla_total_size(sizeof(u8)); /* IFLA_BOND_MODE */ | ||
86 | + nla_total_size(sizeof(u32)); /* IFLA_BOND_ACTIVE_SLAVE */ | ||
87 | } | ||
88 | |||
89 | static int bond_fill_info(struct sk_buff *skb, | ||
90 | const struct net_device *bond_dev) | ||
91 | { | ||
92 | struct bonding *bond = netdev_priv(bond_dev); | ||
93 | struct net_device *slave_dev = bond_option_active_slave_get(bond); | ||
94 | |||
95 | if (nla_put_u8(skb, IFLA_BOND_MODE, bond->params.mode) || | ||
96 | (slave_dev && | ||
97 | nla_put_u32(skb, IFLA_BOND_ACTIVE_SLAVE, slave_dev->ifindex))) | ||
98 | goto nla_put_failure; | ||
99 | return 0; | ||
100 | |||
101 | nla_put_failure: | ||
102 | return -EMSGSIZE; | ||
103 | } | ||
104 | |||
105 | struct rtnl_link_ops bond_link_ops __read_mostly = { | ||
106 | .kind = "bond", | ||
107 | .priv_size = sizeof(struct bonding), | ||
108 | .setup = bond_setup, | ||
109 | .maxtype = IFLA_BOND_MAX, | ||
110 | .policy = bond_policy, | ||
111 | .validate = bond_validate, | ||
112 | .newlink = bond_newlink, | ||
113 | .changelink = bond_changelink, | ||
114 | .get_size = bond_get_size, | ||
115 | .fill_info = bond_fill_info, | ||
116 | .get_num_tx_queues = bond_get_num_tx_queues, | ||
117 | .get_num_rx_queues = bond_get_num_tx_queues, /* Use the same number | ||
118 | as for TX queues */ | ||
119 | }; | ||
120 | |||
121 | int __init bond_netlink_init(void) | ||
122 | { | ||
123 | return rtnl_link_register(&bond_link_ops); | ||
124 | } | ||
125 | |||
126 | void __exit bond_netlink_fini(void) | ||
127 | { | ||
128 | rtnl_link_unregister(&bond_link_ops); | ||
129 | } | ||
130 | |||
131 | MODULE_ALIAS_RTNL_LINK("bond"); | ||
diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c new file mode 100644 index 000000000000..9a5223c7b4d1 --- /dev/null +++ b/drivers/net/bonding/bond_options.c | |||
@@ -0,0 +1,142 @@ | |||
1 | /* | ||
2 | * drivers/net/bond/bond_options.c - bonding options | ||
3 | * Copyright (c) 2013 Jiri Pirko <jiri@resnulli.us> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | */ | ||
10 | |||
11 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
12 | |||
13 | #include <linux/errno.h> | ||
14 | #include <linux/if.h> | ||
15 | #include <linux/netdevice.h> | ||
16 | #include <linux/rwlock.h> | ||
17 | #include <linux/rcupdate.h> | ||
18 | #include "bonding.h" | ||
19 | |||
20 | static bool bond_mode_is_valid(int mode) | ||
21 | { | ||
22 | int i; | ||
23 | |||
24 | for (i = 0; bond_mode_tbl[i].modename; i++); | ||
25 | |||
26 | return mode >= 0 && mode < i; | ||
27 | } | ||
28 | |||
29 | int bond_option_mode_set(struct bonding *bond, int mode) | ||
30 | { | ||
31 | if (!bond_mode_is_valid(mode)) { | ||
32 | pr_err("invalid mode value %d.\n", mode); | ||
33 | return -EINVAL; | ||
34 | } | ||
35 | |||
36 | if (bond->dev->flags & IFF_UP) { | ||
37 | pr_err("%s: unable to update mode because interface is up.\n", | ||
38 | bond->dev->name); | ||
39 | return -EPERM; | ||
40 | } | ||
41 | |||
42 | if (bond_has_slaves(bond)) { | ||
43 | pr_err("%s: unable to update mode because bond has slaves.\n", | ||
44 | bond->dev->name); | ||
45 | return -EPERM; | ||
46 | } | ||
47 | |||
48 | if (BOND_MODE_IS_LB(mode) && bond->params.arp_interval) { | ||
49 | pr_err("%s: %s mode is incompatible with arp monitoring.\n", | ||
50 | bond->dev->name, bond_mode_tbl[mode].modename); | ||
51 | return -EINVAL; | ||
52 | } | ||
53 | |||
54 | /* don't cache arp_validate between modes */ | ||
55 | bond->params.arp_validate = BOND_ARP_VALIDATE_NONE; | ||
56 | bond->params.mode = mode; | ||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | static struct net_device *__bond_option_active_slave_get(struct bonding *bond, | ||
61 | struct slave *slave) | ||
62 | { | ||
63 | return USES_PRIMARY(bond->params.mode) && slave ? slave->dev : NULL; | ||
64 | } | ||
65 | |||
66 | struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond) | ||
67 | { | ||
68 | struct slave *slave = rcu_dereference(bond->curr_active_slave); | ||
69 | |||
70 | return __bond_option_active_slave_get(bond, slave); | ||
71 | } | ||
72 | |||
73 | struct net_device *bond_option_active_slave_get(struct bonding *bond) | ||
74 | { | ||
75 | return __bond_option_active_slave_get(bond, bond->curr_active_slave); | ||
76 | } | ||
77 | |||
78 | int bond_option_active_slave_set(struct bonding *bond, | ||
79 | struct net_device *slave_dev) | ||
80 | { | ||
81 | int ret = 0; | ||
82 | |||
83 | if (slave_dev) { | ||
84 | if (!netif_is_bond_slave(slave_dev)) { | ||
85 | pr_err("Device %s is not bonding slave.\n", | ||
86 | slave_dev->name); | ||
87 | return -EINVAL; | ||
88 | } | ||
89 | |||
90 | if (bond->dev != netdev_master_upper_dev_get(slave_dev)) { | ||
91 | pr_err("%s: Device %s is not our slave.\n", | ||
92 | bond->dev->name, slave_dev->name); | ||
93 | return -EINVAL; | ||
94 | } | ||
95 | } | ||
96 | |||
97 | if (!USES_PRIMARY(bond->params.mode)) { | ||
98 | pr_err("%s: Unable to change active slave; %s is in mode %d\n", | ||
99 | bond->dev->name, bond->dev->name, bond->params.mode); | ||
100 | return -EINVAL; | ||
101 | } | ||
102 | |||
103 | block_netpoll_tx(); | ||
104 | read_lock(&bond->lock); | ||
105 | write_lock_bh(&bond->curr_slave_lock); | ||
106 | |||
107 | /* check to see if we are clearing active */ | ||
108 | if (!slave_dev) { | ||
109 | pr_info("%s: Clearing current active slave.\n", | ||
110 | bond->dev->name); | ||
111 | rcu_assign_pointer(bond->curr_active_slave, NULL); | ||
112 | bond_select_active_slave(bond); | ||
113 | } else { | ||
114 | struct slave *old_active = bond->curr_active_slave; | ||
115 | struct slave *new_active = bond_slave_get_rtnl(slave_dev); | ||
116 | |||
117 | BUG_ON(!new_active); | ||
118 | |||
119 | if (new_active == old_active) { | ||
120 | /* do nothing */ | ||
121 | pr_info("%s: %s is already the current active slave.\n", | ||
122 | bond->dev->name, new_active->dev->name); | ||
123 | } else { | ||
124 | if (old_active && (new_active->link == BOND_LINK_UP) && | ||
125 | IS_UP(new_active->dev)) { | ||
126 | pr_info("%s: Setting %s as active slave.\n", | ||
127 | bond->dev->name, new_active->dev->name); | ||
128 | bond_change_active_slave(bond, new_active); | ||
129 | } else { | ||
130 | pr_err("%s: Could not set %s as active slave; either %s is down or the link is down.\n", | ||
131 | bond->dev->name, new_active->dev->name, | ||
132 | new_active->dev->name); | ||
133 | ret = -EINVAL; | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | |||
138 | write_unlock_bh(&bond->curr_slave_lock); | ||
139 | read_unlock(&bond->lock); | ||
140 | unblock_netpoll_tx(); | ||
141 | return ret; | ||
142 | } | ||
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 03bed0ca935e..47749c970a01 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, | |||
283 | struct device_attribute *attr, | 283 | struct device_attribute *attr, |
284 | const char *buf, size_t count) | 284 | const char *buf, size_t count) |
285 | { | 285 | { |
286 | int new_value, ret = count; | 286 | int new_value, ret; |
287 | struct bonding *bond = to_bond(d); | 287 | struct bonding *bond = to_bond(d); |
288 | 288 | ||
289 | if (!rtnl_trylock()) | ||
290 | return restart_syscall(); | ||
291 | |||
292 | if (bond->dev->flags & IFF_UP) { | ||
293 | pr_err("unable to update mode of %s because interface is up.\n", | ||
294 | bond->dev->name); | ||
295 | ret = -EPERM; | ||
296 | goto out; | ||
297 | } | ||
298 | |||
299 | if (bond_has_slaves(bond)) { | ||
300 | pr_err("unable to update mode of %s because it has slaves.\n", | ||
301 | bond->dev->name); | ||
302 | ret = -EPERM; | ||
303 | goto out; | ||
304 | } | ||
305 | |||
306 | new_value = bond_parse_parm(buf, bond_mode_tbl); | 289 | new_value = bond_parse_parm(buf, bond_mode_tbl); |
307 | if (new_value < 0) { | 290 | if (new_value < 0) { |
308 | pr_err("%s: Ignoring invalid mode value %.*s.\n", | 291 | pr_err("%s: Ignoring invalid mode value %.*s.\n", |
309 | bond->dev->name, (int)strlen(buf) - 1, buf); | 292 | bond->dev->name, (int)strlen(buf) - 1, buf); |
310 | ret = -EINVAL; | 293 | return -EINVAL; |
311 | goto out; | ||
312 | } | 294 | } |
313 | if ((new_value == BOND_MODE_ALB || | 295 | if (!rtnl_trylock()) |
314 | new_value == BOND_MODE_TLB) && | 296 | return restart_syscall(); |
315 | bond->params.arp_interval) { | 297 | |
316 | pr_err("%s: %s mode is incompatible with arp monitoring.\n", | 298 | ret = bond_option_mode_set(bond, new_value); |
317 | bond->dev->name, bond_mode_tbl[new_value].modename); | 299 | if (!ret) { |
318 | ret = -EINVAL; | 300 | pr_info("%s: setting mode to %s (%d).\n", |
319 | goto out; | 301 | bond->dev->name, bond_mode_tbl[new_value].modename, |
302 | new_value); | ||
303 | ret = count; | ||
320 | } | 304 | } |
321 | 305 | ||
322 | /* don't cache arp_validate between modes */ | ||
323 | bond->params.arp_validate = BOND_ARP_VALIDATE_NONE; | ||
324 | bond->params.mode = new_value; | ||
325 | pr_info("%s: setting mode to %s (%d).\n", | ||
326 | bond->dev->name, bond_mode_tbl[new_value].modename, | ||
327 | new_value); | ||
328 | out: | ||
329 | rtnl_unlock(); | 306 | rtnl_unlock(); |
330 | return ret; | 307 | return ret; |
331 | } | 308 | } |
@@ -1242,13 +1219,13 @@ static ssize_t bonding_show_active_slave(struct device *d, | |||
1242 | char *buf) | 1219 | char *buf) |
1243 | { | 1220 | { |
1244 | struct bonding *bond = to_bond(d); | 1221 | struct bonding *bond = to_bond(d); |
1245 | struct slave *curr; | 1222 | struct net_device *slave_dev; |
1246 | int count = 0; | 1223 | int count = 0; |
1247 | 1224 | ||
1248 | rcu_read_lock(); | 1225 | rcu_read_lock(); |
1249 | curr = rcu_dereference(bond->curr_active_slave); | 1226 | slave_dev = bond_option_active_slave_get_rcu(bond); |
1250 | if (USES_PRIMARY(bond->params.mode) && curr) | 1227 | if (slave_dev) |
1251 | count = sprintf(buf, "%s\n", curr->dev->name); | 1228 | count = sprintf(buf, "%s\n", slave_dev->name); |
1252 | rcu_read_unlock(); | 1229 | rcu_read_unlock(); |
1253 | 1230 | ||
1254 | return count; | 1231 | return count; |
@@ -1258,81 +1235,33 @@ static ssize_t bonding_store_active_slave(struct device *d, | |||
1258 | struct device_attribute *attr, | 1235 | struct device_attribute *attr, |
1259 | const char *buf, size_t count) | 1236 | const char *buf, size_t count) |
1260 | { | 1237 | { |
1261 | struct slave *slave, *old_active, *new_active; | 1238 | int ret; |
1262 | struct bonding *bond = to_bond(d); | 1239 | struct bonding *bond = to_bond(d); |
1263 | struct list_head *iter; | ||
1264 | char ifname[IFNAMSIZ]; | 1240 | char ifname[IFNAMSIZ]; |
1241 | struct net_device *dev; | ||
1265 | 1242 | ||
1266 | if (!rtnl_trylock()) | 1243 | if (!rtnl_trylock()) |
1267 | return restart_syscall(); | 1244 | return restart_syscall(); |
1268 | 1245 | ||
1269 | old_active = new_active = NULL; | ||
1270 | block_netpoll_tx(); | ||
1271 | read_lock(&bond->lock); | ||
1272 | write_lock_bh(&bond->curr_slave_lock); | ||
1273 | |||
1274 | if (!USES_PRIMARY(bond->params.mode)) { | ||
1275 | pr_info("%s: Unable to change active slave; %s is in mode %d\n", | ||
1276 | bond->dev->name, bond->dev->name, bond->params.mode); | ||
1277 | goto out; | ||
1278 | } | ||
1279 | |||
1280 | sscanf(buf, "%15s", ifname); /* IFNAMSIZ */ | 1246 | sscanf(buf, "%15s", ifname); /* IFNAMSIZ */ |
1281 | |||
1282 | /* check to see if we are clearing active */ | ||
1283 | if (!strlen(ifname) || buf[0] == '\n') { | 1247 | if (!strlen(ifname) || buf[0] == '\n') { |
1284 | pr_info("%s: Clearing current active slave.\n", | 1248 | dev = NULL; |
1285 | bond->dev->name); | 1249 | } else { |
1286 | rcu_assign_pointer(bond->curr_active_slave, NULL); | 1250 | dev = __dev_get_by_name(dev_net(bond->dev), ifname); |
1287 | bond_select_active_slave(bond); | 1251 | if (!dev) { |
1288 | goto out; | 1252 | ret = -ENODEV; |
1289 | } | 1253 | goto out; |
1290 | |||
1291 | bond_for_each_slave(bond, slave, iter) { | ||
1292 | if (strncmp(slave->dev->name, ifname, IFNAMSIZ) == 0) { | ||
1293 | old_active = bond->curr_active_slave; | ||
1294 | new_active = slave; | ||
1295 | if (new_active == old_active) { | ||
1296 | /* do nothing */ | ||
1297 | pr_info("%s: %s is already the current" | ||
1298 | " active slave.\n", | ||
1299 | bond->dev->name, | ||
1300 | slave->dev->name); | ||
1301 | goto out; | ||
1302 | } else { | ||
1303 | if ((new_active) && | ||
1304 | (old_active) && | ||
1305 | (new_active->link == BOND_LINK_UP) && | ||
1306 | IS_UP(new_active->dev)) { | ||
1307 | pr_info("%s: Setting %s as active" | ||
1308 | " slave.\n", | ||
1309 | bond->dev->name, | ||
1310 | slave->dev->name); | ||
1311 | bond_change_active_slave(bond, | ||
1312 | new_active); | ||
1313 | } else { | ||
1314 | pr_info("%s: Could not set %s as" | ||
1315 | " active slave; either %s is" | ||
1316 | " down or the link is down.\n", | ||
1317 | bond->dev->name, | ||
1318 | slave->dev->name, | ||
1319 | slave->dev->name); | ||
1320 | } | ||
1321 | goto out; | ||
1322 | } | ||
1323 | } | 1254 | } |
1324 | } | 1255 | } |
1325 | 1256 | ||
1326 | pr_info("%s: Unable to set %.*s as active slave.\n", | 1257 | ret = bond_option_active_slave_set(bond, dev); |
1327 | bond->dev->name, (int)strlen(buf) - 1, buf); | 1258 | if (!ret) |
1328 | out: | 1259 | ret = count; |
1329 | write_unlock_bh(&bond->curr_slave_lock); | ||
1330 | read_unlock(&bond->lock); | ||
1331 | unblock_netpoll_tx(); | ||
1332 | 1260 | ||
1261 | out: | ||
1333 | rtnl_unlock(); | 1262 | rtnl_unlock(); |
1334 | 1263 | ||
1335 | return count; | 1264 | return ret; |
1336 | 1265 | ||
1337 | } | 1266 | } |
1338 | static DEVICE_ATTR(active_slave, S_IRUGO | S_IWUSR, | 1267 | static DEVICE_ATTR(active_slave, S_IRUGO | S_IWUSR, |
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index bb5c731e2560..046a60535e04 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h | |||
@@ -58,6 +58,11 @@ | |||
58 | #define TX_QUEUE_OVERRIDE(mode) \ | 58 | #define TX_QUEUE_OVERRIDE(mode) \ |
59 | (((mode) == BOND_MODE_ACTIVEBACKUP) || \ | 59 | (((mode) == BOND_MODE_ACTIVEBACKUP) || \ |
60 | ((mode) == BOND_MODE_ROUNDROBIN)) | 60 | ((mode) == BOND_MODE_ROUNDROBIN)) |
61 | |||
62 | #define BOND_MODE_IS_LB(mode) \ | ||
63 | (((mode) == BOND_MODE_TLB) || \ | ||
64 | ((mode) == BOND_MODE_ALB)) | ||
65 | |||
61 | /* | 66 | /* |
62 | * Less bad way to call ioctl from within the kernel; this needs to be | 67 | * Less bad way to call ioctl from within the kernel; this needs to be |
63 | * done some other way to get the call out of interrupt context. | 68 | * 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) | |||
259 | 264 | ||
260 | static inline bool bond_is_lb(const struct bonding *bond) | 265 | static inline bool bond_is_lb(const struct bonding *bond) |
261 | { | 266 | { |
262 | return (bond->params.mode == BOND_MODE_TLB || | 267 | return BOND_MODE_IS_LB(bond->params.mode); |
263 | bond->params.mode == BOND_MODE_ALB); | ||
264 | } | 268 | } |
265 | 269 | ||
266 | static inline void bond_set_active_slave(struct slave *slave) | 270 | static inline void bond_set_active_slave(struct slave *slave) |
@@ -418,6 +422,14 @@ void bond_debug_register(struct bonding *bond); | |||
418 | void bond_debug_unregister(struct bonding *bond); | 422 | void bond_debug_unregister(struct bonding *bond); |
419 | void bond_debug_reregister(struct bonding *bond); | 423 | void bond_debug_reregister(struct bonding *bond); |
420 | const char *bond_mode_name(int mode); | 424 | const char *bond_mode_name(int mode); |
425 | void bond_setup(struct net_device *bond_dev); | ||
426 | unsigned int bond_get_num_tx_queues(void); | ||
427 | int bond_netlink_init(void); | ||
428 | void bond_netlink_fini(void); | ||
429 | int bond_option_mode_set(struct bonding *bond, int mode); | ||
430 | int bond_option_active_slave_set(struct bonding *bond, struct net_device *slave_dev); | ||
431 | struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond); | ||
432 | struct net_device *bond_option_active_slave_get(struct bonding *bond); | ||
421 | 433 | ||
422 | struct bond_net { | 434 | struct bond_net { |
423 | struct net * net; /* Associated network namespace */ | 435 | struct net * net; /* Associated network namespace */ |
@@ -505,4 +517,7 @@ extern const struct bond_parm_tbl fail_over_mac_tbl[]; | |||
505 | extern const struct bond_parm_tbl pri_reselect_tbl[]; | 517 | extern const struct bond_parm_tbl pri_reselect_tbl[]; |
506 | extern struct bond_parm_tbl ad_select_tbl[]; | 518 | extern struct bond_parm_tbl ad_select_tbl[]; |
507 | 519 | ||
520 | /* exported from bond_netlink.c */ | ||
521 | extern struct rtnl_link_ops bond_link_ops; | ||
522 | |||
508 | #endif /* _LINUX_BONDING_H */ | 523 | #endif /* _LINUX_BONDING_H */ |
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 80394e8dc3a3..8a1e346243b7 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h | |||
@@ -325,6 +325,17 @@ struct ifla_vxlan_port_range { | |||
325 | __be16 high; | 325 | __be16 high; |
326 | }; | 326 | }; |
327 | 327 | ||
328 | /* Bonding section */ | ||
329 | |||
330 | enum { | ||
331 | IFLA_BOND_UNSPEC, | ||
332 | IFLA_BOND_MODE, | ||
333 | IFLA_BOND_ACTIVE_SLAVE, | ||
334 | __IFLA_BOND_MAX, | ||
335 | }; | ||
336 | |||
337 | #define IFLA_BOND_MAX (__IFLA_BOND_MAX - 1) | ||
338 | |||
328 | /* SR-IOV virtual function management section */ | 339 | /* SR-IOV virtual function management section */ |
329 | 340 | ||
330 | enum { | 341 | enum { |