blob: faec5f42c308f51ad5eb07eb8b93464f05e418f9 [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
Klement Sekera630ab582019-07-19 09:14:19 +00004from random import shuffle, choice, randrange
Klement Sekera75e7d132017-09-20 08:26:30 +02005
Klement Sekera947a85c2019-07-24 12:40:37 +00006from framework import VppTestCase, VppTestRunner
7
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07008import scapy.compat
Klement Sekera75e7d132017-09-20 08:26:30 +02009from scapy.packet import Raw
10from scapy.layers.l2 import Ether, GRE
Juraj Sloboda3048b632018-10-02 11:13:53 +020011from scapy.layers.inet import IP, UDP, ICMP
Klement Sekera769145c2019-03-06 11:59:57 +010012from scapy.layers.inet6 import HBHOptUnknown, ICMPv6ParamProblem,\
Ole Troan03092c12021-11-23 15:55:39 +010013 ICMPv6TimeExceeded, IPv6, IPv6ExtHdrFragment,\
14 IPv6ExtHdrHopByHop, IPv6ExtHdrDestOpt, PadN, ICMPv6EchoRequest
Paul Vinciguerra69555952019-03-01 08:46:29 -080015from framework import VppTestCase, VppTestRunner
Klement Sekera630ab582019-07-19 09:14:19 +000016from util import ppp, ppc, fragment_rfc791, fragment_rfc8200
Neale Ranns5a8844b2019-04-16 07:15:35 +000017from vpp_gre_interface import VppGreInterface
Neale Rannsc0a93142018-09-05 15:42:26 -070018from vpp_ip import DpoProto
Neale Ranns097fa662018-05-01 05:17:55 -070019from vpp_ip_route import VppIpRoute, VppRoutePath, FibPathProto
Klement Sekera896c8962019-06-24 11:52:49 +000020from vpp_papi import VppEnum
Klement Sekera75e7d132017-09-20 08:26:30 +020021
Klement Sekerad0f70a32018-12-14 17:24:13 +010022# 35 is enough to have >257 400-byte fragments
23test_packet_count = 35
Klement Sekera75e7d132017-09-20 08:26:30 +020024
25
Klement Sekera947a85c2019-07-24 12:40:37 +000026class TestIPv4Reassembly(VppTestCase):
Klement Sekera75e7d132017-09-20 08:26:30 +020027 """ IPv4 Reassembly """
28
29 @classmethod
30 def setUpClass(cls):
31 super(TestIPv4Reassembly, cls).setUpClass()
32
Klement Sekera4c533132018-02-22 11:41:12 +010033 cls.create_pg_interfaces([0, 1])
34 cls.src_if = cls.pg0
35 cls.dst_if = cls.pg1
Klement Sekera75e7d132017-09-20 08:26:30 +020036
37 # setup all interfaces
38 for i in cls.pg_interfaces:
39 i.admin_up()
40 i.config_ip4()
41 i.resolve_arp()
42
Klement Sekera75e7d132017-09-20 08:26:30 +020043 # packet sizes
44 cls.packet_sizes = [64, 512, 1518, 9018]
45 cls.padding = " abcdefghijklmn"
46 cls.create_stream(cls.packet_sizes)
47 cls.create_fragments()
48
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -070049 @classmethod
50 def tearDownClass(cls):
51 super(TestIPv4Reassembly, cls).tearDownClass()
52
Klement Sekera75e7d132017-09-20 08:26:30 +020053 def setUp(self):
54 """ Test setup - force timeout on existing reassemblies """
55 super(TestIPv4Reassembly, self).setUp()
Klement Sekera4c533132018-02-22 11:41:12 +010056 self.vapi.ip_reassembly_enable_disable(
57 sw_if_index=self.src_if.sw_if_index, enable_ip4=True)
Klement Sekera75e7d132017-09-20 08:26:30 +020058 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +020059 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +020060 expire_walk_interval_ms=10)
BenoƮt Ganne56eccdb2021-08-20 09:18:31 +020061 self.virtual_sleep(.25)
Klement Sekera75e7d132017-09-20 08:26:30 +020062 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +020063 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +020064 expire_walk_interval_ms=10000)
65
66 def tearDown(self):
67 super(TestIPv4Reassembly, self).tearDown()
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -070068
69 def show_commands_at_teardown(self):
Klement Sekera896c8962019-06-24 11:52:49 +000070 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
Klement Sekeracae98b72019-02-19 13:53:43 +010071 self.logger.debug(self.vapi.ppcli("show buffers"))
Klement Sekera75e7d132017-09-20 08:26:30 +020072
73 @classmethod
74 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
Klement Sekerad0f70a32018-12-14 17:24:13 +010075 """Create input packet stream
Klement Sekera75e7d132017-09-20 08:26:30 +020076
77 :param list packet_sizes: Required packet sizes.
78 """
79 for i in range(0, packet_count):
Klement Sekera4c533132018-02-22 11:41:12 +010080 info = cls.create_packet_info(cls.src_if, cls.src_if)
Klement Sekera75e7d132017-09-20 08:26:30 +020081 payload = cls.info_to_payload(info)
Klement Sekera4c533132018-02-22 11:41:12 +010082 p = (Ether(dst=cls.src_if.local_mac, src=cls.src_if.remote_mac) /
83 IP(id=info.index, src=cls.src_if.remote_ip4,
84 dst=cls.dst_if.remote_ip4) /
85 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +020086 Raw(payload))
87 size = packet_sizes[(i // 2) % len(packet_sizes)]
88 cls.extend_packet(p, size, cls.padding)
89 info.data = p
90
91 @classmethod
92 def create_fragments(cls):
93 infos = cls._packet_infos
94 cls.pkt_infos = []
Paul Vinciguerra090096b2020-12-03 00:42:46 -050095 for index, info in infos.items():
Klement Sekera75e7d132017-09-20 08:26:30 +020096 p = info.data
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -070097 # cls.logger.debug(ppp("Packet:",
98 # p.__class__(scapy.compat.raw(p))))
Klement Sekera75e7d132017-09-20 08:26:30 +020099 fragments_400 = fragment_rfc791(p, 400)
100 fragments_300 = fragment_rfc791(p, 300)
101 fragments_200 = [
102 x for f in fragments_400 for x in fragment_rfc791(f, 200)]
103 cls.pkt_infos.append(
104 (index, fragments_400, fragments_300, fragments_200))
105 cls.fragments_400 = [
106 x for (_, frags, _, _) in cls.pkt_infos for x in frags]
107 cls.fragments_300 = [
108 x for (_, _, frags, _) in cls.pkt_infos for x in frags]
109 cls.fragments_200 = [
110 x for (_, _, _, frags) in cls.pkt_infos for x in frags]
111 cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, "
112 "%s 300-byte fragments and %s 200-byte fragments" %
113 (len(infos), len(cls.fragments_400),
114 len(cls.fragments_300), len(cls.fragments_200)))
115
Klement Sekera947a85c2019-07-24 12:40:37 +0000116 def verify_capture(self, capture, dropped_packet_indexes=[]):
117 """Verify captured packet stream.
118
119 :param list capture: Captured packet stream.
120 """
121 info = None
122 seen = set()
123 for packet in capture:
124 try:
125 self.logger.debug(ppp("Got packet:", packet))
126 ip = packet[IP]
127 udp = packet[UDP]
128 payload_info = self.payload_to_info(packet[Raw])
129 packet_index = payload_info.index
130 self.assertTrue(
131 packet_index not in dropped_packet_indexes,
132 ppp("Packet received, but should be dropped:", packet))
133 if packet_index in seen:
134 raise Exception(ppp("Duplicate packet received", packet))
135 seen.add(packet_index)
136 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
137 info = self._packet_infos[packet_index]
138 self.assertTrue(info is not None)
139 self.assertEqual(packet_index, info.index)
140 saved_packet = info.data
141 self.assertEqual(ip.src, saved_packet[IP].src)
142 self.assertEqual(ip.dst, saved_packet[IP].dst)
143 self.assertEqual(udp.payload, saved_packet[UDP].payload)
144 except Exception:
145 self.logger.error(ppp("Unexpected or invalid packet:", packet))
146 raise
147 for index in self._packet_infos:
148 self.assertTrue(index in seen or index in dropped_packet_indexes,
149 "Packet with packet_index %d not received" % index)
150
151 def test_reassembly(self):
Klement Sekera75e7d132017-09-20 08:26:30 +0200152 """ basic reassembly """
153
Klement Sekera947a85c2019-07-24 12:40:37 +0000154 self.pg_enable_capture()
155 self.src_if.add_stream(self.fragments_200)
156 self.pg_start()
157
158 packets = self.dst_if.get_capture(len(self.pkt_infos))
159 self.verify_capture(packets)
160 self.src_if.assert_nothing_captured()
161
162 # run it all again to verify correctness
163 self.pg_enable_capture()
164 self.src_if.add_stream(self.fragments_200)
165 self.pg_start()
166
167 packets = self.dst_if.get_capture(len(self.pkt_infos))
168 self.verify_capture(packets)
169 self.src_if.assert_nothing_captured()
170
Klement Sekera53be16d2020-12-15 21:47:36 +0100171 def test_verify_clear_trace_mid_reassembly(self):
172 """ verify clear trace works mid-reassembly """
173
174 self.pg_enable_capture()
175 self.src_if.add_stream(self.fragments_200[0:-1])
176 self.pg_start()
177
178 self.logger.debug(self.vapi.cli("show trace"))
179 self.vapi.cli("clear trace")
180
181 self.src_if.add_stream(self.fragments_200[-1])
182 self.pg_start()
183 packets = self.dst_if.get_capture(len(self.pkt_infos))
184 self.verify_capture(packets)
185
Klement Sekera947a85c2019-07-24 12:40:37 +0000186 def test_reversed(self):
Klement Sekera75e7d132017-09-20 08:26:30 +0200187 """ reverse order reassembly """
188
Klement Sekera947a85c2019-07-24 12:40:37 +0000189 fragments = list(self.fragments_200)
190 fragments.reverse()
191
192 self.pg_enable_capture()
193 self.src_if.add_stream(fragments)
194 self.pg_start()
195
196 packets = self.dst_if.get_capture(len(self.packet_infos))
197 self.verify_capture(packets)
198 self.src_if.assert_nothing_captured()
199
200 # run it all again to verify correctness
201 self.pg_enable_capture()
202 self.src_if.add_stream(fragments)
203 self.pg_start()
204
205 packets = self.dst_if.get_capture(len(self.packet_infos))
206 self.verify_capture(packets)
207 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200208
Klement Sekera3a343d42019-05-16 14:35:46 +0200209 def test_long_fragment_chain(self):
210 """ long fragment chain """
211
212 error_cnt_str = \
Klement Sekera896c8962019-06-24 11:52:49 +0000213 "/err/ip4-full-reassembly-feature/fragment chain too long (drop)"
Klement Sekera3a343d42019-05-16 14:35:46 +0200214
Klement Sekera34641f22019-05-22 20:18:26 +0200215 error_cnt = self.statistics.get_err_counter(error_cnt_str)
Klement Sekera3a343d42019-05-16 14:35:46 +0200216
217 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
218 max_reassembly_length=3,
219 expire_walk_interval_ms=50)
220
221 p1 = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
222 IP(id=1000, src=self.src_if.remote_ip4,
223 dst=self.dst_if.remote_ip4) /
224 UDP(sport=1234, dport=5678) /
Ole Troan127fbec2019-10-18 15:22:56 +0200225 Raw(b"X" * 1000))
Klement Sekera3a343d42019-05-16 14:35:46 +0200226 p2 = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
227 IP(id=1001, src=self.src_if.remote_ip4,
228 dst=self.dst_if.remote_ip4) /
229 UDP(sport=1234, dport=5678) /
Ole Troan127fbec2019-10-18 15:22:56 +0200230 Raw(b"X" * 1000))
Klement Sekera3a343d42019-05-16 14:35:46 +0200231 frags = fragment_rfc791(p1, 200) + fragment_rfc791(p2, 500)
232
233 self.pg_enable_capture()
234 self.src_if.add_stream(frags)
235 self.pg_start()
236
237 self.dst_if.get_capture(1)
Klement Sekera34641f22019-05-22 20:18:26 +0200238 self.assert_error_counter_equal(error_cnt_str, error_cnt + 1)
Klement Sekera3a343d42019-05-16 14:35:46 +0200239
Klement Sekera14d7e902018-12-10 13:46:09 +0100240 def test_5737(self):
241 """ fragment length + ip header size > 65535 """
Klement Sekera4ee633e2018-12-14 12:00:44 +0100242 self.vapi.cli("clear errors")
Ole Troan127fbec2019-10-18 15:22:56 +0200243 raw = b'''E\x00\x00\x88,\xf8\x1f\xfe@\x01\x98\x00\xc0\xa8\n-\xc0\xa8\n\
244\x01\x08\x00\xf0J\xed\xcb\xf1\xf5Test-group: IPv4.IPv4.ipv4-message.\
245Ethernet-Payload.IPv4-Packet.IPv4-Header.Fragment-Offset; Test-case: 5737'''
Klement Sekera14d7e902018-12-10 13:46:09 +0100246 malformed_packet = (Ether(dst=self.src_if.local_mac,
247 src=self.src_if.remote_mac) /
248 IP(raw))
249 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
250 IP(id=1000, src=self.src_if.remote_ip4,
251 dst=self.dst_if.remote_ip4) /
252 UDP(sport=1234, dport=5678) /
Ole Troan127fbec2019-10-18 15:22:56 +0200253 Raw(b"X" * 1000))
Klement Sekera14d7e902018-12-10 13:46:09 +0100254 valid_fragments = fragment_rfc791(p, 400)
255
Ole Troan127fbec2019-10-18 15:22:56 +0200256 counter = "/err/ip4-full-reassembly-feature/malformed packets"
257 error_counter = self.statistics.get_err_counter(counter)
Klement Sekera14d7e902018-12-10 13:46:09 +0100258 self.pg_enable_capture()
259 self.src_if.add_stream([malformed_packet] + valid_fragments)
260 self.pg_start()
261
262 self.dst_if.get_capture(1)
Klement Sekera896c8962019-06-24 11:52:49 +0000263 self.logger.debug(self.vapi.ppcli("show error"))
Ole Troan127fbec2019-10-18 15:22:56 +0200264 self.assertEqual(self.statistics.get_err_counter(counter),
265 error_counter + 1)
Klement Sekera14d7e902018-12-10 13:46:09 +0100266
Klement Sekera400f6d82018-12-13 14:35:48 +0100267 def test_44924(self):
268 """ compress tiny fragments """
269 packets = [(Ether(dst=self.src_if.local_mac,
270 src=self.src_if.remote_mac) /
271 IP(id=24339, flags="MF", frag=0, ttl=64,
272 src=self.src_if.remote_ip4,
273 dst=self.dst_if.remote_ip4) /
274 ICMP(type="echo-request", code=0, id=0x1fe6, seq=0x2407) /
275 Raw(load='Test-group: IPv4')),
276 (Ether(dst=self.src_if.local_mac,
277 src=self.src_if.remote_mac) /
278 IP(id=24339, flags="MF", frag=3, ttl=64,
279 src=self.src_if.remote_ip4,
280 dst=self.dst_if.remote_ip4) /
281 ICMP(type="echo-request", code=0, id=0x1fe6, seq=0x2407) /
282 Raw(load='.IPv4.Fragmentation.vali')),
283 (Ether(dst=self.src_if.local_mac,
284 src=self.src_if.remote_mac) /
285 IP(id=24339, frag=6, ttl=64,
286 src=self.src_if.remote_ip4,
287 dst=self.dst_if.remote_ip4) /
288 ICMP(type="echo-request", code=0, id=0x1fe6, seq=0x2407) /
289 Raw(load='d; Test-case: 44924'))
290 ]
291
292 self.pg_enable_capture()
293 self.src_if.add_stream(packets)
294 self.pg_start()
295
296 self.dst_if.get_capture(1)
297
Klement Sekera4ee633e2018-12-14 12:00:44 +0100298 def test_frag_1(self):
299 """ fragment of size 1 """
300 self.vapi.cli("clear errors")
301 malformed_packets = [(Ether(dst=self.src_if.local_mac,
302 src=self.src_if.remote_mac) /
303 IP(id=7, len=21, flags="MF", frag=0, ttl=64,
304 src=self.src_if.remote_ip4,
305 dst=self.dst_if.remote_ip4) /
306 ICMP(type="echo-request")),
307 (Ether(dst=self.src_if.local_mac,
308 src=self.src_if.remote_mac) /
309 IP(id=7, len=21, frag=1, ttl=64,
310 src=self.src_if.remote_ip4,
311 dst=self.dst_if.remote_ip4) /
Ole Troan127fbec2019-10-18 15:22:56 +0200312 Raw(load=b'\x08')),
Klement Sekera4ee633e2018-12-14 12:00:44 +0100313 ]
314
315 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
316 IP(id=1000, src=self.src_if.remote_ip4,
317 dst=self.dst_if.remote_ip4) /
318 UDP(sport=1234, dport=5678) /
Ole Troan127fbec2019-10-18 15:22:56 +0200319 Raw(b"X" * 1000))
Klement Sekera4ee633e2018-12-14 12:00:44 +0100320 valid_fragments = fragment_rfc791(p, 400)
321
322 self.pg_enable_capture()
323 self.src_if.add_stream(malformed_packets + valid_fragments)
324 self.pg_start()
325
326 self.dst_if.get_capture(1)
327
Klement Sekera896c8962019-06-24 11:52:49 +0000328 self.assert_packet_counter_equal("ip4-full-reassembly-feature", 1)
Klement Sekera4ee633e2018-12-14 12:00:44 +0100329 # TODO remove above, uncomment below once clearing of counters
330 # is supported
331 # self.assert_packet_counter_equal(
Klement Sekera896c8962019-06-24 11:52:49 +0000332 # "/err/ip4-full-reassembly-feature/malformed packets", 1)
Klement Sekera4ee633e2018-12-14 12:00:44 +0100333
Klement Sekera947a85c2019-07-24 12:40:37 +0000334 def test_random(self):
335 """ random order reassembly """
336
337 fragments = list(self.fragments_200)
338 shuffle(fragments)
339
340 self.pg_enable_capture()
341 self.src_if.add_stream(fragments)
342 self.pg_start()
343
344 packets = self.dst_if.get_capture(len(self.packet_infos))
345 self.verify_capture(packets)
346 self.src_if.assert_nothing_captured()
347
348 # run it all again to verify correctness
349 self.pg_enable_capture()
350 self.src_if.add_stream(fragments)
351 self.pg_start()
352
353 packets = self.dst_if.get_capture(len(self.packet_infos))
354 self.verify_capture(packets)
355 self.src_if.assert_nothing_captured()
356
357 def test_duplicates(self):
Klement Sekera75e7d132017-09-20 08:26:30 +0200358 """ duplicate fragments """
Klement Sekera947a85c2019-07-24 12:40:37 +0000359
Klement Sekera75e7d132017-09-20 08:26:30 +0200360 fragments = [
361 x for (_, frags, _, _) in self.pkt_infos
362 for x in frags
363 for _ in range(0, min(2, len(frags)))
364 ]
Klement Sekera947a85c2019-07-24 12:40:37 +0000365
366 self.pg_enable_capture()
367 self.src_if.add_stream(fragments)
368 self.pg_start()
369
370 packets = self.dst_if.get_capture(len(self.pkt_infos))
371 self.verify_capture(packets)
372 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200373
374 def test_overlap1(self):
375 """ overlapping fragments case #1 """
376
377 fragments = []
378 for _, _, frags_300, frags_200 in self.pkt_infos:
379 if len(frags_300) == 1:
380 fragments.extend(frags_300)
381 else:
382 for i, j in zip(frags_200, frags_300):
383 fragments.extend(i)
384 fragments.extend(j)
385
386 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100387 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200388 self.pg_start()
389
Klement Sekera4c533132018-02-22 11:41:12 +0100390 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera947a85c2019-07-24 12:40:37 +0000391 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100392 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200393
394 # run it all to verify correctness
395 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100396 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200397 self.pg_start()
398
Klement Sekera4c533132018-02-22 11:41:12 +0100399 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera947a85c2019-07-24 12:40:37 +0000400 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100401 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200402
403 def test_overlap2(self):
404 """ overlapping fragments case #2 """
405
406 fragments = []
407 for _, _, frags_300, frags_200 in self.pkt_infos:
408 if len(frags_300) == 1:
409 fragments.extend(frags_300)
410 else:
411 # care must be taken here so that there are no fragments
412 # received by vpp after reassembly is finished, otherwise
413 # new reassemblies will be started and packet generator will
414 # freak out when it detects unfreed buffers
415 zipped = zip(frags_300, frags_200)
Paul Vinciguerrac7834e02019-03-02 10:43:05 -0800416 for i, j in zipped:
Klement Sekera75e7d132017-09-20 08:26:30 +0200417 fragments.extend(i)
418 fragments.extend(j)
Paul Vinciguerrac7834e02019-03-02 10:43:05 -0800419 fragments.pop()
Klement Sekera75e7d132017-09-20 08:26:30 +0200420
421 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100422 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200423 self.pg_start()
424
Klement Sekera4c533132018-02-22 11:41:12 +0100425 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera947a85c2019-07-24 12:40:37 +0000426 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100427 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200428
429 # run it all to verify correctness
430 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100431 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200432 self.pg_start()
433
Klement Sekera4c533132018-02-22 11:41:12 +0100434 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera947a85c2019-07-24 12:40:37 +0000435 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100436 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200437
Klement Sekera947a85c2019-07-24 12:40:37 +0000438 def test_timeout_inline(self):
Klement Sekera75e7d132017-09-20 08:26:30 +0200439 """ timeout (inline) """
440
441 dropped_packet_indexes = set(
442 index for (index, frags, _, _) in self.pkt_infos if len(frags) > 1
443 )
444
Klement Sekera947a85c2019-07-24 12:40:37 +0000445 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
446 max_reassembly_length=3,
447 expire_walk_interval_ms=10000)
448
449 self.pg_enable_capture()
450 self.src_if.add_stream(self.fragments_400)
451 self.pg_start()
452
453 packets = self.dst_if.get_capture(
454 len(self.pkt_infos) - len(dropped_packet_indexes))
455 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +0100456 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200457
458 def test_timeout_cleanup(self):
459 """ timeout (cleanup) """
460
461 # whole packets + fragmented packets sans last fragment
462 fragments = [
463 x for (_, frags_400, _, _) in self.pkt_infos
464 for x in frags_400[:-1 if len(frags_400) > 1 else None]
465 ]
466
467 # last fragments for fragmented packets
468 fragments2 = [frags_400[-1]
469 for (_, frags_400, _, _) in self.pkt_infos
470 if len(frags_400) > 1]
471
472 dropped_packet_indexes = set(
473 index for (index, frags_400, _, _) in self.pkt_infos
474 if len(frags_400) > 1)
475
476 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +0200477 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +0200478 expire_walk_interval_ms=50)
479
480 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100481 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200482 self.pg_start()
483
BenoƮt Ganne56eccdb2021-08-20 09:18:31 +0200484 self.virtual_sleep(.25, "wait before sending rest of fragments")
Klement Sekera75e7d132017-09-20 08:26:30 +0200485
Klement Sekera4c533132018-02-22 11:41:12 +0100486 self.src_if.add_stream(fragments2)
Klement Sekera75e7d132017-09-20 08:26:30 +0200487 self.pg_start()
Klement Sekera75e7d132017-09-20 08:26:30 +0200488
Klement Sekera4c533132018-02-22 11:41:12 +0100489 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +0200490 len(self.pkt_infos) - len(dropped_packet_indexes))
Klement Sekera947a85c2019-07-24 12:40:37 +0000491 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +0100492 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200493
Klement Sekera947a85c2019-07-24 12:40:37 +0000494 def test_disabled(self):
Klement Sekera75e7d132017-09-20 08:26:30 +0200495 """ reassembly disabled """
496
497 dropped_packet_indexes = set(
498 index for (index, frags_400, _, _) in self.pkt_infos
499 if len(frags_400) > 1)
Klement Sekera947a85c2019-07-24 12:40:37 +0000500
501 self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=0,
502 max_reassembly_length=3,
503 expire_walk_interval_ms=10000)
504
505 self.pg_enable_capture()
506 self.src_if.add_stream(self.fragments_400)
507 self.pg_start()
508
509 packets = self.dst_if.get_capture(
510 len(self.pkt_infos) - len(dropped_packet_indexes))
511 self.verify_capture(packets, dropped_packet_indexes)
512 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200513
514
Klement Sekerade34c352019-06-25 11:19:22 +0000515class TestIPv4SVReassembly(VppTestCase):
516 """ IPv4 Shallow Virtual Reassembly """
517
518 @classmethod
519 def setUpClass(cls):
520 super(TestIPv4SVReassembly, cls).setUpClass()
521
522 cls.create_pg_interfaces([0, 1])
523 cls.src_if = cls.pg0
524 cls.dst_if = cls.pg1
525
526 # setup all interfaces
527 for i in cls.pg_interfaces:
528 i.admin_up()
529 i.config_ip4()
530 i.resolve_arp()
531
532 def setUp(self):
533 """ Test setup - force timeout on existing reassemblies """
534 super(TestIPv4SVReassembly, self).setUp()
535 self.vapi.ip_reassembly_enable_disable(
536 sw_if_index=self.src_if.sw_if_index, enable_ip4=True,
537 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL)
538 self.vapi.ip_reassembly_set(
539 timeout_ms=0, max_reassemblies=1000,
540 max_reassembly_length=1000,
541 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
542 expire_walk_interval_ms=10)
BenoƮt Ganne56eccdb2021-08-20 09:18:31 +0200543 self.virtual_sleep(.25)
Klement Sekerade34c352019-06-25 11:19:22 +0000544 self.vapi.ip_reassembly_set(
545 timeout_ms=1000000, max_reassemblies=1000,
546 max_reassembly_length=1000,
547 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
548 expire_walk_interval_ms=10000)
549
550 def tearDown(self):
551 super(TestIPv4SVReassembly, self).tearDown()
552 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
553 self.logger.debug(self.vapi.ppcli("show buffers"))
554
555 def test_basic(self):
556 """ basic reassembly """
557 payload_len = 1000
558 payload = ""
559 counter = 0
560 while len(payload) < payload_len:
561 payload += "%u " % counter
562 counter += 1
563
564 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
565 IP(id=1, src=self.src_if.remote_ip4,
566 dst=self.dst_if.remote_ip4) /
567 UDP(sport=1234, dport=5678) /
568 Raw(payload))
569 fragments = fragment_rfc791(p, payload_len/4)
570
571 # send fragment #2 - should be cached inside reassembly
572 self.pg_enable_capture()
573 self.src_if.add_stream(fragments[1])
574 self.pg_start()
575 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
576 self.logger.debug(self.vapi.ppcli("show buffers"))
577 self.logger.debug(self.vapi.ppcli("show trace"))
578 self.dst_if.assert_nothing_captured()
579
580 # send fragment #1 - reassembly is finished now and both fragments
581 # forwarded
582 self.pg_enable_capture()
583 self.src_if.add_stream(fragments[0])
584 self.pg_start()
585 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
586 self.logger.debug(self.vapi.ppcli("show buffers"))
587 self.logger.debug(self.vapi.ppcli("show trace"))
588 c = self.dst_if.get_capture(2)
589 for sent, recvd in zip([fragments[1], fragments[0]], c):
590 self.assertEqual(sent[IP].src, recvd[IP].src)
591 self.assertEqual(sent[IP].dst, recvd[IP].dst)
592 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
593
594 # send rest of fragments - should be immediately forwarded
595 self.pg_enable_capture()
596 self.src_if.add_stream(fragments[2:])
597 self.pg_start()
598 c = self.dst_if.get_capture(len(fragments[2:]))
599 for sent, recvd in zip(fragments[2:], c):
600 self.assertEqual(sent[IP].src, recvd[IP].src)
601 self.assertEqual(sent[IP].dst, recvd[IP].dst)
602 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
603
Klement Sekera53be16d2020-12-15 21:47:36 +0100604 def test_verify_clear_trace_mid_reassembly(self):
605 """ verify clear trace works mid-reassembly """
606 payload_len = 1000
607 payload = ""
608 counter = 0
609 while len(payload) < payload_len:
610 payload += "%u " % counter
611 counter += 1
612
613 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
614 IP(id=1, src=self.src_if.remote_ip4,
615 dst=self.dst_if.remote_ip4) /
616 UDP(sport=1234, dport=5678) /
617 Raw(payload))
618 fragments = fragment_rfc791(p, payload_len/4)
619
620 self.pg_enable_capture()
621 self.src_if.add_stream(fragments[1])
622 self.pg_start()
623
624 self.logger.debug(self.vapi.cli("show trace"))
625 self.vapi.cli("clear trace")
626
627 self.pg_enable_capture()
628 self.src_if.add_stream(fragments[0])
629 self.pg_start()
630 self.dst_if.get_capture(2)
631
632 self.logger.debug(self.vapi.cli("show trace"))
633 self.vapi.cli("clear trace")
634
635 self.pg_enable_capture()
636 self.src_if.add_stream(fragments[2:])
637 self.pg_start()
638 self.dst_if.get_capture(len(fragments[2:]))
639
Klement Sekerade34c352019-06-25 11:19:22 +0000640 def test_timeout(self):
641 """ reassembly timeout """
642 payload_len = 1000
643 payload = ""
644 counter = 0
645 while len(payload) < payload_len:
646 payload += "%u " % counter
647 counter += 1
648
649 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
650 IP(id=1, src=self.src_if.remote_ip4,
651 dst=self.dst_if.remote_ip4) /
652 UDP(sport=1234, dport=5678) /
653 Raw(payload))
654 fragments = fragment_rfc791(p, payload_len/4)
655
656 self.vapi.ip_reassembly_set(
657 timeout_ms=100, max_reassemblies=1000,
658 max_reassembly_length=1000,
659 expire_walk_interval_ms=50,
660 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL)
661
662 # send fragments #2 and #1 - should be forwarded
663 self.pg_enable_capture()
664 self.src_if.add_stream(fragments[0:2])
665 self.pg_start()
666 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
667 self.logger.debug(self.vapi.ppcli("show buffers"))
668 self.logger.debug(self.vapi.ppcli("show trace"))
669 c = self.dst_if.get_capture(2)
670 for sent, recvd in zip([fragments[1], fragments[0]], c):
671 self.assertEqual(sent[IP].src, recvd[IP].src)
672 self.assertEqual(sent[IP].dst, recvd[IP].dst)
673 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
674
675 # wait for cleanup
BenoƮt Ganne56eccdb2021-08-20 09:18:31 +0200676 self.virtual_sleep(.25, "wait before sending rest of fragments")
Klement Sekerade34c352019-06-25 11:19:22 +0000677
678 # send rest of fragments - shouldn't be forwarded
679 self.pg_enable_capture()
680 self.src_if.add_stream(fragments[2:])
681 self.pg_start()
682 self.dst_if.assert_nothing_captured()
683
684 def test_lru(self):
685 """ reassembly reuses LRU element """
686
687 self.vapi.ip_reassembly_set(
688 timeout_ms=1000000, max_reassemblies=1,
689 max_reassembly_length=1000,
690 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
691 expire_walk_interval_ms=10000)
692
693 payload_len = 1000
694 payload = ""
695 counter = 0
696 while len(payload) < payload_len:
697 payload += "%u " % counter
698 counter += 1
699
700 packet_count = 10
701
702 fragments = [f
703 for i in range(packet_count)
704 for p in (Ether(dst=self.src_if.local_mac,
705 src=self.src_if.remote_mac) /
706 IP(id=i, src=self.src_if.remote_ip4,
707 dst=self.dst_if.remote_ip4) /
708 UDP(sport=1234, dport=5678) /
709 Raw(payload))
710 for f in fragment_rfc791(p, payload_len/4)]
711
712 self.pg_enable_capture()
713 self.src_if.add_stream(fragments)
714 self.pg_start()
715 c = self.dst_if.get_capture(len(fragments))
716 for sent, recvd in zip(fragments, c):
717 self.assertEqual(sent[IP].src, recvd[IP].src)
718 self.assertEqual(sent[IP].dst, recvd[IP].dst)
719 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
720
Klement Sekera18c6cd92020-07-10 09:29:48 +0000721 def send_mixed_and_verify_capture(self, traffic):
722 stream = []
723 for t in traffic:
724 for c in range(t['count']):
725 stream.append(
726 (Ether(dst=self.src_if.local_mac,
727 src=self.src_if.remote_mac) /
728 IP(id=self.counter,
729 flags=t['flags'],
730 src=self.src_if.remote_ip4,
731 dst=self.dst_if.remote_ip4) /
732 UDP(sport=1234, dport=5678) /
733 Raw("abcdef")))
734 self.counter = self.counter + 1
735
736 self.pg_enable_capture()
737 self.src_if.add_stream(stream)
738 self.pg_start()
739 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
740 self.logger.debug(self.vapi.ppcli("show buffers"))
741 self.logger.debug(self.vapi.ppcli("show trace"))
742 self.dst_if.get_capture(len(stream))
743
744 def test_mixed(self):
745 """ mixed traffic correctly passes through SVR """
746 self.counter = 1
747
748 self.send_mixed_and_verify_capture([{'count': 1, 'flags': ''}])
749 self.send_mixed_and_verify_capture([{'count': 2, 'flags': ''}])
750 self.send_mixed_and_verify_capture([{'count': 3, 'flags': ''}])
751 self.send_mixed_and_verify_capture([{'count': 8, 'flags': ''}])
752 self.send_mixed_and_verify_capture([{'count': 257, 'flags': ''}])
753
754 self.send_mixed_and_verify_capture([{'count': 1, 'flags': 'MF'}])
755 self.send_mixed_and_verify_capture([{'count': 2, 'flags': 'MF'}])
756 self.send_mixed_and_verify_capture([{'count': 3, 'flags': 'MF'}])
757 self.send_mixed_and_verify_capture([{'count': 8, 'flags': 'MF'}])
758 self.send_mixed_and_verify_capture([{'count': 257, 'flags': 'MF'}])
759
760 self.send_mixed_and_verify_capture(
761 [{'count': 1, 'flags': ''}, {'count': 1, 'flags': 'MF'}])
762 self.send_mixed_and_verify_capture(
763 [{'count': 2, 'flags': ''}, {'count': 2, 'flags': 'MF'}])
764 self.send_mixed_and_verify_capture(
765 [{'count': 3, 'flags': ''}, {'count': 3, 'flags': 'MF'}])
766 self.send_mixed_and_verify_capture(
767 [{'count': 8, 'flags': ''}, {'count': 8, 'flags': 'MF'}])
768 self.send_mixed_and_verify_capture(
769 [{'count': 129, 'flags': ''}, {'count': 129, 'flags': 'MF'}])
770
771 self.send_mixed_and_verify_capture(
772 [{'count': 1, 'flags': ''}, {'count': 1, 'flags': 'MF'},
773 {'count': 1, 'flags': ''}, {'count': 1, 'flags': 'MF'}])
774 self.send_mixed_and_verify_capture(
775 [{'count': 2, 'flags': ''}, {'count': 2, 'flags': 'MF'},
776 {'count': 2, 'flags': ''}, {'count': 2, 'flags': 'MF'}])
777 self.send_mixed_and_verify_capture(
778 [{'count': 3, 'flags': ''}, {'count': 3, 'flags': 'MF'},
779 {'count': 3, 'flags': ''}, {'count': 3, 'flags': 'MF'}])
780 self.send_mixed_and_verify_capture(
781 [{'count': 8, 'flags': ''}, {'count': 8, 'flags': 'MF'},
782 {'count': 8, 'flags': ''}, {'count': 8, 'flags': 'MF'}])
783 self.send_mixed_and_verify_capture(
784 [{'count': 65, 'flags': ''}, {'count': 65, 'flags': 'MF'},
785 {'count': 65, 'flags': ''}, {'count': 65, 'flags': 'MF'}])
786
Klement Sekerade34c352019-06-25 11:19:22 +0000787
Klement Sekera630ab582019-07-19 09:14:19 +0000788class TestIPv4MWReassembly(VppTestCase):
789 """ IPv4 Reassembly (multiple workers) """
Klement Sekera8d815022021-03-15 16:58:10 +0100790 vpp_worker_count = 3
Klement Sekera630ab582019-07-19 09:14:19 +0000791
792 @classmethod
793 def setUpClass(cls):
794 super(TestIPv4MWReassembly, cls).setUpClass()
795
Klement Sekera8d815022021-03-15 16:58:10 +0100796 cls.create_pg_interfaces(range(cls.vpp_worker_count+1))
Klement Sekera630ab582019-07-19 09:14:19 +0000797 cls.src_if = cls.pg0
798 cls.send_ifs = cls.pg_interfaces[:-1]
799 cls.dst_if = cls.pg_interfaces[-1]
800
801 # setup all interfaces
802 for i in cls.pg_interfaces:
803 i.admin_up()
804 i.config_ip4()
805 i.resolve_arp()
806
807 # packets sizes reduced here because we are generating packets without
808 # Ethernet headers, which are added later (diff fragments go via
809 # different interfaces)
810 cls.packet_sizes = [64-len(Ether()), 512-len(Ether()),
811 1518-len(Ether()), 9018-len(Ether())]
812 cls.padding = " abcdefghijklmn"
813 cls.create_stream(cls.packet_sizes)
814 cls.create_fragments()
815
816 @classmethod
817 def tearDownClass(cls):
818 super(TestIPv4MWReassembly, cls).tearDownClass()
819
820 def setUp(self):
821 """ Test setup - force timeout on existing reassemblies """
822 super(TestIPv4MWReassembly, self).setUp()
823 for intf in self.send_ifs:
824 self.vapi.ip_reassembly_enable_disable(
825 sw_if_index=intf.sw_if_index, enable_ip4=True)
826 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
827 max_reassembly_length=1000,
828 expire_walk_interval_ms=10)
BenoƮt Ganne56eccdb2021-08-20 09:18:31 +0200829 self.virtual_sleep(.25)
Klement Sekera630ab582019-07-19 09:14:19 +0000830 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
831 max_reassembly_length=1000,
832 expire_walk_interval_ms=10000)
833
834 def tearDown(self):
835 super(TestIPv4MWReassembly, self).tearDown()
836
837 def show_commands_at_teardown(self):
Klement Sekera896c8962019-06-24 11:52:49 +0000838 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
Klement Sekera630ab582019-07-19 09:14:19 +0000839 self.logger.debug(self.vapi.ppcli("show buffers"))
840
841 @classmethod
842 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
843 """Create input packet stream
844
845 :param list packet_sizes: Required packet sizes.
846 """
847 for i in range(0, packet_count):
848 info = cls.create_packet_info(cls.src_if, cls.src_if)
849 payload = cls.info_to_payload(info)
850 p = (IP(id=info.index, src=cls.src_if.remote_ip4,
851 dst=cls.dst_if.remote_ip4) /
852 UDP(sport=1234, dport=5678) /
853 Raw(payload))
854 size = packet_sizes[(i // 2) % len(packet_sizes)]
855 cls.extend_packet(p, size, cls.padding)
856 info.data = p
857
858 @classmethod
859 def create_fragments(cls):
860 infos = cls._packet_infos
861 cls.pkt_infos = []
Paul Vinciguerra090096b2020-12-03 00:42:46 -0500862 for index, info in infos.items():
Klement Sekera630ab582019-07-19 09:14:19 +0000863 p = info.data
864 # cls.logger.debug(ppp("Packet:",
865 # p.__class__(scapy.compat.raw(p))))
866 fragments_400 = fragment_rfc791(p, 400)
867 cls.pkt_infos.append((index, fragments_400))
868 cls.fragments_400 = [
869 x for (_, frags) in cls.pkt_infos for x in frags]
870 cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, " %
871 (len(infos), len(cls.fragments_400)))
872
873 def verify_capture(self, capture, dropped_packet_indexes=[]):
874 """Verify captured packet stream.
875
876 :param list capture: Captured packet stream.
877 """
878 info = None
879 seen = set()
880 for packet in capture:
881 try:
882 self.logger.debug(ppp("Got packet:", packet))
883 ip = packet[IP]
884 udp = packet[UDP]
885 payload_info = self.payload_to_info(packet[Raw])
886 packet_index = payload_info.index
887 self.assertTrue(
888 packet_index not in dropped_packet_indexes,
889 ppp("Packet received, but should be dropped:", packet))
890 if packet_index in seen:
891 raise Exception(ppp("Duplicate packet received", packet))
892 seen.add(packet_index)
893 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
894 info = self._packet_infos[packet_index]
895 self.assertTrue(info is not None)
896 self.assertEqual(packet_index, info.index)
897 saved_packet = info.data
898 self.assertEqual(ip.src, saved_packet[IP].src)
899 self.assertEqual(ip.dst, saved_packet[IP].dst)
900 self.assertEqual(udp.payload, saved_packet[UDP].payload)
901 except Exception:
902 self.logger.error(ppp("Unexpected or invalid packet:", packet))
903 raise
904 for index in self._packet_infos:
905 self.assertTrue(index in seen or index in dropped_packet_indexes,
906 "Packet with packet_index %d not received" % index)
907
908 def send_packets(self, packets):
Klement Sekera8d815022021-03-15 16:58:10 +0100909 for counter in range(self.vpp_worker_count):
Klement Sekera630ab582019-07-19 09:14:19 +0000910 if 0 == len(packets[counter]):
911 continue
912 send_if = self.send_ifs[counter]
913 send_if.add_stream(
914 (Ether(dst=send_if.local_mac, src=send_if.remote_mac) / x
915 for x in packets[counter]),
916 worker=counter)
917 self.pg_start()
918
919 def test_worker_conflict(self):
920 """ 1st and FO=0 fragments on different workers """
921
922 # in first wave we send fragments which don't start at offset 0
923 # then we send fragments with offset 0 on a different thread
924 # then the rest of packets on a random thread
Klement Sekera8d815022021-03-15 16:58:10 +0100925 first_packets = [[] for n in range(self.vpp_worker_count)]
926 second_packets = [[] for n in range(self.vpp_worker_count)]
927 rest_of_packets = [[] for n in range(self.vpp_worker_count)]
Klement Sekera630ab582019-07-19 09:14:19 +0000928 for (_, p) in self.pkt_infos:
Klement Sekera8d815022021-03-15 16:58:10 +0100929 wi = randrange(self.vpp_worker_count)
Klement Sekera630ab582019-07-19 09:14:19 +0000930 second_packets[wi].append(p[0])
931 if len(p) <= 1:
932 continue
933 wi2 = wi
934 while wi2 == wi:
Klement Sekera8d815022021-03-15 16:58:10 +0100935 wi2 = randrange(self.vpp_worker_count)
Klement Sekera630ab582019-07-19 09:14:19 +0000936 first_packets[wi2].append(p[1])
Klement Sekera8d815022021-03-15 16:58:10 +0100937 wi3 = randrange(self.vpp_worker_count)
Klement Sekera630ab582019-07-19 09:14:19 +0000938 rest_of_packets[wi3].extend(p[2:])
939
940 self.pg_enable_capture()
941 self.send_packets(first_packets)
942 self.send_packets(second_packets)
943 self.send_packets(rest_of_packets)
944
945 packets = self.dst_if.get_capture(len(self.pkt_infos))
946 self.verify_capture(packets)
947 for send_if in self.send_ifs:
948 send_if.assert_nothing_captured()
949
Klement Sekera68bae5b2019-10-10 18:57:34 +0000950 self.logger.debug(self.vapi.ppcli("show trace"))
951 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
952 self.logger.debug(self.vapi.ppcli("show buffers"))
953 self.vapi.cli("clear trace")
954
Klement Sekera630ab582019-07-19 09:14:19 +0000955 self.pg_enable_capture()
956 self.send_packets(first_packets)
957 self.send_packets(second_packets)
958 self.send_packets(rest_of_packets)
959
960 packets = self.dst_if.get_capture(len(self.pkt_infos))
961 self.verify_capture(packets)
962 for send_if in self.send_ifs:
963 send_if.assert_nothing_captured()
964
965
Klement Sekera947a85c2019-07-24 12:40:37 +0000966class TestIPv6Reassembly(VppTestCase):
Klement Sekera75e7d132017-09-20 08:26:30 +0200967 """ IPv6 Reassembly """
968
969 @classmethod
970 def setUpClass(cls):
971 super(TestIPv6Reassembly, cls).setUpClass()
972
Klement Sekera4c533132018-02-22 11:41:12 +0100973 cls.create_pg_interfaces([0, 1])
974 cls.src_if = cls.pg0
975 cls.dst_if = cls.pg1
Klement Sekera75e7d132017-09-20 08:26:30 +0200976
977 # setup all interfaces
978 for i in cls.pg_interfaces:
979 i.admin_up()
980 i.config_ip6()
981 i.resolve_ndp()
982
Klement Sekera75e7d132017-09-20 08:26:30 +0200983 # packet sizes
984 cls.packet_sizes = [64, 512, 1518, 9018]
985 cls.padding = " abcdefghijklmn"
986 cls.create_stream(cls.packet_sizes)
987 cls.create_fragments()
988
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -0700989 @classmethod
990 def tearDownClass(cls):
991 super(TestIPv6Reassembly, cls).tearDownClass()
992
Klement Sekera75e7d132017-09-20 08:26:30 +0200993 def setUp(self):
994 """ Test setup - force timeout on existing reassemblies """
995 super(TestIPv6Reassembly, self).setUp()
Klement Sekera4c533132018-02-22 11:41:12 +0100996 self.vapi.ip_reassembly_enable_disable(
997 sw_if_index=self.src_if.sw_if_index, enable_ip6=True)
Klement Sekera75e7d132017-09-20 08:26:30 +0200998 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +0200999 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +02001000 expire_walk_interval_ms=10, is_ip6=1)
BenoƮt Ganne56eccdb2021-08-20 09:18:31 +02001001 self.virtual_sleep(.25)
Klement Sekera75e7d132017-09-20 08:26:30 +02001002 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +02001003 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +02001004 expire_walk_interval_ms=10000, is_ip6=1)
Klement Sekera896c8962019-06-24 11:52:49 +00001005 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
Klement Sekeracae98b72019-02-19 13:53:43 +01001006 self.logger.debug(self.vapi.ppcli("show buffers"))
Klement Sekera75e7d132017-09-20 08:26:30 +02001007
1008 def tearDown(self):
1009 super(TestIPv6Reassembly, self).tearDown()
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -07001010
1011 def show_commands_at_teardown(self):
Klement Sekera896c8962019-06-24 11:52:49 +00001012 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
Klement Sekeracae98b72019-02-19 13:53:43 +01001013 self.logger.debug(self.vapi.ppcli("show buffers"))
Klement Sekera75e7d132017-09-20 08:26:30 +02001014
1015 @classmethod
1016 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
1017 """Create input packet stream for defined interface.
1018
1019 :param list packet_sizes: Required packet sizes.
1020 """
1021 for i in range(0, packet_count):
Klement Sekera4c533132018-02-22 11:41:12 +01001022 info = cls.create_packet_info(cls.src_if, cls.src_if)
Klement Sekera75e7d132017-09-20 08:26:30 +02001023 payload = cls.info_to_payload(info)
Klement Sekera4c533132018-02-22 11:41:12 +01001024 p = (Ether(dst=cls.src_if.local_mac, src=cls.src_if.remote_mac) /
1025 IPv6(src=cls.src_if.remote_ip6,
1026 dst=cls.dst_if.remote_ip6) /
1027 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +02001028 Raw(payload))
1029 size = packet_sizes[(i // 2) % len(packet_sizes)]
1030 cls.extend_packet(p, size, cls.padding)
1031 info.data = p
1032
1033 @classmethod
1034 def create_fragments(cls):
1035 infos = cls._packet_infos
1036 cls.pkt_infos = []
Paul Vinciguerra090096b2020-12-03 00:42:46 -05001037 for index, info in infos.items():
Klement Sekera75e7d132017-09-20 08:26:30 +02001038 p = info.data
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07001039 # cls.logger.debug(ppp("Packet:",
1040 # p.__class__(scapy.compat.raw(p))))
Klement Sekera75e7d132017-09-20 08:26:30 +02001041 fragments_400 = fragment_rfc8200(p, info.index, 400)
1042 fragments_300 = fragment_rfc8200(p, info.index, 300)
1043 cls.pkt_infos.append((index, fragments_400, fragments_300))
1044 cls.fragments_400 = [
1045 x for _, frags, _ in cls.pkt_infos for x in frags]
1046 cls.fragments_300 = [
1047 x for _, _, frags in cls.pkt_infos for x in frags]
1048 cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, "
1049 "and %s 300-byte fragments" %
1050 (len(infos), len(cls.fragments_400),
1051 len(cls.fragments_300)))
1052
Klement Sekera947a85c2019-07-24 12:40:37 +00001053 def verify_capture(self, capture, dropped_packet_indexes=[]):
1054 """Verify captured packet strea .
1055
1056 :param list capture: Captured packet stream.
1057 """
1058 info = None
1059 seen = set()
1060 for packet in capture:
1061 try:
1062 self.logger.debug(ppp("Got packet:", packet))
1063 ip = packet[IPv6]
1064 udp = packet[UDP]
1065 payload_info = self.payload_to_info(packet[Raw])
1066 packet_index = payload_info.index
1067 self.assertTrue(
1068 packet_index not in dropped_packet_indexes,
1069 ppp("Packet received, but should be dropped:", packet))
1070 if packet_index in seen:
1071 raise Exception(ppp("Duplicate packet received", packet))
1072 seen.add(packet_index)
1073 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
1074 info = self._packet_infos[packet_index]
1075 self.assertTrue(info is not None)
1076 self.assertEqual(packet_index, info.index)
1077 saved_packet = info.data
1078 self.assertEqual(ip.src, saved_packet[IPv6].src)
1079 self.assertEqual(ip.dst, saved_packet[IPv6].dst)
1080 self.assertEqual(udp.payload, saved_packet[UDP].payload)
1081 except Exception:
1082 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1083 raise
1084 for index in self._packet_infos:
1085 self.assertTrue(index in seen or index in dropped_packet_indexes,
1086 "Packet with packet_index %d not received" % index)
1087
1088 def test_reassembly(self):
Klement Sekera75e7d132017-09-20 08:26:30 +02001089 """ basic reassembly """
1090
Klement Sekera947a85c2019-07-24 12:40:37 +00001091 self.pg_enable_capture()
1092 self.src_if.add_stream(self.fragments_400)
1093 self.pg_start()
1094
1095 packets = self.dst_if.get_capture(len(self.pkt_infos))
1096 self.verify_capture(packets)
1097 self.src_if.assert_nothing_captured()
1098
1099 # run it all again to verify correctness
1100 self.pg_enable_capture()
1101 self.src_if.add_stream(self.fragments_400)
1102 self.pg_start()
1103
1104 packets = self.dst_if.get_capture(len(self.pkt_infos))
1105 self.verify_capture(packets)
1106 self.src_if.assert_nothing_captured()
1107
Klement Sekera769145c2019-03-06 11:59:57 +01001108 def test_buffer_boundary(self):
1109 """ fragment header crossing buffer boundary """
1110
1111 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1112 IPv6(src=self.src_if.remote_ip6,
1113 dst=self.src_if.local_ip6) /
1114 IPv6ExtHdrHopByHop(
1115 options=[HBHOptUnknown(otype=0xff, optlen=0)] * 1000) /
1116 IPv6ExtHdrFragment(m=1) /
1117 UDP(sport=1234, dport=5678) /
1118 Raw())
1119 self.pg_enable_capture()
1120 self.src_if.add_stream([p])
1121 self.pg_start()
1122 self.src_if.assert_nothing_captured()
1123 self.dst_if.assert_nothing_captured()
1124
Klement Sekera53be16d2020-12-15 21:47:36 +01001125 def test_verify_clear_trace_mid_reassembly(self):
1126 """ verify clear trace works mid-reassembly """
1127
1128 self.pg_enable_capture()
1129 self.src_if.add_stream(self.fragments_400[0:-1])
1130 self.pg_start()
1131
1132 self.logger.debug(self.vapi.cli("show trace"))
1133 self.vapi.cli("clear trace")
1134
1135 self.src_if.add_stream(self.fragments_400[-1])
1136 self.pg_start()
1137 packets = self.dst_if.get_capture(len(self.pkt_infos))
1138 self.verify_capture(packets)
1139
Klement Sekera947a85c2019-07-24 12:40:37 +00001140 def test_reversed(self):
Klement Sekera75e7d132017-09-20 08:26:30 +02001141 """ reverse order reassembly """
1142
Klement Sekera947a85c2019-07-24 12:40:37 +00001143 fragments = list(self.fragments_400)
1144 fragments.reverse()
1145
1146 self.pg_enable_capture()
1147 self.src_if.add_stream(fragments)
1148 self.pg_start()
1149
1150 packets = self.dst_if.get_capture(len(self.pkt_infos))
1151 self.verify_capture(packets)
1152 self.src_if.assert_nothing_captured()
1153
1154 # run it all again to verify correctness
1155 self.pg_enable_capture()
1156 self.src_if.add_stream(fragments)
1157 self.pg_start()
1158
1159 packets = self.dst_if.get_capture(len(self.pkt_infos))
1160 self.verify_capture(packets)
1161 self.src_if.assert_nothing_captured()
1162
1163 def test_random(self):
Klement Sekera75e7d132017-09-20 08:26:30 +02001164 """ random order reassembly """
1165
Klement Sekera947a85c2019-07-24 12:40:37 +00001166 fragments = list(self.fragments_400)
1167 shuffle(fragments)
1168
1169 self.pg_enable_capture()
1170 self.src_if.add_stream(fragments)
1171 self.pg_start()
1172
1173 packets = self.dst_if.get_capture(len(self.pkt_infos))
1174 self.verify_capture(packets)
1175 self.src_if.assert_nothing_captured()
1176
1177 # run it all again to verify correctness
1178 self.pg_enable_capture()
1179 self.src_if.add_stream(fragments)
1180 self.pg_start()
1181
1182 packets = self.dst_if.get_capture(len(self.pkt_infos))
1183 self.verify_capture(packets)
1184 self.src_if.assert_nothing_captured()
1185
1186 def test_duplicates(self):
Klement Sekera75e7d132017-09-20 08:26:30 +02001187 """ duplicate fragments """
1188
1189 fragments = [
1190 x for (_, frags, _) in self.pkt_infos
1191 for x in frags
1192 for _ in range(0, min(2, len(frags)))
1193 ]
Klement Sekera947a85c2019-07-24 12:40:37 +00001194
1195 self.pg_enable_capture()
1196 self.src_if.add_stream(fragments)
1197 self.pg_start()
1198
1199 packets = self.dst_if.get_capture(len(self.pkt_infos))
1200 self.verify_capture(packets)
1201 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +02001202
Klement Sekera3a343d42019-05-16 14:35:46 +02001203 def test_long_fragment_chain(self):
1204 """ long fragment chain """
1205
1206 error_cnt_str = \
Klement Sekera896c8962019-06-24 11:52:49 +00001207 "/err/ip6-full-reassembly-feature/fragment chain too long (drop)"
Klement Sekera3a343d42019-05-16 14:35:46 +02001208
Klement Sekera34641f22019-05-22 20:18:26 +02001209 error_cnt = self.statistics.get_err_counter(error_cnt_str)
Klement Sekera3a343d42019-05-16 14:35:46 +02001210
1211 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
1212 max_reassembly_length=3,
1213 expire_walk_interval_ms=50, is_ip6=1)
1214
1215 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1216 IPv6(src=self.src_if.remote_ip6,
1217 dst=self.dst_if.remote_ip6) /
1218 UDP(sport=1234, dport=5678) /
Ole Troan127fbec2019-10-18 15:22:56 +02001219 Raw(b"X" * 1000))
Klement Sekera3a343d42019-05-16 14:35:46 +02001220 frags = fragment_rfc8200(p, 1, 300) + fragment_rfc8200(p, 2, 500)
1221
1222 self.pg_enable_capture()
1223 self.src_if.add_stream(frags)
1224 self.pg_start()
1225
1226 self.dst_if.get_capture(1)
Klement Sekera34641f22019-05-22 20:18:26 +02001227 self.assert_error_counter_equal(error_cnt_str, error_cnt + 1)
Klement Sekera3a343d42019-05-16 14:35:46 +02001228
Klement Sekera75e7d132017-09-20 08:26:30 +02001229 def test_overlap1(self):
Klement Sekera947a85c2019-07-24 12:40:37 +00001230 """ overlapping fragments case #1 """
Klement Sekera75e7d132017-09-20 08:26:30 +02001231
1232 fragments = []
1233 for _, frags_400, frags_300 in self.pkt_infos:
1234 if len(frags_300) == 1:
1235 fragments.extend(frags_400)
1236 else:
1237 for i, j in zip(frags_300, frags_400):
1238 fragments.extend(i)
1239 fragments.extend(j)
1240
1241 dropped_packet_indexes = set(
1242 index for (index, _, frags) in self.pkt_infos if len(frags) > 1
1243 )
1244
1245 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +01001246 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +02001247 self.pg_start()
1248
Klement Sekera4c533132018-02-22 11:41:12 +01001249 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +02001250 len(self.pkt_infos) - len(dropped_packet_indexes))
Klement Sekera947a85c2019-07-24 12:40:37 +00001251 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +01001252 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +02001253
1254 def test_overlap2(self):
Klement Sekera947a85c2019-07-24 12:40:37 +00001255 """ overlapping fragments case #2 """
Klement Sekera75e7d132017-09-20 08:26:30 +02001256
1257 fragments = []
Klement Sekera4c533132018-02-22 11:41:12 +01001258 for _, frags_400, frags_300 in self.pkt_infos:
Klement Sekera75e7d132017-09-20 08:26:30 +02001259 if len(frags_400) == 1:
1260 fragments.extend(frags_400)
1261 else:
1262 # care must be taken here so that there are no fragments
1263 # received by vpp after reassembly is finished, otherwise
1264 # new reassemblies will be started and packet generator will
1265 # freak out when it detects unfreed buffers
Klement Sekera4c533132018-02-22 11:41:12 +01001266 zipped = zip(frags_400, frags_300)
Paul Vinciguerrac7834e02019-03-02 10:43:05 -08001267 for i, j in zipped:
Klement Sekera75e7d132017-09-20 08:26:30 +02001268 fragments.extend(i)
1269 fragments.extend(j)
Paul Vinciguerrac7834e02019-03-02 10:43:05 -08001270 fragments.pop()
Klement Sekera75e7d132017-09-20 08:26:30 +02001271
1272 dropped_packet_indexes = set(
1273 index for (index, _, frags) in self.pkt_infos if len(frags) > 1
1274 )
1275
1276 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +01001277 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +02001278 self.pg_start()
1279
Klement Sekera4c533132018-02-22 11:41:12 +01001280 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +02001281 len(self.pkt_infos) - len(dropped_packet_indexes))
Klement Sekera947a85c2019-07-24 12:40:37 +00001282 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +01001283 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +02001284
Klement Sekera947a85c2019-07-24 12:40:37 +00001285 def test_timeout_inline(self):
Klement Sekera75e7d132017-09-20 08:26:30 +02001286 """ timeout (inline) """
1287
1288 dropped_packet_indexes = set(
1289 index for (index, frags, _) in self.pkt_infos if len(frags) > 1
1290 )
1291
Klement Sekera947a85c2019-07-24 12:40:37 +00001292 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
1293 max_reassembly_length=3,
1294 expire_walk_interval_ms=10000, is_ip6=1)
1295
1296 self.pg_enable_capture()
1297 self.src_if.add_stream(self.fragments_400)
1298 self.pg_start()
1299
1300 packets = self.dst_if.get_capture(
1301 len(self.pkt_infos) - len(dropped_packet_indexes))
1302 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +01001303 pkts = self.src_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +02001304 expected_count=len(dropped_packet_indexes))
1305 for icmp in pkts:
1306 self.assertIn(ICMPv6TimeExceeded, icmp)
1307 self.assertIn(IPv6ExtHdrFragment, icmp)
1308 self.assertIn(icmp[IPv6ExtHdrFragment].id, dropped_packet_indexes)
1309 dropped_packet_indexes.remove(icmp[IPv6ExtHdrFragment].id)
1310
1311 def test_timeout_cleanup(self):
1312 """ timeout (cleanup) """
1313
1314 # whole packets + fragmented packets sans last fragment
1315 fragments = [
1316 x for (_, frags_400, _) in self.pkt_infos
1317 for x in frags_400[:-1 if len(frags_400) > 1 else None]
1318 ]
1319
1320 # last fragments for fragmented packets
1321 fragments2 = [frags_400[-1]
1322 for (_, frags_400, _) in self.pkt_infos
1323 if len(frags_400) > 1]
1324
1325 dropped_packet_indexes = set(
1326 index for (index, frags_400, _) in self.pkt_infos
1327 if len(frags_400) > 1)
1328
1329 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +02001330 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +02001331 expire_walk_interval_ms=50)
1332
1333 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +02001334 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +02001335 expire_walk_interval_ms=50, is_ip6=1)
1336
1337 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +01001338 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +02001339 self.pg_start()
1340
BenoƮt Ganne56eccdb2021-08-20 09:18:31 +02001341 self.virtual_sleep(.25, "wait before sending rest of fragments")
Klement Sekera75e7d132017-09-20 08:26:30 +02001342
Klement Sekera4c533132018-02-22 11:41:12 +01001343 self.src_if.add_stream(fragments2)
Klement Sekera75e7d132017-09-20 08:26:30 +02001344 self.pg_start()
Klement Sekera75e7d132017-09-20 08:26:30 +02001345
Klement Sekera4c533132018-02-22 11:41:12 +01001346 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +02001347 len(self.pkt_infos) - len(dropped_packet_indexes))
Klement Sekera947a85c2019-07-24 12:40:37 +00001348 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +01001349 pkts = self.src_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +02001350 expected_count=len(dropped_packet_indexes))
1351 for icmp in pkts:
1352 self.assertIn(ICMPv6TimeExceeded, icmp)
1353 self.assertIn(IPv6ExtHdrFragment, icmp)
1354 self.assertIn(icmp[IPv6ExtHdrFragment].id, dropped_packet_indexes)
1355 dropped_packet_indexes.remove(icmp[IPv6ExtHdrFragment].id)
1356
Klement Sekera947a85c2019-07-24 12:40:37 +00001357 def test_disabled(self):
Klement Sekera75e7d132017-09-20 08:26:30 +02001358 """ reassembly disabled """
1359
1360 dropped_packet_indexes = set(
1361 index for (index, frags_400, _) in self.pkt_infos
1362 if len(frags_400) > 1)
Klement Sekera947a85c2019-07-24 12:40:37 +00001363
1364 self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=0,
1365 max_reassembly_length=3,
1366 expire_walk_interval_ms=10000, is_ip6=1)
1367
1368 self.pg_enable_capture()
1369 self.src_if.add_stream(self.fragments_400)
1370 self.pg_start()
1371
1372 packets = self.dst_if.get_capture(
1373 len(self.pkt_infos) - len(dropped_packet_indexes))
1374 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +01001375 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +02001376
1377 def test_missing_upper(self):
1378 """ missing upper layer """
Ole Troan03092c12021-11-23 15:55:39 +01001379 optdata = '\x00' * 100
Klement Sekera4c533132018-02-22 11:41:12 +01001380 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1381 IPv6(src=self.src_if.remote_ip6,
1382 dst=self.src_if.local_ip6) /
Ole Troan03092c12021-11-23 15:55:39 +01001383 IPv6ExtHdrFragment(m=1) /
1384 IPv6ExtHdrDestOpt(nh=17, options=PadN(optdata='\101' * 255) /
1385 PadN(optdata='\102'*255)))
1386
Klement Sekera75e7d132017-09-20 08:26:30 +02001387 self.pg_enable_capture()
Ole Troan03092c12021-11-23 15:55:39 +01001388 self.src_if.add_stream([p])
Klement Sekera75e7d132017-09-20 08:26:30 +02001389 self.pg_start()
Klement Sekera4c533132018-02-22 11:41:12 +01001390 pkts = self.src_if.get_capture(expected_count=1)
Klement Sekera75e7d132017-09-20 08:26:30 +02001391 icmp = pkts[0]
1392 self.assertIn(ICMPv6ParamProblem, icmp)
1393 self.assert_equal(icmp[ICMPv6ParamProblem].code, 3, "ICMP code")
1394
Klement Sekera755042d2021-12-01 10:14:38 +00001395 def test_truncated_fragment(self):
1396 """ truncated fragment """
1397 pkt = (Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac) /
1398 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6,
1399 nh=44, plen=2) /
1400 IPv6ExtHdrFragment(nh=6))
1401
1402 self.send_and_assert_no_replies(self.pg0, [pkt], self.pg0)
1403
Klement Sekera75e7d132017-09-20 08:26:30 +02001404 def test_invalid_frag_size(self):
1405 """ fragment size not a multiple of 8 """
Klement Sekera4c533132018-02-22 11:41:12 +01001406 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1407 IPv6(src=self.src_if.remote_ip6,
1408 dst=self.src_if.local_ip6) /
1409 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +02001410 Raw())
1411 self.extend_packet(p, 1000, self.padding)
1412 fragments = fragment_rfc8200(p, 1, 500)
1413 bad_fragment = fragments[0]
1414 self.extend_packet(bad_fragment, len(bad_fragment) + 5)
1415 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +01001416 self.src_if.add_stream([bad_fragment])
Klement Sekera75e7d132017-09-20 08:26:30 +02001417 self.pg_start()
Klement Sekera4c533132018-02-22 11:41:12 +01001418 pkts = self.src_if.get_capture(expected_count=1)
Klement Sekera75e7d132017-09-20 08:26:30 +02001419 icmp = pkts[0]
1420 self.assertIn(ICMPv6ParamProblem, icmp)
1421 self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code")
1422
1423 def test_invalid_packet_size(self):
1424 """ total packet size > 65535 """
Klement Sekera4c533132018-02-22 11:41:12 +01001425 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1426 IPv6(src=self.src_if.remote_ip6,
1427 dst=self.src_if.local_ip6) /
1428 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +02001429 Raw())
1430 self.extend_packet(p, 1000, self.padding)
1431 fragments = fragment_rfc8200(p, 1, 500)
1432 bad_fragment = fragments[1]
1433 bad_fragment[IPv6ExtHdrFragment].offset = 65500
1434 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +01001435 self.src_if.add_stream([bad_fragment])
Klement Sekera75e7d132017-09-20 08:26:30 +02001436 self.pg_start()
Klement Sekera4c533132018-02-22 11:41:12 +01001437 pkts = self.src_if.get_capture(expected_count=1)
Klement Sekera75e7d132017-09-20 08:26:30 +02001438 icmp = pkts[0]
1439 self.assertIn(ICMPv6ParamProblem, icmp)
1440 self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code")
1441
Ole Troan03092c12021-11-23 15:55:39 +01001442 def test_atomic_fragment(self):
1443 """ IPv6 atomic fragment """
1444 pkt = (Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac) /
1445 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6,
1446 nh=44, plen=65535) /
1447 IPv6ExtHdrFragment(offset=8191, m=1, res1=0xFF, res2=0xFF,
1448 nh=255, id=0xffff)/('X'*1452))
1449
1450 rx = self.send_and_expect(self.pg0, [pkt], self.pg0)
1451 self.assertIn(ICMPv6ParamProblem, rx[0])
1452
1453 def test_truncated_fragment(self):
1454 """ IPv6 truncated fragment header """
1455 pkt = (Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac) /
1456 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6,
1457 nh=44, plen=2) /
1458 IPv6ExtHdrFragment(nh=6))
1459
Klement Sekera7c3275e2021-12-07 09:49:53 +00001460 self.send_and_assert_no_replies(self.pg0, [pkt])
Ole Troan03092c12021-11-23 15:55:39 +01001461
1462 pkt = (Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac) /
1463 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.remote_ip6) /
1464 ICMPv6EchoRequest())
1465 rx = self.send_and_expect(self.pg0, [pkt], self.pg0)
1466
Klement Sekera7c3275e2021-12-07 09:49:53 +00001467 def test_one_fragment(self):
1468 """ whole packet in one fragment processed independently """
1469 pkt = (Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac) /
1470 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
1471 ICMPv6EchoRequest()/Raw('X' * 1600))
1472 frags = fragment_rfc8200(pkt, 1, 400)
1473
1474 # send a fragment with known id
1475 self.send_and_assert_no_replies(self.pg0, [frags[0]])
1476
1477 # send an atomic fragment with same id - should be reassembled
1478 pkt = (Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac) /
1479 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
1480 IPv6ExtHdrFragment(id=1)/ICMPv6EchoRequest())
1481 rx = self.send_and_expect(self.pg0, [pkt], self.pg0)
1482 self.assertNotIn(IPv6ExtHdrFragment, rx)
1483
1484 # now finish the original reassembly, this should still be possible
1485 rx = self.send_and_expect(self.pg0, frags[1:], self.pg0, n_rx=1)
1486 self.assertNotIn(IPv6ExtHdrFragment, rx)
1487
1488 def test_bunch_of_fragments(self):
1489 """ valid fragments followed by rogue fragments and atomic fragment"""
1490 pkt = (Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac) /
1491 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
1492 ICMPv6EchoRequest()/Raw('X' * 1600))
1493 frags = fragment_rfc8200(pkt, 1, 400)
1494 self.send_and_expect(self.pg0, frags, self.pg0, n_rx=1)
1495
1496 inc_frag = (Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac) /
1497 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
1498 IPv6ExtHdrFragment(id=1, nh=58, offset=608)/Raw('X'*308))
1499
1500 self.send_and_assert_no_replies(self.pg0, inc_frag*604)
1501
1502 pkt = (Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac) /
1503 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
1504 IPv6ExtHdrFragment(id=1)/ICMPv6EchoRequest())
1505 rx = self.send_and_expect(self.pg0, [pkt], self.pg0)
1506 self.assertNotIn(IPv6ExtHdrFragment, rx)
1507
Klement Sekera75e7d132017-09-20 08:26:30 +02001508
Klement Sekera630ab582019-07-19 09:14:19 +00001509class TestIPv6MWReassembly(VppTestCase):
1510 """ IPv6 Reassembly (multiple workers) """
Klement Sekera8d815022021-03-15 16:58:10 +01001511 vpp_worker_count = 3
Klement Sekera630ab582019-07-19 09:14:19 +00001512
1513 @classmethod
1514 def setUpClass(cls):
1515 super(TestIPv6MWReassembly, cls).setUpClass()
1516
Klement Sekera8d815022021-03-15 16:58:10 +01001517 cls.create_pg_interfaces(range(cls.vpp_worker_count+1))
Klement Sekera630ab582019-07-19 09:14:19 +00001518 cls.src_if = cls.pg0
1519 cls.send_ifs = cls.pg_interfaces[:-1]
1520 cls.dst_if = cls.pg_interfaces[-1]
1521
1522 # setup all interfaces
1523 for i in cls.pg_interfaces:
1524 i.admin_up()
1525 i.config_ip6()
1526 i.resolve_ndp()
1527
1528 # packets sizes reduced here because we are generating packets without
1529 # Ethernet headers, which are added later (diff fragments go via
1530 # different interfaces)
1531 cls.packet_sizes = [64-len(Ether()), 512-len(Ether()),
1532 1518-len(Ether()), 9018-len(Ether())]
1533 cls.padding = " abcdefghijklmn"
1534 cls.create_stream(cls.packet_sizes)
1535 cls.create_fragments()
1536
1537 @classmethod
1538 def tearDownClass(cls):
1539 super(TestIPv6MWReassembly, cls).tearDownClass()
1540
1541 def setUp(self):
1542 """ Test setup - force timeout on existing reassemblies """
1543 super(TestIPv6MWReassembly, self).setUp()
1544 for intf in self.send_ifs:
1545 self.vapi.ip_reassembly_enable_disable(
1546 sw_if_index=intf.sw_if_index, enable_ip6=True)
1547 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
1548 max_reassembly_length=1000,
1549 expire_walk_interval_ms=10, is_ip6=1)
BenoƮt Ganne56eccdb2021-08-20 09:18:31 +02001550 self.virtual_sleep(.25)
Klement Sekera630ab582019-07-19 09:14:19 +00001551 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
1552 max_reassembly_length=1000,
1553 expire_walk_interval_ms=1000, is_ip6=1)
1554
1555 def tearDown(self):
1556 super(TestIPv6MWReassembly, self).tearDown()
1557
1558 def show_commands_at_teardown(self):
Klement Sekera896c8962019-06-24 11:52:49 +00001559 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
Klement Sekera630ab582019-07-19 09:14:19 +00001560 self.logger.debug(self.vapi.ppcli("show buffers"))
1561
1562 @classmethod
1563 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
1564 """Create input packet stream
1565
1566 :param list packet_sizes: Required packet sizes.
1567 """
1568 for i in range(0, packet_count):
1569 info = cls.create_packet_info(cls.src_if, cls.src_if)
1570 payload = cls.info_to_payload(info)
1571 p = (IPv6(src=cls.src_if.remote_ip6,
1572 dst=cls.dst_if.remote_ip6) /
1573 UDP(sport=1234, dport=5678) /
1574 Raw(payload))
1575 size = packet_sizes[(i // 2) % len(packet_sizes)]
1576 cls.extend_packet(p, size, cls.padding)
1577 info.data = p
1578
1579 @classmethod
1580 def create_fragments(cls):
1581 infos = cls._packet_infos
1582 cls.pkt_infos = []
Paul Vinciguerra090096b2020-12-03 00:42:46 -05001583 for index, info in infos.items():
Klement Sekera630ab582019-07-19 09:14:19 +00001584 p = info.data
1585 # cls.logger.debug(ppp("Packet:",
1586 # p.__class__(scapy.compat.raw(p))))
1587 fragments_400 = fragment_rfc8200(p, index, 400)
1588 cls.pkt_infos.append((index, fragments_400))
1589 cls.fragments_400 = [
1590 x for (_, frags) in cls.pkt_infos for x in frags]
1591 cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, " %
1592 (len(infos), len(cls.fragments_400)))
1593
1594 def verify_capture(self, capture, dropped_packet_indexes=[]):
1595 """Verify captured packet strea .
1596
1597 :param list capture: Captured packet stream.
1598 """
1599 info = None
1600 seen = set()
1601 for packet in capture:
1602 try:
1603 self.logger.debug(ppp("Got packet:", packet))
1604 ip = packet[IPv6]
1605 udp = packet[UDP]
1606 payload_info = self.payload_to_info(packet[Raw])
1607 packet_index = payload_info.index
1608 self.assertTrue(
1609 packet_index not in dropped_packet_indexes,
1610 ppp("Packet received, but should be dropped:", packet))
1611 if packet_index in seen:
1612 raise Exception(ppp("Duplicate packet received", packet))
1613 seen.add(packet_index)
1614 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
1615 info = self._packet_infos[packet_index]
1616 self.assertTrue(info is not None)
1617 self.assertEqual(packet_index, info.index)
1618 saved_packet = info.data
1619 self.assertEqual(ip.src, saved_packet[IPv6].src)
1620 self.assertEqual(ip.dst, saved_packet[IPv6].dst)
1621 self.assertEqual(udp.payload, saved_packet[UDP].payload)
1622 except Exception:
1623 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1624 raise
1625 for index in self._packet_infos:
1626 self.assertTrue(index in seen or index in dropped_packet_indexes,
1627 "Packet with packet_index %d not received" % index)
1628
1629 def send_packets(self, packets):
Klement Sekera8d815022021-03-15 16:58:10 +01001630 for counter in range(self.vpp_worker_count):
Klement Sekera630ab582019-07-19 09:14:19 +00001631 if 0 == len(packets[counter]):
1632 continue
1633 send_if = self.send_ifs[counter]
1634 send_if.add_stream(
1635 (Ether(dst=send_if.local_mac, src=send_if.remote_mac) / x
1636 for x in packets[counter]),
1637 worker=counter)
1638 self.pg_start()
1639
1640 def test_worker_conflict(self):
1641 """ 1st and FO=0 fragments on different workers """
1642
1643 # in first wave we send fragments which don't start at offset 0
1644 # then we send fragments with offset 0 on a different thread
1645 # then the rest of packets on a random thread
Klement Sekera8d815022021-03-15 16:58:10 +01001646 first_packets = [[] for n in range(self.vpp_worker_count)]
1647 second_packets = [[] for n in range(self.vpp_worker_count)]
1648 rest_of_packets = [[] for n in range(self.vpp_worker_count)]
Klement Sekera630ab582019-07-19 09:14:19 +00001649 for (_, p) in self.pkt_infos:
Klement Sekera8d815022021-03-15 16:58:10 +01001650 wi = randrange(self.vpp_worker_count)
Klement Sekera630ab582019-07-19 09:14:19 +00001651 second_packets[wi].append(p[0])
1652 if len(p) <= 1:
1653 continue
1654 wi2 = wi
1655 while wi2 == wi:
Klement Sekera8d815022021-03-15 16:58:10 +01001656 wi2 = randrange(self.vpp_worker_count)
Klement Sekera630ab582019-07-19 09:14:19 +00001657 first_packets[wi2].append(p[1])
Klement Sekera8d815022021-03-15 16:58:10 +01001658 wi3 = randrange(self.vpp_worker_count)
Klement Sekera630ab582019-07-19 09:14:19 +00001659 rest_of_packets[wi3].extend(p[2:])
1660
1661 self.pg_enable_capture()
1662 self.send_packets(first_packets)
1663 self.send_packets(second_packets)
1664 self.send_packets(rest_of_packets)
1665
1666 packets = self.dst_if.get_capture(len(self.pkt_infos))
1667 self.verify_capture(packets)
1668 for send_if in self.send_ifs:
1669 send_if.assert_nothing_captured()
1670
Klement Sekera68bae5b2019-10-10 18:57:34 +00001671 self.logger.debug(self.vapi.ppcli("show trace"))
1672 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
1673 self.logger.debug(self.vapi.ppcli("show buffers"))
1674 self.vapi.cli("clear trace")
1675
Klement Sekera630ab582019-07-19 09:14:19 +00001676 self.pg_enable_capture()
1677 self.send_packets(first_packets)
1678 self.send_packets(second_packets)
1679 self.send_packets(rest_of_packets)
1680
1681 packets = self.dst_if.get_capture(len(self.pkt_infos))
1682 self.verify_capture(packets)
1683 for send_if in self.send_ifs:
1684 send_if.assert_nothing_captured()
1685
1686
Klement Sekerade34c352019-06-25 11:19:22 +00001687class TestIPv6SVReassembly(VppTestCase):
1688 """ IPv6 Shallow Virtual Reassembly """
1689
1690 @classmethod
1691 def setUpClass(cls):
1692 super(TestIPv6SVReassembly, cls).setUpClass()
1693
1694 cls.create_pg_interfaces([0, 1])
1695 cls.src_if = cls.pg0
1696 cls.dst_if = cls.pg1
1697
1698 # setup all interfaces
1699 for i in cls.pg_interfaces:
1700 i.admin_up()
1701 i.config_ip6()
1702 i.resolve_ndp()
1703
1704 def setUp(self):
1705 """ Test setup - force timeout on existing reassemblies """
1706 super(TestIPv6SVReassembly, self).setUp()
1707 self.vapi.ip_reassembly_enable_disable(
1708 sw_if_index=self.src_if.sw_if_index, enable_ip6=True,
1709 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL)
1710 self.vapi.ip_reassembly_set(
1711 timeout_ms=0, max_reassemblies=1000,
1712 max_reassembly_length=1000,
1713 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
1714 expire_walk_interval_ms=10, is_ip6=1)
BenoƮt Ganne56eccdb2021-08-20 09:18:31 +02001715 self.virtual_sleep(.25)
Klement Sekerade34c352019-06-25 11:19:22 +00001716 self.vapi.ip_reassembly_set(
1717 timeout_ms=1000000, max_reassemblies=1000,
1718 max_reassembly_length=1000,
1719 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
1720 expire_walk_interval_ms=10000, is_ip6=1)
1721
1722 def tearDown(self):
1723 super(TestIPv6SVReassembly, self).tearDown()
1724 self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details"))
1725 self.logger.debug(self.vapi.ppcli("show buffers"))
1726
1727 def test_basic(self):
1728 """ basic reassembly """
1729 payload_len = 1000
1730 payload = ""
1731 counter = 0
1732 while len(payload) < payload_len:
1733 payload += "%u " % counter
1734 counter += 1
1735
1736 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1737 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1738 UDP(sport=1234, dport=5678) /
1739 Raw(payload))
1740 fragments = fragment_rfc8200(p, 1, payload_len/4)
1741
1742 # send fragment #2 - should be cached inside reassembly
1743 self.pg_enable_capture()
1744 self.src_if.add_stream(fragments[1])
1745 self.pg_start()
1746 self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details"))
1747 self.logger.debug(self.vapi.ppcli("show buffers"))
1748 self.logger.debug(self.vapi.ppcli("show trace"))
1749 self.dst_if.assert_nothing_captured()
1750
1751 # send fragment #1 - reassembly is finished now and both fragments
1752 # forwarded
1753 self.pg_enable_capture()
1754 self.src_if.add_stream(fragments[0])
1755 self.pg_start()
1756 self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details"))
1757 self.logger.debug(self.vapi.ppcli("show buffers"))
1758 self.logger.debug(self.vapi.ppcli("show trace"))
1759 c = self.dst_if.get_capture(2)
1760 for sent, recvd in zip([fragments[1], fragments[0]], c):
1761 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
1762 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
1763 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
1764
1765 # send rest of fragments - should be immediately forwarded
1766 self.pg_enable_capture()
1767 self.src_if.add_stream(fragments[2:])
1768 self.pg_start()
1769 c = self.dst_if.get_capture(len(fragments[2:]))
1770 for sent, recvd in zip(fragments[2:], c):
1771 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
1772 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
1773 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
1774
Klement Sekera53be16d2020-12-15 21:47:36 +01001775 def test_verify_clear_trace_mid_reassembly(self):
1776 """ verify clear trace works mid-reassembly """
1777 payload_len = 1000
1778 payload = ""
1779 counter = 0
1780 while len(payload) < payload_len:
1781 payload += "%u " % counter
1782 counter += 1
1783
1784 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1785 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1786 UDP(sport=1234, dport=5678) /
1787 Raw(payload))
1788 fragments = fragment_rfc8200(p, 1, payload_len/4)
1789
1790 self.pg_enable_capture()
1791 self.src_if.add_stream(fragments[1])
1792 self.pg_start()
1793
1794 self.logger.debug(self.vapi.cli("show trace"))
1795 self.vapi.cli("clear trace")
1796
1797 self.pg_enable_capture()
1798 self.src_if.add_stream(fragments[0])
1799 self.pg_start()
1800 self.dst_if.get_capture(2)
1801
1802 self.logger.debug(self.vapi.cli("show trace"))
1803 self.vapi.cli("clear trace")
1804
1805 self.pg_enable_capture()
1806 self.src_if.add_stream(fragments[2:])
1807 self.pg_start()
1808 self.dst_if.get_capture(len(fragments[2:]))
1809
Klement Sekerade34c352019-06-25 11:19:22 +00001810 def test_timeout(self):
1811 """ reassembly timeout """
1812 payload_len = 1000
1813 payload = ""
1814 counter = 0
1815 while len(payload) < payload_len:
1816 payload += "%u " % counter
1817 counter += 1
1818
1819 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1820 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1821 UDP(sport=1234, dport=5678) /
1822 Raw(payload))
1823 fragments = fragment_rfc8200(p, 1, payload_len/4)
1824
1825 self.vapi.ip_reassembly_set(
1826 timeout_ms=100, max_reassemblies=1000,
1827 max_reassembly_length=1000,
1828 expire_walk_interval_ms=50,
1829 is_ip6=1,
1830 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL)
1831
1832 # send fragments #2 and #1 - should be forwarded
1833 self.pg_enable_capture()
1834 self.src_if.add_stream(fragments[0:2])
1835 self.pg_start()
1836 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
1837 self.logger.debug(self.vapi.ppcli("show buffers"))
1838 self.logger.debug(self.vapi.ppcli("show trace"))
1839 c = self.dst_if.get_capture(2)
1840 for sent, recvd in zip([fragments[1], fragments[0]], c):
1841 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
1842 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
1843 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
1844
1845 # wait for cleanup
BenoƮt Ganne56eccdb2021-08-20 09:18:31 +02001846 self.virtual_sleep(.25, "wait before sending rest of fragments")
Klement Sekerade34c352019-06-25 11:19:22 +00001847
1848 # send rest of fragments - shouldn't be forwarded
1849 self.pg_enable_capture()
1850 self.src_if.add_stream(fragments[2:])
1851 self.pg_start()
1852 self.dst_if.assert_nothing_captured()
1853
1854 def test_lru(self):
1855 """ reassembly reuses LRU element """
1856
1857 self.vapi.ip_reassembly_set(
1858 timeout_ms=1000000, max_reassemblies=1,
1859 max_reassembly_length=1000,
1860 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
1861 is_ip6=1, expire_walk_interval_ms=10000)
1862
1863 payload_len = 1000
1864 payload = ""
1865 counter = 0
1866 while len(payload) < payload_len:
1867 payload += "%u " % counter
1868 counter += 1
1869
1870 packet_count = 10
1871
1872 fragments = [f
1873 for i in range(packet_count)
1874 for p in (Ether(dst=self.src_if.local_mac,
1875 src=self.src_if.remote_mac) /
1876 IPv6(src=self.src_if.remote_ip6,
1877 dst=self.dst_if.remote_ip6) /
1878 UDP(sport=1234, dport=5678) /
1879 Raw(payload))
1880 for f in fragment_rfc8200(p, i, payload_len/4)]
1881
1882 self.pg_enable_capture()
1883 self.src_if.add_stream(fragments)
1884 self.pg_start()
1885 c = self.dst_if.get_capture(len(fragments))
1886 for sent, recvd in zip(fragments, c):
1887 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
1888 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
1889 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
1890
Klement Sekera7c3275e2021-12-07 09:49:53 +00001891 def test_one_fragment(self):
1892 """ whole packet in one fragment processed independently """
1893 pkt = (Ether(src=self.src_if.local_mac, dst=self.src_if.remote_mac) /
1894 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1895 ICMPv6EchoRequest()/Raw('X' * 1600))
1896 frags = fragment_rfc8200(pkt, 1, 400)
1897
1898 # send a fragment with known id
1899 self.send_and_expect(self.src_if, [frags[0]], self.dst_if)
1900
1901 # send an atomic fragment with same id - should be reassembled
1902 pkt = (Ether(src=self.src_if.local_mac, dst=self.src_if.remote_mac) /
1903 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1904 IPv6ExtHdrFragment(id=1)/ICMPv6EchoRequest())
1905 rx = self.send_and_expect(self.src_if, [pkt], self.dst_if)
1906
1907 # now forward packets matching original reassembly, should still work
1908 rx = self.send_and_expect(self.src_if, frags[1:], self.dst_if)
1909
1910 def test_bunch_of_fragments(self):
1911 """ valid fragments followed by rogue fragments and atomic fragment"""
1912 pkt = (Ether(src=self.src_if.local_mac, dst=self.src_if.remote_mac) /
1913 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1914 ICMPv6EchoRequest()/Raw('X' * 1600))
1915 frags = fragment_rfc8200(pkt, 1, 400)
1916 rx = self.send_and_expect(self.src_if, frags, self.dst_if)
1917
1918 rogue = (Ether(src=self.src_if.local_mac, dst=self.src_if.remote_mac) /
1919 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1920 IPv6ExtHdrFragment(id=1, nh=58, offset=608)/Raw('X'*308))
1921
1922 self.send_and_expect(self.src_if, rogue*604, self.dst_if)
1923
1924 pkt = (Ether(src=self.src_if.local_mac, dst=self.src_if.remote_mac) /
1925 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1926 IPv6ExtHdrFragment(id=1)/ICMPv6EchoRequest())
1927 rx = self.send_and_expect(self.src_if, [pkt], self.dst_if)
1928
Klement Sekera755042d2021-12-01 10:14:38 +00001929 def test_truncated_fragment(self):
1930 """ truncated fragment """
1931 pkt = (Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac) /
1932 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6,
1933 nh=44, plen=2) /
1934 IPv6ExtHdrFragment(nh=6))
1935
1936 self.send_and_assert_no_replies(self.pg0, [pkt], self.pg0)
1937
Klement Sekerade34c352019-06-25 11:19:22 +00001938
Juraj Sloboda3048b632018-10-02 11:13:53 +02001939class TestIPv4ReassemblyLocalNode(VppTestCase):
1940 """ IPv4 Reassembly for packets coming to ip4-local node """
1941
1942 @classmethod
1943 def setUpClass(cls):
1944 super(TestIPv4ReassemblyLocalNode, cls).setUpClass()
1945
1946 cls.create_pg_interfaces([0])
1947 cls.src_dst_if = cls.pg0
1948
1949 # setup all interfaces
1950 for i in cls.pg_interfaces:
1951 i.admin_up()
1952 i.config_ip4()
1953 i.resolve_arp()
1954
1955 cls.padding = " abcdefghijklmn"
1956 cls.create_stream()
1957 cls.create_fragments()
1958
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07001959 @classmethod
1960 def tearDownClass(cls):
1961 super(TestIPv4ReassemblyLocalNode, cls).tearDownClass()
1962
Juraj Sloboda3048b632018-10-02 11:13:53 +02001963 def setUp(self):
1964 """ Test setup - force timeout on existing reassemblies """
1965 super(TestIPv4ReassemblyLocalNode, self).setUp()
1966 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +02001967 max_reassembly_length=1000,
Juraj Sloboda3048b632018-10-02 11:13:53 +02001968 expire_walk_interval_ms=10)
BenoƮt Ganne56eccdb2021-08-20 09:18:31 +02001969 self.virtual_sleep(.25)
Juraj Sloboda3048b632018-10-02 11:13:53 +02001970 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +02001971 max_reassembly_length=1000,
Juraj Sloboda3048b632018-10-02 11:13:53 +02001972 expire_walk_interval_ms=10000)
1973
1974 def tearDown(self):
1975 super(TestIPv4ReassemblyLocalNode, self).tearDown()
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -07001976
1977 def show_commands_at_teardown(self):
Klement Sekera896c8962019-06-24 11:52:49 +00001978 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
Klement Sekeracae98b72019-02-19 13:53:43 +01001979 self.logger.debug(self.vapi.ppcli("show buffers"))
Juraj Sloboda3048b632018-10-02 11:13:53 +02001980
1981 @classmethod
1982 def create_stream(cls, packet_count=test_packet_count):
1983 """Create input packet stream for defined interface.
1984
1985 :param list packet_sizes: Required packet sizes.
1986 """
1987 for i in range(0, packet_count):
1988 info = cls.create_packet_info(cls.src_dst_if, cls.src_dst_if)
1989 payload = cls.info_to_payload(info)
1990 p = (Ether(dst=cls.src_dst_if.local_mac,
1991 src=cls.src_dst_if.remote_mac) /
1992 IP(id=info.index, src=cls.src_dst_if.remote_ip4,
1993 dst=cls.src_dst_if.local_ip4) /
1994 ICMP(type='echo-request', id=1234) /
1995 Raw(payload))
1996 cls.extend_packet(p, 1518, cls.padding)
1997 info.data = p
1998
1999 @classmethod
2000 def create_fragments(cls):
2001 infos = cls._packet_infos
2002 cls.pkt_infos = []
Paul Vinciguerra090096b2020-12-03 00:42:46 -05002003 for index, info in infos.items():
Juraj Sloboda3048b632018-10-02 11:13:53 +02002004 p = info.data
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07002005 # cls.logger.debug(ppp("Packet:",
2006 # p.__class__(scapy.compat.raw(p))))
Juraj Sloboda3048b632018-10-02 11:13:53 +02002007 fragments_300 = fragment_rfc791(p, 300)
2008 cls.pkt_infos.append((index, fragments_300))
2009 cls.fragments_300 = [x for (_, frags) in cls.pkt_infos for x in frags]
2010 cls.logger.debug("Fragmented %s packets into %s 300-byte fragments" %
2011 (len(infos), len(cls.fragments_300)))
2012
2013 def verify_capture(self, capture):
2014 """Verify captured packet stream.
2015
2016 :param list capture: Captured packet stream.
2017 """
2018 info = None
2019 seen = set()
2020 for packet in capture:
2021 try:
2022 self.logger.debug(ppp("Got packet:", packet))
2023 ip = packet[IP]
2024 icmp = packet[ICMP]
Paul Vinciguerraeaea4212019-03-06 11:58:06 -08002025 payload_info = self.payload_to_info(packet[Raw])
Juraj Sloboda3048b632018-10-02 11:13:53 +02002026 packet_index = payload_info.index
2027 if packet_index in seen:
2028 raise Exception(ppp("Duplicate packet received", packet))
2029 seen.add(packet_index)
2030 self.assertEqual(payload_info.dst, self.src_dst_if.sw_if_index)
2031 info = self._packet_infos[packet_index]
Klement Sekera14d7e902018-12-10 13:46:09 +01002032 self.assertIsNotNone(info)
Juraj Sloboda3048b632018-10-02 11:13:53 +02002033 self.assertEqual(packet_index, info.index)
2034 saved_packet = info.data
2035 self.assertEqual(ip.src, saved_packet[IP].dst)
2036 self.assertEqual(ip.dst, saved_packet[IP].src)
2037 self.assertEqual(icmp.type, 0) # echo reply
2038 self.assertEqual(icmp.id, saved_packet[ICMP].id)
2039 self.assertEqual(icmp.payload, saved_packet[ICMP].payload)
2040 except Exception:
2041 self.logger.error(ppp("Unexpected or invalid packet:", packet))
2042 raise
2043 for index in self._packet_infos:
Klement Sekera14d7e902018-12-10 13:46:09 +01002044 self.assertIn(index, seen,
2045 "Packet with packet_index %d not received" % index)
Juraj Sloboda3048b632018-10-02 11:13:53 +02002046
2047 def test_reassembly(self):
2048 """ basic reassembly """
2049
2050 self.pg_enable_capture()
2051 self.src_dst_if.add_stream(self.fragments_300)
2052 self.pg_start()
2053
2054 packets = self.src_dst_if.get_capture(len(self.pkt_infos))
2055 self.verify_capture(packets)
2056
2057 # run it all again to verify correctness
2058 self.pg_enable_capture()
2059 self.src_dst_if.add_stream(self.fragments_300)
2060 self.pg_start()
2061
2062 packets = self.src_dst_if.get_capture(len(self.pkt_infos))
2063 self.verify_capture(packets)
2064
2065
Klement Sekera75e7d132017-09-20 08:26:30 +02002066class TestFIFReassembly(VppTestCase):
2067 """ Fragments in fragments reassembly """
2068
2069 @classmethod
2070 def setUpClass(cls):
2071 super(TestFIFReassembly, cls).setUpClass()
2072
Klement Sekera4c533132018-02-22 11:41:12 +01002073 cls.create_pg_interfaces([0, 1])
2074 cls.src_if = cls.pg0
2075 cls.dst_if = cls.pg1
2076 for i in cls.pg_interfaces:
2077 i.admin_up()
2078 i.config_ip4()
2079 i.resolve_arp()
2080 i.config_ip6()
2081 i.resolve_ndp()
Klement Sekera75e7d132017-09-20 08:26:30 +02002082
Klement Sekera75e7d132017-09-20 08:26:30 +02002083 cls.packet_sizes = [64, 512, 1518, 9018]
2084 cls.padding = " abcdefghijklmn"
2085
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07002086 @classmethod
2087 def tearDownClass(cls):
2088 super(TestFIFReassembly, cls).tearDownClass()
2089
Klement Sekera75e7d132017-09-20 08:26:30 +02002090 def setUp(self):
2091 """ Test setup - force timeout on existing reassemblies """
2092 super(TestFIFReassembly, self).setUp()
Klement Sekera4c533132018-02-22 11:41:12 +01002093 self.vapi.ip_reassembly_enable_disable(
2094 sw_if_index=self.src_if.sw_if_index, enable_ip4=True,
2095 enable_ip6=True)
2096 self.vapi.ip_reassembly_enable_disable(
2097 sw_if_index=self.dst_if.sw_if_index, enable_ip4=True,
2098 enable_ip6=True)
Klement Sekera75e7d132017-09-20 08:26:30 +02002099 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +02002100 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +02002101 expire_walk_interval_ms=10)
2102 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +02002103 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +02002104 expire_walk_interval_ms=10, is_ip6=1)
BenoƮt Ganne56eccdb2021-08-20 09:18:31 +02002105 self.virtual_sleep(.25)
Klement Sekera75e7d132017-09-20 08:26:30 +02002106 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +02002107 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +02002108 expire_walk_interval_ms=10000)
2109 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +02002110 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +02002111 expire_walk_interval_ms=10000, is_ip6=1)
2112
2113 def tearDown(self):
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -07002114 super(TestFIFReassembly, self).tearDown()
2115
2116 def show_commands_at_teardown(self):
Klement Sekera896c8962019-06-24 11:52:49 +00002117 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
2118 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
Klement Sekeracae98b72019-02-19 13:53:43 +01002119 self.logger.debug(self.vapi.ppcli("show buffers"))
Klement Sekera75e7d132017-09-20 08:26:30 +02002120
2121 def verify_capture(self, capture, ip_class, dropped_packet_indexes=[]):
2122 """Verify captured packet stream.
2123
2124 :param list capture: Captured packet stream.
2125 """
2126 info = None
2127 seen = set()
2128 for packet in capture:
2129 try:
Klement Sekera4c533132018-02-22 11:41:12 +01002130 self.logger.debug(ppp("Got packet:", packet))
Klement Sekera75e7d132017-09-20 08:26:30 +02002131 ip = packet[ip_class]
2132 udp = packet[UDP]
Paul Vinciguerraeaea4212019-03-06 11:58:06 -08002133 payload_info = self.payload_to_info(packet[Raw])
Klement Sekera75e7d132017-09-20 08:26:30 +02002134 packet_index = payload_info.index
2135 self.assertTrue(
2136 packet_index not in dropped_packet_indexes,
2137 ppp("Packet received, but should be dropped:", packet))
2138 if packet_index in seen:
2139 raise Exception(ppp("Duplicate packet received", packet))
2140 seen.add(packet_index)
Klement Sekera4c533132018-02-22 11:41:12 +01002141 self.assertEqual(payload_info.dst, self.dst_if.sw_if_index)
Klement Sekera75e7d132017-09-20 08:26:30 +02002142 info = self._packet_infos[packet_index]
2143 self.assertTrue(info is not None)
2144 self.assertEqual(packet_index, info.index)
2145 saved_packet = info.data
2146 self.assertEqual(ip.src, saved_packet[ip_class].src)
2147 self.assertEqual(ip.dst, saved_packet[ip_class].dst)
2148 self.assertEqual(udp.payload, saved_packet[UDP].payload)
Klement Sekera4c533132018-02-22 11:41:12 +01002149 except Exception:
Klement Sekera75e7d132017-09-20 08:26:30 +02002150 self.logger.error(ppp("Unexpected or invalid packet:", packet))
2151 raise
2152 for index in self._packet_infos:
2153 self.assertTrue(index in seen or index in dropped_packet_indexes,
2154 "Packet with packet_index %d not received" % index)
2155
2156 def test_fif4(self):
2157 """ Fragments in fragments (4o4) """
2158
2159 # TODO this should be ideally in setUpClass, but then we hit a bug
2160 # with VppIpRoute incorrectly reporting it's present when it's not
2161 # so we need to manually remove the vpp config, thus we cannot have
2162 # it shared for multiple test cases
2163 self.tun_ip4 = "1.1.1.2"
2164
Klement Sekera4c533132018-02-22 11:41:12 +01002165 self.gre4 = VppGreInterface(self, self.src_if.local_ip4, self.tun_ip4)
Klement Sekera75e7d132017-09-20 08:26:30 +02002166 self.gre4.add_vpp_config()
2167 self.gre4.admin_up()
2168 self.gre4.config_ip4()
2169
Klement Sekera4c533132018-02-22 11:41:12 +01002170 self.vapi.ip_reassembly_enable_disable(
2171 sw_if_index=self.gre4.sw_if_index, enable_ip4=True)
2172
Klement Sekera75e7d132017-09-20 08:26:30 +02002173 self.route4 = VppIpRoute(self, self.tun_ip4, 32,
Klement Sekera4c533132018-02-22 11:41:12 +01002174 [VppRoutePath(self.src_if.remote_ip4,
2175 self.src_if.sw_if_index)])
Klement Sekera75e7d132017-09-20 08:26:30 +02002176 self.route4.add_vpp_config()
2177
2178 self.reset_packet_infos()
2179 for i in range(test_packet_count):
Klement Sekera4c533132018-02-22 11:41:12 +01002180 info = self.create_packet_info(self.src_if, self.dst_if)
Klement Sekera75e7d132017-09-20 08:26:30 +02002181 payload = self.info_to_payload(info)
Klement Sekera4c533132018-02-22 11:41:12 +01002182 # Ethernet header here is only for size calculation, thus it
2183 # doesn't matter how it's initialized. This is to ensure that
2184 # reassembled packet is not > 9000 bytes, so that it's not dropped
2185 p = (Ether() /
2186 IP(id=i, src=self.src_if.remote_ip4,
2187 dst=self.dst_if.remote_ip4) /
2188 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +02002189 Raw(payload))
2190 size = self.packet_sizes[(i // 2) % len(self.packet_sizes)]
2191 self.extend_packet(p, size, self.padding)
Klement Sekera4c533132018-02-22 11:41:12 +01002192 info.data = p[IP] # use only IP part, without ethernet header
Klement Sekera75e7d132017-09-20 08:26:30 +02002193
Paul Vinciguerra090096b2020-12-03 00:42:46 -05002194 fragments = [x for _, p in self._packet_infos.items()
Klement Sekera75e7d132017-09-20 08:26:30 +02002195 for x in fragment_rfc791(p.data, 400)]
2196
2197 encapped_fragments = \
Klement Sekera4c533132018-02-22 11:41:12 +01002198 [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
2199 IP(src=self.tun_ip4, dst=self.src_if.local_ip4) /
Klement Sekera75e7d132017-09-20 08:26:30 +02002200 GRE() /
2201 p
2202 for p in fragments]
2203
2204 fragmented_encapped_fragments = \
2205 [x for p in encapped_fragments
2206 for x in fragment_rfc791(p, 200)]
2207
Klement Sekera4c533132018-02-22 11:41:12 +01002208 self.src_if.add_stream(fragmented_encapped_fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +02002209
2210 self.pg_enable_capture(self.pg_interfaces)
2211 self.pg_start()
2212
Klement Sekera4c533132018-02-22 11:41:12 +01002213 self.src_if.assert_nothing_captured()
2214 packets = self.dst_if.get_capture(len(self._packet_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +02002215 self.verify_capture(packets, IP)
2216
2217 # TODO remove gre vpp config by hand until VppIpRoute gets fixed
2218 # so that it's query_vpp_config() works as it should
2219 self.gre4.remove_vpp_config()
Klement Sekera4c533132018-02-22 11:41:12 +01002220 self.logger.debug(self.vapi.ppcli("show interface"))
Klement Sekera75e7d132017-09-20 08:26:30 +02002221
2222 def test_fif6(self):
2223 """ Fragments in fragments (6o6) """
2224 # TODO this should be ideally in setUpClass, but then we hit a bug
2225 # with VppIpRoute incorrectly reporting it's present when it's not
2226 # so we need to manually remove the vpp config, thus we cannot have
2227 # it shared for multiple test cases
2228 self.tun_ip6 = "1002::1"
2229
Neale Ranns5a8844b2019-04-16 07:15:35 +00002230 self.gre6 = VppGreInterface(self, self.src_if.local_ip6, self.tun_ip6)
Klement Sekera75e7d132017-09-20 08:26:30 +02002231 self.gre6.add_vpp_config()
2232 self.gre6.admin_up()
2233 self.gre6.config_ip6()
2234
Klement Sekera4c533132018-02-22 11:41:12 +01002235 self.vapi.ip_reassembly_enable_disable(
2236 sw_if_index=self.gre6.sw_if_index, enable_ip6=True)
2237
Klement Sekera75e7d132017-09-20 08:26:30 +02002238 self.route6 = VppIpRoute(self, self.tun_ip6, 128,
Neale Ranns097fa662018-05-01 05:17:55 -07002239 [VppRoutePath(
2240 self.src_if.remote_ip6,
2241 self.src_if.sw_if_index)])
Klement Sekera75e7d132017-09-20 08:26:30 +02002242 self.route6.add_vpp_config()
2243
2244 self.reset_packet_infos()
2245 for i in range(test_packet_count):
Klement Sekera4c533132018-02-22 11:41:12 +01002246 info = self.create_packet_info(self.src_if, self.dst_if)
Klement Sekera75e7d132017-09-20 08:26:30 +02002247 payload = self.info_to_payload(info)
Klement Sekera4c533132018-02-22 11:41:12 +01002248 # Ethernet header here is only for size calculation, thus it
2249 # doesn't matter how it's initialized. This is to ensure that
2250 # reassembled packet is not > 9000 bytes, so that it's not dropped
2251 p = (Ether() /
2252 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
2253 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +02002254 Raw(payload))
2255 size = self.packet_sizes[(i // 2) % len(self.packet_sizes)]
2256 self.extend_packet(p, size, self.padding)
Klement Sekera4c533132018-02-22 11:41:12 +01002257 info.data = p[IPv6] # use only IPv6 part, without ethernet header
Klement Sekera75e7d132017-09-20 08:26:30 +02002258
Paul Vinciguerra090096b2020-12-03 00:42:46 -05002259 fragments = [x for _, i in self._packet_infos.items()
Klement Sekera75e7d132017-09-20 08:26:30 +02002260 for x in fragment_rfc8200(
2261 i.data, i.index, 400)]
2262
2263 encapped_fragments = \
Klement Sekera4c533132018-02-22 11:41:12 +01002264 [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
2265 IPv6(src=self.tun_ip6, dst=self.src_if.local_ip6) /
Klement Sekera75e7d132017-09-20 08:26:30 +02002266 GRE() /
2267 p
2268 for p in fragments]
2269
2270 fragmented_encapped_fragments = \
2271 [x for p in encapped_fragments for x in (
2272 fragment_rfc8200(
2273 p,
2274 2 * len(self._packet_infos) + p[IPv6ExtHdrFragment].id,
2275 200)
2276 if IPv6ExtHdrFragment in p else [p]
2277 )
2278 ]
2279
Klement Sekera4c533132018-02-22 11:41:12 +01002280 self.src_if.add_stream(fragmented_encapped_fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +02002281
2282 self.pg_enable_capture(self.pg_interfaces)
2283 self.pg_start()
2284
Klement Sekera4c533132018-02-22 11:41:12 +01002285 self.src_if.assert_nothing_captured()
2286 packets = self.dst_if.get_capture(len(self._packet_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +02002287 self.verify_capture(packets, IPv6)
2288
2289 # TODO remove gre vpp config by hand until VppIpRoute gets fixed
2290 # so that it's query_vpp_config() works as it should
Klement Sekera3ecc2212018-03-27 10:34:43 +02002291 self.gre6.remove_vpp_config()
Klement Sekera75e7d132017-09-20 08:26:30 +02002292
2293
2294if __name__ == '__main__':
2295 unittest.main(testRunner=VppTestRunner)