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