From: t_jeang Date: Tue, 6 Jan 2009 12:05:56 +0000 (+0000) Subject: imported patch revert-linux-2.6-net-bonding-update-to-upstream-version-3-2-2.patch X-Git-Tag: revert-linux-2.6-net-bonding-locking-fixes-and-version-3-2-4.patch X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=9d04c8451b287477bc580866219e1e777775174c;p=xenclient%2Fkernel.git imported patch revert-linux-2.6-net-bonding-update-to-upstream-version-3-2-2.patch --- diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 49dc2515..3fb354d9 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -100,6 +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 __htons_lacpdu(struct lacpdu *lacpdu); static u16 __ad_timer_to_ticks(u16 timer_type, u16 Par); @@ -125,7 +126,7 @@ static struct aggregator *__get_active_agg(struct aggregator *aggregator); // ================= main 802.3ad protocol functions ================== static int ad_lacpdu_send(struct port *port); -static int ad_marker_send(struct port *port, struct bond_marker *marker); +static int ad_marker_send(struct port *port, struct marker *marker); static void ad_mux_machine(struct port *port); static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port); static void ad_tx_machine(struct port *port); @@ -138,8 +139,8 @@ static void ad_initialize_port(struct port *port, int lacp_fast); static void ad_initialize_lacpdu(struct lacpdu *Lacpdu); static void ad_enable_collecting_distributing(struct port *port); static void ad_disable_collecting_distributing(struct port *port); -static void ad_marker_info_received(struct bond_marker *marker_info, struct port *port); -static void ad_marker_response_received(struct bond_marker *marker, struct port *port); +static void ad_marker_info_received(struct marker *marker_info, struct port *port); +static void ad_marker_response_received(struct marker *marker, struct port *port); ///////////////////////////////////////////////////////////////////////////////// @@ -418,6 +419,26 @@ static inline void __initialize_port_locks(struct port *port) } //conversions +/** + * __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 __htons_lacpdu(struct lacpdu *lacpdu) +{ + if (lacpdu) { + 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); + } +} /** * __ad_timer_to_ticks - convert a given timer type to AD module ticks @@ -805,11 +826,11 @@ static inline void __update_lacpdu_from_port(struct port *port) * lacpdu->actor_information_length initialized */ - lacpdu->actor_system_priority = htons(port->actor_system_priority); + lacpdu->actor_system_priority = port->actor_system_priority; lacpdu->actor_system = port->actor_system; - lacpdu->actor_key = htons(port->actor_oper_port_key); - lacpdu->actor_port_priority = htons(port->actor_port_priority); - lacpdu->actor_port = htons(port->actor_port_number); + lacpdu->actor_key = port->actor_oper_port_key; + lacpdu->actor_port_priority = port->actor_port_priority; + lacpdu->actor_port = port->actor_port_number; lacpdu->actor_state = port->actor_oper_port_state; /* lacpdu->reserved_3_1 initialized @@ -817,11 +838,11 @@ static inline void __update_lacpdu_from_port(struct port *port) * lacpdu->partner_information_length initialized */ - lacpdu->partner_system_priority = htons(port->partner_oper_system_priority); + lacpdu->partner_system_priority = port->partner_oper_system_priority; lacpdu->partner_system = port->partner_oper_system; - lacpdu->partner_key = htons(port->partner_oper_key); - lacpdu->partner_port_priority = htons(port->partner_oper_port_priority); - lacpdu->partner_port = htons(port->partner_oper_port_number); + lacpdu->partner_key = port->partner_oper_key; + lacpdu->partner_port_priority = port->partner_oper_port_priority; + lacpdu->partner_port = port->partner_oper_port_number; lacpdu->partner_state = port->partner_oper_port_state; /* lacpdu->reserved_3_2 initialized @@ -833,6 +854,9 @@ static inline void __update_lacpdu_from_port(struct port *port) * terminator_length initialized * reserved_50[50] initialized */ + + /* Convert all non u8 parameters to Big Endian for transmit */ + __htons_lacpdu(lacpdu); } ////////////////////////////////////////////////////////////////////////////////////// @@ -860,8 +884,8 @@ static int ad_lacpdu_send(struct port *port) } skb->dev = slave->dev; - skb_reset_mac_header(skb); - skb->nh.raw = skb->mac.raw + ETH_HLEN; + skb->mac.raw = skb->data; + skb->nh.raw = skb->data + ETH_HLEN; skb->protocol = PKT_TYPE_LACPDU; skb->priority = TC_PRIO_CONTROL; @@ -888,12 +912,12 @@ static int ad_lacpdu_send(struct port *port) * Returns: 0 on success * < 0 on error */ -static int ad_marker_send(struct port *port, struct bond_marker *marker) +static int ad_marker_send(struct port *port, struct marker *marker) { struct slave *slave = port->slave; struct sk_buff *skb; - struct bond_marker_header *marker_header; - int length = sizeof(struct bond_marker_header); + struct marker_header *marker_header; + int length = sizeof(struct marker_header); struct mac_addr lacpdu_multicast_address = AD_MULTICAST_LACPDU_ADDR; skb = dev_alloc_skb(length + 16); @@ -904,11 +928,11 @@ static int ad_marker_send(struct port *port, struct bond_marker *marker) skb_reserve(skb, 16); skb->dev = slave->dev; - skb_reset_mac_header(skb); - skb->nh.raw = skb->mac.raw + ETH_HLEN; + skb->mac.raw = skb->data; + skb->nh.raw = skb->data + ETH_HLEN; skb->protocol = PKT_TYPE_LACPDU; - marker_header = (struct bond_marker_header *)skb_put(skb, length); + marker_header = (struct marker_header *)skb_put(skb, length); marker_header->ad_header.destination_address = lacpdu_multicast_address; /* Note: source addres is set to be the member's PERMANENT address, because we use it @@ -1708,7 +1732,7 @@ static void ad_disable_collecting_distributing(struct port *port) */ static void ad_marker_info_send(struct port *port) { - struct bond_marker marker; + struct marker marker; u16 index; // fill the marker PDU with the appropriate values @@ -1741,14 +1765,13 @@ static void ad_marker_info_send(struct port *port) * @port: the port we're looking at * */ -static void ad_marker_info_received(struct bond_marker *marker_info, - struct port *port) +static void ad_marker_info_received(struct marker *marker_info,struct port *port) { - struct bond_marker marker; + struct marker marker; // copy the received marker data to the response marker //marker = *marker_info; - memcpy(&marker, marker_info, sizeof(struct bond_marker)); + memcpy(&marker, marker_info, sizeof(struct marker)); // change the marker subtype to marker response marker.tlv_type=AD_MARKER_RESPONSE_SUBTYPE; // send the marker response @@ -1767,8 +1790,7 @@ static void ad_marker_info_received(struct bond_marker *marker_info, * response for marker PDU's, in this stage, but only to respond to marker * information. */ -static void ad_marker_response_received(struct bond_marker *marker, - struct port *port) +static void ad_marker_response_received(struct marker *marker, struct port *port) { marker=NULL; // just to satisfy the compiler port=NULL; // just to satisfy the compiler @@ -1811,7 +1833,7 @@ static void ad_initialize_lacpdu(struct lacpdu *lacpdu) } lacpdu->tlv_type_collector_info = 0x03; lacpdu->collector_information_length= 0x10; - lacpdu->collector_max_delay = htons(AD_COLLECTOR_MAX_DELAY); + lacpdu->collector_max_delay = AD_COLLECTOR_MAX_DELAY; for (index=0; index<=11; index++) { lacpdu->reserved_12[index]=0; } @@ -2075,9 +2097,8 @@ void bond_3ad_unbind_slave(struct slave *slave) * times out, and it selects an aggregator for the ports that are yet not * related to any aggregator, and selects the active aggregator for a bond. */ -void bond_3ad_state_machine_handler(void *work_data) +void bond_3ad_state_machine_handler(struct bonding *bond) { - struct bonding *bond = work_data; struct port *port; struct aggregator *aggregator; @@ -2128,7 +2149,7 @@ void bond_3ad_state_machine_handler(void *work_data) } re_arm: - queue_delayed_work(bond->wq, &bond->ad_work, ad_delta_in_ticks); + mod_timer(&(BOND_AD_INFO(bond).ad_timer), jiffies + ad_delta_in_ticks); out: read_unlock(&bond->lock); } @@ -2166,15 +2187,15 @@ static void bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u case AD_TYPE_MARKER: // No need to convert fields to Little Endian since we don't use the marker's fields. - switch (((struct bond_marker *)lacpdu)->tlv_type) { + switch (((struct marker *)lacpdu)->tlv_type) { case AD_MARKER_INFORMATION_SUBTYPE: dprintk("Received Marker Information on port %d\n", port->actor_port_number); - ad_marker_info_received((struct bond_marker *)lacpdu, port); + ad_marker_info_received((struct marker *)lacpdu, port); break; case AD_MARKER_RESPONSE_SUBTYPE: dprintk("Received Marker Response on port %d\n", port->actor_port_number); - ad_marker_response_received((struct bond_marker *)lacpdu, port); + ad_marker_response_received((struct marker *)lacpdu, port); break; default: @@ -2282,18 +2303,19 @@ void bond_3ad_handle_link_change(struct slave *slave, char link) } /* - * set link state for bonding master: if we have an active + * set link state for bonding master: if we have an active partnered * aggregator, we're up, if not, we're down. Presumes that we cannot * have an active aggregator if there are no slaves with link up. * - * This behavior complies with IEEE 802.3 section 43.3.9. - * * Called by bond_set_carrier(). Return zero if carrier state does not * change, nonzero if it does. */ int bond_3ad_set_carrier(struct bonding *bond) { - if (__get_active_agg(&(SLAVE_AD_INFO(bond->first_slave).aggregator))) { + struct aggregator *agg; + + agg = __get_active_agg(&(SLAVE_AD_INFO(bond->first_slave).aggregator)); + if (agg && MAC_ADDRESS_COMPARE(&agg->partner_system, &null_mac_addr)) { if (!netif_carrier_ok(bond->dev)) { netif_carrier_on(bond->dev); return 1; diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h index bc25af96..6ad5ad6e 100644 --- a/drivers/net/bonding/bond_3ad.h +++ b/drivers/net/bonding/bond_3ad.h @@ -92,7 +92,7 @@ typedef enum { typedef enum { AD_MARKER_INFORMATION_SUBTYPE = 1, // marker imformation subtype AD_MARKER_RESPONSE_SUBTYPE // marker response subtype -} bond_marker_subtype_t; +} marker_subtype_t; // timers types(43.4.9 in the 802.3ad standard) typedef enum { @@ -108,7 +108,7 @@ typedef enum { typedef struct ad_header { struct mac_addr destination_address; struct mac_addr source_address; - __be16 length_type; + u16 length_type; } ad_header_t; // Link Aggregation Control Protocol(LACP) data unit structure(43.4.2.2 in the 802.3ad standard) @@ -117,25 +117,25 @@ typedef struct lacpdu { u8 version_number; u8 tlv_type_actor_info; // = actor information(type/length/value) u8 actor_information_length; // = 20 - __be16 actor_system_priority; + u16 actor_system_priority; struct mac_addr actor_system; - __be16 actor_key; - __be16 actor_port_priority; - __be16 actor_port; + u16 actor_key; + u16 actor_port_priority; + u16 actor_port; u8 actor_state; u8 reserved_3_1[3]; // = 0 u8 tlv_type_partner_info; // = partner information u8 partner_information_length; // = 20 - __be16 partner_system_priority; + u16 partner_system_priority; struct mac_addr partner_system; - __be16 partner_key; - __be16 partner_port_priority; - __be16 partner_port; + u16 partner_key; + u16 partner_port_priority; + u16 partner_port; u8 partner_state; u8 reserved_3_2[3]; // = 0 u8 tlv_type_collector_info; // = collector information u8 collector_information_length; // = 16 - __be16 collector_max_delay; + u16 collector_max_delay; u8 reserved_12[12]; u8 tlv_type_terminator; // = terminator u8 terminator_length; // = 0 @@ -148,7 +148,7 @@ typedef struct lacpdu_header { } lacpdu_header_t; // Marker Protocol Data Unit(PDU) structure(43.5.3.2 in the 802.3ad standard) -typedef struct bond_marker { +typedef struct marker { u8 subtype; // = 0x02 (marker PDU) u8 version_number; // = 0x01 u8 tlv_type; // = 0x01 (marker information) @@ -161,12 +161,12 @@ typedef struct bond_marker { u8 tlv_type_terminator; // = 0x00 u8 terminator_length; // = 0x00 u8 reserved_90[90]; // = 0 -} bond_marker_t; +} marker_t; -typedef struct bond_marker_header { +typedef struct marker_header { struct ad_header ad_header; - struct bond_marker marker; -} bond_marker_header_t; + struct marker marker; +} marker_header_t; #pragma pack() @@ -276,7 +276,7 @@ struct ad_slave_info { void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution, int lacp_fast); int bond_3ad_bind_slave(struct slave *slave); void bond_3ad_unbind_slave(struct slave *slave); -void bond_3ad_state_machine_handler(void *); +void bond_3ad_state_machine_handler(struct bonding *bond); void bond_3ad_adapter_speed_changed(struct slave *slave); void bond_3ad_adapter_duplex_changed(struct slave *slave); void bond_3ad_handle_link_change(struct slave *slave, char link); diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 09a8a892..217a2eed 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -87,32 +87,27 @@ static const int alb_delta_in_ticks = HZ / ALB_TIMER_TICKS_PER_SEC; struct learning_pkt { u8 mac_dst[ETH_ALEN]; u8 mac_src[ETH_ALEN]; - __be16 type; + u16 type; u8 padding[ETH_ZLEN - ETH_HLEN]; }; struct arp_pkt { - __be16 hw_addr_space; - __be16 prot_addr_space; + u16 hw_addr_space; + u16 prot_addr_space; u8 hw_addr_len; u8 prot_addr_len; - __be16 op_code; + u16 op_code; u8 mac_src[ETH_ALEN]; /* sender hardware address */ - __be32 ip_src; /* sender IP address */ + u32 ip_src; /* sender IP address */ u8 mac_dst[ETH_ALEN]; /* target hardware address */ - __be32 ip_dst; /* target IP address */ + u32 ip_dst; /* target IP address */ }; #pragma pack() -static inline struct arp_pkt *arp_pkt(const struct sk_buff *skb) -{ - return (struct arp_pkt *)skb_network_header(skb); -} - /* Forward declaration */ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[]); -static inline u8 _simple_hash(const u8 *hash_start, int hash_size) +static inline u8 _simple_hash(u8 *hash_start, int hash_size) { int i; u8 hash = 0; @@ -128,12 +123,12 @@ static inline u8 _simple_hash(const u8 *hash_start, int hash_size) static inline void _lock_tx_hashtbl(struct bonding *bond) { - spin_lock_bh(&(BOND_ALB_INFO(bond).tx_hashtbl_lock)); + spin_lock(&(BOND_ALB_INFO(bond).tx_hashtbl_lock)); } static inline void _unlock_tx_hashtbl(struct bonding *bond) { - spin_unlock_bh(&(BOND_ALB_INFO(bond).tx_hashtbl_lock)); + spin_unlock(&(BOND_ALB_INFO(bond).tx_hashtbl_lock)); } /* Caller must hold tx_hashtbl lock */ @@ -305,12 +300,12 @@ static struct slave *tlb_choose_channel(struct bonding *bond, u32 hash_index, u3 /*********************** rlb specific functions ***************************/ static inline void _lock_rx_hashtbl(struct bonding *bond) { - spin_lock_bh(&(BOND_ALB_INFO(bond).rx_hashtbl_lock)); + spin_lock(&(BOND_ALB_INFO(bond).rx_hashtbl_lock)); } static inline void _unlock_rx_hashtbl(struct bonding *bond) { - spin_unlock_bh(&(BOND_ALB_INFO(bond).rx_hashtbl_lock)); + spin_unlock(&(BOND_ALB_INFO(bond).rx_hashtbl_lock)); } /* when an ARP REPLY is received from a client update its info @@ -469,13 +464,13 @@ static void rlb_clear_slave(struct bonding *bond, struct slave *slave) _unlock_rx_hashtbl(bond); - write_lock_bh(&bond->curr_slave_lock); + write_lock(&bond->curr_slave_lock); if (slave != bond->curr_active_slave) { rlb_teach_disabled_mac_on_primary(bond, slave->dev->dev_addr); } - write_unlock_bh(&bond->curr_slave_lock); + write_unlock(&bond->curr_slave_lock); } static void rlb_update_client(struct rlb_client_info *client_info) @@ -579,7 +574,7 @@ static void rlb_req_update_slave_clients(struct bonding *bond, struct slave *sla } /* mark all clients using src_ip to be updated */ -static void rlb_req_update_subnet_clients(struct bonding *bond, __be32 src_ip) +static void rlb_req_update_subnet_clients(struct bonding *bond, u32 src_ip) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); struct rlb_client_info *client_info; @@ -618,7 +613,7 @@ static void rlb_req_update_subnet_clients(struct bonding *bond, __be32 src_ip) static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - struct arp_pkt *arp = arp_pkt(skb); + struct arp_pkt *arp = (struct arp_pkt *)skb->nh.raw; struct slave *assigned_slave; struct rlb_client_info *client_info; u32 hash_index = 0; @@ -706,7 +701,7 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon */ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond) { - struct arp_pkt *arp = arp_pkt(skb); + struct arp_pkt *arp = (struct arp_pkt *)skb->nh.raw; struct slave *tx_slave = NULL; if (arp->op_code == __constant_htons(ARPOP_REPLY)) { @@ -895,8 +890,8 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[]) data = skb_put(skb, size); memcpy(data, &pkt, size); - skb_reset_mac_header(skb); - skb->nh.raw = skb->mac.raw + ETH_HLEN; + skb->mac.raw = data; + skb->nh.raw = data + ETH_HLEN; skb->protocol = pkt.type; skb->priority = TC_PRIO_CONTROL; skb->dev = slave->dev; @@ -956,34 +951,19 @@ static int alb_set_slave_mac_addr(struct slave *slave, u8 addr[], int hw) return 0; } -/* - * Swap MAC addresses between two slaves. - * - * Called with RTNL held, and no other locks. - * - */ - +/* Caller must hold bond lock for write or curr_slave_lock for write*/ static void alb_swap_mac_addr(struct bonding *bond, struct slave *slave1, struct slave *slave2) { + struct slave *disabled_slave = NULL; u8 tmp_mac_addr[ETH_ALEN]; + int slaves_state_differ; + + slaves_state_differ = (SLAVE_IS_OK(slave1) != SLAVE_IS_OK(slave2)); memcpy(tmp_mac_addr, slave1->dev->dev_addr, ETH_ALEN); alb_set_slave_mac_addr(slave1, slave2->dev->dev_addr, bond->alb_info.rlb_enabled); alb_set_slave_mac_addr(slave2, tmp_mac_addr, bond->alb_info.rlb_enabled); -} - -/* - * Send learning packets after MAC address swap. - * - * Called with RTNL and bond->lock held for read. - */ -static void alb_fasten_mac_swap(struct bonding *bond, struct slave *slave1, - struct slave *slave2) -{ - int slaves_state_differ = (SLAVE_IS_OK(slave1) != SLAVE_IS_OK(slave2)); - struct slave *disabled_slave = NULL; - /* fasten the change in the switch */ if (SLAVE_IS_OK(slave1)) { alb_send_learning_packets(slave1, slave1->dev->dev_addr); @@ -1056,9 +1036,7 @@ static void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *sla } if (found) { - /* locking: needs RTNL and nothing else */ alb_swap_mac_addr(bond, slave, tmp_slave); - alb_fasten_mac_swap(bond, slave, tmp_slave); } } } @@ -1281,15 +1259,14 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) struct ethhdr *eth_data; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); struct slave *tx_slave = NULL; - static __be32 ip_bcast; + static const u32 ip_bcast = 0xffffffff; int hash_size = 0; int do_tx_balance = 1; u32 hash_index = 0; - const u8 *hash_start = NULL; + u8 *hash_start = NULL; int res = 1; - ip_bcast = htonl(0xffffffff); - skb_reset_mac_header(skb); + skb->mac.raw = (unsigned char *)skb->data; eth_data = eth_hdr(skb); /* make sure that the curr_active_slave and the slaves list do @@ -1303,18 +1280,15 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) } switch (ntohs(skb->protocol)) { - case ETH_P_IP: { - const struct iphdr *iph = ip_hdr(skb); - + case ETH_P_IP: if ((memcmp(eth_data->h_dest, mac_bcast, ETH_ALEN) == 0) || - (iph->daddr == ip_bcast) || - (iph->protocol == IPPROTO_IGMP)) { + (skb->nh.iph->daddr == ip_bcast) || + (skb->nh.iph->protocol == IPPROTO_IGMP)) { do_tx_balance = 0; break; } - hash_start = (char *)&(iph->daddr); - hash_size = sizeof(iph->daddr); - } + hash_start = (char*)&(skb->nh.iph->daddr); + hash_size = sizeof(skb->nh.iph->daddr); break; case ETH_P_IPV6: if (memcmp(eth_data->h_dest, mac_bcast, ETH_ALEN) == 0) { @@ -1322,11 +1296,12 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) break; } - hash_start = (char *)&(ipv6_hdr(skb)->daddr); - hash_size = sizeof(ipv6_hdr(skb)->daddr); + hash_start = (char*)&(skb->nh.ipv6h->daddr); + hash_size = sizeof(skb->nh.ipv6h->daddr); break; case ETH_P_IPX: - if (ipx_hdr(skb)->ipx_checksum != IPX_NO_CHECKSUM) { + if (ipx_hdr(skb)->ipx_checksum != + __constant_htons(IPX_NO_CHECKSUM)) { /* something is wrong with this packet */ do_tx_balance = 0; break; @@ -1390,9 +1365,8 @@ out: return 0; } -void bond_alb_monitor(void *work_data) +void bond_alb_monitor(struct bonding *bond) { - struct bonding *bond = work_data; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); struct slave *slave; int i; @@ -1452,16 +1426,16 @@ void bond_alb_monitor(void *work_data) /* handle rlb stuff */ if (bond_info->rlb_enabled) { + /* the following code changes the promiscuity of the + * the curr_active_slave. It needs to be locked with a + * write lock to protect from other code that also + * sets the promiscuity. + */ + write_lock_bh(&bond->curr_slave_lock); + if (bond_info->primary_is_promisc && (++bond_info->rlb_promisc_timeout_counter >= RLB_PROMISC_TIMEOUT)) { - /* - * dev_set_promiscuity requires rtnl and - * nothing else. - */ - read_unlock(&bond->lock); - rtnl_lock(); - bond_info->rlb_promisc_timeout_counter = 0; /* If the primary was set to promiscuous mode @@ -1470,11 +1444,10 @@ void bond_alb_monitor(void *work_data) */ dev_set_promiscuity(bond->curr_active_slave->dev, -1); bond_info->primary_is_promisc = 0; - - rtnl_unlock(); - read_lock(&bond->lock); } + write_unlock_bh(&bond->curr_slave_lock); + if (bond_info->rlb_rebalance) { bond_info->rlb_rebalance = 0; rlb_rebalance(bond); @@ -1496,7 +1469,7 @@ void bond_alb_monitor(void *work_data) } re_arm: - queue_delayed_work(bond->wq, &bond->alb_work, alb_delta_in_ticks); + mod_timer(&(bond_info->alb_timer), jiffies + alb_delta_in_ticks); out: read_unlock(&bond->lock); } @@ -1517,11 +1490,11 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave) /* caller must hold the bond lock for write since the mac addresses * are compared and may be swapped. */ - read_lock(&bond->lock); + write_lock_bh(&bond->lock); res = alb_handle_addr_collision_on_attach(bond, slave); - read_unlock(&bond->lock); + write_unlock_bh(&bond->lock); if (res) { return res; @@ -1586,21 +1559,13 @@ void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char * Set the bond->curr_active_slave to @new_slave and handle * mac address swapping and promiscuity changes as needed. * - * If new_slave is NULL, caller must hold curr_slave_lock or - * bond->lock for write. - * - * If new_slave is not NULL, caller must hold RTNL, bond->lock for - * read and curr_slave_lock for write. Processing here may sleep, so - * no other locks may be held. + * Caller must hold bond curr_slave_lock for write (or bond lock for write) */ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave) { struct slave *swap_slave; int i; - if (new_slave) - ASSERT_RTNL(); - if (bond->curr_active_slave == new_slave) { return; } @@ -1633,19 +1598,6 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave } } - /* - * Arrange for swap_slave and new_slave to temporarily be - * ignored so we can mess with their MAC addresses without - * fear of interference from transmit activity. - */ - if (swap_slave) { - tlb_clear_slave(bond, swap_slave, 1); - } - tlb_clear_slave(bond, new_slave, 1); - - write_unlock_bh(&bond->curr_slave_lock); - read_unlock(&bond->lock); - /* curr_active_slave must be set before calling alb_swap_mac_addr */ if (swap_slave) { /* swap mac address */ @@ -1654,23 +1606,11 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave /* set the new_slave to the bond mac address */ alb_set_slave_mac_addr(new_slave, bond->dev->dev_addr, bond->alb_info.rlb_enabled); - } - - read_lock(&bond->lock); - - if (swap_slave) { - alb_fasten_mac_swap(bond, swap_slave, new_slave); - } else { /* fasten bond mac on new current slave */ alb_send_learning_packets(new_slave, bond->dev->dev_addr); } - - write_lock_bh(&bond->curr_slave_lock); } -/* - * Called with RTNL - */ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr) { struct bonding *bond = bond_dev->priv; @@ -1707,12 +1647,8 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr) } } - write_unlock_bh(&bond->curr_slave_lock); - read_unlock(&bond->lock); - if (swap_slave) { alb_swap_mac_addr(bond, swap_slave, bond->curr_active_slave); - alb_fasten_mac_swap(bond, swap_slave, bond->curr_active_slave); } else { alb_set_slave_mac_addr(bond->curr_active_slave, bond_dev->dev_addr, bond->alb_info.rlb_enabled); @@ -1724,9 +1660,6 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr) } } - read_lock(&bond->lock); - write_lock_bh(&bond->curr_slave_lock); - return 0; } diff --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h index 91bb8d15..28f2a2fd 100644 --- a/drivers/net/bonding/bond_alb.h +++ b/drivers/net/bonding/bond_alb.h @@ -60,8 +60,8 @@ struct tlb_client_info { * ------------------------------------------------------------------------- */ struct rlb_client_info { - __be32 ip_src; /* the server IP address */ - __be32 ip_dst; /* the client IP address */ + u32 ip_src; /* the server IP address */ + u32 ip_dst; /* the client IP address */ u8 mac_dst[ETH_ALEN]; /* the client MAC address */ u32 next; /* The next Hash table entry index */ u32 prev; /* The previous Hash table entry index */ @@ -125,7 +125,7 @@ void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave); void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char link); void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave); int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev); -void bond_alb_monitor(void *); +void bond_alb_monitor(struct bonding *bond); int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr); void bond_alb_clear_vlan(struct bonding *bond, unsigned short vlan_id); #endif /* __BOND_ALB_H__ */ diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 4e8048e0..19da415c 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -75,7 +75,6 @@ #include #include #include -#include #include #include "bonding.h" #include "bond_3ad.h" @@ -99,7 +98,6 @@ 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; -static int fail_over_mac = 0; struct bond_params bonding_defaults; module_param(max_bonds, int, 0); @@ -133,8 +131,6 @@ 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"); -module_param(fail_over_mac, int, 0); -MODULE_PARM_DESC(fail_over_mac, "For active-backup, do not set all slaves to the same MAC. 0 of off (default), 1 for on."); /*----------------------------- Global variables ----------------------------*/ @@ -148,7 +144,7 @@ static struct proc_dir_entry *bond_proc_dir = NULL; #endif extern struct rw_semaphore bonding_rwsem; -static __be32 arp_target[BOND_MAX_ARP_TARGETS] = { 0, } ; +static u32 arp_target[BOND_MAX_ARP_TARGETS] = { 0, } ; static int arp_ip_count = 0; static int bond_mode = BOND_MODE_ROUNDROBIN; static int xmit_hashtype= BOND_XMIT_POLICY_LAYER2; @@ -175,7 +171,6 @@ struct bond_parm_tbl bond_mode_tbl[] = { struct bond_parm_tbl xmit_hashtype_tbl[] = { { "layer2", BOND_XMIT_POLICY_LAYER2}, { "layer3+4", BOND_XMIT_POLICY_LAYER34}, -{ "layer2+3", BOND_XMIT_POLICY_LAYER23}, { NULL, -1}, }; @@ -190,11 +185,10 @@ struct bond_parm_tbl arp_validate_tbl[] = { /*-------------------------- Forward declarations ---------------------------*/ static void bond_send_gratuitous_arp(struct bonding *bond); -static void bond_deinit(struct net_device *bond_dev); /*---------------------------- General routines -----------------------------*/ -static const char *bond_mode_name(int mode) +const char *bond_mode_name(int mode) { switch (mode) { case BOND_MODE_ROUNDROBIN : @@ -1134,21 +1128,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) if (new_active) { bond_set_slave_active_flags(new_active); } - - /* when bonding does not set the slave MAC address, the bond MAC - * address is the one of the active slave. - */ - if (new_active && bond->params.fail_over_mac) - memcpy(bond->dev->dev_addr, new_active->dev->dev_addr, - new_active->dev->addr_len); - if (bond->curr_active_slave && - test_bit(__LINK_STATE_LINKWATCH_PENDING, - &bond->curr_active_slave->dev->state)) { - dprintk("delaying gratuitous arp on %s\n", - bond->curr_active_slave->dev->name); - bond->send_grat_arp = 1; - } else - bond_send_gratuitous_arp(bond); + bond_send_gratuitous_arp(bond); } } @@ -1245,8 +1225,7 @@ static void bond_detach_slave(struct bonding *bond, struct slave *slave) /*---------------------------------- IOCTL ----------------------------------*/ -static int bond_sethwaddr(struct net_device *bond_dev, - struct net_device *slave_dev) +int bond_sethwaddr(struct net_device *bond_dev, struct net_device *slave_dev) { dprintk("bond_dev=%p\n", bond_dev); dprintk("slave_dev=%p\n", slave_dev); @@ -1255,35 +1234,43 @@ static int bond_sethwaddr(struct net_device *bond_dev, return 0; } -#define BOND_VLAN_FEATURES \ - (NETIF_F_VLAN_CHALLENGED | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX | \ - NETIF_F_HW_VLAN_FILTER) +#define BOND_INTERSECT_FEATURES \ + (NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_TSO | NETIF_F_UFO) /* * Compute the common dev->feature set available to all slaves. Some - * feature bits are managed elsewhere, so preserve those feature bits - * on the master device. + * feature bits are managed elsewhere, so preserve feature bits set on + * master device that are not part of the examined set. */ 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 long features = bond_dev->features; unsigned short max_hard_header_len = ETH_HLEN; int i; - features &= ~(NETIF_F_ALL_CSUM | BOND_VLAN_FEATURES); - features |= NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | - NETIF_F_GSO_MASK | NETIF_F_NO_CSUM; - bond_for_each_slave(bond, slave, i) { - features = netdev_compute_features(features, - slave->dev->features); + 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; } - features |= (bond_dev->features & BOND_VLAN_FEATURES); + if ((features & NETIF_F_SG) && + !(features & NETIF_F_ALL_CSUM)) + features &= ~NETIF_F_SG; + + /* + * features will include NETIF_F_TSO (NETIF_F_UFO) iff all + * slave devices support NETIF_F_TSO (NETIF_F_UFO), which + * implies that all slaves also support scatter-gather + * (NETIF_F_SG), which implies that features also includes + * NETIF_F_SG. So no need to check whether we have an + * illegal combination of NETIF_F_{TSO,UFO} and + * !NETIF_F_SG + */ + + features |= (bond_dev->features & ~BOND_INTERSECT_FEATURES); bond_dev->features = features; bond_dev->hard_header_len = max_hard_header_len; @@ -1365,22 +1352,13 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) } if (slave_dev->set_mac_address == NULL) { - if (bond->slave_cnt == 0) { - printk(KERN_WARNING DRV_NAME - ": %s: Warning: The first slave device " - "specified does not support setting the MAC " - "address. Enabling the fail_over_mac option.", - bond_dev->name); - bond->params.fail_over_mac = 1; - } else if (!bond->params.fail_over_mac) { - printk(KERN_ERR DRV_NAME - ": %s: Error: The slave device specified " - "does not support setting the MAC address, " - "but fail_over_mac is not enabled.\n" - , bond_dev->name); - res = -EOPNOTSUPP; - goto err_undo_flags; - } + printk(KERN_ERR DRV_NAME + ": %s: Error: The slave device you specified does " + "not support setting the MAC address. " + "Your kernel likely does not support slave " + "devices.\n", bond_dev->name); + res = -EOPNOTSUPP; + goto err_undo_flags; } if (slave_dev->get_stats == NULL) { @@ -1408,25 +1386,18 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) */ memcpy(new_slave->perm_hwaddr, slave_dev->dev_addr, ETH_ALEN); - if (!bond->params.fail_over_mac) { - /* - * Set slave to master's mac address. The application already - * set the master's mac address to that of the first slave - */ - memcpy(addr.sa_data, bond_dev->dev_addr, bond_dev->addr_len); - addr.sa_family = slave_dev->type; - res = dev_set_mac_address(slave_dev, &addr); - if (res) { - dprintk("Error %d calling set_mac_address\n", res); - goto err_free; - } - } - - res = netdev_set_master(slave_dev, bond_dev); + /* + * Set slave to master's mac address. The application already + * set the master's mac address to that of the first slave + */ + memcpy(addr.sa_data, bond_dev->dev_addr, bond_dev->addr_len); + addr.sa_family = slave_dev->type; + res = dev_set_mac_address(slave_dev, &addr); if (res) { - dprintk("Error %d calling netdev_set_master\n", res); - goto err_close; + dprintk("Error %d calling set_mac_address\n", res); + goto err_free; } + /* open the slave since the application closed it */ res = dev_open(slave_dev); if (res) { @@ -1434,6 +1405,12 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) goto err_restore_mac; } + res = netdev_set_master(slave_dev, bond_dev); + if (res) { + dprintk("Error %d calling netdev_set_master\n", res); + goto err_close; + } + new_slave->dev = slave_dev; slave_dev->priv_flags |= IFF_BONDING; @@ -1593,7 +1570,15 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) case BOND_MODE_TLB: case BOND_MODE_ALB: new_slave->state = BOND_STATE_ACTIVE; - bond_set_slave_inactive_flags(new_slave); + if ((!bond->curr_active_slave) && + (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); + } else { + bond_set_slave_inactive_flags(new_slave); + } break; default: dprintk("This slave is always active in trunk mode\n"); @@ -1636,11 +1621,9 @@ err_close: dev_close(slave_dev); err_restore_mac: - if (!bond->params.fail_over_mac) { - memcpy(addr.sa_data, new_slave->perm_hwaddr, ETH_ALEN); - addr.sa_family = slave_dev->type; - dev_set_mac_address(slave_dev, &addr); - } + memcpy(addr.sa_data, new_slave->perm_hwaddr, ETH_ALEN); + addr.sa_family = slave_dev->type; + dev_set_mac_address(slave_dev, &addr); err_free: kfree(new_slave); @@ -1754,23 +1737,9 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) bond_alb_deinit_slave(bond, slave); } - if (oldcurrent == slave) { - /* - * Note that we hold RTNL over this sequence, so there - * is no concern that another slave add/remove event - * will interfere. - */ - write_unlock_bh(&bond->lock); - read_lock(&bond->lock); - write_lock_bh(&bond->curr_slave_lock); - + if (oldcurrent == slave) bond_select_active_slave(bond); - write_unlock_bh(&bond->curr_slave_lock); - read_unlock(&bond->lock); - write_lock_bh(&bond->lock); - } - if (bond->slave_cnt == 0) { bond_set_carrier(bond); @@ -1832,12 +1801,10 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) /* close slave before restoring its mac address */ dev_close(slave_dev); - if (!bond->params.fail_over_mac) { - /* restore original ("permanent") mac address */ - memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN); - addr.sa_family = slave_dev->type; - dev_set_mac_address(slave_dev, &addr); - } + /* restore original ("permanent") mac address */ + memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN); + addr.sa_family = slave_dev->type; + dev_set_mac_address(slave_dev, &addr); slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB | IFF_SLAVE_INACTIVE | IFF_BONDING | @@ -1848,35 +1815,6 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) return 0; /* deletion OK */ } -/* -* Destroy a bonding device. -* Must be under rtnl_lock when this function is called. -*/ -void bond_destroy(struct bonding *bond) -{ - bond_deinit(bond->dev); - bond_destroy_sysfs_entry(bond); - unregister_netdevice(bond->dev); -} - -/* -* First release a slave and than destroy the bond if no more slaves iare left. -* Must be under rtnl_lock when this function is called. -*/ -int bond_release_and_destroy(struct net_device *bond_dev, struct net_device *slave_dev) -{ - struct bonding *bond = bond_dev->priv; - int ret; - - ret = bond_release(bond_dev, slave_dev); - if ((ret == 0) && (bond->slave_cnt == 0)) { - printk(KERN_INFO DRV_NAME ": %s: destroying bond %s.\n", - bond_dev->name, bond_dev->name); - bond_destroy(bond); - } - return ret; -} - /* * This function releases all slaves. */ @@ -1953,12 +1891,10 @@ static int bond_release_all(struct net_device *bond_dev) /* close slave before restoring its mac address */ dev_close(slave_dev); - if (!bond->params.fail_over_mac) { - /* restore original ("permanent") mac address*/ - memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN); - addr.sa_family = slave_dev->type; - dev_set_mac_address(slave_dev, &addr); - } + /* restore original ("permanent") mac address*/ + memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN); + addr.sa_family = slave_dev->type; + dev_set_mac_address(slave_dev, &addr); slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB | IFF_SLAVE_INACTIVE); @@ -2026,19 +1962,16 @@ static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_devi return -EINVAL; } - read_lock(&bond->lock); + write_lock_bh(&bond->lock); - read_lock(&bond->curr_slave_lock); old_active = bond->curr_active_slave; - read_unlock(&bond->curr_slave_lock); - new_active = bond_get_slave_by_dev(bond, slave_dev); /* * Changing to the current active: do nothing; return success. */ if (new_active && (new_active == old_active)) { - read_unlock(&bond->lock); + write_unlock_bh(&bond->lock); return 0; } @@ -2046,14 +1979,12 @@ static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_devi (old_active) && (new_active->link == BOND_LINK_UP) && IS_UP(new_active->dev)) { - write_lock_bh(&bond->curr_slave_lock); bond_change_active_slave(bond, new_active); - write_unlock_bh(&bond->curr_slave_lock); } else { res = -EINVAL; } - read_unlock(&bond->lock); + write_unlock_bh(&bond->lock); return res; } @@ -2065,9 +1996,9 @@ static int bond_info_query(struct net_device *bond_dev, struct ifbond *info) info->bond_mode = bond->params.mode; info->miimon = bond->params.miimon; - read_lock(&bond->lock); + read_lock_bh(&bond->lock); info->num_slaves = bond->slave_cnt; - read_unlock(&bond->lock); + read_unlock_bh(&bond->lock); return 0; } @@ -2082,7 +2013,7 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in return -ENODEV; } - read_lock(&bond->lock); + read_lock_bh(&bond->lock); bond_for_each_slave(bond, slave, i) { if (i == (int)info->slave_id) { @@ -2091,7 +2022,7 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in } } - read_unlock(&bond->lock); + read_unlock_bh(&bond->lock); if (found) { strcpy(info->slave_name, slave->dev->name); @@ -2107,25 +2038,26 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in /*-------------------------------- Monitoring -------------------------------*/ -/* - * if !have_locks, return nonzero if a failover is necessary. if - * have_locks, do whatever failover activities are needed. - * - * This is to separate the inspection and failover steps for locking - * purposes; failover requires rtnl, but acquiring it for every - * inspection is undesirable, so a wrapper first does inspection, and - * the acquires the necessary locks and calls again to perform - * failover if needed. Since all locks are dropped, a complete - * restart is needed between calls. - */ -static int __bond_mii_monitor(struct bonding *bond, int have_locks) +/* this function is called regularly to monitor each slave's link. */ +void bond_mii_monitor(struct net_device *bond_dev) { + struct bonding *bond = bond_dev->priv; struct slave *slave, *oldcurrent; int do_failover = 0; + int delta_in_ticks; int i; - if (bond->slave_cnt == 0) + read_lock(&bond->lock); + + delta_in_ticks = (bond->params.miimon * HZ) / 1000; + + if (bond->kill_timers) { goto out; + } + + if (bond->slave_cnt == 0) { + goto re_arm; + } /* we will try to read the link status of each of our slaves, and * set their IFF_RUNNING flag appropriately. For each slave not @@ -2133,17 +2065,6 @@ static int __bond_mii_monitor(struct bonding *bond, int have_locks) * program could monitor the link itself if needed. */ - if (bond->send_grat_arp) { - if (bond->curr_active_slave && test_bit(__LINK_STATE_LINKWATCH_PENDING, - &bond->curr_active_slave->dev->state)) - dprintk("Needs to send gratuitous arp but not yet\n"); - else { - dprintk("sending delayed gratuitous arp on on %s\n", - bond->curr_active_slave->dev->name); - bond_send_gratuitous_arp(bond); - bond->send_grat_arp = 0; - } - } read_lock(&bond->curr_slave_lock); oldcurrent = bond->curr_active_slave; read_unlock(&bond->curr_slave_lock); @@ -2159,11 +2080,7 @@ static int __bond_mii_monitor(struct bonding *bond, int have_locks) switch (slave->link) { case BOND_LINK_UP: /* the link was up */ if (link_state == BMSR_LSTATUS) { - if (!oldcurrent) { - if (!have_locks) - return 1; - do_failover = 1; - } + /* link stays up, nothing more to do */ break; } else { /* link going down */ slave->link = BOND_LINK_FAIL; @@ -2178,7 +2095,7 @@ static int __bond_mii_monitor(struct bonding *bond, int have_locks) ": %s: link status down for %s " "interface %s, disabling it in " "%d ms.\n", - bond->dev->name, + bond_dev->name, IS_UP(slave_dev) ? ((bond->params.mode == BOND_MODE_ACTIVEBACKUP) ? ((slave == oldcurrent) @@ -2196,9 +2113,6 @@ static int __bond_mii_monitor(struct bonding *bond, int have_locks) if (link_state != BMSR_LSTATUS) { /* link stays down */ if (slave->delay <= 0) { - if (!have_locks) - return 1; - /* link down for too long time */ slave->link = BOND_LINK_DOWN; @@ -2214,7 +2128,7 @@ static int __bond_mii_monitor(struct bonding *bond, int have_locks) ": %s: link status definitely " "down for interface %s, " "disabling it\n", - bond->dev->name, + bond_dev->name, slave_dev->name); /* notify ad that the link status has changed */ @@ -2240,7 +2154,7 @@ static int __bond_mii_monitor(struct bonding *bond, int have_locks) printk(KERN_INFO DRV_NAME ": %s: link status up again after %d " "ms for interface %s.\n", - bond->dev->name, + bond_dev->name, (bond->params.downdelay - slave->delay) * bond->params.miimon, slave_dev->name); } @@ -2260,7 +2174,7 @@ static int __bond_mii_monitor(struct bonding *bond, int have_locks) ": %s: link status up for " "interface %s, enabling it " "in %d ms.\n", - bond->dev->name, + bond_dev->name, slave_dev->name, bond->params.updelay * bond->params.miimon); } @@ -2276,15 +2190,12 @@ static int __bond_mii_monitor(struct bonding *bond, int have_locks) printk(KERN_INFO DRV_NAME ": %s: link status down again after %d " "ms for interface %s.\n", - bond->dev->name, + bond_dev->name, (bond->params.updelay - slave->delay) * bond->params.miimon, slave_dev->name); } else { /* link stays up */ if (slave->delay == 0) { - if (!have_locks) - return 1; - /* now the link has been up for long time enough */ slave->link = BOND_LINK_UP; slave->jiffies = jiffies; @@ -2303,7 +2214,7 @@ static int __bond_mii_monitor(struct bonding *bond, int have_locks) printk(KERN_INFO DRV_NAME ": %s: link status definitely " "up for interface %s.\n", - bond->dev->name, + bond_dev->name, slave_dev->name); /* notify ad that the link status has changed */ @@ -2329,7 +2240,7 @@ static int __bond_mii_monitor(struct bonding *bond, int have_locks) /* Should not happen */ printk(KERN_ERR DRV_NAME ": %s: Error: %s Illegal value (link=%d)\n", - bond->dev->name, + bond_dev->name, slave->dev->name, slave->link); goto out; @@ -2350,53 +2261,24 @@ static int __bond_mii_monitor(struct bonding *bond, int have_locks) } /* end of for */ if (do_failover) { - ASSERT_RTNL(); - - write_lock_bh(&bond->curr_slave_lock); + write_lock(&bond->curr_slave_lock); bond_select_active_slave(bond); - write_unlock_bh(&bond->curr_slave_lock); - + write_unlock(&bond->curr_slave_lock); } else bond_set_carrier(bond); -out: - return 0; -} - -/* - * bond_mii_monitor - * - * Really a wrapper that splits the mii monitor into two phases: an - * inspection, then (if inspection indicates something needs to be - * done) an acquisition of appropriate locks followed by another pass - * to implement whatever link state changes are indicated. - */ -void bond_mii_monitor(void *work_data) -{ - struct bonding *bond = work_data; - unsigned long delay; - - read_lock(&bond->lock); - if (bond->kill_timers) { - read_unlock(&bond->lock); - return; - } - if (__bond_mii_monitor(bond, 0)) { - read_unlock(&bond->lock); - rtnl_lock(); - read_lock(&bond->lock); - __bond_mii_monitor(bond, 1); - rtnl_unlock(); +re_arm: + if (bond->params.miimon) { + mod_timer(&bond->mii_timer, jiffies + delta_in_ticks); } - - delay = ((bond->params.miimon * HZ) / 1000) ? : 1; +out: read_unlock(&bond->lock); - queue_delayed_work(bond->wq, &bond->mii_work, delay); } -static __be32 bond_glean_dev_ip(struct net_device *dev) + +static u32 bond_glean_dev_ip(struct net_device *dev) { struct in_device *idev; struct in_ifaddr *ifa; @@ -2439,7 +2321,7 @@ static int bond_has_ip(struct bonding *bond) return 0; } -static int bond_has_this_ip(struct bonding *bond, __be32 ip) +static int bond_has_this_ip(struct bonding *bond, u32 ip) { struct vlan_entry *vlan, *vlan_next; @@ -2463,7 +2345,7 @@ static int bond_has_this_ip(struct bonding *bond, __be32 ip) * switches in VLAN mode (especially if ports are configured as * "native" to a VLAN) might not pass non-tagged frames. */ -static void bond_arp_send(struct net_device *slave_dev, int arp_op, __be32 dest_ip, __be32 src_ip, unsigned short vlan_id) +static void bond_arp_send(struct net_device *slave_dev, int arp_op, u32 dest_ip, u32 src_ip, unsigned short vlan_id) { struct sk_buff *skb; @@ -2491,7 +2373,7 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, __be32 dest_ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) { int i, vlan_id, rv; - __be32 *targets = bond->params.arp_targets; + u32 *targets = bond->params.arp_targets; struct vlan_entry *vlan, *vlan_next; struct net_device *vlan_dev; struct flowi fl; @@ -2584,7 +2466,7 @@ static void bond_send_gratuitous_arp(struct bonding *bond) if (bond->master_ip) { bond_arp_send(slave->dev, ARPOP_REPLY, bond->master_ip, - bond->master_ip, 0); + bond->master_ip, 0); } list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { @@ -2596,10 +2478,10 @@ static void bond_send_gratuitous_arp(struct bonding *bond) } } -static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32 sip, __be32 tip) +static void bond_validate_arp(struct bonding *bond, struct slave *slave, u32 sip, u32 tip) { int i; - __be32 *targets = bond->params.arp_targets; + u32 *targets = bond->params.arp_targets; targets = bond->params.arp_targets; for (i = 0; (i < BOND_MAX_ARP_TARGETS) && targets[i]; i++) { @@ -2621,7 +2503,7 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack struct slave *slave; struct bonding *bond; unsigned char *arp_ptr; - __be32 sip, tip; + u32 sip, tip; if (!(dev->priv_flags & IFF_BONDING) || !(dev->flags & IFF_MASTER)) goto out; @@ -2643,7 +2525,7 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack (2 * sizeof(u32))))) goto out_unlock; - arp = arp_hdr(skb); + arp = skb->nh.arph; if (arp->ar_hln != dev->addr_len || skb->pkt_type == PACKET_OTHERHOST || skb->pkt_type == PACKET_LOOPBACK || @@ -2690,9 +2572,9 @@ out: * arp is transmitted to generate traffic. see activebackup_arp_monitor for * arp monitoring in active backup mode. */ -void bond_loadbalance_arp_mon(void *work_data) +void bond_loadbalance_arp_mon(struct net_device *bond_dev) { - struct bonding *bond = work_data; + struct bonding *bond = bond_dev->priv; struct slave *slave, *oldcurrent; int do_failover = 0; int delta_in_ticks; @@ -2724,8 +2606,8 @@ void bond_loadbalance_arp_mon(void *work_data) */ bond_for_each_slave(bond, slave, i) { if (slave->link != BOND_LINK_UP) { - if (time_before_eq(jiffies, slave->dev->trans_start + delta_in_ticks) && - time_before_eq(jiffies, slave->dev->last_rx + delta_in_ticks)) { + if (((jiffies - slave->dev->trans_start) <= delta_in_ticks) && + ((jiffies - slave->dev->last_rx) <= delta_in_ticks)) { slave->link = BOND_LINK_UP; slave->state = BOND_STATE_ACTIVE; @@ -2739,13 +2621,13 @@ void bond_loadbalance_arp_mon(void *work_data) printk(KERN_INFO DRV_NAME ": %s: link status definitely " "up for interface %s, ", - bond->dev->name, + bond_dev->name, slave->dev->name); do_failover = 1; } else { printk(KERN_INFO DRV_NAME ": %s: interface %s is now up\n", - bond->dev->name, + bond_dev->name, slave->dev->name); } } @@ -2756,8 +2638,8 @@ void bond_loadbalance_arp_mon(void *work_data) * when the source ip is 0, so don't take the link down * if we don't know our ip yet */ - if (time_after_eq(jiffies, slave->dev->trans_start + 2*delta_in_ticks) || - (time_after_eq(jiffies, slave->dev->last_rx + 2*delta_in_ticks) && + if (((jiffies - slave->dev->trans_start) >= (2*delta_in_ticks)) || + (((jiffies - slave->dev->last_rx) >= (2*delta_in_ticks)) && bond_has_ip(bond))) { slave->link = BOND_LINK_DOWN; @@ -2769,7 +2651,7 @@ void bond_loadbalance_arp_mon(void *work_data) printk(KERN_INFO DRV_NAME ": %s: interface %s is now down.\n", - bond->dev->name, + bond_dev->name, slave->dev->name); if (slave == oldcurrent) { @@ -2791,19 +2673,17 @@ void bond_loadbalance_arp_mon(void *work_data) } if (do_failover) { - rtnl_lock(); - write_lock_bh(&bond->curr_slave_lock); + write_lock(&bond->curr_slave_lock); bond_select_active_slave(bond); - write_unlock_bh(&bond->curr_slave_lock); - rtnl_unlock(); - + write_unlock(&bond->curr_slave_lock); } re_arm: - if (bond->params.arp_interval) - queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks); + if (bond->params.arp_interval) { + mod_timer(&bond->arp_timer, jiffies + delta_in_ticks); + } out: read_unlock(&bond->lock); } @@ -2823,9 +2703,9 @@ out: * may have received. * see loadbalance_arp_monitor for arp monitoring in load balancing mode */ -void bond_activebackup_arp_mon(void *work_data) +void bond_activebackup_arp_mon(struct net_device *bond_dev) { - struct bonding *bond = work_data; + struct bonding *bond = bond_dev->priv; struct slave *slave; int delta_in_ticks; int i; @@ -2849,17 +2729,15 @@ void bond_activebackup_arp_mon(void *work_data) */ bond_for_each_slave(bond, slave, i) { if (slave->link != BOND_LINK_UP) { - if (time_before_eq(jiffies, - slave_last_rx(bond, slave) + delta_in_ticks)) { + if ((jiffies - slave_last_rx(bond, slave)) <= + delta_in_ticks) { slave->link = BOND_LINK_UP; - rtnl_lock(); - - write_lock_bh(&bond->curr_slave_lock); + write_lock(&bond->curr_slave_lock); if ((!bond->curr_active_slave) && - time_before_eq(jiffies, slave->dev->trans_start + delta_in_ticks)) { + ((jiffies - slave->dev->trans_start) <= delta_in_ticks)) { bond_change_active_slave(bond, slave); bond->current_arp_slave = NULL; } else if (bond->curr_active_slave != slave) { @@ -2879,26 +2757,25 @@ void bond_activebackup_arp_mon(void *work_data) printk(KERN_INFO DRV_NAME ": %s: %s is up and now the " "active interface\n", - bond->dev->name, + bond_dev->name, slave->dev->name); netif_carrier_on(bond->dev); } else { printk(KERN_INFO DRV_NAME ": %s: backup interface %s is " "now up\n", - bond->dev->name, + bond_dev->name, slave->dev->name); } - write_unlock_bh(&bond->curr_slave_lock); - rtnl_unlock(); + write_unlock(&bond->curr_slave_lock); } } else { read_lock(&bond->curr_slave_lock); if ((slave != bond->curr_active_slave) && (!bond->current_arp_slave) && - (time_after_eq(jiffies, slave_last_rx(bond, slave) + 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 @@ -2923,7 +2800,7 @@ void bond_activebackup_arp_mon(void *work_data) printk(KERN_INFO DRV_NAME ": %s: backup interface %s is now down\n", - bond->dev->name, + bond_dev->name, slave->dev->name); } else { read_unlock(&bond->curr_slave_lock); @@ -2944,10 +2821,10 @@ void bond_activebackup_arp_mon(void *work_data) * before being taken out. if a primary is being used, check * if it is up and needs to take over as the curr_active_slave */ - if ((time_after_eq(jiffies, slave->dev->trans_start + 2*delta_in_ticks) || - (time_after_eq(jiffies, slave_last_rx(bond, slave) + 2*delta_in_ticks) && - bond_has_ip(bond))) && - time_after_eq(jiffies, slave->jiffies + 2*delta_in_ticks)) { + if ((((jiffies - slave->dev->trans_start) >= (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)) { slave->link = BOND_LINK_DOWN; @@ -2958,18 +2835,15 @@ void bond_activebackup_arp_mon(void *work_data) printk(KERN_INFO DRV_NAME ": %s: link status down for active interface " "%s, disabling it\n", - bond->dev->name, + bond_dev->name, slave->dev->name); - rtnl_lock(); - write_lock_bh(&bond->curr_slave_lock); + write_lock(&bond->curr_slave_lock); bond_select_active_slave(bond); slave = bond->curr_active_slave; - write_unlock_bh(&bond->curr_slave_lock); - - rtnl_unlock(); + write_unlock(&bond->curr_slave_lock); bond->current_arp_slave = slave; @@ -2983,17 +2857,14 @@ void bond_activebackup_arp_mon(void *work_data) printk(KERN_INFO DRV_NAME ": %s: changing from interface %s to primary " "interface %s\n", - bond->dev->name, + bond_dev->name, slave->dev->name, bond->primary_slave->dev->name); /* primary is up so switch to it */ - rtnl_lock(); - write_lock_bh(&bond->curr_slave_lock); + write_lock(&bond->curr_slave_lock); bond_change_active_slave(bond, bond->primary_slave); - write_unlock_bh(&bond->curr_slave_lock); - - rtnl_unlock(); + write_unlock(&bond->curr_slave_lock); slave = bond->primary_slave; slave->jiffies = jiffies; @@ -3050,7 +2921,7 @@ void bond_activebackup_arp_mon(void *work_data) printk(KERN_INFO DRV_NAME ": %s: backup interface %s is " "now down.\n", - bond->dev->name, + bond_dev->name, slave->dev->name); } } @@ -3059,7 +2930,7 @@ void bond_activebackup_arp_mon(void *work_data) re_arm: if (bond->params.arp_interval) { - queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks); + mod_timer(&bond->arp_timer, jiffies + delta_in_ticks); } out: read_unlock(&bond->lock); @@ -3080,7 +2951,7 @@ static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos) /* make sure the bond won't be taken away */ read_lock(&dev_base_lock); - read_lock(&bond->lock); + read_lock_bh(&bond->lock); if (*pos == 0) { return SEQ_START_TOKEN; @@ -3114,7 +2985,7 @@ static void bond_info_seq_stop(struct seq_file *seq, void *v) { struct bonding *bond = seq->private; - read_unlock(&bond->lock); + read_unlock_bh(&bond->lock); read_unlock(&dev_base_lock); } @@ -3129,15 +3000,9 @@ static void bond_info_show_master(struct seq_file *seq) curr = bond->curr_active_slave; read_unlock(&bond->curr_slave_lock); - seq_printf(seq, "Bonding Mode: %s", + seq_printf(seq, "Bonding Mode: %s\n", bond_mode_name(bond->params.mode)); - if (bond->params.mode == BOND_MODE_ACTIVEBACKUP && - bond->params.fail_over_mac) - seq_printf(seq, " (fail_over_mac)"); - - seq_printf(seq, "\n"); - if (bond->params.mode == BOND_MODE_XOR || bond->params.mode == BOND_MODE_8023AD) { seq_printf(seq, "Transmit Hash Policy: %s (%d)\n", @@ -3437,11 +3302,6 @@ static int bond_slave_netdev_event(unsigned long event, struct net_device *slave * ... Or is it this? */ break; - case NETDEV_GOING_DOWN: - dprintk("slave %s is going down\n", slave_dev->name); - if (bond->setup_by_slave) - bond_release_and_destroy(bond_dev, slave_dev); - break; case NETDEV_CHANGEMTU: /* * TODO: Should slaves be allowed to @@ -3609,25 +3469,7 @@ void bond_unregister_arp(struct bonding *bond) /*---------------------------- Hashing Policies -----------------------------*/ /* - * Hash for the output device based upon layer 2 and layer 3 data. If - * the packet is not IP mimic bond_xmit_hash_policy_l2() - */ -static int bond_xmit_hash_policy_l23(struct sk_buff *skb, - struct net_device *bond_dev, int count) -{ - struct ethhdr *data = (struct ethhdr *)skb->data; - struct iphdr *iph = ip_hdr(skb); - - if (skb->protocol == __constant_htons(ETH_P_IP)) { - return ((ntohl(iph->saddr ^ iph->daddr) & 0xffff) ^ - (data->h_dest[5] ^ bond_dev->dev_addr[5])) % count; - } - - return (data->h_dest[5] ^ bond_dev->dev_addr[5]) % count; -} - -/* - * Hash for the output device based upon layer 3 and layer 4 data. If + * Hash for the the output device based upon layer 3 and layer 4 data. If * the packet is a frag or not TCP or UDP, just use layer 3 data. If it is * altogether not IP, mimic bond_xmit_hash_policy_l2() */ @@ -3635,15 +3477,15 @@ static int bond_xmit_hash_policy_l34(struct sk_buff *skb, struct net_device *bond_dev, int count) { struct ethhdr *data = (struct ethhdr *)skb->data; - struct iphdr *iph = ip_hdr(skb); - __be16 *layer4hdr = (__be16 *)((u32 *)iph + iph->ihl); + struct iphdr *iph = skb->nh.iph; + u16 *layer4hdr = (u16 *)((u32 *)iph + iph->ihl); int layer4_xor = 0; if (skb->protocol == __constant_htons(ETH_P_IP)) { if (!(iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) && (iph->protocol == IPPROTO_TCP || iph->protocol == IPPROTO_UDP)) { - layer4_xor = ntohs((*layer4hdr ^ *(layer4hdr + 1))); + layer4_xor = htons((*layer4hdr ^ *(layer4hdr + 1))); } return (layer4_xor ^ ((ntohl(iph->saddr ^ iph->daddr)) & 0xffff)) % count; @@ -3669,11 +3511,15 @@ static int bond_xmit_hash_policy_l2(struct sk_buff *skb, static int bond_open(struct net_device *bond_dev) { struct bonding *bond = bond_dev->priv; + struct timer_list *mii_timer = &bond->mii_timer; + struct timer_list *arp_timer = &bond->arp_timer; bond->kill_timers = 0; if ((bond->params.mode == BOND_MODE_TLB) || (bond->params.mode == BOND_MODE_ALB)) { + struct timer_list *alb_timer = &(BOND_ALB_INFO(bond).alb_timer); + /* bond_alb_initialize must be called before the timer * is started. */ @@ -3682,33 +3528,44 @@ static int bond_open(struct net_device *bond_dev) return -1; } - INIT_WORK(&bond->alb_work, bond_alb_monitor, (void *)bond); - queue_delayed_work(bond->wq, &bond->alb_work, 0); + init_timer(alb_timer); + alb_timer->expires = jiffies + 1; + alb_timer->data = (unsigned long)bond; + alb_timer->function = (void *)&bond_alb_monitor; + add_timer(alb_timer); } if (bond->params.miimon) { /* link check interval, in milliseconds. */ - INIT_WORK(&bond->mii_work, bond_mii_monitor, (void *)bond); - queue_delayed_work(bond->wq, &bond->mii_work, 0); + init_timer(mii_timer); + mii_timer->expires = jiffies + 1; + mii_timer->data = (unsigned long)bond_dev; + mii_timer->function = (void *)&bond_mii_monitor; + add_timer(mii_timer); } if (bond->params.arp_interval) { /* arp interval, in milliseconds. */ - if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) - INIT_WORK(&bond->arp_work, - bond_activebackup_arp_mon, - (void *)bond); - else - INIT_WORK(&bond->arp_work, - bond_loadbalance_arp_mon, - (void *)bond); - - queue_delayed_work(bond->wq, &bond->arp_work, 0); + init_timer(arp_timer); + arp_timer->expires = jiffies + 1; + arp_timer->data = (unsigned long)bond_dev; + if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) { + arp_timer->function = (void *)&bond_activebackup_arp_mon; + } else { + arp_timer->function = (void *)&bond_loadbalance_arp_mon; + } if (bond->params.arp_validate) bond_register_arp(bond); + + add_timer(arp_timer); } if (bond->params.mode == BOND_MODE_8023AD) { - INIT_WORK(&bond->ad_work, bond_3ad_state_machine_handler, (void *)bond); - queue_delayed_work(bond->wq, &bond->ad_work, 0); + struct timer_list *ad_timer = &(BOND_AD_INFO(bond).ad_timer); + init_timer(ad_timer); + ad_timer->expires = jiffies + 1; + ad_timer->data = (unsigned long)bond; + ad_timer->function = (void *)&bond_3ad_state_machine_handler; + add_timer(ad_timer); + /* register to receive LACPDUs */ bond_register_lacpdu(bond); } @@ -3736,21 +3593,25 @@ static int bond_close(struct net_device *bond_dev) write_unlock_bh(&bond->lock); + /* del_timer_sync must run without holding the bond->lock + * because a running timer might be trying to hold it too + */ + if (bond->params.miimon) { /* link check interval, in milliseconds. */ - cancel_delayed_work(&bond->mii_work); + del_timer_sync(&bond->mii_timer); } if (bond->params.arp_interval) { /* arp interval, in milliseconds. */ - cancel_delayed_work(&bond->arp_work); + del_timer_sync(&bond->arp_timer); } switch (bond->params.mode) { case BOND_MODE_8023AD: - cancel_delayed_work(&bond->ad_work); + del_timer_sync(&(BOND_AD_INFO(bond).ad_timer)); break; case BOND_MODE_TLB: case BOND_MODE_ALB: - cancel_delayed_work(&bond->alb_work); + del_timer_sync(&(BOND_ALB_INFO(bond).alb_timer)); break; default: break; @@ -3850,13 +3711,13 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd if (mii->reg_num == 1) { struct bonding *bond = bond_dev->priv; mii->val_out = 0; - read_lock(&bond->lock); + read_lock_bh(&bond->lock); read_lock(&bond->curr_slave_lock); if (netif_carrier_ok(bond->dev)) { mii->val_out = BMSR_LSTATUS; } read_unlock(&bond->curr_slave_lock); - read_unlock(&bond->lock); + read_unlock_bh(&bond->lock); } return 0; @@ -4073,13 +3934,6 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr) dprintk("bond=%p, name=%s\n", bond, (bond_dev ? bond_dev->name : "None")); - /* - * If fail_over_mac is enabled, do nothing and return success. - * Returning an error causes ifenslave to fail. - */ - if (bond->params.fail_over_mac) - return 0; - if (!is_valid_ether_addr(sa->sa_data)) { return -EADDRNOTAVAIL; } @@ -4148,7 +4002,8 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev { struct bonding *bond = bond_dev->priv; struct slave *slave, *start_at; - int i, slave_no, res = 1; + int i; + int res = 1; read_lock(&bond->lock); @@ -4156,29 +4011,29 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev goto out; } - /* - * Concurrent TX may collide on rr_tx_counter; we accept that - * as being rare enough not to justify using an atomic op here - */ - slave_no = bond->rr_tx_counter++ % bond->slave_cnt; + read_lock(&bond->curr_slave_lock); + slave = start_at = bond->curr_active_slave; + read_unlock(&bond->curr_slave_lock); - bond_for_each_slave(bond, slave, i) { - slave_no--; - if (slave_no < 0) { - break; - } + if (!slave) { + goto out; } - start_at = slave; bond_for_each_slave_from(bond, slave, i, start_at) { if (IS_UP(slave->dev) && (slave->link == BOND_LINK_UP) && (slave->state == BOND_STATE_ACTIVE)) { res = bond_dev_queue_xmit(bond, skb, slave->dev); + + write_lock(&bond->curr_slave_lock); + bond->curr_active_slave = slave->next; + write_unlock(&bond->curr_slave_lock); + break; } } + out: if (res) { /* no suitable interface, frame not sent */ @@ -4333,22 +4188,6 @@ out: /*------------------------- Device initialization ---------------------------*/ -static void bond_set_xmit_hash_policy(struct bonding *bond) -{ - switch (bond->params.xmit_policy) { - case BOND_XMIT_POLICY_LAYER23: - bond->xmit_hash_policy = bond_xmit_hash_policy_l23; - break; - case BOND_XMIT_POLICY_LAYER34: - bond->xmit_hash_policy = bond_xmit_hash_policy_l34; - break; - case BOND_XMIT_POLICY_LAYER2: - default: - bond->xmit_hash_policy = bond_xmit_hash_policy_l2; - break; - } -} - /* * set bond mode specific net device operations */ @@ -4365,7 +4204,10 @@ void bond_set_mode_ops(struct bonding *bond, int mode) break; case BOND_MODE_XOR: bond_dev->hard_start_xmit = bond_xmit_xor; - bond_set_xmit_hash_policy(bond); + if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER34) + bond->xmit_hash_policy = bond_xmit_hash_policy_l34; + else + bond->xmit_hash_policy = bond_xmit_hash_policy_l2; break; case BOND_MODE_BROADCAST: bond_dev->hard_start_xmit = bond_xmit_broadcast; @@ -4373,7 +4215,10 @@ void bond_set_mode_ops(struct bonding *bond, int mode) case BOND_MODE_8023AD: bond_set_master_3ad_flags(bond); bond_dev->hard_start_xmit = bond_3ad_xmit_xor; - bond_set_xmit_hash_policy(bond); + if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER34) + bond->xmit_hash_policy = bond_xmit_hash_policy_l34; + else + bond->xmit_hash_policy = bond_xmit_hash_policy_l2; break; case BOND_MODE_ALB: bond_set_master_alb_flags(bond); @@ -4424,18 +4269,12 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params) bond->params = *params; /* copy params struct */ - bond->wq = create_singlethread_workqueue(bond_dev->name); - if (!bond->wq) - return -ENOMEM; - /* Initialize pointers */ bond->first_slave = NULL; bond->curr_active_slave = NULL; bond->current_arp_slave = NULL; bond->primary_slave = NULL; bond->dev = bond_dev; - bond->send_grat_arp = 0; - bond->setup_by_slave = 0; INIT_LIST_HEAD(&bond->vlan_list); /* Initialize the device entry points */ @@ -4484,6 +4323,7 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params) #ifdef CONFIG_PROC_FS bond_create_proc_entry(bond); #endif + list_add_tail(&bond->bond_list, &bond_dev_list); return 0; @@ -4492,7 +4332,7 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params) /* De-initialize device specific data. * Caller must hold rtnl_lock. */ -static void bond_deinit(struct net_device *bond_dev) +void bond_deinit(struct net_device *bond_dev) { struct bonding *bond = bond_dev->priv; @@ -4503,27 +4343,6 @@ static void bond_deinit(struct net_device *bond_dev) #endif } -static void bond_work_cancel_all(struct bonding *bond) -{ - write_lock_bh(&bond->lock); - bond->kill_timers = 1; - write_unlock_bh(&bond->lock); - - if (bond->params.miimon && delayed_work_pending(&bond->mii_work)) - cancel_delayed_work(&bond->mii_work); - - if (bond->params.arp_interval && delayed_work_pending(&bond->arp_work)) - cancel_delayed_work(&bond->arp_work); - - if (bond->params.mode == BOND_MODE_ALB && - delayed_work_pending(&bond->alb_work)) - cancel_delayed_work(&bond->alb_work); - - if (bond->params.mode == BOND_MODE_8023AD && - delayed_work_pending(&bond->ad_work)) - cancel_delayed_work(&bond->ad_work); -} - /* Unregister and free all bond devices. * Caller must hold rtnl_lock. */ @@ -4534,12 +4353,11 @@ 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_work_cancel_all(bond); bond_mc_list_destroy(bond); /* Release the bonded slaves */ bond_release_all(bond_dev); - bond_deinit(bond_dev); unregister_netdevice(bond_dev); + bond_deinit(bond_dev); } #ifdef CONFIG_PROC_FS @@ -4560,7 +4378,8 @@ int bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl) for (i = 0; tbl[i].modename; i++) { if ((isdigit(*mode_arg) && tbl[i].mode == simple_strtol(mode_arg, NULL, 0)) || - (strcmp(mode_arg, tbl[i].modename) == 0)) { + (strncmp(mode_arg, tbl[i].modename, + strlen(tbl[i].modename)) == 0)) { return tbl[i].mode; } } @@ -4760,7 +4579,7 @@ static int bond_check_params(struct bond_params *params) arp_ip_target[arp_ip_count]); arp_interval = 0; } else { - __be32 ip = in_aton(arp_ip_target[arp_ip_count]); + u32 ip = in_aton(arp_ip_target[arp_ip_count]); arp_target[arp_ip_count] = ip; } } @@ -4838,11 +4657,6 @@ static int bond_check_params(struct bond_params *params) primary = NULL; } - if (fail_over_mac && (bond_mode != BOND_MODE_ACTIVEBACKUP)) - printk(KERN_WARNING DRV_NAME - ": Warning: fail_over_mac only affects " - "active-backup mode.\n"); - /* fill params struct with the proper values */ params->mode = bond_mode; params->xmit_policy = xmit_hashtype; @@ -4854,7 +4668,6 @@ static int bond_check_params(struct bond_params *params) params->use_carrier = use_carrier; params->lacp_fast = lacp_fast; params->primary[0] = 0; - params->fail_over_mac = fail_over_mac; if (primary) { strncpy(params->primary, primary, IFNAMSIZ); @@ -4941,7 +4754,6 @@ static int __init bonding_init(void) { int i; int res; - struct bonding *bond, *nxt; printk(KERN_INFO "%s", version); @@ -4968,11 +4780,6 @@ static int __init bonding_init(void) goto out; err: - list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) { - bond_work_cancel_all(bond); - destroy_workqueue(bond->wq); - } - rtnl_lock(); bond_free_all(); bond_destroy_sysfs(); diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 51475a13..8e317e11 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -56,7 +57,7 @@ static int expected_refcount = -1; static struct class *netdev_class; /*--------------------------- Data Structures -----------------------------*/ -/* Bonding sysfs lock. Why can't we just use the subsystem lock? +/* Bonding sysfs lock. Why can't we just use the subsytem lock? * Because kobject_register tries to acquire the subsystem lock. If * we already hold the lock (which we would if the user was creating * a new bond through the sysfs interface), we deadlock. @@ -75,7 +76,7 @@ struct rw_semaphore bonding_rwsem; * "show" function for the bond_masters attribute. * The class parameter is ignored. */ -static ssize_t bonding_show_bonds(struct class *cls, char *buf) +static ssize_t bonding_show_bonds(struct class *cls, char *buffer) { int res = 0; struct bonding *bond; @@ -87,13 +88,14 @@ static ssize_t bonding_show_bonds(struct class *cls, char *buf) /* not enough space for another interface name */ if ((PAGE_SIZE - res) > 10) res = PAGE_SIZE - 10; - res += sprintf(buf + res, "++more++ "); + res += sprintf(buffer + res, "++more++"); break; } - res += sprintf(buf + res, "%s ", bond->dev->name); + res += sprintf(buffer + res, "%s ", + bond->dev->name); } - if (res) - buf[res-1] = '\n'; /* eat the leftover space */ + res += sprintf(buffer + res, "\n"); + res++; up_read(&(bonding_rwsem)); return res; } @@ -164,7 +166,9 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t printk(KERN_INFO DRV_NAME ": %s is being deleted...\n", bond->dev->name); - bond_destroy(bond); + unregister_netdevice(bond->dev); + bond_deinit(bond->dev); + bond_destroy_sysfs_entry(bond); rtnl_unlock(); goto out; } @@ -228,20 +232,20 @@ static ssize_t bonding_show_slaves(struct class_device *cd, char *buf) int i, res = 0; struct bonding *bond = to_bond(cd); - read_lock(&bond->lock); + read_lock_bh(&bond->lock); bond_for_each_slave(bond, slave, i) { if (res > (PAGE_SIZE - IFNAMSIZ)) { /* not enough space for another interface name */ if ((PAGE_SIZE - res) > 10) res = PAGE_SIZE - 10; - res += sprintf(buf + res, "++more++ "); + res += sprintf(buf + res, "++more++"); break; } res += sprintf(buf + res, "%s ", slave->dev->name); } - read_unlock(&bond->lock); - if (res) - buf[res-1] = '\n'; /* eat the leftover space */ + read_unlock_bh(&bond->lock); + res += sprintf(buf + res, "\n"); + res++; return res; } @@ -280,18 +284,18 @@ static ssize_t bonding_store_slaves(struct class_device *cd, const char *buffer, /* Got a slave name in ifname. Is it already in the list? */ found = 0; - read_lock(&bond->lock); + read_lock_bh(&bond->lock); bond_for_each_slave(bond, slave, i) if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0) { printk(KERN_ERR DRV_NAME ": %s: Interface %s is already enslaved!\n", bond->dev->name, ifname); ret = -EPERM; - read_unlock(&bond->lock); + read_unlock_bh(&bond->lock); goto out; } - read_unlock(&bond->lock); + read_unlock_bh(&bond->lock); printk(KERN_INFO DRV_NAME ": %s: Adding slave %s.\n", bond->dev->name, ifname); dev = dev_get_by_name(ifname); @@ -354,10 +358,7 @@ static ssize_t bonding_store_slaves(struct class_device *cd, const char *buffer, printk(KERN_INFO DRV_NAME ": %s: Removing slave %s\n", bond->dev->name, dev->name); rtnl_lock(); - if (bond->setup_by_slave) - res = bond_release_and_destroy(bond->dev, dev); - else - res = bond_release(bond->dev, dev); + res = bond_release(bond->dev, dev); rtnl_unlock(); if (res) { ret = res; @@ -398,7 +399,7 @@ static ssize_t bonding_show_mode(struct class_device *cd, char *buf) return sprintf(buf, "%s %d\n", bond_mode_tbl[bond->params.mode].modename, - bond->params.mode); + bond->params.mode) + 1; } static ssize_t bonding_store_mode(struct class_device *cd, const char *buf, size_t count) @@ -445,11 +446,20 @@ static CLASS_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, bonding_show_mode, bonding_sto */ static ssize_t bonding_show_xmit_hash(struct class_device *cd, char *buf) { + int count; struct bonding *bond = to_bond(cd); - return sprintf(buf, "%s %d\n", + if ((bond->params.mode != BOND_MODE_XOR) && + (bond->params.mode != BOND_MODE_8023AD)) { + // Not Applicable + count = sprintf(buf, "NA\n") + 1; + } else { + count = sprintf(buf, "%s %d\n", xmit_hashtype_tbl[bond->params.xmit_policy].modename, - bond->params.xmit_policy); + bond->params.xmit_policy) + 1; + } + + return count; } static ssize_t bonding_store_xmit_hash(struct class_device *cd, const char *buf, size_t count) @@ -465,6 +475,15 @@ static ssize_t bonding_store_xmit_hash(struct class_device *cd, const char *buf, goto out; } + if ((bond->params.mode != BOND_MODE_XOR) && + (bond->params.mode != BOND_MODE_8023AD)) { + printk(KERN_ERR DRV_NAME + "%s: Transmit hash policy is irrelevant in this mode.\n", + bond->dev->name); + ret = -EPERM; + goto out; + } + new_value = bond_parse_parm((char *)buf, xmit_hashtype_tbl); if (new_value < 0) { printk(KERN_ERR DRV_NAME @@ -493,7 +512,7 @@ static ssize_t bonding_show_arp_validate(struct class_device *cd, char *buf) return sprintf(buf, "%s %d\n", arp_validate_tbl[bond->params.arp_validate].modename, - bond->params.arp_validate); + bond->params.arp_validate) + 1; } static ssize_t bonding_store_arp_validate(struct class_device *cd, const char *buf, size_t count) @@ -531,54 +550,6 @@ static ssize_t bonding_store_arp_validate(struct class_device *cd, const char *b static CLASS_DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate); -/* - * Show and store fail_over_mac. User only allowed to change the - * value when there are no slaves. - */ -static ssize_t bonding_show_fail_over_mac(struct class_device *cd, char *buf) -{ - struct bonding *bond = to_bond(cd); - - return sprintf(buf, "%d\n", bond->params.fail_over_mac) + 1; -} - -static ssize_t bonding_store_fail_over_mac(struct class_device *cd, const char *buf, size_t count) -{ - int new_value; - int ret = count; - struct bonding *bond = to_bond(cd); - - if (bond->slave_cnt != 0) { - printk(KERN_ERR DRV_NAME - ": %s: Can't alter fail_over_mac with slaves in bond.\n", - bond->dev->name); - ret = -EPERM; - goto out; - } - - if (sscanf(buf, "%d", &new_value) != 1) { - printk(KERN_ERR DRV_NAME - ": %s: no fail_over_mac value specified.\n", - bond->dev->name); - ret = -EINVAL; - goto out; - } - - if ((new_value == 0) || (new_value == 1)) { - bond->params.fail_over_mac = new_value; - printk(KERN_INFO DRV_NAME ": %s: Setting fail_over_mac to %d.\n", - bond->dev->name, new_value); - } else { - printk(KERN_INFO DRV_NAME - ": %s: Ignoring invalid fail_over_mac value %d.\n", - bond->dev->name, new_value); - } -out: - return ret; -} - -static CLASS_DEVICE_ATTR(fail_over_mac, S_IRUGO | S_IWUSR, bonding_show_fail_over_mac, bonding_store_fail_over_mac); - /* * Show and set the arp timer interval. There are two tricky bits * here. First, if ARP monitoring is activated, then we must disable @@ -589,7 +560,7 @@ static ssize_t bonding_show_arp_interval(struct class_device *cd, char *buf) { struct bonding *bond = to_bond(cd); - return sprintf(buf, "%d\n", bond->params.arp_interval); + return sprintf(buf, "%d\n", bond->params.arp_interval) + 1; } static ssize_t bonding_store_arp_interval(struct class_device *cd, const char *buf, size_t count) @@ -622,9 +593,12 @@ static ssize_t bonding_store_arp_interval(struct class_device *cd, const char *b "%s Disabling MII monitoring.\n", bond->dev->name, bond->dev->name); bond->params.miimon = 0; - if (delayed_work_pending(&bond->mii_work)) { - cancel_delayed_work(&bond->mii_work); - flush_workqueue(bond->wq); + /* Kill MII timer, else it brings bond's link down */ + if (bond->arp_timer.function) { + printk(KERN_INFO DRV_NAME + ": %s: Kill MII timer, else it brings bond's link down...\n", + bond->dev->name); + del_timer_sync(&bond->mii_timer); } } if (!bond->params.arp_targets[0]) { @@ -639,17 +613,25 @@ static ssize_t bonding_store_arp_interval(struct class_device *cd, const char *b * timer will get fired off when the open function * is called. */ - if (!delayed_work_pending(&bond->arp_work)) { - if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) - INIT_WORK(&bond->arp_work, - bond_activebackup_arp_mon, - bond); - else - INIT_WORK(&bond->arp_work, - bond_loadbalance_arp_mon, - bond); - - queue_delayed_work(bond->wq, &bond->arp_work, 0); + if (bond->arp_timer.function) { + /* The timer's already set up, so fire it off */ + mod_timer(&bond->arp_timer, jiffies + 1); + } else { + /* Set up the timer. */ + init_timer(&bond->arp_timer); + bond->arp_timer.expires = jiffies + 1; + bond->arp_timer.data = + (unsigned long) bond->dev; + if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) { + bond->arp_timer.function = + (void *) + &bond_activebackup_arp_mon; + } else { + bond->arp_timer.function = + (void *) + &bond_loadbalance_arp_mon; + } + add_timer(&bond->arp_timer); } } @@ -672,22 +654,24 @@ static ssize_t bonding_show_arp_targets(struct class_device *cd, char *buf) NIPQUAD(bond->params.arp_targets[i])); } if (res) - buf[res-1] = '\n'; /* eat the leftover space */ + res--; /* eat the leftover space */ + res += sprintf(buf + res, "\n"); + res++; return res; } static ssize_t bonding_store_arp_targets(struct class_device *cd, const char *buf, size_t count) { - __be32 newtarget; + u32 newtarget; int i = 0, done = 0, ret = count; struct bonding *bond = to_bond(cd); - __be32 *targets; + u32 *targets; targets = bond->params.arp_targets; newtarget = in_aton(buf + 1); /* look for adds */ if (buf[0] == '+') { - if ((newtarget == 0) || (newtarget == htonl(INADDR_BROADCAST))) { + if ((newtarget == 0) || (newtarget == INADDR_BROADCAST)) { printk(KERN_ERR DRV_NAME ": %s: invalid ARP target %u.%u.%u.%u specified for addition\n", bond->dev->name, NIPQUAD(newtarget)); @@ -723,7 +707,7 @@ static ssize_t bonding_store_arp_targets(struct class_device *cd, const char *bu } else if (buf[0] == '-') { - if ((newtarget == 0) || (newtarget == htonl(INADDR_BROADCAST))) { + if ((newtarget == 0) || (newtarget == INADDR_BROADCAST)) { printk(KERN_ERR DRV_NAME ": %s: invalid ARP target %d.%d.%d.%d specified for removal\n", bond->dev->name, NIPQUAD(newtarget)); @@ -769,7 +753,7 @@ static ssize_t bonding_show_downdelay(struct class_device *cd, char *buf) { struct bonding *bond = to_bond(cd); - return sprintf(buf, "%d\n", bond->params.downdelay * bond->params.miimon); + return sprintf(buf, "%d\n", bond->params.downdelay * bond->params.miimon) + 1; } static ssize_t bonding_store_downdelay(struct class_device *cd, const char *buf, size_t count) @@ -822,7 +806,7 @@ static ssize_t bonding_show_updelay(struct class_device *cd, char *buf) { struct bonding *bond = to_bond(cd); - return sprintf(buf, "%d\n", bond->params.updelay * bond->params.miimon); + return sprintf(buf, "%d\n", bond->params.updelay * bond->params.miimon) + 1; } @@ -882,7 +866,7 @@ static ssize_t bonding_show_lacp(struct class_device *cd, char *buf) return sprintf(buf, "%s %d\n", bond_lacp_tbl[bond->params.lacp_fast].modename, - bond->params.lacp_fast); + bond->params.lacp_fast) + 1; } static ssize_t bonding_store_lacp(struct class_device *cd, const char *buf, size_t count) @@ -934,7 +918,7 @@ static ssize_t bonding_show_miimon(struct class_device *cd, char *buf) { struct bonding *bond = to_bond(cd); - return sprintf(buf, "%d\n", bond->params.miimon); + return sprintf(buf, "%d\n", bond->params.miimon) + 1; } static ssize_t bonding_store_miimon(struct class_device *cd, const char *buf, size_t count) @@ -983,9 +967,12 @@ static ssize_t bonding_store_miimon(struct class_device *cd, const char *buf, si bond->params.arp_validate = BOND_ARP_VALIDATE_NONE; } - if (delayed_work_pending(&bond->arp_work)) { - cancel_delayed_work(&bond->arp_work); - flush_workqueue(bond->wq); + /* Kill ARP timer, else it brings bond's link down */ + if (bond->mii_timer.function) { + printk(KERN_INFO DRV_NAME + ": %s: Kill ARP timer, else it brings bond's link down...\n", + bond->dev->name); + del_timer_sync(&bond->arp_timer); } } @@ -995,12 +982,18 @@ static ssize_t bonding_store_miimon(struct class_device *cd, const char *buf, si * timer will get fired off when the open function * is called. */ - if (!delayed_work_pending(&bond->mii_work)) { - INIT_WORK(&bond->mii_work, - bond_mii_monitor, - bond); - queue_delayed_work(bond->wq, - &bond->mii_work, 0); + if (bond->mii_timer.function) { + /* The timer's already set up, so fire it off */ + mod_timer(&bond->mii_timer, jiffies + 1); + } else { + /* Set up the timer. */ + init_timer(&bond->mii_timer); + bond->mii_timer.expires = jiffies + 1; + bond->mii_timer.data = + (unsigned long) bond->dev; + bond->mii_timer.function = + (void *) &bond_mii_monitor; + add_timer(&bond->mii_timer); } } } @@ -1022,7 +1015,9 @@ static ssize_t bonding_show_primary(struct class_device *cd, char *buf) struct bonding *bond = to_bond(cd); if (bond->primary_slave) - count = sprintf(buf, "%s\n", bond->primary_slave->dev->name); + count = sprintf(buf, "%s\n", bond->primary_slave->dev->name) + 1; + else + count = sprintf(buf, "\n") + 1; return count; } @@ -1033,10 +1028,7 @@ static ssize_t bonding_store_primary(struct class_device *cd, const char *buf, s struct slave *slave; struct bonding *bond = to_bond(cd); - rtnl_lock(); - read_lock(&bond->lock); - write_lock_bh(&bond->curr_slave_lock); - + write_lock_bh(&bond->lock); if (!USES_PRIMARY(bond->params.mode)) { printk(KERN_INFO DRV_NAME ": %s: Unable to set primary slave; %s is in mode %d\n", @@ -1070,10 +1062,7 @@ static ssize_t bonding_store_primary(struct class_device *cd, const char *buf, s } } out: - write_unlock_bh(&bond->curr_slave_lock); - read_unlock(&bond->lock); - rtnl_unlock(); - + write_unlock_bh(&bond->lock); return count; } static CLASS_DEVICE_ATTR(primary, S_IRUGO | S_IWUSR, bonding_show_primary, bonding_store_primary); @@ -1085,7 +1074,7 @@ static ssize_t bonding_show_carrier(struct class_device *cd, char *buf) { struct bonding *bond = to_bond(cd); - return sprintf(buf, "%d\n", bond->params.use_carrier); + return sprintf(buf, "%d\n", bond->params.use_carrier) + 1; } static ssize_t bonding_store_carrier(struct class_device *cd, const char *buf, size_t count) @@ -1123,14 +1112,17 @@ static ssize_t bonding_show_active_slave(struct class_device *cd, char *buf) { struct slave *curr; struct bonding *bond = to_bond(cd); - int count = 0; + int count; + read_lock(&bond->curr_slave_lock); curr = bond->curr_active_slave; read_unlock(&bond->curr_slave_lock); if (USES_PRIMARY(bond->params.mode) && curr) - count = sprintf(buf, "%s\n", curr->dev->name); + count = sprintf(buf, "%s\n", curr->dev->name) + 1; + else + count = sprintf(buf, "\n") + 1; return count; } @@ -1142,10 +1134,7 @@ static ssize_t bonding_store_active_slave(struct class_device *cd, const char *b struct slave *new_active = NULL; struct bonding *bond = to_bond(cd); - rtnl_lock(); - read_lock(&bond->lock); - write_lock_bh(&bond->curr_slave_lock); - + write_lock_bh(&bond->lock); if (!USES_PRIMARY(bond->params.mode)) { printk(KERN_INFO DRV_NAME ": %s: Unable to change active slave; %s is in mode %d\n", @@ -1201,10 +1190,7 @@ static ssize_t bonding_store_active_slave(struct class_device *cd, const char *b } } out: - write_unlock_bh(&bond->curr_slave_lock); - read_unlock(&bond->lock); - rtnl_unlock(); - + write_unlock_bh(&bond->lock); return count; } @@ -1223,7 +1209,7 @@ static ssize_t bonding_show_mii_status(struct class_device *cd, char *buf) curr = bond->curr_active_slave; read_unlock(&bond->curr_slave_lock); - return sprintf(buf, "%s\n", (curr) ? "up" : "down"); + return sprintf(buf, "%s\n", (curr) ? "up" : "down") + 1; } static CLASS_DEVICE_ATTR(mii_status, S_IRUGO, bonding_show_mii_status, NULL); @@ -1238,8 +1224,10 @@ static ssize_t bonding_show_ad_aggregator(struct class_device *cd, char *buf) if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; - count = sprintf(buf, "%d\n", (bond_3ad_get_active_agg_info(bond, &ad_info)) ? 0 : ad_info.aggregator_id); + count = sprintf(buf, "%d\n", (bond_3ad_get_active_agg_info(bond, &ad_info)) ? 0 : ad_info.aggregator_id) + 1; } + else + count = sprintf(buf, "\n") + 1; return count; } @@ -1256,8 +1244,10 @@ static ssize_t bonding_show_ad_num_ports(struct class_device *cd, char *buf) if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; - count = sprintf(buf, "%d\n", (bond_3ad_get_active_agg_info(bond, &ad_info)) ? 0: ad_info.ports); + count = sprintf(buf, "%d\n", (bond_3ad_get_active_agg_info(bond, &ad_info)) ? 0: ad_info.ports) + 1; } + else + count = sprintf(buf, "\n") + 1; return count; } @@ -1274,8 +1264,10 @@ static ssize_t bonding_show_ad_actor_key(struct class_device *cd, char *buf) if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; - count = sprintf(buf, "%d\n", (bond_3ad_get_active_agg_info(bond, &ad_info)) ? 0 : ad_info.actor_key); + count = sprintf(buf, "%d\n", (bond_3ad_get_active_agg_info(bond, &ad_info)) ? 0 : ad_info.actor_key) + 1; } + else + count = sprintf(buf, "\n") + 1; return count; } @@ -1292,8 +1284,10 @@ static ssize_t bonding_show_ad_partner_key(struct class_device *cd, char *buf) if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; - count = sprintf(buf, "%d\n", (bond_3ad_get_active_agg_info(bond, &ad_info)) ? 0 : ad_info.partner_key); + count = sprintf(buf, "%d\n", (bond_3ad_get_active_agg_info(bond, &ad_info)) ? 0 : ad_info.partner_key) + 1; } + else + count = sprintf(buf, "\n") + 1; return count; } @@ -1317,9 +1311,11 @@ static ssize_t bonding_show_ad_partner_mac(struct class_device *cd, char *buf) ad_info.partner_system[2], ad_info.partner_system[3], ad_info.partner_system[4], - ad_info.partner_system[5]); + ad_info.partner_system[5]) + 1; } } + else + count = sprintf(buf, "\n") + 1; return count; } @@ -1330,7 +1326,6 @@ 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_fail_over_mac.attr, &class_device_attr_arp_validate.attr, &class_device_attr_arp_interval.attr, &class_device_attr_arp_ip_target.attr, diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index aa27cbda..41aa78bf 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.2.3" -#define DRV_RELDATE "December 6, 2007" +#define DRV_VERSION "3.1.2" +#define DRV_RELDATE "January 20, 2007" #define DRV_NAME "bonding" #define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" @@ -128,12 +128,11 @@ struct bond_params { int arp_interval; int arp_validate; int use_carrier; - int fail_over_mac; int updelay; int downdelay; int lacp_fast; char primary[IFNAMSIZ]; - __be32 arp_targets[BOND_MAX_ARP_TARGETS]; + u32 arp_targets[BOND_MAX_ARP_TARGETS]; }; struct bond_parm_tbl { @@ -143,7 +142,7 @@ struct bond_parm_tbl { struct vlan_entry { struct list_head vlan_list; - __be32 vlan_ip; + u32 vlan_ip; unsigned short vlan_id; }; @@ -183,9 +182,9 @@ struct bonding { s32 slave_cnt; /* never change this value outside the attach/detach wrappers */ rwlock_t lock; rwlock_t curr_slave_lock; + struct timer_list mii_timer; + struct timer_list arp_timer; s8 kill_timers; - s8 send_grat_arp; - s8 setup_by_slave; struct net_device_stats stats; #ifdef CONFIG_PROC_FS struct proc_dir_entry *proc_entry; @@ -194,20 +193,14 @@ struct bonding { struct list_head bond_list; struct dev_mc_list *mc_list; int (*xmit_hash_policy)(struct sk_buff *, struct net_device *, int); - __be32 master_ip; + u32 master_ip; u16 flags; - u16 rr_tx_counter; struct ad_bond_info ad_info; struct alb_bond_info alb_info; struct bond_params params; struct list_head vlan_list; struct vlan_group *vlgrp; struct packet_type arp_mon_pt; - struct workqueue_struct *wq; - struct work_struct mii_work; - struct work_struct arp_work; - struct work_struct alb_work; - struct work_struct ad_work; }; /** @@ -299,8 +292,7 @@ static inline void bond_unset_master_alb_flags(struct bonding *bond) struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr); int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev); int bond_create(char *name, struct bond_params *params, struct bonding **newbond); -void bond_destroy(struct bonding *bond); -int bond_release_and_destroy(struct net_device *bond_dev, struct net_device *slave_dev); +void bond_deinit(struct net_device *bond_dev); int bond_create_sysfs(void); void bond_destroy_sysfs(void); void bond_destroy_sysfs_entry(struct bonding *bond); @@ -309,11 +301,13 @@ int bond_create_slave_symlinks(struct net_device *master, struct net_device *sla void bond_destroy_slave_symlinks(struct net_device *master, struct net_device *slave); int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev); int bond_release(struct net_device *bond_dev, struct net_device *slave_dev); -void bond_mii_monitor(void *); -void bond_loadbalance_arp_mon(void *); -void bond_activebackup_arp_mon(void *); +int bond_sethwaddr(struct net_device *bond_dev, struct net_device *slave_dev); +void bond_mii_monitor(struct net_device *bond_dev); +void bond_loadbalance_arp_mon(struct net_device *bond_dev); +void bond_activebackup_arp_mon(struct net_device *bond_dev); void bond_set_mode_ops(struct bonding *bond, int mode); 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 *); diff --git a/include/linux/if_bonding.h b/include/linux/if_bonding.h index 65c2d247..84598fa2 100644 --- a/include/linux/if_bonding.h +++ b/include/linux/if_bonding.h @@ -85,8 +85,7 @@ /* hashing types */ #define BOND_XMIT_POLICY_LAYER2 0 /* layer 2 (MAC only), default */ -#define BOND_XMIT_POLICY_LAYER34 1 /* layer 3+4 (IP ^ (TCP || UDP)) */ -#define BOND_XMIT_POLICY_LAYER23 2 /* layer 2+3 (IP ^ MAC) */ +#define BOND_XMIT_POLICY_LAYER34 1 /* layer 3+4 (IP ^ MAC) */ typedef struct ifbond { __s32 bond_mode; diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index d8e82c9f..c9da36f2 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1007,8 +1007,6 @@ extern void dev_seq_stop(struct seq_file *seq, void *v); extern void linkwatch_run_queue(void); -extern int netdev_compute_features(unsigned long all, unsigned long one); - static inline int net_gso_ok(int features, int gso_type) { int feature = gso_type << NETIF_F_GSO_SHIFT; diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index bf629233..9bca3539 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -98,9 +98,4 @@ static inline int cancel_delayed_work(struct work_struct *work) return ret; } -static inline int delayed_work_pending(struct work_struct *work) -{ - return test_bit(0, &work->pending); -} - #endif diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index efabbb59..f8dbcee8 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -185,5 +185,5 @@ void br_dev_setup(struct net_device *dev) dev->priv_flags = IFF_EBRIDGE; dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | - NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | NETIF_F_LLTX; + NETIF_F_TSO | NETIF_F_NO_CSUM | NETIF_F_GSO_ROBUST; } diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 95ea4d62..c80ecedd 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -358,15 +358,35 @@ int br_min_mtu(const struct net_bridge *br) void br_features_recompute(struct net_bridge *br) { struct net_bridge_port *p; - unsigned long features; + unsigned long features, checksum; - features = br->feature_mask; + checksum = br->feature_mask & NETIF_F_ALL_CSUM ? NETIF_F_NO_CSUM : 0; + features = br->feature_mask & ~NETIF_F_ALL_CSUM; list_for_each_entry(p, &br->port_list, list) { - features = netdev_compute_features(features, p->dev->features); + unsigned long feature = p->dev->features; + + if (checksum & NETIF_F_NO_CSUM && !(feature & NETIF_F_NO_CSUM)) + checksum ^= NETIF_F_NO_CSUM | NETIF_F_HW_CSUM; + if (checksum & NETIF_F_HW_CSUM && !(feature & NETIF_F_HW_CSUM)) + checksum ^= NETIF_F_HW_CSUM | NETIF_F_IP_CSUM; + if (!(feature & NETIF_F_IP_CSUM)) + checksum = 0; + + if (feature & NETIF_F_GSO) + feature |= NETIF_F_GSO_SOFTWARE; + feature |= NETIF_F_GSO; + + features &= feature; } - - br->dev->features = features; + + if (!(checksum & NETIF_F_ALL_CSUM)) + features &= ~NETIF_F_SG; + if (!(features & NETIF_F_SG)) + features &= ~NETIF_F_GSO_MASK; + + br->dev->features = features | checksum | NETIF_F_LLTX | + NETIF_F_GSO_ROBUST; } /* called with RTNL */ diff --git a/net/core/dev.c b/net/core/dev.c index b8101af4..be9c3f93 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3554,44 +3554,6 @@ static int __init netdev_dma_register(void) { return -ENODEV; } * */ -/** - * netdev_compute_feature - compute conjunction of two feature sets - * @all: first feature set - * @one: second feature set - * - * Computes a new feature set after adding a device with feature set - * @one to the master device with current feature set @all. Returns - * the new feature set. - */ -int netdev_compute_features(unsigned long all, unsigned long one) -{ - /* if device needs checksumming, downgrade to hw checksumming */ - if (all & NETIF_F_NO_CSUM && !(one & NETIF_F_NO_CSUM)) - all ^= NETIF_F_NO_CSUM | NETIF_F_HW_CSUM; - - /* if device can't do all checksum, downgrade to ipv4/ipv6 */ - if (all & NETIF_F_HW_CSUM && !(one & NETIF_F_HW_CSUM)) - all ^= NETIF_F_HW_CSUM | NETIF_F_IP_CSUM; - - if (one & NETIF_F_GSO) - one |= NETIF_F_GSO_SOFTWARE; - one |= NETIF_F_GSO; - - /* If even one device supports robust GSO, enable it for all. */ - if (one & NETIF_F_GSO_ROBUST) - all |= NETIF_F_GSO_ROBUST; - - all &= one | NETIF_F_LLTX; - - if (!(all & NETIF_F_ALL_CSUM)) - all &= ~NETIF_F_SG; - if (!(all & NETIF_F_SG)) - all &= ~NETIF_F_GSO_MASK; - - return all; -} -EXPORT_SYMBOL(netdev_compute_features); - /* * This is called single threaded during boot, so no need * to take the rtnl semaphore.