Implement pruning in config as well
After pruning elements from the VPP configuration, also remove them from the configuration. The purpose of this is to leave a reasonable representation of the VPP state in the configuration, so that subsequent creates and syncs do not have to query the VPP API repeatedly. The goal of this change is to be able to plan a complete path from prune, create and sync, with only reading the initial VPP configuration once, not multiple times.
This commit is contained in:
@ -78,6 +78,24 @@ class Reconciler():
|
|||||||
if not self.prune_phys():
|
if not self.prune_phys():
|
||||||
self.logger.warning("Could not prune PHYs from VPP")
|
self.logger.warning("Could not prune PHYs from VPP")
|
||||||
ret = False
|
ret = False
|
||||||
|
|
||||||
|
## Report on what is left in the configuration after pruning.
|
||||||
|
self.logger.debug("After pruning, the following config is left:")
|
||||||
|
for idx, lcp in self.vpp.config['lcps'].items():
|
||||||
|
self.logger.debug("LCP[%d]: %s" % (idx, lcp))
|
||||||
|
for ifname, iface in self.vpp.config['interface_names'].items():
|
||||||
|
self.logger.debug("Interface[%s]: %s" % (ifname, iface))
|
||||||
|
for idx, iface in self.vpp.config['interfaces'].items():
|
||||||
|
self.logger.debug("Interface[%d]: %s" % (idx, iface))
|
||||||
|
for idx, iface in self.vpp.config['bondethernets'].items():
|
||||||
|
self.logger.debug("bondethernets[%d]: %s" % (idx, iface))
|
||||||
|
for idx, iface in self.vpp.config['bondethernet_members'].items():
|
||||||
|
self.logger.debug("bondethernet_members[%d]: %s" % (idx, iface))
|
||||||
|
for idx, iface in self.vpp.config['vxlan_tunnels'].items():
|
||||||
|
self.logger.debug("vxlan_tunnels[%d]: %s" % (idx, iface))
|
||||||
|
for idx, iface in self.vpp.config['l2xcs'].items():
|
||||||
|
self.logger.debug("l2xcs[%d]: %s" % (idx, iface))
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def prune_addresses(self, ifname, address_list):
|
def prune_addresses(self, ifname, address_list):
|
||||||
@ -85,14 +103,19 @@ class Reconciler():
|
|||||||
which may be an empty list, in which case all addresses are removed.
|
which may be an empty list, in which case all addresses are removed.
|
||||||
"""
|
"""
|
||||||
idx = self.vpp.config['interface_names'][ifname].sw_if_index
|
idx = self.vpp.config['interface_names'][ifname].sw_if_index
|
||||||
|
removed_addresses = []
|
||||||
for a in self.vpp.config['interface_addresses'][idx]:
|
for a in self.vpp.config['interface_addresses'][idx]:
|
||||||
if not a in address_list:
|
if not a in address_list:
|
||||||
self.logger.info("1> set interface ip address del %s %s" % (ifname, a))
|
self.logger.info("1> set interface ip address del %s %s" % (ifname, a))
|
||||||
|
removed_addresses.append(a)
|
||||||
else:
|
else:
|
||||||
self.logger.debug("Address OK: %s %s" % (ifname, a))
|
self.logger.debug("Address OK: %s %s" % (ifname, a))
|
||||||
|
for a in removed_addresses:
|
||||||
|
self.vpp.config['interface_addresses'][idx].remove(a)
|
||||||
|
|
||||||
def prune_loopbacks(self):
|
def prune_loopbacks(self):
|
||||||
""" Remove loopbacks from VPP, if they do not occur in the config. """
|
""" Remove loopbacks from VPP, if they do not occur in the config. """
|
||||||
|
removed_interfaces=[]
|
||||||
for numtags in [ 2, 1, 0 ]:
|
for numtags in [ 2, 1, 0 ]:
|
||||||
for idx, vpp_iface in self.vpp.config['interfaces'].items():
|
for idx, vpp_iface in self.vpp.config['interfaces'].items():
|
||||||
if vpp_iface.interface_dev_type!='Loopback':
|
if vpp_iface.interface_dev_type!='Loopback':
|
||||||
@ -104,18 +127,25 @@ class Reconciler():
|
|||||||
self.prune_addresses(vpp_iface.interface_name, [])
|
self.prune_addresses(vpp_iface.interface_name, [])
|
||||||
if numtags == 0:
|
if numtags == 0:
|
||||||
self.logger.info("1> delete loopback interface intfc %s" % vpp_iface.interface_name)
|
self.logger.info("1> delete loopback interface intfc %s" % vpp_iface.interface_name)
|
||||||
|
removed_interfaces.append(vpp_iface.interface_name)
|
||||||
else:
|
else:
|
||||||
self.logger.info("1> delete sub %s" % vpp_iface.interface_name)
|
self.logger.info("1> delete sub %s" % vpp_iface.interface_name)
|
||||||
|
removed_interfaces.append(vpp_iface.interface_name)
|
||||||
continue
|
continue
|
||||||
self.logger.debug("Loopback OK: %s" % (vpp_iface.interface_name))
|
self.logger.debug("Loopback OK: %s" % (vpp_iface.interface_name))
|
||||||
addresses = []
|
addresses = []
|
||||||
if 'addresses' in config_iface:
|
if 'addresses' in config_iface:
|
||||||
addresses = config_iface['addresses']
|
addresses = config_iface['addresses']
|
||||||
self.prune_addresses(vpp_iface.interface_name, addresses)
|
self.prune_addresses(vpp_iface.interface_name, addresses)
|
||||||
|
|
||||||
|
for ifname in removed_interfaces:
|
||||||
|
self.vpp.remove_interface(ifname)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def prune_bvis(self):
|
def prune_bvis(self):
|
||||||
""" Remove BVIs (bridge-domain virtual interfaces) from VPP, if they do not occur in the config. """
|
""" Remove BVIs (bridge-domain virtual interfaces) from VPP, if they do not occur in the config. """
|
||||||
|
removed_interfaces=[]
|
||||||
for numtags in [ 2, 1, 0 ]:
|
for numtags in [ 2, 1, 0 ]:
|
||||||
for idx, vpp_iface in self.vpp.config['interfaces'].items():
|
for idx, vpp_iface in self.vpp.config['interfaces'].items():
|
||||||
if vpp_iface.interface_dev_type!='BVI':
|
if vpp_iface.interface_dev_type!='BVI':
|
||||||
@ -127,16 +157,23 @@ class Reconciler():
|
|||||||
self.prune_addresses(vpp_iface.interface_name, [])
|
self.prune_addresses(vpp_iface.interface_name, [])
|
||||||
if numtags == 0:
|
if numtags == 0:
|
||||||
self.logger.info("1> bvi delete %s" % vpp_iface.interface_name)
|
self.logger.info("1> bvi delete %s" % vpp_iface.interface_name)
|
||||||
|
removed_interfaces.append(vpp_iface.interface_name)
|
||||||
else:
|
else:
|
||||||
self.logger.info("1> delete sub %s" % vpp_iface.interface_name)
|
self.logger.info("1> delete sub %s" % vpp_iface.interface_name)
|
||||||
|
removed_interfaces.append(vpp_iface.interface_name)
|
||||||
continue
|
continue
|
||||||
self.logger.debug("BVI OK: %s" % (vpp_iface.interface_name))
|
self.logger.debug("BVI OK: %s" % (vpp_iface.interface_name))
|
||||||
addresses = []
|
addresses = []
|
||||||
if 'addresses' in config_iface:
|
if 'addresses' in config_iface:
|
||||||
addresses = config_iface['addresses']
|
addresses = config_iface['addresses']
|
||||||
self.prune_addresses(vpp_iface.interface_name, addresses)
|
self.prune_addresses(vpp_iface.interface_name, addresses)
|
||||||
|
|
||||||
|
for ifname in removed_interfaces:
|
||||||
|
self.vpp.remove_interface(ifname)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def prune_bridgedomains(self):
|
def prune_bridgedomains(self):
|
||||||
""" Remove bridge-domains from VPP, if they do not occur in the config. If any interfaces are
|
""" Remove bridge-domains from VPP, if they do not occur in the config. If any interfaces are
|
||||||
found in to-be removed bridge-domains, they are returned to L3 mode, and tag-rewrites removed. """
|
found in to-be removed bridge-domains, they are returned to L3 mode, and tag-rewrites removed. """
|
||||||
@ -166,6 +203,7 @@ class Reconciler():
|
|||||||
""" Remove all L2XC source interfaces from VPP, if they do not occur in the config. If they occur,
|
""" Remove all L2XC source interfaces from VPP, if they do not occur in the config. If they occur,
|
||||||
but are crossconnected to a different interface name, also remove them. Interfaces are put
|
but are crossconnected to a different interface name, also remove them. Interfaces are put
|
||||||
back into L3 mode, and their tag-rewrites removed. """
|
back into L3 mode, and their tag-rewrites removed. """
|
||||||
|
removed_l2xcs=[]
|
||||||
for idx, l2xc in self.vpp.config['l2xcs'].items():
|
for idx, l2xc in self.vpp.config['l2xcs'].items():
|
||||||
vpp_rx_ifname = self.vpp.config['interfaces'][l2xc.rx_sw_if_index].interface_name
|
vpp_rx_ifname = self.vpp.config['interfaces'][l2xc.rx_sw_if_index].interface_name
|
||||||
config_rx_ifname, config_rx_iface = interface.get_by_name(self.cfg, vpp_rx_ifname)
|
config_rx_ifname, config_rx_iface = interface.get_by_name(self.cfg, vpp_rx_ifname)
|
||||||
@ -173,69 +211,96 @@ class Reconciler():
|
|||||||
if self.vpp.config['interfaces'][l2xc.rx_sw_if_index].sub_id > 0:
|
if self.vpp.config['interfaces'][l2xc.rx_sw_if_index].sub_id > 0:
|
||||||
self.logger.info("1> set interface l2 tag-rewrite %s disable" % vpp_rx_ifname)
|
self.logger.info("1> set interface l2 tag-rewrite %s disable" % vpp_rx_ifname)
|
||||||
self.logger.info("1> set interface l3 %s" % vpp_rx_ifname)
|
self.logger.info("1> set interface l3 %s" % vpp_rx_ifname)
|
||||||
|
removed_l2xcs.append(vpp_rx_ifname)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if not interface.is_l2xc_interface(self.cfg, config_rx_ifname):
|
if not interface.is_l2xc_interface(self.cfg, config_rx_ifname):
|
||||||
if interface.is_sub(self.cfg, config_rx_ifname):
|
if interface.is_sub(self.cfg, config_rx_ifname):
|
||||||
self.logger.info("2> set interface l2 tag-rewrite %s disable" % vpp_rx_ifname)
|
self.logger.info("2> set interface l2 tag-rewrite %s disable" % vpp_rx_ifname)
|
||||||
self.logger.info("2> set interface l3 %s" % vpp_rx_ifname)
|
self.logger.info("2> set interface l3 %s" % vpp_rx_ifname)
|
||||||
|
removed_l2xcs.append(vpp_rx_ifname)
|
||||||
continue
|
continue
|
||||||
vpp_tx_ifname = self.vpp.config['interfaces'][l2xc.tx_sw_if_index].interface_name
|
vpp_tx_ifname = self.vpp.config['interfaces'][l2xc.tx_sw_if_index].interface_name
|
||||||
if vpp_tx_ifname != config_rx_iface['l2xc']:
|
if vpp_tx_ifname != config_rx_iface['l2xc']:
|
||||||
if interface.is_sub(self.cfg, config_rx_ifname):
|
if interface.is_sub(self.cfg, config_rx_ifname):
|
||||||
self.logger.info("3> set interface l2 tag-rewrite %s disable" % vpp_rx_ifname)
|
self.logger.info("3> set interface l2 tag-rewrite %s disable" % vpp_rx_ifname)
|
||||||
self.logger.info("3> set interface l3 %s" % vpp_rx_ifname)
|
self.logger.info("3> set interface l3 %s" % vpp_rx_ifname)
|
||||||
|
removed_l2xcs.append(vpp_rx_ifname)
|
||||||
continue
|
continue
|
||||||
self.logger.debug("L2XC OK: %s -> %s" % (vpp_rx_ifname, vpp_tx_ifname))
|
self.logger.debug("L2XC OK: %s -> %s" % (vpp_rx_ifname, vpp_tx_ifname))
|
||||||
|
for l2xc in removed_l2xcs:
|
||||||
|
self.vpp.remove_l2xc(l2xc)
|
||||||
return True
|
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. """
|
||||||
|
removed_interfaces=[]
|
||||||
|
removed_bondethernet_members=[]
|
||||||
for idx, bond in self.vpp.config['bondethernets'].items():
|
for idx, bond in self.vpp.config['bondethernets'].items():
|
||||||
vpp_ifname = bond.interface_name
|
vpp_ifname = bond.interface_name
|
||||||
config_ifname, config_iface = bondethernet.get_by_name(self.cfg, vpp_ifname)
|
config_ifname, config_iface = bondethernet.get_by_name(self.cfg, vpp_ifname)
|
||||||
if not config_iface:
|
if not config_iface:
|
||||||
self.prune_addresses(vpp_ifname, [])
|
self.prune_addresses(vpp_ifname, [])
|
||||||
for member in self.vpp.config['bondethernet_members'][idx]:
|
for member in self.vpp.config['bondethernet_members'][idx]:
|
||||||
self.logger.info("1> bond del %s" % self.vpp.config['interfaces'][member].interface_name)
|
member_ifname = self.vpp.config['interfaces'][member].interface_name
|
||||||
|
self.logger.info("1> bond del %s" % member_ifname)
|
||||||
|
removed_bondethernet_members.append(member_ifname)
|
||||||
self.logger.info("1> delete bond %s" % (vpp_ifname))
|
self.logger.info("1> delete bond %s" % (vpp_ifname))
|
||||||
|
removed_interfaces.append(vpp_ifname)
|
||||||
continue
|
continue
|
||||||
for member in self.vpp.config['bondethernet_members'][idx]:
|
for member in self.vpp.config['bondethernet_members'][idx]:
|
||||||
member_ifname = self.vpp.config['interfaces'][member].interface_name
|
member_ifname = self.vpp.config['interfaces'][member].interface_name
|
||||||
if 'interfaces' in config_iface and not member_ifname in config_iface['interfaces']:
|
if 'interfaces' in config_iface and not member_ifname in config_iface['interfaces']:
|
||||||
self.logger.info("2> bond del %s" % member_ifname)
|
self.logger.info("2> bond del %s" % member_ifname)
|
||||||
|
removed_bondethernet_members.append(member_ifname)
|
||||||
addresses = []
|
addresses = []
|
||||||
if 'addresses' in config_iface:
|
if 'addresses' in config_iface:
|
||||||
addresses = config_iface['addresses']
|
addresses = config_iface['addresses']
|
||||||
self.prune_addresses(vpp_ifname, addresses)
|
self.prune_addresses(vpp_ifname, addresses)
|
||||||
self.logger.debug("BondEthernet OK: %s" % (vpp_ifname))
|
self.logger.debug("BondEthernet OK: %s" % (vpp_ifname))
|
||||||
|
|
||||||
|
for ifname in removed_bondethernet_members:
|
||||||
|
self.vpp.remove_bondethernet_member(ifname)
|
||||||
|
|
||||||
|
for ifname in removed_interfaces:
|
||||||
|
self.vpp.remove_interface(ifname)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def prune_vxlan_tunnels(self):
|
def prune_vxlan_tunnels(self):
|
||||||
""" Remove all VXLAN Tunnels from VPP, if they are not in the config. If they are in the config
|
""" Remove all VXLAN Tunnels from VPP, if they are not in the config. If they are in the config
|
||||||
but with differing attributes, remove them also. """
|
but with differing attributes, remove them also. """
|
||||||
|
removed_interfaces=[]
|
||||||
for idx, vpp_vxlan in self.vpp.config['vxlan_tunnels'].items():
|
for idx, vpp_vxlan in self.vpp.config['vxlan_tunnels'].items():
|
||||||
vpp_ifname = self.vpp.config['interfaces'][idx].interface_name
|
vpp_ifname = self.vpp.config['interfaces'][idx].interface_name
|
||||||
config_ifname, config_iface = vxlan_tunnel.get_by_name(self.cfg, vpp_ifname)
|
config_ifname, config_iface = vxlan_tunnel.get_by_name(self.cfg, vpp_ifname)
|
||||||
if not config_iface:
|
if not config_iface:
|
||||||
self.logger.info("1> create vxlan tunnel instance %d src %s dst %s vni %d del" % (vpp_vxlan.instance,
|
self.logger.info("1> create vxlan tunnel instance %d src %s dst %s vni %d del" % (vpp_vxlan.instance,
|
||||||
vpp_vxlan.src_address, vpp_vxlan.dst_address, vpp_vxlan.vni))
|
vpp_vxlan.src_address, vpp_vxlan.dst_address, vpp_vxlan.vni))
|
||||||
|
removed_interfaces.append(vpp_ifname)
|
||||||
continue
|
continue
|
||||||
if config_iface['local'] != str(vpp_vxlan.src_address) or config_iface['remote'] != str(vpp_vxlan.dst_address) or config_iface['vni'] != vpp_vxlan.vni:
|
if config_iface['local'] != str(vpp_vxlan.src_address) or config_iface['remote'] != str(vpp_vxlan.dst_address) or config_iface['vni'] != vpp_vxlan.vni:
|
||||||
self.logger.info("2> create vxlan tunnel instance %d src %s dst %s vni %d del" % (vpp_vxlan.instance,
|
self.logger.info("2> create vxlan tunnel instance %d src %s dst %s vni %d del" % (vpp_vxlan.instance,
|
||||||
vpp_vxlan.src_address, vpp_vxlan.dst_address, vpp_vxlan.vni))
|
vpp_vxlan.src_address, vpp_vxlan.dst_address, vpp_vxlan.vni))
|
||||||
|
removed_interfaces.append(vpp_ifname)
|
||||||
continue
|
continue
|
||||||
addresses = []
|
addresses = []
|
||||||
if 'addresses' in config_iface:
|
if 'addresses' in config_iface:
|
||||||
addresses = config_iface['addresses']
|
addresses = config_iface['addresses']
|
||||||
self.prune_addresses(vpp_ifname, addresses)
|
self.prune_addresses(vpp_ifname, addresses)
|
||||||
self.logger.debug("VXLAN Tunnel OK: %s" % (vpp_ifname))
|
self.logger.debug("VXLAN Tunnel OK: %s" % (vpp_ifname))
|
||||||
|
|
||||||
|
for ifname in removed_interfaces:
|
||||||
|
self.vpp.remove_vxlan_tunnel(ifname)
|
||||||
|
self.vpp.remove_interface(ifname)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def prune_sub_interfaces(self):
|
def prune_sub_interfaces(self):
|
||||||
""" Remove interfaces from VPP if they are not in the config. Start with inner-most (QinQ/QinAD), then
|
""" Remove interfaces from VPP if they are not in the config. Start with inner-most (QinQ/QinAD), then
|
||||||
Dot1Q/Dot1AD."""
|
Dot1Q/Dot1AD."""
|
||||||
|
removed_interfaces=[]
|
||||||
for numtags in [ 2, 1 ]:
|
for numtags in [ 2, 1 ]:
|
||||||
for vpp_ifname in self.vpp.get_sub_interfaces():
|
for vpp_ifname in self.vpp.get_sub_interfaces():
|
||||||
vpp_iface = self.vpp.config['interface_names'][vpp_ifname]
|
vpp_iface = self.vpp.config['interface_names'][vpp_ifname]
|
||||||
@ -245,12 +310,17 @@ class Reconciler():
|
|||||||
if not config_iface:
|
if not config_iface:
|
||||||
self.prune_addresses(vpp_ifname, [])
|
self.prune_addresses(vpp_ifname, [])
|
||||||
self.logger.info("1> delete sub %s" % vpp_ifname)
|
self.logger.info("1> delete sub %s" % vpp_ifname)
|
||||||
|
removed_interfaces.append(vpp_ifname)
|
||||||
continue
|
continue
|
||||||
addresses = []
|
addresses = []
|
||||||
if 'addresses' in config_iface:
|
if 'addresses' in config_iface:
|
||||||
addresses = config_iface['addresses']
|
addresses = config_iface['addresses']
|
||||||
self.prune_addresses(vpp_ifname, addresses)
|
self.prune_addresses(vpp_ifname, addresses)
|
||||||
self.logger.debug("Sub Interface OK: %s" % (vpp_ifname))
|
self.logger.debug("Sub Interface OK: %s" % (vpp_ifname))
|
||||||
|
|
||||||
|
for ifname in removed_interfaces:
|
||||||
|
self.vpp.remove_interface(ifname)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def prune_phys(self):
|
def prune_phys(self):
|
||||||
@ -316,6 +386,7 @@ class Reconciler():
|
|||||||
"""
|
"""
|
||||||
lcps = self.vpp.config['lcps']
|
lcps = self.vpp.config['lcps']
|
||||||
|
|
||||||
|
removed_lcps = []
|
||||||
## Remove LCPs for QinX interfaces
|
## Remove LCPs for QinX interfaces
|
||||||
for idx, lcp in lcps.items():
|
for idx, lcp in lcps.items():
|
||||||
vpp_iface = self.vpp.config['interfaces'][lcp.phy_sw_if_index]
|
vpp_iface = self.vpp.config['interfaces'][lcp.phy_sw_if_index]
|
||||||
@ -325,10 +396,12 @@ class Reconciler():
|
|||||||
if not config_iface:
|
if not config_iface:
|
||||||
## QinX doesn't exist in the config
|
## QinX doesn't exist in the config
|
||||||
self.logger.info("1> lcp delete %s" % vpp_iface.interface_name)
|
self.logger.info("1> lcp delete %s" % vpp_iface.interface_name)
|
||||||
|
removed_lcps.append(lcp.host_if_name)
|
||||||
continue
|
continue
|
||||||
if not 'lcp' in config_iface:
|
if not 'lcp' in config_iface:
|
||||||
## QinX doesn't have an LCP
|
## QinX doesn't have an LCP
|
||||||
self.logger.info("2> lcp delete %s" % vpp_iface.interface_name)
|
self.logger.info("2> lcp delete %s" % vpp_iface.interface_name)
|
||||||
|
removed_lcps.append(lcp.host_if_name)
|
||||||
continue
|
continue
|
||||||
vpp_parent_idx = self.__parent_iface_by_encap(vpp_iface.sup_sw_if_index, vpp_iface.sub_outer_vlan_id, vpp_iface.sub_if_flags&8)
|
vpp_parent_idx = self.__parent_iface_by_encap(vpp_iface.sup_sw_if_index, vpp_iface.sub_outer_vlan_id, vpp_iface.sub_if_flags&8)
|
||||||
vpp_parent_iface = self.vpp.config['interfaces'][vpp_parent_idx]
|
vpp_parent_iface = self.vpp.config['interfaces'][vpp_parent_idx]
|
||||||
@ -337,14 +410,17 @@ class Reconciler():
|
|||||||
if not config_parent_iface:
|
if not config_parent_iface:
|
||||||
## QinX's parent doesn't exist in the config
|
## QinX's parent doesn't exist in the config
|
||||||
self.logger.info("3> lcp delete %s" % vpp_iface.interface_name)
|
self.logger.info("3> lcp delete %s" % vpp_iface.interface_name)
|
||||||
|
removed_lcps.append(lcp.host_if_name)
|
||||||
continue
|
continue
|
||||||
if not 'lcp' in config_parent_iface:
|
if not 'lcp' in config_parent_iface:
|
||||||
## QinX's parent doesn't have an LCP
|
## QinX's parent doesn't have an LCP
|
||||||
self.logger.info("4> lcp delete %s" % vpp_iface.interface_name)
|
self.logger.info("4> lcp delete %s" % vpp_iface.interface_name)
|
||||||
|
removed_lcps.append(lcp.host_if_name)
|
||||||
continue
|
continue
|
||||||
if parent_lcp.host_if_name != config_parent_iface['lcp']:
|
if parent_lcp.host_if_name != config_parent_iface['lcp']:
|
||||||
## QinX's parent LCP name mismatch
|
## QinX's parent LCP name mismatch
|
||||||
self.logger.info("5> lcp delete %s" % vpp_iface.interface_name)
|
self.logger.info("5> lcp delete %s" % vpp_iface.interface_name)
|
||||||
|
removed_lcps.append(lcp.host_if_name)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
phy_lcp = lcps[vpp_iface.sup_sw_if_index]
|
phy_lcp = lcps[vpp_iface.sup_sw_if_index]
|
||||||
@ -352,14 +428,17 @@ class Reconciler():
|
|||||||
if not config_phy_iface:
|
if not config_phy_iface:
|
||||||
## QinX's phy doesn't exist in the config
|
## QinX's phy doesn't exist in the config
|
||||||
self.logger.info("6> lcp delete %s" % vpp_iface.interface_name)
|
self.logger.info("6> lcp delete %s" % vpp_iface.interface_name)
|
||||||
|
removed_lcps.append(lcp.host_if_name)
|
||||||
continue
|
continue
|
||||||
if not 'lcp' in config_phy_iface:
|
if not 'lcp' in config_phy_iface:
|
||||||
## QinX's phy doesn't have an LCP
|
## QinX's phy doesn't have an LCP
|
||||||
self.logger.info("6> lcp delete %s" % vpp_iface.interface_name)
|
self.logger.info("6> lcp delete %s" % vpp_iface.interface_name)
|
||||||
|
removed_lcps.append(lcp.host_if_name)
|
||||||
continue
|
continue
|
||||||
if phy_lcp.host_if_name != config_phy_iface['lcp']:
|
if phy_lcp.host_if_name != config_phy_iface['lcp']:
|
||||||
## QinX's phy LCP name mismatch
|
## QinX's phy LCP name mismatch
|
||||||
self.logger.info("7> lcp delete %s" % vpp_iface.interface_name)
|
self.logger.info("7> lcp delete %s" % vpp_iface.interface_name)
|
||||||
|
removed_lcps.append(lcp.host_if_name)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
config_encap = interface.get_encapsulation(self.cfg, config_ifname)
|
config_encap = interface.get_encapsulation(self.cfg, config_ifname)
|
||||||
@ -369,10 +448,12 @@ class Reconciler():
|
|||||||
if config_encap != vpp_encap:
|
if config_encap != vpp_encap:
|
||||||
## QinX's encapsulation mismatch
|
## QinX's encapsulation mismatch
|
||||||
self.logger.info("8> lcp delete %s" % vpp_iface.interface_name)
|
self.logger.info("8> lcp delete %s" % vpp_iface.interface_name)
|
||||||
|
removed_lcps.append(lcp.host_if_name)
|
||||||
continue
|
continue
|
||||||
if config_parent_encap != vpp_parent_encap:
|
if config_parent_encap != vpp_parent_encap:
|
||||||
## QinX's parent encapsulation mismatch
|
## QinX's parent encapsulation mismatch
|
||||||
self.logger.info("9> lcp delete %s" % vpp_iface.interface_name)
|
self.logger.info("9> lcp delete %s" % vpp_iface.interface_name)
|
||||||
|
removed_lcps.append(lcp.host_if_name)
|
||||||
continue
|
continue
|
||||||
self.logger.debug("QinX LCP OK: %s -> (vpp=%s, config=%s)" % (lcp.host_if_name, vpp_iface.interface_name, config_ifname))
|
self.logger.debug("QinX LCP OK: %s -> (vpp=%s, config=%s)" % (lcp.host_if_name, vpp_iface.interface_name, config_ifname))
|
||||||
|
|
||||||
@ -385,10 +466,12 @@ class Reconciler():
|
|||||||
if not config_iface:
|
if not config_iface:
|
||||||
## Sub doesn't exist in the config
|
## Sub doesn't exist in the config
|
||||||
self.logger.info("11> lcp delete %s" % vpp_iface.interface_name)
|
self.logger.info("11> lcp delete %s" % vpp_iface.interface_name)
|
||||||
|
removed_lcps.append(lcp.host_if_name)
|
||||||
continue
|
continue
|
||||||
if not 'lcp' in config_iface:
|
if not 'lcp' in config_iface:
|
||||||
## Sub doesn't have an LCP
|
## Sub doesn't have an LCP
|
||||||
self.logger.info("12> lcp delete %s" % vpp_iface.interface_name)
|
self.logger.info("12> lcp delete %s" % vpp_iface.interface_name)
|
||||||
|
removed_lcps.append(lcp.host_if_name)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
phy_lcp = lcps[vpp_iface.sup_sw_if_index]
|
phy_lcp = lcps[vpp_iface.sup_sw_if_index]
|
||||||
@ -396,22 +479,27 @@ class Reconciler():
|
|||||||
if not config_phy_iface:
|
if not config_phy_iface:
|
||||||
## Sub's phy doesn't exist in the config
|
## Sub's phy doesn't exist in the config
|
||||||
self.logger.info("13> lcp delete %s" % vpp_iface.interface_name)
|
self.logger.info("13> lcp delete %s" % vpp_iface.interface_name)
|
||||||
|
removed_lcps.append(lcp.host_if_name)
|
||||||
continue
|
continue
|
||||||
if not 'lcp' in config_phy_iface:
|
if not 'lcp' in config_phy_iface:
|
||||||
## Sub's phy doesn't have an LCP
|
## Sub's phy doesn't have an LCP
|
||||||
self.logger.info("14> lcp delete %s" % vpp_iface.interface_name)
|
self.logger.info("14> lcp delete %s" % vpp_iface.interface_name)
|
||||||
|
removed_lcps.append(lcp.host_if_name)
|
||||||
continue
|
continue
|
||||||
if phy_lcp.host_if_name != config_phy_iface['lcp']:
|
if phy_lcp.host_if_name != config_phy_iface['lcp']:
|
||||||
## Sub's phy LCP name mismatch
|
## Sub's phy LCP name mismatch
|
||||||
self.logger.info("15> lcp delete %s" % vpp_iface.interface_name)
|
self.logger.info("15> lcp delete %s" % vpp_iface.interface_name)
|
||||||
|
removed_lcps.append(lcp.host_if_name)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
config_encap = interface.get_encapsulation(self.cfg, config_ifname)
|
config_encap = interface.get_encapsulation(self.cfg, config_ifname)
|
||||||
vpp_encap = self.__get_encapsulation(vpp_iface)
|
vpp_encap = self.__get_encapsulation(vpp_iface)
|
||||||
if config_encap != vpp_encap:
|
if config_encap != vpp_encap:
|
||||||
## Sub's encapsulation mismatch
|
## Sub's encapsulation mismatch
|
||||||
self.logger.info("10> lcp delete %s" % vpp_iface.interface_name)
|
self.logger.info("16> lcp delete %s" % vpp_iface.interface_name)
|
||||||
|
removed_lcps.append(lcp.host_if_name)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
self.logger.debug("Dot1Q/Dot1AD LCP OK: %s -> (vpp=%s, config=%s)" % (lcp.host_if_name, vpp_iface.interface_name, config_ifname))
|
self.logger.debug("Dot1Q/Dot1AD LCP OK: %s -> (vpp=%s, config=%s)" % (lcp.host_if_name, vpp_iface.interface_name, config_ifname))
|
||||||
|
|
||||||
## Remove LCPs for interfaces, bonds, tunnels, loops, bvis
|
## Remove LCPs for interfaces, bonds, tunnels, loops, bvis
|
||||||
@ -430,12 +518,17 @@ class Reconciler():
|
|||||||
if not config_iface:
|
if not config_iface:
|
||||||
## Interface doesn't exist in the config
|
## Interface doesn't exist in the config
|
||||||
self.logger.info("21> lcp delete %s" % vpp_iface.interface_name)
|
self.logger.info("21> lcp delete %s" % vpp_iface.interface_name)
|
||||||
|
removed_lcps.append(lcp.host_if_name)
|
||||||
continue
|
continue
|
||||||
if not 'lcp' in config_iface:
|
if not 'lcp' in config_iface:
|
||||||
## Interface doesn't have an LCP
|
## Interface doesn't have an LCP
|
||||||
self.logger.info("22> lcp delete %s" % vpp_iface.interface_name)
|
self.logger.info("22> lcp delete %s" % vpp_iface.interface_name)
|
||||||
|
removed_lcps.append(lcp.host_if_name)
|
||||||
continue
|
continue
|
||||||
self.logger.debug("LCP OK: %s -> (vpp=%s, config=%s)" % (lcp.host_if_name, vpp_iface.interface_name, config_ifname))
|
self.logger.debug("LCP OK: %s -> (vpp=%s, config=%s)" % (lcp.host_if_name, vpp_iface.interface_name, config_ifname))
|
||||||
|
|
||||||
|
for lcpname in removed_lcps:
|
||||||
|
self.vpp.remove_lcp(lcpname)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def prune_interfaces_down(self):
|
def prune_interfaces_down(self):
|
||||||
@ -443,6 +536,15 @@ class Reconciler():
|
|||||||
for ifname in self.vpp.get_qinx_interfaces() + self.vpp.get_dot1x_interfaces() + self.vpp.get_bondethernets() + self.vpp.get_phys() + self.vpp.get_vxlan_tunnels() + self.vpp.get_bvis() + self.vpp.get_loopbacks():
|
for ifname in self.vpp.get_qinx_interfaces() + self.vpp.get_dot1x_interfaces() + self.vpp.get_bondethernets() + self.vpp.get_phys() + self.vpp.get_vxlan_tunnels() + self.vpp.get_bvis() + self.vpp.get_loopbacks():
|
||||||
if not ifname in interface.get_interfaces(self.cfg):
|
if not ifname in interface.get_interfaces(self.cfg):
|
||||||
iface = self.vpp.config['interface_names'][ifname]
|
iface = self.vpp.config['interface_names'][ifname]
|
||||||
|
|
||||||
|
## Skip TAP interfaces belonging to an LCP
|
||||||
|
skip = False
|
||||||
|
for idx, lcp in self.vpp.config['lcps'].items():
|
||||||
|
if iface.sw_if_index == lcp.host_sw_if_index:
|
||||||
|
skip = True
|
||||||
|
if skip:
|
||||||
|
continue
|
||||||
|
|
||||||
if iface.flags & 1: # IF_STATUS_API_FLAG_ADMIN_UP
|
if iface.flags & 1: # IF_STATUS_API_FLAG_ADMIN_UP
|
||||||
self.logger.info("1> set interface state %s down" % ifname)
|
self.logger.info("1> set interface state %s down" % ifname)
|
||||||
|
|
||||||
|
@ -64,6 +64,76 @@ class VPPApi():
|
|||||||
"bondethernets": {}, "bondethernet_members": {},
|
"bondethernets": {}, "bondethernet_members": {},
|
||||||
"bridgedomains": {}, "vxlan_tunnels": {}, "l2xcs": {}}
|
"bridgedomains": {}, "vxlan_tunnels": {}, "l2xcs": {}}
|
||||||
|
|
||||||
|
def remove_lcp(self, lcpname):
|
||||||
|
""" Removes the LCP and TAP interface, identified by lcpname, from the config. """
|
||||||
|
self.logger.info("Removing %s" % lcpname)
|
||||||
|
|
||||||
|
for idx, lcp in self.config['lcps'].items():
|
||||||
|
if lcp.host_if_name == lcpname:
|
||||||
|
found = True
|
||||||
|
break
|
||||||
|
if not found:
|
||||||
|
self.logger.warning("Trying to remove an LCP which is not in the config: %s" % lcpname)
|
||||||
|
return False
|
||||||
|
|
||||||
|
ifname = self.config['interfaces'][lcp.host_sw_if_index].interface_name
|
||||||
|
del self.config['interface_names'][ifname]
|
||||||
|
del self.config['interface_addresses'][lcp.host_sw_if_index]
|
||||||
|
del self.config['interfaces'][lcp.host_sw_if_index]
|
||||||
|
del self.config['lcps'][lcp.phy_sw_if_index]
|
||||||
|
return True
|
||||||
|
|
||||||
|
def remove_bondethernet_member(self, ifname):
|
||||||
|
""" Removes the bonderthernet member interface, identified by name, from the config. """
|
||||||
|
if not ifname in self.config['interface_names']:
|
||||||
|
self.logger.warning("Trying to remove a bondethernet member interface which is not in the config: %s" % ifname)
|
||||||
|
return False
|
||||||
|
|
||||||
|
iface = self.config['interface_names'][ifname]
|
||||||
|
for bond_idx, members in self.config['bondethernet_members'].items():
|
||||||
|
if iface.sw_if_index in members:
|
||||||
|
self.config['bondethernet_members'][bond_idx].remove(iface.sw_if_index)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def remove_l2xc(self, ifname):
|
||||||
|
if not ifname in self.config['interface_names']:
|
||||||
|
self.logger.warning("Trying to remove an L2XC which is not in the config: %s" % ifname)
|
||||||
|
return False
|
||||||
|
iface = self.config['interface_names'][ifname]
|
||||||
|
self.config['l2xcs'].pop(iface.sw_if_index, None)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def remove_vxlan_tunnel(self, ifname):
|
||||||
|
if not ifname in self.config['interface_names']:
|
||||||
|
self.logger.warning("Trying to remove a VXLAN Tunnel which is not in the config: %s" % ifname)
|
||||||
|
return False
|
||||||
|
|
||||||
|
iface = self.config['interface_names'][ifname]
|
||||||
|
self.config['vxlan_tunnels'].pop(iface.sw_if_index, None)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def remove_interface(self, ifname):
|
||||||
|
""" Removes the interface, identified by name, from the config. """
|
||||||
|
if not ifname in self.config['interface_names']:
|
||||||
|
self.logger.warning("Trying to remove an interface which is not in the config: %s" % ifname)
|
||||||
|
return False
|
||||||
|
|
||||||
|
iface = self.config['interface_names'][ifname]
|
||||||
|
del self.config['interfaces'][iface.sw_if_index]
|
||||||
|
del self.config['interface_addresses'][iface.sw_if_index]
|
||||||
|
del self.config['interface_names'][ifname]
|
||||||
|
|
||||||
|
## Use my_dict.pop('key', None), as it allows 'key' to be absent
|
||||||
|
if iface.sw_if_index in self.config['bondethernet_members']:
|
||||||
|
if len(self.config['bondethernet_members'][iface.sw_if_index]) != 0:
|
||||||
|
self.logger.warning("When removing BondEthernet %s, its members are not empty: %s" % (ifname, self.config['bondethernet_members'][iface.sw_if_index]))
|
||||||
|
else:
|
||||||
|
del self.config['bondethernet_members'][iface.sw_if_index]
|
||||||
|
self.config['bondethernets'].pop(iface.sw_if_index, None)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def readconfig(self):
|
def readconfig(self):
|
||||||
if not self.connected and not self.connect():
|
if not self.connected and not self.connect():
|
||||||
self.logger.error("Could not connect to VPP")
|
self.logger.error("Could not connect to VPP")
|
||||||
@ -144,15 +214,15 @@ class VPPApi():
|
|||||||
self.dump_subints()
|
self.dump_subints()
|
||||||
|
|
||||||
def get_sub_interfaces(self):
|
def get_sub_interfaces(self):
|
||||||
subints = [self.config['interfaces'][x].interface_name for x in self.config['interfaces'] if self.config['interfaces'][x].interface_dev_type in ['dpdk','bond'] and self.config['interfaces'][x].sub_id>0 and self.config['interfaces'][x].sub_number_of_tags > 0]
|
subints = [self.config['interfaces'][x].interface_name for x in self.config['interfaces'] if self.config['interfaces'][x].sub_id>0 and self.config['interfaces'][x].sub_number_of_tags > 0]
|
||||||
return subints
|
return subints
|
||||||
|
|
||||||
def get_qinx_interfaces(self):
|
def get_qinx_interfaces(self):
|
||||||
qinx_subints = [self.config['interfaces'][x].interface_name for x in self.config['interfaces'] if self.config['interfaces'][x].interface_dev_type in ['dpdk','bond'] and self.config['interfaces'][x].sub_id>0 and self.config['interfaces'][x].sub_inner_vlan_id>0]
|
qinx_subints = [self.config['interfaces'][x].interface_name for x in self.config['interfaces'] if self.config['interfaces'][x].sub_id>0 and self.config['interfaces'][x].sub_inner_vlan_id>0]
|
||||||
return qinx_subints
|
return qinx_subints
|
||||||
|
|
||||||
def get_dot1x_interfaces(self):
|
def get_dot1x_interfaces(self):
|
||||||
dot1x_subints = [self.config['interfaces'][x].interface_name for x in self.config['interfaces'] if self.config['interfaces'][x].interface_dev_type in ['dpdk','bond'] and self.config['interfaces'][x].sub_id>0 and self.config['interfaces'][x].sub_inner_vlan_id==0]
|
dot1x_subints = [self.config['interfaces'][x].interface_name for x in self.config['interfaces'] if self.config['interfaces'][x].sub_id>0 and self.config['interfaces'][x].sub_inner_vlan_id==0]
|
||||||
return dot1x_subints
|
return dot1x_subints
|
||||||
|
|
||||||
def get_loopbacks(self):
|
def get_loopbacks(self):
|
||||||
@ -164,7 +234,7 @@ class VPPApi():
|
|||||||
return bvis
|
return bvis
|
||||||
|
|
||||||
def get_phys(self):
|
def get_phys(self):
|
||||||
phys = [self.config['interfaces'][x].interface_name for x in self.config['interfaces'] if self.config['interfaces'][x].interface_dev_type=='dpdk' and self.config['interfaces'][x].sub_id==0]
|
phys = [self.config['interfaces'][x].interface_name for x in self.config['interfaces'] if self.config['interfaces'][x].interface_dev_type=='dpdk' and self.config['interfaces'][x].sw_if_index == self.config['interfaces'][x].sup_sw_if_index]
|
||||||
return phys
|
return phys
|
||||||
|
|
||||||
def get_bondethernets(self):
|
def get_bondethernets(self):
|
||||||
|
Reference in New Issue
Block a user