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