All of lore.kernel.org
 help / color / mirror / Atom feed
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


             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.