From de34c35fc73226943538149fae9dbc5cfbdc6e75 Mon Sep 17 00:00:00 2001 From: Klement Sekera Date: Tue, 25 Jun 2019 11:19:22 +0000 Subject: ip: add shallow virtual reassembly functionality Type: feature Change-Id: Ibc8334e26c7e6f6120696c3e313b6e11d73dab99 Signed-off-by: Klement Sekera --- test/test_reassembly.py | 343 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 342 insertions(+), 1 deletion(-) (limited to 'test/test_reassembly.py') diff --git a/test/test_reassembly.py b/test/test_reassembly.py index 407b626e1d2..ee7830e1762 100644 --- a/test/test_reassembly.py +++ b/test/test_reassembly.py @@ -11,7 +11,7 @@ from scapy.packet import Raw from scapy.layers.l2 import Ether, GRE from scapy.layers.inet import IP, UDP, ICMP from scapy.layers.inet6 import HBHOptUnknown, ICMPv6ParamProblem,\ - ICMPv6TimeExceeded, IPv6, IPv6ExtHdrFragment, IPv6ExtHdrHopByHop + ICMPv6TimeExceeded, IPv6, IPv6ExtHdrFragment, IPv6ExtHdrHopByHop from framework import VppTestCase, VppTestRunner from util import ppp, ppc, fragment_rfc791, fragment_rfc8200 from vpp_gre_interface import VppGreInterface @@ -503,6 +503,177 @@ class TestIPv4Reassembly(VppTestCase): self.src_if.assert_nothing_captured() +class TestIPv4SVReassembly(VppTestCase): + """ IPv4 Shallow Virtual Reassembly """ + + @classmethod + def setUpClass(cls): + super(TestIPv4SVReassembly, cls).setUpClass() + + cls.create_pg_interfaces([0, 1]) + cls.src_if = cls.pg0 + cls.dst_if = cls.pg1 + + # setup all interfaces + for i in cls.pg_interfaces: + i.admin_up() + i.config_ip4() + i.resolve_arp() + + def setUp(self): + """ Test setup - force timeout on existing reassemblies """ + super(TestIPv4SVReassembly, self).setUp() + self.vapi.ip_reassembly_enable_disable( + sw_if_index=self.src_if.sw_if_index, enable_ip4=True, + type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL) + self.vapi.ip_reassembly_set( + timeout_ms=0, max_reassemblies=1000, + max_reassembly_length=1000, + type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL, + expire_walk_interval_ms=10) + self.sleep(.25) + self.vapi.ip_reassembly_set( + timeout_ms=1000000, max_reassemblies=1000, + max_reassembly_length=1000, + type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL, + expire_walk_interval_ms=10000) + + def tearDown(self): + super(TestIPv4SVReassembly, self).tearDown() + self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details")) + self.logger.debug(self.vapi.ppcli("show buffers")) + + def test_basic(self): + """ basic reassembly """ + payload_len = 1000 + payload = "" + counter = 0 + while len(payload) < payload_len: + payload += "%u " % counter + counter += 1 + + p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) / + IP(id=1, src=self.src_if.remote_ip4, + dst=self.dst_if.remote_ip4) / + UDP(sport=1234, dport=5678) / + Raw(payload)) + fragments = fragment_rfc791(p, payload_len/4) + + # send fragment #2 - should be cached inside reassembly + self.pg_enable_capture() + self.src_if.add_stream(fragments[1]) + self.pg_start() + self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details")) + self.logger.debug(self.vapi.ppcli("show buffers")) + self.logger.debug(self.vapi.ppcli("show trace")) + self.dst_if.assert_nothing_captured() + + # send fragment #1 - reassembly is finished now and both fragments + # forwarded + self.pg_enable_capture() + self.src_if.add_stream(fragments[0]) + self.pg_start() + self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details")) + self.logger.debug(self.vapi.ppcli("show buffers")) + self.logger.debug(self.vapi.ppcli("show trace")) + c = self.dst_if.get_capture(2) + for sent, recvd in zip([fragments[1], fragments[0]], c): + self.assertEqual(sent[IP].src, recvd[IP].src) + self.assertEqual(sent[IP].dst, recvd[IP].dst) + self.assertEqual(sent[Raw].payload, recvd[Raw].payload) + + # send rest of fragments - should be immediately forwarded + self.pg_enable_capture() + self.src_if.add_stream(fragments[2:]) + self.pg_start() + c = self.dst_if.get_capture(len(fragments[2:])) + for sent, recvd in zip(fragments[2:], c): + self.assertEqual(sent[IP].src, recvd[IP].src) + self.assertEqual(sent[IP].dst, recvd[IP].dst) + self.assertEqual(sent[Raw].payload, recvd[Raw].payload) + + def test_timeout(self): + """ reassembly timeout """ + payload_len = 1000 + payload = "" + counter = 0 + while len(payload) < payload_len: + payload += "%u " % counter + counter += 1 + + p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) / + IP(id=1, src=self.src_if.remote_ip4, + dst=self.dst_if.remote_ip4) / + UDP(sport=1234, dport=5678) / + Raw(payload)) + fragments = fragment_rfc791(p, payload_len/4) + + self.vapi.ip_reassembly_set( + timeout_ms=100, max_reassemblies=1000, + max_reassembly_length=1000, + expire_walk_interval_ms=50, + type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL) + + # send fragments #2 and #1 - should be forwarded + self.pg_enable_capture() + self.src_if.add_stream(fragments[0:2]) + self.pg_start() + self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details")) + self.logger.debug(self.vapi.ppcli("show buffers")) + self.logger.debug(self.vapi.ppcli("show trace")) + c = self.dst_if.get_capture(2) + for sent, recvd in zip([fragments[1], fragments[0]], c): + self.assertEqual(sent[IP].src, recvd[IP].src) + self.assertEqual(sent[IP].dst, recvd[IP].dst) + self.assertEqual(sent[Raw].payload, recvd[Raw].payload) + + # wait for cleanup + self.sleep(.25, "wait before sending rest of fragments") + + # send rest of fragments - shouldn't be forwarded + self.pg_enable_capture() + self.src_if.add_stream(fragments[2:]) + self.pg_start() + self.dst_if.assert_nothing_captured() + + def test_lru(self): + """ reassembly reuses LRU element """ + + self.vapi.ip_reassembly_set( + timeout_ms=1000000, max_reassemblies=1, + max_reassembly_length=1000, + type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL, + expire_walk_interval_ms=10000) + + payload_len = 1000 + payload = "" + counter = 0 + while len(payload) < payload_len: + payload += "%u " % counter + counter += 1 + + packet_count = 10 + + fragments = [f + for i in range(packet_count) + for p in (Ether(dst=self.src_if.local_mac, + src=self.src_if.remote_mac) / + IP(id=i, src=self.src_if.remote_ip4, + dst=self.dst_if.remote_ip4) / + UDP(sport=1234, dport=5678) / + Raw(payload)) + for f in fragment_rfc791(p, payload_len/4)] + + self.pg_enable_capture() + self.src_if.add_stream(fragments) + self.pg_start() + c = self.dst_if.get_capture(len(fragments)) + for sent, recvd in zip(fragments, c): + self.assertEqual(sent[IP].src, recvd[IP].src) + self.assertEqual(sent[IP].dst, recvd[IP].dst) + self.assertEqual(sent[Raw].payload, recvd[Raw].payload) + + class TestIPv4MWReassembly(VppTestCase): """ IPv4 Reassembly (multiple workers) """ worker_config = "workers %d" % worker_count @@ -1304,6 +1475,176 @@ class TestIPv6MWReassembly(VppTestCase): send_if.assert_nothing_captured() +class TestIPv6SVReassembly(VppTestCase): + """ IPv6 Shallow Virtual Reassembly """ + + @classmethod + def setUpClass(cls): + super(TestIPv6SVReassembly, cls).setUpClass() + + cls.create_pg_interfaces([0, 1]) + cls.src_if = cls.pg0 + cls.dst_if = cls.pg1 + + # setup all interfaces + for i in cls.pg_interfaces: + i.admin_up() + i.config_ip6() + i.resolve_ndp() + + def setUp(self): + """ Test setup - force timeout on existing reassemblies """ + super(TestIPv6SVReassembly, self).setUp() + self.vapi.ip_reassembly_enable_disable( + sw_if_index=self.src_if.sw_if_index, enable_ip6=True, + type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL) + self.vapi.ip_reassembly_set( + timeout_ms=0, max_reassemblies=1000, + max_reassembly_length=1000, + type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL, + expire_walk_interval_ms=10, is_ip6=1) + self.sleep(.25) + self.vapi.ip_reassembly_set( + timeout_ms=1000000, max_reassemblies=1000, + max_reassembly_length=1000, + type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL, + expire_walk_interval_ms=10000, is_ip6=1) + + def tearDown(self): + super(TestIPv6SVReassembly, self).tearDown() + self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details")) + self.logger.debug(self.vapi.ppcli("show buffers")) + + def test_basic(self): + """ basic reassembly """ + payload_len = 1000 + payload = "" + counter = 0 + while len(payload) < payload_len: + payload += "%u " % counter + counter += 1 + + p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) / + IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) / + UDP(sport=1234, dport=5678) / + Raw(payload)) + fragments = fragment_rfc8200(p, 1, payload_len/4) + + # send fragment #2 - should be cached inside reassembly + self.pg_enable_capture() + self.src_if.add_stream(fragments[1]) + self.pg_start() + self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details")) + self.logger.debug(self.vapi.ppcli("show buffers")) + self.logger.debug(self.vapi.ppcli("show trace")) + self.dst_if.assert_nothing_captured() + + # send fragment #1 - reassembly is finished now and both fragments + # forwarded + self.pg_enable_capture() + self.src_if.add_stream(fragments[0]) + self.pg_start() + self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details")) + self.logger.debug(self.vapi.ppcli("show buffers")) + self.logger.debug(self.vapi.ppcli("show trace")) + c = self.dst_if.get_capture(2) + for sent, recvd in zip([fragments[1], fragments[0]], c): + self.assertEqual(sent[IPv6].src, recvd[IPv6].src) + self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst) + self.assertEqual(sent[Raw].payload, recvd[Raw].payload) + + # send rest of fragments - should be immediately forwarded + self.pg_enable_capture() + self.src_if.add_stream(fragments[2:]) + self.pg_start() + c = self.dst_if.get_capture(len(fragments[2:])) + for sent, recvd in zip(fragments[2:], c): + self.assertEqual(sent[IPv6].src, recvd[IPv6].src) + self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst) + self.assertEqual(sent[Raw].payload, recvd[Raw].payload) + + def test_timeout(self): + """ reassembly timeout """ + payload_len = 1000 + payload = "" + counter = 0 + while len(payload) < payload_len: + payload += "%u " % counter + counter += 1 + + p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) / + IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) / + UDP(sport=1234, dport=5678) / + Raw(payload)) + fragments = fragment_rfc8200(p, 1, payload_len/4) + + self.vapi.ip_reassembly_set( + timeout_ms=100, max_reassemblies=1000, + max_reassembly_length=1000, + expire_walk_interval_ms=50, + is_ip6=1, + type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL) + + # send fragments #2 and #1 - should be forwarded + self.pg_enable_capture() + self.src_if.add_stream(fragments[0:2]) + self.pg_start() + self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details")) + self.logger.debug(self.vapi.ppcli("show buffers")) + self.logger.debug(self.vapi.ppcli("show trace")) + c = self.dst_if.get_capture(2) + for sent, recvd in zip([fragments[1], fragments[0]], c): + self.assertEqual(sent[IPv6].src, recvd[IPv6].src) + self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst) + self.assertEqual(sent[Raw].payload, recvd[Raw].payload) + + # wait for cleanup + self.sleep(.25, "wait before sending rest of fragments") + + # send rest of fragments - shouldn't be forwarded + self.pg_enable_capture() + self.src_if.add_stream(fragments[2:]) + self.pg_start() + self.dst_if.assert_nothing_captured() + + def test_lru(self): + """ reassembly reuses LRU element """ + + self.vapi.ip_reassembly_set( + timeout_ms=1000000, max_reassemblies=1, + max_reassembly_length=1000, + type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL, + is_ip6=1, expire_walk_interval_ms=10000) + + payload_len = 1000 + payload = "" + counter = 0 + while len(payload) < payload_len: + payload += "%u " % counter + counter += 1 + + packet_count = 10 + + fragments = [f + for i in range(packet_count) + for p in (Ether(dst=self.src_if.local_mac, + src=self.src_if.remote_mac) / + IPv6(src=self.src_if.remote_ip6, + dst=self.dst_if.remote_ip6) / + UDP(sport=1234, dport=5678) / + Raw(payload)) + for f in fragment_rfc8200(p, i, payload_len/4)] + + self.pg_enable_capture() + self.src_if.add_stream(fragments) + self.pg_start() + c = self.dst_if.get_capture(len(fragments)) + for sent, recvd in zip(fragments, c): + self.assertEqual(sent[IPv6].src, recvd[IPv6].src) + self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst) + self.assertEqual(sent[Raw].payload, recvd[Raw].payload) + + class TestIPv4ReassemblyLocalNode(VppTestCase): """ IPv4 Reassembly for packets coming to ip4-local node """ -- cgit 1.2.3-korg