Commit 8b4ea4f052 for frr

commit 8b4ea4f052c75a3c14aa09ee5aa4c9edacb4f2ee
Author: Donald Sharp <sharpd@nvidia.com>
Date:   Thu Oct 1 17:41:00 2026 -0400

    tests: Use create_address_on_interface

    Convert the places using `ip addr add..` to use
    create_address_on_interface.

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

diff --git a/tests/topotests/bgp_evpn_advertise_all_vni_vrf/test_bgp_evpn_advertise_all_vni_vrf.py b/tests/topotests/bgp_evpn_advertise_all_vni_vrf/test_bgp_evpn_advertise_all_vni_vrf.py
index a4aab316ed..ee206cdde9 100644
--- a/tests/topotests/bgp_evpn_advertise_all_vni_vrf/test_bgp_evpn_advertise_all_vni_vrf.py
+++ b/tests/topotests/bgp_evpn_advertise_all_vni_vrf/test_bgp_evpn_advertise_all_vni_vrf.py
@@ -54,7 +54,10 @@ sys.path.append(os.path.join(CWD, "../"))

 # pylint: disable=C0413
 from lib import topotest
-from lib.common_config import required_linux_kernel_version
+from lib.common_config import (
+    create_address_on_interface,
+    required_linux_kernel_version,
+)
 from lib.topogen import Topogen, get_topogen
 from lib.topolog import logger

@@ -167,7 +170,7 @@ def _setup_host(host, config):
     host.run(f"ip link set dev {ifname} down")
     host.run(f"ip addr flush dev {ifname}")
     host.run(f"ip link set dev {ifname} address {config['mac']}")
-    host.run(f"ip addr add {config['ip']} dev {ifname}")
+    create_address_on_interface(host.tgen, host.name, ifname, config["ip"])
     host.run(f"ip link set dev {ifname} up")


diff --git a/tests/topotests/bgp_evpn_gr/test_bgp_evpn_gr.py b/tests/topotests/bgp_evpn_gr/test_bgp_evpn_gr.py
index 36944fb0fc..46ad93d4b3 100644
--- a/tests/topotests/bgp_evpn_gr/test_bgp_evpn_gr.py
+++ b/tests/topotests/bgp_evpn_gr/test_bgp_evpn_gr.py
@@ -34,6 +34,7 @@ from lib.topogen import Topogen, TopoRouter, get_topogen
 from lib.topolog import logger
 from lib.common_config import (
     check_router_status,
+    create_address_on_interface,
     kill_router_daemons,
     start_router_daemons,
 )
@@ -76,12 +77,12 @@ def setup_module(mod):
         pe.cmd_raises("ip link add name br100 type bridge stp_state 0")
         pe.cmd_raises("ip link set dev vxlan100 master br100")
         pe.cmd_raises(f"ip link set dev {name}-eth1 master br100")
-        pe.cmd_raises(f"ip addr add {bridge_ip} dev br100")
+        create_address_on_interface(tgen, name, "br100", bridge_ip)
         pe.cmd_raises("ip link set up dev br100")
         pe.cmd_raises("ip link set up dev vxlan100")
         pe.cmd_raises(f"ip link set up dev {name}-eth1")
         pe.cmd_raises("ip link set dev br100 master vrf-blue")
-        pe.cmd_raises(f"ip -6 addr add {bridge_ipv6} dev br100")
+        create_address_on_interface(tgen, name, "br100", bridge_ipv6)
         pe.cmd_raises(
             f"ip link add vxlan1000 type vxlan id 1000 dstport 4789 local {vtep_ip}"
         )
diff --git a/tests/topotests/bgp_evpn_l3vni_modify/PE1/setup.sh b/tests/topotests/bgp_evpn_l3vni_modify/PE1/setup.sh
index 0da580136b..55b83ee440 100755
--- a/tests/topotests/bgp_evpn_l3vni_modify/PE1/setup.sh
+++ b/tests/topotests/bgp_evpn_l3vni_modify/PE1/setup.sh
@@ -17,5 +17,4 @@ bridge vlan add vid 60 dev vxlan3109 pvid untagged

 ip link add link br3109 name vlan60 type vlan id 60
 ip link set dev vlan60 master vrf-blue
-ip addr add 10.99.99.1/24 dev vlan60
 ip link set dev vlan60 up
diff --git a/tests/topotests/bgp_evpn_l3vni_modify/PE2/setup.sh b/tests/topotests/bgp_evpn_l3vni_modify/PE2/setup.sh
index ea0974e425..4fe461f18c 100755
--- a/tests/topotests/bgp_evpn_l3vni_modify/PE2/setup.sh
+++ b/tests/topotests/bgp_evpn_l3vni_modify/PE2/setup.sh
@@ -17,5 +17,4 @@ bridge vlan add vid 60 dev vxlan3109 pvid untagged

 ip link add link br3109 name vlan60 type vlan id 60
 ip link set dev vlan60 master vrf-blue
-ip addr add 10.99.99.3/24 dev vlan60
 ip link set dev vlan60 up
diff --git a/tests/topotests/bgp_evpn_l3vni_modify/test_bgp_evpn_l3vni_modify.py b/tests/topotests/bgp_evpn_l3vni_modify/test_bgp_evpn_l3vni_modify.py
index c2f5f05171..5f181c7845 100644
--- a/tests/topotests/bgp_evpn_l3vni_modify/test_bgp_evpn_l3vni_modify.py
+++ b/tests/topotests/bgp_evpn_l3vni_modify/test_bgp_evpn_l3vni_modify.py
@@ -36,6 +36,7 @@ CWD = os.path.dirname(os.path.realpath(__file__))
 sys.path.append(os.path.join(CWD, "../"))

 from lib import topotest
+from lib.common_config import create_address_on_interface
 from lib.topogen import Topogen, get_topogen

 pytestmark = [pytest.mark.bgpd, pytest.mark.ospfd]
@@ -54,8 +55,9 @@ def setup_module(mod):

     tgen.start_router()

-    for pe in ("PE1", "PE2"):
+    for pe, addr in (("PE1", "10.99.99.1/24"), ("PE2", "10.99.99.3/24")):
         tgen.gears[pe].run(f"/bin/bash {CWD}/{pe}/setup.sh")
+        create_address_on_interface(tgen, pe, "vlan60", addr)


 def teardown_module(mod):
