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