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