diff --git a/tests/topotests/bgp_evpn_mh/test_evpn_mh.py b/tests/topotests/bgp_evpn_mh/test_evpn_mh.py
index a2392b1371..93afcc8e20 100644
--- a/tests/topotests/bgp_evpn_mh/test_evpn_mh.py
+++ b/tests/topotests/bgp_evpn_mh/test_evpn_mh.py
@@ -34,6 +34,7 @@ sys.path.append(os.path.join(CWD, "../"))
 # Import topogen and topotest helpers
 from lib import topotest
 from lib.common_config import (
+    create_address_on_interface,
     create_interface_in_kernel,
     kill_router_daemons,
     start_router_daemons,
@@ -311,7 +312,7 @@ def config_svi(node, svi_pip):
     Create an SVI for VLAN 1000
     """
     node.run("ip link add link bridge name vlan1000 type vlan id 1000 protocol 802.1q")
-    node.run("ip addr add %s/24 dev vlan1000" % svi_pip)
+    create_address_on_interface(node.tgen, node.name, "vlan1000", "%s/24" % svi_pip)
     node.run("ip link set dev vlan1000 up")
     node.run("/sbin/sysctl net.ipv4.conf.vlan1000.arp_accept=1")
     node.run("ip link add link vlan1000 name vlan1000-v0 type macvlan mode private")
@@ -321,7 +322,7 @@ def config_svi(node, svi_pip):
     node.run("ip link set dev vlan1000-v0 address 00:00:5e:00:01:01")
     node.run("ip link set dev vlan1000-v0 up")
     # metric 1024 is not working
-    node.run("ip addr add 45.0.0.1/24 dev vlan1000-v0")
+    create_address_on_interface(node.tgen, node.name, "vlan1000-v0", "45.0.0.1/24")


 def config_tor(tor_name, tor, tor_ip, svi_pip):
@@ -377,7 +378,7 @@ def config_host(host_name, host):
     config_bond(host, bond_name, bond_members, "00:00:00:00:00:00", None)

     host_ip, host_mac = compute_host_ip_mac(host_name)
-    host.run("ip addr add %s dev %s" % (host_ip, bond_name))
+    create_address_on_interface(host.tgen, host.name, bond_name, host_ip)
     host.run("ip link set dev %s address %s" % (bond_name, host_mac))


@@ -993,7 +994,9 @@ def test_evpn_vtep_change():
     secondary_vtep = "192.168.100.117"

     # 1. Add secondary loopback address on torm21
-    remote_tor.run(f"ip addr add {secondary_vtep}/32 dev lo")
+    create_address_on_interface(
+        remote_tor.tgen, remote_tor.name, "lo", f"{secondary_vtep}/32"
+    )

     # 2. Verify primary VTEP is present initially
     test_fn = partial(check_remote_es_vtep_present, dut, esi, primary_vtep)
diff --git a/tests/topotests/bgp_evpn_mh_v4_v6_num/test_evpn_mh_v4_v6_num.py b/tests/topotests/bgp_evpn_mh_v4_v6_num/test_evpn_mh_v4_v6_num.py
index 24cdff2e28..f7a23a8d07 100644
--- a/tests/topotests/bgp_evpn_mh_v4_v6_num/test_evpn_mh_v4_v6_num.py
+++ b/tests/topotests/bgp_evpn_mh_v4_v6_num/test_evpn_mh_v4_v6_num.py
@@ -46,7 +46,7 @@ sys.path.append(os.path.join(CWD, "../"))
 from lib import topotest

 # Required to instantiate the topology builder class.
-from lib.common_config import create_interface_in_kernel
+from lib.common_config import create_address_on_interface, create_interface_in_kernel
 from lib.topogen import Topogen, TopoRouter, get_topogen
 from lib.topolog import logger

@@ -535,15 +535,19 @@ def config_svi(node, svi_pip):

     if active_ip_version == "ipv6":
         # Assign IPv6 anycast GW only to VLAN 1000 in vrf1
-        node.run("ip -6 addr add %s/64 dev vlan1000" % svi_pip)
+        create_address_on_interface(
+            node.tgen, node.name, "vlan1000", "%s/64" % svi_pip
+        )
     else:
         # Preserve legacy IPv4 anycast gateway behavior used by MAC learning tests.
-        node.run("ip addr add %s/24 dev vlan1000" % svi_pip)
+        create_address_on_interface(
+            node.tgen, node.name, "vlan1000", "%s/24" % svi_pip
+        )
         node.run("/sbin/sysctl net.ipv4.conf.vlan1000.arp_accept=1")
         node.run("ip link add link vlan1000 name vlan1000-v0 type macvlan mode private")
         node.run("ip link set dev vlan1000-v0 address 00:00:5e:00:01:01")
         node.run("ip link set dev vlan1000-v0 up")
-        node.run("ip addr add 45.0.0.1/24 dev vlan1000-v0")
+        create_address_on_interface(node.tgen, node.name, "vlan1000-v0", "45.0.0.1/24")


 def config_vrf_l3vni(node):
@@ -590,10 +594,10 @@ def config_tor(tor_name, tor, tor_ip, svi_pip, ip_version):
         ipv4_lo = "10.0.0.18"

     if ip_version == "ipv4":
-        tor.run("ip addr add %s/32 dev lo" % tor_ip)
+        create_address_on_interface(tor.tgen, tor.name, "lo", "%s/32" % tor_ip)
     else:
-        tor.run("ip addr add %s/32 dev lo" % ipv4_lo)
-        tor.run("ip -6 addr add %s/128 dev lo" % tor_ip)
+        create_address_on_interface(tor.tgen, tor.name, "lo", "%s/32" % ipv4_lo)
+        create_address_on_interface(tor.tgen, tor.name, "lo", "%s/128" % tor_ip)

     # Add IPv6 underlay addresses on uplink interfaces using iproute2 as well.
     # This avoids timing/race issues where, when using frr-reload.py, BGP may
@@ -603,10 +607,7 @@ def config_tor(tor_name, tor, tor_ip, svi_pip, ip_version):
     if ip_version == "ipv6":
         uplinks = tor_uplink_ipv6.get(tor_name, {})
     for ifname, prefix in uplinks.items():
-        if ip_version == "ipv6":
-            tor.run("ip -6 addr add %s dev %s" % (prefix, ifname))
-        else:
-            tor.run("ip addr add %s dev %s" % (prefix, ifname))
+        create_address_on_interface(tor.tgen, tor.name, ifname, prefix)

     # create VRFs and L3VNI VLANs based on L3VNI_VRF
     config_bridge(tor)
@@ -617,7 +618,7 @@ def config_tor(tor_name, tor, tor_ip, svi_pip, ip_version):
     # each TOR has unique loopback-style addresses in each VRF.
     vrf_ips = VRF_IPV4.get(tor_name, {})
     for vrf, addr in vrf_ips.items():
-        tor.run(f"ip addr add {addr} dev {vrf}")
+        create_address_on_interface(tor.tgen, tor.name, vrf, addr)

     # create hostbonds; we will attach them to the bridge explicitly
     if "torm1" in tor_name:
@@ -722,7 +723,7 @@ def config_host(host_name, host):
     config_bond(host, bond_name, bond_members, "00:00:00:00:00:00", None)

     host_ip, host_mac = compute_host_ip_mac(host_name)
-    host.run("ip addr add %s dev %s" % (host_ip, bond_name))
+    create_address_on_interface(host.tgen, host.name, bond_name, host_ip)
     host.run("ip link set dev %s address %s" % (bond_name, host_mac))


diff --git a/tests/topotests/bgp_evpn_overlay_index_gateway/test_bgp_evpn_overlay_index_gateway.py b/tests/topotests/bgp_evpn_overlay_index_gateway/test_bgp_evpn_overlay_index_gateway.py
index 58ecec1464..aabc59fe40 100755
--- a/tests/topotests/bgp_evpn_overlay_index_gateway/test_bgp_evpn_overlay_index_gateway.py
+++ b/tests/topotests/bgp_evpn_overlay_index_gateway/test_bgp_evpn_overlay_index_gateway.py
@@ -55,6 +55,7 @@ from lib import topotest
 from lib.topogen import Topogen, TopoRouter, get_topogen
 from lib.topolog import logger
 from lib.common_config import (
+    create_address_on_interface,
     step,
     write_test_header,
     write_test_footer,
@@ -155,12 +156,12 @@ def setup_module(mod):
         pe.cmd_raises("ip link add name br100 type bridge stp_state 0")
         pe.cmd_raises("ip link set dev vxlan100 master br100")
         pe.cmd_raises("ip link set dev {}-eth1 master br100".format(name))
-        pe.cmd_raises("ip addr add {} dev br100".format(bridge_ip))
+        create_address_on_interface(tgen, name, "br100", bridge_ip)
         pe.cmd_raises("ip link set up dev br100")
         pe.cmd_raises("ip link set up dev vxlan100")
         pe.cmd_raises("ip link set up dev {}-eth1".format(name))
         pe.cmd_raises("ip link set dev br100 master vrf-blue")
-        pe.cmd_raises("ip -6 addr add {} dev br100".format(bridge_ipv6))
+        create_address_on_interface(tgen, name, "br100", bridge_ipv6)

         pe.cmd_raises(
             "ip link add vxlan1000 type vxlan id 1000 dstport 4789 local {}".format(
diff --git a/tests/topotests/bgp_evpn_route_target_config/test_bgp_evpn_route_target_config.py b/tests/topotests/bgp_evpn_route_target_config/test_bgp_evpn_route_target_config.py
index 77db351cf8..b58463557a 100644
--- a/tests/topotests/bgp_evpn_route_target_config/test_bgp_evpn_route_target_config.py
+++ b/tests/topotests/bgp_evpn_route_target_config/test_bgp_evpn_route_target_config.py
@@ -48,7 +48,7 @@ sys.path.append(os.path.join(CWD, "../"))

 # pylint: disable=C0413
 from lib import topotest
-from lib.common_config import create_interface_in_kernel
+from lib.common_config import create_address_on_interface, create_interface_in_kernel
 from lib.topogen import Topogen, get_topogen
 from lib.topolog import logger

@@ -113,7 +113,6 @@ def setup_module(mod):
         "ip link add name bridge-202 up address {} type bridge stp_state 0".format(
             GW_MAC
         ),
-        "ip addr add {}/24 dev bridge-202".format(GW_IP),
         "ip link add name vxlan-202 type vxlan id 202 dstport 4789 dev r1-eth0 local 192.168.0.1",
         "ip link set dev vxlan-202 master bridge-202",
         "ip link set vxlan-202 up type bridge_slave learning off flood off mcast_flood off",
@@ -132,6 +131,7 @@ def setup_module(mod):
         logger.info("cmd to r1: {}".format(cmd))
         output = tgen.gears["r1"].cmd_raises(cmd)
         logger.info("result: " + output)
+    create_address_on_interface(tgen, "r1", "bridge-202", "{}/24".format(GW_IP))

     for router in tgen.routers().values():
         router.load_frr_config()
diff --git a/tests/topotests/bgp_evpn_svi_anycast_gw/test_anycast_gw_neigh_linkage.py b/tests/topotests/bgp_evpn_svi_anycast_gw/test_anycast_gw_neigh_linkage.py
index 26355fcae6..db41613eec 100644
--- a/tests/topotests/bgp_evpn_svi_anycast_gw/test_anycast_gw_neigh_linkage.py
+++ b/tests/topotests/bgp_evpn_svi_anycast_gw/test_anycast_gw_neigh_linkage.py
@@ -68,6 +68,7 @@ sys.path.append(os.path.join(CWD, "../"))
 from lib import topotest
 from lib.evpn import evpn_verify_bgp_vni_state, evpn_verify_vni_remote_vteps
 from lib.topogen import Topogen, get_topogen
+from lib.common_config import create_address_on_interface
 from lib.topolog import logger

 pytestmark = [pytest.mark.bgpd]
@@ -136,7 +137,9 @@ def config_leaf_dataplane(leaf, name, svi_mac, with_gw_addrs):
         )
         leaf.run("ip link set dev %s address %s" % (svi, svi_mac))
         if with_gw_addrs:
-            leaf.run("ip addr add %s/%d dev %s" % (GW_IPS[vni], GW_PLEN, svi))
+            create_address_on_interface(
+                leaf.tgen, leaf.name, svi, "%s/%d" % (GW_IPS[vni], GW_PLEN)
+            )
         leaf.run("ip link set dev %s up" % svi)

     leaf.run("/sbin/sysctl -w net.ipv4.ip_forward=1")
diff --git a/tests/topotests/bgp_evpn_three_tier_clos_topo1/test_bgp_evpn_v4_v6_vtep.py b/tests/topotests/bgp_evpn_three_tier_clos_topo1/test_bgp_evpn_v4_v6_vtep.py
index 5342360f54..78a78f33ab 100644
--- a/tests/topotests/bgp_evpn_three_tier_clos_topo1/test_bgp_evpn_v4_v6_vtep.py
+++ b/tests/topotests/bgp_evpn_three_tier_clos_topo1/test_bgp_evpn_v4_v6_vtep.py
@@ -75,7 +75,11 @@ sys.path.append(os.path.join(CWD, "../"))
 from lib import topotest
 from lib.topogen import Topogen, TopoRouter, get_topogen
 from lib.topolog import logger
-from lib.common_config import required_iproute2_version, required_linux_kernel_version
+from lib.common_config import (
+    create_address_on_interface,
+    required_iproute2_version,
+    required_linux_kernel_version,
+)
 from lib.bgp import get_bgp_summary_json
 from lib.evpn import (
     evpn_verify_vni_remote_vteps,
@@ -499,17 +503,17 @@ def setup_vtep(tgen, rname, local_ip, is_bordertor=True):

     # Configure SVI IPs based on router
     if rname == "bordertor-11":
-        router.run("ip addr add 192.168.11.11/24 dev vlan111")
-        router.run("ip addr add fd00:60:1:1::11/64 dev vlan111")
+        create_address_on_interface(tgen, rname, "vlan111", "192.168.11.11/24")
+        create_address_on_interface(tgen, rname, "vlan111", "fd00:60:1:1::11/64")
     elif rname == "bordertor-12":
-        router.run("ip addr add 192.168.11.12/24 dev vlan111")
-        router.run("ip addr add fd00:60:1:1::12/64 dev vlan111")
+        create_address_on_interface(tgen, rname, "vlan111", "192.168.11.12/24")
+        create_address_on_interface(tgen, rname, "vlan111", "fd00:60:1:1::12/64")
     elif rname == "tor-21":
-        router.run("ip addr add 192.168.11.21/24 dev vlan111")
-        router.run("ip addr add fd00:60:1:1::21/64 dev vlan111")
+        create_address_on_interface(tgen, rname, "vlan111", "192.168.11.21/24")
+        create_address_on_interface(tgen, rname, "vlan111", "fd00:60:1:1::21/64")
     elif rname == "tor-22":
-        router.run("ip addr add 192.168.11.22/24 dev vlan111")
-        router.run("ip addr add fd00:60:1:1::22/64 dev vlan111")
+        create_address_on_interface(tgen, rname, "vlan111", "192.168.11.22/24")
+        create_address_on_interface(tgen, rname, "vlan111", "fd00:60:1:1::22/64")

     router.run("ip link set dev vlan111 up")
     router.run("/sbin/sysctl net.ipv4.conf.vlan111.arp_accept=1")
@@ -521,17 +525,17 @@ def setup_vtep(tgen, rname, local_ip, is_bordertor=True):
     router.run("ip link set dev vlan112 master vrf1")

     if rname == "bordertor-11":
-        router.run("ip addr add 192.168.12.11/24 dev vlan112")
-        router.run("ip addr add fd00:50:1:1::11/64 dev vlan112")
+        create_address_on_interface(tgen, rname, "vlan112", "192.168.12.11/24")
+        create_address_on_interface(tgen, rname, "vlan112", "fd00:50:1:1::11/64")
     elif rname == "bordertor-12":
-        router.run("ip addr add 192.168.12.12/24 dev vlan112")
-        router.run("ip addr add fd00:50:1:1::12/64 dev vlan112")
+        create_address_on_interface(tgen, rname, "vlan112", "192.168.12.12/24")
+        create_address_on_interface(tgen, rname, "vlan112", "fd00:50:1:1::12/64")
     elif rname == "tor-21":
-        router.run("ip addr add 192.168.12.21/24 dev vlan112")
-        router.run("ip addr add fd00:50:1:1::21/64 dev vlan112")
+        create_address_on_interface(tgen, rname, "vlan112", "192.168.12.21/24")
+        create_address_on_interface(tgen, rname, "vlan112", "fd00:50:1:1::21/64")
     elif rname == "tor-22":
-        router.run("ip addr add 192.168.12.22/24 dev vlan112")
-        router.run("ip addr add fd00:50:1:1::22/64 dev vlan112")
+        create_address_on_interface(tgen, rname, "vlan112", "192.168.12.22/24")
+        create_address_on_interface(tgen, rname, "vlan112", "fd00:50:1:1::22/64")

     router.run("ip link set dev vlan112 up")
     router.run("/sbin/sysctl net.ipv4.conf.vlan112.arp_accept=1")
@@ -596,17 +600,21 @@ def setup_bordertor_ext_connectivity(tgen, ip_version):
     # swp3.4001 for VRF1 L3VNI
     router.run("ip link add link swp3 name swp3.4001 type vlan id 4001")
     router.run("ip link set dev swp3.4001 master vrf1")
-    router.run("ip addr add 192.0.2.2/30 dev swp3.4001")
+    create_address_on_interface(tgen, router.name, "swp3.4001", "192.0.2.2/30")
     if ip_version == "ipv6":
-        router.run("ip addr add 2001:db8:144:1::2/64 dev swp3.4001")
+        create_address_on_interface(
+            tgen, router.name, "swp3.4001", "2001:db8:144:1::2/64"
+        )
     router.run("ip link set dev swp3.4001 up")

     # swp3.4002 for VRF2 L3VNI
     router.run("ip link add link swp3 name swp3.4002 type vlan id 4002")
     router.run("ip link set dev swp3.4002 master vrf2")
-    router.run("ip addr add 192.0.2.6/30 dev swp3.4002")
+    create_address_on_interface(tgen, router.name, "swp3.4002", "192.0.2.6/30")
     if ip_version == "ipv6":
-        router.run("ip addr add 2001:db8:144:2::6/64 dev swp3.4002")
+        create_address_on_interface(
+            tgen, router.name, "swp3.4002", "2001:db8:144:2::6/64"
+        )
     router.run("ip link set dev swp3.4002 up")

     # Configure bordertor-12
@@ -617,17 +625,21 @@ def setup_bordertor_ext_connectivity(tgen, ip_version):
     # swp3.4001 for VRF1 L3VNI
     router.run("ip link add link swp3 name swp3.4001 type vlan id 4001")
     router.run("ip link set dev swp3.4001 master vrf1")
-    router.run("ip addr add 192.0.2.10/30 dev swp3.4001")
+    create_address_on_interface(tgen, router.name, "swp3.4001", "192.0.2.10/30")
     if ip_version == "ipv6":
-        router.run("ip addr add 2001:db8:144:11::2/64 dev swp3.4001")
+        create_address_on_interface(
+            tgen, router.name, "swp3.4001", "2001:db8:144:11::2/64"
+        )
     router.run("ip link set dev swp3.4001 up")

     # swp3.4002 for VRF2 L3VNI
     router.run("ip link add link swp3 name swp3.4002 type vlan id 4002")
     router.run("ip link set dev swp3.4002 master vrf2")
-    router.run("ip addr add 192.0.2.14/30 dev swp3.4002")
+    create_address_on_interface(tgen, router.name, "swp3.4002", "192.0.2.14/30")
     if ip_version == "ipv6":
-        router.run("ip addr add 2001:db8:144:12::6/64 dev swp3.4002")
+        create_address_on_interface(
+            tgen, router.name, "swp3.4002", "2001:db8:144:12::6/64"
+        )
     router.run("ip link set dev swp3.4002 up")


@@ -646,41 +658,45 @@ def setup_ext1(tgen, ip_version):
     # Configure swp1 - Connected to bordertor-11
     router.run("ip link set dev swp1 up")
     if ip_version == "ipv6":
-        router.run("ip addr add fd00:10:254::2:0:2/126 dev swp1")
+        create_address_on_interface(
+            tgen, router.name, "swp1", "fd00:10:254::2:0:2/126"
+        )
     else:  # ipv4
-        router.run("ip addr add 10.254.0.10/30 dev swp1")
+        create_address_on_interface(tgen, router.name, "swp1", "10.254.0.10/30")

     # Configure swp2 - Connected to bordertor-12
     router.run("ip link set dev swp2 up")
     if ip_version == "ipv6":
-        router.run("ip addr add fd00:10:254::9:0:2/126 dev swp2")
+        create_address_on_interface(
+            tgen, router.name, "swp2", "fd00:10:254::9:0:2/126"
+        )
     else:  # ipv4
-        router.run("ip addr add 10.254.0.38/30 dev swp2")
+        create_address_on_interface(tgen, router.name, "swp2", "10.254.0.38/30")

     # Configure VLAN sub-interfaces on swp1 for bordertor-11
     # swp1.4001 for VRF1 L3VNI connectivity - always configure both IPv4 and IPv6
     router.run("ip link add link swp1 name swp1.4001 type vlan id 4001")
-    router.run("ip addr add 192.0.2.1/30 dev swp1.4001")
-    router.run("ip addr add 2001:db8:144:1::1/64 dev swp1.4001")
+    create_address_on_interface(tgen, router.name, "swp1.4001", "192.0.2.1/30")
+    create_address_on_interface(tgen, router.name, "swp1.4001", "2001:db8:144:1::1/64")
     router.run("ip link set dev swp1.4001 up")

     # swp1.4002 for VRF2 L3VNI connectivity - always configure both IPv4 and IPv6
     router.run("ip link add link swp1 name swp1.4002 type vlan id 4002")
-    router.run("ip addr add 192.0.2.5/30 dev swp1.4002")
-    router.run("ip addr add 2001:db8:144:2::5/64 dev swp1.4002")
+    create_address_on_interface(tgen, router.name, "swp1.4002", "192.0.2.5/30")
+    create_address_on_interface(tgen, router.name, "swp1.4002", "2001:db8:144:2::5/64")
     router.run("ip link set dev swp1.4002 up")

     # Configure VLAN sub-interfaces on swp2 for bordertor-12
     # swp2.4001 for VRF1 L3VNI connectivity - always configure both IPv4 and IPv6
     router.run("ip link add link swp2 name swp2.4001 type vlan id 4001")
-    router.run("ip addr add 192.0.2.9/30 dev swp2.4001")
-    router.run("ip addr add 2001:db8:144:11::1/64 dev swp2.4001")
+    create_address_on_interface(tgen, router.name, "swp2.4001", "192.0.2.9/30")
+    create_address_on_interface(tgen, router.name, "swp2.4001", "2001:db8:144:11::1/64")
     router.run("ip link set dev swp2.4001 up")

     # swp2.4002 for VRF2 L3VNI connectivity - always configure both IPv4 and IPv6
     router.run("ip link add link swp2 name swp2.4002 type vlan id 4002")
-    router.run("ip addr add 192.0.2.13/30 dev swp2.4002")
-    router.run("ip addr add 2001:db8:144:12::5/64 dev swp2.4002")
+    create_address_on_interface(tgen, router.name, "swp2.4002", "192.0.2.13/30")
+    create_address_on_interface(tgen, router.name, "swp2.4002", "2001:db8:144:12::5/64")
     router.run("ip link set dev swp2.4002 up")

     # Configure swp3-6 for connection to host-1 (4 links)
@@ -698,8 +714,12 @@ def setup_ext1(tgen, ip_version):
         output = router.run(f"ip link show {intf} 2>&1")
         if "does not exist" not in output and "Cannot find device" not in output:
             router.run(f"ip link set dev {intf} up")
-            router.run(f"ip addr add 198.51.{ipv4_net}.1/24 dev {intf}")
-            router.run(f"ip addr add 2001:db8:81:{ipv6_net}::1/64 dev {intf}")
+            create_address_on_interface(
+                tgen, router.name, intf, f"198.51.{ipv4_net}.1/24"
+            )
+            create_address_on_interface(
+                tgen, router.name, intf, f"2001:db8:81:{ipv6_net}::1/64"
+            )
             logger.info(f"Configured {intf} on ext-1 (connected to host-1 swp{i-2})")
         else:
             logger.info(f"Interface {intf} does not exist on ext-1, skipping")
diff --git a/tests/topotests/bgp_evpn_vxlan_macvrf_soo_topo1/test_bgp_evpn_vxlan_macvrf_soo.py b/tests/topotests/bgp_evpn_vxlan_macvrf_soo_topo1/test_bgp_evpn_vxlan_macvrf_soo.py
index cdb2ab0212..4cf8078a58 100755
--- a/tests/topotests/bgp_evpn_vxlan_macvrf_soo_topo1/test_bgp_evpn_vxlan_macvrf_soo.py
+++ b/tests/topotests/bgp_evpn_vxlan_macvrf_soo_topo1/test_bgp_evpn_vxlan_macvrf_soo.py
@@ -41,7 +41,7 @@ from lib.evpn import (
 )
 from lib.topogen import Topogen, TopoRouter, get_topogen
 from lib.topolog import logger
-from lib.common_config import step
+from lib.common_config import create_address_on_interface, step

 pytestmark = [pytest.mark.bgpd, pytest.mark.evpn, pytest.mark.ospfd]

@@ -128,7 +128,7 @@ def setup_module(mod):
     ## Setup L2VNI bridge/vxlan + L2 PE/CE link
     # pe1
     pe1.run("ip link add name br101 type bridge stp_state 0")
-    pe1.run("ip addr add 10.10.1.1/24 dev br101")
+    create_address_on_interface(pe1.tgen, pe1.name, "br101", "10.10.1.1/24")
     pe1.run("ip link set dev br101 addr aa:bb:cc:00:11:aa")
     pe1.run("ip link set dev br101 master VRF-A")
     pe1.run("ip link set dev br101 up")
@@ -142,7 +142,7 @@ def setup_module(mod):
     pe1.run("ip link set dev PE1-eth0 up")
     # pe2
     pe2.run("ip link add name br101 type bridge stp_state 0")
-    pe2.run("ip addr add 10.10.1.3/24 dev br101")
+    create_address_on_interface(pe2.tgen, pe2.name, "br101", "10.10.1.3/24")
     pe2.run("ip link set dev br101 addr aa:bb:cc:00:22:ff")
     pe2.run("ip link set dev br101 master VRF-A")
     pe2.run("ip link set dev br101 up")
diff --git a/tests/topotests/bgp_evpn_vxlan_macvrf_soo_topo1/test_bgp_evpn_vxlan_macvrf_soo_v6_vtep.py b/tests/topotests/bgp_evpn_vxlan_macvrf_soo_topo1/test_bgp_evpn_vxlan_macvrf_soo_v6_vtep.py
index 850bb1522b..43a2addc96 100755
--- a/tests/topotests/bgp_evpn_vxlan_macvrf_soo_topo1/test_bgp_evpn_vxlan_macvrf_soo_v6_vtep.py
+++ b/tests/topotests/bgp_evpn_vxlan_macvrf_soo_topo1/test_bgp_evpn_vxlan_macvrf_soo_v6_vtep.py
@@ -41,7 +41,7 @@ from lib.evpn import (
 )
 from lib.topogen import Topogen, TopoRouter, get_topogen
 from lib.topolog import logger
-from lib.common_config import step
+from lib.common_config import create_address_on_interface, step

 pytestmark = [pytest.mark.bgpd, pytest.mark.evpn, pytest.mark.ospf6d]

@@ -128,7 +128,7 @@ def setup_module(mod):
     ## Setup L2VNI bridge/vxlan + L2 PE/CE link
     # pe1
     pe1.run("ip link add name br101 type bridge stp_state 0")
-    pe1.run("ip addr add 10.10.1.1/24 dev br101")
+    create_address_on_interface(pe1.tgen, pe1.name, "br101", "10.10.1.1/24")
     pe1.run("ip link set dev br101 addr aa:bb:cc:00:11:aa")
     pe1.run("ip link set dev br101 master VRF-A")
     pe1.run("ip link set dev br101 up")
@@ -142,7 +142,7 @@ def setup_module(mod):
     pe1.run("ip link set dev PE1-eth0 up")
     # pe2
     pe2.run("ip link add name br101 type bridge stp_state 0")
-    pe2.run("ip addr add 10.10.1.3/24 dev br101")
+    create_address_on_interface(pe2.tgen, pe2.name, "br101", "10.10.1.3/24")
     pe2.run("ip link set dev br101 addr aa:bb:cc:00:22:ff")
     pe2.run("ip link set dev br101 master VRF-A")
     pe2.run("ip link set dev br101 up")
diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/test_bgp_evpn_vxlan_svd.py b/tests/topotests/bgp_evpn_vxlan_svd_topo1/test_bgp_evpn_vxlan_svd.py
index c4a5087f11..f0d7871a8e 100755
--- a/tests/topotests/bgp_evpn_vxlan_svd_topo1/test_bgp_evpn_vxlan_svd.py
+++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/test_bgp_evpn_vxlan_svd.py
@@ -49,7 +49,10 @@ from lib.evpn import (
 )
 from lib.topogen import Topogen, TopoRouter, get_topogen
 from lib.topolog import logger
-from lib.common_config import required_linux_kernel_version
+from lib.common_config import (
+    create_address_on_interface,
+    required_linux_kernel_version,
+)

 # Required to instantiate the topology builder class.

@@ -107,7 +110,7 @@ def setup_pe_router(tgen, pe_name, tunnel_local_ip, svi_ip, intf):
     # setup svi
     pe.run("ip link add link bridge name vlan1 type vlan id 1 protocol 802.1q")
     pe.run("ip link set dev vlan1 up")
-    pe.run("ip addr add {0} dev vlan1".format(svi_ip))
+    create_address_on_interface(tgen, pe_name, "vlan1", svi_ip)
     pe.run("/sbin/sysctl net.ipv4.conf.vlan1.arp_accept=1")

     # setup single vxlan device
@@ -130,8 +133,8 @@ def setup_pe_router(tgen, pe_name, tunnel_local_ip, svi_ip, intf):
     if pe_name == "PE1":
         pe.run("ip link add vrf-blue type vrf table 1002")
         pe.run("ip link set dev vrf-blue up")
-        pe.run("ip addr add 27.2.0.85/32 dev vrf-blue")
-        pe.run("ip addr add 27.3.0.85/32 dev vrf-purple")
+        create_address_on_interface(tgen, pe_name, "vrf-blue", "27.2.0.85/32")
+        create_address_on_interface(tgen, pe_name, "vrf-purple", "27.3.0.85/32")
     if pe_name == "PE2":
         pe.run("ip link add vrf-blue type vrf table 2400")
         pe.run("ip link set dev vrf-blue up")
diff --git a/tests/topotests/bgp_evpn_vxlan_topo1/test_bgp_evpn_vxlan.py b/tests/topotests/bgp_evpn_vxlan_topo1/test_bgp_evpn_vxlan.py
index e11b11cbdb..ac186096ba 100755
--- a/tests/topotests/bgp_evpn_vxlan_topo1/test_bgp_evpn_vxlan.py
+++ b/tests/topotests/bgp_evpn_vxlan_topo1/test_bgp_evpn_vxlan.py
@@ -33,6 +33,7 @@ from lib.evpn import (
     evpn_check_bgp_imet,
 )
 from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.common_config import create_address_on_interface
 from lib.topolog import logger

 # Required to instantiate the topology builder class.
@@ -88,7 +89,7 @@ def setup_module(mod):

     # set up PE bridges with the EVPN member interfaces facing the CE hosts
     pe1.run("ip link add name br101 type bridge stp_state 0")
-    pe1.run("ip addr add 10.10.1.1/24 dev br101")
+    create_address_on_interface(pe1.tgen, pe1.name, "br101", "10.10.1.1/24")
     pe1.run("ip link set dev br101 up")
     pe1.run(
         "ip link add vxlan101 type vxlan id 101 dstport 4789 local 10.10.10.10 nolearning"
@@ -98,7 +99,7 @@ def setup_module(mod):
     pe1.run("ip link set dev PE1-eth0 master br101")

     pe2.run("ip link add name br101 type bridge stp_state 0")
-    pe2.run("ip addr add 10.10.1.3/24 dev br101")
+    create_address_on_interface(pe2.tgen, pe2.name, "br101", "10.10.1.3/24")
     pe2.run("ip link set dev br101 up")
     pe2.run(
         "ip link add vxlan101 type vxlan id 101 dstport 4789 local 10.30.30.30 nolearning"
@@ -125,7 +126,7 @@ def setup_module(mod):
     pe1.run("bridge vlan add vid 999 dev vxlan999 pvid untagged")
     pe1.run("ip link add link br999 name vlan999 type vlan id 999")
     pe1.run("ip link set dev vlan999 master vrf-blue")
-    pe1.run("ip addr add 10.99.99.1/24 dev vlan999")
+    create_address_on_interface(pe1.tgen, pe1.name, "vlan999", "10.99.99.1/24")
     pe1.run("ip link set dev vlan999 up")

     # PE2
@@ -144,7 +145,7 @@ def setup_module(mod):
     pe2.run("bridge vlan add vid 999 dev vxlan999 pvid untagged")
     pe2.run("ip link add link br999 name vlan999 type vlan id 999")
     pe2.run("ip link set dev vlan999 master vrf-blue")
-    pe2.run("ip addr add 10.99.99.3/24 dev vlan999")
+    create_address_on_interface(pe2.tgen, pe2.name, "vlan999", "10.99.99.3/24")
     pe2.run("ip link set dev vlan999 up")

     # This is a sample of configuration loading.
diff --git a/tests/topotests/bgp_evpn_vxlan_topo1/test_bgp_evpn_vxlan_v6_vtep.py b/tests/topotests/bgp_evpn_vxlan_topo1/test_bgp_evpn_vxlan_v6_vtep.py
index ae16219e1e..01e3f96488 100755
--- a/tests/topotests/bgp_evpn_vxlan_topo1/test_bgp_evpn_vxlan_v6_vtep.py
+++ b/tests/topotests/bgp_evpn_vxlan_topo1/test_bgp_evpn_vxlan_v6_vtep.py
@@ -37,6 +37,7 @@ from lib.evpn import (
     evpn_check_bgp_imet,
 )
 from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.common_config import create_address_on_interface
 from lib.topolog import logger

 # Required to instantiate the topology builder class.
@@ -92,7 +93,7 @@ def setup_module(mod):

     # set up PE bridges with the EVPN member interfaces facing the CE hosts
     pe1.run("ip link add name br101 type bridge stp_state 0")
-    pe1.run("ip addr add 10.10.1.1/24 dev br101")
+    create_address_on_interface(pe1.tgen, pe1.name, "br101", "10.10.1.1/24")
     pe1.run("ip link set dev br101 up")
     pe1.run(
         "ip link add vxlan101 type vxlan id 101 dstport 4789 local 10:10:10::10 nolearning"
@@ -102,7 +103,7 @@ def setup_module(mod):
     pe1.run("ip link set dev PE1-eth0 master br101")

     pe2.run("ip link add name br101 type bridge stp_state 0")
-    pe2.run("ip addr add 10.10.1.3/24 dev br101")
+    create_address_on_interface(pe2.tgen, pe2.name, "br101", "10.10.1.3/24")
     pe2.run("ip link set dev br101 up")
     pe2.run(
         "ip link add vxlan101 type vxlan id 101 dstport 4789 local 10:30:30::30 nolearning"
diff --git a/tests/topotests/bgp_link_bw_ip/test_bgp_linkbw_ip.py b/tests/topotests/bgp_link_bw_ip/test_bgp_linkbw_ip.py
index fd67b2ecdd..0798ac0d77 100644
--- a/tests/topotests/bgp_link_bw_ip/test_bgp_linkbw_ip.py
+++ b/tests/topotests/bgp_link_bw_ip/test_bgp_linkbw_ip.py
@@ -27,6 +27,7 @@ sys.path.append(os.path.join(CWD, "../"))
 # Import topogen and topotest helpers
 from lib import topotest
 from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.common_config import create_address_on_interface
 from lib.topolog import logger

 # Required to instantiate the topology builder class.
@@ -174,7 +175,7 @@ def test_bgp_linkbw_adv():
     # Configure anycast IP on server r7
     logger.info("Configure anycast IP on server r7")

-    tgen.net["r7"].cmd("ip addr add 198.10.1.1/32 dev r7-eth1")
+    create_address_on_interface(tgen, "r7", "r7-eth1", "198.10.1.1/32")

     # Check on spine router r2 for link-bw advertisement by leaf router r4
     logger.info("Check on spine router r2 for link-bw advertisement by leaf router r4")
@@ -232,7 +233,7 @@ def test_bgp_cumul_linkbw():
     # Configure anycast IP on additional server r8
     logger.info("Configure anycast IP on server r8")

-    tgen.net["r8"].cmd("ip addr add 198.10.1.1/32 dev r8-eth1")
+    create_address_on_interface(tgen, "r8", "r8-eth1", "198.10.1.1/32")

     # Check multipath on leaf router r4
     logger.info("Check multipath on leaf router r4")
@@ -288,7 +289,7 @@ def test_weighted_ecmp():
     # Configure anycast IP on additional server r9
     logger.info("Configure anycast IP on server r9")

-    tgen.net["r9"].cmd("ip addr add 198.10.1.1/32 dev r9-eth1")
+    create_address_on_interface(tgen, "r9", "r9-eth1", "198.10.1.1/32")

     # Check multipath on spine router r2
     logger.info("Check multipath on spine router r2")
@@ -316,7 +317,7 @@ def test_weighted_ecmp():
     # Configure anycast IP on additional server r10
     logger.info("Configure anycast IP on server r10")

-    tgen.net["r10"].cmd("ip addr add 198.10.1.1/32 dev r10-eth1")
+    create_address_on_interface(tgen, "r10", "r10-eth1", "198.10.1.1/32")

     # Check if bandwidth is properly encoded with non IEEE floatig-point (uint32) format on r3
     logger.info(
@@ -448,9 +449,9 @@ def test_weighted_ecmp_second_anycast_ip():
     # Configure anycast IP on additional server r7, r9 and r10
     logger.info("Configure anycast IP on server r7, r9 and r10")

-    tgen.net["r7"].cmd("ip addr add 198.10.1.11/32 dev r7-eth1")
-    tgen.net["r9"].cmd("ip addr add 198.10.1.11/32 dev r9-eth1")
-    tgen.net["r10"].cmd("ip addr add 198.10.1.11/32 dev r10-eth1")
+    create_address_on_interface(tgen, "r7", "r7-eth1", "198.10.1.11/32")
+    create_address_on_interface(tgen, "r9", "r9-eth1", "198.10.1.11/32")
+    create_address_on_interface(tgen, "r10", "r10-eth1", "198.10.1.11/32")

     # Check link-bandwidth and weighted ECMP on super-spine router r1
     logger.info("Check link-bandwidth and weighted ECMP on super-spine router r1")
diff --git a/tests/topotests/bgp_link_state_bgp_fabric/test_bgp_link_state_bgp_fabric.py b/tests/topotests/bgp_link_state_bgp_fabric/test_bgp_link_state_bgp_fabric.py
index 726d83a9a7..2d3ebfe6f8 100644
--- a/tests/topotests/bgp_link_state_bgp_fabric/test_bgp_link_state_bgp_fabric.py
+++ b/tests/topotests/bgp_link_state_bgp_fabric/test_bgp_link_state_bgp_fabric.py
@@ -43,6 +43,7 @@ sys.path.append(os.path.join(CWD, "../"))
 # pylint: disable=C0413
 from lib import topotest
 from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.common_config import create_address_on_interface
 from lib.topolog import logger

 pytestmark = [pytest.mark.bgpd]
@@ -932,7 +933,7 @@ def test_loopback_address_unset_restore():

     # Step 4: Restore IP address on loopback
     logger.info("Step 4: Restoring IP address on loopback interface on r1")
-    r1.run("ip addr add 10.1.1.1/32 dev lo")
+    create_address_on_interface(r1.tgen, r1.name, "lo", "10.1.1.1/32")

     # Step 5: Verify loopback prefix NLRI is re-advertised
     logger.info("Step 5: Verifying loopback prefix NLRI is re-advertised to rr")
diff --git a/tests/topotests/bgp_srv6l3vpn_multi_nlri/ce/setup.sh b/tests/topotests/bgp_srv6l3vpn_multi_nlri/ce/setup.sh
index 67f8032738..43be196f66 100644
--- a/tests/topotests/bgp_srv6l3vpn_multi_nlri/ce/setup.sh
+++ b/tests/topotests/bgp_srv6l3vpn_multi_nlri/ce/setup.sh
@@ -1,12 +1,2 @@
 ip link add dum0 type dummy
 ip link set dum0 up
-ip addr add 192.100.0.1/32 dev dum0
-ip addr add 192.100.0.2/32 dev dum0
-ip addr add 192.100.0.3/32 dev dum0
-ip addr add 192.100.0.4/32 dev dum0
-ip addr add 192.100.0.5/32 dev dum0
-ip addr add 192.100.0.6/32 dev dum0
-ip addr add 192.100.0.7/32 dev dum0
-ip addr add 192.100.0.8/32 dev dum0
-ip addr add 192.100.0.9/32 dev dum0
-ip addr add 192.100.0.10/32 dev dum0
diff --git a/tests/topotests/bgp_srv6l3vpn_multi_nlri/test_bgp_srv6l3vpn_multi_nlri.py b/tests/topotests/bgp_srv6l3vpn_multi_nlri/test_bgp_srv6l3vpn_multi_nlri.py
index 014af01e09..05ee3646f7 100644
--- a/tests/topotests/bgp_srv6l3vpn_multi_nlri/test_bgp_srv6l3vpn_multi_nlri.py
+++ b/tests/topotests/bgp_srv6l3vpn_multi_nlri/test_bgp_srv6l3vpn_multi_nlri.py
@@ -15,7 +15,10 @@ sys.path.append(os.path.join(CWD, "../"))
 from lib import topotest
 from lib.topogen import Topogen, get_topogen
 from lib.topolog import logger
-from lib.common_config import required_linux_kernel_version
+from lib.common_config import (
+    create_address_on_interface,
+    required_linux_kernel_version,
+)

 pytestmark = [pytest.mark.bgpd]

@@ -49,6 +52,11 @@ def setup_module(mod):
         setup = os.path.join(CWD, "{}/setup.sh".format(rname))
         if os.path.exists(setup):
             router.run("/bin/bash {}".format(setup))
+            if rname == "ce":
+                for host in range(1, 11):
+                    create_address_on_interface(
+                        tgen, rname, "dum0", "192.100.0.{}/32".format(host)
+                    )
         router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)))

     tgen.start_router()
diff --git a/tests/topotests/frr_reload_vrf/dataplane_lib.py b/tests/topotests/frr_reload_vrf/dataplane_lib.py
index 25fc8bb53d..18cf082772 100644
--- a/tests/topotests/frr_reload_vrf/dataplane_lib.py
+++ b/tests/topotests/frr_reload_vrf/dataplane_lib.py
@@ -198,8 +198,7 @@ def plumb_pe(node, num_vrfs, num_mcast_vrfs):
 def plumb_host(node, pe, v, rx=False):
     gw = rx_gw(v) if rx else tenant_gw(pe, v)
     ip = rx_host(v) if rx else tenant_host(pe, v)
-    return [
-        "ip addr add {}/24 dev {}-eth0".format(ip, node),
+    return "{}/24".format(ip), [
         "ip link set dev {}-eth0 up".format(node),
         "ip route add default via {}".format(gw),
     ]
diff --git a/tests/topotests/frr_reload_vrf/test_frr_reload_evpn_rt_import_scale.py b/tests/topotests/frr_reload_vrf/test_frr_reload_evpn_rt_import_scale.py
index 740970926b..fdf63774e1 100644
--- a/tests/topotests/frr_reload_vrf/test_frr_reload_evpn_rt_import_scale.py
+++ b/tests/topotests/frr_reload_vrf/test_frr_reload_evpn_rt_import_scale.py
@@ -40,7 +40,11 @@ CWD = os.path.dirname(os.path.realpath(__file__))
 sys.path.append(os.path.join(CWD, ".."))

 from lib import topotest
-from lib.common_config import required_linux_kernel_version, step
+from lib.common_config import (
+    create_address_on_interface,
+    required_linux_kernel_version,
+    step,
+)
 from lib.evpn import (
     EVPN_SCALE_RT_ASNS,
     EVPN_SCALE_RT_PER_ASN,
@@ -223,7 +227,9 @@ def tgen(request):

     for name, ip in (("pe1", PE1_IP), ("pe2", PE2_IP)):
         router = tg.gears[name]
-        router.cmd_raises("ip addr add {}/24 dev {}-eth0".format(ip, name))
+        create_address_on_interface(
+            tg, name, "{}-eth0".format(name), "{}/24".format(ip)
+        )
         router.cmd_raises("ip link set dev {}-eth0 up".format(name))
         evpn_plumb_l3vni(router, VRF, VRF_TABLE, L3VNI, ip)

diff --git a/tests/topotests/frr_reload_vrf/test_frr_reload_evpn_rt_scale.py b/tests/topotests/frr_reload_vrf/test_frr_reload_evpn_rt_scale.py
index 5b56e6619d..fd49fa62f4 100644
--- a/tests/topotests/frr_reload_vrf/test_frr_reload_evpn_rt_scale.py
+++ b/tests/topotests/frr_reload_vrf/test_frr_reload_evpn_rt_scale.py
@@ -50,7 +50,10 @@ from lib import topotest
 from lib.evpn import evpn_plumb_l3vni, evpn_rt_config_lines, evpn_scale_rt_list
 from lib.topogen import Topogen
 from lib.topotest import iproute2_is_vrf_capable
-from lib.common_config import required_linux_kernel_version
+from lib.common_config import (
+    create_address_on_interface,
+    required_linux_kernel_version,
+)

 import frr_reload_lib as f_reload

@@ -192,7 +195,7 @@ def tgen(request):

     r1 = tg.gears["r1"]
     # VTEP must exist before the VXLAN device is created.
-    r1.cmd_raises("ip addr add {}/32 dev lo".format(VTEP_IP))
+    create_address_on_interface(tg, "r1", "lo", "{}/32".format(VTEP_IP))
     evpn_plumb_l3vni(r1, VRF, VRF_TABLE, L3VNI, VTEP_IP)
     r1.cmd_raises("ip link set dev r1-eth0 master {}".format(VRF))
     r1.cmd_raises("ip link set dev r1-eth0 up")
diff --git a/tests/topotests/frr_reload_vrf/test_frr_reload_vrf_dataplane.py b/tests/topotests/frr_reload_vrf/test_frr_reload_vrf_dataplane.py
index 1de1fd5d7f..de178683dc 100644
--- a/tests/topotests/frr_reload_vrf/test_frr_reload_vrf_dataplane.py
+++ b/tests/topotests/frr_reload_vrf/test_frr_reload_vrf_dataplane.py
@@ -45,7 +45,11 @@ from lib import topotest
 from lib.topogen import Topogen
 from lib.topolog import logger
 from lib.topotest import iproute2_is_vrf_capable
-from lib.common_config import create_interface_in_kernel, required_linux_kernel_version
+from lib.common_config import (
+    create_address_on_interface,
+    create_interface_in_kernel,
+    required_linux_kernel_version,
+)
 from lib.pim import McastTesterHelper

 import dataplane_lib as D
@@ -125,10 +129,12 @@ def tgen(request):
     tg.start_router()

     # Host addressing is applied AFTER start_router: the hosts run no FRR, and a
-    # raw "ip addr add" on their veths before startup is wiped by munet's
+    # kernel address on their veths before startup is wiped by munet's
     # interface reconciliation. Doing it post-start makes it stick.
     for hname, pe, v, rx, ifidx in D.iter_hosts(NUM_VRFS, NUM_MCAST_VRFS):
-        for cmd in D.plumb_host(hname, pe, v, rx=rx):
+        ip, cmds = D.plumb_host(hname, pe, v, rx=rx)
+        create_address_on_interface(tg, hname, "{}-eth0".format(hname), ip)
+        for cmd in cmds:
             tg.gears[hname].cmd_raises(cmd)

     yield tg
diff --git a/tests/topotests/ospf_4222_recommendation_5/test_ospf_broadcast_router_dynamic_pacing.py b/tests/topotests/ospf_4222_recommendation_5/test_ospf_broadcast_router_dynamic_pacing.py
index 50cc0b1825..24dd9667c0 100644
--- a/tests/topotests/ospf_4222_recommendation_5/test_ospf_broadcast_router_dynamic_pacing.py
+++ b/tests/topotests/ospf_4222_recommendation_5/test_ospf_broadcast_router_dynamic_pacing.py
@@ -17,7 +17,7 @@ import time
 from lib import topotest
 from lib.topogen import Topogen, get_topogen
 from lib.topolog import logger
-from lib.common_config import step
+from lib.common_config import create_address_on_interface, step
 from util_pcap import PerInterfacePcapManager

 """
@@ -397,8 +397,8 @@ def test_ospf_broadcast_external_lsa_flooding():
     ), f"failed to enable redistribute connected: stdout={out} stderr={err}"

     for i in range(1, 101):
