2 """IP{4,6} over IP{v,6} tunnel functional tests"""
5 from scapy.layers.inet6 import IPv6, Ether, IP, UDP, IPv6ExtHdrFragment, Raw
6 from scapy.all import fragment, fragment6, RandShort, defragment6
7 from framework import VppTestCase, VppTestRunner
8 from vpp_ip import DpoProto
9 from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable, FibPathProto
10 from vpp_ipip_tun_interface import VppIpIpTunInterface
11 from vpp_papi import VppEnum
12 from socket import AF_INET, AF_INET6, inet_pton
13 from util import reassemble4
15 """ Testipip is a subclass of VPPTestCase classes.
22 def ipip_add_tunnel(test, src, dst, table_id=0, dscp=0x0,
24 """ Add a IPIP tunnel """
25 return test.vapi.ipip_add_tunnel(
30 'instance': 0xffffffff,
36 # the number of packets to send when injecting traffic.
37 # a multiple of 8 minus one, so we test all by 8/4/2/1 loops
41 class TestIPIP(VppTestCase):
42 """ IPIP Test Case """
46 super(TestIPIP, cls).setUpClass()
47 cls.create_pg_interfaces(range(2))
48 cls.interfaces = list(cls.pg_interfaces)
51 def tearDownClass(cls):
52 super(TestIPIP, cls).tearDownClass()
55 super(TestIPIP, self).setUp()
56 for i in self.interfaces:
65 super(TestIPIP, self).tearDown()
67 for i in self.pg_interfaces:
72 def validate(self, rx, expected):
73 self.assertEqual(rx, expected.__class__(expected))
75 def generate_ip4_frags(self, payload_length, fragment_size):
76 p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
77 p_payload = UDP(sport=1234, dport=1234) / self.payload(payload_length)
78 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
79 outer_ip4 = (p_ether / IP(src=self.pg1.remote_ip4,
81 dst=self.pg0.local_ip4) / p_ip4 / p_payload)
82 frags = fragment(outer_ip4, fragment_size)
83 p4_reply = (p_ip4 / p_payload)
85 return frags, p4_reply
87 def verify_ip4ip4_encaps(self, a, p_ip4s, p_ip4_encaps):
88 for i, p_ip4 in enumerate(p_ip4s):
90 p4 = (self.p_ether / p_ip4 / self.p_payload)
93 p4_reply = (p_ip4_encaps[i] / p_ip4_inner / self.p_payload)
96 rx = self.send_and_expect(self.pg0, p4 * N_PACKETS, self.pg1)
98 self.validate(p[1], p4_reply)
99 self.assert_packet_checksums_valid(p)
101 def verify_ip6ip4_encaps(self, a, p_ip6s, p_ip4_encaps):
102 for i, p_ip6 in enumerate(p_ip6s):
104 p6 = (self.p_ether / p_ip6 / self.p_payload)
106 p_inner_ip6.hlim -= 1
107 p6_reply = (p_ip4_encaps[i] / p_inner_ip6 / self.p_payload)
109 rx = self.send_and_expect(self.pg0, p6 * N_PACKETS, self.pg1)
111 self.validate(p[1], p6_reply)
112 self.assert_packet_checksums_valid(p)
114 def test_ipip4(self):
115 """ ip{v4,v6} over ip4 test """
117 self.pg1.generate_remote_hosts(5)
118 self.pg1.configure_ipv4_neighbors()
119 e = VppEnum.vl_api_ipip_tunnel_flags_t
120 d = VppEnum.vl_api_ip_dscp_t
121 self.p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
122 self.p_payload = UDP(sport=1234, dport=1234) / Raw(b'X' * 100)
124 # create a TOS byte by shifting a DSCP code point 2 bits. those 2 bits
126 dscp = d.IP_API_DSCP_AF31 << 2
128 dscp_ecn = d.IP_API_DSCP_AF31 << 2 | ecn
130 # IPv4 transport that copies the DCSP from the payload
131 tun_dscp = VppIpIpTunInterface(
135 self.pg1.remote_hosts[0].ip4,
136 flags=e.IPIP_TUNNEL_API_FLAG_ENCAP_COPY_DSCP).add_vpp_config()
137 # IPv4 transport that copies the DCSP and ECN from the payload
138 tun_dscp_ecn = VppIpIpTunInterface(
142 self.pg1.remote_hosts[1].ip4,
143 flags=(e.IPIP_TUNNEL_API_FLAG_ENCAP_COPY_DSCP |
144 e.IPIP_TUNNEL_API_FLAG_ENCAP_COPY_ECN)).add_vpp_config()
145 # IPv4 transport that copies the ECN from the payload and sets the
146 # DF bit on encap. copies the ECN on decap
147 tun_ecn = VppIpIpTunInterface(
151 self.pg1.remote_hosts[2].ip4,
152 flags=(e.IPIP_TUNNEL_API_FLAG_ENCAP_COPY_ECN |
153 e.IPIP_TUNNEL_API_FLAG_ENCAP_SET_DF |
154 e.IPIP_TUNNEL_API_FLAG_DECAP_COPY_ECN)).add_vpp_config()
155 # IPv4 transport that sets a fixed DSCP in the encap and copies
157 tun = VppIpIpTunInterface(
161 self.pg1.remote_hosts[3].ip4,
162 dscp=d.IP_API_DSCP_AF11,
163 flags=e.IPIP_TUNNEL_API_FLAG_ENCAP_COPY_DF).add_vpp_config()
165 # array of all the tunnels
166 tuns = [tun_dscp, tun_dscp_ecn, tun_ecn, tun]
168 # addresses for prefixes routed via each tunnel
169 a4s = ["" for i in range(len(tuns))]
170 a6s = ["" for i in range(len(tuns))]
172 # IP headers with each combination of DSCp/ECN tested
173 p_ip6s = [IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp),
174 IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp_ecn),
175 IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=ecn),
176 IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=0xff)]
177 p_ip4s = [IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp, flags='DF'),
178 IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp_ecn),
179 IP(src="1.2.3.4", dst="130.67.0.1", tos=ecn),
180 IP(src="1.2.3.4", dst="130.67.0.1", tos=0xff)]
182 # Configure each tunnel
183 for i, t in enumerate(tuns):
184 # Set interface up and enable IP on it
185 self.vapi.sw_interface_set_flags(t.sw_if_index, 1)
186 self.vapi.sw_interface_set_unnumbered(
187 sw_if_index=self.pg0.sw_if_index,
188 unnumbered_sw_if_index=t.sw_if_index)
190 # prefix for route / destination address for packets
191 a4s[i] = "130.67.%d.0" % i
192 a6s[i] = "dead:%d::" % i
194 # Add IPv4 and IPv6 routes via tunnel interface
195 ip4_via_tunnel = VppIpRoute(
197 [VppRoutePath("0.0.0.0",
199 proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
200 ip4_via_tunnel.add_vpp_config()
202 ip6_via_tunnel = VppIpRoute(
206 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
207 ip6_via_tunnel.add_vpp_config()
213 # tun_dscp copies only the dscp
214 # expected TC values are thus only the DCSP value is present from the
216 exp_tcs = [dscp, dscp, 0, 0xfc]
217 p_ip44_encaps = [IP(src=self.pg0.local_ip4,
219 tos=tc) for tc in exp_tcs]
220 p_ip64_encaps = [IP(src=self.pg0.local_ip4,
222 proto='ipv6', id=0, tos=tc) for tc in exp_tcs]
224 # IPv4 in to IPv4 tunnel
225 self.verify_ip4ip4_encaps(a4s[0], p_ip4s, p_ip44_encaps)
226 # IPv6 in to IPv4 tunnel
227 self.verify_ip6ip4_encaps(a6s[0], p_ip6s, p_ip64_encaps)
229 # tun_dscp_ecn copies the dscp and the ecn
230 exp_tcs = [dscp, dscp_ecn, ecn, 0xff]
231 p_ip44_encaps = [IP(src=self.pg0.local_ip4,
232 dst=tun_dscp_ecn.dst,
233 tos=tc) for tc in exp_tcs]
234 p_ip64_encaps = [IP(src=self.pg0.local_ip4,
235 dst=tun_dscp_ecn.dst,
236 proto='ipv6', id=0, tos=tc) for tc in exp_tcs]
238 self.verify_ip4ip4_encaps(a4s[1], p_ip4s, p_ip44_encaps)
239 self.verify_ip6ip4_encaps(a6s[1], p_ip6s, p_ip64_encaps)
241 # tun_ecn copies only the ecn and always sets DF
242 exp_tcs = [0, ecn, ecn, ecn]
243 p_ip44_encaps = [IP(src=self.pg0.local_ip4,
245 flags='DF', tos=tc) for tc in exp_tcs]
246 p_ip64_encaps = [IP(src=self.pg0.local_ip4,
248 flags='DF', proto='ipv6', id=0, tos=tc)
251 self.verify_ip4ip4_encaps(a4s[2], p_ip4s, p_ip44_encaps)
252 self.verify_ip6ip4_encaps(a6s[2], p_ip6s, p_ip64_encaps)
254 # tun sets a fixed dscp and copies DF
255 fixed_dscp = tun.dscp << 2
256 flags = ['DF', 0, 0, 0]
257 p_ip44_encaps = [IP(src=self.pg0.local_ip4,
260 tos=fixed_dscp) for f in flags]
261 p_ip64_encaps = [IP(src=self.pg0.local_ip4,
264 tos=fixed_dscp) for i in range(len(p_ip4s))]
266 self.verify_ip4ip4_encaps(a4s[3], p_ip4s, p_ip44_encaps)
267 self.verify_ip6ip4_encaps(a6s[3], p_ip6s, p_ip64_encaps)
272 n_packets_decapped = 0
273 self.p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
275 # IPv4 tunnel to IPv4
276 tcs = [0, dscp, dscp_ecn, ecn]
278 # one overlay packet and all combinations of its encap
279 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
280 p_ip4_encaps = [IP(src=tun.dst,
281 dst=self.pg0.local_ip4,
282 tos=tc) for tc in tcs]
284 # for each encap tun will produce the same inner packet because it does
285 # not copy up fields from the payload
286 for p_ip4_encap in p_ip4_encaps:
287 p4 = (self.p_ether / p_ip4_encap / p_ip4 / self.p_payload)
288 p4_reply = (p_ip4 / self.p_payload)
290 rx = self.send_and_expect(self.pg1, p4 * N_PACKETS, self.pg0)
291 n_packets_decapped += N_PACKETS
293 self.validate(p[1], p4_reply)
294 self.assert_packet_checksums_valid(p)
296 err = self.statistics.get_err_counter(
297 '/err/ipip4-input/packets decapsulated')
298 self.assertEqual(err, n_packets_decapped)
300 # tun_ecn copies the ECN bits from the encap to the inner
301 p_ip4_encaps = [IP(src=tun_ecn.dst,
302 dst=self.pg0.local_ip4,
303 tos=tc) for tc in tcs]
304 p_ip4_replys = [p_ip4.copy() for i in range(len(p_ip4_encaps))]
305 p_ip4_replys[2].tos = ecn
306 p_ip4_replys[3].tos = ecn
307 for i, p_ip4_encap in enumerate(p_ip4_encaps):
308 p4 = (self.p_ether / p_ip4_encap / p_ip4 / self.p_payload)
309 p4_reply = (p_ip4_replys[i] / self.p_payload)
311 rx = self.send_and_expect(self.pg1, p4 * N_PACKETS, self.pg0)
312 n_packets_decapped += N_PACKETS
314 self.validate(p[1], p4_reply)
315 self.assert_packet_checksums_valid(p)
317 err = self.statistics.get_err_counter(
318 '/err/ipip4-input/packets decapsulated')
319 self.assertEqual(err, n_packets_decapped)
321 # IPv4 tunnel to IPv6
322 # for each encap tun will produce the same inner packet because it does
323 # not copy up fields from the payload
324 p_ip4_encaps = [IP(src=tun.dst,
325 dst=self.pg0.local_ip4,
326 tos=tc) for tc in tcs]
327 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
328 for p_ip4_encap in p_ip4_encaps:
330 p_ip4_encap / p_ip6 /
332 p6_reply = (p_ip6 / self.p_payload)
334 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
335 n_packets_decapped += N_PACKETS
337 self.validate(p[1], p6_reply)
338 self.assert_packet_checksums_valid(p)
340 err = self.statistics.get_err_counter(
341 '/err/ipip4-input/packets decapsulated')
342 self.assertEqual(err, n_packets_decapped)
344 # IPv4 tunnel to IPv6
345 # tun_ecn copies the ECN bits from the encap to the inner
346 p_ip4_encaps = [IP(src=tun_ecn.dst,
347 dst=self.pg0.local_ip4,
348 tos=tc) for tc in tcs]
349 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
350 p_ip6_replys = [p_ip6.copy() for i in range(len(p_ip4_encaps))]
351 p_ip6_replys[2].tc = ecn
352 p_ip6_replys[3].tc = ecn
353 for i, p_ip4_encap in enumerate(p_ip4_encaps):
354 p6 = (self.p_ether / p_ip4_encap / p_ip6 / self.p_payload)
355 p6_reply = (p_ip6_replys[i] / self.p_payload)
357 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
358 n_packets_decapped += N_PACKETS
360 self.validate(p[1], p6_reply)
361 self.assert_packet_checksums_valid(p)
363 err = self.statistics.get_err_counter(
364 '/err/ipip4-input/packets decapsulated')
365 self.assertEqual(err, n_packets_decapped)
368 # Fragmentation / Reassembly and Re-fragmentation
370 rv = self.vapi.ip_reassembly_enable_disable(
371 sw_if_index=self.pg1.sw_if_index,
374 self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=1000,
375 max_reassembly_length=1000,
376 expire_walk_interval_ms=10000,
379 # Send lots of fragments, verify reassembled packet
380 frags, p4_reply = self.generate_ip4_frags(3131, 1400)
382 for i in range(0, 1000):
384 self.pg1.add_stream(f)
385 self.pg_enable_capture()
387 rx = self.pg0.get_capture(1000)
388 n_packets_decapped += 1000
391 self.validate(p[1], p4_reply)
393 err = self.statistics.get_err_counter(
394 '/err/ipip4-input/packets decapsulated')
395 self.assertEqual(err, n_packets_decapped)
399 for i in range(1, 90):
400 frags, p4_reply = self.generate_ip4_frags(i * 100, 1000)
403 self.pg_enable_capture()
404 self.pg1.add_stream(f)
406 rx = self.pg0.get_capture(89)
409 self.validate(p[1], r[i])
412 # Now try with re-fragmentation
414 # Send fragments to tunnel head-end, for the tunnel head end
415 # to reassemble and then refragment
417 self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [576, 0, 0, 0])
418 frags, p4_reply = self.generate_ip4_frags(3123, 1200)
419 self.pg_enable_capture()
420 self.pg1.add_stream(frags)
422 rx = self.pg0.get_capture(6)
423 reass_pkt = reassemble4(rx)
425 self.validate(reass_pkt, p4_reply)
427 self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [1600, 0, 0, 0])
428 frags, p4_reply = self.generate_ip4_frags(3123, 1200)
429 self.pg_enable_capture()
430 self.pg1.add_stream(frags)
432 rx = self.pg0.get_capture(2)
433 reass_pkt = reassemble4(rx)
435 self.validate(reass_pkt, p4_reply)
437 # send large packets through the tunnel, expect them to be fragmented
438 self.vapi.sw_interface_set_mtu(tun_dscp.sw_if_index, [600, 0, 0, 0])
440 p4 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
441 IP(src="1.2.3.4", dst="130.67.0.1", tos=42) /
442 UDP(sport=1234, dport=1234) / Raw(b'Q' * 1000))
443 rx = self.send_and_expect(self.pg0, p4 * 15, self.pg1, 30)
446 inners.append(p[IP].payload)
447 reass_pkt = reassemble4(inners)
449 self.assert_packet_checksums_valid(p)
450 self.assertEqual(p[IP].ttl, 63)
452 def test_ipip_create(self):
453 """ ipip create / delete interface test """
454 rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5')
455 sw_if_index = rv.sw_if_index
456 self.vapi.ipip_del_tunnel(sw_if_index)
458 def test_ipip_vrf_create(self):
459 """ ipip create / delete interface VRF test """
461 t = VppIpTable(self, 20)
463 rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5', table_id=20)
464 sw_if_index = rv.sw_if_index
465 self.vapi.ipip_del_tunnel(sw_if_index)
467 def payload(self, len):
471 class TestIPIP6(VppTestCase):
472 """ IPIP6 Test Case """
476 super(TestIPIP6, cls).setUpClass()
477 cls.create_pg_interfaces(range(2))
478 cls.interfaces = list(cls.pg_interfaces)
481 def tearDownClass(cls):
482 super(TestIPIP6, cls).tearDownClass()
485 super(TestIPIP6, self).setUp()
486 for i in self.interfaces:
496 if not self.vpp_dead:
497 self.destroy_tunnel()
498 for i in self.pg_interfaces:
502 super(TestIPIP6, self).tearDown()
504 def setup_tunnel(self):
506 rv = ipip_add_tunnel(self,
510 sw_if_index = rv.sw_if_index
511 self.tunnel_if_index = sw_if_index
512 self.vapi.sw_interface_set_flags(sw_if_index, 1)
513 self.vapi.sw_interface_set_unnumbered(
514 sw_if_index=self.pg0.sw_if_index,
515 unnumbered_sw_if_index=sw_if_index)
517 # Add IPv4 and IPv6 routes via tunnel interface
518 ip4_via_tunnel = VppIpRoute(
519 self, "130.67.0.0", 16,
520 [VppRoutePath("0.0.0.0",
522 proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
523 ip4_via_tunnel.add_vpp_config()
525 ip6_via_tunnel = VppIpRoute(
529 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
530 ip6_via_tunnel.add_vpp_config()
532 self.tunnel_ip6_via_tunnel = ip6_via_tunnel
533 self.tunnel_ip4_via_tunnel = ip4_via_tunnel
535 def destroy_tunnel(self):
537 self.tunnel_ip4_via_tunnel.remove_vpp_config()
538 self.tunnel_ip6_via_tunnel.remove_vpp_config()
540 rv = self.vapi.ipip_del_tunnel(sw_if_index=self.tunnel_if_index)
542 def validate(self, rx, expected):
543 self.assertEqual(rx, expected.__class__(expected))
545 def generate_ip6_frags(self, payload_length, fragment_size):
546 p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
547 p_payload = UDP(sport=1234, dport=1234) / self.payload(payload_length)
548 p_ip6 = IPv6(src="1::1", dst=self.pg0.remote_ip6)
549 outer_ip6 = (p_ether / IPv6(src=self.pg1.remote_ip6,
550 dst=self.pg0.local_ip6) /
551 IPv6ExtHdrFragment() / p_ip6 / p_payload)
552 frags = fragment6(outer_ip6, fragment_size)
553 p6_reply = (p_ip6 / p_payload)
555 return frags, p6_reply
557 def generate_ip6_hairpin_frags(self, payload_length, fragment_size):
558 p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
559 p_payload = UDP(sport=1234, dport=1234) / self.payload(payload_length)
560 p_ip6 = IPv6(src="1::1", dst="dead::1")
561 outer_ip6 = (p_ether / IPv6(src=self.pg1.remote_ip6,
562 dst=self.pg0.local_ip6) /
563 IPv6ExtHdrFragment() / p_ip6 / p_payload)
564 frags = fragment6(outer_ip6, fragment_size)
566 p6_reply = (IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6,
567 hlim=63) / p_ip6 / p_payload)
569 return frags, p6_reply
571 def test_encap(self):
572 """ ip{v4,v6} over ip6 test encap """
573 p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
574 p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP')
575 p_ip4 = IP(src="1.2.3.4", dst="130.67.0.1", tos=42)
576 p_payload = UDP(sport=1234, dport=1234)
579 # IPv6 in to IPv6 tunnel
580 p6 = (p_ether / p_ip6 / p_payload)
581 p6_reply = (IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6,
584 p6_reply[1].hlim -= 1
585 rx = self.send_and_expect(self.pg0, p6 * 11, self.pg1)
587 self.validate(p[1], p6_reply)
589 # IPv4 in to IPv6 tunnel
590 p4 = (p_ether / p_ip4 / p_payload)
591 p4_reply = (IPv6(src=self.pg0.local_ip6,
592 dst=self.pg1.remote_ip6, hlim=64) /
595 rx = self.send_and_expect(self.pg0, p4 * 11, self.pg1)
597 self.validate(p[1], p4_reply)
599 def test_decap(self):
600 """ ip{v4,v6} over ip6 test decap """
602 p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
603 p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP')
604 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
605 p_payload = UDP(sport=1234, dport=1234)
608 # IPv6 tunnel to IPv4
610 p4 = (p_ether / IPv6(src=self.pg1.remote_ip6,
611 dst=self.pg0.local_ip6) / p_ip4 / p_payload)
612 p4_reply = (p_ip4 / p_payload)
614 rx = self.send_and_expect(self.pg1, p4 * 11, self.pg0)
616 self.validate(p[1], p4_reply)
618 # IPv6 tunnel to IPv6
619 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
620 p6 = (p_ether / IPv6(src=self.pg1.remote_ip6,
621 dst=self.pg0.local_ip6) / p_ip6 / p_payload)
622 p6_reply = (p_ip6 / p_payload)
624 rx = self.send_and_expect(self.pg1, p6 * 11, self.pg0)
626 self.validate(p[1], p6_reply)
628 def verify_ip4ip6_encaps(self, a, p_ip4s, p_ip6_encaps):
629 for i, p_ip4 in enumerate(p_ip4s):
631 p4 = (self.p_ether / p_ip4 / self.p_payload)
634 p6_reply = (p_ip6_encaps[i] / p_ip4_inner / self.p_payload)
635 rx = self.send_and_expect(self.pg0, p4 * N_PACKETS, self.pg1)
637 self.validate(p[1], p6_reply)
638 self.assert_packet_checksums_valid(p)
640 def verify_ip6ip6_encaps(self, a, p_ip6s, p_ip6_encaps):
641 for i, p_ip6 in enumerate(p_ip6s):
643 p6 = (self.p_ether / p_ip6 / self.p_payload)
645 p_inner_ip6.hlim -= 1
646 p6_reply = (p_ip6_encaps[i] / p_inner_ip6 / self.p_payload)
647 rx = self.send_and_expect(self.pg0, p6 * N_PACKETS, self.pg1)
649 self.validate(p[1], p6_reply)
650 self.assert_packet_checksums_valid(p)
652 def test_ipip6(self):
653 """ ip{v4,v6} over ip6 test """
656 self.destroy_tunnel()
658 self.pg1.generate_remote_hosts(5)
659 self.pg1.configure_ipv6_neighbors()
660 e = VppEnum.vl_api_ipip_tunnel_flags_t
661 d = VppEnum.vl_api_ip_dscp_t
662 self.p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
663 self.p_payload = UDP(sport=1234, dport=1234) / Raw(b'X' * 100)
665 # create a TOS byte by shifting a DSCP code point 2 bits. those 2 bits
667 dscp = d.IP_API_DSCP_AF31 << 2
669 dscp_ecn = d.IP_API_DSCP_AF31 << 2 | ecn
671 # IPv4 transport that copies the DCSP from the payload
672 tun_dscp = VppIpIpTunInterface(
676 self.pg1.remote_hosts[0].ip6,
677 flags=e.IPIP_TUNNEL_API_FLAG_ENCAP_COPY_DSCP).add_vpp_config()
678 # IPv4 transport that copies the DCSP and ECN from the payload
679 tun_dscp_ecn = VppIpIpTunInterface(
683 self.pg1.remote_hosts[1].ip6,
684 flags=(e.IPIP_TUNNEL_API_FLAG_ENCAP_COPY_DSCP |
685 e.IPIP_TUNNEL_API_FLAG_ENCAP_COPY_ECN)).add_vpp_config()
686 # IPv4 transport that copies the ECN from the payload and sets the
687 # DF bit on encap. copies the ECN on decap
688 tun_ecn = VppIpIpTunInterface(
692 self.pg1.remote_hosts[2].ip6,
693 flags=(e.IPIP_TUNNEL_API_FLAG_ENCAP_COPY_ECN |
694 e.IPIP_TUNNEL_API_FLAG_ENCAP_SET_DF |
695 e.IPIP_TUNNEL_API_FLAG_DECAP_COPY_ECN)).add_vpp_config()
696 # IPv4 transport that sets a fixed DSCP in the encap and copies
698 tun = VppIpIpTunInterface(
702 self.pg1.remote_hosts[3].ip6,
703 dscp=d.IP_API_DSCP_AF11,
704 flags=e.IPIP_TUNNEL_API_FLAG_ENCAP_COPY_DF).add_vpp_config()
706 # array of all the tunnels
707 tuns = [tun_dscp, tun_dscp_ecn, tun_ecn, tun]
709 # addresses for prefixes routed via each tunnel
710 a4s = ["" for i in range(len(tuns))]
711 a6s = ["" for i in range(len(tuns))]
713 # IP headers for inner packets with each combination of DSCp/ECN tested
714 p_ip6s = [IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp),
715 IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp_ecn),
716 IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=ecn),
717 IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=0xff)]
718 p_ip4s = [IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp, flags='DF'),
719 IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp_ecn),
720 IP(src="1.2.3.4", dst="130.67.0.1", tos=ecn),
721 IP(src="1.2.3.4", dst="130.67.0.1", tos=0xff)]
723 # Configure each tunnel
724 for i, t in enumerate(tuns):
725 # Set interface up and enable IP on it
726 self.vapi.sw_interface_set_flags(t.sw_if_index, 1)
727 self.vapi.sw_interface_set_unnumbered(
728 sw_if_index=self.pg0.sw_if_index,
729 unnumbered_sw_if_index=t.sw_if_index)
731 # prefix for route / destination address for packets
732 a4s[i] = "130.67.%d.0" % i
733 a6s[i] = "dead:%d::" % i
735 # Add IPv4 and IPv6 routes via tunnel interface
736 ip4_via_tunnel = VppIpRoute(
738 [VppRoutePath("0.0.0.0",
740 proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
741 ip4_via_tunnel.add_vpp_config()
743 ip6_via_tunnel = VppIpRoute(
747 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
748 ip6_via_tunnel.add_vpp_config()
754 # tun_dscp copies only the dscp
755 # expected TC values are thus only the DCSP value is present from the
757 exp_tcs = [dscp, dscp, 0, 0xfc]
758 p_ip6_encaps = [IPv6(src=self.pg0.local_ip6,
760 tc=tc) for tc in exp_tcs]
762 # IPv4 in to IPv4 tunnel
763 self.verify_ip4ip6_encaps(a4s[0], p_ip4s, p_ip6_encaps)
764 # IPv6 in to IPv4 tunnel
765 self.verify_ip6ip6_encaps(a6s[0], p_ip6s, p_ip6_encaps)
767 # tun_dscp_ecn copies the dscp and the ecn
768 exp_tcs = [dscp, dscp_ecn, ecn, 0xff]
769 p_ip6_encaps = [IPv6(src=self.pg0.local_ip6,
770 dst=tun_dscp_ecn.dst,
771 tc=tc) for tc in exp_tcs]
773 self.verify_ip4ip6_encaps(a4s[1], p_ip4s, p_ip6_encaps)
774 self.verify_ip6ip6_encaps(a6s[1], p_ip6s, p_ip6_encaps)
776 # tun_ecn copies only the ecn and always sets DF
777 exp_tcs = [0, ecn, ecn, ecn]
778 p_ip6_encaps = [IPv6(src=self.pg0.local_ip6,
780 tc=tc) for tc in exp_tcs]
782 self.verify_ip4ip6_encaps(a4s[2], p_ip4s, p_ip6_encaps)
783 self.verify_ip6ip6_encaps(a6s[2], p_ip6s, p_ip6_encaps)
785 # tun sets a fixed dscp
786 fixed_dscp = tun.dscp << 2
787 p_ip6_encaps = [IPv6(src=self.pg0.local_ip6,
789 tc=fixed_dscp) for i in range(len(p_ip4s))]
791 self.verify_ip4ip6_encaps(a4s[3], p_ip4s, p_ip6_encaps)
792 self.verify_ip6ip6_encaps(a6s[3], p_ip6s, p_ip6_encaps)
797 n_packets_decapped = self.statistics.get_err_counter(
798 '/err/ipip6-input/packets decapsulated')
800 self.p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
802 # IPv6 tunnel to IPv4
803 tcs = [0, dscp, dscp_ecn, ecn]
805 # one overlay packet and all combinations of its encap
806 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
807 p_ip6_encaps = [IPv6(src=tun.dst,
808 dst=self.pg0.local_ip6,
809 tc=tc) for tc in tcs]
811 # for each encap tun will produce the same inner packet because it does
812 # not copy up fields from the payload
813 for p_ip6_encap in p_ip6_encaps:
814 p6 = (self.p_ether / p_ip6_encap / p_ip4 / self.p_payload)
815 p4_reply = (p_ip4 / self.p_payload)
817 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
818 n_packets_decapped += N_PACKETS
820 self.validate(p[1], p4_reply)
821 self.assert_packet_checksums_valid(p)
823 err = self.statistics.get_err_counter(
824 '/err/ipip6-input/packets decapsulated')
825 self.assertEqual(err, n_packets_decapped)
827 # tun_ecn copies the ECN bits from the encap to the inner
828 p_ip6_encaps = [IPv6(src=tun_ecn.dst,
829 dst=self.pg0.local_ip6,
830 tc=tc) for tc in tcs]
831 p_ip4_replys = [p_ip4.copy() for i in range(len(p_ip6_encaps))]
832 p_ip4_replys[2].tos = ecn
833 p_ip4_replys[3].tos = ecn
834 for i, p_ip6_encap in enumerate(p_ip6_encaps):
835 p6 = (self.p_ether / p_ip6_encap / p_ip4 / self.p_payload)
836 p4_reply = (p_ip4_replys[i] / self.p_payload)
838 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
839 n_packets_decapped += N_PACKETS
841 self.validate(p[1], p4_reply)
842 self.assert_packet_checksums_valid(p)
844 err = self.statistics.get_err_counter(
845 '/err/ipip6-input/packets decapsulated')
846 self.assertEqual(err, n_packets_decapped)
848 # IPv6 tunnel to IPv6
849 # for each encap tun will produce the same inner packet because it does
850 # not copy up fields from the payload
851 p_ip6_encaps = [IPv6(src=tun.dst,
852 dst=self.pg0.local_ip6,
853 tc=tc) for tc in tcs]
854 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
855 for p_ip6_encap in p_ip6_encaps:
856 p6 = (self.p_ether / p_ip6_encap / p_ip6 / self.p_payload)
857 p6_reply = (p_ip6 / self.p_payload)
859 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
860 n_packets_decapped += N_PACKETS
862 self.validate(p[1], p6_reply)
863 self.assert_packet_checksums_valid(p)
865 err = self.statistics.get_err_counter(
866 '/err/ipip6-input/packets decapsulated')
867 self.assertEqual(err, n_packets_decapped)
869 # IPv6 tunnel to IPv6
870 # tun_ecn copies the ECN bits from the encap to the inner
871 p_ip6_encaps = [IPv6(src=tun_ecn.dst,
872 dst=self.pg0.local_ip6,
873 tc=tc) for tc in tcs]
874 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
875 p_ip6_replys = [p_ip6.copy() for i in range(len(p_ip6_encaps))]
876 p_ip6_replys[2].tc = ecn
877 p_ip6_replys[3].tc = ecn
878 for i, p_ip6_encap in enumerate(p_ip6_encaps):
879 p6 = (self.p_ether / p_ip6_encap / p_ip6 / self.p_payload)
880 p6_reply = (p_ip6_replys[i] / self.p_payload)
882 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
883 n_packets_decapped += N_PACKETS
885 self.validate(p[1], p6_reply)
886 self.assert_packet_checksums_valid(p)
888 err = self.statistics.get_err_counter(
889 '/err/ipip6-input/packets decapsulated')
890 self.assertEqual(err, n_packets_decapped)
893 """ ip{v4,v6} over ip6 test frag """
895 p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
896 p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP')
897 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
898 p_payload = UDP(sport=1234, dport=1234)
901 # Fragmentation / Reassembly and Re-fragmentation
903 rv = self.vapi.ip_reassembly_enable_disable(
904 sw_if_index=self.pg1.sw_if_index,
907 self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=1000,
908 max_reassembly_length=1000,
909 expire_walk_interval_ms=10000,
912 # Send lots of fragments, verify reassembled packet
913 before_cnt = self.statistics.get_err_counter(
914 '/err/ipip6-input/packets decapsulated')
915 frags, p6_reply = self.generate_ip6_frags(3131, 1400)
917 for i in range(0, 1000):
919 self.pg1.add_stream(f)
920 self.pg_enable_capture()
922 rx = self.pg0.get_capture(1000)
925 self.validate(p[1], p6_reply)
927 cnt = self.statistics.get_err_counter(
928 '/err/ipip6-input/packets decapsulated')
929 self.assertEqual(cnt, before_cnt + 1000)
933 # TODO: Check out why reassembly of atomic fragments don't work
934 for i in range(10, 90):
935 frags, p6_reply = self.generate_ip6_frags(i * 100, 1000)
938 self.pg_enable_capture()
939 self.pg1.add_stream(f)
941 rx = self.pg0.get_capture(80)
944 self.validate(p[1], r[i])
947 # Simple fragmentation
948 p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
949 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1280, 0, 0, 0])
951 # IPv6 in to IPv6 tunnel
952 p_payload = UDP(sport=1234, dport=1234) / self.payload(1300)
954 p6 = (p_ether / p_ip6 / p_payload)
955 p6_reply = (IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6,
958 p6_reply[1].hlim -= 1
959 self.pg_enable_capture()
960 self.pg0.add_stream(p6)
962 rx = self.pg1.get_capture(2)
964 # Scapy defragment doesn't deal well with multiple layers
965 # of same type / Ethernet header first
966 f = [p[1] for p in rx]
967 reass_pkt = defragment6(f)
968 self.validate(reass_pkt, p6_reply)
970 # Now try with re-fragmentation
972 # Send large fragments to tunnel head-end, for the tunnel head end
973 # to reassemble and then refragment out the tunnel again.
976 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1280, 0, 0, 0])
977 frags, p6_reply = self.generate_ip6_hairpin_frags(8000, 1200)
978 self.pg_enable_capture()
979 self.pg1.add_stream(frags)
981 rx = self.pg1.get_capture(7)
982 f = [p[1] for p in rx]
983 reass_pkt = defragment6(f)
985 self.validate(reass_pkt, p6_reply)
987 def test_ipip_create(self):
988 """ ipip create / delete interface test """
989 rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5')
990 sw_if_index = rv.sw_if_index
991 self.vapi.ipip_del_tunnel(sw_if_index)
993 def test_ipip_vrf_create(self):
994 """ ipip create / delete interface VRF test """
996 t = VppIpTable(self, 20)
998 rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5', table_id=20)
999 sw_if_index = rv.sw_if_index
1000 self.vapi.ipip_del_tunnel(sw_if_index)
1002 def payload(self, len):
1006 if __name__ == '__main__':
1007 unittest.main(testRunner=VppTestRunner)