Tests Cleanup: Fix missing calls to setUpClass/tearDownClass.
[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     @classmethod
579     def setUpClass(cls):
580         super(TestGBP, cls).setUpClass()
581
582     @classmethod
583     def tearDownClass(cls):
584         super(TestGBP, cls).tearDownClass()
585
586     def setUp(self):
587         super(TestGBP, self).setUp()
588
589         self.create_pg_interfaces(range(9))
590         self.create_loopback_interfaces(8)
591
592         self.router_mac = MACAddress("00:11:22:33:44:55")
593
594         for i in self.pg_interfaces:
595             i.admin_up()
596         for i in self.lo_interfaces:
597             i.admin_up()
598
599     def tearDown(self):
600         for i in self.pg_interfaces:
601             i.admin_down()
602
603         super(TestGBP, self).tearDown()
604
605     def send_and_expect_bridged(self, src, tx, dst):
606         rx = self.send_and_expect(src, tx, dst)
607
608         for r in rx:
609             self.assertEqual(r[Ether].src, tx[0][Ether].src)
610             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
611             self.assertEqual(r[IP].src, tx[0][IP].src)
612             self.assertEqual(r[IP].dst, tx[0][IP].dst)
613         return rx
614
615     def send_and_expect_bridged6(self, src, tx, dst):
616         rx = self.send_and_expect(src, tx, dst)
617
618         for r in rx:
619             self.assertEqual(r[Ether].src, tx[0][Ether].src)
620             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
621             self.assertEqual(r[IPv6].src, tx[0][IPv6].src)
622             self.assertEqual(r[IPv6].dst, tx[0][IPv6].dst)
623         return rx
624
625     def send_and_expect_routed(self, src, tx, dst, src_mac):
626         rx = self.send_and_expect(src, tx, dst)
627
628         for r in rx:
629             self.assertEqual(r[Ether].src, src_mac)
630             self.assertEqual(r[Ether].dst, dst.remote_mac)
631             self.assertEqual(r[IP].src, tx[0][IP].src)
632             self.assertEqual(r[IP].dst, tx[0][IP].dst)
633         return rx
634
635     def send_and_expect_natted(self, src, tx, dst, src_ip):
636         rx = self.send_and_expect(src, tx, dst)
637
638         for r in rx:
639             self.assertEqual(r[Ether].src, tx[0][Ether].src)
640             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
641             self.assertEqual(r[IP].src, src_ip)
642             self.assertEqual(r[IP].dst, tx[0][IP].dst)
643         return rx
644
645     def send_and_expect_natted6(self, src, tx, dst, src_ip):
646         rx = self.send_and_expect(src, tx, dst)
647
648         for r in rx:
649             self.assertEqual(r[Ether].src, tx[0][Ether].src)
650             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
651             self.assertEqual(r[IPv6].src, src_ip)
652             self.assertEqual(r[IPv6].dst, tx[0][IPv6].dst)
653         return rx
654
655     def send_and_expect_unnatted(self, src, tx, dst, dst_ip):
656         rx = self.send_and_expect(src, tx, dst)
657
658         for r in rx:
659             self.assertEqual(r[Ether].src, tx[0][Ether].src)
660             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
661             self.assertEqual(r[IP].dst, dst_ip)
662             self.assertEqual(r[IP].src, tx[0][IP].src)
663         return rx
664
665     def send_and_expect_unnatted6(self, src, tx, dst, dst_ip):
666         rx = self.send_and_expect(src, tx, dst)
667
668         for r in rx:
669             self.assertEqual(r[Ether].src, tx[0][Ether].src)
670             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
671             self.assertEqual(r[IPv6].dst, dst_ip)
672             self.assertEqual(r[IPv6].src, tx[0][IPv6].src)
673         return rx
674
675     def send_and_expect_double_natted(self, src, tx, dst, src_ip, dst_ip):
676         rx = self.send_and_expect(src, tx, dst)
677
678         for r in rx:
679             self.assertEqual(r[Ether].src, str(self.router_mac))
680             self.assertEqual(r[Ether].dst, dst.remote_mac)
681             self.assertEqual(r[IP].dst, dst_ip)
682             self.assertEqual(r[IP].src, src_ip)
683         return rx
684
685     def send_and_expect_double_natted6(self, src, tx, dst, src_ip, dst_ip):
686         rx = self.send_and_expect(src, tx, dst)
687
688         for r in rx:
689             self.assertEqual(r[Ether].src, str(self.router_mac))
690             self.assertEqual(r[Ether].dst, dst.remote_mac)
691             self.assertEqual(r[IPv6].dst, dst_ip)
692             self.assertEqual(r[IPv6].src, src_ip)
693         return rx
694
695     def test_gbp(self):
696         """ Group Based Policy """
697
698         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
699
700         #
701         # Bridge Domains
702         #
703         bd1 = VppBridgeDomain(self, 1)
704         bd2 = VppBridgeDomain(self, 2)
705         bd20 = VppBridgeDomain(self, 20)
706
707         bd1.add_vpp_config()
708         bd2.add_vpp_config()
709         bd20.add_vpp_config()
710
711         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0)
712         gbd2 = VppGbpBridgeDomain(self, bd2, self.loop1)
713         gbd20 = VppGbpBridgeDomain(self, bd20, self.loop2)
714
715         gbd1.add_vpp_config()
716         gbd2.add_vpp_config()
717         gbd20.add_vpp_config()
718
719         #
720         # Route Domains
721         #
722         gt4 = VppIpTable(self, 0)
723         gt4.add_vpp_config()
724         gt6 = VppIpTable(self, 0, is_ip6=True)
725         gt6.add_vpp_config()
726         nt4 = VppIpTable(self, 20)
727         nt4.add_vpp_config()
728         nt6 = VppIpTable(self, 20, is_ip6=True)
729         nt6.add_vpp_config()
730
731         rd0 = VppGbpRouteDomain(self, 0, gt4, gt6, None, None)
732         rd20 = VppGbpRouteDomain(self, 20, nt4, nt6, None, None)
733
734         rd0.add_vpp_config()
735         rd20.add_vpp_config()
736
737         #
738         # 3 EPGs, 2 of which share a BD.
739         # 2 NAT EPGs, one for floating-IP subnets, the other for internet
740         #
741         epgs = [VppGbpEndpointGroup(self, 220, 1220, rd0, gbd1,
742                                     self.pg4, self.loop0,
743                                     "10.0.0.128", "2001:10::128"),
744                 VppGbpEndpointGroup(self, 221, 1221, rd0, gbd1,
745                                     self.pg5, self.loop0,
746                                     "10.0.1.128", "2001:10:1::128"),
747                 VppGbpEndpointGroup(self, 222, 1222, rd0, gbd2,
748                                     self.pg6, self.loop1,
749                                     "10.0.2.128", "2001:10:2::128"),
750                 VppGbpEndpointGroup(self, 333, 1333, rd20, gbd20,
751                                     self.pg7, self.loop2,
752                                     "11.0.0.128", "3001::128"),
753                 VppGbpEndpointGroup(self, 444, 1444, rd20, gbd20,
754                                     self.pg8, self.loop2,
755                                     "11.0.0.129", "3001::129")]
756         recircs = [VppGbpRecirc(self, epgs[0], self.loop3),
757                    VppGbpRecirc(self, epgs[1], self.loop4),
758                    VppGbpRecirc(self, epgs[2], self.loop5),
759                    VppGbpRecirc(self, epgs[3], self.loop6, is_ext=True),
760                    VppGbpRecirc(self, epgs[4], self.loop7, is_ext=True)]
761
762         epg_nat = epgs[3]
763         recirc_nat = recircs[3]
764
765         #
766         # 4 end-points, 2 in the same subnet, 3 in the same BD
767         #
768         eps = [VppGbpEndpoint(self, self.pg0,
769                               epgs[0], recircs[0],
770                               "10.0.0.1", "11.0.0.1",
771                               "2001:10::1", "3001::1"),
772                VppGbpEndpoint(self, self.pg1,
773                               epgs[0], recircs[0],
774                               "10.0.0.2", "11.0.0.2",
775                               "2001:10::2", "3001::2"),
776                VppGbpEndpoint(self, self.pg2,
777                               epgs[1], recircs[1],
778                               "10.0.1.1", "11.0.0.3",
779                               "2001:10:1::1", "3001::3"),
780                VppGbpEndpoint(self, self.pg3,
781                               epgs[2], recircs[2],
782                               "10.0.2.1", "11.0.0.4",
783                               "2001:10:2::1", "3001::4")]
784
785         #
786         # Config related to each of the EPGs
787         #
788         for epg in epgs:
789             # IP config on the BVI interfaces
790             if epg != epgs[1] and epg != epgs[4]:
791                 VppIpInterfaceBind(self, epg.bvi, epg.rd.t4).add_vpp_config()
792                 VppIpInterfaceBind(self, epg.bvi, epg.rd.t6).add_vpp_config()
793                 self.vapi.sw_interface_set_mac_address(
794                     epg.bvi.sw_if_index,
795                     self.router_mac.packed)
796
797                 # The BVIs are NAT inside interfaces
798                 self.vapi.nat44_interface_add_del_feature(epg.bvi.sw_if_index,
799                                                           is_inside=1,
800                                                           is_add=1)
801                 self.vapi.nat66_add_del_interface(epg.bvi.sw_if_index,
802                                                   is_inside=1,
803                                                   is_add=1)
804
805             if_ip4 = VppIpInterfaceAddress(self, epg.bvi, epg.bvi_ip4, 32)
806             if_ip6 = VppIpInterfaceAddress(self, epg.bvi, epg.bvi_ip6, 128)
807             if_ip4.add_vpp_config()
808             if_ip6.add_vpp_config()
809
810             # EPG uplink interfaces in the RD
811             VppIpInterfaceBind(self, epg.uplink, epg.rd.t4).add_vpp_config()
812             VppIpInterfaceBind(self, epg.uplink, epg.rd.t6).add_vpp_config()
813
814             # add the BD ARP termination entry for BVI IP
815             epg.bd_arp_ip4 = VppBridgeDomainArpEntry(self, epg.bd.bd,
816                                                      str(self.router_mac),
817                                                      epg.bvi_ip4)
818             epg.bd_arp_ip6 = VppBridgeDomainArpEntry(self, epg.bd.bd,
819                                                      str(self.router_mac),
820                                                      epg.bvi_ip6)
821             epg.bd_arp_ip4.add_vpp_config()
822             epg.bd_arp_ip6.add_vpp_config()
823
824             # EPG in VPP
825             epg.add_vpp_config()
826
827         for recirc in recircs:
828             # EPG's ingress recirculation interface maps to its RD
829             VppIpInterfaceBind(self, recirc.recirc,
830                                recirc.epg.rd.t4).add_vpp_config()
831             VppIpInterfaceBind(self, recirc.recirc,
832                                recirc.epg.rd.t6).add_vpp_config()
833
834             self.vapi.nat44_interface_add_del_feature(
835                 recirc.recirc.sw_if_index,
836                 is_inside=0,
837                 is_add=1)
838             self.vapi.nat66_add_del_interface(
839                 recirc.recirc.sw_if_index,
840                 is_inside=0,
841                 is_add=1)
842
843             recirc.add_vpp_config()
844
845         for recirc in recircs:
846             self.assertTrue(find_bridge_domain_port(self,
847                                                     recirc.epg.bd.bd.bd_id,
848                                                     recirc.recirc.sw_if_index))
849
850         for ep in eps:
851             self.pg_enable_capture(self.pg_interfaces)
852             self.pg_start()
853             #
854             # routes to the endpoints. We need these since there are no
855             # adj-fibs due to the fact the the BVI address has /32 and
856             # the subnet is not attached.
857             #
858             for (ip, fip) in zip(ep.ips, ep.fips):
859                 # Add static mappings for each EP from the 10/8 to 11/8 network
860                 if ip.af == AF_INET:
861                     self.vapi.nat44_add_del_static_mapping(ip.bytes,
862                                                            fip.bytes,
863                                                            vrf_id=0,
864                                                            addr_only=1)
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             self.vapi.nat44_add_del_static_mapping(ep.ip4.bytes,
1408                                                    ep.fip4.bytes,
1409                                                    vrf_id=0,
1410                                                    addr_only=1,
1411                                                    is_add=0)
1412             self.vapi.nat66_add_del_static_mapping(ep.ip6.bytes,
1413                                                    ep.fip6.bytes,
1414                                                    vrf_id=0,
1415                                                    is_add=0)
1416
1417         for epg in epgs:
1418             # IP config on the BVI interfaces
1419             if epg != epgs[0] and epg != epgs[3]:
1420                 self.vapi.nat44_interface_add_del_feature(epg.bvi.sw_if_index,
1421                                                           is_inside=1,
1422                                                           is_add=0)
1423                 self.vapi.nat66_add_del_interface(epg.bvi.sw_if_index,
1424                                                   is_inside=1,
1425                                                   is_add=0)
1426
1427         for recirc in recircs:
1428             self.vapi.nat44_interface_add_del_feature(
1429                 recirc.recirc.sw_if_index,
1430                 is_inside=0,
1431                 is_add=0)
1432             self.vapi.nat66_add_del_interface(
1433                 recirc.recirc.sw_if_index,
1434                 is_inside=0,
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         # static EP cannot reach the learnt EPs since there is no contract
1818         # only test 1 EP as the others could timeout
1819         #
1820         p = (Ether(src=ep.mac, dst=l['mac']) /
1821              IP(dst=learnt[0]['ip'], src=ep.ip4.address) /
1822              UDP(sport=1234, dport=1234) /
1823              Raw('\xa5' * 100))
1824
1825         self.send_and_assert_no_replies(self.pg0, [p])
1826
1827         #
1828         # refresh the entries after the check for no replies above
1829         #
1830         for l in learnt:
1831             # a packet with an sclass from a known EPG
1832             p = (Ether(src=self.pg2.remote_mac,
1833                        dst=self.pg2.local_mac) /
1834                  IP(src=self.pg2.remote_hosts[1].ip4,
1835                     dst=self.pg2.local_ip4) /
1836                  UDP(sport=1234, dport=48879) /
1837                  VXLAN(vni=99, gpid=113, flags=0x88, gpflags='A') /
1838                  Ether(src=l['mac'], dst=ep.mac) /
1839                  IP(src=l['ip'], dst=ep.ip4.address) /
1840                  UDP(sport=1234, dport=1234) /
1841                  Raw('\xa5' * 100))
1842
1843             rx = self.send_and_expect(self.pg2, p*65, self.pg0)
1844
1845             self.assertTrue(find_gbp_endpoint(self,
1846                                               vx_tun_l2_1.sw_if_index,
1847                                               mac=l['mac']))
1848
1849         #
1850         # Add the contract so they can talk
1851         #
1852         acl = VppGbpAcl(self)
1853         rule = acl.create_rule(permit_deny=1, proto=17)
1854         rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
1855         acl_index = acl.add_vpp_config([rule, rule2])
1856         c1 = VppGbpContract(
1857             self, epg_220.sclass, epg_330.sclass, acl_index,
1858             [VppGbpContractRule(
1859                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1860                 []),
1861              VppGbpContractRule(
1862                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1863                  [])],
1864             [ETH_P_IP, ETH_P_IPV6])
1865         c1.add_vpp_config()
1866
1867         for l in learnt:
1868             p = (Ether(src=ep.mac, dst=l['mac']) /
1869                  IP(dst=l['ip'], src=ep.ip4.address) /
1870                  UDP(sport=1234, dport=1234) /
1871                  Raw('\xa5' * 100))
1872
1873             self.send_and_expect(self.pg0, [p], self.pg2)
1874
1875         #
1876         # send UU packets from the local EP
1877         #
1878         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1879         self.logger.info(self.vapi.cli("sh gbp bridge"))
1880         p_uu = (Ether(src=ep.mac, dst="00:11:11:11:11:11") /
1881                 IP(dst="10.0.0.133", src=ep.ip4.address) /
1882                 UDP(sport=1234, dport=1234) /
1883                 Raw('\xa5' * 100))
1884         rxs = self.send_and_expect(ep.itf, [p_uu], gbd1.uu_fwd)
1885
1886         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1887
1888         p_bm = (Ether(src=ep.mac, dst="ff:ff:ff:ff:ff:ff") /
1889                 IP(dst="10.0.0.133", src=ep.ip4.address) /
1890                 UDP(sport=1234, dport=1234) /
1891                 Raw('\xa5' * 100))
1892         rxs = self.send_and_expect_only(ep.itf, [p_bm], tun_bm.mcast_itf)
1893
1894         for rx in rxs:
1895             self.assertEqual(rx[IP].src, self.pg4.local_ip4)
1896             self.assertEqual(rx[IP].dst, "239.1.1.1")
1897             self.assertEqual(rx[UDP].dport, 48879)
1898             # the UDP source port is a random value for hashing
1899             self.assertEqual(rx[VXLAN].gpid, 112)
1900             self.assertEqual(rx[VXLAN].vni, 88)
1901             self.assertTrue(rx[VXLAN].flags.G)
1902             self.assertTrue(rx[VXLAN].flags.Instance)
1903             self.assertFalse(rx[VXLAN].gpflags.A)
1904             self.assertFalse(rx[VXLAN].gpflags.D)
1905
1906         #
1907         # Check v6 Endpoints
1908         #
1909         for l in learnt:
1910             # a packet with an sclass from a known EPG
1911             p = (Ether(src=self.pg2.remote_mac,
1912                        dst=self.pg2.local_mac) /
1913                  IP(src=self.pg2.remote_hosts[1].ip4,
1914                     dst=self.pg2.local_ip4) /
1915                  UDP(sport=1234, dport=48879) /
1916                  VXLAN(vni=99, gpid=113, flags=0x88, gpflags='A') /
1917                  Ether(src=l['mac'], dst=ep.mac) /
1918                  IPv6(src=l['ip6'], dst=ep.ip6.address) /
1919                  UDP(sport=1234, dport=1234) /
1920                  Raw('\xa5' * 100))
1921
1922             rx = self.send_and_expect(self.pg2, p*65, self.pg0)
1923
1924             self.assertTrue(find_gbp_endpoint(self,
1925                                               vx_tun_l2_1.sw_if_index,
1926                                               mac=l['mac']))
1927
1928         #
1929         # L3 Endpoint Learning
1930         #  - configured on the bridge's BVI
1931         #
1932
1933         #
1934         # clean up
1935         #
1936         for l in learnt:
1937             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
1938                                      mac=l['mac'])
1939         self.pg2.unconfig_ip4()
1940         self.pg3.unconfig_ip4()
1941         self.pg4.unconfig_ip4()
1942
1943         self.logger.info(self.vapi.cli("sh int"))
1944         self.logger.info(self.vapi.cli("sh gbp vxlan"))
1945
1946     def test_gbp_bd_flags(self):
1947         """ GBP BD FLAGS """
1948
1949         #
1950         # IP tables
1951         #
1952         gt4 = VppIpTable(self, 1)
1953         gt4.add_vpp_config()
1954         gt6 = VppIpTable(self, 1, is_ip6=True)
1955         gt6.add_vpp_config()
1956
1957         rd1 = VppGbpRouteDomain(self, 1, gt4, gt6)
1958         rd1.add_vpp_config()
1959
1960         #
1961         # Pg3 hosts the IP4 UU-flood VXLAN tunnel
1962         # Pg4 hosts the IP6 UU-flood VXLAN tunnel
1963         #
1964         self.pg3.config_ip4()
1965         self.pg3.resolve_arp()
1966         self.pg4.config_ip4()
1967         self.pg4.resolve_arp()
1968
1969         #
1970         # Add a mcast destination VXLAN-GBP tunnel for B&M traffic
1971         #
1972         tun_bm = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
1973                                    "239.1.1.1", 88,
1974                                    mcast_itf=self.pg4)
1975         tun_bm.add_vpp_config()
1976
1977         #
1978         # a GBP bridge domain with a BVI and a UU-flood interface
1979         #
1980         bd1 = VppBridgeDomain(self, 1)
1981         bd1.add_vpp_config()
1982
1983         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0, self.pg3, tun_bm,
1984                                   uu_drop=True, bm_drop=True)
1985         gbd1.add_vpp_config()
1986
1987         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1988         self.logger.info(self.vapi.cli("sh gbp bridge"))
1989
1990         # ... and has a /32 applied
1991         ip_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
1992         ip_addr.add_vpp_config()
1993
1994         #
1995         # The Endpoint-group
1996         #
1997         epg_220 = VppGbpEndpointGroup(self, 220, 112, rd1, gbd1,
1998                                       None, self.loop0,
1999                                       "10.0.0.128",
2000                                       "2001:10::128",
2001                                       VppGbpEndpointRetention(2))
2002         epg_220.add_vpp_config()
2003
2004         ep = VppGbpEndpoint(self, self.pg0,
2005                             epg_220, None,
2006                             "10.0.0.127", "11.0.0.127",
2007                             "2001:10::1", "3001::1")
2008         ep.add_vpp_config()
2009         #
2010         # send UU/BM packet from the local EP with UU drop and BM drop enabled
2011         # in bd
2012         #
2013         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
2014         self.logger.info(self.vapi.cli("sh gbp bridge"))
2015         p_uu = (Ether(src=ep.mac, dst="00:11:11:11:11:11") /
2016                 IP(dst="10.0.0.133", src=ep.ip4.address) /
2017                 UDP(sport=1234, dport=1234) /
2018                 Raw('\xa5' * 100))
2019         self.send_and_assert_no_replies(ep.itf, [p_uu])
2020
2021         p_bm = (Ether(src=ep.mac, dst="ff:ff:ff:ff:ff:ff") /
2022                 IP(dst="10.0.0.133", src=ep.ip4.address) /
2023                 UDP(sport=1234, dport=1234) /
2024                 Raw('\xa5' * 100))
2025         self.send_and_assert_no_replies(ep.itf, [p_bm])
2026
2027         self.pg3.unconfig_ip4()
2028         self.pg4.unconfig_ip4()
2029
2030         self.logger.info(self.vapi.cli("sh int"))
2031
2032     def test_gbp_learn_vlan_l2(self):
2033         """ GBP L2 Endpoint w/ VLANs"""
2034
2035         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
2036         learnt = [{'mac': '00:00:11:11:11:01',
2037                    'ip': '10.0.0.1',
2038                    'ip6': '2001:10::2'},
2039                   {'mac': '00:00:11:11:11:02',
2040                    'ip': '10.0.0.2',
2041                    'ip6': '2001:10::3'}]
2042
2043         #
2044         # IP tables
2045         #
2046         gt4 = VppIpTable(self, 1)
2047         gt4.add_vpp_config()
2048         gt6 = VppIpTable(self, 1, is_ip6=True)
2049         gt6.add_vpp_config()
2050
2051         rd1 = VppGbpRouteDomain(self, 1, gt4, gt6)
2052         rd1.add_vpp_config()
2053
2054         #
2055         # Pg2 hosts the vxlan tunnel, hosts on pg2 to act as TEPs
2056         #
2057         self.pg2.config_ip4()
2058         self.pg2.resolve_arp()
2059         self.pg2.generate_remote_hosts(4)
2060         self.pg2.configure_ipv4_neighbors()
2061         self.pg3.config_ip4()
2062         self.pg3.resolve_arp()
2063
2064         #
2065         # The EP will be on a vlan sub-interface
2066         #
2067         vlan_11 = VppDot1QSubint(self, self.pg0, 11)
2068         vlan_11.admin_up()
2069         self.vapi.l2_interface_vlan_tag_rewrite(
2070             sw_if_index=vlan_11.sw_if_index, vtr_op=L2_VTR_OP.L2_POP_1,
2071             push_dot1q=11)
2072
2073         bd_uu_fwd = VppVxlanGbpTunnel(self, self.pg3.local_ip4,
2074                                       self.pg3.remote_ip4, 116)
2075         bd_uu_fwd.add_vpp_config()
2076
2077         #
2078         # a GBP bridge domain with a BVI and a UU-flood interface
2079         # The BD is marked as do not learn, so no endpoints are ever
2080         # learnt in this BD.
2081         #
2082         bd1 = VppBridgeDomain(self, 1)
2083         bd1.add_vpp_config()
2084         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0, bd_uu_fwd,
2085                                   learn=False)
2086         gbd1.add_vpp_config()
2087
2088         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
2089         self.logger.info(self.vapi.cli("sh gbp bridge"))
2090
2091         # ... and has a /32 applied
2092         ip_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
2093         ip_addr.add_vpp_config()
2094
2095         #
2096         # The Endpoint-group in which we are learning endpoints
2097         #
2098         epg_220 = VppGbpEndpointGroup(self, 220, 441, rd1, gbd1,
2099                                       None, self.loop0,
2100                                       "10.0.0.128",
2101                                       "2001:10::128",
2102                                       VppGbpEndpointRetention(2))
2103         epg_220.add_vpp_config()
2104
2105         #
2106         # The VXLAN GBP tunnel is a bridge-port and has L2 endpoint
2107         # learning enabled
2108         #
2109         vx_tun_l2_1 = VppGbpVxlanTunnel(
2110             self, 99, bd1.bd_id,
2111             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L2,
2112             self.pg2.local_ip4)
2113         vx_tun_l2_1.add_vpp_config()
2114
2115         #
2116         # A static endpoint that the learnt endpoints are trying to
2117         # talk to
2118         #
2119         ep = VppGbpEndpoint(self, vlan_11,
2120                             epg_220, None,
2121                             "10.0.0.127", "11.0.0.127",
2122                             "2001:10::1", "3001::1")
2123         ep.add_vpp_config()
2124
2125         self.assertTrue(find_route(self, ep.ip4.address, 32, table_id=1))
2126
2127         #
2128         # Send to the static EP
2129         #
2130         for ii, l in enumerate(learnt):
2131             # a packet with an sclass from a known EPG
2132             # arriving on an unknown TEP
2133             p = (Ether(src=self.pg2.remote_mac,
2134                        dst=self.pg2.local_mac) /
2135                  IP(src=self.pg2.remote_hosts[1].ip4,
2136                     dst=self.pg2.local_ip4) /
2137                  UDP(sport=1234, dport=48879) /
2138                  VXLAN(vni=99, gpid=441, flags=0x88) /
2139                  Ether(src=l['mac'], dst=ep.mac) /
2140                  IP(src=l['ip'], dst=ep.ip4.address) /
2141                  UDP(sport=1234, dport=1234) /
2142                  Raw('\xa5' * 100))
2143
2144             rxs = self.send_and_expect(self.pg2, [p], self.pg0)
2145
2146             #
2147             # packet to EP has the EP's vlan tag
2148             #
2149             for rx in rxs:
2150                 self.assertEqual(rx[Dot1Q].vlan, 11)
2151
2152             #
2153             # the EP is not learnt since the BD setting prevents it
2154             # also no TEP too
2155             #
2156             self.assertFalse(find_gbp_endpoint(self,
2157                                                vx_tun_l2_1.sw_if_index,
2158                                                mac=l['mac']))
2159             self.assertEqual(INDEX_INVALID,
2160                              find_vxlan_gbp_tunnel(
2161                                  self,
2162                                  self.pg2.local_ip4,
2163                                  self.pg2.remote_hosts[1].ip4,
2164                                  99))
2165
2166         self.assertEqual(len(self.vapi.gbp_endpoint_dump()), 1)
2167
2168         #
2169         # static to remotes
2170         # we didn't learn the remotes so they are sent to the UU-fwd
2171         #
2172         for l in learnt:
2173             p = (Ether(src=ep.mac, dst=l['mac']) /
2174                  Dot1Q(vlan=11) /
2175                  IP(dst=l['ip'], src=ep.ip4.address) /
2176                  UDP(sport=1234, dport=1234) /
2177                  Raw('\xa5' * 100))
2178
2179             rxs = self.send_and_expect(self.pg0, p * 17, self.pg3)
2180
2181             for rx in rxs:
2182                 self.assertEqual(rx[IP].src, self.pg3.local_ip4)
2183                 self.assertEqual(rx[IP].dst, self.pg3.remote_ip4)
2184                 self.assertEqual(rx[UDP].dport, 48879)
2185                 # the UDP source port is a random value for hashing
2186                 self.assertEqual(rx[VXLAN].gpid, 441)
2187                 self.assertEqual(rx[VXLAN].vni, 116)
2188                 self.assertTrue(rx[VXLAN].flags.G)
2189                 self.assertTrue(rx[VXLAN].flags.Instance)
2190                 self.assertFalse(rx[VXLAN].gpflags.A)
2191                 self.assertFalse(rx[VXLAN].gpflags.D)
2192
2193         self.pg2.unconfig_ip4()
2194         self.pg3.unconfig_ip4()
2195
2196     def test_gbp_learn_l3(self):
2197         """ GBP L3 Endpoint Learning """
2198
2199         self.vapi.cli("set logging class gbp debug")
2200
2201         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
2202         routed_dst_mac = "00:0c:0c:0c:0c:0c"
2203         routed_src_mac = "00:22:bd:f8:19:ff"
2204
2205         learnt = [{'mac': '00:00:11:11:11:02',
2206                    'ip': '10.0.1.2',
2207                    'ip6': '2001:10::2'},
2208                   {'mac': '00:00:11:11:11:03',
2209                    'ip': '10.0.1.3',
2210                    'ip6': '2001:10::3'}]
2211
2212         #
2213         # IP tables
2214         #
2215         t4 = VppIpTable(self, 1)
2216         t4.add_vpp_config()
2217         t6 = VppIpTable(self, 1, True)
2218         t6.add_vpp_config()
2219
2220         tun_ip4_uu = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
2221                                        self.pg4.remote_ip4, 114)
2222         tun_ip6_uu = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
2223                                        self.pg4.remote_ip4, 116)
2224         tun_ip4_uu.add_vpp_config()
2225         tun_ip6_uu.add_vpp_config()
2226
2227         rd1 = VppGbpRouteDomain(self, 2, t4, t6, tun_ip4_uu, tun_ip6_uu)
2228         rd1.add_vpp_config()
2229
2230         self.loop0.set_mac(self.router_mac)
2231
2232         #
2233         # Bind the BVI to the RD
2234         #
2235         VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
2236         VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
2237
2238         #
2239         # Pg2 hosts the vxlan tunnel
2240         # hosts on pg2 to act as TEPs
2241         # pg3 is BD uu-fwd
2242         # pg4 is RD uu-fwd
2243         #
2244         self.pg2.config_ip4()
2245         self.pg2.resolve_arp()
2246         self.pg2.generate_remote_hosts(4)
2247         self.pg2.configure_ipv4_neighbors()
2248         self.pg3.config_ip4()
2249         self.pg3.resolve_arp()
2250         self.pg4.config_ip4()
2251         self.pg4.resolve_arp()
2252
2253         #
2254         # a GBP bridge domain with a BVI and a UU-flood interface
2255         #
2256         bd1 = VppBridgeDomain(self, 1)
2257         bd1.add_vpp_config()
2258         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0, self.pg3)
2259         gbd1.add_vpp_config()
2260
2261         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
2262         self.logger.info(self.vapi.cli("sh gbp bridge"))
2263         self.logger.info(self.vapi.cli("sh gbp route"))
2264
2265         # ... and has a /32 and /128 applied
2266         ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
2267         ip4_addr.add_vpp_config()
2268         ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128", 128)
2269         ip6_addr.add_vpp_config()
2270
2271         #
2272         # The Endpoint-group in which we are learning endpoints
2273         #
2274         epg_220 = VppGbpEndpointGroup(self, 220, 441, rd1, gbd1,
2275                                       None, self.loop0,
2276                                       "10.0.0.128",
2277                                       "2001:10::128",
2278                                       VppGbpEndpointRetention(2))
2279         epg_220.add_vpp_config()
2280
2281         #
2282         # The VXLAN GBP tunnel is a bridge-port and has L2 endpoint
2283         # learning enabled
2284         #
2285         vx_tun_l3 = VppGbpVxlanTunnel(
2286             self, 101, rd1.rd_id,
2287             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3,
2288             self.pg2.local_ip4)
2289         vx_tun_l3.add_vpp_config()
2290
2291         #
2292         # A static endpoint that the learnt endpoints are trying to
2293         # talk to
2294         #
2295         ep = VppGbpEndpoint(self, self.pg0,
2296                             epg_220, None,
2297                             "10.0.0.127", "11.0.0.127",
2298                             "2001:10::1", "3001::1")
2299         ep.add_vpp_config()
2300
2301         #
2302         # learn some remote IPv4 EPs
2303         #
2304         for ii, l in enumerate(learnt):
2305             # a packet with an sclass from a known EPG
2306             # arriving on an unknown TEP
2307             p = (Ether(src=self.pg2.remote_mac,
2308                        dst=self.pg2.local_mac) /
2309                  IP(src=self.pg2.remote_hosts[1].ip4,
2310                     dst=self.pg2.local_ip4) /
2311                  UDP(sport=1234, dport=48879) /
2312                  VXLAN(vni=101, gpid=441, flags=0x88) /
2313                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
2314                  IP(src=l['ip'], dst=ep.ip4.address) /
2315                  UDP(sport=1234, dport=1234) /
2316                  Raw('\xa5' * 100))
2317
2318             rx = self.send_and_expect(self.pg2, [p], self.pg0)
2319
2320             # the new TEP
2321             tep1_sw_if_index = find_vxlan_gbp_tunnel(
2322                 self,
2323                 self.pg2.local_ip4,
2324                 self.pg2.remote_hosts[1].ip4,
2325                 vx_tun_l3.vni)
2326             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
2327
2328             # endpoint learnt via the parent GBP-vxlan interface
2329             self.assertTrue(find_gbp_endpoint(self,
2330                                               vx_tun_l3._sw_if_index,
2331                                               ip=l['ip']))
2332
2333         #
2334         # Static IPv4 EP replies to learnt
2335         #
2336         for l in learnt:
2337             p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2338                  IP(dst=l['ip'], src=ep.ip4.address) /
2339                  UDP(sport=1234, dport=1234) /
2340                  Raw('\xa5' * 100))
2341
2342             rxs = self.send_and_expect(self.pg0, p*1, self.pg2)
2343
2344             for rx in rxs:
2345                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2346                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
2347                 self.assertEqual(rx[UDP].dport, 48879)
2348                 # the UDP source port is a random value for hashing
2349                 self.assertEqual(rx[VXLAN].gpid, 441)
2350                 self.assertEqual(rx[VXLAN].vni, 101)
2351                 self.assertTrue(rx[VXLAN].flags.G)
2352                 self.assertTrue(rx[VXLAN].flags.Instance)
2353                 self.assertTrue(rx[VXLAN].gpflags.A)
2354                 self.assertFalse(rx[VXLAN].gpflags.D)
2355
2356                 inner = rx[VXLAN].payload
2357
2358                 self.assertEqual(inner[Ether].src, routed_src_mac)
2359                 self.assertEqual(inner[Ether].dst, routed_dst_mac)
2360                 self.assertEqual(inner[IP].src, ep.ip4.address)
2361                 self.assertEqual(inner[IP].dst, l['ip'])
2362
2363         for l in learnt:
2364             self.assertFalse(find_gbp_endpoint(self,
2365                                                tep1_sw_if_index,
2366                                                ip=l['ip']))
2367
2368         #
2369         # learn some remote IPv6 EPs
2370         #
2371         for ii, l in enumerate(learnt):
2372             # a packet with an sclass from a known EPG
2373             # arriving on an unknown TEP
2374             p = (Ether(src=self.pg2.remote_mac,
2375                        dst=self.pg2.local_mac) /
2376                  IP(src=self.pg2.remote_hosts[1].ip4,
2377                     dst=self.pg2.local_ip4) /
2378                  UDP(sport=1234, dport=48879) /
2379                  VXLAN(vni=101, gpid=441, flags=0x88) /
2380                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
2381                  IPv6(src=l['ip6'], dst=ep.ip6.address) /
2382                  UDP(sport=1234, dport=1234) /
2383                  Raw('\xa5' * 100))
2384
2385             rx = self.send_and_expect(self.pg2, [p], self.pg0)
2386
2387             # the new TEP
2388             tep1_sw_if_index = find_vxlan_gbp_tunnel(
2389                 self,
2390                 self.pg2.local_ip4,
2391                 self.pg2.remote_hosts[1].ip4,
2392                 vx_tun_l3.vni)
2393             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
2394
2395             self.logger.info(self.vapi.cli("show gbp bridge"))
2396             self.logger.info(self.vapi.cli("show vxlan-gbp tunnel"))
2397             self.logger.info(self.vapi.cli("show gbp vxlan"))
2398             self.logger.info(self.vapi.cli("show int addr"))
2399
2400             # endpoint learnt via the TEP
2401             self.assertTrue(find_gbp_endpoint(self, ip=l['ip6']))
2402
2403         self.logger.info(self.vapi.cli("show gbp endpoint"))
2404         self.logger.info(self.vapi.cli("show ip fib index 1 %s" % l['ip']))
2405
2406         #
2407         # Static EP replies to learnt
2408         #
2409         for l in learnt:
2410             p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2411                  IPv6(dst=l['ip6'], src=ep.ip6.address) /
2412                  UDP(sport=1234, dport=1234) /
2413                  Raw('\xa5' * 100))
2414
2415             rxs = self.send_and_expect(self.pg0, p*65, self.pg2)
2416
2417             for rx in rxs:
2418                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2419                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
2420                 self.assertEqual(rx[UDP].dport, 48879)
2421                 # the UDP source port is a random value for hashing
2422                 self.assertEqual(rx[VXLAN].gpid, 441)
2423                 self.assertEqual(rx[VXLAN].vni, 101)
2424                 self.assertTrue(rx[VXLAN].flags.G)
2425                 self.assertTrue(rx[VXLAN].flags.Instance)
2426                 self.assertTrue(rx[VXLAN].gpflags.A)
2427                 self.assertFalse(rx[VXLAN].gpflags.D)
2428
2429                 inner = rx[VXLAN].payload
2430
2431                 self.assertEqual(inner[Ether].src, routed_src_mac)
2432                 self.assertEqual(inner[Ether].dst, routed_dst_mac)
2433                 self.assertEqual(inner[IPv6].src, ep.ip6.address)
2434                 self.assertEqual(inner[IPv6].dst, l['ip6'])
2435
2436         self.logger.info(self.vapi.cli("sh gbp endpoint"))
2437         for l in learnt:
2438             self.wait_for_ep_timeout(ip=l['ip'])
2439
2440         #
2441         # Static sends to unknown EP with no route
2442         #
2443         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2444              IP(dst="10.0.0.99", src=ep.ip4.address) /
2445              UDP(sport=1234, dport=1234) /
2446              Raw('\xa5' * 100))
2447
2448         self.send_and_assert_no_replies(self.pg0, [p])
2449
2450         #
2451         # Add a route to static EP's v4 and v6 subnet
2452         #  packets should be sent on the v4/v6 uu=fwd interface resp.
2453         #
2454         se_10_24 = VppGbpSubnet(
2455             self, rd1, "10.0.0.0", 24,
2456             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_TRANSPORT)
2457         se_10_24.add_vpp_config()
2458
2459         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2460              IP(dst="10.0.0.99", src=ep.ip4.address) /
2461              UDP(sport=1234, dport=1234) /
2462              Raw('\xa5' * 100))
2463
2464         rxs = self.send_and_expect(self.pg0, [p], self.pg4)
2465         for rx in rxs:
2466             self.assertEqual(rx[IP].src, self.pg4.local_ip4)
2467             self.assertEqual(rx[IP].dst, self.pg4.remote_ip4)
2468             self.assertEqual(rx[UDP].dport, 48879)
2469             # the UDP source port is a random value for hashing
2470             self.assertEqual(rx[VXLAN].gpid, 441)
2471             self.assertEqual(rx[VXLAN].vni, 114)
2472             self.assertTrue(rx[VXLAN].flags.G)
2473             self.assertTrue(rx[VXLAN].flags.Instance)
2474             # policy is not applied to packets sent to the uu-fwd interfaces
2475             self.assertFalse(rx[VXLAN].gpflags.A)
2476             self.assertFalse(rx[VXLAN].gpflags.D)
2477
2478         #
2479         # learn some remote IPv4 EPs
2480         #
2481         for ii, l in enumerate(learnt):
2482             # a packet with an sclass from a known EPG
2483             # arriving on an unknown TEP
2484             p = (Ether(src=self.pg2.remote_mac,
2485                        dst=self.pg2.local_mac) /
2486                  IP(src=self.pg2.remote_hosts[2].ip4,
2487                     dst=self.pg2.local_ip4) /
2488                  UDP(sport=1234, dport=48879) /
2489                  VXLAN(vni=101, gpid=441, flags=0x88) /
2490                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
2491                  IP(src=l['ip'], dst=ep.ip4.address) /
2492                  UDP(sport=1234, dport=1234) /
2493                  Raw('\xa5' * 100))
2494
2495             rx = self.send_and_expect(self.pg2, [p], self.pg0)
2496
2497             # the new TEP
2498             tep1_sw_if_index = find_vxlan_gbp_tunnel(
2499                 self,
2500                 self.pg2.local_ip4,
2501                 self.pg2.remote_hosts[2].ip4,
2502                 vx_tun_l3.vni)
2503             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
2504
2505             # endpoint learnt via the parent GBP-vxlan interface
2506             self.assertTrue(find_gbp_endpoint(self,
2507                                               vx_tun_l3._sw_if_index,
2508                                               ip=l['ip']))
2509
2510         #
2511         # Add a remote endpoint from the API
2512         #
2513         rep_88 = VppGbpEndpoint(self, vx_tun_l3,
2514                                 epg_220, None,
2515                                 "10.0.0.88", "11.0.0.88",
2516                                 "2001:10::88", "3001::88",
2517                                 ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
2518                                 self.pg2.local_ip4,
2519                                 self.pg2.remote_hosts[1].ip4,
2520                                 mac=None)
2521         rep_88.add_vpp_config()
2522
2523         #
2524         # Add a remote endpoint from the API that matches an existing one
2525         #
2526         rep_2 = VppGbpEndpoint(self, vx_tun_l3,
2527                                epg_220, None,
2528                                learnt[0]['ip'], "11.0.0.101",
2529                                learnt[0]['ip6'], "3001::101",
2530                                ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
2531                                self.pg2.local_ip4,
2532                                self.pg2.remote_hosts[1].ip4,
2533                                mac=None)
2534         rep_2.add_vpp_config()
2535
2536         #
2537         # Add a route to the learned EP's v4 subnet
2538         #  packets should be send on the v4/v6 uu=fwd interface resp.
2539         #
2540         se_10_1_24 = VppGbpSubnet(
2541             self, rd1, "10.0.1.0", 24,
2542             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_TRANSPORT)
2543         se_10_1_24.add_vpp_config()
2544
2545         self.logger.info(self.vapi.cli("show gbp endpoint"))
2546
2547         ips = ["10.0.0.88", learnt[0]['ip']]
2548         for ip in ips:
2549             p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2550                  IP(dst=ip, src=ep.ip4.address) /
2551                  UDP(sport=1234, dport=1234) /
2552                  Raw('\xa5' * 100))
2553
2554             rxs = self.send_and_expect(self.pg0, p*65, self.pg2)
2555
2556             for rx in rxs:
2557                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2558                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
2559                 self.assertEqual(rx[UDP].dport, 48879)
2560                 # the UDP source port is a random value for hashing
2561                 self.assertEqual(rx[VXLAN].gpid, 441)
2562                 self.assertEqual(rx[VXLAN].vni, 101)
2563                 self.assertTrue(rx[VXLAN].flags.G)
2564                 self.assertTrue(rx[VXLAN].flags.Instance)
2565                 self.assertTrue(rx[VXLAN].gpflags.A)
2566                 self.assertFalse(rx[VXLAN].gpflags.D)
2567
2568                 inner = rx[VXLAN].payload
2569
2570                 self.assertEqual(inner[Ether].src, routed_src_mac)
2571                 self.assertEqual(inner[Ether].dst, routed_dst_mac)
2572                 self.assertEqual(inner[IP].src, ep.ip4.address)
2573                 self.assertEqual(inner[IP].dst, ip)
2574
2575         #
2576         # remove the API remote EPs, only API sourced is gone, the DP
2577         # learnt one remains
2578         #
2579         rep_88.remove_vpp_config()
2580         rep_2.remove_vpp_config()
2581
2582         self.assertTrue(find_gbp_endpoint(self, ip=rep_2.ip4.address))
2583
2584         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2585              IP(src=ep.ip4.address, dst=rep_2.ip4.address) /
2586              UDP(sport=1234, dport=1234) /
2587              Raw('\xa5' * 100))
2588         rxs = self.send_and_expect(self.pg0, [p], self.pg2)
2589
2590         self.assertFalse(find_gbp_endpoint(self, ip=rep_88.ip4.address))
2591
2592         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2593              IP(src=ep.ip4.address, dst=rep_88.ip4.address) /
2594              UDP(sport=1234, dport=1234) /
2595              Raw('\xa5' * 100))
2596         rxs = self.send_and_expect(self.pg0, [p], self.pg4)
2597
2598         #
2599         # to appease the testcase we cannot have the registered EP still
2600         # present (because it's DP learnt) when the TC ends so wait until
2601         # it is removed
2602         #
2603         self.wait_for_ep_timeout(ip=rep_88.ip4.address)
2604         self.wait_for_ep_timeout(ip=rep_2.ip4.address)
2605
2606         #
2607         # shutdown with learnt endpoint present
2608         #
2609         p = (Ether(src=self.pg2.remote_mac,
2610                    dst=self.pg2.local_mac) /
2611              IP(src=self.pg2.remote_hosts[1].ip4,
2612                 dst=self.pg2.local_ip4) /
2613              UDP(sport=1234, dport=48879) /
2614              VXLAN(vni=101, gpid=441, flags=0x88) /
2615              Ether(src=l['mac'], dst="00:00:00:11:11:11") /
2616              IP(src=learnt[1]['ip'], dst=ep.ip4.address) /
2617              UDP(sport=1234, dport=1234) /
2618              Raw('\xa5' * 100))
2619
2620         rx = self.send_and_expect(self.pg2, [p], self.pg0)
2621
2622         # endpoint learnt via the parent GBP-vxlan interface
2623         self.assertTrue(find_gbp_endpoint(self,
2624                                           vx_tun_l3._sw_if_index,
2625                                           ip=l['ip']))
2626
2627         #
2628         # TODO
2629         # remote endpoint becomes local
2630         #
2631         self.pg2.unconfig_ip4()
2632         self.pg3.unconfig_ip4()
2633         self.pg4.unconfig_ip4()
2634
2635     def test_gbp_redirect(self):
2636         """ GBP Endpoint Redirect """
2637
2638         self.vapi.cli("set logging class gbp debug")
2639
2640         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
2641         routed_dst_mac = "00:0c:0c:0c:0c:0c"
2642         routed_src_mac = "00:22:bd:f8:19:ff"
2643
2644         learnt = [{'mac': '00:00:11:11:11:02',
2645                    'ip': '10.0.1.2',
2646                    'ip6': '2001:10::2'},
2647                   {'mac': '00:00:11:11:11:03',
2648                    'ip': '10.0.1.3',
2649                    'ip6': '2001:10::3'}]
2650
2651         #
2652         # IP tables
2653         #
2654         t4 = VppIpTable(self, 1)
2655         t4.add_vpp_config()
2656         t6 = VppIpTable(self, 1, True)
2657         t6.add_vpp_config()
2658
2659         rd1 = VppGbpRouteDomain(self, 2, t4, t6)
2660         rd1.add_vpp_config()
2661
2662         self.loop0.set_mac(self.router_mac)
2663
2664         #
2665         # Bind the BVI to the RD
2666         #
2667         VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
2668         VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
2669
2670         #
2671         # Pg7 hosts a BD's UU-fwd
2672         #
2673         self.pg7.config_ip4()
2674         self.pg7.resolve_arp()
2675
2676         #
2677         # a GBP bridge domains for the EPs
2678         #
2679         bd1 = VppBridgeDomain(self, 1)
2680         bd1.add_vpp_config()
2681         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0)
2682         gbd1.add_vpp_config()
2683
2684         bd2 = VppBridgeDomain(self, 2)
2685         bd2.add_vpp_config()
2686         gbd2 = VppGbpBridgeDomain(self, bd2, self.loop1)
2687         gbd2.add_vpp_config()
2688
2689         # ... and has a /32 and /128 applied
2690         ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
2691         ip4_addr.add_vpp_config()
2692         ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128", 128)
2693         ip6_addr.add_vpp_config()
2694         ip4_addr = VppIpInterfaceAddress(self, gbd2.bvi, "10.0.1.128", 32)
2695         ip4_addr.add_vpp_config()
2696         ip6_addr = VppIpInterfaceAddress(self, gbd2.bvi, "2001:11::128", 128)
2697         ip6_addr.add_vpp_config()
2698
2699         #
2700         # The Endpoint-groups in which we are learning endpoints
2701         #
2702         epg_220 = VppGbpEndpointGroup(self, 220, 440, rd1, gbd1,
2703                                       None, gbd1.bvi,
2704                                       "10.0.0.128",
2705                                       "2001:10::128",
2706                                       VppGbpEndpointRetention(2))
2707         epg_220.add_vpp_config()
2708         epg_221 = VppGbpEndpointGroup(self, 221, 441, rd1, gbd2,
2709                                       None, gbd2.bvi,
2710                                       "10.0.1.128",
2711                                       "2001:11::128",
2712                                       VppGbpEndpointRetention(2))
2713         epg_221.add_vpp_config()
2714         epg_222 = VppGbpEndpointGroup(self, 222, 442, rd1, gbd1,
2715                                       None, gbd1.bvi,
2716                                       "10.0.2.128",
2717                                       "2001:12::128",
2718                                       VppGbpEndpointRetention(2))
2719         epg_222.add_vpp_config()
2720
2721         #
2722         # a GBP bridge domains for the SEPs
2723         #
2724         bd_uu1 = VppVxlanGbpTunnel(self, self.pg7.local_ip4,
2725                                    self.pg7.remote_ip4, 116)
2726         bd_uu1.add_vpp_config()
2727         bd_uu2 = VppVxlanGbpTunnel(self, self.pg7.local_ip4,
2728                                    self.pg7.remote_ip4, 117)
2729         bd_uu2.add_vpp_config()
2730
2731         bd3 = VppBridgeDomain(self, 3)
2732         bd3.add_vpp_config()
2733         gbd3 = VppGbpBridgeDomain(self, bd3, self.loop2, bd_uu1, learn=False)
2734         gbd3.add_vpp_config()
2735         bd4 = VppBridgeDomain(self, 4)
2736         bd4.add_vpp_config()
2737         gbd4 = VppGbpBridgeDomain(self, bd4, self.loop3, bd_uu2, learn=False)
2738         gbd4.add_vpp_config()
2739
2740         #
2741         # EPGs in which the service endpoints exist
2742         #
2743         epg_320 = VppGbpEndpointGroup(self, 320, 550, rd1, gbd3,
2744                                       None, gbd1.bvi,
2745                                       "12.0.0.128",
2746                                       "4001:10::128",
2747                                       VppGbpEndpointRetention(2))
2748         epg_320.add_vpp_config()
2749         epg_321 = VppGbpEndpointGroup(self, 321, 551, rd1, gbd4,
2750                                       None, gbd2.bvi,
2751                                       "12.0.1.128",
2752                                       "4001:11::128",
2753                                       VppGbpEndpointRetention(2))
2754         epg_321.add_vpp_config()
2755
2756         #
2757         # three local endpoints
2758         #
2759         ep1 = VppGbpEndpoint(self, self.pg0,
2760                              epg_220, None,
2761                              "10.0.0.1", "11.0.0.1",
2762                              "2001:10::1", "3001:10::1")
2763         ep1.add_vpp_config()
2764         ep2 = VppGbpEndpoint(self, self.pg1,
2765                              epg_221, None,
2766                              "10.0.1.1", "11.0.1.1",
2767                              "2001:11::1", "3001:11::1")
2768         ep2.add_vpp_config()
2769         ep3 = VppGbpEndpoint(self, self.pg2,
2770                              epg_222, None,
2771                              "10.0.2.2", "11.0.2.2",
2772                              "2001:12::1", "3001:12::1")
2773         ep3.add_vpp_config()
2774
2775         #
2776         # service endpoints
2777         #
2778         sep1 = VppGbpEndpoint(self, self.pg3,
2779                               epg_320, None,
2780                               "12.0.0.1", "13.0.0.1",
2781                               "4001:10::1", "5001:10::1")
2782         sep1.add_vpp_config()
2783         sep2 = VppGbpEndpoint(self, self.pg4,
2784                               epg_320, None,
2785                               "12.0.0.2", "13.0.0.2",
2786                               "4001:10::2", "5001:10::2")
2787         sep2.add_vpp_config()
2788         sep3 = VppGbpEndpoint(self, self.pg5,
2789                               epg_321, None,
2790                               "12.0.1.1", "13.0.1.1",
2791                               "4001:11::1", "5001:11::1")
2792         sep3.add_vpp_config()
2793         # this EP is not installed immediately
2794         sep4 = VppGbpEndpoint(self, self.pg6,
2795                               epg_321, None,
2796                               "12.0.1.2", "13.0.1.2",
2797                               "4001:11::2", "5001:11::2")
2798
2799         #
2800         # an L2 switch packet between local EPs in different EPGs
2801         #  different dest ports on each so the are LB hashed differently
2802         #
2803         p4 = [(Ether(src=ep1.mac, dst=ep3.mac) /
2804                IP(src=ep1.ip4.address, dst=ep3.ip4.address) /
2805                UDP(sport=1234, dport=1234) /
2806                Raw('\xa5' * 100)),
2807               (Ether(src=ep3.mac, dst=ep1.mac) /
2808                IP(src=ep3.ip4.address, dst=ep1.ip4.address) /
2809                UDP(sport=1234, dport=1234) /
2810                Raw('\xa5' * 100))]
2811         p6 = [(Ether(src=ep1.mac, dst=ep3.mac) /
2812                IPv6(src=ep1.ip6.address, dst=ep3.ip6.address) /
2813                UDP(sport=1234, dport=1234) /
2814                Raw('\xa5' * 100)),
2815               (Ether(src=ep3.mac, dst=ep1.mac) /
2816                IPv6(src=ep3.ip6.address, dst=ep1.ip6.address) /
2817                UDP(sport=1234, dport=1230) /
2818                Raw('\xa5' * 100))]
2819
2820         # should be dropped since no contract yet
2821         self.send_and_assert_no_replies(self.pg0, [p4[0]])
2822         self.send_and_assert_no_replies(self.pg0, [p6[0]])
2823
2824         #
2825         # Add a contract with a rule to load-balance redirect via SEP1 and SEP2
2826         # one of the next-hops is via an EP that is not known
2827         #
2828         acl = VppGbpAcl(self)
2829         rule4 = acl.create_rule(permit_deny=1, proto=17)
2830         rule6 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
2831         acl_index = acl.add_vpp_config([rule4, rule6])
2832
2833         #
2834         # test the src-ip hash mode
2835         #
2836         c1 = VppGbpContract(
2837             self, epg_220.sclass, epg_222.sclass, acl_index,
2838             [VppGbpContractRule(
2839                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
2840                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2841                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
2842                                        sep1.ip4, sep1.epg.rd),
2843                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
2844                                        sep2.ip4, sep2.epg.rd)]),
2845              VppGbpContractRule(
2846                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
2847                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2848                  [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
2849                                         sep3.ip6, sep3.epg.rd),
2850                   VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
2851                                         sep4.ip6, sep4.epg.rd)])],
2852             [ETH_P_IP, ETH_P_IPV6])
2853         c1.add_vpp_config()
2854
2855         c2 = VppGbpContract(
2856             self, epg_222.sclass, epg_220.sclass, acl_index,
2857             [VppGbpContractRule(
2858                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
2859                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2860                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
2861                                        sep1.ip4, sep1.epg.rd),
2862                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
2863                                        sep2.ip4, sep2.epg.rd)]),
2864              VppGbpContractRule(
2865                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
2866                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2867                  [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
2868                                         sep3.ip6, sep3.epg.rd),
2869                   VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
2870                                         sep4.ip6, sep4.epg.rd)])],
2871             [ETH_P_IP, ETH_P_IPV6])
2872         c2.add_vpp_config()
2873
2874         #
2875         # send again with the contract preset, now packets arrive
2876         # at SEP1 or SEP2 depending on the hashing
2877         #
2878         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
2879
2880         for rx in rxs:
2881             self.assertEqual(rx[Ether].src, routed_src_mac)
2882             self.assertEqual(rx[Ether].dst, sep1.mac)
2883             self.assertEqual(rx[IP].src, ep1.ip4.address)
2884             self.assertEqual(rx[IP].dst, ep3.ip4.address)
2885
2886         rxs = self.send_and_expect(self.pg2, p4[1] * 17, sep2.itf)
2887
2888         for rx in rxs:
2889             self.assertEqual(rx[Ether].src, routed_src_mac)
2890             self.assertEqual(rx[Ether].dst, sep2.mac)
2891             self.assertEqual(rx[IP].src, ep3.ip4.address)
2892             self.assertEqual(rx[IP].dst, ep1.ip4.address)
2893
2894         rxs = self.send_and_expect(self.pg0, p6[0] * 17, self.pg7)
2895
2896         for rx in rxs:
2897             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
2898             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
2899             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
2900             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
2901             self.assertEqual(rx[VXLAN].vni, 117)
2902             self.assertTrue(rx[VXLAN].flags.G)
2903             self.assertTrue(rx[VXLAN].flags.Instance)
2904             # redirect policy has been applied
2905             self.assertTrue(rx[VXLAN].gpflags.A)
2906             self.assertFalse(rx[VXLAN].gpflags.D)
2907
2908             inner = rx[VXLAN].payload
2909
2910             self.assertEqual(inner[Ether].src, routed_src_mac)
2911             self.assertEqual(inner[Ether].dst, sep4.mac)
2912             self.assertEqual(inner[IPv6].src, ep1.ip6.address)
2913             self.assertEqual(inner[IPv6].dst, ep3.ip6.address)
2914
2915         rxs = self.send_and_expect(self.pg2, p6[1] * 17, sep3.itf)
2916
2917         for rx in rxs:
2918             self.assertEqual(rx[Ether].src, routed_src_mac)
2919             self.assertEqual(rx[Ether].dst, sep3.mac)
2920             self.assertEqual(rx[IPv6].src, ep3.ip6.address)
2921             self.assertEqual(rx[IPv6].dst, ep1.ip6.address)
2922
2923         #
2924         # programme the unknown EP
2925         #
2926         sep4.add_vpp_config()
2927
2928         rxs = self.send_and_expect(self.pg0, p6[0] * 17, sep4.itf)
2929
2930         for rx in rxs:
2931             self.assertEqual(rx[Ether].src, routed_src_mac)
2932             self.assertEqual(rx[Ether].dst, sep4.mac)
2933             self.assertEqual(rx[IPv6].src, ep1.ip6.address)
2934             self.assertEqual(rx[IPv6].dst, ep3.ip6.address)
2935
2936         #
2937         # and revert back to unprogrammed
2938         #
2939         sep4.remove_vpp_config()
2940
2941         rxs = self.send_and_expect(self.pg0, p6[0] * 17, self.pg7)
2942
2943         for rx in rxs:
2944             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
2945             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
2946             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
2947             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
2948             self.assertEqual(rx[VXLAN].vni, 117)
2949             self.assertTrue(rx[VXLAN].flags.G)
2950             self.assertTrue(rx[VXLAN].flags.Instance)
2951             # redirect policy has been applied
2952             self.assertTrue(rx[VXLAN].gpflags.A)
2953             self.assertFalse(rx[VXLAN].gpflags.D)
2954
2955             inner = rx[VXLAN].payload
2956
2957             self.assertEqual(inner[Ether].src, routed_src_mac)
2958             self.assertEqual(inner[Ether].dst, sep4.mac)
2959             self.assertEqual(inner[IPv6].src, ep1.ip6.address)
2960             self.assertEqual(inner[IPv6].dst, ep3.ip6.address)
2961
2962         c1.remove_vpp_config()
2963         c2.remove_vpp_config()
2964
2965         #
2966         # test the symmetric hash mode
2967         #
2968         c1 = VppGbpContract(
2969             self, epg_220.sclass, epg_222.sclass, acl_index,
2970             [VppGbpContractRule(
2971                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
2972                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
2973                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
2974                                        sep1.ip4, sep1.epg.rd),
2975                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
2976                                        sep2.ip4, sep2.epg.rd)]),
2977              VppGbpContractRule(
2978                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
2979                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
2980                  [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
2981                                         sep3.ip6, sep3.epg.rd),
2982                   VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
2983                                         sep4.ip6, sep4.epg.rd)])],
2984             [ETH_P_IP, ETH_P_IPV6])
2985         c1.add_vpp_config()
2986
2987         c2 = VppGbpContract(
2988             self, epg_222.sclass, epg_220.sclass, acl_index,
2989             [VppGbpContractRule(
2990                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
2991                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
2992                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
2993                                        sep1.ip4, sep1.epg.rd),
2994                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
2995                                        sep2.ip4, sep2.epg.rd)]),
2996              VppGbpContractRule(
2997                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
2998                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
2999                  [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3000                                         sep3.ip6, sep3.epg.rd),
3001                   VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3002                                         sep4.ip6, sep4.epg.rd)])],
3003             [ETH_P_IP, ETH_P_IPV6])
3004         c2.add_vpp_config()
3005
3006         #
3007         # send again with the contract preset, now packets arrive
3008         # at SEP1 for both directions
3009         #
3010         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
3011
3012         for rx in rxs:
3013             self.assertEqual(rx[Ether].src, routed_src_mac)
3014             self.assertEqual(rx[Ether].dst, sep1.mac)
3015             self.assertEqual(rx[IP].src, ep1.ip4.address)
3016             self.assertEqual(rx[IP].dst, ep3.ip4.address)
3017
3018         rxs = self.send_and_expect(self.pg2, p4[1] * 17, sep1.itf)
3019
3020         for rx in rxs:
3021             self.assertEqual(rx[Ether].src, routed_src_mac)
3022             self.assertEqual(rx[Ether].dst, sep1.mac)
3023             self.assertEqual(rx[IP].src, ep3.ip4.address)
3024             self.assertEqual(rx[IP].dst, ep1.ip4.address)
3025
3026         #
3027         # programme the unknown EP for the L3 tests
3028         #
3029         sep4.add_vpp_config()
3030
3031         #
3032         # an L3 switch packet between local EPs in different EPGs
3033         #  different dest ports on each so the are LB hashed differently
3034         #
3035         p4 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) /
3036                IP(src=ep1.ip4.address, dst=ep2.ip4.address) /
3037                UDP(sport=1234, dport=1234) /
3038                Raw('\xa5' * 100)),
3039               (Ether(src=ep2.mac, dst=str(self.router_mac)) /
3040                IP(src=ep2.ip4.address, dst=ep1.ip4.address) /
3041                UDP(sport=1234, dport=1234) /
3042                Raw('\xa5' * 100))]
3043         p6 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) /
3044                IPv6(src=ep1.ip6.address, dst=ep2.ip6.address) /
3045                UDP(sport=1234, dport=1234) /
3046                Raw('\xa5' * 100)),
3047               (Ether(src=ep2.mac, dst=str(self.router_mac)) /
3048                IPv6(src=ep2.ip6.address, dst=ep1.ip6.address) /
3049                UDP(sport=1234, dport=1234) /
3050                Raw('\xa5' * 100))]
3051
3052         c3 = VppGbpContract(
3053             self, epg_220.sclass, epg_221.sclass, acl_index,
3054             [VppGbpContractRule(
3055                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3056                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3057                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3058                                        sep1.ip4, sep1.epg.rd),
3059                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3060                                        sep2.ip4, sep2.epg.rd)]),
3061              VppGbpContractRule(
3062                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3063                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3064                  [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3065                                         sep3.ip6, sep3.epg.rd),
3066                   VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3067                                         sep4.ip6, sep4.epg.rd)])],
3068             [ETH_P_IP, ETH_P_IPV6])
3069         c3.add_vpp_config()
3070
3071         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
3072
3073         for rx in rxs:
3074             self.assertEqual(rx[Ether].src, routed_src_mac)
3075             self.assertEqual(rx[Ether].dst, sep1.mac)
3076             self.assertEqual(rx[IP].src, ep1.ip4.address)
3077             self.assertEqual(rx[IP].dst, ep2.ip4.address)
3078
3079         #
3080         # learn a remote EP in EPG 221
3081         #
3082         vx_tun_l3 = VppGbpVxlanTunnel(
3083             self, 444, rd1.rd_id,
3084             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3,
3085             self.pg2.local_ip4)
3086         vx_tun_l3.add_vpp_config()
3087
3088         c4 = VppGbpContract(
3089             self, epg_221.sclass, epg_220.sclass, acl_index,
3090             [VppGbpContractRule(
3091                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3092                 []),
3093              VppGbpContractRule(
3094                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3095                  [])],
3096             [ETH_P_IP, ETH_P_IPV6])
3097         c4.add_vpp_config()
3098
3099         p = (Ether(src=self.pg7.remote_mac,
3100                    dst=self.pg7.local_mac) /
3101              IP(src=self.pg7.remote_ip4,
3102                 dst=self.pg7.local_ip4) /
3103              UDP(sport=1234, dport=48879) /
3104              VXLAN(vni=444, gpid=441, flags=0x88) /
3105              Ether(src="00:22:22:22:22:33", dst=str(self.router_mac)) /
3106              IP(src="10.0.0.88", dst=ep1.ip4.address) /
3107              UDP(sport=1234, dport=1234) /
3108              Raw('\xa5' * 100))
3109
3110         rx = self.send_and_expect(self.pg7, [p], self.pg0)
3111
3112         # endpoint learnt via the parent GBP-vxlan interface
3113         self.assertTrue(find_gbp_endpoint(self,
3114                                           vx_tun_l3._sw_if_index,
3115                                           ip="10.0.0.88"))
3116
3117         p = (Ether(src=self.pg7.remote_mac,
3118                    dst=self.pg7.local_mac) /
3119              IP(src=self.pg7.remote_ip4,
3120                 dst=self.pg7.local_ip4) /
3121              UDP(sport=1234, dport=48879) /
3122              VXLAN(vni=444, gpid=441, flags=0x88) /
3123              Ether(src="00:22:22:22:22:33", dst=str(self.router_mac)) /
3124              IPv6(src="2001:10::88", dst=ep1.ip6.address) /
3125              UDP(sport=1234, dport=1234) /
3126              Raw('\xa5' * 100))
3127
3128         rx = self.send_and_expect(self.pg7, [p], self.pg0)
3129
3130         # endpoint learnt via the parent GBP-vxlan interface
3131         self.assertTrue(find_gbp_endpoint(self,
3132                                           vx_tun_l3._sw_if_index,
3133                                           ip="2001:10::88"))
3134
3135         #
3136         # L3 switch from local to remote EP
3137         #
3138         p4 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) /
3139                IP(src=ep1.ip4.address, dst="10.0.0.88") /
3140                UDP(sport=1234, dport=1234) /
3141                Raw('\xa5' * 100))]
3142         p6 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) /
3143                IPv6(src=ep1.ip6.address, dst="2001:10::88") /
3144                UDP(sport=1234, dport=1234) /
3145                Raw('\xa5' * 100))]
3146
3147         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
3148
3149         for rx in rxs:
3150             self.assertEqual(rx[Ether].src, routed_src_mac)
3151             self.assertEqual(rx[Ether].dst, sep1.mac)
3152             self.assertEqual(rx[IP].src, ep1.ip4.address)
3153             self.assertEqual(rx[IP].dst, "10.0.0.88")
3154
3155         rxs = self.send_and_expect(self.pg0, p6[0] * 17, sep4.itf)
3156
3157         for rx in rxs:
3158             self.assertEqual(rx[Ether].src, routed_src_mac)
3159             self.assertEqual(rx[Ether].dst, sep4.mac)
3160             self.assertEqual(rx[IPv6].src, ep1.ip6.address)
3161             self.assertEqual(rx[IPv6].dst, "2001:10::88")
3162
3163         #
3164         # test the dst-ip hash mode
3165         #
3166         c5 = VppGbpContract(
3167             self, epg_220.sclass, epg_221.sclass, acl_index,
3168             [VppGbpContractRule(
3169                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3170                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
3171                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3172                                        sep1.ip4, sep1.epg.rd),
3173                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3174                                        sep2.ip4, sep2.epg.rd)]),
3175              VppGbpContractRule(
3176                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3177                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
3178                  [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3179                                         sep3.ip6, sep3.epg.rd),
3180                   VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3181                                         sep4.ip6, sep4.epg.rd)])],
3182             [ETH_P_IP, ETH_P_IPV6])
3183         c5.add_vpp_config()
3184
3185         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
3186
3187         for rx in rxs:
3188             self.assertEqual(rx[Ether].src, routed_src_mac)
3189             self.assertEqual(rx[Ether].dst, sep1.mac)
3190             self.assertEqual(rx[IP].src, ep1.ip4.address)
3191             self.assertEqual(rx[IP].dst, "10.0.0.88")
3192
3193         rxs = self.send_and_expect(self.pg0, p6[0] * 17, sep3.itf)
3194
3195         for rx in rxs:
3196             self.assertEqual(rx[Ether].src, routed_src_mac)
3197             self.assertEqual(rx[Ether].dst, sep3.mac)
3198             self.assertEqual(rx[IPv6].src, ep1.ip6.address)
3199             self.assertEqual(rx[IPv6].dst, "2001:10::88")
3200
3201         #
3202         # cleanup
3203         #
3204         self.pg7.unconfig_ip4()
3205
3206     def test_gbp_l3_out(self):
3207         """ GBP L3 Out """
3208
3209         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
3210         self.vapi.cli("set logging class gbp debug")
3211
3212         routed_dst_mac = "00:0c:0c:0c:0c:0c"
3213         routed_src_mac = "00:22:bd:f8:19:ff"
3214
3215         #
3216         # IP tables
3217         #
3218         t4 = VppIpTable(self, 1)
3219         t4.add_vpp_config()
3220         t6 = VppIpTable(self, 1, True)
3221         t6.add_vpp_config()
3222
3223         rd1 = VppGbpRouteDomain(self, 2, t4, t6)
3224         rd1.add_vpp_config()
3225
3226         self.loop0.set_mac(self.router_mac)
3227
3228         #
3229         # Bind the BVI to the RD
3230         #
3231         VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
3232         VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
3233
3234         #
3235         # Pg7 hosts a BD's BUM
3236         # Pg1 some other l3 interface
3237         #
3238         self.pg7.config_ip4()
3239         self.pg7.resolve_arp()
3240
3241         #
3242         # a multicast vxlan-gbp tunnel for broadcast in the BD
3243         #
3244         tun_bm = VppVxlanGbpTunnel(self, self.pg7.local_ip4,
3245                                    "239.1.1.1", 88,
3246                                    mcast_itf=self.pg7)
3247         tun_bm.add_vpp_config()
3248
3249         #
3250         # a GBP external bridge domains for the EPs
3251         #
3252         bd1 = VppBridgeDomain(self, 1)
3253         bd1.add_vpp_config()
3254         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0, None, tun_bm)
3255         gbd1.add_vpp_config()
3256
3257         #
3258         # The Endpoint-groups in which the external endpoints exist
3259         #
3260         epg_220 = VppGbpEndpointGroup(self, 220, 113, rd1, gbd1,
3261                                       None, gbd1.bvi,
3262                                       "10.0.0.128",
3263                                       "2001:10::128",
3264                                       VppGbpEndpointRetention(2))
3265         epg_220.add_vpp_config()
3266
3267         # the BVIs have the subnets applied ...
3268         ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 24)
3269         ip4_addr.add_vpp_config()
3270         ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128", 64)
3271         ip6_addr.add_vpp_config()
3272
3273         # ... which are L3-out subnets
3274         l3o_1 = VppGbpSubnet(
3275             self, rd1, "10.0.0.0", 24,
3276             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3277             sclass=113)
3278         l3o_1.add_vpp_config()
3279
3280         #
3281         # an external interface attached to the outside world and the
3282         # external BD
3283         #
3284         vlan_100 = VppDot1QSubint(self, self.pg0, 100)
3285         vlan_100.admin_up()
3286         VppL2Vtr(self, vlan_100, L2_VTR_OP.L2_POP_1).add_vpp_config()
3287         vlan_101 = VppDot1QSubint(self, self.pg0, 101)
3288         vlan_101.admin_up()
3289         VppL2Vtr(self, vlan_101, L2_VTR_OP.L2_POP_1).add_vpp_config()
3290
3291         ext_itf = VppGbpExtItf(self, self.loop0, bd1, rd1)
3292         ext_itf.add_vpp_config()
3293
3294         #
3295         # an unicast vxlan-gbp for inter-RD traffic
3296         #
3297         vx_tun_l3 = VppGbpVxlanTunnel(
3298             self, 444, rd1.rd_id,
3299             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3,
3300             self.pg2.local_ip4)
3301         vx_tun_l3.add_vpp_config()
3302
3303         #
3304         # External Endpoints
3305         #
3306         eep1 = VppGbpEndpoint(self, vlan_100,
3307                               epg_220, None,
3308                               "10.0.0.1", "11.0.0.1",
3309                               "2001:10::1", "3001::1",
3310                               ep_flags.GBP_API_ENDPOINT_FLAG_EXTERNAL)
3311         eep1.add_vpp_config()
3312         eep2 = VppGbpEndpoint(self, vlan_101,
3313                               epg_220, None,
3314                               "10.0.0.2", "11.0.0.2",
3315                               "2001:10::2", "3001::2",
3316                               ep_flags.GBP_API_ENDPOINT_FLAG_EXTERNAL)
3317         eep2.add_vpp_config()
3318
3319         #
3320         # A remote external endpoint
3321         #
3322         rep = VppGbpEndpoint(self, vx_tun_l3,
3323                              epg_220, None,
3324                              "10.0.0.101", "11.0.0.101",
3325                              "2001:10::101", "3001::101",
3326                              ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
3327                              self.pg7.local_ip4,
3328                              self.pg7.remote_ip4,
3329                              mac=None)
3330         rep.add_vpp_config()
3331
3332         #
3333         # ARP packet from External EPs are accepted and replied to
3334         #
3335         p_arp = (Ether(src=eep1.mac, dst="ff:ff:ff:ff:ff:ff") /
3336                  Dot1Q(vlan=100) /
3337                  ARP(op="who-has",
3338                      psrc=eep1.ip4.address, pdst="10.0.0.128",
3339                      hwsrc=eep1.mac, hwdst="ff:ff:ff:ff:ff:ff"))
3340         rxs = self.send_and_expect(self.pg0, p_arp * 1, self.pg0)
3341
3342         #
3343         # packets destined to unknown addresses in the BVI's subnet
3344         # are ARP'd for
3345         #
3346         p4 = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
3347               Dot1Q(vlan=100) /
3348               IP(src="10.0.0.1", dst="10.0.0.88") /
3349               UDP(sport=1234, dport=1234) /
3350               Raw('\xa5' * 100))
3351         p6 = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
3352               Dot1Q(vlan=100) /
3353               IPv6(src="2001:10::1", dst="2001:10::88") /
3354               UDP(sport=1234, dport=1234) /
3355               Raw('\xa5' * 100))
3356
3357         rxs = self.send_and_expect(self.pg0, p4 * 1, self.pg7)
3358
3359         for rx in rxs:
3360             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
3361             # self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
3362             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
3363             self.assertEqual(rx[IP].dst, "239.1.1.1")
3364             self.assertEqual(rx[VXLAN].vni, 88)
3365             self.assertTrue(rx[VXLAN].flags.G)
3366             self.assertTrue(rx[VXLAN].flags.Instance)
3367             # policy was applied to the original IP packet
3368             self.assertEqual(rx[VXLAN].gpid, 113)
3369             self.assertTrue(rx[VXLAN].gpflags.A)
3370             self.assertFalse(rx[VXLAN].gpflags.D)
3371
3372             inner = rx[VXLAN].payload
3373
3374             self.assertTrue(inner.haslayer(ARP))
3375
3376         #
3377         # remote to external
3378         #
3379         p = (Ether(src=self.pg7.remote_mac,
3380                    dst=self.pg7.local_mac) /
3381              IP(src=self.pg7.remote_ip4,
3382                 dst=self.pg7.local_ip4) /
3383              UDP(sport=1234, dport=48879) /
3384              VXLAN(vni=444, gpid=113, flags=0x88) /
3385              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
3386              IP(src="10.0.0.101", dst="10.0.0.1") /
3387              UDP(sport=1234, dport=1234) /
3388              Raw('\xa5' * 100))
3389
3390         rxs = self.send_and_expect(self.pg7, p * 1, self.pg0)
3391
3392         #
3393         # local EP pings router
3394         #
3395         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
3396              Dot1Q(vlan=100) /
3397              IP(src=eep1.ip4.address, dst="10.0.0.128") /
3398              ICMP(type='echo-request'))
3399
3400         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
3401
3402         for rx in rxs:
3403             self.assertEqual(rx[Ether].src, str(self.router_mac))
3404             self.assertEqual(rx[Ether].dst, eep1.mac)
3405             self.assertEqual(rx[Dot1Q].vlan, 100)
3406
3407         #
3408         # local EP pings other local EP
3409         #
3410         p = (Ether(src=eep1.mac, dst=eep2.mac) /
3411              Dot1Q(vlan=100) /
3412              IP(src=eep1.ip4.address, dst=eep2.ip4.address) /
3413              ICMP(type='echo-request'))
3414
3415         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
3416
3417         for rx in rxs:
3418             self.assertEqual(rx[Ether].src, eep1.mac)
3419             self.assertEqual(rx[Ether].dst, eep2.mac)
3420             self.assertEqual(rx[Dot1Q].vlan, 101)
3421
3422         #
3423         # A subnet reachable through the external EP1
3424         #
3425         ip_220 = VppIpRoute(self, "10.220.0.0", 24,
3426                             [VppRoutePath(eep1.ip4.address,
3427                                           eep1.epg.bvi.sw_if_index)],
3428                             table_id=t4.table_id)
3429         ip_220.add_vpp_config()
3430
3431         l3o_220 = VppGbpSubnet(
3432             self, rd1, "10.220.0.0", 24,
3433             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3434             sclass=4220)
3435         l3o_220.add_vpp_config()
3436
3437         #
3438         # A subnet reachable through the external EP2
3439         #
3440         ip_221 = VppIpRoute(self, "10.221.0.0", 24,
3441                             [VppRoutePath(eep2.ip4.address,
3442                                           eep2.epg.bvi.sw_if_index)],
3443                             table_id=t4.table_id)
3444         ip_221.add_vpp_config()
3445
3446         l3o_221 = VppGbpSubnet(
3447             self, rd1, "10.221.0.0", 24,
3448             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3449             sclass=4221)
3450         l3o_221.add_vpp_config()
3451
3452         #
3453         # ping between hosts in remote subnets
3454         #  dropped without a contract
3455         #
3456         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
3457              Dot1Q(vlan=100) /
3458              IP(src="10.220.0.1", dst="10.221.0.1") /
3459              ICMP(type='echo-request'))
3460
3461         rxs = self.send_and_assert_no_replies(self.pg0, p * 1)
3462
3463         #
3464         # contract for the external nets to communicate
3465         #
3466         acl = VppGbpAcl(self)
3467         rule4 = acl.create_rule(permit_deny=1, proto=17)
3468         rule6 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
3469         acl_index = acl.add_vpp_config([rule4, rule6])
3470
3471         c1 = VppGbpContract(
3472             self, 4220, 4221, acl_index,
3473             [VppGbpContractRule(
3474                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3475                 []),
3476              VppGbpContractRule(
3477                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3478                  [])],
3479             [ETH_P_IP, ETH_P_IPV6])
3480         c1.add_vpp_config()
3481
3482         #
3483         # Contracts allowing ext-net 200 to talk with external EPs
3484         #
3485         c2 = VppGbpContract(
3486             self, 4220, 113, acl_index,
3487             [VppGbpContractRule(
3488                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3489                 []),
3490              VppGbpContractRule(
3491                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3492                  [])],
3493             [ETH_P_IP, ETH_P_IPV6])
3494         c2.add_vpp_config()
3495         c3 = VppGbpContract(
3496             self, 113, 4220, 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         c3.add_vpp_config()
3505
3506         #
3507         # ping between hosts in remote subnets
3508         #
3509         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
3510              Dot1Q(vlan=100) /
3511              IP(src="10.220.0.1", dst="10.221.0.1") /
3512              UDP(sport=1234, dport=1234) /
3513              Raw('\xa5' * 100))
3514
3515         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
3516
3517         for rx in rxs:
3518             self.assertEqual(rx[Ether].src, str(self.router_mac))
3519             self.assertEqual(rx[Ether].dst, eep2.mac)
3520             self.assertEqual(rx[Dot1Q].vlan, 101)
3521
3522         # we did not learn these external hosts
3523         self.assertFalse(find_gbp_endpoint(self, ip="10.220.0.1"))
3524         self.assertFalse(find_gbp_endpoint(self, ip="10.221.0.1"))
3525
3526         #
3527         # from remote external EP to local external EP
3528         #
3529         p = (Ether(src=self.pg7.remote_mac,
3530                    dst=self.pg7.local_mac) /
3531              IP(src=self.pg7.remote_ip4,
3532                 dst=self.pg7.local_ip4) /
3533              UDP(sport=1234, dport=48879) /
3534              VXLAN(vni=444, gpid=113, flags=0x88) /
3535              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
3536              IP(src="10.0.0.101", dst="10.220.0.1") /
3537              UDP(sport=1234, dport=1234) /
3538              Raw('\xa5' * 100))
3539
3540         rxs = self.send_and_expect(self.pg7, p * 1, self.pg0)
3541
3542         #
3543         # ping from an external host to the remote external EP
3544         #
3545         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
3546              Dot1Q(vlan=100) /
3547              IP(src="10.220.0.1", dst=rep.ip4.address) /
3548              UDP(sport=1234, dport=1234) /
3549              Raw('\xa5' * 100))
3550
3551         rxs = self.send_and_expect(self.pg0, p * 1, self.pg7)
3552
3553         for rx in rxs:
3554             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
3555             # self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
3556             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
3557             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
3558             self.assertEqual(rx[VXLAN].vni, 444)
3559             self.assertTrue(rx[VXLAN].flags.G)
3560             self.assertTrue(rx[VXLAN].flags.Instance)
3561             # the sclass of the ext-net the packet came from
3562             self.assertEqual(rx[VXLAN].gpid, 4220)
3563             # policy was applied to the original IP packet
3564             self.assertTrue(rx[VXLAN].gpflags.A)
3565             # since it's an external host the reciever should not learn it
3566             self.assertTrue(rx[VXLAN].gpflags.D)
3567             inner = rx[VXLAN].payload
3568             self.assertEqual(inner[IP].src, "10.220.0.1")
3569             self.assertEqual(inner[IP].dst, rep.ip4.address)
3570
3571         #
3572         # An external subnet reachable via the remote external EP
3573         #
3574
3575         #
3576         # first the VXLAN-GBP tunnel over which it is reached
3577         #
3578         vx_tun_r = VppVxlanGbpTunnel(
3579             self, self.pg7.local_ip4,
3580             self.pg7.remote_ip4, 445,
3581             mode=(VppEnum.vl_api_vxlan_gbp_api_tunnel_mode_t.
3582                   VXLAN_GBP_API_TUNNEL_MODE_L3))
3583         vx_tun_r.add_vpp_config()
3584         VppIpInterfaceBind(self, vx_tun_r, t4).add_vpp_config()
3585
3586         self.logger.info(self.vapi.cli("sh vxlan-gbp tunnel"))
3587
3588         #
3589         # then the special adj to resolve through on that tunnel
3590         #
3591         n1 = VppNeighbor(self,
3592                          vx_tun_r.sw_if_index,
3593                          "00:0c:0c:0c:0c:0c",
3594                          self.pg7.remote_ip4)
3595         n1.add_vpp_config()
3596
3597         #
3598         # the route via the adj above
3599         #
3600         ip_222 = VppIpRoute(self, "10.222.0.0", 24,
3601                             [VppRoutePath(self.pg7.remote_ip4,
3602                                           vx_tun_r.sw_if_index)],
3603                             table_id=t4.table_id)
3604         ip_222.add_vpp_config()
3605
3606         l3o_222 = VppGbpSubnet(
3607             self, rd1, "10.222.0.0", 24,
3608             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3609             sclass=4222)
3610         l3o_222.add_vpp_config()
3611
3612         #
3613         # ping between hosts in local and remote external subnets
3614         #  dropped without a contract
3615         #
3616         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
3617              Dot1Q(vlan=100) /
3618              IP(src="10.220.0.1", dst="10.222.0.1") /
3619              UDP(sport=1234, dport=1234) /
3620              Raw('\xa5' * 100))
3621
3622         rxs = self.send_and_assert_no_replies(self.pg0, p * 1)
3623
3624         #
3625         # Add contracts ext-nets for 220 -> 222
3626         #
3627         c4 = VppGbpContract(
3628             self, 4220, 4222, acl_index,
3629             [VppGbpContractRule(
3630                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3631                 []),
3632              VppGbpContractRule(
3633                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3634                  [])],
3635             [ETH_P_IP, ETH_P_IPV6])
3636         c4.add_vpp_config()
3637
3638         #
3639         # ping from host in local to remote external subnets
3640         #
3641         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
3642              Dot1Q(vlan=100) /
3643              IP(src="10.220.0.1", dst="10.222.0.1") /
3644              UDP(sport=1234, dport=1234) /
3645              Raw('\xa5' * 100))
3646
3647         rxs = self.send_and_expect(self.pg0, p * 3, self.pg7)
3648
3649         for rx in rxs:
3650             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
3651             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
3652             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
3653             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
3654             self.assertEqual(rx[VXLAN].vni, 445)
3655             self.assertTrue(rx[VXLAN].flags.G)
3656             self.assertTrue(rx[VXLAN].flags.Instance)
3657             # the sclass of the ext-net the packet came from
3658             self.assertEqual(rx[VXLAN].gpid, 4220)
3659             # policy was applied to the original IP packet
3660             self.assertTrue(rx[VXLAN].gpflags.A)
3661             # since it's an external host the reciever should not learn it
3662             self.assertTrue(rx[VXLAN].gpflags.D)
3663             inner = rx[VXLAN].payload
3664             self.assertEqual(inner[Ether].dst, "00:0c:0c:0c:0c:0c")
3665             self.assertEqual(inner[IP].src, "10.220.0.1")
3666             self.assertEqual(inner[IP].dst, "10.222.0.1")
3667
3668         #
3669         # ping from host in remote to local external subnets
3670         # there's no contract for this, but the A bit is set.
3671         #
3672         p = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) /
3673              IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) /
3674              UDP(sport=1234, dport=48879) /
3675              VXLAN(vni=445, gpid=4222, flags=0x88, gpflags='A') /
3676              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
3677              IP(src="10.222.0.1", dst="10.220.0.1") /
3678              UDP(sport=1234, dport=1234) /
3679              Raw('\xa5' * 100))
3680
3681         rxs = self.send_and_expect(self.pg7, p * 3, self.pg0)
3682         self.assertFalse(find_gbp_endpoint(self, ip="10.222.0.1"))
3683
3684         #
3685         # ping from host in remote to remote external subnets
3686         #   this is dropped by reflection check.
3687         #
3688         p = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) /
3689              IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) /
3690              UDP(sport=1234, dport=48879) /
3691              VXLAN(vni=445, gpid=4222, flags=0x88, gpflags='A') /
3692              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
3693              IP(src="10.222.0.1", dst="10.222.0.2") /
3694              UDP(sport=1234, dport=1234) /
3695              Raw('\xa5' * 100))
3696
3697         rxs = self.send_and_assert_no_replies(self.pg7, p * 3)
3698
3699         #
3700         # cleanup
3701         #
3702         self.pg7.unconfig_ip4()
3703         vlan_100.set_vtr(L2_VTR_OP.L2_DISABLED)
3704
3705
3706 if __name__ == '__main__':
3707     unittest.main(testRunner=VppTestRunner)