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