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