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