gbp: add unit-tests for anonymous l3out
[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             # a packet with an sclass from a known EPG
1723             # arriving on an unknown TEP
1724             p = (Ether(src=self.pg2.remote_mac,
1725                        dst=self.pg2.local_mac) /
1726                  IP(src=self.pg2.remote_hosts[1].ip4,
1727                     dst="239.1.1.1") /
1728                  UDP(sport=1234, dport=48879) /
1729                  VXLAN(vni=88, gpid=112, flags=0x88) /
1730                  Ether(src=l['mac'], dst="ff:ff:ff:ff:ff:ff") /
1731                  ARP(op="who-has",
1732                      psrc=l['ip'], pdst=l['ip'],
1733                      hwsrc=l['mac'], hwdst="ff:ff:ff:ff:ff:ff"))
1734
1735             rx = self.send_and_expect(self.pg4, [p], self.pg0)
1736
1737             # the new TEP
1738             tep1_sw_if_index = find_vxlan_gbp_tunnel(
1739                 self,
1740                 self.pg2.local_ip4,
1741                 self.pg2.remote_hosts[1].ip4,
1742                 99)
1743             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
1744
1745             #
1746             # the EP is learnt via the learnt TEP
1747             # both from its MAC and its IP
1748             #
1749             self.assertTrue(find_gbp_endpoint(self,
1750                                               vx_tun_l2_1.sw_if_index,
1751                                               mac=l['mac']))
1752             self.assertTrue(find_gbp_endpoint(self,
1753                                               vx_tun_l2_1.sw_if_index,
1754                                               ip=l['ip']))
1755
1756         #
1757         # wait for the learnt endpoints to age out
1758         #
1759         for l in learnt:
1760             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
1761                                      mac=l['mac'])
1762
1763         #
1764         # Learn new EPs from L2 packets
1765         #
1766         for ii, l in enumerate(learnt):
1767             # a packet with an sclass from a known EPG
1768             # arriving on an unknown TEP
1769             p = (Ether(src=self.pg2.remote_mac,
1770                        dst=self.pg2.local_mac) /
1771                  IP(src=self.pg2.remote_hosts[1].ip4,
1772                     dst=self.pg2.local_ip4) /
1773                  UDP(sport=1234, dport=48879) /
1774                  VXLAN(vni=99, gpid=112, flags=0x88) /
1775                  Ether(src=l['mac'], dst=ep.mac) /
1776                  Raw('\xa5' * 100))
1777
1778             rx = self.send_and_expect(self.pg2, [p], self.pg0)
1779
1780             # the new TEP
1781             tep1_sw_if_index = find_vxlan_gbp_tunnel(
1782                 self,
1783                 self.pg2.local_ip4,
1784                 self.pg2.remote_hosts[1].ip4,
1785                 99)
1786             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
1787
1788             #
1789             # the EP is learnt via the learnt TEP
1790             # both from its MAC and its IP
1791             #
1792             self.assertTrue(find_gbp_endpoint(self,
1793                                               vx_tun_l2_1.sw_if_index,
1794                                               mac=l['mac']))
1795
1796         self.logger.info(self.vapi.cli("show gbp endpoint"))
1797         self.logger.info(self.vapi.cli("show gbp vxlan"))
1798         self.logger.info(self.vapi.cli("show vxlan-gbp tunnel"))
1799
1800         #
1801         # wait for the learnt endpoints to age out
1802         #
1803         for l in learnt:
1804             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
1805                                      mac=l['mac'])
1806
1807         #
1808         # repeat. the do not learn bit is set so the EPs are not learnt
1809         #
1810         for l in learnt:
1811             # a packet with an sclass from a known EPG
1812             p = (Ether(src=self.pg2.remote_mac,
1813                        dst=self.pg2.local_mac) /
1814                  IP(src=self.pg2.remote_hosts[1].ip4,
1815                     dst=self.pg2.local_ip4) /
1816                  UDP(sport=1234, dport=48879) /
1817                  VXLAN(vni=99, gpid=112, flags=0x88, gpflags="D") /
1818                  Ether(src=l['mac'], dst=ep.mac) /
1819                  IP(src=l['ip'], dst=ep.ip4.address) /
1820                  UDP(sport=1234, dport=1234) /
1821                  Raw('\xa5' * 100))
1822
1823             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
1824
1825         for l in learnt:
1826             self.assertFalse(find_gbp_endpoint(self,
1827                                                vx_tun_l2_1.sw_if_index,
1828                                                mac=l['mac']))
1829
1830         #
1831         # repeat
1832         #
1833         for l in learnt:
1834             # a packet with an sclass from a known EPG
1835             p = (Ether(src=self.pg2.remote_mac,
1836                        dst=self.pg2.local_mac) /
1837                  IP(src=self.pg2.remote_hosts[1].ip4,
1838                     dst=self.pg2.local_ip4) /
1839                  UDP(sport=1234, dport=48879) /
1840                  VXLAN(vni=99, gpid=112, flags=0x88) /
1841                  Ether(src=l['mac'], dst=ep.mac) /
1842                  IP(src=l['ip'], dst=ep.ip4.address) /
1843                  UDP(sport=1234, dport=1234) /
1844                  Raw('\xa5' * 100))
1845
1846             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
1847
1848             self.assertTrue(find_gbp_endpoint(self,
1849                                               vx_tun_l2_1.sw_if_index,
1850                                               mac=l['mac']))
1851
1852         #
1853         # Static EP replies to dynamics
1854         #
1855         self.logger.info(self.vapi.cli("sh l2fib bd_id 1"))
1856         for l in learnt:
1857             p = (Ether(src=ep.mac, dst=l['mac']) /
1858                  IP(dst=l['ip'], src=ep.ip4.address) /
1859                  UDP(sport=1234, dport=1234) /
1860                  Raw('\xa5' * 100))
1861
1862             rxs = self.send_and_expect(self.pg0, p * 17, self.pg2)
1863
1864             for rx in rxs:
1865                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
1866                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
1867                 self.assertEqual(rx[UDP].dport, 48879)
1868                 # the UDP source port is a random value for hashing
1869                 self.assertEqual(rx[VXLAN].gpid, 112)
1870                 self.assertEqual(rx[VXLAN].vni, 99)
1871                 self.assertTrue(rx[VXLAN].flags.G)
1872                 self.assertTrue(rx[VXLAN].flags.Instance)
1873                 self.assertTrue(rx[VXLAN].gpflags.A)
1874                 self.assertFalse(rx[VXLAN].gpflags.D)
1875
1876         for l in learnt:
1877             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
1878                                      mac=l['mac'])
1879
1880         #
1881         # repeat in the other EPG
1882         # there's no contract between 220 and 330, but the A-bit is set
1883         # so the packet is cleared for delivery
1884         #
1885         for l in learnt:
1886             # a packet with an sclass from a known EPG
1887             p = (Ether(src=self.pg2.remote_mac,
1888                        dst=self.pg2.local_mac) /
1889                  IP(src=self.pg2.remote_hosts[1].ip4,
1890                     dst=self.pg2.local_ip4) /
1891                  UDP(sport=1234, dport=48879) /
1892                  VXLAN(vni=99, gpid=113, flags=0x88, gpflags='A') /
1893                  Ether(src=l['mac'], dst=ep.mac) /
1894                  IP(src=l['ip'], dst=ep.ip4.address) /
1895                  UDP(sport=1234, dport=1234) /
1896                  Raw('\xa5' * 100))
1897
1898             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
1899
1900             self.assertTrue(find_gbp_endpoint(self,
1901                                               vx_tun_l2_1.sw_if_index,
1902                                               mac=l['mac']))
1903
1904         #
1905         # static EP cannot reach the learnt EPs since there is no contract
1906         # only test 1 EP as the others could timeout
1907         #
1908         p = (Ether(src=ep.mac, dst=l['mac']) /
1909              IP(dst=learnt[0]['ip'], src=ep.ip4.address) /
1910              UDP(sport=1234, dport=1234) /
1911              Raw('\xa5' * 100))
1912
1913         self.send_and_assert_no_replies(self.pg0, [p])
1914
1915         #
1916         # refresh the entries after the check for no replies above
1917         #
1918         for l in learnt:
1919             # a packet with an sclass from a known EPG
1920             p = (Ether(src=self.pg2.remote_mac,
1921                        dst=self.pg2.local_mac) /
1922                  IP(src=self.pg2.remote_hosts[1].ip4,
1923                     dst=self.pg2.local_ip4) /
1924                  UDP(sport=1234, dport=48879) /
1925                  VXLAN(vni=99, gpid=113, flags=0x88, gpflags='A') /
1926                  Ether(src=l['mac'], dst=ep.mac) /
1927                  IP(src=l['ip'], dst=ep.ip4.address) /
1928                  UDP(sport=1234, dport=1234) /
1929                  Raw('\xa5' * 100))
1930
1931             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
1932
1933             self.assertTrue(find_gbp_endpoint(self,
1934                                               vx_tun_l2_1.sw_if_index,
1935                                               mac=l['mac']))
1936
1937         #
1938         # Add the contract so they can talk
1939         #
1940         acl = VppGbpAcl(self)
1941         rule = acl.create_rule(permit_deny=1, proto=17)
1942         rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
1943         acl_index = acl.add_vpp_config([rule, rule2])
1944         c1 = VppGbpContract(
1945             self, 401, epg_220.sclass, epg_330.sclass, acl_index,
1946             [VppGbpContractRule(
1947                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1948                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1949                 []),
1950                 VppGbpContractRule(
1951                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1952                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
1953                     [])],
1954             [ETH_P_IP, ETH_P_IPV6])
1955         c1.add_vpp_config()
1956
1957         for l in learnt:
1958             p = (Ether(src=ep.mac, dst=l['mac']) /
1959                  IP(dst=l['ip'], src=ep.ip4.address) /
1960                  UDP(sport=1234, dport=1234) /
1961                  Raw('\xa5' * 100))
1962
1963             self.send_and_expect(self.pg0, [p], self.pg2)
1964
1965         #
1966         # send UU packets from the local EP
1967         #
1968         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1969         self.logger.info(self.vapi.cli("sh gbp bridge"))
1970         p_uu = (Ether(src=ep.mac, dst="00:11:11:11:11:11") /
1971                 IP(dst="10.0.0.133", src=ep.ip4.address) /
1972                 UDP(sport=1234, dport=1234) /
1973                 Raw('\xa5' * 100))
1974         rxs = self.send_and_expect(ep.itf, [p_uu], gbd1.uu_fwd)
1975
1976         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1977
1978         p_bm = (Ether(src=ep.mac, dst="ff:ff:ff:ff:ff:ff") /
1979                 IP(dst="10.0.0.133", src=ep.ip4.address) /
1980                 UDP(sport=1234, dport=1234) /
1981                 Raw('\xa5' * 100))
1982         rxs = self.send_and_expect_only(ep.itf, [p_bm], tun_bm.mcast_itf)
1983
1984         for rx in rxs:
1985             self.assertEqual(rx[IP].src, self.pg4.local_ip4)
1986             self.assertEqual(rx[IP].dst, "239.1.1.1")
1987             self.assertEqual(rx[UDP].dport, 48879)
1988             # the UDP source port is a random value for hashing
1989             self.assertEqual(rx[VXLAN].gpid, 112)
1990             self.assertEqual(rx[VXLAN].vni, 88)
1991             self.assertTrue(rx[VXLAN].flags.G)
1992             self.assertTrue(rx[VXLAN].flags.Instance)
1993             self.assertFalse(rx[VXLAN].gpflags.A)
1994             self.assertFalse(rx[VXLAN].gpflags.D)
1995
1996         #
1997         # Check v6 Endpoints
1998         #
1999         for l in learnt:
2000             # a packet with an sclass from a known EPG
2001             p = (Ether(src=self.pg2.remote_mac,
2002                        dst=self.pg2.local_mac) /
2003                  IP(src=self.pg2.remote_hosts[1].ip4,
2004                     dst=self.pg2.local_ip4) /
2005                  UDP(sport=1234, dport=48879) /
2006                  VXLAN(vni=99, gpid=113, flags=0x88, gpflags='A') /
2007                  Ether(src=l['mac'], dst=ep.mac) /
2008                  IPv6(src=l['ip6'], dst=ep.ip6.address) /
2009                  UDP(sport=1234, dport=1234) /
2010                  Raw('\xa5' * 100))
2011
2012             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
2013
2014             self.assertTrue(find_gbp_endpoint(self,
2015                                               vx_tun_l2_1.sw_if_index,
2016                                               mac=l['mac']))
2017
2018         #
2019         # L3 Endpoint Learning
2020         #  - configured on the bridge's BVI
2021         #
2022
2023         #
2024         # clean up
2025         #
2026         for l in learnt:
2027             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
2028                                      mac=l['mac'])
2029         self.pg2.unconfig_ip4()
2030         self.pg3.unconfig_ip4()
2031         self.pg4.unconfig_ip4()
2032
2033         self.logger.info(self.vapi.cli("sh int"))
2034         self.logger.info(self.vapi.cli("sh gbp vxlan"))
2035
2036     def test_gbp_contract(self):
2037         """ GBP CONTRACTS """
2038
2039         #
2040         # Route Domains
2041         #
2042         gt4 = VppIpTable(self, 0)
2043         gt4.add_vpp_config()
2044         gt6 = VppIpTable(self, 0, is_ip6=True)
2045         gt6.add_vpp_config()
2046
2047         rd0 = VppGbpRouteDomain(self, 0, 400, gt4, gt6, None, None)
2048
2049         rd0.add_vpp_config()
2050
2051         #
2052         # Bridge Domains
2053         #
2054         bd1 = VppBridgeDomain(self, 1, arp_term=0)
2055         bd2 = VppBridgeDomain(self, 2, arp_term=0)
2056
2057         bd1.add_vpp_config()
2058         bd2.add_vpp_config()
2059
2060         gbd1 = VppGbpBridgeDomain(self, bd1, rd0, self.loop0)
2061         gbd2 = VppGbpBridgeDomain(self, bd2, rd0, self.loop1)
2062
2063         gbd1.add_vpp_config()
2064         gbd2.add_vpp_config()
2065
2066         #
2067         # 3 EPGs, 2 of which share a BD.
2068         #
2069         epgs = [VppGbpEndpointGroup(self, 220, 1220, rd0, gbd1,
2070                                     None, self.loop0,
2071                                     "10.0.0.128", "2001:10::128"),
2072                 VppGbpEndpointGroup(self, 221, 1221, rd0, gbd1,
2073                                     None, self.loop0,
2074                                     "10.0.1.128", "2001:10:1::128"),
2075                 VppGbpEndpointGroup(self, 222, 1222, rd0, gbd2,
2076                                     None, self.loop1,
2077                                     "10.0.2.128", "2001:10:2::128")]
2078         #
2079         # 4 end-points, 2 in the same subnet, 3 in the same BD
2080         #
2081         eps = [VppGbpEndpoint(self, self.pg0,
2082                               epgs[0], None,
2083                               "10.0.0.1", "11.0.0.1",
2084                               "2001:10::1", "3001::1"),
2085                VppGbpEndpoint(self, self.pg1,
2086                               epgs[0], None,
2087                               "10.0.0.2", "11.0.0.2",
2088                               "2001:10::2", "3001::2"),
2089                VppGbpEndpoint(self, self.pg2,
2090                               epgs[1], None,
2091                               "10.0.1.1", "11.0.0.3",
2092                               "2001:10:1::1", "3001::3"),
2093                VppGbpEndpoint(self, self.pg3,
2094                               epgs[2], None,
2095                               "10.0.2.1", "11.0.0.4",
2096                               "2001:10:2::1", "3001::4")]
2097
2098         #
2099         # Config related to each of the EPGs
2100         #
2101         for epg in epgs:
2102             # IP config on the BVI interfaces
2103             if epg != epgs[1]:
2104                 VppIpInterfaceBind(self, epg.bvi, epg.rd.t4).add_vpp_config()
2105                 VppIpInterfaceBind(self, epg.bvi, epg.rd.t6).add_vpp_config()
2106                 self.vapi.sw_interface_set_mac_address(
2107                     epg.bvi.sw_if_index,
2108                     self.router_mac.packed)
2109
2110             if_ip4 = VppIpInterfaceAddress(self, epg.bvi, epg.bvi_ip4, 32)
2111             if_ip6 = VppIpInterfaceAddress(self, epg.bvi, epg.bvi_ip6, 128)
2112             if_ip4.add_vpp_config()
2113             if_ip6.add_vpp_config()
2114
2115             # add the BD ARP termination entry for BVI IP
2116             epg.bd_arp_ip4 = VppBridgeDomainArpEntry(self, epg.bd.bd,
2117                                                      str(self.router_mac),
2118                                                      epg.bvi_ip4.address)
2119             epg.bd_arp_ip4.add_vpp_config()
2120
2121             # EPG in VPP
2122             epg.add_vpp_config()
2123
2124         #
2125         # config ep
2126         #
2127         for ep in eps:
2128             ep.add_vpp_config()
2129
2130         self.logger.info(self.vapi.cli("show gbp endpoint"))
2131         self.logger.info(self.vapi.cli("show interface"))
2132         self.logger.info(self.vapi.cli("show br"))
2133
2134         #
2135         # Intra epg allowed without contract
2136         #
2137         pkt_intra_epg_220_to_220 = (Ether(src=self.pg0.remote_mac,
2138                                           dst=self.pg1.remote_mac) /
2139                                     IP(src=eps[0].ip4.address,
2140                                        dst=eps[1].ip4.address) /
2141                                     UDP(sport=1234, dport=1234) /
2142                                     Raw('\xa5' * 100))
2143
2144         self.send_and_expect_bridged(self.pg0,
2145                                      pkt_intra_epg_220_to_220 * 65,
2146                                      self.pg1)
2147
2148         #
2149         # Inter epg denied without contract
2150         #
2151         pkt_inter_epg_220_to_221 = (Ether(src=self.pg0.remote_mac,
2152                                           dst=self.pg2.remote_mac) /
2153                                     IP(src=eps[0].ip4.address,
2154                                        dst=eps[2].ip4.address) /
2155                                     UDP(sport=1234, dport=1234) /
2156                                     Raw('\xa5' * 100))
2157
2158         self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_220_to_221)
2159
2160         #
2161         # A uni-directional contract from EPG 220 -> 221
2162         #
2163         acl = VppGbpAcl(self)
2164         rule = acl.create_rule(permit_deny=1, proto=17)
2165         rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
2166         acl_index = acl.add_vpp_config([rule, rule2])
2167         c1 = VppGbpContract(
2168             self, 400, epgs[0].sclass, epgs[1].sclass, acl_index,
2169             [VppGbpContractRule(
2170                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2171                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2172                 []),
2173              VppGbpContractRule(
2174                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2175                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2176                  [])],
2177             [ETH_P_IP, ETH_P_IPV6])
2178         c1.add_vpp_config()
2179
2180         self.send_and_expect_bridged(eps[0].itf,
2181                                      pkt_inter_epg_220_to_221 * 65,
2182                                      eps[2].itf)
2183
2184         pkt_inter_epg_220_to_222 = (Ether(src=self.pg0.remote_mac,
2185                                           dst=str(self.router_mac)) /
2186                                     IP(src=eps[0].ip4.address,
2187                                        dst=eps[3].ip4.address) /
2188                                     UDP(sport=1234, dport=1234) /
2189                                     Raw('\xa5' * 100))
2190         self.send_and_assert_no_replies(eps[0].itf,
2191                                         pkt_inter_epg_220_to_222 * 65)
2192
2193         #
2194         # contract for the return direction
2195         #
2196         c2 = VppGbpContract(
2197             self, 400, epgs[1].sclass, epgs[0].sclass, acl_index,
2198             [VppGbpContractRule(
2199                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2200                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2201                 []),
2202              VppGbpContractRule(
2203                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2204                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2205                  [])],
2206             [ETH_P_IP, ETH_P_IPV6])
2207         c2.add_vpp_config()
2208
2209         self.send_and_expect_bridged(eps[0].itf,
2210                                      pkt_inter_epg_220_to_221 * 65,
2211                                      eps[2].itf)
2212         pkt_inter_epg_221_to_220 = (Ether(src=self.pg2.remote_mac,
2213                                           dst=self.pg0.remote_mac) /
2214                                     IP(src=eps[2].ip4.address,
2215                                        dst=eps[0].ip4.address) /
2216                                     UDP(sport=1234, dport=1234) /
2217                                     Raw('\xa5' * 100))
2218         self.send_and_expect_bridged(eps[2].itf,
2219                                      pkt_inter_epg_221_to_220 * 65,
2220                                      eps[0].itf)
2221
2222         #
2223         # contract between 220 and 222 uni-direction
2224         #
2225         c3 = VppGbpContract(
2226             self, 400, epgs[0].sclass, epgs[2].sclass, acl_index,
2227             [VppGbpContractRule(
2228                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2229                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2230                 []),
2231              VppGbpContractRule(
2232                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2233                  VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
2234                  [])],
2235             [ETH_P_IP, ETH_P_IPV6])
2236         c3.add_vpp_config()
2237
2238         self.send_and_expect(eps[0].itf,
2239                              pkt_inter_epg_220_to_222 * 65,
2240                              eps[3].itf)
2241
2242         c3.remove_vpp_config()
2243         c1.remove_vpp_config()
2244         c2.remove_vpp_config()
2245         acl.remove_vpp_config()
2246
2247     def test_gbp_bd_flags(self):
2248         """ GBP BD FLAGS """
2249
2250         #
2251         # IP tables
2252         #
2253         gt4 = VppIpTable(self, 1)
2254         gt4.add_vpp_config()
2255         gt6 = VppIpTable(self, 1, is_ip6=True)
2256         gt6.add_vpp_config()
2257
2258         rd1 = VppGbpRouteDomain(self, 1, 401, gt4, gt6)
2259         rd1.add_vpp_config()
2260
2261         #
2262         # Pg3 hosts the IP4 UU-flood VXLAN tunnel
2263         # Pg4 hosts the IP6 UU-flood VXLAN tunnel
2264         #
2265         self.pg3.config_ip4()
2266         self.pg3.resolve_arp()
2267         self.pg4.config_ip4()
2268         self.pg4.resolve_arp()
2269
2270         #
2271         # Add a mcast destination VXLAN-GBP tunnel for B&M traffic
2272         #
2273         tun_bm = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
2274                                    "239.1.1.1", 88,
2275                                    mcast_itf=self.pg4)
2276         tun_bm.add_vpp_config()
2277
2278         #
2279         # a GBP bridge domain with a BVI and a UU-flood interface
2280         #
2281         bd1 = VppBridgeDomain(self, 1)
2282         bd1.add_vpp_config()
2283
2284         gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0, self.pg3,
2285                                   tun_bm, uu_drop=True, bm_drop=True)
2286         gbd1.add_vpp_config()
2287
2288         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
2289         self.logger.info(self.vapi.cli("sh gbp bridge"))
2290
2291         # ... and has a /32 applied
2292         ip_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
2293         ip_addr.add_vpp_config()
2294
2295         #
2296         # The Endpoint-group
2297         #
2298         epg_220 = VppGbpEndpointGroup(self, 220, 112, rd1, gbd1,
2299                                       None, self.loop0,
2300                                       "10.0.0.128",
2301                                       "2001:10::128",
2302                                       VppGbpEndpointRetention(2))
2303         epg_220.add_vpp_config()
2304
2305         ep = VppGbpEndpoint(self, self.pg0,
2306                             epg_220, None,
2307                             "10.0.0.127", "11.0.0.127",
2308                             "2001:10::1", "3001::1")
2309         ep.add_vpp_config()
2310         #
2311         # send UU/BM packet from the local EP with UU drop and BM drop enabled
2312         # in bd
2313         #
2314         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
2315         self.logger.info(self.vapi.cli("sh gbp bridge"))
2316         p_uu = (Ether(src=ep.mac, dst="00:11:11:11:11:11") /
2317                 IP(dst="10.0.0.133", src=ep.ip4.address) /
2318                 UDP(sport=1234, dport=1234) /
2319                 Raw('\xa5' * 100))
2320         self.send_and_assert_no_replies(ep.itf, [p_uu])
2321
2322         p_bm = (Ether(src=ep.mac, dst="ff:ff:ff:ff:ff:ff") /
2323                 IP(dst="10.0.0.133", src=ep.ip4.address) /
2324                 UDP(sport=1234, dport=1234) /
2325                 Raw('\xa5' * 100))
2326         self.send_and_assert_no_replies(ep.itf, [p_bm])
2327
2328         self.pg3.unconfig_ip4()
2329         self.pg4.unconfig_ip4()
2330
2331         self.logger.info(self.vapi.cli("sh int"))
2332
2333     def test_gbp_learn_vlan_l2(self):
2334         """ GBP L2 Endpoint w/ VLANs"""
2335
2336         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
2337         learnt = [{'mac': '00:00:11:11:11:01',
2338                    'ip': '10.0.0.1',
2339                    'ip6': '2001:10::2'},
2340                   {'mac': '00:00:11:11:11:02',
2341                    'ip': '10.0.0.2',
2342                    'ip6': '2001:10::3'}]
2343
2344         #
2345         # IP tables
2346         #
2347         gt4 = VppIpTable(self, 1)
2348         gt4.add_vpp_config()
2349         gt6 = VppIpTable(self, 1, is_ip6=True)
2350         gt6.add_vpp_config()
2351
2352         rd1 = VppGbpRouteDomain(self, 1, 401, gt4, gt6)
2353         rd1.add_vpp_config()
2354
2355         #
2356         # Pg2 hosts the vxlan tunnel, hosts on pg2 to act as TEPs
2357         #
2358         self.pg2.config_ip4()
2359         self.pg2.resolve_arp()
2360         self.pg2.generate_remote_hosts(4)
2361         self.pg2.configure_ipv4_neighbors()
2362         self.pg3.config_ip4()
2363         self.pg3.resolve_arp()
2364
2365         #
2366         # The EP will be on a vlan sub-interface
2367         #
2368         vlan_11 = VppDot1QSubint(self, self.pg0, 11)
2369         vlan_11.admin_up()
2370         self.vapi.l2_interface_vlan_tag_rewrite(
2371             sw_if_index=vlan_11.sw_if_index, vtr_op=L2_VTR_OP.L2_POP_1,
2372             push_dot1q=11)
2373
2374         bd_uu_fwd = VppVxlanGbpTunnel(self, self.pg3.local_ip4,
2375                                       self.pg3.remote_ip4, 116)
2376         bd_uu_fwd.add_vpp_config()
2377
2378         #
2379         # a GBP bridge domain with a BVI and a UU-flood interface
2380         # The BD is marked as do not learn, so no endpoints are ever
2381         # learnt in this BD.
2382         #
2383         bd1 = VppBridgeDomain(self, 1)
2384         bd1.add_vpp_config()
2385         gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0, bd_uu_fwd,
2386                                   learn=False)
2387         gbd1.add_vpp_config()
2388
2389         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
2390         self.logger.info(self.vapi.cli("sh gbp bridge"))
2391
2392         # ... and has a /32 applied
2393         ip_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
2394         ip_addr.add_vpp_config()
2395
2396         #
2397         # The Endpoint-group in which we are learning endpoints
2398         #
2399         epg_220 = VppGbpEndpointGroup(self, 220, 441, rd1, gbd1,
2400                                       None, self.loop0,
2401                                       "10.0.0.128",
2402                                       "2001:10::128",
2403                                       VppGbpEndpointRetention(2))
2404         epg_220.add_vpp_config()
2405
2406         #
2407         # The VXLAN GBP tunnel is a bridge-port and has L2 endpoint
2408         # learning enabled
2409         #
2410         vx_tun_l2_1 = VppGbpVxlanTunnel(
2411             self, 99, bd1.bd_id,
2412             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L2,
2413             self.pg2.local_ip4)
2414         vx_tun_l2_1.add_vpp_config()
2415
2416         #
2417         # A static endpoint that the learnt endpoints are trying to
2418         # talk to
2419         #
2420         ep = VppGbpEndpoint(self, vlan_11,
2421                             epg_220, None,
2422                             "10.0.0.127", "11.0.0.127",
2423                             "2001:10::1", "3001::1")
2424         ep.add_vpp_config()
2425
2426         self.assertTrue(find_route(self, ep.ip4.address, 32, table_id=1))
2427
2428         #
2429         # Send to the static EP
2430         #
2431         for ii, l in enumerate(learnt):
2432             # a packet with an sclass from a known EPG
2433             # arriving on an unknown TEP
2434             p = (Ether(src=self.pg2.remote_mac,
2435                        dst=self.pg2.local_mac) /
2436                  IP(src=self.pg2.remote_hosts[1].ip4,
2437                     dst=self.pg2.local_ip4) /
2438                  UDP(sport=1234, dport=48879) /
2439                  VXLAN(vni=99, gpid=441, flags=0x88) /
2440                  Ether(src=l['mac'], dst=ep.mac) /
2441                  IP(src=l['ip'], dst=ep.ip4.address) /
2442                  UDP(sport=1234, dport=1234) /
2443                  Raw('\xa5' * 100))
2444
2445             rxs = self.send_and_expect(self.pg2, [p], self.pg0)
2446
2447             #
2448             # packet to EP has the EP's vlan tag
2449             #
2450             for rx in rxs:
2451                 self.assertEqual(rx[Dot1Q].vlan, 11)
2452
2453             #
2454             # the EP is not learnt since the BD setting prevents it
2455             # also no TEP too
2456             #
2457             self.assertFalse(find_gbp_endpoint(self,
2458                                                vx_tun_l2_1.sw_if_index,
2459                                                mac=l['mac']))
2460             self.assertEqual(INDEX_INVALID,
2461                              find_vxlan_gbp_tunnel(
2462                                  self,
2463                                  self.pg2.local_ip4,
2464                                  self.pg2.remote_hosts[1].ip4,
2465                                  99))
2466
2467         self.assertEqual(len(self.vapi.gbp_endpoint_dump()), 1)
2468
2469         #
2470         # static to remotes
2471         # we didn't learn the remotes so they are sent to the UU-fwd
2472         #
2473         for l in learnt:
2474             p = (Ether(src=ep.mac, dst=l['mac']) /
2475                  Dot1Q(vlan=11) /
2476                  IP(dst=l['ip'], src=ep.ip4.address) /
2477                  UDP(sport=1234, dport=1234) /
2478                  Raw('\xa5' * 100))
2479
2480             rxs = self.send_and_expect(self.pg0, p * 17, self.pg3)
2481
2482             for rx in rxs:
2483                 self.assertEqual(rx[IP].src, self.pg3.local_ip4)
2484                 self.assertEqual(rx[IP].dst, self.pg3.remote_ip4)
2485                 self.assertEqual(rx[UDP].dport, 48879)
2486                 # the UDP source port is a random value for hashing
2487                 self.assertEqual(rx[VXLAN].gpid, 441)
2488                 self.assertEqual(rx[VXLAN].vni, 116)
2489                 self.assertTrue(rx[VXLAN].flags.G)
2490                 self.assertTrue(rx[VXLAN].flags.Instance)
2491                 self.assertFalse(rx[VXLAN].gpflags.A)
2492                 self.assertFalse(rx[VXLAN].gpflags.D)
2493
2494         self.pg2.unconfig_ip4()
2495         self.pg3.unconfig_ip4()
2496
2497     def test_gbp_learn_l3(self):
2498         """ GBP L3 Endpoint Learning """
2499
2500         self.vapi.cli("set logging class gbp level debug")
2501
2502         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
2503         routed_dst_mac = "00:0c:0c:0c:0c:0c"
2504         routed_src_mac = "00:22:bd:f8:19:ff"
2505
2506         learnt = [{'mac': '00:00:11:11:11:02',
2507                    'ip': '10.0.1.2',
2508                    'ip6': '2001:10::2'},
2509                   {'mac': '00:00:11:11:11:03',
2510                    'ip': '10.0.1.3',
2511                    'ip6': '2001:10::3'}]
2512
2513         #
2514         # IP tables
2515         #
2516         t4 = VppIpTable(self, 1)
2517         t4.add_vpp_config()
2518         t6 = VppIpTable(self, 1, True)
2519         t6.add_vpp_config()
2520
2521         tun_ip4_uu = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
2522                                        self.pg4.remote_ip4, 114)
2523         tun_ip6_uu = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
2524                                        self.pg4.remote_ip4, 116)
2525         tun_ip4_uu.add_vpp_config()
2526         tun_ip6_uu.add_vpp_config()
2527
2528         rd1 = VppGbpRouteDomain(self, 2, 401, t4, t6, tun_ip4_uu, tun_ip6_uu)
2529         rd1.add_vpp_config()
2530
2531         self.loop0.set_mac(self.router_mac)
2532
2533         #
2534         # Bind the BVI to the RD
2535         #
2536         VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
2537         VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
2538
2539         #
2540         # Pg2 hosts the vxlan tunnel
2541         # hosts on pg2 to act as TEPs
2542         # pg3 is BD uu-fwd
2543         # pg4 is RD uu-fwd
2544         #
2545         self.pg2.config_ip4()
2546         self.pg2.resolve_arp()
2547         self.pg2.generate_remote_hosts(4)
2548         self.pg2.configure_ipv4_neighbors()
2549         self.pg3.config_ip4()
2550         self.pg3.resolve_arp()
2551         self.pg4.config_ip4()
2552         self.pg4.resolve_arp()
2553
2554         #
2555         # a GBP bridge domain with a BVI and a UU-flood interface
2556         #
2557         bd1 = VppBridgeDomain(self, 1)
2558         bd1.add_vpp_config()
2559         gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0, self.pg3)
2560         gbd1.add_vpp_config()
2561
2562         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
2563         self.logger.info(self.vapi.cli("sh gbp bridge"))
2564         self.logger.info(self.vapi.cli("sh gbp route"))
2565
2566         # ... and has a /32 and /128 applied
2567         ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
2568         ip4_addr.add_vpp_config()
2569         ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128", 128)
2570         ip6_addr.add_vpp_config()
2571
2572         #
2573         # The Endpoint-group in which we are learning endpoints
2574         #
2575         epg_220 = VppGbpEndpointGroup(self, 220, 441, rd1, gbd1,
2576                                       None, self.loop0,
2577                                       "10.0.0.128",
2578                                       "2001:10::128",
2579                                       VppGbpEndpointRetention(2))
2580         epg_220.add_vpp_config()
2581
2582         #
2583         # The VXLAN GBP tunnel is a bridge-port and has L2 endpoint
2584         # learning enabled
2585         #
2586         vx_tun_l3 = VppGbpVxlanTunnel(
2587             self, 101, rd1.rd_id,
2588             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3,
2589             self.pg2.local_ip4)
2590         vx_tun_l3.add_vpp_config()
2591
2592         #
2593         # A static endpoint that the learnt endpoints are trying to
2594         # talk to
2595         #
2596         ep = VppGbpEndpoint(self, self.pg0,
2597                             epg_220, None,
2598                             "10.0.0.127", "11.0.0.127",
2599                             "2001:10::1", "3001::1")
2600         ep.add_vpp_config()
2601
2602         #
2603         # learn some remote IPv4 EPs
2604         #
2605         for ii, l in enumerate(learnt):
2606             # a packet with an sclass from a known EPG
2607             # arriving on an unknown TEP
2608             p = (Ether(src=self.pg2.remote_mac,
2609                        dst=self.pg2.local_mac) /
2610                  IP(src=self.pg2.remote_hosts[1].ip4,
2611                     dst=self.pg2.local_ip4) /
2612                  UDP(sport=1234, dport=48879) /
2613                  VXLAN(vni=101, gpid=441, flags=0x88) /
2614                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
2615                  IP(src=l['ip'], dst=ep.ip4.address) /
2616                  UDP(sport=1234, dport=1234) /
2617                  Raw('\xa5' * 100))
2618
2619             rx = self.send_and_expect(self.pg2, [p], self.pg0)
2620
2621             # the new TEP
2622             tep1_sw_if_index = find_vxlan_gbp_tunnel(
2623                 self,
2624                 self.pg2.local_ip4,
2625                 self.pg2.remote_hosts[1].ip4,
2626                 vx_tun_l3.vni)
2627             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
2628
2629             # endpoint learnt via the parent GBP-vxlan interface
2630             self.assertTrue(find_gbp_endpoint(self,
2631                                               vx_tun_l3._sw_if_index,
2632                                               ip=l['ip']))
2633
2634         #
2635         # Static IPv4 EP replies to learnt
2636         #
2637         for l in learnt:
2638             p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2639                  IP(dst=l['ip'], src=ep.ip4.address) /
2640                  UDP(sport=1234, dport=1234) /
2641                  Raw('\xa5' * 100))
2642
2643             rxs = self.send_and_expect(self.pg0, p * 1, self.pg2)
2644
2645             for rx in rxs:
2646                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2647                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
2648                 self.assertEqual(rx[UDP].dport, 48879)
2649                 # the UDP source port is a random value for hashing
2650                 self.assertEqual(rx[VXLAN].gpid, 441)
2651                 self.assertEqual(rx[VXLAN].vni, 101)
2652                 self.assertTrue(rx[VXLAN].flags.G)
2653                 self.assertTrue(rx[VXLAN].flags.Instance)
2654                 self.assertTrue(rx[VXLAN].gpflags.A)
2655                 self.assertFalse(rx[VXLAN].gpflags.D)
2656
2657                 inner = rx[VXLAN].payload
2658
2659                 self.assertEqual(inner[Ether].src, routed_src_mac)
2660                 self.assertEqual(inner[Ether].dst, routed_dst_mac)
2661                 self.assertEqual(inner[IP].src, ep.ip4.address)
2662                 self.assertEqual(inner[IP].dst, l['ip'])
2663
2664         for l in learnt:
2665             self.assertFalse(find_gbp_endpoint(self,
2666                                                tep1_sw_if_index,
2667                                                ip=l['ip']))
2668
2669         #
2670         # learn some remote IPv6 EPs
2671         #
2672         for ii, l in enumerate(learnt):
2673             # a packet with an sclass from a known EPG
2674             # arriving on an unknown TEP
2675             p = (Ether(src=self.pg2.remote_mac,
2676                        dst=self.pg2.local_mac) /
2677                  IP(src=self.pg2.remote_hosts[1].ip4,
2678                     dst=self.pg2.local_ip4) /
2679                  UDP(sport=1234, dport=48879) /
2680                  VXLAN(vni=101, gpid=441, flags=0x88) /
2681                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
2682                  IPv6(src=l['ip6'], dst=ep.ip6.address) /
2683                  UDP(sport=1234, dport=1234) /
2684                  Raw('\xa5' * 100))
2685
2686             rx = self.send_and_expect(self.pg2, [p], self.pg0)
2687
2688             # the new TEP
2689             tep1_sw_if_index = find_vxlan_gbp_tunnel(
2690                 self,
2691                 self.pg2.local_ip4,
2692                 self.pg2.remote_hosts[1].ip4,
2693                 vx_tun_l3.vni)
2694             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
2695
2696             self.logger.info(self.vapi.cli("show gbp bridge"))
2697             self.logger.info(self.vapi.cli("show vxlan-gbp tunnel"))
2698             self.logger.info(self.vapi.cli("show gbp vxlan"))
2699             self.logger.info(self.vapi.cli("show int addr"))
2700
2701             # endpoint learnt via the TEP
2702             self.assertTrue(find_gbp_endpoint(self, ip=l['ip6']))
2703
2704         self.logger.info(self.vapi.cli("show gbp endpoint"))
2705         self.logger.info(self.vapi.cli("show ip fib index 1 %s" % l['ip']))
2706
2707         #
2708         # Static EP replies to learnt
2709         #
2710         for l in learnt:
2711             p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2712                  IPv6(dst=l['ip6'], src=ep.ip6.address) /
2713                  UDP(sport=1234, dport=1234) /
2714                  Raw('\xa5' * 100))
2715
2716             rxs = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg2)
2717
2718             for rx in rxs:
2719                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2720                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
2721                 self.assertEqual(rx[UDP].dport, 48879)
2722                 # the UDP source port is a random value for hashing
2723                 self.assertEqual(rx[VXLAN].gpid, 441)
2724                 self.assertEqual(rx[VXLAN].vni, 101)
2725                 self.assertTrue(rx[VXLAN].flags.G)
2726                 self.assertTrue(rx[VXLAN].flags.Instance)
2727                 self.assertTrue(rx[VXLAN].gpflags.A)
2728                 self.assertFalse(rx[VXLAN].gpflags.D)
2729
2730                 inner = rx[VXLAN].payload
2731
2732                 self.assertEqual(inner[Ether].src, routed_src_mac)
2733                 self.assertEqual(inner[Ether].dst, routed_dst_mac)
2734                 self.assertEqual(inner[IPv6].src, ep.ip6.address)
2735                 self.assertEqual(inner[IPv6].dst, l['ip6'])
2736
2737         self.logger.info(self.vapi.cli("sh gbp endpoint"))
2738         for l in learnt:
2739             self.wait_for_ep_timeout(ip=l['ip'])
2740
2741         #
2742         # Static sends to unknown EP with no route
2743         #
2744         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2745              IP(dst="10.0.0.99", src=ep.ip4.address) /
2746              UDP(sport=1234, dport=1234) /
2747              Raw('\xa5' * 100))
2748
2749         self.send_and_assert_no_replies(self.pg0, [p])
2750
2751         #
2752         # Add a route to static EP's v4 and v6 subnet
2753         #  packets should be sent on the v4/v6 uu=fwd interface resp.
2754         #
2755         se_10_24 = VppGbpSubnet(
2756             self, rd1, "10.0.0.0", 24,
2757             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_TRANSPORT)
2758         se_10_24.add_vpp_config()
2759
2760         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2761              IP(dst="10.0.0.99", src=ep.ip4.address) /
2762              UDP(sport=1234, dport=1234) /
2763              Raw('\xa5' * 100))
2764
2765         rxs = self.send_and_expect(self.pg0, [p], self.pg4)
2766         for rx in rxs:
2767             self.assertEqual(rx[IP].src, self.pg4.local_ip4)
2768             self.assertEqual(rx[IP].dst, self.pg4.remote_ip4)
2769             self.assertEqual(rx[UDP].dport, 48879)
2770             # the UDP source port is a random value for hashing
2771             self.assertEqual(rx[VXLAN].gpid, 441)
2772             self.assertEqual(rx[VXLAN].vni, 114)
2773             self.assertTrue(rx[VXLAN].flags.G)
2774             self.assertTrue(rx[VXLAN].flags.Instance)
2775             # policy is not applied to packets sent to the uu-fwd interfaces
2776             self.assertFalse(rx[VXLAN].gpflags.A)
2777             self.assertFalse(rx[VXLAN].gpflags.D)
2778
2779         #
2780         # learn some remote IPv4 EPs
2781         #
2782         for ii, l in enumerate(learnt):
2783             # a packet with an sclass from a known EPG
2784             # arriving on an unknown TEP
2785             p = (Ether(src=self.pg2.remote_mac,
2786                        dst=self.pg2.local_mac) /
2787                  IP(src=self.pg2.remote_hosts[2].ip4,
2788                     dst=self.pg2.local_ip4) /
2789                  UDP(sport=1234, dport=48879) /
2790                  VXLAN(vni=101, gpid=441, flags=0x88) /
2791                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
2792                  IP(src=l['ip'], dst=ep.ip4.address) /
2793                  UDP(sport=1234, dport=1234) /
2794                  Raw('\xa5' * 100))
2795
2796             rx = self.send_and_expect(self.pg2, [p], self.pg0)
2797
2798             # the new TEP
2799             tep1_sw_if_index = find_vxlan_gbp_tunnel(
2800                 self,
2801                 self.pg2.local_ip4,
2802                 self.pg2.remote_hosts[2].ip4,
2803                 vx_tun_l3.vni)
2804             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
2805
2806             # endpoint learnt via the parent GBP-vxlan interface
2807             self.assertTrue(find_gbp_endpoint(self,
2808                                               vx_tun_l3._sw_if_index,
2809                                               ip=l['ip']))
2810
2811         #
2812         # Add a remote endpoint from the API
2813         #
2814         rep_88 = VppGbpEndpoint(self, vx_tun_l3,
2815                                 epg_220, None,
2816                                 "10.0.0.88", "11.0.0.88",
2817                                 "2001:10::88", "3001::88",
2818                                 ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
2819                                 self.pg2.local_ip4,
2820                                 self.pg2.remote_hosts[2].ip4,
2821                                 mac=None)
2822         rep_88.add_vpp_config()
2823
2824         #
2825         # Add a remote endpoint from the API that matches an existing one
2826         # this is a lower priority, hence the packet is sent to the DP leanrt
2827         # TEP
2828         #
2829         rep_2 = VppGbpEndpoint(self, vx_tun_l3,
2830                                epg_220, None,
2831                                learnt[0]['ip'], "11.0.0.101",
2832                                learnt[0]['ip6'], "3001::101",
2833                                ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
2834                                self.pg2.local_ip4,
2835                                self.pg2.remote_hosts[1].ip4,
2836                                mac=None)
2837         rep_2.add_vpp_config()
2838
2839         #
2840         # Add a route to the learned EP's v4 subnet
2841         #  packets should be send on the v4/v6 uu=fwd interface resp.
2842         #
2843         se_10_1_24 = VppGbpSubnet(
2844             self, rd1, "10.0.1.0", 24,
2845             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_TRANSPORT)
2846         se_10_1_24.add_vpp_config()
2847
2848         self.logger.info(self.vapi.cli("show gbp endpoint"))
2849
2850         ips = ["10.0.0.88", learnt[0]['ip']]
2851         for ip in ips:
2852             p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2853                  IP(dst=ip, src=ep.ip4.address) /
2854                  UDP(sport=1234, dport=1234) /
2855                  Raw('\xa5' * 100))
2856
2857             rxs = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg2)
2858
2859             for rx in rxs:
2860                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2861                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[2].ip4)
2862                 self.assertEqual(rx[UDP].dport, 48879)
2863                 # the UDP source port is a random value for hashing
2864                 self.assertEqual(rx[VXLAN].gpid, 441)
2865                 self.assertEqual(rx[VXLAN].vni, 101)
2866                 self.assertTrue(rx[VXLAN].flags.G)
2867                 self.assertTrue(rx[VXLAN].flags.Instance)
2868                 self.assertTrue(rx[VXLAN].gpflags.A)
2869                 self.assertFalse(rx[VXLAN].gpflags.D)
2870
2871                 inner = rx[VXLAN].payload
2872
2873                 self.assertEqual(inner[Ether].src, routed_src_mac)
2874                 self.assertEqual(inner[Ether].dst, routed_dst_mac)
2875                 self.assertEqual(inner[IP].src, ep.ip4.address)
2876                 self.assertEqual(inner[IP].dst, ip)
2877
2878         #
2879         # remove the API remote EPs, only API sourced is gone, the DP
2880         # learnt one remains
2881         #
2882         rep_88.remove_vpp_config()
2883         rep_2.remove_vpp_config()
2884
2885         self.assertTrue(find_gbp_endpoint(self, ip=rep_2.ip4.address))
2886
2887         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2888              IP(src=ep.ip4.address, dst=rep_2.ip4.address) /
2889              UDP(sport=1234, dport=1234) /
2890              Raw('\xa5' * 100))
2891         rxs = self.send_and_expect(self.pg0, [p], self.pg2)
2892
2893         self.assertFalse(find_gbp_endpoint(self, ip=rep_88.ip4.address))
2894
2895         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2896              IP(src=ep.ip4.address, dst=rep_88.ip4.address) /
2897              UDP(sport=1234, dport=1234) /
2898              Raw('\xa5' * 100))
2899         rxs = self.send_and_expect(self.pg0, [p], self.pg4)
2900
2901         #
2902         # to appease the testcase we cannot have the registered EP still
2903         # present (because it's DP learnt) when the TC ends so wait until
2904         # it is removed
2905         #
2906         self.wait_for_ep_timeout(ip=rep_88.ip4.address)
2907         self.wait_for_ep_timeout(ip=rep_2.ip4.address)
2908
2909         #
2910         # Same as above, learn a remote EP via CP and DP
2911         # this time remove the DP one first. expect the CP data to remain
2912         #
2913         rep_3 = VppGbpEndpoint(self, vx_tun_l3,
2914                                epg_220, None,
2915                                "10.0.1.4", "11.0.0.103",
2916                                "2001::10:3", "3001::103",
2917                                ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
2918                                self.pg2.local_ip4,
2919                                self.pg2.remote_hosts[1].ip4,
2920                                mac=None)
2921         rep_3.add_vpp_config()
2922
2923         p = (Ether(src=self.pg2.remote_mac,
2924                    dst=self.pg2.local_mac) /
2925              IP(src=self.pg2.remote_hosts[2].ip4,
2926                 dst=self.pg2.local_ip4) /
2927              UDP(sport=1234, dport=48879) /
2928              VXLAN(vni=101, gpid=441, flags=0x88) /
2929              Ether(src=l['mac'], dst="00:00:00:11:11:11") /
2930              IP(src="10.0.1.4", dst=ep.ip4.address) /
2931              UDP(sport=1234, dport=1234) /
2932              Raw('\xa5' * 100))
2933         rxs = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
2934
2935         self.assertTrue(find_gbp_endpoint(self,
2936                                           vx_tun_l3._sw_if_index,
2937                                           ip=rep_3.ip4.address,
2938                                           tep=[self.pg2.local_ip4,
2939                                                self.pg2.remote_hosts[2].ip4]))
2940
2941         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2942              IP(dst="10.0.1.4", src=ep.ip4.address) /
2943              UDP(sport=1234, dport=1234) /
2944              Raw('\xa5' * 100))
2945         rxs = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg2)
2946
2947         # host 2 is the DP learned TEP
2948         for rx in rxs:
2949             self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2950             self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[2].ip4)
2951
2952         self.wait_for_ep_timeout(ip=rep_3.ip4.address,
2953                                  tep=[self.pg2.local_ip4,
2954                                       self.pg2.remote_hosts[2].ip4])
2955
2956         rxs = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg2)
2957
2958         # host 1 is the CP learned TEP
2959         for rx in rxs:
2960             self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2961             self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
2962
2963         #
2964         # shutdown with learnt endpoint present
2965         #
2966         p = (Ether(src=self.pg2.remote_mac,
2967                    dst=self.pg2.local_mac) /
2968              IP(src=self.pg2.remote_hosts[1].ip4,
2969                 dst=self.pg2.local_ip4) /
2970              UDP(sport=1234, dport=48879) /
2971              VXLAN(vni=101, gpid=441, flags=0x88) /
2972              Ether(src=l['mac'], dst="00:00:00:11:11:11") /
2973              IP(src=learnt[1]['ip'], dst=ep.ip4.address) /
2974              UDP(sport=1234, dport=1234) /
2975              Raw('\xa5' * 100))
2976
2977         rx = self.send_and_expect(self.pg2, [p], self.pg0)
2978
2979         # endpoint learnt via the parent GBP-vxlan interface
2980         self.assertTrue(find_gbp_endpoint(self,
2981                                           vx_tun_l3._sw_if_index,
2982                                           ip=l['ip']))
2983
2984         #
2985         # TODO
2986         # remote endpoint becomes local
2987         #
2988         self.pg2.unconfig_ip4()
2989         self.pg3.unconfig_ip4()
2990         self.pg4.unconfig_ip4()
2991
2992     def test_gbp_redirect(self):
2993         """ GBP Endpoint Redirect """
2994
2995         self.vapi.cli("set logging class gbp level debug")
2996
2997         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
2998         routed_dst_mac = "00:0c:0c:0c:0c:0c"
2999         routed_src_mac = "00:22:bd:f8:19:ff"
3000
3001         learnt = [{'mac': '00:00:11:11:11:02',
3002                    'ip': '10.0.1.2',
3003                    'ip6': '2001:10::2'},
3004                   {'mac': '00:00:11:11:11:03',
3005                    'ip': '10.0.1.3',
3006                    'ip6': '2001:10::3'}]
3007
3008         #
3009         # IP tables
3010         #
3011         t4 = VppIpTable(self, 1)
3012         t4.add_vpp_config()
3013         t6 = VppIpTable(self, 1, True)
3014         t6.add_vpp_config()
3015
3016         rd1 = VppGbpRouteDomain(self, 2, 402, t4, t6)
3017         rd1.add_vpp_config()
3018
3019         self.loop0.set_mac(self.router_mac)
3020
3021         #
3022         # Bind the BVI to the RD
3023         #
3024         VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
3025         VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
3026
3027         #
3028         # Pg7 hosts a BD's UU-fwd
3029         #
3030         self.pg7.config_ip4()
3031         self.pg7.resolve_arp()
3032
3033         #
3034         # a GBP bridge domains for the EPs
3035         #
3036         bd1 = VppBridgeDomain(self, 1)
3037         bd1.add_vpp_config()
3038         gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0)
3039         gbd1.add_vpp_config()
3040
3041         bd2 = VppBridgeDomain(self, 2)
3042         bd2.add_vpp_config()
3043         gbd2 = VppGbpBridgeDomain(self, bd2, rd1, self.loop1)
3044         gbd2.add_vpp_config()
3045
3046         # ... and has a /32 and /128 applied
3047         ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
3048         ip4_addr.add_vpp_config()
3049         ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128", 128)
3050         ip6_addr.add_vpp_config()
3051         ip4_addr = VppIpInterfaceAddress(self, gbd2.bvi, "10.0.1.128", 32)
3052         ip4_addr.add_vpp_config()
3053         ip6_addr = VppIpInterfaceAddress(self, gbd2.bvi, "2001:11::128", 128)
3054         ip6_addr.add_vpp_config()
3055
3056         #
3057         # The Endpoint-groups in which we are learning endpoints
3058         #
3059         epg_220 = VppGbpEndpointGroup(self, 220, 440, rd1, gbd1,
3060                                       None, gbd1.bvi,
3061                                       "10.0.0.128",
3062                                       "2001:10::128",
3063                                       VppGbpEndpointRetention(2))
3064         epg_220.add_vpp_config()
3065         epg_221 = VppGbpEndpointGroup(self, 221, 441, rd1, gbd2,
3066                                       None, gbd2.bvi,
3067                                       "10.0.1.128",
3068                                       "2001:11::128",
3069                                       VppGbpEndpointRetention(2))
3070         epg_221.add_vpp_config()
3071         epg_222 = VppGbpEndpointGroup(self, 222, 442, rd1, gbd1,
3072                                       None, gbd1.bvi,
3073                                       "10.0.2.128",
3074                                       "2001:12::128",
3075                                       VppGbpEndpointRetention(2))
3076         epg_222.add_vpp_config()
3077
3078         #
3079         # a GBP bridge domains for the SEPs
3080         #
3081         bd_uu1 = VppVxlanGbpTunnel(self, self.pg7.local_ip4,
3082                                    self.pg7.remote_ip4, 116)
3083         bd_uu1.add_vpp_config()
3084         bd_uu2 = VppVxlanGbpTunnel(self, self.pg7.local_ip4,
3085                                    self.pg7.remote_ip4, 117)
3086         bd_uu2.add_vpp_config()
3087
3088         bd3 = VppBridgeDomain(self, 3)
3089         bd3.add_vpp_config()
3090         gbd3 = VppGbpBridgeDomain(self, bd3, rd1, self.loop2,
3091                                   bd_uu1, learn=False)
3092         gbd3.add_vpp_config()
3093         bd4 = VppBridgeDomain(self, 4)
3094         bd4.add_vpp_config()
3095         gbd4 = VppGbpBridgeDomain(self, bd4, rd1, self.loop3,
3096                                   bd_uu2, learn=False)
3097         gbd4.add_vpp_config()
3098
3099         #
3100         # EPGs in which the service endpoints exist
3101         #
3102         epg_320 = VppGbpEndpointGroup(self, 320, 550, rd1, gbd3,
3103                                       None, gbd1.bvi,
3104                                       "12.0.0.128",
3105                                       "4001:10::128",
3106                                       VppGbpEndpointRetention(2))
3107         epg_320.add_vpp_config()
3108         epg_321 = VppGbpEndpointGroup(self, 321, 551, rd1, gbd4,
3109                                       None, gbd2.bvi,
3110                                       "12.0.1.128",
3111                                       "4001:11::128",
3112                                       VppGbpEndpointRetention(2))
3113         epg_321.add_vpp_config()
3114
3115         #
3116         # three local endpoints
3117         #
3118         ep1 = VppGbpEndpoint(self, self.pg0,
3119                              epg_220, None,
3120                              "10.0.0.1", "11.0.0.1",
3121                              "2001:10::1", "3001:10::1")
3122         ep1.add_vpp_config()
3123         ep2 = VppGbpEndpoint(self, self.pg1,
3124                              epg_221, None,
3125                              "10.0.1.1", "11.0.1.1",
3126                              "2001:11::1", "3001:11::1")
3127         ep2.add_vpp_config()
3128         ep3 = VppGbpEndpoint(self, self.pg2,
3129                              epg_222, None,
3130                              "10.0.2.2", "11.0.2.2",
3131                              "2001:12::1", "3001:12::1")
3132         ep3.add_vpp_config()
3133
3134         #
3135         # service endpoints
3136         #
3137         sep1 = VppGbpEndpoint(self, self.pg3,
3138                               epg_320, None,
3139                               "12.0.0.1", "13.0.0.1",
3140                               "4001:10::1", "5001:10::1")
3141         sep1.add_vpp_config()
3142         sep2 = VppGbpEndpoint(self, self.pg4,
3143                               epg_320, None,
3144                               "12.0.0.2", "13.0.0.2",
3145                               "4001:10::2", "5001:10::2")
3146         sep2.add_vpp_config()
3147         sep3 = VppGbpEndpoint(self, self.pg5,
3148                               epg_321, None,
3149                               "12.0.1.1", "13.0.1.1",
3150                               "4001:11::1", "5001:11::1")
3151         sep3.add_vpp_config()
3152         # this EP is not installed immediately
3153         sep4 = VppGbpEndpoint(self, self.pg6,
3154                               epg_321, None,
3155                               "12.0.1.2", "13.0.1.2",
3156                               "4001:11::2", "5001:11::2")
3157
3158         #
3159         # an L2 switch packet between local EPs in different EPGs
3160         #  different dest ports on each so the are LB hashed differently
3161         #
3162         p4 = [(Ether(src=ep1.mac, dst=ep3.mac) /
3163                IP(src=ep1.ip4.address, dst=ep3.ip4.address) /
3164                UDP(sport=1234, dport=1234) /
3165                Raw('\xa5' * 100)),
3166               (Ether(src=ep3.mac, dst=ep1.mac) /
3167                IP(src=ep3.ip4.address, dst=ep1.ip4.address) /
3168                UDP(sport=1234, dport=1234) /
3169                Raw('\xa5' * 100))]
3170         p6 = [(Ether(src=ep1.mac, dst=ep3.mac) /
3171                IPv6(src=ep1.ip6.address, dst=ep3.ip6.address) /
3172                UDP(sport=1234, dport=1234) /
3173                Raw('\xa5' * 100)),
3174               (Ether(src=ep3.mac, dst=ep1.mac) /
3175                IPv6(src=ep3.ip6.address, dst=ep1.ip6.address) /
3176                UDP(sport=1234, dport=1230) /
3177                Raw('\xa5' * 100))]
3178
3179         # should be dropped since no contract yet
3180         self.send_and_assert_no_replies(self.pg0, [p4[0]])
3181         self.send_and_assert_no_replies(self.pg0, [p6[0]])
3182
3183         #
3184         # Add a contract with a rule to load-balance redirect via SEP1 and SEP2
3185         # one of the next-hops is via an EP that is not known
3186         #
3187         acl = VppGbpAcl(self)
3188         rule4 = acl.create_rule(permit_deny=1, proto=17)
3189         rule6 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
3190         acl_index = acl.add_vpp_config([rule4, rule6])
3191
3192         #
3193         # test the src-ip hash mode
3194         #
3195         c1 = VppGbpContract(
3196             self, 402, epg_220.sclass, epg_222.sclass, acl_index,
3197             [VppGbpContractRule(
3198                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3199                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3200                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3201                                        sep1.ip4, sep1.epg.rd),
3202                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3203                                        sep2.ip4, sep2.epg.rd)]),
3204                 VppGbpContractRule(
3205                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3206                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3207                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3208                                            sep3.ip6, sep3.epg.rd),
3209                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3210                                            sep4.ip6, sep4.epg.rd)])],
3211             [ETH_P_IP, ETH_P_IPV6])
3212         c1.add_vpp_config()
3213
3214         c2 = VppGbpContract(
3215             self, 402, epg_222.sclass, epg_220.sclass, acl_index,
3216             [VppGbpContractRule(
3217                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3218                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3219                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3220                                        sep1.ip4, sep1.epg.rd),
3221                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3222                                        sep2.ip4, sep2.epg.rd)]),
3223                 VppGbpContractRule(
3224                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3225                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3226                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3227                                            sep3.ip6, sep3.epg.rd),
3228                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3229                                            sep4.ip6, sep4.epg.rd)])],
3230             [ETH_P_IP, ETH_P_IPV6])
3231         c2.add_vpp_config()
3232
3233         #
3234         # send again with the contract preset, now packets arrive
3235         # at SEP1 or SEP2 depending on the hashing
3236         #
3237         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
3238
3239         for rx in rxs:
3240             self.assertEqual(rx[Ether].src, routed_src_mac)
3241             self.assertEqual(rx[Ether].dst, sep1.mac)
3242             self.assertEqual(rx[IP].src, ep1.ip4.address)
3243             self.assertEqual(rx[IP].dst, ep3.ip4.address)
3244
3245         rxs = self.send_and_expect(self.pg2, p4[1] * 17, sep2.itf)
3246
3247         for rx in rxs:
3248             self.assertEqual(rx[Ether].src, routed_src_mac)
3249             self.assertEqual(rx[Ether].dst, sep2.mac)
3250             self.assertEqual(rx[IP].src, ep3.ip4.address)
3251             self.assertEqual(rx[IP].dst, ep1.ip4.address)
3252
3253         rxs = self.send_and_expect(self.pg0, p6[0] * 17, self.pg7)
3254
3255         for rx in rxs:
3256             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
3257             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
3258             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
3259             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
3260             self.assertEqual(rx[VXLAN].vni, 117)
3261             self.assertTrue(rx[VXLAN].flags.G)
3262             self.assertTrue(rx[VXLAN].flags.Instance)
3263             # redirect policy has been applied
3264             self.assertTrue(rx[VXLAN].gpflags.A)
3265             self.assertFalse(rx[VXLAN].gpflags.D)
3266
3267             inner = rx[VXLAN].payload
3268
3269             self.assertEqual(inner[Ether].src, routed_src_mac)
3270             self.assertEqual(inner[Ether].dst, sep4.mac)
3271             self.assertEqual(inner[IPv6].src, ep1.ip6.address)
3272             self.assertEqual(inner[IPv6].dst, ep3.ip6.address)
3273
3274         rxs = self.send_and_expect(self.pg2, p6[1] * 17, sep3.itf)
3275
3276         for rx in rxs:
3277             self.assertEqual(rx[Ether].src, routed_src_mac)
3278             self.assertEqual(rx[Ether].dst, sep3.mac)
3279             self.assertEqual(rx[IPv6].src, ep3.ip6.address)
3280             self.assertEqual(rx[IPv6].dst, ep1.ip6.address)
3281
3282         #
3283         # programme the unknown EP
3284         #
3285         sep4.add_vpp_config()
3286
3287         rxs = self.send_and_expect(self.pg0, p6[0] * 17, sep4.itf)
3288
3289         for rx in rxs:
3290             self.assertEqual(rx[Ether].src, routed_src_mac)
3291             self.assertEqual(rx[Ether].dst, sep4.mac)
3292             self.assertEqual(rx[IPv6].src, ep1.ip6.address)
3293             self.assertEqual(rx[IPv6].dst, ep3.ip6.address)
3294
3295         #
3296         # and revert back to unprogrammed
3297         #
3298         sep4.remove_vpp_config()
3299
3300         rxs = self.send_and_expect(self.pg0, p6[0] * 17, self.pg7)
3301
3302         for rx in rxs:
3303             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
3304             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
3305             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
3306             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
3307             self.assertEqual(rx[VXLAN].vni, 117)
3308             self.assertTrue(rx[VXLAN].flags.G)
3309             self.assertTrue(rx[VXLAN].flags.Instance)
3310             # redirect policy has been applied
3311             self.assertTrue(rx[VXLAN].gpflags.A)
3312             self.assertFalse(rx[VXLAN].gpflags.D)
3313
3314             inner = rx[VXLAN].payload
3315
3316             self.assertEqual(inner[Ether].src, routed_src_mac)
3317             self.assertEqual(inner[Ether].dst, sep4.mac)
3318             self.assertEqual(inner[IPv6].src, ep1.ip6.address)
3319             self.assertEqual(inner[IPv6].dst, ep3.ip6.address)
3320
3321         c1.remove_vpp_config()
3322         c2.remove_vpp_config()
3323
3324         #
3325         # test the symmetric hash mode
3326         #
3327         c1 = VppGbpContract(
3328             self, 402, epg_220.sclass, epg_222.sclass, acl_index,
3329             [VppGbpContractRule(
3330                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3331                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3332                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3333                                        sep1.ip4, sep1.epg.rd),
3334                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3335                                        sep2.ip4, sep2.epg.rd)]),
3336                 VppGbpContractRule(
3337                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3338                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3339                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3340                                            sep3.ip6, sep3.epg.rd),
3341                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3342                                            sep4.ip6, sep4.epg.rd)])],
3343             [ETH_P_IP, ETH_P_IPV6])
3344         c1.add_vpp_config()
3345
3346         c2 = VppGbpContract(
3347             self, 402, epg_222.sclass, epg_220.sclass, acl_index,
3348             [VppGbpContractRule(
3349                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3350                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3351                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3352                                        sep1.ip4, sep1.epg.rd),
3353                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3354                                        sep2.ip4, sep2.epg.rd)]),
3355                 VppGbpContractRule(
3356                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3357                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3358                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3359                                            sep3.ip6, sep3.epg.rd),
3360                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3361                                            sep4.ip6, sep4.epg.rd)])],
3362             [ETH_P_IP, ETH_P_IPV6])
3363         c2.add_vpp_config()
3364
3365         #
3366         # send again with the contract preset, now packets arrive
3367         # at SEP1 for both directions
3368         #
3369         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
3370
3371         for rx in rxs:
3372             self.assertEqual(rx[Ether].src, routed_src_mac)
3373             self.assertEqual(rx[Ether].dst, sep1.mac)
3374             self.assertEqual(rx[IP].src, ep1.ip4.address)
3375             self.assertEqual(rx[IP].dst, ep3.ip4.address)
3376
3377         rxs = self.send_and_expect(self.pg2, p4[1] * 17, sep1.itf)
3378
3379         for rx in rxs:
3380             self.assertEqual(rx[Ether].src, routed_src_mac)
3381             self.assertEqual(rx[Ether].dst, sep1.mac)
3382             self.assertEqual(rx[IP].src, ep3.ip4.address)
3383             self.assertEqual(rx[IP].dst, ep1.ip4.address)
3384
3385         #
3386         # programme the unknown EP for the L3 tests
3387         #
3388         sep4.add_vpp_config()
3389
3390         #
3391         # an L3 switch packet between local EPs in different EPGs
3392         #  different dest ports on each so the are LB hashed differently
3393         #
3394         p4 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) /
3395                IP(src=ep1.ip4.address, dst=ep2.ip4.address) /
3396                UDP(sport=1234, dport=1234) /
3397                Raw('\xa5' * 100)),
3398               (Ether(src=ep2.mac, dst=str(self.router_mac)) /
3399                IP(src=ep2.ip4.address, dst=ep1.ip4.address) /
3400                UDP(sport=1234, dport=1234) /
3401                Raw('\xa5' * 100))]
3402         p6 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) /
3403                IPv6(src=ep1.ip6.address, dst=ep2.ip6.address) /
3404                UDP(sport=1234, dport=1234) /
3405                Raw('\xa5' * 100)),
3406               (Ether(src=ep2.mac, dst=str(self.router_mac)) /
3407                IPv6(src=ep2.ip6.address, dst=ep1.ip6.address) /
3408                UDP(sport=1234, dport=1234) /
3409                Raw('\xa5' * 100))]
3410
3411         c3 = VppGbpContract(
3412             self, 402, epg_220.sclass, epg_221.sclass, acl_index,
3413             [VppGbpContractRule(
3414                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3415                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3416                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3417                                        sep1.ip4, sep1.epg.rd),
3418                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3419                                        sep2.ip4, sep2.epg.rd)]),
3420                 VppGbpContractRule(
3421                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3422                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3423                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3424                                            sep3.ip6, sep3.epg.rd),
3425                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3426                                            sep4.ip6, sep4.epg.rd)])],
3427             [ETH_P_IP, ETH_P_IPV6])
3428         c3.add_vpp_config()
3429
3430         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
3431
3432         for rx in rxs:
3433             self.assertEqual(rx[Ether].src, routed_src_mac)
3434             self.assertEqual(rx[Ether].dst, sep1.mac)
3435             self.assertEqual(rx[IP].src, ep1.ip4.address)
3436             self.assertEqual(rx[IP].dst, ep2.ip4.address)
3437
3438         #
3439         # learn a remote EP in EPG 221
3440         #
3441         vx_tun_l3 = VppGbpVxlanTunnel(
3442             self, 444, rd1.rd_id,
3443             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3,
3444             self.pg2.local_ip4)
3445         vx_tun_l3.add_vpp_config()
3446
3447         c4 = VppGbpContract(
3448             self, 402, epg_221.sclass, epg_220.sclass, acl_index,
3449             [VppGbpContractRule(
3450                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3451                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3452                 []),
3453                 VppGbpContractRule(
3454                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3455                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3456                     [])],
3457             [ETH_P_IP, ETH_P_IPV6])
3458         c4.add_vpp_config()
3459
3460         p = (Ether(src=self.pg7.remote_mac,
3461                    dst=self.pg7.local_mac) /
3462              IP(src=self.pg7.remote_ip4,
3463                 dst=self.pg7.local_ip4) /
3464              UDP(sport=1234, dport=48879) /
3465              VXLAN(vni=444, gpid=441, flags=0x88) /
3466              Ether(src="00:22:22:22:22:33", dst=str(self.router_mac)) /
3467              IP(src="10.0.0.88", dst=ep1.ip4.address) /
3468              UDP(sport=1234, dport=1234) /
3469              Raw('\xa5' * 100))
3470
3471         rx = self.send_and_expect(self.pg7, [p], self.pg0)
3472
3473         # endpoint learnt via the parent GBP-vxlan interface
3474         self.assertTrue(find_gbp_endpoint(self,
3475                                           vx_tun_l3._sw_if_index,
3476                                           ip="10.0.0.88"))
3477
3478         p = (Ether(src=self.pg7.remote_mac,
3479                    dst=self.pg7.local_mac) /
3480              IP(src=self.pg7.remote_ip4,
3481                 dst=self.pg7.local_ip4) /
3482              UDP(sport=1234, dport=48879) /
3483              VXLAN(vni=444, gpid=441, flags=0x88) /
3484              Ether(src="00:22:22:22:22:33", dst=str(self.router_mac)) /
3485              IPv6(src="2001:10::88", dst=ep1.ip6.address) /
3486              UDP(sport=1234, dport=1234) /
3487              Raw('\xa5' * 100))
3488
3489         rx = self.send_and_expect(self.pg7, [p], self.pg0)
3490
3491         # endpoint learnt via the parent GBP-vxlan interface
3492         self.assertTrue(find_gbp_endpoint(self,
3493                                           vx_tun_l3._sw_if_index,
3494                                           ip="2001:10::88"))
3495
3496         #
3497         # L3 switch from local to remote EP
3498         #
3499         p4 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) /
3500                IP(src=ep1.ip4.address, dst="10.0.0.88") /
3501                UDP(sport=1234, dport=1234) /
3502                Raw('\xa5' * 100))]
3503         p6 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) /
3504                IPv6(src=ep1.ip6.address, dst="2001:10::88") /
3505                UDP(sport=1234, dport=1234) /
3506                Raw('\xa5' * 100))]
3507
3508         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
3509
3510         for rx in rxs:
3511             self.assertEqual(rx[Ether].src, routed_src_mac)
3512             self.assertEqual(rx[Ether].dst, sep1.mac)
3513             self.assertEqual(rx[IP].src, ep1.ip4.address)
3514             self.assertEqual(rx[IP].dst, "10.0.0.88")
3515
3516         rxs = self.send_and_expect(self.pg0, p6[0] * 17, sep4.itf)
3517
3518         for rx in rxs:
3519             self.assertEqual(rx[Ether].src, routed_src_mac)
3520             self.assertEqual(rx[Ether].dst, sep4.mac)
3521             self.assertEqual(rx[IPv6].src, ep1.ip6.address)
3522             self.assertEqual(rx[IPv6].dst, "2001:10::88")
3523
3524         #
3525         # test the dst-ip hash mode
3526         #
3527         c5 = VppGbpContract(
3528             self, 402, epg_220.sclass, epg_221.sclass, acl_index,
3529             [VppGbpContractRule(
3530                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3531                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
3532                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3533                                        sep1.ip4, sep1.epg.rd),
3534                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3535                                        sep2.ip4, sep2.epg.rd)]),
3536                 VppGbpContractRule(
3537                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3538                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
3539                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3540                                            sep3.ip6, sep3.epg.rd),
3541                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3542                                            sep4.ip6, sep4.epg.rd)])],
3543             [ETH_P_IP, ETH_P_IPV6])
3544         c5.add_vpp_config()
3545
3546         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
3547
3548         for rx in rxs:
3549             self.assertEqual(rx[Ether].src, routed_src_mac)
3550             self.assertEqual(rx[Ether].dst, sep1.mac)
3551             self.assertEqual(rx[IP].src, ep1.ip4.address)
3552             self.assertEqual(rx[IP].dst, "10.0.0.88")
3553
3554         rxs = self.send_and_expect(self.pg0, p6[0] * 17, sep3.itf)
3555
3556         for rx in rxs:
3557             self.assertEqual(rx[Ether].src, routed_src_mac)
3558             self.assertEqual(rx[Ether].dst, sep3.mac)
3559             self.assertEqual(rx[IPv6].src, ep1.ip6.address)
3560             self.assertEqual(rx[IPv6].dst, "2001:10::88")
3561
3562         #
3563         # cleanup
3564         #
3565         self.pg7.unconfig_ip4()
3566
3567     def test_gbp_l3_out(self):
3568         """ GBP L3 Out """
3569
3570         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
3571         self.vapi.cli("set logging class gbp level debug")
3572
3573         routed_dst_mac = "00:0c:0c:0c:0c:0c"
3574         routed_src_mac = "00:22:bd:f8:19:ff"
3575
3576         #
3577         # IP tables
3578         #
3579         t4 = VppIpTable(self, 1)
3580         t4.add_vpp_config()
3581         t6 = VppIpTable(self, 1, True)
3582         t6.add_vpp_config()
3583
3584         rd1 = VppGbpRouteDomain(self, 2, 55, t4, t6)
3585         rd1.add_vpp_config()
3586
3587         self.loop0.set_mac(self.router_mac)
3588
3589         #
3590         # Bind the BVI to the RD
3591         #
3592         VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
3593         VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
3594
3595         #
3596         # Pg7 hosts a BD's BUM
3597         # Pg1 some other l3 interface
3598         #
3599         self.pg7.config_ip4()
3600         self.pg7.resolve_arp()
3601
3602         #
3603         # a multicast vxlan-gbp tunnel for broadcast in the BD
3604         #
3605         tun_bm = VppVxlanGbpTunnel(self, self.pg7.local_ip4,
3606                                    "239.1.1.1", 88,
3607                                    mcast_itf=self.pg7)
3608         tun_bm.add_vpp_config()
3609
3610         #
3611         # a GBP external bridge domains for the EPs
3612         #
3613         bd1 = VppBridgeDomain(self, 1)
3614         bd1.add_vpp_config()
3615         gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0, None, tun_bm)
3616         gbd1.add_vpp_config()
3617
3618         #
3619         # The Endpoint-groups in which the external endpoints exist
3620         #
3621         epg_220 = VppGbpEndpointGroup(self, 220, 113, rd1, gbd1,
3622                                       None, gbd1.bvi,
3623                                       "10.0.0.128",
3624                                       "2001:10::128",
3625                                       VppGbpEndpointRetention(2))
3626         epg_220.add_vpp_config()
3627
3628         # the BVIs have the subnets applied ...
3629         ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 24)
3630         ip4_addr.add_vpp_config()
3631         ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128", 64)
3632         ip6_addr.add_vpp_config()
3633
3634         # ... which are L3-out subnets
3635         l3o_1 = VppGbpSubnet(
3636             self, rd1, "10.0.0.0", 24,
3637             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3638             sclass=113)
3639         l3o_1.add_vpp_config()
3640
3641         #
3642         # an external interface attached to the outside world and the
3643         # external BD
3644         #
3645         VppL2Vtr(self, self.vlan_100, L2_VTR_OP.L2_POP_1).add_vpp_config()
3646         VppL2Vtr(self, self.vlan_101, L2_VTR_OP.L2_POP_1).add_vpp_config()
3647         # vlan_102 is not poped
3648
3649         ext_itf = VppGbpExtItf(self, self.loop0, bd1, rd1)
3650         ext_itf.add_vpp_config()
3651
3652         #
3653         # an unicast vxlan-gbp for inter-RD traffic
3654         #
3655         vx_tun_l3 = VppGbpVxlanTunnel(
3656             self, 444, rd1.rd_id,
3657             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3,
3658             self.pg2.local_ip4)
3659         vx_tun_l3.add_vpp_config()
3660
3661         #
3662         # External Endpoints
3663         #
3664         eep1 = VppGbpEndpoint(self, self.vlan_100,
3665                               epg_220, None,
3666                               "10.0.0.1", "11.0.0.1",
3667                               "2001:10::1", "3001::1",
3668                               ep_flags.GBP_API_ENDPOINT_FLAG_EXTERNAL)
3669         eep1.add_vpp_config()
3670         eep2 = VppGbpEndpoint(self, self.vlan_101,
3671                               epg_220, None,
3672                               "10.0.0.2", "11.0.0.2",
3673                               "2001:10::2", "3001::2",
3674                               ep_flags.GBP_API_ENDPOINT_FLAG_EXTERNAL)
3675         eep2.add_vpp_config()
3676         eep3 = VppGbpEndpoint(self, self.vlan_102,
3677                               epg_220, None,
3678                               "10.0.0.3", "11.0.0.3",
3679                               "2001:10::3", "3001::3",
3680                               ep_flags.GBP_API_ENDPOINT_FLAG_EXTERNAL)
3681         eep3.add_vpp_config()
3682
3683         #
3684         # A remote external endpoint
3685         #
3686         rep = VppGbpEndpoint(self, vx_tun_l3,
3687                              epg_220, None,
3688                              "10.0.0.101", "11.0.0.101",
3689                              "2001:10::101", "3001::101",
3690                              ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
3691                              self.pg7.local_ip4,
3692                              self.pg7.remote_ip4,
3693                              mac=None)
3694         rep.add_vpp_config()
3695
3696         #
3697         # EP1 impersonating EP3 is dropped
3698         #
3699         p = (Ether(src=eep1.mac, dst="ff:ff:ff:ff:ff:ff") /
3700              Dot1Q(vlan=100) /
3701              ARP(op="who-has",
3702                  psrc="10.0.0.3", pdst="10.0.0.128",
3703                  hwsrc=eep1.mac, hwdst="ff:ff:ff:ff:ff:ff"))
3704         self.send_and_assert_no_replies(self.pg0, p)
3705
3706         #
3707         # ARP packet from External EPs are accepted and replied to
3708         #
3709         p_arp = (Ether(src=eep1.mac, dst="ff:ff:ff:ff:ff:ff") /
3710                  Dot1Q(vlan=100) /
3711                  ARP(op="who-has",
3712                      psrc=eep1.ip4.address, pdst="10.0.0.128",
3713                      hwsrc=eep1.mac, hwdst="ff:ff:ff:ff:ff:ff"))
3714         rxs = self.send_and_expect(self.pg0, p_arp * 1, self.pg0)
3715
3716         #
3717         # ARP packet from host in remote subnet are accepted and replied to
3718         #
3719         p_arp = (Ether(src=eep3.mac, dst="ff:ff:ff:ff:ff:ff") /
3720                  Dot1Q(vlan=102) /
3721                  ARP(op="who-has",
3722                      psrc=eep3.ip4.address, pdst="10.0.0.128",
3723                      hwsrc=eep3.mac, hwdst="ff:ff:ff:ff:ff:ff"))
3724         rxs = self.send_and_expect(self.pg0, p_arp * 1, self.pg0)
3725
3726         #
3727         # packets destined to unknown addresses in the BVI's subnet
3728         # are ARP'd for
3729         #
3730         p4 = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
3731               Dot1Q(vlan=100) /
3732               IP(src="10.0.0.1", dst="10.0.0.88") /
3733               UDP(sport=1234, dport=1234) /
3734               Raw('\xa5' * 100))
3735         p6 = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
3736               Dot1Q(vlan=100) /
3737               IPv6(src="2001:10::1", dst="2001:10::88") /
3738               UDP(sport=1234, dport=1234) /
3739               Raw('\xa5' * 100))
3740
3741         rxs = self.send_and_expect(self.pg0, p4 * 1, self.pg7)
3742
3743         for rx in rxs:
3744             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
3745             # self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
3746             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
3747             self.assertEqual(rx[IP].dst, "239.1.1.1")
3748             self.assertEqual(rx[VXLAN].vni, 88)
3749             self.assertTrue(rx[VXLAN].flags.G)
3750             self.assertTrue(rx[VXLAN].flags.Instance)
3751             # policy was applied to the original IP packet
3752             self.assertEqual(rx[VXLAN].gpid, 113)
3753             self.assertTrue(rx[VXLAN].gpflags.A)
3754             self.assertFalse(rx[VXLAN].gpflags.D)
3755
3756             inner = rx[VXLAN].payload
3757
3758             self.assertTrue(inner.haslayer(ARP))
3759
3760         #
3761         # remote to external
3762         #
3763         p = (Ether(src=self.pg7.remote_mac,
3764                    dst=self.pg7.local_mac) /
3765              IP(src=self.pg7.remote_ip4,
3766                 dst=self.pg7.local_ip4) /
3767              UDP(sport=1234, dport=48879) /
3768              VXLAN(vni=444, gpid=113, flags=0x88) /
3769              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
3770              IP(src="10.0.0.101", dst="10.0.0.1") /
3771              UDP(sport=1234, dport=1234) /
3772              Raw('\xa5' * 100))
3773
3774         rxs = self.send_and_expect(self.pg7, p * 1, self.pg0)
3775
3776         #
3777         # local EP pings router
3778         #
3779         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
3780              Dot1Q(vlan=100) /
3781              IP(src=eep1.ip4.address, dst="10.0.0.128") /
3782              ICMP(type='echo-request'))
3783
3784         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
3785
3786         for rx in rxs:
3787             self.assertEqual(rx[Ether].src, str(self.router_mac))
3788             self.assertEqual(rx[Ether].dst, eep1.mac)
3789             self.assertEqual(rx[Dot1Q].vlan, 100)
3790
3791         #
3792         # local EP pings other local EP
3793         #
3794         p = (Ether(src=eep1.mac, dst=eep2.mac) /
3795              Dot1Q(vlan=100) /
3796              IP(src=eep1.ip4.address, dst=eep2.ip4.address) /
3797              ICMP(type='echo-request'))
3798
3799         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
3800
3801         for rx in rxs:
3802             self.assertEqual(rx[Ether].src, eep1.mac)
3803             self.assertEqual(rx[Ether].dst, eep2.mac)
3804             self.assertEqual(rx[Dot1Q].vlan, 101)
3805
3806         #
3807         # local EP pings router w/o vlan tag poped
3808         #
3809         p = (Ether(src=eep3.mac, dst=str(self.router_mac)) /
3810              Dot1Q(vlan=102) /
3811              IP(src=eep3.ip4.address, dst="10.0.0.128") /
3812              ICMP(type='echo-request'))
3813
3814         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
3815
3816         for rx in rxs:
3817             self.assertEqual(rx[Ether].src, str(self.router_mac))
3818             self.assertEqual(rx[Ether].dst, self.vlan_102.remote_mac)
3819
3820         #
3821         # A subnet reachable through the external EP1
3822         #
3823         ip_220 = VppIpRoute(self, "10.220.0.0", 24,
3824                             [VppRoutePath(eep1.ip4.address,
3825                                           eep1.epg.bvi.sw_if_index)],
3826                             table_id=t4.table_id)
3827         ip_220.add_vpp_config()
3828
3829         l3o_220 = VppGbpSubnet(
3830             self, rd1, "10.220.0.0", 24,
3831             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3832             sclass=4220)
3833         l3o_220.add_vpp_config()
3834
3835         #
3836         # A subnet reachable through the external EP2
3837         #
3838         ip_221 = VppIpRoute(self, "10.221.0.0", 24,
3839                             [VppRoutePath(eep2.ip4.address,
3840                                           eep2.epg.bvi.sw_if_index)],
3841                             table_id=t4.table_id)
3842         ip_221.add_vpp_config()
3843
3844         l3o_221 = VppGbpSubnet(
3845             self, rd1, "10.221.0.0", 24,
3846             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3847             sclass=4221)
3848         l3o_221.add_vpp_config()
3849
3850         #
3851         # ping between hosts in remote subnets
3852         #  dropped without a contract
3853         #
3854         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
3855              Dot1Q(vlan=100) /
3856              IP(src="10.220.0.1", dst="10.221.0.1") /
3857              ICMP(type='echo-request'))
3858
3859         self.send_and_assert_no_replies(self.pg0, p * 1)
3860
3861         #
3862         # contract for the external nets to communicate
3863         #
3864         acl = VppGbpAcl(self)
3865         rule4 = acl.create_rule(permit_deny=1, proto=17)
3866         rule6 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
3867         acl_index = acl.add_vpp_config([rule4, rule6])
3868
3869         #
3870         # A contract with the wrong scope is not matched
3871         #
3872         c_44 = VppGbpContract(
3873             self, 44, 4220, 4221, acl_index,
3874             [VppGbpContractRule(
3875                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3876                 []),
3877                 VppGbpContractRule(
3878                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3879                     [])],
3880             [ETH_P_IP, ETH_P_IPV6])
3881         c_44.add_vpp_config()
3882         self.send_and_assert_no_replies(self.pg0, p * 1)
3883
3884         c1 = VppGbpContract(
3885             self, 55, 4220, 4221, acl_index,
3886             [VppGbpContractRule(
3887                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3888                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3889                 []),
3890                 VppGbpContractRule(
3891                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3892                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3893                     [])],
3894             [ETH_P_IP, ETH_P_IPV6])
3895         c1.add_vpp_config()
3896
3897         #
3898         # Contracts allowing ext-net 200 to talk with external EPs
3899         #
3900         c2 = VppGbpContract(
3901             self, 55, 4220, 113, acl_index,
3902             [VppGbpContractRule(
3903                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3904                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3905                 []),
3906                 VppGbpContractRule(
3907                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3908                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3909                     [])],
3910             [ETH_P_IP, ETH_P_IPV6])
3911         c2.add_vpp_config()
3912         c3 = VppGbpContract(
3913             self, 55, 113, 4220, acl_index,
3914             [VppGbpContractRule(
3915                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3916                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3917                 []),
3918                 VppGbpContractRule(
3919                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3920                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3921                     [])],
3922             [ETH_P_IP, ETH_P_IPV6])
3923         c3.add_vpp_config()
3924
3925         #
3926         # ping between hosts in remote subnets
3927         #
3928         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
3929              Dot1Q(vlan=100) /
3930              IP(src="10.220.0.1", dst="10.221.0.1") /
3931              UDP(sport=1234, dport=1234) /
3932              Raw('\xa5' * 100))
3933
3934         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
3935
3936         for rx in rxs:
3937             self.assertEqual(rx[Ether].src, str(self.router_mac))
3938             self.assertEqual(rx[Ether].dst, eep2.mac)
3939             self.assertEqual(rx[Dot1Q].vlan, 101)
3940
3941         # we did not learn these external hosts
3942         self.assertFalse(find_gbp_endpoint(self, ip="10.220.0.1"))
3943         self.assertFalse(find_gbp_endpoint(self, ip="10.221.0.1"))
3944
3945         #
3946         # from remote external EP to local external EP
3947         #
3948         p = (Ether(src=self.pg7.remote_mac,
3949                    dst=self.pg7.local_mac) /
3950              IP(src=self.pg7.remote_ip4,
3951                 dst=self.pg7.local_ip4) /
3952              UDP(sport=1234, dport=48879) /
3953              VXLAN(vni=444, gpid=113, flags=0x88) /
3954              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
3955              IP(src="10.0.0.101", dst="10.220.0.1") /
3956              UDP(sport=1234, dport=1234) /
3957              Raw('\xa5' * 100))
3958
3959         rxs = self.send_and_expect(self.pg7, p * 1, self.pg0)
3960
3961         #
3962         # ping from an external host to the remote external EP
3963         #
3964         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
3965              Dot1Q(vlan=100) /
3966              IP(src="10.220.0.1", dst=rep.ip4.address) /
3967              UDP(sport=1234, dport=1234) /
3968              Raw('\xa5' * 100))
3969
3970         rxs = self.send_and_expect(self.pg0, p * 1, self.pg7)
3971
3972         for rx in rxs:
3973             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
3974             # self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
3975             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
3976             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
3977             self.assertEqual(rx[VXLAN].vni, 444)
3978             self.assertTrue(rx[VXLAN].flags.G)
3979             self.assertTrue(rx[VXLAN].flags.Instance)
3980             # the sclass of the ext-net the packet came from
3981             self.assertEqual(rx[VXLAN].gpid, 4220)
3982             # policy was applied to the original IP packet
3983             self.assertTrue(rx[VXLAN].gpflags.A)
3984             # since it's an external host the reciever should not learn it
3985             self.assertTrue(rx[VXLAN].gpflags.D)
3986             inner = rx[VXLAN].payload
3987             self.assertEqual(inner[IP].src, "10.220.0.1")
3988             self.assertEqual(inner[IP].dst, rep.ip4.address)
3989
3990         #
3991         # An external subnet reachable via the remote external EP
3992         #
3993
3994         #
3995         # first the VXLAN-GBP tunnel over which it is reached
3996         #
3997         vx_tun_r = VppVxlanGbpTunnel(
3998             self, self.pg7.local_ip4,
3999             self.pg7.remote_ip4, 445,
4000             mode=(VppEnum.vl_api_vxlan_gbp_api_tunnel_mode_t.
4001                   VXLAN_GBP_API_TUNNEL_MODE_L3))
4002         vx_tun_r.add_vpp_config()
4003         VppIpInterfaceBind(self, vx_tun_r, t4).add_vpp_config()
4004
4005         self.logger.info(self.vapi.cli("sh vxlan-gbp tunnel"))
4006
4007         #
4008         # then the special adj to resolve through on that tunnel
4009         #
4010         n1 = VppNeighbor(self,
4011                          vx_tun_r.sw_if_index,
4012                          "00:0c:0c:0c:0c:0c",
4013                          self.pg7.remote_ip4)
4014         n1.add_vpp_config()
4015
4016         #
4017         # the route via the adj above
4018         #
4019         ip_222 = VppIpRoute(self, "10.222.0.0", 24,
4020                             [VppRoutePath(self.pg7.remote_ip4,
4021                                           vx_tun_r.sw_if_index)],
4022                             table_id=t4.table_id)
4023         ip_222.add_vpp_config()
4024
4025         l3o_222 = VppGbpSubnet(
4026             self, rd1, "10.222.0.0", 24,
4027             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
4028             sclass=4222)
4029         l3o_222.add_vpp_config()
4030
4031         #
4032         # ping between hosts in local and remote external subnets
4033         #  dropped without a contract
4034         #
4035         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
4036              Dot1Q(vlan=100) /
4037              IP(src="10.220.0.1", dst="10.222.0.1") /
4038              UDP(sport=1234, dport=1234) /
4039              Raw('\xa5' * 100))
4040
4041         rxs = self.send_and_assert_no_replies(self.pg0, p * 1)
4042
4043         #
4044         # Add contracts ext-nets for 220 -> 222
4045         #
4046         c4 = VppGbpContract(
4047             self, 55, 4220, 4222, acl_index,
4048             [VppGbpContractRule(
4049                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4050                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
4051                 []),
4052                 VppGbpContractRule(
4053                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4054                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
4055                     [])],
4056             [ETH_P_IP, ETH_P_IPV6])
4057         c4.add_vpp_config()
4058
4059         #
4060         # ping from host in local to remote external subnets
4061         #
4062         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
4063              Dot1Q(vlan=100) /
4064              IP(src="10.220.0.1", dst="10.222.0.1") /
4065              UDP(sport=1234, dport=1234) /
4066              Raw('\xa5' * 100))
4067
4068         rxs = self.send_and_expect(self.pg0, p * 3, self.pg7)
4069
4070         for rx in rxs:
4071             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
4072             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
4073             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
4074             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
4075             self.assertEqual(rx[VXLAN].vni, 445)
4076             self.assertTrue(rx[VXLAN].flags.G)
4077             self.assertTrue(rx[VXLAN].flags.Instance)
4078             # the sclass of the ext-net the packet came from
4079             self.assertEqual(rx[VXLAN].gpid, 4220)
4080             # policy was applied to the original IP packet
4081             self.assertTrue(rx[VXLAN].gpflags.A)
4082             # since it's an external host the reciever should not learn it
4083             self.assertTrue(rx[VXLAN].gpflags.D)
4084             inner = rx[VXLAN].payload
4085             self.assertEqual(inner[Ether].dst, "00:0c:0c:0c:0c:0c")
4086             self.assertEqual(inner[IP].src, "10.220.0.1")
4087             self.assertEqual(inner[IP].dst, "10.222.0.1")
4088
4089         #
4090         # ping from host in remote to local external subnets
4091         # there's no contract for this, but the A bit is set.
4092         #
4093         p = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) /
4094              IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) /
4095              UDP(sport=1234, dport=48879) /
4096              VXLAN(vni=445, gpid=4222, flags=0x88, gpflags='A') /
4097              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
4098              IP(src="10.222.0.1", dst="10.220.0.1") /
4099              UDP(sport=1234, dport=1234) /
4100              Raw('\xa5' * 100))
4101
4102         rxs = self.send_and_expect(self.pg7, p * 3, self.pg0)
4103         self.assertFalse(find_gbp_endpoint(self, ip="10.222.0.1"))
4104
4105         #
4106         # ping from host in remote to remote external subnets
4107         #   this is dropped by reflection check.
4108         #
4109         p = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) /
4110              IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) /
4111              UDP(sport=1234, dport=48879) /
4112              VXLAN(vni=445, gpid=4222, flags=0x88, gpflags='A') /
4113              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
4114              IP(src="10.222.0.1", dst="10.222.0.2") /
4115              UDP(sport=1234, dport=1234) /
4116              Raw('\xa5' * 100))
4117
4118         rxs = self.send_and_assert_no_replies(self.pg7, p * 3)
4119
4120         #
4121         # cleanup
4122         #
4123         self.pg7.unconfig_ip4()
4124         self.vlan_101.set_vtr(L2_VTR_OP.L2_DISABLED)
4125         self.vlan_100.set_vtr(L2_VTR_OP.L2_DISABLED)
4126
4127     def test_gbp_anon_l3_out(self):
4128         """ GBP Anonymous L3 Out """
4129
4130         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
4131         self.vapi.cli("set logging class gbp level debug")
4132
4133         routed_dst_mac = "00:0c:0c:0c:0c:0c"
4134         routed_src_mac = "00:22:bd:f8:19:ff"
4135
4136         #
4137         # IP tables
4138         #
4139         t4 = VppIpTable(self, 1)
4140         t4.add_vpp_config()
4141         t6 = VppIpTable(self, 1, True)
4142         t6.add_vpp_config()
4143
4144         rd1 = VppGbpRouteDomain(self, 2, 55, t4, t6)
4145         rd1.add_vpp_config()
4146
4147         self.loop0.set_mac(self.router_mac)
4148
4149         #
4150         # Bind the BVI to the RD
4151         #
4152         VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
4153         VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
4154
4155         #
4156         # Pg7 hosts a BD's BUM
4157         # Pg1 some other l3 interface
4158         #
4159         self.pg7.config_ip4()
4160         self.pg7.resolve_arp()
4161
4162         #
4163         # a GBP external bridge domains for the EPs
4164         #
4165         bd1 = VppBridgeDomain(self, 1)
4166         bd1.add_vpp_config()
4167         gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0, None, None)
4168         gbd1.add_vpp_config()
4169
4170         #
4171         # The Endpoint-groups in which the external endpoints exist
4172         #
4173         epg_220 = VppGbpEndpointGroup(self, 220, 113, rd1, gbd1,
4174                                       None, gbd1.bvi,
4175                                       "10.0.0.128",
4176                                       "2001:10::128",
4177                                       VppGbpEndpointRetention(2))
4178         epg_220.add_vpp_config()
4179
4180         # the BVIs have the subnet applied ...
4181         ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 24)
4182         ip4_addr.add_vpp_config()
4183
4184         # ... which is an Anonymous L3-out subnets
4185         l3o_1 = VppGbpSubnet(
4186             self, rd1, "10.0.0.0", 24,
4187             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_ANON_L3_OUT,
4188             sclass=113)
4189         l3o_1.add_vpp_config()
4190
4191         #
4192         # an external interface attached to the outside world and the
4193         # external BD
4194         #
4195         VppL2Vtr(self, self.vlan_100, L2_VTR_OP.L2_POP_1).add_vpp_config()
4196         VppL2Vtr(self, self.vlan_101, L2_VTR_OP.L2_POP_1).add_vpp_config()
4197
4198         ext_itf = VppGbpExtItf(self, self.loop0, bd1, rd1)
4199         ext_itf.add_vpp_config()
4200
4201         #
4202         # vlan_100 and vlan_101 are anonymous l3-out interfaces
4203         #
4204         ext_itf = VppGbpExtItf(self, self.vlan_100, bd1, rd1, anon=True)
4205         ext_itf.add_vpp_config()
4206         ext_itf = VppGbpExtItf(self, self.vlan_101, bd1, rd1, anon=True)
4207         ext_itf.add_vpp_config()
4208
4209         #
4210         # an unicast vxlan-gbp for inter-RD traffic
4211         #
4212         vx_tun_l3 = VppGbpVxlanTunnel(
4213             self, 444, rd1.rd_id,
4214             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3,
4215             self.pg2.local_ip4)
4216         vx_tun_l3.add_vpp_config()
4217
4218         #
4219         # A remote external endpoint
4220         #
4221         rep = VppGbpEndpoint(self, vx_tun_l3,
4222                              epg_220, None,
4223                              "10.0.0.201", "11.0.0.201",
4224                              "2001:10::201", "3001::101",
4225                              ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
4226                              self.pg7.local_ip4,
4227                              self.pg7.remote_ip4,
4228                              mac=None)
4229         rep.add_vpp_config()
4230
4231         #
4232         # ARP packet from host in external subnet are accepted, flooded and
4233         # replied to. We expect 2 packets:
4234         #   - APR request flooded over the other vlan subif
4235         #   - ARP reply from BVI
4236         #
4237         p_arp = (Ether(src=self.vlan_100.remote_mac,
4238                        dst="ff:ff:ff:ff:ff:ff") /
4239                  Dot1Q(vlan=100) /
4240                  ARP(op="who-has",
4241                      psrc="10.0.0.100",
4242                      pdst="10.0.0.128",
4243                      hwsrc=self.vlan_100.remote_mac,
4244                      hwdst="ff:ff:ff:ff:ff:ff"))
4245         rxs = self.send_and_expect(self.pg0, p_arp * 1, self.pg0, n_rx=2)
4246
4247         p_arp = (Ether(src=self.vlan_101.remote_mac,
4248                        dst="ff:ff:ff:ff:ff:ff") /
4249                  Dot1Q(vlan=101) /
4250                  ARP(op="who-has",
4251                      psrc='10.0.0.101',
4252                      pdst="10.0.0.128",
4253                      hwsrc=self.vlan_101.remote_mac,
4254                      hwdst="ff:ff:ff:ff:ff:ff"))
4255         rxs = self.send_and_expect(self.pg0, p_arp * 1, self.pg0, n_rx=2)
4256
4257         #
4258         # remote to external
4259         #
4260         p = (Ether(src=self.pg7.remote_mac,
4261                    dst=self.pg7.local_mac) /
4262              IP(src=self.pg7.remote_ip4,
4263                 dst=self.pg7.local_ip4) /
4264              UDP(sport=1234, dport=48879) /
4265              VXLAN(vni=vx_tun_l3.vni, gpid=epg_220.sclass, flags=0x88) /
4266              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
4267              IP(src=str(rep.ip4), dst="10.0.0.100") /
4268              UDP(sport=1234, dport=1234) /
4269              Raw('\xa5' * 100))
4270         rxs = self.send_and_expect(self.pg7, p * 1, self.pg0)
4271
4272         #
4273         # local EP pings router
4274         #
4275         p = (Ether(src=self.vlan_100.remote_mac, dst=str(self.router_mac)) /
4276              Dot1Q(vlan=100) /
4277              IP(src="10.0.0.100", dst="10.0.0.128") /
4278              ICMP(type='echo-request'))
4279         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
4280
4281         for rx in rxs:
4282             self.assertEqual(rx[Ether].src, str(self.router_mac))
4283             self.assertEqual(rx[Ether].dst, self.vlan_100.remote_mac)
4284             self.assertEqual(rx[Dot1Q].vlan, 100)
4285
4286         #
4287         # local EP pings other local EP
4288         #
4289         p = (Ether(src=self.vlan_100.remote_mac,
4290                    dst=self.vlan_101.remote_mac) /
4291              Dot1Q(vlan=100) /
4292              IP(src="10.0.0.100", dst="10.0.0.101") /
4293              ICMP(type='echo-request'))
4294         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
4295
4296         for rx in rxs:
4297             self.assertEqual(rx[Ether].src, self.vlan_100.remote_mac)
4298             self.assertEqual(rx[Ether].dst, self.vlan_101.remote_mac)
4299             self.assertEqual(rx[Dot1Q].vlan, 101)
4300
4301         #
4302         # A subnet reachable through an external router on vlan 100
4303         #
4304         ip_220 = VppIpRoute(self, "10.220.0.0", 24,
4305                             [VppRoutePath("10.0.0.100",
4306                                           epg_220.bvi.sw_if_index)],
4307                             table_id=t4.table_id)
4308         ip_220.add_vpp_config()
4309
4310         l3o_220 = VppGbpSubnet(
4311             self, rd1, "10.220.0.0", 24,
4312             # note: this a "regular" L3 out subnet (not connected)
4313             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
4314             sclass=4220)
4315         l3o_220.add_vpp_config()
4316
4317         #
4318         # A subnet reachable through an external router on vlan 101
4319         #
4320         ip_221 = VppIpRoute(self, "10.221.0.0", 24,
4321                             [VppRoutePath("10.0.0.101",
4322                                           epg_220.bvi.sw_if_index)],
4323                             table_id=t4.table_id)
4324         ip_221.add_vpp_config()
4325
4326         l3o_221 = VppGbpSubnet(
4327             self, rd1, "10.221.0.0", 24,
4328             # note: this a "regular" L3 out subnet (not connected)
4329             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
4330             sclass=4221)
4331         l3o_221.add_vpp_config()
4332
4333         #
4334         # ping between hosts in remote subnets
4335         #  dropped without a contract
4336         #
4337         p = (Ether(src=self.vlan_100.remote_mac, dst=str(self.router_mac)) /
4338              Dot1Q(vlan=100) /
4339              IP(src="10.220.0.1", dst="10.221.0.1") /
4340              ICMP(type='echo-request'))
4341
4342         rxs = self.send_and_assert_no_replies(self.pg0, p * 1)
4343
4344         #
4345         # contract for the external nets to communicate
4346         #
4347         acl = VppGbpAcl(self)
4348         rule4 = acl.create_rule(permit_deny=1, proto=17)
4349         rule6 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
4350         acl_index = acl.add_vpp_config([rule4, rule6])
4351
4352         c1 = VppGbpContract(
4353             self, 55, 4220, 4221, acl_index,
4354             [VppGbpContractRule(
4355                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4356                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
4357                 []),
4358                 VppGbpContractRule(
4359                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4360                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
4361                     [])],
4362             [ETH_P_IP, ETH_P_IPV6])
4363         c1.add_vpp_config()
4364
4365         #
4366         # Contracts allowing ext-net 200 to talk with external EPs
4367         #
4368         c2 = VppGbpContract(
4369             self, 55, 4220, 113, acl_index,
4370             [VppGbpContractRule(
4371                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4372                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
4373                 []),
4374                 VppGbpContractRule(
4375                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4376                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
4377                     [])],
4378             [ETH_P_IP, ETH_P_IPV6])
4379         c2.add_vpp_config()
4380         c3 = VppGbpContract(
4381             self, 55, 113, 4220, acl_index,
4382             [VppGbpContractRule(
4383                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4384                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
4385                 []),
4386                 VppGbpContractRule(
4387                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4388                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
4389                     [])],
4390             [ETH_P_IP, ETH_P_IPV6])
4391         c3.add_vpp_config()
4392
4393         #
4394         # ping between hosts in remote subnets
4395         #
4396         p = (Ether(src=self.vlan_100.remote_mac, dst=str(self.router_mac)) /
4397              Dot1Q(vlan=100) /
4398              IP(src="10.220.0.1", dst="10.221.0.1") /
4399              UDP(sport=1234, dport=1234) /
4400              Raw('\xa5' * 100))
4401
4402         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
4403
4404         for rx in rxs:
4405             self.assertEqual(rx[Ether].src, str(self.router_mac))
4406             self.assertEqual(rx[Ether].dst, self.vlan_101.remote_mac)
4407             self.assertEqual(rx[Dot1Q].vlan, 101)
4408
4409         # we did not learn these external hosts
4410         self.assertFalse(find_gbp_endpoint(self, ip="10.220.0.1"))
4411         self.assertFalse(find_gbp_endpoint(self, ip="10.221.0.1"))
4412
4413         #
4414         # from remote external EP to local external EP
4415         #
4416         p = (Ether(src=self.pg7.remote_mac,
4417                    dst=self.pg7.local_mac) /
4418              IP(src=self.pg7.remote_ip4,
4419                 dst=self.pg7.local_ip4) /
4420              UDP(sport=1234, dport=48879) /
4421              VXLAN(vni=444, gpid=113, flags=0x88) /
4422              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
4423              IP(src=rep.ip4.address, dst="10.220.0.1") /
4424              UDP(sport=1234, dport=1234) /
4425              Raw('\xa5' * 100))
4426
4427         rxs = self.send_and_expect(self.pg7, p * 1, self.pg0)
4428
4429         #
4430         # ping from an external host to the remote external EP
4431         #
4432         p = (Ether(src=self.vlan_100.remote_mac, dst=str(self.router_mac)) /
4433              Dot1Q(vlan=100) /
4434              IP(src="10.220.0.1", dst=rep.ip4.address) /
4435              UDP(sport=1234, dport=1234) /
4436              Raw('\xa5' * 100))
4437
4438         rxs = self.send_and_expect(self.pg0, p * 1, self.pg7)
4439
4440         for rx in rxs:
4441             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
4442             # self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
4443             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
4444             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
4445             self.assertEqual(rx[VXLAN].vni, 444)
4446             self.assertTrue(rx[VXLAN].flags.G)
4447             self.assertTrue(rx[VXLAN].flags.Instance)
4448             # the sclass of the ext-net the packet came from
4449             self.assertEqual(rx[VXLAN].gpid, 4220)
4450             # policy was applied to the original IP packet
4451             self.assertTrue(rx[VXLAN].gpflags.A)
4452             # since it's an external host the reciever should not learn it
4453             self.assertTrue(rx[VXLAN].gpflags.D)
4454             inner = rx[VXLAN].payload
4455             self.assertEqual(inner[IP].src, "10.220.0.1")
4456             self.assertEqual(inner[IP].dst, rep.ip4.address)
4457
4458         #
4459         # An external subnet reachable via the remote external EP
4460         #
4461
4462         #
4463         # first the VXLAN-GBP tunnel over which it is reached
4464         #
4465         vx_tun_r = VppVxlanGbpTunnel(
4466             self, self.pg7.local_ip4,
4467             self.pg7.remote_ip4, 445,
4468             mode=(VppEnum.vl_api_vxlan_gbp_api_tunnel_mode_t.
4469                   VXLAN_GBP_API_TUNNEL_MODE_L3))
4470         vx_tun_r.add_vpp_config()
4471         VppIpInterfaceBind(self, vx_tun_r, t4).add_vpp_config()
4472
4473         self.logger.info(self.vapi.cli("sh vxlan-gbp tunnel"))
4474
4475         #
4476         # then the special adj to resolve through on that tunnel
4477         #
4478         n1 = VppNeighbor(self,
4479                          vx_tun_r.sw_if_index,
4480                          "00:0c:0c:0c:0c:0c",
4481                          self.pg7.remote_ip4)
4482         n1.add_vpp_config()
4483
4484         #
4485         # the route via the adj above
4486         #
4487         ip_222 = VppIpRoute(self, "10.222.0.0", 24,
4488                             [VppRoutePath(self.pg7.remote_ip4,
4489                                           vx_tun_r.sw_if_index)],
4490                             table_id=t4.table_id)
4491         ip_222.add_vpp_config()
4492
4493         l3o_222 = VppGbpSubnet(
4494             self, rd1, "10.222.0.0", 24,
4495             # note: this a "regular" l3out subnet (not connected)
4496             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
4497             sclass=4222)
4498         l3o_222.add_vpp_config()
4499
4500         #
4501         # ping between hosts in local and remote external subnets
4502         #  dropped without a contract
4503         #
4504         p = (Ether(src=self.vlan_100.remote_mac, dst=str(self.router_mac)) /
4505              Dot1Q(vlan=100) /
4506              IP(src="10.220.0.1", dst="10.222.0.1") /
4507              UDP(sport=1234, dport=1234) /
4508              Raw('\xa5' * 100))
4509
4510         rxs = self.send_and_assert_no_replies(self.pg0, p * 1)
4511
4512         #
4513         # Add contracts ext-nets for 220 -> 222
4514         #
4515         c4 = VppGbpContract(
4516             self, 55, 4220, 4222, acl_index,
4517             [VppGbpContractRule(
4518                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4519                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
4520                 []),
4521                 VppGbpContractRule(
4522                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
4523                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
4524                     [])],
4525             [ETH_P_IP, ETH_P_IPV6])
4526         c4.add_vpp_config()
4527
4528         #
4529         # ping from host in local to remote external subnets
4530         #
4531         p = (Ether(src=self.vlan_100.remote_mac, dst=str(self.router_mac)) /
4532              Dot1Q(vlan=100) /
4533              IP(src="10.220.0.1", dst="10.222.0.1") /
4534              UDP(sport=1234, dport=1234) /
4535              Raw('\xa5' * 100))
4536
4537         rxs = self.send_and_expect(self.pg0, p * 3, self.pg7)
4538
4539         for rx in rxs:
4540             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
4541             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
4542             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
4543             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
4544             self.assertEqual(rx[VXLAN].vni, 445)
4545             self.assertTrue(rx[VXLAN].flags.G)
4546             self.assertTrue(rx[VXLAN].flags.Instance)
4547             # the sclass of the ext-net the packet came from
4548             self.assertEqual(rx[VXLAN].gpid, 4220)
4549             # policy was applied to the original IP packet
4550             self.assertTrue(rx[VXLAN].gpflags.A)
4551             # since it's an external host the reciever should not learn it
4552             self.assertTrue(rx[VXLAN].gpflags.D)
4553             inner = rx[VXLAN].payload
4554             self.assertEqual(inner[Ether].dst, "00:0c:0c:0c:0c:0c")
4555             self.assertEqual(inner[IP].src, "10.220.0.1")
4556             self.assertEqual(inner[IP].dst, "10.222.0.1")
4557
4558         #
4559         # ping from host in remote to local external subnets
4560         # there's no contract for this, but the A bit is set.
4561         #
4562         p = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) /
4563              IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) /
4564              UDP(sport=1234, dport=48879) /
4565              VXLAN(vni=445, gpid=4222, flags=0x88, gpflags='A') /
4566              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
4567              IP(src="10.222.0.1", dst="10.220.0.1") /
4568              UDP(sport=1234, dport=1234) /
4569              Raw('\xa5' * 100))
4570
4571         rxs = self.send_and_expect(self.pg7, p * 3, self.pg0)
4572         self.assertFalse(find_gbp_endpoint(self, ip="10.222.0.1"))
4573
4574         #
4575         # ping from host in remote to remote external subnets
4576         #   this is dropped by reflection check.
4577         #
4578         p = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) /
4579              IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) /
4580              UDP(sport=1234, dport=48879) /
4581              VXLAN(vni=445, gpid=4222, flags=0x88, gpflags='A') /
4582              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
4583              IP(src="10.222.0.1", dst="10.222.0.2") /
4584              UDP(sport=1234, dport=1234) /
4585              Raw('\xa5' * 100))
4586
4587         rxs = self.send_and_assert_no_replies(self.pg7, p * 3)
4588
4589         #
4590         # cleanup
4591         #
4592         self.vlan_101.set_vtr(L2_VTR_OP.L2_DISABLED)
4593         self.vlan_100.set_vtr(L2_VTR_OP.L2_DISABLED)
4594         self.pg7.unconfig_ip4()
4595
4596
4597 if __name__ == '__main__':
4598     unittest.main(testRunner=VppTestRunner)