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