summaryrefslogtreecommitdiffstats
path: root/test/test_ipip.py
diff options
context:
space:
mode:
authorOle Troan <ot@cisco.com>2018-09-19 12:38:51 +0200
committerNeale Ranns <nranns@cisco.com>2018-09-27 08:47:40 +0000
commit282093f1fe783b5d36a014d4495995cd64e2e3fb (patch)
tree09e6536da14c262d33991383e408b2c35d361b4a /test/test_ipip.py
parente23edac38ec239115689fe252b4b41a3556f6280 (diff)
IPIP and IPv6 fragmentation
- Error where ICMPv6 error code doesn't reset VLIB_TX = -1 Leading to crash for ICMP generated on tunnelled packets - Missed setting VNET_BUFFER_F_LOCALLY_ORIGINATED, so IP in IPv6 packets never got fragmented. - Add support for fragmentation of buffer chains. - Remove support for inner fragmentation in frag code itself. Change-Id: If9a97301b7e35ca97ffa5c0fada2b9e7e7dbfb27 Signed-off-by: Ole Troan <ot@cisco.com>
Diffstat (limited to 'test/test_ipip.py')
-rw-r--r--test/test_ipip.py225
1 files changed, 206 insertions, 19 deletions
diff --git a/test/test_ipip.py b/test/test_ipip.py
index efaaf52539e..b7a0179957b 100644
--- a/test/test_ipip.py
+++ b/test/test_ipip.py
@@ -2,8 +2,8 @@
"""IP{4,6} over IP{v,6} tunnel functional tests"""
import unittest
-from scapy.layers.inet6 import IPv6, Ether, IP, UDP
-from scapy.all import fragment, RandShort
+from scapy.layers.inet6 import IPv6, Ether, IP, UDP, IPv6ExtHdrFragment
+from scapy.all import fragment, fragment6, RandShort, defragment6
from framework import VppTestCase, VppTestRunner
from vpp_ip import DpoProto
from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable
@@ -17,6 +17,7 @@ IPIP tests.
"""
+# Replace by deframent from scapy.
def reassemble(listoffragments):
buffer = StringIO.StringIO()
first = listoffragments[0]
@@ -61,7 +62,7 @@ class TestIPIP(VppTestCase):
def validate(self, rx, expected):
self.assertEqual(rx, expected.__class__(str(expected)))
- def generate_frags(self, payload_length, fragment_size):
+ def generate_ip4_frags(self, payload_length, fragment_size):
p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
p_payload = UDP(sport=1234, dport=1234) / self.payload(payload_length)
p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
@@ -171,7 +172,7 @@ class TestIPIP(VppTestCase):
enable_ip4=1)
# Send lots of fragments, verify reassembled packet
- frags, p4_reply = self.generate_frags(3131, 1400)
+ frags, p4_reply = self.generate_ip4_frags(3131, 1400)
f = []
for i in range(0, 1000):
f.extend(frags)
@@ -190,7 +191,7 @@ class TestIPIP(VppTestCase):
f = []
r = []
for i in range(1, 90):
- frags, p4_reply = self.generate_frags(i * 100, 1000)
+ frags, p4_reply = self.generate_ip4_frags(i * 100, 1000)
f.extend(frags)
r.extend(p4_reply)
self.pg_enable_capture()
@@ -208,7 +209,7 @@ class TestIPIP(VppTestCase):
# to reassemble and then refragment
#
self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [576, 0, 0, 0])
- frags, p4_reply = self.generate_frags(3123, 1200)
+ frags, p4_reply = self.generate_ip4_frags(3123, 1200)
self.pg_enable_capture()
self.pg1.add_stream(frags)
self.pg_start()
@@ -219,7 +220,7 @@ class TestIPIP(VppTestCase):
self.validate(reass_pkt, p4_reply)
self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [1600, 0, 0, 0])
- frags, p4_reply = self.generate_frags(3123, 1200)
+ frags, p4_reply = self.generate_ip4_frags(3123, 1200)
self.pg_enable_capture()
self.pg1.add_stream(frags)
self.pg_start()
@@ -229,20 +230,66 @@ class TestIPIP(VppTestCase):
p4_reply.id = 512
self.validate(reass_pkt, p4_reply)
- def test_ipip6(self):
- """ ip{v4,v6} over ip6 test """
- p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
- p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP')
- p_ip4 = IP(src="1.2.3.4", dst="130.67.0.1", tos=42)
- p_payload = UDP(sport=1234, dport=1234)
+ def test_ipip_create(self):
+ """ ipip create / delete interface test """
+ rv = self.vapi.ipip_add_tunnel(
+ src_address=inet_pton(AF_INET, '1.2.3.4'),
+ dst_address=inet_pton(AF_INET, '2.3.4.5'), is_ipv6=0)
+ sw_if_index = rv.sw_if_index
+ self.vapi.ipip_del_tunnel(sw_if_index)
+
+ def test_ipip_vrf_create(self):
+ """ ipip create / delete interface VRF test """
+
+ t = VppIpTable(self, 20)
+ t.add_vpp_config()
+ rv = self.vapi.ipip_add_tunnel(
+ src_address=inet_pton(AF_INET, '1.2.3.4'),
+ dst_address=inet_pton(AF_INET, '2.3.4.5'), is_ipv6=0,
+ table_id=20)
+ sw_if_index = rv.sw_if_index
+ self.vapi.ipip_del_tunnel(sw_if_index)
+
+ def payload(self, len):
+ return 'x' * len
+
+class TestIPIP6(VppTestCase):
+ """ IPIP6 Test Case """
+
+ @classmethod
+ def setUpClass(cls):
+ super(TestIPIP6, cls).setUpClass()
+ cls.create_pg_interfaces(range(2))
+ cls.interfaces = list(cls.pg_interfaces)
+
+ def setUp(self):
+ for i in self.interfaces:
+ i.admin_up()
+ i.config_ip4()
+ i.config_ip6()
+ i.disable_ipv6_ra()
+ i.resolve_arp()
+ i.resolve_ndp()
+ self.setup_tunnel()
+
+ def tearDown(self):
+ if not self.vpp_dead:
+ self.destroy_tunnel()
+ for i in self.pg_interfaces:
+ i.unconfig_ip4()
+ i.unconfig_ip6()
+ i.admin_down()
+ super(TestIPIP6, self).tearDown()
+
+ def setup_tunnel(self):
# IPv6 transport
rv = self.vapi.ipip_add_tunnel(
src_address=self.pg0.local_ip6n,
dst_address=self.pg1.remote_ip6n, tc_tos=255)
sw_if_index = rv.sw_if_index
-
+ self.tunnel_if_index = sw_if_index
self.vapi.sw_interface_set_flags(sw_if_index, 1)
self.vapi.sw_interface_set_unnumbered(
ip_sw_if_index=self.pg0.sw_if_index, sw_if_index=sw_if_index)
@@ -262,12 +309,57 @@ class TestIPIP(VppTestCase):
proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1)
ip6_via_tunnel.add_vpp_config()
- # Encapsulation
+ self.tunnel_ip6_via_tunnel = ip6_via_tunnel
+ self.tunnel_ip4_via_tunnel = ip4_via_tunnel
+
+ def destroy_tunnel(self):
+ # IPv6 transport
+ self.tunnel_ip4_via_tunnel.remove_vpp_config()
+ self.tunnel_ip6_via_tunnel.remove_vpp_config()
+
+ rv = self.vapi.ipip_del_tunnel(sw_if_index=self.tunnel_if_index)
+
+ def validate(self, rx, expected):
+ self.assertEqual(rx, expected.__class__(str(expected)))
+
+ def generate_ip6_frags(self, payload_length, fragment_size):
+ p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
+ p_payload = UDP(sport=1234, dport=1234) / self.payload(payload_length)
+ p_ip6 = IPv6(src="1::1", dst=self.pg0.remote_ip6)
+ outer_ip6 = (p_ether / IPv6(src=self.pg1.remote_ip6,
+ dst=self.pg0.local_ip6) /
+ IPv6ExtHdrFragment() / p_ip6 / p_payload)
+ frags = fragment6(outer_ip6, fragment_size)
+ p6_reply = (p_ip6 / p_payload)
+ p6_reply.hlim -= 1
+ return frags, p6_reply
+
+ def generate_ip6_hairpin_frags(self, payload_length, fragment_size):
+ p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
+ p_payload = UDP(sport=1234, dport=1234) / self.payload(payload_length)
+ p_ip6 = IPv6(src="1::1", dst="dead::1")
+ outer_ip6 = (p_ether / IPv6(src=self.pg1.remote_ip6,
+ dst=self.pg0.local_ip6) /
+ IPv6ExtHdrFragment() / p_ip6 / p_payload)
+ frags = fragment6(outer_ip6, fragment_size)
+ p_ip6.hlim -= 1
+ p6_reply = (IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6,
+ hlim=63) / p_ip6 / p_payload)
+
+ return frags, p6_reply
+
+ def test_encap(self):
+ """ ip{v4,v6} over ip6 test encap """
+ p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
+ p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP')
+ p_ip4 = IP(src="1.2.3.4", dst="130.67.0.1", tos=42)
+ p_payload = UDP(sport=1234, dport=1234)
+ # Encapsulation
# IPv6 in to IPv6 tunnel
p6 = (p_ether / p_ip6 / p_payload)
p6_reply = (IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6,
- hlim=63, tc=42) /
+ hlim=64, tc=42) /
p_ip6 / p_payload)
p6_reply[1].hlim -= 1
rx = self.send_and_expect(self.pg0, p6*11, self.pg1)
@@ -277,19 +369,24 @@ class TestIPIP(VppTestCase):
# IPv4 in to IPv6 tunnel
p4 = (p_ether / p_ip4 / p_payload)
p4_reply = (IPv6(src=self.pg0.local_ip6,
- dst=self.pg1.remote_ip6, hlim=63, tc=42) /
+ dst=self.pg1.remote_ip6, hlim=64, tc=42) /
p_ip4 / p_payload)
p4_reply[1].ttl -= 1
rx = self.send_and_expect(self.pg0, p4*11, self.pg1)
for p in rx:
self.validate(p[1], p4_reply)
- # Decapsulation
+ def test_decap(self):
+ """ ip{v4,v6} over ip6 test decap """
p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
+ p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP')
+ p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
+ p_payload = UDP(sport=1234, dport=1234)
+ # Decapsulation
# IPv6 tunnel to IPv4
- p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
+
p4 = (p_ether / IPv6(src=self.pg1.remote_ip6,
dst=self.pg0.local_ip6) / p_ip4 / p_payload)
p4_reply = (p_ip4 / p_payload)
@@ -308,6 +405,96 @@ class TestIPIP(VppTestCase):
for p in rx:
self.validate(p[1], p6_reply)
+ def test_frag(self):
+ """ ip{v4,v6} over ip6 test frag """
+
+ p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
+ p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP')
+ p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4)
+ p_payload = UDP(sport=1234, dport=1234)
+
+ #
+ # Fragmentation / Reassembly and Re-fragmentation
+ #
+ rv = self.vapi.ip_reassembly_enable_disable(
+ sw_if_index=self.pg1.sw_if_index,
+ enable_ip6=1)
+
+ # Send lots of fragments, verify reassembled packet
+ before_cnt = self.statistics.get_counter(
+ '/err/ipip6-input/packets decapsulated')
+ frags, p6_reply = self.generate_ip6_frags(3131, 1400)
+ f = []
+ for i in range(0, 1000):
+ f.extend(frags)
+ self.pg1.add_stream(f)
+ self.pg_enable_capture()
+ self.pg_start()
+ rx = self.pg0.get_capture(1000)
+
+ for p in rx:
+ self.validate(p[1], p6_reply)
+
+ cnt = self.statistics.get_counter(
+ '/err/ipip6-input/packets decapsulated')
+ self.assertEqual(cnt, before_cnt + 1000)
+
+ f = []
+ r = []
+ # TODO: Check out why reassembly of atomic fragments don't work
+ for i in range(10, 90):
+ frags, p6_reply = self.generate_ip6_frags(i * 100, 1000)
+ f.extend(frags)
+ r.extend(p6_reply)
+ self.pg_enable_capture()
+ self.pg1.add_stream(f)
+ self.pg_start()
+ rx = self.pg0.get_capture(80)
+ i = 0
+ for p in rx:
+ self.validate(p[1], r[i])
+ i += 1
+
+ # Simple fragmentation
+ p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
+ self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1280, 0, 0, 0])
+
+ # IPv6 in to IPv6 tunnel
+ p_payload = UDP(sport=1234, dport=1234) / self.payload(1300)
+
+ p6 = (p_ether / p_ip6 / p_payload)
+ p6_reply = (IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6,
+ hlim=63, tc=42) /
+ p_ip6 / p_payload)
+ p6_reply[1].hlim -= 1
+ self.pg_enable_capture()
+ self.pg0.add_stream(p6)
+ self.pg_start()
+ rx = self.pg1.get_capture(2)
+
+ # Scapy defragment doesn't deal well with multiple layers
+ # of samy type / Ethernet header first
+ f = [p[1] for p in rx]
+ reass_pkt = defragment6(f)
+ self.validate(reass_pkt, p6_reply)
+
+ # Now try with re-fragmentation
+ #
+ # Send large fragments to tunnel head-end, for the tunnel head end
+ # to reassemble and then refragment out the tunnel again.
+ # Hair-pinning
+ #
+ self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1280, 0, 0, 0])
+ frags, p6_reply = self.generate_ip6_hairpin_frags(8000, 1200)
+ self.pg_enable_capture()
+ self.pg1.add_stream(frags)
+ self.pg_start()
+ rx = self.pg1.get_capture(7)
+ f = [p[1] for p in rx]
+ reass_pkt = defragment6(f)
+ p6_reply.id = 256
+ self.validate(reass_pkt, p6_reply)
+
def test_ipip_create(self):
""" ipip create / delete interface test """
rv = self.vapi.ipip_add_tunnel(