Commit 8e90499dc2 for frr

commit 8e90499dc2f178e63d44abc0fcf2958fcf46cfac
Author: Donald Sharp <sharpd@nvidia.com>
Date:   Thu Oct 1 16:54:42 2026 -0400

    tests: Convert them to use create_interface_in_kernel

    There is a common pattern in the tests:
    Create a dummy interface
    Assign an address to it.

    Find all the places that do this and have them use create_interface_in_kernel()
    instead.

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

diff --git a/tests/topotests/bgp_auth/test_bgp_auth1.py b/tests/topotests/bgp_auth/test_bgp_auth1.py
index acd9abfeb9..36ac6fe5bb 100644
--- a/tests/topotests/bgp_auth/test_bgp_auth1.py
+++ b/tests/topotests/bgp_auth/test_bgp_auth1.py
@@ -39,6 +39,7 @@ import sys
 import pytest
 from lib import topotest
 from lib.common_config import (
+    create_interface_in_kernel,
     save_initial_config_on_routers,
     reset_with_new_configs,
 )
@@ -90,15 +91,9 @@ def setup_module(mod):
     r3.cmd_raises("ip link add blue type vrf table 1001")
     r3.cmd_raises("ip link set up dev blue")

-    r1.cmd_raises("ip link add lo1 type dummy")
-    r1.cmd_raises("ip link set lo1 master blue")
-    r1.cmd_raises("ip link set up dev lo1")
-    r2.cmd_raises("ip link add lo1 type dummy")
-    r2.cmd_raises("ip link set up dev lo1")
-    r2.cmd_raises("ip link set lo1 master blue")
-    r3.cmd_raises("ip link add lo1 type dummy")
-    r3.cmd_raises("ip link set up dev lo1")
-    r3.cmd_raises("ip link set lo1 master blue")
+    create_interface_in_kernel(tgen, "R1", "lo1", vrf="blue")
+    create_interface_in_kernel(tgen, "R2", "lo1", vrf="blue")
+    create_interface_in_kernel(tgen, "R3", "lo1", vrf="blue")

     r1.cmd_raises("ip link set R1-eth2 master blue")
     r1.cmd_raises("ip link set R1-eth3 master blue")
@@ -122,15 +117,9 @@ def setup_module(mod):
     r3.cmd_raises("ip link add red type vrf table 1002")
     r3.cmd_raises("ip link set up dev red")

-    r1.cmd_raises("ip link add lo2 type dummy")
-    r1.cmd_raises("ip link set lo2 master red")
-    r1.cmd_raises("ip link set up dev lo2")
-    r2.cmd_raises("ip link add lo2 type dummy")
-    r2.cmd_raises("ip link set up dev lo2")
-    r2.cmd_raises("ip link set lo2 master red")
-    r3.cmd_raises("ip link add lo2 type dummy")
-    r3.cmd_raises("ip link set up dev lo2")
-    r3.cmd_raises("ip link set lo2 master red")
+    create_interface_in_kernel(tgen, "R1", "lo2", vrf="red")
+    create_interface_in_kernel(tgen, "R2", "lo2", vrf="red")
+    create_interface_in_kernel(tgen, "R3", "lo2", vrf="red")

     r1.cmd_raises("ip link set R1-eth4 master red")
     r1.cmd_raises("ip link set R1-eth5 master red")
diff --git a/tests/topotests/bgp_auth/test_bgp_auth2.py b/tests/topotests/bgp_auth/test_bgp_auth2.py
index 524d04f8d8..65de1058ee 100644
--- a/tests/topotests/bgp_auth/test_bgp_auth2.py
+++ b/tests/topotests/bgp_auth/test_bgp_auth2.py
@@ -39,6 +39,7 @@ import sys
 import pytest
 from lib import topotest
 from lib.common_config import (
+    create_interface_in_kernel,
     save_initial_config_on_routers,
     reset_with_new_configs,
 )
@@ -90,15 +91,9 @@ def setup_module(mod):
     r3.cmd_raises("ip link add blue type vrf table 1001")
     r3.cmd_raises("ip link set up dev blue")

-    r1.cmd_raises("ip link add lo1 type dummy")
-    r1.cmd_raises("ip link set lo1 master blue")
-    r1.cmd_raises("ip link set up dev lo1")
-    r2.cmd_raises("ip link add lo1 type dummy")
-    r2.cmd_raises("ip link set up dev lo1")
-    r2.cmd_raises("ip link set lo1 master blue")
-    r3.cmd_raises("ip link add lo1 type dummy")
-    r3.cmd_raises("ip link set up dev lo1")
-    r3.cmd_raises("ip link set lo1 master blue")
+    create_interface_in_kernel(tgen, "R1", "lo1", vrf="blue")
+    create_interface_in_kernel(tgen, "R2", "lo1", vrf="blue")
+    create_interface_in_kernel(tgen, "R3", "lo1", vrf="blue")

     r1.cmd_raises("ip link set R1-eth2 master blue")
     r1.cmd_raises("ip link set R1-eth3 master blue")
@@ -122,15 +117,9 @@ def setup_module(mod):
     r3.cmd_raises("ip link add red type vrf table 1002")
     r3.cmd_raises("ip link set up dev red")

-    r1.cmd_raises("ip link add lo2 type dummy")
-    r1.cmd_raises("ip link set lo2 master red")
-    r1.cmd_raises("ip link set up dev lo2")
-    r2.cmd_raises("ip link add lo2 type dummy")
-    r2.cmd_raises("ip link set up dev lo2")
-    r2.cmd_raises("ip link set lo2 master red")
-    r3.cmd_raises("ip link add lo2 type dummy")
-    r3.cmd_raises("ip link set up dev lo2")
-    r3.cmd_raises("ip link set lo2 master red")
+    create_interface_in_kernel(tgen, "R1", "lo2", vrf="red")
+    create_interface_in_kernel(tgen, "R2", "lo2", vrf="red")
+    create_interface_in_kernel(tgen, "R3", "lo2", vrf="red")

     r1.cmd_raises("ip link set R1-eth4 master red")
     r1.cmd_raises("ip link set R1-eth5 master red")
diff --git a/tests/topotests/bgp_auth/test_bgp_auth3.py b/tests/topotests/bgp_auth/test_bgp_auth3.py
index 585f8cb719..354fbfe799 100644
--- a/tests/topotests/bgp_auth/test_bgp_auth3.py
+++ b/tests/topotests/bgp_auth/test_bgp_auth3.py
@@ -39,6 +39,7 @@ import sys
 import pytest
 from lib import topotest
 from lib.common_config import (
+    create_interface_in_kernel,
     save_initial_config_on_routers,
     reset_with_new_configs,
 )
