tests: clean up gbp calls from vpp_papi_provider
[vpp.git] / src / plugins / gbp / test / test_gbp.py
index 872ab4b..21d0770 100644 (file)
@@ -1,26 +1,45 @@
 #!/usr/bin/env python3
-
-from socket import AF_INET, AF_INET6, inet_pton, inet_ntop
+import typing
+from socket import AF_INET6, inet_pton, inet_ntop
 import unittest
 from ipaddress import ip_address, IPv4Network, IPv6Network
 
 from scapy.packet import Raw
 from scapy.layers.l2 import Ether, ARP, Dot1Q
 from scapy.layers.inet import IP, UDP, ICMP
-from scapy.layers.inet6 import IPv6, ICMPv6ND_NS, ICMPv6NDOptSrcLLAddr, \
-    ICMPv6ND_NA, ICMPv6EchoRequest
+from scapy.layers.inet6 import (
+    IPv6,
+    ICMPv6ND_NS,
+    ICMPv6NDOptSrcLLAddr,
+    ICMPv6ND_NA,
+    ICMPv6EchoRequest,
+)
 from scapy.utils6 import in6_getnsma, in6_getnsmac
 from scapy.layers.vxlan import VXLAN
-from scapy.data import ETH_P_IP, ETH_P_IPV6, ETH_P_ARP
+from scapy.data import ETH_P_IP, ETH_P_IPV6
 
+from framework import tag_fixme_vpp_workers
 from framework import VppTestCase, VppTestRunner
 from vpp_object import VppObject
 from vpp_interface import VppInterface
-from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable, \
-    VppIpInterfaceAddress, VppIpInterfaceBind, find_route, FibPathProto, \
-    FibPathType
-from vpp_l2 import VppBridgeDomain, VppBridgeDomainPort, \
-    VppBridgeDomainArpEntry, VppL2FibEntry, find_bridge_domain_port, VppL2Vtr
+from vpp_ip_route import (
+    VppIpRoute,
+    VppRoutePath,
+    VppIpTable,
+    VppIpInterfaceAddress,
+    VppIpInterfaceBind,
+    find_route,
+    FibPathProto,
+    FibPathType,
+)
+from vpp_l2 import (
+    VppBridgeDomain,
+    VppBridgeDomainPort,
+    VppBridgeDomainArpEntry,
+    VppL2FibEntry,
+    find_bridge_domain_port,
+    VppL2Vtr,
+)
 from vpp_sub_interface import L2_VTR_OP, VppDot1QSubint
 from vpp_ip import DpoProto, get_dpo_proto
 from vpp_papi import VppEnum, MACAddress
@@ -28,10 +47,6 @@ from vpp_vxlan_gbp_tunnel import find_vxlan_gbp_tunnel, INDEX_INVALID, \
     VppVxlanGbpTunnel
 from vpp_neighbor import VppNeighbor
 from vpp_acl import AclRule, VppAcl
-try:
-    text_type = unicode
-except NameError:
-    text_type = str
 
 NUM_PKTS = 67
 
@@ -72,7 +87,7 @@ def find_gbp_endpoint(test, sw_if_index=None, ip=None, mac=None,
     return False
 
 
-def find_gbp_vxlan(test, vni):
+def find_gbp_vxlan(test: VppTestCase, vni):
     ts = test.vapi.gbp_vxlan_tunnel_dump()
     for t in ts:
         if t.tunnel.vni == vni:
@@ -120,6 +135,7 @@ class VppGbpEndpoint(VppObject):
                  mac=True):
         self._test = test
         self.itf = itf
+        self.handle = None
         self.epg = epg
         self.recirc = recirc
 
@@ -137,20 +153,30 @@ class VppGbpEndpoint(VppObject):
         self.tun_src = tun_src
         self.tun_dst = tun_dst
 
+    def encode(self):
+        ips = [self.ip4, self.ip6]
+        return {
+            "sw_if_index": self.itf.sw_if_index,
+            "ips": ips,
+            "n_ips": len(ips),
+            "mac": self.vmac.packed,
+            "sclass": self.epg.sclass,
+            "flags": self.flags,
+            "tun": {
+                "src": self.tun_src,
+                "dst": self.tun_dst,
+            },
+        }
+
     def add_vpp_config(self):
         res = self._test.vapi.gbp_endpoint_add(
-            self.itf.sw_if_index,
-            [self.ip4, self.ip6],
-            self.vmac.packed,
-            self.epg.sclass,
-            self.flags,
-            self.tun_src,
-            self.tun_dst)
+            endpoint=self.encode(),
+        )
         self.handle = res.handle
         self._test.registry.register(self, self._test.logger)
 
     def remove_vpp_config(self):
