Commit a77c64c1 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6

* 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6: (48 commits)
  [PATCH] bonding: update version number
  [PATCH] git-netdev-all: pc300_tty build fix
  [PATCH] Make PC300 WAN driver compile again
  [PATCH] Modularize generic HDLC
  [PATCH] more s2io __iomem annotations
  [PATCH] restore __iomem annotations in e1000
  [PATCH] 64bit bugs in s2io
  [PATCH] bonding: Fix primary selection error at enslavement time
  [PATCH] bonding: Don't mangle LACPDUs
  [PATCH] bonding: Validate probe replies in ARP monitor
  [PATCH] bonding: Don't release slaves when master is admin down
  [PATCH] bonding: Add priv_flag to avoid event mishandling
  [PATCH] bonding: Handle large hard_header_len
  [PATCH] bonding: Remove unneeded NULL test
  [PATCH] bonding: Format fix in seq_printf call
  [PATCH] bonding: Convert delay value from s16 to int
  [PATCH] bonding: Allow bonding to enslave a 10 Gig adapter
  Delete unused drivers/net/gt64240eth.h
  [PATCH] skge: fiber support
  [PATCH] fix possible NULL ptr deref in forcedeth
  ...
parents ac7f6b5e 0ba8821b
......@@ -192,6 +192,17 @@ or, for backwards compatibility, the option value. E.g.,
arp_interval
Specifies the ARP link monitoring frequency in milliseconds.
The ARP monitor works by periodically checking the slave
devices to determine whether they have sent or received
traffic recently (the precise criteria depends upon the
bonding mode, and the state of the slave). Regular traffic is
generated via ARP probes issued for the addresses specified by
the arp_ip_target option.
This behavior can be modified by the arp_validate option,
below.
If ARP monitoring is used in an etherchannel compatible mode
(modes 0 and 2), the switch should be configured in a mode
that evenly distributes packets across all links. If the
......@@ -213,6 +224,54 @@ arp_ip_target
maximum number of targets that can be specified is 16. The
default value is no IP addresses.
arp_validate
Specifies whether or not ARP probes and replies should be
validated in the active-backup mode. This causes the ARP
monitor to examine the incoming ARP requests and replies, and
only consider a slave to be up if it is receiving the
appropriate ARP traffic.
Possible values are:
none or 0
No validation is performed. This is the default.
active or 1
Validation is performed only for the active slave.
backup or 2
Validation is performed only for backup slaves.
all or 3
Validation is performed for all slaves.
For the active slave, the validation checks ARP replies to
confirm that they were generated by an arp_ip_target. Since
backup slaves do not typically receive these replies, the
validation performed for backup slaves is on the ARP request
sent out via the active slave. It is possible that some
switch or network configurations may result in situations
wherein the backup slaves do not receive the ARP requests; in
such a situation, validation of backup slaves must be
disabled.
This option is useful in network configurations in which
multiple bonding hosts are concurrently issuing ARPs to one or
more targets beyond a common switch. Should the link between
the switch and target fail (but not the switch itself), the
probe traffic generated by the multiple bonding instances will
fool the standard ARP monitor into considering the links as
still up. Use of the arp_validate option can resolve this, as
the ARP monitor will only consider ARP requests and replies
associated with its own instance of bonding.
This option was added in bonding version 3.1.0.
downdelay
Specifies the time, in milliseconds, to wait before disabling
......
......@@ -2679,7 +2679,6 @@ M: josejx@gentoo.org
P: Daniel Drake
M: dsd@gentoo.org
W: http://softmac.sipsolutions.net/
L: softmac-dev@sipsolutions.net
L: netdev@vger.kernel.org
S: Maintained
......
......@@ -163,11 +163,7 @@ MODULE_DEVICE_TABLE(pci, acenic_pci_tbl);
#define SET_NETDEV_DEV(net, pdev) do{} while(0)
#endif
#if LINUX_VERSION_CODE >= 0x2051c
#define ace_sync_irq(irq) synchronize_irq(irq)
#else
#define ace_sync_irq(irq) synchronize_irq()
#endif
#ifndef offset_in_page
#define offset_in_page(ptr) ((unsigned long)(ptr) & ~PAGE_MASK)
......
......@@ -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;
......
......@@ -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;