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