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
next 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