blob: 95fefdb5aa1b5bd8c5263721820fb32d2a192bbf [file] [log] [blame]
Klement Sekera75e7d132017-09-20 08:26:30 +02001#!/usr/bin/env python
Paul Vinciguerraf1f2aa62018-11-25 08:36:47 -08002
3import six
Klement Sekera75e7d132017-09-20 08:26:30 +02004import unittest
5from random import shuffle
6
7from framework import VppTestCase, VppTestRunner
8
9from scapy.packet import Raw
10from scapy.layers.l2 import Ether, GRE
Juraj Sloboda3048b632018-10-02 11:13:53 +020011from scapy.layers.inet import IP, UDP, ICMP
Klement Sekera75e7d132017-09-20 08:26:30 +020012from util import ppp, fragment_rfc791, fragment_rfc8200
Klement Sekera75e7d132017-09-20 08:26:30 +020013from scapy.layers.inet6 import IPv6, IPv6ExtHdrFragment, ICMPv6ParamProblem,\
14 ICMPv6TimeExceeded
15from vpp_gre_interface import VppGreInterface, VppGre6Interface
Neale Rannsc0a93142018-09-05 15:42:26 -070016from vpp_ip import DpoProto
17from vpp_ip_route import VppIpRoute, VppRoutePath
Klement Sekera75e7d132017-09-20 08:26:30 +020018
19test_packet_count = 257
20
21
22class TestIPv4Reassembly(VppTestCase):
23 """ IPv4 Reassembly """
24
25 @classmethod
26 def setUpClass(cls):
27 super(TestIPv4Reassembly, cls).setUpClass()
28
Klement Sekera4c533132018-02-22 11:41:12 +010029 cls.create_pg_interfaces([0, 1])
30 cls.src_if = cls.pg0
31 cls.dst_if = cls.pg1
Klement Sekera75e7d132017-09-20 08:26:30 +020032
33 # setup all interfaces
34 for i in cls.pg_interfaces:
35 i.admin_up()
36 i.config_ip4()
37 i.resolve_arp()
38
Klement Sekera75e7d132017-09-20 08:26:30 +020039 # packet sizes
40 cls.packet_sizes = [64, 512, 1518, 9018]
41 cls.padding = " abcdefghijklmn"
42 cls.create_stream(cls.packet_sizes)
43 cls.create_fragments()
44
45 def setUp(self):
46 """ Test setup - force timeout on existing reassemblies """
47 super(TestIPv4Reassembly, self).setUp()
Klement Sekera4c533132018-02-22 11:41:12 +010048 self.vapi.ip_reassembly_enable_disable(
49 sw_if_index=self.src_if.sw_if_index, enable_ip4=True)
Klement Sekera75e7d132017-09-20 08:26:30 +020050 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
51 expire_walk_interval_ms=10)
52 self.sleep(.25)
53 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
54 expire_walk_interval_ms=10000)
55
56 def tearDown(self):
57 super(TestIPv4Reassembly, self).tearDown()
58 self.logger.debug(self.vapi.ppcli("show ip4-reassembly details"))
59
60 @classmethod
61 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
62 """Create input packet stream for defined interface.
63
64 :param list packet_sizes: Required packet sizes.
65 """
66 for i in range(0, packet_count):
Klement Sekera4c533132018-02-22 11:41:12 +010067 info = cls.create_packet_info(cls.src_if, cls.src_if)
Klement Sekera75e7d132017-09-20 08:26:30 +020068 payload = cls.info_to_payload(info)
Klement Sekera4c533132018-02-22 11:41:12 +010069 p = (Ether(dst=cls.src_if.local_mac, src=cls.src_if.remote_mac) /
70 IP(id=info.index, src=cls.src_if.remote_ip4,
71 dst=cls.dst_if.remote_ip4) /
72 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +020073 Raw(payload))
74 size = packet_sizes[(i // 2) % len(packet_sizes)]
75 cls.extend_packet(p, size, cls.padding)
76 info.data = p
77
78 @classmethod
79 def create_fragments(cls):
80 infos = cls._packet_infos
81 cls.pkt_infos = []
Paul Vinciguerraf1f2aa62018-11-25 08:36:47 -080082 for index, info in six.iteritems(infos):
Klement Sekera75e7d132017-09-20 08:26:30 +020083 p = info.data
Klement Sekera4c533132018-02-22 11:41:12 +010084 # cls.logger.debug(ppp("Packet:", p.__class__(str(p))))
Klement Sekera75e7d132017-09-20 08:26:30 +020085 fragments_400 = fragment_rfc791(p, 400)
86 fragments_300 = fragment_rfc791(p, 300)
87 fragments_200 = [
88 x for f in fragments_400 for x in fragment_rfc791(f, 200)]
89 cls.pkt_infos.append(
90 (index, fragments_400, fragments_300, fragments_200))
91 cls.fragments_400 = [
92 x for (_, frags, _, _) in cls.pkt_infos for x in frags]
93 cls.fragments_300 = [
94 x for (_, _, frags, _) in cls.pkt_infos for x in frags]
95 cls.fragments_200 = [
96 x for (_, _, _, frags) in cls.pkt_infos for x in frags]
97 cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, "
98 "%s 300-byte fragments and %s 200-byte fragments" %
99 (len(infos), len(cls.fragments_400),
100 len(cls.fragments_300), len(cls.fragments_200)))
101
102 def verify_capture(self, capture, dropped_packet_indexes=[]):
103 """Verify captured packet stream.
104
105 :param list capture: Captured packet stream.
106 """
107 info = None
108 seen = set()
109 for packet in capture:
110 try:
Klement Sekera4c533132018-02-22 11:41:12 +0100111 self.logger.debug(ppp("Got packet:", packet))
Klement Sekera75e7d132017-09-20 08:26:30 +0200112 ip = packet[IP]
113 udp = packet[UDP]
114 payload_info = self.payload_to_info(str(packet[Raw]))
115 packet_index = payload_info.index
116 self.assertTrue(
117 packet_index not in dropped_packet_indexes,
118 ppp("Packet received, but should be dropped:", packet))
119 if packet_index in seen:
120 raise Exception(ppp("Duplicate packet received", packet))
121 seen.add(packet_index)
Klement Sekera4c533132018-02-22 11:41:12 +0100122 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
Klement Sekera75e7d132017-09-20 08:26:30 +0200123 info = self._packet_infos[packet_index]
124 self.assertTrue(info is not None)
125 self.assertEqual(packet_index, info.index)
126 saved_packet = info.data
127 self.assertEqual(ip.src, saved_packet[IP].src)
128 self.assertEqual(ip.dst, saved_packet[IP].dst)
129 self.assertEqual(udp.payload, saved_packet[UDP].payload)
Klement Sekera4c533132018-02-22 11:41:12 +0100130 except Exception:
Klement Sekera75e7d132017-09-20 08:26:30 +0200131 self.logger.error(ppp("Unexpected or invalid packet:", packet))
132 raise
133 for index in self._packet_infos:
134 self.assertTrue(index in seen or index in dropped_packet_indexes,
135 "Packet with packet_index %d not received" % index)
136
137 def test_reassembly(self):
138 """ basic reassembly """
139
140 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100141 self.src_if.add_stream(self.fragments_200)
Klement Sekera75e7d132017-09-20 08:26:30 +0200142 self.pg_start()
143
Klement Sekera4c533132018-02-22 11:41:12 +0100144 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200145 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100146 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200147
148 # run it all again to verify correctness
149 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100150 self.src_if.add_stream(self.fragments_200)
Klement Sekera75e7d132017-09-20 08:26:30 +0200151 self.pg_start()
152
Klement Sekera4c533132018-02-22 11:41:12 +0100153 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200154 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100155 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200156
157 def test_reversed(self):
158 """ reverse order reassembly """
159
160 fragments = list(self.fragments_200)
161 fragments.reverse()
162
163 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100164 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200165 self.pg_start()
166
Klement Sekera4c533132018-02-22 11:41:12 +0100167 packets = self.dst_if.get_capture(len(self.packet_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200168 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100169 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200170
171 # run it all again to verify correctness
172 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100173 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200174 self.pg_start()
175
Klement Sekera4c533132018-02-22 11:41:12 +0100176 packets = self.dst_if.get_capture(len(self.packet_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200177 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100178 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200179
180 def test_random(self):
181 """ random order reassembly """
182
183 fragments = list(self.fragments_200)
184 shuffle(fragments)
185
186 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100187 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200188 self.pg_start()
189
Klement Sekera4c533132018-02-22 11:41:12 +0100190 packets = self.dst_if.get_capture(len(self.packet_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200191 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100192 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200193
194 # run it all again to verify correctness
195 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100196 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200197 self.pg_start()
198
Klement Sekera4c533132018-02-22 11:41:12 +0100199 packets = self.dst_if.get_capture(len(self.packet_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200200 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100201 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200202
203 def test_duplicates(self):
204 """ duplicate fragments """
205
206 fragments = [
207 x for (_, frags, _, _) in self.pkt_infos
208 for x in frags
209 for _ in range(0, min(2, len(frags)))
210 ]
211
212 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100213 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200214 self.pg_start()
215
Klement Sekera4c533132018-02-22 11:41:12 +0100216 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200217 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100218 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200219
220 def test_overlap1(self):
221 """ overlapping fragments case #1 """
222
223 fragments = []
224 for _, _, frags_300, frags_200 in self.pkt_infos:
225 if len(frags_300) == 1:
226 fragments.extend(frags_300)
227 else:
228 for i, j in zip(frags_200, frags_300):
229 fragments.extend(i)
230 fragments.extend(j)
231
232 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100233 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200234 self.pg_start()
235
Klement Sekera4c533132018-02-22 11:41:12 +0100236 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200237 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100238 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200239
240 # run it all to verify correctness
241 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100242 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200243 self.pg_start()
244
Klement Sekera4c533132018-02-22 11:41:12 +0100245 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200246 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100247 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200248
249 def test_overlap2(self):
250 """ overlapping fragments case #2 """
251
252 fragments = []
253 for _, _, frags_300, frags_200 in self.pkt_infos:
254 if len(frags_300) == 1:
255 fragments.extend(frags_300)
256 else:
257 # care must be taken here so that there are no fragments
258 # received by vpp after reassembly is finished, otherwise
259 # new reassemblies will be started and packet generator will
260 # freak out when it detects unfreed buffers
261 zipped = zip(frags_300, frags_200)
262 for i, j in zipped[:-1]:
263 fragments.extend(i)
264 fragments.extend(j)
265 fragments.append(zipped[-1][0])
266
267 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100268 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200269 self.pg_start()
270
Klement Sekera4c533132018-02-22 11:41:12 +0100271 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200272 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100273 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200274
275 # run it all to verify correctness
276 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100277 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200278 self.pg_start()
279
Klement Sekera4c533132018-02-22 11:41:12 +0100280 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200281 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100282 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200283
284 def test_timeout_inline(self):
285 """ timeout (inline) """
286
287 dropped_packet_indexes = set(
288 index for (index, frags, _, _) in self.pkt_infos if len(frags) > 1
289 )
290
291 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
292 expire_walk_interval_ms=10000)
293
294 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100295 self.src_if.add_stream(self.fragments_400)
Klement Sekera75e7d132017-09-20 08:26:30 +0200296 self.pg_start()
297
Klement Sekera4c533132018-02-22 11:41:12 +0100298 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +0200299 len(self.pkt_infos) - len(dropped_packet_indexes))
300 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +0100301 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200302
303 def test_timeout_cleanup(self):
304 """ timeout (cleanup) """
305
306 # whole packets + fragmented packets sans last fragment
307 fragments = [
308 x for (_, frags_400, _, _) in self.pkt_infos
309 for x in frags_400[:-1 if len(frags_400) > 1 else None]
310 ]
311
312 # last fragments for fragmented packets
313 fragments2 = [frags_400[-1]
314 for (_, frags_400, _, _) in self.pkt_infos
315 if len(frags_400) > 1]
316
317 dropped_packet_indexes = set(
318 index for (index, frags_400, _, _) in self.pkt_infos
319 if len(frags_400) > 1)
320
321 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
322 expire_walk_interval_ms=50)
323
324 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100325 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200326 self.pg_start()
327
328 self.sleep(.25, "wait before sending rest of fragments")
329
Klement Sekera4c533132018-02-22 11:41:12 +0100330 self.src_if.add_stream(fragments2)
Klement Sekera75e7d132017-09-20 08:26:30 +0200331 self.pg_start()
Klement Sekera75e7d132017-09-20 08:26:30 +0200332
Klement Sekera4c533132018-02-22 11:41:12 +0100333 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +0200334 len(self.pkt_infos) - len(dropped_packet_indexes))
335 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +0100336 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200337
338 def test_disabled(self):
339 """ reassembly disabled """
340
341 dropped_packet_indexes = set(
342 index for (index, frags_400, _, _) in self.pkt_infos
343 if len(frags_400) > 1)
344
345 self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=0,
346 expire_walk_interval_ms=10000)
347
348 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100349 self.src_if.add_stream(self.fragments_400)
Klement Sekera75e7d132017-09-20 08:26:30 +0200350 self.pg_start()
351
Klement Sekera4c533132018-02-22 11:41:12 +0100352 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +0200353 len(self.pkt_infos) - len(dropped_packet_indexes))
354 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +0100355 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200356
357
358class TestIPv6Reassembly(VppTestCase):
359 """ IPv6 Reassembly """
360
361 @classmethod
362 def setUpClass(cls):
363 super(TestIPv6Reassembly, cls).setUpClass()
364
Klement Sekera4c533132018-02-22 11:41:12 +0100365 cls.create_pg_interfaces([0, 1])
366 cls.src_if = cls.pg0
367 cls.dst_if = cls.pg1
Klement Sekera75e7d132017-09-20 08:26:30 +0200368
369 # setup all interfaces
370 for i in cls.pg_interfaces:
371 i.admin_up()
372 i.config_ip6()
373 i.resolve_ndp()
374
Klement Sekera75e7d132017-09-20 08:26:30 +0200375 # packet sizes
376 cls.packet_sizes = [64, 512, 1518, 9018]
377 cls.padding = " abcdefghijklmn"
378 cls.create_stream(cls.packet_sizes)
379 cls.create_fragments()
380
381 def setUp(self):
382 """ Test setup - force timeout on existing reassemblies """
383 super(TestIPv6Reassembly, self).setUp()
Klement Sekera4c533132018-02-22 11:41:12 +0100384 self.vapi.ip_reassembly_enable_disable(
385 sw_if_index=self.src_if.sw_if_index, enable_ip6=True)
Klement Sekera75e7d132017-09-20 08:26:30 +0200386 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
387 expire_walk_interval_ms=10, is_ip6=1)
388 self.sleep(.25)
389 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
390 expire_walk_interval_ms=10000, is_ip6=1)
Klement Sekera4c533132018-02-22 11:41:12 +0100391 self.logger.debug(self.vapi.ppcli("show ip6-reassembly details"))
Klement Sekera75e7d132017-09-20 08:26:30 +0200392
393 def tearDown(self):
394 super(TestIPv6Reassembly, self).tearDown()
395 self.logger.debug(self.vapi.ppcli("show ip6-reassembly details"))
396
397 @classmethod
398 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
399 """Create input packet stream for defined interface.
400
401 :param list packet_sizes: Required packet sizes.
402 """
403 for i in range(0, packet_count):
Klement Sekera4c533132018-02-22 11:41:12 +0100404 info = cls.create_packet_info(cls.src_if, cls.src_if)
Klement Sekera75e7d132017-09-20 08:26:30 +0200405 payload = cls.info_to_payload(info)
Klement Sekera4c533132018-02-22 11:41:12 +0100406 p = (Ether(dst=cls.src_if.local_mac, src=cls.src_if.remote_mac) /
407 IPv6(src=cls.src_if.remote_ip6,
408 dst=cls.dst_if.remote_ip6) /
409 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +0200410 Raw(payload))
411 size = packet_sizes[(i // 2) % len(packet_sizes)]
412 cls.extend_packet(p, size, cls.padding)
413 info.data = p
414
415 @classmethod
416 def create_fragments(cls):
417 infos = cls._packet_infos
418 cls.pkt_infos = []
Paul Vinciguerraf1f2aa62018-11-25 08:36:47 -0800419 for index, info in six.iteritems(infos):
Klement Sekera75e7d132017-09-20 08:26:30 +0200420 p = info.data
Klement Sekera4c533132018-02-22 11:41:12 +0100421 # cls.logger.debug(ppp("Packet:", p.__class__(str(p))))
Klement Sekera75e7d132017-09-20 08:26:30 +0200422 fragments_400 = fragment_rfc8200(p, info.index, 400)
423 fragments_300 = fragment_rfc8200(p, info.index, 300)
424 cls.pkt_infos.append((index, fragments_400, fragments_300))
425 cls.fragments_400 = [
426 x for _, frags, _ in cls.pkt_infos for x in frags]
427 cls.fragments_300 = [
428 x for _, _, frags in cls.pkt_infos for x in frags]
429 cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, "
430 "and %s 300-byte fragments" %
431 (len(infos), len(cls.fragments_400),
432 len(cls.fragments_300)))
433
434 def verify_capture(self, capture, dropped_packet_indexes=[]):
435 """Verify captured packet strea .
436
437 :param list capture: Captured packet stream.
438 """
439 info = None
440 seen = set()
441 for packet in capture:
442 try:
Klement Sekera4c533132018-02-22 11:41:12 +0100443 self.logger.debug(ppp("Got packet:", packet))
Klement Sekera75e7d132017-09-20 08:26:30 +0200444 ip = packet[IPv6]
445 udp = packet[UDP]
446 payload_info = self.payload_to_info(str(packet[Raw]))
447 packet_index = payload_info.index
448 self.assertTrue(
449 packet_index not in dropped_packet_indexes,
450 ppp("Packet received, but should be dropped:", packet))
451 if packet_index in seen:
452 raise Exception(ppp("Duplicate packet received", packet))
453 seen.add(packet_index)
Klement Sekera4c533132018-02-22 11:41:12 +0100454 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
Klement Sekera75e7d132017-09-20 08:26:30 +0200455 info = self._packet_infos[packet_index]
456 self.assertTrue(info is not None)
457 self.assertEqual(packet_index, info.index)
458 saved_packet = info.data
459 self.assertEqual(ip.src, saved_packet[IPv6].src)
460 self.assertEqual(ip.dst, saved_packet[IPv6].dst)
461 self.assertEqual(udp.payload, saved_packet[UDP].payload)
Klement Sekera4c533132018-02-22 11:41:12 +0100462 except Exception:
Klement Sekera75e7d132017-09-20 08:26:30 +0200463 self.logger.error(ppp("Unexpected or invalid packet:", packet))
464 raise
465 for index in self._packet_infos:
466 self.assertTrue(index in seen or index in dropped_packet_indexes,
467 "Packet with packet_index %d not received" % index)
468
469 def test_reassembly(self):
470 """ basic reassembly """
471
472 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100473 self.src_if.add_stream(self.fragments_400)
Klement Sekera75e7d132017-09-20 08:26:30 +0200474 self.pg_start()
475
Klement Sekera4c533132018-02-22 11:41:12 +0100476 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200477 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100478 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200479
480 # run it all again to verify correctness
481 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100482 self.src_if.add_stream(self.fragments_400)
Klement Sekera75e7d132017-09-20 08:26:30 +0200483 self.pg_start()
484
Klement Sekera4c533132018-02-22 11:41:12 +0100485 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200486 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100487 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200488
489 def test_reversed(self):
490 """ reverse order reassembly """
491
492 fragments = list(self.fragments_400)
493 fragments.reverse()
494
495 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100496 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200497 self.pg_start()
498
Klement Sekera4c533132018-02-22 11:41:12 +0100499 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200500 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100501 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200502
503 # run it all again to verify correctness
504 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100505 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200506 self.pg_start()
507
Klement Sekera4c533132018-02-22 11:41:12 +0100508 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200509 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100510 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200511
512 def test_random(self):
513 """ random order reassembly """
514
515 fragments = list(self.fragments_400)
516 shuffle(fragments)
517
518 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100519 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200520 self.pg_start()
521
Klement Sekera4c533132018-02-22 11:41:12 +0100522 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200523 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100524 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200525
526 # run it all again to verify correctness
527 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100528 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200529 self.pg_start()
530
Klement Sekera4c533132018-02-22 11:41:12 +0100531 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200532 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100533 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200534
535 def test_duplicates(self):
536 """ duplicate fragments """
537
538 fragments = [
539 x for (_, frags, _) in self.pkt_infos
540 for x in frags
541 for _ in range(0, min(2, len(frags)))
542 ]
543
544 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100545 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200546 self.pg_start()
547
Klement Sekera4c533132018-02-22 11:41:12 +0100548 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200549 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100550 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200551
552 def test_overlap1(self):
553 """ overlapping fragments case #1 """
554
555 fragments = []
556 for _, frags_400, frags_300 in self.pkt_infos:
557 if len(frags_300) == 1:
558 fragments.extend(frags_400)
559 else:
560 for i, j in zip(frags_300, frags_400):
561 fragments.extend(i)
562 fragments.extend(j)
563
564 dropped_packet_indexes = set(
565 index for (index, _, frags) in self.pkt_infos if len(frags) > 1
566 )
567
568 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100569 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200570 self.pg_start()
571
Klement Sekera4c533132018-02-22 11:41:12 +0100572 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +0200573 len(self.pkt_infos) - len(dropped_packet_indexes))
574 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +0100575 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200576
577 def test_overlap2(self):
578 """ overlapping fragments case #2 """
579
580 fragments = []
Klement Sekera4c533132018-02-22 11:41:12 +0100581 for _, frags_400, frags_300 in self.pkt_infos:
Klement Sekera75e7d132017-09-20 08:26:30 +0200582 if len(frags_400) == 1:
583 fragments.extend(frags_400)
584 else:
585 # care must be taken here so that there are no fragments
586 # received by vpp after reassembly is finished, otherwise
587 # new reassemblies will be started and packet generator will
588 # freak out when it detects unfreed buffers
Klement Sekera4c533132018-02-22 11:41:12 +0100589 zipped = zip(frags_400, frags_300)
Klement Sekera75e7d132017-09-20 08:26:30 +0200590 for i, j in zipped[:-1]:
591 fragments.extend(i)
592 fragments.extend(j)
593 fragments.append(zipped[-1][0])
594
595 dropped_packet_indexes = set(
596 index for (index, _, frags) in self.pkt_infos if len(frags) > 1
597 )
598
599 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100600 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200601 self.pg_start()
602
Klement Sekera4c533132018-02-22 11:41:12 +0100603 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +0200604 len(self.pkt_infos) - len(dropped_packet_indexes))
605 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +0100606 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200607
608 def test_timeout_inline(self):
609 """ timeout (inline) """
610
611 dropped_packet_indexes = set(
612 index for (index, frags, _) in self.pkt_infos if len(frags) > 1
613 )
614
615 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
616 expire_walk_interval_ms=10000, is_ip6=1)
617
618 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100619 self.src_if.add_stream(self.fragments_400)
Klement Sekera75e7d132017-09-20 08:26:30 +0200620 self.pg_start()
621
Klement Sekera4c533132018-02-22 11:41:12 +0100622 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +0200623 len(self.pkt_infos) - len(dropped_packet_indexes))
624 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +0100625 pkts = self.src_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +0200626 expected_count=len(dropped_packet_indexes))
627 for icmp in pkts:
628 self.assertIn(ICMPv6TimeExceeded, icmp)
629 self.assertIn(IPv6ExtHdrFragment, icmp)
630 self.assertIn(icmp[IPv6ExtHdrFragment].id, dropped_packet_indexes)
631 dropped_packet_indexes.remove(icmp[IPv6ExtHdrFragment].id)
632
633 def test_timeout_cleanup(self):
634 """ timeout (cleanup) """
635
636 # whole packets + fragmented packets sans last fragment
637 fragments = [
638 x for (_, frags_400, _) in self.pkt_infos
639 for x in frags_400[:-1 if len(frags_400) > 1 else None]
640 ]
641
642 # last fragments for fragmented packets
643 fragments2 = [frags_400[-1]
644 for (_, frags_400, _) in self.pkt_infos
645 if len(frags_400) > 1]
646
647 dropped_packet_indexes = set(
648 index for (index, frags_400, _) in self.pkt_infos
649 if len(frags_400) > 1)
650
651 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
652 expire_walk_interval_ms=50)
653
654 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
655 expire_walk_interval_ms=50, is_ip6=1)
656
657 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100658 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200659 self.pg_start()
660
661 self.sleep(.25, "wait before sending rest of fragments")
662
Klement Sekera4c533132018-02-22 11:41:12 +0100663 self.src_if.add_stream(fragments2)
Klement Sekera75e7d132017-09-20 08:26:30 +0200664 self.pg_start()
Klement Sekera75e7d132017-09-20 08:26:30 +0200665
Klement Sekera4c533132018-02-22 11:41:12 +0100666 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +0200667 len(self.pkt_infos) - len(dropped_packet_indexes))
668 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +0100669 pkts = self.src_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +0200670 expected_count=len(dropped_packet_indexes))
671 for icmp in pkts:
672 self.assertIn(ICMPv6TimeExceeded, icmp)
673 self.assertIn(IPv6ExtHdrFragment, icmp)
674 self.assertIn(icmp[IPv6ExtHdrFragment].id, dropped_packet_indexes)
675 dropped_packet_indexes.remove(icmp[IPv6ExtHdrFragment].id)
676
677 def test_disabled(self):
678 """ reassembly disabled """
679
680 dropped_packet_indexes = set(
681 index for (index, frags_400, _) in self.pkt_infos
682 if len(frags_400) > 1)
683
684 self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=0,
685 expire_walk_interval_ms=10000, is_ip6=1)
686
687 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100688 self.src_if.add_stream(self.fragments_400)
Klement Sekera75e7d132017-09-20 08:26:30 +0200689 self.pg_start()
690
Klement Sekera4c533132018-02-22 11:41:12 +0100691 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +0200692 len(self.pkt_infos) - len(dropped_packet_indexes))
693 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +0100694 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200695
696 def test_missing_upper(self):
697 """ missing upper layer """
Klement Sekera4c533132018-02-22 11:41:12 +0100698 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
699 IPv6(src=self.src_if.remote_ip6,
700 dst=self.src_if.local_ip6) /
701 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +0200702 Raw())
703 self.extend_packet(p, 1000, self.padding)
704 fragments = fragment_rfc8200(p, 1, 500)
705 bad_fragment = p.__class__(str(fragments[1]))
706 bad_fragment[IPv6ExtHdrFragment].nh = 59
707 bad_fragment[IPv6ExtHdrFragment].offset = 0
708 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100709 self.src_if.add_stream([bad_fragment])
Klement Sekera75e7d132017-09-20 08:26:30 +0200710 self.pg_start()
Klement Sekera4c533132018-02-22 11:41:12 +0100711 pkts = self.src_if.get_capture(expected_count=1)
Klement Sekera75e7d132017-09-20 08:26:30 +0200712 icmp = pkts[0]
713 self.assertIn(ICMPv6ParamProblem, icmp)
714 self.assert_equal(icmp[ICMPv6ParamProblem].code, 3, "ICMP code")
715
716 def test_invalid_frag_size(self):
717 """ fragment size not a multiple of 8 """
Klement Sekera4c533132018-02-22 11:41:12 +0100718 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
719 IPv6(src=self.src_if.remote_ip6,
720 dst=self.src_if.local_ip6) /
721 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +0200722 Raw())
723 self.extend_packet(p, 1000, self.padding)
724 fragments = fragment_rfc8200(p, 1, 500)
725 bad_fragment = fragments[0]
726 self.extend_packet(bad_fragment, len(bad_fragment) + 5)
727 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100728 self.src_if.add_stream([bad_fragment])
Klement Sekera75e7d132017-09-20 08:26:30 +0200729 self.pg_start()
Klement Sekera4c533132018-02-22 11:41:12 +0100730 pkts = self.src_if.get_capture(expected_count=1)
Klement Sekera75e7d132017-09-20 08:26:30 +0200731 icmp = pkts[0]
732 self.assertIn(ICMPv6ParamProblem, icmp)
733 self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code")
734
735 def test_invalid_packet_size(self):
736 """ total packet size > 65535 """
Klement Sekera4c533132018-02-22 11:41:12 +0100737 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
738 IPv6(src=self.src_if.remote_ip6,
739 dst=self.src_if.local_ip6) /
740 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +0200741 Raw())
742 self.extend_packet(p, 1000, self.padding)
743 fragments = fragment_rfc8200(p, 1, 500)
744 bad_fragment = fragments[1]
745 bad_fragment[IPv6ExtHdrFragment].offset = 65500
746 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100747 self.src_if.add_stream([bad_fragment])
Klement Sekera75e7d132017-09-20 08:26:30 +0200748 self.pg_start()
Klement Sekera4c533132018-02-22 11:41:12 +0100749 pkts = self.src_if.get_capture(expected_count=1)
Klement Sekera75e7d132017-09-20 08:26:30 +0200750 icmp = pkts[0]
751 self.assertIn(ICMPv6ParamProblem, icmp)
752 self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code")
753
754
Juraj Sloboda3048b632018-10-02 11:13:53 +0200755class TestIPv4ReassemblyLocalNode(VppTestCase):
756 """ IPv4 Reassembly for packets coming to ip4-local node """
757
758 @classmethod
759 def setUpClass(cls):
760 super(TestIPv4ReassemblyLocalNode, cls).setUpClass()
761
762 cls.create_pg_interfaces([0])
763 cls.src_dst_if = cls.pg0
764
765 # setup all interfaces
766 for i in cls.pg_interfaces:
767 i.admin_up()
768 i.config_ip4()
769 i.resolve_arp()
770
771 cls.padding = " abcdefghijklmn"
772 cls.create_stream()
773 cls.create_fragments()
774
775 def setUp(self):
776 """ Test setup - force timeout on existing reassemblies """
777 super(TestIPv4ReassemblyLocalNode, self).setUp()
778 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
779 expire_walk_interval_ms=10)
780 self.sleep(.25)
781 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
782 expire_walk_interval_ms=10000)
783
784 def tearDown(self):
785 super(TestIPv4ReassemblyLocalNode, self).tearDown()
786 self.logger.debug(self.vapi.ppcli("show ip4-reassembly details"))
787
788 @classmethod
789 def create_stream(cls, packet_count=test_packet_count):
790 """Create input packet stream for defined interface.
791
792 :param list packet_sizes: Required packet sizes.
793 """
794 for i in range(0, packet_count):
795 info = cls.create_packet_info(cls.src_dst_if, cls.src_dst_if)
796 payload = cls.info_to_payload(info)
797 p = (Ether(dst=cls.src_dst_if.local_mac,
798 src=cls.src_dst_if.remote_mac) /
799 IP(id=info.index, src=cls.src_dst_if.remote_ip4,
800 dst=cls.src_dst_if.local_ip4) /
801 ICMP(type='echo-request', id=1234) /
802 Raw(payload))
803 cls.extend_packet(p, 1518, cls.padding)
804 info.data = p
805
806 @classmethod
807 def create_fragments(cls):
808 infos = cls._packet_infos
809 cls.pkt_infos = []
Paul Vinciguerraf1f2aa62018-11-25 08:36:47 -0800810 for index, info in six.iteritems(infos):
Juraj Sloboda3048b632018-10-02 11:13:53 +0200811 p = info.data
812 # cls.logger.debug(ppp("Packet:", p.__class__(str(p))))
813 fragments_300 = fragment_rfc791(p, 300)
814 cls.pkt_infos.append((index, fragments_300))
815 cls.fragments_300 = [x for (_, frags) in cls.pkt_infos for x in frags]
816 cls.logger.debug("Fragmented %s packets into %s 300-byte fragments" %
817 (len(infos), len(cls.fragments_300)))
818
819 def verify_capture(self, capture):
820 """Verify captured packet stream.
821
822 :param list capture: Captured packet stream.
823 """
824 info = None
825 seen = set()
826 for packet in capture:
827 try:
828 self.logger.debug(ppp("Got packet:", packet))
829 ip = packet[IP]
830 icmp = packet[ICMP]
831 payload_info = self.payload_to_info(str(packet[Raw]))
832 packet_index = payload_info.index
833 if packet_index in seen:
834 raise Exception(ppp("Duplicate packet received", packet))
835 seen.add(packet_index)
836 self.assertEqual(payload_info.dst, self.src_dst_if.sw_if_index)
837 info = self._packet_infos[packet_index]
838 self.assertTrue(info is not None)
839 self.assertEqual(packet_index, info.index)
840 saved_packet = info.data
841 self.assertEqual(ip.src, saved_packet[IP].dst)
842 self.assertEqual(ip.dst, saved_packet[IP].src)
843 self.assertEqual(icmp.type, 0) # echo reply
844 self.assertEqual(icmp.id, saved_packet[ICMP].id)
845 self.assertEqual(icmp.payload, saved_packet[ICMP].payload)
846 except Exception:
847 self.logger.error(ppp("Unexpected or invalid packet:", packet))
848 raise
849 for index in self._packet_infos:
850 self.assertTrue(index in seen or index in dropped_packet_indexes,
851 "Packet with packet_index %d not received" % index)
852
853 def test_reassembly(self):
854 """ basic reassembly """
855
856 self.pg_enable_capture()
857 self.src_dst_if.add_stream(self.fragments_300)
858 self.pg_start()
859
860 packets = self.src_dst_if.get_capture(len(self.pkt_infos))
861 self.verify_capture(packets)
862
863 # run it all again to verify correctness
864 self.pg_enable_capture()
865 self.src_dst_if.add_stream(self.fragments_300)
866 self.pg_start()
867
868 packets = self.src_dst_if.get_capture(len(self.pkt_infos))
869 self.verify_capture(packets)
870
871
Klement Sekera75e7d132017-09-20 08:26:30 +0200872class TestFIFReassembly(VppTestCase):
873 """ Fragments in fragments reassembly """
874
875 @classmethod
876 def setUpClass(cls):
877 super(TestFIFReassembly, cls).setUpClass()
878
Klement Sekera4c533132018-02-22 11:41:12 +0100879 cls.create_pg_interfaces([0, 1])
880 cls.src_if = cls.pg0
881 cls.dst_if = cls.pg1
882 for i in cls.pg_interfaces:
883 i.admin_up()
884 i.config_ip4()
885 i.resolve_arp()
886 i.config_ip6()
887 i.resolve_ndp()
Klement Sekera75e7d132017-09-20 08:26:30 +0200888
Klement Sekera75e7d132017-09-20 08:26:30 +0200889 cls.packet_sizes = [64, 512, 1518, 9018]
890 cls.padding = " abcdefghijklmn"
891
892 def setUp(self):
893 """ Test setup - force timeout on existing reassemblies """
894 super(TestFIFReassembly, self).setUp()
Klement Sekera4c533132018-02-22 11:41:12 +0100895 self.vapi.ip_reassembly_enable_disable(
896 sw_if_index=self.src_if.sw_if_index, enable_ip4=True,
897 enable_ip6=True)
898 self.vapi.ip_reassembly_enable_disable(
899 sw_if_index=self.dst_if.sw_if_index, enable_ip4=True,
900 enable_ip6=True)
Klement Sekera75e7d132017-09-20 08:26:30 +0200901 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
902 expire_walk_interval_ms=10)
903 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
904 expire_walk_interval_ms=10, is_ip6=1)
905 self.sleep(.25)
906 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
907 expire_walk_interval_ms=10000)
908 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
909 expire_walk_interval_ms=10000, is_ip6=1)
910
911 def tearDown(self):
912 self.logger.debug(self.vapi.ppcli("show ip4-reassembly details"))
913 self.logger.debug(self.vapi.ppcli("show ip6-reassembly details"))
914 super(TestFIFReassembly, self).tearDown()
915
916 def verify_capture(self, capture, ip_class, dropped_packet_indexes=[]):
917 """Verify captured packet stream.
918
919 :param list capture: Captured packet stream.
920 """
921 info = None
922 seen = set()
923 for packet in capture:
924 try:
Klement Sekera4c533132018-02-22 11:41:12 +0100925 self.logger.debug(ppp("Got packet:", packet))
Klement Sekera75e7d132017-09-20 08:26:30 +0200926 ip = packet[ip_class]
927 udp = packet[UDP]
928 payload_info = self.payload_to_info(str(packet[Raw]))
929 packet_index = payload_info.index
930 self.assertTrue(
931 packet_index not in dropped_packet_indexes,
932 ppp("Packet received, but should be dropped:", packet))
933 if packet_index in seen:
934 raise Exception(ppp("Duplicate packet received", packet))
935 seen.add(packet_index)
Klement Sekera4c533132018-02-22 11:41:12 +0100936 self.assertEqual(payload_info.dst, self.dst_if.sw_if_index)
Klement Sekera75e7d132017-09-20 08:26:30 +0200937 info = self._packet_infos[packet_index]
938 self.assertTrue(info is not None)
939 self.assertEqual(packet_index, info.index)
940 saved_packet = info.data
941 self.assertEqual(ip.src, saved_packet[ip_class].src)
942 self.assertEqual(ip.dst, saved_packet[ip_class].dst)
943 self.assertEqual(udp.payload, saved_packet[UDP].payload)
Klement Sekera4c533132018-02-22 11:41:12 +0100944 except Exception:
Klement Sekera75e7d132017-09-20 08:26:30 +0200945 self.logger.error(ppp("Unexpected or invalid packet:", packet))
946 raise
947 for index in self._packet_infos:
948 self.assertTrue(index in seen or index in dropped_packet_indexes,
949 "Packet with packet_index %d not received" % index)
950
951 def test_fif4(self):
952 """ Fragments in fragments (4o4) """
953
954 # TODO this should be ideally in setUpClass, but then we hit a bug
955 # with VppIpRoute incorrectly reporting it's present when it's not
956 # so we need to manually remove the vpp config, thus we cannot have
957 # it shared for multiple test cases
958 self.tun_ip4 = "1.1.1.2"
959
Klement Sekera4c533132018-02-22 11:41:12 +0100960 self.gre4 = VppGreInterface(self, self.src_if.local_ip4, self.tun_ip4)
Klement Sekera75e7d132017-09-20 08:26:30 +0200961 self.gre4.add_vpp_config()
962 self.gre4.admin_up()
963 self.gre4.config_ip4()
964
Klement Sekera4c533132018-02-22 11:41:12 +0100965 self.vapi.ip_reassembly_enable_disable(
966 sw_if_index=self.gre4.sw_if_index, enable_ip4=True)
967
Klement Sekera75e7d132017-09-20 08:26:30 +0200968 self.route4 = VppIpRoute(self, self.tun_ip4, 32,
Klement Sekera4c533132018-02-22 11:41:12 +0100969 [VppRoutePath(self.src_if.remote_ip4,
970 self.src_if.sw_if_index)])
Klement Sekera75e7d132017-09-20 08:26:30 +0200971 self.route4.add_vpp_config()
972
973 self.reset_packet_infos()
974 for i in range(test_packet_count):
Klement Sekera4c533132018-02-22 11:41:12 +0100975 info = self.create_packet_info(self.src_if, self.dst_if)
Klement Sekera75e7d132017-09-20 08:26:30 +0200976 payload = self.info_to_payload(info)
Klement Sekera4c533132018-02-22 11:41:12 +0100977 # Ethernet header here is only for size calculation, thus it
978 # doesn't matter how it's initialized. This is to ensure that
979 # reassembled packet is not > 9000 bytes, so that it's not dropped
980 p = (Ether() /
981 IP(id=i, src=self.src_if.remote_ip4,
982 dst=self.dst_if.remote_ip4) /
983 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +0200984 Raw(payload))
985 size = self.packet_sizes[(i // 2) % len(self.packet_sizes)]
986 self.extend_packet(p, size, self.padding)
Klement Sekera4c533132018-02-22 11:41:12 +0100987 info.data = p[IP] # use only IP part, without ethernet header
Klement Sekera75e7d132017-09-20 08:26:30 +0200988
Paul Vinciguerraf1f2aa62018-11-25 08:36:47 -0800989 fragments = [x for _, p in six.iteritems(self._packet_infos)
Klement Sekera75e7d132017-09-20 08:26:30 +0200990 for x in fragment_rfc791(p.data, 400)]
991
992 encapped_fragments = \
Klement Sekera4c533132018-02-22 11:41:12 +0100993 [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
994 IP(src=self.tun_ip4, dst=self.src_if.local_ip4) /
Klement Sekera75e7d132017-09-20 08:26:30 +0200995 GRE() /
996 p
997 for p in fragments]
998
999 fragmented_encapped_fragments = \
1000 [x for p in encapped_fragments
1001 for x in fragment_rfc791(p, 200)]
1002
Klement Sekera4c533132018-02-22 11:41:12 +01001003 self.src_if.add_stream(fragmented_encapped_fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +02001004
1005 self.pg_enable_capture(self.pg_interfaces)
1006 self.pg_start()
1007
Klement Sekera4c533132018-02-22 11:41:12 +01001008 self.src_if.assert_nothing_captured()
1009 packets = self.dst_if.get_capture(len(self._packet_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +02001010 self.verify_capture(packets, IP)
1011
1012 # TODO remove gre vpp config by hand until VppIpRoute gets fixed
1013 # so that it's query_vpp_config() works as it should
1014 self.gre4.remove_vpp_config()
Klement Sekera4c533132018-02-22 11:41:12 +01001015 self.logger.debug(self.vapi.ppcli("show interface"))
Klement Sekera75e7d132017-09-20 08:26:30 +02001016
1017 def test_fif6(self):
1018 """ Fragments in fragments (6o6) """
1019 # TODO this should be ideally in setUpClass, but then we hit a bug
1020 # with VppIpRoute incorrectly reporting it's present when it's not
1021 # so we need to manually remove the vpp config, thus we cannot have
1022 # it shared for multiple test cases
1023 self.tun_ip6 = "1002::1"
1024
Klement Sekera4c533132018-02-22 11:41:12 +01001025 self.gre6 = VppGre6Interface(self, self.src_if.local_ip6, self.tun_ip6)
Klement Sekera75e7d132017-09-20 08:26:30 +02001026 self.gre6.add_vpp_config()
1027 self.gre6.admin_up()
1028 self.gre6.config_ip6()
1029
Klement Sekera4c533132018-02-22 11:41:12 +01001030 self.vapi.ip_reassembly_enable_disable(
1031 sw_if_index=self.gre6.sw_if_index, enable_ip6=True)
1032
Klement Sekera75e7d132017-09-20 08:26:30 +02001033 self.route6 = VppIpRoute(self, self.tun_ip6, 128,
Klement Sekera4c533132018-02-22 11:41:12 +01001034 [VppRoutePath(self.src_if.remote_ip6,
1035 self.src_if.sw_if_index,
Klement Sekera75e7d132017-09-20 08:26:30 +02001036 proto=DpoProto.DPO_PROTO_IP6)],
1037 is_ip6=1)
1038 self.route6.add_vpp_config()
1039
1040 self.reset_packet_infos()
1041 for i in range(test_packet_count):
Klement Sekera4c533132018-02-22 11:41:12 +01001042 info = self.create_packet_info(self.src_if, self.dst_if)
Klement Sekera75e7d132017-09-20 08:26:30 +02001043 payload = self.info_to_payload(info)
Klement Sekera4c533132018-02-22 11:41:12 +01001044 # Ethernet header here is only for size calculation, thus it
1045 # doesn't matter how it's initialized. This is to ensure that
1046 # reassembled packet is not > 9000 bytes, so that it's not dropped
1047 p = (Ether() /
1048 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1049 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +02001050 Raw(payload))
1051 size = self.packet_sizes[(i // 2) % len(self.packet_sizes)]
1052 self.extend_packet(p, size, self.padding)
Klement Sekera4c533132018-02-22 11:41:12 +01001053 info.data = p[IPv6] # use only IPv6 part, without ethernet header
Klement Sekera75e7d132017-09-20 08:26:30 +02001054
Paul Vinciguerraf1f2aa62018-11-25 08:36:47 -08001055 fragments = [x for _, i in six.iteritems(self._packet_infos)
Klement Sekera75e7d132017-09-20 08:26:30 +02001056 for x in fragment_rfc8200(
1057 i.data, i.index, 400)]
1058
1059 encapped_fragments = \
Klement Sekera4c533132018-02-22 11:41:12 +01001060 [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1061 IPv6(src=self.tun_ip6, dst=self.src_if.local_ip6) /
Klement Sekera75e7d132017-09-20 08:26:30 +02001062 GRE() /
1063 p
1064 for p in fragments]
1065
1066 fragmented_encapped_fragments = \
1067 [x for p in encapped_fragments for x in (
1068 fragment_rfc8200(
1069 p,
1070 2 * len(self._packet_infos) + p[IPv6ExtHdrFragment].id,
1071 200)
1072 if IPv6ExtHdrFragment in p else [p]
1073 )
1074 ]
1075
Klement Sekera4c533132018-02-22 11:41:12 +01001076 self.src_if.add_stream(fragmented_encapped_fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +02001077
1078 self.pg_enable_capture(self.pg_interfaces)
1079 self.pg_start()
1080
Klement Sekera4c533132018-02-22 11:41:12 +01001081 self.src_if.assert_nothing_captured()
1082 packets = self.dst_if.get_capture(len(self._packet_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +02001083 self.verify_capture(packets, IPv6)
1084
1085 # TODO remove gre vpp config by hand until VppIpRoute gets fixed
1086 # so that it's query_vpp_config() works as it should
Klement Sekera3ecc2212018-03-27 10:34:43 +02001087 self.gre6.remove_vpp_config()
Klement Sekera75e7d132017-09-20 08:26:30 +02001088
1089
1090if __name__ == '__main__':
1091 unittest.main(testRunner=VppTestRunner)