* Re: [PATCH] bonding: alb: Fix overflow in TLB gap calculation
2026-09-13 12:58 [PATCH] bonding: alb: Fix overflow in TLB gap calculation lirongqing
@ 2026-09-14 3:24 ` Xuanqiang Luo
2026-09-14 13:49 ` netdev-bot+sashiko
1 sibling, 0 replies; 3+ messages in thread
From: Xuanqiang Luo @ 2026-09-14 3:24 UTC (permalink / raw)
To: lirongqing
Cc: stable, Jay Vosburgh, Andrew Lunn, David S . Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Jiri Pirko, netdev,
linux-kernel
在 2026/9/13 20:58, lirongqing 写道:
> From: Li RongQing <lirongqing@baidu.com>
>
> compute_gap() shifts 32-bit values before converting them to s64,
> which can overflow for high speed network devices. The overflowed
> value is then incorrectly used in the TLB load balancing calculation.
>
> Convert the operands to s64 before shifting so the arithmetic is done
> in 64-bit width.
>
> Fixes: 097811bb48c7 ("bonding: optimize tlb_get_least_loaded_slave")
> Cc: stable@vger.kernel.org
> Signed-off-by: Li RongQing <lirongqing@baidu.com>
> ---
> drivers/net/bonding/bond_alb.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
> index 43ac8e2..b520040 100644
> --- a/drivers/net/bonding/bond_alb.c
> +++ b/drivers/net/bonding/bond_alb.c
> @@ -160,8 +160,8 @@ static void tlb_deinitialize(struct bonding *bond)
>
> static long long compute_gap(struct slave *slave)
> {
> - return (s64) (slave->speed << 20) - /* Convert to Megabit per sec */
> - (s64) (SLAVE_TLB_INFO(slave).load << 3); /* Bytes to bits */
> + return ((s64)slave->speed << 20) - /* Convert to Megabit per sec */
> + ((s64)SLAVE_TLB_INFO(slave).load << 3); /* Bytes to bits */
> }
>
> static struct slave *tlb_get_least_loaded_slave(struct bonding *bond)
This appears to have already been fixed by Hangbin Liu.
Please see:
https://lore.kernel.org/all/20260831-bond_overflow-v6-2-ffb0ed1f7268@kylinos.cn/
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH] bonding: alb: Fix overflow in TLB gap calculation
2026-09-13 12:58 [PATCH] bonding: alb: Fix overflow in TLB gap calculation lirongqing
2026-09-14 3:24 ` Xuanqiang Luo
@ 2026-09-14 13:49 ` netdev-bot+sashiko
1 sibling, 0 replies; 3+ messages in thread
From: netdev-bot+sashiko @ 2026-09-14 13:49 UTC (permalink / raw)
To: lirongqing
Cc: jv, andrew+netdev, davem, edumazet, kuba, pabeni, jiri, netdev,
linux-kernel, stable
Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider:
Critical: 0 · High: 1 · Medium: 0 · Low: 0 (1)
- [High] compute_gap() (drivers/net/bonding/bond_alb.c:163) now widens
slave->speed to 64 bits before shifting, but slave->speed is a u32…
Pre-existing issues:
- [Low] The comment retained on the rewritten line, `/* Convert to
Megabit per sec */` (drivers/net/bonding/bond_alb.c:163), mislabels…
--
bonding: alb: Fix overflow in TLB gap calculation
This changes compute_gap() in the TLB/ALB balancer so that slave->speed and
the per-slave TLB load are cast to s64 before being shifted, rather than
being shifted in 32-bit width and cast afterwards. The stated goal is to
avoid overflow of the gap value on high speed devices.
> diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
> index 43ac8e28e4182..b52004030a4b0 100644
> --- a/drivers/net/bonding/bond_alb.c
> +++ b/drivers/net/bonding/bond_alb.c
> @@ -160,8 +160,8 @@ static void tlb_deinitialize(struct bonding *bond)
>
> static long long compute_gap(struct slave *slave)
> {
> - return (s64) (slave->speed << 20) - /* Convert to Megabit per sec */
> - (s64) (SLAVE_TLB_INFO(slave).load << 3); /* Bytes to bits */
> + return ((s64)slave->speed << 20) - /* Convert to Megabit per sec */
[Severity: High]
What happens here when slave->speed holds SPEED_UNKNOWN?
slave->speed is a u32, and bond_update_speed_duplex() in bond_main.c stores
the sentinel on its failure path:
drivers/net/bonding/bond_main.c:bond_update_speed_duplex() {
...
speed_duplex_unknown:
slave->speed = SPEED_UNKNOWN;
slave->duplex = DUPLEX_UNKNOWN;
}
That is (u32)-1, so after the new pre-shift cast the first term becomes
((s64)0xFFFFFFFF << 20), roughly 4.5e15. The load term can never offset
that: ((s64)U32_MAX << 3) is only about 3.4e10, and even a real 100 Gbit/s
slave reaches only about 1.05e11.
Does that make tlb_get_least_loaded_slave() pick the unknown-speed slave
permanently?
bond_for_each_slave_rcu(bond, slave, iter) {
if (bond_slave_can_tx(slave)) {
long long gap = compute_gap(slave);
if (max_gap < gap) {
least_loaded = slave;
max_gap = gap;
}
}
}
bond_slave_can_tx() in include/net/bonding.h only checks up/link/active and
never looks at speed:
return bond_slave_is_up(slave) && slave->link == BOND_LINK_UP &&
bond_is_active_slave(slave);
so the sentinel reaches the comparison and every newly hashed TLB client
lands on that slave. Since the periodic rebalance clears assignments, would
this end up steering effectively all clients onto it?
Before this change the sentinel was shifted in 32-bit width, giving
0xFFFFFFFF << 20 == 0xFFF00000 (about 4.29e9), which the load term could
grow past, so the imbalance corrected itself. Does widening the arithmetic
remove that accidental cap and make it permanent?
Some paths where a tx-eligible TLB slave can carry SPEED_UNKNOWN:
- bond_enslave() sets new_slave->link = BOND_LINK_DOWN when the speed query
fails and bond_needs_speed_duplex(), but a few lines later does
new_slave->link = BOND_LINK_NOCHANGE, and the final else branch sets
BOND_LINK_UP when both miimon and arp_interval are 0.
- bond_slave_netdev_event() on NETDEV_UP/NETDEV_CHANGE only forces a
down/fail state for BOND_MODE_8023AD:
if (bond_update_speed_duplex(slave) &&
BOND_MODE(bond) == BOND_MODE_8023AD) {
- bond_ethtool_get_link_ksettings() re-runs bond_update_speed_duplex() on an
already tx-capable slave and can latch SPEED_UNKNOWN without touching
slave->link:
bond_update_speed_duplex(slave);
netdev_unlock_ops(slave->dev);
if (slave->speed != SPEED_UNKNOWN) {
Would it make sense to also clamp or skip SPEED_UNKNOWN in compute_gap()
(treat it as 0, or exclude the slave) alongside the widening?
> + ((s64)SLAVE_TLB_INFO(slave).load << 3); /* Bytes to bits */
> }
>
> static struct slave *tlb_get_least_loaded_slave(struct bonding *bond)
[Severity: Low]
This isn't a bug introduced by this patch, but since the line is being
rewritten anyway: is the retained comment /* Convert to Megabit per sec */
accurate?
slave->speed is already in Mbit/s. It is copied straight from ethtool in
bond_update_speed_duplex():
slave->speed = ecmd.base.speed;
and bond_procfs.c prints it as:
seq_printf(seq, "Speed: %d Mbps\n", slave->speed);
So the << 20 goes from Mbit/s to bit/s, matching the second term whose
comment already says /* Bytes to bits */ (load_history is documented in
include/net/bond_alb.h as being in Bps). As written, a reader auditing units
would conclude the two subtracted terms are in different units. Would
something like /* Mbit/s to bit/s */ be clearer?
Also, << 20 scales by 1048576 while a megabit is 10^6 bits, about a 4.9%
bias. Presumably that is intentional, but nothing in the code says so.
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260913125859.2349-1-lirongqing%40baidu.com
^ permalink raw reply [flat|nested] 3+ messages in thread