]> Pileus Git - ~andy/linux/blobdiff - drivers/net/bonding/bond_alb.c
bonding: split alb_send_learning_packets()
[~andy/linux] / drivers / net / bonding / bond_alb.c
index 4ea8ed150d469d55c741d63c09fa4fc7f7a29fa5..3ca3c85d6f2492f3d4baa3936d2bb87813d5948e 100644 (file)
@@ -224,13 +224,12 @@ static struct slave *tlb_get_least_loaded_slave(struct bonding *bond)
 {
        struct slave *slave, *least_loaded;
        long long max_gap;
-       int i;
 
        least_loaded = NULL;
        max_gap = LLONG_MIN;
 
        /* Find the slave with the largest gap */
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                if (SLAVE_IS_OK(slave)) {
                        long long gap = compute_gap(slave);
 
@@ -386,11 +385,10 @@ static struct slave *rlb_next_rx_slave(struct bonding *bond)
        struct slave *rx_slave, *slave, *start_at;
        int i = 0;
 
-       if (bond_info->next_rx_slave) {
+       if (bond_info->next_rx_slave)
                start_at = bond_info->next_rx_slave;
-       } else {
-               start_at = bond->first_slave;
-       }
+       else
+               start_at = bond_first_slave(bond);
 
        rx_slave = NULL;
 
@@ -405,7 +403,8 @@ static struct slave *rlb_next_rx_slave(struct bonding *bond)
        }
 
        if (rx_slave) {
-               bond_info->next_rx_slave = rx_slave->next;
+               slave = bond_next_slave(bond, rx_slave);
+               bond_info->next_rx_slave = slave;
        }
 
        return rx_slave;
@@ -972,35 +971,53 @@ static void rlb_clear_vlan(struct bonding *bond, unsigned short vlan_id)
 
 /*********************** tlb/rlb shared functions *********************/
 
-static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[])
+static void alb_send_lp_vid(struct slave *slave, u8 mac_addr[],
+                           u16 vid)
 {
-       struct bonding *bond = bond_get_bond_by_slave(slave);
        struct learning_pkt pkt;
+       struct sk_buff *skb;
        int size = sizeof(struct learning_pkt);
-       int i;
+       char *data;
 
        memset(&pkt, 0, size);
        memcpy(pkt.mac_dst, mac_addr, ETH_ALEN);
        memcpy(pkt.mac_src, mac_addr, ETH_ALEN);
        pkt.type = cpu_to_be16(ETH_P_LOOP);
 
-       for (i = 0; i < MAX_LP_BURST; i++) {
-               struct sk_buff *skb;
-               char *data;
+       skb = dev_alloc_skb(size);
+       if (!skb)
+               return;
+
+       data = skb_put(skb, size);
+       memcpy(data, &pkt, size);
 
-               skb = dev_alloc_skb(size);
+       skb_reset_mac_header(skb);
+       skb->network_header = skb->mac_header + ETH_HLEN;
+       skb->protocol = pkt.type;
+       skb->priority = TC_PRIO_CONTROL;
+       skb->dev = slave->dev;
+
+       if (vid) {
+               skb = vlan_put_tag(skb, htons(ETH_P_8021Q), vid);
                if (!skb) {
+                       pr_err("%s: Error: failed to insert VLAN tag\n",
+                              slave->bond->dev->name);
                        return;
                }
+       }
 
-               data = skb_put(skb, size);
-               memcpy(data, &pkt, size);
+       dev_queue_xmit(skb);
+}
 
-               skb_reset_mac_header(skb);
-               skb->network_header = skb->mac_header + ETH_HLEN;
-               skb->protocol = pkt.type;
-               skb->priority = TC_PRIO_CONTROL;
-               skb->dev = slave->dev;
+
+static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[])
+{
+       struct bonding *bond = bond_get_bond_by_slave(slave);
+       u16 vlan_id;
+       int i;
+
+       for (i = 0; i < MAX_LP_BURST; i++) {
+               vlan_id = 0;
 
                if (bond_vlan_used(bond)) {
                        struct vlan_entry *vlan;
@@ -1009,20 +1026,13 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[])
                                              bond->alb_info.current_alb_vlan);
 
                        bond->alb_info.current_alb_vlan = vlan;
-                       if (!vlan) {
-                               kfree_skb(skb);
+                       if (!vlan)
                                continue;
-                       }
 
-                       skb = vlan_put_tag(skb, htons(ETH_P_8021Q), vlan->vlan_id);
-                       if (!skb) {
-                               pr_err("%s: Error: failed to insert VLAN tag\n",
-                                      bond->dev->name);
-                               continue;
-                       }
+                       vlan_id = vlan->vlan_id;
                }
 
-               dev_queue_xmit(skb);
+               alb_send_lp_vid(slave, mac_addr, vlan_id);
        }
 }
 
