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