blob: e407252d380939503bb4be3460ff1d81cccc61c8 [file] [log] [blame]
Renato Botelho do Coutoead1e532019-10-31 13:31:07 -05001#!/usr/bin/env python3
Paul Vinciguerraf1f2aa62018-11-25 08:36:47 -08002
Klement Sekera75e7d132017-09-20 08:26:30 +02003import unittest
Dave Wallace8800f732023-08-31 00:47:44 -04004from random import shuffle, randrange
Klement Sekera75e7d132017-09-20 08:26:30 +02005
Dave Wallace8800f732023-08-31 00:47:44 -04006from framework import VppTestCase
7from asfframework import VppTestRunner
Klement Sekera947a85c2019-07-24 12:40:37 +00008
Klement Sekera75e7d132017-09-20 08:26:30 +02009from scapy.packet import Raw
10from scapy.layers.l2 import Ether, GRE
Klement Sekera01c1fa42021-12-14 18:25:11 +000011from scapy.layers.inet import IP, UDP, ICMP, icmptypes
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020012from scapy.layers.inet6 import (
13 HBHOptUnknown,
14 ICMPv6ParamProblem,
15 ICMPv6TimeExceeded,
16 IPv6,
17 IPv6ExtHdrFragment,
18 IPv6ExtHdrHopByHop,
19 IPv6ExtHdrDestOpt,
20 PadN,
21 ICMPv6EchoRequest,
22 ICMPv6EchoReply,
23)
Dave Wallace8800f732023-08-31 00:47:44 -040024from util import ppp, fragment_rfc791, fragment_rfc8200
Neale Ranns5a8844b2019-04-16 07:15:35 +000025from vpp_gre_interface import VppGreInterface
Dave Wallace8800f732023-08-31 00:47:44 -040026from vpp_ip_route import VppIpRoute, VppRoutePath
Klement Sekera896c8962019-06-24 11:52:49 +000027from vpp_papi import VppEnum
Klement Sekera75e7d132017-09-20 08:26:30 +020028
Klement Sekerad0f70a32018-12-14 17:24:13 +010029# 35 is enough to have >257 400-byte fragments
30test_packet_count = 35
Klement Sekera75e7d132017-09-20 08:26:30 +020031
32
Klement Sekera947a85c2019-07-24 12:40:37 +000033class TestIPv4Reassembly(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020034 """IPv4 Reassembly"""
Klement Sekera75e7d132017-09-20 08:26:30 +020035
36 @classmethod
37 def setUpClass(cls):
Klement Sekera01c1fa42021-12-14 18:25:11 +000038 super().setUpClass()
Klement Sekera75e7d132017-09-20 08:26:30 +020039
Klement Sekera4c533132018-02-22 11:41:12 +010040 cls.create_pg_interfaces([0, 1])
41 cls.src_if = cls.pg0
42 cls.dst_if = cls.pg1
Klement Sekera75e7d132017-09-20 08:26:30 +020043
44 # setup all interfaces
45 for i in cls.pg_interfaces:
46 i.admin_up()
47 i.config_ip4()
48 i.resolve_arp()
49
Klement Sekera75e7d132017-09-20 08:26:30 +020050 # packet sizes
51 cls.packet_sizes = [64, 512, 1518, 9018]
52 cls.padding = " abcdefghijklmn"
53 cls.create_stream(cls.packet_sizes)
54 cls.create_fragments()
55
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -070056 @classmethod
57 def tearDownClass(cls):
Klement Sekera01c1fa42021-12-14 18:25:11 +000058 super().tearDownClass()
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -070059
Klement Sekera75e7d132017-09-20 08:26:30 +020060 def setUp(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020061 """Test setup - force timeout on existing reassemblies"""
Klement Sekera01c1fa42021-12-14 18:25:11 +000062 super().setUp()
Klement Sekera4c533132018-02-22 11:41:12 +010063 self.vapi.ip_reassembly_enable_disable(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020064 sw_if_index=self.src_if.sw_if_index, enable_ip4=True
65 )
66 self.vapi.ip_reassembly_set(
67 timeout_ms=0,
68 max_reassemblies=1000,
69 max_reassembly_length=1000,
70 expire_walk_interval_ms=10,
71 )
72 self.virtual_sleep(0.25)
73 self.vapi.ip_reassembly_set(
74 timeout_ms=1000000,
75 max_reassemblies=1000,
76 max_reassembly_length=1000,
77 expire_walk_interval_ms=10000,
78 )
Klement Sekera75e7d132017-09-20 08:26:30 +020079
80 def tearDown(self):
Klement Sekera01c1fa42021-12-14 18:25:11 +000081 self.vapi.ip_reassembly_enable_disable(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020082 sw_if_index=self.src_if.sw_if_index, enable_ip4=False
83 )
Klement Sekera01c1fa42021-12-14 18:25:11 +000084 super().tearDown()
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -070085
86 def show_commands_at_teardown(self):
Klement Sekera896c8962019-06-24 11:52:49 +000087 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
Klement Sekeracae98b72019-02-19 13:53:43 +010088 self.logger.debug(self.vapi.ppcli("show buffers"))
Klement Sekera75e7d132017-09-20 08:26:30 +020089
90 @classmethod
91 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
Klement Sekerad0f70a32018-12-14 17:24:13 +010092 """Create input packet stream
Klement Sekera75e7d132017-09-20 08:26:30 +020093
94 :param list packet_sizes: Required packet sizes.
95 """
96 for i in range(0, packet_count):
Klement Sekera4c533132018-02-22 11:41:12 +010097 info = cls.create_packet_info(cls.src_if, cls.src_if)
Klement Sekera75e7d132017-09-20 08:26:30 +020098 payload = cls.info_to_payload(info)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020099 p = (
100 Ether(dst=cls.src_if.local_mac, src=cls.src_if.remote_mac)
101 / IP(
102 id=info.index, src=cls.src_if.remote_ip4, dst=cls.dst_if.remote_ip4
103 )
104 / UDP(sport=1234, dport=5678)
105 / Raw(payload)
106 )
Klement Sekera75e7d132017-09-20 08:26:30 +0200107 size = packet_sizes[(i // 2) % len(packet_sizes)]
108 cls.extend_packet(p, size, cls.padding)
109 info.data = p
110
111 @classmethod
112 def create_fragments(cls):
113 infos = cls._packet_infos
114 cls.pkt_infos = []
Paul Vinciguerra090096b2020-12-03 00:42:46 -0500115 for index, info in infos.items():
Klement Sekera75e7d132017-09-20 08:26:30 +0200116 p = info.data
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -0700117 # cls.logger.debug(ppp("Packet:",
118 # p.__class__(scapy.compat.raw(p))))
Klement Sekera75e7d132017-09-20 08:26:30 +0200119 fragments_400 = fragment_rfc791(p, 400)
120 fragments_300 = fragment_rfc791(p, 300)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200121 fragments_200 = [x for f in fragments_400 for x in fragment_rfc791(f, 200)]
122 cls.pkt_infos.append((index, fragments_400, fragments_300, fragments_200))
123 cls.fragments_400 = [x for (_, frags, _, _) in cls.pkt_infos for x in frags]
124 cls.fragments_300 = [x for (_, _, frags, _) in cls.pkt_infos for x in frags]
125 cls.fragments_200 = [x for (_, _, _, frags) in cls.pkt_infos for x in frags]
126 cls.logger.debug(
127 "Fragmented %s packets into %s 400-byte fragments, "
128 "%s 300-byte fragments and %s 200-byte fragments"
129 % (
130 len(infos),
131 len(cls.fragments_400),
132 len(cls.fragments_300),
133 len(cls.fragments_200),
134 )
135 )
Klement Sekera75e7d132017-09-20 08:26:30 +0200136
Klement Sekera947a85c2019-07-24 12:40:37 +0000137 def verify_capture(self, capture, dropped_packet_indexes=[]):
138 """Verify captured packet stream.
139
140 :param list capture: Captured packet stream.
141 """
142 info = None
143 seen = set()
144 for packet in capture:
145 try:
146 self.logger.debug(ppp("Got packet:", packet))
147 ip = packet[IP]
148 udp = packet[UDP]
149 payload_info = self.payload_to_info(packet[Raw])
150 packet_index = payload_info.index
151 self.assertTrue(
152 packet_index not in dropped_packet_indexes,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200153 ppp("Packet received, but should be dropped:", packet),
154 )
Klement Sekera947a85c2019-07-24 12:40:37 +0000155 if packet_index in seen:
156 raise Exception(ppp("Duplicate packet received", packet))
157 seen.add(packet_index)
158 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
159 info = self._packet_infos[packet_index]
160 self.assertTrue(info is not None)
161 self.assertEqual(packet_index, info.index)
162 saved_packet = info.data
163 self.assertEqual(ip.src, saved_packet[IP].src)
164 self.assertEqual(ip.dst, saved_packet[IP].dst)
165 self.assertEqual(udp.payload, saved_packet[UDP].payload)
166 except Exception:
167 self.logger.error(ppp("Unexpected or invalid packet:", packet))
168 raise
169 for index in self._packet_infos:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200170 self.assertTrue(
171 index in seen or index in dropped_packet_indexes,
172 "Packet with packet_index %d not received" % index,
173 )
Klement Sekera947a85c2019-07-24 12:40:37 +0000174
175 def test_reassembly(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200176 """basic reassembly"""
Klement Sekera75e7d132017-09-20 08:26:30 +0200177
Klement Sekera947a85c2019-07-24 12:40:37 +0000178 self.pg_enable_capture()
179 self.src_if.add_stream(self.fragments_200)
180 self.pg_start()
181
182 packets = self.dst_if.get_capture(len(self.pkt_infos))
183 self.verify_capture(packets)
184 self.src_if.assert_nothing_captured()
185
186 # run it all again to verify correctness
187 self.pg_enable_capture()
188 self.src_if.add_stream(self.fragments_200)
189 self.pg_start()
190
191 packets = self.dst_if.get_capture(len(self.pkt_infos))
192 self.verify_capture(packets)
193 self.src_if.assert_nothing_captured()
194
Klement Sekera53be16d2020-12-15 21:47:36 +0100195 def test_verify_clear_trace_mid_reassembly(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200196 """verify clear trace works mid-reassembly"""
Klement Sekera53be16d2020-12-15 21:47:36 +0100197
198 self.pg_enable_capture()
199 self.src_if.add_stream(self.fragments_200[0:-1])
200 self.pg_start()
201
202 self.logger.debug(self.vapi.cli("show trace"))
203 self.vapi.cli("clear trace")
204
205 self.src_if.add_stream(self.fragments_200[-1])
206 self.pg_start()
207 packets = self.dst_if.get_capture(len(self.pkt_infos))
208 self.verify_capture(packets)
209
Klement Sekera947a85c2019-07-24 12:40:37 +0000210 def test_reversed(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200211 """reverse order reassembly"""
Klement Sekera75e7d132017-09-20 08:26:30 +0200212
Klement Sekera947a85c2019-07-24 12:40:37 +0000213 fragments = list(self.fragments_200)
214 fragments.reverse()
215
216 self.pg_enable_capture()
217 self.src_if.add_stream(fragments)
218 self.pg_start()
219
220 packets = self.dst_if.get_capture(len(self.packet_infos))
221 self.verify_capture(packets)
222 self.src_if.assert_nothing_captured()
223
224 # run it all again to verify correctness
225 self.pg_enable_capture()
226 self.src_if.add_stream(fragments)
227 self.pg_start()
228
229 packets = self.dst_if.get_capture(len(self.packet_infos))
230 self.verify_capture(packets)
231 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200232
Klement Sekera3a343d42019-05-16 14:35:46 +0200233 def test_long_fragment_chain(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200234 """long fragment chain"""
Klement Sekera3a343d42019-05-16 14:35:46 +0200235
Neale Rannse22a7042022-08-09 03:03:29 +0000236 error_cnt_str = "/err/ip4-full-reassembly-feature/reass_fragment_chain_too_long"
Klement Sekera3a343d42019-05-16 14:35:46 +0200237
Klement Sekera34641f22019-05-22 20:18:26 +0200238 error_cnt = self.statistics.get_err_counter(error_cnt_str)
Klement Sekera3a343d42019-05-16 14:35:46 +0200239
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200240 self.vapi.ip_reassembly_set(
241 timeout_ms=100,
242 max_reassemblies=1000,
243 max_reassembly_length=3,
244 expire_walk_interval_ms=50,
245 )
Klement Sekera3a343d42019-05-16 14:35:46 +0200246
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200247 p1 = (
248 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
249 / IP(id=1000, src=self.src_if.remote_ip4, dst=self.dst_if.remote_ip4)
250 / UDP(sport=1234, dport=5678)
251 / Raw(b"X" * 1000)
252 )
253 p2 = (
254 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
255 / IP(id=1001, src=self.src_if.remote_ip4, dst=self.dst_if.remote_ip4)
256 / UDP(sport=1234, dport=5678)
257 / Raw(b"X" * 1000)
258 )
Klement Sekera3a343d42019-05-16 14:35:46 +0200259 frags = fragment_rfc791(p1, 200) + fragment_rfc791(p2, 500)
260
261 self.pg_enable_capture()
262 self.src_if.add_stream(frags)
263 self.pg_start()
264
265 self.dst_if.get_capture(1)
Klement Sekera34641f22019-05-22 20:18:26 +0200266 self.assert_error_counter_equal(error_cnt_str, error_cnt + 1)
Klement Sekera3a343d42019-05-16 14:35:46 +0200267
Klement Sekera14d7e902018-12-10 13:46:09 +0100268 def test_5737(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200269 """fragment length + ip header size > 65535"""
Klement Sekera4ee633e2018-12-14 12:00:44 +0100270 self.vapi.cli("clear errors")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200271 raw = b"""E\x00\x00\x88,\xf8\x1f\xfe@\x01\x98\x00\xc0\xa8\n-\xc0\xa8\n\
Ole Troan127fbec2019-10-18 15:22:56 +0200272\x01\x08\x00\xf0J\xed\xcb\xf1\xf5Test-group: IPv4.IPv4.ipv4-message.\
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200273Ethernet-Payload.IPv4-Packet.IPv4-Header.Fragment-Offset; Test-case: 5737"""
274 malformed_packet = Ether(
275 dst=self.src_if.local_mac, src=self.src_if.remote_mac
276 ) / IP(raw)
277 p = (
278 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
279 / IP(id=1000, src=self.src_if.remote_ip4, dst=self.dst_if.remote_ip4)
280 / UDP(sport=1234, dport=5678)
281 / Raw(b"X" * 1000)
282 )
Klement Sekera14d7e902018-12-10 13:46:09 +0100283 valid_fragments = fragment_rfc791(p, 400)
284
Neale Rannse22a7042022-08-09 03:03:29 +0000285 counter = "/err/ip4-full-reassembly-feature/reass_malformed_packet"
Ole Troan127fbec2019-10-18 15:22:56 +0200286 error_counter = self.statistics.get_err_counter(counter)
Klement Sekera14d7e902018-12-10 13:46:09 +0100287 self.pg_enable_capture()
288 self.src_if.add_stream([malformed_packet] + valid_fragments)
289 self.pg_start()
290
291 self.dst_if.get_capture(1)
Klement Sekera896c8962019-06-24 11:52:49 +0000292 self.logger.debug(self.vapi.ppcli("show error"))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200293 self.assertEqual(self.statistics.get_err_counter(counter), error_counter + 1)
Klement Sekera14d7e902018-12-10 13:46:09 +0100294
Klement Sekera400f6d82018-12-13 14:35:48 +0100295 def test_44924(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200296 """compress tiny fragments"""
297 packets = [
298 (
299 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
300 / IP(
301 id=24339,
302 flags="MF",
303 frag=0,
304 ttl=64,
305 src=self.src_if.remote_ip4,
306 dst=self.dst_if.remote_ip4,
307 )
308 / ICMP(type="echo-request", code=0, id=0x1FE6, seq=0x2407)
309 / Raw(load="Test-group: IPv4")
310 ),
311 (
312 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
313 / IP(
314 id=24339,
315 flags="MF",
316 frag=3,
317 ttl=64,
318 src=self.src_if.remote_ip4,
319 dst=self.dst_if.remote_ip4,
320 )
321 / ICMP(type="echo-request", code=0, id=0x1FE6, seq=0x2407)
322 / Raw(load=".IPv4.Fragmentation.vali")
323 ),
324 (
325 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
326 / IP(
327 id=24339,
328 frag=6,
329 ttl=64,
330 src=self.src_if.remote_ip4,
331 dst=self.dst_if.remote_ip4,
332 )
333 / ICMP(type="echo-request", code=0, id=0x1FE6, seq=0x2407)
334 / Raw(load="d; Test-case: 44924")
335 ),
336 ]
Klement Sekera400f6d82018-12-13 14:35:48 +0100337
338 self.pg_enable_capture()
339 self.src_if.add_stream(packets)
340 self.pg_start()
341
342 self.dst_if.get_capture(1)
343
Klement Sekera4ee633e2018-12-14 12:00:44 +0100344 def test_frag_1(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200345 """fragment of size 1"""
Klement Sekera4ee633e2018-12-14 12:00:44 +0100346 self.vapi.cli("clear errors")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200347 malformed_packets = [
348 (
349 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
350 / IP(
351 id=7,
352 len=21,
353 flags="MF",
354 frag=0,
355 ttl=64,
356 src=self.src_if.remote_ip4,
357 dst=self.dst_if.remote_ip4,
358 )
359 / ICMP(type="echo-request")
360 ),
361 (
362 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
363 / IP(
364 id=7,
365 len=21,
366 frag=1,
367 ttl=64,
368 src=self.src_if.remote_ip4,
369 dst=self.dst_if.remote_ip4,
370 )
371 / Raw(load=b"\x08")
372 ),
373 ]
Klement Sekera4ee633e2018-12-14 12:00:44 +0100374
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200375 p = (
376 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
377 / IP(id=1000, src=self.src_if.remote_ip4, dst=self.dst_if.remote_ip4)
378 / UDP(sport=1234, dport=5678)
379 / Raw(b"X" * 1000)
380 )
Klement Sekera4ee633e2018-12-14 12:00:44 +0100381 valid_fragments = fragment_rfc791(p, 400)
382
383 self.pg_enable_capture()
384 self.src_if.add_stream(malformed_packets + valid_fragments)
385 self.pg_start()
386
387 self.dst_if.get_capture(1)
388
Klement Sekera896c8962019-06-24 11:52:49 +0000389 self.assert_packet_counter_equal("ip4-full-reassembly-feature", 1)
Klement Sekera4ee633e2018-12-14 12:00:44 +0100390 # TODO remove above, uncomment below once clearing of counters
391 # is supported
392 # self.assert_packet_counter_equal(
Neale Rannse22a7042022-08-09 03:03:29 +0000393 # "/err/ip4-full-reassembly-feature/reass_malformed_packet", 1)
Klement Sekera4ee633e2018-12-14 12:00:44 +0100394
Klement Sekera947a85c2019-07-24 12:40:37 +0000395 def test_random(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200396 """random order reassembly"""
Klement Sekera947a85c2019-07-24 12:40:37 +0000397
398 fragments = list(self.fragments_200)
399 shuffle(fragments)
400
401 self.pg_enable_capture()
402 self.src_if.add_stream(fragments)
403 self.pg_start()
404
405 packets = self.dst_if.get_capture(len(self.packet_infos))
406 self.verify_capture(packets)
407 self.src_if.assert_nothing_captured()
408
409 # run it all again to verify correctness
410 self.pg_enable_capture()
411 self.src_if.add_stream(fragments)
412 self.pg_start()
413
414 packets = self.dst_if.get_capture(len(self.packet_infos))
415 self.verify_capture(packets)
416 self.src_if.assert_nothing_captured()
417
418 def test_duplicates(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200419 """duplicate fragments"""
Klement Sekera947a85c2019-07-24 12:40:37 +0000420
Klement Sekera75e7d132017-09-20 08:26:30 +0200421 fragments = [
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200422 x
423 for (_, frags, _, _) in self.pkt_infos
Klement Sekera75e7d132017-09-20 08:26:30 +0200424 for x in frags
425 for _ in range(0, min(2, len(frags)))
426 ]
Klement Sekera947a85c2019-07-24 12:40:37 +0000427
428 self.pg_enable_capture()
429 self.src_if.add_stream(fragments)
430 self.pg_start()
431
432 packets = self.dst_if.get_capture(len(self.pkt_infos))
433 self.verify_capture(packets)
434 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200435
436 def test_overlap1(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200437 """overlapping fragments case #1"""
Klement Sekera75e7d132017-09-20 08:26:30 +0200438
439 fragments = []
440 for _, _, frags_300, frags_200 in self.pkt_infos:
441 if len(frags_300) == 1:
442 fragments.extend(frags_300)
443 else:
444 for i, j in zip(frags_200, frags_300):
445 fragments.extend(i)
446 fragments.extend(j)
447
448 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100449 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200450 self.pg_start()
451
Klement Sekera4c533132018-02-22 11:41:12 +0100452 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera947a85c2019-07-24 12:40:37 +0000453 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100454 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200455
456 # run it all to verify correctness
457 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100458 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200459 self.pg_start()
460
Klement Sekera4c533132018-02-22 11:41:12 +0100461 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera947a85c2019-07-24 12:40:37 +0000462 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100463 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200464
465 def test_overlap2(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200466 """overlapping fragments case #2"""
Klement Sekera75e7d132017-09-20 08:26:30 +0200467
468 fragments = []
469 for _, _, frags_300, frags_200 in self.pkt_infos:
470 if len(frags_300) == 1:
471 fragments.extend(frags_300)
472 else:
473 # care must be taken here so that there are no fragments
474 # received by vpp after reassembly is finished, otherwise
475 # new reassemblies will be started and packet generator will
476 # freak out when it detects unfreed buffers
477 zipped = zip(frags_300, frags_200)
Paul Vinciguerrac7834e02019-03-02 10:43:05 -0800478 for i, j in zipped:
Klement Sekera75e7d132017-09-20 08:26:30 +0200479 fragments.extend(i)
480 fragments.extend(j)
Paul Vinciguerrac7834e02019-03-02 10:43:05 -0800481 fragments.pop()
Klement Sekera75e7d132017-09-20 08:26:30 +0200482
483 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100484 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200485 self.pg_start()
486
Klement Sekera4c533132018-02-22 11:41:12 +0100487 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera947a85c2019-07-24 12:40:37 +0000488 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100489 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200490
491 # run it all to verify correctness
492 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100493 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200494 self.pg_start()
495
Klement Sekera4c533132018-02-22 11:41:12 +0100496 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera947a85c2019-07-24 12:40:37 +0000497 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100498 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200499
Klement Sekera947a85c2019-07-24 12:40:37 +0000500 def test_timeout_inline(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200501 """timeout (inline)"""
Klement Sekera75e7d132017-09-20 08:26:30 +0200502
503 dropped_packet_indexes = set(
504 index for (index, frags, _, _) in self.pkt_infos if len(frags) > 1
505 )
506
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200507 self.vapi.ip_reassembly_set(
508 timeout_ms=0,
509 max_reassemblies=1000,
510 max_reassembly_length=3,
511 expire_walk_interval_ms=10000,
512 )
Klement Sekera947a85c2019-07-24 12:40:37 +0000513
514 self.pg_enable_capture()
515 self.src_if.add_stream(self.fragments_400)
516 self.pg_start()
517
518 packets = self.dst_if.get_capture(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200519 len(self.pkt_infos) - len(dropped_packet_indexes)
520 )
Klement Sekera947a85c2019-07-24 12:40:37 +0000521 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +0100522 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200523
524 def test_timeout_cleanup(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200525 """timeout (cleanup)"""
Klement Sekera75e7d132017-09-20 08:26:30 +0200526
527 # whole packets + fragmented packets sans last fragment
528 fragments = [
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200529 x
530 for (_, frags_400, _, _) in self.pkt_infos
531 for x in frags_400[: -1 if len(frags_400) > 1 else None]
Klement Sekera75e7d132017-09-20 08:26:30 +0200532 ]
533
534 # last fragments for fragmented packets
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200535 fragments2 = [
536 frags_400[-1]
537 for (_, frags_400, _, _) in self.pkt_infos
538 if len(frags_400) > 1
539 ]
Klement Sekera75e7d132017-09-20 08:26:30 +0200540
541 dropped_packet_indexes = set(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200542 index for (index, frags_400, _, _) in self.pkt_infos if len(frags_400) > 1
543 )
Klement Sekera75e7d132017-09-20 08:26:30 +0200544
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200545 self.vapi.ip_reassembly_set(
546 timeout_ms=100,
547 max_reassemblies=1000,
548 max_reassembly_length=1000,
549 expire_walk_interval_ms=50,
550 )
Klement Sekera75e7d132017-09-20 08:26:30 +0200551
552 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100553 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200554 self.pg_start()
555
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200556 self.virtual_sleep(0.25, "wait before sending rest of fragments")
Klement Sekera75e7d132017-09-20 08:26:30 +0200557
Klement Sekera4c533132018-02-22 11:41:12 +0100558 self.src_if.add_stream(fragments2)
Klement Sekera75e7d132017-09-20 08:26:30 +0200559 self.pg_start()
Klement Sekera75e7d132017-09-20 08:26:30 +0200560
Klement Sekera4c533132018-02-22 11:41:12 +0100561 packets = self.dst_if.get_capture(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200562 len(self.pkt_infos) - len(dropped_packet_indexes)
563 )
Klement Sekera947a85c2019-07-24 12:40:37 +0000564 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +0100565 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200566
Klement Sekera947a85c2019-07-24 12:40:37 +0000567 def test_disabled(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200568 """reassembly disabled"""
Klement Sekera75e7d132017-09-20 08:26:30 +0200569
570 dropped_packet_indexes = set(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200571 index for (index, frags_400, _, _) in self.pkt_infos if len(frags_400) > 1
572 )
Klement Sekera947a85c2019-07-24 12:40:37 +0000573
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200574 self.vapi.ip_reassembly_set(
575 timeout_ms=1000,
576 max_reassemblies=0,
577 max_reassembly_length=3,
578 expire_walk_interval_ms=10000,
579 )
Klement Sekera947a85c2019-07-24 12:40:37 +0000580
581 self.pg_enable_capture()
582 self.src_if.add_stream(self.fragments_400)
583 self.pg_start()
584
585 packets = self.dst_if.get_capture(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200586 len(self.pkt_infos) - len(dropped_packet_indexes)
587 )
Klement Sekera947a85c2019-07-24 12:40:37 +0000588 self.verify_capture(packets, dropped_packet_indexes)
589 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200590
Klement Sekera01c1fa42021-12-14 18:25:11 +0000591 def test_local_enable_disable(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200592 """local reassembly enabled/disable"""
Klement Sekera01c1fa42021-12-14 18:25:11 +0000593 self.vapi.ip_reassembly_enable_disable(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200594 sw_if_index=self.src_if.sw_if_index, enable_ip4=False
595 )
Klement Sekera01c1fa42021-12-14 18:25:11 +0000596 self.vapi.ip_local_reass_enable_disable(enable_ip4=True)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200597 p = (
598 Ether(src=self.src_if.remote_mac, dst=self.src_if.local_mac)
599 / IP(src=self.src_if.remote_ip4, dst=self.src_if.local_ip4)
600 / ICMP(id=1234, type="echo-request")
601 / Raw("x" * 1000)
602 )
Klement Sekera01c1fa42021-12-14 18:25:11 +0000603 frags = fragment_rfc791(p, 400)
604 r = self.send_and_expect(self.src_if, frags, self.src_if, n_rx=1)[0]
605 self.assertEqual(1234, r[ICMP].id)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200606 self.assertEqual(icmptypes[r[ICMP].type], "echo-reply")
Klement Sekera01c1fa42021-12-14 18:25:11 +0000607 self.vapi.ip_local_reass_enable_disable()
608
609 self.send_and_assert_no_replies(self.src_if, frags)
610 self.vapi.ip_local_reass_enable_disable(enable_ip4=True)
611
Klement Sekera75e7d132017-09-20 08:26:30 +0200612
Klement Sekerade34c352019-06-25 11:19:22 +0000613class TestIPv4SVReassembly(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200614 """IPv4 Shallow Virtual Reassembly"""
Klement Sekerade34c352019-06-25 11:19:22 +0000615
616 @classmethod
617 def setUpClass(cls):
Klement Sekera01c1fa42021-12-14 18:25:11 +0000618 super().setUpClass()
Klement Sekerade34c352019-06-25 11:19:22 +0000619
620 cls.create_pg_interfaces([0, 1])
621 cls.src_if = cls.pg0
622 cls.dst_if = cls.pg1
623
624 # setup all interfaces
625 for i in cls.pg_interfaces:
626 i.admin_up()
627 i.config_ip4()
628 i.resolve_arp()
629
630 def setUp(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200631 """Test setup - force timeout on existing reassemblies"""
Klement Sekera01c1fa42021-12-14 18:25:11 +0000632 super().setUp()
Klement Sekerade34c352019-06-25 11:19:22 +0000633 self.vapi.ip_reassembly_enable_disable(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200634 sw_if_index=self.src_if.sw_if_index,
635 enable_ip4=True,
636 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
637 )
Klement Sekerade34c352019-06-25 11:19:22 +0000638 self.vapi.ip_reassembly_set(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200639 timeout_ms=0,
640 max_reassemblies=1000,
Klement Sekerade34c352019-06-25 11:19:22 +0000641 max_reassembly_length=1000,
642 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200643 expire_walk_interval_ms=10,
644 )
645 self.virtual_sleep(0.25)
Klement Sekerade34c352019-06-25 11:19:22 +0000646 self.vapi.ip_reassembly_set(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200647 timeout_ms=1000000,
648 max_reassemblies=1000,
Klement Sekerade34c352019-06-25 11:19:22 +0000649 max_reassembly_length=1000,
650 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200651 expire_walk_interval_ms=10000,
652 )
Klement Sekerade34c352019-06-25 11:19:22 +0000653
654 def tearDown(self):
Klement Sekera01c1fa42021-12-14 18:25:11 +0000655 super().tearDown()
Klement Sekerade34c352019-06-25 11:19:22 +0000656 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
657 self.logger.debug(self.vapi.ppcli("show buffers"))
658
659 def test_basic(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200660 """basic reassembly"""
Klement Sekerade34c352019-06-25 11:19:22 +0000661 payload_len = 1000
662 payload = ""
663 counter = 0
664 while len(payload) < payload_len:
665 payload += "%u " % counter
666 counter += 1
667
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200668 p = (
669 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
670 / IP(id=1, src=self.src_if.remote_ip4, dst=self.dst_if.remote_ip4)
671 / UDP(sport=1234, dport=5678)
672 / Raw(payload)
673 )
674 fragments = fragment_rfc791(p, payload_len / 4)
Klement Sekerade34c352019-06-25 11:19:22 +0000675
676 # send fragment #2 - should be cached inside reassembly
677 self.pg_enable_capture()
678 self.src_if.add_stream(fragments[1])
679 self.pg_start()
680 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
681 self.logger.debug(self.vapi.ppcli("show buffers"))
682 self.logger.debug(self.vapi.ppcli("show trace"))
683 self.dst_if.assert_nothing_captured()
684
685 # send fragment #1 - reassembly is finished now and both fragments
686 # forwarded
687 self.pg_enable_capture()
688 self.src_if.add_stream(fragments[0])
689 self.pg_start()
690 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
691 self.logger.debug(self.vapi.ppcli("show buffers"))
692 self.logger.debug(self.vapi.ppcli("show trace"))
693 c = self.dst_if.get_capture(2)
694 for sent, recvd in zip([fragments[1], fragments[0]], c):
695 self.assertEqual(sent[IP].src, recvd[IP].src)
696 self.assertEqual(sent[IP].dst, recvd[IP].dst)
697 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
698
699 # send rest of fragments - should be immediately forwarded
700 self.pg_enable_capture()
701 self.src_if.add_stream(fragments[2:])
702 self.pg_start()
703 c = self.dst_if.get_capture(len(fragments[2:]))
704 for sent, recvd in zip(fragments[2:], c):
705 self.assertEqual(sent[IP].src, recvd[IP].src)
706 self.assertEqual(sent[IP].dst, recvd[IP].dst)
707 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
708
Klement Sekera53be16d2020-12-15 21:47:36 +0100709 def test_verify_clear_trace_mid_reassembly(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200710 """verify clear trace works mid-reassembly"""
Klement Sekera53be16d2020-12-15 21:47:36 +0100711 payload_len = 1000
712 payload = ""
713 counter = 0
714 while len(payload) < payload_len:
715 payload += "%u " % counter
716 counter += 1
717
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200718 p = (
719 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
720 / IP(id=1, src=self.src_if.remote_ip4, dst=self.dst_if.remote_ip4)
721 / UDP(sport=1234, dport=5678)
722 / Raw(payload)
723 )
724 fragments = fragment_rfc791(p, payload_len / 4)
Klement Sekera53be16d2020-12-15 21:47:36 +0100725
726 self.pg_enable_capture()
727 self.src_if.add_stream(fragments[1])
728 self.pg_start()
729
730 self.logger.debug(self.vapi.cli("show trace"))
731 self.vapi.cli("clear trace")
732
733 self.pg_enable_capture()
734 self.src_if.add_stream(fragments[0])
735 self.pg_start()
736 self.dst_if.get_capture(2)
737
738 self.logger.debug(self.vapi.cli("show trace"))
739 self.vapi.cli("clear trace")
740
741 self.pg_enable_capture()
742 self.src_if.add_stream(fragments[2:])
743 self.pg_start()
744 self.dst_if.get_capture(len(fragments[2:]))
745
Klement Sekerade34c352019-06-25 11:19:22 +0000746 def test_timeout(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200747 """reassembly timeout"""
Klement Sekerade34c352019-06-25 11:19:22 +0000748 payload_len = 1000
749 payload = ""
750 counter = 0
751 while len(payload) < payload_len:
752 payload += "%u " % counter
753 counter += 1
754
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200755 p = (
756 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
757 / IP(id=1, src=self.src_if.remote_ip4, dst=self.dst_if.remote_ip4)
758 / UDP(sport=1234, dport=5678)
759 / Raw(payload)
760 )
761 fragments = fragment_rfc791(p, payload_len / 4)
Klement Sekerade34c352019-06-25 11:19:22 +0000762
763 self.vapi.ip_reassembly_set(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200764 timeout_ms=100,
765 max_reassemblies=1000,
Klement Sekerade34c352019-06-25 11:19:22 +0000766 max_reassembly_length=1000,
767 expire_walk_interval_ms=50,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200768 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
769 )
Klement Sekerade34c352019-06-25 11:19:22 +0000770
771 # send fragments #2 and #1 - should be forwarded
772 self.pg_enable_capture()
773 self.src_if.add_stream(fragments[0:2])
774 self.pg_start()
775 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
776 self.logger.debug(self.vapi.ppcli("show buffers"))
777 self.logger.debug(self.vapi.ppcli("show trace"))
778 c = self.dst_if.get_capture(2)
779 for sent, recvd in zip([fragments[1], fragments[0]], c):
780 self.assertEqual(sent[IP].src, recvd[IP].src)
781 self.assertEqual(sent[IP].dst, recvd[IP].dst)
782 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
783
784 # wait for cleanup
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200785 self.virtual_sleep(0.25, "wait before sending rest of fragments")
Klement Sekerade34c352019-06-25 11:19:22 +0000786
787 # send rest of fragments - shouldn't be forwarded
788 self.pg_enable_capture()
789 self.src_if.add_stream(fragments[2:])
790 self.pg_start()
791 self.dst_if.assert_nothing_captured()
792
793 def test_lru(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200794 """reassembly reuses LRU element"""
Klement Sekerade34c352019-06-25 11:19:22 +0000795
796 self.vapi.ip_reassembly_set(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200797 timeout_ms=1000000,
798 max_reassemblies=1,
Klement Sekerade34c352019-06-25 11:19:22 +0000799 max_reassembly_length=1000,
800 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200801 expire_walk_interval_ms=10000,
802 )
Klement Sekerade34c352019-06-25 11:19:22 +0000803
804 payload_len = 1000
805 payload = ""
806 counter = 0
807 while len(payload) < payload_len:
808 payload += "%u " % counter
809 counter += 1
810
811 packet_count = 10
812
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200813 fragments = [
814 f
815 for i in range(packet_count)
816 for p in (
817 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
818 / IP(id=i, src=self.src_if.remote_ip4, dst=self.dst_if.remote_ip4)
819 / UDP(sport=1234, dport=5678)
820 / Raw(payload)
821 )
822 for f in fragment_rfc791(p, payload_len / 4)
823 ]
Klement Sekerade34c352019-06-25 11:19:22 +0000824
825 self.pg_enable_capture()
826 self.src_if.add_stream(fragments)
827 self.pg_start()
828 c = self.dst_if.get_capture(len(fragments))
829 for sent, recvd in zip(fragments, c):
830 self.assertEqual(sent[IP].src, recvd[IP].src)
831 self.assertEqual(sent[IP].dst, recvd[IP].dst)
832 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
833
Klement Sekera18c6cd92020-07-10 09:29:48 +0000834 def send_mixed_and_verify_capture(self, traffic):
835 stream = []
836 for t in traffic:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200837 for c in range(t["count"]):
Klement Sekera18c6cd92020-07-10 09:29:48 +0000838 stream.append(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200839 (
840 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
841 / IP(
842 id=self.counter,
843 flags=t["flags"],
844 src=self.src_if.remote_ip4,
845 dst=self.dst_if.remote_ip4,
846 )
847 / UDP(sport=1234, dport=5678)
848 / Raw("abcdef")
849 )
850 )
Klement Sekera18c6cd92020-07-10 09:29:48 +0000851 self.counter = self.counter + 1
852
853 self.pg_enable_capture()
854 self.src_if.add_stream(stream)
855 self.pg_start()
856 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
857 self.logger.debug(self.vapi.ppcli("show buffers"))
858 self.logger.debug(self.vapi.ppcli("show trace"))
859 self.dst_if.get_capture(len(stream))
860
861 def test_mixed(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200862 """mixed traffic correctly passes through SVR"""
Klement Sekera18c6cd92020-07-10 09:29:48 +0000863 self.counter = 1
864
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200865 self.send_mixed_and_verify_capture([{"count": 1, "flags": ""}])
866 self.send_mixed_and_verify_capture([{"count": 2, "flags": ""}])
867 self.send_mixed_and_verify_capture([{"count": 3, "flags": ""}])
868 self.send_mixed_and_verify_capture([{"count": 8, "flags": ""}])
869 self.send_mixed_and_verify_capture([{"count": 257, "flags": ""}])
Klement Sekera18c6cd92020-07-10 09:29:48 +0000870
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200871 self.send_mixed_and_verify_capture([{"count": 1, "flags": "MF"}])
872 self.send_mixed_and_verify_capture([{"count": 2, "flags": "MF"}])
873 self.send_mixed_and_verify_capture([{"count": 3, "flags": "MF"}])
874 self.send_mixed_and_verify_capture([{"count": 8, "flags": "MF"}])
875 self.send_mixed_and_verify_capture([{"count": 257, "flags": "MF"}])
Klement Sekera18c6cd92020-07-10 09:29:48 +0000876
877 self.send_mixed_and_verify_capture(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200878 [{"count": 1, "flags": ""}, {"count": 1, "flags": "MF"}]
879 )
Klement Sekera18c6cd92020-07-10 09:29:48 +0000880 self.send_mixed_and_verify_capture(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200881 [{"count": 2, "flags": ""}, {"count": 2, "flags": "MF"}]
882 )
Klement Sekera18c6cd92020-07-10 09:29:48 +0000883 self.send_mixed_and_verify_capture(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200884 [{"count": 3, "flags": ""}, {"count": 3, "flags": "MF"}]
885 )
Klement Sekera18c6cd92020-07-10 09:29:48 +0000886 self.send_mixed_and_verify_capture(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200887 [{"count": 8, "flags": ""}, {"count": 8, "flags": "MF"}]
888 )
Klement Sekera18c6cd92020-07-10 09:29:48 +0000889 self.send_mixed_and_verify_capture(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200890 [{"count": 129, "flags": ""}, {"count": 129, "flags": "MF"}]
891 )
Klement Sekera18c6cd92020-07-10 09:29:48 +0000892
893 self.send_mixed_and_verify_capture(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200894 [
895 {"count": 1, "flags": ""},
896 {"count": 1, "flags": "MF"},
897 {"count": 1, "flags": ""},
898 {"count": 1, "flags": "MF"},
899 ]
900 )
Klement Sekera18c6cd92020-07-10 09:29:48 +0000901 self.send_mixed_and_verify_capture(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200902 [
903 {"count": 2, "flags": ""},
904 {"count": 2, "flags": "MF"},
905 {"count": 2, "flags": ""},
906 {"count": 2, "flags": "MF"},
907 ]
908 )
Klement Sekera18c6cd92020-07-10 09:29:48 +0000909 self.send_mixed_and_verify_capture(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200910 [
911 {"count": 3, "flags": ""},
912 {"count": 3, "flags": "MF"},
913 {"count": 3, "flags": ""},
914 {"count": 3, "flags": "MF"},
915 ]
916 )
Klement Sekera18c6cd92020-07-10 09:29:48 +0000917 self.send_mixed_and_verify_capture(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200918 [
919 {"count": 8, "flags": ""},
920 {"count": 8, "flags": "MF"},
921 {"count": 8, "flags": ""},
922 {"count": 8, "flags": "MF"},
923 ]
924 )
Klement Sekera18c6cd92020-07-10 09:29:48 +0000925 self.send_mixed_and_verify_capture(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200926 [
927 {"count": 65, "flags": ""},
928 {"count": 65, "flags": "MF"},
929 {"count": 65, "flags": ""},
930 {"count": 65, "flags": "MF"},
931 ]
932 )
Klement Sekera18c6cd92020-07-10 09:29:48 +0000933
Klement Sekerade34c352019-06-25 11:19:22 +0000934
Klement Sekera630ab582019-07-19 09:14:19 +0000935class TestIPv4MWReassembly(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200936 """IPv4 Reassembly (multiple workers)"""
937
Klement Sekera8d815022021-03-15 16:58:10 +0100938 vpp_worker_count = 3
Klement Sekera630ab582019-07-19 09:14:19 +0000939
940 @classmethod
941 def setUpClass(cls):
Klement Sekera01c1fa42021-12-14 18:25:11 +0000942 super().setUpClass()
Klement Sekera630ab582019-07-19 09:14:19 +0000943
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200944 cls.create_pg_interfaces(range(cls.vpp_worker_count + 1))
Klement Sekera630ab582019-07-19 09:14:19 +0000945 cls.src_if = cls.pg0
946 cls.send_ifs = cls.pg_interfaces[:-1]
947 cls.dst_if = cls.pg_interfaces[-1]
948
949 # setup all interfaces
950 for i in cls.pg_interfaces:
951 i.admin_up()
952 i.config_ip4()
953 i.resolve_arp()
954
955 # packets sizes reduced here because we are generating packets without
956 # Ethernet headers, which are added later (diff fragments go via
957 # different interfaces)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200958 cls.packet_sizes = [
959 64 - len(Ether()),
960 512 - len(Ether()),
961 1518 - len(Ether()),
962 9018 - len(Ether()),
963 ]
Klement Sekera630ab582019-07-19 09:14:19 +0000964 cls.padding = " abcdefghijklmn"
965 cls.create_stream(cls.packet_sizes)
966 cls.create_fragments()
967
968 @classmethod
969 def tearDownClass(cls):
Klement Sekera01c1fa42021-12-14 18:25:11 +0000970 super().tearDownClass()
Klement Sekera630ab582019-07-19 09:14:19 +0000971
972 def setUp(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200973 """Test setup - force timeout on existing reassemblies"""
Klement Sekera01c1fa42021-12-14 18:25:11 +0000974 super().setUp()
Klement Sekera630ab582019-07-19 09:14:19 +0000975 for intf in self.send_ifs:
976 self.vapi.ip_reassembly_enable_disable(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200977 sw_if_index=intf.sw_if_index, enable_ip4=True
978 )
979 self.vapi.ip_reassembly_set(
980 timeout_ms=0,
981 max_reassemblies=1000,
982 max_reassembly_length=1000,
983 expire_walk_interval_ms=10,
984 )
985 self.virtual_sleep(0.25)
986 self.vapi.ip_reassembly_set(
987 timeout_ms=1000000,
988 max_reassemblies=1000,
989 max_reassembly_length=1000,
990 expire_walk_interval_ms=10000,
991 )
Klement Sekera630ab582019-07-19 09:14:19 +0000992
993 def tearDown(self):
Klement Sekera01c1fa42021-12-14 18:25:11 +0000994 for intf in self.send_ifs:
995 self.vapi.ip_reassembly_enable_disable(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200996 sw_if_index=intf.sw_if_index, enable_ip4=False
997 )
Klement Sekera01c1fa42021-12-14 18:25:11 +0000998 super().tearDown()
Klement Sekera630ab582019-07-19 09:14:19 +0000999
1000 def show_commands_at_teardown(self):
Klement Sekera896c8962019-06-24 11:52:49 +00001001 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
Klement Sekera630ab582019-07-19 09:14:19 +00001002 self.logger.debug(self.vapi.ppcli("show buffers"))
1003
1004 @classmethod
1005 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
1006 """Create input packet stream
1007
1008 :param list packet_sizes: Required packet sizes.
1009 """
1010 for i in range(0, packet_count):
1011 info = cls.create_packet_info(cls.src_if, cls.src_if)
1012 payload = cls.info_to_payload(info)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001013 p = (
1014 IP(id=info.index, src=cls.src_if.remote_ip4, dst=cls.dst_if.remote_ip4)
1015 / UDP(sport=1234, dport=5678)
1016 / Raw(payload)
1017 )
Klement Sekera630ab582019-07-19 09:14:19 +00001018 size = packet_sizes[(i // 2) % len(packet_sizes)]
1019 cls.extend_packet(p, size, cls.padding)
1020 info.data = p
1021
1022 @classmethod
1023 def create_fragments(cls):
1024 infos = cls._packet_infos
1025 cls.pkt_infos = []
Paul Vinciguerra090096b2020-12-03 00:42:46 -05001026 for index, info in infos.items():
Klement Sekera630ab582019-07-19 09:14:19 +00001027 p = info.data
1028 # cls.logger.debug(ppp("Packet:",
1029 # p.__class__(scapy.compat.raw(p))))
1030 fragments_400 = fragment_rfc791(p, 400)
1031 cls.pkt_infos.append((index, fragments_400))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001032 cls.fragments_400 = [x for (_, frags) in cls.pkt_infos for x in frags]
1033 cls.logger.debug(
1034 "Fragmented %s packets into %s 400-byte fragments, "
1035 % (len(infos), len(cls.fragments_400))
1036 )
Klement Sekera630ab582019-07-19 09:14:19 +00001037
1038 def verify_capture(self, capture, dropped_packet_indexes=[]):
1039 """Verify captured packet stream.
1040
1041 :param list capture: Captured packet stream.
1042 """
1043 info = None
1044 seen = set()
1045 for packet in capture:
1046 try:
1047 self.logger.debug(ppp("Got packet:", packet))
1048 ip = packet[IP]
1049 udp = packet[UDP]
1050 payload_info = self.payload_to_info(packet[Raw])
1051 packet_index = payload_info.index
1052 self.assertTrue(
1053 packet_index not in dropped_packet_indexes,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001054 ppp("Packet received, but should be dropped:", packet),
1055 )
Klement Sekera630ab582019-07-19 09:14:19 +00001056 if packet_index in seen:
1057 raise Exception(ppp("Duplicate packet received", packet))
1058 seen.add(packet_index)
1059 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
1060 info = self._packet_infos[packet_index]
1061 self.assertTrue(info is not None)
1062 self.assertEqual(packet_index, info.index)
1063 saved_packet = info.data
1064 self.assertEqual(ip.src, saved_packet[IP].src)
1065 self.assertEqual(ip.dst, saved_packet[IP].dst)
1066 self.assertEqual(udp.payload, saved_packet[UDP].payload)
1067 except Exception:
1068 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1069 raise
1070 for index in self._packet_infos:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001071 self.assertTrue(
1072 index in seen or index in dropped_packet_indexes,
1073 "Packet with packet_index %d not received" % index,
1074 )
Klement Sekera630ab582019-07-19 09:14:19 +00001075
1076 def send_packets(self, packets):
Klement Sekera8d815022021-03-15 16:58:10 +01001077 for counter in range(self.vpp_worker_count):
Klement Sekera630ab582019-07-19 09:14:19 +00001078 if 0 == len(packets[counter]):
1079 continue
1080 send_if = self.send_ifs[counter]
1081 send_if.add_stream(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001082 (
1083 Ether(dst=send_if.local_mac, src=send_if.remote_mac) / x
1084 for x in packets[counter]
1085 ),
1086 worker=counter,
1087 )
Klement Sekera630ab582019-07-19 09:14:19 +00001088 self.pg_start()
1089
1090 def test_worker_conflict(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001091 """1st and FO=0 fragments on different workers"""
Klement Sekera630ab582019-07-19 09:14:19 +00001092
1093 # in first wave we send fragments which don't start at offset 0
1094 # then we send fragments with offset 0 on a different thread
1095 # then the rest of packets on a random thread
Klement Sekera8d815022021-03-15 16:58:10 +01001096 first_packets = [[] for n in range(self.vpp_worker_count)]
1097 second_packets = [[] for n in range(self.vpp_worker_count)]
1098 rest_of_packets = [[] for n in range(self.vpp_worker_count)]
Dave Wallace7b8b4652023-08-15 19:05:26 -04001099 for _, p in self.pkt_infos:
Klement Sekera8d815022021-03-15 16:58:10 +01001100 wi = randrange(self.vpp_worker_count)
Klement Sekera630ab582019-07-19 09:14:19 +00001101 second_packets[wi].append(p[0])
1102 if len(p) <= 1:
1103 continue
1104 wi2 = wi
1105 while wi2 == wi:
Klement Sekera8d815022021-03-15 16:58:10 +01001106 wi2 = randrange(self.vpp_worker_count)
Klement Sekera630ab582019-07-19 09:14:19 +00001107 first_packets[wi2].append(p[1])
Klement Sekera8d815022021-03-15 16:58:10 +01001108 wi3 = randrange(self.vpp_worker_count)
Klement Sekera630ab582019-07-19 09:14:19 +00001109 rest_of_packets[wi3].extend(p[2:])
1110
1111 self.pg_enable_capture()
1112 self.send_packets(first_packets)
1113 self.send_packets(second_packets)
1114 self.send_packets(rest_of_packets)
1115
1116 packets = self.dst_if.get_capture(len(self.pkt_infos))
1117 self.verify_capture(packets)
1118 for send_if in self.send_ifs:
1119 send_if.assert_nothing_captured()
1120
Klement Sekera68bae5b2019-10-10 18:57:34 +00001121 self.logger.debug(self.vapi.ppcli("show trace"))
1122 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
1123 self.logger.debug(self.vapi.ppcli("show buffers"))
1124 self.vapi.cli("clear trace")
1125
Klement Sekera630ab582019-07-19 09:14:19 +00001126 self.pg_enable_capture()
1127 self.send_packets(first_packets)
1128 self.send_packets(second_packets)
1129 self.send_packets(rest_of_packets)
1130
1131 packets = self.dst_if.get_capture(len(self.pkt_infos))
1132 self.verify_capture(packets)
1133 for send_if in self.send_ifs:
1134 send_if.assert_nothing_captured()
1135
1136
Klement Sekera947a85c2019-07-24 12:40:37 +00001137class TestIPv6Reassembly(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001138 """IPv6 Reassembly"""
Klement Sekera75e7d132017-09-20 08:26:30 +02001139
1140 @classmethod
1141 def setUpClass(cls):
Klement Sekera01c1fa42021-12-14 18:25:11 +00001142 super().setUpClass()
Klement Sekera75e7d132017-09-20 08:26:30 +02001143
Klement Sekera4c533132018-02-22 11:41:12 +01001144 cls.create_pg_interfaces([0, 1])
1145 cls.src_if = cls.pg0
1146 cls.dst_if = cls.pg1
Klement Sekera75e7d132017-09-20 08:26:30 +02001147
1148 # setup all interfaces
1149 for i in cls.pg_interfaces:
1150 i.admin_up()
1151 i.config_ip6()
1152 i.resolve_ndp()
1153
Klement Sekera75e7d132017-09-20 08:26:30 +02001154 # packet sizes
1155 cls.packet_sizes = [64, 512, 1518, 9018]
1156 cls.padding = " abcdefghijklmn"
1157 cls.create_stream(cls.packet_sizes)
1158 cls.create_fragments()
1159
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07001160 @classmethod
1161 def tearDownClass(cls):
Klement Sekera01c1fa42021-12-14 18:25:11 +00001162 super().tearDownClass()
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07001163
Klement Sekera75e7d132017-09-20 08:26:30 +02001164 def setUp(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001165 """Test setup - force timeout on existing reassemblies"""
Klement Sekera01c1fa42021-12-14 18:25:11 +00001166 super().setUp()
Klement Sekera4c533132018-02-22 11:41:12 +01001167 self.vapi.ip_reassembly_enable_disable(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001168 sw_if_index=self.src_if.sw_if_index, enable_ip6=True
1169 )
1170 self.vapi.ip_reassembly_set(
1171 timeout_ms=0,
1172 max_reassemblies=1000,
1173 max_reassembly_length=1000,
1174 expire_walk_interval_ms=10,
1175 is_ip6=1,
1176 )
1177 self.virtual_sleep(0.25)
1178 self.vapi.ip_reassembly_set(
1179 timeout_ms=1000000,
1180 max_reassemblies=1000,
1181 max_reassembly_length=1000,
1182 expire_walk_interval_ms=10000,
1183 is_ip6=1,
1184 )
Klement Sekera896c8962019-06-24 11:52:49 +00001185 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
Klement Sekeracae98b72019-02-19 13:53:43 +01001186 self.logger.debug(self.vapi.ppcli("show buffers"))
Klement Sekera75e7d132017-09-20 08:26:30 +02001187
1188 def tearDown(self):
Klement Sekera01c1fa42021-12-14 18:25:11 +00001189 self.vapi.ip_reassembly_enable_disable(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001190 sw_if_index=self.src_if.sw_if_index, enable_ip6=False
1191 )
Klement Sekera01c1fa42021-12-14 18:25:11 +00001192 super().tearDown()
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -07001193
1194 def show_commands_at_teardown(self):
Klement Sekera896c8962019-06-24 11:52:49 +00001195 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
Klement Sekeracae98b72019-02-19 13:53:43 +01001196 self.logger.debug(self.vapi.ppcli("show buffers"))
Klement Sekera75e7d132017-09-20 08:26:30 +02001197
1198 @classmethod
1199 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
1200 """Create input packet stream for defined interface.
1201
1202 :param list packet_sizes: Required packet sizes.
1203 """
1204 for i in range(0, packet_count):
Klement Sekera4c533132018-02-22 11:41:12 +01001205 info = cls.create_packet_info(cls.src_if, cls.src_if)
Klement Sekera75e7d132017-09-20 08:26:30 +02001206 payload = cls.info_to_payload(info)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001207 p = (
1208 Ether(dst=cls.src_if.local_mac, src=cls.src_if.remote_mac)
1209 / IPv6(src=cls.src_if.remote_ip6, dst=cls.dst_if.remote_ip6)
1210 / UDP(sport=1234, dport=5678)
1211 / Raw(payload)
1212 )
Klement Sekera75e7d132017-09-20 08:26:30 +02001213 size = packet_sizes[(i // 2) % len(packet_sizes)]
1214 cls.extend_packet(p, size, cls.padding)
1215 info.data = p
1216
1217 @classmethod
1218 def create_fragments(cls):
1219 infos = cls._packet_infos
1220 cls.pkt_infos = []
Paul Vinciguerra090096b2020-12-03 00:42:46 -05001221 for index, info in infos.items():
Klement Sekera75e7d132017-09-20 08:26:30 +02001222 p = info.data
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07001223 # cls.logger.debug(ppp("Packet:",
1224 # p.__class__(scapy.compat.raw(p))))
Klement Sekera75e7d132017-09-20 08:26:30 +02001225 fragments_400 = fragment_rfc8200(p, info.index, 400)
1226 fragments_300 = fragment_rfc8200(p, info.index, 300)
1227 cls.pkt_infos.append((index, fragments_400, fragments_300))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001228 cls.fragments_400 = [x for _, frags, _ in cls.pkt_infos for x in frags]
1229 cls.fragments_300 = [x for _, _, frags in cls.pkt_infos for x in frags]
1230 cls.logger.debug(
1231 "Fragmented %s packets into %s 400-byte fragments, "
1232 "and %s 300-byte fragments"
1233 % (len(infos), len(cls.fragments_400), len(cls.fragments_300))
1234 )
Klement Sekera75e7d132017-09-20 08:26:30 +02001235
Klement Sekera947a85c2019-07-24 12:40:37 +00001236 def verify_capture(self, capture, dropped_packet_indexes=[]):
1237 """Verify captured packet strea .
1238
1239 :param list capture: Captured packet stream.
1240 """
1241 info = None
1242 seen = set()
1243 for packet in capture:
1244 try:
1245 self.logger.debug(ppp("Got packet:", packet))
1246 ip = packet[IPv6]
1247 udp = packet[UDP]
1248 payload_info = self.payload_to_info(packet[Raw])
1249 packet_index = payload_info.index
1250 self.assertTrue(
1251 packet_index not in dropped_packet_indexes,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001252 ppp("Packet received, but should be dropped:", packet),
1253 )
Klement Sekera947a85c2019-07-24 12:40:37 +00001254 if packet_index in seen:
1255 raise Exception(ppp("Duplicate packet received", packet))
1256 seen.add(packet_index)
1257 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
1258 info = self._packet_infos[packet_index]
1259 self.assertTrue(info is not None)
1260 self.assertEqual(packet_index, info.index)
1261 saved_packet = info.data
1262 self.assertEqual(ip.src, saved_packet[IPv6].src)
1263 self.assertEqual(ip.dst, saved_packet[IPv6].dst)
1264 self.assertEqual(udp.payload, saved_packet[UDP].payload)
1265 except Exception:
1266 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1267 raise
1268 for index in self._packet_infos:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001269 self.assertTrue(
1270 index in seen or index in dropped_packet_indexes,
1271 "Packet with packet_index %d not received" % index,
1272 )
Klement Sekera947a85c2019-07-24 12:40:37 +00001273
1274 def test_reassembly(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001275 """basic reassembly"""
Klement Sekera75e7d132017-09-20 08:26:30 +02001276
Klement Sekera947a85c2019-07-24 12:40:37 +00001277 self.pg_enable_capture()
1278 self.src_if.add_stream(self.fragments_400)
1279 self.pg_start()
1280
1281 packets = self.dst_if.get_capture(len(self.pkt_infos))
1282 self.verify_capture(packets)
1283 self.src_if.assert_nothing_captured()
1284
1285 # run it all again to verify correctness
1286 self.pg_enable_capture()
1287 self.src_if.add_stream(self.fragments_400)
1288 self.pg_start()
1289
1290 packets = self.dst_if.get_capture(len(self.pkt_infos))
1291 self.verify_capture(packets)
1292 self.src_if.assert_nothing_captured()
1293
Klement Sekera769145c2019-03-06 11:59:57 +01001294 def test_buffer_boundary(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001295 """fragment header crossing buffer boundary"""
Klement Sekera769145c2019-03-06 11:59:57 +01001296
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001297 p = (
1298 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
1299 / IPv6(src=self.src_if.remote_ip6, dst=self.src_if.local_ip6)
1300 / IPv6ExtHdrHopByHop(options=[HBHOptUnknown(otype=0xFF, optlen=0)] * 1000)
1301 / IPv6ExtHdrFragment(m=1)
1302 / UDP(sport=1234, dport=5678)
1303 / Raw()
1304 )
Klement Sekera769145c2019-03-06 11:59:57 +01001305 self.pg_enable_capture()
1306 self.src_if.add_stream([p])
1307 self.pg_start()
1308 self.src_if.assert_nothing_captured()
1309 self.dst_if.assert_nothing_captured()
1310
Klement Sekera53be16d2020-12-15 21:47:36 +01001311 def test_verify_clear_trace_mid_reassembly(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001312 """verify clear trace works mid-reassembly"""
Klement Sekera53be16d2020-12-15 21:47:36 +01001313
1314 self.pg_enable_capture()
1315 self.src_if.add_stream(self.fragments_400[0:-1])
1316 self.pg_start()
1317
1318 self.logger.debug(self.vapi.cli("show trace"))
1319 self.vapi.cli("clear trace")
1320
1321 self.src_if.add_stream(self.fragments_400[-1])
1322 self.pg_start()
1323 packets = self.dst_if.get_capture(len(self.pkt_infos))
1324 self.verify_capture(packets)
1325
Klement Sekera947a85c2019-07-24 12:40:37 +00001326 def test_reversed(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001327 """reverse order reassembly"""
Klement Sekera75e7d132017-09-20 08:26:30 +02001328
Klement Sekera947a85c2019-07-24 12:40:37 +00001329 fragments = list(self.fragments_400)
1330 fragments.reverse()
1331
1332 self.pg_enable_capture()
1333 self.src_if.add_stream(fragments)
1334 self.pg_start()
1335
1336 packets = self.dst_if.get_capture(len(self.pkt_infos))
1337 self.verify_capture(packets)
1338 self.src_if.assert_nothing_captured()
1339
1340 # run it all again to verify correctness
1341 self.pg_enable_capture()
1342 self.src_if.add_stream(fragments)
1343 self.pg_start()
1344
1345 packets = self.dst_if.get_capture(len(self.pkt_infos))
1346 self.verify_capture(packets)
1347 self.src_if.assert_nothing_captured()
1348
1349 def test_random(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001350 """random order reassembly"""
Klement Sekera75e7d132017-09-20 08:26:30 +02001351
Klement Sekera947a85c2019-07-24 12:40:37 +00001352 fragments = list(self.fragments_400)
1353 shuffle(fragments)
1354
1355 self.pg_enable_capture()
1356 self.src_if.add_stream(fragments)
1357 self.pg_start()
1358
1359 packets = self.dst_if.get_capture(len(self.pkt_infos))
1360 self.verify_capture(packets)
1361 self.src_if.assert_nothing_captured()
1362
1363 # run it all again to verify correctness
1364 self.pg_enable_capture()
1365 self.src_if.add_stream(fragments)
1366 self.pg_start()
1367
1368 packets = self.dst_if.get_capture(len(self.pkt_infos))
1369 self.verify_capture(packets)
1370 self.src_if.assert_nothing_captured()
1371
1372 def test_duplicates(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001373 """duplicate fragments"""
Klement Sekera75e7d132017-09-20 08:26:30 +02001374
1375 fragments = [
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001376 x
1377 for (_, frags, _) in self.pkt_infos
Klement Sekera75e7d132017-09-20 08:26:30 +02001378 for x in frags
1379 for _ in range(0, min(2, len(frags)))
1380 ]
Klement Sekera947a85c2019-07-24 12:40:37 +00001381
1382 self.pg_enable_capture()
1383 self.src_if.add_stream(fragments)
1384 self.pg_start()
1385
1386 packets = self.dst_if.get_capture(len(self.pkt_infos))
1387 self.verify_capture(packets)
1388 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +02001389
Klement Sekera3a343d42019-05-16 14:35:46 +02001390 def test_long_fragment_chain(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001391 """long fragment chain"""
Klement Sekera3a343d42019-05-16 14:35:46 +02001392
Neale Rannse22a7042022-08-09 03:03:29 +00001393 error_cnt_str = "/err/ip6-full-reassembly-feature/reass_fragment_chain_too_long"
Klement Sekera3a343d42019-05-16 14:35:46 +02001394
Klement Sekera34641f22019-05-22 20:18:26 +02001395 error_cnt = self.statistics.get_err_counter(error_cnt_str)
Klement Sekera3a343d42019-05-16 14:35:46 +02001396
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001397 self.vapi.ip_reassembly_set(
1398 timeout_ms=100,
1399 max_reassemblies=1000,
1400 max_reassembly_length=3,
1401 expire_walk_interval_ms=50,
1402 is_ip6=1,
1403 )
Klement Sekera3a343d42019-05-16 14:35:46 +02001404
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001405 p = (
1406 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
1407 / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6)
1408 / UDP(sport=1234, dport=5678)
1409 / Raw(b"X" * 1000)
1410 )
Klement Sekera3a343d42019-05-16 14:35:46 +02001411 frags = fragment_rfc8200(p, 1, 300) + fragment_rfc8200(p, 2, 500)
1412
1413 self.pg_enable_capture()
1414 self.src_if.add_stream(frags)
1415 self.pg_start()
1416
1417 self.dst_if.get_capture(1)
Klement Sekera34641f22019-05-22 20:18:26 +02001418 self.assert_error_counter_equal(error_cnt_str, error_cnt + 1)
Klement Sekera3a343d42019-05-16 14:35:46 +02001419
Klement Sekera75e7d132017-09-20 08:26:30 +02001420 def test_overlap1(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001421 """overlapping fragments case #1"""
Klement Sekera75e7d132017-09-20 08:26:30 +02001422
1423 fragments = []
1424 for _, frags_400, frags_300 in self.pkt_infos:
1425 if len(frags_300) == 1:
1426 fragments.extend(frags_400)
1427 else:
1428 for i, j in zip(frags_300, frags_400):
1429 fragments.extend(i)
1430 fragments.extend(j)
1431
1432 dropped_packet_indexes = set(
1433 index for (index, _, frags) in self.pkt_infos if len(frags) > 1
1434 )
1435
1436 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +01001437 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +02001438 self.pg_start()
1439
Klement Sekera4c533132018-02-22 11:41:12 +01001440 packets = self.dst_if.get_capture(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001441 len(self.pkt_infos) - len(dropped_packet_indexes)
1442 )
Klement Sekera947a85c2019-07-24 12:40:37 +00001443 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +01001444 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +02001445
1446 def test_overlap2(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001447 """overlapping fragments case #2"""
Klement Sekera75e7d132017-09-20 08:26:30 +02001448
1449 fragments = []
Klement Sekera4c533132018-02-22 11:41:12 +01001450 for _, frags_400, frags_300 in self.pkt_infos:
Klement Sekera75e7d132017-09-20 08:26:30 +02001451 if len(frags_400) == 1:
1452 fragments.extend(frags_400)
1453 else:
1454 # care must be taken here so that there are no fragments
1455 # received by vpp after reassembly is finished, otherwise
1456 # new reassemblies will be started and packet generator will
1457 # freak out when it detects unfreed buffers
Klement Sekera4c533132018-02-22 11:41:12 +01001458 zipped = zip(frags_400, frags_300)
Paul Vinciguerrac7834e02019-03-02 10:43:05 -08001459 for i, j in zipped:
Klement Sekera75e7d132017-09-20 08:26:30 +02001460 fragments.extend(i)
1461 fragments.extend(j)
Paul Vinciguerrac7834e02019-03-02 10:43:05 -08001462 fragments.pop()
Klement Sekera75e7d132017-09-20 08:26:30 +02001463
1464 dropped_packet_indexes = set(
1465 index for (index, _, frags) in self.pkt_infos if len(frags) > 1
1466 )
1467
1468 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +01001469 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +02001470 self.pg_start()
1471
Klement Sekera4c533132018-02-22 11:41:12 +01001472 packets = self.dst_if.get_capture(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001473 len(self.pkt_infos) - len(dropped_packet_indexes)
1474 )
Klement Sekera947a85c2019-07-24 12:40:37 +00001475 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +01001476 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +02001477
Klement Sekera947a85c2019-07-24 12:40:37 +00001478 def test_timeout_inline(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001479 """timeout (inline)"""
Klement Sekera75e7d132017-09-20 08:26:30 +02001480
1481 dropped_packet_indexes = set(
1482 index for (index, frags, _) in self.pkt_infos if len(frags) > 1
1483 )
1484
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001485 self.vapi.ip_reassembly_set(
1486 timeout_ms=0,
1487 max_reassemblies=1000,
1488 max_reassembly_length=3,
1489 expire_walk_interval_ms=10000,
1490 is_ip6=1,
1491 )
Klement Sekera947a85c2019-07-24 12:40:37 +00001492
1493 self.pg_enable_capture()
1494 self.src_if.add_stream(self.fragments_400)
1495 self.pg_start()
1496
1497 packets = self.dst_if.get_capture(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001498 len(self.pkt_infos) - len(dropped_packet_indexes)
1499 )
Klement Sekera947a85c2019-07-24 12:40:37 +00001500 self.verify_capture(packets, dropped_packet_indexes)
Neale Ranns5c6dd172022-02-17 09:08:47 +00001501 pkts = self.src_if._get_capture(1)
Klement Sekera75e7d132017-09-20 08:26:30 +02001502 for icmp in pkts:
1503 self.assertIn(ICMPv6TimeExceeded, icmp)
1504 self.assertIn(IPv6ExtHdrFragment, icmp)
1505 self.assertIn(icmp[IPv6ExtHdrFragment].id, dropped_packet_indexes)
1506 dropped_packet_indexes.remove(icmp[IPv6ExtHdrFragment].id)
1507
1508 def test_timeout_cleanup(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001509 """timeout (cleanup)"""
Klement Sekera75e7d132017-09-20 08:26:30 +02001510
1511 # whole packets + fragmented packets sans last fragment
1512 fragments = [
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001513 x
1514 for (_, frags_400, _) in self.pkt_infos
1515 for x in frags_400[: -1 if len(frags_400) > 1 else None]
Klement Sekera75e7d132017-09-20 08:26:30 +02001516 ]
1517
1518 # last fragments for fragmented packets
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001519 fragments2 = [
1520 frags_400[-1] for (_, frags_400, _) in self.pkt_infos if len(frags_400) > 1
1521 ]
Klement Sekera75e7d132017-09-20 08:26:30 +02001522
1523 dropped_packet_indexes = set(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001524 index for (index, frags_400, _) in self.pkt_infos if len(frags_400) > 1
1525 )
Klement Sekera75e7d132017-09-20 08:26:30 +02001526
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001527 self.vapi.ip_reassembly_set(
1528 timeout_ms=100,
1529 max_reassemblies=1000,
1530 max_reassembly_length=1000,
1531 expire_walk_interval_ms=50,
1532 )
Klement Sekera75e7d132017-09-20 08:26:30 +02001533
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001534 self.vapi.ip_reassembly_set(
1535 timeout_ms=100,
1536 max_reassemblies=1000,
1537 max_reassembly_length=1000,
1538 expire_walk_interval_ms=50,
1539 is_ip6=1,
1540 )
Klement Sekera75e7d132017-09-20 08:26:30 +02001541
1542 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +01001543 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +02001544 self.pg_start()
1545
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001546 self.virtual_sleep(0.25, "wait before sending rest of fragments")
Klement Sekera75e7d132017-09-20 08:26:30 +02001547
Klement Sekera4c533132018-02-22 11:41:12 +01001548 self.src_if.add_stream(fragments2)
Klement Sekera75e7d132017-09-20 08:26:30 +02001549 self.pg_start()
Klement Sekera75e7d132017-09-20 08:26:30 +02001550
Klement Sekera4c533132018-02-22 11:41:12 +01001551 packets = self.dst_if.get_capture(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001552 len(self.pkt_infos) - len(dropped_packet_indexes)
1553 )
Klement Sekera947a85c2019-07-24 12:40:37 +00001554 self.verify_capture(packets, dropped_packet_indexes)
Neale Ranns5c6dd172022-02-17 09:08:47 +00001555 pkts = self.src_if._get_capture(1)
Klement Sekera75e7d132017-09-20 08:26:30 +02001556 for icmp in pkts:
1557 self.assertIn(ICMPv6TimeExceeded, icmp)
1558 self.assertIn(IPv6ExtHdrFragment, icmp)
1559 self.assertIn(icmp[IPv6ExtHdrFragment].id, dropped_packet_indexes)
1560 dropped_packet_indexes.remove(icmp[IPv6ExtHdrFragment].id)
1561
Klement Sekera947a85c2019-07-24 12:40:37 +00001562 def test_disabled(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001563 """reassembly disabled"""
Klement Sekera75e7d132017-09-20 08:26:30 +02001564
1565 dropped_packet_indexes = set(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001566 index for (index, frags_400, _) in self.pkt_infos if len(frags_400) > 1
1567 )
Klement Sekera947a85c2019-07-24 12:40:37 +00001568
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001569 self.vapi.ip_reassembly_set(
1570 timeout_ms=1000,
1571 max_reassemblies=0,
1572 max_reassembly_length=3,
1573 expire_walk_interval_ms=10000,
1574 is_ip6=1,
1575 )
Klement Sekera947a85c2019-07-24 12:40:37 +00001576
1577 self.pg_enable_capture()
1578 self.src_if.add_stream(self.fragments_400)
1579 self.pg_start()
1580
1581 packets = self.dst_if.get_capture(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001582 len(self.pkt_infos) - len(dropped_packet_indexes)
1583 )
Klement Sekera947a85c2019-07-24 12:40:37 +00001584 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +01001585 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +02001586
1587 def test_missing_upper(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001588 """missing upper layer"""
1589 optdata = "\x00" * 100
1590 p = (
1591 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
1592 / IPv6(src=self.src_if.remote_ip6, dst=self.src_if.local_ip6)
1593 / IPv6ExtHdrFragment(m=1)
1594 / IPv6ExtHdrDestOpt(
1595 nh=17, options=PadN(optdata="\101" * 255) / PadN(optdata="\102" * 255)
1596 )
1597 )
Ole Troan03092c12021-11-23 15:55:39 +01001598
Klement Sekera75e7d132017-09-20 08:26:30 +02001599 self.pg_enable_capture()
Ole Troan03092c12021-11-23 15:55:39 +01001600 self.src_if.add_stream([p])
Klement Sekera75e7d132017-09-20 08:26:30 +02001601 self.pg_start()
Klement Sekera4c533132018-02-22 11:41:12 +01001602 pkts = self.src_if.get_capture(expected_count=1)
Klement Sekera75e7d132017-09-20 08:26:30 +02001603 icmp = pkts[0]
1604 self.assertIn(ICMPv6ParamProblem, icmp)
1605 self.assert_equal(icmp[ICMPv6ParamProblem].code, 3, "ICMP code")
1606
Klement Sekera755042d2021-12-01 10:14:38 +00001607 def test_truncated_fragment(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001608 """truncated fragment"""
1609 pkt = (
1610 Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac)
1611 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6, nh=44, plen=2)
1612 / IPv6ExtHdrFragment(nh=6)
1613 )
Klement Sekera755042d2021-12-01 10:14:38 +00001614
1615 self.send_and_assert_no_replies(self.pg0, [pkt], self.pg0)
1616
Klement Sekera75e7d132017-09-20 08:26:30 +02001617 def test_invalid_frag_size(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001618 """fragment size not a multiple of 8"""
1619 p = (
1620 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
1621 / IPv6(src=self.src_if.remote_ip6, dst=self.src_if.local_ip6)
1622 / UDP(sport=1234, dport=5678)
1623 / Raw()
1624 )
Klement Sekera75e7d132017-09-20 08:26:30 +02001625 self.extend_packet(p, 1000, self.padding)
1626 fragments = fragment_rfc8200(p, 1, 500)
1627 bad_fragment = fragments[0]
1628 self.extend_packet(bad_fragment, len(bad_fragment) + 5)
1629 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +01001630 self.src_if.add_stream([bad_fragment])
Klement Sekera75e7d132017-09-20 08:26:30 +02001631 self.pg_start()
Klement Sekera4c533132018-02-22 11:41:12 +01001632 pkts = self.src_if.get_capture(expected_count=1)
Klement Sekera75e7d132017-09-20 08:26:30 +02001633 icmp = pkts[0]
1634 self.assertIn(ICMPv6ParamProblem, icmp)
1635 self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code")
1636
1637 def test_invalid_packet_size(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001638 """total packet size > 65535"""
1639 p = (
1640 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
1641 / IPv6(src=self.src_if.remote_ip6, dst=self.src_if.local_ip6)
1642 / UDP(sport=1234, dport=5678)
1643 / Raw()
1644 )
Klement Sekera75e7d132017-09-20 08:26:30 +02001645 self.extend_packet(p, 1000, self.padding)
1646 fragments = fragment_rfc8200(p, 1, 500)
1647 bad_fragment = fragments[1]
1648 bad_fragment[IPv6ExtHdrFragment].offset = 65500
1649 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +01001650 self.src_if.add_stream([bad_fragment])
Klement Sekera75e7d132017-09-20 08:26:30 +02001651 self.pg_start()
Klement Sekera4c533132018-02-22 11:41:12 +01001652 pkts = self.src_if.get_capture(expected_count=1)
Klement Sekera75e7d132017-09-20 08:26:30 +02001653 icmp = pkts[0]
1654 self.assertIn(ICMPv6ParamProblem, icmp)
1655 self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code")
1656
Ole Troan03092c12021-11-23 15:55:39 +01001657 def test_atomic_fragment(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001658 """IPv6 atomic fragment"""
1659 pkt = (
1660 Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac)
1661 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6, nh=44, plen=65535)
1662 / IPv6ExtHdrFragment(
1663 offset=8191, m=1, res1=0xFF, res2=0xFF, nh=255, id=0xFFFF
1664 )
1665 / ("X" * 1452)
1666 )
Ole Troan03092c12021-11-23 15:55:39 +01001667
1668 rx = self.send_and_expect(self.pg0, [pkt], self.pg0)
1669 self.assertIn(ICMPv6ParamProblem, rx[0])
1670
1671 def test_truncated_fragment(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001672 """IPv6 truncated fragment header"""
1673 pkt = (
1674 Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac)
1675 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6, nh=44, plen=2)
1676 / IPv6ExtHdrFragment(nh=6)
1677 )
Ole Troan03092c12021-11-23 15:55:39 +01001678
Klement Sekera7c3275e2021-12-07 09:49:53 +00001679 self.send_and_assert_no_replies(self.pg0, [pkt])
Ole Troan03092c12021-11-23 15:55:39 +01001680
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001681 pkt = (
1682 Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac)
1683 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.remote_ip6)
1684 / ICMPv6EchoRequest()
1685 )
Ole Troan03092c12021-11-23 15:55:39 +01001686 rx = self.send_and_expect(self.pg0, [pkt], self.pg0)
1687
Klement Sekera7c3275e2021-12-07 09:49:53 +00001688 def test_one_fragment(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001689 """whole packet in one fragment processed independently"""
1690 pkt = (
1691 Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac)
1692 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6)
1693 / ICMPv6EchoRequest()
1694 / Raw("X" * 1600)
1695 )
Klement Sekera7c3275e2021-12-07 09:49:53 +00001696 frags = fragment_rfc8200(pkt, 1, 400)
1697
1698 # send a fragment with known id
1699 self.send_and_assert_no_replies(self.pg0, [frags[0]])
1700
1701 # send an atomic fragment with same id - should be reassembled
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001702 pkt = (
1703 Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac)
1704 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6)
1705 / IPv6ExtHdrFragment(id=1)
1706 / ICMPv6EchoRequest()
1707 )
Klement Sekera7c3275e2021-12-07 09:49:53 +00001708 rx = self.send_and_expect(self.pg0, [pkt], self.pg0)
1709 self.assertNotIn(IPv6ExtHdrFragment, rx)
1710
1711 # now finish the original reassembly, this should still be possible
1712 rx = self.send_and_expect(self.pg0, frags[1:], self.pg0, n_rx=1)
1713 self.assertNotIn(IPv6ExtHdrFragment, rx)
1714
1715 def test_bunch_of_fragments(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001716 """valid fragments followed by rogue fragments and atomic fragment"""
1717 pkt = (
1718 Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac)
1719 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6)
1720 / ICMPv6EchoRequest()
1721 / Raw("X" * 1600)
1722 )
Klement Sekera7c3275e2021-12-07 09:49:53 +00001723 frags = fragment_rfc8200(pkt, 1, 400)
1724 self.send_and_expect(self.pg0, frags, self.pg0, n_rx=1)
1725
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001726 inc_frag = (
1727 Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac)
1728 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6)
1729 / IPv6ExtHdrFragment(id=1, nh=58, offset=608)
1730 / Raw("X" * 308)
1731 )
Klement Sekera7c3275e2021-12-07 09:49:53 +00001732
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001733 self.send_and_assert_no_replies(self.pg0, inc_frag * 604)
Klement Sekera7c3275e2021-12-07 09:49:53 +00001734
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001735 pkt = (
1736 Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac)
1737 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6)
1738 / IPv6ExtHdrFragment(id=1)
1739 / ICMPv6EchoRequest()
1740 )
Klement Sekera7c3275e2021-12-07 09:49:53 +00001741 rx = self.send_and_expect(self.pg0, [pkt], self.pg0)
1742 self.assertNotIn(IPv6ExtHdrFragment, rx)
1743
Klement Sekera01c1fa42021-12-14 18:25:11 +00001744 def test_local_enable_disable(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001745 """local reassembly enabled/disable"""
Klement Sekera01c1fa42021-12-14 18:25:11 +00001746 self.vapi.ip_reassembly_enable_disable(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001747 sw_if_index=self.src_if.sw_if_index, enable_ip6=False
1748 )
Klement Sekera01c1fa42021-12-14 18:25:11 +00001749 self.vapi.ip_local_reass_enable_disable(enable_ip6=True)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001750 pkt = (
1751 Ether(src=self.src_if.local_mac, dst=self.src_if.remote_mac)
1752 / IPv6(src=self.src_if.remote_ip6, dst=self.src_if.local_ip6)
1753 / ICMPv6EchoRequest(id=1234)
1754 / Raw("X" * 1600)
1755 )
Klement Sekera01c1fa42021-12-14 18:25:11 +00001756 frags = fragment_rfc8200(pkt, 1, 400)
1757 r = self.send_and_expect(self.src_if, frags, self.src_if, n_rx=1)[0]
1758 self.assertEqual(1234, r[ICMPv6EchoReply].id)
1759 self.vapi.ip_local_reass_enable_disable()
1760
1761 self.send_and_assert_no_replies(self.src_if, frags)
1762 self.vapi.ip_local_reass_enable_disable(enable_ip6=True)
1763
Klement Sekera75e7d132017-09-20 08:26:30 +02001764
Klement Sekera630ab582019-07-19 09:14:19 +00001765class TestIPv6MWReassembly(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001766 """IPv6 Reassembly (multiple workers)"""
1767
Klement Sekera8d815022021-03-15 16:58:10 +01001768 vpp_worker_count = 3
Klement Sekera630ab582019-07-19 09:14:19 +00001769
1770 @classmethod
1771 def setUpClass(cls):
Klement Sekera01c1fa42021-12-14 18:25:11 +00001772 super().setUpClass()
Klement Sekera630ab582019-07-19 09:14:19 +00001773
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001774 cls.create_pg_interfaces(range(cls.vpp_worker_count + 1))
Klement Sekera630ab582019-07-19 09:14:19 +00001775 cls.src_if = cls.pg0
1776 cls.send_ifs = cls.pg_interfaces[:-1]
1777 cls.dst_if = cls.pg_interfaces[-1]
1778
1779 # setup all interfaces
1780 for i in cls.pg_interfaces:
1781 i.admin_up()
1782 i.config_ip6()
1783 i.resolve_ndp()
1784
1785 # packets sizes reduced here because we are generating packets without
1786 # Ethernet headers, which are added later (diff fragments go via
1787 # different interfaces)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001788 cls.packet_sizes = [
1789 64 - len(Ether()),
1790 512 - len(Ether()),
1791 1518 - len(Ether()),
1792 9018 - len(Ether()),
1793 ]
Klement Sekera630ab582019-07-19 09:14:19 +00001794 cls.padding = " abcdefghijklmn"
1795 cls.create_stream(cls.packet_sizes)
1796 cls.create_fragments()
1797
1798 @classmethod
1799 def tearDownClass(cls):
Klement Sekera01c1fa42021-12-14 18:25:11 +00001800 super().tearDownClass()
Klement Sekera630ab582019-07-19 09:14:19 +00001801
1802 def setUp(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001803 """Test setup - force timeout on existing reassemblies"""
Klement Sekera01c1fa42021-12-14 18:25:11 +00001804 super().setUp()
Klement Sekera630ab582019-07-19 09:14:19 +00001805 for intf in self.send_ifs:
1806 self.vapi.ip_reassembly_enable_disable(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001807 sw_if_index=intf.sw_if_index, enable_ip6=True
1808 )
1809 self.vapi.ip_reassembly_set(
1810 timeout_ms=0,
1811 max_reassemblies=1000,
1812 max_reassembly_length=1000,
1813 expire_walk_interval_ms=10,
1814 is_ip6=1,
1815 )
1816 self.virtual_sleep(0.25)
1817 self.vapi.ip_reassembly_set(
1818 timeout_ms=1000000,
1819 max_reassemblies=1000,
1820 max_reassembly_length=1000,
1821 expire_walk_interval_ms=1000,
1822 is_ip6=1,
1823 )
Klement Sekera630ab582019-07-19 09:14:19 +00001824
1825 def tearDown(self):
Klement Sekera01c1fa42021-12-14 18:25:11 +00001826 for intf in self.send_ifs:
1827 self.vapi.ip_reassembly_enable_disable(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001828 sw_if_index=intf.sw_if_index, enable_ip6=False
1829 )
Klement Sekera01c1fa42021-12-14 18:25:11 +00001830 super().tearDown()
Klement Sekera630ab582019-07-19 09:14:19 +00001831
1832 def show_commands_at_teardown(self):
Klement Sekera896c8962019-06-24 11:52:49 +00001833 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
Klement Sekera630ab582019-07-19 09:14:19 +00001834 self.logger.debug(self.vapi.ppcli("show buffers"))
1835
1836 @classmethod
1837 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
1838 """Create input packet stream
1839
1840 :param list packet_sizes: Required packet sizes.
1841 """
1842 for i in range(0, packet_count):
1843 info = cls.create_packet_info(cls.src_if, cls.src_if)
1844 payload = cls.info_to_payload(info)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001845 p = (
1846 IPv6(src=cls.src_if.remote_ip6, dst=cls.dst_if.remote_ip6)
1847 / UDP(sport=1234, dport=5678)
1848 / Raw(payload)
1849 )
Klement Sekera630ab582019-07-19 09:14:19 +00001850 size = packet_sizes[(i // 2) % len(packet_sizes)]
1851 cls.extend_packet(p, size, cls.padding)
1852 info.data = p
1853
1854 @classmethod
1855 def create_fragments(cls):
1856 infos = cls._packet_infos
1857 cls.pkt_infos = []
Paul Vinciguerra090096b2020-12-03 00:42:46 -05001858 for index, info in infos.items():
Klement Sekera630ab582019-07-19 09:14:19 +00001859 p = info.data
1860 # cls.logger.debug(ppp("Packet:",
1861 # p.__class__(scapy.compat.raw(p))))
1862 fragments_400 = fragment_rfc8200(p, index, 400)
1863 cls.pkt_infos.append((index, fragments_400))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001864 cls.fragments_400 = [x for (_, frags) in cls.pkt_infos for x in frags]
1865 cls.logger.debug(
1866 "Fragmented %s packets into %s 400-byte fragments, "
1867 % (len(infos), len(cls.fragments_400))
1868 )
Klement Sekera630ab582019-07-19 09:14:19 +00001869
1870 def verify_capture(self, capture, dropped_packet_indexes=[]):
1871 """Verify captured packet strea .
1872
1873 :param list capture: Captured packet stream.
1874 """
1875 info = None
1876 seen = set()
1877 for packet in capture:
1878 try:
1879 self.logger.debug(ppp("Got packet:", packet))
1880 ip = packet[IPv6]
1881 udp = packet[UDP]
1882 payload_info = self.payload_to_info(packet[Raw])
1883 packet_index = payload_info.index
1884 self.assertTrue(
1885 packet_index not in dropped_packet_indexes,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001886 ppp("Packet received, but should be dropped:", packet),
1887 )
Klement Sekera630ab582019-07-19 09:14:19 +00001888 if packet_index in seen:
1889 raise Exception(ppp("Duplicate packet received", packet))
1890 seen.add(packet_index)
1891 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
1892 info = self._packet_infos[packet_index]
1893 self.assertTrue(info is not None)
1894 self.assertEqual(packet_index, info.index)
1895 saved_packet = info.data
1896 self.assertEqual(ip.src, saved_packet[IPv6].src)
1897 self.assertEqual(ip.dst, saved_packet[IPv6].dst)
1898 self.assertEqual(udp.payload, saved_packet[UDP].payload)
1899 except Exception:
1900 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1901 raise
1902 for index in self._packet_infos:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001903 self.assertTrue(
1904 index in seen or index in dropped_packet_indexes,
1905 "Packet with packet_index %d not received" % index,
1906 )
Klement Sekera630ab582019-07-19 09:14:19 +00001907
1908 def send_packets(self, packets):
Klement Sekera8d815022021-03-15 16:58:10 +01001909 for counter in range(self.vpp_worker_count):
Klement Sekera630ab582019-07-19 09:14:19 +00001910 if 0 == len(packets[counter]):
1911 continue
1912 send_if = self.send_ifs[counter]
1913 send_if.add_stream(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001914 (
1915 Ether(dst=send_if.local_mac, src=send_if.remote_mac) / x
1916 for x in packets[counter]
1917 ),
1918 worker=counter,
1919 )
Klement Sekera630ab582019-07-19 09:14:19 +00001920 self.pg_start()
1921
1922 def test_worker_conflict(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001923 """1st and FO=0 fragments on different workers"""
Klement Sekera630ab582019-07-19 09:14:19 +00001924
1925 # in first wave we send fragments which don't start at offset 0
1926 # then we send fragments with offset 0 on a different thread
1927 # then the rest of packets on a random thread
Klement Sekera8d815022021-03-15 16:58:10 +01001928 first_packets = [[] for n in range(self.vpp_worker_count)]
1929 second_packets = [[] for n in range(self.vpp_worker_count)]
1930 rest_of_packets = [[] for n in range(self.vpp_worker_count)]
Dave Wallace7b8b4652023-08-15 19:05:26 -04001931 for _, p in self.pkt_infos:
Klement Sekera8d815022021-03-15 16:58:10 +01001932 wi = randrange(self.vpp_worker_count)
Klement Sekera630ab582019-07-19 09:14:19 +00001933 second_packets[wi].append(p[0])
1934 if len(p) <= 1:
1935 continue
1936 wi2 = wi
1937 while wi2 == wi:
Klement Sekera8d815022021-03-15 16:58:10 +01001938 wi2 = randrange(self.vpp_worker_count)
Klement Sekera630ab582019-07-19 09:14:19 +00001939 first_packets[wi2].append(p[1])
Klement Sekera8d815022021-03-15 16:58:10 +01001940 wi3 = randrange(self.vpp_worker_count)
Klement Sekera630ab582019-07-19 09:14:19 +00001941 rest_of_packets[wi3].extend(p[2:])
1942
1943 self.pg_enable_capture()
1944 self.send_packets(first_packets)
1945 self.send_packets(second_packets)
1946 self.send_packets(rest_of_packets)
1947
1948 packets = self.dst_if.get_capture(len(self.pkt_infos))
1949 self.verify_capture(packets)
1950 for send_if in self.send_ifs:
1951 send_if.assert_nothing_captured()
1952
Klement Sekera68bae5b2019-10-10 18:57:34 +00001953 self.logger.debug(self.vapi.ppcli("show trace"))
1954 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
1955 self.logger.debug(self.vapi.ppcli("show buffers"))
1956 self.vapi.cli("clear trace")
1957
Klement Sekera630ab582019-07-19 09:14:19 +00001958 self.pg_enable_capture()
1959 self.send_packets(first_packets)
1960 self.send_packets(second_packets)
1961 self.send_packets(rest_of_packets)
1962
1963 packets = self.dst_if.get_capture(len(self.pkt_infos))
1964 self.verify_capture(packets)
1965 for send_if in self.send_ifs:
1966 send_if.assert_nothing_captured()
1967
1968
Klement Sekerade34c352019-06-25 11:19:22 +00001969class TestIPv6SVReassembly(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001970 """IPv6 Shallow Virtual Reassembly"""
Klement Sekerade34c352019-06-25 11:19:22 +00001971
1972 @classmethod
1973 def setUpClass(cls):
Klement Sekera01c1fa42021-12-14 18:25:11 +00001974 super().setUpClass()
Klement Sekerade34c352019-06-25 11:19:22 +00001975
1976 cls.create_pg_interfaces([0, 1])
1977 cls.src_if = cls.pg0
1978 cls.dst_if = cls.pg1
1979
1980 # setup all interfaces
1981 for i in cls.pg_interfaces:
1982 i.admin_up()
1983 i.config_ip6()
1984 i.resolve_ndp()
1985
1986 def setUp(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001987 """Test setup - force timeout on existing reassemblies"""
Klement Sekera01c1fa42021-12-14 18:25:11 +00001988 super().setUp()
Klement Sekerade34c352019-06-25 11:19:22 +00001989 self.vapi.ip_reassembly_enable_disable(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001990 sw_if_index=self.src_if.sw_if_index,
1991 enable_ip6=True,
1992 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
1993 )
Klement Sekerade34c352019-06-25 11:19:22 +00001994 self.vapi.ip_reassembly_set(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001995 timeout_ms=0,
1996 max_reassemblies=1000,
Klement Sekerade34c352019-06-25 11:19:22 +00001997 max_reassembly_length=1000,
1998 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001999 expire_walk_interval_ms=10,
2000 is_ip6=1,
2001 )
2002 self.virtual_sleep(0.25)
Klement Sekerade34c352019-06-25 11:19:22 +00002003 self.vapi.ip_reassembly_set(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002004 timeout_ms=1000000,
2005 max_reassemblies=1000,
Klement Sekerade34c352019-06-25 11:19:22 +00002006 max_reassembly_length=1000,
2007 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002008 expire_walk_interval_ms=10000,
2009 is_ip6=1,
2010 )
Klement Sekerade34c352019-06-25 11:19:22 +00002011
2012 def tearDown(self):
Klement Sekera01c1fa42021-12-14 18:25:11 +00002013 super().tearDown()
Klement Sekerade34c352019-06-25 11:19:22 +00002014 self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details"))
2015 self.logger.debug(self.vapi.ppcli("show buffers"))
2016
2017 def test_basic(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002018 """basic reassembly"""
Klement Sekerade34c352019-06-25 11:19:22 +00002019 payload_len = 1000
2020 payload = ""
2021 counter = 0
2022 while len(payload) < payload_len:
2023 payload += "%u " % counter
2024 counter += 1
2025
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002026 p = (
2027 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
2028 / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6)
2029 / UDP(sport=1234, dport=5678)
2030 / Raw(payload)
2031 )
2032 fragments = fragment_rfc8200(p, 1, payload_len / 4)
Klement Sekerade34c352019-06-25 11:19:22 +00002033
2034 # send fragment #2 - should be cached inside reassembly
2035 self.pg_enable_capture()
2036 self.src_if.add_stream(fragments[1])
2037 self.pg_start()
2038 self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details"))
2039 self.logger.debug(self.vapi.ppcli("show buffers"))
2040 self.logger.debug(self.vapi.ppcli("show trace"))
2041 self.dst_if.assert_nothing_captured()
2042
2043 # send fragment #1 - reassembly is finished now and both fragments
2044 # forwarded
2045 self.pg_enable_capture()
2046 self.src_if.add_stream(fragments[0])
2047 self.pg_start()
2048 self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details"))
2049 self.logger.debug(self.vapi.ppcli("show buffers"))
2050 self.logger.debug(self.vapi.ppcli("show trace"))
2051 c = self.dst_if.get_capture(2)
2052 for sent, recvd in zip([fragments[1], fragments[0]], c):
2053 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
2054 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
2055 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
2056
2057 # send rest of fragments - should be immediately forwarded
2058 self.pg_enable_capture()
2059 self.src_if.add_stream(fragments[2:])
2060 self.pg_start()
2061 c = self.dst_if.get_capture(len(fragments[2:]))
2062 for sent, recvd in zip(fragments[2:], c):
2063 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
2064 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
2065 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
2066
Klement Sekera53be16d2020-12-15 21:47:36 +01002067 def test_verify_clear_trace_mid_reassembly(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002068 """verify clear trace works mid-reassembly"""
Klement Sekera53be16d2020-12-15 21:47:36 +01002069 payload_len = 1000
2070 payload = ""
2071 counter = 0
2072 while len(payload) < payload_len:
2073 payload += "%u " % counter
2074 counter += 1
2075
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002076 p = (
2077 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
2078 / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6)
2079 / UDP(sport=1234, dport=5678)
2080 / Raw(payload)
2081 )
2082 fragments = fragment_rfc8200(p, 1, payload_len / 4)
Klement Sekera53be16d2020-12-15 21:47:36 +01002083
2084 self.pg_enable_capture()
2085 self.src_if.add_stream(fragments[1])
2086 self.pg_start()
2087
2088 self.logger.debug(self.vapi.cli("show trace"))
2089 self.vapi.cli("clear trace")
2090
2091 self.pg_enable_capture()
2092 self.src_if.add_stream(fragments[0])
2093 self.pg_start()
2094 self.dst_if.get_capture(2)
2095
2096 self.logger.debug(self.vapi.cli("show trace"))
2097 self.vapi.cli("clear trace")
2098
2099 self.pg_enable_capture()
2100 self.src_if.add_stream(fragments[2:])
2101 self.pg_start()
2102 self.dst_if.get_capture(len(fragments[2:]))
2103
Klement Sekerade34c352019-06-25 11:19:22 +00002104 def test_timeout(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002105 """reassembly timeout"""
Klement Sekerade34c352019-06-25 11:19:22 +00002106 payload_len = 1000
2107 payload = ""
2108 counter = 0
2109 while len(payload) < payload_len:
2110 payload += "%u " % counter
2111 counter += 1
2112
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002113 p = (
2114 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
2115 / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6)
2116 / UDP(sport=1234, dport=5678)
2117 / Raw(payload)
2118 )
2119 fragments = fragment_rfc8200(p, 1, payload_len / 4)
Klement Sekerade34c352019-06-25 11:19:22 +00002120
2121 self.vapi.ip_reassembly_set(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002122 timeout_ms=100,
2123 max_reassemblies=1000,
Klement Sekerade34c352019-06-25 11:19:22 +00002124 max_reassembly_length=1000,
2125 expire_walk_interval_ms=50,
2126 is_ip6=1,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002127 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
2128 )
Klement Sekerade34c352019-06-25 11:19:22 +00002129
2130 # send fragments #2 and #1 - should be forwarded
2131 self.pg_enable_capture()
2132 self.src_if.add_stream(fragments[0:2])
2133 self.pg_start()
2134 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
2135 self.logger.debug(self.vapi.ppcli("show buffers"))
2136 self.logger.debug(self.vapi.ppcli("show trace"))
2137 c = self.dst_if.get_capture(2)
2138 for sent, recvd in zip([fragments[1], fragments[0]], c):
2139 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
2140 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
2141 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
2142
2143 # wait for cleanup
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002144 self.virtual_sleep(0.25, "wait before sending rest of fragments")
Klement Sekerade34c352019-06-25 11:19:22 +00002145
2146 # send rest of fragments - shouldn't be forwarded
2147 self.pg_enable_capture()
2148 self.src_if.add_stream(fragments[2:])
2149 self.pg_start()
2150 self.dst_if.assert_nothing_captured()
2151
2152 def test_lru(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002153 """reassembly reuses LRU element"""
Klement Sekerade34c352019-06-25 11:19:22 +00002154
2155 self.vapi.ip_reassembly_set(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002156 timeout_ms=1000000,
2157 max_reassemblies=1,
Klement Sekerade34c352019-06-25 11:19:22 +00002158 max_reassembly_length=1000,
2159 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002160 is_ip6=1,
2161 expire_walk_interval_ms=10000,
2162 )
Klement Sekerade34c352019-06-25 11:19:22 +00002163
2164 payload_len = 1000
2165 payload = ""
2166 counter = 0
2167 while len(payload) < payload_len:
2168 payload += "%u " % counter
2169 counter += 1
2170
2171 packet_count = 10
2172
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002173 fragments = [
2174 f
2175 for i in range(packet_count)
2176 for p in (
2177 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
2178 / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6)
2179 / UDP(sport=1234, dport=5678)
2180 / Raw(payload)
2181 )
2182 for f in fragment_rfc8200(p, i, payload_len / 4)
2183 ]
Klement Sekerade34c352019-06-25 11:19:22 +00002184
2185 self.pg_enable_capture()
2186 self.src_if.add_stream(fragments)
2187 self.pg_start()
2188 c = self.dst_if.get_capture(len(fragments))
2189 for sent, recvd in zip(fragments, c):
2190 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
2191 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
2192 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
2193
Klement Sekera7c3275e2021-12-07 09:49:53 +00002194 def test_one_fragment(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002195 """whole packet in one fragment processed independently"""
2196 pkt = (
2197 Ether(src=self.src_if.local_mac, dst=self.src_if.remote_mac)
2198 / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6)
2199 / ICMPv6EchoRequest()
2200 / Raw("X" * 1600)
2201 )
Klement Sekera7c3275e2021-12-07 09:49:53 +00002202 frags = fragment_rfc8200(pkt, 1, 400)
2203
2204 # send a fragment with known id
2205 self.send_and_expect(self.src_if, [frags[0]], self.dst_if)
2206
2207 # send an atomic fragment with same id - should be reassembled
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002208 pkt = (
2209 Ether(src=self.src_if.local_mac, dst=self.src_if.remote_mac)
2210 / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6)
2211 / IPv6ExtHdrFragment(id=1)
2212 / ICMPv6EchoRequest()
2213 )
Klement Sekera7c3275e2021-12-07 09:49:53 +00002214 rx = self.send_and_expect(self.src_if, [pkt], self.dst_if)
2215
2216 # now forward packets matching original reassembly, should still work
2217 rx = self.send_and_expect(self.src_if, frags[1:], self.dst_if)
2218
2219 def test_bunch_of_fragments(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002220 """valid fragments followed by rogue fragments and atomic fragment"""
2221 pkt = (
2222 Ether(src=self.src_if.local_mac, dst=self.src_if.remote_mac)
2223 / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6)
2224 / ICMPv6EchoRequest()
2225 / Raw("X" * 1600)
2226 )
Klement Sekera7c3275e2021-12-07 09:49:53 +00002227 frags = fragment_rfc8200(pkt, 1, 400)
2228 rx = self.send_and_expect(self.src_if, frags, self.dst_if)
2229
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002230 rogue = (
2231 Ether(src=self.src_if.local_mac, dst=self.src_if.remote_mac)
2232 / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6)
2233 / IPv6ExtHdrFragment(id=1, nh=58, offset=608)
2234 / Raw("X" * 308)
2235 )
Klement Sekera7c3275e2021-12-07 09:49:53 +00002236
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002237 self.send_and_expect(self.src_if, rogue * 604, self.dst_if)
Klement Sekera7c3275e2021-12-07 09:49:53 +00002238
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002239 pkt = (
2240 Ether(src=self.src_if.local_mac, dst=self.src_if.remote_mac)
2241 / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6)
2242 / IPv6ExtHdrFragment(id=1)
2243 / ICMPv6EchoRequest()
2244 )
Klement Sekera7c3275e2021-12-07 09:49:53 +00002245 rx = self.send_and_expect(self.src_if, [pkt], self.dst_if)
2246
Klement Sekera755042d2021-12-01 10:14:38 +00002247 def test_truncated_fragment(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002248 """truncated fragment"""
2249 pkt = (
2250 Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac)
2251 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6, nh=44, plen=2)
2252 / IPv6ExtHdrFragment(nh=6)
2253 )
Klement Sekera755042d2021-12-01 10:14:38 +00002254
2255 self.send_and_assert_no_replies(self.pg0, [pkt], self.pg0)
2256
Klement Sekerade34c352019-06-25 11:19:22 +00002257
Juraj Sloboda3048b632018-10-02 11:13:53 +02002258class TestIPv4ReassemblyLocalNode(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002259 """IPv4 Reassembly for packets coming to ip4-local node"""
Juraj Sloboda3048b632018-10-02 11:13:53 +02002260
2261 @classmethod
2262 def setUpClass(cls):
Klement Sekera01c1fa42021-12-14 18:25:11 +00002263 super().setUpClass()
Juraj Sloboda3048b632018-10-02 11:13:53 +02002264
2265 cls.create_pg_interfaces([0])
2266 cls.src_dst_if = cls.pg0
2267
2268 # setup all interfaces
2269 for i in cls.pg_interfaces:
2270 i.admin_up()
2271 i.config_ip4()
2272 i.resolve_arp()
2273
2274 cls.padding = " abcdefghijklmn"
2275 cls.create_stream()
2276 cls.create_fragments()
2277
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07002278 @classmethod
2279 def tearDownClass(cls):
Klement Sekera01c1fa42021-12-14 18:25:11 +00002280 super().tearDownClass()
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07002281
Juraj Sloboda3048b632018-10-02 11:13:53 +02002282 def setUp(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002283 """Test setup - force timeout on existing reassemblies"""
Klement Sekera01c1fa42021-12-14 18:25:11 +00002284 super().setUp()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002285 self.vapi.ip_reassembly_set(
2286 timeout_ms=0,
2287 max_reassemblies=1000,
2288 max_reassembly_length=1000,
2289 expire_walk_interval_ms=10,
2290 )
2291 self.virtual_sleep(0.25)
2292 self.vapi.ip_reassembly_set(
2293 timeout_ms=1000000,
2294 max_reassemblies=1000,
2295 max_reassembly_length=1000,
2296 expire_walk_interval_ms=10000,
2297 )
Juraj Sloboda3048b632018-10-02 11:13:53 +02002298
2299 def tearDown(self):
Klement Sekera01c1fa42021-12-14 18:25:11 +00002300 super().tearDown()
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -07002301
2302 def show_commands_at_teardown(self):
Klement Sekera896c8962019-06-24 11:52:49 +00002303 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
Klement Sekeracae98b72019-02-19 13:53:43 +01002304 self.logger.debug(self.vapi.ppcli("show buffers"))
Juraj Sloboda3048b632018-10-02 11:13:53 +02002305
2306 @classmethod
2307 def create_stream(cls, packet_count=test_packet_count):
2308 """Create input packet stream for defined interface.
2309
2310 :param list packet_sizes: Required packet sizes.
2311 """
2312 for i in range(0, packet_count):
2313 info = cls.create_packet_info(cls.src_dst_if, cls.src_dst_if)
2314 payload = cls.info_to_payload(info)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002315 p = (
2316 Ether(dst=cls.src_dst_if.local_mac, src=cls.src_dst_if.remote_mac)
2317 / IP(
2318 id=info.index,
2319 src=cls.src_dst_if.remote_ip4,
2320 dst=cls.src_dst_if.local_ip4,
2321 )
2322 / ICMP(type="echo-request", id=1234)
2323 / Raw(payload)
2324 )
Juraj Sloboda3048b632018-10-02 11:13:53 +02002325 cls.extend_packet(p, 1518, cls.padding)
2326 info.data = p
2327
2328 @classmethod
2329 def create_fragments(cls):
2330 infos = cls._packet_infos
2331 cls.pkt_infos = []
Paul Vinciguerra090096b2020-12-03 00:42:46 -05002332 for index, info in infos.items():
Juraj Sloboda3048b632018-10-02 11:13:53 +02002333 p = info.data
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07002334 # cls.logger.debug(ppp("Packet:",
2335 # p.__class__(scapy.compat.raw(p))))
Juraj Sloboda3048b632018-10-02 11:13:53 +02002336 fragments_300 = fragment_rfc791(p, 300)
2337 cls.pkt_infos.append((index, fragments_300))
2338 cls.fragments_300 = [x for (_, frags) in cls.pkt_infos for x in frags]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002339 cls.logger.debug(
2340 "Fragmented %s packets into %s 300-byte fragments"
2341 % (len(infos), len(cls.fragments_300))
2342 )
Juraj Sloboda3048b632018-10-02 11:13:53 +02002343
2344 def verify_capture(self, capture):
2345 """Verify captured packet stream.
2346
2347 :param list capture: Captured packet stream.
2348 """
2349 info = None
2350 seen = set()
2351 for packet in capture:
2352 try:
2353 self.logger.debug(ppp("Got packet:", packet))
2354 ip = packet[IP]
2355 icmp = packet[ICMP]
Paul Vinciguerraeaea4212019-03-06 11:58:06 -08002356 payload_info = self.payload_to_info(packet[Raw])
Juraj Sloboda3048b632018-10-02 11:13:53 +02002357 packet_index = payload_info.index
2358 if packet_index in seen:
2359 raise Exception(ppp("Duplicate packet received", packet))
2360 seen.add(packet_index)
2361 self.assertEqual(payload_info.dst, self.src_dst_if.sw_if_index)
2362 info = self._packet_infos[packet_index]
Klement Sekera14d7e902018-12-10 13:46:09 +01002363 self.assertIsNotNone(info)
Juraj Sloboda3048b632018-10-02 11:13:53 +02002364 self.assertEqual(packet_index, info.index)
2365 saved_packet = info.data
2366 self.assertEqual(ip.src, saved_packet[IP].dst)
2367 self.assertEqual(ip.dst, saved_packet[IP].src)
2368 self.assertEqual(icmp.type, 0) # echo reply
2369 self.assertEqual(icmp.id, saved_packet[ICMP].id)
2370 self.assertEqual(icmp.payload, saved_packet[ICMP].payload)
2371 except Exception:
2372 self.logger.error(ppp("Unexpected or invalid packet:", packet))
2373 raise
2374 for index in self._packet_infos:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002375 self.assertIn(
2376 index, seen, "Packet with packet_index %d not received" % index
2377 )
Juraj Sloboda3048b632018-10-02 11:13:53 +02002378
2379 def test_reassembly(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002380 """basic reassembly"""
Juraj Sloboda3048b632018-10-02 11:13:53 +02002381
2382 self.pg_enable_capture()
2383 self.src_dst_if.add_stream(self.fragments_300)
2384 self.pg_start()
2385
2386 packets = self.src_dst_if.get_capture(len(self.pkt_infos))
2387 self.verify_capture(packets)
2388
2389 # run it all again to verify correctness
2390 self.pg_enable_capture()
2391 self.src_dst_if.add_stream(self.fragments_300)
2392 self.pg_start()
2393
2394 packets = self.src_dst_if.get_capture(len(self.pkt_infos))
2395 self.verify_capture(packets)
2396
2397
Klement Sekera75e7d132017-09-20 08:26:30 +02002398class TestFIFReassembly(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002399 """Fragments in fragments reassembly"""
Klement Sekera75e7d132017-09-20 08:26:30 +02002400
2401 @classmethod
2402 def setUpClass(cls):
Klement Sekera01c1fa42021-12-14 18:25:11 +00002403 super().setUpClass()
Klement Sekera75e7d132017-09-20 08:26:30 +02002404
Klement Sekera4c533132018-02-22 11:41:12 +01002405 cls.create_pg_interfaces([0, 1])
2406 cls.src_if = cls.pg0
2407 cls.dst_if = cls.pg1
2408 for i in cls.pg_interfaces:
2409 i.admin_up()
2410 i.config_ip4()
2411 i.resolve_arp()
2412 i.config_ip6()
2413 i.resolve_ndp()
Klement Sekera75e7d132017-09-20 08:26:30 +02002414
Klement Sekera75e7d132017-09-20 08:26:30 +02002415 cls.packet_sizes = [64, 512, 1518, 9018]
2416 cls.padding = " abcdefghijklmn"
2417
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07002418 @classmethod
2419 def tearDownClass(cls):
Klement Sekera01c1fa42021-12-14 18:25:11 +00002420 super().tearDownClass()
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07002421
Klement Sekera75e7d132017-09-20 08:26:30 +02002422 def setUp(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002423 """Test setup - force timeout on existing reassemblies"""
Klement Sekera01c1fa42021-12-14 18:25:11 +00002424 super().setUp()
Klement Sekera4c533132018-02-22 11:41:12 +01002425 self.vapi.ip_reassembly_enable_disable(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002426 sw_if_index=self.src_if.sw_if_index, enable_ip4=True, enable_ip6=True
2427 )
Klement Sekera4c533132018-02-22 11:41:12 +01002428 self.vapi.ip_reassembly_enable_disable(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002429 sw_if_index=self.dst_if.sw_if_index, enable_ip4=True, enable_ip6=True
2430 )
2431 self.vapi.ip_reassembly_set(
2432 timeout_ms=0,
2433 max_reassemblies=1000,
2434 max_reassembly_length=1000,
2435 expire_walk_interval_ms=10,
2436 )
2437 self.vapi.ip_reassembly_set(
2438 timeout_ms=0,
2439 max_reassemblies=1000,
2440 max_reassembly_length=1000,
2441 expire_walk_interval_ms=10,
2442 is_ip6=1,
2443 )
2444 self.virtual_sleep(0.25)
2445 self.vapi.ip_reassembly_set(
2446 timeout_ms=1000000,
2447 max_reassemblies=1000,
2448 max_reassembly_length=1000,
2449 expire_walk_interval_ms=10000,
2450 )
2451 self.vapi.ip_reassembly_set(
2452 timeout_ms=1000000,
2453 max_reassemblies=1000,
2454 max_reassembly_length=1000,
2455 expire_walk_interval_ms=10000,
2456 is_ip6=1,
2457 )
Klement Sekera75e7d132017-09-20 08:26:30 +02002458
2459 def tearDown(self):
Klement Sekera01c1fa42021-12-14 18:25:11 +00002460 super().tearDown()
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -07002461
2462 def show_commands_at_teardown(self):
Klement Sekera896c8962019-06-24 11:52:49 +00002463 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
2464 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
Klement Sekeracae98b72019-02-19 13:53:43 +01002465 self.logger.debug(self.vapi.ppcli("show buffers"))
Klement Sekera75e7d132017-09-20 08:26:30 +02002466
2467 def verify_capture(self, capture, ip_class, dropped_packet_indexes=[]):
2468 """Verify captured packet stream.
2469
2470 :param list capture: Captured packet stream.
2471 """
2472 info = None
2473 seen = set()
2474 for packet in capture:
2475 try:
Klement Sekera4c533132018-02-22 11:41:12 +01002476 self.logger.debug(ppp("Got packet:", packet))
Klement Sekera75e7d132017-09-20 08:26:30 +02002477 ip = packet[ip_class]
2478 udp = packet[UDP]
Paul Vinciguerraeaea4212019-03-06 11:58:06 -08002479 payload_info = self.payload_to_info(packet[Raw])
Klement Sekera75e7d132017-09-20 08:26:30 +02002480 packet_index = payload_info.index
2481 self.assertTrue(
2482 packet_index not in dropped_packet_indexes,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002483 ppp("Packet received, but should be dropped:", packet),
2484 )
Klement Sekera75e7d132017-09-20 08:26:30 +02002485 if packet_index in seen:
2486 raise Exception(ppp("Duplicate packet received", packet))
2487 seen.add(packet_index)
Klement Sekera4c533132018-02-22 11:41:12 +01002488 self.assertEqual(payload_info.dst, self.dst_if.sw_if_index)
Klement Sekera75e7d132017-09-20 08:26:30 +02002489 info = self._packet_infos[packet_index]
2490 self.assertTrue(info is not None)
2491 self.assertEqual(packet_index, info.index)
2492 saved_packet = info.data
2493 self.assertEqual(ip.src, saved_packet[ip_class].src)
2494 self.assertEqual(ip.dst, saved_packet[ip_class].dst)
2495 self.assertEqual(udp.payload, saved_packet[UDP].payload)
Klement Sekera4c533132018-02-22 11:41:12 +01002496 except Exception:
Klement Sekera75e7d132017-09-20 08:26:30 +02002497 self.logger.error(ppp("Unexpected or invalid packet:", packet))
2498 raise
2499 for index in self._packet_infos:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002500 self.assertTrue(
2501 index in seen or index in dropped_packet_indexes,
2502 "Packet with packet_index %d not received" % index,
2503 )
Klement Sekera75e7d132017-09-20 08:26:30 +02002504
2505 def test_fif4(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002506 """Fragments in fragments (4o4)"""
Klement Sekera75e7d132017-09-20 08:26:30 +02002507
2508 # TODO this should be ideally in setUpClass, but then we hit a bug
2509 # with VppIpRoute incorrectly reporting it's present when it's not
2510 # so we need to manually remove the vpp config, thus we cannot have
2511 # it shared for multiple test cases
2512 self.tun_ip4 = "1.1.1.2"
2513
Klement Sekera4c533132018-02-22 11:41:12 +01002514 self.gre4 = VppGreInterface(self, self.src_if.local_ip4, self.tun_ip4)
Klement Sekera75e7d132017-09-20 08:26:30 +02002515 self.gre4.add_vpp_config()
2516 self.gre4.admin_up()
2517 self.gre4.config_ip4()
2518
Klement Sekera4c533132018-02-22 11:41:12 +01002519 self.vapi.ip_reassembly_enable_disable(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002520 sw_if_index=self.gre4.sw_if_index, enable_ip4=True
2521 )
Klement Sekera4c533132018-02-22 11:41:12 +01002522
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002523 self.route4 = VppIpRoute(
2524 self,
2525 self.tun_ip4,
2526 32,
2527 [VppRoutePath(self.src_if.remote_ip4, self.src_if.sw_if_index)],
2528 )
Klement Sekera75e7d132017-09-20 08:26:30 +02002529 self.route4.add_vpp_config()
2530
2531 self.reset_packet_infos()
2532 for i in range(test_packet_count):
Klement Sekera4c533132018-02-22 11:41:12 +01002533 info = self.create_packet_info(self.src_if, self.dst_if)
Klement Sekera75e7d132017-09-20 08:26:30 +02002534 payload = self.info_to_payload(info)
Klement Sekera4c533132018-02-22 11:41:12 +01002535 # Ethernet header here is only for size calculation, thus it
2536 # doesn't matter how it's initialized. This is to ensure that
2537 # reassembled packet is not > 9000 bytes, so that it's not dropped
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002538 p = (
2539 Ether()
2540 / IP(id=i, src=self.src_if.remote_ip4, dst=self.dst_if.remote_ip4)
2541 / UDP(sport=1234, dport=5678)
2542 / Raw(payload)
2543 )
Klement Sekera75e7d132017-09-20 08:26:30 +02002544 size = self.packet_sizes[(i // 2) % len(self.packet_sizes)]
2545 self.extend_packet(p, size, self.padding)
Klement Sekera4c533132018-02-22 11:41:12 +01002546 info.data = p[IP] # use only IP part, without ethernet header
Klement Sekera75e7d132017-09-20 08:26:30 +02002547
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002548 fragments = [
2549 x
2550 for _, p in self._packet_infos.items()
2551 for x in fragment_rfc791(p.data, 400)
2552 ]
Klement Sekera75e7d132017-09-20 08:26:30 +02002553
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002554 encapped_fragments = [
2555 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
2556 / IP(src=self.tun_ip4, dst=self.src_if.local_ip4)
2557 / GRE()
2558 / p
2559 for p in fragments
2560 ]
Klement Sekera75e7d132017-09-20 08:26:30 +02002561
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002562 fragmented_encapped_fragments = [
2563 x for p in encapped_fragments for x in fragment_rfc791(p, 200)
2564 ]
Klement Sekera75e7d132017-09-20 08:26:30 +02002565
Klement Sekera4c533132018-02-22 11:41:12 +01002566 self.src_if.add_stream(fragmented_encapped_fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +02002567
2568 self.pg_enable_capture(self.pg_interfaces)
2569 self.pg_start()
2570
Klement Sekera4c533132018-02-22 11:41:12 +01002571 self.src_if.assert_nothing_captured()
2572 packets = self.dst_if.get_capture(len(self._packet_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +02002573 self.verify_capture(packets, IP)
2574
2575 # TODO remove gre vpp config by hand until VppIpRoute gets fixed
2576 # so that it's query_vpp_config() works as it should
2577 self.gre4.remove_vpp_config()
Klement Sekera4c533132018-02-22 11:41:12 +01002578 self.logger.debug(self.vapi.ppcli("show interface"))
Klement Sekera75e7d132017-09-20 08:26:30 +02002579
2580 def test_fif6(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002581 """Fragments in fragments (6o6)"""
Klement Sekera75e7d132017-09-20 08:26:30 +02002582 # TODO this should be ideally in setUpClass, but then we hit a bug
2583 # with VppIpRoute incorrectly reporting it's present when it's not
2584 # so we need to manually remove the vpp config, thus we cannot have
2585 # it shared for multiple test cases
2586 self.tun_ip6 = "1002::1"
2587
Neale Ranns5a8844b2019-04-16 07:15:35 +00002588 self.gre6 = VppGreInterface(self, self.src_if.local_ip6, self.tun_ip6)
Klement Sekera75e7d132017-09-20 08:26:30 +02002589 self.gre6.add_vpp_config()
2590 self.gre6.admin_up()
2591 self.gre6.config_ip6()
2592
Klement Sekera4c533132018-02-22 11:41:12 +01002593 self.vapi.ip_reassembly_enable_disable(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002594 sw_if_index=self.gre6.sw_if_index, enable_ip6=True
2595 )
Klement Sekera4c533132018-02-22 11:41:12 +01002596
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002597 self.route6 = VppIpRoute(
2598 self,
2599 self.tun_ip6,
2600 128,
2601 [VppRoutePath(self.src_if.remote_ip6, self.src_if.sw_if_index)],
2602 )
Klement Sekera75e7d132017-09-20 08:26:30 +02002603 self.route6.add_vpp_config()
2604
2605 self.reset_packet_infos()
2606 for i in range(test_packet_count):
Klement Sekera4c533132018-02-22 11:41:12 +01002607 info = self.create_packet_info(self.src_if, self.dst_if)
Klement Sekera75e7d132017-09-20 08:26:30 +02002608 payload = self.info_to_payload(info)
Klement Sekera4c533132018-02-22 11:41:12 +01002609 # Ethernet header here is only for size calculation, thus it
2610 # doesn't matter how it's initialized. This is to ensure that
2611 # reassembled packet is not > 9000 bytes, so that it's not dropped
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002612 p = (
2613 Ether()
2614 / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6)
2615 / UDP(sport=1234, dport=5678)
2616 / Raw(payload)
2617 )
Klement Sekera75e7d132017-09-20 08:26:30 +02002618 size = self.packet_sizes[(i // 2) % len(self.packet_sizes)]
2619 self.extend_packet(p, size, self.padding)
Klement Sekera4c533132018-02-22 11:41:12 +01002620 info.data = p[IPv6] # use only IPv6 part, without ethernet header
Klement Sekera75e7d132017-09-20 08:26:30 +02002621
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002622 fragments = [
2623 x
2624 for _, i in self._packet_infos.items()
2625 for x in fragment_rfc8200(i.data, i.index, 400)
2626 ]
Klement Sekera75e7d132017-09-20 08:26:30 +02002627
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002628 encapped_fragments = [
2629 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
2630 / IPv6(src=self.tun_ip6, dst=self.src_if.local_ip6)
2631 / GRE()
2632 / p
2633 for p in fragments
2634 ]
Klement Sekera75e7d132017-09-20 08:26:30 +02002635
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002636 fragmented_encapped_fragments = [
2637 x
2638 for p in encapped_fragments
2639 for x in (
Klement Sekera75e7d132017-09-20 08:26:30 +02002640 fragment_rfc8200(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002641 p, 2 * len(self._packet_infos) + p[IPv6ExtHdrFragment].id, 200
2642 )
2643 if IPv6ExtHdrFragment in p
2644 else [p]
Klement Sekera75e7d132017-09-20 08:26:30 +02002645 )
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002646 ]
Klement Sekera75e7d132017-09-20 08:26:30 +02002647
Klement Sekera4c533132018-02-22 11:41:12 +01002648 self.src_if.add_stream(fragmented_encapped_fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +02002649
2650 self.pg_enable_capture(self.pg_interfaces)
2651 self.pg_start()
2652
Klement Sekera4c533132018-02-22 11:41:12 +01002653 self.src_if.assert_nothing_captured()
2654 packets = self.dst_if.get_capture(len(self._packet_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +02002655 self.verify_capture(packets, IPv6)
2656
2657 # TODO remove gre vpp config by hand until VppIpRoute gets fixed
2658 # so that it's query_vpp_config() works as it should
Klement Sekera3ecc2212018-03-27 10:34:43 +02002659 self.gre6.remove_vpp_config()
Klement Sekera75e7d132017-09-20 08:26:30 +02002660
2661
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002662if __name__ == "__main__":
Klement Sekera75e7d132017-09-20 08:26:30 +02002663 unittest.main(testRunner=VppTestRunner)