-        self._test.vapi.gbp_endpoint_del(self.handle)
+        self._test.vapi.gbp_endpoint_del(handle=self.handle)
 
     def object_id(self):
         return "gbp-endpoint:[%d==%d:%s:%d]" % (self.handle,
@@ -175,20 +201,25 @@ class VppGbpRecirc(VppObject):
         self.epg = epg
         self.is_ext = is_ext
 
+    def encode(self):
+        return {
+            "is_ext": self.is_ext,
+            "sw_if_index": self.recirc.sw_if_index,
+            "sclass": self.epg.sclass,
+        }
+
     def add_vpp_config(self):
         self._test.vapi.gbp_recirc_add_del(
             1,
-            self.recirc.sw_if_index,
-            self.epg.sclass,
-            self.is_ext)
+            recirc=self.encode(),
+        )
         self._test.registry.register(self, self._test.logger)
 
     def remove_vpp_config(self):
         self._test.vapi.gbp_recirc_add_del(
             0,
-            self.recirc.sw_if_index,
-            self.epg.sclass,
-            self.is_ext)
+            recirc=self.encode(),
+        )
 
     def object_id(self):
         return "gbp-recirc:[%d]" % (self.recirc.sw_if_index)
@@ -213,14 +244,26 @@ class VppGbpExtItf(VppObject):
         self.rd = rd
         self.flags = 1 if anon else 0
 
