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_teib import VppTeib
12 from vpp_papi import VppEnum
13 from socket import AF_INET, AF_INET6, inet_pton
14 from util import reassemble4
16 """ Testipip is a subclass of VPPTestCase classes.
23 def ipip_add_tunnel(test, src, dst, table_id=0, dscp=0x0,
25 """ Add a IPIP tunnel """
26 return test.vapi.ipip_add_tunnel(
31 'instance': 0xffffffff,
37 # the number of packets to send when injecting traffic.
38 # a multiple of 8 minus one, so we test all by 8/4/2/1 loops
42 class TestIPIP(VppTestCase):
43 """ IPIP Test Case """
47 super(TestIPIP, cls).setUpClass()
48 cls.create_pg_interfaces(range(3))
49 cls.interfaces = list(cls.pg_interfaces)
52 def tearDownClass(cls):
53 super(TestIPIP, cls).tearDownClass()
56 super(TestIPIP, self).setUp()
57 self.table = VppIpTable(self, 1, register=False)
58 self.table.add_vpp_config()
60 for i in self.interfaces:
63 self.pg2.set_table_ip4(self.table.table_id)
64 for i in self.interfaces:
72 super(TestIPIP, self).tearDown()
74 for i in self.pg_interfaces:
80 self.table.remove_vpp_config()
82 def validate(self, rx, expected):
83 self.assertEqual(rx, expected.__class__(expected))
85 def generate_ip4_frags(self, payload_length, fragment_size):
86 p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
87 p_payload = UDP(sport=1234, dport=1234) / self.payload(payload_length)
88 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
89 outer_ip4 = (p_ether / IP(src=self.pg1.remote_ip4,
91 dst=self.pg0.local_ip4) / p_ip4 / p_payload)
92 frags = fragment(outer_ip4, fragment_size)
93 p4_reply = (p_ip4 / p_payload)
95 return frags, p4_reply
97 def verify_ip4ip4_encaps(self, a, p_ip4s, p_ip4_encaps):
98 for i, p_ip4 in enumerate(p_ip4s):
100 p4 = (self.p_ether / p_ip4 / self.p_payload)
103 p4_reply = (p_ip4_encaps[i] / p_ip4_inner / self.p_payload)
106 rx = self.send_and_expect(self.pg0, p4 * N_PACKETS, self.pg1)
108 self.validate(p[1], p4_reply)
109 self.assert_packet_checksums_valid(p)
111 def verify_ip6ip4_encaps(self, a, p_ip6s, p_ip4_encaps):
112 for i, p_ip6 in enumerate(p_ip6s):
114 p6 = (self.p_ether / p_ip6 / self.p_payload)
116 p_inner_ip6.hlim -= 1
117 p6_reply = (p_ip4_encaps[i] / p_inner_ip6 / self.p_payload)
119 rx = self.send_and_expect(self.pg0, p6 * N_PACKETS, self.pg1)
121 self.validate(p[1], p6_reply)
122 self.assert_packet_checksums_valid(p)
124 def test_ipip4(self):
125 """ ip{v4,v6} over ip4 test """
127 self.pg1.generate_remote_hosts(5)
128 self.pg1.configure_ipv4_neighbors()
129 e = VppEnum.vl_api_tunnel_encap_decap_flags_t
130 d = VppEnum.vl_api_ip_dscp_t
131 self.p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
132 self.p_payload = UDP(sport=1234, dport=1234) / Raw(b'X' * 100)
134 # create a TOS byte by shifting a DSCP code point 2 bits. those 2 bits
136 dscp = d.IP_API_DSCP_AF31 << 2
138 dscp_ecn = d.IP_API_DSCP_AF31 << 2 | ecn
140 # IPv4 transport that copies the DCSP from the payload
141 tun_dscp = VppIpIpTunInterface(
145 self.pg1.remote_hosts[0].ip4,
146 flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP)
147 tun_dscp.add_vpp_config()
148 # IPv4 transport that copies the DCSP and ECN from the payload
149 tun_dscp_ecn = VppIpIpTunInterface(
153 self.pg1.remote_hosts[1].ip4,
154 flags=(e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP |
155 e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN))
156 tun_dscp_ecn.add_vpp_config()
157 # IPv4 transport that copies the ECN from the payload and sets the
158 # DF bit on encap. copies the ECN on decap
159 tun_ecn = VppIpIpTunInterface(
163 self.pg1.remote_hosts[2].ip4,
164 flags=(e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN |
165 e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_SET_DF |
166 e.TUNNEL_API_ENCAP_DECAP_FLAG_DECAP_COPY_ECN))
167 tun_ecn.add_vpp_config()
168 # IPv4 transport that sets a fixed DSCP in the encap and copies
170 tun = VppIpIpTunInterface(
174 self.pg1.remote_hosts[3].ip4,
175 dscp=d.IP_API_DSCP_AF11,
176 flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DF)
179 # array of all the tunnels
180 tuns = [tun_dscp, tun_dscp_ecn, tun_ecn, tun]
182 # addresses for prefixes routed via each tunnel
183 a4s = ["" for i in range(len(tuns))]
184 a6s = ["" for i in range(len(tuns))]
186 # IP headers with each combination of DSCp/ECN tested
187 p_ip6s = [IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp),
188 IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp_ecn),
189 IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=ecn),
190 IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=0xff)]
191 p_ip4s = [IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp, flags='DF'),
192 IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp_ecn),
193 IP(src="1.2.3.4", dst="130.67.0.1", tos=ecn),
194 IP(src="1.2.3.4", dst="130.67.0.1", tos=0xff)]
196 # Configure each tunnel
197 for i, t in enumerate(tuns):
198 # Set interface up and enable IP on it
199 self.vapi.sw_interface_set_flags(t.sw_if_index, 1)
200 self.vapi.sw_interface_set_unnumbered(
201 sw_if_index=self.pg0.sw_if_index,
202 unnumbered_sw_if_index=t.sw_if_index)
204 # prefix for route / destination address for packets
205 a4s[i] = "130.67.%d.0" % i
206 a6s[i] = "dead:%d::" % i
208 # Add IPv4 and IPv6 routes via tunnel interface
209 ip4_via_tunnel = VppIpRoute(
211 [VppRoutePath("0.0.0.0",
213 proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
214 ip4_via_tunnel.add_vpp_config()
216 ip6_via_tunnel = VppIpRoute(
220 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
221 ip6_via_tunnel.add_vpp_config()
227 # tun_dscp copies only the dscp
228 # expected TC values are thus only the DCSP value is present from the
230 exp_tcs = [dscp, dscp, 0, 0xfc]
231 p_ip44_encaps = [IP(src=self.pg0.local_ip4,
233 tos=tc) for tc in exp_tcs]
234 p_ip64_encaps = [IP(src=self.pg0.local_ip4,
236 proto='ipv6', id=0, tos=tc) for tc in exp_tcs]
238 # IPv4 in to IPv4 tunnel
239 self.verify_ip4ip4_encaps(a4s[0], p_ip4s, p_ip44_encaps)
240 # IPv6 in to IPv4 tunnel
241 self.verify_ip6ip4_encaps(a6s[0], p_ip6s, p_ip64_encaps)
243 # tun_dscp_ecn copies the dscp and the ecn
244 exp_tcs = [dscp, dscp_ecn, ecn, 0xff]
245 p_ip44_encaps = [IP(src=self.pg0.local_ip4,
246 dst=tun_dscp_ecn.dst,
247 tos=tc) for tc in exp_tcs]
248 p_ip64_encaps = [IP(src=self.pg0.local_ip4,
249 dst=tun_dscp_ecn.dst,
250 proto='ipv6', id=0, tos=tc) for tc in exp_tcs]
252 self.verify_ip4ip4_encaps(a4s[1], p_ip4s, p_ip44_encaps)
253 self.verify_ip6ip4_encaps(a6s[1], p_ip6s, p_ip64_encaps)
255 # tun_ecn copies only the ecn and always sets DF
256 exp_tcs = [0, ecn, ecn, ecn]
257 p_ip44_encaps = [IP(src=self.pg0.local_ip4,
259 flags='DF', tos=tc) for tc in exp_tcs]
260 p_ip64_encaps = [IP(src=self.pg0.local_ip4,
262 flags='DF', proto='ipv6', id=0, tos=tc)
265 self.verify_ip4ip4_encaps(a4s[2], p_ip4s, p_ip44_encaps)
266 self.verify_ip6ip4_encaps(a6s[2], p_ip6s, p_ip64_encaps)
268 # tun sets a fixed dscp and copies DF
269 fixed_dscp = tun.dscp << 2
270 flags = ['DF', 0, 0, 0]
271 p_ip44_encaps = [IP(src=self.pg0.local_ip4,
274 tos=fixed_dscp) for f in flags]
275 p_ip64_encaps = [IP(src=self.pg0.local_ip4,
278 tos=fixed_dscp) for i in range(len(p_ip4s))]
280 self.verify_ip4ip4_encaps(a4s[3], p_ip4s, p_ip44_encaps)
281 self.verify_ip6ip4_encaps(a6s[3], p_ip6s, p_ip64_encaps)
286 n_packets_decapped = 0
287 self.p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
289 # IPv4 tunnel to IPv4
290 tcs = [0, dscp, dscp_ecn, ecn]
292 # one overlay packet and all combinations of its encap
293 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
294 p_ip4_encaps = [IP(src=tun.dst,
295 dst=self.pg0.local_ip4,
296 tos=tc) for tc in tcs]
298 # for each encap tun will produce the same inner packet because it does
299 # not copy up fields from the payload
300 for p_ip4_encap in p_ip4_encaps:
301 p4 = (self.p_ether / p_ip4_encap / p_ip4 / self.p_payload)
302 p4_reply = (p_ip4 / self.p_payload)
304 rx = self.send_and_expect(self.pg1, p4 * N_PACKETS, self.pg0)
305 n_packets_decapped += N_PACKETS
307 self.validate(p[1], p4_reply)
308 self.assert_packet_checksums_valid(p)
310 err = self.statistics.get_err_counter(
311 '/err/ipip4-input/packets decapsulated')
312 self.assertEqual(err, n_packets_decapped)
314 # tun_ecn copies the ECN bits from the encap to the inner
315 p_ip4_encaps = [IP(src=tun_ecn.dst,
316 dst=self.pg0.local_ip4,
317 tos=tc) for tc in tcs]
318 p_ip4_replys = [p_ip4.copy() for i in range(len(p_ip4_encaps))]
319 p_ip4_replys[2].tos = ecn
320 p_ip4_replys[3].tos = ecn
321 for i, p_ip4_encap in enumerate(p_ip4_encaps):
322 p4 = (self.p_ether / p_ip4_encap / p_ip4 / self.p_payload)
323 p4_reply = (p_ip4_replys[i] / self.p_payload)
325 rx = self.send_and_expect(self.pg1, p4 * N_PACKETS, self.pg0)
326 n_packets_decapped += N_PACKETS
328 self.validate(p[1], p4_reply)
329 self.assert_packet_checksums_valid(p)
331 err = self.statistics.get_err_counter(
332 '/err/ipip4-input/packets decapsulated')
333 self.assertEqual(err, n_packets_decapped)
335 # IPv4 tunnel to IPv6
336 # for each encap tun will produce the same inner packet because it does
337 # not copy up fields from the payload
338 p_ip4_encaps = [IP(src=tun.dst,
339 dst=self.pg0.local_ip4,
340 tos=tc) for tc in tcs]
341 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
342 for p_ip4_encap in p_ip4_encaps:
344 p_ip4_encap / p_ip6 /
346 p6_reply = (p_ip6 / self.p_payload)
348 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
349 n_packets_decapped += N_PACKETS
351 self.validate(p[1], p6_reply)
352 self.assert_packet_checksums_valid(p)
354 err = self.statistics.get_err_counter(
355 '/err/ipip4-input/packets decapsulated')
356 self.assertEqual(err, n_packets_decapped)
358 # IPv4 tunnel to IPv6
359 # tun_ecn copies the ECN bits from the encap to the inner
360 p_ip4_encaps = [IP(src=tun_ecn.dst,
361 dst=self.pg0.local_ip4,
362 tos=tc) for tc in tcs]
363 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
364 p_ip6_replys = [p_ip6.copy() for i in range(len(p_ip4_encaps))]
365 p_ip6_replys[2].tc = ecn
366 p_ip6_replys[3].tc = ecn
367 for i, p_ip4_encap in enumerate(p_ip4_encaps):
368 p6 = (self.p_ether / p_ip4_encap / p_ip6 / self.p_payload)
369 p6_reply = (p_ip6_replys[i] / self.p_payload)
371 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
372 n_packets_decapped += N_PACKETS
374 self.validate(p[1], p6_reply)
375 self.assert_packet_checksums_valid(p)
377 err = self.statistics.get_err_counter(
378 '/err/ipip4-input/packets decapsulated')
379 self.assertEqual(err, n_packets_decapped)
382 # Fragmentation / Reassembly and Re-fragmentation
384 rv = self.vapi.ip_reassembly_enable_disable(
385 sw_if_index=self.pg1.sw_if_index,
388 self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=1000,
389 max_reassembly_length=1000,
390 expire_walk_interval_ms=10000,
393 # Send lots of fragments, verify reassembled packet
394 frags, p4_reply = self.generate_ip4_frags(3131, 1400)
396 for i in range(0, 1000):
398 self.pg1.add_stream(f)
399 self.pg_enable_capture()
401 rx = self.pg0.get_capture(1000)
402 n_packets_decapped += 1000
405 self.validate(p[1], p4_reply)
407 err = self.statistics.get_err_counter(
408 '/err/ipip4-input/packets decapsulated')
409 self.assertEqual(err, n_packets_decapped)
413 for i in range(1, 90):
414 frags, p4_reply = self.generate_ip4_frags(i * 100, 1000)
417 self.pg_enable_capture()
418 self.pg1.add_stream(f)
420 rx = self.pg0.get_capture(89)
423 self.validate(p[1], r[i])
426 # Now try with re-fragmentation
428 # Send fragments to tunnel head-end, for the tunnel head end
429 # to reassemble and then refragment
431 self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [576, 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(6)
437 reass_pkt = reassemble4(rx)
439 self.validate(reass_pkt, p4_reply)
441 self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [1600, 0, 0, 0])
442 frags, p4_reply = self.generate_ip4_frags(3123, 1200)
443 self.pg_enable_capture()
444 self.pg1.add_stream(frags)
446 rx = self.pg0.get_capture(2)
447 reass_pkt = reassemble4(rx)
449 self.validate(reass_pkt, p4_reply)
451 # send large packets through the tunnel, expect them to be fragmented
452 self.vapi.sw_interface_set_mtu(tun_dscp.sw_if_index, [600, 0, 0, 0])
454 p4 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
455 IP(src="1.2.3.4", dst="130.67.0.1", tos=42) /
456 UDP(sport=1234, dport=1234) / Raw(b'Q' * 1000))
457 rx = self.send_and_expect(self.pg0, p4 * 15, self.pg1, 30)
460 inners.append(p[IP].payload)
461 reass_pkt = reassemble4(inners)
463 self.assert_packet_checksums_valid(p)
464 self.assertEqual(p[IP].ttl, 63)
466 def test_ipip_create(self):
467 """ ipip create / delete interface test """
468 rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5')
469 sw_if_index = rv.sw_if_index
470 self.vapi.ipip_del_tunnel(sw_if_index)
472 def test_ipip_vrf_create(self):
473 """ ipip create / delete interface VRF test """
475 t = VppIpTable(self, 20)
477 rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5', table_id=20)
478 sw_if_index = rv.sw_if_index
479 self.vapi.ipip_del_tunnel(sw_if_index)
481 def payload(self, len):
484 def test_mipip4(self):
485 """ p2mp IPv4 tunnel Tests """
487 for itf in self.pg_interfaces[:2]:
489 # one underlay nh for each overlay/tunnel peer
491 itf.generate_remote_hosts(4)
492 itf.configure_ipv4_neighbors()
495 # Create an p2mo IPIP tunnel.
497 # - assign an IP Addres
498 # - Add a route via the tunnel
500 ipip_if = VppIpIpTunInterface(self, itf,
503 mode=(VppEnum.vl_api_tunnel_mode_t.
505 ipip_if.add_vpp_config()
508 ipip_if.generate_remote_hosts(4)
510 self.logger.info(self.vapi.cli("sh adj"))
511 self.logger.info(self.vapi.cli("sh ip fib"))
514 # ensure we don't match to the tunnel if the source address
517 # tx = self.create_tunnel_stream_4o4(self.pg0,
520 # self.pg0.local_ip4,
521 # self.pg0.remote_ip4)
522 # self.send_and_assert_no_replies(self.pg0, tx)
527 for ii in range(1, 4):
528 route_addr = "4.4.4.%d" % ii
531 # route traffic via the peer
533 route_via_tun = VppIpRoute(
534 self, route_addr, 32,
535 [VppRoutePath(ipip_if._remote_hosts[ii].ip4,
536 ipip_if.sw_if_index)])
537 route_via_tun.add_vpp_config()
540 # Add a TEIB entry resolves the peer
542 teib = VppTeib(self, ipip_if,
543 ipip_if._remote_hosts[ii].ip4,
544 itf._remote_hosts[ii].ip4)
545 teib.add_vpp_config()
546 self.logger.info(self.vapi.cli("sh adj nbr ipip0 %s" %
547 ipip_if._remote_hosts[ii].ip4))
550 # Send a packet stream that is routed into the tunnel
551 # - packets are IPIP encapped
553 inner = (IP(dst=route_addr, src="5.5.5.5") /
554 UDP(sport=1234, dport=1234) /
556 tx_e = [(Ether(dst=self.pg0.local_mac,
557 src=self.pg0.remote_mac) /
558 inner) for x in range(63)]
560 rxs = self.send_and_expect(self.pg0, tx_e, itf)
563 self.assertEqual(rx[IP].src, itf.local_ip4)
564 self.assertEqual(rx[IP].dst, itf._remote_hosts[ii].ip4)
566 tx_i = [(Ether(dst=self.pg0.local_mac,
567 src=self.pg0.remote_mac) /
568 IP(src=itf._remote_hosts[ii].ip4,
570 IP(src=self.pg0.local_ip4, dst=self.pg0.remote_ip4) /
571 UDP(sport=1234, dport=1234) /
572 Raw(b'0x44' * 100)) for x in range(63)]
574 self.logger.info(self.vapi.cli("sh ipip tunnel-hash"))
575 rx = self.send_and_expect(self.pg0, tx_i, self.pg0)
578 # delete and re-add the TEIB
580 teib.remove_vpp_config()
581 self.send_and_assert_no_replies(self.pg0, tx_e)
582 self.send_and_assert_no_replies(self.pg0, tx_i)
584 teib.add_vpp_config()
585 rx = self.send_and_expect(self.pg0, tx_e, itf)
587 self.assertEqual(rx[IP].src, itf.local_ip4)
588 self.assertEqual(rx[IP].dst, itf._remote_hosts[ii].ip4)
589 rx = self.send_and_expect(self.pg0, tx_i, self.pg0)
592 # we can also send to the peer's address
594 inner = (IP(dst=teib.peer, src="5.5.5.5") /
595 UDP(sport=1234, dport=1234) /
597 tx_e = [(Ether(dst=self.pg0.local_mac,
598 src=self.pg0.remote_mac) /
599 inner) for x in range(63)]
601 rxs = self.send_and_expect(self.pg0, tx_e, itf)
604 # with all of the peers in place, swap the ip-table of
607 table = VppIpTable(self, 2)
608 table.add_vpp_config()
610 ipip_if.unconfig_ip4()
611 ipip_if.set_table_ip4(self.table.table_id)
615 # we should still be able to reach the peers from the new table
617 inner = (IP(dst=teib.peer, src="5.5.5.5") /
618 UDP(sport=1234, dport=1234) /
620 tx_e = [(Ether(dst=self.pg0.local_mac,
621 src=self.pg0.remote_mac) /
622 inner) for x in range(63)]
624 rxs = self.send_and_expect(self.pg2, tx_e, itf)
627 ipip_if.unconfig_ip4()
628 ipip_if.set_table_ip4(0)
631 class TestIPIP6(VppTestCase):
632 """ IPIP6 Test Case """
636 super(TestIPIP6, cls).setUpClass()
637 cls.create_pg_interfaces(range(2))
638 cls.interfaces = list(cls.pg_interfaces)
641 def tearDownClass(cls):
642 super(TestIPIP6, cls).tearDownClass()
645 super(TestIPIP6, self).setUp()
646 for i in self.interfaces:
656 if not self.vpp_dead:
657 self.destroy_tunnel()
658 for i in self.pg_interfaces:
662 super(TestIPIP6, self).tearDown()
664 def setup_tunnel(self):
666 rv = ipip_add_tunnel(self,
670 sw_if_index = rv.sw_if_index
671 self.tunnel_if_index = sw_if_index
672 self.vapi.sw_interface_set_flags(sw_if_index, 1)
673 self.vapi.sw_interface_set_unnumbered(
674 sw_if_index=self.pg0.sw_if_index,
675 unnumbered_sw_if_index=sw_if_index)
677 # Add IPv4 and IPv6 routes via tunnel interface
678 ip4_via_tunnel = VppIpRoute(
679 self, "130.67.0.0", 16,
680 [VppRoutePath("0.0.0.0",
682 proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
683 ip4_via_tunnel.add_vpp_config()
685 ip6_via_tunnel = VppIpRoute(
689 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
690 ip6_via_tunnel.add_vpp_config()
692 self.tunnel_ip6_via_tunnel = ip6_via_tunnel
693 self.tunnel_ip4_via_tunnel = ip4_via_tunnel
695 def destroy_tunnel(self):
697 self.tunnel_ip4_via_tunnel.remove_vpp_config()
698 self.tunnel_ip6_via_tunnel.remove_vpp_config()
700 rv = self.vapi.ipip_del_tunnel(sw_if_index=self.tunnel_if_index)
702 def validate(self, rx, expected):
703 self.assertEqual(rx, expected.__class__(expected))
705 def generate_ip6_frags(self, payload_length, fragment_size):
706 p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
707 p_payload = UDP(sport=1234, dport=1234) / self.payload(payload_length)
708 p_ip6 = IPv6(src="1::1", dst=self.pg0.remote_ip6)
709 outer_ip6 = (p_ether / IPv6(src=self.pg1.remote_ip6,
710 dst=self.pg0.local_ip6) /
711 IPv6ExtHdrFragment() / p_ip6 / p_payload)
712 frags = fragment6(outer_ip6, fragment_size)
713 p6_reply = (p_ip6 / p_payload)
715 return frags, p6_reply
717 def generate_ip6_hairpin_frags(self, payload_length, fragment_size):
718 p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
719 p_payload = UDP(sport=1234, dport=1234) / self.payload(payload_length)
720 p_ip6 = IPv6(src="1::1", dst="dead::1")
721 outer_ip6 = (p_ether / IPv6(src=self.pg1.remote_ip6,
722 dst=self.pg0.local_ip6) /
723 IPv6ExtHdrFragment() / p_ip6 / p_payload)
724 frags = fragment6(outer_ip6, fragment_size)
726 p6_reply = (IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6,
727 hlim=63) / p_ip6 / p_payload)
729 return frags, p6_reply
731 def test_encap(self):
732 """ ip{v4,v6} over ip6 test encap """
733 p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
734 p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP')
735 p_ip4 = IP(src="1.2.3.4", dst="130.67.0.1", tos=42)
736 p_payload = UDP(sport=1234, dport=1234)
739 # IPv6 in to IPv6 tunnel
740 p6 = (p_ether / p_ip6 / p_payload)
741 p6_reply = (IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6,
744 p6_reply[1].hlim -= 1
745 rx = self.send_and_expect(self.pg0, p6 * 11, self.pg1)
747 self.validate(p[1], p6_reply)
749 # IPv4 in to IPv6 tunnel
750 p4 = (p_ether / p_ip4 / p_payload)
751 p4_reply = (IPv6(src=self.pg0.local_ip6,
752 dst=self.pg1.remote_ip6, hlim=64) /
755 rx = self.send_and_expect(self.pg0, p4 * 11, self.pg1)
757 self.validate(p[1], p4_reply)
759 def test_decap(self):
760 """ ip{v4,v6} over ip6 test decap """
762 p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
763 p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP')
764 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
765 p_payload = UDP(sport=1234, dport=1234)
768 # IPv6 tunnel to IPv4
770 p4 = (p_ether / IPv6(src=self.pg1.remote_ip6,
771 dst=self.pg0.local_ip6) / p_ip4 / p_payload)
772 p4_reply = (p_ip4 / p_payload)
774 rx = self.send_and_expect(self.pg1, p4 * 11, self.pg0)
776 self.validate(p[1], p4_reply)
778 # IPv6 tunnel to IPv6
779 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
780 p6 = (p_ether / IPv6(src=self.pg1.remote_ip6,
781 dst=self.pg0.local_ip6) / p_ip6 / p_payload)
782 p6_reply = (p_ip6 / p_payload)
784 rx = self.send_and_expect(self.pg1, p6 * 11, self.pg0)
786 self.validate(p[1], p6_reply)
788 def verify_ip4ip6_encaps(self, a, p_ip4s, p_ip6_encaps):
789 for i, p_ip4 in enumerate(p_ip4s):
791 p4 = (self.p_ether / p_ip4 / self.p_payload)
794 p6_reply = (p_ip6_encaps[i] / p_ip4_inner / self.p_payload)
795 rx = self.send_and_expect(self.pg0, p4 * N_PACKETS, self.pg1)
797 self.validate(p[1], p6_reply)
798 self.assert_packet_checksums_valid(p)
800 def verify_ip6ip6_encaps(self, a, p_ip6s, p_ip6_encaps):
801 for i, p_ip6 in enumerate(p_ip6s):
803 p6 = (self.p_ether / p_ip6 / self.p_payload)
805 p_inner_ip6.hlim -= 1
806 p6_reply = (p_ip6_encaps[i] / p_inner_ip6 / self.p_payload)
807 rx = self.send_and_expect(self.pg0, p6 * N_PACKETS, self.pg1)
809 self.validate(p[1], p6_reply)
810 self.assert_packet_checksums_valid(p)
812 def test_ipip6(self):
813 """ ip{v4,v6} over ip6 test """
816 self.destroy_tunnel()
818 self.pg1.generate_remote_hosts(5)
819 self.pg1.configure_ipv6_neighbors()
820 e = VppEnum.vl_api_tunnel_encap_decap_flags_t
821 d = VppEnum.vl_api_ip_dscp_t
822 self.p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
823 self.p_payload = UDP(sport=1234, dport=1234) / Raw(b'X' * 100)
825 # create a TOS byte by shifting a DSCP code point 2 bits. those 2 bits
827 dscp = d.IP_API_DSCP_AF31 << 2
829 dscp_ecn = d.IP_API_DSCP_AF31 << 2 | ecn
831 # IPv4 transport that copies the DCSP from the payload
832 tun_dscp = VppIpIpTunInterface(
836 self.pg1.remote_hosts[0].ip6,
837 flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP)
838 tun_dscp.add_vpp_config()
839 # IPv4 transport that copies the DCSP and ECN from the payload
840 tun_dscp_ecn = VppIpIpTunInterface(
844 self.pg1.remote_hosts[1].ip6,
845 flags=(e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP |
846 e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN))
847 tun_dscp_ecn.add_vpp_config()
848 # IPv4 transport that copies the ECN from the payload and sets the
849 # DF bit on encap. copies the ECN on decap
850 tun_ecn = VppIpIpTunInterface(
854 self.pg1.remote_hosts[2].ip6,
855 flags=(e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN |
856 e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_SET_DF |
857 e.TUNNEL_API_ENCAP_DECAP_FLAG_DECAP_COPY_ECN))
858 tun_ecn.add_vpp_config()
859 # IPv4 transport that sets a fixed DSCP in the encap and copies
861 tun = VppIpIpTunInterface(
865 self.pg1.remote_hosts[3].ip6,
866 dscp=d.IP_API_DSCP_AF11,
867 flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DF)
870 # array of all the tunnels
871 tuns = [tun_dscp, tun_dscp_ecn, tun_ecn, tun]
873 # addresses for prefixes routed via each tunnel
874 a4s = ["" for i in range(len(tuns))]
875 a6s = ["" for i in range(len(tuns))]
877 # IP headers for inner packets with each combination of DSCp/ECN tested
878 p_ip6s = [IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp),
879 IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp_ecn),
880 IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=ecn),
881 IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=0xff)]
882 p_ip4s = [IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp, flags='DF'),
883 IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp_ecn),
884 IP(src="1.2.3.4", dst="130.67.0.1", tos=ecn),
885 IP(src="1.2.3.4", dst="130.67.0.1", tos=0xff)]
887 # Configure each tunnel
888 for i, t in enumerate(tuns):
889 # Set interface up and enable IP on it
890 self.vapi.sw_interface_set_flags(t.sw_if_index, 1)
891 self.vapi.sw_interface_set_unnumbered(
892 sw_if_index=self.pg0.sw_if_index,
893 unnumbered_sw_if_index=t.sw_if_index)
895 # prefix for route / destination address for packets
896 a4s[i] = "130.67.%d.0" % i
897 a6s[i] = "dead:%d::" % i
899 # Add IPv4 and IPv6 routes via tunnel interface
900 ip4_via_tunnel = VppIpRoute(
902 [VppRoutePath("0.0.0.0",
904 proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
905 ip4_via_tunnel.add_vpp_config()
907 ip6_via_tunnel = VppIpRoute(
911 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
912 ip6_via_tunnel.add_vpp_config()
918 # tun_dscp copies only the dscp
919 # expected TC values are thus only the DCSP value is present from the
921 exp_tcs = [dscp, dscp, 0, 0xfc]
922 p_ip6_encaps = [IPv6(src=self.pg0.local_ip6,
924 tc=tc) for tc in exp_tcs]
926 # IPv4 in to IPv4 tunnel
927 self.verify_ip4ip6_encaps(a4s[0], p_ip4s, p_ip6_encaps)
928 # IPv6 in to IPv4 tunnel
929 self.verify_ip6ip6_encaps(a6s[0], p_ip6s, p_ip6_encaps)
931 # tun_dscp_ecn copies the dscp and the ecn
932 exp_tcs = [dscp, dscp_ecn, ecn, 0xff]
933 p_ip6_encaps = [IPv6(src=self.pg0.local_ip6,
934 dst=tun_dscp_ecn.dst,
935 tc=tc) for tc in exp_tcs]
937 self.verify_ip4ip6_encaps(a4s[1], p_ip4s, p_ip6_encaps)
938 self.verify_ip6ip6_encaps(a6s[1], p_ip6s, p_ip6_encaps)
940 # tun_ecn copies only the ecn and always sets DF
941 exp_tcs = [0, ecn, ecn, ecn]
942 p_ip6_encaps = [IPv6(src=self.pg0.local_ip6,
944 tc=tc) for tc in exp_tcs]
946 self.verify_ip4ip6_encaps(a4s[2], p_ip4s, p_ip6_encaps)
947 self.verify_ip6ip6_encaps(a6s[2], p_ip6s, p_ip6_encaps)
949 # tun sets a fixed dscp
950 fixed_dscp = tun.dscp << 2
951 p_ip6_encaps = [IPv6(src=self.pg0.local_ip6,
953 tc=fixed_dscp) for i in range(len(p_ip4s))]
955 self.verify_ip4ip6_encaps(a4s[3], p_ip4s, p_ip6_encaps)
956 self.verify_ip6ip6_encaps(a6s[3], p_ip6s, p_ip6_encaps)
961 n_packets_decapped = self.statistics.get_err_counter(
962 '/err/ipip6-input/packets decapsulated')
964 self.p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
966 # IPv6 tunnel to IPv4
967 tcs = [0, dscp, dscp_ecn, ecn]
969 # one overlay packet and all combinations of its encap
970 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
971 p_ip6_encaps = [IPv6(src=tun.dst,
972 dst=self.pg0.local_ip6,
973 tc=tc) for tc in tcs]
975 # for each encap tun will produce the same inner packet because it does
976 # not copy up fields from the payload
977 for p_ip6_encap in p_ip6_encaps:
978 p6 = (self.p_ether / p_ip6_encap / p_ip4 / self.p_payload)
979 p4_reply = (p_ip4 / self.p_payload)
981 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
982 n_packets_decapped += N_PACKETS
984 self.validate(p[1], p4_reply)
985 self.assert_packet_checksums_valid(p)
987 err = self.statistics.get_err_counter(
988 '/err/ipip6-input/packets decapsulated')
989 self.assertEqual(err, n_packets_decapped)
991 # tun_ecn copies the ECN bits from the encap to the inner
992 p_ip6_encaps = [IPv6(src=tun_ecn.dst,
993 dst=self.pg0.local_ip6,
994 tc=tc) for tc in tcs]
995 p_ip4_replys = [p_ip4.copy() for i in range(len(p_ip6_encaps))]
996 p_ip4_replys[2].tos = ecn
997 p_ip4_replys[3].tos = ecn
998 for i, p_ip6_encap in enumerate(p_ip6_encaps):
999 p6 = (self.p_ether / p_ip6_encap / p_ip4 / self.p_payload)
1000 p4_reply = (p_ip4_replys[i] / self.p_payload)
1002 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
1003 n_packets_decapped += N_PACKETS
1005 self.validate(p[1], p4_reply)
1006 self.assert_packet_checksums_valid(p)
1008 err = self.statistics.get_err_counter(
1009 '/err/ipip6-input/packets decapsulated')
1010 self.assertEqual(err, n_packets_decapped)
1012 # IPv6 tunnel to IPv6
1013 # for each encap tun will produce the same inner packet because it does
1014 # not copy up fields from the payload
1015 p_ip6_encaps = [IPv6(src=tun.dst,
1016 dst=self.pg0.local_ip6,
1017 tc=tc) for tc in tcs]
1018 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
1019 for p_ip6_encap in p_ip6_encaps:
1020 p6 = (self.p_ether / p_ip6_encap / p_ip6 / self.p_payload)
1021 p6_reply = (p_ip6 / self.p_payload)
1023 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
1024 n_packets_decapped += N_PACKETS
1026 self.validate(p[1], p6_reply)
1027 self.assert_packet_checksums_valid(p)
1029 err = self.statistics.get_err_counter(
1030 '/err/ipip6-input/packets decapsulated')
1031 self.assertEqual(err, n_packets_decapped)
1033 # IPv6 tunnel to IPv6
1034 # tun_ecn copies the ECN bits from the encap to the inner
1035 p_ip6_encaps = [IPv6(src=tun_ecn.dst,
1036 dst=self.pg0.local_ip6,
1037 tc=tc) for tc in tcs]
1038 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
1039 p_ip6_replys = [p_ip6.copy() for i in range(len(p_ip6_encaps))]
1040 p_ip6_replys[2].tc = ecn
1041 p_ip6_replys[3].tc = ecn
1042 for i, p_ip6_encap in enumerate(p_ip6_encaps):
1043 p6 = (self.p_ether / p_ip6_encap / p_ip6 / self.p_payload)
1044 p6_reply = (p_ip6_replys[i] / self.p_payload)
1046 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
1047 n_packets_decapped += N_PACKETS
1049 self.validate(p[1], p6_reply)
1050 self.assert_packet_checksums_valid(p)
1052 err = self.statistics.get_err_counter(
1053 '/err/ipip6-input/packets decapsulated')
1054 self.assertEqual(err, n_packets_decapped)
1056 def test_frag(self):
1057 """ ip{v4,v6} over ip6 test frag """
1059 p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
1060 p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP')
1061 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
1062 p_payload = UDP(sport=1234, dport=1234)
1065 # Fragmentation / Reassembly and Re-fragmentation
1067 rv = self.vapi.ip_reassembly_enable_disable(
1068 sw_if_index=self.pg1.sw_if_index,
1071 self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=1000,
1072 max_reassembly_length=1000,
1073 expire_walk_interval_ms=10000,
1076 # Send lots of fragments, verify reassembled packet
1077 before_cnt = self.statistics.get_err_counter(
1078 '/err/ipip6-input/packets decapsulated')
1079 frags, p6_reply = self.generate_ip6_frags(3131, 1400)
1081 for i in range(0, 1000):
1083 self.pg1.add_stream(f)
1084 self.pg_enable_capture()
1086 rx = self.pg0.get_capture(1000)
1089 self.validate(p[1], p6_reply)
1091 cnt = self.statistics.get_err_counter(
1092 '/err/ipip6-input/packets decapsulated')
1093 self.assertEqual(cnt, before_cnt + 1000)
1097 # TODO: Check out why reassembly of atomic fragments don't work
1098 for i in range(10, 90):
1099 frags, p6_reply = self.generate_ip6_frags(i * 100, 1000)
1102 self.pg_enable_capture()
1103 self.pg1.add_stream(f)
1105 rx = self.pg0.get_capture(80)
1108 self.validate(p[1], r[i])
1111 # Simple fragmentation
1112 p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1113 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1280, 0, 0, 0])
1115 # IPv6 in to IPv6 tunnel
1116 p_payload = UDP(sport=1234, dport=1234) / self.payload(1300)
1118 p6 = (p_ether / p_ip6 / p_payload)
1119 p6_reply = (IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6,
1122 p6_reply[1].hlim -= 1
1123 self.pg_enable_capture()
1124 self.pg0.add_stream(p6)
1126 rx = self.pg1.get_capture(2)
1128 # Scapy defragment doesn't deal well with multiple layers
1129 # of same type / Ethernet header first
1130 f = [p[1] for p in rx]
1131 reass_pkt = defragment6(f)
1132 self.validate(reass_pkt, p6_reply)
1134 # Now try with re-fragmentation
1136 # Send large fragments to tunnel head-end, for the tunnel head end
1137 # to reassemble and then refragment out the tunnel again.
1140 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1280, 0, 0, 0])
1141 frags, p6_reply = self.generate_ip6_hairpin_frags(8000, 1200)
1142 self.pg_enable_capture()
1143 self.pg1.add_stream(frags)
1145 rx = self.pg1.get_capture(7)
1146 f = [p[1] for p in rx]
1147 reass_pkt = defragment6(f)
1149 self.validate(reass_pkt, p6_reply)
1151 def test_ipip_create(self):
1152 """ ipip create / delete interface test """
1153 rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5')
1154 sw_if_index = rv.sw_if_index
1155 self.vapi.ipip_del_tunnel(sw_if_index)
1157 def test_ipip_vrf_create(self):
1158 """ ipip create / delete interface VRF test """
1160 t = VppIpTable(self, 20)
1162 rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5', table_id=20)
1163 sw_if_index = rv.sw_if_index
1164 self.vapi.ipip_del_tunnel(sw_if_index)
1166 def payload(self, len):
1170 if __name__ == '__main__':
1171 unittest.main(testRunner=VppTestRunner)