Ejemplo n.º 1
0
/* Caller must hold bond lock for write or ptrlock for write*/
static void
alb_swap_mac_addr(struct bonding *bond,
		  struct slave *slave1,
		  struct slave *slave2)
{
	u8 tmp_mac_addr[ETH_ALEN];
	struct slave *disabled_slave = NULL;
	u8 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_mac_addr(slave1, slave2->dev->dev_addr, bond->alb_info.rlb_enabled);
	alb_set_mac_addr(slave2, tmp_mac_addr, bond->alb_info.rlb_enabled);

	/* fasten the change in the switch */
	if (SLAVE_IS_OK(slave1)) {
		alb_send_learning_packets(slave1, slave1->dev->dev_addr);
		if (bond->alb_info.rlb_enabled) {
			/* inform the clients that the mac address
			 * has changed
			 */
			rlb_req_update_slave_clients(bond, slave1);
		}
	}
	else {
		disabled_slave = slave1;
	}

	if (SLAVE_IS_OK(slave2)) {
		alb_send_learning_packets(slave2, slave2->dev->dev_addr);
		if (bond->alb_info.rlb_enabled) {
			/* inform the clients that the mac address
			 * has changed
			 */
			rlb_req_update_slave_clients(bond, slave2);
		}
	}
	else {
		disabled_slave = slave2;
	}

	if (bond->alb_info.rlb_enabled && slaves_state_differ) {
			/* A disabled slave was assigned an active mac addr */
			rlb_teach_disabled_mac_on_primary(bond,
				disabled_slave->dev->dev_addr);
	}
}
Ejemplo n.º 2
0
/* Caller must hold bond lock for read */
static struct slave*
rlb_next_rx_slave(struct bonding *bond)
{
	struct slave *rx_slave = NULL, *slave = NULL;
	unsigned int i = 0;
	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));

	slave = bond_info->next_rx_slave;
	if (slave == NULL) {
		slave = bond->next;
	}

	/* this loop uses the circular linked list property of the
	 * slave's list to go through all slaves
	 */
	for (i = 0; i < bond->slave_cnt; i++, slave = slave->next) {

		if (SLAVE_IS_OK(slave)) {
			if (!rx_slave) {
				rx_slave = slave;
			}
			else if (slave->speed > rx_slave->speed) {
				rx_slave = slave;
			}
		}
	}

	if (rx_slave) {
		bond_info->next_rx_slave = rx_slave->next;
	}

	return rx_slave;
}
Ejemplo n.º 3
0
/* Caller must hold bond lock for read */
static struct slave*
tlb_get_least_loaded_slave(struct bonding *bond)
{
	struct slave *slave;
	struct slave *least_loaded;
	s64 curr_gap, max_gap;

	/* Find the first enabled slave */
	slave = bond_get_first_slave(bond);
	while (slave) {
		if (SLAVE_IS_OK(slave)) {
			break;
		}
		slave = bond_get_next_slave(bond, slave);
	}

	if (!slave) {
		return NULL;
	}

	least_loaded = slave;
	max_gap = (s64)(slave->speed * 1000000) -
			(s64)(SLAVE_TLB_INFO(slave).load * 8);

	/* Find the slave with the largest gap */
	slave = bond_get_next_slave(bond, slave);
	while (slave) {
		if (SLAVE_IS_OK(slave)) {
			curr_gap = (s64)(slave->speed * 1000000) -
					(s64)(SLAVE_TLB_INFO(slave).load * 8);
			if (max_gap < curr_gap) {
				least_loaded = slave;
				max_gap = curr_gap;
			}
		}
		slave = bond_get_next_slave(bond, slave);
	}

	return least_loaded;
}
Ejemplo n.º 4
0
/* Caller must hold bond lock for read */
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) {
		if (SLAVE_IS_OK(slave)) {
			long long gap = compute_gap(slave);

			if (max_gap < gap) {
				least_loaded = slave;
				max_gap = gap;
			}
		}
	}

	return least_loaded;
}
Ejemplo n.º 5
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;
}