PAPI: Add support for format/unformat functions.
[vpp.git] / test / test_gbp.py
1 #!/usr/bin/env python
2
3 import unittest
4
5 from framework import VppTestCase, VppTestRunner
6 from vpp_object import VppObject
7 from vpp_neighbor import VppNeighbor
8 from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable
9
10 from vpp_ip import *
11 from vpp_mac import *
12 from vpp_papi_provider import L2_PORT_TYPE
13 from vpp_papi.vpp_format import VPPFormat
14
15 from scapy.packet import Raw
16 from scapy.layers.l2 import Ether, ARP
17 from scapy.layers.inet import IP, UDP
18 from scapy.layers.inet6 import IPv6, ICMPv6ND_NS,  ICMPv6NDOptSrcLLAddr, \
19     ICMPv6ND_NA
20 from scapy.utils6 import in6_getnsma, in6_getnsmac
21
22 from socket import AF_INET, AF_INET6
23 from scapy.utils import inet_pton, inet_ntop
24 from util import mactobinary
25
26
27 def find_gbp_endpoint(test, sw_if_index, ip=None, mac=None):
28     vip = VppIpAddress(ip)
29
30     eps = test.vapi.gbp_endpoint_dump()
31     for ep in eps:
32         if ep.endpoint.sw_if_index != sw_if_index:
33             continue
34         for eip in ep.endpoint.ips:
35             if vip == eip:
36                 return True
37     return False
38
39
40 class VppGbpEndpoint(VppObject):
41     """
42     GBP Endpoint
43     """
44
45     @property
46     def bin_mac(self):
47         return mactobinary(self.itf.remote_mac)
48
49     @property
50     def mac(self):
51         return self.itf.remote_mac
52
53     @property
54     def ip4(self):
55         return self._ip4
56
57     @property
58     def fip4(self):
59         return self._fip4
60
61     @property
62     def ip6(self):
63         return self._ip6
64
65     @property
66     def fip6(self):
67         return self._fip6
68
69     @property
70     def ips(self):
71         return [self.ip4, self.ip6]
72
73     @property
74     def fips(self):
75         return [self.fip4, self.fip6]
76
77     def __init__(self, test, itf, epg, recirc, ip4, fip4, ip6, fip6):
78         self._test = test
79         self.itf = itf
80         self.epg = epg
81         self.recirc = recirc
82
83         self._ip4 = VppIpAddress(ip4)
84         self._fip4 = VppIpAddress(fip4)
85         self._ip6 = VppIpAddress(ip6)
86         self._fip6 = VppIpAddress(fip6)
87
88         self.vmac = VppMacAddress(self.itf.remote_mac)
89
90     def add_vpp_config(self):
91         res = self._test.vapi.gbp_endpoint_add(
92             self.itf.sw_if_index,
93             [self.ip4.encode(), self.ip6.encode()],
94             self.vmac.encode(),
95             self.epg.epg)
96         self.handle = res.handle
97         self._test.registry.register(self, self._test.logger)
98
99     def remove_vpp_config(self):
100         self._test.vapi.gbp_endpoint_del(self.handle)
101
102     def __str__(self):
103         return self.object_id()
104
105     def object_id(self):
106         return "gbp-endpoint;[%d:%s:%d]" % (self.itf.sw_if_index,
107                                             self.ip4.address,
108                                             self.epg.epg)
109
110     def query_vpp_config(self):
111         return find_gbp_endpoint(self._test,
112                                  self.itf.sw_if_index,
113                                  self.ip4.address)
114
115
116 class VppGbpRecirc(VppObject):
117     """
118     GBP Recirculation Interface
119     """
120
121     def __init__(self, test, epg, recirc, is_ext=False):
122         self._test = test
123         self.recirc = recirc
124         self.epg = epg
125         self.is_ext = is_ext
126
127     def add_vpp_config(self):
128         self._test.vapi.gbp_recirc_add_del(
129             1,
130             self.recirc.sw_if_index,
131             self.epg.epg,
132             self.is_ext)
133         self._test.registry.register(self, self._test.logger)
134
135     def remove_vpp_config(self):
136         self._test.vapi.gbp_recirc_add_del(
137             0,
138             self.recirc.sw_if_index,
139             self.epg.epg,
140             self.is_ext)
141
142     def __str__(self):
143         return self.object_id()
144
145     def object_id(self):
146         return "gbp-recirc;[%d]" % (self.recirc.sw_if_index)
147
148     def query_vpp_config(self):
149         rs = self._test.vapi.gbp_recirc_dump()
150         for r in rs:
151             if r.recirc.sw_if_index == self.recirc.sw_if_index:
152                 return True
153         return False
154
155
156 class VppGbpSubnet(VppObject):
157     """
158     GBP Subnet
159     """
160
161     def __init__(self, test, table_id, address, address_len,
162                  is_internal=True,
163                  sw_if_index=None, epg=None):
164         self._test = test
165         self.table_id = table_id
166         self.prefix = "{}/{}".format(address, address_len)
167         self.is_internal = is_internal
168         self.sw_if_index = sw_if_index
169         self.epg = epg
170
171     def add_vpp_config(self):
172         self._test.vapi.gbp_subnet_add_del(
173             1,
174             self.table_id,
175             self.is_internal,
176             self.prefix,
177             sw_if_index=self.sw_if_index if self.sw_if_index else 0xffffffff,
178             epg_id=self.epg if self.epg else 0xffff)
179         self._test.registry.register(self, self._test.logger)
180
181     def remove_vpp_config(self):
182         self._test.vapi.gbp_subnet_add_del(
183             0,
184             self.table_id,
185             self.is_internal,
186             self.prefix)
187
188     def __str__(self):
189         return self.object_id()
190
191     def object_id(self):
192         return "gbp-subnet;[%d-%s]" % (self.table_id,
193                                        self.prefix)
194
195     def query_vpp_config(self):
196         ss = self._test.vapi.gbp_subnet_dump()
197         for s in ss:
198             if s.subnet.table_id == self.table_id and \
199                VPPFormat.unformat(s.subnet.prefix) == self.prefix:
200                 return True
201         return False
202
203
204 class VppGbpEndpointGroup(VppObject):
205     """
206     GBP Endpoint Group
207     """
208
209     def __init__(self, test, epg, rd, bd, uplink,
210                  bvi, bvi_ip4, bvi_ip6=None):
211         self._test = test
212         self.uplink = uplink
213         self.bvi = bvi
214         self.bvi_ip4 = bvi_ip4
215         self.bvi_ip4_n = inet_pton(AF_INET, bvi_ip4)
216         self.bvi_ip6 = bvi_ip6
217         self.bvi_ip6_n = inet_pton(AF_INET6, bvi_ip6)
218         self.epg = epg
219         self.bd = bd
220         self.rd = rd
221
222     def add_vpp_config(self):
223         self._test.vapi.gbp_endpoint_group_add_del(
224             1,
225             self.epg,
226             self.bd,
227             self.rd,
228             self.rd,
229             self.uplink.sw_if_index)
230         self._test.registry.register(self, self._test.logger)
231
232     def remove_vpp_config(self):
233         self._test.vapi.gbp_endpoint_group_add_del(
234             0,
235             self.epg,
236             self.bd,
237             self.rd,
238             self.rd,
239             self.uplink.sw_if_index)
240
241     def __str__(self):
242         return self.object_id()
243
244     def object_id(self):
245         return "gbp-endpoint-group;[%d]" % (self.epg)
246
247     def query_vpp_config(self):
248         epgs = self._test.vapi.gbp_endpoint_group_dump()
249         for epg in epgs:
250             if epg.epg.epg_id == self.epg:
251                 return True
252         return False
253
254
255 class VppGbpContract(VppObject):
256     """
257     GBP Contract
258     """
259
260     def __init__(self, test, src_epg, dst_epg, acl_index):
261         self._test = test
262         self.acl_index = acl_index
263         self.src_epg = src_epg
264         self.dst_epg = dst_epg
265
266     def add_vpp_config(self):
267         self._test.vapi.gbp_contract_add_del(
268             1,
269             self.src_epg,
270             self.dst_epg,
271             self.acl_index)
272         self._test.registry.register(self, self._test.logger)
273
274     def remove_vpp_config(self):
275         self._test.vapi.gbp_contract_add_del(
276             0,
277             self.src_epg,
278             self.dst_epg,
279             self.acl_index)
280
281     def __str__(self):
282         return self.object_id()
283
284     def object_id(self):
285         return "gbp-contract;[%d:%s:%d]" % (self.src_epg,
286                                             self.dst_epg,
287                                             self.acl_index)
288
289     def query_vpp_config(self):
290         cs = self._test.vapi.gbp_contract_dump()
291         for c in cs:
292             if c.contract.src_epg == self.src_epg \
293                and c.contract.dst_epg == self.dst_epg:
294                 return True
295         return False
296
297
298 class VppGbpAcl(VppObject):
299     """
300     GBP Acl
301     """
302
303     def __init__(self, test):
304         self._test = test
305         self.acl_index = 4294967295
306
307     def create_rule(self, is_ipv6=0, permit_deny=0, proto=-1,
308                     s_prefix=0, s_ip='\x00\x00\x00\x00', sport_from=0,
309                     sport_to=65535, d_prefix=0, d_ip='\x00\x00\x00\x00',
310                     dport_from=0, dport_to=65535):
311         if proto == -1 or proto == 0:
312             sport_to = 0
313             dport_to = sport_to
314         elif proto == 1 or proto == 58:
315             sport_to = 255
316             dport_to = sport_to
317         rule = ({'is_permit': permit_deny, 'is_ipv6': is_ipv6, 'proto': proto,
318                  'srcport_or_icmptype_first': sport_from,
319                  'srcport_or_icmptype_last': sport_to,
320                  'src_ip_prefix_len': s_prefix,
321                  'src_ip_addr': s_ip,
322                  'dstport_or_icmpcode_first': dport_from,
323                  'dstport_or_icmpcode_last': dport_to,
324                  'dst_ip_prefix_len': d_prefix,
325                  'dst_ip_addr': d_ip})
326         return rule
327
328     def add_vpp_config(self, rules):
329
330         reply = self._test.vapi.acl_add_replace(self.acl_index,
331                                                 r=rules,
332                                                 tag='GBPTest')
333         self.acl_index = reply.acl_index
334         return self.acl_index
335
336     def remove_vpp_config(self):
337         self._test.vapi.acl_del(self.acl_index)
338
339     def __str__(self):
340         return self.object_id()
341
342     def object_id(self):
343         return "gbp-acl;[%d]" % (self.acl_index)
344
345     def query_vpp_config(self):
346         cs = self._test.vapi.acl_dump()
347         for c in cs:
348             if c.acl_index == self.acl_index:
349                 return True
350         return False
351
352
353 class TestGBP(VppTestCase):
354     """ GBP Test Case """
355
356     def setUp(self):
357         super(TestGBP, self).setUp()
358
359         self.create_pg_interfaces(range(9))
360         self.create_loopback_interfaces(9)
361
362         self.router_mac = "00:11:22:33:44:55"
363
364         for i in self.pg_interfaces:
365             i.admin_up()
366         for i in self.lo_interfaces:
367             i.admin_up()
368             self.vapi.sw_interface_set_mac_address(
369                 i.sw_if_index,
370                 mactobinary(self.router_mac))
371
372     def tearDown(self):
373         for i in self.pg_interfaces:
374             i.admin_down()
375
376         super(TestGBP, self).tearDown()
377
378     def send_and_expect_bridged(self, src, tx, dst):
379         rx = self.send_and_expect(src, tx, dst)
380
381         for r in rx:
382             self.assertEqual(r[Ether].src, tx[0][Ether].src)
383             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
384             self.assertEqual(r[IP].src, tx[0][IP].src)
385             self.assertEqual(r[IP].dst, tx[0][IP].dst)
386         return rx
387
388     def send_and_expect_bridged6(self, src, tx, dst):
389         rx = self.send_and_expect(src, tx, dst)
390
391         for r in rx:
392             self.assertEqual(r[Ether].src, tx[0][Ether].src)
393             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
394             self.assertEqual(r[IPv6].src, tx[0][IPv6].src)
395             self.assertEqual(r[IPv6].dst, tx[0][IPv6].dst)
396         return rx
397
398     def send_and_expect_routed(self, src, tx, dst, src_mac):
399         rx = self.send_and_expect(src, tx, dst)
400
401         for r in rx:
402             self.assertEqual(r[Ether].src, src_mac)
403             self.assertEqual(r[Ether].dst, dst.remote_mac)
404             self.assertEqual(r[IP].src, tx[0][IP].src)
405             self.assertEqual(r[IP].dst, tx[0][IP].dst)
406         return rx
407
408     def send_and_expect_natted(self, src, tx, dst, src_ip):
409         rx = self.send_and_expect(src, tx, dst)
410
411         for r in rx:
412             self.assertEqual(r[Ether].src, tx[0][Ether].src)
413             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
414             self.assertEqual(r[IP].src, src_ip)
415             self.assertEqual(r[IP].dst, tx[0][IP].dst)
416         return rx
417
418     def send_and_expect_natted6(self, src, tx, dst, src_ip):
419         rx = self.send_and_expect(src, tx, dst)
420
421         for r in rx:
422             self.assertEqual(r[Ether].src, tx[0][Ether].src)
423             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
424             self.assertEqual(r[IPv6].src, src_ip)
425             self.assertEqual(r[IPv6].dst, tx[0][IPv6].dst)
426         return rx
427
428     def send_and_expect_unnatted(self, src, tx, dst, dst_ip):
429         rx = self.send_and_expect(src, tx, dst)
430
431         for r in rx:
432             self.assertEqual(r[Ether].src, tx[0][Ether].src)
433             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
434             self.assertEqual(r[IP].dst, dst_ip)
435             self.assertEqual(r[IP].src, tx[0][IP].src)
436         return rx
437
438     def send_and_expect_unnatted6(self, src, tx, dst, dst_ip):
439         rx = self.send_and_expect(src, tx, dst)
440
441         for r in rx:
442             self.assertEqual(r[Ether].src, tx[0][Ether].src)
443             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
444             self.assertEqual(r[IPv6].dst, dst_ip)
445             self.assertEqual(r[IPv6].src, tx[0][IPv6].src)
446         return rx
447
448     def send_and_expect_double_natted(self, src, tx, dst, src_ip, dst_ip):
449         rx = self.send_and_expect(src, tx, dst)
450
451         for r in rx:
452             self.assertEqual(r[Ether].src, self.router_mac)
453             self.assertEqual(r[Ether].dst, dst.remote_mac)
454             self.assertEqual(r[IP].dst, dst_ip)
455             self.assertEqual(r[IP].src, src_ip)
456         return rx
457
458     def send_and_expect_double_natted6(self, src, tx, dst, src_ip, dst_ip):
459         rx = self.send_and_expect(src, tx, dst)
460
461         for r in rx:
462             self.assertEqual(r[Ether].src, self.router_mac)
463             self.assertEqual(r[Ether].dst, dst.remote_mac)
464             self.assertEqual(r[IPv6].dst, dst_ip)
465             self.assertEqual(r[IPv6].src, src_ip)
466         return rx
467
468     def test_gbp(self):
469         """ Group Based Policy """
470
471         nat_table = VppIpTable(self, 20)
472         nat_table.add_vpp_config()
473         nat_table = VppIpTable(self, 20, is_ip6=True)
474         nat_table.add_vpp_config()
475
476         #
477         # Bridge Domains
478         #
479         self.vapi.bridge_domain_add_del(1, flood=1, uu_flood=1, forward=1,
480                                         learn=0, arp_term=1, is_add=1)
481         self.vapi.bridge_domain_add_del(2, flood=1, uu_flood=1, forward=1,
482                                         learn=0, arp_term=1, is_add=1)
483         self.vapi.bridge_domain_add_del(20, flood=1, uu_flood=1, forward=1,
484                                         learn=0, arp_term=1, is_add=1)
485
486         #
487         # 3 EPGs, 2 of which share a BD.
488         # 2 NAT EPGs, one for floating-IP subnets, the other for internet
489         #
490         epgs = [VppGbpEndpointGroup(self, 220, 0, 1, self.pg4,
491                                     self.loop0,
492                                     "10.0.0.128",
493                                     "2001:10::128"),
494                 VppGbpEndpointGroup(self, 221, 0, 1, self.pg5,
495                                     self.loop0,
496                                     "10.0.1.128",
497                                     "2001:10:1::128"),
498                 VppGbpEndpointGroup(self, 222, 0, 2, self.pg6,
499                                     self.loop1,
500                                     "10.0.2.128",
501                                     "2001:10:2::128"),
502                 VppGbpEndpointGroup(self, 333, 20, 20, self.pg7,
503                                     self.loop2,
504                                     "11.0.0.128",
505                                     "3001::128"),
506                 VppGbpEndpointGroup(self, 444, 20, 20, self.pg8,
507                                     self.loop2,
508                                     "11.0.0.129",
509                                     "3001::129")]
510         recircs = [VppGbpRecirc(self, epgs[0],
511                                 self.loop3),
512                    VppGbpRecirc(self, epgs[1],
513                                 self.loop4),
514                    VppGbpRecirc(self, epgs[2],
515                                 self.loop5),
516                    VppGbpRecirc(self, epgs[3],
517                                 self.loop6, is_ext=True),
518                    VppGbpRecirc(self, epgs[4],
519                                 self.loop8, is_ext=True)]
520
521         epg_nat = epgs[3]
522         recirc_nat = recircs[3]
523
524         #
525         # 4 end-points, 2 in the same subnet, 3 in the same BD
526         #
527         eps = [VppGbpEndpoint(self, self.pg0,
528                               epgs[0], recircs[0],
529                               "10.0.0.1", "11.0.0.1",
530                               "2001:10::1", "3001::1"),
531                VppGbpEndpoint(self, self.pg1,
532                               epgs[0], recircs[0],
533                               "10.0.0.2", "11.0.0.2",
534                               "2001:10::2", "3001::2"),
535                VppGbpEndpoint(self, self.pg2,
536                               epgs[1], recircs[1],
537                               "10.0.1.1", "11.0.0.3",
538                               "2001:10:1::1", "3001::3"),
539                VppGbpEndpoint(self, self.pg3,
540                               epgs[2], recircs[2],
541                               "10.0.2.1", "11.0.0.4",
542                               "2001:10:2::1", "3001::4")]
543
544         #
545         # Config related to each of the EPGs
546         #
547         for epg in epgs:
548             # IP config on the BVI interfaces
549             if epg != epgs[1] and epg != epgs[4]:
550                 epg.bvi.set_table_ip4(epg.rd)
551                 epg.bvi.set_table_ip6(epg.rd)
552
553                 # The BVIs are NAT inside interfaces
554                 self.vapi.nat44_interface_add_del_feature(epg.bvi.sw_if_index,
555                                                           is_inside=1,
556                                                           is_add=1)
557                 self.vapi.nat66_add_del_interface(epg.bvi.sw_if_index,
558                                                   is_inside=1,
559                                                   is_add=1)
560
561             self.vapi.sw_interface_add_del_address(epg.bvi.sw_if_index,
562                                                    epg.bvi_ip4_n,
563                                                    32)
564             self.vapi.sw_interface_add_del_address(epg.bvi.sw_if_index,
565                                                    epg.bvi_ip6_n,
566                                                    128,
567                                                    is_ipv6=True)
568
569             # EPG uplink interfaces in the BD
570             epg.uplink.set_table_ip4(epg.rd)
571             epg.uplink.set_table_ip6(epg.rd)
572             self.vapi.sw_interface_set_l2_bridge(epg.uplink.sw_if_index,
573                                                  epg.bd)
574
575             # add the BD ARP termination entry for BVI IP
576             self.vapi.bd_ip_mac_add_del(bd_id=epg.bd,
577                                         mac=mactobinary(self.router_mac),
578                                         ip=epg.bvi_ip4_n,
579                                         is_ipv6=0,
580                                         is_add=1)
581             self.vapi.bd_ip_mac_add_del(bd_id=epg.bd,
582                                         mac=mactobinary(self.router_mac),
583                                         ip=epg.bvi_ip6_n,
584                                         is_ipv6=1,
585                                         is_add=1)
586
587             # epg[1] shares the same BVI to epg[0]
588             if epg != epgs[1] and epg != epgs[4]:
589                 # BVI in BD
590                 self.vapi.sw_interface_set_l2_bridge(
591                     epg.bvi.sw_if_index,
592                     epg.bd,
593                     port_type=L2_PORT_TYPE.BVI)
594
595                 # BVI L2 FIB entry
596                 self.vapi.l2fib_add_del(self.router_mac,
597                                         epg.bd,
598                                         epg.bvi.sw_if_index,
599                                         is_add=1, bvi_mac=1)
600
601             # EPG in VPP
602             epg.add_vpp_config()
603
604         for recirc in recircs:
605             # EPG's ingress recirculation interface maps to its RD
606             recirc.recirc.set_table_ip4(recirc.epg.rd)
607             recirc.recirc.set_table_ip6(recirc.epg.rd)
608
609             # in the bridge to allow DVR. L2 emulation to punt to L3
610             self.vapi.sw_interface_set_l2_bridge(recirc.recirc.sw_if_index,
611                                                  recirc.epg.bd)
612             self.vapi.sw_interface_set_l2_emulation(
613                 recirc.recirc.sw_if_index)
614
615             self.vapi.nat44_interface_add_del_feature(
616                 recirc.recirc.sw_if_index,
617                 is_inside=0,
618                 is_add=1)
619             self.vapi.nat66_add_del_interface(
620                 recirc.recirc.sw_if_index,
621                 is_inside=0,
622                 is_add=1)
623
624             recirc.add_vpp_config()
625
626         ep_routes = []
627         ep_arps = []
628         for ep in eps:
629             self.pg_enable_capture(self.pg_interfaces)
630             self.pg_start()
631             #
632             # routes to the endpoints. We need these since there are no
633             # adj-fibs due to the fact the the BVI address has /32 and
634             # the subnet is not attached.
635             #
636             for (ip, fip) in zip(ep.ips, ep.fips):
637                 r = VppIpRoute(self, ip.address, ip.length,
638                                [VppRoutePath(ip.address,
639                                              ep.epg.bvi.sw_if_index,
640                                              proto=ip.dpo_proto)],
641                                is_ip6=ip.is_ip6)
642                 r.add_vpp_config()
643                 ep_routes.append(r)
644
645                 #
646                 # ARP entries for the endpoints
647                 #
648                 a = VppNeighbor(self,
649                                 ep.epg.bvi.sw_if_index,
650                                 ep.itf.remote_mac,
651                                 ip.address,
652                                 af=ip.af)
653                 a.add_vpp_config()
654                 ep_arps.append(a)
655
656                 # add the BD ARP termination entry
657                 self.vapi.bd_ip_mac_add_del(bd_id=ep.epg.bd,
658                                             mac=ep.bin_mac,
659                                             ip=ip.bytes,
660                                             is_ipv6=ip.is_ip6,
661                                             is_add=1)
662
663                 # Add static mappings for each EP from the 10/8 to 11/8 network
664                 if ip.af == AF_INET:
665                     self.vapi.nat44_add_del_static_mapping(ip.bytes,
666                                                            fip.bytes,
667                                                            vrf_id=0,
668                                                            addr_only=1)
669                 else:
670                     self.vapi.nat66_add_del_static_mapping(ip.bytes,
671                                                            fip.bytes,
672                                                            vrf_id=0)
673
674             # add each EP itf to the its BD
675             self.vapi.sw_interface_set_l2_bridge(ep.itf.sw_if_index,
676                                                  ep.epg.bd)
677
678             # L2 FIB entry
679             self.vapi.l2fib_add_del(ep.mac,
680                                     ep.epg.bd,
681                                     ep.itf.sw_if_index,
682                                     is_add=1)
683
684             # VPP EP create ...
685             ep.add_vpp_config()
686
687             self.logger.info(self.vapi.cli("sh gbp endpoint"))
688
689             # ... results in a Gratuitous ARP/ND on the EPG's uplink
690             rx = ep.epg.uplink.get_capture(len(ep.ips), timeout=0.2)
691
692             for ii, ip in enumerate(ep.ips):
693                 p = rx[ii]
694
695                 if ip.is_ip6:
696                     self.assertTrue(p.haslayer(ICMPv6ND_NA))
697                     self.assertEqual(p[ICMPv6ND_NA].tgt, ip.address)
698                 else:
699                     self.assertTrue(p.haslayer(ARP))
700                     self.assertEqual(p[ARP].psrc, ip.address)
701                     self.assertEqual(p[ARP].pdst, ip.address)
702
703             # add the BD ARP termination entry for floating IP
704             for fip in ep.fips:
705                 self.vapi.bd_ip_mac_add_del(bd_id=epg_nat.bd,
706                                             mac=ep.bin_mac,
707                                             ip=fip.bytes,
708                                             is_ipv6=fip.is_ip6,
709                                             is_add=1)
710
711                 # floating IPs route via EPG recirc
712                 r = VppIpRoute(self, fip.address, fip.length,
713                                [VppRoutePath(fip.address,
714                                              ep.recirc.recirc.sw_if_index,
715                                              is_dvr=1,
716                                              proto=fip.dpo_proto)],
717                                table_id=20,
718                                is_ip6=fip.is_ip6)
719                 r.add_vpp_config()
720                 ep_routes.append(r)
721
722             # L2 FIB entries in the NAT EPG BD to bridge the packets from
723             # the outside direct to the internal EPG
724             self.vapi.l2fib_add_del(ep.mac,
725                                     epg_nat.bd,
726                                     ep.recirc.recirc.sw_if_index,
727                                     is_add=1)
728
729         #
730         # ARP packets for unknown IP are flooded
731         #
732         pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff",
733                          src=self.pg0.remote_mac) /
734                    ARP(op="who-has",
735                        hwdst="ff:ff:ff:ff:ff:ff",
736                        hwsrc=self.pg0.remote_mac,
737                        pdst=epgs[0].bvi_ip4,
738                        psrc="10.0.0.88"))
739
740         self.send_and_expect(self.pg0, [pkt_arp], self.pg0)
741
742         #
743         # ARP/ND packets get a response
744         #
745         pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff",
746                          src=self.pg0.remote_mac) /
747                    ARP(op="who-has",
748                        hwdst="ff:ff:ff:ff:ff:ff",
749                        hwsrc=self.pg0.remote_mac,
750                        pdst=epgs[0].bvi_ip4,
751                        psrc=eps[0].ip4.address))
752
753         self.send_and_expect(self.pg0, [pkt_arp], self.pg0)
754
755         nsma = in6_getnsma(inet_pton(AF_INET6, eps[0].ip6.address))
756         d = inet_ntop(AF_INET6, nsma)
757         pkt_nd = (Ether(dst=in6_getnsmac(nsma)) /
758                   IPv6(dst=d, src=eps[0].ip6.address) /
759                   ICMPv6ND_NS(tgt=epgs[0].bvi_ip6) /
760                   ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac))
761         self.send_and_expect(self.pg0, [pkt_nd], self.pg0)
762
763         #
764         # broadcast packets are flooded
765         #
766         pkt_bcast = (Ether(dst="ff:ff:ff:ff:ff:ff",
767                            src=self.pg0.remote_mac) /
768                      IP(src=eps[0].ip4.address, dst="232.1.1.1") /
769                      UDP(sport=1234, dport=1234) /
770                      Raw('\xa5' * 100))
771
772         self.vapi.cli("clear trace")
773         self.pg0.add_stream(pkt_bcast)
774
775         self.pg_enable_capture(self.pg_interfaces)
776         self.pg_start()
777
778         rxd = eps[1].itf.get_capture(1)
779         self.assertEqual(rxd[0][Ether].dst, pkt_bcast[Ether].dst)
780         rxd = epgs[0].uplink.get_capture(1)
781         self.assertEqual(rxd[0][Ether].dst, pkt_bcast[Ether].dst)
782
783         #
784         # packets to non-local L3 destinations dropped
785         #
786         pkt_intra_epg_220_ip4 = (Ether(src=self.pg0.remote_mac,
787                                        dst=self.router_mac) /
788                                  IP(src=eps[0].ip4.address,
789                                     dst="10.0.0.99") /
790                                  UDP(sport=1234, dport=1234) /
791                                  Raw('\xa5' * 100))
792         pkt_inter_epg_222_ip4 = (Ether(src=self.pg0.remote_mac,
793                                        dst=self.router_mac) /
794                                  IP(src=eps[0].ip4.address,
795                                     dst="10.0.1.99") /
796                                  UDP(sport=1234, dport=1234) /
797                                  Raw('\xa5' * 100))
798
799         self.send_and_assert_no_replies(self.pg0, pkt_intra_epg_220_ip4 * 65)
800
801         pkt_inter_epg_222_ip6 = (Ether(src=self.pg0.remote_mac,
802                                        dst=self.router_mac) /
803                                  IPv6(src=eps[0].ip6.address,
804                                       dst="2001:10::99") /
805                                  UDP(sport=1234, dport=1234) /
806                                  Raw('\xa5' * 100))
807         self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_222_ip6 * 65)
808
809         #
810         # Add the subnet routes
811         #
812         s41 = VppGbpSubnet(self, 0, "10.0.0.0", 24)
813         s42 = VppGbpSubnet(self, 0, "10.0.1.0", 24)
814         s43 = VppGbpSubnet(self, 0, "10.0.2.0", 24)
815         s41.add_vpp_config()
816         s42.add_vpp_config()
817         s43.add_vpp_config()
818         s61 = VppGbpSubnet(self, 0, "2001:10::1", 64)
819         s62 = VppGbpSubnet(self, 0, "2001:10:1::1", 64)
820         s63 = VppGbpSubnet(self, 0, "2001:10:2::1", 64)
821         s61.add_vpp_config()
822         s62.add_vpp_config()
823         s63.add_vpp_config()
824
825         self.send_and_expect_bridged(self.pg0,
826                                      pkt_intra_epg_220_ip4 * 65,
827                                      self.pg4)
828         self.send_and_expect_bridged(self.pg3,
829                                      pkt_inter_epg_222_ip4 * 65,
830                                      self.pg6)
831         self.send_and_expect_bridged6(self.pg3,
832                                       pkt_inter_epg_222_ip6 * 65,
833                                       self.pg6)
834
835         self.logger.info(self.vapi.cli("sh ip fib 11.0.0.2"))
836         self.logger.info(self.vapi.cli("sh gbp endpoint-group"))
837         self.logger.info(self.vapi.cli("sh gbp endpoint"))
838         self.logger.info(self.vapi.cli("sh gbp recirc"))
839         self.logger.info(self.vapi.cli("sh int"))
840         self.logger.info(self.vapi.cli("sh int addr"))
841         self.logger.info(self.vapi.cli("sh int feat loop6"))
842         self.logger.info(self.vapi.cli("sh vlib graph ip4-gbp-src-classify"))
843         self.logger.info(self.vapi.cli("sh int feat loop3"))
844
845         #
846         # Packet destined to unknown unicast is sent on the epg uplink ...
847         #
848         pkt_intra_epg_220_to_uplink = (Ether(src=self.pg0.remote_mac,
849                                              dst="00:00:00:33:44:55") /
850                                        IP(src=eps[0].ip4.address,
851                                           dst="10.0.0.99") /
852                                        UDP(sport=1234, dport=1234) /
853                                        Raw('\xa5' * 100))
854
855         self.send_and_expect_bridged(self.pg0,
856                                      pkt_intra_epg_220_to_uplink * 65,
857                                      self.pg4)
858         # ... and nowhere else
859         self.pg1.get_capture(0, timeout=0.1)
860         self.pg1.assert_nothing_captured(remark="Flood onto other VMS")
861
862         pkt_intra_epg_221_to_uplink = (Ether(src=self.pg2.remote_mac,
863                                              dst="00:00:00:33:44:66") /
864                                        IP(src=eps[0].ip4.address,
865                                           dst="10.0.0.99") /
866                                        UDP(sport=1234, dport=1234) /
867                                        Raw('\xa5' * 100))
868
869         self.send_and_expect_bridged(self.pg2,
870                                      pkt_intra_epg_221_to_uplink * 65,
871                                      self.pg5)
872
873         #
874         # Packets from the uplink are forwarded in the absence of a contract
875         #
876         pkt_intra_epg_220_from_uplink = (Ether(src="00:00:00:33:44:55",
877                                                dst=self.pg0.remote_mac) /
878                                          IP(src=eps[0].ip4.address,
879                                             dst="10.0.0.99") /
880                                          UDP(sport=1234, dport=1234) /
881                                          Raw('\xa5' * 100))
882
883         self.send_and_expect_bridged(self.pg4,
884                                      pkt_intra_epg_220_from_uplink * 65,
885                                      self.pg0)
886
887         #
888         # in the absence of policy, endpoints in the same EPG
889         # can communicate
890         #
891         pkt_intra_epg = (Ether(src=self.pg0.remote_mac,
892                                dst=self.pg1.remote_mac) /
893                          IP(src=eps[0].ip4.address,
894                             dst=eps[1].ip4.address) /
895                          UDP(sport=1234, dport=1234) /
896                          Raw('\xa5' * 100))
897
898         self.send_and_expect_bridged(self.pg0, pkt_intra_epg * 65, self.pg1)
899
900         #
901         # in the abscense of policy, endpoints in the different EPG
902         # cannot communicate
903         #
904         pkt_inter_epg_220_to_221 = (Ether(src=self.pg0.remote_mac,
905                                           dst=self.pg2.remote_mac) /
906                                     IP(src=eps[0].ip4.address,
907                                        dst=eps[2].ip4.address) /
908                                     UDP(sport=1234, dport=1234) /
909                                     Raw('\xa5' * 100))
910         pkt_inter_epg_221_to_220 = (Ether(src=self.pg2.remote_mac,
911                                           dst=self.pg0.remote_mac) /
912                                     IP(src=eps[2].ip4.address,
913                                        dst=eps[0].ip4.address) /
914                                     UDP(sport=1234, dport=1234) /
915                                     Raw('\xa5' * 100))
916         pkt_inter_epg_220_to_222 = (Ether(src=self.pg0.remote_mac,
917                                           dst=self.router_mac) /
918                                     IP(src=eps[0].ip4.address,
919                                        dst=eps[3].ip4.address) /
920                                     UDP(sport=1234, dport=1234) /
921                                     Raw('\xa5' * 100))
922
923         self.send_and_assert_no_replies(self.pg0,
924                                         pkt_inter_epg_220_to_221 * 65)
925         self.send_and_assert_no_replies(self.pg0,
926                                         pkt_inter_epg_220_to_222 * 65)
927
928         #
929         # A uni-directional contract from EPG 220 -> 221
930         #
931         acl = VppGbpAcl(self)
932         rule = acl.create_rule(permit_deny=1, proto=17)
933         rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
934         acl_index = acl.add_vpp_config([rule, rule2])
935         c1 = VppGbpContract(self, 220, 221, acl_index)
936         c1.add_vpp_config()
937
938         self.send_and_expect_bridged(self.pg0,
939                                      pkt_inter_epg_220_to_221 * 65,
940                                      self.pg2)
941         self.send_and_assert_no_replies(self.pg0,
942                                         pkt_inter_epg_220_to_222 * 65)
943
944         #
945         # contract for the return direction
946         #
947         c2 = VppGbpContract(self, 221, 220, acl_index)
948         c2.add_vpp_config()
949
950         self.send_and_expect_bridged(self.pg0,
951                                      pkt_inter_epg_220_to_221 * 65,
952                                      self.pg2)
953         self.send_and_expect_bridged(self.pg2,
954                                      pkt_inter_epg_221_to_220 * 65,
955                                      self.pg0)
956
957         #
958         # check that inter group is still disabled for the groups
959         # not in the contract.
960         #
961         self.send_and_assert_no_replies(self.pg0,
962                                         pkt_inter_epg_220_to_222 * 65)
963
964         #
965         # A uni-directional contract from EPG 220 -> 222 'L3 routed'
966         #
967         c3 = VppGbpContract(self, 220, 222, acl_index)
968         c3.add_vpp_config()
969
970         self.logger.info(self.vapi.cli("sh gbp contract"))
971
972         self.send_and_expect_routed(self.pg0,
973                                     pkt_inter_epg_220_to_222 * 65,
974                                     self.pg3,
975                                     self.router_mac)
976
977         #
978         # remove both contracts, traffic stops in both directions
979         #
980         c2.remove_vpp_config()
981         c1.remove_vpp_config()
982         c3.remove_vpp_config()
983         acl.remove_vpp_config()
984
985         self.send_and_assert_no_replies(self.pg2,
986                                         pkt_inter_epg_221_to_220 * 65)
987         self.send_and_assert_no_replies(self.pg0,
988                                         pkt_inter_epg_220_to_221 * 65)
989         self.send_and_expect_bridged(self.pg0, pkt_intra_epg * 65, self.pg1)
990
991         #
992         # EPs to the outside world
993         #
994
995         # in the EP's RD an external subnet via the NAT EPG's recirc
996         se1 = VppGbpSubnet(self, 0, "0.0.0.0", 0,
997                            is_internal=False,
998                            sw_if_index=recirc_nat.recirc.sw_if_index,
999                            epg=epg_nat.epg)
1000         se1.add_vpp_config()
1001         se2 = VppGbpSubnet(self, 0, "11.0.0.0", 8,
1002                            is_internal=False,
1003                            sw_if_index=recirc_nat.recirc.sw_if_index,
1004                            epg=epg_nat.epg)
1005         se2.add_vpp_config()
1006         se16 = VppGbpSubnet(self, 0, "::", 0,
1007                             is_internal=False,
1008                             sw_if_index=recirc_nat.recirc.sw_if_index,
1009                             epg=epg_nat.epg)
1010         se16.add_vpp_config()
1011         # in the NAT RD an external subnet via the NAT EPG's uplink
1012         se3 = VppGbpSubnet(self, 20, "0.0.0.0", 0,
1013                            is_internal=False,
1014                            sw_if_index=epg_nat.uplink.sw_if_index,
1015                            epg=epg_nat.epg)
1016         se36 = VppGbpSubnet(self, 20, "::", 0,
1017                             is_internal=False,
1018                             sw_if_index=epg_nat.uplink.sw_if_index,
1019                             epg=epg_nat.epg)
1020         se4 = VppGbpSubnet(self, 20, "11.0.0.0", 8,
1021                            is_internal=False,
1022                            sw_if_index=epg_nat.uplink.sw_if_index,
1023                            epg=epg_nat.epg)
1024         se3.add_vpp_config()
1025         se36.add_vpp_config()
1026         se4.add_vpp_config()
1027
1028         self.logger.info(self.vapi.cli("sh ip fib 0.0.0.0/0"))
1029         self.logger.info(self.vapi.cli("sh ip fib 11.0.0.1"))
1030         self.logger.info(self.vapi.cli("sh ip6 fib ::/0"))
1031         self.logger.info(self.vapi.cli("sh ip6 fib %s" %
1032                                        eps[0].fip6))
1033
1034         #
1035         # From an EP to an outside addess: IN2OUT
1036         #
1037         pkt_inter_epg_220_to_global = (Ether(src=self.pg0.remote_mac,
1038                                              dst=self.router_mac) /
1039                                        IP(src=eps[0].ip4.address,
1040                                           dst="1.1.1.1") /
1041                                        UDP(sport=1234, dport=1234) /
1042                                        Raw('\xa5' * 100))
1043
1044         # no policy yet
1045         self.send_and_assert_no_replies(self.pg0,
1046                                         pkt_inter_epg_220_to_global * 65)
1047
1048         acl2 = VppGbpAcl(self)
1049         rule = acl2.create_rule(permit_deny=1, proto=17, sport_from=1234,
1050                                 sport_to=1234, dport_from=1234, dport_to=1234)
1051         rule2 = acl2.create_rule(is_ipv6=1, permit_deny=1, proto=17,
1052                                  sport_from=1234, sport_to=1234,
1053                                  dport_from=1234, dport_to=1234)
1054
1055         acl_index2 = acl2.add_vpp_config([rule, rule2])
1056         c4 = VppGbpContract(self, 220, 333, acl_index2)
1057         c4.add_vpp_config()
1058
1059         self.send_and_expect_natted(self.pg0,
1060                                     pkt_inter_epg_220_to_global * 65,
1061                                     self.pg7,
1062                                     eps[0].fip4.address)
1063
1064         pkt_inter_epg_220_to_global = (Ether(src=self.pg0.remote_mac,
1065                                              dst=self.router_mac) /
1066                                        IPv6(src=eps[0].ip6.address,
1067                                             dst="6001::1") /
1068                                        UDP(sport=1234, dport=1234) /
1069                                        Raw('\xa5' * 100))
1070
1071         self.send_and_expect_natted6(self.pg0,
1072                                      pkt_inter_epg_220_to_global * 65,
1073                                      self.pg7,
1074                                      eps[0].fip6.address)
1075
1076         #
1077         # From a global address to an EP: OUT2IN
1078         #
1079         pkt_inter_epg_220_from_global = (Ether(src=self.router_mac,
1080                                                dst=self.pg0.remote_mac) /
1081                                          IP(dst=eps[0].fip4.address,
1082                                             src="1.1.1.1") /
1083                                          UDP(sport=1234, dport=1234) /
1084                                          Raw('\xa5' * 100))
1085
1086         self.send_and_assert_no_replies(self.pg7,
1087                                         pkt_inter_epg_220_from_global * 65)
1088
1089         c5 = VppGbpContract(self, 333, 220, acl_index2)
1090         c5.add_vpp_config()
1091
1092         self.send_and_expect_unnatted(self.pg7,
1093                                       pkt_inter_epg_220_from_global * 65,
1094                                       eps[0].itf,
1095                                       eps[0].ip4.address)
1096
1097         pkt_inter_epg_220_from_global = (Ether(src=self.router_mac,
1098                                                dst=self.pg0.remote_mac) /
1099                                          IPv6(dst=eps[0].fip6.address,
1100                                               src="6001::1") /
1101                                          UDP(sport=1234, dport=1234) /
1102                                          Raw('\xa5' * 100))
1103
1104         self.send_and_expect_unnatted6(self.pg7,
1105                                        pkt_inter_epg_220_from_global * 65,
1106                                        eps[0].itf,
1107                                        eps[0].ip6.address)
1108
1109         #
1110         # From a local VM to another local VM using resp. public addresses:
1111         #  IN2OUT2IN
1112         #
1113         pkt_intra_epg_220_global = (Ether(src=self.pg0.remote_mac,
1114                                           dst=self.router_mac) /
1115                                     IP(src=eps[0].ip4.address,
1116                                        dst=eps[1].fip4.address) /
1117                                     UDP(sport=1234, dport=1234) /
1118                                     Raw('\xa5' * 100))
1119
1120         self.send_and_expect_double_natted(eps[0].itf,
1121                                            pkt_intra_epg_220_global * 65,
1122                                            eps[1].itf,
1123                                            eps[0].fip4.address,
1124                                            eps[1].ip4.address)
1125
1126         pkt_intra_epg_220_global = (Ether(src=self.pg0.remote_mac,
1127                                           dst=self.router_mac) /
1128                                     IPv6(src=eps[0].ip6.address,
1129                                          dst=eps[1].fip6.address) /
1130                                     UDP(sport=1234, dport=1234) /
1131                                     Raw('\xa5' * 100))
1132
1133         self.send_and_expect_double_natted6(eps[0].itf,
1134                                             pkt_intra_epg_220_global * 65,
1135                                             eps[1].itf,
1136                                             eps[0].fip6.address,
1137                                             eps[1].ip6.address)
1138
1139         #
1140         # cleanup
1141         #
1142         for ep in eps:
1143             # del static mappings for each EP from the 10/8 to 11/8 network
1144             self.vapi.nat44_add_del_static_mapping(ep.ip4.bytes,
1145                                                    ep.fip4.bytes,
1146                                                    vrf_id=0,
1147                                                    addr_only=1,
1148                                                    is_add=0)
1149             self.vapi.nat66_add_del_static_mapping(ep.ip6.bytes,
1150                                                    ep.fip6.bytes,
1151                                                    vrf_id=0,
1152                                                    is_add=0)
1153
1154         for epg in epgs:
1155             # IP config on the BVI interfaces
1156             self.vapi.sw_interface_add_del_address(epg.bvi.sw_if_index,
1157                                                    epg.bvi_ip4_n,
1158                                                    32,
1159                                                    is_add=0)
1160             self.vapi.sw_interface_add_del_address(epg.bvi.sw_if_index,
1161                                                    epg.bvi_ip6_n,
1162                                                    128,
1163                                                    is_add=0,
1164                                                    is_ipv6=True)
1165             self.logger.info(self.vapi.cli("sh int addr"))
1166
1167             epg.uplink.set_table_ip4(0)
1168             epg.uplink.set_table_ip6(0)
1169
1170             if epg != epgs[0] and epg != epgs[3]:
1171                 epg.bvi.set_table_ip4(0)
1172                 epg.bvi.set_table_ip6(0)
1173
1174                 self.vapi.nat44_interface_add_del_feature(epg.bvi.sw_if_index,
1175                                                           is_inside=1,
1176                                                           is_add=0)
1177                 self.vapi.nat66_add_del_interface(epg.bvi.sw_if_index,
1178                                                   is_inside=1,
1179                                                   is_add=0)
1180
1181         for recirc in recircs:
1182             recirc.recirc.set_table_ip4(0)
1183             recirc.recirc.set_table_ip6(0)
1184
1185             self.vapi.nat44_interface_add_del_feature(
1186                 recirc.recirc.sw_if_index,
1187                 is_inside=0,
1188                 is_add=0)
1189             self.vapi.nat66_add_del_interface(
1190                 recirc.recirc.sw_if_index,
1191                 is_inside=0,
1192                 is_add=0)
1193
1194
1195 if __name__ == '__main__':
1196     unittest.main(testRunner=VppTestRunner)