@@ -89,15 +90,9 @@ def setup_module(mod):
     r3.cmd_raises("ip link add blue type vrf table 1001")
     r3.cmd_raises("ip link set up dev blue")

-    r1.cmd_raises("ip link add lo1 type dummy")
-    r1.cmd_raises("ip link set lo1 master blue")
-    r1.cmd_raises("ip link set up dev lo1")
-    r2.cmd_raises("ip link add lo1 type dummy")
-    r2.cmd_raises("ip link set up dev lo1")
-    r2.cmd_raises("ip link set lo1 master blue")
-    r3.cmd_raises("ip link add lo1 type dummy")
-    r3.cmd_raises("ip link set up dev lo1")
-    r3.cmd_raises("ip link set lo1 master blue")
+    create_interface_in_kernel(tgen, "R1", "lo1", vrf="blue")
+    create_interface_in_kernel(tgen, "R2", "lo1", vrf="blue")
+    create_interface_in_kernel(tgen, "R3", "lo1", vrf="blue")

     r1.cmd_raises("ip link set R1-eth2 master blue")
     r1.cmd_raises("ip link set R1-eth3 master blue")
@@ -121,15 +116,9 @@ def setup_module(mod):
     r3.cmd_raises("ip link add red type vrf table 1002")
     r3.cmd_raises("ip link set up dev red")

-    r1.cmd_raises("ip link add lo2 type dummy")
-    r1.cmd_raises("ip link set lo2 master red")
-    r1.cmd_raises("ip link set up dev lo2")
-    r2.cmd_raises("ip link add lo2 type dummy")
-    r2.cmd_raises("ip link set up dev lo2")
-    r2.cmd_raises("ip link set lo2 master red")
-    r3.cmd_raises("ip link add lo2 type dummy")
-    r3.cmd_raises("ip link set up dev lo2")
-    r3.cmd_raises("ip link set lo2 master red")
+    create_interface_in_kernel(tgen, "R1", "lo2", vrf="red")
+    create_interface_in_kernel(tgen, "R2", "lo2", vrf="red")
+    create_interface_in_kernel(tgen, "R3", "lo2", vrf="red")

     r1.cmd_raises("ip link set R1-eth4 master red")
     r1.cmd_raises("ip link set R1-eth5 master red")
diff --git a/tests/topotests/bgp_auth/test_bgp_auth4.py b/tests/topotests/bgp_auth/test_bgp_auth4.py
index fc13cd9d50..eb947a9b36 100644
--- a/tests/topotests/bgp_auth/test_bgp_auth4.py
+++ b/tests/topotests/bgp_auth/test_bgp_auth4.py
@@ -39,6 +39,7 @@ import sys
 import pytest
 from lib import topotest
 from lib.common_config import (
+    create_interface_in_kernel,
     save_initial_config_on_routers,
     reset_with_new_configs,
 )
@@ -89,15 +90,9 @@ def setup_module(mod):
     r3.cmd_raises("ip link add blue type vrf table 1001")
     r3.cmd_raises("ip link set up dev blue")

-    r1.cmd_raises("ip link add lo1 type dummy")
-    r1.cmd_raises("ip link set lo1 master blue")
-    r1.cmd_raises("ip link set up dev lo1")
-    r2.cmd_raises("ip link add lo1 type dummy")
-    r2.cmd_raises("ip link set up dev lo1")
-    r2.cmd_raises("ip link set lo1 master blue")
-    r3.cmd_raises("ip link add lo1 type dummy")
-    r3.cmd_raises("ip link set up dev lo1")
-    r3.cmd_raises("ip link set lo1 master blue")
+    create_interface_in_kernel(tgen, "R1", "lo1", vrf="blue")
+    create_interface_in_kernel(tgen, "R2", "lo1", vrf="blue")
+    create_interface_in_kernel(tgen, "R3", "lo1", vrf="blue")

     r1.cmd_raises("ip link set R1-eth2 master blue")
     r1.cmd_raises("ip link set R1-eth3 master blue")
@@ -121,15 +116,9 @@ def setup_module(mod):
     r3.cmd_raises("ip link add red type vrf table 1002")
     r3.cmd_raises("ip link set up dev red")

-    r1.cmd_raises("ip link add lo2 type dummy")
-    r1.cmd_raises("ip link set lo2 master red")
-    r1.cmd_raises("ip link set up dev lo2")
-    r2.cmd_raises("ip link add lo2 type dummy")
-    r2.cmd_raises("ip link set up dev lo2")
-    r2.cmd_raises("ip link set lo2 master red")
-    r3.cmd_raises("ip link add lo2 type dummy")
-    r3.cmd_raises("ip link set up dev lo2")
-    r3.cmd_raises("ip link set lo2 master red")
+    create_interface_in_kernel(tgen, "R1", "lo2", vrf="red")
+    create_interface_in_kernel(tgen, "R2", "lo2", vrf="red")
+    create_interface_in_kernel(tgen, "R3", "lo2", vrf="red")

     r1.cmd_raises("ip link set R1-eth4 master red")
     r1.cmd_raises("ip link set R1-eth5 master red")
diff --git a/tests/topotests/bgp_evpn_mh/test_evpn_mh.py b/tests/topotests/bgp_evpn_mh/test_evpn_mh.py
index 525b32cda5..a2392b1371 100644
--- a/tests/topotests/bgp_evpn_mh/test_evpn_mh.py
+++ b/tests/topotests/bgp_evpn_mh/test_evpn_mh.py
@@ -33,7 +33,11 @@ sys.path.append(os.path.join(CWD, "../"))
 # pylint: disable=C0413
 # Import topogen and topotest helpers
 from lib import topotest
-from lib.common_config import kill_router_daemons, start_router_daemons
+from lib.common_config import (
+    create_interface_in_kernel,
+    kill_router_daemons,
+    start_router_daemons,
+)

 # Required to instantiate the topology builder class.
 from lib.topogen import Topogen, TopoRouter, get_topogen
@@ -258,7 +262,7 @@ def config_mcast_tunnel_termination_device(node):
     The kernel requires a device to terminate VxLAN multicast tunnels
     when EVPN-PIM is used for flooded traffic
     """
-    node.run("ip link add dev ipmr-lo type dummy")
+    create_interface_in_kernel(node.tgen, node.name, "ipmr-lo")
     node.run("ip link set dev ipmr-lo mtu 16000")
     node.run("ip link set dev ipmr-lo mode dormant")
     node.run("ip link set dev ipmr-lo up")
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 230ccf3322..24cdff2e28 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,6 +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.topogen import Topogen, TopoRouter, get_topogen
 from lib.topolog import logger

@@ -435,7 +436,7 @@ def config_mcast_tunnel_termination_device(node):
     The kernel requires a device to terminate VxLAN multicast tunnels
     when EVPN-PIM is used for flooded traffic
     """
