diff options
Diffstat (limited to 'drivers/net/bonding')
-rw-r--r-- | drivers/net/bonding/bond_main.c | 33 | ||||
-rw-r--r-- | drivers/net/bonding/bond_sysfs.c | 79 | ||||
-rw-r--r-- | drivers/net/bonding/bonding.h | 30 |
3 files changed, 128 insertions, 14 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index d3a70c0d0edd..142d55dc526e 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c | |||
@@ -104,6 +104,7 @@ static char *xmit_hash_policy; | |||
104 | static int arp_interval = BOND_LINK_ARP_INTERV; | 104 | static int arp_interval = BOND_LINK_ARP_INTERV; |
105 | static char *arp_ip_target[BOND_MAX_ARP_TARGETS]; | 105 | static char *arp_ip_target[BOND_MAX_ARP_TARGETS]; |
106 | static char *arp_validate; | 106 | static char *arp_validate; |
107 | static char *arp_all_targets; | ||
107 | static char *fail_over_mac; | 108 | static char *fail_over_mac; |
108 | static int all_slaves_active = 0; | 109 | static int all_slaves_active = 0; |
109 | static struct bond_params bonding_defaults; | 110 | static struct bond_params bonding_defaults; |
@@ -166,6 +167,8 @@ module_param(arp_validate, charp, 0); | |||
166 | MODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes; " | 167 | MODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes; " |
167 | "0 for none (default), 1 for active, " | 168 | "0 for none (default), 1 for active, " |
168 | "2 for backup, 3 for all"); | 169 | "2 for backup, 3 for all"); |
170 | module_param(arp_all_targets, charp, 0); | ||
171 | MODULE_PARM_DESC(arp_all_targets, "fail on any/all arp targets timeout; 0 for any (default), 1 for all"); | ||
169 | module_param(fail_over_mac, charp, 0); | 172 | module_param(fail_over_mac, charp, 0); |
170 | MODULE_PARM_DESC(fail_over_mac, "For active-backup, do not set all slaves to " | 173 | MODULE_PARM_DESC(fail_over_mac, "For active-backup, do not set all slaves to " |
171 | "the same MAC; 0 for none (default), " | 174 | "the same MAC; 0 for none (default), " |
@@ -216,6 +219,12 @@ const struct bond_parm_tbl xmit_hashtype_tbl[] = { | |||
216 | { NULL, -1}, | 219 | { NULL, -1}, |
217 | }; | 220 | }; |
218 | 221 | ||
222 | const struct bond_parm_tbl arp_all_targets_tbl[] = { | ||
223 | { "any", BOND_ARP_TARGETS_ANY}, | ||
224 | { "all", BOND_ARP_TARGETS_ALL}, | ||
225 | { NULL, -1}, | ||
226 | }; | ||
227 | |||
219 | const struct bond_parm_tbl arp_validate_tbl[] = { | 228 | const struct bond_parm_tbl arp_validate_tbl[] = { |
220 | { "none", BOND_ARP_VALIDATE_NONE}, | 229 | { "none", BOND_ARP_VALIDATE_NONE}, |
221 | { "active", BOND_ARP_VALIDATE_ACTIVE}, | 230 | { "active", BOND_ARP_VALIDATE_ACTIVE}, |
@@ -1483,7 +1492,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) | |||
1483 | struct slave *new_slave = NULL; | 1492 | struct slave *new_slave = NULL; |
1484 | struct sockaddr addr; | 1493 | struct sockaddr addr; |
1485 | int link_reporting; | 1494 | int link_reporting; |
1486 | int res = 0; | 1495 | int res = 0, i; |
1487 | 1496 | ||
1488 | if (!bond->params.use_carrier && | 1497 | if (!bond->params.use_carrier && |
1489 | slave_dev->ethtool_ops->get_link == NULL && | 1498 | slave_dev->ethtool_ops->get_link == NULL && |
@@ -1712,6 +1721,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) | |||
1712 | 1721 | ||
1713 | new_slave->last_arp_rx = jiffies - | 1722 | new_slave->last_arp_rx = jiffies - |
1714 | (msecs_to_jiffies(bond->params.arp_interval) + 1); | 1723 | (msecs_to_jiffies(bond->params.arp_interval) + 1); |
1724 | for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) | ||
1725 | new_slave->target_last_arp_rx[i] = new_slave->last_arp_rx; | ||
1715 | 1726 | ||
1716 | if (bond->params.miimon && !bond->params.use_carrier) { | 1727 | if (bond->params.miimon && !bond->params.use_carrier) { |
1717 | link_reporting = bond_check_dev_link(bond, slave_dev, 1); | 1728 | link_reporting = bond_check_dev_link(bond, slave_dev, 1); |
@@ -2610,16 +2621,20 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) | |||
2610 | 2621 | ||
2611 | static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32 sip, __be32 tip) | 2622 | static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32 sip, __be32 tip) |
2612 | { | 2623 | { |
2624 | int i; | ||
2625 | |||
2613 | if (!sip || !bond_has_this_ip(bond, tip)) { | 2626 | if (!sip || !bond_has_this_ip(bond, tip)) { |
2614 | pr_debug("bva: sip %pI4 tip %pI4 not found\n", &sip, &tip); | 2627 | pr_debug("bva: sip %pI4 tip %pI4 not found\n", &sip, &tip); |
2615 | return; | 2628 | return; |
2616 | } | 2629 | } |
2617 | 2630 | ||
2618 | if (bond_get_targets_ip(bond->params.arp_targets, sip) == -1) { | 2631 | i = bond_get_targets_ip(bond->params.arp_targets, sip); |
2632 | if (i == -1) { | ||
2619 | pr_debug("bva: sip %pI4 not found in targets\n", &sip); | 2633 | pr_debug("bva: sip %pI4 not found in targets\n", &sip); |
2620 | return; | 2634 | return; |
2621 | } | 2635 | } |
2622 | slave->last_arp_rx = jiffies; | 2636 | slave->last_arp_rx = jiffies; |
2637 | slave->target_last_arp_rx[i] = jiffies; | ||
2623 | } | 2638 | } |
2624 | 2639 | ||
2625 | static int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond, | 2640 | static int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond, |
@@ -4409,6 +4424,7 @@ int bond_parse_parm(const char *buf, const struct bond_parm_tbl *tbl) | |||
4409 | static int bond_check_params(struct bond_params *params) | 4424 | static int bond_check_params(struct bond_params *params) |
4410 | { | 4425 | { |
4411 | int arp_validate_value, fail_over_mac_value, primary_reselect_value, i; | 4426 | int arp_validate_value, fail_over_mac_value, primary_reselect_value, i; |
4427 | int arp_all_targets_value; | ||
4412 | 4428 | ||
4413 | /* | 4429 | /* |
4414 | * Convert string parameters. | 4430 | * Convert string parameters. |
@@ -4634,6 +4650,18 @@ static int bond_check_params(struct bond_params *params) | |||
4634 | } else | 4650 | } else |
4635 | arp_validate_value = 0; | 4651 | arp_validate_value = 0; |
4636 | 4652 | ||
4653 | arp_all_targets_value = 0; | ||
4654 | if (arp_all_targets) { | ||
4655 | arp_all_targets_value = bond_parse_parm(arp_all_targets, | ||
4656 | arp_all_targets_tbl); | ||
4657 | |||
4658 | if (arp_all_targets_value == -1) { | ||
4659 | pr_err("Error: invalid arp_all_targets_value \"%s\"\n", | ||
4660 | arp_all_targets); | ||
4661 | arp_all_targets_value = 0; | ||
4662 | } | ||
4663 | } | ||
4664 | |||
4637 | if (miimon) { | 4665 | if (miimon) { |
4638 | pr_info("MII link monitoring set to %d ms\n", miimon); | 4666 | pr_info("MII link monitoring set to %d ms\n", miimon); |
4639 | } else if (arp_interval) { | 4667 | } else if (arp_interval) { |
@@ -4698,6 +4726,7 @@ static int bond_check_params(struct bond_params *params) | |||
4698 | params->num_peer_notif = num_peer_notif; | 4726 | params->num_peer_notif = num_peer_notif; |
4699 | params->arp_interval = arp_interval; | 4727 | params->arp_interval = arp_interval; |
4700 | params->arp_validate = arp_validate_value; | 4728 | params->arp_validate = arp_validate_value; |
4729 | params->arp_all_targets = arp_all_targets_value; | ||
4701 | params->updelay = updelay; | 4730 | params->updelay = updelay; |
4702 | params->downdelay = downdelay; | 4731 | params->downdelay = downdelay; |
4703 | params->use_carrier = use_carrier; | 4732 | params->use_carrier = use_carrier; |
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index ece57f146a60..dc36a3d7d9e9 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c | |||
@@ -443,6 +443,44 @@ static ssize_t bonding_store_arp_validate(struct device *d, | |||
443 | 443 | ||
444 | static DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, | 444 | static DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, |
445 | bonding_store_arp_validate); | 445 | bonding_store_arp_validate); |
446 | /* | ||
447 | * Show and set arp_all_targets. | ||
448 | */ | ||
449 | static ssize_t bonding_show_arp_all_targets(struct device *d, | ||
450 | struct device_attribute *attr, | ||
451 | char *buf) | ||
452 | { | ||
453 | struct bonding *bond = to_bond(d); | ||
454 | int value = bond->params.arp_all_targets; | ||
455 | |||
456 | return sprintf(buf, "%s %d\n", arp_all_targets_tbl[value].modename, | ||
457 | value); | ||
458 | } | ||
459 | |||
460 | static ssize_t bonding_store_arp_all_targets(struct device *d, | ||
461 | struct device_attribute *attr, | ||
462 | const char *buf, size_t count) | ||
463 | { | ||
464 | struct bonding *bond = to_bond(d); | ||
465 | int new_value; | ||
466 | |||
467 | new_value = bond_parse_parm(buf, arp_all_targets_tbl); | ||
468 | if (new_value < 0) { | ||
469 | pr_err("%s: Ignoring invalid arp_all_targets value %s\n", | ||
470 | bond->dev->name, buf); | ||
471 | return -EINVAL; | ||
472 | } | ||
473 | pr_info("%s: setting arp_all_targets to %s (%d).\n", | ||
474 | bond->dev->name, arp_all_targets_tbl[new_value].modename, | ||
475 | new_value); | ||
476 | |||
477 | bond->params.arp_all_targets = new_value; | ||
478 | |||
479 | return count; | ||
480 | } | ||
481 | |||
482 | static DEVICE_ATTR(arp_all_targets, S_IRUGO | S_IWUSR, | ||
483 | bonding_show_arp_all_targets, bonding_store_arp_all_targets); | ||
446 | 484 | ||
447 | /* | 485 | /* |
448 | * Show and store fail_over_mac. User only allowed to change the | 486 | * Show and store fail_over_mac. User only allowed to change the |
@@ -590,10 +628,11 @@ static ssize_t bonding_store_arp_targets(struct device *d, | |||
590 | struct device_attribute *attr, | 628 | struct device_attribute *attr, |
591 | const char *buf, size_t count) | 629 | const char *buf, size_t count) |
592 | { | 630 | { |
593 | __be32 newtarget; | ||
594 | int i = 0, ret = -EINVAL; | ||
595 | struct bonding *bond = to_bond(d); | 631 | struct bonding *bond = to_bond(d); |
596 | __be32 *targets; | 632 | struct slave *slave; |
633 | __be32 newtarget, *targets; | ||
634 | unsigned long *targets_rx; | ||
635 | int ind, i, j, ret = -EINVAL; | ||
597 | 636 | ||
598 | targets = bond->params.arp_targets; | 637 | targets = bond->params.arp_targets; |
599 | newtarget = in_aton(buf + 1); | 638 | newtarget = in_aton(buf + 1); |
@@ -611,8 +650,8 @@ static ssize_t bonding_store_arp_targets(struct device *d, | |||
611 | goto out; | 650 | goto out; |
612 | } | 651 | } |
613 | 652 | ||
614 | i = bond_get_targets_ip(targets, 0); /* first free slot */ | 653 | ind = bond_get_targets_ip(targets, 0); /* first free slot */ |
615 | if (i == -1) { | 654 | if (ind == -1) { |
616 | pr_err("%s: ARP target table is full!\n", | 655 | pr_err("%s: ARP target table is full!\n", |
617 | bond->dev->name); | 656 | bond->dev->name); |
618 | goto out; | 657 | goto out; |
@@ -620,7 +659,12 @@ static ssize_t bonding_store_arp_targets(struct device *d, | |||
620 | 659 | ||
621 | pr_info("%s: adding ARP target %pI4.\n", bond->dev->name, | 660 | pr_info("%s: adding ARP target %pI4.\n", bond->dev->name, |
622 | &newtarget); | 661 | &newtarget); |
623 | targets[i] = newtarget; | 662 | /* not to race with bond_arp_rcv */ |
663 | write_lock_bh(&bond->lock); | ||
664 | bond_for_each_slave(bond, slave, i) | ||
665 | slave->target_last_arp_rx[ind] = jiffies; | ||
666 | targets[ind] = newtarget; | ||
667 | write_unlock_bh(&bond->lock); | ||
624 | } else if (buf[0] == '-') { | 668 | } else if (buf[0] == '-') { |
625 | if ((newtarget == 0) || (newtarget == htonl(INADDR_BROADCAST))) { | 669 | if ((newtarget == 0) || (newtarget == htonl(INADDR_BROADCAST))) { |
626 | pr_err("%s: invalid ARP target %pI4 specified for removal\n", | 670 | pr_err("%s: invalid ARP target %pI4 specified for removal\n", |
@@ -628,18 +672,32 @@ static ssize_t bonding_store_arp_targets(struct device *d, | |||
628 | goto out; | 672 | goto out; |
629 | } | 673 | } |
630 | 674 | ||
631 | i = bond_get_targets_ip(targets, newtarget); | 675 | ind = bond_get_targets_ip(targets, newtarget); |
632 | if (i == -1) { | 676 | if (ind == -1) { |
633 | pr_info("%s: unable to remove nonexistent ARP target %pI4.\n", | 677 | pr_err("%s: unable to remove nonexistent ARP target %pI4.\n", |
634 | bond->dev->name, &newtarget); | 678 | bond->dev->name, &newtarget); |
635 | goto out; | 679 | goto out; |
636 | } | 680 | } |
637 | 681 | ||
682 | if (ind == 0 && !targets[1] && bond->params.arp_interval) | ||
683 | pr_warn("%s: removing last arp target with arp_interval on\n", | ||
684 | bond->dev->name); | ||
685 | |||
638 | pr_info("%s: removing ARP target %pI4.\n", bond->dev->name, | 686 | pr_info("%s: removing ARP target %pI4.\n", bond->dev->name, |
639 | &newtarget); | 687 | &newtarget); |
640 | for (; (i < BOND_MAX_ARP_TARGETS-1) && targets[i+1]; i++) | 688 | |
689 | write_lock_bh(&bond->lock); | ||
690 | bond_for_each_slave(bond, slave, i) { | ||
691 | targets_rx = slave->target_last_arp_rx; | ||
692 | j = ind; | ||
693 | for (; (j < BOND_MAX_ARP_TARGETS-1) && targets[j+1]; j++) | ||
694 | targets_rx[j] = targets_rx[j+1]; | ||
695 | targets_rx[j] = 0; | ||
696 | } | ||
697 | for (i = ind; (i < BOND_MAX_ARP_TARGETS-1) && targets[i+1]; i++) | ||
641 | targets[i] = targets[i+1]; | 698 | targets[i] = targets[i+1]; |
642 | targets[i] = 0; | 699 | targets[i] = 0; |
700 | write_unlock_bh(&bond->lock); | ||
643 | } else { | 701 | } else { |
644 | pr_err("no command found in arp_ip_targets file for bond %s. Use +<addr> or -<addr>.\n", | 702 | pr_err("no command found in arp_ip_targets file for bond %s. Use +<addr> or -<addr>.\n", |
645 | bond->dev->name); | 703 | bond->dev->name); |
@@ -1623,6 +1681,7 @@ static struct attribute *per_bond_attrs[] = { | |||
1623 | &dev_attr_mode.attr, | 1681 | &dev_attr_mode.attr, |
1624 | &dev_attr_fail_over_mac.attr, | 1682 | &dev_attr_fail_over_mac.attr, |
1625 | &dev_attr_arp_validate.attr, | 1683 | &dev_attr_arp_validate.attr, |
1684 | &dev_attr_arp_all_targets.attr, | ||
1626 | &dev_attr_arp_interval.attr, | 1685 | &dev_attr_arp_interval.attr, |
1627 | &dev_attr_arp_ip_target.attr, | 1686 | &dev_attr_arp_ip_target.attr, |
1628 | &dev_attr_downdelay.attr, | 1687 | &dev_attr_downdelay.attr, |
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 486e532f77e4..3fb73cc8c34a 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h | |||
@@ -144,6 +144,7 @@ struct bond_params { | |||
144 | u8 num_peer_notif; | 144 | u8 num_peer_notif; |
145 | int arp_interval; | 145 | int arp_interval; |
146 | int arp_validate; | 146 | int arp_validate; |
147 | int arp_all_targets; | ||
147 | int use_carrier; | 148 | int use_carrier; |
148 | int fail_over_mac; | 149 | int fail_over_mac; |
149 | int updelay; | 150 | int updelay; |
@@ -179,6 +180,7 @@ struct slave { | |||
179 | int delay; | 180 | int delay; |
180 | unsigned long jiffies; | 181 | unsigned long jiffies; |
181 | unsigned long last_arp_rx; | 182 | unsigned long last_arp_rx; |
183 | unsigned long target_last_arp_rx[BOND_MAX_ARP_TARGETS]; | ||
182 | s8 link; /* one of BOND_LINK_XXXX */ | 184 | s8 link; /* one of BOND_LINK_XXXX */ |
183 | s8 new_link; | 185 | s8 new_link; |
184 | u8 backup:1, /* indicates backup slave. Value corresponds with | 186 | u8 backup:1, /* indicates backup slave. Value corresponds with |
@@ -322,6 +324,9 @@ static inline bool bond_is_active_slave(struct slave *slave) | |||
322 | #define BOND_FOM_ACTIVE 1 | 324 | #define BOND_FOM_ACTIVE 1 |
323 | #define BOND_FOM_FOLLOW 2 | 325 | #define BOND_FOM_FOLLOW 2 |
324 | 326 | ||
327 | #define BOND_ARP_TARGETS_ANY 0 | ||
328 | #define BOND_ARP_TARGETS_ALL 1 | ||
329 | |||
325 | #define BOND_ARP_VALIDATE_NONE 0 | 330 | #define BOND_ARP_VALIDATE_NONE 0 |
326 | #define BOND_ARP_VALIDATE_ACTIVE (1 << BOND_STATE_ACTIVE) | 331 | #define BOND_ARP_VALIDATE_ACTIVE (1 << BOND_STATE_ACTIVE) |
327 | #define BOND_ARP_VALIDATE_BACKUP (1 << BOND_STATE_BACKUP) | 332 | #define BOND_ARP_VALIDATE_BACKUP (1 << BOND_STATE_BACKUP) |
@@ -334,11 +339,31 @@ static inline int slave_do_arp_validate(struct bonding *bond, | |||
334 | return bond->params.arp_validate & (1 << bond_slave_state(slave)); | 339 | return bond->params.arp_validate & (1 << bond_slave_state(slave)); |
335 | } | 340 | } |
336 | 341 | ||
342 | /* Get the oldest arp which we've received on this slave for bond's | ||
343 | * arp_targets. | ||
344 | */ | ||
345 | static inline unsigned long slave_oldest_target_arp_rx(struct bonding *bond, | ||
346 | struct slave *slave) | ||
347 | { | ||
348 | int i = 1; | ||
349 | unsigned long ret = slave->target_last_arp_rx[0]; | ||
350 | |||
351 | for (; (i < BOND_MAX_ARP_TARGETS) && bond->params.arp_targets[i]; i++) | ||
352 | if (time_before(slave->target_last_arp_rx[i], ret)) | ||
353 | ret = slave->target_last_arp_rx[i]; | ||
354 | |||
355 | return ret; | ||
356 | } | ||
357 | |||
337 | static inline unsigned long slave_last_rx(struct bonding *bond, | 358 | static inline unsigned long slave_last_rx(struct bonding *bond, |
338 | struct slave *slave) | 359 | struct slave *slave) |
339 | { | 360 | { |
340 | if (slave_do_arp_validate(bond, slave)) | 361 | if (slave_do_arp_validate(bond, slave)) { |
341 | return slave->last_arp_rx; | 362 | if (bond->params.arp_all_targets == BOND_ARP_TARGETS_ALL) |
363 | return slave_oldest_target_arp_rx(bond, slave); | ||
364 | else | ||
365 | return slave->last_arp_rx; | ||
366 | } | ||
342 | 367 | ||
343 | return slave->dev->last_rx; | 368 | return slave->dev->last_rx; |
344 | } | 369 | } |
@@ -486,6 +511,7 @@ extern const struct bond_parm_tbl bond_lacp_tbl[]; | |||
486 | extern const struct bond_parm_tbl bond_mode_tbl[]; | 511 | extern const struct bond_parm_tbl bond_mode_tbl[]; |
487 | extern const struct bond_parm_tbl xmit_hashtype_tbl[]; | 512 | extern const struct bond_parm_tbl xmit_hashtype_tbl[]; |
488 | extern const struct bond_parm_tbl arp_validate_tbl[]; | 513 | extern const struct bond_parm_tbl arp_validate_tbl[]; |
514 | extern const struct bond_parm_tbl arp_all_targets_tbl[]; | ||
489 | extern const struct bond_parm_tbl fail_over_mac_tbl[]; | 515 | extern const struct bond_parm_tbl fail_over_mac_tbl[]; |
490 | extern const struct bond_parm_tbl pri_reselect_tbl[]; | 516 | extern const struct bond_parm_tbl pri_reselect_tbl[]; |
491 | extern struct bond_parm_tbl ad_select_tbl[]; | 517 | extern struct bond_parm_tbl ad_select_tbl[]; |