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