]> xenbits.xensource.com Git - xenclient/kernel.git/commitdiff
imported patch revert-linux-2.6-net-bonding-update-to-upstream-version-3-2-2.patch revert-linux-2.6-net-bonding-locking-fixes-and-version-3-2-4.patch
authort_jeang <devnull@localhost>
Tue, 6 Jan 2009 12:05:56 +0000 (12:05 +0000)
committert_jeang <devnull@localhost>
Tue, 6 Jan 2009 12:05:56 +0000 (12:05 +0000)
13 files changed:
drivers/net/bonding/bond_3ad.c
drivers/net/bonding/bond_3ad.h
drivers/net/bonding/bond_alb.c
drivers/net/bonding/bond_alb.h
drivers/net/bonding/bond_main.c
drivers/net/bonding/bond_sysfs.c
drivers/net/bonding/bonding.h
include/linux/if_bonding.h
include/linux/netdevice.h
include/linux/workqueue.h
net/bridge/br_device.c
net/bridge/br_if.c
net/core/dev.c

index 49dc2515c3474d87f17598972ddc3883d0666023..3fb354d9c5156b6e25ab617cbcded5d4e57e74d1 100644 (file)
@@ -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;
index bc25af96b0d87acd0b7383abc6ae4c0ea2f98782..6ad5ad6e65d50536aabc652d7ada6e2135c5156b 100644 (file)
@@ -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);
index 09a8a892873f1aaf0b2db272f5631894c28b8fb0..217a2eedee0aafc143e5533aff617b70693927cb 100644 (file)
@@ -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;
 }
 
index 91bb8d155456cf1794e6a05505dc1e5de374a796..28f2a2fd1b5a956cb896561d2646690ed49bf230 100644 (file)
@@ -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__ */
index 4e8048e0d11e54dfd8aa830c60273e0f09bd5cbd..19da415c5a98bc59456d37bb5415c15584c01001 100644 (file)
@@ -75,7 +75,6 @@
 #include <linux/ethtool.h>
 #include <linux/if_vlan.h>
 #include <linux/if_bonding.h>
-#include <linux/jiffies.h>
 #include <net/route.h>
 #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();
index 51475a130fa5c1210724ce4f9d71ac49b8a26458..8e317e115532cccc63e946c4034e6dd44e25fc3a 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/inetdevice.h>
 #include <linux/in.h>
 #include <linux/sysfs.h>
+#include <linux/string.h>
 #include <linux/ctype.h>
 #include <linux/inet.h>
 #include <linux/rtnetlink.h>
@@ -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,
index aa27cbda46523bb0abfd50e150679cece5f952b7..41aa78bf1f783af9d86928db4c1216de406dd6d4 100644 (file)
@@ -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 *);
index 65c2d247068b298b769e999d99f563c14312299e..84598fa2e9de4c8aebe8ebf625bb667bfa505b18 100644 (file)
@@ -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;
index d8e82c9f47d32ed13fa2441c0ad7792c7599db46..c9da36f24033c1424ca3fdaeb3093d5f4bd8aa12 100644 (file)
@@ -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;
index bf629233fb02320bdf3cf98ebbd5a9669799c908..9bca3539a1e5a965023bd20c148320d96f7d1e27 100644 (file)
@@ -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
index efabbb59438e0625b598c3b5f17f0cb6823e6ce7..f8dbcee80ebad7cdffb110fd87a8796db93643ab 100644 (file)
@@ -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;
 }
index 95ea4d6248d3ff4c1788f5274cfea0b0aef637b4..c80ecedd3aa6ce8acfaed639d3be341550d7443a 100644 (file)
@@ -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 */
index b8101af4bd65cfcdd48d272090b4220d092b6071..be9c3f9358be1096bca4b4e700491332470b2829 100644 (file)
@@ -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.