diff options
Diffstat (limited to 'drivers/net/bonding')
-rw-r--r-- | drivers/net/bonding/bond_netlink.c | 78 | ||||
-rw-r--r-- | drivers/net/bonding/bond_options.c | 80 | ||||
-rw-r--r-- | drivers/net/bonding/bond_sysfs.c | 116 | ||||
-rw-r--r-- | drivers/net/bonding/bonding.h | 7 |
4 files changed, 220 insertions, 61 deletions
diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index e161c9cbd91e..84acd144d075 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/if_ether.h> | 19 | #include <linux/if_ether.h> |
20 | #include <net/netlink.h> | 20 | #include <net/netlink.h> |
21 | #include <net/rtnetlink.h> | 21 | #include <net/rtnetlink.h> |
22 | #include <linux/reciprocal_div.h> | ||
22 | #include "bonding.h" | 23 | #include "bonding.h" |
23 | 24 | ||
24 | static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = { | 25 | static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = { |
@@ -37,6 +38,11 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = { | |||
37 | [IFLA_BOND_FAIL_OVER_MAC] = { .type = NLA_U8 }, | 38 | [IFLA_BOND_FAIL_OVER_MAC] = { .type = NLA_U8 }, |
38 | [IFLA_BOND_XMIT_HASH_POLICY] = { .type = NLA_U8 }, | 39 | [IFLA_BOND_XMIT_HASH_POLICY] = { .type = NLA_U8 }, |
39 | [IFLA_BOND_RESEND_IGMP] = { .type = NLA_U32 }, | 40 | [IFLA_BOND_RESEND_IGMP] = { .type = NLA_U32 }, |
41 | [IFLA_BOND_NUM_PEER_NOTIF] = { .type = NLA_U8 }, | ||
42 | [IFLA_BOND_ALL_SLAVES_ACTIVE] = { .type = NLA_U8 }, | ||
43 | [IFLA_BOND_MIN_LINKS] = { .type = NLA_U32 }, | ||
44 | [IFLA_BOND_LP_INTERVAL] = { .type = NLA_U32 }, | ||
45 | [IFLA_BOND_PACKETS_PER_SLAVE] = { .type = NLA_U32 }, | ||
40 | }; | 46 | }; |
41 | 47 | ||
42 | static int bond_validate(struct nlattr *tb[], struct nlattr *data[]) | 48 | static int bond_validate(struct nlattr *tb[], struct nlattr *data[]) |
@@ -204,6 +210,48 @@ static int bond_changelink(struct net_device *bond_dev, | |||
204 | if (err) | 210 | if (err) |
205 | return err; | 211 | return err; |
206 | } | 212 | } |
213 | if (data[IFLA_BOND_NUM_PEER_NOTIF]) { | ||
214 | int num_peer_notif = | ||
215 | nla_get_u8(data[IFLA_BOND_NUM_PEER_NOTIF]); | ||
216 | |||
217 | err = bond_option_num_peer_notif_set(bond, num_peer_notif); | ||
218 | if (err) | ||
219 | return err; | ||
220 | } | ||
221 | if (data[IFLA_BOND_ALL_SLAVES_ACTIVE]) { | ||
222 | int all_slaves_active = | ||
223 | nla_get_u8(data[IFLA_BOND_ALL_SLAVES_ACTIVE]); | ||
224 | |||
225 | err = bond_option_all_slaves_active_set(bond, | ||
226 | all_slaves_active); | ||
227 | if (err) | ||
228 | return err; | ||
229 | } | ||
230 | if (data[IFLA_BOND_MIN_LINKS]) { | ||
231 | int min_links = | ||
232 | nla_get_u32(data[IFLA_BOND_MIN_LINKS]); | ||
233 | |||
234 | err = bond_option_min_links_set(bond, min_links); | ||
235 | if (err) | ||
236 | return err; | ||
237 | } | ||
238 | if (data[IFLA_BOND_LP_INTERVAL]) { | ||
239 | int lp_interval = | ||
240 | nla_get_u32(data[IFLA_BOND_LP_INTERVAL]); | ||
241 | |||
242 | err = bond_option_lp_interval_set(bond, lp_interval); | ||
243 | if (err) | ||
244 | return err; | ||
245 | } | ||
246 | if (data[IFLA_BOND_PACKETS_PER_SLAVE]) { | ||
247 | int packets_per_slave = | ||
248 | nla_get_u32(data[IFLA_BOND_PACKETS_PER_SLAVE]); | ||
249 | |||
250 | err = bond_option_packets_per_slave_set(bond, | ||
251 | packets_per_slave); | ||
252 | if (err) | ||
253 | return err; | ||
254 | } | ||
207 | return 0; | 255 | return 0; |
208 | } | 256 | } |
209 | 257 | ||
@@ -237,6 +285,11 @@ static size_t bond_get_size(const struct net_device *bond_dev) | |||
237 | nla_total_size(sizeof(u8)) + /* IFLA_BOND_FAIL_OVER_MAC */ | 285 | nla_total_size(sizeof(u8)) + /* IFLA_BOND_FAIL_OVER_MAC */ |
238 | nla_total_size(sizeof(u8)) + /* IFLA_BOND_XMIT_HASH_POLICY */ | 286 | nla_total_size(sizeof(u8)) + /* IFLA_BOND_XMIT_HASH_POLICY */ |
239 | nla_total_size(sizeof(u32)) + /* IFLA_BOND_RESEND_IGMP */ | 287 | nla_total_size(sizeof(u32)) + /* IFLA_BOND_RESEND_IGMP */ |
288 | nla_total_size(sizeof(u8)) + /* IFLA_BOND_NUM_PEER_NOTIF */ | ||
289 | nla_total_size(sizeof(u8)) + /* IFLA_BOND_ALL_SLAVES_ACTIVE */ | ||
290 | nla_total_size(sizeof(u32)) + /* IFLA_BOND_MIN_LINKS */ | ||
291 | nla_total_size(sizeof(u32)) + /* IFLA_BOND_LP_INTERVAL */ | ||
292 | nla_total_size(sizeof(u32)) + /* IFLA_BOND_PACKETS_PER_SLAVE */ | ||
240 | 0; | 293 | 0; |
241 | } | 294 | } |
242 | 295 | ||
@@ -246,6 +299,7 @@ static int bond_fill_info(struct sk_buff *skb, | |||
246 | struct bonding *bond = netdev_priv(bond_dev); | 299 | struct bonding *bond = netdev_priv(bond_dev); |
247 | struct net_device *slave_dev = bond_option_active_slave_get(bond); | 300 | struct net_device *slave_dev = bond_option_active_slave_get(bond); |
248 | struct nlattr *targets; | 301 | struct nlattr *targets; |
302 | unsigned int packets_per_slave; | ||
249 | int i, targets_added; | 303 | int i, targets_added; |
250 | 304 | ||
251 | if (nla_put_u8(skb, IFLA_BOND_MODE, bond->params.mode)) | 305 | if (nla_put_u8(skb, IFLA_BOND_MODE, bond->params.mode)) |
@@ -317,6 +371,30 @@ static int bond_fill_info(struct sk_buff *skb, | |||
317 | bond->params.resend_igmp)) | 371 | bond->params.resend_igmp)) |
318 | goto nla_put_failure; | 372 | goto nla_put_failure; |
319 | 373 | ||
374 | if (nla_put_u8(skb, IFLA_BOND_NUM_PEER_NOTIF, | ||
375 | bond->params.num_peer_notif)) | ||
376 | goto nla_put_failure; | ||
377 | |||
378 | if (nla_put_u8(skb, IFLA_BOND_ALL_SLAVES_ACTIVE, | ||
379 | bond->params.all_slaves_active)) | ||
380 | goto nla_put_failure; | ||
381 | |||
382 | if (nla_put_u32(skb, IFLA_BOND_MIN_LINKS, | ||
383 | bond->params.min_links)) | ||
384 | goto nla_put_failure; | ||
385 | |||
386 | if (nla_put_u32(skb, IFLA_BOND_LP_INTERVAL, | ||
387 | bond->params.lp_interval)) | ||
388 | goto nla_put_failure; | ||
389 | |||
390 | packets_per_slave = bond->params.packets_per_slave; | ||
391 | if (packets_per_slave > 1) | ||
392 | packets_per_slave = reciprocal_value(packets_per_slave); | ||
393 | |||
394 | if (nla_put_u32(skb, IFLA_BOND_PACKETS_PER_SLAVE, | ||
395 | packets_per_slave)) | ||
396 | goto nla_put_failure; | ||
397 | |||
320 | return 0; | 398 | return 0; |
321 | 399 | ||
322 | nla_put_failure: | 400 | nla_put_failure: |
diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index 1ed7dff9a679..f8a2cd8c7b57 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/netdevice.h> | 16 | #include <linux/netdevice.h> |
17 | #include <linux/rwlock.h> | 17 | #include <linux/rwlock.h> |
18 | #include <linux/rcupdate.h> | 18 | #include <linux/rcupdate.h> |
19 | #include <linux/reciprocal_div.h> | ||
19 | #include "bonding.h" | 20 | #include "bonding.h" |
20 | 21 | ||
21 | static bool bond_mode_is_valid(int mode) | 22 | static bool bond_mode_is_valid(int mode) |
@@ -576,3 +577,82 @@ int bond_option_resend_igmp_set(struct bonding *bond, int resend_igmp) | |||
576 | 577 | ||
577 | return 0; | 578 | return 0; |
578 | } | 579 | } |
580 | |||
581 | int bond_option_num_peer_notif_set(struct bonding *bond, int num_peer_notif) | ||
582 | { | ||
583 | bond->params.num_peer_notif = num_peer_notif; | ||
584 | return 0; | ||
585 | } | ||
586 | |||
587 | int bond_option_all_slaves_active_set(struct bonding *bond, | ||
588 | int all_slaves_active) | ||
589 | { | ||
590 | struct list_head *iter; | ||
591 | struct slave *slave; | ||
592 | |||
593 | if (all_slaves_active == bond->params.all_slaves_active) | ||
594 | return 0; | ||
595 | |||
596 | if ((all_slaves_active == 0) || (all_slaves_active == 1)) { | ||
597 | bond->params.all_slaves_active = all_slaves_active; | ||
598 | } else { | ||
599 | pr_info("%s: Ignoring invalid all_slaves_active value %d.\n", | ||
600 | bond->dev->name, all_slaves_active); | ||
601 | return -EINVAL; | ||
602 | } | ||
603 | |||
604 | bond_for_each_slave(bond, slave, iter) { | ||
605 | if (!bond_is_active_slave(slave)) { | ||
606 | if (all_slaves_active) | ||
607 | slave->inactive = 0; | ||
608 | else | ||
609 | slave->inactive = 1; | ||
610 | } | ||
611 | } | ||
612 | |||
613 | return 0; | ||
614 | } | ||
615 | |||
616 | int bond_option_min_links_set(struct bonding *bond, int min_links) | ||
617 | { | ||
618 | pr_info("%s: Setting min links value to %u\n", | ||
619 | bond->dev->name, min_links); | ||
620 | bond->params.min_links = min_links; | ||
621 | |||
622 | return 0; | ||
623 | } | ||
624 | |||
625 | int bond_option_lp_interval_set(struct bonding *bond, int lp_interval) | ||
626 | { | ||
627 | if (lp_interval <= 0) { | ||
628 | pr_err("%s: lp_interval must be between 1 and %d\n", | ||
629 | bond->dev->name, INT_MAX); | ||
630 | return -EINVAL; | ||
631 | } | ||
632 | |||
633 | bond->params.lp_interval = lp_interval; | ||
634 | |||
635 | return 0; | ||
636 | } | ||
637 | |||
638 | int bond_option_packets_per_slave_set(struct bonding *bond, | ||
639 | int packets_per_slave) | ||
640 | { | ||
641 | if (packets_per_slave < 0 || packets_per_slave > USHRT_MAX) { | ||
642 | pr_err("%s: packets_per_slave must be between 0 and %u\n", | ||
643 | bond->dev->name, USHRT_MAX); | ||
644 | return -EINVAL; | ||
645 | } | ||
646 | |||
647 | if (bond->params.mode != BOND_MODE_ROUNDROBIN) | ||
648 | pr_warn("%s: Warning: packets_per_slave has effect only in balance-rr mode\n", | ||
649 | bond->dev->name); | ||
650 | |||
651 | if (packets_per_slave > 1) | ||
652 | bond->params.packets_per_slave = | ||
653 | reciprocal_value(packets_per_slave); | ||
654 | else | ||
655 | bond->params.packets_per_slave = packets_per_slave; | ||
656 | |||
657 | return 0; | ||
658 | } | ||
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index f5c1a54095b9..a0a3476fadba 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c | |||
@@ -722,10 +722,15 @@ static ssize_t bonding_store_min_links(struct device *d, | |||
722 | return ret; | 722 | return ret; |
723 | } | 723 | } |
724 | 724 | ||
725 | pr_info("%s: Setting min links value to %u\n", | 725 | if (!rtnl_trylock()) |
726 | bond->dev->name, new_value); | 726 | return restart_syscall(); |
727 | bond->params.min_links = new_value; | 727 | |
728 | return count; | 728 | ret = bond_option_min_links_set(bond, new_value); |
729 | if (!ret) | ||
730 | ret = count; | ||
731 | |||
732 | rtnl_unlock(); | ||
733 | return ret; | ||
729 | } | 734 | } |
730 | static DEVICE_ATTR(min_links, S_IRUGO | S_IWUSR, | 735 | static DEVICE_ATTR(min_links, S_IRUGO | S_IWUSR, |
731 | bonding_show_min_links, bonding_store_min_links); | 736 | bonding_show_min_links, bonding_store_min_links); |
@@ -790,8 +795,25 @@ static ssize_t bonding_store_num_peer_notif(struct device *d, | |||
790 | const char *buf, size_t count) | 795 | const char *buf, size_t count) |
791 | { | 796 | { |
792 | struct bonding *bond = to_bond(d); | 797 | struct bonding *bond = to_bond(d); |
793 | int err = kstrtou8(buf, 10, &bond->params.num_peer_notif); | 798 | u8 new_value; |
794 | return err ? err : count; | 799 | int ret; |
800 | |||
801 | ret = kstrtou8(buf, 10, &new_value); | ||
802 | if (!ret) { | ||
803 | pr_err("%s: invalid value %s specified.\n", | ||
804 | bond->dev->name, buf); | ||
805 | return ret; | ||
806 | } | ||
807 | |||
808 | if (!rtnl_trylock()) | ||
809 | return restart_syscall(); | ||
810 | |||
811 | ret = bond_option_num_peer_notif_set(bond, new_value); | ||
812 | if (!ret) | ||
813 | ret = count; | ||
814 | |||
815 | rtnl_unlock(); | ||
816 | return ret; | ||
795 | } | 817 | } |
796 | static DEVICE_ATTR(num_grat_arp, S_IRUGO | S_IWUSR, | 818 | static DEVICE_ATTR(num_grat_arp, S_IRUGO | S_IWUSR, |
797 | bonding_show_num_peer_notif, bonding_store_num_peer_notif); | 819 | bonding_show_num_peer_notif, bonding_store_num_peer_notif); |
@@ -1273,41 +1295,21 @@ static ssize_t bonding_store_slaves_active(struct device *d, | |||
1273 | const char *buf, size_t count) | 1295 | const char *buf, size_t count) |
1274 | { | 1296 | { |
1275 | struct bonding *bond = to_bond(d); | 1297 | struct bonding *bond = to_bond(d); |
1276 | int new_value, ret = count; | 1298 | int new_value, ret; |
1277 | struct list_head *iter; | ||
1278 | struct slave *slave; | ||
1279 | |||
1280 | if (!rtnl_trylock()) | ||
1281 | return restart_syscall(); | ||
1282 | 1299 | ||
1283 | if (sscanf(buf, "%d", &new_value) != 1) { | 1300 | if (sscanf(buf, "%d", &new_value) != 1) { |
1284 | pr_err("%s: no all_slaves_active value specified.\n", | 1301 | pr_err("%s: no all_slaves_active value specified.\n", |
1285 | bond->dev->name); | 1302 | bond->dev->name); |
1286 | ret = -EINVAL; | 1303 | return -EINVAL; |
1287 | goto out; | ||
1288 | } | 1304 | } |
1289 | 1305 | ||
1290 | if (new_value == bond->params.all_slaves_active) | 1306 | if (!rtnl_trylock()) |
1291 | goto out; | 1307 | return restart_syscall(); |
1292 | 1308 | ||
1293 | if ((new_value == 0) || (new_value == 1)) { | 1309 | ret = bond_option_all_slaves_active_set(bond, new_value); |
1294 | bond->params.all_slaves_active = new_value; | 1310 | if (!ret) |
1295 | } else { | 1311 | ret = count; |
1296 | pr_info("%s: Ignoring invalid all_slaves_active value %d.\n", | ||
1297 | bond->dev->name, new_value); | ||
1298 | ret = -EINVAL; | ||
1299 | goto out; | ||
1300 | } | ||
1301 | 1312 | ||
1302 | bond_for_each_slave(bond, slave, iter) { | ||
1303 | if (!bond_is_active_slave(slave)) { | ||
1304 | if (new_value) | ||
1305 | slave->inactive = 0; | ||
1306 | else | ||
1307 | slave->inactive = 1; | ||
1308 | } | ||
1309 | } | ||
1310 | out: | ||
1311 | rtnl_unlock(); | 1313 | rtnl_unlock(); |
1312 | return ret; | 1314 | return ret; |
1313 | } | 1315 | } |
@@ -1367,24 +1369,22 @@ static ssize_t bonding_store_lp_interval(struct device *d, | |||
1367 | const char *buf, size_t count) | 1369 | const char *buf, size_t count) |
1368 | { | 1370 | { |
1369 | struct bonding *bond = to_bond(d); | 1371 | struct bonding *bond = to_bond(d); |
1370 | int new_value, ret = count; | 1372 | int new_value, ret; |
1371 | 1373 | ||
1372 | if (sscanf(buf, "%d", &new_value) != 1) { | 1374 | if (sscanf(buf, "%d", &new_value) != 1) { |
1373 | pr_err("%s: no lp interval value specified.\n", | 1375 | pr_err("%s: no lp interval value specified.\n", |
1374 | bond->dev->name); | 1376 | bond->dev->name); |
1375 | ret = -EINVAL; | 1377 | return -EINVAL; |
1376 | goto out; | ||
1377 | } | 1378 | } |
1378 | 1379 | ||
1379 | if (new_value <= 0) { | 1380 | if (!rtnl_trylock()) |
1380 | pr_err ("%s: lp_interval must be between 1 and %d\n", | 1381 | return restart_syscall(); |
1381 | bond->dev->name, INT_MAX); | ||
1382 | ret = -EINVAL; | ||
1383 | goto out; | ||
1384 | } | ||
1385 | 1382 | ||
1386 | bond->params.lp_interval = new_value; | 1383 | ret = bond_option_lp_interval_set(bond, new_value); |
1387 | out: | 1384 | if (!ret) |
1385 | ret = count; | ||
1386 | |||
1387 | rtnl_unlock(); | ||
1388 | return ret; | 1388 | return ret; |
1389 | } | 1389 | } |
1390 | 1390 | ||
@@ -1409,28 +1409,22 @@ static ssize_t bonding_store_packets_per_slave(struct device *d, | |||
1409 | const char *buf, size_t count) | 1409 | const char *buf, size_t count) |
1410 | { | 1410 | { |
1411 | struct bonding *bond = to_bond(d); | 1411 | struct bonding *bond = to_bond(d); |
1412 | int new_value, ret = count; | 1412 | int new_value, ret; |
1413 | 1413 | ||
1414 | if (sscanf(buf, "%d", &new_value) != 1) { | 1414 | if (sscanf(buf, "%d", &new_value) != 1) { |
1415 | pr_err("%s: no packets_per_slave value specified.\n", | 1415 | pr_err("%s: no packets_per_slave value specified.\n", |
1416 | bond->dev->name); | 1416 | bond->dev->name); |
1417 | ret = -EINVAL; | 1417 | return -EINVAL; |
1418 | goto out; | ||
1419 | } | ||
1420 | if (new_value < 0 || new_value > USHRT_MAX) { | ||
1421 | pr_err("%s: packets_per_slave must be between 0 and %u\n", | ||
1422 | bond->dev->name, USHRT_MAX); | ||
1423 | ret = -EINVAL; | ||
1424 | goto out; | ||
1425 | } | 1418 | } |
1426 | if (bond->params.mode != BOND_MODE_ROUNDROBIN) | 1419 | |
1427 | pr_warn("%s: Warning: packets_per_slave has effect only in balance-rr mode\n", | 1420 | if (!rtnl_trylock()) |
1428 | bond->dev->name); | 1421 | return restart_syscall(); |
1429 | if (new_value > 1) | 1422 | |
1430 | bond->params.packets_per_slave = reciprocal_value(new_value); | 1423 | ret = bond_option_packets_per_slave_set(bond, new_value); |
1431 | else | 1424 | if (!ret) |
1432 | bond->params.packets_per_slave = new_value; | 1425 | ret = count; |
1433 | out: | 1426 | |
1427 | rtnl_unlock(); | ||
1434 | return ret; | 1428 | return ret; |
1435 | } | 1429 | } |
1436 | 1430 | ||
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index c70ad9f02b1e..5886f07dc1f3 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h | |||
@@ -461,6 +461,13 @@ int bond_option_fail_over_mac_set(struct bonding *bond, int fail_over_mac); | |||
461 | int bond_option_xmit_hash_policy_set(struct bonding *bond, | 461 | int bond_option_xmit_hash_policy_set(struct bonding *bond, |
462 | int xmit_hash_policy); | 462 | int xmit_hash_policy); |
463 | int bond_option_resend_igmp_set(struct bonding *bond, int resend_igmp); | 463 | int bond_option_resend_igmp_set(struct bonding *bond, int resend_igmp); |
464 | int bond_option_num_peer_notif_set(struct bonding *bond, int num_peer_notif); | ||
465 | int bond_option_all_slaves_active_set(struct bonding *bond, | ||
466 | int all_slaves_active); | ||
467 | int bond_option_min_links_set(struct bonding *bond, int min_links); | ||
468 | int bond_option_lp_interval_set(struct bonding *bond, int min_links); | ||
469 | int bond_option_packets_per_slave_set(struct bonding *bond, | ||
470 | int packets_per_slave); | ||
464 | struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond); | 471 | struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond); |
465 | struct net_device *bond_option_active_slave_get(struct bonding *bond); | 472 | struct net_device *bond_option_active_slave_get(struct bonding *bond); |
466 | 473 | ||