diff options
Diffstat (limited to 'test/test_reassembly.py')
-rw-r--r-- | test/test_reassembly.py | 966 |
1 files changed, 0 insertions, 966 deletions
diff --git a/test/test_reassembly.py b/test/test_reassembly.py deleted file mode 100644 index a2d77d493de..00000000000 --- a/test/test_reassembly.py +++ /dev/null @@ -1,966 +0,0 @@ -#!/usr/bin/env python -import unittest -from random import shuffle - -from framework import VppTestCase, VppTestRunner - -from scapy.packet import Raw -from scapy.layers.l2 import Ether, GRE -from scapy.layers.inet import IP, UDP -from util import ppp, fragment_rfc791, fragment_rfc8200 -from vpp_punt_socket import VppUDSPuntSocket -from scapy.layers.inet6 import IPv6, IPv6ExtHdrFragment, ICMPv6ParamProblem,\ - ICMPv6TimeExceeded -from vpp_gre_interface import VppGreInterface, VppGre6Interface -from vpp_ip_route import VppIpRoute, VppRoutePath, DpoProto - -test_packet_count = 257 - - -class TestIPv4Reassembly(VppTestCase): - """ IPv4 Reassembly """ - - @classmethod - def setUpClass(cls): - super(TestIPv4Reassembly, cls).setUpClass() - - cls.create_pg_interfaces([0]) - cls.pg_if = cls.pg0 - - # setup all interfaces - for i in cls.pg_interfaces: - i.admin_up() - i.config_ip4() - i.resolve_arp() - - cls.punt_port = 9999 - cls.punt_socket = VppUDSPuntSocket(cls, cls.punt_port) - - # packet sizes - cls.packet_sizes = [64, 512, 1518, 9018] - cls.padding = " abcdefghijklmn" - cls.create_stream(cls.packet_sizes) - cls.create_fragments() - - def setUp(self): - """ Test setup - force timeout on existing reassemblies """ - super(TestIPv4Reassembly, self).setUp() - self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000, - expire_walk_interval_ms=10) - self.sleep(.25) - self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000, - expire_walk_interval_ms=10000) - - def tearDown(self): - super(TestIPv4Reassembly, self).tearDown() - self.logger.debug(self.vapi.ppcli("show ip4-reassembly details")) - - @classmethod - def create_stream(cls, packet_sizes, packet_count=test_packet_count): - """Create input packet stream for defined interface. - - :param list packet_sizes: Required packet sizes. - """ - for i in range(0, packet_count): - info = cls.create_packet_info(cls.pg_if, cls.pg_if) - payload = cls.info_to_payload(info) - p = (Ether(dst=cls.pg_if.local_mac, src=cls.pg_if.remote_mac) / - IP(id=info.index, src=cls.pg_if.remote_ip4, - dst=cls.pg_if.local_ip4) / - UDP(sport=1234, dport=cls.punt_port) / - Raw(payload)) - size = packet_sizes[(i // 2) % len(packet_sizes)] - cls.extend_packet(p, size, cls.padding) - info.data = p - - @classmethod - def create_fragments(cls): - infos = cls._packet_infos - cls.pkt_infos = [] - for index, info in infos.iteritems(): - p = info.data - # self.logger.debug(ppp("Packet:", p.__class__(str(p)))) - fragments_400 = fragment_rfc791(p, 400) - fragments_300 = fragment_rfc791(p, 300) - fragments_200 = [ - x for f in fragments_400 for x in fragment_rfc791(f, 200)] - cls.pkt_infos.append( - (index, fragments_400, fragments_300, fragments_200)) - cls.fragments_400 = [ - x for (_, frags, _, _) in cls.pkt_infos for x in frags] - cls.fragments_300 = [ - x for (_, _, frags, _) in cls.pkt_infos for x in frags] - cls.fragments_200 = [ - x for (_, _, _, frags) in cls.pkt_infos for x in frags] - cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, " - "%s 300-byte fragments and %s 200-byte fragments" % - (len(infos), len(cls.fragments_400), - len(cls.fragments_300), len(cls.fragments_200))) - - def verify_capture(self, capture, dropped_packet_indexes=[]): - """Verify captured packet stream. - - :param list capture: Captured packet stream. - """ - info = None - seen = set() - for packet in capture: - try: - sw_if_index = packet['sw_if_index'] - punt_action = packet['punt_action'] - packet = Ether(packet['packet']) - self.logger.debug(ppp("Got packet from %s, action %s" % - (sw_if_index, punt_action), packet)) - ip = packet[IP] - udp = packet[UDP] - payload_info = self.payload_to_info(str(packet[Raw])) - packet_index = payload_info.index - self.assertTrue( - packet_index not in dropped_packet_indexes, - ppp("Packet received, but should be dropped:", packet)) - if packet_index in seen: - raise Exception(ppp("Duplicate packet received", packet)) - seen.add(packet_index) - self.assertEqual(payload_info.dst, self.pg_if.sw_if_index) - info = self._packet_infos[packet_index] - self.assertTrue(info is not None) - self.assertEqual(packet_index, info.index) - saved_packet = info.data - self.assertEqual(ip.src, saved_packet[IP].src) - self.assertEqual(ip.dst, saved_packet[IP].dst) - self.assertEqual(udp.payload, saved_packet[UDP].payload) - except: - self.logger.error(ppp("Unexpected or invalid packet:", packet)) - raise - for index in self._packet_infos: - self.assertTrue(index in seen or index in dropped_packet_indexes, - "Packet with packet_index %d not received" % index) - - def test_reassembly(self): - """ basic reassembly """ - - self.pg_enable_capture() - self.pg_if.add_stream(self.fragments_200) - self.pg_start() - - packets = self.punt_socket.wait_for_packets(len(self.pkt_infos)) - self.verify_capture(packets) - self.pg_if.assert_nothing_captured() - - # run it all again to verify correctness - self.pg_enable_capture() - self.pg_if.add_stream(self.fragments_200) - self.pg_start() - - packets = self.punt_socket.wait_for_packets(len(self.pkt_infos)) - self.verify_capture(packets) - self.pg_if.assert_nothing_captured() - - def test_reversed(self): - """ reverse order reassembly """ - - fragments = list(self.fragments_200) - fragments.reverse() - - self.pg_enable_capture() - self.pg_if.add_stream(fragments) - self.pg_start() - - packets = self.punt_socket.wait_for_packets(len(self.packet_infos)) - self.verify_capture(packets) - self.pg_if.assert_nothing_captured() - - # run it all again to verify correctness - self.pg_enable_capture() - self.pg_if.add_stream(fragments) - self.pg_start() - - packets = self.punt_socket.wait_for_packets(len(self.packet_infos)) - self.verify_capture(packets) - self.pg_if.assert_nothing_captured() - - def test_random(self): - """ random order reassembly """ - - fragments = list(self.fragments_200) - shuffle(fragments) - - self.pg_enable_capture() - self.pg_if.add_stream(fragments) - self.pg_start() - - packets = self.punt_socket.wait_for_packets(len(self.packet_infos)) - self.verify_capture(packets) - self.pg_if.assert_nothing_captured() - - # run it all again to verify correctness - self.pg_enable_capture() - self.pg_if.add_stream(fragments) - self.pg_start() - - packets = self.punt_socket.wait_for_packets(len(self.packet_infos)) - self.verify_capture(packets) - self.pg_if.assert_nothing_captured() - - def test_duplicates(self): - """ duplicate fragments """ - - fragments = [ - x for (_, frags, _, _) in self.pkt_infos - for x in frags - for _ in range(0, min(2, len(frags))) - ] - - self.pg_enable_capture() - self.pg_if.add_stream(fragments) - self.pg_start() - - packets = self.punt_socket.wait_for_packets(len(self.pkt_infos)) - self.verify_capture(packets) - self.pg_if.assert_nothing_captured() - - def test_overlap1(self): - """ overlapping fragments case #1 """ - - fragments = [] - for _, _, frags_300, frags_200 in self.pkt_infos: - if len(frags_300) == 1: - fragments.extend(frags_300) - else: - for i, j in zip(frags_200, frags_300): - fragments.extend(i) - fragments.extend(j) - - self.pg_enable_capture() - self.pg_if.add_stream(fragments) - self.pg_start() - - packets = self.punt_socket.wait_for_packets(len(self.pkt_infos)) - self.verify_capture(packets) - self.pg_if.assert_nothing_captured() - - # run it all to verify correctness - self.pg_enable_capture() - self.pg_if.add_stream(fragments) - self.pg_start() - - packets = self.punt_socket.wait_for_packets(len(self.pkt_infos)) - self.verify_capture(packets) - self.pg_if.assert_nothing_captured() - - def test_overlap2(self): - """ overlapping fragments case #2 """ - - fragments = [] - for _, _, frags_300, frags_200 in self.pkt_infos: - if len(frags_300) == 1: - fragments.extend(frags_300) - else: - # care must be taken here so that there are no fragments - # received by vpp after reassembly is finished, otherwise - # new reassemblies will be started and packet generator will - # freak out when it detects unfreed buffers - zipped = zip(frags_300, frags_200) - for i, j in zipped[:-1]: - fragments.extend(i) - fragments.extend(j) - fragments.append(zipped[-1][0]) - - self.pg_enable_capture() - self.pg_if.add_stream(fragments) - self.pg_start() - - packets = self.punt_socket.wait_for_packets(len(self.pkt_infos)) - self.verify_capture(packets) - self.pg_if.assert_nothing_captured() - - # run it all to verify correctness - self.pg_enable_capture() - self.pg_if.add_stream(fragments) - self.pg_start() - - packets = self.punt_socket.wait_for_packets(len(self.pkt_infos)) - self.verify_capture(packets) - self.pg_if.assert_nothing_captured() - - def test_timeout_inline(self): - """ timeout (inline) """ - - dropped_packet_indexes = set( - index for (index, frags, _, _) in self.pkt_infos if len(frags) > 1 - ) - - self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000, - expire_walk_interval_ms=10000) - - self.pg_enable_capture() - self.pg_if.add_stream(self.fragments_400) - self.pg_start() - - packets = self.punt_socket.wait_for_packets( - len(self.pkt_infos) - len(dropped_packet_indexes)) - self.verify_capture(packets, dropped_packet_indexes) - self.pg_if.assert_nothing_captured() - - def test_timeout_cleanup(self): - """ timeout (cleanup) """ - - # whole packets + fragmented packets sans last fragment - fragments = [ - x for (_, frags_400, _, _) in self.pkt_infos - for x in frags_400[:-1 if len(frags_400) > 1 else None] - ] - - # last fragments for fragmented packets - fragments2 = [frags_400[-1] - for (_, frags_400, _, _) in self.pkt_infos - if len(frags_400) > 1] - - dropped_packet_indexes = set( - index for (index, frags_400, _, _) in self.pkt_infos - if len(frags_400) > 1) - - self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000, - expire_walk_interval_ms=50) - - self.pg_enable_capture() - self.pg_if.add_stream(fragments) - self.pg_start() - - self.sleep(.25, "wait before sending rest of fragments") - - self.pg_if.add_stream(fragments2) - self.pg_start() - self.sleep(.25, "wait for vpp to process packets") - - packets = self.punt_socket.wait_for_packets( - len(self.pkt_infos) - len(dropped_packet_indexes)) - self.verify_capture(packets, dropped_packet_indexes) - self.pg_if.assert_nothing_captured() - - def test_disabled(self): - """ reassembly disabled """ - - dropped_packet_indexes = set( - index for (index, frags_400, _, _) in self.pkt_infos - if len(frags_400) > 1) - - self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=0, - expire_walk_interval_ms=10000) - - self.pg_enable_capture() - self.pg_if.add_stream(self.fragments_400) - self.pg_start() - - packets = self.punt_socket.wait_for_packets( - len(self.pkt_infos) - len(dropped_packet_indexes)) - self.verify_capture(packets, dropped_packet_indexes) - self.pg_if.assert_nothing_captured() - - -class TestIPv6Reassembly(VppTestCase): - """ IPv6 Reassembly """ - - @classmethod - def setUpClass(cls): - super(TestIPv6Reassembly, cls).setUpClass() - - cls.create_pg_interfaces([0]) - cls.pg_if = cls.pg0 - - # setup all interfaces - for i in cls.pg_interfaces: - i.admin_up() - i.config_ip6() - i.resolve_ndp() - - cls.punt_port = 9999 - cls.punt_socket = VppUDSPuntSocket(cls, cls.punt_port, is_ip4=0) - - # packet sizes - cls.packet_sizes = [64, 512, 1518, 9018] - cls.padding = " abcdefghijklmn" - cls.create_stream(cls.packet_sizes) - cls.create_fragments() - - def setUp(self): - """ Test setup - force timeout on existing reassemblies """ - super(TestIPv6Reassembly, self).setUp() - self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000, - expire_walk_interval_ms=10, is_ip6=1) - self.sleep(.25) - self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000, - expire_walk_interval_ms=10000, is_ip6=1) - - def tearDown(self): - super(TestIPv6Reassembly, self).tearDown() - self.logger.debug(self.vapi.ppcli("show ip6-reassembly details")) - - @classmethod - def create_stream(cls, packet_sizes, packet_count=test_packet_count): - """Create input packet stream for defined interface. - - :param list packet_sizes: Required packet sizes. - """ - for i in range(0, packet_count): - info = cls.create_packet_info(cls.pg_if, cls.pg_if) - payload = cls.info_to_payload(info) - p = (Ether(dst=cls.pg_if.local_mac, src=cls.pg_if.remote_mac) / - IPv6(src=cls.pg_if.remote_ip6, - dst=cls.pg_if.local_ip6) / - UDP(sport=1234, dport=cls.punt_port) / - Raw(payload)) - size = packet_sizes[(i // 2) % len(packet_sizes)] - cls.extend_packet(p, size, cls.padding) - info.data = p - - @classmethod - def create_fragments(cls): - infos = cls._packet_infos - cls.pkt_infos = [] - for index, info in infos.iteritems(): - p = info.data - # self.logger.debug(ppp("Packet:", p.__class__(str(p)))) - fragments_400 = fragment_rfc8200(p, info.index, 400) - fragments_300 = fragment_rfc8200(p, info.index, 300) - cls.pkt_infos.append((index, fragments_400, fragments_300)) - cls.fragments_400 = [ - x for _, frags, _ in cls.pkt_infos for x in frags] - cls.fragments_300 = [ - x for _, _, frags in cls.pkt_infos for x in frags] - cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, " - "and %s 300-byte fragments" % - (len(infos), len(cls.fragments_400), - len(cls.fragments_300))) - - def verify_capture(self, capture, dropped_packet_indexes=[]): - """Verify captured packet strea . - - :param list capture: Captured packet stream. - """ - info = None - seen = set() - for packet in capture: - try: - sw_if_index = packet['sw_if_index'] - punt_action = packet['punt_action'] - packet = Ether(packet['packet']) - self.logger.debug(ppp("Got packet from %s, action %s" % - (sw_if_index, punt_action), packet)) - ip = packet[IPv6] - udp = packet[UDP] - payload_info = self.payload_to_info(str(packet[Raw])) - packet_index = payload_info.index - self.assertTrue( - packet_index not in dropped_packet_indexes, - ppp("Packet received, but should be dropped:", packet)) - if packet_index in seen: - raise Exception(ppp("Duplicate packet received", packet)) - seen.add(packet_index) - self.assertEqual(payload_info.dst, self.pg_if.sw_if_index) - info = self._packet_infos[packet_index] - self.assertTrue(info is not None) - self.assertEqual(packet_index, info.index) - saved_packet = info.data - self.assertEqual(ip.src, saved_packet[IPv6].src) - self.assertEqual(ip.dst, saved_packet[IPv6].dst) - self.assertEqual(udp.payload, saved_packet[UDP].payload) - except: - self.logger.error(ppp("Unexpected or invalid packet:", packet)) - raise - for index in self._packet_infos: - self.assertTrue(index in seen or index in dropped_packet_indexes, - "Packet with packet_index %d not received" % index) - - def test_reassembly(self): - """ basic reassembly """ - - self.pg_enable_capture() - self.pg_if.add_stream(self.fragments_400) - self.pg_start() - - packets = self.punt_socket.wait_for_packets(len(self.pkt_infos)) - self.verify_capture(packets) - self.pg_if.assert_nothing_captured() - - # run it all again to verify correctness - self.pg_enable_capture() - self.pg_if.add_stream(self.fragments_400) - self.pg_start() - - packets = self.punt_socket.wait_for_packets(len(self.pkt_infos)) - self.verify_capture(packets) - self.pg_if.assert_nothing_captured() - - def test_reversed(self): - """ reverse order reassembly """ - - fragments = list(self.fragments_400) - fragments.reverse() - - self.pg_enable_capture() - self.pg_if.add_stream(fragments) - self.pg_start() - - packets = self.punt_socket.wait_for_packets(len(self.pkt_infos)) - self.verify_capture(packets) - self.pg_if.assert_nothing_captured() - - # run it all again to verify correctness - self.pg_enable_capture() - self.pg_if.add_stream(fragments) - self.pg_start() - - packets = self.punt_socket.wait_for_packets(len(self.pkt_infos)) - self.verify_capture(packets) - self.pg_if.assert_nothing_captured() - - def test_random(self): - """ random order reassembly """ - - fragments = list(self.fragments_400) - shuffle(fragments) - - self.pg_enable_capture() - self.pg_if.add_stream(fragments) - self.pg_start() - - packets = self.punt_socket.wait_for_packets(len(self.pkt_infos)) - self.verify_capture(packets) - self.pg_if.assert_nothing_captured() - - # run it all again to verify correctness - self.pg_enable_capture() - self.pg_if.add_stream(fragments) - self.pg_start() - - packets = self.punt_socket.wait_for_packets(len(self.pkt_infos)) - self.verify_capture(packets) - self.pg_if.assert_nothing_captured() - - def test_duplicates(self): - """ duplicate fragments """ - - fragments = [ - x for (_, frags, _) in self.pkt_infos - for x in frags - for _ in range(0, min(2, len(frags))) - ] - - self.pg_enable_capture() - self.pg_if.add_stream(fragments) - self.pg_start() - - packets = self.punt_socket.wait_for_packets(len(self.pkt_infos)) - self.verify_capture(packets) - self.pg_if.assert_nothing_captured() - - def test_overlap1(self): - """ overlapping fragments case #1 """ - - fragments = [] - for _, frags_400, frags_300 in self.pkt_infos: - if len(frags_300) == 1: - fragments.extend(frags_400) - else: - for i, j in zip(frags_300, frags_400): - fragments.extend(i) - fragments.extend(j) - - dropped_packet_indexes = set( - index for (index, _, frags) in self.pkt_infos if len(frags) > 1 - ) - - self.pg_enable_capture() - self.pg_if.add_stream(fragments) - self.pg_start() - - self.sleep(.1, "wait for vpp to process packets") - packets = self.punt_socket.wait_for_packets( - len(self.pkt_infos) - len(dropped_packet_indexes)) - self.verify_capture(packets, dropped_packet_indexes) - self.pg_if.assert_nothing_captured() - - def test_overlap2(self): - """ overlapping fragments case #2 """ - - fragments = [] - for _, frags_400, frags_30 in self.pkt_infos: - if len(frags_400) == 1: - fragments.extend(frags_400) - else: - # care must be taken here so that there are no fragments - # received by vpp after reassembly is finished, otherwise - # new reassemblies will be started and packet generator will - # freak out when it detects unfreed buffers - zipped = zip(frags_400, frags_30) - for i, j in zipped[:-1]: - fragments.extend(i) - fragments.extend(j) - fragments.append(zipped[-1][0]) - - dropped_packet_indexes = set( - index for (index, _, frags) in self.pkt_infos if len(frags) > 1 - ) - - self.pg_enable_capture() - self.pg_if.add_stream(fragments) - self.pg_start() - - self.sleep(.1, "wait for vpp to process packets") - packets = self.punt_socket.wait_for_packets( - len(self.pkt_infos) - len(dropped_packet_indexes)) - self.verify_capture(packets, dropped_packet_indexes) - self.pg_if.assert_nothing_captured() - - def test_timeout_inline(self): - """ timeout (inline) """ - - dropped_packet_indexes = set( - index for (index, frags, _) in self.pkt_infos if len(frags) > 1 - ) - - self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000, - expire_walk_interval_ms=10000, is_ip6=1) - - self.pg_enable_capture() - self.pg_if.add_stream(self.fragments_400) - self.pg_start() - - packets = self.punt_socket.wait_for_packets( - len(self.pkt_infos) - len(dropped_packet_indexes)) - self.verify_capture(packets, dropped_packet_indexes) - pkts = self.pg_if.get_capture( - expected_count=len(dropped_packet_indexes)) - for icmp in pkts: - self.assertIn(ICMPv6TimeExceeded, icmp) - self.assertIn(IPv6ExtHdrFragment, icmp) - self.assertIn(icmp[IPv6ExtHdrFragment].id, dropped_packet_indexes) - dropped_packet_indexes.remove(icmp[IPv6ExtHdrFragment].id) - - def test_timeout_cleanup(self): - """ timeout (cleanup) """ - - # whole packets + fragmented packets sans last fragment - fragments = [ - x for (_, frags_400, _) in self.pkt_infos - for x in frags_400[:-1 if len(frags_400) > 1 else None] - ] - - # last fragments for fragmented packets - fragments2 = [frags_400[-1] - for (_, frags_400, _) in self.pkt_infos - if len(frags_400) > 1] - - dropped_packet_indexes = set( - index for (index, frags_400, _) in self.pkt_infos - if len(frags_400) > 1) - - self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000, - expire_walk_interval_ms=50) - - self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000, - expire_walk_interval_ms=50, is_ip6=1) - - self.pg_enable_capture() - self.pg_if.add_stream(fragments) - self.pg_start() - - self.sleep(.25, "wait before sending rest of fragments") - - self.pg_if.add_stream(fragments2) - self.pg_start() - self.sleep(.25, "wait for vpp to process packets") - - packets = self.punt_socket.wait_for_packets( - len(self.pkt_infos) - len(dropped_packet_indexes)) - self.verify_capture(packets, dropped_packet_indexes) - pkts = self.pg_if.get_capture( - expected_count=len(dropped_packet_indexes)) - for icmp in pkts: - self.assertIn(ICMPv6TimeExceeded, icmp) - self.assertIn(IPv6ExtHdrFragment, icmp) - self.assertIn(icmp[IPv6ExtHdrFragment].id, dropped_packet_indexes) - dropped_packet_indexes.remove(icmp[IPv6ExtHdrFragment].id) - - def test_disabled(self): - """ reassembly disabled """ - - dropped_packet_indexes = set( - index for (index, frags_400, _) in self.pkt_infos - if len(frags_400) > 1) - - self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=0, - expire_walk_interval_ms=10000, is_ip6=1) - - self.pg_enable_capture() - self.pg_if.add_stream(self.fragments_400) - self.pg_start() - - packets = self.punt_socket.wait_for_packets( - len(self.pkt_infos) - len(dropped_packet_indexes)) - self.verify_capture(packets, dropped_packet_indexes) - self.pg_if.assert_nothing_captured() - - def test_missing_upper(self): - """ missing upper layer """ - p = (Ether(dst=self.pg_if.local_mac, src=self.pg_if.remote_mac) / - IPv6(src=self.pg_if.remote_ip6, - dst=self.pg_if.local_ip6) / - UDP(sport=1234, dport=self.punt_port) / - Raw()) - self.extend_packet(p, 1000, self.padding) - fragments = fragment_rfc8200(p, 1, 500) - bad_fragment = p.__class__(str(fragments[1])) - bad_fragment[IPv6ExtHdrFragment].nh = 59 - bad_fragment[IPv6ExtHdrFragment].offset = 0 - self.pg_enable_capture() - self.pg_if.add_stream([bad_fragment]) - self.pg_start() - pkts = self.pg_if.get_capture(expected_count=1) - icmp = pkts[0] - self.assertIn(ICMPv6ParamProblem, icmp) - self.assert_equal(icmp[ICMPv6ParamProblem].code, 3, "ICMP code") - - def test_invalid_frag_size(self): - """ fragment size not a multiple of 8 """ - p = (Ether(dst=self.pg_if.local_mac, src=self.pg_if.remote_mac) / - IPv6(src=self.pg_if.remote_ip6, - dst=self.pg_if.local_ip6) / - UDP(sport=1234, dport=self.punt_port) / - Raw()) - self.extend_packet(p, 1000, self.padding) - fragments = fragment_rfc8200(p, 1, 500) - bad_fragment = fragments[0] - self.extend_packet(bad_fragment, len(bad_fragment) + 5) - self.pg_enable_capture() - self.pg_if.add_stream([bad_fragment]) - self.pg_start() - pkts = self.pg_if.get_capture(expected_count=1) - icmp = pkts[0] - self.assertIn(ICMPv6ParamProblem, icmp) - self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code") - - def test_invalid_packet_size(self): - """ total packet size > 65535 """ - p = (Ether(dst=self.pg_if.local_mac, src=self.pg_if.remote_mac) / - IPv6(src=self.pg_if.remote_ip6, - dst=self.pg_if.local_ip6) / - UDP(sport=1234, dport=self.punt_port) / - Raw()) - self.extend_packet(p, 1000, self.padding) - fragments = fragment_rfc8200(p, 1, 500) - bad_fragment = fragments[1] - bad_fragment[IPv6ExtHdrFragment].offset = 65500 - self.pg_enable_capture() - self.pg_if.add_stream([bad_fragment]) - self.pg_start() - pkts = self.pg_if.get_capture(expected_count=1) - icmp = pkts[0] - self.assertIn(ICMPv6ParamProblem, icmp) - self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code") - - -class TestFIFReassembly(VppTestCase): - """ Fragments in fragments reassembly """ - - @classmethod - def setUpClass(cls): - super(TestFIFReassembly, cls).setUpClass() - - cls.create_pg_interfaces([0]) - cls.pg_if = cls.pg0 - cls.pg_if.admin_up() - cls.pg_if.config_ip4() - cls.pg_if.resolve_arp() - cls.pg_if.config_ip6() - cls.pg_if.resolve_ndp() - - cls.punt_port = 9999 - cls.punt4_socket = VppUDSPuntSocket(cls, cls.punt_port) - cls.punt6_socket = VppUDSPuntSocket(cls, cls.punt_port, is_ip4=0) - cls.packet_sizes = [64, 512, 1518, 9018] - cls.padding = " abcdefghijklmn" - - def setUp(self): - """ Test setup - force timeout on existing reassemblies """ - super(TestFIFReassembly, self).setUp() - self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000, - expire_walk_interval_ms=10) - self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000, - expire_walk_interval_ms=10, is_ip6=1) - self.sleep(.25) - self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000, - expire_walk_interval_ms=10000) - self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000, - expire_walk_interval_ms=10000, is_ip6=1) - - def tearDown(self): - self.logger.debug(self.vapi.ppcli("show ip4-reassembly details")) - self.logger.debug(self.vapi.ppcli("show ip6-reassembly details")) - super(TestFIFReassembly, self).tearDown() - - def verify_capture(self, capture, ip_class, dropped_packet_indexes=[]): - """Verify captured packet stream. - - :param list capture: Captured packet stream. - """ - info = None - seen = set() - for packet in capture: - try: - sw_if_index = packet['sw_if_index'] - punt_action = packet['punt_action'] - packet = Ether(packet['packet']) - self.logger.debug(ppp("Got packet from %s, action %s" % - (sw_if_index, punt_action), packet)) - ip = packet[ip_class] - udp = packet[UDP] - payload_info = self.payload_to_info(str(packet[Raw])) - packet_index = payload_info.index - self.assertTrue( - packet_index not in dropped_packet_indexes, - ppp("Packet received, but should be dropped:", packet)) - if packet_index in seen: - raise Exception(ppp("Duplicate packet received", packet)) - seen.add(packet_index) - self.assertEqual(payload_info.dst, self.pg_if.sw_if_index) - info = self._packet_infos[packet_index] - self.assertTrue(info is not None) - self.assertEqual(packet_index, info.index) - saved_packet = info.data - self.assertEqual(ip.src, saved_packet[ip_class].src) - self.assertEqual(ip.dst, saved_packet[ip_class].dst) - self.assertEqual(udp.payload, saved_packet[UDP].payload) - except: - self.logger.error(ppp("Unexpected or invalid packet:", packet)) - raise - for index in self._packet_infos: - self.assertTrue(index in seen or index in dropped_packet_indexes, - "Packet with packet_index %d not received" % index) - - def test_fif4(self): - """ Fragments in fragments (4o4) """ - - # TODO this should be ideally in setUpClass, but then we hit a bug - # with VppIpRoute incorrectly reporting it's present when it's not - # so we need to manually remove the vpp config, thus we cannot have - # it shared for multiple test cases - self.tun_ip4 = "1.1.1.2" - - self.gre4 = VppGreInterface(self, self.pg0.local_ip4, self.tun_ip4) - self.gre4.add_vpp_config() - self.gre4.admin_up() - self.gre4.config_ip4() - - self.route4 = VppIpRoute(self, self.tun_ip4, 32, - [VppRoutePath(self.pg0.remote_ip4, - self.pg0.sw_if_index)]) - self.route4.add_vpp_config() - - self.reset_packet_infos() - for i in range(test_packet_count): - info = self.create_packet_info(self.pg0, self.pg0) - payload = self.info_to_payload(info) - p = (IP(id=i, src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / - UDP(sport=1234, dport=self.punt_port) / - Raw(payload)) - size = self.packet_sizes[(i // 2) % len(self.packet_sizes)] - self.extend_packet(p, size, self.padding) - info.data = p - - fragments = [x for _, p in self._packet_infos.iteritems() - for x in fragment_rfc791(p.data, 400)] - - encapped_fragments = \ - [Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.tun_ip4, dst=self.pg0.local_ip4) / - GRE() / - p - for p in fragments] - - fragmented_encapped_fragments = \ - [x for p in encapped_fragments - for x in fragment_rfc791(p, 200)] - - self.pg0.add_stream(fragmented_encapped_fragments) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - self.pg0.assert_nothing_captured() - packets = self.punt4_socket.wait_for_packets(len(self._packet_infos)) - self.verify_capture(packets, IP) - - # TODO remove gre vpp config by hand until VppIpRoute gets fixed - # so that it's query_vpp_config() works as it should - self.gre4.remove_vpp_config() - - def test_fif6(self): - """ Fragments in fragments (6o6) """ - # TODO this should be ideally in setUpClass, but then we hit a bug - # with VppIpRoute incorrectly reporting it's present when it's not - # so we need to manually remove the vpp config, thus we cannot have - # it shared for multiple test cases - self.tun_ip6 = "1002::1" - - self.gre6 = VppGre6Interface(self, self.pg0.local_ip6, self.tun_ip6) - self.gre6.add_vpp_config() - self.gre6.admin_up() - self.gre6.config_ip6() - - self.route6 = VppIpRoute(self, self.tun_ip6, 128, - [VppRoutePath(self.pg0.remote_ip6, - self.pg0.sw_if_index, - proto=DpoProto.DPO_PROTO_IP6)], - is_ip6=1) - self.route6.add_vpp_config() - - self.reset_packet_infos() - for i in range(test_packet_count): - info = self.create_packet_info(self.pg0, self.pg0) - payload = self.info_to_payload(info) - p = (IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) / - UDP(sport=1234, dport=self.punt_port) / - Raw(payload)) - size = self.packet_sizes[(i // 2) % len(self.packet_sizes)] - self.extend_packet(p, size, self.padding) - info.data = p - - fragments = [x for _, i in self._packet_infos.iteritems() - for x in fragment_rfc8200( - i.data, i.index, 400)] - - encapped_fragments = \ - [Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IPv6(src=self.tun_ip6, dst=self.pg0.local_ip6) / - GRE() / - p - for p in fragments] - - fragmented_encapped_fragments = \ - [x for p in encapped_fragments for x in ( - fragment_rfc8200( - p, - 2 * len(self._packet_infos) + p[IPv6ExtHdrFragment].id, - 200) - if IPv6ExtHdrFragment in p else [p] - ) - ] - - self.pg0.add_stream(fragmented_encapped_fragments) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - self.pg0.assert_nothing_captured() - packets = self.punt6_socket.wait_for_packets(len(self._packet_infos)) - self.verify_capture(packets, IPv6) - - # TODO remove gre vpp config by hand until VppIpRoute gets fixed - # so that it's query_vpp_config() works as it should - self.gre6.remove_vpp_config() - - -if __name__ == '__main__': - unittest.main(testRunner=VppTestRunner) |