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