ipip: Tunnel flags controlling copying data to/from payload/encap
[vpp.git] / test / test_ipip.py
1 #!/usr/bin/env python3
2 """IP{4,6} over IP{v,6} tunnel functional tests"""
3
4 import unittest
5 from scapy.layers.inet6 import IPv6, Ether, IP, UDP, IPv6ExtHdrFragment, Raw
6 from scapy.all import fragment, fragment6, RandShort, defragment6
7 from framework import VppTestCase, VppTestRunner
8 from vpp_ip import DpoProto
9 from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable, FibPathProto
10 from vpp_ipip_tun_interface import VppIpIpTunInterface
11 from vpp_papi import VppEnum
12 from socket import AF_INET, AF_INET6, inet_pton
13 from util import reassemble4
14
15 """ Testipip is a subclass of  VPPTestCase classes.
16
17 IPIP tests.
18
19 """
20
21
22 def ipip_add_tunnel(test, src, dst, table_id=0, dscp=0x0,
23                     flags=0):
24     """ Add a IPIP tunnel """
25     return test.vapi.ipip_add_tunnel(
26         tunnel={
27             'src': src,
28             'dst': dst,
29             'table_id': table_id,
30             'instance': 0xffffffff,
31             'dscp': dscp,
32             'flags': flags
33         }
34     )
35
36 # the number of packets to send when injecting traffic.
37 # a multiple of 8 minus one, so we test all by 8/4/2/1 loops
38 N_PACKETS = 64 - 1
39
40
41 class TestIPIP(VppTestCase):
42     """ IPIP Test Case """
43
44     @classmethod
45     def setUpClass(cls):
46         super(TestIPIP, cls).setUpClass()
47         cls.create_pg_interfaces(range(2))
48         cls.interfaces = list(cls.pg_interfaces)
49
50     @classmethod
51     def tearDownClass(cls):
52         super(TestIPIP, cls).tearDownClass()
53
54     def setUp(self):
55         super(TestIPIP, self).setUp()
56         for i in self.interfaces:
57             i.admin_up()
58             i.config_ip4()
59             i.config_ip6()
60             i.disable_ipv6_ra()
61             i.resolve_arp()
62             i.resolve_ndp()
63
64     def tearDown(self):
65         super(TestIPIP, self).tearDown()
66         if not self.vpp_dead:
67             for i in self.pg_interfaces:
68                 i.unconfig_ip4()
69                 i.unconfig_ip6()
70                 i.admin_down()
71
72     def validate(self, rx, expected):
73         self.assertEqual(rx, expected.__class__(expected))
74
75     def generate_ip4_frags(self, payload_length, fragment_size):
76         p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
77         p_payload = UDP(sport=1234, dport=1234) / self.payload(payload_length)
78         p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
79         outer_ip4 = (p_ether / IP(src=self.pg1.remote_ip4,
80                                   id=RandShort(),
81                                   dst=self.pg0.local_ip4) / p_ip4 / p_payload)
82         frags = fragment(outer_ip4, fragment_size)
83         p4_reply = (p_ip4 / p_payload)
84         p4_reply.ttl -= 1
85         return frags, p4_reply
86
87     def verify_ip4ip4_encaps(self, a, p_ip4s, p_ip4_encaps):
88         for i, p_ip4 in enumerate(p_ip4s):
89             p_ip4.dst = a
90             p4 = (self.p_ether / p_ip4 / self.p_payload)
91             p_ip4_inner = p_ip4
92             p_ip4_inner.ttl -= 1
93             p4_reply = (p_ip4_encaps[i] / p_ip4_inner / self.p_payload)
94             p4_reply.ttl -= 1
95             p4_reply.id = 0
96             rx = self.send_and_expect(self.pg0, p4 * N_PACKETS, self.pg1)
97             for p in rx:
98                 self.validate(p[1], p4_reply)
99                 self.assert_packet_checksums_valid(p)
100
101     def verify_ip6ip4_encaps(self, a, p_ip6s, p_ip4_encaps):
102         for i, p_ip6 in enumerate(p_ip6s):
103             p_ip6.dst = a
104             p6 = (self.p_ether / p_ip6 / self.p_payload)
105             p_inner_ip6 = p_ip6
106             p_inner_ip6.hlim -= 1
107             p6_reply = (p_ip4_encaps[i] / p_inner_ip6 / self.p_payload)
108             p6_reply.ttl -= 1
109             rx = self.send_and_expect(self.pg0, p6 * N_PACKETS, self.pg1)
110             for p in rx:
111                 self.validate(p[1], p6_reply)
112                 self.assert_packet_checksums_valid(p)
113
114     def test_ipip4(self):
115         """ ip{v4,v6} over ip4 test """
116
117         self.pg1.generate_remote_hosts(5)
118         self.pg1.configure_ipv4_neighbors()
119         e = VppEnum.vl_api_ipip_tunnel_flags_t
120         d = VppEnum.vl_api_ip_dscp_t
121         self.p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
122         self.p_payload = UDP(sport=1234, dport=1234) / Raw(b'X' * 100)
123
124         # create a TOS byte by shifting a DSCP code point 2 bits. those 2 bits
125         # are for the ECN.
126         dscp = d.IP_API_DSCP_AF31 << 2
127         ecn = 3
128         dscp_ecn = d.IP_API_DSCP_AF31 << 2 | ecn
129
130         # IPv4 transport that copies the DCSP from the payload
131         tun_dscp = VppIpIpTunInterface(
132             self,
133             self.pg0,
134             self.pg0.local_ip4,
135             self.pg1.remote_hosts[0].ip4,
136             flags=e.IPIP_TUNNEL_API_FLAG_ENCAP_COPY_DSCP).add_vpp_config()
137         # IPv4 transport that copies the DCSP and ECN from the payload
138         tun_dscp_ecn = VppIpIpTunInterface(
139             self,
140             self.pg0,
141             self.pg0.local_ip4,
142             self.pg1.remote_hosts[1].ip4,
143             flags=(e.IPIP_TUNNEL_API_FLAG_ENCAP_COPY_DSCP |
144                    e.IPIP_TUNNEL_API_FLAG_ENCAP_COPY_ECN)).add_vpp_config()
145         # IPv4 transport that copies the ECN from the payload and sets the
146         # DF bit on encap. copies the ECN on decap
147         tun_ecn = VppIpIpTunInterface(
148             self,
149             self.pg0,
150             self.pg0.local_ip4,
151             self.pg1.remote_hosts[2].ip4,
152             flags=(e.IPIP_TUNNEL_API_FLAG_ENCAP_COPY_ECN |
153                    e.IPIP_TUNNEL_API_FLAG_ENCAP_SET_DF |
154                    e.IPIP_TUNNEL_API_FLAG_DECAP_COPY_ECN)).add_vpp_config()
155         # IPv4 transport that sets a fixed DSCP in the encap and copies
156         # the DF bit
157         tun = VppIpIpTunInterface(
158             self,
159             self.pg0,
160             self.pg0.local_ip4,
161             self.pg1.remote_hosts[3].ip4,
162             dscp=d.IP_API_DSCP_AF11,
163             flags=e.IPIP_TUNNEL_API_FLAG_ENCAP_COPY_DF).add_vpp_config()
164
165         # array of all the tunnels
166         tuns = [tun_dscp, tun_dscp_ecn, tun_ecn, tun]
167
168         # addresses for prefixes routed via each tunnel
169         a4s = ["" for i in range(len(tuns))]
170         a6s = ["" for i in range(len(tuns))]
171
172         # IP headers with each combination of DSCp/ECN tested
173         p_ip6s = [IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp),
174                   IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp_ecn),
175                   IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=ecn),
176                   IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=0xff)]
177         p_ip4s = [IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp, flags='DF'),
178                   IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp_ecn),
179                   IP(src="1.2.3.4", dst="130.67.0.1", tos=ecn),
180                   IP(src="1.2.3.4", dst="130.67.0.1", tos=0xff)]
181
182         # Configure each tunnel
183         for i, t in enumerate(tuns):
184             # Set interface up and enable IP on it
185             self.vapi.sw_interface_set_flags(t.sw_if_index, 1)
186             self.vapi.sw_interface_set_unnumbered(
187                 sw_if_index=self.pg0.sw_if_index,
188                 unnumbered_sw_if_index=t.sw_if_index)
189
190             # prefix for route / destination address for packets
191             a4s[i] = "130.67.%d.0" % i
192             a6s[i] = "dead:%d::" % i
193
194             # Add IPv4 and IPv6 routes via tunnel interface
195             ip4_via_tunnel = VppIpRoute(
196                 self, a4s[i], 24,
197                 [VppRoutePath("0.0.0.0",
198                               t.sw_if_index,
199                               proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
200             ip4_via_tunnel.add_vpp_config()
201
202             ip6_via_tunnel = VppIpRoute(
203                 self, a6s[i], 64,
204                 [VppRoutePath("::",
205                               t.sw_if_index,
206                               proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
207             ip6_via_tunnel.add_vpp_config()
208
209         #
210         # Encapsulation
211         #
212
213         # tun_dscp copies only the dscp
214         # expected TC values are thus only the DCSP value is present from the
215         # inner
216         exp_tcs = [dscp, dscp, 0, 0xfc]
217         p_ip44_encaps = [IP(src=self.pg0.local_ip4,
218                             dst=tun_dscp.dst,
219                             tos=tc) for tc in exp_tcs]
220         p_ip64_encaps = [IP(src=self.pg0.local_ip4,
221                             dst=tun_dscp.dst,
222                             proto='ipv6', id=0, tos=tc) for tc in exp_tcs]
223
224         # IPv4 in to IPv4 tunnel
225         self.verify_ip4ip4_encaps(a4s[0], p_ip4s, p_ip44_encaps)
226         # IPv6 in to IPv4 tunnel
227         self.verify_ip6ip4_encaps(a6s[0], p_ip6s, p_ip64_encaps)
228
229         # tun_dscp_ecn copies the dscp and the ecn
230         exp_tcs = [dscp, dscp_ecn, ecn, 0xff]
231         p_ip44_encaps = [IP(src=self.pg0.local_ip4,
232                             dst=tun_dscp_ecn.dst,
233                             tos=tc) for tc in exp_tcs]
234         p_ip64_encaps = [IP(src=self.pg0.local_ip4,
235                             dst=tun_dscp_ecn.dst,
236                             proto='ipv6', id=0, tos=tc) for tc in exp_tcs]
237
238         self.verify_ip4ip4_encaps(a4s[1], p_ip4s, p_ip44_encaps)
239         self.verify_ip6ip4_encaps(a6s[1], p_ip6s, p_ip64_encaps)
240
241         # tun_ecn copies only the ecn and always sets DF
242         exp_tcs = [0, ecn, ecn, ecn]
243         p_ip44_encaps = [IP(src=self.pg0.local_ip4,
244                             dst=tun_ecn.dst,
245                             flags='DF', tos=tc) for tc in exp_tcs]
246         p_ip64_encaps = [IP(src=self.pg0.local_ip4,
247                             dst=tun_ecn.dst,
248                             flags='DF', proto='ipv6', id=0, tos=tc)
249                          for tc in exp_tcs]
250
251         self.verify_ip4ip4_encaps(a4s[2], p_ip4s, p_ip44_encaps)
252         self.verify_ip6ip4_encaps(a6s[2], p_ip6s, p_ip64_encaps)
253
254         # tun sets a fixed dscp and copies DF
255         fixed_dscp = tun.dscp << 2
256         flags = ['DF', 0, 0, 0]
257         p_ip44_encaps = [IP(src=self.pg0.local_ip4,
258                             dst=tun.dst,
259                             flags=f,
260                             tos=fixed_dscp) for f in flags]
261         p_ip64_encaps = [IP(src=self.pg0.local_ip4,
262                             dst=tun.dst,
263                             proto='ipv6', id=0,
264                             tos=fixed_dscp) for i in range(len(p_ip4s))]
265
266         self.verify_ip4ip4_encaps(a4s[3], p_ip4s, p_ip44_encaps)
267         self.verify_ip6ip4_encaps(a6s[3], p_ip6s, p_ip64_encaps)
268
269         #
270         # Decapsulation
271         #
272         n_packets_decapped = 0
273         self.p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
274
275         # IPv4 tunnel to IPv4
276         tcs = [0, dscp, dscp_ecn, ecn]
277
278         # one overlay packet and all combinations of its encap
279         p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
280         p_ip4_encaps = [IP(src=tun.dst,
281                            dst=self.pg0.local_ip4,
282                            tos=tc) for tc in tcs]
283
284         # for each encap tun will produce the same inner packet because it does
285         # not copy up fields from the payload
286         for p_ip4_encap in p_ip4_encaps:
287             p4 = (self.p_ether / p_ip4_encap / p_ip4 / self.p_payload)
288             p4_reply = (p_ip4 / self.p_payload)
289             p4_reply.ttl -= 1
290             rx = self.send_and_expect(self.pg1, p4 * N_PACKETS, self.pg0)
291             n_packets_decapped += N_PACKETS
292             for p in rx:
293                 self.validate(p[1], p4_reply)
294                 self.assert_packet_checksums_valid(p)
295
296         err = self.statistics.get_err_counter(
297             '/err/ipip4-input/packets decapsulated')
298         self.assertEqual(err, n_packets_decapped)
299
300         # tun_ecn copies the ECN bits from the encap to the inner
301         p_ip4_encaps = [IP(src=tun_ecn.dst,
302                            dst=self.pg0.local_ip4,
303                            tos=tc) for tc in tcs]
304         p_ip4_replys = [p_ip4.copy() for i in range(len(p_ip4_encaps))]
305         p_ip4_replys[2].tos = ecn
306         p_ip4_replys[3].tos = ecn
307         for i, p_ip4_encap in enumerate(p_ip4_encaps):
308             p4 = (self.p_ether / p_ip4_encap / p_ip4 / self.p_payload)
309             p4_reply = (p_ip4_replys[i] / self.p_payload)
310             p4_reply.ttl -= 1
311             rx = self.send_and_expect(self.pg1, p4 * N_PACKETS, self.pg0)
312             n_packets_decapped += N_PACKETS
313             for p in rx:
314                 self.validate(p[1], p4_reply)
315                 self.assert_packet_checksums_valid(p)
316
317         err = self.statistics.get_err_counter(
318             '/err/ipip4-input/packets decapsulated')
319         self.assertEqual(err, n_packets_decapped)
320
321         # IPv4 tunnel to IPv6
322         # for each encap tun will produce the same inner packet because it does
323         # not copy up fields from the payload
324         p_ip4_encaps = [IP(src=tun.dst,
325                            dst=self.pg0.local_ip4,
326                            tos=tc) for tc in tcs]
327         p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
328         for p_ip4_encap in p_ip4_encaps:
329             p6 = (self.p_ether /
330                   p_ip4_encap / p_ip6 /
331                   self.p_payload)
332             p6_reply = (p_ip6 / self.p_payload)
333             p6_reply.hlim = 63
334             rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
335             n_packets_decapped += N_PACKETS
336             for p in rx:
337                 self.validate(p[1], p6_reply)
338                 self.assert_packet_checksums_valid(p)
339
340         err = self.statistics.get_err_counter(
341             '/err/ipip4-input/packets decapsulated')
342         self.assertEqual(err, n_packets_decapped)
343
344         # IPv4 tunnel to IPv6
345         # tun_ecn copies the ECN bits from the encap to the inner
346         p_ip4_encaps = [IP(src=tun_ecn.dst,
347                            dst=self.pg0.local_ip4,
348                            tos=tc) for tc in tcs]
349         p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
350         p_ip6_replys = [p_ip6.copy() for i in range(len(p_ip4_encaps))]
351         p_ip6_replys[2].tc = ecn
352         p_ip6_replys[3].tc = ecn
353         for i, p_ip4_encap in enumerate(p_ip4_encaps):
354             p6 = (self.p_ether / p_ip4_encap / p_ip6 / self.p_payload)
355             p6_reply = (p_ip6_replys[i] / self.p_payload)
356             p6_reply.hlim = 63
357             rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
358             n_packets_decapped += N_PACKETS
359             for p in rx:
360                 self.validate(p[1], p6_reply)
361                 self.assert_packet_checksums_valid(p)
362
363         err = self.statistics.get_err_counter(
364             '/err/ipip4-input/packets decapsulated')
365         self.assertEqual(err, n_packets_decapped)
366
367         #
368         # Fragmentation / Reassembly and Re-fragmentation
369         #
370         rv = self.vapi.ip_reassembly_enable_disable(
371             sw_if_index=self.pg1.sw_if_index,
372             enable_ip4=1)
373
374         self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=1000,
375                                     max_reassembly_length=1000,
376                                     expire_walk_interval_ms=10000,
377                                     is_ip6=0)
378
379         # Send lots of fragments, verify reassembled packet
380         frags, p4_reply = self.generate_ip4_frags(3131, 1400)
381         f = []
382         for i in range(0, 1000):
383             f.extend(frags)
384         self.pg1.add_stream(f)
385         self.pg_enable_capture()
386         self.pg_start()
387         rx = self.pg0.get_capture(1000)
388         n_packets_decapped += 1000
389
390         for p in rx:
391             self.validate(p[1], p4_reply)
392
393         err = self.statistics.get_err_counter(
394             '/err/ipip4-input/packets decapsulated')
395         self.assertEqual(err, n_packets_decapped)
396
397         f = []
398         r = []
399         for i in range(1, 90):
400             frags, p4_reply = self.generate_ip4_frags(i * 100, 1000)
401             f.extend(frags)
402             r.extend(p4_reply)
403         self.pg_enable_capture()
404         self.pg1.add_stream(f)
405         self.pg_start()
406         rx = self.pg0.get_capture(89)
407         i = 0
408         for p in rx:
409             self.validate(p[1], r[i])
410             i += 1
411
412         # Now try with re-fragmentation
413         #
414         # Send fragments to tunnel head-end, for the tunnel head end
415         # to reassemble and then refragment
416         #
417         self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [576, 0, 0, 0])
418         frags, p4_reply = self.generate_ip4_frags(3123, 1200)
419         self.pg_enable_capture()
420         self.pg1.add_stream(frags)
421         self.pg_start()
422         rx = self.pg0.get_capture(6)
423         reass_pkt = reassemble4(rx)
424         p4_reply.id = 256
425         self.validate(reass_pkt, p4_reply)
426
427         self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [1600, 0, 0, 0])
428         frags, p4_reply = self.generate_ip4_frags(3123, 1200)
429         self.pg_enable_capture()
430         self.pg1.add_stream(frags)
431         self.pg_start()
432         rx = self.pg0.get_capture(2)
433         reass_pkt = reassemble4(rx)
434         p4_reply.id = 512
435         self.validate(reass_pkt, p4_reply)
436
437         # send large packets through the tunnel, expect them to be fragmented
438         self.vapi.sw_interface_set_mtu(tun_dscp.sw_if_index, [600, 0, 0, 0])
439
440         p4 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
441               IP(src="1.2.3.4", dst="130.67.0.1", tos=42) /
442               UDP(sport=1234, dport=1234) / Raw(b'Q' * 1000))
443         rx = self.send_and_expect(self.pg0, p4 * 15, self.pg1, 30)
444         inners = []
445         for p in rx:
446             inners.append(p[IP].payload)
447         reass_pkt = reassemble4(inners)
448         for p in reass_pkt:
449             self.assert_packet_checksums_valid(p)
450             self.assertEqual(p[IP].ttl, 63)
451
452     def test_ipip_create(self):
453         """ ipip create / delete interface test """
454         rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5')
455         sw_if_index = rv.sw_if_index
456         self.vapi.ipip_del_tunnel(sw_if_index)
457
458     def test_ipip_vrf_create(self):
459         """ ipip create / delete interface VRF test """
460
461         t = VppIpTable(self, 20)
462         t.add_vpp_config()
463         rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5', table_id=20)
464         sw_if_index = rv.sw_if_index
465         self.vapi.ipip_del_tunnel(sw_if_index)
466
467     def payload(self, len):
468         return 'x' * len
469
470
471 class TestIPIP6(VppTestCase):
472     """ IPIP6 Test Case """
473
474     @classmethod
475     def setUpClass(cls):
476         super(TestIPIP6, cls).setUpClass()
477         cls.create_pg_interfaces(range(2))
478         cls.interfaces = list(cls.pg_interfaces)
479
480     @classmethod
481     def tearDownClass(cls):
482         super(TestIPIP6, cls).tearDownClass()
483
484     def setUp(self):
485         super(TestIPIP6, self).setUp()
486         for i in self.interfaces:
487             i.admin_up()
488             i.config_ip4()
489             i.config_ip6()
490             i.disable_ipv6_ra()
491             i.resolve_arp()
492             i.resolve_ndp()
493         self.setup_tunnel()
494
495     def tearDown(self):
496         if not self.vpp_dead:
497             self.destroy_tunnel()
498             for i in self.pg_interfaces:
499                 i.unconfig_ip4()
500                 i.unconfig_ip6()
501                 i.admin_down()
502             super(TestIPIP6, self).tearDown()
503
504     def setup_tunnel(self):
505         # IPv6 transport
506         rv = ipip_add_tunnel(self,
507                              self.pg0.local_ip6,
508                              self.pg1.remote_ip6)
509
510         sw_if_index = rv.sw_if_index
511         self.tunnel_if_index = sw_if_index
512         self.vapi.sw_interface_set_flags(sw_if_index, 1)
513         self.vapi.sw_interface_set_unnumbered(
514             sw_if_index=self.pg0.sw_if_index,
515             unnumbered_sw_if_index=sw_if_index)
516
517         # Add IPv4 and IPv6 routes via tunnel interface
518         ip4_via_tunnel = VppIpRoute(
519             self, "130.67.0.0", 16,
520             [VppRoutePath("0.0.0.0",
521                           sw_if_index,
522                           proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
523         ip4_via_tunnel.add_vpp_config()
524
525         ip6_via_tunnel = VppIpRoute(
526             self, "dead::", 16,
527             [VppRoutePath("::",
528                           sw_if_index,
529                           proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
530         ip6_via_tunnel.add_vpp_config()
531
532         self.tunnel_ip6_via_tunnel = ip6_via_tunnel
533         self.tunnel_ip4_via_tunnel = ip4_via_tunnel
534
535     def destroy_tunnel(self):
536         # IPv6 transport
537         self.tunnel_ip4_via_tunnel.remove_vpp_config()
538         self.tunnel_ip6_via_tunnel.remove_vpp_config()
539
540         rv = self.vapi.ipip_del_tunnel(sw_if_index=self.tunnel_if_index)
541
542     def validate(self, rx, expected):
543         self.assertEqual(rx, expected.__class__(expected))
544
545     def generate_ip6_frags(self, payload_length, fragment_size):
546         p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
547         p_payload = UDP(sport=1234, dport=1234) / self.payload(payload_length)
548         p_ip6 = IPv6(src="1::1", dst=self.pg0.remote_ip6)
549         outer_ip6 = (p_ether / IPv6(src=self.pg1.remote_ip6,
550                                     dst=self.pg0.local_ip6) /
551                      IPv6ExtHdrFragment() / p_ip6 / p_payload)
552         frags = fragment6(outer_ip6, fragment_size)
553         p6_reply = (p_ip6 / p_payload)
554         p6_reply.hlim -= 1
555         return frags, p6_reply
556
557     def generate_ip6_hairpin_frags(self, payload_length, fragment_size):
558         p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
559         p_payload = UDP(sport=1234, dport=1234) / self.payload(payload_length)
560         p_ip6 = IPv6(src="1::1", dst="dead::1")
561         outer_ip6 = (p_ether / IPv6(src=self.pg1.remote_ip6,
562                                     dst=self.pg0.local_ip6) /
563                      IPv6ExtHdrFragment() / p_ip6 / p_payload)
564         frags = fragment6(outer_ip6, fragment_size)
565         p_ip6.hlim -= 1
566         p6_reply = (IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6,
567                          hlim=63) / p_ip6 / p_payload)
568
569         return frags, p6_reply
570
571     def test_encap(self):
572         """ ip{v4,v6} over ip6 test encap """
573         p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
574         p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP')
575         p_ip4 = IP(src="1.2.3.4", dst="130.67.0.1", tos=42)
576         p_payload = UDP(sport=1234, dport=1234)
577
578         # Encapsulation
579         # IPv6 in to IPv6 tunnel
580         p6 = (p_ether / p_ip6 / p_payload)
581         p6_reply = (IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6,
582                          hlim=64) /
583                     p_ip6 / p_payload)
584         p6_reply[1].hlim -= 1
585         rx = self.send_and_expect(self.pg0, p6 * 11, self.pg1)
586         for p in rx:
587             self.validate(p[1], p6_reply)
588
589         # IPv4 in to IPv6 tunnel
590         p4 = (p_ether / p_ip4 / p_payload)
591         p4_reply = (IPv6(src=self.pg0.local_ip6,
592                          dst=self.pg1.remote_ip6, hlim=64) /
593                     p_ip4 / p_payload)
594         p4_reply[1].ttl -= 1
595         rx = self.send_and_expect(self.pg0, p4 * 11, self.pg1)
596         for p in rx:
597             self.validate(p[1], p4_reply)
598
599     def test_decap(self):
600         """ ip{v4,v6} over ip6 test decap """
601
602         p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
603         p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP')
604         p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
605         p_payload = UDP(sport=1234, dport=1234)
606
607         # Decapsulation
608         # IPv6 tunnel to IPv4
609
610         p4 = (p_ether / IPv6(src=self.pg1.remote_ip6,
611                              dst=self.pg0.local_ip6) / p_ip4 / p_payload)
612         p4_reply = (p_ip4 / p_payload)
613         p4_reply.ttl -= 1
614         rx = self.send_and_expect(self.pg1, p4 * 11, self.pg0)
615         for p in rx:
616             self.validate(p[1], p4_reply)
617
618         # IPv6 tunnel to IPv6
619         p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
620         p6 = (p_ether / IPv6(src=self.pg1.remote_ip6,
621                              dst=self.pg0.local_ip6) / p_ip6 / p_payload)
622         p6_reply = (p_ip6 / p_payload)
623         p6_reply.hlim = 63
624         rx = self.send_and_expect(self.pg1, p6 * 11, self.pg0)
625         for p in rx:
626             self.validate(p[1], p6_reply)
627
628     def verify_ip4ip6_encaps(self, a, p_ip4s, p_ip6_encaps):
629         for i, p_ip4 in enumerate(p_ip4s):
630             p_ip4.dst = a
631             p4 = (self.p_ether / p_ip4 / self.p_payload)
632             p_ip4_inner = p_ip4
633             p_ip4_inner.ttl -= 1
634             p6_reply = (p_ip6_encaps[i] / p_ip4_inner / self.p_payload)
635             rx = self.send_and_expect(self.pg0, p4 * N_PACKETS, self.pg1)
636             for p in rx:
637                 self.validate(p[1], p6_reply)
638                 self.assert_packet_checksums_valid(p)
639
640     def verify_ip6ip6_encaps(self, a, p_ip6s, p_ip6_encaps):
641         for i, p_ip6 in enumerate(p_ip6s):
642             p_ip6.dst = a
643             p6 = (self.p_ether / p_ip6 / self.p_payload)
644             p_inner_ip6 = p_ip6
645             p_inner_ip6.hlim -= 1
646             p6_reply = (p_ip6_encaps[i] / p_inner_ip6 / self.p_payload)
647             rx = self.send_and_expect(self.pg0, p6 * N_PACKETS, self.pg1)
648             for p in rx:
649                 self.validate(p[1], p6_reply)
650                 self.assert_packet_checksums_valid(p)
651
652     def test_ipip6(self):
653         """ ip{v4,v6} over ip6 test """
654
655         # that's annoying
656         self.destroy_tunnel()
657
658         self.pg1.generate_remote_hosts(5)
659         self.pg1.configure_ipv6_neighbors()
660         e = VppEnum.vl_api_ipip_tunnel_flags_t
661         d = VppEnum.vl_api_ip_dscp_t
662         self.p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
663         self.p_payload = UDP(sport=1234, dport=1234) / Raw(b'X' * 100)
664
665         # create a TOS byte by shifting a DSCP code point 2 bits. those 2 bits
666         # are for the ECN.
667         dscp = d.IP_API_DSCP_AF31 << 2
668         ecn = 3
669         dscp_ecn = d.IP_API_DSCP_AF31 << 2 | ecn
670
671         # IPv4 transport that copies the DCSP from the payload
672         tun_dscp = VppIpIpTunInterface(
673             self,
674             self.pg0,
675             self.pg0.local_ip6,
676             self.pg1.remote_hosts[0].ip6,
677             flags=e.IPIP_TUNNEL_API_FLAG_ENCAP_COPY_DSCP).add_vpp_config()
678         # IPv4 transport that copies the DCSP and ECN from the payload
679         tun_dscp_ecn = VppIpIpTunInterface(
680             self,
681             self.pg0,
682             self.pg0.local_ip6,
683             self.pg1.remote_hosts[1].ip6,
684             flags=(e.IPIP_TUNNEL_API_FLAG_ENCAP_COPY_DSCP |
685                    e.IPIP_TUNNEL_API_FLAG_ENCAP_COPY_ECN)).add_vpp_config()
686         # IPv4 transport that copies the ECN from the payload and sets the
687         # DF bit on encap. copies the ECN on decap
688         tun_ecn = VppIpIpTunInterface(
689             self,
690             self.pg0,
691             self.pg0.local_ip6,
692             self.pg1.remote_hosts[2].ip6,
693             flags=(e.IPIP_TUNNEL_API_FLAG_ENCAP_COPY_ECN |
694                    e.IPIP_TUNNEL_API_FLAG_ENCAP_SET_DF |
695                    e.IPIP_TUNNEL_API_FLAG_DECAP_COPY_ECN)).add_vpp_config()
696         # IPv4 transport that sets a fixed DSCP in the encap and copies
697         # the DF bit
698         tun = VppIpIpTunInterface(
699             self,
700             self.pg0,
701             self.pg0.local_ip6,
702             self.pg1.remote_hosts[3].ip6,
703             dscp=d.IP_API_DSCP_AF11,
704             flags=e.IPIP_TUNNEL_API_FLAG_ENCAP_COPY_DF).add_vpp_config()
705
706         # array of all the tunnels
707         tuns = [tun_dscp, tun_dscp_ecn, tun_ecn, tun]
708
709         # addresses for prefixes routed via each tunnel
710         a4s = ["" for i in range(len(tuns))]
711         a6s = ["" for i in range(len(tuns))]
712
713         # IP headers for inner packets with each combination of DSCp/ECN tested
714         p_ip6s = [IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp),
715                   IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp_ecn),
716                   IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=ecn),
717                   IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=0xff)]
718         p_ip4s = [IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp, flags='DF'),
719                   IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp_ecn),
720                   IP(src="1.2.3.4", dst="130.67.0.1", tos=ecn),
721                   IP(src="1.2.3.4", dst="130.67.0.1", tos=0xff)]
722
723         # Configure each tunnel
724         for i, t in enumerate(tuns):
725             # Set interface up and enable IP on it
726             self.vapi.sw_interface_set_flags(t.sw_if_index, 1)
727             self.vapi.sw_interface_set_unnumbered(
728                 sw_if_index=self.pg0.sw_if_index,
729                 unnumbered_sw_if_index=t.sw_if_index)
730
731             # prefix for route / destination address for packets
732             a4s[i] = "130.67.%d.0" % i
733             a6s[i] = "dead:%d::" % i
734
735             # Add IPv4 and IPv6 routes via tunnel interface
736             ip4_via_tunnel = VppIpRoute(
737                 self, a4s[i], 24,
738                 [VppRoutePath("0.0.0.0",
739                               t.sw_if_index,
740                               proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
741             ip4_via_tunnel.add_vpp_config()
742
743             ip6_via_tunnel = VppIpRoute(
744                 self, a6s[i], 64,
745                 [VppRoutePath("::",
746                               t.sw_if_index,
747                               proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
748             ip6_via_tunnel.add_vpp_config()
749
750         #
751         # Encapsulation
752         #
753
754         # tun_dscp copies only the dscp
755         # expected TC values are thus only the DCSP value is present from the
756         # inner
757         exp_tcs = [dscp, dscp, 0, 0xfc]
758         p_ip6_encaps = [IPv6(src=self.pg0.local_ip6,
759                              dst=tun_dscp.dst,
760                              tc=tc) for tc in exp_tcs]
761
762         # IPv4 in to IPv4 tunnel
763         self.verify_ip4ip6_encaps(a4s[0], p_ip4s, p_ip6_encaps)
764         # IPv6 in to IPv4 tunnel
765         self.verify_ip6ip6_encaps(a6s[0], p_ip6s, p_ip6_encaps)
766
767         # tun_dscp_ecn copies the dscp and the ecn
768         exp_tcs = [dscp, dscp_ecn, ecn, 0xff]
769         p_ip6_encaps = [IPv6(src=self.pg0.local_ip6,
770                              dst=tun_dscp_ecn.dst,
771                              tc=tc) for tc in exp_tcs]
772
773         self.verify_ip4ip6_encaps(a4s[1], p_ip4s, p_ip6_encaps)
774         self.verify_ip6ip6_encaps(a6s[1], p_ip6s, p_ip6_encaps)
775
776         # tun_ecn copies only the ecn and always sets DF
777         exp_tcs = [0, ecn, ecn, ecn]
778         p_ip6_encaps = [IPv6(src=self.pg0.local_ip6,
779                              dst=tun_ecn.dst,
780                              tc=tc) for tc in exp_tcs]
781
782         self.verify_ip4ip6_encaps(a4s[2], p_ip4s, p_ip6_encaps)
783         self.verify_ip6ip6_encaps(a6s[2], p_ip6s, p_ip6_encaps)
784
785         # tun sets a fixed dscp
786         fixed_dscp = tun.dscp << 2
787         p_ip6_encaps = [IPv6(src=self.pg0.local_ip6,
788                              dst=tun.dst,
789                              tc=fixed_dscp) for i in range(len(p_ip4s))]
790
791         self.verify_ip4ip6_encaps(a4s[3], p_ip4s, p_ip6_encaps)
792         self.verify_ip6ip6_encaps(a6s[3], p_ip6s, p_ip6_encaps)
793
794         #
795         # Decapsulation
796         #
797         n_packets_decapped = self.statistics.get_err_counter(
798             '/err/ipip6-input/packets decapsulated')
799
800         self.p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
801
802         # IPv6 tunnel to IPv4
803         tcs = [0, dscp, dscp_ecn, ecn]
804
805         # one overlay packet and all combinations of its encap
806         p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
807         p_ip6_encaps = [IPv6(src=tun.dst,
808                              dst=self.pg0.local_ip6,
809                              tc=tc) for tc in tcs]
810
811         # for each encap tun will produce the same inner packet because it does
812         # not copy up fields from the payload
813         for p_ip6_encap in p_ip6_encaps:
814             p6 = (self.p_ether / p_ip6_encap / p_ip4 / self.p_payload)
815             p4_reply = (p_ip4 / self.p_payload)
816             p4_reply.ttl -= 1
817             rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
818             n_packets_decapped += N_PACKETS
819             for p in rx:
820                 self.validate(p[1], p4_reply)
821                 self.assert_packet_checksums_valid(p)
822
823         err = self.statistics.get_err_counter(
824             '/err/ipip6-input/packets decapsulated')
825         self.assertEqual(err, n_packets_decapped)
826
827         # tun_ecn copies the ECN bits from the encap to the inner
828         p_ip6_encaps = [IPv6(src=tun_ecn.dst,
829                              dst=self.pg0.local_ip6,
830                              tc=tc) for tc in tcs]
831         p_ip4_replys = [p_ip4.copy() for i in range(len(p_ip6_encaps))]
832         p_ip4_replys[2].tos = ecn
833         p_ip4_replys[3].tos = ecn
834         for i, p_ip6_encap in enumerate(p_ip6_encaps):
835             p6 = (self.p_ether / p_ip6_encap / p_ip4 / self.p_payload)
836             p4_reply = (p_ip4_replys[i] / self.p_payload)
837             p4_reply.ttl -= 1
838             rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
839             n_packets_decapped += N_PACKETS
840             for p in rx:
841                 self.validate(p[1], p4_reply)
842                 self.assert_packet_checksums_valid(p)
843
844         err = self.statistics.get_err_counter(
845             '/err/ipip6-input/packets decapsulated')
846         self.assertEqual(err, n_packets_decapped)
847
848         # IPv6 tunnel to IPv6
849         # for each encap tun will produce the same inner packet because it does
850         # not copy up fields from the payload
851         p_ip6_encaps = [IPv6(src=tun.dst,
852                              dst=self.pg0.local_ip6,
853                              tc=tc) for tc in tcs]
854         p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
855         for p_ip6_encap in p_ip6_encaps:
856             p6 = (self.p_ether / p_ip6_encap / p_ip6 / self.p_payload)
857             p6_reply = (p_ip6 / self.p_payload)
858             p6_reply.hlim = 63
859             rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
860             n_packets_decapped += N_PACKETS
861             for p in rx:
862                 self.validate(p[1], p6_reply)
863                 self.assert_packet_checksums_valid(p)
864
865         err = self.statistics.get_err_counter(
866             '/err/ipip6-input/packets decapsulated')
867         self.assertEqual(err, n_packets_decapped)
868
869         # IPv6 tunnel to IPv6
870         # tun_ecn copies the ECN bits from the encap to the inner
871         p_ip6_encaps = [IPv6(src=tun_ecn.dst,
872                              dst=self.pg0.local_ip6,
873                              tc=tc) for tc in tcs]
874         p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
875         p_ip6_replys = [p_ip6.copy() for i in range(len(p_ip6_encaps))]
876         p_ip6_replys[2].tc = ecn
877         p_ip6_replys[3].tc = ecn
878         for i, p_ip6_encap in enumerate(p_ip6_encaps):
879             p6 = (self.p_ether / p_ip6_encap / p_ip6 / self.p_payload)
880             p6_reply = (p_ip6_replys[i] / self.p_payload)
881             p6_reply.hlim = 63
882             rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
883             n_packets_decapped += N_PACKETS
884             for p in rx:
885                 self.validate(p[1], p6_reply)
886                 self.assert_packet_checksums_valid(p)
887
888         err = self.statistics.get_err_counter(
889             '/err/ipip6-input/packets decapsulated')
890         self.assertEqual(err, n_packets_decapped)
891
892     def test_frag(self):
893         """ ip{v4,v6} over ip6 test frag """
894
895         p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
896         p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP')
897         p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
898         p_payload = UDP(sport=1234, dport=1234)
899
900         #
901         # Fragmentation / Reassembly and Re-fragmentation
902         #
903         rv = self.vapi.ip_reassembly_enable_disable(
904             sw_if_index=self.pg1.sw_if_index,
905             enable_ip6=1)
906
907         self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=1000,
908                                     max_reassembly_length=1000,
909                                     expire_walk_interval_ms=10000,
910                                     is_ip6=1)
911
912         # Send lots of fragments, verify reassembled packet
913         before_cnt = self.statistics.get_err_counter(
914             '/err/ipip6-input/packets decapsulated')
915         frags, p6_reply = self.generate_ip6_frags(3131, 1400)
916         f = []
917         for i in range(0, 1000):
918             f.extend(frags)
919         self.pg1.add_stream(f)
920         self.pg_enable_capture()
921         self.pg_start()
922         rx = self.pg0.get_capture(1000)
923
924         for p in rx:
925             self.validate(p[1], p6_reply)
926
927         cnt = self.statistics.get_err_counter(
928             '/err/ipip6-input/packets decapsulated')
929         self.assertEqual(cnt, before_cnt + 1000)
930
931         f = []
932         r = []
933         # TODO: Check out why reassembly of atomic fragments don't work
934         for i in range(10, 90):
935             frags, p6_reply = self.generate_ip6_frags(i * 100, 1000)
936             f.extend(frags)
937             r.extend(p6_reply)
938         self.pg_enable_capture()
939         self.pg1.add_stream(f)
940         self.pg_start()
941         rx = self.pg0.get_capture(80)
942         i = 0
943         for p in rx:
944             self.validate(p[1], r[i])
945             i += 1
946
947         # Simple fragmentation
948         p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
949         self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1280, 0, 0, 0])
950
951         # IPv6 in to IPv6 tunnel
952         p_payload = UDP(sport=1234, dport=1234) / self.payload(1300)
953
954         p6 = (p_ether / p_ip6 / p_payload)
955         p6_reply = (IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6,
956                          hlim=63) /
957                     p_ip6 / p_payload)
958         p6_reply[1].hlim -= 1
959         self.pg_enable_capture()
960         self.pg0.add_stream(p6)
961         self.pg_start()
962         rx = self.pg1.get_capture(2)
963
964         # Scapy defragment doesn't deal well with multiple layers
965         # of same type / Ethernet header first
966         f = [p[1] for p in rx]
967         reass_pkt = defragment6(f)
968         self.validate(reass_pkt, p6_reply)
969
970         # Now try with re-fragmentation
971         #
972         # Send large fragments to tunnel head-end, for the tunnel head end
973         # to reassemble and then refragment out the tunnel again.
974         # Hair-pinning
975         #
976         self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1280, 0, 0, 0])
977         frags, p6_reply = self.generate_ip6_hairpin_frags(8000, 1200)
978         self.pg_enable_capture()
979         self.pg1.add_stream(frags)
980         self.pg_start()
981         rx = self.pg1.get_capture(7)
982         f = [p[1] for p in rx]
983         reass_pkt = defragment6(f)
984         p6_reply.id = 256
985         self.validate(reass_pkt, p6_reply)
986
987     def test_ipip_create(self):
988         """ ipip create / delete interface test """
989         rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5')
990         sw_if_index = rv.sw_if_index
991         self.vapi.ipip_del_tunnel(sw_if_index)
992
993     def test_ipip_vrf_create(self):
994         """ ipip create / delete interface VRF test """
995
996         t = VppIpTable(self, 20)
997         t.add_vpp_config()
998         rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5', table_id=20)
999         sw_if_index = rv.sw_if_index
1000         self.vapi.ipip_del_tunnel(sw_if_index)
1001
1002     def payload(self, len):
1003         return 'x' * len
1004
1005
1006 if __name__ == '__main__':
1007     unittest.main(testRunner=VppTestRunner)