@@ -1173,9 +1183,8 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
 {
        struct slave *tmp_slave1, *free_mac_slave = NULL;
        struct slave *has_bond_addr = bond->curr_active_slave;
-       int i;
 
-       if (bond->slave_cnt == 0) {
+       if (list_empty(&bond->slave_list)) {
                /* this is the first slave */
                return 0;
        }
@@ -1196,7 +1205,7 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
        /* The slave's address is equal to the address of the bond.
         * Search for a spare address in the bond for this slave.
         */
-       bond_for_each_slave(bond, tmp_slave1, i) {
+       bond_for_each_slave(bond, tmp_slave1) {
                if (!bond_slave_has_mac(bond, tmp_slave1->perm_hwaddr)) {
                        /* no slave has tmp_slave1's perm addr
                         * as its curr addr
@@ -1246,17 +1255,15 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
  */
 static int alb_set_mac_address(struct bonding *bond, void *addr)
 {
-       struct sockaddr sa;
-       struct slave *slave, *stop_at;
        char tmp_addr[ETH_ALEN];
+       struct slave *slave;
+       struct sockaddr sa;
        int res;
-       int i;
 
-       if (bond->alb_info.rlb_enabled) {
+       if (bond->alb_info.rlb_enabled)
                return 0;
-       }
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                /* save net_device's current hw address */
                memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN);
 
@@ -1276,8 +1283,7 @@ unwind:
        sa.sa_family = bond->dev->type;
 
        /* unwind from head to the slave that failed */
-       stop_at = slave;
-       bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) {
+       bond_for_each_slave_continue_reverse(bond, slave) {
                memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN);
                dev_set_mac_address(slave->dev, &sa);
                memcpy(slave->dev->dev_addr, tmp_addr, ETH_ALEN);
@@ -1342,6 +1348,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
 
        /* make sure that the curr_active_slave do not change during tx
         */
+       read_lock(&bond->lock);
        read_lock(&bond->curr_slave_lock);
 
        switch (ntohs(skb->protocol)) {
@@ -1446,11 +1453,12 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
        }
 
        read_unlock(&bond->curr_slave_lock);
-
+       read_unlock(&bond->lock);
        if (res) {
                /* no suitable interface, frame not sent */
                kfree_skb(skb);
        }
+
        return NETDEV_TX_OK;
 }
 
@@ -1460,11 +1468,10 @@ void bond_alb_monitor(struct work_struct *work)
                                            alb_work.work);
        struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
        struct slave *slave;
-       int i;
 
        read_lock(&bond->lock);
 
-       if (bond->slave_cnt == 0) {
+       if (list_empty(&bond->slave_list)) {
                bond_info->tx_rebalance_counter = 0;
                bond_info->lp_counter = 0;
                goto re_arm;
@@ -1482,9 +1489,8 @@ void bond_alb_monitor(struct work_struct *work)
                 */
                read_lock(&bond->curr_slave_lock);
 
-               bond_for_each_slave(bond, slave, i) {
+               bond_for_each_slave(bond, slave)
                        alb_send_learning_packets(slave, slave->dev->dev_addr);
-               }
 
                read_unlock(&bond->curr_slave_lock);
 
@@ -1496,7 +1502,7 @@ void bond_alb_monitor(struct work_struct *work)
 
                read_lock(&bond->curr_slave_lock);
 
-               bond_for_each_slave(bond, slave, i) {
+               bond_for_each_slave(bond, slave) {
                        tlb_clear_slave(bond, slave, 1);
                        if (slave == bond->curr_active_slave) {
                                SLAVE_TLB_INFO(slave).load =
@@ -1602,9 +1608,8 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave)
  */
 void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave)
 {
-       if (bond->slave_cnt > 1) {
+       if (!list_empty(&bond->slave_list))
                alb_change_hw_addr_on_detach(bond, slave);
-       }
 
        tlb_clear_slave(bond, slave, 0);
 
@@ -1661,9 +1666,8 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
 {
        struct slave *swap_slave;
 
-       if (bond->curr_active_slave == new_slave) {
+       if (bond->curr_active_slave == new_slave)
                return;
-       }
 
        if (bond->curr_active_slave && bond->alb_info.primary_is_promisc) {
                dev_set_promiscuity(bond->curr_active_slave->dev, -1);
@@ -1672,11 +1676,10 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
        }
 
        swap_slave = bond->curr_active_slave;
-       bond->curr_active_slave = new_slave;
+       rcu_assign_pointer(bond->curr_active_slave, new_slave);
 
-       if (!new_slave || (bond->slave_cnt == 0)) {
+       if (!new_slave || list_empty(&bond->slave_list))
                return;
-       }
 
        /* set the new curr_active_slave to the bonds mac address
         * i.e. swap mac addresses of old curr_active_slave and new curr_active_slave
@@ -1689,9 +1692,8 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
         * ignored so we can mess with their MAC addresses without
         * fear of interference from transmit activity.
         */
-       if (swap_slave) {
+       if (swap_slave)
                tlb_clear_slave(bond, swap_slave, 1);
-       }
        tlb_clear_slave(bond, new_slave, 1);
 
        write_unlock_bh(&bond->curr_slave_lock);