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