Merge pull request #13 from pimvanpelt/mpls_iface
Support MPLS Interfaces
This commit is contained in:
		@@ -73,6 +73,9 @@ following fields:
 | 
				
			|||||||
    in CIDR format. VPP requires IP addresses to be unique in the entire dataplane, with one
 | 
					    in CIDR format. VPP requires IP addresses to be unique in the entire dataplane, with one
 | 
				
			||||||
    notable exception: Multiple IP addresses in the same prefix/len can be added on one and the
 | 
					    notable exception: Multiple IP addresses in the same prefix/len can be added on one and the
 | 
				
			||||||
    same interface.
 | 
					    same interface.
 | 
				
			||||||
 | 
					*   ***mpls***: An optional boolean that configures MPLS on the interface or sub-interface. The
 | 
				
			||||||
 | 
					    default value is `false`, if the field is not specified, which means MPLS will not be enabled.
 | 
				
			||||||
 | 
					    This allows BVIs, represented by Loopbacks, to participate in MPLS .
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Although VPP would allow it, `vppcfg` does not allow for loopbacks to have sub-interfaces.
 | 
					Although VPP would allow it, `vppcfg` does not allow for loopbacks to have sub-interfaces.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -87,6 +90,7 @@ loopbacks:
 | 
				
			|||||||
    lcp: bvi1
 | 
					    lcp: bvi1
 | 
				
			||||||
    mtu: 9000
 | 
					    mtu: 9000
 | 
				
			||||||
    addresses: [ 10.0.1.1/24, 10.0.1.2/24, 2001:db8:1::1/64 ]
 | 
					    addresses: [ 10.0.1.1/24, 10.0.1.2/24, 2001:db8:1::1/64 ]
 | 
				
			||||||
 | 
					    mpls: true
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Bridge Domains
 | 
					### Bridge Domains
 | 
				
			||||||
