From: Dave Seddon <dave.seddon.ca@gmail.com>
To: dave.seddon.ca@gmail.com, netdev@vger.kernel.org
Subject: [PATCH iproute2 3/3] testsuite: add bond slave LACP port state test
Date: Sat, 10 Oct 2026 20:29:06 -0700 [thread overview]
Message-ID: <20261011032906.1398174-4-dave.seddon.ca@gmail.com> (raw)
In-Reply-To: <20261011032906.1398174-1-dave.seddon.ca@gmail.com>
Decode generated RTM_NEWLINK messages with ip -d monitor file and
check the partner state value and flags, the u8 actor state, and
zero and absent partner attributes.
Use a synthetic 0x0100 partner state to detect a one-byte reader on
both endian types: it returns 0 on little-endian and 1 on big-endian
instead of 256. Real LACP states use only the low eight bits.
Check the actor state before asserting partner attribute absence,
so empty output cannot satisfy that test.
Assisted-by: LLM
Signed-off-by: Dave Seddon <dave.seddon.ca@gmail.com>
---
.gitignore | 1 +
testsuite/Makefile | 1 +
.../ip/link/show_bond_slave_lacp_state.t | 33 ++++++
testsuite/tools/generate_nlmsg.c | 103 ++++++++++++++++--
4 files changed, 129 insertions(+), 9 deletions(-)
create mode 100755 testsuite/tests/ip/link/show_bond_slave_lacp_state.t
diff --git a/.gitignore b/.gitignore
index e5234a3d..a16f6362 100644
--- a/.gitignore
+++ b/.gitignore
@@ -39,3 +39,4 @@ testsuite/results
testsuite/iproute2/iproute2-this
testsuite/tools/generate_nlmsg
testsuite/tests/ip/link/dev_wo_vf_rate.nl
+testsuite/tests/ip/link/bond_slave_partner_*.nl
diff --git a/testsuite/Makefile b/testsuite/Makefile
index fb50f618..bef66002 100644
--- a/testsuite/Makefile
+++ b/testsuite/Makefile
@@ -48,6 +48,7 @@ testclean:
clean: testclean
@rm -f iproute2/iproute2-this
@rm -f tests/ip/link/dev_wo_vf_rate.nl
+ @rm -f tests/ip/link/bond_slave_partner_*.nl
$(MAKE) -C tools clean
distclean: clean
diff --git a/testsuite/tests/ip/link/show_bond_slave_lacp_state.t b/testsuite/tests/ip/link/show_bond_slave_lacp_state.t
new file mode 100755
index 00000000..4ccf3960
--- /dev/null
+++ b/testsuite/tests/ip/link/show_bond_slave_lacp_state.t
@@ -0,0 +1,33 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+
+. lib/generic.sh
+
+# IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE is a u16 on the wire; the
+# actor state next to it is a u8. Each row decodes one blob written by
+# tools/generate_nlmsg and checks the printed value.
+#
+# The synthetic 0x0100 state checks the full attribute width on either
+# endian: a u8 reader returns 0 on little-endian and 1 on big-endian.
+#
+# row: file suffix | description | expected regex (!regex: must be absent)
+while IFS='|' read -r suffix desc expect; do
+ [ -z "$suffix" ] && continue
+ NL_FILE="tests/ip/link/bond_slave_partner_${suffix}.nl"
+ ts_ip "$0" "$desc" -d monitor file "$NL_FILE"
+ case "$expect" in
+ !*)
+ test_on "ad_actor_oper_port_state 63[^0-9]"
+ test_on_not "${expect#!}"
+ ;;
+ *)
+ test_on "$expect"
+ ;;
+ esac
+done <<EOF
+fast|partner state 0x3f|ad_partner_oper_port_state 63 ad_partner_oper_port_state_str <active,short_timeout,aggregating,in_sync,collecting,distributing>
+fast|actor state stays u8|ad_actor_oper_port_state 63[^0-9]
+zero|partner state 0|ad_partner_oper_port_state 0 ad_partner_oper_port_state_str <>
+hionly|partner state 0x0100, high byte only|ad_partner_oper_port_state 256[^0-9]
+absent|no partner attribute|!ad_partner_oper_port_state
+EOF
diff --git a/testsuite/tools/generate_nlmsg.c b/testsuite/tools/generate_nlmsg.c
index 106dca63..7c0aed3a 100644
--- a/testsuite/tools/generate_nlmsg.c
+++ b/testsuite/tools/generate_nlmsg.c
@@ -11,6 +11,9 @@
#include <linux/if.h>
#include <errno.h>
#include <stdio.h>
+#include <string.h>
+#include <linux/if_link.h>
+#include "utils.h"
int fill_vf_rate_test(void *buf, size_t buflen)
{
@@ -40,6 +43,7 @@ int fill_vf_rate_test(void *buf, size_t buflen)
#define ASSERT(x) if (x < 0) return -1
#define ATTR_L(t, v, l) ASSERT(addattr_l(h, buflen, t, v, l))
#define ATTR_8(t, v) ASSERT(addattr8(h, buflen, t, v))
+#define ATTR_16(t, v) ASSERT(addattr16(h, buflen, t, v))
#define ATTR_32(t, v) ASSERT(addattr32(h, buflen, t, v))
#define ATTR_STRZ(t, v) ASSERT(addattrstrz(h, buflen, t, v))
@@ -87,26 +91,107 @@ int fill_vf_rate_test(void *buf, size_t buflen)
return h->nlmsg_len;
}
+/* The synthetic 0x0100 state detects a u8 reader on either endian. */
+struct bond_slave_case {
+ const char *file;
+ __u16 partner_state;
+ bool has_partner;
+};
+
+static const struct bond_slave_case bond_slave_cases[] = {
+ { "tests/ip/link/bond_slave_partner_fast.nl", 0x003f, true },
+ { "tests/ip/link/bond_slave_partner_zero.nl", 0x0000, true },
+ { "tests/ip/link/bond_slave_partner_hionly.nl", 0x0100, true },
+ { "tests/ip/link/bond_slave_partner_absent.nl", 0x0000, false },
+};
+
+static int fill_bond_slave_test(void *buf, size_t buflen,
+ const struct bond_slave_case *c)
+{
+ __u8 mac[ETH_ALEN] = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x01 };
+ struct rtattr *linkinfo, *slave_data;
+ struct nlmsghdr *h = buf;
+ struct ifinfomsg *ifi;
+
+ memset(buf, 0, buflen);
+ h->nlmsg_type = RTM_NEWLINK;
+ h->nlmsg_len = NLMSG_LENGTH(sizeof(*ifi));
+
+ ifi = NLMSG_DATA(h);
+ ifi->ifi_type = ARPHRD_ETHER;
+ ifi->ifi_index = 2;
+ ifi->ifi_flags = IFF_RUNNING | IFF_BROADCAST | IFF_MULTICAST |
+ IFF_UP | IFF_LOWER_UP | IFF_SLAVE;
+
+ ATTR_STRZ(IFLA_IFNAME, "eth1");
+ ATTR_32(IFLA_MTU, 1500);
+ ATTR_L(IFLA_ADDRESS, mac, sizeof(mac));
+
+ linkinfo = NEST(IFLA_LINKINFO);
+ ATTR_STRZ(IFLA_INFO_SLAVE_KIND, "bond");
+ slave_data = NEST(IFLA_INFO_SLAVE_DATA);
+ ATTR_8(IFLA_BOND_SLAVE_STATE, 0);
+ ATTR_8(IFLA_BOND_SLAVE_MII_STATUS, 0);
+ ATTR_32(IFLA_BOND_SLAVE_LINK_FAILURE_COUNT, 0);
+ ATTR_L(IFLA_BOND_SLAVE_PERM_HWADDR, mac, sizeof(mac));
+ ATTR_16(IFLA_BOND_SLAVE_QUEUE_ID, 0);
+ ATTR_16(IFLA_BOND_SLAVE_AD_AGGREGATOR_ID, 1);
+ ATTR_8(IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE, 0x3f);
+ if (c->has_partner)
+ ATTR_16(IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE,
+ c->partner_state);
+ NEST_END(slave_data);
+ NEST_END(linkinfo);
+
+ return h->nlmsg_len;
+}
+
+static int write_nlmsg(const char *file, const void *buf, int msglen)
+{
+ FILE *fp;
+
+ fp = fopen(file, "wb");
+ if (!fp) {
+ perror("fopen()");
+ return -1;
+ }
+ if (fwrite(buf, msglen, 1, fp) != 1) {
+ perror("fwrite()");
+ fclose(fp);
+ return -1;
+ }
+ if (fclose(fp)) {
+ perror("fclose()");
+ return -1;
+ }
+ return 0;
+}
+
int main(void)
{
char buf[16384] = { 0 };
+ unsigned int i;
int msglen;
- FILE *fp;
msglen = fill_vf_rate_test(buf, sizeof(buf));
if (msglen < 0) {
fprintf(stderr, "fill_vf_rate_test() failed!\n");
return 1;
}
- fp = fopen("tests/ip/link/dev_wo_vf_rate.nl", "w");
- if (!fp) {
- perror("fopen()");
- return 1;
- }
- if (fwrite(buf, msglen, 1, fp) != 1) {
- perror("fwrite()");
+ if (write_nlmsg("tests/ip/link/dev_wo_vf_rate.nl", buf, msglen))
return 1;
+
+ for (i = 0; i < ARRAY_SIZE(bond_slave_cases); i++) {
+ const struct bond_slave_case *c = &bond_slave_cases[i];
+
+ msglen = fill_bond_slave_test(buf, sizeof(buf), c);
+ if (msglen < 0) {
+ fprintf(stderr, "fill_bond_slave_test(%s) failed!\n",
+ c->file);
+ return 1;
+ }
+ if (write_nlmsg(c->file, buf, msglen))
+ return 1;
}
- fclose(fp);
return 0;
}
--
2.55.0
prev parent 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 [PATCH iproute2 0/3] iplink: bond: fix partner LACP state decoding Dave Seddon
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 ` Dave Seddon [this message]
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-4-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