diff options
author | Jay Vosburgh <fubar@us.ibm.com> | 2005-06-26 17:52:20 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-06-26 17:52:20 -0400 |
commit | c3ade5cad07f4d67f2e16a28f3c73d9483a55e0e (patch) | |
tree | 198f479dbcb793ad84cbb23d8f5f049253de5f07 /drivers/net/bonding/bond_main.c | |
parent | 12755c16a9e4fa2fd5b0ca1963e83d671a6251da (diff) |
bonding: gratuitous ARP
Add support for generating gratuitous ARPs in bonding
active-backup mode when failovers occur. Includes support for VLAN
tagging the ARPs as needed.
Signed-off-by: Jay Vosburgh <fubar@us.ibm.com>
Diffstat (limited to 'drivers/net/bonding/bond_main.c')
-rw-r--r-- | drivers/net/bonding/bond_main.c | 283 |
1 files changed, 251 insertions, 32 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 269a5e407349..545f6fe025a8 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c | |||
@@ -475,7 +475,10 @@ | |||
475 | * Solution is to move call to dev_remove_pack outside of the | 475 | * Solution is to move call to dev_remove_pack outside of the |
476 | * spinlock. | 476 | * spinlock. |
477 | * Set version to 2.6.1. | 477 | * Set version to 2.6.1. |
478 | * | 478 | * 2005/06/05 - Jay Vosburgh <fubar@us.ibm.com> |
479 | * - Support for generating gratuitous ARPs in active-backup mode. | ||
480 | * Includes support for VLAN tagging all bonding-generated ARPs | ||
481 | * as needed. Set version to 2.6.2. | ||
479 | */ | 482 | */ |
480 | 483 | ||
481 | //#define BONDING_DEBUG 1 | 484 | //#define BONDING_DEBUG 1 |
@@ -519,6 +522,7 @@ | |||
519 | #include <linux/ethtool.h> | 522 | #include <linux/ethtool.h> |
520 | #include <linux/if_vlan.h> | 523 | #include <linux/if_vlan.h> |
521 | #include <linux/if_bonding.h> | 524 | #include <linux/if_bonding.h> |
525 | #include <net/route.h> | ||
522 | #include "bonding.h" | 526 | #include "bonding.h" |
523 | #include "bond_3ad.h" | 527 | #include "bond_3ad.h" |
524 | #include "bond_alb.h" | 528 | #include "bond_alb.h" |
@@ -574,7 +578,6 @@ static struct proc_dir_entry *bond_proc_dir = NULL; | |||
574 | 578 | ||
575 | static u32 arp_target[BOND_MAX_ARP_TARGETS] = { 0, } ; | 579 | static u32 arp_target[BOND_MAX_ARP_TARGETS] = { 0, } ; |
576 | static int arp_ip_count = 0; | 580 | static int arp_ip_count = 0; |
577 | static u32 my_ip = 0; | ||
578 | static int bond_mode = BOND_MODE_ROUNDROBIN; | 581 | static int bond_mode = BOND_MODE_ROUNDROBIN; |
579 | static int lacp_fast = 0; | 582 | static int lacp_fast = 0; |
580 | static int app_abi_ver = 0; | 583 | static int app_abi_ver = 0; |
@@ -611,6 +614,7 @@ static struct bond_parm_tbl bond_mode_tbl[] = { | |||
611 | /*-------------------------- Forward declarations ---------------------------*/ | 614 | /*-------------------------- Forward declarations ---------------------------*/ |
612 | 615 | ||
613 | static inline void bond_set_mode_ops(struct net_device *bond_dev, int mode); | 616 | static inline void bond_set_mode_ops(struct net_device *bond_dev, int mode); |
617 | static void bond_send_gratuitous_arp(struct bonding *bond); | ||
614 | 618 | ||
615 | /*---------------------------- General routines -----------------------------*/ | 619 | /*---------------------------- General routines -----------------------------*/ |
616 | 620 | ||
@@ -659,6 +663,7 @@ static int bond_add_vlan(struct bonding *bond, unsigned short vlan_id) | |||
659 | 663 | ||
660 | INIT_LIST_HEAD(&vlan->vlan_list); | 664 | INIT_LIST_HEAD(&vlan->vlan_list); |
661 | vlan->vlan_id = vlan_id; | 665 | vlan->vlan_id = vlan_id; |
666 | vlan->vlan_ip = 0; | ||
662 | 667 | ||
663 | write_lock_bh(&bond->lock); | 668 | write_lock_bh(&bond->lock); |
664 | 669 | ||
@@ -1468,16 +1473,6 @@ static void bond_change_active_slave(struct bonding *bond, struct slave *new_act | |||
1468 | } | 1473 | } |
1469 | } | 1474 | } |
1470 | 1475 | ||
1471 | if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) { | ||
1472 | if (old_active) { | ||
1473 | bond_set_slave_inactive_flags(old_active); | ||
1474 | } | ||
1475 | |||
1476 | if (new_active) { | ||
1477 | bond_set_slave_active_flags(new_active); | ||
1478 | } | ||
1479 | } | ||
1480 | |||
1481 | if (USES_PRIMARY(bond->params.mode)) { | 1476 | if (USES_PRIMARY(bond->params.mode)) { |
1482 | bond_mc_swap(bond, new_active, old_active); | 1477 | bond_mc_swap(bond, new_active, old_active); |
1483 | } | 1478 | } |
@@ -1488,6 +1483,17 @@ static void bond_change_active_slave(struct bonding *bond, struct slave *new_act | |||
1488 | } else { | 1483 | } else { |
1489 | bond->curr_active_slave = new_active; | 1484 | bond->curr_active_slave = new_active; |
1490 | } | 1485 | } |
1486 | |||
1487 | if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) { | ||
1488 | if (old_active) { | ||
1489 | bond_set_slave_inactive_flags(old_active); | ||
1490 | } | ||
1491 | |||
1492 | if (new_active) { | ||
1493 | bond_set_slave_active_flags(new_active); | ||
1494 | } | ||
1495 | bond_send_gratuitous_arp(bond); | ||
1496 | } | ||
1491 | } | 1497 | } |
1492 | 1498 | ||
1493 | /** | 1499 | /** |
@@ -2694,15 +2700,180 @@ out: | |||
2694 | read_unlock(&bond->lock); | 2700 | read_unlock(&bond->lock); |
2695 | } | 2701 | } |
2696 | 2702 | ||
2703 | |||
2704 | static u32 bond_glean_dev_ip(struct net_device *dev) | ||
2705 | { | ||
2706 | struct in_device *idev; | ||
2707 | struct in_ifaddr *ifa; | ||
2708 | u32 addr = 0; | ||
2709 | |||
2710 | if (!dev) | ||
2711 | return 0; | ||
2712 | |||
2713 | rcu_read_lock(); | ||
2714 | idev = __in_dev_get(dev); | ||
2715 | if (!idev) | ||
2716 | goto out; | ||
2717 | |||
2718 | ifa = idev->ifa_list; | ||
2719 | if (!ifa) | ||
2720 | goto out; | ||
2721 | |||
2722 | addr = ifa->ifa_local; | ||
2723 | out: | ||
2724 | rcu_read_unlock(); | ||
2725 | return addr; | ||
2726 | } | ||
2727 | |||
2728 | static int bond_has_ip(struct bonding *bond) | ||
2729 | { | ||
2730 | struct vlan_entry *vlan, *vlan_next; | ||
2731 | |||
2732 | if (bond->master_ip) | ||
2733 | return 1; | ||
2734 | |||
2735 | if (list_empty(&bond->vlan_list)) | ||
2736 | return 0; | ||
2737 | |||
2738 | list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list, | ||
2739 | vlan_list) { | ||
2740 | if (vlan->vlan_ip) | ||
2741 | return 1; | ||
2742 | } | ||
2743 | |||
2744 | return 0; | ||
2745 | } | ||
2746 | |||
2747 | /* | ||
2748 | * We go to the (large) trouble of VLAN tagging ARP frames because | ||
2749 | * switches in VLAN mode (especially if ports are configured as | ||
2750 | * "native" to a VLAN) might not pass non-tagged frames. | ||
2751 | */ | ||
2752 | static void bond_arp_send(struct net_device *slave_dev, int arp_op, u32 dest_ip, u32 src_ip, unsigned short vlan_id) | ||
2753 | { | ||
2754 | struct sk_buff *skb; | ||
2755 | |||
2756 | dprintk("arp %d on slave %s: dst %x src %x vid %d\n", arp_op, | ||
2757 | slave_dev->name, dest_ip, src_ip, vlan_id); | ||
2758 | |||
2759 | skb = arp_create(arp_op, ETH_P_ARP, dest_ip, slave_dev, src_ip, | ||
2760 | NULL, slave_dev->dev_addr, NULL); | ||
2761 | |||
2762 | if (!skb) { | ||
2763 | printk(KERN_ERR DRV_NAME ": ARP packet allocation failed\n"); | ||
2764 | return; | ||
2765 | } | ||
2766 | if (vlan_id) { | ||
2767 | skb = vlan_put_tag(skb, vlan_id); | ||
2768 | if (!skb) { | ||
2769 | printk(KERN_ERR DRV_NAME ": failed to insert VLAN tag\n"); | ||
2770 | return; | ||
2771 | } | ||
2772 | } | ||
2773 | arp_xmit(skb); | ||
2774 | } | ||
2775 | |||
2776 | |||
2697 | static void bond_arp_send_all(struct bonding *bond, struct slave *slave) | 2777 | static void bond_arp_send_all(struct bonding *bond, struct slave *slave) |
2698 | { | 2778 | { |
2699 | int i; | 2779 | int i, vlan_id, rv; |
2700 | u32 *targets = bond->params.arp_targets; | 2780 | u32 *targets = bond->params.arp_targets; |
2781 | struct vlan_entry *vlan, *vlan_next; | ||
2782 | struct net_device *vlan_dev; | ||
2783 | struct flowi fl; | ||
2784 | struct rtable *rt; | ||
2701 | 2785 | ||
2702 | for (i = 0; (i < BOND_MAX_ARP_TARGETS) && targets[i]; i++) { | 2786 | for (i = 0; (i < BOND_MAX_ARP_TARGETS) && targets[i]; i++) { |
2703 | arp_send(ARPOP_REQUEST, ETH_P_ARP, targets[i], slave->dev, | 2787 | dprintk("basa: target %x\n", targets[i]); |
2704 | my_ip, NULL, slave->dev->dev_addr, | 2788 | if (list_empty(&bond->vlan_list)) { |
2705 | NULL); | 2789 | dprintk("basa: empty vlan: arp_send\n"); |
2790 | bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], | ||
2791 | bond->master_ip, 0); | ||
2792 | continue; | ||
2793 | } | ||
2794 | |||
2795 | /* | ||
2796 | * If VLANs are configured, we do a route lookup to | ||
2797 | * determine which VLAN interface would be used, so we | ||
2798 | * can tag the ARP with the proper VLAN tag. | ||
2799 | */ | ||
2800 | memset(&fl, 0, sizeof(fl)); | ||
2801 | fl.fl4_dst = targets[i]; | ||
2802 | fl.fl4_tos = RTO_ONLINK; | ||
2803 | |||
2804 | rv = ip_route_output_key(&rt, &fl); | ||
2805 | if (rv) { | ||
2806 | if (net_ratelimit()) { | ||
2807 | printk(KERN_WARNING DRV_NAME | ||
2808 | ": %s: no route to arp_ip_target %u.%u.%u.%u\n", | ||
2809 | bond->dev->name, NIPQUAD(fl.fl4_dst)); | ||
2810 | } | ||
2811 | continue; | ||
2812 | } | ||
2813 | |||
2814 | /* | ||
2815 | * This target is not on a VLAN | ||
2816 | */ | ||
2817 | if (rt->u.dst.dev == bond->dev) { | ||
2818 | dprintk("basa: rtdev == bond->dev: arp_send\n"); | ||
2819 | bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], | ||
2820 | bond->master_ip, 0); | ||
2821 | continue; | ||
2822 | } | ||
2823 | |||
2824 | vlan_id = 0; | ||
2825 | list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list, | ||
2826 | vlan_list) { | ||
2827 | vlan_dev = bond->vlgrp->vlan_devices[vlan->vlan_id]; | ||
2828 | if (vlan_dev == rt->u.dst.dev) { | ||
2829 | vlan_id = vlan->vlan_id; | ||
2830 | dprintk("basa: vlan match on %s %d\n", | ||
2831 | vlan_dev->name, vlan_id); | ||
2832 | break; | ||
2833 | } | ||
2834 | } | ||
2835 | |||
2836 | if (vlan_id) { | ||
2837 | bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], | ||
2838 | vlan->vlan_ip, vlan_id); | ||
2839 | continue; | ||
2840 | } | ||
2841 | |||
2842 | if (net_ratelimit()) { | ||
2843 | printk(KERN_WARNING DRV_NAME | ||
2844 | ": %s: no path to arp_ip_target %u.%u.%u.%u via rt.dev %s\n", | ||
2845 | bond->dev->name, NIPQUAD(fl.fl4_dst), | ||
2846 | rt->u.dst.dev ? rt->u.dst.dev->name : "NULL"); | ||
2847 | } | ||
2848 | } | ||
2849 | } | ||
2850 | |||
2851 | /* | ||
2852 | * Kick out a gratuitous ARP for an IP on the bonding master plus one | ||
2853 | * for each VLAN above us. | ||
2854 | */ | ||
2855 | static void bond_send_gratuitous_arp(struct bonding *bond) | ||
2856 | { | ||
2857 | struct slave *slave = bond->curr_active_slave; | ||
2858 | struct vlan_entry *vlan; | ||
2859 | struct net_device *vlan_dev; | ||
2860 | |||
2861 | dprintk("bond_send_grat_arp: bond %s slave %s\n", bond->dev->name, | ||
2862 | slave ? slave->dev->name : "NULL"); | ||
2863 | if (!slave) | ||
2864 | return; | ||
2865 | |||
2866 | if (bond->master_ip) { | ||
2867 | bond_arp_send(slave->dev, ARPOP_REPLY, bond->master_ip, | ||
2868 | bond->master_ip, 0); | ||
2869 | } | ||
2870 | |||
2871 | list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { | ||
2872 | vlan_dev = bond->vlgrp->vlan_devices[vlan->vlan_id]; | ||
2873 | if (vlan->vlan_ip) { | ||
2874 | bond_arp_send(slave->dev, ARPOP_REPLY, vlan->vlan_ip, | ||
2875 | vlan->vlan_ip, vlan->vlan_id); | ||
2876 | } | ||
2706 | } | 2877 | } |
2707 | } | 2878 | } |
2708 | 2879 | ||
@@ -2781,7 +2952,7 @@ static void bond_loadbalance_arp_mon(struct net_device *bond_dev) | |||
2781 | */ | 2952 | */ |
2782 | if (((jiffies - slave->dev->trans_start) >= (2*delta_in_ticks)) || | 2953 | if (((jiffies - slave->dev->trans_start) >= (2*delta_in_ticks)) || |
2783 | (((jiffies - slave->dev->last_rx) >= (2*delta_in_ticks)) && | 2954 | (((jiffies - slave->dev->last_rx) >= (2*delta_in_ticks)) && |
2784 | my_ip)) { | 2955 | bond_has_ip(bond))) { |
2785 | 2956 | ||
2786 | slave->link = BOND_LINK_DOWN; | 2957 | slave->link = BOND_LINK_DOWN; |
2787 | slave->state = BOND_STATE_BACKUP; | 2958 | slave->state = BOND_STATE_BACKUP; |
@@ -2920,7 +3091,7 @@ static void bond_activebackup_arp_mon(struct net_device *bond_dev) | |||
2920 | if ((slave != bond->curr_active_slave) && | 3091 | if ((slave != bond->curr_active_slave) && |
2921 | (!bond->current_arp_slave) && | 3092 | (!bond->current_arp_slave) && |
2922 | (((jiffies - slave->dev->last_rx) >= 3*delta_in_ticks) && | 3093 | (((jiffies - slave->dev->last_rx) >= 3*delta_in_ticks) && |
2923 | my_ip)) { | 3094 | bond_has_ip(bond))) { |
2924 | /* a backup slave has gone down; three times | 3095 | /* a backup slave has gone down; three times |
2925 | * the delta allows the current slave to be | 3096 | * the delta allows the current slave to be |
2926 | * taken out before the backup slave. | 3097 | * taken out before the backup slave. |
@@ -2966,8 +3137,8 @@ static void bond_activebackup_arp_mon(struct net_device *bond_dev) | |||
2966 | * if it is up and needs to take over as the curr_active_slave | 3137 | * if it is up and needs to take over as the curr_active_slave |
2967 | */ | 3138 | */ |
2968 | if ((((jiffies - slave->dev->trans_start) >= (2*delta_in_ticks)) || | 3139 | if ((((jiffies - slave->dev->trans_start) >= (2*delta_in_ticks)) || |
2969 | (((jiffies - slave->dev->last_rx) >= (2*delta_in_ticks)) && | 3140 | (((jiffies - slave->dev->last_rx) >= (2*delta_in_ticks)) && |
2970 | my_ip)) && | 3141 | bond_has_ip(bond))) && |
2971 | ((jiffies - slave->jiffies) >= 2*delta_in_ticks)) { | 3142 | ((jiffies - slave->jiffies) >= 2*delta_in_ticks)) { |
2972 | 3143 | ||
2973 | slave->link = BOND_LINK_DOWN; | 3144 | slave->link = BOND_LINK_DOWN; |
@@ -3019,7 +3190,7 @@ static void bond_activebackup_arp_mon(struct net_device *bond_dev) | |||
3019 | /* the current slave must tx an arp to ensure backup slaves | 3190 | /* the current slave must tx an arp to ensure backup slaves |
3020 | * rx traffic | 3191 | * rx traffic |
3021 | */ | 3192 | */ |
3022 | if (slave && my_ip) { | 3193 | if (slave && bond_has_ip(bond)) { |
3023 | bond_arp_send_all(bond, slave); | 3194 | bond_arp_send_all(bond, slave); |
3024 | } | 3195 | } |
3025 | } | 3196 | } |
@@ -3471,10 +3642,67 @@ static int bond_netdev_event(struct notifier_block *this, unsigned long event, v | |||
3471 | return NOTIFY_DONE; | 3642 | return NOTIFY_DONE; |
3472 | } | 3643 | } |
3473 | 3644 | ||
3645 | /* | ||
3646 | * bond_inetaddr_event: handle inetaddr notifier chain events. | ||
3647 | * | ||
3648 | * We keep track of device IPs primarily to use as source addresses in | ||
3649 | * ARP monitor probes (rather than spewing out broadcasts all the time). | ||
3650 | * | ||
3651 | * We track one IP for the main device (if it has one), plus one per VLAN. | ||
3652 | */ | ||
3653 | static int bond_inetaddr_event(struct notifier_block *this, unsigned long event, void *ptr) | ||
3654 | { | ||
3655 | struct in_ifaddr *ifa = ptr; | ||
3656 | struct net_device *vlan_dev, *event_dev = ifa->ifa_dev->dev; | ||
3657 | struct bonding *bond, *bond_next; | ||
3658 | struct vlan_entry *vlan, *vlan_next; | ||
3659 | |||
3660 | list_for_each_entry_safe(bond, bond_next, &bond_dev_list, bond_list) { | ||
3661 | if (bond->dev == event_dev) { | ||
3662 | switch (event) { | ||
3663 | case NETDEV_UP: | ||
3664 | bond->master_ip = ifa->ifa_local; | ||
3665 | return NOTIFY_OK; | ||
3666 | case NETDEV_DOWN: | ||
3667 | bond->master_ip = bond_glean_dev_ip(bond->dev); | ||
3668 | return NOTIFY_OK; | ||
3669 | default: | ||
3670 | return NOTIFY_DONE; | ||
3671 | } | ||
3672 | } | ||
3673 | |||
3674 | if (list_empty(&bond->vlan_list)) | ||
3675 | continue; | ||
3676 | |||
3677 | list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list, | ||
3678 | vlan_list) { | ||
3679 | vlan_dev = bond->vlgrp->vlan_devices[vlan->vlan_id]; | ||
3680 | if (vlan_dev == event_dev) { | ||
3681 | switch (event) { | ||
3682 | case NETDEV_UP: | ||
3683 | vlan->vlan_ip = ifa->ifa_local; | ||
3684 | return NOTIFY_OK; | ||
3685 | case NETDEV_DOWN: | ||
3686 | vlan->vlan_ip = | ||
3687 | bond_glean_dev_ip(vlan_dev); | ||
3688 | return NOTIFY_OK; | ||
3689 | default: | ||
3690 | return NOTIFY_DONE; | ||
3691 | } | ||
3692 | } | ||
3693 | } | ||
3694 | } | ||
3695 | return NOTIFY_DONE; | ||
3696 | } | ||
3697 | |||
3474 | static struct notifier_block bond_netdev_notifier = { | 3698 | static struct notifier_block bond_netdev_notifier = { |
3475 | .notifier_call = bond_netdev_event, | 3699 | .notifier_call = bond_netdev_event, |
3476 | }; | 3700 | }; |
3477 | 3701 | ||
3702 | static struct notifier_block bond_inetaddr_notifier = { | ||
3703 | .notifier_call = bond_inetaddr_event, | ||
3704 | }; | ||
3705 | |||
3478 | /*-------------------------- Packet type handling ---------------------------*/ | 3706 | /*-------------------------- Packet type handling ---------------------------*/ |
3479 | 3707 | ||
3480 | /* register to receive lacpdus on a bond */ | 3708 | /* register to receive lacpdus on a bond */ |
@@ -4060,17 +4288,6 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d | |||
4060 | struct bonding *bond = bond_dev->priv; | 4288 | struct bonding *bond = bond_dev->priv; |
4061 | int res = 1; | 4289 | int res = 1; |
4062 | 4290 | ||
4063 | /* if we are sending arp packets, try to at least | ||
4064 | identify our own ip address */ | ||
4065 | if (bond->params.arp_interval && !my_ip && | ||
4066 | (skb->protocol == __constant_htons(ETH_P_ARP))) { | ||
4067 | char *the_ip = (char *)skb->data + | ||
4068 | sizeof(struct ethhdr) + | ||
4069 | sizeof(struct arphdr) + | ||
4070 | ETH_ALEN; | ||
4071 | memcpy(&my_ip, the_ip, 4); | ||
4072 | } | ||
4073 | |||
4074 | read_lock(&bond->lock); | 4291 | read_lock(&bond->lock); |
4075 | read_lock(&bond->curr_slave_lock); | 4292 | read_lock(&bond->curr_slave_lock); |
4076 | 4293 | ||
@@ -4669,6 +4886,7 @@ static int __init bonding_init(void) | |||
4669 | 4886 | ||
4670 | rtnl_unlock(); | 4887 | rtnl_unlock(); |
4671 | register_netdevice_notifier(&bond_netdev_notifier); | 4888 | register_netdevice_notifier(&bond_netdev_notifier); |
4889 | register_inetaddr_notifier(&bond_inetaddr_notifier); | ||
4672 | 4890 | ||
4673 | return 0; | 4891 | return 0; |
4674 | 4892 | ||
@@ -4684,6 +4902,7 @@ out_err: | |||
4684 | static void __exit bonding_exit(void) | 4902 | static void __exit bonding_exit(void) |
4685 | { | 4903 | { |
4686 | unregister_netdevice_notifier(&bond_netdev_notifier); | 4904 | unregister_netdevice_notifier(&bond_netdev_notifier); |
4905 | unregister_inetaddr_notifier(&bond_inetaddr_notifier); | ||
4687 | 4906 | ||
4688 | rtnl_lock(); | 4907 | rtnl_lock(); |
4689 | bond_free_all(); | 4908 | bond_free_all(); |