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