-        tgen.net["r1"].cmd(f"ip addr add 198.51.110.{i}/32 dev lo")
-        tgen.net["r1"].cmd(f"ip addr add 198.51.111.{i}/32 dev lo")
+        create_address_on_interface(tgen, "r1", "lo", f"198.51.110.{i}/32")
+        create_address_on_interface(tgen, "r1", "lo", f"198.51.111.{i}/32")

     step("Continuously verify key adjacencies remain FULL during LSA storm")
     for _ in range(5):
@@ -602,7 +602,7 @@ def test_ospf_dynamic_pacing_queue_kick_on_limit_increase():
     )
     tgen.net["r1"].cmd("vtysh -c 'conf t' -c 'router ospf' -c 'redistribute connected'")
     for i in range(1, 101):
-        tgen.net["r1"].cmd(f"ip addr add 198.51.120.{i}/32 dev lo")
+        create_address_on_interface(tgen, "r1", "lo", f"198.51.120.{i}/32")

     # Step 4: Mark start of the congestion/recovery observation window, then
     # flap r3/r4/r5 simultaneously right after injecting LSAs.
diff --git a/tests/topotests/ospf_rfc4222_inactive_tmr/test_ospf_rfc4222_inactive_tmr.py b/tests/topotests/ospf_rfc4222_inactive_tmr/test_ospf_rfc4222_inactive_tmr.py
index 1fadb8c074..1822213471 100644
--- a/tests/topotests/ospf_rfc4222_inactive_tmr/test_ospf_rfc4222_inactive_tmr.py
+++ b/tests/topotests/ospf_rfc4222_inactive_tmr/test_ospf_rfc4222_inactive_tmr.py
@@ -15,6 +15,7 @@ import pytest
 import json
 import re

