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