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