a45b2f845b8bce7b12dc4aad8e48aba3e7a75e9e
[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
14 from vpp_ip import *
15 from vpp_mac import *
16 from vpp_papi_provider import L2_PORT_TYPE
17 from vpp_papi import VppEnum
18
19 from scapy.packet import Raw
20 from scapy.layers.l2 import Ether, ARP
21 from scapy.layers.inet import IP, UDP
22 from scapy.layers.inet6 import IPv6, ICMPv6ND_NS,  ICMPv6NDOptSrcLLAddr, \
23     ICMPv6ND_NA
24 from scapy.utils6 import in6_getnsma, in6_getnsmac
25 from scapy.layers.vxlan import VXLAN
26
27 from socket import AF_INET, AF_INET6
28 from scapy.utils import inet_pton, inet_ntop
29 from util import mactobinary
30
31
32 def find_gbp_endpoint(test, sw_if_index=None, ip=None, mac=None):
33     if ip:
34         vip = VppIpAddress(ip)
35     if mac:
36         vmac = VppMacAddress(mac)
37
38     eps = test.vapi.gbp_endpoint_dump()
39
40     for ep in eps:
41         if sw_if_index:
42             if ep.endpoint.sw_if_index != sw_if_index:
43                 continue
44         if ip:
45             for eip in ep.endpoint.ips:
46                 if vip == eip:
47                     return True
48         if mac:
49             if vmac == ep.endpoint.mac:
50                 return True
51     return False
52
53
54 def find_gbp_vxlan(test, vni):
55     ts = test.vapi.gbp_vxlan_tunnel_dump()
56     for t in ts:
57         if t.tunnel.vni == vni:
58             return True
59     return False
60
61
62 class VppGbpEndpoint(VppObject):
63     """
64     GBP Endpoint
65     """
66
67     @property
68     def bin_mac(self):
69         return self.vmac.bytes
70
71     @property
72     def mac(self):
73         return self.vmac.address
74
75     @property
76     def mac(self):
77         return self.itf.remote_mac
78
79     @property
80     def ip4(self):
81         return self._ip4
82
83     @property
84     def fip4(self):
85         return self._fip4
86
87     @property
88     def ip6(self):
89         return self._ip6
90
91     @property
92     def fip6(self):
93         return self._fip6
94
95     @property
96     def ips(self):
97         return [self.ip4, self.ip6]
98
99     @property
100     def fips(self):
101         return [self.fip4, self.fip6]
102
103     def __init__(self, test, itf, epg, recirc, ip4, fip4, ip6, fip6,
104                  flags=0,
105                  tun_src="0.0.0.0",
106                  tun_dst="0.0.0.0",
107                  mac=True):
108         self._test = test
109         self.itf = itf
110         self.epg = epg
111         self.recirc = recirc
112
113         self._ip4 = VppIpAddress(ip4)
114         self._fip4 = VppIpAddress(fip4)
115         self._ip6 = VppIpAddress(ip6)
116         self._fip6 = VppIpAddress(fip6)
117
118         if mac:
119             self.vmac = VppMacAddress(self.itf.remote_mac)
120         else:
121             self.vmac = VppMacAddress("00:00:00:00:00:00")
122
123         self.flags = flags
124         self.tun_src = VppIpAddress(tun_src)
125         self.tun_dst = VppIpAddress(tun_dst)
126
127     def add_vpp_config(self):
128         res = self._test.vapi.gbp_endpoint_add(
129             self.itf.sw_if_index,
130             [self.ip4.encode(), self.ip6.encode()],
131             self.vmac.encode(),
132             self.epg.epg,
133             self.flags,
134             self.tun_src.encode(),
135             self.tun_dst.encode())
136         self.handle = res.handle
137         self._test.registry.register(self, self._test.logger)
138
139     def remove_vpp_config(self):
140         self._test.vapi.gbp_endpoint_del(self.handle)
141
142     def __str__(self):
143         return self.object_id()
144
145     def object_id(self):
146         return "gbp-endpoint:[%d==%d:%s:%d]" % (self.handle,
147                                                 self.itf.sw_if_index,
148                                                 self.ip4.address,
149                                                 self.epg.epg)
150
151     def query_vpp_config(self):
152         return find_gbp_endpoint(self._test,
153                                  self.itf.sw_if_index,
154                                  self.ip4.address)
155
156
157 class VppGbpRecirc(VppObject):
158     """
159     GBP Recirculation Interface
160     """
161
162     def __init__(self, test, epg, recirc, is_ext=False):
163         self._test = test
164         self.recirc = recirc
165         self.epg = epg
166         self.is_ext = is_ext
167
168     def add_vpp_config(self):
169         self._test.vapi.gbp_recirc_add_del(
170             1,
171             self.recirc.sw_if_index,
172             self.epg.epg,
173             self.is_ext)
174         self._test.registry.register(self, self._test.logger)
175
176     def remove_vpp_config(self):
177         self._test.vapi.gbp_recirc_add_del(
178             0,
179             self.recirc.sw_if_index,
180             self.epg.epg,
181             self.is_ext)
182
183     def __str__(self):
184         return self.object_id()
185
186     def object_id(self):
187         return "gbp-recirc:[%d]" % (self.recirc.sw_if_index)
188
189     def query_vpp_config(self):
190         rs = self._test.vapi.gbp_recirc_dump()
191         for r in rs:
192             if r.recirc.sw_if_index == self.recirc.sw_if_index:
193                 return True
194         return False
195
196
197 class VppGbpSubnet(VppObject):
198     """
199     GBP Subnet
200     """
201     def __init__(self, test, rd, address, address_len,
202                  type, sw_if_index=None, epg=None):
203         self._test = test
204         self.rd_id = rd.rd_id
205         self.prefix = VppIpPrefix(address, address_len)
206         self.type = type
207         self.sw_if_index = sw_if_index
208         self.epg = epg
209
210     def add_vpp_config(self):
211         self._test.vapi.gbp_subnet_add_del(
212             1,
213             self.rd_id,
214             self.prefix.encode(),
215             self.type,
216             sw_if_index=self.sw_if_index if self.sw_if_index else 0xffffffff,
217             epg_id=self.epg if self.epg else 0xffff)
218         self._test.registry.register(self, self._test.logger)
219
220     def remove_vpp_config(self):
221         self._test.vapi.gbp_subnet_add_del(
222             0,
223             self.rd_id,
224             self.prefix.encode(),
225             self.type)
226
227     def __str__(self):
228         return self.object_id()
229
230     def object_id(self):
231         return "gbp-subnet:[%d-%s]" % (self.rd_id, self.prefix)
232
233     def query_vpp_config(self):
234         ss = self._test.vapi.gbp_subnet_dump()
235         for s in ss:
236             if s.subnet.rd_id == self.rd_id and \
237                s.subnet.type == self.type and \
238                s.subnet.prefix == self.prefix:
239                 return True
240         return False
241
242
243 class VppGbpEndpointGroup(VppObject):
244     """
245     GBP Endpoint Group
246     """
247
248     def __init__(self, test, epg, rd, bd, uplink,
249                  bvi, bvi_ip4, bvi_ip6=None):
250         self._test = test
251         self.uplink = uplink
252         self.bvi = bvi
253         self.bvi_ip4 = VppIpAddress(bvi_ip4)
254         self.bvi_ip6 = VppIpAddress(bvi_ip6)
255         self.epg = epg
256         self.bd = bd
257         self.rd = rd
258
259     def add_vpp_config(self):
260         self._test.vapi.gbp_endpoint_group_add(
261             self.epg,
262             self.bd.bd.bd_id,
263             self.rd.rd_id,
264             self.uplink.sw_if_index if self.uplink else INDEX_INVALID)
265         self._test.registry.register(self, self._test.logger)
266
267     def remove_vpp_config(self):
268         self._test.vapi.gbp_endpoint_group_del(
269             self.epg)
270
271     def __str__(self):
272         return self.object_id()
273
274     def object_id(self):
275         return "gbp-endpoint-group:[%d]" % (self.epg)
276
277     def query_vpp_config(self):
278         epgs = self._test.vapi.gbp_endpoint_group_dump()
279         for epg in epgs:
280             if epg.epg.epg_id == self.epg:
281                 return True
282         return False
283
284
285 class VppGbpBridgeDomain(VppObject):
286     """
287     GBP Bridge Domain
288     """
289
290     def __init__(self, test, bd, bvi, uu_flood=None):
291         self._test = test
292         self.bvi = bvi
293         self.uu_flood = uu_flood
294         self.bd = bd
295
296     def add_vpp_config(self):
297         self._test.vapi.gbp_bridge_domain_add(
298             self.bd.bd_id,
299             self.bvi.sw_if_index,
300             self.uu_flood.sw_if_index if self.uu_flood else INDEX_INVALID)
301         self._test.registry.register(self, self._test.logger)
302
303     def remove_vpp_config(self):
304         self._test.vapi.gbp_bridge_domain_del(self.bd.bd_id)
305
306     def __str__(self):
307         return self.object_id()
308
309     def object_id(self):
310         return "gbp-bridge-domain:[%d]" % (self.bd.bd_id)
311
312     def query_vpp_config(self):
313         bds = self._test.vapi.gbp_bridge_domain_dump()
314         for bd in bds:
315             if bd.bd.bd_id == self.bd.bd_id:
316                 return True
317         return False
318
319
320 class VppGbpRouteDomain(VppObject):
321     """
322     GBP Route Domain
323     """
324
325     def __init__(self, test, rd_id, t4, t6, ip4_uu=None, ip6_uu=None):
326         self._test = test
327         self.rd_id = rd_id
328         self.t4 = t4
329         self.t6 = t6
330         self.ip4_uu = ip4_uu
331         self.ip6_uu = ip6_uu
332
333     def add_vpp_config(self):
334         self._test.vapi.gbp_route_domain_add(
335             self.rd_id,
336             self.t4.table_id,
337             self.t6.table_id,
338             self.ip4_uu.sw_if_index if self.ip4_uu else INDEX_INVALID,
339             self.ip6_uu.sw_if_index if self.ip6_uu else INDEX_INVALID)
340         self._test.registry.register(self, self._test.logger)
341
342     def remove_vpp_config(self):
343         self._test.vapi.gbp_route_domain_del(self.rd_id)
344
345     def __str__(self):
346         return self.object_id()
347
348     def object_id(self):
349         return "gbp-route-domain:[%d]" % (self.rd_id)
350
351     def query_vpp_config(self):
352         rds = self._test.vapi.gbp_route_domain_dump()
353         for rd in rds:
354             if rd.rd.rd_id == self.rd_id:
355                 return True
356         return False
357
358
359 class VppGbpContract(VppObject):
360     """
361     GBP Contract
362     """
363
364     def __init__(self, test, src_epg, dst_epg, acl_index):
365         self._test = test
366         self.acl_index = acl_index
367         self.src_epg = src_epg
368         self.dst_epg = dst_epg
369
370     def add_vpp_config(self):
371         self._test.vapi.gbp_contract_add_del(
372             1,
373             self.src_epg,
374             self.dst_epg,
375             self.acl_index)
376         self._test.registry.register(self, self._test.logger)
377
378     def remove_vpp_config(self):
379         self._test.vapi.gbp_contract_add_del(
380             0,
381             self.src_epg,
382             self.dst_epg,
383             self.acl_index)
384
385     def __str__(self):
386         return self.object_id()
387
388     def object_id(self):
389         return "gbp-contract:[%d:%s:%d]" % (self.src_epg,
390                                             self.dst_epg,
391                                             self.acl_index)
392
393     def query_vpp_config(self):
394         cs = self._test.vapi.gbp_contract_dump()
395         for c in cs:
396             if c.contract.src_epg == self.src_epg \
397                and c.contract.dst_epg == self.dst_epg:
398                 return True
399         return False
400
401
402 class VppGbpVxlanTunnel(VppInterface):
403     """
404     GBP VXLAN tunnel
405     """
406
407     def __init__(self, test, vni, bd_rd_id, mode):
408         super(VppGbpVxlanTunnel, self).__init__(test)
409         self._test = test
410         self.vni = vni
411         self.bd_rd_id = bd_rd_id
412         self.mode = mode
413
414     def add_vpp_config(self):
415         r = self._test.vapi.gbp_vxlan_tunnel_add(
416             self.vni,
417             self.bd_rd_id,
418             self.mode)
419         self.set_sw_if_index(r.sw_if_index)
420         self._test.registry.register(self, self._test.logger)
421
422     def remove_vpp_config(self):
423         self._test.vapi.gbp_vxlan_tunnel_del(self.vni)
424
425     def __str__(self):
426         return self.object_id()
427
428     def object_id(self):
429         return "gbp-vxlan:%d" % (self.vni)
430
431     def query_vpp_config(self):
432         return find_gbp_vxlan(self._test, self.vni)
433
434
435 class VppGbpAcl(VppObject):
436     """
437     GBP Acl
438     """
439
440     def __init__(self, test):
441         self._test = test
442         self.acl_index = 4294967295
443
444     def create_rule(self, is_ipv6=0, permit_deny=0, proto=-1,
445                     s_prefix=0, s_ip='\x00\x00\x00\x00', sport_from=0,
446                     sport_to=65535, d_prefix=0, d_ip='\x00\x00\x00\x00',
447                     dport_from=0, dport_to=65535):
448         if proto == -1 or proto == 0:
449             sport_to = 0
450             dport_to = sport_to
451         elif proto == 1 or proto == 58:
452             sport_to = 255
453             dport_to = sport_to
454         rule = ({'is_permit': permit_deny, 'is_ipv6': is_ipv6, 'proto': proto,
455                  'srcport_or_icmptype_first': sport_from,
456                  'srcport_or_icmptype_last': sport_to,
457                  'src_ip_prefix_len': s_prefix,
458                  'src_ip_addr': s_ip,
459                  'dstport_or_icmpcode_first': dport_from,
460                  'dstport_or_icmpcode_last': dport_to,
461                  'dst_ip_prefix_len': d_prefix,
462                  'dst_ip_addr': d_ip})
463         return rule
464
465     def add_vpp_config(self, rules):
466
467         reply = self._test.vapi.acl_add_replace(self.acl_index,
468                                                 r=rules,
469                                                 tag='GBPTest')
470         self.acl_index = reply.acl_index
471         return self.acl_index
472
473     def remove_vpp_config(self):
474         self._test.vapi.acl_del(self.acl_index)
475
476     def __str__(self):
477         return self.object_id()
478
479     def object_id(self):
480         return "gbp-acl:[%d]" % (self.acl_index)
481
482     def query_vpp_config(self):
483         cs = self._test.vapi.acl_dump()
484         for c in cs:
485             if c.acl_index == self.acl_index:
486                 return True
487         return False
488
489
490 class TestGBP(VppTestCase):
491     """ GBP Test Case """
492
493     def setUp(self):
494         super(TestGBP, self).setUp()
495
496         self.create_pg_interfaces(range(9))
497         self.create_loopback_interfaces(8)
498
499         self.router_mac = VppMacAddress("00:11:22:33:44:55")
500
501         for i in self.pg_interfaces:
502             i.admin_up()
503         for i in self.lo_interfaces:
504             i.admin_up()
505
506     def tearDown(self):
507         for i in self.pg_interfaces:
508             i.admin_down()
509
510         super(TestGBP, self).tearDown()
511
512     def send_and_expect_bridged(self, src, tx, dst):
513         rx = self.send_and_expect(src, tx, dst)
514
515         for r in rx:
516             self.assertEqual(r[Ether].src, tx[0][Ether].src)
517             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
518             self.assertEqual(r[IP].src, tx[0][IP].src)
519             self.assertEqual(r[IP].dst, tx[0][IP].dst)
520         return rx
521
522     def send_and_expect_bridged6(self, src, tx, dst):
523         rx = self.send_and_expect(src, tx, dst)
524
525         for r in rx:
526             self.assertEqual(r[Ether].src, tx[0][Ether].src)
527             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
528             self.assertEqual(r[IPv6].src, tx[0][IPv6].src)
529             self.assertEqual(r[IPv6].dst, tx[0][IPv6].dst)
530         return rx
531
532     def send_and_expect_routed(self, src, tx, dst, src_mac):
533         rx = self.send_and_expect(src, tx, dst)
534
535         for r in rx:
536             self.assertEqual(r[Ether].src, src_mac)
537             self.assertEqual(r[Ether].dst, dst.remote_mac)
538             self.assertEqual(r[IP].src, tx[0][IP].src)
539             self.assertEqual(r[IP].dst, tx[0][IP].dst)
540         return rx
541
542     def send_and_expect_natted(self, src, tx, dst, src_ip):
543         rx = self.send_and_expect(src, tx, dst)
544
545         for r in rx:
546             self.assertEqual(r[Ether].src, tx[0][Ether].src)
547             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
548             self.assertEqual(r[IP].src, src_ip)
549             self.assertEqual(r[IP].dst, tx[0][IP].dst)
550         return rx
551
552     def send_and_expect_natted6(self, src, tx, dst, src_ip):
553         rx = self.send_and_expect(src, tx, dst)
554
555         for r in rx:
556             self.assertEqual(r[Ether].src, tx[0][Ether].src)
557             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
558             self.assertEqual(r[IPv6].src, src_ip)
559             self.assertEqual(r[IPv6].dst, tx[0][IPv6].dst)
560         return rx
561
562     def send_and_expect_unnatted(self, src, tx, dst, dst_ip):
563         rx = self.send_and_expect(src, tx, dst)
564
565         for r in rx:
566             self.assertEqual(r[Ether].src, tx[0][Ether].src)
567             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
568             self.assertEqual(r[IP].dst, dst_ip)
569             self.assertEqual(r[IP].src, tx[0][IP].src)
570         return rx
571
572     def send_and_expect_unnatted6(self, src, tx, dst, dst_ip):
573         rx = self.send_and_expect(src, tx, dst)
574
575         for r in rx:
576             self.assertEqual(r[Ether].src, tx[0][Ether].src)
577             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
578             self.assertEqual(r[IPv6].dst, dst_ip)
579             self.assertEqual(r[IPv6].src, tx[0][IPv6].src)
580         return rx
581
582     def send_and_expect_double_natted(self, src, tx, dst, src_ip, dst_ip):
583         rx = self.send_and_expect(src, tx, dst)
584
585         for r in rx:
586             self.assertEqual(r[Ether].src, self.router_mac.address)
587             self.assertEqual(r[Ether].dst, dst.remote_mac)
588             self.assertEqual(r[IP].dst, dst_ip)
589             self.assertEqual(r[IP].src, src_ip)
590         return rx
591
592     def send_and_expect_double_natted6(self, src, tx, dst, src_ip, dst_ip):
593         rx = self.send_and_expect(src, tx, dst)
594
595         for r in rx:
596             self.assertEqual(r[Ether].src, self.router_mac.address)
597             self.assertEqual(r[Ether].dst, dst.remote_mac)
598             self.assertEqual(r[IPv6].dst, dst_ip)
599             self.assertEqual(r[IPv6].src, src_ip)
600         return rx
601
602     def test_gbp(self):
603         """ Group Based Policy """
604
605         #
606         # Bridge Domains
607         #
608         bd1 = VppBridgeDomain(self, 1)
609         bd2 = VppBridgeDomain(self, 2)
610         bd20 = VppBridgeDomain(self, 20)
611
612         bd1.add_vpp_config()
613         bd2.add_vpp_config()
614         bd20.add_vpp_config()
615
616         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0)
617         gbd2 = VppGbpBridgeDomain(self, bd2, self.loop1)
618         gbd20 = VppGbpBridgeDomain(self, bd20, self.loop2)
619
620         gbd1.add_vpp_config()
621         gbd2.add_vpp_config()
622         gbd20.add_vpp_config()
623
624         #
625         # Route Domains
626         #
627         gt4 = VppIpTable(self, 0)
628         gt4.add_vpp_config()
629         gt6 = VppIpTable(self, 0, is_ip6=True)
630         gt6.add_vpp_config()
631         nt4 = VppIpTable(self, 20)
632         nt4.add_vpp_config()
633         nt6 = VppIpTable(self, 20, is_ip6=True)
634         nt6.add_vpp_config()
635
636         rd0 = VppGbpRouteDomain(self, 0, gt4, gt6, None, None)
637         rd20 = VppGbpRouteDomain(self, 20, nt4, nt6, None, None)
638
639         rd0.add_vpp_config()
640         rd20.add_vpp_config()
641
642         #
643         # 3 EPGs, 2 of which share a BD.
644         # 2 NAT EPGs, one for floating-IP subnets, the other for internet
645         #
646         epgs = [VppGbpEndpointGroup(self, 220, rd0, gbd1, self.pg4,
647                                     self.loop0,
648                                     "10.0.0.128",
649                                     "2001:10::128"),
650                 VppGbpEndpointGroup(self, 221, rd0, gbd1, self.pg5,
651                                     self.loop0,
652                                     "10.0.1.128",
653                                     "2001:10:1::128"),
654                 VppGbpEndpointGroup(self, 222, rd0, gbd2, self.pg6,
655                                     self.loop1,
656                                     "10.0.2.128",
657                                     "2001:10:2::128"),
658                 VppGbpEndpointGroup(self, 333, rd20, gbd20, self.pg7,
659                                     self.loop2,
660                                     "11.0.0.128",
661                                     "3001::128"),
662                 VppGbpEndpointGroup(self, 444, rd20, gbd20, self.pg8,
663                                     self.loop2,
664                                     "11.0.0.129",
665                                     "3001::129")]
666         recircs = [VppGbpRecirc(self, epgs[0],
667                                 self.loop3),
668                    VppGbpRecirc(self, epgs[1],
669                                 self.loop4),
670                    VppGbpRecirc(self, epgs[2],
671                                 self.loop5),
672                    VppGbpRecirc(self, epgs[3],
673                                 self.loop6, is_ext=True),
674                    VppGbpRecirc(self, epgs[4],
675                                 self.loop7, is_ext=True)]
676
677         epg_nat = epgs[3]
678         recirc_nat = recircs[3]
679
680         #
681         # 4 end-points, 2 in the same subnet, 3 in the same BD
682         #
683         eps = [VppGbpEndpoint(self, self.pg0,
684                               epgs[0], recircs[0],
685                               "10.0.0.1", "11.0.0.1",
686                               "2001:10::1", "3001::1"),
687                VppGbpEndpoint(self, self.pg1,
688                               epgs[0], recircs[0],
689                               "10.0.0.2", "11.0.0.2",
690                               "2001:10::2", "3001::2"),
691                VppGbpEndpoint(self, self.pg2,
692                               epgs[1], recircs[1],
693                               "10.0.1.1", "11.0.0.3",
694                               "2001:10:1::1", "3001::3"),
695                VppGbpEndpoint(self, self.pg3,
696                               epgs[2], recircs[2],
697                               "10.0.2.1", "11.0.0.4",
698                               "2001:10:2::1", "3001::4")]
699
700         #
701         # Config related to each of the EPGs
702         #
703         for epg in epgs:
704             # IP config on the BVI interfaces
705             if epg != epgs[1] and epg != epgs[4]:
706                 VppIpInterfaceBind(self, epg.bvi, epg.rd.t4).add_vpp_config()
707                 VppIpInterfaceBind(self, epg.bvi, epg.rd.t6).add_vpp_config()
708                 self.vapi.sw_interface_set_mac_address(
709                     epg.bvi.sw_if_index,
710                     self.router_mac.bytes)
711
712                 # The BVIs are NAT inside interfaces
713                 self.vapi.nat44_interface_add_del_feature(epg.bvi.sw_if_index,
714                                                           is_inside=1,
715                                                           is_add=1)
716                 self.vapi.nat66_add_del_interface(epg.bvi.sw_if_index,
717                                                   is_inside=1,
718                                                   is_add=1)
719
720             if_ip4 = VppIpInterfaceAddress(self, epg.bvi, epg.bvi_ip4, 32)
721             if_ip6 = VppIpInterfaceAddress(self, epg.bvi, epg.bvi_ip6, 128)
722             if_ip4.add_vpp_config()
723             if_ip6.add_vpp_config()
724
725             # EPG uplink interfaces in the RD
726             VppIpInterfaceBind(self, epg.uplink, epg.rd.t4).add_vpp_config()
727             VppIpInterfaceBind(self, epg.uplink, epg.rd.t6).add_vpp_config()
728
729             # add the BD ARP termination entry for BVI IP
730             epg.bd_arp_ip4 = VppBridgeDomainArpEntry(self, epg.bd.bd,
731                                                      self.router_mac.address,
732                                                      epg.bvi_ip4)
733             epg.bd_arp_ip6 = VppBridgeDomainArpEntry(self, epg.bd.bd,
734                                                      self.router_mac.address,
735                                                      epg.bvi_ip6)
736             epg.bd_arp_ip4.add_vpp_config()
737             epg.bd_arp_ip6.add_vpp_config()
738
739             # EPG in VPP
740             epg.add_vpp_config()
741
742         for recirc in recircs:
743             # EPG's ingress recirculation interface maps to its RD
744             VppIpInterfaceBind(self, recirc.recirc,
745                                recirc.epg.rd.t4).add_vpp_config()
746             VppIpInterfaceBind(self, recirc.recirc,
747                                recirc.epg.rd.t6).add_vpp_config()
748
749             self.vapi.sw_interface_set_l2_emulation(
750                 recirc.recirc.sw_if_index)
751             self.vapi.nat44_interface_add_del_feature(
752                 recirc.recirc.sw_if_index,
753                 is_inside=0,
754                 is_add=1)
755             self.vapi.nat66_add_del_interface(
756                 recirc.recirc.sw_if_index,
757                 is_inside=0,
758                 is_add=1)
759
760             recirc.add_vpp_config()
761
762         for recirc in recircs:
763             self.assertTrue(find_bridge_domain_port(self,
764                                                     recirc.epg.bd.bd.bd_id,
765                                                     recirc.recirc.sw_if_index))
766
767         for ep in eps:
768             self.pg_enable_capture(self.pg_interfaces)
769             self.pg_start()
770             #
771             # routes to the endpoints. We need these since there are no
772             # adj-fibs due to the fact the the BVI address has /32 and
773             # the subnet is not attached.
774             #
775             for (ip, fip) in zip(ep.ips, ep.fips):
776                 # Add static mappings for each EP from the 10/8 to 11/8 network
777                 if ip.af == AF_INET:
778                     self.vapi.nat44_add_del_static_mapping(ip.bytes,
779                                                            fip.bytes,
780                                                            vrf_id=0,
781                                                            addr_only=1)
782                 else:
783                     self.vapi.nat66_add_del_static_mapping(ip.bytes,
784                                                            fip.bytes,
785                                                            vrf_id=0)
786
787             # VPP EP create ...
788             ep.add_vpp_config()
789
790             self.logger.info(self.vapi.cli("sh gbp endpoint"))
791
792             # ... results in a Gratuitous ARP/ND on the EPG's uplink
793             rx = ep.epg.uplink.get_capture(len(ep.ips), timeout=0.2)
794
795             for ii, ip in enumerate(ep.ips):
796                 p = rx[ii]
797
798                 if ip.is_ip6:
799                     self.assertTrue(p.haslayer(ICMPv6ND_NA))
800                     self.assertEqual(p[ICMPv6ND_NA].tgt, ip.address)
801                 else:
802                     self.assertTrue(p.haslayer(ARP))
803                     self.assertEqual(p[ARP].psrc, ip.address)
804                     self.assertEqual(p[ARP].pdst, ip.address)
805
806             # add the BD ARP termination entry for floating IP
807             for fip in ep.fips:
808                 ba = VppBridgeDomainArpEntry(self, epg_nat.bd.bd, ep.mac, fip)
809                 ba.add_vpp_config()
810
811                 # floating IPs route via EPG recirc
812                 r = VppIpRoute(self, fip.address, fip.length,
813                                [VppRoutePath(fip.address,
814                                              ep.recirc.recirc.sw_if_index,
815                                              is_dvr=1,
816                                              proto=fip.dpo_proto)],
817                                table_id=20,
818                                is_ip6=fip.is_ip6)
819                 r.add_vpp_config()
820
821             # L2 FIB entries in the NAT EPG BD to bridge the packets from
822             # the outside direct to the internal EPG
823             lf = VppL2FibEntry(self, epg_nat.bd.bd, ep.mac,
824                                ep.recirc.recirc, bvi_mac=0)
825             lf.add_vpp_config()
826
827         #
828         # ARP packets for unknown IP are sent to the EPG uplink
829         #
830         pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff",
831                          src=self.pg0.remote_mac) /
832                    ARP(op="who-has",
833                        hwdst="ff:ff:ff:ff:ff:ff",
834                        hwsrc=self.pg0.remote_mac,
835                        pdst="10.0.0.88",
836                        psrc="10.0.0.99"))
837
838         self.vapi.cli("clear trace")
839         self.pg0.add_stream(pkt_arp)
840
841         self.pg_enable_capture(self.pg_interfaces)
842         self.pg_start()
843
844         rxd = epgs[0].uplink.get_capture(1)
845
846         #
847         # ARP/ND packets get a response
848         #
849         pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff",
850                          src=self.pg0.remote_mac) /
851                    ARP(op="who-has",
852                        hwdst="ff:ff:ff:ff:ff:ff",
853                        hwsrc=self.pg0.remote_mac,
854                        pdst=epgs[0].bvi_ip4.address,
855                        psrc=eps[0].ip4.address))
856
857         self.send_and_expect(self.pg0, [pkt_arp], self.pg0)
858
859         nsma = in6_getnsma(inet_pton(AF_INET6, eps[0].ip6.address))
860         d = inet_ntop(AF_INET6, nsma)
861         pkt_nd = (Ether(dst=in6_getnsmac(nsma),
862                         src=self.pg0.remote_mac) /
863                   IPv6(dst=d, src=eps[0].ip6.address) /
864                   ICMPv6ND_NS(tgt=epgs[0].bvi_ip6.address) /
865                   ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac))
866         self.send_and_expect(self.pg0, [pkt_nd], self.pg0)
867
868         #
869         # broadcast packets are flooded
870         #
871         pkt_bcast = (Ether(dst="ff:ff:ff:ff:ff:ff",
872                            src=self.pg0.remote_mac) /
873                      IP(src=eps[0].ip4.address, dst="232.1.1.1") /
874                      UDP(sport=1234, dport=1234) /
875                      Raw('\xa5' * 100))
876
877         self.vapi.cli("clear trace")
878         self.pg0.add_stream(pkt_bcast)
879
880         self.pg_enable_capture(self.pg_interfaces)
881         self.pg_start()
882
883         rxd = eps[1].itf.get_capture(1)
884         self.assertEqual(rxd[0][Ether].dst, pkt_bcast[Ether].dst)
885         rxd = epgs[0].uplink.get_capture(1)
886         self.assertEqual(rxd[0][Ether].dst, pkt_bcast[Ether].dst)
887
888         #
889         # packets to non-local L3 destinations dropped
890         #
891         pkt_intra_epg_220_ip4 = (Ether(src=self.pg0.remote_mac,
892                                        dst=self.router_mac.address) /
893                                  IP(src=eps[0].ip4.address,
894                                     dst="10.0.0.99") /
895                                  UDP(sport=1234, dport=1234) /
896                                  Raw('\xa5' * 100))
897         pkt_inter_epg_222_ip4 = (Ether(src=self.pg0.remote_mac,
898                                        dst=self.router_mac.address) /
899                                  IP(src=eps[0].ip4.address,
900                                     dst="10.0.1.99") /
901                                  UDP(sport=1234, dport=1234) /
902                                  Raw('\xa5' * 100))
903
904         self.send_and_assert_no_replies(self.pg0, pkt_intra_epg_220_ip4 * 65)
905
906         pkt_inter_epg_222_ip6 = (Ether(src=self.pg0.remote_mac,
907                                        dst=self.router_mac.address) /
908                                  IPv6(src=eps[0].ip6.address,
909                                       dst="2001:10::99") /
910                                  UDP(sport=1234, dport=1234) /
911                                  Raw('\xa5' * 100))
912         self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_222_ip6 * 65)
913
914         #
915         # Add the subnet routes
916         #
917         s41 = VppGbpSubnet(
918             self, rd0, "10.0.0.0", 24,
919             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
920         s42 = VppGbpSubnet(
921             self, rd0, "10.0.1.0", 24,
922             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
923         s43 = VppGbpSubnet(
924             self, rd0, "10.0.2.0", 24,
925             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
926         s61 = VppGbpSubnet(
927             self, rd0, "2001:10::1", 64,
928             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
929         s62 = VppGbpSubnet(
930             self, rd0, "2001:10:1::1", 64,
931             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
932         s63 = VppGbpSubnet(
933             self, rd0, "2001:10:2::1", 64,
934             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
935         s41.add_vpp_config()
936         s42.add_vpp_config()
937         s43.add_vpp_config()
938         s61.add_vpp_config()
939         s62.add_vpp_config()
940         s63.add_vpp_config()
941
942         self.send_and_expect_bridged(eps[0].itf,
943                                      pkt_intra_epg_220_ip4 * 65,
944                                      eps[0].epg.uplink)
945         self.send_and_expect_bridged(eps[0].itf,
946                                      pkt_inter_epg_222_ip4 * 65,
947                                      eps[0].epg.uplink)
948         self.send_and_expect_bridged6(eps[0].itf,
949                                       pkt_inter_epg_222_ip6 * 65,
950                                       eps[0].epg.uplink)
951
952         self.logger.info(self.vapi.cli("sh ip fib 11.0.0.2"))
953         self.logger.info(self.vapi.cli("sh gbp endpoint-group"))
954         self.logger.info(self.vapi.cli("sh gbp endpoint"))
955         self.logger.info(self.vapi.cli("sh gbp recirc"))
956         self.logger.info(self.vapi.cli("sh int"))
957         self.logger.info(self.vapi.cli("sh int addr"))
958         self.logger.info(self.vapi.cli("sh int feat loop6"))
959         self.logger.info(self.vapi.cli("sh vlib graph ip4-gbp-src-classify"))
960         self.logger.info(self.vapi.cli("sh int feat loop3"))
961         self.logger.info(self.vapi.cli("sh int feat pg0"))
962
963         #
964         # Packet destined to unknown unicast is sent on the epg uplink ...
965         #
966         pkt_intra_epg_220_to_uplink = (Ether(src=self.pg0.remote_mac,
967                                              dst="00:00:00:33:44:55") /
968                                        IP(src=eps[0].ip4.address,
969                                           dst="10.0.0.99") /
970                                        UDP(sport=1234, dport=1234) /
971                                        Raw('\xa5' * 100))
972
973         self.send_and_expect_bridged(eps[0].itf,
974                                      pkt_intra_epg_220_to_uplink * 65,
975                                      eps[0].epg.uplink)
976         # ... and nowhere else
977         self.pg1.get_capture(0, timeout=0.1)
978         self.pg1.assert_nothing_captured(remark="Flood onto other VMS")
979
980         pkt_intra_epg_221_to_uplink = (Ether(src=self.pg2.remote_mac,
981                                              dst="00:00:00:33:44:66") /
982                                        IP(src=eps[0].ip4.address,
983                                           dst="10.0.0.99") /
984                                        UDP(sport=1234, dport=1234) /
985                                        Raw('\xa5' * 100))
986
987         self.send_and_expect_bridged(eps[2].itf,
988                                      pkt_intra_epg_221_to_uplink * 65,
989                                      eps[2].epg.uplink)
990
991         #
992         # Packets from the uplink are forwarded in the absence of a contract
993         #
994         pkt_intra_epg_220_from_uplink = (Ether(src="00:00:00:33:44:55",
995                                                dst=self.pg0.remote_mac) /
996                                          IP(src=eps[0].ip4.address,
997                                             dst="10.0.0.99") /
998                                          UDP(sport=1234, dport=1234) /
999                                          Raw('\xa5' * 100))
1000
1001         self.send_and_expect_bridged(self.pg4,
1002                                      pkt_intra_epg_220_from_uplink * 65,
1003                                      self.pg0)
1004
1005         #
1006         # in the absence of policy, endpoints in the same EPG
1007         # can communicate
1008         #
1009         pkt_intra_epg = (Ether(src=self.pg0.remote_mac,
1010                                dst=self.pg1.remote_mac) /
1011                          IP(src=eps[0].ip4.address,
1012                             dst=eps[1].ip4.address) /
1013                          UDP(sport=1234, dport=1234) /
1014                          Raw('\xa5' * 100))
1015
1016         self.send_and_expect_bridged(self.pg0, pkt_intra_epg * 65, self.pg1)
1017
1018         #
1019         # in the abscense of policy, endpoints in the different EPG
1020         # cannot communicate
1021         #
1022         pkt_inter_epg_220_to_221 = (Ether(src=self.pg0.remote_mac,
1023                                           dst=self.pg2.remote_mac) /
1024                                     IP(src=eps[0].ip4.address,
1025                                        dst=eps[2].ip4.address) /
1026                                     UDP(sport=1234, dport=1234) /
1027                                     Raw('\xa5' * 100))
1028         pkt_inter_epg_221_to_220 = (Ether(src=self.pg2.remote_mac,
1029                                           dst=self.pg0.remote_mac) /
1030                                     IP(src=eps[2].ip4.address,
1031                                        dst=eps[0].ip4.address) /
1032                                     UDP(sport=1234, dport=1234) /
1033                                     Raw('\xa5' * 100))
1034         pkt_inter_epg_220_to_222 = (Ether(src=self.pg0.remote_mac,
1035                                           dst=self.router_mac.address) /
1036                                     IP(src=eps[0].ip4.address,
1037                                        dst=eps[3].ip4.address) /
1038                                     UDP(sport=1234, dport=1234) /
1039                                     Raw('\xa5' * 100))
1040
1041         self.send_and_assert_no_replies(eps[0].itf,
1042                                         pkt_inter_epg_220_to_221 * 65)
1043         self.send_and_assert_no_replies(eps[0].itf,
1044                                         pkt_inter_epg_220_to_222 * 65)
1045
1046         #
1047         # A uni-directional contract from EPG 220 -> 221
1048         #
1049         acl = VppGbpAcl(self)
1050         rule = acl.create_rule(permit_deny=1, proto=17)
1051         rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
1052         acl_index = acl.add_vpp_config([rule, rule2])
1053         c1 = VppGbpContract(self, 220, 221, acl_index)
1054         c1.add_vpp_config()
1055
1056         self.send_and_expect_bridged(eps[0].itf,
1057                                      pkt_inter_epg_220_to_221 * 65,
1058                                      eps[2].itf)
1059         self.send_and_assert_no_replies(eps[0].itf,
1060                                         pkt_inter_epg_220_to_222 * 65)
1061
1062         #
1063         # contract for the return direction
1064         #
1065         c2 = VppGbpContract(self, 221, 220, acl_index)
1066         c2.add_vpp_config()
1067
1068         self.send_and_expect_bridged(eps[0].itf,
1069                                      pkt_inter_epg_220_to_221 * 65,
1070                                      eps[2].itf)
1071         self.send_and_expect_bridged(eps[2].itf,
1072                                      pkt_inter_epg_221_to_220 * 65,
1073                                      eps[0].itf)
1074
1075         #
1076         # check that inter group is still disabled for the groups
1077         # not in the contract.
1078         #
1079         self.send_and_assert_no_replies(eps[0].itf,
1080                                         pkt_inter_epg_220_to_222 * 65)
1081
1082         #
1083         # A uni-directional contract from EPG 220 -> 222 'L3 routed'
1084         #
1085         c3 = VppGbpContract(self, 220, 222, acl_index)
1086         c3.add_vpp_config()
1087
1088         self.logger.info(self.vapi.cli("sh gbp contract"))
1089
1090         self.send_and_expect_routed(eps[0].itf,
1091                                     pkt_inter_epg_220_to_222 * 65,
1092                                     eps[3].itf,
1093                                     self.router_mac.address)
1094
1095         #
1096         # remove both contracts, traffic stops in both directions
1097         #
1098         c2.remove_vpp_config()
1099         c1.remove_vpp_config()
1100         c3.remove_vpp_config()
1101         acl.remove_vpp_config()
1102
1103         self.send_and_assert_no_replies(eps[2].itf,
1104                                         pkt_inter_epg_221_to_220 * 65)
1105         self.send_and_assert_no_replies(eps[0].itf,
1106                                         pkt_inter_epg_220_to_221 * 65)
1107         self.send_and_expect_bridged(eps[0].itf,
1108                                      pkt_intra_epg * 65,
1109                                      eps[1].itf)
1110
1111         #
1112         # EPs to the outside world
1113         #
1114
1115         # in the EP's RD an external subnet via the NAT EPG's recirc
1116         se1 = VppGbpSubnet(
1117             self, rd0, "0.0.0.0", 0,
1118             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1119             sw_if_index=recirc_nat.recirc.sw_if_index,
1120             epg=epg_nat.epg)
1121         se2 = VppGbpSubnet(
1122             self, rd0, "11.0.0.0", 8,
1123             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1124             sw_if_index=recirc_nat.recirc.sw_if_index,
1125             epg=epg_nat.epg)
1126         se16 = VppGbpSubnet(
1127             self, rd0, "::", 0,
1128             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1129             sw_if_index=recirc_nat.recirc.sw_if_index,
1130             epg=epg_nat.epg)
1131         # in the NAT RD an external subnet via the NAT EPG's uplink
1132         se3 = VppGbpSubnet(
1133             self, rd20, "0.0.0.0", 0,
1134             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1135             sw_if_index=epg_nat.uplink.sw_if_index,
1136             epg=epg_nat.epg)
1137         se36 = VppGbpSubnet(
1138             self, rd20, "::", 0,
1139             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1140             sw_if_index=epg_nat.uplink.sw_if_index,
1141             epg=epg_nat.epg)
1142         se4 = VppGbpSubnet(
1143             self, rd20, "11.0.0.0", 8,
1144             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1145             sw_if_index=epg_nat.uplink.sw_if_index,
1146             epg=epg_nat.epg)
1147         se1.add_vpp_config()
1148         se2.add_vpp_config()
1149         se16.add_vpp_config()
1150         se3.add_vpp_config()
1151         se36.add_vpp_config()
1152         se4.add_vpp_config()
1153
1154         self.logger.info(self.vapi.cli("sh ip fib 0.0.0.0/0"))
1155         self.logger.info(self.vapi.cli("sh ip fib 11.0.0.1"))
1156         self.logger.info(self.vapi.cli("sh ip6 fib ::/0"))
1157         self.logger.info(self.vapi.cli("sh ip6 fib %s" %
1158                                        eps[0].fip6))
1159
1160         #
1161         # From an EP to an outside addess: IN2OUT
1162         #
1163         pkt_inter_epg_220_to_global = (Ether(src=self.pg0.remote_mac,
1164                                              dst=self.router_mac.address) /
1165                                        IP(src=eps[0].ip4.address,
1166                                           dst="1.1.1.1") /
1167                                        UDP(sport=1234, dport=1234) /
1168                                        Raw('\xa5' * 100))
1169
1170         # no policy yet
1171         self.send_and_assert_no_replies(eps[0].itf,
1172                                         pkt_inter_epg_220_to_global * 65)
1173
1174         acl2 = VppGbpAcl(self)
1175         rule = acl2.create_rule(permit_deny=1, proto=17, sport_from=1234,
1176                                 sport_to=1234, dport_from=1234, dport_to=1234)
1177         rule2 = acl2.create_rule(is_ipv6=1, permit_deny=1, proto=17,
1178                                  sport_from=1234, sport_to=1234,
1179                                  dport_from=1234, dport_to=1234)
1180
1181         acl_index2 = acl2.add_vpp_config([rule, rule2])
1182         c4 = VppGbpContract(self, 220, 333, acl_index2)
1183         c4.add_vpp_config()
1184
1185         self.send_and_expect_natted(eps[0].itf,
1186                                     pkt_inter_epg_220_to_global * 65,
1187                                     self.pg7,
1188                                     eps[0].fip4.address)
1189
1190         pkt_inter_epg_220_to_global = (Ether(src=self.pg0.remote_mac,
1191                                              dst=self.router_mac.address) /
1192                                        IPv6(src=eps[0].ip6.address,
1193                                             dst="6001::1") /
1194                                        UDP(sport=1234, dport=1234) /
1195                                        Raw('\xa5' * 100))
1196
1197         self.send_and_expect_natted6(self.pg0,
1198                                      pkt_inter_epg_220_to_global * 65,
1199                                      self.pg7,
1200                                      eps[0].fip6.address)
1201
1202         #
1203         # From a global address to an EP: OUT2IN
1204         #
1205         pkt_inter_epg_220_from_global = (Ether(src=self.router_mac.address,
1206                                                dst=self.pg0.remote_mac) /
1207                                          IP(dst=eps[0].fip4.address,
1208                                             src="1.1.1.1") /
1209                                          UDP(sport=1234, dport=1234) /
1210                                          Raw('\xa5' * 100))
1211
1212         self.send_and_assert_no_replies(self.pg7,
1213                                         pkt_inter_epg_220_from_global * 65)
1214
1215         c5 = VppGbpContract(self, 333, 220, acl_index2)
1216         c5.add_vpp_config()
1217
1218         self.send_and_expect_unnatted(self.pg7,
1219                                       pkt_inter_epg_220_from_global * 65,
1220                                       eps[0].itf,
1221                                       eps[0].ip4.address)
1222
1223         pkt_inter_epg_220_from_global = (Ether(src=self.router_mac.address,
1224                                                dst=self.pg0.remote_mac) /
1225                                          IPv6(dst=eps[0].fip6.address,
1226                                               src="6001::1") /
1227                                          UDP(sport=1234, dport=1234) /
1228                                          Raw('\xa5' * 100))
1229
1230         self.send_and_expect_unnatted6(self.pg7,
1231                                        pkt_inter_epg_220_from_global * 65,
1232                                        eps[0].itf,
1233                                        eps[0].ip6.address)
1234
1235         #
1236         # From a local VM to another local VM using resp. public addresses:
1237         #  IN2OUT2IN
1238         #
1239         pkt_intra_epg_220_global = (Ether(src=self.pg0.remote_mac,
1240                                           dst=self.router_mac.address) /
1241                                     IP(src=eps[0].ip4.address,
1242                                        dst=eps[1].fip4.address) /
1243                                     UDP(sport=1234, dport=1234) /
1244                                     Raw('\xa5' * 100))
1245
1246         self.send_and_expect_double_natted(eps[0].itf,
1247                                            pkt_intra_epg_220_global * 65,
1248                                            eps[1].itf,
1249                                            eps[0].fip4.address,
1250                                            eps[1].ip4.address)
1251
1252         pkt_intra_epg_220_global = (Ether(src=self.pg0.remote_mac,
1253                                           dst=self.router_mac.address) /
1254                                     IPv6(src=eps[0].ip6.address,
1255                                          dst=eps[1].fip6.address) /
1256                                     UDP(sport=1234, dport=1234) /
1257                                     Raw('\xa5' * 100))
1258
1259         self.send_and_expect_double_natted6(eps[0].itf,
1260                                             pkt_intra_epg_220_global * 65,
1261                                             eps[1].itf,
1262                                             eps[0].fip6.address,
1263                                             eps[1].ip6.address)
1264
1265         #
1266         # cleanup
1267         #
1268         for ep in eps:
1269             # del static mappings for each EP from the 10/8 to 11/8 network
1270             self.vapi.nat44_add_del_static_mapping(ep.ip4.bytes,
1271                                                    ep.fip4.bytes,
1272                                                    vrf_id=0,
1273                                                    addr_only=1,
1274                                                    is_add=0)
1275             self.vapi.nat66_add_del_static_mapping(ep.ip6.bytes,
1276                                                    ep.fip6.bytes,
1277                                                    vrf_id=0,
1278                                                    is_add=0)
1279
1280         for epg in epgs:
1281             # IP config on the BVI interfaces
1282             if epg != epgs[0] and epg != epgs[3]:
1283                 self.vapi.nat44_interface_add_del_feature(epg.bvi.sw_if_index,
1284                                                           is_inside=1,
1285                                                           is_add=0)
1286                 self.vapi.nat66_add_del_interface(epg.bvi.sw_if_index,
1287                                                   is_inside=1,
1288                                                   is_add=0)
1289
1290         for recirc in recircs:
1291             self.vapi.sw_interface_set_l2_emulation(
1292                 recirc.recirc.sw_if_index, enable=0)
1293             self.vapi.nat44_interface_add_del_feature(
1294                 recirc.recirc.sw_if_index,
1295                 is_inside=0,
1296                 is_add=0)
1297             self.vapi.nat66_add_del_interface(
1298                 recirc.recirc.sw_if_index,
1299                 is_inside=0,
1300                 is_add=0)
1301
1302     def test_gbp_learn_l2(self):
1303         """ GBP L2 Endpoint Learning """
1304
1305         learnt = [{'mac': '00:00:11:11:11:01',
1306                    'ip': '10.0.0.1',
1307                    'ip6': '2001:10::2'},
1308                   {'mac': '00:00:11:11:11:02',
1309                    'ip': '10.0.0.2',
1310                    'ip6': '2001:10::3'}]
1311
1312         #
1313         # lower the inactive threshold so these tests pass in a
1314         # reasonable amount of time
1315         #
1316         self.vapi.gbp_endpoint_learn_set_inactive_threshold(1)
1317
1318         #
1319         # IP tables
1320         #
1321         gt4 = VppIpTable(self, 1)
1322         gt4.add_vpp_config()
1323         gt6 = VppIpTable(self, 1, is_ip6=True)
1324         gt6.add_vpp_config()
1325
1326         rd1 = VppGbpRouteDomain(self, 1, gt4, gt6)
1327         rd1.add_vpp_config()
1328
1329         #
1330         # Pg2 hosts the vxlan tunnel, hosts on pg2 to act as TEPs
1331         # Pg3 hosts the IP4 UU-flood VXLAN tunnel
1332         # Pg4 hosts the IP6 UU-flood VXLAN tunnel
1333         #
1334         self.pg2.config_ip4()
1335         self.pg2.resolve_arp()
1336         self.pg2.generate_remote_hosts(4)
1337         self.pg2.configure_ipv4_neighbors()
1338         self.pg3.config_ip4()
1339         self.pg3.resolve_arp()
1340         self.pg4.config_ip4()
1341         self.pg4.resolve_arp()
1342
1343         #
1344         # a GBP bridge domain with a BVI and a UU-flood interface
1345         #
1346         bd1 = VppBridgeDomain(self, 1)
1347         bd1.add_vpp_config()
1348         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0, self.pg3)
1349         gbd1.add_vpp_config()
1350
1351         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1352         self.logger.info(self.vapi.cli("sh gbp bridge"))
1353
1354         # ... and has a /32 applied
1355         ip_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
1356         ip_addr.add_vpp_config()
1357
1358         #
1359         # The Endpoint-group in which we are learning endpoints
1360         #
1361         epg_220 = VppGbpEndpointGroup(self, 220, rd1, gbd1,
1362                                       None, self.loop0,
1363                                       "10.0.0.128",
1364                                       "2001:10::128")
1365         epg_220.add_vpp_config()
1366         epg_330 = VppGbpEndpointGroup(self, 330, rd1, gbd1,
1367                                       None, self.loop1,
1368                                       "10.0.1.128",
1369                                       "2001:11::128")
1370         epg_330.add_vpp_config()
1371
1372         #
1373         # The VXLAN GBP tunnel is a bridge-port and has L2 endpoint
1374         # leanring enabled
1375         #
1376         vx_tun_l2_1 = VppGbpVxlanTunnel(
1377             self, 99, bd1.bd_id,
1378             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L2)
1379         vx_tun_l2_1.add_vpp_config()
1380
1381         #
1382         # A static endpoint that the learnt endpoints are trying to
1383         # talk to
1384         #
1385         ep = VppGbpEndpoint(self, self.pg0,
1386                             epg_220, None,
1387                             "10.0.0.127", "11.0.0.127",
1388                             "2001:10::1", "3001::1")
1389         ep.add_vpp_config()
1390
1391         self.assertTrue(find_route(self, ep.ip4.address, 32, table_id=1))
1392
1393         # a packet with an sclass from an unknwon EPG
1394         p = (Ether(src=self.pg2.remote_mac,
1395                    dst=self.pg2.local_mac) /
1396              IP(src=self.pg2.remote_hosts[0].ip4,
1397                 dst=self.pg2.local_ip4) /
1398              UDP(sport=1234, dport=48879) /
1399              VXLAN(vni=99, gpid=88, flags=0x88) /
1400              Ether(src=learnt[0]["mac"], dst=ep.mac) /
1401              IP(src=learnt[0]["ip"], dst=ep.ip4.address) /
1402              UDP(sport=1234, dport=1234) /
1403              Raw('\xa5' * 100))
1404
1405         self.send_and_assert_no_replies(self.pg2, p)
1406
1407         #
1408         # we should not have learnt a new tunnel endpoint, since
1409         # the EPG was not learnt.
1410         #
1411         self.assertEqual(INDEX_INVALID,
1412                          find_vxlan_gbp_tunnel(self,
1413                                                self.pg2.local_ip4,
1414                                                self.pg2.remote_hosts[0].ip4,
1415                                                99))
1416
1417         # epg is not learnt, becasue the EPG is unknwon
1418         self.assertEqual(len(self.vapi.gbp_endpoint_dump()), 1)
1419
1420         for ii, l in enumerate(learnt):
1421             # a packet with an sclass from a knwon EPG
1422             # arriving on an unknown TEP
1423             p = (Ether(src=self.pg2.remote_mac,
1424                        dst=self.pg2.local_mac) /
1425                  IP(src=self.pg2.remote_hosts[1].ip4,
1426                     dst=self.pg2.local_ip4) /
1427                  UDP(sport=1234, dport=48879) /
1428                  VXLAN(vni=99, gpid=220, flags=0x88) /
1429                  Ether(src=l['mac'], dst=ep.mac) /
1430                  IP(src=l['ip'], dst=ep.ip4.address) /
1431                  UDP(sport=1234, dport=1234) /
1432                  Raw('\xa5' * 100))
1433
1434             rx = self.send_and_expect(self.pg2, [p], self.pg0)
1435
1436             # the new TEP
1437             tep1_sw_if_index = find_vxlan_gbp_tunnel(
1438                 self,
1439                 self.pg2.local_ip4,
1440                 self.pg2.remote_hosts[1].ip4,
1441                 99)
1442             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
1443
1444             #
1445             # the EP is learnt via the learnt TEP
1446             # both from its MAC and its IP
1447             #
1448             self.assertTrue(find_gbp_endpoint(self,
1449                                               vx_tun_l2_1.sw_if_index,
1450                                               mac=l['mac']))
1451             self.assertTrue(find_gbp_endpoint(self,
1452                                               vx_tun_l2_1.sw_if_index,
1453                                               ip=l['ip']))
1454
1455         self.logger.info(self.vapi.cli("show gbp endpoint"))
1456         self.logger.info(self.vapi.cli("show gbp vxlan"))
1457         self.logger.info(self.vapi.cli("show vxlan-gbp tunnel"))
1458
1459         #
1460         # If we sleep for the threshold time, the learnt endpoints should
1461         # age out
1462         #
1463         self.sleep(2)
1464         for l in learnt:
1465             self.assertFalse(find_gbp_endpoint(self,
1466                                                tep1_sw_if_index,
1467                                                mac=l['mac']))
1468
1469         self.logger.info(self.vapi.cli("show gbp endpoint"))
1470         self.logger.info(self.vapi.cli("show gbp vxlan"))
1471         self.logger.info(self.vapi.cli("show vxlan-gbp tunnel"))
1472
1473         #
1474         # repeat. the do not learn bit is set so the EPs are not learnt
1475         #
1476         for l in learnt:
1477             # a packet with an sclass from a knwon EPG
1478             p = (Ether(src=self.pg2.remote_mac,
1479                        dst=self.pg2.local_mac) /
1480                  IP(src=self.pg2.remote_hosts[1].ip4,
1481                     dst=self.pg2.local_ip4) /
1482                  UDP(sport=1234, dport=48879) /
1483                  VXLAN(vni=99, gpid=220, flags=0x88, gpflags="D") /
1484                  Ether(src=l['mac'], dst=ep.mac) /
1485                  IP(src=l['ip'], dst=ep.ip4.address) /
1486                  UDP(sport=1234, dport=1234) /
1487                  Raw('\xa5' * 100))
1488
1489             rx = self.send_and_expect(self.pg2, p*65, self.pg0)
1490
1491         for l in learnt:
1492             self.assertFalse(find_gbp_endpoint(self,
1493                                                vx_tun_l2_1.sw_if_index,
1494                                                mac=l['mac']))
1495
1496         #
1497         # repeat
1498         #
1499         for l in learnt:
1500             # a packet with an sclass from a knwon EPG
1501             p = (Ether(src=self.pg2.remote_mac,
1502                        dst=self.pg2.local_mac) /
1503                  IP(src=self.pg2.remote_hosts[1].ip4,
1504                     dst=self.pg2.local_ip4) /
1505                  UDP(sport=1234, dport=48879) /
1506                  VXLAN(vni=99, gpid=220, flags=0x88) /
1507                  Ether(src=l['mac'], dst=ep.mac) /
1508                  IP(src=l['ip'], dst=ep.ip4.address) /
1509                  UDP(sport=1234, dport=1234) /
1510                  Raw('\xa5' * 100))
1511
1512             rx = self.send_and_expect(self.pg2, p*65, self.pg0)
1513
1514             self.assertTrue(find_gbp_endpoint(self,
1515                                               vx_tun_l2_1.sw_if_index,
1516                                               mac=l['mac']))
1517
1518         #
1519         # Static EP replies to dynamics
1520         #
1521         self.logger.info(self.vapi.cli("sh l2fib bd_id 1"))
1522         for l in learnt:
1523             p = (Ether(src=ep.mac, dst=l['mac']) /
1524                  IP(dst=l['ip'], src=ep.ip4.address) /
1525                  UDP(sport=1234, dport=1234) /
1526                  Raw('\xa5' * 100))
1527
1528             rxs = self.send_and_expect(self.pg0, p * 17, self.pg2)
1529
1530             for rx in rxs:
1531                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
1532                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
1533                 self.assertEqual(rx[UDP].dport, 48879)
1534                 # the UDP source port is a random value for hashing
1535                 self.assertEqual(rx[VXLAN].gpid, 220)
1536                 self.assertEqual(rx[VXLAN].vni, 99)
1537                 self.assertTrue(rx[VXLAN].flags.G)
1538                 self.assertTrue(rx[VXLAN].flags.Instance)
1539                 self.assertTrue(rx[VXLAN].gpflags.A)
1540                 self.assertFalse(rx[VXLAN].gpflags.D)
1541
1542         self.sleep(2)
1543         for l in learnt:
1544             self.assertFalse(find_gbp_endpoint(self,
1545                                                vx_tun_l2_1.sw_if_index,
1546                                                mac=l['mac']))
1547
1548         #
1549         # repeat in the other EPG
1550         # there's no contract between 220 and 330, but the A-bit is set
1551         # so the packet is cleared for delivery
1552         #
1553         for l in learnt:
1554             # a packet with an sclass from a knwon EPG
1555             p = (Ether(src=self.pg2.remote_mac,
1556                        dst=self.pg2.local_mac) /
1557                  IP(src=self.pg2.remote_hosts[1].ip4,
1558                     dst=self.pg2.local_ip4) /
1559                  UDP(sport=1234, dport=48879) /
1560                  VXLAN(vni=99, gpid=330, flags=0x88, gpflags='A') /
1561                  Ether(src=l['mac'], dst=ep.mac) /
1562                  IP(src=l['ip'], dst=ep.ip4.address) /
1563                  UDP(sport=1234, dport=1234) /
1564                  Raw('\xa5' * 100))
1565
1566             rx = self.send_and_expect(self.pg2, p*65, self.pg0)
1567
1568             self.assertTrue(find_gbp_endpoint(self,
1569                                               vx_tun_l2_1.sw_if_index,
1570                                               mac=l['mac']))
1571
1572         #
1573         # static EP cannot reach the learnt EPs since there is no contract
1574         #
1575         self.logger.info(self.vapi.cli("show gbp endpoint"))
1576         self.logger.info(self.vapi.cli("show l2fib all"))
1577         for l in learnt:
1578             p = (Ether(src=ep.mac, dst=l['mac']) /
1579                  IP(dst=l['ip'], src=ep.ip4.address) /
1580                  UDP(sport=1234, dport=1234) /
1581                  Raw('\xa5' * 100))
1582
1583             self.send_and_assert_no_replies(self.pg0, [p], timeout=0.2)
1584
1585         #
1586         # refresh the entries after the check for no replies above
1587         #
1588         for l in learnt:
1589             # a packet with an sclass from a knwon EPG
1590             p = (Ether(src=self.pg2.remote_mac,
1591                        dst=self.pg2.local_mac) /
1592                  IP(src=self.pg2.remote_hosts[1].ip4,
1593                     dst=self.pg2.local_ip4) /
1594                  UDP(sport=1234, dport=48879) /
1595                  VXLAN(vni=99, gpid=330, flags=0x88, gpflags='A') /
1596                  Ether(src=l['mac'], dst=ep.mac) /
1597                  IP(src=l['ip'], dst=ep.ip4.address) /
1598                  UDP(sport=1234, dport=1234) /
1599                  Raw('\xa5' * 100))
1600
1601             rx = self.send_and_expect(self.pg2, p*65, self.pg0)
1602
1603             self.assertTrue(find_gbp_endpoint(self,
1604                                               vx_tun_l2_1.sw_if_index,
1605                                               mac=l['mac']))
1606
1607         #
1608         # Add the contract so they can talk
1609         #
1610         acl = VppGbpAcl(self)
1611         rule = acl.create_rule(permit_deny=1, proto=17)
1612         rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
1613         acl_index = acl.add_vpp_config([rule, rule2])
1614         c1 = VppGbpContract(self, 220, 330, acl_index)
1615         c1.add_vpp_config()
1616
1617         for l in learnt:
1618             p = (Ether(src=ep.mac, dst=l['mac']) /
1619                  IP(dst=l['ip'], src=ep.ip4.address) /
1620                  UDP(sport=1234, dport=1234) /
1621                  Raw('\xa5' * 100))
1622
1623             self.send_and_expect(self.pg0, [p], self.pg2)
1624
1625         #
1626         # send UU packets from the local EP
1627         #
1628         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1629         self.logger.info(self.vapi.cli("sh gbp bridge"))
1630         p_uu = (Ether(src=ep.mac, dst="00:11:11:11:11:11") /
1631                 IP(dst="10.0.0.133", src=ep.ip4.address) /
1632                 UDP(sport=1234, dport=1234) /
1633                 Raw('\xa5' * 100))
1634         rxs = self.send_and_expect(ep.itf, [p_uu], gbd1.uu_flood)
1635
1636         #
1637         # Add a mcast destination VXLAN-GBP tunnel for B&M traffic
1638         #
1639         tun_bm = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
1640                                    "239.1.1.1", 88,
1641                                    mcast_itf=self.pg4)
1642         tun_bm.add_vpp_config()
1643         bp_bm = VppBridgeDomainPort(self, bd1, tun_bm,
1644                                     port_type=L2_PORT_TYPE.NORMAL)
1645         bp_bm.add_vpp_config()
1646
1647         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1648
1649         p_bm = (Ether(src=ep.mac, dst="ff:ff:ff:ff:ff:ff") /
1650                 IP(dst="10.0.0.133", src=ep.ip4.address) /
1651                 UDP(sport=1234, dport=1234) /
1652                 Raw('\xa5' * 100))
1653         rxs = self.send_and_expect_only(ep.itf, [p_bm], tun_bm.mcast_itf)
1654
1655         #
1656         # Check v6 Endpoints
1657         #
1658         for l in learnt:
1659             # a packet with an sclass from a knwon EPG
1660             p = (Ether(src=self.pg2.remote_mac,
1661                        dst=self.pg2.local_mac) /
1662                  IP(src=self.pg2.remote_hosts[1].ip4,
1663                     dst=self.pg2.local_ip4) /
1664                  UDP(sport=1234, dport=48879) /
1665                  VXLAN(vni=99, gpid=330, flags=0x88, gpflags='A') /
1666                  Ether(src=l['mac'], dst=ep.mac) /
1667                  IPv6(src=l['ip6'], dst=ep.ip6.address) /
1668                  UDP(sport=1234, dport=1234) /
1669                  Raw('\xa5' * 100))
1670
1671             rx = self.send_and_expect(self.pg2, p*65, self.pg0)
1672
1673             self.assertTrue(find_gbp_endpoint(self,
1674                                               vx_tun_l2_1.sw_if_index,
1675                                               mac=l['mac']))
1676
1677         #
1678         # L3 Endpoint Learning
1679         #  - configured on the bridge's BVI
1680         #
1681
1682         #
1683         # clean up
1684         #
1685         self.sleep(2)
1686         for l in learnt:
1687             self.assertFalse(find_gbp_endpoint(self,
1688                                                vx_tun_l2_1.sw_if_index,
1689                                                mac=l['mac']))
1690
1691         self.pg2.unconfig_ip4()
1692         self.pg3.unconfig_ip4()
1693         self.pg4.unconfig_ip4()
1694
1695         self.logger.info(self.vapi.cli("sh int"))
1696         self.logger.info(self.vapi.cli("sh gbp vxlan"))
1697
1698     def test_gbp_learn_l3(self):
1699         """ GBP L3 Endpoint Learning """
1700
1701         routed_dst_mac = "00:0c:0c:0c:0c:0c"
1702         routed_src_mac = "00:22:bd:f8:19:ff"
1703
1704         learnt = [{'mac': '00:00:11:11:11:02',
1705                    'ip': '10.0.1.2',
1706                    'ip6': '2001:10::2'},
1707                   {'mac': '00:00:11:11:11:03',
1708                    'ip': '10.0.1.3',
1709                    'ip6': '2001:10::3'}]
1710
1711         #
1712         # lower the inactive threshold so these tests pass in a
1713         # reasonable amount of time
1714         #
1715         self.vapi.gbp_endpoint_learn_set_inactive_threshold(1)
1716
1717         #
1718         # IP tables
1719         #
1720         t4 = VppIpTable(self, 1)
1721         t4.add_vpp_config()
1722         t6 = VppIpTable(self, 1, True)
1723         t6.add_vpp_config()
1724
1725         tun_ip4_uu = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
1726                                        self.pg4.remote_ip4, 114)
1727         tun_ip6_uu = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
1728                                        self.pg4.remote_ip4, 116)
1729         tun_ip4_uu.add_vpp_config()
1730         tun_ip6_uu.add_vpp_config()
1731
1732         rd1 = VppGbpRouteDomain(self, 2, t4, t6, tun_ip4_uu, tun_ip6_uu)
1733         rd1.add_vpp_config()
1734
1735         self.loop0.set_mac(self.router_mac.address)
1736
1737         #
1738         # Bind the BVI to the RD
1739         #
1740         VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
1741         VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
1742
1743         #
1744         # Pg2 hosts the vxlan tunnel
1745         # hosts on pg2 to act as TEPs
1746         # pg3 is BD uu-fwd
1747         # pg4 is RD uu-fwd
1748         #
1749         self.pg2.config_ip4()
1750         self.pg2.resolve_arp()
1751         self.pg2.generate_remote_hosts(4)
1752         self.pg2.configure_ipv4_neighbors()
1753         self.pg3.config_ip4()
1754         self.pg3.resolve_arp()
1755         self.pg4.config_ip4()
1756         self.pg4.resolve_arp()
1757
1758         #
1759         # a GBP bridge domain with a BVI and a UU-flood interface
1760         #
1761         bd1 = VppBridgeDomain(self, 1)
1762         bd1.add_vpp_config()
1763         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0, self.pg3)
1764         gbd1.add_vpp_config()
1765
1766         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1767         self.logger.info(self.vapi.cli("sh gbp bridge"))
1768         self.logger.info(self.vapi.cli("sh gbp route"))
1769         self.logger.info(self.vapi.cli("show l2fib all"))
1770
1771         # ... and has a /32 and /128 applied
1772         ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
1773         ip4_addr.add_vpp_config()
1774         ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128", 128)
1775         ip6_addr.add_vpp_config()
1776
1777         #
1778         # The Endpoint-group in which we are learning endpoints
1779         #
1780         epg_220 = VppGbpEndpointGroup(self, 220, rd1, gbd1,
1781                                       None, self.loop0,
1782                                       "10.0.0.128",
1783                                       "2001:10::128")
1784         epg_220.add_vpp_config()
1785
1786         #
1787         # The VXLAN GBP tunnel is a bridge-port and has L2 endpoint
1788         # leanring enabled
1789         #
1790         vx_tun_l3 = VppGbpVxlanTunnel(
1791             self, 101, rd1.rd_id,
1792             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3)
1793         vx_tun_l3.add_vpp_config()
1794
1795         #
1796         # A static endpoint that the learnt endpoints are trying to
1797         # talk to
1798         #
1799         ep = VppGbpEndpoint(self, self.pg0,
1800                             epg_220, None,
1801                             "10.0.0.127", "11.0.0.127",
1802                             "2001:10::1", "3001::1")
1803         ep.add_vpp_config()
1804
1805         #
1806         # learn some remote IPv4 EPs
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=101, gpid=220, flags=0x88) /
1817                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
1818                  IP(src=l['ip'], dst=ep.ip4.address) /
1819                  UDP(sport=1234, dport=1234) /
1820                  Raw('\xa5' * 100))
1821
1822             rx = self.send_and_expect(self.pg2, [p], self.pg0)
1823
1824             # the new TEP
1825             tep1_sw_if_index = find_vxlan_gbp_tunnel(
1826                 self,
1827                 self.pg2.local_ip4,
1828                 self.pg2.remote_hosts[1].ip4,
1829                 vx_tun_l3.vni)
1830             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
1831
1832             # endpoint learnt via the parent GBP-vxlan interface
1833             self.assertTrue(find_gbp_endpoint(self,
1834                                               vx_tun_l3._sw_if_index,
1835                                               ip=l['ip']))
1836
1837         #
1838         # Static IPv4 EP replies to learnt
1839         #
1840         for l in learnt:
1841             p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
1842                  IP(dst=l['ip'], src=ep.ip4.address) /
1843                  UDP(sport=1234, dport=1234) /
1844                  Raw('\xa5' * 100))
1845
1846             rxs = self.send_and_expect(self.pg0, p*1, self.pg2)
1847
1848             for rx in rxs:
1849                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
1850                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
1851                 self.assertEqual(rx[UDP].dport, 48879)
1852                 # the UDP source port is a random value for hashing
1853                 self.assertEqual(rx[VXLAN].gpid, 220)
1854                 self.assertEqual(rx[VXLAN].vni, 101)
1855                 self.assertTrue(rx[VXLAN].flags.G)
1856                 self.assertTrue(rx[VXLAN].flags.Instance)
1857                 self.assertTrue(rx[VXLAN].gpflags.A)
1858                 self.assertFalse(rx[VXLAN].gpflags.D)
1859
1860                 inner = rx[VXLAN].payload
1861
1862                 self.assertEqual(inner[Ether].src, routed_src_mac)
1863                 self.assertEqual(inner[Ether].dst, routed_dst_mac)
1864                 self.assertEqual(inner[IP].src, ep.ip4.address)
1865                 self.assertEqual(inner[IP].dst, l['ip'])
1866
1867         self.sleep(2)
1868         for l in learnt:
1869             self.assertFalse(find_gbp_endpoint(self,
1870                                                tep1_sw_if_index,
1871                                                ip=l['ip']))
1872
1873         #
1874         # learn some remote IPv6 EPs
1875         #
1876         for ii, l in enumerate(learnt):
1877             # a packet with an sclass from a knwon EPG
1878             # arriving on an unknown TEP
1879             p = (Ether(src=self.pg2.remote_mac,
1880                        dst=self.pg2.local_mac) /
1881                  IP(src=self.pg2.remote_hosts[1].ip4,
1882                     dst=self.pg2.local_ip4) /
1883                  UDP(sport=1234, dport=48879) /
1884                  VXLAN(vni=101, gpid=220, flags=0x88) /
1885                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
1886                  IPv6(src=l['ip6'], dst=ep.ip6.address) /
1887                  UDP(sport=1234, dport=1234) /
1888                  Raw('\xa5' * 100))
1889
1890             rx = self.send_and_expect(self.pg2, [p], self.pg0)
1891
1892             # the new TEP
1893             tep1_sw_if_index = find_vxlan_gbp_tunnel(
1894                 self,
1895                 self.pg2.local_ip4,
1896                 self.pg2.remote_hosts[1].ip4,
1897                 vx_tun_l3.vni)
1898             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
1899
1900             self.logger.info(self.vapi.cli("show gbp bridge"))
1901             self.logger.info(self.vapi.cli("show vxlan-gbp tunnel"))
1902             self.logger.info(self.vapi.cli("show gbp vxlan"))
1903             self.logger.info(self.vapi.cli("show int addr"))
1904
1905             # endpoint learnt via the TEP
1906             self.assertTrue(find_gbp_endpoint(self, ip=l['ip6']))
1907
1908         self.logger.info(self.vapi.cli("show gbp endpoint"))
1909         self.logger.info(self.vapi.cli("show ip fib index 1 %s" % l['ip']))
1910
1911         #
1912         # Static EP replies to learnt
1913         #
1914         for l in learnt:
1915             p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
1916                  IPv6(dst=l['ip6'], src=ep.ip6.address) /
1917                  UDP(sport=1234, dport=1234) /
1918                  Raw('\xa5' * 100))
1919
1920             rxs = self.send_and_expect(self.pg0, p*65, self.pg2)
1921
1922             for rx in rxs:
1923                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
1924                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
1925                 self.assertEqual(rx[UDP].dport, 48879)
1926                 # the UDP source port is a random value for hashing
1927                 self.assertEqual(rx[VXLAN].gpid, 220)
1928                 self.assertEqual(rx[VXLAN].vni, 101)
1929                 self.assertTrue(rx[VXLAN].flags.G)
1930                 self.assertTrue(rx[VXLAN].flags.Instance)
1931                 self.assertTrue(rx[VXLAN].gpflags.A)
1932                 self.assertFalse(rx[VXLAN].gpflags.D)
1933
1934                 inner = rx[VXLAN].payload
1935
1936                 self.assertEqual(inner[Ether].src, routed_src_mac)
1937                 self.assertEqual(inner[Ether].dst, routed_dst_mac)
1938                 self.assertEqual(inner[IPv6].src, ep.ip6.address)
1939                 self.assertEqual(inner[IPv6].dst, l['ip6'])
1940
1941         self.logger.info(self.vapi.cli("sh gbp endpoint"))
1942         self.sleep(2)
1943         for l in learnt:
1944             self.assertFalse(find_gbp_endpoint(self,
1945                                                tep1_sw_if_index,
1946                                                ip=l['ip']))
1947
1948         #
1949         # Static sends to unknown EP with no route
1950         #
1951         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
1952              IP(dst="10.0.0.99", src=ep.ip4.address) /
1953              UDP(sport=1234, dport=1234) /
1954              Raw('\xa5' * 100))
1955
1956         self.send_and_assert_no_replies(self.pg0, [p])
1957
1958         #
1959         # Add a route to static EP's v4 and v6 subnet
1960         #  packets should be send on the v4/v6 uu=fwd interface resp.
1961         #
1962         se_10_24 = VppGbpSubnet(
1963             self, rd1, "10.0.0.0", 24,
1964             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_TRANSPORT)
1965         se_10_24.add_vpp_config()
1966
1967         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
1968              IP(dst="10.0.0.99", src=ep.ip4.address) /
1969              UDP(sport=1234, dport=1234) /
1970              Raw('\xa5' * 100))
1971
1972         rxs = self.send_and_expect(self.pg0, [p], self.pg4)
1973         for rx in rxs:
1974             self.assertEqual(rx[IP].src, self.pg4.local_ip4)
1975             self.assertEqual(rx[IP].dst, self.pg4.remote_ip4)
1976             self.assertEqual(rx[UDP].dport, 48879)
1977             # the UDP source port is a random value for hashing
1978             self.assertEqual(rx[VXLAN].gpid, 220)
1979             self.assertEqual(rx[VXLAN].vni, 114)
1980             self.assertTrue(rx[VXLAN].flags.G)
1981             self.assertTrue(rx[VXLAN].flags.Instance)
1982             # policy is not applied to packets sent to the uu-fwd interfaces
1983             self.assertFalse(rx[VXLAN].gpflags.A)
1984             self.assertFalse(rx[VXLAN].gpflags.D)
1985
1986         #
1987         # learn some remote IPv4 EPs
1988         #
1989         for ii, l in enumerate(learnt):
1990             # a packet with an sclass from a knwon EPG
1991             # arriving on an unknown TEP
1992             p = (Ether(src=self.pg2.remote_mac,
1993                        dst=self.pg2.local_mac) /
1994                  IP(src=self.pg2.remote_hosts[1].ip4,
1995                     dst=self.pg2.local_ip4) /
1996                  UDP(sport=1234, dport=48879) /
1997                  VXLAN(vni=101, gpid=220, flags=0x88) /
1998                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
1999                  IP(src=l['ip'], dst=ep.ip4.address) /
2000                  UDP(sport=1234, dport=1234) /
2001                  Raw('\xa5' * 100))
2002
2003             rx = self.send_and_expect(self.pg2, [p], self.pg0)
2004
2005             # the new TEP
2006             tep1_sw_if_index = find_vxlan_gbp_tunnel(
2007                 self,
2008                 self.pg2.local_ip4,
2009                 self.pg2.remote_hosts[1].ip4,
2010                 vx_tun_l3.vni)
2011             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
2012
2013             # endpoint learnt via the parent GBP-vxlan interface
2014             self.assertTrue(find_gbp_endpoint(self,
2015                                               vx_tun_l3._sw_if_index,
2016                                               ip=l['ip']))
2017
2018         #
2019         # Add a remote endpoint from the API
2020         #
2021         rep_88 = VppGbpEndpoint(self, vx_tun_l3,
2022                                 epg_220, None,
2023                                 "10.0.0.88", "11.0.0.88",
2024                                 "2001:10::88", "3001::88",
2025                                 VppEnum.vl_api_gbp_endpoint_flags_t.REMOTE,
2026                                 self.pg2.local_ip4,
2027                                 self.pg2.remote_hosts[1].ip4,
2028                                 mac=None)
2029         rep_88.add_vpp_config()
2030
2031         #
2032         # Add a remote endpoint from the API that matches an existing one
2033         #
2034         rep_2 = VppGbpEndpoint(self, vx_tun_l3,
2035                                epg_220, None,
2036                                learnt[0]['ip'], "11.0.0.101",
2037                                learnt[0]['ip6'], "3001::101",
2038                                VppEnum.vl_api_gbp_endpoint_flags_t.REMOTE,
2039                                self.pg2.local_ip4,
2040                                self.pg2.remote_hosts[1].ip4,
2041                                mac=None)
2042         rep_2.add_vpp_config()
2043
2044         #
2045         # Add a route to the leanred EP's v4 subnet
2046         #  packets should be send on the v4/v6 uu=fwd interface resp.
2047         #
2048         se_10_1_24 = VppGbpSubnet(
2049             self, rd1, "10.0.1.0", 24,
2050             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_TRANSPORT)
2051         se_10_1_24.add_vpp_config()
2052
2053         self.logger.info(self.vapi.cli("show gbp endpoint"))
2054
2055         ips = ["10.0.0.88", learnt[0]['ip']]
2056         for ip in ips:
2057             p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2058                  IP(dst=ip, src=ep.ip4.address) /
2059                  UDP(sport=1234, dport=1234) /
2060                  Raw('\xa5' * 100))
2061
2062             rxs = self.send_and_expect(self.pg0, p*65, self.pg2)
2063
2064             for rx in rxs:
2065                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2066                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
2067                 self.assertEqual(rx[UDP].dport, 48879)
2068                 # the UDP source port is a random value for hashing
2069                 self.assertEqual(rx[VXLAN].gpid, 220)
2070                 self.assertEqual(rx[VXLAN].vni, 101)
2071                 self.assertTrue(rx[VXLAN].flags.G)
2072                 self.assertTrue(rx[VXLAN].flags.Instance)
2073                 self.assertTrue(rx[VXLAN].gpflags.A)
2074                 self.assertFalse(rx[VXLAN].gpflags.D)
2075
2076                 inner = rx[VXLAN].payload
2077
2078                 self.assertEqual(inner[Ether].src, routed_src_mac)
2079                 self.assertEqual(inner[Ether].dst, routed_dst_mac)
2080                 self.assertEqual(inner[IP].src, ep.ip4.address)
2081                 self.assertEqual(inner[IP].dst, ip)
2082
2083         #
2084         # remove the API remote EPs, they are now UU-fwd
2085         #
2086         rep_88.remove_vpp_config()
2087         rep_2.remove_vpp_config()
2088
2089         self.logger.info(self.vapi.cli("show gbp endpoint"))
2090
2091         for ip in ips:
2092             self.assertFalse(find_gbp_endpoint(self, ip=ip))
2093
2094             p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2095                  IP(dst=ip, src=ep.ip4.address) /
2096                  UDP(sport=1234, dport=1234) /
2097                  Raw('\xa5' * 100))
2098
2099             rxs = self.send_and_expect(self.pg0, [p], self.pg4)
2100
2101         #
2102         # shutdown with learnt endpoint present
2103         #
2104         self.logger.info(self.vapi.cli("show gbp endpoint-group"))
2105
2106         #
2107         # TODO
2108         # remote endpoint becomes local
2109         #
2110         self.pg2.unconfig_ip4()
2111         self.pg3.unconfig_ip4()
2112         self.pg4.unconfig_ip4()
2113
2114
2115 if __name__ == '__main__':
2116     unittest.main(testRunner=VppTestRunner)