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.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 (
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
24 """ Testipip is a subclass of VPPTestCase classes.
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(
38 "instance": 0xFFFFFFFF,
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
50 class TestIPIP(VppTestCase):
55 super(TestIPIP, cls).setUpClass()
56 cls.create_pg_interfaces(range(3))
57 cls.interfaces = list(cls.pg_interfaces)
60 def tearDownClass(cls):
61 super(TestIPIP, cls).tearDownClass()
64 super(TestIPIP, self).setUp()
65 self.table = VppIpTable(self, 1, register=False)
66 self.table.add_vpp_config()
68 for i in self.interfaces:
71 self.pg2.set_table_ip4(self.table.table_id)
72 for i in self.interfaces:
80 super(TestIPIP, self).tearDown()
82 for i in self.pg_interfaces:
88 self.table.remove_vpp_config()
90 def validate(self, rx, expected):
91 self.assertEqual(rx, expected.__class__(expected))
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)
99 / IP(src=self.pg1.remote_ip4, id=RandShort(), dst=self.pg0.local_ip4)
103 frags = fragment(outer_ip4, fragment_size)
104 p4_reply = p_ip4 / p_payload
106 return frags, p4_reply
108 def verify_ip4ip4_encaps(self, a, p_ip4s, p_ip4_encaps):
109 for i, p_ip4 in enumerate(p_ip4s):
111 p4 = self.p_ether / p_ip4 / self.p_payload
114 p4_reply = p_ip4_encaps[i] / p_ip4_inner / self.p_payload
117 rx = self.send_and_expect(self.pg0, p4 * N_PACKETS, self.pg1)
119 self.validate(p[1], p4_reply)
120 self.assert_packet_checksums_valid(p)
122 def verify_ip6ip4_encaps(self, a, p_ip6s, p_ip4_encaps):
123 for i, p_ip6 in enumerate(p_ip6s):
125 p6 = self.p_ether / p_ip6 / self.p_payload
127 p_inner_ip6.hlim -= 1
128 p6_reply = p_ip4_encaps[i] / p_inner_ip6 / self.p_payload
130 rx = self.send_and_expect(self.pg0, p6 * N_PACKETS, self.pg1)
132 self.validate(p[1], p6_reply)
133 self.assert_packet_checksums_valid(p)
135 def test_ipip4(self):
136 """ip{v4,v6} over ip4 test"""
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)
145 # create a TOS byte by shifting a DSCP code point 2 bits. those 2 bits
147 dscp = d.IP_API_DSCP_AF31 << 2
149 dscp_ecn = d.IP_API_DSCP_AF31 << 2 | ecn
151 # IPv4 transport that copies the DCSP from the payload
152 tun_dscp = VppIpIpTunInterface(
156 self.pg1.remote_hosts[0].ip4,
157 flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP,
159 tun_dscp.add_vpp_config()
160 # IPv4 transport that copies the DCSP and ECN from the payload
161 tun_dscp_ecn = VppIpIpTunInterface(
165 self.pg1.remote_hosts[1].ip4,
167 e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP
168 | e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN
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(
178 self.pg1.remote_hosts[2].ip4,
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
185 tun_ecn.add_vpp_config()
186 # IPv4 transport that sets a fixed DSCP in the encap and copies
188 tun = VppIpIpTunInterface(
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,
198 # array of all the tunnels
199 tuns = [tun_dscp, tun_dscp_ecn, tun_ecn, tun]
201 # addresses for prefixes routed via each tunnel
202 a4s = ["" for i in range(len(tuns))]
203 a6s = ["" for i in range(len(tuns))]
205 # IP headers with each combination of DSCp/ECN tested
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),
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),
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
227 # prefix for route / destination address for packets
228 a4s[i] = "130.67.%d.0" % i
229 a6s[i] = "dead:%d::" % i
231 # Add IPv4 and IPv6 routes via tunnel interface
232 ip4_via_tunnel = VppIpRoute(
240 proto=FibPathProto.FIB_PATH_NH_PROTO_IP4,
244 ip4_via_tunnel.add_vpp_config()
246 ip6_via_tunnel = VppIpRoute(
252 "::", t.sw_if_index, proto=FibPathProto.FIB_PATH_NH_PROTO_IP6
256 ip6_via_tunnel.add_vpp_config()
262 # tun_dscp copies only the dscp
263 # expected TC values are thus only the DCSP value is present from the
265 exp_tcs = [dscp, dscp, 0, 0xFC]
267 IP(src=self.pg0.local_ip4, dst=tun_dscp.dst, tos=tc) for tc in exp_tcs
270 IP(src=self.pg0.local_ip4, dst=tun_dscp.dst, proto="ipv6", id=0, tos=tc)
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)
279 # tun_dscp_ecn copies the dscp and the ecn
280 exp_tcs = [dscp, dscp_ecn, ecn, 0xFF]
282 IP(src=self.pg0.local_ip4, dst=tun_dscp_ecn.dst, tos=tc) for tc in exp_tcs
285 IP(src=self.pg0.local_ip4, dst=tun_dscp_ecn.dst, proto="ipv6", id=0, tos=tc)
289 self.verify_ip4ip4_encaps(a4s[1], p_ip4s, p_ip44_encaps)
290 self.verify_ip6ip4_encaps(a6s[1], p_ip6s, p_ip64_encaps)
292 # tun_ecn copies only the ecn and always sets DF
293 exp_tcs = [0, ecn, ecn, ecn]
295 IP(src=self.pg0.local_ip4, dst=tun_ecn.dst, flags="DF", tos=tc)
300 src=self.pg0.local_ip4,
310 self.verify_ip4ip4_encaps(a4s[2], p_ip4s, p_ip44_encaps)
311 self.verify_ip6ip4_encaps(a6s[2], p_ip6s, p_ip64_encaps)
313 # tun sets a fixed dscp and copies DF
314 fixed_dscp = tun.dscp << 2
315 flags = ["DF", 0, 0, 0]
317 IP(src=self.pg0.local_ip4, dst=tun.dst, flags=f, tos=fixed_dscp)
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))
325 self.verify_ip4ip4_encaps(a4s[3], p_ip4s, p_ip44_encaps)
326 self.verify_ip6ip4_encaps(a6s[3], p_ip6s, p_ip64_encaps)
331 n_packets_decapped = 0
332 self.p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
334 # IPv4 tunnel to IPv4
335 tcs = [0, dscp, dscp_ecn, ecn]
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]
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
347 rx = self.send_and_expect(self.pg1, p4 * N_PACKETS, self.pg0)
348 n_packets_decapped += N_PACKETS
350 self.validate(p[1], p4_reply)
351 self.assert_packet_checksums_valid(p)
353 err = self.statistics.get_err_counter("/err/ipip4-input/packets decapsulated")
354 self.assertEqual(err, n_packets_decapped)
356 # tun_ecn copies the ECN bits from the encap to the inner
358 IP(src=tun_ecn.dst, dst=self.pg0.local_ip4, tos=tc) for tc in tcs
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
367 rx = self.send_and_expect(self.pg1, p4 * N_PACKETS, self.pg0)
368 n_packets_decapped += N_PACKETS
370 self.validate(p[1], p4_reply)
371 self.assert_packet_checksums_valid(p)
373 err = self.statistics.get_err_counter("/err/ipip4-input/packets decapsulated")
374 self.assertEqual(err, n_packets_decapped)
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
385 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
386 n_packets_decapped += N_PACKETS
388 self.validate(p[1], p6_reply)
389 self.assert_packet_checksums_valid(p)
391 err = self.statistics.get_err_counter("/err/ipip4-input/packets decapsulated")
392 self.assertEqual(err, n_packets_decapped)
394 # IPv4 tunnel to IPv6
395 # tun_ecn copies the ECN bits from the encap to the inner
397 IP(src=tun_ecn.dst, dst=self.pg0.local_ip4, tos=tc) for tc in tcs
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
407 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
408 n_packets_decapped += N_PACKETS
410 self.validate(p[1], p6_reply)
411 self.assert_packet_checksums_valid(p)
413 err = self.statistics.get_err_counter("/err/ipip4-input/packets decapsulated")
414 self.assertEqual(err, n_packets_decapped)
417 # Fragmentation / Reassembly and Re-fragmentation
419 rv = self.vapi.ip_reassembly_enable_disable(
420 sw_if_index=self.pg1.sw_if_index, enable_ip4=1
423 self.vapi.ip_reassembly_set(
425 max_reassemblies=1000,
426 max_reassembly_length=1000,
427 expire_walk_interval_ms=10000,
431 # Send lots of fragments, verify reassembled packet
432 frags, p4_reply = self.generate_ip4_frags(3131, 1400)
434 for i in range(0, 1000):
436 self.pg1.add_stream(f)
437 self.pg_enable_capture()
439 rx = self.pg0.get_capture(1000)
440 n_packets_decapped += 1000
443 self.validate(p[1], p4_reply)
445 err = self.statistics.get_err_counter("/err/ipip4-input/packets decapsulated")
446 self.assertEqual(err, n_packets_decapped)
450 for i in range(1, 90):
451 frags, p4_reply = self.generate_ip4_frags(i * 100, 1000)
454 self.pg_enable_capture()
455 self.pg1.add_stream(f)
457 rx = self.pg0.get_capture(89)
460 self.validate(p[1], r[i])
463 # Now try with re-fragmentation
465 # Send fragments to tunnel head-end, for the tunnel head end
466 # to reassemble and then refragment
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)
473 rx = self.pg0.get_capture(6)
474 reass_pkt = reassemble4(rx)
476 self.validate(reass_pkt, p4_reply)
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)
483 rx = self.pg0.get_capture(2)
484 reass_pkt = reassemble4(rx)
486 self.validate(reass_pkt, p4_reply)
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])
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)
497 rx = self.send_and_expect(self.pg0, p4 * 15, self.pg1, 30)
500 inners.append(p[IP].payload)
501 reass_pkt = reassemble4(inners)
503 self.assert_packet_checksums_valid(p)
504 self.assertEqual(p[IP].ttl, 63)
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)
512 def test_ipip_vrf_create(self):
513 """ipip create / delete interface VRF test"""
515 t = VppIpTable(self, 20)
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)
521 def payload(self, len):
524 def test_mipip4(self):
525 """p2mp IPv4 tunnel Tests"""
527 for itf in self.pg_interfaces[:2]:
529 # one underlay nh for each overlay/tunnel peer
531 itf.generate_remote_hosts(4)
532 itf.configure_ipv4_neighbors()
535 # Create an p2mo IPIP tunnel.
537 # - assign an IP Addres
538 # - Add a route via the tunnel
540 ipip_if = VppIpIpTunInterface(
545 mode=(VppEnum.vl_api_tunnel_mode_t.TUNNEL_API_MODE_MP),
547 ipip_if.add_vpp_config()
550 ipip_if.generate_remote_hosts(4)
552 self.logger.info(self.vapi.cli("sh adj"))
553 self.logger.info(self.vapi.cli("sh ip fib"))
556 # ensure we don't match to the tunnel if the source address
559 # tx = self.create_tunnel_stream_4o4(self.pg0,
562 # self.pg0.local_ip4,
563 # self.pg0.remote_ip4)
564 # self.send_and_assert_no_replies(self.pg0, tx)
569 for ii in range(1, 4):
570 route_addr = "4.4.4.%d" % ii
573 # route traffic via the peer
575 route_via_tun = VppIpRoute(
579 [VppRoutePath(ipip_if._remote_hosts[ii].ip4, ipip_if.sw_if_index)],
581 route_via_tun.add_vpp_config()
584 # Add a TEIB entry resolves the peer
589 ipip_if._remote_hosts[ii].ip4,
590 itf._remote_hosts[ii].ip4,
592 teib.add_vpp_config()
594 self.vapi.cli("sh adj nbr ipip0 %s" % ipip_if._remote_hosts[ii].ip4)
598 # Send a packet stream that is routed into the tunnel
599 # - packets are IPIP encapped
602 IP(dst=route_addr, src="5.5.5.5")
603 / UDP(sport=1234, dport=1234)
607 (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / inner)
611 rxs = self.send_and_expect(self.pg0, tx_e, itf)
614 self.assertEqual(rx[IP].src, itf.local_ip4)
615 self.assertEqual(rx[IP].dst, itf._remote_hosts[ii].ip4)
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)
628 self.logger.info(self.vapi.cli("sh ipip tunnel-hash"))
629 rx = self.send_and_expect(self.pg0, tx_i, self.pg0)
632 # delete and re-add the TEIB
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)
638 teib.add_vpp_config()
639 rx = self.send_and_expect(self.pg0, tx_e, itf)
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)
646 # we can also send to the peer's address
649 IP(dst=teib.peer, src="5.5.5.5")
650 / UDP(sport=1234, dport=1234)
654 (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / inner)
658 rxs = self.send_and_expect(self.pg0, tx_e, itf)
661 # with all of the peers in place, swap the ip-table of
664 table = VppIpTable(self, 2)
665 table.add_vpp_config()
667 ipip_if.unconfig_ip4()
668 ipip_if.set_table_ip4(self.table.table_id)
672 # we should still be able to reach the peers from the new table
675 IP(dst=teib.peer, src="5.5.5.5")
676 / UDP(sport=1234, dport=1234)
680 (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / inner)
684 rxs = self.send_and_expect(self.pg2, tx_e, itf)
687 ipip_if.unconfig_ip4()
688 ipip_if.set_table_ip4(0)
691 class TestIPIP6(VppTestCase):
692 """IPIP6 Test Case"""
696 super(TestIPIP6, cls).setUpClass()
697 cls.create_pg_interfaces(range(2))
698 cls.interfaces = list(cls.pg_interfaces)
701 def tearDownClass(cls):
702 super(TestIPIP6, cls).tearDownClass()
705 super(TestIPIP6, self).setUp()
706 for i in self.interfaces:
716 if not self.vpp_dead:
717 self.destroy_tunnel()
718 for i in self.pg_interfaces:
722 super(TestIPIP6, self).tearDown()
724 def setup_tunnel(self):
726 rv = ipip_add_tunnel(self, self.pg0.local_ip6, self.pg1.remote_ip6)
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
735 # Add IPv4 and IPv6 routes via tunnel interface
736 ip4_via_tunnel = VppIpRoute(
742 "0.0.0.0", sw_if_index, proto=FibPathProto.FIB_PATH_NH_PROTO_IP4
746 ip4_via_tunnel.add_vpp_config()
748 ip6_via_tunnel = VppIpRoute(
752 [VppRoutePath("::", sw_if_index, proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)],
754 ip6_via_tunnel.add_vpp_config()
756 self.tunnel_ip6_via_tunnel = ip6_via_tunnel
757 self.tunnel_ip4_via_tunnel = ip4_via_tunnel
759 def destroy_tunnel(self):
761 self.tunnel_ip4_via_tunnel.remove_vpp_config()
762 self.tunnel_ip6_via_tunnel.remove_vpp_config()
764 rv = self.vapi.ipip_del_tunnel(sw_if_index=self.tunnel_if_index)
766 def validate(self, rx, expected):
767 self.assertEqual(rx, expected.__class__(expected))
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)
775 / IPv6(src=self.pg1.remote_ip6, dst=self.pg0.local_ip6)
776 / IPv6ExtHdrFragment()
780 frags = fragment6(outer_ip6, fragment_size)
781 p6_reply = p_ip6 / p_payload
783 return frags, p6_reply
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")
791 / IPv6(src=self.pg1.remote_ip6, dst=self.pg0.local_ip6)
792 / IPv6ExtHdrFragment()
796 frags = fragment6(outer_ip6, fragment_size)
799 IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6, hlim=63)
804 return frags, p6_reply
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)
814 # IPv6 in to IPv6 tunnel
815 p6 = p_ether / p_ip6 / p_payload
817 IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6, hlim=64)
821 p6_reply[1].hlim -= 1
822 rx = self.send_and_expect(self.pg0, p6 * 11, self.pg1)
824 self.validate(p[1], p6_reply)
826 # IPv4 in to IPv6 tunnel
827 p4 = p_ether / p_ip4 / p_payload
829 IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6, hlim=64)
834 rx = self.send_and_expect(self.pg0, p4 * 11, self.pg1)
836 self.validate(p[1], p4_reply)
838 def test_decap(self):
839 """ip{v4,v6} over ip6 test decap"""
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)
847 # IPv6 tunnel to IPv4
851 / IPv6(src=self.pg1.remote_ip6, dst=self.pg0.local_ip6)
855 p4_reply = p_ip4 / p_payload
857 rx = self.send_and_expect(self.pg1, p4 * 11, self.pg0)
859 self.validate(p[1], p4_reply)
861 # IPv6 tunnel to IPv6
862 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6)
865 / IPv6(src=self.pg1.remote_ip6, dst=self.pg0.local_ip6)
869 p6_reply = p_ip6 / p_payload
871 rx = self.send_and_expect(self.pg1, p6 * 11, self.pg0)
873 self.validate(p[1], p6_reply)
875 def verify_ip4ip6_encaps(self, a, p_ip4s, p_ip6_encaps):
876 for i, p_ip4 in enumerate(p_ip4s):
878 p4 = self.p_ether / p_ip4 / self.p_payload
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)
884 self.validate(p[1], p6_reply)
885 self.assert_packet_checksums_valid(p)
887 def verify_ip6ip6_encaps(self, a, p_ip6s, p_ip6_encaps):
888 for i, p_ip6 in enumerate(p_ip6s):
890 p6 = self.p_ether / p_ip6 / self.p_payload
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)
896 self.validate(p[1], p6_reply)
897 self.assert_packet_checksums_valid(p)
899 def test_ipip6(self):
900 """ip{v4,v6} over ip6 test"""
903 self.destroy_tunnel()
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)
912 # create a TOS byte by shifting a DSCP code point 2 bits. those 2 bits
914 dscp = d.IP_API_DSCP_AF31 << 2
916 dscp_ecn = d.IP_API_DSCP_AF31 << 2 | ecn
918 # IPv4 transport that copies the DCSP from the payload
919 tun_dscp = VppIpIpTunInterface(
923 self.pg1.remote_hosts[0].ip6,
924 flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP,
926 tun_dscp.add_vpp_config()
927 # IPv4 transport that copies the DCSP and ECN from the payload
928 tun_dscp_ecn = VppIpIpTunInterface(
932 self.pg1.remote_hosts[1].ip6,
934 e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP
935 | e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN
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(
945 self.pg1.remote_hosts[2].ip6,
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
952 tun_ecn.add_vpp_config()
953 # IPv4 transport that sets a fixed DSCP in the encap and copies
955 tun = VppIpIpTunInterface(
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,
965 # array of all the tunnels
966 tuns = [tun_dscp, tun_dscp_ecn, tun_ecn, tun]
968 # addresses for prefixes routed via each tunnel
969 a4s = ["" for i in range(len(tuns))]
970 a6s = ["" for i in range(len(tuns))]
972 # IP headers for inner packets with each combination of DSCp/ECN tested
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),
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),
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
994 # prefix for route / destination address for packets
995 a4s[i] = "130.67.%d.0" % i
996 a6s[i] = "dead:%d::" % i
998 # Add IPv4 and IPv6 routes via tunnel interface
999 ip4_via_tunnel = VppIpRoute(
1007 proto=FibPathProto.FIB_PATH_NH_PROTO_IP4,
1011 ip4_via_tunnel.add_vpp_config()
1013 ip6_via_tunnel = VppIpRoute(
1019 "::", t.sw_if_index, proto=FibPathProto.FIB_PATH_NH_PROTO_IP6
1023 ip6_via_tunnel.add_vpp_config()
1029 # tun_dscp copies only the dscp
1030 # expected TC values are thus only the DCSP value is present from the
1032 exp_tcs = [dscp, dscp, 0, 0xFC]
1034 IPv6(src=self.pg0.local_ip6, dst=tun_dscp.dst, tc=tc) for tc in exp_tcs
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)
1042 # tun_dscp_ecn copies the dscp and the ecn
1043 exp_tcs = [dscp, dscp_ecn, ecn, 0xFF]
1045 IPv6(src=self.pg0.local_ip6, dst=tun_dscp_ecn.dst, tc=tc) for tc in exp_tcs
1048 self.verify_ip4ip6_encaps(a4s[1], p_ip4s, p_ip6_encaps)
1049 self.verify_ip6ip6_encaps(a6s[1], p_ip6s, p_ip6_encaps)
1051 # tun_ecn copies only the ecn and always sets DF
1052 exp_tcs = [0, ecn, ecn, ecn]
1054 IPv6(src=self.pg0.local_ip6, dst=tun_ecn.dst, tc=tc) for tc in exp_tcs
1057 self.verify_ip4ip6_encaps(a4s[2], p_ip4s, p_ip6_encaps)
1058 self.verify_ip6ip6_encaps(a6s[2], p_ip6s, p_ip6_encaps)
1060 # tun sets a fixed dscp
1061 fixed_dscp = tun.dscp << 2
1063 IPv6(src=self.pg0.local_ip6, dst=tun.dst, tc=fixed_dscp)
1064 for i in range(len(p_ip4s))
1067 self.verify_ip4ip6_encaps(a4s[3], p_ip4s, p_ip6_encaps)
1068 self.verify_ip6ip6_encaps(a6s[3], p_ip6s, p_ip6_encaps)
1073 n_packets_decapped = self.statistics.get_err_counter(
1074 "/err/ipip6-input/packets decapsulated"
1077 self.p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
1079 # IPv6 tunnel to IPv4
1080 tcs = [0, dscp, dscp_ecn, ecn]
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]
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
1092 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
1093 n_packets_decapped += N_PACKETS
1095 self.validate(p[1], p4_reply)
1096 self.assert_packet_checksums_valid(p)
1098 err = self.statistics.get_err_counter("/err/ipip6-input/packets decapsulated")
1099 self.assertEqual(err, n_packets_decapped)
1101 # tun_ecn copies the ECN bits from the encap to the inner
1103 IPv6(src=tun_ecn.dst, dst=self.pg0.local_ip6, tc=tc) for tc in tcs
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
1112 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
1113 n_packets_decapped += N_PACKETS
1115 self.validate(p[1], p4_reply)
1116 self.assert_packet_checksums_valid(p)
1118 err = self.statistics.get_err_counter("/err/ipip6-input/packets decapsulated")
1119 self.assertEqual(err, n_packets_decapped)
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
1130 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
1131 n_packets_decapped += N_PACKETS
1133 self.validate(p[1], p6_reply)
1134 self.assert_packet_checksums_valid(p)
1136 err = self.statistics.get_err_counter("/err/ipip6-input/packets decapsulated")
1137 self.assertEqual(err, n_packets_decapped)
1139 # IPv6 tunnel to IPv6
1140 # tun_ecn copies the ECN bits from the encap to the inner
1142 IPv6(src=tun_ecn.dst, dst=self.pg0.local_ip6, tc=tc) for tc in tcs
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
1152 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
1153 n_packets_decapped += N_PACKETS
1155 self.validate(p[1], p6_reply)
1156 self.assert_packet_checksums_valid(p)
1158 err = self.statistics.get_err_counter("/err/ipip6-input/packets decapsulated")
1159 self.assertEqual(err, n_packets_decapped)
1161 def test_frag(self):
1162 """ip{v4,v6} over ip6 test frag"""
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)
1170 # Fragmentation / Reassembly and Re-fragmentation
1172 rv = self.vapi.ip_reassembly_enable_disable(
1173 sw_if_index=self.pg1.sw_if_index, enable_ip6=1
1176 self.vapi.ip_reassembly_set(
1178 max_reassemblies=1000,
1179 max_reassembly_length=1000,
1180 expire_walk_interval_ms=10000,
1184 # Send lots of fragments, verify reassembled packet
1185 before_cnt = self.statistics.get_err_counter(
1186 "/err/ipip6-input/packets decapsulated"
1188 frags, p6_reply = self.generate_ip6_frags(3131, 1400)
1190 for i in range(0, 1000):
1192 self.pg1.add_stream(f)
1193 self.pg_enable_capture()
1195 rx = self.pg0.get_capture(1000)
1198 self.validate(p[1], p6_reply)
1200 cnt = self.statistics.get_err_counter("/err/ipip6-input/packets decapsulated")
1201 self.assertEqual(cnt, before_cnt + 1000)
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)
1210 self.pg_enable_capture()
1211 self.pg1.add_stream(f)
1213 rx = self.pg0.get_capture(80)
1216 self.validate(p[1], r[i])
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])
1223 # IPv6 in to IPv6 tunnel
1224 p_payload = UDP(sport=1234, dport=1234) / self.payload(1300)
1226 p6 = p_ether / p_ip6 / p_payload
1228 IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6, hlim=63)
1232 p6_reply[1].hlim -= 1
1233 self.pg_enable_capture()
1234 self.pg0.add_stream(p6)
1236 rx = self.pg1.get_capture(2)
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)
1244 # Now try with re-fragmentation
1246 # Send large fragments to tunnel head-end, for the tunnel head end
1247 # to reassemble and then refragment out the tunnel again.
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)
1255 rx = self.pg1.get_capture(7)
1256 f = [p[1] for p in rx]
1257 reass_pkt = defragment6(f)
1259 self.validate(reass_pkt, p6_reply)
1261 def test_ip6_mpls_frag(self):
1262 """Test fragmenting IPv6 over MPLS"""
1264 # IPv6 packets must be locally generated to be fragmented
1265 # the use of tunnel encaps
1266 tun_dst = VppIpRoute(
1272 self.pg1.remote_ip6, self.pg1.sw_if_index, labels=[VppMplsLabel(32)]
1277 tun = VppIpIpTunInterface(
1278 self, self.pg0, self.pg0.local_ip6, "1000::1"
1285 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [2000, 0, 0, 0])
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)
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)
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)
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)
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)
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)
1322 def test_ipip_vrf_create(self):
1323 """ipip create / delete interface VRF test"""
1325 t = VppIpTable(self, 20)
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)
1331 def payload(self, len):
1335 class TestIPIPMPLS(VppTestCase):
1336 """MPLS Test Case"""
1339 def setUpClass(cls):
1340 super(TestIPIPMPLS, cls).setUpClass()
1341 cls.create_pg_interfaces(range(2))
1342 cls.interfaces = list(cls.pg_interfaces)
1345 def tearDownClass(cls):
1346 super(TestIPIPMPLS, cls).tearDownClass()
1349 super(TestIPIPMPLS, self).setUp()
1350 for i in self.interfaces:
1359 super(TestIPIPMPLS, self).tearDown()
1361 for i in self.pg_interfaces:
1366 def test_mpls(self):
1367 """MPLS over ip{6,4} test"""
1369 tbl = VppMplsTable(self, 0)
1370 tbl.add_vpp_config()
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)
1377 tun4 = VppIpIpTunInterface(
1378 self, self.pg1, self.pg1.local_ip4, self.pg1.remote_ip4
1385 tun6 = VppIpIpTunInterface(
1386 self, self.pg1, self.pg1.local_ip6, self.pg1.remote_ip6
1392 # ip routes into the tunnels with output labels
1399 tun4.remote_ip4, tun4.sw_if_index, labels=[VppMplsLabel(44)]
1409 tun6.remote_ip6, tun6.sw_if_index, labels=[VppMplsLabel(66)]
1414 # deag MPLS routes from the tunnel
1416 self, 44, 1, [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index)]
1422 [VppRoutePath(self.pg0.remote_ip6, self.pg0.sw_if_index)],
1423 eos_proto=f.FIB_PATH_NH_PROTO_IP6,
1429 p4 = self.p_ether / IP(src="2.2.2.2", dst="1.1.1.1") / self.p_payload
1431 rxs = self.send_and_expect(self.pg0, p4 * N_PACKETS, self.pg1)
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")
1441 p6 = self.p_ether / IPv6(src="2::2", dst="1::1") / self.p_payload
1443 rxs = self.send_and_expect(self.pg0, p6 * N_PACKETS, self.pg1)
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")
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")
1464 rxs = self.send_and_expect(self.pg1, p4 * N_PACKETS, self.pg0)
1467 self.assertEqual(rx[IP].src, "1.1.1.1")
1468 self.assertEqual(rx[IP].dst, "2.2.2.2")
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")
1478 rxs = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0)
1481 self.assertEqual(rx[IPv6].src, "1::1")
1482 self.assertEqual(rx[IPv6].dst, "2::2")
1488 if __name__ == "__main__":
1489 unittest.main(testRunner=VppTestRunner)