diff options
Diffstat (limited to 'drivers/net/bonding')
-rw-r--r-- | drivers/net/bonding/bond_3ad.c | 70 | ||||
-rw-r--r-- | drivers/net/bonding/bond_main.c | 228 | ||||
-rw-r--r-- | drivers/net/bonding/bond_sysfs.c | 56 | ||||
-rw-r--r-- | drivers/net/bonding/bonding.h | 34 |
4 files changed, 318 insertions, 70 deletions
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 6a407070c2e..3fb354d9c51 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -85,6 +85,7 @@ #define AD_LINK_SPEED_BITMASK_10MBPS 0x2 #define AD_LINK_SPEED_BITMASK_100MBPS 0x4 #define AD_LINK_SPEED_BITMASK_1000MBPS 0x8 +#define AD_LINK_SPEED_BITMASK_10000MBPS 0x10 //endalloun // compare MAC addresses @@ -99,7 +100,7 @@ static u16 __get_link_speed(struct port *port); static u8 __get_duplex(struct port *port); static inline void __initialize_port_locks(struct port *port); //conversions -static void __ntohs_lacpdu(struct lacpdu *lacpdu); +static void __htons_lacpdu(struct lacpdu *lacpdu); static u16 __ad_timer_to_ticks(u16 timer_type, u16 Par); @@ -330,7 +331,8 @@ static inline void __release_rx_machine_lock(struct port *port) * 0, * %AD_LINK_SPEED_BITMASK_10MBPS, * %AD_LINK_SPEED_BITMASK_100MBPS, - * %AD_LINK_SPEED_BITMASK_1000MBPS + * %AD_LINK_SPEED_BITMASK_1000MBPS, + * %AD_LINK_SPEED_BITMASK_10000MBPS */ static u16 __get_link_speed(struct port *port) { @@ -357,6 +359,10 @@ static u16 __get_link_speed(struct port *port) speed = AD_LINK_SPEED_BITMASK_1000MBPS; break; + case SPEED_10000: + speed = AD_LINK_SPEED_BITMASK_10000MBPS; + break; + default: speed = 0; // unknown speed value from ethtool. shouldn't happen break; @@ -414,23 +420,23 @@ static inline void __initialize_port_locks(struct port *port) //conversions /** - * __ntohs_lacpdu - convert the contents of a LACPDU to host byte order + * __htons_lacpdu - convert the contents of a LACPDU to network byte order * @lacpdu: the speicifed lacpdu * * For each multi-byte field in the lacpdu, convert its content */ -static void __ntohs_lacpdu(struct lacpdu *lacpdu) +static void __htons_lacpdu(struct lacpdu *lacpdu) { if (lacpdu) { - lacpdu->actor_system_priority = ntohs(lacpdu->actor_system_priority); - lacpdu->actor_key = ntohs(lacpdu->actor_key); - lacpdu->actor_port_priority = ntohs(lacpdu->actor_port_priority); - lacpdu->actor_port = ntohs(lacpdu->actor_port); - lacpdu->partner_system_priority = ntohs(lacpdu->partner_system_priority); - lacpdu->partner_key = ntohs(lacpdu->partner_key); - lacpdu->partner_port_priority = ntohs(lacpdu->partner_port_priority); - lacpdu->partner_port = ntohs(lacpdu->partner_port); - lacpdu->collector_max_delay = ntohs(lacpdu->collector_max_delay); + lacpdu->actor_system_priority = htons(lacpdu->actor_system_priority); + lacpdu->actor_key = htons(lacpdu->actor_key); + lacpdu->actor_port_priority = htons(lacpdu->actor_port_priority); + lacpdu->actor_port = htons(lacpdu->actor_port); + lacpdu->partner_system_priority = htons(lacpdu->partner_system_priority); + lacpdu->partner_key = htons(lacpdu->partner_key); + lacpdu->partner_port_priority = htons(lacpdu->partner_port_priority); + lacpdu->partner_port = htons(lacpdu->partner_port); + lacpdu->collector_max_delay = htons(lacpdu->collector_max_delay); } } @@ -490,11 +496,11 @@ static void __record_pdu(struct lacpdu *lacpdu, struct port *port) // validate lacpdu and port if (lacpdu && port) { // record the new parameter values for the partner operational - port->partner_oper_port_number = lacpdu->actor_port; - port->partner_oper_port_priority = lacpdu->actor_port_priority; + port->partner_oper_port_number = ntohs(lacpdu->actor_port); + port->partner_oper_port_priority = ntohs(lacpdu->actor_port_priority); port->partner_oper_system = lacpdu->actor_system; - port->partner_oper_system_priority = lacpdu->actor_system_priority; - port->partner_oper_key = lacpdu->actor_key; + port->partner_oper_system_priority = ntohs(lacpdu->actor_system_priority); + port->partner_oper_key = ntohs(lacpdu->actor_key); // zero partener's lase states port->partner_oper_port_state = 0; port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_LACP_ACTIVITY); @@ -561,11 +567,11 @@ static void __update_selected(struct lacpdu *lacpdu, struct port *port) // validate lacpdu and port if (lacpdu && port) { // check if any parameter is different - if ((lacpdu->actor_port != port->partner_oper_port_number) || - (lacpdu->actor_port_priority != port->partner_oper_port_priority) || + if ((ntohs(lacpdu->actor_port) != port->partner_oper_port_number) || + (ntohs(lacpdu->actor_port_priority) != port->partner_oper_port_priority) || MAC_ADDRESS_COMPARE(&(lacpdu->actor_system), &(port->partner_oper_system)) || - (lacpdu->actor_system_priority != port->partner_oper_system_priority) || - (lacpdu->actor_key != port->partner_oper_key) || + (ntohs(lacpdu->actor_system_priority) != port->partner_oper_system_priority) || + (ntohs(lacpdu->actor_key) != port->partner_oper_key) || ((lacpdu->actor_state & AD_STATE_AGGREGATION) != (port->partner_oper_port_state & AD_STATE_AGGREGATION)) ) { // update the state machine Selected variable @@ -628,11 +634,11 @@ static void __choose_matched(struct lacpdu *lacpdu, struct port *port) // validate lacpdu and port if (lacpdu && port) { // check if all parameters are alike - if (((lacpdu->partner_port == port->actor_port_number) && - (lacpdu->partner_port_priority == port->actor_port_priority) && + if (((ntohs(lacpdu->partner_port) == port->actor_port_number) && + (ntohs(lacpdu->partner_port_priority) == port->actor_port_priority) && !MAC_ADDRESS_COMPARE(&(lacpdu->partner_system), &(port->actor_system)) && - (lacpdu->partner_system_priority == port->actor_system_priority) && - (lacpdu->partner_key == port->actor_oper_port_key) && + (ntohs(lacpdu->partner_system_priority) == port->actor_system_priority) && + (ntohs(lacpdu->partner_key) == port->actor_oper_port_key) && ((lacpdu->partner_state & AD_STATE_AGGREGATION) == (port->actor_oper_port_state & AD_STATE_AGGREGATION))) || // or this is individual link(aggregation == FALSE) ((lacpdu->actor_state & AD_STATE_AGGREGATION) == 0) @@ -662,11 +668,11 @@ static void __update_ntt(struct lacpdu *lacpdu, struct port *port) // validate lacpdu and port if (lacpdu && port) { // check if any parameter is different - if ((lacpdu->partner_port != port->actor_port_number) || - (lacpdu->partner_port_priority != port->actor_port_priority) || + if ((ntohs(lacpdu->partner_port) != port->actor_port_number) || + (ntohs(lacpdu->partner_port_priority) != port->actor_port_priority) || MAC_ADDRESS_COMPARE(&(lacpdu->partner_system), &(port->actor_system)) || - (lacpdu->partner_system_priority != port->actor_system_priority) || - (lacpdu->partner_key != port->actor_oper_port_key) || + (ntohs(lacpdu->partner_system_priority) != port->actor_system_priority) || + (ntohs(lacpdu->partner_key) != port->actor_oper_port_key) || ((lacpdu->partner_state & AD_STATE_LACP_ACTIVITY) != (port->actor_oper_port_state & AD_STATE_LACP_ACTIVITY)) || ((lacpdu->partner_state & AD_STATE_LACP_TIMEOUT) != (port->actor_oper_port_state & AD_STATE_LACP_TIMEOUT)) || ((lacpdu->partner_state & AD_STATE_SYNCHRONIZATION) != (port->actor_oper_port_state & AD_STATE_SYNCHRONIZATION)) || @@ -775,6 +781,9 @@ static u32 __get_agg_bandwidth(struct aggregator *aggregator) case AD_LINK_SPEED_BITMASK_1000MBPS: bandwidth = aggregator->num_of_ports * 1000; break; + case AD_LINK_SPEED_BITMASK_10000MBPS: + bandwidth = aggregator->num_of_ports * 10000; + break; default: bandwidth=0; // to silent the compilor .... } @@ -847,7 +856,7 @@ static inline void __update_lacpdu_from_port(struct port *port) */ /* Convert all non u8 parameters to Big Endian for transmit */ - __ntohs_lacpdu(lacpdu); + __htons_lacpdu(lacpdu); } ////////////////////////////////////////////////////////////////////////////////////// @@ -2171,7 +2180,6 @@ static void bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u switch (lacpdu->subtype) { case AD_TYPE_LACPDU: - __ntohs_lacpdu(lacpdu); dprintk("Received LACPDU on port %d\n", port->actor_port_number); ad_rx_machine(lacpdu, port); break; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 850aae21a2f..0fb5f653d3c 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -96,6 +96,7 @@ static char *lacp_rate = NULL; static char *xmit_hash_policy = NULL; static int arp_interval = BOND_LINK_ARP_INTERV; static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, }; +static char *arp_validate = NULL; struct bond_params bonding_defaults; module_param(max_bonds, int, 0); @@ -127,6 +128,8 @@ module_param(arp_interval, int, 0); MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds"); module_param_array(arp_ip_target, charp, NULL, 0); MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form"); +module_param(arp_validate, charp, 0); +MODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes: none (default), active, backup or all"); /*----------------------------- Global variables ----------------------------*/ @@ -170,6 +173,14 @@ struct bond_parm_tbl xmit_hashtype_tbl[] = { { NULL, -1}, }; +struct bond_parm_tbl arp_validate_tbl[] = { +{ "none", BOND_ARP_VALIDATE_NONE}, +{ "active", BOND_ARP_VALIDATE_ACTIVE}, +{ "backup", BOND_ARP_VALIDATE_BACKUP}, +{ "all", BOND_ARP_VALIDATE_ALL}, +{ NULL, -1}, +}; + /*-------------------------- Forward declarations ---------------------------*/ static void bond_send_gratuitous_arp(struct bonding *bond); @@ -638,6 +649,7 @@ verify: case SPEED_10: case SPEED_100: case SPEED_1000: + case SPEED_10000: break; default: return -1; @@ -1210,10 +1222,14 @@ static int bond_compute_features(struct bonding *bond) unsigned long features = BOND_INTERSECT_FEATURES; struct slave *slave; struct net_device *bond_dev = bond->dev; + unsigned short max_hard_header_len = ETH_HLEN; int i; - bond_for_each_slave(bond, slave, i) + bond_for_each_slave(bond, slave, i) { features &= (slave->dev->features & BOND_INTERSECT_FEATURES); + if (slave->dev->hard_header_len > max_hard_header_len) + max_hard_header_len = slave->dev->hard_header_len; + } if ((features & NETIF_F_SG) && !(features & NETIF_F_ALL_CSUM)) @@ -1231,6 +1247,7 @@ static int bond_compute_features(struct bonding *bond) features |= (bond_dev->features & ~BOND_INTERSECT_FEATURES); bond_dev->features = features; + bond_dev->hard_header_len = max_hard_header_len; return 0; } @@ -1365,6 +1382,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) } new_slave->dev = slave_dev; + slave_dev->priv_flags |= IFF_BONDING; if ((bond->params.mode == BOND_MODE_TLB) || (bond->params.mode == BOND_MODE_ALB)) { @@ -1417,6 +1435,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) bond_compute_features(bond); + new_slave->last_arp_rx = jiffies; + if (bond->params.miimon && !bond->params.use_carrier) { link_reporting = bond_check_dev_link(bond, slave_dev, 1); @@ -1493,29 +1513,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) switch (bond->params.mode) { case BOND_MODE_ACTIVEBACKUP: - /* if we're in active-backup mode, we need one and - * only one active interface. The backup interfaces - * will have their SLAVE_INACTIVE flag set because we - * need them to be drop all packets. Thus, since we - * guarantee that curr_active_slave always point to - * the last usable interface, we just have to verify - * this interface's flag. - */ - if (((!bond->curr_active_slave) || - (bond->curr_active_slave->dev->priv_flags & IFF_SLAVE_INACTIVE)) && - (new_slave->link != BOND_LINK_DOWN)) { - /* first slave or no active slave yet, and this link - is OK, so make this interface the active one */ - bond_change_active_slave(bond, new_slave); - printk(KERN_INFO DRV_NAME - ": %s: first active interface up!\n", - bond->dev->name); - netif_carrier_on(bond->dev); - - } else { - dprintk("This is just a backup slave\n"); - bond_set_slave_inactive_flags(new_slave); - } + bond_set_slave_inactive_flags(new_slave); + bond_select_active_slave(bond); break; case BOND_MODE_8023AD: /* in 802.3ad mode, the internal mechanism @@ -1778,7 +1777,8 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) dev_set_mac_address(slave_dev, &addr); slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB | - IFF_SLAVE_INACTIVE); + IFF_SLAVE_INACTIVE | IFF_BONDING | + IFF_SLAVE_NEEDARP); kfree(slave); @@ -2291,6 +2291,25 @@ static int bond_has_ip(struct bonding *bond) return 0; } +static int bond_has_this_ip(struct bonding *bond, u32 ip) +{ + struct vlan_entry *vlan, *vlan_next; + + if (ip == bond->master_ip) + return 1; + + if (list_empty(&bond->vlan_list)) + return 0; + + list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list, + vlan_list) { + if (ip == vlan->vlan_ip) + return 1; + } + + return 0; +} + /* * We go to the (large) trouble of VLAN tagging ARP frames because * switches in VLAN mode (especially if ports are configured as @@ -2429,6 +2448,93 @@ static void bond_send_gratuitous_arp(struct bonding *bond) } } +static void bond_validate_arp(struct bonding *bond, struct slave *slave, u32 sip, u32 tip) +{ + int i; + u32 *targets = bond->params.arp_targets; + + targets = bond->params.arp_targets; + for (i = 0; (i < BOND_MAX_ARP_TARGETS) && targets[i]; i++) { + dprintk("bva: sip %u.%u.%u.%u tip %u.%u.%u.%u t[%d] " + "%u.%u.%u.%u bhti(tip) %d\n", + NIPQUAD(sip), NIPQUAD(tip), i, NIPQUAD(targets[i]), + bond_has_this_ip(bond, tip)); + if (sip == targets[i]) { + if (bond_has_this_ip(bond, tip)) + slave->last_arp_rx = jiffies; + return; + } + } +} + +static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) +{ + struct arphdr *arp; + struct slave *slave; + struct bonding *bond; + unsigned char *arp_ptr; + u32 sip, tip; + + if (!(dev->priv_flags & IFF_BONDING) || !(dev->flags & IFF_MASTER)) + goto out; + + bond = dev->priv; + read_lock(&bond->lock); + + dprintk("bond_arp_rcv: bond %s skb->dev %s orig_dev %s\n", + bond->dev->name, skb->dev ? skb->dev->name : "NULL", + orig_dev ? orig_dev->name : "NULL"); + + slave = bond_get_slave_by_dev(bond, orig_dev); + if (!slave || !slave_do_arp_validate(bond, slave)) + goto out_unlock; + + /* ARP header, plus 2 device addresses, plus 2 IP addresses. */ + if (!pskb_may_pull(skb, (sizeof(struct arphdr) + + (2 * dev->addr_len) + + (2 * sizeof(u32))))) + goto out_unlock; + + arp = skb->nh.arph; + if (arp->ar_hln != dev->addr_len || + skb->pkt_type == PACKET_OTHERHOST || + skb->pkt_type == PACKET_LOOPBACK || + arp->ar_hrd != htons(ARPHRD_ETHER) || + arp->ar_pro != htons(ETH_P_IP) || + arp->ar_pln != 4) + goto out_unlock; + + arp_ptr = (unsigned char *)(arp + 1); + arp_ptr += dev->addr_len; + memcpy(&sip, arp_ptr, 4); + arp_ptr += 4 + dev->addr_len; + memcpy(&tip, arp_ptr, 4); + + dprintk("bond_arp_rcv: %s %s/%d av %d sv %d sip %u.%u.%u.%u" + " tip %u.%u.%u.%u\n", bond->dev->name, slave->dev->name, + slave->state, bond->params.arp_validate, + slave_do_arp_validate(bond, slave), NIPQUAD(sip), NIPQUAD(tip)); + + /* + * Backup slaves won't see the ARP reply, but do come through + * here for each ARP probe (so we swap the sip/tip to validate + * the probe). In a "redundant switch, common router" type of + * configuration, the ARP probe will (hopefully) travel from + * the active, through one switch, the router, then the other + * switch before reaching the backup. + */ + if (slave->state == BOND_STATE_ACTIVE) + bond_validate_arp(bond, slave, sip, tip); + else + bond_validate_arp(bond, slave, tip, sip); + +out_unlock: + read_unlock(&bond->lock); +out: + dev_kfree_skb(skb); + return NET_RX_SUCCESS; +} + /* * this function is called regularly to monitor each slave's link * ensuring that traffic is being sent and received when arp monitoring @@ -2593,7 +2699,8 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev) */ bond_for_each_slave(bond, slave, i) { if (slave->link != BOND_LINK_UP) { - if ((jiffies - slave->dev->last_rx) <= delta_in_ticks) { + if ((jiffies - slave_last_rx(bond, slave)) <= + delta_in_ticks) { slave->link = BOND_LINK_UP; @@ -2638,7 +2745,7 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev) if ((slave != bond->curr_active_slave) && (!bond->current_arp_slave) && - (((jiffies - slave->dev->last_rx) >= 3*delta_in_ticks) && + (((jiffies - slave_last_rx(bond, slave)) >= 3*delta_in_ticks) && bond_has_ip(bond))) { /* a backup slave has gone down; three times * the delta allows the current slave to be @@ -2685,7 +2792,7 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev) * if it is up and needs to take over as the curr_active_slave */ if ((((jiffies - slave->dev->trans_start) >= (2*delta_in_ticks)) || - (((jiffies - slave->dev->last_rx) >= (2*delta_in_ticks)) && + (((jiffies - slave_last_rx(bond, slave)) >= (2*delta_in_ticks)) && bond_has_ip(bond))) && ((jiffies - slave->jiffies) >= 2*delta_in_ticks)) { @@ -2950,7 +3057,7 @@ static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave seq_printf(seq, "\nSlave Interface: %s\n", slave->dev->name); seq_printf(seq, "MII Status: %s\n", (slave->link == BOND_LINK_UP) ? "up" : "down"); - seq_printf(seq, "Link Failure Count: %d\n", + seq_printf(seq, "Link Failure Count: %u\n", slave->link_failure_count); seq_printf(seq, @@ -3210,6 +3317,9 @@ static int bond_netdev_event(struct notifier_block *this, unsigned long event, v (event_dev ? event_dev->name : "None"), event); + if (!(event_dev->priv_flags & IFF_BONDING)) + return NOTIFY_DONE; + if (event_dev->flags & IFF_MASTER) { dprintk("IFF_MASTER\n"); return bond_master_netdev_event(event, event_dev); @@ -3305,6 +3415,21 @@ static void bond_unregister_lacpdu(struct bonding *bond) dev_remove_pack(&(BOND_AD_INFO(bond).ad_pkt_type)); } +void bond_register_arp(struct bonding *bond) +{ + struct packet_type *pt = &bond->arp_mon_pt; + + pt->type = htons(ETH_P_ARP); + pt->dev = NULL; /*bond->dev;XXX*/ + pt->func = bond_arp_rcv; + dev_add_pack(pt); +} + +void bond_unregister_arp(struct bonding *bond) +{ + dev_remove_pack(&bond->arp_mon_pt); +} + /*---------------------------- Hashing Policies -----------------------------*/ /* @@ -3391,6 +3516,9 @@ static int bond_open(struct net_device *bond_dev) } else { arp_timer->function = (void *)&bond_loadbalance_arp_mon; } + if (bond->params.arp_validate) + bond_register_arp(bond); + add_timer(arp_timer); } @@ -3418,9 +3546,11 @@ static int bond_close(struct net_device *bond_dev) bond_unregister_lacpdu(bond); } + if (bond->params.arp_validate) + bond_unregister_arp(bond); + write_lock_bh(&bond->lock); - bond_mc_list_destroy(bond); /* signal timers not to re-arm */ bond->kill_timers = 1; @@ -3451,8 +3581,6 @@ static int bond_close(struct net_device *bond_dev) break; } - /* Release the bonded slaves */ - bond_release_all(bond_dev); if ((bond->params.mode == BOND_MODE_TLB) || (bond->params.mode == BOND_MODE_ALB)) { @@ -4179,6 +4307,7 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params) /* Initialize the device options */ bond_dev->tx_queue_len = 0; bond_dev->flags |= IFF_MASTER|IFF_MULTICAST; + bond_dev->priv_flags |= IFF_BONDING; /* At first, we block adding VLANs. That's the only way to * prevent problems that occur when adding VLANs over an @@ -4237,6 +4366,9 @@ static void bond_free_all(void) list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) { struct net_device *bond_dev = bond->dev; + bond_mc_list_destroy(bond); + /* Release the bonded slaves */ + bond_release_all(bond_dev); unregister_netdevice(bond_dev); bond_deinit(bond_dev); } @@ -4270,6 +4402,8 @@ int bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl) static int bond_check_params(struct bond_params *params) { + int arp_validate_value; + /* * Convert string parameters. */ @@ -4473,6 +4607,29 @@ static int bond_check_params(struct bond_params *params) arp_interval = 0; } + if (arp_validate) { + if (bond_mode != BOND_MODE_ACTIVEBACKUP) { + printk(KERN_ERR DRV_NAME + ": arp_validate only supported in active-backup mode\n"); + return -EINVAL; + } + if (!arp_interval) { + printk(KERN_ERR DRV_NAME + ": arp_validate requires arp_interval\n"); + return -EINVAL; + } + + arp_validate_value = bond_parse_parm(arp_validate, + arp_validate_tbl); + if (arp_validate_value == -1) { + printk(KERN_ERR DRV_NAME + ": Error: invalid arp_validate \"%s\"\n", + arp_validate == NULL ? "NULL" : arp_validate); + return -EINVAL; + } + } else + arp_validate_value = 0; + if (miimon) { printk(KERN_INFO DRV_NAME ": MII link monitoring set to %d ms\n", @@ -4481,8 +4638,10 @@ static int bond_check_params(struct bond_params *params) int i; printk(KERN_INFO DRV_NAME - ": ARP monitoring set to %d ms with %d target(s):", - arp_interval, arp_ip_count); + ": ARP monitoring set to %d ms, validate %s, with %d target(s):", + arp_interval, + arp_validate_tbl[arp_validate_value].modename, + arp_ip_count); for (i = 0; i < arp_ip_count; i++) printk (" %s", arp_ip_target[i]); @@ -4516,6 +4675,7 @@ static int bond_check_params(struct bond_params *params) params->xmit_policy = xmit_hashtype; params->miimon = miimon; params->arp_interval = arp_interval; + params->arp_validate = arp_validate_value; params->updelay = updelay; params->downdelay = downdelay; params->use_carrier = use_carrier; diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index cfe4dc3a93a..ced9ed8f995 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -51,6 +51,7 @@ extern struct bond_params bonding_defaults; extern struct bond_parm_tbl bond_mode_tbl[]; extern struct bond_parm_tbl bond_lacp_tbl[]; extern struct bond_parm_tbl xmit_hashtype_tbl[]; +extern struct bond_parm_tbl arp_validate_tbl[]; static int expected_refcount = -1; static struct class *netdev_class; @@ -503,6 +504,53 @@ out: static CLASS_DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR, bonding_show_xmit_hash, bonding_store_xmit_hash); /* + * Show and set arp_validate. + */ +static ssize_t bonding_show_arp_validate(struct class_device *cd, char *buf) +{ + struct bonding *bond = to_bond(cd); + + return sprintf(buf, "%s %d\n", + arp_validate_tbl[bond->params.arp_validate].modename, + bond->params.arp_validate) + 1; +} + +static ssize_t bonding_store_arp_validate(struct class_device *cd, const char *buf, size_t count) +{ + int new_value; + struct bonding *bond = to_bond(cd); + + new_value = bond_parse_parm((char *)buf, arp_validate_tbl); + if (new_value < 0) { + printk(KERN_ERR DRV_NAME + ": %s: Ignoring invalid arp_validate value %s\n", + bond->dev->name, buf); + return -EINVAL; + } + if (new_value && (bond->params.mode != BOND_MODE_ACTIVEBACKUP)) { + printk(KERN_ERR DRV_NAME + ": %s: arp_validate only supported in active-backup mode.\n", + bond->dev->name); + return -EINVAL; + } + printk(KERN_INFO DRV_NAME ": %s: setting arp_validate to %s (%d).\n", + bond->dev->name, arp_validate_tbl[new_value].modename, + new_value); + + if (!bond->params.arp_validate && new_value) { + bond_register_arp(bond); + } else if (bond->params.arp_validate && !new_value) { + bond_unregister_arp(bond); + } + + bond->params.arp_validate = new_value; + + return count; +} + +static CLASS_DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate); + +/* * Show and set the arp timer interval. There are two tricky bits * here. First, if ARP monitoring is activated, then we must disable * MII monitoring. Second, if the ARP timer isn't running, we must @@ -914,6 +962,11 @@ static ssize_t bonding_store_miimon(struct class_device *cd, const char *buf, si "ARP monitoring. Disabling ARP monitoring...\n", bond->dev->name); bond->params.arp_interval = 0; + if (bond->params.arp_validate) { + bond_unregister_arp(bond); + bond->params.arp_validate = + BOND_ARP_VALIDATE_NONE; + } /* Kill ARP timer, else it brings bond's link down */ if (bond->mii_timer.function) { printk(KERN_INFO DRV_NAME @@ -1093,7 +1146,7 @@ static ssize_t bonding_store_active_slave(struct class_device *cd, const char *b strlen(slave->dev->name)) == 0) { old_active = bond->curr_active_slave; new_active = slave; - if (new_active && (new_active == old_active)) { + if (new_active == old_active) { /* do nothing */ printk(KERN_INFO DRV_NAME ": %s: %s is already the current active slave.\n", @@ -1273,6 +1326,7 @@ static CLASS_DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, N static struct attribute *per_bond_attrs[] = { &class_device_attr_slaves.attr, &class_device_attr_mode.attr, + &class_device_attr_arp_validate.attr, &class_device_attr_arp_interval.attr, &class_device_attr_arp_ip_target.attr, &class_device_attr_downdelay.attr, diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 0bdfe2c7145..dc434fb6da8 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -22,8 +22,8 @@ #include "bond_3ad.h" #include "bond_alb.h" -#define DRV_VERSION "3.0.3" -#define DRV_RELDATE "March 23, 2006" +#define DRV_VERSION "3.1.1" +#define DRV_RELDATE "September 26, 2006" #define DRV_NAME "bonding" #define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" @@ -126,6 +126,7 @@ struct bond_params { int xmit_policy; int miimon; int arp_interval; + int arp_validate; int use_carrier; int updelay; int downdelay; @@ -149,8 +150,9 @@ struct slave { struct net_device *dev; /* first - useful for panic debug */ struct slave *next; struct slave *prev; - s16 delay; + int delay; u32 jiffies; + u32 last_arp_rx; s8 link; /* one of BOND_LINK_XXXX */ s8 state; /* one of BOND_STATE_XXXX */ u32 original_flags; @@ -198,6 +200,7 @@ struct bonding { struct bond_params params; struct list_head vlan_list; struct vlan_group *vlgrp; + struct packet_type arp_mon_pt; }; /** @@ -228,6 +231,25 @@ static inline struct bonding *bond_get_bond_by_slave(struct slave *slave) return (struct bonding *)slave->dev->master->priv; } +#define BOND_ARP_VALIDATE_NONE 0 +#define BOND_ARP_VALIDATE_ACTIVE (1 << BOND_STATE_ACTIVE) +#define BOND_ARP_VALIDATE_BACKUP (1 << BOND_STATE_BACKUP) +#define BOND_ARP_VALIDATE_ALL (BOND_ARP_VALIDATE_ACTIVE | \ + BOND_ARP_VALIDATE_BACKUP) + +extern inline int slave_do_arp_validate(struct bonding *bond, struct slave *slave) +{ + return bond->params.arp_validate & (1 << slave->state); +} + +extern inline u32 slave_last_rx(struct bonding *bond, struct slave *slave) +{ + if (slave_do_arp_validate(bond, slave)) + return slave->last_arp_rx; + + return slave->dev->last_rx; +} + static inline void bond_set_slave_inactive_flags(struct slave *slave) { struct bonding *bond = slave->dev->master->priv; @@ -235,12 +257,14 @@ static inline void bond_set_slave_inactive_flags(struct slave *slave) bond->params.mode != BOND_MODE_ALB) slave->state = BOND_STATE_BACKUP; slave->dev->priv_flags |= IFF_SLAVE_INACTIVE; + if (slave_do_arp_validate(bond, slave)) + slave->dev->priv_flags |= IFF_SLAVE_NEEDARP; } static inline void bond_set_slave_active_flags(struct slave *slave) { slave->state = BOND_STATE_ACTIVE; - slave->dev->priv_flags &= ~IFF_SLAVE_INACTIVE; + slave->dev->priv_flags &= ~(IFF_SLAVE_INACTIVE | IFF_SLAVE_NEEDARP); } static inline void bond_set_master_3ad_flags(struct bonding *bond) @@ -284,6 +308,8 @@ int bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl); const char *bond_mode_name(int mode); void bond_select_active_slave(struct bonding *bond); void bond_change_active_slave(struct bonding *bond, struct slave *new_active); +void bond_register_arp(struct bonding *); +void bond_unregister_arp(struct bonding *); #endif /* _LINUX_BONDING_H */ |