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