misc: deprecate gbp and its dependents
[vpp.git] / extras / deprecated / plugins / gbp / test_gbp.py
1 #!/usr/bin/env python3
2 import typing
3 from socket import AF_INET6, inet_pton, inet_ntop
4 import unittest
5 from ipaddress import ip_address, IPv4Network, IPv6Network
6
7 from scapy.packet import Raw
8 from scapy.layers.l2 import Ether, ARP, Dot1Q
9 from scapy.layers.inet import IP, UDP, ICMP
10 from scapy.layers.inet6 import (
11     IPv6,
12     ICMPv6ND_NS,
13     ICMPv6NDOptSrcLLAddr,
14     ICMPv6ND_NA,
15     ICMPv6EchoRequest,
16 )
17 from scapy.utils6 import in6_getnsma, in6_getnsmac
18 from scapy.layers.vxlan import VXLAN
19 from scapy.data import ETH_P_IP, ETH_P_IPV6
20
21 from framework import tag_fixme_vpp_workers
22 from framework import VppTestCase, VppTestRunner
23 from vpp_object import VppObject
24 from vpp_interface import VppInterface
25 from vpp_ip_route import (
26     VppIpRoute,
27     VppRoutePath,
28     VppIpTable,
29     VppIpInterfaceAddress,
30     VppIpInterfaceBind,
31     find_route,
32     FibPathProto,
33     FibPathType,
34 )
35 from vpp_l2 import (
36     VppBridgeDomain,
37     VppBridgeDomainPort,
38     VppBridgeDomainArpEntry,
39     VppL2FibEntry,
40     find_bridge_domain_port,
41     VppL2Vtr,
42 )
43 from vpp_sub_interface import L2_VTR_OP, VppDot1QSubint
44 from vpp_ip import DpoProto, get_dpo_proto
45 from vpp_papi import VppEnum, MACAddress
46 from vpp_vxlan_gbp_tunnel import find_vxlan_gbp_tunnel, INDEX_INVALID, \
47     VppVxlanGbpTunnel
48 from vpp_neighbor import VppNeighbor
49 from vpp_acl import AclRule, VppAcl
50
51 NUM_PKTS = 67
52
53
54 def find_gbp_endpoint(test, sw_if_index=None, ip=None, mac=None,
55                       tep=None, sclass=None, flags=None):
56     if ip:
57         vip = ip
58     if mac:
59         vmac = MACAddress(mac)
60
61     eps = test.vapi.gbp_endpoint_dump()
62
63     for ep in eps:
64         if tep:
65             src = tep[0]
66             dst = tep[1]
67             if src != str(ep.endpoint.tun.src) or \
68                dst != str(ep.endpoint.tun.dst):
69                 continue
70         if sw_if_index:
71             if ep.endpoint.sw_if_index != sw_if_index:
72                 continue
73         if sclass:
74             if ep.endpoint.sclass != sclass:
75                 continue
76         if flags:
77             if flags != (flags & ep.endpoint.flags):
78                 continue
79         if ip:
80             for eip in ep.endpoint.ips:
81                 if vip == str(eip):
82                     return True
83         if mac:
84             if vmac == ep.endpoint.mac:
85                 return True
86
87     return False
88
89
90 def find_gbp_vxlan(test: VppTestCase, vni):
91     ts = test.vapi.gbp_vxlan_tunnel_dump()
92     for t in ts:
93         if t.tunnel.vni == vni:
94             return True
95     return False
96
97
98 class VppGbpEndpoint(VppObject):
99     """
100     GBP Endpoint
101     """
102
103     @property
104     def mac(self):
105         return str(self.vmac)
106
107     @property
108     def ip4(self):
109         return self._ip4
110
111     @property
112     def fip4(self):
113         return self._fip4
114
115     @property
116     def ip6(self):
117         return self._ip6
118
119     @property
120     def fip6(self):
121         return self._fip6
122
123     @property
124     def ips(self):
125         return [self.ip4, self.ip6]
126
127     @property
128     def fips(self):
129         return [self.fip4, self.fip6]
130
131     def __init__(self, test, itf, epg, recirc, ip4, fip4, ip6, fip6,
132                  flags=0,
133                  tun_src="0.0.0.0",
134                  tun_dst="0.0.0.0",
135                  mac=True):
136         self._test = test
137         self.itf = itf
138         self.handle = None
139         self.epg = epg
140         self.recirc = recirc
141
142         self._ip4 = ip4
143         self._fip4 = fip4
144         self._ip6 = ip6
145         self._fip6 = fip6
146
147         if mac:
148             self.vmac = MACAddress(self.itf.remote_mac)
149         else:
150             self.vmac = MACAddress("00:00:00:00:00:00")
151
152         self.flags = flags
153         self.tun_src = tun_src
154         self.tun_dst = tun_dst
155
156     def encode(self):
157         ips = [self.ip4, self.ip6]
158         return {
159             "sw_if_index": self.itf.sw_if_index,
160             "ips": ips,
161             "n_ips": len(ips),
162             "mac": self.vmac.packed,
163             "sclass": self.epg.sclass,
164             "flags": self.flags,
165             "tun": {
166                 "src": self.tun_src,
167                 "dst": self.tun_dst,
168             },
169         }
170
171     def add_vpp_config(self):
172         res = self._test.vapi.gbp_endpoint_add(
173             endpoint=self.encode(),
174         )
175         self.handle = res.handle
176         self._test.registry.register(self, self._test.logger)
177
178     def remove_vpp_config(self):
179         self._test.vapi.gbp_endpoint_del(handle=self.handle)
180
181     def object_id(self):
182         return "gbp-endpoint:[%d==%d:%s:%d]" % (self.handle,
183                                                 self.itf.sw_if_index,
184                                                 self.ip4,
185                                                 self.epg.sclass)
186
187     def query_vpp_config(self):
188         return find_gbp_endpoint(self._test,
189                                  self.itf.sw_if_index,
190                                  self.ip4)
191
192
193 class VppGbpRecirc(VppObject):
194     """
195     GBP Recirculation Interface
196     """
197
198     def __init__(self, test, epg, recirc, is_ext=False):
199         self._test = test
200         self.recirc = recirc
201         self.epg = epg
202         self.is_ext = is_ext
203
204     def encode(self):
205         return {
206             "is_ext": self.is_ext,
207             "sw_if_index": self.recirc.sw_if_index,
208             "sclass": self.epg.sclass,
209         }
210
211     def add_vpp_config(self):
212         self._test.vapi.gbp_recirc_add_del(
213             1,
214             recirc=self.encode(),
215         )
216         self._test.registry.register(self, self._test.logger)
217
218     def remove_vpp_config(self):
219         self._test.vapi.gbp_recirc_add_del(
220             0,
221             recirc=self.encode(),
222         )
223
224     def object_id(self):
225         return "gbp-recirc:[%d]" % (self.recirc.sw_if_index)
226
227     def query_vpp_config(self):
228         rs = self._test.vapi.gbp_recirc_dump()
229         for r in rs:
230             if r.recirc.sw_if_index == self.recirc.sw_if_index:
231                 return True
232         return False
233
234
235 class VppGbpExtItf(VppObject):
236     """
237     GBP ExtItfulation Interface
238     """
239
240     def __init__(self, test, itf, bd, rd, anon=False):
241         self._test = test
242         self.itf = itf
243         self.bd = bd
244         self.rd = rd
245         self.flags = 1 if anon else 0
246
247     def encode(self):
248         return {
249             "sw_if_index": self.itf.sw_if_index,
250             "bd_id": self.bd.bd_id,
251             "rd_id": self.rd.rd_id,
252             "flags": self.flags,
253         }
254
255     def add_vpp_config(self):
256         self._test.vapi.gbp_ext_itf_add_del(
257             1,
258             ext_itf=self.encode(),
259         )
260         self._test.registry.register(self, self._test.logger)
261
262     def remove_vpp_config(self):
263         self._test.vapi.gbp_ext_itf_add_del(
264             0,
265             ext_itf=self.encode(),
266         )
267
268     def object_id(self):
269         return "gbp-ext-itf:[%d]%s" % (self.itf.sw_if_index,
270                                        " [anon]" if self.flags else "")
271
272     def query_vpp_config(self):
273         rs = self._test.vapi.gbp_ext_itf_dump()
274         for r in rs:
275             if r.ext_itf.sw_if_index == self.itf.sw_if_index:
276                 return True
277         return False
278
279
280 class VppGbpSubnet(VppObject):
281     """
282     GBP Subnet
283     """
284
285     def __init__(self, test, rd, address, address_len,
286                  type, sw_if_index=0xffffffff, sclass=0xffff):
287         # TODO: replace hardcoded defaults when vpp_papi supports
288         #  defaults in typedefs
289         self._test = test
290         self.rd_id = rd.rd_id
291         a = ip_address(address)
292         if 4 == a.version:
293             self.prefix = IPv4Network("%s/%d" % (address, address_len),
294                                       strict=False)
295         else:
296             self.prefix = IPv6Network("%s/%d" % (address, address_len),
297                                       strict=False)
298         self.type = type
299         self.sw_if_index = sw_if_index
300         self.sclass = sclass
301
302     def encode(self):
303         return {
304             "type": self.type,
305             "sw_if_index": self.sw_if_index,
306             "sclass": self.sclass,
307             "prefix": self.prefix,
308             "rd_id": self.rd_id,
309         }
310
311     def add_vpp_config(self):
312         self._test.vapi.gbp_subnet_add_del(
313             is_add=1,
314             subnet=self.encode(),
315         )
316         self._test.registry.register(self, self._test.logger)
317
318     def remove_vpp_config(self):
319         self._test.vapi.gbp_subnet_add_del(
320             is_add=0,
321             subnet=self.encode()
322         )
323
324     def object_id(self):
325         return "gbp-subnet:[%d-%s]" % (self.rd_id, self.prefix)
326
327     def query_vpp_config(self):
328         ss = self._test.vapi.gbp_subnet_dump()
329         for s in ss:
330             if s.subnet.rd_id == self.rd_id and \
331                     s.subnet.type == self.type and \
332                     s.subnet.prefix == self.prefix:
333                 return True
334         return False
335
336
337 class VppGbpEndpointRetention(object):
338     def __init__(self, remote_ep_timeout=0xffffffff):
339         self.remote_ep_timeout = remote_ep_timeout
340
341     def encode(self):
342         return {'remote_ep_timeout': self.remote_ep_timeout}
343
344
345 class VppGbpEndpointGroup(VppObject):
346     """
347     GBP Endpoint Group
348     """
349
350     def __init__(self, test, vnid, sclass, rd, bd, uplink,
351                  bvi, bvi_ip4, bvi_ip6=None,
352                  retention=VppGbpEndpointRetention()):
353         self._test = test
354         self.uplink = uplink
355         self.bvi = bvi
356         self.bvi_ip4 = bvi_ip4
357         self.bvi_ip6 = bvi_ip6
358         self.vnid = vnid
359         self.bd = bd  # VppGbpBridgeDomain
360         self.rd = rd
361         self.sclass = sclass
362         if 0 == self.sclass:
363             self.sclass = 0xffff
364         self.retention = retention
365
366     def encode(self) -> dict:
367         return {
368             "uplink_sw_if_index": self.uplink.sw_if_index
369             if self.uplink else INDEX_INVALID,
370             "bd_id": self.bd.bd.bd_id,
371             "rd_id": self.rd.rd_id,
372             "vnid": self.vnid,
373             "sclass": self.sclass,
374             "retention": self.retention.encode(),
375         }
376
377     def add_vpp_config(self):
378         self._test.vapi.gbp_endpoint_group_add(epg=self.encode())
379         self._test.registry.register(self, self._test.logger)
380
381     def remove_vpp_config(self):
382         self._test.vapi.gbp_endpoint_group_del(sclass=self.sclass)
383
384     def object_id(self) -> str:
385         return "gbp-endpoint-group:[%d]" % (self.vnid)
386
387     def query_vpp_config(self) -> bool:
388         epgs = self._test.vapi.gbp_endpoint_group_dump()
389         for epg in epgs:
390             if epg.epg.vnid == self.vnid:
391                 return True
392         return False
393
394
395 class VppGbpBridgeDomain(VppObject):
396     """
397     GBP Bridge Domain
398     """
399
400     def __init__(self, test, bd, rd, bvi,
401                  uu_fwd: typing.Optional[VppVxlanGbpTunnel] = None,
402                  bm_flood=None, learn=True,
403                  uu_drop=False, bm_drop=False,
404                  ucast_arp=False):
405         self._test = test
406         self.bvi = bvi
407         self.uu_fwd = uu_fwd
408         self.bm_flood = bm_flood
409         self.bd = bd
410         self.rd = rd
411
412         e = VppEnum.vl_api_gbp_bridge_domain_flags_t
413
414         self.flags = e.GBP_BD_API_FLAG_NONE
415         if not learn:
416             self.flags |= e.GBP_BD_API_FLAG_DO_NOT_LEARN
417         if uu_drop:
418             self.flags |= e.GBP_BD_API_FLAG_UU_FWD_DROP
419         if bm_drop:
420             self.flags |= e.GBP_BD_API_FLAG_MCAST_DROP
421         if ucast_arp:
422             self.flags |= e.GBP_BD_API_FLAG_UCAST_ARP
423
424     def encode(self) -> dict:
425         return {
426             "flags": self.flags,
427             "bvi_sw_if_index": self.bvi.sw_if_index,
428             "uu_fwd_sw_if_index": self.uu_fwd.sw_if_index
429             if self.uu_fwd else INDEX_INVALID,
430             "bm_flood_sw_if_index": self.bm_flood.sw_if_index
431             if self.bm_flood else INDEX_INVALID,
432             "bd_id": self.bd.bd_id,
433             "rd_id": self.rd.rd_id,
434         }
435
436     def add_vpp_config(self):
437         self._test.vapi.gbp_bridge_domain_add(
438             bd=self.encode(),
439         )
440         self._test.registry.register(self, self._test.logger)
441
442     def remove_vpp_config(self):
443         self._test.vapi.gbp_bridge_domain_del(bd_id=self.bd.bd_id)
444
445     def object_id(self) -> str:
446         return "gbp-bridge-domain:[%d]" % (self.bd.bd_id)
447
448     def query_vpp_config(self) -> bool:
449         bds = self._test.vapi.gbp_bridge_domain_dump()
450         for bd in bds:
451             if bd.bd.bd_id == self.bd.bd_id:
452                 return True
453         return False
454
455
456 class VppGbpRouteDomain(VppObject):
457     """
458     GBP Route Domain
459     """
460
461     def __init__(self, test, rd_id, scope, t4, t6, ip4_uu=None, ip6_uu=None):
462         self._test = test
463         self.rd_id = rd_id
464         self.scope = scope
465         self.t4 = t4
466         self.t6 = t6
467         self.ip4_uu = ip4_uu
468         self.ip6_uu = ip6_uu
469
470     def encode(self) -> dict:
471         return {
472             "rd_id": self.rd_id,
473             "scope": self.scope,
474             "ip4_table_id": self.t4.table_id,
475             "ip6_table_id": self.t6.table_id,
476             "ip4_uu_sw_if_index": self.ip4_uu.sw_if_index
477             if self.ip4_uu else INDEX_INVALID,
478             "ip6_uu_sw_if_index": self.ip6_uu.sw_if_index
479             if self.ip6_uu else INDEX_INVALID,
480
481         }
482
483     def add_vpp_config(self):
484         self._test.vapi.gbp_route_domain_add(
485             rd=self.encode(),
486         )
487         self._test.registry.register(self, self._test.logger)
488
489     def remove_vpp_config(self):
490         self._test.vapi.gbp_route_domain_del(rd_id=self.rd_id)
491
492     def object_id(self):
493         return "gbp-route-domain:[%d]" % (self.rd_id)
494
495     def query_vpp_config(self):
496         rds = self._test.vapi.gbp_route_domain_dump()
497         for rd in rds:
498             if rd.rd.rd_id == self.rd_id:
499                 return True
500         return False
501
502
503 class VppGbpContractNextHop:
504     def __init__(self, mac, bd, ip, rd):
505         self.mac = mac
506         self.ip = ip
507         self.bd = bd
508         self.rd = rd
509
510     def encode(self) -> dict:
511         return {
512             "ip": self.ip,
513             "mac": self.mac.packed,
514             "bd_id": self.bd.bd.bd_id,
515             "rd_id": self.rd.rd_id,
516         }
517
518
519 class VppGbpContractRule:
520     def __init__(self, action, hash_mode, nhs=None):
521         self.action = action
522         self.hash_mode = hash_mode
523         self.nhs = [] if nhs is None else nhs
524
525     def encode(self) -> dict:
526         nhs = []
527         for nh in self.nhs:
528             nhs.append(nh.encode())
529         while len(nhs) < 8:
530             nhs.append({})
531         return {'action': self.action,
532                 'nh_set': {
533                     'hash_mode': self.hash_mode,
534                     'n_nhs': len(self.nhs),
535                     'nhs': nhs}}
536
537     def __repr__(self):
538         return '<VppGbpContractRule action=%s, hash_mode=%s>' % (
539             self.action, self.hash_mode)
540
541
542 class VppGbpContract(VppObject):
543     """
544     GBP Contract
545     """
546
547     def __init__(self, test, scope, sclass, dclass, acl_index,
548                  rules: list, allowed_ethertypes: list):
549         self._test = test
550         self.scope = scope
551         self.acl_index = acl_index
552         self.sclass = sclass
553         self.dclass = dclass
554         self.rules = rules
555         self.allowed_ethertypes = allowed_ethertypes
556         while (len(self.allowed_ethertypes) < 16):
557             self.allowed_ethertypes.append(0)
558
559     def encode(self) -> dict:
560         rules = []
561         for r in self.rules:
562             rules.append(r.encode())
563         return {
564             'acl_index': self.acl_index,
565             'scope': self.scope,
566             'sclass': self.sclass,
567             'dclass': self.dclass,
568             'n_rules': len(rules),
569             'rules': rules,
570             'n_ether_types': len(self.allowed_ethertypes),
571             'allowed_ethertypes': self.allowed_ethertypes,
572         }
573
574     def add_vpp_config(self):
575         r = self._test.vapi.gbp_contract_add_del(
576             is_add=1,
577             contract=self.encode()
578         )
579
580         self.stats_index = r.stats_index
581         self._test.registry.register(self, self._test.logger)
582
583     def remove_vpp_config(self):
584         self._test.vapi.gbp_contract_add_del(
585             is_add=0,
586             contract=self.encode(),
587         )
588
589     def object_id(self):
590         return "gbp-contract:[%d:%d:%d:%d]" % (self.scope,
591                                                self.sclass,
592                                                self.dclass,
593                                                self.acl_index)
594
595     def query_vpp_config(self):
596         cs = self._test.vapi.gbp_contract_dump()
597         for c in cs:
598             if c.contract.scope == self.scope \
599                and c.contract.sclass == self.sclass \
600                and c.contract.dclass == self.dclass:
601                 return True
602         return False
603
604     def get_drop_stats(self):
605         c = self._test.statistics.get_counter("/net/gbp/contract/drop")
606         return c[0][self.stats_index]
607
608     def get_permit_stats(self):
609         c = self._test.statistics.get_counter("/net/gbp/contract/permit")
610         return c[0][self.stats_index]
611
612
613 class VppGbpVxlanTunnel(VppInterface):
614     """
615     GBP VXLAN tunnel
616     """
617
618     def __init__(self, test, vni, bd_rd_id, mode, src):
619         super(VppGbpVxlanTunnel, self).__init__(test)
620         self._test = test
621         self.vni = vni
622         self.bd_rd_id = bd_rd_id
623         self.mode = mode
624         self.src = src
625
626     def encode(self) -> dict:
627         return {
628             "vni": self.vni,
629             "mode": self.mode,
630             "bd_rd_id": self.bd_rd_id,
631             "src": self.src,
632         }
633
634     def add_vpp_config(self):
635         r = self._test.vapi.gbp_vxlan_tunnel_add(
636             tunnel=self.encode(),
637         )
638         self.set_sw_if_index(r.sw_if_index)
639         self._test.registry.register(self, self._test.logger)
640
641     def remove_vpp_config(self):
642         self._test.vapi.gbp_vxlan_tunnel_del(vni=self.vni)
643
644     def object_id(self):
645         return "gbp-vxlan:%d" % (self.sw_if_index)
646
647     def query_vpp_config(self):
648         return find_gbp_vxlan(self._test, self.vni)
649
650
651 @tag_fixme_vpp_workers
652 class TestGBP(VppTestCase):
653     """ GBP Test Case """
654
655     @property
656     def nat_config_flags(self):
657         return VppEnum.vl_api_nat_config_flags_t
658
659     @property
660     def nat44_config_flags(self):
661         return VppEnum.vl_api_nat44_config_flags_t
662
663     @classmethod
664     def setUpClass(cls):
665         super(TestGBP, cls).setUpClass()
666
667     @classmethod
668     def tearDownClass(cls):
669         super(TestGBP, cls).tearDownClass()
670
671     def setUp(self):
672         super(TestGBP, self).setUp()
673
674         self.create_pg_interfaces(range(9))
675         self.create_loopback_interfaces(8)
676
677         self.router_mac = MACAddress("00:11:22:33:44:55")
678
679         for i in self.pg_interfaces:
680             i.admin_up()
681         for i in self.lo_interfaces:
682             i.admin_up()
683
684         self.vlan_100 = VppDot1QSubint(self, self.pg0, 100)
685         self.vlan_100.admin_up()
686         self.vlan_101 = VppDot1QSubint(self, self.pg0, 101)
687         self.vlan_101.admin_up()
688         self.vlan_102 = VppDot1QSubint(self, self.pg0, 102)
689         self.vlan_102.admin_up()
690
691     def tearDown(self):
692         for i in self.pg_interfaces:
693             i.admin_down()
694         super(TestGBP, self).tearDown()
695         for i in self.lo_interfaces:
696             i.remove_vpp_config()
697         self.lo_interfaces = []
698         self.vlan_102.remove_vpp_config()
699         self.vlan_101.remove_vpp_config()
700         self.vlan_100.remove_vpp_config()
701
702     def send_and_expect_bridged(self, src, tx, dst):
703         rx = self.send_and_expect(src, tx, dst)
704
705         for r in rx:
706             self.assertEqual(r[Ether].src, tx[0][Ether].src)
707             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
708             self.assertEqual(r[IP].src, tx[0][IP].src)
709             self.assertEqual(r[IP].dst, tx[0][IP].dst)
710         return rx
711
712     def send_and_expect_bridged6(self, src, tx, dst):
713         rx = self.send_and_expect(src, tx, dst)
714
715         for r in rx:
716             self.assertEqual(r[Ether].src, tx[0][Ether].src)
717             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
718             self.assertEqual(r[IPv6].src, tx[0][IPv6].src)
719             self.assertEqual(r[IPv6].dst, tx[0][IPv6].dst)
720         return rx
721
722     def send_and_expect_routed(self, src, tx, dst, src_mac):
723         rx = self.send_and_expect(src, tx, dst)
724
725         for r in rx:
726             self.assertEqual(r[Ether].src, src_mac)
727             self.assertEqual(r[Ether].dst, dst.remote_mac)
728             self.assertEqual(r[IP].src, tx[0][IP].src)
729             self.assertEqual(r[IP].dst, tx[0][IP].dst)
730         return rx
731
732     def send_and_expect_routed6(self, src, tx, dst, src_mac):
733         rx = self.send_and_expect(src, tx, dst)
734
735         for r in rx:
736             self.assertEqual(r[Ether].src, src_mac)
737             self.assertEqual(r[Ether].dst, dst.remote_mac)
738             self.assertEqual(r[IPv6].src, tx[0][IPv6].src)
739             self.assertEqual(r[IPv6].dst, tx[0][IPv6].dst)
740         return rx
741
742     def send_and_expect_natted(self, src, tx, dst, src_ip):
743         rx = self.send_and_expect(src, tx, dst)
744
745         for r in rx:
746             self.assertEqual(r[Ether].src, tx[0][Ether].src)
747             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
748             self.assertEqual(r[IP].src, src_ip)
749             self.assertEqual(r[IP].dst, tx[0][IP].dst)
750         return rx
751
752     def send_and_expect_natted6(self, src, tx, dst, src_ip):
753         rx = self.send_and_expect(src, tx, dst)
754
755         for r in rx:
756             self.assertEqual(r[Ether].src, tx[0][Ether].src)
757             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
758             self.assertEqual(r[IPv6].src, src_ip)
759             self.assertEqual(r[IPv6].dst, tx[0][IPv6].dst)
760         return rx
761
762     def send_and_expect_unnatted(self, src, tx, dst, dst_ip):
763         rx = self.send_and_expect(src, tx, dst)
764
765         for r in rx:
766             self.assertEqual(r[Ether].src, tx[0][Ether].src)
767             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
768             self.assertEqual(r[IP].dst, dst_ip)
769             self.assertEqual(r[IP].src, tx[0][IP].src)
770         return rx
771
772     def send_and_expect_unnatted6(self, src, tx, dst, dst_ip):
773         rx = self.send_and_expect(src, tx, dst)
774
775         for r in rx:
776             self.assertEqual(r[Ether].src, tx[0][Ether].src)
777             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
778             self.assertEqual(r[IPv6].dst, dst_ip)
779             self.assertEqual(r[IPv6].src, tx[0][IPv6].src)
780         return rx
781
782     def send_and_expect_double_natted(self, src, tx, dst, src_ip, dst_ip):
783         rx = self.send_and_expect(src, tx, dst)
784
785         for r in rx:
786             self.assertEqual(r[Ether].src, str(self.router_mac))
787             self.assertEqual(r[Ether].dst, dst.remote_mac)
788             self.assertEqual(r[IP].dst, dst_ip)
789             self.assertEqual(r[IP].src, src_ip)
790         return rx
791
792     def send_and_expect_double_natted6(self, src, tx, dst, src_ip, dst_ip):
793         rx = self.send_and_expect(src, tx, dst)
794
795         for r in rx:
796             self.assertEqual(r[Ether].src, str(self.router_mac))
797             self.assertEqual(r[Ether].dst, dst.remote_mac)
798             self.assertEqual(r[IPv6].dst, dst_ip)
799             self.assertEqual(r[IPv6].src, src_ip)
800         return rx
801
802     def send_and_expect_no_arp(self, src, tx, dst):
803         self.pg_send(src, tx)
804         dst.get_capture(0, timeout=1)
805         dst.assert_nothing_captured(remark="")
806
807     def send_and_expect_arp(self, src, tx, dst):
808         rx = self.send_and_expect(src, tx, dst)
809
810         for r in rx:
811             self.assertEqual(r[Ether].src, tx[0][Ether].src)
812             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
813             self.assertEqual(r[ARP].psrc, tx[0][ARP].psrc)
814             self.assertEqual(r[ARP].pdst, tx[0][ARP].pdst)
815             self.assertEqual(r[ARP].hwsrc, tx[0][ARP].hwsrc)
816             self.assertEqual(r[ARP].hwdst, tx[0][ARP].hwdst)
817         return rx
818
819     def test_gbp(self):
820         """ Group Based Policy """
821
822         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
823
824         #
825         # Route Domains
826         #
827         gt4 = VppIpTable(self, 0)
828         gt4.add_vpp_config()
829         gt6 = VppIpTable(self, 0, is_ip6=True)
830         gt6.add_vpp_config()
831         nt4 = VppIpTable(self, 20)
832         nt4.add_vpp_config()
833         nt6 = VppIpTable(self, 20, is_ip6=True)
834         nt6.add_vpp_config()
835
836         rd0 = VppGbpRouteDomain(self, 0, 400, gt4, gt6, None, None)
837         rd20 = VppGbpRouteDomain(self, 20, 420, nt4, nt6, None, None)
838
839         rd0.add_vpp_config()
840         rd20.add_vpp_config()
841
842         #
843         # Bridge Domains
844         #
845         bd1 = VppBridgeDomain(self, 1)
846         bd2 = VppBridgeDomain(self, 2)
847         bd20 = VppBridgeDomain(self, 20)
848
849         bd1.add_vpp_config()
850         bd2.add_vpp_config()
851         bd20.add_vpp_config()
852
853         gbd1 = VppGbpBridgeDomain(self, bd1, rd0, self.loop0)
854         gbd2 = VppGbpBridgeDomain(self, bd2, rd0, self.loop1)
855         gbd20 = VppGbpBridgeDomain(self, bd20, rd20, self.loop2)
856
857         gbd1.add_vpp_config()
858         gbd2.add_vpp_config()
859         gbd20.add_vpp_config()
860
861         #
862         # 3 EPGs, 2 of which share a BD.
863         # 2 NAT EPGs, one for floating-IP subnets, the other for internet
864         #
865         epgs = [VppGbpEndpointGroup(self, 220, 1220, rd0, gbd1,
866                                     self.pg4, self.loop0,
867                                     "10.0.0.128", "2001:10::128"),
868                 VppGbpEndpointGroup(self, 221, 1221, rd0, gbd1,
869                                     self.pg5, self.loop0,
870                                     "10.0.1.128", "2001:10:1::128"),
871                 VppGbpEndpointGroup(self, 222, 1222, rd0, gbd2,
872                                     self.pg6, self.loop1,
873                                     "10.0.2.128", "2001:10:2::128"),
874                 VppGbpEndpointGroup(self, 333, 1333, rd20, gbd20,
875                                     self.pg7, self.loop2,
876                                     "11.0.0.128", "3001::128"),
877                 VppGbpEndpointGroup(self, 444, 1444, rd20, gbd20,
878                                     self.pg8, self.loop2,
879                                     "11.0.0.129", "3001::129")]
880         recircs = [VppGbpRecirc(self, epgs[0], self.loop3),
881                    VppGbpRecirc(self, epgs[1], self.loop4),
882                    VppGbpRecirc(self, epgs[2], self.loop5),
883                    VppGbpRecirc(self, epgs[3], self.loop6, is_ext=True),
884                    VppGbpRecirc(self, epgs[4], self.loop7, is_ext=True)]
885
886         epg_nat = epgs[3]
887         recirc_nat = recircs[3]
888
889         #
890         # 4 end-points, 2 in the same subnet, 3 in the same BD
891         #
892         eps = [VppGbpEndpoint(self, self.pg0,
893                               epgs[0], recircs[0],
894                               "10.0.0.1", "11.0.0.1",
895                               "2001:10::1", "3001::1"),
896                VppGbpEndpoint(self, self.pg1,
897                               epgs[0], recircs[0],
898                               "10.0.0.2", "11.0.0.2",
899                               "2001:10::2", "3001::2"),
900                VppGbpEndpoint(self, self.pg2,
901                               epgs[1], recircs[1],
902                               "10.0.1.1", "11.0.0.3",
903                               "2001:10:1::1", "3001::3"),
904                VppGbpEndpoint(self, self.pg3,
905                               epgs[2], recircs[2],
906                               "10.0.2.1", "11.0.0.4",
907                               "2001:10:2::1", "3001::4")]
908
909         self.vapi.nat44_ed_plugin_enable_disable(enable=1)
910         self.vapi.nat66_plugin_enable_disable(enable=1)
911
912         #
913         # Config related to each of the EPGs
914         #
915         for epg in epgs:
916             # IP config on the BVI interfaces
917             if epg != epgs[1] and epg != epgs[4]:
918                 b4 = VppIpInterfaceBind(self, epg.bvi,
919                                         epg.rd.t4).add_vpp_config()
920                 b6 = VppIpInterfaceBind(self, epg.bvi,
921                                         epg.rd.t6).add_vpp_config()
922                 epg.bvi.set_mac(self.router_mac)
923
924                 # The BVIs are NAT inside interfaces
925                 flags = self.nat_config_flags.NAT_IS_INSIDE
926                 self.vapi.nat44_interface_add_del_feature(
927                     sw_if_index=epg.bvi.sw_if_index,
928                     flags=flags, is_add=1)
929                 self.vapi.nat66_add_del_interface(
930                     sw_if_index=epg.bvi.sw_if_index,
931                     flags=flags, is_add=1)
932
933             if_ip4 = VppIpInterfaceAddress(self, epg.bvi,
934                                            epg.bvi_ip4, 32,
935                                            bind=b4).add_vpp_config()
936             if_ip6 = VppIpInterfaceAddress(self, epg.bvi,
937                                            epg.bvi_ip6, 128,
938                                            bind=b6).add_vpp_config()
939
940             # EPG uplink interfaces in the RD
941             VppIpInterfaceBind(self, epg.uplink, epg.rd.t4).add_vpp_config()
942             VppIpInterfaceBind(self, epg.uplink, epg.rd.t6).add_vpp_config()
943
944             # add the BD ARP termination entry for BVI IP
945             epg.bd_arp_ip4 = VppBridgeDomainArpEntry(self, epg.bd.bd,
946                                                      str(self.router_mac),
947                                                      epg.bvi_ip4)
948             epg.bd_arp_ip6 = VppBridgeDomainArpEntry(self, epg.bd.bd,
949                                                      str(self.router_mac),
950                                                      epg.bvi_ip6)
951             epg.bd_arp_ip4.add_vpp_config()
952             epg.bd_arp_ip6.add_vpp_config()
953
954             # EPG in VPP
955             epg.add_vpp_config()
956
957         for recirc in recircs:
958             # EPG's ingress recirculation interface maps to its RD
959             VppIpInterfaceBind(self, recirc.recirc,
960                                recirc.epg.rd.t4).add_vpp_config()
961             VppIpInterfaceBind(self, recirc.recirc,
962                                recirc.epg.rd.t6).add_vpp_config()
963
964             self.vapi.nat44_interface_add_del_feature(
965                 sw_if_index=recirc.recirc.sw_if_index, is_add=1)
966             self.vapi.nat66_add_del_interface(
967                 sw_if_index=recirc.recirc.sw_if_index, is_add=1)
968
969             recirc.add_vpp_config()
970
971         for recirc in recircs:
972             self.assertTrue(find_bridge_domain_port(self,
973                                                     recirc.epg.bd.bd.bd_id,
974                                                     recirc.recirc.sw_if_index))
975
976         for ep in eps:
977             self.pg_enable_capture(self.pg_interfaces)
978             self.pg_start()
979             #
980             # routes to the endpoints. We need these since there are no
981             # adj-fibs due to the fact the the BVI address has /32 and
982             # the subnet is not attached.
983             #
984             for (ip, fip) in zip(ep.ips, ep.fips):
985                 # Add static mappings for each EP from the 10/8 to 11/8 network
986                 if ip_address(ip).version == 4:
987                     flags = self.nat_config_flags.NAT_IS_ADDR_ONLY
988                     self.vapi.nat44_add_del_static_mapping(
989                         is_add=1,
990                         local_ip_address=ip,
991                         external_ip_address=fip,
992                         external_sw_if_index=0xFFFFFFFF,
993                         vrf_id=0,
994                         flags=flags)
995                 else:
996                     self.vapi.nat66_add_del_static_mapping(
997                         local_ip_address=ip,
998                         external_ip_address=fip,
999                         vrf_id=0, is_add=1)
1000
1001             # VPP EP create ...
1002             ep.add_vpp_config()
1003
1004             self.logger.info(self.vapi.cli("sh gbp endpoint"))
1005
1006             # ... results in a Gratuitous ARP/ND on the EPG's uplink
1007             rx = ep.epg.uplink.get_capture(len(ep.ips) + 1, timeout=0.2)
1008
1009             for ii, ip in enumerate(ep.ips):
1010                 p = rx[ii]
1011
1012                 if ip_address(ip).version == 6:
1013                     self.assertTrue(p.haslayer(ICMPv6ND_NA))
1014                     self.assertEqual(p[ICMPv6ND_NA].tgt, ip)
1015                 else:
1016                     self.assertTrue(p.haslayer(ARP))
1017                     self.assertEqual(p[ARP].psrc, ip)
1018                     self.assertEqual(p[ARP].pdst, ip)
1019
1020             # add the BD ARP termination entry for floating IP
1021             for fip in ep.fips:
1022                 ba = VppBridgeDomainArpEntry(self, epg_nat.bd.bd, ep.mac,
1023                                              fip)
1024                 ba.add_vpp_config()
1025
1026                 # floating IPs route via EPG recirc
1027                 r = VppIpRoute(
1028                     self, fip, ip_address(fip).max_prefixlen,
1029                     [VppRoutePath(fip,
1030                                   ep.recirc.recirc.sw_if_index,
1031                                   type=FibPathType.FIB_PATH_TYPE_DVR,
1032                                   proto=get_dpo_proto(fip))],
1033                     table_id=20)
1034                 r.add_vpp_config()
1035
1036             # L2 FIB entries in the NAT EPG BD to bridge the packets from
1037             # the outside direct to the internal EPG
1038             lf = VppL2FibEntry(self, epg_nat.bd.bd, ep.mac,
1039                                ep.recirc.recirc, bvi_mac=0)
1040             lf.add_vpp_config()
1041
1042         #
1043         # ARP packets for unknown IP are sent to the EPG uplink
1044         #
1045         pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff",
1046                          src=self.pg0.remote_mac) /
1047                    ARP(op="who-has",
1048                        hwdst="ff:ff:ff:ff:ff:ff",
1049                        hwsrc=self.pg0.remote_mac,
1050                        pdst="10.0.0.88",
1051                        psrc="10.0.0.99"))
1052
1053         self.vapi.cli("clear trace")
1054         self.pg0.add_stream(pkt_arp)
1055
1056         self.pg_enable_capture(self.pg_interfaces)
1057         self.pg_start()
1058
1059         rxd = epgs[0].uplink.get_capture(1)
1060
1061         #
1062         # ARP/ND packets get a response
1063         #
1064         pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff",
1065                          src=self.pg0.remote_mac) /
1066                    ARP(op="who-has",
1067                        hwdst="ff:ff:ff:ff:ff:ff",
1068                        hwsrc=self.pg0.remote_mac,
1069                        pdst=epgs[0].bvi_ip4,
1070                        psrc=eps[0].ip4))
1071
1072         self.send_and_expect(self.pg0, [pkt_arp], self.pg0)
1073
1074         nsma = in6_getnsma(inet_pton(AF_INET6, eps[0].ip6))
1075         d = inet_ntop(AF_INET6, nsma)
1076         pkt_nd = (Ether(dst=in6_getnsmac(nsma),
1077                         src=self.pg0.remote_mac) /
1078                   IPv6(dst=d, src=eps[0].ip6) /
1079                   ICMPv6ND_NS(tgt=epgs[0].bvi_ip6) /
1080                   ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac))
1081         self.send_and_expect(self.pg0, [pkt_nd], self.pg0)
1082
1083         #
1084         # broadcast packets are flooded
1085         #
1086         pkt_bcast = (Ether(dst="ff:ff:ff:ff:ff:ff",
1087                            src=self.pg0.remote_mac) /
1088                      IP(src=eps[0].ip4, dst="232.1.1.1") /
1089                      UDP(sport=1234, dport=1234) /
1090                      Raw(b'\xa5' * 100))
1091
1092         self.vapi.cli("clear trace")
1093         self.pg0.add_stream(pkt_bcast)
1094
1095         self.pg_enable_capture(self.pg_interfaces)
1096         self.pg_start()
1097
1098         rxd = eps[1].itf.get_capture(1)
1099         self.assertEqual(rxd[0][Ether].dst, pkt_bcast[Ether].dst)
1100         rxd = epgs[0].uplink.get_capture(1)
1101         self.assertEqual(rxd[0][Ether].dst, pkt_bcast[Ether].dst)
1102
1103         #
1104         # packets to non-local L3 destinations dropped
1105         #
1106         pkt_intra_epg_220_ip4 = (Ether(src=self.pg0.remote_mac,
1107                                        dst=str(self.router_mac)) /
1108                                  IP(src=eps[0].ip4,
1109                                     dst="10.0.0.99") /
1110                                  UDP(sport=1234, dport=1234) /
1111                                  Raw(b'\xa5' * 100))
1112         pkt_inter_epg_222_ip4 = (Ether(src=self.pg0.remote_mac,
1113                                        dst=str(self.router_mac)) /
1114                                  IP(src=eps[0].ip4,
1115                                     dst="10.0.1.99") /
1116                                  UDP(sport=1234, dport=1234) /
1117                                  Raw(b'\xa5' * 100))
1118
1119         self.send_and_assert_no_replies(self.pg0,
1120                                         pkt_intra_epg_220_ip4 * NUM_PKTS)
1121
1122         pkt_inter_epg_222_ip6 = (Ether(src=self.pg0.remote_mac,
1123                                        dst=str(self.router_mac)) /
1124                                  IPv6(src=eps[0].ip6,
1125                                       dst="2001:10::99") /
1126                                  UDP(sport=1234, dport=1234) /
1127                                  Raw(b'\xa5' * 100))
1128         self.send_and_assert_no_replies(self.pg0,
1129                                         pkt_inter_epg_222_ip6 * NUM_PKTS)
1130
1131         #
1132         # Add the subnet routes
1133         #
1134         s41 = VppGbpSubnet(
1135             self, rd0, "10.0.0.0", 24,
1136             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
1137         s42 = VppGbpSubnet(
1138             self, rd0, "10.0.1.0", 24,
1139             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
1140         s43 = VppGbpSubnet(
1141             self, rd0, "10.0.2.0", 24,
1142             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
1143         s61 = VppGbpSubnet(
1144             self, rd0, "2001:10::1", 64,
1145             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
1146         s62 = VppGbpSubnet(
1147             self, rd0, "2001:10:1::1", 64,
1148             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
1149         s63 = VppGbpSubnet(
1150             self, rd0, "2001:10:2::1", 64,
1151             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
1152         s41.add_vpp_config()
1153         s42.add_vpp_config()
1154         s43.add_vpp_config()
1155         s61.add_vpp_config()
1156         s62.add_vpp_config()
1157         s63.add_vpp_config()
1158
1159         self.send_and_expect_bridged(eps[0].itf,
1160                                      pkt_intra_epg_220_ip4 * NUM_PKTS,
1161                                      eps[0].epg.uplink)
1162         self.send_and_expect_bridged(eps[0].itf,
1163                                      pkt_inter_epg_222_ip4 * NUM_PKTS,
1164                                      eps[0].epg.uplink)
1165         self.send_and_expect_bridged6(eps[0].itf,
1166                                       pkt_inter_epg_222_ip6 * NUM_PKTS,
1167                                       eps[0].epg.uplink)
1168
1169         self.logger.info(self.vapi.cli("sh ip fib 11.0.0.2"))
1170         self.logger.info(self.vapi.cli("sh gbp endpoint-group"))
1171         self.logger.info(self.vapi.cli("sh gbp endpoint"))
1172         self.logger.info(self.vapi.cli("sh gbp recirc"))
1173         self.logger.info(self.vapi.cli("sh int"))
1174         self.logger.info(self.vapi.cli("sh int addr"))
1175         self.logger.info(self.vapi.cli("sh int feat loop6"))
1176         self.logger.info(self.vapi.cli("sh vlib graph ip4-gbp-src-classify"))
1177         self.logger.info(self.vapi.cli("sh int feat loop3"))
1178         self.logger.info(self.vapi.cli("sh int feat pg0"))
1179
1180         #
1181         # Packet destined to unknown unicast is sent on the epg uplink ...
1182         #
1183         pkt_intra_epg_220_to_uplink = (Ether(src=self.pg0.remote_mac,
1184                                              dst="00:00:00:33:44:55") /
1185                                        IP(src=eps[0].ip4,
1186                                           dst="10.0.0.99") /
1187                                        UDP(sport=1234, dport=1234) /
1188                                        Raw(b'\xa5' * 100))
1189
1190         self.send_and_expect_bridged(eps[0].itf,
1191                                      pkt_intra_epg_220_to_uplink * NUM_PKTS,
1192                                      eps[0].epg.uplink)
1193         # ... and nowhere else
1194         self.pg1.get_capture(0, timeout=0.1)
1195         self.pg1.assert_nothing_captured(remark="Flood onto other VMS")
1196
1197         pkt_intra_epg_221_to_uplink = (Ether(src=self.pg2.remote_mac,
1198                                              dst="00:00:00:33:44:66") /
1199                                        IP(src=eps[0].ip4,
1200                                           dst="10.0.0.99") /
1201                                        UDP(sport=1234, dport=1234) /
1202                                        Raw(b'\xa5' * 100))
1203
1204         self.send_and_expect_bridged(eps[2].itf,
1205                                      pkt_intra_epg_221_to_uplink * NUM_PKTS,
1206                                      eps[2].epg.uplink)
1207
1208         #
1209         # Packets from the uplink are forwarded in the absence of a contract
1210         #
1211         pkt_intra_epg_220_from_uplink = (Ether(src="00:00:00:33:44:55",
1212                                                dst=self.pg0.remote_mac) /
1213                                          IP(src=eps[0].ip4,
1214                                             dst="10.0.0.99") /
1215                                          UDP(sport=1234, dport=1234) /
1216                                          Raw(b'\xa5' * 100))
1217
1218         self.send_and_expect_bridged(self.pg4,
1219                                      pkt_intra_epg_220_from_uplink * NUM_PKTS,
1220                                      self.pg0)
1221
1222         #
1223         # in the absence of policy, endpoints in the same EPG
1224         # can communicate
1225         #
1226         pkt_intra_epg = (Ether(src=self.pg0.remote_mac,
1227                                dst=self.pg1.remote_mac) /
1228                          IP(src=eps[0].ip4,
1229                             dst=eps[1].ip4) /
1230                          UDP(sport=1234, dport=1234) /
1231                          Raw(b'\xa5' * 100))
1232
1233         self.send_and_expect_bridged(self.pg0,
1234                                      pkt_intra_epg * NUM_PKTS,
1235                                      self.pg1)
1236
1237         #
1238         # in the absence of policy, endpoints in the different EPG
1239         # cannot communicate
1240         #
1241         pkt_inter_epg_220_to_221 = (Ether(src=self.pg0.remote_mac,
1242                                           dst=self.pg2.remote_mac) /
1243                                     IP(src=eps[0].ip4,
1244                                        dst=eps[2].ip4) /
1245                                     UDP(sport=1234, dport=1234) /
1246                                     Raw(b'\xa5' * 100))
1247         pkt_inter_epg_221_to_220 = (Ether(src=self.pg2.remote_mac,
1248                                           dst=self.pg0.remote_mac) /
1249                                     IP(src=eps[2].ip4,
1250                                        dst=eps[0].ip4) /
1251                                     UDP(sport=1234, dport=1234) /
1252                                     Raw(b'\xa5' * 100))
1253         pkt_inter_epg_220_to_222 = (Ether(src=self.pg0.remote_mac,
1254                                           dst=str(self.router_mac)) /
1255                                     IP(src=eps[0].ip4,
1256                                        dst=eps[3].ip4) /
1257                                     UDP(sport=1234, dport=1234) /
1258                                     Raw(b'\xa5' * 100))
1259
1260         self.send_and_assert_no_replies(eps[0].itf,
1261                                         pkt_inter_epg_220_to_221 * NUM_PKTS)
1262         self.send_and_assert_no_replies(eps[0].itf,
1263                                         pkt_inter_epg_220_to_222 * NUM_PKTS)
1264
1265         #
1266         # A uni-directional contract from EPG 220 -> 221
1267         #
1268         rule = AclRule(is_permit=1, proto=17)
1269         rule2 = AclRule(src_prefix=IPv6Network((0, 0)),
1270                         dst_prefix=IPv6Network((0, 0)), is_permit=1, proto=17)
1271         acl = VppAcl(self, rules=[rule, rule2])
1272         acl.add_vpp_config()
1273
1274         c1 = VppGbpContract(
1275             self, 400, epgs[0].sclass, epgs[1].sclass, acl.acl_index,
1276             [VppGbpContractRule(
1277                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1278                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1279                 []),
1280                 VppGbpContractRule(
1281                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1282                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1283                     [])],
1284             [ETH_P_IP, ETH_P_IPV6])
1285         c1.add_vpp_config()
1286
1287         self.send_and_expect_bridged(eps[0].itf,
1288                                      pkt_inter_epg_220_to_221 * NUM_PKTS,
1289                                      eps[2].itf)
1290         self.send_and_assert_no_replies(eps[0].itf,
1291                                         pkt_inter_epg_220_to_222 * NUM_PKTS)
1292
1293         #
1294         # contract for the return direction
1295         #
1296         c2 = VppGbpContract(
1297             self, 400, epgs[1].sclass, epgs[0].sclass, acl.acl_index,
1298             [VppGbpContractRule(
1299                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1300                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1301                 []),
1302                 VppGbpContractRule(
1303                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1304                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1305                     [])],
1306             [ETH_P_IP, ETH_P_IPV6])
1307         c2.add_vpp_config()
1308
1309         self.send_and_expect_bridged(eps[0].itf,
1310                                      pkt_inter_epg_220_to_221 * NUM_PKTS,
1311                                      eps[2].itf)
1312         self.send_and_expect_bridged(eps[2].itf,
1313                                      pkt_inter_epg_221_to_220 * NUM_PKTS,
1314                                      eps[0].itf)
1315
1316         ds = c2.get_drop_stats()
1317         self.assertEqual(ds['packets'], 0)
1318         ps = c2.get_permit_stats()
1319         self.assertEqual(ps['packets'], NUM_PKTS)
1320
1321         #
1322         # the contract does not allow non-IP
1323         #
1324         pkt_non_ip_inter_epg_220_to_221 = (Ether(src=self.pg0.remote_mac,
1325                                                  dst=self.pg2.remote_mac) /
1326                                            ARP())
1327         self.send_and_assert_no_replies(eps[0].itf,
1328                                         pkt_non_ip_inter_epg_220_to_221 * 17)
1329
1330         #
1331         # check that inter group is still disabled for the groups
1332         # not in the contract.
1333         #
1334         self.send_and_assert_no_replies(eps[0].itf,
1335                                         pkt_inter_epg_220_to_222 * NUM_PKTS)
1336
1337         #
1338         # A uni-directional contract from EPG 220 -> 222 'L3 routed'
1339         #
1340         c3 = VppGbpContract(
1341             self, 400, epgs[0].sclass, epgs[2].sclass, acl.acl_index,
1342             [VppGbpContractRule(
1343                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1344                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1345                 []),
1346                 VppGbpContractRule(
1347                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1348                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1349                     [])],
1350             [ETH_P_IP, ETH_P_IPV6])
1351         c3.add_vpp_config()
1352
1353         self.logger.info(self.vapi.cli("sh gbp contract"))
1354
1355         self.send_and_expect_routed(eps[0].itf,
1356                                     pkt_inter_epg_220_to_222 * NUM_PKTS,
1357                                     eps[3].itf,
1358                                     str(self.router_mac))
1359         #
1360         # remove both contracts, traffic stops in both directions
1361         #
1362         c2.remove_vpp_config()
1363         c1.remove_vpp_config()
1364         c3.remove_vpp_config()
1365         acl.remove_vpp_config()
1366
1367         self.send_and_assert_no_replies(eps[2].itf,
1368                                         pkt_inter_epg_221_to_220 * NUM_PKTS)
1369         self.send_and_assert_no_replies(eps[0].itf,
1370                                         pkt_inter_epg_220_to_221 * NUM_PKTS)
1371         self.send_and_expect_bridged(eps[0].itf,
1372                                      pkt_intra_epg * NUM_PKTS,
1373                                      eps[1].itf)
1374
1375         #
1376         # EPs to the outside world
1377         #
1378
1379         # in the EP's RD an external subnet via the NAT EPG's recirc
1380         se1 = VppGbpSubnet(
1381             self, rd0, "0.0.0.0", 0,
1382             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1383             sw_if_index=recirc_nat.recirc.sw_if_index,
1384             sclass=epg_nat.sclass)
1385         se2 = VppGbpSubnet(
1386             self, rd0, "11.0.0.0", 8,
1387             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1388             sw_if_index=recirc_nat.recirc.sw_if_index,
1389             sclass=epg_nat.sclass)
1390         se16 = VppGbpSubnet(
1391             self, rd0, "::", 0,
1392             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1393             sw_if_index=recirc_nat.recirc.sw_if_index,
1394             sclass=epg_nat.sclass)
1395         # in the NAT RD an external subnet via the NAT EPG's uplink
1396         se3 = VppGbpSubnet(
1397             self, rd20, "0.0.0.0", 0,
1398             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1399             sw_if_index=epg_nat.uplink.sw_if_index,
1400             sclass=epg_nat.sclass)
1401         se36 = VppGbpSubnet(
1402             self, rd20, "::", 0,
1403             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1404             sw_if_index=epg_nat.uplink.sw_if_index,
1405             sclass=epg_nat.sclass)
1406         se4 = VppGbpSubnet(
1407             self, rd20, "11.0.0.0", 8,
1408             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1409             sw_if_index=epg_nat.uplink.sw_if_index,
1410             sclass=epg_nat.sclass)
1411         se1.add_vpp_config()
1412         se2.add_vpp_config()
1413         se16.add_vpp_config()
1414         se3.add_vpp_config()
1415         se36.add_vpp_config()
1416         se4.add_vpp_config()
1417
1418         self.logger.info(self.vapi.cli("sh ip fib 0.0.0.0/0"))
1419         self.logger.info(self.vapi.cli("sh ip fib 11.0.0.1"))
1420         self.logger.info(self.vapi.cli("sh ip6 fib ::/0"))
1421         self.logger.info(self.vapi.cli("sh ip6 fib %s" %
1422                                        eps[0].fip6))
1423
1424         #
1425         # From an EP to an outside address: IN2OUT
1426         #
1427         pkt_inter_epg_220_to_global = (Ether(src=self.pg0.remote_mac,
1428                                              dst=str(self.router_mac)) /
1429                                        IP(src=eps[0].ip4,
1430                                           dst="1.1.1.1") /
1431                                        UDP(sport=1234, dport=1234) /
1432                                        Raw(b'\xa5' * 100))
1433
1434         # no policy yet
1435         self.send_and_assert_no_replies(eps[0].itf,
1436                                         pkt_inter_epg_220_to_global * NUM_PKTS)
1437         rule = AclRule(is_permit=1, proto=17, ports=1234)
1438         rule2 = AclRule(is_permit=1, proto=17, ports=1234,
1439                         src_prefix=IPv6Network((0, 0)),
1440                         dst_prefix=IPv6Network((0, 0)))
1441         acl2 = VppAcl(self, rules=[rule, rule2])
1442         acl2.add_vpp_config()
1443
1444         c4 = VppGbpContract(
1445             self, 400, epgs[0].sclass, epgs[3].sclass, acl2.acl_index,
1446             [VppGbpContractRule(
1447                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1448                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1449                 []),
1450                 VppGbpContractRule(
1451                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1452                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1453                     [])],
1454             [ETH_P_IP, ETH_P_IPV6])
1455         c4.add_vpp_config()
1456
1457         self.send_and_expect_natted(eps[0].itf,
1458                                     pkt_inter_epg_220_to_global * NUM_PKTS,
1459                                     self.pg7,
1460                                     eps[0].fip4)
1461
1462         pkt_inter_epg_220_to_global = (Ether(src=self.pg0.remote_mac,
1463                                              dst=str(self.router_mac)) /
1464                                        IPv6(src=eps[0].ip6,
1465                                             dst="6001::1") /
1466                                        UDP(sport=1234, dport=1234) /
1467                                        Raw(b'\xa5' * 100))
1468
1469         self.send_and_expect_natted6(self.pg0,
1470                                      pkt_inter_epg_220_to_global * NUM_PKTS,
1471                                      self.pg7,
1472                                      eps[0].fip6)
1473         #
1474         # From a global address to an EP: OUT2IN
1475         #
1476         pkt_inter_epg_220_from_global = (Ether(src=str(self.router_mac),
1477                                                dst=self.pg0.remote_mac) /
1478                                          IP(dst=eps[0].fip4,
1479                                             src="1.1.1.1") /
1480                                          UDP(sport=1234, dport=1234) /
1481                                          Raw(b'\xa5' * 100))
1482
1483         self.send_and_assert_no_replies(
1484             self.pg7, pkt_inter_epg_220_from_global * NUM_PKTS)
1485
1486         c5 = VppGbpContract(
1487             self, 400, epgs[3].sclass, epgs[0].sclass, acl2.acl_index,
1488             [VppGbpContractRule(
1489                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1490                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1491                 []),
1492                 VppGbpContractRule(
1493                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1494                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1495                     [])],
1496             [ETH_P_IP, ETH_P_IPV6])
1497         c5.add_vpp_config()
1498
1499         self.send_and_expect_unnatted(self.pg7,
1500                                       pkt_inter_epg_220_from_global * NUM_PKTS,
1501                                       eps[0].itf,
1502                                       eps[0].ip4)
1503
1504         pkt_inter_epg_220_from_global = (Ether(src=str(self.router_mac),
1505                                                dst=self.pg0.remote_mac) /
1506                                          IPv6(dst=eps[0].fip6,
1507                                               src="6001::1") /
1508                                          UDP(sport=1234, dport=1234) /
1509                                          Raw(b'\xa5' * 100))
1510
1511         self.send_and_expect_unnatted6(
1512             self.pg7,
1513             pkt_inter_epg_220_from_global * NUM_PKTS,
1514             eps[0].itf,
1515             eps[0].ip6)
1516
1517         #
1518         # From a local VM to another local VM using resp. public addresses:
1519         #  IN2OUT2IN
1520         #
1521         pkt_intra_epg_220_global = (Ether(src=self.pg0.remote_mac,
1522                                           dst=str(self.router_mac)) /
1523                                     IP(src=eps[0].ip4,
1524                                        dst=eps[1].fip4) /
1525                                     UDP(sport=1234, dport=1234) /
1526                                     Raw(b'\xa5' * 100))
1527
1528         self.send_and_expect_double_natted(eps[0].itf,
1529                                            pkt_intra_epg_220_global * NUM_PKTS,
1530                                            eps[1].itf,
1531                                            eps[0].fip4,
1532                                            eps[1].ip4)
1533
1534         pkt_intra_epg_220_global = (Ether(src=self.pg0.remote_mac,
1535                                           dst=str(self.router_mac)) /
1536                                     IPv6(src=eps[0].ip6,
1537                                          dst=eps[1].fip6) /
1538                                     UDP(sport=1234, dport=1234) /
1539                                     Raw(b'\xa5' * 100))
1540
1541         self.send_and_expect_double_natted6(
1542             eps[0].itf,
1543             pkt_intra_epg_220_global * NUM_PKTS,
1544             eps[1].itf,
1545             eps[0].fip6,
1546             eps[1].ip6)
1547
1548         #
1549         # cleanup
1550         #
1551         self.vapi.nat44_ed_plugin_enable_disable(enable=0)
1552         self.vapi.nat66_plugin_enable_disable(enable=0)
1553
1554     def wait_for_ep_timeout(self, sw_if_index=None, ip=None, mac=None,
1555                             tep=None, n_tries=100, s_time=1):
1556         # only learnt EP can timeout
1557         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
1558         flags = ep_flags.GBP_API_ENDPOINT_FLAG_LEARNT
1559         while (n_tries):
1560             if not find_gbp_endpoint(self, sw_if_index, ip, mac, tep=tep,
1561                                      flags=flags):
1562                 return True
1563             n_tries = n_tries - 1
1564             self.sleep(s_time)
1565         self.assertFalse(find_gbp_endpoint(self, sw_if_index, ip, mac, tep=tep,
1566                                            flags=flags))
1567         return False
1568
1569     def test_gbp_learn_l2(self):
1570         """ GBP L2 Endpoint Learning """
1571
1572         drop_no_contract = self.statistics.get_err_counter(
1573             '/err/gbp-policy-port/drop-no-contract')
1574         allow_intra_class = self.statistics.get_err_counter(
1575             '/err/gbp-policy-port/allow-intra-sclass')
1576
1577         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
1578         learnt = [{'mac': '00:00:11:11:11:01',
1579                    'ip': '10.0.0.1',
1580                    'ip6': '2001:10::2'},
1581                   {'mac': '00:00:11:11:11:02',
1582                    'ip': '10.0.0.2',
1583                    'ip6': '2001:10::3'}]
1584
1585         #
1586         # IP tables
1587         #
1588         gt4 = VppIpTable(self, 1)
1589         gt4.add_vpp_config()
1590         gt6 = VppIpTable(self, 1, is_ip6=True)
1591         gt6.add_vpp_config()
1592
1593         rd1 = VppGbpRouteDomain(self, 1, 401, gt4, gt6)
1594         rd1.add_vpp_config()
1595
1596         #
1597         # Pg2 hosts the vxlan tunnel, hosts on pg2 to act as TEPs
1598         # Pg3 hosts the IP4 UU-flood VXLAN tunnel
1599         # Pg4 hosts the IP6 UU-flood VXLAN tunnel
1600         #
1601         self.pg2.config_ip4()
1602         self.pg2.resolve_arp()
1603         self.pg2.generate_remote_hosts(4)
1604         self.pg2.configure_ipv4_neighbors()
1605         self.pg3.config_ip4()
1606         self.pg3.resolve_arp()
1607         self.pg4.config_ip4()
1608         self.pg4.resolve_arp()
1609
1610         #
1611         # Add a mcast destination VXLAN-GBP tunnel for B&M traffic
1612         #
1613         tun_bm = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
1614                                    "239.1.1.1", 88,
1615                                    mcast_itf=self.pg4)
1616         tun_bm.add_vpp_config()
1617
1618         #
1619         # a GBP bridge domain with a BVI and a UU-flood interface
1620         #
1621         bd1 = VppBridgeDomain(self, 1)
1622         bd1.add_vpp_config()
1623         gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0,
1624                                   self.pg3, tun_bm)
1625         gbd1.add_vpp_config()
1626
1627         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1628         self.logger.info(self.vapi.cli("sh gbp bridge"))
1629
1630         # ... and has a /32 applied
1631         ip_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
1632         ip_addr.add_vpp_config()
1633
1634         #
1635         # The Endpoint-group in which we are learning endpoints
1636         #
1637         epg_220 = VppGbpEndpointGroup(self, 220, 112, rd1, gbd1,
1638                                       None, self.loop0,
1639                                       "10.0.0.128",
1640                                       "2001:10::128",
1641                                       VppGbpEndpointRetention(4))
1642         epg_220.add_vpp_config()
1643         epg_330 = VppGbpEndpointGroup(self, 330, 113, rd1, gbd1,
1644                                       None, self.loop1,
1645                                       "10.0.1.128",
1646                                       "2001:11::128",
1647                                       VppGbpEndpointRetention(4))
1648         epg_330.add_vpp_config()
1649
1650         #
1651         # The VXLAN GBP tunnel is a bridge-port and has L2 endpoint
1652         # learning enabled
1653         #
1654         vx_tun_l2_1 = VppGbpVxlanTunnel(
1655             self, 99, bd1.bd_id,
1656             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L2,
1657             self.pg2.local_ip4)
1658         vx_tun_l2_1.add_vpp_config()
1659
1660         #
1661         # A static endpoint that the learnt endpoints are trying to
1662         # talk to
1663         #
1664         ep = VppGbpEndpoint(self, self.pg0,
1665                             epg_220, None,
1666                             "10.0.0.127", "11.0.0.127",
1667                             "2001:10::1", "3001::1")
1668         ep.add_vpp_config()
1669
1670         self.assertTrue(find_route(self, ep.ip4, 32, table_id=1))
1671
1672         # a packet with an sclass from an unknown EPG
1673         p = (Ether(src=self.pg2.remote_mac,
1674                    dst=self.pg2.local_mac) /
1675              IP(src=self.pg2.remote_hosts[0].ip4,
1676                 dst=self.pg2.local_ip4) /
1677              UDP(sport=1234, dport=48879) /
1678              VXLAN(vni=99, gpid=88, flags=0x88) /
1679              Ether(src=learnt[0]["mac"], dst=ep.mac) /
1680              IP(src=learnt[0]["ip"], dst=ep.ip4) /
1681              UDP(sport=1234, dport=1234) /
1682              Raw(b'\xa5' * 100))
1683
1684         self.send_and_assert_no_replies(self.pg2, p)
1685
1686         self.logger.info(self.vapi.cli("sh error"))
1687         self.assert_error_counter_equal(
1688             '/err/gbp-policy-port/drop-no-contract',
1689             drop_no_contract + 1)
1690
1691         #
1692         # we should not have learnt a new tunnel endpoint, since
1693         # the EPG was not learnt.
1694         #
1695         self.assertEqual(INDEX_INVALID,
1696                          find_vxlan_gbp_tunnel(self,
1697                                                self.pg2.local_ip4,
1698                                                self.pg2.remote_hosts[0].ip4,
1699                                                99))
1700
1701         # ep is not learnt, because the EPG is unknown
1702         self.assertEqual(len(self.vapi.gbp_endpoint_dump()), 1)
1703
1704         #
1705         # Learn new EPs from IP packets
1706         #
1707         for ii, l in enumerate(learnt):
1708             # a packet with an sclass from a known EPG
1709             # arriving on an unknown TEP
1710             p = (Ether(src=self.pg2.remote_mac,
1711                        dst=self.pg2.local_mac) /
1712                  IP(src=self.pg2.remote_hosts[1].ip4,
1713                     dst=self.pg2.local_ip4) /
1714                  UDP(sport=1234, dport=48879) /
1715                  VXLAN(vni=99, gpid=112, flags=0x88) /
1716                  Ether(src=l['mac'], dst=ep.mac) /
1717                  IP(src=l['ip'], dst=ep.ip4) /
1718                  UDP(sport=1234, dport=1234) /
1719                  Raw(b'\xa5' * 100))
1720
1721             rx = self.send_and_expect(self.pg2, [p], self.pg0)
1722
1723             # the new TEP
1724             tep1_sw_if_index = find_vxlan_gbp_tunnel(
1725                 self,
1726                 self.pg2.local_ip4,
1727                 self.pg2.remote_hosts[1].ip4,
1728                 99)
1729             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
1730
1731             #
1732             # the EP is learnt via the learnt TEP
1733             # both from its MAC and its IP
1734             #
1735             self.assertTrue(find_gbp_endpoint(self,
1736                                               vx_tun_l2_1.sw_if_index,
1737                                               mac=l['mac']))
1738             self.assertTrue(find_gbp_endpoint(self,
1739                                               vx_tun_l2_1.sw_if_index,
1740                                               ip=l['ip']))
1741
1742         self.assert_error_counter_equal(
1743             '/err/gbp-policy-port/allow-intra-sclass',
1744             allow_intra_class + 2)
1745
1746         self.logger.info(self.vapi.cli("show gbp endpoint"))
1747         self.logger.info(self.vapi.cli("show gbp vxlan"))
1748         self.logger.info(self.vapi.cli("show ip mfib"))
1749
1750         #
1751         # If we sleep for the threshold time, the learnt endpoints should
1752         # age out
1753         #
1754         for l in learnt:
1755             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
1756                                      mac=l['mac'])
1757
1758         #
1759         # Learn new EPs from GARP packets received on the BD's mcast tunnel
1760         #
1761         for ii, l in enumerate(learnt):
1762             # add some junk in the reserved field of the vxlan-header
1763             # next to the VNI. we should accept since reserved bits are
1764             # ignored on rx.
1765             p = (Ether(src=self.pg2.remote_mac,
1766                        dst=self.pg2.local_mac) /
1767                  IP(src=self.pg2.remote_hosts[1].ip4,
1768                     dst="239.1.1.1") /
1769                  UDP(sport=1234, dport=48879) /
1770                  VXLAN(vni=88, reserved2=0x80, gpid=112, flags=0x88) /
1771                  Ether(src=l['mac'], dst="ff:ff:ff:ff:ff:ff") /
1772                  ARP(op="who-has",
1773                      psrc=l['ip'], pdst=l['ip'],
1774                      hwsrc=l['mac'], hwdst="ff:ff:ff:ff:ff:ff"))
1775
1776             rx = self.send_and_expect(self.pg4, [p], self.pg0)
1777
1778             # the new TEP
1779             tep1_sw_if_index = find_vxlan_gbp_tunnel(
1780                 self,
1781                 self.pg2.local_ip4,
1782                 self.pg2.remote_hosts[1].ip4,
1783                 99)
1784             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
1785
1786             #
1787             # the EP is learnt via the learnt TEP
1788             # both from its MAC and its IP
1789             #
1790             self.assertTrue(find_gbp_endpoint(self,
1791                                               vx_tun_l2_1.sw_if_index,
1792                                               mac=l['mac']))
1793             self.assertTrue(find_gbp_endpoint(self,
1794                                               vx_tun_l2_1.sw_if_index,
1795                                               ip=l['ip']))
1796
1797         #
1798         # wait for the learnt endpoints to age out
1799         #
1800         for l in learnt:
1801             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
1802                                      mac=l['mac'])
1803
1804         #
1805         # Learn new EPs from L2 packets
1806         #
1807         for ii, l in enumerate(learnt):
1808             # a packet with an sclass from a known EPG
1809             # arriving on an unknown TEP
1810             p = (Ether(src=self.pg2.remote_mac,
1811                        dst=self.pg2.local_mac) /
1812                  IP(src=self.pg2.remote_hosts[1].ip4,
1813                     dst=self.pg2.local_ip4) /
1814                  UDP(sport=1234, dport=48879) /
1815                  VXLAN(vni=99, gpid=112, flags=0x88) /
1816                  Ether(src=l['mac'], dst=ep.mac) /
1817                  Raw(b'\xa5' * 100))
1818
1819             rx = self.send_and_expect(self.pg2, [p], self.pg0)
1820
1821             # the new TEP
1822             tep1_sw_if_index = find_vxlan_gbp_tunnel(
1823                 self,
1824                 self.pg2.local_ip4,
1825                 self.pg2.remote_hosts[1].ip4,
1826                 99)
1827             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
1828
1829             #
1830             # the EP is learnt via the learnt TEP
1831             # both from its MAC and its IP
1832             #
1833             self.assertTrue(find_gbp_endpoint(self,
1834                                               vx_tun_l2_1.sw_if_index,
1835                                               mac=l['mac']))
1836
1837         self.logger.info(self.vapi.cli("show gbp endpoint"))
1838         self.logger.info(self.vapi.cli("show gbp vxlan"))
1839         self.logger.info(self.vapi.cli("show vxlan-gbp tunnel"))
1840
1841         #
1842         # wait for the learnt endpoints to age out
1843         #
1844         for l in learnt:
1845             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
1846                                      mac=l['mac'])
1847
1848         #
1849         # repeat. the do not learn bit is set so the EPs are not learnt
1850         #
1851         for l in learnt:
1852             # a packet with an sclass from a known EPG
1853             p = (Ether(src=self.pg2.remote_mac,
1854                        dst=self.pg2.local_mac) /
1855                  IP(src=self.pg2.remote_hosts[1].ip4,
1856                     dst=self.pg2.local_ip4) /
1857                  UDP(sport=1234, dport=48879) /
1858                  VXLAN(vni=99, gpid=112, flags=0x88, gpflags="D") /
1859                  Ether(src=l['mac'], dst=ep.mac) /
1860                  IP(src=l['ip'], dst=ep.ip4) /
1861                  UDP(sport=1234, dport=1234) /
1862                  Raw(b'\xa5' * 100))
1863
1864             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
1865
1866         for l in learnt:
1867             self.assertFalse(find_gbp_endpoint(self,
1868                                                vx_tun_l2_1.sw_if_index,
1869                                                mac=l['mac']))
1870
1871         #
1872         # repeat
1873         #
1874         for l in learnt:
1875             # a packet with an sclass from a known EPG
1876             # set a reserved bit in addition to the G and I
1877             # reserved bits should not be checked on rx.
1878             p = (Ether(src=self.pg2.remote_mac,
1879                        dst=self.pg2.local_mac) /
1880                  IP(src=self.pg2.remote_hosts[1].ip4,
1881                     dst=self.pg2.local_ip4) /
1882                  UDP(sport=1234, dport=48879) /
1883                  VXLAN(vni=99, gpid=112, flags=0xc8) /
1884                  Ether(src=l['mac'], dst=ep.mac) /
1885                  IP(src=l['ip'], dst=ep.ip4) /
1886                  UDP(sport=1234, dport=1234) /
1887                  Raw(b'\xa5' * 100))
1888
1889             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
1890
1891             self.assertTrue(find_gbp_endpoint(self,
1892                                               vx_tun_l2_1.sw_if_index,
1893                                               mac=l['mac']))
1894
1895         #
1896         # Static EP replies to dynamics
1897         #
1898         self.logger.info(self.vapi.cli("sh l2fib bd_id 1"))
1899         for l in learnt:
1900             p = (Ether(src=ep.mac, dst=l['mac']) /
1901                  IP(dst=l['ip'], src=ep.ip4) /
1902                  UDP(sport=1234, dport=1234) /
1903                  Raw(b'\xa5' * 100))
1904
1905             rxs = self.send_and_expect(self.pg0, p * 17, self.pg2)
1906
1907             for rx in rxs:
1908                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
1909                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
1910                 self.assertEqual(rx[UDP].dport, 48879)
1911                 # the UDP source port is a random value for hashing
1912                 self.assertEqual(rx[VXLAN].gpid, 112)
1913                 self.assertEqual(rx[VXLAN].vni, 99)
1914                 self.assertTrue(rx[VXLAN].flags.G)
1915                 self.assertTrue(rx[VXLAN].flags.Instance)
1916                 self.assertTrue(rx[VXLAN].gpflags.A)
1917                 self.assertFalse(rx[VXLAN].gpflags.D)
1918
1919         for l in learnt:
1920             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
1921                                      mac=l['mac'])
1922
1923         #
1924         # repeat in the other EPG
1925         # there's no contract between 220 and 330, but the A-bit is set
1926         # so the packet is cleared for delivery
1927         #
1928         for l in learnt:
1929             # a packet with an sclass from a known EPG
1930             p = (Ether(src=self.pg2.remote_mac,
1931                        dst=self.pg2.local_mac) /
1932                  IP(src=self.pg2.remote_hosts[1].ip4,
1933                     dst=self.pg2.local_ip4) /
1934                  UDP(sport=1234, dport=48879) /
1935                  VXLAN(vni=99, gpid=113, flags=0x88, gpflags='A') /
1936                  Ether(src=l['mac'], dst=ep.mac) /
1937                  IP(src=l['ip'], dst=ep.ip4) /
1938                  UDP(sport=1234, dport=1234) /
1939                  Raw(b'\xa5' * 100))
1940
1941             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
1942
1943             self.assertTrue(find_gbp_endpoint(self,
1944                                               vx_tun_l2_1.sw_if_index,
1945                                               mac=l['mac']))
1946
1947         #
1948         # static EP cannot reach the learnt EPs since there is no contract
1949         # only test 1 EP as the others could timeout
1950         #
1951         p = (Ether(src=ep.mac, dst=l['mac']) /
1952              IP(dst=learnt[0]['ip'], src=ep.ip4) /
1953              UDP(sport=1234, dport=1234) /
1954              Raw(b'\xa5' * 100))
1955
1956         self.send_and_assert_no_replies(self.pg0, [p])
1957
1958         #
1959         # refresh the entries after the check for no replies above
1960         #
1961         for l in learnt:
1962             # a packet with an sclass from a known EPG
1963             p = (Ether(src=self.pg2.remote_mac,
1964                        dst=self.pg2.local_mac) /
1965                  IP(src=self.pg2.remote_hosts[1].ip4,
1966                     dst=self.pg2.local_ip4) /
1967                  UDP(sport=1234, dport=48879) /
1968                  VXLAN(vni=99, gpid=113, flags=0x88, gpflags='A') /
1969                  Ether(src=l['mac'], dst=ep.mac) /
1970                  IP(src=l['ip'], dst=ep.ip4) /
1971                  UDP(sport=1234, dport=1234) /
1972                  Raw(b'\xa5' * 100))
1973
1974             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
1975
1976             self.assertTrue(find_gbp_endpoint(self,
1977                                               vx_tun_l2_1.sw_if_index,
1978                                               mac=l['mac']))
1979
1980         #
1981         # Add the contract so they can talk
1982         #
1983         rule = AclRule(is_permit=1, proto=17)
1984         rule2 = AclRule(src_prefix=IPv6Network((0, 0)),
1985                         dst_prefix=IPv6Network((0, 0)), is_permit=1, proto=17)
1986         acl = VppAcl(self, rules=[rule, rule2])
1987         acl.add_vpp_config()
1988
1989         c1 = VppGbpContract(
1990             self, 401, epg_220.sclass, epg_330.sclass, acl.acl_index,
1991             [VppGbpContractRule(
1992                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1993                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1994                 []),
1995              VppGbpContractRule(
1996                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1997                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1998                  [])],
1999             [ETH_P_IP, ETH_P_IPV6])
2000         c1.add_vpp_config()
2001
2002         for l in learnt:
2003             p = (Ether(src=ep.mac, dst=l['mac']) /
2004                  IP(dst=l['ip'], src=ep.ip4) /
2005                  UDP(sport=1234, dport=1234) /
2006                  Raw(b'\xa5' * 100))
2007
2008             self.send_and_expect(self.pg0, [p], self.pg2)
2009
2010         #
2011         # send UU packets from the local EP
2012         #
2013         self.logger.info(self.vapi.cli("sh gbp bridge"))
2014         self.logger.info(self.vapi.cli("sh bridge-domain 1 detail"))
2015         p_uu = (Ether(src=ep.mac, dst="00:11:11:11:11:11") /
2016                 IP(dst="10.0.0.133", src=ep.ip4) /
2017                 UDP(sport=1234, dport=1234) /
2018                 Raw(b'\xa5' * 100))
2019         rxs = self.send_and_expect(ep.itf, [p_uu], gbd1.uu_fwd)
2020
2021         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
2022
2023         p_bm = (Ether(src=ep.mac, dst="ff:ff:ff:ff:ff:ff") /
2024                 IP(dst="10.0.0.133", src=ep.ip4) /
2025                 UDP(sport=1234, dport=1234) /
2026                 Raw(b'\xa5' * 100))
2027         rxs = self.send_and_expect_only(ep.itf, [p_bm], tun_bm.mcast_itf)
2028
2029         for rx in rxs:
2030             self.assertEqual(rx[IP].src, self.pg4.local_ip4)
2031             self.assertEqual(rx[IP].dst, "239.1.1.1")
2032             self.assertEqual(rx[UDP].dport, 48879)
2033             # the UDP source port is a random value for hashing
2034             self.assertEqual(rx[VXLAN].gpid, 112)
2035             self.assertEqual(rx[VXLAN].vni, 88)
2036             self.assertTrue(rx[VXLAN].flags.G)
2037             self.assertTrue(rx[VXLAN].flags.Instance)
2038             self.assertFalse(rx[VXLAN].gpflags.A)
2039             self.assertFalse(rx[VXLAN].gpflags.D)
2040
2041         rule = AclRule(is_permit=1, proto=17)
2042         rule2 = AclRule(src_prefix=IPv6Network((0, 0)),
2043                         dst_prefix=IPv6Network((0, 0)), is_permit=1, proto=17)
2044         acl = VppAcl(self, rules=[rule, rule2])
2045         acl.add_vpp_config()
2046
2047         c2 = VppGbpContract(
2048             self, 401, epg_330.sclass, epg_220.sclass, acl.acl_index,
2049             [VppGbpContractRule(
2050                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2051                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2052                 []),
2053                 VppGbpContractRule(
2054                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2055                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2056                     [])],
2057             [ETH_P_IP, ETH_P_IPV6])
2058         c2.add_vpp_config()
2059
2060         for l in learnt:
2061             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
2062                                      mac=l['mac'])
2063         #
2064         # Check v6 Endpoints learning
2065         #
2066         for l in learnt:
2067             # a packet with an sclass from a known EPG
2068             p = (Ether(src=self.pg2.remote_mac,
2069                        dst=self.pg2.local_mac) /
2070                  IP(src=self.pg2.remote_hosts[1].ip4,
2071                     dst=self.pg2.local_ip4) /
2072                  UDP(sport=1234, dport=48879) /
2073                  VXLAN(vni=99, gpid=113, flags=0x88) /
2074                  Ether(src=l['mac'], dst=ep.mac) /
2075                  IPv6(src=l['ip6'], dst=ep.ip6) /
2076                  UDP(sport=1234, dport=1234) /
2077                  Raw(b'\xa5' * 100))
2078
2079             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
2080             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
2081
2082             self.assertTrue(find_gbp_endpoint(
2083                 self,
2084                 vx_tun_l2_1.sw_if_index,
2085                 ip=l['ip6'],
2086                 tep=[self.pg2.local_ip4,
2087                      self.pg2.remote_hosts[1].ip4]))
2088
2089         self.logger.info(self.vapi.cli("sh int"))
2090         self.logger.info(self.vapi.cli("sh vxlan-gbp tunnel"))
2091         self.logger.info(self.vapi.cli("sh gbp vxlan"))
2092         self.logger.info(self.vapi.cli("sh gbp endpoint"))
2093         self.logger.info(self.vapi.cli("sh gbp interface"))
2094
2095         #
2096         # EP moves to a different TEP
2097         #
2098         for l in learnt:
2099             # a packet with an sclass from a known EPG
2100             p = (Ether(src=self.pg2.remote_mac,
2101                        dst=self.pg2.local_mac) /
2102                  IP(src=self.pg2.remote_hosts[2].ip4,
2103                     dst=self.pg2.local_ip4) /
2104                  UDP(sport=1234, dport=48879) /
2105                  VXLAN(vni=99, gpid=113, flags=0x88) /
2106                  Ether(src=l['mac'], dst=ep.mac) /
2107                  IPv6(src=l['ip6'], dst=ep.ip6) /
2108                  UDP(sport=1234, dport=1234) /
2109                  Raw(b'\xa5' * 100))
2110
2111             rx = self.send_and_expect(self.pg2, p * 1, self.pg0)
2112             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
2113
2114             self.assertTrue(find_gbp_endpoint(
2115                 self,
2116                 vx_tun_l2_1.sw_if_index,
2117                 sclass=113,
2118                 mac=l['mac'],
2119                 tep=[self.pg2.local_ip4,
2120                      self.pg2.remote_hosts[2].ip4]))
2121
2122         #
2123         # v6 remote EP reachability
2124         #
2125         for l in learnt:
2126             p = (Ether(src=ep.mac, dst=l['mac']) /
2127                  IPv6(dst=l['ip6'], src=ep.ip6) /
2128                  UDP(sport=1234, dport=1234) /
2129                  Raw(b'\xa5' * 100))
2130
2131             rxs = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg2)
2132
2133             for rx in rxs:
2134                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2135                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[2].ip4)
2136                 self.assertEqual(rx[UDP].dport, 48879)
2137                 # the UDP source port is a random value for hashing
2138                 self.assertEqual(rx[VXLAN].gpid, 112)
2139                 self.assertEqual(rx[VXLAN].vni, 99)
2140                 self.assertTrue(rx[VXLAN].flags.G)
2141                 self.assertTrue(rx[VXLAN].flags.Instance)
2142                 self.assertTrue(rx[VXLAN].gpflags.A)
2143                 self.assertFalse(rx[VXLAN].gpflags.D)
2144                 self.assertEqual(rx[IPv6].dst, l['ip6'])
2145
2146         #
2147         # EP changes sclass
2148         #
2149         for l in learnt:
2150             # a packet with an sclass from a known EPG
2151             p = (Ether(src=self.pg2.remote_mac,
2152                        dst=self.pg2.local_mac) /
2153                  IP(src=self.pg2.remote_hosts[2].ip4,
2154                     dst=self.pg2.local_ip4) /
2155                  UDP(sport=1234, dport=48879) /
2156                  VXLAN(vni=99, gpid=112, flags=0x88) /
2157                  Ether(src=l['mac'], dst=ep.mac) /
2158                  IPv6(src=l['ip6'], dst=ep.ip6) /
2159                  UDP(sport=1234, dport=1234) /
2160                  Raw(b'\xa5' * 100))
2161
2162             rx = self.send_and_expect(self.pg2, p * 1, self.pg0)
2163             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
2164
2165             self.assertTrue(find_gbp_endpoint(
2166                 self,
2167                 vx_tun_l2_1.sw_if_index,
2168                 mac=l['mac'],
2169                 sclass=112,
2170                 tep=[self.pg2.local_ip4,
2171                      self.pg2.remote_hosts[2].ip4]))
2172
2173         #
2174         # check reachability and contract intra-epg
2175         #
2176         allow_intra_class = self.statistics.get_err_counter(
2177             '/err/gbp-policy-mac/allow-intra-sclass')
2178
2179         for l in learnt:
2180             p = (Ether(src=ep.mac, dst=l['mac']) /
2181                  IPv6(dst=l['ip6'], src=ep.ip6) /
2182                  UDP(sport=1234, dport=1234) /
2183                  Raw(b'\xa5' * 100))
2184
2185             rxs = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg2)
2186
2187             for rx in rxs:
2188                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2189                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[2].ip4)
2190                 self.assertEqual(rx[UDP].dport, 48879)
2191                 self.assertEqual(rx[VXLAN].gpid, 112)
2192                 self.assertEqual(rx[VXLAN].vni, 99)
2193                 self.assertTrue(rx[VXLAN].flags.G)
2194                 self.assertTrue(rx[VXLAN].flags.Instance)
2195                 self.assertTrue(rx[VXLAN].gpflags.A)
2196                 self.assertFalse(rx[VXLAN].gpflags.D)
2197                 self.assertEqual(rx[IPv6].dst, l['ip6'])
2198
2199             allow_intra_class += NUM_PKTS
2200
2201         self.assert_error_counter_equal(
2202             '/err/gbp-policy-mac/allow-intra-sclass',
2203             allow_intra_class)
2204
2205         #
2206         # clean up
2207         #
2208         for l in learnt:
2209             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
2210                                      mac=l['mac'])
2211         self.pg2.unconfig_ip4()
2212         self.pg3.unconfig_ip4()
2213         self.pg4.unconfig_ip4()
2214
2215     def test_gbp_contract(self):
2216         """ GBP Contracts """
2217
2218         #
2219         # Route Domains
2220         #
2221         gt4 = VppIpTable(self, 0)
2222         gt4.add_vpp_config()
2223         gt6 = VppIpTable(self, 0, is_ip6=True)
2224         gt6.add_vpp_config()
2225
2226         rd0 = VppGbpRouteDomain(self, 0, 400, gt4, gt6, None, None)
2227
2228         rd0.add_vpp_config()
2229
2230         #
2231         # Bridge Domains
2232         #
2233         bd1 = VppBridgeDomain(self, 1, arp_term=0)
2234         bd2 = VppBridgeDomain(self, 2, arp_term=0)
2235
2236         bd1.add_vpp_config()
2237         bd2.add_vpp_config()
2238
2239         gbd1 = VppGbpBridgeDomain(self, bd1, rd0, self.loop0)
2240         gbd2 = VppGbpBridgeDomain(self, bd2, rd0, self.loop1)
2241
2242         gbd1.add_vpp_config()
2243         gbd2.add_vpp_config()
2244
2245         #
2246         # 3 EPGs, 2 of which share a BD.
2247         #
2248         epgs = [VppGbpEndpointGroup(self, 220, 1220, rd0, gbd1,
2249                                     None, self.loop0,
2250                                     "10.0.0.128", "2001:10::128"),
2251                 VppGbpEndpointGroup(self, 221, 1221, rd0, gbd1,
2252                                     None, self.loop0,
2253                                     "10.0.1.128", "2001:10:1::128"),
2254                 VppGbpEndpointGroup(self, 222, 1222, rd0, gbd2,
2255                                     None, self.loop1,
2256                                     "10.0.2.128", "2001:10:2::128")]
2257         #
2258         # 4 end-points, 2 in the same subnet, 3 in the same BD
2259         #
2260         eps = [VppGbpEndpoint(self, self.pg0,
2261                               epgs[0], None,
2262                               "10.0.0.1", "11.0.0.1",
2263                               "2001:10::1", "3001::1"),
2264                VppGbpEndpoint(self, self.pg1,
2265                               epgs[0], None,
2266                               "10.0.0.2", "11.0.0.2",
2267                               "2001:10::2", "3001::2"),
2268                VppGbpEndpoint(self, self.pg2,
2269                               epgs[1], None,
2270                               "10.0.1.1", "11.0.0.3",
2271                               "2001:10:1::1", "3001::3"),
2272                VppGbpEndpoint(self, self.pg3,
2273                               epgs[2], None,
2274                               "10.0.2.1", "11.0.0.4",
2275                               "2001:10:2::1", "3001::4")]
2276
2277         #
2278         # Config related to each of the EPGs
2279         #
2280         for epg in epgs:
2281             # IP config on the BVI interfaces
2282             if epg != epgs[1]:
2283                 b4 = VppIpInterfaceBind(self, epg.bvi,
2284                                         epg.rd.t4).add_vpp_config()
2285                 b6 = VppIpInterfaceBind(self, epg.bvi,
2286                                         epg.rd.t6).add_vpp_config()
2287                 epg.bvi.set_mac(self.router_mac)
2288
2289             if_ip4 = VppIpInterfaceAddress(self, epg.bvi,
2290                                            epg.bvi_ip4, 32,
2291                                            bind=b4).add_vpp_config()
2292             if_ip6 = VppIpInterfaceAddress(self, epg.bvi,
2293                                            epg.bvi_ip6, 128,
2294                                            bind=b6).add_vpp_config()
2295
2296             # add the BD ARP termination entry for BVI IP
2297             epg.bd_arp_ip4 = VppBridgeDomainArpEntry(self, epg.bd.bd,
2298                                                      str(self.router_mac),
2299                                                      epg.bvi_ip4)
2300             epg.bd_arp_ip4.add_vpp_config()
2301
2302             # EPG in VPP
2303             epg.add_vpp_config()
2304
2305         #
2306         # config ep
2307         #
2308         for ep in eps:
2309             ep.add_vpp_config()
2310
2311         self.logger.info(self.vapi.cli("show gbp endpoint"))
2312         self.logger.info(self.vapi.cli("show interface"))
2313         self.logger.info(self.vapi.cli("show br"))
2314
2315         #
2316         # Intra epg allowed without contract
2317         #
2318         pkt_intra_epg_220_to_220 = (Ether(src=self.pg0.remote_mac,
2319                                           dst=self.pg1.remote_mac) /
2320                                     IP(src=eps[0].ip4,
2321                                        dst=eps[1].ip4) /
2322                                     UDP(sport=1234, dport=1234) /
2323                                     Raw(b'\xa5' * 100))
2324
2325         self.send_and_expect_bridged(self.pg0,
2326                                      pkt_intra_epg_220_to_220 * 65,
2327                                      self.pg1)
2328
2329         pkt_intra_epg_220_to_220 = (Ether(src=self.pg0.remote_mac,
2330                                           dst=self.pg1.remote_mac) /
2331                                     IPv6(src=eps[0].ip6,
2332                                          dst=eps[1].ip6) /
2333                                     UDP(sport=1234, dport=1234) /
2334                                     Raw(b'\xa5' * 100))
2335
2336         self.send_and_expect_bridged6(self.pg0,
2337                                       pkt_intra_epg_220_to_220 * 65,
2338                                       self.pg1)
2339
2340         #
2341         # Inter epg denied without contract
2342         #
2343         pkt_inter_epg_220_to_221 = (Ether(src=self.pg0.remote_mac,
2344                                           dst=self.pg2.remote_mac) /
2345                                     IP(src=eps[0].ip4,
2346                                        dst=eps[2].ip4) /
2347                                     UDP(sport=1234, dport=1234) /
2348                                     Raw(b'\xa5' * 100))
2349
2350         self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_220_to_221)
2351
2352         #
2353         # A uni-directional contract from EPG 220 -> 221
2354         #
2355         rule = AclRule(is_permit=1, proto=17)
2356         rule2 = AclRule(src_prefix=IPv6Network((0, 0)),
2357                         dst_prefix=IPv6Network((0, 0)), is_permit=1, proto=17)
2358         rule3 = AclRule(is_permit=1, proto=1)
2359         acl = VppAcl(self, rules=[rule, rule2, rule3])
2360         acl.add_vpp_config()
2361
2362         c1 = VppGbpContract(
2363             self, 400, epgs[0].sclass, epgs[1].sclass, acl.acl_index,
2364             [VppGbpContractRule(
2365                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2366                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2367                 []),
2368              VppGbpContractRule(
2369                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2370                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2371                  []),
2372              VppGbpContractRule(
2373                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2374                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2375                  [])],
2376             [ETH_P_IP, ETH_P_IPV6])
2377         c1.add_vpp_config()
2378
2379         self.send_and_expect_bridged(eps[0].itf,
2380                                      pkt_inter_epg_220_to_221 * 65,
2381                                      eps[2].itf)
2382
2383         pkt_inter_epg_220_to_222 = (Ether(src=self.pg0.remote_mac,
2384                                           dst=str(self.router_mac)) /
2385                                     IP(src=eps[0].ip4,
2386                                        dst=eps[3].ip4) /
2387                                     UDP(sport=1234, dport=1234) /
2388                                     Raw(b'\xa5' * 100))
2389         self.send_and_assert_no_replies(eps[0].itf,
2390                                         pkt_inter_epg_220_to_222 * 65)
2391
2392         #
2393         # ping router IP in different BD
2394         #
2395         pkt_router_ping_220_to_221 = (Ether(src=self.pg0.remote_mac,
2396                                             dst=str(self.router_mac)) /
2397                                       IP(src=eps[0].ip4,
2398                                          dst=epgs[1].bvi_ip4) /
2399                                       ICMP(type='echo-request'))
2400
2401         self.send_and_expect(self.pg0, [pkt_router_ping_220_to_221], self.pg0)
2402
2403         pkt_router_ping_220_to_221 = (Ether(src=self.pg0.remote_mac,
2404                                             dst=str(self.router_mac)) /
2405                                       IPv6(src=eps[0].ip6,
2406                                            dst=epgs[1].bvi_ip6) /
2407                                       ICMPv6EchoRequest())
2408
2409         self.send_and_expect(self.pg0, [pkt_router_ping_220_to_221], self.pg0)
2410
2411         #
2412         # contract for the return direction
2413         #
2414         c2 = VppGbpContract(
2415             self, 400, epgs[1].sclass, epgs[0].sclass, acl.acl_index,
2416             [VppGbpContractRule(
2417                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2418                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2419                 []),
2420              VppGbpContractRule(
2421                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2422                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2423                  [])],
2424             [ETH_P_IP, ETH_P_IPV6])
2425         c2.add_vpp_config()
2426
2427         self.send_and_expect_bridged(eps[0].itf,
2428                                      pkt_inter_epg_220_to_221 * 65,
2429                                      eps[2].itf)
2430         pkt_inter_epg_221_to_220 = (Ether(src=self.pg2.remote_mac,
2431                                           dst=self.pg0.remote_mac) /
2432                                     IP(src=eps[2].ip4,
2433                                        dst=eps[0].ip4) /
2434                                     UDP(sport=1234, dport=1234) /
2435                                     Raw(b'\xa5' * 100))
2436         self.send_and_expect_bridged(eps[2].itf,
2437                                      pkt_inter_epg_221_to_220 * 65,
2438                                      eps[0].itf)
2439         pkt_inter_epg_221_to_220 = (Ether(src=self.pg2.remote_mac,
2440                                           dst=str(self.router_mac)) /
2441                                     IP(src=eps[2].ip4,
2442                                        dst=eps[0].ip4) /
2443                                     UDP(sport=1234, dport=1234) /
2444                                     Raw(b'\xa5' * 100))
2445         self.send_and_expect_routed(eps[2].itf,
2446                                     pkt_inter_epg_221_to_220 * 65,
2447                                     eps[0].itf,
2448                                     str(self.router_mac))
2449         pkt_inter_epg_221_to_220 = (Ether(src=self.pg2.remote_mac,
2450                                           dst=str(self.router_mac)) /
2451                                     IPv6(src=eps[2].ip6,
2452                                          dst=eps[0].ip6) /
2453                                     UDP(sport=1234, dport=1234) /
2454                                     Raw(b'\xa5' * 100))
2455         self.send_and_expect_routed6(eps[2].itf,
2456                                      pkt_inter_epg_221_to_220 * 65,
2457                                      eps[0].itf,
2458                                      str(self.router_mac))
2459
2460         #
2461         # contract between 220 and 222 uni-direction
2462         #
2463         c3 = VppGbpContract(
2464             self, 400, epgs[0].sclass, epgs[2].sclass, acl.acl_index,
2465             [VppGbpContractRule(
2466                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2467                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2468                 []),
2469              VppGbpContractRule(
2470                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2471                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2472                  [])],
2473             [ETH_P_IP, ETH_P_IPV6])
2474         c3.add_vpp_config()
2475
2476         self.send_and_expect(eps[0].itf,
2477                              pkt_inter_epg_220_to_222 * 65,
2478                              eps[3].itf)
2479
2480         c3.remove_vpp_config()
2481         c1.remove_vpp_config()
2482         c2.remove_vpp_config()
2483         acl.remove_vpp_config()
2484
2485     def test_gbp_bd_drop_flags(self):
2486         """ GBP BD drop flags """
2487
2488         #
2489         # IP tables
2490         #
2491         gt4 = VppIpTable(self, 1)
2492         gt4.add_vpp_config()
2493         gt6 = VppIpTable(self, 1, is_ip6=True)
2494         gt6.add_vpp_config()
2495
2496         rd1 = VppGbpRouteDomain(self, 1, 401, gt4, gt6)
2497         rd1.add_vpp_config()
2498
2499         #
2500         # a GBP bridge domain with a BVI only
2501         #
2502         bd1 = VppBridgeDomain(self, 1)
2503         bd1.add_vpp_config()
2504
2505         gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0,
2506                                   None, None,
2507                                   uu_drop=True, bm_drop=True)
2508         gbd1.add_vpp_config()
2509
2510         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
2511         self.logger.info(self.vapi.cli("sh gbp bridge"))
2512
2513         # ... and has a /32 applied
2514         ip_addr = VppIpInterfaceAddress(self, gbd1.bvi,
2515                                         "10.0.0.128", 32).add_vpp_config()
2516
2517         #
2518         # The Endpoint-group
2519         #
2520         epg_220 = VppGbpEndpointGroup(self, 220, 112, rd1, gbd1,
2521                                       None, self.loop0,
2522                                       "10.0.0.128",
2523                                       "2001:10::128",
2524                                       VppGbpEndpointRetention(3))
2525         epg_220.add_vpp_config()
2526
2527         ep = VppGbpEndpoint(self, self.pg0,
2528                             epg_220, None,
2529                             "10.0.0.127", "11.0.0.127",
2530                             "2001:10::1", "3001::1")
2531         ep.add_vpp_config()
2532
2533         #
2534         # send UU/BM packet from the local EP with UU drop and BM drop enabled
2535         # in bd
2536         #
2537         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
2538         self.logger.info(self.vapi.cli("sh gbp bridge"))
2539         p_uu = (Ether(src=ep.mac, dst="00:11:11:11:11:11") /
2540                 IP(dst="10.0.0.133", src=ep.ip4) /
2541                 UDP(sport=1234, dport=1234) /
2542                 Raw(b'\xa5' * 100))
2543         self.send_and_assert_no_replies(ep.itf, [p_uu])
2544
2545         p_bm = (Ether(src=ep.mac, dst="ff:ff:ff:ff:ff:ff") /
2546                 IP(dst="10.0.0.133", src=ep.ip4) /
2547                 UDP(sport=1234, dport=1234) /
2548                 Raw(b'\xa5' * 100))
2549         self.send_and_assert_no_replies(ep.itf, [p_bm])
2550
2551         self.pg3.unconfig_ip4()
2552
2553         self.logger.info(self.vapi.cli("sh int"))
2554
2555     def test_gbp_bd_arp_flags(self):
2556         """ GBP BD arp flags """
2557
2558         #
2559         # IP tables
2560         #
2561         gt4 = VppIpTable(self, 1)
2562         gt4.add_vpp_config()
2563         gt6 = VppIpTable(self, 1, is_ip6=True)
2564         gt6.add_vpp_config()
2565
2566         rd1 = VppGbpRouteDomain(self, 1, 401, gt4, gt6)
2567         rd1.add_vpp_config()
2568
2569         #
2570         # Pg4 hosts the IP6 UU-flood VXLAN tunnel
2571         #
2572         self.pg4.config_ip4()
2573         self.pg4.resolve_arp()
2574
2575         #
2576         # Add a mcast destination VXLAN-GBP tunnel for B&M traffic
2577         #
2578         tun_uu = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
2579                                    "239.1.1.1", 88,
2580                                    mcast_itf=self.pg4)
2581         tun_uu.add_vpp_config()
2582
2583         #
2584         # a GBP bridge domain with a BVI and a UU-flood interface
2585         #
2586         bd1 = VppBridgeDomain(self, 1)
2587         bd1.add_vpp_config()
2588
2589         gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0,
2590                                   tun_uu, None,
2591                                   ucast_arp=True)
2592         gbd1.add_vpp_config()
2593
2594         # ... and has a /32 applied
2595         ip_addr = VppIpInterfaceAddress(self, gbd1.bvi,
2596                                         "10.0.0.128", 32).add_vpp_config()
2597
2598         #
2599         # The Endpoint-group
2600         #
2601         epg_220 = VppGbpEndpointGroup(self, 220, 112, rd1, gbd1,
2602                                       None, self.loop0,
2603                                       "10.0.0.128",
2604                                       "2001:10::128",
2605                                       VppGbpEndpointRetention(2))
2606         epg_220.add_vpp_config()
2607
2608         ep = VppGbpEndpoint(self, self.pg0,
2609                             epg_220, None,
2610                             "10.0.0.127", "11.0.0.127",
2611                             "2001:10::1", "3001::1")
2612         ep.add_vpp_config()
2613
2614         #
2615         # send ARP packet from the local EP expect it on the uu interface
2616         #
2617         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
2618         self.logger.info(self.vapi.cli("sh gbp bridge"))
2619         p_arp = (Ether(src=ep.mac, dst="ff:ff:ff:ff:ff:ff") /
2620                  ARP(op="who-has",
2621                      psrc=ep.ip4, pdst="10.0.0.99",
2622                      hwsrc=ep.mac,
2623                      hwdst="ff:ff:ff:ff:ff:ff"))
2624         self.send_and_expect(ep.itf, [p_arp], self.pg4)
2625
2626         self.pg4.unconfig_ip4()
2627
2628     def test_gbp_learn_vlan_l2(self):
2629         """ GBP L2 Endpoint w/ VLANs"""
2630
2631         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
2632         learnt = [{'mac': '00:00:11:11:11:01',
2633                    'ip': '10.0.0.1',
2634                    'ip6': '2001:10::2'},
2635                   {'mac': '00:00:11:11:11:02',
2636                    'ip': '10.0.0.2',
2637                    'ip6': '2001:10::3'}]
2638
2639         #
2640         # IP tables
2641         #
2642         gt4 = VppIpTable(self, 1)
2643         gt4.add_vpp_config()
2644         gt6 = VppIpTable(self, 1, is_ip6=True)
2645         gt6.add_vpp_config()
2646
2647         rd1 = VppGbpRouteDomain(self, 1, 401, gt4, gt6)
2648         rd1.add_vpp_config()
2649
2650         #
2651         # Pg2 hosts the vxlan tunnel, hosts on pg2 to act as TEPs
2652         #
2653         self.pg2.config_ip4()
2654         self.pg2.resolve_arp()
2655         self.pg2.generate_remote_hosts(4)
2656         self.pg2.configure_ipv4_neighbors()
2657         self.pg3.config_ip4()
2658         self.pg3.resolve_arp()
2659
2660         #
2661         # The EP will be on a vlan sub-interface
2662         #
2663         vlan_11 = VppDot1QSubint(self, self.pg0, 11)
2664         vlan_11.admin_up()
2665         self.vapi.l2_interface_vlan_tag_rewrite(
2666             sw_if_index=vlan_11.sw_if_index, vtr_op=L2_VTR_OP.L2_POP_1,
2667             push_dot1q=11)
2668
2669         bd_uu_fwd = VppVxlanGbpTunnel(self, self.pg3.local_ip4,
2670                                       self.pg3.remote_ip4, 116)
2671         bd_uu_fwd.add_vpp_config()
2672
2673         #
2674         # a GBP bridge domain with a BVI and a UU-flood interface
2675         # The BD is marked as do not learn, so no endpoints are ever
2676         # learnt in this BD.
2677         #
2678         bd1 = VppBridgeDomain(self, 1)
2679         bd1.add_vpp_config()
2680         gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0, bd_uu_fwd,
2681                                   learn=False)
2682         gbd1.add_vpp_config()
2683
2684         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
2685         self.logger.info(self.vapi.cli("sh gbp bridge"))
2686
2687         # ... and has a /32 applied
2688         ip_addr = VppIpInterfaceAddress(self, gbd1.bvi,
2689                                         "10.0.0.128", 32).add_vpp_config()
2690
2691         #
2692         # The Endpoint-group in which we are learning endpoints
2693         #
2694         epg_220 = VppGbpEndpointGroup(self, 220, 441, rd1, gbd1,
2695                                       None, self.loop0,
2696                                       "10.0.0.128",
2697                                       "2001:10::128",
2698                                       VppGbpEndpointRetention(4))
2699         epg_220.add_vpp_config()
2700
2701         #
2702         # The VXLAN GBP tunnel is a bridge-port and has L2 endpoint
2703         # learning enabled
2704         #
2705         vx_tun_l2_1 = VppGbpVxlanTunnel(
2706             self, 99, bd1.bd_id,
2707             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L2,
2708             self.pg2.local_ip4)
2709         vx_tun_l2_1.add_vpp_config()
2710
2711         #
2712         # A static endpoint that the learnt endpoints are trying to
2713         # talk to
2714         #
2715         ep = VppGbpEndpoint(self, vlan_11,
2716                             epg_220, None,
2717                             "10.0.0.127", "11.0.0.127",
2718                             "2001:10::1", "3001::1")
2719         ep.add_vpp_config()
2720
2721         self.assertTrue(find_route(self, ep.ip4, 32, table_id=1))
2722
2723         #
2724         # Send to the static EP
2725         #
2726         for ii, l in enumerate(learnt):
2727             # a packet with an sclass from a known EPG
2728             # arriving on an unknown TEP
2729             p = (Ether(src=self.pg2.remote_mac,
2730                        dst=self.pg2.local_mac) /
2731                  IP(src=self.pg2.remote_hosts[1].ip4,
2732                     dst=self.pg2.local_ip4) /
2733                  UDP(sport=1234, dport=48879) /
2734                  VXLAN(vni=99, gpid=441, flags=0x88) /
2735                  Ether(src=l['mac'], dst=ep.mac) /
2736                  IP(src=l['ip'], dst=ep.ip4) /
2737                  UDP(sport=1234, dport=1234) /
2738                  Raw(b'\xa5' * 100))
2739
2740             rxs = self.send_and_expect(self.pg2, [p], self.pg0)
2741
2742             #
2743             # packet to EP has the EP's vlan tag
2744             #
2745             for rx in rxs:
2746                 self.assertEqual(rx[Dot1Q].vlan, 11)
2747
2748             #
2749             # the EP is not learnt since the BD setting prevents it
2750             # also no TEP too
2751             #
2752             self.assertFalse(find_gbp_endpoint(self,
2753                                                vx_tun_l2_1.sw_if_index,
2754                                                mac=l['mac']))
2755             self.assertEqual(INDEX_INVALID,
2756                              find_vxlan_gbp_tunnel(
2757                                  self,
2758                                  self.pg2.local_ip4,
2759                                  self.pg2.remote_hosts[1].ip4,
2760                                  99))
2761
2762         self.assertEqual(len(self.vapi.gbp_endpoint_dump()), 1)
2763
2764         #
2765         # static to remotes
2766         # we didn't learn the remotes so they are sent to the UU-fwd
2767         #
2768         for l in learnt:
2769             p = (Ether(src=ep.mac, dst=l['mac']) /
2770                  Dot1Q(vlan=11) /
2771                  IP(dst=l['ip'], src=ep.ip4) /
2772                  UDP(sport=1234, dport=1234) /
2773                  Raw(b'\xa5' * 100))
2774
2775             rxs = self.send_and_expect(self.pg0, p * 17, self.pg3)
2776
2777             for rx in rxs:
2778                 self.assertEqual(rx[IP].src, self.pg3.local_ip4)
2779                 self.assertEqual(rx[IP].dst, self.pg3.remote_ip4)
2780                 self.assertEqual(rx[UDP].dport, 48879)
2781                 # the UDP source port is a random value for hashing
2782                 self.assertEqual(rx[VXLAN].gpid, 441)
2783                 self.assertEqual(rx[VXLAN].vni, 116)
2784                 self.assertTrue(rx[VXLAN].flags.G)
2785                 self.assertTrue(rx[VXLAN].flags.Instance)
2786                 self.assertFalse(rx[VXLAN].gpflags.A)
2787                 self.assertFalse(rx[VXLAN].gpflags.D)
2788
2789         self.pg2.unconfig_ip4()
2790         self.pg3.unconfig_ip4()
2791
2792     def test_gbp_learn_l3(self):
2793         """ GBP L3 Endpoint Learning """
2794
2795         self.vapi.cli("set logging class gbp level debug")
2796
2797         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
2798         routed_dst_mac = "00:0c:0c:0c:0c:0c"
2799         routed_src_mac = "00:22:bd:f8:19:ff"
2800
2801         learnt = [{'mac': '00:00:11:11:11:02',
2802                    'ip': '10.0.1.2',
2803                    'ip6': '2001:10::2'},
2804                   {'mac': '00:00:11:11:11:03',
2805                    'ip': '10.0.1.3',
2806                    'ip6': '2001:10::3'}]
2807
2808         #
2809         # IP tables
2810         #
2811         t4 = VppIpTable(self, 1)
2812         t4.add_vpp_config()
2813         t6 = VppIpTable(self, 1, True)
2814         t6.add_vpp_config()
2815
2816         tun_ip4_uu = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
2817                                        self.pg4.remote_ip4, 114)
2818         tun_ip6_uu = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
2819                                        self.pg4.remote_ip4, 116)
2820         tun_ip4_uu.add_vpp_config()
2821         tun_ip6_uu.add_vpp_config()
2822
2823         rd1 = VppGbpRouteDomain(self, 2, 401, t4, t6, tun_ip4_uu, tun_ip6_uu)
2824         rd1.add_vpp_config()
2825
2826         self.loop0.set_mac(self.router_mac)
2827
2828         #
2829         # Bind the BVI to the RD
2830         #
2831         b4 = VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
2832         b6 = VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
2833
2834         #
2835         # Pg2 hosts the vxlan tunnel
2836         # hosts on pg2 to act as TEPs
2837         # pg3 is BD uu-fwd
2838         # pg4 is RD uu-fwd
2839         #
2840         self.pg2.config_ip4()
2841         self.pg2.resolve_arp()
2842         self.pg2.generate_remote_hosts(4)
2843         self.pg2.configure_ipv4_neighbors()
2844         self.pg3.config_ip4()
2845         self.pg3.resolve_arp()
2846         self.pg4.config_ip4()
2847         self.pg4.resolve_arp()
2848
2849         #
2850         # a GBP bridge domain with a BVI and a UU-flood interface
2851         #
2852         bd1 = VppBridgeDomain(self, 1)
2853         bd1.add_vpp_config()
2854         gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0, self.pg3)
2855         gbd1.add_vpp_config()
2856
2857         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
2858         self.logger.info(self.vapi.cli("sh gbp bridge"))
2859         self.logger.info(self.vapi.cli("sh gbp route"))
2860
2861         # ... and has a /32 and /128 applied
2862         ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi,
2863                                          "10.0.0.128", 32,
2864                                          bind=b4).add_vpp_config()
2865         ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi,
2866                                          "2001:10::128", 128,
2867                                          bind=b6).add_vpp_config()
2868
2869         #
2870         # The Endpoint-group in which we are learning endpoints
2871         #
2872         epg_220 = VppGbpEndpointGroup(self, 220, 441, rd1, gbd1,
2873                                       None, self.loop0,
2874                                       "10.0.0.128",
2875                                       "2001:10::128",
2876                                       VppGbpEndpointRetention(4))
2877         epg_220.add_vpp_config()
2878
2879         #
2880         # The VXLAN GBP tunnel is in L3 mode with learning enabled
2881         #
2882         vx_tun_l3 = VppGbpVxlanTunnel(
2883             self, 101, rd1.rd_id,
2884             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3,
2885             self.pg2.local_ip4)
2886         vx_tun_l3.add_vpp_config()
2887
2888         #
2889         # A static endpoint that the learnt endpoints are trying to
2890         # talk to
2891         #
2892         ep = VppGbpEndpoint(self, self.pg0,
2893                             epg_220, None,
2894                             "10.0.0.127", "11.0.0.127",
2895                             "2001:10::1", "3001::1")
2896         ep.add_vpp_config()
2897
2898         #
2899         # learn some remote IPv4 EPs
2900         #
2901         for ii, l in enumerate(learnt):
2902             # a packet with an sclass from a known EPG
2903             # arriving on an unknown TEP
2904             p = (Ether(src=self.pg2.remote_mac,
2905                        dst=self.pg2.local_mac) /
2906                  IP(src=self.pg2.remote_hosts[1].ip4,
2907                     dst=self.pg2.local_ip4) /
2908                  UDP(sport=1234, dport=48879) /
2909                  VXLAN(vni=101, gpid=441, flags=0x88) /
2910                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
2911                  IP(src=l['ip'], dst=ep.ip4) /
2912                  UDP(sport=1234, dport=1234) /
2913                  Raw(b'\xa5' * 100))
2914
2915             rx = self.send_and_expect(self.pg2, [p], self.pg0)
2916
2917             # the new TEP
2918             tep1_sw_if_index = find_vxlan_gbp_tunnel(
2919                 self,
2920                 self.pg2.local_ip4,
2921                 self.pg2.remote_hosts[1].ip4,
2922                 vx_tun_l3.vni)
2923             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
2924
2925             # endpoint learnt via the parent GBP-vxlan interface
2926             self.assertTrue(find_gbp_endpoint(self,
2927                                               vx_tun_l3._sw_if_index,
2928                                               ip=l['ip']))
2929
2930         #
2931         # Static IPv4 EP replies to learnt
2932         #
2933         for l in learnt:
2934             p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2935                  IP(dst=l['ip'], src=ep.ip4) /
2936                  UDP(sport=1234, dport=1234) /
2937                  Raw(b'\xa5' * 100))
2938
2939             rxs = self.send_and_expect(self.pg0, p * 1, self.pg2)
2940
2941             for rx in rxs:
2942                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2943                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
2944                 self.assertEqual(rx[UDP].dport, 48879)
2945                 # the UDP source port is a random value for hashing
2946                 self.assertEqual(rx[VXLAN].gpid, 441)
2947                 self.assertEqual(rx[VXLAN].vni, 101)
2948                 self.assertTrue(rx[VXLAN].flags.G)
2949                 self.assertTrue(rx[VXLAN].flags.Instance)
2950                 self.assertTrue(rx[VXLAN].gpflags.A)
2951                 self.assertFalse(rx[VXLAN].gpflags.D)
2952
2953                 inner = rx[VXLAN].payload
2954
2955                 self.assertEqual(inner[Ether].src, routed_src_mac)
2956                 self.assertEqual(inner[Ether].dst, routed_dst_mac)
2957                 self.assertEqual(inner[IP].src, ep.ip4)
2958                 self.assertEqual(inner[IP].dst, l['ip'])
2959
2960         for l in learnt:
2961             self.assertFalse(find_gbp_endpoint(self,
2962                                                tep1_sw_if_index,
2963                                                ip=l['ip']))
2964
2965         #
2966         # learn some remote IPv6 EPs
2967         #
2968         for ii, l in enumerate(learnt):
2969             # a packet with an sclass from a known EPG
2970             # arriving on an unknown TEP
2971             p = (Ether(src=self.pg2.remote_mac,
2972                        dst=self.pg2.local_mac) /
2973                  IP(src=self.pg2.remote_hosts[1].ip4,
2974                     dst=self.pg2.local_ip4) /
2975                  UDP(sport=1234, dport=48879) /
2976                  VXLAN(vni=101, gpid=441, flags=0x88) /
2977                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
2978                  IPv6(src=l['ip6'], dst=ep.ip6) /
2979                  UDP(sport=1234, dport=1234) /
2980                  Raw(b'\xa5' * 100))
2981
2982             rx = self.send_and_expect(self.pg2, [p], self.pg0)
2983
2984             # the new TEP
2985             tep1_sw_if_index = find_vxlan_gbp_tunnel(
2986                 self,
2987                 self.pg2.local_ip4,
2988                 self.pg2.remote_hosts[1].ip4,
2989                 vx_tun_l3.vni)
2990             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
2991
2992             self.logger.info(self.vapi.cli("show gbp bridge"))
2993             self.logger.info(self.vapi.cli("show vxlan-gbp tunnel"))
2994             self.logger.info(self.vapi.cli("show gbp vxlan"))
2995             self.logger.info(self.vapi.cli("show int addr"))
2996
2997             # endpoint learnt via the TEP
2998             self.assertTrue(find_gbp_endpoint(self, ip=l['ip6']))
2999
3000         self.logger.info(self.vapi.cli("show gbp endpoint"))
3001         self.logger.info(self.vapi.cli("show ip fib index 1 %s" % l['ip']))
3002
3003         #
3004         # Static EP replies to learnt
3005         #
3006         for l in learnt:
3007             p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
3008                  IPv6(dst=l['ip6'], src=ep.ip6) /
3009                  UDP(sport=1234, dport=1234) /
3010                  Raw(b'\xa5' * 100))
3011
3012             rxs = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg2)
3013
3014             for rx in rxs:
3015                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
3016                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
3017                 self.assertEqual(rx[UDP].dport, 48879)
3018                 # the UDP source port is a random value for hashing
3019                 self.assertEqual(rx[VXLAN].gpid, 441)
3020                 self.assertEqual(rx[VXLAN].vni, 101)
3021                 self.assertTrue(rx[VXLAN].flags.G)
3022                 self.assertTrue(rx[VXLAN].flags.Instance)
3023                 self.assertTrue(rx[VXLAN].gpflags.A)
3024                 self.assertFalse(rx[VXLAN].gpflags.D)
3025
3026                 inner = rx[VXLAN].payload
3027
3028                 self.assertEqual(inner[Ether].src, routed_src_mac)
3029                 self.assertEqual(inner[Ether].dst, routed_dst_mac)
3030                 self.assertEqual(inner[IPv6].src, ep.ip6)
3031                 self.assertEqual(inner[IPv6].dst, l['ip6'])
3032
3033         self.logger.info(self.vapi.cli("sh gbp endpoint"))
3034         for l in learnt:
3035             self.wait_for_ep_timeout(ip=l['ip'])
3036
3037         #
3038         # Static sends to unknown EP with no route
3039         #
3040         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
3041              IP(dst="10.0.0.99", src=ep.ip4) /
3042              UDP(sport=1234, dport=1234) /
3043              Raw(b'\xa5' * 100))
3044
3045         self.send_and_assert_no_replies(self.pg0, [p])
3046
3047         #
3048         # Add a route to static EP's v4 and v6 subnet
3049         #
3050         se_10_24 = VppGbpSubnet(
3051             self, rd1, "10.0.0.0", 24,
3052             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_TRANSPORT)
3053         se_10_24.add_vpp_config()
3054
3055         #
3056         # static pings router
3057         #
3058         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
3059              IP(dst=epg_220.bvi_ip4, src=ep.ip4) /
3060              UDP(sport=1234, dport=1234) /
3061              Raw(b'\xa5' * 100))
3062
3063         self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg0)
3064
3065         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
3066              IPv6(dst=epg_220.bvi_ip6, src=ep.ip6) /
3067              UDP(sport=1234, dport=1234) /
3068              Raw(b'\xa5' * 100))
3069
3070         self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg0)
3071
3072         #
3073         # packets to address in the subnet are sent on the uu-fwd
3074         #
3075         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
3076              IP(dst="10.0.0.99", src=ep.ip4) /
3077              UDP(sport=1234, dport=1234) /
3078              Raw(b'\xa5' * 100))
3079
3080         rxs = self.send_and_expect(self.pg0, [p], self.pg4)
3081         for rx in rxs:
3082             self.assertEqual(rx[IP].src, self.pg4.local_ip4)
3083             self.assertEqual(rx[IP].dst, self.pg4.remote_ip4)
3084             self.assertEqual(rx[UDP].dport, 48879)
3085             # the UDP source port is a random value for hashing
3086             self.assertEqual(rx[VXLAN].gpid, 441)
3087             self.assertEqual(rx[VXLAN].vni, 114)
3088             self.assertTrue(rx[VXLAN].flags.G)
3089             self.assertTrue(rx[VXLAN].flags.Instance)
3090             # policy is not applied to packets sent to the uu-fwd interfaces
3091             self.assertFalse(rx[VXLAN].gpflags.A)
3092             self.assertFalse(rx[VXLAN].gpflags.D)
3093
3094         #
3095         # learn some remote IPv4 EPs
3096         #
3097         for ii, l in enumerate(learnt):
3098             # a packet with an sclass from a known EPG
3099             # arriving on an unknown TEP
3100             p = (Ether(src=self.pg2.remote_mac,
3101                        dst=self.pg2.local_mac) /
3102                  IP(src=self.pg2.remote_hosts[2].ip4,
3103                     dst=self.pg2.local_ip4) /
3104                  UDP(sport=1234, dport=48879) /
3105                  VXLAN(vni=101, gpid=441, flags=0x88) /
3106                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
3107                  IP(src=l['ip'], dst=ep.ip4) /
3108                  UDP(sport=1234, dport=1234) /
3109                  Raw(b'\xa5' * 100))
3110
3111             rx = self.send_and_expect(self.pg2, [p], self.pg0)
3112
3113             # the new TEP
3114             tep1_sw_if_index = find_vxlan_gbp_tunnel(
3115                 self,
3116                 self.pg2.local_ip4,
3117                 self.pg2.remote_hosts[2].ip4,
3118                 vx_tun_l3.vni)
3119             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
3120
3121             # endpoint learnt via the parent GBP-vxlan interface
3122             self.assertTrue(find_gbp_endpoint(self,
3123                                               vx_tun_l3._sw_if_index,
3124                                               ip=l['ip']))
3125
3126         #
3127         # Add a remote endpoint from the API
3128         #
3129         rep_88 = VppGbpEndpoint(self, vx_tun_l3,
3130                                 epg_220, None,
3131                                 "10.0.0.88", "11.0.0.88",
3132                                 "2001:10::88", "3001::88",
3133                                 ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
3134                                 self.pg2.local_ip4,
3135                                 self.pg2.remote_hosts[2].ip4,
3136                                 mac=None)
3137         rep_88.add_vpp_config()
3138
3139         #
3140         # Add a remote endpoint from the API that matches an existing one
3141         # this is a lower priority, hence the packet is sent to the DP leanrt
3142         # TEP
3143         #
3144         rep_2 = VppGbpEndpoint(self, vx_tun_l3,
3145                                epg_220, None,
3146                                learnt[0]['ip'], "11.0.0.101",
3147                                learnt[0]['ip6'], "3001::101",
3148                                ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
3149                                self.pg2.local_ip4,
3150                                self.pg2.remote_hosts[1].ip4,
3151                                mac=None)
3152         rep_2.add_vpp_config()
3153
3154         #
3155         # Add a route to the learned EP's v4 subnet
3156         #  packets should be send on the v4/v6 uu=fwd interface resp.
3157         #
3158         se_10_1_24 = VppGbpSubnet(
3159             self, rd1, "10.0.1.0", 24,
3160             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_TRANSPORT)
3161         se_10_1_24.add_vpp_config()
3162
3163         self.logger.info(self.vapi.cli("show gbp endpoint"))
3164
3165         ips = ["10.0.0.88", learnt[0]['ip']]
3166         for ip in ips:
3167             p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
3168                  IP(dst=ip, src=ep.ip4) /
3169                  UDP(sport=1234, dport=1234) /
3170                  Raw(b'\xa5' * 100))
3171
3172             rxs = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg2)
3173
3174             for rx in rxs:
3175                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
3176                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[2].ip4)
3177                 self.assertEqual(rx[UDP].dport, 48879)
3178                 # the UDP source port is a random value for hashing
3179                 self.assertEqual(rx[VXLAN].gpid, 441)
3180                 self.assertEqual(rx[VXLAN].vni, 101)
3181                 self.assertTrue(rx[VXLAN].flags.G)
3182                 self.assertTrue(rx[VXLAN].flags.Instance)
3183                 self.assertTrue(rx[VXLAN].gpflags.A)
3184                 self.assertFalse(rx[VXLAN].gpflags.D)
3185
3186                 inner = rx[VXLAN].payload
3187
3188                 self.assertEqual(inner[Ether].src, routed_src_mac)
3189                 self.assertEqual(inner[Ether].dst, routed_dst_mac)
3190                 self.assertEqual(inner[IP].src, ep.ip4)
3191                 self.assertEqual(inner[IP].dst, ip)
3192
3193         #
3194         # remove the API remote EPs, only API sourced is gone, the DP
3195         # learnt one remains
3196         #
3197         rep_88.remove_vpp_config()
3198         rep_2.remove_vpp_config()
3199
3200         self.assertTrue(find_gbp_endpoint(self, ip=rep_2.ip4))
3201
3202         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
3203              IP(src=ep.ip4, dst=rep_2.ip4) /
3204              UDP(sport=1234, dport=1234) /
3205              Raw(b'\xa5' * 100))
3206         rxs = self.send_and_expect(self.pg0, [p], self.pg2)
3207
3208         self.assertFalse(find_gbp_endpoint(self, ip=rep_88.ip4))
3209
3210         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
3211              IP(src=ep.ip4, dst=rep_88.ip4) /
3212              UDP(sport=1234, dport=1234) /
3213              Raw(b'\xa5' * 100))
3214         rxs = self.send_and_expect(self.pg0, [p], self.pg4)
3215
3216         #
3217         # to appease the testcase we cannot have the registered EP still
3218         # present (because it's DP learnt) when the TC ends so wait until
3219         # it is removed
3220         #
3221         self.wait_for_ep_timeout(ip=rep_88.ip4)
3222         self.wait_for_ep_timeout(ip=rep_2.ip4)
3223
3224         #
3225         # Same as above, learn a remote EP via CP and DP
3226         # this time remove the DP one first. expect the CP data to remain
3227         #
3228         rep_3 = VppGbpEndpoint(self, vx_tun_l3,
3229                                epg_220, None,
3230                                "10.0.1.4", "11.0.0.103",
3231                                "2001::10:3", "3001::103",
3232                                ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
3233                                self.pg2.local_ip4,
3234                                self.pg2.remote_hosts[1].ip4,
3235                                mac=None)
3236         rep_3.add_vpp_config()
3237
3238         p = (Ether(src=self.pg2.remote_mac,
3239                    dst=self.pg2.local_mac) /
3240              IP(src=self.pg2.remote_hosts[2].ip4,
3241                 dst=self.pg2.local_ip4) /
3242              UDP(sport=1234, dport=48879) /
3243              VXLAN(vni=101, gpid=441, flags=0x88) /
3244              Ether(src=l['mac'], dst="00:00:00:11:11:11") /
3245              IP(src="10.0.1.4", dst=ep.ip4) /
3246              UDP(sport=1234, dport=1234) /
3247              Raw(b'\xa5' * 100))
3248         rxs = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
3249
3250         self.assertTrue(find_gbp_endpoint(self,
3251                                           vx_tun_l3._sw_if_index,
3252                                           ip=rep_3.ip4,
3253                                           tep=[self.pg2.local_ip4,
3254                                                self.pg2.remote_hosts[2].ip4]))
3255
3256         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
3257              IP(dst="10.0.1.4", src=ep.ip4) /
3258              UDP(sport=1234, dport=1234) /
3259              Raw(b'\xa5' * 100))
3260         rxs = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg2)
3261
3262         # host 2 is the DP learned TEP
3263         for rx in rxs:
3264             self.assertEqual(rx[IP].src, self.pg2.local_ip4)
3265             self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[2].ip4)
3266
3267         self.wait_for_ep_timeout(ip=rep_3.ip4,
3268                                  tep=[self.pg2.local_ip4,
3269                                       self.pg2.remote_hosts[2].ip4])
3270
3271         rxs = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg2)
3272
3273         # host 1 is the CP learned TEP
3274         for rx in rxs:
3275             self.assertEqual(rx[IP].src, self.pg2.local_ip4)
3276             self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
3277
3278         #
3279         # shutdown with learnt endpoint present
3280         #
3281         p = (Ether(src=self.pg2.remote_mac,
3282                    dst=self.pg2.local_mac) /
3283              IP(src=self.pg2.remote_hosts[1].ip4,
3284                 dst=self.pg2.local_ip4) /
3285              UDP(sport=1234, dport=48879) /
3286              VXLAN(vni=101, gpid=441, flags=0x88) /
3287              Ether(src=l['mac'], dst="00:00:00:11:11:11") /
3288              IP(src=learnt[1]['ip'], dst=ep.ip4) /
3289              UDP(sport=1234, dport=1234) /
3290              Raw(b'\xa5' * 100))
3291
3292         rx = self.send_and_expect(self.pg2, [p], self.pg0)
3293
3294         # endpoint learnt via the parent GBP-vxlan interface
3295         self.assertTrue(find_gbp_endpoint(self,
3296                                           vx_tun_l3._sw_if_index,
3297                                           ip=l['ip']))
3298
3299         #
3300         # TODO
3301         # remote endpoint becomes local
3302         #
3303         self.pg2.unconfig_ip4()
3304         self.pg3.unconfig_ip4()
3305         self.pg4.unconfig_ip4()
3306
3307     def test_gbp_redirect(self):
3308         """ GBP Endpoint Redirect """
3309
3310         self.vapi.cli("set logging class gbp level debug")
3311
3312         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
3313         routed_dst_mac = "00:0c:0c:0c:0c:0c"
3314         routed_src_mac = "00:22:bd:f8:19:ff"
3315
3316         learnt = [{'mac': '00:00:11:11:11:02',
3317                    'ip': '10.0.1.2',
3318                    'ip6': '2001:10::2'},
3319                   {'mac': '00:00:11:11:11:03',
3320                    'ip': '10.0.1.3',
3321                    'ip6': '2001:10::3'}]
3322
3323         #
3324         # IP tables
3325         #
3326         t4 = VppIpTable(self, 1)
3327         t4.add_vpp_config()
3328         t6 = VppIpTable(self, 1, True)
3329         t6.add_vpp_config()
3330
3331         rd1 = VppGbpRouteDomain(self, 2, 402, t4, t6)
3332         rd1.add_vpp_config()
3333
3334         self.loop0.set_mac(self.router_mac)
3335
3336         #
3337         # Bind the BVI to the RD
3338         #
3339         b_ip4 = VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
3340         b_ip6 = VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
3341
3342         #
3343         # Pg7 hosts a BD's UU-fwd
3344         #
3345         self.pg7.config_ip4()
3346         self.pg7.resolve_arp()
3347
3348         #
3349         # a GBP bridge domains for the EPs
3350         #
3351         bd1 = VppBridgeDomain(self, 1)
3352         bd1.add_vpp_config()
3353         gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0)
3354         gbd1.add_vpp_config()
3355
3356         bd2 = VppBridgeDomain(self, 2)
3357         bd2.add_vpp_config()
3358         gbd2 = VppGbpBridgeDomain(self, bd2, rd1, self.loop1)
3359         gbd2.add_vpp_config()
3360
3361         # ... and has a /32 and /128 applied
3362         ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi,
3363                                          "10.0.0.128", 32,
3364                                          bind=b_ip4).add_vpp_config()
3365         ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi,
3366                                          "2001:10::128", 128,
3367                                          bind=b_ip6).add_vpp_config()
3368         ip4_addr = VppIpInterfaceAddress(self, gbd2.bvi,
3369                                          "10.0.1.128", 32).add_vpp_config()
3370         ip6_addr = VppIpInterfaceAddress(self, gbd2.bvi,
3371                                          "2001:11::128", 128).add_vpp_config()
3372
3373         #
3374         # The Endpoint-groups in which we are learning endpoints
3375         #
3376         epg_220 = VppGbpEndpointGroup(self, 220, 440, rd1, gbd1,
3377                                       None, gbd1.bvi,
3378                                       "10.0.0.128",
3379                                       "2001:10::128",
3380                                       VppGbpEndpointRetention(60))
3381         epg_220.add_vpp_config()
3382         epg_221 = VppGbpEndpointGroup(self, 221, 441, rd1, gbd2,
3383                                       None, gbd2.bvi,
3384                                       "10.0.1.128",
3385                                       "2001:11::128",
3386                                       VppGbpEndpointRetention(60))
3387         epg_221.add_vpp_config()
3388         epg_222 = VppGbpEndpointGroup(self, 222, 442, rd1, gbd1,
3389                                       None, gbd1.bvi,
3390                                       "10.0.2.128",
3391                                       "2001:12::128",
3392                                       VppGbpEndpointRetention(60))
3393         epg_222.add_vpp_config()
3394
3395         #
3396         # a GBP bridge domains for the SEPs
3397         #
3398         bd_uu1 = VppVxlanGbpTunnel(self, self.pg7.local_ip4,
3399                                    self.pg7.remote_ip4, 116)
3400         bd_uu1.add_vpp_config()
3401         bd_uu2 = VppVxlanGbpTunnel(self, self.pg7.local_ip4,
3402                                    self.pg7.remote_ip4, 117)
3403         bd_uu2.add_vpp_config()
3404
3405         bd3 = VppBridgeDomain(self, 3)
3406         bd3.add_vpp_config()
3407         gbd3 = VppGbpBridgeDomain(self, bd3, rd1, self.loop2,
3408                                   bd_uu1, learn=False)
3409         gbd3.add_vpp_config()
3410         bd4 = VppBridgeDomain(self, 4)
3411         bd4.add_vpp_config()
3412         gbd4 = VppGbpBridgeDomain(self, bd4, rd1, self.loop3,
3413                                   bd_uu2, learn=False)
3414         gbd4.add_vpp_config()
3415
3416         #
3417         # EPGs in which the service endpoints exist
3418         #
3419         epg_320 = VppGbpEndpointGroup(self, 320, 550, rd1, gbd3,
3420                                       None, gbd1.bvi,
3421                                       "12.0.0.128",
3422                                       "4001:10::128",
3423                                       VppGbpEndpointRetention(60))
3424         epg_320.add_vpp_config()
3425         epg_321 = VppGbpEndpointGroup(self, 321, 551, rd1, gbd4,
3426                                       None, gbd2.bvi,
3427                                       "12.0.1.128",
3428                                       "4001:11::128",
3429                                       VppGbpEndpointRetention(60))
3430         epg_321.add_vpp_config()
3431
3432         #
3433         # three local endpoints
3434         #
3435         ep1 = VppGbpEndpoint(self, self.pg0,
3436                              epg_220, None,
3437                              "10.0.0.1", "11.0.0.1",
3438                              "2001:10::1", "3001:10::1")
3439         ep1.add_vpp_config()
3440         ep2 = VppGbpEndpoint(self, self.pg1,
3441                              epg_221, None,
3442                              "10.0.1.1", "11.0.1.1",
3443                              "2001:11::1", "3001:11::1")
3444         ep2.add_vpp_config()
3445         ep3 = VppGbpEndpoint(self, self.pg2,
3446                              epg_222, None,
3447                              "10.0.2.2", "11.0.2.2",
3448                              "2001:12::1", "3001:12::1")
3449         ep3.add_vpp_config()
3450
3451         #
3452         # service endpoints
3453         #
3454         sep1 = VppGbpEndpoint(self, self.pg3,
3455                               epg_320, None,
3456                               "12.0.0.1", "13.0.0.1",
3457                               "4001:10::1", "5001:10::1")
3458         sep1.add_vpp_config()
3459         sep2 = VppGbpEndpoint(self, self.pg4,
3460                               epg_320, None,
3461                               "12.0.0.2", "13.0.0.2",
3462                               "4001:10::2", "5001:10::2")
3463         sep2.add_vpp_config()
3464         sep3 = VppGbpEndpoint(self, self.pg5,
3465                               epg_321, None,
3466                               "12.0.1.1", "13.0.1.1",
3467                               "4001:11::1", "5001:11::1")
3468         sep3.add_vpp_config()
3469         # this EP is not installed immediately
3470         sep4 = VppGbpEndpoint(self, self.pg6,
3471                               epg_321, None,
3472                               "12.0.1.2", "13.0.1.2",
3473                               "4001:11::2", "5001:11::2")
3474
3475         #
3476         # an L2 switch packet between local EPs in different EPGs
3477         #  different dest ports on each so the are LB hashed differently
3478         #
3479         p4 = [(Ether(src=ep1.mac, dst=ep3.mac) /
3480                IP(src=ep1.ip4, dst=ep3.ip4) /
3481                UDP(sport=1234, dport=1234) /
3482                Raw(b'\xa5' * 100)),
3483               (Ether(src=ep3.mac, dst=ep1.mac) /
3484                IP(src=ep3.ip4, dst=ep1.ip4) /
3485                UDP(sport=1234, dport=1234) /
3486                Raw(b'\xa5' * 100))]
3487         p6 = [(Ether(src=ep1.mac, dst=ep3.mac) /
3488                IPv6(src=ep1.ip6, dst=ep3.ip6) /
3489                UDP(sport=1234, dport=1234) /
3490                Raw(b'\xa5' * 100)),
3491               (Ether(src=ep3.mac, dst=ep1.mac) /
3492                IPv6(src=ep3.ip6, dst=ep1.ip6) /
3493                UDP(sport=1234, dport=1230) /
3494                Raw(b'\xa5' * 100))]
3495
3496         # should be dropped since no contract yet
3497         self.send_and_assert_no_replies(self.pg0, [p4[0]])
3498         self.send_and_assert_no_replies(self.pg0, [p6[0]])
3499
3500         #
3501         # Add a contract with a rule to load-balance redirect via SEP1 and SEP2
3502         # one of the next-hops is via an EP that is not known
3503         #
3504         rule4 = AclRule(is_permit=1, proto=17)
3505         rule6 = AclRule(src_prefix=IPv6Network((0, 0)),
3506                         dst_prefix=IPv6Network((0, 0)), is_permit=1, proto=17)
3507         acl = VppAcl(self, rules=[rule4, rule6])
3508         acl.add_vpp_config()
3509
3510         #
3511         # test the src-ip hash mode
3512         #
3513         c1 = VppGbpContract(
3514             self, 402, epg_220.sclass, epg_222.sclass, acl.acl_index,
3515             [VppGbpContractRule(
3516                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3517                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3518                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3519                                        sep1.ip4, sep1.epg.rd),
3520                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3521                                        sep2.ip4, sep2.epg.rd)]),
3522                 VppGbpContractRule(
3523                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3524                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3525                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3526                                            sep3.ip6, sep3.epg.rd),
3527                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3528                                            sep4.ip6, sep4.epg.rd)])],
3529             [ETH_P_IP, ETH_P_IPV6])
3530         c1.add_vpp_config()
3531
3532         c2 = VppGbpContract(
3533             self, 402, epg_222.sclass, epg_220.sclass, acl.acl_index,
3534             [VppGbpContractRule(
3535                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3536                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3537                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3538                                        sep1.ip4, sep1.epg.rd),
3539                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3540                                        sep2.ip4, sep2.epg.rd)]),
3541                 VppGbpContractRule(
3542                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3543                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3544                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3545                                            sep3.ip6, sep3.epg.rd),
3546                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3547                                            sep4.ip6, sep4.epg.rd)])],
3548             [ETH_P_IP, ETH_P_IPV6])
3549         c2.add_vpp_config()
3550
3551         #
3552         # send again with the contract preset, now packets arrive
3553         # at SEP1 or SEP2 depending on the hashing
3554         #
3555         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
3556
3557         for rx in rxs:
3558             self.assertEqual(rx[Ether].src, routed_src_mac)
3559             self.assertEqual(rx[Ether].dst, sep1.mac)
3560             self.assertEqual(rx[IP].src, ep1.ip4)
3561             self.assertEqual(rx[IP].dst, ep3.ip4)
3562
3563         rxs = self.send_and_expect(self.pg2, p4[1] * 17, sep2.itf)
3564
3565         for rx in rxs:
3566             self.assertEqual(rx[Ether].src, routed_src_mac)
3567             self.assertEqual(rx[Ether].dst, sep2.mac)
3568             self.assertEqual(rx[IP].src, ep3.ip4)
3569             self.assertEqual(rx[IP].dst, ep1.ip4)
3570
3571         rxs = self.send_and_expect(self.pg0, p6[0] * 17, self.pg7)
3572
3573         for rx in rxs:
3574             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
3575             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
3576             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
3577             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
3578             self.assertEqual(rx[VXLAN].vni, 117)
3579             self.assertTrue(rx[VXLAN].flags.G)
3580             self.assertTrue(rx[VXLAN].flags.Instance)
3581             # redirect policy has been applied
3582             self.assertTrue(rx[VXLAN].gpflags.A)
3583             self.assertFalse(rx[VXLAN].gpflags.D)
3584
3585             inner = rx[VXLAN].payload
3586
3587             self.assertEqual(inner[Ether].src, routed_src_mac)
3588             self.assertEqual(inner[Ether].dst, sep4.mac)
3589             self.assertEqual(inner[IPv6].src, ep1.ip6)
3590             self.assertEqual(inner[IPv6].dst, ep3.ip6)
3591
3592         rxs = self.send_and_expect(self.pg2, p6[1] * 17, sep3.itf)
3593
3594         for rx in rxs:
3595             self.assertEqual(rx[Ether].src, routed_src_mac)
3596             self.assertEqual(rx[Ether].dst, sep3.mac)
3597             self.assertEqual(rx[IPv6].src, ep3.ip6)
3598             self.assertEqual(rx[IPv6].dst, ep1.ip6)
3599
3600         #
3601         # programme the unknown EP
3602         #
3603         sep4.add_vpp_config()
3604
3605         rxs = self.send_and_expect(self.pg0, p6[0] * 17, sep4.itf)
3606
3607         for rx in rxs:
3608             self.assertEqual(rx[Ether].src, routed_src_mac)
3609             self.assertEqual(rx[Ether].dst, sep4.mac)
3610             self.assertEqual(rx[IPv6].src, ep1.ip6)
3611             self.assertEqual(rx[IPv6].dst, ep3.ip6)
3612
3613         #
3614         # and revert back to unprogrammed
3615         #
3616         sep4.remove_vpp_config()
3617
3618         rxs = self.send_and_expect(self.pg0, p6[0] * 17, self.pg7)
3619
3620         for rx in rxs:
3621             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
3622             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
3623             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
3624             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
3625             self.assertEqual(rx[VXLAN].vni, 117)
3626             self.assertTrue(rx[VXLAN].flags.G)
3627             self.assertTrue(rx[VXLAN].flags.Instance)
3628             # redirect policy has been applied
3629             self.assertTrue(rx[VXLAN].gpflags.A)
3630             self.assertFalse(rx[VXLAN].gpflags.D)
3631
3632             inner = rx[VXLAN].payload
3633
3634             self.assertEqual(inner[Ether].src, routed_src_mac)
3635             self.assertEqual(inner[Ether].dst, sep4.mac)
3636             self.assertEqual(inner[IPv6].src, ep1.ip6)
3637             self.assertEqual(inner[IPv6].dst, ep3.ip6)
3638
3639         c1.remove_vpp_config()
3640         c2.remove_vpp_config()
3641
3642         #
3643         # test the symmetric hash mode
3644         #
3645         c1 = VppGbpContract(
3646             self, 402, epg_220.sclass, epg_222.sclass, acl.acl_index,
3647             [VppGbpContractRule(
3648                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3649                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3650                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3651                                        sep1.ip4, sep1.epg.rd),
3652                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3653                                        sep2.ip4, sep2.epg.rd)]),
3654                 VppGbpContractRule(
3655                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3656                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3657                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3658                                            sep3.ip6, sep3.epg.rd),
3659                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3660                                            sep4.ip6, sep4.epg.rd)])],
3661             [ETH_P_IP, ETH_P_IPV6])
3662         c1.add_vpp_config()
3663
3664         c2 = VppGbpContract(
3665             self, 402, epg_222.sclass, epg_220.sclass, acl.acl_index,
3666             [VppGbpContractRule(
3667                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3668                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3669                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3670                                        sep1.ip4, sep1.epg.rd),
3671                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3672                                        sep2.ip4, sep2.epg.rd)]),
3673                 VppGbpContractRule(
3674                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3675                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3676                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3677                                            sep3.ip6, sep3.epg.rd),
3678                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3679                                            sep4.ip6, sep4.epg.rd)])],
3680             [ETH_P_IP, ETH_P_IPV6])
3681         c2.add_vpp_config()
3682
3683         #
3684         # send again with the contract preset, now packets arrive
3685         # at SEP1 for both directions
3686         #
3687         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
3688
3689         for rx in rxs:
3690             self.assertEqual(rx[Ether].src, routed_src_mac)
3691             self.assertEqual(rx[Ether].dst, sep1.mac)
3692             self.assertEqual(rx[IP].src, ep1.ip4)
3693             self.assertEqual(rx[IP].dst, ep3.ip4)
3694
3695         rxs = self.send_and_expect(self.pg2, p4[1] * 17, sep1.itf)
3696
3697         for rx in rxs:
3698             self.assertEqual(rx[Ether].src, routed_src_mac)
3699             self.assertEqual(rx[Ether].dst, sep1.mac)
3700             self.assertEqual(rx[IP].src, ep3.ip4)
3701             self.assertEqual(rx[IP].dst, ep1.ip4)
3702
3703         #
3704         # programme the unknown EP for the L3 tests
3705         #
3706         sep4.add_vpp_config()
3707
3708         #
3709         # an L3 switch packet between local EPs in different EPGs
3710         #  different dest ports on each so the are LB hashed differently
3711         #
3712         p4 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) /
3713                IP(src=ep1.ip4, dst=ep2.ip4) /
3714                UDP(sport=1234, dport=1234) /
3715                Raw(b'\xa5' * 100)),
3716               (Ether(src=ep2.mac, dst=str(self.router_mac)) /
3717                IP(src=ep2.ip4, dst=ep1.ip4) /
3718                UDP(sport=1234, dport=1234) /
3719                Raw(b'\xa5' * 100))]
3720         p6 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) /
3721                IPv6(src=ep1.ip6, dst=ep2.ip6) /
3722                UDP(sport=1234, dport=1234) /
3723                Raw(b'\xa5' * 100)),
3724               (Ether(src=ep2.mac, dst=str(self.router_mac)) /
3725                IPv6(src=ep2.ip6, dst=ep1.ip6) /
3726                UDP(sport=1234, dport=1234) /
3727                Raw(b'\xa5' * 100))]
3728
3729         c3 = VppGbpContract(
3730             self, 402, epg_220.sclass, epg_221.sclass, acl.acl_index,
3731             [VppGbpContractRule(
3732                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3733                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3734                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3735                                        sep1.ip4, sep1.epg.rd),
3736                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3737                                        sep2.ip4, sep2.epg.rd)]),
3738                 VppGbpContractRule(
3739                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3740                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3741                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3742                                            sep3.ip6, sep3.epg.rd),
3743                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3744                                            sep4.ip6, sep4.epg.rd)])],
3745             [ETH_P_IP, ETH_P_IPV6])
3746         c3.add_vpp_config()
3747
3748         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
3749
3750         for rx in rxs:
3751             self.assertEqual(rx[Ether].src, routed_src_mac)
3752             self.assertEqual(rx[Ether].dst, sep1.mac)
3753             self.assertEqual(rx[IP].src, ep1.ip4)
3754             self.assertEqual(rx[IP].dst, ep2.ip4)
3755
3756         #
3757         # learn a remote EP in EPG 221
3758         #   packets coming from unknown remote EPs will be leant & redirected
3759         #
3760         vx_tun_l3 = VppGbpVxlanTunnel(
3761             self, 444, rd1.rd_id,
3762             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3,
3763             self.pg2.local_ip4)
3764         vx_tun_l3.add_vpp_config()
3765
3766         c4 = VppGbpContract(
3767             self, 402, epg_221.sclass, epg_220.sclass, acl.acl_index,
3768             [VppGbpContractRule(
3769                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3770                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3771                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3772                                        sep1.ip4, sep1.epg.rd),
3773                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3774                                        sep2.ip4, sep2.epg.rd)]),
3775                 VppGbpContractRule(
3776                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3777                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3778                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3779                                            sep3.ip6, sep3.epg.rd),
3780                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3781                                            sep4.ip6, sep4.epg.rd)])],
3782             [ETH_P_IP, ETH_P_IPV6])
3783         c4.add_vpp_config()
3784
3785         p = (Ether(src=self.pg7.remote_mac,
3786                    dst=self.pg7.local_mac) /
3787              IP(src=self.pg7.remote_ip4,
3788                 dst=self.pg7.local_ip4) /
3789              UDP(sport=1234, dport=48879) /
3790              VXLAN(vni=444, gpid=441, flags=0x88) /
3791              Ether(src="00:22:22:22:22:33", dst=str(self.router_mac)) /
3792              IP(src="10.0.0.88", dst=ep1.ip4) /
3793              UDP(sport=1234, dport=1234) /
3794              Raw(b'\xa5' * 100))
3795
3796         # unknown remote EP to local EP redirected
3797         rxs = self.send_and_expect(self.pg7, [p], sep1.itf)
3798
3799         for rx in rxs:
3800             self.assertEqual(rx[Ether].src, routed_src_mac)
3801             self.assertEqual(rx[Ether].dst, sep1.mac)
3802             self.assertEqual(rx[IP].src, "10.0.0.88")
3803             self.assertEqual(rx[IP].dst, ep1.ip4)
3804
3805         # endpoint learnt via the parent GBP-vxlan interface
3806         self.assertTrue(find_gbp_endpoint(self,
3807                                           vx_tun_l3._sw_if_index,
3808                                           ip="10.0.0.88"))
3809
3810         p = (Ether(src=self.pg7.remote_mac,
3811                    dst=self.pg7.local_mac) /
3812              IP(src=self.pg7.remote_ip4,
3813                 dst=self.pg7.local_ip4) /
3814              UDP(sport=1234, dport=48879) /
3815              VXLAN(vni=444, gpid=441, flags=0x88) /
3816              Ether(src="00:22:22:22:22:33", dst=str(self.router_mac)) /
3817              IPv6(src="2001:10::88", dst=ep1.ip6) /
3818              UDP(sport=1234, dport=1234) /
3819              Raw(b'\xa5' * 100))
3820
3821         # unknown remote EP to local EP redirected (ipv6)
3822         rxs = self.send_and_expect(self.pg7, [p], sep3.itf)
3823
3824         for rx in rxs:
3825             self.assertEqual(rx[Ether].src, routed_src_mac)
3826             self.assertEqual(rx[Ether].dst, sep3.mac)
3827             self.assertEqual(rx[IPv6].src, "2001:10::88")
3828             self.assertEqual(rx[IPv6].dst, ep1.ip6)
3829
3830         # endpoint learnt via the parent GBP-vxlan interface
3831         self.assertTrue(find_gbp_endpoint(self,
3832                                           vx_tun_l3._sw_if_index,
3833                                           ip="2001:10::88"))
3834
3835         #
3836         # L3 switch from local to remote EP
3837         #
3838         p4 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) /
3839                IP(src=ep1.ip4, dst="10.0.0.88") /
3840                UDP(sport=1234, dport=1234) /
3841                Raw(b'\xa5' * 100))]
3842         p6 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) /
3843                IPv6(src=ep1.ip6, dst="2001:10::88") /
3844                UDP(sport=1234, dport=1234) /
3845                Raw(b'\xa5' * 100))]
3846
3847         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
3848
3849         for rx in rxs:
3850             self.assertEqual(rx[Ether].src, routed_src_mac)
3851             self.assertEqual(rx[Ether].dst, sep1.mac)
3852             self.assertEqual(rx[IP].src, ep1.ip4)
3853             self.assertEqual(rx[IP].dst, "10.0.0.88")
3854
3855         rxs = self.send_and_expect(self.pg0, p6[0] * 17, sep4.itf)
3856
3857         for rx in rxs:
3858             self.assertEqual(rx[Ether].src, routed_src_mac)
3859             self.assertEqual(rx[Ether].dst, sep4.mac)
3860             self.assertEqual(rx[IPv6].src, ep1.ip6)
3861             self.assertEqual(rx[IPv6].dst, "2001:10::88")
3862
3863         #
3864         # test the dst-ip hash mode
3865         #
3866         c5 = VppGbpContract(
3867             self, 402, epg_220.sclass, epg_221.sclass, acl.acl_index,
3868             [VppGbpContractRule(
3869                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3870                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
3871                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3872                                        sep1.ip4, sep1.epg.rd),
3873                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3874                                        sep2.ip4, sep2.epg.rd)]),
3875                 VppGbpContractRule(
3876                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3877                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
3878                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3879                                            sep3.ip6, sep3.epg.rd),
3880                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3881                                            sep4.ip6, sep4.epg.rd)])],
3882             [ETH_P_IP, ETH_P_IPV6])
3883         c5.add_vpp_config()
3884
3885         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
3886
3887         for rx in rxs:
3888             self.assertEqual(rx[Ether].src, routed_src_mac)
3889             self.assertEqual(rx[Ether].dst, sep1.mac)
3890             self.assertEqual(rx[IP].src, ep1.ip4)
3891             self.assertEqual(rx[IP].dst, "10.0.0.88")
3892
3893         rxs = self.send_and_expect(self.pg0, p6[0] * 17, sep3.itf)
3894
3895         for rx in rxs:
3896             self.assertEqual(rx[Ether].src, routed_src_mac)
3897             self.assertEqual(rx[Ether].dst, sep3.mac)
3898             self.assertEqual(rx[IPv6].src, ep1.ip6)
3899             self.assertEqual(rx[IPv6].dst, "2001:10::88")
3900
3901         #
3902         # a programmed remote SEP in EPG 320
3903         #
3904
3905         # gbp vxlan tunnel for the remote SEP
3906         vx_tun_l3_sep = VppGbpVxlanTunnel(
3907             self, 555, rd1.rd_id,
3908             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3,
3909             self.pg2.local_ip4)
3910         vx_tun_l3_sep.add_vpp_config()
3911
3912         # remote SEP
3913         sep5 = VppGbpEndpoint(self, vx_tun_l3_sep,
3914                               epg_320, None,
3915                               "12.0.0.10", "13.0.0.10",
3916                               "4001:10::10", "5001:10::10",
3917                               ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
3918                               self.pg7.local_ip4,
3919                               self.pg7.remote_ip4,
3920                               mac=None)
3921         sep5.add_vpp_config()
3922
3923         #
3924         # local l3out redirect tests
3925         #
3926
3927         # add local l3out
3928         # the external bd
3929         self.loop4.set_mac(self.router_mac)
3930         b_lo4_ip4 = VppIpInterfaceBind(self, self.loop4, t4).add_vpp_config()
3931         b_lo4_ip6 = VppIpInterfaceBind(self, self.loop4, t6).add_vpp_config()
3932         ebd = VppBridgeDomain(self, 100)
3933         ebd.add_vpp_config()
3934         gebd = VppGbpBridgeDomain(self, ebd, rd1, self.loop4, None, None)
3935         gebd.add_vpp_config()
3936         # the external epg
3937         eepg = VppGbpEndpointGroup(self, 888, 765, rd1, gebd,
3938                                    None, gebd.bvi,
3939                                    "10.1.0.128",
3940                                    "2001:10:1::128",
3941                                    VppGbpEndpointRetention(60))
3942         eepg.add_vpp_config()
3943         # add subnets to BVI
3944         VppIpInterfaceAddress(
3945             self,
3946             gebd.bvi,
3947             "10.1.0.128",
3948             24, bind=b_lo4_ip4).add_vpp_config()
3949         VppIpInterfaceAddress(
3950             self,
3951             gebd.bvi,
3952             "2001:10:1::128",
3953             64, bind=b_lo4_ip6).add_vpp_config()
3954         # ... which are L3-out subnets
3955         VppGbpSubnet(self, rd1, "10.1.0.0", 24,
3956                      VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3957                      sclass=765).add_vpp_config()
3958         VppGbpSubnet(self, rd1, "2001:10:1::128", 64,
3959                      VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3960                      sclass=765).add_vpp_config()
3961         # external endpoints
3962         VppL2Vtr(self, self.vlan_100, L2_VTR_OP.L2_POP_1).add_vpp_config()
3963         eep1 = VppGbpEndpoint(self, self.vlan_100, eepg, None, "10.1.0.1",
3964                               "11.1.0.1", "2001:10:1::1", "3001:10:1::1",
3965                               ep_flags.GBP_API_ENDPOINT_FLAG_EXTERNAL)
3966         eep1.add_vpp_config()
3967         VppL2Vtr(self, self.vlan_101, L2_VTR_OP.L2_POP_1).add_vpp_config()
3968         eep2 = VppGbpEndpoint(self, self.vlan_101, eepg, None, "10.1.0.2",
3969                               "11.1.0.2", "2001:10:1::2", "3001:10:1::2",
3970                               ep_flags.GBP_API_ENDPOINT_FLAG_EXTERNAL)
3971         eep2.add_vpp_config()
3972
3973         # external subnets reachable though eep1 and eep2 respectively
3974         VppIpRoute(self, "10.220.0.0", 24,
3975                    [VppRoutePath(eep1.ip4, eep1.epg.bvi.sw_if_index)],
3976                    table_id=t4.table_id).add_vpp_config()
3977         VppGbpSubnet(self, rd1, "10.220.0.0", 24,
3978                      VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3979                      sclass=4220).add_vpp_config()
3980         VppIpRoute(self, "10:220::", 64,
3981                    [VppRoutePath(eep1.ip6, eep1.epg.bvi.sw_if_index)],
3982                    table_id=t6.table_id).add_vpp_config()
3983         VppGbpSubnet(self, rd1, "10:220::", 64,
3984                      VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3985                      sclass=4220).add_vpp_config()
3986         VppIpRoute(self, "10.221.0.0", 24,
3987                    [VppRoutePath(eep2.ip4, eep2.epg.bvi.sw_if_index)],
3988                    table_id=t4.table_id).add_vpp_config()
3989         VppGbpSubnet(self, rd1, "10.221.0.0", 24,
3990                      VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3991                      sclass=4221).add_vpp_config()
3992         VppIpRoute(self, "10:221::", 64,
3993                    [VppRoutePath(eep2.ip6, eep2.epg.bvi.sw_if_index)],
3994                    table_id=t6.table_id).add_vpp_config()
3995         VppGbpSubnet(self, rd1, "10:221::", 64,
3996                      VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3997                      sclass=4221).add_vpp_config()
3998
3999         #
4000         # l3out redirect to remote (known, then unknown) SEP
4001         #
4002
4003         # packets from 1 external subnet to the other
4004         p = [(Ether(src=eep1.mac, dst=self.router_mac) /
4005               Dot1Q(vlan=100) /
4006               IP(src="10.220.0.17", dst="10.221.0.65") /
4007               UDP(sport=1234, dport=1234) /
4008               Raw(b'\xa5' * 100)),
4009              (Ether(src=eep1.mac, dst=self.router_mac) /
4010               Dot1Q(vlan=100) /
4011               IPv6(src="10:220::17", dst="10:221::65") /
4012               UDP(sport=1234, dport=1234) /
4013               Raw(b'\xa5' * 100))]
4014
4015         # packets should be dropped in absence of contract
4016         self.send_and_assert_no_replies(self.pg0, p)
4017
4018         # contract redirecting to sep5
4019         VppGbpContract(
4020             self, 402, 4220, 4221, acl.acl_index,
4021             [VppGbpContractRule(
4022                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
4023                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
4024                 [VppGbpContractNextHop(sep5.vmac, sep5.epg.bd,
4025                                        sep5.ip4, sep5.epg.rd)]),
4026                 VppGbpContractRule(
4027                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
4028                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
4029                     [VppGbpContractNextHop(sep5.vmac, sep5.epg.bd,
4030                                            sep5.ip6, sep5.epg.rd)])],
4031             [ETH_P_IP, ETH_P_IPV6]).add_vpp_config()
4032
4033         rxs = self.send_and_expect(self.pg0, p, self.pg7)
4034
4035         for rx, tx in zip(rxs, p):
4036             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
4037             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
4038             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
4039             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
4040             # this should use the programmed remote leaf TEP
4041             self.assertEqual(rx[VXLAN].vni, 555)
4042             self.assertEqual(rx[VXLAN].gpid, 4220)
4043             self.assertTrue(rx[VXLAN].flags.G)
4044             self.assertTrue(rx[VXLAN].flags.Instance)
4045             # redirect policy has been applied
4046             self.assertTrue(rx[VXLAN].gpflags.A)
4047             self.assertTrue(rx[VXLAN].gpflags.D)
4048             rxip = rx[VXLAN][Ether].payload
4049             txip = tx[Dot1Q].payload
4050             self.assertEqual(rxip.src, txip.src)
4051             self.assertEqual(rxip.dst, txip.dst)
4052
4053         # remote SEP: it is now an unknown remote SEP and should go
4054         # to spine proxy
4055         sep5.remove_vpp_config()
4056
4057         rxs = self.send_and_expect(self.pg0, p, self.pg7)
4058
4059         for rx, tx in zip(rxs, p):
4060             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
4061             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
4062             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
4063             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
4064             # this should use the spine proxy TEP
4065             self.assertEqual(rx[VXLAN].vni, epg_320.bd.uu_fwd.vni)
4066             self.assertEqual(rx[VXLAN].gpid, 4220)
4067             self.assertTrue(rx[VXLAN].flags.G)
4068             self.assertTrue(rx[VXLAN].flags.Instance)
4069             # redirect policy has been applied
4070             self.assertTrue(rx[VXLAN].gpflags.A)
4071             self.assertTrue(rx[VXLAN].gpflags.D)
4072             rxip = rx[VXLAN][Ether].payload
4073             txip = tx[Dot1Q].payload
4074             self.assertEqual(rxip.src, txip.src)
4075             self.assertEqual(rxip.dst, txip.dst)
4076
4077         #
4078         # l3out redirect to local SEP
4079         #
4080
4081         # change the contract between l3out to redirect to local SEPs
4082         # instead of remote SEP
4083         VppGbpContract(
4084             self, 402, 4220, 4221, acl.acl_index,
4085             [VppGbpContractRule(
4086                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
4087                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
4088                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
4089                                        sep1.ip4, sep1.epg.rd)]),
4090                 VppGbpContractRule(
4091                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
4092                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
4093                     [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
4094                                            sep1.ip6, sep1.epg.rd)])],
4095             [ETH_P_IP, ETH_P_IPV6]).add_vpp_config()
4096
4097         rxs = self.send_and_expect(self.pg0, p, sep1.itf)
4098         for rx, tx in zip(rxs, p):
4099             self.assertEqual(rx[Ether].src, routed_src_mac)
4100             self.assertEqual(rx[Ether].dst, sep1.mac)
4101             rxip = rx[Ether].payload
4102             txip = tx[Ether].payload
4103             self.assertEqual(rxip.src, txip.src)
4104             self.assertEqual(rxip.dst, txip.dst)
4105
4106         #
4107         # redirect remote EP to remote (known then unknown) SEP
4108         #
4109
4110         # remote SEP known again
4111         sep5.add_vpp_config()
4112
4113         # contract to redirect to learnt SEP
4114         VppGbpContract(
4115             self, 402, epg_221.sclass, epg_222.sclass, acl.acl_index,
4116             [VppGbpContractRule(
4117                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
4118                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
4119                 [VppGbpContractNextHop(sep5.vmac, sep5.epg.bd,
4120                                        sep5.ip4, sep5.epg.rd)]),
4121                 VppGbpContractRule(
4122                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
4123                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
4124                     [VppGbpContractNextHop(sep5.vmac, sep5.epg.bd,
4125                                            sep5.ip6, sep5.epg.rd)])],
4126             [ETH_P_IP, ETH_P_IPV6]).add_vpp_config()
4127
4128         # packets from unknown EP 221 to known EP in EPG 222
4129         # should be redirected to known remote SEP
4130         base = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) /
4131                 IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) /
4132                 UDP(sport=1234, dport=48879) /
4133                 VXLAN(vni=444, gpid=441, flags=0x88) /
4134                 Ether(src="00:22:22:22:22:44", dst=str(self.router_mac)))
4135         p = [(base /
4136               IP(src="10.0.1.100", dst=ep3.ip4) /
4137               UDP(sport=1234, dport=1234) /
4138               Raw(b'\xa5' * 100)),
4139              (base /
4140               IPv6(src="2001:10::100", dst=ep3.ip6) /
4141               UDP(sport=1234, dport=1234) /
4142               Raw(b'\xa5' * 100))]
4143
4144         # unknown remote EP to local EP redirected to known remote SEP
4145         rxs = self.send_and_expect(self.pg7, p, self.pg7)
4146
4147         for rx, tx in zip(rxs, p):
4148             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
4149             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
4150             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
4151             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
4152             # this should use the programmed remote leaf TEP
4153             self.assertEqual(rx[VXLAN].vni, 555)
4154             self.assertEqual(rx[VXLAN].gpid, epg_221.sclass)
4155             self.assertTrue(rx[VXLAN].flags.G)
4156             self.assertTrue(rx[VXLAN].flags.Instance)
4157             # redirect policy has been applied
4158             self.assertTrue(rx[VXLAN].gpflags.A)
4159             self.assertFalse(rx[VXLAN].gpflags.D)
4160             rxip = rx[VXLAN][Ether].payload
4161             txip = tx[VXLAN][Ether].payload
4162             self.assertEqual(rxip.src, txip.src)
4163             self.assertEqual(rxip.dst, txip.dst)
4164
4165         # endpoint learnt via the parent GBP-vxlan interface
4166         self.assertTrue(find_gbp_endpoint(self,
4167                                           vx_tun_l3._sw_if_index,
4168                                           ip="10.0.1.100"))
4169         self.assertTrue(find_gbp_endpoint(self,
4170                                           vx_tun_l3._sw_if_index,
4171                                           ip="2001:10::100"))
4172
4173         # remote SEP: it is now an unknown remote SEP and should go
4174         # to spine proxy
4175         sep5.remove_vpp_config()
4176
4177         # remote EP (coming from spine proxy) to local EP redirected to
4178         # known remote SEP
4179         rxs = self.send_and_expect(self.pg7, p, self.pg7)
4180
4181         for rx, tx in zip(rxs, p):
4182             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
4183             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
4184             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
4185             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
4186             # this should use the spine proxy TEP
4187             self.assertEqual(rx[VXLAN].vni, epg_320.bd.uu_fwd.vni)
4188             self.assertEqual(rx[VXLAN].gpid, epg_221.sclass)
4189             self.assertTrue(rx[VXLAN].flags.G)
4190             self.assertTrue(rx[VXLAN].flags.Instance)
4191             # redirect policy has been applied
4192             self.assertTrue(rx[VXLAN].gpflags.A)
4193             self.assertFalse(rx[VXLAN].gpflags.D)
4194             rxip = rx[VXLAN][Ether].payload
4195             txip = tx[VXLAN][Ether].payload
4196             self.assertEqual(rxip.src, txip.src)
4197             self.assertEqual(rxip.dst, txip.dst)
4198
4199         #
4200         # cleanup
4201         #
4202         self.pg7.unconfig_ip4()
4203
4204     def test_gbp_redirect_extended(self):
4205         """ GBP Endpoint Redirect Extended """
4206
4207         self.vapi.cli("set logging class gbp level debug")
4208
4209         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
4210         routed_dst_mac = "00:0c:0c:0c:0c:0c"
4211         routed_src_mac = "00:22:bd:f8:19:ff"
4212
4213         learnt = [{'mac': '00:00:11:11:11:02',
4214                    'ip': '10.0.1.2',
4215                    'ip6': '2001:10::2'},
4216                   {'mac': '00:00:11:11:11:03',
4217                    'ip': '10.0.1.3',
4218                    'ip6': '2001:10::3'}]
4219
4220         #
4221         # IP tables
4222         #
4223         t4 = VppIpTable(self, 1)
4224         t4.add_vpp_config()
4225         t6 = VppIpTable(self, 1, True)
4226         t6.add_vpp_config()
4227
4228         # create IPv4 and IPv6 RD UU VxLAN-GBP TEP and bind them to the right
4229         # VRF
4230         rd_uu4 = VppVxlanGbpTunnel(
4231             self,
4232             self.pg7.local_ip4,
4233             self.pg7.remote_ip4,
4234             114,
4235             mode=(VppEnum.vl_api_vxlan_gbp_api_tunnel_mode_t.
4236                   VXLAN_GBP_API_TUNNEL_MODE_L3))
4237         rd_uu4.add_vpp_config()
4238         VppIpInterfaceBind(self, rd_uu4, t4).add_vpp_config()
4239
4240         rd_uu6 = VppVxlanGbpTunnel(
4241             self,
4242             self.pg7.local_ip4,
4243             self.pg7.remote_ip4,
4244             115,
4245             mode=(VppEnum.vl_api_vxlan_gbp_api_tunnel_mode_t.
4246                   VXLAN_GBP_API_TUNNEL_MODE_L3))
4247         rd_uu6.add_vpp_config()
4248         VppIpInterfaceBind(self, rd_uu6, t4).add_vpp_config()
4249
4250         rd1 = VppGbpRouteDomain(self, 2, 402, t4, t6, rd_uu4, rd_uu6)
4251         rd1.add_vpp_config()
4252
4253         self.loop0.set_mac(self.router_mac)
4254         self.loop1.set_mac(self.router_mac)
4255         self.loop2.set_mac(self.router_mac)
4256
4257         #
4258         # Bind the BVI to the RD
4259         #
4260         b_lo0_ip4 = VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
4261         b_lo0_ip6 = VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
4262         b_lo1_ip4 = VppIpInterfaceBind(self, self.loop1, t4).add_vpp_config()
4263         b_lo1_ip6 = VppIpInterfaceBind(self, self.loop1, t6).add_vpp_config()
4264         b_lo2_ip4 = VppIpInterfaceBind(self, self.loop2, t4).add_vpp_config()
4265         b_lo2_ip6 = VppIpInterfaceBind(self, self.loop2, t6).add_vpp_config()
4266
4267         #
4268         # Pg7 hosts a BD's UU-fwd
4269         #
4270         self.pg7.config_ip4()
4271         self.pg7.resolve_arp()
4272
4273         #
4274         # a GBP bridge domains for the EPs
4275         #
4276         bd1 = VppBridgeDomain(self, 1)
4277         bd1.add_vpp_config()
4278         gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0)
4279         gbd1.add_vpp_config()
4280
4281         bd2 = VppBridgeDomain(self, 2)
4282         bd2.add_vpp_config()
4283         gbd2 = VppGbpBridgeDomain(self, bd2, rd1, self.loop1)
4284         gbd2.add_vpp_config()
4285
4286         # ... and has a /32 and /128 applied
4287         ip4_addr1 = VppIpInterfaceAddress(self, gbd1.bvi,
4288                                           "10.0.0.128", 32,
4289                                           bind=b_lo0_ip4).add_vpp_config()
4290         ip6_addr1 = VppIpInterfaceAddress(self, gbd1.bvi,
4291                                           "2001:10::128", 128,
4292                                           bind=b_lo0_ip6).add_vpp_config()
4293         ip4_addr2 = VppIpInterfaceAddress(self, gbd2.bvi,
4294                                           "10.0.1.128", 32,
4295                                           bind=b_lo1_ip4).add_vpp_config()
4296         ip6_addr2 = VppIpInterfaceAddress(self, gbd2.bvi,
4297                                           "2001:11::128", 128,
4298                                           bind=b_lo1_ip6).add_vpp_config()
4299
4300         #
4301         # The Endpoint-groups
4302         #
4303         epg_220 = VppGbpEndpointGroup(self, 220, 440, rd1, gbd1,
4304                                       None, gbd1.bvi,
4305                                       "10.0.0.128",
4306                                       "2001:10::128",
4307                                       VppGbpEndpointRetention(60))
4308         epg_220.add_vpp_config()
4309         epg_221 = VppGbpEndpointGroup(self, 221, 441, rd1, gbd2,
4310                                       None, gbd2.bvi,
4311                                       "10.0.1.128",
4312                                       "2001:11::128",
4313                                       VppGbpEndpointRetention(60))
4314         epg_221.add_vpp_config()
4315
4316         #
4317         # a GBP bridge domains for the SEPs
4318         #
4319         bd_uu3 = VppVxlanGbpTunnel(self, self.pg7.local_ip4,
4320                                    self.pg7.remote_ip4, 116)
4321         bd_uu3.add_vpp_config()
4322
4323         bd3 = VppBridgeDomain(self, 3)
4324         bd3.add_vpp_config()
4325         gbd3 = VppGbpBridgeDomain(self, bd3, rd1, self.loop2,
4326                                   bd_uu3, learn=False)
4327         gbd3.add_vpp_config()
4328
4329         ip4_addr3 = VppIpInterfaceAddress(self, gbd3.bvi,
4330                                           "12.0.0.128", 32,
4331                                           bind=b_lo2_ip4).add_vpp_config()
4332         ip6_addr3 = VppIpInterfaceAddress(self, gbd3.bvi,
4333                                           "4001:10::128", 128,
4334                                           bind=b_lo2_ip6).add_vpp_config()
4335
4336         #
4337         # self.logger.info(self.vapi.cli("show gbp bridge"))
4338         # self.logger.info(self.vapi.cli("show vxlan-gbp tunnel"))
4339         # self.logger.info(self.vapi.cli("show gbp vxlan"))
4340         # self.logger.info(self.vapi.cli("show int addr"))
4341         #
4342
4343         #
4344         # EPGs in which the service endpoints exist
4345         #
4346         epg_320 = VppGbpEndpointGroup(self, 320, 550, rd1, gbd3,
4347                                       None, gbd3.bvi,
4348                                       "12.0.0.128",
4349                                       "4001:10::128",
4350                                       VppGbpEndpointRetention(60))
4351         epg_320.add_vpp_config()
4352
4353         #
4354         # endpoints
4355         #
4356         ep1 = VppGbpEndpoint(self, self.pg0,
4357                              epg_220, None,
4358                              "10.0.0.1", "11.0.0.1",
4359                              "2001:10::1", "3001:10::1")
4360         ep1.add_vpp_config()
4361         ep2 = VppGbpEndpoint(self, self.pg1,
4362                              epg_221, None,
4363                              "10.0.1.1", "11.0.1.1",
4364                              "2001:11::1", "3001:11::1")
4365         ep2.add_vpp_config()
4366
4367         #
4368         # service endpoints
4369         #
4370         sep1 = VppGbpEndpoint(self, self.pg3,
4371                               epg_320, None,
4372                               "12.0.0.1", "13.0.0.1",
4373                               "4001:10::1", "5001:10::1")
4374         sep2 = VppGbpEndpoint(self, self.pg4,
4375                               epg_320, None,
4376                               "12.0.0.2", "13.0.0.2",
4377                               "4001:10::2", "5001:10::2")
4378
4379         # sep1 and sep2 are not added to config yet
4380         # they are unknown for now
4381
4382         #
4383         # add routes to EPG subnets
4384         #
4385         VppGbpSubnet(self, rd1, "10.0.0.0", 24,
4386                      VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_TRANSPORT
4387                      ).add_vpp_config()
4388         VppGbpSubnet(self, rd1, "10.0.1.0", 24,
4389                      VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_TRANSPORT
4390                      ).add_vpp_config()
4391
4392         #
4393         # Local host to known local host in different BD
4394         # with SFC contract (source and destination are in
4395         # one node and service endpoint in another node)
4396         #
4397         p4 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) /
4398                IP(src=ep1.ip4, dst=ep2.ip4) /
4399                UDP(sport=1234, dport=1234) /
4400                Raw(b'\xa5' * 100)),
4401               (Ether(src=ep2.mac, dst=str(self.router_mac)) /
4402                IP(src=ep2.ip4, dst=ep1.ip4) /
4403                UDP(sport=1234, dport=1234) /
4404                Raw(b'\xa5' * 100))]
4405         p6 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) /
4406                IPv6(src=ep1.ip6, dst=ep2.ip6) /
4407                UDP(sport=1234, dport=1234) /
4408                Raw(b'\xa5' * 100)),
4409               (Ether(src=ep2.mac, dst=str(self.router_mac)) /
4410                IPv6(src=ep2.ip6, dst=ep1.ip6) /
4411                UDP(sport=1234, dport=1230) /
4412                Raw(b'\xa5' * 100))]
4413
4414         # should be dropped since no contract yet
4415         self.send_and_assert_no_replies(self.pg0, [p4[0]])
4416         self.send_and_assert_no_replies(self.pg0, [p6[0]])
4417
4418         #
4419         # Add a contract with a rule to load-balance redirect via SEP1 and SEP2
4420         # one of the next-hops is via an EP that is not known
4421         #
4422         rule4 = AclRule(is_permit=1, proto=17)
4423         rule6 = AclRule(src_prefix=IPv6Network((0, 0)),
4424                         dst_prefix=IPv6Network((0, 0)), is_permit=1, proto=17)
4425         acl = VppAcl(self, rules=[rule4, rule6])
4426         acl.add_vpp_config()
4427
4428         #
4429         # test the src-ip hash mode
4430         #
4431         c1 = VppGbpContract(
4432             self, 402, epg_220.sclass, epg_221.sclass, acl.acl_index,
4433             [VppGbpContractRule(
4434                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
4435                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
4436                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
4437                                        sep1.ip4, sep1.epg.rd)]),
4438              VppGbpContractRule(
4439                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
4440                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
4441                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
4442                                        sep1.ip6, sep1.epg.rd)])],
4443             [ETH_P_IP, ETH_P_IPV6])
4444         c1.add_vpp_config()
4445
4446         c2 = VppGbpContract(
4447             self, 402, epg_221.sclass, epg_220.sclass, acl.acl_index,
4448             [VppGbpContractRule(
4449                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
4450                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
4451                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
4452                                        sep1.ip4, sep1.epg.rd)]),
4453              VppGbpContractRule(
4454                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
4455                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
4456                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
4457                                        sep1.ip6, sep1.epg.rd)])],
4458             [ETH_P_IP, ETH_P_IPV6])
4459         c2.add_vpp_config()
4460
4461         # ep1 <--> ep2 redirected through sep1
4462         # sep1 is unknown
4463         # packet is redirected to sep bd and then go through sep bd UU
4464
4465         rxs = self.send_and_expect(self.pg0, p4[0] * 17, self.pg7)
4466
4467         for rx in rxs:
4468             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
4469             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
4470             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
4471             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
4472             self.assertEqual(rx[VXLAN].vni, 116)
4473             self.assertTrue(rx[VXLAN].flags.G)
4474             self.assertTrue(rx[VXLAN].flags.Instance)
4475             # redirect policy has been applied
4476             self.assertTrue(rx[VXLAN].gpflags.A)
4477             self.assertFalse(rx[VXLAN].gpflags.D)
4478
4479             inner = rx[VXLAN].payload
4480
4481             self.assertEqual(inner[Ether].src, routed_src_mac)
4482             self.assertEqual(inner[Ether].dst, sep1.mac)
4483             self.assertEqual(inner[IP].src, ep1.ip4)
4484             self.assertEqual(inner[IP].dst, ep2.ip4)
4485
4486         rxs = self.send_and_expect(self.pg1, p4[1] * 17, self.pg7)
4487
4488         for rx in rxs:
4489             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
4490             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
4491             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
4492             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
4493             self.assertEqual(rx[VXLAN].vni, 116)
4494             self.assertTrue(rx[VXLAN].flags.G)
4495             self.assertTrue(rx[VXLAN].flags.Instance)
4496             # redirect policy has been applied
4497             self.assertTrue(rx[VXLAN].gpflags.A)
4498             self.assertFalse(rx[VXLAN].gpflags.D)
4499
4500             inner = rx[VXLAN].payload
4501
4502             self.assertEqual(inner[Ether].src, routed_src_mac)
4503             self.assertEqual(inner[Ether].dst, sep1.mac)
4504             self.assertEqual(inner[IP].src, ep2.ip4)
4505             self.assertEqual(inner[IP].dst, ep1.ip4)
4506
4507         rxs = self.send_and_expect(self.pg0, p6[0] * 17, self.pg7)
4508
4509         for rx in rxs:
4510             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
4511             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
4512             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
4513             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
4514             self.assertEqual(rx[VXLAN].vni, 116)
4515             self.assertTrue(rx[VXLAN].flags.G)
4516             self.assertTrue(rx[VXLAN].flags.Instance)
4517             # redirect policy has been applied
4518             inner = rx[VXLAN].payload
4519
4520             self.assertEqual(inner[Ether].src, routed_src_mac)
4521             self.assertEqual(inner[Ether].dst, sep1.mac)
4522             self.assertEqual(inner[IPv6].src, ep1.ip6)
4523             self.assertEqual(inner[IPv6].dst, ep2.ip6)
4524
4525         rxs = self.send_and_expect(self.pg1, p6[1] * 17, self.pg7)
4526
4527         for rx in rxs:
4528             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
4529             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
4530             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
4531             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
4532             self.assertEqual(rx[VXLAN].vni, 116)
4533             self.assertTrue(rx[VXLAN].flags.G)
4534             self.assertTrue(rx[VXLAN].flags.Instance)
4535             # redirect policy has been applied
4536             self.assertTrue(rx[VXLAN].gpflags.A)
4537             self.assertFalse(rx[VXLAN].gpflags.D)
4538
4539             inner = rx[VXLAN].payload
4540
4541             self.assertEqual(inner[Ether].src, routed_src_mac)
4542             self.assertEqual(inner[Ether].dst, sep1.mac)
4543             self.assertEqual(inner[IPv6].src, ep2.ip6)
4544             self.assertEqual(inner[IPv6].dst, ep1.ip6)
4545
4546         # configure sep1: it is now local
4547         # packets between ep1 and ep2 are redirected locally
4548         sep1.add_vpp_config()
4549
4550         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
4551
4552         for rx in rxs:
4553             self.assertEqual(rx[Ether].src, routed_src_mac)
4554             self.assertEqual(rx[Ether].dst, sep1.mac)
4555             self.assertEqual(rx[IP].src, ep1.ip4)
4556             self.assertEqual(rx[IP].dst, ep2.ip4)
4557
4558         rxs = self.send_and_expect(self.pg1, p6[1] * 17, sep1.itf)
4559
4560         for rx in rxs:
4561             self.assertEqual(rx[Ether].src, routed_src_mac)
4562             self.assertEqual(rx[Ether].dst, sep1.mac)
4563             self.assertEqual(rx[IPv6].src, ep2.ip6)
4564             self.assertEqual(rx[IPv6].dst, ep1.ip6)
4565
4566         # packet coming from the l2 spine-proxy to sep1
4567         p = (Ether(src=self.pg7.remote_mac,
4568                    dst=self.pg7.local_mac) /
4569              IP(src=self.pg7.remote_ip4,
4570                 dst=self.pg7.local_ip4) /
4571              UDP(sport=1234, dport=48879) /
4572              VXLAN(vni=116, gpid=440, gpflags=0x08, flags=0x88) /
4573              Ether(src=str(self.router_mac), dst=sep1.mac) /
4574              IP(src=ep1.ip4, dst=ep2.ip4) /
4575              UDP(sport=1234, dport=1234) /
4576              Raw(b'\xa5' * 100))
4577
4578         rxs = self.send_and_expect(self.pg7, [p] * 17, sep1.itf)
4579
4580         for rx in rxs:
4581             self.assertEqual(rx[Ether].src, str(self.router_mac))
4582             self.assertEqual(rx[Ether].dst, sep1.mac)
4583             self.assertEqual(rx[IP].src, ep1.ip4)
4584             self.assertEqual(rx[IP].dst, ep2.ip4)
4585
4586         # contract for SEP to communicate with dst EP
4587         c3 = VppGbpContract(
4588             self, 402, epg_320.sclass, epg_221.sclass, acl.acl_index,
4589             [VppGbpContractRule(
4590                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4591                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC),
4592              VppGbpContractRule(
4593                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4594                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC)],
4595             [ETH_P_IP, ETH_P_IPV6])
4596         c3.add_vpp_config()
4597
4598         # temporarily remove ep2, so that ep2 is remote & unknown
4599         ep2.remove_vpp_config()
4600
4601         # packet going back from sep1 to its original dest (ep2)
4602         # as ep2 is now unknown (see above), it must go through
4603         # the rd UU (packet is routed)
4604
4605         p1 = (Ether(src=sep1.mac, dst=self.router_mac) /
4606               IP(src=ep1.ip4, dst=ep2.ip4) /
4607               UDP(sport=1234, dport=1234) /
4608               Raw(b'\xa5' * 100))
4609
4610         rxs = self.send_and_expect(self.pg3, [p1] * 17, self.pg7)
4611
4612         for rx in rxs:
4613             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
4614             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
4615             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
4616             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
4617             self.assertEqual(rx[VXLAN].vni, 114)
4618             self.assertTrue(rx[VXLAN].flags.G)
4619             self.assertTrue(rx[VXLAN].flags.Instance)
4620             # redirect policy has been applied
4621             inner = rx[VXLAN].payload
4622             self.assertEqual(inner[Ether].src, routed_src_mac)
4623             self.assertEqual(inner[Ether].dst, routed_dst_mac)
4624             self.assertEqual(inner[IP].src, ep1.ip4)
4625             self.assertEqual(inner[IP].dst, ep2.ip4)
4626
4627         self.logger.info(self.vapi.cli("show bridge 3 detail"))
4628         sep1.remove_vpp_config()
4629
4630         self.logger.info(self.vapi.cli("show bridge 1 detail"))
4631         self.logger.info(self.vapi.cli("show bridge 2 detail"))
4632
4633         # re-add ep2: it is local again :)
4634         ep2.add_vpp_config()
4635
4636         # packet coming back from the remote sep through rd UU
4637         p2 = (Ether(src=self.pg7.remote_mac,
4638                     dst=self.pg7.local_mac) /
4639               IP(src=self.pg7.remote_ip4,
4640                  dst=self.pg7.local_ip4) /
4641               UDP(sport=1234, dport=48879) /
4642               VXLAN(vni=114, gpid=441, gpflags=0x09, flags=0x88) /
4643               Ether(src=str(self.router_mac), dst=self.router_mac) /
4644               IP(src=ep1.ip4, dst=ep2.ip4) /
4645               UDP(sport=1234, dport=1234) /
4646               Raw(b'\xa5' * 100))
4647
4648         rxs = self.send_and_expect(self.pg7, [p2], self.pg1)
4649
4650         for rx in rxs:
4651             self.assertEqual(rx[Ether].src, str(self.router_mac))
4652             self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
4653             self.assertEqual(rx[IP].src, ep1.ip4)
4654             self.assertEqual(rx[IP].dst, ep2.ip4)
4655
4656         #
4657         # bd_uu2.add_vpp_config()
4658         #
4659
4660         #
4661         # cleanup
4662         #
4663         c1.remove_vpp_config()
4664         c2.remove_vpp_config()
4665         c3.remove_vpp_config()
4666         self.pg7.unconfig_ip4()
4667
4668     def test_gbp_l3_out(self):
4669         """ GBP L3 Out """
4670
4671         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
4672         self.vapi.cli("set logging class gbp level debug")
4673
4674         routed_dst_mac = "00:0c:0c:0c:0c:0c"
4675         routed_src_mac = "00:22:bd:f8:19:ff"
4676
4677         #
4678         # IP tables
4679         #
4680         t4 = VppIpTable(self, 1)
4681         t4.add_vpp_config()
4682         t6 = VppIpTable(self, 1, True)
4683         t6.add_vpp_config()
4684
4685         rd1 = VppGbpRouteDomain(self, 2, 55, t4, t6)
4686         rd1.add_vpp_config()
4687
4688         self.loop0.set_mac(self.router_mac)
4689
4690         #
4691         # Bind the BVI to the RD
4692         #
4693         b_ip4 = VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
4694         b_ip6 = VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
4695
4696         #
4697         # Pg7 hosts a BD's BUM
4698         # Pg1 some other l3 interface
4699         #
4700         self.pg7.config_ip4()
4701         self.pg7.resolve_arp()
4702
4703         #
4704         # a multicast vxlan-gbp tunnel for broadcast in the BD
4705         #
4706         tun_bm = VppVxlanGbpTunnel(self, self.pg7.local_ip4,
4707                                    "239.1.1.1", 88,
4708                                    mcast_itf=self.pg7)
4709         tun_bm.add_vpp_config()
4710
4711         #
4712         # a GBP external bridge domains for the EPs
4713         #
4714         bd1 = VppBridgeDomain(self, 1)
4715         bd1.add_vpp_config()
4716         gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0, None, tun_bm)
4717         gbd1.add_vpp_config()
4718
4719         #
4720         # The Endpoint-groups in which the external endpoints exist
4721         #
4722         epg_220 = VppGbpEndpointGroup(self, 220, 113, rd1, gbd1,
4723                                       None, gbd1.bvi,
4724                                       "10.0.0.128",
4725                                       "2001:10::128",
4726                                       VppGbpEndpointRetention(4))
4727         epg_220.add_vpp_config()
4728
4729         # the BVIs have the subnets applied ...
4730         ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128",
4731                                          24, bind=b_ip4).add_vpp_config()
4732         ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128",
4733                                          64, bind=b_ip6).add_vpp_config()
4734
4735         # ... which are L3-out subnets
4736         l3o_1 = VppGbpSubnet(
4737             self, rd1, "10.0.0.0", 24,
4738             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
4739             sclass=113)
4740         l3o_1.add_vpp_config()
4741
4742         #
4743         # an external interface attached to the outside world and the
4744         # external BD
4745         #
4746         VppL2Vtr(self, self.vlan_100, L2_VTR_OP.L2_POP_1).add_vpp_config()
4747         VppL2Vtr(self, self.vlan_101, L2_VTR_OP.L2_POP_1).add_vpp_config()
4748         vlan_144 = VppDot1QSubint(self, self.pg0, 144)
4749         vlan_144.admin_up()
4750         # vlan_102 is not poped
4751
4752         #
4753         # an unicast vxlan-gbp for inter-RD traffic
4754         #
4755         vx_tun_l3 = VppGbpVxlanTunnel(
4756             self, 444, rd1.rd_id,
4757             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3,
4758             self.pg2.local_ip4)
4759         vx_tun_l3.add_vpp_config()
4760
4761         #
4762         # External Endpoints
4763         #
4764         eep1 = VppGbpEndpoint(self, self.vlan_100,
4765                               epg_220, None,
4766                               "10.0.0.1", "11.0.0.1",
4767                               "2001:10::1", "3001::1",
4768                               ep_flags.GBP_API_ENDPOINT_FLAG_EXTERNAL)
4769         eep1.add_vpp_config()
4770         eep2 = VppGbpEndpoint(self, self.vlan_101,
4771                               epg_220, None,
4772                               "10.0.0.2", "11.0.0.2",
4773                               "2001:10::2", "3001::2",
4774                               ep_flags.GBP_API_ENDPOINT_FLAG_EXTERNAL)
4775         eep2.add_vpp_config()
4776         eep3 = VppGbpEndpoint(self, self.vlan_102,
4777                               epg_220, None,
4778                               "10.0.0.3", "11.0.0.3",
4779                               "2001:10::3", "3001::3",
4780                               ep_flags.GBP_API_ENDPOINT_FLAG_EXTERNAL)
4781         eep3.add_vpp_config()
4782
4783         #
4784         # A remote external endpoint
4785         #
4786         rep = VppGbpEndpoint(self, vx_tun_l3,
4787                              epg_220, None,
4788                              "10.0.0.101", "11.0.0.101",
4789                              "2001:10::101", "3001::101",
4790                              ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
4791                              self.pg7.local_ip4,
4792                              self.pg7.remote_ip4,
4793                              mac=None)
4794         rep.add_vpp_config()
4795
4796         #
4797         # EP1 impersonating EP3 is dropped
4798         #
4799         p = (Ether(src=eep1.mac, dst="ff:ff:ff:ff:ff:ff") /
4800              Dot1Q(vlan=100) /
4801              ARP(op="who-has",
4802                  psrc="10.0.0.3", pdst="10.0.0.128",
4803                  hwsrc=eep1.mac, hwdst="ff:ff:ff:ff:ff:ff"))
4804         self.send_and_assert_no_replies(self.pg0, p)
4805
4806         #
4807         # ARP packet from External EPs are accepted and replied to
4808         #
4809         p_arp = (Ether(src=eep1.mac, dst="ff:ff:ff:ff:ff:ff") /
4810                  Dot1Q(vlan=100) /
4811                  ARP(op="who-has",
4812                      psrc=eep1.ip4, pdst="10.0.0.128",
4813                      hwsrc=eep1.mac, hwdst="ff:ff:ff:ff:ff:ff"))
4814         rxs = self.send_and_expect(self.pg0, p_arp * 1, self.pg0)
4815
4816         #
4817         # ARP packet from host in remote subnet are accepted and replied to
4818         #
4819         p_arp = (Ether(src=eep3.mac, dst="ff:ff:ff:ff:ff:ff") /
4820                  Dot1Q(vlan=102) /
4821                  ARP(op="who-has",
4822                      psrc=eep3.ip4, pdst="10.0.0.128",
4823                      hwsrc=eep3.mac, hwdst="ff:ff:ff:ff:ff:ff"))
4824         rxs = self.send_and_expect(self.pg0, p_arp * 1, self.pg0)
4825
4826         #
4827         # packets destined to unknown addresses in the BVI's subnet
4828         # are ARP'd for
4829         #
4830         p4 = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
4831               Dot1Q(vlan=100) /
4832               IP(src="10.0.0.1", dst="10.0.0.88") /
4833               UDP(sport=1234, dport=1234) /
4834               Raw(b'\xa5' * 100))
4835         p6 = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
4836               Dot1Q(vlan=100) /
4837               IPv6(src="2001:10::1", dst="2001:10::88") /
4838               UDP(sport=1234, dport=1234) /
4839               Raw(b'\xa5' * 100))
4840
4841         rxs = self.send_and_expect(self.pg0, p4 * 1, self.pg7)
4842
4843         for rx in rxs:
4844             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
4845             # self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
4846             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
4847             self.assertEqual(rx[IP].dst, "239.1.1.1")
4848             self.assertEqual(rx[VXLAN].vni, 88)
4849             self.assertTrue(rx[VXLAN].flags.G)
4850             self.assertTrue(rx[VXLAN].flags.Instance)
4851             # policy was applied to the original IP packet
4852             self.assertEqual(rx[VXLAN].gpid, 113)
4853             self.assertTrue(rx[VXLAN].gpflags.A)
4854             self.assertFalse(rx[VXLAN].gpflags.D)
4855
4856             inner = rx[VXLAN].payload
4857
4858             self.assertTrue(inner.haslayer(ARP))
4859
4860         #
4861         # remote to external
4862         #
4863         p = (Ether(src=self.pg7.remote_mac,
4864                    dst=self.pg7.local_mac) /
4865              IP(src=self.pg7.remote_ip4,
4866                 dst=self.pg7.local_ip4) /
4867              UDP(sport=1234, dport=48879) /
4868              VXLAN(vni=444, gpid=113, flags=0x88) /
4869              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
4870              IP(src="10.0.0.101", dst="10.0.0.1") /
4871              UDP(sport=1234, dport=1234) /
4872              Raw(b'\xa5' * 100))
4873
4874         rxs = self.send_and_expect(self.pg7, p * 1, self.pg0)
4875
4876         #
4877         # local EP pings router
4878         #
4879         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
4880              Dot1Q(vlan=100) /
4881              IP(src=eep1.ip4, dst="10.0.0.128") /
4882              ICMP(type='echo-request'))
4883
4884         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
4885
4886         for rx in rxs:
4887             self.assertEqual(rx[Ether].src, str(self.router_mac))
4888             self.assertEqual(rx[Ether].dst, eep1.mac)
4889             self.assertEqual(rx[Dot1Q].vlan, 100)
4890
4891         #
4892         # local EP pings other local EP
4893         #
4894         p = (Ether(src=eep1.mac, dst=eep2.mac) /
4895              Dot1Q(vlan=100) /
4896              IP(src=eep1.ip4, dst=eep2.ip4) /
4897              ICMP(type='echo-request'))
4898
4899         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
4900
4901         for rx in rxs:
4902             self.assertEqual(rx[Ether].src, eep1.mac)
4903             self.assertEqual(rx[Ether].dst, eep2.mac)
4904             self.assertEqual(rx[Dot1Q].vlan, 101)
4905
4906         #
4907         # local EP pings router w/o vlan tag poped
4908         #
4909         p = (Ether(src=eep3.mac, dst=str(self.router_mac)) /
4910              Dot1Q(vlan=102) /
4911              IP(src=eep3.ip4, dst="10.0.0.128") /
4912              ICMP(type='echo-request'))
4913
4914         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
4915
4916         for rx in rxs:
4917             self.assertEqual(rx[Ether].src, str(self.router_mac))
4918             self.assertEqual(rx[Ether].dst, self.vlan_102.remote_mac)
4919
4920         #
4921         # A ip4 subnet reachable through the external EP1
4922         #
4923         ip_220 = VppIpRoute(self, "10.220.0.0", 24,
4924                             [VppRoutePath(eep1.ip4,
4925                                           eep1.epg.bvi.sw_if_index)],
4926                             table_id=t4.table_id)
4927         ip_220.add_vpp_config()
4928
4929         l3o_220 = VppGbpSubnet(
4930             self, rd1, "10.220.0.0", 24,
4931             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
4932             sclass=4220)
4933         l3o_220.add_vpp_config()
4934
4935         #
4936         # An ip6 subnet reachable through the external EP1
4937         #
4938         ip6_220 = VppIpRoute(self, "10:220::", 64,
4939                              [VppRoutePath(eep1.ip6,
4940                                            eep1.epg.bvi.sw_if_index)],
4941                              table_id=t6.table_id)
4942         ip6_220.add_vpp_config()
4943
4944         l3o6_220 = VppGbpSubnet(
4945             self, rd1, "10:220::", 64,
4946             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
4947             sclass=4220)
4948         l3o6_220.add_vpp_config()
4949
4950         #
4951         # A subnet reachable through the external EP2
4952         #
4953         ip_221 = VppIpRoute(self, "10.221.0.0", 24,
4954                             [VppRoutePath(eep2.ip4,
4955                                           eep2.epg.bvi.sw_if_index)],
4956                             table_id=t4.table_id)
4957         ip_221.add_vpp_config()
4958
4959         l3o_221 = VppGbpSubnet(
4960             self, rd1, "10.221.0.0", 24,
4961             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
4962             sclass=4221)
4963         l3o_221.add_vpp_config()
4964
4965         #
4966         # ping between hosts in remote subnets
4967         #  dropped without a contract
4968         #
4969         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
4970              Dot1Q(vlan=100) /
4971              IP(src="10.220.0.1", dst="10.221.0.1") /
4972              ICMP(type='echo-request'))
4973
4974         self.send_and_assert_no_replies(self.pg0, p * 1)
4975
4976         #
4977         # contract for the external nets to communicate
4978         #
4979         rule4 = AclRule(is_permit=1, proto=17)
4980         rule6 = AclRule(src_prefix=IPv6Network((0, 0)),
4981                         dst_prefix=IPv6Network((0, 0)), is_permit=1, proto=17)
4982         acl = VppAcl(self, rules=[rule4, rule6])
4983         acl.add_vpp_config()
4984
4985         #
4986         # A contract with the wrong scope is not matched
4987         #
4988         c_44 = VppGbpContract(
4989             self, 44, 4220, 4221, acl.acl_index,
4990             [VppGbpContractRule(
4991                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4992                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
4993                 []),
4994              VppGbpContractRule(
4995                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4996                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
4997                  [])],
4998             [ETH_P_IP, ETH_P_IPV6])
4999         c_44.add_vpp_config()
5000         self.send_and_assert_no_replies(self.pg0, p * 1)
5001
5002         c1 = VppGbpContract(
5003             self, 55, 4220, 4221, acl.acl_index,
5004             [VppGbpContractRule(
5005                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5006                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5007                 []),
5008                 VppGbpContractRule(
5009                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5010                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5011                     [])],
5012             [ETH_P_IP, ETH_P_IPV6])
5013         c1.add_vpp_config()
5014
5015         #
5016         # Contracts allowing ext-net 200 to talk with external EPs
5017         #
5018         c2 = VppGbpContract(
5019             self, 55, 4220, 113, acl.acl_index,
5020             [VppGbpContractRule(
5021                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5022                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5023                 []),
5024                 VppGbpContractRule(
5025                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5026                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5027                     [])],
5028             [ETH_P_IP, ETH_P_IPV6])
5029         c2.add_vpp_config()
5030         c3 = VppGbpContract(
5031             self, 55, 113, 4220, acl.acl_index,
5032             [VppGbpContractRule(
5033                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5034                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5035                 []),
5036                 VppGbpContractRule(
5037                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5038                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5039                     [])],
5040             [ETH_P_IP, ETH_P_IPV6])
5041         c3.add_vpp_config()
5042
5043         #
5044         # ping between hosts in remote subnets
5045         #
5046         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
5047              Dot1Q(vlan=100) /
5048              IP(src="10.220.0.1", dst="10.221.0.1") /
5049              UDP(sport=1234, dport=1234) /
5050              Raw(b'\xa5' * 100))
5051
5052         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
5053
5054         for rx in rxs:
5055             self.assertEqual(rx[Ether].src, str(self.router_mac))
5056             self.assertEqual(rx[Ether].dst, eep2.mac)
5057             self.assertEqual(rx[Dot1Q].vlan, 101)
5058
5059         # we did not learn these external hosts
5060         self.assertFalse(find_gbp_endpoint(self, ip="10.220.0.1"))
5061         self.assertFalse(find_gbp_endpoint(self, ip="10.221.0.1"))
5062
5063         #
5064         # from remote external EP to local external EP
5065         #
5066         p = (Ether(src=self.pg7.remote_mac,
5067                    dst=self.pg7.local_mac) /
5068              IP(src=self.pg7.remote_ip4,
5069                 dst=self.pg7.local_ip4) /
5070              UDP(sport=1234, dport=48879) /
5071              VXLAN(vni=444, gpid=113, flags=0x88) /
5072              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
5073              IP(src="10.0.0.101", dst="10.220.0.1") /
5074              UDP(sport=1234, dport=1234) /
5075              Raw(b'\xa5' * 100))
5076
5077         rxs = self.send_and_expect(self.pg7, p * 1, self.pg0)
5078
5079         #
5080         # ping from an external host to the remote external EP
5081         #
5082         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
5083              Dot1Q(vlan=100) /
5084              IP(src="10.220.0.1", dst=rep.ip4) /
5085              UDP(sport=1234, dport=1234) /
5086              Raw(b'\xa5' * 100))
5087
5088         rxs = self.send_and_expect(self.pg0, p * 1, self.pg7)
5089
5090         for rx in rxs:
5091             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
5092             # self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
5093             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
5094             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
5095             self.assertEqual(rx[VXLAN].vni, 444)
5096             self.assertTrue(rx[VXLAN].flags.G)
5097             self.assertTrue(rx[VXLAN].flags.Instance)
5098             # the sclass of the ext-net the packet came from
5099             self.assertEqual(rx[VXLAN].gpid, 4220)
5100             # policy was applied to the original IP packet
5101             self.assertTrue(rx[VXLAN].gpflags.A)
5102             # since it's an external host the reciever should not learn it
5103             self.assertTrue(rx[VXLAN].gpflags.D)
5104             inner = rx[VXLAN].payload
5105             self.assertEqual(inner[IP].src, "10.220.0.1")
5106             self.assertEqual(inner[IP].dst, rep.ip4)
5107
5108         #
5109         # An external subnet reachable via the remote external EP
5110         #
5111
5112         #
5113         # first the VXLAN-GBP tunnel over which it is reached
5114         #
5115         vx_tun_r1 = VppVxlanGbpTunnel(
5116             self, self.pg7.local_ip4,
5117             self.pg7.remote_ip4, 445,
5118             mode=(VppEnum.vl_api_vxlan_gbp_api_tunnel_mode_t.
5119                   VXLAN_GBP_API_TUNNEL_MODE_L3))
5120         vx_tun_r1.add_vpp_config()
5121         VppIpInterfaceBind(self, vx_tun_r1, t4).add_vpp_config()
5122
5123         self.logger.info(self.vapi.cli("sh vxlan-gbp tunnel"))
5124
5125         #
5126         # then the special adj to resolve through on that tunnel
5127         #
5128         n1 = VppNeighbor(self,
5129                          vx_tun_r1.sw_if_index,
5130                          "00:0c:0c:0c:0c:0c",
5131                          self.pg7.remote_ip4)
5132         n1.add_vpp_config()
5133
5134         #
5135         # the route via the adj above
5136         #
5137         ip_222 = VppIpRoute(self, "10.222.0.0", 24,
5138                             [VppRoutePath(self.pg7.remote_ip4,
5139                                           vx_tun_r1.sw_if_index)],
5140                             table_id=t4.table_id)
5141         ip_222.add_vpp_config()
5142
5143         l3o_222 = VppGbpSubnet(
5144             self, rd1, "10.222.0.0", 24,
5145             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
5146             sclass=4222)
5147         l3o_222.add_vpp_config()
5148
5149         #
5150         # ping between hosts in local and remote external subnets
5151         #  dropped without a contract
5152         #
5153         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
5154              Dot1Q(vlan=100) /
5155              IP(src="10.220.0.1", dst="10.222.0.1") /
5156              UDP(sport=1234, dport=1234) /
5157              Raw(b'\xa5' * 100))
5158
5159         rxs = self.send_and_assert_no_replies(self.pg0, p * 1)
5160
5161         #
5162         # Add contracts ext-nets for 220 -> 222
5163         #
5164         c4 = VppGbpContract(
5165             self, 55, 4220, 4222, acl.acl_index,
5166             [VppGbpContractRule(
5167                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5168                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5169                 []),
5170                 VppGbpContractRule(
5171                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5172                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5173                     [])],
5174             [ETH_P_IP, ETH_P_IPV6])
5175         c4.add_vpp_config()
5176
5177         #
5178         # ping from host in local to remote external subnets
5179         #
5180         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
5181              Dot1Q(vlan=100) /
5182              IP(src="10.220.0.1", dst="10.222.0.1") /
5183              UDP(sport=1234, dport=1234) /
5184              Raw(b'\xa5' * 100))
5185
5186         rxs = self.send_and_expect(self.pg0, p * 3, self.pg7)
5187
5188         for rx in rxs:
5189             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
5190             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
5191             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
5192             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
5193             self.assertEqual(rx[VXLAN].vni, 445)
5194             self.assertTrue(rx[VXLAN].flags.G)
5195             self.assertTrue(rx[VXLAN].flags.Instance)
5196             # the sclass of the ext-net the packet came from
5197             self.assertEqual(rx[VXLAN].gpid, 4220)
5198             # policy was applied to the original IP packet
5199             self.assertTrue(rx[VXLAN].gpflags.A)
5200             # since it's an external host the reciever should not learn it
5201             self.assertTrue(rx[VXLAN].gpflags.D)
5202             inner = rx[VXLAN].payload
5203             self.assertEqual(inner[Ether].dst, "00:0c:0c:0c:0c:0c")
5204             self.assertEqual(inner[IP].src, "10.220.0.1")
5205             self.assertEqual(inner[IP].dst, "10.222.0.1")
5206
5207         #
5208         # make the external subnet ECMP
5209         #
5210         vx_tun_r2 = VppVxlanGbpTunnel(
5211             self, self.pg7.local_ip4,
5212             self.pg7.remote_ip4, 446,
5213             mode=(VppEnum.vl_api_vxlan_gbp_api_tunnel_mode_t.
5214                   VXLAN_GBP_API_TUNNEL_MODE_L3))
5215         vx_tun_r2.add_vpp_config()
5216         VppIpInterfaceBind(self, vx_tun_r2, t4).add_vpp_config()
5217
5218         self.logger.info(self.vapi.cli("sh vxlan-gbp tunnel"))
5219
5220         n2 = VppNeighbor(self,
5221                          vx_tun_r2.sw_if_index,
5222                          "00:0c:0c:0c:0c:0c",
5223                          self.pg7.remote_ip4)
5224         n2.add_vpp_config()
5225
5226         ip_222.modify([VppRoutePath(self.pg7.remote_ip4,
5227                                     vx_tun_r1.sw_if_index),
5228                        VppRoutePath(self.pg7.remote_ip4,
5229                                     vx_tun_r2.sw_if_index)])
5230
5231         #
5232         # now expect load-balance
5233         #
5234         p = [(Ether(src=eep1.mac, dst=str(self.router_mac)) /
5235               Dot1Q(vlan=100) /
5236               IP(src="10.220.0.1", dst="10.222.0.1") /
5237               UDP(sport=1234, dport=1234) /
5238               Raw(b'\xa5' * 100)),
5239              (Ether(src=eep1.mac, dst=str(self.router_mac)) /
5240               Dot1Q(vlan=100) /
5241               IP(src="10.220.0.1", dst="10.222.0.1") /
5242               UDP(sport=1222, dport=1235) /
5243               Raw(b'\xa5' * 100))]
5244
5245         rxs = self.send_and_expect(self.pg0, p, self.pg7)
5246
5247         self.assertEqual(rxs[0][VXLAN].vni, 445)
5248         self.assertEqual(rxs[1][VXLAN].vni, 446)
5249
5250         #
5251         # Same LB test for v6
5252         #
5253         n3 = VppNeighbor(self,
5254                          vx_tun_r1.sw_if_index,
5255                          "00:0c:0c:0c:0c:0c",
5256                          self.pg7.remote_ip6)
5257         n3.add_vpp_config()
5258         n4 = VppNeighbor(self,
5259                          vx_tun_r2.sw_if_index,
5260                          "00:0c:0c:0c:0c:0c",
5261                          self.pg7.remote_ip6)
5262         n4.add_vpp_config()
5263
5264         ip_222_6 = VppIpRoute(self, "10:222::", 64,
5265                               [VppRoutePath(self.pg7.remote_ip6,
5266                                             vx_tun_r1.sw_if_index),
5267                                VppRoutePath(self.pg7.remote_ip6,
5268                                             vx_tun_r2.sw_if_index)],
5269                               table_id=t6.table_id)
5270         ip_222_6.add_vpp_config()
5271
5272         l3o_222_6 = VppGbpSubnet(
5273             self, rd1, "10:222::", 64,
5274             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
5275             sclass=4222)
5276         l3o_222_6.add_vpp_config()
5277
5278         p = [(Ether(src=eep1.mac, dst=str(self.router_mac)) /
5279               Dot1Q(vlan=100) /
5280               IPv6(src="10:220::1", dst="10:222::1") /
5281               UDP(sport=1234, dport=1234) /
5282               Raw(b'\xa5' * 100)),
5283              (Ether(src=eep1.mac, dst=str(self.router_mac)) /
5284               Dot1Q(vlan=100) /
5285               IPv6(src="10:220::1", dst="10:222::1") /
5286               UDP(sport=7777, dport=8881) /
5287               Raw(b'\xa5' * 100))]
5288
5289         self.logger.info(self.vapi.cli("sh ip6 fib 10:222::1"))
5290         rxs = self.send_and_expect(self.pg0, p, self.pg7)
5291
5292         self.assertEqual(rxs[0][VXLAN].vni, 445)
5293         self.assertEqual(rxs[1][VXLAN].vni, 446)
5294
5295         #
5296         # ping from host in remote to local external subnets
5297         # there's no contract for this, but the A bit is set.
5298         #
5299         p = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) /
5300              IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) /
5301              UDP(sport=1234, dport=48879) /
5302              VXLAN(vni=445, gpid=4222, flags=0x88, gpflags='A') /
5303              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
5304              IP(src="10.222.0.1", dst="10.220.0.1") /
5305              UDP(sport=1234, dport=1234) /
5306              Raw(b'\xa5' * 100))
5307
5308         rxs = self.send_and_expect(self.pg7, p * 3, self.pg0)
5309         self.assertFalse(find_gbp_endpoint(self, ip="10.222.0.1"))
5310
5311         #
5312         # ping from host in remote to remote external subnets
5313         #   this is dropped by reflection check.
5314         #
5315         p = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) /
5316              IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) /
5317              UDP(sport=1234, dport=48879) /
5318              VXLAN(vni=445, gpid=4222, flags=0x88, gpflags='A') /
5319              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
5320              IP(src="10.222.0.1", dst="10.222.0.2") /
5321              UDP(sport=1234, dport=1234) /
5322              Raw(b'\xa5' * 100))
5323
5324         rxs = self.send_and_assert_no_replies(self.pg7, p * 3)
5325
5326         p = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) /
5327              IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) /
5328              UDP(sport=1234, dport=48879) /
5329              VXLAN(vni=445, gpid=4222, flags=0x88, gpflags='A') /
5330              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
5331              IPv6(src="10:222::1", dst="10:222::2") /
5332              UDP(sport=1234, dport=1234) /
5333              Raw(b'\xa5' * 100))
5334
5335         rxs = self.send_and_assert_no_replies(self.pg7, p * 3)
5336
5337         #
5338         # local EP
5339         #
5340         lep1 = VppGbpEndpoint(self, vlan_144,
5341                               epg_220, None,
5342                               "10.0.0.44", "11.0.0.44",
5343                               "2001:10::44", "3001::44")
5344         lep1.add_vpp_config()
5345
5346         #
5347         # local EP to local ip4 external subnet
5348         #
5349         p = (Ether(src=lep1.mac, dst=str(self.router_mac)) /
5350              Dot1Q(vlan=144) /
5351              IP(src=lep1.ip4, dst="10.220.0.1") /
5352              UDP(sport=1234, dport=1234) /
5353              Raw(b'\xa5' * 100))
5354
5355         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
5356
5357         for rx in rxs:
5358             self.assertEqual(rx[Ether].src, str(self.router_mac))
5359             self.assertEqual(rx[Ether].dst, eep1.mac)
5360             self.assertEqual(rx[Dot1Q].vlan, 100)
5361
5362         #
5363         # local EP to local ip6 external subnet
5364         #
5365         p = (Ether(src=lep1.mac, dst=str(self.router_mac)) /
5366              Dot1Q(vlan=144) /
5367              IPv6(src=lep1.ip6, dst="10:220::1") /
5368              UDP(sport=1234, dport=1234) /
5369              Raw(b'\xa5' * 100))
5370
5371         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
5372
5373         for rx in rxs:
5374             self.assertEqual(rx[Ether].src, str(self.router_mac))
5375             self.assertEqual(rx[Ether].dst, eep1.mac)
5376             self.assertEqual(rx[Dot1Q].vlan, 100)
5377
5378         #
5379         # ip4 and ip6 subnets that load-balance
5380         #
5381         ip_20 = VppIpRoute(self, "10.20.0.0", 24,
5382                            [VppRoutePath(eep1.ip4,
5383                                          eep1.epg.bvi.sw_if_index),
5384                             VppRoutePath(eep2.ip4,
5385                                          eep2.epg.bvi.sw_if_index)],
5386                            table_id=t4.table_id)
5387         ip_20.add_vpp_config()
5388
5389         l3o_20 = VppGbpSubnet(
5390             self, rd1, "10.20.0.0", 24,
5391             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
5392             sclass=4220)
5393         l3o_20.add_vpp_config()
5394
5395         ip6_20 = VppIpRoute(self, "10:20::", 64,
5396                             [VppRoutePath(eep1.ip6,
5397                                           eep1.epg.bvi.sw_if_index),
5398                              VppRoutePath(eep2.ip6,
5399                                           eep2.epg.bvi.sw_if_index)],
5400                             table_id=t6.table_id)
5401         ip6_20.add_vpp_config()
5402
5403         l3o6_20 = VppGbpSubnet(
5404             self, rd1, "10:20::", 64,
5405             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
5406             sclass=4220)
5407         l3o6_20.add_vpp_config()
5408
5409         self.logger.info(self.vapi.cli("sh ip fib 10.20.0.1"))
5410         self.logger.info(self.vapi.cli("sh ip6 fib 10:20::1"))
5411
5412         # two ip6 packets whose port are chosen so they load-balance
5413         p = [(Ether(src=lep1.mac, dst=str(self.router_mac)) /
5414               Dot1Q(vlan=144) /
5415               IPv6(src=lep1.ip6, dst="10:20::1") /
5416               UDP(sport=1234, dport=1234) /
5417               Raw(b'\xa5' * 100)),
5418              (Ether(src=lep1.mac, dst=str(self.router_mac)) /
5419               Dot1Q(vlan=144) /
5420               IPv6(src=lep1.ip6, dst="10:20::1") /
5421               UDP(sport=124, dport=1230) /
5422               Raw(b'\xa5' * 100))]
5423
5424         rxs = self.send_and_expect(self.pg0, p, self.pg0, 2)
5425
5426         self.assertEqual(rxs[0][Dot1Q].vlan, 101)
5427         self.assertEqual(rxs[1][Dot1Q].vlan, 100)
5428
5429         # two ip4 packets whose port are chosen so they load-balance
5430         p = [(Ether(src=lep1.mac, dst=str(self.router_mac)) /
5431               Dot1Q(vlan=144) /
5432               IP(src=lep1.ip4, dst="10.20.0.1") /
5433               UDP(sport=1235, dport=1235) /
5434               Raw(b'\xa5' * 100)),
5435              (Ether(src=lep1.mac, dst=str(self.router_mac)) /
5436               Dot1Q(vlan=144) /
5437               IP(src=lep1.ip4, dst="10.20.0.1") /
5438               UDP(sport=124, dport=1230) /
5439               Raw(b'\xa5' * 100))]
5440
5441         rxs = self.send_and_expect(self.pg0, p, self.pg0, 2)
5442
5443         self.assertEqual(rxs[0][Dot1Q].vlan, 101)
5444         self.assertEqual(rxs[1][Dot1Q].vlan, 100)
5445
5446         #
5447         # cleanup
5448         #
5449         ip_222.remove_vpp_config()
5450         self.pg7.unconfig_ip4()
5451         self.vlan_101.set_vtr(L2_VTR_OP.L2_DISABLED)
5452         self.vlan_100.set_vtr(L2_VTR_OP.L2_DISABLED)
5453
5454     def test_gbp_anon_l3_out(self):
5455         """ GBP Anonymous L3 Out """
5456
5457         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
5458         self.vapi.cli("set logging class gbp level debug")
5459
5460         routed_dst_mac = "00:0c:0c:0c:0c:0c"
5461         routed_src_mac = "00:22:bd:f8:19:ff"
5462
5463         #
5464         # IP tables
5465         #
5466         t4 = VppIpTable(self, 1)
5467         t4.add_vpp_config()
5468         t6 = VppIpTable(self, 1, True)
5469         t6.add_vpp_config()
5470
5471         rd1 = VppGbpRouteDomain(self, 2, 55, t4, t6)
5472         rd1.add_vpp_config()
5473
5474         self.loop0.set_mac(self.router_mac)
5475
5476         #
5477         # Bind the BVI to the RD
5478         #
5479         bind_l0_ip4 = VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
5480         bind_l0_ip6 = VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
5481
5482         #
5483         # Pg7 hosts a BD's BUM
5484         # Pg1 some other l3 interface
5485         #
5486         self.pg7.config_ip4()
5487         self.pg7.resolve_arp()
5488
5489         #
5490         # a GBP external bridge domains for the EPs
5491         #
5492         bd1 = VppBridgeDomain(self, 1)
5493         bd1.add_vpp_config()
5494         gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0, None, None)
5495         gbd1.add_vpp_config()
5496
5497         #
5498         # The Endpoint-groups in which the external endpoints exist
5499         #
5500         epg_220 = VppGbpEndpointGroup(self, 220, 113, rd1, gbd1,
5501                                       None, gbd1.bvi,
5502                                       "10.0.0.128",
5503                                       "2001:10::128",
5504                                       VppGbpEndpointRetention(4))
5505         epg_220.add_vpp_config()
5506
5507         # the BVIs have the subnet applied ...
5508         ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi,
5509                                          "10.0.0.128", 24,
5510                                          bind=bind_l0_ip4).add_vpp_config()
5511
5512         # ... which is an Anonymous L3-out subnets
5513         l3o_1 = VppGbpSubnet(
5514             self, rd1, "10.0.0.0", 24,
5515             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_ANON_L3_OUT,
5516             sclass=113)
5517         l3o_1.add_vpp_config()
5518
5519         #
5520         # an external interface attached to the outside world and the
5521         # external BD
5522         #
5523         VppL2Vtr(self, self.vlan_100, L2_VTR_OP.L2_POP_1).add_vpp_config()
5524         VppL2Vtr(self, self.vlan_101, L2_VTR_OP.L2_POP_1).add_vpp_config()
5525
5526         #
5527         # vlan_100 and vlan_101 are anonymous l3-out interfaces
5528         #
5529         ext_itf = VppGbpExtItf(self, self.vlan_100, bd1, rd1, anon=True)
5530         ext_itf.add_vpp_config()
5531         ext_itf = VppGbpExtItf(self, self.vlan_101, bd1, rd1, anon=True)
5532         ext_itf.add_vpp_config()
5533
5534         #
5535         # an unicast vxlan-gbp for inter-RD traffic
5536         #
5537         vx_tun_l3 = VppGbpVxlanTunnel(
5538             self, 444, rd1.rd_id,
5539             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3,
5540             self.pg2.local_ip4)
5541         vx_tun_l3.add_vpp_config()
5542
5543         #
5544         # A remote external endpoint
5545         #
5546         rep = VppGbpEndpoint(self, vx_tun_l3,
5547                              epg_220, None,
5548                              "10.0.0.201", "11.0.0.201",
5549                              "2001:10::201", "3001::101",
5550                              ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
5551                              self.pg7.local_ip4,
5552                              self.pg7.remote_ip4,
5553                              mac=None)
5554         rep.add_vpp_config()
5555
5556         #
5557         # ARP packet from host in external subnet are accepted, flooded and
5558         # replied to. We expect 2 packets:
5559         #   - APR request flooded over the other vlan subif
5560         #   - ARP reply from BVI
5561         #
5562         p_arp = (Ether(src=self.vlan_100.remote_mac,
5563                        dst="ff:ff:ff:ff:ff:ff") /
5564                  Dot1Q(vlan=100) /
5565                  ARP(op="who-has",
5566                      psrc="10.0.0.100",
5567                      pdst="10.0.0.128",
5568                      hwsrc=self.vlan_100.remote_mac,
5569                      hwdst="ff:ff:ff:ff:ff:ff"))
5570         rxs = self.send_and_expect(self.pg0, p_arp * 1, self.pg0, n_rx=2)
5571
5572         p_arp = (Ether(src=self.vlan_101.remote_mac,
5573                        dst="ff:ff:ff:ff:ff:ff") /
5574                  Dot1Q(vlan=101) /
5575                  ARP(op="who-has",
5576                      psrc='10.0.0.101',
5577                      pdst="10.0.0.128",
5578                      hwsrc=self.vlan_101.remote_mac,
5579                      hwdst="ff:ff:ff:ff:ff:ff"))
5580         rxs = self.send_and_expect(self.pg0, p_arp * 1, self.pg0, n_rx=2)
5581
5582         #
5583         # remote to external
5584         #
5585         p = (Ether(src=self.pg7.remote_mac,
5586                    dst=self.pg7.local_mac) /
5587              IP(src=self.pg7.remote_ip4,
5588                 dst=self.pg7.local_ip4) /
5589              UDP(sport=1234, dport=48879) /
5590              VXLAN(vni=vx_tun_l3.vni, gpid=epg_220.sclass, flags=0x88) /
5591              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
5592              IP(src=str(rep.ip4), dst="10.0.0.100") /
5593              UDP(sport=1234, dport=1234) /
5594              Raw(b'\xa5' * 100))
5595         rxs = self.send_and_expect(self.pg7, p * 1, self.pg0)
5596
5597         #
5598         # local EP pings router
5599         #
5600         p = (Ether(src=self.vlan_100.remote_mac, dst=str(self.router_mac)) /
5601              Dot1Q(vlan=100) /
5602              IP(src="10.0.0.100", dst="10.0.0.128") /
5603              ICMP(type='echo-request'))
5604         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
5605
5606         for rx in rxs:
5607             self.assertEqual(rx[Ether].src, str(self.router_mac))
5608             self.assertEqual(rx[Ether].dst, self.vlan_100.remote_mac)
5609             self.assertEqual(rx[Dot1Q].vlan, 100)
5610
5611         #
5612         # local EP pings other local EP
5613         #
5614         p = (Ether(src=self.vlan_100.remote_mac,
5615                    dst=self.vlan_101.remote_mac) /
5616              Dot1Q(vlan=100) /
5617              IP(src="10.0.0.100", dst="10.0.0.101") /
5618              ICMP(type='echo-request'))
5619         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
5620
5621         for rx in rxs:
5622             self.assertEqual(rx[Ether].src, self.vlan_100.remote_mac)
5623             self.assertEqual(rx[Ether].dst, self.vlan_101.remote_mac)
5624             self.assertEqual(rx[Dot1Q].vlan, 101)
5625
5626         #
5627         # A subnet reachable through an external router on vlan 100
5628         #
5629         ip_220 = VppIpRoute(self, "10.220.0.0", 24,
5630                             [VppRoutePath("10.0.0.100",
5631                                           epg_220.bvi.sw_if_index)],
5632                             table_id=t4.table_id)
5633         ip_220.add_vpp_config()
5634
5635         l3o_220 = VppGbpSubnet(
5636             self, rd1, "10.220.0.0", 24,
5637             # note: this a "regular" L3 out subnet (not connected)
5638             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
5639             sclass=4220)
5640         l3o_220.add_vpp_config()
5641
5642         #
5643         # A subnet reachable through an external router on vlan 101
5644         #
5645         ip_221 = VppIpRoute(self, "10.221.0.0", 24,
5646                             [VppRoutePath("10.0.0.101",
5647                                           epg_220.bvi.sw_if_index)],
5648                             table_id=t4.table_id)
5649         ip_221.add_vpp_config()
5650
5651         l3o_221 = VppGbpSubnet(
5652             self, rd1, "10.221.0.0", 24,
5653             # note: this a "regular" L3 out subnet (not connected)
5654             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
5655             sclass=4221)
5656         l3o_221.add_vpp_config()
5657
5658         #
5659         # ping between hosts in remote subnets
5660         #  dropped without a contract
5661         #
5662         p = (Ether(src=self.vlan_100.remote_mac, dst=str(self.router_mac)) /
5663              Dot1Q(vlan=100) /
5664              IP(src="10.220.0.1", dst="10.221.0.1") /
5665              ICMP(type='echo-request'))
5666
5667         rxs = self.send_and_assert_no_replies(self.pg0, p * 1)
5668
5669         #
5670         # contract for the external nets to communicate
5671         #
5672         rule4 = AclRule(is_permit=1, proto=17)
5673         rule6 = AclRule(src_prefix=IPv6Network((0, 0)),
5674                         dst_prefix=IPv6Network((0, 0)), is_permit=1, proto=17)
5675         acl = VppAcl(self, rules=[rule4, rule6])
5676         acl.add_vpp_config()
5677
5678         c1 = VppGbpContract(
5679             self, 55, 4220, 4221, acl.acl_index,
5680             [VppGbpContractRule(
5681                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5682                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5683                 []),
5684                 VppGbpContractRule(
5685                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5686                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5687                     [])],
5688             [ETH_P_IP, ETH_P_IPV6])
5689         c1.add_vpp_config()
5690
5691         #
5692         # Contracts allowing ext-net 200 to talk with external EPs
5693         #
5694         c2 = VppGbpContract(
5695             self, 55, 4220, 113, acl.acl_index,
5696             [VppGbpContractRule(
5697                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5698                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5699                 []),
5700                 VppGbpContractRule(
5701                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5702                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5703                     [])],
5704             [ETH_P_IP, ETH_P_IPV6])
5705         c2.add_vpp_config()
5706         c3 = VppGbpContract(
5707             self, 55, 113, 4220, acl.acl_index,
5708             [VppGbpContractRule(
5709                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5710                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5711                 []),
5712                 VppGbpContractRule(
5713                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5714                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5715                     [])],
5716             [ETH_P_IP, ETH_P_IPV6])
5717         c3.add_vpp_config()
5718
5719         #
5720         # ping between hosts in remote subnets
5721         #
5722         p = (Ether(src=self.vlan_100.remote_mac, dst=str(self.router_mac)) /
5723              Dot1Q(vlan=100) /
5724              IP(src="10.220.0.1", dst="10.221.0.1") /
5725              UDP(sport=1234, dport=1234) /
5726              Raw(b'\xa5' * 100))
5727
5728         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
5729
5730         for rx in rxs:
5731             self.assertEqual(rx[Ether].src, str(self.router_mac))
5732             self.assertEqual(rx[Ether].dst, self.vlan_101.remote_mac)
5733             self.assertEqual(rx[Dot1Q].vlan, 101)
5734
5735         # we did not learn these external hosts
5736         self.assertFalse(find_gbp_endpoint(self, ip="10.220.0.1"))
5737         self.assertFalse(find_gbp_endpoint(self, ip="10.221.0.1"))
5738
5739         #
5740         # from remote external EP to local external EP
5741         #
5742         p = (Ether(src=self.pg7.remote_mac,
5743                    dst=self.pg7.local_mac) /
5744              IP(src=self.pg7.remote_ip4,
5745                 dst=self.pg7.local_ip4) /
5746              UDP(sport=1234, dport=48879) /
5747              VXLAN(vni=444, gpid=113, flags=0x88) /
5748              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
5749              IP(src=rep.ip4, dst="10.220.0.1") /
5750              UDP(sport=1234, dport=1234) /
5751              Raw(b'\xa5' * 100))
5752
5753         rxs = self.send_and_expect(self.pg7, p * 1, self.pg0)
5754
5755         #
5756         # ping from an external host to the remote external EP
5757         #
5758         p = (Ether(src=self.vlan_100.remote_mac, dst=str(self.router_mac)) /
5759              Dot1Q(vlan=100) /
5760              IP(src="10.220.0.1", dst=rep.ip4) /
5761              UDP(sport=1234, dport=1234) /
5762              Raw(b'\xa5' * 100))
5763
5764         rxs = self.send_and_expect(self.pg0, p * 1, self.pg7)
5765
5766         for rx in rxs:
5767             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
5768             # self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
5769             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
5770             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
5771             self.assertEqual(rx[VXLAN].vni, 444)
5772             self.assertTrue(rx[VXLAN].flags.G)
5773             self.assertTrue(rx[VXLAN].flags.Instance)
5774             # the sclass of the ext-net the packet came from
5775             self.assertEqual(rx[VXLAN].gpid, 4220)
5776             # policy was applied to the original IP packet
5777             self.assertTrue(rx[VXLAN].gpflags.A)
5778             # since it's an external host the reciever should not learn it
5779             self.assertTrue(rx[VXLAN].gpflags.D)
5780             inner = rx[VXLAN].payload
5781             self.assertEqual(inner[IP].src, "10.220.0.1")
5782             self.assertEqual(inner[IP].dst, rep.ip4)
5783
5784         #
5785         # An external subnet reachable via the remote external EP
5786         #
5787
5788         #
5789         # first the VXLAN-GBP tunnel over which it is reached
5790         #
5791         vx_tun_r = VppVxlanGbpTunnel(
5792             self, self.pg7.local_ip4,
5793             self.pg7.remote_ip4, 445,
5794             mode=(VppEnum.vl_api_vxlan_gbp_api_tunnel_mode_t.
5795                   VXLAN_GBP_API_TUNNEL_MODE_L3))
5796         vx_tun_r.add_vpp_config()
5797         VppIpInterfaceBind(self, vx_tun_r, t4).add_vpp_config()
5798
5799         self.logger.info(self.vapi.cli("sh vxlan-gbp tunnel"))
5800
5801         #
5802         # then the special adj to resolve through on that tunnel
5803         #
5804         n1 = VppNeighbor(self,
5805                          vx_tun_r.sw_if_index,
5806                          "00:0c:0c:0c:0c:0c",
5807                          self.pg7.remote_ip4)
5808         n1.add_vpp_config()
5809
5810         #
5811         # the route via the adj above
5812         #
5813         ip_222 = VppIpRoute(self, "10.222.0.0", 24,
5814                             [VppRoutePath(self.pg7.remote_ip4,
5815                                           vx_tun_r.sw_if_index)],
5816                             table_id=t4.table_id)
5817         ip_222.add_vpp_config()
5818
5819         l3o_222 = VppGbpSubnet(
5820             self, rd1, "10.222.0.0", 24,
5821             # note: this a "regular" l3out subnet (not connected)
5822             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
5823             sclass=4222)
5824         l3o_222.add_vpp_config()
5825
5826         #
5827         # ping between hosts in local and remote external subnets
5828         #  dropped without a contract
5829         #
5830         p = (Ether(src=self.vlan_100.remote_mac, dst=str(self.router_mac)) /
5831              Dot1Q(vlan=100) /
5832              IP(src="10.220.0.1", dst="10.222.0.1") /
5833              UDP(sport=1234, dport=1234) /
5834              Raw(b'\xa5' * 100))
5835
5836         rxs = self.send_and_assert_no_replies(self.pg0, p * 1)
5837
5838         #
5839         # Add contracts ext-nets for 220 -> 222
5840         #
5841         c4 = VppGbpContract(
5842             self, 55, 4220, 4222, acl.acl_index,
5843             [VppGbpContractRule(
5844                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5845                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5846                 []),
5847                 VppGbpContractRule(
5848                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
5849                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
5850                     [])],
5851             [ETH_P_IP, ETH_P_IPV6])
5852         c4.add_vpp_config()
5853
5854         #
5855         # ping from host in local to remote external subnets
5856         #
5857         p = (Ether(src=self.vlan_100.remote_mac, dst=str(self.router_mac)) /
5858              Dot1Q(vlan=100) /
5859              IP(src="10.220.0.1", dst="10.222.0.1") /
5860              UDP(sport=1234, dport=1234) /
5861              Raw(b'\xa5' * 100))
5862
5863         rxs = self.send_and_expect(self.pg0, p * 3, self.pg7)
5864
5865         for rx in rxs:
5866             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
5867             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
5868             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
5869             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
5870             self.assertEqual(rx[VXLAN].vni, 445)
5871             self.assertTrue(rx[VXLAN].flags.G)
5872             self.assertTrue(rx[VXLAN].flags.Instance)
5873             # the sclass of the ext-net the packet came from
5874             self.assertEqual(rx[VXLAN].gpid, 4220)
5875             # policy was applied to the original IP packet
5876             self.assertTrue(rx[VXLAN].gpflags.A)
5877             # since it's an external host the reciever should not learn it
5878             self.assertTrue(rx[VXLAN].gpflags.D)
5879             inner = rx[VXLAN].payload
5880             self.assertEqual(inner[Ether].dst, "00:0c:0c:0c:0c:0c")
5881             self.assertEqual(inner[IP].src, "10.220.0.1")
5882             self.assertEqual(inner[IP].dst, "10.222.0.1")
5883
5884         #
5885         # ping from host in remote to local external subnets
5886         # there's no contract for this, but the A bit is set.
5887         #
5888         p = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) /
5889              IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) /
5890              UDP(sport=1234, dport=48879) /
5891              VXLAN(vni=445, gpid=4222, flags=0x88, gpflags='A') /
5892              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
5893              IP(src="10.222.0.1", dst="10.220.0.1") /
5894              UDP(sport=1234, dport=1234) /
5895              Raw(b'\xa5' * 100))
5896
5897         rxs = self.send_and_expect(self.pg7, p * 3, self.pg0)
5898         self.assertFalse(find_gbp_endpoint(self, ip="10.222.0.1"))
5899
5900         #
5901         # ping from host in remote to remote external subnets
5902         #   this is dropped by reflection check.
5903         #
5904         p = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) /
5905              IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) /
5906              UDP(sport=1234, dport=48879) /
5907              VXLAN(vni=445, gpid=4222, flags=0x88, gpflags='A') /
5908              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
5909              IP(src="10.222.0.1", dst="10.222.0.2") /
5910              UDP(sport=1234, dport=1234) /
5911              Raw(b'\xa5' * 100))
5912
5913         rxs = self.send_and_assert_no_replies(self.pg7, p * 3)
5914
5915         #
5916         # cleanup
5917         #
5918         self.vlan_101.set_vtr(L2_VTR_OP.L2_DISABLED)
5919         self.vlan_100.set_vtr(L2_VTR_OP.L2_DISABLED)
5920         self.pg7.unconfig_ip4()
5921         # make sure the programmed EP is no longer learnt from DP
5922         self.wait_for_ep_timeout(sw_if_index=rep.itf.sw_if_index, ip=rep.ip4)
5923
5924
5925 if __name__ == '__main__':
5926     unittest.main(testRunner=VppTestRunner)