Revert "Revert "make test: fix broken interfaces""
[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, DpoProto
9
10 from scapy.packet import Raw
11 from scapy.layers.l2 import Ether, ARP
12 from scapy.layers.inet import IP, UDP
13 from scapy.layers.inet6 import IPv6, ICMPv6ND_NS,  ICMPv6NDOptSrcLLAddr, \
14     ICMPv6ND_NA
15 from scapy.utils6 import in6_getnsma, in6_getnsmac
16
17 from socket import AF_INET, AF_INET6
18 from scapy.utils import inet_pton, inet_ntop
19 from util import mactobinary
20
21
22 class VppGbpEndpoint(VppObject):
23     """
24     GDB Endpoint
25     """
26
27     @property
28     def bin_mac(self):
29         return mactobinary(self.itf.remote_mac)
30
31     @property
32     def mac(self):
33         return self.itf.remote_mac
34
35     def __init__(self, test, itf, epg, recirc, ip, fip, is_ip6=False):
36         self._test = test
37         self.itf = itf
38         self.epg = epg
39         self.recirc = recirc
40         self.ip = ip
41         self.floating_ip = fip
42         self.is_ip6 = is_ip6
43         if is_ip6:
44             self.proto = DpoProto.DPO_PROTO_IP6
45             self.af = AF_INET6
46             self.is_ip6 = True
47             self.ip_len = 128
48         else:
49             self.proto = DpoProto.DPO_PROTO_IP4
50             self.af = AF_INET
51             self.is_ip6 = False
52             self.ip_len = 32
53         self.ip_n = inet_pton(self.af, ip)
54         self.floating_ip_n = inet_pton(self.af, fip)
55
56     def add_vpp_config(self):
57         self._test.vapi.gbp_endpoint_add_del(
58             1,
59             self.itf.sw_if_index,
60             self.ip_n,
61             self.is_ip6,
62             self.epg.epg)
63         self._test.registry.register(self, self._test.logger)
64
65     def remove_vpp_config(self):
66         self._test.vapi.gbp_endpoint_add_del(
67             0,
68             self.itf.sw_if_index,
69             self.ip_n,
70             self.is_ip6,
71             self.epg.epg)
72
73     def __str__(self):
74         return self.object_id()
75
76     def object_id(self):
77         return "gbp-endpoint;[%d:%s:%d]" % (self.itf.sw_if_index,
78                                             self.ip,
79                                             self.epg.epg)
80
81     def query_vpp_config(self):
82         eps = self._test.vapi.gbp_endpoint_dump()
83         for ep in eps:
84             if self.is_ip6:
85                 if ep.endpoint.address == self.ip_n \
86                    and ep.endpoint.sw_if_index == self.itf.sw_if_index:
87                     return True
88             else:
89                 if ep.endpoint.address[:4] == self.ip_n \
90                    and ep.endpoint.sw_if_index == self.itf.sw_if_index:
91                     return True
92         return False
93
94
95 class VppGbpRecirc(VppObject):
96     """
97     GDB Recirculation Interface
98     """
99
100     def __init__(self, test, epg, recirc, is_ext=False):
101         self._test = test
102         self.recirc = recirc
103         self.epg = epg
104         self.is_ext = is_ext
105
106     def add_vpp_config(self):
107         self._test.vapi.gbp_recirc_add_del(
108             1,
109             self.recirc.sw_if_index,
110             self.epg.epg,
111             self.is_ext)
112         self._test.registry.register(self, self._test.logger)
113
114     def remove_vpp_config(self):
115         self._test.vapi.gbp_recirc_add_del(
116             0,
117             self.recirc.sw_if_index,
118             self.epg.epg,
119             self.is_ext)
120
121     def __str__(self):
122         return self.object_id()
123
124     def object_id(self):
125         return "gbp-recirc;[%d]" % (self.recirc.sw_if_index)
126
127     def query_vpp_config(self):
128         rs = self._test.vapi.gbp_recirc_dump()
129         for r in rs:
130             if r.recirc.sw_if_index == self.recirc.sw_if_index:
131                 return True
132         return False
133
134
135 class VppGbpSubnet(VppObject):
136     """
137     GDB Subnet
138     """
139
140     def __init__(self, test, table_id, address, address_len,
141                  is_internal=True, is_ip6=False,
142                  sw_if_index=None, epg=None):
143         self._test = test
144         self.table_id = table_id
145         self.address = address
146         self.address_len = address_len
147         self.is_ip6 = is_ip6
148         if is_ip6:
149             self.address_n = inet_pton(AF_INET6, address)
150         else:
151             self.address_n = inet_pton(AF_INET, address)
152         self.is_internal = is_internal
153         self.sw_if_index = sw_if_index
154         self.epg = epg
155
156     def add_vpp_config(self):
157         self._test.vapi.gbp_subnet_add_del(
158             1,
159             self.table_id,
160             self.is_internal,
161             self.address_n,
162             self.address_len,
163             sw_if_index=self.sw_if_index if self.sw_if_index else 0xffffffff,
164             epg_id=self.epg if self.epg else 0xffffffff,
165             is_ip6=self.is_ip6)
166         self._test.registry.register(self, self._test.logger)
167
168     def remove_vpp_config(self):
169         self._test.vapi.gbp_subnet_add_del(
170             0,
171             self.table_id,
172             self.is_internal,
173             self.address_n,
174             self.address_len,
175             is_ip6=self.is_ip6)
176
177     def __str__(self):
178         return self.object_id()
179
180     def object_id(self):
181         return "gbp-subnet;[%d:%s/%d]" % (self.table_id,
182                                           self.address,
183                                           self.address_len)
184
185     def query_vpp_config(self):
186         ss = self._test.vapi.gbp_subnet_dump()
187         for s in ss:
188             if s.subnet.table_id == self.table_id and \
189                s.subnet.address_length == self.address_len and \
190                s.subnet.is_ip6 == self.is_ip6:
191                 if self.is_ip6:
192                     if s.subnet.address == self.address_n:
193                         return True
194                 else:
195                     if s.subnet.address[:4] == self.address_n:
196                         return True
197         return False
198
199
200 class VppGbpEndpointGroup(VppObject):
201     """
202     GDB Endpoint Group
203     """
204
205     def __init__(self, test, epg, rd, bd, uplink,
206                  bvi, bvi_ip4, bvi_ip6=None):
207         self._test = test
208         self.uplink = uplink
209         self.bvi = bvi
210         self.bvi_ip4 = bvi_ip4
211         self.bvi_ip4_n = inet_pton(AF_INET, bvi_ip4)
212         self.bvi_ip6 = bvi_ip6
213         self.bvi_ip6_n = inet_pton(AF_INET6, bvi_ip6)
214         self.epg = epg
215         self.bd = bd
216         self.rd = rd
217
218     def add_vpp_config(self):
219         self._test.vapi.gbp_endpoint_group_add_del(
220             1,
221             self.epg,
222             self.bd,
223             self.rd,
224             self.rd,
225             self.uplink.sw_if_index)
226         self._test.registry.register(self, self._test.logger)
227
228     def remove_vpp_config(self):
229         self._test.vapi.gbp_endpoint_group_add_del(
230             0,
231             self.epg,
232             self.bd,
233             self.rd,
234             self.rd,
235             self.uplink.sw_if_index)
236
237     def __str__(self):
238         return self.object_id()
239
240     def object_id(self):
241         return "gbp-endpoint-group;[%d]" % (self.epg)
242
243     def query_vpp_config(self):
244         epgs = self._test.vapi.gbp_endpoint_group_dump()
245         for epg in epgs:
246             if epg.epg.epg_id == self.epg:
247                 return True
248         return False
249
250
251 class VppGbpContract(VppObject):
252     """
253     GDB Contract
254     """
255
256     def __init__(self, test, src_epg, dst_epg, acl_index):
257         self._test = test
258         self.acl_index = acl_index
259         self.src_epg = src_epg
260         self.dst_epg = dst_epg
261
262     def add_vpp_config(self):
263         self._test.vapi.gbp_contract_add_del(
264             1,
265             self.src_epg,
266             self.dst_epg,
267             self.acl_index)
268         self._test.registry.register(self, self._test.logger)
269
270     def remove_vpp_config(self):
271         self._test.vapi.gbp_contract_add_del(
272             0,
273             self.src_epg,
274             self.dst_epg,
275             self.acl_index)
276
277     def __str__(self):
278         return self.object_id()
279
280     def object_id(self):
281         return "gbp-contract;[%d:%s:%d]" % (self.src_epg,
282                                             self.dst_epg,
283                                             self.acl_index)
284
285     def query_vpp_config(self):
286         cs = self._test.vapi.gbp_contract_dump()
287         for c in cs:
288             if c.contract.src_epg == self.src_epg \
289                and c.contract.dst_epg == self.dst_epg:
290                 return True
291         return False
292
293
294 class TestGBP(VppTestCase):
295     """ GBP Test Case """
296
297     def setUp(self):
298         super(TestGBP, self).setUp()
299
300         self.create_pg_interfaces(range(9))
301         self.create_loopback_interfaces(9)
302
303         self.router_mac = "00:11:22:33:44:55"
304
305         for i in self.pg_interfaces:
306             i.admin_up()
307         for i in self.lo_interfaces:
308             i.admin_up()
309             self.vapi.sw_interface_set_mac_address(
310                 i.sw_if_index,
311                 mactobinary(self.router_mac))
312
313     def tearDown(self):
314         for i in self.pg_interfaces:
315             i.admin_down()
316
317         super(TestGBP, self).tearDown()
318
319     def send_and_expect_bridged(self, src, tx, dst):
320         rx = self.send_and_expect(src, tx, dst)
321
322         for r in rx:
323             self.assertEqual(r[Ether].src, tx[0][Ether].src)
324             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
325             self.assertEqual(r[IP].src, tx[0][IP].src)
326             self.assertEqual(r[IP].dst, tx[0][IP].dst)
327         return rx
328
329     def send_and_expect_bridged6(self, src, tx, dst):
330         rx = self.send_and_expect(src, tx, dst)
331
332         for r in rx:
333             self.assertEqual(r[Ether].src, tx[0][Ether].src)
334             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
335             self.assertEqual(r[IPv6].src, tx[0][IPv6].src)
336             self.assertEqual(r[IPv6].dst, tx[0][IPv6].dst)
337         return rx
338
339     def send_and_expect_routed(self, src, tx, dst, src_mac):
340         rx = self.send_and_expect(src, tx, dst)
341
342         for r in rx:
343             self.assertEqual(r[Ether].src, src_mac)
344             self.assertEqual(r[Ether].dst, dst.remote_mac)
345             self.assertEqual(r[IP].src, tx[0][IP].src)
346             self.assertEqual(r[IP].dst, tx[0][IP].dst)
347         return rx
348
349     def send_and_expect_natted(self, src, tx, dst, src_ip):
350         rx = self.send_and_expect(src, tx, dst)
351
352         for r in rx:
353             self.assertEqual(r[Ether].src, tx[0][Ether].src)
354             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
355             self.assertEqual(r[IP].src, src_ip)
356             self.assertEqual(r[IP].dst, tx[0][IP].dst)
357         return rx
358
359     def send_and_expect_natted6(self, src, tx, dst, src_ip):
360         rx = self.send_and_expect(src, tx, dst)
361
362         for r in rx:
363             self.assertEqual(r[Ether].src, tx[0][Ether].src)
364             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
365             self.assertEqual(r[IPv6].src, src_ip)
366             self.assertEqual(r[IPv6].dst, tx[0][IPv6].dst)
367         return rx
368
369     def send_and_expect_unnatted(self, src, tx, dst, dst_ip):
370         rx = self.send_and_expect(src, tx, dst)
371
372         for r in rx:
373             self.assertEqual(r[Ether].src, tx[0][Ether].src)
374             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
375             self.assertEqual(r[IP].dst, dst_ip)
376             self.assertEqual(r[IP].src, tx[0][IP].src)
377         return rx
378
379     def send_and_expect_unnatted6(self, src, tx, dst, dst_ip):
380         rx = self.send_and_expect(src, tx, dst)
381
382         for r in rx:
383             self.assertEqual(r[Ether].src, tx[0][Ether].src)
384             self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
385             self.assertEqual(r[IPv6].dst, dst_ip)
386             self.assertEqual(r[IPv6].src, tx[0][IPv6].src)
387         return rx
388
389     def send_and_expect_double_natted(self, src, tx, dst, src_ip, dst_ip):
390         rx = self.send_and_expect(src, tx, dst)
391
392         for r in rx:
393             self.assertEqual(r[Ether].src, self.router_mac)
394             self.assertEqual(r[Ether].dst, dst.remote_mac)
395             self.assertEqual(r[IP].dst, dst_ip)
396             self.assertEqual(r[IP].src, src_ip)
397         return rx
398
399     def send_and_expect_double_natted6(self, src, tx, dst, src_ip, dst_ip):
400         rx = self.send_and_expect(src, tx, dst)
401
402         for r in rx:
403             self.assertEqual(r[Ether].src, self.router_mac)
404             self.assertEqual(r[Ether].dst, dst.remote_mac)
405             self.assertEqual(r[IPv6].dst, dst_ip)
406             self.assertEqual(r[IPv6].src, src_ip)
407         return rx
408
409     def test_gbp(self):
410         """ Group Based Policy """
411
412         nat_table = VppIpTable(self, 20)
413         nat_table.add_vpp_config()
414         nat_table = VppIpTable(self, 20, is_ip6=True)
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)