Skip failing ARM testcases for CI
[vpp.git] / test / test_gbp.py
1 #!/usr/bin/env python
2
3 import unittest
4
5 from framework import VppTestCase, VppTestRunner, is_skip_aarch64_set, \
6     is_platform_aarch64
7 from vpp_object import VppObject
8 from vpp_neighbor import VppNeighbor
9 from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable, \
10     VppIpInterfaceAddress, VppIpInterfaceBind, find_route
11 from vpp_l2 import VppBridgeDomain, VppBridgeDomainPort, \
12     VppBridgeDomainArpEntry, VppL2FibEntry, find_bridge_domain_port
13 from vpp_vxlan_gbp_tunnel import *
14 from vpp_sub_interface import VppDot1QSubint
15
16 from vpp_ip import *
17 from vpp_mac import *
18 from vpp_papi_provider import L2_PORT_TYPE
19 from vpp_papi import VppEnum
20
21 from scapy.packet import Raw
22 from scapy.layers.l2 import Ether, ARP, Dot1Q
23 from scapy.layers.inet import IP, UDP
24 from scapy.layers.inet6 import IPv6, ICMPv6ND_NS,  ICMPv6NDOptSrcLLAddr, \
25     ICMPv6ND_NA
26 from scapy.utils6 import in6_getnsma, in6_getnsmac
27 from scapy.layers.vxlan import VXLAN
28
29 from socket import AF_INET, AF_INET6
30 from scapy.utils import inet_pton, inet_ntop
31 from util import mactobinary
32 from vpp_papi_provider import L2_VTR_OP
33
34
35 def find_gbp_endpoint(test, sw_if_index=None, ip=None, mac=None):
36     if ip:
37         vip = VppIpAddress(ip)
38     if mac:
39         vmac = VppMacAddress(mac)
40
41     eps = test.vapi.gbp_endpoint_dump()
42
43     for ep in eps:
44         if sw_if_index:
45             if ep.endpoint.sw_if_index != sw_if_index:
46                 continue
47         if ip:
48             for eip in ep.endpoint.ips:
49                 if vip == eip:
50                     return True
51         if mac:
52             if vmac == ep.endpoint.mac:
53                 return True
54     return False
55
56
57 def find_gbp_vxlan(test, vni):
58     ts = test.vapi.gbp_vxlan_tunnel_dump()
59     for t in ts:
60         if t.tunnel.vni == vni:
61             return True
62     return False
63
64
65 class VppGbpEndpoint(VppObject):
66     """
67     GBP Endpoint
68     """
69
70     @property
71     def bin_mac(self):
72         return self.vmac.bytes
73
74     @property
75     def mac(self):
76         return self.vmac.address
77
78     @property
79     def mac(self):
80         return self.itf.remote_mac
81
82     @property
83     def ip4(self):
84         return self._ip4
85
86     @property
87     def fip4(self):
88         return self._fip4
89
90     @property
91     def ip6(self):
92         return self._ip6
93
94     @property
95     def fip6(self):
96         return self._fip6
97
98     @property
99     def ips(self):
100         return [self.ip4, self.ip6]
101
102     @property
103     def fips(self):
104         return [self.fip4, self.fip6]
105
106     def __init__(self, test, itf, epg, recirc, ip4, fip4, ip6, fip6,
107                  flags=0,
108                  tun_src="0.0.0.0",
109                  tun_dst="0.0.0.0",
110                  mac=True):
111         self._test = test
112         self.itf = itf
113         self.epg = epg
114         self.recirc = recirc
115
116         self._ip4 = VppIpAddress(ip4)
117         self._fip4 = VppIpAddress(fip4)
118         self._ip6 = VppIpAddress(ip6)
119         self._fip6 = VppIpAddress(fip6)
120
121         if mac:
122             self.vmac = VppMacAddress(self.itf.remote_mac)
123         else:
124             self.vmac = VppMacAddress("00:00:00:00:00:00")
125
126         self.flags = flags
127         self.tun_src = VppIpAddress(tun_src)
128         self.tun_dst = VppIpAddress(tun_dst)
129
130     def add_vpp_config(self):
131         res = self._test.vapi.gbp_endpoint_add(
132             self.itf.sw_if_index,
133             [self.ip4.encode(), self.ip6.encode()],
134             self.vmac.encode(),
135             self.epg.epg,
136             self.flags,
137             self.tun_src.encode(),
138             self.tun_dst.encode())
139         self.handle = res.handle
140         self._test.registry.register(self, self._test.logger)
141
142     def remove_vpp_config(self):
143         self._test.vapi.gbp_endpoint_del(self.handle)
144
145     def __str__(self):
146         return self.object_id()
147
148     def object_id(self):
149         return "gbp-endpoint:[%d==%d:%s:%d]" % (self.handle,
150                                                 self.itf.sw_if_index,
151                                                 self.ip4.address,
152                                                 self.epg.epg)
153
154     def query_vpp_config(self):
155         return find_gbp_endpoint(self._test,
156                                  self.itf.sw_if_index,
157                                  self.ip4.address)
158
159
160 class VppGbpRecirc(VppObject):
161     """
162     GBP Recirculation Interface
163     """
164
165     def __init__(self, test, epg, recirc, is_ext=False):
166         self._test = test
167         self.recirc = recirc
168         self.epg = epg
169         self.is_ext = is_ext
170
171     def add_vpp_config(self):
172         self._test.vapi.gbp_recirc_add_del(
173             1,
174             self.recirc.sw_if_index,
175             self.epg.epg,
176             self.is_ext)
177         self._test.registry.register(self, self._test.logger)
178
179     def remove_vpp_config(self):
180         self._test.vapi.gbp_recirc_add_del(
181             0,
182             self.recirc.sw_if_index,
183             self.epg.epg,
184             self.is_ext)
185
186     def __str__(self):
187         return self.object_id()
188
189     def object_id(self):
190         return "gbp-recirc:[%d]" % (self.recirc.sw_if_index)
191
192     def query_vpp_config(self):
193         rs = self._test.vapi.gbp_recirc_dump()
194         for r in rs:
195             if r.recirc.sw_if_index == self.recirc.sw_if_index:
196                 return True
197         return False
198
199
200 class VppGbpExtItf(VppObject):
201     """
202     GBP ExtItfulation Interface
203     """
204
205     def __init__(self, test, itf, bd, rd):
206         self._test = test
207         self.itf = itf
208         self.bd = bd
209         self.rd = rd
210
211     def add_vpp_config(self):
212         self._test.vapi.gbp_ext_itf_add_del(
213             1,
214             self.itf.sw_if_index,
215             self.bd.bd_id,
216             self.rd.rd_id)
217         self._test.registry.register(self, self._test.logger)
218
219     def remove_vpp_config(self):
220         self._test.vapi.gbp_ext_itf_add_del(
221             0,
222             self.itf.sw_if_index,
223             self.bd.bd_id,
224             self.rd.rd_id)
225
226     def __str__(self):
227         return self.object_id()
228
229     def object_id(self):
230         return "gbp-ext-itf:[%d]" % (self.itf.sw_if_index)
231
232     def query_vpp_config(self):
233         rs = self._test.vapi.gbp_ext_itf_dump()
234         for r in rs:
235             if r.ext_itf.sw_if_index == self.itf.sw_if_index:
236                 return True
237         return False
238
239
240 class VppGbpSubnet(VppObject):
241     """
242     GBP Subnet
243     """
244     def __init__(self, test, rd, address, address_len,
245                  type, sw_if_index=None, epg=None):
246         self._test = test
247         self.rd_id = rd.rd_id
248         self.prefix = VppIpPrefix(address, address_len)
249         self.type = type
250         self.sw_if_index = sw_if_index
251         self.epg = epg
252
253     def add_vpp_config(self):
254         self._test.vapi.gbp_subnet_add_del(
255             1,
256             self.rd_id,
257             self.prefix.encode(),
258             self.type,
259             sw_if_index=self.sw_if_index if self.sw_if_index else 0xffffffff,
260             epg_id=self.epg if self.epg else 0xffff)
261         self._test.registry.register(self, self._test.logger)
262
263     def remove_vpp_config(self):
264         self._test.vapi.gbp_subnet_add_del(
265             0,
266             self.rd_id,
267             self.prefix.encode(),
268             self.type)
269
270     def __str__(self):
271         return self.object_id()
272
273     def object_id(self):
274         return "gbp-subnet:[%d-%s]" % (self.rd_id, self.prefix)
275
276     def query_vpp_config(self):
277         ss = self._test.vapi.gbp_subnet_dump()
278         for s in ss:
279             if s.subnet.rd_id == self.rd_id and \
280                s.subnet.type == self.type and \
281                s.subnet.prefix == self.prefix:
282                 return True
283         return False
284
285
286 class VppGbpEndpointGroup(VppObject):
287     """
288     GBP Endpoint Group
289     """
290
291     def __init__(self, test, epg, rd, bd, uplink,
292                  bvi, bvi_ip4, bvi_ip6=None):
293         self._test = test
294         self.uplink = uplink
295         self.bvi = bvi
296         self.bvi_ip4 = VppIpAddress(bvi_ip4)
297         self.bvi_ip6 = VppIpAddress(bvi_ip6)
298         self.epg = epg
299         self.bd = bd
300         self.rd = rd
301
302     def add_vpp_config(self):
303         self._test.vapi.gbp_endpoint_group_add(
304             self.epg,
305             self.bd.bd.bd_id,
306             self.rd.rd_id,
307             self.uplink.sw_if_index if self.uplink else INDEX_INVALID)
308         self._test.registry.register(self, self._test.logger)
309
310     def remove_vpp_config(self):
311         self._test.vapi.gbp_endpoint_group_del(
312             self.epg)
313
314     def __str__(self):
315         return self.object_id()
316
317     def object_id(self):
318         return "gbp-endpoint-group:[%d]" % (self.epg)
319
320     def query_vpp_config(self):
321         epgs = self._test.vapi.gbp_endpoint_group_dump()
322         for epg in epgs:
323             if epg.epg.epg_id == self.epg:
324                 return True
325         return False
326
327
328 class VppGbpBridgeDomain(VppObject):
329     """
330     GBP Bridge Domain
331     """
332
333     def __init__(self, test, bd, bvi, uu_flood=None, learn=True):
334         self._test = test
335         self.bvi = bvi
336         self.uu_flood = uu_flood
337         self.bd = bd
338
339         e = VppEnum.vl_api_gbp_bridge_domain_flags_t
340         if (learn):
341             self.learn = e.GBP_BD_API_FLAG_NONE
342         else:
343             self.learn = e.GBP_BD_API_FLAG_DO_NOT_LEARN
344
345     def add_vpp_config(self):
346         self._test.vapi.gbp_bridge_domain_add(
347             self.bd.bd_id,
348             self.learn,
349             self.bvi.sw_if_index,
350             self.uu_flood.sw_if_index if self.uu_flood else INDEX_INVALID)
351         self._test.registry.register(self, self._test.logger)
352
353     def remove_vpp_config(self):
354         self._test.vapi.gbp_bridge_domain_del(self.bd.bd_id)
355
356     def __str__(self):
357         return self.object_id()
358
359     def object_id(self):
360         return "gbp-bridge-domain:[%d]" % (self.bd.bd_id)
361
362     def query_vpp_config(self):
363         bds = self._test.vapi.gbp_bridge_domain_dump()
364         for bd in bds:
365             if bd.bd.bd_id == self.bd.bd_id:
366                 return True
367         return False
368
369
370 class VppGbpRouteDomain(VppObject):
371     """
372     GBP Route Domain
373     """
374
375     def __init__(self, test, rd_id, t4, t6, ip4_uu=None, ip6_uu=None):
376         self._test = test
377         self.rd_id = rd_id
378         self.t4 = t4
379         self.t6 = t6
380         self.ip4_uu = ip4_uu
381         self.ip6_uu = ip6_uu
382
383     def add_vpp_config(self):
384         self._test.vapi.gbp_route_domain_add(
385             self.rd_id,
386             self.t4.table_id,
387             self.t6.table_id,
388             self.ip4_uu.sw_if_index if self.ip4_uu else INDEX_INVALID,
389             self.ip6_uu.sw_if_index if self.ip6_uu else INDEX_INVALID)
390         self._test.registry.register(self, self._test.logger)
391
392     def remove_vpp_config(self):
393         self._test.vapi.gbp_route_domain_del(self.rd_id)
394
395     def __str__(self):
396         return self.object_id()
397
398     def object_id(self):
399         return "gbp-route-domain:[%d]" % (self.rd_id)
400
401     def query_vpp_config(self):
402         rds = self._test.vapi.gbp_route_domain_dump()
403         for rd in rds:
404             if rd.rd.rd_id == self.rd_id:
405                 return True
406         return False
407
408
409 class VppGbpContractNextHop():
410     def __init__(self, mac, bd, ip, rd):
411         self.mac = mac
412         self.ip = ip
413         self.bd = bd
414         self.rd = rd
415
416     def encode(self):
417         return {'ip': self.ip.encode(),
418                 'mac': self.mac.encode(),
419                 'bd_id': self.bd.bd.bd_id,
420                 'rd_id': self.rd.rd_id}
421
422
423 class VppGbpContractRule():
424     def __init__(self, action, hash_mode, nhs=[]):
425         self.action = action
426         self.hash_mode = hash_mode
427         self.nhs = nhs
428
429     def encode(self):
430         nhs = []
431         for nh in self.nhs:
432             nhs.append(nh.encode())
433         while len(nhs) < 8:
434             nhs.append({})
435         return {'action': self.action,
436                 'nh_set': {
437                     'hash_mode': self.hash_mode,
438                     'n_nhs': len(self.nhs),
439                     'nhs': nhs}}
440
441
442 class VppGbpContract(VppObject):
443     """
444     GBP Contract
445     """
446
447     def __init__(self, test, src_epg, dst_epg, acl_index, rules=[]):
448         self._test = test
449         self.acl_index = acl_index
450         self.src_epg = src_epg
451         self.dst_epg = dst_epg
452         self.rules = rules
453
454     def add_vpp_config(self):
455         rules = []
456         for r in self.rules:
457             rules.append(r.encode())
458         self._test.vapi.gbp_contract_add_del(
459             1,
460             self.src_epg,
461             self.dst_epg,
462             self.acl_index,
463             rules)
464         self._test.registry.register(self, self._test.logger)
465
466     def remove_vpp_config(self):
467         self._test.vapi.gbp_contract_add_del(
468             0,
469             self.src_epg,
470             self.dst_epg,
471             self.acl_index,
472             [])
473
474     def __str__(self):
475         return self.object_id()
476
477     def object_id(self):
478         return "gbp-contract:[%d:%s:%d]" % (self.src_epg,
479                                             self.dst_epg,
480                                             self.acl_index)
481
482     def query_vpp_config(self):
483         cs = self._test.vapi.gbp_contract_dump()
484         for c in cs:
485             if c.contract.src_epg == self.src_epg \
486                and c.contract.dst_epg == self.dst_epg:
487                 return True
488         return False
489
490
491 class VppGbpVxlanTunnel(VppInterface):
492     """
493     GBP VXLAN tunnel
494     """
495
496     def __init__(self, test, vni, bd_rd_id, mode):
497         super(VppGbpVxlanTunnel, self).__init__(test)
498         self._test = test
499         self.vni = vni
500         self.bd_rd_id = bd_rd_id
501         self.mode = mode
502
503     def add_vpp_config(self):
504         r = self._test.vapi.gbp_vxlan_tunnel_add(
505             self.vni,
506             self.bd_rd_id,
507             self.mode)
508         self.set_sw_if_index(r.sw_if_index)
509         self._test.registry.register(self, self._test.logger)
510
511     def remove_vpp_config(self):
512         self._test.vapi.gbp_vxlan_tunnel_del(self.vni)
513
514     def __str__(self):
515         return self.object_id()
516
517     def object_id(self):
518         return "gbp-vxlan:%d" % (self.vni)
519
520     def query_vpp_config(self):
521         return find_gbp_vxlan(self._test, self.vni)
522
523
524 class VppGbpAcl(VppObject):
525     """
526     GBP Acl
527     """
528
529     def __init__(self, test):
530         self._test = test
531         self.acl_index = 4294967295
532
533     def create_rule(self, is_ipv6=0, permit_deny=0, proto=-1,
534                     s_prefix=0, s_ip='\x00\x00\x00\x00', sport_from=0,
535                     sport_to=65535, d_prefix=0, d_ip='\x00\x00\x00\x00',
536                     dport_from=0, dport_to=65535):
537         if proto == -1 or proto == 0:
538             sport_to = 0
539             dport_to = sport_to
540         elif proto == 1 or proto == 58:
541             sport_to = 255
542             dport_to = sport_to
543         rule = ({'is_permit': permit_deny, 'is_ipv6': is_ipv6, 'proto': proto,
544                  'srcport_or_icmptype_first': sport_from,
545                  'srcport_or_icmptype_last': sport_to,
546                  'src_ip_prefix_len': s_prefix,
547                  'src_ip_addr': s_ip,
548                  'dstport_or_icmpcode_first': dport_from,
549                  'dstport_or_icmpcode_last': dport_to,
550                  'dst_ip_prefix_len': d_prefix,
551                  'dst_ip_addr': d_ip})
552         return rule
553
554     def add_vpp_config(self, rules):
555
556         reply = self._test.vapi.acl_add_replace(self.acl_index,
557                                                 r=rules,
558                                                 tag='GBPTest')
559         self.acl_index = reply.acl_index
560         return self.acl_index
561
562     def remove_vpp_config(self):
563         self._test.vapi.acl_del(self.acl_index)
564
565     def __str__(self):
566         return self.object_id()
567
568     def object_id(self):
569         return "gbp-acl:[%d]" % (self.acl_index)
570
571     def query_vpp_config(self):
572         cs = self._test.vapi.acl_dump()
573         for c in cs:
574             if c.acl_index == self.acl_index:
575                 return True
576         return False
577
578
579 class TestGBP(VppTestCase):
580     """ GBP Test Case """
581
582     def setUp(self):
583         super(TestGBP, self).setUp()
584
585         self.create_pg_interfaces(range(9))
586         self.create_loopback_interfaces(8)
587
588         self.router_mac = VppMacAddress("00:11:22:33:44:55")
589
590         for i in self.pg_interfaces:
591             i.admin_up()
592         for i in self.lo_interfaces:
593             i.admin_up()
594
595     def tearDown(self):
596         for i in self.pg_interfaces:
597             i.admin_down()
598
599         super(TestGBP, self).tearDown()
600
601     def send_and_expect_bridged(self, src, tx, dst):
602         rx = self.send_and_expect(src, tx, dst)
603
604         for r in rx:
605             self.assertEqual(r[Ether].src, tx[0][Ether].src)
606             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
607             self.assertEqual(r[IP].src, tx[0][IP].src)
608             self.assertEqual(r[IP].dst, tx[0][IP].dst)
609         return rx
610
611     def send_and_expect_bridged6(self, src, tx, dst):
612         rx = self.send_and_expect(src, tx, dst)
613
614         for r in rx:
615             self.assertEqual(r[Ether].src, tx[0][Ether].src)
616             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
617             self.assertEqual(r[IPv6].src, tx[0][IPv6].src)
618             self.assertEqual(r[IPv6].dst, tx[0][IPv6].dst)
619         return rx
620
621     def send_and_expect_routed(self, src, tx, dst, src_mac):
622         rx = self.send_and_expect(src, tx, dst)
623
624         for r in rx:
625             self.assertEqual(r[Ether].src, src_mac)
626             self.assertEqual(r[Ether].dst, dst.remote_mac)
627             self.assertEqual(r[IP].src, tx[0][IP].src)
628             self.assertEqual(r[IP].dst, tx[0][IP].dst)
629         return rx
630
631     def send_and_expect_natted(self, src, tx, dst, src_ip):
632         rx = self.send_and_expect(src, tx, dst)
633
634         for r in rx:
635             self.assertEqual(r[Ether].src, tx[0][Ether].src)
636             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
637             self.assertEqual(r[IP].src, src_ip)
638             self.assertEqual(r[IP].dst, tx[0][IP].dst)
639         return rx
640
641     def send_and_expect_natted6(self, src, tx, dst, src_ip):
642         rx = self.send_and_expect(src, tx, dst)
643
644         for r in rx:
645             self.assertEqual(r[Ether].src, tx[0][Ether].src)
646             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
647             self.assertEqual(r[IPv6].src, src_ip)
648             self.assertEqual(r[IPv6].dst, tx[0][IPv6].dst)
649         return rx
650
651     def send_and_expect_unnatted(self, src, tx, dst, dst_ip):
652         rx = self.send_and_expect(src, tx, dst)
653
654         for r in rx:
655             self.assertEqual(r[Ether].src, tx[0][Ether].src)
656             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
657             self.assertEqual(r[IP].dst, dst_ip)
658             self.assertEqual(r[IP].src, tx[0][IP].src)
659         return rx
660
661     def send_and_expect_unnatted6(self, src, tx, dst, dst_ip):
662         rx = self.send_and_expect(src, tx, dst)
663
664         for r in rx:
665             self.assertEqual(r[Ether].src, tx[0][Ether].src)
666             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
667             self.assertEqual(r[IPv6].dst, dst_ip)
668             self.assertEqual(r[IPv6].src, tx[0][IPv6].src)
669         return rx
670
671     def send_and_expect_double_natted(self, src, tx, dst, src_ip, dst_ip):
672         rx = self.send_and_expect(src, tx, dst)
673
674         for r in rx:
675             self.assertEqual(r[Ether].src, self.router_mac.address)
676             self.assertEqual(r[Ether].dst, dst.remote_mac)
677             self.assertEqual(r[IP].dst, dst_ip)
678             self.assertEqual(r[IP].src, src_ip)
679         return rx
680
681     def send_and_expect_double_natted6(self, src, tx, dst, src_ip, dst_ip):
682         rx = self.send_and_expect(src, tx, dst)
683
684         for r in rx:
685             self.assertEqual(r[Ether].src, self.router_mac.address)
686             self.assertEqual(r[Ether].dst, dst.remote_mac)
687             self.assertEqual(r[IPv6].dst, dst_ip)
688             self.assertEqual(r[IPv6].src, src_ip)
689         return rx
690
691     def test_gbp(self):
692         """ Group Based Policy """
693
694         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
695
696         #
697         # Bridge Domains
698         #
699         bd1 = VppBridgeDomain(self, 1)
700         bd2 = VppBridgeDomain(self, 2)
701         bd20 = VppBridgeDomain(self, 20)
702
703         bd1.add_vpp_config()
704         bd2.add_vpp_config()
705         bd20.add_vpp_config()
706
707         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0)
708         gbd2 = VppGbpBridgeDomain(self, bd2, self.loop1)
709         gbd20 = VppGbpBridgeDomain(self, bd20, self.loop2)
710
711         gbd1.add_vpp_config()
712         gbd2.add_vpp_config()
713         gbd20.add_vpp_config()
714
715         #
716         # Route Domains
717         #
718         gt4 = VppIpTable(self, 0)
719         gt4.add_vpp_config()
720         gt6 = VppIpTable(self, 0, is_ip6=True)
721         gt6.add_vpp_config()
722         nt4 = VppIpTable(self, 20)
723         nt4.add_vpp_config()
724         nt6 = VppIpTable(self, 20, is_ip6=True)
725         nt6.add_vpp_config()
726
727         rd0 = VppGbpRouteDomain(self, 0, gt4, gt6, None, None)
728         rd20 = VppGbpRouteDomain(self, 20, nt4, nt6, None, None)
729
730         rd0.add_vpp_config()
731         rd20.add_vpp_config()
732
733         #
734         # 3 EPGs, 2 of which share a BD.
735         # 2 NAT EPGs, one for floating-IP subnets, the other for internet
736         #
737         epgs = [VppGbpEndpointGroup(self, 220, rd0, gbd1, self.pg4,
738                                     self.loop0,
739                                     "10.0.0.128",
740                                     "2001:10::128"),
741                 VppGbpEndpointGroup(self, 221, rd0, gbd1, self.pg5,
742                                     self.loop0,
743                                     "10.0.1.128",
744                                     "2001:10:1::128"),
745                 VppGbpEndpointGroup(self, 222, rd0, gbd2, self.pg6,
746                                     self.loop1,
747                                     "10.0.2.128",
748                                     "2001:10:2::128"),
749                 VppGbpEndpointGroup(self, 333, rd20, gbd20, self.pg7,
750                                     self.loop2,
751                                     "11.0.0.128",
752                                     "3001::128"),
753                 VppGbpEndpointGroup(self, 444, rd20, gbd20, self.pg8,
754                                     self.loop2,
755                                     "11.0.0.129",
756                                     "3001::129")]
757         recircs = [VppGbpRecirc(self, epgs[0],
758                                 self.loop3),
759                    VppGbpRecirc(self, epgs[1],
760                                 self.loop4),
761                    VppGbpRecirc(self, epgs[2],
762                                 self.loop5),
763                    VppGbpRecirc(self, epgs[3],
764                                 self.loop6, is_ext=True),
765                    VppGbpRecirc(self, epgs[4],
766                                 self.loop7, is_ext=True)]
767
768         epg_nat = epgs[3]
769         recirc_nat = recircs[3]
770
771         #
772         # 4 end-points, 2 in the same subnet, 3 in the same BD
773         #
774         eps = [VppGbpEndpoint(self, self.pg0,
775                               epgs[0], recircs[0],
776                               "10.0.0.1", "11.0.0.1",
777                               "2001:10::1", "3001::1"),
778                VppGbpEndpoint(self, self.pg1,
779                               epgs[0], recircs[0],
780                               "10.0.0.2", "11.0.0.2",
781                               "2001:10::2", "3001::2"),
782                VppGbpEndpoint(self, self.pg2,
783                               epgs[1], recircs[1],
784                               "10.0.1.1", "11.0.0.3",
785                               "2001:10:1::1", "3001::3"),
786                VppGbpEndpoint(self, self.pg3,
787                               epgs[2], recircs[2],
788                               "10.0.2.1", "11.0.0.4",
789                               "2001:10:2::1", "3001::4")]
790
791         #
792         # Config related to each of the EPGs
793         #
794         for epg in epgs:
795             # IP config on the BVI interfaces
796             if epg != epgs[1] and epg != epgs[4]:
797                 VppIpInterfaceBind(self, epg.bvi, epg.rd.t4).add_vpp_config()
798                 VppIpInterfaceBind(self, epg.bvi, epg.rd.t6).add_vpp_config()
799                 self.vapi.sw_interface_set_mac_address(
800                     epg.bvi.sw_if_index,
801                     self.router_mac.bytes)
802
803                 # The BVIs are NAT inside interfaces
804                 self.vapi.nat44_interface_add_del_feature(epg.bvi.sw_if_index,
805                                                           is_inside=1,
806                                                           is_add=1)
807                 self.vapi.nat66_add_del_interface(epg.bvi.sw_if_index,
808                                                   is_inside=1,
809                                                   is_add=1)
810
811             if_ip4 = VppIpInterfaceAddress(self, epg.bvi, epg.bvi_ip4, 32)
812             if_ip6 = VppIpInterfaceAddress(self, epg.bvi, epg.bvi_ip6, 128)
813             if_ip4.add_vpp_config()
814             if_ip6.add_vpp_config()
815
816             # EPG uplink interfaces in the RD
817             VppIpInterfaceBind(self, epg.uplink, epg.rd.t4).add_vpp_config()
818             VppIpInterfaceBind(self, epg.uplink, epg.rd.t6).add_vpp_config()
819
820             # add the BD ARP termination entry for BVI IP
821             epg.bd_arp_ip4 = VppBridgeDomainArpEntry(self, epg.bd.bd,
822                                                      self.router_mac.address,
823                                                      epg.bvi_ip4)
824             epg.bd_arp_ip6 = VppBridgeDomainArpEntry(self, epg.bd.bd,
825                                                      self.router_mac.address,
826                                                      epg.bvi_ip6)
827             epg.bd_arp_ip4.add_vpp_config()
828             epg.bd_arp_ip6.add_vpp_config()
829
830             # EPG in VPP
831             epg.add_vpp_config()
832
833         for recirc in recircs:
834             # EPG's ingress recirculation interface maps to its RD
835             VppIpInterfaceBind(self, recirc.recirc,
836                                recirc.epg.rd.t4).add_vpp_config()
837             VppIpInterfaceBind(self, recirc.recirc,
838                                recirc.epg.rd.t6).add_vpp_config()
839
840             self.vapi.nat44_interface_add_del_feature(
841                 recirc.recirc.sw_if_index,
842                 is_inside=0,
843                 is_add=1)
844             self.vapi.nat66_add_del_interface(
845                 recirc.recirc.sw_if_index,
846                 is_inside=0,
847                 is_add=1)
848
849             recirc.add_vpp_config()
850
851         for recirc in recircs:
852             self.assertTrue(find_bridge_domain_port(self,
853                                                     recirc.epg.bd.bd.bd_id,
854                                                     recirc.recirc.sw_if_index))
855
856         for ep in eps:
857             self.pg_enable_capture(self.pg_interfaces)
858             self.pg_start()
859             #
860             # routes to the endpoints. We need these since there are no
861             # adj-fibs due to the fact the the BVI address has /32 and
862             # the subnet is not attached.
863             #
864             for (ip, fip) in zip(ep.ips, ep.fips):
865                 # Add static mappings for each EP from the 10/8 to 11/8 network
866                 if ip.af == AF_INET:
867                     self.vapi.nat44_add_del_static_mapping(ip.bytes,
868                                                            fip.bytes,
869                                                            vrf_id=0,
870                                                            addr_only=1)
871                 else:
872                     self.vapi.nat66_add_del_static_mapping(ip.bytes,
873                                                            fip.bytes,
874                                                            vrf_id=0)
875
876             # VPP EP create ...
877             ep.add_vpp_config()
878
879             self.logger.info(self.vapi.cli("sh gbp endpoint"))
880
881             # ... results in a Gratuitous ARP/ND on the EPG's uplink
882             rx = ep.epg.uplink.get_capture(len(ep.ips), timeout=0.2)
883
884             for ii, ip in enumerate(ep.ips):
885                 p = rx[ii]
886
887                 if ip.is_ip6:
888                     self.assertTrue(p.haslayer(ICMPv6ND_NA))
889                     self.assertEqual(p[ICMPv6ND_NA].tgt, ip.address)
890                 else:
891                     self.assertTrue(p.haslayer(ARP))
892                     self.assertEqual(p[ARP].psrc, ip.address)
893                     self.assertEqual(p[ARP].pdst, ip.address)
894
895             # add the BD ARP termination entry for floating IP
896             for fip in ep.fips:
897                 ba = VppBridgeDomainArpEntry(self, epg_nat.bd.bd, ep.mac, fip)
898                 ba.add_vpp_config()
899
900                 # floating IPs route via EPG recirc
901                 r = VppIpRoute(self, fip.address, fip.length,
902                                [VppRoutePath(fip.address,
903                                              ep.recirc.recirc.sw_if_index,
904                                              is_dvr=1,
905                                              proto=fip.dpo_proto)],
906                                table_id=20,
907                                is_ip6=fip.is_ip6)
908                 r.add_vpp_config()
909
910             # L2 FIB entries in the NAT EPG BD to bridge the packets from
911             # the outside direct to the internal EPG
912             lf = VppL2FibEntry(self, epg_nat.bd.bd, ep.mac,
913                                ep.recirc.recirc, bvi_mac=0)
914             lf.add_vpp_config()
915
916         #
917         # ARP packets for unknown IP are sent to the EPG uplink
918         #
919         pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff",
920                          src=self.pg0.remote_mac) /
921                    ARP(op="who-has",
922                        hwdst="ff:ff:ff:ff:ff:ff",
923                        hwsrc=self.pg0.remote_mac,
924                        pdst="10.0.0.88",
925                        psrc="10.0.0.99"))
926
927         self.vapi.cli("clear trace")
928         self.pg0.add_stream(pkt_arp)
929
930         self.pg_enable_capture(self.pg_interfaces)
931         self.pg_start()
932
933         rxd = epgs[0].uplink.get_capture(1)
934
935         #
936         # ARP/ND packets get a response
937         #
938         pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff",
939                          src=self.pg0.remote_mac) /
940                    ARP(op="who-has",
941                        hwdst="ff:ff:ff:ff:ff:ff",
942                        hwsrc=self.pg0.remote_mac,
943                        pdst=epgs[0].bvi_ip4.address,
944                        psrc=eps[0].ip4.address))
945
946         self.send_and_expect(self.pg0, [pkt_arp], self.pg0)
947
948         nsma = in6_getnsma(inet_pton(AF_INET6, eps[0].ip6.address))
949         d = inet_ntop(AF_INET6, nsma)
950         pkt_nd = (Ether(dst=in6_getnsmac(nsma),
951                         src=self.pg0.remote_mac) /
952                   IPv6(dst=d, src=eps[0].ip6.address) /
953                   ICMPv6ND_NS(tgt=epgs[0].bvi_ip6.address) /
954                   ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac))
955         self.send_and_expect(self.pg0, [pkt_nd], self.pg0)
956
957         #
958         # broadcast packets are flooded
959         #
960         pkt_bcast = (Ether(dst="ff:ff:ff:ff:ff:ff",
961                            src=self.pg0.remote_mac) /
962                      IP(src=eps[0].ip4.address, dst="232.1.1.1") /
963                      UDP(sport=1234, dport=1234) /
964                      Raw('\xa5' * 100))
965
966         self.vapi.cli("clear trace")
967         self.pg0.add_stream(pkt_bcast)
968
969         self.pg_enable_capture(self.pg_interfaces)
970         self.pg_start()
971
972         rxd = eps[1].itf.get_capture(1)
973         self.assertEqual(rxd[0][Ether].dst, pkt_bcast[Ether].dst)
974         rxd = epgs[0].uplink.get_capture(1)
975         self.assertEqual(rxd[0][Ether].dst, pkt_bcast[Ether].dst)
976
977         #
978         # packets to non-local L3 destinations dropped
979         #
980         pkt_intra_epg_220_ip4 = (Ether(src=self.pg0.remote_mac,
981                                        dst=self.router_mac.address) /
982                                  IP(src=eps[0].ip4.address,
983                                     dst="10.0.0.99") /
984                                  UDP(sport=1234, dport=1234) /
985                                  Raw('\xa5' * 100))
986         pkt_inter_epg_222_ip4 = (Ether(src=self.pg0.remote_mac,
987                                        dst=self.router_mac.address) /
988                                  IP(src=eps[0].ip4.address,
989                                     dst="10.0.1.99") /
990                                  UDP(sport=1234, dport=1234) /
991                                  Raw('\xa5' * 100))
992
993         self.send_and_assert_no_replies(self.pg0, pkt_intra_epg_220_ip4 * 65)
994
995         pkt_inter_epg_222_ip6 = (Ether(src=self.pg0.remote_mac,
996                                        dst=self.router_mac.address) /
997                                  IPv6(src=eps[0].ip6.address,
998                                       dst="2001:10::99") /
999                                  UDP(sport=1234, dport=1234) /
1000                                  Raw('\xa5' * 100))
1001         self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_222_ip6 * 65)
1002
1003         #
1004         # Add the subnet routes
1005         #
1006         s41 = VppGbpSubnet(
1007             self, rd0, "10.0.0.0", 24,
1008             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
1009         s42 = VppGbpSubnet(
1010             self, rd0, "10.0.1.0", 24,
1011             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
1012         s43 = VppGbpSubnet(
1013             self, rd0, "10.0.2.0", 24,
1014             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
1015         s61 = VppGbpSubnet(
1016             self, rd0, "2001:10::1", 64,
1017             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
1018         s62 = VppGbpSubnet(
1019             self, rd0, "2001:10:1::1", 64,
1020             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
1021         s63 = VppGbpSubnet(
1022             self, rd0, "2001:10:2::1", 64,
1023             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
1024         s41.add_vpp_config()
1025         s42.add_vpp_config()
1026         s43.add_vpp_config()
1027         s61.add_vpp_config()
1028         s62.add_vpp_config()
1029         s63.add_vpp_config()
1030
1031         self.send_and_expect_bridged(eps[0].itf,
1032                                      pkt_intra_epg_220_ip4 * 65,
1033                                      eps[0].epg.uplink)
1034         self.send_and_expect_bridged(eps[0].itf,
1035                                      pkt_inter_epg_222_ip4 * 65,
1036                                      eps[0].epg.uplink)
1037         self.send_and_expect_bridged6(eps[0].itf,
1038                                       pkt_inter_epg_222_ip6 * 65,
1039                                       eps[0].epg.uplink)
1040
1041         self.logger.info(self.vapi.cli("sh ip fib 11.0.0.2"))
1042         self.logger.info(self.vapi.cli("sh gbp endpoint-group"))
1043         self.logger.info(self.vapi.cli("sh gbp endpoint"))
1044         self.logger.info(self.vapi.cli("sh gbp recirc"))
1045         self.logger.info(self.vapi.cli("sh int"))
1046         self.logger.info(self.vapi.cli("sh int addr"))
1047         self.logger.info(self.vapi.cli("sh int feat loop6"))
1048         self.logger.info(self.vapi.cli("sh vlib graph ip4-gbp-src-classify"))
1049         self.logger.info(self.vapi.cli("sh int feat loop3"))
1050         self.logger.info(self.vapi.cli("sh int feat pg0"))
1051
1052         #
1053         # Packet destined to unknown unicast is sent on the epg uplink ...
1054         #
1055         pkt_intra_epg_220_to_uplink = (Ether(src=self.pg0.remote_mac,
1056                                              dst="00:00:00:33:44:55") /
1057                                        IP(src=eps[0].ip4.address,
1058                                           dst="10.0.0.99") /
1059                                        UDP(sport=1234, dport=1234) /
1060                                        Raw('\xa5' * 100))
1061
1062         self.send_and_expect_bridged(eps[0].itf,
1063                                      pkt_intra_epg_220_to_uplink * 65,
1064                                      eps[0].epg.uplink)
1065         # ... and nowhere else
1066         self.pg1.get_capture(0, timeout=0.1)
1067         self.pg1.assert_nothing_captured(remark="Flood onto other VMS")
1068
1069         pkt_intra_epg_221_to_uplink = (Ether(src=self.pg2.remote_mac,
1070                                              dst="00:00:00:33:44:66") /
1071                                        IP(src=eps[0].ip4.address,
1072                                           dst="10.0.0.99") /
1073                                        UDP(sport=1234, dport=1234) /
1074                                        Raw('\xa5' * 100))
1075
1076         self.send_and_expect_bridged(eps[2].itf,
1077                                      pkt_intra_epg_221_to_uplink * 65,
1078                                      eps[2].epg.uplink)
1079
1080         #
1081         # Packets from the uplink are forwarded in the absence of a contract
1082         #
1083         pkt_intra_epg_220_from_uplink = (Ether(src="00:00:00:33:44:55",
1084                                                dst=self.pg0.remote_mac) /
1085                                          IP(src=eps[0].ip4.address,
1086                                             dst="10.0.0.99") /
1087                                          UDP(sport=1234, dport=1234) /
1088                                          Raw('\xa5' * 100))
1089
1090         self.send_and_expect_bridged(self.pg4,
1091                                      pkt_intra_epg_220_from_uplink * 65,
1092                                      self.pg0)
1093
1094         #
1095         # in the absence of policy, endpoints in the same EPG
1096         # can communicate
1097         #
1098         pkt_intra_epg = (Ether(src=self.pg0.remote_mac,
1099                                dst=self.pg1.remote_mac) /
1100                          IP(src=eps[0].ip4.address,
1101                             dst=eps[1].ip4.address) /
1102                          UDP(sport=1234, dport=1234) /
1103                          Raw('\xa5' * 100))
1104
1105         self.send_and_expect_bridged(self.pg0, pkt_intra_epg * 65, self.pg1)
1106
1107         #
1108         # in the abscense of policy, endpoints in the different EPG
1109         # cannot communicate
1110         #
1111         pkt_inter_epg_220_to_221 = (Ether(src=self.pg0.remote_mac,
1112                                           dst=self.pg2.remote_mac) /
1113                                     IP(src=eps[0].ip4.address,
1114                                        dst=eps[2].ip4.address) /
1115                                     UDP(sport=1234, dport=1234) /
1116                                     Raw('\xa5' * 100))
1117         pkt_inter_epg_221_to_220 = (Ether(src=self.pg2.remote_mac,
1118                                           dst=self.pg0.remote_mac) /
1119                                     IP(src=eps[2].ip4.address,
1120                                        dst=eps[0].ip4.address) /
1121                                     UDP(sport=1234, dport=1234) /
1122                                     Raw('\xa5' * 100))
1123         pkt_inter_epg_220_to_222 = (Ether(src=self.pg0.remote_mac,
1124                                           dst=self.router_mac.address) /
1125                                     IP(src=eps[0].ip4.address,
1126                                        dst=eps[3].ip4.address) /
1127                                     UDP(sport=1234, dport=1234) /
1128                                     Raw('\xa5' * 100))
1129
1130         self.send_and_assert_no_replies(eps[0].itf,
1131                                         pkt_inter_epg_220_to_221 * 65)
1132         self.send_and_assert_no_replies(eps[0].itf,
1133                                         pkt_inter_epg_220_to_222 * 65)
1134
1135         #
1136         # A uni-directional contract from EPG 220 -> 221
1137         #
1138         acl = VppGbpAcl(self)
1139         rule = acl.create_rule(permit_deny=1, proto=17)
1140         rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
1141         acl_index = acl.add_vpp_config([rule, rule2])
1142         c1 = VppGbpContract(
1143             self, 220, 221, acl_index,
1144             [VppGbpContractRule(
1145                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1146                 []),
1147              VppGbpContractRule(
1148                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1149                  [])])
1150         c1.add_vpp_config()
1151
1152         self.send_and_expect_bridged(eps[0].itf,
1153                                      pkt_inter_epg_220_to_221 * 65,
1154                                      eps[2].itf)
1155         self.send_and_assert_no_replies(eps[0].itf,
1156                                         pkt_inter_epg_220_to_222 * 65)
1157
1158         #
1159         # contract for the return direction
1160         #
1161         c2 = VppGbpContract(
1162             self, 221, 220, acl_index,
1163             [VppGbpContractRule(
1164                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1165                 []),
1166              VppGbpContractRule(
1167                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1168                  [])])
1169
1170         c2.add_vpp_config()
1171
1172         self.send_and_expect_bridged(eps[0].itf,
1173                                      pkt_inter_epg_220_to_221 * 65,
1174                                      eps[2].itf)
1175         self.send_and_expect_bridged(eps[2].itf,
1176                                      pkt_inter_epg_221_to_220 * 65,
1177                                      eps[0].itf)
1178
1179         #
1180         # check that inter group is still disabled for the groups
1181         # not in the contract.
1182         #
1183         self.send_and_assert_no_replies(eps[0].itf,
1184                                         pkt_inter_epg_220_to_222 * 65)
1185
1186         #
1187         # A uni-directional contract from EPG 220 -> 222 'L3 routed'
1188         #
1189         c3 = VppGbpContract(
1190             self, 220, 222, acl_index,
1191             [VppGbpContractRule(
1192                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1193                 []),
1194              VppGbpContractRule(
1195                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1196                  [])])
1197
1198         c3.add_vpp_config()
1199
1200         self.logger.info(self.vapi.cli("sh gbp contract"))
1201
1202         self.send_and_expect_routed(eps[0].itf,
1203                                     pkt_inter_epg_220_to_222 * 65,
1204                                     eps[3].itf,
1205                                     self.router_mac.address)
1206
1207         #
1208         # remove both contracts, traffic stops in both directions
1209         #
1210         c2.remove_vpp_config()
1211         c1.remove_vpp_config()
1212         c3.remove_vpp_config()
1213         acl.remove_vpp_config()
1214
1215         self.send_and_assert_no_replies(eps[2].itf,
1216                                         pkt_inter_epg_221_to_220 * 65)
1217         self.send_and_assert_no_replies(eps[0].itf,
1218                                         pkt_inter_epg_220_to_221 * 65)
1219         self.send_and_expect_bridged(eps[0].itf,
1220                                      pkt_intra_epg * 65,
1221                                      eps[1].itf)
1222
1223         #
1224         # EPs to the outside world
1225         #
1226
1227         # in the EP's RD an external subnet via the NAT EPG's recirc
1228         se1 = VppGbpSubnet(
1229             self, rd0, "0.0.0.0", 0,
1230             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1231             sw_if_index=recirc_nat.recirc.sw_if_index,
1232             epg=epg_nat.epg)
1233         se2 = VppGbpSubnet(
1234             self, rd0, "11.0.0.0", 8,
1235             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1236             sw_if_index=recirc_nat.recirc.sw_if_index,
1237             epg=epg_nat.epg)
1238         se16 = VppGbpSubnet(
1239             self, rd0, "::", 0,
1240             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1241             sw_if_index=recirc_nat.recirc.sw_if_index,
1242             epg=epg_nat.epg)
1243         # in the NAT RD an external subnet via the NAT EPG's uplink
1244         se3 = VppGbpSubnet(
1245             self, rd20, "0.0.0.0", 0,
1246             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1247             sw_if_index=epg_nat.uplink.sw_if_index,
1248             epg=epg_nat.epg)
1249         se36 = VppGbpSubnet(
1250             self, rd20, "::", 0,
1251             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1252             sw_if_index=epg_nat.uplink.sw_if_index,
1253             epg=epg_nat.epg)
1254         se4 = VppGbpSubnet(
1255             self, rd20, "11.0.0.0", 8,
1256             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1257             sw_if_index=epg_nat.uplink.sw_if_index,
1258             epg=epg_nat.epg)
1259         se1.add_vpp_config()
1260         se2.add_vpp_config()
1261         se16.add_vpp_config()
1262         se3.add_vpp_config()
1263         se36.add_vpp_config()
1264         se4.add_vpp_config()
1265
1266         self.logger.info(self.vapi.cli("sh ip fib 0.0.0.0/0"))
1267         self.logger.info(self.vapi.cli("sh ip fib 11.0.0.1"))
1268         self.logger.info(self.vapi.cli("sh ip6 fib ::/0"))
1269         self.logger.info(self.vapi.cli("sh ip6 fib %s" %
1270                                        eps[0].fip6))
1271
1272         #
1273         # From an EP to an outside addess: IN2OUT
1274         #
1275         pkt_inter_epg_220_to_global = (Ether(src=self.pg0.remote_mac,
1276                                              dst=self.router_mac.address) /
1277                                        IP(src=eps[0].ip4.address,
1278                                           dst="1.1.1.1") /
1279                                        UDP(sport=1234, dport=1234) /
1280                                        Raw('\xa5' * 100))
1281
1282         # no policy yet
1283         self.send_and_assert_no_replies(eps[0].itf,
1284                                         pkt_inter_epg_220_to_global * 65)
1285
1286         acl2 = VppGbpAcl(self)
1287         rule = acl2.create_rule(permit_deny=1, proto=17, sport_from=1234,
1288                                 sport_to=1234, dport_from=1234, dport_to=1234)
1289         rule2 = acl2.create_rule(is_ipv6=1, permit_deny=1, proto=17,
1290                                  sport_from=1234, sport_to=1234,
1291                                  dport_from=1234, dport_to=1234)
1292
1293         acl_index2 = acl2.add_vpp_config([rule, rule2])
1294         c4 = VppGbpContract(
1295             self, 220, 333, acl_index2,
1296             [VppGbpContractRule(
1297                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1298                 []),
1299              VppGbpContractRule(
1300                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1301                  [])])
1302
1303         c4.add_vpp_config()
1304
1305         self.send_and_expect_natted(eps[0].itf,
1306                                     pkt_inter_epg_220_to_global * 65,
1307                                     self.pg7,
1308                                     eps[0].fip4.address)
1309
1310         pkt_inter_epg_220_to_global = (Ether(src=self.pg0.remote_mac,
1311                                              dst=self.router_mac.address) /
1312                                        IPv6(src=eps[0].ip6.address,
1313                                             dst="6001::1") /
1314                                        UDP(sport=1234, dport=1234) /
1315                                        Raw('\xa5' * 100))
1316
1317         self.send_and_expect_natted6(self.pg0,
1318                                      pkt_inter_epg_220_to_global * 65,
1319                                      self.pg7,
1320                                      eps[0].fip6.address)
1321
1322         #
1323         # From a global address to an EP: OUT2IN
1324         #
1325         pkt_inter_epg_220_from_global = (Ether(src=self.router_mac.address,
1326                                                dst=self.pg0.remote_mac) /
1327                                          IP(dst=eps[0].fip4.address,
1328                                             src="1.1.1.1") /
1329                                          UDP(sport=1234, dport=1234) /
1330                                          Raw('\xa5' * 100))
1331
1332         self.send_and_assert_no_replies(self.pg7,
1333                                         pkt_inter_epg_220_from_global * 65)
1334
1335         c5 = VppGbpContract(
1336             self, 333, 220, acl_index2,
1337             [VppGbpContractRule(
1338                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1339                 []),
1340              VppGbpContractRule(
1341                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1342                  [])])
1343
1344         c5.add_vpp_config()
1345
1346         self.send_and_expect_unnatted(self.pg7,
1347                                       pkt_inter_epg_220_from_global * 65,
1348                                       eps[0].itf,
1349                                       eps[0].ip4.address)
1350
1351         pkt_inter_epg_220_from_global = (Ether(src=self.router_mac.address,
1352                                                dst=self.pg0.remote_mac) /
1353                                          IPv6(dst=eps[0].fip6.address,
1354                                               src="6001::1") /
1355                                          UDP(sport=1234, dport=1234) /
1356                                          Raw('\xa5' * 100))
1357
1358         self.send_and_expect_unnatted6(self.pg7,
1359                                        pkt_inter_epg_220_from_global * 65,
1360                                        eps[0].itf,
1361                                        eps[0].ip6.address)
1362
1363         #
1364         # From a local VM to another local VM using resp. public addresses:
1365         #  IN2OUT2IN
1366         #
1367         pkt_intra_epg_220_global = (Ether(src=self.pg0.remote_mac,
1368                                           dst=self.router_mac.address) /
1369                                     IP(src=eps[0].ip4.address,
1370                                        dst=eps[1].fip4.address) /
1371                                     UDP(sport=1234, dport=1234) /
1372                                     Raw('\xa5' * 100))
1373
1374         self.send_and_expect_double_natted(eps[0].itf,
1375                                            pkt_intra_epg_220_global * 65,
1376                                            eps[1].itf,
1377                                            eps[0].fip4.address,
1378                                            eps[1].ip4.address)
1379
1380         pkt_intra_epg_220_global = (Ether(src=self.pg0.remote_mac,
1381                                           dst=self.router_mac.address) /
1382                                     IPv6(src=eps[0].ip6.address,
1383                                          dst=eps[1].fip6.address) /
1384                                     UDP(sport=1234, dport=1234) /
1385                                     Raw('\xa5' * 100))
1386
1387         self.send_and_expect_double_natted6(eps[0].itf,
1388                                             pkt_intra_epg_220_global * 65,
1389                                             eps[1].itf,
1390                                             eps[0].fip6.address,
1391                                             eps[1].ip6.address)
1392
1393         #
1394         # cleanup
1395         #
1396         for ep in eps:
1397             # del static mappings for each EP from the 10/8 to 11/8 network
1398             self.vapi.nat44_add_del_static_mapping(ep.ip4.bytes,
1399                                                    ep.fip4.bytes,
1400                                                    vrf_id=0,
1401                                                    addr_only=1,
1402                                                    is_add=0)
1403             self.vapi.nat66_add_del_static_mapping(ep.ip6.bytes,
1404                                                    ep.fip6.bytes,
1405                                                    vrf_id=0,
1406                                                    is_add=0)
1407
1408         for epg in epgs:
1409             # IP config on the BVI interfaces
1410             if epg != epgs[0] and epg != epgs[3]:
1411                 self.vapi.nat44_interface_add_del_feature(epg.bvi.sw_if_index,
1412                                                           is_inside=1,
1413                                                           is_add=0)
1414                 self.vapi.nat66_add_del_interface(epg.bvi.sw_if_index,
1415                                                   is_inside=1,
1416                                                   is_add=0)
1417
1418         for recirc in recircs:
1419             self.vapi.nat44_interface_add_del_feature(
1420                 recirc.recirc.sw_if_index,
1421                 is_inside=0,
1422                 is_add=0)
1423             self.vapi.nat66_add_del_interface(
1424                 recirc.recirc.sw_if_index,
1425                 is_inside=0,
1426                 is_add=0)
1427
1428     def wait_for_ep_timeout(self, sw_if_index=None, ip=None, mac=None,
1429                             n_tries=100, s_time=1):
1430         while (n_tries):
1431             if not find_gbp_endpoint(self, sw_if_index, ip, mac):
1432                 return True
1433             n_tries = n_tries - 1
1434             self.sleep(s_time)
1435         self.assertFalse(find_gbp_endpoint(self, sw_if_index, ip, mac))
1436         return False
1437
1438     def test_gbp_learn_l2(self):
1439         """ GBP L2 Endpoint Learning """
1440
1441         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
1442         learnt = [{'mac': '00:00:11:11:11:01',
1443                    'ip': '10.0.0.1',
1444                    'ip6': '2001:10::2'},
1445                   {'mac': '00:00:11:11:11:02',
1446                    'ip': '10.0.0.2',
1447                    'ip6': '2001:10::3'}]
1448
1449         #
1450         # lower the inactive threshold so these tests pass in a
1451         # reasonable amount of time
1452         #
1453         self.vapi.gbp_endpoint_learn_set_inactive_threshold(1)
1454
1455         #
1456         # IP tables
1457         #
1458         gt4 = VppIpTable(self, 1)
1459         gt4.add_vpp_config()
1460         gt6 = VppIpTable(self, 1, is_ip6=True)
1461         gt6.add_vpp_config()
1462
1463         rd1 = VppGbpRouteDomain(self, 1, gt4, gt6)
1464         rd1.add_vpp_config()
1465
1466         #
1467         # Pg2 hosts the vxlan tunnel, hosts on pg2 to act as TEPs
1468         # Pg3 hosts the IP4 UU-flood VXLAN tunnel
1469         # Pg4 hosts the IP6 UU-flood VXLAN tunnel
1470         #
1471         self.pg2.config_ip4()
1472         self.pg2.resolve_arp()
1473         self.pg2.generate_remote_hosts(4)
1474         self.pg2.configure_ipv4_neighbors()
1475         self.pg3.config_ip4()
1476         self.pg3.resolve_arp()
1477         self.pg4.config_ip4()
1478         self.pg4.resolve_arp()
1479
1480         #
1481         # a GBP bridge domain with a BVI and a UU-flood interface
1482         #
1483         bd1 = VppBridgeDomain(self, 1)
1484         bd1.add_vpp_config()
1485         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0, self.pg3)
1486         gbd1.add_vpp_config()
1487
1488         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1489         self.logger.info(self.vapi.cli("sh gbp bridge"))
1490
1491         # ... and has a /32 applied
1492         ip_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
1493         ip_addr.add_vpp_config()
1494
1495         #
1496         # The Endpoint-group in which we are learning endpoints
1497         #
1498         epg_220 = VppGbpEndpointGroup(self, 220, rd1, gbd1,
1499                                       None, self.loop0,
1500                                       "10.0.0.128",
1501                                       "2001:10::128")
1502         epg_220.add_vpp_config()
1503         epg_330 = VppGbpEndpointGroup(self, 330, rd1, gbd1,
1504                                       None, self.loop1,
1505                                       "10.0.1.128",
1506                                       "2001:11::128")
1507         epg_330.add_vpp_config()
1508
1509         #
1510         # The VXLAN GBP tunnel is a bridge-port and has L2 endpoint
1511         # leanring enabled
1512         #
1513         vx_tun_l2_1 = VppGbpVxlanTunnel(
1514             self, 99, bd1.bd_id,
1515             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L2)
1516         vx_tun_l2_1.add_vpp_config()
1517
1518         #
1519         # A static endpoint that the learnt endpoints are trying to
1520         # talk to
1521         #
1522         ep = VppGbpEndpoint(self, self.pg0,
1523                             epg_220, None,
1524                             "10.0.0.127", "11.0.0.127",
1525                             "2001:10::1", "3001::1")
1526         ep.add_vpp_config()
1527
1528         self.assertTrue(find_route(self, ep.ip4.address, 32, table_id=1))
1529
1530         # a packet with an sclass from an unknwon EPG
1531         p = (Ether(src=self.pg2.remote_mac,
1532                    dst=self.pg2.local_mac) /
1533              IP(src=self.pg2.remote_hosts[0].ip4,
1534                 dst=self.pg2.local_ip4) /
1535              UDP(sport=1234, dport=48879) /
1536              VXLAN(vni=99, gpid=88, flags=0x88) /
1537              Ether(src=learnt[0]["mac"], dst=ep.mac) /
1538              IP(src=learnt[0]["ip"], dst=ep.ip4.address) /
1539              UDP(sport=1234, dport=1234) /
1540              Raw('\xa5' * 100))
1541
1542         self.send_and_assert_no_replies(self.pg2, p)
1543
1544         #
1545         # we should not have learnt a new tunnel endpoint, since
1546         # the EPG was not learnt.
1547         #
1548         self.assertEqual(INDEX_INVALID,
1549                          find_vxlan_gbp_tunnel(self,
1550                                                self.pg2.local_ip4,
1551                                                self.pg2.remote_hosts[0].ip4,
1552                                                99))
1553
1554         # epg is not learnt, becasue the EPG is unknwon
1555         self.assertEqual(len(self.vapi.gbp_endpoint_dump()), 1)
1556
1557         for ii, l in enumerate(learnt):
1558             # a packet with an sclass from a knwon EPG
1559             # arriving on an unknown TEP
1560             p = (Ether(src=self.pg2.remote_mac,
1561                        dst=self.pg2.local_mac) /
1562                  IP(src=self.pg2.remote_hosts[1].ip4,
1563                     dst=self.pg2.local_ip4) /
1564                  UDP(sport=1234, dport=48879) /
1565                  VXLAN(vni=99, gpid=220, flags=0x88) /
1566                  Ether(src=l['mac'], dst=ep.mac) /
1567                  IP(src=l['ip'], dst=ep.ip4.address) /
1568                  UDP(sport=1234, dport=1234) /
1569                  Raw('\xa5' * 100))
1570
1571             rx = self.send_and_expect(self.pg2, [p], self.pg0)
1572
1573             # the new TEP
1574             tep1_sw_if_index = find_vxlan_gbp_tunnel(
1575                 self,
1576                 self.pg2.local_ip4,
1577                 self.pg2.remote_hosts[1].ip4,
1578                 99)
1579             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
1580
1581             #
1582             # the EP is learnt via the learnt TEP
1583             # both from its MAC and its IP
1584             #
1585             self.assertTrue(find_gbp_endpoint(self,
1586                                               vx_tun_l2_1.sw_if_index,
1587                                               mac=l['mac']))
1588             self.assertTrue(find_gbp_endpoint(self,
1589                                               vx_tun_l2_1.sw_if_index,
1590                                               ip=l['ip']))
1591
1592         self.logger.info(self.vapi.cli("show gbp endpoint"))
1593         self.logger.info(self.vapi.cli("show gbp vxlan"))
1594         self.logger.info(self.vapi.cli("show vxlan-gbp tunnel"))
1595
1596         #
1597         # If we sleep for the threshold time, the learnt endpoints should
1598         # age out
1599         #
1600         for l in learnt:
1601             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
1602                                      mac=l['mac'])
1603
1604         #
1605         # repeat. the do not learn bit is set so the EPs are not learnt
1606         #
1607         for l in learnt:
1608             # a packet with an sclass from a knwon EPG
1609             p = (Ether(src=self.pg2.remote_mac,
1610                        dst=self.pg2.local_mac) /
1611                  IP(src=self.pg2.remote_hosts[1].ip4,
1612                     dst=self.pg2.local_ip4) /
1613                  UDP(sport=1234, dport=48879) /
1614                  VXLAN(vni=99, gpid=220, flags=0x88, gpflags="D") /
1615                  Ether(src=l['mac'], dst=ep.mac) /
1616                  IP(src=l['ip'], dst=ep.ip4.address) /
1617                  UDP(sport=1234, dport=1234) /
1618                  Raw('\xa5' * 100))
1619
1620             rx = self.send_and_expect(self.pg2, p*65, self.pg0)
1621
1622         for l in learnt:
1623             self.assertFalse(find_gbp_endpoint(self,
1624                                                vx_tun_l2_1.sw_if_index,
1625                                                mac=l['mac']))
1626
1627         #
1628         # repeat
1629         #
1630         for l in learnt:
1631             # a packet with an sclass from a knwon EPG
1632             p = (Ether(src=self.pg2.remote_mac,
1633                        dst=self.pg2.local_mac) /
1634                  IP(src=self.pg2.remote_hosts[1].ip4,
1635                     dst=self.pg2.local_ip4) /
1636                  UDP(sport=1234, dport=48879) /
1637                  VXLAN(vni=99, gpid=220, flags=0x88) /
1638                  Ether(src=l['mac'], dst=ep.mac) /
1639                  IP(src=l['ip'], dst=ep.ip4.address) /
1640                  UDP(sport=1234, dport=1234) /
1641                  Raw('\xa5' * 100))
1642
1643             rx = self.send_and_expect(self.pg2, p*65, self.pg0)
1644
1645             self.assertTrue(find_gbp_endpoint(self,
1646                                               vx_tun_l2_1.sw_if_index,
1647                                               mac=l['mac']))
1648
1649         #
1650         # Static EP replies to dynamics
1651         #
1652         self.logger.info(self.vapi.cli("sh l2fib bd_id 1"))
1653         for l in learnt:
1654             p = (Ether(src=ep.mac, dst=l['mac']) /
1655                  IP(dst=l['ip'], src=ep.ip4.address) /
1656                  UDP(sport=1234, dport=1234) /
1657                  Raw('\xa5' * 100))
1658
1659             rxs = self.send_and_expect(self.pg0, p * 17, self.pg2)
1660
1661             for rx in rxs:
1662                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
1663                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
1664                 self.assertEqual(rx[UDP].dport, 48879)
1665                 # the UDP source port is a random value for hashing
1666                 self.assertEqual(rx[VXLAN].gpid, 220)
1667                 self.assertEqual(rx[VXLAN].vni, 99)
1668                 self.assertTrue(rx[VXLAN].flags.G)
1669                 self.assertTrue(rx[VXLAN].flags.Instance)
1670                 self.assertTrue(rx[VXLAN].gpflags.A)
1671                 self.assertFalse(rx[VXLAN].gpflags.D)
1672
1673         for l in learnt:
1674             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
1675                                      mac=l['mac'])
1676
1677         #
1678         # repeat in the other EPG
1679         # there's no contract between 220 and 330, but the A-bit is set
1680         # so the packet is cleared for delivery
1681         #
1682         for l in learnt:
1683             # a packet with an sclass from a knwon EPG
1684             p = (Ether(src=self.pg2.remote_mac,
1685                        dst=self.pg2.local_mac) /
1686                  IP(src=self.pg2.remote_hosts[1].ip4,
1687                     dst=self.pg2.local_ip4) /
1688                  UDP(sport=1234, dport=48879) /
1689                  VXLAN(vni=99, gpid=330, flags=0x88, gpflags='A') /
1690                  Ether(src=l['mac'], dst=ep.mac) /
1691                  IP(src=l['ip'], dst=ep.ip4.address) /
1692                  UDP(sport=1234, dport=1234) /
1693                  Raw('\xa5' * 100))
1694
1695             rx = self.send_and_expect(self.pg2, p*65, self.pg0)
1696
1697             self.assertTrue(find_gbp_endpoint(self,
1698                                               vx_tun_l2_1.sw_if_index,
1699                                               mac=l['mac']))
1700
1701         #
1702         # static EP cannot reach the learnt EPs since there is no contract
1703         # only test 1 EP as the others could timeout
1704         #
1705         p = (Ether(src=ep.mac, dst=l['mac']) /
1706              IP(dst=learnt[0]['ip'], src=ep.ip4.address) /
1707              UDP(sport=1234, dport=1234) /
1708              Raw('\xa5' * 100))
1709
1710         self.send_and_assert_no_replies(self.pg0, [p])
1711
1712         #
1713         # refresh the entries after the check for no replies above
1714         #
1715         for l in learnt:
1716             # a packet with an sclass from a knwon EPG
1717             p = (Ether(src=self.pg2.remote_mac,
1718                        dst=self.pg2.local_mac) /
1719                  IP(src=self.pg2.remote_hosts[1].ip4,
1720                     dst=self.pg2.local_ip4) /
1721                  UDP(sport=1234, dport=48879) /
1722                  VXLAN(vni=99, gpid=330, flags=0x88, gpflags='A') /
1723                  Ether(src=l['mac'], dst=ep.mac) /
1724                  IP(src=l['ip'], dst=ep.ip4.address) /
1725                  UDP(sport=1234, dport=1234) /
1726                  Raw('\xa5' * 100))
1727
1728             rx = self.send_and_expect(self.pg2, p*65, self.pg0)
1729
1730             self.assertTrue(find_gbp_endpoint(self,
1731                                               vx_tun_l2_1.sw_if_index,
1732                                               mac=l['mac']))
1733
1734         #
1735         # Add the contract so they can talk
1736         #
1737         acl = VppGbpAcl(self)
1738         rule = acl.create_rule(permit_deny=1, proto=17)
1739         rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
1740         acl_index = acl.add_vpp_config([rule, rule2])
1741         c1 = VppGbpContract(
1742             self, 220, 330, acl_index,
1743             [VppGbpContractRule(
1744                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1745                 []),
1746              VppGbpContractRule(
1747                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1748                  [])])
1749
1750         c1.add_vpp_config()
1751
1752         for l in learnt:
1753             p = (Ether(src=ep.mac, dst=l['mac']) /
1754                  IP(dst=l['ip'], src=ep.ip4.address) /
1755                  UDP(sport=1234, dport=1234) /
1756                  Raw('\xa5' * 100))
1757
1758             self.send_and_expect(self.pg0, [p], self.pg2)
1759
1760         #
1761         # send UU packets from the local EP
1762         #
1763         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1764         self.logger.info(self.vapi.cli("sh gbp bridge"))
1765         p_uu = (Ether(src=ep.mac, dst="00:11:11:11:11:11") /
1766                 IP(dst="10.0.0.133", src=ep.ip4.address) /
1767                 UDP(sport=1234, dport=1234) /
1768                 Raw('\xa5' * 100))
1769         rxs = self.send_and_expect(ep.itf, [p_uu], gbd1.uu_flood)
1770
1771         #
1772         # Add a mcast destination VXLAN-GBP tunnel for B&M traffic
1773         #
1774         tun_bm = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
1775                                    "239.1.1.1", 88,
1776                                    mcast_itf=self.pg4)
1777         tun_bm.add_vpp_config()
1778         bp_bm = VppBridgeDomainPort(self, bd1, tun_bm,
1779                                     port_type=L2_PORT_TYPE.NORMAL)
1780         bp_bm.add_vpp_config()
1781
1782         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1783
1784         p_bm = (Ether(src=ep.mac, dst="ff:ff:ff:ff:ff:ff") /
1785                 IP(dst="10.0.0.133", src=ep.ip4.address) /
1786                 UDP(sport=1234, dport=1234) /
1787                 Raw('\xa5' * 100))
1788         rxs = self.send_and_expect_only(ep.itf, [p_bm], tun_bm.mcast_itf)
1789
1790         #
1791         # Check v6 Endpoints
1792         #
1793         for l in learnt:
1794             # a packet with an sclass from a knwon EPG
1795             p = (Ether(src=self.pg2.remote_mac,
1796                        dst=self.pg2.local_mac) /
1797                  IP(src=self.pg2.remote_hosts[1].ip4,
1798                     dst=self.pg2.local_ip4) /
1799                  UDP(sport=1234, dport=48879) /
1800                  VXLAN(vni=99, gpid=330, flags=0x88, gpflags='A') /
1801                  Ether(src=l['mac'], dst=ep.mac) /
1802                  IPv6(src=l['ip6'], dst=ep.ip6.address) /
1803                  UDP(sport=1234, dport=1234) /
1804                  Raw('\xa5' * 100))
1805
1806             rx = self.send_and_expect(self.pg2, p*65, self.pg0)
1807
1808             self.assertTrue(find_gbp_endpoint(self,
1809                                               vx_tun_l2_1.sw_if_index,
1810                                               mac=l['mac']))
1811
1812         #
1813         # L3 Endpoint Learning
1814         #  - configured on the bridge's BVI
1815         #
1816
1817         #
1818         # clean up
1819         #
1820         for l in learnt:
1821             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
1822                                      mac=l['mac'])
1823
1824         self.pg2.unconfig_ip4()
1825         self.pg3.unconfig_ip4()
1826         self.pg4.unconfig_ip4()
1827
1828         self.logger.info(self.vapi.cli("sh int"))
1829         self.logger.info(self.vapi.cli("sh gbp vxlan"))
1830
1831     @unittest.skipIf(is_skip_aarch64_set() and is_platform_aarch64(),
1832                      "test doesn't work on aarch64")
1833     def test_gbp_learn_vlan_l2(self):
1834         """ GBP L2 Endpoint w/ VLANs"""
1835
1836         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
1837         learnt = [{'mac': '00:00:11:11:11:01',
1838                    'ip': '10.0.0.1',
1839                    'ip6': '2001:10::2'},
1840                   {'mac': '00:00:11:11:11:02',
1841                    'ip': '10.0.0.2',
1842                    'ip6': '2001:10::3'}]
1843
1844         #
1845         # lower the inactive threshold so these tests pass in a
1846         # reasonable amount of time
1847         #
1848         self.vapi.gbp_endpoint_learn_set_inactive_threshold(1)
1849
1850         #
1851         # IP tables
1852         #
1853         gt4 = VppIpTable(self, 1)
1854         gt4.add_vpp_config()
1855         gt6 = VppIpTable(self, 1, is_ip6=True)
1856         gt6.add_vpp_config()
1857
1858         rd1 = VppGbpRouteDomain(self, 1, gt4, gt6)
1859         rd1.add_vpp_config()
1860
1861         #
1862         # Pg2 hosts the vxlan tunnel, hosts on pg2 to act as TEPs
1863         #
1864         self.pg2.config_ip4()
1865         self.pg2.resolve_arp()
1866         self.pg2.generate_remote_hosts(4)
1867         self.pg2.configure_ipv4_neighbors()
1868         self.pg3.config_ip4()
1869         self.pg3.resolve_arp()
1870
1871         #
1872         # The EP will be on a vlan sub-interface
1873         #
1874         vlan_11 = VppDot1QSubint(self, self.pg0, 11)
1875         vlan_11.admin_up()
1876         self.vapi.sw_interface_set_l2_tag_rewrite(vlan_11.sw_if_index,
1877                                                   L2_VTR_OP.L2_POP_1,
1878                                                   11)
1879
1880         bd_uu_fwd = VppVxlanGbpTunnel(self, self.pg3.local_ip4,
1881                                       self.pg3.remote_ip4, 116)
1882         bd_uu_fwd.add_vpp_config()
1883
1884         #
1885         # a GBP bridge domain with a BVI and a UU-flood interface
1886         # The BD is marked as do not learn, so no endpoints are ever
1887         # learnt in this BD.
1888         #
1889         bd1 = VppBridgeDomain(self, 1)
1890         bd1.add_vpp_config()
1891         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0, bd_uu_fwd,
1892                                   learn=False)
1893         gbd1.add_vpp_config()
1894
1895         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1896         self.logger.info(self.vapi.cli("sh gbp bridge"))
1897
1898         # ... and has a /32 applied
1899         ip_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
1900         ip_addr.add_vpp_config()
1901
1902         #
1903         # The Endpoint-group in which we are learning endpoints
1904         #
1905         epg_220 = VppGbpEndpointGroup(self, 220, rd1, gbd1,
1906                                       None, self.loop0,
1907                                       "10.0.0.128",
1908                                       "2001:10::128")
1909         epg_220.add_vpp_config()
1910
1911         #
1912         # The VXLAN GBP tunnel is a bridge-port and has L2 endpoint
1913         # leanring enabled
1914         #
1915         vx_tun_l2_1 = VppGbpVxlanTunnel(
1916             self, 99, bd1.bd_id,
1917             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L2)
1918         vx_tun_l2_1.add_vpp_config()
1919
1920         #
1921         # A static endpoint that the learnt endpoints are trying to
1922         # talk to
1923         #
1924         ep = VppGbpEndpoint(self, vlan_11,
1925                             epg_220, None,
1926                             "10.0.0.127", "11.0.0.127",
1927                             "2001:10::1", "3001::1")
1928         ep.add_vpp_config()
1929
1930         self.assertTrue(find_route(self, ep.ip4.address, 32, table_id=1))
1931
1932         #
1933         # Send to the static EP
1934         #
1935         for ii, l in enumerate(learnt):
1936             # a packet with an sclass from a knwon EPG
1937             # arriving on an unknown TEP
1938             p = (Ether(src=self.pg2.remote_mac,
1939                        dst=self.pg2.local_mac) /
1940                  IP(src=self.pg2.remote_hosts[1].ip4,
1941                     dst=self.pg2.local_ip4) /
1942                  UDP(sport=1234, dport=48879) /
1943                  VXLAN(vni=99, gpid=220, flags=0x88) /
1944                  Ether(src=l['mac'], dst=ep.mac) /
1945                  IP(src=l['ip'], dst=ep.ip4.address) /
1946                  UDP(sport=1234, dport=1234) /
1947                  Raw('\xa5' * 100))
1948
1949             rxs = self.send_and_expect(self.pg2, [p], self.pg0)
1950
1951             #
1952             # packet to EP has the EP's vlan tag
1953             #
1954             for rx in rxs:
1955                 self.assertEqual(rx[Dot1Q].vlan, 11)
1956
1957             #
1958             # the EP is not learnt since the BD setting prevents it
1959             # also no TEP too
1960             #
1961             self.assertFalse(find_gbp_endpoint(self,
1962                                                vx_tun_l2_1.sw_if_index,
1963                                                mac=l['mac']))
1964             self.assertEqual(INDEX_INVALID,
1965                              find_vxlan_gbp_tunnel(
1966                                  self,
1967                                  self.pg2.local_ip4,
1968                                  self.pg2.remote_hosts[1].ip4,
1969                                  99))
1970
1971         self.assertEqual(len(self.vapi.gbp_endpoint_dump()), 1)
1972
1973         #
1974         # static to remotes
1975         # we didn't learn the remotes so they are sent to the UU-fwd
1976         #
1977         for l in learnt:
1978             p = (Ether(src=ep.mac, dst=l['mac']) /
1979                  Dot1Q(vlan=11) /
1980                  IP(dst=l['ip'], src=ep.ip4.address) /
1981                  UDP(sport=1234, dport=1234) /
1982                  Raw('\xa5' * 100))
1983
1984             rxs = self.send_and_expect(self.pg0, p * 17, self.pg3)
1985
1986             for rx in rxs:
1987                 self.assertEqual(rx[IP].src, self.pg3.local_ip4)
1988                 self.assertEqual(rx[IP].dst, self.pg3.remote_ip4)
1989                 self.assertEqual(rx[UDP].dport, 48879)
1990                 # the UDP source port is a random value for hashing
1991                 self.assertEqual(rx[VXLAN].gpid, 220)
1992                 self.assertEqual(rx[VXLAN].vni, 116)
1993                 self.assertTrue(rx[VXLAN].flags.G)
1994                 self.assertTrue(rx[VXLAN].flags.Instance)
1995                 self.assertFalse(rx[VXLAN].gpflags.A)
1996                 self.assertFalse(rx[VXLAN].gpflags.D)
1997
1998         self.pg2.unconfig_ip4()
1999         self.pg3.unconfig_ip4()
2000
2001     @unittest.skipIf(is_skip_aarch64_set() and is_platform_aarch64(),
2002                      "test doesn't work on aarch64")
2003     def test_gbp_learn_l3(self):
2004         """ GBP L3 Endpoint Learning """
2005
2006         self.vapi.cli("set logging class gbp debug")
2007
2008         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
2009         routed_dst_mac = "00:0c:0c:0c:0c:0c"
2010         routed_src_mac = "00:22:bd:f8:19:ff"
2011
2012         learnt = [{'mac': '00:00:11:11:11:02',
2013                    'ip': '10.0.1.2',
2014                    'ip6': '2001:10::2'},
2015                   {'mac': '00:00:11:11:11:03',
2016                    'ip': '10.0.1.3',
2017                    'ip6': '2001:10::3'}]
2018
2019         #
2020         # lower the inactive threshold so these tests pass in a
2021         # reasonable amount of time
2022         #
2023         self.vapi.gbp_endpoint_learn_set_inactive_threshold(1)
2024
2025         #
2026         # IP tables
2027         #
2028         t4 = VppIpTable(self, 1)
2029         t4.add_vpp_config()
2030         t6 = VppIpTable(self, 1, True)
2031         t6.add_vpp_config()
2032
2033         tun_ip4_uu = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
2034                                        self.pg4.remote_ip4, 114)
2035         tun_ip6_uu = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
2036                                        self.pg4.remote_ip4, 116)
2037         tun_ip4_uu.add_vpp_config()
2038         tun_ip6_uu.add_vpp_config()
2039
2040         rd1 = VppGbpRouteDomain(self, 2, t4, t6, tun_ip4_uu, tun_ip6_uu)
2041         rd1.add_vpp_config()
2042
2043         self.loop0.set_mac(self.router_mac.address)
2044
2045         #
2046         # Bind the BVI to the RD
2047         #
2048         VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
2049         VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
2050
2051         #
2052         # Pg2 hosts the vxlan tunnel
2053         # hosts on pg2 to act as TEPs
2054         # pg3 is BD uu-fwd
2055         # pg4 is RD uu-fwd
2056         #
2057         self.pg2.config_ip4()
2058         self.pg2.resolve_arp()
2059         self.pg2.generate_remote_hosts(4)
2060         self.pg2.configure_ipv4_neighbors()
2061         self.pg3.config_ip4()
2062         self.pg3.resolve_arp()
2063         self.pg4.config_ip4()
2064         self.pg4.resolve_arp()
2065
2066         #
2067         # a GBP bridge domain with a BVI and a UU-flood interface
2068         #
2069         bd1 = VppBridgeDomain(self, 1)
2070         bd1.add_vpp_config()
2071         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0, self.pg3)
2072         gbd1.add_vpp_config()
2073
2074         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
2075         self.logger.info(self.vapi.cli("sh gbp bridge"))
2076         self.logger.info(self.vapi.cli("sh gbp route"))
2077
2078         # ... and has a /32 and /128 applied
2079         ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
2080         ip4_addr.add_vpp_config()
2081         ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128", 128)
2082         ip6_addr.add_vpp_config()
2083
2084         #
2085         # The Endpoint-group in which we are learning endpoints
2086         #
2087         epg_220 = VppGbpEndpointGroup(self, 220, rd1, gbd1,
2088                                       None, self.loop0,
2089                                       "10.0.0.128",
2090                                       "2001:10::128")
2091         epg_220.add_vpp_config()
2092
2093         #
2094         # The VXLAN GBP tunnel is a bridge-port and has L2 endpoint
2095         # leanring enabled
2096         #
2097         vx_tun_l3 = VppGbpVxlanTunnel(
2098             self, 101, rd1.rd_id,
2099             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3)
2100         vx_tun_l3.add_vpp_config()
2101
2102         #
2103         # A static endpoint that the learnt endpoints are trying to
2104         # talk to
2105         #
2106         ep = VppGbpEndpoint(self, self.pg0,
2107                             epg_220, None,
2108                             "10.0.0.127", "11.0.0.127",
2109                             "2001:10::1", "3001::1")
2110         ep.add_vpp_config()
2111
2112         #
2113         # learn some remote IPv4 EPs
2114         #
2115         for ii, l in enumerate(learnt):
2116             # a packet with an sclass from a knwon EPG
2117             # arriving on an unknown TEP
2118             p = (Ether(src=self.pg2.remote_mac,
2119                        dst=self.pg2.local_mac) /
2120                  IP(src=self.pg2.remote_hosts[1].ip4,
2121                     dst=self.pg2.local_ip4) /
2122                  UDP(sport=1234, dport=48879) /
2123                  VXLAN(vni=101, gpid=220, flags=0x88) /
2124                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
2125                  IP(src=l['ip'], dst=ep.ip4.address) /
2126                  UDP(sport=1234, dport=1234) /
2127                  Raw('\xa5' * 100))
2128
2129             rx = self.send_and_expect(self.pg2, [p], self.pg0)
2130
2131             # the new TEP
2132             tep1_sw_if_index = find_vxlan_gbp_tunnel(
2133                 self,
2134                 self.pg2.local_ip4,
2135                 self.pg2.remote_hosts[1].ip4,
2136                 vx_tun_l3.vni)
2137             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
2138
2139             # endpoint learnt via the parent GBP-vxlan interface
2140             self.assertTrue(find_gbp_endpoint(self,
2141                                               vx_tun_l3._sw_if_index,
2142                                               ip=l['ip']))
2143
2144         #
2145         # Static IPv4 EP replies to learnt
2146         #
2147         for l in learnt:
2148             p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2149                  IP(dst=l['ip'], src=ep.ip4.address) /
2150                  UDP(sport=1234, dport=1234) /
2151                  Raw('\xa5' * 100))
2152
2153             rxs = self.send_and_expect(self.pg0, p*1, self.pg2)
2154
2155             for rx in rxs:
2156                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2157                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
2158                 self.assertEqual(rx[UDP].dport, 48879)
2159                 # the UDP source port is a random value for hashing
2160                 self.assertEqual(rx[VXLAN].gpid, 220)
2161                 self.assertEqual(rx[VXLAN].vni, 101)
2162                 self.assertTrue(rx[VXLAN].flags.G)
2163                 self.assertTrue(rx[VXLAN].flags.Instance)
2164                 self.assertTrue(rx[VXLAN].gpflags.A)
2165                 self.assertFalse(rx[VXLAN].gpflags.D)
2166
2167                 inner = rx[VXLAN].payload
2168
2169                 self.assertEqual(inner[Ether].src, routed_src_mac)
2170                 self.assertEqual(inner[Ether].dst, routed_dst_mac)
2171                 self.assertEqual(inner[IP].src, ep.ip4.address)
2172                 self.assertEqual(inner[IP].dst, l['ip'])
2173
2174         for l in learnt:
2175             self.assertFalse(find_gbp_endpoint(self,
2176                                                tep1_sw_if_index,
2177                                                ip=l['ip']))
2178
2179         #
2180         # learn some remote IPv6 EPs
2181         #
2182         for ii, l in enumerate(learnt):
2183             # a packet with an sclass from a knwon EPG
2184             # arriving on an unknown TEP
2185             p = (Ether(src=self.pg2.remote_mac,
2186                        dst=self.pg2.local_mac) /
2187                  IP(src=self.pg2.remote_hosts[1].ip4,
2188                     dst=self.pg2.local_ip4) /
2189                  UDP(sport=1234, dport=48879) /
2190                  VXLAN(vni=101, gpid=220, flags=0x88) /
2191                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
2192                  IPv6(src=l['ip6'], dst=ep.ip6.address) /
2193                  UDP(sport=1234, dport=1234) /
2194                  Raw('\xa5' * 100))
2195
2196             rx = self.send_and_expect(self.pg2, [p], self.pg0)
2197
2198             # the new TEP
2199             tep1_sw_if_index = find_vxlan_gbp_tunnel(
2200                 self,
2201                 self.pg2.local_ip4,
2202                 self.pg2.remote_hosts[1].ip4,
2203                 vx_tun_l3.vni)
2204             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
2205
2206             self.logger.info(self.vapi.cli("show gbp bridge"))
2207             self.logger.info(self.vapi.cli("show vxlan-gbp tunnel"))
2208             self.logger.info(self.vapi.cli("show gbp vxlan"))
2209             self.logger.info(self.vapi.cli("show int addr"))
2210
2211             # endpoint learnt via the TEP
2212             self.assertTrue(find_gbp_endpoint(self, ip=l['ip6']))
2213
2214         self.logger.info(self.vapi.cli("show gbp endpoint"))
2215         self.logger.info(self.vapi.cli("show ip fib index 1 %s" % l['ip']))
2216
2217         #
2218         # Static EP replies to learnt
2219         #
2220         for l in learnt:
2221             p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2222                  IPv6(dst=l['ip6'], src=ep.ip6.address) /
2223                  UDP(sport=1234, dport=1234) /
2224                  Raw('\xa5' * 100))
2225
2226             rxs = self.send_and_expect(self.pg0, p*65, self.pg2)
2227
2228             for rx in rxs:
2229                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2230                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
2231                 self.assertEqual(rx[UDP].dport, 48879)
2232                 # the UDP source port is a random value for hashing
2233                 self.assertEqual(rx[VXLAN].gpid, 220)
2234                 self.assertEqual(rx[VXLAN].vni, 101)
2235                 self.assertTrue(rx[VXLAN].flags.G)
2236                 self.assertTrue(rx[VXLAN].flags.Instance)
2237                 self.assertTrue(rx[VXLAN].gpflags.A)
2238                 self.assertFalse(rx[VXLAN].gpflags.D)
2239
2240                 inner = rx[VXLAN].payload
2241
2242                 self.assertEqual(inner[Ether].src, routed_src_mac)
2243                 self.assertEqual(inner[Ether].dst, routed_dst_mac)
2244                 self.assertEqual(inner[IPv6].src, ep.ip6.address)
2245                 self.assertEqual(inner[IPv6].dst, l['ip6'])
2246
2247         self.logger.info(self.vapi.cli("sh gbp endpoint"))
2248         for l in learnt:
2249             self.wait_for_ep_timeout(ip=l['ip'])
2250
2251         #
2252         # Static sends to unknown EP with no route
2253         #
2254         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2255              IP(dst="10.0.0.99", src=ep.ip4.address) /
2256              UDP(sport=1234, dport=1234) /
2257              Raw('\xa5' * 100))
2258
2259         self.send_and_assert_no_replies(self.pg0, [p])
2260
2261         #
2262         # Add a route to static EP's v4 and v6 subnet
2263         #  packets should be sent on the v4/v6 uu=fwd interface resp.
2264         #
2265         se_10_24 = VppGbpSubnet(
2266             self, rd1, "10.0.0.0", 24,
2267             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_TRANSPORT)
2268         se_10_24.add_vpp_config()
2269
2270         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2271              IP(dst="10.0.0.99", src=ep.ip4.address) /
2272              UDP(sport=1234, dport=1234) /
2273              Raw('\xa5' * 100))
2274
2275         rxs = self.send_and_expect(self.pg0, [p], self.pg4)
2276         for rx in rxs:
2277             self.assertEqual(rx[IP].src, self.pg4.local_ip4)
2278             self.assertEqual(rx[IP].dst, self.pg4.remote_ip4)
2279             self.assertEqual(rx[UDP].dport, 48879)
2280             # the UDP source port is a random value for hashing
2281             self.assertEqual(rx[VXLAN].gpid, 220)
2282             self.assertEqual(rx[VXLAN].vni, 114)
2283             self.assertTrue(rx[VXLAN].flags.G)
2284             self.assertTrue(rx[VXLAN].flags.Instance)
2285             # policy is not applied to packets sent to the uu-fwd interfaces
2286             self.assertFalse(rx[VXLAN].gpflags.A)
2287             self.assertFalse(rx[VXLAN].gpflags.D)
2288
2289         #
2290         # learn some remote IPv4 EPs
2291         #
2292         for ii, l in enumerate(learnt):
2293             # a packet with an sclass from a knwon EPG
2294             # arriving on an unknown TEP
2295             p = (Ether(src=self.pg2.remote_mac,
2296                        dst=self.pg2.local_mac) /
2297                  IP(src=self.pg2.remote_hosts[1].ip4,
2298                     dst=self.pg2.local_ip4) /
2299                  UDP(sport=1234, dport=48879) /
2300                  VXLAN(vni=101, gpid=220, flags=0x88) /
2301                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
2302                  IP(src=l['ip'], dst=ep.ip4.address) /
2303                  UDP(sport=1234, dport=1234) /
2304                  Raw('\xa5' * 100))
2305
2306             rx = self.send_and_expect(self.pg2, [p], self.pg0)
2307
2308             # the new TEP
2309             tep1_sw_if_index = find_vxlan_gbp_tunnel(
2310                 self,
2311                 self.pg2.local_ip4,
2312                 self.pg2.remote_hosts[1].ip4,
2313                 vx_tun_l3.vni)
2314             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
2315
2316             # endpoint learnt via the parent GBP-vxlan interface
2317             self.assertTrue(find_gbp_endpoint(self,
2318                                               vx_tun_l3._sw_if_index,
2319                                               ip=l['ip']))
2320
2321         #
2322         # Add a remote endpoint from the API
2323         #
2324         rep_88 = VppGbpEndpoint(self, vx_tun_l3,
2325                                 epg_220, None,
2326                                 "10.0.0.88", "11.0.0.88",
2327                                 "2001:10::88", "3001::88",
2328                                 ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
2329                                 self.pg2.local_ip4,
2330                                 self.pg2.remote_hosts[1].ip4,
2331                                 mac=None)
2332         rep_88.add_vpp_config()
2333
2334         #
2335         # Add a remote endpoint from the API that matches an existing one
2336         #
2337         rep_2 = VppGbpEndpoint(self, vx_tun_l3,
2338                                epg_220, None,
2339                                learnt[0]['ip'], "11.0.0.101",
2340                                learnt[0]['ip6'], "3001::101",
2341                                ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
2342                                self.pg2.local_ip4,
2343                                self.pg2.remote_hosts[1].ip4,
2344                                mac=None)
2345         rep_2.add_vpp_config()
2346
2347         #
2348         # Add a route to the leanred EP's v4 subnet
2349         #  packets should be send on the v4/v6 uu=fwd interface resp.
2350         #
2351         se_10_1_24 = VppGbpSubnet(
2352             self, rd1, "10.0.1.0", 24,
2353             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_TRANSPORT)
2354         se_10_1_24.add_vpp_config()
2355
2356         self.logger.info(self.vapi.cli("show gbp endpoint"))
2357
2358         ips = ["10.0.0.88", learnt[0]['ip']]
2359         for ip in ips:
2360             p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2361                  IP(dst=ip, src=ep.ip4.address) /
2362                  UDP(sport=1234, dport=1234) /
2363                  Raw('\xa5' * 100))
2364
2365             rxs = self.send_and_expect(self.pg0, p*65, self.pg2)
2366
2367             for rx in rxs:
2368                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2369                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
2370                 self.assertEqual(rx[UDP].dport, 48879)
2371                 # the UDP source port is a random value for hashing
2372                 self.assertEqual(rx[VXLAN].gpid, 220)
2373                 self.assertEqual(rx[VXLAN].vni, 101)
2374                 self.assertTrue(rx[VXLAN].flags.G)
2375                 self.assertTrue(rx[VXLAN].flags.Instance)
2376                 self.assertTrue(rx[VXLAN].gpflags.A)
2377                 self.assertFalse(rx[VXLAN].gpflags.D)
2378
2379                 inner = rx[VXLAN].payload
2380
2381                 self.assertEqual(inner[Ether].src, routed_src_mac)
2382                 self.assertEqual(inner[Ether].dst, routed_dst_mac)
2383                 self.assertEqual(inner[IP].src, ep.ip4.address)
2384                 self.assertEqual(inner[IP].dst, ip)
2385
2386         #
2387         # remove the API remote EPs, only API sourced is gone, the DP
2388         # learnt one remains
2389         #
2390         rep_88.remove_vpp_config()
2391         rep_2.remove_vpp_config()
2392
2393         self.logger.info(self.vapi.cli("show gbp endpoint"))
2394
2395         self.assertFalse(find_gbp_endpoint(self, ip=rep_88.ip4.address))
2396
2397         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2398              IP(src=ep.ip4.address, dst=rep_88.ip4.address) /
2399              UDP(sport=1234, dport=1234) /
2400              Raw('\xa5' * 100))
2401         rxs = self.send_and_expect(self.pg0, [p], self.pg4)
2402
2403         self.assertTrue(find_gbp_endpoint(self, ip=rep_2.ip4.address))
2404
2405         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2406              IP(src=ep.ip4.address, dst=rep_2.ip4.address) /
2407              UDP(sport=1234, dport=1234) /
2408              Raw('\xa5' * 100))
2409         rxs = self.send_and_expect(self.pg0, [p], self.pg2)
2410
2411         #
2412         # to appease the testcase we cannot have the registered EP stll
2413         # present (because it's DP learnt) when the TC ends so wait until
2414         # it is removed
2415         #
2416         self.sleep(2)
2417
2418         #
2419         # shutdown with learnt endpoint present
2420         #
2421         p = (Ether(src=self.pg2.remote_mac,
2422                    dst=self.pg2.local_mac) /
2423              IP(src=self.pg2.remote_hosts[1].ip4,
2424                 dst=self.pg2.local_ip4) /
2425              UDP(sport=1234, dport=48879) /
2426              VXLAN(vni=101, gpid=220, flags=0x88) /
2427              Ether(src=l['mac'], dst="00:00:00:11:11:11") /
2428              IP(src=learnt[1]['ip'], dst=ep.ip4.address) /
2429              UDP(sport=1234, dport=1234) /
2430              Raw('\xa5' * 100))
2431
2432         rx = self.send_and_expect(self.pg2, [p], self.pg0)
2433
2434         # endpoint learnt via the parent GBP-vxlan interface
2435         self.assertTrue(find_gbp_endpoint(self,
2436                                           vx_tun_l3._sw_if_index,
2437                                           ip=l['ip']))
2438
2439         #
2440         # TODO
2441         # remote endpoint becomes local
2442         #
2443         self.pg2.unconfig_ip4()
2444         self.pg3.unconfig_ip4()
2445         self.pg4.unconfig_ip4()
2446
2447     def test_gbp_redirect(self):
2448         """ GBP Endpoint Redirect """
2449
2450         self.vapi.cli("set logging class gbp debug")
2451
2452         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
2453         routed_dst_mac = "00:0c:0c:0c:0c:0c"
2454         routed_src_mac = "00:22:bd:f8:19:ff"
2455
2456         learnt = [{'mac': '00:00:11:11:11:02',
2457                    'ip': '10.0.1.2',
2458                    'ip6': '2001:10::2'},
2459                   {'mac': '00:00:11:11:11:03',
2460                    'ip': '10.0.1.3',
2461                    'ip6': '2001:10::3'}]
2462
2463         #
2464         # lower the inactive threshold so these tests pass in a
2465         # reasonable amount of time
2466         #
2467         self.vapi.gbp_endpoint_learn_set_inactive_threshold(1)
2468
2469         #
2470         # IP tables
2471         #
2472         t4 = VppIpTable(self, 1)
2473         t4.add_vpp_config()
2474         t6 = VppIpTable(self, 1, True)
2475         t6.add_vpp_config()
2476
2477         rd1 = VppGbpRouteDomain(self, 2, t4, t6)
2478         rd1.add_vpp_config()
2479
2480         self.loop0.set_mac(self.router_mac.address)
2481
2482         #
2483         # Bind the BVI to the RD
2484         #
2485         VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
2486         VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
2487
2488         #
2489         # Pg7 hosts a BD's UU-fwd
2490         #
2491         self.pg7.config_ip4()
2492         self.pg7.resolve_arp()
2493
2494         #
2495         # a GBP bridge domains for the EPs
2496         #
2497         bd1 = VppBridgeDomain(self, 1)
2498         bd1.add_vpp_config()
2499         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0)
2500         gbd1.add_vpp_config()
2501
2502         bd2 = VppBridgeDomain(self, 2)
2503         bd2.add_vpp_config()
2504         gbd2 = VppGbpBridgeDomain(self, bd2, self.loop1)
2505         gbd2.add_vpp_config()
2506
2507         # ... and has a /32 and /128 applied
2508         ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
2509         ip4_addr.add_vpp_config()
2510         ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128", 128)
2511         ip6_addr.add_vpp_config()
2512         ip4_addr = VppIpInterfaceAddress(self, gbd2.bvi, "10.0.1.128", 32)
2513         ip4_addr.add_vpp_config()
2514         ip6_addr = VppIpInterfaceAddress(self, gbd2.bvi, "2001:11::128", 128)
2515         ip6_addr.add_vpp_config()
2516
2517         #
2518         # The Endpoint-groups in which we are learning endpoints
2519         #
2520         epg_220 = VppGbpEndpointGroup(self, 220, rd1, gbd1,
2521                                       None, gbd1.bvi,
2522                                       "10.0.0.128",
2523                                       "2001:10::128")
2524         epg_220.add_vpp_config()
2525         epg_221 = VppGbpEndpointGroup(self, 221, rd1, gbd2,
2526                                       None, gbd2.bvi,
2527                                       "10.0.1.128",
2528                                       "2001:11::128")
2529         epg_221.add_vpp_config()
2530         epg_222 = VppGbpEndpointGroup(self, 222, rd1, gbd1,
2531                                       None, gbd1.bvi,
2532                                       "10.0.2.128",
2533                                       "2001:12::128")
2534         epg_222.add_vpp_config()
2535
2536         #
2537         # a GBP bridge domains for the SEPs
2538         #
2539         bd_uu1 = VppVxlanGbpTunnel(self, self.pg7.local_ip4,
2540                                    self.pg7.remote_ip4, 116)
2541         bd_uu1.add_vpp_config()
2542         bd_uu2 = VppVxlanGbpTunnel(self, self.pg7.local_ip4,
2543                                    self.pg7.remote_ip4, 117)
2544         bd_uu2.add_vpp_config()
2545
2546         bd3 = VppBridgeDomain(self, 3)
2547         bd3.add_vpp_config()
2548         gbd3 = VppGbpBridgeDomain(self, bd3, self.loop2, bd_uu1, learn=False)
2549         gbd3.add_vpp_config()
2550         bd4 = VppBridgeDomain(self, 4)
2551         bd4.add_vpp_config()
2552         gbd4 = VppGbpBridgeDomain(self, bd4, self.loop3, bd_uu2, learn=False)
2553         gbd4.add_vpp_config()
2554
2555         #
2556         # EPGs in which the service endpoints exist
2557         #
2558         epg_320 = VppGbpEndpointGroup(self, 320, rd1, gbd3,
2559                                       None, gbd1.bvi,
2560                                       "12.0.0.128",
2561                                       "4001:10::128")
2562         epg_320.add_vpp_config()
2563         epg_321 = VppGbpEndpointGroup(self, 321, rd1, gbd4,
2564                                       None, gbd2.bvi,
2565                                       "12.0.1.128",
2566                                       "4001:11::128")
2567         epg_321.add_vpp_config()
2568
2569         #
2570         # three local endpoints
2571         #
2572         ep1 = VppGbpEndpoint(self, self.pg0,
2573                              epg_220, None,
2574                              "10.0.0.1", "11.0.0.1",
2575                              "2001:10::1", "3001:10::1")
2576         ep1.add_vpp_config()
2577         ep2 = VppGbpEndpoint(self, self.pg1,
2578                              epg_221, None,
2579                              "10.0.1.1", "11.0.1.1",
2580                              "2001:11::1", "3001:11::1")
2581         ep2.add_vpp_config()
2582         ep3 = VppGbpEndpoint(self, self.pg2,
2583                              epg_222, None,
2584                              "10.0.2.2", "11.0.2.2",
2585                              "2001:12::1", "3001:12::1")
2586         ep3.add_vpp_config()
2587
2588         #
2589         # service endpoints
2590         #
2591         sep1 = VppGbpEndpoint(self, self.pg3,
2592                               epg_320, None,
2593                               "12.0.0.1", "13.0.0.1",
2594                               "4001:10::1", "5001:10::1")
2595         sep1.add_vpp_config()
2596         sep2 = VppGbpEndpoint(self, self.pg4,
2597                               epg_320, None,
2598                               "12.0.0.2", "13.0.0.2",
2599                               "4001:10::2", "5001:10::2")
2600         sep2.add_vpp_config()
2601         sep3 = VppGbpEndpoint(self, self.pg5,
2602                               epg_321, None,
2603                               "12.0.1.1", "13.0.1.1",
2604                               "4001:11::1", "5001:11::1")
2605         sep3.add_vpp_config()
2606         # this EP is not installed immediately
2607         sep4 = VppGbpEndpoint(self, self.pg6,
2608                               epg_321, None,
2609                               "12.0.1.2", "13.0.1.2",
2610                               "4001:11::2", "5001:11::2")
2611
2612         #
2613         # an L2 switch packet between local EPs in different EPGs
2614         #  different dest ports on each so the are LB hashed differently
2615         #
2616         p4 = [(Ether(src=ep1.mac, dst=ep3.mac) /
2617                IP(src=ep1.ip4.address, dst=ep3.ip4.address) /
2618                UDP(sport=1234, dport=1234) /
2619                Raw('\xa5' * 100)),
2620               (Ether(src=ep3.mac, dst=ep1.mac) /
2621                IP(src=ep3.ip4.address, dst=ep1.ip4.address) /
2622                UDP(sport=1234, dport=1234) /
2623                Raw('\xa5' * 100))]
2624         p6 = [(Ether(src=ep1.mac, dst=ep3.mac) /
2625                IPv6(src=ep1.ip6.address, dst=ep3.ip6.address) /
2626                UDP(sport=1234, dport=1234) /
2627                Raw('\xa5' * 100)),
2628               (Ether(src=ep3.mac, dst=ep1.mac) /
2629                IPv6(src=ep3.ip6.address, dst=ep1.ip6.address) /
2630                UDP(sport=1234, dport=1230) /
2631                Raw('\xa5' * 100))]
2632
2633         # should be dropped since no contract yet
2634         self.send_and_assert_no_replies(self.pg0, [p4[0]])
2635         self.send_and_assert_no_replies(self.pg0, [p6[0]])
2636
2637         #
2638         # Add a contract with a rule to load-balance redirect via SEP1 and SEP2
2639         # one of the next-hops is via an EP that is not known
2640         #
2641         acl = VppGbpAcl(self)
2642         rule4 = acl.create_rule(permit_deny=1, proto=17)
2643         rule6 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
2644         acl_index = acl.add_vpp_config([rule4, rule6])
2645
2646         #
2647         # test the src-ip hash mode
2648         #
2649         c1 = VppGbpContract(
2650             self, 220, 222, acl_index,
2651             [VppGbpContractRule(
2652                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
2653                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2654                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
2655                                        sep1.ip4, sep1.epg.rd),
2656                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
2657                                        sep2.ip4, sep2.epg.rd)]),
2658              VppGbpContractRule(
2659                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
2660                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2661                  [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
2662                                         sep3.ip6, sep3.epg.rd),
2663                   VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
2664                                         sep4.ip6, sep4.epg.rd)])])
2665         c1.add_vpp_config()
2666
2667         c2 = VppGbpContract(
2668             self, 222, 220, acl_index,
2669             [VppGbpContractRule(
2670                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
2671                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2672                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
2673                                        sep1.ip4, sep1.epg.rd),
2674                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
2675                                        sep2.ip4, sep2.epg.rd)]),
2676              VppGbpContractRule(
2677                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
2678                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2679                  [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
2680                                         sep3.ip6, sep3.epg.rd),
2681                   VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
2682                                         sep4.ip6, sep4.epg.rd)])])
2683         c2.add_vpp_config()
2684
2685         #
2686         # send again with the contract preset, now packets arrive
2687         # at SEP1 or SEP2 depending on the hashing
2688         #
2689         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
2690
2691         for rx in rxs:
2692             self.assertEqual(rx[Ether].src, routed_src_mac)
2693             self.assertEqual(rx[Ether].dst, sep1.mac)
2694             self.assertEqual(rx[IP].src, ep1.ip4.address)
2695             self.assertEqual(rx[IP].dst, ep3.ip4.address)
2696
2697         rxs = self.send_and_expect(self.pg2, p4[1] * 17, sep2.itf)
2698
2699         for rx in rxs:
2700             self.assertEqual(rx[Ether].src, routed_src_mac)
2701             self.assertEqual(rx[Ether].dst, sep2.mac)
2702             self.assertEqual(rx[IP].src, ep3.ip4.address)
2703             self.assertEqual(rx[IP].dst, ep1.ip4.address)
2704
2705         rxs = self.send_and_expect(self.pg0, p6[0] * 17, self.pg7)
2706
2707         for rx in rxs:
2708             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
2709             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
2710             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
2711             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
2712             self.assertEqual(rx[VXLAN].vni, 117)
2713             self.assertTrue(rx[VXLAN].flags.G)
2714             self.assertTrue(rx[VXLAN].flags.Instance)
2715             # redirect policy has been applied
2716             self.assertTrue(rx[VXLAN].gpflags.A)
2717             self.assertFalse(rx[VXLAN].gpflags.D)
2718
2719             inner = rx[VXLAN].payload
2720
2721             self.assertEqual(inner[Ether].src, routed_src_mac)
2722             self.assertEqual(inner[Ether].dst, sep4.mac)
2723             self.assertEqual(inner[IPv6].src, ep1.ip6.address)
2724             self.assertEqual(inner[IPv6].dst, ep3.ip6.address)
2725
2726         rxs = self.send_and_expect(self.pg2, p6[1] * 17, sep3.itf)
2727
2728         for rx in rxs:
2729             self.assertEqual(rx[Ether].src, routed_src_mac)
2730             self.assertEqual(rx[Ether].dst, sep3.mac)
2731             self.assertEqual(rx[IPv6].src, ep3.ip6.address)
2732             self.assertEqual(rx[IPv6].dst, ep1.ip6.address)
2733
2734         #
2735         # programme the unknown EP
2736         #
2737         sep4.add_vpp_config()
2738
2739         rxs = self.send_and_expect(self.pg0, p6[0] * 17, sep4.itf)
2740
2741         for rx in rxs:
2742             self.assertEqual(rx[Ether].src, routed_src_mac)
2743             self.assertEqual(rx[Ether].dst, sep4.mac)
2744             self.assertEqual(rx[IPv6].src, ep1.ip6.address)
2745             self.assertEqual(rx[IPv6].dst, ep3.ip6.address)
2746
2747         #
2748         # and revert back to unprogrammed
2749         #
2750         sep4.remove_vpp_config()
2751
2752         rxs = self.send_and_expect(self.pg0, p6[0] * 17, self.pg7)
2753
2754         for rx in rxs:
2755             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
2756             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
2757             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
2758             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
2759             self.assertEqual(rx[VXLAN].vni, 117)
2760             self.assertTrue(rx[VXLAN].flags.G)
2761             self.assertTrue(rx[VXLAN].flags.Instance)
2762             # redirect policy has been applied
2763             self.assertTrue(rx[VXLAN].gpflags.A)
2764             self.assertFalse(rx[VXLAN].gpflags.D)
2765
2766             inner = rx[VXLAN].payload
2767
2768             self.assertEqual(inner[Ether].src, routed_src_mac)
2769             self.assertEqual(inner[Ether].dst, sep4.mac)
2770             self.assertEqual(inner[IPv6].src, ep1.ip6.address)
2771             self.assertEqual(inner[IPv6].dst, ep3.ip6.address)
2772
2773         c1.remove_vpp_config()
2774         c2.remove_vpp_config()
2775
2776         #
2777         # test the symmetric hash mode
2778         #
2779         c1 = VppGbpContract(
2780             self, 220, 222, acl_index,
2781             [VppGbpContractRule(
2782                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
2783                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
2784                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
2785                                        sep1.ip4, sep1.epg.rd),
2786                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
2787                                        sep2.ip4, sep2.epg.rd)]),
2788              VppGbpContractRule(
2789                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
2790                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
2791                  [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
2792                                         sep3.ip6, sep3.epg.rd),
2793                   VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
2794                                         sep4.ip6, sep4.epg.rd)])])
2795         c1.add_vpp_config()
2796
2797         c2 = VppGbpContract(
2798             self, 222, 220, acl_index,
2799             [VppGbpContractRule(
2800                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
2801                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
2802                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
2803                                        sep1.ip4, sep1.epg.rd),
2804                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
2805                                        sep2.ip4, sep2.epg.rd)]),
2806              VppGbpContractRule(
2807                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
2808                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
2809                  [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
2810                                         sep3.ip6, sep3.epg.rd),
2811                   VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
2812                                         sep4.ip6, sep4.epg.rd)])])
2813         c2.add_vpp_config()
2814
2815         #
2816         # send again with the contract preset, now packets arrive
2817         # at SEP1 for both directions
2818         #
2819         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
2820
2821         for rx in rxs:
2822             self.assertEqual(rx[Ether].src, routed_src_mac)
2823             self.assertEqual(rx[Ether].dst, sep1.mac)
2824             self.assertEqual(rx[IP].src, ep1.ip4.address)
2825             self.assertEqual(rx[IP].dst, ep3.ip4.address)
2826
2827         rxs = self.send_and_expect(self.pg2, p4[1] * 17, sep1.itf)
2828
2829         for rx in rxs:
2830             self.assertEqual(rx[Ether].src, routed_src_mac)
2831             self.assertEqual(rx[Ether].dst, sep1.mac)
2832             self.assertEqual(rx[IP].src, ep3.ip4.address)
2833             self.assertEqual(rx[IP].dst, ep1.ip4.address)
2834
2835         #
2836         # programme the unknown EP for the L3 tests
2837         #
2838         sep4.add_vpp_config()
2839
2840         #
2841         # an L3 switch packet between local EPs in different EPGs
2842         #  different dest ports on each so the are LB hashed differently
2843         #
2844         p4 = [(Ether(src=ep1.mac, dst=self.router_mac.address) /
2845                IP(src=ep1.ip4.address, dst=ep2.ip4.address) /
2846                UDP(sport=1234, dport=1234) /
2847                Raw('\xa5' * 100)),
2848               (Ether(src=ep2.mac, dst=self.router_mac.address) /
2849                IP(src=ep2.ip4.address, dst=ep1.ip4.address) /
2850                UDP(sport=1234, dport=1234) /
2851                Raw('\xa5' * 100))]
2852         p6 = [(Ether(src=ep1.mac, dst=self.router_mac.address) /
2853                IPv6(src=ep1.ip6.address, dst=ep2.ip6.address) /
2854                UDP(sport=1234, dport=1234) /
2855                Raw('\xa5' * 100)),
2856               (Ether(src=ep2.mac, dst=self.router_mac.address) /
2857                IPv6(src=ep2.ip6.address, dst=ep1.ip6.address) /
2858                UDP(sport=1234, dport=1234) /
2859                Raw('\xa5' * 100))]
2860
2861         c3 = VppGbpContract(
2862              self, 220, 221, acl_index,
2863              [VppGbpContractRule(
2864                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
2865                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
2866                  [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
2867                                         sep1.ip4, sep1.epg.rd),
2868                   VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
2869                                         sep2.ip4, sep2.epg.rd)]),
2870               VppGbpContractRule(
2871                   VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
2872                   VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
2873                   [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
2874                                          sep3.ip6, sep3.epg.rd),
2875                    VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
2876                                          sep4.ip6, sep4.epg.rd)])])
2877         c3.add_vpp_config()
2878
2879         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
2880
2881         for rx in rxs:
2882             self.assertEqual(rx[Ether].src, routed_src_mac)
2883             self.assertEqual(rx[Ether].dst, sep1.mac)
2884             self.assertEqual(rx[IP].src, ep1.ip4.address)
2885             self.assertEqual(rx[IP].dst, ep2.ip4.address)
2886
2887         #
2888         # learn a remote EP in EPG 221
2889         #
2890         vx_tun_l3 = VppGbpVxlanTunnel(
2891             self, 444, rd1.rd_id,
2892             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3)
2893         vx_tun_l3.add_vpp_config()
2894
2895         c4 = VppGbpContract(
2896             self, 221, 220, acl_index,
2897             [VppGbpContractRule(
2898                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2899                 []),
2900              VppGbpContractRule(
2901                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2902                  [])])
2903         c4.add_vpp_config()
2904
2905         p = (Ether(src=self.pg7.remote_mac,
2906                    dst=self.pg7.local_mac) /
2907              IP(src=self.pg7.remote_ip4,
2908                 dst=self.pg7.local_ip4) /
2909              UDP(sport=1234, dport=48879) /
2910              VXLAN(vni=444, gpid=221, flags=0x88) /
2911              Ether(src="00:22:22:22:22:33", dst=self.router_mac.address) /
2912              IP(src="10.0.0.88", dst=ep1.ip4.address) /
2913              UDP(sport=1234, dport=1234) /
2914              Raw('\xa5' * 100))
2915
2916         rx = self.send_and_expect(self.pg7, [p], self.pg0)
2917
2918         # endpoint learnt via the parent GBP-vxlan interface
2919         self.assertTrue(find_gbp_endpoint(self,
2920                                           vx_tun_l3._sw_if_index,
2921                                           ip="10.0.0.88"))
2922
2923         p = (Ether(src=self.pg7.remote_mac,
2924                    dst=self.pg7.local_mac) /
2925              IP(src=self.pg7.remote_ip4,
2926                 dst=self.pg7.local_ip4) /
2927              UDP(sport=1234, dport=48879) /
2928              VXLAN(vni=444, gpid=221, flags=0x88) /
2929              Ether(src="00:22:22:22:22:33", dst=self.router_mac.address) /
2930              IPv6(src="2001:10::88", dst=ep1.ip6.address) /
2931              UDP(sport=1234, dport=1234) /
2932              Raw('\xa5' * 100))
2933
2934         rx = self.send_and_expect(self.pg7, [p], self.pg0)
2935
2936         # endpoint learnt via the parent GBP-vxlan interface
2937         self.assertTrue(find_gbp_endpoint(self,
2938                                           vx_tun_l3._sw_if_index,
2939                                           ip="2001:10::88"))
2940
2941         #
2942         # L3 switch from local to remote EP
2943         #
2944         p4 = [(Ether(src=ep1.mac, dst=self.router_mac.address) /
2945                IP(src=ep1.ip4.address, dst="10.0.0.88") /
2946                UDP(sport=1234, dport=1234) /
2947                Raw('\xa5' * 100))]
2948         p6 = [(Ether(src=ep1.mac, dst=self.router_mac.address) /
2949                IPv6(src=ep1.ip6.address, dst="2001:10::88") /
2950                UDP(sport=1234, dport=1234) /
2951                Raw('\xa5' * 100))]
2952
2953         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
2954
2955         for rx in rxs:
2956             self.assertEqual(rx[Ether].src, routed_src_mac)
2957             self.assertEqual(rx[Ether].dst, sep1.mac)
2958             self.assertEqual(rx[IP].src, ep1.ip4.address)
2959             self.assertEqual(rx[IP].dst, "10.0.0.88")
2960
2961         rxs = self.send_and_expect(self.pg0, p6[0] * 17, sep4.itf)
2962
2963         for rx in rxs:
2964             self.assertEqual(rx[Ether].src, routed_src_mac)
2965             self.assertEqual(rx[Ether].dst, sep4.mac)
2966             self.assertEqual(rx[IPv6].src, ep1.ip6.address)
2967             self.assertEqual(rx[IPv6].dst, "2001:10::88")
2968
2969         #
2970         # test the dst-ip hash mode
2971         #
2972         c5 = VppGbpContract(
2973             self, 220, 221, acl_index,
2974             [VppGbpContractRule(
2975                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
2976                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
2977                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
2978                                        sep1.ip4, sep1.epg.rd),
2979                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
2980                                        sep2.ip4, sep2.epg.rd)]),
2981              VppGbpContractRule(
2982                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
2983                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
2984                  [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
2985                                         sep3.ip6, sep3.epg.rd),
2986                   VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
2987                                         sep4.ip6, sep4.epg.rd)])])
2988         c5.add_vpp_config()
2989
2990         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
2991
2992         for rx in rxs:
2993             self.assertEqual(rx[Ether].src, routed_src_mac)
2994             self.assertEqual(rx[Ether].dst, sep1.mac)
2995             self.assertEqual(rx[IP].src, ep1.ip4.address)
2996             self.assertEqual(rx[IP].dst, "10.0.0.88")
2997
2998         rxs = self.send_and_expect(self.pg0, p6[0] * 17, sep3.itf)
2999
3000         for rx in rxs:
3001             self.assertEqual(rx[Ether].src, routed_src_mac)
3002             self.assertEqual(rx[Ether].dst, sep3.mac)
3003             self.assertEqual(rx[IPv6].src, ep1.ip6.address)
3004             self.assertEqual(rx[IPv6].dst, "2001:10::88")
3005
3006         #
3007         # cleanup
3008         #
3009         self.pg7.unconfig_ip4()
3010
3011     def test_gbp_l3_out(self):
3012         """ GBP L3 Out """
3013
3014         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
3015         self.vapi.cli("set logging class gbp debug")
3016
3017         routed_dst_mac = "00:0c:0c:0c:0c:0c"
3018         routed_src_mac = "00:22:bd:f8:19:ff"
3019
3020         #
3021         # IP tables
3022         #
3023         t4 = VppIpTable(self, 1)
3024         t4.add_vpp_config()
3025         t6 = VppIpTable(self, 1, True)
3026         t6.add_vpp_config()
3027
3028         rd1 = VppGbpRouteDomain(self, 2, t4, t6)
3029         rd1.add_vpp_config()
3030
3031         self.loop0.set_mac(self.router_mac.address)
3032
3033         #
3034         # Bind the BVI to the RD
3035         #
3036         VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
3037         VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
3038
3039         #
3040         # Pg7 hosts a BD's BUM
3041         # Pg1 some other l3 interface
3042         #
3043         self.pg7.config_ip4()
3044         self.pg7.resolve_arp()
3045
3046         #
3047         # a GBP external bridge domains for the EPs
3048         #
3049         bd1 = VppBridgeDomain(self, 1)
3050         bd1.add_vpp_config()
3051         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0)
3052         gbd1.add_vpp_config()
3053
3054         #
3055         # The Endpoint-groups in which the external endpoints exist
3056         #
3057         epg_220 = VppGbpEndpointGroup(self, 220, rd1, gbd1,
3058                                       None, gbd1.bvi,
3059                                       "10.0.0.128",
3060                                       "2001:10::128")
3061         epg_220.add_vpp_config()
3062
3063         # the BVIs have the subnets applied ...
3064         ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 24)
3065         ip4_addr.add_vpp_config()
3066         ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128", 64)
3067         ip6_addr.add_vpp_config()
3068
3069         # ... which are L3-out subnets
3070         l3o_1 = VppGbpSubnet(
3071             self, rd1, "10.0.0.0", 24,
3072             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3073             epg=200)
3074         l3o_1.add_vpp_config()
3075
3076         #
3077         # an external interface attached to the outside world and the
3078         # external BD
3079         #
3080         vlan_100 = VppDot1QSubint(self, self.pg0, 100)
3081         vlan_100.admin_up()
3082         ext_itf = VppGbpExtItf(self, vlan_100, bd1, rd1)
3083         ext_itf.add_vpp_config()
3084
3085         #
3086         # a multicast vxlan-gbp tunnel for broadcast in the BD
3087         #
3088         tun_bm = VppVxlanGbpTunnel(self, self.pg7.local_ip4,
3089                                    "239.1.1.1", 88,
3090                                    mcast_itf=self.pg7)
3091         tun_bm.add_vpp_config()
3092         bp_bm = VppBridgeDomainPort(self, bd1, tun_bm,
3093                                     port_type=L2_PORT_TYPE.NORMAL)
3094         bp_bm.add_vpp_config()
3095
3096         #
3097         # an unicast vxlan-gbp for inter-BD traffic
3098         #
3099         vx_tun_l3 = VppGbpVxlanTunnel(
3100             self, 444, rd1.rd_id,
3101             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3)
3102         vx_tun_l3.add_vpp_config()
3103
3104         #
3105         # packets destined to unkown addresses in the BVI's subnet
3106         # are ARP'd for
3107         #
3108         p4 = (Ether(src=self.pg0.remote_mac, dst=self.router_mac.address) /
3109               Dot1Q(vlan=100) /
3110               IP(src="10.0.0.1", dst="10.0.0.88") /
3111               UDP(sport=1234, dport=1234) /
3112               Raw('\xa5' * 100))
3113         p6 = (Ether(src=self.pg0.remote_mac, dst=self.router_mac.address) /
3114               Dot1Q(vlan=100) /
3115               IPv6(src="2001:10::1", dst="2001:10::88") /
3116               UDP(sport=1234, dport=1234) /
3117               Raw('\xa5' * 100))
3118
3119         rxs = self.send_and_expect(self.pg0, p4 * 1, self.pg7)
3120
3121         for rx in rxs:
3122             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
3123             # self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
3124             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
3125             self.assertEqual(rx[IP].dst, "239.1.1.1")
3126             self.assertEqual(rx[VXLAN].vni, 88)
3127             self.assertTrue(rx[VXLAN].flags.G)
3128             self.assertTrue(rx[VXLAN].flags.Instance)
3129             # policy is not applied since we don't know where it's going
3130             self.assertFalse(rx[VXLAN].gpflags.A)
3131             self.assertFalse(rx[VXLAN].gpflags.D)
3132
3133             inner = rx[VXLAN].payload
3134
3135             self.assertTrue(inner.haslayer(ARP))
3136
3137         #
3138         # An external Endpoint
3139         #
3140         eep = VppGbpEndpoint(self, vlan_100,
3141                              epg_220, None,
3142                              "10.0.0.1", "11.0.0.1",
3143                              "2001:10::1", "3001::1",
3144                              ep_flags.GBP_API_ENDPOINT_FLAG_EXTERNAL)
3145         eep.add_vpp_config()
3146
3147         #
3148         # A remote endpoint
3149         #
3150         rep = VppGbpEndpoint(self, vx_tun_l3,
3151                              epg_220, None,
3152                              "10.0.0.101", "11.0.0.101",
3153                              "2001:10::101", "3001::101",
3154                              ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
3155                              self.pg7.local_ip4,
3156                              self.pg7.remote_ip4,
3157                              mac=None)
3158         rep.add_vpp_config()
3159
3160         #
3161         # remote to external
3162         #
3163         p = (Ether(src=self.pg7.remote_mac,
3164                    dst=self.pg7.local_mac) /
3165              IP(src=self.pg7.remote_ip4,
3166                 dst=self.pg7.local_ip4) /
3167              UDP(sport=1234, dport=48879) /
3168              VXLAN(vni=444, gpid=220, flags=0x88) /
3169              Ether(src=self.pg0.remote_mac, dst=self.router_mac.address) /
3170              IP(src="10.0.0.101", dst="10.0.0.1") /
3171              UDP(sport=1234, dport=1234) /
3172              Raw('\xa5' * 100))
3173
3174         rxs = self.send_and_expect(self.pg7, p * 1, self.pg0)
3175
3176         #
3177         # A subnet reachable through the external EP
3178         #
3179         ip_220 = VppIpRoute(self, "10.220.0.0", 24,
3180                             [VppRoutePath(eep.ip4.address,
3181                                           eep.epg.bvi.sw_if_index)],
3182                             table_id=t4.table_id)
3183         ip_220.add_vpp_config()
3184
3185         l3o_220 = VppGbpSubnet(
3186             self, rd1, "10.220.0.0", 24,
3187             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3188             epg=220)
3189         l3o_220.add_vpp_config()
3190
3191         p = (Ether(src=self.pg7.remote_mac,
3192                    dst=self.pg7.local_mac) /
3193              IP(src=self.pg7.remote_ip4,
3194                 dst=self.pg7.local_ip4) /
3195              UDP(sport=1234, dport=48879) /
3196              VXLAN(vni=444, gpid=220, flags=0x88) /
3197              Ether(src=self.pg0.remote_mac, dst=self.router_mac.address) /
3198              IP(src="10.0.0.101", dst="10.220.0.1") /
3199              UDP(sport=1234, dport=1234) /
3200              Raw('\xa5' * 100))
3201
3202         rxs = self.send_and_expect(self.pg7, p * 1, self.pg0)
3203
3204         #
3205         # another external subnet, this time in a different EPG
3206         #
3207         ip_200 = VppIpRoute(self, "10.200.0.0", 24,
3208                             [VppRoutePath(eep.ip4.address,
3209                                           eep.epg.bvi.sw_if_index)],
3210                             table_id=t4.table_id)
3211         ip_200.add_vpp_config()
3212
3213         l3o_200 = VppGbpSubnet(
3214             self, rd1, "10.200.0.0", 24,
3215             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3216             epg=200)
3217         l3o_200.add_vpp_config()
3218
3219         p = (Ether(src=self.pg7.remote_mac,
3220                    dst=self.pg7.local_mac) /
3221              IP(src=self.pg7.remote_ip4,
3222                 dst=self.pg7.local_ip4) /
3223              UDP(sport=1234, dport=48879) /
3224              VXLAN(vni=444, gpid=220, flags=0x88) /
3225              Ether(src=self.pg0.remote_mac, dst=self.router_mac.address) /
3226              IP(src="10.0.0.101", dst="10.200.0.1") /
3227              UDP(sport=1234, dport=1234) /
3228              Raw('\xa5' * 100))
3229
3230         #
3231         # packets dropped due to lack of contract.
3232         #
3233         rxs = self.send_and_assert_no_replies(self.pg7, p * 1)
3234
3235         #
3236         # from the the subnet in EPG 220 beyond the external to remote
3237         #
3238         p4 = (Ether(src=self.pg0.remote_mac, dst=self.router_mac.address) /
3239               Dot1Q(vlan=100) /
3240               IP(src="10.220.0.1", dst=rep.ip4.address) /
3241               UDP(sport=1234, dport=1234) /
3242               Raw('\xa5' * 100))
3243
3244         rxs = self.send_and_expect(self.pg0, p4 * 1, self.pg7)
3245
3246         for rx in rxs:
3247             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
3248             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
3249             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
3250             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
3251             self.assertEqual(rx[VXLAN].vni, 444)
3252             self.assertTrue(rx[VXLAN].flags.G)
3253             self.assertTrue(rx[VXLAN].flags.Instance)
3254             self.assertTrue(rx[VXLAN].gpflags.A)
3255             self.assertFalse(rx[VXLAN].gpflags.D)
3256
3257         #
3258         # from the the subnet in EPG 200 beyond the external to remote
3259         # dropped due to no contract
3260         #
3261         p4 = (Ether(src=self.pg0.remote_mac, dst=self.router_mac.address) /
3262               Dot1Q(vlan=100) /
3263               IP(src="10.200.0.1", dst=rep.ip4.address) /
3264               UDP(sport=1234, dport=1234) /
3265               Raw('\xa5' * 100))
3266
3267         rxs = self.send_and_assert_no_replies(self.pg0, p4 * 1)
3268
3269         #
3270         # add a contract
3271         #
3272         acl = VppGbpAcl(self)
3273         rule = acl.create_rule(permit_deny=1, proto=17)
3274         rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
3275         acl_index = acl.add_vpp_config([rule, rule2])
3276         c1 = VppGbpContract(
3277             self, 200, 220, acl_index,
3278             [VppGbpContractRule(
3279                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3280                 []),
3281              VppGbpContractRule(
3282                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3283                  [])])
3284         c1.add_vpp_config()
3285
3286         rxs = self.send_and_expect(self.pg0, p4 * 1, self.pg7)
3287
3288         for rx in rxs:
3289             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
3290             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
3291             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
3292             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
3293             self.assertEqual(rx[VXLAN].vni, 444)
3294             self.assertTrue(rx[VXLAN].flags.G)
3295             self.assertTrue(rx[VXLAN].flags.Instance)
3296             self.assertTrue(rx[VXLAN].gpflags.A)
3297             self.assertFalse(rx[VXLAN].gpflags.D)
3298
3299         #
3300         # cleanup
3301         #
3302         self.pg7.unconfig_ip4()
3303
3304
3305 if __name__ == '__main__':
3306     unittest.main(testRunner=VppTestRunner)