tests: replace pycodestyle with black
[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.contrib.mpls import MPLS
7 from scapy.all import fragment, fragment6, RandShort, defragment6
8 from framework import VppTestCase, VppTestRunner
9 from vpp_ip import DpoProto
10 from vpp_ip_route import (
11     VppIpRoute,
12     VppRoutePath,
13     VppIpTable,
14     FibPathProto,
15     VppMplsLabel,
16     VppMplsRoute,
17     VppMplsTable,
18 )
19 from vpp_ipip_tun_interface import VppIpIpTunInterface
20 from vpp_teib import VppTeib
21 from vpp_papi import VppEnum
22 from socket import AF_INET, AF_INET6, inet_pton
23 from util import reassemble4
24
25 """ Testipip is a subclass of  VPPTestCase classes.
26
27 IPIP tests.
28
29 """
30
31
32 def ipip_add_tunnel(test, src, dst, table_id=0, dscp=0x0, flags=0):
33     """Add a IPIP tunnel"""
34     return test.vapi.ipip_add_tunnel(
35         tunnel={
36             "src": src,
37             "dst": dst,
38             "table_id": table_id,
39             "instance": 0xFFFFFFFF,
40             "dscp": dscp,
41             "flags": flags,
42         }
43     )
44
45
46 # the number of packets to send when injecting traffic.
47 # a multiple of 8 minus one, so we test all by 8/4/2/1 loops
48 N_PACKETS = 64 - 1
49
50
51 class TestIPIP(VppTestCase):
52     """IPIP Test Case"""
53
54     @classmethod
55     def setUpClass(cls):
56         super(TestIPIP, cls).setUpClass()
57         cls.create_pg_interfaces(range(3))
58         cls.interfaces = list(cls.pg_interfaces)
59
60     @classmethod
61     def tearDownClass(cls):
62         super(TestIPIP, cls).tearDownClass()
63
64     def setUp(self):
65         super(TestIPIP, self).setUp()
66         self.table = VppIpTable(self, 1, register=False)
67         self.table.add_vpp_config()
68
69         for i in self.interfaces:
70             i.admin_up()
71
72         self.pg2.set_table_ip4(self.table.table_id)
73         for i in self.interfaces:
74             i.config_ip4()
75             i.config_ip6()
76             i.disable_ipv6_ra()
77             i.resolve_arp()
78             i.resolve_ndp()
79
80     def tearDown(self):
81         super(TestIPIP, self).tearDown()
82         if not self.vpp_dead:
83             for i in self.pg_interfaces:
84                 i.unconfig_ip4()
85                 i.unconfig_ip6()
86                 i.set_table_ip4(0)
87                 i.admin_down()
88
89         self.table.remove_vpp_config()
90
91     def validate(self, rx, expected):
92         self.assertEqual(rx, expected.__class__(expected))
93
94     def generate_ip4_frags(self, payload_length, fragment_size):
95         p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
96         p_payload = UDP(sport=1234, dport=1234) / self.payload(payload_length)
97         p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
98         outer_ip4 = (
99             p_ether
100             / IP(src=self.pg1.remote_ip4, id=RandShort(), dst=self.pg0.local_ip4)
101             / p_ip4
102             / p_payload
103         )
104         frags = fragment(outer_ip4, fragment_size)
105         p4_reply = p_ip4 / p_payload
106         p4_reply.ttl -= 1
107         return frags, p4_reply
108
109     def verify_ip4ip4_encaps(self, a, p_ip4s, p_ip4_encaps):
110         for i, p_ip4 in enumerate(p_ip4s):
111             p_ip4.dst = a
112             p4 = self.p_ether / p_ip4 / self.p_payload
113             p_ip4_inner = p_ip4
114             p_ip4_inner.ttl -= 1
115             p4_reply = p_ip4_encaps[i] / p_ip4_inner / self.p_payload
116             p4_reply.ttl -= 1
117             p4_reply.id = 0
118             rx = self.send_and_expect(self.pg0, p4 * N_PACKETS, self.pg1)
119             for p in rx:
120                 self.validate(p[1], p4_reply)
121                 self.assert_packet_checksums_valid(p)
122
123     def verify_ip6ip4_encaps(self, a, p_ip6s, p_ip4_encaps):
124         for i, p_ip6 in enumerate(p_ip6s):
125             p_ip6.dst = a
126             p6 = self.p_ether / p_ip6 / self.p_payload
127             p_inner_ip6 = p_ip6
128             p_inner_ip6.hlim -= 1
129             p6_reply = p_ip4_encaps[i] / p_inner_ip6 / self.p_payload
130             p6_reply.ttl -= 1
131             rx = self.send_and_expect(self.pg0, p6 * N_PACKETS, self.pg1)
132             for p in rx:
133                 self.validate(p[1], p6_reply)
134                 self.assert_packet_checksums_valid(p)
135
136     def test_ipip4(self):
137         """ip{v4,v6} over ip4 test"""
138
139         self.pg1.generate_remote_hosts(5)
140         self.pg1.configure_ipv4_neighbors()
141         e = VppEnum.vl_api_tunnel_encap_decap_flags_t
142         d = VppEnum.vl_api_ip_dscp_t
143         self.p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
144         self.p_payload = UDP(sport=1234, dport=1234) / Raw(b"X" * 100)
145
146         # create a TOS byte by shifting a DSCP code point 2 bits. those 2 bits
147         # are for the ECN.
148         dscp = d.IP_API_DSCP_AF31 << 2
149         ecn = 3
150         dscp_ecn = d.IP_API_DSCP_AF31 << 2 | ecn
151
152         # IPv4 transport that copies the DCSP from the payload
153         tun_dscp = VppIpIpTunInterface(
154             self,
155             self.pg0,
156             self.pg0.local_ip4,
157             self.pg1.remote_hosts[0].ip4,
158             flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP,
159         )
160         tun_dscp.add_vpp_config()
161         # IPv4 transport that copies the DCSP and ECN from the payload
162         tun_dscp_ecn = VppIpIpTunInterface(
163             self,
164             self.pg0,
165             self.pg0.local_ip4,
166             self.pg1.remote_hosts[1].ip4,
167             flags=(
168                 e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP
169                 | e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN
170             ),
171         )
172         tun_dscp_ecn.add_vpp_config()
173         # IPv4 transport that copies the ECN from the payload and sets the
174         # DF bit on encap. copies the ECN on decap
175         tun_ecn = VppIpIpTunInterface(
176             self,
177             self.pg0,
178             self.pg0.local_ip4,
179             self.pg1.remote_hosts[2].ip4,
180             flags=(
181                 e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN
182                 | e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_SET_DF
183                 | e.TUNNEL_API_ENCAP_DECAP_FLAG_DECAP_COPY_ECN
184             ),
185         )
186         tun_ecn.add_vpp_config()
187         # IPv4 transport that sets a fixed DSCP in the encap and copies
188         # the DF bit
189         tun = VppIpIpTunInterface(
190             self,
191             self.pg0,
192             self.pg0.local_ip4,
193             self.pg1.remote_hosts[3].ip4,
194             dscp=d.IP_API_DSCP_AF11,
195             flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DF,
196         )
197         tun.add_vpp_config()
198
199         # array of all the tunnels
200         tuns = [tun_dscp, tun_dscp_ecn, tun_ecn, tun]
201
202         # addresses for prefixes routed via each tunnel
203         a4s = ["" for i in range(len(tuns))]
204         a6s = ["" for i in range(len(tuns))]
205
206         # IP headers with each combination of DSCp/ECN tested
207         p_ip6s = [
208             IPv6(src="1::1", dst="DEAD::1", nh="UDP", tc=dscp),
209             IPv6(src="1::1", dst="DEAD::1", nh="UDP", tc=dscp_ecn),
210             IPv6(src="1::1", dst="DEAD::1", nh="UDP", tc=ecn),
211             IPv6(src="1::1", dst="DEAD::1", nh="UDP", tc=0xFF),
212         ]
213         p_ip4s = [
214             IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp, flags="DF"),
215             IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp_ecn),
216             IP(src="1.2.3.4", dst="130.67.0.1", tos=ecn),
217             IP(src="1.2.3.4", dst="130.67.0.1", tos=0xFF),
218         ]
219
220         # Configure each tunnel
221         for i, t in enumerate(tuns):
222             # Set interface up and enable IP on it
223             self.vapi.sw_interface_set_flags(t.sw_if_index, 1)
224             self.vapi.sw_interface_set_unnumbered(
225                 sw_if_index=self.pg0.sw_if_index, unnumbered_sw_if_index=t.sw_if_index
226             )
227
228             # prefix for route / destination address for packets
229             a4s[i] = "130.67.%d.0" % i
230             a6s[i] = "dead:%d::" % i
231
232             # Add IPv4 and IPv6 routes via tunnel interface
233             ip4_via_tunnel = VppIpRoute(
234                 self,
235                 a4s[i],
236                 24,
237                 [
238                     VppRoutePath(
239                         "0.0.0.0",
240                         t.sw_if_index,
241                         proto=FibPathProto.FIB_PATH_NH_PROTO_IP4,
242                     )
243                 ],
244             )
245             ip4_via_tunnel.add_vpp_config()
246
247             ip6_via_tunnel = VppIpRoute(
248                 self,
249                 a6s[i],
250                 64,
251                 [
252                     VppRoutePath(
253                         "::", t.sw_if_index, proto=FibPathProto.FIB_PATH_NH_PROTO_IP6
254                     )
255                 ],
256             )
257             ip6_via_tunnel.add_vpp_config()
258
259         #
260         # Encapsulation
261         #
262
263         # tun_dscp copies only the dscp
264         # expected TC values are thus only the DCSP value is present from the
265         # inner
266         exp_tcs = [dscp, dscp, 0, 0xFC]
267         p_ip44_encaps = [
268             IP(src=self.pg0.local_ip4, dst=tun_dscp.dst, tos=tc) for tc in exp_tcs
269         ]
270         p_ip64_encaps = [
271             IP(src=self.pg0.local_ip4, dst=tun_dscp.dst, proto="ipv6", id=0, tos=tc)
272             for tc in exp_tcs
273         ]
274
275         # IPv4 in to IPv4 tunnel
276         self.verify_ip4ip4_encaps(a4s[0], p_ip4s, p_ip44_encaps)
277         # IPv6 in to IPv4 tunnel
278         self.verify_ip6ip4_encaps(a6s[0], p_ip6s, p_ip64_encaps)
279
280         # tun_dscp_ecn copies the dscp and the ecn
281         exp_tcs = [dscp, dscp_ecn, ecn, 0xFF]
282         p_ip44_encaps = [
283             IP(src=self.pg0.local_ip4, dst=tun_dscp_ecn.dst, tos=tc) for tc in exp_tcs
284         ]
285         p_ip64_encaps = [
286             IP(src=self.pg0.local_ip4, dst=tun_dscp_ecn.dst, proto="ipv6", id=0, tos=tc)
287             for tc in exp_tcs
288         ]
289
290         self.verify_ip4ip4_encaps(a4s[1], p_ip4s, p_ip44_encaps)
291         self.verify_ip6ip4_encaps(a6s[1], p_ip6s, p_ip64_encaps)
292
293         # tun_ecn copies only the ecn and always sets DF
294         exp_tcs = [0, ecn, ecn, ecn]
295         p_ip44_encaps = [
296             IP(src=self.pg0.local_ip4, dst=tun_ecn.dst, flags="DF", tos=tc)
297             for tc in exp_tcs
298         ]
299         p_ip64_encaps = [
300             IP(
301                 src=self.pg0.local_ip4,
302                 dst=tun_ecn.dst,
303                 flags="DF",
304                 proto="ipv6",
305                 id=0,
306                 tos=tc,
307             )
308             for tc in exp_tcs
309         ]
310
311         self.verify_ip4ip4_encaps(a4s[2], p_ip4s, p_ip44_encaps)
312         self.verify_ip6ip4_encaps(a6s[2], p_ip6s, p_ip64_encaps)
313
314         # tun sets a fixed dscp and copies DF
315         fixed_dscp = tun.dscp << 2
316         flags = ["DF", 0, 0, 0]
317         p_ip44_encaps = [
318             IP(src=self.pg0.local_ip4, dst=tun.dst, flags=f, tos=fixed_dscp)
319             for f in flags
320         ]
321         p_ip64_encaps = [
322             IP(src=self.pg0.local_ip4, dst=tun.dst, proto="ipv6", id=0, tos=fixed_dscp)
323             for i in range(len(p_ip4s))
324         ]
325
326         self.verify_ip4ip4_encaps(a4s[3], p_ip4s, p_ip44_encaps)
327         self.verify_ip6ip4_encaps(a6s[3], p_ip6s, p_ip64_encaps)
328
329         #
330         # Decapsulation
331         #
332         n_packets_decapped = 0
333         self.p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
334
335         # IPv4 tunnel to IPv4
336         tcs = [0, dscp, dscp_ecn, ecn]
337
338         # one overlay packet and all combinations of its encap
339         p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
340         p_ip4_encaps = [IP(src=tun.dst, dst=self.pg0.local_ip4, tos=tc) for tc in tcs]
341
342         # for each encap tun will produce the same inner packet because it does
343         # not copy up fields from the payload
344         for p_ip4_encap in p_ip4_encaps:
345             p4 = self.p_ether / p_ip4_encap / p_ip4 / self.p_payload
346             p4_reply = p_ip4 / self.p_payload
347             p4_reply.ttl -= 1
348             rx = self.send_and_expect(self.pg1, p4 * N_PACKETS, self.pg0)
349             n_packets_decapped += N_PACKETS
350             for p in rx:
351                 self.validate(p[1], p4_reply)
352                 self.assert_packet_checksums_valid(p)
353
354         err = self.statistics.get_err_counter("/err/ipip4-input/packets decapsulated")
355         self.assertEqual(err, n_packets_decapped)
356
357         # tun_ecn copies the ECN bits from the encap to the inner
358         p_ip4_encaps = [
359             IP(src=tun_ecn.dst, dst=self.pg0.local_ip4, tos=tc) for tc in tcs
360         ]
361         p_ip4_replys = [p_ip4.copy() for i in range(len(p_ip4_encaps))]
362         p_ip4_replys[2].tos = ecn
363         p_ip4_replys[3].tos = ecn
364         for i, p_ip4_encap in enumerate(p_ip4_encaps):
365             p4 = self.p_ether / p_ip4_encap / p_ip4 / self.p_payload
366             p4_reply = p_ip4_replys[i] / self.p_payload
367             p4_reply.ttl -= 1
368             rx = self.send_and_expect(self.pg1, p4 * N_PACKETS, self.pg0)
369             n_packets_decapped += N_PACKETS
370             for p in rx:
371                 self.validate(p[1], p4_reply)
372                 self.assert_packet_checksums_valid(p)
373
374         err = self.statistics.get_err_counter("/err/ipip4-input/packets decapsulated")
375         self.assertEqual(err, n_packets_decapped)
376
377         # IPv4 tunnel to IPv6
378         # for each encap tun will produce the same inner packet because it does
379         # not copy up fields from the payload
380         p_ip4_encaps = [IP(src=tun.dst, dst=self.pg0.local_ip4, tos=tc) for tc in tcs]
381         p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
382         for p_ip4_encap in p_ip4_encaps:
383             p6 = self.p_ether / p_ip4_encap / p_ip6 / self.p_payload
384             p6_reply = p_ip6 / self.p_payload
385             p6_reply.hlim = 63
386             rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
387             n_packets_decapped += N_PACKETS
388             for p in rx:
389                 self.validate(p[1], p6_reply)
390                 self.assert_packet_checksums_valid(p)
391
392         err = self.statistics.get_err_counter("/err/ipip4-input/packets decapsulated")
393         self.assertEqual(err, n_packets_decapped)
394
395         # IPv4 tunnel to IPv6
396         # tun_ecn copies the ECN bits from the encap to the inner
397         p_ip4_encaps = [
398             IP(src=tun_ecn.dst, dst=self.pg0.local_ip4, tos=tc) for tc in tcs
399         ]
400         p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
401         p_ip6_replys = [p_ip6.copy() for i in range(len(p_ip4_encaps))]
402         p_ip6_replys[2].tc = ecn
403         p_ip6_replys[3].tc = ecn
404         for i, p_ip4_encap in enumerate(p_ip4_encaps):
405             p6 = self.p_ether / p_ip4_encap / p_ip6 / self.p_payload
406             p6_reply = p_ip6_replys[i] / self.p_payload
407             p6_reply.hlim = 63
408             rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
409             n_packets_decapped += N_PACKETS
410             for p in rx:
411                 self.validate(p[1], p6_reply)
412                 self.assert_packet_checksums_valid(p)
413
414         err = self.statistics.get_err_counter("/err/ipip4-input/packets decapsulated")
415         self.assertEqual(err, n_packets_decapped)
416
417         #
418         # Fragmentation / Reassembly and Re-fragmentation
419         #
420         rv = self.vapi.ip_reassembly_enable_disable(
421             sw_if_index=self.pg1.sw_if_index, enable_ip4=1
422         )
423
424         self.vapi.ip_reassembly_set(
425             timeout_ms=1000,
426             max_reassemblies=1000,
427             max_reassembly_length=1000,
428             expire_walk_interval_ms=10000,
429             is_ip6=0,
430         )
431
432         # Send lots of fragments, verify reassembled packet
433         frags, p4_reply = self.generate_ip4_frags(3131, 1400)
434         f = []
435         for i in range(0, 1000):
436             f.extend(frags)
437         self.pg1.add_stream(f)
438         self.pg_enable_capture()
439         self.pg_start()
440         rx = self.pg0.get_capture(1000)
441         n_packets_decapped += 1000
442
443         for p in rx:
444             self.validate(p[1], p4_reply)
445
446         err = self.statistics.get_err_counter("/err/ipip4-input/packets decapsulated")
447         self.assertEqual(err, n_packets_decapped)
448
449         f = []
450         r = []
451         for i in range(1, 90):
452             frags, p4_reply = self.generate_ip4_frags(i * 100, 1000)
453             f.extend(frags)
454             r.extend(p4_reply)
455         self.pg_enable_capture()
456         self.pg1.add_stream(f)
457         self.pg_start()
458         rx = self.pg0.get_capture(89)
459         i = 0
460         for p in rx:
461             self.validate(p[1], r[i])
462             i += 1
463
464         # Now try with re-fragmentation
465         #
466         # Send fragments to tunnel head-end, for the tunnel head end
467         # to reassemble and then refragment
468         #
469         self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [576, 0, 0, 0])
470         frags, p4_reply = self.generate_ip4_frags(3123, 1200)
471         self.pg_enable_capture()
472         self.pg1.add_stream(frags)
473         self.pg_start()
474         rx = self.pg0.get_capture(6)
475         reass_pkt = reassemble4(rx)
476         p4_reply.id = 256
477         self.validate(reass_pkt, p4_reply)
478
479         self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [1600, 0, 0, 0])
480         frags, p4_reply = self.generate_ip4_frags(3123, 1200)
481         self.pg_enable_capture()
482         self.pg1.add_stream(frags)
483         self.pg_start()
484         rx = self.pg0.get_capture(2)
485         reass_pkt = reassemble4(rx)
486         p4_reply.id = 512
487         self.validate(reass_pkt, p4_reply)
488
489         # send large packets through the tunnel, expect them to be fragmented
490         self.vapi.sw_interface_set_mtu(tun_dscp.sw_if_index, [600, 0, 0, 0])
491
492         p4 = (
493             Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
494             / IP(src="1.2.3.4", dst="130.67.0.1", tos=42)
495             / UDP(sport=1234, dport=1234)
496             / Raw(b"Q" * 1000)
497         )
498         rx = self.send_and_expect(self.pg0, p4 * 15, self.pg1, 30)
499         inners = []
500         for p in rx:
501             inners.append(p[IP].payload)
502         reass_pkt = reassemble4(inners)
503         for p in reass_pkt:
504             self.assert_packet_checksums_valid(p)
505             self.assertEqual(p[IP].ttl, 63)
506
507     def test_ipip_create(self):
508         """ipip create / delete interface test"""
509         rv = ipip_add_tunnel(self, "1.2.3.4", "2.3.4.5")
510         sw_if_index = rv.sw_if_index
511         self.vapi.ipip_del_tunnel(sw_if_index)
512
513     def test_ipip_vrf_create(self):
514         """ipip create / delete interface VRF test"""
515
516         t = VppIpTable(self, 20)
517         t.add_vpp_config()
518         rv = ipip_add_tunnel(self, "1.2.3.4", "2.3.4.5", table_id=20)
519         sw_if_index = rv.sw_if_index
520         self.vapi.ipip_del_tunnel(sw_if_index)
521
522     def payload(self, len):
523         return "x" * len
524
525     def test_mipip4(self):
526         """p2mp IPv4 tunnel Tests"""
527
528         for itf in self.pg_interfaces[:2]:
529             #
530             # one underlay nh for each overlay/tunnel peer
531             #
532             itf.generate_remote_hosts(4)
533             itf.configure_ipv4_neighbors()
534
535             #
536             # Create an p2mo IPIP tunnel.
537             #  - set it admin up
538             #  - assign an IP Addres
539             #  - Add a route via the tunnel
540             #
541             ipip_if = VppIpIpTunInterface(
542                 self,
543                 itf,
544                 itf.local_ip4,
545                 "0.0.0.0",
546                 mode=(VppEnum.vl_api_tunnel_mode_t.TUNNEL_API_MODE_MP),
547             )
548             ipip_if.add_vpp_config()
549             ipip_if.admin_up()
550             ipip_if.config_ip4()
551             ipip_if.generate_remote_hosts(4)
552
553             self.logger.info(self.vapi.cli("sh adj"))
554             self.logger.info(self.vapi.cli("sh ip fib"))
555
556             #
557             # ensure we don't match to the tunnel if the source address
558             # is all zeros
559             #
560             # tx = self.create_tunnel_stream_4o4(self.pg0,
561             #                                    "0.0.0.0",
562             #                                    itf.local_ip4,
563             #                                    self.pg0.local_ip4,
564             #                                    self.pg0.remote_ip4)
565             # self.send_and_assert_no_replies(self.pg0, tx)
566
567             #
568             # for-each peer
569             #
570             for ii in range(1, 4):
571                 route_addr = "4.4.4.%d" % ii
572
573                 #
574                 # route traffic via the peer
575                 #
576                 route_via_tun = VppIpRoute(
577                     self,
578                     route_addr,
579                     32,
580                     [VppRoutePath(ipip_if._remote_hosts[ii].ip4, ipip_if.sw_if_index)],
581                 )
582                 route_via_tun.add_vpp_config()
583
584                 #
585                 # Add a TEIB entry resolves the peer
586                 #
587                 teib = VppTeib(
588                     self,
589                     ipip_if,
590                     ipip_if._remote_hosts[ii].ip4,
591                     itf._remote_hosts[ii].ip4,
592                 )
593                 teib.add_vpp_config()
594                 self.logger.info(
595                     self.vapi.cli("sh adj nbr ipip0 %s" % ipip_if._remote_hosts[ii].ip4)
596                 )
597
598                 #
599                 # Send a packet stream that is routed into the tunnel
600                 #  - packets are IPIP encapped
601                 #
602                 inner = (
603                     IP(dst=route_addr, src="5.5.5.5")
604                     / UDP(sport=1234, dport=1234)
605                     / Raw(b"0x44" * 100)
606                 )
607                 tx_e = [
608                     (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / inner)
609                     for x in range(63)
610                 ]
611
612                 rxs = self.send_and_expect(self.pg0, tx_e, itf)
613
614                 for rx in rxs:
615                     self.assertEqual(rx[IP].src, itf.local_ip4)
616                     self.assertEqual(rx[IP].dst, itf._remote_hosts[ii].ip4)
617
618                 tx_i = [
619                     (
620                         Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
621                         / IP(src=itf._remote_hosts[ii].ip4, dst=itf.local_ip4)
622                         / IP(src=self.pg0.local_ip4, dst=self.pg0.remote_ip4)
623                         / UDP(sport=1234, dport=1234)
624                         / Raw(b"0x44" * 100)
625                     )
626                     for x in range(63)
627                 ]
628
629                 self.logger.info(self.vapi.cli("sh ipip tunnel-hash"))
630                 rx = self.send_and_expect(self.pg0, tx_i, self.pg0)
631
632                 #
633                 # delete and re-add the TEIB
634                 #
635                 teib.remove_vpp_config()
636                 self.send_and_assert_no_replies(self.pg0, tx_e)
637                 self.send_and_assert_no_replies(self.pg0, tx_i)
638
639                 teib.add_vpp_config()
640                 rx = self.send_and_expect(self.pg0, tx_e, itf)
641                 for rx in rxs:
642                     self.assertEqual(rx[IP].src, itf.local_ip4)
643                     self.assertEqual(rx[IP].dst, itf._remote_hosts[ii].ip4)
644                 rx = self.send_and_expect(self.pg0, tx_i, self.pg0)
645
646                 #
647                 # we can also send to the peer's address
648                 #
649                 inner = (
650                     IP(dst=teib.peer, src="5.5.5.5")
651                     / UDP(sport=1234, dport=1234)
652                     / Raw(b"0x44" * 100)
653                 )
654                 tx_e = [
655                     (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / inner)
656                     for x in range(63)
657                 ]
658
659                 rxs = self.send_and_expect(self.pg0, tx_e, itf)
660
661             #
662             # with all of the peers in place, swap the ip-table of
663             # the ipip interface
664             #
665             table = VppIpTable(self, 2)
666             table.add_vpp_config()
667
668             ipip_if.unconfig_ip4()
669             ipip_if.set_table_ip4(self.table.table_id)
670             ipip_if.config_ip4()
671
672             #
673             # we should still be able to reach the peers from the new table
674             #
675             inner = (
676                 IP(dst=teib.peer, src="5.5.5.5")
677                 / UDP(sport=1234, dport=1234)
678                 / Raw(b"0x44" * 100)
679             )
680             tx_e = [
681                 (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / inner)
682                 for x in range(63)
683             ]
684
685             rxs = self.send_and_expect(self.pg2, tx_e, itf)
686
687             ipip_if.admin_down()
688             ipip_if.unconfig_ip4()
689             ipip_if.set_table_ip4(0)
690
691
692 class TestIPIP6(VppTestCase):
693     """IPIP6 Test Case"""
694
695     @classmethod
696     def setUpClass(cls):
697         super(TestIPIP6, cls).setUpClass()
698         cls.create_pg_interfaces(range(2))
699         cls.interfaces = list(cls.pg_interfaces)
700
701     @classmethod
702     def tearDownClass(cls):
703         super(TestIPIP6, cls).tearDownClass()
704
705     def setUp(self):
706         super(TestIPIP6, self).setUp()
707         for i in self.interfaces:
708             i.admin_up()
709             i.config_ip4()
710             i.config_ip6()
711             i.disable_ipv6_ra()
712             i.resolve_arp()
713             i.resolve_ndp()
714         self.setup_tunnel()
715
716     def tearDown(self):
717         if not self.vpp_dead:
718             self.destroy_tunnel()
719             for i in self.pg_interfaces:
720                 i.unconfig_ip4()
721                 i.unconfig_ip6()
722                 i.admin_down()
723             super(TestIPIP6, self).tearDown()
724
725     def setup_tunnel(self):
726         # IPv6 transport
727         rv = ipip_add_tunnel(self, self.pg0.local_ip6, self.pg1.remote_ip6)
728
729         sw_if_index = rv.sw_if_index
730         self.tunnel_if_index = sw_if_index
731         self.vapi.sw_interface_set_flags(sw_if_index, 1)
732         self.vapi.sw_interface_set_unnumbered(
733             sw_if_index=self.pg0.sw_if_index, unnumbered_sw_if_index=sw_if_index
734         )
735
736         # Add IPv4 and IPv6 routes via tunnel interface
737         ip4_via_tunnel = VppIpRoute(
738             self,
739             "130.67.0.0",
740             16,
741             [
742                 VppRoutePath(
743                     "0.0.0.0", sw_if_index, proto=FibPathProto.FIB_PATH_NH_PROTO_IP4
744                 )
745             ],
746         )
747         ip4_via_tunnel.add_vpp_config()
748
749         ip6_via_tunnel = VppIpRoute(
750             self,
751             "dead::",
752             16,
753             [VppRoutePath("::", sw_if_index, proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)],
754         )
755         ip6_via_tunnel.add_vpp_config()
756
757         self.tunnel_ip6_via_tunnel = ip6_via_tunnel
758         self.tunnel_ip4_via_tunnel = ip4_via_tunnel
759
760     def destroy_tunnel(self):
761         # IPv6 transport
762         self.tunnel_ip4_via_tunnel.remove_vpp_config()
763         self.tunnel_ip6_via_tunnel.remove_vpp_config()
764
765         rv = self.vapi.ipip_del_tunnel(sw_if_index=self.tunnel_if_index)
766
767     def validate(self, rx, expected):
768         self.assertEqual(rx, expected.__class__(expected))
769
770     def generate_ip6_frags(self, payload_length, fragment_size):
771         p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
772         p_payload = UDP(sport=1234, dport=1234) / self.payload(payload_length)
773         p_ip6 = IPv6(src="1::1", dst=self.pg0.remote_ip6)
774         outer_ip6 = (
775             p_ether
776             / IPv6(src=self.pg1.remote_ip6, dst=self.pg0.local_ip6)
777             / IPv6ExtHdrFragment()
778             / p_ip6
779             / p_payload
780         )
781         frags = fragment6(outer_ip6, fragment_size)
782         p6_reply = p_ip6 / p_payload
783         p6_reply.hlim -= 1
784         return frags, p6_reply
785
786     def generate_ip6_hairpin_frags(self, payload_length, fragment_size):
787         p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
788         p_payload = UDP(sport=1234, dport=1234) / self.payload(payload_length)
789         p_ip6 = IPv6(src="1::1", dst="dead::1")
790         outer_ip6 = (
791             p_ether
792             / IPv6(src=self.pg1.remote_ip6, dst=self.pg0.local_ip6)
793             / IPv6ExtHdrFragment()
794             / p_ip6
795             / p_payload
796         )
797         frags = fragment6(outer_ip6, fragment_size)
798         p_ip6.hlim -= 1
799         p6_reply = (
800             IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6, hlim=63)
801             / p_ip6
802             / p_payload
803         )
804
805         return frags, p6_reply
806
807     def test_encap(self):
808         """ip{v4,v6} over ip6 test encap"""
809         p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
810         p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh="UDP")
811         p_ip4 = IP(src="1.2.3.4", dst="130.67.0.1", tos=42)
812         p_payload = UDP(sport=1234, dport=1234)
813
814         # Encapsulation
815         # IPv6 in to IPv6 tunnel
816         p6 = p_ether / p_ip6 / p_payload
817         p6_reply = (
818             IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6, hlim=64)
819             / p_ip6
820             / p_payload
821         )
822         p6_reply[1].hlim -= 1
823         rx = self.send_and_expect(self.pg0, p6 * 11, self.pg1)
824         for p in rx:
825             self.validate(p[1], p6_reply)
826
827         # IPv4 in to IPv6 tunnel
828         p4 = p_ether / p_ip4 / p_payload
829         p4_reply = (
830             IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6, hlim=64)
831             / p_ip4
832             / p_payload
833         )
834         p4_reply[1].ttl -= 1
835         rx = self.send_and_expect(self.pg0, p4 * 11, self.pg1)
836         for p in rx:
837             self.validate(p[1], p4_reply)
838
839     def test_decap(self):
840         """ip{v4,v6} over ip6 test decap"""
841
842         p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
843         p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh="UDP")
844         p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
845         p_payload = UDP(sport=1234, dport=1234)
846
847         # Decapsulation
848         # IPv6 tunnel to IPv4
849
850         p4 = (
851             p_ether
852             / IPv6(src=self.pg1.remote_ip6, dst=self.pg0.local_ip6)
853             / p_ip4
854             / p_payload
855         )
856         p4_reply = p_ip4 / p_payload
857         p4_reply.ttl -= 1
858         rx = self.send_and_expect(self.pg1, p4 * 11, self.pg0)
859         for p in rx:
860             self.validate(p[1], p4_reply)
861
862         # IPv6 tunnel to IPv6
863         p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
864         p6 = (
865             p_ether
866             / IPv6(src=self.pg1.remote_ip6, dst=self.pg0.local_ip6)
867             / p_ip6
868             / p_payload
869         )
870         p6_reply = p_ip6 / p_payload
871         p6_reply.hlim = 63
872         rx = self.send_and_expect(self.pg1, p6 * 11, self.pg0)
873         for p in rx:
874             self.validate(p[1], p6_reply)
875
876     def verify_ip4ip6_encaps(self, a, p_ip4s, p_ip6_encaps):
877         for i, p_ip4 in enumerate(p_ip4s):
878             p_ip4.dst = a
879             p4 = self.p_ether / p_ip4 / self.p_payload
880             p_ip4_inner = p_ip4
881             p_ip4_inner.ttl -= 1
882             p6_reply = p_ip6_encaps[i] / p_ip4_inner / self.p_payload
883             rx = self.send_and_expect(self.pg0, p4 * N_PACKETS, self.pg1)
884             for p in rx:
885                 self.validate(p[1], p6_reply)
886                 self.assert_packet_checksums_valid(p)
887
888     def verify_ip6ip6_encaps(self, a, p_ip6s, p_ip6_encaps):
889         for i, p_ip6 in enumerate(p_ip6s):
890             p_ip6.dst = a
891             p6 = self.p_ether / p_ip6 / self.p_payload
892             p_inner_ip6 = p_ip6
893             p_inner_ip6.hlim -= 1
894             p6_reply = p_ip6_encaps[i] / p_inner_ip6 / self.p_payload
895             rx = self.send_and_expect(self.pg0, p6 * N_PACKETS, self.pg1)
896             for p in rx:
897                 self.validate(p[1], p6_reply)
898                 self.assert_packet_checksums_valid(p)
899
900     def test_ipip6(self):
901         """ip{v4,v6} over ip6 test"""
902
903         # that's annoying
904         self.destroy_tunnel()
905
906         self.pg1.generate_remote_hosts(5)
907         self.pg1.configure_ipv6_neighbors()
908         e = VppEnum.vl_api_tunnel_encap_decap_flags_t
909         d = VppEnum.vl_api_ip_dscp_t
910         self.p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
911         self.p_payload = UDP(sport=1234, dport=1234) / Raw(b"X" * 100)
912
913         # create a TOS byte by shifting a DSCP code point 2 bits. those 2 bits
914         # are for the ECN.
915         dscp = d.IP_API_DSCP_AF31 << 2
916         ecn = 3
917         dscp_ecn = d.IP_API_DSCP_AF31 << 2 | ecn
918
919         # IPv4 transport that copies the DCSP from the payload
920         tun_dscp = VppIpIpTunInterface(
921             self,
922             self.pg0,
923             self.pg0.local_ip6,
924             self.pg1.remote_hosts[0].ip6,
925             flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP,
926         )
927         tun_dscp.add_vpp_config()
928         # IPv4 transport that copies the DCSP and ECN from the payload
929         tun_dscp_ecn = VppIpIpTunInterface(
930             self,
931             self.pg0,
932             self.pg0.local_ip6,
933             self.pg1.remote_hosts[1].ip6,
934             flags=(
935                 e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP
936                 | e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN
937             ),
938         )
939         tun_dscp_ecn.add_vpp_config()
940         # IPv4 transport that copies the ECN from the payload and sets the
941         # DF bit on encap. copies the ECN on decap
942         tun_ecn = VppIpIpTunInterface(
943             self,
944             self.pg0,
945             self.pg0.local_ip6,
946             self.pg1.remote_hosts[2].ip6,
947             flags=(
948                 e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN
949                 | e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_SET_DF
950                 | e.TUNNEL_API_ENCAP_DECAP_FLAG_DECAP_COPY_ECN
951             ),
952         )
953         tun_ecn.add_vpp_config()
954         # IPv4 transport that sets a fixed DSCP in the encap and copies
955         # the DF bit
956         tun = VppIpIpTunInterface(
957             self,
958             self.pg0,
959             self.pg0.local_ip6,
960             self.pg1.remote_hosts[3].ip6,
961             dscp=d.IP_API_DSCP_AF11,
962             flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DF,
963         )
964         tun.add_vpp_config()
965
966         # array of all the tunnels
967         tuns = [tun_dscp, tun_dscp_ecn, tun_ecn, tun]
968
969         # addresses for prefixes routed via each tunnel
970         a4s = ["" for i in range(len(tuns))]
971         a6s = ["" for i in range(len(tuns))]
972
973         # IP headers for inner packets with each combination of DSCp/ECN tested
974         p_ip6s = [
975             IPv6(src="1::1", dst="DEAD::1", nh="UDP", tc=dscp),
976             IPv6(src="1::1", dst="DEAD::1", nh="UDP", tc=dscp_ecn),
977             IPv6(src="1::1", dst="DEAD::1", nh="UDP", tc=ecn),
978             IPv6(src="1::1", dst="DEAD::1", nh="UDP", tc=0xFF),
979         ]
980         p_ip4s = [
981             IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp, flags="DF"),
982             IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp_ecn),
983             IP(src="1.2.3.4", dst="130.67.0.1", tos=ecn),
984             IP(src="1.2.3.4", dst="130.67.0.1", tos=0xFF),
985         ]
986
987         # Configure each tunnel
988         for i, t in enumerate(tuns):
989             # Set interface up and enable IP on it
990             self.vapi.sw_interface_set_flags(t.sw_if_index, 1)
991             self.vapi.sw_interface_set_unnumbered(
992                 sw_if_index=self.pg0.sw_if_index, unnumbered_sw_if_index=t.sw_if_index
993             )
994
995             # prefix for route / destination address for packets
996             a4s[i] = "130.67.%d.0" % i
997             a6s[i] = "dead:%d::" % i
998
999             # Add IPv4 and IPv6 routes via tunnel interface
1000             ip4_via_tunnel = VppIpRoute(
1001                 self,
1002                 a4s[i],
1003                 24,
1004                 [
1005                     VppRoutePath(
1006                         "0.0.0.0",
1007                         t.sw_if_index,
1008                         proto=FibPathProto.FIB_PATH_NH_PROTO_IP4,
1009                     )
1010                 ],
1011             )
1012             ip4_via_tunnel.add_vpp_config()
1013
1014             ip6_via_tunnel = VppIpRoute(
1015                 self,
1016                 a6s[i],
1017                 64,
1018                 [
1019                     VppRoutePath(
1020                         "::", t.sw_if_index, proto=FibPathProto.FIB_PATH_NH_PROTO_IP6
1021                     )
1022                 ],
1023             )
1024             ip6_via_tunnel.add_vpp_config()
1025
1026         #
1027         # Encapsulation
1028         #
1029
1030         # tun_dscp copies only the dscp
1031         # expected TC values are thus only the DCSP value is present from the
1032         # inner
1033         exp_tcs = [dscp, dscp, 0, 0xFC]
1034         p_ip6_encaps = [
1035             IPv6(src=self.pg0.local_ip6, dst=tun_dscp.dst, tc=tc) for tc in exp_tcs
1036         ]
1037
1038         # IPv4 in to IPv4 tunnel
1039         self.verify_ip4ip6_encaps(a4s[0], p_ip4s, p_ip6_encaps)
1040         # IPv6 in to IPv4 tunnel
1041         self.verify_ip6ip6_encaps(a6s[0], p_ip6s, p_ip6_encaps)
1042
1043         # tun_dscp_ecn copies the dscp and the ecn
1044         exp_tcs = [dscp, dscp_ecn, ecn, 0xFF]
1045         p_ip6_encaps = [
1046             IPv6(src=self.pg0.local_ip6, dst=tun_dscp_ecn.dst, tc=tc) for tc in exp_tcs
1047         ]
1048
1049         self.verify_ip4ip6_encaps(a4s[1], p_ip4s, p_ip6_encaps)
1050         self.verify_ip6ip6_encaps(a6s[1], p_ip6s, p_ip6_encaps)
1051
1052         # tun_ecn copies only the ecn and always sets DF
1053         exp_tcs = [0, ecn, ecn, ecn]
1054         p_ip6_encaps = [
1055             IPv6(src=self.pg0.local_ip6, dst=tun_ecn.dst, tc=tc) for tc in exp_tcs
1056         ]
1057
1058         self.verify_ip4ip6_encaps(a4s[2], p_ip4s, p_ip6_encaps)
1059         self.verify_ip6ip6_encaps(a6s[2], p_ip6s, p_ip6_encaps)
1060
1061         # tun sets a fixed dscp
1062         fixed_dscp = tun.dscp << 2
1063         p_ip6_encaps = [
1064             IPv6(src=self.pg0.local_ip6, dst=tun.dst, tc=fixed_dscp)
1065             for i in range(len(p_ip4s))
1066         ]
1067
1068         self.verify_ip4ip6_encaps(a4s[3], p_ip4s, p_ip6_encaps)
1069         self.verify_ip6ip6_encaps(a6s[3], p_ip6s, p_ip6_encaps)
1070
1071         #
1072         # Decapsulation
1073         #
1074         n_packets_decapped = self.statistics.get_err_counter(
1075             "/err/ipip6-input/packets decapsulated"
1076         )
1077
1078         self.p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
1079
1080         # IPv6 tunnel to IPv4
1081         tcs = [0, dscp, dscp_ecn, ecn]
1082
1083         # one overlay packet and all combinations of its encap
1084         p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
1085         p_ip6_encaps = [IPv6(src=tun.dst, dst=self.pg0.local_ip6, tc=tc) for tc in tcs]
1086
1087         # for each encap tun will produce the same inner packet because it does
1088         # not copy up fields from the payload
1089         for p_ip6_encap in p_ip6_encaps:
1090             p6 = self.p_ether / p_ip6_encap / p_ip4 / self.p_payload
1091             p4_reply = p_ip4 / self.p_payload
1092             p4_reply.ttl -= 1
1093             rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
1094             n_packets_decapped += N_PACKETS
1095             for p in rx:
1096                 self.validate(p[1], p4_reply)
1097                 self.assert_packet_checksums_valid(p)
1098
1099         err = self.statistics.get_err_counter("/err/ipip6-input/packets decapsulated")
1100         self.assertEqual(err, n_packets_decapped)
1101
1102         # tun_ecn copies the ECN bits from the encap to the inner
1103         p_ip6_encaps = [
1104             IPv6(src=tun_ecn.dst, dst=self.pg0.local_ip6, tc=tc) for tc in tcs
1105         ]
1106         p_ip4_replys = [p_ip4.copy() for i in range(len(p_ip6_encaps))]
1107         p_ip4_replys[2].tos = ecn
1108         p_ip4_replys[3].tos = ecn
1109         for i, p_ip6_encap in enumerate(p_ip6_encaps):
1110             p6 = self.p_ether / p_ip6_encap / p_ip4 / self.p_payload
1111             p4_reply = p_ip4_replys[i] / self.p_payload
1112             p4_reply.ttl -= 1
1113             rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
1114             n_packets_decapped += N_PACKETS
1115             for p in rx:
1116                 self.validate(p[1], p4_reply)
1117                 self.assert_packet_checksums_valid(p)
1118
1119         err = self.statistics.get_err_counter("/err/ipip6-input/packets decapsulated")
1120         self.assertEqual(err, n_packets_decapped)
1121
1122         # IPv6 tunnel to IPv6
1123         # for each encap tun will produce the same inner packet because it does
1124         # not copy up fields from the payload
1125         p_ip6_encaps = [IPv6(src=tun.dst, dst=self.pg0.local_ip6, tc=tc) for tc in tcs]
1126         p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
1127         for p_ip6_encap in p_ip6_encaps:
1128             p6 = self.p_ether / p_ip6_encap / p_ip6 / self.p_payload
1129             p6_reply = p_ip6 / self.p_payload
1130             p6_reply.hlim = 63
1131             rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
1132             n_packets_decapped += N_PACKETS
1133             for p in rx:
1134                 self.validate(p[1], p6_reply)
1135                 self.assert_packet_checksums_valid(p)
1136
1137         err = self.statistics.get_err_counter("/err/ipip6-input/packets decapsulated")
1138         self.assertEqual(err, n_packets_decapped)
1139
1140         # IPv6 tunnel to IPv6
1141         # tun_ecn copies the ECN bits from the encap to the inner
1142         p_ip6_encaps = [
1143             IPv6(src=tun_ecn.dst, dst=self.pg0.local_ip6, tc=tc) for tc in tcs
1144         ]
1145         p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
1146         p_ip6_replys = [p_ip6.copy() for i in range(len(p_ip6_encaps))]
1147         p_ip6_replys[2].tc = ecn
1148         p_ip6_replys[3].tc = ecn
1149         for i, p_ip6_encap in enumerate(p_ip6_encaps):
1150             p6 = self.p_ether / p_ip6_encap / p_ip6 / self.p_payload
1151             p6_reply = p_ip6_replys[i] / self.p_payload
1152             p6_reply.hlim = 63
1153             rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
1154             n_packets_decapped += N_PACKETS
1155             for p in rx:
1156                 self.validate(p[1], p6_reply)
1157                 self.assert_packet_checksums_valid(p)
1158
1159         err = self.statistics.get_err_counter("/err/ipip6-input/packets decapsulated")
1160         self.assertEqual(err, n_packets_decapped)
1161
1162     def test_frag(self):
1163         """ip{v4,v6} over ip6 test frag"""
1164
1165         p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
1166         p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh="UDP")
1167         p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
1168         p_payload = UDP(sport=1234, dport=1234)
1169
1170         #
1171         # Fragmentation / Reassembly and Re-fragmentation
1172         #
1173         rv = self.vapi.ip_reassembly_enable_disable(
1174             sw_if_index=self.pg1.sw_if_index, enable_ip6=1
1175         )
1176
1177         self.vapi.ip_reassembly_set(
1178             timeout_ms=1000,
1179             max_reassemblies=1000,
1180             max_reassembly_length=1000,
1181             expire_walk_interval_ms=10000,
1182             is_ip6=1,
1183         )
1184
1185         # Send lots of fragments, verify reassembled packet
1186         before_cnt = self.statistics.get_err_counter(
1187             "/err/ipip6-input/packets decapsulated"
1188         )
1189         frags, p6_reply = self.generate_ip6_frags(3131, 1400)
1190         f = []
1191         for i in range(0, 1000):
1192             f.extend(frags)
1193         self.pg1.add_stream(f)
1194         self.pg_enable_capture()
1195         self.pg_start()
1196         rx = self.pg0.get_capture(1000)
1197
1198         for p in rx:
1199             self.validate(p[1], p6_reply)
1200
1201         cnt = self.statistics.get_err_counter("/err/ipip6-input/packets decapsulated")
1202         self.assertEqual(cnt, before_cnt + 1000)
1203
1204         f = []
1205         r = []
1206         # TODO: Check out why reassembly of atomic fragments don't work
1207         for i in range(10, 90):
1208             frags, p6_reply = self.generate_ip6_frags(i * 100, 1000)
1209             f.extend(frags)
1210             r.extend(p6_reply)
1211         self.pg_enable_capture()
1212         self.pg1.add_stream(f)
1213         self.pg_start()
1214         rx = self.pg0.get_capture(80)
1215         i = 0
1216         for p in rx:
1217             self.validate(p[1], r[i])
1218             i += 1
1219
1220         # Simple fragmentation
1221         p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1222         self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1280, 0, 0, 0])
1223
1224         # IPv6 in to IPv6 tunnel
1225         p_payload = UDP(sport=1234, dport=1234) / self.payload(1300)
1226
1227         p6 = p_ether / p_ip6 / p_payload
1228         p6_reply = (
1229             IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6, hlim=63)
1230             / p_ip6
1231             / p_payload
1232         )
1233         p6_reply[1].hlim -= 1
1234         self.pg_enable_capture()
1235         self.pg0.add_stream(p6)
1236         self.pg_start()
1237         rx = self.pg1.get_capture(2)
1238
1239         # Scapy defragment doesn't deal well with multiple layers
1240         # of same type / Ethernet header first
1241         f = [p[1] for p in rx]
1242         reass_pkt = defragment6(f)
1243         self.validate(reass_pkt, p6_reply)
1244
1245         # Now try with re-fragmentation
1246         #
1247         # Send large fragments to tunnel head-end, for the tunnel head end
1248         # to reassemble and then refragment out the tunnel again.
1249         # Hair-pinning
1250         #
1251         self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1280, 0, 0, 0])
1252         frags, p6_reply = self.generate_ip6_hairpin_frags(8000, 1200)
1253         self.pg_enable_capture()
1254         self.pg1.add_stream(frags)
1255         self.pg_start()
1256         rx = self.pg1.get_capture(7)
1257         f = [p[1] for p in rx]
1258         reass_pkt = defragment6(f)
1259         p6_reply.id = 256
1260         self.validate(reass_pkt, p6_reply)
1261
1262     def test_ip6_mpls_frag(self):
1263         """Test fragmenting IPv6 over MPLS"""
1264
1265         # IPv6 packets must be locally generated to be fragmented
1266         # the use of tunnel encaps
1267         tun_dst = VppIpRoute(
1268             self,
1269             "1000::1",
1270             128,
1271             [
1272                 VppRoutePath(
1273                     self.pg1.remote_ip6, self.pg1.sw_if_index, labels=[VppMplsLabel(32)]
1274                 )
1275             ],
1276         ).add_vpp_config()
1277
1278         tun = VppIpIpTunInterface(
1279             self, self.pg0, self.pg0.local_ip6, "1000::1"
1280         ).add_vpp_config()
1281
1282         tun.admin_up()
1283         tun.config_ip6()
1284         tun.config_ip4()
1285
1286         self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [2000, 0, 0, 0])
1287
1288         p_6k = (
1289             Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1290             / IPv6(src=self.pg0.remote_ip6, dst=tun.remote_ip6)
1291             / UDP(sport=1234, dport=5678)
1292             / Raw(b"0xa" * 2000)
1293         )
1294         p_2k = (
1295             Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1296             / IPv6(src=self.pg0.remote_ip6, dst=tun.remote_ip6)
1297             / UDP(sport=1234, dport=5678)
1298             / Raw(b"0xa" * 1000)
1299         )
1300         p_1k = (
1301             Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1302             / IPv6(src=self.pg0.remote_ip6, dst=tun.remote_ip6)
1303             / UDP(sport=1234, dport=5678)
1304             / Raw(b"0xa" * 600)
1305         )
1306
1307         # this is now the interface MTU frags
1308         rxs = self.send_and_expect(self.pg0, [p_6k], self.pg1, n_rx=4)
1309         self.assertEqual(rxs[0][UDP].dport, 5678)
1310         for rx in rxs:
1311             self.assertEqual(rx[MPLS].label, 32)
1312             self.assertEqual(rx[IPv6].dst, "1000::1")
1313             self.assertEqual(rx[IPv6].dst, "1000::1")
1314         self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
1315         self.send_and_expect(self.pg0, [p_1k], self.pg1)
1316
1317     def test_ipip_create(self):
1318         """ipip create / delete interface test"""
1319         rv = ipip_add_tunnel(self, "1.2.3.4", "2.3.4.5")
1320         sw_if_index = rv.sw_if_index
1321         self.vapi.ipip_del_tunnel(sw_if_index)
1322
1323     def test_ipip_vrf_create(self):
1324         """ipip create / delete interface VRF test"""
1325
1326         t = VppIpTable(self, 20)
1327         t.add_vpp_config()
1328         rv = ipip_add_tunnel(self, "1.2.3.4", "2.3.4.5", table_id=20)
1329         sw_if_index = rv.sw_if_index
1330         self.vapi.ipip_del_tunnel(sw_if_index)
1331
1332     def payload(self, len):
1333         return "x" * len
1334
1335
1336 class TestIPIPMPLS(VppTestCase):
1337     """MPLS Test Case"""
1338
1339     @classmethod
1340     def setUpClass(cls):
1341         super(TestIPIPMPLS, cls).setUpClass()
1342         cls.create_pg_interfaces(range(2))
1343         cls.interfaces = list(cls.pg_interfaces)
1344
1345     @classmethod
1346     def tearDownClass(cls):
1347         super(TestIPIPMPLS, cls).tearDownClass()
1348
1349     def setUp(self):
1350         super(TestIPIPMPLS, self).setUp()
1351         for i in self.interfaces:
1352             i.admin_up()
1353             i.config_ip4()
1354             i.config_ip6()
1355             i.disable_ipv6_ra()
1356             i.resolve_arp()
1357             i.resolve_ndp()
1358
1359     def tearDown(self):
1360         super(TestIPIPMPLS, self).tearDown()
1361
1362         for i in self.pg_interfaces:
1363             i.unconfig_ip4()
1364             i.unconfig_ip6()
1365             i.admin_down()
1366
1367     def test_mpls(self):
1368         """MPLS over ip{6,4} test"""
1369
1370         tbl = VppMplsTable(self, 0)
1371         tbl.add_vpp_config()
1372
1373         self.p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1374         self.p_payload = UDP(sport=1234, dport=1234) / Raw(b"X" * 100)
1375         f = FibPathProto
1376
1377         # IPv4 transport
1378         tun4 = VppIpIpTunInterface(
1379             self, self.pg1, self.pg1.local_ip4, self.pg1.remote_ip4
1380         ).add_vpp_config()
1381         tun4.admin_up()
1382         tun4.config_ip4()
1383         tun4.enable_mpls()
1384
1385         # IPv6 transport
1386         tun6 = VppIpIpTunInterface(
1387             self, self.pg1, self.pg1.local_ip6, self.pg1.remote_ip6
1388         ).add_vpp_config()
1389         tun6.admin_up()
1390         tun6.config_ip6()
1391         tun6.enable_mpls()
1392
1393         # ip routes into the tunnels with output labels
1394         r4 = VppIpRoute(
1395             self,
1396             "1.1.1.1",
1397             32,
1398             [
1399                 VppRoutePath(
1400                     tun4.remote_ip4, tun4.sw_if_index, labels=[VppMplsLabel(44)]
1401                 )
1402             ],
1403         ).add_vpp_config()
1404         r6 = VppIpRoute(
1405             self,
1406             "1::1",
1407             128,
1408             [
1409                 VppRoutePath(
1410                     tun6.remote_ip6, tun6.sw_if_index, labels=[VppMplsLabel(66)]
1411                 )
1412             ],
1413         ).add_vpp_config()
1414
1415         # deag MPLS routes from the tunnel
1416         r4 = VppMplsRoute(
1417             self, 44, 1, [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index)]
1418         ).add_vpp_config()
1419         r6 = VppMplsRoute(
1420             self,
1421             66,
1422             1,
1423             [VppRoutePath(self.pg0.remote_ip6, self.pg0.sw_if_index)],
1424             eos_proto=f.FIB_PATH_NH_PROTO_IP6,
1425         ).add_vpp_config()
1426
1427         #
1428         # Tunnel Encap
1429         #
1430         p4 = self.p_ether / IP(src="2.2.2.2", dst="1.1.1.1") / self.p_payload
1431
1432         rxs = self.send_and_expect(self.pg0, p4 * N_PACKETS, self.pg1)
1433
1434         for rx in rxs:
1435             self.assertEqual(rx[IP].src, self.pg1.local_ip4)
1436             self.assertEqual(rx[IP].dst, self.pg1.remote_ip4)
1437             self.assertEqual(rx[MPLS].label, 44)
1438             inner = rx[MPLS].payload
1439             self.assertEqual(inner.src, "2.2.2.2")
1440             self.assertEqual(inner.dst, "1.1.1.1")
1441
1442         p6 = self.p_ether / IPv6(src="2::2", dst="1::1") / self.p_payload
1443
1444         rxs = self.send_and_expect(self.pg0, p6 * N_PACKETS, self.pg1)
1445
1446         for rx in rxs:
1447             self.assertEqual(rx[IPv6].src, self.pg1.local_ip6)
1448             self.assertEqual(rx[IPv6].dst, self.pg1.remote_ip6)
1449             self.assertEqual(rx[MPLS].label, 66)
1450             inner = rx[MPLS].payload
1451             self.assertEqual(inner.src, "2::2")
1452             self.assertEqual(inner.dst, "1::1")
1453
1454         #
1455         # Tunnel Decap
1456         #
1457         p4 = (
1458             self.p_ether
1459             / IP(src=self.pg1.remote_ip4, dst=self.pg1.local_ip4)
1460             / MPLS(label=44, ttl=4)
1461             / IP(src="1.1.1.1", dst="2.2.2.2")
1462             / self.p_payload
1463         )
1464
1465         rxs = self.send_and_expect(self.pg1, p4 * N_PACKETS, self.pg0)
1466
1467         for rx in rxs:
1468             self.assertEqual(rx[IP].src, "1.1.1.1")
1469             self.assertEqual(rx[IP].dst, "2.2.2.2")
1470
1471         p6 = (
1472             self.p_ether
1473             / IPv6(src=self.pg1.remote_ip6, dst=self.pg1.local_ip6)
1474             / MPLS(label=66, ttl=4)
1475             / IPv6(src="1::1", dst="2::2")
1476             / self.p_payload
1477         )
1478
1479         rxs = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
1480
1481         for rx in rxs:
1482             self.assertEqual(rx[IPv6].src, "1::1")
1483             self.assertEqual(rx[IPv6].dst, "2::2")
1484
1485         tun4.disable_mpls()
1486         tun6.disable_mpls()
1487
1488
1489 if __name__ == "__main__":
1490     unittest.main(testRunner=VppTestRunner)