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