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