""" The functions in this file interact with the VPP API to retrieve certain interface metadata and write it to a YAML file. """ from vpp.vppapi import VPPApi import sys import yaml import config.bondethernet as bondethernet class Dumper(VPPApi): def __init__(self, address="/run/vpp/api.sock", clientname="vppcfg"): VPPApi.__init__(self, address, clientname) def write(self, outfile): if outfile and outfile == "-": fh = sys.stdout outfile = "(stdout)" else: fh = open(outfile, "w") config = self.cache_to_config() print(yaml.dump(config), file=fh) if fh is not sys.stdout: fh.close() self.logger.info(f"Wrote YAML config to {outfile}") def cache_to_config(self): config = { "loopbacks": {}, "bondethernets": {}, "interfaces": {}, "bridgedomains": {}, "vxlan_tunnels": {}, "taps": {}, } for idx, bond_iface in self.cache["bondethernets"].items(): bond = {"description": ""} if bond_iface.sw_if_index in self.cache["bondethernet_members"]: members = [ self.cache["interfaces"][x].interface_name for x in self.cache["bondethernet_members"][bond_iface.sw_if_index] ] if len(members) > 0: bond["interfaces"] = members mode = bondethernet.int_to_mode(bond_iface.mode) bond["mode"] = mode if mode in ["xor", "lacp"]: bond["load-balance"] = bondethernet.int_to_lb(bond_iface.lb) iface = self.cache["interfaces"][bond_iface.sw_if_index] bond["mac"] = str(iface.l2_address) config["bondethernets"][iface.interface_name] = bond for numtags in [0, 1, 2]: for idx, iface in self.cache["interfaces"].items(): if iface.sub_number_of_tags != numtags: continue if iface.interface_dev_type == "Loopback": if iface.sub_id > 0: self.logger.warning( f"Refusing to export sub-interfaces of loopback devices ({iface.interface_name})" ) continue loop = {"description": ""} loop["mtu"] = iface.mtu[0] loop["mac"] = str(iface.l2_address) if iface.sw_if_index in self.cache["lcps"]: loop["lcp"] = self.cache["lcps"][iface.sw_if_index].host_if_name if iface.sw_if_index in self.cache["interface_addresses"]: if ( len(self.cache["interface_addresses"][iface.sw_if_index]) > 0 ): loop["addresses"] = self.cache["interface_addresses"][ iface.sw_if_index ] config["loopbacks"][iface.interface_name] = loop elif iface.interface_dev_type in ["bond", "VXLAN", "dpdk", "virtio"]: i = {"description": ""} if iface.sw_if_index in self.cache["lcps"]: i["lcp"] = self.cache["lcps"][iface.sw_if_index].host_if_name if iface.sw_if_index in self.cache["interface_addresses"]: if ( len(self.cache["interface_addresses"][iface.sw_if_index]) > 0 ): i["addresses"] = self.cache["interface_addresses"][ iface.sw_if_index ] if iface.sw_if_index in self.cache["l2xcs"]: l2xc = self.cache["l2xcs"][iface.sw_if_index] i["l2xc"] = self.cache["interfaces"][ l2xc.tx_sw_if_index ].interface_name if ( not self.cache["interfaces"][idx].flags & 1 ): # IF_STATUS_API_FLAG_ADMIN_UP i["state"] = "down" if ( iface.interface_dev_type == "dpdk" and iface.sub_number_of_tags == 0 ): i["mac"] = str(iface.l2_address) if self.tap_is_lcp(iface.interface_name): continue i["mtu"] = iface.mtu[0] if iface.sub_number_of_tags == 0: config["interfaces"][iface.interface_name] = i continue encap = {} if iface.sub_if_flags & 8: encap["dot1ad"] = iface.sub_outer_vlan_id else: encap["dot1q"] = iface.sub_outer_vlan_id if iface.sub_inner_vlan_id > 0: encap["inner-dot1q"] = iface.sub_inner_vlan_id encap["exact-match"] = bool(iface.sub_if_flags & 16) i["encapsulation"] = encap sup_iface = self.cache["interfaces"][iface.sup_sw_if_index] if iface.mtu[0] > 0: i["mtu"] = iface.mtu[0] else: i["mtu"] = sup_iface.mtu[0] if ( not "sub-interfaces" in config["interfaces"][sup_iface.interface_name] ): config["interfaces"][sup_iface.interface_name][ "sub-interfaces" ] = {} config["interfaces"][sup_iface.interface_name]["sub-interfaces"][ iface.sub_id ] = i for idx, iface in self.cache["vxlan_tunnels"].items(): vpp_iface = self.cache["interfaces"][iface.sw_if_index] vxlan = { "description": "", "vni": int(iface.vni), "local": str(iface.src_address), "remote": str(iface.dst_address), } 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] if self.tap_is_lcp(vpp_iface.interface_name): continue 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(): bridge_name = f"bd{int(idx)}" mtu = 1500 bridge = {"description": ""} settings = {} settings["learn"] = iface.learn settings["unicast-flood"] = iface.flood settings["unknown-unicast-flood"] = iface.uu_flood settings["unicast-forward"] = iface.forward settings["arp-termination"] = iface.arp_term settings["arp-unicast-forward"] = iface.arp_ufwd settings["mac-age-minutes"] = int(iface.mac_age) bridge["settings"] = settings bvi = None if iface.bvi_sw_if_index != 2**32 - 1: bvi = self.cache["interfaces"][iface.bvi_sw_if_index] mtu = bvi.mtu[0] bridge["bvi"] = bvi.interface_name members = [] for member in iface.sw_if_details: if ( bvi and bvi.interface_name == self.cache["interfaces"][member.sw_if_index].interface_name == bvi.interface_name ): continue members.append( self.cache["interfaces"][member.sw_if_index].interface_name ) mtu = self.cache["interfaces"][member.sw_if_index].mtu[0] if len(members) > 0: bridge["interfaces"] = members bridge["mtu"] = mtu config["bridgedomains"][bridge_name] = bridge return config