Commit f0582d9aee for frr

commit f0582d9aee7d3f2e9adb8b3aa271e70cfab153bb
Author: Donald Sharp <sharpd@nvidia.com>
Date:   Fri Oct 2 13:08:34 2026 -0400

    tests: Add platform agnostic delete_address_on_interface

    Add a platform agnostic delete_address_on_interface function
    in the topotests to allow generic handling of removing
    interface addresses.

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

diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py
index a93fa9f530..b6b3b20cce 100644
--- a/tests/topotests/lib/common_config.py
+++ b/tests/topotests/lib/common_config.py
@@ -1603,6 +1603,33 @@ def create_address_on_interface(tgen, dut, name, ip_addr, vrf=None, netmask=None
         create_address_on_interface_linux(tgen, dut, name, ip_addr, vrf, netmask)


+def delete_address_on_interface(tgen, dut, name, ip_addr, vrf=None, netmask=None):
+    """
+    Remove an IP address from an existing kernel interface.
+
+    The interface must already exist. Other addresses configured on it are
+    left in place. Link state is not changed. ``vrf`` is accepted so callers
+    can pass the same arguments as ``create_address_on_interface``. Interface
+    VRF membership is left unchanged.
+
+    Parameters
+    ----------
+    * `tgen` : Topogen object
+    * `dut` : Device whose interface loses the address
+    * `name` : interface name
+    * `ip_addr` : ip address to remove. Include the prefix length unless
+                  ``netmask`` is set.
+    * `vrf` : VRF name. Accepted for signature compatibility. Membership is
+              not changed.
+    * `netmask` : netmask value, default is None
+    """
+
+    if sys.platform.startswith("freebsd"):
+        delete_address_on_interface_freebsd(tgen, dut, name, ip_addr, vrf, netmask)
+    else:
+        delete_address_on_interface_linux(tgen, dut, name, ip_addr, vrf, netmask)
+
+
 def _kernel_interface_address(ip_addr, netmask):
     """Return an ipaddress interface for ip_addr and an optional netmask."""
     if not netmask:
@@ -1662,6 +1689,21 @@ def create_address_on_interface_linux(
         rnode.run(cmd)


+def delete_address_on_interface_linux(
+    tgen, dut, name, ip_addr, vrf=None, netmask=None
+):
+    """Remove an IP address from an existing Linux interface."""
+
+    rnode = tgen.gears[dut]
+    ifaddr = _kernel_interface_address(ip_addr, netmask)
+    cmd = "ip -{0} a del {1} dev {2}".format(ifaddr.version, ifaddr, name)
+    logger.debug("[DUT: %s]: Running command: %s", dut, cmd)
+    rnode.run(cmd)
+
+    if vrf:
+        logger.debug("[DUT: %s]: %s VRF membership unchanged (vrf %s)", dut, name, vrf)
+
+
 def _freebsd_run(rnode, dut, args):
     """Run an ifconfig argv inside the router and log it."""
     logger.debug("[DUT: %s]: Running command: %s", dut, " ".join(args))
@@ -1756,6 +1798,20 @@ def create_address_on_interface_freebsd(
         logger.debug("[DUT: %s]: %s stays in the base FIB (vrf %s)", dut, name, vrf)


+def delete_address_on_interface_freebsd(
+    tgen, dut, name, ip_addr, vrf=None, netmask=None
+):
+    """Remove an IP address from an existing FreeBSD interface."""
+
+    rnode = tgen.gears[dut]
+    ifaddr = _kernel_interface_address(ip_addr, netmask)
+    family = "inet6" if ifaddr.version == 6 else "inet"
+    _freebsd_run(rnode, dut, ["/sbin/ifconfig", name, family, str(ifaddr.ip), "delete"])
+
+    if vrf:
+        logger.debug("[DUT: %s]: %s stays in the base FIB (vrf %s)", dut, name, vrf)
+
+
 def shutdown_bringup_interface_in_kernel(tgen, dut, intf_name, ifaceaction=False):
     """
     Cretae interfaces in kernel for ipv4/ipv6