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