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