GBP: Endpoints with VLAN tags and birdges that don't learn
[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 VppGbpContract(VppObject):
369     """
370     GBP Contract
371     """
372
373     def __init__(self, test, src_epg, dst_epg, acl_index):
374         self._test = test
375         self.acl_index = acl_index
376         self.src_epg = src_epg
377         self.dst_epg = dst_epg
378
379     def add_vpp_config(self):
380         self._test.vapi.gbp_contract_add_del(
381             1,
382             self.src_epg,
383             self.dst_epg,
384             self.acl_index)
385         self._test.registry.register(self, self._test.logger)
386
387     def remove_vpp_config(self):
388         self._test.vapi.gbp_contract_add_del(
389             0,
390             self.src_epg,
391             self.dst_epg,
392             self.acl_index)
393
394     def __str__(self):
395         return self.object_id()
396
397     def object_id(self):
398         return "gbp-contract:[%d:%s:%d]" % (self.src_epg,
399                                             self.dst_epg,
400                                             self.acl_index)
401
402     def query_vpp_config(self):
403         cs = self._test.vapi.gbp_contract_dump()
404         for c in cs:
405             if c.contract.src_epg == self.src_epg \
406                and c.contract.dst_epg == self.dst_epg:
407                 return True
408         return False
409
410
411 class VppGbpVxlanTunnel(VppInterface):
412     """
413     GBP VXLAN tunnel
414     """
415
416     def __init__(self, test, vni, bd_rd_id, mode):
417         super(VppGbpVxlanTunnel, self).__init__(test)
418         self._test = test
419         self.vni = vni
420         self.bd_rd_id = bd_rd_id
421         self.mode = mode
422
423     def add_vpp_config(self):
424         r = self._test.vapi.gbp_vxlan_tunnel_add(
425             self.vni,
426             self.bd_rd_id,
427             self.mode)
428         self.set_sw_if_index(r.sw_if_index)
429         self._test.registry.register(self, self._test.logger)
430
431     def remove_vpp_config(self):
432         self._test.vapi.gbp_vxlan_tunnel_del(self.vni)
433
434     def __str__(self):
435         return self.object_id()
436
437     def object_id(self):
438         return "gbp-vxlan:%d" % (self.vni)
439
440     def query_vpp_config(self):
441         return find_gbp_vxlan(self._test, self.vni)
442
443
444 class VppGbpAcl(VppObject):
445     """
446     GBP Acl
447     """
448
449     def __init__(self, test):
450         self._test = test
451         self.acl_index = 4294967295
452
453     def create_rule(self, is_ipv6=0, permit_deny=0, proto=-1,
454                     s_prefix=0, s_ip='\x00\x00\x00\x00', sport_from=0,
455                     sport_to=65535, d_prefix=0, d_ip='\x00\x00\x00\x00',
456                     dport_from=0, dport_to=65535):
457         if proto == -1 or proto == 0:
458             sport_to = 0
459             dport_to = sport_to
460         elif proto == 1 or proto == 58:
461             sport_to = 255
462             dport_to = sport_to
463         rule = ({'is_permit': permit_deny, 'is_ipv6': is_ipv6, 'proto': proto,
464                  'srcport_or_icmptype_first': sport_from,
465                  'srcport_or_icmptype_last': sport_to,
466                  'src_ip_prefix_len': s_prefix,
467                  'src_ip_addr': s_ip,
468                  'dstport_or_icmpcode_first': dport_from,
469                  'dstport_or_icmpcode_last': dport_to,
470                  'dst_ip_prefix_len': d_prefix,
471                  'dst_ip_addr': d_ip})
472         return rule
473
474     def add_vpp_config(self, rules):
475
476         reply = self._test.vapi.acl_add_replace(self.acl_index,
477                                                 r=rules,
478                                                 tag='GBPTest')
479         self.acl_index = reply.acl_index
480         return self.acl_index
481
482     def remove_vpp_config(self):
483         self._test.vapi.acl_del(self.acl_index)
484
485     def __str__(self):
486         return self.object_id()
487
488     def object_id(self):
489         return "gbp-acl:[%d]" % (self.acl_index)
490
491     def query_vpp_config(self):
492         cs = self._test.vapi.acl_dump()
493         for c in cs:
494             if c.acl_index == self.acl_index:
495                 return True
496         return False
497
498
499 class TestGBP(VppTestCase):
500     """ GBP Test Case """
501
502     def setUp(self):
503         super(TestGBP, self).setUp()
504
505         self.create_pg_interfaces(range(9))
506         self.create_loopback_interfaces(8)
507
508         self.router_mac = VppMacAddress("00:11:22:33:44:55")
509
510         for i in self.pg_interfaces:
511             i.admin_up()
512         for i in self.lo_interfaces:
513             i.admin_up()
514
515     def tearDown(self):
516         for i in self.pg_interfaces:
517             i.admin_down()
518
519         super(TestGBP, self).tearDown()
520
521     def send_and_expect_bridged(self, src, tx, dst):
522         rx = self.send_and_expect(src, tx, dst)
523
524         for r in rx:
525             self.assertEqual(r[Ether].src, tx[0][Ether].src)
526             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
527             self.assertEqual(r[IP].src, tx[0][IP].src)
528             self.assertEqual(r[IP].dst, tx[0][IP].dst)
529         return rx
530
531     def send_and_expect_bridged6(self, src, tx, dst):
532         rx = self.send_and_expect(src, tx, dst)
533
534         for r in rx:
535             self.assertEqual(r[Ether].src, tx[0][Ether].src)
536             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
537             self.assertEqual(r[IPv6].src, tx[0][IPv6].src)
538             self.assertEqual(r[IPv6].dst, tx[0][IPv6].dst)
539         return rx
540
541     def send_and_expect_routed(self, src, tx, dst, src_mac):
542         rx = self.send_and_expect(src, tx, dst)
543
544         for r in rx:
545             self.assertEqual(r[Ether].src, src_mac)
546             self.assertEqual(r[Ether].dst, dst.remote_mac)
547             self.assertEqual(r[IP].src, tx[0][IP].src)
548             self.assertEqual(r[IP].dst, tx[0][IP].dst)
549         return rx
550
551     def send_and_expect_natted(self, src, tx, dst, src_ip):
552         rx = self.send_and_expect(src, tx, dst)
553
554         for r in rx:
555             self.assertEqual(r[Ether].src, tx[0][Ether].src)
556             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
557             self.assertEqual(r[IP].src, src_ip)
558             self.assertEqual(r[IP].dst, tx[0][IP].dst)
559         return rx
560
561     def send_and_expect_natted6(self, src, tx, dst, src_ip):
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[IPv6].src, src_ip)
568             self.assertEqual(r[IPv6].dst, tx[0][IPv6].dst)
569         return rx
570
571     def send_and_expect_unnatted(self, src, tx, dst, dst_ip):
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[IP].dst, dst_ip)
578             self.assertEqual(r[IP].src, tx[0][IP].src)
579         return rx
580
581     def send_and_expect_unnatted6(self, src, tx, dst, dst_ip):
582         rx = self.send_and_expect(src, tx, dst)
583
584         for r in rx:
585             self.assertEqual(r[Ether].src, tx[0][Ether].src)
586             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
587             self.assertEqual(r[IPv6].dst, dst_ip)
588             self.assertEqual(r[IPv6].src, tx[0][IPv6].src)
589         return rx
590
591     def send_and_expect_double_natted(self, src, tx, dst, src_ip, dst_ip):
592         rx = self.send_and_expect(src, tx, dst)
593
594         for r in rx:
595             self.assertEqual(r[Ether].src, self.router_mac.address)
596             self.assertEqual(r[Ether].dst, dst.remote_mac)
597             self.assertEqual(r[IP].dst, dst_ip)
598             self.assertEqual(r[IP].src, src_ip)
599         return rx
600
601     def send_and_expect_double_natted6(self, src, tx, dst, src_ip, dst_ip):
602         rx = self.send_and_expect(src, tx, dst)
603
604         for r in rx:
605             self.assertEqual(r[Ether].src, self.router_mac.address)
606             self.assertEqual(r[Ether].dst, dst.remote_mac)
607             self.assertEqual(r[IPv6].dst, dst_ip)
608             self.assertEqual(r[IPv6].src, src_ip)
609         return rx
610
611     def test_gbp(self):
612         """ Group Based Policy """
613
614         #
615         # Bridge Domains
616         #
617         bd1 = VppBridgeDomain(self, 1)
618         bd2 = VppBridgeDomain(self, 2)
619         bd20 = VppBridgeDomain(self, 20)
620
621         bd1.add_vpp_config()
622         bd2.add_vpp_config()
623         bd20.add_vpp_config()
624
625         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0)
626         gbd2 = VppGbpBridgeDomain(self, bd2, self.loop1)
627         gbd20 = VppGbpBridgeDomain(self, bd20, self.loop2)
628
629         gbd1.add_vpp_config()
630         gbd2.add_vpp_config()
631         gbd20.add_vpp_config()
632
633         #
634         # Route Domains
635         #
636         gt4 = VppIpTable(self, 0)
637         gt4.add_vpp_config()
638         gt6 = VppIpTable(self, 0, is_ip6=True)
639         gt6.add_vpp_config()
640         nt4 = VppIpTable(self, 20)
641         nt4.add_vpp_config()
642         nt6 = VppIpTable(self, 20, is_ip6=True)
643         nt6.add_vpp_config()
644
645         rd0 = VppGbpRouteDomain(self, 0, gt4, gt6, None, None)
646         rd20 = VppGbpRouteDomain(self, 20, nt4, nt6, None, None)
647
648         rd0.add_vpp_config()
649         rd20.add_vpp_config()
650
651         #
652         # 3 EPGs, 2 of which share a BD.
653         # 2 NAT EPGs, one for floating-IP subnets, the other for internet
654         #
655         epgs = [VppGbpEndpointGroup(self, 220, rd0, gbd1, self.pg4,
656                                     self.loop0,
657                                     "10.0.0.128",
658                                     "2001:10::128"),
659                 VppGbpEndpointGroup(self, 221, rd0, gbd1, self.pg5,
660                                     self.loop0,
661                                     "10.0.1.128",
662                                     "2001:10:1::128"),
663                 VppGbpEndpointGroup(self, 222, rd0, gbd2, self.pg6,
664                                     self.loop1,
665                                     "10.0.2.128",
666                                     "2001:10:2::128"),
667                 VppGbpEndpointGroup(self, 333, rd20, gbd20, self.pg7,
668                                     self.loop2,
669                                     "11.0.0.128",
670                                     "3001::128"),
671                 VppGbpEndpointGroup(self, 444, rd20, gbd20, self.pg8,
672                                     self.loop2,
673                                     "11.0.0.129",
674                                     "3001::129")]
675         recircs = [VppGbpRecirc(self, epgs[0],
676                                 self.loop3),
677                    VppGbpRecirc(self, epgs[1],
678                                 self.loop4),
679                    VppGbpRecirc(self, epgs[2],
680                                 self.loop5),
681                    VppGbpRecirc(self, epgs[3],
682                                 self.loop6, is_ext=True),
683                    VppGbpRecirc(self, epgs[4],
684                                 self.loop7, is_ext=True)]
685
686         epg_nat = epgs[3]
687         recirc_nat = recircs[3]
688
689         #
690         # 4 end-points, 2 in the same subnet, 3 in the same BD
691         #
692         eps = [VppGbpEndpoint(self, self.pg0,
693                               epgs[0], recircs[0],
694                               "10.0.0.1", "11.0.0.1",
695                               "2001:10::1", "3001::1"),
696                VppGbpEndpoint(self, self.pg1,
697                               epgs[0], recircs[0],
698                               "10.0.0.2", "11.0.0.2",
699                               "2001:10::2", "3001::2"),
700                VppGbpEndpoint(self, self.pg2,
701                               epgs[1], recircs[1],
702                               "10.0.1.1", "11.0.0.3",
703                               "2001:10:1::1", "3001::3"),
704                VppGbpEndpoint(self, self.pg3,
705                               epgs[2], recircs[2],
706                               "10.0.2.1", "11.0.0.4",
707                               "2001:10:2::1", "3001::4")]
708
709         #
710         # Config related to each of the EPGs
711         #
712         for epg in epgs:
713             # IP config on the BVI interfaces
714             if epg != epgs[1] and epg != epgs[4]:
715                 VppIpInterfaceBind(self, epg.bvi, epg.rd.t4).add_vpp_config()
716                 VppIpInterfaceBind(self, epg.bvi, epg.rd.t6).add_vpp_config()
717                 self.vapi.sw_interface_set_mac_address(
718                     epg.bvi.sw_if_index,
719                     self.router_mac.bytes)
720
721                 # The BVIs are NAT inside interfaces
722                 self.vapi.nat44_interface_add_del_feature(epg.bvi.sw_if_index,
723                                                           is_inside=1,
724                                                           is_add=1)
725                 self.vapi.nat66_add_del_interface(epg.bvi.sw_if_index,
726                                                   is_inside=1,
727                                                   is_add=1)
728
729             if_ip4 = VppIpInterfaceAddress(self, epg.bvi, epg.bvi_ip4, 32)
730             if_ip6 = VppIpInterfaceAddress(self, epg.bvi, epg.bvi_ip6, 128)
731             if_ip4.add_vpp_config()
732             if_ip6.add_vpp_config()
733
734             # EPG uplink interfaces in the RD
735             VppIpInterfaceBind(self, epg.uplink, epg.rd.t4).add_vpp_config()
736             VppIpInterfaceBind(self, epg.uplink, epg.rd.t6).add_vpp_config()
737
738             # add the BD ARP termination entry for BVI IP
739             epg.bd_arp_ip4 = VppBridgeDomainArpEntry(self, epg.bd.bd,
740                                                      self.router_mac.address,
741                                                      epg.bvi_ip4)
742             epg.bd_arp_ip6 = VppBridgeDomainArpEntry(self, epg.bd.bd,
743                                                      self.router_mac.address,
744                                                      epg.bvi_ip6)
745             epg.bd_arp_ip4.add_vpp_config()
746             epg.bd_arp_ip6.add_vpp_config()
747
748             # EPG in VPP
749             epg.add_vpp_config()
750
751         for recirc in recircs:
752             # EPG's ingress recirculation interface maps to its RD
753             VppIpInterfaceBind(self, recirc.recirc,
754                                recirc.epg.rd.t4).add_vpp_config()
755             VppIpInterfaceBind(self, recirc.recirc,
756                                recirc.epg.rd.t6).add_vpp_config()
757
758             self.vapi.sw_interface_set_l2_emulation(
759                 recirc.recirc.sw_if_index)
760             self.vapi.nat44_interface_add_del_feature(
761                 recirc.recirc.sw_if_index,
762                 is_inside=0,
763                 is_add=1)
764             self.vapi.nat66_add_del_interface(
765                 recirc.recirc.sw_if_index,
766                 is_inside=0,
767                 is_add=1)
768
769             recirc.add_vpp_config()
770
771         for recirc in recircs:
772             self.assertTrue(find_bridge_domain_port(self,
773                                                     recirc.epg.bd.bd.bd_id,
774                                                     recirc.recirc.sw_if_index))
775
776         for ep in eps:
777             self.pg_enable_capture(self.pg_interfaces)
778             self.pg_start()
779             #
780             # routes to the endpoints. We need these since there are no
781             # adj-fibs due to the fact the the BVI address has /32 and
782             # the subnet is not attached.
783             #
784             for (ip, fip) in zip(ep.ips, ep.fips):
785                 # Add static mappings for each EP from the 10/8 to 11/8 network
786                 if ip.af == AF_INET:
787                     self.vapi.nat44_add_del_static_mapping(ip.bytes,
788                                                            fip.bytes,
789                                                            vrf_id=0,
790                                                            addr_only=1)
791                 else:
792                     self.vapi.nat66_add_del_static_mapping(ip.bytes,
793                                                            fip.bytes,
794                                                            vrf_id=0)
795
796             # VPP EP create ...
797             ep.add_vpp_config()
798
799             self.logger.info(self.vapi.cli("sh gbp endpoint"))
800
801             # ... results in a Gratuitous ARP/ND on the EPG's uplink
802             rx = ep.epg.uplink.get_capture(len(ep.ips), timeout=0.2)
803
804             for ii, ip in enumerate(ep.ips):
805                 p = rx[ii]
806
807                 if ip.is_ip6:
808                     self.assertTrue(p.haslayer(ICMPv6ND_NA))
809                     self.assertEqual(p[ICMPv6ND_NA].tgt, ip.address)
810                 else:
811                     self.assertTrue(p.haslayer(ARP))
812                     self.assertEqual(p[ARP].psrc, ip.address)
813                     self.assertEqual(p[ARP].pdst, ip.address)
814
815             # add the BD ARP termination entry for floating IP
816             for fip in ep.fips:
817                 ba = VppBridgeDomainArpEntry(self, epg_nat.bd.bd, ep.mac, fip)
818                 ba.add_vpp_config()
819
820                 # floating IPs route via EPG recirc
821                 r = VppIpRoute(self, fip.address, fip.length,
822                                [VppRoutePath(fip.address,
823                                              ep.recirc.recirc.sw_if_index,
824                                              is_dvr=1,
825                                              proto=fip.dpo_proto)],
826                                table_id=20,
827                                is_ip6=fip.is_ip6)
828                 r.add_vpp_config()
829
830             # L2 FIB entries in the NAT EPG BD to bridge the packets from
831             # the outside direct to the internal EPG
832             lf = VppL2FibEntry(self, epg_nat.bd.bd, ep.mac,
833                                ep.recirc.recirc, bvi_mac=0)
834             lf.add_vpp_config()
835
836         #
837         # ARP packets for unknown IP are sent to the EPG uplink
838         #
839         pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff",
840                          src=self.pg0.remote_mac) /
841                    ARP(op="who-has",
842                        hwdst="ff:ff:ff:ff:ff:ff",
843                        hwsrc=self.pg0.remote_mac,
844                        pdst="10.0.0.88",
845                        psrc="10.0.0.99"))
846
847         self.vapi.cli("clear trace")
848         self.pg0.add_stream(pkt_arp)
849
850         self.pg_enable_capture(self.pg_interfaces)
851         self.pg_start()
852
853         rxd = epgs[0].uplink.get_capture(1)
854
855         #
856         # ARP/ND packets get a response
857         #
858         pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff",
859                          src=self.pg0.remote_mac) /
860                    ARP(op="who-has",
861                        hwdst="ff:ff:ff:ff:ff:ff",
862                        hwsrc=self.pg0.remote_mac,
863                        pdst=epgs[0].bvi_ip4.address,
864                        psrc=eps[0].ip4.address))
865
866         self.send_and_expect(self.pg0, [pkt_arp], self.pg0)
867
868         nsma = in6_getnsma(inet_pton(AF_INET6, eps[0].ip6.address))
869         d = inet_ntop(AF_INET6, nsma)
870         pkt_nd = (Ether(dst=in6_getnsmac(nsma),
871                         src=self.pg0.remote_mac) /
872                   IPv6(dst=d, src=eps[0].ip6.address) /
873                   ICMPv6ND_NS(tgt=epgs[0].bvi_ip6.address) /
874                   ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac))
875         self.send_and_expect(self.pg0, [pkt_nd], self.pg0)
876
877         #
878         # broadcast packets are flooded
879         #
880         pkt_bcast = (Ether(dst="ff:ff:ff:ff:ff:ff",
881                            src=self.pg0.remote_mac) /
882                      IP(src=eps[0].ip4.address, dst="232.1.1.1") /
883                      UDP(sport=1234, dport=1234) /
884                      Raw('\xa5' * 100))
885
886         self.vapi.cli("clear trace")
887         self.pg0.add_stream(pkt_bcast)
888
889         self.pg_enable_capture(self.pg_interfaces)
890         self.pg_start()
891
892         rxd = eps[1].itf.get_capture(1)
893         self.assertEqual(rxd[0][Ether].dst, pkt_bcast[Ether].dst)
894         rxd = epgs[0].uplink.get_capture(1)
895         self.assertEqual(rxd[0][Ether].dst, pkt_bcast[Ether].dst)
896
897         #
898         # packets to non-local L3 destinations dropped
899         #
900         pkt_intra_epg_220_ip4 = (Ether(src=self.pg0.remote_mac,
901                                        dst=self.router_mac.address) /
902                                  IP(src=eps[0].ip4.address,
903                                     dst="10.0.0.99") /
904                                  UDP(sport=1234, dport=1234) /
905                                  Raw('\xa5' * 100))
906         pkt_inter_epg_222_ip4 = (Ether(src=self.pg0.remote_mac,
907                                        dst=self.router_mac.address) /
908                                  IP(src=eps[0].ip4.address,
909                                     dst="10.0.1.99") /
910                                  UDP(sport=1234, dport=1234) /
911                                  Raw('\xa5' * 100))
912
913         self.send_and_assert_no_replies(self.pg0, pkt_intra_epg_220_ip4 * 65)
914
915         pkt_inter_epg_222_ip6 = (Ether(src=self.pg0.remote_mac,
916                                        dst=self.router_mac.address) /
917                                  IPv6(src=eps[0].ip6.address,
918                                       dst="2001:10::99") /
919                                  UDP(sport=1234, dport=1234) /
920                                  Raw('\xa5' * 100))
921         self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_222_ip6 * 65)
922
923         #
924         # Add the subnet routes
925         #
926         s41 = VppGbpSubnet(
927             self, rd0, "10.0.0.0", 24,
928             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
929         s42 = VppGbpSubnet(
930             self, rd0, "10.0.1.0", 24,
931             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
932         s43 = VppGbpSubnet(
933             self, rd0, "10.0.2.0", 24,
934             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
935         s61 = VppGbpSubnet(
936             self, rd0, "2001:10::1", 64,
937             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
938         s62 = VppGbpSubnet(
939             self, rd0, "2001:10:1::1", 64,
940             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
941         s63 = VppGbpSubnet(
942             self, rd0, "2001:10:2::1", 64,
943             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
944         s41.add_vpp_config()
945         s42.add_vpp_config()
946         s43.add_vpp_config()
947         s61.add_vpp_config()
948         s62.add_vpp_config()
949         s63.add_vpp_config()
950
951         self.send_and_expect_bridged(eps[0].itf,
952                                      pkt_intra_epg_220_ip4 * 65,
953                                      eps[0].epg.uplink)
954         self.send_and_expect_bridged(eps[0].itf,
955                                      pkt_inter_epg_222_ip4 * 65,
956                                      eps[0].epg.uplink)
957         self.send_and_expect_bridged6(eps[0].itf,
958                                       pkt_inter_epg_222_ip6 * 65,
959                                       eps[0].epg.uplink)
960
961         self.logger.info(self.vapi.cli("sh ip fib 11.0.0.2"))
962         self.logger.info(self.vapi.cli("sh gbp endpoint-group"))
963         self.logger.info(self.vapi.cli("sh gbp endpoint"))
964         self.logger.info(self.vapi.cli("sh gbp recirc"))
965         self.logger.info(self.vapi.cli("sh int"))
966         self.logger.info(self.vapi.cli("sh int addr"))
967         self.logger.info(self.vapi.cli("sh int feat loop6"))
968         self.logger.info(self.vapi.cli("sh vlib graph ip4-gbp-src-classify"))
969         self.logger.info(self.vapi.cli("sh int feat loop3"))
970         self.logger.info(self.vapi.cli("sh int feat pg0"))
971
972         #
973         # Packet destined to unknown unicast is sent on the epg uplink ...
974         #
975         pkt_intra_epg_220_to_uplink = (Ether(src=self.pg0.remote_mac,
976                                              dst="00:00:00:33:44:55") /
977                                        IP(src=eps[0].ip4.address,
978                                           dst="10.0.0.99") /
979                                        UDP(sport=1234, dport=1234) /
980                                        Raw('\xa5' * 100))
981
982         self.send_and_expect_bridged(eps[0].itf,
983                                      pkt_intra_epg_220_to_uplink * 65,
984                                      eps[0].epg.uplink)
985         # ... and nowhere else
986         self.pg1.get_capture(0, timeout=0.1)
987         self.pg1.assert_nothing_captured(remark="Flood onto other VMS")
988
989         pkt_intra_epg_221_to_uplink = (Ether(src=self.pg2.remote_mac,
990                                              dst="00:00:00:33:44:66") /
991                                        IP(src=eps[0].ip4.address,
992                                           dst="10.0.0.99") /
993                                        UDP(sport=1234, dport=1234) /
994                                        Raw('\xa5' * 100))
995
996         self.send_and_expect_bridged(eps[2].itf,
997                                      pkt_intra_epg_221_to_uplink * 65,
998                                      eps[2].epg.uplink)
999
1000         #
1001         # Packets from the uplink are forwarded in the absence of a contract
1002         #
1003         pkt_intra_epg_220_from_uplink = (Ether(src="00:00:00:33:44:55",
1004                                                dst=self.pg0.remote_mac) /
1005                                          IP(src=eps[0].ip4.address,
1006                                             dst="10.0.0.99") /
1007                                          UDP(sport=1234, dport=1234) /
1008                                          Raw('\xa5' * 100))
1009
1010         self.send_and_expect_bridged(self.pg4,
1011                                      pkt_intra_epg_220_from_uplink * 65,
1012                                      self.pg0)
1013
1014         #
1015         # in the absence of policy, endpoints in the same EPG
1016         # can communicate
1017         #
1018         pkt_intra_epg = (Ether(src=self.pg0.remote_mac,
1019                                dst=self.pg1.remote_mac) /
1020                          IP(src=eps[0].ip4.address,
1021                             dst=eps[1].ip4.address) /
1022                          UDP(sport=1234, dport=1234) /
1023                          Raw('\xa5' * 100))
1024
1025         self.send_and_expect_bridged(self.pg0, pkt_intra_epg * 65, self.pg1)
1026
1027         #
1028         # in the abscense of policy, endpoints in the different EPG
1029         # cannot communicate
1030         #
1031         pkt_inter_epg_220_to_221 = (Ether(src=self.pg0.remote_mac,
1032                                           dst=self.pg2.remote_mac) /
1033                                     IP(src=eps[0].ip4.address,
1034                                        dst=eps[2].ip4.address) /
1035                                     UDP(sport=1234, dport=1234) /
1036                                     Raw('\xa5' * 100))
1037         pkt_inter_epg_221_to_220 = (Ether(src=self.pg2.remote_mac,
1038                                           dst=self.pg0.remote_mac) /
1039                                     IP(src=eps[2].ip4.address,
1040                                        dst=eps[0].ip4.address) /
1041                                     UDP(sport=1234, dport=1234) /
1042                                     Raw('\xa5' * 100))
1043         pkt_inter_epg_220_to_222 = (Ether(src=self.pg0.remote_mac,
1044                                           dst=self.router_mac.address) /
1045                                     IP(src=eps[0].ip4.address,
1046                                        dst=eps[3].ip4.address) /
1047                                     UDP(sport=1234, dport=1234) /
1048                                     Raw('\xa5' * 100))
1049
1050         self.send_and_assert_no_replies(eps[0].itf,
1051                                         pkt_inter_epg_220_to_221 * 65)
1052         self.send_and_assert_no_replies(eps[0].itf,
1053                                         pkt_inter_epg_220_to_222 * 65)
1054
1055         #
1056         # A uni-directional contract from EPG 220 -> 221
1057         #
1058         acl = VppGbpAcl(self)
1059         rule = acl.create_rule(permit_deny=1, proto=17)
1060         rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
1061         acl_index = acl.add_vpp_config([rule, rule2])
1062         c1 = VppGbpContract(self, 220, 221, acl_index)
1063         c1.add_vpp_config()
1064
1065         self.send_and_expect_bridged(eps[0].itf,
1066                                      pkt_inter_epg_220_to_221 * 65,
1067                                      eps[2].itf)
1068         self.send_and_assert_no_replies(eps[0].itf,
1069                                         pkt_inter_epg_220_to_222 * 65)
1070
1071         #
1072         # contract for the return direction
1073         #
1074         c2 = VppGbpContract(self, 221, 220, acl_index)
1075         c2.add_vpp_config()
1076
1077         self.send_and_expect_bridged(eps[0].itf,
1078                                      pkt_inter_epg_220_to_221 * 65,
1079                                      eps[2].itf)
1080         self.send_and_expect_bridged(eps[2].itf,
1081                                      pkt_inter_epg_221_to_220 * 65,
1082                                      eps[0].itf)
1083
1084         #
1085         # check that inter group is still disabled for the groups
1086         # not in the contract.
1087         #
1088         self.send_and_assert_no_replies(eps[0].itf,
1089                                         pkt_inter_epg_220_to_222 * 65)
1090
1091         #
1092         # A uni-directional contract from EPG 220 -> 222 'L3 routed'
1093         #
1094         c3 = VppGbpContract(self, 220, 222, acl_index)
1095         c3.add_vpp_config()
1096
1097         self.logger.info(self.vapi.cli("sh gbp contract"))
1098
1099         self.send_and_expect_routed(eps[0].itf,
1100                                     pkt_inter_epg_220_to_222 * 65,
1101                                     eps[3].itf,
1102                                     self.router_mac.address)
1103
1104         #
1105         # remove both contracts, traffic stops in both directions
1106         #
1107         c2.remove_vpp_config()
1108         c1.remove_vpp_config()
1109         c3.remove_vpp_config()
1110         acl.remove_vpp_config()
1111
1112         self.send_and_assert_no_replies(eps[2].itf,
1113                                         pkt_inter_epg_221_to_220 * 65)
1114         self.send_and_assert_no_replies(eps[0].itf,
1115                                         pkt_inter_epg_220_to_221 * 65)
1116         self.send_and_expect_bridged(eps[0].itf,
1117                                      pkt_intra_epg * 65,
1118                                      eps[1].itf)
1119
1120         #
1121         # EPs to the outside world
1122         #
1123
1124         # in the EP's RD an external subnet via the NAT EPG's recirc
1125         se1 = VppGbpSubnet(
1126             self, rd0, "0.0.0.0", 0,
1127             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1128             sw_if_index=recirc_nat.recirc.sw_if_index,
1129             epg=epg_nat.epg)
1130         se2 = VppGbpSubnet(
1131             self, rd0, "11.0.0.0", 8,
1132             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1133             sw_if_index=recirc_nat.recirc.sw_if_index,
1134             epg=epg_nat.epg)
1135         se16 = VppGbpSubnet(
1136             self, rd0, "::", 0,
1137             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1138             sw_if_index=recirc_nat.recirc.sw_if_index,
1139             epg=epg_nat.epg)
1140         # in the NAT RD an external subnet via the NAT EPG's uplink
1141         se3 = VppGbpSubnet(
1142             self, rd20, "0.0.0.0", 0,
1143             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1144             sw_if_index=epg_nat.uplink.sw_if_index,
1145             epg=epg_nat.epg)
1146         se36 = VppGbpSubnet(
1147             self, rd20, "::", 0,
1148             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1149             sw_if_index=epg_nat.uplink.sw_if_index,
1150             epg=epg_nat.epg)
1151         se4 = VppGbpSubnet(
1152             self, rd20, "11.0.0.0", 8,
1153             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1154             sw_if_index=epg_nat.uplink.sw_if_index,
1155             epg=epg_nat.epg)
1156         se1.add_vpp_config()
1157         se2.add_vpp_config()
1158         se16.add_vpp_config()
1159         se3.add_vpp_config()
1160         se36.add_vpp_config()
1161         se4.add_vpp_config()
1162
1163         self.logger.info(self.vapi.cli("sh ip fib 0.0.0.0/0"))
1164         self.logger.info(self.vapi.cli("sh ip fib 11.0.0.1"))
1165         self.logger.info(self.vapi.cli("sh ip6 fib ::/0"))
1166         self.logger.info(self.vapi.cli("sh ip6 fib %s" %
1167                                        eps[0].fip6))
1168
1169         #
1170         # From an EP to an outside addess: IN2OUT
1171         #
1172         pkt_inter_epg_220_to_global = (Ether(src=self.pg0.remote_mac,
1173                                              dst=self.router_mac.address) /
1174                                        IP(src=eps[0].ip4.address,
1175                                           dst="1.1.1.1") /
1176                                        UDP(sport=1234, dport=1234) /
1177                                        Raw('\xa5' * 100))
1178
1179         # no policy yet
1180         self.send_and_assert_no_replies(eps[0].itf,
1181                                         pkt_inter_epg_220_to_global * 65)
1182
1183         acl2 = VppGbpAcl(self)
1184         rule = acl2.create_rule(permit_deny=1, proto=17, sport_from=1234,
1185                                 sport_to=1234, dport_from=1234, dport_to=1234)
1186         rule2 = acl2.create_rule(is_ipv6=1, permit_deny=1, proto=17,
1187                                  sport_from=1234, sport_to=1234,
1188                                  dport_from=1234, dport_to=1234)
1189
1190         acl_index2 = acl2.add_vpp_config([rule, rule2])
1191         c4 = VppGbpContract(self, 220, 333, acl_index2)
1192         c4.add_vpp_config()
1193
1194         self.send_and_expect_natted(eps[0].itf,
1195                                     pkt_inter_epg_220_to_global * 65,
1196                                     self.pg7,
1197                                     eps[0].fip4.address)
1198
1199         pkt_inter_epg_220_to_global = (Ether(src=self.pg0.remote_mac,
1200                                              dst=self.router_mac.address) /
1201                                        IPv6(src=eps[0].ip6.address,
1202                                             dst="6001::1") /
1203                                        UDP(sport=1234, dport=1234) /
1204                                        Raw('\xa5' * 100))
1205
1206         self.send_and_expect_natted6(self.pg0,
1207                                      pkt_inter_epg_220_to_global * 65,
1208                                      self.pg7,
1209                                      eps[0].fip6.address)
1210
1211         #
1212         # From a global address to an EP: OUT2IN
1213         #
1214         pkt_inter_epg_220_from_global = (Ether(src=self.router_mac.address,
1215                                                dst=self.pg0.remote_mac) /
1216                                          IP(dst=eps[0].fip4.address,
1217                                             src="1.1.1.1") /
1218                                          UDP(sport=1234, dport=1234) /
1219                                          Raw('\xa5' * 100))
1220
1221         self.send_and_assert_no_replies(self.pg7,
1222                                         pkt_inter_epg_220_from_global * 65)
1223
1224         c5 = VppGbpContract(self, 333, 220, acl_index2)
1225         c5.add_vpp_config()
1226
1227         self.send_and_expect_unnatted(self.pg7,
1228                                       pkt_inter_epg_220_from_global * 65,
1229                                       eps[0].itf,
1230                                       eps[0].ip4.address)
1231
1232         pkt_inter_epg_220_from_global = (Ether(src=self.router_mac.address,
1233                                                dst=self.pg0.remote_mac) /
1234                                          IPv6(dst=eps[0].fip6.address,
1235                                               src="6001::1") /
1236                                          UDP(sport=1234, dport=1234) /
1237                                          Raw('\xa5' * 100))
1238
1239         self.send_and_expect_unnatted6(self.pg7,
1240                                        pkt_inter_epg_220_from_global * 65,
1241                                        eps[0].itf,
1242                                        eps[0].ip6.address)
1243
1244         #
1245         # From a local VM to another local VM using resp. public addresses:
1246         #  IN2OUT2IN
1247         #
1248         pkt_intra_epg_220_global = (Ether(src=self.pg0.remote_mac,
1249                                           dst=self.router_mac.address) /
1250                                     IP(src=eps[0].ip4.address,
1251                                        dst=eps[1].fip4.address) /
1252                                     UDP(sport=1234, dport=1234) /
1253                                     Raw('\xa5' * 100))
1254
1255         self.send_and_expect_double_natted(eps[0].itf,
1256                                            pkt_intra_epg_220_global * 65,
1257                                            eps[1].itf,
1258                                            eps[0].fip4.address,
1259                                            eps[1].ip4.address)
1260
1261         pkt_intra_epg_220_global = (Ether(src=self.pg0.remote_mac,
1262                                           dst=self.router_mac.address) /
1263                                     IPv6(src=eps[0].ip6.address,
1264                                          dst=eps[1].fip6.address) /
1265                                     UDP(sport=1234, dport=1234) /
1266                                     Raw('\xa5' * 100))
1267
1268         self.send_and_expect_double_natted6(eps[0].itf,
1269                                             pkt_intra_epg_220_global * 65,
1270                                             eps[1].itf,
1271                                             eps[0].fip6.address,
1272                                             eps[1].ip6.address)
1273
1274         #
1275         # cleanup
1276         #
1277         for ep in eps:
1278             # del static mappings for each EP from the 10/8 to 11/8 network
1279             self.vapi.nat44_add_del_static_mapping(ep.ip4.bytes,
1280                                                    ep.fip4.bytes,
1281                                                    vrf_id=0,
1282                                                    addr_only=1,
1283                                                    is_add=0)
1284             self.vapi.nat66_add_del_static_mapping(ep.ip6.bytes,
1285                                                    ep.fip6.bytes,
1286                                                    vrf_id=0,
1287                                                    is_add=0)
1288
1289         for epg in epgs:
1290             # IP config on the BVI interfaces
1291             if epg != epgs[0] and epg != epgs[3]:
1292                 self.vapi.nat44_interface_add_del_feature(epg.bvi.sw_if_index,
1293                                                           is_inside=1,
1294                                                           is_add=0)
1295                 self.vapi.nat66_add_del_interface(epg.bvi.sw_if_index,
1296                                                   is_inside=1,
1297                                                   is_add=0)
1298
1299         for recirc in recircs:
1300             self.vapi.sw_interface_set_l2_emulation(
1301                 recirc.recirc.sw_if_index, enable=0)
1302             self.vapi.nat44_interface_add_del_feature(
1303                 recirc.recirc.sw_if_index,
1304                 is_inside=0,
1305                 is_add=0)
1306             self.vapi.nat66_add_del_interface(
1307                 recirc.recirc.sw_if_index,
1308                 is_inside=0,
1309                 is_add=0)
1310
1311     def test_gbp_learn_l2(self):
1312         """ GBP L2 Endpoint Learning """
1313
1314         learnt = [{'mac': '00:00:11:11:11:01',
1315                    'ip': '10.0.0.1',
1316                    'ip6': '2001:10::2'},
1317                   {'mac': '00:00:11:11:11:02',
1318                    'ip': '10.0.0.2',
1319                    'ip6': '2001:10::3'}]
1320
1321         #
1322         # lower the inactive threshold so these tests pass in a
1323         # reasonable amount of time
1324         #
1325         self.vapi.gbp_endpoint_learn_set_inactive_threshold(1)
1326
1327         #
1328         # IP tables
1329         #
1330         gt4 = VppIpTable(self, 1)
1331         gt4.add_vpp_config()
1332         gt6 = VppIpTable(self, 1, is_ip6=True)
1333         gt6.add_vpp_config()
1334
1335         rd1 = VppGbpRouteDomain(self, 1, gt4, gt6)
1336         rd1.add_vpp_config()
1337
1338         #
1339         # Pg2 hosts the vxlan tunnel, hosts on pg2 to act as TEPs
1340         # Pg3 hosts the IP4 UU-flood VXLAN tunnel
1341         # Pg4 hosts the IP6 UU-flood VXLAN tunnel
1342         #
1343         self.pg2.config_ip4()
1344         self.pg2.resolve_arp()
1345         self.pg2.generate_remote_hosts(4)
1346         self.pg2.configure_ipv4_neighbors()
1347         self.pg3.config_ip4()
1348         self.pg3.resolve_arp()
1349         self.pg4.config_ip4()
1350         self.pg4.resolve_arp()
1351
1352         #
1353         # a GBP bridge domain with a BVI and a UU-flood interface
1354         #
1355         bd1 = VppBridgeDomain(self, 1)
1356         bd1.add_vpp_config()
1357         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0, self.pg3)
1358         gbd1.add_vpp_config()
1359
1360         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1361         self.logger.info(self.vapi.cli("sh gbp bridge"))
1362
1363         # ... and has a /32 applied
1364         ip_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
1365         ip_addr.add_vpp_config()
1366
1367         #
1368         # The Endpoint-group in which we are learning endpoints
1369         #
1370         epg_220 = VppGbpEndpointGroup(self, 220, rd1, gbd1,
1371                                       None, self.loop0,
1372                                       "10.0.0.128",
1373                                       "2001:10::128")
1374         epg_220.add_vpp_config()
1375         epg_330 = VppGbpEndpointGroup(self, 330, rd1, gbd1,
1376                                       None, self.loop1,
1377                                       "10.0.1.128",
1378                                       "2001:11::128")
1379         epg_330.add_vpp_config()
1380
1381         #
1382         # The VXLAN GBP tunnel is a bridge-port and has L2 endpoint
1383         # leanring enabled
1384         #
1385         vx_tun_l2_1 = VppGbpVxlanTunnel(
1386             self, 99, bd1.bd_id,
1387             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L2)
1388         vx_tun_l2_1.add_vpp_config()
1389
1390         #
1391         # A static endpoint that the learnt endpoints are trying to
1392         # talk to
1393         #
1394         ep = VppGbpEndpoint(self, self.pg0,
1395                             epg_220, None,
1396                             "10.0.0.127", "11.0.0.127",
1397                             "2001:10::1", "3001::1")
1398         ep.add_vpp_config()
1399
1400         self.assertTrue(find_route(self, ep.ip4.address, 32, table_id=1))
1401
1402         # a packet with an sclass from an unknwon EPG
1403         p = (Ether(src=self.pg2.remote_mac,
1404                    dst=self.pg2.local_mac) /
1405              IP(src=self.pg2.remote_hosts[0].ip4,
1406                 dst=self.pg2.local_ip4) /
1407              UDP(sport=1234, dport=48879) /
1408              VXLAN(vni=99, gpid=88, flags=0x88) /
1409              Ether(src=learnt[0]["mac"], dst=ep.mac) /
1410              IP(src=learnt[0]["ip"], dst=ep.ip4.address) /
1411              UDP(sport=1234, dport=1234) /
1412              Raw('\xa5' * 100))
1413
1414         self.send_and_assert_no_replies(self.pg2, p)
1415
1416         #
1417         # we should not have learnt a new tunnel endpoint, since
1418         # the EPG was not learnt.
1419         #
1420         self.assertEqual(INDEX_INVALID,
1421                          find_vxlan_gbp_tunnel(self,
1422                                                self.pg2.local_ip4,
1423                                                self.pg2.remote_hosts[0].ip4,
1424                                                99))
1425
1426         # epg is not learnt, becasue the EPG is unknwon
1427         self.assertEqual(len(self.vapi.gbp_endpoint_dump()), 1)
1428
1429         for ii, l in enumerate(learnt):
1430             # a packet with an sclass from a knwon EPG
1431             # arriving on an unknown TEP
1432             p = (Ether(src=self.pg2.remote_mac,
1433                        dst=self.pg2.local_mac) /
1434                  IP(src=self.pg2.remote_hosts[1].ip4,
1435                     dst=self.pg2.local_ip4) /
1436                  UDP(sport=1234, dport=48879) /
1437                  VXLAN(vni=99, gpid=220, flags=0x88) /
1438                  Ether(src=l['mac'], dst=ep.mac) /
1439                  IP(src=l['ip'], dst=ep.ip4.address) /
1440                  UDP(sport=1234, dport=1234) /
1441                  Raw('\xa5' * 100))
1442
1443             rx = self.send_and_expect(self.pg2, [p], self.pg0)
1444
1445             # the new TEP
1446             tep1_sw_if_index = find_vxlan_gbp_tunnel(
1447                 self,
1448                 self.pg2.local_ip4,
1449                 self.pg2.remote_hosts[1].ip4,
1450                 99)
1451             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
1452
1453             #
1454             # the EP is learnt via the learnt TEP
1455             # both from its MAC and its IP
1456             #
1457             self.assertTrue(find_gbp_endpoint(self,
1458                                               vx_tun_l2_1.sw_if_index,
1459                                               mac=l['mac']))
1460             self.assertTrue(find_gbp_endpoint(self,
1461                                               vx_tun_l2_1.sw_if_index,
1462                                               ip=l['ip']))
1463
1464         self.logger.info(self.vapi.cli("show gbp endpoint"))
1465         self.logger.info(self.vapi.cli("show gbp vxlan"))
1466         self.logger.info(self.vapi.cli("show vxlan-gbp tunnel"))
1467
1468         #
1469         # If we sleep for the threshold time, the learnt endpoints should
1470         # age out
1471         #
1472         self.sleep(2)
1473         for l in learnt:
1474             self.assertFalse(find_gbp_endpoint(self,
1475                                                tep1_sw_if_index,
1476                                                mac=l['mac']))
1477
1478         self.logger.info(self.vapi.cli("show gbp endpoint"))
1479         self.logger.info(self.vapi.cli("show gbp vxlan"))
1480         self.logger.info(self.vapi.cli("show vxlan-gbp tunnel"))
1481
1482         #
1483         # repeat. the do not learn bit is set so the EPs are not learnt
1484         #
1485         for l in learnt:
1486             # a packet with an sclass from a knwon EPG
1487             p = (Ether(src=self.pg2.remote_mac,
1488                        dst=self.pg2.local_mac) /
1489                  IP(src=self.pg2.remote_hosts[1].ip4,
1490                     dst=self.pg2.local_ip4) /
1491                  UDP(sport=1234, dport=48879) /
1492                  VXLAN(vni=99, gpid=220, flags=0x88, gpflags="D") /
1493                  Ether(src=l['mac'], dst=ep.mac) /
1494                  IP(src=l['ip'], dst=ep.ip4.address) /
1495                  UDP(sport=1234, dport=1234) /
1496                  Raw('\xa5' * 100))
1497
1498             rx = self.send_and_expect(self.pg2, p*65, self.pg0)
1499
1500         for l in learnt:
1501             self.assertFalse(find_gbp_endpoint(self,
1502                                                vx_tun_l2_1.sw_if_index,
1503                                                mac=l['mac']))
1504
1505         #
1506         # repeat
1507         #
1508         for l in learnt:
1509             # a packet with an sclass from a knwon EPG
1510             p = (Ether(src=self.pg2.remote_mac,
1511                        dst=self.pg2.local_mac) /
1512                  IP(src=self.pg2.remote_hosts[1].ip4,
1513                     dst=self.pg2.local_ip4) /
1514                  UDP(sport=1234, dport=48879) /
1515                  VXLAN(vni=99, gpid=220, flags=0x88) /
1516                  Ether(src=l['mac'], dst=ep.mac) /
1517                  IP(src=l['ip'], dst=ep.ip4.address) /
1518                  UDP(sport=1234, dport=1234) /
1519                  Raw('\xa5' * 100))
1520
1521             rx = self.send_and_expect(self.pg2, p*65, self.pg0)
1522
1523             self.assertTrue(find_gbp_endpoint(self,
1524                                               vx_tun_l2_1.sw_if_index,
1525                                               mac=l['mac']))
1526
1527         #
1528         # Static EP replies to dynamics
1529         #
1530         self.logger.info(self.vapi.cli("sh l2fib bd_id 1"))
1531         for l in learnt:
1532             p = (Ether(src=ep.mac, dst=l['mac']) /
1533                  IP(dst=l['ip'], src=ep.ip4.address) /
1534                  UDP(sport=1234, dport=1234) /
1535                  Raw('\xa5' * 100))
1536
1537             rxs = self.send_and_expect(self.pg0, p * 17, self.pg2)
1538
1539             for rx in rxs:
1540                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
1541                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
1542                 self.assertEqual(rx[UDP].dport, 48879)
1543                 # the UDP source port is a random value for hashing
1544                 self.assertEqual(rx[VXLAN].gpid, 220)
1545                 self.assertEqual(rx[VXLAN].vni, 99)
1546                 self.assertTrue(rx[VXLAN].flags.G)
1547                 self.assertTrue(rx[VXLAN].flags.Instance)
1548                 self.assertTrue(rx[VXLAN].gpflags.A)
1549                 self.assertFalse(rx[VXLAN].gpflags.D)
1550
1551         self.sleep(2)
1552         for l in learnt:
1553             self.assertFalse(find_gbp_endpoint(self,
1554                                                vx_tun_l2_1.sw_if_index,
1555                                                mac=l['mac']))
1556
1557         #
1558         # repeat in the other EPG
1559         # there's no contract between 220 and 330, but the A-bit is set
1560         # so the packet is cleared for delivery
1561         #
1562         for l in learnt:
1563             # a packet with an sclass from a knwon EPG
1564             p = (Ether(src=self.pg2.remote_mac,
1565                        dst=self.pg2.local_mac) /
1566                  IP(src=self.pg2.remote_hosts[1].ip4,
1567                     dst=self.pg2.local_ip4) /
1568                  UDP(sport=1234, dport=48879) /
1569                  VXLAN(vni=99, gpid=330, flags=0x88, gpflags='A') /
1570                  Ether(src=l['mac'], dst=ep.mac) /
1571                  IP(src=l['ip'], dst=ep.ip4.address) /
1572                  UDP(sport=1234, dport=1234) /
1573                  Raw('\xa5' * 100))
1574
1575             rx = self.send_and_expect(self.pg2, p*65, self.pg0)
1576
1577             self.assertTrue(find_gbp_endpoint(self,
1578                                               vx_tun_l2_1.sw_if_index,
1579                                               mac=l['mac']))
1580
1581         #
1582         # static EP cannot reach the learnt EPs since there is no contract
1583         #
1584         self.logger.info(self.vapi.cli("show gbp endpoint"))
1585         self.logger.info(self.vapi.cli("show l2fib all"))
1586         for l in learnt:
1587             p = (Ether(src=ep.mac, dst=l['mac']) /
1588                  IP(dst=l['ip'], src=ep.ip4.address) /
1589                  UDP(sport=1234, dport=1234) /
1590                  Raw('\xa5' * 100))
1591
1592             self.send_and_assert_no_replies(self.pg0, [p], timeout=0.2)
1593
1594         #
1595         # refresh the entries after the check for no replies above
1596         #
1597         for l in learnt:
1598             # a packet with an sclass from a knwon EPG
1599             p = (Ether(src=self.pg2.remote_mac,
1600                        dst=self.pg2.local_mac) /
1601                  IP(src=self.pg2.remote_hosts[1].ip4,
1602                     dst=self.pg2.local_ip4) /
1603                  UDP(sport=1234, dport=48879) /
1604                  VXLAN(vni=99, gpid=330, flags=0x88, gpflags='A') /
1605                  Ether(src=l['mac'], dst=ep.mac) /
1606                  IP(src=l['ip'], dst=ep.ip4.address) /
1607                  UDP(sport=1234, dport=1234) /
1608                  Raw('\xa5' * 100))
1609
1610             rx = self.send_and_expect(self.pg2, p*65, self.pg0)
1611
1612             self.assertTrue(find_gbp_endpoint(self,
1613                                               vx_tun_l2_1.sw_if_index,
1614                                               mac=l['mac']))
1615
1616         #
1617         # Add the contract so they can talk
1618         #
1619         acl = VppGbpAcl(self)
1620         rule = acl.create_rule(permit_deny=1, proto=17)
1621         rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
1622         acl_index = acl.add_vpp_config([rule, rule2])
1623         c1 = VppGbpContract(self, 220, 330, acl_index)
1624         c1.add_vpp_config()
1625
1626         for l in learnt:
1627             p = (Ether(src=ep.mac, dst=l['mac']) /
1628                  IP(dst=l['ip'], src=ep.ip4.address) /
1629                  UDP(sport=1234, dport=1234) /
1630                  Raw('\xa5' * 100))
1631
1632             self.send_and_expect(self.pg0, [p], self.pg2)
1633
1634         #
1635         # send UU packets from the local EP
1636         #
1637         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1638         self.logger.info(self.vapi.cli("sh gbp bridge"))
1639         p_uu = (Ether(src=ep.mac, dst="00:11:11:11:11:11") /
1640                 IP(dst="10.0.0.133", src=ep.ip4.address) /
1641                 UDP(sport=1234, dport=1234) /
1642                 Raw('\xa5' * 100))
1643         rxs = self.send_and_expect(ep.itf, [p_uu], gbd1.uu_flood)
1644
1645         #
1646         # Add a mcast destination VXLAN-GBP tunnel for B&M traffic
1647         #
1648         tun_bm = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
1649                                    "239.1.1.1", 88,
1650                                    mcast_itf=self.pg4)
1651         tun_bm.add_vpp_config()
1652         bp_bm = VppBridgeDomainPort(self, bd1, tun_bm,
1653                                     port_type=L2_PORT_TYPE.NORMAL)
1654         bp_bm.add_vpp_config()
1655
1656         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1657
1658         p_bm = (Ether(src=ep.mac, dst="ff:ff:ff:ff:ff:ff") /
1659                 IP(dst="10.0.0.133", src=ep.ip4.address) /
1660                 UDP(sport=1234, dport=1234) /
1661                 Raw('\xa5' * 100))
1662         rxs = self.send_and_expect_only(ep.itf, [p_bm], tun_bm.mcast_itf)
1663
1664         #
1665         # Check v6 Endpoints
1666         #
1667         for l in learnt:
1668             # a packet with an sclass from a knwon EPG
1669             p = (Ether(src=self.pg2.remote_mac,
1670                        dst=self.pg2.local_mac) /
1671                  IP(src=self.pg2.remote_hosts[1].ip4,
1672                     dst=self.pg2.local_ip4) /
1673                  UDP(sport=1234, dport=48879) /
1674                  VXLAN(vni=99, gpid=330, flags=0x88, gpflags='A') /
1675                  Ether(src=l['mac'], dst=ep.mac) /
1676                  IPv6(src=l['ip6'], dst=ep.ip6.address) /
1677                  UDP(sport=1234, dport=1234) /
1678                  Raw('\xa5' * 100))
1679
1680             rx = self.send_and_expect(self.pg2, p*65, self.pg0)
1681
1682             self.assertTrue(find_gbp_endpoint(self,
1683                                               vx_tun_l2_1.sw_if_index,
1684                                               mac=l['mac']))
1685
1686         #
1687         # L3 Endpoint Learning
1688         #  - configured on the bridge's BVI
1689         #
1690
1691         #
1692         # clean up
1693         #
1694         self.sleep(2)
1695         for l in learnt:
1696             self.assertFalse(find_gbp_endpoint(self,
1697                                                vx_tun_l2_1.sw_if_index,
1698                                                mac=l['mac']))
1699
1700         self.pg2.unconfig_ip4()
1701         self.pg3.unconfig_ip4()
1702         self.pg4.unconfig_ip4()
1703
1704         self.logger.info(self.vapi.cli("sh int"))
1705         self.logger.info(self.vapi.cli("sh gbp vxlan"))
1706
1707     def test_gbp_learn_vlan_l2(self):
1708         """ GBP L2 Endpoint w/ VLANs"""
1709
1710         learnt = [{'mac': '00:00:11:11:11:01',
1711                    'ip': '10.0.0.1',
1712                    'ip6': '2001:10::2'},
1713                   {'mac': '00:00:11:11:11:02',
1714                    'ip': '10.0.0.2',
1715                    'ip6': '2001:10::3'}]
1716
1717         #
1718         # lower the inactive threshold so these tests pass in a
1719         # reasonable amount of time
1720         #
1721         self.vapi.gbp_endpoint_learn_set_inactive_threshold(1)
1722
1723         #
1724         # IP tables
1725         #
1726         gt4 = VppIpTable(self, 1)
1727         gt4.add_vpp_config()
1728         gt6 = VppIpTable(self, 1, is_ip6=True)
1729         gt6.add_vpp_config()
1730
1731         rd1 = VppGbpRouteDomain(self, 1, gt4, gt6)
1732         rd1.add_vpp_config()
1733
1734         #
1735         # Pg2 hosts the vxlan tunnel, hosts on pg2 to act as TEPs
1736         #
1737         self.pg2.config_ip4()
1738         self.pg2.resolve_arp()
1739         self.pg2.generate_remote_hosts(4)
1740         self.pg2.configure_ipv4_neighbors()
1741         self.pg3.config_ip4()
1742         self.pg3.resolve_arp()
1743
1744         #
1745         # The EP will be on a vlan sub-interface
1746         #
1747         vlan_11 = VppDot1QSubint(self, self.pg0, 11)
1748         vlan_11.admin_up()
1749         self.vapi.sw_interface_set_l2_tag_rewrite(vlan_11.sw_if_index,
1750                                                   L2_VTR_OP.L2_POP_1,
1751                                                   11)
1752
1753         bd_uu_fwd = VppVxlanGbpTunnel(self, self.pg3.local_ip4,
1754                                       self.pg3.remote_ip4, 116)
1755         bd_uu_fwd.add_vpp_config()
1756
1757         #
1758         # a GBP bridge domain with a BVI and a UU-flood interface
1759         # The BD is marked as do not learn, so no endpoints are ever
1760         # learnt in this BD.
1761         #
1762         bd1 = VppBridgeDomain(self, 1)
1763         bd1.add_vpp_config()
1764         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0, bd_uu_fwd,
1765                                   learn=False)
1766         gbd1.add_vpp_config()
1767
1768         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1769         self.logger.info(self.vapi.cli("sh gbp bridge"))
1770
1771         # ... and has a /32 applied
1772         ip_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
1773         ip_addr.add_vpp_config()
1774
1775         #
1776         # The Endpoint-group in which we are learning endpoints
1777         #
1778         epg_220 = VppGbpEndpointGroup(self, 220, rd1, gbd1,
1779                                       None, self.loop0,
1780                                       "10.0.0.128",
1781                                       "2001:10::128")
1782         epg_220.add_vpp_config()
1783
1784         #
1785         # The VXLAN GBP tunnel is a bridge-port and has L2 endpoint
1786         # leanring enabled
1787         #
1788         vx_tun_l2_1 = VppGbpVxlanTunnel(
1789             self, 99, bd1.bd_id,
1790             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L2)
1791         vx_tun_l2_1.add_vpp_config()
1792
1793         #
1794         # A static endpoint that the learnt endpoints are trying to
1795         # talk to
1796         #
1797         ep = VppGbpEndpoint(self, vlan_11,
1798                             epg_220, None,
1799                             "10.0.0.127", "11.0.0.127",
1800                             "2001:10::1", "3001::1")
1801         ep.add_vpp_config()
1802
1803         self.assertTrue(find_route(self, ep.ip4.address, 32, table_id=1))
1804
1805         #
1806         # Send to the static EP
1807         #
1808         for ii, l in enumerate(learnt):
1809             # a packet with an sclass from a knwon EPG
1810             # arriving on an unknown TEP
1811             p = (Ether(src=self.pg2.remote_mac,
1812                        dst=self.pg2.local_mac) /
1813                  IP(src=self.pg2.remote_hosts[1].ip4,
1814                     dst=self.pg2.local_ip4) /
1815                  UDP(sport=1234, dport=48879) /
1816                  VXLAN(vni=99, gpid=220, flags=0x88) /
1817                  Ether(src=l['mac'], dst=ep.mac) /
1818                  IP(src=l['ip'], dst=ep.ip4.address) /
1819                  UDP(sport=1234, dport=1234) /
1820                  Raw('\xa5' * 100))
1821
1822             rxs = self.send_and_expect(self.pg2, [p], self.pg0)
1823
1824             #
1825             # packet to EP has the EP's vlan tag
1826             #
1827             for rx in rxs:
1828                 self.assertEqual(rx[Dot1Q].vlan, 11)
1829
1830             #
1831             # the EP is not learnt since the BD setting prevents it
1832             # also no TEP too
1833             #
1834             self.assertFalse(find_gbp_endpoint(self,
1835                                                vx_tun_l2_1.sw_if_index,
1836                                                mac=l['mac']))
1837             self.assertEqual(INDEX_INVALID,
1838                              find_vxlan_gbp_tunnel(
1839                                  self,
1840                                  self.pg2.local_ip4,
1841                                  self.pg2.remote_hosts[1].ip4,
1842                                  99))
1843
1844         self.assertEqual(len(self.vapi.gbp_endpoint_dump()), 1)
1845
1846         #
1847         # static to remotes
1848         # we didn't learn the remotes so they are sent to the UU-fwd
1849         #
1850         for l in learnt:
1851             p = (Ether(src=ep.mac, dst=l['mac']) /
1852                  Dot1Q(vlan=11) /
1853                  IP(dst=l['ip'], src=ep.ip4.address) /
1854                  UDP(sport=1234, dport=1234) /
1855                  Raw('\xa5' * 100))
1856
1857             rxs = self.send_and_expect(self.pg0, p * 17, self.pg3)
1858
1859             for rx in rxs:
1860                 self.assertEqual(rx[IP].src, self.pg3.local_ip4)
1861                 self.assertEqual(rx[IP].dst, self.pg3.remote_ip4)
1862                 self.assertEqual(rx[UDP].dport, 48879)
1863                 # the UDP source port is a random value for hashing
1864                 self.assertEqual(rx[VXLAN].gpid, 220)
1865                 self.assertEqual(rx[VXLAN].vni, 116)
1866                 self.assertTrue(rx[VXLAN].flags.G)
1867                 self.assertTrue(rx[VXLAN].flags.Instance)
1868                 self.assertFalse(rx[VXLAN].gpflags.A)
1869                 self.assertFalse(rx[VXLAN].gpflags.D)
1870
1871         self.pg2.unconfig_ip4()
1872         self.pg3.unconfig_ip4()
1873
1874     def test_gbp_learn_l3(self):
1875         """ GBP L3 Endpoint Learning """
1876
1877         routed_dst_mac = "00:0c:0c:0c:0c:0c"
1878         routed_src_mac = "00:22:bd:f8:19:ff"
1879
1880         learnt = [{'mac': '00:00:11:11:11:02',
1881                    'ip': '10.0.1.2',
1882                    'ip6': '2001:10::2'},
1883                   {'mac': '00:00:11:11:11:03',
1884                    'ip': '10.0.1.3',
1885                    'ip6': '2001:10::3'}]
1886
1887         #
1888         # lower the inactive threshold so these tests pass in a
1889         # reasonable amount of time
1890         #
1891         self.vapi.gbp_endpoint_learn_set_inactive_threshold(1)
1892
1893         #
1894         # IP tables
1895         #
1896         t4 = VppIpTable(self, 1)
1897         t4.add_vpp_config()
1898         t6 = VppIpTable(self, 1, True)
1899         t6.add_vpp_config()
1900
1901         tun_ip4_uu = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
1902                                        self.pg4.remote_ip4, 114)
1903         tun_ip6_uu = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
1904                                        self.pg4.remote_ip4, 116)
1905         tun_ip4_uu.add_vpp_config()
1906         tun_ip6_uu.add_vpp_config()
1907
1908         rd1 = VppGbpRouteDomain(self, 2, t4, t6, tun_ip4_uu, tun_ip6_uu)
1909         rd1.add_vpp_config()
1910
1911         self.loop0.set_mac(self.router_mac.address)
1912
1913         #
1914         # Bind the BVI to the RD
1915         #
1916         VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
1917         VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
1918
1919         #
1920         # Pg2 hosts the vxlan tunnel
1921         # hosts on pg2 to act as TEPs
1922         # pg3 is BD uu-fwd
1923         # pg4 is RD uu-fwd
1924         #
1925         self.pg2.config_ip4()
1926         self.pg2.resolve_arp()
1927         self.pg2.generate_remote_hosts(4)
1928         self.pg2.configure_ipv4_neighbors()
1929         self.pg3.config_ip4()
1930         self.pg3.resolve_arp()
1931         self.pg4.config_ip4()
1932         self.pg4.resolve_arp()
1933
1934         #
1935         # a GBP bridge domain with a BVI and a UU-flood interface
1936         #
1937         bd1 = VppBridgeDomain(self, 1)
1938         bd1.add_vpp_config()
1939         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0, self.pg3)
1940         gbd1.add_vpp_config()
1941
1942         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1943         self.logger.info(self.vapi.cli("sh gbp bridge"))
1944         self.logger.info(self.vapi.cli("sh gbp route"))
1945         self.logger.info(self.vapi.cli("show l2fib all"))
1946
1947         # ... and has a /32 and /128 applied
1948         ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
1949         ip4_addr.add_vpp_config()
1950         ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128", 128)
1951         ip6_addr.add_vpp_config()
1952
1953         #
1954         # The Endpoint-group in which we are learning endpoints
1955         #
1956         epg_220 = VppGbpEndpointGroup(self, 220, rd1, gbd1,
1957                                       None, self.loop0,
1958                                       "10.0.0.128",
1959                                       "2001:10::128")
1960         epg_220.add_vpp_config()
1961
1962         #
1963         # The VXLAN GBP tunnel is a bridge-port and has L2 endpoint
1964         # leanring enabled
1965         #
1966         vx_tun_l3 = VppGbpVxlanTunnel(
1967             self, 101, rd1.rd_id,
1968             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3)
1969         vx_tun_l3.add_vpp_config()
1970
1971         #
1972         # A static endpoint that the learnt endpoints are trying to
1973         # talk to
1974         #
1975         ep = VppGbpEndpoint(self, self.pg0,
1976                             epg_220, None,
1977                             "10.0.0.127", "11.0.0.127",
1978                             "2001:10::1", "3001::1")
1979         ep.add_vpp_config()
1980
1981         #
1982         # learn some remote IPv4 EPs
1983         #
1984         for ii, l in enumerate(learnt):
1985             # a packet with an sclass from a knwon EPG
1986             # arriving on an unknown TEP
1987             p = (Ether(src=self.pg2.remote_mac,
1988                        dst=self.pg2.local_mac) /
1989                  IP(src=self.pg2.remote_hosts[1].ip4,
1990                     dst=self.pg2.local_ip4) /
1991                  UDP(sport=1234, dport=48879) /
1992                  VXLAN(vni=101, gpid=220, flags=0x88) /
1993                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
1994                  IP(src=l['ip'], dst=ep.ip4.address) /
1995                  UDP(sport=1234, dport=1234) /
1996                  Raw('\xa5' * 100))
1997
1998             rx = self.send_and_expect(self.pg2, [p], self.pg0)
1999
2000             # the new TEP
2001             tep1_sw_if_index = find_vxlan_gbp_tunnel(
2002                 self,
2003                 self.pg2.local_ip4,
2004                 self.pg2.remote_hosts[1].ip4,
2005                 vx_tun_l3.vni)
2006             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
2007
2008             # endpoint learnt via the parent GBP-vxlan interface
2009             self.assertTrue(find_gbp_endpoint(self,
2010                                               vx_tun_l3._sw_if_index,
2011                                               ip=l['ip']))
2012
2013         #
2014         # Static IPv4 EP replies to learnt
2015         #
2016         for l in learnt:
2017             p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2018                  IP(dst=l['ip'], src=ep.ip4.address) /
2019                  UDP(sport=1234, dport=1234) /
2020                  Raw('\xa5' * 100))
2021
2022             rxs = self.send_and_expect(self.pg0, p*1, self.pg2)
2023
2024             for rx in rxs:
2025                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2026                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
2027                 self.assertEqual(rx[UDP].dport, 48879)
2028                 # the UDP source port is a random value for hashing
2029                 self.assertEqual(rx[VXLAN].gpid, 220)
2030                 self.assertEqual(rx[VXLAN].vni, 101)
2031                 self.assertTrue(rx[VXLAN].flags.G)
2032                 self.assertTrue(rx[VXLAN].flags.Instance)
2033                 self.assertTrue(rx[VXLAN].gpflags.A)
2034                 self.assertFalse(rx[VXLAN].gpflags.D)
2035
2036                 inner = rx[VXLAN].payload
2037
2038                 self.assertEqual(inner[Ether].src, routed_src_mac)
2039                 self.assertEqual(inner[Ether].dst, routed_dst_mac)
2040                 self.assertEqual(inner[IP].src, ep.ip4.address)
2041                 self.assertEqual(inner[IP].dst, l['ip'])
2042
2043         self.sleep(2)
2044         for l in learnt:
2045             self.assertFalse(find_gbp_endpoint(self,
2046                                                tep1_sw_if_index,
2047                                                ip=l['ip']))
2048
2049         #
2050         # learn some remote IPv6 EPs
2051         #
2052         for ii, l in enumerate(learnt):
2053             # a packet with an sclass from a knwon EPG
2054             # arriving on an unknown TEP
2055             p = (Ether(src=self.pg2.remote_mac,
2056                        dst=self.pg2.local_mac) /
2057                  IP(src=self.pg2.remote_hosts[1].ip4,
2058                     dst=self.pg2.local_ip4) /
2059                  UDP(sport=1234, dport=48879) /
2060                  VXLAN(vni=101, gpid=220, flags=0x88) /
2061                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
2062                  IPv6(src=l['ip6'], dst=ep.ip6.address) /
2063                  UDP(sport=1234, dport=1234) /
2064                  Raw('\xa5' * 100))
2065
2066             rx = self.send_and_expect(self.pg2, [p], self.pg0)
2067
2068             # the new TEP
2069             tep1_sw_if_index = find_vxlan_gbp_tunnel(
2070                 self,
2071                 self.pg2.local_ip4,
2072                 self.pg2.remote_hosts[1].ip4,
2073                 vx_tun_l3.vni)
2074             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
2075
2076             self.logger.info(self.vapi.cli("show gbp bridge"))
2077             self.logger.info(self.vapi.cli("show vxlan-gbp tunnel"))
2078             self.logger.info(self.vapi.cli("show gbp vxlan"))
2079             self.logger.info(self.vapi.cli("show int addr"))
2080
2081             # endpoint learnt via the TEP
2082             self.assertTrue(find_gbp_endpoint(self, ip=l['ip6']))
2083
2084         self.logger.info(self.vapi.cli("show gbp endpoint"))
2085         self.logger.info(self.vapi.cli("show ip fib index 1 %s" % l['ip']))
2086
2087         #
2088         # Static EP replies to learnt
2089         #
2090         for l in learnt:
2091             p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2092                  IPv6(dst=l['ip6'], src=ep.ip6.address) /
2093                  UDP(sport=1234, dport=1234) /
2094                  Raw('\xa5' * 100))
2095
2096             rxs = self.send_and_expect(self.pg0, p*65, self.pg2)
2097
2098             for rx in rxs:
2099                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2100                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
2101                 self.assertEqual(rx[UDP].dport, 48879)
2102                 # the UDP source port is a random value for hashing
2103                 self.assertEqual(rx[VXLAN].gpid, 220)
2104                 self.assertEqual(rx[VXLAN].vni, 101)
2105                 self.assertTrue(rx[VXLAN].flags.G)
2106                 self.assertTrue(rx[VXLAN].flags.Instance)
2107                 self.assertTrue(rx[VXLAN].gpflags.A)
2108                 self.assertFalse(rx[VXLAN].gpflags.D)
2109
2110                 inner = rx[VXLAN].payload
2111
2112                 self.assertEqual(inner[Ether].src, routed_src_mac)
2113                 self.assertEqual(inner[Ether].dst, routed_dst_mac)
2114                 self.assertEqual(inner[IPv6].src, ep.ip6.address)
2115                 self.assertEqual(inner[IPv6].dst, l['ip6'])
2116
2117         self.logger.info(self.vapi.cli("sh gbp endpoint"))
2118         self.sleep(2)
2119         for l in learnt:
2120             self.assertFalse(find_gbp_endpoint(self,
2121                                                tep1_sw_if_index,
2122                                                ip=l['ip']))
2123
2124         #
2125         # Static sends to unknown EP with no route
2126         #
2127         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2128              IP(dst="10.0.0.99", src=ep.ip4.address) /
2129              UDP(sport=1234, dport=1234) /
2130              Raw('\xa5' * 100))
2131
2132         self.send_and_assert_no_replies(self.pg0, [p])
2133
2134         #
2135         # Add a route to static EP's v4 and v6 subnet
2136         #  packets should be send on the v4/v6 uu=fwd interface resp.
2137         #
2138         se_10_24 = VppGbpSubnet(
2139             self, rd1, "10.0.0.0", 24,
2140             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_TRANSPORT)
2141         se_10_24.add_vpp_config()
2142
2143         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2144              IP(dst="10.0.0.99", src=ep.ip4.address) /
2145              UDP(sport=1234, dport=1234) /
2146              Raw('\xa5' * 100))
2147
2148         rxs = self.send_and_expect(self.pg0, [p], self.pg4)
2149         for rx in rxs:
2150             self.assertEqual(rx[IP].src, self.pg4.local_ip4)
2151             self.assertEqual(rx[IP].dst, self.pg4.remote_ip4)
2152             self.assertEqual(rx[UDP].dport, 48879)
2153             # the UDP source port is a random value for hashing
2154             self.assertEqual(rx[VXLAN].gpid, 220)
2155             self.assertEqual(rx[VXLAN].vni, 114)
2156             self.assertTrue(rx[VXLAN].flags.G)
2157             self.assertTrue(rx[VXLAN].flags.Instance)
2158             # policy is not applied to packets sent to the uu-fwd interfaces
2159             self.assertFalse(rx[VXLAN].gpflags.A)
2160             self.assertFalse(rx[VXLAN].gpflags.D)
2161
2162         #
2163         # learn some remote IPv4 EPs
2164         #
2165         for ii, l in enumerate(learnt):
2166             # a packet with an sclass from a knwon EPG
2167             # arriving on an unknown TEP
2168             p = (Ether(src=self.pg2.remote_mac,
2169                        dst=self.pg2.local_mac) /
2170                  IP(src=self.pg2.remote_hosts[1].ip4,
2171                     dst=self.pg2.local_ip4) /
2172                  UDP(sport=1234, dport=48879) /
2173                  VXLAN(vni=101, gpid=220, flags=0x88) /
2174                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
2175                  IP(src=l['ip'], dst=ep.ip4.address) /
2176                  UDP(sport=1234, dport=1234) /
2177                  Raw('\xa5' * 100))
2178
2179             rx = self.send_and_expect(self.pg2, [p], self.pg0)
2180
2181             # the new TEP
2182             tep1_sw_if_index = find_vxlan_gbp_tunnel(
2183                 self,
2184                 self.pg2.local_ip4,
2185                 self.pg2.remote_hosts[1].ip4,
2186                 vx_tun_l3.vni)
2187             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
2188
2189             # endpoint learnt via the parent GBP-vxlan interface
2190             self.assertTrue(find_gbp_endpoint(self,
2191                                               vx_tun_l3._sw_if_index,
2192                                               ip=l['ip']))
2193
2194         #
2195         # Add a remote endpoint from the API
2196         #
2197         rep_88 = VppGbpEndpoint(self, vx_tun_l3,
2198                                 epg_220, None,
2199                                 "10.0.0.88", "11.0.0.88",
2200                                 "2001:10::88", "3001::88",
2201                                 VppEnum.vl_api_gbp_endpoint_flags_t.REMOTE,
2202                                 self.pg2.local_ip4,
2203                                 self.pg2.remote_hosts[1].ip4,
2204                                 mac=None)
2205         rep_88.add_vpp_config()
2206
2207         #
2208         # Add a remote endpoint from the API that matches an existing one
2209         #
2210         rep_2 = VppGbpEndpoint(self, vx_tun_l3,
2211                                epg_220, None,
2212                                learnt[0]['ip'], "11.0.0.101",
2213                                learnt[0]['ip6'], "3001::101",
2214                                VppEnum.vl_api_gbp_endpoint_flags_t.REMOTE,
2215                                self.pg2.local_ip4,
2216                                self.pg2.remote_hosts[1].ip4,
2217                                mac=None)
2218         rep_2.add_vpp_config()
2219
2220         #
2221         # Add a route to the leanred EP's v4 subnet
2222         #  packets should be send on the v4/v6 uu=fwd interface resp.
2223         #
2224         se_10_1_24 = VppGbpSubnet(
2225             self, rd1, "10.0.1.0", 24,
2226             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_TRANSPORT)
2227         se_10_1_24.add_vpp_config()
2228
2229         self.logger.info(self.vapi.cli("show gbp endpoint"))
2230
2231         ips = ["10.0.0.88", learnt[0]['ip']]
2232         for ip in ips:
2233             p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2234                  IP(dst=ip, src=ep.ip4.address) /
2235                  UDP(sport=1234, dport=1234) /
2236                  Raw('\xa5' * 100))
2237
2238             rxs = self.send_and_expect(self.pg0, p*65, self.pg2)
2239
2240             for rx in rxs:
2241                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2242                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
2243                 self.assertEqual(rx[UDP].dport, 48879)
2244                 # the UDP source port is a random value for hashing
2245                 self.assertEqual(rx[VXLAN].gpid, 220)
2246                 self.assertEqual(rx[VXLAN].vni, 101)
2247                 self.assertTrue(rx[VXLAN].flags.G)
2248                 self.assertTrue(rx[VXLAN].flags.Instance)
2249                 self.assertTrue(rx[VXLAN].gpflags.A)
2250                 self.assertFalse(rx[VXLAN].gpflags.D)
2251
2252                 inner = rx[VXLAN].payload
2253
2254                 self.assertEqual(inner[Ether].src, routed_src_mac)
2255                 self.assertEqual(inner[Ether].dst, routed_dst_mac)
2256                 self.assertEqual(inner[IP].src, ep.ip4.address)
2257                 self.assertEqual(inner[IP].dst, ip)
2258
2259         #
2260         # remove the API remote EPs, they are now UU-fwd
2261         #
2262         rep_88.remove_vpp_config()
2263         rep_2.remove_vpp_config()
2264
2265         self.logger.info(self.vapi.cli("show gbp endpoint"))
2266
2267         for ip in ips:
2268             self.assertFalse(find_gbp_endpoint(self, ip=ip))
2269
2270             p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2271                  IP(dst=ip, src=ep.ip4.address) /
2272                  UDP(sport=1234, dport=1234) /
2273                  Raw('\xa5' * 100))
2274
2275             rxs = self.send_and_expect(self.pg0, [p], self.pg4)
2276
2277         #
2278         # shutdown with learnt endpoint present
2279         #
2280         self.logger.info(self.vapi.cli("show gbp endpoint-group"))
2281
2282         #
2283         # TODO
2284         # remote endpoint becomes local
2285         #
2286         self.pg2.unconfig_ip4()
2287         self.pg3.unconfig_ip4()
2288         self.pg4.unconfig_ip4()
2289
2290
2291 if __name__ == '__main__':
2292     unittest.main(testRunner=VppTestRunner)