def find_l2_fib_entry(test, bd_id, mac, sw_if_index): vmac = MACAddress(mac) lfs = test.vapi.l2_fib_table_dump(bd_id) for lf in lfs: if vmac.packed == lf.mac and sw_if_index == lf.sw_if_index: return True return False
def test_ip4_irb_2(self): """IPv4 IRB test 2 Test scenario: - ip traffic from pg0 and pg1 ends on pg2 """ self.send_and_verify_l2_to_ip() # change the BVI's mac and resed traffic self.bvi0.set_mac(MACAddress("00:00:00:11:11:33")) self.send_and_verify_l2_to_ip() # check it wasn't flooded self.pg1.assert_nothing_captured(remark="UU Flood")
def test_lisp(self): VPPEnumType('vl_api_eid_type_t', [["EID_TYPE_API_PREFIX", 0], ["EID_TYPE_API_MAC", 1], ["EID_TYPE_API_NSH", 2], {"enumtype": "u32"}]) VPPTypeAlias('vl_api_mac_address_t', {'type': 'u8', 'length': 6}) VPPType('vl_api_nsh_t', [["u32", "spi"], ["u8", "si"]]) VPPEnumType('vl_api_address_family_t', [["ADDRESS_IP4", 0], ["ADDRESS_IP6", 1], {"enumtype": "u32"}]) VPPTypeAlias('vl_api_ip4_address_t', {'type': 'u8', 'length': 4}) VPPTypeAlias('vl_api_ip6_address_t', {'type': 'u8', 'length': 16}) VPPUnionType('vl_api_address_union_t', [["vl_api_ip4_address_t", "ip4"], ["vl_api_ip6_address_t", "ip6"]]) VPPType('vl_api_address_t', [['vl_api_address_family_t', 'af'], ['vl_api_address_union_t', 'un']]) VPPType('vl_api_prefix_t', [['vl_api_address_t', 'address'], ['u8', 'len']]) VPPUnionType('vl_api_eid_address_t', [["vl_api_prefix_t", "prefix"], ["vl_api_mac_address_t", "mac"], ["vl_api_nsh_t", "nsh"]]) eid = VPPType('vl_api_eid_t', [["vl_api_eid_type_t", "type"], ["vl_api_eid_address_t", "address"]]) b = eid.pack({'type':1, 'address': { 'mac': MACAddress('aa:bb:cc:dd:ee:ff')}}) self.assertEqual(len(b), 25) nt, size = eid.unpack(b) self.assertEqual(str(nt.address.mac), 'aa:bb:cc:dd:ee:ff') self.assertIsNone(nt.address.prefix)
def find_bridge_domain_arp_entry(test, bd_id, mac, ip): vmac = MACAddress(mac) vip = VppIpAddress(ip) if vip.version == 4: n = 4 else: n = 16 arps = test.vapi.bd_ip_mac_dump(bd_id) for arp in arps: # do IP addr comparison too once .api is fixed... if vmac.packed == arp.mac_address and \ vip.bytes == arp.ip_address[:n]: return True return False
def __init__(self, test, bd, mac, itf, static_mac=0, filter_mac=0, bvi_mac=-1): self._test = test self.bd = bd self.mac = MACAddress(mac) self.itf = itf self.static_mac = static_mac self.filter_mac = filter_mac if bvi_mac == -1: self.bvi_mac = isinstance(self.itf, VppLoInterface) else: self.bvi_mac = bvi_mac
def test_bond_traffic(self): """ Bond traffic test """ # topology # # RX-> TX-> # # pg2 ------+ +------pg0 (slave) # | | # BondEthernet0 (10.10.10.1) # | | # pg3 ------+ +------pg1 (slave) # # create interface (BondEthernet0) # self.logger.info("create bond") bond0_mac = "02:fe:38:30:59:3c" mac = MACAddress(bond0_mac).packed bond0 = VppBondInterface(self, mode=3, lb=1, use_custom_mac=1, mac_address=mac) bond0.add_vpp_config() bond0.admin_up() bond0_addr = socket.inet_pton(socket.AF_INET, "10.10.10.1") self.vapi.sw_interface_add_del_address(bond0.sw_if_index, bond0_addr, 24) self.pg2.config_ip4() self.pg2.resolve_arp() self.pg3.config_ip4() self.pg3.resolve_arp() self.logger.info(self.vapi.cli("show interface")) self.logger.info(self.vapi.cli("show interface address")) self.logger.info(self.vapi.cli("show ip arp")) # enslave pg0 and pg1 to BondEthernet0 self.logger.info("bond enslave interface pg0 to BondEthernet0") bond0.enslave_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index, is_passive=0, is_long_timeout=0) self.logger.info("bond enslave interface pg1 to BondEthernet0") bond0.enslave_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index, is_passive=0, is_long_timeout=0) # verify both slaves in BondEthernet0 if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index) self.assertTrue(self.pg0.is_interface_config_in_dump(if_dump)) self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump)) # generate a packet from pg2 -> BondEthernet0 -> pg1 # BondEthernet0 TX hashes this packet to pg1 p2 = (Ether(src=bond0_mac, dst=self.pg2.local_mac) / IP(src=self.pg2.local_ip4, dst="10.10.10.12") / UDP(sport=1235, dport=1235) / Raw('\xa5' * 100)) self.pg2.add_stream(p2) # generate a packet from pg3 -> BondEthernet0 -> pg0 # BondEthernet0 TX hashes this packet to pg0 # notice the ip address and ports are different than p2 packet p3 = (Ether(src=bond0_mac, dst=self.pg3.local_mac) / IP(src=self.pg3.local_ip4, dst="10.10.10.11") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.pg3.add_stream(p3) self.pg_enable_capture(self.pg_interfaces) # set up the static arp entries pointing to the BondEthernet0 interface # so that it does not try to resolve the ip address self.logger.info(self.vapi.cli( "set ip arp static BondEthernet0 10.10.10.12 abcd.abcd.0002")) self.logger.info(self.vapi.cli( "set ip arp static BondEthernet0 10.10.10.11 abcd.abcd.0004")) # clear the interface counters self.logger.info(self.vapi.cli("clear interfaces")) self.pg_start() self.logger.info("check the interface counters") # verify counters # BondEthernet0 tx bytes = 284 intfs = self.vapi.cli("show interface BondEthernet0").split("\n") found = 0 for intf in intfs: if "tx bytes" in intf and "284" in intf: found = 1 self.assertEqual(found, 1) # BondEthernet0 tx bytes = 284 intfs = self.vapi.cli("show interface BondEthernet0").split("\n") found = 0 for intf in intfs: if "tx bytes" in intf and "284" in intf: found = 1 self.assertEqual(found, 1) # pg2 rx bytes = 142 intfs = self.vapi.cli("show interface pg2").split("\n") found = 0 for intf in intfs: if "rx bytes" in intf and "142" in intf: found = 1 self.assertEqual(found, 1) # pg3 rx bytes = 142 intfs = self.vapi.cli("show interface pg3").split("\n") found = 0 for intf in intfs: if "rx bytes" in intf and "142" in intf: found = 1 self.assertEqual(found, 1) bond0.remove_vpp_config()
def test_eq(self): mac = "11:22:33:44:55:66" self.assertEqual(MACAddress(mac), MACAddress(mac))
def test_bond_traffic(self): """ Bond traffic test """ # topology # # RX-> TX-> # # pg2 ------+ +------pg0 (member) # | | # BondEthernet0 (10.10.10.1) # | | # pg3 ------+ +------pg1 (memberx) # # create interface (BondEthernet0) # self.logger.info("create bond") bond0_mac = "02:fe:38:30:59:3c" mac = MACAddress(bond0_mac).packed bond0 = VppBondInterface( self, mode=VppEnum.vl_api_bond_mode_t.BOND_API_MODE_XOR, lb=VppEnum.vl_api_bond_lb_algo_t.BOND_API_LB_ALGO_L34, numa_only=0, use_custom_mac=1, mac_address=mac) bond0.add_vpp_config() bond0.admin_up() self.vapi.sw_interface_add_del_address(sw_if_index=bond0.sw_if_index, prefix="10.10.10.1/24") self.pg2.config_ip4() self.pg2.resolve_arp() self.pg3.config_ip4() self.pg3.resolve_arp() self.logger.info(self.vapi.cli("show interface")) self.logger.info(self.vapi.cli("show interface address")) self.logger.info(self.vapi.cli("show ip neighbors")) # add member pg0 and pg1 to BondEthernet0 self.logger.info("bond add member interface pg0 to BondEthernet0") bond0.add_member_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index) self.logger.info("bond add_member interface pg1 to BondEthernet0") bond0.add_member_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index) # verify both members in BondEthernet0 if_dump = self.vapi.sw_member_interface_dump(bond0.sw_if_index) self.assertTrue(self.pg0.is_interface_config_in_dump(if_dump)) self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump)) # generate a packet from pg2 -> BondEthernet0 -> pg1 # BondEthernet0 TX hashes this packet to pg1 p2 = (Ether(src=bond0_mac, dst=self.pg2.local_mac) / IP(src=self.pg2.local_ip4, dst="10.10.10.12") / UDP(sport=1235, dport=1235) / Raw(b'\xa5' * 100)) self.pg2.add_stream(p2) # generate a packet from pg3 -> BondEthernet0 -> pg0 # BondEthernet0 TX hashes this packet to pg0 # notice the ip address and ports are different than p2 packet p3 = (Ether(src=bond0_mac, dst=self.pg3.local_mac) / IP(src=self.pg3.local_ip4, dst="10.10.10.11") / UDP(sport=1234, dport=1234) / Raw(b'\xa5' * 100)) self.pg3.add_stream(p3) self.pg_enable_capture(self.pg_interfaces) # set up the static arp entries pointing to the BondEthernet0 interface # so that it does not try to resolve the ip address self.logger.info( self.vapi.cli( "set ip neighbor static BondEthernet0 10.10.10.12 abcd.abcd.0002" )) self.logger.info( self.vapi.cli( "set ip neighbor static BondEthernet0 10.10.10.11 abcd.abcd.0004" )) # clear the interface counters self.logger.info(self.vapi.cli("clear interfaces")) self.pg_start() self.logger.info("check the interface counters") # verify counters # BondEthernet0 tx bytes = 284 intfs = self.vapi.cli("show interface BondEthernet0").split("\n") found = 0 for intf in intfs: if "tx bytes" in intf and "284" in intf: found = 1 self.assertEqual(found, 1) # BondEthernet0 tx bytes = 284 intfs = self.vapi.cli("show interface BondEthernet0").split("\n") found = 0 for intf in intfs: if "tx bytes" in intf and "284" in intf: found = 1 self.assertEqual(found, 1) # pg2 rx bytes = 142 intfs = self.vapi.cli("show interface pg2").split("\n") found = 0 for intf in intfs: if "rx bytes" in intf and "142" in intf: found = 1 self.assertEqual(found, 1) # pg3 rx bytes = 142 intfs = self.vapi.cli("show interface pg3").split("\n") found = 0 for intf in intfs: if "rx bytes" in intf and "142" in intf: found = 1 self.assertEqual(found, 1) bond0.remove_vpp_config()
def __init__(self, test, bd, mac, ip): self._test = test self.bd = bd self.mac = MACAddress(mac) self.ip = VppIpAddress(ip)
def create_stream( self, mac_type, ip_type, packet_count, src_if, dst_if, traffic, is_ip6, tags=PERMIT_TAGS, ): # exact MAC and exact IP # exact MAC and subnet of IPs # exact MAC and wildcard IP # wildcard MAC and exact IP # wildcard MAC and subnet of IPs # wildcard MAC and wildcard IP # OUI restricted MAC and exact IP # OUI restricted MAC and subnet of IPs # OUI restricted MAC and wildcard IP packets = [] macip_rules = [] acl_rules = [] ip_permit = "" mac_permit = "" dst_mac = "" mac_rule = "00:00:00:00:00:00" mac_mask = "00:00:00:00:00:00" for p in range(0, packet_count): remote_dst_index = p % len(dst_if.remote_hosts) remote_dst_host = dst_if.remote_hosts[remote_dst_index] dst_port = 1234 + p src_port = 4321 + p is_permit = self.PERMIT if p % 3 == 0 else self.DENY denyMAC = True if not is_permit and p % 3 == 1 else False denyIP = True if not is_permit and p % 3 == 2 else False if not is_permit and ip_type == self.WILD_IP: denyMAC = True if not is_permit and mac_type == self.WILD_MAC: denyIP = True if traffic == self.BRIDGED: if is_permit: src_mac = remote_dst_host._mac dst_mac = "de:ad:00:00:00:00" src_ip4 = remote_dst_host.ip4 dst_ip4 = src_if.remote_ip4 src_ip6 = remote_dst_host.ip6 dst_ip6 = src_if.remote_ip6 ip_permit = src_ip6 if is_ip6 else src_ip4 mac_permit = src_mac if denyMAC: mac = src_mac.split(":") mac[0] = format(int(mac[0], 16) + 1, "02x") src_mac = ":".join(mac) if is_ip6: src_ip6 = ip_permit else: src_ip4 = ip_permit if denyIP: if ip_type != self.WILD_IP: src_mac = mac_permit src_ip4 = remote_dst_host.ip4 dst_ip4 = src_if.remote_ip4 src_ip6 = remote_dst_host.ip6 dst_ip6 = src_if.remote_ip6 else: if is_permit: src_mac = remote_dst_host._mac dst_mac = src_if.local_mac src_ip4 = src_if.remote_ip4 dst_ip4 = remote_dst_host.ip4 src_ip6 = src_if.remote_ip6 dst_ip6 = remote_dst_host.ip6 ip_permit = src_ip6 if is_ip6 else src_ip4 mac_permit = src_mac if denyMAC: mac = src_mac.split(":") mac[0] = format(int(mac[0], 16) + 1, "02x") src_mac = ":".join(mac) if is_ip6: src_ip6 = ip_permit else: src_ip4 = ip_permit if denyIP: src_mac = remote_dst_host._mac if ip_type != self.WILD_IP: src_mac = mac_permit src_ip4 = remote_dst_host.ip4 dst_ip4 = src_if.remote_ip4 src_ip6 = remote_dst_host.ip6 dst_ip6 = src_if.remote_ip6 if is_permit: info = self.create_packet_info(src_if, dst_if) payload = self.info_to_payload(info) else: payload = "to be blocked" if mac_type == self.WILD_MAC: mac = src_mac.split(":") for i in range(1, 5): mac[i] = format(random.randint(0, 255), "02x") src_mac = ":".join(mac) # create packet packet = Ether(src=src_mac, dst=dst_mac) ip_rule = src_ip6 if is_ip6 else src_ip4 if is_ip6: if ip_type != self.EXACT_IP: sub_ip = list(unpack("<16B", inet_pton(AF_INET6, ip_rule))) if ip_type == self.WILD_IP: sub_ip[0] = random.randint(240, 254) sub_ip[1] = random.randint(230, 239) sub_ip[14] = random.randint(100, 199) sub_ip[15] = random.randint(200, 255) elif ip_type == self.SUBNET_IP: if denyIP: sub_ip[2] = int(sub_ip[2]) + 1 sub_ip[14] = random.randint(100, 199) sub_ip[15] = random.randint(200, 255) packed_src_ip6 = b"".join([scapy.compat.chb(x) for x in sub_ip]) src_ip6 = inet_ntop(AF_INET6, packed_src_ip6) packet /= IPv6(src=src_ip6, dst=dst_ip6) else: if ip_type != self.EXACT_IP: sub_ip = ip_rule.split(".") if ip_type == self.WILD_IP: sub_ip[0] = random.randint(1, 49) sub_ip[1] = random.randint(50, 99) sub_ip[2] = random.randint(100, 199) sub_ip[3] = random.randint(200, 255) elif ip_type == self.SUBNET_IP: if denyIP: sub_ip[1] = int(sub_ip[1]) + 1 sub_ip[2] = random.randint(100, 199) sub_ip[3] = random.randint(200, 255) src_ip4 = ".".join(["{!s}".format(x) for x in sub_ip]) packet /= IP(src=src_ip4, dst=dst_ip4, frag=0, flags=0) packet /= UDP(sport=src_port, dport=dst_port) / Raw(payload) packet[Raw].load += b" mac:%s" % src_mac.encode("utf-8") size = self.pg_if_packet_sizes[p % len(self.pg_if_packet_sizes)] if isinstance(src_if, VppSubInterface): size = size + 4 if isinstance(src_if, VppDot1QSubint): if src_if is self.subifs[0]: if tags == self.PERMIT_TAGS: packet = src_if.add_dot1q_layer(packet, 10) else: packet = src_if.add_dot1q_layer(packet, 11) else: if tags == self.PERMIT_TAGS: packet = src_if.add_dot1q_layer(packet, 30) else: packet = src_if.add_dot1q_layer(packet, 33) elif isinstance(src_if, VppDot1ADSubint): if src_if is self.subifs[1]: if tags == self.PERMIT_TAGS: packet = src_if.add_dot1ad_layer(packet, 300, 400) else: packet = src_if.add_dot1ad_layer(packet, 333, 444) else: if tags == self.PERMIT_TAGS: packet = src_if.add_dot1ad_layer(packet, 600, 700) else: packet = src_if.add_dot1ad_layer(packet, 666, 777) self.extend_packet(packet, size) packets.append(packet) # create suitable MACIP rule if mac_type == self.EXACT_MAC: mac_rule = src_mac mac_mask = "ff:ff:ff:ff:ff:ff" elif mac_type == self.WILD_MAC: mac_rule = "00:00:00:00:00:00" mac_mask = "00:00:00:00:00:00" elif mac_type == self.OUI_MAC: mac = src_mac.split(":") mac[3] = mac[4] = mac[5] = "00" mac_rule = ":".join(mac) mac_mask = "ff:ff:ff:00:00:00" if is_ip6: if ip_type == self.WILD_IP: ip = "0::0" else: ip = src_ip6 if ip_type == self.SUBNET_IP: sub_ip = list(unpack("<16B", inet_pton(AF_INET6, ip))) for i in range(8, 16): sub_ip[i] = 0 packed_ip = b"".join([scapy.compat.chb(x) for x in sub_ip]) ip = inet_ntop(AF_INET6, packed_ip) else: if ip_type == self.WILD_IP: ip = "0.0.0.0" else: ip = src_ip4 if ip_type == self.SUBNET_IP: sub_ip = ip.split(".") sub_ip[2] = sub_ip[3] = "0" ip = ".".join(sub_ip) prefix_len = 128 if is_ip6 else 32 if ip_type == self.WILD_IP: prefix_len = 0 elif ip_type == self.SUBNET_IP: prefix_len = 64 if is_ip6 else 16 ip_rule = inet_pton(AF_INET6 if is_ip6 else AF_INET, ip) # create suitable ACL rule if is_permit: rule_l4_sport = packet[UDP].sport rule_l4_dport = packet[UDP].dport rule_family = AF_INET6 if packet.haslayer(IPv6) else AF_INET rule_prefix_len = 128 if packet.haslayer(IPv6) else 32 rule_l3_layer = IPv6 if packet.haslayer(IPv6) else IP if packet.haslayer(IPv6): rule_l4_proto = packet[UDP].overload_fields[IPv6]["nh"] else: rule_l4_proto = packet[IP].proto src_network = ip_network((packet[rule_l3_layer].src, rule_prefix_len)) dst_network = ip_network((packet[rule_l3_layer].dst, rule_prefix_len)) acl_rule = AclRule( is_permit=is_permit, proto=rule_l4_proto, src_prefix=src_network, dst_prefix=dst_network, sport_from=rule_l4_sport, sport_to=rule_l4_sport, dport_from=rule_l4_dport, dport_to=rule_l4_dport, ) acl_rules.append(acl_rule) if mac_type == self.WILD_MAC and ip_type == self.WILD_IP and p > 0: continue if is_permit: macip_rule = MacipRule( is_permit=is_permit, src_prefix=ip_network((ip_rule, prefix_len)), src_mac=MACAddress(mac_rule).packed, src_mac_mask=MACAddress(mac_mask).packed, ) macip_rules.append(macip_rule) # deny all other packets if not (mac_type == self.WILD_MAC and ip_type == self.WILD_IP): network = IPv6Network((0, 0)) if is_ip6 else IPv4Network((0, 0)) macip_rule = MacipRule( is_permit=0, src_prefix=network, src_mac=MACAddress("00:00:00:00:00:00").packed, src_mac_mask=MACAddress("00:00:00:00:00:00").packed, ) macip_rules.append(macip_rule) network = IPv6Network((0, 0)) if is_ip6 else IPv4Network((0, 0)) acl_rule = AclRule( is_permit=0, src_prefix=network, dst_prefix=network, sport_from=0, sport_to=0, dport_from=0, dport_to=0, ) acl_rules.append(acl_rule) return {"stream": packets, "macip_rules": macip_rules, "acl_rules": acl_rules}
def create_rules( self, mac_type=EXACT_MAC, ip_type=EXACT_IP, acl_count=1, rules_count=None ): acls = [] if rules_count is None: rules_count = [1] src_mac = int("220000dead00", 16) for acl in range(2, (acl_count + 1) * 2): rules = [] host = random.choice(self.loop0.remote_hosts) is_ip6 = acl % 2 ip4 = host.ip4.split(".") ip6 = list(unpack("<16B", inet_pton(AF_INET6, host.ip6))) if ip_type == self.EXACT_IP: prefix_len4 = 32 prefix_len6 = 128 elif ip_type == self.WILD_IP: ip4 = [0, 0, 0, 0] ip6 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] prefix_len4 = 0 prefix_len6 = 0 rules_count[int((acl / 2) - 1)] = 1 else: prefix_len4 = 24 prefix_len6 = 64 if mac_type == self.EXACT_MAC: mask = "ff:ff:ff:ff:ff:ff" elif mac_type == self.WILD_MAC: mask = "00:00:00:00:00:00" elif mac_type == self.OUI_MAC: mask = "ff:ff:ff:00:00:00" else: mask = "ff:ff:ff:ff:ff:00" ip = ip6 if is_ip6 else ip4 ip_len = prefix_len6 if is_ip6 else prefix_len4 for i in range(0, (rules_count[int((acl / 2) - 1)])): src_mac += 16777217 if mac_type == self.WILD_MAC: mac = "00:00:00:00:00:00" elif mac_type == self.OUI_MAC: mac = ( ":".join(re.findall("..", "{:02x}".format(src_mac))[:3]) + ":00:00:00" ) else: mac = ":".join(re.findall("..", "{:02x}".format(src_mac))) if ip_type == self.EXACT_IP: ip4[3] = random.randint(100, 200) ip6[15] = random.randint(100, 200) elif ip_type == self.SUBNET_IP: ip4[2] = random.randint(100, 200) ip4[3] = 0 ip6[7] = random.randint(100, 200) ip6[15] = 0 ip_pack = b"" for j in range(0, len(ip)): ip_pack += pack("<B", int(ip[j])) rule = MacipRule( is_permit=self.PERMIT, src_prefix=ip_network((ip_pack, ip_len)), src_mac=MACAddress(mac).packed, src_mac_mask=MACAddress(mask).packed, ) rules.append(rule) if ip_type == self.WILD_IP: break acls.append(rules) src_mac += 1099511627776 return acls
def test_lisp(self): VPPEnumType( "vl_api_eid_type_t", [ ["EID_TYPE_API_PREFIX", 0], ["EID_TYPE_API_MAC", 1], ["EID_TYPE_API_NSH", 2], { "enumtype": "u32" }, ], ) VPPTypeAlias("vl_api_mac_address_t", {"type": "u8", "length": 6}) VPPType("vl_api_nsh_t", [["u32", "spi"], ["u8", "si"]]) VPPEnumType( "vl_api_address_family_t", [["ADDRESS_IP4", 0], ["ADDRESS_IP6", 1], { "enumtype": "u32" }], ) VPPTypeAlias("vl_api_ip4_address_t", {"type": "u8", "length": 4}) VPPTypeAlias("vl_api_ip6_address_t", {"type": "u8", "length": 16}) VPPUnionType( "vl_api_address_union_t", [["vl_api_ip4_address_t", "ip4"], ["vl_api_ip6_address_t", "ip6"]], ) VPPType( "vl_api_address_t", [["vl_api_address_family_t", "af"], ["vl_api_address_union_t", "un"]], ) VPPType("vl_api_prefix_t", [["vl_api_address_t", "address"], ["u8", "len"]]) VPPUnionType( "vl_api_eid_address_t", [ ["vl_api_prefix_t", "prefix"], ["vl_api_mac_address_t", "mac"], ["vl_api_nsh_t", "nsh"], ], ) eid = VPPType( "vl_api_eid_t", [["vl_api_eid_type_t", "type"], ["vl_api_eid_address_t", "address"]], ) b = eid.pack({ "type": 1, "address": { "mac": MACAddress("aa:bb:cc:dd:ee:ff") } }) self.assertEqual(len(b), 25) nt, size = eid.unpack(b) self.assertEqual(str(nt.address.mac), "aa:bb:cc:dd:ee:ff") self.assertIsNone(nt.address.prefix)