diff options
author | Jay Vosburgh <fubar@us.ibm.com> | 2006-09-23 00:54:53 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-09-25 20:08:09 -0400 |
commit | f5b2b966f032f22d3a289045a5afd4afa09f09c6 (patch) | |
tree | cb3c505d8f444438bed09353788f6c96150f68ad /drivers/net/bonding/bond_main.c | |
parent | 70298705bb29fb7982b85089adf17cd37b94baa7 (diff) |
[PATCH] bonding: Validate probe replies in ARP monitor
Add logic to check ARP request / reply packets used for ARP
monitor link integrity checking.
The current method simply examines the slave device to see if it
has sent and received traffic; this can be fooled by extraneous traffic.
For example, if multiple hosts running bonding are behind a common
switch, the probe traffic from the multiple instances of bonding will
update the tx/rx times on each other's slave devices.
Signed-off-by: Jay Vosburgh <fubar@us.ibm.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/bonding/bond_main.c')
-rw-r--r-- | drivers/net/bonding/bond_main.c | 182 |
1 files changed, 176 insertions, 6 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index bafe62f7c9b7..fd521b05db83 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c | |||
@@ -96,6 +96,7 @@ static char *lacp_rate = NULL; | |||
96 | static char *xmit_hash_policy = NULL; | 96 | static char *xmit_hash_policy = NULL; |
97 | static int arp_interval = BOND_LINK_ARP_INTERV; | 97 | static int arp_interval = BOND_LINK_ARP_INTERV; |
98 | static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, }; | 98 | static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, }; |
99 | static char *arp_validate = NULL; | ||
99 | struct bond_params bonding_defaults; | 100 | struct bond_params bonding_defaults; |
100 | 101 | ||
101 | module_param(max_bonds, int, 0); | 102 | module_param(max_bonds, int, 0); |
@@ -127,6 +128,8 @@ module_param(arp_interval, int, 0); | |||
127 | MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds"); | 128 | MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds"); |
128 | module_param_array(arp_ip_target, charp, NULL, 0); | 129 | module_param_array(arp_ip_target, charp, NULL, 0); |
129 | MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form"); | 130 | MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form"); |
131 | module_param(arp_validate, charp, 0); | ||
132 | MODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes: none (default), active, backup or all"); | ||
130 | 133 | ||
131 | /*----------------------------- Global variables ----------------------------*/ | 134 | /*----------------------------- Global variables ----------------------------*/ |
132 | 135 | ||
@@ -170,6 +173,14 @@ struct bond_parm_tbl xmit_hashtype_tbl[] = { | |||
170 | { NULL, -1}, | 173 | { NULL, -1}, |
171 | }; | 174 | }; |
172 | 175 | ||
176 | struct bond_parm_tbl arp_validate_tbl[] = { | ||
177 | { "none", BOND_ARP_VALIDATE_NONE}, | ||
178 | { "active", BOND_ARP_VALIDATE_ACTIVE}, | ||
179 | { "backup", BOND_ARP_VALIDATE_BACKUP}, | ||
180 | { "all", BOND_ARP_VALIDATE_ALL}, | ||
181 | { NULL, -1}, | ||
182 | }; | ||
183 | |||
173 | /*-------------------------- Forward declarations ---------------------------*/ | 184 | /*-------------------------- Forward declarations ---------------------------*/ |
174 | 185 | ||
175 | static void bond_send_gratuitous_arp(struct bonding *bond); | 186 | static void bond_send_gratuitous_arp(struct bonding *bond); |
@@ -1424,6 +1435,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) | |||
1424 | 1435 | ||
1425 | bond_compute_features(bond); | 1436 | bond_compute_features(bond); |
1426 | 1437 | ||
1438 | new_slave->last_arp_rx = jiffies; | ||
1439 | |||
1427 | if (bond->params.miimon && !bond->params.use_carrier) { | 1440 | if (bond->params.miimon && !bond->params.use_carrier) { |
1428 | link_reporting = bond_check_dev_link(bond, slave_dev, 1); | 1441 | link_reporting = bond_check_dev_link(bond, slave_dev, 1); |
1429 | 1442 | ||
@@ -1785,7 +1798,8 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) | |||
1785 | dev_set_mac_address(slave_dev, &addr); | 1798 | dev_set_mac_address(slave_dev, &addr); |
1786 | 1799 | ||
1787 | slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB | | 1800 | slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB | |
1788 | IFF_SLAVE_INACTIVE | IFF_BONDING); | 1801 | IFF_SLAVE_INACTIVE | IFF_BONDING | |
1802 | IFF_SLAVE_NEEDARP); | ||
1789 | 1803 | ||
1790 | kfree(slave); | 1804 | kfree(slave); |
1791 | 1805 | ||
@@ -2298,6 +2312,25 @@ static int bond_has_ip(struct bonding *bond) | |||
2298 | return 0; | 2312 | return 0; |
2299 | } | 2313 | } |
2300 | 2314 | ||
2315 | static int bond_has_this_ip(struct bonding *bond, u32 ip) | ||
2316 | { | ||
2317 | struct vlan_entry *vlan, *vlan_next; | ||
2318 | |||
2319 | if (ip == bond->master_ip) | ||
2320 | return 1; | ||
2321 | |||
2322 | if (list_empty(&bond->vlan_list)) | ||
2323 | return 0; | ||
2324 | |||
2325 | list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list, | ||
2326 | vlan_list) { | ||
2327 | if (ip == vlan->vlan_ip) | ||
2328 | return 1; | ||
2329 | } | ||
2330 | |||
2331 | return 0; | ||
2332 | } | ||
2333 | |||
2301 | /* | 2334 | /* |
2302 | * We go to the (large) trouble of VLAN tagging ARP frames because | 2335 | * We go to the (large) trouble of VLAN tagging ARP frames because |
2303 | * switches in VLAN mode (especially if ports are configured as | 2336 | * switches in VLAN mode (especially if ports are configured as |
@@ -2436,6 +2469,93 @@ static void bond_send_gratuitous_arp(struct bonding *bond) | |||
2436 | } | 2469 | } |
2437 | } | 2470 | } |
2438 | 2471 | ||
2472 | static void bond_validate_arp(struct bonding *bond, struct slave *slave, u32 sip, u32 tip) | ||
2473 | { | ||
2474 | int i; | ||
2475 | u32 *targets = bond->params.arp_targets; | ||
2476 | |||
2477 | targets = bond->params.arp_targets; | ||
2478 | for (i = 0; (i < BOND_MAX_ARP_TARGETS) && targets[i]; i++) { | ||
2479 | dprintk("bva: sip %u.%u.%u.%u tip %u.%u.%u.%u t[%d] " | ||
2480 | "%u.%u.%u.%u bhti(tip) %d\n", | ||
2481 | NIPQUAD(sip), NIPQUAD(tip), i, NIPQUAD(targets[i]), | ||
2482 | bond_has_this_ip(bond, tip)); | ||
2483 | if (sip == targets[i]) { | ||
2484 | if (bond_has_this_ip(bond, tip)) | ||
2485 | slave->last_arp_rx = jiffies; | ||
2486 | return; | ||
2487 | } | ||
2488 | } | ||
2489 | } | ||
2490 | |||
2491 | static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) | ||
2492 | { | ||
2493 | struct arphdr *arp; | ||
2494 | struct slave *slave; | ||
2495 | struct bonding *bond; | ||
2496 | unsigned char *arp_ptr; | ||
2497 | u32 sip, tip; | ||
2498 | |||
2499 | if (!(dev->priv_flags & IFF_BONDING) || !(dev->flags & IFF_MASTER)) | ||
2500 | goto out; | ||
2501 | |||
2502 | bond = dev->priv; | ||
2503 | read_lock(&bond->lock); | ||
2504 | |||
2505 | dprintk("bond_arp_rcv: bond %s skb->dev %s orig_dev %s\n", | ||
2506 | bond->dev->name, skb->dev ? skb->dev->name : "NULL", | ||
2507 | orig_dev ? orig_dev->name : "NULL"); | ||
2508 | |||
2509 | slave = bond_get_slave_by_dev(bond, orig_dev); | ||
2510 | if (!slave || !slave_do_arp_validate(bond, slave)) | ||
2511 | goto out_unlock; | ||
2512 | |||
2513 | /* ARP header, plus 2 device addresses, plus 2 IP addresses. */ | ||
2514 | if (!pskb_may_pull(skb, (sizeof(struct arphdr) + | ||
2515 | (2 * dev->addr_len) + | ||
2516 | (2 * sizeof(u32))))) | ||
2517 | goto out_unlock; | ||
2518 | |||
2519 | arp = skb->nh.arph; | ||
2520 | if (arp->ar_hln != dev->addr_len || | ||
2521 | skb->pkt_type == PACKET_OTHERHOST || | ||
2522 | skb->pkt_type == PACKET_LOOPBACK || | ||
2523 | arp->ar_hrd != htons(ARPHRD_ETHER) || | ||
2524 | arp->ar_pro != htons(ETH_P_IP) || | ||
2525 | arp->ar_pln != 4) | ||
2526 | goto out_unlock; | ||
2527 | |||
2528 | arp_ptr = (unsigned char *)(arp + 1); | ||
2529 | arp_ptr += dev->addr_len; | ||
2530 | memcpy(&sip, arp_ptr, 4); | ||
2531 | arp_ptr += 4 + dev->addr_len; | ||
2532 | memcpy(&tip, arp_ptr, 4); | ||
2533 | |||
2534 | dprintk("bond_arp_rcv: %s %s/%d av %d sv %d sip %u.%u.%u.%u" | ||
2535 | " tip %u.%u.%u.%u\n", bond->dev->name, slave->dev->name, | ||
2536 | slave->state, bond->params.arp_validate, | ||
2537 | slave_do_arp_validate(bond, slave), NIPQUAD(sip), NIPQUAD(tip)); | ||
2538 | |||
2539 | /* | ||
2540 | * Backup slaves won't see the ARP reply, but do come through | ||
2541 | * here for each ARP probe (so we swap the sip/tip to validate | ||
2542 | * the probe). In a "redundant switch, common router" type of | ||
2543 | * configuration, the ARP probe will (hopefully) travel from | ||
2544 | * the active, through one switch, the router, then the other | ||
2545 | * switch before reaching the backup. | ||
2546 | */ | ||
2547 | if (slave->state == BOND_STATE_ACTIVE) | ||
2548 | bond_validate_arp(bond, slave, sip, tip); | ||
2549 | else | ||
2550 | bond_validate_arp(bond, slave, tip, sip); | ||
2551 | |||
2552 | out_unlock: | ||
2553 | read_unlock(&bond->lock); | ||
2554 | out: | ||
2555 | dev_kfree_skb(skb); | ||
2556 | return NET_RX_SUCCESS; | ||
2557 | } | ||
2558 | |||
2439 | /* | 2559 | /* |
2440 | * this function is called regularly to monitor each slave's link | 2560 | * this function is called regularly to monitor each slave's link |
2441 | * ensuring that traffic is being sent and received when arp monitoring | 2561 | * ensuring that traffic is being sent and received when arp monitoring |
@@ -2600,7 +2720,8 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev) | |||
2600 | */ | 2720 | */ |
2601 | bond_for_each_slave(bond, slave, i) { | 2721 | bond_for_each_slave(bond, slave, i) { |
2602 | if (slave->link != BOND_LINK_UP) { | 2722 | if (slave->link != BOND_LINK_UP) { |
2603 | if ((jiffies - slave->dev->last_rx) <= delta_in_ticks) { | 2723 | if ((jiffies - slave_last_rx(bond, slave)) <= |
2724 | delta_in_ticks) { | ||
2604 | 2725 | ||
2605 | slave->link = BOND_LINK_UP; | 2726 | slave->link = BOND_LINK_UP; |
2606 | 2727 | ||
@@ -2645,7 +2766,7 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev) | |||
2645 | 2766 | ||
2646 | if ((slave != bond->curr_active_slave) && | 2767 | if ((slave != bond->curr_active_slave) && |
2647 | (!bond->current_arp_slave) && | 2768 | (!bond->current_arp_slave) && |
2648 | (((jiffies - slave->dev->last_rx) >= 3*delta_in_ticks) && | 2769 | (((jiffies - slave_last_rx(bond, slave)) >= 3*delta_in_ticks) && |
2649 | bond_has_ip(bond))) { | 2770 | bond_has_ip(bond))) { |
2650 | /* a backup slave has gone down; three times | 2771 | /* a backup slave has gone down; three times |
2651 | * the delta allows the current slave to be | 2772 | * the delta allows the current slave to be |
@@ -2692,7 +2813,7 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev) | |||
2692 | * if it is up and needs to take over as the curr_active_slave | 2813 | * if it is up and needs to take over as the curr_active_slave |
2693 | */ | 2814 | */ |
2694 | if ((((jiffies - slave->dev->trans_start) >= (2*delta_in_ticks)) || | 2815 | if ((((jiffies - slave->dev->trans_start) >= (2*delta_in_ticks)) || |
2695 | (((jiffies - slave->dev->last_rx) >= (2*delta_in_ticks)) && | 2816 | (((jiffies - slave_last_rx(bond, slave)) >= (2*delta_in_ticks)) && |
2696 | bond_has_ip(bond))) && | 2817 | bond_has_ip(bond))) && |
2697 | ((jiffies - slave->jiffies) >= 2*delta_in_ticks)) { | 2818 | ((jiffies - slave->jiffies) >= 2*delta_in_ticks)) { |
2698 | 2819 | ||
@@ -3315,6 +3436,21 @@ static void bond_unregister_lacpdu(struct bonding *bond) | |||
3315 | dev_remove_pack(&(BOND_AD_INFO(bond).ad_pkt_type)); | 3436 | dev_remove_pack(&(BOND_AD_INFO(bond).ad_pkt_type)); |
3316 | } | 3437 | } |
3317 | 3438 | ||
3439 | void bond_register_arp(struct bonding *bond) | ||
3440 | { | ||
3441 | struct packet_type *pt = &bond->arp_mon_pt; | ||
3442 | |||
3443 | pt->type = htons(ETH_P_ARP); | ||
3444 | pt->dev = NULL; /*bond->dev;XXX*/ | ||
3445 | pt->func = bond_arp_rcv; | ||
3446 | dev_add_pack(pt); | ||
3447 | } | ||
3448 | |||
3449 | void bond_unregister_arp(struct bonding *bond) | ||
3450 | { | ||
3451 | dev_remove_pack(&bond->arp_mon_pt); | ||
3452 | } | ||
3453 | |||
3318 | /*---------------------------- Hashing Policies -----------------------------*/ | 3454 | /*---------------------------- Hashing Policies -----------------------------*/ |
3319 | 3455 | ||
3320 | /* | 3456 | /* |
@@ -3401,6 +3537,9 @@ static int bond_open(struct net_device *bond_dev) | |||
3401 | } else { | 3537 | } else { |
3402 | arp_timer->function = (void *)&bond_loadbalance_arp_mon; | 3538 | arp_timer->function = (void *)&bond_loadbalance_arp_mon; |
3403 | } | 3539 | } |
3540 | if (bond->params.arp_validate) | ||
3541 | bond_register_arp(bond); | ||
3542 | |||
3404 | add_timer(arp_timer); | 3543 | add_timer(arp_timer); |
3405 | } | 3544 | } |
3406 | 3545 | ||
@@ -3428,6 +3567,9 @@ static int bond_close(struct net_device *bond_dev) | |||
3428 | bond_unregister_lacpdu(bond); | 3567 | bond_unregister_lacpdu(bond); |
3429 | } | 3568 | } |
3430 | 3569 | ||
3570 | if (bond->params.arp_validate) | ||
3571 | bond_unregister_arp(bond); | ||
3572 | |||
3431 | write_lock_bh(&bond->lock); | 3573 | write_lock_bh(&bond->lock); |
3432 | 3574 | ||
3433 | 3575 | ||
@@ -4281,6 +4423,8 @@ int bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl) | |||
4281 | 4423 | ||
4282 | static int bond_check_params(struct bond_params *params) | 4424 | static int bond_check_params(struct bond_params *params) |
4283 | { | 4425 | { |
4426 | int arp_validate_value; | ||
4427 | |||
4284 | /* | 4428 | /* |
4285 | * Convert string parameters. | 4429 | * Convert string parameters. |
4286 | */ | 4430 | */ |
@@ -4484,6 +4628,29 @@ static int bond_check_params(struct bond_params *params) | |||
4484 | arp_interval = 0; | 4628 | arp_interval = 0; |
4485 | } | 4629 | } |
4486 | 4630 | ||
4631 | if (arp_validate) { | ||
4632 | if (bond_mode != BOND_MODE_ACTIVEBACKUP) { | ||
4633 | printk(KERN_ERR DRV_NAME | ||
4634 | ": arp_validate only supported in active-backup mode\n"); | ||
4635 | return -EINVAL; | ||
4636 | } | ||
4637 | if (!arp_interval) { | ||
4638 | printk(KERN_ERR DRV_NAME | ||
4639 | ": arp_validate requires arp_interval\n"); | ||
4640 | return -EINVAL; | ||
4641 | } | ||
4642 | |||
4643 | arp_validate_value = bond_parse_parm(arp_validate, | ||
4644 | arp_validate_tbl); | ||
4645 | if (arp_validate_value == -1) { | ||
4646 | printk(KERN_ERR DRV_NAME | ||
4647 | ": Error: invalid arp_validate \"%s\"\n", | ||
4648 | arp_validate == NULL ? "NULL" : arp_validate); | ||
4649 | return -EINVAL; | ||
4650 | } | ||
4651 | } else | ||
4652 | arp_validate_value = 0; | ||
4653 | |||
4487 | if (miimon) { | 4654 | if (miimon) { |
4488 | printk(KERN_INFO DRV_NAME | 4655 | printk(KERN_INFO DRV_NAME |
4489 | ": MII link monitoring set to %d ms\n", | 4656 | ": MII link monitoring set to %d ms\n", |
@@ -4492,8 +4659,10 @@ static int bond_check_params(struct bond_params *params) | |||
4492 | int i; | 4659 | int i; |
4493 | 4660 | ||
4494 | printk(KERN_INFO DRV_NAME | 4661 | printk(KERN_INFO DRV_NAME |
4495 | ": ARP monitoring set to %d ms with %d target(s):", | 4662 | ": ARP monitoring set to %d ms, validate %s, with %d target(s):", |
4496 | arp_interval, arp_ip_count); | 4663 | arp_interval, |
4664 | arp_validate_tbl[arp_validate_value].modename, | ||
4665 | arp_ip_count); | ||
4497 | 4666 | ||
4498 | for (i = 0; i < arp_ip_count; i++) | 4667 | for (i = 0; i < arp_ip_count; i++) |
4499 | printk (" %s", arp_ip_target[i]); | 4668 | printk (" %s", arp_ip_target[i]); |
@@ -4527,6 +4696,7 @@ static int bond_check_params(struct bond_params *params) | |||
4527 | params->xmit_policy = xmit_hashtype; | 4696 | params->xmit_policy = xmit_hashtype; |
4528 | params->miimon = miimon; | 4697 | params->miimon = miimon; |
4529 | params->arp_interval = arp_interval; | 4698 | params->arp_interval = arp_interval; |
4699 | params->arp_validate = arp_validate_value; | ||
4530 | params->updelay = updelay; | 4700 | params->updelay = updelay; |
4531 | params->downdelay = downdelay; | 4701 | params->downdelay = downdelay; |
4532 | params->use_carrier = use_carrier; | 4702 | params->use_carrier = use_carrier; |