From: Dave Seddon <dave.seddon.ca@gmail.com>
To: dave.seddon.ca@gmail.com, netdev@vger.kernel.org
Subject: [PATCH iproute2 0/3] iplink: bond: fix partner LACP state decoding
Date: Sat, 10 Oct 2026 20:29:03 -0700 [thread overview]
Message-ID: <20261011032906.1398174-1-dave.seddon.ca@gmail.com> (raw)
I have been using an LLM to help port iproute2's netlink handling to
Go. While comparing the two decoders it flagged that ip reads
IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE one byte wide. I may well be
missing something; details below in case it is real.
Patch 1 is the one-line fix and stands on its own. Patches 2 and 3 add
a test for it. Please take just patch 1 if you would rather not have
the test.
Issue
- kernel sends u16: nla_put_u16() in bond_fill_slave_info(),
drivers/net/bonding/bond_netlink.c:79. The field is
struct port_params.port_state, u16, include/net/bond_3ad.h:205.
- iproute2 reads u8: rta_getattr_u8() in bond_slave_print_opt(),
ip/iplink_bond_slave.c:148.
- little endian: first byte is the low byte. Output is right because
the kernel never sets bits above 0xff (the value comes from the
one-byte LACPDU actor_state, bond_3ad.c:562).
- big endian: first byte is the always-zero high byte. Every bond port
prints:
ad_partner_oper_port_state 0 ad_partner_oper_port_state_str <>
Reproduced on s390x under qemu-user by replaying a generated message.
- regressed in 39ac2d2b802b (v5.6.0). That commit added the _str
output and copied the actor (u8) block for the partner. The code
before it used rta_getattr_u16().
- the kernel width is old: u16 in the struct since 1055c9aba3b6
(2008), exported as u16 since 46ea297ed67c (2015). sysfs and the
YNL spec agree with it, so the fix belongs in iproute2.
- /proc/net/bonding and sysfs read the struct directly and are fine,
which is probably why nobody noticed.
- the other bond and bond slave attributes match bond_netlink.c; this
is the only width mismatch.
Test
- tools/generate_nlmsg writes four RTM_NEWLINK blobs for a bond slave
with partner state 0x003f, 0x0000, 0x0100 and absent.
- tests/ip/link/show_bond_slave_lacp_state.t decodes them with
"ip -d monitor file" and checks the printed value. No root needed.
- 0x0100 cannot occur in real LACP. A one-byte reader prints 0 for it
on little endian and 1 on big endian; only a u16 reader prints 256.
That makes the bug visible on x86_64 too.
How it was tested
- x86_64, native: new test red with patch 1 reverted (0x0100 prints 0),
green with it.
- s390x, qemu-user: the blobs were written by an s390x build of
generate_nlmsg, so they are big endian (partner payload 01 00 for
0x0100). ip built with and without patch 1:
without: 0x3f prints "0 <>", 0x0100 prints "1 <active>"
with: 0x3f prints "63 <active,...>", 0x0100 prints "256"
- results: without patch 1, 1 of 6 checks fails on x86_64 and 2 of 6
on s390x. With it, all pass on both.
- whole testsuite, rootless, with the series: no change. add_tunnel.t
and the two netns/set_nsid tests fail (no module load, no
/var/run/netns), the same as on unpatched e11870d5.
- test_on_not fix checked against matching, mixed, absent and empty
output, a bad regex and a missing file.
- builds with no warnings. checkpatch --strict is clean apart from the
exec bit on the new .t, which matches the existing .t files.
- the new .t is shellcheck clean and passes under dash, busybox sh and
bash --posix, so it does not depend on what /bin/sh points to.
Fix
- patch 1: rta_getattr_u8 -> rta_getattr_u16.
- patch 2: lib/generic.sh test_on_not uses "grep -vqE", which passes
whenever any line does not match. Fixed so the new test can use it.
Its one caller, tests/bridge/vlan/show.t, still passes.
- patch 3: the test.
LLM use
- The LLM spotted the mismatch, wrote the patches and drafted this
letter. Each patch carries Assisted-by: LLM.
- Every result above comes from running the code, natively and under
qemu-s390x. I have read all of it and can answer for it.
Dave Seddon (3):
iplink_bond_slave: read ad_partner_oper_port_state as u16
testsuite: fix test_on_not on multi-line output
testsuite: add bond slave LACP port state test
.gitignore | 1 +
ip/iplink_bond_slave.c | 2 +-
testsuite/Makefile | 1 +
testsuite/lib/generic.sh | 5 +-
.../ip/link/show_bond_slave_lacp_state.t | 33 ++++++
testsuite/tools/generate_nlmsg.c | 103 ++++++++++++++++--
6 files changed, 133 insertions(+), 12 deletions(-)
create mode 100755 testsuite/tests/ip/link/show_bond_slave_lacp_state.t
--
2.55.0
next reply other threads:[~2026-10-11 3:29 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-11 3:29 Dave Seddon [this message]
2026-10-11 3:29 ` [PATCH iproute2 1/3] iplink_bond_slave: read ad_partner_oper_port_state as u16 Dave Seddon
2026-10-11 3:29 ` [PATCH iproute2 2/3] testsuite: fix test_on_not on multi-line output Dave Seddon
2026-10-11 3:29 ` [PATCH iproute2 3/3] testsuite: add bond slave LACP port state test Dave Seddon
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=20261011032906.1398174-1-dave.seddon.ca@gmail.com \
--to=dave.seddon.ca@gmail.com \
--cc=netdev@vger.kernel.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