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