blob: 85fb97dee071b36a0940fbb830dcb239a855a48f [file] [log] [blame]
Klement Sekera75e7d132017-09-20 08:26:30 +02001#!/usr/bin/env python
Paul Vinciguerraf1f2aa62018-11-25 08:36:47 -08002
3import six
Klement Sekera75e7d132017-09-20 08:26:30 +02004import unittest
Klement Sekera630ab582019-07-19 09:14:19 +00005from random import shuffle, choice, randrange
Klement Sekera75e7d132017-09-20 08:26:30 +02006
Klement Sekera947a85c2019-07-24 12:40:37 +00007from framework import VppTestCase, VppTestRunner
8
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07009import scapy.compat
Klement Sekera75e7d132017-09-20 08:26:30 +020010from scapy.packet import Raw
11from scapy.layers.l2 import Ether, GRE
Juraj Sloboda3048b632018-10-02 11:13:53 +020012from scapy.layers.inet import IP, UDP, ICMP
Klement Sekera769145c2019-03-06 11:59:57 +010013from scapy.layers.inet6 import HBHOptUnknown, ICMPv6ParamProblem,\
Klement Sekerade34c352019-06-25 11:19:22 +000014 ICMPv6TimeExceeded, IPv6, IPv6ExtHdrFragment, IPv6ExtHdrHopByHop
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
Klement Sekera630ab582019-07-19 09:14:19 +000025# number of workers used for multi-worker test cases
26worker_count = 3
27
Klement Sekera75e7d132017-09-20 08:26:30 +020028
Klement Sekera947a85c2019-07-24 12:40:37 +000029class TestIPv4Reassembly(VppTestCase):
Klement Sekera75e7d132017-09-20 08:26:30 +020030 """ IPv4 Reassembly """
31
32 @classmethod
33 def setUpClass(cls):
34 super(TestIPv4Reassembly, cls).setUpClass()
35
Klement Sekera4c533132018-02-22 11:41:12 +010036 cls.create_pg_interfaces([0, 1])
37 cls.src_if = cls.pg0
38 cls.dst_if = cls.pg1
Klement Sekera75e7d132017-09-20 08:26:30 +020039
40 # setup all interfaces
41 for i in cls.pg_interfaces:
42 i.admin_up()
43 i.config_ip4()
44 i.resolve_arp()
45
Klement Sekera75e7d132017-09-20 08:26:30 +020046 # packet sizes
47 cls.packet_sizes = [64, 512, 1518, 9018]
48 cls.padding = " abcdefghijklmn"
49 cls.create_stream(cls.packet_sizes)
50 cls.create_fragments()
51
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -070052 @classmethod
53 def tearDownClass(cls):
54 super(TestIPv4Reassembly, cls).tearDownClass()
55
Klement Sekera75e7d132017-09-20 08:26:30 +020056 def setUp(self):
57 """ Test setup - force timeout on existing reassemblies """
58 super(TestIPv4Reassembly, self).setUp()
Klement Sekera4c533132018-02-22 11:41:12 +010059 self.vapi.ip_reassembly_enable_disable(
60 sw_if_index=self.src_if.sw_if_index, enable_ip4=True)
Klement Sekera75e7d132017-09-20 08:26:30 +020061 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +020062 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +020063 expire_walk_interval_ms=10)
64 self.sleep(.25)
65 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +020066 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +020067 expire_walk_interval_ms=10000)
68
69 def tearDown(self):
70 super(TestIPv4Reassembly, self).tearDown()
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -070071
72 def show_commands_at_teardown(self):
Klement Sekera896c8962019-06-24 11:52:49 +000073 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
Klement Sekeracae98b72019-02-19 13:53:43 +010074 self.logger.debug(self.vapi.ppcli("show buffers"))
Klement Sekera75e7d132017-09-20 08:26:30 +020075
76 @classmethod
77 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
Klement Sekerad0f70a32018-12-14 17:24:13 +010078 """Create input packet stream
Klement Sekera75e7d132017-09-20 08:26:30 +020079
80 :param list packet_sizes: Required packet sizes.
81 """
82 for i in range(0, packet_count):
Klement Sekera4c533132018-02-22 11:41:12 +010083 info = cls.create_packet_info(cls.src_if, cls.src_if)
Klement Sekera75e7d132017-09-20 08:26:30 +020084 payload = cls.info_to_payload(info)
Klement Sekera4c533132018-02-22 11:41:12 +010085 p = (Ether(dst=cls.src_if.local_mac, src=cls.src_if.remote_mac) /
86 IP(id=info.index, src=cls.src_if.remote_ip4,
87 dst=cls.dst_if.remote_ip4) /
88 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +020089 Raw(payload))
90 size = packet_sizes[(i // 2) % len(packet_sizes)]
91 cls.extend_packet(p, size, cls.padding)
92 info.data = p
93
94 @classmethod
95 def create_fragments(cls):
96 infos = cls._packet_infos
97 cls.pkt_infos = []
Paul Vinciguerraf1f2aa62018-11-25 08:36:47 -080098 for index, info in six.iteritems(infos):
Klement Sekera75e7d132017-09-20 08:26:30 +020099 p = info.data
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -0700100 # cls.logger.debug(ppp("Packet:",
101 # p.__class__(scapy.compat.raw(p))))
Klement Sekera75e7d132017-09-20 08:26:30 +0200102 fragments_400 = fragment_rfc791(p, 400)
103 fragments_300 = fragment_rfc791(p, 300)
104 fragments_200 = [
105 x for f in fragments_400 for x in fragment_rfc791(f, 200)]
106 cls.pkt_infos.append(
107 (index, fragments_400, fragments_300, fragments_200))
108 cls.fragments_400 = [
109 x for (_, frags, _, _) in cls.pkt_infos for x in frags]
110 cls.fragments_300 = [
111 x for (_, _, frags, _) in cls.pkt_infos for x in frags]
112 cls.fragments_200 = [
113 x for (_, _, _, frags) in cls.pkt_infos for x in frags]
114 cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, "
115 "%s 300-byte fragments and %s 200-byte fragments" %
116 (len(infos), len(cls.fragments_400),
117 len(cls.fragments_300), len(cls.fragments_200)))
118
Klement Sekera947a85c2019-07-24 12:40:37 +0000119 def verify_capture(self, capture, dropped_packet_indexes=[]):
120 """Verify captured packet stream.
121
122 :param list capture: Captured packet stream.
123 """
124 info = None
125 seen = set()
126 for packet in capture:
127 try:
128 self.logger.debug(ppp("Got packet:", packet))
129 ip = packet[IP]
130 udp = packet[UDP]
131 payload_info = self.payload_to_info(packet[Raw])
132 packet_index = payload_info.index
133 self.assertTrue(
134 packet_index not in dropped_packet_indexes,
135 ppp("Packet received, but should be dropped:", packet))
136 if packet_index in seen:
137 raise Exception(ppp("Duplicate packet received", packet))
138 seen.add(packet_index)
139 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
140 info = self._packet_infos[packet_index]
141 self.assertTrue(info is not None)
142 self.assertEqual(packet_index, info.index)
143 saved_packet = info.data
144 self.assertEqual(ip.src, saved_packet[IP].src)
145 self.assertEqual(ip.dst, saved_packet[IP].dst)
146 self.assertEqual(udp.payload, saved_packet[UDP].payload)
147 except Exception:
148 self.logger.error(ppp("Unexpected or invalid packet:", packet))
149 raise
150 for index in self._packet_infos:
151 self.assertTrue(index in seen or index in dropped_packet_indexes,
152 "Packet with packet_index %d not received" % index)
153
154 def test_reassembly(self):
Klement Sekera75e7d132017-09-20 08:26:30 +0200155 """ basic reassembly """
156
Klement Sekera947a85c2019-07-24 12:40:37 +0000157 self.pg_enable_capture()
158 self.src_if.add_stream(self.fragments_200)
159 self.pg_start()
160
161 packets = self.dst_if.get_capture(len(self.pkt_infos))
162 self.verify_capture(packets)
163 self.src_if.assert_nothing_captured()
164
165 # run it all again to verify correctness
166 self.pg_enable_capture()
167 self.src_if.add_stream(self.fragments_200)
168 self.pg_start()
169
170 packets = self.dst_if.get_capture(len(self.pkt_infos))
171 self.verify_capture(packets)
172 self.src_if.assert_nothing_captured()
173
174 def test_reversed(self):
Klement Sekera75e7d132017-09-20 08:26:30 +0200175 """ reverse order reassembly """
176
Klement Sekera947a85c2019-07-24 12:40:37 +0000177 fragments = list(self.fragments_200)
178 fragments.reverse()
179
180 self.pg_enable_capture()
181 self.src_if.add_stream(fragments)
182 self.pg_start()
183
184 packets = self.dst_if.get_capture(len(self.packet_infos))
185 self.verify_capture(packets)
186 self.src_if.assert_nothing_captured()
187
188 # run it all again to verify correctness
189 self.pg_enable_capture()
190 self.src_if.add_stream(fragments)
191 self.pg_start()
192
193 packets = self.dst_if.get_capture(len(self.packet_infos))
194 self.verify_capture(packets)
195 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200196
Klement Sekera3a343d42019-05-16 14:35:46 +0200197 def test_long_fragment_chain(self):
198 """ long fragment chain """
199
200 error_cnt_str = \
Klement Sekera896c8962019-06-24 11:52:49 +0000201 "/err/ip4-full-reassembly-feature/fragment chain too long (drop)"
Klement Sekera3a343d42019-05-16 14:35:46 +0200202
Klement Sekera34641f22019-05-22 20:18:26 +0200203 error_cnt = self.statistics.get_err_counter(error_cnt_str)
Klement Sekera3a343d42019-05-16 14:35:46 +0200204
205 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
206 max_reassembly_length=3,
207 expire_walk_interval_ms=50)
208
209 p1 = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
210 IP(id=1000, src=self.src_if.remote_ip4,
211 dst=self.dst_if.remote_ip4) /
212 UDP(sport=1234, dport=5678) /
213 Raw("X" * 1000))
214 p2 = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
215 IP(id=1001, src=self.src_if.remote_ip4,
216 dst=self.dst_if.remote_ip4) /
217 UDP(sport=1234, dport=5678) /
218 Raw("X" * 1000))
219 frags = fragment_rfc791(p1, 200) + fragment_rfc791(p2, 500)
220
221 self.pg_enable_capture()
222 self.src_if.add_stream(frags)
223 self.pg_start()
224
225 self.dst_if.get_capture(1)
Klement Sekera34641f22019-05-22 20:18:26 +0200226 self.assert_error_counter_equal(error_cnt_str, error_cnt + 1)
Klement Sekera3a343d42019-05-16 14:35:46 +0200227
Klement Sekera14d7e902018-12-10 13:46:09 +0100228 def test_5737(self):
229 """ fragment length + ip header size > 65535 """
Klement Sekera4ee633e2018-12-14 12:00:44 +0100230 self.vapi.cli("clear errors")
Klement Sekera14d7e902018-12-10 13:46:09 +0100231 raw = ('E\x00\x00\x88,\xf8\x1f\xfe@\x01\x98\x00\xc0\xa8\n-\xc0\xa8\n'
232 '\x01\x08\x00\xf0J\xed\xcb\xf1\xf5Test-group: IPv4.IPv4.ipv4-'
233 'message.Ethernet-Payload.IPv4-Packet.IPv4-Header.Fragment-Of'
234 'fset; Test-case: 5737')
235
236 malformed_packet = (Ether(dst=self.src_if.local_mac,
237 src=self.src_if.remote_mac) /
238 IP(raw))
239 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
240 IP(id=1000, src=self.src_if.remote_ip4,
241 dst=self.dst_if.remote_ip4) /
242 UDP(sport=1234, dport=5678) /
243 Raw("X" * 1000))
244 valid_fragments = fragment_rfc791(p, 400)
245
246 self.pg_enable_capture()
247 self.src_if.add_stream([malformed_packet] + valid_fragments)
248 self.pg_start()
249
250 self.dst_if.get_capture(1)
Klement Sekera896c8962019-06-24 11:52:49 +0000251 self.logger.debug(self.vapi.ppcli("show error"))
252 self.assert_packet_counter_equal("ip4-full-reassembly-feature", 1)
Klement Sekera4ee633e2018-12-14 12:00:44 +0100253 # TODO remove above, uncomment below once clearing of counters
254 # is supported
255 # self.assert_packet_counter_equal(
Klement Sekera896c8962019-06-24 11:52:49 +0000256 # "/err/ip4-full-reassembly-feature/malformed packets", 1)
Klement Sekera14d7e902018-12-10 13:46:09 +0100257
Klement Sekera400f6d82018-12-13 14:35:48 +0100258 def test_44924(self):
259 """ compress tiny fragments """
260 packets = [(Ether(dst=self.src_if.local_mac,
261 src=self.src_if.remote_mac) /
262 IP(id=24339, flags="MF", frag=0, ttl=64,
263 src=self.src_if.remote_ip4,
264 dst=self.dst_if.remote_ip4) /
265 ICMP(type="echo-request", code=0, id=0x1fe6, seq=0x2407) /
266 Raw(load='Test-group: IPv4')),
267 (Ether(dst=self.src_if.local_mac,
268 src=self.src_if.remote_mac) /
269 IP(id=24339, flags="MF", frag=3, ttl=64,
270 src=self.src_if.remote_ip4,
271 dst=self.dst_if.remote_ip4) /
272 ICMP(type="echo-request", code=0, id=0x1fe6, seq=0x2407) /
273 Raw(load='.IPv4.Fragmentation.vali')),
274 (Ether(dst=self.src_if.local_mac,
275 src=self.src_if.remote_mac) /
276 IP(id=24339, frag=6, ttl=64,
277 src=self.src_if.remote_ip4,
278 dst=self.dst_if.remote_ip4) /
279 ICMP(type="echo-request", code=0, id=0x1fe6, seq=0x2407) /
280 Raw(load='d; Test-case: 44924'))
281 ]
282
283 self.pg_enable_capture()
284 self.src_if.add_stream(packets)
285 self.pg_start()
286
287 self.dst_if.get_capture(1)
288
Klement Sekera4ee633e2018-12-14 12:00:44 +0100289 def test_frag_1(self):
290 """ fragment of size 1 """
291 self.vapi.cli("clear errors")
292 malformed_packets = [(Ether(dst=self.src_if.local_mac,
293 src=self.src_if.remote_mac) /
294 IP(id=7, len=21, flags="MF", frag=0, ttl=64,
295 src=self.src_if.remote_ip4,
296 dst=self.dst_if.remote_ip4) /
297 ICMP(type="echo-request")),
298 (Ether(dst=self.src_if.local_mac,
299 src=self.src_if.remote_mac) /
300 IP(id=7, len=21, frag=1, ttl=64,
301 src=self.src_if.remote_ip4,
302 dst=self.dst_if.remote_ip4) /
303 Raw(load='\x08')),
304 ]
305
306 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
307 IP(id=1000, src=self.src_if.remote_ip4,
308 dst=self.dst_if.remote_ip4) /
309 UDP(sport=1234, dport=5678) /
310 Raw("X" * 1000))
311 valid_fragments = fragment_rfc791(p, 400)
312
313 self.pg_enable_capture()
314 self.src_if.add_stream(malformed_packets + valid_fragments)
315 self.pg_start()
316
317 self.dst_if.get_capture(1)
318
Klement Sekera896c8962019-06-24 11:52:49 +0000319 self.assert_packet_counter_equal("ip4-full-reassembly-feature", 1)
Klement Sekera4ee633e2018-12-14 12:00:44 +0100320 # TODO remove above, uncomment below once clearing of counters
321 # is supported
322 # self.assert_packet_counter_equal(
Klement Sekera896c8962019-06-24 11:52:49 +0000323 # "/err/ip4-full-reassembly-feature/malformed packets", 1)
Klement Sekera4ee633e2018-12-14 12:00:44 +0100324
Klement Sekera947a85c2019-07-24 12:40:37 +0000325 def test_random(self):
326 """ random order reassembly """
327
328 fragments = list(self.fragments_200)
329 shuffle(fragments)
330
331 self.pg_enable_capture()
332 self.src_if.add_stream(fragments)
333 self.pg_start()
334
335 packets = self.dst_if.get_capture(len(self.packet_infos))
336 self.verify_capture(packets)
337 self.src_if.assert_nothing_captured()
338
339 # run it all again to verify correctness
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 def test_duplicates(self):
Klement Sekera75e7d132017-09-20 08:26:30 +0200349 """ duplicate fragments """
Klement Sekera947a85c2019-07-24 12:40:37 +0000350
Klement Sekera75e7d132017-09-20 08:26:30 +0200351 fragments = [
352 x for (_, frags, _, _) in self.pkt_infos
353 for x in frags
354 for _ in range(0, min(2, len(frags)))
355 ]
Klement Sekera947a85c2019-07-24 12:40:37 +0000356
357 self.pg_enable_capture()
358 self.src_if.add_stream(fragments)
359 self.pg_start()
360
361 packets = self.dst_if.get_capture(len(self.pkt_infos))
362 self.verify_capture(packets)
363 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200364
365 def test_overlap1(self):
366 """ overlapping fragments case #1 """
367
368 fragments = []
369 for _, _, frags_300, frags_200 in self.pkt_infos:
370 if len(frags_300) == 1:
371 fragments.extend(frags_300)
372 else:
373 for i, j in zip(frags_200, frags_300):
374 fragments.extend(i)
375 fragments.extend(j)
376
377 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100378 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200379 self.pg_start()
380
Klement Sekera4c533132018-02-22 11:41:12 +0100381 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera947a85c2019-07-24 12:40:37 +0000382 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100383 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200384
385 # run it all to verify correctness
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 def test_overlap2(self):
395 """ overlapping fragments case #2 """
396
397 fragments = []
398 for _, _, frags_300, frags_200 in self.pkt_infos:
399 if len(frags_300) == 1:
400 fragments.extend(frags_300)
401 else:
402 # care must be taken here so that there are no fragments
403 # received by vpp after reassembly is finished, otherwise
404 # new reassemblies will be started and packet generator will
405 # freak out when it detects unfreed buffers
406 zipped = zip(frags_300, frags_200)
Paul Vinciguerrac7834e02019-03-02 10:43:05 -0800407 for i, j in zipped:
Klement Sekera75e7d132017-09-20 08:26:30 +0200408 fragments.extend(i)
409 fragments.extend(j)
Paul Vinciguerrac7834e02019-03-02 10:43:05 -0800410 fragments.pop()
Klement Sekera75e7d132017-09-20 08:26:30 +0200411
412 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100413 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200414 self.pg_start()
415
Klement Sekera4c533132018-02-22 11:41:12 +0100416 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera947a85c2019-07-24 12:40:37 +0000417 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100418 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200419
420 # run it all to verify correctness
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
Klement Sekera947a85c2019-07-24 12:40:37 +0000429 def test_timeout_inline(self):
Klement Sekera75e7d132017-09-20 08:26:30 +0200430 """ timeout (inline) """
431
432 dropped_packet_indexes = set(
433 index for (index, frags, _, _) in self.pkt_infos if len(frags) > 1
434 )
435
Klement Sekera947a85c2019-07-24 12:40:37 +0000436 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
437 max_reassembly_length=3,
438 expire_walk_interval_ms=10000)
439
440 self.pg_enable_capture()
441 self.src_if.add_stream(self.fragments_400)
442 self.pg_start()
443
444 packets = self.dst_if.get_capture(
445 len(self.pkt_infos) - len(dropped_packet_indexes))
446 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +0100447 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200448
449 def test_timeout_cleanup(self):
450 """ timeout (cleanup) """
451
452 # whole packets + fragmented packets sans last fragment
453 fragments = [
454 x for (_, frags_400, _, _) in self.pkt_infos
455 for x in frags_400[:-1 if len(frags_400) > 1 else None]
456 ]
457
458 # last fragments for fragmented packets
459 fragments2 = [frags_400[-1]
460 for (_, frags_400, _, _) in self.pkt_infos
461 if len(frags_400) > 1]
462
463 dropped_packet_indexes = set(
464 index for (index, frags_400, _, _) in self.pkt_infos
465 if len(frags_400) > 1)
466
467 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +0200468 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +0200469 expire_walk_interval_ms=50)
470
471 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100472 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200473 self.pg_start()
474
475 self.sleep(.25, "wait before sending rest of fragments")
476
Klement Sekera4c533132018-02-22 11:41:12 +0100477 self.src_if.add_stream(fragments2)
Klement Sekera75e7d132017-09-20 08:26:30 +0200478 self.pg_start()
Klement Sekera75e7d132017-09-20 08:26:30 +0200479
Klement Sekera4c533132018-02-22 11:41:12 +0100480 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +0200481 len(self.pkt_infos) - len(dropped_packet_indexes))
Klement Sekera947a85c2019-07-24 12:40:37 +0000482 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +0100483 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200484
Klement Sekera947a85c2019-07-24 12:40:37 +0000485 def test_disabled(self):
Klement Sekera75e7d132017-09-20 08:26:30 +0200486 """ reassembly disabled """
487
488 dropped_packet_indexes = set(
489 index for (index, frags_400, _, _) in self.pkt_infos
490 if len(frags_400) > 1)
Klement Sekera947a85c2019-07-24 12:40:37 +0000491
492 self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=0,
493 max_reassembly_length=3,
494 expire_walk_interval_ms=10000)
495
496 self.pg_enable_capture()
497 self.src_if.add_stream(self.fragments_400)
498 self.pg_start()
499
500 packets = self.dst_if.get_capture(
501 len(self.pkt_infos) - len(dropped_packet_indexes))
502 self.verify_capture(packets, dropped_packet_indexes)
503 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200504
505
Klement Sekerade34c352019-06-25 11:19:22 +0000506class TestIPv4SVReassembly(VppTestCase):
507 """ IPv4 Shallow Virtual Reassembly """
508
509 @classmethod
510 def setUpClass(cls):
511 super(TestIPv4SVReassembly, cls).setUpClass()
512
513 cls.create_pg_interfaces([0, 1])
514 cls.src_if = cls.pg0
515 cls.dst_if = cls.pg1
516
517 # setup all interfaces
518 for i in cls.pg_interfaces:
519 i.admin_up()
520 i.config_ip4()
521 i.resolve_arp()
522
523 def setUp(self):
524 """ Test setup - force timeout on existing reassemblies """
525 super(TestIPv4SVReassembly, self).setUp()
526 self.vapi.ip_reassembly_enable_disable(
527 sw_if_index=self.src_if.sw_if_index, enable_ip4=True,
528 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL)
529 self.vapi.ip_reassembly_set(
530 timeout_ms=0, max_reassemblies=1000,
531 max_reassembly_length=1000,
532 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
533 expire_walk_interval_ms=10)
534 self.sleep(.25)
535 self.vapi.ip_reassembly_set(
536 timeout_ms=1000000, max_reassemblies=1000,
537 max_reassembly_length=1000,
538 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
539 expire_walk_interval_ms=10000)
540
541 def tearDown(self):
542 super(TestIPv4SVReassembly, self).tearDown()
543 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
544 self.logger.debug(self.vapi.ppcli("show buffers"))
545
546 def test_basic(self):
547 """ basic reassembly """
548 payload_len = 1000
549 payload = ""
550 counter = 0
551 while len(payload) < payload_len:
552 payload += "%u " % counter
553 counter += 1
554
555 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
556 IP(id=1, src=self.src_if.remote_ip4,
557 dst=self.dst_if.remote_ip4) /
558 UDP(sport=1234, dport=5678) /
559 Raw(payload))
560 fragments = fragment_rfc791(p, payload_len/4)
561
562 # send fragment #2 - should be cached inside reassembly
563 self.pg_enable_capture()
564 self.src_if.add_stream(fragments[1])
565 self.pg_start()
566 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
567 self.logger.debug(self.vapi.ppcli("show buffers"))
568 self.logger.debug(self.vapi.ppcli("show trace"))
569 self.dst_if.assert_nothing_captured()
570
571 # send fragment #1 - reassembly is finished now and both fragments
572 # forwarded
573 self.pg_enable_capture()
574 self.src_if.add_stream(fragments[0])
575 self.pg_start()
576 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
577 self.logger.debug(self.vapi.ppcli("show buffers"))
578 self.logger.debug(self.vapi.ppcli("show trace"))
579 c = self.dst_if.get_capture(2)
580 for sent, recvd in zip([fragments[1], fragments[0]], c):
581 self.assertEqual(sent[IP].src, recvd[IP].src)
582 self.assertEqual(sent[IP].dst, recvd[IP].dst)
583 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
584
585 # send rest of fragments - should be immediately forwarded
586 self.pg_enable_capture()
587 self.src_if.add_stream(fragments[2:])
588 self.pg_start()
589 c = self.dst_if.get_capture(len(fragments[2:]))
590 for sent, recvd in zip(fragments[2:], c):
591 self.assertEqual(sent[IP].src, recvd[IP].src)
592 self.assertEqual(sent[IP].dst, recvd[IP].dst)
593 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
594
595 def test_timeout(self):
596 """ reassembly timeout """
597 payload_len = 1000
598 payload = ""
599 counter = 0
600 while len(payload) < payload_len:
601 payload += "%u " % counter
602 counter += 1
603
604 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
605 IP(id=1, src=self.src_if.remote_ip4,
606 dst=self.dst_if.remote_ip4) /
607 UDP(sport=1234, dport=5678) /
608 Raw(payload))
609 fragments = fragment_rfc791(p, payload_len/4)
610
611 self.vapi.ip_reassembly_set(
612 timeout_ms=100, max_reassemblies=1000,
613 max_reassembly_length=1000,
614 expire_walk_interval_ms=50,
615 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL)
616
617 # send fragments #2 and #1 - should be forwarded
618 self.pg_enable_capture()
619 self.src_if.add_stream(fragments[0:2])
620 self.pg_start()
621 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
622 self.logger.debug(self.vapi.ppcli("show buffers"))
623 self.logger.debug(self.vapi.ppcli("show trace"))
624 c = self.dst_if.get_capture(2)
625 for sent, recvd in zip([fragments[1], fragments[0]], c):
626 self.assertEqual(sent[IP].src, recvd[IP].src)
627 self.assertEqual(sent[IP].dst, recvd[IP].dst)
628 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
629
630 # wait for cleanup
631 self.sleep(.25, "wait before sending rest of fragments")
632
633 # send rest of fragments - shouldn't be forwarded
634 self.pg_enable_capture()
635 self.src_if.add_stream(fragments[2:])
636 self.pg_start()
637 self.dst_if.assert_nothing_captured()
638
639 def test_lru(self):
640 """ reassembly reuses LRU element """
641
642 self.vapi.ip_reassembly_set(
643 timeout_ms=1000000, max_reassemblies=1,
644 max_reassembly_length=1000,
645 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
646 expire_walk_interval_ms=10000)
647
648 payload_len = 1000
649 payload = ""
650 counter = 0
651 while len(payload) < payload_len:
652 payload += "%u " % counter
653 counter += 1
654
655 packet_count = 10
656
657 fragments = [f
658 for i in range(packet_count)
659 for p in (Ether(dst=self.src_if.local_mac,
660 src=self.src_if.remote_mac) /
661 IP(id=i, src=self.src_if.remote_ip4,
662 dst=self.dst_if.remote_ip4) /
663 UDP(sport=1234, dport=5678) /
664 Raw(payload))
665 for f in fragment_rfc791(p, payload_len/4)]
666
667 self.pg_enable_capture()
668 self.src_if.add_stream(fragments)
669 self.pg_start()
670 c = self.dst_if.get_capture(len(fragments))
671 for sent, recvd in zip(fragments, c):
672 self.assertEqual(sent[IP].src, recvd[IP].src)
673 self.assertEqual(sent[IP].dst, recvd[IP].dst)
674 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
675
676
Klement Sekera630ab582019-07-19 09:14:19 +0000677class TestIPv4MWReassembly(VppTestCase):
678 """ IPv4 Reassembly (multiple workers) """
679 worker_config = "workers %d" % worker_count
680
681 @classmethod
682 def setUpClass(cls):
683 super(TestIPv4MWReassembly, cls).setUpClass()
684
685 cls.create_pg_interfaces(range(worker_count+1))
686 cls.src_if = cls.pg0
687 cls.send_ifs = cls.pg_interfaces[:-1]
688 cls.dst_if = cls.pg_interfaces[-1]
689
690 # setup all interfaces
691 for i in cls.pg_interfaces:
692 i.admin_up()
693 i.config_ip4()
694 i.resolve_arp()
695
696 # packets sizes reduced here because we are generating packets without
697 # Ethernet headers, which are added later (diff fragments go via
698 # different interfaces)
699 cls.packet_sizes = [64-len(Ether()), 512-len(Ether()),
700 1518-len(Ether()), 9018-len(Ether())]
701 cls.padding = " abcdefghijklmn"
702 cls.create_stream(cls.packet_sizes)
703 cls.create_fragments()
704
705 @classmethod
706 def tearDownClass(cls):
707 super(TestIPv4MWReassembly, cls).tearDownClass()
708
709 def setUp(self):
710 """ Test setup - force timeout on existing reassemblies """
711 super(TestIPv4MWReassembly, self).setUp()
712 for intf in self.send_ifs:
713 self.vapi.ip_reassembly_enable_disable(
714 sw_if_index=intf.sw_if_index, enable_ip4=True)
715 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
716 max_reassembly_length=1000,
717 expire_walk_interval_ms=10)
718 self.sleep(.25)
719 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
720 max_reassembly_length=1000,
721 expire_walk_interval_ms=10000)
722
723 def tearDown(self):
724 super(TestIPv4MWReassembly, self).tearDown()
725
726 def show_commands_at_teardown(self):
Klement Sekera896c8962019-06-24 11:52:49 +0000727 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
Klement Sekera630ab582019-07-19 09:14:19 +0000728 self.logger.debug(self.vapi.ppcli("show buffers"))
729
730 @classmethod
731 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
732 """Create input packet stream
733
734 :param list packet_sizes: Required packet sizes.
735 """
736 for i in range(0, packet_count):
737 info = cls.create_packet_info(cls.src_if, cls.src_if)
738 payload = cls.info_to_payload(info)
739 p = (IP(id=info.index, src=cls.src_if.remote_ip4,
740 dst=cls.dst_if.remote_ip4) /
741 UDP(sport=1234, dport=5678) /
742 Raw(payload))
743 size = packet_sizes[(i // 2) % len(packet_sizes)]
744 cls.extend_packet(p, size, cls.padding)
745 info.data = p
746
747 @classmethod
748 def create_fragments(cls):
749 infos = cls._packet_infos
750 cls.pkt_infos = []
751 for index, info in six.iteritems(infos):
752 p = info.data
753 # cls.logger.debug(ppp("Packet:",
754 # p.__class__(scapy.compat.raw(p))))
755 fragments_400 = fragment_rfc791(p, 400)
756 cls.pkt_infos.append((index, fragments_400))
757 cls.fragments_400 = [
758 x for (_, frags) in cls.pkt_infos for x in frags]
759 cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, " %
760 (len(infos), len(cls.fragments_400)))
761
762 def verify_capture(self, capture, dropped_packet_indexes=[]):
763 """Verify captured packet stream.
764
765 :param list capture: Captured packet stream.
766 """
767 info = None
768 seen = set()
769 for packet in capture:
770 try:
771 self.logger.debug(ppp("Got packet:", packet))
772 ip = packet[IP]
773 udp = packet[UDP]
774 payload_info = self.payload_to_info(packet[Raw])
775 packet_index = payload_info.index
776 self.assertTrue(
777 packet_index not in dropped_packet_indexes,
778 ppp("Packet received, but should be dropped:", packet))
779 if packet_index in seen:
780 raise Exception(ppp("Duplicate packet received", packet))
781 seen.add(packet_index)
782 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
783 info = self._packet_infos[packet_index]
784 self.assertTrue(info is not None)
785 self.assertEqual(packet_index, info.index)
786 saved_packet = info.data
787 self.assertEqual(ip.src, saved_packet[IP].src)
788 self.assertEqual(ip.dst, saved_packet[IP].dst)
789 self.assertEqual(udp.payload, saved_packet[UDP].payload)
790 except Exception:
791 self.logger.error(ppp("Unexpected or invalid packet:", packet))
792 raise
793 for index in self._packet_infos:
794 self.assertTrue(index in seen or index in dropped_packet_indexes,
795 "Packet with packet_index %d not received" % index)
796
797 def send_packets(self, packets):
798 for counter in range(worker_count):
799 if 0 == len(packets[counter]):
800 continue
801 send_if = self.send_ifs[counter]
802 send_if.add_stream(
803 (Ether(dst=send_if.local_mac, src=send_if.remote_mac) / x
804 for x in packets[counter]),
805 worker=counter)
806 self.pg_start()
807
808 def test_worker_conflict(self):
809 """ 1st and FO=0 fragments on different workers """
810
811 # in first wave we send fragments which don't start at offset 0
812 # then we send fragments with offset 0 on a different thread
813 # then the rest of packets on a random thread
814 first_packets = [[] for n in range(worker_count)]
815 second_packets = [[] for n in range(worker_count)]
816 rest_of_packets = [[] for n in range(worker_count)]
817 for (_, p) in self.pkt_infos:
818 wi = randrange(worker_count)
819 second_packets[wi].append(p[0])
820 if len(p) <= 1:
821 continue
822 wi2 = wi
823 while wi2 == wi:
824 wi2 = randrange(worker_count)
825 first_packets[wi2].append(p[1])
826 wi3 = randrange(worker_count)
827 rest_of_packets[wi3].extend(p[2:])
828
829 self.pg_enable_capture()
830 self.send_packets(first_packets)
831 self.send_packets(second_packets)
832 self.send_packets(rest_of_packets)
833
834 packets = self.dst_if.get_capture(len(self.pkt_infos))
835 self.verify_capture(packets)
836 for send_if in self.send_ifs:
837 send_if.assert_nothing_captured()
838
Klement Sekera68bae5b2019-10-10 18:57:34 +0000839 self.logger.debug(self.vapi.ppcli("show trace"))
840 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
841 self.logger.debug(self.vapi.ppcli("show buffers"))
842 self.vapi.cli("clear trace")
843
Klement Sekera630ab582019-07-19 09:14:19 +0000844 self.pg_enable_capture()
845 self.send_packets(first_packets)
846 self.send_packets(second_packets)
847 self.send_packets(rest_of_packets)
848
849 packets = self.dst_if.get_capture(len(self.pkt_infos))
850 self.verify_capture(packets)
851 for send_if in self.send_ifs:
852 send_if.assert_nothing_captured()
853
854
Klement Sekera947a85c2019-07-24 12:40:37 +0000855class TestIPv6Reassembly(VppTestCase):
Klement Sekera75e7d132017-09-20 08:26:30 +0200856 """ IPv6 Reassembly """
857
858 @classmethod
859 def setUpClass(cls):
860 super(TestIPv6Reassembly, cls).setUpClass()
861
Klement Sekera4c533132018-02-22 11:41:12 +0100862 cls.create_pg_interfaces([0, 1])
863 cls.src_if = cls.pg0
864 cls.dst_if = cls.pg1
Klement Sekera75e7d132017-09-20 08:26:30 +0200865
866 # setup all interfaces
867 for i in cls.pg_interfaces:
868 i.admin_up()
869 i.config_ip6()
870 i.resolve_ndp()
871
Klement Sekera75e7d132017-09-20 08:26:30 +0200872 # packet sizes
873 cls.packet_sizes = [64, 512, 1518, 9018]
874 cls.padding = " abcdefghijklmn"
875 cls.create_stream(cls.packet_sizes)
876 cls.create_fragments()
877
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -0700878 @classmethod
879 def tearDownClass(cls):
880 super(TestIPv6Reassembly, cls).tearDownClass()
881
Klement Sekera75e7d132017-09-20 08:26:30 +0200882 def setUp(self):
883 """ Test setup - force timeout on existing reassemblies """
884 super(TestIPv6Reassembly, self).setUp()
Klement Sekera4c533132018-02-22 11:41:12 +0100885 self.vapi.ip_reassembly_enable_disable(
886 sw_if_index=self.src_if.sw_if_index, enable_ip6=True)
Klement Sekera75e7d132017-09-20 08:26:30 +0200887 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +0200888 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +0200889 expire_walk_interval_ms=10, is_ip6=1)
890 self.sleep(.25)
891 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +0200892 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +0200893 expire_walk_interval_ms=10000, is_ip6=1)
Klement Sekera896c8962019-06-24 11:52:49 +0000894 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
Klement Sekeracae98b72019-02-19 13:53:43 +0100895 self.logger.debug(self.vapi.ppcli("show buffers"))
Klement Sekera75e7d132017-09-20 08:26:30 +0200896
897 def tearDown(self):
898 super(TestIPv6Reassembly, self).tearDown()
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -0700899
900 def show_commands_at_teardown(self):
Klement Sekera896c8962019-06-24 11:52:49 +0000901 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
Klement Sekeracae98b72019-02-19 13:53:43 +0100902 self.logger.debug(self.vapi.ppcli("show buffers"))
Klement Sekera75e7d132017-09-20 08:26:30 +0200903
904 @classmethod
905 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
906 """Create input packet stream for defined interface.
907
908 :param list packet_sizes: Required packet sizes.
909 """
910 for i in range(0, packet_count):
Klement Sekera4c533132018-02-22 11:41:12 +0100911 info = cls.create_packet_info(cls.src_if, cls.src_if)
Klement Sekera75e7d132017-09-20 08:26:30 +0200912 payload = cls.info_to_payload(info)
Klement Sekera4c533132018-02-22 11:41:12 +0100913 p = (Ether(dst=cls.src_if.local_mac, src=cls.src_if.remote_mac) /
914 IPv6(src=cls.src_if.remote_ip6,
915 dst=cls.dst_if.remote_ip6) /
916 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +0200917 Raw(payload))
918 size = packet_sizes[(i // 2) % len(packet_sizes)]
919 cls.extend_packet(p, size, cls.padding)
920 info.data = p
921
922 @classmethod
923 def create_fragments(cls):
924 infos = cls._packet_infos
925 cls.pkt_infos = []
Paul Vinciguerraf1f2aa62018-11-25 08:36:47 -0800926 for index, info in six.iteritems(infos):
Klement Sekera75e7d132017-09-20 08:26:30 +0200927 p = info.data
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -0700928 # cls.logger.debug(ppp("Packet:",
929 # p.__class__(scapy.compat.raw(p))))
Klement Sekera75e7d132017-09-20 08:26:30 +0200930 fragments_400 = fragment_rfc8200(p, info.index, 400)
931 fragments_300 = fragment_rfc8200(p, info.index, 300)
932 cls.pkt_infos.append((index, fragments_400, fragments_300))
933 cls.fragments_400 = [
934 x for _, frags, _ in cls.pkt_infos for x in frags]
935 cls.fragments_300 = [
936 x for _, _, frags in cls.pkt_infos for x in frags]
937 cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, "
938 "and %s 300-byte fragments" %
939 (len(infos), len(cls.fragments_400),
940 len(cls.fragments_300)))
941
Klement Sekera947a85c2019-07-24 12:40:37 +0000942 def verify_capture(self, capture, dropped_packet_indexes=[]):
943 """Verify captured packet strea .
944
945 :param list capture: Captured packet stream.
946 """
947 info = None
948 seen = set()
949 for packet in capture:
950 try:
951 self.logger.debug(ppp("Got packet:", packet))
952 ip = packet[IPv6]
953 udp = packet[UDP]
954 payload_info = self.payload_to_info(packet[Raw])
955 packet_index = payload_info.index
956 self.assertTrue(
957 packet_index not in dropped_packet_indexes,
958 ppp("Packet received, but should be dropped:", packet))
959 if packet_index in seen:
960 raise Exception(ppp("Duplicate packet received", packet))
961 seen.add(packet_index)
962 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
963 info = self._packet_infos[packet_index]
964 self.assertTrue(info is not None)
965 self.assertEqual(packet_index, info.index)
966 saved_packet = info.data
967 self.assertEqual(ip.src, saved_packet[IPv6].src)
968 self.assertEqual(ip.dst, saved_packet[IPv6].dst)
969 self.assertEqual(udp.payload, saved_packet[UDP].payload)
970 except Exception:
971 self.logger.error(ppp("Unexpected or invalid packet:", packet))
972 raise
973 for index in self._packet_infos:
974 self.assertTrue(index in seen or index in dropped_packet_indexes,
975 "Packet with packet_index %d not received" % index)
976
977 def test_reassembly(self):
Klement Sekera75e7d132017-09-20 08:26:30 +0200978 """ basic reassembly """
979
Klement Sekera947a85c2019-07-24 12:40:37 +0000980 self.pg_enable_capture()
981 self.src_if.add_stream(self.fragments_400)
982 self.pg_start()
983
984 packets = self.dst_if.get_capture(len(self.pkt_infos))
985 self.verify_capture(packets)
986 self.src_if.assert_nothing_captured()
987
988 # run it all again to verify correctness
989 self.pg_enable_capture()
990 self.src_if.add_stream(self.fragments_400)
991 self.pg_start()
992
993 packets = self.dst_if.get_capture(len(self.pkt_infos))
994 self.verify_capture(packets)
995 self.src_if.assert_nothing_captured()
996
Klement Sekera769145c2019-03-06 11:59:57 +0100997 def test_buffer_boundary(self):
998 """ fragment header crossing buffer boundary """
999
1000 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1001 IPv6(src=self.src_if.remote_ip6,
1002 dst=self.src_if.local_ip6) /
1003 IPv6ExtHdrHopByHop(
1004 options=[HBHOptUnknown(otype=0xff, optlen=0)] * 1000) /
1005 IPv6ExtHdrFragment(m=1) /
1006 UDP(sport=1234, dport=5678) /
1007 Raw())
1008 self.pg_enable_capture()
1009 self.src_if.add_stream([p])
1010 self.pg_start()
1011 self.src_if.assert_nothing_captured()
1012 self.dst_if.assert_nothing_captured()
1013
Klement Sekera947a85c2019-07-24 12:40:37 +00001014 def test_reversed(self):
Klement Sekera75e7d132017-09-20 08:26:30 +02001015 """ reverse order reassembly """
1016
Klement Sekera947a85c2019-07-24 12:40:37 +00001017 fragments = list(self.fragments_400)
1018 fragments.reverse()
1019
1020 self.pg_enable_capture()
1021 self.src_if.add_stream(fragments)
1022 self.pg_start()
1023
1024 packets = self.dst_if.get_capture(len(self.pkt_infos))
1025 self.verify_capture(packets)
1026 self.src_if.assert_nothing_captured()
1027
1028 # run it all again to verify correctness
1029 self.pg_enable_capture()
1030 self.src_if.add_stream(fragments)
1031 self.pg_start()
1032
1033 packets = self.dst_if.get_capture(len(self.pkt_infos))
1034 self.verify_capture(packets)
1035 self.src_if.assert_nothing_captured()
1036
1037 def test_random(self):
Klement Sekera75e7d132017-09-20 08:26:30 +02001038 """ random order reassembly """
1039
Klement Sekera947a85c2019-07-24 12:40:37 +00001040 fragments = list(self.fragments_400)
1041 shuffle(fragments)
1042
1043 self.pg_enable_capture()
1044 self.src_if.add_stream(fragments)
1045 self.pg_start()
1046
1047 packets = self.dst_if.get_capture(len(self.pkt_infos))
1048 self.verify_capture(packets)
1049 self.src_if.assert_nothing_captured()
1050
1051 # run it all again to verify correctness
1052 self.pg_enable_capture()
1053 self.src_if.add_stream(fragments)
1054 self.pg_start()
1055
1056 packets = self.dst_if.get_capture(len(self.pkt_infos))
1057 self.verify_capture(packets)
1058 self.src_if.assert_nothing_captured()
1059
1060 def test_duplicates(self):
Klement Sekera75e7d132017-09-20 08:26:30 +02001061 """ duplicate fragments """
1062
1063 fragments = [
1064 x for (_, frags, _) in self.pkt_infos
1065 for x in frags
1066 for _ in range(0, min(2, len(frags)))
1067 ]
Klement Sekera947a85c2019-07-24 12:40:37 +00001068
1069 self.pg_enable_capture()
1070 self.src_if.add_stream(fragments)
1071 self.pg_start()
1072
1073 packets = self.dst_if.get_capture(len(self.pkt_infos))
1074 self.verify_capture(packets)
1075 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +02001076
Klement Sekera3a343d42019-05-16 14:35:46 +02001077 def test_long_fragment_chain(self):
1078 """ long fragment chain """
1079
1080 error_cnt_str = \
Klement Sekera896c8962019-06-24 11:52:49 +00001081 "/err/ip6-full-reassembly-feature/fragment chain too long (drop)"
Klement Sekera3a343d42019-05-16 14:35:46 +02001082
Klement Sekera34641f22019-05-22 20:18:26 +02001083 error_cnt = self.statistics.get_err_counter(error_cnt_str)
Klement Sekera3a343d42019-05-16 14:35:46 +02001084
1085 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
1086 max_reassembly_length=3,
1087 expire_walk_interval_ms=50, is_ip6=1)
1088
1089 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1090 IPv6(src=self.src_if.remote_ip6,
1091 dst=self.dst_if.remote_ip6) /
1092 UDP(sport=1234, dport=5678) /
1093 Raw("X" * 1000))
1094 frags = fragment_rfc8200(p, 1, 300) + fragment_rfc8200(p, 2, 500)
1095
1096 self.pg_enable_capture()
1097 self.src_if.add_stream(frags)
1098 self.pg_start()
1099
1100 self.dst_if.get_capture(1)
Klement Sekera34641f22019-05-22 20:18:26 +02001101 self.assert_error_counter_equal(error_cnt_str, error_cnt + 1)
Klement Sekera3a343d42019-05-16 14:35:46 +02001102
Klement Sekera75e7d132017-09-20 08:26:30 +02001103 def test_overlap1(self):
Klement Sekera947a85c2019-07-24 12:40:37 +00001104 """ overlapping fragments case #1 """
Klement Sekera75e7d132017-09-20 08:26:30 +02001105
1106 fragments = []
1107 for _, frags_400, frags_300 in self.pkt_infos:
1108 if len(frags_300) == 1:
1109 fragments.extend(frags_400)
1110 else:
1111 for i, j in zip(frags_300, frags_400):
1112 fragments.extend(i)
1113 fragments.extend(j)
1114
1115 dropped_packet_indexes = set(
1116 index for (index, _, frags) in self.pkt_infos if len(frags) > 1
1117 )
1118
1119 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +01001120 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +02001121 self.pg_start()
1122
Klement Sekera4c533132018-02-22 11:41:12 +01001123 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +02001124 len(self.pkt_infos) - len(dropped_packet_indexes))
Klement Sekera947a85c2019-07-24 12:40:37 +00001125 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +01001126 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +02001127
1128 def test_overlap2(self):
Klement Sekera947a85c2019-07-24 12:40:37 +00001129 """ overlapping fragments case #2 """
Klement Sekera75e7d132017-09-20 08:26:30 +02001130
1131 fragments = []
Klement Sekera4c533132018-02-22 11:41:12 +01001132 for _, frags_400, frags_300 in self.pkt_infos:
Klement Sekera75e7d132017-09-20 08:26:30 +02001133 if len(frags_400) == 1:
1134 fragments.extend(frags_400)
1135 else:
1136 # care must be taken here so that there are no fragments
1137 # received by vpp after reassembly is finished, otherwise
1138 # new reassemblies will be started and packet generator will
1139 # freak out when it detects unfreed buffers
Klement Sekera4c533132018-02-22 11:41:12 +01001140 zipped = zip(frags_400, frags_300)
Paul Vinciguerrac7834e02019-03-02 10:43:05 -08001141 for i, j in zipped:
Klement Sekera75e7d132017-09-20 08:26:30 +02001142 fragments.extend(i)
1143 fragments.extend(j)
Paul Vinciguerrac7834e02019-03-02 10:43:05 -08001144 fragments.pop()
Klement Sekera75e7d132017-09-20 08:26:30 +02001145
1146 dropped_packet_indexes = set(
1147 index for (index, _, frags) in self.pkt_infos if len(frags) > 1
1148 )
1149
1150 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +01001151 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +02001152 self.pg_start()
1153
Klement Sekera4c533132018-02-22 11:41:12 +01001154 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +02001155 len(self.pkt_infos) - len(dropped_packet_indexes))
Klement Sekera947a85c2019-07-24 12:40:37 +00001156 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +01001157 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +02001158
Klement Sekera947a85c2019-07-24 12:40:37 +00001159 def test_timeout_inline(self):
Klement Sekera75e7d132017-09-20 08:26:30 +02001160 """ timeout (inline) """
1161
1162 dropped_packet_indexes = set(
1163 index for (index, frags, _) in self.pkt_infos if len(frags) > 1
1164 )
1165
Klement Sekera947a85c2019-07-24 12:40:37 +00001166 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
1167 max_reassembly_length=3,
1168 expire_walk_interval_ms=10000, is_ip6=1)
1169
1170 self.pg_enable_capture()
1171 self.src_if.add_stream(self.fragments_400)
1172 self.pg_start()
1173
1174 packets = self.dst_if.get_capture(
1175 len(self.pkt_infos) - len(dropped_packet_indexes))
1176 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +01001177 pkts = self.src_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +02001178 expected_count=len(dropped_packet_indexes))
1179 for icmp in pkts:
1180 self.assertIn(ICMPv6TimeExceeded, icmp)
1181 self.assertIn(IPv6ExtHdrFragment, icmp)
1182 self.assertIn(icmp[IPv6ExtHdrFragment].id, dropped_packet_indexes)
1183 dropped_packet_indexes.remove(icmp[IPv6ExtHdrFragment].id)
1184
1185 def test_timeout_cleanup(self):
1186 """ timeout (cleanup) """
1187
1188 # whole packets + fragmented packets sans last fragment
1189 fragments = [
1190 x for (_, frags_400, _) in self.pkt_infos
1191 for x in frags_400[:-1 if len(frags_400) > 1 else None]
1192 ]
1193
1194 # last fragments for fragmented packets
1195 fragments2 = [frags_400[-1]
1196 for (_, frags_400, _) in self.pkt_infos
1197 if len(frags_400) > 1]
1198
1199 dropped_packet_indexes = set(
1200 index for (index, frags_400, _) in self.pkt_infos
1201 if len(frags_400) > 1)
1202
1203 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +02001204 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +02001205 expire_walk_interval_ms=50)
1206
1207 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +02001208 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +02001209 expire_walk_interval_ms=50, is_ip6=1)
1210
1211 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +01001212 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +02001213 self.pg_start()
1214
1215 self.sleep(.25, "wait before sending rest of fragments")
1216
Klement Sekera4c533132018-02-22 11:41:12 +01001217 self.src_if.add_stream(fragments2)
Klement Sekera75e7d132017-09-20 08:26:30 +02001218 self.pg_start()
Klement Sekera75e7d132017-09-20 08:26:30 +02001219
Klement Sekera4c533132018-02-22 11:41:12 +01001220 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +02001221 len(self.pkt_infos) - len(dropped_packet_indexes))
Klement Sekera947a85c2019-07-24 12:40:37 +00001222 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +01001223 pkts = self.src_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +02001224 expected_count=len(dropped_packet_indexes))
1225 for icmp in pkts:
1226 self.assertIn(ICMPv6TimeExceeded, icmp)
1227 self.assertIn(IPv6ExtHdrFragment, icmp)
1228 self.assertIn(icmp[IPv6ExtHdrFragment].id, dropped_packet_indexes)
1229 dropped_packet_indexes.remove(icmp[IPv6ExtHdrFragment].id)
1230
Klement Sekera947a85c2019-07-24 12:40:37 +00001231 def test_disabled(self):
Klement Sekera75e7d132017-09-20 08:26:30 +02001232 """ reassembly disabled """
1233
1234 dropped_packet_indexes = set(
1235 index for (index, frags_400, _) in self.pkt_infos
1236 if len(frags_400) > 1)
Klement Sekera947a85c2019-07-24 12:40:37 +00001237
1238 self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=0,
1239 max_reassembly_length=3,
1240 expire_walk_interval_ms=10000, is_ip6=1)
1241
1242 self.pg_enable_capture()
1243 self.src_if.add_stream(self.fragments_400)
1244 self.pg_start()
1245
1246 packets = self.dst_if.get_capture(
1247 len(self.pkt_infos) - len(dropped_packet_indexes))
1248 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +01001249 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +02001250
1251 def test_missing_upper(self):
1252 """ missing upper layer """
Klement Sekera4c533132018-02-22 11:41:12 +01001253 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1254 IPv6(src=self.src_if.remote_ip6,
1255 dst=self.src_if.local_ip6) /
1256 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +02001257 Raw())
1258 self.extend_packet(p, 1000, self.padding)
1259 fragments = fragment_rfc8200(p, 1, 500)
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07001260 bad_fragment = p.__class__(scapy.compat.raw(fragments[1]))
Klement Sekera75e7d132017-09-20 08:26:30 +02001261 bad_fragment[IPv6ExtHdrFragment].nh = 59
1262 bad_fragment[IPv6ExtHdrFragment].offset = 0
1263 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +01001264 self.src_if.add_stream([bad_fragment])
Klement Sekera75e7d132017-09-20 08:26:30 +02001265 self.pg_start()
Klement Sekera4c533132018-02-22 11:41:12 +01001266 pkts = self.src_if.get_capture(expected_count=1)
Klement Sekera75e7d132017-09-20 08:26:30 +02001267 icmp = pkts[0]
1268 self.assertIn(ICMPv6ParamProblem, icmp)
1269 self.assert_equal(icmp[ICMPv6ParamProblem].code, 3, "ICMP code")
1270
1271 def test_invalid_frag_size(self):
1272 """ fragment size not a multiple of 8 """
Klement Sekera4c533132018-02-22 11:41:12 +01001273 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1274 IPv6(src=self.src_if.remote_ip6,
1275 dst=self.src_if.local_ip6) /
1276 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +02001277 Raw())
1278 self.extend_packet(p, 1000, self.padding)
1279 fragments = fragment_rfc8200(p, 1, 500)
1280 bad_fragment = fragments[0]
1281 self.extend_packet(bad_fragment, len(bad_fragment) + 5)
1282 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +01001283 self.src_if.add_stream([bad_fragment])
Klement Sekera75e7d132017-09-20 08:26:30 +02001284 self.pg_start()
Klement Sekera4c533132018-02-22 11:41:12 +01001285 pkts = self.src_if.get_capture(expected_count=1)
Klement Sekera75e7d132017-09-20 08:26:30 +02001286 icmp = pkts[0]
1287 self.assertIn(ICMPv6ParamProblem, icmp)
1288 self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code")
1289
1290 def test_invalid_packet_size(self):
1291 """ total packet size > 65535 """
Klement Sekera4c533132018-02-22 11:41:12 +01001292 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1293 IPv6(src=self.src_if.remote_ip6,
1294 dst=self.src_if.local_ip6) /
1295 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +02001296 Raw())
1297 self.extend_packet(p, 1000, self.padding)
1298 fragments = fragment_rfc8200(p, 1, 500)
1299 bad_fragment = fragments[1]
1300 bad_fragment[IPv6ExtHdrFragment].offset = 65500
1301 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +01001302 self.src_if.add_stream([bad_fragment])
Klement Sekera75e7d132017-09-20 08:26:30 +02001303 self.pg_start()
Klement Sekera4c533132018-02-22 11:41:12 +01001304 pkts = self.src_if.get_capture(expected_count=1)
Klement Sekera75e7d132017-09-20 08:26:30 +02001305 icmp = pkts[0]
1306 self.assertIn(ICMPv6ParamProblem, icmp)
1307 self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code")
1308
1309
Klement Sekera630ab582019-07-19 09:14:19 +00001310class TestIPv6MWReassembly(VppTestCase):
1311 """ IPv6 Reassembly (multiple workers) """
1312 worker_config = "workers %d" % worker_count
1313
1314 @classmethod
1315 def setUpClass(cls):
1316 super(TestIPv6MWReassembly, cls).setUpClass()
1317
1318 cls.create_pg_interfaces(range(worker_count+1))
1319 cls.src_if = cls.pg0
1320 cls.send_ifs = cls.pg_interfaces[:-1]
1321 cls.dst_if = cls.pg_interfaces[-1]
1322
1323 # setup all interfaces
1324 for i in cls.pg_interfaces:
1325 i.admin_up()
1326 i.config_ip6()
1327 i.resolve_ndp()
1328
1329 # packets sizes reduced here because we are generating packets without
1330 # Ethernet headers, which are added later (diff fragments go via
1331 # different interfaces)
1332 cls.packet_sizes = [64-len(Ether()), 512-len(Ether()),
1333 1518-len(Ether()), 9018-len(Ether())]
1334 cls.padding = " abcdefghijklmn"
1335 cls.create_stream(cls.packet_sizes)
1336 cls.create_fragments()
1337
1338 @classmethod
1339 def tearDownClass(cls):
1340 super(TestIPv6MWReassembly, cls).tearDownClass()
1341
1342 def setUp(self):
1343 """ Test setup - force timeout on existing reassemblies """
1344 super(TestIPv6MWReassembly, self).setUp()
1345 for intf in self.send_ifs:
1346 self.vapi.ip_reassembly_enable_disable(
1347 sw_if_index=intf.sw_if_index, enable_ip6=True)
1348 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
1349 max_reassembly_length=1000,
1350 expire_walk_interval_ms=10, is_ip6=1)
1351 self.sleep(.25)
1352 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
1353 max_reassembly_length=1000,
1354 expire_walk_interval_ms=1000, is_ip6=1)
1355
1356 def tearDown(self):
1357 super(TestIPv6MWReassembly, self).tearDown()
1358
1359 def show_commands_at_teardown(self):
Klement Sekera896c8962019-06-24 11:52:49 +00001360 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
Klement Sekera630ab582019-07-19 09:14:19 +00001361 self.logger.debug(self.vapi.ppcli("show buffers"))
1362
1363 @classmethod
1364 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
1365 """Create input packet stream
1366
1367 :param list packet_sizes: Required packet sizes.
1368 """
1369 for i in range(0, packet_count):
1370 info = cls.create_packet_info(cls.src_if, cls.src_if)
1371 payload = cls.info_to_payload(info)
1372 p = (IPv6(src=cls.src_if.remote_ip6,
1373 dst=cls.dst_if.remote_ip6) /
1374 UDP(sport=1234, dport=5678) /
1375 Raw(payload))
1376 size = packet_sizes[(i // 2) % len(packet_sizes)]
1377 cls.extend_packet(p, size, cls.padding)
1378 info.data = p
1379
1380 @classmethod
1381 def create_fragments(cls):
1382 infos = cls._packet_infos
1383 cls.pkt_infos = []
1384 for index, info in six.iteritems(infos):
1385 p = info.data
1386 # cls.logger.debug(ppp("Packet:",
1387 # p.__class__(scapy.compat.raw(p))))
1388 fragments_400 = fragment_rfc8200(p, index, 400)
1389 cls.pkt_infos.append((index, fragments_400))
1390 cls.fragments_400 = [
1391 x for (_, frags) in cls.pkt_infos for x in frags]
1392 cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, " %
1393 (len(infos), len(cls.fragments_400)))
1394
1395 def verify_capture(self, capture, dropped_packet_indexes=[]):
1396 """Verify captured packet strea .
1397
1398 :param list capture: Captured packet stream.
1399 """
1400 info = None
1401 seen = set()
1402 for packet in capture:
1403 try:
1404 self.logger.debug(ppp("Got packet:", packet))
1405 ip = packet[IPv6]
1406 udp = packet[UDP]
1407 payload_info = self.payload_to_info(packet[Raw])
1408 packet_index = payload_info.index
1409 self.assertTrue(
1410 packet_index not in dropped_packet_indexes,
1411 ppp("Packet received, but should be dropped:", packet))
1412 if packet_index in seen:
1413 raise Exception(ppp("Duplicate packet received", packet))
1414 seen.add(packet_index)
1415 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
1416 info = self._packet_infos[packet_index]
1417 self.assertTrue(info is not None)
1418 self.assertEqual(packet_index, info.index)
1419 saved_packet = info.data
1420 self.assertEqual(ip.src, saved_packet[IPv6].src)
1421 self.assertEqual(ip.dst, saved_packet[IPv6].dst)
1422 self.assertEqual(udp.payload, saved_packet[UDP].payload)
1423 except Exception:
1424 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1425 raise
1426 for index in self._packet_infos:
1427 self.assertTrue(index in seen or index in dropped_packet_indexes,
1428 "Packet with packet_index %d not received" % index)
1429
1430 def send_packets(self, packets):
1431 for counter in range(worker_count):
1432 if 0 == len(packets[counter]):
1433 continue
1434 send_if = self.send_ifs[counter]
1435 send_if.add_stream(
1436 (Ether(dst=send_if.local_mac, src=send_if.remote_mac) / x
1437 for x in packets[counter]),
1438 worker=counter)
1439 self.pg_start()
1440
1441 def test_worker_conflict(self):
1442 """ 1st and FO=0 fragments on different workers """
1443
1444 # in first wave we send fragments which don't start at offset 0
1445 # then we send fragments with offset 0 on a different thread
1446 # then the rest of packets on a random thread
1447 first_packets = [[] for n in range(worker_count)]
1448 second_packets = [[] for n in range(worker_count)]
1449 rest_of_packets = [[] for n in range(worker_count)]
1450 for (_, p) in self.pkt_infos:
1451 wi = randrange(worker_count)
1452 second_packets[wi].append(p[0])
1453 if len(p) <= 1:
1454 continue
1455 wi2 = wi
1456 while wi2 == wi:
1457 wi2 = randrange(worker_count)
1458 first_packets[wi2].append(p[1])
1459 wi3 = randrange(worker_count)
1460 rest_of_packets[wi3].extend(p[2:])
1461
1462 self.pg_enable_capture()
1463 self.send_packets(first_packets)
1464 self.send_packets(second_packets)
1465 self.send_packets(rest_of_packets)
1466
1467 packets = self.dst_if.get_capture(len(self.pkt_infos))
1468 self.verify_capture(packets)
1469 for send_if in self.send_ifs:
1470 send_if.assert_nothing_captured()
1471
Klement Sekera68bae5b2019-10-10 18:57:34 +00001472 self.logger.debug(self.vapi.ppcli("show trace"))
1473 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
1474 self.logger.debug(self.vapi.ppcli("show buffers"))
1475 self.vapi.cli("clear trace")
1476
Klement Sekera630ab582019-07-19 09:14:19 +00001477 self.pg_enable_capture()
1478 self.send_packets(first_packets)
1479 self.send_packets(second_packets)
1480 self.send_packets(rest_of_packets)
1481
1482 packets = self.dst_if.get_capture(len(self.pkt_infos))
1483 self.verify_capture(packets)
1484 for send_if in self.send_ifs:
1485 send_if.assert_nothing_captured()
1486
1487
Klement Sekerade34c352019-06-25 11:19:22 +00001488class TestIPv6SVReassembly(VppTestCase):
1489 """ IPv6 Shallow Virtual Reassembly """
1490
1491 @classmethod
1492 def setUpClass(cls):
1493 super(TestIPv6SVReassembly, cls).setUpClass()
1494
1495 cls.create_pg_interfaces([0, 1])
1496 cls.src_if = cls.pg0
1497 cls.dst_if = cls.pg1
1498
1499 # setup all interfaces
1500 for i in cls.pg_interfaces:
1501 i.admin_up()
1502 i.config_ip6()
1503 i.resolve_ndp()
1504
1505 def setUp(self):
1506 """ Test setup - force timeout on existing reassemblies """
1507 super(TestIPv6SVReassembly, self).setUp()
1508 self.vapi.ip_reassembly_enable_disable(
1509 sw_if_index=self.src_if.sw_if_index, enable_ip6=True,
1510 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL)
1511 self.vapi.ip_reassembly_set(
1512 timeout_ms=0, max_reassemblies=1000,
1513 max_reassembly_length=1000,
1514 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
1515 expire_walk_interval_ms=10, is_ip6=1)
1516 self.sleep(.25)
1517 self.vapi.ip_reassembly_set(
1518 timeout_ms=1000000, max_reassemblies=1000,
1519 max_reassembly_length=1000,
1520 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
1521 expire_walk_interval_ms=10000, is_ip6=1)
1522
1523 def tearDown(self):
1524 super(TestIPv6SVReassembly, self).tearDown()
1525 self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details"))
1526 self.logger.debug(self.vapi.ppcli("show buffers"))
1527
1528 def test_basic(self):
1529 """ basic reassembly """
1530 payload_len = 1000
1531 payload = ""
1532 counter = 0
1533 while len(payload) < payload_len:
1534 payload += "%u " % counter
1535 counter += 1
1536
1537 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1538 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1539 UDP(sport=1234, dport=5678) /
1540 Raw(payload))
1541 fragments = fragment_rfc8200(p, 1, payload_len/4)
1542
1543 # send fragment #2 - should be cached inside reassembly
1544 self.pg_enable_capture()
1545 self.src_if.add_stream(fragments[1])
1546 self.pg_start()
1547 self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details"))
1548 self.logger.debug(self.vapi.ppcli("show buffers"))
1549 self.logger.debug(self.vapi.ppcli("show trace"))
1550 self.dst_if.assert_nothing_captured()
1551
1552 # send fragment #1 - reassembly is finished now and both fragments
1553 # forwarded
1554 self.pg_enable_capture()
1555 self.src_if.add_stream(fragments[0])
1556 self.pg_start()
1557 self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details"))
1558 self.logger.debug(self.vapi.ppcli("show buffers"))
1559 self.logger.debug(self.vapi.ppcli("show trace"))
1560 c = self.dst_if.get_capture(2)
1561 for sent, recvd in zip([fragments[1], fragments[0]], c):
1562 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
1563 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
1564 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
1565
1566 # send rest of fragments - should be immediately forwarded
1567 self.pg_enable_capture()
1568 self.src_if.add_stream(fragments[2:])
1569 self.pg_start()
1570 c = self.dst_if.get_capture(len(fragments[2:]))
1571 for sent, recvd in zip(fragments[2:], c):
1572 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
1573 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
1574 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
1575
1576 def test_timeout(self):
1577 """ reassembly timeout """
1578 payload_len = 1000
1579 payload = ""
1580 counter = 0
1581 while len(payload) < payload_len:
1582 payload += "%u " % counter
1583 counter += 1
1584
1585 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1586 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1587 UDP(sport=1234, dport=5678) /
1588 Raw(payload))
1589 fragments = fragment_rfc8200(p, 1, payload_len/4)
1590
1591 self.vapi.ip_reassembly_set(
1592 timeout_ms=100, max_reassemblies=1000,
1593 max_reassembly_length=1000,
1594 expire_walk_interval_ms=50,
1595 is_ip6=1,
1596 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL)
1597
1598 # send fragments #2 and #1 - should be forwarded
1599 self.pg_enable_capture()
1600 self.src_if.add_stream(fragments[0:2])
1601 self.pg_start()
1602 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
1603 self.logger.debug(self.vapi.ppcli("show buffers"))
1604 self.logger.debug(self.vapi.ppcli("show trace"))
1605 c = self.dst_if.get_capture(2)
1606 for sent, recvd in zip([fragments[1], fragments[0]], c):
1607 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
1608 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
1609 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
1610
1611 # wait for cleanup
1612 self.sleep(.25, "wait before sending rest of fragments")
1613
1614 # send rest of fragments - shouldn't be forwarded
1615 self.pg_enable_capture()
1616 self.src_if.add_stream(fragments[2:])
1617 self.pg_start()
1618 self.dst_if.assert_nothing_captured()
1619
1620 def test_lru(self):
1621 """ reassembly reuses LRU element """
1622
1623 self.vapi.ip_reassembly_set(
1624 timeout_ms=1000000, max_reassemblies=1,
1625 max_reassembly_length=1000,
1626 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
1627 is_ip6=1, expire_walk_interval_ms=10000)
1628
1629 payload_len = 1000
1630 payload = ""
1631 counter = 0
1632 while len(payload) < payload_len:
1633 payload += "%u " % counter
1634 counter += 1
1635
1636 packet_count = 10
1637
1638 fragments = [f
1639 for i in range(packet_count)
1640 for p in (Ether(dst=self.src_if.local_mac,
1641 src=self.src_if.remote_mac) /
1642 IPv6(src=self.src_if.remote_ip6,
1643 dst=self.dst_if.remote_ip6) /
1644 UDP(sport=1234, dport=5678) /
1645 Raw(payload))
1646 for f in fragment_rfc8200(p, i, payload_len/4)]
1647
1648 self.pg_enable_capture()
1649 self.src_if.add_stream(fragments)
1650 self.pg_start()
1651 c = self.dst_if.get_capture(len(fragments))
1652 for sent, recvd in zip(fragments, c):
1653 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
1654 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
1655 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
1656
1657
Juraj Sloboda3048b632018-10-02 11:13:53 +02001658class TestIPv4ReassemblyLocalNode(VppTestCase):
1659 """ IPv4 Reassembly for packets coming to ip4-local node """
1660
1661 @classmethod
1662 def setUpClass(cls):
1663 super(TestIPv4ReassemblyLocalNode, cls).setUpClass()
1664
1665 cls.create_pg_interfaces([0])
1666 cls.src_dst_if = cls.pg0
1667
1668 # setup all interfaces
1669 for i in cls.pg_interfaces:
1670 i.admin_up()
1671 i.config_ip4()
1672 i.resolve_arp()
1673
1674 cls.padding = " abcdefghijklmn"
1675 cls.create_stream()
1676 cls.create_fragments()
1677
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07001678 @classmethod
1679 def tearDownClass(cls):
1680 super(TestIPv4ReassemblyLocalNode, cls).tearDownClass()
1681
Juraj Sloboda3048b632018-10-02 11:13:53 +02001682 def setUp(self):
1683 """ Test setup - force timeout on existing reassemblies """
1684 super(TestIPv4ReassemblyLocalNode, self).setUp()
1685 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +02001686 max_reassembly_length=1000,
Juraj Sloboda3048b632018-10-02 11:13:53 +02001687 expire_walk_interval_ms=10)
1688 self.sleep(.25)
1689 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +02001690 max_reassembly_length=1000,
Juraj Sloboda3048b632018-10-02 11:13:53 +02001691 expire_walk_interval_ms=10000)
1692
1693 def tearDown(self):
1694 super(TestIPv4ReassemblyLocalNode, self).tearDown()
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -07001695
1696 def show_commands_at_teardown(self):
Klement Sekera896c8962019-06-24 11:52:49 +00001697 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
Klement Sekeracae98b72019-02-19 13:53:43 +01001698 self.logger.debug(self.vapi.ppcli("show buffers"))
Juraj Sloboda3048b632018-10-02 11:13:53 +02001699
1700 @classmethod
1701 def create_stream(cls, packet_count=test_packet_count):
1702 """Create input packet stream for defined interface.
1703
1704 :param list packet_sizes: Required packet sizes.
1705 """
1706 for i in range(0, packet_count):
1707 info = cls.create_packet_info(cls.src_dst_if, cls.src_dst_if)
1708 payload = cls.info_to_payload(info)
1709 p = (Ether(dst=cls.src_dst_if.local_mac,
1710 src=cls.src_dst_if.remote_mac) /
1711 IP(id=info.index, src=cls.src_dst_if.remote_ip4,
1712 dst=cls.src_dst_if.local_ip4) /
1713 ICMP(type='echo-request', id=1234) /
1714 Raw(payload))
1715 cls.extend_packet(p, 1518, cls.padding)
1716 info.data = p
1717
1718 @classmethod
1719 def create_fragments(cls):
1720 infos = cls._packet_infos
1721 cls.pkt_infos = []
Paul Vinciguerraf1f2aa62018-11-25 08:36:47 -08001722 for index, info in six.iteritems(infos):
Juraj Sloboda3048b632018-10-02 11:13:53 +02001723 p = info.data
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07001724 # cls.logger.debug(ppp("Packet:",
1725 # p.__class__(scapy.compat.raw(p))))
Juraj Sloboda3048b632018-10-02 11:13:53 +02001726 fragments_300 = fragment_rfc791(p, 300)
1727 cls.pkt_infos.append((index, fragments_300))
1728 cls.fragments_300 = [x for (_, frags) in cls.pkt_infos for x in frags]
1729 cls.logger.debug("Fragmented %s packets into %s 300-byte fragments" %
1730 (len(infos), len(cls.fragments_300)))
1731
1732 def verify_capture(self, capture):
1733 """Verify captured packet stream.
1734
1735 :param list capture: Captured packet stream.
1736 """
1737 info = None
1738 seen = set()
1739 for packet in capture:
1740 try:
1741 self.logger.debug(ppp("Got packet:", packet))
1742 ip = packet[IP]
1743 icmp = packet[ICMP]
Paul Vinciguerraeaea4212019-03-06 11:58:06 -08001744 payload_info = self.payload_to_info(packet[Raw])
Juraj Sloboda3048b632018-10-02 11:13:53 +02001745 packet_index = payload_info.index
1746 if packet_index in seen:
1747 raise Exception(ppp("Duplicate packet received", packet))
1748 seen.add(packet_index)
1749 self.assertEqual(payload_info.dst, self.src_dst_if.sw_if_index)
1750 info = self._packet_infos[packet_index]
Klement Sekera14d7e902018-12-10 13:46:09 +01001751 self.assertIsNotNone(info)
Juraj Sloboda3048b632018-10-02 11:13:53 +02001752 self.assertEqual(packet_index, info.index)
1753 saved_packet = info.data
1754 self.assertEqual(ip.src, saved_packet[IP].dst)
1755 self.assertEqual(ip.dst, saved_packet[IP].src)
1756 self.assertEqual(icmp.type, 0) # echo reply
1757 self.assertEqual(icmp.id, saved_packet[ICMP].id)
1758 self.assertEqual(icmp.payload, saved_packet[ICMP].payload)
1759 except Exception:
1760 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1761 raise
1762 for index in self._packet_infos:
Klement Sekera14d7e902018-12-10 13:46:09 +01001763 self.assertIn(index, seen,
1764 "Packet with packet_index %d not received" % index)
Juraj Sloboda3048b632018-10-02 11:13:53 +02001765
1766 def test_reassembly(self):
1767 """ basic reassembly """
1768
1769 self.pg_enable_capture()
1770 self.src_dst_if.add_stream(self.fragments_300)
1771 self.pg_start()
1772
1773 packets = self.src_dst_if.get_capture(len(self.pkt_infos))
1774 self.verify_capture(packets)
1775
1776 # run it all again to verify correctness
1777 self.pg_enable_capture()
1778 self.src_dst_if.add_stream(self.fragments_300)
1779 self.pg_start()
1780
1781 packets = self.src_dst_if.get_capture(len(self.pkt_infos))
1782 self.verify_capture(packets)
1783
1784
Klement Sekera75e7d132017-09-20 08:26:30 +02001785class TestFIFReassembly(VppTestCase):
1786 """ Fragments in fragments reassembly """
1787
1788 @classmethod
1789 def setUpClass(cls):
1790 super(TestFIFReassembly, cls).setUpClass()
1791
Klement Sekera4c533132018-02-22 11:41:12 +01001792 cls.create_pg_interfaces([0, 1])
1793 cls.src_if = cls.pg0
1794 cls.dst_if = cls.pg1
1795 for i in cls.pg_interfaces:
1796 i.admin_up()
1797 i.config_ip4()
1798 i.resolve_arp()
1799 i.config_ip6()
1800 i.resolve_ndp()
Klement Sekera75e7d132017-09-20 08:26:30 +02001801
Klement Sekera75e7d132017-09-20 08:26:30 +02001802 cls.packet_sizes = [64, 512, 1518, 9018]
1803 cls.padding = " abcdefghijklmn"
1804
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07001805 @classmethod
1806 def tearDownClass(cls):
1807 super(TestFIFReassembly, cls).tearDownClass()
1808
Klement Sekera75e7d132017-09-20 08:26:30 +02001809 def setUp(self):
1810 """ Test setup - force timeout on existing reassemblies """
1811 super(TestFIFReassembly, self).setUp()
Klement Sekera4c533132018-02-22 11:41:12 +01001812 self.vapi.ip_reassembly_enable_disable(
1813 sw_if_index=self.src_if.sw_if_index, enable_ip4=True,
1814 enable_ip6=True)
1815 self.vapi.ip_reassembly_enable_disable(
1816 sw_if_index=self.dst_if.sw_if_index, enable_ip4=True,
1817 enable_ip6=True)
Klement Sekera75e7d132017-09-20 08:26:30 +02001818 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +02001819 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +02001820 expire_walk_interval_ms=10)
1821 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +02001822 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +02001823 expire_walk_interval_ms=10, is_ip6=1)
1824 self.sleep(.25)
1825 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +02001826 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +02001827 expire_walk_interval_ms=10000)
1828 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +02001829 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +02001830 expire_walk_interval_ms=10000, is_ip6=1)
1831
1832 def tearDown(self):
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -07001833 super(TestFIFReassembly, self).tearDown()
1834
1835 def show_commands_at_teardown(self):
Klement Sekera896c8962019-06-24 11:52:49 +00001836 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
1837 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
Klement Sekeracae98b72019-02-19 13:53:43 +01001838 self.logger.debug(self.vapi.ppcli("show buffers"))
Klement Sekera75e7d132017-09-20 08:26:30 +02001839
1840 def verify_capture(self, capture, ip_class, dropped_packet_indexes=[]):
1841 """Verify captured packet stream.
1842
1843 :param list capture: Captured packet stream.
1844 """
1845 info = None
1846 seen = set()
1847 for packet in capture:
1848 try:
Klement Sekera4c533132018-02-22 11:41:12 +01001849 self.logger.debug(ppp("Got packet:", packet))
Klement Sekera75e7d132017-09-20 08:26:30 +02001850 ip = packet[ip_class]
1851 udp = packet[UDP]
Paul Vinciguerraeaea4212019-03-06 11:58:06 -08001852 payload_info = self.payload_to_info(packet[Raw])
Klement Sekera75e7d132017-09-20 08:26:30 +02001853 packet_index = payload_info.index
1854 self.assertTrue(
1855 packet_index not in dropped_packet_indexes,
1856 ppp("Packet received, but should be dropped:", packet))
1857 if packet_index in seen:
1858 raise Exception(ppp("Duplicate packet received", packet))
1859 seen.add(packet_index)
Klement Sekera4c533132018-02-22 11:41:12 +01001860 self.assertEqual(payload_info.dst, self.dst_if.sw_if_index)
Klement Sekera75e7d132017-09-20 08:26:30 +02001861 info = self._packet_infos[packet_index]
1862 self.assertTrue(info is not None)
1863 self.assertEqual(packet_index, info.index)
1864 saved_packet = info.data
1865 self.assertEqual(ip.src, saved_packet[ip_class].src)
1866 self.assertEqual(ip.dst, saved_packet[ip_class].dst)
1867 self.assertEqual(udp.payload, saved_packet[UDP].payload)
Klement Sekera4c533132018-02-22 11:41:12 +01001868 except Exception:
Klement Sekera75e7d132017-09-20 08:26:30 +02001869 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1870 raise
1871 for index in self._packet_infos:
1872 self.assertTrue(index in seen or index in dropped_packet_indexes,
1873 "Packet with packet_index %d not received" % index)
1874
1875 def test_fif4(self):
1876 """ Fragments in fragments (4o4) """
1877
1878 # TODO this should be ideally in setUpClass, but then we hit a bug
1879 # with VppIpRoute incorrectly reporting it's present when it's not
1880 # so we need to manually remove the vpp config, thus we cannot have
1881 # it shared for multiple test cases
1882 self.tun_ip4 = "1.1.1.2"
1883
Klement Sekera4c533132018-02-22 11:41:12 +01001884 self.gre4 = VppGreInterface(self, self.src_if.local_ip4, self.tun_ip4)
Klement Sekera75e7d132017-09-20 08:26:30 +02001885 self.gre4.add_vpp_config()
1886 self.gre4.admin_up()
1887 self.gre4.config_ip4()
1888
Klement Sekera4c533132018-02-22 11:41:12 +01001889 self.vapi.ip_reassembly_enable_disable(
1890 sw_if_index=self.gre4.sw_if_index, enable_ip4=True)
1891
Klement Sekera75e7d132017-09-20 08:26:30 +02001892 self.route4 = VppIpRoute(self, self.tun_ip4, 32,
Klement Sekera4c533132018-02-22 11:41:12 +01001893 [VppRoutePath(self.src_if.remote_ip4,
1894 self.src_if.sw_if_index)])
Klement Sekera75e7d132017-09-20 08:26:30 +02001895 self.route4.add_vpp_config()
1896
1897 self.reset_packet_infos()
1898 for i in range(test_packet_count):
Klement Sekera4c533132018-02-22 11:41:12 +01001899 info = self.create_packet_info(self.src_if, self.dst_if)
Klement Sekera75e7d132017-09-20 08:26:30 +02001900 payload = self.info_to_payload(info)
Klement Sekera4c533132018-02-22 11:41:12 +01001901 # Ethernet header here is only for size calculation, thus it
1902 # doesn't matter how it's initialized. This is to ensure that
1903 # reassembled packet is not > 9000 bytes, so that it's not dropped
1904 p = (Ether() /
1905 IP(id=i, src=self.src_if.remote_ip4,
1906 dst=self.dst_if.remote_ip4) /
1907 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +02001908 Raw(payload))
1909 size = self.packet_sizes[(i // 2) % len(self.packet_sizes)]
1910 self.extend_packet(p, size, self.padding)
Klement Sekera4c533132018-02-22 11:41:12 +01001911 info.data = p[IP] # use only IP part, without ethernet header
Klement Sekera75e7d132017-09-20 08:26:30 +02001912
Paul Vinciguerraf1f2aa62018-11-25 08:36:47 -08001913 fragments = [x for _, p in six.iteritems(self._packet_infos)
Klement Sekera75e7d132017-09-20 08:26:30 +02001914 for x in fragment_rfc791(p.data, 400)]
1915
1916 encapped_fragments = \
Klement Sekera4c533132018-02-22 11:41:12 +01001917 [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1918 IP(src=self.tun_ip4, dst=self.src_if.local_ip4) /
Klement Sekera75e7d132017-09-20 08:26:30 +02001919 GRE() /
1920 p
1921 for p in fragments]
1922
1923 fragmented_encapped_fragments = \
1924 [x for p in encapped_fragments
1925 for x in fragment_rfc791(p, 200)]
1926
Klement Sekera4c533132018-02-22 11:41:12 +01001927 self.src_if.add_stream(fragmented_encapped_fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +02001928
1929 self.pg_enable_capture(self.pg_interfaces)
1930 self.pg_start()
1931
Klement Sekera4c533132018-02-22 11:41:12 +01001932 self.src_if.assert_nothing_captured()
1933 packets = self.dst_if.get_capture(len(self._packet_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +02001934 self.verify_capture(packets, IP)
1935
1936 # TODO remove gre vpp config by hand until VppIpRoute gets fixed
1937 # so that it's query_vpp_config() works as it should
1938 self.gre4.remove_vpp_config()
Klement Sekera4c533132018-02-22 11:41:12 +01001939 self.logger.debug(self.vapi.ppcli("show interface"))
Klement Sekera75e7d132017-09-20 08:26:30 +02001940
1941 def test_fif6(self):
1942 """ Fragments in fragments (6o6) """
1943 # TODO this should be ideally in setUpClass, but then we hit a bug
1944 # with VppIpRoute incorrectly reporting it's present when it's not
1945 # so we need to manually remove the vpp config, thus we cannot have
1946 # it shared for multiple test cases
1947 self.tun_ip6 = "1002::1"
1948
Neale Ranns5a8844b2019-04-16 07:15:35 +00001949 self.gre6 = VppGreInterface(self, self.src_if.local_ip6, self.tun_ip6)
Klement Sekera75e7d132017-09-20 08:26:30 +02001950 self.gre6.add_vpp_config()
1951 self.gre6.admin_up()
1952 self.gre6.config_ip6()
1953
Klement Sekera4c533132018-02-22 11:41:12 +01001954 self.vapi.ip_reassembly_enable_disable(
1955 sw_if_index=self.gre6.sw_if_index, enable_ip6=True)
1956
Klement Sekera75e7d132017-09-20 08:26:30 +02001957 self.route6 = VppIpRoute(self, self.tun_ip6, 128,
Neale Ranns097fa662018-05-01 05:17:55 -07001958 [VppRoutePath(
1959 self.src_if.remote_ip6,
1960 self.src_if.sw_if_index)])
Klement Sekera75e7d132017-09-20 08:26:30 +02001961 self.route6.add_vpp_config()
1962
1963 self.reset_packet_infos()
1964 for i in range(test_packet_count):
Klement Sekera4c533132018-02-22 11:41:12 +01001965 info = self.create_packet_info(self.src_if, self.dst_if)
Klement Sekera75e7d132017-09-20 08:26:30 +02001966 payload = self.info_to_payload(info)
Klement Sekera4c533132018-02-22 11:41:12 +01001967 # Ethernet header here is only for size calculation, thus it
1968 # doesn't matter how it's initialized. This is to ensure that
1969 # reassembled packet is not > 9000 bytes, so that it's not dropped
1970 p = (Ether() /
1971 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1972 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +02001973 Raw(payload))
1974 size = self.packet_sizes[(i // 2) % len(self.packet_sizes)]
1975 self.extend_packet(p, size, self.padding)
Klement Sekera4c533132018-02-22 11:41:12 +01001976 info.data = p[IPv6] # use only IPv6 part, without ethernet header
Klement Sekera75e7d132017-09-20 08:26:30 +02001977
Paul Vinciguerraf1f2aa62018-11-25 08:36:47 -08001978 fragments = [x for _, i in six.iteritems(self._packet_infos)
Klement Sekera75e7d132017-09-20 08:26:30 +02001979 for x in fragment_rfc8200(
1980 i.data, i.index, 400)]
1981
1982 encapped_fragments = \
Klement Sekera4c533132018-02-22 11:41:12 +01001983 [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1984 IPv6(src=self.tun_ip6, dst=self.src_if.local_ip6) /
Klement Sekera75e7d132017-09-20 08:26:30 +02001985 GRE() /
1986 p
1987 for p in fragments]
1988
1989 fragmented_encapped_fragments = \
1990 [x for p in encapped_fragments for x in (
1991 fragment_rfc8200(
1992 p,
1993 2 * len(self._packet_infos) + p[IPv6ExtHdrFragment].id,
1994 200)
1995 if IPv6ExtHdrFragment in p else [p]
1996 )
1997 ]
1998
Klement Sekera4c533132018-02-22 11:41:12 +01001999 self.src_if.add_stream(fragmented_encapped_fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +02002000
2001 self.pg_enable_capture(self.pg_interfaces)
2002 self.pg_start()
2003
Klement Sekera4c533132018-02-22 11:41:12 +01002004 self.src_if.assert_nothing_captured()
2005 packets = self.dst_if.get_capture(len(self._packet_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +02002006 self.verify_capture(packets, IPv6)
2007
2008 # TODO remove gre vpp config by hand until VppIpRoute gets fixed
2009 # so that it's query_vpp_config() works as it should
Klement Sekera3ecc2212018-03-27 10:34:43 +02002010 self.gre6.remove_vpp_config()
Klement Sekera75e7d132017-09-20 08:26:30 +02002011
2012
2013if __name__ == '__main__':
2014 unittest.main(testRunner=VppTestRunner)