+from lib.common_config import create_address_on_interface
 from lib.topogen import Topogen, get_topogen, TopoRouter, topotest


@@ -166,7 +167,7 @@ interface r2-eth0
     # Flood: add 10 loopbacks on r1 and redistribute connected
     r1.vtysh_cmd("conf t\nrouter ospf\n redistribute connected\n exit")
     for i in range(1, 50):
-        r1.cmd(f"ip addr add 198.51.100.{i}/32 dev lo")
+        create_address_on_interface(tgen, "r1", "lo", f"198.51.100.{i}/32")

     topotest.sleep(3, "Wait for LSU flood")
     out = r2.vtysh_cmd("show ip ospf neighbor detail")
diff --git a/tests/topotests/pim_nocache_forward/test_pim_nocache_forward.py b/tests/topotests/pim_nocache_forward/test_pim_nocache_forward.py
index b51d7fd98b..a76a2353d3 100644
--- a/tests/topotests/pim_nocache_forward/test_pim_nocache_forward.py
+++ b/tests/topotests/pim_nocache_forward/test_pim_nocache_forward.py
@@ -56,7 +56,12 @@ CWD = os.path.dirname(os.path.realpath(__file__))
 sys.path.append(os.path.join(CWD, "../"))

 from lib import topotest
-from lib.common_config import step, write_test_footer, write_test_header
+from lib.common_config import (
+    create_address_on_interface,
+    step,
+    write_test_footer,
+    write_test_header,
+)
 from lib.pim import (
     McastTesterHelper,
     clear_mroute,
@@ -588,7 +593,7 @@ def test_wrongvif_prefer_kernel_ingress(request):
     # SO_BINDTODEVICE uses the interface primary address; temporarily replace
     # 10.10.4.2 so packets are sourced as WRONGVIF_SOURCE toward the parent.
     h_src.run("ip addr del 10.10.4.2/24 dev h_src-eth0 || true")
-    h_src.run(f"ip addr add {source}/16 dev h_src-eth0")
+    create_address_on_interface(tgen, "h_src", "h_src-eth0", f"{source}/16")
     h_src.run(
         f"ip route replace default via {WRONGVIF_PARENT_SEC.split('/')[0]} || true"
     )
@@ -664,7 +669,7 @@ def test_wrongvif_prefer_kernel_ingress(request):
     )

     step("Move source traffic to alternate ingress {}".format(FHR_TO_TUNNEL))
