Add TAP support
- based on previously submitted schema and validation, can add a TAP with host netns, bridge and MTU. - detect diffs in __tap_has_diff(), used to prune TAPs that must change - add prune_taps() and create_taps() in the reconciler - add Dumper() logic to emit YAML config for TAPs - Move tap_is_lcp() into the VPPApi() class, so it can be reused Add lots of test cases in intest/*.yaml and example.yaml - full regression and integration and unit/YAML tests pass on this change.
This commit is contained in:
@ -11,7 +11,8 @@ interfaces:
|
|||||||
description: "LAG #2"
|
description: "LAG #2"
|
||||||
|
|
||||||
HundredGigabitEthernet12/0/0:
|
HundredGigabitEthernet12/0/0:
|
||||||
description: Not Used
|
mtu: 1500
|
||||||
|
description: "bridged with tap"
|
||||||
|
|
||||||
HundredGigabitEthernet12/0/1:
|
HundredGigabitEthernet12/0/1:
|
||||||
description: Not Used
|
description: Not Used
|
||||||
@ -42,3 +43,23 @@ interfaces:
|
|||||||
encapsulation:
|
encapsulation:
|
||||||
dot1ad: 501
|
dot1ad: 501
|
||||||
exact-match: False
|
exact-match: False
|
||||||
|
tap100:
|
||||||
|
mtu: 1500
|
||||||
|
|
||||||
|
loopbacks:
|
||||||
|
loop100:
|
||||||
|
lcp: "bvi100"
|
||||||
|
addresses: [ 10.1.2.1/24 ]
|
||||||
|
|
||||||
|
bridgedomains:
|
||||||
|
bd100:
|
||||||
|
description: "Bridge Domain 100"
|
||||||
|
mtu: 1500
|
||||||
|
bvi: loop100
|
||||||
|
interfaces: [ HundredGigabitEthernet12/0/0, tap100 ]
|
||||||
|
|
||||||
|
taps:
|
||||||
|
tap100:
|
||||||
|
host:
|
||||||
|
name: vpp-tap100
|
||||||
|
mtu: 1500
|
||||||
|
@ -66,6 +66,8 @@ interfaces:
|
|||||||
exact-match: False
|
exact-match: False
|
||||||
vxlan_tunnel1:
|
vxlan_tunnel1:
|
||||||
mtu: 2000
|
mtu: 2000
|
||||||
|
tap100:
|
||||||
|
mtu: 9000
|
||||||
|
|
||||||
loopbacks:
|
loopbacks:
|
||||||
loop0:
|
loop0:
|
||||||
@ -90,3 +92,9 @@ vxlan_tunnels:
|
|||||||
local: 192.0.2.1
|
local: 192.0.2.1
|
||||||
remote: 192.0.2.2
|
remote: 192.0.2.2
|
||||||
vni: 101
|
vni: 101
|
||||||
|
|
||||||
|
taps:
|
||||||
|
tap100:
|
||||||
|
host:
|
||||||
|
name: vpp-tap
|
||||||
|
mtu: 9000
|
||||||
|
34
intest/hippo14.yaml
Normal file
34
intest/hippo14.yaml
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
interfaces:
|
||||||
|
GigabitEthernet3/0/0:
|
||||||
|
mtu: 9000
|
||||||
|
state: up
|
||||||
|
sub-interfaces:
|
||||||
|
100:
|
||||||
|
mtu: 9000
|
||||||
|
l2xc: tap100
|
||||||
|
GigabitEthernet3/0/1:
|
||||||
|
mtu: 1500
|
||||||
|
mac: 00:25:90:0c:05:01
|
||||||
|
state: down
|
||||||
|
description: Not Used
|
||||||
|
HundredGigabitEthernet12/0/0:
|
||||||
|
mtu: 1500
|
||||||
|
mac: b4:96:91:b3:b1:10
|
||||||
|
state: down
|
||||||
|
description: Not Used
|
||||||
|
HundredGigabitEthernet12/0/1:
|
||||||
|
mtu: 1500
|
||||||
|
mac: b4:96:91:b3:b1:11
|
||||||
|
state: down
|
||||||
|
description: Not Used
|
||||||
|
|
||||||
|
tap100:
|
||||||
|
mtu: 9000
|
||||||
|
l2xc: GigabitEthernet3/0/0.100
|
||||||
|
|
||||||
|
taps:
|
||||||
|
tap100:
|
||||||
|
host:
|
||||||
|
name: vpp-tap100
|
||||||
|
mac: 02:01:be:ef:ca:fe
|
||||||
|
mtu: 9000
|
@ -28,7 +28,7 @@ class Dumper(VPPApi):
|
|||||||
self.logger.info("Wrote YAML config to %s" % (outfile))
|
self.logger.info("Wrote YAML config to %s" % (outfile))
|
||||||
|
|
||||||
def cache_to_config(self):
|
def cache_to_config(self):
|
||||||
config = {"loopbacks": {}, "bondethernets": {}, "interfaces": {}, "bridgedomains": {}, "vxlan_tunnels": {} }
|
config = {"loopbacks": {}, "bondethernets": {}, "interfaces": {}, "bridgedomains": {}, "vxlan_tunnels": {}, "taps": {} }
|
||||||
for idx, bond_iface in self.cache['bondethernets'].items():
|
for idx, bond_iface in self.cache['bondethernets'].items():
|
||||||
bond = {"description": ""}
|
bond = {"description": ""}
|
||||||
if bond_iface.sw_if_index in self.cache['bondethernet_members']:
|
if bond_iface.sw_if_index in self.cache['bondethernet_members']:
|
||||||
@ -62,7 +62,7 @@ class Dumper(VPPApi):
|
|||||||
if len(self.cache['interface_addresses'][iface.sw_if_index]) > 0:
|
if len(self.cache['interface_addresses'][iface.sw_if_index]) > 0:
|
||||||
loop['addresses'] = self.cache['interface_addresses'][iface.sw_if_index]
|
loop['addresses'] = self.cache['interface_addresses'][iface.sw_if_index]
|
||||||
config['loopbacks'][iface.interface_name] = loop
|
config['loopbacks'][iface.interface_name] = loop
|
||||||
elif iface.interface_dev_type in ['bond', 'VXLAN', 'dpdk']:
|
elif iface.interface_dev_type in ['bond', 'VXLAN', 'dpdk', 'virtio']:
|
||||||
i = {"description": "" }
|
i = {"description": "" }
|
||||||
if iface.sw_if_index in self.cache['lcps']:
|
if iface.sw_if_index in self.cache['lcps']:
|
||||||
i['lcp'] = self.cache['lcps'][iface.sw_if_index].host_if_name
|
i['lcp'] = self.cache['lcps'][iface.sw_if_index].host_if_name
|
||||||
@ -77,6 +77,10 @@ class Dumper(VPPApi):
|
|||||||
|
|
||||||
if iface.interface_dev_type == 'dpdk':
|
if iface.interface_dev_type == 'dpdk':
|
||||||
i['mac'] = str(iface.l2_address)
|
i['mac'] = str(iface.l2_address)
|
||||||
|
|
||||||
|
if self.tap_is_lcp(iface.interface_name):
|
||||||
|
continue
|
||||||
|
|
||||||
i['mtu'] = iface.mtu[0]
|
i['mtu'] = iface.mtu[0]
|
||||||
if iface.sub_number_of_tags == 0:
|
if iface.sub_number_of_tags == 0:
|
||||||
config['interfaces'][iface.interface_name] = i
|
config['interfaces'][iface.interface_name] = i
|
||||||
@ -109,6 +113,25 @@ class Dumper(VPPApi):
|
|||||||
"remote": str(iface.dst_address) }
|
"remote": str(iface.dst_address) }
|
||||||
config['vxlan_tunnels'][vpp_iface.interface_name] = vxlan
|
config['vxlan_tunnels'][vpp_iface.interface_name] = vxlan
|
||||||
|
|
||||||
|
for idx, iface in self.cache['taps'].items():
|
||||||
|
vpp_tap = self.cache['taps'][iface.sw_if_index]
|
||||||
|
vpp_iface = self.cache['interfaces'][vpp_tap.sw_if_index]
|
||||||
|
|
||||||
|
tap = { "description": "",
|
||||||
|
"tx-ring-size": vpp_tap.tx_ring_sz,
|
||||||
|
"rx-ring-size": vpp_tap.rx_ring_sz,
|
||||||
|
"host": {
|
||||||
|
"mac": str(vpp_tap.host_mac_addr),
|
||||||
|
"name": vpp_tap.host_if_name,
|
||||||
|
} }
|
||||||
|
if vpp_tap.host_mtu_size > 0:
|
||||||
|
tap['host']['mtu'] = vpp_tap.host_mtu_size
|
||||||
|
if vpp_tap.host_namespace:
|
||||||
|
tap['host']['namespace'] = vpp_tap.host_namespace
|
||||||
|
if vpp_tap.host_bridge:
|
||||||
|
tap['host']['bridge'] = vpp_tap.host_bridge
|
||||||
|
config['taps'][vpp_iface.interface_name] = tap
|
||||||
|
|
||||||
for idx, iface in self.cache['bridgedomains'].items():
|
for idx, iface in self.cache['bridgedomains'].items():
|
||||||
# self.logger.info("%d: %s" % (idx, iface))
|
# self.logger.info("%d: %s" % (idx, iface))
|
||||||
bridge_name = "bd%d" % idx
|
bridge_name = "bd%d" % idx
|
||||||
|
@ -21,6 +21,7 @@ import config.bondethernet as bondethernet
|
|||||||
import config.bridgedomain as bridgedomain
|
import config.bridgedomain as bridgedomain
|
||||||
import config.vxlan_tunnel as vxlan_tunnel
|
import config.vxlan_tunnel as vxlan_tunnel
|
||||||
import config.lcp as lcp
|
import config.lcp as lcp
|
||||||
|
import config.tap as tap
|
||||||
from vpp.vppapi import VPPApi
|
from vpp.vppapi import VPPApi
|
||||||
|
|
||||||
class Reconciler():
|
class Reconciler():
|
||||||
@ -95,6 +96,9 @@ class Reconciler():
|
|||||||
if not self.prune_sub_interfaces():
|
if not self.prune_sub_interfaces():
|
||||||
self.logger.warning("Could not prune Sub Interfaces from VPP")
|
self.logger.warning("Could not prune Sub Interfaces from VPP")
|
||||||
ret = False
|
ret = False
|
||||||
|
if not self.prune_taps():
|
||||||
|
self.logger.warning("Could not prune TAPs from VPP")
|
||||||
|
ret = False
|
||||||
if not self.prune_vxlan_tunnels():
|
if not self.prune_vxlan_tunnels():
|
||||||
self.logger.warning("Could not prune VXLAN Tunnels from VPP")
|
self.logger.warning("Could not prune VXLAN Tunnels from VPP")
|
||||||
ret = False
|
ret = False
|
||||||
@ -236,6 +240,41 @@ class Reconciler():
|
|||||||
self.vpp.cache_remove_l2xc(l2xc)
|
self.vpp.cache_remove_l2xc(l2xc)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def __tap_has_diff(self, ifname):
|
||||||
|
""" Returns True if the given ifname (tap0) has different attributes between VPP
|
||||||
|
and the given configuration, or if either does not exist.
|
||||||
|
|
||||||
|
Returns False if the TAP is a Linux Control Plane LIP.
|
||||||
|
Returns False if they are identical."""
|
||||||
|
if not ifname in self.vpp.cache['interface_names']:
|
||||||
|
return True
|
||||||
|
vpp_iface = self.vpp.cache['interface_names'][ifname]
|
||||||
|
vpp_tap = self.vpp.cache['taps'][vpp_iface.sw_if_index]
|
||||||
|
|
||||||
|
config_ifname, config_iface = tap.get_by_name(self.cfg, ifname)
|
||||||
|
if not config_iface:
|
||||||
|
return True
|
||||||
|
|
||||||
|
if self.vpp.tap_is_lcp(ifname):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if 'name' in config_iface['host'] and config_iface['host']['name'] != vpp_tap.host_if_name:
|
||||||
|
self.logger.info("TAP diff: hostname")
|
||||||
|
return True
|
||||||
|
if 'mtu' in config_iface['host'] and config_iface['host']['mtu'] != vpp_tap.host_mtu_size:
|
||||||
|
return True
|
||||||
|
if 'mac' in config_iface['host'] and config_iface['host']['mac'] != str(vpp_tap.host_mac_addr):
|
||||||
|
self.logger.info("TAP diff: mac")
|
||||||
|
return True
|
||||||
|
if 'bridge' in config_iface['host'] and config_iface['host']['bridge'] != vpp_tap.host_bridge:
|
||||||
|
self.logger.info("TAP diff: bridge")
|
||||||
|
return True
|
||||||
|
if 'namespace' in config_iface['host'] and config_iface['host']['namespace'] != vpp_tap.host_namespace:
|
||||||
|
self.logger.info("TAP diff: namespace")
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
def __bond_has_diff(self, ifname):
|
def __bond_has_diff(self, ifname):
|
||||||
""" Returns True if the given ifname (BondEthernet0) have different attributes,
|
""" Returns True if the given ifname (BondEthernet0) have different attributes,
|
||||||
or if either does not exist.
|
or if either does not exist.
|
||||||
@ -263,6 +302,28 @@ class Reconciler():
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def prune_taps(self):
|
||||||
|
""" Remove all TAPs from VPP, if they are not in the config. As an exception,
|
||||||
|
TAPs which are a part of Linux Control Plane, are left alone, to be handled
|
||||||
|
by prune_lcps() later. """
|
||||||
|
removed_taps = []
|
||||||
|
for idx, vpp_tap in self.vpp.cache['taps'].items():
|
||||||
|
vpp_iface = self.vpp.cache['interfaces'][vpp_tap.sw_if_index]
|
||||||
|
vpp_ifname = vpp_iface.interface_name
|
||||||
|
if self.vpp.tap_is_lcp(vpp_ifname):
|
||||||
|
continue
|
||||||
|
if self.__tap_has_diff(vpp_ifname):
|
||||||
|
removed_taps.append(vpp_ifname)
|
||||||
|
continue
|
||||||
|
self.logger.debug("TAP OK: %s" % (vpp_ifname))
|
||||||
|
|
||||||
|
for ifname in removed_taps:
|
||||||
|
cli = "delete tap %s" % ifname
|
||||||
|
self.cli['prune'].append(cli)
|
||||||
|
self.vpp.cache_remove_tap(ifname)
|
||||||
|
self.vpp.cache_remove_interface(ifname)
|
||||||
|
return True
|
||||||
|
|
||||||
def prune_bondethernets(self):
|
def prune_bondethernets(self):
|
||||||
""" Remove all BondEthernets from VPP, if they are not in the config. If the bond has members,
|
""" Remove all BondEthernets from VPP, if they are not in the config. If the bond has members,
|
||||||
remove those from the bond before removing the bond. """
|
remove those from the bond before removing the bond. """
|
||||||
@ -338,22 +399,6 @@ class Reconciler():
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def __tap_is_lcp(self, sw_if_index):
|
|
||||||
""" Returns True if the given sw_if_index is a TAP interface belonging to an LCP,
|
|
||||||
or False otherwise."""
|
|
||||||
if not sw_if_index in self.vpp.cache['interfaces']:
|
|
||||||
return False
|
|
||||||
|
|
||||||
vpp_iface = self.vpp.cache['interfaces'][sw_if_index]
|
|
||||||
if not vpp_iface.interface_dev_type=="virtio":
|
|
||||||
return False
|
|
||||||
|
|
||||||
match = False
|
|
||||||
for idx, lcp in self.vpp.cache['lcps'].items():
|
|
||||||
if vpp_iface.sw_if_index == lcp.host_sw_if_index:
|
|
||||||
match = True
|
|
||||||
return match
|
|
||||||
|
|
||||||
def prune_sub_interfaces(self):
|
def prune_sub_interfaces(self):
|
||||||
""" Remove interfaces from VPP if they are not in the config, if their encapsulation is different,
|
""" Remove interfaces from VPP if they are not in the config, if their encapsulation is different,
|
||||||
or if the BondEthernet they reside on is different.
|
or if the BondEthernet they reside on is different.
|
||||||
@ -365,7 +410,7 @@ class Reconciler():
|
|||||||
if vpp_iface.sub_number_of_tags != numtags:
|
if vpp_iface.sub_number_of_tags != numtags:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if self.__tap_is_lcp(vpp_iface.sw_if_index):
|
if self.vpp.tap_is_lcp(vpp_ifname):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
prune=False
|
prune=False
|
||||||
@ -573,7 +618,7 @@ class Reconciler():
|
|||||||
if not ifname in interface.get_interfaces(self.cfg) + loopback.get_loopbacks(self.cfg):
|
if not ifname in interface.get_interfaces(self.cfg) + loopback.get_loopbacks(self.cfg):
|
||||||
vpp_iface = self.vpp.cache['interface_names'][ifname]
|
vpp_iface = self.vpp.cache['interface_names'][ifname]
|
||||||
|
|
||||||
if self.__tap_is_lcp(vpp_iface.sw_if_index):
|
if self.vpp.tap_is_lcp(ifname):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if vpp_iface.flags & 1: # IF_STATUS_API_FLAG_ADMIN_UP
|
if vpp_iface.flags & 1: # IF_STATUS_API_FLAG_ADMIN_UP
|
||||||
@ -596,6 +641,9 @@ class Reconciler():
|
|||||||
if not self.create_vxlan_tunnels():
|
if not self.create_vxlan_tunnels():
|
||||||
self.logger.warning("Could not create VXLAN Tunnels in VPP")
|
self.logger.warning("Could not create VXLAN Tunnels in VPP")
|
||||||
ret = False
|
ret = False
|
||||||
|
if not self.create_taps():
|
||||||
|
self.logger.warning("Could not create TAPs in VPP")
|
||||||
|
ret = False
|
||||||
if not self.create_sub_interfaces():
|
if not self.create_sub_interfaces():
|
||||||
self.logger.warning("Could not create Sub Interfaces in VPP")
|
self.logger.warning("Could not create Sub Interfaces in VPP")
|
||||||
ret = False
|
ret = False
|
||||||
@ -672,6 +720,29 @@ class Reconciler():
|
|||||||
self.cli['create'].append(cli);
|
self.cli['create'].append(cli);
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def create_taps(self):
|
||||||
|
for ifname in tap.get_taps(self.cfg):
|
||||||
|
ifname, iface = tap.get_by_name(self.cfg, ifname)
|
||||||
|
if ifname in self.vpp.cache['interface_names']:
|
||||||
|
continue
|
||||||
|
instance=int(ifname[3:])
|
||||||
|
cli="create tap id %d host-if-name %s" % (instance, iface['host']['name'])
|
||||||
|
if 'mac' in iface['host']:
|
||||||
|
cli+=" host-mac-addr %s" % iface['host']['mac']
|
||||||
|
if 'namespace' in iface['host']:
|
||||||
|
cli+=" host-ns %d" % iface['host']['namespace']
|
||||||
|
if 'bridge' in iface['host']:
|
||||||
|
cli+=" host-bridge %s" % iface['host']['bridge']
|
||||||
|
if 'mtu' in iface['host']:
|
||||||
|
cli+=" host-mtu-size %d" % iface['host']['mtu']
|
||||||
|
if 'rx-ring-size' in iface:
|
||||||
|
cli+=" rx-ring-size %d" % iface['rx-ring-size']
|
||||||
|
if 'tx-ring-size' in iface:
|
||||||
|
cli+=" tx-ring-size %d" % iface['tx-ring-size']
|
||||||
|
self.cli['create'].append(cli)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
def create_bridgedomains(self):
|
def create_bridgedomains(self):
|
||||||
for ifname in bridgedomain.get_bridgedomains(self.cfg):
|
for ifname in bridgedomain.get_bridgedomains(self.cfg):
|
||||||
ifname, iface = bridgedomain.get_by_name(self.cfg, ifname)
|
ifname, iface = bridgedomain.get_by_name(self.cfg, ifname)
|
||||||
|
@ -66,7 +66,7 @@ class VPPApi():
|
|||||||
self.cache_read = False
|
self.cache_read = False
|
||||||
return {"lcps": {}, "interface_names": {}, "interfaces": {}, "interface_addresses": {},
|
return {"lcps": {}, "interface_names": {}, "interfaces": {}, "interface_addresses": {},
|
||||||
"bondethernets": {}, "bondethernet_members": {},
|
"bondethernets": {}, "bondethernet_members": {},
|
||||||
"bridgedomains": {}, "vxlan_tunnels": {}, "l2xcs": {}}
|
"bridgedomains": {}, "vxlan_tunnels": {}, "l2xcs": {}, "taps": {}}
|
||||||
|
|
||||||
def cache_remove_lcp(self, lcpname):
|
def cache_remove_lcp(self, lcpname):
|
||||||
""" Removes the LCP and TAP interface, identified by lcpname, from the config. """
|
""" Removes the LCP and TAP interface, identified by lcpname, from the config. """
|
||||||
@ -79,11 +79,10 @@ class VPPApi():
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
ifname = self.cache['interfaces'][lcp.host_sw_if_index].interface_name
|
ifname = self.cache['interfaces'][lcp.host_sw_if_index].interface_name
|
||||||
del self.cache['interface_names'][ifname]
|
|
||||||
del self.cache['interface_addresses'][lcp.host_sw_if_index]
|
|
||||||
del self.cache['interfaces'][lcp.host_sw_if_index]
|
|
||||||
del self.cache['lcps'][lcp.phy_sw_if_index]
|
del self.cache['lcps'][lcp.phy_sw_if_index]
|
||||||
return True
|
|
||||||
|
# Remove the TAP interface and its dependencies
|
||||||
|
return self.cache_remove_interface(ifname)
|
||||||
|
|
||||||
def cache_remove_bondethernet_member(self, ifname):
|
def cache_remove_bondethernet_member(self, ifname):
|
||||||
""" Removes the bonderthernet member interface, identified by name, from the config. """
|
""" Removes the bonderthernet member interface, identified by name, from the config. """
|
||||||
@ -106,6 +105,15 @@ class VPPApi():
|
|||||||
self.cache['l2xcs'].pop(iface.sw_if_index, None)
|
self.cache['l2xcs'].pop(iface.sw_if_index, None)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def cache_remove_tap(self, ifname):
|
||||||
|
if not ifname in self.cache['interface_names']:
|
||||||
|
self.logger.warning("Trying to remove a TAP which is not in the config: %s" % ifname)
|
||||||
|
return False
|
||||||
|
|
||||||
|
iface = self.cache['interface_names'][ifname]
|
||||||
|
self.cache['taps'].pop(iface.sw_if_index, None)
|
||||||
|
return True
|
||||||
|
|
||||||
def cache_remove_vxlan_tunnel(self, ifname):
|
def cache_remove_vxlan_tunnel(self, ifname):
|
||||||
if not ifname in self.cache['interface_names']:
|
if not ifname in self.cache['interface_names']:
|
||||||
self.logger.warning("Trying to remove a VXLAN Tunnel which is not in the config: %s" % ifname)
|
self.logger.warning("Trying to remove a VXLAN Tunnel which is not in the config: %s" % ifname)
|
||||||
@ -135,6 +143,8 @@ class VPPApi():
|
|||||||
else:
|
else:
|
||||||
del self.cache['bondethernet_members'][iface.sw_if_index]
|
del self.cache['bondethernet_members'][iface.sw_if_index]
|
||||||
self.cache['bondethernets'].pop(iface.sw_if_index, None)
|
self.cache['bondethernets'].pop(iface.sw_if_index, None)
|
||||||
|
|
||||||
|
self.cache['taps'].pop(iface.sw_if_index, None)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def readconfig(self):
|
def readconfig(self):
|
||||||
@ -201,6 +211,11 @@ class VPPApi():
|
|||||||
for l2xc in r:
|
for l2xc in r:
|
||||||
self.cache['l2xcs'][l2xc.rx_sw_if_index] = l2xc
|
self.cache['l2xcs'][l2xc.rx_sw_if_index] = l2xc
|
||||||
|
|
||||||
|
self.logger.debug("Retrieving TAPs")
|
||||||
|
r = self.vpp.api.sw_interface_tap_v2_dump()
|
||||||
|
for tap in r:
|
||||||
|
self.cache['taps'][tap.sw_if_index] = tap
|
||||||
|
|
||||||
self.cache_read = True
|
self.cache_read = True
|
||||||
return self.cache_read
|
return self.cache_read
|
||||||
|
|
||||||
@ -247,3 +262,18 @@ class VPPApi():
|
|||||||
if lcp.phy_sw_if_index == sw_if_index:
|
if lcp.phy_sw_if_index == sw_if_index:
|
||||||
return lcp
|
return lcp
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def tap_is_lcp(self, tap_ifname):
|
||||||
|
""" Returns True if the given tap_ifname is a TAP interface belonging to an LCP,
|
||||||
|
or False otherwise."""
|
||||||
|
if not tap_ifname in self.cache['interface_names']:
|
||||||
|
return False
|
||||||
|
|
||||||
|
vpp_iface = self.cache['interface_names'][tap_ifname]
|
||||||
|
if not vpp_iface.interface_dev_type=="virtio":
|
||||||
|
return False
|
||||||
|
|
||||||
|
for idx, lcp in self.cache['lcps'].items():
|
||||||
|
if vpp_iface.sw_if_index == lcp.host_sw_if_index:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
Reference in New Issue
Block a user