]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
selftests: bonding: add test for lacp_strict mode
authorLouis Scalbert <louis.scalbert@6wind.com>
Wed, 3 Jun 2026 15:03:31 +0000 (17:03 +0200)
committerJakub Kicinski <kuba@kernel.org>
Wed, 10 Jun 2026 14:53:41 +0000 (07:53 -0700)
Add a test for the bonding lacp_strict mode.

Signed-off-by: Louis Scalbert <louis.scalbert@6wind.com>
Acked-by: Jay Vosburgh <jv@jvosburgh.net>
Link: https://patch.msgid.link/20260603150331.1919611-7-louis.scalbert@6wind.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
tools/testing/selftests/drivers/net/bonding/Makefile
tools/testing/selftests/drivers/net/bonding/bond_lacp_strict.sh [new file with mode: 0755]

index 9af5f84edd3746e4c7610199e97039db9aefce25..be130bf585a419df8aa5d50b0b18e6effe780334 100644 (file)
@@ -8,6 +8,7 @@ TEST_PROGS := \
        bond-lladdr-target.sh \
        bond_ipsec_offload.sh \
        bond_lacp_prio.sh \
+       bond_lacp_strict.sh \
        bond_macvlan_ipvlan.sh \
        bond_options.sh \
        bond_passive_lacp.sh \
