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