+    def encode(self):
+        return {
+            "sw_if_index": self.itf.sw_if_index,
+            "bd_id": self.bd.bd_id,
+            "rd_id": self.rd.rd_id,
+            "flags": self.flags,
+        }
+
     def add_vpp_config(self):
         self._test.vapi.gbp_ext_itf_add_del(
-            1, self.itf.sw_if_index, self.bd.bd_id, self.rd.rd_id, self.flags)
+            1,
+            ext_itf=self.encode(),
+        )
         self._test.registry.register(self, self._test.logger)
 
     def remove_vpp_config(self):
         self._test.vapi.gbp_ext_itf_add_del(
-            0, self.itf.sw_if_index, self.bd.bd_id, self.rd.rd_id, self.flags)
+            0,
+            ext_itf=self.encode(),
+        )
 
     def object_id(self):
         return "gbp-ext-itf:[%d]%s" % (self.itf.sw_if_index,
@@ -240,7 +283,9 @@ class VppGbpSubnet(VppObject):
     """
 
     def __init__(self, test, rd, address, address_len,
-                 type, sw_if_index=None, sclass=None):
+                 type, sw_if_index=0xffffffff, sclass=0xffff):
+        # TODO: replace hardcoded defaults when vpp_papi supports
+        #  defaults in typedefs
         self._test = test
         self.rd_id = rd.rd_id
         a = ip_address(address)
@@ -254,22 +299,27 @@ class VppGbpSubnet(VppObject):
         self.sw_if_index = sw_if_index
         self.sclass = sclass
 
+    def encode(self):
+        return {
+            "type": self.type,
+            "sw_if_index": self.sw_if_index,
+            "sclass": self.sclass,
+            "prefix": self.prefix,
+            "rd_id": self.rd_id,
+        }
+
     def add_vpp_config(self):
         self._test.vapi.gbp_subnet_add_del(
-            1,
-            self.rd_id,
-            self.prefix,
-            self.type,
-            sw_if_index=self.sw_if_index if self.sw_if_index else 0xffffffff,
-            sclass=self.sclass if self.sclass else 0xffff)
+            is_add=1,
+            subnet=self.encode(),
+        )
         self._test.registry.register(self, self._test.logger)
 
     def remove_vpp_config(self):
         self._test.vapi.gbp_subnet_add_del(
-            0,
-            self.rd_id,
-            self.prefix,
-            self.type)
+            is_add=0,
+            subnet=self.encode()
+        )
 
     def object_id(self):
         return "gbp-subnet:[%d-%s]" % (self.rd_id, self.prefix)
@@ -306,30 +356,35 @@ class VppGbpEndpointGroup(VppObject):
         self.bvi_ip4 = bvi_ip4
         self.bvi_ip6 = bvi_ip6
         self.vnid = vnid
-        self.bd = bd
+        self.bd = bd  # VppGbpBridgeDomain
         self.rd = rd
         self.sclass = sclass
         if 0 == self.sclass:
             self.sclass = 0xffff
         self.retention = retention
 
+    def encode(self) -> dict:
+        return {
+            "uplink_sw_if_index": self.uplink.sw_if_index
+            if self.uplink else INDEX_INVALID,
+            "bd_id": self.bd.bd.bd_id,
+            "rd_id": self.rd.rd_id,
+            "vnid": self.vnid,
+            "sclass": self.sclass,
+            "retention": self.retention.encode(),
+        }
+
     def add_vpp_config(self):
-        self._test.vapi.gbp_endpoint_group_add(
-            self.vnid,
-            self.sclass,
-            self.bd.bd.bd_id,
-            self.rd.rd_id,
-            self.uplink.sw_if_index if self.uplink else INDEX_INVALID,
-            self.retention.encode())
+        self._test.vapi.gbp_endpoint_group_add(epg=self.encode())
         self._test.registry.register(self, self._test.logger)
 
     def remove_vpp_config(self):
-        self._test.vapi.gbp_endpoint_group_del(self.sclass)
+        self._test.vapi.gbp_endpoint_group_del(sclass=self.sclass)
 
-    def object_id(self):
+    def object_id(self) -> str:
         return "gbp-endpoint-group:[%d]" % (self.vnid)
 
-    def query_vpp_config(self):
+    def query_vpp_config(self) -> bool:
         epgs = self._test.vapi.gbp_endpoint_group_dump()
         for epg in epgs:
             if epg.epg.vnid == self.vnid:
@@ -342,7 +397,8 @@ class VppGbpBridgeDomain(VppObject):
     GBP Bridge Domain
     """
 
-    def __init__(self, test, bd, rd, bvi, uu_fwd=None,
+    def __init__(self, test, bd, rd, bvi,
+                 uu_fwd: typing.Optional[VppVxlanGbpTunnel] = None,
                  bm_flood=None, learn=True,
                  uu_drop=False, bm_drop=False,
                  ucast_arp=False):
@@ -365,23 +421,31 @@ class VppGbpBridgeDomain(VppObject):
         if ucast_arp:
             self.flags |= e.GBP_BD_API_FLAG_UCAST_ARP
 
+    def encode(self) -> dict:
+        return {
+            "flags": self.flags,
+            "bvi_sw_if_index": self.bvi.sw_if_index,
+            "uu_fwd_sw_if_index": self.uu_fwd.sw_if_index
+            if self.uu_fwd else INDEX_INVALID,
+            "bm_flood_sw_if_index": self.bm_flood.sw_if_index
+            if self.bm_flood else INDEX_INVALID,
+            "bd_id": self.bd.bd_id,
+            "rd_id": self.rd.rd_id,
+        }
+
     def add_vpp_config(self):
         self._test.vapi.gbp_bridge_domain_add(
-            self.bd.bd_id,
-            self.rd.rd_id,
-            self.flags,
-            self.bvi.sw_if_index,
-            self.uu_fwd.sw_if_index if self.uu_fwd else INDEX_INVALID,
-            self.bm_flood.sw_if_index if self.bm_flood else INDEX_INVALID)
+            bd=self.encode(),
+        )
         self._test.registry.register(self, self._test.logger)
 
     def remove_vpp_config(self):
-        self._test.vapi.gbp_bridge_domain_del(self.bd.bd_id)
+        self._test.vapi.gbp_bridge_domain_del(bd_id=self.bd.bd_id)
 
-    def object_id(self):
+    def object_id(self) -> str:
         return "gbp-bridge-domain:[%d]" % (self.bd.bd_id)
 
-    def query_vpp_config(self):
+    def query_vpp_config(self) -> bool:
         bds = self._test.vapi.gbp_bridge_domain_dump()
         for bd in bds:
             if bd.bd.bd_id == self.bd.bd_id:
@@ -403,18 +467,27 @@ class VppGbpRouteDomain(VppObject):
         self.ip4_uu = ip4_uu
         self.ip6_uu = ip6_uu
 
+    def encode(self) -> dict:
+        return {
+            "rd_id": self.rd_id,
+            "scope": self.scope,
+            "ip4_table_id": self.t4.table_id,
+            "ip6_table_id": self.t6.table_id,
+            "ip4_uu_sw_if_index": self.ip4_uu.sw_if_index
+            if self.ip4_uu else INDEX_INVALID,
+            "ip6_uu_sw_if_index": self.ip6_uu.sw_if_index
+            if self.ip6_uu else INDEX_INVALID,
+
+        }
+
     def add_vpp_config(self):
         self._test.vapi.gbp_route_domain_add(
-            self.rd_id,
-            self.scope,
-            self.t4.table_id,
-            self.t6.table_id,
-            self.ip4_uu.sw_if_index if self.ip4_uu else INDEX_INVALID,
-            self.ip6_uu.sw_if_index if self.ip6_uu else INDEX_INVALID)
+            rd=self.encode(),
+        )
         self._test.registry.register(self, self._test.logger)
 
     def remove_vpp_config(self):