diff --git a/tools/testing/selftests/drivers/net/bonding/bond_lacp_strict.sh b/tools/testing/selftests/drivers/net/bonding/bond_lacp_strict.sh
new file mode 100755 (executable)
index 0000000..f1a93a1
--- /dev/null
@@ -0,0 +1,347 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Testing if bond lacp_strict works
+#
+#          Partner (p_ns)
+#  +--------------------------+
+#  |          bond0           |
+#  |            +             |
+#  |      eth0  |  eth1       |
+#  |        +---+---+         |
+#  |        |       |         |
+#  +--------------------------+
+#  |        | eth0  | eth1    |
+#  |        |       |         |
+#  |(br_ns) | br0   | br1     |
+#  |        |       |         |
+#  |        | eth2  | eth3    |
+#  +--------------------------+
+#  |        |       |         |
+#  |        +---+---+         |
+#  |      eth0  |  eth1       |
+#  |            +             |
+#  |          bond0           |
+#  +--------------------------+
+#         Dut (d_ns)
+
+lib_dir=$(dirname "$0")
+# shellcheck disable=SC1090
+source "$lib_dir"/../../../net/lib.sh
+
+COLLECTING_DISTRIBUTING_MASK=48
+COLLECTING_DISTRIBUTING=48
+FAILED=0
+
+setup_links()
+{
+       # shellcheck disable=SC2154
+       ip -n "${p_ns}" link add eth0 type veth peer name eth0 netns "${br_ns}"
+       ip -n "${p_ns}" link add eth1 type veth peer name eth1 netns "${br_ns}"
+       ip -n "${d_ns}" link add eth0 type veth peer name eth2 netns "${br_ns}"
+       ip -n "${d_ns}" link add eth1 type veth peer name eth3 netns "${br_ns}"
+
+       ip -n "${br_ns}" link add br0 type bridge
+       ip -n "${br_ns}" link add br1 type bridge
+
+       ip -n "${br_ns}" link set dev br0 type bridge stp_state 0
+       ip -n "${br_ns}" link set dev br1 type bridge stp_state 0
+
+       ip -n "${br_ns}" link set eth0 master br0
+       ip -n "${br_ns}" link set eth2 master br0
+       ip -n "${br_ns}" link set eth1 master br1
+       ip -n "${br_ns}" link set eth3 master br1
+
+       # Allow LACP trames forwarding on bridge ports
+       ip netns exec "${br_ns}" sh -c "echo 4 > /sys/class/net/br0/brif/eth0/group_fwd_mask"
+       ip netns exec "${br_ns}" sh -c "echo 4 > /sys/class/net/br1/brif/eth1/group_fwd_mask"
+       ip netns exec "${br_ns}" sh -c "echo 4 > /sys/class/net/br0/brif/eth2/group_fwd_mask"
+       ip netns exec "${br_ns}" sh -c "echo 4 > /sys/class/net/br1/brif/eth3/group_fwd_mask"
+
+       ip -n "${br_ns}" link set eth0 up
+       ip -n "${br_ns}" link set eth2 up
+       ip -n "${br_ns}" link set eth1 up
+       ip -n "${br_ns}" link set eth3 up
+
+       ip -n "${br_ns}" link set br0 up
+       ip -n "${br_ns}" link set br1 up
+
+       ip -n "${d_ns}" link add bond0 type bond mode 802.3ad miimon 100 \
+               lacp_rate fast min_links 1
+       ip -n "${p_ns}" link add bond0 type bond mode 802.3ad miimon 100 \
+               lacp_rate fast min_links 1
+
+       ip -n "${d_ns}" link set eth0 master bond0
+       ip -n "${d_ns}" link set eth1 master bond0
+       ip -n "${p_ns}" link set eth0 master bond0
+       ip -n "${p_ns}" link set eth1 master bond0
+
+       ip -n "${d_ns}" link set bond0 up
+       ip -n "${p_ns}" link set bond0 up
+}
+
+test_master_carrier() {
+       local expected=$1
+       local mode_name=$2
+       local carrier
+
+       carrier=$(ip netns exec "${d_ns}" cat /sys/class/net/bond0/carrier)
+       [ "$carrier" == "1" ] && carrier="up" || carrier="down"
+
+       [ "$carrier" == "$expected" ] && return
+
+       echo "FAIL: Expected carrier $expected in lacp_strict $mode_name mode, got $carrier"
+
+       RET=1
+
+}
+
+compare_state() {
+       local actual_state=$1
+       local expected_state=$2
+       local iface=$3
+       local last_attempt=$4
+
+    [ $((actual_state & COLLECTING_DISTRIBUTING_MASK)) -eq "$expected_state" ] \
+               && return 0
+
+       [ "$last_attempt" -ne 1 ] && return 1
+
+       printf "FAIL: Expected LACP %s actor state to " "$iface"
+       if [ "$expected_state" -eq $COLLECTING_DISTRIBUTING ]; then
+               echo "be in Collecting/Distributing state"
+       else
+               echo "have neither Collecting nor Distributing set."
+       fi
+
+       return 1
+}
+
+_test_lacp_port_state() {
+       local interface=$1
+       local expected=$2
+       local last_attempt=$3
+       local eth0_actor_state eth1_actor_state
+       local ret=0
+
+       # shellcheck disable=SC2016
+       while IFS='=' read -r k v; do
+               printf -v "$k" '%s' "$v"
+       done < <(
+               ip netns exec "${d_ns}" awk '
+               /^Slave Interface: / { iface=$3 }
+               /details actor lacp pdu:/ { ctx="actor" }
+               /details partner lacp pdu:/ { ctx="partner" }
+               /^[[:space:]]+port state: / {
+                       if (ctx == "actor") {
+                               gsub(":", "", iface)
+                               printf "%s_%s_state=%s\n", iface, ctx, $3
+                       }
+               }
+               ' /proc/net/bonding/bond0
+       )
+
+       if [ "$interface" == "eth0" ] || [ "$interface" == "both" ]; then
+               compare_state "$eth0_actor_state" "$expected" eth0 "$last_attempt" || ret=1
+       fi
+
+       if [ "$interface" == "eth1" ] || [ "$interface" == "both" ]; then
+               compare_state "$eth1_actor_state" "$expected" eth1 "$last_attempt" || ret=1
+       fi
+
+       return $ret
+}
+
+test_lacp_port_state() {
+       local interface=$1
+       local expected=$2
+       local retry=$3
+       local last_attempt=0
+       local attempt=1
+       local ret=1
+
+       while [ $attempt -le $((retry + 1)) ]; do
+               [ $attempt -eq $((retry + 1)) ] && last_attempt=1
+               _test_lacp_port_state "$interface" "$expected" "$last_attempt" && return
+               ((attempt++))
+               sleep 1
+       done
+
+       RET=1
+}
+
+
+trap cleanup_all_ns EXIT
+setup_ns d_ns p_ns br_ns
+setup_links
+
+# Initial state
+RET=0
+mode=off
+test_lacp_port_state both $COLLECTING_DISTRIBUTING 3
+test_master_carrier up $mode
+log_test "bond LACP" "lacp_strict $mode - eth0 and eth1 up"
+
+# partner eth0 down, eth1 up
+# (replicate eth0 state to dut eth0 by shutting a bridge port)
+RET=0
+ip -n "${p_ns}" link set eth0 down
+ip -n "${br_ns}" link set eth2 down
+test_lacp_port_state eth0 $FAILED 5
+test_lacp_port_state eth1 $COLLECTING_DISTRIBUTING 1
+test_master_carrier up $mode
+log_test "bond LACP" "lacp_strict $mode - eth0 down"
+
+# partner eth0 and eth1 down
+RET=0
+ip -n "${p_ns}" link set eth1 down
+ip -n "${br_ns}" link set eth3 down
+test_lacp_port_state both $FAILED 5
+test_master_carrier down $mode # down because of min_links
+log_test "bond LACP" "lacp_strict $mode - eth0 and eth1 down"
+
+# partner eth0 up, eth1 down
+RET=0
+ip -n "${p_ns}" link set eth0 up
+ip -n "${br_ns}" link set eth2 up
+test_lacp_port_state eth0 $COLLECTING_DISTRIBUTING 60
+test_lacp_port_state eth1 $FAILED 1
+test_master_carrier up $mode
+log_test "bond LACP" "lacp_strict $mode - eth0 up, eth1 down"
+
+# partner eth0 and eth1 up
+RET=0
+ip -n "${p_ns}" link set eth1 up
+ip -n "${br_ns}" link set eth3 up
+test_lacp_port_state both $COLLECTING_DISTRIBUTING 60
+test_master_carrier up $mode
+log_test "bond LACP" "lacp_strict $mode - eth0 and eth1 up"
+
+# partner eth0 stops LACP and eth1 up
+RET=0
+ip netns exec "${br_ns}" sh -c "echo 0 > /sys/class/net/br0/brif/eth0/group_fwd_mask"
+ip netns exec "${br_ns}" sh -c "echo 0 > /sys/class/net/br0/brif/eth2/group_fwd_mask"
+test_lacp_port_state eth0 $FAILED 5
+test_lacp_port_state eth1 $COLLECTING_DISTRIBUTING 1
+test_master_carrier up $mode
+log_test "bond LACP" "lacp_strict $mode - eth0 stopped sending LACP"
+
+# partner eth0 and eth1 stop LACP
+RET=0
+ip netns exec "${br_ns}" sh -c "echo 0 > /sys/class/net/br1/brif/eth1/group_fwd_mask"
+ip netns exec "${br_ns}" sh -c "echo 0 > /sys/class/net/br1/brif/eth3/group_fwd_mask"
+test_lacp_port_state both $FAILED 5
+test_master_carrier up $mode
+log_test "bond LACP" "lacp_strict $mode - eth0 and eth1 stopped sending LACP"
+
+# switch to lacp_strict on
+RET=0
+mode=on
+ip -n "${d_ns}" link set dev bond0 type bond lacp_strict $mode
+test_lacp_port_state both $FAILED 1
+test_master_carrier down $mode
+log_test "bond LACP" "lacp_strict $mode - eth0 and eth1 stopped sending LACP"
+
+# switch back to lacp_strict off mode
+RET=0
+mode=off
+ip -n "${d_ns}" link set dev bond0 type bond lacp_strict $mode
+test_lacp_port_state both $FAILED 1
+test_master_carrier up $mode
+log_test "bond LACP" "lacp_strict $mode - eth0 and eth1 stopped sending LACP"
+
+# eth0 recovers LACP
+RET=0
+ip netns exec "${br_ns}" sh -c "echo 4 > /sys/class/net/br0/brif/eth0/group_fwd_mask"
+ip netns exec "${br_ns}" sh -c "echo 4 > /sys/class/net/br0/brif/eth2/group_fwd_mask"
+test_lacp_port_state eth0 $COLLECTING_DISTRIBUTING 60
+test_lacp_port_state eth1 $FAILED 1
+test_master_carrier up $mode
+log_test "bond LACP" "lacp_strict $mode - eth0 recovered and eth1 stopped sending LACP"
+
+# eth1 recovers LACP
+RET=0
+ip netns exec "${br_ns}" sh -c "echo 4 > /sys/class/net/br1/brif/eth1/group_fwd_mask"
+ip netns exec "${br_ns}" sh -c "echo 4 > /sys/class/net/br1/brif/eth3/group_fwd_mask"
+test_lacp_port_state both $COLLECTING_DISTRIBUTING 60
+test_master_carrier up $mode
+log_test "bond LACP" "lacp_strict $mode - eth0 and eth1 recovered LACP"
+
+# switch to lacp_strict on
+RET=0
+mode=on
+ip -n "${d_ns}" link set dev bond0 type bond lacp_strict $mode
+test_lacp_port_state both $COLLECTING_DISTRIBUTING 1
+test_master_carrier up $mode
+log_test "bond LACP" "lacp_strict $mode - eth0 and eth1 up"
+
+# partner eth0 down, eth1 up
+RET=0
+ip -n "${p_ns}" link set eth0 down
+ip -n "${br_ns}" link set eth2 down
+test_lacp_port_state eth0 $FAILED 5
+test_lacp_port_state eth1 $COLLECTING_DISTRIBUTING 1
+test_master_carrier up $mode
+log_test "bond LACP" "lacp_strict $mode - eth0 down"
+
+# partner eth0 and eth1 down
+RET=0
+ip -n "${p_ns}" link set eth1 down
+ip -n "${br_ns}" link set eth3 down
+test_lacp_port_state both $FAILED 5
+test_master_carrier down $mode # down because of min_links
+log_test "bond LACP" "lacp_strict $mode - eth0 and eth1 down"
+
+# partner eth0 up, eth1 down
+RET=0
+ip -n "${p_ns}" link set eth0 up
+ip -n "${br_ns}" link set eth2 up
+test_lacp_port_state eth0 $COLLECTING_DISTRIBUTING 60
+test_lacp_port_state eth1 $FAILED 1
+test_master_carrier up $mode
+log_test "bond LACP" "lacp_strict $mode - eth0 up, eth1 down"
+
+# partner eth0 and eth1 up
+RET=0
+ip -n "${p_ns}" link set eth1 up
+ip -n "${br_ns}" link set eth3 up
+test_lacp_port_state both $COLLECTING_DISTRIBUTING 60
+test_master_carrier up $mode
+log_test "bond LACP" "lacp_strict $mode - eth0 and eth1 up"
+
+# partner eth0 stops LACP and eth1 up
+RET=0
+ip netns exec "${br_ns}" sh -c "echo 0 > /sys/class/net/br0/brif/eth0/group_fwd_mask"
+ip netns exec "${br_ns}" sh -c "echo 0 > /sys/class/net/br0/brif/eth2/group_fwd_mask"
+test_lacp_port_state eth0 $FAILED 5
+test_lacp_port_state eth1 $COLLECTING_DISTRIBUTING 1
+test_master_carrier up $mode
+log_test "bond LACP" "lacp_strict $mode - eth0 stopped sending LACP"
+
+# partner eth0 and eth1 stop LACP
+RET=0
+ip netns exec "${br_ns}" sh -c "echo 0 > /sys/class/net/br1/brif/eth1/group_fwd_mask"
+ip netns exec "${br_ns}" sh -c "echo 0 > /sys/class/net/br1/brif/eth3/group_fwd_mask"
+test_lacp_port_state both $FAILED 5
+test_master_carrier down $mode
+log_test "bond LACP" "lacp_strict $mode - eth0 and eth1 stopped sending LACP"
+
+# eth0 recovers LACP
+RET=0
+ip netns exec "${br_ns}" sh -c "echo 4 > /sys/class/net/br0/brif/eth0/group_fwd_mask"
+ip netns exec "${br_ns}" sh -c "echo 4 > /sys/class/net/br0/brif/eth2/group_fwd_mask"
+test_lacp_port_state eth0 $COLLECTING_DISTRIBUTING 60
+test_lacp_port_state eth1 $FAILED 1
+test_master_carrier up $mode
+log_test "bond LACP" "lacp_strict $mode - eth0 recovered and eth1 stopped sending LACP"
+
+# eth1 recovers LACP
+# shellcheck disable=SC2034
+RET=0
+ip netns exec "${br_ns}" sh -c "echo 4 > /sys/class/net/br1/brif/eth1/group_fwd_mask"
+ip netns exec "${br_ns}" sh -c "echo 4 > /sys/class/net/br1/brif/eth3/group_fwd_mask"
+test_lacp_port_state both $COLLECTING_DISTRIBUTING 60
+test_master_carrier up $mode
+log_test "bond LACP" "lacp_strict $mode - eth0 and eth1 recovered LACP"
+
+exit "${EXIT_STATUS}"