gbp: Add gbp bd flags unit test
[vpp.git] / 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
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
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
21 from vpp_l2 import VppBridgeDomain, VppBridgeDomainPort, \
22     VppBridgeDomainArpEntry, VppL2FibEntry, find_bridge_domain_port, VppL2Vtr
23 from vpp_sub_interface import L2_VTR_OP, VppDot1QSubint
24 from vpp_ip import VppIpAddress, VppIpPrefix
25 from vpp_papi import VppEnum, MACAddress
26 from vpp_vxlan_gbp_tunnel import find_vxlan_gbp_tunnel, INDEX_INVALID, \
27     VppVxlanGbpTunnel
28 from vpp_neighbor import VppNeighbor
29
30
31 def find_gbp_endpoint(test, sw_if_index=None, ip=None, mac=None):
32     if ip:
33         vip = VppIpAddress(ip)
34     if mac:
35         vmac = MACAddress(mac)
36
37     eps = test.vapi.gbp_endpoint_dump()
38
39     for ep in eps:
40         if sw_if_index:
41             if ep.endpoint.sw_if_index != sw_if_index:
42                 continue
43         if ip:
44             for eip in ep.endpoint.ips:
45                 if vip == eip:
46                     return True
47         if mac:
48             if vmac.packed == ep.endpoint.mac:
49                 return True
50     return False
51
52
53 def find_gbp_vxlan(test, vni):
54     ts = test.vapi.gbp_vxlan_tunnel_dump()
55     for t in ts:
56         if t.tunnel.vni == vni:
57             return True
58     return False
59
60
61 class VppGbpEndpoint(VppObject):
62     """
63     GBP Endpoint
64     """
65
66     @property
67     def mac(self):
68         return str(self.vmac)
69
70     @property
71     def ip4(self):
72         return self._ip4
73
74     @property
75     def fip4(self):
76         return self._fip4
77
78     @property
79     def ip6(self):
80         return self._ip6
81
82     @property
83     def fip6(self):
84         return self._fip6
85
86     @property
87     def ips(self):
88         return [self.ip4, self.ip6]
89
90     @property
91     def fips(self):
92         return [self.fip4, self.fip6]
93
94     def __init__(self, test, itf, epg, recirc, ip4, fip4, ip6, fip6,
95                  flags=0,
96                  tun_src="0.0.0.0",
97                  tun_dst="0.0.0.0",
98                  mac=True):
99         self._test = test
100         self.itf = itf
101         self.epg = epg
102         self.recirc = recirc
103
104         self._ip4 = VppIpAddress(ip4)
105         self._fip4 = VppIpAddress(fip4)
106         self._ip6 = VppIpAddress(ip6)
107         self._fip6 = VppIpAddress(fip6)
108
109         if mac:
110             self.vmac = MACAddress(self.itf.remote_mac)
111         else:
112             self.vmac = MACAddress("00:00:00:00:00:00")
113
114         self.flags = flags
115         self.tun_src = VppIpAddress(tun_src)
116         self.tun_dst = VppIpAddress(tun_dst)
117
118     def add_vpp_config(self):
119         res = self._test.vapi.gbp_endpoint_add(
120             self.itf.sw_if_index,
121             [self.ip4.encode(), self.ip6.encode()],
122             self.vmac.packed,
123             self.epg.sclass,
124             self.flags,
125             self.tun_src.encode(),
126             self.tun_dst.encode())
127         self.handle = res.handle
128         self._test.registry.register(self, self._test.logger)
129
130     def remove_vpp_config(self):
131         self._test.vapi.gbp_endpoint_del(self.handle)
132
133     def object_id(self):
134         return "gbp-endpoint:[%d==%d:%s:%d]" % (self.handle,
135                                                 self.itf.sw_if_index,
136                                                 self.ip4.address,
137                                                 self.epg.sclass)
138
139     def query_vpp_config(self):
140         return find_gbp_endpoint(self._test,
141                                  self.itf.sw_if_index,
142                                  self.ip4.address)
143
144
145 class VppGbpRecirc(VppObject):
146     """
147     GBP Recirculation Interface
148     """
149
150     def __init__(self, test, epg, recirc, is_ext=False):
151         self._test = test
152         self.recirc = recirc
153         self.epg = epg
154         self.is_ext = is_ext
155
156     def add_vpp_config(self):
157         self._test.vapi.gbp_recirc_add_del(
158             1,
159             self.recirc.sw_if_index,
160             self.epg.sclass,
161             self.is_ext)
162         self._test.registry.register(self, self._test.logger)
163
164     def remove_vpp_config(self):
165         self._test.vapi.gbp_recirc_add_del(
166             0,
167             self.recirc.sw_if_index,
168             self.epg.sclass,
169             self.is_ext)
170
171     def object_id(self):
172         return "gbp-recirc:[%d]" % (self.recirc.sw_if_index)
173
174     def query_vpp_config(self):
175         rs = self._test.vapi.gbp_recirc_dump()
176         for r in rs:
177             if r.recirc.sw_if_index == self.recirc.sw_if_index:
178                 return True
179         return False
180
181
182 class VppGbpExtItf(VppObject):
183     """
184     GBP ExtItfulation Interface
185     """
186
187     def __init__(self, test, itf, bd, rd):
188         self._test = test
189         self.itf = itf
190         self.bd = bd
191         self.rd = rd
192
193     def add_vpp_config(self):
194         self._test.vapi.gbp_ext_itf_add_del(
195             1,
196             self.itf.sw_if_index,
197             self.bd.bd_id,
198             self.rd.rd_id)
199         self._test.registry.register(self, self._test.logger)
200
201     def remove_vpp_config(self):
202         self._test.vapi.gbp_ext_itf_add_del(
203             0,
204             self.itf.sw_if_index,
205             self.bd.bd_id,
206             self.rd.rd_id)
207
208     def object_id(self):
209         return "gbp-ext-itf:[%d]" % (self.itf.sw_if_index)
210
211     def query_vpp_config(self):
212         rs = self._test.vapi.gbp_ext_itf_dump()
213         for r in rs:
214             if r.ext_itf.sw_if_index == self.itf.sw_if_index:
215                 return True
216         return False
217
218
219 class VppGbpSubnet(VppObject):
220     """
221     GBP Subnet
222     """
223     def __init__(self, test, rd, address, address_len,
224                  type, sw_if_index=None, sclass=None):
225         self._test = test
226         self.rd_id = rd.rd_id
227         self.prefix = VppIpPrefix(address, address_len)
228         self.type = type
229         self.sw_if_index = sw_if_index
230         self.sclass = sclass
231
232     def add_vpp_config(self):
233         self._test.vapi.gbp_subnet_add_del(
234             1,
235             self.rd_id,
236             self.prefix.encode(),
237             self.type,
238             sw_if_index=self.sw_if_index if self.sw_if_index else 0xffffffff,
239             sclass=self.sclass if self.sclass else 0xffff)
240         self._test.registry.register(self, self._test.logger)
241
242     def remove_vpp_config(self):
243         self._test.vapi.gbp_subnet_add_del(
244             0,
245             self.rd_id,
246             self.prefix.encode(),
247             self.type)
248
249     def object_id(self):
250         return "gbp-subnet:[%d-%s]" % (self.rd_id, self.prefix)
251
252     def query_vpp_config(self):
253         ss = self._test.vapi.gbp_subnet_dump()
254         for s in ss:
255             if s.subnet.rd_id == self.rd_id and \
256                s.subnet.type == self.type and \
257                s.subnet.prefix == self.prefix:
258                 return True
259         return False
260
261
262 class VppGbpEndpointRetention(object):
263     def __init__(self, remote_ep_timeout=0xffffffff):
264         self.remote_ep_timeout = remote_ep_timeout
265
266     def encode(self):
267         return {'remote_ep_timeout': self.remote_ep_timeout}
268
269
270 class VppGbpEndpointGroup(VppObject):
271     """
272     GBP Endpoint Group
273     """
274
275     def __init__(self, test, vnid, sclass, rd, bd, uplink,
276                  bvi, bvi_ip4, bvi_ip6=None,
277                  retention=VppGbpEndpointRetention()):
278         self._test = test
279         self.uplink = uplink
280         self.bvi = bvi
281         self.bvi_ip4 = VppIpAddress(bvi_ip4)
282         self.bvi_ip6 = VppIpAddress(bvi_ip6)
283         self.vnid = vnid
284         self.bd = bd
285         self.rd = rd
286         self.sclass = sclass
287         if 0 == self.sclass:
288             self.sclass = 0xffff
289         self.retention = retention
290
291     def add_vpp_config(self):
292         self._test.vapi.gbp_endpoint_group_add(
293             self.vnid,
294             self.sclass,
295             self.bd.bd.bd_id,
296             self.rd.rd_id,
297             self.uplink.sw_if_index if self.uplink else INDEX_INVALID,
298             self.retention.encode())
299         self._test.registry.register(self, self._test.logger)
300
301     def remove_vpp_config(self):
302         self._test.vapi.gbp_endpoint_group_del(self.sclass)
303
304     def object_id(self):
305         return "gbp-endpoint-group:[%d]" % (self.vnid)
306
307     def query_vpp_config(self):
308         epgs = self._test.vapi.gbp_endpoint_group_dump()
309         for epg in epgs:
310             if epg.epg.vnid == self.vnid:
311                 return True
312         return False
313
314
315 class VppGbpBridgeDomain(VppObject):
316     """
317     GBP Bridge Domain
318     """
319
320     def __init__(self, test, bd, bvi, uu_fwd=None,
321                  bm_flood=None, learn=True, uu_drop=False, bm_drop=False):
322         self._test = test
323         self.bvi = bvi
324         self.uu_fwd = uu_fwd
325         self.bm_flood = bm_flood
326         self.bd = bd
327
328         e = VppEnum.vl_api_gbp_bridge_domain_flags_t
329         if (learn):
330             self.learn = e.GBP_BD_API_FLAG_NONE
331         else:
332             self.learn = e.GBP_BD_API_FLAG_DO_NOT_LEARN
333         if (uu_drop):
334             self.learn |= e.GBP_BD_API_FLAG_UU_FWD_DROP
335         if (bm_drop):
336             self.learn |= e.GBP_BD_API_FLAG_MCAST_DROP
337
338     def add_vpp_config(self):
339         self._test.vapi.gbp_bridge_domain_add(
340             self.bd.bd_id,
341             self.learn,
342             self.bvi.sw_if_index,
343             self.uu_fwd.sw_if_index if self.uu_fwd else INDEX_INVALID,
344             self.bm_flood.sw_if_index if self.bm_flood else INDEX_INVALID)
345         self._test.registry.register(self, self._test.logger)
346
347     def remove_vpp_config(self):
348         self._test.vapi.gbp_bridge_domain_del(self.bd.bd_id)
349
350     def object_id(self):
351         return "gbp-bridge-domain:[%d]" % (self.bd.bd_id)
352
353     def query_vpp_config(self):
354         bds = self._test.vapi.gbp_bridge_domain_dump()
355         for bd in bds:
356             if bd.bd.bd_id == self.bd.bd_id:
357                 return True
358         return False
359
360
361 class VppGbpRouteDomain(VppObject):
362     """
363     GBP Route Domain
364     """
365
366     def __init__(self, test, rd_id, t4, t6, ip4_uu=None, ip6_uu=None):
367         self._test = test
368         self.rd_id = rd_id
369         self.t4 = t4
370         self.t6 = t6
371         self.ip4_uu = ip4_uu
372         self.ip6_uu = ip6_uu
373
374     def add_vpp_config(self):
375         self._test.vapi.gbp_route_domain_add(
376             self.rd_id,
377             self.t4.table_id,
378             self.t6.table_id,
379             self.ip4_uu.sw_if_index if self.ip4_uu else INDEX_INVALID,
380             self.ip6_uu.sw_if_index if self.ip6_uu else INDEX_INVALID)
381         self._test.registry.register(self, self._test.logger)
382
383     def remove_vpp_config(self):
384         self._test.vapi.gbp_route_domain_del(self.rd_id)
385
386     def object_id(self):
387         return "gbp-route-domain:[%d]" % (self.rd_id)
388
389     def query_vpp_config(self):
390         rds = self._test.vapi.gbp_route_domain_dump()
391         for rd in rds:
392             if rd.rd.rd_id == self.rd_id:
393                 return True
394         return False
395
396
397 class VppGbpContractNextHop():
398     def __init__(self, mac, bd, ip, rd):
399         self.mac = mac
400         self.ip = ip
401         self.bd = bd
402         self.rd = rd
403
404     def encode(self):
405         return {'ip': self.ip.encode(),
406                 'mac': self.mac.packed,
407                 'bd_id': self.bd.bd.bd_id,
408                 'rd_id': self.rd.rd_id}
409
410
411 class VppGbpContractRule():
412     def __init__(self, action, hash_mode, nhs=[]):
413         self.action = action
414         self.hash_mode = hash_mode
415         self.nhs = nhs
416
417     def encode(self):
418         nhs = []
419         for nh in self.nhs:
420             nhs.append(nh.encode())
421         while len(nhs) < 8:
422             nhs.append({})
423         return {'action': self.action,
424                 'nh_set': {
425                     'hash_mode': self.hash_mode,
426                     'n_nhs': len(self.nhs),
427                     'nhs': nhs}}
428
429
430 class VppGbpContract(VppObject):
431     """
432     GBP Contract
433     """
434
435     def __init__(self, test, sclass, dclass, acl_index,
436                  rules, allowed_ethertypes):
437         self._test = test
438         self.acl_index = acl_index
439         self.sclass = sclass
440         self.dclass = dclass
441         self.rules = rules
442         self.allowed_ethertypes = allowed_ethertypes
443         while (len(self.allowed_ethertypes) < 16):
444             self.allowed_ethertypes.append(0)
445
446     def add_vpp_config(self):
447         rules = []
448         for r in self.rules:
449             rules.append(r.encode())
450         self._test.vapi.gbp_contract_add_del(
451             1,
452             self.sclass,
453             self.dclass,
454             self.acl_index,
455             rules,
456             self.allowed_ethertypes)
457         self._test.registry.register(self, self._test.logger)
458
459     def remove_vpp_config(self):
460         self._test.vapi.gbp_contract_add_del(
461             0,
462             self.sclass,
463             self.dclass,
464             self.acl_index,
465             [],
466             self.allowed_ethertypes)
467
468     def object_id(self):
469         return "gbp-contract:[%d:%s:%d]" % (self.sclass,
470                                             self.dclass,
471                                             self.acl_index)
472
473     def query_vpp_config(self):
474         cs = self._test.vapi.gbp_contract_dump()
475         for c in cs:
476             if c.contract.sclass == self.sclass \
477                and c.contract.dclass == self.dclass:
478                 return True
479         return False
480
481
482 class VppGbpVxlanTunnel(VppInterface):
483     """
484     GBP VXLAN tunnel
485     """
486
487     def __init__(self, test, vni, bd_rd_id, mode, src):
488         super(VppGbpVxlanTunnel, self).__init__(test)
489         self._test = test
490         self.vni = vni
491         self.bd_rd_id = bd_rd_id
492         self.mode = mode
493         self.src = src
494
495     def add_vpp_config(self):
496         r = self._test.vapi.gbp_vxlan_tunnel_add(
497             self.vni,
498             self.bd_rd_id,
499             self.mode,
500             self.src)
501         self.set_sw_if_index(r.sw_if_index)
502         self._test.registry.register(self, self._test.logger)
503
504     def remove_vpp_config(self):
505         self._test.vapi.gbp_vxlan_tunnel_del(self.vni)
506
507     def object_id(self):
508         return "gbp-vxlan:%d" % (self.sw_if_index)
509
510     def query_vpp_config(self):
511         return find_gbp_vxlan(self._test, self.vni)
512
513
514 class VppGbpAcl(VppObject):
515     """
516     GBP Acl
517     """
518
519     def __init__(self, test):
520         self._test = test
521         self.acl_index = 4294967295
522
523     def create_rule(self, is_ipv6=0, permit_deny=0, proto=-1,
524                     s_prefix=0, s_ip=b'\x00\x00\x00\x00', sport_from=0,
525                     sport_to=65535, d_prefix=0, d_ip=b'\x00\x00\x00\x00',
526                     dport_from=0, dport_to=65535):
527         if proto == -1 or proto == 0:
528             sport_to = 0
529             dport_to = sport_to
530         elif proto == 1 or proto == 58:
531             sport_to = 255
532             dport_to = sport_to
533         rule = ({'is_permit': permit_deny, 'is_ipv6': is_ipv6, 'proto': proto,
534                  'srcport_or_icmptype_first': sport_from,
535                  'srcport_or_icmptype_last': sport_to,
536                  'src_ip_prefix_len': s_prefix,
537                  'src_ip_addr': s_ip,
538                  'dstport_or_icmpcode_first': dport_from,
539                  'dstport_or_icmpcode_last': dport_to,
540                  'dst_ip_prefix_len': d_prefix,
541                  'dst_ip_addr': d_ip})
542         return rule
543
544     def add_vpp_config(self, rules):
545
546         reply = self._test.vapi.acl_add_replace(self.acl_index,
547                                                 r=rules,
548                                                 tag=b'GBPTest')
549         self.acl_index = reply.acl_index
550         return self.acl_index
551
552     def remove_vpp_config(self):
553         self._test.vapi.acl_del(self.acl_index)
554
555     def object_id(self):
556         return "gbp-acl:[%d]" % (self.acl_index)
557
558     def query_vpp_config(self):
559         cs = self._test.vapi.acl_dump()
560         for c in cs:
561             if c.acl_index == self.acl_index:
562                 return True
563         return False
564
565
566 class TestGBP(VppTestCase):
567     """ GBP Test Case """
568
569     def setUp(self):
570         super(TestGBP, self).setUp()
571
572         self.create_pg_interfaces(range(9))
573         self.create_loopback_interfaces(8)
574
575         self.router_mac = MACAddress("00:11:22:33:44:55")
576
577         for i in self.pg_interfaces:
578             i.admin_up()
579         for i in self.lo_interfaces:
580             i.admin_up()
581
582     def tearDown(self):
583         for i in self.pg_interfaces:
584             i.admin_down()
585
586         super(TestGBP, self).tearDown()
587
588     def send_and_expect_bridged(self, src, tx, dst):
589         rx = self.send_and_expect(src, tx, dst)
590
591         for r in rx:
592             self.assertEqual(r[Ether].src, tx[0][Ether].src)
593             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
594             self.assertEqual(r[IP].src, tx[0][IP].src)
595             self.assertEqual(r[IP].dst, tx[0][IP].dst)
596         return rx
597
598     def send_and_expect_bridged6(self, src, tx, dst):
599         rx = self.send_and_expect(src, tx, dst)
600
601         for r in rx:
602             self.assertEqual(r[Ether].src, tx[0][Ether].src)
603             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
604             self.assertEqual(r[IPv6].src, tx[0][IPv6].src)
605             self.assertEqual(r[IPv6].dst, tx[0][IPv6].dst)
606         return rx
607
608     def send_and_expect_routed(self, src, tx, dst, src_mac):
609         rx = self.send_and_expect(src, tx, dst)
610
611         for r in rx:
612             self.assertEqual(r[Ether].src, src_mac)
613             self.assertEqual(r[Ether].dst, dst.remote_mac)
614             self.assertEqual(r[IP].src, tx[0][IP].src)
615             self.assertEqual(r[IP].dst, tx[0][IP].dst)
616         return rx
617
618     def send_and_expect_natted(self, src, tx, dst, src_ip):
619         rx = self.send_and_expect(src, tx, dst)
620
621         for r in rx:
622             self.assertEqual(r[Ether].src, tx[0][Ether].src)
623             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
624             self.assertEqual(r[IP].src, src_ip)
625             self.assertEqual(r[IP].dst, tx[0][IP].dst)
626         return rx
627
628     def send_and_expect_natted6(self, src, tx, dst, src_ip):
629         rx = self.send_and_expect(src, tx, dst)
630
631         for r in rx:
632             self.assertEqual(r[Ether].src, tx[0][Ether].src)
633             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
634             self.assertEqual(r[IPv6].src, src_ip)
635             self.assertEqual(r[IPv6].dst, tx[0][IPv6].dst)
636         return rx
637
638     def send_and_expect_unnatted(self, src, tx, dst, dst_ip):
639         rx = self.send_and_expect(src, tx, dst)
640
641         for r in rx:
642             self.assertEqual(r[Ether].src, tx[0][Ether].src)
643             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
644             self.assertEqual(r[IP].dst, dst_ip)
645             self.assertEqual(r[IP].src, tx[0][IP].src)
646         return rx
647
648     def send_and_expect_unnatted6(self, src, tx, dst, dst_ip):
649         rx = self.send_and_expect(src, tx, dst)
650
651         for r in rx:
652             self.assertEqual(r[Ether].src, tx[0][Ether].src)
653             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
654             self.assertEqual(r[IPv6].dst, dst_ip)
655             self.assertEqual(r[IPv6].src, tx[0][IPv6].src)
656         return rx
657
658     def send_and_expect_double_natted(self, src, tx, dst, src_ip, dst_ip):
659         rx = self.send_and_expect(src, tx, dst)
660
661         for r in rx:
662             self.assertEqual(r[Ether].src, str(self.router_mac))
663             self.assertEqual(r[Ether].dst, dst.remote_mac)
664             self.assertEqual(r[IP].dst, dst_ip)
665             self.assertEqual(r[IP].src, src_ip)
666         return rx
667
668     def send_and_expect_double_natted6(self, src, tx, dst, src_ip, dst_ip):
669         rx = self.send_and_expect(src, tx, dst)
670
671         for r in rx:
672             self.assertEqual(r[Ether].src, str(self.router_mac))
673             self.assertEqual(r[Ether].dst, dst.remote_mac)
674             self.assertEqual(r[IPv6].dst, dst_ip)
675             self.assertEqual(r[IPv6].src, src_ip)
676         return rx
677
678     def test_gbp(self):
679         """ Group Based Policy """
680
681         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
682
683         #
684         # Bridge Domains
685         #
686         bd1 = VppBridgeDomain(self, 1)
687         bd2 = VppBridgeDomain(self, 2)
688         bd20 = VppBridgeDomain(self, 20)
689
690         bd1.add_vpp_config()
691         bd2.add_vpp_config()
692         bd20.add_vpp_config()
693
694         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0)
695         gbd2 = VppGbpBridgeDomain(self, bd2, self.loop1)
696         gbd20 = VppGbpBridgeDomain(self, bd20, self.loop2)
697
698         gbd1.add_vpp_config()
699         gbd2.add_vpp_config()
700         gbd20.add_vpp_config()
701
702         #
703         # Route Domains
704         #
705         gt4 = VppIpTable(self, 0)
706         gt4.add_vpp_config()
707         gt6 = VppIpTable(self, 0, is_ip6=True)
708         gt6.add_vpp_config()
709         nt4 = VppIpTable(self, 20)
710         nt4.add_vpp_config()
711         nt6 = VppIpTable(self, 20, is_ip6=True)
712         nt6.add_vpp_config()
713
714         rd0 = VppGbpRouteDomain(self, 0, gt4, gt6, None, None)
715         rd20 = VppGbpRouteDomain(self, 20, nt4, nt6, None, None)
716
717         rd0.add_vpp_config()
718         rd20.add_vpp_config()
719
720         #
721         # 3 EPGs, 2 of which share a BD.
722         # 2 NAT EPGs, one for floating-IP subnets, the other for internet
723         #
724         epgs = [VppGbpEndpointGroup(self, 220, 1220, rd0, gbd1,
725                                     self.pg4, self.loop0,
726                                     "10.0.0.128", "2001:10::128"),
727                 VppGbpEndpointGroup(self, 221, 1221, rd0, gbd1,
728                                     self.pg5, self.loop0,
729                                     "10.0.1.128", "2001:10:1::128"),
730                 VppGbpEndpointGroup(self, 222, 1222, rd0, gbd2,
731                                     self.pg6, self.loop1,
732                                     "10.0.2.128", "2001:10:2::128"),
733                 VppGbpEndpointGroup(self, 333, 1333, rd20, gbd20,
734                                     self.pg7, self.loop2,
735                                     "11.0.0.128", "3001::128"),
736                 VppGbpEndpointGroup(self, 444, 1444, rd20, gbd20,
737                                     self.pg8, self.loop2,
738                                     "11.0.0.129", "3001::129")]
739         recircs = [VppGbpRecirc(self, epgs[0], self.loop3),
740                    VppGbpRecirc(self, epgs[1], self.loop4),
741                    VppGbpRecirc(self, epgs[2], self.loop5),
742                    VppGbpRecirc(self, epgs[3], self.loop6, is_ext=True),
743                    VppGbpRecirc(self, epgs[4], self.loop7, is_ext=True)]
744
745         epg_nat = epgs[3]
746         recirc_nat = recircs[3]
747
748         #
749         # 4 end-points, 2 in the same subnet, 3 in the same BD
750         #
751         eps = [VppGbpEndpoint(self, self.pg0,
752                               epgs[0], recircs[0],
753                               "10.0.0.1", "11.0.0.1",
754                               "2001:10::1", "3001::1"),
755                VppGbpEndpoint(self, self.pg1,
756                               epgs[0], recircs[0],
757                               "10.0.0.2", "11.0.0.2",
758                               "2001:10::2", "3001::2"),
759                VppGbpEndpoint(self, self.pg2,
760                               epgs[1], recircs[1],
761                               "10.0.1.1", "11.0.0.3",
762                               "2001:10:1::1", "3001::3"),
763                VppGbpEndpoint(self, self.pg3,
764                               epgs[2], recircs[2],
765                               "10.0.2.1", "11.0.0.4",
766                               "2001:10:2::1", "3001::4")]
767
768         #
769         # Config related to each of the EPGs
770         #
771         for epg in epgs:
772             # IP config on the BVI interfaces
773             if epg != epgs[1] and epg != epgs[4]:
774                 VppIpInterfaceBind(self, epg.bvi, epg.rd.t4).add_vpp_config()
775                 VppIpInterfaceBind(self, epg.bvi, epg.rd.t6).add_vpp_config()
776                 self.vapi.sw_interface_set_mac_address(
777                     epg.bvi.sw_if_index,
778                     self.router_mac.packed)
779
780                 # The BVIs are NAT inside interfaces
781                 self.vapi.nat44_interface_add_del_feature(epg.bvi.sw_if_index,
782                                                           is_inside=1,
783                                                           is_add=1)
784                 self.vapi.nat66_add_del_interface(epg.bvi.sw_if_index,
785                                                   is_inside=1,
786                                                   is_add=1)
787
788             if_ip4 = VppIpInterfaceAddress(self, epg.bvi, epg.bvi_ip4, 32)
789             if_ip6 = VppIpInterfaceAddress(self, epg.bvi, epg.bvi_ip6, 128)
790             if_ip4.add_vpp_config()
791             if_ip6.add_vpp_config()
792
793             # EPG uplink interfaces in the RD
794             VppIpInterfaceBind(self, epg.uplink, epg.rd.t4).add_vpp_config()
795             VppIpInterfaceBind(self, epg.uplink, epg.rd.t6).add_vpp_config()
796
797             # add the BD ARP termination entry for BVI IP
798             epg.bd_arp_ip4 = VppBridgeDomainArpEntry(self, epg.bd.bd,
799                                                      str(self.router_mac),
800                                                      epg.bvi_ip4)
801             epg.bd_arp_ip6 = VppBridgeDomainArpEntry(self, epg.bd.bd,
802                                                      str(self.router_mac),
803                                                      epg.bvi_ip6)
804             epg.bd_arp_ip4.add_vpp_config()
805             epg.bd_arp_ip6.add_vpp_config()
806
807             # EPG in VPP
808             epg.add_vpp_config()
809
810         for recirc in recircs:
811             # EPG's ingress recirculation interface maps to its RD
812             VppIpInterfaceBind(self, recirc.recirc,
813                                recirc.epg.rd.t4).add_vpp_config()
814             VppIpInterfaceBind(self, recirc.recirc,
815                                recirc.epg.rd.t6).add_vpp_config()
816
817             self.vapi.nat44_interface_add_del_feature(
818                 recirc.recirc.sw_if_index,
819                 is_inside=0,
820                 is_add=1)
821             self.vapi.nat66_add_del_interface(
822                 recirc.recirc.sw_if_index,
823                 is_inside=0,
824                 is_add=1)
825
826             recirc.add_vpp_config()
827
828         for recirc in recircs:
829             self.assertTrue(find_bridge_domain_port(self,
830                                                     recirc.epg.bd.bd.bd_id,
831                                                     recirc.recirc.sw_if_index))
832
833         for ep in eps:
834             self.pg_enable_capture(self.pg_interfaces)
835             self.pg_start()
836             #
837             # routes to the endpoints. We need these since there are no
838             # adj-fibs due to the fact the the BVI address has /32 and
839             # the subnet is not attached.
840             #
841             for (ip, fip) in zip(ep.ips, ep.fips):
842                 # Add static mappings for each EP from the 10/8 to 11/8 network
843                 if ip.af == AF_INET:
844                     self.vapi.nat44_add_del_static_mapping(ip.bytes,
845                                                            fip.bytes,
846                                                            vrf_id=0,
847                                                            addr_only=1)
848                 else:
849                     self.vapi.nat66_add_del_static_mapping(ip.bytes,
850                                                            fip.bytes,
851                                                            vrf_id=0)
852
853             # VPP EP create ...
854             ep.add_vpp_config()
855
856             self.logger.info(self.vapi.cli("sh gbp endpoint"))
857
858             # ... results in a Gratuitous ARP/ND on the EPG's uplink
859             rx = ep.epg.uplink.get_capture(len(ep.ips), timeout=0.2)
860
861             for ii, ip in enumerate(ep.ips):
862                 p = rx[ii]
863
864                 if ip.is_ip6:
865                     self.assertTrue(p.haslayer(ICMPv6ND_NA))
866                     self.assertEqual(p[ICMPv6ND_NA].tgt, ip.address)
867                 else:
868                     self.assertTrue(p.haslayer(ARP))
869                     self.assertEqual(p[ARP].psrc, ip.address)
870                     self.assertEqual(p[ARP].pdst, ip.address)
871
872             # add the BD ARP termination entry for floating IP
873             for fip in ep.fips:
874                 ba = VppBridgeDomainArpEntry(self, epg_nat.bd.bd, ep.mac, fip)
875                 ba.add_vpp_config()
876
877                 # floating IPs route via EPG recirc
878                 r = VppIpRoute(self, fip.address, fip.length,
879                                [VppRoutePath(fip.address,
880                                              ep.recirc.recirc.sw_if_index,
881                                              is_dvr=1,
882                                              proto=fip.dpo_proto)],
883                                table_id=20,
884                                is_ip6=fip.is_ip6)
885                 r.add_vpp_config()
886
887             # L2 FIB entries in the NAT EPG BD to bridge the packets from
888             # the outside direct to the internal EPG
889             lf = VppL2FibEntry(self, epg_nat.bd.bd, ep.mac,
890                                ep.recirc.recirc, bvi_mac=0)
891             lf.add_vpp_config()
892
893         #
894         # ARP packets for unknown IP are sent to the EPG uplink
895         #
896         pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff",
897                          src=self.pg0.remote_mac) /
898                    ARP(op="who-has",
899                        hwdst="ff:ff:ff:ff:ff:ff",
900                        hwsrc=self.pg0.remote_mac,
901                        pdst="10.0.0.88",
902                        psrc="10.0.0.99"))
903
904         self.vapi.cli("clear trace")
905         self.pg0.add_stream(pkt_arp)
906
907         self.pg_enable_capture(self.pg_interfaces)
908         self.pg_start()
909
910         rxd = epgs[0].uplink.get_capture(1)
911
912         #
913         # ARP/ND packets get a response
914         #
915         pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff",
916                          src=self.pg0.remote_mac) /
917                    ARP(op="who-has",
918                        hwdst="ff:ff:ff:ff:ff:ff",
919                        hwsrc=self.pg0.remote_mac,
920                        pdst=epgs[0].bvi_ip4.address,
921                        psrc=eps[0].ip4.address))
922
923         self.send_and_expect(self.pg0, [pkt_arp], self.pg0)
924
925         nsma = in6_getnsma(inet_pton(AF_INET6, eps[0].ip6.address))
926         d = inet_ntop(AF_INET6, nsma)
927         pkt_nd = (Ether(dst=in6_getnsmac(nsma),
928                         src=self.pg0.remote_mac) /
929                   IPv6(dst=d, src=eps[0].ip6.address) /
930                   ICMPv6ND_NS(tgt=epgs[0].bvi_ip6.address) /
931                   ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac))
932         self.send_and_expect(self.pg0, [pkt_nd], self.pg0)
933
934         #
935         # broadcast packets are flooded
936         #
937         pkt_bcast = (Ether(dst="ff:ff:ff:ff:ff:ff",
938                            src=self.pg0.remote_mac) /
939                      IP(src=eps[0].ip4.address, dst="232.1.1.1") /
940                      UDP(sport=1234, dport=1234) /
941                      Raw('\xa5' * 100))
942
943         self.vapi.cli("clear trace")
944         self.pg0.add_stream(pkt_bcast)
945
946         self.pg_enable_capture(self.pg_interfaces)
947         self.pg_start()
948
949         rxd = eps[1].itf.get_capture(1)
950         self.assertEqual(rxd[0][Ether].dst, pkt_bcast[Ether].dst)
951         rxd = epgs[0].uplink.get_capture(1)
952         self.assertEqual(rxd[0][Ether].dst, pkt_bcast[Ether].dst)
953
954         #
955         # packets to non-local L3 destinations dropped
956         #
957         pkt_intra_epg_220_ip4 = (Ether(src=self.pg0.remote_mac,
958                                        dst=str(self.router_mac)) /
959                                  IP(src=eps[0].ip4.address,
960                                     dst="10.0.0.99") /
961                                  UDP(sport=1234, dport=1234) /
962                                  Raw('\xa5' * 100))
963         pkt_inter_epg_222_ip4 = (Ether(src=self.pg0.remote_mac,
964                                        dst=str(self.router_mac)) /
965                                  IP(src=eps[0].ip4.address,
966                                     dst="10.0.1.99") /
967                                  UDP(sport=1234, dport=1234) /
968                                  Raw('\xa5' * 100))
969
970         self.send_and_assert_no_replies(self.pg0, pkt_intra_epg_220_ip4 * 65)
971
972         pkt_inter_epg_222_ip6 = (Ether(src=self.pg0.remote_mac,
973                                        dst=str(self.router_mac)) /
974                                  IPv6(src=eps[0].ip6.address,
975                                       dst="2001:10::99") /
976                                  UDP(sport=1234, dport=1234) /
977                                  Raw('\xa5' * 100))
978         self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_222_ip6 * 65)
979
980         #
981         # Add the subnet routes
982         #
983         s41 = VppGbpSubnet(
984             self, rd0, "10.0.0.0", 24,
985             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
986         s42 = VppGbpSubnet(
987             self, rd0, "10.0.1.0", 24,
988             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
989         s43 = VppGbpSubnet(
990             self, rd0, "10.0.2.0", 24,
991             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
992         s61 = VppGbpSubnet(
993             self, rd0, "2001:10::1", 64,
994             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
995         s62 = VppGbpSubnet(
996             self, rd0, "2001:10:1::1", 64,
997             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
998         s63 = VppGbpSubnet(
999             self, rd0, "2001:10:2::1", 64,
1000             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
1001         s41.add_vpp_config()
1002         s42.add_vpp_config()
1003         s43.add_vpp_config()
1004         s61.add_vpp_config()
1005         s62.add_vpp_config()
1006         s63.add_vpp_config()
1007
1008         self.send_and_expect_bridged(eps[0].itf,
1009                                      pkt_intra_epg_220_ip4 * 65,
1010                                      eps[0].epg.uplink)
1011         self.send_and_expect_bridged(eps[0].itf,
1012                                      pkt_inter_epg_222_ip4 * 65,
1013                                      eps[0].epg.uplink)
1014         self.send_and_expect_bridged6(eps[0].itf,
1015                                       pkt_inter_epg_222_ip6 * 65,
1016                                       eps[0].epg.uplink)
1017
1018         self.logger.info(self.vapi.cli("sh ip fib 11.0.0.2"))
1019         self.logger.info(self.vapi.cli("sh gbp endpoint-group"))
1020         self.logger.info(self.vapi.cli("sh gbp endpoint"))
1021         self.logger.info(self.vapi.cli("sh gbp recirc"))
1022         self.logger.info(self.vapi.cli("sh int"))
1023         self.logger.info(self.vapi.cli("sh int addr"))
1024         self.logger.info(self.vapi.cli("sh int feat loop6"))
1025         self.logger.info(self.vapi.cli("sh vlib graph ip4-gbp-src-classify"))
1026         self.logger.info(self.vapi.cli("sh int feat loop3"))
1027         self.logger.info(self.vapi.cli("sh int feat pg0"))
1028
1029         #
1030         # Packet destined to unknown unicast is sent on the epg uplink ...
1031         #
1032         pkt_intra_epg_220_to_uplink = (Ether(src=self.pg0.remote_mac,
1033                                              dst="00:00:00:33:44:55") /
1034                                        IP(src=eps[0].ip4.address,
1035                                           dst="10.0.0.99") /
1036                                        UDP(sport=1234, dport=1234) /
1037                                        Raw('\xa5' * 100))
1038
1039         self.send_and_expect_bridged(eps[0].itf,
1040                                      pkt_intra_epg_220_to_uplink * 65,
1041                                      eps[0].epg.uplink)
1042         # ... and nowhere else
1043         self.pg1.get_capture(0, timeout=0.1)
1044         self.pg1.assert_nothing_captured(remark="Flood onto other VMS")
1045
1046         pkt_intra_epg_221_to_uplink = (Ether(src=self.pg2.remote_mac,
1047                                              dst="00:00:00:33:44:66") /
1048                                        IP(src=eps[0].ip4.address,
1049                                           dst="10.0.0.99") /
1050                                        UDP(sport=1234, dport=1234) /
1051                                        Raw('\xa5' * 100))
1052
1053         self.send_and_expect_bridged(eps[2].itf,
1054                                      pkt_intra_epg_221_to_uplink * 65,
1055                                      eps[2].epg.uplink)
1056
1057         #
1058         # Packets from the uplink are forwarded in the absence of a contract
1059         #
1060         pkt_intra_epg_220_from_uplink = (Ether(src="00:00:00:33:44:55",
1061                                                dst=self.pg0.remote_mac) /
1062                                          IP(src=eps[0].ip4.address,
1063                                             dst="10.0.0.99") /
1064                                          UDP(sport=1234, dport=1234) /
1065                                          Raw('\xa5' * 100))
1066
1067         self.send_and_expect_bridged(self.pg4,
1068                                      pkt_intra_epg_220_from_uplink * 65,
1069                                      self.pg0)
1070
1071         #
1072         # in the absence of policy, endpoints in the same EPG
1073         # can communicate
1074         #
1075         pkt_intra_epg = (Ether(src=self.pg0.remote_mac,
1076                                dst=self.pg1.remote_mac) /
1077                          IP(src=eps[0].ip4.address,
1078                             dst=eps[1].ip4.address) /
1079                          UDP(sport=1234, dport=1234) /
1080                          Raw('\xa5' * 100))
1081
1082         self.send_and_expect_bridged(self.pg0, pkt_intra_epg * 65, self.pg1)
1083
1084         #
1085         # in the absence of policy, endpoints in the different EPG
1086         # cannot communicate
1087         #
1088         pkt_inter_epg_220_to_221 = (Ether(src=self.pg0.remote_mac,
1089                                           dst=self.pg2.remote_mac) /
1090                                     IP(src=eps[0].ip4.address,
1091                                        dst=eps[2].ip4.address) /
1092                                     UDP(sport=1234, dport=1234) /
1093                                     Raw('\xa5' * 100))
1094         pkt_inter_epg_221_to_220 = (Ether(src=self.pg2.remote_mac,
1095                                           dst=self.pg0.remote_mac) /
1096                                     IP(src=eps[2].ip4.address,
1097                                        dst=eps[0].ip4.address) /
1098                                     UDP(sport=1234, dport=1234) /
1099                                     Raw('\xa5' * 100))
1100         pkt_inter_epg_220_to_222 = (Ether(src=self.pg0.remote_mac,
1101                                           dst=str(self.router_mac)) /
1102                                     IP(src=eps[0].ip4.address,
1103                                        dst=eps[3].ip4.address) /
1104                                     UDP(sport=1234, dport=1234) /
1105                                     Raw('\xa5' * 100))
1106
1107         self.send_and_assert_no_replies(eps[0].itf,
1108                                         pkt_inter_epg_220_to_221 * 65)
1109         self.send_and_assert_no_replies(eps[0].itf,
1110                                         pkt_inter_epg_220_to_222 * 65)
1111
1112         #
1113         # A uni-directional contract from EPG 220 -> 221
1114         #
1115         acl = VppGbpAcl(self)
1116         rule = acl.create_rule(permit_deny=1, proto=17)
1117         rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
1118         acl_index = acl.add_vpp_config([rule, rule2])
1119         c1 = VppGbpContract(
1120             self, epgs[0].sclass, epgs[1].sclass, acl_index,
1121             [VppGbpContractRule(
1122                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1123                 []),
1124              VppGbpContractRule(
1125                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1126                  [])],
1127             [ETH_P_IP, ETH_P_IPV6])
1128         c1.add_vpp_config()
1129
1130         self.send_and_expect_bridged(eps[0].itf,
1131                                      pkt_inter_epg_220_to_221 * 65,
1132                                      eps[2].itf)
1133         self.send_and_assert_no_replies(eps[0].itf,
1134                                         pkt_inter_epg_220_to_222 * 65)
1135
1136         #
1137         # contract for the return direction
1138         #
1139         c2 = VppGbpContract(
1140             self, epgs[1].sclass, epgs[0].sclass, acl_index,
1141             [VppGbpContractRule(
1142                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1143                 []),
1144              VppGbpContractRule(
1145                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1146                  [])],
1147             [ETH_P_IP, ETH_P_IPV6])
1148         c2.add_vpp_config()
1149
1150         self.send_and_expect_bridged(eps[0].itf,
1151                                      pkt_inter_epg_220_to_221 * 65,
1152                                      eps[2].itf)
1153         self.send_and_expect_bridged(eps[2].itf,
1154                                      pkt_inter_epg_221_to_220 * 65,
1155                                      eps[0].itf)
1156
1157         #
1158         # the contract does not allow non-IP
1159         #
1160         pkt_non_ip_inter_epg_220_to_221 = (Ether(src=self.pg0.remote_mac,
1161                                                  dst=self.pg2.remote_mac) /
1162                                            ARP())
1163         self.send_and_assert_no_replies(eps[0].itf,
1164                                         pkt_non_ip_inter_epg_220_to_221 * 17)
1165
1166         #
1167         # check that inter group is still disabled for the groups
1168         # not in the contract.
1169         #
1170         self.send_and_assert_no_replies(eps[0].itf,
1171                                         pkt_inter_epg_220_to_222 * 65)
1172
1173         #
1174         # A uni-directional contract from EPG 220 -> 222 'L3 routed'
1175         #
1176         c3 = VppGbpContract(
1177             self, epgs[0].sclass, epgs[2].sclass, acl_index,
1178             [VppGbpContractRule(
1179                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1180                 []),
1181              VppGbpContractRule(
1182                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1183                  [])],
1184             [ETH_P_IP, ETH_P_IPV6])
1185         c3.add_vpp_config()
1186
1187         self.logger.info(self.vapi.cli("sh gbp contract"))
1188
1189         self.send_and_expect_routed(eps[0].itf,
1190                                     pkt_inter_epg_220_to_222 * 65,
1191                                     eps[3].itf,
1192                                     str(self.router_mac))
1193
1194         #
1195         # remove both contracts, traffic stops in both directions
1196         #
1197         c2.remove_vpp_config()
1198         c1.remove_vpp_config()
1199         c3.remove_vpp_config()
1200         acl.remove_vpp_config()
1201
1202         self.send_and_assert_no_replies(eps[2].itf,
1203                                         pkt_inter_epg_221_to_220 * 65)
1204         self.send_and_assert_no_replies(eps[0].itf,
1205                                         pkt_inter_epg_220_to_221 * 65)
1206         self.send_and_expect_bridged(eps[0].itf,
1207                                      pkt_intra_epg * 65,
1208                                      eps[1].itf)
1209
1210         #
1211         # EPs to the outside world
1212         #
1213
1214         # in the EP's RD an external subnet via the NAT EPG's recirc
1215         se1 = VppGbpSubnet(
1216             self, rd0, "0.0.0.0", 0,
1217             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1218             sw_if_index=recirc_nat.recirc.sw_if_index,
1219             sclass=epg_nat.sclass)
1220         se2 = VppGbpSubnet(
1221             self, rd0, "11.0.0.0", 8,
1222             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1223             sw_if_index=recirc_nat.recirc.sw_if_index,
1224             sclass=epg_nat.sclass)
1225         se16 = VppGbpSubnet(
1226             self, rd0, "::", 0,
1227             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1228             sw_if_index=recirc_nat.recirc.sw_if_index,
1229             sclass=epg_nat.sclass)
1230         # in the NAT RD an external subnet via the NAT EPG's uplink
1231         se3 = VppGbpSubnet(
1232             self, rd20, "0.0.0.0", 0,
1233             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1234             sw_if_index=epg_nat.uplink.sw_if_index,
1235             sclass=epg_nat.sclass)
1236         se36 = VppGbpSubnet(
1237             self, rd20, "::", 0,
1238             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1239             sw_if_index=epg_nat.uplink.sw_if_index,
1240             sclass=epg_nat.sclass)
1241         se4 = VppGbpSubnet(
1242             self, rd20, "11.0.0.0", 8,
1243             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1244             sw_if_index=epg_nat.uplink.sw_if_index,
1245             sclass=epg_nat.sclass)
1246         se1.add_vpp_config()
1247         se2.add_vpp_config()
1248         se16.add_vpp_config()
1249         se3.add_vpp_config()
1250         se36.add_vpp_config()
1251         se4.add_vpp_config()
1252
1253         self.logger.info(self.vapi.cli("sh ip fib 0.0.0.0/0"))
1254         self.logger.info(self.vapi.cli("sh ip fib 11.0.0.1"))
1255         self.logger.info(self.vapi.cli("sh ip6 fib ::/0"))
1256         self.logger.info(self.vapi.cli("sh ip6 fib %s" %
1257                                        eps[0].fip6))
1258
1259         #
1260         # From an EP to an outside address: IN2OUT
1261         #
1262         pkt_inter_epg_220_to_global = (Ether(src=self.pg0.remote_mac,
1263                                              dst=str(self.router_mac)) /
1264                                        IP(src=eps[0].ip4.address,
1265                                           dst="1.1.1.1") /
1266                                        UDP(sport=1234, dport=1234) /
1267                                        Raw('\xa5' * 100))
1268
1269         # no policy yet
1270         self.send_and_assert_no_replies(eps[0].itf,
1271                                         pkt_inter_epg_220_to_global * 65)
1272
1273         acl2 = VppGbpAcl(self)
1274         rule = acl2.create_rule(permit_deny=1, proto=17, sport_from=1234,
1275                                 sport_to=1234, dport_from=1234, dport_to=1234)
1276         rule2 = acl2.create_rule(is_ipv6=1, permit_deny=1, proto=17,
1277                                  sport_from=1234, sport_to=1234,
1278                                  dport_from=1234, dport_to=1234)
1279
1280         acl_index2 = acl2.add_vpp_config([rule, rule2])
1281         c4 = VppGbpContract(
1282             self, epgs[0].sclass, epgs[3].sclass, acl_index2,
1283             [VppGbpContractRule(
1284                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1285                 []),
1286              VppGbpContractRule(
1287                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1288                  [])],
1289             [ETH_P_IP, ETH_P_IPV6])
1290         c4.add_vpp_config()
1291
1292         self.send_and_expect_natted(eps[0].itf,
1293                                     pkt_inter_epg_220_to_global * 65,
1294                                     self.pg7,
1295                                     eps[0].fip4.address)
1296
1297         pkt_inter_epg_220_to_global = (Ether(src=self.pg0.remote_mac,
1298                                              dst=str(self.router_mac)) /
1299                                        IPv6(src=eps[0].ip6.address,
1300                                             dst="6001::1") /
1301                                        UDP(sport=1234, dport=1234) /
1302                                        Raw('\xa5' * 100))
1303
1304         self.send_and_expect_natted6(self.pg0,
1305                                      pkt_inter_epg_220_to_global * 65,
1306                                      self.pg7,
1307                                      eps[0].fip6.address)
1308
1309         #
1310         # From a global address to an EP: OUT2IN
1311         #
1312         pkt_inter_epg_220_from_global = (Ether(src=str(self.router_mac),
1313                                                dst=self.pg0.remote_mac) /
1314                                          IP(dst=eps[0].fip4.address,
1315                                             src="1.1.1.1") /
1316                                          UDP(sport=1234, dport=1234) /
1317                                          Raw('\xa5' * 100))
1318
1319         self.send_and_assert_no_replies(self.pg7,
1320                                         pkt_inter_epg_220_from_global * 65)
1321
1322         c5 = VppGbpContract(
1323             self, epgs[3].sclass, epgs[0].sclass, acl_index2,
1324             [VppGbpContractRule(
1325                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1326                 []),
1327              VppGbpContractRule(
1328                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1329                  [])],
1330             [ETH_P_IP, ETH_P_IPV6])
1331         c5.add_vpp_config()
1332
1333         self.send_and_expect_unnatted(self.pg7,
1334                                       pkt_inter_epg_220_from_global * 65,
1335                                       eps[0].itf,
1336                                       eps[0].ip4.address)
1337
1338         pkt_inter_epg_220_from_global = (Ether(src=str(self.router_mac),
1339                                                dst=self.pg0.remote_mac) /
1340                                          IPv6(dst=eps[0].fip6.address,
1341                                               src="6001::1") /
1342                                          UDP(sport=1234, dport=1234) /
1343                                          Raw('\xa5' * 100))
1344
1345         self.send_and_expect_unnatted6(self.pg7,
1346                                        pkt_inter_epg_220_from_global * 65,
1347                                        eps[0].itf,
1348                                        eps[0].ip6.address)
1349
1350         #
1351         # From a local VM to another local VM using resp. public addresses:
1352         #  IN2OUT2IN
1353         #
1354         pkt_intra_epg_220_global = (Ether(src=self.pg0.remote_mac,
1355                                           dst=str(self.router_mac)) /
1356                                     IP(src=eps[0].ip4.address,
1357                                        dst=eps[1].fip4.address) /
1358                                     UDP(sport=1234, dport=1234) /
1359                                     Raw('\xa5' * 100))
1360
1361         self.send_and_expect_double_natted(eps[0].itf,
1362                                            pkt_intra_epg_220_global * 65,
1363                                            eps[1].itf,
1364                                            eps[0].fip4.address,
1365                                            eps[1].ip4.address)
1366
1367         pkt_intra_epg_220_global = (Ether(src=self.pg0.remote_mac,
1368                                           dst=str(self.router_mac)) /
1369                                     IPv6(src=eps[0].ip6.address,
1370                                          dst=eps[1].fip6.address) /
1371                                     UDP(sport=1234, dport=1234) /
1372                                     Raw('\xa5' * 100))
1373
1374         self.send_and_expect_double_natted6(eps[0].itf,
1375                                             pkt_intra_epg_220_global * 65,
1376                                             eps[1].itf,
1377                                             eps[0].fip6.address,
1378                                             eps[1].ip6.address)
1379
1380         #
1381         # cleanup
1382         #
1383         for ep in eps:
1384             # del static mappings for each EP from the 10/8 to 11/8 network
1385             self.vapi.nat44_add_del_static_mapping(ep.ip4.bytes,
1386                                                    ep.fip4.bytes,
1387                                                    vrf_id=0,
1388                                                    addr_only=1,
1389                                                    is_add=0)
1390             self.vapi.nat66_add_del_static_mapping(ep.ip6.bytes,
1391                                                    ep.fip6.bytes,
1392                                                    vrf_id=0,
1393                                                    is_add=0)
1394
1395         for epg in epgs:
1396             # IP config on the BVI interfaces
1397             if epg != epgs[0] and epg != epgs[3]:
1398                 self.vapi.nat44_interface_add_del_feature(epg.bvi.sw_if_index,
1399                                                           is_inside=1,
1400                                                           is_add=0)
1401                 self.vapi.nat66_add_del_interface(epg.bvi.sw_if_index,
1402                                                   is_inside=1,
1403                                                   is_add=0)
1404
1405         for recirc in recircs:
1406             self.vapi.nat44_interface_add_del_feature(
1407                 recirc.recirc.sw_if_index,
1408                 is_inside=0,
1409                 is_add=0)
1410             self.vapi.nat66_add_del_interface(
1411                 recirc.recirc.sw_if_index,
1412                 is_inside=0,
1413                 is_add=0)
1414
1415     def wait_for_ep_timeout(self, sw_if_index=None, ip=None, mac=None,
1416                             n_tries=100, s_time=1):
1417         while (n_tries):
1418             if not find_gbp_endpoint(self, sw_if_index, ip, mac):
1419                 return True
1420             n_tries = n_tries - 1
1421             self.sleep(s_time)
1422         self.assertFalse(find_gbp_endpoint(self, sw_if_index, ip, mac))
1423         return False
1424
1425     def test_gbp_learn_l2(self):
1426         """ GBP L2 Endpoint Learning """
1427
1428         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
1429         learnt = [{'mac': '00:00:11:11:11:01',
1430                    'ip': '10.0.0.1',
1431                    'ip6': '2001:10::2'},
1432                   {'mac': '00:00:11:11:11:02',
1433                    'ip': '10.0.0.2',
1434                    'ip6': '2001:10::3'}]
1435
1436         #
1437         # IP tables
1438         #
1439         gt4 = VppIpTable(self, 1)
1440         gt4.add_vpp_config()
1441         gt6 = VppIpTable(self, 1, is_ip6=True)
1442         gt6.add_vpp_config()
1443
1444         rd1 = VppGbpRouteDomain(self, 1, gt4, gt6)
1445         rd1.add_vpp_config()
1446
1447         #
1448         # Pg2 hosts the vxlan tunnel, hosts on pg2 to act as TEPs
1449         # Pg3 hosts the IP4 UU-flood VXLAN tunnel
1450         # Pg4 hosts the IP6 UU-flood VXLAN tunnel
1451         #
1452         self.pg2.config_ip4()
1453         self.pg2.resolve_arp()
1454         self.pg2.generate_remote_hosts(4)
1455         self.pg2.configure_ipv4_neighbors()
1456         self.pg3.config_ip4()
1457         self.pg3.resolve_arp()
1458         self.pg4.config_ip4()
1459         self.pg4.resolve_arp()
1460
1461         #
1462         # Add a mcast destination VXLAN-GBP tunnel for B&M traffic
1463         #
1464         tun_bm = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
1465                                    "239.1.1.1", 88,
1466                                    mcast_itf=self.pg4)
1467         tun_bm.add_vpp_config()
1468
1469         #
1470         # a GBP bridge domain with a BVI and a UU-flood interface
1471         #
1472         bd1 = VppBridgeDomain(self, 1)
1473         bd1.add_vpp_config()
1474         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0, self.pg3, tun_bm)
1475         gbd1.add_vpp_config()
1476
1477         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1478         self.logger.info(self.vapi.cli("sh gbp bridge"))
1479
1480         # ... and has a /32 applied
1481         ip_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
1482         ip_addr.add_vpp_config()
1483
1484         #
1485         # The Endpoint-group in which we are learning endpoints
1486         #
1487         epg_220 = VppGbpEndpointGroup(self, 220, 112, rd1, gbd1,
1488                                       None, self.loop0,
1489                                       "10.0.0.128",
1490                                       "2001:10::128",
1491                                       VppGbpEndpointRetention(2))
1492         epg_220.add_vpp_config()
1493         epg_330 = VppGbpEndpointGroup(self, 330, 113, rd1, gbd1,
1494                                       None, self.loop1,
1495                                       "10.0.1.128",
1496                                       "2001:11::128",
1497                                       VppGbpEndpointRetention(2))
1498         epg_330.add_vpp_config()
1499
1500         #
1501         # The VXLAN GBP tunnel is a bridge-port and has L2 endpoint
1502         # learning enabled
1503         #
1504         vx_tun_l2_1 = VppGbpVxlanTunnel(
1505             self, 99, bd1.bd_id,
1506             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L2,
1507             self.pg2.local_ip4)
1508         vx_tun_l2_1.add_vpp_config()
1509
1510         #
1511         # A static endpoint that the learnt endpoints are trying to
1512         # talk to
1513         #
1514         ep = VppGbpEndpoint(self, self.pg0,
1515                             epg_220, None,
1516                             "10.0.0.127", "11.0.0.127",
1517                             "2001:10::1", "3001::1")
1518         ep.add_vpp_config()
1519
1520         self.assertTrue(find_route(self, ep.ip4.address, 32, table_id=1))
1521
1522         # a packet with an sclass from an unknown EPG
1523         p = (Ether(src=self.pg2.remote_mac,
1524                    dst=self.pg2.local_mac) /
1525              IP(src=self.pg2.remote_hosts[0].ip4,
1526                 dst=self.pg2.local_ip4) /
1527              UDP(sport=1234, dport=48879) /
1528              VXLAN(vni=99, gpid=88, flags=0x88) /
1529              Ether(src=learnt[0]["mac"], dst=ep.mac) /
1530              IP(src=learnt[0]["ip"], dst=ep.ip4.address) /
1531              UDP(sport=1234, dport=1234) /
1532              Raw('\xa5' * 100))
1533
1534         self.send_and_assert_no_replies(self.pg2, p)
1535
1536         #
1537         # we should not have learnt a new tunnel endpoint, since
1538         # the EPG was not learnt.
1539         #
1540         self.assertEqual(INDEX_INVALID,
1541                          find_vxlan_gbp_tunnel(self,
1542                                                self.pg2.local_ip4,
1543                                                self.pg2.remote_hosts[0].ip4,
1544                                                99))
1545
1546         # epg is not learnt, because the EPG is unknwon
1547         self.assertEqual(len(self.vapi.gbp_endpoint_dump()), 1)
1548
1549         #
1550         # Learn new EPs from IP packets
1551         #
1552         for ii, l in enumerate(learnt):
1553             # a packet with an sclass from a known EPG
1554             # arriving on an unknown TEP
1555             p = (Ether(src=self.pg2.remote_mac,
1556                        dst=self.pg2.local_mac) /
1557                  IP(src=self.pg2.remote_hosts[1].ip4,
1558                     dst=self.pg2.local_ip4) /
1559                  UDP(sport=1234, dport=48879) /
1560                  VXLAN(vni=99, gpid=112, flags=0x88) /
1561                  Ether(src=l['mac'], dst=ep.mac) /
1562                  IP(src=l['ip'], dst=ep.ip4.address) /
1563                  UDP(sport=1234, dport=1234) /
1564                  Raw('\xa5' * 100))
1565
1566             rx = self.send_and_expect(self.pg2, [p], self.pg0)
1567
1568             # the new TEP
1569             tep1_sw_if_index = find_vxlan_gbp_tunnel(
1570                 self,
1571                 self.pg2.local_ip4,
1572                 self.pg2.remote_hosts[1].ip4,
1573                 99)
1574             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
1575
1576             #
1577             # the EP is learnt via the learnt TEP
1578             # both from its MAC and its IP
1579             #
1580             self.assertTrue(find_gbp_endpoint(self,
1581                                               vx_tun_l2_1.sw_if_index,
1582                                               mac=l['mac']))
1583             self.assertTrue(find_gbp_endpoint(self,
1584                                               vx_tun_l2_1.sw_if_index,
1585                                               ip=l['ip']))
1586
1587         self.logger.info(self.vapi.cli("show gbp endpoint"))
1588         self.logger.info(self.vapi.cli("show gbp vxlan"))
1589         self.logger.info(self.vapi.cli("show ip mfib"))
1590
1591         #
1592         # If we sleep for the threshold time, the learnt endpoints should
1593         # age out
1594         #
1595         for l in learnt:
1596             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
1597                                      mac=l['mac'])
1598
1599         #
1600         # Learn new EPs from GARP packets received on the BD's mcast tunnel
1601         #
1602         for ii, l in enumerate(learnt):
1603             # a packet with an sclass from a known EPG
1604             # arriving on an unknown TEP
1605             p = (Ether(src=self.pg2.remote_mac,
1606                        dst=self.pg2.local_mac) /
1607                  IP(src=self.pg2.remote_hosts[1].ip4,
1608                     dst="239.1.1.1") /
1609                  UDP(sport=1234, dport=48879) /
1610                  VXLAN(vni=88, gpid=112, flags=0x88) /
1611                  Ether(src=l['mac'], dst="ff:ff:ff:ff:ff:ff") /
1612                  ARP(op="who-has",
1613                      psrc=l['ip'], pdst=l['ip'],
1614                      hwsrc=l['mac'], hwdst="ff:ff:ff:ff:ff:ff"))
1615
1616             rx = self.send_and_expect(self.pg4, [p], self.pg0)
1617
1618             # the new TEP
1619             tep1_sw_if_index = find_vxlan_gbp_tunnel(
1620                 self,
1621                 self.pg2.local_ip4,
1622                 self.pg2.remote_hosts[1].ip4,
1623                 99)
1624             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
1625
1626             #
1627             # the EP is learnt via the learnt TEP
1628             # both from its MAC and its IP
1629             #
1630             self.assertTrue(find_gbp_endpoint(self,
1631                                               vx_tun_l2_1.sw_if_index,
1632                                               mac=l['mac']))
1633             self.assertTrue(find_gbp_endpoint(self,
1634                                               vx_tun_l2_1.sw_if_index,
1635                                               ip=l['ip']))
1636
1637         #
1638         # wait for the learnt endpoints to age out
1639         #
1640         for l in learnt:
1641             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
1642                                      mac=l['mac'])
1643
1644         #
1645         # Learn new EPs from L2 packets
1646         #
1647         for ii, l in enumerate(learnt):
1648             # a packet with an sclass from a known EPG
1649             # arriving on an unknown TEP
1650             p = (Ether(src=self.pg2.remote_mac,
1651                        dst=self.pg2.local_mac) /
1652                  IP(src=self.pg2.remote_hosts[1].ip4,
1653                     dst=self.pg2.local_ip4) /
1654                  UDP(sport=1234, dport=48879) /
1655                  VXLAN(vni=99, gpid=112, flags=0x88) /
1656                  Ether(src=l['mac'], dst=ep.mac) /
1657                  Raw('\xa5' * 100))
1658
1659             rx = self.send_and_expect(self.pg2, [p], self.pg0)
1660
1661             # the new TEP
1662             tep1_sw_if_index = find_vxlan_gbp_tunnel(
1663                 self,
1664                 self.pg2.local_ip4,
1665                 self.pg2.remote_hosts[1].ip4,
1666                 99)
1667             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
1668
1669             #
1670             # the EP is learnt via the learnt TEP
1671             # both from its MAC and its IP
1672             #
1673             self.assertTrue(find_gbp_endpoint(self,
1674                                               vx_tun_l2_1.sw_if_index,
1675                                               mac=l['mac']))
1676
1677         self.logger.info(self.vapi.cli("show gbp endpoint"))
1678         self.logger.info(self.vapi.cli("show gbp vxlan"))
1679         self.logger.info(self.vapi.cli("show vxlan-gbp tunnel"))
1680
1681         #
1682         # wait for the learnt endpoints to age out
1683         #
1684         for l in learnt:
1685             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
1686                                      mac=l['mac'])
1687
1688         #
1689         # repeat. the do not learn bit is set so the EPs are not learnt
1690         #
1691         for l in learnt:
1692             # a packet with an sclass from a known EPG
1693             p = (Ether(src=self.pg2.remote_mac,
1694                        dst=self.pg2.local_mac) /
1695                  IP(src=self.pg2.remote_hosts[1].ip4,
1696                     dst=self.pg2.local_ip4) /
1697                  UDP(sport=1234, dport=48879) /
1698                  VXLAN(vni=99, gpid=112, flags=0x88, gpflags="D") /
1699                  Ether(src=l['mac'], dst=ep.mac) /
1700                  IP(src=l['ip'], dst=ep.ip4.address) /
1701                  UDP(sport=1234, dport=1234) /
1702                  Raw('\xa5' * 100))
1703
1704             rx = self.send_and_expect(self.pg2, p*65, self.pg0)
1705
1706         for l in learnt:
1707             self.assertFalse(find_gbp_endpoint(self,
1708                                                vx_tun_l2_1.sw_if_index,
1709                                                mac=l['mac']))
1710
1711         #
1712         # repeat
1713         #
1714         for l in learnt:
1715             # a packet with an sclass from a known EPG
1716             p = (Ether(src=self.pg2.remote_mac,
1717                        dst=self.pg2.local_mac) /
1718                  IP(src=self.pg2.remote_hosts[1].ip4,
1719                     dst=self.pg2.local_ip4) /
1720                  UDP(sport=1234, dport=48879) /
1721                  VXLAN(vni=99, gpid=112, flags=0x88) /
1722                  Ether(src=l['mac'], dst=ep.mac) /
1723                  IP(src=l['ip'], dst=ep.ip4.address) /
1724                  UDP(sport=1234, dport=1234) /
1725                  Raw('\xa5' * 100))
1726
1727             rx = self.send_and_expect(self.pg2, p*65, self.pg0)
1728
1729             self.assertTrue(find_gbp_endpoint(self,
1730                                               vx_tun_l2_1.sw_if_index,
1731                                               mac=l['mac']))
1732
1733         #
1734         # Static EP replies to dynamics
1735         #
1736         self.logger.info(self.vapi.cli("sh l2fib bd_id 1"))
1737         for l in learnt:
1738             p = (Ether(src=ep.mac, dst=l['mac']) /
1739                  IP(dst=l['ip'], src=ep.ip4.address) /
1740                  UDP(sport=1234, dport=1234) /
1741                  Raw('\xa5' * 100))
1742
1743             rxs = self.send_and_expect(self.pg0, p * 17, self.pg2)
1744
1745             for rx in rxs:
1746                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
1747                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
1748                 self.assertEqual(rx[UDP].dport, 48879)
1749                 # the UDP source port is a random value for hashing
1750                 self.assertEqual(rx[VXLAN].gpid, 112)
1751                 self.assertEqual(rx[VXLAN].vni, 99)
1752                 self.assertTrue(rx[VXLAN].flags.G)
1753                 self.assertTrue(rx[VXLAN].flags.Instance)
1754                 self.assertTrue(rx[VXLAN].gpflags.A)
1755                 self.assertFalse(rx[VXLAN].gpflags.D)
1756
1757         for l in learnt:
1758             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
1759                                      mac=l['mac'])
1760
1761         #
1762         # repeat in the other EPG
1763         # there's no contract between 220 and 330, but the A-bit is set
1764         # so the packet is cleared for delivery
1765         #
1766         for l in learnt:
1767             # a packet with an sclass from a known EPG
1768             p = (Ether(src=self.pg2.remote_mac,
1769                        dst=self.pg2.local_mac) /
1770                  IP(src=self.pg2.remote_hosts[1].ip4,
1771                     dst=self.pg2.local_ip4) /
1772                  UDP(sport=1234, dport=48879) /
1773                  VXLAN(vni=99, gpid=113, flags=0x88, gpflags='A') /
1774                  Ether(src=l['mac'], dst=ep.mac) /
1775                  IP(src=l['ip'], dst=ep.ip4.address) /
1776                  UDP(sport=1234, dport=1234) /
1777                  Raw('\xa5' * 100))
1778
1779             rx = self.send_and_expect(self.pg2, p*65, self.pg0)
1780
1781             self.assertTrue(find_gbp_endpoint(self,
1782                                               vx_tun_l2_1.sw_if_index,
1783                                               mac=l['mac']))
1784
1785         #
1786         # static EP cannot reach the learnt EPs since there is no contract
1787         # only test 1 EP as the others could timeout
1788         #
1789         p = (Ether(src=ep.mac, dst=l['mac']) /
1790              IP(dst=learnt[0]['ip'], src=ep.ip4.address) /
1791              UDP(sport=1234, dport=1234) /
1792              Raw('\xa5' * 100))
1793
1794         self.send_and_assert_no_replies(self.pg0, [p])
1795
1796         #
1797         # refresh the entries after the check for no replies above
1798         #
1799         for l in learnt:
1800             # a packet with an sclass from a known EPG
1801             p = (Ether(src=self.pg2.remote_mac,
1802                        dst=self.pg2.local_mac) /
1803                  IP(src=self.pg2.remote_hosts[1].ip4,
1804                     dst=self.pg2.local_ip4) /
1805                  UDP(sport=1234, dport=48879) /
1806                  VXLAN(vni=99, gpid=113, flags=0x88, gpflags='A') /
1807                  Ether(src=l['mac'], dst=ep.mac) /
1808                  IP(src=l['ip'], dst=ep.ip4.address) /
1809                  UDP(sport=1234, dport=1234) /
1810                  Raw('\xa5' * 100))
1811
1812             rx = self.send_and_expect(self.pg2, p*65, self.pg0)
1813
1814             self.assertTrue(find_gbp_endpoint(self,
1815                                               vx_tun_l2_1.sw_if_index,
1816                                               mac=l['mac']))
1817
1818         #
1819         # Add the contract so they can talk
1820         #
1821         acl = VppGbpAcl(self)
1822         rule = acl.create_rule(permit_deny=1, proto=17)
1823         rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
1824         acl_index = acl.add_vpp_config([rule, rule2])
1825         c1 = VppGbpContract(
1826             self, epg_220.sclass, epg_330.sclass, acl_index,
1827             [VppGbpContractRule(
1828                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1829                 []),
1830              VppGbpContractRule(
1831                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1832                  [])],
1833             [ETH_P_IP, ETH_P_IPV6])
1834         c1.add_vpp_config()
1835
1836         for l in learnt:
1837             p = (Ether(src=ep.mac, dst=l['mac']) /
1838                  IP(dst=l['ip'], src=ep.ip4.address) /
1839                  UDP(sport=1234, dport=1234) /
1840                  Raw('\xa5' * 100))
1841
1842             self.send_and_expect(self.pg0, [p], self.pg2)
1843
1844         #
1845         # send UU packets from the local EP
1846         #
1847         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1848         self.logger.info(self.vapi.cli("sh gbp bridge"))
1849         p_uu = (Ether(src=ep.mac, dst="00:11:11:11:11:11") /
1850                 IP(dst="10.0.0.133", src=ep.ip4.address) /
1851                 UDP(sport=1234, dport=1234) /
1852                 Raw('\xa5' * 100))
1853         rxs = self.send_and_expect(ep.itf, [p_uu], gbd1.uu_fwd)
1854
1855         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1856
1857         p_bm = (Ether(src=ep.mac, dst="ff:ff:ff:ff:ff:ff") /
1858                 IP(dst="10.0.0.133", src=ep.ip4.address) /
1859                 UDP(sport=1234, dport=1234) /
1860                 Raw('\xa5' * 100))
1861         rxs = self.send_and_expect_only(ep.itf, [p_bm], tun_bm.mcast_itf)
1862
1863         for rx in rxs:
1864             self.assertEqual(rx[IP].src, self.pg4.local_ip4)
1865             self.assertEqual(rx[IP].dst, "239.1.1.1")
1866             self.assertEqual(rx[UDP].dport, 48879)
1867             # the UDP source port is a random value for hashing
1868             self.assertEqual(rx[VXLAN].gpid, 112)
1869             self.assertEqual(rx[VXLAN].vni, 88)
1870             self.assertTrue(rx[VXLAN].flags.G)
1871             self.assertTrue(rx[VXLAN].flags.Instance)
1872             self.assertFalse(rx[VXLAN].gpflags.A)
1873             self.assertFalse(rx[VXLAN].gpflags.D)
1874
1875         #
1876         # Check v6 Endpoints
1877         #
1878         for l in learnt:
1879             # a packet with an sclass from a known EPG
1880             p = (Ether(src=self.pg2.remote_mac,
1881                        dst=self.pg2.local_mac) /
1882                  IP(src=self.pg2.remote_hosts[1].ip4,
1883                     dst=self.pg2.local_ip4) /
1884                  UDP(sport=1234, dport=48879) /
1885                  VXLAN(vni=99, gpid=113, flags=0x88, gpflags='A') /
1886                  Ether(src=l['mac'], dst=ep.mac) /
1887                  IPv6(src=l['ip6'], dst=ep.ip6.address) /
1888                  UDP(sport=1234, dport=1234) /
1889                  Raw('\xa5' * 100))
1890
1891             rx = self.send_and_expect(self.pg2, p*65, self.pg0)
1892
1893             self.assertTrue(find_gbp_endpoint(self,
1894                                               vx_tun_l2_1.sw_if_index,
1895                                               mac=l['mac']))
1896
1897         #
1898         # L3 Endpoint Learning
1899         #  - configured on the bridge's BVI
1900         #
1901
1902         #
1903         # clean up
1904         #
1905         for l in learnt:
1906             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
1907                                      mac=l['mac'])
1908         self.pg2.unconfig_ip4()
1909         self.pg3.unconfig_ip4()
1910         self.pg4.unconfig_ip4()
1911
1912         self.logger.info(self.vapi.cli("sh int"))
1913         self.logger.info(self.vapi.cli("sh gbp vxlan"))
1914
1915     def test_gbp_bd_flags(self):
1916         """ GBP BD FLAGS """
1917
1918         #
1919         # IP tables
1920         #
1921         gt4 = VppIpTable(self, 1)
1922         gt4.add_vpp_config()
1923         gt6 = VppIpTable(self, 1, is_ip6=True)
1924         gt6.add_vpp_config()
1925
1926         rd1 = VppGbpRouteDomain(self, 1, gt4, gt6)
1927         rd1.add_vpp_config()
1928
1929         #
1930         # Pg3 hosts the IP4 UU-flood VXLAN tunnel
1931         # Pg4 hosts the IP6 UU-flood VXLAN tunnel
1932         #
1933         self.pg3.config_ip4()
1934         self.pg3.resolve_arp()
1935         self.pg4.config_ip4()
1936         self.pg4.resolve_arp()
1937
1938         #
1939         # Add a mcast destination VXLAN-GBP tunnel for B&M traffic
1940         #
1941         tun_bm = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
1942                                    "239.1.1.1", 88,
1943                                    mcast_itf=self.pg4)
1944         tun_bm.add_vpp_config()
1945
1946         #
1947         # a GBP bridge domain with a BVI and a UU-flood interface
1948         #
1949         bd1 = VppBridgeDomain(self, 1)
1950         bd1.add_vpp_config()
1951
1952         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0, self.pg3, tun_bm,
1953                                   uu_drop=True, bm_drop=True)
1954         gbd1.add_vpp_config()
1955
1956         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1957         self.logger.info(self.vapi.cli("sh gbp bridge"))
1958
1959         # ... and has a /32 applied
1960         ip_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
1961         ip_addr.add_vpp_config()
1962
1963         #
1964         # The Endpoint-group
1965         #
1966         epg_220 = VppGbpEndpointGroup(self, 220, 112, rd1, gbd1,
1967                                       None, self.loop0,
1968                                       "10.0.0.128",
1969                                       "2001:10::128",
1970                                       VppGbpEndpointRetention(2))
1971         epg_220.add_vpp_config()
1972
1973         ep = VppGbpEndpoint(self, self.pg0,
1974                             epg_220, None,
1975                             "10.0.0.127", "11.0.0.127",
1976                             "2001:10::1", "3001::1")
1977         ep.add_vpp_config()
1978         #
1979         # send UU/BM packet from the local EP with UU drop and BM drop enabled
1980         # in bd
1981         #
1982         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1983         self.logger.info(self.vapi.cli("sh gbp bridge"))
1984         p_uu = (Ether(src=ep.mac, dst="00:11:11:11:11:11") /
1985                 IP(dst="10.0.0.133", src=ep.ip4.address) /
1986                 UDP(sport=1234, dport=1234) /
1987                 Raw('\xa5' * 100))
1988         self.send_and_assert_no_replies(ep.itf, [p_uu])
1989
1990         p_bm = (Ether(src=ep.mac, dst="ff:ff:ff:ff:ff:ff") /
1991                 IP(dst="10.0.0.133", src=ep.ip4.address) /
1992                 UDP(sport=1234, dport=1234) /
1993                 Raw('\xa5' * 100))
1994         self.send_and_assert_no_replies(ep.itf, [p_bm])
1995
1996         self.pg3.unconfig_ip4()
1997         self.pg4.unconfig_ip4()
1998
1999         self.logger.info(self.vapi.cli("sh int"))
2000
2001     def test_gbp_learn_vlan_l2(self):
2002         """ GBP L2 Endpoint w/ VLANs"""
2003
2004         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
2005         learnt = [{'mac': '00:00:11:11:11:01',
2006                    'ip': '10.0.0.1',
2007                    'ip6': '2001:10::2'},
2008                   {'mac': '00:00:11:11:11:02',
2009                    'ip': '10.0.0.2',
2010                    'ip6': '2001:10::3'}]
2011
2012         #
2013         # IP tables
2014         #
2015         gt4 = VppIpTable(self, 1)
2016         gt4.add_vpp_config()
2017         gt6 = VppIpTable(self, 1, is_ip6=True)
2018         gt6.add_vpp_config()
2019
2020         rd1 = VppGbpRouteDomain(self, 1, gt4, gt6)
2021         rd1.add_vpp_config()
2022
2023         #
2024         # Pg2 hosts the vxlan tunnel, hosts on pg2 to act as TEPs
2025         #
2026         self.pg2.config_ip4()
2027         self.pg2.resolve_arp()
2028         self.pg2.generate_remote_hosts(4)
2029         self.pg2.configure_ipv4_neighbors()
2030         self.pg3.config_ip4()
2031         self.pg3.resolve_arp()
2032
2033         #
2034         # The EP will be on a vlan sub-interface
2035         #
2036         vlan_11 = VppDot1QSubint(self, self.pg0, 11)
2037         vlan_11.admin_up()
2038         self.vapi.l2_interface_vlan_tag_rewrite(
2039             sw_if_index=vlan_11.sw_if_index, vtr_op=L2_VTR_OP.L2_POP_1,
2040             push_dot1q=11)
2041
2042         bd_uu_fwd = VppVxlanGbpTunnel(self, self.pg3.local_ip4,
2043                                       self.pg3.remote_ip4, 116)
2044         bd_uu_fwd.add_vpp_config()
2045
2046         #
2047         # a GBP bridge domain with a BVI and a UU-flood interface
2048         # The BD is marked as do not learn, so no endpoints are ever
2049         # learnt in this BD.
2050         #
2051         bd1 = VppBridgeDomain(self, 1)
2052         bd1.add_vpp_config()
2053         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0, bd_uu_fwd,
2054                                   learn=False)
2055         gbd1.add_vpp_config()
2056
2057         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
2058         self.logger.info(self.vapi.cli("sh gbp bridge"))
2059
2060         # ... and has a /32 applied
2061         ip_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
2062         ip_addr.add_vpp_config()
2063
2064         #
2065         # The Endpoint-group in which we are learning endpoints
2066         #
2067         epg_220 = VppGbpEndpointGroup(self, 220, 441, rd1, gbd1,
2068                                       None, self.loop0,
2069                                       "10.0.0.128",
2070                                       "2001:10::128",
2071                                       VppGbpEndpointRetention(2))
2072         epg_220.add_vpp_config()
2073
2074         #
2075         # The VXLAN GBP tunnel is a bridge-port and has L2 endpoint
2076         # learning enabled
2077         #
2078         vx_tun_l2_1 = VppGbpVxlanTunnel(
2079             self, 99, bd1.bd_id,
2080             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L2,
2081             self.pg2.local_ip4)
2082         vx_tun_l2_1.add_vpp_config()
2083
2084         #
2085         # A static endpoint that the learnt endpoints are trying to
2086         # talk to
2087         #
2088         ep = VppGbpEndpoint(self, vlan_11,
2089                             epg_220, None,
2090                             "10.0.0.127", "11.0.0.127",
2091                             "2001:10::1", "3001::1")
2092         ep.add_vpp_config()
2093
2094         self.assertTrue(find_route(self, ep.ip4.address, 32, table_id=1))
2095
2096         #
2097         # Send to the static EP
2098         #
2099         for ii, l in enumerate(learnt):
2100             # a packet with an sclass from a known EPG
2101             # arriving on an unknown TEP
2102             p = (Ether(src=self.pg2.remote_mac,
2103                        dst=self.pg2.local_mac) /
2104                  IP(src=self.pg2.remote_hosts[1].ip4,
2105                     dst=self.pg2.local_ip4) /
2106                  UDP(sport=1234, dport=48879) /
2107                  VXLAN(vni=99, gpid=441, flags=0x88) /
2108                  Ether(src=l['mac'], dst=ep.mac) /
2109                  IP(src=l['ip'], dst=ep.ip4.address) /
2110                  UDP(sport=1234, dport=1234) /
2111                  Raw('\xa5' * 100))
2112
2113             rxs = self.send_and_expect(self.pg2, [p], self.pg0)
2114
2115             #
2116             # packet to EP has the EP's vlan tag
2117             #
2118             for rx in rxs:
2119                 self.assertEqual(rx[Dot1Q].vlan, 11)
2120
2121             #
2122             # the EP is not learnt since the BD setting prevents it
2123             # also no TEP too
2124             #
2125             self.assertFalse(find_gbp_endpoint(self,
2126                                                vx_tun_l2_1.sw_if_index,
2127                                                mac=l['mac']))
2128             self.assertEqual(INDEX_INVALID,
2129                              find_vxlan_gbp_tunnel(
2130                                  self,
2131                                  self.pg2.local_ip4,
2132                                  self.pg2.remote_hosts[1].ip4,
2133                                  99))
2134
2135         self.assertEqual(len(self.vapi.gbp_endpoint_dump()), 1)
2136
2137         #
2138         # static to remotes
2139         # we didn't learn the remotes so they are sent to the UU-fwd
2140         #
2141         for l in learnt:
2142             p = (Ether(src=ep.mac, dst=l['mac']) /
2143                  Dot1Q(vlan=11) /
2144                  IP(dst=l['ip'], src=ep.ip4.address) /
2145                  UDP(sport=1234, dport=1234) /
2146                  Raw('\xa5' * 100))
2147
2148             rxs = self.send_and_expect(self.pg0, p * 17, self.pg3)
2149
2150             for rx in rxs:
2151                 self.assertEqual(rx[IP].src, self.pg3.local_ip4)
2152                 self.assertEqual(rx[IP].dst, self.pg3.remote_ip4)
2153                 self.assertEqual(rx[UDP].dport, 48879)
2154                 # the UDP source port is a random value for hashing
2155                 self.assertEqual(rx[VXLAN].gpid, 441)
2156                 self.assertEqual(rx[VXLAN].vni, 116)
2157                 self.assertTrue(rx[VXLAN].flags.G)
2158                 self.assertTrue(rx[VXLAN].flags.Instance)
2159                 self.assertFalse(rx[VXLAN].gpflags.A)
2160                 self.assertFalse(rx[VXLAN].gpflags.D)
2161
2162         self.pg2.unconfig_ip4()
2163         self.pg3.unconfig_ip4()
2164
2165     def test_gbp_learn_l3(self):
2166         """ GBP L3 Endpoint Learning """
2167
2168         self.vapi.cli("set logging class gbp debug")
2169
2170         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
2171         routed_dst_mac = "00:0c:0c:0c:0c:0c"
2172         routed_src_mac = "00:22:bd:f8:19:ff"
2173
2174         learnt = [{'mac': '00:00:11:11:11:02',
2175                    'ip': '10.0.1.2',
2176                    'ip6': '2001:10::2'},
2177                   {'mac': '00:00:11:11:11:03',
2178                    'ip': '10.0.1.3',
2179                    'ip6': '2001:10::3'}]
2180
2181         #
2182         # IP tables
2183         #
2184         t4 = VppIpTable(self, 1)
2185         t4.add_vpp_config()
2186         t6 = VppIpTable(self, 1, True)
2187         t6.add_vpp_config()
2188
2189         tun_ip4_uu = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
2190                                        self.pg4.remote_ip4, 114)
2191         tun_ip6_uu = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
2192                                        self.pg4.remote_ip4, 116)
2193         tun_ip4_uu.add_vpp_config()
2194         tun_ip6_uu.add_vpp_config()
2195
2196         rd1 = VppGbpRouteDomain(self, 2, t4, t6, tun_ip4_uu, tun_ip6_uu)
2197         rd1.add_vpp_config()
2198
2199         self.loop0.set_mac(self.router_mac)
2200
2201         #
2202         # Bind the BVI to the RD
2203         #
2204         VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
2205         VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
2206
2207         #
2208         # Pg2 hosts the vxlan tunnel
2209         # hosts on pg2 to act as TEPs
2210         # pg3 is BD uu-fwd
2211         # pg4 is RD uu-fwd
2212         #
2213         self.pg2.config_ip4()
2214         self.pg2.resolve_arp()
2215         self.pg2.generate_remote_hosts(4)
2216         self.pg2.configure_ipv4_neighbors()
2217         self.pg3.config_ip4()
2218         self.pg3.resolve_arp()
2219         self.pg4.config_ip4()
2220         self.pg4.resolve_arp()
2221
2222         #
2223         # a GBP bridge domain with a BVI and a UU-flood interface
2224         #
2225         bd1 = VppBridgeDomain(self, 1)
2226         bd1.add_vpp_config()
2227         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0, self.pg3)
2228         gbd1.add_vpp_config()
2229
2230         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
2231         self.logger.info(self.vapi.cli("sh gbp bridge"))
2232         self.logger.info(self.vapi.cli("sh gbp route"))
2233
2234         # ... and has a /32 and /128 applied
2235         ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
2236         ip4_addr.add_vpp_config()
2237         ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128", 128)
2238         ip6_addr.add_vpp_config()
2239
2240         #
2241         # The Endpoint-group in which we are learning endpoints
2242         #
2243         epg_220 = VppGbpEndpointGroup(self, 220, 441, rd1, gbd1,
2244                                       None, self.loop0,
2245                                       "10.0.0.128",
2246                                       "2001:10::128",
2247                                       VppGbpEndpointRetention(2))
2248         epg_220.add_vpp_config()
2249
2250         #
2251         # The VXLAN GBP tunnel is a bridge-port and has L2 endpoint
2252         # learning enabled
2253         #
2254         vx_tun_l3 = VppGbpVxlanTunnel(
2255             self, 101, rd1.rd_id,
2256             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3,
2257             self.pg2.local_ip4)
2258         vx_tun_l3.add_vpp_config()
2259
2260         #
2261         # A static endpoint that the learnt endpoints are trying to
2262         # talk to
2263         #
2264         ep = VppGbpEndpoint(self, self.pg0,
2265                             epg_220, None,
2266                             "10.0.0.127", "11.0.0.127",
2267                             "2001:10::1", "3001::1")
2268         ep.add_vpp_config()
2269
2270         #
2271         # learn some remote IPv4 EPs
2272         #
2273         for ii, l in enumerate(learnt):
2274             # a packet with an sclass from a known EPG
2275             # arriving on an unknown TEP
2276             p = (Ether(src=self.pg2.remote_mac,
2277                        dst=self.pg2.local_mac) /
2278                  IP(src=self.pg2.remote_hosts[1].ip4,
2279                     dst=self.pg2.local_ip4) /
2280                  UDP(sport=1234, dport=48879) /
2281                  VXLAN(vni=101, gpid=441, flags=0x88) /
2282                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
2283                  IP(src=l['ip'], dst=ep.ip4.address) /
2284                  UDP(sport=1234, dport=1234) /
2285                  Raw('\xa5' * 100))
2286
2287             rx = self.send_and_expect(self.pg2, [p], self.pg0)
2288
2289             # the new TEP
2290             tep1_sw_if_index = find_vxlan_gbp_tunnel(
2291                 self,
2292                 self.pg2.local_ip4,
2293                 self.pg2.remote_hosts[1].ip4,
2294                 vx_tun_l3.vni)
2295             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
2296
2297             # endpoint learnt via the parent GBP-vxlan interface
2298             self.assertTrue(find_gbp_endpoint(self,
2299                                               vx_tun_l3._sw_if_index,
2300                                               ip=l['ip']))
2301
2302         #
2303         # Static IPv4 EP replies to learnt
2304         #
2305         for l in learnt:
2306             p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2307                  IP(dst=l['ip'], src=ep.ip4.address) /
2308                  UDP(sport=1234, dport=1234) /
2309                  Raw('\xa5' * 100))
2310
2311             rxs = self.send_and_expect(self.pg0, p*1, self.pg2)
2312
2313             for rx in rxs:
2314                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2315                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
2316                 self.assertEqual(rx[UDP].dport, 48879)
2317                 # the UDP source port is a random value for hashing
2318                 self.assertEqual(rx[VXLAN].gpid, 441)
2319                 self.assertEqual(rx[VXLAN].vni, 101)
2320                 self.assertTrue(rx[VXLAN].flags.G)
2321                 self.assertTrue(rx[VXLAN].flags.Instance)
2322                 self.assertTrue(rx[VXLAN].gpflags.A)
2323                 self.assertFalse(rx[VXLAN].gpflags.D)
2324
2325                 inner = rx[VXLAN].payload
2326
2327                 self.assertEqual(inner[Ether].src, routed_src_mac)
2328                 self.assertEqual(inner[Ether].dst, routed_dst_mac)
2329                 self.assertEqual(inner[IP].src, ep.ip4.address)
2330                 self.assertEqual(inner[IP].dst, l['ip'])
2331
2332         for l in learnt:
2333             self.assertFalse(find_gbp_endpoint(self,
2334                                                tep1_sw_if_index,
2335                                                ip=l['ip']))
2336
2337         #
2338         # learn some remote IPv6 EPs
2339         #
2340         for ii, l in enumerate(learnt):
2341             # a packet with an sclass from a known EPG
2342             # arriving on an unknown TEP
2343             p = (Ether(src=self.pg2.remote_mac,
2344                        dst=self.pg2.local_mac) /
2345                  IP(src=self.pg2.remote_hosts[1].ip4,
2346                     dst=self.pg2.local_ip4) /
2347                  UDP(sport=1234, dport=48879) /
2348                  VXLAN(vni=101, gpid=441, flags=0x88) /
2349                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
2350                  IPv6(src=l['ip6'], dst=ep.ip6.address) /
2351                  UDP(sport=1234, dport=1234) /
2352                  Raw('\xa5' * 100))
2353
2354             rx = self.send_and_expect(self.pg2, [p], self.pg0)
2355
2356             # the new TEP
2357             tep1_sw_if_index = find_vxlan_gbp_tunnel(
2358                 self,
2359                 self.pg2.local_ip4,
2360                 self.pg2.remote_hosts[1].ip4,
2361                 vx_tun_l3.vni)
2362             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
2363
2364             self.logger.info(self.vapi.cli("show gbp bridge"))
2365             self.logger.info(self.vapi.cli("show vxlan-gbp tunnel"))
2366             self.logger.info(self.vapi.cli("show gbp vxlan"))
2367             self.logger.info(self.vapi.cli("show int addr"))
2368
2369             # endpoint learnt via the TEP
2370             self.assertTrue(find_gbp_endpoint(self, ip=l['ip6']))
2371
2372         self.logger.info(self.vapi.cli("show gbp endpoint"))
2373         self.logger.info(self.vapi.cli("show ip fib index 1 %s" % l['ip']))
2374
2375         #
2376         # Static EP replies to learnt
2377         #
2378         for l in learnt:
2379             p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2380                  IPv6(dst=l['ip6'], src=ep.ip6.address) /
2381                  UDP(sport=1234, dport=1234) /
2382                  Raw('\xa5' * 100))
2383
2384             rxs = self.send_and_expect(self.pg0, p*65, self.pg2)
2385
2386             for rx in rxs:
2387                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2388                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
2389                 self.assertEqual(rx[UDP].dport, 48879)
2390                 # the UDP source port is a random value for hashing
2391                 self.assertEqual(rx[VXLAN].gpid, 441)
2392                 self.assertEqual(rx[VXLAN].vni, 101)
2393                 self.assertTrue(rx[VXLAN].flags.G)
2394                 self.assertTrue(rx[VXLAN].flags.Instance)
2395                 self.assertTrue(rx[VXLAN].gpflags.A)
2396                 self.assertFalse(rx[VXLAN].gpflags.D)
2397
2398                 inner = rx[VXLAN].payload
2399
2400                 self.assertEqual(inner[Ether].src, routed_src_mac)
2401                 self.assertEqual(inner[Ether].dst, routed_dst_mac)
2402                 self.assertEqual(inner[IPv6].src, ep.ip6.address)
2403                 self.assertEqual(inner[IPv6].dst, l['ip6'])
2404
2405         self.logger.info(self.vapi.cli("sh gbp endpoint"))
2406         for l in learnt:
2407             self.wait_for_ep_timeout(ip=l['ip'])
2408
2409         #
2410         # Static sends to unknown EP with no route
2411         #
2412         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2413              IP(dst="10.0.0.99", src=ep.ip4.address) /
2414              UDP(sport=1234, dport=1234) /
2415              Raw('\xa5' * 100))
2416
2417         self.send_and_assert_no_replies(self.pg0, [p])
2418
2419         #
2420         # Add a route to static EP's v4 and v6 subnet
2421         #  packets should be sent on the v4/v6 uu=fwd interface resp.
2422         #
2423         se_10_24 = VppGbpSubnet(
2424             self, rd1, "10.0.0.0", 24,
2425             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_TRANSPORT)
2426         se_10_24.add_vpp_config()
2427
2428         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2429              IP(dst="10.0.0.99", src=ep.ip4.address) /
2430              UDP(sport=1234, dport=1234) /
2431              Raw('\xa5' * 100))
2432
2433         rxs = self.send_and_expect(self.pg0, [p], self.pg4)
2434         for rx in rxs:
2435             self.assertEqual(rx[IP].src, self.pg4.local_ip4)
2436             self.assertEqual(rx[IP].dst, self.pg4.remote_ip4)
2437             self.assertEqual(rx[UDP].dport, 48879)
2438             # the UDP source port is a random value for hashing
2439             self.assertEqual(rx[VXLAN].gpid, 441)
2440             self.assertEqual(rx[VXLAN].vni, 114)
2441             self.assertTrue(rx[VXLAN].flags.G)
2442             self.assertTrue(rx[VXLAN].flags.Instance)
2443             # policy is not applied to packets sent to the uu-fwd interfaces
2444             self.assertFalse(rx[VXLAN].gpflags.A)
2445             self.assertFalse(rx[VXLAN].gpflags.D)
2446
2447         #
2448         # learn some remote IPv4 EPs
2449         #
2450         for ii, l in enumerate(learnt):
2451             # a packet with an sclass from a known EPG
2452             # arriving on an unknown TEP
2453             p = (Ether(src=self.pg2.remote_mac,
2454                        dst=self.pg2.local_mac) /
2455                  IP(src=self.pg2.remote_hosts[2].ip4,
2456                     dst=self.pg2.local_ip4) /
2457                  UDP(sport=1234, dport=48879) /
2458                  VXLAN(vni=101, gpid=441, flags=0x88) /
2459                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
2460                  IP(src=l['ip'], dst=ep.ip4.address) /
2461                  UDP(sport=1234, dport=1234) /
2462                  Raw('\xa5' * 100))
2463
2464             rx = self.send_and_expect(self.pg2, [p], self.pg0)
2465
2466             # the new TEP
2467             tep1_sw_if_index = find_vxlan_gbp_tunnel(
2468                 self,
2469                 self.pg2.local_ip4,
2470                 self.pg2.remote_hosts[2].ip4,
2471                 vx_tun_l3.vni)
2472             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
2473
2474             # endpoint learnt via the parent GBP-vxlan interface
2475             self.assertTrue(find_gbp_endpoint(self,
2476                                               vx_tun_l3._sw_if_index,
2477                                               ip=l['ip']))
2478
2479         #
2480         # Add a remote endpoint from the API
2481         #
2482         rep_88 = VppGbpEndpoint(self, vx_tun_l3,
2483                                 epg_220, None,
2484                                 "10.0.0.88", "11.0.0.88",
2485                                 "2001:10::88", "3001::88",
2486                                 ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
2487                                 self.pg2.local_ip4,
2488                                 self.pg2.remote_hosts[1].ip4,
2489                                 mac=None)
2490         rep_88.add_vpp_config()
2491
2492         #
2493         # Add a remote endpoint from the API that matches an existing one
2494         #
2495         rep_2 = VppGbpEndpoint(self, vx_tun_l3,
2496                                epg_220, None,
2497                                learnt[0]['ip'], "11.0.0.101",
2498                                learnt[0]['ip6'], "3001::101",
2499                                ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
2500                                self.pg2.local_ip4,
2501                                self.pg2.remote_hosts[1].ip4,
2502                                mac=None)
2503         rep_2.add_vpp_config()
2504
2505         #
2506         # Add a route to the learned EP's v4 subnet
2507         #  packets should be send on the v4/v6 uu=fwd interface resp.
2508         #
2509         se_10_1_24 = VppGbpSubnet(
2510             self, rd1, "10.0.1.0", 24,
2511             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_TRANSPORT)
2512         se_10_1_24.add_vpp_config()
2513
2514         self.logger.info(self.vapi.cli("show gbp endpoint"))
2515
2516         ips = ["10.0.0.88", learnt[0]['ip']]
2517         for ip in ips:
2518             p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2519                  IP(dst=ip, src=ep.ip4.address) /
2520                  UDP(sport=1234, dport=1234) /
2521                  Raw('\xa5' * 100))
2522
2523             rxs = self.send_and_expect(self.pg0, p*65, self.pg2)
2524
2525             for rx in rxs:
2526                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2527                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
2528                 self.assertEqual(rx[UDP].dport, 48879)
2529                 # the UDP source port is a random value for hashing
2530                 self.assertEqual(rx[VXLAN].gpid, 441)
2531                 self.assertEqual(rx[VXLAN].vni, 101)
2532                 self.assertTrue(rx[VXLAN].flags.G)
2533                 self.assertTrue(rx[VXLAN].flags.Instance)
2534                 self.assertTrue(rx[VXLAN].gpflags.A)
2535                 self.assertFalse(rx[VXLAN].gpflags.D)
2536
2537                 inner = rx[VXLAN].payload
2538
2539                 self.assertEqual(inner[Ether].src, routed_src_mac)
2540                 self.assertEqual(inner[Ether].dst, routed_dst_mac)
2541                 self.assertEqual(inner[IP].src, ep.ip4.address)
2542                 self.assertEqual(inner[IP].dst, ip)
2543
2544         #
2545         # remove the API remote EPs, only API sourced is gone, the DP
2546         # learnt one remains
2547         #
2548         rep_88.remove_vpp_config()
2549         rep_2.remove_vpp_config()
2550
2551         self.assertTrue(find_gbp_endpoint(self, ip=rep_2.ip4.address))
2552
2553         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2554              IP(src=ep.ip4.address, dst=rep_2.ip4.address) /
2555              UDP(sport=1234, dport=1234) /
2556              Raw('\xa5' * 100))
2557         rxs = self.send_and_expect(self.pg0, [p], self.pg2)
2558
2559         self.assertFalse(find_gbp_endpoint(self, ip=rep_88.ip4.address))
2560
2561         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2562              IP(src=ep.ip4.address, dst=rep_88.ip4.address) /
2563              UDP(sport=1234, dport=1234) /
2564              Raw('\xa5' * 100))
2565         rxs = self.send_and_expect(self.pg0, [p], self.pg4)
2566
2567         #
2568         # to appease the testcase we cannot have the registered EP still
2569         # present (because it's DP learnt) when the TC ends so wait until
2570         # it is removed
2571         #
2572         self.wait_for_ep_timeout(ip=rep_88.ip4.address)
2573         self.wait_for_ep_timeout(ip=rep_2.ip4.address)
2574
2575         #
2576         # shutdown with learnt endpoint present
2577         #
2578         p = (Ether(src=self.pg2.remote_mac,
2579                    dst=self.pg2.local_mac) /
2580              IP(src=self.pg2.remote_hosts[1].ip4,
2581                 dst=self.pg2.local_ip4) /
2582              UDP(sport=1234, dport=48879) /
2583              VXLAN(vni=101, gpid=441, flags=0x88) /
2584              Ether(src=l['mac'], dst="00:00:00:11:11:11") /
2585              IP(src=learnt[1]['ip'], dst=ep.ip4.address) /
2586              UDP(sport=1234, dport=1234) /
2587              Raw('\xa5' * 100))
2588
2589         rx = self.send_and_expect(self.pg2, [p], self.pg0)
2590
2591         # endpoint learnt via the parent GBP-vxlan interface
2592         self.assertTrue(find_gbp_endpoint(self,
2593                                           vx_tun_l3._sw_if_index,
2594                                           ip=l['ip']))
2595
2596         #
2597         # TODO
2598         # remote endpoint becomes local
2599         #
2600         self.pg2.unconfig_ip4()
2601         self.pg3.unconfig_ip4()
2602         self.pg4.unconfig_ip4()
2603
2604     def test_gbp_redirect(self):
2605         """ GBP Endpoint Redirect """
2606
2607         self.vapi.cli("set logging class gbp debug")
2608
2609         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
2610         routed_dst_mac = "00:0c:0c:0c:0c:0c"
2611         routed_src_mac = "00:22:bd:f8:19:ff"
2612
2613         learnt = [{'mac': '00:00:11:11:11:02',
2614                    'ip': '10.0.1.2',
2615                    'ip6': '2001:10::2'},
2616                   {'mac': '00:00:11:11:11:03',
2617                    'ip': '10.0.1.3',
2618                    'ip6': '2001:10::3'}]
2619
2620         #
2621         # IP tables
2622         #
2623         t4 = VppIpTable(self, 1)
2624         t4.add_vpp_config()
2625         t6 = VppIpTable(self, 1, True)
2626         t6.add_vpp_config()
2627
2628         rd1 = VppGbpRouteDomain(self, 2, t4, t6)
2629         rd1.add_vpp_config()
2630
2631         self.loop0.set_mac(self.router_mac)
2632
2633         #
2634         # Bind the BVI to the RD
2635         #
2636         VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
2637         VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
2638
2639         #
2640         # Pg7 hosts a BD's UU-fwd
2641         #
2642         self.pg7.config_ip4()
2643         self.pg7.resolve_arp()
2644
2645         #
2646         # a GBP bridge domains for the EPs
2647         #
2648         bd1 = VppBridgeDomain(self, 1)
2649         bd1.add_vpp_config()
2650         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0)
2651         gbd1.add_vpp_config()
2652
2653         bd2 = VppBridgeDomain(self, 2)
2654         bd2.add_vpp_config()
2655         gbd2 = VppGbpBridgeDomain(self, bd2, self.loop1)
2656         gbd2.add_vpp_config()
2657
2658         # ... and has a /32 and /128 applied
2659         ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
2660         ip4_addr.add_vpp_config()
2661         ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128", 128)
2662         ip6_addr.add_vpp_config()
2663         ip4_addr = VppIpInterfaceAddress(self, gbd2.bvi, "10.0.1.128", 32)
2664         ip4_addr.add_vpp_config()
2665         ip6_addr = VppIpInterfaceAddress(self, gbd2.bvi, "2001:11::128", 128)
2666         ip6_addr.add_vpp_config()
2667
2668         #
2669         # The Endpoint-groups in which we are learning endpoints
2670         #
2671         epg_220 = VppGbpEndpointGroup(self, 220, 440, rd1, gbd1,
2672                                       None, gbd1.bvi,
2673                                       "10.0.0.128",
2674                                       "2001:10::128",
2675                                       VppGbpEndpointRetention(2))
2676         epg_220.add_vpp_config()
2677         epg_221 = VppGbpEndpointGroup(self, 221, 441, rd1, gbd2,
2678                                       None, gbd2.bvi,
2679                                       "10.0.1.128",
2680                                       "2001:11::128",
2681                                       VppGbpEndpointRetention(2))
2682         epg_221.add_vpp_config()
2683         epg_222 = VppGbpEndpointGroup(self, 222, 442, rd1, gbd1,
2684                                       None, gbd1.bvi,
2685                                       "10.0.2.128",
2686                                       "2001:12::128",
2687                                       VppGbpEndpointRetention(2))
2688         epg_222.add_vpp_config()
2689
2690         #
2691         # a GBP bridge domains for the SEPs
2692         #
2693         bd_uu1 = VppVxlanGbpTunnel(self, self.pg7.local_ip4,
2694                                    self.pg7.remote_ip4, 116)
2695         bd_uu1.add_vpp_config()
2696         bd_uu2 = VppVxlanGbpTunnel(self, self.pg7.local_ip4,
2697                                    self.pg7.remote_ip4, 117)
2698         bd_uu2.add_vpp_config()
2699
2700         bd3 = VppBridgeDomain(self, 3)
2701         bd3.add_vpp_config()
2702         gbd3 = VppGbpBridgeDomain(self, bd3, self.loop2, bd_uu1, learn=False)
2703         gbd3.add_vpp_config()
2704         bd4 = VppBridgeDomain(self, 4)
2705         bd4.add_vpp_config()
2706         gbd4 = VppGbpBridgeDomain(self, bd4, self.loop3, bd_uu2, learn=False)
2707         gbd4.add_vpp_config()
2708
2709         #
2710         # EPGs in which the service endpoints exist
2711         #
2712         epg_320 = VppGbpEndpointGroup(self, 320, 550, rd1, gbd3,
2713                                       None, gbd1.bvi,
2714                                       "12.0.0.128",
2715                                       "4001:10::128",
2716                                       VppGbpEndpointRetention(2))
2717         epg_320.add_vpp_config()
2718         epg_321 = VppGbpEndpointGroup(self, 321, 551, rd1, gbd4,
2719                                       None, gbd2.bvi,
2720                                       "12.0.1.128",
2721                                       "4001:11::128",
2722                                       VppGbpEndpointRetention(2))
2723         epg_321.add_vpp_config()
2724
2725         #
2726         # three local endpoints
2727         #
2728         ep1 = VppGbpEndpoint(self, self.pg0,
2729                              epg_220, None,
2730                              "10.0.0.1", "11.0.0.1",
2731                              "2001:10::1", "3001:10::1")
2732         ep1.add_vpp_config()
2733         ep2 = VppGbpEndpoint(self, self.pg1,
2734                              epg_221, None,
2735                              "10.0.1.1", "11.0.1.1",
2736                              "2001:11::1", "3001:11::1")
2737         ep2.add_vpp_config()
2738         ep3 = VppGbpEndpoint(self, self.pg2,
2739                              epg_222, None,
2740                              "10.0.2.2", "11.0.2.2",
2741                              "2001:12::1", "3001:12::1")
2742         ep3.add_vpp_config()
2743
2744         #
2745         # service endpoints
2746         #
2747         sep1 = VppGbpEndpoint(self, self.pg3,
2748                               epg_320, None,
2749                               "12.0.0.1", "13.0.0.1",
2750                               "4001:10::1", "5001:10::1")
2751         sep1.add_vpp_config()
2752         sep2 = VppGbpEndpoint(self, self.pg4,
2753                               epg_320, None,
2754                               "12.0.0.2", "13.0.0.2",
2755                               "4001:10::2", "5001:10::2")
2756         sep2.add_vpp_config()
2757         sep3 = VppGbpEndpoint(self, self.pg5,
2758                               epg_321, None,
2759                               "12.0.1.1", "13.0.1.1",
2760                               "4001:11::1", "5001:11::1")
2761         sep3.add_vpp_config()
2762         # this EP is not installed immediately
2763         sep4 = VppGbpEndpoint(self, self.pg6,
2764                               epg_321, None,
2765                               "12.0.1.2", "13.0.1.2",
2766                               "4001:11::2", "5001:11::2")
2767
2768         #
2769         # an L2 switch packet between local EPs in different EPGs
2770         #  different dest ports on each so the are LB hashed differently
2771         #
2772         p4 = [(Ether(src=ep1.mac, dst=ep3.mac) /
2773                IP(src=ep1.ip4.address, dst=ep3.ip4.address) /
2774                UDP(sport=1234, dport=1234) /
2775                Raw('\xa5' * 100)),
2776               (Ether(src=ep3.mac, dst=ep1.mac) /
2777                IP(src=ep3.ip4.address, dst=ep1.ip4.address) /
2778                UDP(sport=1234, dport=1234) /
2779                Raw('\xa5' * 100))]
2780         p6 = [(Ether(src=ep1.mac, dst=ep3.mac) /
2781                IPv6(src=ep1.ip6.address, dst=ep3.ip6.address) /
2782                UDP(sport=1234, dport=1234) /
2783                Raw('\xa5' * 100)),
2784               (Ether(src=ep3.mac, dst=ep1.mac) /
2785                IPv6(src=ep3.ip6.address, dst=ep1.ip6.address) /
2786                UDP(sport=1234, dport=1230) /
2787                Raw('\xa5' * 100))]
2788
2789         # should be dropped since no contract yet
2790         self.send_and_assert_no_replies(self.pg0, [p4[0]])
2791         self.send_and_assert_no_replies(self.pg0, [p6[0]])
2792
2793         #
2794         # Add a contract with a rule to load-balance redirect via SEP1 and SEP2
2795         # one of the next-hops is via an EP that is not known
2796         #
2797         acl = VppGbpAcl(self)
2798         rule4 = acl.create_rule(permit_deny=1, proto=17)
2799         rule6 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
2800         acl_index = acl.add_vpp_config([rule4, rule6])
2801
2802         #
2803         # test the src-ip hash mode
2804         #
2805         c1 = VppGbpContract(
2806             self, epg_220.sclass, epg_222.sclass, acl_index,
2807             [VppGbpContractRule(
2808                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
2809                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2810                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
2811                                        sep1.ip4, sep1.epg.rd),
2812                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
2813                                        sep2.ip4, sep2.epg.rd)]),
2814              VppGbpContractRule(
2815                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
2816                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2817                  [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
2818                                         sep3.ip6, sep3.epg.rd),
2819                   VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
2820                                         sep4.ip6, sep4.epg.rd)])],
2821             [ETH_P_IP, ETH_P_IPV6])
2822         c1.add_vpp_config()
2823
2824         c2 = VppGbpContract(
2825             self, epg_222.sclass, epg_220.sclass, acl_index,
2826             [VppGbpContractRule(
2827                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
2828                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2829                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
2830                                        sep1.ip4, sep1.epg.rd),
2831                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
2832                                        sep2.ip4, sep2.epg.rd)]),
2833              VppGbpContractRule(
2834                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
2835                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2836                  [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
2837                                         sep3.ip6, sep3.epg.rd),
2838                   VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
2839                                         sep4.ip6, sep4.epg.rd)])],
2840             [ETH_P_IP, ETH_P_IPV6])
2841         c2.add_vpp_config()
2842
2843         #
2844         # send again with the contract preset, now packets arrive
2845         # at SEP1 or SEP2 depending on the hashing
2846         #
2847         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
2848
2849         for rx in rxs:
2850             self.assertEqual(rx[Ether].src, routed_src_mac)
2851             self.assertEqual(rx[Ether].dst, sep1.mac)
2852             self.assertEqual(rx[IP].src, ep1.ip4.address)
2853             self.assertEqual(rx[IP].dst, ep3.ip4.address)
2854
2855         rxs = self.send_and_expect(self.pg2, p4[1] * 17, sep2.itf)
2856
2857         for rx in rxs:
2858             self.assertEqual(rx[Ether].src, routed_src_mac)
2859             self.assertEqual(rx[Ether].dst, sep2.mac)
2860             self.assertEqual(rx[IP].src, ep3.ip4.address)
2861             self.assertEqual(rx[IP].dst, ep1.ip4.address)
2862
2863         rxs = self.send_and_expect(self.pg0, p6[0] * 17, self.pg7)
2864
2865         for rx in rxs:
2866             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
2867             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
2868             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
2869             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
2870             self.assertEqual(rx[VXLAN].vni, 117)
2871             self.assertTrue(rx[VXLAN].flags.G)
2872             self.assertTrue(rx[VXLAN].flags.Instance)
2873             # redirect policy has been applied
2874             self.assertTrue(rx[VXLAN].gpflags.A)
2875             self.assertFalse(rx[VXLAN].gpflags.D)
2876
2877             inner = rx[VXLAN].payload
2878
2879             self.assertEqual(inner[Ether].src, routed_src_mac)
2880             self.assertEqual(inner[Ether].dst, sep4.mac)
2881             self.assertEqual(inner[IPv6].src, ep1.ip6.address)
2882             self.assertEqual(inner[IPv6].dst, ep3.ip6.address)
2883
2884         rxs = self.send_and_expect(self.pg2, p6[1] * 17, sep3.itf)
2885
2886         for rx in rxs:
2887             self.assertEqual(rx[Ether].src, routed_src_mac)
2888             self.assertEqual(rx[Ether].dst, sep3.mac)
2889             self.assertEqual(rx[IPv6].src, ep3.ip6.address)
2890             self.assertEqual(rx[IPv6].dst, ep1.ip6.address)
2891
2892         #
2893         # programme the unknown EP
2894         #
2895         sep4.add_vpp_config()
2896
2897         rxs = self.send_and_expect(self.pg0, p6[0] * 17, sep4.itf)
2898
2899         for rx in rxs:
2900             self.assertEqual(rx[Ether].src, routed_src_mac)
2901             self.assertEqual(rx[Ether].dst, sep4.mac)
2902             self.assertEqual(rx[IPv6].src, ep1.ip6.address)
2903             self.assertEqual(rx[IPv6].dst, ep3.ip6.address)
2904
2905         #
2906         # and revert back to unprogrammed
2907         #
2908         sep4.remove_vpp_config()
2909
2910         rxs = self.send_and_expect(self.pg0, p6[0] * 17, self.pg7)
2911
2912         for rx in rxs:
2913             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
2914             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
2915             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
2916             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
2917             self.assertEqual(rx[VXLAN].vni, 117)
2918             self.assertTrue(rx[VXLAN].flags.G)
2919             self.assertTrue(rx[VXLAN].flags.Instance)
2920             # redirect policy has been applied
2921             self.assertTrue(rx[VXLAN].gpflags.A)
2922             self.assertFalse(rx[VXLAN].gpflags.D)
2923
2924             inner = rx[VXLAN].payload
2925
2926             self.assertEqual(inner[Ether].src, routed_src_mac)
2927             self.assertEqual(inner[Ether].dst, sep4.mac)
2928             self.assertEqual(inner[IPv6].src, ep1.ip6.address)
2929             self.assertEqual(inner[IPv6].dst, ep3.ip6.address)
2930
2931         c1.remove_vpp_config()
2932         c2.remove_vpp_config()
2933
2934         #
2935         # test the symmetric hash mode
2936         #
2937         c1 = VppGbpContract(
2938             self, epg_220.sclass, epg_222.sclass, acl_index,
2939             [VppGbpContractRule(
2940                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
2941                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
2942                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
2943                                        sep1.ip4, sep1.epg.rd),
2944                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
2945                                        sep2.ip4, sep2.epg.rd)]),
2946              VppGbpContractRule(
2947                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
2948                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
2949                  [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
2950                                         sep3.ip6, sep3.epg.rd),
2951                   VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
2952                                         sep4.ip6, sep4.epg.rd)])],
2953             [ETH_P_IP, ETH_P_IPV6])
2954         c1.add_vpp_config()
2955
2956         c2 = VppGbpContract(
2957             self, epg_222.sclass, epg_220.sclass, acl_index,
2958             [VppGbpContractRule(
2959                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
2960                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
2961                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
2962                                        sep1.ip4, sep1.epg.rd),
2963                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
2964                                        sep2.ip4, sep2.epg.rd)]),
2965              VppGbpContractRule(
2966                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
2967                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
2968                  [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
2969                                         sep3.ip6, sep3.epg.rd),
2970                   VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
2971                                         sep4.ip6, sep4.epg.rd)])],
2972             [ETH_P_IP, ETH_P_IPV6])
2973         c2.add_vpp_config()
2974
2975         #
2976         # send again with the contract preset, now packets arrive
2977         # at SEP1 for both directions
2978         #
2979         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
2980
2981         for rx in rxs:
2982             self.assertEqual(rx[Ether].src, routed_src_mac)
2983             self.assertEqual(rx[Ether].dst, sep1.mac)
2984             self.assertEqual(rx[IP].src, ep1.ip4.address)
2985             self.assertEqual(rx[IP].dst, ep3.ip4.address)
2986
2987         rxs = self.send_and_expect(self.pg2, p4[1] * 17, sep1.itf)
2988
2989         for rx in rxs:
2990             self.assertEqual(rx[Ether].src, routed_src_mac)
2991             self.assertEqual(rx[Ether].dst, sep1.mac)
2992             self.assertEqual(rx[IP].src, ep3.ip4.address)
2993             self.assertEqual(rx[IP].dst, ep1.ip4.address)
2994
2995         #
2996         # programme the unknown EP for the L3 tests
2997         #
2998         sep4.add_vpp_config()
2999
3000         #
3001         # an L3 switch packet between local EPs in different EPGs
3002         #  different dest ports on each so the are LB hashed differently
3003         #
3004         p4 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) /
3005                IP(src=ep1.ip4.address, dst=ep2.ip4.address) /
3006                UDP(sport=1234, dport=1234) /
3007                Raw('\xa5' * 100)),
3008               (Ether(src=ep2.mac, dst=str(self.router_mac)) /
3009                IP(src=ep2.ip4.address, dst=ep1.ip4.address) /
3010                UDP(sport=1234, dport=1234) /
3011                Raw('\xa5' * 100))]
3012         p6 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) /
3013                IPv6(src=ep1.ip6.address, dst=ep2.ip6.address) /
3014                UDP(sport=1234, dport=1234) /
3015                Raw('\xa5' * 100)),
3016               (Ether(src=ep2.mac, dst=str(self.router_mac)) /
3017                IPv6(src=ep2.ip6.address, dst=ep1.ip6.address) /
3018                UDP(sport=1234, dport=1234) /
3019                Raw('\xa5' * 100))]
3020
3021         c3 = VppGbpContract(
3022             self, epg_220.sclass, epg_221.sclass, acl_index,
3023             [VppGbpContractRule(
3024                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3025                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3026                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3027                                        sep1.ip4, sep1.epg.rd),
3028                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3029                                        sep2.ip4, sep2.epg.rd)]),
3030              VppGbpContractRule(
3031                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3032                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3033                  [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3034                                         sep3.ip6, sep3.epg.rd),
3035                   VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3036                                         sep4.ip6, sep4.epg.rd)])],
3037             [ETH_P_IP, ETH_P_IPV6])
3038         c3.add_vpp_config()
3039
3040         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
3041
3042         for rx in rxs:
3043             self.assertEqual(rx[Ether].src, routed_src_mac)
3044             self.assertEqual(rx[Ether].dst, sep1.mac)
3045             self.assertEqual(rx[IP].src, ep1.ip4.address)
3046             self.assertEqual(rx[IP].dst, ep2.ip4.address)
3047
3048         #
3049         # learn a remote EP in EPG 221
3050         #
3051         vx_tun_l3 = VppGbpVxlanTunnel(
3052             self, 444, rd1.rd_id,
3053             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3,
3054             self.pg2.local_ip4)
3055         vx_tun_l3.add_vpp_config()
3056
3057         c4 = VppGbpContract(
3058             self, epg_221.sclass, epg_220.sclass, acl_index,
3059             [VppGbpContractRule(
3060                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3061                 []),
3062              VppGbpContractRule(
3063                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3064                  [])],
3065             [ETH_P_IP, ETH_P_IPV6])
3066         c4.add_vpp_config()
3067
3068         p = (Ether(src=self.pg7.remote_mac,
3069                    dst=self.pg7.local_mac) /
3070              IP(src=self.pg7.remote_ip4,
3071                 dst=self.pg7.local_ip4) /
3072              UDP(sport=1234, dport=48879) /
3073              VXLAN(vni=444, gpid=441, flags=0x88) /
3074              Ether(src="00:22:22:22:22:33", dst=str(self.router_mac)) /
3075              IP(src="10.0.0.88", dst=ep1.ip4.address) /
3076              UDP(sport=1234, dport=1234) /
3077              Raw('\xa5' * 100))
3078
3079         rx = self.send_and_expect(self.pg7, [p], self.pg0)
3080
3081         # endpoint learnt via the parent GBP-vxlan interface
3082         self.assertTrue(find_gbp_endpoint(self,
3083                                           vx_tun_l3._sw_if_index,
3084                                           ip="10.0.0.88"))
3085
3086         p = (Ether(src=self.pg7.remote_mac,
3087                    dst=self.pg7.local_mac) /
3088              IP(src=self.pg7.remote_ip4,
3089                 dst=self.pg7.local_ip4) /
3090              UDP(sport=1234, dport=48879) /
3091              VXLAN(vni=444, gpid=441, flags=0x88) /
3092              Ether(src="00:22:22:22:22:33", dst=str(self.router_mac)) /
3093              IPv6(src="2001:10::88", dst=ep1.ip6.address) /
3094              UDP(sport=1234, dport=1234) /
3095              Raw('\xa5' * 100))
3096
3097         rx = self.send_and_expect(self.pg7, [p], self.pg0)
3098
3099         # endpoint learnt via the parent GBP-vxlan interface
3100         self.assertTrue(find_gbp_endpoint(self,
3101                                           vx_tun_l3._sw_if_index,
3102                                           ip="2001:10::88"))
3103
3104         #
3105         # L3 switch from local to remote EP
3106         #
3107         p4 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) /
3108                IP(src=ep1.ip4.address, dst="10.0.0.88") /
3109                UDP(sport=1234, dport=1234) /
3110                Raw('\xa5' * 100))]
3111         p6 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) /
3112                IPv6(src=ep1.ip6.address, dst="2001:10::88") /
3113                UDP(sport=1234, dport=1234) /
3114                Raw('\xa5' * 100))]
3115
3116         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
3117
3118         for rx in rxs:
3119             self.assertEqual(rx[Ether].src, routed_src_mac)
3120             self.assertEqual(rx[Ether].dst, sep1.mac)
3121             self.assertEqual(rx[IP].src, ep1.ip4.address)
3122             self.assertEqual(rx[IP].dst, "10.0.0.88")
3123
3124         rxs = self.send_and_expect(self.pg0, p6[0] * 17, sep4.itf)
3125
3126         for rx in rxs:
3127             self.assertEqual(rx[Ether].src, routed_src_mac)
3128             self.assertEqual(rx[Ether].dst, sep4.mac)
3129             self.assertEqual(rx[IPv6].src, ep1.ip6.address)
3130             self.assertEqual(rx[IPv6].dst, "2001:10::88")
3131
3132         #
3133         # test the dst-ip hash mode
3134         #
3135         c5 = VppGbpContract(
3136             self, epg_220.sclass, epg_221.sclass, acl_index,
3137             [VppGbpContractRule(
3138                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3139                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
3140                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3141                                        sep1.ip4, sep1.epg.rd),
3142                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3143                                        sep2.ip4, sep2.epg.rd)]),
3144              VppGbpContractRule(
3145                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3146                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
3147                  [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3148                                         sep3.ip6, sep3.epg.rd),
3149                   VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3150                                         sep4.ip6, sep4.epg.rd)])],
3151             [ETH_P_IP, ETH_P_IPV6])
3152         c5.add_vpp_config()
3153
3154         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
3155
3156         for rx in rxs:
3157             self.assertEqual(rx[Ether].src, routed_src_mac)
3158             self.assertEqual(rx[Ether].dst, sep1.mac)
3159             self.assertEqual(rx[IP].src, ep1.ip4.address)
3160             self.assertEqual(rx[IP].dst, "10.0.0.88")
3161
3162         rxs = self.send_and_expect(self.pg0, p6[0] * 17, sep3.itf)
3163
3164         for rx in rxs:
3165             self.assertEqual(rx[Ether].src, routed_src_mac)
3166             self.assertEqual(rx[Ether].dst, sep3.mac)
3167             self.assertEqual(rx[IPv6].src, ep1.ip6.address)
3168             self.assertEqual(rx[IPv6].dst, "2001:10::88")
3169
3170         #
3171         # cleanup
3172         #
3173         self.pg7.unconfig_ip4()
3174
3175     def test_gbp_l3_out(self):
3176         """ GBP L3 Out """
3177
3178         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
3179         self.vapi.cli("set logging class gbp debug")
3180
3181         routed_dst_mac = "00:0c:0c:0c:0c:0c"
3182         routed_src_mac = "00:22:bd:f8:19:ff"
3183
3184         #
3185         # IP tables
3186         #
3187         t4 = VppIpTable(self, 1)
3188         t4.add_vpp_config()
3189         t6 = VppIpTable(self, 1, True)
3190         t6.add_vpp_config()
3191
3192         rd1 = VppGbpRouteDomain(self, 2, t4, t6)
3193         rd1.add_vpp_config()
3194
3195         self.loop0.set_mac(self.router_mac)
3196
3197         #
3198         # Bind the BVI to the RD
3199         #
3200         VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
3201         VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
3202
3203         #
3204         # Pg7 hosts a BD's BUM
3205         # Pg1 some other l3 interface
3206         #
3207         self.pg7.config_ip4()
3208         self.pg7.resolve_arp()
3209
3210         #
3211         # a multicast vxlan-gbp tunnel for broadcast in the BD
3212         #
3213         tun_bm = VppVxlanGbpTunnel(self, self.pg7.local_ip4,
3214                                    "239.1.1.1", 88,
3215                                    mcast_itf=self.pg7)
3216         tun_bm.add_vpp_config()
3217
3218         #
3219         # a GBP external bridge domains for the EPs
3220         #
3221         bd1 = VppBridgeDomain(self, 1)
3222         bd1.add_vpp_config()
3223         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0, None, tun_bm)
3224         gbd1.add_vpp_config()
3225
3226         #
3227         # The Endpoint-groups in which the external endpoints exist
3228         #
3229         epg_220 = VppGbpEndpointGroup(self, 220, 113, rd1, gbd1,
3230                                       None, gbd1.bvi,
3231                                       "10.0.0.128",
3232                                       "2001:10::128",
3233                                       VppGbpEndpointRetention(2))
3234         epg_220.add_vpp_config()
3235
3236         # the BVIs have the subnets applied ...
3237         ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 24)
3238         ip4_addr.add_vpp_config()
3239         ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128", 64)
3240         ip6_addr.add_vpp_config()
3241
3242         # ... which are L3-out subnets
3243         l3o_1 = VppGbpSubnet(
3244             self, rd1, "10.0.0.0", 24,
3245             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3246             sclass=113)
3247         l3o_1.add_vpp_config()
3248
3249         #
3250         # an external interface attached to the outside world and the
3251         # external BD
3252         #
3253         vlan_100 = VppDot1QSubint(self, self.pg0, 100)
3254         vlan_100.admin_up()
3255         VppL2Vtr(self, vlan_100, L2_VTR_OP.L2_POP_1).add_vpp_config()
3256         vlan_101 = VppDot1QSubint(self, self.pg0, 101)
3257         vlan_101.admin_up()
3258         VppL2Vtr(self, vlan_101, L2_VTR_OP.L2_POP_1).add_vpp_config()
3259
3260         ext_itf = VppGbpExtItf(self, self.loop0, bd1, rd1)
3261         ext_itf.add_vpp_config()
3262
3263         #
3264         # an unicast vxlan-gbp for inter-RD traffic
3265         #
3266         vx_tun_l3 = VppGbpVxlanTunnel(
3267             self, 444, rd1.rd_id,
3268             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3,
3269             self.pg2.local_ip4)
3270         vx_tun_l3.add_vpp_config()
3271
3272         #
3273         # External Endpoints
3274         #
3275         eep1 = VppGbpEndpoint(self, vlan_100,
3276                               epg_220, None,
3277                               "10.0.0.1", "11.0.0.1",
3278                               "2001:10::1", "3001::1",
3279                               ep_flags.GBP_API_ENDPOINT_FLAG_EXTERNAL)
3280         eep1.add_vpp_config()
3281         eep2 = VppGbpEndpoint(self, vlan_101,
3282                               epg_220, None,
3283                               "10.0.0.2", "11.0.0.2",
3284                               "2001:10::2", "3001::2",
3285                               ep_flags.GBP_API_ENDPOINT_FLAG_EXTERNAL)
3286         eep2.add_vpp_config()
3287
3288         #
3289         # A remote external endpoint
3290         #
3291         rep = VppGbpEndpoint(self, vx_tun_l3,
3292                              epg_220, None,
3293                              "10.0.0.101", "11.0.0.101",
3294                              "2001:10::101", "3001::101",
3295                              ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
3296                              self.pg7.local_ip4,
3297                              self.pg7.remote_ip4,
3298                              mac=None)
3299         rep.add_vpp_config()
3300
3301         #
3302         # ARP packet from External EPs are accepted and replied to
3303         #
3304         p_arp = (Ether(src=eep1.mac, dst="ff:ff:ff:ff:ff:ff") /
3305                  Dot1Q(vlan=100) /
3306                  ARP(op="who-has",
3307                      psrc=eep1.ip4.address, pdst="10.0.0.128",
3308                      hwsrc=eep1.mac, hwdst="ff:ff:ff:ff:ff:ff"))
3309         rxs = self.send_and_expect(self.pg0, p_arp * 1, self.pg0)
3310
3311         #
3312         # packets destined to unknown addresses in the BVI's subnet
3313         # are ARP'd for
3314         #
3315         p4 = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
3316               Dot1Q(vlan=100) /
3317               IP(src="10.0.0.1", dst="10.0.0.88") /
3318               UDP(sport=1234, dport=1234) /
3319               Raw('\xa5' * 100))
3320         p6 = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
3321               Dot1Q(vlan=100) /
3322               IPv6(src="2001:10::1", dst="2001:10::88") /
3323               UDP(sport=1234, dport=1234) /
3324               Raw('\xa5' * 100))
3325
3326         rxs = self.send_and_expect(self.pg0, p4 * 1, self.pg7)
3327
3328         for rx in rxs:
3329             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
3330             # self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
3331             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
3332             self.assertEqual(rx[IP].dst, "239.1.1.1")
3333             self.assertEqual(rx[VXLAN].vni, 88)
3334             self.assertTrue(rx[VXLAN].flags.G)
3335             self.assertTrue(rx[VXLAN].flags.Instance)
3336             # policy was applied to the original IP packet
3337             self.assertEqual(rx[VXLAN].gpid, 113)
3338             self.assertTrue(rx[VXLAN].gpflags.A)
3339             self.assertFalse(rx[VXLAN].gpflags.D)
3340
3341             inner = rx[VXLAN].payload
3342
3343             self.assertTrue(inner.haslayer(ARP))
3344
3345         #
3346         # remote to external
3347         #
3348         p = (Ether(src=self.pg7.remote_mac,
3349                    dst=self.pg7.local_mac) /
3350              IP(src=self.pg7.remote_ip4,
3351                 dst=self.pg7.local_ip4) /
3352              UDP(sport=1234, dport=48879) /
3353              VXLAN(vni=444, gpid=113, flags=0x88) /
3354              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
3355              IP(src="10.0.0.101", dst="10.0.0.1") /
3356              UDP(sport=1234, dport=1234) /
3357              Raw('\xa5' * 100))
3358
3359         rxs = self.send_and_expect(self.pg7, p * 1, self.pg0)
3360
3361         #
3362         # local EP pings router
3363         #
3364         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
3365              Dot1Q(vlan=100) /
3366              IP(src=eep1.ip4.address, dst="10.0.0.128") /
3367              ICMP(type='echo-request'))
3368
3369         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
3370
3371         for rx in rxs:
3372             self.assertEqual(rx[Ether].src, str(self.router_mac))
3373             self.assertEqual(rx[Ether].dst, eep1.mac)
3374             self.assertEqual(rx[Dot1Q].vlan, 100)
3375
3376         #
3377         # local EP pings other local EP
3378         #
3379         p = (Ether(src=eep1.mac, dst=eep2.mac) /
3380              Dot1Q(vlan=100) /
3381              IP(src=eep1.ip4.address, dst=eep2.ip4.address) /
3382              ICMP(type='echo-request'))
3383
3384         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
3385
3386         for rx in rxs:
3387             self.assertEqual(rx[Ether].src, eep1.mac)
3388             self.assertEqual(rx[Ether].dst, eep2.mac)
3389             self.assertEqual(rx[Dot1Q].vlan, 101)
3390
3391         #
3392         # A subnet reachable through the external EP1
3393         #
3394         ip_220 = VppIpRoute(self, "10.220.0.0", 24,
3395                             [VppRoutePath(eep1.ip4.address,
3396                                           eep1.epg.bvi.sw_if_index)],
3397                             table_id=t4.table_id)
3398         ip_220.add_vpp_config()
3399
3400         l3o_220 = VppGbpSubnet(
3401             self, rd1, "10.220.0.0", 24,
3402             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3403             sclass=4220)
3404         l3o_220.add_vpp_config()
3405
3406         #
3407         # A subnet reachable through the external EP2
3408         #
3409         ip_221 = VppIpRoute(self, "10.221.0.0", 24,
3410                             [VppRoutePath(eep2.ip4.address,
3411                                           eep2.epg.bvi.sw_if_index)],
3412                             table_id=t4.table_id)
3413         ip_221.add_vpp_config()
3414
3415         l3o_221 = VppGbpSubnet(
3416             self, rd1, "10.221.0.0", 24,
3417             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3418             sclass=4221)
3419         l3o_221.add_vpp_config()
3420
3421         #
3422         # ping between hosts in remote subnets
3423         #  dropped without a contract
3424         #
3425         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
3426              Dot1Q(vlan=100) /
3427              IP(src="10.220.0.1", dst="10.221.0.1") /
3428              ICMP(type='echo-request'))
3429
3430         rxs = self.send_and_assert_no_replies(self.pg0, p * 1)
3431
3432         #
3433         # contract for the external nets to communicate
3434         #
3435         acl = VppGbpAcl(self)
3436         rule4 = acl.create_rule(permit_deny=1, proto=17)
3437         rule6 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
3438         acl_index = acl.add_vpp_config([rule4, rule6])
3439
3440         c1 = VppGbpContract(
3441             self, 4220, 4221, acl_index,
3442             [VppGbpContractRule(
3443                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3444                 []),
3445              VppGbpContractRule(
3446                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3447                  [])],
3448             [ETH_P_IP, ETH_P_IPV6])
3449         c1.add_vpp_config()
3450
3451         #
3452         # Contracts allowing ext-net 200 to talk with external EPs
3453         #
3454         c2 = VppGbpContract(
3455             self, 4220, 113, acl_index,
3456             [VppGbpContractRule(
3457                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3458                 []),
3459              VppGbpContractRule(
3460                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3461                  [])],
3462             [ETH_P_IP, ETH_P_IPV6])
3463         c2.add_vpp_config()
3464         c3 = VppGbpContract(
3465             self, 113, 4220, acl_index,
3466             [VppGbpContractRule(
3467                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3468                 []),
3469              VppGbpContractRule(
3470                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3471                  [])],
3472             [ETH_P_IP, ETH_P_IPV6])
3473         c3.add_vpp_config()
3474
3475         #
3476         # ping between hosts in remote subnets
3477         #
3478         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
3479              Dot1Q(vlan=100) /
3480              IP(src="10.220.0.1", dst="10.221.0.1") /
3481              UDP(sport=1234, dport=1234) /
3482              Raw('\xa5' * 100))
3483
3484         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
3485
3486         for rx in rxs:
3487             self.assertEqual(rx[Ether].src, str(self.router_mac))
3488             self.assertEqual(rx[Ether].dst, eep2.mac)
3489             self.assertEqual(rx[Dot1Q].vlan, 101)
3490
3491         # we did not learn these external hosts
3492         self.assertFalse(find_gbp_endpoint(self, ip="10.220.0.1"))
3493         self.assertFalse(find_gbp_endpoint(self, ip="10.221.0.1"))
3494
3495         #
3496         # from remote external EP to local external EP
3497         #
3498         p = (Ether(src=self.pg7.remote_mac,
3499                    dst=self.pg7.local_mac) /
3500              IP(src=self.pg7.remote_ip4,
3501                 dst=self.pg7.local_ip4) /
3502              UDP(sport=1234, dport=48879) /
3503              VXLAN(vni=444, gpid=113, flags=0x88) /
3504              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
3505              IP(src="10.0.0.101", dst="10.220.0.1") /
3506              UDP(sport=1234, dport=1234) /
3507              Raw('\xa5' * 100))
3508
3509         rxs = self.send_and_expect(self.pg7, p * 1, self.pg0)
3510
3511         #
3512         # ping from an external host to the remote external EP
3513         #
3514         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
3515              Dot1Q(vlan=100) /
3516              IP(src="10.220.0.1", dst=rep.ip4.address) /
3517              UDP(sport=1234, dport=1234) /
3518              Raw('\xa5' * 100))
3519
3520         rxs = self.send_and_expect(self.pg0, p * 1, self.pg7)
3521
3522         for rx in rxs:
3523             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
3524             # self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
3525             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
3526             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
3527             self.assertEqual(rx[VXLAN].vni, 444)
3528             self.assertTrue(rx[VXLAN].flags.G)
3529             self.assertTrue(rx[VXLAN].flags.Instance)
3530             # the sclass of the ext-net the packet came from
3531             self.assertEqual(rx[VXLAN].gpid, 4220)
3532             # policy was applied to the original IP packet
3533             self.assertTrue(rx[VXLAN].gpflags.A)
3534             # since it's an external host the reciever should not learn it
3535             self.assertTrue(rx[VXLAN].gpflags.D)
3536             inner = rx[VXLAN].payload
3537             self.assertEqual(inner[IP].src, "10.220.0.1")
3538             self.assertEqual(inner[IP].dst, rep.ip4.address)
3539
3540         #
3541         # An external subnet reachable via the remote external EP
3542         #
3543
3544         #
3545         # first the VXLAN-GBP tunnel over which it is reached
3546         #
3547         vx_tun_r = VppVxlanGbpTunnel(
3548             self, self.pg7.local_ip4,
3549             self.pg7.remote_ip4, 445,
3550             mode=(VppEnum.vl_api_vxlan_gbp_api_tunnel_mode_t.
3551                   VXLAN_GBP_API_TUNNEL_MODE_L3))
3552         vx_tun_r.add_vpp_config()
3553         VppIpInterfaceBind(self, vx_tun_r, t4).add_vpp_config()
3554
3555         self.logger.info(self.vapi.cli("sh vxlan-gbp tunnel"))
3556
3557         #
3558         # then the special adj to resolve through on that tunnel
3559         #
3560         n1 = VppNeighbor(self,
3561                          vx_tun_r.sw_if_index,
3562                          "00:0c:0c:0c:0c:0c",
3563                          self.pg7.remote_ip4)
3564         n1.add_vpp_config()
3565
3566         #
3567         # the route via the adj above
3568         #
3569         ip_222 = VppIpRoute(self, "10.222.0.0", 24,
3570                             [VppRoutePath(self.pg7.remote_ip4,
3571                                           vx_tun_r.sw_if_index)],
3572                             table_id=t4.table_id)
3573         ip_222.add_vpp_config()
3574
3575         l3o_222 = VppGbpSubnet(
3576             self, rd1, "10.222.0.0", 24,
3577             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3578             sclass=4222)
3579         l3o_222.add_vpp_config()
3580
3581         #
3582         # ping between hosts in local and remote external subnets
3583         #  dropped without a contract
3584         #
3585         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
3586              Dot1Q(vlan=100) /
3587              IP(src="10.220.0.1", dst="10.222.0.1") /
3588              UDP(sport=1234, dport=1234) /
3589              Raw('\xa5' * 100))
3590
3591         rxs = self.send_and_assert_no_replies(self.pg0, p * 1)
3592
3593         #
3594         # Add contracts ext-nets for 220 -> 222
3595         #
3596         c4 = VppGbpContract(
3597             self, 4220, 4222, acl_index,
3598             [VppGbpContractRule(
3599                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3600                 []),
3601              VppGbpContractRule(
3602                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3603                  [])],
3604             [ETH_P_IP, ETH_P_IPV6])
3605         c4.add_vpp_config()
3606
3607         #
3608         # ping from host in local to remote external subnets
3609         #
3610         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
3611              Dot1Q(vlan=100) /
3612              IP(src="10.220.0.1", dst="10.222.0.1") /
3613              UDP(sport=1234, dport=1234) /
3614              Raw('\xa5' * 100))
3615
3616         rxs = self.send_and_expect(self.pg0, p * 3, self.pg7)
3617
3618         for rx in rxs:
3619             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
3620             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
3621             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
3622             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
3623             self.assertEqual(rx[VXLAN].vni, 445)
3624             self.assertTrue(rx[VXLAN].flags.G)
3625             self.assertTrue(rx[VXLAN].flags.Instance)
3626             # the sclass of the ext-net the packet came from
3627             self.assertEqual(rx[VXLAN].gpid, 4220)
3628             # policy was applied to the original IP packet
3629             self.assertTrue(rx[VXLAN].gpflags.A)
3630             # since it's an external host the reciever should not learn it
3631             self.assertTrue(rx[VXLAN].gpflags.D)
3632             inner = rx[VXLAN].payload
3633             self.assertEqual(inner[Ether].dst, "00:0c:0c:0c:0c:0c")
3634             self.assertEqual(inner[IP].src, "10.220.0.1")
3635             self.assertEqual(inner[IP].dst, "10.222.0.1")
3636
3637         #
3638         # ping from host in remote to local external subnets
3639         # there's no contract for this, but the A bit is set.
3640         #
3641         p = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) /
3642              IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) /
3643              UDP(sport=1234, dport=48879) /
3644              VXLAN(vni=445, gpid=4222, flags=0x88, gpflags='A') /
3645              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
3646              IP(src="10.222.0.1", dst="10.220.0.1") /
3647              UDP(sport=1234, dport=1234) /
3648              Raw('\xa5' * 100))
3649
3650         rxs = self.send_and_expect(self.pg7, p * 3, self.pg0)
3651         self.assertFalse(find_gbp_endpoint(self, ip="10.222.0.1"))
3652
3653         #
3654         # ping from host in remote to remote external subnets
3655         #   this is dropped by reflection check.
3656         #
3657         p = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) /
3658              IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) /
3659              UDP(sport=1234, dport=48879) /
3660              VXLAN(vni=445, gpid=4222, flags=0x88, gpflags='A') /
3661              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
3662              IP(src="10.222.0.1", dst="10.222.0.2") /
3663              UDP(sport=1234, dport=1234) /
3664              Raw('\xa5' * 100))
3665
3666         rxs = self.send_and_assert_no_replies(self.pg7, p * 3)
3667
3668         #
3669         # cleanup
3670         #
3671         self.pg7.unconfig_ip4()
3672         vlan_100.set_vtr(L2_VTR_OP.L2_DISABLED)
3673
3674
3675 if __name__ == '__main__':
3676     unittest.main(testRunner=VppTestRunner)