5 from framework import VppTestCase, VppTestRunner
6 from vpp_object import VppObject
7 from vpp_neighbor import VppNeighbor
8 from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable, \
9 VppIpInterfaceAddress, VppIpInterfaceBind, find_route
10 from vpp_l2 import VppBridgeDomain, VppBridgeDomainPort, \
11 VppBridgeDomainArpEntry, VppL2FibEntry, find_bridge_domain_port
12 from vpp_vxlan_gbp_tunnel import *
13 from vpp_sub_interface import VppDot1QSubint
17 from vpp_papi_provider import L2_PORT_TYPE
18 from vpp_papi import VppEnum
20 from scapy.packet import Raw
21 from scapy.layers.l2 import Ether, ARP, Dot1Q
22 from scapy.layers.inet import IP, UDP
23 from scapy.layers.inet6 import IPv6, ICMPv6ND_NS, ICMPv6NDOptSrcLLAddr, \
25 from scapy.utils6 import in6_getnsma, in6_getnsmac
26 from scapy.layers.vxlan import VXLAN
28 from socket import AF_INET, AF_INET6
29 from scapy.utils import inet_pton, inet_ntop
30 from util import mactobinary
31 from vpp_papi_provider import L2_VTR_OP
34 def find_gbp_endpoint(test, sw_if_index=None, ip=None, mac=None):
36 vip = VppIpAddress(ip)
38 vmac = VppMacAddress(mac)
40 eps = test.vapi.gbp_endpoint_dump()
44 if ep.endpoint.sw_if_index != sw_if_index:
47 for eip in ep.endpoint.ips:
51 if vmac == ep.endpoint.mac:
56 def find_gbp_vxlan(test, vni):
57 ts = test.vapi.gbp_vxlan_tunnel_dump()
59 if t.tunnel.vni == vni:
64 class VppGbpEndpoint(VppObject):
71 return self.vmac.bytes
75 return self.vmac.address
79 return self.itf.remote_mac
99 return [self.ip4, self.ip6]
103 return [self.fip4, self.fip6]
105 def __init__(self, test, itf, epg, recirc, ip4, fip4, ip6, fip6,
115 self._ip4 = VppIpAddress(ip4)
116 self._fip4 = VppIpAddress(fip4)
117 self._ip6 = VppIpAddress(ip6)
118 self._fip6 = VppIpAddress(fip6)
121 self.vmac = VppMacAddress(self.itf.remote_mac)
123 self.vmac = VppMacAddress("00:00:00:00:00:00")
126 self.tun_src = VppIpAddress(tun_src)
127 self.tun_dst = VppIpAddress(tun_dst)
129 def add_vpp_config(self):
130 res = self._test.vapi.gbp_endpoint_add(
131 self.itf.sw_if_index,
132 [self.ip4.encode(), self.ip6.encode()],
136 self.tun_src.encode(),
137 self.tun_dst.encode())
138 self.handle = res.handle
139 self._test.registry.register(self, self._test.logger)
141 def remove_vpp_config(self):
142 self._test.vapi.gbp_endpoint_del(self.handle)
145 return self.object_id()
148 return "gbp-endpoint:[%d==%d:%s:%d]" % (self.handle,
149 self.itf.sw_if_index,
153 def query_vpp_config(self):
154 return find_gbp_endpoint(self._test,
155 self.itf.sw_if_index,
159 class VppGbpRecirc(VppObject):
161 GBP Recirculation Interface
164 def __init__(self, test, epg, recirc, is_ext=False):
170 def add_vpp_config(self):
171 self._test.vapi.gbp_recirc_add_del(
173 self.recirc.sw_if_index,
176 self._test.registry.register(self, self._test.logger)
178 def remove_vpp_config(self):
179 self._test.vapi.gbp_recirc_add_del(
181 self.recirc.sw_if_index,
186 return self.object_id()
189 return "gbp-recirc:[%d]" % (self.recirc.sw_if_index)
191 def query_vpp_config(self):
192 rs = self._test.vapi.gbp_recirc_dump()
194 if r.recirc.sw_if_index == self.recirc.sw_if_index:
199 class VppGbpSubnet(VppObject):
203 def __init__(self, test, rd, address, address_len,
204 type, sw_if_index=None, epg=None):
206 self.rd_id = rd.rd_id
207 self.prefix = VppIpPrefix(address, address_len)
209 self.sw_if_index = sw_if_index
212 def add_vpp_config(self):
213 self._test.vapi.gbp_subnet_add_del(
216 self.prefix.encode(),
218 sw_if_index=self.sw_if_index if self.sw_if_index else 0xffffffff,
219 epg_id=self.epg if self.epg else 0xffff)
220 self._test.registry.register(self, self._test.logger)
222 def remove_vpp_config(self):
223 self._test.vapi.gbp_subnet_add_del(
226 self.prefix.encode(),
230 return self.object_id()
233 return "gbp-subnet:[%d-%s]" % (self.rd_id, self.prefix)
235 def query_vpp_config(self):
236 ss = self._test.vapi.gbp_subnet_dump()
238 if s.subnet.rd_id == self.rd_id and \
239 s.subnet.type == self.type and \
240 s.subnet.prefix == self.prefix:
245 class VppGbpEndpointGroup(VppObject):
250 def __init__(self, test, epg, rd, bd, uplink,
251 bvi, bvi_ip4, bvi_ip6=None):
255 self.bvi_ip4 = VppIpAddress(bvi_ip4)
256 self.bvi_ip6 = VppIpAddress(bvi_ip6)
261 def add_vpp_config(self):
262 self._test.vapi.gbp_endpoint_group_add(
266 self.uplink.sw_if_index if self.uplink else INDEX_INVALID)
267 self._test.registry.register(self, self._test.logger)
269 def remove_vpp_config(self):
270 self._test.vapi.gbp_endpoint_group_del(
274 return self.object_id()
277 return "gbp-endpoint-group:[%d]" % (self.epg)
279 def query_vpp_config(self):
280 epgs = self._test.vapi.gbp_endpoint_group_dump()
282 if epg.epg.epg_id == self.epg:
287 class VppGbpBridgeDomain(VppObject):
292 def __init__(self, test, bd, bvi, uu_flood=None, learn=True):
295 self.uu_flood = uu_flood
298 e = VppEnum.vl_api_gbp_bridge_domain_flags_t
300 self.learn = e.GBP_BD_API_FLAG_NONE
302 self.learn = e.GBP_BD_API_FLAG_DO_NOT_LEARN
304 def add_vpp_config(self):
305 self._test.vapi.gbp_bridge_domain_add(
308 self.bvi.sw_if_index,
309 self.uu_flood.sw_if_index if self.uu_flood else INDEX_INVALID)
310 self._test.registry.register(self, self._test.logger)
312 def remove_vpp_config(self):
313 self._test.vapi.gbp_bridge_domain_del(self.bd.bd_id)
316 return self.object_id()
319 return "gbp-bridge-domain:[%d]" % (self.bd.bd_id)
321 def query_vpp_config(self):
322 bds = self._test.vapi.gbp_bridge_domain_dump()
324 if bd.bd.bd_id == self.bd.bd_id:
329 class VppGbpRouteDomain(VppObject):
334 def __init__(self, test, rd_id, t4, t6, ip4_uu=None, ip6_uu=None):
342 def add_vpp_config(self):
343 self._test.vapi.gbp_route_domain_add(
347 self.ip4_uu.sw_if_index if self.ip4_uu else INDEX_INVALID,
348 self.ip6_uu.sw_if_index if self.ip6_uu else INDEX_INVALID)
349 self._test.registry.register(self, self._test.logger)
351 def remove_vpp_config(self):
352 self._test.vapi.gbp_route_domain_del(self.rd_id)
355 return self.object_id()
358 return "gbp-route-domain:[%d]" % (self.rd_id)
360 def query_vpp_config(self):
361 rds = self._test.vapi.gbp_route_domain_dump()
363 if rd.rd.rd_id == self.rd_id:
368 class VppGbpContract(VppObject):
373 def __init__(self, test, src_epg, dst_epg, acl_index):
375 self.acl_index = acl_index
376 self.src_epg = src_epg
377 self.dst_epg = dst_epg
379 def add_vpp_config(self):
380 self._test.vapi.gbp_contract_add_del(
385 self._test.registry.register(self, self._test.logger)
387 def remove_vpp_config(self):
388 self._test.vapi.gbp_contract_add_del(
395 return self.object_id()
398 return "gbp-contract:[%d:%s:%d]" % (self.src_epg,
402 def query_vpp_config(self):
403 cs = self._test.vapi.gbp_contract_dump()
405 if c.contract.src_epg == self.src_epg \
406 and c.contract.dst_epg == self.dst_epg:
411 class VppGbpVxlanTunnel(VppInterface):
416 def __init__(self, test, vni, bd_rd_id, mode):
417 super(VppGbpVxlanTunnel, self).__init__(test)
420 self.bd_rd_id = bd_rd_id
423 def add_vpp_config(self):
424 r = self._test.vapi.gbp_vxlan_tunnel_add(
428 self.set_sw_if_index(r.sw_if_index)
429 self._test.registry.register(self, self._test.logger)
431 def remove_vpp_config(self):
432 self._test.vapi.gbp_vxlan_tunnel_del(self.vni)
435 return self.object_id()
438 return "gbp-vxlan:%d" % (self.vni)
440 def query_vpp_config(self):
441 return find_gbp_vxlan(self._test, self.vni)
444 class VppGbpAcl(VppObject):
449 def __init__(self, test):
451 self.acl_index = 4294967295
453 def create_rule(self, is_ipv6=0, permit_deny=0, proto=-1,
454 s_prefix=0, s_ip='\x00\x00\x00\x00', sport_from=0,
455 sport_to=65535, d_prefix=0, d_ip='\x00\x00\x00\x00',
456 dport_from=0, dport_to=65535):
457 if proto == -1 or proto == 0:
460 elif proto == 1 or proto == 58:
463 rule = ({'is_permit': permit_deny, 'is_ipv6': is_ipv6, 'proto': proto,
464 'srcport_or_icmptype_first': sport_from,
465 'srcport_or_icmptype_last': sport_to,
466 'src_ip_prefix_len': s_prefix,
468 'dstport_or_icmpcode_first': dport_from,
469 'dstport_or_icmpcode_last': dport_to,
470 'dst_ip_prefix_len': d_prefix,
471 'dst_ip_addr': d_ip})
474 def add_vpp_config(self, rules):
476 reply = self._test.vapi.acl_add_replace(self.acl_index,
479 self.acl_index = reply.acl_index
480 return self.acl_index
482 def remove_vpp_config(self):
483 self._test.vapi.acl_del(self.acl_index)
486 return self.object_id()
489 return "gbp-acl:[%d]" % (self.acl_index)
491 def query_vpp_config(self):
492 cs = self._test.vapi.acl_dump()
494 if c.acl_index == self.acl_index:
499 class TestGBP(VppTestCase):
500 """ GBP Test Case """
503 super(TestGBP, self).setUp()
505 self.create_pg_interfaces(range(9))
506 self.create_loopback_interfaces(8)
508 self.router_mac = VppMacAddress("00:11:22:33:44:55")
510 for i in self.pg_interfaces:
512 for i in self.lo_interfaces:
516 for i in self.pg_interfaces:
519 super(TestGBP, self).tearDown()
521 def send_and_expect_bridged(self, src, tx, dst):
522 rx = self.send_and_expect(src, tx, dst)
525 self.assertEqual(r[Ether].src, tx[0][Ether].src)
526 self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
527 self.assertEqual(r[IP].src, tx[0][IP].src)
528 self.assertEqual(r[IP].dst, tx[0][IP].dst)
531 def send_and_expect_bridged6(self, src, tx, dst):
532 rx = self.send_and_expect(src, tx, dst)
535 self.assertEqual(r[Ether].src, tx[0][Ether].src)
536 self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
537 self.assertEqual(r[IPv6].src, tx[0][IPv6].src)
538 self.assertEqual(r[IPv6].dst, tx[0][IPv6].dst)
541 def send_and_expect_routed(self, src, tx, dst, src_mac):
542 rx = self.send_and_expect(src, tx, dst)
545 self.assertEqual(r[Ether].src, src_mac)
546 self.assertEqual(r[Ether].dst, dst.remote_mac)
547 self.assertEqual(r[IP].src, tx[0][IP].src)
548 self.assertEqual(r[IP].dst, tx[0][IP].dst)
551 def send_and_expect_natted(self, src, tx, dst, src_ip):
552 rx = self.send_and_expect(src, tx, dst)
555 self.assertEqual(r[Ether].src, tx[0][Ether].src)
556 self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
557 self.assertEqual(r[IP].src, src_ip)
558 self.assertEqual(r[IP].dst, tx[0][IP].dst)
561 def send_and_expect_natted6(self, src, tx, dst, src_ip):
562 rx = self.send_and_expect(src, tx, dst)
565 self.assertEqual(r[Ether].src, tx[0][Ether].src)
566 self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
567 self.assertEqual(r[IPv6].src, src_ip)
568 self.assertEqual(r[IPv6].dst, tx[0][IPv6].dst)
571 def send_and_expect_unnatted(self, src, tx, dst, dst_ip):
572 rx = self.send_and_expect(src, tx, dst)
575 self.assertEqual(r[Ether].src, tx[0][Ether].src)
576 self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
577 self.assertEqual(r[IP].dst, dst_ip)
578 self.assertEqual(r[IP].src, tx[0][IP].src)
581 def send_and_expect_unnatted6(self, src, tx, dst, dst_ip):
582 rx = self.send_and_expect(src, tx, dst)
585 self.assertEqual(r[Ether].src, tx[0][Ether].src)
586 self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
587 self.assertEqual(r[IPv6].dst, dst_ip)
588 self.assertEqual(r[IPv6].src, tx[0][IPv6].src)
591 def send_and_expect_double_natted(self, src, tx, dst, src_ip, dst_ip):
592 rx = self.send_and_expect(src, tx, dst)
595 self.assertEqual(r[Ether].src, self.router_mac.address)
596 self.assertEqual(r[Ether].dst, dst.remote_mac)
597 self.assertEqual(r[IP].dst, dst_ip)
598 self.assertEqual(r[IP].src, src_ip)
601 def send_and_expect_double_natted6(self, src, tx, dst, src_ip, dst_ip):
602 rx = self.send_and_expect(src, tx, dst)
605 self.assertEqual(r[Ether].src, self.router_mac.address)
606 self.assertEqual(r[Ether].dst, dst.remote_mac)
607 self.assertEqual(r[IPv6].dst, dst_ip)
608 self.assertEqual(r[IPv6].src, src_ip)
612 """ Group Based Policy """
617 bd1 = VppBridgeDomain(self, 1)
618 bd2 = VppBridgeDomain(self, 2)
619 bd20 = VppBridgeDomain(self, 20)
623 bd20.add_vpp_config()
625 gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0)
626 gbd2 = VppGbpBridgeDomain(self, bd2, self.loop1)
627 gbd20 = VppGbpBridgeDomain(self, bd20, self.loop2)
629 gbd1.add_vpp_config()
630 gbd2.add_vpp_config()
631 gbd20.add_vpp_config()
636 gt4 = VppIpTable(self, 0)
638 gt6 = VppIpTable(self, 0, is_ip6=True)
640 nt4 = VppIpTable(self, 20)
642 nt6 = VppIpTable(self, 20, is_ip6=True)
645 rd0 = VppGbpRouteDomain(self, 0, gt4, gt6, None, None)
646 rd20 = VppGbpRouteDomain(self, 20, nt4, nt6, None, None)
649 rd20.add_vpp_config()
652 # 3 EPGs, 2 of which share a BD.
653 # 2 NAT EPGs, one for floating-IP subnets, the other for internet
655 epgs = [VppGbpEndpointGroup(self, 220, rd0, gbd1, self.pg4,
659 VppGbpEndpointGroup(self, 221, rd0, gbd1, self.pg5,
663 VppGbpEndpointGroup(self, 222, rd0, gbd2, self.pg6,
667 VppGbpEndpointGroup(self, 333, rd20, gbd20, self.pg7,
671 VppGbpEndpointGroup(self, 444, rd20, gbd20, self.pg8,
675 recircs = [VppGbpRecirc(self, epgs[0],
677 VppGbpRecirc(self, epgs[1],
679 VppGbpRecirc(self, epgs[2],
681 VppGbpRecirc(self, epgs[3],
682 self.loop6, is_ext=True),
683 VppGbpRecirc(self, epgs[4],
684 self.loop7, is_ext=True)]
687 recirc_nat = recircs[3]
690 # 4 end-points, 2 in the same subnet, 3 in the same BD
692 eps = [VppGbpEndpoint(self, self.pg0,
694 "10.0.0.1", "11.0.0.1",
695 "2001:10::1", "3001::1"),
696 VppGbpEndpoint(self, self.pg1,
698 "10.0.0.2", "11.0.0.2",
699 "2001:10::2", "3001::2"),
700 VppGbpEndpoint(self, self.pg2,
702 "10.0.1.1", "11.0.0.3",
703 "2001:10:1::1", "3001::3"),
704 VppGbpEndpoint(self, self.pg3,
706 "10.0.2.1", "11.0.0.4",
707 "2001:10:2::1", "3001::4")]
710 # Config related to each of the EPGs
713 # IP config on the BVI interfaces
714 if epg != epgs[1] and epg != epgs[4]:
715 VppIpInterfaceBind(self, epg.bvi, epg.rd.t4).add_vpp_config()
716 VppIpInterfaceBind(self, epg.bvi, epg.rd.t6).add_vpp_config()
717 self.vapi.sw_interface_set_mac_address(
719 self.router_mac.bytes)
721 # The BVIs are NAT inside interfaces
722 self.vapi.nat44_interface_add_del_feature(epg.bvi.sw_if_index,
725 self.vapi.nat66_add_del_interface(epg.bvi.sw_if_index,
729 if_ip4 = VppIpInterfaceAddress(self, epg.bvi, epg.bvi_ip4, 32)
730 if_ip6 = VppIpInterfaceAddress(self, epg.bvi, epg.bvi_ip6, 128)
731 if_ip4.add_vpp_config()
732 if_ip6.add_vpp_config()
734 # EPG uplink interfaces in the RD
735 VppIpInterfaceBind(self, epg.uplink, epg.rd.t4).add_vpp_config()
736 VppIpInterfaceBind(self, epg.uplink, epg.rd.t6).add_vpp_config()
738 # add the BD ARP termination entry for BVI IP
739 epg.bd_arp_ip4 = VppBridgeDomainArpEntry(self, epg.bd.bd,
740 self.router_mac.address,
742 epg.bd_arp_ip6 = VppBridgeDomainArpEntry(self, epg.bd.bd,
743 self.router_mac.address,
745 epg.bd_arp_ip4.add_vpp_config()
746 epg.bd_arp_ip6.add_vpp_config()
751 for recirc in recircs:
752 # EPG's ingress recirculation interface maps to its RD
753 VppIpInterfaceBind(self, recirc.recirc,
754 recirc.epg.rd.t4).add_vpp_config()
755 VppIpInterfaceBind(self, recirc.recirc,
756 recirc.epg.rd.t6).add_vpp_config()
758 self.vapi.sw_interface_set_l2_emulation(
759 recirc.recirc.sw_if_index)
760 self.vapi.nat44_interface_add_del_feature(
761 recirc.recirc.sw_if_index,
764 self.vapi.nat66_add_del_interface(
765 recirc.recirc.sw_if_index,
769 recirc.add_vpp_config()
771 for recirc in recircs:
772 self.assertTrue(find_bridge_domain_port(self,
773 recirc.epg.bd.bd.bd_id,
774 recirc.recirc.sw_if_index))
777 self.pg_enable_capture(self.pg_interfaces)
780 # routes to the endpoints. We need these since there are no
781 # adj-fibs due to the fact the the BVI address has /32 and
782 # the subnet is not attached.
784 for (ip, fip) in zip(ep.ips, ep.fips):
785 # Add static mappings for each EP from the 10/8 to 11/8 network
787 self.vapi.nat44_add_del_static_mapping(ip.bytes,
792 self.vapi.nat66_add_del_static_mapping(ip.bytes,
799 self.logger.info(self.vapi.cli("sh gbp endpoint"))
801 # ... results in a Gratuitous ARP/ND on the EPG's uplink
802 rx = ep.epg.uplink.get_capture(len(ep.ips), timeout=0.2)
804 for ii, ip in enumerate(ep.ips):
808 self.assertTrue(p.haslayer(ICMPv6ND_NA))
809 self.assertEqual(p[ICMPv6ND_NA].tgt, ip.address)
811 self.assertTrue(p.haslayer(ARP))
812 self.assertEqual(p[ARP].psrc, ip.address)
813 self.assertEqual(p[ARP].pdst, ip.address)
815 # add the BD ARP termination entry for floating IP
817 ba = VppBridgeDomainArpEntry(self, epg_nat.bd.bd, ep.mac, fip)
820 # floating IPs route via EPG recirc
821 r = VppIpRoute(self, fip.address, fip.length,
822 [VppRoutePath(fip.address,
823 ep.recirc.recirc.sw_if_index,
825 proto=fip.dpo_proto)],
830 # L2 FIB entries in the NAT EPG BD to bridge the packets from
831 # the outside direct to the internal EPG
832 lf = VppL2FibEntry(self, epg_nat.bd.bd, ep.mac,
833 ep.recirc.recirc, bvi_mac=0)
837 # ARP packets for unknown IP are sent to the EPG uplink
839 pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff",
840 src=self.pg0.remote_mac) /
842 hwdst="ff:ff:ff:ff:ff:ff",
843 hwsrc=self.pg0.remote_mac,
847 self.vapi.cli("clear trace")
848 self.pg0.add_stream(pkt_arp)
850 self.pg_enable_capture(self.pg_interfaces)
853 rxd = epgs[0].uplink.get_capture(1)
856 # ARP/ND packets get a response
858 pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff",
859 src=self.pg0.remote_mac) /
861 hwdst="ff:ff:ff:ff:ff:ff",
862 hwsrc=self.pg0.remote_mac,
863 pdst=epgs[0].bvi_ip4.address,
864 psrc=eps[0].ip4.address))
866 self.send_and_expect(self.pg0, [pkt_arp], self.pg0)
868 nsma = in6_getnsma(inet_pton(AF_INET6, eps[0].ip6.address))
869 d = inet_ntop(AF_INET6, nsma)
870 pkt_nd = (Ether(dst=in6_getnsmac(nsma),
871 src=self.pg0.remote_mac) /
872 IPv6(dst=d, src=eps[0].ip6.address) /
873 ICMPv6ND_NS(tgt=epgs[0].bvi_ip6.address) /
874 ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac))
875 self.send_and_expect(self.pg0, [pkt_nd], self.pg0)
878 # broadcast packets are flooded
880 pkt_bcast = (Ether(dst="ff:ff:ff:ff:ff:ff",
881 src=self.pg0.remote_mac) /
882 IP(src=eps[0].ip4.address, dst="232.1.1.1") /
883 UDP(sport=1234, dport=1234) /
886 self.vapi.cli("clear trace")
887 self.pg0.add_stream(pkt_bcast)
889 self.pg_enable_capture(self.pg_interfaces)
892 rxd = eps[1].itf.get_capture(1)
893 self.assertEqual(rxd[0][Ether].dst, pkt_bcast[Ether].dst)
894 rxd = epgs[0].uplink.get_capture(1)
895 self.assertEqual(rxd[0][Ether].dst, pkt_bcast[Ether].dst)
898 # packets to non-local L3 destinations dropped
900 pkt_intra_epg_220_ip4 = (Ether(src=self.pg0.remote_mac,
901 dst=self.router_mac.address) /
902 IP(src=eps[0].ip4.address,
904 UDP(sport=1234, dport=1234) /
906 pkt_inter_epg_222_ip4 = (Ether(src=self.pg0.remote_mac,
907 dst=self.router_mac.address) /
908 IP(src=eps[0].ip4.address,
910 UDP(sport=1234, dport=1234) /
913 self.send_and_assert_no_replies(self.pg0, pkt_intra_epg_220_ip4 * 65)
915 pkt_inter_epg_222_ip6 = (Ether(src=self.pg0.remote_mac,
916 dst=self.router_mac.address) /
917 IPv6(src=eps[0].ip6.address,
919 UDP(sport=1234, dport=1234) /
921 self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_222_ip6 * 65)
924 # Add the subnet routes
927 self, rd0, "10.0.0.0", 24,
928 VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
930 self, rd0, "10.0.1.0", 24,
931 VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
933 self, rd0, "10.0.2.0", 24,
934 VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
936 self, rd0, "2001:10::1", 64,
937 VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
939 self, rd0, "2001:10:1::1", 64,
940 VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
942 self, rd0, "2001:10:2::1", 64,
943 VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
951 self.send_and_expect_bridged(eps[0].itf,
952 pkt_intra_epg_220_ip4 * 65,
954 self.send_and_expect_bridged(eps[0].itf,
955 pkt_inter_epg_222_ip4 * 65,
957 self.send_and_expect_bridged6(eps[0].itf,
958 pkt_inter_epg_222_ip6 * 65,
961 self.logger.info(self.vapi.cli("sh ip fib 11.0.0.2"))
962 self.logger.info(self.vapi.cli("sh gbp endpoint-group"))
963 self.logger.info(self.vapi.cli("sh gbp endpoint"))
964 self.logger.info(self.vapi.cli("sh gbp recirc"))
965 self.logger.info(self.vapi.cli("sh int"))
966 self.logger.info(self.vapi.cli("sh int addr"))
967 self.logger.info(self.vapi.cli("sh int feat loop6"))
968 self.logger.info(self.vapi.cli("sh vlib graph ip4-gbp-src-classify"))
969 self.logger.info(self.vapi.cli("sh int feat loop3"))
970 self.logger.info(self.vapi.cli("sh int feat pg0"))
973 # Packet destined to unknown unicast is sent on the epg uplink ...
975 pkt_intra_epg_220_to_uplink = (Ether(src=self.pg0.remote_mac,
976 dst="00:00:00:33:44:55") /
977 IP(src=eps[0].ip4.address,
979 UDP(sport=1234, dport=1234) /
982 self.send_and_expect_bridged(eps[0].itf,
983 pkt_intra_epg_220_to_uplink * 65,
985 # ... and nowhere else
986 self.pg1.get_capture(0, timeout=0.1)
987 self.pg1.assert_nothing_captured(remark="Flood onto other VMS")
989 pkt_intra_epg_221_to_uplink = (Ether(src=self.pg2.remote_mac,
990 dst="00:00:00:33:44:66") /
991 IP(src=eps[0].ip4.address,
993 UDP(sport=1234, dport=1234) /
996 self.send_and_expect_bridged(eps[2].itf,
997 pkt_intra_epg_221_to_uplink * 65,
1001 # Packets from the uplink are forwarded in the absence of a contract
1003 pkt_intra_epg_220_from_uplink = (Ether(src="00:00:00:33:44:55",
1004 dst=self.pg0.remote_mac) /
1005 IP(src=eps[0].ip4.address,
1007 UDP(sport=1234, dport=1234) /
1010 self.send_and_expect_bridged(self.pg4,
1011 pkt_intra_epg_220_from_uplink * 65,
1015 # in the absence of policy, endpoints in the same EPG
1018 pkt_intra_epg = (Ether(src=self.pg0.remote_mac,
1019 dst=self.pg1.remote_mac) /
1020 IP(src=eps[0].ip4.address,
1021 dst=eps[1].ip4.address) /
1022 UDP(sport=1234, dport=1234) /
1025 self.send_and_expect_bridged(self.pg0, pkt_intra_epg * 65, self.pg1)
1028 # in the abscense of policy, endpoints in the different EPG
1029 # cannot communicate
1031 pkt_inter_epg_220_to_221 = (Ether(src=self.pg0.remote_mac,
1032 dst=self.pg2.remote_mac) /
1033 IP(src=eps[0].ip4.address,
1034 dst=eps[2].ip4.address) /
1035 UDP(sport=1234, dport=1234) /
1037 pkt_inter_epg_221_to_220 = (Ether(src=self.pg2.remote_mac,
1038 dst=self.pg0.remote_mac) /
1039 IP(src=eps[2].ip4.address,
1040 dst=eps[0].ip4.address) /
1041 UDP(sport=1234, dport=1234) /
1043 pkt_inter_epg_220_to_222 = (Ether(src=self.pg0.remote_mac,
1044 dst=self.router_mac.address) /
1045 IP(src=eps[0].ip4.address,
1046 dst=eps[3].ip4.address) /
1047 UDP(sport=1234, dport=1234) /
1050 self.send_and_assert_no_replies(eps[0].itf,
1051 pkt_inter_epg_220_to_221 * 65)
1052 self.send_and_assert_no_replies(eps[0].itf,
1053 pkt_inter_epg_220_to_222 * 65)
1056 # A uni-directional contract from EPG 220 -> 221
1058 acl = VppGbpAcl(self)
1059 rule = acl.create_rule(permit_deny=1, proto=17)
1060 rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
1061 acl_index = acl.add_vpp_config([rule, rule2])
1062 c1 = VppGbpContract(self, 220, 221, acl_index)
1065 self.send_and_expect_bridged(eps[0].itf,
1066 pkt_inter_epg_220_to_221 * 65,
1068 self.send_and_assert_no_replies(eps[0].itf,
1069 pkt_inter_epg_220_to_222 * 65)
1072 # contract for the return direction
1074 c2 = VppGbpContract(self, 221, 220, acl_index)
1077 self.send_and_expect_bridged(eps[0].itf,
1078 pkt_inter_epg_220_to_221 * 65,
1080 self.send_and_expect_bridged(eps[2].itf,
1081 pkt_inter_epg_221_to_220 * 65,
1085 # check that inter group is still disabled for the groups
1086 # not in the contract.
1088 self.send_and_assert_no_replies(eps[0].itf,
1089 pkt_inter_epg_220_to_222 * 65)
1092 # A uni-directional contract from EPG 220 -> 222 'L3 routed'
1094 c3 = VppGbpContract(self, 220, 222, acl_index)
1097 self.logger.info(self.vapi.cli("sh gbp contract"))
1099 self.send_and_expect_routed(eps[0].itf,
1100 pkt_inter_epg_220_to_222 * 65,
1102 self.router_mac.address)
1105 # remove both contracts, traffic stops in both directions
1107 c2.remove_vpp_config()
1108 c1.remove_vpp_config()
1109 c3.remove_vpp_config()
1110 acl.remove_vpp_config()
1112 self.send_and_assert_no_replies(eps[2].itf,
1113 pkt_inter_epg_221_to_220 * 65)
1114 self.send_and_assert_no_replies(eps[0].itf,
1115 pkt_inter_epg_220_to_221 * 65)
1116 self.send_and_expect_bridged(eps[0].itf,
1121 # EPs to the outside world
1124 # in the EP's RD an external subnet via the NAT EPG's recirc
1126 self, rd0, "0.0.0.0", 0,
1127 VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1128 sw_if_index=recirc_nat.recirc.sw_if_index,
1131 self, rd0, "11.0.0.0", 8,
1132 VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1133 sw_if_index=recirc_nat.recirc.sw_if_index,
1135 se16 = VppGbpSubnet(
1137 VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1138 sw_if_index=recirc_nat.recirc.sw_if_index,
1140 # in the NAT RD an external subnet via the NAT EPG's uplink
1142 self, rd20, "0.0.0.0", 0,
1143 VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1144 sw_if_index=epg_nat.uplink.sw_if_index,
1146 se36 = VppGbpSubnet(
1147 self, rd20, "::", 0,
1148 VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1149 sw_if_index=epg_nat.uplink.sw_if_index,
1152 self, rd20, "11.0.0.0", 8,
1153 VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1154 sw_if_index=epg_nat.uplink.sw_if_index,
1156 se1.add_vpp_config()
1157 se2.add_vpp_config()
1158 se16.add_vpp_config()
1159 se3.add_vpp_config()
1160 se36.add_vpp_config()
1161 se4.add_vpp_config()
1163 self.logger.info(self.vapi.cli("sh ip fib 0.0.0.0/0"))
1164 self.logger.info(self.vapi.cli("sh ip fib 11.0.0.1"))
1165 self.logger.info(self.vapi.cli("sh ip6 fib ::/0"))
1166 self.logger.info(self.vapi.cli("sh ip6 fib %s" %
1170 # From an EP to an outside addess: IN2OUT
1172 pkt_inter_epg_220_to_global = (Ether(src=self.pg0.remote_mac,
1173 dst=self.router_mac.address) /
1174 IP(src=eps[0].ip4.address,
1176 UDP(sport=1234, dport=1234) /
1180 self.send_and_assert_no_replies(eps[0].itf,
1181 pkt_inter_epg_220_to_global * 65)
1183 acl2 = VppGbpAcl(self)
1184 rule = acl2.create_rule(permit_deny=1, proto=17, sport_from=1234,
1185 sport_to=1234, dport_from=1234, dport_to=1234)
1186 rule2 = acl2.create_rule(is_ipv6=1, permit_deny=1, proto=17,
1187 sport_from=1234, sport_to=1234,
1188 dport_from=1234, dport_to=1234)
1190 acl_index2 = acl2.add_vpp_config([rule, rule2])
1191 c4 = VppGbpContract(self, 220, 333, acl_index2)
1194 self.send_and_expect_natted(eps[0].itf,
1195 pkt_inter_epg_220_to_global * 65,
1197 eps[0].fip4.address)
1199 pkt_inter_epg_220_to_global = (Ether(src=self.pg0.remote_mac,
1200 dst=self.router_mac.address) /
1201 IPv6(src=eps[0].ip6.address,
1203 UDP(sport=1234, dport=1234) /
1206 self.send_and_expect_natted6(self.pg0,
1207 pkt_inter_epg_220_to_global * 65,
1209 eps[0].fip6.address)
1212 # From a global address to an EP: OUT2IN
1214 pkt_inter_epg_220_from_global = (Ether(src=self.router_mac.address,
1215 dst=self.pg0.remote_mac) /
1216 IP(dst=eps[0].fip4.address,
1218 UDP(sport=1234, dport=1234) /
1221 self.send_and_assert_no_replies(self.pg7,
1222 pkt_inter_epg_220_from_global * 65)
1224 c5 = VppGbpContract(self, 333, 220, acl_index2)
1227 self.send_and_expect_unnatted(self.pg7,
1228 pkt_inter_epg_220_from_global * 65,
1232 pkt_inter_epg_220_from_global = (Ether(src=self.router_mac.address,
1233 dst=self.pg0.remote_mac) /
1234 IPv6(dst=eps[0].fip6.address,
1236 UDP(sport=1234, dport=1234) /
1239 self.send_and_expect_unnatted6(self.pg7,
1240 pkt_inter_epg_220_from_global * 65,
1245 # From a local VM to another local VM using resp. public addresses:
1248 pkt_intra_epg_220_global = (Ether(src=self.pg0.remote_mac,
1249 dst=self.router_mac.address) /
1250 IP(src=eps[0].ip4.address,
1251 dst=eps[1].fip4.address) /
1252 UDP(sport=1234, dport=1234) /
1255 self.send_and_expect_double_natted(eps[0].itf,
1256 pkt_intra_epg_220_global * 65,
1258 eps[0].fip4.address,
1261 pkt_intra_epg_220_global = (Ether(src=self.pg0.remote_mac,
1262 dst=self.router_mac.address) /
1263 IPv6(src=eps[0].ip6.address,
1264 dst=eps[1].fip6.address) /
1265 UDP(sport=1234, dport=1234) /
1268 self.send_and_expect_double_natted6(eps[0].itf,
1269 pkt_intra_epg_220_global * 65,
1271 eps[0].fip6.address,
1278 # del static mappings for each EP from the 10/8 to 11/8 network
1279 self.vapi.nat44_add_del_static_mapping(ep.ip4.bytes,
1284 self.vapi.nat66_add_del_static_mapping(ep.ip6.bytes,
1290 # IP config on the BVI interfaces
1291 if epg != epgs[0] and epg != epgs[3]:
1292 self.vapi.nat44_interface_add_del_feature(epg.bvi.sw_if_index,
1295 self.vapi.nat66_add_del_interface(epg.bvi.sw_if_index,
1299 for recirc in recircs:
1300 self.vapi.sw_interface_set_l2_emulation(
1301 recirc.recirc.sw_if_index, enable=0)
1302 self.vapi.nat44_interface_add_del_feature(
1303 recirc.recirc.sw_if_index,
1306 self.vapi.nat66_add_del_interface(
1307 recirc.recirc.sw_if_index,
1311 def test_gbp_learn_l2(self):
1312 """ GBP L2 Endpoint Learning """
1314 learnt = [{'mac': '00:00:11:11:11:01',
1316 'ip6': '2001:10::2'},
1317 {'mac': '00:00:11:11:11:02',
1319 'ip6': '2001:10::3'}]
1322 # lower the inactive threshold so these tests pass in a
1323 # reasonable amount of time
1325 self.vapi.gbp_endpoint_learn_set_inactive_threshold(1)
1330 gt4 = VppIpTable(self, 1)
1331 gt4.add_vpp_config()
1332 gt6 = VppIpTable(self, 1, is_ip6=True)
1333 gt6.add_vpp_config()
1335 rd1 = VppGbpRouteDomain(self, 1, gt4, gt6)
1336 rd1.add_vpp_config()
1339 # Pg2 hosts the vxlan tunnel, hosts on pg2 to act as TEPs
1340 # Pg3 hosts the IP4 UU-flood VXLAN tunnel
1341 # Pg4 hosts the IP6 UU-flood VXLAN tunnel
1343 self.pg2.config_ip4()
1344 self.pg2.resolve_arp()
1345 self.pg2.generate_remote_hosts(4)
1346 self.pg2.configure_ipv4_neighbors()
1347 self.pg3.config_ip4()
1348 self.pg3.resolve_arp()
1349 self.pg4.config_ip4()
1350 self.pg4.resolve_arp()
1353 # a GBP bridge domain with a BVI and a UU-flood interface
1355 bd1 = VppBridgeDomain(self, 1)
1356 bd1.add_vpp_config()
1357 gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0, self.pg3)
1358 gbd1.add_vpp_config()
1360 self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1361 self.logger.info(self.vapi.cli("sh gbp bridge"))
1363 # ... and has a /32 applied
1364 ip_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
1365 ip_addr.add_vpp_config()
1368 # The Endpoint-group in which we are learning endpoints
1370 epg_220 = VppGbpEndpointGroup(self, 220, rd1, gbd1,
1374 epg_220.add_vpp_config()
1375 epg_330 = VppGbpEndpointGroup(self, 330, rd1, gbd1,
1379 epg_330.add_vpp_config()
1382 # The VXLAN GBP tunnel is a bridge-port and has L2 endpoint
1385 vx_tun_l2_1 = VppGbpVxlanTunnel(
1386 self, 99, bd1.bd_id,
1387 VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L2)
1388 vx_tun_l2_1.add_vpp_config()
1391 # A static endpoint that the learnt endpoints are trying to
1394 ep = VppGbpEndpoint(self, self.pg0,
1396 "10.0.0.127", "11.0.0.127",
1397 "2001:10::1", "3001::1")
1400 self.assertTrue(find_route(self, ep.ip4.address, 32, table_id=1))
1402 # a packet with an sclass from an unknwon EPG
1403 p = (Ether(src=self.pg2.remote_mac,
1404 dst=self.pg2.local_mac) /
1405 IP(src=self.pg2.remote_hosts[0].ip4,
1406 dst=self.pg2.local_ip4) /
1407 UDP(sport=1234, dport=48879) /
1408 VXLAN(vni=99, gpid=88, flags=0x88) /
1409 Ether(src=learnt[0]["mac"], dst=ep.mac) /
1410 IP(src=learnt[0]["ip"], dst=ep.ip4.address) /
1411 UDP(sport=1234, dport=1234) /
1414 self.send_and_assert_no_replies(self.pg2, p)
1417 # we should not have learnt a new tunnel endpoint, since
1418 # the EPG was not learnt.
1420 self.assertEqual(INDEX_INVALID,
1421 find_vxlan_gbp_tunnel(self,
1423 self.pg2.remote_hosts[0].ip4,
1426 # epg is not learnt, becasue the EPG is unknwon
1427 self.assertEqual(len(self.vapi.gbp_endpoint_dump()), 1)
1429 for ii, l in enumerate(learnt):
1430 # a packet with an sclass from a knwon EPG
1431 # arriving on an unknown TEP
1432 p = (Ether(src=self.pg2.remote_mac,
1433 dst=self.pg2.local_mac) /
1434 IP(src=self.pg2.remote_hosts[1].ip4,
1435 dst=self.pg2.local_ip4) /
1436 UDP(sport=1234, dport=48879) /
1437 VXLAN(vni=99, gpid=220, flags=0x88) /
1438 Ether(src=l['mac'], dst=ep.mac) /
1439 IP(src=l['ip'], dst=ep.ip4.address) /
1440 UDP(sport=1234, dport=1234) /
1443 rx = self.send_and_expect(self.pg2, [p], self.pg0)
1446 tep1_sw_if_index = find_vxlan_gbp_tunnel(
1449 self.pg2.remote_hosts[1].ip4,
1451 self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
1454 # the EP is learnt via the learnt TEP
1455 # both from its MAC and its IP
1457 self.assertTrue(find_gbp_endpoint(self,
1458 vx_tun_l2_1.sw_if_index,
1460 self.assertTrue(find_gbp_endpoint(self,
1461 vx_tun_l2_1.sw_if_index,
1464 self.logger.info(self.vapi.cli("show gbp endpoint"))
1465 self.logger.info(self.vapi.cli("show gbp vxlan"))
1466 self.logger.info(self.vapi.cli("show vxlan-gbp tunnel"))
1469 # If we sleep for the threshold time, the learnt endpoints should
1474 self.assertFalse(find_gbp_endpoint(self,
1478 self.logger.info(self.vapi.cli("show gbp endpoint"))
1479 self.logger.info(self.vapi.cli("show gbp vxlan"))
1480 self.logger.info(self.vapi.cli("show vxlan-gbp tunnel"))
1483 # repeat. the do not learn bit is set so the EPs are not learnt
1486 # a packet with an sclass from a knwon EPG
1487 p = (Ether(src=self.pg2.remote_mac,
1488 dst=self.pg2.local_mac) /
1489 IP(src=self.pg2.remote_hosts[1].ip4,
1490 dst=self.pg2.local_ip4) /
1491 UDP(sport=1234, dport=48879) /
1492 VXLAN(vni=99, gpid=220, flags=0x88, gpflags="D") /
1493 Ether(src=l['mac'], dst=ep.mac) /
1494 IP(src=l['ip'], dst=ep.ip4.address) /
1495 UDP(sport=1234, dport=1234) /
1498 rx = self.send_and_expect(self.pg2, p*65, self.pg0)
1501 self.assertFalse(find_gbp_endpoint(self,
1502 vx_tun_l2_1.sw_if_index,
1509 # a packet with an sclass from a knwon EPG
1510 p = (Ether(src=self.pg2.remote_mac,
1511 dst=self.pg2.local_mac) /
1512 IP(src=self.pg2.remote_hosts[1].ip4,
1513 dst=self.pg2.local_ip4) /
1514 UDP(sport=1234, dport=48879) /
1515 VXLAN(vni=99, gpid=220, flags=0x88) /
1516 Ether(src=l['mac'], dst=ep.mac) /
1517 IP(src=l['ip'], dst=ep.ip4.address) /
1518 UDP(sport=1234, dport=1234) /
1521 rx = self.send_and_expect(self.pg2, p*65, self.pg0)
1523 self.assertTrue(find_gbp_endpoint(self,
1524 vx_tun_l2_1.sw_if_index,
1528 # Static EP replies to dynamics
1530 self.logger.info(self.vapi.cli("sh l2fib bd_id 1"))
1532 p = (Ether(src=ep.mac, dst=l['mac']) /
1533 IP(dst=l['ip'], src=ep.ip4.address) /
1534 UDP(sport=1234, dport=1234) /
1537 rxs = self.send_and_expect(self.pg0, p * 17, self.pg2)
1540 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
1541 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
1542 self.assertEqual(rx[UDP].dport, 48879)
1543 # the UDP source port is a random value for hashing
1544 self.assertEqual(rx[VXLAN].gpid, 220)
1545 self.assertEqual(rx[VXLAN].vni, 99)
1546 self.assertTrue(rx[VXLAN].flags.G)
1547 self.assertTrue(rx[VXLAN].flags.Instance)
1548 self.assertTrue(rx[VXLAN].gpflags.A)
1549 self.assertFalse(rx[VXLAN].gpflags.D)
1553 self.assertFalse(find_gbp_endpoint(self,
1554 vx_tun_l2_1.sw_if_index,
1558 # repeat in the other EPG
1559 # there's no contract between 220 and 330, but the A-bit is set
1560 # so the packet is cleared for delivery
1563 # a packet with an sclass from a knwon EPG
1564 p = (Ether(src=self.pg2.remote_mac,
1565 dst=self.pg2.local_mac) /
1566 IP(src=self.pg2.remote_hosts[1].ip4,
1567 dst=self.pg2.local_ip4) /
1568 UDP(sport=1234, dport=48879) /
1569 VXLAN(vni=99, gpid=330, flags=0x88, gpflags='A') /
1570 Ether(src=l['mac'], dst=ep.mac) /
1571 IP(src=l['ip'], dst=ep.ip4.address) /
1572 UDP(sport=1234, dport=1234) /
1575 rx = self.send_and_expect(self.pg2, p*65, self.pg0)
1577 self.assertTrue(find_gbp_endpoint(self,
1578 vx_tun_l2_1.sw_if_index,
1582 # static EP cannot reach the learnt EPs since there is no contract
1584 self.logger.info(self.vapi.cli("show gbp endpoint"))
1585 self.logger.info(self.vapi.cli("show l2fib all"))
1587 p = (Ether(src=ep.mac, dst=l['mac']) /
1588 IP(dst=l['ip'], src=ep.ip4.address) /
1589 UDP(sport=1234, dport=1234) /
1592 self.send_and_assert_no_replies(self.pg0, [p], timeout=0.2)
1595 # refresh the entries after the check for no replies above
1598 # a packet with an sclass from a knwon EPG
1599 p = (Ether(src=self.pg2.remote_mac,
1600 dst=self.pg2.local_mac) /
1601 IP(src=self.pg2.remote_hosts[1].ip4,
1602 dst=self.pg2.local_ip4) /
1603 UDP(sport=1234, dport=48879) /
1604 VXLAN(vni=99, gpid=330, flags=0x88, gpflags='A') /
1605 Ether(src=l['mac'], dst=ep.mac) /
1606 IP(src=l['ip'], dst=ep.ip4.address) /
1607 UDP(sport=1234, dport=1234) /
1610 rx = self.send_and_expect(self.pg2, p*65, self.pg0)
1612 self.assertTrue(find_gbp_endpoint(self,
1613 vx_tun_l2_1.sw_if_index,
1617 # Add the contract so they can talk
1619 acl = VppGbpAcl(self)
1620 rule = acl.create_rule(permit_deny=1, proto=17)
1621 rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
1622 acl_index = acl.add_vpp_config([rule, rule2])
1623 c1 = VppGbpContract(self, 220, 330, acl_index)
1627 p = (Ether(src=ep.mac, dst=l['mac']) /
1628 IP(dst=l['ip'], src=ep.ip4.address) /
1629 UDP(sport=1234, dport=1234) /
1632 self.send_and_expect(self.pg0, [p], self.pg2)
1635 # send UU packets from the local EP
1637 self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1638 self.logger.info(self.vapi.cli("sh gbp bridge"))
1639 p_uu = (Ether(src=ep.mac, dst="00:11:11:11:11:11") /
1640 IP(dst="10.0.0.133", src=ep.ip4.address) /
1641 UDP(sport=1234, dport=1234) /
1643 rxs = self.send_and_expect(ep.itf, [p_uu], gbd1.uu_flood)
1646 # Add a mcast destination VXLAN-GBP tunnel for B&M traffic
1648 tun_bm = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
1651 tun_bm.add_vpp_config()
1652 bp_bm = VppBridgeDomainPort(self, bd1, tun_bm,
1653 port_type=L2_PORT_TYPE.NORMAL)
1654 bp_bm.add_vpp_config()
1656 self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1658 p_bm = (Ether(src=ep.mac, dst="ff:ff:ff:ff:ff:ff") /
1659 IP(dst="10.0.0.133", src=ep.ip4.address) /
1660 UDP(sport=1234, dport=1234) /
1662 rxs = self.send_and_expect_only(ep.itf, [p_bm], tun_bm.mcast_itf)
1665 # Check v6 Endpoints
1668 # a packet with an sclass from a knwon EPG
1669 p = (Ether(src=self.pg2.remote_mac,
1670 dst=self.pg2.local_mac) /
1671 IP(src=self.pg2.remote_hosts[1].ip4,
1672 dst=self.pg2.local_ip4) /
1673 UDP(sport=1234, dport=48879) /
1674 VXLAN(vni=99, gpid=330, flags=0x88, gpflags='A') /
1675 Ether(src=l['mac'], dst=ep.mac) /
1676 IPv6(src=l['ip6'], dst=ep.ip6.address) /
1677 UDP(sport=1234, dport=1234) /
1680 rx = self.send_and_expect(self.pg2, p*65, self.pg0)
1682 self.assertTrue(find_gbp_endpoint(self,
1683 vx_tun_l2_1.sw_if_index,
1687 # L3 Endpoint Learning
1688 # - configured on the bridge's BVI
1696 self.assertFalse(find_gbp_endpoint(self,
1697 vx_tun_l2_1.sw_if_index,
1700 self.pg2.unconfig_ip4()
1701 self.pg3.unconfig_ip4()
1702 self.pg4.unconfig_ip4()
1704 self.logger.info(self.vapi.cli("sh int"))
1705 self.logger.info(self.vapi.cli("sh gbp vxlan"))
1707 def test_gbp_learn_vlan_l2(self):
1708 """ GBP L2 Endpoint w/ VLANs"""
1710 learnt = [{'mac': '00:00:11:11:11:01',
1712 'ip6': '2001:10::2'},
1713 {'mac': '00:00:11:11:11:02',
1715 'ip6': '2001:10::3'}]
1718 # lower the inactive threshold so these tests pass in a
1719 # reasonable amount of time
1721 self.vapi.gbp_endpoint_learn_set_inactive_threshold(1)
1726 gt4 = VppIpTable(self, 1)
1727 gt4.add_vpp_config()
1728 gt6 = VppIpTable(self, 1, is_ip6=True)
1729 gt6.add_vpp_config()
1731 rd1 = VppGbpRouteDomain(self, 1, gt4, gt6)
1732 rd1.add_vpp_config()
1735 # Pg2 hosts the vxlan tunnel, hosts on pg2 to act as TEPs
1737 self.pg2.config_ip4()
1738 self.pg2.resolve_arp()
1739 self.pg2.generate_remote_hosts(4)
1740 self.pg2.configure_ipv4_neighbors()
1741 self.pg3.config_ip4()
1742 self.pg3.resolve_arp()
1745 # The EP will be on a vlan sub-interface
1747 vlan_11 = VppDot1QSubint(self, self.pg0, 11)
1749 self.vapi.sw_interface_set_l2_tag_rewrite(vlan_11.sw_if_index,
1753 bd_uu_fwd = VppVxlanGbpTunnel(self, self.pg3.local_ip4,
1754 self.pg3.remote_ip4, 116)
1755 bd_uu_fwd.add_vpp_config()
1758 # a GBP bridge domain with a BVI and a UU-flood interface
1759 # The BD is marked as do not learn, so no endpoints are ever
1760 # learnt in this BD.
1762 bd1 = VppBridgeDomain(self, 1)
1763 bd1.add_vpp_config()
1764 gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0, bd_uu_fwd,
1766 gbd1.add_vpp_config()
1768 self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1769 self.logger.info(self.vapi.cli("sh gbp bridge"))
1771 # ... and has a /32 applied
1772 ip_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
1773 ip_addr.add_vpp_config()
1776 # The Endpoint-group in which we are learning endpoints
1778 epg_220 = VppGbpEndpointGroup(self, 220, rd1, gbd1,
1782 epg_220.add_vpp_config()
1785 # The VXLAN GBP tunnel is a bridge-port and has L2 endpoint
1788 vx_tun_l2_1 = VppGbpVxlanTunnel(
1789 self, 99, bd1.bd_id,
1790 VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L2)
1791 vx_tun_l2_1.add_vpp_config()
1794 # A static endpoint that the learnt endpoints are trying to
1797 ep = VppGbpEndpoint(self, vlan_11,
1799 "10.0.0.127", "11.0.0.127",
1800 "2001:10::1", "3001::1")
1803 self.assertTrue(find_route(self, ep.ip4.address, 32, table_id=1))
1806 # Send to the static EP
1808 for ii, l in enumerate(learnt):
1809 # a packet with an sclass from a knwon EPG
1810 # arriving on an unknown TEP
1811 p = (Ether(src=self.pg2.remote_mac,
1812 dst=self.pg2.local_mac) /
1813 IP(src=self.pg2.remote_hosts[1].ip4,
1814 dst=self.pg2.local_ip4) /
1815 UDP(sport=1234, dport=48879) /
1816 VXLAN(vni=99, gpid=220, flags=0x88) /
1817 Ether(src=l['mac'], dst=ep.mac) /
1818 IP(src=l['ip'], dst=ep.ip4.address) /
1819 UDP(sport=1234, dport=1234) /
1822 rxs = self.send_and_expect(self.pg2, [p], self.pg0)
1825 # packet to EP has the EP's vlan tag
1828 self.assertEqual(rx[Dot1Q].vlan, 11)
1831 # the EP is not learnt since the BD setting prevents it
1834 self.assertFalse(find_gbp_endpoint(self,
1835 vx_tun_l2_1.sw_if_index,
1837 self.assertEqual(INDEX_INVALID,
1838 find_vxlan_gbp_tunnel(
1841 self.pg2.remote_hosts[1].ip4,
1844 self.assertEqual(len(self.vapi.gbp_endpoint_dump()), 1)
1848 # we didn't learn the remotes so they are sent to the UU-fwd
1851 p = (Ether(src=ep.mac, dst=l['mac']) /
1853 IP(dst=l['ip'], src=ep.ip4.address) /
1854 UDP(sport=1234, dport=1234) /
1857 rxs = self.send_and_expect(self.pg0, p * 17, self.pg3)
1860 self.assertEqual(rx[IP].src, self.pg3.local_ip4)
1861 self.assertEqual(rx[IP].dst, self.pg3.remote_ip4)
1862 self.assertEqual(rx[UDP].dport, 48879)
1863 # the UDP source port is a random value for hashing
1864 self.assertEqual(rx[VXLAN].gpid, 220)
1865 self.assertEqual(rx[VXLAN].vni, 116)
1866 self.assertTrue(rx[VXLAN].flags.G)
1867 self.assertTrue(rx[VXLAN].flags.Instance)
1868 self.assertFalse(rx[VXLAN].gpflags.A)
1869 self.assertFalse(rx[VXLAN].gpflags.D)
1871 self.pg2.unconfig_ip4()
1872 self.pg3.unconfig_ip4()
1874 def test_gbp_learn_l3(self):
1875 """ GBP L3 Endpoint Learning """
1877 routed_dst_mac = "00:0c:0c:0c:0c:0c"
1878 routed_src_mac = "00:22:bd:f8:19:ff"
1880 learnt = [{'mac': '00:00:11:11:11:02',
1882 'ip6': '2001:10::2'},
1883 {'mac': '00:00:11:11:11:03',
1885 'ip6': '2001:10::3'}]
1888 # lower the inactive threshold so these tests pass in a
1889 # reasonable amount of time
1891 self.vapi.gbp_endpoint_learn_set_inactive_threshold(1)
1896 t4 = VppIpTable(self, 1)
1898 t6 = VppIpTable(self, 1, True)
1901 tun_ip4_uu = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
1902 self.pg4.remote_ip4, 114)
1903 tun_ip6_uu = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
1904 self.pg4.remote_ip4, 116)
1905 tun_ip4_uu.add_vpp_config()
1906 tun_ip6_uu.add_vpp_config()
1908 rd1 = VppGbpRouteDomain(self, 2, t4, t6, tun_ip4_uu, tun_ip6_uu)
1909 rd1.add_vpp_config()
1911 self.loop0.set_mac(self.router_mac.address)
1914 # Bind the BVI to the RD
1916 VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
1917 VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
1920 # Pg2 hosts the vxlan tunnel
1921 # hosts on pg2 to act as TEPs
1925 self.pg2.config_ip4()
1926 self.pg2.resolve_arp()
1927 self.pg2.generate_remote_hosts(4)
1928 self.pg2.configure_ipv4_neighbors()
1929 self.pg3.config_ip4()
1930 self.pg3.resolve_arp()
1931 self.pg4.config_ip4()
1932 self.pg4.resolve_arp()
1935 # a GBP bridge domain with a BVI and a UU-flood interface
1937 bd1 = VppBridgeDomain(self, 1)
1938 bd1.add_vpp_config()
1939 gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0, self.pg3)
1940 gbd1.add_vpp_config()
1942 self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1943 self.logger.info(self.vapi.cli("sh gbp bridge"))
1944 self.logger.info(self.vapi.cli("sh gbp route"))
1945 self.logger.info(self.vapi.cli("show l2fib all"))
1947 # ... and has a /32 and /128 applied
1948 ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
1949 ip4_addr.add_vpp_config()
1950 ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128", 128)
1951 ip6_addr.add_vpp_config()
1954 # The Endpoint-group in which we are learning endpoints
1956 epg_220 = VppGbpEndpointGroup(self, 220, rd1, gbd1,
1960 epg_220.add_vpp_config()
1963 # The VXLAN GBP tunnel is a bridge-port and has L2 endpoint
1966 vx_tun_l3 = VppGbpVxlanTunnel(
1967 self, 101, rd1.rd_id,
1968 VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3)
1969 vx_tun_l3.add_vpp_config()
1972 # A static endpoint that the learnt endpoints are trying to
1975 ep = VppGbpEndpoint(self, self.pg0,
1977 "10.0.0.127", "11.0.0.127",
1978 "2001:10::1", "3001::1")
1982 # learn some remote IPv4 EPs
1984 for ii, l in enumerate(learnt):
1985 # a packet with an sclass from a knwon EPG
1986 # arriving on an unknown TEP
1987 p = (Ether(src=self.pg2.remote_mac,
1988 dst=self.pg2.local_mac) /
1989 IP(src=self.pg2.remote_hosts[1].ip4,
1990 dst=self.pg2.local_ip4) /
1991 UDP(sport=1234, dport=48879) /
1992 VXLAN(vni=101, gpid=220, flags=0x88) /
1993 Ether(src=l['mac'], dst="00:00:00:11:11:11") /
1994 IP(src=l['ip'], dst=ep.ip4.address) /
1995 UDP(sport=1234, dport=1234) /
1998 rx = self.send_and_expect(self.pg2, [p], self.pg0)
2001 tep1_sw_if_index = find_vxlan_gbp_tunnel(
2004 self.pg2.remote_hosts[1].ip4,
2006 self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
2008 # endpoint learnt via the parent GBP-vxlan interface
2009 self.assertTrue(find_gbp_endpoint(self,
2010 vx_tun_l3._sw_if_index,
2014 # Static IPv4 EP replies to learnt
2017 p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2018 IP(dst=l['ip'], src=ep.ip4.address) /
2019 UDP(sport=1234, dport=1234) /
2022 rxs = self.send_and_expect(self.pg0, p*1, self.pg2)
2025 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2026 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
2027 self.assertEqual(rx[UDP].dport, 48879)
2028 # the UDP source port is a random value for hashing
2029 self.assertEqual(rx[VXLAN].gpid, 220)
2030 self.assertEqual(rx[VXLAN].vni, 101)
2031 self.assertTrue(rx[VXLAN].flags.G)
2032 self.assertTrue(rx[VXLAN].flags.Instance)
2033 self.assertTrue(rx[VXLAN].gpflags.A)
2034 self.assertFalse(rx[VXLAN].gpflags.D)
2036 inner = rx[VXLAN].payload
2038 self.assertEqual(inner[Ether].src, routed_src_mac)
2039 self.assertEqual(inner[Ether].dst, routed_dst_mac)
2040 self.assertEqual(inner[IP].src, ep.ip4.address)
2041 self.assertEqual(inner[IP].dst, l['ip'])
2045 self.assertFalse(find_gbp_endpoint(self,
2050 # learn some remote IPv6 EPs
2052 for ii, l in enumerate(learnt):
2053 # a packet with an sclass from a knwon EPG
2054 # arriving on an unknown TEP
2055 p = (Ether(src=self.pg2.remote_mac,
2056 dst=self.pg2.local_mac) /
2057 IP(src=self.pg2.remote_hosts[1].ip4,
2058 dst=self.pg2.local_ip4) /
2059 UDP(sport=1234, dport=48879) /
2060 VXLAN(vni=101, gpid=220, flags=0x88) /
2061 Ether(src=l['mac'], dst="00:00:00:11:11:11") /
2062 IPv6(src=l['ip6'], dst=ep.ip6.address) /
2063 UDP(sport=1234, dport=1234) /
2066 rx = self.send_and_expect(self.pg2, [p], self.pg0)
2069 tep1_sw_if_index = find_vxlan_gbp_tunnel(
2072 self.pg2.remote_hosts[1].ip4,
2074 self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
2076 self.logger.info(self.vapi.cli("show gbp bridge"))
2077 self.logger.info(self.vapi.cli("show vxlan-gbp tunnel"))
2078 self.logger.info(self.vapi.cli("show gbp vxlan"))
2079 self.logger.info(self.vapi.cli("show int addr"))
2081 # endpoint learnt via the TEP
2082 self.assertTrue(find_gbp_endpoint(self, ip=l['ip6']))
2084 self.logger.info(self.vapi.cli("show gbp endpoint"))
2085 self.logger.info(self.vapi.cli("show ip fib index 1 %s" % l['ip']))
2088 # Static EP replies to learnt
2091 p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2092 IPv6(dst=l['ip6'], src=ep.ip6.address) /
2093 UDP(sport=1234, dport=1234) /
2096 rxs = self.send_and_expect(self.pg0, p*65, self.pg2)
2099 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2100 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
2101 self.assertEqual(rx[UDP].dport, 48879)
2102 # the UDP source port is a random value for hashing
2103 self.assertEqual(rx[VXLAN].gpid, 220)
2104 self.assertEqual(rx[VXLAN].vni, 101)
2105 self.assertTrue(rx[VXLAN].flags.G)
2106 self.assertTrue(rx[VXLAN].flags.Instance)
2107 self.assertTrue(rx[VXLAN].gpflags.A)
2108 self.assertFalse(rx[VXLAN].gpflags.D)
2110 inner = rx[VXLAN].payload
2112 self.assertEqual(inner[Ether].src, routed_src_mac)
2113 self.assertEqual(inner[Ether].dst, routed_dst_mac)
2114 self.assertEqual(inner[IPv6].src, ep.ip6.address)
2115 self.assertEqual(inner[IPv6].dst, l['ip6'])
2117 self.logger.info(self.vapi.cli("sh gbp endpoint"))
2120 self.assertFalse(find_gbp_endpoint(self,
2125 # Static sends to unknown EP with no route
2127 p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2128 IP(dst="10.0.0.99", src=ep.ip4.address) /
2129 UDP(sport=1234, dport=1234) /
2132 self.send_and_assert_no_replies(self.pg0, [p])
2135 # Add a route to static EP's v4 and v6 subnet
2136 # packets should be send on the v4/v6 uu=fwd interface resp.
2138 se_10_24 = VppGbpSubnet(
2139 self, rd1, "10.0.0.0", 24,
2140 VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_TRANSPORT)
2141 se_10_24.add_vpp_config()
2143 p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2144 IP(dst="10.0.0.99", src=ep.ip4.address) /
2145 UDP(sport=1234, dport=1234) /
2148 rxs = self.send_and_expect(self.pg0, [p], self.pg4)
2150 self.assertEqual(rx[IP].src, self.pg4.local_ip4)
2151 self.assertEqual(rx[IP].dst, self.pg4.remote_ip4)
2152 self.assertEqual(rx[UDP].dport, 48879)
2153 # the UDP source port is a random value for hashing
2154 self.assertEqual(rx[VXLAN].gpid, 220)
2155 self.assertEqual(rx[VXLAN].vni, 114)
2156 self.assertTrue(rx[VXLAN].flags.G)
2157 self.assertTrue(rx[VXLAN].flags.Instance)
2158 # policy is not applied to packets sent to the uu-fwd interfaces
2159 self.assertFalse(rx[VXLAN].gpflags.A)
2160 self.assertFalse(rx[VXLAN].gpflags.D)
2163 # learn some remote IPv4 EPs
2165 for ii, l in enumerate(learnt):
2166 # a packet with an sclass from a knwon EPG
2167 # arriving on an unknown TEP
2168 p = (Ether(src=self.pg2.remote_mac,
2169 dst=self.pg2.local_mac) /
2170 IP(src=self.pg2.remote_hosts[1].ip4,
2171 dst=self.pg2.local_ip4) /
2172 UDP(sport=1234, dport=48879) /
2173 VXLAN(vni=101, gpid=220, flags=0x88) /
2174 Ether(src=l['mac'], dst="00:00:00:11:11:11") /
2175 IP(src=l['ip'], dst=ep.ip4.address) /
2176 UDP(sport=1234, dport=1234) /
2179 rx = self.send_and_expect(self.pg2, [p], self.pg0)
2182 tep1_sw_if_index = find_vxlan_gbp_tunnel(
2185 self.pg2.remote_hosts[1].ip4,
2187 self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
2189 # endpoint learnt via the parent GBP-vxlan interface
2190 self.assertTrue(find_gbp_endpoint(self,
2191 vx_tun_l3._sw_if_index,
2195 # Add a remote endpoint from the API
2197 rep_88 = VppGbpEndpoint(self, vx_tun_l3,
2199 "10.0.0.88", "11.0.0.88",
2200 "2001:10::88", "3001::88",
2201 VppEnum.vl_api_gbp_endpoint_flags_t.REMOTE,
2203 self.pg2.remote_hosts[1].ip4,
2205 rep_88.add_vpp_config()
2208 # Add a remote endpoint from the API that matches an existing one
2210 rep_2 = VppGbpEndpoint(self, vx_tun_l3,
2212 learnt[0]['ip'], "11.0.0.101",
2213 learnt[0]['ip6'], "3001::101",
2214 VppEnum.vl_api_gbp_endpoint_flags_t.REMOTE,
2216 self.pg2.remote_hosts[1].ip4,
2218 rep_2.add_vpp_config()
2221 # Add a route to the leanred EP's v4 subnet
2222 # packets should be send on the v4/v6 uu=fwd interface resp.
2224 se_10_1_24 = VppGbpSubnet(
2225 self, rd1, "10.0.1.0", 24,
2226 VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_TRANSPORT)
2227 se_10_1_24.add_vpp_config()
2229 self.logger.info(self.vapi.cli("show gbp endpoint"))
2231 ips = ["10.0.0.88", learnt[0]['ip']]
2233 p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2234 IP(dst=ip, src=ep.ip4.address) /
2235 UDP(sport=1234, dport=1234) /
2238 rxs = self.send_and_expect(self.pg0, p*65, self.pg2)
2241 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2242 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
2243 self.assertEqual(rx[UDP].dport, 48879)
2244 # the UDP source port is a random value for hashing
2245 self.assertEqual(rx[VXLAN].gpid, 220)
2246 self.assertEqual(rx[VXLAN].vni, 101)
2247 self.assertTrue(rx[VXLAN].flags.G)
2248 self.assertTrue(rx[VXLAN].flags.Instance)
2249 self.assertTrue(rx[VXLAN].gpflags.A)
2250 self.assertFalse(rx[VXLAN].gpflags.D)
2252 inner = rx[VXLAN].payload
2254 self.assertEqual(inner[Ether].src, routed_src_mac)
2255 self.assertEqual(inner[Ether].dst, routed_dst_mac)
2256 self.assertEqual(inner[IP].src, ep.ip4.address)
2257 self.assertEqual(inner[IP].dst, ip)
2260 # remove the API remote EPs, they are now UU-fwd
2262 rep_88.remove_vpp_config()
2263 rep_2.remove_vpp_config()
2265 self.logger.info(self.vapi.cli("show gbp endpoint"))
2268 self.assertFalse(find_gbp_endpoint(self, ip=ip))
2270 p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2271 IP(dst=ip, src=ep.ip4.address) /
2272 UDP(sport=1234, dport=1234) /
2275 rxs = self.send_and_expect(self.pg0, [p], self.pg4)
2278 # shutdown with learnt endpoint present
2280 self.logger.info(self.vapi.cli("show gbp endpoint-group"))
2284 # remote endpoint becomes local
2286 self.pg2.unconfig_ip4()
2287 self.pg3.unconfig_ip4()
2288 self.pg4.unconfig_ip4()
2291 if __name__ == '__main__':
2292 unittest.main(testRunner=VppTestRunner)