Commit b879561526 for frr

commit b8795615264b6f846a505aa5e90e7bfcd5e1d36a
Author: Donald Sharp <sharpd@nvidia.com>
Date:   Wed Sep 23 11:42:46 2026 -0400

    tests: Ensure that address is in kernel before starting script

    The test_bfd_auth_replay_topo1.py test starts a sub script
    bfd_replay_peer.py that can occassionally fail when the assigned
    ip address for the interface it is running on has not been fully
    integrated into the system.  Put a small delay in the test to
    ensure that the test has the ip address on the interface to allow
    the script to run.

    Signed-off-by: Donald Sharp <sharpd@nvidia.com>

diff --git a/tests/topotests/bfd_auth_replay_topo1/test_bfd_auth_replay_topo1.py b/tests/topotests/bfd_auth_replay_topo1/test_bfd_auth_replay_topo1.py
index 924ef03a73..04664ad757 100644
--- a/tests/topotests/bfd_auth_replay_topo1/test_bfd_auth_replay_topo1.py
+++ b/tests/topotests/bfd_auth_replay_topo1/test_bfd_auth_replay_topo1.py
@@ -43,6 +43,8 @@ pytestmark = [pytest.mark.bfdd]
 KEY = "bfdauthkey123"
 RT1_ADDR = "10.0.1.1"
 RT2_ADDR = "10.0.1.2"
+# rt2 is the namespace the scripted peer speaks from.
+RT2_IFACE = "eth-rt1"

 SEQ_ERROR = "rx-pkt-authentication-keyed-sha1-sequence-error"
 SEQ_ERROR_METICULOUS = "rx-pkt-authentication-keyed-sha1-sequence-meticulous-error"
@@ -84,19 +86,67 @@ def peer_state():
     return output[0].get("status") if output else None


-def run_peer(after_up="none", meticulous=False, by=400000, seconds=20,
-             seq_start=None, hold_until_up=False):
+def address_in_kernel(router, ifname, address):
+    """True once `address` is on `ifname` and no longer tentative.
+
+    zebra installs the configured address after the daemon starts. Until
+    that address is usable in the kernel, binding it fails.
+    """
+    output = router.run("ip -4 -j addr show dev {}".format(ifname))
+    try:
+        interfaces = json.loads(output)
+    except ValueError:
+        return False
+    if not interfaces:
+        return False
+    for info in interfaces[0].get("addr_info", []):
+        if info.get("local") != address:
+            continue
+        # iproute2 reports this either as a boolean or in the flags list.
+        flags = info.get("flags", [])
+        if info.get("tentative") is True or "tentative" in flags:
+            return False
+        return True
+    return False
+
+
+def wait_for_peering_address():
+    "Wait until rt2 can bind the address the scripted peer speaks from."
+    rt2 = get_topogen().gears["rt2"]
+
+    def _ready():
+        return address_in_kernel(rt2, RT2_IFACE, RT2_ADDR)
+
+    _, result = topotest.run_and_expect(_ready, True, count=20, wait=1)
+    assert result is True, "{} on {} is not in the kernel".format(RT2_ADDR, RT2_IFACE)
+
+
+def run_peer(
+    after_up="none",
+    meticulous=False,
+    by=400000,
+    seconds=20,
+    seq_start=None,
+    hold_until_up=False,
+):
     """Speak BFD from rt2 for `seconds`, misbehaving as asked once up."""
+    wait_for_peering_address()
     rt2 = get_topogen().gears["rt2"]
     cmd = [
         sys.executable,
         os.path.join(CWD, "bfd_replay_peer.py"),
-        "--local", RT2_ADDR,
-        "--peer", RT1_ADDR,
-        "--key", KEY,
-        "--after-up", after_up,
-        "--by", str(by),
-        "--seconds", str(seconds),
+        "--local",
+        RT2_ADDR,
+        "--peer",
+        RT1_ADDR,
+        "--key",
+        KEY,
+        "--after-up",
+        after_up,
+        "--by",
+        str(by),
+        "--seconds",
+        str(seconds),
     ]
     if seq_start is not None:
         cmd += ["--seq-start", str(seq_start)]
@@ -228,8 +278,9 @@ def test_bfd_auth_sequence_may_wrap():
     # Held at six short of the wrap until something is accepted, so the
     # window is established there and the wrap falls inside the session
     # rather than while the previous window is still ageing out.
-    peer = run_peer(after_up="none", seconds=40, seq_start=0xFFFFFFFA,
-                    hold_until_up=True)
+    peer = run_peer(
+        after_up="none", seconds=40, seq_start=0xFFFFFFFA, hold_until_up=True
+    )
     expect_state("up")

     before = counter(SEQ_ERROR)
@@ -266,7 +317,9 @@ def test_bfd_auth_meticulous_refuses_a_repeat():
         authentication algorithm meticulous
         exit
         exit
-        """.format(RT2_ADDR, RT1_ADDR)
+        """.format(
+            RT2_ADDR, RT1_ADDR
+        )
     )

     before = counter(SEQ_ERROR_METICULOUS)