Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / net / bonding / bond_alb.c
index 5ce606d..e83bc82 100644 (file)
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
- *
- * Changes:
- *
- * 2003/06/25 - Shmulik Hen <shmulik.hen at intel dot com>
- *     - Fixed signed/unsigned calculation errors that caused load sharing
- *       to collapse to one slave under very heavy UDP Tx stress.
- *
- * 2003/08/06 - Amir Noam <amir.noam at intel dot com>
- *     - Add support for setting bond's MAC address with special
- *       handling required for ALB/TLB.
- *
- * 2003/12/01 - Shmulik Hen <shmulik.hen at intel dot com>
- *     - Code cleanup and style changes
- *
- * 2003/12/30 - Amir Noam <amir.noam at intel dot com>
- *     - Fixed: Cannot remove and re-enslave the original active slave.
- *
- * 2004/01/14 - Shmulik Hen <shmulik.hen at intel dot com>
- *     - Add capability to tag self generated packets in ALB/TLB modes.
  */
 
 //#define BONDING_DEBUG 1
@@ -188,9 +169,9 @@ static void tlb_clear_slave(struct bonding *bond, struct slave *slave, int save_
                index = next_index;
        }
 
-       _unlock_tx_hashtbl(bond);
-
        tlb_init_slave(slave);
+
+       _unlock_tx_hashtbl(bond);
 }
 
 /* Must be called before starting the monitor timer */
@@ -198,20 +179,21 @@ static int tlb_initialize(struct bonding *bond)
 {
        struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
        int size = TLB_HASH_TABLE_SIZE * sizeof(struct tlb_client_info);
+       struct tlb_client_info *new_hashtbl;
        int i;
 
        spin_lock_init(&(bond_info->tx_hashtbl_lock));
 
-       _lock_tx_hashtbl(bond);
-
-       bond_info->tx_hashtbl = kmalloc(size, GFP_KERNEL);
-       if (!bond_info->tx_hashtbl) {
+       new_hashtbl = kmalloc(size, GFP_KERNEL);
+       if (!new_hashtbl) {
                printk(KERN_ERR DRV_NAME
-                      ": Error: %s: Failed to allocate TLB hash table\n",
+                      ": %s: Error: Failed to allocate TLB hash table\n",
                       bond->dev->name);
-               _unlock_tx_hashtbl(bond);
                return -1;
        }
+       _lock_tx_hashtbl(bond);
+
+       bond_info->tx_hashtbl = new_hashtbl;
 
        memset(bond_info->tx_hashtbl, 0, size);
 
@@ -354,15 +336,14 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp)
        _unlock_rx_hashtbl(bond);
 }
 
-static int rlb_arp_recv(struct sk_buff *skb, struct net_device *bond_dev, struct packet_type *ptype)
+static int rlb_arp_recv(struct sk_buff *skb, struct net_device *bond_dev, struct packet_type *ptype, struct net_device *orig_dev)
 {
        struct bonding *bond = bond_dev->priv;
        struct arp_pkt *arp = (struct arp_pkt *)skb->data;
        int res = NET_RX_DROP;
 
-       if (!(bond_dev->flags & IFF_MASTER)) {
+       if (!(bond_dev->flags & IFF_MASTER))
                goto out;
-       }
 
        if (!arp) {
                dprintk("Packet has no ARP data\n");
@@ -514,7 +495,8 @@ static void rlb_update_client(struct rlb_client_info *client_info)
                                 client_info->mac_dst);
                if (!skb) {
                        printk(KERN_ERR DRV_NAME
-                              ": Error: failed to create an ARP packet\n");
+                              ": %s: Error: failed to create an ARP packet\n",
+                              client_info->slave->dev->master->name);
                        continue;
                }
 
@@ -524,7 +506,8 @@ static void rlb_update_client(struct rlb_client_info *client_info)
                        skb = vlan_put_tag(skb, client_info->vlan_id);
                        if (!skb) {
                                printk(KERN_ERR DRV_NAME
-                                      ": Error: failed to insert VLAN tag\n");
+                                      ": %s: Error: failed to insert VLAN tag\n",
+                                      client_info->slave->dev->master->name);
                                continue;
                        }
                }
