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