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