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_tunnel_encap_decap_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.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP)
137 tun_dscp.add_vpp_config()
138 # IPv4 transport that copies the DCSP and ECN from the payload
139 tun_dscp_ecn = VppIpIpTunInterface(
143 self.pg1.remote_hosts[1].ip4,
144 flags=(e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP |
145 e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN))
146 tun_dscp_ecn.add_vpp_config()
147 # IPv4 transport that copies the ECN from the payload and sets the
148 # DF bit on encap. copies the ECN on decap
149 tun_ecn = VppIpIpTunInterface(
153 self.pg1.remote_hosts[2].ip4,
154 flags=(e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN |
155 e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_SET_DF |
156 e.TUNNEL_API_ENCAP_DECAP_FLAG_DECAP_COPY_ECN))
157 tun_ecn.add_vpp_config()
158 # IPv4 transport that sets a fixed DSCP in the encap and copies
160 tun = VppIpIpTunInterface(
164 self.pg1.remote_hosts[3].ip4,
165 dscp=d.IP_API_DSCP_AF11,
166 flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DF)
169 # array of all the tunnels
170 tuns = [tun_dscp, tun_dscp_ecn, tun_ecn, tun]
172 # addresses for prefixes routed via each tunnel
173 a4s = ["" for i in range(len(tuns))]
174 a6s = ["" for i in range(len(tuns))]
176 # IP headers with each combination of DSCp/ECN tested
177 p_ip6s = [IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp),
178 IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp_ecn),
179 IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=ecn),
180 IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=0xff)]
181 p_ip4s = [IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp, flags='DF'),
182 IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp_ecn),
183 IP(src="1.2.3.4", dst="130.67.0.1", tos=ecn),
184 IP(src="1.2.3.4", dst="130.67.0.1", tos=0xff)]
186 # Configure each tunnel
187 for i, t in enumerate(tuns):
188 # Set interface up and enable IP on it
189 self.vapi.sw_interface_set_flags(t.sw_if_index, 1)
190 self.vapi.sw_interface_set_unnumbered(
191 sw_if_index=self.pg0.sw_if_index,
192 unnumbered_sw_if_index=t.sw_if_index)
194 # prefix for route / destination address for packets
195 a4s[i] = "130.67.%d.0" % i
196 a6s[i] = "dead:%d::" % i
198 # Add IPv4 and IPv6 routes via tunnel interface
199 ip4_via_tunnel = VppIpRoute(
201 [VppRoutePath("0.0.0.0",
203 proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
204 ip4_via_tunnel.add_vpp_config()
206 ip6_via_tunnel = VppIpRoute(
210 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
211 ip6_via_tunnel.add_vpp_config()
217 # tun_dscp copies only the dscp
218 # expected TC values are thus only the DCSP value is present from the
220 exp_tcs = [dscp, dscp, 0, 0xfc]
221 p_ip44_encaps = [IP(src=self.pg0.local_ip4,
223 tos=tc) for tc in exp_tcs]
224 p_ip64_encaps = [IP(src=self.pg0.local_ip4,
226 proto='ipv6', id=0, tos=tc) for tc in exp_tcs]
228 # IPv4 in to IPv4 tunnel
229 self.verify_ip4ip4_encaps(a4s[0], p_ip4s, p_ip44_encaps)
230 # IPv6 in to IPv4 tunnel
231 self.verify_ip6ip4_encaps(a6s[0], p_ip6s, p_ip64_encaps)
233 # tun_dscp_ecn copies the dscp and the ecn
234 exp_tcs = [dscp, dscp_ecn, ecn, 0xff]
235 p_ip44_encaps = [IP(src=self.pg0.local_ip4,
236 dst=tun_dscp_ecn.dst,
237 tos=tc) for tc in exp_tcs]
238 p_ip64_encaps = [IP(src=self.pg0.local_ip4,
239 dst=tun_dscp_ecn.dst,
240 proto='ipv6', id=0, tos=tc) for tc in exp_tcs]
242 self.verify_ip4ip4_encaps(a4s[1], p_ip4s, p_ip44_encaps)
243 self.verify_ip6ip4_encaps(a6s[1], p_ip6s, p_ip64_encaps)
245 # tun_ecn copies only the ecn and always sets DF
246 exp_tcs = [0, ecn, ecn, ecn]
247 p_ip44_encaps = [IP(src=self.pg0.local_ip4,
249 flags='DF', tos=tc) for tc in exp_tcs]
250 p_ip64_encaps = [IP(src=self.pg0.local_ip4,
252 flags='DF', proto='ipv6', id=0, tos=tc)
255 self.verify_ip4ip4_encaps(a4s[2], p_ip4s, p_ip44_encaps)
256 self.verify_ip6ip4_encaps(a6s[2], p_ip6s, p_ip64_encaps)
258 # tun sets a fixed dscp and copies DF
259 fixed_dscp = tun.dscp << 2
260 flags = ['DF', 0, 0, 0]
261 p_ip44_encaps = [IP(src=self.pg0.local_ip4,
264 tos=fixed_dscp) for f in flags]
265 p_ip64_encaps = [IP(src=self.pg0.local_ip4,
268 tos=fixed_dscp) for i in range(len(p_ip4s))]
270 self.verify_ip4ip4_encaps(a4s[3], p_ip4s, p_ip44_encaps)
271 self.verify_ip6ip4_encaps(a6s[3], p_ip6s, p_ip64_encaps)
276 n_packets_decapped = 0
277 self.p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
279 # IPv4 tunnel to IPv4
280 tcs = [0, dscp, dscp_ecn, ecn]
282 # one overlay packet and all combinations of its encap
283 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
284 p_ip4_encaps = [IP(src=tun.dst,
285 dst=self.pg0.local_ip4,
286 tos=tc) for tc in tcs]
288 # for each encap tun will produce the same inner packet because it does
289 # not copy up fields from the payload
290 for p_ip4_encap in p_ip4_encaps:
291 p4 = (self.p_ether / p_ip4_encap / p_ip4 / self.p_payload)
292 p4_reply = (p_ip4 / self.p_payload)
294 rx = self.send_and_expect(self.pg1, p4 * N_PACKETS, self.pg0)
295 n_packets_decapped += N_PACKETS
297 self.validate(p[1], p4_reply)
298 self.assert_packet_checksums_valid(p)
300 err = self.statistics.get_err_counter(
301 '/err/ipip4-input/packets decapsulated')
302 self.assertEqual(err, n_packets_decapped)
304 # tun_ecn copies the ECN bits from the encap to the inner
305 p_ip4_encaps = [IP(src=tun_ecn.dst,
306 dst=self.pg0.local_ip4,
307 tos=tc) for tc in tcs]
308 p_ip4_replys = [p_ip4.copy() for i in range(len(p_ip4_encaps))]
309 p_ip4_replys[2].tos = ecn
310 p_ip4_replys[3].tos = ecn
311 for i, p_ip4_encap in enumerate(p_ip4_encaps):
312 p4 = (self.p_ether / p_ip4_encap / p_ip4 / self.p_payload)
313 p4_reply = (p_ip4_replys[i] / self.p_payload)
315 rx = self.send_and_expect(self.pg1, p4 * N_PACKETS, self.pg0)
316 n_packets_decapped += N_PACKETS
318 self.validate(p[1], p4_reply)
319 self.assert_packet_checksums_valid(p)
321 err = self.statistics.get_err_counter(
322 '/err/ipip4-input/packets decapsulated')
323 self.assertEqual(err, n_packets_decapped)
325 # IPv4 tunnel to IPv6
326 # for each encap tun will produce the same inner packet because it does
327 # not copy up fields from the payload
328 p_ip4_encaps = [IP(src=tun.dst,
329 dst=self.pg0.local_ip4,
330 tos=tc) for tc in tcs]
331 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
332 for p_ip4_encap in p_ip4_encaps:
334 p_ip4_encap / p_ip6 /
336 p6_reply = (p_ip6 / self.p_payload)
338 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
339 n_packets_decapped += N_PACKETS
341 self.validate(p[1], p6_reply)
342 self.assert_packet_checksums_valid(p)
344 err = self.statistics.get_err_counter(
345 '/err/ipip4-input/packets decapsulated')
346 self.assertEqual(err, n_packets_decapped)
348 # IPv4 tunnel to IPv6
349 # tun_ecn copies the ECN bits from the encap to the inner
350 p_ip4_encaps = [IP(src=tun_ecn.dst,
351 dst=self.pg0.local_ip4,
352 tos=tc) for tc in tcs]
353 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
354 p_ip6_replys = [p_ip6.copy() for i in range(len(p_ip4_encaps))]
355 p_ip6_replys[2].tc = ecn
356 p_ip6_replys[3].tc = ecn
357 for i, p_ip4_encap in enumerate(p_ip4_encaps):
358 p6 = (self.p_ether / p_ip4_encap / p_ip6 / self.p_payload)
359 p6_reply = (p_ip6_replys[i] / self.p_payload)
361 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
362 n_packets_decapped += N_PACKETS
364 self.validate(p[1], p6_reply)
365 self.assert_packet_checksums_valid(p)
367 err = self.statistics.get_err_counter(
368 '/err/ipip4-input/packets decapsulated')
369 self.assertEqual(err, n_packets_decapped)
372 # Fragmentation / Reassembly and Re-fragmentation
374 rv = self.vapi.ip_reassembly_enable_disable(
375 sw_if_index=self.pg1.sw_if_index,
378 self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=1000,
379 max_reassembly_length=1000,
380 expire_walk_interval_ms=10000,
383 # Send lots of fragments, verify reassembled packet
384 frags, p4_reply = self.generate_ip4_frags(3131, 1400)
386 for i in range(0, 1000):
388 self.pg1.add_stream(f)
389 self.pg_enable_capture()
391 rx = self.pg0.get_capture(1000)
392 n_packets_decapped += 1000
395 self.validate(p[1], p4_reply)
397 err = self.statistics.get_err_counter(
398 '/err/ipip4-input/packets decapsulated')
399 self.assertEqual(err, n_packets_decapped)
403 for i in range(1, 90):
404 frags, p4_reply = self.generate_ip4_frags(i * 100, 1000)
407 self.pg_enable_capture()
408 self.pg1.add_stream(f)
410 rx = self.pg0.get_capture(89)
413 self.validate(p[1], r[i])
416 # Now try with re-fragmentation
418 # Send fragments to tunnel head-end, for the tunnel head end
419 # to reassemble and then refragment
421 self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [576, 0, 0, 0])
422 frags, p4_reply = self.generate_ip4_frags(3123, 1200)
423 self.pg_enable_capture()
424 self.pg1.add_stream(frags)
426 rx = self.pg0.get_capture(6)
427 reass_pkt = reassemble4(rx)
429 self.validate(reass_pkt, p4_reply)
431 self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [1600, 0, 0, 0])
432 frags, p4_reply = self.generate_ip4_frags(3123, 1200)
433 self.pg_enable_capture()
434 self.pg1.add_stream(frags)
436 rx = self.pg0.get_capture(2)
437 reass_pkt = reassemble4(rx)
439 self.validate(reass_pkt, p4_reply)
441 # send large packets through the tunnel, expect them to be fragmented
442 self.vapi.sw_interface_set_mtu(tun_dscp.sw_if_index, [600, 0, 0, 0])
444 p4 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
445 IP(src="1.2.3.4", dst="130.67.0.1", tos=42) /
446 UDP(sport=1234, dport=1234) / Raw(b'Q' * 1000))
447 rx = self.send_and_expect(self.pg0, p4 * 15, self.pg1, 30)
450 inners.append(p[IP].payload)
451 reass_pkt = reassemble4(inners)
453 self.assert_packet_checksums_valid(p)
454 self.assertEqual(p[IP].ttl, 63)
456 def test_ipip_create(self):
457 """ ipip create / delete interface test """
458 rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5')
459 sw_if_index = rv.sw_if_index
460 self.vapi.ipip_del_tunnel(sw_if_index)
462 def test_ipip_vrf_create(self):
463 """ ipip create / delete interface VRF test """
465 t = VppIpTable(self, 20)
467 rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5', table_id=20)
468 sw_if_index = rv.sw_if_index
469 self.vapi.ipip_del_tunnel(sw_if_index)
471 def payload(self, len):
475 class TestIPIP6(VppTestCase):
476 """ IPIP6 Test Case """
480 super(TestIPIP6, cls).setUpClass()
481 cls.create_pg_interfaces(range(2))
482 cls.interfaces = list(cls.pg_interfaces)
485 def tearDownClass(cls):
486 super(TestIPIP6, cls).tearDownClass()
489 super(TestIPIP6, self).setUp()
490 for i in self.interfaces:
500 if not self.vpp_dead:
501 self.destroy_tunnel()
502 for i in self.pg_interfaces:
506 super(TestIPIP6, self).tearDown()
508 def setup_tunnel(self):
510 rv = ipip_add_tunnel(self,
514 sw_if_index = rv.sw_if_index
515 self.tunnel_if_index = sw_if_index
516 self.vapi.sw_interface_set_flags(sw_if_index, 1)
517 self.vapi.sw_interface_set_unnumbered(
518 sw_if_index=self.pg0.sw_if_index,
519 unnumbered_sw_if_index=sw_if_index)
521 # Add IPv4 and IPv6 routes via tunnel interface
522 ip4_via_tunnel = VppIpRoute(
523 self, "130.67.0.0", 16,
524 [VppRoutePath("0.0.0.0",
526 proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
527 ip4_via_tunnel.add_vpp_config()
529 ip6_via_tunnel = VppIpRoute(
533 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
534 ip6_via_tunnel.add_vpp_config()
536 self.tunnel_ip6_via_tunnel = ip6_via_tunnel
537 self.tunnel_ip4_via_tunnel = ip4_via_tunnel
539 def destroy_tunnel(self):
541 self.tunnel_ip4_via_tunnel.remove_vpp_config()
542 self.tunnel_ip6_via_tunnel.remove_vpp_config()
544 rv = self.vapi.ipip_del_tunnel(sw_if_index=self.tunnel_if_index)
546 def validate(self, rx, expected):
547 self.assertEqual(rx, expected.__class__(expected))
549 def generate_ip6_frags(self, payload_length, fragment_size):
550 p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
551 p_payload = UDP(sport=1234, dport=1234) / self.payload(payload_length)
552 p_ip6 = IPv6(src="1::1", dst=self.pg0.remote_ip6)
553 outer_ip6 = (p_ether / IPv6(src=self.pg1.remote_ip6,
554 dst=self.pg0.local_ip6) /
555 IPv6ExtHdrFragment() / p_ip6 / p_payload)
556 frags = fragment6(outer_ip6, fragment_size)
557 p6_reply = (p_ip6 / p_payload)
559 return frags, p6_reply
561 def generate_ip6_hairpin_frags(self, payload_length, fragment_size):
562 p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
563 p_payload = UDP(sport=1234, dport=1234) / self.payload(payload_length)
564 p_ip6 = IPv6(src="1::1", dst="dead::1")
565 outer_ip6 = (p_ether / IPv6(src=self.pg1.remote_ip6,
566 dst=self.pg0.local_ip6) /
567 IPv6ExtHdrFragment() / p_ip6 / p_payload)
568 frags = fragment6(outer_ip6, fragment_size)
570 p6_reply = (IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6,
571 hlim=63) / p_ip6 / p_payload)
573 return frags, p6_reply
575 def test_encap(self):
576 """ ip{v4,v6} over ip6 test encap """
577 p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
578 p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP')
579 p_ip4 = IP(src="1.2.3.4", dst="130.67.0.1", tos=42)
580 p_payload = UDP(sport=1234, dport=1234)
583 # IPv6 in to IPv6 tunnel
584 p6 = (p_ether / p_ip6 / p_payload)
585 p6_reply = (IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6,
588 p6_reply[1].hlim -= 1
589 rx = self.send_and_expect(self.pg0, p6 * 11, self.pg1)
591 self.validate(p[1], p6_reply)
593 # IPv4 in to IPv6 tunnel
594 p4 = (p_ether / p_ip4 / p_payload)
595 p4_reply = (IPv6(src=self.pg0.local_ip6,
596 dst=self.pg1.remote_ip6, hlim=64) /
599 rx = self.send_and_expect(self.pg0, p4 * 11, self.pg1)
601 self.validate(p[1], p4_reply)
603 def test_decap(self):
604 """ ip{v4,v6} over ip6 test decap """
606 p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
607 p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP')
608 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
609 p_payload = UDP(sport=1234, dport=1234)
612 # IPv6 tunnel to IPv4
614 p4 = (p_ether / IPv6(src=self.pg1.remote_ip6,
615 dst=self.pg0.local_ip6) / p_ip4 / p_payload)
616 p4_reply = (p_ip4 / p_payload)
618 rx = self.send_and_expect(self.pg1, p4 * 11, self.pg0)
620 self.validate(p[1], p4_reply)
622 # IPv6 tunnel to IPv6
623 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
624 p6 = (p_ether / IPv6(src=self.pg1.remote_ip6,
625 dst=self.pg0.local_ip6) / p_ip6 / p_payload)
626 p6_reply = (p_ip6 / p_payload)
628 rx = self.send_and_expect(self.pg1, p6 * 11, self.pg0)
630 self.validate(p[1], p6_reply)
632 def verify_ip4ip6_encaps(self, a, p_ip4s, p_ip6_encaps):
633 for i, p_ip4 in enumerate(p_ip4s):
635 p4 = (self.p_ether / p_ip4 / self.p_payload)
638 p6_reply = (p_ip6_encaps[i] / p_ip4_inner / self.p_payload)
639 rx = self.send_and_expect(self.pg0, p4 * N_PACKETS, self.pg1)
641 self.validate(p[1], p6_reply)
642 self.assert_packet_checksums_valid(p)
644 def verify_ip6ip6_encaps(self, a, p_ip6s, p_ip6_encaps):
645 for i, p_ip6 in enumerate(p_ip6s):
647 p6 = (self.p_ether / p_ip6 / self.p_payload)
649 p_inner_ip6.hlim -= 1
650 p6_reply = (p_ip6_encaps[i] / p_inner_ip6 / self.p_payload)
651 rx = self.send_and_expect(self.pg0, p6 * N_PACKETS, self.pg1)
653 self.validate(p[1], p6_reply)
654 self.assert_packet_checksums_valid(p)
656 def test_ipip6(self):
657 """ ip{v4,v6} over ip6 test """
660 self.destroy_tunnel()
662 self.pg1.generate_remote_hosts(5)
663 self.pg1.configure_ipv6_neighbors()
664 e = VppEnum.vl_api_tunnel_encap_decap_flags_t
665 d = VppEnum.vl_api_ip_dscp_t
666 self.p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
667 self.p_payload = UDP(sport=1234, dport=1234) / Raw(b'X' * 100)
669 # create a TOS byte by shifting a DSCP code point 2 bits. those 2 bits
671 dscp = d.IP_API_DSCP_AF31 << 2
673 dscp_ecn = d.IP_API_DSCP_AF31 << 2 | ecn
675 # IPv4 transport that copies the DCSP from the payload
676 tun_dscp = VppIpIpTunInterface(
680 self.pg1.remote_hosts[0].ip6,
681 flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP)
682 tun_dscp.add_vpp_config()
683 # IPv4 transport that copies the DCSP and ECN from the payload
684 tun_dscp_ecn = VppIpIpTunInterface(
688 self.pg1.remote_hosts[1].ip6,
689 flags=(e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP |
690 e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN))
691 tun_dscp_ecn.add_vpp_config()
692 # IPv4 transport that copies the ECN from the payload and sets the
693 # DF bit on encap. copies the ECN on decap
694 tun_ecn = VppIpIpTunInterface(
698 self.pg1.remote_hosts[2].ip6,
699 flags=(e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN |
700 e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_SET_DF |
701 e.TUNNEL_API_ENCAP_DECAP_FLAG_DECAP_COPY_ECN))
702 tun_ecn.add_vpp_config()
703 # IPv4 transport that sets a fixed DSCP in the encap and copies
705 tun = VppIpIpTunInterface(
709 self.pg1.remote_hosts[3].ip6,
710 dscp=d.IP_API_DSCP_AF11,
711 flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DF)
714 # array of all the tunnels
715 tuns = [tun_dscp, tun_dscp_ecn, tun_ecn, tun]
717 # addresses for prefixes routed via each tunnel
718 a4s = ["" for i in range(len(tuns))]
719 a6s = ["" for i in range(len(tuns))]
721 # IP headers for inner packets with each combination of DSCp/ECN tested
722 p_ip6s = [IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp),
723 IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp_ecn),
724 IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=ecn),
725 IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=0xff)]
726 p_ip4s = [IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp, flags='DF'),
727 IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp_ecn),
728 IP(src="1.2.3.4", dst="130.67.0.1", tos=ecn),
729 IP(src="1.2.3.4", dst="130.67.0.1", tos=0xff)]
731 # Configure each tunnel
732 for i, t in enumerate(tuns):
733 # Set interface up and enable IP on it
734 self.vapi.sw_interface_set_flags(t.sw_if_index, 1)
735 self.vapi.sw_interface_set_unnumbered(
736 sw_if_index=self.pg0.sw_if_index,
737 unnumbered_sw_if_index=t.sw_if_index)
739 # prefix for route / destination address for packets
740 a4s[i] = "130.67.%d.0" % i
741 a6s[i] = "dead:%d::" % i
743 # Add IPv4 and IPv6 routes via tunnel interface
744 ip4_via_tunnel = VppIpRoute(
746 [VppRoutePath("0.0.0.0",
748 proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
749 ip4_via_tunnel.add_vpp_config()
751 ip6_via_tunnel = VppIpRoute(
755 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
756 ip6_via_tunnel.add_vpp_config()
762 # tun_dscp copies only the dscp
763 # expected TC values are thus only the DCSP value is present from the
765 exp_tcs = [dscp, dscp, 0, 0xfc]
766 p_ip6_encaps = [IPv6(src=self.pg0.local_ip6,
768 tc=tc) for tc in exp_tcs]
770 # IPv4 in to IPv4 tunnel
771 self.verify_ip4ip6_encaps(a4s[0], p_ip4s, p_ip6_encaps)
772 # IPv6 in to IPv4 tunnel
773 self.verify_ip6ip6_encaps(a6s[0], p_ip6s, p_ip6_encaps)
775 # tun_dscp_ecn copies the dscp and the ecn
776 exp_tcs = [dscp, dscp_ecn, ecn, 0xff]
777 p_ip6_encaps = [IPv6(src=self.pg0.local_ip6,
778 dst=tun_dscp_ecn.dst,
779 tc=tc) for tc in exp_tcs]
781 self.verify_ip4ip6_encaps(a4s[1], p_ip4s, p_ip6_encaps)
782 self.verify_ip6ip6_encaps(a6s[1], p_ip6s, p_ip6_encaps)
784 # tun_ecn copies only the ecn and always sets DF
785 exp_tcs = [0, ecn, ecn, ecn]
786 p_ip6_encaps = [IPv6(src=self.pg0.local_ip6,
788 tc=tc) for tc in exp_tcs]
790 self.verify_ip4ip6_encaps(a4s[2], p_ip4s, p_ip6_encaps)
791 self.verify_ip6ip6_encaps(a6s[2], p_ip6s, p_ip6_encaps)
793 # tun sets a fixed dscp
794 fixed_dscp = tun.dscp << 2
795 p_ip6_encaps = [IPv6(src=self.pg0.local_ip6,
797 tc=fixed_dscp) for i in range(len(p_ip4s))]
799 self.verify_ip4ip6_encaps(a4s[3], p_ip4s, p_ip6_encaps)
800 self.verify_ip6ip6_encaps(a6s[3], p_ip6s, p_ip6_encaps)
805 n_packets_decapped = self.statistics.get_err_counter(
806 '/err/ipip6-input/packets decapsulated')
808 self.p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
810 # IPv6 tunnel to IPv4
811 tcs = [0, dscp, dscp_ecn, ecn]
813 # one overlay packet and all combinations of its encap
814 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
815 p_ip6_encaps = [IPv6(src=tun.dst,
816 dst=self.pg0.local_ip6,
817 tc=tc) for tc in tcs]
819 # for each encap tun will produce the same inner packet because it does
820 # not copy up fields from the payload
821 for p_ip6_encap in p_ip6_encaps:
822 p6 = (self.p_ether / p_ip6_encap / p_ip4 / self.p_payload)
823 p4_reply = (p_ip4 / self.p_payload)
825 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
826 n_packets_decapped += N_PACKETS
828 self.validate(p[1], p4_reply)
829 self.assert_packet_checksums_valid(p)
831 err = self.statistics.get_err_counter(
832 '/err/ipip6-input/packets decapsulated')
833 self.assertEqual(err, n_packets_decapped)
835 # tun_ecn copies the ECN bits from the encap to the inner
836 p_ip6_encaps = [IPv6(src=tun_ecn.dst,
837 dst=self.pg0.local_ip6,
838 tc=tc) for tc in tcs]
839 p_ip4_replys = [p_ip4.copy() for i in range(len(p_ip6_encaps))]
840 p_ip4_replys[2].tos = ecn
841 p_ip4_replys[3].tos = ecn
842 for i, p_ip6_encap in enumerate(p_ip6_encaps):
843 p6 = (self.p_ether / p_ip6_encap / p_ip4 / self.p_payload)
844 p4_reply = (p_ip4_replys[i] / self.p_payload)
846 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
847 n_packets_decapped += N_PACKETS
849 self.validate(p[1], p4_reply)
850 self.assert_packet_checksums_valid(p)
852 err = self.statistics.get_err_counter(
853 '/err/ipip6-input/packets decapsulated')
854 self.assertEqual(err, n_packets_decapped)
856 # IPv6 tunnel to IPv6
857 # for each encap tun will produce the same inner packet because it does
858 # not copy up fields from the payload
859 p_ip6_encaps = [IPv6(src=tun.dst,
860 dst=self.pg0.local_ip6,
861 tc=tc) for tc in tcs]
862 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
863 for p_ip6_encap in p_ip6_encaps:
864 p6 = (self.p_ether / p_ip6_encap / p_ip6 / self.p_payload)
865 p6_reply = (p_ip6 / self.p_payload)
867 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
868 n_packets_decapped += N_PACKETS
870 self.validate(p[1], p6_reply)
871 self.assert_packet_checksums_valid(p)
873 err = self.statistics.get_err_counter(
874 '/err/ipip6-input/packets decapsulated')
875 self.assertEqual(err, n_packets_decapped)
877 # IPv6 tunnel to IPv6
878 # tun_ecn copies the ECN bits from the encap to the inner
879 p_ip6_encaps = [IPv6(src=tun_ecn.dst,
880 dst=self.pg0.local_ip6,
881 tc=tc) for tc in tcs]
882 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
883 p_ip6_replys = [p_ip6.copy() for i in range(len(p_ip6_encaps))]
884 p_ip6_replys[2].tc = ecn
885 p_ip6_replys[3].tc = ecn
886 for i, p_ip6_encap in enumerate(p_ip6_encaps):
887 p6 = (self.p_ether / p_ip6_encap / p_ip6 / self.p_payload)
888 p6_reply = (p_ip6_replys[i] / self.p_payload)
890 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
891 n_packets_decapped += N_PACKETS
893 self.validate(p[1], p6_reply)
894 self.assert_packet_checksums_valid(p)
896 err = self.statistics.get_err_counter(
897 '/err/ipip6-input/packets decapsulated')
898 self.assertEqual(err, n_packets_decapped)
901 """ ip{v4,v6} over ip6 test frag """
903 p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
904 p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP')
905 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
906 p_payload = UDP(sport=1234, dport=1234)
909 # Fragmentation / Reassembly and Re-fragmentation
911 rv = self.vapi.ip_reassembly_enable_disable(
912 sw_if_index=self.pg1.sw_if_index,
915 self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=1000,
916 max_reassembly_length=1000,
917 expire_walk_interval_ms=10000,
920 # Send lots of fragments, verify reassembled packet
921 before_cnt = self.statistics.get_err_counter(
922 '/err/ipip6-input/packets decapsulated')
923 frags, p6_reply = self.generate_ip6_frags(3131, 1400)
925 for i in range(0, 1000):
927 self.pg1.add_stream(f)
928 self.pg_enable_capture()
930 rx = self.pg0.get_capture(1000)
933 self.validate(p[1], p6_reply)
935 cnt = self.statistics.get_err_counter(
936 '/err/ipip6-input/packets decapsulated')
937 self.assertEqual(cnt, before_cnt + 1000)
941 # TODO: Check out why reassembly of atomic fragments don't work
942 for i in range(10, 90):
943 frags, p6_reply = self.generate_ip6_frags(i * 100, 1000)
946 self.pg_enable_capture()
947 self.pg1.add_stream(f)
949 rx = self.pg0.get_capture(80)
952 self.validate(p[1], r[i])
955 # Simple fragmentation
956 p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
957 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1280, 0, 0, 0])
959 # IPv6 in to IPv6 tunnel
960 p_payload = UDP(sport=1234, dport=1234) / self.payload(1300)
962 p6 = (p_ether / p_ip6 / p_payload)
963 p6_reply = (IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6,
966 p6_reply[1].hlim -= 1
967 self.pg_enable_capture()
968 self.pg0.add_stream(p6)
970 rx = self.pg1.get_capture(2)
972 # Scapy defragment doesn't deal well with multiple layers
973 # of same type / Ethernet header first
974 f = [p[1] for p in rx]
975 reass_pkt = defragment6(f)
976 self.validate(reass_pkt, p6_reply)
978 # Now try with re-fragmentation
980 # Send large fragments to tunnel head-end, for the tunnel head end
981 # to reassemble and then refragment out the tunnel again.
984 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1280, 0, 0, 0])
985 frags, p6_reply = self.generate_ip6_hairpin_frags(8000, 1200)
986 self.pg_enable_capture()
987 self.pg1.add_stream(frags)
989 rx = self.pg1.get_capture(7)
990 f = [p[1] for p in rx]
991 reass_pkt = defragment6(f)
993 self.validate(reass_pkt, p6_reply)
995 def test_ipip_create(self):
996 """ ipip create / delete interface test """
997 rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5')
998 sw_if_index = rv.sw_if_index
999 self.vapi.ipip_del_tunnel(sw_if_index)
1001 def test_ipip_vrf_create(self):
1002 """ ipip create / delete interface VRF test """
1004 t = VppIpTable(self, 20)
1006 rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5', table_id=20)
1007 sw_if_index = rv.sw_if_index
1008 self.vapi.ipip_del_tunnel(sw_if_index)
1010 def payload(self, len):
1014 if __name__ == '__main__':
1015 unittest.main(testRunner=VppTestRunner)