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