-        self._test.vapi.gbp_route_domain_del(self.rd_id)
+        self._test.vapi.gbp_route_domain_del(rd_id=self.rd_id)
 
     def object_id(self):
         return "gbp-route-domain:[%d]" % (self.rd_id)
@@ -427,27 +500,29 @@ class VppGbpRouteDomain(VppObject):
         return False
 
 
-class VppGbpContractNextHop():
+class VppGbpContractNextHop:
     def __init__(self, mac, bd, ip, rd):
         self.mac = mac
         self.ip = ip
         self.bd = bd
         self.rd = rd
 
-    def encode(self):
-        return {'ip': self.ip,
-                'mac': self.mac.packed,
-                'bd_id': self.bd.bd.bd_id,
-                'rd_id': self.rd.rd_id}
+    def encode(self) -> dict:
+        return {
+            "ip": self.ip,
+            "mac": self.mac.packed,
+            "bd_id": self.bd.bd.bd_id,
+            "rd_id": self.rd.rd_id,
+        }
 
 
-class VppGbpContractRule():
+class VppGbpContractRule:
     def __init__(self, action, hash_mode, nhs=None):
         self.action = action
         self.hash_mode = hash_mode
         self.nhs = [] if nhs is None else nhs
 
-    def encode(self):
+    def encode(self) -> dict:
         nhs = []
         for nh in self.nhs:
             nhs.append(nh.encode())
