nat: NAT44ED fail if using old plugin option
[vpp.git] / src / plugins / gbp / test / test_gbp.py
1 #!/usr/bin/env python3
2
3 from socket import AF_INET, AF_INET6, inet_pton, inet_ntop
4 import unittest
5 from ipaddress import ip_address, IPv4Network, IPv6Network
6
7 from scapy.packet import Raw
8 from scapy.layers.l2 import Ether, ARP, Dot1Q
9 from scapy.layers.inet import IP, UDP, ICMP
10 from scapy.layers.inet6 import IPv6, ICMPv6ND_NS, ICMPv6NDOptSrcLLAddr, \
11     ICMPv6ND_NA, ICMPv6EchoRequest
12 from scapy.utils6 import in6_getnsma, in6_getnsmac
13 from scapy.layers.vxlan import VXLAN
14 from scapy.data import ETH_P_IP, ETH_P_IPV6, ETH_P_ARP
15
16 from framework import tag_fixme_vpp_workers
17 from framework import VppTestCase, VppTestRunner
18 from vpp_object import VppObject
19 from vpp_interface import VppInterface
20 from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable, \
21     VppIpInterfaceAddress, VppIpInterfaceBind, find_route, FibPathProto, \
22     FibPathType
23 from vpp_l2 import VppBridgeDomain, VppBridgeDomainPort, \
24     VppBridgeDomainArpEntry, VppL2FibEntry, find_bridge_domain_port, VppL2Vtr
25 from vpp_sub_interface import L2_VTR_OP, VppDot1QSubint
26 from vpp_ip import DpoProto, get_dpo_proto
27 from vpp_papi import VppEnum, MACAddress
28 from vpp_vxlan_gbp_tunnel import find_vxlan_gbp_tunnel, INDEX_INVALID, \
29     VppVxlanGbpTunnel
30 from vpp_neighbor import VppNeighbor
31 from vpp_acl import AclRule, VppAcl
32 try:
33     text_type = unicode
34 except NameError:
35     text_type = str
36
37 NUM_PKTS = 67
38
39
40 def find_gbp_endpoint(test, sw_if_index=None, ip=None, mac=None,
41                       tep=None, sclass=None, flags=None):
42     if ip:
43         vip = ip
44     if mac:
45         vmac = MACAddress(mac)
46
47     eps = test.vapi.gbp_endpoint_dump()
48
49     for ep in eps:
50         if tep:
51             src = tep[0]
52             dst = tep[1]
53             if src != str(ep.endpoint.tun.src) or \
54                dst != str(ep.endpoint.tun.dst):
55                 continue
56         if sw_if_index:
57             if ep.endpoint.sw_if_index != sw_if_index:
58                 continue
59         if sclass:
60             if ep.endpoint.sclass != sclass:
61                 continue
62         if flags:
63             if flags != (flags & ep.endpoint.flags):
64                 continue
65         if ip:
66             for eip in ep.endpoint.ips:
67                 if vip == str(eip):
68                     return True
69         if mac:
70             if vmac == ep.endpoint.mac:
71                 return True
72
73     return False
74
75
76 def find_gbp_vxlan(test, vni):
77     ts = test.vapi.gbp_vxlan_tunnel_dump()
78     for t in ts:
79         if t.tunnel.vni == vni:
80             return True
81     return False
82
83
84 class VppGbpEndpoint(VppObject):
85     """
86     GBP Endpoint
87     """
88
89     @property
90     def mac(self):
91         return str(self.vmac)
92
93     @property
94     def ip4(self):
95         return self._ip4
96
97     @property
98     def fip4(self):
99         return self._fip4
100
101     @property
102     def ip6(self):
103         return self._ip6
104
105     @property
106     def fip6(self):
107         return self._fip6
108
109     @property
110     def ips(self):
111         return [self.ip4, self.ip6]
112
113     @property
114     def fips(self):
115         return [self.fip4, self.fip6]
116
117     def __init__(self, test, itf, epg, recirc, ip4, fip4, ip6, fip6,
118                  flags=0,
119                  tun_src="0.0.0.0",
120                  tun_dst="0.0.0.0",
121                  mac=True):
122         self._test = test
123         self.itf = itf
124         self.epg = epg
125         self.recirc = recirc
126
127         self._ip4 = ip4
128         self._fip4 = fip4
129         self._ip6 = ip6
130         self._fip6 = fip6
131
132         if mac:
133             self.vmac = MACAddress(self.itf.remote_mac)
134         else:
135             self.vmac = MACAddress("00:00:00:00:00:00")
136
137         self.flags = flags
138         self.tun_src = tun_src
139         self.tun_dst = tun_dst
140
141     def add_vpp_config(self):
142         res = self._test.vapi.gbp_endpoint_add(
143             self.itf.sw_if_index,
144             [self.ip4, self.ip6],
145             self.vmac.packed,
146             self.epg.sclass,
147             self.flags,
148             self.tun_src,
149             self.tun_dst)
150         self.handle = res.handle
151         self._test.registry.register(self, self._test.logger)
152
153     def remove_vpp_config(self):
154         self._test.vapi.gbp_endpoint_del(self.handle)
155
156     def object_id(self):
157         return "gbp-endpoint:[%d==%d:%s:%d]" % (self.handle,
158                                                 self.itf.sw_if_index,
159                                                 self.ip4,
160                                                 self.epg.sclass)
161
162     def query_vpp_config(self):
163         return find_gbp_endpoint(self._test,
164                                  self.itf.sw_if_index,
165                                  self.ip4)
166
167
168 class VppGbpRecirc(VppObject):
169     """
170     GBP Recirculation Interface
171     """
172
173     def __init__(self, test, epg, recirc, is_ext=False):
174         self._test = test
175         self.recirc = recirc
176         self.epg = epg
177         self.is_ext = is_ext
178
179     def add_vpp_config(self):
180         self._test.vapi.gbp_recirc_add_del(
181             1,
182             self.recirc.sw_if_index,
183             self.epg.sclass,
184             self.is_ext)
185         self._test.registry.register(self, self._test.logger)
186
187     def remove_vpp_config(self):
188         self._test.vapi.gbp_recirc_add_del(
189             0,
190             self.recirc.sw_if_index,
191             self.epg.sclass,
192             self.is_ext)
193
194     def object_id(self):
195         return "gbp-recirc:[%d]" % (self.recirc.sw_if_index)
196
197     def query_vpp_config(self):
198         rs = self._test.vapi.gbp_recirc_dump()
199         for r in rs:
200             if r.recirc.sw_if_index == self.recirc.sw_if_index:
201                 return True
202         return False
203
204
205 class VppGbpExtItf(VppObject):
206     """
207     GBP ExtItfulation Interface
208     """
209
210     def __init__(self, test, itf, bd, rd, anon=False):
211         self._test = test
212         self.itf = itf
213         self.bd = bd
214         self.rd = rd
215         self.flags = 1 if anon else 0
216
217     def add_vpp_config(self):
218         self._test.vapi.gbp_ext_itf_add_del(
219             1, self.itf.sw_if_index, self.bd.bd_id, self.rd.rd_id, self.flags)
220         self._test.registry.register(self, self._test.logger)
221
222     def remove_vpp_config(self):
223         self._test.vapi.gbp_ext_itf_add_del(
224             0, self.itf.sw_if_index, self.bd.bd_id, self.rd.rd_id, self.flags)
225
226     def object_id(self):
227         return "gbp-ext-itf:[%d]%s" % (self.itf.sw_if_index,
228                                        " [anon]" if self.flags else "")
229
230     def query_vpp_config(self):
231         rs = self._test.vapi.gbp_ext_itf_dump()
232         for r in rs:
233             if r.ext_itf.sw_if_index == self.itf.sw_if_index:
234                 return True
235         return False
236
237
238 class VppGbpSubnet(VppObject):
239     """
240     GBP Subnet
241     """
242
243     def __init__(self, test, rd, address, address_len,
244                  type, sw_if_index=None, sclass=None):
245         self._test = test
246         self.rd_id = rd.rd_id
247         a = ip_address(address)
248         if 4 == a.version:
249             self.prefix = IPv4Network("%s/%d" % (address, address_len),
250                                       strict=False)
251         else:
252             self.prefix = IPv6Network("%s/%d" % (address, address_len),
253                                       strict=False)
254         self.type = type
255         self.sw_if_index = sw_if_index
256         self.sclass = sclass
257
258     def add_vpp_config(self):
259         self._test.vapi.gbp_subnet_add_del(
260             1,
261             self.rd_id,
262             self.prefix,
263             self.type,
264             sw_if_index=self.sw_if_index if self.sw_if_index else 0xffffffff,
265             sclass=self.sclass if self.sclass else 0xffff)
266         self._test.registry.register(self, self._test.logger)
267
268     def remove_vpp_config(self):
269         self._test.vapi.gbp_subnet_add_del(
270             0,
271             self.rd_id,
272             self.prefix,
273             self.type)
274
275     def object_id(self):
276         return "gbp-subnet:[%d-%s]" % (self.rd_id, self.prefix)
277
278     def query_vpp_config(self):
279         ss = self._test.vapi.gbp_subnet_dump()
280         for s in ss:
281             if s.subnet.rd_id == self.rd_id and \
282                     s.subnet.type == self.type and \
283                     s.subnet.prefix == self.prefix:
284                 return True
285         return False
286
287
288 class VppGbpEndpointRetention(object):
289     def __init__(self, remote_ep_timeout=0xffffffff):
290         self.remote_ep_timeout = remote_ep_timeout
291
292     def encode(self):
293         return {'remote_ep_timeout': self.remote_ep_timeout}
294
295
296 class VppGbpEndpointGroup(VppObject):
297     """
298     GBP Endpoint Group
299     """
300
301     def __init__(self, test, vnid, sclass, rd, bd, uplink,
302                  bvi, bvi_ip4, bvi_ip6=None,
303                  retention=VppGbpEndpointRetention()):
304         self._test = test
305         self.uplink = uplink
306         self.bvi = bvi
307         self.bvi_ip4 = bvi_ip4
308         self.bvi_ip6 = bvi_ip6
309         self.vnid = vnid
310         self.bd = bd
311         self.rd = rd
312         self.sclass = sclass
313         if 0 == self.sclass:
314             self.sclass = 0xffff
315         self.retention = retention
316
317     def add_vpp_config(self):
318         self._test.vapi.gbp_endpoint_group_add(
319             self.vnid,
320             self.sclass,
321             self.bd.bd.bd_id,
322             self.rd.rd_id,
323             self.uplink.sw_if_index if self.uplink else INDEX_INVALID,
324             self.retention.encode())
325         self._test.registry.register(self, self._test.logger)
326
327     def remove_vpp_config(self):
328         self._test.vapi.gbp_endpoint_group_del(self.sclass)
329
330     def object_id(self):
331         return "gbp-endpoint-group:[%d]" % (self.vnid)
332
333     def query_vpp_config(self):
334         epgs = self._test.vapi.gbp_endpoint_group_dump()
335         for epg in epgs:
336             if epg.epg.vnid == self.vnid:
337                 return True
338         return False
339
340
341 class VppGbpBridgeDomain(VppObject):
342     """
343     GBP Bridge Domain
344     """
345
346     def __init__(self, test, bd, rd, bvi, uu_fwd=None,
347                  bm_flood=None, learn=True,
348                  uu_drop=False, bm_drop=False,
349                  ucast_arp=False):
350         self._test = test
351         self.bvi = bvi
352         self.uu_fwd = uu_fwd
353         self.bm_flood = bm_flood
354         self.bd = bd
355         self.rd = rd
356
357         e = VppEnum.vl_api_gbp_bridge_domain_flags_t
358
359         self.flags = e.GBP_BD_API_FLAG_NONE
360         if not learn:
361             self.flags |= e.GBP_BD_API_FLAG_DO_NOT_LEARN
362         if uu_drop:
363             self.flags |= e.GBP_BD_API_FLAG_UU_FWD_DROP
364         if bm_drop:
365             self.flags |= e.GBP_BD_API_FLAG_MCAST_DROP
366         if ucast_arp:
367             self.flags |= e.GBP_BD_API_FLAG_UCAST_ARP
368
369     def add_vpp_config(self):
370         self._test.vapi.gbp_bridge_domain_add(
371             self.bd.bd_id,
372             self.rd.rd_id,
373             self.flags,
374             self.bvi.sw_if_index,
375             self.uu_fwd.sw_if_index if self.uu_fwd else INDEX_INVALID,
376             self.bm_flood.sw_if_index if self.bm_flood else INDEX_INVALID)
377         self._test.registry.register(self, self._test.logger)
378
379     def remove_vpp_config(self):
380         self._test.vapi.gbp_bridge_domain_del(self.bd.bd_id)
381
382     def object_id(self):
383         return "gbp-bridge-domain:[%d]" % (self.bd.bd_id)
384
385     def query_vpp_config(self):
386         bds = self._test.vapi.gbp_bridge_domain_dump()
387         for bd in bds:
388             if bd.bd.bd_id == self.bd.bd_id:
389                 return True
390         return False
391
392
393 class VppGbpRouteDomain(VppObject):
394     """
395     GBP Route Domain
396     """
397
398     def __init__(self, test, rd_id, scope, t4, t6, ip4_uu=None, ip6_uu=None):
399         self._test = test
400         self.rd_id = rd_id
401         self.scope = scope
402         self.t4 = t4
403         self.t6 = t6
404         self.ip4_uu = ip4_uu
405         self.ip6_uu = ip6_uu
406
407     def add_vpp_config(self):
408         self._test.vapi.gbp_route_domain_add(
409             self.rd_id,
410             self.scope,
411             self.t4.table_id,
412             self.t6.table_id,
413             self.ip4_uu.sw_if_index if self.ip4_uu else INDEX_INVALID,
414             self.ip6_uu.sw_if_index if self.ip6_uu else INDEX_INVALID)
415         self._test.registry.register(self, self._test.logger)
416
417     def remove_vpp_config(self):
418         self._test.vapi.gbp_route_domain_del(self.rd_id)
419
420     def object_id(self):
421         return "gbp-route-domain:[%d]" % (self.rd_id)
422
423     def query_vpp_config(self):
424         rds = self._test.vapi.gbp_route_domain_dump()
425         for rd in rds:
426             if rd.rd.rd_id == self.rd_id:
427                 return True
428         return False
429
430
431 class VppGbpContractNextHop():
432     def __init__(self, mac, bd, ip, rd):
433         self.mac = mac
434         self.ip = ip
435         self.bd = bd
436         self.rd = rd
437
438     def encode(self):
439         return {'ip': self.ip,
440                 'mac': self.mac.packed,
441                 'bd_id': self.bd.bd.bd_id,
442                 'rd_id': self.rd.rd_id}
443
444
445 class VppGbpContractRule():
446     def __init__(self, action, hash_mode, nhs=None):
447         self.action = action
448         self.hash_mode = hash_mode
449         self.nhs = [] if nhs is None else nhs
450
451     def encode(self):
452         nhs = []
453         for nh in self.nhs:
454             nhs.append(nh.encode())
455         while len(nhs) < 8:
456             nhs.append({})
457         return {'action': self.action,
458                 'nh_set': {
459                     'hash_mode': self.hash_mode,
460                     'n_nhs': len(self.nhs),
461                     'nhs': nhs}}
462
463     def __repr__(self):
464         return '<VppGbpContractRule action=%s, hash_mode=%s>' % (
465             self.action, self.hash_mode)
466
467
468 class VppGbpContract(VppObject):
469     """
470     GBP Contract
471     """
472
473     def __init__(self, test, scope, sclass, dclass, acl_index,
474                  rules, allowed_ethertypes):
475         self._test = test
476         if not isinstance(rules, list):
477             raise ValueError("'rules' must be a list.")
478         if not isinstance(allowed_ethertypes, list):
479             raise ValueError("'allowed_ethertypes' must be a list.")
480         self.scope = scope
481         self.acl_index = acl_index
482         self.sclass = sclass
483         self.dclass = dclass
484         self.rules = rules
485         self.allowed_ethertypes = allowed_ethertypes
486         while (len(self.allowed_ethertypes) < 16):
487             self.allowed_ethertypes.append(0)
488
489     def add_vpp_config(self):
490         rules = []
491         for r in self.rules:
492             rules.append(r.encode())
493         r = self._test.vapi.gbp_contract_add_del(
494             is_add=1,
495             contract={
496                 'acl_index': self.acl_index,
497                 'scope': self.scope,
498                 'sclass': self.sclass,
499                 'dclass': self.dclass,
500                 'n_rules': len(rules),
501                 'rules': rules,
502                 'n_ether_types': len(self.allowed_ethertypes),
503                 'allowed_ethertypes': self.allowed_ethertypes})
504         self.stats_index = r.stats_index
505         self._test.registry.register(self, self._test.logger)
506
507     def remove_vpp_config(self):
508         self._test.vapi.gbp_contract_add_del(
509             is_add=0,
510             contract={
511                 'acl_index': self.acl_index,
512                 'scope': self.scope,
513                 'sclass': self.sclass,
514                 'dclass': self.dclass,
515                 'n_rules': 0,
516                 'rules': [],
517                 'n_ether_types': len(self.allowed_ethertypes),
518                 'allowed_ethertypes': self.allowed_ethertypes})
519
520     def object_id(self):
521         return "gbp-contract:[%d:%d:%d:%d]" % (self.scope,
522                                                self.sclass,
523                                                self.dclass,
524                                                self.acl_index)
525
526     def query_vpp_config(self):
527         cs = self._test.vapi.gbp_contract_dump()
528         for c in cs:
529             if c.contract.scope == self.scope \
530                and c.contract.sclass == self.sclass \
531                and c.contract.dclass == self.dclass:
532                 return True
533         return False
534
535     def get_drop_stats(self):
536         c = self._test.statistics.get_counter("/net/gbp/contract/drop")
537         return c[0][self.stats_index]
538
539     def get_permit_stats(self):
540         c = self._test.statistics.get_counter("/net/gbp/contract/permit")
541         return c[0][self.stats_index]
542
543
544 class VppGbpVxlanTunnel(VppInterface):
545     """
546     GBP VXLAN tunnel
547     """
548
549     def __init__(self, test, vni, bd_rd_id, mode, src):
550         super(VppGbpVxlanTunnel, self).__init__(test)
551         self._test = test
552         self.vni = vni
553         self.bd_rd_id = bd_rd_id
554         self.mode = mode
555         self.src = src
556
557     def add_vpp_config(self):
558         r = self._test.vapi.gbp_vxlan_tunnel_add(
559             self.vni,
560             self.bd_rd_id,
561             self.mode,
562             self.src)
563         self.set_sw_if_index(r.sw_if_index)
564         self._test.registry.register(self, self._test.logger)
565
566     def remove_vpp_config(self):
567         self._test.vapi.gbp_vxlan_tunnel_del(self.vni)
568
569     def object_id(self):
570         return "gbp-vxlan:%d" % (self.sw_if_index)
571
572     def query_vpp_config(self):
573         return find_gbp_vxlan(self._test, self.vni)
574
575
576 @tag_fixme_vpp_workers
577 class TestGBP(VppTestCase):
578     """ GBP Test Case """
579
580     @property
581     def nat_config_flags(self):
582         return VppEnum.vl_api_nat_config_flags_t
583
584     @property
585     def nat44_config_flags(self):
586         return VppEnum.vl_api_nat44_config_flags_t
587
588     @classmethod
589     def setUpClass(cls):
590         super(TestGBP, cls).setUpClass()
591
592     @classmethod
593     def tearDownClass(cls):
594         super(TestGBP, cls).tearDownClass()
595
596     def setUp(self):
597         super(TestGBP, self).setUp()
598
599         self.create_pg_interfaces(range(9))
600         self.create_loopback_interfaces(8)
601
602         self.router_mac = MACAddress("00:11:22:33:44:55")
603
604         for i in self.pg_interfaces:
605             i.admin_up()
606         for i in self.lo_interfaces:
607             i.admin_up()
608
609         self.vlan_100 = VppDot1QSubint(self, self.pg0, 100)
610         self.vlan_100.admin_up()
611         self.vlan_101 = VppDot1QSubint(self, self.pg0, 101)
612         self.vlan_101.admin_up()
613         self.vlan_102 = VppDot1QSubint(self, self.pg0, 102)
614         self.vlan_102.admin_up()
615
616     def tearDown(self):
617         for i in self.pg_interfaces:
618             i.admin_down()
619         super(TestGBP, self).tearDown()
620         for i in self.lo_interfaces:
621             i.remove_vpp_config()
622         self.lo_interfaces = []
623         self.vlan_102.remove_vpp_config()
624         self.vlan_101.remove_vpp_config()
625         self.vlan_100.remove_vpp_config()
626
627     def send_and_expect_bridged(self, src, tx, dst):
628         rx = self.send_and_expect(src, tx, dst)
629
630         for r in rx:
631             self.assertEqual(r[Ether].src, tx[0][Ether].src)
632             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
633             self.assertEqual(r[IP].src, tx[0][IP].src)
634             self.assertEqual(r[IP].dst, tx[0][IP].dst)
635         return rx
636
637     def send_and_expect_bridged6(self, src, tx, dst):
638         rx = self.send_and_expect(src, tx, dst)
639
640         for r in rx:
641             self.assertEqual(r[Ether].src, tx[0][Ether].src)
642             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
643             self.assertEqual(r[IPv6].src, tx[0][IPv6].src)
644             self.assertEqual(r[IPv6].dst, tx[0][IPv6].dst)
645         return rx
646
647     def send_and_expect_routed(self, src, tx, dst, src_mac):
648         rx = self.send_and_expect(src, tx, dst)
649
650         for r in rx:
651             self.assertEqual(r[Ether].src, src_mac)
652             self.assertEqual(r[Ether].dst, dst.remote_mac)
653             self.assertEqual(r[IP].src, tx[0][IP].src)
654             self.assertEqual(r[IP].dst, tx[0][IP].dst)
655         return rx
656
657     def send_and_expect_routed6(self, src, tx, dst, src_mac):
658         rx = self.send_and_expect(src, tx, dst)
659
660         for r in rx:
661             self.assertEqual(r[Ether].src, src_mac)
662             self.assertEqual(r[Ether].dst, dst.remote_mac)
663             self.assertEqual(r[IPv6].src, tx[0][IPv6].src)
664             self.assertEqual(r[IPv6].dst, tx[0][IPv6].dst)
665         return rx
666
667     def send_and_expect_natted(self, src, tx, dst, src_ip):
668         rx = self.send_and_expect(src, tx, dst)
669
670         for r in rx:
671             self.assertEqual(r[Ether].src, tx[0][Ether].src)
672             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
673             self.assertEqual(r[IP].src, src_ip)
674             self.assertEqual(r[IP].dst, tx[0][IP].dst)
675         return rx
676
677     def send_and_expect_natted6(self, src, tx, dst, src_ip):
678         rx = self.send_and_expect(src, tx, dst)
679
680         for r in rx:
681             self.assertEqual(r[Ether].src, tx[0][Ether].src)
682             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
683             self.assertEqual(r[IPv6].src, src_ip)
684             self.assertEqual(r[IPv6].dst, tx[0][IPv6].dst)
685         return rx
686
687     def send_and_expect_unnatted(self, src, tx, dst, dst_ip):
688         rx = self.send_and_expect(src, tx, dst)
689
690         for r in rx:
691             self.assertEqual(r[Ether].src, tx[0][Ether].src)
692             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
693             self.assertEqual(r[IP].dst, dst_ip)
694             self.assertEqual(r[IP].src, tx[0][IP].src)
695         return rx
696
697     def send_and_expect_unnatted6(self, src, tx, dst, dst_ip):
698         rx = self.send_and_expect(src, tx, dst)
699
700         for r in rx:
701             self.assertEqual(r[Ether].src, tx[0][Ether].src)
702             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
703             self.assertEqual(r[IPv6].dst, dst_ip)
704             self.assertEqual(r[IPv6].src, tx[0][IPv6].src)
705         return rx
706
707     def send_and_expect_double_natted(self, src, tx, dst, src_ip, dst_ip):
708         rx = self.send_and_expect(src, tx, dst)
709
710         for r in rx:
711             self.assertEqual(r[Ether].src, str(self.router_mac))
712             self.assertEqual(r[Ether].dst, dst.remote_mac)
713             self.assertEqual(r[IP].dst, dst_ip)
714             self.assertEqual(r[IP].src, src_ip)
715         return rx
716
717     def send_and_expect_double_natted6(self, src, tx, dst, src_ip, dst_ip):
718         rx = self.send_and_expect(src, tx, dst)
719
720         for r in rx:
721             self.assertEqual(r[Ether].src, str(self.router_mac))
722             self.assertEqual(r[Ether].dst, dst.remote_mac)
723             self.assertEqual(r[IPv6].dst, dst_ip)
724             self.assertEqual(r[IPv6].src, src_ip)
725         return rx
726
727     def send_and_expect_no_arp(self, src, tx, dst):
728         self.pg_send(src, tx)
729         dst.get_capture(0, timeout=1)
730         dst.assert_nothing_captured(remark="")
731         timeout = 0.1
732
733     def send_and_expect_arp(self, src, tx, dst):
734         rx = self.send_and_expect(src, tx, dst)
735
736         for r in rx:
737             self.assertEqual(r[Ether].src, tx[0][Ether].src)
738             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
739             self.assertEqual(r[ARP].psrc, tx[0][ARP].psrc)
740             self.assertEqual(r[ARP].pdst, tx[0][ARP].pdst)
741             self.assertEqual(r[ARP].hwsrc, tx[0][ARP].hwsrc)
742             self.assertEqual(r[ARP].hwdst, tx[0][ARP].hwdst)
743         return rx
744
745     def test_gbp(self):
746         """ Group Based Policy """
747
748         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
749
750         #
751         # Route Domains
752         #
753         gt4 = VppIpTable(self, 0)
754         gt4.add_vpp_config()
755         gt6 = VppIpTable(self, 0, is_ip6=True)
756         gt6.add_vpp_config()
757         nt4 = VppIpTable(self, 20)
758         nt4.add_vpp_config()
759         nt6 = VppIpTable(self, 20, is_ip6=True)
760         nt6.add_vpp_config()
761
762         rd0 = VppGbpRouteDomain(self, 0, 400, gt4, gt6, None, None)
763         rd20 = VppGbpRouteDomain(self, 20, 420, nt4, nt6, None, None)
764
765         rd0.add_vpp_config()
766         rd20.add_vpp_config()
767
768         #
769         # Bridge Domains
770         #
771         bd1 = VppBridgeDomain(self, 1)
772         bd2 = VppBridgeDomain(self, 2)
773         bd20 = VppBridgeDomain(self, 20)
774
775         bd1.add_vpp_config()
776         bd2.add_vpp_config()
777         bd20.add_vpp_config()
778
779         gbd1 = VppGbpBridgeDomain(self, bd1, rd0, self.loop0)
780         gbd2 = VppGbpBridgeDomain(self, bd2, rd0, self.loop1)
781         gbd20 = VppGbpBridgeDomain(self, bd20, rd20, self.loop2)
782
783         gbd1.add_vpp_config()
784         gbd2.add_vpp_config()
785         gbd20.add_vpp_config()
786
787         #
788         # 3 EPGs, 2 of which share a BD.
789         # 2 NAT EPGs, one for floating-IP subnets, the other for internet
790         #
791         epgs = [VppGbpEndpointGroup(self, 220, 1220, rd0, gbd1,
792                                     self.pg4, self.loop0,
793                                     "10.0.0.128", "2001:10::128"),
794                 VppGbpEndpointGroup(self, 221, 1221, rd0, gbd1,
795                                     self.pg5, self.loop0,
796                                     "10.0.1.128", "2001:10:1::128"),
797                 VppGbpEndpointGroup(self, 222, 1222, rd0, gbd2,
798                                     self.pg6, self.loop1,
799                                     "10.0.2.128", "2001:10:2::128"),
800                 VppGbpEndpointGroup(self, 333, 1333, rd20, gbd20,
801                                     self.pg7, self.loop2,
802                                     "11.0.0.128", "3001::128"),
803                 VppGbpEndpointGroup(self, 444, 1444, rd20, gbd20,
804                                     self.pg8, self.loop2,
805                                     "11.0.0.129", "3001::129")]
806         recircs = [VppGbpRecirc(self, epgs[0], self.loop3),
807                    VppGbpRecirc(self, epgs[1], self.loop4),
808                    VppGbpRecirc(self, epgs[2], self.loop5),
809                    VppGbpRecirc(self, epgs[3], self.loop6, is_ext=True),
810                    VppGbpRecirc(self, epgs[4], self.loop7, is_ext=True)]
811
812         epg_nat = epgs[3]
813         recirc_nat = recircs[3]
814
815         #
816         # 4 end-points, 2 in the same subnet, 3 in the same BD
817         #
818         eps = [VppGbpEndpoint(self, self.pg0,
819                               epgs[0], recircs[0],
820                               "10.0.0.1", "11.0.0.1",
821                               "2001:10::1", "3001::1"),
822                VppGbpEndpoint(self, self.pg1,
823                               epgs[0], recircs[0],
824                               "10.0.0.2", "11.0.0.2",
825                               "2001:10::2", "3001::2"),
826                VppGbpEndpoint(self, self.pg2,
827                               epgs[1], recircs[1],
828                               "10.0.1.1", "11.0.0.3",
829                               "2001:10:1::1", "3001::3"),
830                VppGbpEndpoint(self, self.pg3,
831                               epgs[2], recircs[2],
832                               "10.0.2.1", "11.0.0.4",
833                               "2001:10:2::1", "3001::4")]
834
835         self.vapi.nat44_ed_plugin_enable_disable(enable=1)
836
837         #
838         # Config related to each of the EPGs
839         #
840         for epg in epgs:
841             # IP config on the BVI interfaces
842             if epg != epgs[1] and epg != epgs[4]:
843                 b4 = VppIpInterfaceBind(self, epg.bvi,
844                                         epg.rd.t4).add_vpp_config()
845                 b6 = VppIpInterfaceBind(self, epg.bvi,
846                                         epg.rd.t6).add_vpp_config()
847                 epg.bvi.set_mac(self.router_mac)
848
849                 # The BVIs are NAT inside interfaces
850                 flags = self.nat_config_flags.NAT_IS_INSIDE
851                 self.vapi.nat44_interface_add_del_feature(
852                     sw_if_index=epg.bvi.sw_if_index,
853                     flags=flags, is_add=1)
854                 self.vapi.nat66_add_del_interface(
855                     is_add=1, flags=flags,
856                     sw_if_index=epg.bvi.sw_if_index)
857
858             if_ip4 = VppIpInterfaceAddress(self, epg.bvi,
859                                            epg.bvi_ip4, 32,
860                                            bind=b4).add_vpp_config()
861             if_ip6 = VppIpInterfaceAddress(self, epg.bvi,
862                                            epg.bvi_ip6, 128,
863                                            bind=b6).add_vpp_config()
864
865             # EPG uplink interfaces in the RD
866             VppIpInterfaceBind(self, epg.uplink, epg.rd.t4).add_vpp_config()
867             VppIpInterfaceBind(self, epg.uplink, epg.rd.t6).add_vpp_config()
868
869             # add the BD ARP termination entry for BVI IP
870             epg.bd_arp_ip4 = VppBridgeDomainArpEntry(self, epg.bd.bd,
871                                                      str(self.router_mac),
872                                                      epg.bvi_ip4)
873             epg.bd_arp_ip6 = VppBridgeDomainArpEntry(self, epg.bd.bd,
874                                                      str(self.router_mac),
875                                                      epg.bvi_ip6)
876             epg.bd_arp_ip4.add_vpp_config()
877             epg.bd_arp_ip6.add_vpp_config()
878
879             # EPG in VPP
880             epg.add_vpp_config()
881
882         for recirc in recircs:
883             # EPG's ingress recirculation interface maps to its RD
884             VppIpInterfaceBind(self, recirc.recirc,
885                                recirc.epg.rd.t4).add_vpp_config()
886             VppIpInterfaceBind(self, recirc.recirc,
887                                recirc.epg.rd.t6).add_vpp_config()
888
889             self.vapi.nat44_interface_add_del_feature(
890                 sw_if_index=recirc.recirc.sw_if_index, is_add=1)
891             self.vapi.nat66_add_del_interface(
892                 is_add=1,
893                 sw_if_index=recirc.recirc.sw_if_index)
894
895             recirc.add_vpp_config()
896
897         for recirc in recircs:
898             self.assertTrue(find_bridge_domain_port(self,
899                                                     recirc.epg.bd.bd.bd_id,
900                                                     recirc.recirc.sw_if_index))
901
902         for ep in eps:
903             self.pg_enable_capture(self.pg_interfaces)
904             self.pg_start()
905             #
906             # routes to the endpoints. We need these since there are no
907             # adj-fibs due to the fact the the BVI address has /32 and
908             # the subnet is not attached.
909             #
910             for (ip, fip) in zip(ep.ips, ep.fips):
911                 # Add static mappings for each EP from the 10/8 to 11/8 network
912                 if ip_address(ip).version == 4:
913                     flags = self.nat_config_flags.NAT_IS_ADDR_ONLY
914                     self.vapi.nat44_add_del_static_mapping(
915                         is_add=1,
916                         local_ip_address=ip,
917                         external_ip_address=fip,
918                         external_sw_if_index=0xFFFFFFFF,
919                         vrf_id=0,
920                         flags=flags)
921                 else:
922                     self.vapi.nat66_add_del_static_mapping(
923                         local_ip_address=ip,
924                         external_ip_address=fip,
925                         vrf_id=0, is_add=1)
926
927             # VPP EP create ...
928             ep.add_vpp_config()
929
930             self.logger.info(self.vapi.cli("sh gbp endpoint"))
931
932             # ... results in a Gratuitous ARP/ND on the EPG's uplink
933             rx = ep.epg.uplink.get_capture(len(ep.ips), timeout=0.2)
934
935             for ii, ip in enumerate(ep.ips):
936                 p = rx[ii]
937
938                 if ip_address(ip).version == 6:
939                     self.assertTrue(p.haslayer(ICMPv6ND_NA))
940                     self.assertEqual(p[ICMPv6ND_NA].tgt, ip)
941                 else:
942                     self.assertTrue(p.haslayer(ARP))
943                     self.assertEqual(p[ARP].psrc, ip)
944                     self.assertEqual(p[ARP].pdst, ip)
945
946             # add the BD ARP termination entry for floating IP
947             for fip in ep.fips:
948                 ba = VppBridgeDomainArpEntry(self, epg_nat.bd.bd, ep.mac,
949                                              fip)
950                 ba.add_vpp_config()
951
952                 # floating IPs route via EPG recirc
953                 r = VppIpRoute(
954                     self, fip, ip_address(fip).max_prefixlen,
955                     [VppRoutePath(fip,
956                                   ep.recirc.recirc.sw_if_index,
957                                   type=FibPathType.FIB_PATH_TYPE_DVR,
958                                   proto=get_dpo_proto(fip))],
959                     table_id=20)
960                 r.add_vpp_config()
961
962             # L2 FIB entries in the NAT EPG BD to bridge the packets from
963             # the outside direct to the internal EPG
964             lf = VppL2FibEntry(self, epg_nat.bd.bd, ep.mac,
965                                ep.recirc.recirc, bvi_mac=0)
966             lf.add_vpp_config()
967
968         #
969         # ARP packets for unknown IP are sent to the EPG uplink
970         #
971         pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff",
972                          src=self.pg0.remote_mac) /
973                    ARP(op="who-has",
974                        hwdst="ff:ff:ff:ff:ff:ff",
975                        hwsrc=self.pg0.remote_mac,
976                        pdst="10.0.0.88",
977                        psrc="10.0.0.99"))
978
979         self.vapi.cli("clear trace")
980         self.pg0.add_stream(pkt_arp)
981
982         self.pg_enable_capture(self.pg_interfaces)
983         self.pg_start()
984
985         rxd = epgs[0].uplink.get_capture(1)
986
987         #
988         # ARP/ND packets get a response
989         #
990         pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff",
991                          src=self.pg0.remote_mac) /
992                    ARP(op="who-has",
993                        hwdst="ff:ff:ff:ff:ff:ff",
994                        hwsrc=self.pg0.remote_mac,
995                        pdst=epgs[0].bvi_ip4,
996                        psrc=eps[0].ip4))
997
998         self.send_and_expect(self.pg0, [pkt_arp], self.pg0)
999
1000         nsma = in6_getnsma(inet_pton(AF_INET6, eps[0].ip6))
1001         d = inet_ntop(AF_INET6, nsma)
1002         pkt_nd = (Ether(dst=in6_getnsmac(nsma),
1003                         src=self.pg0.remote_mac) /
1004                   IPv6(dst=d, src=eps[0].ip6) /
1005                   ICMPv6ND_NS(tgt=epgs[0].bvi_ip6) /
1006                   ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac))
1007         self.send_and_expect(self.pg0, [pkt_nd], self.pg0)
1008
1009         #
1010         # broadcast packets are flooded
1011         #
1012         pkt_bcast = (Ether(dst="ff:ff:ff:ff:ff:ff",
1013                            src=self.pg0.remote_mac) /
1014                      IP(src=eps[0].ip4, dst="232.1.1.1") /
1015                      UDP(sport=1234, dport=1234) /
1016                      Raw(b'\xa5' * 100))
1017
1018         self.vapi.cli("clear trace")
1019         self.pg0.add_stream(pkt_bcast)
1020
1021         self.pg_enable_capture(self.pg_interfaces)
1022         self.pg_start()
1023
1024         rxd = eps[1].itf.get_capture(1)
1025         self.assertEqual(rxd[0][Ether].dst, pkt_bcast[Ether].dst)
1026         rxd = epgs[0].uplink.get_capture(1)
1027         self.assertEqual(rxd[0][Ether].dst, pkt_bcast[Ether].dst)
1028
1029         #
1030         # packets to non-local L3 destinations dropped
1031         #
1032         pkt_intra_epg_220_ip4 = (Ether(src=self.pg0.remote_mac,
1033                                        dst=str(self.router_mac)) /
1034                                  IP(src=eps[0].ip4,
1035                                     dst="10.0.0.99") /
1036                                  UDP(sport=1234, dport=1234) /
1037                                  Raw(b'\xa5' * 100))
1038         pkt_inter_epg_222_ip4 = (Ether(src=self.pg0.remote_mac,
1039                                        dst=str(self.router_mac)) /
1040                                  IP(src=eps[0].ip4,
1041                                     dst="10.0.1.99") /
1042                                  UDP(sport=1234, dport=1234) /
1043                                  Raw(b'\xa5' * 100))
1044
1045         self.send_and_assert_no_replies(self.pg0,
1046                                         pkt_intra_epg_220_ip4 * NUM_PKTS)
1047
1048         pkt_inter_epg_222_ip6 = (Ether(src=self.pg0.remote_mac,
1049                                        dst=str(self.router_mac)) /
1050                                  IPv6(src=eps[0].ip6,
1051                                       dst="2001:10::99") /
1052                                  UDP(sport=1234, dport=1234) /
1053                                  Raw(b'\xa5' * 100))
1054         self.send_and_assert_no_replies(self.pg0,
1055                                         pkt_inter_epg_222_ip6 * NUM_PKTS)
1056
1057         #
1058         # Add the subnet routes
1059         #
1060         s41 = VppGbpSubnet(
1061             self, rd0, "10.0.0.0", 24,
1062             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
1063         s42 = VppGbpSubnet(
1064             self, rd0, "10.0.1.0", 24,
1065             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
1066         s43 = VppGbpSubnet(
1067             self, rd0, "10.0.2.0", 24,
1068             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
1069         s61 = VppGbpSubnet(
1070             self, rd0, "2001:10::1", 64,
1071             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
1072         s62 = VppGbpSubnet(
1073             self, rd0, "2001:10:1::1", 64,
1074             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
1075         s63 = VppGbpSubnet(
1076             self, rd0, "2001:10:2::1", 64,
1077             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
1078         s41.add_vpp_config()
1079         s42.add_vpp_config()
1080         s43.add_vpp_config()
1081         s61.add_vpp_config()
1082         s62.add_vpp_config()
1083         s63.add_vpp_config()
1084
1085         self.send_and_expect_bridged(eps[0].itf,
1086                                      pkt_intra_epg_220_ip4 * NUM_PKTS,
1087                                      eps[0].epg.uplink)
1088         self.send_and_expect_bridged(eps[0].itf,
1089                                      pkt_inter_epg_222_ip4 * NUM_PKTS,
1090                                      eps[0].epg.uplink)
1091         self.send_and_expect_bridged6(eps[0].itf,
1092                                       pkt_inter_epg_222_ip6 * NUM_PKTS,
1093                                       eps[0].epg.uplink)
1094
1095         self.logger.info(self.vapi.cli("sh ip fib 11.0.0.2"))
1096         self.logger.info(self.vapi.cli("sh gbp endpoint-group"))
1097         self.logger.info(self.vapi.cli("sh gbp endpoint"))
1098         self.logger.info(self.vapi.cli("sh gbp recirc"))
1099         self.logger.info(self.vapi.cli("sh int"))
1100         self.logger.info(self.vapi.cli("sh int addr"))
1101         self.logger.info(self.vapi.cli("sh int feat loop6"))
1102         self.logger.info(self.vapi.cli("sh vlib graph ip4-gbp-src-classify"))
1103         self.logger.info(self.vapi.cli("sh int feat loop3"))
1104         self.logger.info(self.vapi.cli("sh int feat pg0"))
1105
1106         #
1107         # Packet destined to unknown unicast is sent on the epg uplink ...
1108         #
1109         pkt_intra_epg_220_to_uplink = (Ether(src=self.pg0.remote_mac,
1110                                              dst="00:00:00:33:44:55") /
1111                                        IP(src=eps[0].ip4,
1112                                           dst="10.0.0.99") /
1113                                        UDP(sport=1234, dport=1234) /
1114                                        Raw(b'\xa5' * 100))
1115
1116         self.send_and_expect_bridged(eps[0].itf,
1117                                      pkt_intra_epg_220_to_uplink * NUM_PKTS,
1118                                      eps[0].epg.uplink)
1119         # ... and nowhere else
1120         self.pg1.get_capture(0, timeout=0.1)
1121         self.pg1.assert_nothing_captured(remark="Flood onto other VMS")
1122
1123         pkt_intra_epg_221_to_uplink = (Ether(src=self.pg2.remote_mac,
1124                                              dst="00:00:00:33:44:66") /
1125                                        IP(src=eps[0].ip4,
1126                                           dst="10.0.0.99") /
1127                                        UDP(sport=1234, dport=1234) /
1128                                        Raw(b'\xa5' * 100))
1129
1130         self.send_and_expect_bridged(eps[2].itf,
1131                                      pkt_intra_epg_221_to_uplink * NUM_PKTS,
1132                                      eps[2].epg.uplink)
1133
1134         #
1135         # Packets from the uplink are forwarded in the absence of a contract
1136         #
1137         pkt_intra_epg_220_from_uplink = (Ether(src="00:00:00:33:44:55",
1138                                                dst=self.pg0.remote_mac) /
1139                                          IP(src=eps[0].ip4,
1140                                             dst="10.0.0.99") /
1141                                          UDP(sport=1234, dport=1234) /
1142                                          Raw(b'\xa5' * 100))
1143
1144         self.send_and_expect_bridged(self.pg4,
1145                                      pkt_intra_epg_220_from_uplink * NUM_PKTS,
1146                                      self.pg0)
1147
1148         #
1149         # in the absence of policy, endpoints in the same EPG
1150         # can communicate
1151         #
1152         pkt_intra_epg = (Ether(src=self.pg0.remote_mac,
1153                                dst=self.pg1.remote_mac) /
1154                          IP(src=eps[0].ip4,
1155                             dst=eps[1].ip4) /
1156                          UDP(sport=1234, dport=1234) /
1157                          Raw(b'\xa5' * 100))
1158
1159         self.send_and_expect_bridged(self.pg0,
1160                                      pkt_intra_epg * NUM_PKTS,
1161                                      self.pg1)
1162
1163         #
1164         # in the absence of policy, endpoints in the different EPG
1165         # cannot communicate
1166         #
1167         pkt_inter_epg_220_to_221 = (Ether(src=self.pg0.remote_mac,
1168                                           dst=self.pg2.remote_mac) /
1169                                     IP(src=eps[0].ip4,
1170                                        dst=eps[2].ip4) /
1171                                     UDP(sport=1234, dport=1234) /
1172                                     Raw(b'\xa5' * 100))
1173         pkt_inter_epg_221_to_220 = (Ether(src=self.pg2.remote_mac,
1174                                           dst=self.pg0.remote_mac) /
1175                                     IP(src=eps[2].ip4,
1176                                        dst=eps[0].ip4) /
1177                                     UDP(sport=1234, dport=1234) /
1178                                     Raw(b'\xa5' * 100))
1179         pkt_inter_epg_220_to_222 = (Ether(src=self.pg0.remote_mac,
1180                                           dst=str(self.router_mac)) /
1181                                     IP(src=eps[0].ip4,
1182                                        dst=eps[3].ip4) /
1183                                     UDP(sport=1234, dport=1234) /
1184                                     Raw(b'\xa5' * 100))
1185
1186         self.send_and_assert_no_replies(eps[0].itf,
1187                                         pkt_inter_epg_220_to_221 * NUM_PKTS)
1188         self.send_and_assert_no_replies(eps[0].itf,
1189                                         pkt_inter_epg_220_to_222 * NUM_PKTS)
1190
1191         #
1192         # A uni-directional contract from EPG 220 -> 221
1193         #
1194         rule = AclRule(is_permit=1, proto=17)
1195         rule2 = AclRule(src_prefix=IPv6Network((0, 0)),
1196                         dst_prefix=IPv6Network((0, 0)), is_permit=1, proto=17)
1197         acl = VppAcl(self, rules=[rule, rule2])
1198         acl.add_vpp_config()
1199
1200         c1 = VppGbpContract(
1201             self, 400, epgs[0].sclass, epgs[1].sclass, acl.acl_index,
1202             [VppGbpContractRule(
1203                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1204                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1205                 []),
1206                 VppGbpContractRule(
1207                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1208                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1209                     [])],
1210             [ETH_P_IP, ETH_P_IPV6])
1211         c1.add_vpp_config()
1212
1213         self.send_and_expect_bridged(eps[0].itf,
1214                                      pkt_inter_epg_220_to_221 * NUM_PKTS,
1215                                      eps[2].itf)
1216         self.send_and_assert_no_replies(eps[0].itf,
1217                                         pkt_inter_epg_220_to_222 * NUM_PKTS)
1218
1219         #
1220         # contract for the return direction
1221         #
1222         c2 = VppGbpContract(
1223             self, 400, epgs[1].sclass, epgs[0].sclass, acl.acl_index,
1224             [VppGbpContractRule(
1225                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1226                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1227                 []),
1228                 VppGbpContractRule(
1229                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1230                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1231                     [])],
1232             [ETH_P_IP, ETH_P_IPV6])
1233         c2.add_vpp_config()
1234
1235         self.send_and_expect_bridged(eps[0].itf,
1236                                      pkt_inter_epg_220_to_221 * NUM_PKTS,
1237                                      eps[2].itf)
1238         self.send_and_expect_bridged(eps[2].itf,
1239                                      pkt_inter_epg_221_to_220 * NUM_PKTS,
1240                                      eps[0].itf)
1241
1242         ds = c2.get_drop_stats()
1243         self.assertEqual(ds['packets'], 0)
1244         ps = c2.get_permit_stats()
1245         self.assertEqual(ps['packets'], NUM_PKTS)
1246
1247         #
1248         # the contract does not allow non-IP
1249         #
1250         pkt_non_ip_inter_epg_220_to_221 = (Ether(src=self.pg0.remote_mac,
1251                                                  dst=self.pg2.remote_mac) /
1252                                            ARP())
1253         self.send_and_assert_no_replies(eps[0].itf,
1254                                         pkt_non_ip_inter_epg_220_to_221 * 17)
1255
1256         #
1257         # check that inter group is still disabled for the groups
1258         # not in the contract.
1259         #
1260         self.send_and_assert_no_replies(eps[0].itf,
1261                                         pkt_inter_epg_220_to_222 * NUM_PKTS)
1262
1263         #
1264         # A uni-directional contract from EPG 220 -> 222 'L3 routed'
1265         #
1266         c3 = VppGbpContract(
1267             self, 400, epgs[0].sclass, epgs[2].sclass, acl.acl_index,
1268             [VppGbpContractRule(
1269                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1270                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1271                 []),
1272                 VppGbpContractRule(
1273                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1274                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1275                     [])],
1276             [ETH_P_IP, ETH_P_IPV6])
1277         c3.add_vpp_config()
1278
1279         self.logger.info(self.vapi.cli("sh gbp contract"))
1280
1281         self.send_and_expect_routed(eps[0].itf,
1282                                     pkt_inter_epg_220_to_222 * NUM_PKTS,
1283                                     eps[3].itf,
1284                                     str(self.router_mac))
1285
1286         #
1287         # remove both contracts, traffic stops in both directions
1288         #
1289         c2.remove_vpp_config()
1290         c1.remove_vpp_config()
1291         c3.remove_vpp_config()
1292         acl.remove_vpp_config()
1293
1294         self.send_and_assert_no_replies(eps[2].itf,
1295                                         pkt_inter_epg_221_to_220 * NUM_PKTS)
1296         self.send_and_assert_no_replies(eps[0].itf,
1297                                         pkt_inter_epg_220_to_221 * NUM_PKTS)
1298         self.send_and_expect_bridged(eps[0].itf,
1299                                      pkt_intra_epg * NUM_PKTS,
1300                                      eps[1].itf)
1301
1302         #
1303         # EPs to the outside world
1304         #
1305
1306         # in the EP's RD an external subnet via the NAT EPG's recirc
1307         se1 = VppGbpSubnet(
1308             self, rd0, "0.0.0.0", 0,
1309             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1310             sw_if_index=recirc_nat.recirc.sw_if_index,
1311             sclass=epg_nat.sclass)
1312         se2 = VppGbpSubnet(
1313             self, rd0, "11.0.0.0", 8,
1314             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1315             sw_if_index=recirc_nat.recirc.sw_if_index,
1316             sclass=epg_nat.sclass)
1317         se16 = VppGbpSubnet(
1318             self, rd0, "::", 0,
1319             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1320             sw_if_index=recirc_nat.recirc.sw_if_index,
1321             sclass=epg_nat.sclass)
1322         # in the NAT RD an external subnet via the NAT EPG's uplink
1323         se3 = VppGbpSubnet(
1324             self, rd20, "0.0.0.0", 0,
1325             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1326             sw_if_index=epg_nat.uplink.sw_if_index,
1327             sclass=epg_nat.sclass)
1328         se36 = VppGbpSubnet(
1329             self, rd20, "::", 0,
1330             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1331             sw_if_index=epg_nat.uplink.sw_if_index,
1332             sclass=epg_nat.sclass)
1333         se4 = VppGbpSubnet(
1334             self, rd20, "11.0.0.0", 8,
1335             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1336             sw_if_index=epg_nat.uplink.sw_if_index,
1337             sclass=epg_nat.sclass)
1338         se1.add_vpp_config()
1339         se2.add_vpp_config()
1340         se16.add_vpp_config()
1341         se3.add_vpp_config()
1342         se36.add_vpp_config()
1343         se4.add_vpp_config()
1344
1345         self.logger.info(self.vapi.cli("sh ip fib 0.0.0.0/0"))
1346         self.logger.info(self.vapi.cli("sh ip fib 11.0.0.1"))
1347         self.logger.info(self.vapi.cli("sh ip6 fib ::/0"))
1348         self.logger.info(self.vapi.cli("sh ip6 fib %s" %
1349                                        eps[0].fip6))
1350
1351         #
1352         # From an EP to an outside address: IN2OUT
1353         #
1354         pkt_inter_epg_220_to_global = (Ether(src=self.pg0.remote_mac,
1355                                              dst=str(self.router_mac)) /
1356                                        IP(src=eps[0].ip4,
1357                                           dst="1.1.1.1") /
1358                                        UDP(sport=1234, dport=1234) /
1359                                        Raw(b'\xa5' * 100))
1360
1361         # no policy yet
1362         self.send_and_assert_no_replies(eps[0].itf,
1363                                         pkt_inter_epg_220_to_global * NUM_PKTS)
1364         rule = AclRule(is_permit=1, proto=17, ports=1234)
1365         rule2 = AclRule(is_permit=1, proto=17, ports=1234,
1366                         src_prefix=IPv6Network((0, 0)),
1367                         dst_prefix=IPv6Network((0, 0)))
1368         acl2 = VppAcl(self, rules=[rule, rule2])
1369         acl2.add_vpp_config()
1370
1371         c4 = VppGbpContract(
1372             self, 400, epgs[0].sclass, epgs[3].sclass, acl2.acl_index,
1373             [VppGbpContractRule(
1374                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1375                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1376                 []),
1377                 VppGbpContractRule(
1378                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1379                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1380                     [])],
1381             [ETH_P_IP, ETH_P_IPV6])
1382         c4.add_vpp_config()
1383
1384         self.send_and_expect_natted(eps[0].itf,
1385                                     pkt_inter_epg_220_to_global * NUM_PKTS,
1386                                     self.pg7,
1387                                     eps[0].fip4)
1388
1389         pkt_inter_epg_220_to_global = (Ether(src=self.pg0.remote_mac,
1390                                              dst=str(self.router_mac)) /
1391                                        IPv6(src=eps[0].ip6,
1392                                             dst="6001::1") /
1393                                        UDP(sport=1234, dport=1234) /
1394                                        Raw(b'\xa5' * 100))
1395
1396         self.send_and_expect_natted6(self.pg0,
1397                                      pkt_inter_epg_220_to_global * NUM_PKTS,
1398                                      self.pg7,
1399                                      eps[0].fip6)
1400
1401         #
1402         # From a global address to an EP: OUT2IN
1403         #
1404         pkt_inter_epg_220_from_global = (Ether(src=str(self.router_mac),
1405                                                dst=self.pg0.remote_mac) /
1406                                          IP(dst=eps[0].fip4,
1407                                             src="1.1.1.1") /
1408                                          UDP(sport=1234, dport=1234) /
1409                                          Raw(b'\xa5' * 100))
1410
1411         self.send_and_assert_no_replies(
1412             self.pg7, pkt_inter_epg_220_from_global * NUM_PKTS)
1413
1414         c5 = VppGbpContract(
1415             self, 400, epgs[3].sclass, epgs[0].sclass, acl2.acl_index,
1416             [VppGbpContractRule(
1417                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1418                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1419                 []),
1420                 VppGbpContractRule(
1421                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1422                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1423                     [])],
1424             [ETH_P_IP, ETH_P_IPV6])
1425         c5.add_vpp_config()
1426
1427         self.send_and_expect_unnatted(self.pg7,
1428                                       pkt_inter_epg_220_from_global * NUM_PKTS,
1429                                       eps[0].itf,
1430                                       eps[0].ip4)
1431
1432         pkt_inter_epg_220_from_global = (Ether(src=str(self.router_mac),
1433                                                dst=self.pg0.remote_mac) /
1434                                          IPv6(dst=eps[0].fip6,
1435                                               src="6001::1") /
1436                                          UDP(sport=1234, dport=1234) /
1437                                          Raw(b'\xa5' * 100))
1438
1439         self.send_and_expect_unnatted6(
1440             self.pg7,
1441             pkt_inter_epg_220_from_global * NUM_PKTS,
1442             eps[0].itf,
1443             eps[0].ip6)
1444
1445         #
1446         # From a local VM to another local VM using resp. public addresses:
1447         #  IN2OUT2IN
1448         #
1449         pkt_intra_epg_220_global = (Ether(src=self.pg0.remote_mac,
1450                                           dst=str(self.router_mac)) /
1451                                     IP(src=eps[0].ip4,
1452                                        dst=eps[1].fip4) /
1453                                     UDP(sport=1234, dport=1234) /
1454                                     Raw(b'\xa5' * 100))
1455
1456         self.send_and_expect_double_natted(eps[0].itf,
1457                                            pkt_intra_epg_220_global * NUM_PKTS,
1458                                            eps[1].itf,
1459                                            eps[0].fip4,
1460                                            eps[1].ip4)
1461
1462         pkt_intra_epg_220_global = (Ether(src=self.pg0.remote_mac,
1463                                           dst=str(self.router_mac)) /
1464                                     IPv6(src=eps[0].ip6,
1465                                          dst=eps[1].fip6) /
1466                                     UDP(sport=1234, dport=1234) /
1467                                     Raw(b'\xa5' * 100))
1468
1469         self.send_and_expect_double_natted6(
1470             eps[0].itf,
1471             pkt_intra_epg_220_global * NUM_PKTS,
1472             eps[1].itf,
1473             eps[0].fip6,
1474             eps[1].ip6)
1475
1476         #
1477         # cleanup
1478         #
1479         self.vapi.nat44_ed_plugin_enable_disable(enable=0)
1480
1481         for ep in eps:
1482             # del static mappings for each EP from the 10/8 to 11/8 network
1483             flags = self.nat_config_flags.NAT_IS_ADDR_ONLY
1484             self.vapi.nat66_add_del_static_mapping(
1485                 local_ip_address=ep.ip6,
1486                 external_ip_address=ep.fip6,
1487                 vrf_id=0, is_add=0)
1488
1489         for epg in epgs:
1490             # IP config on the BVI interfaces
1491             if epg != epgs[0] and epg != epgs[3]:
1492                 flags = self.nat_config_flags.NAT_IS_INSIDE
1493                 self.vapi.nat66_add_del_interface(
1494                     sw_if_index=epg.bvi.sw_if_index,
1495                     flags=flags, is_add=0)
1496
1497         for recirc in recircs:
1498             self.vapi.nat66_add_del_interface(
1499                 sw_if_index=recirc.recirc.sw_if_index, is_add=0)
1500
1501     def wait_for_ep_timeout(self, sw_if_index=None, ip=None, mac=None,
1502                             tep=None, n_tries=100, s_time=1):
1503         # only learnt EP can timeout
1504         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
1505         flags = ep_flags.GBP_API_ENDPOINT_FLAG_LEARNT
1506         while (n_tries):
1507             if not find_gbp_endpoint(self, sw_if_index, ip, mac, tep=tep,
1508                                      flags=flags):
1509                 return True
1510             n_tries = n_tries - 1
1511             self.sleep(s_time)
1512         self.assertFalse(find_gbp_endpoint(self, sw_if_index, ip, mac, tep=tep,
1513                                            flags=flags))
1514         return False
1515
1516     def test_gbp_learn_l2(self):
1517         """ GBP L2 Endpoint Learning """
1518
1519         drop_no_contract = self.statistics.get_err_counter(
1520             '/err/gbp-policy-port/drop-no-contract')
1521         allow_intra_class = self.statistics.get_err_counter(
1522             '/err/gbp-policy-port/allow-intra-sclass')
1523
1524         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
1525         learnt = [{'mac': '00:00:11:11:11:01',
1526                    'ip': '10.0.0.1',
1527                    'ip6': '2001:10::2'},
1528                   {'mac': '00:00:11:11:11:02',
1529                    'ip': '10.0.0.2',
1530                    'ip6': '2001:10::3'}]
1531
1532         #
1533         # IP tables
1534         #
1535         gt4 = VppIpTable(self, 1)
1536         gt4.add_vpp_config()
1537         gt6 = VppIpTable(self, 1, is_ip6=True)
1538         gt6.add_vpp_config()
1539
1540         rd1 = VppGbpRouteDomain(self, 1, 401, gt4, gt6)
1541         rd1.add_vpp_config()
1542
1543         #
1544         # Pg2 hosts the vxlan tunnel, hosts on pg2 to act as TEPs
1545         # Pg3 hosts the IP4 UU-flood VXLAN tunnel
1546         # Pg4 hosts the IP6 UU-flood VXLAN tunnel
1547         #
1548         self.pg2.config_ip4()
1549         self.pg2.resolve_arp()
1550         self.pg2.generate_remote_hosts(4)
1551         self.pg2.configure_ipv4_neighbors()
1552         self.pg3.config_ip4()
1553         self.pg3.resolve_arp()
1554         self.pg4.config_ip4()
1555         self.pg4.resolve_arp()
1556
1557         #
1558         # Add a mcast destination VXLAN-GBP tunnel for B&M traffic
1559         #
1560         tun_bm = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
1561                                    "239.1.1.1", 88,
1562                                    mcast_itf=self.pg4)
1563         tun_bm.add_vpp_config()
1564
1565         #
1566         # a GBP bridge domain with a BVI and a UU-flood interface
1567         #
1568         bd1 = VppBridgeDomain(self, 1)
1569         bd1.add_vpp_config()
1570         gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0,
1571                                   self.pg3, tun_bm)
1572         gbd1.add_vpp_config()
1573
1574         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1575         self.logger.info(self.vapi.cli("sh gbp bridge"))
1576
1577         # ... and has a /32 applied
1578         ip_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
1579         ip_addr.add_vpp_config()
1580
1581         #
1582         # The Endpoint-group in which we are learning endpoints
1583         #
1584         epg_220 = VppGbpEndpointGroup(self, 220, 112, rd1, gbd1,
1585                                       None, self.loop0,
1586                                       "10.0.0.128",
1587                                       "2001:10::128",
1588                                       VppGbpEndpointRetention(4))
1589         epg_220.add_vpp_config()
1590         epg_330 = VppGbpEndpointGroup(self, 330, 113, rd1, gbd1,
1591                                       None, self.loop1,
1592                                       "10.0.1.128",
1593                                       "2001:11::128",
1594                                       VppGbpEndpointRetention(4))
1595         epg_330.add_vpp_config()
1596
1597         #
1598         # The VXLAN GBP tunnel is a bridge-port and has L2 endpoint
1599         # learning enabled
1600         #
1601         vx_tun_l2_1 = VppGbpVxlanTunnel(
1602             self, 99, bd1.bd_id,
1603             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L2,
1604             self.pg2.local_ip4)
1605         vx_tun_l2_1.add_vpp_config()
1606
1607         #
1608         # A static endpoint that the learnt endpoints are trying to
1609         # talk to
1610         #
1611         ep = VppGbpEndpoint(self, self.pg0,
1612                             epg_220, None,
1613                             "10.0.0.127", "11.0.0.127",
1614                             "2001:10::1", "3001::1")
1615         ep.add_vpp_config()
1616
1617         self.assertTrue(find_route(self, ep.ip4, 32, table_id=1))
1618
1619         # a packet with an sclass from an unknown EPG
1620         p = (Ether(src=self.pg2.remote_mac,
1621                    dst=self.pg2.local_mac) /
1622              IP(src=self.pg2.remote_hosts[0].ip4,
1623                 dst=self.pg2.local_ip4) /
1624              UDP(sport=1234, dport=48879) /
1625              VXLAN(vni=99, gpid=88, flags=0x88) /
1626              Ether(src=learnt[0]["mac"], dst=ep.mac) /
1627              IP(src=learnt[0]["ip"], dst=ep.ip4) /
1628              UDP(sport=1234, dport=1234) /
1629              Raw(b'\xa5' * 100))
1630
1631         self.send_and_assert_no_replies(self.pg2, p)
1632
1633         self.logger.info(self.vapi.cli("sh error"))
1634         self.assert_error_counter_equal(
1635             '/err/gbp-policy-port/drop-no-contract',
1636             drop_no_contract + 1)
1637
1638         #
1639         # we should not have learnt a new tunnel endpoint, since
1640         # the EPG was not learnt.
1641         #
1642         self.assertEqual(INDEX_INVALID,
1643                          find_vxlan_gbp_tunnel(self,
1644                                                self.pg2.local_ip4,
1645                                                self.pg2.remote_hosts[0].ip4,
1646                                                99))
1647
1648         # ep is not learnt, because the EPG is unknown
1649         self.assertEqual(len(self.vapi.gbp_endpoint_dump()), 1)
1650
1651         #
1652         # Learn new EPs from IP packets
1653         #
1654         for ii, l in enumerate(learnt):
1655             # a packet with an sclass from a known EPG
1656             # arriving on an unknown TEP
1657             p = (Ether(src=self.pg2.remote_mac,
1658                        dst=self.pg2.local_mac) /
1659                  IP(src=self.pg2.remote_hosts[1].ip4,
1660                     dst=self.pg2.local_ip4) /
1661                  UDP(sport=1234, dport=48879) /
1662                  VXLAN(vni=99, gpid=112, flags=0x88) /
1663                  Ether(src=l['mac'], dst=ep.mac) /
1664                  IP(src=l['ip'], dst=ep.ip4) /
1665                  UDP(sport=1234, dport=1234) /
1666                  Raw(b'\xa5' * 100))
1667
1668             rx = self.send_and_expect(self.pg2, [p], self.pg0)
1669
1670             # the new TEP
1671             tep1_sw_if_index = find_vxlan_gbp_tunnel(
1672                 self,
1673                 self.pg2.local_ip4,
1674                 self.pg2.remote_hosts[1].ip4,
1675                 99)
1676             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
1677
1678             #
1679             # the EP is learnt via the learnt TEP
1680             # both from its MAC and its IP
1681             #
1682             self.assertTrue(find_gbp_endpoint(self,
1683                                               vx_tun_l2_1.sw_if_index,
1684                                               mac=l['mac']))
1685             self.assertTrue(find_gbp_endpoint(self,
1686                                               vx_tun_l2_1.sw_if_index,
1687                                               ip=l['ip']))
1688
1689         self.assert_error_counter_equal(
1690             '/err/gbp-policy-port/allow-intra-sclass',
1691             allow_intra_class + 2)
1692
1693         self.logger.info(self.vapi.cli("show gbp endpoint"))
1694         self.logger.info(self.vapi.cli("show gbp vxlan"))
1695         self.logger.info(self.vapi.cli("show ip mfib"))
1696
1697         #
1698         # If we sleep for the threshold time, the learnt endpoints should
1699         # age out
1700         #
1701         for l in learnt:
1702             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
1703                                      mac=l['mac'])
1704
1705         #
1706         # Learn new EPs from GARP packets received on the BD's mcast tunnel
1707         #
1708         for ii, l in enumerate(learnt):
1709             # add some junk in the reserved field of the vxlan-header
1710             # next to the VNI. we should accept since reserved bits are
1711             # ignored on rx.
1712             p = (Ether(src=self.pg2.remote_mac,
1713                        dst=self.pg2.local_mac) /
1714                  IP(src=self.pg2.remote_hosts[1].ip4,
1715                     dst="239.1.1.1") /
1716                  UDP(sport=1234, dport=48879) /
1717                  VXLAN(vni=88, reserved2=0x80, gpid=112, flags=0x88) /
1718                  Ether(src=l['mac'], dst="ff:ff:ff:ff:ff:ff") /
1719                  ARP(op="who-has",
1720                      psrc=l['ip'], pdst=l['ip'],
1721                      hwsrc=l['mac'], hwdst="ff:ff:ff:ff:ff:ff"))
1722
1723             rx = self.send_and_expect(self.pg4, [p], self.pg0)
1724
1725             # the new TEP
1726             tep1_sw_if_index = find_vxlan_gbp_tunnel(
1727                 self,
1728                 self.pg2.local_ip4,
1729                 self.pg2.remote_hosts[1].ip4,
1730                 99)
1731             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
1732
1733             #
1734             # the EP is learnt via the learnt TEP
1735             # both from its MAC and its IP
1736             #
1737             self.assertTrue(find_gbp_endpoint(self,
1738                                               vx_tun_l2_1.sw_if_index,
1739                                               mac=l['mac']))
1740             self.assertTrue(find_gbp_endpoint(self,
1741                                               vx_tun_l2_1.sw_if_index,
1742                                               ip=l['ip']))
1743
1744         #
1745         # wait for the learnt endpoints to age out
1746         #
1747         for l in learnt:
1748             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
1749                                      mac=l['mac'])
1750
1751         #
1752         # Learn new EPs from L2 packets
1753         #
1754         for ii, l in enumerate(learnt):
1755             # a packet with an sclass from a known EPG
1756             # arriving on an unknown TEP
1757             p = (Ether(src=self.pg2.remote_mac,
1758                        dst=self.pg2.local_mac) /
1759                  IP(src=self.pg2.remote_hosts[1].ip4,
1760                     dst=self.pg2.local_ip4) /
1761                  UDP(sport=1234, dport=48879) /
1762                  VXLAN(vni=99, gpid=112, flags=0x88) /
1763                  Ether(src=l['mac'], dst=ep.mac) /
1764                  Raw(b'\xa5' * 100))
1765
1766             rx = self.send_and_expect(self.pg2, [p], self.pg0)
1767
1768             # the new TEP
1769             tep1_sw_if_index = find_vxlan_gbp_tunnel(
1770                 self,
1771                 self.pg2.local_ip4,
1772                 self.pg2.remote_hosts[1].ip4,
1773                 99)
1774             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
1775
1776             #
1777             # the EP is learnt via the learnt TEP
1778             # both from its MAC and its IP
1779             #
1780             self.assertTrue(find_gbp_endpoint(self,
1781                                               vx_tun_l2_1.sw_if_index,
1782                                               mac=l['mac']))
1783
1784         self.logger.info(self.vapi.cli("show gbp endpoint"))
1785         self.logger.info(self.vapi.cli("show gbp vxlan"))
1786         self.logger.info(self.vapi.cli("show vxlan-gbp tunnel"))
1787
1788         #
1789         # wait for the learnt endpoints to age out
1790         #
1791         for l in learnt:
1792             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
1793                                      mac=l['mac'])
1794
1795         #
1796         # repeat. the do not learn bit is set so the EPs are not learnt
1797         #
1798         for l in learnt:
1799             # a packet with an sclass from a known EPG
1800             p = (Ether(src=self.pg2.remote_mac,
1801                        dst=self.pg2.local_mac) /
1802                  IP(src=self.pg2.remote_hosts[1].ip4,
1803                     dst=self.pg2.local_ip4) /
1804                  UDP(sport=1234, dport=48879) /
1805                  VXLAN(vni=99, gpid=112, flags=0x88, gpflags="D") /
1806                  Ether(src=l['mac'], dst=ep.mac) /
1807                  IP(src=l['ip'], dst=ep.ip4) /
1808                  UDP(sport=1234, dport=1234) /
1809                  Raw(b'\xa5' * 100))
1810
1811             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
1812
1813         for l in learnt:
1814             self.assertFalse(find_gbp_endpoint(self,
1815                                                vx_tun_l2_1.sw_if_index,
1816                                                mac=l['mac']))
1817
1818         #
1819         # repeat
1820         #
1821         for l in learnt:
1822             # a packet with an sclass from a known EPG
1823             # set a reserved bit in addition to the G and I
1824             # reserved bits should not be checked on rx.
1825             p = (Ether(src=self.pg2.remote_mac,
1826                        dst=self.pg2.local_mac) /
1827                  IP(src=self.pg2.remote_hosts[1].ip4,
1828                     dst=self.pg2.local_ip4) /
1829                  UDP(sport=1234, dport=48879) /
1830                  VXLAN(vni=99, gpid=112, flags=0xc8) /
1831                  Ether(src=l['mac'], dst=ep.mac) /
1832                  IP(src=l['ip'], dst=ep.ip4) /
1833                  UDP(sport=1234, dport=1234) /
1834                  Raw(b'\xa5' * 100))
1835
1836             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
1837
1838             self.assertTrue(find_gbp_endpoint(self,
1839                                               vx_tun_l2_1.sw_if_index,
1840                                               mac=l['mac']))
1841
1842         #
1843         # Static EP replies to dynamics
1844         #
1845         self.logger.info(self.vapi.cli("sh l2fib bd_id 1"))
1846         for l in learnt:
1847             p = (Ether(src=ep.mac, dst=l['mac']) /
1848                  IP(dst=l['ip'], src=ep.ip4) /
1849                  UDP(sport=1234, dport=1234) /
1850                  Raw(b'\xa5' * 100))
1851
1852             rxs = self.send_and_expect(self.pg0, p * 17, self.pg2)
1853
1854             for rx in rxs:
1855                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
1856                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
1857                 self.assertEqual(rx[UDP].dport, 48879)
1858                 # the UDP source port is a random value for hashing
1859                 self.assertEqual(rx[VXLAN].gpid, 112)
1860                 self.assertEqual(rx[VXLAN].vni, 99)
1861                 self.assertTrue(rx[VXLAN].flags.G)
1862                 self.assertTrue(rx[VXLAN].flags.Instance)
1863                 self.assertTrue(rx[VXLAN].gpflags.A)
1864                 self.assertFalse(rx[VXLAN].gpflags.D)
1865
1866         for l in learnt:
1867             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
1868                                      mac=l['mac'])
1869
1870         #
1871         # repeat in the other EPG
1872         # there's no contract between 220 and 330, but the A-bit is set
1873         # so the packet is cleared for delivery
1874         #
1875         for l in learnt:
1876             # a packet with an sclass from a known EPG
1877             p = (Ether(src=self.pg2.remote_mac,
1878                        dst=self.pg2.local_mac) /
1879                  IP(src=self.pg2.remote_hosts[1].ip4,
1880                     dst=self.pg2.local_ip4) /
1881                  UDP(sport=1234, dport=48879) /
1882                  VXLAN(vni=99, gpid=113, flags=0x88, gpflags='A') /
1883                  Ether(src=l['mac'], dst=ep.mac) /
1884                  IP(src=l['ip'], dst=ep.ip4) /
1885                  UDP(sport=1234, dport=1234) /
1886                  Raw(b'\xa5' * 100))
1887
1888             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
1889
1890             self.assertTrue(find_gbp_endpoint(self,
1891                                               vx_tun_l2_1.sw_if_index,
1892                                               mac=l['mac']))
1893
1894         #
1895         # static EP cannot reach the learnt EPs since there is no contract
1896         # only test 1 EP as the others could timeout
1897         #
1898         p = (Ether(src=ep.mac, dst=l['mac']) /
1899              IP(dst=learnt[0]['ip'], src=ep.ip4) /
1900              UDP(sport=1234, dport=1234) /
1901              Raw(b'\xa5' * 100))
1902
1903         self.send_and_assert_no_replies(self.pg0, [p])
1904
1905         #
1906         # refresh the entries after the check for no replies above
1907         #
1908         for l in learnt:
1909             # a packet with an sclass from a known EPG
1910             p = (Ether(src=self.pg2.remote_mac,
1911                        dst=self.pg2.local_mac) /
1912                  IP(src=self.pg2.remote_hosts[1].ip4,
1913                     dst=self.pg2.local_ip4) /
1914                  UDP(sport=1234, dport=48879) /
1915                  VXLAN(vni=99, gpid=113, flags=0x88, gpflags='A') /
1916                  Ether(src=l['mac'], dst=ep.mac) /
1917                  IP(src=l['ip'], dst=ep.ip4) /
1918                  UDP(sport=1234, dport=1234) /
1919                  Raw(b'\xa5' * 100))
1920
1921             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
1922
1923             self.assertTrue(find_gbp_endpoint(self,
1924                                               vx_tun_l2_1.sw_if_index,
1925                                               mac=l['mac']))
1926
1927         #
1928         # Add the contract so they can talk
1929         #
1930         rule = AclRule(is_permit=1, proto=17)
1931         rule2 = AclRule(src_prefix=IPv6Network((0, 0)),
1932                         dst_prefix=IPv6Network((0, 0)), is_permit=1, proto=17)
1933         acl = VppAcl(self, rules=[rule, rule2])
1934         acl.add_vpp_config()
1935
1936         c1 = VppGbpContract(
1937             self, 401, epg_220.sclass, epg_330.sclass, acl.acl_index,
1938             [VppGbpContractRule(
1939                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1940                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1941                 []),
1942              VppGbpContractRule(
1943                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1944                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1945                  [])],
1946             [ETH_P_IP, ETH_P_IPV6])
1947         c1.add_vpp_config()
1948
1949         for l in learnt:
1950             p = (Ether(src=ep.mac, dst=l['mac']) /
1951                  IP(dst=l['ip'], src=ep.ip4) /
1952                  UDP(sport=1234, dport=1234) /
1953                  Raw(b'\xa5' * 100))
1954
1955             self.send_and_expect(self.pg0, [p], self.pg2)
1956
1957         #
1958         # send UU packets from the local EP
1959         #
1960         self.logger.info(self.vapi.cli("sh gbp bridge"))
1961         self.logger.info(self.vapi.cli("sh bridge-domain 1 detail"))
1962         p_uu = (Ether(src=ep.mac, dst="00:11:11:11:11:11") /
1963                 IP(dst="10.0.0.133", src=ep.ip4) /
1964                 UDP(sport=1234, dport=1234) /
1965                 Raw(b'\xa5' * 100))
1966         rxs = self.send_and_expect(ep.itf, [p_uu], gbd1.uu_fwd)
1967
1968         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1969
1970         p_bm = (Ether(src=ep.mac, dst="ff:ff:ff:ff:ff:ff") /
1971                 IP(dst="10.0.0.133", src=ep.ip4) /
1972                 UDP(sport=1234, dport=1234) /
1973                 Raw(b'\xa5' * 100))
1974         rxs = self.send_and_expect_only(ep.itf, [p_bm], tun_bm.mcast_itf)
1975
1976         for rx in rxs:
1977             self.assertEqual(rx[IP].src, self.pg4.local_ip4)
1978             self.assertEqual(rx[IP].dst, "239.1.1.1")
1979             self.assertEqual(rx[UDP].dport, 48879)
1980             # the UDP source port is a random value for hashing
1981             self.assertEqual(rx[VXLAN].gpid, 112)
1982             self.assertEqual(rx[VXLAN].vni, 88)
1983             self.assertTrue(rx[VXLAN].flags.G)
1984             self.assertTrue(rx[VXLAN].flags.Instance)
1985             self.assertFalse(rx[VXLAN].gpflags.A)
1986             self.assertFalse(rx[VXLAN].gpflags.D)
1987
1988         rule = AclRule(is_permit=1, proto=17)
1989         rule2 = AclRule(src_prefix=IPv6Network((0, 0)),
1990                         dst_prefix=IPv6Network((0, 0)), is_permit=1, proto=17)
1991         acl = VppAcl(self, rules=[rule, rule2])
1992         acl.add_vpp_config()
1993
1994         c2 = VppGbpContract(
1995             self, 401, epg_330.sclass, epg_220.sclass, acl.acl_index,
1996             [VppGbpContractRule(
1997                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1998                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1999                 []),
2000                 VppGbpContractRule(
2001                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2002                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2003                     [])],
2004             [ETH_P_IP, ETH_P_IPV6])
2005         c2.add_vpp_config()
2006
2007         for l in learnt:
2008             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
2009                                      mac=l['mac'])
2010         #
2011         # Check v6 Endpoints learning
2012         #
2013         for l in learnt:
2014             # a packet with an sclass from a known EPG
2015             p = (Ether(src=self.pg2.remote_mac,
2016                        dst=self.pg2.local_mac) /
2017                  IP(src=self.pg2.remote_hosts[1].ip4,
2018                     dst=self.pg2.local_ip4) /
2019                  UDP(sport=1234, dport=48879) /
2020                  VXLAN(vni=99, gpid=113, flags=0x88) /
2021                  Ether(src=l['mac'], dst=ep.mac) /
2022                  IPv6(src=l['ip6'], dst=ep.ip6) /
2023                  UDP(sport=1234, dport=1234) /
2024                  Raw(b'\xa5' * 100))
2025
2026             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
2027             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
2028
2029             self.assertTrue(find_gbp_endpoint(
2030                 self,
2031                 vx_tun_l2_1.sw_if_index,
2032                 ip=l['ip6'],
2033                 tep=[self.pg2.local_ip4,
2034                      self.pg2.remote_hosts[1].ip4]))
2035
2036         self.logger.info(self.vapi.cli("sh int"))
2037         self.logger.info(self.vapi.cli("sh vxlan-gbp tunnel"))
2038         self.logger.info(self.vapi.cli("sh gbp vxlan"))
2039         self.logger.info(self.vapi.cli("sh gbp endpoint"))
2040         self.logger.info(self.vapi.cli("sh gbp interface"))
2041
2042         #
2043         # EP moves to a different TEP
2044         #
2045         for l in learnt:
2046             # a packet with an sclass from a known EPG
2047             p = (Ether(src=self.pg2.remote_mac,
2048                        dst=self.pg2.local_mac) /
2049                  IP(src=self.pg2.remote_hosts[2].ip4,
2050                     dst=self.pg2.local_ip4) /
2051                  UDP(sport=1234, dport=48879) /
2052                  VXLAN(vni=99, gpid=113, flags=0x88) /
2053                  Ether(src=l['mac'], dst=ep.mac) /
2054                  IPv6(src=l['ip6'], dst=ep.ip6) /
2055                  UDP(sport=1234, dport=1234) /
2056                  Raw(b'\xa5' * 100))
2057
2058             rx = self.send_and_expect(self.pg2, p * 1, self.pg0)
2059             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
2060
2061             self.assertTrue(find_gbp_endpoint(
2062                 self,
2063                 vx_tun_l2_1.sw_if_index,
2064                 sclass=113,
2065                 mac=l['mac'],
2066                 tep=[self.pg2.local_ip4,
2067                      self.pg2.remote_hosts[2].ip4]))
2068
2069         #
2070         # v6 remote EP reachability
2071         #
2072         for l in learnt:
2073             p = (Ether(src=ep.mac, dst=l['mac']) /
2074                  IPv6(dst=l['ip6'], src=ep.ip6) /
2075                  UDP(sport=1234, dport=1234) /
2076                  Raw(b'\xa5' * 100))
2077
2078             rxs = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg2)
2079
2080             for rx in rxs:
2081                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2082                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[2].ip4)
2083                 self.assertEqual(rx[UDP].dport, 48879)
2084                 # the UDP source port is a random value for hashing
2085                 self.assertEqual(rx[VXLAN].gpid, 112)
2086                 self.assertEqual(rx[VXLAN].vni, 99)
2087                 self.assertTrue(rx[VXLAN].flags.G)
2088                 self.assertTrue(rx[VXLAN].flags.Instance)
2089                 self.assertTrue(rx[VXLAN].gpflags.A)
2090                 self.assertFalse(rx[VXLAN].gpflags.D)
2091                 self.assertEqual(rx[IPv6].dst, l['ip6'])
2092
2093         #
2094         # EP changes sclass
2095         #
2096         for l in learnt:
2097             # a packet with an sclass from a known EPG
2098             p = (Ether(src=self.pg2.remote_mac,
2099                        dst=self.pg2.local_mac) /
2100                  IP(src=self.pg2.remote_hosts[2].ip4,
2101                     dst=self.pg2.local_ip4) /
2102                  UDP(sport=1234, dport=48879) /
2103                  VXLAN(vni=99, gpid=112, flags=0x88) /
2104                  Ether(src=l['mac'], dst=ep.mac) /
2105                  IPv6(src=l['ip6'], dst=ep.ip6) /
2106                  UDP(sport=1234, dport=1234) /
2107                  Raw(b'\xa5' * 100))
2108
2109             rx = self.send_and_expect(self.pg2, p * 1, self.pg0)
2110             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
2111
2112             self.assertTrue(find_gbp_endpoint(
2113                 self,
2114                 vx_tun_l2_1.sw_if_index,
2115                 mac=l['mac'],
2116                 sclass=112,
2117                 tep=[self.pg2.local_ip4,
2118                      self.pg2.remote_hosts[2].ip4]))
2119
2120         #
2121         # check reachability and contract intra-epg
2122         #
2123         allow_intra_class = self.statistics.get_err_counter(
2124             '/err/gbp-policy-mac/allow-intra-sclass')
2125
2126         for l in learnt:
2127             p = (Ether(src=ep.mac, dst=l['mac']) /
2128                  IPv6(dst=l['ip6'], src=ep.ip6) /
2129                  UDP(sport=1234, dport=1234) /
2130                  Raw(b'\xa5' * 100))
2131
2132             rxs = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg2)
2133
2134             for rx in rxs:
2135                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2136                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[2].ip4)
2137                 self.assertEqual(rx[UDP].dport, 48879)
2138                 self.assertEqual(rx[VXLAN].gpid, 112)
2139                 self.assertEqual(rx[VXLAN].vni, 99)
2140                 self.assertTrue(rx[VXLAN].flags.G)
2141                 self.assertTrue(rx[VXLAN].flags.Instance)
2142                 self.assertTrue(rx[VXLAN].gpflags.A)
2143                 self.assertFalse(rx[VXLAN].gpflags.D)
2144                 self.assertEqual(rx[IPv6].dst, l['ip6'])
2145
2146             allow_intra_class += NUM_PKTS
2147
2148         self.assert_error_counter_equal(
2149             '/err/gbp-policy-mac/allow-intra-sclass',
2150             allow_intra_class)
2151
2152         #
2153         # clean up
2154         #
2155         for l in learnt:
2156             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
2157                                      mac=l['mac'])
2158         self.pg2.unconfig_ip4()
2159         self.pg3.unconfig_ip4()
2160         self.pg4.unconfig_ip4()
2161
2162     def test_gbp_contract(self):
2163         """ GBP Contracts """
2164
2165         #
2166         # Route Domains
2167         #
2168         gt4 = VppIpTable(self, 0)
2169         gt4.add_vpp_config()
2170         gt6 = VppIpTable(self, 0, is_ip6=True)
2171         gt6.add_vpp_config()
2172
2173         rd0 = VppGbpRouteDomain(self, 0, 400, gt4, gt6, None, None)
2174
2175         rd0.add_vpp_config()
2176
2177         #
2178         # Bridge Domains
2179         #
2180         bd1 = VppBridgeDomain(self, 1, arp_term=0)
2181         bd2 = VppBridgeDomain(self, 2, arp_term=0)
2182
2183         bd1.add_vpp_config()
2184         bd2.add_vpp_config()
2185
2186         gbd1 = VppGbpBridgeDomain(self, bd1, rd0, self.loop0)
2187         gbd2 = VppGbpBridgeDomain(self, bd2, rd0, self.loop1)
2188
2189         gbd1.add_vpp_config()
2190         gbd2.add_vpp_config()
2191
2192         #
2193         # 3 EPGs, 2 of which share a BD.
2194         #
2195         epgs = [VppGbpEndpointGroup(self, 220, 1220, rd0, gbd1,
2196                                     None, self.loop0,
2197                                     "10.0.0.128", "2001:10::128"),
2198                 VppGbpEndpointGroup(self, 221, 1221, rd0, gbd1,
2199                                     None, self.loop0,
2200                                     "10.0.1.128", "2001:10:1::128"),
2201                 VppGbpEndpointGroup(self, 222, 1222, rd0, gbd2,
2202                                     None, self.loop1,
2203                                     "10.0.2.128", "2001:10:2::128")]
2204         #
2205         # 4 end-points, 2 in the same subnet, 3 in the same BD
2206         #
2207         eps = [VppGbpEndpoint(self, self.pg0,
2208                               epgs[0], None,
2209                               "10.0.0.1", "11.0.0.1",
2210                               "2001:10::1", "3001::1"),
2211                VppGbpEndpoint(self, self.pg1,
2212                               epgs[0], None,
2213                               "10.0.0.2", "11.0.0.2",
2214                               "2001:10::2", "3001::2"),
2215                VppGbpEndpoint(self, self.pg2,
2216                               epgs[1], None,
2217                               "10.0.1.1", "11.0.0.3",
2218                               "2001:10:1::1", "3001::3"),
2219                VppGbpEndpoint(self, self.pg3,
2220                               epgs[2], None,
2221                               "10.0.2.1", "11.0.0.4",
2222                               "2001:10:2::1", "3001::4")]
2223
2224         #
2225         # Config related to each of the EPGs
2226         #
2227         for epg in epgs:
2228             # IP config on the BVI interfaces
2229             if epg != epgs[1]:
2230                 b4 = VppIpInterfaceBind(self, epg.bvi,
2231                                         epg.rd.t4).add_vpp_config()
2232                 b6 = VppIpInterfaceBind(self, epg.bvi,
2233                                         epg.rd.t6).add_vpp_config()
2234                 epg.bvi.set_mac(self.router_mac)
2235
2236             if_ip4 = VppIpInterfaceAddress(self, epg.bvi,
2237                                            epg.bvi_ip4, 32,
2238                                            bind=b4).add_vpp_config()
2239             if_ip6 = VppIpInterfaceAddress(self, epg.bvi,
2240                                            epg.bvi_ip6, 128,
2241                                            bind=b6).add_vpp_config()
2242
2243             # add the BD ARP termination entry for BVI IP
2244             epg.bd_arp_ip4 = VppBridgeDomainArpEntry(self, epg.bd.bd,
2245                                                      str(self.router_mac),
2246                                                      epg.bvi_ip4)
2247             epg.bd_arp_ip4.add_vpp_config()
2248
2249             # EPG in VPP
2250             epg.add_vpp_config()
2251
2252         #
2253         # config ep
2254         #
2255         for ep in eps:
2256             ep.add_vpp_config()
2257
2258         self.logger.info(self.vapi.cli("show gbp endpoint"))
2259         self.logger.info(self.vapi.cli("show interface"))
2260         self.logger.info(self.vapi.cli("show br"))
2261
2262         #
2263         # Intra epg allowed without contract
2264         #
2265         pkt_intra_epg_220_to_220 = (Ether(src=self.pg0.remote_mac,
2266                                           dst=self.pg1.remote_mac) /
2267                                     IP(src=eps[0].ip4,
2268                                        dst=eps[1].ip4) /
2269                                     UDP(sport=1234, dport=1234) /
2270                                     Raw(b'\xa5' * 100))
2271
2272         self.send_and_expect_bridged(self.pg0,
2273                                      pkt_intra_epg_220_to_220 * 65,
2274                                      self.pg1)
2275
2276         pkt_intra_epg_220_to_220 = (Ether(src=self.pg0.remote_mac,
2277                                           dst=self.pg1.remote_mac) /
2278                                     IPv6(src=eps[0].ip6,
2279                                          dst=eps[1].ip6) /
2280                                     UDP(sport=1234, dport=1234) /
2281                                     Raw(b'\xa5' * 100))
2282
2283         self.send_and_expect_bridged6(self.pg0,
2284                                       pkt_intra_epg_220_to_220 * 65,
2285                                       self.pg1)
2286
2287         #
2288         # Inter epg denied without contract
2289         #
2290         pkt_inter_epg_220_to_221 = (Ether(src=self.pg0.remote_mac,
2291                                           dst=self.pg2.remote_mac) /
2292                                     IP(src=eps[0].ip4,
2293                                        dst=eps[2].ip4) /
2294                                     UDP(sport=1234, dport=1234) /
2295                                     Raw(b'\xa5' * 100))
2296
2297         self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_220_to_221)
2298
2299         #
2300         # A uni-directional contract from EPG 220 -> 221
2301         #
2302         rule = AclRule(is_permit=1, proto=17)
2303         rule2 = AclRule(src_prefix=IPv6Network((0, 0)),
2304                         dst_prefix=IPv6Network((0, 0)), is_permit=1, proto=17)
2305         rule3 = AclRule(is_permit=1, proto=1)
2306         acl = VppAcl(self, rules=[rule, rule2, rule3])
2307         acl.add_vpp_config()
2308
2309         c1 = VppGbpContract(
2310             self, 400, epgs[0].sclass, epgs[1].sclass, acl.acl_index,
2311             [VppGbpContractRule(
2312                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2313                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2314                 []),
2315              VppGbpContractRule(
2316                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2317                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2318                  []),
2319              VppGbpContractRule(
2320                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2321                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2322                  [])],
2323             [ETH_P_IP, ETH_P_IPV6])
2324         c1.add_vpp_config()
2325
2326         self.send_and_expect_bridged(eps[0].itf,
2327                                      pkt_inter_epg_220_to_221 * 65,
2328                                      eps[2].itf)
2329
2330         pkt_inter_epg_220_to_222 = (Ether(src=self.pg0.remote_mac,
2331                                           dst=str(self.router_mac)) /
2332                                     IP(src=eps[0].ip4,
2333                                        dst=eps[3].ip4) /
2334                                     UDP(sport=1234, dport=1234) /
2335                                     Raw(b'\xa5' * 100))
2336         self.send_and_assert_no_replies(eps[0].itf,
2337                                         pkt_inter_epg_220_to_222 * 65)
2338
2339         #
2340         # ping router IP in different BD
2341         #
2342         pkt_router_ping_220_to_221 = (Ether(src=self.pg0.remote_mac,
2343                                             dst=str(self.router_mac)) /
2344                                       IP(src=eps[0].ip4,
2345                                          dst=epgs[1].bvi_ip4) /
2346                                       ICMP(type='echo-request'))
2347
2348         self.send_and_expect(self.pg0, [pkt_router_ping_220_to_221], self.pg0)
2349
2350         pkt_router_ping_220_to_221 = (Ether(src=self.pg0.remote_mac,
2351                                             dst=str(self.router_mac)) /
2352                                       IPv6(src=eps[0].ip6,
2353                                            dst=epgs[1].bvi_ip6) /
2354                                       ICMPv6EchoRequest())
2355
2356         self.send_and_expect(self.pg0, [pkt_router_ping_220_to_221], self.pg0)
2357
2358         #
2359         # contract for the return direction
2360         #
2361         c2 = VppGbpContract(
2362             self, 400, epgs[1].sclass, epgs[0].sclass, acl.acl_index,
2363             [VppGbpContractRule(
2364                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2365                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2366                 []),
2367              VppGbpContractRule(
2368                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2369                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2370                  [])],
2371             [ETH_P_IP, ETH_P_IPV6])
2372         c2.add_vpp_config()
2373
2374         self.send_and_expect_bridged(eps[0].itf,
2375                                      pkt_inter_epg_220_to_221 * 65,
2376                                      eps[2].itf)
2377         pkt_inter_epg_221_to_220 = (Ether(src=self.pg2.remote_mac,
2378                                           dst=self.pg0.remote_mac) /
2379                                     IP(src=eps[2].ip4,
2380                                        dst=eps[0].ip4) /
2381                                     UDP(sport=1234, dport=1234) /
2382                                     Raw(b'\xa5' * 100))
2383         self.send_and_expect_bridged(eps[2].itf,
2384                                      pkt_inter_epg_221_to_220 * 65,
2385                                      eps[0].itf)
2386         pkt_inter_epg_221_to_220 = (Ether(src=self.pg2.remote_mac,
2387                                           dst=str(self.router_mac)) /
2388                                     IP(src=eps[2].ip4,
2389                                        dst=eps[0].ip4) /
2390                                     UDP(sport=1234, dport=1234) /
2391                                     Raw(b'\xa5' * 100))
2392         self.send_and_expect_routed(eps[2].itf,
2393                                     pkt_inter_epg_221_to_220 * 65,
2394                                     eps[0].itf,
2395                                     str(self.router_mac))
2396         pkt_inter_epg_221_to_220 = (Ether(src=self.pg2.remote_mac,
2397                                           dst=str(self.router_mac)) /
2398                                     IPv6(src=eps[2].ip6,
2399                                          dst=eps[0].ip6) /
2400                                     UDP(sport=1234, dport=1234) /
2401                                     Raw(b'\xa5' * 100))
2402         self.send_and_expect_routed6(eps[2].itf,
2403                                      pkt_inter_epg_221_to_220 * 65,
2404                                      eps[0].itf,
2405                                      str(self.router_mac))
2406
2407         #
2408         # contract between 220 and 222 uni-direction
2409         #
2410         c3 = VppGbpContract(
2411             self, 400, epgs[0].sclass, epgs[2].sclass, acl.acl_index,
2412             [VppGbpContractRule(
2413                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2414                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2415                 []),
2416              VppGbpContractRule(
2417                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2418                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2419                  [])],
2420             [ETH_P_IP, ETH_P_IPV6])
2421         c3.add_vpp_config()
2422
2423         self.send_and_expect(eps[0].itf,
2424                              pkt_inter_epg_220_to_222 * 65,
2425                              eps[3].itf)
2426
2427         c3.remove_vpp_config()
2428         c1.remove_vpp_config()
2429         c2.remove_vpp_config()
2430         acl.remove_vpp_config()
2431
2432     def test_gbp_bd_drop_flags(self):
2433         """ GBP BD drop flags """
2434
2435         #
2436         # IP tables
2437         #
2438         gt4 = VppIpTable(self, 1)
2439         gt4.add_vpp_config()
2440         gt6 = VppIpTable(self, 1, is_ip6=True)
2441         gt6.add_vpp_config()
2442
2443         rd1 = VppGbpRouteDomain(self, 1, 401, gt4, gt6)
2444         rd1.add_vpp_config()
2445
2446         #
2447         # a GBP bridge domain with a BVI only
2448         #
2449         bd1 = VppBridgeDomain(self, 1)
2450         bd1.add_vpp_config()
2451
2452         gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0,
2453                                   None, None,
2454                                   uu_drop=True, bm_drop=True)
2455         gbd1.add_vpp_config()
2456
2457         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
2458         self.logger.info(self.vapi.cli("sh gbp bridge"))
2459
2460         # ... and has a /32 applied
2461         ip_addr = VppIpInterfaceAddress(self, gbd1.bvi,
2462                                         "10.0.0.128", 32).add_vpp_config()
2463
2464         #
2465         # The Endpoint-group
2466         #
2467         epg_220 = VppGbpEndpointGroup(self, 220, 112, rd1, gbd1,
2468                                       None, self.loop0,
2469                                       "10.0.0.128",
2470                                       "2001:10::128",
2471                                       VppGbpEndpointRetention(3))
2472         epg_220.add_vpp_config()
2473
2474         ep = VppGbpEndpoint(self, self.pg0,
2475                             epg_220, None,
2476                             "10.0.0.127", "11.0.0.127",
2477                             "2001:10::1", "3001::1")
2478         ep.add_vpp_config()
2479
2480         #
2481         # send UU/BM packet from the local EP with UU drop and BM drop enabled
2482         # in bd
2483         #
2484         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
2485         self.logger.info(self.vapi.cli("sh gbp bridge"))
2486         p_uu = (Ether(src=ep.mac, dst="00:11:11:11:11:11") /
2487                 IP(dst="10.0.0.133", src=ep.ip4) /
2488                 UDP(sport=1234, dport=1234) /
2489                 Raw(b'\xa5' * 100))
2490         self.send_and_assert_no_replies(ep.itf, [p_uu])
2491
2492         p_bm = (Ether(src=ep.mac, dst="ff:ff:ff:ff:ff:ff") /
2493                 IP(dst="10.0.0.133", src=ep.ip4) /
2494                 UDP(sport=1234, dport=1234) /
2495                 Raw(b'\xa5' * 100))
2496         self.send_and_assert_no_replies(ep.itf, [p_bm])
2497
2498         self.pg3.unconfig_ip4()
2499
2500         self.logger.info(self.vapi.cli("sh int"))
2501
2502     def test_gbp_bd_arp_flags(self):
2503         """ GBP BD arp flags """
2504
2505         #
2506         # IP tables
2507         #
2508         gt4 = VppIpTable(self, 1)
2509         gt4.add_vpp_config()
2510         gt6 = VppIpTable(self, 1, is_ip6=True)
2511         gt6.add_vpp_config()
2512
2513         rd1 = VppGbpRouteDomain(self, 1, 401, gt4, gt6)
2514         rd1.add_vpp_config()
2515
2516         #
2517         # Pg4 hosts the IP6 UU-flood VXLAN tunnel
2518         #
2519         self.pg4.config_ip4()
2520         self.pg4.resolve_arp()
2521
2522         #
2523         # Add a mcast destination VXLAN-GBP tunnel for B&M traffic
2524         #
2525         tun_uu = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
2526                                    "239.1.1.1", 88,
2527                                    mcast_itf=self.pg4)
2528         tun_uu.add_vpp_config()
2529
2530         #
2531         # a GBP bridge domain with a BVI and a UU-flood interface
2532         #
2533         bd1 = VppBridgeDomain(self, 1)
2534         bd1.add_vpp_config()
2535
2536         gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0,
2537                                   tun_uu, None,
2538                                   ucast_arp=True)
2539         gbd1.add_vpp_config()
2540
2541         # ... and has a /32 applied
2542         ip_addr = VppIpInterfaceAddress(self, gbd1.bvi,
2543                                         "10.0.0.128", 32).add_vpp_config()
2544
2545         #
2546         # The Endpoint-group
2547         #
2548         epg_220 = VppGbpEndpointGroup(self, 220, 112, rd1, gbd1,
2549                                       None, self.loop0,
2550                                       "10.0.0.128",
2551                                       "2001:10::128",
2552                                       VppGbpEndpointRetention(2))
2553         epg_220.add_vpp_config()
2554
2555         ep = VppGbpEndpoint(self, self.pg0,
2556                             epg_220, None,
2557                             "10.0.0.127", "11.0.0.127",
2558                             "2001:10::1", "3001::1")
2559         ep.add_vpp_config()
2560
2561         #
2562         # send ARP packet from the local EP expect it on the uu interface
2563         #
2564         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
2565         self.logger.info(self.vapi.cli("sh gbp bridge"))
2566         p_arp = (Ether(src=ep.mac, dst="ff:ff:ff:ff:ff:ff") /
2567                  ARP(op="who-has",
2568                      psrc=ep.ip4, pdst="10.0.0.99",
2569                      hwsrc=ep.mac,
2570                      hwdst="ff:ff:ff:ff:ff:ff"))
2571         self.send_and_expect(ep.itf, [p_arp], self.pg4)
2572
2573         self.pg4.unconfig_ip4()
2574
2575     def test_gbp_learn_vlan_l2(self):
2576         """ GBP L2 Endpoint w/ VLANs"""
2577
2578         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
2579         learnt = [{'mac': '00:00:11:11:11:01',
2580                    'ip': '10.0.0.1',
2581                    'ip6': '2001:10::2'},
2582                   {'mac': '00:00:11:11:11:02',
2583                    'ip': '10.0.0.2',
2584                    'ip6': '2001:10::3'}]
2585
2586         #
2587         # IP tables
2588         #
2589         gt4 = VppIpTable(self, 1)
2590         gt4.add_vpp_config()
2591         gt6 = VppIpTable(self, 1, is_ip6=True)
2592         gt6.add_vpp_config()
2593
2594         rd1 = VppGbpRouteDomain(self, 1, 401, gt4, gt6)
2595         rd1.add_vpp_config()
2596
2597         #
2598         # Pg2 hosts the vxlan tunnel, hosts on pg2 to act as TEPs
2599         #
2600         self.pg2.config_ip4()
2601         self.pg2.resolve_arp()
2602         self.pg2.generate_remote_hosts(4)
2603         self.pg2.configure_ipv4_neighbors()
2604         self.pg3.config_ip4()
2605         self.pg3.resolve_arp()
2606
2607         #
2608         # The EP will be on a vlan sub-interface
2609         #
2610         vlan_11 = VppDot1QSubint(self, self.pg0, 11)
2611         vlan_11.admin_up()
2612         self.vapi.l2_interface_vlan_tag_rewrite(
2613             sw_if_index=vlan_11.sw_if_index, vtr_op=L2_VTR_OP.L2_POP_1,
2614             push_dot1q=11)
2615
2616         bd_uu_fwd = VppVxlanGbpTunnel(self, self.pg3.local_ip4,
2617                                       self.pg3.remote_ip4, 116)
2618         bd_uu_fwd.add_vpp_config()
2619
2620         #
2621         # a GBP bridge domain with a BVI and a UU-flood interface
2622         # The BD is marked as do not learn, so no endpoints are ever
2623         # learnt in this BD.
2624         #
2625         bd1 = VppBridgeDomain(self, 1)
2626         bd1.add_vpp_config()
2627         gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0, bd_uu_fwd,
2628                                   learn=False)
2629         gbd1.add_vpp_config()
2630
2631         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
2632         self.logger.info(self.vapi.cli("sh gbp bridge"))
2633
2634         # ... and has a /32 applied
2635         ip_addr = VppIpInterfaceAddress(self, gbd1.bvi,
2636                                         "10.0.0.128", 32).add_vpp_config()
2637
2638         #
2639         # The Endpoint-group in which we are learning endpoints
2640         #
2641         epg_220 = VppGbpEndpointGroup(self, 220, 441, rd1, gbd1,
2642                                       None, self.loop0,
2643                                       "10.0.0.128",
2644                                       "2001:10::128",
2645                                       VppGbpEndpointRetention(4))
2646         epg_220.add_vpp_config()
2647
2648         #
2649         # The VXLAN GBP tunnel is a bridge-port and has L2 endpoint
2650         # learning enabled
2651         #
2652         vx_tun_l2_1 = VppGbpVxlanTunnel(
2653             self, 99, bd1.bd_id,
2654             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L2,
2655             self.pg2.local_ip4)
2656         vx_tun_l2_1.add_vpp_config()
2657
2658         #
2659         # A static endpoint that the learnt endpoints are trying to
2660         # talk to
2661         #
2662         ep = VppGbpEndpoint(self, vlan_11,
2663                             epg_220, None,
2664                             "10.0.0.127", "11.0.0.127",
2665                             "2001:10::1", "3001::1")
2666         ep.add_vpp_config()
2667
2668         self.assertTrue(find_route(self, ep.ip4, 32, table_id=1))
2669
2670         #
2671         # Send to the static EP
2672         #
2673         for ii, l in enumerate(learnt):
2674             # a packet with an sclass from a known EPG
2675             # arriving on an unknown TEP
2676             p = (Ether(src=self.pg2.remote_mac,
2677                        dst=self.pg2.local_mac) /
2678                  IP(src=self.pg2.remote_hosts[1].ip4,
2679                     dst=self.pg2.local_ip4) /
2680                  UDP(sport=1234, dport=48879) /
2681                  VXLAN(vni=99, gpid=441, flags=0x88) /
2682                  Ether(src=l['mac'], dst=ep.mac) /
2683                  IP(src=l['ip'], dst=ep.ip4) /
2684                  UDP(sport=1234, dport=1234) /
2685                  Raw(b'\xa5' * 100))
2686
2687             rxs = self.send_and_expect(self.pg2, [p], self.pg0)
2688
2689             #
2690             # packet to EP has the EP's vlan tag
2691             #
2692             for rx in rxs:
2693                 self.assertEqual(rx[Dot1Q].vlan, 11)
2694
2695             #
2696             # the EP is not learnt since the BD setting prevents it
2697             # also no TEP too
2698             #
2699             self.assertFalse(find_gbp_endpoint(self,
2700                                                vx_tun_l2_1.sw_if_index,
2701                                                mac=l['mac']))
2702             self.assertEqual(INDEX_INVALID,
2703                              find_vxlan_gbp_tunnel(
2704                                  self,
2705                                  self.pg2.local_ip4,
2706                                  self.pg2.remote_hosts[1].ip4,
2707                                  99))
2708
2709         self.assertEqual(len(self.vapi.gbp_endpoint_dump()), 1)
2710
2711         #
2712         # static to remotes
2713         # we didn't learn the remotes so they are sent to the UU-fwd
2714         #
2715         for l in learnt:
2716             p = (Ether(src=ep.mac, dst=l['mac']) /
2717                  Dot1Q(vlan=11) /
2718                  IP(dst=l['ip'], src=ep.ip4) /
2719                  UDP(sport=1234, dport=1234) /
2720                  Raw(b'\xa5' * 100))
2721
2722             rxs = self.send_and_expect(self.pg0, p * 17, self.pg3)
2723
2724             for rx in rxs:
2725                 self.assertEqual(rx[IP].src, self.pg3.local_ip4)
2726                 self.assertEqual(rx[IP].dst, self.pg3.remote_ip4)
2727                 self.assertEqual(rx[UDP].dport, 48879)
2728                 # the UDP source port is a random value for hashing
2729                 self.assertEqual(rx[VXLAN].gpid, 441)
2730                 self.assertEqual(rx[VXLAN].vni, 116)
2731                 self.assertTrue(rx[VXLAN].flags.G)
2732                 self.assertTrue(rx[VXLAN].flags.Instance)
2733                 self.assertFalse(rx[VXLAN].gpflags.A)
2734                 self.assertFalse(rx[VXLAN].gpflags.D)
2735
2736         self.pg2.unconfig_ip4()
2737         self.pg3.unconfig_ip4()
2738
2739     def test_gbp_learn_l3(self):
2740         """ GBP L3 Endpoint Learning """
2741
2742         self.vapi.cli("set logging class gbp level debug")
2743
2744         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
2745         routed_dst_mac = "00:0c:0c:0c:0c:0c"
2746         routed_src_mac = "00:22:bd:f8:19:ff"
2747
2748         learnt = [{'mac': '00:00:11:11:11:02',
2749                    'ip': '10.0.1.2',
2750                    'ip6': '2001:10::2'},
2751                   {'mac': '00:00:11:11:11:03',
2752                    'ip': '10.0.1.3',
2753                    'ip6': '2001:10::3'}]
2754
2755         #
2756         # IP tables
2757         #
2758         t4 = VppIpTable(self, 1)
2759         t4.add_vpp_config()
2760         t6 = VppIpTable(self, 1, True)
2761         t6.add_vpp_config()
2762
2763         tun_ip4_uu = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
2764                                        self.pg4.remote_ip4, 114)
2765         tun_ip6_uu = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
2766                                        self.pg4.remote_ip4, 116)
2767         tun_ip4_uu.add_vpp_config()
2768         tun_ip6_uu.add_vpp_config()
2769
2770         rd1 = VppGbpRouteDomain(self, 2, 401, t4, t6, tun_ip4_uu, tun_ip6_uu)
2771         rd1.add_vpp_config()
2772
2773         self.loop0.set_mac(self.router_mac)
2774
2775         #
2776         # Bind the BVI to the RD
2777         #
2778         b4 = VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
2779         b6 = VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
2780
2781         #
2782         # Pg2 hosts the vxlan tunnel
2783         # hosts on pg2 to act as TEPs
2784         # pg3 is BD uu-fwd
2785         # pg4 is RD uu-fwd
2786         #
2787         self.pg2.config_ip4()
2788         self.pg2.resolve_arp()
2789         self.pg2.generate_remote_hosts(4)
2790         self.pg2.configure_ipv4_neighbors()
2791         self.pg3.config_ip4()
2792         self.pg3.resolve_arp()
2793         self.pg4.config_ip4()
2794         self.pg4.resolve_arp()
2795
2796         #
2797         # a GBP bridge domain with a BVI and a UU-flood interface
2798         #
2799         bd1 = VppBridgeDomain(self, 1)
2800         bd1.add_vpp_config()
2801         gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0, self.pg3)
2802         gbd1.add_vpp_config()
2803
2804         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
2805         self.logger.info(self.vapi.cli("sh gbp bridge"))
2806         self.logger.info(self.vapi.cli("sh gbp route"))
2807
2808         # ... and has a /32 and /128 applied
2809         ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi,
2810                                          "10.0.0.128", 32,
2811                                          bind=b4).add_vpp_config()
2812         ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi,
2813                                          "2001:10::128", 128,
2814                                          bind=b6).add_vpp_config()
2815
2816         #
2817         # The Endpoint-group in which we are learning endpoints
2818         #
2819         epg_220 = VppGbpEndpointGroup(self, 220, 441, rd1, gbd1,
2820                                       None, self.loop0,
2821                                       "10.0.0.128",
2822                                       "2001:10::128",
2823                                       VppGbpEndpointRetention(4))
2824         epg_220.add_vpp_config()
2825
2826         #
2827         # The VXLAN GBP tunnel is in L3 mode with learning enabled
2828         #
2829         vx_tun_l3 = VppGbpVxlanTunnel(
2830             self, 101, rd1.rd_id,
2831             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3,
2832             self.pg2.local_ip4)
2833         vx_tun_l3.add_vpp_config()
2834
2835         #
2836         # A static endpoint that the learnt endpoints are trying to
2837         # talk to
2838         #
2839         ep = VppGbpEndpoint(self, self.pg0,
2840                             epg_220, None,
2841                             "10.0.0.127", "11.0.0.127",
2842                             "2001:10::1", "3001::1")
2843         ep.add_vpp_config()
2844
2845         #
2846         # learn some remote IPv4 EPs
2847         #
2848         for ii, l in enumerate(learnt):
2849             # a packet with an sclass from a known EPG
2850             # arriving on an unknown TEP
2851             p = (Ether(src=self.pg2.remote_mac,
2852                        dst=self.pg2.local_mac) /
2853                  IP(src=self.pg2.remote_hosts[1].ip4,
2854                     dst=self.pg2.local_ip4) /
2855                  UDP(sport=1234, dport=48879) /
2856                  VXLAN(vni=101, gpid=441, flags=0x88) /
2857                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
2858                  IP(src=l['ip'], dst=ep.ip4) /
2859                  UDP(sport=1234, dport=1234) /
2860                  Raw(b'\xa5' * 100))
2861
2862             rx = self.send_and_expect(self.pg2, [p], self.pg0)
2863
2864             # the new TEP
2865             tep1_sw_if_index = find_vxlan_gbp_tunnel(
2866                 self,
2867                 self.pg2.local_ip4,
2868                 self.pg2.remote_hosts[1].ip4,
2869                 vx_tun_l3.vni)
2870             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
2871
2872             # endpoint learnt via the parent GBP-vxlan interface
2873             self.assertTrue(find_gbp_endpoint(self,
2874                                               vx_tun_l3._sw_if_index,
2875                                               ip=l['ip']))
2876
2877         #
2878         # Static IPv4 EP replies to learnt
2879         #
2880         for l in learnt:
2881             p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2882                  IP(dst=l['ip'], src=ep.ip4) /
2883                  UDP(sport=1234, dport=1234) /
2884                  Raw(b'\xa5' * 100))
2885
2886             rxs = self.send_and_expect(self.pg0, p * 1, self.pg2)
2887
2888             for rx in rxs:
2889                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2890                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
2891                 self.assertEqual(rx[UDP].dport, 48879)
2892                 # the UDP source port is a random value for hashing
2893                 self.assertEqual(rx[VXLAN].gpid, 441)
2894                 self.assertEqual(rx[VXLAN].vni, 101)
2895                 self.assertTrue(rx[VXLAN].flags.G)
2896                 self.assertTrue(rx[VXLAN].flags.Instance)
2897                 self.assertTrue(rx[VXLAN].gpflags.A)
2898                 self.assertFalse(rx[VXLAN].gpflags.D)
2899
2900                 inner = rx[VXLAN].payload
2901
2902                 self.assertEqual(inner[Ether].src, routed_src_mac)
2903                 self.assertEqual(inner[Ether].dst, routed_dst_mac)
2904                 self.assertEqual(inner[IP].src, ep.ip4)
2905                 self.assertEqual(inner[IP].dst, l['ip'])
2906
2907         for l in learnt:
2908             self.assertFalse(find_gbp_endpoint(self,
2909                                                tep1_sw_if_index,
2910                                                ip=l['ip']))
2911
2912         #
2913         # learn some remote IPv6 EPs
2914         #
2915         for ii, l in enumerate(learnt):
2916             # a packet with an sclass from a known EPG
2917             # arriving on an unknown TEP
2918             p = (Ether(src=self.pg2.remote_mac,
2919                        dst=self.pg2.local_mac) /
2920                  IP(src=self.pg2.remote_hosts[1].ip4,
2921                     dst=self.pg2.local_ip4) /
2922                  UDP(sport=1234, dport=48879) /
2923                  VXLAN(vni=101, gpid=441, flags=0x88) /
2924                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
2925                  IPv6(src=l['ip6'], dst=ep.ip6) /
2926                  UDP(sport=1234, dport=1234) /
2927                  Raw(b'\xa5' * 100))
2928
2929             rx = self.send_and_expect(self.pg2, [p], self.pg0)
2930
2931             # the new TEP
2932             tep1_sw_if_index = find_vxlan_gbp_tunnel(
2933                 self,
2934                 self.pg2.local_ip4,
2935                 self.pg2.remote_hosts[1].ip4,
2936                 vx_tun_l3.vni)
2937             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
2938
2939             self.logger.info(self.vapi.cli("show gbp bridge"))
2940             self.logger.info(self.vapi.cli("show vxlan-gbp tunnel"))
2941             self.logger.info(self.vapi.cli("show gbp vxlan"))
2942             self.logger.info(self.vapi.cli("show int addr"))
2943
2944             # endpoint learnt via the TEP
2945             self.assertTrue(find_gbp_endpoint(self, ip=l['ip6']))
2946
2947         self.logger.info(self.vapi.cli("show gbp endpoint"))
2948         self.logger.info(self.vapi.cli("show ip fib index 1 %s" % l['ip']))
2949
2950         #
2951         # Static EP replies to learnt
2952         #
2953         for l in learnt:
2954             p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2955                  IPv6(dst=l['ip6'], src=ep.ip6) /
2956                  UDP(sport=1234, dport=1234) /
2957                  Raw(b'\xa5' * 100))
2958
2959             rxs = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg2)
2960
2961             for rx in rxs:
2962                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2963                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
2964                 self.assertEqual(rx[UDP].dport, 48879)
2965                 # the UDP source port is a random value for hashing
2966                 self.assertEqual(rx[VXLAN].gpid, 441)
2967                 self.assertEqual(rx[VXLAN].vni, 101)
2968                 self.assertTrue(rx[VXLAN].flags.G)
2969                 self.assertTrue(rx[VXLAN].flags.Instance)
2970                 self.assertTrue(rx[VXLAN].gpflags.A)
2971                 self.assertFalse(rx[VXLAN].gpflags.D)
2972
2973                 inner = rx[VXLAN].payload
2974
2975                 self.assertEqual(inner[Ether].src, routed_src_mac)
2976                 self.assertEqual(inner[Ether].dst, routed_dst_mac)
2977                 self.assertEqual(inner[IPv6].src, ep.ip6)
2978                 self.assertEqual(inner[IPv6].dst, l['ip6'])
2979
2980         self.logger.info(self.vapi.cli("sh gbp endpoint"))
2981         for l in learnt:
2982             self.wait_for_ep_timeout(ip=l['ip'])
2983
2984         #
2985         # Static sends to unknown EP with no route
2986         #
2987         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2988              IP(dst="10.0.0.99", src=ep.ip4) /
2989              UDP(sport=1234, dport=1234) /
2990              Raw(b'\xa5' * 100))
2991
2992         self.send_and_assert_no_replies(self.pg0, [p])
2993
2994         #
2995         # Add a route to static EP's v4 and v6 subnet
2996         #
2997         se_10_24 = VppGbpSubnet(
2998             self, rd1, "10.0.0.0", 24,
2999             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_TRANSPORT)
3000         se_10_24.add_vpp_config()
3001
3002         #
3003         # static pings router
3004         #
3005         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
3006              IP(dst=epg_220.bvi_ip4, src=ep.ip4) /
3007              UDP(sport=1234, dport=1234) /
3008              Raw(b'\xa5' * 100))
3009
3010         self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg0)
3011
3012         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
3013              IPv6(dst=epg_220.bvi_ip6, src=ep.ip6) /
3014              UDP(sport=1234, dport=1234) /
3015              Raw(b'\xa5' * 100))
3016
3017         self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg0)
3018
3019         #
3020         # packets to address in the subnet are sent on the uu-fwd
3021         #
3022         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
3023              IP(dst="10.0.0.99", src=ep.ip4) /
3024              UDP(sport=1234, dport=1234) /
3025              Raw(b'\xa5' * 100))
3026
3027         rxs = self.send_and_expect(self.pg0, [p], self.pg4)
3028         for rx in rxs:
3029             self.assertEqual(rx[IP].src, self.pg4.local_ip4)
3030             self.assertEqual(rx[IP].dst, self.pg4.remote_ip4)
3031             self.assertEqual(rx[UDP].dport, 48879)
3032             # the UDP source port is a random value for hashing
3033             self.assertEqual(rx[VXLAN].gpid, 441)
3034             self.assertEqual(rx[VXLAN].vni, 114)
3035             self.assertTrue(rx[VXLAN].flags.G)
3036             self.assertTrue(rx[VXLAN].flags.Instance)
3037             # policy is not applied to packets sent to the uu-fwd interfaces
3038             self.assertFalse(rx[VXLAN].gpflags.A)
3039             self.assertFalse(rx[VXLAN].gpflags.D)
3040
3041         #
3042         # learn some remote IPv4 EPs
3043         #
3044         for ii, l in enumerate(learnt):
3045             # a packet with an sclass from a known EPG
3046             # arriving on an unknown TEP
3047             p = (Ether(src=self.pg2.remote_mac,
3048                        dst=self.pg2.local_mac) /
3049                  IP(src=self.pg2.remote_hosts[2].ip4,
3050                     dst=self.pg2.local_ip4) /
3051                  UDP(sport=1234, dport=48879) /
3052                  VXLAN(vni=101, gpid=441, flags=0x88) /
3053                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
3054                  IP(src=l['ip'], dst=ep.ip4) /
3055                  UDP(sport=1234, dport=1234) /
3056                  Raw(b'\xa5' * 100))
3057
3058             rx = self.send_and_expect(self.pg2, [p], self.pg0)
3059
3060             # the new TEP
3061             tep1_sw_if_index = find_vxlan_gbp_tunnel(
3062                 self,
3063                 self.pg2.local_ip4,
3064                 self.pg2.remote_hosts[2].ip4,
3065                 vx_tun_l3.vni)
3066             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
3067
3068             # endpoint learnt via the parent GBP-vxlan interface
3069             self.assertTrue(find_gbp_endpoint(self,
3070                                               vx_tun_l3._sw_if_index,
3071                                               ip=l['ip']))
3072
3073         #
3074         # Add a remote endpoint from the API
3075         #
3076         rep_88 = VppGbpEndpoint(self, vx_tun_l3,
3077                                 epg_220, None,
3078                                 "10.0.0.88", "11.0.0.88",
3079                                 "2001:10::88", "3001::88",
3080                                 ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
3081                                 self.pg2.local_ip4,
3082                                 self.pg2.remote_hosts[2].ip4,
3083                                 mac=None)
3084         rep_88.add_vpp_config()
3085
3086         #
3087         # Add a remote endpoint from the API that matches an existing one
3088         # this is a lower priority, hence the packet is sent to the DP leanrt
3089         # TEP
3090         #
3091         rep_2 = VppGbpEndpoint(self, vx_tun_l3,
3092                                epg_220, None,
3093                                learnt[0]['ip'], "11.0.0.101",
3094                                learnt[0]['ip6'], "3001::101",
3095                                ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
3096                                self.pg2.local_ip4,
3097                                self.pg2.remote_hosts[1].ip4,
3098                                mac=None)
3099         rep_2.add_vpp_config()
3100
3101         #
3102         # Add a route to the learned EP's v4 subnet
3103         #  packets should be send on the v4/v6 uu=fwd interface resp.
3104         #
3105         se_10_1_24 = VppGbpSubnet(
3106             self, rd1, "10.0.1.0", 24,
3107             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_TRANSPORT)
3108         se_10_1_24.add_vpp_config()
3109
3110         self.logger.info(self.vapi.cli("show gbp endpoint"))
3111
3112         ips = ["10.0.0.88", learnt[0]['ip']]
3113         for ip in ips:
3114             p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
3115                  IP(dst=ip, src=ep.ip4) /
3116                  UDP(sport=1234, dport=1234) /
3117                  Raw(b'\xa5' * 100))
3118
3119             rxs = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg2)
3120
3121             for rx in rxs:
3122                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
3123                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[2].ip4)
3124                 self.assertEqual(rx[UDP].dport, 48879)
3125                 # the UDP source port is a random value for hashing
3126                 self.assertEqual(rx[VXLAN].gpid, 441)
3127                 self.assertEqual(rx[VXLAN].vni, 101)
3128                 self.assertTrue(rx[VXLAN].flags.G)
3129                 self.assertTrue(rx[VXLAN].flags.Instance)
3130                 self.assertTrue(rx[VXLAN].gpflags.A)
3131                 self.assertFalse(rx[VXLAN].gpflags.D)
3132
3133                 inner = rx[VXLAN].payload
3134
3135                 self.assertEqual(inner[Ether].src, routed_src_mac)
3136                 self.assertEqual(inner[Ether].dst, routed_dst_mac)
3137                 self.assertEqual(inner[IP].src, ep.ip4)
3138                 self.assertEqual(inner[IP].dst, ip)
3139
3140         #
3141         # remove the API remote EPs, only API sourced is gone, the DP
3142         # learnt one remains
3143         #
3144         rep_88.remove_vpp_config()
3145         rep_2.remove_vpp_config()
3146
3147         self.assertTrue(find_gbp_endpoint(self, ip=rep_2.ip4))
3148
3149         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
3150              IP(src=ep.ip4, dst=rep_2.ip4) /
3151              UDP(sport=1234, dport=1234) /
3152              Raw(b'\xa5' * 100))
3153         rxs = self.send_and_expect(self.pg0, [p], self.pg2)
3154
3155         self.assertFalse(find_gbp_endpoint(self, ip=rep_88.ip4))
3156
3157         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
3158              IP(src=ep.ip4, dst=rep_88.ip4) /
3159              UDP(sport=1234, dport=1234) /
3160              Raw(b'\xa5' * 100))
3161         rxs = self.send_and_expect(self.pg0, [p], self.pg4)
3162
3163         #
3164         # to appease the testcase we cannot have the registered EP still
3165         # present (because it's DP learnt) when the TC ends so wait until
3166         # it is removed
3167         #
3168         self.wait_for_ep_timeout(ip=rep_88.ip4)
3169         self.wait_for_ep_timeout(ip=rep_2.ip4)
3170
3171         #
3172         # Same as above, learn a remote EP via CP and DP
3173         # this time remove the DP one first. expect the CP data to remain
3174         #
3175         rep_3 = VppGbpEndpoint(self, vx_tun_l3,
3176                                epg_220, None,
3177                                "10.0.1.4", "11.0.0.103",
3178                                "2001::10:3", "3001::103",
3179                                ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
3180                                self.pg2.local_ip4,
3181                                self.pg2.remote_hosts[1].ip4,
3182                                mac=None)
3183         rep_3.add_vpp_config()
3184
3185         p = (Ether(src=self.pg2.remote_mac,
3186                    dst=self.pg2.local_mac) /
3187              IP(src=self.pg2.remote_hosts[2].ip4,
3188                 dst=self.pg2.local_ip4) /
3189              UDP(sport=1234, dport=48879) /
3190              VXLAN(vni=101, gpid=441, flags=0x88) /
3191              Ether(src=l['mac'], dst="00:00:00:11:11:11") /
3192              IP(src="10.0.1.4", dst=ep.ip4) /
3193              UDP(sport=1234, dport=1234) /
3194              Raw(b'\xa5' * 100))
3195         rxs = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
3196
3197         self.assertTrue(find_gbp_endpoint(self,
3198                                           vx_tun_l3._sw_if_index,
3199                                           ip=rep_3.ip4,
3200                                           tep=[self.pg2.local_ip4,
3201                                                self.pg2.remote_hosts[2].ip4]))
3202
3203         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
3204              IP(dst="10.0.1.4", src=ep.ip4) /
3205              UDP(sport=1234, dport=1234) /
3206              Raw(b'\xa5' * 100))
3207         rxs = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg2)
3208
3209         # host 2 is the DP learned TEP
3210         for rx in rxs:
3211             self.assertEqual(rx[IP].src, self.pg2.local_ip4)
3212             self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[2].ip4)
3213
3214         self.wait_for_ep_timeout(ip=rep_3.ip4,
3215                                  tep=[self.pg2.local_ip4,
3216                                       self.pg2.remote_hosts[2].ip4])
3217
3218         rxs = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg2)
3219
3220         # host 1 is the CP learned TEP
3221         for rx in rxs:
3222             self.assertEqual(rx[IP].src, self.pg2.local_ip4)
3223             self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
3224
3225         #
3226         # shutdown with learnt endpoint present
3227         #
3228         p = (Ether(src=self.pg2.remote_mac,
3229                    dst=self.pg2.local_mac) /
3230              IP(src=self.pg2.remote_hosts[1].ip4,
3231                 dst=self.pg2.local_ip4) /
3232              UDP(sport=1234, dport=48879) /
3233              VXLAN(vni=101, gpid=441, flags=0x88) /
3234              Ether(src=l['mac'], dst="00:00:00:11:11:11") /
3235              IP(src=learnt[1]['ip'], dst=ep.ip4) /
3236              UDP(sport=1234, dport=1234) /
3237              Raw(b'\xa5' * 100))
3238
3239         rx = self.send_and_expect(self.pg2, [p], self.pg0)
3240
3241         # endpoint learnt via the parent GBP-vxlan interface
3242         self.assertTrue(find_gbp_endpoint(self,
3243                                           vx_tun_l3._sw_if_index,
3244                                           ip=l['ip']))
3245
3246         #
3247         # TODO
3248         # remote endpoint becomes local
3249         #
3250         self.pg2.unconfig_ip4()
3251         self.pg3.unconfig_ip4()
3252         self.pg4.unconfig_ip4()
3253
3254     def test_gbp_redirect(self):
3255         """ GBP Endpoint Redirect """
3256
3257         self.vapi.cli("set logging class gbp level debug")
3258
3259         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
3260         routed_dst_mac = "00:0c:0c:0c:0c:0c"
3261         routed_src_mac = "00:22:bd:f8:19:ff"
3262
3263         learnt = [{'mac': '00:00:11:11:11:02',
3264                    'ip': '10.0.1.2',
3265                    'ip6': '2001:10::2'},
3266                   {'mac': '00:00:11:11:11:03',
3267                    'ip': '10.0.1.3',
3268                    'ip6': '2001:10::3'}]
3269
3270         #
3271         # IP tables
3272         #
3273         t4 = VppIpTable(self, 1)
3274         t4.add_vpp_config()
3275         t6 = VppIpTable(self, 1, True)
3276         t6.add_vpp_config()
3277
3278         rd1 = VppGbpRouteDomain(self, 2, 402, t4, t6)
3279         rd1.add_vpp_config()
3280
3281         self.loop0.set_mac(self.router_mac)
3282
3283         #
3284         # Bind the BVI to the RD
3285         #
3286         b_ip4 = VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
3287         b_ip6 = VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
3288
3289         #
3290         # Pg7 hosts a BD's UU-fwd
3291         #
3292         self.pg7.config_ip4()
3293         self.pg7.resolve_arp()
3294
3295         #
3296         # a GBP bridge domains for the EPs
3297         #
3298         bd1 = VppBridgeDomain(self, 1)
3299         bd1.add_vpp_config()
3300         gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0)
3301         gbd1.add_vpp_config()
3302
3303         bd2 = VppBridgeDomain(self, 2)
3304         bd2.add_vpp_config()
3305         gbd2 = VppGbpBridgeDomain(self, bd2, rd1, self.loop1)
3306         gbd2.add_vpp_config()
3307
3308         # ... and has a /32 and /128 applied
3309         ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi,
3310                                          "10.0.0.128", 32,
3311                                          bind=b_ip4).add_vpp_config()
3312         ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi,
3313                                          "2001:10::128", 128,
3314                                          bind=b_ip6).add_vpp_config()
3315         ip4_addr = VppIpInterfaceAddress(self, gbd2.bvi,
3316                                          "10.0.1.128", 32).add_vpp_config()
3317         ip6_addr = VppIpInterfaceAddress(self, gbd2.bvi,
3318                                          "2001:11::128", 128).add_vpp_config()
3319
3320         #
3321         # The Endpoint-groups in which we are learning endpoints
3322         #
3323         epg_220 = VppGbpEndpointGroup(self, 220, 440, rd1, gbd1,
3324                                       None, gbd1.bvi,
3325                                       "10.0.0.128",
3326                                       "2001:10::128",
3327                                       VppGbpEndpointRetention(60))
3328         epg_220.add_vpp_config()
3329         epg_221 = VppGbpEndpointGroup(self, 221, 441, rd1, gbd2,
3330                                       None, gbd2.bvi,
3331                                       "10.0.1.128",
3332                                       "2001:11::128",
3333                                       VppGbpEndpointRetention(60))
3334         epg_221.add_vpp_config()
3335         epg_222 = VppGbpEndpointGroup(self, 222, 442, rd1, gbd1,
3336                                       None, gbd1.bvi,
3337                                       "10.0.2.128",
3338                                       "2001:12::128",
3339                                       VppGbpEndpointRetention(60))
3340         epg_222.add_vpp_config()
3341
3342         #
3343         # a GBP bridge domains for the SEPs
3344         #
3345         bd_uu1 = VppVxlanGbpTunnel(self, self.pg7.local_ip4,
3346                                    self.pg7.remote_ip4, 116)
3347         bd_uu1.add_vpp_config()
3348         bd_uu2 = VppVxlanGbpTunnel(self, self.pg7.local_ip4,
3349                                    self.pg7.remote_ip4, 117)
3350         bd_uu2.add_vpp_config()
3351
3352         bd3 = VppBridgeDomain(self, 3)
3353         bd3.add_vpp_config()
3354         gbd3 = VppGbpBridgeDomain(self, bd3, rd1, self.loop2,
3355                                   bd_uu1, learn=False)
3356         gbd3.add_vpp_config()
3357         bd4 = VppBridgeDomain(self, 4)
3358         bd4.add_vpp_config()
3359         gbd4 = VppGbpBridgeDomain(self, bd4, rd1, self.loop3,
3360                                   bd_uu2, learn=False)
3361         gbd4.add_vpp_config()
3362
3363         #
3364         # EPGs in which the service endpoints exist
3365         #
3366         epg_320 = VppGbpEndpointGroup(self, 320, 550, rd1, gbd3,
3367                                       None, gbd1.bvi,
3368                                       "12.0.0.128",
3369                                       "4001:10::128",
3370                                       VppGbpEndpointRetention(60))
3371         epg_320.add_vpp_config()
3372         epg_321 = VppGbpEndpointGroup(self, 321, 551, rd1, gbd4,
3373                                       None, gbd2.bvi,
3374                                       "12.0.1.128",
3375                                       "4001:11::128",
3376                                       VppGbpEndpointRetention(60))
3377         epg_321.add_vpp_config()
3378
3379         #
3380         # three local endpoints
3381         #
3382         ep1 = VppGbpEndpoint(self, self.pg0,
3383                              epg_220, None,
3384                              "10.0.0.1", "11.0.0.1",
3385                              "2001:10::1", "3001:10::1")
3386         ep1.add_vpp_config()
3387         ep2 = VppGbpEndpoint(self, self.pg1,
3388                              epg_221, None,
3389                              "10.0.1.1", "11.0.1.1",
3390                              "2001:11::1", "3001:11::1")
3391         ep2.add_vpp_config()
3392         ep3 = VppGbpEndpoint(self, self.pg2,
3393                              epg_222, None,
3394                              "10.0.2.2", "11.0.2.2",
3395                              "2001:12::1", "3001:12::1")
3396         ep3.add_vpp_config()
3397
3398         #
3399         # service endpoints
3400         #
3401         sep1 = VppGbpEndpoint(self, self.pg3,
3402                               epg_320, None,
3403                               "12.0.0.1", "13.0.0.1",
3404                               "4001:10::1", "5001:10::1")
3405         sep1.add_vpp_config()
3406         sep2 = VppGbpEndpoint(self, self.pg4,
3407                               epg_320, None,
3408                               "12.0.0.2", "13.0.0.2",
3409                               "4001:10::2", "5001:10::2")
3410         sep2.add_vpp_config()
3411         sep3 = VppGbpEndpoint(self, self.pg5,
3412                               epg_321, None,
3413                               "12.0.1.1", "13.0.1.1",
3414                               "4001:11::1", "5001:11::1")
3415         sep3.add_vpp_config()
3416         # this EP is not installed immediately
3417         sep4 = VppGbpEndpoint(self, self.pg6,
3418                               epg_321, None,
3419                               "12.0.1.2", "13.0.1.2",
3420                               "4001:11::2", "5001:11::2")
3421
3422         #
3423         # an L2 switch packet between local EPs in different EPGs
3424         #  different dest ports on each so the are LB hashed differently
3425         #
3426         p4 = [(Ether(src=ep1.mac, dst=ep3.mac) /
3427                IP(src=ep1.ip4, dst=ep3.ip4) /
3428                UDP(sport=1234, dport=1234) /
3429                Raw(b'\xa5' * 100)),
3430               (Ether(src=ep3.mac, dst=ep1.mac) /
3431                IP(src=ep3.ip4, dst=ep1.ip4) /
3432                UDP(sport=1234, dport=1234) /
3433                Raw(b'\xa5' * 100))]
3434         p6 = [(Ether(src=ep1.mac, dst=ep3.mac) /
3435                IPv6(src=ep1.ip6, dst=ep3.ip6) /
3436                UDP(sport=1234, dport=1234) /
3437                Raw(b'\xa5' * 100)),
3438               (Ether(src=ep3.mac, dst=ep1.mac) /
3439                IPv6(src=ep3.ip6, dst=ep1.ip6) /
3440                UDP(sport=1234, dport=1230) /
3441                Raw(b'\xa5' * 100))]
3442
3443         # should be dropped since no contract yet
3444         self.send_and_assert_no_replies(self.pg0, [p4[0]])
3445         self.send_and_assert_no_replies(self.pg0, [p6[0]])
3446
3447         #
3448         # Add a contract with a rule to load-balance redirect via SEP1 and SEP2
3449         # one of the next-hops is via an EP that is not known
3450         #
3451         rule4 = AclRule(is_permit=1, proto=17)
3452         rule6 = AclRule(src_prefix=IPv6Network((0, 0)),
3453                         dst_prefix=IPv6Network((0, 0)), is_permit=1, proto=17)
3454         acl = VppAcl(self, rules=[rule4, rule6])
3455         acl.add_vpp_config()
3456
3457         #
3458         # test the src-ip hash mode
3459         #
3460         c1 = VppGbpContract(
3461             self, 402, epg_220.sclass, epg_222.sclass, acl.acl_index,
3462             [VppGbpContractRule(
3463                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3464                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3465                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3466                                        sep1.ip4, sep1.epg.rd),
3467                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3468                                        sep2.ip4, sep2.epg.rd)]),
3469                 VppGbpContractRule(
3470                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3471                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3472                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3473                                            sep3.ip6, sep3.epg.rd),
3474                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3475                                            sep4.ip6, sep4.epg.rd)])],
3476             [ETH_P_IP, ETH_P_IPV6])
3477         c1.add_vpp_config()
3478
3479         c2 = VppGbpContract(
3480             self, 402, epg_222.sclass, epg_220.sclass, acl.acl_index,
3481             [VppGbpContractRule(
3482                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3483                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3484                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3485                                        sep1.ip4, sep1.epg.rd),
3486                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3487                                        sep2.ip4, sep2.epg.rd)]),
3488                 VppGbpContractRule(
3489                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3490                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3491                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3492                                            sep3.ip6, sep3.epg.rd),
3493                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3494                                            sep4.ip6, sep4.epg.rd)])],
3495             [ETH_P_IP, ETH_P_IPV6])
3496         c2.add_vpp_config()
3497
3498         #
3499         # send again with the contract preset, now packets arrive
3500         # at SEP1 or SEP2 depending on the hashing
3501         #
3502         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
3503
3504         for rx in rxs:
3505             self.assertEqual(rx[Ether].src, routed_src_mac)
3506             self.assertEqual(rx[Ether].dst, sep1.mac)
3507             self.assertEqual(rx[IP].src, ep1.ip4)
3508             self.assertEqual(rx[IP].dst, ep3.ip4)
3509
3510         rxs = self.send_and_expect(self.pg2, p4[1] * 17, sep2.itf)
3511
3512         for rx in rxs:
3513             self.assertEqual(rx[Ether].src, routed_src_mac)
3514             self.assertEqual(rx[Ether].dst, sep2.mac)
3515             self.assertEqual(rx[IP].src, ep3.ip4)
3516             self.assertEqual(rx[IP].dst, ep1.ip4)
3517
3518         rxs = self.send_and_expect(self.pg0, p6[0] * 17, self.pg7)
3519
3520         for rx in rxs:
3521             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
3522             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
3523             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
3524             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
3525             self.assertEqual(rx[VXLAN].vni, 117)
3526             self.assertTrue(rx[VXLAN].flags.G)
3527             self.assertTrue(rx[VXLAN].flags.Instance)
3528             # redirect policy has been applied
3529             self.assertTrue(rx[VXLAN].gpflags.A)
3530             self.assertFalse(rx[VXLAN].gpflags.D)
3531
3532             inner = rx[VXLAN].payload
3533
3534             self.assertEqual(inner[Ether].src, routed_src_mac)
3535             self.assertEqual(inner[Ether].dst, sep4.mac)
3536             self.assertEqual(inner[IPv6].src, ep1.ip6)
3537             self.assertEqual(inner[IPv6].dst, ep3.ip6)
3538
3539         rxs = self.send_and_expect(self.pg2, p6[1] * 17, sep3.itf)
3540
3541         for rx in rxs:
3542             self.assertEqual(rx[Ether].src, routed_src_mac)
3543             self.assertEqual(rx[Ether].dst, sep3.mac)
3544             self.assertEqual(rx[IPv6].src, ep3.ip6)
3545             self.assertEqual(rx[IPv6].dst, ep1.ip6)
3546
3547         #
3548         # programme the unknown EP
3549         #
3550         sep4.add_vpp_config()
3551
3552         rxs = self.send_and_expect(self.pg0, p6[0] * 17, sep4.itf)
3553
3554         for rx in rxs:
3555             self.assertEqual(rx[Ether].src, routed_src_mac)
3556             self.assertEqual(rx[Ether].dst, sep4.mac)
3557             self.assertEqual(rx[IPv6].src, ep1.ip6)
3558             self.assertEqual(rx[IPv6].dst, ep3.ip6)
3559
3560         #
3561         # and revert back to unprogrammed
3562         #
3563         sep4.remove_vpp_config()
3564
3565         rxs = self.send_and_expect(self.pg0, p6[0] * 17, self.pg7)
3566
3567         for rx in rxs:
3568             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
3569             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
3570             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
3571             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
3572             self.assertEqual(rx[VXLAN].vni, 117)
3573             self.assertTrue(rx[VXLAN].flags.G)
3574             self.assertTrue(rx[VXLAN].flags.Instance)
3575             # redirect policy has been applied
3576             self.assertTrue(rx[VXLAN].gpflags.A)
3577             self.assertFalse(rx[VXLAN].gpflags.D)
3578
3579             inner = rx[VXLAN].payload
3580
3581             self.assertEqual(inner[Ether].src, routed_src_mac)
3582             self.assertEqual(inner[Ether].dst, sep4.mac)
3583             self.assertEqual(inner[IPv6].src, ep1.ip6)
3584             self.assertEqual(inner[IPv6].dst, ep3.ip6)
3585
3586         c1.remove_vpp_config()
3587         c2.remove_vpp_config()
3588
3589         #
3590         # test the symmetric hash mode
3591         #
3592         c1 = VppGbpContract(
3593             self, 402, epg_220.sclass, epg_222.sclass, acl.acl_index,
3594             [VppGbpContractRule(
3595                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3596                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3597                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3598                                        sep1.ip4, sep1.epg.rd),
3599                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3600                                        sep2.ip4, sep2.epg.rd)]),
3601                 VppGbpContractRule(
3602                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3603                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3604                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3605                                            sep3.ip6, sep3.epg.rd),
3606                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3607                                            sep4.ip6, sep4.epg.rd)])],
3608             [ETH_P_IP, ETH_P_IPV6])
3609         c1.add_vpp_config()
3610
3611         c2 = VppGbpContract(
3612             self, 402, epg_222.sclass, epg_220.sclass, acl.acl_index,
3613             [VppGbpContractRule(
3614                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3615                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3616                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3617                                        sep1.ip4, sep1.epg.rd),
3618                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3619                                        sep2.ip4, sep2.epg.rd)]),
3620                 VppGbpContractRule(
3621                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3622                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3623                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3624                                            sep3.ip6, sep3.epg.rd),
3625                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3626                                            sep4.ip6, sep4.epg.rd)])],
3627             [ETH_P_IP, ETH_P_IPV6])
3628         c2.add_vpp_config()
3629
3630         #
3631         # send again with the contract preset, now packets arrive
3632         # at SEP1 for both directions
3633         #
3634         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
3635
3636         for rx in rxs:
3637             self.assertEqual(rx[Ether].src, routed_src_mac)
3638             self.assertEqual(rx[Ether].dst, sep1.mac)
3639             self.assertEqual(rx[IP].src, ep1.ip4)
3640             self.assertEqual(rx[IP].dst, ep3.ip4)
3641
3642         rxs = self.send_and_expect(self.pg2, p4[1] * 17, sep1.itf)
3643
3644         for rx in rxs:
3645             self.assertEqual(rx[Ether].src, routed_src_mac)
3646             self.assertEqual(rx[Ether].dst, sep1.mac)
3647             self.assertEqual(rx[IP].src, ep3.ip4)
3648             self.assertEqual(rx[IP].dst, ep1.ip4)
3649
3650         #
3651         # programme the unknown EP for the L3 tests
3652         #
3653         sep4.add_vpp_config()
3654
3655         #
3656         # an L3 switch packet between local EPs in different EPGs
3657         #  different dest ports on each so the are LB hashed differently
3658         #
3659         p4 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) /
3660                IP(src=ep1.ip4, dst=ep2.ip4) /
3661                UDP(sport=1234, dport=1234) /
3662                Raw(b'\xa5' * 100)),
3663               (Ether(src=ep2.mac, dst=str(self.router_mac)) /
3664                IP(src=ep2.ip4, dst=ep1.ip4) /
3665                UDP(sport=1234, dport=1234) /
3666                Raw(b'\xa5' * 100))]
3667         p6 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) /
3668                IPv6(src=ep1.ip6, dst=ep2.ip6) /
3669                UDP(sport=1234, dport=1234) /
3670                Raw(b'\xa5' * 100)),
3671               (Ether(src=ep2.mac, dst=str(self.router_mac)) /
3672                IPv6(src=ep2.ip6, dst=ep1.ip6) /
3673                UDP(sport=1234, dport=1234) /
3674                Raw(b'\xa5' * 100))]
3675
3676         c3 = VppGbpContract(
3677             self, 402, epg_220.sclass, epg_221.sclass, acl.acl_index,
3678             [VppGbpContractRule(
3679                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3680                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3681                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3682                                        sep1.ip4, sep1.epg.rd),
3683                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3684                                        sep2.ip4, sep2.epg.rd)]),
3685                 VppGbpContractRule(
3686                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3687                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3688                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3689                                            sep3.ip6, sep3.epg.rd),
3690                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3691                                            sep4.ip6, sep4.epg.rd)])],
3692             [ETH_P_IP, ETH_P_IPV6])
3693         c3.add_vpp_config()
3694
3695         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
3696
3697         for rx in rxs:
3698             self.assertEqual(rx[Ether].src, routed_src_mac)
3699             self.assertEqual(rx[Ether].dst, sep1.mac)
3700             self.assertEqual(rx[IP].src, ep1.ip4)
3701             self.assertEqual(rx[IP].dst, ep2.ip4)
3702
3703         #
3704         # learn a remote EP in EPG 221
3705         #   packets coming from unknown remote EPs will be leant & redirected
3706         #
3707         vx_tun_l3 = VppGbpVxlanTunnel(
3708             self, 444, rd1.rd_id,
3709             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3,
3710             self.pg2.local_ip4)
3711         vx_tun_l3.add_vpp_config()
3712
3713         c4 = VppGbpContract(
3714             self, 402, epg_221.sclass, epg_220.sclass, acl.acl_index,
3715             [VppGbpContractRule(
3716                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3717                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3718                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3719                                        sep1.ip4, sep1.epg.rd),
3720                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3721                                        sep2.ip4, sep2.epg.rd)]),
3722                 VppGbpContractRule(
3723                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3724                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3725                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3726                                            sep3.ip6, sep3.epg.rd),
3727                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3728                                            sep4.ip6, sep4.epg.rd)])],
3729             [ETH_P_IP, ETH_P_IPV6])
3730         c4.add_vpp_config()
3731
3732         p = (Ether(src=self.pg7.remote_mac,
3733                    dst=self.pg7.local_mac) /
3734              IP(src=self.pg7.remote_ip4,
3735                 dst=self.pg7.local_ip4) /
3736              UDP(sport=1234, dport=48879) /
3737              VXLAN(vni=444, gpid=441, flags=0x88) /
3738              Ether(src="00:22:22:22:22:33", dst=str(self.router_mac)) /
3739              IP(src="10.0.0.88", dst=ep1.ip4) /
3740              UDP(sport=1234, dport=1234) /
3741              Raw(b'\xa5' * 100))
3742
3743         # unknown remote EP to local EP redirected
3744         rxs = self.send_and_expect(self.pg7, [p], sep1.itf)
3745
3746         for rx in rxs:
3747             self.assertEqual(rx[Ether].src, routed_src_mac)
3748             self.assertEqual(rx[Ether].dst, sep1.mac)
3749             self.assertEqual(rx[IP].src, "10.0.0.88")
3750             self.assertEqual(rx[IP].dst, ep1.ip4)
3751
3752         # endpoint learnt via the parent GBP-vxlan interface
3753         self.assertTrue(find_gbp_endpoint(self,
3754                                           vx_tun_l3._sw_if_index,
3755                                           ip="10.0.0.88"))
3756
3757         p = (Ether(src=self.pg7.remote_mac,
3758                    dst=self.pg7.local_mac) /
3759              IP(src=self.pg7.remote_ip4,
3760                 dst=self.pg7.local_ip4) /
3761              UDP(sport=1234, dport=48879) /
3762              VXLAN(vni=444, gpid=441, flags=0x88) /
3763              Ether(src="00:22:22:22:22:33", dst=str(self.router_mac)) /
3764              IPv6(src="2001:10::88", dst=ep1.ip6) /
3765              UDP(sport=1234, dport=1234) /
3766              Raw(b'\xa5' * 100))
3767
3768         # unknown remote EP to local EP redirected (ipv6)
3769         rxs = self.send_and_expect(self.pg7, [p], sep3.itf)
3770
3771         for rx in rxs:
3772             self.assertEqual(rx[Ether].src, routed_src_mac)
3773             self.assertEqual(rx[Ether].dst, sep3.mac)
3774             self.assertEqual(rx[IPv6].src, "2001:10::88")
3775             self.assertEqual(rx[IPv6].dst, ep1.ip6)
3776
3777         # endpoint learnt via the parent GBP-vxlan interface
3778         self.assertTrue(find_gbp_endpoint(self,
3779                                           vx_tun_l3._sw_if_index,
3780                                           ip="2001:10::88"))
3781
3782         #
3783         # L3 switch from local to remote EP
3784         #
3785         p4 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) /
3786                IP(src=ep1.ip4, dst="10.0.0.88") /
3787                UDP(sport=1234, dport=1234) /
3788                Raw(b'\xa5' * 100))]
3789         p6 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) /
3790                IPv6(src=ep1.ip6, dst="2001:10::88") /
3791                UDP(sport=1234, dport=1234) /
3792                Raw(b'\xa5' * 100))]
3793
3794         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
3795
3796         for rx in rxs:
3797             self.assertEqual(rx[Ether].src, routed_src_mac)
3798             self.assertEqual(rx[Ether].dst, sep1.mac)
3799             self.assertEqual(rx[IP].src, ep1.ip4)
3800             self.assertEqual(rx[IP].dst, "10.0.0.88")
3801
3802         rxs = self.send_and_expect(self.pg0, p6[0] * 17, sep4.itf)
3803
3804         for rx in rxs:
3805             self.assertEqual(rx[Ether].src, routed_src_mac)
3806             self.assertEqual(rx[Ether].dst, sep4.mac)
3807             self.assertEqual(rx[IPv6].src, ep1.ip6)
3808             self.assertEqual(rx[IPv6].dst, "2001:10::88")
3809
3810         #
3811         # test the dst-ip hash mode
3812         #
3813         c5 = VppGbpContract(
3814             self, 402, epg_220.sclass, epg_221.sclass, acl.acl_index,
3815             [VppGbpContractRule(
3816                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3817                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
3818                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3819                                        sep1.ip4, sep1.epg.rd),
3820                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3821                                        sep2.ip4, sep2.epg.rd)]),
3822                 VppGbpContractRule(
3823                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3824                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
3825                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3826                                            sep3.ip6, sep3.epg.rd),
3827                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3828                                            sep4.ip6, sep4.epg.rd)])],
3829             [ETH_P_IP, ETH_P_IPV6])
3830         c5.add_vpp_config()
3831
3832         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
3833
3834         for rx in rxs:
3835             self.assertEqual(rx[Ether].src, routed_src_mac)
3836             self.assertEqual(rx[Ether].dst, sep1.mac)
3837             self.assertEqual(rx[IP].src, ep1.ip4)
3838             self.assertEqual(rx[IP].dst, "10.0.0.88")
3839
3840         rxs = self.send_and_expect(self.pg0, p6[0] * 17, sep3.itf)
3841
3842         for rx in rxs:
3843             self.assertEqual(rx[Ether].src, routed_src_mac)
3844             self.assertEqual(rx[Ether].dst, sep3.mac)
3845             self.assertEqual(rx[IPv6].src, ep1.ip6)
3846             self.assertEqual(rx[IPv6].dst, "2001:10::88")
3847
3848         #
3849         # a programmed remote SEP in EPG 320
3850         #
3851
3852         # gbp vxlan tunnel for the remote SEP
3853         vx_tun_l3_sep = VppGbpVxlanTunnel(
3854             self, 555, rd1.rd_id,
3855             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3,
3856             self.pg2.local_ip4)
3857         vx_tun_l3_sep.add_vpp_config()
3858
3859         # remote SEP
3860         sep5 = VppGbpEndpoint(self, vx_tun_l3_sep,
3861                               epg_320, None,
3862                               "12.0.0.10", "13.0.0.10",
3863                               "4001:10::10", "5001:10::10",
3864                               ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
3865                               self.pg7.local_ip4,
3866                               self.pg7.remote_ip4,
3867                               mac=None)
3868         sep5.add_vpp_config()
3869
3870         #
3871         # local l3out redirect tests
3872         #
3873
3874         # add local l3out
3875         # the external bd
3876         self.loop4.set_mac(self.router_mac)
3877         b_lo4_ip4 = VppIpInterfaceBind(self, self.loop4, t4).add_vpp_config()
3878         b_lo4_ip6 = VppIpInterfaceBind(self, self.loop4, t6).add_vpp_config()
3879         ebd = VppBridgeDomain(self, 100)
3880         ebd.add_vpp_config()
3881         gebd = VppGbpBridgeDomain(self, ebd, rd1, self.loop4, None, None)
3882         gebd.add_vpp_config()
3883         # the external epg
3884         eepg = VppGbpEndpointGroup(self, 888, 765, rd1, gebd,
3885                                    None, gebd.bvi,
3886                                    "10.1.0.128",
3887                                    "2001:10:1::128",
3888                                    VppGbpEndpointRetention(60))
3889         eepg.add_vpp_config()
3890         # add subnets to BVI
3891         VppIpInterfaceAddress(
3892             self,
3893             gebd.bvi,
3894             "10.1.0.128",
3895             24, bind=b_lo4_ip4).add_vpp_config()
3896         VppIpInterfaceAddress(
3897             self,
3898             gebd.bvi,
3899             "2001:10:1::128",
3900             64, bind=b_lo4_ip6).add_vpp_config()
3901         # ... which are L3-out subnets
3902         VppGbpSubnet(self, rd1, "10.1.0.0", 24,
3903                      VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3904                      sclass=765).add_vpp_config()
3905         VppGbpSubnet(self, rd1, "2001:10:1::128", 64,
3906                      VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3907                      sclass=765).add_vpp_config()
3908         # external endpoints
3909         VppL2Vtr(self, self.vlan_100, L2_VTR_OP.L2_POP_1).add_vpp_config()
3910         eep1 = VppGbpEndpoint(self, self.vlan_100, eepg, None, "10.1.0.1",
3911                               "11.1.0.1", "2001:10:1::1", "3001:10:1::1",
3912                               ep_flags.GBP_API_ENDPOINT_FLAG_EXTERNAL)
3913         eep1.add_vpp_config()
3914         VppL2Vtr(self, self.vlan_101, L2_VTR_OP.L2_POP_1).add_vpp_config()
3915         eep2 = VppGbpEndpoint(self, self.vlan_101, eepg, None, "10.1.0.2",
3916                               "11.1.0.2", "2001:10:1::2", "3001:10:1::2",
3917                               ep_flags.GBP_API_ENDPOINT_FLAG_EXTERNAL)
3918         eep2.add_vpp_config()
3919
3920         # external subnets reachable though eep1 and eep2 respectively
3921         VppIpRoute(self, "10.220.0.0", 24,
3922                    [VppRoutePath(eep1.ip4, eep1.epg.bvi.sw_if_index)],
3923                    table_id=t4.table_id).add_vpp_config()
3924         VppGbpSubnet(self, rd1, "10.220.0.0", 24,
3925                      VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3926                      sclass=4220).add_vpp_config()
3927         VppIpRoute(self, "10:220::", 64,
3928                    [VppRoutePath(eep1.ip6, eep1.epg.bvi.sw_if_index)],
3929                    table_id=t6.table_id).add_vpp_config()
3930         VppGbpSubnet(self, rd1, "10:220::", 64,
3931                      VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3932                      sclass=4220).add_vpp_config()
3933         VppIpRoute(self, "10.221.0.0", 24,
3934                    [VppRoutePath(eep2.ip4, eep2.epg.bvi.sw_if_index)],
3935                    table_id=t4.table_id).add_vpp_config()
3936         VppGbpSubnet(self, rd1, "10.221.0.0", 24,
3937                      VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3938                      sclass=4221).add_vpp_config()
3939         VppIpRoute(self, "10:221::", 64,
3940                    [VppRoutePath(eep2.ip6, eep2.epg.bvi.sw_if_index)],
3941                    table_id=t6.table_id).add_vpp_config()
3942         VppGbpSubnet(self, rd1, "10:221::", 64,
3943                      VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3944                      sclass=4221).add_vpp_config()
3945
3946         #
3947         # l3out redirect to remote (known, then unknown) SEP
3948         #
3949
3950         # packets from 1 external subnet to the other
3951         p = [(Ether(src=eep1.mac, dst=self.router_mac) /
3952               Dot1Q(vlan=100) /
3953               IP(src="10.220.0.17", dst="10.221.0.65") /
3954               UDP(sport=1234, dport=1234) /
3955               Raw(b'\xa5' * 100)),
3956              (Ether(src=eep1.mac, dst=self.router_mac) /
3957               Dot1Q(vlan=100) /
3958               IPv6(src="10:220::17", dst="10:221::65") /
3959               UDP(sport=1234, dport=1234) /
3960               Raw(b'\xa5' * 100))]
3961
3962         # packets should be dropped in absence of contract
3963         self.send_and_assert_no_replies(self.pg0, p)
3964
3965         # contract redirecting to sep5
3966         VppGbpContract(
3967             self, 402, 4220, 4221, acl.acl_index,
3968             [VppGbpContractRule(
3969                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3970                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
3971                 [VppGbpContractNextHop(sep5.vmac, sep5.epg.bd,
3972                                        sep5.ip4, sep5.epg.rd)]),
3973                 VppGbpContractRule(
3974                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3975                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
3976                     [VppGbpContractNextHop(sep5.vmac, sep5.epg.bd,
3977                                            sep5.ip6, sep5.epg.rd)])],
3978             [ETH_P_IP, ETH_P_IPV6]).add_vpp_config()
3979
3980         rxs = self.send_and_expect(self.pg0, p, self.pg7)
3981
3982         for rx, tx in zip(rxs, p):
3983             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
3984             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
3985             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
3986             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
3987             # this should use the programmed remote leaf TEP
3988             self.assertEqual(rx[VXLAN].vni, 555)
3989             self.assertEqual(rx[VXLAN].gpid, 4220)
3990             self.assertTrue(rx[VXLAN].flags.G)
3991             self.assertTrue(rx[VXLAN].flags.Instance)
3992             # redirect policy has been applied
3993             self.assertTrue(rx[VXLAN].gpflags.A)
3994             self.assertTrue(rx[VXLAN].gpflags.D)
3995             rxip = rx[VXLAN][Ether].payload
3996             txip = tx[Dot1Q].payload
3997             self.assertEqual(rxip.src, txip.src)
3998             self.assertEqual(rxip.dst, txip.dst)
3999
4000         # remote SEP: it is now an unknown remote SEP and should go
4001         # to spine proxy
4002         sep5.remove_vpp_config()
4003
4004         rxs = self.send_and_expect(self.pg0, p, self.pg7)
4005
4006         for rx, tx in zip(rxs, p):
4007             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
4008             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
4009             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
4010             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
4011             # this should use the spine proxy TEP
4012             self.assertEqual(rx[VXLAN].vni, epg_320.bd.uu_fwd.vni)
4013             self.assertEqual(rx[VXLAN].gpid, 4220)
4014             self.assertTrue(rx[VXLAN].flags.G)
4015             self.assertTrue(rx[VXLAN].flags.Instance)
4016             # redirect policy has been applied
4017             self.assertTrue(rx[VXLAN].gpflags.A)
4018             self.assertTrue(rx[VXLAN].gpflags.D)
4019             rxip = rx[VXLAN][Ether].payload
4020             txip = tx[Dot1Q].payload
4021             self.assertEqual(rxip.src, txip.src)
4022             self.assertEqual(rxip.dst, txip.dst)
4023
4024         #
4025         # l3out redirect to local SEP
4026         #
4027
4028         # change the contract between l3out to redirect to local SEPs
4029         # instead of remote SEP
4030         VppGbpContract(
4031             self, 402, 4220, 4221, acl.acl_index,
4032             [VppGbpContractRule(
4033                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
4034                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
4035                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
4036                                        sep1.ip4, sep1.epg.rd)]),
4037                 VppGbpContractRule(
4038                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
4039                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
4040                     [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
4041                                            sep1.ip6, sep1.epg.rd)])],
4042             [ETH_P_IP, ETH_P_IPV6]).add_vpp_config()
4043
4044         rxs = self.send_and_expect(self.pg0, p, sep1.itf)
4045         for rx, tx in zip(rxs, p):
4046             self.assertEqual(rx[Ether].src, routed_src_mac)
4047             self.assertEqual(rx[Ether].dst, sep1.mac)
4048             rxip = rx[Ether].payload
4049             txip = tx[Ether].payload
4050             self.assertEqual(rxip.src, txip.src)
4051             self.assertEqual(rxip.dst, txip.dst)
4052
4053         #
4054         # redirect remote EP to remote (known then unknown) SEP
4055         #
4056
4057         # remote SEP known again
4058         sep5.add_vpp_config()
4059
4060         # contract to redirect to learnt SEP
4061         VppGbpContract(
4062             self, 402, epg_221.sclass, epg_222.sclass, acl.acl_index,
4063             [VppGbpContractRule(
4064                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
4065                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
4066                 [VppGbpContractNextHop(sep5.vmac, sep5.epg.bd,
4067                                        sep5.ip4, sep5.epg.rd)]),
4068                 VppGbpContractRule(
4069                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
4070                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
4071                     [VppGbpContractNextHop(sep5.vmac, sep5.epg.bd,
4072                                            sep5.ip6, sep5.epg.rd)])],
4073             [ETH_P_IP, ETH_P_IPV6]).add_vpp_config()
4074
4075         # packets from unknown EP 221 to known EP in EPG 222
4076         # should be redirected to known remote SEP
4077         base = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) /
4078                 IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) /
4079                 UDP(sport=1234, dport=48879) /
4080                 VXLAN(vni=444, gpid=441, flags=0x88) /
4081                 Ether(src="00:22:22:22:22:44", dst=str(self.router_mac)))
4082         p = [(base /
4083               IP(src="10.0.1.100", dst=ep3.ip4) /
4084               UDP(sport=1234, dport=1234) /
4085               Raw(b'\xa5' * 100)),
4086              (base /
4087               IPv6(src="2001:10::100", dst=ep3.ip6) /
4088               UDP(sport=1234, dport=1234) /
4089               Raw(b'\xa5' * 100))]
4090
4091         # unknown remote EP to local EP redirected to known remote SEP
4092         rxs = self.send_and_expect(self.pg7, p, self.pg7)
4093
4094         for rx, tx in zip(rxs, p):
4095             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
4096             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
4097             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
4098             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
4099             # this should use the programmed remote leaf TEP
4100             self.assertEqual(rx[VXLAN].vni, 555)
4101             self.assertEqual(rx[VXLAN].gpid, epg_221.sclass)
4102             self.assertTrue(rx[VXLAN].flags.G)
4103             self.assertTrue(rx[VXLAN].flags.Instance)
4104             # redirect policy has been applied
4105             self.assertTrue(rx[VXLAN].gpflags.A)
4106             self.assertFalse(rx[VXLAN].gpflags.D)
4107             rxip = rx[VXLAN][Ether].payload
4108             txip = tx[VXLAN][Ether].payload
4109             self.assertEqual(rxip.src, txip.src)
4110             self.assertEqual(rxip.dst, txip.dst)
4111
4112         # endpoint learnt via the parent GBP-vxlan interface
4113         self.assertTrue(find_gbp_endpoint(self,
4114                                           vx_tun_l3._sw_if_index,
4115                                           ip="10.0.1.100"))
4116         self.assertTrue(find_gbp_endpoint(self,
4117                                           vx_tun_l3._sw_if_index,
4118                                           ip="2001:10::100"))
4119
4120         # remote SEP: it is now an unknown remote SEP and should go
4121         # to spine proxy
4122         sep5.remove_vpp_config()
4123
4124         # remote EP (coming from spine proxy) to local EP redirected to
4125         # known remote SEP
4126         rxs = self.send_and_expect(self.pg7, p, self.pg7)
4127
4128         for rx, tx in zip(rxs, p):
4129             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
4130             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
4131             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
4132             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
4133             # this should use the spine proxy TEP
4134             self.assertEqual(rx[VXLAN].vni, epg_320.bd.uu_fwd.vni)
4135             self.assertEqual(rx[VXLAN].gpid, epg_221.sclass)
4136             self.assertTrue(rx[VXLAN].flags.G)
4137             self.assertTrue(rx[VXLAN].flags.Instance)
4138             # redirect policy has been applied
4139             self.assertTrue(rx[VXLAN].gpflags.A)
4140             self.assertFalse(rx[VXLAN].gpflags.D)
4141             rxip = rx[VXLAN][Ether].payload
4142             txip = tx[VXLAN][Ether].payload
4143             self.assertEqual(rxip.src, txip.src)
4144             self.assertEqual(rxip.dst, txip.dst)
4145
4146         #
4147         # cleanup
4148         #
4149         self.pg7.unconfig_ip4()
4150
4151     def test_gbp_redirect_extended(self):
4152         """ GBP Endpoint Redirect Extended """
4153
4154         self.vapi.cli("set logging class gbp level debug")
4155
4156         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
4157         routed_dst_mac = "00:0c:0c:0c:0c:0c"
4158         routed_src_mac = "00:22:bd:f8:19:ff"
4159
4160         learnt = [{'mac': '00:00:11:11:11:02',
4161                    'ip': '10.0.1.2',
4162                    'ip6': '2001:10::2'},
4163                   {'mac': '00:00:11:11:11:03',
4164                    'ip': '10.0.1.3',
4165                    'ip6': '2001:10::3'}]
4166
4167         #
4168         # IP tables
4169         #
4170         t4 = VppIpTable(self, 1)
4171         t4.add_vpp_config()
4172         t6 = VppIpTable(self, 1, True)
4173         t6.add_vpp_config()
4174
4175         # create IPv4 and IPv6 RD UU VxLAN-GBP TEP and bind them to the right
4176         # VRF
4177         rd_uu4 = VppVxlanGbpTunnel(
4178             self,
4179             self.pg7.local_ip4,
4180             self.pg7.remote_ip4,
4181             114,
4182             mode=(VppEnum.vl_api_vxlan_gbp_api_tunnel_mode_t.
4183                   VXLAN_GBP_API_TUNNEL_MODE_L3))
4184         rd_uu4.add_vpp_config()
4185         VppIpInterfaceBind(self, rd_uu4, t4).add_vpp_config()
4186
4187         rd_uu6 = VppVxlanGbpTunnel(
4188             self,
4189             self.pg7.local_ip4,
4190             self.pg7.remote_ip4,
4191             115,
4192             mode=(VppEnum.vl_api_vxlan_gbp_api_tunnel_mode_t.
4193                   VXLAN_GBP_API_TUNNEL_MODE_L3))
4194         rd_uu6.add_vpp_config()
4195         VppIpInterfaceBind(self, rd_uu6, t4).add_vpp_config()
4196
4197         rd1 = VppGbpRouteDomain(self, 2, 402, t4, t6, rd_uu4, rd_uu6)
4198         rd1.add_vpp_config()
4199
4200         self.loop0.set_mac(self.router_mac)
4201         self.loop1.set_mac(self.router_mac)
4202         self.loop2.set_mac(self.router_mac)
4203
4204         #
4205         # Bind the BVI to the RD
4206         #
4207         b_lo0_ip4 = VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
4208         b_lo0_ip6 = VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
4209         b_lo1_ip4 = VppIpInterfaceBind(self, self.loop1, t4).add_vpp_config()
4210         b_lo1_ip6 = VppIpInterfaceBind(self, self.loop1, t6).add_vpp_config()
4211         b_lo2_ip4 = VppIpInterfaceBind(self, self.loop2, t4).add_vpp_config()
4212         b_lo2_ip6 = VppIpInterfaceBind(self, self.loop2, t6).add_vpp_config()
4213
4214         #
4215         # Pg7 hosts a BD's UU-fwd
4216         #
4217         self.pg7.config_ip4()
4218         self.pg7.resolve_arp()
4219
4220         #
4221         # a GBP bridge domains for the EPs
4222         #
4223         bd1 = VppBridgeDomain(self, 1)
4224         bd1.add_vpp_config()
4225         gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0)
4226         gbd1.add_vpp_config()
4227
4228         bd2 = VppBridgeDomain(self, 2)
4229         bd2.add_vpp_config()
4230         gbd2 = VppGbpBridgeDomain(self, bd2, rd1, self.loop1)
4231         gbd2.add_vpp_config()
4232
4233         # ... and has a /32 and /128 applied
4234         ip4_addr1 = VppIpInterfaceAddress(self, gbd1.bvi,
4235                                           "10.0.0.128", 32,
4236                                           bind=b_lo0_ip4).add_vpp_config()
4237         ip6_addr1 = VppIpInterfaceAddress(self, gbd1.bvi,
4238                                           "2001:10::128", 128,
4239                                           bind=b_lo0_ip6).add_vpp_config()
4240         ip4_addr2 = VppIpInterfaceAddress(self, gbd2.bvi,
4241                                           "10.0.1.128", 32,
4242                                           bind=b_lo1_ip4).add_vpp_config()
4243         ip6_addr2 = VppIpInterfaceAddress(self, gbd2.bvi,
4244                                           "2001:11::128", 128,
4245                                           bind=b_lo1_ip6).add_vpp_config()
4246
4247         #
4248         # The Endpoint-groups
4249         #
4250         epg_220 = VppGbpEndpointGroup(self, 220, 440, rd1, gbd1,
4251                                       None, gbd1.bvi,
4252                                       "10.0.0.128",
4253                                       "2001:10::128",
4254                                       VppGbpEndpointRetention(60))
4255         epg_220.add_vpp_config()
4256         epg_221 = VppGbpEndpointGroup(self, 221, 441, rd1, gbd2,
4257                                       None, gbd2.bvi,
4258                                       "10.0.1.128",
4259                                       "2001:11::128",
4260                                       VppGbpEndpointRetention(60))
4261         epg_221.add_vpp_config()
4262
4263         #
4264         # a GBP bridge domains for the SEPs
4265         #
4266         bd_uu3 = VppVxlanGbpTunnel(self, self.pg7.local_ip4,
4267                                    self.pg7.remote_ip4, 116)
4268         bd_uu3.add_vpp_config()
4269
4270         bd3 = VppBridgeDomain(self, 3)
4271         bd3.add_vpp_config()
4272         gbd3 = VppGbpBridgeDomain(self, bd3, rd1, self.loop2,
4273                                   bd_uu3, learn=False)
4274         gbd3.add_vpp_config()
4275
4276         ip4_addr3 = VppIpInterfaceAddress(self, gbd3.bvi,
4277                                           "12.0.0.128", 32,
4278                                           bind=b_lo2_ip4).add_vpp_config()
4279         ip6_addr3 = VppIpInterfaceAddress(self, gbd3.bvi,
4280                                           "4001:10::128", 128,
4281                                           bind=b_lo2_ip6).add_vpp_config()
4282
4283         #
4284         # self.logger.info(self.vapi.cli("show gbp bridge"))
4285         # self.logger.info(self.vapi.cli("show vxlan-gbp tunnel"))
4286         # self.logger.info(self.vapi.cli("show gbp vxlan"))
4287         # self.logger.info(self.vapi.cli("show int addr"))
4288         #
4289
4290         #
4291         # EPGs in which the service endpoints exist
4292         #
4293         epg_320 = VppGbpEndpointGroup(self, 320, 550, rd1, gbd3,
4294                                       None, gbd3.bvi,
4295                                       "12.0.0.128",
4296                                       "4001:10::128",
4297                                       VppGbpEndpointRetention(60))
4298         epg_320.add_vpp_config()
4299
4300         #
4301         # endpoints
4302         #
4303         ep1 = VppGbpEndpoint(self, self.pg0,
4304                              epg_220, None,
4305                              "10.0.0.1", "11.0.0.1",
4306                              "2001:10::1", "3001:10::1")
4307         ep1.add_vpp_config()
4308         ep2 = VppGbpEndpoint(self, self.pg1,
4309                              epg_221, None,
4310                              "10.0.1.1", "11.0.1.1",
4311                              "2001:11::1", "3001:11::1")
4312         ep2.add_vpp_config()
4313
4314         #
4315         # service endpoints
4316         #
4317         sep1 = VppGbpEndpoint(self, self.pg3,
4318                               epg_320, None,
4319                               "12.0.0.1", "13.0.0.1",
4320                               "4001:10::1", "5001:10::1")
4321         sep2 = VppGbpEndpoint(self, self.pg4,
4322                               epg_320, None,
4323                               "12.0.0.2", "13.0.0.2",
4324                               "4001:10::2", "5001:10::2")
4325
4326         # sep1 and sep2 are not added to config yet
4327         # they are unknown for now
4328
4329         #
4330         # add routes to EPG subnets
4331         #
4332         VppGbpSubnet(self, rd1, "10.0.0.0", 24,
4333                      VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_TRANSPORT
4334                      ).add_vpp_config()
4335         VppGbpSubnet(self, rd1, "10.0.1.0", 24,
4336                      VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_TRANSPORT
4337                      ).add_vpp_config()
4338
4339         #
4340         # Local host to known local host in different BD
4341         # with SFC contract (source and destination are in
4342         # one node and service endpoint in another node)
4343         #
4344         p4 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) /
4345                IP(src=ep1.ip4, dst=ep2.ip4) /
4346                UDP(sport=1234, dport=1234) /
4347                Raw(b'\xa5' * 100)),
4348               (Ether(src=ep2.mac, dst=str(self.router_mac)) /
4349                IP(src=ep2.ip4, dst=ep1.ip4) /
4350                UDP(sport=1234, dport=1234) /
4351                Raw(b'\xa5' * 100))]
4352         p6 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) /
4353                IPv6(src=ep1.ip6, dst=ep2.ip6) /
4354                UDP(sport=1234, dport=1234) /
4355                Raw(b'\xa5' * 100)),
4356               (Ether(src=ep2.mac, dst=str(self.router_mac)) /
4357                IPv6(src=ep2.ip6, dst=ep1.ip6) /
4358                UDP(sport=1234, dport=1230) /
4359                Raw(b'\xa5' * 100))]
4360
4361         # should be dropped since no contract yet
4362         self.send_and_assert_no_replies(self.pg0, [p4[0]])
4363         self.send_and_assert_no_replies(self.pg0, [p6[0]])
4364
4365         #
4366         # Add a contract with a rule to load-balance redirect via SEP1 and SEP2
4367         # one of the next-hops is via an EP that is not known
4368         #
4369         rule4 = AclRule(is_permit=1, proto=17)
4370         rule6 = AclRule(src_prefix=IPv6Network((0, 0)),
4371                         dst_prefix=IPv6Network((0, 0)), is_permit=1, proto=17)
4372         acl = VppAcl(self, rules=[rule4, rule6])
4373         acl.add_vpp_config()
4374
4375         #
4376         # test the src-ip hash mode
4377         #
4378         c1 = VppGbpContract(
4379             self, 402, epg_220.sclass, epg_221.sclass, acl.acl_index,
4380             [VppGbpContractRule(
4381                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
4382                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
4383                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
4384                                        sep1.ip4, sep1.epg.rd)]),
4385              VppGbpContractRule(
4386                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
4387                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
4388                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
4389                                        sep1.ip6, sep1.epg.rd)])],
4390             [ETH_P_IP, ETH_P_IPV6])
4391         c1.add_vpp_config()
4392
4393         c2 = VppGbpContract(
4394             self, 402, epg_221.sclass, epg_220.sclass, acl.acl_index,
4395             [VppGbpContractRule(
4396                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
4397                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
4398                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
4399                                        sep1.ip4, sep1.epg.rd)]),
4400              VppGbpContractRule(
4401                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
4402                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
4403                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
4404                                        sep1.ip6, sep1.epg.rd)])],
4405             [ETH_P_IP, ETH_P_IPV6])
4406         c2.add_vpp_config()
4407
4408         # ep1 <--> ep2 redirected through sep1
4409         # sep1 is unknown
4410         # packet is redirected to sep bd and then go through sep bd UU
4411
4412         rxs = self.send_and_expect(self.pg0, p4[0] * 17, self.pg7)
4413
4414         for rx in rxs:
4415             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
4416             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
4417             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
4418             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
4419             self.assertEqual(rx[VXLAN].vni, 116)
4420             self.assertTrue(rx[VXLAN].flags.G)
4421             self.assertTrue(rx[VXLAN].flags.Instance)
4422             # redirect policy has been applied
4423             self.assertTrue(rx[VXLAN].gpflags.A)
4424             self.assertFalse(rx[VXLAN].gpflags.D)
4425
4426             inner = rx[VXLAN].payload
4427
4428             self.assertEqual(inner[Ether].src, routed_src_mac)
4429             self.assertEqual(inner[Ether].dst, sep1.mac)
4430             self.assertEqual(inner[IP].src, ep1.ip4)
4431             self.assertEqual(inner[IP].dst, ep2.ip4)
4432
4433         rxs = self.send_and_expect(self.pg1, p4[1] * 17, self.pg7)
4434
4435         for rx in rxs:
4436             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
4437             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
4438             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
4439             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
4440             self.assertEqual(rx[VXLAN].vni, 116)
4441             self.assertTrue(rx[VXLAN].flags.G)
4442             self.assertTrue(rx[VXLAN].flags.Instance)
4443             # redirect policy has been applied
4444             self.assertTrue(rx[VXLAN].gpflags.A)
4445             self.assertFalse(rx[VXLAN].gpflags.D)
4446
4447             inner = rx[VXLAN].payload
4448
4449             self.assertEqual(inner[Ether].src, routed_src_mac)
4450             self.assertEqual(inner[Ether].dst, sep1.mac)
4451             self.assertEqual(inner[IP].src, ep2.ip4)
4452             self.assertEqual(inner[IP].dst, ep1.ip4)
4453
4454         rxs = self.send_and_expect(self.pg0, p6[0] * 17, self.pg7)
4455
4456         for rx in rxs:
4457             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
4458             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
4459             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
4460             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
4461             self.assertEqual(rx[VXLAN].vni, 116)
4462             self.assertTrue(rx[VXLAN].flags.G)
4463             self.assertTrue(rx[VXLAN].flags.Instance)
4464             # redirect policy has been applied
4465             inner = rx[VXLAN].payload
4466
4467             self.assertEqual(inner[Ether].src, routed_src_mac)
4468             self.assertEqual(inner[Ether].dst, sep1.mac)
4469             self.assertEqual(inner[IPv6].src, ep1.ip6)
4470             self.assertEqual(inner[IPv6].dst, ep2.ip6)
4471
4472         rxs = self.send_and_expect(self.pg1, p6[1] * 17, self.pg7)
4473
4474         for rx in rxs:
4475             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
4476             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
4477             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
4478             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
4479             self.assertEqual(rx[VXLAN].vni, 116)
4480             self.assertTrue(rx[VXLAN].flags.G)
4481             self.assertTrue(rx[VXLAN].flags.Instance)
4482             # redirect policy has been applied
4483             self.assertTrue(rx[VXLAN].gpflags.A)
4484             self.assertFalse(rx[VXLAN].gpflags.D)
4485
4486             inner = rx[VXLAN].payload
4487
4488             self.assertEqual(inner[Ether].src, routed_src_mac)
4489             self.assertEqual(inner[Ether].dst, sep1.mac)
4490             self.assertEqual(inner[IPv6].src, ep2.ip6)
4491             self.assertEqual(inner[IPv6].dst, ep1.ip6)
4492
4493         # configure sep1: it is now local
4494         # packets between ep1 and ep2 are redirected locally
4495         sep1.add_vpp_config()
4496
4497         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
4498
4499         for rx in rxs:
4500             self.assertEqual(rx[Ether].src, routed_src_mac)
4501             self.assertEqual(rx[Ether].dst, sep1.mac)
4502             self.assertEqual(rx[IP].src, ep1.ip4)
4503             self.assertEqual(rx[IP].dst, ep2.ip4)
4504
4505         rxs = self.send_and_expect(self.pg1, p6[1] * 17, sep1.itf)
4506
4507         for rx in rxs:
4508             self.assertEqual(rx[Ether].src, routed_src_mac)
4509             self.assertEqual(rx[Ether].dst, sep1.mac)
4510             self.assertEqual(rx[IPv6].src, ep2.ip6)
4511             self.assertEqual(rx[IPv6].dst, ep1.ip6)
4512
4513         # packet coming from the l2 spine-proxy to sep1
4514         p = (Ether(src=self.pg7.remote_mac,
4515                    dst=self.pg7.local_mac) /
4516              IP(src=self.pg7.remote_ip4,
4517                 dst=self.pg7.local_ip4) /
4518              UDP(sport=1234, dport=48879) /
4519              VXLAN(vni=116, gpid=440, gpflags=0x08, flags=0x88) /
4520              Ether(src=str(self.router_mac), dst=sep1.mac) /
4521              IP(src=ep1.ip4, dst=ep2.ip4) /
4522              UDP(sport=1234, dport=1234) /
4523              Raw(b'\xa5' * 100))
4524
4525         rxs = self.send_and_expect(self.pg7, [p] * 17, sep1.itf)
4526
4527         for rx in rxs:
4528             self.assertEqual(rx[Ether].src, str(self.router_mac))
4529             self.assertEqual(rx[Ether].dst, sep1.mac)
4530             self.assertEqual(rx[IP].src, ep1.ip4)
4531             self.assertEqual(rx[IP].dst, ep2.ip4)
4532
4533         # contract for SEP to communicate with dst EP
4534         c3 = VppGbpContract(
4535             self, 402, epg_320.sclass, epg_221.sclass, acl.acl_index,
4536             [VppGbpContractRule(
4537                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4538                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC),
4539              VppGbpContractRule(
4540                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4541                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC)],
4542             [ETH_P_IP, ETH_P_IPV6])
4543         c3.add_vpp_config()
4544
4545         # temporarily remove ep2, so that ep2 is remote & unknown
4546         ep2.remove_vpp_config()
4547
4548         # packet going back from sep1 to its original dest (ep2)
4549         # as ep2 is now unknown (see above), it must go through
4550         # the rd UU (packet is routed)
4551
4552         p1 = (Ether(src=sep1.mac, dst=self.router_mac) /
4553               IP(src=ep1.ip4, dst=ep2.ip4) /
4554               UDP(sport=1234, dport=1234) /
4555               Raw(b'\xa5' * 100))
4556
4557         rxs = self.send_and_expect(self.pg3, [p1] * 17, self.pg7)
4558
4559         for rx in rxs:
4560             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
4561             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
4562             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
4563             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
4564             self.assertEqual(rx[VXLAN].vni, 114)
4565             self.assertTrue(rx[VXLAN].flags.G)
4566             self.assertTrue(rx[VXLAN].flags.Instance)
4567             # redirect policy has been applied
4568             inner = rx[VXLAN].payload
4569             self.assertEqual(inner[Ether].src, routed_src_mac)
4570             self.assertEqual(inner[Ether].dst, routed_dst_mac)
4571             self.assertEqual(inner[IP].src, ep1.ip4)
4572             self.assertEqual(inner[IP].dst, ep2.ip4)
4573
4574         self.logger.info(self.vapi.cli("show bridge 3 detail"))
4575         sep1.remove_vpp_config()
4576
4577         self.logger.info(self.vapi.cli("show bridge 1 detail"))
4578         self.logger.info(self.vapi.cli("show bridge 2 detail"))
4579
4580         # re-add ep2: it is local again :)
4581         ep2.add_vpp_config()
4582
4583         # packet coming back from the remote sep through rd UU
4584         p2 = (Ether(src=self.pg7.remote_mac,
4585                     dst=self.pg7.local_mac) /
4586               IP(src=self.pg7.remote_ip4,
4587                  dst=self.pg7.local_ip4) /
4588               UDP(sport=1234, dport=48879) /
4589               VXLAN(vni=114, gpid=441, gpflags=0x09, flags=0x88) /
4590               Ether(src=str(self.router_mac), dst=self.router_mac) /
4591               IP(src=ep1.ip4, dst=ep2.ip4) /
4592               UDP(sport=1234, dport=1234) /
4593               Raw(b'\xa5' * 100))
4594
4595         rxs = self.send_and_expect(self.pg7, [p2], self.pg1)
4596
4597         for rx in rxs:
4598             self.assertEqual(rx[Ether].src, str(self.router_mac))
4599             self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
4600             self.assertEqual(rx[IP].src, ep1.ip4)
4601             self.assertEqual(rx[IP].dst, ep2.ip4)
4602
4603         #
4604         # bd_uu2.add_vpp_config()
4605         #
4606
4607         #
4608         # cleanup
4609         #
4610         c1.remove_vpp_config()
4611         c2.remove_vpp_config()
4612         c3.remove_vpp_config()
4613         self.pg7.unconfig_ip4()
4614
4615     def test_gbp_l3_out(self):
4616         """ GBP L3 Out """
4617
4618         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
4619         self.vapi.cli("set logging class gbp level debug")
4620
4621         routed_dst_mac = "00:0c:0c:0c:0c:0c"
4622         routed_src_mac = "00:22:bd:f8:19:ff"
4623
4624         #
4625         # IP tables
4626         #
4627         t4 = VppIpTable(self, 1)
4628         t4.add_vpp_config()
4629         t6 = VppIpTable(self, 1, True)
4630         t6.add_vpp_config()
4631
4632         rd1 = VppGbpRouteDomain(self, 2, 55, t4, t6)
4633         rd1.add_vpp_config()
4634
4635         self.loop0.set_mac(self.router_mac)
4636
4637         #
4638         # Bind the BVI to the RD
4639         #
4640         b_ip4 = VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
4641         b_ip6 = VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
4642
4643         #
4644         # Pg7 hosts a BD's BUM
4645         # Pg1 some other l3 interface
4646         #
4647         self.pg7.config_ip4()
4648         self.pg7.resolve_arp()
4649
4650         #
4651         # a multicast vxlan-gbp tunnel for broadcast in the BD
4652         #
4653         tun_bm = VppVxlanGbpTunnel(self, self.pg7.local_ip4,
4654                                    "239.1.1.1", 88,
4655                                    mcast_itf=self.pg7)
4656         tun_bm.add_vpp_config()
4657
4658         #
4659         # a GBP external bridge domains for the EPs
4660         #
4661         bd1 = VppBridgeDomain(self, 1)
4662         bd1.add_vpp_config()
4663         gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0, None, tun_bm)
4664         gbd1.add_vpp_config()
4665
4666         #
4667         # The Endpoint-groups in which the external endpoints exist
4668         #
4669         epg_220 = VppGbpEndpointGroup(self, 220, 113, rd1, gbd1,
4670                                       None, gbd1.bvi,
4671                                       "10.0.0.128",
4672                                       "2001:10::128",
4673                                       VppGbpEndpointRetention(4))
4674         epg_220.add_vpp_config()
4675
4676         # the BVIs have the subnets applied ...
4677         ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128",
4678                                          24, bind=b_ip4).add_vpp_config()
4679         ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128",
4680                                          64, bind=b_ip6).add_vpp_config()
4681
4682         # ... which are L3-out subnets
4683         l3o_1 = VppGbpSubnet(
4684             self, rd1, "10.0.0.0", 24,
4685             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
4686             sclass=113)
4687         l3o_1.add_vpp_config()
4688
4689         #
4690         # an external interface attached to the outside world and the
4691         # external BD
4692         #
4693         VppL2Vtr(self, self.vlan_100, L2_VTR_OP.L2_POP_1).add_vpp_config()
4694         VppL2Vtr(self, self.vlan_101, L2_VTR_OP.L2_POP_1).add_vpp_config()
4695         vlan_144 = VppDot1QSubint(self, self.pg0, 144)
4696         vlan_144.admin_up()
4697         # vlan_102 is not poped
4698
4699         #
4700         # an unicast vxlan-gbp for inter-RD traffic
4701         #
4702         vx_tun_l3 = VppGbpVxlanTunnel(
4703             self, 444, rd1.rd_id,
4704             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3,
4705             self.pg2.local_ip4)
4706         vx_tun_l3.add_vpp_config()
4707
4708         #
4709         # External Endpoints
4710         #
4711         eep1 = VppGbpEndpoint(self, self.vlan_100,
4712                               epg_220, None,
4713                               "10.0.0.1", "11.0.0.1",
4714                               "2001:10::1", "3001::1",
4715                               ep_flags.GBP_API_ENDPOINT_FLAG_EXTERNAL)
4716         eep1.add_vpp_config()
4717         eep2 = VppGbpEndpoint(self, self.vlan_101,
4718                               epg_220, None,
4719                               "10.0.0.2", "11.0.0.2",
4720                               "2001:10::2", "3001::2",
4721                               ep_flags.GBP_API_ENDPOINT_FLAG_EXTERNAL)
4722         eep2.add_vpp_config()
4723         eep3 = VppGbpEndpoint(self, self.vlan_102,
4724                               epg_220, None,
4725                               "10.0.0.3", "11.0.0.3",
4726                               "2001:10::3", "3001::3",
4727                               ep_flags.GBP_API_ENDPOINT_FLAG_EXTERNAL)
4728         eep3.add_vpp_config()
4729
4730         #
4731         # A remote external endpoint
4732         #
4733         rep = VppGbpEndpoint(self, vx_tun_l3,
4734                              epg_220, None,
4735                              "10.0.0.101", "11.0.0.101",
4736                              "2001:10::101", "3001::101",
4737                              ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
4738                              self.pg7.local_ip4,
4739                              self.pg7.remote_ip4,
4740                              mac=None)
4741         rep.add_vpp_config()
4742
4743         #
4744         # EP1 impersonating EP3 is dropped
4745         #
4746         p = (Ether(src=eep1.mac, dst="ff:ff:ff:ff:ff:ff") /
4747              Dot1Q(vlan=100) /
4748              ARP(op="who-has",
4749                  psrc="10.0.0.3", pdst="10.0.0.128",
4750                  hwsrc=eep1.mac, hwdst="ff:ff:ff:ff:ff:ff"))
4751         self.send_and_assert_no_replies(self.pg0, p)
4752
4753         #
4754         # ARP packet from External EPs are accepted and replied to
4755         #
4756         p_arp = (Ether(src=eep1.mac, dst="ff:ff:ff:ff:ff:ff") /
4757                  Dot1Q(vlan=100) /
4758                  ARP(op="who-has",
4759                      psrc=eep1.ip4, pdst="10.0.0.128",
4760                      hwsrc=eep1.mac, hwdst="ff:ff:ff:ff:ff:ff"))
4761         rxs = self.send_and_expect(self.pg0, p_arp * 1, self.pg0)
4762
4763         #
4764         # ARP packet from host in remote subnet are accepted and replied to
4765         #
4766         p_arp = (Ether(src=eep3.mac, dst="ff:ff:ff:ff:ff:ff") /
4767                  Dot1Q(vlan=102) /
4768                  ARP(op="who-has",
4769                      psrc=eep3.ip4, pdst="10.0.0.128",
4770                      hwsrc=eep3.mac, hwdst="ff:ff:ff:ff:ff:ff"))
4771         rxs = self.send_and_expect(self.pg0, p_arp * 1, self.pg0)
4772
4773         #
4774         # packets destined to unknown addresses in the BVI's subnet
4775         # are ARP'd for
4776         #
4777         p4 = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
4778               Dot1Q(vlan=100) /
4779               IP(src="10.0.0.1", dst="10.0.0.88") /
4780               UDP(sport=1234, dport=1234) /
4781               Raw(b'\xa5' * 100))
4782         p6 = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
4783               Dot1Q(vlan=100) /
4784               IPv6(src="2001:10::1", dst="2001:10::88") /
4785               UDP(sport=1234, dport=1234) /
4786               Raw(b'\xa5' * 100))
4787
4788         rxs = self.send_and_expect(self.pg0, p4 * 1, self.pg7)
4789
4790         for rx in rxs:
4791             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
4792             # self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
4793             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
4794             self.assertEqual(rx[IP].dst, "239.1.1.1")
4795             self.assertEqual(rx[VXLAN].vni, 88)
4796             self.assertTrue(rx[VXLAN].flags.G)
4797             self.assertTrue(rx[VXLAN].flags.Instance)
4798             # policy was applied to the original IP packet
4799             self.assertEqual(rx[VXLAN].gpid, 113)
4800             self.assertTrue(rx[VXLAN].gpflags.A)
4801             self.assertFalse(rx[VXLAN].gpflags.D)
4802
4803             inner = rx[VXLAN].payload
4804
4805             self.assertTrue(inner.haslayer(ARP))
4806
4807         #
4808         # remote to external
4809         #
4810         p = (Ether(src=self.pg7.remote_mac,
4811                    dst=self.pg7.local_mac) /
4812              IP(src=self.pg7.remote_ip4,
4813                 dst=self.pg7.local_ip4) /
4814              UDP(sport=1234, dport=48879) /
4815              VXLAN(vni=444, gpid=113, flags=0x88) /
4816              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
4817              IP(src="10.0.0.101", dst="10.0.0.1") /
4818              UDP(sport=1234, dport=1234) /
4819              Raw(b'\xa5' * 100))
4820
4821         rxs = self.send_and_expect(self.pg7, p * 1, self.pg0)
4822
4823         #
4824         # local EP pings router
4825         #
4826         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
4827              Dot1Q(vlan=100) /
4828              IP(src=eep1.ip4, dst="10.0.0.128") /
4829              ICMP(type='echo-request'))
4830
4831         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
4832
4833         for rx in rxs:
4834             self.assertEqual(rx[Ether].src, str(self.router_mac))
4835             self.assertEqual(rx[Ether].dst, eep1.mac)
4836             self.assertEqual(rx[Dot1Q].vlan, 100)
4837
4838         #
4839         # local EP pings other local EP
4840         #
4841         p = (Ether(src=eep1.mac, dst=eep2.mac) /
4842              Dot1Q(vlan=100) /
4843              IP(src=eep1.ip4, dst=eep2.ip4) /
4844              ICMP(type='echo-request'))
4845
4846         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
4847
4848         for rx in rxs:
4849             self.assertEqual(rx[Ether].src, eep1.mac)
4850             self.assertEqual(rx[Ether].dst, eep2.mac)
4851             self.assertEqual(rx[Dot1Q].vlan, 101)
4852
4853         #
4854         # local EP pings router w/o vlan tag poped
4855         #
4856         p = (Ether(src=eep3.mac, dst=str(self.router_mac)) /
4857              Dot1Q(vlan=102) /
4858              IP(src=eep3.ip4, dst="10.0.0.128") /
4859              ICMP(type='echo-request'))
4860
4861         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
4862
4863         for rx in rxs:
4864             self.assertEqual(rx[Ether].src, str(self.router_mac))
4865             self.assertEqual(rx[Ether].dst, self.vlan_102.remote_mac)
4866
4867         #
4868         # A ip4 subnet reachable through the external EP1
4869         #
4870         ip_220 = VppIpRoute(self, "10.220.0.0", 24,
4871                             [VppRoutePath(eep1.ip4,
4872                                           eep1.epg.bvi.sw_if_index)],
4873                             table_id=t4.table_id)
4874         ip_220.add_vpp_config()
4875
4876         l3o_220 = VppGbpSubnet(
4877             self, rd1, "10.220.0.0", 24,
4878             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
4879             sclass=4220)
4880         l3o_220.add_vpp_config()
4881
4882         #
4883         # An ip6 subnet reachable through the external EP1
4884         #
4885         ip6_220 = VppIpRoute(self, "10:220::", 64,
4886                              [VppRoutePath(eep1.ip6,
4887                                            eep1.epg.bvi.sw_if_index)],
4888                              table_id=t6.table_id)
4889         ip6_220.add_vpp_config()
4890
4891         l3o6_220 = VppGbpSubnet(
4892             self, rd1, "10:220::", 64,
4893             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
4894             sclass=4220)
4895         l3o6_220.add_vpp_config()
4896
4897         #
4898         # A subnet reachable through the external EP2
4899         #
4900         ip_221 = VppIpRoute(self, "10.221.0.0", 24,
4901                             [VppRoutePath(eep2.ip4,
4902                                           eep2.epg.bvi.sw_if_index)],
4903                             table_id=t4.table_id)
4904         ip_221.add_vpp_config()
4905
4906         l3o_221 = VppGbpSubnet(
4907             self, rd1, "10.221.0.0", 24,
4908             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
4909             sclass=4221)
4910         l3o_221.add_vpp_config()
4911
4912         #
4913         # ping between hosts in remote subnets
4914         #  dropped without a contract
4915         #
4916         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
4917              Dot1Q(vlan=100) /
4918              IP(src="10.220.0.1", dst="10.221.0.1") /
4919              ICMP(type='echo-request'))
4920
4921         self.send_and_assert_no_replies(self.pg0, p * 1)
4922
4923         #
4924         # contract for the external nets to communicate
4925         #
4926         rule4 = AclRule(is_permit=1, proto=17)
4927         rule6 = AclRule(src_prefix=IPv6Network((0, 0)),
4928                         dst_prefix=IPv6Network((0, 0)), is_permit=1, proto=17)
4929         acl = VppAcl(self, rules=[rule4, rule6])
4930         acl.add_vpp_config()
4931
4932         #
4933         # A contract with the wrong scope is not matched
4934         #
4935         c_44 = VppGbpContract(
4936             self, 44, 4220, 4221, acl.acl_index,
4937             [VppGbpContractRule(
4938                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4939                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
4940                 []),
4941              VppGbpContractRule(
4942                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4943                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
4944                  [])],
4945             [ETH_P_IP, ETH_P_IPV6])
4946         c_44.add_vpp_config()
4947         self.send_and_assert_no_replies(self.pg0, p * 1)
4948
4949         c1 = VppGbpContract(
4950             self, 55, 4220, 4221, acl.acl_index,
4951             [VppGbpContractRule(
4952                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4953                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
4954                 []),
4955                 VppGbpContractRule(
4956                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4957                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
4958                     [])],
4959             [ETH_P_IP, ETH_P_IPV6])
4960         c1.add_vpp_config()
4961
4962         #
4963         # Contracts allowing ext-net 200 to talk with external EPs
4964         #
4965         c2 = VppGbpContract(
4966             self, 55, 4220, 113, acl.acl_index,
4967             [VppGbpContractRule(
4968                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4969                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
4970                 []),
4971                 VppGbpContractRule(
4972                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4973                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
4974                     [])],
4975             [ETH_P_IP, ETH_P_IPV6])
4976         c2.add_vpp_config()
4977         c3 = VppGbpContract(
4978             self, 55, 113, 4220, acl.acl_index,
4979             [VppGbpContractRule(
4980                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4981                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
4982                 []),
4983                 VppGbpContractRule(
4984                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4985                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
4986                     [])],
4987             [ETH_P_IP, ETH_P_IPV6])
4988         c3.add_vpp_config()
4989
4990         #
4991         # ping between hosts in remote subnets
4992         #
4993         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
4994              Dot1Q(vlan=100) /
4995              IP(src="10.220.0.1", dst="10.221.0.1") /
4996              UDP(sport=1234, dport=1234) /
4997              Raw(b'\xa5' * 100))
4998
4999         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
5000
5001         for rx in rxs:
5002             self.assertEqual(rx[Ether].src, str(self.router_mac))
5003             self.assertEqual(rx[Ether].dst, eep2.mac)
5004             self.assertEqual(rx[Dot1Q].vlan, 101)
5005
5006         # we did not learn these external hosts
5007         self.assertFalse(find_gbp_endpoint(self, ip="10.220.0.1"))
5008         self.assertFalse(find_gbp_endpoint(self, ip="10.221.0.1"))
5009
5010         #
5011         # from remote external EP to local external EP
5012         #
5013         p = (Ether(src=self.pg7.remote_mac,
5014                    dst=self.pg7.local_mac) /
5015              IP(src=self.pg7.remote_ip4,
5016                 dst=self.pg7.local_ip4) /
5017              UDP(sport=1234, dport=48879) /
5018              VXLAN(vni=444, gpid=113, flags=0x88) /
5019              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
5020              IP(src="10.0.0.101", dst="10.220.0.1") /
5021              UDP(sport=1234, dport=1234) /
5022              Raw(b'\xa5' * 100))
5023
5024         rxs = self.send_and_expect(self.pg7, p * 1, self.pg0)
5025
5026         #
5027         # ping from an external host to the remote external EP
5028         #
5029         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
5030              Dot1Q(vlan=100) /
5031              IP(src="10.220.0.1", dst=rep.ip4) /
5032              UDP(sport=1234, dport=1234) /
5033              Raw(b'\xa5' * 100))
5034
5035         rxs = self.send_and_expect(self.pg0, p * 1, self.pg7)
5036
5037         for rx in rxs:
5038             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
5039             # self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
5040             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
5041             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
5042             self.assertEqual(rx[VXLAN].vni, 444)
5043             self.assertTrue(rx[VXLAN].flags.G)
5044             self.assertTrue(rx[VXLAN].flags.Instance)
5045             # the sclass of the ext-net the packet came from
5046             self.assertEqual(rx[VXLAN].gpid, 4220)
5047             # policy was applied to the original IP packet
5048             self.assertTrue(rx[VXLAN].gpflags.A)
5049             # since it's an external host the reciever should not learn it
5050             self.assertTrue(rx[VXLAN].gpflags.D)
5051             inner = rx[VXLAN].payload
5052             self.assertEqual(inner[IP].src, "10.220.0.1")
5053             self.assertEqual(inner[IP].dst, rep.ip4)
5054
5055         #
5056         # An external subnet reachable via the remote external EP
5057         #
5058
5059         #
5060         # first the VXLAN-GBP tunnel over which it is reached
5061         #
5062         vx_tun_r1 = VppVxlanGbpTunnel(
5063             self, self.pg7.local_ip4,
5064             self.pg7.remote_ip4, 445,
5065             mode=(VppEnum.vl_api_vxlan_gbp_api_tunnel_mode_t.
5066                   VXLAN_GBP_API_TUNNEL_MODE_L3))
5067         vx_tun_r1.add_vpp_config()
5068         VppIpInterfaceBind(self, vx_tun_r1, t4).add_vpp_config()
5069
5070         self.logger.info(self.vapi.cli("sh vxlan-gbp tunnel"))
5071
5072         #
5073         # then the special adj to resolve through on that tunnel
5074         #
5075         n1 = VppNeighbor(self,
5076                          vx_tun_r1.sw_if_index,
5077                          "00:0c:0c:0c:0c:0c",
5078                          self.pg7.remote_ip4)
5079         n1.add_vpp_config()
5080
5081         #
5082         # the route via the adj above
5083         #
5084         ip_222 = VppIpRoute(self, "10.222.0.0", 24,
5085                             [VppRoutePath(self.pg7.remote_ip4,
5086                                           vx_tun_r1.sw_if_index)],
5087                             table_id=t4.table_id)
5088         ip_222.add_vpp_config()
5089
5090         l3o_222 = VppGbpSubnet(
5091             self, rd1, "10.222.0.0", 24,
5092             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
5093             sclass=4222)
5094         l3o_222.add_vpp_config()
5095
5096         #
5097         # ping between hosts in local and remote external subnets
5098         #  dropped without a contract
5099         #
5100         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
5101              Dot1Q(vlan=100) /
5102              IP(src="10.220.0.1", dst="10.222.0.1") /
5103              UDP(sport=1234, dport=1234) /
5104              Raw(b'\xa5' * 100))
5105
5106         rxs = self.send_and_assert_no_replies(self.pg0, p * 1)
5107
5108         #
5109         # Add contracts ext-nets for 220 -> 222
5110         #
5111         c4 = VppGbpContract(
5112             self, 55, 4220, 4222, acl.acl_index,
5113             [VppGbpContractRule(
5114                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5115                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5116                 []),
5117                 VppGbpContractRule(
5118                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5119                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5120                     [])],
5121             [ETH_P_IP, ETH_P_IPV6])
5122         c4.add_vpp_config()
5123
5124         #
5125         # ping from host in local to remote external subnets
5126         #
5127         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
5128              Dot1Q(vlan=100) /
5129              IP(src="10.220.0.1", dst="10.222.0.1") /
5130              UDP(sport=1234, dport=1234) /
5131              Raw(b'\xa5' * 100))
5132
5133         rxs = self.send_and_expect(self.pg0, p * 3, self.pg7)
5134
5135         for rx in rxs:
5136             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
5137             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
5138             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
5139             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
5140             self.assertEqual(rx[VXLAN].vni, 445)
5141             self.assertTrue(rx[VXLAN].flags.G)
5142             self.assertTrue(rx[VXLAN].flags.Instance)
5143             # the sclass of the ext-net the packet came from
5144             self.assertEqual(rx[VXLAN].gpid, 4220)
5145             # policy was applied to the original IP packet
5146             self.assertTrue(rx[VXLAN].gpflags.A)
5147             # since it's an external host the reciever should not learn it
5148             self.assertTrue(rx[VXLAN].gpflags.D)
5149             inner = rx[VXLAN].payload
5150             self.assertEqual(inner[Ether].dst, "00:0c:0c:0c:0c:0c")
5151             self.assertEqual(inner[IP].src, "10.220.0.1")
5152             self.assertEqual(inner[IP].dst, "10.222.0.1")
5153
5154         #
5155         # make the external subnet ECMP
5156         #
5157         vx_tun_r2 = VppVxlanGbpTunnel(
5158             self, self.pg7.local_ip4,
5159             self.pg7.remote_ip4, 446,
5160             mode=(VppEnum.vl_api_vxlan_gbp_api_tunnel_mode_t.
5161                   VXLAN_GBP_API_TUNNEL_MODE_L3))
5162         vx_tun_r2.add_vpp_config()
5163         VppIpInterfaceBind(self, vx_tun_r2, t4).add_vpp_config()
5164
5165         self.logger.info(self.vapi.cli("sh vxlan-gbp tunnel"))
5166
5167         n2 = VppNeighbor(self,
5168                          vx_tun_r2.sw_if_index,
5169                          "00:0c:0c:0c:0c:0c",
5170                          self.pg7.remote_ip4)
5171         n2.add_vpp_config()
5172
5173         ip_222.modify([VppRoutePath(self.pg7.remote_ip4,
5174                                     vx_tun_r1.sw_if_index),
5175                        VppRoutePath(self.pg7.remote_ip4,
5176                                     vx_tun_r2.sw_if_index)])
5177
5178         #
5179         # now expect load-balance
5180         #
5181         p = [(Ether(src=eep1.mac, dst=str(self.router_mac)) /
5182               Dot1Q(vlan=100) /
5183               IP(src="10.220.0.1", dst="10.222.0.1") /
5184               UDP(sport=1234, dport=1234) /
5185               Raw(b'\xa5' * 100)),
5186              (Ether(src=eep1.mac, dst=str(self.router_mac)) /
5187               Dot1Q(vlan=100) /
5188               IP(src="10.220.0.1", dst="10.222.0.1") /
5189               UDP(sport=1222, dport=1235) /
5190               Raw(b'\xa5' * 100))]
5191
5192         rxs = self.send_and_expect(self.pg0, p, self.pg7)
5193
5194         self.assertEqual(rxs[0][VXLAN].vni, 445)
5195         self.assertEqual(rxs[1][VXLAN].vni, 446)
5196
5197         #
5198         # Same LB test for v6
5199         #
5200         n3 = VppNeighbor(self,
5201                          vx_tun_r1.sw_if_index,
5202                          "00:0c:0c:0c:0c:0c",
5203                          self.pg7.remote_ip6)
5204         n3.add_vpp_config()
5205         n4 = VppNeighbor(self,
5206                          vx_tun_r2.sw_if_index,
5207                          "00:0c:0c:0c:0c:0c",
5208                          self.pg7.remote_ip6)
5209         n4.add_vpp_config()
5210
5211         ip_222_6 = VppIpRoute(self, "10:222::", 64,
5212                               [VppRoutePath(self.pg7.remote_ip6,
5213                                             vx_tun_r1.sw_if_index),
5214                                VppRoutePath(self.pg7.remote_ip6,
5215                                             vx_tun_r2.sw_if_index)],
5216                               table_id=t6.table_id)
5217         ip_222_6.add_vpp_config()
5218
5219         l3o_222_6 = VppGbpSubnet(
5220             self, rd1, "10:222::", 64,
5221             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
5222             sclass=4222)
5223         l3o_222_6.add_vpp_config()
5224
5225         p = [(Ether(src=eep1.mac, dst=str(self.router_mac)) /
5226               Dot1Q(vlan=100) /
5227               IPv6(src="10:220::1", dst="10:222::1") /
5228               UDP(sport=1234, dport=1234) /
5229               Raw(b'\xa5' * 100)),
5230              (Ether(src=eep1.mac, dst=str(self.router_mac)) /
5231               Dot1Q(vlan=100) /
5232               IPv6(src="10:220::1", dst="10:222::1") /
5233               UDP(sport=7777, dport=8881) /
5234               Raw(b'\xa5' * 100))]
5235
5236         self.logger.info(self.vapi.cli("sh ip6 fib 10:222::1"))
5237         rxs = self.send_and_expect(self.pg0, p, self.pg7)
5238
5239         self.assertEqual(rxs[0][VXLAN].vni, 445)
5240         self.assertEqual(rxs[1][VXLAN].vni, 446)
5241
5242         #
5243         # ping from host in remote to local external subnets
5244         # there's no contract for this, but the A bit is set.
5245         #
5246         p = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) /
5247              IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) /
5248              UDP(sport=1234, dport=48879) /
5249              VXLAN(vni=445, gpid=4222, flags=0x88, gpflags='A') /
5250              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
5251              IP(src="10.222.0.1", dst="10.220.0.1") /
5252              UDP(sport=1234, dport=1234) /
5253              Raw(b'\xa5' * 100))
5254
5255         rxs = self.send_and_expect(self.pg7, p * 3, self.pg0)
5256         self.assertFalse(find_gbp_endpoint(self, ip="10.222.0.1"))
5257
5258         #
5259         # ping from host in remote to remote external subnets
5260         #   this is dropped by reflection check.
5261         #
5262         p = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) /
5263              IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) /
5264              UDP(sport=1234, dport=48879) /
5265              VXLAN(vni=445, gpid=4222, flags=0x88, gpflags='A') /
5266              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
5267              IP(src="10.222.0.1", dst="10.222.0.2") /
5268              UDP(sport=1234, dport=1234) /
5269              Raw(b'\xa5' * 100))
5270
5271         rxs = self.send_and_assert_no_replies(self.pg7, p * 3)
5272
5273         p = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) /
5274              IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) /
5275              UDP(sport=1234, dport=48879) /
5276              VXLAN(vni=445, gpid=4222, flags=0x88, gpflags='A') /
5277              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
5278              IPv6(src="10:222::1", dst="10:222::2") /
5279              UDP(sport=1234, dport=1234) /
5280              Raw(b'\xa5' * 100))
5281
5282         rxs = self.send_and_assert_no_replies(self.pg7, p * 3)
5283
5284         #
5285         # local EP
5286         #
5287         lep1 = VppGbpEndpoint(self, vlan_144,
5288                               epg_220, None,
5289                               "10.0.0.44", "11.0.0.44",
5290                               "2001:10::44", "3001::44")
5291         lep1.add_vpp_config()
5292
5293         #
5294         # local EP to local ip4 external subnet
5295         #
5296         p = (Ether(src=lep1.mac, dst=str(self.router_mac)) /
5297              Dot1Q(vlan=144) /
5298              IP(src=lep1.ip4, dst="10.220.0.1") /
5299              UDP(sport=1234, dport=1234) /
5300              Raw(b'\xa5' * 100))
5301
5302         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
5303
5304         for rx in rxs:
5305             self.assertEqual(rx[Ether].src, str(self.router_mac))
5306             self.assertEqual(rx[Ether].dst, eep1.mac)
5307             self.assertEqual(rx[Dot1Q].vlan, 100)
5308
5309         #
5310         # local EP to local ip6 external subnet
5311         #
5312         p = (Ether(src=lep1.mac, dst=str(self.router_mac)) /
5313              Dot1Q(vlan=144) /
5314              IPv6(src=lep1.ip6, dst="10:220::1") /
5315              UDP(sport=1234, dport=1234) /
5316              Raw(b'\xa5' * 100))
5317
5318         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
5319
5320         for rx in rxs:
5321             self.assertEqual(rx[Ether].src, str(self.router_mac))
5322             self.assertEqual(rx[Ether].dst, eep1.mac)
5323             self.assertEqual(rx[Dot1Q].vlan, 100)
5324
5325         #
5326         # ip4 and ip6 subnets that load-balance
5327         #
5328         ip_20 = VppIpRoute(self, "10.20.0.0", 24,
5329                            [VppRoutePath(eep1.ip4,
5330                                          eep1.epg.bvi.sw_if_index),
5331                             VppRoutePath(eep2.ip4,
5332                                          eep2.epg.bvi.sw_if_index)],
5333                            table_id=t4.table_id)
5334         ip_20.add_vpp_config()
5335
5336         l3o_20 = VppGbpSubnet(
5337             self, rd1, "10.20.0.0", 24,
5338             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
5339             sclass=4220)
5340         l3o_20.add_vpp_config()
5341
5342         ip6_20 = VppIpRoute(self, "10:20::", 64,
5343                             [VppRoutePath(eep1.ip6,
5344                                           eep1.epg.bvi.sw_if_index),
5345                              VppRoutePath(eep2.ip6,
5346                                           eep2.epg.bvi.sw_if_index)],
5347                             table_id=t6.table_id)
5348         ip6_20.add_vpp_config()
5349
5350         l3o6_20 = VppGbpSubnet(
5351             self, rd1, "10:20::", 64,
5352             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
5353             sclass=4220)
5354         l3o6_20.add_vpp_config()
5355
5356         self.logger.info(self.vapi.cli("sh ip fib 10.20.0.1"))
5357         self.logger.info(self.vapi.cli("sh ip6 fib 10:20::1"))
5358
5359         # two ip6 packets whose port are chosen so they load-balance
5360         p = [(Ether(src=lep1.mac, dst=str(self.router_mac)) /
5361               Dot1Q(vlan=144) /
5362               IPv6(src=lep1.ip6, dst="10:20::1") /
5363               UDP(sport=1234, dport=1234) /
5364               Raw(b'\xa5' * 100)),
5365              (Ether(src=lep1.mac, dst=str(self.router_mac)) /
5366               Dot1Q(vlan=144) /
5367               IPv6(src=lep1.ip6, dst="10:20::1") /
5368               UDP(sport=124, dport=1230) /
5369               Raw(b'\xa5' * 100))]
5370
5371         rxs = self.send_and_expect(self.pg0, p, self.pg0, 2)
5372
5373         self.assertEqual(rxs[0][Dot1Q].vlan, 101)
5374         self.assertEqual(rxs[1][Dot1Q].vlan, 100)
5375
5376         # two ip4 packets whose port are chosen so they load-balance
5377         p = [(Ether(src=lep1.mac, dst=str(self.router_mac)) /
5378               Dot1Q(vlan=144) /
5379               IP(src=lep1.ip4, dst="10.20.0.1") /
5380               UDP(sport=1235, dport=1235) /
5381               Raw(b'\xa5' * 100)),
5382              (Ether(src=lep1.mac, dst=str(self.router_mac)) /
5383               Dot1Q(vlan=144) /
5384               IP(src=lep1.ip4, dst="10.20.0.1") /
5385               UDP(sport=124, dport=1230) /
5386               Raw(b'\xa5' * 100))]
5387
5388         rxs = self.send_and_expect(self.pg0, p, self.pg0, 2)
5389
5390         self.assertEqual(rxs[0][Dot1Q].vlan, 101)
5391         self.assertEqual(rxs[1][Dot1Q].vlan, 100)
5392
5393         #
5394         # cleanup
5395         #
5396         ip_222.remove_vpp_config()
5397         self.pg7.unconfig_ip4()
5398         self.vlan_101.set_vtr(L2_VTR_OP.L2_DISABLED)
5399         self.vlan_100.set_vtr(L2_VTR_OP.L2_DISABLED)
5400
5401     def test_gbp_anon_l3_out(self):
5402         """ GBP Anonymous L3 Out """
5403
5404         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
5405         self.vapi.cli("set logging class gbp level debug")
5406
5407         routed_dst_mac = "00:0c:0c:0c:0c:0c"
5408         routed_src_mac = "00:22:bd:f8:19:ff"
5409
5410         #
5411         # IP tables
5412         #
5413         t4 = VppIpTable(self, 1)
5414         t4.add_vpp_config()
5415         t6 = VppIpTable(self, 1, True)
5416         t6.add_vpp_config()
5417
5418         rd1 = VppGbpRouteDomain(self, 2, 55, t4, t6)
5419         rd1.add_vpp_config()
5420
5421         self.loop0.set_mac(self.router_mac)
5422
5423         #
5424         # Bind the BVI to the RD
5425         #
5426         bind_l0_ip4 = VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
5427         bind_l0_ip6 = VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
5428
5429         #
5430         # Pg7 hosts a BD's BUM
5431         # Pg1 some other l3 interface
5432         #
5433         self.pg7.config_ip4()
5434         self.pg7.resolve_arp()
5435
5436         #
5437         # a GBP external bridge domains for the EPs
5438         #
5439         bd1 = VppBridgeDomain(self, 1)
5440         bd1.add_vpp_config()
5441         gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0, None, None)
5442         gbd1.add_vpp_config()
5443
5444         #
5445         # The Endpoint-groups in which the external endpoints exist
5446         #
5447         epg_220 = VppGbpEndpointGroup(self, 220, 113, rd1, gbd1,
5448                                       None, gbd1.bvi,
5449                                       "10.0.0.128",
5450                                       "2001:10::128",
5451                                       VppGbpEndpointRetention(4))
5452         epg_220.add_vpp_config()
5453
5454         # the BVIs have the subnet applied ...
5455         ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi,
5456                                          "10.0.0.128", 24,
5457                                          bind=bind_l0_ip4).add_vpp_config()
5458
5459         # ... which is an Anonymous L3-out subnets
5460         l3o_1 = VppGbpSubnet(
5461             self, rd1, "10.0.0.0", 24,
5462             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_ANON_L3_OUT,
5463             sclass=113)
5464         l3o_1.add_vpp_config()
5465
5466         #
5467         # an external interface attached to the outside world and the
5468         # external BD
5469         #
5470         VppL2Vtr(self, self.vlan_100, L2_VTR_OP.L2_POP_1).add_vpp_config()
5471         VppL2Vtr(self, self.vlan_101, L2_VTR_OP.L2_POP_1).add_vpp_config()
5472
5473         #
5474         # vlan_100 and vlan_101 are anonymous l3-out interfaces
5475         #
5476         ext_itf = VppGbpExtItf(self, self.vlan_100, bd1, rd1, anon=True)
5477         ext_itf.add_vpp_config()
5478         ext_itf = VppGbpExtItf(self, self.vlan_101, bd1, rd1, anon=True)
5479         ext_itf.add_vpp_config()
5480
5481         #
5482         # an unicast vxlan-gbp for inter-RD traffic
5483         #
5484         vx_tun_l3 = VppGbpVxlanTunnel(
5485             self, 444, rd1.rd_id,
5486             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3,
5487             self.pg2.local_ip4)
5488         vx_tun_l3.add_vpp_config()
5489
5490         #
5491         # A remote external endpoint
5492         #
5493         rep = VppGbpEndpoint(self, vx_tun_l3,
5494                              epg_220, None,
5495                              "10.0.0.201", "11.0.0.201",
5496                              "2001:10::201", "3001::101",
5497                              ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
5498                              self.pg7.local_ip4,
5499                              self.pg7.remote_ip4,
5500                              mac=None)
5501         rep.add_vpp_config()
5502
5503         #
5504         # ARP packet from host in external subnet are accepted, flooded and
5505         # replied to. We expect 2 packets:
5506         #   - APR request flooded over the other vlan subif
5507         #   - ARP reply from BVI
5508         #
5509         p_arp = (Ether(src=self.vlan_100.remote_mac,
5510                        dst="ff:ff:ff:ff:ff:ff") /
5511                  Dot1Q(vlan=100) /
5512                  ARP(op="who-has",
5513                      psrc="10.0.0.100",
5514                      pdst="10.0.0.128",
5515                      hwsrc=self.vlan_100.remote_mac,
5516                      hwdst="ff:ff:ff:ff:ff:ff"))
5517         rxs = self.send_and_expect(self.pg0, p_arp * 1, self.pg0, n_rx=2)
5518
5519         p_arp = (Ether(src=self.vlan_101.remote_mac,
5520                        dst="ff:ff:ff:ff:ff:ff") /
5521                  Dot1Q(vlan=101) /
5522                  ARP(op="who-has",
5523                      psrc='10.0.0.101',
5524                      pdst="10.0.0.128",
5525                      hwsrc=self.vlan_101.remote_mac,
5526                      hwdst="ff:ff:ff:ff:ff:ff"))
5527         rxs = self.send_and_expect(self.pg0, p_arp * 1, self.pg0, n_rx=2)
5528
5529         #
5530         # remote to external
5531         #
5532         p = (Ether(src=self.pg7.remote_mac,
5533                    dst=self.pg7.local_mac) /
5534              IP(src=self.pg7.remote_ip4,
5535                 dst=self.pg7.local_ip4) /
5536              UDP(sport=1234, dport=48879) /
5537              VXLAN(vni=vx_tun_l3.vni, gpid=epg_220.sclass, flags=0x88) /
5538              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
5539              IP(src=str(rep.ip4), dst="10.0.0.100") /
5540              UDP(sport=1234, dport=1234) /
5541              Raw(b'\xa5' * 100))
5542         rxs = self.send_and_expect(self.pg7, p * 1, self.pg0)
5543
5544         #
5545         # local EP pings router
5546         #
5547         p = (Ether(src=self.vlan_100.remote_mac, dst=str(self.router_mac)) /
5548              Dot1Q(vlan=100) /
5549              IP(src="10.0.0.100", dst="10.0.0.128") /
5550              ICMP(type='echo-request'))
5551         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
5552
5553         for rx in rxs:
5554             self.assertEqual(rx[Ether].src, str(self.router_mac))
5555             self.assertEqual(rx[Ether].dst, self.vlan_100.remote_mac)
5556             self.assertEqual(rx[Dot1Q].vlan, 100)
5557
5558         #
5559         # local EP pings other local EP
5560         #
5561         p = (Ether(src=self.vlan_100.remote_mac,
5562                    dst=self.vlan_101.remote_mac) /
5563              Dot1Q(vlan=100) /
5564              IP(src="10.0.0.100", dst="10.0.0.101") /
5565              ICMP(type='echo-request'))
5566         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
5567
5568         for rx in rxs:
5569             self.assertEqual(rx[Ether].src, self.vlan_100.remote_mac)
5570             self.assertEqual(rx[Ether].dst, self.vlan_101.remote_mac)
5571             self.assertEqual(rx[Dot1Q].vlan, 101)
5572
5573         #
5574         # A subnet reachable through an external router on vlan 100
5575         #
5576         ip_220 = VppIpRoute(self, "10.220.0.0", 24,
5577                             [VppRoutePath("10.0.0.100",
5578                                           epg_220.bvi.sw_if_index)],
5579                             table_id=t4.table_id)
5580         ip_220.add_vpp_config()
5581
5582         l3o_220 = VppGbpSubnet(
5583             self, rd1, "10.220.0.0", 24,
5584             # note: this a "regular" L3 out subnet (not connected)
5585             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
5586             sclass=4220)
5587         l3o_220.add_vpp_config()
5588
5589         #
5590         # A subnet reachable through an external router on vlan 101
5591         #
5592         ip_221 = VppIpRoute(self, "10.221.0.0", 24,
5593                             [VppRoutePath("10.0.0.101",
5594                                           epg_220.bvi.sw_if_index)],
5595                             table_id=t4.table_id)
5596         ip_221.add_vpp_config()
5597
5598         l3o_221 = VppGbpSubnet(
5599             self, rd1, "10.221.0.0", 24,
5600             # note: this a "regular" L3 out subnet (not connected)
5601             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
5602             sclass=4221)
5603         l3o_221.add_vpp_config()
5604
5605         #
5606         # ping between hosts in remote subnets
5607         #  dropped without a contract
5608         #
5609         p = (Ether(src=self.vlan_100.remote_mac, dst=str(self.router_mac)) /
5610              Dot1Q(vlan=100) /
5611              IP(src="10.220.0.1", dst="10.221.0.1") /
5612              ICMP(type='echo-request'))
5613
5614         rxs = self.send_and_assert_no_replies(self.pg0, p * 1)
5615
5616         #
5617         # contract for the external nets to communicate
5618         #
5619         rule4 = AclRule(is_permit=1, proto=17)
5620         rule6 = AclRule(src_prefix=IPv6Network((0, 0)),
5621                         dst_prefix=IPv6Network((0, 0)), is_permit=1, proto=17)
5622         acl = VppAcl(self, rules=[rule4, rule6])
5623         acl.add_vpp_config()
5624
5625         c1 = VppGbpContract(
5626             self, 55, 4220, 4221, acl.acl_index,
5627             [VppGbpContractRule(
5628                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5629                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5630                 []),
5631                 VppGbpContractRule(
5632                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5633                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5634                     [])],
5635             [ETH_P_IP, ETH_P_IPV6])
5636         c1.add_vpp_config()
5637
5638         #
5639         # Contracts allowing ext-net 200 to talk with external EPs
5640         #
5641         c2 = VppGbpContract(
5642             self, 55, 4220, 113, acl.acl_index,
5643             [VppGbpContractRule(
5644                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5645                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5646                 []),
5647                 VppGbpContractRule(
5648                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5649                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5650                     [])],
5651             [ETH_P_IP, ETH_P_IPV6])
5652         c2.add_vpp_config()
5653         c3 = VppGbpContract(
5654             self, 55, 113, 4220, acl.acl_index,
5655             [VppGbpContractRule(
5656                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5657                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5658                 []),
5659                 VppGbpContractRule(
5660                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5661                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5662                     [])],
5663             [ETH_P_IP, ETH_P_IPV6])
5664         c3.add_vpp_config()
5665
5666         #
5667         # ping between hosts in remote subnets
5668         #
5669         p = (Ether(src=self.vlan_100.remote_mac, dst=str(self.router_mac)) /
5670              Dot1Q(vlan=100) /
5671              IP(src="10.220.0.1", dst="10.221.0.1") /
5672              UDP(sport=1234, dport=1234) /
5673              Raw(b'\xa5' * 100))
5674
5675         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
5676
5677         for rx in rxs:
5678             self.assertEqual(rx[Ether].src, str(self.router_mac))
5679             self.assertEqual(rx[Ether].dst, self.vlan_101.remote_mac)
5680             self.assertEqual(rx[Dot1Q].vlan, 101)
5681
5682         # we did not learn these external hosts
5683         self.assertFalse(find_gbp_endpoint(self, ip="10.220.0.1"))
5684         self.assertFalse(find_gbp_endpoint(self, ip="10.221.0.1"))
5685
5686         #
5687         # from remote external EP to local external EP
5688         #
5689         p = (Ether(src=self.pg7.remote_mac,
5690                    dst=self.pg7.local_mac) /
5691              IP(src=self.pg7.remote_ip4,
5692                 dst=self.pg7.local_ip4) /
5693              UDP(sport=1234, dport=48879) /
5694              VXLAN(vni=444, gpid=113, flags=0x88) /
5695              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
5696              IP(src=rep.ip4, dst="10.220.0.1") /
5697              UDP(sport=1234, dport=1234) /
5698              Raw(b'\xa5' * 100))
5699
5700         rxs = self.send_and_expect(self.pg7, p * 1, self.pg0)
5701
5702         #
5703         # ping from an external host to the remote external EP
5704         #
5705         p = (Ether(src=self.vlan_100.remote_mac, dst=str(self.router_mac)) /
5706              Dot1Q(vlan=100) /
5707              IP(src="10.220.0.1", dst=rep.ip4) /
5708              UDP(sport=1234, dport=1234) /
5709              Raw(b'\xa5' * 100))
5710
5711         rxs = self.send_and_expect(self.pg0, p * 1, self.pg7)
5712
5713         for rx in rxs:
5714             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
5715             # self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
5716             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
5717             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
5718             self.assertEqual(rx[VXLAN].vni, 444)
5719             self.assertTrue(rx[VXLAN].flags.G)
5720             self.assertTrue(rx[VXLAN].flags.Instance)
5721             # the sclass of the ext-net the packet came from
5722             self.assertEqual(rx[VXLAN].gpid, 4220)
5723             # policy was applied to the original IP packet
5724             self.assertTrue(rx[VXLAN].gpflags.A)
5725             # since it's an external host the reciever should not learn it
5726             self.assertTrue(rx[VXLAN].gpflags.D)
5727             inner = rx[VXLAN].payload
5728             self.assertEqual(inner[IP].src, "10.220.0.1")
5729             self.assertEqual(inner[IP].dst, rep.ip4)
5730
5731         #
5732         # An external subnet reachable via the remote external EP
5733         #
5734
5735         #
5736         # first the VXLAN-GBP tunnel over which it is reached
5737         #
5738         vx_tun_r = VppVxlanGbpTunnel(
5739             self, self.pg7.local_ip4,
5740             self.pg7.remote_ip4, 445,
5741             mode=(VppEnum.vl_api_vxlan_gbp_api_tunnel_mode_t.
5742                   VXLAN_GBP_API_TUNNEL_MODE_L3))
5743         vx_tun_r.add_vpp_config()
5744         VppIpInterfaceBind(self, vx_tun_r, t4).add_vpp_config()
5745
5746         self.logger.info(self.vapi.cli("sh vxlan-gbp tunnel"))
5747
5748         #
5749         # then the special adj to resolve through on that tunnel
5750         #
5751         n1 = VppNeighbor(self,
5752                          vx_tun_r.sw_if_index,
5753                          "00:0c:0c:0c:0c:0c",
5754                          self.pg7.remote_ip4)
5755         n1.add_vpp_config()
5756
5757         #
5758         # the route via the adj above
5759         #
5760         ip_222 = VppIpRoute(self, "10.222.0.0", 24,
5761                             [VppRoutePath(self.pg7.remote_ip4,
5762                                           vx_tun_r.sw_if_index)],
5763                             table_id=t4.table_id)
5764         ip_222.add_vpp_config()
5765
5766         l3o_222 = VppGbpSubnet(
5767             self, rd1, "10.222.0.0", 24,
5768             # note: this a "regular" l3out subnet (not connected)
5769             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
5770             sclass=4222)
5771         l3o_222.add_vpp_config()
5772
5773         #
5774         # ping between hosts in local and remote external subnets
5775         #  dropped without a contract
5776         #
5777         p = (Ether(src=self.vlan_100.remote_mac, dst=str(self.router_mac)) /
5778              Dot1Q(vlan=100) /
5779              IP(src="10.220.0.1", dst="10.222.0.1") /
5780              UDP(sport=1234, dport=1234) /
5781              Raw(b'\xa5' * 100))
5782
5783         rxs = self.send_and_assert_no_replies(self.pg0, p * 1)
5784
5785         #
5786         # Add contracts ext-nets for 220 -> 222
5787         #
5788         c4 = VppGbpContract(
5789             self, 55, 4220, 4222, acl.acl_index,
5790             [VppGbpContractRule(
5791                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5792                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5793                 []),
5794                 VppGbpContractRule(
5795                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5796                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5797                     [])],
5798             [ETH_P_IP, ETH_P_IPV6])
5799         c4.add_vpp_config()
5800
5801         #
5802         # ping from host in local to remote external subnets
5803         #
5804         p = (Ether(src=self.vlan_100.remote_mac, dst=str(self.router_mac)) /
5805              Dot1Q(vlan=100) /
5806              IP(src="10.220.0.1", dst="10.222.0.1") /
5807              UDP(sport=1234, dport=1234) /
5808              Raw(b'\xa5' * 100))
5809
5810         rxs = self.send_and_expect(self.pg0, p * 3, self.pg7)
5811
5812         for rx in rxs:
5813             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
5814             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
5815             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
5816             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
5817             self.assertEqual(rx[VXLAN].vni, 445)
5818             self.assertTrue(rx[VXLAN].flags.G)
5819             self.assertTrue(rx[VXLAN].flags.Instance)
5820             # the sclass of the ext-net the packet came from
5821             self.assertEqual(rx[VXLAN].gpid, 4220)
5822             # policy was applied to the original IP packet
5823             self.assertTrue(rx[VXLAN].gpflags.A)
5824             # since it's an external host the reciever should not learn it
5825             self.assertTrue(rx[VXLAN].gpflags.D)
5826             inner = rx[VXLAN].payload
5827             self.assertEqual(inner[Ether].dst, "00:0c:0c:0c:0c:0c")
5828             self.assertEqual(inner[IP].src, "10.220.0.1")
5829             self.assertEqual(inner[IP].dst, "10.222.0.1")
5830
5831         #
5832         # ping from host in remote to local external subnets
5833         # there's no contract for this, but the A bit is set.
5834         #
5835         p = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) /
5836              IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) /
5837              UDP(sport=1234, dport=48879) /
5838              VXLAN(vni=445, gpid=4222, flags=0x88, gpflags='A') /
5839              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
5840              IP(src="10.222.0.1", dst="10.220.0.1") /
5841              UDP(sport=1234, dport=1234) /
5842              Raw(b'\xa5' * 100))
5843
5844         rxs = self.send_and_expect(self.pg7, p * 3, self.pg0)
5845         self.assertFalse(find_gbp_endpoint(self, ip="10.222.0.1"))
5846
5847         #
5848         # ping from host in remote to remote external subnets
5849         #   this is dropped by reflection check.
5850         #
5851         p = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) /
5852              IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) /
5853              UDP(sport=1234, dport=48879) /
5854              VXLAN(vni=445, gpid=4222, flags=0x88, gpflags='A') /
5855              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
5856              IP(src="10.222.0.1", dst="10.222.0.2") /
5857              UDP(sport=1234, dport=1234) /
5858              Raw(b'\xa5' * 100))
5859
5860         rxs = self.send_and_assert_no_replies(self.pg7, p * 3)
5861
5862         #
5863         # cleanup
5864         #
5865         self.vlan_101.set_vtr(L2_VTR_OP.L2_DISABLED)
5866         self.vlan_100.set_vtr(L2_VTR_OP.L2_DISABLED)
5867         self.pg7.unconfig_ip4()
5868         # make sure the programmed EP is no longer learnt from DP
5869         self.wait_for_ep_timeout(sw_if_index=rep.itf.sw_if_index, ip=rep.ip4)
5870
5871
5872 if __name__ == '__main__':
5873     unittest.main(testRunner=VppTestRunner)