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