Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit aae8c287 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'bonding_neighbours'



bonding: use neighbours instead of own lists

Veaceslav Falico says:

====================
This patchset introduces all the needed infrastructure, on top of current
adjacent lists, to be able to remove bond's slave_list/slave->list. The
overhead in memory/CPU is minimal, and after the patchset bonding can rely
on its slave-related functions, given the proper locking. I've done some
netperf benchmarks on a vm, and the delta was about 0.1gbps for 35gbps as a
whole, so no speed fluctuations.

It also automatically creates lower/upper and master symlinks in dev's
sysfs directory.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 4ed377e3 5831d66e
Loading
Loading
Loading
Loading
+27 −27
Original line number Diff line number Diff line
@@ -2117,7 +2117,7 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
	read_lock(&bond->lock);

	//check if there are any slaves
	if (list_empty(&bond->slave_list))
	if (!bond_has_slaves(bond))
		goto re_arm;

	// check if agg_select_timer timer after initialize is timed out
@@ -2417,14 +2417,15 @@ int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info)

int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
{
	struct slave *slave, *start_at;
	struct bonding *bond = netdev_priv(dev);
	int slave_agg_no;
	int slaves_in_agg;
	int agg_id;
	int i;
	struct slave *slave, *first_ok_slave;
	struct aggregator *agg;
	struct ad_info ad_info;
	struct list_head *iter;
	int slaves_in_agg;
	int slave_agg_no;
	int res = 1;
	int agg_id;

	read_lock(&bond->lock);
	if (__bond_3ad_get_active_agg_info(bond, &ad_info)) {
@@ -2437,20 +2438,28 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
	agg_id = ad_info.aggregator_id;

	if (slaves_in_agg == 0) {
		/*the aggregator is empty*/
		pr_debug("%s: Error: active aggregator is empty\n", dev->name);
		goto out;
	}

	slave_agg_no = bond->xmit_hash_policy(skb, slaves_in_agg);
	first_ok_slave = NULL;

	bond_for_each_slave(bond, slave) {
		struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator;
	bond_for_each_slave(bond, slave, iter) {
		agg = SLAVE_AD_INFO(slave).port.aggregator;
		if (!agg || agg->aggregator_identifier != agg_id)
			continue;

		if (agg && (agg->aggregator_identifier == agg_id)) {
		if (slave_agg_no >= 0) {
			if (!first_ok_slave && SLAVE_IS_OK(slave))
				first_ok_slave = slave;
			slave_agg_no--;
			if (slave_agg_no < 0)
				break;
			continue;
		}

		if (SLAVE_IS_OK(slave)) {
			res = bond_dev_queue_xmit(bond, skb, slave->dev);
			goto out;
		}
	}

@@ -2460,20 +2469,10 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
		goto out;
	}

	start_at = slave;

	bond_for_each_slave_from(bond, slave, i, start_at) {
		int slave_agg_id = 0;
		struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator;

		if (agg)
			slave_agg_id = agg->aggregator_identifier;

		if (SLAVE_IS_OK(slave) && agg && (slave_agg_id == agg_id)) {
			res = bond_dev_queue_xmit(bond, skb, slave->dev);
			break;
		}
	}
	/* we couldn't find any suitable slave after the agg_no, so use the
	 * first suitable found, if found. */
	if (first_ok_slave)
		res = bond_dev_queue_xmit(bond, skb, first_ok_slave->dev);

out:
	read_unlock(&bond->lock);
@@ -2515,11 +2514,12 @@ int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
void bond_3ad_update_lacp_rate(struct bonding *bond)
{
	struct port *port = NULL;
	struct list_head *iter;
	struct slave *slave;
	int lacp_fast;

	lacp_fast = bond->params.lacp_fast;
	bond_for_each_slave(bond, slave) {
	bond_for_each_slave(bond, slave, iter) {
		port = &(SLAVE_AD_INFO(slave).port);
		__get_state_machine_lock(port);
		if (lacp_fast)
+44 −37
Original line number Diff line number Diff line
@@ -223,13 +223,14 @@ static long long compute_gap(struct slave *slave)
static struct slave *tlb_get_least_loaded_slave(struct bonding *bond)
{
	struct slave *slave, *least_loaded;
	struct list_head *iter;
	long long max_gap;

	least_loaded = NULL;
	max_gap = LLONG_MIN;

	/* Find the slave with the largest gap */
	bond_for_each_slave(bond, slave) {
	bond_for_each_slave(bond, slave, iter) {
		if (SLAVE_IS_OK(slave)) {
			long long gap = compute_gap(slave);

@@ -382,30 +383,31 @@ static int rlb_arp_recv(const struct sk_buff *skb, struct bonding *bond,
static struct slave *rlb_next_rx_slave(struct bonding *bond)
{
	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
	struct slave *rx_slave, *slave, *start_at;
	int i = 0;

	if (bond_info->next_rx_slave)
		start_at = bond_info->next_rx_slave;
	else
		start_at = bond_first_slave(bond);

	rx_slave = NULL;
	struct slave *before = NULL, *rx_slave = NULL, *slave;
	struct list_head *iter;
	bool found = false;

	bond_for_each_slave_from(bond, slave, i, start_at) {
		if (SLAVE_IS_OK(slave)) {
			if (!rx_slave) {
				rx_slave = slave;
			} else if (slave->speed > rx_slave->speed) {
	bond_for_each_slave(bond, slave, iter) {
		if (!SLAVE_IS_OK(slave))
			continue;
		if (!found) {
			if (!before || before->speed < slave->speed)
				before = slave;
		} else {
			if (!rx_slave || rx_slave->speed < slave->speed)
				rx_slave = slave;
		}
		if (slave == bond_info->rx_slave)
			found = true;
	}
	}
	/* we didn't find anything after the current or we have something
	 * better before and up to the current slave
	 */
	if (!rx_slave || (before && rx_slave->speed < before->speed))
		rx_slave = before;

	if (rx_slave) {
		slave = bond_next_slave(bond, rx_slave);
		bond_info->next_rx_slave = slave;
	}
	if (rx_slave)
		bond_info->rx_slave = rx_slave;

	return rx_slave;
}
@@ -1019,7 +1021,7 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[])

	/* loop through vlans and send one packet for each */
	rcu_read_lock();
	netdev_for_each_upper_dev_rcu(bond->dev, upper, iter) {
	netdev_for_each_all_upper_dev_rcu(bond->dev, upper, iter) {
		if (upper->priv_flags & IFF_802_1Q_VLAN)
			alb_send_lp_vid(slave, mac_addr,
					vlan_dev_vlan_id(upper));
@@ -1172,10 +1174,11 @@ static void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *sla
 */
static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slave *slave)
{
	struct slave *tmp_slave1, *free_mac_slave = NULL;
	struct slave *has_bond_addr = bond->curr_active_slave;
	struct slave *tmp_slave1, *free_mac_slave = NULL;
	struct list_head *iter;

	if (list_empty(&bond->slave_list)) {
	if (!bond_has_slaves(bond)) {
		/* this is the first slave */
		return 0;
	}
@@ -1196,7 +1199,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) {
	bond_for_each_slave(bond, tmp_slave1, iter) {
		if (!bond_slave_has_mac(bond, tmp_slave1->perm_hwaddr)) {
			/* no slave has tmp_slave1's perm addr
			 * as its curr addr
@@ -1246,15 +1249,16 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
 */
static int alb_set_mac_address(struct bonding *bond, void *addr)
{
	char tmp_addr[ETH_ALEN];
	struct slave *slave;
	struct slave *slave, *rollback_slave;
	struct list_head *iter;
	struct sockaddr sa;
	char tmp_addr[ETH_ALEN];
	int res;

	if (bond->alb_info.rlb_enabled)
		return 0;

	bond_for_each_slave(bond, slave) {
	bond_for_each_slave(bond, slave, iter) {
		/* save net_device's current hw address */
		memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN);

@@ -1274,10 +1278,12 @@ static int alb_set_mac_address(struct bonding *bond, void *addr)
	sa.sa_family = bond->dev->type;

	/* unwind from head to the slave that failed */
	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);
	bond_for_each_slave(bond, rollback_slave, iter) {
		if (rollback_slave == slave)
			break;
		memcpy(tmp_addr, rollback_slave->dev->dev_addr, ETH_ALEN);
		dev_set_mac_address(rollback_slave->dev, &sa);
		memcpy(rollback_slave->dev->dev_addr, tmp_addr, ETH_ALEN);
	}

	return res;
@@ -1458,11 +1464,12 @@ void bond_alb_monitor(struct work_struct *work)
	struct bonding *bond = container_of(work, struct bonding,
					    alb_work.work);
	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
	struct list_head *iter;
	struct slave *slave;

	read_lock(&bond->lock);

	if (list_empty(&bond->slave_list)) {
	if (!bond_has_slaves(bond)) {
		bond_info->tx_rebalance_counter = 0;
		bond_info->lp_counter = 0;
		goto re_arm;
@@ -1480,7 +1487,7 @@ void bond_alb_monitor(struct work_struct *work)
		 */
		read_lock(&bond->curr_slave_lock);

		bond_for_each_slave(bond, slave)
		bond_for_each_slave(bond, slave, iter)
			alb_send_learning_packets(slave, slave->dev->dev_addr);

		read_unlock(&bond->curr_slave_lock);
@@ -1493,7 +1500,7 @@ void bond_alb_monitor(struct work_struct *work)

		read_lock(&bond->curr_slave_lock);

		bond_for_each_slave(bond, slave) {
		bond_for_each_slave(bond, slave, iter) {
			tlb_clear_slave(bond, slave, 1);
			if (slave == bond->curr_active_slave) {
				SLAVE_TLB_INFO(slave).load =
@@ -1599,13 +1606,13 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave)
 */
void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave)
{
	if (!list_empty(&bond->slave_list))
	if (bond_has_slaves(bond))
		alb_change_hw_addr_on_detach(bond, slave);

	tlb_clear_slave(bond, slave, 0);

	if (bond->alb_info.rlb_enabled) {
		bond->alb_info.next_rx_slave = NULL;
		bond->alb_info.rx_slave = NULL;
		rlb_clear_slave(bond, slave);
	}
}
@@ -1669,7 +1676,7 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
	swap_slave = bond->curr_active_slave;
	rcu_assign_pointer(bond->curr_active_slave, new_slave);

	if (!new_slave || list_empty(&bond->slave_list))
	if (!new_slave || !bond_has_slaves(bond))
		return;

	/* set the new curr_active_slave to the bonds mac address
+1 −3
Original line number Diff line number Diff line
@@ -154,9 +154,7 @@ struct alb_bond_info {
	u8			rx_ntt;	/* flag - need to transmit
					 * to all rx clients
					 */
	struct slave		*next_rx_slave;/* next slave to be assigned
						* to a new rx client for
						*/
	struct slave		*rx_slave;/* last slave to xmit from */
	u8			primary_is_promisc;	   /* boolean */
	u32			rlb_promisc_timeout_counter;/* counts primary
							     * promiscuity time
+156 −140

File changed.

Preview size limit exceeded, changes collapsed.

+3 −2
Original line number Diff line number Diff line
@@ -10,8 +10,9 @@ static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos)
	__acquires(&bond->lock)
{
	struct bonding *bond = seq->private;
	loff_t off = 0;
	struct list_head *iter;
	struct slave *slave;
	loff_t off = 0;

	/* make sure the bond won't be taken away */
	rcu_read_lock();
@@ -20,7 +21,7 @@ static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos)
	if (*pos == 0)
		return SEQ_START_TOKEN;

	bond_for_each_slave(bond, slave)
	bond_for_each_slave(bond, slave, iter)
		if (++off == *pos)
			return slave;

Loading