fib: fib api updates
[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)
845             epg.bd_arp_ip6 = VppBridgeDomainArpEntry(self, epg.bd.bd,
846                                                      str(self.router_mac),
847                                                      epg.bvi_ip6)
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, fip)
921                 ba.add_vpp_config()
922
923                 # floating IPs route via EPG recirc
924                 r = VppIpRoute(
925                     self, fip.address, fip.length,
926                     [VppRoutePath(fip.address,
927                                   ep.recirc.recirc.sw_if_index,
928                                   type=FibPathType.FIB_PATH_TYPE_DVR,
929                                   proto=fip.dpo_proto)],
930                     table_id=20)
931                 r.add_vpp_config()
932
933             # L2 FIB entries in the NAT EPG BD to bridge the packets from
934             # the outside direct to the internal EPG
935             lf = VppL2FibEntry(self, epg_nat.bd.bd, ep.mac,
936                                ep.recirc.recirc, bvi_mac=0)
937             lf.add_vpp_config()
938
939         #
940         # ARP packets for unknown IP are sent to the EPG uplink
941         #
942         pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff",
943                          src=self.pg0.remote_mac) /
944                    ARP(op="who-has",
945                        hwdst="ff:ff:ff:ff:ff:ff",
946                        hwsrc=self.pg0.remote_mac,
947                        pdst="10.0.0.88",
948                        psrc="10.0.0.99"))
949
950         self.vapi.cli("clear trace")
951         self.pg0.add_stream(pkt_arp)
952
953         self.pg_enable_capture(self.pg_interfaces)
954         self.pg_start()
955
956         rxd = epgs[0].uplink.get_capture(1)
957
958         #
959         # ARP/ND packets get a response
960         #
961         pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff",
962                          src=self.pg0.remote_mac) /
963                    ARP(op="who-has",
964                        hwdst="ff:ff:ff:ff:ff:ff",
965                        hwsrc=self.pg0.remote_mac,
966                        pdst=epgs[0].bvi_ip4.address,
967                        psrc=eps[0].ip4.address))
968
969         self.send_and_expect(self.pg0, [pkt_arp], self.pg0)
970
971         nsma = in6_getnsma(inet_pton(AF_INET6, eps[0].ip6.address))
972         d = inet_ntop(AF_INET6, nsma)
973         pkt_nd = (Ether(dst=in6_getnsmac(nsma),
974                         src=self.pg0.remote_mac) /
975                   IPv6(dst=d, src=eps[0].ip6.address) /
976                   ICMPv6ND_NS(tgt=epgs[0].bvi_ip6.address) /
977                   ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac))
978         self.send_and_expect(self.pg0, [pkt_nd], self.pg0)
979
980         #
981         # broadcast packets are flooded
982         #
983         pkt_bcast = (Ether(dst="ff:ff:ff:ff:ff:ff",
984                            src=self.pg0.remote_mac) /
985                      IP(src=eps[0].ip4.address, dst="232.1.1.1") /
986                      UDP(sport=1234, dport=1234) /
987                      Raw('\xa5' * 100))
988
989         self.vapi.cli("clear trace")
990         self.pg0.add_stream(pkt_bcast)
991
992         self.pg_enable_capture(self.pg_interfaces)
993         self.pg_start()
994
995         rxd = eps[1].itf.get_capture(1)
996         self.assertEqual(rxd[0][Ether].dst, pkt_bcast[Ether].dst)
997         rxd = epgs[0].uplink.get_capture(1)
998         self.assertEqual(rxd[0][Ether].dst, pkt_bcast[Ether].dst)
999
1000         #
1001         # packets to non-local L3 destinations dropped
1002         #
1003         pkt_intra_epg_220_ip4 = (Ether(src=self.pg0.remote_mac,
1004                                        dst=str(self.router_mac)) /
1005                                  IP(src=eps[0].ip4.address,
1006                                     dst="10.0.0.99") /
1007                                  UDP(sport=1234, dport=1234) /
1008                                  Raw('\xa5' * 100))
1009         pkt_inter_epg_222_ip4 = (Ether(src=self.pg0.remote_mac,
1010                                        dst=str(self.router_mac)) /
1011                                  IP(src=eps[0].ip4.address,
1012                                     dst="10.0.1.99") /
1013                                  UDP(sport=1234, dport=1234) /
1014                                  Raw('\xa5' * 100))
1015
1016         self.send_and_assert_no_replies(self.pg0,
1017                                         pkt_intra_epg_220_ip4 * NUM_PKTS)
1018
1019         pkt_inter_epg_222_ip6 = (Ether(src=self.pg0.remote_mac,
1020                                        dst=str(self.router_mac)) /
1021                                  IPv6(src=eps[0].ip6.address,
1022                                       dst="2001:10::99") /
1023                                  UDP(sport=1234, dport=1234) /
1024                                  Raw('\xa5' * 100))
1025         self.send_and_assert_no_replies(self.pg0,
1026                                         pkt_inter_epg_222_ip6 * NUM_PKTS)
1027
1028         #
1029         # Add the subnet routes
1030         #
1031         s41 = VppGbpSubnet(
1032             self, rd0, "10.0.0.0", 24,
1033             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
1034         s42 = VppGbpSubnet(
1035             self, rd0, "10.0.1.0", 24,
1036             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
1037         s43 = VppGbpSubnet(
1038             self, rd0, "10.0.2.0", 24,
1039             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
1040         s61 = VppGbpSubnet(
1041             self, rd0, "2001:10::1", 64,
1042             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
1043         s62 = VppGbpSubnet(
1044             self, rd0, "2001:10:1::1", 64,
1045             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
1046         s63 = VppGbpSubnet(
1047             self, rd0, "2001:10:2::1", 64,
1048             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_INTERNAL)
1049         s41.add_vpp_config()
1050         s42.add_vpp_config()
1051         s43.add_vpp_config()
1052         s61.add_vpp_config()
1053         s62.add_vpp_config()
1054         s63.add_vpp_config()
1055
1056         self.send_and_expect_bridged(eps[0].itf,
1057                                      pkt_intra_epg_220_ip4 * NUM_PKTS,
1058                                      eps[0].epg.uplink)
1059         self.send_and_expect_bridged(eps[0].itf,
1060                                      pkt_inter_epg_222_ip4 * NUM_PKTS,
1061                                      eps[0].epg.uplink)
1062         self.send_and_expect_bridged6(eps[0].itf,
1063                                       pkt_inter_epg_222_ip6 * NUM_PKTS,
1064                                       eps[0].epg.uplink)
1065
1066         self.logger.info(self.vapi.cli("sh ip fib 11.0.0.2"))
1067         self.logger.info(self.vapi.cli("sh gbp endpoint-group"))
1068         self.logger.info(self.vapi.cli("sh gbp endpoint"))
1069         self.logger.info(self.vapi.cli("sh gbp recirc"))
1070         self.logger.info(self.vapi.cli("sh int"))
1071         self.logger.info(self.vapi.cli("sh int addr"))
1072         self.logger.info(self.vapi.cli("sh int feat loop6"))
1073         self.logger.info(self.vapi.cli("sh vlib graph ip4-gbp-src-classify"))
1074         self.logger.info(self.vapi.cli("sh int feat loop3"))
1075         self.logger.info(self.vapi.cli("sh int feat pg0"))
1076
1077         #
1078         # Packet destined to unknown unicast is sent on the epg uplink ...
1079         #
1080         pkt_intra_epg_220_to_uplink = (Ether(src=self.pg0.remote_mac,
1081                                              dst="00:00:00:33:44:55") /
1082                                        IP(src=eps[0].ip4.address,
1083                                           dst="10.0.0.99") /
1084                                        UDP(sport=1234, dport=1234) /
1085                                        Raw('\xa5' * 100))
1086
1087         self.send_and_expect_bridged(eps[0].itf,
1088                                      pkt_intra_epg_220_to_uplink * NUM_PKTS,
1089                                      eps[0].epg.uplink)
1090         # ... and nowhere else
1091         self.pg1.get_capture(0, timeout=0.1)
1092         self.pg1.assert_nothing_captured(remark="Flood onto other VMS")
1093
1094         pkt_intra_epg_221_to_uplink = (Ether(src=self.pg2.remote_mac,
1095                                              dst="00:00:00:33:44:66") /
1096                                        IP(src=eps[0].ip4.address,
1097                                           dst="10.0.0.99") /
1098                                        UDP(sport=1234, dport=1234) /
1099                                        Raw('\xa5' * 100))
1100
1101         self.send_and_expect_bridged(eps[2].itf,
1102                                      pkt_intra_epg_221_to_uplink * NUM_PKTS,
1103                                      eps[2].epg.uplink)
1104
1105         #
1106         # Packets from the uplink are forwarded in the absence of a contract
1107         #
1108         pkt_intra_epg_220_from_uplink = (Ether(src="00:00:00:33:44:55",
1109                                                dst=self.pg0.remote_mac) /
1110                                          IP(src=eps[0].ip4.address,
1111                                             dst="10.0.0.99") /
1112                                          UDP(sport=1234, dport=1234) /
1113                                          Raw('\xa5' * 100))
1114
1115         self.send_and_expect_bridged(self.pg4,
1116                                      pkt_intra_epg_220_from_uplink * NUM_PKTS,
1117                                      self.pg0)
1118
1119         #
1120         # in the absence of policy, endpoints in the same EPG
1121         # can communicate
1122         #
1123         pkt_intra_epg = (Ether(src=self.pg0.remote_mac,
1124                                dst=self.pg1.remote_mac) /
1125                          IP(src=eps[0].ip4.address,
1126                             dst=eps[1].ip4.address) /
1127                          UDP(sport=1234, dport=1234) /
1128                          Raw('\xa5' * 100))
1129
1130         self.send_and_expect_bridged(self.pg0,
1131                                      pkt_intra_epg * NUM_PKTS,
1132                                      self.pg1)
1133
1134         #
1135         # in the absence of policy, endpoints in the different EPG
1136         # cannot communicate
1137         #
1138         pkt_inter_epg_220_to_221 = (Ether(src=self.pg0.remote_mac,
1139                                           dst=self.pg2.remote_mac) /
1140                                     IP(src=eps[0].ip4.address,
1141                                        dst=eps[2].ip4.address) /
1142                                     UDP(sport=1234, dport=1234) /
1143                                     Raw('\xa5' * 100))
1144         pkt_inter_epg_221_to_220 = (Ether(src=self.pg2.remote_mac,
1145                                           dst=self.pg0.remote_mac) /
1146                                     IP(src=eps[2].ip4.address,
1147                                        dst=eps[0].ip4.address) /
1148                                     UDP(sport=1234, dport=1234) /
1149                                     Raw('\xa5' * 100))
1150         pkt_inter_epg_220_to_222 = (Ether(src=self.pg0.remote_mac,
1151                                           dst=str(self.router_mac)) /
1152                                     IP(src=eps[0].ip4.address,
1153                                        dst=eps[3].ip4.address) /
1154                                     UDP(sport=1234, dport=1234) /
1155                                     Raw('\xa5' * 100))
1156
1157         self.send_and_assert_no_replies(eps[0].itf,
1158                                         pkt_inter_epg_220_to_221 * NUM_PKTS)
1159         self.send_and_assert_no_replies(eps[0].itf,
1160                                         pkt_inter_epg_220_to_222 * NUM_PKTS)
1161
1162         #
1163         # A uni-directional contract from EPG 220 -> 221
1164         #
1165         acl = VppGbpAcl(self)
1166         rule = acl.create_rule(permit_deny=1, proto=17)
1167         rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
1168         acl_index = acl.add_vpp_config([rule, rule2])
1169         c1 = VppGbpContract(
1170             self, epgs[0].sclass, epgs[1].sclass, acl_index,
1171             [VppGbpContractRule(
1172                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1173                 []),
1174                 VppGbpContractRule(
1175                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1176                     [])],
1177             [ETH_P_IP, ETH_P_IPV6])
1178         c1.add_vpp_config()
1179
1180         self.send_and_expect_bridged(eps[0].itf,
1181                                      pkt_inter_epg_220_to_221 * NUM_PKTS,
1182                                      eps[2].itf)
1183         self.send_and_assert_no_replies(eps[0].itf,
1184                                         pkt_inter_epg_220_to_222 * NUM_PKTS)
1185
1186         #
1187         # contract for the return direction
1188         #
1189         c2 = VppGbpContract(
1190             self, epgs[1].sclass, epgs[0].sclass, acl_index,
1191             [VppGbpContractRule(
1192                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1193                 []),
1194                 VppGbpContractRule(
1195                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1196                     [])],
1197             [ETH_P_IP, ETH_P_IPV6])
1198         c2.add_vpp_config()
1199
1200         self.send_and_expect_bridged(eps[0].itf,
1201                                      pkt_inter_epg_220_to_221 * NUM_PKTS,
1202                                      eps[2].itf)
1203         self.send_and_expect_bridged(eps[2].itf,
1204                                      pkt_inter_epg_221_to_220 * NUM_PKTS,
1205                                      eps[0].itf)
1206
1207         ds = c2.get_drop_stats()
1208         self.assertEqual(ds['packets'], 0)
1209         ps = c2.get_permit_stats()
1210         self.assertEqual(ps['packets'], NUM_PKTS)
1211
1212         #
1213         # the contract does not allow non-IP
1214         #
1215         pkt_non_ip_inter_epg_220_to_221 = (Ether(src=self.pg0.remote_mac,
1216                                                  dst=self.pg2.remote_mac) /
1217                                            ARP())
1218         self.send_and_assert_no_replies(eps[0].itf,
1219                                         pkt_non_ip_inter_epg_220_to_221 * 17)
1220
1221         #
1222         # check that inter group is still disabled for the groups
1223         # not in the contract.
1224         #
1225         self.send_and_assert_no_replies(eps[0].itf,
1226                                         pkt_inter_epg_220_to_222 * NUM_PKTS)
1227
1228         #
1229         # A uni-directional contract from EPG 220 -> 222 'L3 routed'
1230         #
1231         c3 = VppGbpContract(
1232             self, epgs[0].sclass, epgs[2].sclass, acl_index,
1233             [VppGbpContractRule(
1234                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1235                 []),
1236                 VppGbpContractRule(
1237                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1238                     [])],
1239             [ETH_P_IP, ETH_P_IPV6])
1240         c3.add_vpp_config()
1241
1242         self.logger.info(self.vapi.cli("sh gbp contract"))
1243
1244         self.send_and_expect_routed(eps[0].itf,
1245                                     pkt_inter_epg_220_to_222 * NUM_PKTS,
1246                                     eps[3].itf,
1247                                     str(self.router_mac))
1248
1249         #
1250         # remove both contracts, traffic stops in both directions
1251         #
1252         c2.remove_vpp_config()
1253         c1.remove_vpp_config()
1254         c3.remove_vpp_config()
1255         acl.remove_vpp_config()
1256
1257         self.send_and_assert_no_replies(eps[2].itf,
1258                                         pkt_inter_epg_221_to_220 * NUM_PKTS)
1259         self.send_and_assert_no_replies(eps[0].itf,
1260                                         pkt_inter_epg_220_to_221 * NUM_PKTS)
1261         self.send_and_expect_bridged(eps[0].itf,
1262                                      pkt_intra_epg * NUM_PKTS,
1263                                      eps[1].itf)
1264
1265         #
1266         # EPs to the outside world
1267         #
1268
1269         # in the EP's RD an external subnet via the NAT EPG's recirc
1270         se1 = VppGbpSubnet(
1271             self, rd0, "0.0.0.0", 0,
1272             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1273             sw_if_index=recirc_nat.recirc.sw_if_index,
1274             sclass=epg_nat.sclass)
1275         se2 = VppGbpSubnet(
1276             self, rd0, "11.0.0.0", 8,
1277             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1278             sw_if_index=recirc_nat.recirc.sw_if_index,
1279             sclass=epg_nat.sclass)
1280         se16 = VppGbpSubnet(
1281             self, rd0, "::", 0,
1282             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1283             sw_if_index=recirc_nat.recirc.sw_if_index,
1284             sclass=epg_nat.sclass)
1285         # in the NAT RD an external subnet via the NAT EPG's uplink
1286         se3 = VppGbpSubnet(
1287             self, rd20, "0.0.0.0", 0,
1288             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1289             sw_if_index=epg_nat.uplink.sw_if_index,
1290             sclass=epg_nat.sclass)
1291         se36 = VppGbpSubnet(
1292             self, rd20, "::", 0,
1293             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1294             sw_if_index=epg_nat.uplink.sw_if_index,
1295             sclass=epg_nat.sclass)
1296         se4 = VppGbpSubnet(
1297             self, rd20, "11.0.0.0", 8,
1298             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_STITCHED_EXTERNAL,
1299             sw_if_index=epg_nat.uplink.sw_if_index,
1300             sclass=epg_nat.sclass)
1301         se1.add_vpp_config()
1302         se2.add_vpp_config()
1303         se16.add_vpp_config()
1304         se3.add_vpp_config()
1305         se36.add_vpp_config()
1306         se4.add_vpp_config()
1307
1308         self.logger.info(self.vapi.cli("sh ip fib 0.0.0.0/0"))
1309         self.logger.info(self.vapi.cli("sh ip fib 11.0.0.1"))
1310         self.logger.info(self.vapi.cli("sh ip6 fib ::/0"))
1311         self.logger.info(self.vapi.cli("sh ip6 fib %s" %
1312                                        eps[0].fip6))
1313
1314         #
1315         # From an EP to an outside address: IN2OUT
1316         #
1317         pkt_inter_epg_220_to_global = (Ether(src=self.pg0.remote_mac,
1318                                              dst=str(self.router_mac)) /
1319                                        IP(src=eps[0].ip4.address,
1320                                           dst="1.1.1.1") /
1321                                        UDP(sport=1234, dport=1234) /
1322                                        Raw('\xa5' * 100))
1323
1324         # no policy yet
1325         self.send_and_assert_no_replies(eps[0].itf,
1326                                         pkt_inter_epg_220_to_global * NUM_PKTS)
1327
1328         acl2 = VppGbpAcl(self)
1329         rule = acl2.create_rule(permit_deny=1, proto=17, sport_from=1234,
1330                                 sport_to=1234, dport_from=1234, dport_to=1234)
1331         rule2 = acl2.create_rule(is_ipv6=1, permit_deny=1, proto=17,
1332                                  sport_from=1234, sport_to=1234,
1333                                  dport_from=1234, dport_to=1234)
1334
1335         acl_index2 = acl2.add_vpp_config([rule, rule2])
1336         c4 = VppGbpContract(
1337             self, epgs[0].sclass, epgs[3].sclass, acl_index2,
1338             [VppGbpContractRule(
1339                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1340                 []),
1341                 VppGbpContractRule(
1342                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1343                     [])],
1344             [ETH_P_IP, ETH_P_IPV6])
1345         c4.add_vpp_config()
1346
1347         self.send_and_expect_natted(eps[0].itf,
1348                                     pkt_inter_epg_220_to_global * NUM_PKTS,
1349                                     self.pg7,
1350                                     eps[0].fip4.address)
1351
1352         pkt_inter_epg_220_to_global = (Ether(src=self.pg0.remote_mac,
1353                                              dst=str(self.router_mac)) /
1354                                        IPv6(src=eps[0].ip6.address,
1355                                             dst="6001::1") /
1356                                        UDP(sport=1234, dport=1234) /
1357                                        Raw('\xa5' * 100))
1358
1359         self.send_and_expect_natted6(self.pg0,
1360                                      pkt_inter_epg_220_to_global * NUM_PKTS,
1361                                      self.pg7,
1362                                      eps[0].fip6.address)
1363
1364         #
1365         # From a global address to an EP: OUT2IN
1366         #
1367         pkt_inter_epg_220_from_global = (Ether(src=str(self.router_mac),
1368                                                dst=self.pg0.remote_mac) /
1369                                          IP(dst=eps[0].fip4.address,
1370                                             src="1.1.1.1") /
1371                                          UDP(sport=1234, dport=1234) /
1372                                          Raw('\xa5' * 100))
1373
1374         self.send_and_assert_no_replies(
1375             self.pg7, pkt_inter_epg_220_from_global * NUM_PKTS)
1376
1377         c5 = VppGbpContract(
1378             self, epgs[3].sclass, epgs[0].sclass, acl_index2,
1379             [VppGbpContractRule(
1380                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1381                 []),
1382                 VppGbpContractRule(
1383                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1384                     [])],
1385             [ETH_P_IP, ETH_P_IPV6])
1386         c5.add_vpp_config()
1387
1388         self.send_and_expect_unnatted(self.pg7,
1389                                       pkt_inter_epg_220_from_global * NUM_PKTS,
1390                                       eps[0].itf,
1391                                       eps[0].ip4.address)
1392
1393         pkt_inter_epg_220_from_global = (Ether(src=str(self.router_mac),
1394                                                dst=self.pg0.remote_mac) /
1395                                          IPv6(dst=eps[0].fip6.address,
1396                                               src="6001::1") /
1397                                          UDP(sport=1234, dport=1234) /
1398                                          Raw('\xa5' * 100))
1399
1400         self.send_and_expect_unnatted6(
1401             self.pg7,
1402             pkt_inter_epg_220_from_global * NUM_PKTS,
1403             eps[0].itf,
1404             eps[0].ip6.address)
1405
1406         #
1407         # From a local VM to another local VM using resp. public addresses:
1408         #  IN2OUT2IN
1409         #
1410         pkt_intra_epg_220_global = (Ether(src=self.pg0.remote_mac,
1411                                           dst=str(self.router_mac)) /
1412                                     IP(src=eps[0].ip4.address,
1413                                        dst=eps[1].fip4.address) /
1414                                     UDP(sport=1234, dport=1234) /
1415                                     Raw('\xa5' * 100))
1416
1417         self.send_and_expect_double_natted(eps[0].itf,
1418                                            pkt_intra_epg_220_global * NUM_PKTS,
1419                                            eps[1].itf,
1420                                            eps[0].fip4.address,
1421                                            eps[1].ip4.address)
1422
1423         pkt_intra_epg_220_global = (Ether(src=self.pg0.remote_mac,
1424                                           dst=str(self.router_mac)) /
1425                                     IPv6(src=eps[0].ip6.address,
1426                                          dst=eps[1].fip6.address) /
1427                                     UDP(sport=1234, dport=1234) /
1428                                     Raw('\xa5' * 100))
1429
1430         self.send_and_expect_double_natted6(
1431             eps[0].itf,
1432             pkt_intra_epg_220_global * NUM_PKTS,
1433             eps[1].itf,
1434             eps[0].fip6.address,
1435             eps[1].ip6.address)
1436
1437         #
1438         # cleanup
1439         #
1440         for ep in eps:
1441             # del static mappings for each EP from the 10/8 to 11/8 network
1442             flags = self.config_flags.NAT_IS_ADDR_ONLY
1443             self.vapi.nat44_add_del_static_mapping(
1444                 is_add=0,
1445                 local_ip_address=ep.ip4.bytes,
1446                 external_ip_address=ep.fip4.bytes,
1447                 external_sw_if_index=0xFFFFFFFF,
1448                 vrf_id=0,
1449                 flags=flags)
1450             self.vapi.nat66_add_del_static_mapping(
1451                 local_ip_address=ep.ip6.bytes,
1452                 external_ip_address=ep.fip6.bytes,
1453                 vrf_id=0, is_add=0)
1454
1455         for epg in epgs:
1456             # IP config on the BVI interfaces
1457             if epg != epgs[0] and epg != epgs[3]:
1458                 flags = self.config_flags.NAT_IS_INSIDE
1459                 self.vapi.nat44_interface_add_del_feature(
1460                     sw_if_index=epg.bvi.sw_if_index,
1461                     flags=flags,
1462                     is_add=0)
1463                 self.vapi.nat66_add_del_interface(
1464                     is_add=0, flags=flags,
1465                     sw_if_index=epg.bvi.sw_if_index)
1466
1467         for recirc in recircs:
1468             self.vapi.nat44_interface_add_del_feature(
1469                 sw_if_index=recirc.recirc.sw_if_index,
1470                 is_add=0)
1471             self.vapi.nat66_add_del_interface(
1472                 is_add=0,
1473                 sw_if_index=recirc.recirc.sw_if_index)
1474
1475     def wait_for_ep_timeout(self, sw_if_index=None, ip=None, mac=None,
1476                             n_tries=100, s_time=1):
1477         while (n_tries):
1478             if not find_gbp_endpoint(self, sw_if_index, ip, mac):
1479                 return True
1480             n_tries = n_tries - 1
1481             self.sleep(s_time)
1482         self.assertFalse(find_gbp_endpoint(self, sw_if_index, ip, mac))
1483         return False
1484
1485     def test_gbp_learn_l2(self):
1486         """ GBP L2 Endpoint Learning """
1487
1488         self.vapi.cli("clear errors")
1489
1490         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
1491         learnt = [{'mac': '00:00:11:11:11:01',
1492                    'ip': '10.0.0.1',
1493                    'ip6': '2001:10::2'},
1494                   {'mac': '00:00:11:11:11:02',
1495                    'ip': '10.0.0.2',
1496                    'ip6': '2001:10::3'}]
1497
1498         #
1499         # IP tables
1500         #
1501         gt4 = VppIpTable(self, 1)
1502         gt4.add_vpp_config()
1503         gt6 = VppIpTable(self, 1, is_ip6=True)
1504         gt6.add_vpp_config()
1505
1506         rd1 = VppGbpRouteDomain(self, 1, gt4, gt6)
1507         rd1.add_vpp_config()
1508
1509         #
1510         # Pg2 hosts the vxlan tunnel, hosts on pg2 to act as TEPs
1511         # Pg3 hosts the IP4 UU-flood VXLAN tunnel
1512         # Pg4 hosts the IP6 UU-flood VXLAN tunnel
1513         #
1514         self.pg2.config_ip4()
1515         self.pg2.resolve_arp()
1516         self.pg2.generate_remote_hosts(4)
1517         self.pg2.configure_ipv4_neighbors()
1518         self.pg3.config_ip4()
1519         self.pg3.resolve_arp()
1520         self.pg4.config_ip4()
1521         self.pg4.resolve_arp()
1522
1523         #
1524         # Add a mcast destination VXLAN-GBP tunnel for B&M traffic
1525         #
1526         tun_bm = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
1527                                    "239.1.1.1", 88,
1528                                    mcast_itf=self.pg4)
1529         tun_bm.add_vpp_config()
1530
1531         #
1532         # a GBP bridge domain with a BVI and a UU-flood interface
1533         #
1534         bd1 = VppBridgeDomain(self, 1)
1535         bd1.add_vpp_config()
1536         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0, self.pg3, tun_bm)
1537         gbd1.add_vpp_config()
1538
1539         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1540         self.logger.info(self.vapi.cli("sh gbp bridge"))
1541
1542         # ... and has a /32 applied
1543         ip_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
1544         ip_addr.add_vpp_config()
1545
1546         #
1547         # The Endpoint-group in which we are learning endpoints
1548         #
1549         epg_220 = VppGbpEndpointGroup(self, 220, 112, rd1, gbd1,
1550                                       None, self.loop0,
1551                                       "10.0.0.128",
1552                                       "2001:10::128",
1553                                       VppGbpEndpointRetention(2))
1554         epg_220.add_vpp_config()
1555         epg_330 = VppGbpEndpointGroup(self, 330, 113, rd1, gbd1,
1556                                       None, self.loop1,
1557                                       "10.0.1.128",
1558                                       "2001:11::128",
1559                                       VppGbpEndpointRetention(2))
1560         epg_330.add_vpp_config()
1561
1562         #
1563         # The VXLAN GBP tunnel is a bridge-port and has L2 endpoint
1564         # learning enabled
1565         #
1566         vx_tun_l2_1 = VppGbpVxlanTunnel(
1567             self, 99, bd1.bd_id,
1568             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L2,
1569             self.pg2.local_ip4)
1570         vx_tun_l2_1.add_vpp_config()
1571
1572         #
1573         # A static endpoint that the learnt endpoints are trying to
1574         # talk to
1575         #
1576         ep = VppGbpEndpoint(self, self.pg0,
1577                             epg_220, None,
1578                             "10.0.0.127", "11.0.0.127",
1579                             "2001:10::1", "3001::1")
1580         ep.add_vpp_config()
1581
1582         self.assertTrue(find_route(self, ep.ip4.address, 32, table_id=1))
1583
1584         # a packet with an sclass from an unknown EPG
1585         p = (Ether(src=self.pg2.remote_mac,
1586                    dst=self.pg2.local_mac) /
1587              IP(src=self.pg2.remote_hosts[0].ip4,
1588                 dst=self.pg2.local_ip4) /
1589              UDP(sport=1234, dport=48879) /
1590              VXLAN(vni=99, gpid=88, flags=0x88) /
1591              Ether(src=learnt[0]["mac"], dst=ep.mac) /
1592              IP(src=learnt[0]["ip"], dst=ep.ip4.address) /
1593              UDP(sport=1234, dport=1234) /
1594              Raw('\xa5' * 100))
1595
1596         self.send_and_assert_no_replies(self.pg2, p)
1597
1598         self.logger.info(self.vapi.cli("sh error"))
1599         # self.assert_packet_counter_equal(
1600         #    '/err/gbp-policy-port/drop-no-contract', 1)
1601
1602         #
1603         # we should not have learnt a new tunnel endpoint, since
1604         # the EPG was not learnt.
1605         #
1606         self.assertEqual(INDEX_INVALID,
1607                          find_vxlan_gbp_tunnel(self,
1608                                                self.pg2.local_ip4,
1609                                                self.pg2.remote_hosts[0].ip4,
1610                                                99))
1611
1612         # epg is not learnt, because the EPG is unknown
1613         self.assertEqual(len(self.vapi.gbp_endpoint_dump()), 1)
1614
1615         #
1616         # Learn new EPs from IP packets
1617         #
1618         for ii, l in enumerate(learnt):
1619             # a packet with an sclass from a known EPG
1620             # arriving on an unknown TEP
1621             p = (Ether(src=self.pg2.remote_mac,
1622                        dst=self.pg2.local_mac) /
1623                  IP(src=self.pg2.remote_hosts[1].ip4,
1624                     dst=self.pg2.local_ip4) /
1625                  UDP(sport=1234, dport=48879) /
1626                  VXLAN(vni=99, gpid=112, flags=0x88) /
1627                  Ether(src=l['mac'], dst=ep.mac) /
1628                  IP(src=l['ip'], dst=ep.ip4.address) /
1629                  UDP(sport=1234, dport=1234) /
1630                  Raw('\xa5' * 100))
1631
1632             rx = self.send_and_expect(self.pg2, [p], self.pg0)
1633
1634             # the new TEP
1635             tep1_sw_if_index = find_vxlan_gbp_tunnel(
1636                 self,
1637                 self.pg2.local_ip4,
1638                 self.pg2.remote_hosts[1].ip4,
1639                 99)
1640             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
1641
1642             #
1643             # the EP is learnt via the learnt TEP
1644             # both from its MAC and its IP
1645             #
1646             self.assertTrue(find_gbp_endpoint(self,
1647                                               vx_tun_l2_1.sw_if_index,
1648                                               mac=l['mac']))
1649             self.assertTrue(find_gbp_endpoint(self,
1650                                               vx_tun_l2_1.sw_if_index,
1651                                               ip=l['ip']))
1652
1653         # self.assert_packet_counter_equal(
1654         #    '/err/gbp-policy-port/allow-intra-sclass', 2)
1655
1656         self.logger.info(self.vapi.cli("show gbp endpoint"))
1657         self.logger.info(self.vapi.cli("show gbp vxlan"))
1658         self.logger.info(self.vapi.cli("show ip mfib"))
1659
1660         #
1661         # If we sleep for the threshold time, the learnt endpoints should
1662         # age out
1663         #
1664         for l in learnt:
1665             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
1666                                      mac=l['mac'])
1667
1668         #
1669         # Learn new EPs from GARP packets received on the BD's mcast tunnel
1670         #
1671         for ii, l in enumerate(learnt):
1672             # a packet with an sclass from a known EPG
1673             # arriving on an unknown TEP
1674             p = (Ether(src=self.pg2.remote_mac,
1675                        dst=self.pg2.local_mac) /
1676                  IP(src=self.pg2.remote_hosts[1].ip4,
1677                     dst="239.1.1.1") /
1678                  UDP(sport=1234, dport=48879) /
1679                  VXLAN(vni=88, gpid=112, flags=0x88) /
1680                  Ether(src=l['mac'], dst="ff:ff:ff:ff:ff:ff") /
1681                  ARP(op="who-has",
1682                      psrc=l['ip'], pdst=l['ip'],
1683                      hwsrc=l['mac'], hwdst="ff:ff:ff:ff:ff:ff"))
1684
1685             rx = self.send_and_expect(self.pg4, [p], self.pg0)
1686
1687             # the new TEP
1688             tep1_sw_if_index = find_vxlan_gbp_tunnel(
1689                 self,
1690                 self.pg2.local_ip4,
1691                 self.pg2.remote_hosts[1].ip4,
1692                 99)
1693             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
1694
1695             #
1696             # the EP is learnt via the learnt TEP
1697             # both from its MAC and its IP
1698             #
1699             self.assertTrue(find_gbp_endpoint(self,
1700                                               vx_tun_l2_1.sw_if_index,
1701                                               mac=l['mac']))
1702             self.assertTrue(find_gbp_endpoint(self,
1703                                               vx_tun_l2_1.sw_if_index,
1704                                               ip=l['ip']))
1705
1706         #
1707         # wait for the learnt endpoints to age out
1708         #
1709         for l in learnt:
1710             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
1711                                      mac=l['mac'])
1712
1713         #
1714         # Learn new EPs from L2 packets
1715         #
1716         for ii, l in enumerate(learnt):
1717             # a packet with an sclass from a known EPG
1718             # arriving on an unknown TEP
1719             p = (Ether(src=self.pg2.remote_mac,
1720                        dst=self.pg2.local_mac) /
1721                  IP(src=self.pg2.remote_hosts[1].ip4,
1722                     dst=self.pg2.local_ip4) /
1723                  UDP(sport=1234, dport=48879) /
1724                  VXLAN(vni=99, gpid=112, flags=0x88) /
1725                  Ether(src=l['mac'], dst=ep.mac) /
1726                  Raw('\xa5' * 100))
1727
1728             rx = self.send_and_expect(self.pg2, [p], self.pg0)
1729
1730             # the new TEP
1731             tep1_sw_if_index = find_vxlan_gbp_tunnel(
1732                 self,
1733                 self.pg2.local_ip4,
1734                 self.pg2.remote_hosts[1].ip4,
1735                 99)
1736             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
1737
1738             #
1739             # the EP is learnt via the learnt TEP
1740             # both from its MAC and its IP
1741             #
1742             self.assertTrue(find_gbp_endpoint(self,
1743                                               vx_tun_l2_1.sw_if_index,
1744                                               mac=l['mac']))
1745
1746         self.logger.info(self.vapi.cli("show gbp endpoint"))
1747         self.logger.info(self.vapi.cli("show gbp vxlan"))
1748         self.logger.info(self.vapi.cli("show vxlan-gbp tunnel"))
1749
1750         #
1751         # wait for the learnt endpoints to age out
1752         #
1753         for l in learnt:
1754             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
1755                                      mac=l['mac'])
1756
1757         #
1758         # repeat. the do not learn bit is set so the EPs are not learnt
1759         #
1760         for l in learnt:
1761             # a packet with an sclass from a known EPG
1762             p = (Ether(src=self.pg2.remote_mac,
1763                        dst=self.pg2.local_mac) /
1764                  IP(src=self.pg2.remote_hosts[1].ip4,
1765                     dst=self.pg2.local_ip4) /
1766                  UDP(sport=1234, dport=48879) /
1767                  VXLAN(vni=99, gpid=112, flags=0x88, gpflags="D") /
1768                  Ether(src=l['mac'], dst=ep.mac) /
1769                  IP(src=l['ip'], dst=ep.ip4.address) /
1770                  UDP(sport=1234, dport=1234) /
1771                  Raw('\xa5' * 100))
1772
1773             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
1774
1775         for l in learnt:
1776             self.assertFalse(find_gbp_endpoint(self,
1777                                                vx_tun_l2_1.sw_if_index,
1778                                                mac=l['mac']))
1779
1780         #
1781         # repeat
1782         #
1783         for l in learnt:
1784             # a packet with an sclass from a known EPG
1785             p = (Ether(src=self.pg2.remote_mac,
1786                        dst=self.pg2.local_mac) /
1787                  IP(src=self.pg2.remote_hosts[1].ip4,
1788                     dst=self.pg2.local_ip4) /
1789                  UDP(sport=1234, dport=48879) /
1790                  VXLAN(vni=99, gpid=112, flags=0x88) /
1791                  Ether(src=l['mac'], dst=ep.mac) /
1792                  IP(src=l['ip'], dst=ep.ip4.address) /
1793                  UDP(sport=1234, dport=1234) /
1794                  Raw('\xa5' * 100))
1795
1796             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
1797
1798             self.assertTrue(find_gbp_endpoint(self,
1799                                               vx_tun_l2_1.sw_if_index,
1800                                               mac=l['mac']))
1801
1802         #
1803         # Static EP replies to dynamics
1804         #
1805         self.logger.info(self.vapi.cli("sh l2fib bd_id 1"))
1806         for l in learnt:
1807             p = (Ether(src=ep.mac, dst=l['mac']) /
1808                  IP(dst=l['ip'], src=ep.ip4.address) /
1809                  UDP(sport=1234, dport=1234) /
1810                  Raw('\xa5' * 100))
1811
1812             rxs = self.send_and_expect(self.pg0, p * 17, self.pg2)
1813
1814             for rx in rxs:
1815                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
1816                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
1817                 self.assertEqual(rx[UDP].dport, 48879)
1818                 # the UDP source port is a random value for hashing
1819                 self.assertEqual(rx[VXLAN].gpid, 112)
1820                 self.assertEqual(rx[VXLAN].vni, 99)
1821                 self.assertTrue(rx[VXLAN].flags.G)
1822                 self.assertTrue(rx[VXLAN].flags.Instance)
1823                 self.assertTrue(rx[VXLAN].gpflags.A)
1824                 self.assertFalse(rx[VXLAN].gpflags.D)
1825
1826         for l in learnt:
1827             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
1828                                      mac=l['mac'])
1829
1830         #
1831         # repeat in the other EPG
1832         # there's no contract between 220 and 330, but the A-bit is set
1833         # so the packet is cleared for delivery
1834         #
1835         for l in learnt:
1836             # a packet with an sclass from a known EPG
1837             p = (Ether(src=self.pg2.remote_mac,
1838                        dst=self.pg2.local_mac) /
1839                  IP(src=self.pg2.remote_hosts[1].ip4,
1840                     dst=self.pg2.local_ip4) /
1841                  UDP(sport=1234, dport=48879) /
1842                  VXLAN(vni=99, gpid=113, flags=0x88, gpflags='A') /
1843                  Ether(src=l['mac'], dst=ep.mac) /
1844                  IP(src=l['ip'], dst=ep.ip4.address) /
1845                  UDP(sport=1234, dport=1234) /
1846                  Raw('\xa5' * 100))
1847
1848             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
1849
1850             self.assertTrue(find_gbp_endpoint(self,
1851                                               vx_tun_l2_1.sw_if_index,
1852                                               mac=l['mac']))
1853
1854         #
1855         # static EP cannot reach the learnt EPs since there is no contract
1856         # only test 1 EP as the others could timeout
1857         #
1858         p = (Ether(src=ep.mac, dst=l['mac']) /
1859              IP(dst=learnt[0]['ip'], src=ep.ip4.address) /
1860              UDP(sport=1234, dport=1234) /
1861              Raw('\xa5' * 100))
1862
1863         self.send_and_assert_no_replies(self.pg0, [p])
1864
1865         #
1866         # refresh the entries after the check for no replies above
1867         #
1868         for l in learnt:
1869             # a packet with an sclass from a known EPG
1870             p = (Ether(src=self.pg2.remote_mac,
1871                        dst=self.pg2.local_mac) /
1872                  IP(src=self.pg2.remote_hosts[1].ip4,
1873                     dst=self.pg2.local_ip4) /
1874                  UDP(sport=1234, dport=48879) /
1875                  VXLAN(vni=99, gpid=113, flags=0x88, gpflags='A') /
1876                  Ether(src=l['mac'], dst=ep.mac) /
1877                  IP(src=l['ip'], dst=ep.ip4.address) /
1878                  UDP(sport=1234, dport=1234) /
1879                  Raw('\xa5' * 100))
1880
1881             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
1882
1883             self.assertTrue(find_gbp_endpoint(self,
1884                                               vx_tun_l2_1.sw_if_index,
1885                                               mac=l['mac']))
1886
1887         #
1888         # Add the contract so they can talk
1889         #
1890         acl = VppGbpAcl(self)
1891         rule = acl.create_rule(permit_deny=1, proto=17)
1892         rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
1893         acl_index = acl.add_vpp_config([rule, rule2])
1894         c1 = VppGbpContract(
1895             self, epg_220.sclass, epg_330.sclass, acl_index,
1896             [VppGbpContractRule(
1897                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1898                 []),
1899                 VppGbpContractRule(
1900                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
1901                     [])],
1902             [ETH_P_IP, ETH_P_IPV6])
1903         c1.add_vpp_config()
1904
1905         for l in learnt:
1906             p = (Ether(src=ep.mac, dst=l['mac']) /
1907                  IP(dst=l['ip'], src=ep.ip4.address) /
1908                  UDP(sport=1234, dport=1234) /
1909                  Raw('\xa5' * 100))
1910
1911             self.send_and_expect(self.pg0, [p], self.pg2)
1912
1913         #
1914         # send UU packets from the local EP
1915         #
1916         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1917         self.logger.info(self.vapi.cli("sh gbp bridge"))
1918         p_uu = (Ether(src=ep.mac, dst="00:11:11:11:11:11") /
1919                 IP(dst="10.0.0.133", src=ep.ip4.address) /
1920                 UDP(sport=1234, dport=1234) /
1921                 Raw('\xa5' * 100))
1922         rxs = self.send_and_expect(ep.itf, [p_uu], gbd1.uu_fwd)
1923
1924         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
1925
1926         p_bm = (Ether(src=ep.mac, dst="ff:ff:ff:ff:ff:ff") /
1927                 IP(dst="10.0.0.133", src=ep.ip4.address) /
1928                 UDP(sport=1234, dport=1234) /
1929                 Raw('\xa5' * 100))
1930         rxs = self.send_and_expect_only(ep.itf, [p_bm], tun_bm.mcast_itf)
1931
1932         for rx in rxs:
1933             self.assertEqual(rx[IP].src, self.pg4.local_ip4)
1934             self.assertEqual(rx[IP].dst, "239.1.1.1")
1935             self.assertEqual(rx[UDP].dport, 48879)
1936             # the UDP source port is a random value for hashing
1937             self.assertEqual(rx[VXLAN].gpid, 112)
1938             self.assertEqual(rx[VXLAN].vni, 88)
1939             self.assertTrue(rx[VXLAN].flags.G)
1940             self.assertTrue(rx[VXLAN].flags.Instance)
1941             self.assertFalse(rx[VXLAN].gpflags.A)
1942             self.assertFalse(rx[VXLAN].gpflags.D)
1943
1944         #
1945         # Check v6 Endpoints
1946         #
1947         for l in learnt:
1948             # a packet with an sclass from a known EPG
1949             p = (Ether(src=self.pg2.remote_mac,
1950                        dst=self.pg2.local_mac) /
1951                  IP(src=self.pg2.remote_hosts[1].ip4,
1952                     dst=self.pg2.local_ip4) /
1953                  UDP(sport=1234, dport=48879) /
1954                  VXLAN(vni=99, gpid=113, flags=0x88, gpflags='A') /
1955                  Ether(src=l['mac'], dst=ep.mac) /
1956                  IPv6(src=l['ip6'], dst=ep.ip6.address) /
1957                  UDP(sport=1234, dport=1234) /
1958                  Raw('\xa5' * 100))
1959
1960             rx = self.send_and_expect(self.pg2, p * NUM_PKTS, self.pg0)
1961
1962             self.assertTrue(find_gbp_endpoint(self,
1963                                               vx_tun_l2_1.sw_if_index,
1964                                               mac=l['mac']))
1965
1966         #
1967         # L3 Endpoint Learning
1968         #  - configured on the bridge's BVI
1969         #
1970
1971         #
1972         # clean up
1973         #
1974         for l in learnt:
1975             self.wait_for_ep_timeout(vx_tun_l2_1.sw_if_index,
1976                                      mac=l['mac'])
1977         self.pg2.unconfig_ip4()
1978         self.pg3.unconfig_ip4()
1979         self.pg4.unconfig_ip4()
1980
1981         self.logger.info(self.vapi.cli("sh int"))
1982         self.logger.info(self.vapi.cli("sh gbp vxlan"))
1983
1984     def test_gbp_contract(self):
1985         """ GBP CONTRACTS """
1986
1987         #
1988         # Bridge Domains
1989         #
1990         bd1 = VppBridgeDomain(self, 1, arp_term=0)
1991         bd2 = VppBridgeDomain(self, 2, arp_term=0)
1992
1993         bd1.add_vpp_config()
1994         bd2.add_vpp_config()
1995
1996         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0)
1997         gbd2 = VppGbpBridgeDomain(self, bd2, self.loop1)
1998
1999         gbd1.add_vpp_config()
2000         gbd2.add_vpp_config()
2001
2002         #
2003         # Route Domains
2004         #
2005         gt4 = VppIpTable(self, 0)
2006         gt4.add_vpp_config()
2007         gt6 = VppIpTable(self, 0, is_ip6=True)
2008         gt6.add_vpp_config()
2009
2010         rd0 = VppGbpRouteDomain(self, 0, gt4, gt6, None, None)
2011
2012         rd0.add_vpp_config()
2013
2014         #
2015         # 3 EPGs, 2 of which share a BD.
2016         #
2017         epgs = [VppGbpEndpointGroup(self, 220, 1220, rd0, gbd1,
2018                                     None, self.loop0,
2019                                     "10.0.0.128", "2001:10::128"),
2020                 VppGbpEndpointGroup(self, 221, 1221, rd0, gbd1,
2021                                     None, self.loop0,
2022                                     "10.0.1.128", "2001:10:1::128"),
2023                 VppGbpEndpointGroup(self, 222, 1222, rd0, gbd2,
2024                                     None, self.loop1,
2025                                     "10.0.2.128", "2001:10:2::128")]
2026         #
2027         # 4 end-points, 2 in the same subnet, 3 in the same BD
2028         #
2029         eps = [VppGbpEndpoint(self, self.pg0,
2030                               epgs[0], None,
2031                               "10.0.0.1", "11.0.0.1",
2032                               "2001:10::1", "3001::1"),
2033                VppGbpEndpoint(self, self.pg1,
2034                               epgs[0], None,
2035                               "10.0.0.2", "11.0.0.2",
2036                               "2001:10::2", "3001::2"),
2037                VppGbpEndpoint(self, self.pg2,
2038                               epgs[1], None,
2039                               "10.0.1.1", "11.0.0.3",
2040                               "2001:10:1::1", "3001::3"),
2041                VppGbpEndpoint(self, self.pg3,
2042                               epgs[2], None,
2043                               "10.0.2.1", "11.0.0.4",
2044                               "2001:10:2::1", "3001::4")]
2045
2046         #
2047         # Config related to each of the EPGs
2048         #
2049         for epg in epgs:
2050             # IP config on the BVI interfaces
2051             if epg != epgs[1]:
2052                 VppIpInterfaceBind(self, epg.bvi, epg.rd.t4).add_vpp_config()
2053                 VppIpInterfaceBind(self, epg.bvi, epg.rd.t6).add_vpp_config()
2054                 self.vapi.sw_interface_set_mac_address(
2055                     epg.bvi.sw_if_index,
2056                     self.router_mac.packed)
2057
2058             if_ip4 = VppIpInterfaceAddress(self, epg.bvi, epg.bvi_ip4, 32)
2059             if_ip6 = VppIpInterfaceAddress(self, epg.bvi, epg.bvi_ip6, 128)
2060             if_ip4.add_vpp_config()
2061             if_ip6.add_vpp_config()
2062
2063             # add the BD ARP termination entry for BVI IP
2064             epg.bd_arp_ip4 = VppBridgeDomainArpEntry(self, epg.bd.bd,
2065                                                      str(self.router_mac),
2066                                                      epg.bvi_ip4)
2067             epg.bd_arp_ip4.add_vpp_config()
2068
2069             # EPG in VPP
2070             epg.add_vpp_config()
2071
2072         #
2073         # config ep
2074         #
2075         for ep in eps:
2076             ep.add_vpp_config()
2077
2078         self.logger.info(self.vapi.cli("show gbp endpoint"))
2079         self.logger.info(self.vapi.cli("show interface"))
2080         self.logger.info(self.vapi.cli("show br"))
2081
2082         #
2083         # Intra epg allowed without contract
2084         #
2085         pkt_intra_epg_220_to_220 = (Ether(src=self.pg0.remote_mac,
2086                                           dst=self.pg1.remote_mac) /
2087                                     IP(src=eps[0].ip4.address,
2088                                        dst=eps[1].ip4.address) /
2089                                     UDP(sport=1234, dport=1234) /
2090                                     Raw('\xa5' * 100))
2091
2092         self.send_and_expect_bridged(self.pg0,
2093                                      pkt_intra_epg_220_to_220 * 65,
2094                                      self.pg1)
2095
2096         #
2097         # Inter epg denied without contract
2098         #
2099         pkt_inter_epg_220_to_221 = (Ether(src=self.pg0.remote_mac,
2100                                           dst=self.pg2.remote_mac) /
2101                                     IP(src=eps[0].ip4.address,
2102                                        dst=eps[2].ip4.address) /
2103                                     UDP(sport=1234, dport=1234) /
2104                                     Raw('\xa5' * 100))
2105
2106         self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_220_to_221)
2107
2108         #
2109         # A uni-directional contract from EPG 220 -> 221
2110         #
2111         acl = VppGbpAcl(self)
2112         rule = acl.create_rule(permit_deny=1, proto=17)
2113         rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
2114         acl_index = acl.add_vpp_config([rule, rule2])
2115         c1 = VppGbpContract(
2116             self, epgs[0].sclass, epgs[1].sclass, acl_index,
2117             [VppGbpContractRule(
2118                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2119                 []),
2120              VppGbpContractRule(
2121                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2122                  [])],
2123             [ETH_P_IP, ETH_P_IPV6])
2124         c1.add_vpp_config()
2125
2126         self.send_and_expect_bridged(eps[0].itf,
2127                                      pkt_inter_epg_220_to_221 * 65,
2128                                      eps[2].itf)
2129
2130         pkt_inter_epg_220_to_222 = (Ether(src=self.pg0.remote_mac,
2131                                           dst=str(self.router_mac)) /
2132                                     IP(src=eps[0].ip4.address,
2133                                        dst=eps[3].ip4.address) /
2134                                     UDP(sport=1234, dport=1234) /
2135                                     Raw('\xa5' * 100))
2136         self.send_and_assert_no_replies(eps[0].itf,
2137                                         pkt_inter_epg_220_to_222 * 65)
2138
2139         #
2140         # contract for the return direction
2141         #
2142         c2 = VppGbpContract(
2143             self, epgs[1].sclass, epgs[0].sclass, acl_index,
2144             [VppGbpContractRule(
2145                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2146                 []),
2147              VppGbpContractRule(
2148                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2149                  [])],
2150             [ETH_P_IP, ETH_P_IPV6])
2151         c2.add_vpp_config()
2152
2153         self.send_and_expect_bridged(eps[0].itf,
2154                                      pkt_inter_epg_220_to_221 * 65,
2155                                      eps[2].itf)
2156         pkt_inter_epg_221_to_220 = (Ether(src=self.pg2.remote_mac,
2157                                           dst=self.pg0.remote_mac) /
2158                                     IP(src=eps[2].ip4.address,
2159                                        dst=eps[0].ip4.address) /
2160                                     UDP(sport=1234, dport=1234) /
2161                                     Raw('\xa5' * 100))
2162         self.send_and_expect_bridged(eps[2].itf,
2163                                      pkt_inter_epg_221_to_220 * 65,
2164                                      eps[0].itf)
2165
2166         #
2167         # contract between 220 and 222 uni-direction
2168         #
2169         c3 = VppGbpContract(
2170             self, epgs[0].sclass, epgs[2].sclass, acl_index,
2171             [VppGbpContractRule(
2172                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2173                 []),
2174              VppGbpContractRule(
2175                  VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
2176                  [])],
2177             [ETH_P_IP, ETH_P_IPV6])
2178         c3.add_vpp_config()
2179
2180         self.send_and_expect(eps[0].itf,
2181                              pkt_inter_epg_220_to_222 * 65,
2182                              eps[3].itf)
2183
2184         c3.remove_vpp_config()
2185         c1.remove_vpp_config()
2186         c2.remove_vpp_config()
2187         acl.remove_vpp_config()
2188
2189     def test_gbp_bd_flags(self):
2190         """ GBP BD FLAGS """
2191
2192         #
2193         # IP tables
2194         #
2195         gt4 = VppIpTable(self, 1)
2196         gt4.add_vpp_config()
2197         gt6 = VppIpTable(self, 1, is_ip6=True)
2198         gt6.add_vpp_config()
2199
2200         rd1 = VppGbpRouteDomain(self, 1, gt4, gt6)
2201         rd1.add_vpp_config()
2202
2203         #
2204         # Pg3 hosts the IP4 UU-flood VXLAN tunnel
2205         # Pg4 hosts the IP6 UU-flood VXLAN tunnel
2206         #
2207         self.pg3.config_ip4()
2208         self.pg3.resolve_arp()
2209         self.pg4.config_ip4()
2210         self.pg4.resolve_arp()
2211
2212         #
2213         # Add a mcast destination VXLAN-GBP tunnel for B&M traffic
2214         #
2215         tun_bm = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
2216                                    "239.1.1.1", 88,
2217                                    mcast_itf=self.pg4)
2218         tun_bm.add_vpp_config()
2219
2220         #
2221         # a GBP bridge domain with a BVI and a UU-flood interface
2222         #
2223         bd1 = VppBridgeDomain(self, 1)
2224         bd1.add_vpp_config()
2225
2226         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0, self.pg3, tun_bm,
2227                                   uu_drop=True, bm_drop=True)
2228         gbd1.add_vpp_config()
2229
2230         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
2231         self.logger.info(self.vapi.cli("sh gbp bridge"))
2232
2233         # ... and has a /32 applied
2234         ip_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
2235         ip_addr.add_vpp_config()
2236
2237         #
2238         # The Endpoint-group
2239         #
2240         epg_220 = VppGbpEndpointGroup(self, 220, 112, rd1, gbd1,
2241                                       None, self.loop0,
2242                                       "10.0.0.128",
2243                                       "2001:10::128",
2244                                       VppGbpEndpointRetention(2))
2245         epg_220.add_vpp_config()
2246
2247         ep = VppGbpEndpoint(self, self.pg0,
2248                             epg_220, None,
2249                             "10.0.0.127", "11.0.0.127",
2250                             "2001:10::1", "3001::1")
2251         ep.add_vpp_config()
2252         #
2253         # send UU/BM packet from the local EP with UU drop and BM drop enabled
2254         # in bd
2255         #
2256         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
2257         self.logger.info(self.vapi.cli("sh gbp bridge"))
2258         p_uu = (Ether(src=ep.mac, dst="00:11:11:11:11:11") /
2259                 IP(dst="10.0.0.133", src=ep.ip4.address) /
2260                 UDP(sport=1234, dport=1234) /
2261                 Raw('\xa5' * 100))
2262         self.send_and_assert_no_replies(ep.itf, [p_uu])
2263
2264         p_bm = (Ether(src=ep.mac, dst="ff:ff:ff:ff:ff:ff") /
2265                 IP(dst="10.0.0.133", src=ep.ip4.address) /
2266                 UDP(sport=1234, dport=1234) /
2267                 Raw('\xa5' * 100))
2268         self.send_and_assert_no_replies(ep.itf, [p_bm])
2269
2270         self.pg3.unconfig_ip4()
2271         self.pg4.unconfig_ip4()
2272
2273         self.logger.info(self.vapi.cli("sh int"))
2274
2275     def test_gbp_learn_vlan_l2(self):
2276         """ GBP L2 Endpoint w/ VLANs"""
2277
2278         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
2279         learnt = [{'mac': '00:00:11:11:11:01',
2280                    'ip': '10.0.0.1',
2281                    'ip6': '2001:10::2'},
2282                   {'mac': '00:00:11:11:11:02',
2283                    'ip': '10.0.0.2',
2284                    'ip6': '2001:10::3'}]
2285
2286         #
2287         # IP tables
2288         #
2289         gt4 = VppIpTable(self, 1)
2290         gt4.add_vpp_config()
2291         gt6 = VppIpTable(self, 1, is_ip6=True)
2292         gt6.add_vpp_config()
2293
2294         rd1 = VppGbpRouteDomain(self, 1, gt4, gt6)
2295         rd1.add_vpp_config()
2296
2297         #
2298         # Pg2 hosts the vxlan tunnel, hosts on pg2 to act as TEPs
2299         #
2300         self.pg2.config_ip4()
2301         self.pg2.resolve_arp()
2302         self.pg2.generate_remote_hosts(4)
2303         self.pg2.configure_ipv4_neighbors()
2304         self.pg3.config_ip4()
2305         self.pg3.resolve_arp()
2306
2307         #
2308         # The EP will be on a vlan sub-interface
2309         #
2310         vlan_11 = VppDot1QSubint(self, self.pg0, 11)
2311         vlan_11.admin_up()
2312         self.vapi.l2_interface_vlan_tag_rewrite(
2313             sw_if_index=vlan_11.sw_if_index, vtr_op=L2_VTR_OP.L2_POP_1,
2314             push_dot1q=11)
2315
2316         bd_uu_fwd = VppVxlanGbpTunnel(self, self.pg3.local_ip4,
2317                                       self.pg3.remote_ip4, 116)
2318         bd_uu_fwd.add_vpp_config()
2319
2320         #
2321         # a GBP bridge domain with a BVI and a UU-flood interface
2322         # The BD is marked as do not learn, so no endpoints are ever
2323         # learnt in this BD.
2324         #
2325         bd1 = VppBridgeDomain(self, 1)
2326         bd1.add_vpp_config()
2327         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0, bd_uu_fwd,
2328                                   learn=False)
2329         gbd1.add_vpp_config()
2330
2331         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
2332         self.logger.info(self.vapi.cli("sh gbp bridge"))
2333
2334         # ... and has a /32 applied
2335         ip_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
2336         ip_addr.add_vpp_config()
2337
2338         #
2339         # The Endpoint-group in which we are learning endpoints
2340         #
2341         epg_220 = VppGbpEndpointGroup(self, 220, 441, rd1, gbd1,
2342                                       None, self.loop0,
2343                                       "10.0.0.128",
2344                                       "2001:10::128",
2345                                       VppGbpEndpointRetention(2))
2346         epg_220.add_vpp_config()
2347
2348         #
2349         # The VXLAN GBP tunnel is a bridge-port and has L2 endpoint
2350         # learning enabled
2351         #
2352         vx_tun_l2_1 = VppGbpVxlanTunnel(
2353             self, 99, bd1.bd_id,
2354             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L2,
2355             self.pg2.local_ip4)
2356         vx_tun_l2_1.add_vpp_config()
2357
2358         #
2359         # A static endpoint that the learnt endpoints are trying to
2360         # talk to
2361         #
2362         ep = VppGbpEndpoint(self, vlan_11,
2363                             epg_220, None,
2364                             "10.0.0.127", "11.0.0.127",
2365                             "2001:10::1", "3001::1")
2366         ep.add_vpp_config()
2367
2368         self.assertTrue(find_route(self, ep.ip4.address, 32, table_id=1))
2369
2370         #
2371         # Send to the static EP
2372         #
2373         for ii, l in enumerate(learnt):
2374             # a packet with an sclass from a known EPG
2375             # arriving on an unknown TEP
2376             p = (Ether(src=self.pg2.remote_mac,
2377                        dst=self.pg2.local_mac) /
2378                  IP(src=self.pg2.remote_hosts[1].ip4,
2379                     dst=self.pg2.local_ip4) /
2380                  UDP(sport=1234, dport=48879) /
2381                  VXLAN(vni=99, gpid=441, flags=0x88) /
2382                  Ether(src=l['mac'], dst=ep.mac) /
2383                  IP(src=l['ip'], dst=ep.ip4.address) /
2384                  UDP(sport=1234, dport=1234) /
2385                  Raw('\xa5' * 100))
2386
2387             rxs = self.send_and_expect(self.pg2, [p], self.pg0)
2388
2389             #
2390             # packet to EP has the EP's vlan tag
2391             #
2392             for rx in rxs:
2393                 self.assertEqual(rx[Dot1Q].vlan, 11)
2394
2395             #
2396             # the EP is not learnt since the BD setting prevents it
2397             # also no TEP too
2398             #
2399             self.assertFalse(find_gbp_endpoint(self,
2400                                                vx_tun_l2_1.sw_if_index,
2401                                                mac=l['mac']))
2402             self.assertEqual(INDEX_INVALID,
2403                              find_vxlan_gbp_tunnel(
2404                                  self,
2405                                  self.pg2.local_ip4,
2406                                  self.pg2.remote_hosts[1].ip4,
2407                                  99))
2408
2409         self.assertEqual(len(self.vapi.gbp_endpoint_dump()), 1)
2410
2411         #
2412         # static to remotes
2413         # we didn't learn the remotes so they are sent to the UU-fwd
2414         #
2415         for l in learnt:
2416             p = (Ether(src=ep.mac, dst=l['mac']) /
2417                  Dot1Q(vlan=11) /
2418                  IP(dst=l['ip'], src=ep.ip4.address) /
2419                  UDP(sport=1234, dport=1234) /
2420                  Raw('\xa5' * 100))
2421
2422             rxs = self.send_and_expect(self.pg0, p * 17, self.pg3)
2423
2424             for rx in rxs:
2425                 self.assertEqual(rx[IP].src, self.pg3.local_ip4)
2426                 self.assertEqual(rx[IP].dst, self.pg3.remote_ip4)
2427                 self.assertEqual(rx[UDP].dport, 48879)
2428                 # the UDP source port is a random value for hashing
2429                 self.assertEqual(rx[VXLAN].gpid, 441)
2430                 self.assertEqual(rx[VXLAN].vni, 116)
2431                 self.assertTrue(rx[VXLAN].flags.G)
2432                 self.assertTrue(rx[VXLAN].flags.Instance)
2433                 self.assertFalse(rx[VXLAN].gpflags.A)
2434                 self.assertFalse(rx[VXLAN].gpflags.D)
2435
2436         self.pg2.unconfig_ip4()
2437         self.pg3.unconfig_ip4()
2438
2439     def test_gbp_learn_l3(self):
2440         """ GBP L3 Endpoint Learning """
2441
2442         self.vapi.cli("set logging class gbp level debug")
2443
2444         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
2445         routed_dst_mac = "00:0c:0c:0c:0c:0c"
2446         routed_src_mac = "00:22:bd:f8:19:ff"
2447
2448         learnt = [{'mac': '00:00:11:11:11:02',
2449                    'ip': '10.0.1.2',
2450                    'ip6': '2001:10::2'},
2451                   {'mac': '00:00:11:11:11:03',
2452                    'ip': '10.0.1.3',
2453                    'ip6': '2001:10::3'}]
2454
2455         #
2456         # IP tables
2457         #
2458         t4 = VppIpTable(self, 1)
2459         t4.add_vpp_config()
2460         t6 = VppIpTable(self, 1, True)
2461         t6.add_vpp_config()
2462
2463         tun_ip4_uu = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
2464                                        self.pg4.remote_ip4, 114)
2465         tun_ip6_uu = VppVxlanGbpTunnel(self, self.pg4.local_ip4,
2466                                        self.pg4.remote_ip4, 116)
2467         tun_ip4_uu.add_vpp_config()
2468         tun_ip6_uu.add_vpp_config()
2469
2470         rd1 = VppGbpRouteDomain(self, 2, t4, t6, tun_ip4_uu, tun_ip6_uu)
2471         rd1.add_vpp_config()
2472
2473         self.loop0.set_mac(self.router_mac)
2474
2475         #
2476         # Bind the BVI to the RD
2477         #
2478         VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
2479         VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
2480
2481         #
2482         # Pg2 hosts the vxlan tunnel
2483         # hosts on pg2 to act as TEPs
2484         # pg3 is BD uu-fwd
2485         # pg4 is RD uu-fwd
2486         #
2487         self.pg2.config_ip4()
2488         self.pg2.resolve_arp()
2489         self.pg2.generate_remote_hosts(4)
2490         self.pg2.configure_ipv4_neighbors()
2491         self.pg3.config_ip4()
2492         self.pg3.resolve_arp()
2493         self.pg4.config_ip4()
2494         self.pg4.resolve_arp()
2495
2496         #
2497         # a GBP bridge domain with a BVI and a UU-flood interface
2498         #
2499         bd1 = VppBridgeDomain(self, 1)
2500         bd1.add_vpp_config()
2501         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0, self.pg3)
2502         gbd1.add_vpp_config()
2503
2504         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
2505         self.logger.info(self.vapi.cli("sh gbp bridge"))
2506         self.logger.info(self.vapi.cli("sh gbp route"))
2507
2508         # ... and has a /32 and /128 applied
2509         ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
2510         ip4_addr.add_vpp_config()
2511         ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128", 128)
2512         ip6_addr.add_vpp_config()
2513
2514         #
2515         # The Endpoint-group in which we are learning endpoints
2516         #
2517         epg_220 = VppGbpEndpointGroup(self, 220, 441, rd1, gbd1,
2518                                       None, self.loop0,
2519                                       "10.0.0.128",
2520                                       "2001:10::128",
2521                                       VppGbpEndpointRetention(2))
2522         epg_220.add_vpp_config()
2523
2524         #
2525         # The VXLAN GBP tunnel is a bridge-port and has L2 endpoint
2526         # learning enabled
2527         #
2528         vx_tun_l3 = VppGbpVxlanTunnel(
2529             self, 101, rd1.rd_id,
2530             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3,
2531             self.pg2.local_ip4)
2532         vx_tun_l3.add_vpp_config()
2533
2534         #
2535         # A static endpoint that the learnt endpoints are trying to
2536         # talk to
2537         #
2538         ep = VppGbpEndpoint(self, self.pg0,
2539                             epg_220, None,
2540                             "10.0.0.127", "11.0.0.127",
2541                             "2001:10::1", "3001::1")
2542         ep.add_vpp_config()
2543
2544         #
2545         # learn some remote IPv4 EPs
2546         #
2547         for ii, l in enumerate(learnt):
2548             # a packet with an sclass from a known EPG
2549             # arriving on an unknown TEP
2550             p = (Ether(src=self.pg2.remote_mac,
2551                        dst=self.pg2.local_mac) /
2552                  IP(src=self.pg2.remote_hosts[1].ip4,
2553                     dst=self.pg2.local_ip4) /
2554                  UDP(sport=1234, dport=48879) /
2555                  VXLAN(vni=101, gpid=441, flags=0x88) /
2556                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
2557                  IP(src=l['ip'], dst=ep.ip4.address) /
2558                  UDP(sport=1234, dport=1234) /
2559                  Raw('\xa5' * 100))
2560
2561             rx = self.send_and_expect(self.pg2, [p], self.pg0)
2562
2563             # the new TEP
2564             tep1_sw_if_index = find_vxlan_gbp_tunnel(
2565                 self,
2566                 self.pg2.local_ip4,
2567                 self.pg2.remote_hosts[1].ip4,
2568                 vx_tun_l3.vni)
2569             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
2570
2571             # endpoint learnt via the parent GBP-vxlan interface
2572             self.assertTrue(find_gbp_endpoint(self,
2573                                               vx_tun_l3._sw_if_index,
2574                                               ip=l['ip']))
2575
2576         #
2577         # Static IPv4 EP replies to learnt
2578         #
2579         for l in learnt:
2580             p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2581                  IP(dst=l['ip'], src=ep.ip4.address) /
2582                  UDP(sport=1234, dport=1234) /
2583                  Raw('\xa5' * 100))
2584
2585             rxs = self.send_and_expect(self.pg0, p * 1, self.pg2)
2586
2587             for rx in rxs:
2588                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2589                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
2590                 self.assertEqual(rx[UDP].dport, 48879)
2591                 # the UDP source port is a random value for hashing
2592                 self.assertEqual(rx[VXLAN].gpid, 441)
2593                 self.assertEqual(rx[VXLAN].vni, 101)
2594                 self.assertTrue(rx[VXLAN].flags.G)
2595                 self.assertTrue(rx[VXLAN].flags.Instance)
2596                 self.assertTrue(rx[VXLAN].gpflags.A)
2597                 self.assertFalse(rx[VXLAN].gpflags.D)
2598
2599                 inner = rx[VXLAN].payload
2600
2601                 self.assertEqual(inner[Ether].src, routed_src_mac)
2602                 self.assertEqual(inner[Ether].dst, routed_dst_mac)
2603                 self.assertEqual(inner[IP].src, ep.ip4.address)
2604                 self.assertEqual(inner[IP].dst, l['ip'])
2605
2606         for l in learnt:
2607             self.assertFalse(find_gbp_endpoint(self,
2608                                                tep1_sw_if_index,
2609                                                ip=l['ip']))
2610
2611         #
2612         # learn some remote IPv6 EPs
2613         #
2614         for ii, l in enumerate(learnt):
2615             # a packet with an sclass from a known EPG
2616             # arriving on an unknown TEP
2617             p = (Ether(src=self.pg2.remote_mac,
2618                        dst=self.pg2.local_mac) /
2619                  IP(src=self.pg2.remote_hosts[1].ip4,
2620                     dst=self.pg2.local_ip4) /
2621                  UDP(sport=1234, dport=48879) /
2622                  VXLAN(vni=101, gpid=441, flags=0x88) /
2623                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
2624                  IPv6(src=l['ip6'], dst=ep.ip6.address) /
2625                  UDP(sport=1234, dport=1234) /
2626                  Raw('\xa5' * 100))
2627
2628             rx = self.send_and_expect(self.pg2, [p], self.pg0)
2629
2630             # the new TEP
2631             tep1_sw_if_index = find_vxlan_gbp_tunnel(
2632                 self,
2633                 self.pg2.local_ip4,
2634                 self.pg2.remote_hosts[1].ip4,
2635                 vx_tun_l3.vni)
2636             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
2637
2638             self.logger.info(self.vapi.cli("show gbp bridge"))
2639             self.logger.info(self.vapi.cli("show vxlan-gbp tunnel"))
2640             self.logger.info(self.vapi.cli("show gbp vxlan"))
2641             self.logger.info(self.vapi.cli("show int addr"))
2642
2643             # endpoint learnt via the TEP
2644             self.assertTrue(find_gbp_endpoint(self, ip=l['ip6']))
2645
2646         self.logger.info(self.vapi.cli("show gbp endpoint"))
2647         self.logger.info(self.vapi.cli("show ip fib index 1 %s" % l['ip']))
2648
2649         #
2650         # Static EP replies to learnt
2651         #
2652         for l in learnt:
2653             p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2654                  IPv6(dst=l['ip6'], src=ep.ip6.address) /
2655                  UDP(sport=1234, dport=1234) /
2656                  Raw('\xa5' * 100))
2657
2658             rxs = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg2)
2659
2660             for rx in rxs:
2661                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2662                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
2663                 self.assertEqual(rx[UDP].dport, 48879)
2664                 # the UDP source port is a random value for hashing
2665                 self.assertEqual(rx[VXLAN].gpid, 441)
2666                 self.assertEqual(rx[VXLAN].vni, 101)
2667                 self.assertTrue(rx[VXLAN].flags.G)
2668                 self.assertTrue(rx[VXLAN].flags.Instance)
2669                 self.assertTrue(rx[VXLAN].gpflags.A)
2670                 self.assertFalse(rx[VXLAN].gpflags.D)
2671
2672                 inner = rx[VXLAN].payload
2673
2674                 self.assertEqual(inner[Ether].src, routed_src_mac)
2675                 self.assertEqual(inner[Ether].dst, routed_dst_mac)
2676                 self.assertEqual(inner[IPv6].src, ep.ip6.address)
2677                 self.assertEqual(inner[IPv6].dst, l['ip6'])
2678
2679         self.logger.info(self.vapi.cli("sh gbp endpoint"))
2680         for l in learnt:
2681             self.wait_for_ep_timeout(ip=l['ip'])
2682
2683         #
2684         # Static sends to unknown EP with no route
2685         #
2686         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2687              IP(dst="10.0.0.99", src=ep.ip4.address) /
2688              UDP(sport=1234, dport=1234) /
2689              Raw('\xa5' * 100))
2690
2691         self.send_and_assert_no_replies(self.pg0, [p])
2692
2693         #
2694         # Add a route to static EP's v4 and v6 subnet
2695         #  packets should be sent on the v4/v6 uu=fwd interface resp.
2696         #
2697         se_10_24 = VppGbpSubnet(
2698             self, rd1, "10.0.0.0", 24,
2699             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_TRANSPORT)
2700         se_10_24.add_vpp_config()
2701
2702         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2703              IP(dst="10.0.0.99", src=ep.ip4.address) /
2704              UDP(sport=1234, dport=1234) /
2705              Raw('\xa5' * 100))
2706
2707         rxs = self.send_and_expect(self.pg0, [p], self.pg4)
2708         for rx in rxs:
2709             self.assertEqual(rx[IP].src, self.pg4.local_ip4)
2710             self.assertEqual(rx[IP].dst, self.pg4.remote_ip4)
2711             self.assertEqual(rx[UDP].dport, 48879)
2712             # the UDP source port is a random value for hashing
2713             self.assertEqual(rx[VXLAN].gpid, 441)
2714             self.assertEqual(rx[VXLAN].vni, 114)
2715             self.assertTrue(rx[VXLAN].flags.G)
2716             self.assertTrue(rx[VXLAN].flags.Instance)
2717             # policy is not applied to packets sent to the uu-fwd interfaces
2718             self.assertFalse(rx[VXLAN].gpflags.A)
2719             self.assertFalse(rx[VXLAN].gpflags.D)
2720
2721         #
2722         # learn some remote IPv4 EPs
2723         #
2724         for ii, l in enumerate(learnt):
2725             # a packet with an sclass from a known EPG
2726             # arriving on an unknown TEP
2727             p = (Ether(src=self.pg2.remote_mac,
2728                        dst=self.pg2.local_mac) /
2729                  IP(src=self.pg2.remote_hosts[2].ip4,
2730                     dst=self.pg2.local_ip4) /
2731                  UDP(sport=1234, dport=48879) /
2732                  VXLAN(vni=101, gpid=441, flags=0x88) /
2733                  Ether(src=l['mac'], dst="00:00:00:11:11:11") /
2734                  IP(src=l['ip'], dst=ep.ip4.address) /
2735                  UDP(sport=1234, dport=1234) /
2736                  Raw('\xa5' * 100))
2737
2738             rx = self.send_and_expect(self.pg2, [p], self.pg0)
2739
2740             # the new TEP
2741             tep1_sw_if_index = find_vxlan_gbp_tunnel(
2742                 self,
2743                 self.pg2.local_ip4,
2744                 self.pg2.remote_hosts[2].ip4,
2745                 vx_tun_l3.vni)
2746             self.assertNotEqual(INDEX_INVALID, tep1_sw_if_index)
2747
2748             # endpoint learnt via the parent GBP-vxlan interface
2749             self.assertTrue(find_gbp_endpoint(self,
2750                                               vx_tun_l3._sw_if_index,
2751                                               ip=l['ip']))
2752
2753         #
2754         # Add a remote endpoint from the API
2755         #
2756         rep_88 = VppGbpEndpoint(self, vx_tun_l3,
2757                                 epg_220, None,
2758                                 "10.0.0.88", "11.0.0.88",
2759                                 "2001:10::88", "3001::88",
2760                                 ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
2761                                 self.pg2.local_ip4,
2762                                 self.pg2.remote_hosts[1].ip4,
2763                                 mac=None)
2764         rep_88.add_vpp_config()
2765
2766         #
2767         # Add a remote endpoint from the API that matches an existing one
2768         #
2769         rep_2 = VppGbpEndpoint(self, vx_tun_l3,
2770                                epg_220, None,
2771                                learnt[0]['ip'], "11.0.0.101",
2772                                learnt[0]['ip6'], "3001::101",
2773                                ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
2774                                self.pg2.local_ip4,
2775                                self.pg2.remote_hosts[1].ip4,
2776                                mac=None)
2777         rep_2.add_vpp_config()
2778
2779         #
2780         # Add a route to the learned EP's v4 subnet
2781         #  packets should be send on the v4/v6 uu=fwd interface resp.
2782         #
2783         se_10_1_24 = VppGbpSubnet(
2784             self, rd1, "10.0.1.0", 24,
2785             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_TRANSPORT)
2786         se_10_1_24.add_vpp_config()
2787
2788         self.logger.info(self.vapi.cli("show gbp endpoint"))
2789
2790         ips = ["10.0.0.88", learnt[0]['ip']]
2791         for ip in ips:
2792             p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2793                  IP(dst=ip, src=ep.ip4.address) /
2794                  UDP(sport=1234, dport=1234) /
2795                  Raw('\xa5' * 100))
2796
2797             rxs = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg2)
2798
2799             for rx in rxs:
2800                 self.assertEqual(rx[IP].src, self.pg2.local_ip4)
2801                 self.assertEqual(rx[IP].dst, self.pg2.remote_hosts[1].ip4)
2802                 self.assertEqual(rx[UDP].dport, 48879)
2803                 # the UDP source port is a random value for hashing
2804                 self.assertEqual(rx[VXLAN].gpid, 441)
2805                 self.assertEqual(rx[VXLAN].vni, 101)
2806                 self.assertTrue(rx[VXLAN].flags.G)
2807                 self.assertTrue(rx[VXLAN].flags.Instance)
2808                 self.assertTrue(rx[VXLAN].gpflags.A)
2809                 self.assertFalse(rx[VXLAN].gpflags.D)
2810
2811                 inner = rx[VXLAN].payload
2812
2813                 self.assertEqual(inner[Ether].src, routed_src_mac)
2814                 self.assertEqual(inner[Ether].dst, routed_dst_mac)
2815                 self.assertEqual(inner[IP].src, ep.ip4.address)
2816                 self.assertEqual(inner[IP].dst, ip)
2817
2818         #
2819         # remove the API remote EPs, only API sourced is gone, the DP
2820         # learnt one remains
2821         #
2822         rep_88.remove_vpp_config()
2823         rep_2.remove_vpp_config()
2824
2825         self.assertTrue(find_gbp_endpoint(self, ip=rep_2.ip4.address))
2826
2827         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2828              IP(src=ep.ip4.address, dst=rep_2.ip4.address) /
2829              UDP(sport=1234, dport=1234) /
2830              Raw('\xa5' * 100))
2831         rxs = self.send_and_expect(self.pg0, [p], self.pg2)
2832
2833         self.assertFalse(find_gbp_endpoint(self, ip=rep_88.ip4.address))
2834
2835         p = (Ether(src=ep.mac, dst=self.loop0.local_mac) /
2836              IP(src=ep.ip4.address, dst=rep_88.ip4.address) /
2837              UDP(sport=1234, dport=1234) /
2838              Raw('\xa5' * 100))
2839         rxs = self.send_and_expect(self.pg0, [p], self.pg4)
2840
2841         #
2842         # to appease the testcase we cannot have the registered EP still
2843         # present (because it's DP learnt) when the TC ends so wait until
2844         # it is removed
2845         #
2846         self.wait_for_ep_timeout(ip=rep_88.ip4.address)
2847         self.wait_for_ep_timeout(ip=rep_2.ip4.address)
2848
2849         #
2850         # shutdown with learnt endpoint present
2851         #
2852         p = (Ether(src=self.pg2.remote_mac,
2853                    dst=self.pg2.local_mac) /
2854              IP(src=self.pg2.remote_hosts[1].ip4,
2855                 dst=self.pg2.local_ip4) /
2856              UDP(sport=1234, dport=48879) /
2857              VXLAN(vni=101, gpid=441, flags=0x88) /
2858              Ether(src=l['mac'], dst="00:00:00:11:11:11") /
2859              IP(src=learnt[1]['ip'], dst=ep.ip4.address) /
2860              UDP(sport=1234, dport=1234) /
2861              Raw('\xa5' * 100))
2862
2863         rx = self.send_and_expect(self.pg2, [p], self.pg0)
2864
2865         # endpoint learnt via the parent GBP-vxlan interface
2866         self.assertTrue(find_gbp_endpoint(self,
2867                                           vx_tun_l3._sw_if_index,
2868                                           ip=l['ip']))
2869
2870         #
2871         # TODO
2872         # remote endpoint becomes local
2873         #
2874         self.pg2.unconfig_ip4()
2875         self.pg3.unconfig_ip4()
2876         self.pg4.unconfig_ip4()
2877
2878     def test_gbp_redirect(self):
2879         """ GBP Endpoint Redirect """
2880
2881         self.vapi.cli("set logging class gbp level debug")
2882
2883         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
2884         routed_dst_mac = "00:0c:0c:0c:0c:0c"
2885         routed_src_mac = "00:22:bd:f8:19:ff"
2886
2887         learnt = [{'mac': '00:00:11:11:11:02',
2888                    'ip': '10.0.1.2',
2889                    'ip6': '2001:10::2'},
2890                   {'mac': '00:00:11:11:11:03',
2891                    'ip': '10.0.1.3',
2892                    'ip6': '2001:10::3'}]
2893
2894         #
2895         # IP tables
2896         #
2897         t4 = VppIpTable(self, 1)
2898         t4.add_vpp_config()
2899         t6 = VppIpTable(self, 1, True)
2900         t6.add_vpp_config()
2901
2902         rd1 = VppGbpRouteDomain(self, 2, t4, t6)
2903         rd1.add_vpp_config()
2904
2905         self.loop0.set_mac(self.router_mac)
2906
2907         #
2908         # Bind the BVI to the RD
2909         #
2910         VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
2911         VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
2912
2913         #
2914         # Pg7 hosts a BD's UU-fwd
2915         #
2916         self.pg7.config_ip4()
2917         self.pg7.resolve_arp()
2918
2919         #
2920         # a GBP bridge domains for the EPs
2921         #
2922         bd1 = VppBridgeDomain(self, 1)
2923         bd1.add_vpp_config()
2924         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0)
2925         gbd1.add_vpp_config()
2926
2927         bd2 = VppBridgeDomain(self, 2)
2928         bd2.add_vpp_config()
2929         gbd2 = VppGbpBridgeDomain(self, bd2, self.loop1)
2930         gbd2.add_vpp_config()
2931
2932         # ... and has a /32 and /128 applied
2933         ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32)
2934         ip4_addr.add_vpp_config()
2935         ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128", 128)
2936         ip6_addr.add_vpp_config()
2937         ip4_addr = VppIpInterfaceAddress(self, gbd2.bvi, "10.0.1.128", 32)
2938         ip4_addr.add_vpp_config()
2939         ip6_addr = VppIpInterfaceAddress(self, gbd2.bvi, "2001:11::128", 128)
2940         ip6_addr.add_vpp_config()
2941
2942         #
2943         # The Endpoint-groups in which we are learning endpoints
2944         #
2945         epg_220 = VppGbpEndpointGroup(self, 220, 440, rd1, gbd1,
2946                                       None, gbd1.bvi,
2947                                       "10.0.0.128",
2948                                       "2001:10::128",
2949                                       VppGbpEndpointRetention(2))
2950         epg_220.add_vpp_config()
2951         epg_221 = VppGbpEndpointGroup(self, 221, 441, rd1, gbd2,
2952                                       None, gbd2.bvi,
2953                                       "10.0.1.128",
2954                                       "2001:11::128",
2955                                       VppGbpEndpointRetention(2))
2956         epg_221.add_vpp_config()
2957         epg_222 = VppGbpEndpointGroup(self, 222, 442, rd1, gbd1,
2958                                       None, gbd1.bvi,
2959                                       "10.0.2.128",
2960                                       "2001:12::128",
2961                                       VppGbpEndpointRetention(2))
2962         epg_222.add_vpp_config()
2963
2964         #
2965         # a GBP bridge domains for the SEPs
2966         #
2967         bd_uu1 = VppVxlanGbpTunnel(self, self.pg7.local_ip4,
2968                                    self.pg7.remote_ip4, 116)
2969         bd_uu1.add_vpp_config()
2970         bd_uu2 = VppVxlanGbpTunnel(self, self.pg7.local_ip4,
2971                                    self.pg7.remote_ip4, 117)
2972         bd_uu2.add_vpp_config()
2973
2974         bd3 = VppBridgeDomain(self, 3)
2975         bd3.add_vpp_config()
2976         gbd3 = VppGbpBridgeDomain(self, bd3, self.loop2, bd_uu1, learn=False)
2977         gbd3.add_vpp_config()
2978         bd4 = VppBridgeDomain(self, 4)
2979         bd4.add_vpp_config()
2980         gbd4 = VppGbpBridgeDomain(self, bd4, self.loop3, bd_uu2, learn=False)
2981         gbd4.add_vpp_config()
2982
2983         #
2984         # EPGs in which the service endpoints exist
2985         #
2986         epg_320 = VppGbpEndpointGroup(self, 320, 550, rd1, gbd3,
2987                                       None, gbd1.bvi,
2988                                       "12.0.0.128",
2989                                       "4001:10::128",
2990                                       VppGbpEndpointRetention(2))
2991         epg_320.add_vpp_config()
2992         epg_321 = VppGbpEndpointGroup(self, 321, 551, rd1, gbd4,
2993                                       None, gbd2.bvi,
2994                                       "12.0.1.128",
2995                                       "4001:11::128",
2996                                       VppGbpEndpointRetention(2))
2997         epg_321.add_vpp_config()
2998
2999         #
3000         # three local endpoints
3001         #
3002         ep1 = VppGbpEndpoint(self, self.pg0,
3003                              epg_220, None,
3004                              "10.0.0.1", "11.0.0.1",
3005                              "2001:10::1", "3001:10::1")
3006         ep1.add_vpp_config()
3007         ep2 = VppGbpEndpoint(self, self.pg1,
3008                              epg_221, None,
3009                              "10.0.1.1", "11.0.1.1",
3010                              "2001:11::1", "3001:11::1")
3011         ep2.add_vpp_config()
3012         ep3 = VppGbpEndpoint(self, self.pg2,
3013                              epg_222, None,
3014                              "10.0.2.2", "11.0.2.2",
3015                              "2001:12::1", "3001:12::1")
3016         ep3.add_vpp_config()
3017
3018         #
3019         # service endpoints
3020         #
3021         sep1 = VppGbpEndpoint(self, self.pg3,
3022                               epg_320, None,
3023                               "12.0.0.1", "13.0.0.1",
3024                               "4001:10::1", "5001:10::1")
3025         sep1.add_vpp_config()
3026         sep2 = VppGbpEndpoint(self, self.pg4,
3027                               epg_320, None,
3028                               "12.0.0.2", "13.0.0.2",
3029                               "4001:10::2", "5001:10::2")
3030         sep2.add_vpp_config()
3031         sep3 = VppGbpEndpoint(self, self.pg5,
3032                               epg_321, None,
3033                               "12.0.1.1", "13.0.1.1",
3034                               "4001:11::1", "5001:11::1")
3035         sep3.add_vpp_config()
3036         # this EP is not installed immediately
3037         sep4 = VppGbpEndpoint(self, self.pg6,
3038                               epg_321, None,
3039                               "12.0.1.2", "13.0.1.2",
3040                               "4001:11::2", "5001:11::2")
3041
3042         #
3043         # an L2 switch packet between local EPs in different EPGs
3044         #  different dest ports on each so the are LB hashed differently
3045         #
3046         p4 = [(Ether(src=ep1.mac, dst=ep3.mac) /
3047                IP(src=ep1.ip4.address, dst=ep3.ip4.address) /
3048                UDP(sport=1234, dport=1234) /
3049                Raw('\xa5' * 100)),
3050               (Ether(src=ep3.mac, dst=ep1.mac) /
3051                IP(src=ep3.ip4.address, dst=ep1.ip4.address) /
3052                UDP(sport=1234, dport=1234) /
3053                Raw('\xa5' * 100))]
3054         p6 = [(Ether(src=ep1.mac, dst=ep3.mac) /
3055                IPv6(src=ep1.ip6.address, dst=ep3.ip6.address) /
3056                UDP(sport=1234, dport=1234) /
3057                Raw('\xa5' * 100)),
3058               (Ether(src=ep3.mac, dst=ep1.mac) /
3059                IPv6(src=ep3.ip6.address, dst=ep1.ip6.address) /
3060                UDP(sport=1234, dport=1230) /
3061                Raw('\xa5' * 100))]
3062
3063         # should be dropped since no contract yet
3064         self.send_and_assert_no_replies(self.pg0, [p4[0]])
3065         self.send_and_assert_no_replies(self.pg0, [p6[0]])
3066
3067         #
3068         # Add a contract with a rule to load-balance redirect via SEP1 and SEP2
3069         # one of the next-hops is via an EP that is not known
3070         #
3071         acl = VppGbpAcl(self)
3072         rule4 = acl.create_rule(permit_deny=1, proto=17)
3073         rule6 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
3074         acl_index = acl.add_vpp_config([rule4, rule6])
3075
3076         #
3077         # test the src-ip hash mode
3078         #
3079         c1 = VppGbpContract(
3080             self, epg_220.sclass, epg_222.sclass, acl_index,
3081             [VppGbpContractRule(
3082                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3083                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3084                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3085                                        sep1.ip4, sep1.epg.rd),
3086                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3087                                        sep2.ip4, sep2.epg.rd)]),
3088                 VppGbpContractRule(
3089                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3090                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3091                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3092                                            sep3.ip6, sep3.epg.rd),
3093                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3094                                            sep4.ip6, sep4.epg.rd)])],
3095             [ETH_P_IP, ETH_P_IPV6])
3096         c1.add_vpp_config()
3097
3098         c2 = VppGbpContract(
3099             self, epg_222.sclass, epg_220.sclass, acl_index,
3100             [VppGbpContractRule(
3101                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3102                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3103                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3104                                        sep1.ip4, sep1.epg.rd),
3105                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3106                                        sep2.ip4, sep2.epg.rd)]),
3107                 VppGbpContractRule(
3108                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3109                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SRC_IP,
3110                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3111                                            sep3.ip6, sep3.epg.rd),
3112                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3113                                            sep4.ip6, sep4.epg.rd)])],
3114             [ETH_P_IP, ETH_P_IPV6])
3115         c2.add_vpp_config()
3116
3117         #
3118         # send again with the contract preset, now packets arrive
3119         # at SEP1 or SEP2 depending on the hashing
3120         #
3121         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
3122
3123         for rx in rxs:
3124             self.assertEqual(rx[Ether].src, routed_src_mac)
3125             self.assertEqual(rx[Ether].dst, sep1.mac)
3126             self.assertEqual(rx[IP].src, ep1.ip4.address)
3127             self.assertEqual(rx[IP].dst, ep3.ip4.address)
3128
3129         rxs = self.send_and_expect(self.pg2, p4[1] * 17, sep2.itf)
3130
3131         for rx in rxs:
3132             self.assertEqual(rx[Ether].src, routed_src_mac)
3133             self.assertEqual(rx[Ether].dst, sep2.mac)
3134             self.assertEqual(rx[IP].src, ep3.ip4.address)
3135             self.assertEqual(rx[IP].dst, ep1.ip4.address)
3136
3137         rxs = self.send_and_expect(self.pg0, p6[0] * 17, self.pg7)
3138
3139         for rx in rxs:
3140             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
3141             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
3142             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
3143             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
3144             self.assertEqual(rx[VXLAN].vni, 117)
3145             self.assertTrue(rx[VXLAN].flags.G)
3146             self.assertTrue(rx[VXLAN].flags.Instance)
3147             # redirect policy has been applied
3148             self.assertTrue(rx[VXLAN].gpflags.A)
3149             self.assertFalse(rx[VXLAN].gpflags.D)
3150
3151             inner = rx[VXLAN].payload
3152
3153             self.assertEqual(inner[Ether].src, routed_src_mac)
3154             self.assertEqual(inner[Ether].dst, sep4.mac)
3155             self.assertEqual(inner[IPv6].src, ep1.ip6.address)
3156             self.assertEqual(inner[IPv6].dst, ep3.ip6.address)
3157
3158         rxs = self.send_and_expect(self.pg2, p6[1] * 17, sep3.itf)
3159
3160         for rx in rxs:
3161             self.assertEqual(rx[Ether].src, routed_src_mac)
3162             self.assertEqual(rx[Ether].dst, sep3.mac)
3163             self.assertEqual(rx[IPv6].src, ep3.ip6.address)
3164             self.assertEqual(rx[IPv6].dst, ep1.ip6.address)
3165
3166         #
3167         # programme the unknown EP
3168         #
3169         sep4.add_vpp_config()
3170
3171         rxs = self.send_and_expect(self.pg0, p6[0] * 17, sep4.itf)
3172
3173         for rx in rxs:
3174             self.assertEqual(rx[Ether].src, routed_src_mac)
3175             self.assertEqual(rx[Ether].dst, sep4.mac)
3176             self.assertEqual(rx[IPv6].src, ep1.ip6.address)
3177             self.assertEqual(rx[IPv6].dst, ep3.ip6.address)
3178
3179         #
3180         # and revert back to unprogrammed
3181         #
3182         sep4.remove_vpp_config()
3183
3184         rxs = self.send_and_expect(self.pg0, p6[0] * 17, self.pg7)
3185
3186         for rx in rxs:
3187             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
3188             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
3189             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
3190             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
3191             self.assertEqual(rx[VXLAN].vni, 117)
3192             self.assertTrue(rx[VXLAN].flags.G)
3193             self.assertTrue(rx[VXLAN].flags.Instance)
3194             # redirect policy has been applied
3195             self.assertTrue(rx[VXLAN].gpflags.A)
3196             self.assertFalse(rx[VXLAN].gpflags.D)
3197
3198             inner = rx[VXLAN].payload
3199
3200             self.assertEqual(inner[Ether].src, routed_src_mac)
3201             self.assertEqual(inner[Ether].dst, sep4.mac)
3202             self.assertEqual(inner[IPv6].src, ep1.ip6.address)
3203             self.assertEqual(inner[IPv6].dst, ep3.ip6.address)
3204
3205         c1.remove_vpp_config()
3206         c2.remove_vpp_config()
3207
3208         #
3209         # test the symmetric hash mode
3210         #
3211         c1 = VppGbpContract(
3212             self, epg_220.sclass, epg_222.sclass, acl_index,
3213             [VppGbpContractRule(
3214                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3215                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3216                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3217                                        sep1.ip4, sep1.epg.rd),
3218                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3219                                        sep2.ip4, sep2.epg.rd)]),
3220                 VppGbpContractRule(
3221                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3222                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3223                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3224                                            sep3.ip6, sep3.epg.rd),
3225                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3226                                            sep4.ip6, sep4.epg.rd)])],
3227             [ETH_P_IP, ETH_P_IPV6])
3228         c1.add_vpp_config()
3229
3230         c2 = VppGbpContract(
3231             self, epg_222.sclass, epg_220.sclass, acl_index,
3232             [VppGbpContractRule(
3233                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3234                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3235                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3236                                        sep1.ip4, sep1.epg.rd),
3237                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3238                                        sep2.ip4, sep2.epg.rd)]),
3239                 VppGbpContractRule(
3240                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3241                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3242                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3243                                            sep3.ip6, sep3.epg.rd),
3244                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3245                                            sep4.ip6, sep4.epg.rd)])],
3246             [ETH_P_IP, ETH_P_IPV6])
3247         c2.add_vpp_config()
3248
3249         #
3250         # send again with the contract preset, now packets arrive
3251         # at SEP1 for both directions
3252         #
3253         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
3254
3255         for rx in rxs:
3256             self.assertEqual(rx[Ether].src, routed_src_mac)
3257             self.assertEqual(rx[Ether].dst, sep1.mac)
3258             self.assertEqual(rx[IP].src, ep1.ip4.address)
3259             self.assertEqual(rx[IP].dst, ep3.ip4.address)
3260
3261         rxs = self.send_and_expect(self.pg2, p4[1] * 17, sep1.itf)
3262
3263         for rx in rxs:
3264             self.assertEqual(rx[Ether].src, routed_src_mac)
3265             self.assertEqual(rx[Ether].dst, sep1.mac)
3266             self.assertEqual(rx[IP].src, ep3.ip4.address)
3267             self.assertEqual(rx[IP].dst, ep1.ip4.address)
3268
3269         #
3270         # programme the unknown EP for the L3 tests
3271         #
3272         sep4.add_vpp_config()
3273
3274         #
3275         # an L3 switch packet between local EPs in different EPGs
3276         #  different dest ports on each so the are LB hashed differently
3277         #
3278         p4 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) /
3279                IP(src=ep1.ip4.address, dst=ep2.ip4.address) /
3280                UDP(sport=1234, dport=1234) /
3281                Raw('\xa5' * 100)),
3282               (Ether(src=ep2.mac, dst=str(self.router_mac)) /
3283                IP(src=ep2.ip4.address, dst=ep1.ip4.address) /
3284                UDP(sport=1234, dport=1234) /
3285                Raw('\xa5' * 100))]
3286         p6 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) /
3287                IPv6(src=ep1.ip6.address, dst=ep2.ip6.address) /
3288                UDP(sport=1234, dport=1234) /
3289                Raw('\xa5' * 100)),
3290               (Ether(src=ep2.mac, dst=str(self.router_mac)) /
3291                IPv6(src=ep2.ip6.address, dst=ep1.ip6.address) /
3292                UDP(sport=1234, dport=1234) /
3293                Raw('\xa5' * 100))]
3294
3295         c3 = VppGbpContract(
3296             self, epg_220.sclass, epg_221.sclass, acl_index,
3297             [VppGbpContractRule(
3298                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3299                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3300                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3301                                        sep1.ip4, sep1.epg.rd),
3302                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3303                                        sep2.ip4, sep2.epg.rd)]),
3304                 VppGbpContractRule(
3305                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3306                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC,
3307                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3308                                            sep3.ip6, sep3.epg.rd),
3309                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3310                                            sep4.ip6, sep4.epg.rd)])],
3311             [ETH_P_IP, ETH_P_IPV6])
3312         c3.add_vpp_config()
3313
3314         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
3315
3316         for rx in rxs:
3317             self.assertEqual(rx[Ether].src, routed_src_mac)
3318             self.assertEqual(rx[Ether].dst, sep1.mac)
3319             self.assertEqual(rx[IP].src, ep1.ip4.address)
3320             self.assertEqual(rx[IP].dst, ep2.ip4.address)
3321
3322         #
3323         # learn a remote EP in EPG 221
3324         #
3325         vx_tun_l3 = VppGbpVxlanTunnel(
3326             self, 444, rd1.rd_id,
3327             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3,
3328             self.pg2.local_ip4)
3329         vx_tun_l3.add_vpp_config()
3330
3331         c4 = VppGbpContract(
3332             self, epg_221.sclass, epg_220.sclass, acl_index,
3333             [VppGbpContractRule(
3334                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3335                 []),
3336                 VppGbpContractRule(
3337                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3338                     [])],
3339             [ETH_P_IP, ETH_P_IPV6])
3340         c4.add_vpp_config()
3341
3342         p = (Ether(src=self.pg7.remote_mac,
3343                    dst=self.pg7.local_mac) /
3344              IP(src=self.pg7.remote_ip4,
3345                 dst=self.pg7.local_ip4) /
3346              UDP(sport=1234, dport=48879) /
3347              VXLAN(vni=444, gpid=441, flags=0x88) /
3348              Ether(src="00:22:22:22:22:33", dst=str(self.router_mac)) /
3349              IP(src="10.0.0.88", dst=ep1.ip4.address) /
3350              UDP(sport=1234, dport=1234) /
3351              Raw('\xa5' * 100))
3352
3353         rx = self.send_and_expect(self.pg7, [p], self.pg0)
3354
3355         # endpoint learnt via the parent GBP-vxlan interface
3356         self.assertTrue(find_gbp_endpoint(self,
3357                                           vx_tun_l3._sw_if_index,
3358                                           ip="10.0.0.88"))
3359
3360         p = (Ether(src=self.pg7.remote_mac,
3361                    dst=self.pg7.local_mac) /
3362              IP(src=self.pg7.remote_ip4,
3363                 dst=self.pg7.local_ip4) /
3364              UDP(sport=1234, dport=48879) /
3365              VXLAN(vni=444, gpid=441, flags=0x88) /
3366              Ether(src="00:22:22:22:22:33", dst=str(self.router_mac)) /
3367              IPv6(src="2001:10::88", dst=ep1.ip6.address) /
3368              UDP(sport=1234, dport=1234) /
3369              Raw('\xa5' * 100))
3370
3371         rx = self.send_and_expect(self.pg7, [p], self.pg0)
3372
3373         # endpoint learnt via the parent GBP-vxlan interface
3374         self.assertTrue(find_gbp_endpoint(self,
3375                                           vx_tun_l3._sw_if_index,
3376                                           ip="2001:10::88"))
3377
3378         #
3379         # L3 switch from local to remote EP
3380         #
3381         p4 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) /
3382                IP(src=ep1.ip4.address, dst="10.0.0.88") /
3383                UDP(sport=1234, dport=1234) /
3384                Raw('\xa5' * 100))]
3385         p6 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) /
3386                IPv6(src=ep1.ip6.address, dst="2001:10::88") /
3387                UDP(sport=1234, dport=1234) /
3388                Raw('\xa5' * 100))]
3389
3390         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
3391
3392         for rx in rxs:
3393             self.assertEqual(rx[Ether].src, routed_src_mac)
3394             self.assertEqual(rx[Ether].dst, sep1.mac)
3395             self.assertEqual(rx[IP].src, ep1.ip4.address)
3396             self.assertEqual(rx[IP].dst, "10.0.0.88")
3397
3398         rxs = self.send_and_expect(self.pg0, p6[0] * 17, sep4.itf)
3399
3400         for rx in rxs:
3401             self.assertEqual(rx[Ether].src, routed_src_mac)
3402             self.assertEqual(rx[Ether].dst, sep4.mac)
3403             self.assertEqual(rx[IPv6].src, ep1.ip6.address)
3404             self.assertEqual(rx[IPv6].dst, "2001:10::88")
3405
3406         #
3407         # test the dst-ip hash mode
3408         #
3409         c5 = VppGbpContract(
3410             self, epg_220.sclass, epg_221.sclass, acl_index,
3411             [VppGbpContractRule(
3412                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3413                 VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
3414                 [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd,
3415                                        sep1.ip4, sep1.epg.rd),
3416                  VppGbpContractNextHop(sep2.vmac, sep2.epg.bd,
3417                                        sep2.ip4, sep2.epg.rd)]),
3418                 VppGbpContractRule(
3419                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT,
3420                     VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_DST_IP,
3421                     [VppGbpContractNextHop(sep3.vmac, sep3.epg.bd,
3422                                            sep3.ip6, sep3.epg.rd),
3423                      VppGbpContractNextHop(sep4.vmac, sep4.epg.bd,
3424                                            sep4.ip6, sep4.epg.rd)])],
3425             [ETH_P_IP, ETH_P_IPV6])
3426         c5.add_vpp_config()
3427
3428         rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf)
3429
3430         for rx in rxs:
3431             self.assertEqual(rx[Ether].src, routed_src_mac)
3432             self.assertEqual(rx[Ether].dst, sep1.mac)
3433             self.assertEqual(rx[IP].src, ep1.ip4.address)
3434             self.assertEqual(rx[IP].dst, "10.0.0.88")
3435
3436         rxs = self.send_and_expect(self.pg0, p6[0] * 17, sep3.itf)
3437
3438         for rx in rxs:
3439             self.assertEqual(rx[Ether].src, routed_src_mac)
3440             self.assertEqual(rx[Ether].dst, sep3.mac)
3441             self.assertEqual(rx[IPv6].src, ep1.ip6.address)
3442             self.assertEqual(rx[IPv6].dst, "2001:10::88")
3443
3444         #
3445         # cleanup
3446         #
3447         self.pg7.unconfig_ip4()
3448
3449     def test_gbp_l3_out(self):
3450         """ GBP L3 Out """
3451
3452         ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
3453         self.vapi.cli("set logging class gbp level debug")
3454
3455         routed_dst_mac = "00:0c:0c:0c:0c:0c"
3456         routed_src_mac = "00:22:bd:f8:19:ff"
3457
3458         #
3459         # IP tables
3460         #
3461         t4 = VppIpTable(self, 1)
3462         t4.add_vpp_config()
3463         t6 = VppIpTable(self, 1, True)
3464         t6.add_vpp_config()
3465
3466         rd1 = VppGbpRouteDomain(self, 2, t4, t6)
3467         rd1.add_vpp_config()
3468
3469         self.loop0.set_mac(self.router_mac)
3470
3471         #
3472         # Bind the BVI to the RD
3473         #
3474         VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
3475         VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
3476
3477         #
3478         # Pg7 hosts a BD's BUM
3479         # Pg1 some other l3 interface
3480         #
3481         self.pg7.config_ip4()
3482         self.pg7.resolve_arp()
3483
3484         #
3485         # a multicast vxlan-gbp tunnel for broadcast in the BD
3486         #
3487         tun_bm = VppVxlanGbpTunnel(self, self.pg7.local_ip4,
3488                                    "239.1.1.1", 88,
3489                                    mcast_itf=self.pg7)
3490         tun_bm.add_vpp_config()
3491
3492         #
3493         # a GBP external bridge domains for the EPs
3494         #
3495         bd1 = VppBridgeDomain(self, 1)
3496         bd1.add_vpp_config()
3497         gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0, None, tun_bm)
3498         gbd1.add_vpp_config()
3499
3500         #
3501         # The Endpoint-groups in which the external endpoints exist
3502         #
3503         epg_220 = VppGbpEndpointGroup(self, 220, 113, rd1, gbd1,
3504                                       None, gbd1.bvi,
3505                                       "10.0.0.128",
3506                                       "2001:10::128",
3507                                       VppGbpEndpointRetention(2))
3508         epg_220.add_vpp_config()
3509
3510         # the BVIs have the subnets applied ...
3511         ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 24)
3512         ip4_addr.add_vpp_config()
3513         ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128", 64)
3514         ip6_addr.add_vpp_config()
3515
3516         # ... which are L3-out subnets
3517         l3o_1 = VppGbpSubnet(
3518             self, rd1, "10.0.0.0", 24,
3519             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3520             sclass=113)
3521         l3o_1.add_vpp_config()
3522
3523         #
3524         # an external interface attached to the outside world and the
3525         # external BD
3526         #
3527         vlan_100 = VppDot1QSubint(self, self.pg0, 100)
3528         vlan_100.admin_up()
3529         VppL2Vtr(self, vlan_100, L2_VTR_OP.L2_POP_1).add_vpp_config()
3530         vlan_101 = VppDot1QSubint(self, self.pg0, 101)
3531         vlan_101.admin_up()
3532         VppL2Vtr(self, vlan_101, L2_VTR_OP.L2_POP_1).add_vpp_config()
3533         # vlan_102 is not poped
3534         vlan_102 = VppDot1QSubint(self, self.pg0, 102)
3535         vlan_102.admin_up()
3536
3537         ext_itf = VppGbpExtItf(self, self.loop0, bd1, rd1)
3538         ext_itf.add_vpp_config()
3539
3540         #
3541         # an unicast vxlan-gbp for inter-RD traffic
3542         #
3543         vx_tun_l3 = VppGbpVxlanTunnel(
3544             self, 444, rd1.rd_id,
3545             VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3,
3546             self.pg2.local_ip4)
3547         vx_tun_l3.add_vpp_config()
3548
3549         #
3550         # External Endpoints
3551         #
3552         eep1 = VppGbpEndpoint(self, vlan_100,
3553                               epg_220, None,
3554                               "10.0.0.1", "11.0.0.1",
3555                               "2001:10::1", "3001::1",
3556                               ep_flags.GBP_API_ENDPOINT_FLAG_EXTERNAL)
3557         eep1.add_vpp_config()
3558         eep2 = VppGbpEndpoint(self, vlan_101,
3559                               epg_220, None,
3560                               "10.0.0.2", "11.0.0.2",
3561                               "2001:10::2", "3001::2",
3562                               ep_flags.GBP_API_ENDPOINT_FLAG_EXTERNAL)
3563         eep2.add_vpp_config()
3564         eep3 = VppGbpEndpoint(self, vlan_102,
3565                               epg_220, None,
3566                               "10.0.0.3", "11.0.0.3",
3567                               "2001:10::3", "3001::3",
3568                               ep_flags.GBP_API_ENDPOINT_FLAG_EXTERNAL)
3569         eep3.add_vpp_config()
3570
3571         #
3572         # A remote external endpoint
3573         #
3574         rep = VppGbpEndpoint(self, vx_tun_l3,
3575                              epg_220, None,
3576                              "10.0.0.101", "11.0.0.101",
3577                              "2001:10::101", "3001::101",
3578                              ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
3579                              self.pg7.local_ip4,
3580                              self.pg7.remote_ip4,
3581                              mac=None)
3582         rep.add_vpp_config()
3583
3584         #
3585         # ARP packet from External EPs are accepted and replied to
3586         #
3587         p_arp = (Ether(src=eep1.mac, dst="ff:ff:ff:ff:ff:ff") /
3588                  Dot1Q(vlan=100) /
3589                  ARP(op="who-has",
3590                      psrc=eep1.ip4.address, pdst="10.0.0.128",
3591                      hwsrc=eep1.mac, hwdst="ff:ff:ff:ff:ff:ff"))
3592         rxs = self.send_and_expect(self.pg0, p_arp * 1, self.pg0)
3593
3594         #
3595         # ARP packet from host in remote subnet are accepted and replied to
3596         #
3597         p_arp = (Ether(src=vlan_102.remote_mac, dst="ff:ff:ff:ff:ff:ff") /
3598                  Dot1Q(vlan=102) /
3599                  ARP(op="who-has",
3600                      psrc="10.0.0.17", pdst="10.0.0.128",
3601                      hwsrc=vlan_102.remote_mac, hwdst="ff:ff:ff:ff:ff:ff"))
3602         rxs = self.send_and_expect(self.pg0, p_arp * 1, self.pg0)
3603
3604         #
3605         # packets destined to unknown addresses in the BVI's subnet
3606         # are ARP'd for
3607         #
3608         p4 = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
3609               Dot1Q(vlan=100) /
3610               IP(src="10.0.0.1", dst="10.0.0.88") /
3611               UDP(sport=1234, dport=1234) /
3612               Raw('\xa5' * 100))
3613         p6 = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
3614               Dot1Q(vlan=100) /
3615               IPv6(src="2001:10::1", dst="2001:10::88") /
3616               UDP(sport=1234, dport=1234) /
3617               Raw('\xa5' * 100))
3618
3619         rxs = self.send_and_expect(self.pg0, p4 * 1, self.pg7)
3620
3621         for rx in rxs:
3622             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
3623             # self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
3624             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
3625             self.assertEqual(rx[IP].dst, "239.1.1.1")
3626             self.assertEqual(rx[VXLAN].vni, 88)
3627             self.assertTrue(rx[VXLAN].flags.G)
3628             self.assertTrue(rx[VXLAN].flags.Instance)
3629             # policy was applied to the original IP packet
3630             self.assertEqual(rx[VXLAN].gpid, 113)
3631             self.assertTrue(rx[VXLAN].gpflags.A)
3632             self.assertFalse(rx[VXLAN].gpflags.D)
3633
3634             inner = rx[VXLAN].payload
3635
3636             self.assertTrue(inner.haslayer(ARP))
3637
3638         #
3639         # remote to external
3640         #
3641         p = (Ether(src=self.pg7.remote_mac,
3642                    dst=self.pg7.local_mac) /
3643              IP(src=self.pg7.remote_ip4,
3644                 dst=self.pg7.local_ip4) /
3645              UDP(sport=1234, dport=48879) /
3646              VXLAN(vni=444, gpid=113, flags=0x88) /
3647              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
3648              IP(src="10.0.0.101", dst="10.0.0.1") /
3649              UDP(sport=1234, dport=1234) /
3650              Raw('\xa5' * 100))
3651
3652         rxs = self.send_and_expect(self.pg7, p * 1, self.pg0)
3653
3654         #
3655         # local EP pings router
3656         #
3657         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
3658              Dot1Q(vlan=100) /
3659              IP(src=eep1.ip4.address, dst="10.0.0.128") /
3660              ICMP(type='echo-request'))
3661
3662         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
3663
3664         for rx in rxs:
3665             self.assertEqual(rx[Ether].src, str(self.router_mac))
3666             self.assertEqual(rx[Ether].dst, eep1.mac)
3667             self.assertEqual(rx[Dot1Q].vlan, 100)
3668
3669         #
3670         # local EP pings other local EP
3671         #
3672         p = (Ether(src=eep1.mac, dst=eep2.mac) /
3673              Dot1Q(vlan=100) /
3674              IP(src=eep1.ip4.address, dst=eep2.ip4.address) /
3675              ICMP(type='echo-request'))
3676
3677         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
3678
3679         for rx in rxs:
3680             self.assertEqual(rx[Ether].src, eep1.mac)
3681             self.assertEqual(rx[Ether].dst, eep2.mac)
3682             self.assertEqual(rx[Dot1Q].vlan, 101)
3683
3684         #
3685         # local EP pings router w/o vlan tag poped
3686         #
3687         p = (Ether(src=eep3.mac, dst=str(self.router_mac)) /
3688              Dot1Q(vlan=102) /
3689              IP(src=eep3.ip4.address, dst="10.0.0.128") /
3690              ICMP(type='echo-request'))
3691
3692         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
3693
3694         for rx in rxs:
3695             self.assertEqual(rx[Ether].src, str(self.router_mac))
3696             self.assertEqual(rx[Ether].dst, vlan_102.remote_mac)
3697
3698         #
3699         # A subnet reachable through the external EP1
3700         #
3701         ip_220 = VppIpRoute(self, "10.220.0.0", 24,
3702                             [VppRoutePath(eep1.ip4.address,
3703                                           eep1.epg.bvi.sw_if_index)],
3704                             table_id=t4.table_id)
3705         ip_220.add_vpp_config()
3706
3707         l3o_220 = VppGbpSubnet(
3708             self, rd1, "10.220.0.0", 24,
3709             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3710             sclass=4220)
3711         l3o_220.add_vpp_config()
3712
3713         #
3714         # A subnet reachable through the external EP2
3715         #
3716         ip_221 = VppIpRoute(self, "10.221.0.0", 24,
3717                             [VppRoutePath(eep2.ip4.address,
3718                                           eep2.epg.bvi.sw_if_index)],
3719                             table_id=t4.table_id)
3720         ip_221.add_vpp_config()
3721
3722         l3o_221 = VppGbpSubnet(
3723             self, rd1, "10.221.0.0", 24,
3724             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3725             sclass=4221)
3726         l3o_221.add_vpp_config()
3727
3728         #
3729         # ping between hosts in remote subnets
3730         #  dropped without a contract
3731         #
3732         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
3733              Dot1Q(vlan=100) /
3734              IP(src="10.220.0.1", dst="10.221.0.1") /
3735              ICMP(type='echo-request'))
3736
3737         rxs = self.send_and_assert_no_replies(self.pg0, p * 1)
3738
3739         #
3740         # contract for the external nets to communicate
3741         #
3742         acl = VppGbpAcl(self)
3743         rule4 = acl.create_rule(permit_deny=1, proto=17)
3744         rule6 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
3745         acl_index = acl.add_vpp_config([rule4, rule6])
3746
3747         c1 = VppGbpContract(
3748             self, 4220, 4221, acl_index,
3749             [VppGbpContractRule(
3750                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3751                 []),
3752                 VppGbpContractRule(
3753                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3754                     [])],
3755             [ETH_P_IP, ETH_P_IPV6])
3756         c1.add_vpp_config()
3757
3758         #
3759         # Contracts allowing ext-net 200 to talk with external EPs
3760         #
3761         c2 = VppGbpContract(
3762             self, 4220, 113, acl_index,
3763             [VppGbpContractRule(
3764                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3765                 []),
3766                 VppGbpContractRule(
3767                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3768                     [])],
3769             [ETH_P_IP, ETH_P_IPV6])
3770         c2.add_vpp_config()
3771         c3 = VppGbpContract(
3772             self, 113, 4220, acl_index,
3773             [VppGbpContractRule(
3774                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3775                 []),
3776                 VppGbpContractRule(
3777                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3778                     [])],
3779             [ETH_P_IP, ETH_P_IPV6])
3780         c3.add_vpp_config()
3781
3782         #
3783         # ping between hosts in remote subnets
3784         #
3785         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
3786              Dot1Q(vlan=100) /
3787              IP(src="10.220.0.1", dst="10.221.0.1") /
3788              UDP(sport=1234, dport=1234) /
3789              Raw('\xa5' * 100))
3790
3791         rxs = self.send_and_expect(self.pg0, p * 1, self.pg0)
3792
3793         for rx in rxs:
3794             self.assertEqual(rx[Ether].src, str(self.router_mac))
3795             self.assertEqual(rx[Ether].dst, eep2.mac)
3796             self.assertEqual(rx[Dot1Q].vlan, 101)
3797
3798         # we did not learn these external hosts
3799         self.assertFalse(find_gbp_endpoint(self, ip="10.220.0.1"))
3800         self.assertFalse(find_gbp_endpoint(self, ip="10.221.0.1"))
3801
3802         #
3803         # from remote external EP to local external EP
3804         #
3805         p = (Ether(src=self.pg7.remote_mac,
3806                    dst=self.pg7.local_mac) /
3807              IP(src=self.pg7.remote_ip4,
3808                 dst=self.pg7.local_ip4) /
3809              UDP(sport=1234, dport=48879) /
3810              VXLAN(vni=444, gpid=113, flags=0x88) /
3811              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
3812              IP(src="10.0.0.101", dst="10.220.0.1") /
3813              UDP(sport=1234, dport=1234) /
3814              Raw('\xa5' * 100))
3815
3816         rxs = self.send_and_expect(self.pg7, p * 1, self.pg0)
3817
3818         #
3819         # ping from an external host to the remote external EP
3820         #
3821         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
3822              Dot1Q(vlan=100) /
3823              IP(src="10.220.0.1", dst=rep.ip4.address) /
3824              UDP(sport=1234, dport=1234) /
3825              Raw('\xa5' * 100))
3826
3827         rxs = self.send_and_expect(self.pg0, p * 1, self.pg7)
3828
3829         for rx in rxs:
3830             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
3831             # self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
3832             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
3833             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
3834             self.assertEqual(rx[VXLAN].vni, 444)
3835             self.assertTrue(rx[VXLAN].flags.G)
3836             self.assertTrue(rx[VXLAN].flags.Instance)
3837             # the sclass of the ext-net the packet came from
3838             self.assertEqual(rx[VXLAN].gpid, 4220)
3839             # policy was applied to the original IP packet
3840             self.assertTrue(rx[VXLAN].gpflags.A)
3841             # since it's an external host the reciever should not learn it
3842             self.assertTrue(rx[VXLAN].gpflags.D)
3843             inner = rx[VXLAN].payload
3844             self.assertEqual(inner[IP].src, "10.220.0.1")
3845             self.assertEqual(inner[IP].dst, rep.ip4.address)
3846
3847         #
3848         # An external subnet reachable via the remote external EP
3849         #
3850
3851         #
3852         # first the VXLAN-GBP tunnel over which it is reached
3853         #
3854         vx_tun_r = VppVxlanGbpTunnel(
3855             self, self.pg7.local_ip4,
3856             self.pg7.remote_ip4, 445,
3857             mode=(VppEnum.vl_api_vxlan_gbp_api_tunnel_mode_t.
3858                   VXLAN_GBP_API_TUNNEL_MODE_L3))
3859         vx_tun_r.add_vpp_config()
3860         VppIpInterfaceBind(self, vx_tun_r, t4).add_vpp_config()
3861
3862         self.logger.info(self.vapi.cli("sh vxlan-gbp tunnel"))
3863
3864         #
3865         # then the special adj to resolve through on that tunnel
3866         #
3867         n1 = VppNeighbor(self,
3868                          vx_tun_r.sw_if_index,
3869                          "00:0c:0c:0c:0c:0c",
3870                          self.pg7.remote_ip4)
3871         n1.add_vpp_config()
3872
3873         #
3874         # the route via the adj above
3875         #
3876         ip_222 = VppIpRoute(self, "10.222.0.0", 24,
3877                             [VppRoutePath(self.pg7.remote_ip4,
3878                                           vx_tun_r.sw_if_index)],
3879                             table_id=t4.table_id)
3880         ip_222.add_vpp_config()
3881
3882         l3o_222 = VppGbpSubnet(
3883             self, rd1, "10.222.0.0", 24,
3884             VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
3885             sclass=4222)
3886         l3o_222.add_vpp_config()
3887
3888         #
3889         # ping between hosts in local and remote external subnets
3890         #  dropped without a contract
3891         #
3892         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
3893              Dot1Q(vlan=100) /
3894              IP(src="10.220.0.1", dst="10.222.0.1") /
3895              UDP(sport=1234, dport=1234) /
3896              Raw('\xa5' * 100))
3897
3898         rxs = self.send_and_assert_no_replies(self.pg0, p * 1)
3899
3900         #
3901         # Add contracts ext-nets for 220 -> 222
3902         #
3903         c4 = VppGbpContract(
3904             self, 4220, 4222, acl_index,
3905             [VppGbpContractRule(
3906                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3907                 []),
3908                 VppGbpContractRule(
3909                     VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
3910                     [])],
3911             [ETH_P_IP, ETH_P_IPV6])
3912         c4.add_vpp_config()
3913
3914         #
3915         # ping from host in local to remote external subnets
3916         #
3917         p = (Ether(src=eep1.mac, dst=str(self.router_mac)) /
3918              Dot1Q(vlan=100) /
3919              IP(src="10.220.0.1", dst="10.222.0.1") /
3920              UDP(sport=1234, dport=1234) /
3921              Raw('\xa5' * 100))
3922
3923         rxs = self.send_and_expect(self.pg0, p * 3, self.pg7)
3924
3925         for rx in rxs:
3926             self.assertEqual(rx[Ether].src, self.pg7.local_mac)
3927             self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
3928             self.assertEqual(rx[IP].src, self.pg7.local_ip4)
3929             self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
3930             self.assertEqual(rx[VXLAN].vni, 445)
3931             self.assertTrue(rx[VXLAN].flags.G)
3932             self.assertTrue(rx[VXLAN].flags.Instance)
3933             # the sclass of the ext-net the packet came from
3934             self.assertEqual(rx[VXLAN].gpid, 4220)
3935             # policy was applied to the original IP packet
3936             self.assertTrue(rx[VXLAN].gpflags.A)
3937             # since it's an external host the reciever should not learn it
3938             self.assertTrue(rx[VXLAN].gpflags.D)
3939             inner = rx[VXLAN].payload
3940             self.assertEqual(inner[Ether].dst, "00:0c:0c:0c:0c:0c")
3941             self.assertEqual(inner[IP].src, "10.220.0.1")
3942             self.assertEqual(inner[IP].dst, "10.222.0.1")
3943
3944         #
3945         # ping from host in remote to local external subnets
3946         # there's no contract for this, but the A bit is set.
3947         #
3948         p = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) /
3949              IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) /
3950              UDP(sport=1234, dport=48879) /
3951              VXLAN(vni=445, gpid=4222, flags=0x88, gpflags='A') /
3952              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
3953              IP(src="10.222.0.1", dst="10.220.0.1") /
3954              UDP(sport=1234, dport=1234) /
3955              Raw('\xa5' * 100))
3956
3957         rxs = self.send_and_expect(self.pg7, p * 3, self.pg0)
3958         self.assertFalse(find_gbp_endpoint(self, ip="10.222.0.1"))
3959
3960         #
3961         # ping from host in remote to remote external subnets
3962         #   this is dropped by reflection check.
3963         #
3964         p = (Ether(src=self.pg7.remote_mac, dst=self.pg7.local_mac) /
3965              IP(src=self.pg7.remote_ip4, dst=self.pg7.local_ip4) /
3966              UDP(sport=1234, dport=48879) /
3967              VXLAN(vni=445, gpid=4222, flags=0x88, gpflags='A') /
3968              Ether(src=self.pg0.remote_mac, dst=str(self.router_mac)) /
3969              IP(src="10.222.0.1", dst="10.222.0.2") /
3970              UDP(sport=1234, dport=1234) /
3971              Raw('\xa5' * 100))
3972
3973         rxs = self.send_and_assert_no_replies(self.pg7, p * 3)
3974
3975         #
3976         # cleanup
3977         #
3978         self.pg7.unconfig_ip4()
3979         vlan_100.set_vtr(L2_VTR_OP.L2_DISABLED)
3980
3981
3982 if __name__ == '__main__':
3983     unittest.main(testRunner=VppTestRunner)