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