/* Caller must hold bond lock for read */ static struct slave *tlb_choose_channel(struct bonding *bond, u32 hash_index, u32 skb_len) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); struct tlb_client_info *hash_table; struct slave *assigned_slave,max_assigned_slave,slave; int i; _lock_tx_hashtbl(bond); hash_table = bond_info->tx_hashtbl; assigned_slave = hash_table[hash_index].tx_slave; if (!assigned_slave) { assigned_slave = tlb_get_least_loaded_slave(bond); if(assigned_slave == assigend_slave_old) { max_assigned_slave = assigned_slave; assigned_slave = max_assigned_slave->next; bond_for_each_slave_from(bond,slave,i) { if (IS_UP(slave->dev) && (slave->link == BOND_LINK_UP) && (slave->state == BOND_STATE_ACTIVE)) { if (compute_gap(slave) > compute_gap(assigned_slave) && slave != max_assigned_slave) assigned_slave = slave; } } }
int bond_option_active_slave_set(struct bonding *bond, struct net_device *slave_dev) { int ret = 0; if (slave_dev) { if (!netif_is_bond_slave(slave_dev)) { pr_err("Device %s is not bonding slave.\n", slave_dev->name); return -EINVAL; } if (bond->dev != netdev_master_upper_dev_get(slave_dev)) { pr_err("%s: Device %s is not our slave.\n", bond->dev->name, slave_dev->name); return -EINVAL; } } if (!USES_PRIMARY(bond->params.mode)) { pr_err("%s: Unable to change active slave; %s is in mode %d\n", bond->dev->name, bond->dev->name, bond->params.mode); return -EINVAL; } block_netpoll_tx(); read_lock(&bond->lock); write_lock_bh(&bond->curr_slave_lock); /* check to see if we are clearing active */ if (!slave_dev) { pr_info("%s: Clearing current active slave.\n", bond->dev->name); rcu_assign_pointer(bond->curr_active_slave, NULL); bond_select_active_slave(bond); } else { struct slave *old_active = bond->curr_active_slave; struct slave *new_active = bond_slave_get_rtnl(slave_dev); BUG_ON(!new_active); if (new_active == old_active) { /* do nothing */ pr_info("%s: %s is already the current active slave.\n", bond->dev->name, new_active->dev->name); } else { if (old_active && (new_active->link == BOND_LINK_UP) && IS_UP(new_active->dev)) { pr_info("%s: Setting %s as active slave.\n", bond->dev->name, new_active->dev->name); bond_change_active_slave(bond, new_active); } else { pr_err("%s: Could not set %s as active slave; either %s is down or the link is down.\n", bond->dev->name, new_active->dev->name, new_active->dev->name); ret = -EINVAL; } } } write_unlock_bh(&bond->curr_slave_lock); read_unlock(&bond->lock); unblock_netpoll_tx(); return ret; }
int bond_option_active_slave_set(struct bonding *bond, struct bond_opt_value *newval) { char ifname[IFNAMSIZ] = { 0, }; struct net_device *slave_dev; int ret = 0; sscanf(newval->string, "%15s", ifname); /* IFNAMSIZ */ if (!strlen(ifname) || newval->string[0] == '\n') { slave_dev = NULL; } else { slave_dev = __dev_get_by_name(dev_net(bond->dev), ifname); if (!slave_dev) return -ENODEV; } if (slave_dev) { if (!netif_is_bond_slave(slave_dev)) { pr_err("Device %s is not bonding slave.\n", slave_dev->name); return -EINVAL; } if (bond->dev != netdev_master_upper_dev_get(slave_dev)) { pr_err("%s: Device %s is not our slave.\n", bond->dev->name, slave_dev->name); return -EINVAL; } } block_netpoll_tx(); write_lock_bh(&bond->curr_slave_lock); /* check to see if we are clearing active */ if (!slave_dev) { pr_info("%s: Clearing current active slave.\n", bond->dev->name); rcu_assign_pointer(bond->curr_active_slave, NULL); bond_select_active_slave(bond); } else { struct slave *old_active = bond->curr_active_slave; struct slave *new_active = bond_slave_get_rtnl(slave_dev); BUG_ON(!new_active); if (new_active == old_active) { /* do nothing */ pr_info("%s: %s is already the current active slave.\n", bond->dev->name, new_active->dev->name); } else { if (old_active && (new_active->link == BOND_LINK_UP) && IS_UP(new_active->dev)) { pr_info("%s: Setting %s as active slave.\n", bond->dev->name, new_active->dev->name); bond_change_active_slave(bond, new_active); } else { pr_err("%s: Could not set %s as active slave; either %s is down or the link is down.\n", bond->dev->name, new_active->dev->name, new_active->dev->name); ret = -EINVAL; } } } write_unlock_bh(&bond->curr_slave_lock); unblock_netpoll_tx(); return ret; }
int bond_alb_xmit(struct sk_buff *skb, struct net_device *dev) { struct bonding *bond = (struct bonding *) dev->priv; struct ethhdr *eth_data = (struct ethhdr *)skb->data; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); struct slave *tx_slave = NULL; char do_tx_balance = 1; int hash_size = 0; u32 hash_index = 0; u8 *hash_start = NULL; u8 mac_bcast[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; if (!IS_UP(dev)) { /* bond down */ dev_kfree_skb(skb); return 0; } /* make sure that the current_slave and the slaves list do * not change during tx */ read_lock(&bond->lock); if (bond->slave_cnt == 0) { /* no suitable interface, frame not sent */ dev_kfree_skb(skb); read_unlock(&bond->lock); return 0; } read_lock(&bond->ptrlock); switch (ntohs(skb->protocol)) { case ETH_P_IP: if ((memcmp(eth_data->h_dest, mac_bcast, ETH_ALEN) == 0) || (skb->nh.iph->daddr == 0xffffffff)) { do_tx_balance = 0; break; } hash_start = (char*)&(skb->nh.iph->daddr); hash_size = 4; break; case ETH_P_IPV6: if (memcmp(eth_data->h_dest, mac_bcast, ETH_ALEN) == 0) { do_tx_balance = 0; break; } hash_start = (char*)&(skb->nh.ipv6h->daddr); hash_size = 16; break; case ETH_P_IPX: if (skb->nh.ipxh->ipx_checksum != __constant_htons(IPX_NO_CHECKSUM)) { /* something is wrong with this packet */ do_tx_balance = 0; break; } if (skb->nh.ipxh->ipx_type != __constant_htons(IPX_TYPE_NCP)) { /* The only protocol worth balancing in * this family since it has an "ARP" like * mechanism */ do_tx_balance = 0; break; } hash_start = (char*)eth_data->h_dest; hash_size = ETH_ALEN; break; case ETH_P_ARP: do_tx_balance = 0; if (bond_info->rlb_enabled) { tx_slave = rlb_arp_xmit(skb, bond); } break; default: do_tx_balance = 0; break; } if (do_tx_balance) { hash_index = _simple_hash(hash_start, hash_size); tx_slave = tlb_choose_channel(bond, hash_index, skb->len); } if (!tx_slave) { /* unbalanced or unassigned, send through primary */ tx_slave = bond->current_slave; bond_info->unbalanced_load += skb->len; } if (tx_slave && SLAVE_IS_OK(tx_slave)) { skb->dev = tx_slave->dev; if (tx_slave != bond->current_slave) { memcpy(eth_data->h_source, tx_slave->dev->dev_addr, ETH_ALEN); } dev_queue_xmit(skb); } else { /* no suitable interface, frame not sent */ if (tx_slave) { tlb_clear_slave(bond, tx_slave, 0); } dev_kfree_skb(skb); } read_unlock(&bond->ptrlock); read_unlock(&bond->lock); return 0; }