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