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