blob: d7cc627a318457fc0aaa61b162c2bd77560de32c [file] [log] [blame]
Klement Sekera75e7d132017-09-20 08:26:30 +02001#!/usr/bin/env python
2import unittest
3from random import shuffle
4
5from framework import VppTestCase, VppTestRunner
6
7from scapy.packet import Raw
8from scapy.layers.l2 import Ether, GRE
Juraj Sloboda3048b632018-10-02 11:13:53 +02009from scapy.layers.inet import IP, UDP, ICMP
Klement Sekera75e7d132017-09-20 08:26:30 +020010from util import ppp, fragment_rfc791, fragment_rfc8200
Klement Sekera75e7d132017-09-20 08:26:30 +020011from scapy.layers.inet6 import IPv6, IPv6ExtHdrFragment, ICMPv6ParamProblem,\
12 ICMPv6TimeExceeded
13from vpp_gre_interface import VppGreInterface, VppGre6Interface
Neale Rannsc0a93142018-09-05 15:42:26 -070014from vpp_ip import DpoProto
15from vpp_ip_route import VppIpRoute, VppRoutePath
Klement Sekera75e7d132017-09-20 08:26:30 +020016
17test_packet_count = 257
18
19
20class TestIPv4Reassembly(VppTestCase):
21 """ IPv4 Reassembly """
22
23 @classmethod
24 def setUpClass(cls):
25 super(TestIPv4Reassembly, cls).setUpClass()
26
Klement Sekera4c533132018-02-22 11:41:12 +010027 cls.create_pg_interfaces([0, 1])
28 cls.src_if = cls.pg0
29 cls.dst_if = cls.pg1
Klement Sekera75e7d132017-09-20 08:26:30 +020030
31 # setup all interfaces
32 for i in cls.pg_interfaces:
33 i.admin_up()
34 i.config_ip4()
35 i.resolve_arp()
36
Klement Sekera75e7d132017-09-20 08:26:30 +020037 # packet sizes
38 cls.packet_sizes = [64, 512, 1518, 9018]
39 cls.padding = " abcdefghijklmn"
40 cls.create_stream(cls.packet_sizes)
41 cls.create_fragments()
42
43 def setUp(self):
44 """ Test setup - force timeout on existing reassemblies """
45 super(TestIPv4Reassembly, self).setUp()
Klement Sekera4c533132018-02-22 11:41:12 +010046 self.vapi.ip_reassembly_enable_disable(
47 sw_if_index=self.src_if.sw_if_index, enable_ip4=True)
Klement Sekera75e7d132017-09-20 08:26:30 +020048 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
49 expire_walk_interval_ms=10)
50 self.sleep(.25)
51 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
52 expire_walk_interval_ms=10000)
53
54 def tearDown(self):
55 super(TestIPv4Reassembly, self).tearDown()
56 self.logger.debug(self.vapi.ppcli("show ip4-reassembly details"))
57
58 @classmethod
59 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
60 """Create input packet stream for defined interface.
61
62 :param list packet_sizes: Required packet sizes.
63 """
64 for i in range(0, packet_count):
Klement Sekera4c533132018-02-22 11:41:12 +010065 info = cls.create_packet_info(cls.src_if, cls.src_if)
Klement Sekera75e7d132017-09-20 08:26:30 +020066 payload = cls.info_to_payload(info)
Klement Sekera4c533132018-02-22 11:41:12 +010067 p = (Ether(dst=cls.src_if.local_mac, src=cls.src_if.remote_mac) /
68 IP(id=info.index, src=cls.src_if.remote_ip4,
69 dst=cls.dst_if.remote_ip4) /
70 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +020071 Raw(payload))
72 size = packet_sizes[(i // 2) % len(packet_sizes)]
73 cls.extend_packet(p, size, cls.padding)
74 info.data = p
75
76 @classmethod
77 def create_fragments(cls):
78 infos = cls._packet_infos
79 cls.pkt_infos = []
80 for index, info in infos.iteritems():
81 p = info.data
Klement Sekera4c533132018-02-22 11:41:12 +010082 # cls.logger.debug(ppp("Packet:", p.__class__(str(p))))
Klement Sekera75e7d132017-09-20 08:26:30 +020083 fragments_400 = fragment_rfc791(p, 400)
84 fragments_300 = fragment_rfc791(p, 300)
85 fragments_200 = [
86 x for f in fragments_400 for x in fragment_rfc791(f, 200)]
87 cls.pkt_infos.append(
88 (index, fragments_400, fragments_300, fragments_200))
89 cls.fragments_400 = [
90 x for (_, frags, _, _) in cls.pkt_infos for x in frags]
91 cls.fragments_300 = [
92 x for (_, _, frags, _) in cls.pkt_infos for x in frags]
93 cls.fragments_200 = [
94 x for (_, _, _, frags) in cls.pkt_infos for x in frags]
95 cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, "
96 "%s 300-byte fragments and %s 200-byte fragments" %
97 (len(infos), len(cls.fragments_400),
98 len(cls.fragments_300), len(cls.fragments_200)))
99
100 def verify_capture(self, capture, dropped_packet_indexes=[]):
101 """Verify captured packet stream.
102
103 :param list capture: Captured packet stream.
104 """
105 info = None
106 seen = set()
107 for packet in capture:
108 try:
Klement Sekera4c533132018-02-22 11:41:12 +0100109 self.logger.debug(ppp("Got packet:", packet))
Klement Sekera75e7d132017-09-20 08:26:30 +0200110 ip = packet[IP]
111 udp = packet[UDP]
112 payload_info = self.payload_to_info(str(packet[Raw]))
113 packet_index = payload_info.index
114 self.assertTrue(
115 packet_index not in dropped_packet_indexes,
116 ppp("Packet received, but should be dropped:", packet))
117 if packet_index in seen:
118 raise Exception(ppp("Duplicate packet received", packet))
119 seen.add(packet_index)
Klement Sekera4c533132018-02-22 11:41:12 +0100120 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
Klement Sekera75e7d132017-09-20 08:26:30 +0200121 info = self._packet_infos[packet_index]
122 self.assertTrue(info is not None)
123 self.assertEqual(packet_index, info.index)
124 saved_packet = info.data
125 self.assertEqual(ip.src, saved_packet[IP].src)
126 self.assertEqual(ip.dst, saved_packet[IP].dst)
127 self.assertEqual(udp.payload, saved_packet[UDP].payload)
Klement Sekera4c533132018-02-22 11:41:12 +0100128 except Exception:
Klement Sekera75e7d132017-09-20 08:26:30 +0200129 self.logger.error(ppp("Unexpected or invalid packet:", packet))
130 raise
131 for index in self._packet_infos:
132 self.assertTrue(index in seen or index in dropped_packet_indexes,
133 "Packet with packet_index %d not received" % index)
134
135 def test_reassembly(self):
136 """ basic reassembly """
137
138 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100139 self.src_if.add_stream(self.fragments_200)
Klement Sekera75e7d132017-09-20 08:26:30 +0200140 self.pg_start()
141
Klement Sekera4c533132018-02-22 11:41:12 +0100142 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200143 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100144 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200145
146 # run it all again to verify correctness
147 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100148 self.src_if.add_stream(self.fragments_200)
Klement Sekera75e7d132017-09-20 08:26:30 +0200149 self.pg_start()
150
Klement Sekera4c533132018-02-22 11:41:12 +0100151 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200152 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100153 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200154
155 def test_reversed(self):
156 """ reverse order reassembly """
157
158 fragments = list(self.fragments_200)
159 fragments.reverse()
160
161 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100162 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200163 self.pg_start()
164
Klement Sekera4c533132018-02-22 11:41:12 +0100165 packets = self.dst_if.get_capture(len(self.packet_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200166 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100167 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200168
169 # run it all again to verify correctness
170 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100171 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200172 self.pg_start()
173
Klement Sekera4c533132018-02-22 11:41:12 +0100174 packets = self.dst_if.get_capture(len(self.packet_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200175 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100176 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200177
178 def test_random(self):
179 """ random order reassembly """
180
181 fragments = list(self.fragments_200)
182 shuffle(fragments)
183
184 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100185 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200186 self.pg_start()
187
Klement Sekera4c533132018-02-22 11:41:12 +0100188 packets = self.dst_if.get_capture(len(self.packet_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200189 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100190 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200191
192 # run it all again to verify correctness
193 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100194 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200195 self.pg_start()
196
Klement Sekera4c533132018-02-22 11:41:12 +0100197 packets = self.dst_if.get_capture(len(self.packet_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200198 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100199 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200200
201 def test_duplicates(self):
202 """ duplicate fragments """
203
204 fragments = [
205 x for (_, frags, _, _) in self.pkt_infos
206 for x in frags
207 for _ in range(0, min(2, len(frags)))
208 ]
209
210 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100211 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200212 self.pg_start()
213
Klement Sekera4c533132018-02-22 11:41:12 +0100214 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200215 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100216 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200217
218 def test_overlap1(self):
219 """ overlapping fragments case #1 """
220
221 fragments = []
222 for _, _, frags_300, frags_200 in self.pkt_infos:
223 if len(frags_300) == 1:
224 fragments.extend(frags_300)
225 else:
226 for i, j in zip(frags_200, frags_300):
227 fragments.extend(i)
228 fragments.extend(j)
229
230 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100231 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200232 self.pg_start()
233
Klement Sekera4c533132018-02-22 11:41:12 +0100234 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200235 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100236 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200237
238 # run it all to verify correctness
239 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100240 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200241 self.pg_start()
242
Klement Sekera4c533132018-02-22 11:41:12 +0100243 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200244 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100245 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200246
247 def test_overlap2(self):
248 """ overlapping fragments case #2 """
249
250 fragments = []
251 for _, _, frags_300, frags_200 in self.pkt_infos:
252 if len(frags_300) == 1:
253 fragments.extend(frags_300)
254 else:
255 # care must be taken here so that there are no fragments
256 # received by vpp after reassembly is finished, otherwise
257 # new reassemblies will be started and packet generator will
258 # freak out when it detects unfreed buffers
259 zipped = zip(frags_300, frags_200)
260 for i, j in zipped[:-1]:
261 fragments.extend(i)
262 fragments.extend(j)
263 fragments.append(zipped[-1][0])
264
265 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100266 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200267 self.pg_start()
268
Klement Sekera4c533132018-02-22 11:41:12 +0100269 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200270 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100271 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200272
273 # run it all to verify correctness
274 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100275 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200276 self.pg_start()
277
Klement Sekera4c533132018-02-22 11:41:12 +0100278 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200279 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100280 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200281
282 def test_timeout_inline(self):
283 """ timeout (inline) """
284
285 dropped_packet_indexes = set(
286 index for (index, frags, _, _) in self.pkt_infos if len(frags) > 1
287 )
288
289 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
290 expire_walk_interval_ms=10000)
291
292 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100293 self.src_if.add_stream(self.fragments_400)
Klement Sekera75e7d132017-09-20 08:26:30 +0200294 self.pg_start()
295
Klement Sekera4c533132018-02-22 11:41:12 +0100296 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +0200297 len(self.pkt_infos) - len(dropped_packet_indexes))
298 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +0100299 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200300
301 def test_timeout_cleanup(self):
302 """ timeout (cleanup) """
303
304 # whole packets + fragmented packets sans last fragment
305 fragments = [
306 x for (_, frags_400, _, _) in self.pkt_infos
307 for x in frags_400[:-1 if len(frags_400) > 1 else None]
308 ]
309
310 # last fragments for fragmented packets
311 fragments2 = [frags_400[-1]
312 for (_, frags_400, _, _) in self.pkt_infos
313 if len(frags_400) > 1]
314
315 dropped_packet_indexes = set(
316 index for (index, frags_400, _, _) in self.pkt_infos
317 if len(frags_400) > 1)
318
319 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
320 expire_walk_interval_ms=50)
321
322 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100323 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200324 self.pg_start()
325
326 self.sleep(.25, "wait before sending rest of fragments")
327
Klement Sekera4c533132018-02-22 11:41:12 +0100328 self.src_if.add_stream(fragments2)
Klement Sekera75e7d132017-09-20 08:26:30 +0200329 self.pg_start()
Klement Sekera75e7d132017-09-20 08:26:30 +0200330
Klement Sekera4c533132018-02-22 11:41:12 +0100331 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +0200332 len(self.pkt_infos) - len(dropped_packet_indexes))
333 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +0100334 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200335
336 def test_disabled(self):
337 """ reassembly disabled """
338
339 dropped_packet_indexes = set(
340 index for (index, frags_400, _, _) in self.pkt_infos
341 if len(frags_400) > 1)
342
343 self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=0,
344 expire_walk_interval_ms=10000)
345
346 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100347 self.src_if.add_stream(self.fragments_400)
Klement Sekera75e7d132017-09-20 08:26:30 +0200348 self.pg_start()
349
Klement Sekera4c533132018-02-22 11:41:12 +0100350 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +0200351 len(self.pkt_infos) - len(dropped_packet_indexes))
352 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +0100353 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200354
355
356class TestIPv6Reassembly(VppTestCase):
357 """ IPv6 Reassembly """
358
359 @classmethod
360 def setUpClass(cls):
361 super(TestIPv6Reassembly, cls).setUpClass()
362
Klement Sekera4c533132018-02-22 11:41:12 +0100363 cls.create_pg_interfaces([0, 1])
364 cls.src_if = cls.pg0
365 cls.dst_if = cls.pg1
Klement Sekera75e7d132017-09-20 08:26:30 +0200366
367 # setup all interfaces
368 for i in cls.pg_interfaces:
369 i.admin_up()
370 i.config_ip6()
371 i.resolve_ndp()
372
Klement Sekera75e7d132017-09-20 08:26:30 +0200373 # packet sizes
374 cls.packet_sizes = [64, 512, 1518, 9018]
375 cls.padding = " abcdefghijklmn"
376 cls.create_stream(cls.packet_sizes)
377 cls.create_fragments()
378
379 def setUp(self):
380 """ Test setup - force timeout on existing reassemblies """
381 super(TestIPv6Reassembly, self).setUp()
Klement Sekera4c533132018-02-22 11:41:12 +0100382 self.vapi.ip_reassembly_enable_disable(
383 sw_if_index=self.src_if.sw_if_index, enable_ip6=True)
Klement Sekera75e7d132017-09-20 08:26:30 +0200384 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
385 expire_walk_interval_ms=10, is_ip6=1)
386 self.sleep(.25)
387 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
388 expire_walk_interval_ms=10000, is_ip6=1)
Klement Sekera4c533132018-02-22 11:41:12 +0100389 self.logger.debug(self.vapi.ppcli("show ip6-reassembly details"))
Klement Sekera75e7d132017-09-20 08:26:30 +0200390
391 def tearDown(self):
392 super(TestIPv6Reassembly, self).tearDown()
393 self.logger.debug(self.vapi.ppcli("show ip6-reassembly details"))
394
395 @classmethod
396 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
397 """Create input packet stream for defined interface.
398
399 :param list packet_sizes: Required packet sizes.
400 """
401 for i in range(0, packet_count):
Klement Sekera4c533132018-02-22 11:41:12 +0100402 info = cls.create_packet_info(cls.src_if, cls.src_if)
Klement Sekera75e7d132017-09-20 08:26:30 +0200403 payload = cls.info_to_payload(info)
Klement Sekera4c533132018-02-22 11:41:12 +0100404 p = (Ether(dst=cls.src_if.local_mac, src=cls.src_if.remote_mac) /
405 IPv6(src=cls.src_if.remote_ip6,
406 dst=cls.dst_if.remote_ip6) /
407 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +0200408 Raw(payload))
409 size = packet_sizes[(i // 2) % len(packet_sizes)]
410 cls.extend_packet(p, size, cls.padding)
411 info.data = p
412
413 @classmethod
414 def create_fragments(cls):
415 infos = cls._packet_infos
416 cls.pkt_infos = []
417 for index, info in infos.iteritems():
418 p = info.data
Klement Sekera4c533132018-02-22 11:41:12 +0100419 # cls.logger.debug(ppp("Packet:", p.__class__(str(p))))
Klement Sekera75e7d132017-09-20 08:26:30 +0200420 fragments_400 = fragment_rfc8200(p, info.index, 400)
421 fragments_300 = fragment_rfc8200(p, info.index, 300)
422 cls.pkt_infos.append((index, fragments_400, fragments_300))
423 cls.fragments_400 = [
424 x for _, frags, _ in cls.pkt_infos for x in frags]
425 cls.fragments_300 = [
426 x for _, _, frags in cls.pkt_infos for x in frags]
427 cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, "
428 "and %s 300-byte fragments" %
429 (len(infos), len(cls.fragments_400),
430 len(cls.fragments_300)))
431
432 def verify_capture(self, capture, dropped_packet_indexes=[]):
433 """Verify captured packet strea .
434
435 :param list capture: Captured packet stream.
436 """
437 info = None
438 seen = set()
439 for packet in capture:
440 try:
Klement Sekera4c533132018-02-22 11:41:12 +0100441 self.logger.debug(ppp("Got packet:", packet))
Klement Sekera75e7d132017-09-20 08:26:30 +0200442 ip = packet[IPv6]
443 udp = packet[UDP]
444 payload_info = self.payload_to_info(str(packet[Raw]))
445 packet_index = payload_info.index
446 self.assertTrue(
447 packet_index not in dropped_packet_indexes,
448 ppp("Packet received, but should be dropped:", packet))
449 if packet_index in seen:
450 raise Exception(ppp("Duplicate packet received", packet))
451 seen.add(packet_index)
Klement Sekera4c533132018-02-22 11:41:12 +0100452 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
Klement Sekera75e7d132017-09-20 08:26:30 +0200453 info = self._packet_infos[packet_index]
454 self.assertTrue(info is not None)
455 self.assertEqual(packet_index, info.index)
456 saved_packet = info.data
457 self.assertEqual(ip.src, saved_packet[IPv6].src)
458 self.assertEqual(ip.dst, saved_packet[IPv6].dst)
459 self.assertEqual(udp.payload, saved_packet[UDP].payload)
Klement Sekera4c533132018-02-22 11:41:12 +0100460 except Exception:
Klement Sekera75e7d132017-09-20 08:26:30 +0200461 self.logger.error(ppp("Unexpected or invalid packet:", packet))
462 raise
463 for index in self._packet_infos:
464 self.assertTrue(index in seen or index in dropped_packet_indexes,
465 "Packet with packet_index %d not received" % index)
466
467 def test_reassembly(self):
468 """ basic reassembly """
469
470 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100471 self.src_if.add_stream(self.fragments_400)
Klement Sekera75e7d132017-09-20 08:26:30 +0200472 self.pg_start()
473
Klement Sekera4c533132018-02-22 11:41:12 +0100474 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200475 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100476 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200477
478 # run it all again to verify correctness
479 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100480 self.src_if.add_stream(self.fragments_400)
Klement Sekera75e7d132017-09-20 08:26:30 +0200481 self.pg_start()
482
Klement Sekera4c533132018-02-22 11:41:12 +0100483 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200484 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100485 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200486
487 def test_reversed(self):
488 """ reverse order reassembly """
489
490 fragments = list(self.fragments_400)
491 fragments.reverse()
492
493 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100494 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200495 self.pg_start()
496
Klement Sekera4c533132018-02-22 11:41:12 +0100497 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200498 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100499 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200500
501 # run it all again to verify correctness
502 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100503 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200504 self.pg_start()
505
Klement Sekera4c533132018-02-22 11:41:12 +0100506 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200507 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100508 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200509
510 def test_random(self):
511 """ random order reassembly """
512
513 fragments = list(self.fragments_400)
514 shuffle(fragments)
515
516 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100517 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200518 self.pg_start()
519
Klement Sekera4c533132018-02-22 11:41:12 +0100520 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200521 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100522 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200523
524 # run it all again to verify correctness
525 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100526 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200527 self.pg_start()
528
Klement Sekera4c533132018-02-22 11:41:12 +0100529 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200530 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100531 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200532
533 def test_duplicates(self):
534 """ duplicate fragments """
535
536 fragments = [
537 x for (_, frags, _) in self.pkt_infos
538 for x in frags
539 for _ in range(0, min(2, len(frags)))
540 ]
541
542 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100543 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200544 self.pg_start()
545
Klement Sekera4c533132018-02-22 11:41:12 +0100546 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200547 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100548 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200549
550 def test_overlap1(self):
551 """ overlapping fragments case #1 """
552
553 fragments = []
554 for _, frags_400, frags_300 in self.pkt_infos:
555 if len(frags_300) == 1:
556 fragments.extend(frags_400)
557 else:
558 for i, j in zip(frags_300, frags_400):
559 fragments.extend(i)
560 fragments.extend(j)
561
562 dropped_packet_indexes = set(
563 index for (index, _, frags) in self.pkt_infos if len(frags) > 1
564 )
565
566 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100567 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200568 self.pg_start()
569
Klement Sekera4c533132018-02-22 11:41:12 +0100570 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +0200571 len(self.pkt_infos) - len(dropped_packet_indexes))
572 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +0100573 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200574
575 def test_overlap2(self):
576 """ overlapping fragments case #2 """
577
578 fragments = []
Klement Sekera4c533132018-02-22 11:41:12 +0100579 for _, frags_400, frags_300 in self.pkt_infos:
Klement Sekera75e7d132017-09-20 08:26:30 +0200580 if len(frags_400) == 1:
581 fragments.extend(frags_400)
582 else:
583 # care must be taken here so that there are no fragments
584 # received by vpp after reassembly is finished, otherwise
585 # new reassemblies will be started and packet generator will
586 # freak out when it detects unfreed buffers
Klement Sekera4c533132018-02-22 11:41:12 +0100587 zipped = zip(frags_400, frags_300)
Klement Sekera75e7d132017-09-20 08:26:30 +0200588 for i, j in zipped[:-1]:
589 fragments.extend(i)
590 fragments.extend(j)
591 fragments.append(zipped[-1][0])
592
593 dropped_packet_indexes = set(
594 index for (index, _, frags) in self.pkt_infos if len(frags) > 1
595 )
596
597 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100598 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200599 self.pg_start()
600
Klement Sekera4c533132018-02-22 11:41:12 +0100601 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +0200602 len(self.pkt_infos) - len(dropped_packet_indexes))
603 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +0100604 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200605
606 def test_timeout_inline(self):
607 """ timeout (inline) """
608
609 dropped_packet_indexes = set(
610 index for (index, frags, _) in self.pkt_infos if len(frags) > 1
611 )
612
613 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
614 expire_walk_interval_ms=10000, is_ip6=1)
615
616 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100617 self.src_if.add_stream(self.fragments_400)
Klement Sekera75e7d132017-09-20 08:26:30 +0200618 self.pg_start()
619
Klement Sekera4c533132018-02-22 11:41:12 +0100620 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +0200621 len(self.pkt_infos) - len(dropped_packet_indexes))
622 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +0100623 pkts = self.src_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +0200624 expected_count=len(dropped_packet_indexes))
625 for icmp in pkts:
626 self.assertIn(ICMPv6TimeExceeded, icmp)
627 self.assertIn(IPv6ExtHdrFragment, icmp)
628 self.assertIn(icmp[IPv6ExtHdrFragment].id, dropped_packet_indexes)
629 dropped_packet_indexes.remove(icmp[IPv6ExtHdrFragment].id)
630
631 def test_timeout_cleanup(self):
632 """ timeout (cleanup) """
633
634 # whole packets + fragmented packets sans last fragment
635 fragments = [
636 x for (_, frags_400, _) in self.pkt_infos
637 for x in frags_400[:-1 if len(frags_400) > 1 else None]
638 ]
639
640 # last fragments for fragmented packets
641 fragments2 = [frags_400[-1]
642 for (_, frags_400, _) in self.pkt_infos
643 if len(frags_400) > 1]
644
645 dropped_packet_indexes = set(
646 index for (index, frags_400, _) in self.pkt_infos
647 if len(frags_400) > 1)
648
649 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
650 expire_walk_interval_ms=50)
651
652 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
653 expire_walk_interval_ms=50, is_ip6=1)
654
655 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100656 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200657 self.pg_start()
658
659 self.sleep(.25, "wait before sending rest of fragments")
660
Klement Sekera4c533132018-02-22 11:41:12 +0100661 self.src_if.add_stream(fragments2)
Klement Sekera75e7d132017-09-20 08:26:30 +0200662 self.pg_start()
Klement Sekera75e7d132017-09-20 08:26:30 +0200663
Klement Sekera4c533132018-02-22 11:41:12 +0100664 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +0200665 len(self.pkt_infos) - len(dropped_packet_indexes))
666 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +0100667 pkts = self.src_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +0200668 expected_count=len(dropped_packet_indexes))
669 for icmp in pkts:
670 self.assertIn(ICMPv6TimeExceeded, icmp)
671 self.assertIn(IPv6ExtHdrFragment, icmp)
672 self.assertIn(icmp[IPv6ExtHdrFragment].id, dropped_packet_indexes)
673 dropped_packet_indexes.remove(icmp[IPv6ExtHdrFragment].id)
674
675 def test_disabled(self):
676 """ reassembly disabled """
677
678 dropped_packet_indexes = set(
679 index for (index, frags_400, _) in self.pkt_infos
680 if len(frags_400) > 1)
681
682 self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=0,
683 expire_walk_interval_ms=10000, is_ip6=1)
684
685 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100686 self.src_if.add_stream(self.fragments_400)
Klement Sekera75e7d132017-09-20 08:26:30 +0200687 self.pg_start()
688
Klement Sekera4c533132018-02-22 11:41:12 +0100689 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +0200690 len(self.pkt_infos) - len(dropped_packet_indexes))
691 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +0100692 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200693
694 def test_missing_upper(self):
695 """ missing upper layer """
Klement Sekera4c533132018-02-22 11:41:12 +0100696 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
697 IPv6(src=self.src_if.remote_ip6,
698 dst=self.src_if.local_ip6) /
699 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +0200700 Raw())
701 self.extend_packet(p, 1000, self.padding)
702 fragments = fragment_rfc8200(p, 1, 500)
703 bad_fragment = p.__class__(str(fragments[1]))
704 bad_fragment[IPv6ExtHdrFragment].nh = 59
705 bad_fragment[IPv6ExtHdrFragment].offset = 0
706 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100707 self.src_if.add_stream([bad_fragment])
Klement Sekera75e7d132017-09-20 08:26:30 +0200708 self.pg_start()
Klement Sekera4c533132018-02-22 11:41:12 +0100709 pkts = self.src_if.get_capture(expected_count=1)
Klement Sekera75e7d132017-09-20 08:26:30 +0200710 icmp = pkts[0]
711 self.assertIn(ICMPv6ParamProblem, icmp)
712 self.assert_equal(icmp[ICMPv6ParamProblem].code, 3, "ICMP code")
713
714 def test_invalid_frag_size(self):
715 """ fragment size not a multiple of 8 """
Klement Sekera4c533132018-02-22 11:41:12 +0100716 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
717 IPv6(src=self.src_if.remote_ip6,
718 dst=self.src_if.local_ip6) /
719 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +0200720 Raw())
721 self.extend_packet(p, 1000, self.padding)
722 fragments = fragment_rfc8200(p, 1, 500)
723 bad_fragment = fragments[0]
724 self.extend_packet(bad_fragment, len(bad_fragment) + 5)
725 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100726 self.src_if.add_stream([bad_fragment])
Klement Sekera75e7d132017-09-20 08:26:30 +0200727 self.pg_start()
Klement Sekera4c533132018-02-22 11:41:12 +0100728 pkts = self.src_if.get_capture(expected_count=1)
Klement Sekera75e7d132017-09-20 08:26:30 +0200729 icmp = pkts[0]
730 self.assertIn(ICMPv6ParamProblem, icmp)
731 self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code")
732
733 def test_invalid_packet_size(self):
734 """ total packet size > 65535 """
Klement Sekera4c533132018-02-22 11:41:12 +0100735 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
736 IPv6(src=self.src_if.remote_ip6,
737 dst=self.src_if.local_ip6) /
738 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +0200739 Raw())
740 self.extend_packet(p, 1000, self.padding)
741 fragments = fragment_rfc8200(p, 1, 500)
742 bad_fragment = fragments[1]
743 bad_fragment[IPv6ExtHdrFragment].offset = 65500
744 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100745 self.src_if.add_stream([bad_fragment])
Klement Sekera75e7d132017-09-20 08:26:30 +0200746 self.pg_start()
Klement Sekera4c533132018-02-22 11:41:12 +0100747 pkts = self.src_if.get_capture(expected_count=1)
Klement Sekera75e7d132017-09-20 08:26:30 +0200748 icmp = pkts[0]
749 self.assertIn(ICMPv6ParamProblem, icmp)
750 self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code")
751
752
Juraj Sloboda3048b632018-10-02 11:13:53 +0200753class TestIPv4ReassemblyLocalNode(VppTestCase):
754 """ IPv4 Reassembly for packets coming to ip4-local node """
755
756 @classmethod
757 def setUpClass(cls):
758 super(TestIPv4ReassemblyLocalNode, cls).setUpClass()
759
760 cls.create_pg_interfaces([0])
761 cls.src_dst_if = cls.pg0
762
763 # setup all interfaces
764 for i in cls.pg_interfaces:
765 i.admin_up()
766 i.config_ip4()
767 i.resolve_arp()
768
769 cls.padding = " abcdefghijklmn"
770 cls.create_stream()
771 cls.create_fragments()
772
773 def setUp(self):
774 """ Test setup - force timeout on existing reassemblies """
775 super(TestIPv4ReassemblyLocalNode, self).setUp()
776 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
777 expire_walk_interval_ms=10)
778 self.sleep(.25)
779 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
780 expire_walk_interval_ms=10000)
781
782 def tearDown(self):
783 super(TestIPv4ReassemblyLocalNode, self).tearDown()
784 self.logger.debug(self.vapi.ppcli("show ip4-reassembly details"))
785
786 @classmethod
787 def create_stream(cls, packet_count=test_packet_count):
788 """Create input packet stream for defined interface.
789
790 :param list packet_sizes: Required packet sizes.
791 """
792 for i in range(0, packet_count):
793 info = cls.create_packet_info(cls.src_dst_if, cls.src_dst_if)
794 payload = cls.info_to_payload(info)
795 p = (Ether(dst=cls.src_dst_if.local_mac,
796 src=cls.src_dst_if.remote_mac) /
797 IP(id=info.index, src=cls.src_dst_if.remote_ip4,
798 dst=cls.src_dst_if.local_ip4) /
799 ICMP(type='echo-request', id=1234) /
800 Raw(payload))
801 cls.extend_packet(p, 1518, cls.padding)
802 info.data = p
803
804 @classmethod
805 def create_fragments(cls):
806 infos = cls._packet_infos
807 cls.pkt_infos = []
808 for index, info in infos.iteritems():
809 p = info.data
810 # cls.logger.debug(ppp("Packet:", p.__class__(str(p))))
811 fragments_300 = fragment_rfc791(p, 300)
812 cls.pkt_infos.append((index, fragments_300))
813 cls.fragments_300 = [x for (_, frags) in cls.pkt_infos for x in frags]
814 cls.logger.debug("Fragmented %s packets into %s 300-byte fragments" %
815 (len(infos), len(cls.fragments_300)))
816
817 def verify_capture(self, capture):
818 """Verify captured packet stream.
819
820 :param list capture: Captured packet stream.
821 """
822 info = None
823 seen = set()
824 for packet in capture:
825 try:
826 self.logger.debug(ppp("Got packet:", packet))
827 ip = packet[IP]
828 icmp = packet[ICMP]
829 payload_info = self.payload_to_info(str(packet[Raw]))
830 packet_index = payload_info.index
831 if packet_index in seen:
832 raise Exception(ppp("Duplicate packet received", packet))
833 seen.add(packet_index)
834 self.assertEqual(payload_info.dst, self.src_dst_if.sw_if_index)
835 info = self._packet_infos[packet_index]
836 self.assertTrue(info is not None)
837 self.assertEqual(packet_index, info.index)
838 saved_packet = info.data
839 self.assertEqual(ip.src, saved_packet[IP].dst)
840 self.assertEqual(ip.dst, saved_packet[IP].src)
841 self.assertEqual(icmp.type, 0) # echo reply
842 self.assertEqual(icmp.id, saved_packet[ICMP].id)
843 self.assertEqual(icmp.payload, saved_packet[ICMP].payload)
844 except Exception:
845 self.logger.error(ppp("Unexpected or invalid packet:", packet))
846 raise
847 for index in self._packet_infos:
848 self.assertTrue(index in seen or index in dropped_packet_indexes,
849 "Packet with packet_index %d not received" % index)
850
851 def test_reassembly(self):
852 """ basic reassembly """
853
854 self.pg_enable_capture()
855 self.src_dst_if.add_stream(self.fragments_300)
856 self.pg_start()
857
858 packets = self.src_dst_if.get_capture(len(self.pkt_infos))
859 self.verify_capture(packets)
860
861 # run it all again to verify correctness
862 self.pg_enable_capture()
863 self.src_dst_if.add_stream(self.fragments_300)
864 self.pg_start()
865
866 packets = self.src_dst_if.get_capture(len(self.pkt_infos))
867 self.verify_capture(packets)
868
869
Klement Sekera75e7d132017-09-20 08:26:30 +0200870class TestFIFReassembly(VppTestCase):
871 """ Fragments in fragments reassembly """
872
873 @classmethod
874 def setUpClass(cls):
875 super(TestFIFReassembly, cls).setUpClass()
876
Klement Sekera4c533132018-02-22 11:41:12 +0100877 cls.create_pg_interfaces([0, 1])
878 cls.src_if = cls.pg0
879 cls.dst_if = cls.pg1
880 for i in cls.pg_interfaces:
881 i.admin_up()
882 i.config_ip4()
883 i.resolve_arp()
884 i.config_ip6()
885 i.resolve_ndp()
Klement Sekera75e7d132017-09-20 08:26:30 +0200886
Klement Sekera75e7d132017-09-20 08:26:30 +0200887 cls.packet_sizes = [64, 512, 1518, 9018]
888 cls.padding = " abcdefghijklmn"
889
890 def setUp(self):
891 """ Test setup - force timeout on existing reassemblies """
892 super(TestFIFReassembly, self).setUp()
Klement Sekera4c533132018-02-22 11:41:12 +0100893 self.vapi.ip_reassembly_enable_disable(
894 sw_if_index=self.src_if.sw_if_index, enable_ip4=True,
895 enable_ip6=True)
896 self.vapi.ip_reassembly_enable_disable(
897 sw_if_index=self.dst_if.sw_if_index, enable_ip4=True,
898 enable_ip6=True)
Klement Sekera75e7d132017-09-20 08:26:30 +0200899 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
900 expire_walk_interval_ms=10)
901 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
902 expire_walk_interval_ms=10, is_ip6=1)
903 self.sleep(.25)
904 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
905 expire_walk_interval_ms=10000)
906 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
907 expire_walk_interval_ms=10000, is_ip6=1)
908
909 def tearDown(self):
910 self.logger.debug(self.vapi.ppcli("show ip4-reassembly details"))
911 self.logger.debug(self.vapi.ppcli("show ip6-reassembly details"))
912 super(TestFIFReassembly, self).tearDown()
913
914 def verify_capture(self, capture, ip_class, dropped_packet_indexes=[]):
915 """Verify captured packet stream.
916
917 :param list capture: Captured packet stream.
918 """
919 info = None
920 seen = set()
921 for packet in capture:
922 try:
Klement Sekera4c533132018-02-22 11:41:12 +0100923 self.logger.debug(ppp("Got packet:", packet))
Klement Sekera75e7d132017-09-20 08:26:30 +0200924 ip = packet[ip_class]
925 udp = packet[UDP]
926 payload_info = self.payload_to_info(str(packet[Raw]))
927 packet_index = payload_info.index
928 self.assertTrue(
929 packet_index not in dropped_packet_indexes,
930 ppp("Packet received, but should be dropped:", packet))
931 if packet_index in seen:
932 raise Exception(ppp("Duplicate packet received", packet))
933 seen.add(packet_index)
Klement Sekera4c533132018-02-22 11:41:12 +0100934 self.assertEqual(payload_info.dst, self.dst_if.sw_if_index)
Klement Sekera75e7d132017-09-20 08:26:30 +0200935 info = self._packet_infos[packet_index]
936 self.assertTrue(info is not None)
937 self.assertEqual(packet_index, info.index)
938 saved_packet = info.data
939 self.assertEqual(ip.src, saved_packet[ip_class].src)
940 self.assertEqual(ip.dst, saved_packet[ip_class].dst)
941 self.assertEqual(udp.payload, saved_packet[UDP].payload)
Klement Sekera4c533132018-02-22 11:41:12 +0100942 except Exception:
Klement Sekera75e7d132017-09-20 08:26:30 +0200943 self.logger.error(ppp("Unexpected or invalid packet:", packet))
944 raise
945 for index in self._packet_infos:
946 self.assertTrue(index in seen or index in dropped_packet_indexes,
947 "Packet with packet_index %d not received" % index)
948
949 def test_fif4(self):
950 """ Fragments in fragments (4o4) """
951
952 # TODO this should be ideally in setUpClass, but then we hit a bug
953 # with VppIpRoute incorrectly reporting it's present when it's not
954 # so we need to manually remove the vpp config, thus we cannot have
955 # it shared for multiple test cases
956 self.tun_ip4 = "1.1.1.2"
957
Klement Sekera4c533132018-02-22 11:41:12 +0100958 self.gre4 = VppGreInterface(self, self.src_if.local_ip4, self.tun_ip4)
Klement Sekera75e7d132017-09-20 08:26:30 +0200959 self.gre4.add_vpp_config()
960 self.gre4.admin_up()
961 self.gre4.config_ip4()
962
Klement Sekera4c533132018-02-22 11:41:12 +0100963 self.vapi.ip_reassembly_enable_disable(
964 sw_if_index=self.gre4.sw_if_index, enable_ip4=True)
965
Klement Sekera75e7d132017-09-20 08:26:30 +0200966 self.route4 = VppIpRoute(self, self.tun_ip4, 32,
Klement Sekera4c533132018-02-22 11:41:12 +0100967 [VppRoutePath(self.src_if.remote_ip4,
968 self.src_if.sw_if_index)])
Klement Sekera75e7d132017-09-20 08:26:30 +0200969 self.route4.add_vpp_config()
970
971 self.reset_packet_infos()
972 for i in range(test_packet_count):
Klement Sekera4c533132018-02-22 11:41:12 +0100973 info = self.create_packet_info(self.src_if, self.dst_if)
Klement Sekera75e7d132017-09-20 08:26:30 +0200974 payload = self.info_to_payload(info)
Klement Sekera4c533132018-02-22 11:41:12 +0100975 # Ethernet header here is only for size calculation, thus it
976 # doesn't matter how it's initialized. This is to ensure that
977 # reassembled packet is not > 9000 bytes, so that it's not dropped
978 p = (Ether() /
979 IP(id=i, src=self.src_if.remote_ip4,
980 dst=self.dst_if.remote_ip4) /
981 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +0200982 Raw(payload))
983 size = self.packet_sizes[(i // 2) % len(self.packet_sizes)]
984 self.extend_packet(p, size, self.padding)
Klement Sekera4c533132018-02-22 11:41:12 +0100985 info.data = p[IP] # use only IP part, without ethernet header
Klement Sekera75e7d132017-09-20 08:26:30 +0200986
987 fragments = [x for _, p in self._packet_infos.iteritems()
988 for x in fragment_rfc791(p.data, 400)]
989
990 encapped_fragments = \
Klement Sekera4c533132018-02-22 11:41:12 +0100991 [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
992 IP(src=self.tun_ip4, dst=self.src_if.local_ip4) /
Klement Sekera75e7d132017-09-20 08:26:30 +0200993 GRE() /
994 p
995 for p in fragments]
996
997 fragmented_encapped_fragments = \
998 [x for p in encapped_fragments
999 for x in fragment_rfc791(p, 200)]
1000
Klement Sekera4c533132018-02-22 11:41:12 +01001001 self.src_if.add_stream(fragmented_encapped_fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +02001002
1003 self.pg_enable_capture(self.pg_interfaces)
1004 self.pg_start()
1005
Klement Sekera4c533132018-02-22 11:41:12 +01001006 self.src_if.assert_nothing_captured()
1007 packets = self.dst_if.get_capture(len(self._packet_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +02001008 self.verify_capture(packets, IP)
1009
1010 # TODO remove gre vpp config by hand until VppIpRoute gets fixed
1011 # so that it's query_vpp_config() works as it should
1012 self.gre4.remove_vpp_config()
Klement Sekera4c533132018-02-22 11:41:12 +01001013 self.logger.debug(self.vapi.ppcli("show interface"))
Klement Sekera75e7d132017-09-20 08:26:30 +02001014
1015 def test_fif6(self):
1016 """ Fragments in fragments (6o6) """
1017 # TODO this should be ideally in setUpClass, but then we hit a bug
1018 # with VppIpRoute incorrectly reporting it's present when it's not
1019 # so we need to manually remove the vpp config, thus we cannot have
1020 # it shared for multiple test cases
1021 self.tun_ip6 = "1002::1"
1022
Klement Sekera4c533132018-02-22 11:41:12 +01001023 self.gre6 = VppGre6Interface(self, self.src_if.local_ip6, self.tun_ip6)
Klement Sekera75e7d132017-09-20 08:26:30 +02001024 self.gre6.add_vpp_config()
1025 self.gre6.admin_up()
1026 self.gre6.config_ip6()
1027
Klement Sekera4c533132018-02-22 11:41:12 +01001028 self.vapi.ip_reassembly_enable_disable(
1029 sw_if_index=self.gre6.sw_if_index, enable_ip6=True)
1030
Klement Sekera75e7d132017-09-20 08:26:30 +02001031 self.route6 = VppIpRoute(self, self.tun_ip6, 128,
Klement Sekera4c533132018-02-22 11:41:12 +01001032 [VppRoutePath(self.src_if.remote_ip6,
1033 self.src_if.sw_if_index,
Klement Sekera75e7d132017-09-20 08:26:30 +02001034 proto=DpoProto.DPO_PROTO_IP6)],
1035 is_ip6=1)
1036 self.route6.add_vpp_config()
1037
1038 self.reset_packet_infos()
1039 for i in range(test_packet_count):
Klement Sekera4c533132018-02-22 11:41:12 +01001040 info = self.create_packet_info(self.src_if, self.dst_if)
Klement Sekera75e7d132017-09-20 08:26:30 +02001041 payload = self.info_to_payload(info)
Klement Sekera4c533132018-02-22 11:41:12 +01001042 # Ethernet header here is only for size calculation, thus it
1043 # doesn't matter how it's initialized. This is to ensure that
1044 # reassembled packet is not > 9000 bytes, so that it's not dropped
1045 p = (Ether() /
1046 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1047 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +02001048 Raw(payload))
1049 size = self.packet_sizes[(i // 2) % len(self.packet_sizes)]
1050 self.extend_packet(p, size, self.padding)
Klement Sekera4c533132018-02-22 11:41:12 +01001051 info.data = p[IPv6] # use only IPv6 part, without ethernet header
Klement Sekera75e7d132017-09-20 08:26:30 +02001052
1053 fragments = [x for _, i in self._packet_infos.iteritems()
1054 for x in fragment_rfc8200(
1055 i.data, i.index, 400)]
1056
1057 encapped_fragments = \
Klement Sekera4c533132018-02-22 11:41:12 +01001058 [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1059 IPv6(src=self.tun_ip6, dst=self.src_if.local_ip6) /
Klement Sekera75e7d132017-09-20 08:26:30 +02001060 GRE() /
1061 p
1062 for p in fragments]
1063
1064 fragmented_encapped_fragments = \
1065 [x for p in encapped_fragments for x in (
1066 fragment_rfc8200(
1067 p,
1068 2 * len(self._packet_infos) + p[IPv6ExtHdrFragment].id,
1069 200)
1070 if IPv6ExtHdrFragment in p else [p]
1071 )
1072 ]
1073
Klement Sekera4c533132018-02-22 11:41:12 +01001074 self.src_if.add_stream(fragmented_encapped_fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +02001075
1076 self.pg_enable_capture(self.pg_interfaces)
1077 self.pg_start()
1078
Klement Sekera4c533132018-02-22 11:41:12 +01001079 self.src_if.assert_nothing_captured()
1080 packets = self.dst_if.get_capture(len(self._packet_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +02001081 self.verify_capture(packets, IPv6)
1082
1083 # TODO remove gre vpp config by hand until VppIpRoute gets fixed
1084 # so that it's query_vpp_config() works as it should
Klement Sekera3ecc2212018-03-27 10:34:43 +02001085 self.gre6.remove_vpp_config()
Klement Sekera75e7d132017-09-20 08:26:30 +02001086
1087
1088if __name__ == '__main__':
1089 unittest.main(testRunner=VppTestRunner)