-    h_src.run(f"ip addr add {source}/16 dev h_src-eth1 || true")
+    create_address_on_interface(tgen, "h_src", "h_src-eth1", f"{source}/16")
     h_src.run("ip link set h_src-eth1 up")
     h_src.run(f"ip route replace {WRONGVIF_TUNNEL_GW}/32 dev h_src-eth1 || true")
     app_helper.stop_traffic_senders()
@@ -713,7 +718,7 @@ def test_wrongvif_prefer_kernel_ingress(request):
     h_src.run(f"ip route del {WRONGVIF_TUNNEL_GW}/32 || true")
     h_src.run(f"ip addr del {source}/16 dev h_src-eth1 || true")
     h_src.run(f"ip addr del {source}/16 dev h_src-eth0 || true")
-    h_src.run("ip addr add 10.10.4.2/24 dev h_src-eth0 || true")
+    create_address_on_interface(tgen, "h_src", "h_src-eth0", "10.10.4.2/24")
     h_src.run("ip route replace default via 10.10.4.1 || true")

     write_test_footer(tc_name)
diff --git a/tests/topotests/simple_snmp_test/test_simple_snmp.py b/tests/topotests/simple_snmp_test/test_simple_snmp.py
index 137ba40543..74ebece7b7 100755
--- a/tests/topotests/simple_snmp_test/test_simple_snmp.py
+++ b/tests/topotests/simple_snmp_test/test_simple_snmp.py
@@ -25,6 +25,7 @@ sys.path.append(os.path.join(CWD, "../"))
 from lib import topotest
 from lib.topogen import Topogen, TopoRouter, get_topogen
 from lib.snmptest import SnmpTester
