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