@@ -470,12 +545,8 @@ class VppGbpContract(VppObject):
     """
 
     def __init__(self, test, scope, sclass, dclass, acl_index,
-                 rules, allowed_ethertypes):
+                 rules: list, allowed_ethertypes: list):
         self._test = test
-        if not isinstance(rules, list):
-            raise ValueError("'rules' must be a list.")
-        if not isinstance(allowed_ethertypes, list):
-            raise ValueError("'allowed_ethertypes' must be a list.")
         self.scope = scope
         self.acl_index = acl_index
         self.sclass = sclass
@@ -485,36 +556,35 @@ class VppGbpContract(VppObject):
         while (len(self.allowed_ethertypes) < 16):
             self.allowed_ethertypes.append(0)
 
-    def add_vpp_config(self):
+    def encode(self) -> dict:
         rules = []
         for r in self.rules:
             rules.append(r.encode())
+        return {
+            'acl_index': self.acl_index,
+            'scope': self.scope,
+            'sclass': self.sclass,
+            'dclass': self.dclass,
+            'n_rules': len(rules),
+            'rules': rules,
+            'n_ether_types': len(self.allowed_ethertypes),
+            'allowed_ethertypes': self.allowed_ethertypes,
+        }
+
+    def add_vpp_config(self):
         r = self._test.vapi.gbp_contract_add_del(
             is_add=1,
-            contract={
-                'acl_index': self.acl_index,
-                'scope': self.scope,
-                'sclass': self.sclass,
-                'dclass': self.dclass,
-                'n_rules': len(rules),
-                'rules': rules,
-                'n_ether_types': len(self.allowed_ethertypes),
-                'allowed_ethertypes': self.allowed_ethertypes})
+            contract=self.encode()
+        )
+
         self.stats_index = r.stats_index
         self._test.registry.register(self, self._test.logger)
 
     def remove_vpp_config(self):
         self._test.vapi.gbp_contract_add_del(
             is_add=0,
-            contract={
-                'acl_index': self.acl_index,
-                'scope': self.scope,
-                'sclass': self.sclass,
-                'dclass': self.dclass,
-                'n_rules': 0,
-                'rules': [],
-                'n_ether_types': len(self.allowed_ethertypes),
-                'allowed_ethertypes': self.allowed_ethertypes})
+            contract=self.encode(),
+        )
 
     def object_id(self):
         return "gbp-contract:[%d:%d:%d:%d]" % (self.scope,
@@ -553,17 +623,23 @@ class VppGbpVxlanTunnel(VppInterface):
         self.mode = mode
         self.src = src
 
+    def encode(self) -> dict:
+        return {
+            "vni": self.vni,
+            "mode": self.mode,
+            "bd_rd_id": self.bd_rd_id,
+            "src": self.src,
+        }
+
     def add_vpp_config(self):
         r = self._test.vapi.gbp_vxlan_tunnel_add(
-            self.vni,
-            self.bd_rd_id,
-            self.mode,
-            self.src)
+            tunnel=self.encode(),
+        )
         self.set_sw_if_index(r.sw_if_index)
         self._test.registry.register(self, self._test.logger)
 
     def remove_vpp_config(self):
-        self._test.vapi.gbp_vxlan_tunnel_del(self.vni)
+        self._test.vapi.gbp_vxlan_tunnel_del(vni=self.vni)
 
     def object_id(self):
         return "gbp-vxlan:%d" % (self.sw_if_index)
@@ -572,13 +648,18 @@ class VppGbpVxlanTunnel(VppInterface):
         return find_gbp_vxlan(self._test, self.vni)
 
 
+@tag_fixme_vpp_workers
 class TestGBP(VppTestCase):
     """ GBP Test Case """
 
     @property
-    def config_flags(self):
+    def nat_config_flags(self):
         return VppEnum.vl_api_nat_config_flags_t
 
+    @property
+    def nat44_config_flags(self):
+        return VppEnum.vl_api_nat44_config_flags_t
+
     @classmethod
     def setUpClass(cls):
         super(TestGBP, cls).setUpClass()
@@ -722,7 +803,6 @@ class TestGBP(VppTestCase):
         self.pg_send(src, tx)
         dst.get_capture(0, timeout=1)
         dst.assert_nothing_captured(remark="")
-        timeout = 0.1
 
     def send_and_expect_arp(self, src, tx, dst):
         rx = self.send_and_expect(src, tx, dst)
@@ -826,29 +906,36 @@ class TestGBP(VppTestCase):
                               "10.0.2.1", "11.0.0.4",
                               "2001:10:2::1", "3001::4")]
 
+        self.vapi.nat44_ed_plugin_enable_disable(enable=1)
+        self.vapi.nat66_plugin_enable_disable(enable=1)
+
         #
         # Config related to each of the EPGs
         #
         for epg in epgs:
             # IP config on the BVI interfaces
             if epg != epgs[1] and epg != epgs[4]:
-                VppIpInterfaceBind(self, epg.bvi, epg.rd.t4).add_vpp_config()
-                VppIpInterfaceBind(self, epg.bvi, epg.rd.t6).add_vpp_config()
+                b4 = VppIpInterfaceBind(self, epg.bvi,
+                                        epg.rd.t4).add_vpp_config()
+                b6 = VppIpInterfaceBind(self, epg.bvi,
+                                        epg.rd.t6).add_vpp_config()
                 epg.bvi.set_mac(self.router_mac)
 
                 # The BVIs are NAT inside interfaces
-                flags = self.config_flags.NAT_IS_INSIDE
+                flags = self.nat_config_flags.NAT_IS_INSIDE
                 self.vapi.nat44_interface_add_del_feature(
                     sw_if_index=epg.bvi.sw_if_index,
                     flags=flags, is_add=1)
                 self.vapi.nat66_add_del_interface(
-                    is_add=1, flags=flags,
-                    sw_if_index=epg.bvi.sw_if_index)
+                    sw_if_index=epg.bvi.sw_if_index,
+                    flags=flags, is_add=1)
 
-            if_ip4 = VppIpInterfaceAddress(self, epg.bvi, epg.bvi_ip4, 32)
-            if_ip6 = VppIpInterfaceAddress(self, epg.bvi, epg.bvi_ip6, 128)
-            if_ip4.add_vpp_config()
-            if_ip6.add_vpp_config()
+            if_ip4 = VppIpInterfaceAddress(self, epg.bvi,
+                                           epg.bvi_ip4, 32,
+                                           bind=b4).add_vpp_config()
+            if_ip6 = VppIpInterfaceAddress(self, epg.bvi,
+                                           epg.bvi_ip6, 128,
+                                           bind=b6).add_vpp_config()
 
             # EPG uplink interfaces in the RD
             VppIpInterfaceBind(self, epg.uplink, epg.rd.t4).add_vpp_config()
@@ -877,8 +964,7 @@ class TestGBP(VppTestCase):
             self.vapi.nat44_interface_add_del_feature(
                 sw_if_index=recirc.recirc.sw_if_index, is_add=1)
             self.vapi.nat66_add_del_interface(
-                is_add=1,
-                sw_if_index=recirc.recirc.sw_if_index)
+                sw_if_index=recirc.recirc.sw_if_index, is_add=1)
 
             recirc.add_vpp_config()
 
@@ -898,7 +984,7 @@ class TestGBP(VppTestCase):
             for (ip, fip) in zip(ep.ips, ep.fips):
                 # Add static mappings for each EP from the 10/8 to 11/8 network
                 if ip_address(ip).version == 4:
-                    flags = self.config_flags.NAT_IS_ADDR_ONLY
+                    flags = self.nat_config_flags.NAT_IS_ADDR_ONLY
                     self.vapi.nat44_add_del_static_mapping(
                         is_add=1,
                         local_ip_address=ip,
@@ -1270,7 +1356,6 @@ class TestGBP(VppTestCase):
                                     pkt_inter_epg_220_to_222 * NUM_PKTS,
                                     eps[3].itf,
                                     str(self.router_mac))
-
         #
         # remove both contracts, traffic stops in both directions
         #
@@ -1385,7 +1470,6 @@ class TestGBP(VppTestCase):
                                      pkt_inter_epg_220_to_global * NUM_PKTS,
                                      self.pg7,
                                      eps[0].fip6)
-
         #
         # From a global address to an EP: OUT2IN
         #
@@ -1464,40 +1548,8 @@ class TestGBP(VppTestCase):
         #
         # cleanup
         #
-        for ep in eps:
-            # del static mappings for each EP from the 10/8 to 11/8 network
-            flags = self.config_flags.NAT_IS_ADDR_ONLY
-            self.vapi.nat44_add_del_static_mapping(
-                is_add=0,
-                local_ip_address=ep.ip4,
-                external_ip_address=ep.fip4,
-                external_sw_if_index=0xFFFFFFFF,
-                vrf_id=0,
-                flags=flags)
-            self.vapi.nat66_add_del_static_mapping(
-                local_ip_address=ep.ip6,
-                external_ip_address=ep.fip6,
-                vrf_id=0, is_add=0)
-
-        for epg in epgs:
-            # IP config on the BVI interfaces
-            if epg != epgs[0] and epg != epgs[3]:
-                flags = self.config_flags.NAT_IS_INSIDE
-                self.vapi.nat44_interface_add_del_feature(
-                    sw_if_index=epg.bvi.sw_if_index,
-                    flags=flags,
-                    is_add=0)
-                self.vapi.nat66_add_del_interface(
-                    is_add=0, flags=flags,
-                    sw_if_index=epg.bvi.sw_if_index)
-
-        for recirc in recircs:
-            self.vapi.nat44_interface_add_del_feature(
-                sw_if_index=recirc.recirc.sw_if_index,
-                is_add=0)
-            self.vapi.nat66_add_del_interface(
-                is_add=0,
-                sw_if_index=recirc.recirc.sw_if_index)
+        self.vapi.nat44_ed_plugin_enable_disable(enable=0)
+        self.vapi.nat66_plugin_enable_disable(enable=0)
 
     def wait_for_ep_timeout(self, sw_if_index=None, ip=None, mac=None,
                             tep=None, n_tries=100, s_time=1):
@@ -2228,14 +2280,18 @@ class TestGBP(VppTestCase):
         for epg in epgs:
             # IP config on the BVI interfaces
             if epg != epgs[1]:
-                VppIpInterfaceBind(self, epg.bvi, epg.rd.t4).add_vpp_config()
-                VppIpInterfaceBind(self, epg.bvi, epg.rd.t6).add_vpp_config()
+                b4 = VppIpInterfaceBind(self, epg.bvi,
+                                        epg.rd.t4).add_vpp_config()
+                b6 = VppIpInterfaceBind(self, epg.bvi,
+                                        epg.rd.t6).add_vpp_config()
                 epg.bvi.set_mac(self.router_mac)
 
-            if_ip4 = VppIpInterfaceAddress(self, epg.bvi, epg.bvi_ip4, 32)
-            if_ip6 = VppIpInterfaceAddress(self, epg.bvi, epg.bvi_ip6, 128)
-            if_ip4.add_vpp_config()
-            if_ip6.add_vpp_config()
+            if_ip4 = VppIpInterfaceAddress(self, epg.bvi,
+                                           epg.bvi_ip4, 32,
+                                           bind=b4).add_vpp_config()
+            if_ip6 = VppIpInterfaceAddress(self, epg.bvi,
+                                           epg.bvi_ip6, 128,
+                                           bind=b6).add_vpp_config()
 
             # add the BD ARP termination entry for BVI IP
             epg.bd_arp_ip4 = VppBridgeDomainArpEntry(self, epg.bd.bd,
@@ -2455,8 +2511,8 @@ class TestGBP(VppTestCase):
         self.logger.info(self.vapi.cli("sh gbp bridge"))
 
         # ... and has a /32 applied
-        ip_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
-        ip_addr.add_vpp_config()
+        ip_addr = VppIpInterfaceAddress(self, gbd1.bvi,
+                                        "10.0.0.128", 32).add_vpp_config()
 
         #
         # The Endpoint-group
@@ -2536,8 +2592,8 @@ class TestGBP(VppTestCase):
         gbd1.add_vpp_config()
 
         # ... and has a /32 applied
-        ip_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
-        ip_addr.add_vpp_config()
+        ip_addr = VppIpInterfaceAddress(self, gbd1.bvi,
+                                        "10.0.0.128", 32).add_vpp_config()
 
         #
         # The Endpoint-group
@@ -2629,8 +2685,8 @@ class TestGBP(VppTestCase):
         self.logger.info(self.vapi.cli("sh gbp bridge"))
 
         # ... and has a /32 applied
-        ip_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
-        ip_addr.add_vpp_config()
+        ip_addr = VppIpInterfaceAddress(self, gbd1.bvi,
+                                        "10.0.0.128", 32).add_vpp_config()
 
         #
         # The Endpoint-group in which we are learning endpoints
@@ -2772,8 +2828,8 @@ class TestGBP(VppTestCase):
         #
         # Bind the BVI to the RD
         #
-        VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
-        VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
+        b4 = VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
+        b6 = VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
 
         #
         # Pg2 hosts the vxlan tunnel
@@ -2803,10 +2859,12 @@ class TestGBP(VppTestCase):
         self.logger.info(self.vapi.cli("sh gbp route"))
 
         # ... and has a /32 and /128 applied
-        ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
-        ip4_addr.add_vpp_config()
-        ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128", 128)
-        ip6_addr.add_vpp_config()
+        ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi,
+                                         "10.0.0.128", 32,
+                                         bind=b4).add_vpp_config()
+        ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi,
+                                         "2001:10::128", 128,
+                                         bind=b6).add_vpp_config()
 
         #
         # The Endpoint-group in which we are learning endpoints
@@ -3278,8 +3336,8 @@ class TestGBP(VppTestCase):
         #
         # Bind the BVI to the RD
         #
-        VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
-        VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
+        b_ip4 = VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
+        b_ip6 = VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
 
         #
         # Pg7 hosts a BD's UU-fwd
@@ -3301,14 +3359,16 @@ class TestGBP(VppTestCase):
         gbd2.add_vpp_config()
 
         # ... and has a /32 and /128 applied
-        ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
-        ip4_addr.add_vpp_config()
-        ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128", 128)
-        ip6_addr.add_vpp_config()
-        ip4_addr = VppIpInterfaceAddress(self, gbd2.bvi, "10.0.1.128", 32)
-        ip4_addr.add_vpp_config()
-        ip6_addr = VppIpInterfaceAddress(self, gbd2.bvi, "2001:11::128", 128)
-        ip6_addr.add_vpp_config()
+        ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi,
+                                         "10.0.0.128", 32,
+                                         bind=b_ip4).add_vpp_config()
+        ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi,
+                                         "2001:10::128", 128,
+                                         bind=b_ip6).add_vpp_config()
+        ip4_addr = VppIpInterfaceAddress(self, gbd2.bvi,
+                                         "10.0.1.128", 32).add_vpp_config()
+        ip6_addr = VppIpInterfaceAddress(self, gbd2.bvi,
+                                         "2001:11::128", 128).add_vpp_config()
 
         #
         # The Endpoint-groups in which we are learning endpoints
@@ -3867,8 +3927,8 @@ class TestGBP(VppTestCase):
         # add local l3out
         # the external bd
         self.loop4.set_mac(self.router_mac)
-        VppIpInterfaceBind(self, self.loop4, t4).add_vpp_config()
-        VppIpInterfaceBind(self, self.loop4, t6).add_vpp_config()
+        b_lo4_ip4 = VppIpInterfaceBind(self, self.loop4, t4).add_vpp_config()
+        b_lo4_ip6 = VppIpInterfaceBind(self, self.loop4, t6).add_vpp_config()
         ebd = VppBridgeDomain(self, 100)
         ebd.add_vpp_config()
         gebd = VppGbpBridgeDomain(self, ebd, rd1, self.loop4, None, None)
@@ -3885,12 +3945,12 @@ class TestGBP(VppTestCase):
             self,
             gebd.bvi,
             "10.1.0.128",
-            24).add_vpp_config()
+            24, bind=b_lo4_ip4).add_vpp_config()
         VppIpInterfaceAddress(
             self,
             gebd.bvi,
             "2001:10:1::128",
-            64).add_vpp_config()
+            64, bind=b_lo4_ip6).add_vpp_config()
         # ... which are L3-out subnets
         VppGbpSubnet(self, rd1, "10.1.0.0", 24,
                      VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
@@ -4197,12 +4257,12 @@ class TestGBP(VppTestCase):
         #
         # Bind the BVI to the RD
         #
-        VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
-        VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
-        VppIpInterfaceBind(self, self.loop1, t4).add_vpp_config()
-        VppIpInterfaceBind(self, self.loop1, t6).add_vpp_config()
-        VppIpInterfaceBind(self, self.loop2, t4).add_vpp_config()
-        VppIpInterfaceBind(self, self.loop2, t6).add_vpp_config()
+        b_lo0_ip4 = VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
+        b_lo0_ip6 = VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
+        b_lo1_ip4 = VppIpInterfaceBind(self, self.loop1, t4).add_vpp_config()
+        b_lo1_ip6 = VppIpInterfaceBind(self, self.loop1, t6).add_vpp_config()
+        b_lo2_ip4 = VppIpInterfaceBind(self, self.loop2, t4).add_vpp_config()
+        b_lo2_ip6 = VppIpInterfaceBind(self, self.loop2, t6).add_vpp_config()
 
         #
         # Pg7 hosts a BD's UU-fwd
@@ -4224,14 +4284,18 @@ class TestGBP(VppTestCase):
         gbd2.add_vpp_config()
 
         # ... and has a /32 and /128 applied
-        ip4_addr1 = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
-        ip4_addr1.add_vpp_config()
-        ip6_addr1 = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128", 128)
-        ip6_addr1.add_vpp_config()
-        ip4_addr2 = VppIpInterfaceAddress(self, gbd2.bvi, "10.0.1.128", 32)
-        ip4_addr2.add_vpp_config()
-        ip6_addr2 = VppIpInterfaceAddress(self, gbd2.bvi, "2001:11::128", 128)
-        ip6_addr2.add_vpp_config()
+        ip4_addr1 = VppIpInterfaceAddress(self, gbd1.bvi,
+                                          "10.0.0.128", 32,
+                                          bind=b_lo0_ip4).add_vpp_config()
+        ip6_addr1 = VppIpInterfaceAddress(self, gbd1.bvi,
+                                          "2001:10::128", 128,
+                                          bind=b_lo0_ip6).add_vpp_config()
+        ip4_addr2 = VppIpInterfaceAddress(self, gbd2.bvi,
+                                          "10.0.1.128", 32,
+                                          bind=b_lo1_ip4).add_vpp_config()
+        ip6_addr2 = VppIpInterfaceAddress(self, gbd2.bvi,
+                                          "2001:11::128", 128,
+                                          bind=b_lo1_ip6).add_vpp_config()
 
         #
         # The Endpoint-groups
@@ -4262,10 +4326,12 @@ class TestGBP(VppTestCase):
                                   bd_uu3, learn=False)
         gbd3.add_vpp_config()
 
-        ip4_addr3 = VppIpInterfaceAddress(self, gbd3.bvi, "12.0.0.128", 32)
-        ip4_addr3.add_vpp_config()
-        ip6_addr3 = VppIpInterfaceAddress(self, gbd3.bvi, "4001:10::128", 128)
-        ip6_addr3.add_vpp_config()
+        ip4_addr3 = VppIpInterfaceAddress(self, gbd3.bvi,
+                                          "12.0.0.128", 32,
+                                          bind=b_lo2_ip4).add_vpp_config()
+        ip6_addr3 = VppIpInterfaceAddress(self, gbd3.bvi,
+                                          "4001:10::128", 128,
+                                          bind=b_lo2_ip6).add_vpp_config()
 
         #
         # self.logger.info(self.vapi.cli("show gbp bridge"))
@@ -4624,8 +4690,8 @@ class TestGBP(VppTestCase):
         #
         # Bind the BVI to the RD
         #
-        VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
-        VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
+        b_ip4 = VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
+        b_ip6 = VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
 
         #
         # Pg7 hosts a BD's BUM
@@ -4661,10 +4727,10 @@ class TestGBP(VppTestCase):
         epg_220.add_vpp_config()
 
         # the BVIs have the subnets applied ...
-        ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 24)
-        ip4_addr.add_vpp_config()
-        ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128", 64)
-        ip6_addr.add_vpp_config()
+        ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128",
+                                         24, bind=b_ip4).add_vpp_config()
+        ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128",
+                                         64, bind=b_ip6).add_vpp_config()
 
         # ... which are L3-out subnets
         l3o_1 = VppGbpSubnet(
@@ -5410,8 +5476,8 @@ class TestGBP(VppTestCase):
         #
         # Bind the BVI to the RD
         #
-        VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
-        VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
+        bind_l0_ip4 = VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
+        bind_l0_ip6 = VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
 
         #
         # Pg7 hosts a BD's BUM
@@ -5439,8 +5505,9 @@ class TestGBP(VppTestCase):
         epg_220.add_vpp_config()
 
         # the BVIs have the subnet applied ...
-        ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 24)
-        ip4_addr.add_vpp_config()
+        ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi,
+                                         "10.0.0.128", 24,
+                                         bind=bind_l0_ip4).add_vpp_config()
 
         # ... which is an Anonymous L3-out subnets
         l3o_1 = VppGbpSubnet(