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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.