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