+from lib.common_config import create_address_on_interface
 from lib.topolog import logger

 pytestmark = [
@@ -52,14 +53,14 @@ def setup_module(mod):

     r1 = tgen.gears["r1"]

-    r1.run("ip addr add 192.168.12.12/24 dev r1-eth0")
-    r1.run("ip -6 addr add 2000:1:1:12::12/64 dev r1-eth0")
-    r1.run("ip addr add 192.168.13.13/24 dev r1-eth1")
-    r1.run("ip -6 addr add 2000:1:1:13::13/64 dev r1-eth1")
-    r1.run("ip addr add 192.168.14.14/24 dev r1-eth2")
-    r1.run("ip -6 addr add 2000:1:1:14::14/64 dev r1-eth2")
-    r1.run("ip addr add 1.1.1.1/32 dev lo")
-    r1.run("ip -6 addr add 2000:1:1:1::1/128 dev lo")
+    create_address_on_interface(tgen, "r1", "r1-eth0", "192.168.12.12/24")
+    create_address_on_interface(tgen, "r1", "r1-eth0", "2000:1:1:12::12/64")
+    create_address_on_interface(tgen, "r1", "r1-eth1", "192.168.13.13/24")
+    create_address_on_interface(tgen, "r1", "r1-eth1", "2000:1:1:13::13/64")
+    create_address_on_interface(tgen, "r1", "r1-eth2", "192.168.14.14/24")
+    create_address_on_interface(tgen, "r1", "r1-eth2", "2000:1:1:14::14/64")
+    create_address_on_interface(tgen, "r1", "lo", "1.1.1.1/32")
+    create_address_on_interface(tgen, "r1", "lo", "2000:1:1:1::1/128")
     r1.run("ip addr show")

     router_list = tgen.routers()
diff --git a/tests/topotests/zebra_ipv6_dad/test_zebra_ipv6_tentative_connected.py b/tests/topotests/zebra_ipv6_dad/test_zebra_ipv6_tentative_connected.py
index 160aee2873..9a86914374 100644
--- a/tests/topotests/zebra_ipv6_dad/test_zebra_ipv6_tentative_connected.py
+++ b/tests/topotests/zebra_ipv6_dad/test_zebra_ipv6_tentative_connected.py
@@ -26,7 +26,7 @@ sys.path.append(os.path.join(CWD, "../"))

 # pylint: disable=C0413
 from lib import topotest
-from lib.common_config import step
+from lib.common_config import create_address_on_interface, step
 from lib.topogen import Topogen, TopoRouter, get_topogen
 from lib.topolog import logger

@@ -123,7 +123,7 @@ def test_zebra_ipv6_tentative_not_in_rib():
     r1.run("echo 60 > /proc/sys/net/ipv6/conf/{}/dad_transmits".format(IFNAME))

     step("Add the IPv6 address while the interface is down")
-    r1.run("ip -6 addr add {}/64 dev {}".format(ADDR, IFNAME))
+    create_address_on_interface(tgen, "r1", IFNAME, "{}/64".format(ADDR))

     def _down_iface_and_tentative():
         try:
diff --git a/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py b/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py
index 59e47287e4..55c574dbb1 100644
--- a/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py
+++ b/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py
@@ -19,7 +19,11 @@ import sys
 import pytest
 import json
 from functools import partial
-from lib.common_config import create_interface_in_kernel, step
+from lib.common_config import (
+    create_address_on_interface,
+    create_interface_in_kernel,
+    step,
+)
 from lib.topolog import logger

 # Save the Current Working Directory to find configuration files.
@@ -378,8 +382,8 @@ def test_zebra_kernel_last_ipv4_address_deleted():
     # Prepare scene: create dummy interface
     # add two addresses, two routes
     create_interface_in_kernel(tgen, router.name, ifname)
-    router.run(f"ip -4 addr add 192.168.0.2/24 dev {ifname}")
-    router.run(f"ip -4 addr add 192.168.100.7/24 dev {ifname}")
+    create_address_on_interface(tgen, router.name, ifname, "192.168.0.2/24")
+    create_address_on_interface(tgen, router.name, ifname, "192.168.100.7/24")
     router.run(f"ip -4 route add 203.0.113.0/24 via 192.168.0.1")
     router.run(f"ip -4 route add 10.0.170.0/24 dev {ifname}")

@@ -605,8 +609,8 @@ def test_zebra_kernel_last_ipv6_address_deleted():
     create_interface_in_kernel(tgen, router.name, ifname)
     # clear scope link address
     router.run(f"ip -6 addr flush dev {ifname}")
-    router.run(f"ip -6 addr add 2001:db8:a::2/64 dev {ifname}")
-    router.run(f"ip -6 addr add 2001:db8:b::7/64 dev {ifname}")
+    create_address_on_interface(tgen, router.name, ifname, "2001:db8:a::2/64")
+    create_address_on_interface(tgen, router.name, ifname, "2001:db8:b::7/64")
     router.run(f"ip -6 route add 2001:db8:c::/64 via 2001:db8:a::1")
     router.run(f"ip -6 route add 2001:db8:d::/64 dev {ifname}")

diff --git a/tests/topotests/zebra_protodown_connected/test_zebra_protodown_connected.py b/tests/topotests/zebra_protodown_connected/test_zebra_protodown_connected.py
index 992db3714a..7cb6016ac3 100644
--- a/tests/topotests/zebra_protodown_connected/test_zebra_protodown_connected.py
+++ b/tests/topotests/zebra_protodown_connected/test_zebra_protodown_connected.py
@@ -15,6 +15,7 @@ CWD = os.path.dirname(os.path.realpath(__file__))
 sys.path.append(os.path.join(CWD, "../"))

 # pylint: disable=C0413
+from lib.common_config import create_address_on_interface
 from lib.topogen import Topogen, get_topogen
 from lib.topolog import logger

@@ -107,7 +108,7 @@ def test_vlan_updown():
     vrrp2.run("ip link del {} 2>/dev/null || true".format(vlan_if))
     cmd = "ip link add link vrrp2-eth0 name {} type vlan id 101"
     vrrp2.run(cmd.format(vlan_if))
-    vrrp2.run("ip addr add 50.0.0.1/24 dev {}".format(vlan_if))
+    create_address_on_interface(tgen, vrrp2.name, vlan_if, "50.0.0.1/24")
     vrrp2.run("ip link set {} up".format(vlan_if))
     sleep(2)

@@ -142,7 +143,7 @@ def test_macvlan_updown():
     vrrp2.run("ip link del {} 2>/dev/null || true".format(macvlan))
     cmd = "ip link add {} link vrrp2-eth0 type macvlan mode bridge"
     vrrp2.run(cmd.format(macvlan))
-    vrrp2.run("ip addr add 10.99.0.1/24 dev {}".format(macvlan))
+    create_address_on_interface(tgen, vrrp2.name, macvlan, "10.99.0.1/24")
     vrrp2.run("ip link set {} up".format(macvlan))
     sleep(2)

@@ -177,7 +178,7 @@ def test_rapid_updown():
     vrrp2.run("ip link del {} 2>/dev/null || true".format(vlan_if))
     cmd = "ip link add link vrrp2-eth0 name {} type vlan id 102"
     vrrp2.run(cmd.format(vlan_if))
-    vrrp2.run("ip addr add 60.0.0.1/24 dev {}".format(vlan_if))
+    create_address_on_interface(tgen, vrrp2.name, vlan_if, "60.0.0.1/24")
     vrrp2.run("ip link set {} up".format(vlan_if))
     sleep(2)