@@ -607,8 +590,9 @@ static void rlb_req_update_subnet_clients(struct bonding *bond, u32 src_ip)
 
                if (!client_info->slave) {
                        printk(KERN_ERR DRV_NAME
-                              ": Error: found a client with no channel in "
-                              "the client's hash table\n");
+                              ": %s: Error: found a client with no channel in "
+                              "the client's hash table\n",
+                              bond->dev->name);
                        continue;
                }
                /*update all clients using this src_ip, that are not assigned
@@ -798,21 +782,22 @@ static int rlb_initialize(struct bonding *bond)
 {
        struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
        struct packet_type *pk_type = &(BOND_ALB_INFO(bond).rlb_pkt_type);
+       struct rlb_client_info  *new_hashtbl;
        int size = RLB_HASH_TABLE_SIZE * sizeof(struct rlb_client_info);
        int i;
 
        spin_lock_init(&(bond_info->rx_hashtbl_lock));
 
-       _lock_rx_hashtbl(bond);
-
-       bond_info->rx_hashtbl = kmalloc(size, GFP_KERNEL);
-       if (!bond_info->rx_hashtbl) {
+       new_hashtbl = kmalloc(size, GFP_KERNEL);
+       if (!new_hashtbl) {
                printk(KERN_ERR DRV_NAME
-                      ": Error: %s: Failed to allocate RLB hash table\n",
+                      ": %s: Error: Failed to allocate RLB hash table\n",
                       bond->dev->name);
-               _unlock_rx_hashtbl(bond);
                return -1;
        }
+       _lock_rx_hashtbl(bond);
+
+       bond_info->rx_hashtbl = new_hashtbl;
 
        bond_info->rx_hashtbl_head = RLB_NULL_INDEX;
 
@@ -928,7 +913,8 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[])
                        skb = vlan_put_tag(skb, vlan->vlan_id);
                        if (!skb) {
                                printk(KERN_ERR DRV_NAME
-                                      ": Error: failed to insert VLAN tag\n");
+                                      ": %s: Error: failed to insert VLAN tag\n",
+                                      bond->dev->name);
                                continue;
                        }
                }
@@ -957,11 +943,11 @@ static int alb_set_slave_mac_addr(struct slave *slave, u8 addr[], int hw)
        s_addr.sa_family = dev->type;
        if (dev_set_mac_address(dev, &s_addr)) {
                printk(KERN_ERR DRV_NAME
-                      ": Error: dev_set_mac_address of dev %s failed! ALB "
+                      ": %s: Error: dev_set_mac_address of dev %s failed! ALB "
                       "mode requires that the base driver support setting "
                       "the hw address also when the network device's "
                       "interface is open\n",
-                      dev->name);
+                      dev->master->name, dev->name);
                return -EOPNOTSUPP;
        }
        return 0;
@@ -1106,18 +1092,13 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
                        }
                }
 
-               if (found) {
-                       /* a slave was found that is using the mac address
-                        * of the new slave
-                        */
-                       printk(KERN_ERR DRV_NAME
-                              ": Error: the hw address of slave %s is not "
-                              "unique - cannot enslave it!",
-                              slave->dev->name);
-                       return -EINVAL;
-               }
+               if (!found)
+                       return 0;
 
-               return 0;
+               /* Try setting slave mac to bond address and fall-through
+                  to code handling that situation below... */
+               alb_set_slave_mac_addr(slave, bond->dev->dev_addr,
+                                      bond->alb_info.rlb_enabled);
        }
 
        /* The slave's address is equal to the address of the bond.
@@ -1159,16 +1140,16 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
                                       bond->alb_info.rlb_enabled);
 
                printk(KERN_WARNING DRV_NAME
-                      ": Warning: the hw address of slave %s is in use by "
+                      ": %s: Warning: the hw address of slave %s is in use by "
                       "the bond; giving it the hw address of %s\n",
-                      slave->dev->name, free_mac_slave->dev->name);
+                      bond->dev->name, slave->dev->name, free_mac_slave->dev->name);
 
        } else if (has_bond_addr) {
                printk(KERN_ERR DRV_NAME
-                      ": Error: the hw address of slave %s is in use by the "
+                      ": %s: Error: the hw address of slave %s is in use by the "
                       "bond; couldn't find a slave with a free hw address to "
                       "give it (this should not have happened)\n",
-                      slave->dev->name);
+                      bond->dev->name, slave->dev->name);
                return -EFAULT;
        }
 
@@ -1256,6 +1237,8 @@ int bond_alb_initialize(struct bonding *bond, int rlb_enabled)
                        tlb_deinitialize(bond);
                        return res;
                }
+       } else {
+               bond->alb_info.rlb_enabled = 0;
        }
 
        return 0;
@@ -1278,7 +1261,7 @@ 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 u32 ip_bcast = 0xffffffff;
+       static const u32 ip_bcast = 0xffffffff;
        int hash_size = 0;
        int do_tx_balance = 1;
        u32 hash_index = 0;
@@ -1415,7 +1398,7 @@ void bond_alb_monitor(struct bonding *bond)
                read_lock(&bond->curr_slave_lock);
 
                bond_for_each_slave(bond, slave, i) {
-                       alb_send_learning_packets(slave,slave->dev->dev_addr);
+                       alb_send_learning_packets(slave, slave->dev->dev_addr);
                }
 
                read_unlock(&bond->curr_slave_lock);