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