Ejemplo n.º 1
0
/* 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;
				}
			}
		}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
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;
}
Ejemplo n.º 4
0
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;
}