blob: 98c50f9bb61568494bc6e23da53e1289fd4aa73e [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
1607 def test_invalid_frag_size(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001608 """fragment size not a multiple of 8"""
1609 p = (
1610 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
1611 / IPv6(src=self.src_if.remote_ip6, dst=self.src_if.local_ip6)
1612 / UDP(sport=1234, dport=5678)
1613 / Raw()
1614 )
Klement Sekera75e7d132017-09-20 08:26:30 +02001615 self.extend_packet(p, 1000, self.padding)
1616 fragments = fragment_rfc8200(p, 1, 500)
1617 bad_fragment = fragments[0]
1618 self.extend_packet(bad_fragment, len(bad_fragment) + 5)
1619 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +01001620 self.src_if.add_stream([bad_fragment])
Klement Sekera75e7d132017-09-20 08:26:30 +02001621 self.pg_start()
Klement Sekera4c533132018-02-22 11:41:12 +01001622 pkts = self.src_if.get_capture(expected_count=1)
Klement Sekera75e7d132017-09-20 08:26:30 +02001623 icmp = pkts[0]
1624 self.assertIn(ICMPv6ParamProblem, icmp)
1625 self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code")
1626
1627 def test_invalid_packet_size(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001628 """total packet size > 65535"""
1629 p = (
1630 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
1631 / IPv6(src=self.src_if.remote_ip6, dst=self.src_if.local_ip6)
1632 / UDP(sport=1234, dport=5678)
1633 / Raw()
1634 )
Klement Sekera75e7d132017-09-20 08:26:30 +02001635 self.extend_packet(p, 1000, self.padding)
1636 fragments = fragment_rfc8200(p, 1, 500)
1637 bad_fragment = fragments[1]
1638 bad_fragment[IPv6ExtHdrFragment].offset = 65500
1639 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +01001640 self.src_if.add_stream([bad_fragment])
Klement Sekera75e7d132017-09-20 08:26:30 +02001641 self.pg_start()
Klement Sekera4c533132018-02-22 11:41:12 +01001642 pkts = self.src_if.get_capture(expected_count=1)
Klement Sekera75e7d132017-09-20 08:26:30 +02001643 icmp = pkts[0]
1644 self.assertIn(ICMPv6ParamProblem, icmp)
1645 self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code")
1646
Ole Troan03092c12021-11-23 15:55:39 +01001647 def test_atomic_fragment(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001648 """IPv6 atomic fragment"""
1649 pkt = (
Steven Luonge4238aa2024-04-19 09:49:20 -07001650 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001651 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6, nh=44, plen=65535)
1652 / IPv6ExtHdrFragment(
1653 offset=8191, m=1, res1=0xFF, res2=0xFF, nh=255, id=0xFFFF
1654 )
1655 / ("X" * 1452)
1656 )
Ole Troan03092c12021-11-23 15:55:39 +01001657
1658 rx = self.send_and_expect(self.pg0, [pkt], self.pg0)
1659 self.assertIn(ICMPv6ParamProblem, rx[0])
1660
1661 def test_truncated_fragment(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001662 """IPv6 truncated fragment header"""
1663 pkt = (
1664 Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac)
1665 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6, nh=44, plen=2)
1666 / IPv6ExtHdrFragment(nh=6)
1667 )
Ole Troan03092c12021-11-23 15:55:39 +01001668
Klement Sekera7c3275e2021-12-07 09:49:53 +00001669 self.send_and_assert_no_replies(self.pg0, [pkt])
Ole Troan03092c12021-11-23 15:55:39 +01001670
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001671 pkt = (
Steven Luonge4238aa2024-04-19 09:49:20 -07001672 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001673 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.remote_ip6)
1674 / ICMPv6EchoRequest()
1675 )
Ole Troan03092c12021-11-23 15:55:39 +01001676 rx = self.send_and_expect(self.pg0, [pkt], self.pg0)
1677
Klement Sekera7c3275e2021-12-07 09:49:53 +00001678 def test_one_fragment(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001679 """whole packet in one fragment processed independently"""
1680 pkt = (
Steven Luonge4238aa2024-04-19 09:49:20 -07001681 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001682 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6)
1683 / ICMPv6EchoRequest()
1684 / Raw("X" * 1600)
1685 )
Klement Sekera7c3275e2021-12-07 09:49:53 +00001686 frags = fragment_rfc8200(pkt, 1, 400)
1687
1688 # send a fragment with known id
1689 self.send_and_assert_no_replies(self.pg0, [frags[0]])
1690
1691 # send an atomic fragment with same id - should be reassembled
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001692 pkt = (
Steven Luonge4238aa2024-04-19 09:49:20 -07001693 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001694 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6)
1695 / IPv6ExtHdrFragment(id=1)
1696 / ICMPv6EchoRequest()
1697 )
Klement Sekera7c3275e2021-12-07 09:49:53 +00001698 rx = self.send_and_expect(self.pg0, [pkt], self.pg0)
1699 self.assertNotIn(IPv6ExtHdrFragment, rx)
1700
1701 # now finish the original reassembly, this should still be possible
1702 rx = self.send_and_expect(self.pg0, frags[1:], self.pg0, n_rx=1)
1703 self.assertNotIn(IPv6ExtHdrFragment, rx)
1704
1705 def test_bunch_of_fragments(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001706 """valid fragments followed by rogue fragments and atomic fragment"""
1707 pkt = (
Steven Luonge4238aa2024-04-19 09:49:20 -07001708 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001709 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6)
1710 / ICMPv6EchoRequest()
1711 / Raw("X" * 1600)
1712 )
Klement Sekera7c3275e2021-12-07 09:49:53 +00001713 frags = fragment_rfc8200(pkt, 1, 400)
1714 self.send_and_expect(self.pg0, frags, self.pg0, n_rx=1)
1715
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001716 inc_frag = (
1717 Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac)
1718 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6)
1719 / IPv6ExtHdrFragment(id=1, nh=58, offset=608)
1720 / Raw("X" * 308)
1721 )
Klement Sekera7c3275e2021-12-07 09:49:53 +00001722
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001723 self.send_and_assert_no_replies(self.pg0, inc_frag * 604)
Klement Sekera7c3275e2021-12-07 09:49:53 +00001724
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001725 pkt = (
Steven Luonge4238aa2024-04-19 09:49:20 -07001726 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001727 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6)
1728 / IPv6ExtHdrFragment(id=1)
1729 / ICMPv6EchoRequest()
1730 )
Klement Sekera7c3275e2021-12-07 09:49:53 +00001731 rx = self.send_and_expect(self.pg0, [pkt], self.pg0)
1732 self.assertNotIn(IPv6ExtHdrFragment, rx)
1733
Klement Sekera01c1fa42021-12-14 18:25:11 +00001734 def test_local_enable_disable(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001735 """local reassembly enabled/disable"""
Klement Sekera01c1fa42021-12-14 18:25:11 +00001736 self.vapi.ip_reassembly_enable_disable(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001737 sw_if_index=self.src_if.sw_if_index, enable_ip6=False
1738 )
Klement Sekera01c1fa42021-12-14 18:25:11 +00001739 self.vapi.ip_local_reass_enable_disable(enable_ip6=True)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001740 pkt = (
Steven Luonge4238aa2024-04-19 09:49:20 -07001741 Ether(src=self.src_if.remote_mac, dst=self.src_if.local_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001742 / IPv6(src=self.src_if.remote_ip6, dst=self.src_if.local_ip6)
1743 / ICMPv6EchoRequest(id=1234)
1744 / Raw("X" * 1600)
1745 )
Klement Sekera01c1fa42021-12-14 18:25:11 +00001746 frags = fragment_rfc8200(pkt, 1, 400)
1747 r = self.send_and_expect(self.src_if, frags, self.src_if, n_rx=1)[0]
1748 self.assertEqual(1234, r[ICMPv6EchoReply].id)
1749 self.vapi.ip_local_reass_enable_disable()
1750
1751 self.send_and_assert_no_replies(self.src_if, frags)
1752 self.vapi.ip_local_reass_enable_disable(enable_ip6=True)
1753
Klement Sekera75e7d132017-09-20 08:26:30 +02001754
Klement Sekera630ab582019-07-19 09:14:19 +00001755class TestIPv6MWReassembly(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001756 """IPv6 Reassembly (multiple workers)"""
1757
Klement Sekera8d815022021-03-15 16:58:10 +01001758 vpp_worker_count = 3
Klement Sekera630ab582019-07-19 09:14:19 +00001759
1760 @classmethod
1761 def setUpClass(cls):
Klement Sekera01c1fa42021-12-14 18:25:11 +00001762 super().setUpClass()
Klement Sekera630ab582019-07-19 09:14:19 +00001763
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001764 cls.create_pg_interfaces(range(cls.vpp_worker_count + 1))
Klement Sekera630ab582019-07-19 09:14:19 +00001765 cls.src_if = cls.pg0
1766 cls.send_ifs = cls.pg_interfaces[:-1]
1767 cls.dst_if = cls.pg_interfaces[-1]
1768
1769 # setup all interfaces
1770 for i in cls.pg_interfaces:
1771 i.admin_up()
1772 i.config_ip6()
1773 i.resolve_ndp()
1774
1775 # packets sizes reduced here because we are generating packets without
1776 # Ethernet headers, which are added later (diff fragments go via
1777 # different interfaces)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001778 cls.packet_sizes = [
1779 64 - len(Ether()),
1780 512 - len(Ether()),
1781 1518 - len(Ether()),
1782 9018 - len(Ether()),
1783 ]
Klement Sekera630ab582019-07-19 09:14:19 +00001784 cls.padding = " abcdefghijklmn"
1785 cls.create_stream(cls.packet_sizes)
1786 cls.create_fragments()
1787
1788 @classmethod
1789 def tearDownClass(cls):
Klement Sekera01c1fa42021-12-14 18:25:11 +00001790 super().tearDownClass()
Klement Sekera630ab582019-07-19 09:14:19 +00001791
1792 def setUp(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001793 """Test setup - force timeout on existing reassemblies"""
Klement Sekera01c1fa42021-12-14 18:25:11 +00001794 super().setUp()
Klement Sekera630ab582019-07-19 09:14:19 +00001795 for intf in self.send_ifs:
1796 self.vapi.ip_reassembly_enable_disable(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001797 sw_if_index=intf.sw_if_index, enable_ip6=True
1798 )
1799 self.vapi.ip_reassembly_set(
1800 timeout_ms=0,
1801 max_reassemblies=1000,
1802 max_reassembly_length=1000,
1803 expire_walk_interval_ms=10,
1804 is_ip6=1,
1805 )
1806 self.virtual_sleep(0.25)
1807 self.vapi.ip_reassembly_set(
1808 timeout_ms=1000000,
1809 max_reassemblies=1000,
1810 max_reassembly_length=1000,
1811 expire_walk_interval_ms=1000,
1812 is_ip6=1,
1813 )
Klement Sekera630ab582019-07-19 09:14:19 +00001814
1815 def tearDown(self):
Klement Sekera01c1fa42021-12-14 18:25:11 +00001816 for intf in self.send_ifs:
1817 self.vapi.ip_reassembly_enable_disable(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001818 sw_if_index=intf.sw_if_index, enable_ip6=False
1819 )
Klement Sekera01c1fa42021-12-14 18:25:11 +00001820 super().tearDown()
Klement Sekera630ab582019-07-19 09:14:19 +00001821
1822 def show_commands_at_teardown(self):
Klement Sekera896c8962019-06-24 11:52:49 +00001823 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
Klement Sekera630ab582019-07-19 09:14:19 +00001824 self.logger.debug(self.vapi.ppcli("show buffers"))
1825
1826 @classmethod
1827 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
1828 """Create input packet stream
1829
1830 :param list packet_sizes: Required packet sizes.
1831 """
1832 for i in range(0, packet_count):
1833 info = cls.create_packet_info(cls.src_if, cls.src_if)
1834 payload = cls.info_to_payload(info)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001835 p = (
1836 IPv6(src=cls.src_if.remote_ip6, dst=cls.dst_if.remote_ip6)
1837 / UDP(sport=1234, dport=5678)
1838 / Raw(payload)
1839 )
Klement Sekera630ab582019-07-19 09:14:19 +00001840 size = packet_sizes[(i // 2) % len(packet_sizes)]
1841 cls.extend_packet(p, size, cls.padding)
1842 info.data = p
1843
1844 @classmethod
1845 def create_fragments(cls):
1846 infos = cls._packet_infos
1847 cls.pkt_infos = []
Paul Vinciguerra090096b2020-12-03 00:42:46 -05001848 for index, info in infos.items():
Klement Sekera630ab582019-07-19 09:14:19 +00001849 p = info.data
1850 # cls.logger.debug(ppp("Packet:",
1851 # p.__class__(scapy.compat.raw(p))))
1852 fragments_400 = fragment_rfc8200(p, index, 400)
1853 cls.pkt_infos.append((index, fragments_400))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001854 cls.fragments_400 = [x for (_, frags) in cls.pkt_infos for x in frags]
1855 cls.logger.debug(
1856 "Fragmented %s packets into %s 400-byte fragments, "
1857 % (len(infos), len(cls.fragments_400))
1858 )
Klement Sekera630ab582019-07-19 09:14:19 +00001859
1860 def verify_capture(self, capture, dropped_packet_indexes=[]):
1861 """Verify captured packet strea .
1862
1863 :param list capture: Captured packet stream.
1864 """
1865 info = None
1866 seen = set()
1867 for packet in capture:
1868 try:
1869 self.logger.debug(ppp("Got packet:", packet))
1870 ip = packet[IPv6]
1871 udp = packet[UDP]
1872 payload_info = self.payload_to_info(packet[Raw])
1873 packet_index = payload_info.index
1874 self.assertTrue(
1875 packet_index not in dropped_packet_indexes,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001876 ppp("Packet received, but should be dropped:", packet),
1877 )
Klement Sekera630ab582019-07-19 09:14:19 +00001878 if packet_index in seen:
1879 raise Exception(ppp("Duplicate packet received", packet))
1880 seen.add(packet_index)
1881 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
1882 info = self._packet_infos[packet_index]
1883 self.assertTrue(info is not None)
1884 self.assertEqual(packet_index, info.index)
1885 saved_packet = info.data
1886 self.assertEqual(ip.src, saved_packet[IPv6].src)
1887 self.assertEqual(ip.dst, saved_packet[IPv6].dst)
1888 self.assertEqual(udp.payload, saved_packet[UDP].payload)
1889 except Exception:
1890 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1891 raise
1892 for index in self._packet_infos:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001893 self.assertTrue(
1894 index in seen or index in dropped_packet_indexes,
1895 "Packet with packet_index %d not received" % index,
1896 )
Klement Sekera630ab582019-07-19 09:14:19 +00001897
1898 def send_packets(self, packets):
Klement Sekera8d815022021-03-15 16:58:10 +01001899 for counter in range(self.vpp_worker_count):
Klement Sekera630ab582019-07-19 09:14:19 +00001900 if 0 == len(packets[counter]):
1901 continue
1902 send_if = self.send_ifs[counter]
1903 send_if.add_stream(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001904 (
1905 Ether(dst=send_if.local_mac, src=send_if.remote_mac) / x
1906 for x in packets[counter]
1907 ),
1908 worker=counter,
1909 )
Klement Sekera630ab582019-07-19 09:14:19 +00001910 self.pg_start()
1911
1912 def test_worker_conflict(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001913 """1st and FO=0 fragments on different workers"""
Klement Sekera630ab582019-07-19 09:14:19 +00001914
1915 # in first wave we send fragments which don't start at offset 0
1916 # then we send fragments with offset 0 on a different thread
1917 # then the rest of packets on a random thread
Klement Sekera8d815022021-03-15 16:58:10 +01001918 first_packets = [[] for n in range(self.vpp_worker_count)]
1919 second_packets = [[] for n in range(self.vpp_worker_count)]
1920 rest_of_packets = [[] for n in range(self.vpp_worker_count)]
Dave Wallace7b8b4652023-08-15 19:05:26 -04001921 for _, p in self.pkt_infos:
Klement Sekera8d815022021-03-15 16:58:10 +01001922 wi = randrange(self.vpp_worker_count)
Klement Sekera630ab582019-07-19 09:14:19 +00001923 second_packets[wi].append(p[0])
1924 if len(p) <= 1:
1925 continue
1926 wi2 = wi
1927 while wi2 == wi:
Klement Sekera8d815022021-03-15 16:58:10 +01001928 wi2 = randrange(self.vpp_worker_count)
Klement Sekera630ab582019-07-19 09:14:19 +00001929 first_packets[wi2].append(p[1])
Klement Sekera8d815022021-03-15 16:58:10 +01001930 wi3 = randrange(self.vpp_worker_count)
Klement Sekera630ab582019-07-19 09:14:19 +00001931 rest_of_packets[wi3].extend(p[2:])
1932
1933 self.pg_enable_capture()
1934 self.send_packets(first_packets)
1935 self.send_packets(second_packets)
1936 self.send_packets(rest_of_packets)
1937
1938 packets = self.dst_if.get_capture(len(self.pkt_infos))
1939 self.verify_capture(packets)
1940 for send_if in self.send_ifs:
1941 send_if.assert_nothing_captured()
1942
Klement Sekera68bae5b2019-10-10 18:57:34 +00001943 self.logger.debug(self.vapi.ppcli("show trace"))
1944 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
1945 self.logger.debug(self.vapi.ppcli("show buffers"))
1946 self.vapi.cli("clear trace")
1947
Klement Sekera630ab582019-07-19 09:14:19 +00001948 self.pg_enable_capture()
1949 self.send_packets(first_packets)
1950 self.send_packets(second_packets)
1951 self.send_packets(rest_of_packets)
1952
1953 packets = self.dst_if.get_capture(len(self.pkt_infos))
1954 self.verify_capture(packets)
1955 for send_if in self.send_ifs:
1956 send_if.assert_nothing_captured()
1957
1958
Klement Sekerade34c352019-06-25 11:19:22 +00001959class TestIPv6SVReassembly(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001960 """IPv6 Shallow Virtual Reassembly"""
Klement Sekerade34c352019-06-25 11:19:22 +00001961
1962 @classmethod
1963 def setUpClass(cls):
Klement Sekera01c1fa42021-12-14 18:25:11 +00001964 super().setUpClass()
Klement Sekerade34c352019-06-25 11:19:22 +00001965
1966 cls.create_pg_interfaces([0, 1])
1967 cls.src_if = cls.pg0
1968 cls.dst_if = cls.pg1
1969
1970 # setup all interfaces
1971 for i in cls.pg_interfaces:
1972 i.admin_up()
1973 i.config_ip6()
1974 i.resolve_ndp()
1975
1976 def setUp(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001977 """Test setup - force timeout on existing reassemblies"""
Klement Sekera01c1fa42021-12-14 18:25:11 +00001978 super().setUp()
Klement Sekerade34c352019-06-25 11:19:22 +00001979 self.vapi.ip_reassembly_enable_disable(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001980 sw_if_index=self.src_if.sw_if_index,
1981 enable_ip6=True,
1982 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
1983 )
Klement Sekerade34c352019-06-25 11:19:22 +00001984 self.vapi.ip_reassembly_set(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001985 timeout_ms=0,
1986 max_reassemblies=1000,
Klement Sekerade34c352019-06-25 11:19:22 +00001987 max_reassembly_length=1000,
1988 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001989 expire_walk_interval_ms=10,
1990 is_ip6=1,
1991 )
1992 self.virtual_sleep(0.25)
Klement Sekerade34c352019-06-25 11:19:22 +00001993 self.vapi.ip_reassembly_set(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001994 timeout_ms=1000000,
1995 max_reassemblies=1000,
Klement Sekerade34c352019-06-25 11:19:22 +00001996 max_reassembly_length=1000,
1997 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001998 expire_walk_interval_ms=10000,
1999 is_ip6=1,
2000 )
Klement Sekerade34c352019-06-25 11:19:22 +00002001
2002 def tearDown(self):
Klement Sekera01c1fa42021-12-14 18:25:11 +00002003 super().tearDown()
Klement Sekerade34c352019-06-25 11:19:22 +00002004 self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details"))
2005 self.logger.debug(self.vapi.ppcli("show buffers"))
2006
2007 def test_basic(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002008 """basic reassembly"""
Klement Sekerade34c352019-06-25 11:19:22 +00002009 payload_len = 1000
2010 payload = ""
2011 counter = 0
2012 while len(payload) < payload_len:
2013 payload += "%u " % counter
2014 counter += 1
2015
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002016 p = (
2017 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
2018 / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6)
2019 / UDP(sport=1234, dport=5678)
2020 / Raw(payload)
2021 )
2022 fragments = fragment_rfc8200(p, 1, payload_len / 4)
Klement Sekerade34c352019-06-25 11:19:22 +00002023
2024 # send fragment #2 - should be cached inside reassembly
2025 self.pg_enable_capture()
2026 self.src_if.add_stream(fragments[1])
2027 self.pg_start()
2028 self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details"))
2029 self.logger.debug(self.vapi.ppcli("show buffers"))
2030 self.logger.debug(self.vapi.ppcli("show trace"))
2031 self.dst_if.assert_nothing_captured()
2032
2033 # send fragment #1 - reassembly is finished now and both fragments
2034 # forwarded
2035 self.pg_enable_capture()
2036 self.src_if.add_stream(fragments[0])
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 c = self.dst_if.get_capture(2)
2042 for sent, recvd in zip([fragments[1], fragments[0]], c):
2043 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
2044 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
2045 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
2046
2047 # send rest of fragments - should be immediately forwarded
2048 self.pg_enable_capture()
2049 self.src_if.add_stream(fragments[2:])
2050 self.pg_start()
2051 c = self.dst_if.get_capture(len(fragments[2:]))
2052 for sent, recvd in zip(fragments[2:], 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
Klement Sekera53be16d2020-12-15 21:47:36 +01002057 def test_verify_clear_trace_mid_reassembly(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002058 """verify clear trace works mid-reassembly"""
Klement Sekera53be16d2020-12-15 21:47:36 +01002059 payload_len = 1000
2060 payload = ""
2061 counter = 0
2062 while len(payload) < payload_len:
2063 payload += "%u " % counter
2064 counter += 1
2065
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002066 p = (
2067 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
2068 / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6)
2069 / UDP(sport=1234, dport=5678)
2070 / Raw(payload)
2071 )
2072 fragments = fragment_rfc8200(p, 1, payload_len / 4)
Klement Sekera53be16d2020-12-15 21:47:36 +01002073
2074 self.pg_enable_capture()
2075 self.src_if.add_stream(fragments[1])
2076 self.pg_start()
2077
2078 self.logger.debug(self.vapi.cli("show trace"))
2079 self.vapi.cli("clear trace")
2080
2081 self.pg_enable_capture()
2082 self.src_if.add_stream(fragments[0])
2083 self.pg_start()
2084 self.dst_if.get_capture(2)
2085
2086 self.logger.debug(self.vapi.cli("show trace"))
2087 self.vapi.cli("clear trace")
2088
2089 self.pg_enable_capture()
2090 self.src_if.add_stream(fragments[2:])
2091 self.pg_start()
2092 self.dst_if.get_capture(len(fragments[2:]))
2093
Klement Sekerade34c352019-06-25 11:19:22 +00002094 def test_timeout(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002095 """reassembly timeout"""
Klement Sekerade34c352019-06-25 11:19:22 +00002096 payload_len = 1000
2097 payload = ""
2098 counter = 0
2099 while len(payload) < payload_len:
2100 payload += "%u " % counter
2101 counter += 1
2102
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002103 p = (
2104 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
2105 / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6)
2106 / UDP(sport=1234, dport=5678)
2107 / Raw(payload)
2108 )
2109 fragments = fragment_rfc8200(p, 1, payload_len / 4)
Klement Sekerade34c352019-06-25 11:19:22 +00002110
2111 self.vapi.ip_reassembly_set(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002112 timeout_ms=100,
2113 max_reassemblies=1000,
Klement Sekerade34c352019-06-25 11:19:22 +00002114 max_reassembly_length=1000,
2115 expire_walk_interval_ms=50,
2116 is_ip6=1,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002117 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
2118 )
Klement Sekerade34c352019-06-25 11:19:22 +00002119
2120 # send fragments #2 and #1 - should be forwarded
2121 self.pg_enable_capture()
2122 self.src_if.add_stream(fragments[0:2])
2123 self.pg_start()
2124 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
2125 self.logger.debug(self.vapi.ppcli("show buffers"))
2126 self.logger.debug(self.vapi.ppcli("show trace"))
2127 c = self.dst_if.get_capture(2)
2128 for sent, recvd in zip([fragments[1], fragments[0]], c):
2129 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
2130 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
2131 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
2132
2133 # wait for cleanup
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002134 self.virtual_sleep(0.25, "wait before sending rest of fragments")
Klement Sekerade34c352019-06-25 11:19:22 +00002135
2136 # send rest of fragments - shouldn't be forwarded
2137 self.pg_enable_capture()
2138 self.src_if.add_stream(fragments[2:])
2139 self.pg_start()
2140 self.dst_if.assert_nothing_captured()
2141
2142 def test_lru(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002143 """reassembly reuses LRU element"""
Klement Sekerade34c352019-06-25 11:19:22 +00002144
2145 self.vapi.ip_reassembly_set(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002146 timeout_ms=1000000,
2147 max_reassemblies=1,
Klement Sekerade34c352019-06-25 11:19:22 +00002148 max_reassembly_length=1000,
2149 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002150 is_ip6=1,
2151 expire_walk_interval_ms=10000,
2152 )
Klement Sekerade34c352019-06-25 11:19:22 +00002153
2154 payload_len = 1000
2155 payload = ""
2156 counter = 0
2157 while len(payload) < payload_len:
2158 payload += "%u " % counter
2159 counter += 1
2160
2161 packet_count = 10
2162
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002163 fragments = [
2164 f
2165 for i in range(packet_count)
2166 for p in (
2167 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
2168 / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6)
2169 / UDP(sport=1234, dport=5678)
2170 / Raw(payload)
2171 )
2172 for f in fragment_rfc8200(p, i, payload_len / 4)
2173 ]
Klement Sekerade34c352019-06-25 11:19:22 +00002174
2175 self.pg_enable_capture()
2176 self.src_if.add_stream(fragments)
2177 self.pg_start()
2178 c = self.dst_if.get_capture(len(fragments))
2179 for sent, recvd in zip(fragments, c):
2180 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
2181 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
2182 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
2183
Klement Sekera7c3275e2021-12-07 09:49:53 +00002184 def test_one_fragment(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002185 """whole packet in one fragment processed independently"""
2186 pkt = (
Steven Luonge4238aa2024-04-19 09:49:20 -07002187 Ether(src=self.src_if.remote_mac, dst=self.src_if.local_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002188 / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6)
2189 / ICMPv6EchoRequest()
2190 / Raw("X" * 1600)
2191 )
Klement Sekera7c3275e2021-12-07 09:49:53 +00002192 frags = fragment_rfc8200(pkt, 1, 400)
2193
2194 # send a fragment with known id
2195 self.send_and_expect(self.src_if, [frags[0]], self.dst_if)
2196
2197 # send an atomic fragment with same id - should be reassembled
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002198 pkt = (
Steven Luonge4238aa2024-04-19 09:49:20 -07002199 Ether(src=self.src_if.remote_mac, dst=self.src_if.local_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002200 / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6)
2201 / IPv6ExtHdrFragment(id=1)
2202 / ICMPv6EchoRequest()
2203 )
Klement Sekera7c3275e2021-12-07 09:49:53 +00002204 rx = self.send_and_expect(self.src_if, [pkt], self.dst_if)
2205
2206 # now forward packets matching original reassembly, should still work
2207 rx = self.send_and_expect(self.src_if, frags[1:], self.dst_if)
2208
2209 def test_bunch_of_fragments(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002210 """valid fragments followed by rogue fragments and atomic fragment"""
2211 pkt = (
Steven Luonge4238aa2024-04-19 09:49:20 -07002212 Ether(src=self.src_if.remote_mac, dst=self.src_if.local_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002213 / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6)
2214 / ICMPv6EchoRequest()
2215 / Raw("X" * 1600)
2216 )
Klement Sekera7c3275e2021-12-07 09:49:53 +00002217 frags = fragment_rfc8200(pkt, 1, 400)
2218 rx = self.send_and_expect(self.src_if, frags, self.dst_if)
2219
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002220 rogue = (
Steven Luonge4238aa2024-04-19 09:49:20 -07002221 Ether(src=self.src_if.remote_mac, dst=self.src_if.local_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002222 / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6)
2223 / IPv6ExtHdrFragment(id=1, nh=58, offset=608)
2224 / Raw("X" * 308)
2225 )
Klement Sekera7c3275e2021-12-07 09:49:53 +00002226
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002227 self.send_and_expect(self.src_if, rogue * 604, self.dst_if)
Klement Sekera7c3275e2021-12-07 09:49:53 +00002228
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002229 pkt = (
Steven Luonge4238aa2024-04-19 09:49:20 -07002230 Ether(src=self.src_if.remote_mac, dst=self.src_if.local_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002231 / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6)
2232 / IPv6ExtHdrFragment(id=1)
2233 / ICMPv6EchoRequest()
2234 )
Klement Sekera7c3275e2021-12-07 09:49:53 +00002235 rx = self.send_and_expect(self.src_if, [pkt], self.dst_if)
2236
Klement Sekera755042d2021-12-01 10:14:38 +00002237 def test_truncated_fragment(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002238 """truncated fragment"""
2239 pkt = (
2240 Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac)
2241 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6, nh=44, plen=2)
2242 / IPv6ExtHdrFragment(nh=6)
2243 )
Klement Sekera755042d2021-12-01 10:14:38 +00002244
2245 self.send_and_assert_no_replies(self.pg0, [pkt], self.pg0)
2246
Klement Sekerade34c352019-06-25 11:19:22 +00002247
Juraj Sloboda3048b632018-10-02 11:13:53 +02002248class TestIPv4ReassemblyLocalNode(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002249 """IPv4 Reassembly for packets coming to ip4-local node"""
Juraj Sloboda3048b632018-10-02 11:13:53 +02002250
2251 @classmethod
2252 def setUpClass(cls):
Klement Sekera01c1fa42021-12-14 18:25:11 +00002253 super().setUpClass()
Juraj Sloboda3048b632018-10-02 11:13:53 +02002254
2255 cls.create_pg_interfaces([0])
2256 cls.src_dst_if = cls.pg0
2257
2258 # setup all interfaces
2259 for i in cls.pg_interfaces:
2260 i.admin_up()
2261 i.config_ip4()
2262 i.resolve_arp()
2263
2264 cls.padding = " abcdefghijklmn"
2265 cls.create_stream()
2266 cls.create_fragments()
2267
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07002268 @classmethod
2269 def tearDownClass(cls):
Klement Sekera01c1fa42021-12-14 18:25:11 +00002270 super().tearDownClass()
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07002271
Juraj Sloboda3048b632018-10-02 11:13:53 +02002272 def setUp(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002273 """Test setup - force timeout on existing reassemblies"""
Klement Sekera01c1fa42021-12-14 18:25:11 +00002274 super().setUp()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002275 self.vapi.ip_reassembly_set(
2276 timeout_ms=0,
2277 max_reassemblies=1000,
2278 max_reassembly_length=1000,
2279 expire_walk_interval_ms=10,
2280 )
2281 self.virtual_sleep(0.25)
2282 self.vapi.ip_reassembly_set(
2283 timeout_ms=1000000,
2284 max_reassemblies=1000,
2285 max_reassembly_length=1000,
2286 expire_walk_interval_ms=10000,
2287 )
Juraj Sloboda3048b632018-10-02 11:13:53 +02002288
2289 def tearDown(self):
Klement Sekera01c1fa42021-12-14 18:25:11 +00002290 super().tearDown()
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -07002291
2292 def show_commands_at_teardown(self):
Klement Sekera896c8962019-06-24 11:52:49 +00002293 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
Klement Sekeracae98b72019-02-19 13:53:43 +01002294 self.logger.debug(self.vapi.ppcli("show buffers"))
Juraj Sloboda3048b632018-10-02 11:13:53 +02002295
2296 @classmethod
2297 def create_stream(cls, packet_count=test_packet_count):
2298 """Create input packet stream for defined interface.
2299
2300 :param list packet_sizes: Required packet sizes.
2301 """
2302 for i in range(0, packet_count):
2303 info = cls.create_packet_info(cls.src_dst_if, cls.src_dst_if)
2304 payload = cls.info_to_payload(info)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002305 p = (
2306 Ether(dst=cls.src_dst_if.local_mac, src=cls.src_dst_if.remote_mac)
2307 / IP(
2308 id=info.index,
2309 src=cls.src_dst_if.remote_ip4,
2310 dst=cls.src_dst_if.local_ip4,
2311 )
2312 / ICMP(type="echo-request", id=1234)
2313 / Raw(payload)
2314 )
Juraj Sloboda3048b632018-10-02 11:13:53 +02002315 cls.extend_packet(p, 1518, cls.padding)
2316 info.data = p
2317
2318 @classmethod
2319 def create_fragments(cls):
2320 infos = cls._packet_infos
2321 cls.pkt_infos = []
Paul Vinciguerra090096b2020-12-03 00:42:46 -05002322 for index, info in infos.items():
Juraj Sloboda3048b632018-10-02 11:13:53 +02002323 p = info.data
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07002324 # cls.logger.debug(ppp("Packet:",
2325 # p.__class__(scapy.compat.raw(p))))
Juraj Sloboda3048b632018-10-02 11:13:53 +02002326 fragments_300 = fragment_rfc791(p, 300)
2327 cls.pkt_infos.append((index, fragments_300))
2328 cls.fragments_300 = [x for (_, frags) in cls.pkt_infos for x in frags]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002329 cls.logger.debug(
2330 "Fragmented %s packets into %s 300-byte fragments"
2331 % (len(infos), len(cls.fragments_300))
2332 )
Juraj Sloboda3048b632018-10-02 11:13:53 +02002333
2334 def verify_capture(self, capture):
2335 """Verify captured packet stream.
2336
2337 :param list capture: Captured packet stream.
2338 """
2339 info = None
2340 seen = set()
2341 for packet in capture:
2342 try:
2343 self.logger.debug(ppp("Got packet:", packet))
2344 ip = packet[IP]
2345 icmp = packet[ICMP]
Paul Vinciguerraeaea4212019-03-06 11:58:06 -08002346 payload_info = self.payload_to_info(packet[Raw])
Juraj Sloboda3048b632018-10-02 11:13:53 +02002347 packet_index = payload_info.index
2348 if packet_index in seen:
2349 raise Exception(ppp("Duplicate packet received", packet))
2350 seen.add(packet_index)
2351 self.assertEqual(payload_info.dst, self.src_dst_if.sw_if_index)
2352 info = self._packet_infos[packet_index]
Klement Sekera14d7e902018-12-10 13:46:09 +01002353 self.assertIsNotNone(info)
Juraj Sloboda3048b632018-10-02 11:13:53 +02002354 self.assertEqual(packet_index, info.index)
2355 saved_packet = info.data
2356 self.assertEqual(ip.src, saved_packet[IP].dst)
2357 self.assertEqual(ip.dst, saved_packet[IP].src)
2358 self.assertEqual(icmp.type, 0) # echo reply
2359 self.assertEqual(icmp.id, saved_packet[ICMP].id)
2360 self.assertEqual(icmp.payload, saved_packet[ICMP].payload)
2361 except Exception:
2362 self.logger.error(ppp("Unexpected or invalid packet:", packet))
2363 raise
2364 for index in self._packet_infos:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002365 self.assertIn(
2366 index, seen, "Packet with packet_index %d not received" % index
2367 )
Juraj Sloboda3048b632018-10-02 11:13:53 +02002368
2369 def test_reassembly(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002370 """basic reassembly"""
Juraj Sloboda3048b632018-10-02 11:13:53 +02002371
2372 self.pg_enable_capture()
2373 self.src_dst_if.add_stream(self.fragments_300)
2374 self.pg_start()
2375
2376 packets = self.src_dst_if.get_capture(len(self.pkt_infos))
2377 self.verify_capture(packets)
2378
2379 # run it all again to verify correctness
2380 self.pg_enable_capture()
2381 self.src_dst_if.add_stream(self.fragments_300)
2382 self.pg_start()
2383
2384 packets = self.src_dst_if.get_capture(len(self.pkt_infos))
2385 self.verify_capture(packets)
2386
2387
Klement Sekera75e7d132017-09-20 08:26:30 +02002388class TestFIFReassembly(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002389 """Fragments in fragments reassembly"""
Klement Sekera75e7d132017-09-20 08:26:30 +02002390
2391 @classmethod
2392 def setUpClass(cls):
Klement Sekera01c1fa42021-12-14 18:25:11 +00002393 super().setUpClass()
Klement Sekera75e7d132017-09-20 08:26:30 +02002394
Klement Sekera4c533132018-02-22 11:41:12 +01002395 cls.create_pg_interfaces([0, 1])
2396 cls.src_if = cls.pg0
2397 cls.dst_if = cls.pg1
2398 for i in cls.pg_interfaces:
2399 i.admin_up()
2400 i.config_ip4()
2401 i.resolve_arp()
2402 i.config_ip6()
2403 i.resolve_ndp()
Klement Sekera75e7d132017-09-20 08:26:30 +02002404
Klement Sekera75e7d132017-09-20 08:26:30 +02002405 cls.packet_sizes = [64, 512, 1518, 9018]
2406 cls.padding = " abcdefghijklmn"
2407
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07002408 @classmethod
2409 def tearDownClass(cls):
Klement Sekera01c1fa42021-12-14 18:25:11 +00002410 super().tearDownClass()
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07002411
Klement Sekera75e7d132017-09-20 08:26:30 +02002412 def setUp(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002413 """Test setup - force timeout on existing reassemblies"""
Klement Sekera01c1fa42021-12-14 18:25:11 +00002414 super().setUp()
Klement Sekera4c533132018-02-22 11:41:12 +01002415 self.vapi.ip_reassembly_enable_disable(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002416 sw_if_index=self.src_if.sw_if_index, enable_ip4=True, enable_ip6=True
2417 )
Klement Sekera4c533132018-02-22 11:41:12 +01002418 self.vapi.ip_reassembly_enable_disable(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002419 sw_if_index=self.dst_if.sw_if_index, enable_ip4=True, enable_ip6=True
2420 )
2421 self.vapi.ip_reassembly_set(
2422 timeout_ms=0,
2423 max_reassemblies=1000,
2424 max_reassembly_length=1000,
2425 expire_walk_interval_ms=10,
2426 )
2427 self.vapi.ip_reassembly_set(
2428 timeout_ms=0,
2429 max_reassemblies=1000,
2430 max_reassembly_length=1000,
2431 expire_walk_interval_ms=10,
2432 is_ip6=1,
2433 )
2434 self.virtual_sleep(0.25)
2435 self.vapi.ip_reassembly_set(
2436 timeout_ms=1000000,
2437 max_reassemblies=1000,
2438 max_reassembly_length=1000,
2439 expire_walk_interval_ms=10000,
2440 )
2441 self.vapi.ip_reassembly_set(
2442 timeout_ms=1000000,
2443 max_reassemblies=1000,
2444 max_reassembly_length=1000,
2445 expire_walk_interval_ms=10000,
2446 is_ip6=1,
2447 )
Klement Sekera75e7d132017-09-20 08:26:30 +02002448
2449 def tearDown(self):
Klement Sekera01c1fa42021-12-14 18:25:11 +00002450 super().tearDown()
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -07002451
2452 def show_commands_at_teardown(self):
Klement Sekera896c8962019-06-24 11:52:49 +00002453 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
2454 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
Klement Sekeracae98b72019-02-19 13:53:43 +01002455 self.logger.debug(self.vapi.ppcli("show buffers"))
Klement Sekera75e7d132017-09-20 08:26:30 +02002456
2457 def verify_capture(self, capture, ip_class, dropped_packet_indexes=[]):
2458 """Verify captured packet stream.
2459
2460 :param list capture: Captured packet stream.
2461 """
2462 info = None
2463 seen = set()
2464 for packet in capture:
2465 try:
Klement Sekera4c533132018-02-22 11:41:12 +01002466 self.logger.debug(ppp("Got packet:", packet))
Klement Sekera75e7d132017-09-20 08:26:30 +02002467 ip = packet[ip_class]
2468 udp = packet[UDP]
Paul Vinciguerraeaea4212019-03-06 11:58:06 -08002469 payload_info = self.payload_to_info(packet[Raw])
Klement Sekera75e7d132017-09-20 08:26:30 +02002470 packet_index = payload_info.index
2471 self.assertTrue(
2472 packet_index not in dropped_packet_indexes,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002473 ppp("Packet received, but should be dropped:", packet),
2474 )
Klement Sekera75e7d132017-09-20 08:26:30 +02002475 if packet_index in seen:
2476 raise Exception(ppp("Duplicate packet received", packet))
2477 seen.add(packet_index)
Klement Sekera4c533132018-02-22 11:41:12 +01002478 self.assertEqual(payload_info.dst, self.dst_if.sw_if_index)
Klement Sekera75e7d132017-09-20 08:26:30 +02002479 info = self._packet_infos[packet_index]
2480 self.assertTrue(info is not None)
2481 self.assertEqual(packet_index, info.index)
2482 saved_packet = info.data
2483 self.assertEqual(ip.src, saved_packet[ip_class].src)
2484 self.assertEqual(ip.dst, saved_packet[ip_class].dst)
2485 self.assertEqual(udp.payload, saved_packet[UDP].payload)
Klement Sekera4c533132018-02-22 11:41:12 +01002486 except Exception:
Klement Sekera75e7d132017-09-20 08:26:30 +02002487 self.logger.error(ppp("Unexpected or invalid packet:", packet))
2488 raise
2489 for index in self._packet_infos:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002490 self.assertTrue(
2491 index in seen or index in dropped_packet_indexes,
2492 "Packet with packet_index %d not received" % index,
2493 )
Klement Sekera75e7d132017-09-20 08:26:30 +02002494
2495 def test_fif4(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002496 """Fragments in fragments (4o4)"""
Klement Sekera75e7d132017-09-20 08:26:30 +02002497
2498 # TODO this should be ideally in setUpClass, but then we hit a bug
2499 # with VppIpRoute incorrectly reporting it's present when it's not
2500 # so we need to manually remove the vpp config, thus we cannot have
2501 # it shared for multiple test cases
2502 self.tun_ip4 = "1.1.1.2"
2503
Klement Sekera4c533132018-02-22 11:41:12 +01002504 self.gre4 = VppGreInterface(self, self.src_if.local_ip4, self.tun_ip4)
Klement Sekera75e7d132017-09-20 08:26:30 +02002505 self.gre4.add_vpp_config()
2506 self.gre4.admin_up()
2507 self.gre4.config_ip4()
2508
Klement Sekera4c533132018-02-22 11:41:12 +01002509 self.vapi.ip_reassembly_enable_disable(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002510 sw_if_index=self.gre4.sw_if_index, enable_ip4=True
2511 )
Klement Sekera4c533132018-02-22 11:41:12 +01002512
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002513 self.route4 = VppIpRoute(
2514 self,
2515 self.tun_ip4,
2516 32,
2517 [VppRoutePath(self.src_if.remote_ip4, self.src_if.sw_if_index)],
2518 )
Klement Sekera75e7d132017-09-20 08:26:30 +02002519 self.route4.add_vpp_config()
2520
2521 self.reset_packet_infos()
2522 for i in range(test_packet_count):
Klement Sekera4c533132018-02-22 11:41:12 +01002523 info = self.create_packet_info(self.src_if, self.dst_if)
Klement Sekera75e7d132017-09-20 08:26:30 +02002524 payload = self.info_to_payload(info)
Klement Sekera4c533132018-02-22 11:41:12 +01002525 # Ethernet header here is only for size calculation, thus it
2526 # doesn't matter how it's initialized. This is to ensure that
2527 # reassembled packet is not > 9000 bytes, so that it's not dropped
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002528 p = (
2529 Ether()
2530 / IP(id=i, src=self.src_if.remote_ip4, dst=self.dst_if.remote_ip4)
2531 / UDP(sport=1234, dport=5678)
2532 / Raw(payload)
2533 )
Klement Sekera75e7d132017-09-20 08:26:30 +02002534 size = self.packet_sizes[(i // 2) % len(self.packet_sizes)]
2535 self.extend_packet(p, size, self.padding)
Klement Sekera4c533132018-02-22 11:41:12 +01002536 info.data = p[IP] # use only IP part, without ethernet header
Klement Sekera75e7d132017-09-20 08:26:30 +02002537
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002538 fragments = [
2539 x
2540 for _, p in self._packet_infos.items()
2541 for x in fragment_rfc791(p.data, 400)
2542 ]
Klement Sekera75e7d132017-09-20 08:26:30 +02002543
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002544 encapped_fragments = [
2545 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
2546 / IP(src=self.tun_ip4, dst=self.src_if.local_ip4)
2547 / GRE()
2548 / p
2549 for p in fragments
2550 ]
Klement Sekera75e7d132017-09-20 08:26:30 +02002551
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002552 fragmented_encapped_fragments = [
2553 x for p in encapped_fragments for x in fragment_rfc791(p, 200)
2554 ]
Klement Sekera75e7d132017-09-20 08:26:30 +02002555
Klement Sekera4c533132018-02-22 11:41:12 +01002556 self.src_if.add_stream(fragmented_encapped_fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +02002557
2558 self.pg_enable_capture(self.pg_interfaces)
2559 self.pg_start()
2560
Klement Sekera4c533132018-02-22 11:41:12 +01002561 self.src_if.assert_nothing_captured()
2562 packets = self.dst_if.get_capture(len(self._packet_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +02002563 self.verify_capture(packets, IP)
2564
2565 # TODO remove gre vpp config by hand until VppIpRoute gets fixed
2566 # so that it's query_vpp_config() works as it should
2567 self.gre4.remove_vpp_config()
Klement Sekera4c533132018-02-22 11:41:12 +01002568 self.logger.debug(self.vapi.ppcli("show interface"))
Klement Sekera75e7d132017-09-20 08:26:30 +02002569
2570 def test_fif6(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002571 """Fragments in fragments (6o6)"""
Klement Sekera75e7d132017-09-20 08:26:30 +02002572 # TODO this should be ideally in setUpClass, but then we hit a bug
2573 # with VppIpRoute incorrectly reporting it's present when it's not
2574 # so we need to manually remove the vpp config, thus we cannot have
2575 # it shared for multiple test cases
2576 self.tun_ip6 = "1002::1"
2577
Neale Ranns5a8844b2019-04-16 07:15:35 +00002578 self.gre6 = VppGreInterface(self, self.src_if.local_ip6, self.tun_ip6)
Klement Sekera75e7d132017-09-20 08:26:30 +02002579 self.gre6.add_vpp_config()
2580 self.gre6.admin_up()
2581 self.gre6.config_ip6()
2582
Klement Sekera4c533132018-02-22 11:41:12 +01002583 self.vapi.ip_reassembly_enable_disable(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002584 sw_if_index=self.gre6.sw_if_index, enable_ip6=True
2585 )
Klement Sekera4c533132018-02-22 11:41:12 +01002586
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002587 self.route6 = VppIpRoute(
2588 self,
2589 self.tun_ip6,
2590 128,
2591 [VppRoutePath(self.src_if.remote_ip6, self.src_if.sw_if_index)],
2592 )
Klement Sekera75e7d132017-09-20 08:26:30 +02002593 self.route6.add_vpp_config()
2594
2595 self.reset_packet_infos()
2596 for i in range(test_packet_count):
Klement Sekera4c533132018-02-22 11:41:12 +01002597 info = self.create_packet_info(self.src_if, self.dst_if)
Klement Sekera75e7d132017-09-20 08:26:30 +02002598 payload = self.info_to_payload(info)
Klement Sekera4c533132018-02-22 11:41:12 +01002599 # Ethernet header here is only for size calculation, thus it
2600 # doesn't matter how it's initialized. This is to ensure that
2601 # reassembled packet is not > 9000 bytes, so that it's not dropped
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002602 p = (
2603 Ether()
2604 / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6)
2605 / UDP(sport=1234, dport=5678)
2606 / Raw(payload)
2607 )
Klement Sekera75e7d132017-09-20 08:26:30 +02002608 size = self.packet_sizes[(i // 2) % len(self.packet_sizes)]
2609 self.extend_packet(p, size, self.padding)
Klement Sekera4c533132018-02-22 11:41:12 +01002610 info.data = p[IPv6] # use only IPv6 part, without ethernet header
Klement Sekera75e7d132017-09-20 08:26:30 +02002611
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002612 fragments = [
2613 x
2614 for _, i in self._packet_infos.items()
2615 for x in fragment_rfc8200(i.data, i.index, 400)
2616 ]
Klement Sekera75e7d132017-09-20 08:26:30 +02002617
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002618 encapped_fragments = [
2619 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
2620 / IPv6(src=self.tun_ip6, dst=self.src_if.local_ip6)
2621 / GRE()
2622 / p
2623 for p in fragments
2624 ]
Klement Sekera75e7d132017-09-20 08:26:30 +02002625
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002626 fragmented_encapped_fragments = [
2627 x
2628 for p in encapped_fragments
2629 for x in (
Klement Sekera75e7d132017-09-20 08:26:30 +02002630 fragment_rfc8200(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002631 p, 2 * len(self._packet_infos) + p[IPv6ExtHdrFragment].id, 200
2632 )
2633 if IPv6ExtHdrFragment in p
2634 else [p]
Klement Sekera75e7d132017-09-20 08:26:30 +02002635 )
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002636 ]
Klement Sekera75e7d132017-09-20 08:26:30 +02002637
Klement Sekera4c533132018-02-22 11:41:12 +01002638 self.src_if.add_stream(fragmented_encapped_fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +02002639
2640 self.pg_enable_capture(self.pg_interfaces)
2641 self.pg_start()
2642
Klement Sekera4c533132018-02-22 11:41:12 +01002643 self.src_if.assert_nothing_captured()
2644 packets = self.dst_if.get_capture(len(self._packet_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +02002645 self.verify_capture(packets, IPv6)
2646
2647 # TODO remove gre vpp config by hand until VppIpRoute gets fixed
2648 # so that it's query_vpp_config() works as it should
Klement Sekera3ecc2212018-03-27 10:34:43 +02002649 self.gre6.remove_vpp_config()
Klement Sekera75e7d132017-09-20 08:26:30 +02002650
2651
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002652if __name__ == "__main__":
Klement Sekera75e7d132017-09-20 08:26:30 +02002653 unittest.main(testRunner=VppTestRunner)