-    node.run("ip link add dev ipmr-lo type dummy")
+    create_interface_in_kernel(node.tgen, node.name, "ipmr-lo")
     node.run("ip link set dev ipmr-lo mtu 16000")
     node.run("ip link set dev ipmr-lo mode dormant")
     node.run("ip link set dev ipmr-lo up")
diff --git a/tests/topotests/bgp_evpn_rmac_conflict/test_bgp_evpn_rmac_conflict.py b/tests/topotests/bgp_evpn_rmac_conflict/test_bgp_evpn_rmac_conflict.py
index 4526619a8e..879cfbac3f 100644
--- a/tests/topotests/bgp_evpn_rmac_conflict/test_bgp_evpn_rmac_conflict.py
+++ b/tests/topotests/bgp_evpn_rmac_conflict/test_bgp_evpn_rmac_conflict.py
@@ -39,6 +39,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.topogen import Topogen, get_topogen
 from lib.topolog import logger

@@ -92,9 +93,9 @@ def setup_module(mod):
     for vrf in (101, 102):
         ns = "vrf-{}".format(vrf)
         r1.add_netns(ns)
+        create_interface_in_kernel(tgen, "r1", "loop{}".format(vrf))
         r1.cmd_raises(
             """
-ip link add loop{0} type dummy
 ip link add vxlan-{0} type vxlan id {0} dstport 4789 dev eth-rr local 192.168.1.1
 """.format(
                 vrf
@@ -122,9 +123,15 @@ ip -n vrf-{vrf} link set vxlan-{vrf} up
             """
 ip link add vrf-{vrf} type vrf table {vrf}
 ip link set dev vrf-{vrf} up
-ip link add loop{vrf} type dummy
-ip link set dev loop{vrf} master vrf-{vrf}
-ip link set dev loop{vrf} up
+""".format(
+                vrf=vrf
+            )
+        )
+        create_interface_in_kernel(
+            tgen, "r2", "loop{}".format(vrf), vrf="vrf-{}".format(vrf)
+        )
+        tgen.gears["r2"].cmd(
+            """
 ip link add bridge-{vrf} up address {rmac} type bridge stp_state 0
 ip link set bridge-{vrf} master vrf-{vrf}
 ip link set dev bridge-{vrf} up
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 a5604a8f67..77db351cf8 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,6 +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.topogen import Topogen, get_topogen
 from lib.topolog import logger

@@ -94,9 +95,6 @@ def setup_module(mod):
     cmds_vxlan = [
         "ip link add vrf-101 type vrf table 101",
         "ip link set dev vrf-101 up",
-        "ip link add loop101 type dummy",
-        "ip link set dev loop101 master vrf-101",
-        "ip link set dev loop101 up",
         "ip link add bridge-101 up address 52:54:00:0{0}:01:65 type bridge stp_state 0",
         "ip link set bridge-101 master vrf-101",
         "ip link set dev bridge-101 up",
@@ -128,6 +126,7 @@ def setup_module(mod):
             logger.info("cmd to r{}: {}".format(rid, formatted))
             output = router.cmd_raises(formatted)
             logger.info("result: " + output)
+        create_interface_in_kernel(tgen, "r{}".format(rid), "loop101", vrf="vrf-101")

     for cmd in cmds_vxlan_r1:
         logger.info("cmd to r1: {}".format(cmd))
diff --git a/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py b/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py
index 0af852e638..ff65cdb924 100644
--- a/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py
+++ b/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py
@@ -32,6 +32,7 @@ from lib.checkping import check_ping
 from lib.bgp import get_bgp_summary_json, verify_bgp_rib
 from lib.common_config import (
     apply_raw_config,
+    create_interface_in_kernel,
     required_iproute2_version,
     required_linux_kernel_version,
 )
@@ -86,9 +87,9 @@ def setup_module(mod):
     for vrf in (101, 102):
         ns = "vrf-{}".format(vrf)
         r1.add_netns(ns)
+        create_interface_in_kernel(tgen, "r1", "loop{}".format(vrf))
         r1.cmd_raises(
             """
-ip link add loop{0} type dummy
 ip link add vxlan-{0} type vxlan id {0} dstport 4789 dev eth-rr local 192.168.1.1
 """.format(
                 vrf
@@ -112,9 +113,15 @@ ip -n vrf-{0} link set vxlan-{0} up
             """
 ip link add vrf-{0} type vrf table {0}
 ip link set dev vrf-{0} up
-ip link add loop{0} type dummy
-ip link set dev loop{0} master vrf-{0}
-ip link set dev loop{0} up
+""".format(
+                vrf
+            )
+        )
+        create_interface_in_kernel(
+            tgen, "r2", "loop{}".format(vrf), vrf="vrf-{}".format(vrf)
+        )
+        tgen.gears["r2"].cmd(
+            """
 ip link add bridge-{0} up address {1} type bridge stp_state 0
 ip link set bridge-{0} master vrf-{0}
 ip link set dev bridge-{0} up
diff --git a/tests/topotests/bgp_evpn_rt5/test_bgp_evpn_v6_vtep.py b/tests/topotests/bgp_evpn_rt5/test_bgp_evpn_v6_vtep.py
index b38b433532..77c46c6abc 100644
--- a/tests/topotests/bgp_evpn_rt5/test_bgp_evpn_v6_vtep.py
+++ b/tests/topotests/bgp_evpn_rt5/test_bgp_evpn_v6_vtep.py
@@ -29,7 +29,7 @@ sys.path.append(os.path.join(CWD, "../"))
 # Import topogen and topotest helpers
 from lib import topotest
 from lib.bgp import verify_bgp_rib
-from lib.common_config import apply_raw_config
+from lib.common_config import apply_raw_config, create_interface_in_kernel
 from lib.topogen import Topogen, TopoRouter, get_topogen
 from lib.topolog import logger

@@ -84,9 +84,6 @@ def setup_module(mod):
         "ip ru add oif {0}-vrf-{1} table {1}",
         "ip ru add iif {0}-vrf-{1} table {1}",
         "ip link set dev {0}-vrf-{1} up",
-        "ip link add loop{1} type dummy",
-        "ip link set dev loop{1} master {0}-vrf-{1}",
-        "ip link set dev loop{1} up",
     ]

     cmds_r2 = [  # config routing 101
@@ -121,7 +118,7 @@ def setup_module(mod):

     ns = "r1-vrf-101"
     tgen.net["r1"].add_netns(ns)
-    tgen.net["r1"].cmd_raises("ip link add loop101 type dummy")
+    create_interface_in_kernel(tgen, "r1", "loop101")
     tgen.net["r1"].set_intf_netns("loop101", ns, up=True)

     router = tgen.gears["r2"]
@@ -129,6 +126,7 @@ def setup_module(mod):
         logger.info("cmd to r2: " + cmd.format("r2", 101))
         output = router.cmd_raises(cmd.format("r2", 101))
         logger.info("result: " + output)
+    create_interface_in_kernel(tgen, "r2", "loop101", vrf="r2-vrf-101")

     for cmd in cmds_r2:
         logger.info("cmd to r2: " + cmd.format("r2"))
@@ -140,6 +138,7 @@ def setup_module(mod):
         logger.info("cmd to r3: " + cmd.format("r3", 102))
         output = router.cmd_raises(cmd.format("r3", 102))
         logger.info("result: " + output)
+    create_interface_in_kernel(tgen, "r3", "loop102", vrf="r3-vrf-102")

     for cmd in cmds_r3:
         logger.info("cmd to r3: " + cmd.format("r3"))
diff --git a/tests/topotests/bgp_evpn_rt5_implied/test_bgp_evpn_implied.py b/tests/topotests/bgp_evpn_rt5_implied/test_bgp_evpn_implied.py
index e85a7e6810..6236a030d9 100644
--- a/tests/topotests/bgp_evpn_rt5_implied/test_bgp_evpn_implied.py
+++ b/tests/topotests/bgp_evpn_rt5_implied/test_bgp_evpn_implied.py
@@ -37,7 +37,7 @@ sys.path.append(os.path.join(CWD, "../"))
 # Import topogen and topotest helpers
 from lib import topotest
 from lib.bgp import verify_bgp_rib
-from lib.common_config import apply_raw_config
+from lib.common_config import apply_raw_config, create_interface_in_kernel
 from lib.topogen import Topogen, TopoRouter, get_topogen
 from lib.topolog import logger

@@ -83,9 +83,9 @@ def setup_module(mod):
     for vrf in (101, 102):
         ns = "vrf-{}".format(vrf)
         r1.add_netns(ns)
+        create_interface_in_kernel(tgen, "r1", "loop{}".format(vrf))
         r1.cmd_raises(
             """
-ip link add loop{0} type dummy
 ip link add vxlan-{0} type vxlan id {0} dstport 4789 dev eth-rr local 192.168.1.1
 """.format(
                 vrf
@@ -109,9 +109,15 @@ ip -n vrf-{0} link set vxlan-{0} up
             """
 ip link add vrf-{0} type vrf table {0}
 ip link set dev vrf-{0} up
-ip link add loop{0} type dummy
-ip link set dev loop{0} master vrf-{0}
-ip link set dev loop{0} up
+""".format(
+                vrf
+            )
+        )
+        create_interface_in_kernel(
+            tgen, "r2", "loop{}".format(vrf), vrf="vrf-{}".format(vrf)
+        )
+        tgen.gears["r2"].cmd(
+            """
 ip link add bridge-{0} up address {1} type bridge stp_state 0
 ip link set bridge-{0} master vrf-{0}
 ip link set dev bridge-{0} up
diff --git a/tests/topotests/bgp_evpn_rt_wildcard_matching/test_bgp_evpn_rt_wildcard_matching.py b/tests/topotests/bgp_evpn_rt_wildcard_matching/test_bgp_evpn_rt_wildcard_matching.py
index ba4cceb1b7..651448360b 100644
--- a/tests/topotests/bgp_evpn_rt_wildcard_matching/test_bgp_evpn_rt_wildcard_matching.py
+++ b/tests/topotests/bgp_evpn_rt_wildcard_matching/test_bgp_evpn_rt_wildcard_matching.py
@@ -47,6 +47,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.topogen import Topogen, get_topogen
 from lib.topolog import logger

@@ -88,9 +89,6 @@ def setup_module(mod):
     cmds_vxlan = [
         "ip link add vrf-101 type vrf table 101",
         "ip link set dev vrf-101 up",
-        "ip link add loop101 type dummy",
-        "ip link set dev loop101 master vrf-101",
-        "ip link set dev loop101 up",
         "ip link add bridge-101 up address 52:54:00:0{0}:01:65 type bridge stp_state 0",
         "ip link set bridge-101 master vrf-101",
         "ip link set dev bridge-101 up",
@@ -110,6 +108,7 @@ def setup_module(mod):
             logger.info("cmd to r{}: {}".format(rid, formatted))
             output = router.cmd_raises(formatted)
             logger.info("result: " + output)
+        create_interface_in_kernel(tgen, "r{}".format(rid), "loop101", vrf="vrf-101")

     for router in tgen.routers().values():
         router.load_frr_config()
diff --git a/tests/topotests/bgp_evpn_type5_vrf_leak_stale/test_bgp_evpn_type5_vrf_leak_stale.py b/tests/topotests/bgp_evpn_type5_vrf_leak_stale/test_bgp_evpn_type5_vrf_leak_stale.py
index ca7ee92448..5ce53e248f 100644
--- a/tests/topotests/bgp_evpn_type5_vrf_leak_stale/test_bgp_evpn_type5_vrf_leak_stale.py
+++ b/tests/topotests/bgp_evpn_type5_vrf_leak_stale/test_bgp_evpn_type5_vrf_leak_stale.py
@@ -64,10 +64,12 @@ sys.path.append(os.path.join(CWD, "../"))
 # pylint: disable=C0413
 from lib import topotest
 from lib.common_config import (
+    create_interface_in_kernel,
     create_static_routes,
     create_vrf_cfg,
     kill_router_daemons,
     start_router_daemons,
+    step
 )
 from lib.common_check import iproute2_check_path_selection
 from lib.bgp import create_router_bgp, verify_bgp_convergence_from_running_config
@@ -145,6 +147,34 @@ def _configure_l3vni_interfaces(router, rname, vrf, vni, local_vtep):
         router.cmd_raises(command)


+<<<<<<< HEAD
+=======
+def _add_vrf_vni(router, rname, vrf, table, vni, local_vtep):
+    _run_cmds(
+        router,
+        [
+            "ip link add {0} type vrf table {1}".format(vrf, table),
+            "ip link set dev {0} up".format(vrf),
+            "ip link add name br{0} up type bridge stp_state 0".format(vni),
+            "ip link set dev br{0} master {1}".format(vni, vrf),
+            "ip link set dev br{0} up".format(vni),
+            (
+                "ip link add name vxlan{0} type vxlan id {0} dstport 4789 "
+                "dev {1}-eth0 local {2} nolearning"
+            ).format(vni, rname, local_vtep),
+            "ip link set dev vxlan{0} master br{0}".format(vni),
+            (
+                "ip link set dev vxlan{0} up type bridge_slave "
+                "learning off flood off mcast_flood off"
+            ).format(vni),
+        ],
+    )
+    create_interface_in_kernel(
+        router.tgen, router.name, "loop{}".format(vni), vrf=vrf
+    )
+
+
+>>>>>>> 7d80721b4e (tests: Convert them to use create_interface_in_kernel)
 def setup_module(mod):
     "Create router VRFs and L3VNIs, load configs, and start the topology."

diff --git a/tests/topotests/bgp_hidden_evpn_revival/test_bgp_hidden_evpn_revival.py b/tests/topotests/bgp_hidden_evpn_revival/test_bgp_hidden_evpn_revival.py
index 6b47ec9a4d..4333e88364 100644
--- a/tests/topotests/bgp_hidden_evpn_revival/test_bgp_hidden_evpn_revival.py
+++ b/tests/topotests/bgp_hidden_evpn_revival/test_bgp_hidden_evpn_revival.py
@@ -41,7 +41,7 @@ sys.path.append(os.path.join(CWD, "../"))
 # pylint: disable=C0413
 from lib import topotest
 from lib.topogen import Topogen, get_topogen
-from lib.common_config import step
+from lib.common_config import create_interface_in_kernel, step

 pytestmark = [pytest.mark.bgpd]

@@ -60,14 +60,8 @@ def setup_module(mod):
     tgen.start_topology()

     r1 = tgen.gears["r1"]
-    r1.run(
-        "ip link add vrf1 type vrf table 101 && "
-        "ip link add dummy1 type dummy && "
-        "ip link set dummy1 master vrf1 && "
-        "ip addr add 10.10.1.1/24 dev dummy1 && "
-        "ip link set dummy1 up && "
-        "ip link set vrf1 up"
-    )
+    r1.run("ip link add vrf1 type vrf table 101 && ip link set vrf1 up")
+    create_interface_in_kernel(tgen, "r1", "dummy1", "10.10.1.1/24", vrf="vrf1")

     r1.load_frr_config(os.path.join(CWD, "r1/frr.conf"))

diff --git a/tests/topotests/bgp_listen_l3vrf/test_bgp_listen_l3vrf.py b/tests/topotests/bgp_listen_l3vrf/test_bgp_listen_l3vrf.py
index e922641024..5647d638dc 100644
--- a/tests/topotests/bgp_listen_l3vrf/test_bgp_listen_l3vrf.py
+++ b/tests/topotests/bgp_listen_l3vrf/test_bgp_listen_l3vrf.py
@@ -38,7 +38,7 @@ sys.path.append(os.path.join(CWD, "../"))
 # Import topogen and topotest helpers
 from lib import topotest
 from lib.common_check import ip_check_path_selection, iproute2_check_path_selection
-from lib.common_config import step
+from lib.common_config import create_interface_in_kernel, step
 from lib.topogen import Topogen, TopoRouter, get_topogen
 from lib.topolog import logger

@@ -144,9 +144,7 @@ def test_add_vrf():
     r1.cmd("ip link set dev r1-eth1.100 up")
     r1.cmd("ip link set  dev r1-eth1.100 master r1-cust")

-    r1.cmd("ip link add r1-loop1 type dummy")
-    r1.cmd("ip link set dev r1-loop1 up")
-    r1.cmd("ip link set  dev r1-loop1 master r1-cust")
+    create_interface_in_kernel(tgen, "r1", "r1-loop1", vrf="r1-cust")

     r3.cmd("ip link add link r3-eth1 dev r3-eth1.100 type vlan id 100")
     r3.cmd("ip link set dev r3-eth1.100 up")
diff --git a/tests/topotests/bgp_rd_as_zero/test_bgp_rd_as_zero.py b/tests/topotests/bgp_rd_as_zero/test_bgp_rd_as_zero.py
index 0da370e3d5..190ef23f95 100644
--- a/tests/topotests/bgp_rd_as_zero/test_bgp_rd_as_zero.py
+++ b/tests/topotests/bgp_rd_as_zero/test_bgp_rd_as_zero.py
@@ -35,6 +35,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.topogen import Topogen, get_topogen
 from lib.topolog import logger

@@ -58,10 +59,7 @@ def setup_module(mod):
     # A VRF with a connected route to redistribute into the ipv4 vpn table.
     r1.run("ip link add dummy-vrf type vrf table 1001")
     r1.run("ip link set dummy-vrf up")
-    r1.run("ip link add dummy0 type dummy")
-    r1.run("ip link set dummy0 master dummy-vrf")
-    r1.run("ip link set dummy0 up")
-    r1.run("ip addr add 192.0.2.100/32 dev dummy0")
+    create_interface_in_kernel(tgen, "r1", "dummy0", "192.0.2.100/32", vrf="dummy-vrf")

     for rname, router in tgen.routers().items():
         router.load_frr_config(os.path.join(CWD, rname, "frr.conf"))
diff --git a/tests/topotests/bgp_show_l2vpn_evpn_rt/test_bgp_show_l2vpn_evpn_rt.py b/tests/topotests/bgp_show_l2vpn_evpn_rt/test_bgp_show_l2vpn_evpn_rt.py
index 13ab533e4f..ba9ce3e8f0 100644
--- a/tests/topotests/bgp_show_l2vpn_evpn_rt/test_bgp_show_l2vpn_evpn_rt.py
+++ b/tests/topotests/bgp_show_l2vpn_evpn_rt/test_bgp_show_l2vpn_evpn_rt.py
@@ -25,6 +25,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.topogen import Topogen, get_topogen
 from lib.topolog import logger

@@ -49,9 +50,9 @@ def _setup_vrfs(router, vrf):
     mac = f"52:54:00:00:{idx}{idx}:{idx}{idx}"
     iface = f"eth-{router.name}"
     router.add_netns(ns)
+    create_interface_in_kernel(get_topogen(), router.name, "loop{}".format(vrf))
     router.cmd_raises(
         f"""
-ip link add loop{vrf} type dummy
 ip link add vxlan-{vrf} type vxlan id {vrf} dstport 4789 dev {iface} local {ip}
 """
     )
diff --git a/tests/topotests/bgp_srv6_unicast/test_bgp_srv6_unicast.py b/tests/topotests/bgp_srv6_unicast/test_bgp_srv6_unicast.py
index 0dfd6616f0..c402bbb4b6 100644
--- a/tests/topotests/bgp_srv6_unicast/test_bgp_srv6_unicast.py
+++ b/tests/topotests/bgp_srv6_unicast/test_bgp_srv6_unicast.py
@@ -37,7 +37,7 @@ import functools
 CWD = os.path.dirname(os.path.realpath(__file__))
 sys.path.append(os.path.join(CWD, "../"))

-from lib.common_config import retry
+from lib.common_config import create_interface_in_kernel, retry
 from lib import topotest
 from lib.topogen import Topogen, get_topogen
 from lib.topolog import logger
@@ -67,19 +67,17 @@ def setup_module(mod):
         sysctl -w net.vrf.strict_mode=1
         ip link add vrfdefault type vrf table 254
         ip link set up dev vrfdefault
-        ip link add sr0 type dummy
-        ip link set up dev sr0
         """
     )
+    create_interface_in_kernel(tgen, "r1", "sr0")
     tgen.net["r3"].cmd(
         """
         sysctl -w net.vrf.strict_mode=1
         ip link add vrfdefault type vrf table 254
         ip link set up dev vrfdefault
-        ip link add sr0 type dummy
-        ip link set up dev sr0
         """
     )
+    create_interface_in_kernel(tgen, "r3", "sr0")

     for router in router_list.values():
         router.load_frr_config(
diff --git a/tests/topotests/bgp_vrf_import_route_map/test_bgp_vrf_import_route_map.py b/tests/topotests/bgp_vrf_import_route_map/test_bgp_vrf_import_route_map.py
index 061b48def1..d261c69e86 100644
--- a/tests/topotests/bgp_vrf_import_route_map/test_bgp_vrf_import_route_map.py
+++ b/tests/topotests/bgp_vrf_import_route_map/test_bgp_vrf_import_route_map.py
@@ -31,6 +31,7 @@ from lib.topogen import Topogen, TopoRouter, get_topogen
 from lib.common_config import (
     step,
     apply_raw_config,
+    create_interface_in_kernel,
     create_route_maps,
     check_address_types,
     reset_config_on_routers,
@@ -65,24 +66,16 @@ def setup_module(mod):
     r1.cmd_raises("ip link set up dev vrf1")
     r1.cmd_raises("ip link add vrf2 type vrf table 20")
     r1.cmd_raises("ip link set up dev vrf2")
-    r1.cmd_raises("ip link add r1-eth1 type dummy")
-    r1.cmd_raises("ip link set r1-eth1 master vrf1")
-    r1.cmd_raises("ip link set up dev r1-eth1")
-    r1.cmd_raises("ip link add r1-eth2 type dummy")
-    r1.cmd_raises("ip link set r1-eth2 master vrf2")
-    r1.cmd_raises("ip link set up dev r1-eth2")
+    create_interface_in_kernel(tgen, "r1", "r1-eth1", vrf="vrf1")
+    create_interface_in_kernel(tgen, "r1", "r1-eth2", vrf="vrf2")

     r2 = tgen.gears["r2"]
     r2.cmd_raises("ip link add vrf3 type vrf table 30")
     r2.cmd_raises("ip link set up dev vrf3")
     r2.cmd_raises("ip link add vrf4 type vrf table 40")
     r2.cmd_raises("ip link set up dev vrf4")
-    r2.cmd_raises("ip link add r2-eth1 type dummy")
-    r2.cmd_raises("ip link set r2-eth1 master vrf3")
-    r2.cmd_raises("ip link set up dev r2-eth1")
-    r2.cmd_raises("ip link add r2-eth2 type dummy")
-    r2.cmd_raises("ip link set r2-eth2 master vrf4")
-    r2.cmd_raises("ip link set up dev r2-eth2")
+    create_interface_in_kernel(tgen, "r2", "r2-eth1", vrf="vrf3")
+    create_interface_in_kernel(tgen, "r2", "r2-eth2", vrf="vrf4")

     # Enable required daemons for all routers
     router_list = tgen.routers()
diff --git a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.py b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.py
index 62c8c9889d..4c8408defd 100644
--- a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.py
+++ b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.py
@@ -28,7 +28,7 @@ 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_linux_kernel_version
+from lib.common_config import create_interface_in_kernel, required_linux_kernel_version

 # Required to instantiate the topology builder class.

@@ -65,15 +65,15 @@ def setup_module(mod):
     cmds = [
         "ip link add {0}-cust1 type vrf table 1001",
         "ip link set {0}-cust1 up",
-        "ip link add loop1 type dummy",
-        "ip link set loop1 master {0}-cust1",
-        "ip link set loop1 up",
         "ip link set {0}-eth0 master {0}-cust1",
     ]

     for rname, router in router_list.items():
         for cmd in cmds:
             output = tgen.net[rname].cmd(cmd.format(rname))
+        create_interface_in_kernel(
+            tgen, rname, "loop1", vrf="{}-cust1".format(rname)
+        )

     for rname, router in router_list.items():
         router.load_config(
diff --git a/tests/topotests/frr_reload_vrf/dataplane_lib.py b/tests/topotests/frr_reload_vrf/dataplane_lib.py
index bb91db3e5e..25fc8bb53d 100644
--- a/tests/topotests/frr_reload_vrf/dataplane_lib.py
+++ b/tests/topotests/frr_reload_vrf/dataplane_lib.py
@@ -188,10 +188,6 @@ def plumb_pe(node, num_vrfs, num_mcast_vrfs):
         if node == MCAST_PE and v <= num_mcast_vrfs:
             rxidx = rx_ifidx(num_vrfs, v)
             cmds += [
-                # RP loopback in the vrf (address via zebra config)
-                "ip link add loop-rp{} type dummy".format(v),
-                "ip link set dev loop-rp{} master {}".format(v, vrf),
-                "ip link set dev loop-rp{} up".format(v),
                 # receiver access iface in the vrf (address via zebra config)
                 "ip link set dev {}-eth{} master {}".format(node, rxidx, vrf),
                 "ip link set dev {}-eth{} up".format(node, rxidx),
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 1a5e3e9a4a..1de1fd5d7f 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,7 @@ 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 required_linux_kernel_version
+from lib.common_config import create_interface_in_kernel, required_linux_kernel_version
 from lib.pim import McastTesterHelper

 import dataplane_lib as D
@@ -105,6 +105,11 @@ def tgen(request):
         node = tg.gears[pe]
         for cmd in D.plumb_pe(pe, NUM_VRFS, NUM_MCAST_VRFS):
             node.cmd_raises(cmd)
+        if pe == D.MCAST_PE:
+            for v in range(1, NUM_MCAST_VRFS + 1):
+                create_interface_in_kernel(
+                    tg, pe, "loop-rp{}".format(v), vrf=D.vrf_name(v)
+                )

     # generate + load unified frr.conf on the fabric nodes
     for node in [D.SPINE] + D.PES:
diff --git a/tests/topotests/isis_sr_flex_algo_topo2/test_isis_sr_flex_algo_topo2.py b/tests/topotests/isis_sr_flex_algo_topo2/test_isis_sr_flex_algo_topo2.py
index a940402426..b3b3256cc2 100755
--- a/tests/topotests/isis_sr_flex_algo_topo2/test_isis_sr_flex_algo_topo2.py
+++ b/tests/topotests/isis_sr_flex_algo_topo2/test_isis_sr_flex_algo_topo2.py
@@ -56,6 +56,7 @@ sys.path.append(os.path.join(CWD, "../"))
 # pylint: disable=C0413
 # Import topogen and topotest helpers
 from lib import topotest
+from lib.common_config import create_interface_in_kernel
 from lib.topogen import Topogen, TopoRouter, get_topogen
 from lib.topolog import logger

@@ -129,12 +130,10 @@ def setup_module(mod):
             router.load_config(
                 TopoRouter.RD_PATH, os.path.join(CWD, "{}/pathd.conf".format(rname))
             )
-            router.run("ip link add dum0 type dummy")
-            router.run("ip link set dum0 up")
             if rname == "rt0":
-                router.run("ip addr add 10.255.0.1/24 dev dum0")
+                create_interface_in_kernel(tgen, rname, "dum0", "10.255.0.1/24")
             elif rname == "rt9":
-                router.run("ip addr add 10.255.9.1/24 dev dum0")
+                create_interface_in_kernel(tgen, rname, "dum0", "10.255.9.1/24")
     tgen.start_router()


diff --git a/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py b/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py
index afc6864b98..51334d1eb7 100644
--- a/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py
+++ b/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py
@@ -26,7 +26,7 @@ from lib import topotest
 from lib.topogen import Topogen, TopoRouter, get_topogen
 from lib.topolog import logger
 from lib.topotest import iproute2_is_vrf_capable
-from lib.common_config import required_linux_kernel_version
+from lib.common_config import create_interface_in_kernel, required_linux_kernel_version


 pytestmark = [pytest.mark.isisd]
@@ -90,7 +90,6 @@ def setup_module(mod):

     cmds = [
         "ip link add {0}-cust1 type vrf table 1001",
-        "ip link add loop1 type dummy",
         "ip link set {0}-eth0 master {0}-cust1",
     ]

@@ -101,6 +100,7 @@ def setup_module(mod):
         # create VRF rx-cust1 and link rx-eth0 to rx-cust1
         for cmd in cmds:
             output = tgen.net[rname].cmd(cmd.format(rname))
+        create_interface_in_kernel(tgen, rname, "loop1")

         # If router has an rX-eth1, link that to vrf also
         if "{}-eth1".format(rname) in router.links.keys():
diff --git a/tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py b/tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py
index 3f102796c1..8b1a8c9024 100755
--- a/tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py
+++ b/tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py
@@ -76,7 +76,7 @@ from lib import topotest
 from lib.topogen import Topogen, TopoRouter, get_topogen
 from lib.topolog import logger
 from lib.topotest import iproute2_is_vrf_capable
-from lib.common_config import required_linux_kernel_version
+from lib.common_config import create_interface_in_kernel, required_linux_kernel_version


 pytestmark = [pytest.mark.ospf6d]
@@ -151,7 +151,6 @@ def setup_module(mod):

     cmds = [
         "ip link add {0}-cust1 type vrf table 1001",
-        "ip link add loop1 type dummy",
         "ip link set {0}-stubnet master {0}-cust1",
     ]

@@ -164,6 +163,7 @@ def setup_module(mod):
         # create VRF rx-cust1 and link rx-eth0 to rx-cust1
         for cmd in cmds:
             output = tgen.net[rname].cmd(cmd.format(rname))
+        create_interface_in_kernel(tgen, rname, "loop1")
         if rname == "r1" or rname == "r2" or rname == "r3":
             for cmd in cmds1:
                 output = tgen.net[rname].cmd(cmd.format(rname))
diff --git a/tests/topotests/pbr_topo1/test_pbr_topo1.py b/tests/topotests/pbr_topo1/test_pbr_topo1.py
index 0ca89fb75a..85acbae91f 100644
--- a/tests/topotests/pbr_topo1/test_pbr_topo1.py
+++ b/tests/topotests/pbr_topo1/test_pbr_topo1.py
@@ -33,7 +33,7 @@ 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 shutdown_bringup_interface
+from lib.common_config import create_interface_in_kernel, shutdown_bringup_interface

 # Required to instantiate the topology builder class.

@@ -244,8 +244,7 @@ def test_pbr_late_if_real_invalid_seq():
     )

     try:
-        router.run("ip link add {} type dummy".format(late_if))
-        router.run("ip link set {} up".format(late_if))
+        create_interface_in_kernel(tgen, "r1", late_if)

         def _late_if_real(router, ifname):
             try:
diff --git a/tests/topotests/pim_basic_igmp_proxy/test_pim_igmp_proxy.py b/tests/topotests/pim_basic_igmp_proxy/test_pim_igmp_proxy.py
index 5c2ebe5bdd..27b4c6c4aa 100644
--- a/tests/topotests/pim_basic_igmp_proxy/test_pim_igmp_proxy.py
+++ b/tests/topotests/pim_basic_igmp_proxy/test_pim_igmp_proxy.py
@@ -41,6 +41,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.topogen import Topogen, TopoRouter, get_topogen
 from lib.topolog import logger
 from lib.pim import verify_local_igmp_proxy_groups
@@ -83,8 +84,7 @@ def build_topo(tgen):
     sw.add_link(tgen.gears["r3"])

     # Dummy interface for static joins
-    tgen.gears["r2"].run("ip link add r2-eth1 type dummy")
-    tgen.gears["r2"].run("ip link set r2-eth1 up")
+    create_interface_in_kernel(tgen, "r2", "r2-eth1")


 def setup_module(mod):
diff --git a/tests/topotests/pim_mrib/test_pim_mrib.py b/tests/topotests/pim_mrib/test_pim_mrib.py
index 32e598acb7..785db73838 100644
--- a/tests/topotests/pim_mrib/test_pim_mrib.py
+++ b/tests/topotests/pim_mrib/test_pim_mrib.py
@@ -16,6 +16,7 @@ from functools import partial
 # pylint: disable=C0413
 # Import topogen and topotest helpers
 from lib import topotest
+from lib.common_config import create_interface_in_kernel
 from lib.topogen import Topogen, get_topogen
 from lib.topolog import logger
 from lib.pim import (
@@ -77,8 +78,7 @@ def build_topo(tgen):
     tgen.add_link(tgen.gears["r2"], tgen.gears["r4"], "r2-eth1", "r4-eth0")
     tgen.add_link(tgen.gears["r3"], tgen.gears["r4"], "r3-eth1", "r4-eth1")

-    tgen.gears["r4"].run("ip link add r4-dum0 type dummy")
-    tgen.gears["r4"].run("ip link set r4-dum0 up")
+    create_interface_in_kernel(tgen, "r4", "r4-dum0")


 def setup_module(mod):
diff --git a/tests/topotests/static_cross_vrf_nexthop/test_static_cross_vrf_nexthop.py b/tests/topotests/static_cross_vrf_nexthop/test_static_cross_vrf_nexthop.py
index f5205a3b56..a295a8c3d0 100644
--- a/tests/topotests/static_cross_vrf_nexthop/test_static_cross_vrf_nexthop.py
+++ b/tests/topotests/static_cross_vrf_nexthop/test_static_cross_vrf_nexthop.py
@@ -25,6 +25,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.topogen import Topogen, TopoRouter, get_topogen
 from lib.topolog import logger
 from time import sleep
@@ -318,10 +319,7 @@ ip route 9.9.9.9/32 blackhole vrf vrf_a

     # Add a dummy interface to vrf_b so 10.2.0.0/24 is connected there,
     # making 10.2.0.2 resolvable as a local nexthop in vrf_b.
-    r1.run("ip link add dummy_b type dummy")
-    r1.run("ip link set dummy_b master vrf_b")
-    r1.run("ip link set dummy_b up")
-    r1.run("ip addr add 10.2.0.1/24 dev dummy_b")
+    create_interface_in_kernel(tgen, "r1", "dummy_b", "10.2.0.1/24", vrf="vrf_b")

     # Configure ECMP route 10.3.0.0/24 in vrf_b with two nexthops:
     #   - 9.9.9.9 resolved in vrf_a (cross-VRF, via blackhole → always active)
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 f02f1f91de..59e47287e4 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,7 @@ import sys
 import pytest
 import json
 from functools import partial
-from lib.common_config import step
+from lib.common_config import create_interface_in_kernel, step
 from lib.topolog import logger

 # Save the Current Working Directory to find configuration files.
@@ -105,8 +105,7 @@ def test_zebra_connected_multiple():

     router = tgen.gears["r1"]
     router.run("ip route add 192.168.1.1/32 via 10.0.1.99 dev r1-eth1")
-    router.run("ip link add dummy1 type dummy")
-    router.run("ip link set dummy1 up")
+    create_interface_in_kernel(tgen, router.name, "dummy1")
     router.run("ip link set dummy1 down")

     routes = "{}/{}/ip_route.json".format(CWD, router.name)
@@ -130,8 +129,7 @@ def test_zebra_system_recursion():
     router = tgen.gears["r1"]
     router.run("ip route add 10.0.1.30/32 dev r1-eth1")
     router.run("ip route add 10.9.9.0/24 via 10.0.1.30 dev r1-eth1")
-    router.run("ip link add dummy2 type dummy")
-    router.run("ip link set dummy2 up")
+    create_interface_in_kernel(tgen, router.name, "dummy2")
     router.run("ip link set dummy2 down")

     routes = "{}/{}/ip_route2.json".format(CWD, router.name)
@@ -379,8 +377,7 @@ def test_zebra_kernel_last_ipv4_address_deleted():

     # Prepare scene: create dummy interface
     # add two addresses, two routes
-    router.run(f"ip link add {ifname} type dummy")
-    router.run(f"ip link set {ifname} up")
+    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}")
     router.run(f"ip -4 route add 203.0.113.0/24 via 192.168.0.1")
@@ -442,8 +439,7 @@ def test_zebra_metaq_early_route_table_discriminator():

     step("Create dummy0")
     router.run(f"ip link del dev {ifname} >/dev/null 2>&1 || true")
-    router.run(f"ip link add {ifname} type dummy")
-    router.run(f"ip link set {ifname} up")
+    create_interface_in_kernel(tgen, router.name, ifname)

     step("Wait for zebra to finish handling dummy0 up")

@@ -606,8 +602,7 @@ def test_zebra_kernel_last_ipv6_address_deleted():

     # Prepare scene: create dummy interface
     # add two addresses, two routes
-    router.run(f"ip link add {ifname} type dummy")
-    router.run(f"ip link set {ifname} up")
+    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}")
diff --git a/tests/topotests/zebra_recursive/test_zebra_recursive.py b/tests/topotests/zebra_recursive/test_zebra_recursive.py
index 2b6fcb3864..c12baebcc9 100644
--- a/tests/topotests/zebra_recursive/test_zebra_recursive.py
+++ b/tests/topotests/zebra_recursive/test_zebra_recursive.py
@@ -26,6 +26,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.topogen import Topogen, get_topogen
 from lib.topolog import logger
 from lib.common_config import step
@@ -49,12 +50,10 @@ def setup_module(mod):
     r1.run("modprobe mpls_router")
     r1.run("echo 100000 > /proc/sys/net/mpls/platform_labels")

-    r1.run("ip link add ANNIE type dummy")
-    r1.run("ip link set ANNIE up")
+    create_interface_in_kernel(tgen, "r1", "ANNIE")
     r1.run("echo 1 > /proc/sys/net/mpls/conf/ANNIE/input")

-    r1.run("ip link add BETTY type dummy")
-    r1.run("ip link set BETTY up")
+    create_interface_in_kernel(tgen, "r1", "BETTY")
     r1.run("echo 1 > /proc/sys/net/mpls/conf/BETTY/input")

     for router in tgen.routers().values():
diff --git a/tests/topotests/zebra_vrf_metaq_leak/test_zebra_vrf_metaq_leak.py b/tests/topotests/zebra_vrf_metaq_leak/test_zebra_vrf_metaq_leak.py
index 444374008b..ddd4e41134 100644
--- a/tests/topotests/zebra_vrf_metaq_leak/test_zebra_vrf_metaq_leak.py
+++ b/tests/topotests/zebra_vrf_metaq_leak/test_zebra_vrf_metaq_leak.py
@@ -50,7 +50,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_interface_in_kernel, step
 from lib.topogen import Topogen, get_topogen
 from lib.topolog import logger

@@ -128,8 +128,7 @@ def test_vrf_disable_metaq_leak():

     step("Create VRF RED netdev + kernel routes, confirm they install")
     _add_vrf_netdev(r1)
-    r1.run("ip link add metaqflap type dummy")
-    r1.run("ip link set metaqflap up")
+    create_interface_in_kernel(tgen, "r1", "metaqflap")
     _add_kernel_routes(r1)

     test_func = partial(_all_routes_active, r1)