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