@@ -306,6 +310,8 @@ exist as a PHY in VPP (ie. `HundredGigabitEthernet12/0/0`) or as a specified `Bo
 | 
				
			|||||||
    If it is not specified, the link is considered admin 'up'.
 | 
					    If it is not specified, the link is considered admin 'up'.
 | 
				
			||||||
*   ***device-type***: An optional interface type in VPP. Currently the only supported vlaue is
 | 
					*   ***device-type***: An optional interface type in VPP. Currently the only supported vlaue is
 | 
				
			||||||
    `dpdk`, and it is used to generate correct mock interfaces if the `--novpp` flag is used.
 | 
					    `dpdk`, and it is used to generate correct mock interfaces if the `--novpp` flag is used.
 | 
				
			||||||
 | 
					*   ***mpls***: An optional boolean that configures MPLS on the interface or sub-interface. The
 | 
				
			||||||
 | 
					    default value is `false`, if the field is not specified, which means MPLS will not be enabled.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Further, top-level interfaces, that is to say those that do not have an encapsulation, are permitted
 | 
					Further, top-level interfaces, that is to say those that do not have an encapsulation, are permitted
 | 
				
			||||||
to have any number of sub-interfaces specified by `subid`, an integer between [0,2G), which further
 | 
					to have any number of sub-interfaces specified by `subid`, an integer between [0,2G), which further
 | 
				
			||||||
@@ -330,6 +336,7 @@ interfaces:
 | 
				
			|||||||
    lcp: "ice0"
 | 
					    lcp: "ice0"
 | 
				
			||||||
    mtu: 9000
 | 
					    mtu: 9000
 | 
				
			||||||
    addresses: [ 192.0.2.1/30, 2001:db8:1::1/64 ]
 | 
					    addresses: [ 192.0.2.1/30, 2001:db8:1::1/64 ]
 | 
				
			||||||
 | 
					    mpls: true
 | 
				
			||||||
    sub-interfaces:
 | 
					    sub-interfaces:
 | 
				
			||||||
      1234:
 | 
					      1234:
 | 
				
			||||||
        mtu: 9000
 | 
					        mtu: 9000
 | 
				
			||||||
@@ -338,6 +345,7 @@ interfaces:
 | 
				
			|||||||
      1235:
 | 
					      1235:
 | 
				
			||||||
        mtu: 1500
 | 
					        mtu: 1500
 | 
				
			||||||
        lcp: "ice0.qinq"
 | 
					        lcp: "ice0.qinq"
 | 
				
			||||||
 | 
					        mpls: true
 | 
				
			||||||
        addresses: [ 192.0.2.9/30, 2001:db8:3::1/64 ]
 | 
					        addresses: [ 192.0.2.9/30, 2001:db8:3::1/64 ]
 | 
				
			||||||
        encapsulation:
 | 
					        encapsulation:
 | 
				
			||||||
          dot1q: 1234
 | 
					          dot1q: 1234
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -701,3 +701,14 @@ def validate_interfaces(yaml):
 | 
				
			|||||||
                        result = False
 | 
					                        result = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return result, msgs
 | 
					    return result, msgs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def is_mpls(yaml, ifname):
 | 
				
			||||||
 | 
					    """Returns True if the interface exists and has mpls enabled. Returns false otherwise."""
 | 
				
			||||||
 | 
					    ifname, iface = get_by_name(yaml, ifname)
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        if iface["mpls"] == True:
 | 
				
			||||||
 | 
					            return True
 | 
				
			||||||
 | 
					    except:
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					    return False
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -96,3 +96,14 @@ def validate_loopbacks(yaml):
 | 
				
			|||||||
            result = False
 | 
					            result = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return result, msgs
 | 
					    return result, msgs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def is_mpls(yaml, ifname):
 | 
				
			||||||
 | 
					    """Returns True if the loopback exists and has mpls enabled. Returns false otherwise."""
 | 
				
			||||||
 | 
					    ifname, iface = get_by_name(yaml, ifname)
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        if iface["mpls"] == True:
 | 
				
			||||||
 | 
					            return True
 | 
				
			||||||
 | 
					    except:
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					    return False
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -277,3 +277,10 @@ class TestInterfaceMethods(unittest.TestCase):
 | 
				
			|||||||
        self.assertFalse(
 | 
					        self.assertFalse(
 | 
				
			||||||
            interface.get_admin_state(self.cfg, "GigabitEthernet1/0/0.102")
 | 
					            interface.get_admin_state(self.cfg, "GigabitEthernet1/0/0.102")
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_is_mpls(self):
 | 
				
			||||||
 | 
					        self.assertTrue(interface.is_mpls(self.cfg, "GigabitEthernet1/0/1"))
 | 
				
			||||||
 | 
					        self.assertTrue(interface.is_mpls(self.cfg, "GigabitEthernet1/0/1.101"))
 | 
				
			||||||
 | 
					        self.assertFalse(interface.is_mpls(self.cfg, "GigabitEthernet1/0/0"))
 | 
				
			||||||
 | 
					        self.assertFalse(interface.is_mpls(self.cfg, "GigabitEthernet1/0/0.100"))
 | 
				
			||||||
 | 
					        self.assertFalse(interface.is_mpls(self.cfg, "notexist"))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -50,3 +50,8 @@ class TestLoopbackMethods(unittest.TestCase):
 | 
				
			|||||||
        self.assertIn("loop1", ifs)
 | 
					        self.assertIn("loop1", ifs)
 | 
				
			||||||
        self.assertIn("loop2", ifs)
 | 
					        self.assertIn("loop2", ifs)
 | 
				
			||||||
        self.assertNotIn("loop-noexist", ifs)
 | 
					        self.assertNotIn("loop-noexist", ifs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_is_mpls(self):
 | 
				
			||||||
 | 
					        self.assertTrue(loopback.is_mpls(self.cfg, "loop1"))
 | 
				
			||||||
 | 
					        self.assertFalse(loopback.is_mpls(self.cfg, "loop2"))
 | 
				
			||||||
 | 
					        self.assertFalse(loopback.is_mpls(self.cfg, "loop-noexist"))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,7 +20,8 @@ interfaces:
 | 
				
			|||||||
    lcp: "ice12-0-0"
 | 
					    lcp: "ice12-0-0"
 | 
				
			||||||
    mac: f2:01:00:12:00:00
 | 
					    mac: f2:01:00:12:00:00
 | 
				
			||||||
    mtu: 9000
 | 
					    mtu: 9000
 | 
				
			||||||
    addresses: [ 192.0.2.17/30, 2001:DB8:3::1/64 ]
 | 
					    addresses: [ 192.0.2.17/30, 2001:db8:3::1/64 ]
 | 
				
			||||||
 | 
					    mpls: true
 | 
				
			||||||
    sub-interfaces:
 | 
					    sub-interfaces:
 | 
				
			||||||
      1234:
 | 
					      1234:
 | 
				
			||||||
        mtu: 1200
 | 
					        mtu: 1200
 | 
				
			||||||
@@ -90,6 +91,7 @@ loopbacks:
 | 
				
			|||||||
    mtu: 1500
 | 
					    mtu: 1500
 | 
				
			||||||
    mac: 02:de:ad:11:be:ef
 | 
					    mac: 02:de:ad:11:be:ef
 | 
				
			||||||
    addresses: [ 10.0.2.1/24, 2001:db8:2::1/64 ]
 | 
					    addresses: [ 10.0.2.1/24, 2001:db8:2::1/64 ]
 | 
				
			||||||
 | 
					    mpls: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bridgedomains:
 | 
					bridgedomains:
 | 
				
			||||||
  bd1:
 | 
					  bd1:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,6 +33,7 @@ loopback:
 | 
				
			|||||||
  lcp: str(max=15,matches='[a-z]+[a-z0-9-]*',required=False)
 | 
					  lcp: str(max=15,matches='[a-z]+[a-z0-9-]*',required=False)
 | 
				
			||||||
  mtu: int(min=128,max=9216,required=False)
 | 
					  mtu: int(min=128,max=9216,required=False)
 | 
				
			||||||
  addresses: list(ip_interface(),min=1,max=6,required=False)
 | 
					  addresses: list(ip_interface(),min=1,max=6,required=False)
 | 
				
			||||||
 | 
					  mpls: bool(required=False)
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
bondethernet:
 | 
					bondethernet:
 | 
				
			||||||
  description: str(exclude='\'"',len=64,required=False)
 | 
					  description: str(exclude='\'"',len=64,required=False)
 | 
				
			||||||
@@ -50,6 +51,7 @@ interface:
 | 
				
			|||||||
  sub-interfaces: map(include('sub-interface'),key=int(min=1,max=4294967295),required=False)
 | 
					  sub-interfaces: map(include('sub-interface'),key=int(min=1,max=4294967295),required=False)
 | 
				
			||||||
  l2xc: str(required=False)
 | 
					  l2xc: str(required=False)
 | 
				
			||||||
  state: enum('up', 'down', required=False)
 | 
					  state: enum('up', 'down', required=False)
 | 
				
			||||||
 | 
					  mpls: bool(required=False)
 | 
				
			||||||
  device-type: enum('dpdk', required=False)
 | 
					  device-type: enum('dpdk', required=False)
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
sub-interface:
 | 
					sub-interface:
 | 
				
			||||||
@@ -60,6 +62,7 @@ sub-interface:
 | 
				
			|||||||
  encapsulation: include('encapsulation',required=False)
 | 
					  encapsulation: include('encapsulation',required=False)
 | 
				
			||||||
  l2xc: str(required=False)
 | 
					  l2xc: str(required=False)
 | 
				
			||||||
  state: enum('up', 'down', required=False)
 | 
					  state: enum('up', 'down', required=False)
 | 
				
			||||||
 | 
					  mpls: bool(required=False)
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
encapsulation:
 | 
					encapsulation:
 | 
				
			||||||
  dot1q: int(min=1,max=4095,required=False)
 | 
					  dot1q: int(min=1,max=4095,required=False)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,6 +23,7 @@ interfaces:
 | 
				
			|||||||
    mtu: 9216
 | 
					    mtu: 9216
 | 
				
			||||||
    lcp: "e1"
 | 
					    lcp: "e1"
 | 
				
			||||||
    addresses: [ "192.0.2.1/30", "2001:db8:1::1/64" ]
 | 
					    addresses: [ "192.0.2.1/30", "2001:db8:1::1/64" ]
 | 
				
			||||||
 | 
					    mpls: true
 | 
				
			||||||
    sub-interfaces:
 | 
					    sub-interfaces:
 | 
				
			||||||
      100:
 | 
					      100:
 | 
				
			||||||
        lcp: "foo"
 | 
					        lcp: "foo"
 | 
				
			||||||
@@ -33,6 +34,7 @@ interfaces:
 | 
				
			|||||||
          exact-match: True
 | 
					          exact-match: True
 | 
				
			||||||
        lcp: "e1.100"
 | 
					        lcp: "e1.100"
 | 
				
			||||||
        addresses: [ "10.0.2.1/30" ]
 | 
					        addresses: [ "10.0.2.1/30" ]
 | 
				
			||||||
 | 
					        mpls: true
 | 
				
			||||||
      102:
 | 
					      102:
 | 
				
			||||||
        encapsulation:
 | 
					        encapsulation:
 | 
				
			||||||
          dot1ad: 100
 | 
					          dot1ad: 100
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@ loopbacks:
 | 
				
			|||||||
    mtu: 2000
 | 
					    mtu: 2000
 | 
				
			||||||
    lcp: "loop56789012345"
 | 
					    lcp: "loop56789012345"
 | 
				
			||||||
    addresses: [ 192.0.2.1/29, 2001:db8::1/64 ]
 | 
					    addresses: [ 192.0.2.1/29, 2001:db8::1/64 ]
 | 
				
			||||||
 | 
					    mpls: true
 | 
				
			||||||
  loop2:
 | 
					  loop2:
 | 
				
			||||||
    description: "Loopback, invalid because it has an address but no LCP"
 | 
					    description: "Loopback, invalid because it has an address but no LCP"
 | 
				
			||||||
    mtu: 2000
 | 
					    mtu: 2000
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -108,6 +108,8 @@ class Dumper(VPPApi):
 | 
				
			|||||||
                            loop["addresses"] = self.cache["interface_addresses"][
 | 
					                            loop["addresses"] = self.cache["interface_addresses"][
 | 
				
			||||||
                                iface.sw_if_index
 | 
					                                iface.sw_if_index
 | 
				
			||||||
                            ]
 | 
					                            ]
 | 
				
			||||||
 | 
					                    if iface.sw_if_index in self.cache["interface_mpls"]:
 | 
				
			||||||
 | 
					                        loop["mpls"] = self.cache["interface_mpls"][iface.sw_if_index]
 | 
				
			||||||
                    config["loopbacks"][iface.interface_name] = loop
 | 
					                    config["loopbacks"][iface.interface_name] = loop
 | 
				
			||||||
                elif iface.interface_dev_type in [
 | 
					                elif iface.interface_dev_type in [
 | 
				
			||||||
                    "bond",
 | 
					                    "bond",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -947,6 +947,9 @@ class Reconciler:
 | 
				
			|||||||
        if not self.__sync_phys():
 | 
					        if not self.__sync_phys():
 | 
				
			||||||
            self.logger.warning("Could not sync PHYs in VPP")
 | 
					            self.logger.warning("Could not sync PHYs in VPP")
 | 
				
			||||||
            ret = False
 | 
					            ret = False
 | 
				
			||||||
 | 
					        if not self.__sync_mpls_state():
 | 
				
			||||||
 | 
					            self.logger.warning("Could not sync interface MPLS state in VPP")
 | 
				
			||||||
 | 
					            ret = False
 | 
				
			||||||
        if not self.__sync_admin_state():
 | 
					        if not self.__sync_admin_state():
 | 
				
			||||||
            self.logger.warning("Could not sync interface adminstate in VPP")
 | 
					            self.logger.warning("Could not sync interface adminstate in VPP")
 | 
				
			||||||
            ret = False
 | 
					            ret = False
 | 
				
			||||||
@@ -1291,6 +1294,36 @@ class Reconciler:
 | 
				
			|||||||
            ret = False
 | 
					            ret = False
 | 
				
			||||||
        return ret
 | 
					        return ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __sync_mpls_state(self):
 | 
				
			||||||
 | 
					        """Synchronize the VPP Dataplane configuration for interface and loopback MPLS state"""
 | 
				
			||||||
 | 
					        for ifname in interface.get_interfaces(self.cfg) + loopback.get_loopbacks(
 | 
				
			||||||
 | 
					            self.cfg
 | 
				
			||||||
 | 
					        ):
 | 
				
			||||||
 | 
					            if ifname.startswith("loop"):
 | 
				
			||||||
 | 
					                vpp_ifname, config_iface = loopback.get_by_name(self.cfg, ifname)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                vpp_ifname, config_iface = interface.get_by_name(self.cfg, ifname)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                config_mpls = config_iface["mpls"]
 | 
				
			||||||
 | 
					            except KeyError:
 | 
				
			||||||
 | 
					                config_mpls = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            vpp_mpls = False
 | 
				
			||||||
 | 
					            if vpp_ifname in self.vpp.cache["interface_names"]:
 | 
				
			||||||
 | 
					                sw_if_index = self.vpp.cache["interface_names"][vpp_ifname]
 | 
				
			||||||
 | 
					                try:
 | 
				
			||||||
 | 
					                    vpp_mpls = self.vpp.cache["interface_mpls"][sw_if_index]
 | 
				
			||||||
 | 
					                except KeyError:
 | 
				
			||||||
 | 
					                    pass
 | 
				
			||||||
 | 
					            if vpp_mpls != config_mpls:
 | 
				
			||||||
 | 
					                state = "disable"
 | 
				
			||||||
 | 
					                if config_mpls:
 | 
				
			||||||
 | 
					                    state = "enable"
 | 
				
			||||||
 | 
					                cli = f"set interface mpls {vpp_ifname} {state}"
 | 
				
			||||||
 | 
					                self.cli["sync"].append(cli)
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __sync_addresses(self):
 | 
					    def __sync_addresses(self):
 | 
				
			||||||
        """Synchronize the VPP Dataplane configuration for interface addresses"""
 | 
					        """Synchronize the VPP Dataplane configuration for interface addresses"""
 | 
				
			||||||
        for ifname in interface.get_interfaces(self.cfg) + loopback.get_loopbacks(
 | 
					        for ifname in interface.get_interfaces(self.cfg) + loopback.get_loopbacks(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -119,6 +119,7 @@ class VPPApi:
 | 
				
			|||||||
            "interface_names": {},
 | 
					            "interface_names": {},
 | 
				
			||||||
            "interfaces": {},
 | 
					            "interfaces": {},
 | 
				
			||||||
            "interface_addresses": {},
 | 
					            "interface_addresses": {},
 | 
				
			||||||
 | 
					            "interface_mpls": {},
 | 
				
			||||||
            "bondethernets": {},
 | 
					            "bondethernets": {},
 | 
				
			||||||
            "bondethernet_members": {},
 | 
					            "bondethernet_members": {},
 | 
				
			||||||
            "bridgedomains": {},
 | 
					            "bridgedomains": {},
 | 
				
			||||||
@@ -215,7 +216,7 @@ class VPPApi:
 | 
				
			|||||||
        enumerating the 'interfaces' scope from yaml_config"""
 | 
					        enumerating the 'interfaces' scope from yaml_config"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if not "interfaces" in yaml_config:
 | 
					        if not "interfaces" in yaml_config:
 | 
				
			||||||
            self.logger.error(f"YAML config does not contain any interfaces")
 | 
					            self.logger.error("YAML config does not contain any interfaces")
 | 
				
			||||||
            return False
 | 
					            return False
 | 
				
			||||||
        self.logger.debug(f"config: {yaml_config['interfaces']}")
 | 
					        self.logger.debug(f"config: {yaml_config['interfaces']}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -305,9 +306,7 @@ class VPPApi:
 | 
				
			|||||||
                    self.cache["lcps"][lcp.phy_sw_if_index] = lcp
 | 
					                    self.cache["lcps"][lcp.phy_sw_if_index] = lcp
 | 
				
			||||||
                self.lcp_enabled = True
 | 
					                self.lcp_enabled = True
 | 
				
			||||||
        except AttributeError as err:
 | 
					        except AttributeError as err:
 | 
				
			||||||
            self.logger.warning(
 | 
					            self.logger.warning(f"LinuxCP API not found - missing plugin: {err}")
 | 
				
			||||||
                f"linux-cp not found, will not reconcile Linux Control Plane: {err}"
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.logger.debug("Retrieving interfaces")
 | 
					        self.logger.debug("Retrieving interfaces")
 | 
				
			||||||
        api_response = self.vpp.api.sw_interface_dump()
 | 
					        api_response = self.vpp.api.sw_interface_dump()
 | 
				
			||||||
@@ -332,6 +331,16 @@ class VPPApi:
 | 
				
			|||||||
                    str(addr.prefix)
 | 
					                    str(addr.prefix)
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try:  ## TODO(pim): Remove after 23.10 release
 | 
				
			||||||
 | 
					            self.logger.debug("Retrieving interface MPLS state")
 | 
				
			||||||
 | 
					            api_response = self.vpp.api.mpls_interface_dump()
 | 
				
			||||||
 | 
					            for iface in api_response:
 | 
				
			||||||
 | 
					                self.cache["interface_mpls"][iface.sw_if_index] = True
 | 
				
			||||||
 | 
					        except AttributeError:
 | 
				
			||||||
 | 
					            self.logger.warning(
 | 
				
			||||||
 | 
					                f"MPLS state retrieval requires https://gerrit.fd.io/r/c/vpp/+/39022"
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.logger.debug("Retrieving bondethernets")
 | 
					        self.logger.debug("Retrieving bondethernets")
 | 
				
			||||||
        api_response = self.vpp.api.sw_bond_interface_dump()
 | 
					        api_response = self.vpp.api.sw_bond_interface_dump()
 | 
				
			||||||
        for iface in api_response:
 | 
					        for iface in api_response:
 | 
				
			||||||
@@ -349,10 +358,13 @@ class VPPApi:
 | 
				
			|||||||
        for bridge in api_response:
 | 
					        for bridge in api_response:
 | 
				
			||||||
            self.cache["bridgedomains"][bridge.bd_id] = bridge
 | 
					            self.cache["bridgedomains"][bridge.bd_id] = bridge
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.logger.debug("Retrieving vxlan_tunnels")
 | 
					        try:
 | 
				
			||||||
        api_response = self.vpp.api.vxlan_tunnel_v2_dump()
 | 
					            self.logger.debug("Retrieving vxlan_tunnels")
 | 
				
			||||||
        for vxlan in api_response:
 | 
					            api_response = self.vpp.api.vxlan_tunnel_v2_dump()
 | 
				
			||||||
            self.cache["vxlan_tunnels"][vxlan.sw_if_index] = vxlan
 | 
					            for vxlan in api_response:
 | 
				
			||||||
 | 
					                self.cache["vxlan_tunnels"][vxlan.sw_if_index] = vxlan
 | 
				
			||||||
 | 
					        except AttributeError as err:
 | 
				
			||||||
 | 
					            self.logger.warning(f"VXLAN API not found - missing plugin: {err}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.logger.debug("Retrieving L2 Cross Connects")
 | 
					        self.logger.debug("Retrieving L2 Cross Connects")
 | 
				
			||||||
        api_response = self.vpp.api.l2_xconnect_dump()
 | 
					        api_response = self.vpp.api.l2_xconnect_dump()
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user