#!/bin/bash
 # SPDX-License-Identifier: GPL-2.0
 
+NAMESPACES=""
+
 # Test that a link aggregation device (bonding, team) removes the hardware
 # addresses that it adds on its underlying devices.
 test_LAG_cleanup()
 
        log_test "$driver cleanup mode $mode"
 }
+
+# Build a generic 2 node net namespace with 2 connections
+# between the namespaces
+#
+#  +-----------+       +-----------+
+#  | node1     |       | node2     |
+#  |           |       |           |
+#  |           |       |           |
+#  |      eth0 +-------+ eth0      |
+#  |           |       |           |
+#  |      eth1 +-------+ eth1      |
+#  |           |       |           |
+#  +-----------+       +-----------+
+lag_setup2x2()
+{
+       local state=${1:-down}
+       local namespaces="lag_node1 lag_node2"
+
+       # create namespaces
+       for n in ${namespaces}; do
+               ip netns add ${n}
+       done
+
+       # wire up namespaces
+       ip link add name lag1 type veth peer name lag1-end
+       ip link set dev lag1 netns lag_node1 $state name eth0
+       ip link set dev lag1-end netns lag_node2 $state name eth0
+
+       ip link add name lag1 type veth peer name lag1-end
+       ip link set dev lag1 netns lag_node1 $state name eth1
+       ip link set dev lag1-end netns lag_node2 $state name eth1
+
+       NAMESPACES="${namespaces}"
+}
+
+# cleanup all lag related namespaces and remove the bonding module
+lag_cleanup()
+{
+       for n in ${NAMESPACES}; do
+               ip netns delete ${n} >/dev/null 2>&1 || true
+       done
+       modprobe -r bonding
+}
+
+SWITCH="lag_node1"
+CLIENT="lag_node2"
+CLIENTIP="172.20.2.1"
+SWITCHIP="172.20.2.2"
+
+lag_setup_network()
+{
+       lag_setup2x2 "down"
+
+       # create switch
+       ip netns exec ${SWITCH} ip link add br0 up type bridge
+       ip netns exec ${SWITCH} ip link set eth0 master br0 up
+       ip netns exec ${SWITCH} ip link set eth1 master br0 up
+       ip netns exec ${SWITCH} ip addr add ${SWITCHIP}/24 dev br0
+}
+
+lag_reset_network()
+{
+       ip netns exec ${CLIENT} ip link del bond0
+       ip netns exec ${SWITCH} ip link set eth0 up
+       ip netns exec ${SWITCH} ip link set eth1 up
+}
+
+create_bond()
+{
+       # create client
+       ip netns exec ${CLIENT} ip link set eth0 down
+       ip netns exec ${CLIENT} ip link set eth1 down
+
+       ip netns exec ${CLIENT} ip link add bond0 type bond $@
+       ip netns exec ${CLIENT} ip link set eth0 master bond0
+       ip netns exec ${CLIENT} ip link set eth1 master bond0
+       ip netns exec ${CLIENT} ip link set bond0 up
+       ip netns exec ${CLIENT} ip addr add ${CLIENTIP}/24 dev bond0
+}
+
+test_bond_recovery()
+{
+       RET=0
+
+       create_bond $@
+
+       # verify connectivity
+       ip netns exec ${CLIENT} ping ${SWITCHIP} -c 2 >/dev/null 2>&1
+       check_err $? "No connectivity"
+
+       # force the links of the bond down
+       ip netns exec ${SWITCH} ip link set eth0 down
+       sleep 2
+       ip netns exec ${SWITCH} ip link set eth0 up
+       ip netns exec ${SWITCH} ip link set eth1 down
+
+       # re-verify connectivity
+       ip netns exec ${CLIENT} ping ${SWITCHIP} -c 2 >/dev/null 2>&1
+
+       local rc=$?
+       check_err $rc "Bond failed to recover"
+       log_test "$1 ($2) bond recovery"
+       lag_reset_network
+}
 
--- /dev/null
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+
+# Regression Test:
+#  When the bond is configured with down/updelay and the link state of
+#  slave members flaps if there are no remaining members up the bond
+#  should immediately select a member to bring up. (from bonding.txt
+#  section 13.1 paragraph 4)
+#
+#  +-------------+       +-----------+
+#  | client      |       | switch    |
+#  |             |       |           |
+#  |    +--------| link1 |-----+     |
+#  |    |        +-------+     |     |
+#  |    |        |       |     |     |
+#  |    |        +-------+     |     |
+#  |    | bond   | link2 | Br0 |     |
+#  +-------------+       +-----------+
+#     172.20.2.1           172.20.2.2
+
+
+REQUIRE_MZ=no
+REQUIRE_JQ=no
+NUM_NETIFS=0
+lib_dir=$(dirname "$0")
+source "$lib_dir"/net_forwarding_lib.sh
+source "$lib_dir"/lag_lib.sh
+
+cleanup()
+{
+       lag_cleanup
+}
+
+trap cleanup 0 1 2
+
+lag_setup_network
+test_bond_recovery mode 1 miimon 100 updelay 0
+test_bond_recovery mode 1 miimon 100 updelay 200
+test_bond_recovery mode 1 miimon 100 updelay 500
+test_bond_recovery mode 1 miimon 100 updelay 1000
+test_bond_recovery mode 1 miimon 100 updelay 2000
+test_bond_recovery mode 1 miimon 100 updelay 5000
+test_bond_recovery mode 1 miimon 100 updelay 10000
+
+exit "$EXIT_STATUS"
 
--- /dev/null
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+
+# Regression Test:
+#  When the bond is configured with down/updelay and the link state of
+#  slave members flaps if there are no remaining members up the bond
+#  should immediately select a member to bring up. (from bonding.txt
+#  section 13.1 paragraph 4)
+#
+#  +-------------+       +-----------+
+#  | client      |       | switch    |
+#  |             |       |           |
+#  |    +--------| link1 |-----+     |
+#  |    |        +-------+     |     |
+#  |    |        |       |     |     |
+#  |    |        +-------+     |     |
+#  |    | bond   | link2 | Br0 |     |
+#  +-------------+       +-----------+
+#     172.20.2.1           172.20.2.2
+
+
+REQUIRE_MZ=no
+REQUIRE_JQ=no
+NUM_NETIFS=0
+lib_dir=$(dirname "$0")
+source "$lib_dir"/net_forwarding_lib.sh
+source "$lib_dir"/lag_lib.sh
+
+cleanup()
+{
+       lag_cleanup
+}
+
+trap cleanup 0 1 2
+
+lag_setup_network
+test_bond_recovery mode 2 miimon 100 updelay 0
+test_bond_recovery mode 2 miimon 100 updelay 200
+test_bond_recovery mode 2 miimon 100 updelay 500
+test_bond_recovery mode 2 miimon 100 updelay 1000
+test_bond_recovery mode 2 miimon 100 updelay 2000
+test_bond_recovery mode 2 miimon 100 updelay 5000
+test_bond_recovery mode 2 miimon 100 updelay 10000
+
+exit "$EXIT_STATUS"