Netdev List
 help / color / mirror / Atom feed
From: Yun Lu <luyun_611@163.com>
To: jv@jvosburgh.net, andrew+netdev@lunn.ch, davem@davemloft.net,
	edumazet@google.com, kuba@kernel.org, pabeni@redhat.com
Cc: razor@blackwall.org, maheshb@google.com, netdev@vger.kernel.org
Subject: [PATCH net] bonding: 3ad: select a port when the TX array is empty
Date: Tue, 15 Sep 2026 17:02:07 +0800	[thread overview]
Message-ID: <20260915090207.110987-1-luyun_611@163.com> (raw)

From: Yun Lu <luyun@kylinos.cn>

During 802.3ad bond bring-up, userspace can observe carrier up while
ARP requests still fail to transmit. This can happen even though the
active aggregator already has ports eligible for transmission.

Commit 23de0d7b6f0e ("bonding: pair enable_port with
slave_arr_updates") made port enablement request an array rebuild, but
the rebuild remains asynchronous. The 802.3ad state machine enables a
port before queueing slave_arr_work. Until the worker publishes the new
usable_slaves array, the transmit path drops packets. RTNL contention
can prolong this window because the worker retries later.

When ordinary 802.3ad skb transmission finds an empty usable array,
select a port directly from the active aggregator. Hold mode_lock across
the counting and selection passes so aggregator reselection cannot expose
the intermediate state where all is_active flags are clear. The caller's
RCU read lock protects the slave lifetime.

Use the same bond_slave_can_tx() eligibility and list order as the array
path, so hash selection remains equivalent when the eligible set is
stable. Skip the fallback in netpoll context because TX may be re-entered
while mode_lock is already held.

Fixes: ee6377147409 ("bonding: Simplify the xmit function for modes that use xmit_hash")
Signed-off-by: Yun Lu <luyun@kylinos.cn>
---
 drivers/net/bonding/bond_main.c | 66 +++++++++++++++++++++++++++++++--
 1 file changed, 62 insertions(+), 4 deletions(-)

diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index a9bff7663eec..2cf280bf134f 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -5233,11 +5233,11 @@ static struct slave *bond_xmit_3ad_xor_slave_get(struct bonding *bond,
 	unsigned int count;
 	u32 hash;
 
-	hash = bond_xmit_hash(bond, skb);
 	count = slaves ? READ_ONCE(slaves->count) : 0;
 	if (unlikely(!count))
 		return NULL;
 
+	hash = bond_xmit_hash(bond, skb);
 	slave = slaves->arr[hash % count];
 	return slave;
 }
@@ -5289,9 +5289,65 @@ static bool bond_should_broadcast_neighbor(struct sk_buff *skb,
 	return false;
 }
 
-/* Use this Xmit function for 3AD as well as XOR modes. The current
- * usable slave array is formed in the control path. The xmit function
- * just calculates hash and sends the packet out.
+/* Called with RCU and bond->mode_lock held. */
+static bool bond_3ad_slave_is_eligible(struct slave *slave)
+{
+	const struct aggregator *agg;
+
+	agg = rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator);
+	return agg && agg->is_active && bond_slave_can_tx(slave);
+}
+
+/* Called with RCU held when the transmit array has not caught up with
+ * the 802.3ad state machine. Do not enable ports here: use the same
+ * eligibility checks as bond_update_slave_arr().
+ */
+static struct slave *bond_3ad_xmit_fallback(struct bonding *bond, u32 hash)
+{
+	struct slave *selected = NULL;
+	unsigned int eligible = 0;
+	unsigned int target;
+	struct list_head *iter;
+	struct slave *slave;
+
+	/* Netpoll can re-enter TX while the state machine holds mode_lock.
+	 * Keep the existing empty-array drop behavior in that context.
+	 */
+	if (unlikely(netpoll_tx_running(bond->dev)))
+		return NULL;
+
+	/* Aggregator selection temporarily clears all is_active flags. Keep
+	 * both loops under mode_lock to avoid observing that intermediate
+	 * state. The caller's RCU read lock protects the selected slave.
+	 */
+	spin_lock_bh(&bond->mode_lock);
+	bond_for_each_slave_rcu(bond, slave, iter)
+		if (bond_3ad_slave_is_eligible(slave))
+			eligible++;
+
+	if (!eligible)
+		goto out;
+
+	target = hash % eligible;
+	bond_for_each_slave_rcu(bond, slave, iter) {
+		if (!bond_3ad_slave_is_eligible(slave))
+			continue;
+
+		if (!target) {
+			selected = slave;
+			break;
+		}
+		target--;
+	}
+
+out:
+	spin_unlock_bh(&bond->mode_lock);
+	return selected;
+}
+
+/* Use this Xmit function for 3AD as well as XOR modes. The usable slave
+ * array is formed in the control path.  In 3AD mode, fall back to the
+ * current port state while an empty array awaits an update.
  */
 static netdev_tx_t bond_3ad_xor_xmit(struct sk_buff *skb,
 				     struct net_device *dev)
@@ -5302,6 +5358,8 @@ static netdev_tx_t bond_3ad_xor_xmit(struct sk_buff *skb,
 
 	slaves = rcu_dereference(bond->usable_slaves);
 	slave = bond_xmit_3ad_xor_slave_get(bond, skb, slaves);
+	if (unlikely(!slave) && BOND_MODE(bond) == BOND_MODE_8023AD)
+		slave = bond_3ad_xmit_fallback(bond, bond_xmit_hash(bond, skb));
 	if (likely(slave))
 		return bond_dev_queue_xmit(bond, skb, slave->dev);
 
-- 
2.43.0


             reply	other threads:[~2026-09-15  9:03 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-15  9:02 Yun Lu [this message]
2026-09-17 21:02 ` [PATCH net] bonding: 3ad: select a port when the TX array is empty netdev-bot+sashiko
2026-09-18  9:37   ` luyun

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260915090207.110987-1-luyun_611@163.com \
    --to=luyun_611@163.com \
    --cc=andrew+netdev@lunn.ch \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=jv@jvosburgh.net \
    --cc=kuba@kernel.org \
    --cc=maheshb@google.com \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=razor@blackwall.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox