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