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