blob: bd622a94794d9de8e3f788535650c422c4528362 [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
1395 def test_invalid_frag_size(self):
1396 """ fragment size not a multiple of 8 """
Klement Sekera4c533132018-02-22 11:41:12 +01001397 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1398 IPv6(src=self.src_if.remote_ip6,
1399 dst=self.src_if.local_ip6) /
1400 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +02001401 Raw())
1402 self.extend_packet(p, 1000, self.padding)
1403 fragments = fragment_rfc8200(p, 1, 500)
1404 bad_fragment = fragments[0]
1405 self.extend_packet(bad_fragment, len(bad_fragment) + 5)
1406 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +01001407 self.src_if.add_stream([bad_fragment])
Klement Sekera75e7d132017-09-20 08:26:30 +02001408 self.pg_start()
Klement Sekera4c533132018-02-22 11:41:12 +01001409 pkts = self.src_if.get_capture(expected_count=1)
Klement Sekera75e7d132017-09-20 08:26:30 +02001410 icmp = pkts[0]
1411 self.assertIn(ICMPv6ParamProblem, icmp)
1412 self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code")
1413
1414 def test_invalid_packet_size(self):
1415 """ total packet size > 65535 """
Klement Sekera4c533132018-02-22 11:41:12 +01001416 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1417 IPv6(src=self.src_if.remote_ip6,
1418 dst=self.src_if.local_ip6) /
1419 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +02001420 Raw())
1421 self.extend_packet(p, 1000, self.padding)
1422 fragments = fragment_rfc8200(p, 1, 500)
1423 bad_fragment = fragments[1]
1424 bad_fragment[IPv6ExtHdrFragment].offset = 65500
1425 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +01001426 self.src_if.add_stream([bad_fragment])
Klement Sekera75e7d132017-09-20 08:26:30 +02001427 self.pg_start()
Klement Sekera4c533132018-02-22 11:41:12 +01001428 pkts = self.src_if.get_capture(expected_count=1)
Klement Sekera75e7d132017-09-20 08:26:30 +02001429 icmp = pkts[0]
1430 self.assertIn(ICMPv6ParamProblem, icmp)
1431 self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code")
1432
Ole Troan03092c12021-11-23 15:55:39 +01001433 def test_atomic_fragment(self):
1434 """ IPv6 atomic fragment """
1435 pkt = (Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac) /
1436 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6,
1437 nh=44, plen=65535) /
1438 IPv6ExtHdrFragment(offset=8191, m=1, res1=0xFF, res2=0xFF,
1439 nh=255, id=0xffff)/('X'*1452))
1440
1441 rx = self.send_and_expect(self.pg0, [pkt], self.pg0)
1442 self.assertIn(ICMPv6ParamProblem, rx[0])
1443
1444 def test_truncated_fragment(self):
1445 """ IPv6 truncated fragment header """
1446 pkt = (Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac) /
1447 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6,
1448 nh=44, plen=2) /
1449 IPv6ExtHdrFragment(nh=6))
1450
Klement Sekera7c3275e2021-12-07 09:49:53 +00001451 self.send_and_assert_no_replies(self.pg0, [pkt])
Ole Troan03092c12021-11-23 15:55:39 +01001452
1453 pkt = (Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac) /
1454 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.remote_ip6) /
1455 ICMPv6EchoRequest())
1456 rx = self.send_and_expect(self.pg0, [pkt], self.pg0)
1457
Klement Sekera7c3275e2021-12-07 09:49:53 +00001458 def test_one_fragment(self):
1459 """ whole packet in one fragment processed independently """
1460 pkt = (Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac) /
1461 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
1462 ICMPv6EchoRequest()/Raw('X' * 1600))
1463 frags = fragment_rfc8200(pkt, 1, 400)
1464
1465 # send a fragment with known id
1466 self.send_and_assert_no_replies(self.pg0, [frags[0]])
1467
1468 # send an atomic fragment with same id - should be reassembled
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 IPv6ExtHdrFragment(id=1)/ICMPv6EchoRequest())
1472 rx = self.send_and_expect(self.pg0, [pkt], self.pg0)
1473 self.assertNotIn(IPv6ExtHdrFragment, rx)
1474
1475 # now finish the original reassembly, this should still be possible
1476 rx = self.send_and_expect(self.pg0, frags[1:], self.pg0, n_rx=1)
1477 self.assertNotIn(IPv6ExtHdrFragment, rx)
1478
1479 def test_bunch_of_fragments(self):
1480 """ valid fragments followed by rogue fragments and atomic fragment"""
1481 pkt = (Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac) /
1482 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
1483 ICMPv6EchoRequest()/Raw('X' * 1600))
1484 frags = fragment_rfc8200(pkt, 1, 400)
1485 self.send_and_expect(self.pg0, frags, self.pg0, n_rx=1)
1486
1487 inc_frag = (Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac) /
1488 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
1489 IPv6ExtHdrFragment(id=1, nh=58, offset=608)/Raw('X'*308))
1490
1491 self.send_and_assert_no_replies(self.pg0, inc_frag*604)
1492
1493 pkt = (Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac) /
1494 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
1495 IPv6ExtHdrFragment(id=1)/ICMPv6EchoRequest())
1496 rx = self.send_and_expect(self.pg0, [pkt], self.pg0)
1497 self.assertNotIn(IPv6ExtHdrFragment, rx)
1498
Klement Sekera75e7d132017-09-20 08:26:30 +02001499
Klement Sekera630ab582019-07-19 09:14:19 +00001500class TestIPv6MWReassembly(VppTestCase):
1501 """ IPv6 Reassembly (multiple workers) """
Klement Sekera8d815022021-03-15 16:58:10 +01001502 vpp_worker_count = 3
Klement Sekera630ab582019-07-19 09:14:19 +00001503
1504 @classmethod
1505 def setUpClass(cls):
1506 super(TestIPv6MWReassembly, cls).setUpClass()
1507
Klement Sekera8d815022021-03-15 16:58:10 +01001508 cls.create_pg_interfaces(range(cls.vpp_worker_count+1))
Klement Sekera630ab582019-07-19 09:14:19 +00001509 cls.src_if = cls.pg0
1510 cls.send_ifs = cls.pg_interfaces[:-1]
1511 cls.dst_if = cls.pg_interfaces[-1]
1512
1513 # setup all interfaces
1514 for i in cls.pg_interfaces:
1515 i.admin_up()
1516 i.config_ip6()
1517 i.resolve_ndp()
1518
1519 # packets sizes reduced here because we are generating packets without
1520 # Ethernet headers, which are added later (diff fragments go via
1521 # different interfaces)
1522 cls.packet_sizes = [64-len(Ether()), 512-len(Ether()),
1523 1518-len(Ether()), 9018-len(Ether())]
1524 cls.padding = " abcdefghijklmn"
1525 cls.create_stream(cls.packet_sizes)
1526 cls.create_fragments()
1527
1528 @classmethod
1529 def tearDownClass(cls):
1530 super(TestIPv6MWReassembly, cls).tearDownClass()
1531
1532 def setUp(self):
1533 """ Test setup - force timeout on existing reassemblies """
1534 super(TestIPv6MWReassembly, self).setUp()
1535 for intf in self.send_ifs:
1536 self.vapi.ip_reassembly_enable_disable(
1537 sw_if_index=intf.sw_if_index, enable_ip6=True)
1538 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
1539 max_reassembly_length=1000,
1540 expire_walk_interval_ms=10, is_ip6=1)
BenoƮt Ganne56eccdb2021-08-20 09:18:31 +02001541 self.virtual_sleep(.25)
Klement Sekera630ab582019-07-19 09:14:19 +00001542 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
1543 max_reassembly_length=1000,
1544 expire_walk_interval_ms=1000, is_ip6=1)
1545
1546 def tearDown(self):
1547 super(TestIPv6MWReassembly, self).tearDown()
1548
1549 def show_commands_at_teardown(self):
Klement Sekera896c8962019-06-24 11:52:49 +00001550 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
Klement Sekera630ab582019-07-19 09:14:19 +00001551 self.logger.debug(self.vapi.ppcli("show buffers"))
1552
1553 @classmethod
1554 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
1555 """Create input packet stream
1556
1557 :param list packet_sizes: Required packet sizes.
1558 """
1559 for i in range(0, packet_count):
1560 info = cls.create_packet_info(cls.src_if, cls.src_if)
1561 payload = cls.info_to_payload(info)
1562 p = (IPv6(src=cls.src_if.remote_ip6,
1563 dst=cls.dst_if.remote_ip6) /
1564 UDP(sport=1234, dport=5678) /
1565 Raw(payload))
1566 size = packet_sizes[(i // 2) % len(packet_sizes)]
1567 cls.extend_packet(p, size, cls.padding)
1568 info.data = p
1569
1570 @classmethod
1571 def create_fragments(cls):
1572 infos = cls._packet_infos
1573 cls.pkt_infos = []
Paul Vinciguerra090096b2020-12-03 00:42:46 -05001574 for index, info in infos.items():
Klement Sekera630ab582019-07-19 09:14:19 +00001575 p = info.data
1576 # cls.logger.debug(ppp("Packet:",
1577 # p.__class__(scapy.compat.raw(p))))
1578 fragments_400 = fragment_rfc8200(p, index, 400)
1579 cls.pkt_infos.append((index, fragments_400))
1580 cls.fragments_400 = [
1581 x for (_, frags) in cls.pkt_infos for x in frags]
1582 cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, " %
1583 (len(infos), len(cls.fragments_400)))
1584
1585 def verify_capture(self, capture, dropped_packet_indexes=[]):
1586 """Verify captured packet strea .
1587
1588 :param list capture: Captured packet stream.
1589 """
1590 info = None
1591 seen = set()
1592 for packet in capture:
1593 try:
1594 self.logger.debug(ppp("Got packet:", packet))
1595 ip = packet[IPv6]
1596 udp = packet[UDP]
1597 payload_info = self.payload_to_info(packet[Raw])
1598 packet_index = payload_info.index
1599 self.assertTrue(
1600 packet_index not in dropped_packet_indexes,
1601 ppp("Packet received, but should be dropped:", packet))
1602 if packet_index in seen:
1603 raise Exception(ppp("Duplicate packet received", packet))
1604 seen.add(packet_index)
1605 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
1606 info = self._packet_infos[packet_index]
1607 self.assertTrue(info is not None)
1608 self.assertEqual(packet_index, info.index)
1609 saved_packet = info.data
1610 self.assertEqual(ip.src, saved_packet[IPv6].src)
1611 self.assertEqual(ip.dst, saved_packet[IPv6].dst)
1612 self.assertEqual(udp.payload, saved_packet[UDP].payload)
1613 except Exception:
1614 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1615 raise
1616 for index in self._packet_infos:
1617 self.assertTrue(index in seen or index in dropped_packet_indexes,
1618 "Packet with packet_index %d not received" % index)
1619
1620 def send_packets(self, packets):
Klement Sekera8d815022021-03-15 16:58:10 +01001621 for counter in range(self.vpp_worker_count):
Klement Sekera630ab582019-07-19 09:14:19 +00001622 if 0 == len(packets[counter]):
1623 continue
1624 send_if = self.send_ifs[counter]
1625 send_if.add_stream(
1626 (Ether(dst=send_if.local_mac, src=send_if.remote_mac) / x
1627 for x in packets[counter]),
1628 worker=counter)
1629 self.pg_start()
1630
1631 def test_worker_conflict(self):
1632 """ 1st and FO=0 fragments on different workers """
1633
1634 # in first wave we send fragments which don't start at offset 0
1635 # then we send fragments with offset 0 on a different thread
1636 # then the rest of packets on a random thread
Klement Sekera8d815022021-03-15 16:58:10 +01001637 first_packets = [[] for n in range(self.vpp_worker_count)]
1638 second_packets = [[] for n in range(self.vpp_worker_count)]
1639 rest_of_packets = [[] for n in range(self.vpp_worker_count)]
Klement Sekera630ab582019-07-19 09:14:19 +00001640 for (_, p) in self.pkt_infos:
Klement Sekera8d815022021-03-15 16:58:10 +01001641 wi = randrange(self.vpp_worker_count)
Klement Sekera630ab582019-07-19 09:14:19 +00001642 second_packets[wi].append(p[0])
1643 if len(p) <= 1:
1644 continue
1645 wi2 = wi
1646 while wi2 == wi:
Klement Sekera8d815022021-03-15 16:58:10 +01001647 wi2 = randrange(self.vpp_worker_count)
Klement Sekera630ab582019-07-19 09:14:19 +00001648 first_packets[wi2].append(p[1])
Klement Sekera8d815022021-03-15 16:58:10 +01001649 wi3 = randrange(self.vpp_worker_count)
Klement Sekera630ab582019-07-19 09:14:19 +00001650 rest_of_packets[wi3].extend(p[2:])
1651
1652 self.pg_enable_capture()
1653 self.send_packets(first_packets)
1654 self.send_packets(second_packets)
1655 self.send_packets(rest_of_packets)
1656
1657 packets = self.dst_if.get_capture(len(self.pkt_infos))
1658 self.verify_capture(packets)
1659 for send_if in self.send_ifs:
1660 send_if.assert_nothing_captured()
1661
Klement Sekera68bae5b2019-10-10 18:57:34 +00001662 self.logger.debug(self.vapi.ppcli("show trace"))
1663 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
1664 self.logger.debug(self.vapi.ppcli("show buffers"))
1665 self.vapi.cli("clear trace")
1666
Klement Sekera630ab582019-07-19 09:14:19 +00001667 self.pg_enable_capture()
1668 self.send_packets(first_packets)
1669 self.send_packets(second_packets)
1670 self.send_packets(rest_of_packets)
1671
1672 packets = self.dst_if.get_capture(len(self.pkt_infos))
1673 self.verify_capture(packets)
1674 for send_if in self.send_ifs:
1675 send_if.assert_nothing_captured()
1676
1677
Klement Sekerade34c352019-06-25 11:19:22 +00001678class TestIPv6SVReassembly(VppTestCase):
1679 """ IPv6 Shallow Virtual Reassembly """
1680
1681 @classmethod
1682 def setUpClass(cls):
1683 super(TestIPv6SVReassembly, cls).setUpClass()
1684
1685 cls.create_pg_interfaces([0, 1])
1686 cls.src_if = cls.pg0
1687 cls.dst_if = cls.pg1
1688
1689 # setup all interfaces
1690 for i in cls.pg_interfaces:
1691 i.admin_up()
1692 i.config_ip6()
1693 i.resolve_ndp()
1694
1695 def setUp(self):
1696 """ Test setup - force timeout on existing reassemblies """
1697 super(TestIPv6SVReassembly, self).setUp()
1698 self.vapi.ip_reassembly_enable_disable(
1699 sw_if_index=self.src_if.sw_if_index, enable_ip6=True,
1700 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL)
1701 self.vapi.ip_reassembly_set(
1702 timeout_ms=0, max_reassemblies=1000,
1703 max_reassembly_length=1000,
1704 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
1705 expire_walk_interval_ms=10, is_ip6=1)
BenoƮt Ganne56eccdb2021-08-20 09:18:31 +02001706 self.virtual_sleep(.25)
Klement Sekerade34c352019-06-25 11:19:22 +00001707 self.vapi.ip_reassembly_set(
1708 timeout_ms=1000000, max_reassemblies=1000,
1709 max_reassembly_length=1000,
1710 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
1711 expire_walk_interval_ms=10000, is_ip6=1)
1712
1713 def tearDown(self):
1714 super(TestIPv6SVReassembly, self).tearDown()
1715 self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details"))
1716 self.logger.debug(self.vapi.ppcli("show buffers"))
1717
1718 def test_basic(self):
1719 """ basic reassembly """
1720 payload_len = 1000
1721 payload = ""
1722 counter = 0
1723 while len(payload) < payload_len:
1724 payload += "%u " % counter
1725 counter += 1
1726
1727 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1728 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1729 UDP(sport=1234, dport=5678) /
1730 Raw(payload))
1731 fragments = fragment_rfc8200(p, 1, payload_len/4)
1732
1733 # send fragment #2 - should be cached inside reassembly
1734 self.pg_enable_capture()
1735 self.src_if.add_stream(fragments[1])
1736 self.pg_start()
1737 self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details"))
1738 self.logger.debug(self.vapi.ppcli("show buffers"))
1739 self.logger.debug(self.vapi.ppcli("show trace"))
1740 self.dst_if.assert_nothing_captured()
1741
1742 # send fragment #1 - reassembly is finished now and both fragments
1743 # forwarded
1744 self.pg_enable_capture()
1745 self.src_if.add_stream(fragments[0])
1746 self.pg_start()
1747 self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details"))
1748 self.logger.debug(self.vapi.ppcli("show buffers"))
1749 self.logger.debug(self.vapi.ppcli("show trace"))
1750 c = self.dst_if.get_capture(2)
1751 for sent, recvd in zip([fragments[1], fragments[0]], c):
1752 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
1753 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
1754 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
1755
1756 # send rest of fragments - should be immediately forwarded
1757 self.pg_enable_capture()
1758 self.src_if.add_stream(fragments[2:])
1759 self.pg_start()
1760 c = self.dst_if.get_capture(len(fragments[2:]))
1761 for sent, recvd in zip(fragments[2:], c):
1762 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
1763 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
1764 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
1765
Klement Sekera53be16d2020-12-15 21:47:36 +01001766 def test_verify_clear_trace_mid_reassembly(self):
1767 """ verify clear trace works mid-reassembly """
1768 payload_len = 1000
1769 payload = ""
1770 counter = 0
1771 while len(payload) < payload_len:
1772 payload += "%u " % counter
1773 counter += 1
1774
1775 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1776 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1777 UDP(sport=1234, dport=5678) /
1778 Raw(payload))
1779 fragments = fragment_rfc8200(p, 1, payload_len/4)
1780
1781 self.pg_enable_capture()
1782 self.src_if.add_stream(fragments[1])
1783 self.pg_start()
1784
1785 self.logger.debug(self.vapi.cli("show trace"))
1786 self.vapi.cli("clear trace")
1787
1788 self.pg_enable_capture()
1789 self.src_if.add_stream(fragments[0])
1790 self.pg_start()
1791 self.dst_if.get_capture(2)
1792
1793 self.logger.debug(self.vapi.cli("show trace"))
1794 self.vapi.cli("clear trace")
1795
1796 self.pg_enable_capture()
1797 self.src_if.add_stream(fragments[2:])
1798 self.pg_start()
1799 self.dst_if.get_capture(len(fragments[2:]))
1800
Klement Sekerade34c352019-06-25 11:19:22 +00001801 def test_timeout(self):
1802 """ reassembly timeout """
1803 payload_len = 1000
1804 payload = ""
1805 counter = 0
1806 while len(payload) < payload_len:
1807 payload += "%u " % counter
1808 counter += 1
1809
1810 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1811 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1812 UDP(sport=1234, dport=5678) /
1813 Raw(payload))
1814 fragments = fragment_rfc8200(p, 1, payload_len/4)
1815
1816 self.vapi.ip_reassembly_set(
1817 timeout_ms=100, max_reassemblies=1000,
1818 max_reassembly_length=1000,
1819 expire_walk_interval_ms=50,
1820 is_ip6=1,
1821 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL)
1822
1823 # send fragments #2 and #1 - should be forwarded
1824 self.pg_enable_capture()
1825 self.src_if.add_stream(fragments[0:2])
1826 self.pg_start()
1827 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
1828 self.logger.debug(self.vapi.ppcli("show buffers"))
1829 self.logger.debug(self.vapi.ppcli("show trace"))
1830 c = self.dst_if.get_capture(2)
1831 for sent, recvd in zip([fragments[1], fragments[0]], c):
1832 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
1833 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
1834 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
1835
1836 # wait for cleanup
BenoƮt Ganne56eccdb2021-08-20 09:18:31 +02001837 self.virtual_sleep(.25, "wait before sending rest of fragments")
Klement Sekerade34c352019-06-25 11:19:22 +00001838
1839 # send rest of fragments - shouldn't be forwarded
1840 self.pg_enable_capture()
1841 self.src_if.add_stream(fragments[2:])
1842 self.pg_start()
1843 self.dst_if.assert_nothing_captured()
1844
1845 def test_lru(self):
1846 """ reassembly reuses LRU element """
1847
1848 self.vapi.ip_reassembly_set(
1849 timeout_ms=1000000, max_reassemblies=1,
1850 max_reassembly_length=1000,
1851 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
1852 is_ip6=1, expire_walk_interval_ms=10000)
1853
1854 payload_len = 1000
1855 payload = ""
1856 counter = 0
1857 while len(payload) < payload_len:
1858 payload += "%u " % counter
1859 counter += 1
1860
1861 packet_count = 10
1862
1863 fragments = [f
1864 for i in range(packet_count)
1865 for p in (Ether(dst=self.src_if.local_mac,
1866 src=self.src_if.remote_mac) /
1867 IPv6(src=self.src_if.remote_ip6,
1868 dst=self.dst_if.remote_ip6) /
1869 UDP(sport=1234, dport=5678) /
1870 Raw(payload))
1871 for f in fragment_rfc8200(p, i, payload_len/4)]
1872
1873 self.pg_enable_capture()
1874 self.src_if.add_stream(fragments)
1875 self.pg_start()
1876 c = self.dst_if.get_capture(len(fragments))
1877 for sent, recvd in zip(fragments, c):
1878 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
1879 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
1880 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
1881
Klement Sekera7c3275e2021-12-07 09:49:53 +00001882 def test_one_fragment(self):
1883 """ whole packet in one fragment processed independently """
1884 pkt = (Ether(src=self.src_if.local_mac, dst=self.src_if.remote_mac) /
1885 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1886 ICMPv6EchoRequest()/Raw('X' * 1600))
1887 frags = fragment_rfc8200(pkt, 1, 400)
1888
1889 # send a fragment with known id
1890 self.send_and_expect(self.src_if, [frags[0]], self.dst_if)
1891
1892 # send an atomic fragment with same id - should be reassembled
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 IPv6ExtHdrFragment(id=1)/ICMPv6EchoRequest())
1896 rx = self.send_and_expect(self.src_if, [pkt], self.dst_if)
1897
1898 # now forward packets matching original reassembly, should still work
1899 rx = self.send_and_expect(self.src_if, frags[1:], self.dst_if)
1900
1901 def test_bunch_of_fragments(self):
1902 """ valid fragments followed by rogue fragments and atomic fragment"""
1903 pkt = (Ether(src=self.src_if.local_mac, dst=self.src_if.remote_mac) /
1904 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1905 ICMPv6EchoRequest()/Raw('X' * 1600))
1906 frags = fragment_rfc8200(pkt, 1, 400)
1907 rx = self.send_and_expect(self.src_if, frags, self.dst_if)
1908
1909 rogue = (Ether(src=self.src_if.local_mac, dst=self.src_if.remote_mac) /
1910 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1911 IPv6ExtHdrFragment(id=1, nh=58, offset=608)/Raw('X'*308))
1912
1913 self.send_and_expect(self.src_if, rogue*604, self.dst_if)
1914
1915 pkt = (Ether(src=self.src_if.local_mac, dst=self.src_if.remote_mac) /
1916 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1917 IPv6ExtHdrFragment(id=1)/ICMPv6EchoRequest())
1918 rx = self.send_and_expect(self.src_if, [pkt], self.dst_if)
1919
Klement Sekerade34c352019-06-25 11:19:22 +00001920
Juraj Sloboda3048b632018-10-02 11:13:53 +02001921class TestIPv4ReassemblyLocalNode(VppTestCase):
1922 """ IPv4 Reassembly for packets coming to ip4-local node """
1923
1924 @classmethod
1925 def setUpClass(cls):
1926 super(TestIPv4ReassemblyLocalNode, cls).setUpClass()
1927
1928 cls.create_pg_interfaces([0])
1929 cls.src_dst_if = cls.pg0
1930
1931 # setup all interfaces
1932 for i in cls.pg_interfaces:
1933 i.admin_up()
1934 i.config_ip4()
1935 i.resolve_arp()
1936
1937 cls.padding = " abcdefghijklmn"
1938 cls.create_stream()
1939 cls.create_fragments()
1940
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07001941 @classmethod
1942 def tearDownClass(cls):
1943 super(TestIPv4ReassemblyLocalNode, cls).tearDownClass()
1944
Juraj Sloboda3048b632018-10-02 11:13:53 +02001945 def setUp(self):
1946 """ Test setup - force timeout on existing reassemblies """
1947 super(TestIPv4ReassemblyLocalNode, self).setUp()
1948 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +02001949 max_reassembly_length=1000,
Juraj Sloboda3048b632018-10-02 11:13:53 +02001950 expire_walk_interval_ms=10)
BenoƮt Ganne56eccdb2021-08-20 09:18:31 +02001951 self.virtual_sleep(.25)
Juraj Sloboda3048b632018-10-02 11:13:53 +02001952 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +02001953 max_reassembly_length=1000,
Juraj Sloboda3048b632018-10-02 11:13:53 +02001954 expire_walk_interval_ms=10000)
1955
1956 def tearDown(self):
1957 super(TestIPv4ReassemblyLocalNode, self).tearDown()
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -07001958
1959 def show_commands_at_teardown(self):
Klement Sekera896c8962019-06-24 11:52:49 +00001960 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
Klement Sekeracae98b72019-02-19 13:53:43 +01001961 self.logger.debug(self.vapi.ppcli("show buffers"))
Juraj Sloboda3048b632018-10-02 11:13:53 +02001962
1963 @classmethod
1964 def create_stream(cls, packet_count=test_packet_count):
1965 """Create input packet stream for defined interface.
1966
1967 :param list packet_sizes: Required packet sizes.
1968 """
1969 for i in range(0, packet_count):
1970 info = cls.create_packet_info(cls.src_dst_if, cls.src_dst_if)
1971 payload = cls.info_to_payload(info)
1972 p = (Ether(dst=cls.src_dst_if.local_mac,
1973 src=cls.src_dst_if.remote_mac) /
1974 IP(id=info.index, src=cls.src_dst_if.remote_ip4,
1975 dst=cls.src_dst_if.local_ip4) /
1976 ICMP(type='echo-request', id=1234) /
1977 Raw(payload))
1978 cls.extend_packet(p, 1518, cls.padding)
1979 info.data = p
1980
1981 @classmethod
1982 def create_fragments(cls):
1983 infos = cls._packet_infos
1984 cls.pkt_infos = []
Paul Vinciguerra090096b2020-12-03 00:42:46 -05001985 for index, info in infos.items():
Juraj Sloboda3048b632018-10-02 11:13:53 +02001986 p = info.data
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07001987 # cls.logger.debug(ppp("Packet:",
1988 # p.__class__(scapy.compat.raw(p))))
Juraj Sloboda3048b632018-10-02 11:13:53 +02001989 fragments_300 = fragment_rfc791(p, 300)
1990 cls.pkt_infos.append((index, fragments_300))
1991 cls.fragments_300 = [x for (_, frags) in cls.pkt_infos for x in frags]
1992 cls.logger.debug("Fragmented %s packets into %s 300-byte fragments" %
1993 (len(infos), len(cls.fragments_300)))
1994
1995 def verify_capture(self, capture):
1996 """Verify captured packet stream.
1997
1998 :param list capture: Captured packet stream.
1999 """
2000 info = None
2001 seen = set()
2002 for packet in capture:
2003 try:
2004 self.logger.debug(ppp("Got packet:", packet))
2005 ip = packet[IP]
2006 icmp = packet[ICMP]
Paul Vinciguerraeaea4212019-03-06 11:58:06 -08002007 payload_info = self.payload_to_info(packet[Raw])
Juraj Sloboda3048b632018-10-02 11:13:53 +02002008 packet_index = payload_info.index
2009 if packet_index in seen:
2010 raise Exception(ppp("Duplicate packet received", packet))
2011 seen.add(packet_index)
2012 self.assertEqual(payload_info.dst, self.src_dst_if.sw_if_index)
2013 info = self._packet_infos[packet_index]
Klement Sekera14d7e902018-12-10 13:46:09 +01002014 self.assertIsNotNone(info)
Juraj Sloboda3048b632018-10-02 11:13:53 +02002015 self.assertEqual(packet_index, info.index)
2016 saved_packet = info.data
2017 self.assertEqual(ip.src, saved_packet[IP].dst)
2018 self.assertEqual(ip.dst, saved_packet[IP].src)
2019 self.assertEqual(icmp.type, 0) # echo reply
2020 self.assertEqual(icmp.id, saved_packet[ICMP].id)
2021 self.assertEqual(icmp.payload, saved_packet[ICMP].payload)
2022 except Exception:
2023 self.logger.error(ppp("Unexpected or invalid packet:", packet))
2024 raise
2025 for index in self._packet_infos:
Klement Sekera14d7e902018-12-10 13:46:09 +01002026 self.assertIn(index, seen,
2027 "Packet with packet_index %d not received" % index)
Juraj Sloboda3048b632018-10-02 11:13:53 +02002028
2029 def test_reassembly(self):
2030 """ basic reassembly """
2031
2032 self.pg_enable_capture()
2033 self.src_dst_if.add_stream(self.fragments_300)
2034 self.pg_start()
2035
2036 packets = self.src_dst_if.get_capture(len(self.pkt_infos))
2037 self.verify_capture(packets)
2038
2039 # run it all again to verify correctness
2040 self.pg_enable_capture()
2041 self.src_dst_if.add_stream(self.fragments_300)
2042 self.pg_start()
2043
2044 packets = self.src_dst_if.get_capture(len(self.pkt_infos))
2045 self.verify_capture(packets)
2046
2047
Klement Sekera75e7d132017-09-20 08:26:30 +02002048class TestFIFReassembly(VppTestCase):
2049 """ Fragments in fragments reassembly """
2050
2051 @classmethod
2052 def setUpClass(cls):
2053 super(TestFIFReassembly, cls).setUpClass()
2054
Klement Sekera4c533132018-02-22 11:41:12 +01002055 cls.create_pg_interfaces([0, 1])
2056 cls.src_if = cls.pg0
2057 cls.dst_if = cls.pg1
2058 for i in cls.pg_interfaces:
2059 i.admin_up()
2060 i.config_ip4()
2061 i.resolve_arp()
2062 i.config_ip6()
2063 i.resolve_ndp()
Klement Sekera75e7d132017-09-20 08:26:30 +02002064
Klement Sekera75e7d132017-09-20 08:26:30 +02002065 cls.packet_sizes = [64, 512, 1518, 9018]
2066 cls.padding = " abcdefghijklmn"
2067
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07002068 @classmethod
2069 def tearDownClass(cls):
2070 super(TestFIFReassembly, cls).tearDownClass()
2071
Klement Sekera75e7d132017-09-20 08:26:30 +02002072 def setUp(self):
2073 """ Test setup - force timeout on existing reassemblies """
2074 super(TestFIFReassembly, self).setUp()
Klement Sekera4c533132018-02-22 11:41:12 +01002075 self.vapi.ip_reassembly_enable_disable(
2076 sw_if_index=self.src_if.sw_if_index, enable_ip4=True,
2077 enable_ip6=True)
2078 self.vapi.ip_reassembly_enable_disable(
2079 sw_if_index=self.dst_if.sw_if_index, enable_ip4=True,
2080 enable_ip6=True)
Klement Sekera75e7d132017-09-20 08:26:30 +02002081 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +02002082 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +02002083 expire_walk_interval_ms=10)
2084 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +02002085 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +02002086 expire_walk_interval_ms=10, is_ip6=1)
BenoƮt Ganne56eccdb2021-08-20 09:18:31 +02002087 self.virtual_sleep(.25)
Klement Sekera75e7d132017-09-20 08:26:30 +02002088 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +02002089 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +02002090 expire_walk_interval_ms=10000)
2091 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +02002092 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +02002093 expire_walk_interval_ms=10000, is_ip6=1)
2094
2095 def tearDown(self):
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -07002096 super(TestFIFReassembly, self).tearDown()
2097
2098 def show_commands_at_teardown(self):
Klement Sekera896c8962019-06-24 11:52:49 +00002099 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
2100 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
Klement Sekeracae98b72019-02-19 13:53:43 +01002101 self.logger.debug(self.vapi.ppcli("show buffers"))
Klement Sekera75e7d132017-09-20 08:26:30 +02002102
2103 def verify_capture(self, capture, ip_class, dropped_packet_indexes=[]):
2104 """Verify captured packet stream.
2105
2106 :param list capture: Captured packet stream.
2107 """
2108 info = None
2109 seen = set()
2110 for packet in capture:
2111 try:
Klement Sekera4c533132018-02-22 11:41:12 +01002112 self.logger.debug(ppp("Got packet:", packet))
Klement Sekera75e7d132017-09-20 08:26:30 +02002113 ip = packet[ip_class]
2114 udp = packet[UDP]
Paul Vinciguerraeaea4212019-03-06 11:58:06 -08002115 payload_info = self.payload_to_info(packet[Raw])
Klement Sekera75e7d132017-09-20 08:26:30 +02002116 packet_index = payload_info.index
2117 self.assertTrue(
2118 packet_index not in dropped_packet_indexes,
2119 ppp("Packet received, but should be dropped:", packet))
2120 if packet_index in seen:
2121 raise Exception(ppp("Duplicate packet received", packet))
2122 seen.add(packet_index)
Klement Sekera4c533132018-02-22 11:41:12 +01002123 self.assertEqual(payload_info.dst, self.dst_if.sw_if_index)
Klement Sekera75e7d132017-09-20 08:26:30 +02002124 info = self._packet_infos[packet_index]
2125 self.assertTrue(info is not None)
2126 self.assertEqual(packet_index, info.index)
2127 saved_packet = info.data
2128 self.assertEqual(ip.src, saved_packet[ip_class].src)
2129 self.assertEqual(ip.dst, saved_packet[ip_class].dst)
2130 self.assertEqual(udp.payload, saved_packet[UDP].payload)
Klement Sekera4c533132018-02-22 11:41:12 +01002131 except Exception:
Klement Sekera75e7d132017-09-20 08:26:30 +02002132 self.logger.error(ppp("Unexpected or invalid packet:", packet))
2133 raise
2134 for index in self._packet_infos:
2135 self.assertTrue(index in seen or index in dropped_packet_indexes,
2136 "Packet with packet_index %d not received" % index)
2137
2138 def test_fif4(self):
2139 """ Fragments in fragments (4o4) """
2140
2141 # TODO this should be ideally in setUpClass, but then we hit a bug
2142 # with VppIpRoute incorrectly reporting it's present when it's not
2143 # so we need to manually remove the vpp config, thus we cannot have
2144 # it shared for multiple test cases
2145 self.tun_ip4 = "1.1.1.2"
2146
Klement Sekera4c533132018-02-22 11:41:12 +01002147 self.gre4 = VppGreInterface(self, self.src_if.local_ip4, self.tun_ip4)
Klement Sekera75e7d132017-09-20 08:26:30 +02002148 self.gre4.add_vpp_config()
2149 self.gre4.admin_up()
2150 self.gre4.config_ip4()
2151
Klement Sekera4c533132018-02-22 11:41:12 +01002152 self.vapi.ip_reassembly_enable_disable(
2153 sw_if_index=self.gre4.sw_if_index, enable_ip4=True)
2154
Klement Sekera75e7d132017-09-20 08:26:30 +02002155 self.route4 = VppIpRoute(self, self.tun_ip4, 32,
Klement Sekera4c533132018-02-22 11:41:12 +01002156 [VppRoutePath(self.src_if.remote_ip4,
2157 self.src_if.sw_if_index)])
Klement Sekera75e7d132017-09-20 08:26:30 +02002158 self.route4.add_vpp_config()
2159
2160 self.reset_packet_infos()
2161 for i in range(test_packet_count):
Klement Sekera4c533132018-02-22 11:41:12 +01002162 info = self.create_packet_info(self.src_if, self.dst_if)
Klement Sekera75e7d132017-09-20 08:26:30 +02002163 payload = self.info_to_payload(info)
Klement Sekera4c533132018-02-22 11:41:12 +01002164 # Ethernet header here is only for size calculation, thus it
2165 # doesn't matter how it's initialized. This is to ensure that
2166 # reassembled packet is not > 9000 bytes, so that it's not dropped
2167 p = (Ether() /
2168 IP(id=i, src=self.src_if.remote_ip4,
2169 dst=self.dst_if.remote_ip4) /
2170 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +02002171 Raw(payload))
2172 size = self.packet_sizes[(i // 2) % len(self.packet_sizes)]
2173 self.extend_packet(p, size, self.padding)
Klement Sekera4c533132018-02-22 11:41:12 +01002174 info.data = p[IP] # use only IP part, without ethernet header
Klement Sekera75e7d132017-09-20 08:26:30 +02002175
Paul Vinciguerra090096b2020-12-03 00:42:46 -05002176 fragments = [x for _, p in self._packet_infos.items()
Klement Sekera75e7d132017-09-20 08:26:30 +02002177 for x in fragment_rfc791(p.data, 400)]
2178
2179 encapped_fragments = \
Klement Sekera4c533132018-02-22 11:41:12 +01002180 [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
2181 IP(src=self.tun_ip4, dst=self.src_if.local_ip4) /
Klement Sekera75e7d132017-09-20 08:26:30 +02002182 GRE() /
2183 p
2184 for p in fragments]
2185
2186 fragmented_encapped_fragments = \
2187 [x for p in encapped_fragments
2188 for x in fragment_rfc791(p, 200)]
2189
Klement Sekera4c533132018-02-22 11:41:12 +01002190 self.src_if.add_stream(fragmented_encapped_fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +02002191
2192 self.pg_enable_capture(self.pg_interfaces)
2193 self.pg_start()
2194
Klement Sekera4c533132018-02-22 11:41:12 +01002195 self.src_if.assert_nothing_captured()
2196 packets = self.dst_if.get_capture(len(self._packet_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +02002197 self.verify_capture(packets, IP)
2198
2199 # TODO remove gre vpp config by hand until VppIpRoute gets fixed
2200 # so that it's query_vpp_config() works as it should
2201 self.gre4.remove_vpp_config()
Klement Sekera4c533132018-02-22 11:41:12 +01002202 self.logger.debug(self.vapi.ppcli("show interface"))
Klement Sekera75e7d132017-09-20 08:26:30 +02002203
2204 def test_fif6(self):
2205 """ Fragments in fragments (6o6) """
2206 # TODO this should be ideally in setUpClass, but then we hit a bug
2207 # with VppIpRoute incorrectly reporting it's present when it's not
2208 # so we need to manually remove the vpp config, thus we cannot have
2209 # it shared for multiple test cases
2210 self.tun_ip6 = "1002::1"
2211
Neale Ranns5a8844b2019-04-16 07:15:35 +00002212 self.gre6 = VppGreInterface(self, self.src_if.local_ip6, self.tun_ip6)
Klement Sekera75e7d132017-09-20 08:26:30 +02002213 self.gre6.add_vpp_config()
2214 self.gre6.admin_up()
2215 self.gre6.config_ip6()
2216
Klement Sekera4c533132018-02-22 11:41:12 +01002217 self.vapi.ip_reassembly_enable_disable(
2218 sw_if_index=self.gre6.sw_if_index, enable_ip6=True)
2219
Klement Sekera75e7d132017-09-20 08:26:30 +02002220 self.route6 = VppIpRoute(self, self.tun_ip6, 128,
Neale Ranns097fa662018-05-01 05:17:55 -07002221 [VppRoutePath(
2222 self.src_if.remote_ip6,
2223 self.src_if.sw_if_index)])
Klement Sekera75e7d132017-09-20 08:26:30 +02002224 self.route6.add_vpp_config()
2225
2226 self.reset_packet_infos()
2227 for i in range(test_packet_count):
Klement Sekera4c533132018-02-22 11:41:12 +01002228 info = self.create_packet_info(self.src_if, self.dst_if)
Klement Sekera75e7d132017-09-20 08:26:30 +02002229 payload = self.info_to_payload(info)
Klement Sekera4c533132018-02-22 11:41:12 +01002230 # Ethernet header here is only for size calculation, thus it
2231 # doesn't matter how it's initialized. This is to ensure that
2232 # reassembled packet is not > 9000 bytes, so that it's not dropped
2233 p = (Ether() /
2234 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
2235 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +02002236 Raw(payload))
2237 size = self.packet_sizes[(i // 2) % len(self.packet_sizes)]
2238 self.extend_packet(p, size, self.padding)
Klement Sekera4c533132018-02-22 11:41:12 +01002239 info.data = p[IPv6] # use only IPv6 part, without ethernet header
Klement Sekera75e7d132017-09-20 08:26:30 +02002240
Paul Vinciguerra090096b2020-12-03 00:42:46 -05002241 fragments = [x for _, i in self._packet_infos.items()
Klement Sekera75e7d132017-09-20 08:26:30 +02002242 for x in fragment_rfc8200(
2243 i.data, i.index, 400)]
2244
2245 encapped_fragments = \
Klement Sekera4c533132018-02-22 11:41:12 +01002246 [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
2247 IPv6(src=self.tun_ip6, dst=self.src_if.local_ip6) /
Klement Sekera75e7d132017-09-20 08:26:30 +02002248 GRE() /
2249 p
2250 for p in fragments]
2251
2252 fragmented_encapped_fragments = \
2253 [x for p in encapped_fragments for x in (
2254 fragment_rfc8200(
2255 p,
2256 2 * len(self._packet_infos) + p[IPv6ExtHdrFragment].id,
2257 200)
2258 if IPv6ExtHdrFragment in p else [p]
2259 )
2260 ]
2261
Klement Sekera4c533132018-02-22 11:41:12 +01002262 self.src_if.add_stream(fragmented_encapped_fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +02002263
2264 self.pg_enable_capture(self.pg_interfaces)
2265 self.pg_start()
2266
Klement Sekera4c533132018-02-22 11:41:12 +01002267 self.src_if.assert_nothing_captured()
2268 packets = self.dst_if.get_capture(len(self._packet_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +02002269 self.verify_capture(packets, IPv6)
2270
2271 # TODO remove gre vpp config by hand until VppIpRoute gets fixed
2272 # so that it's query_vpp_config() works as it should
Klement Sekera3ecc2212018-03-27 10:34:43 +02002273 self.gre6.remove_vpp_config()
Klement Sekera75e7d132017-09-20 08:26:30 +02002274
2275
2276if __name__ == '__main__':
2277 unittest.main(testRunner=VppTestRunner)