blob: ee7830e1762e337baf2298285e09ea80db67b551 [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
839 self.pg_enable_capture()
840 self.send_packets(first_packets)
841 self.send_packets(second_packets)
842 self.send_packets(rest_of_packets)
843
844 packets = self.dst_if.get_capture(len(self.pkt_infos))
845 self.verify_capture(packets)
846 for send_if in self.send_ifs:
847 send_if.assert_nothing_captured()
848
849
Klement Sekera947a85c2019-07-24 12:40:37 +0000850class TestIPv6Reassembly(VppTestCase):
Klement Sekera75e7d132017-09-20 08:26:30 +0200851 """ IPv6 Reassembly """
852
853 @classmethod
854 def setUpClass(cls):
855 super(TestIPv6Reassembly, cls).setUpClass()
856
Klement Sekera4c533132018-02-22 11:41:12 +0100857 cls.create_pg_interfaces([0, 1])
858 cls.src_if = cls.pg0
859 cls.dst_if = cls.pg1
Klement Sekera75e7d132017-09-20 08:26:30 +0200860
861 # setup all interfaces
862 for i in cls.pg_interfaces:
863 i.admin_up()
864 i.config_ip6()
865 i.resolve_ndp()
866
Klement Sekera75e7d132017-09-20 08:26:30 +0200867 # packet sizes
868 cls.packet_sizes = [64, 512, 1518, 9018]
869 cls.padding = " abcdefghijklmn"
870 cls.create_stream(cls.packet_sizes)
871 cls.create_fragments()
872
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -0700873 @classmethod
874 def tearDownClass(cls):
875 super(TestIPv6Reassembly, cls).tearDownClass()
876
Klement Sekera75e7d132017-09-20 08:26:30 +0200877 def setUp(self):
878 """ Test setup - force timeout on existing reassemblies """
879 super(TestIPv6Reassembly, self).setUp()
Klement Sekera4c533132018-02-22 11:41:12 +0100880 self.vapi.ip_reassembly_enable_disable(
881 sw_if_index=self.src_if.sw_if_index, enable_ip6=True)
Klement Sekera75e7d132017-09-20 08:26:30 +0200882 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +0200883 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +0200884 expire_walk_interval_ms=10, is_ip6=1)
885 self.sleep(.25)
886 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +0200887 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +0200888 expire_walk_interval_ms=10000, is_ip6=1)
Klement Sekera896c8962019-06-24 11:52:49 +0000889 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
Klement Sekeracae98b72019-02-19 13:53:43 +0100890 self.logger.debug(self.vapi.ppcli("show buffers"))
Klement Sekera75e7d132017-09-20 08:26:30 +0200891
892 def tearDown(self):
893 super(TestIPv6Reassembly, self).tearDown()
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -0700894
895 def show_commands_at_teardown(self):
Klement Sekera896c8962019-06-24 11:52:49 +0000896 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
Klement Sekeracae98b72019-02-19 13:53:43 +0100897 self.logger.debug(self.vapi.ppcli("show buffers"))
Klement Sekera75e7d132017-09-20 08:26:30 +0200898
899 @classmethod
900 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
901 """Create input packet stream for defined interface.
902
903 :param list packet_sizes: Required packet sizes.
904 """
905 for i in range(0, packet_count):
Klement Sekera4c533132018-02-22 11:41:12 +0100906 info = cls.create_packet_info(cls.src_if, cls.src_if)
Klement Sekera75e7d132017-09-20 08:26:30 +0200907 payload = cls.info_to_payload(info)
Klement Sekera4c533132018-02-22 11:41:12 +0100908 p = (Ether(dst=cls.src_if.local_mac, src=cls.src_if.remote_mac) /
909 IPv6(src=cls.src_if.remote_ip6,
910 dst=cls.dst_if.remote_ip6) /
911 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +0200912 Raw(payload))
913 size = packet_sizes[(i // 2) % len(packet_sizes)]
914 cls.extend_packet(p, size, cls.padding)
915 info.data = p
916
917 @classmethod
918 def create_fragments(cls):
919 infos = cls._packet_infos
920 cls.pkt_infos = []
Paul Vinciguerraf1f2aa62018-11-25 08:36:47 -0800921 for index, info in six.iteritems(infos):
Klement Sekera75e7d132017-09-20 08:26:30 +0200922 p = info.data
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -0700923 # cls.logger.debug(ppp("Packet:",
924 # p.__class__(scapy.compat.raw(p))))
Klement Sekera75e7d132017-09-20 08:26:30 +0200925 fragments_400 = fragment_rfc8200(p, info.index, 400)
926 fragments_300 = fragment_rfc8200(p, info.index, 300)
927 cls.pkt_infos.append((index, fragments_400, fragments_300))
928 cls.fragments_400 = [
929 x for _, frags, _ in cls.pkt_infos for x in frags]
930 cls.fragments_300 = [
931 x for _, _, frags in cls.pkt_infos for x in frags]
932 cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, "
933 "and %s 300-byte fragments" %
934 (len(infos), len(cls.fragments_400),
935 len(cls.fragments_300)))
936
Klement Sekera947a85c2019-07-24 12:40:37 +0000937 def verify_capture(self, capture, dropped_packet_indexes=[]):
938 """Verify captured packet strea .
939
940 :param list capture: Captured packet stream.
941 """
942 info = None
943 seen = set()
944 for packet in capture:
945 try:
946 self.logger.debug(ppp("Got packet:", packet))
947 ip = packet[IPv6]
948 udp = packet[UDP]
949 payload_info = self.payload_to_info(packet[Raw])
950 packet_index = payload_info.index
951 self.assertTrue(
952 packet_index not in dropped_packet_indexes,
953 ppp("Packet received, but should be dropped:", packet))
954 if packet_index in seen:
955 raise Exception(ppp("Duplicate packet received", packet))
956 seen.add(packet_index)
957 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
958 info = self._packet_infos[packet_index]
959 self.assertTrue(info is not None)
960 self.assertEqual(packet_index, info.index)
961 saved_packet = info.data
962 self.assertEqual(ip.src, saved_packet[IPv6].src)
963 self.assertEqual(ip.dst, saved_packet[IPv6].dst)
964 self.assertEqual(udp.payload, saved_packet[UDP].payload)
965 except Exception:
966 self.logger.error(ppp("Unexpected or invalid packet:", packet))
967 raise
968 for index in self._packet_infos:
969 self.assertTrue(index in seen or index in dropped_packet_indexes,
970 "Packet with packet_index %d not received" % index)
971
972 def test_reassembly(self):
Klement Sekera75e7d132017-09-20 08:26:30 +0200973 """ basic reassembly """
974
Klement Sekera947a85c2019-07-24 12:40:37 +0000975 self.pg_enable_capture()
976 self.src_if.add_stream(self.fragments_400)
977 self.pg_start()
978
979 packets = self.dst_if.get_capture(len(self.pkt_infos))
980 self.verify_capture(packets)
981 self.src_if.assert_nothing_captured()
982
983 # run it all again to verify correctness
984 self.pg_enable_capture()
985 self.src_if.add_stream(self.fragments_400)
986 self.pg_start()
987
988 packets = self.dst_if.get_capture(len(self.pkt_infos))
989 self.verify_capture(packets)
990 self.src_if.assert_nothing_captured()
991
Klement Sekera769145c2019-03-06 11:59:57 +0100992 def test_buffer_boundary(self):
993 """ fragment header crossing buffer boundary """
994
995 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
996 IPv6(src=self.src_if.remote_ip6,
997 dst=self.src_if.local_ip6) /
998 IPv6ExtHdrHopByHop(
999 options=[HBHOptUnknown(otype=0xff, optlen=0)] * 1000) /
1000 IPv6ExtHdrFragment(m=1) /
1001 UDP(sport=1234, dport=5678) /
1002 Raw())
1003 self.pg_enable_capture()
1004 self.src_if.add_stream([p])
1005 self.pg_start()
1006 self.src_if.assert_nothing_captured()
1007 self.dst_if.assert_nothing_captured()
1008
Klement Sekera947a85c2019-07-24 12:40:37 +00001009 def test_reversed(self):
Klement Sekera75e7d132017-09-20 08:26:30 +02001010 """ reverse order reassembly """
1011
Klement Sekera947a85c2019-07-24 12:40:37 +00001012 fragments = list(self.fragments_400)
1013 fragments.reverse()
1014
1015 self.pg_enable_capture()
1016 self.src_if.add_stream(fragments)
1017 self.pg_start()
1018
1019 packets = self.dst_if.get_capture(len(self.pkt_infos))
1020 self.verify_capture(packets)
1021 self.src_if.assert_nothing_captured()
1022
1023 # run it all again to verify correctness
1024 self.pg_enable_capture()
1025 self.src_if.add_stream(fragments)
1026 self.pg_start()
1027
1028 packets = self.dst_if.get_capture(len(self.pkt_infos))
1029 self.verify_capture(packets)
1030 self.src_if.assert_nothing_captured()
1031
1032 def test_random(self):
Klement Sekera75e7d132017-09-20 08:26:30 +02001033 """ random order reassembly """
1034
Klement Sekera947a85c2019-07-24 12:40:37 +00001035 fragments = list(self.fragments_400)
1036 shuffle(fragments)
1037
1038 self.pg_enable_capture()
1039 self.src_if.add_stream(fragments)
1040 self.pg_start()
1041
1042 packets = self.dst_if.get_capture(len(self.pkt_infos))
1043 self.verify_capture(packets)
1044 self.src_if.assert_nothing_captured()
1045
1046 # run it all again to verify correctness
1047 self.pg_enable_capture()
1048 self.src_if.add_stream(fragments)
1049 self.pg_start()
1050
1051 packets = self.dst_if.get_capture(len(self.pkt_infos))
1052 self.verify_capture(packets)
1053 self.src_if.assert_nothing_captured()
1054
1055 def test_duplicates(self):
Klement Sekera75e7d132017-09-20 08:26:30 +02001056 """ duplicate fragments """
1057
1058 fragments = [
1059 x for (_, frags, _) in self.pkt_infos
1060 for x in frags
1061 for _ in range(0, min(2, len(frags)))
1062 ]
Klement Sekera947a85c2019-07-24 12:40:37 +00001063
1064 self.pg_enable_capture()
1065 self.src_if.add_stream(fragments)
1066 self.pg_start()
1067
1068 packets = self.dst_if.get_capture(len(self.pkt_infos))
1069 self.verify_capture(packets)
1070 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +02001071
Klement Sekera3a343d42019-05-16 14:35:46 +02001072 def test_long_fragment_chain(self):
1073 """ long fragment chain """
1074
1075 error_cnt_str = \
Klement Sekera896c8962019-06-24 11:52:49 +00001076 "/err/ip6-full-reassembly-feature/fragment chain too long (drop)"
Klement Sekera3a343d42019-05-16 14:35:46 +02001077
Klement Sekera34641f22019-05-22 20:18:26 +02001078 error_cnt = self.statistics.get_err_counter(error_cnt_str)
Klement Sekera3a343d42019-05-16 14:35:46 +02001079
1080 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
1081 max_reassembly_length=3,
1082 expire_walk_interval_ms=50, is_ip6=1)
1083
1084 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1085 IPv6(src=self.src_if.remote_ip6,
1086 dst=self.dst_if.remote_ip6) /
1087 UDP(sport=1234, dport=5678) /
1088 Raw("X" * 1000))
1089 frags = fragment_rfc8200(p, 1, 300) + fragment_rfc8200(p, 2, 500)
1090
1091 self.pg_enable_capture()
1092 self.src_if.add_stream(frags)
1093 self.pg_start()
1094
1095 self.dst_if.get_capture(1)
Klement Sekera34641f22019-05-22 20:18:26 +02001096 self.assert_error_counter_equal(error_cnt_str, error_cnt + 1)
Klement Sekera3a343d42019-05-16 14:35:46 +02001097
Klement Sekera75e7d132017-09-20 08:26:30 +02001098 def test_overlap1(self):
Klement Sekera947a85c2019-07-24 12:40:37 +00001099 """ overlapping fragments case #1 """
Klement Sekera75e7d132017-09-20 08:26:30 +02001100
1101 fragments = []
1102 for _, frags_400, frags_300 in self.pkt_infos:
1103 if len(frags_300) == 1:
1104 fragments.extend(frags_400)
1105 else:
1106 for i, j in zip(frags_300, frags_400):
1107 fragments.extend(i)
1108 fragments.extend(j)
1109
1110 dropped_packet_indexes = set(
1111 index for (index, _, frags) in self.pkt_infos if len(frags) > 1
1112 )
1113
1114 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +01001115 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +02001116 self.pg_start()
1117
Klement Sekera4c533132018-02-22 11:41:12 +01001118 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +02001119 len(self.pkt_infos) - len(dropped_packet_indexes))
Klement Sekera947a85c2019-07-24 12:40:37 +00001120 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +01001121 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +02001122
1123 def test_overlap2(self):
Klement Sekera947a85c2019-07-24 12:40:37 +00001124 """ overlapping fragments case #2 """
Klement Sekera75e7d132017-09-20 08:26:30 +02001125
1126 fragments = []
Klement Sekera4c533132018-02-22 11:41:12 +01001127 for _, frags_400, frags_300 in self.pkt_infos:
Klement Sekera75e7d132017-09-20 08:26:30 +02001128 if len(frags_400) == 1:
1129 fragments.extend(frags_400)
1130 else:
1131 # care must be taken here so that there are no fragments
1132 # received by vpp after reassembly is finished, otherwise
1133 # new reassemblies will be started and packet generator will
1134 # freak out when it detects unfreed buffers
Klement Sekera4c533132018-02-22 11:41:12 +01001135 zipped = zip(frags_400, frags_300)
Paul Vinciguerrac7834e02019-03-02 10:43:05 -08001136 for i, j in zipped:
Klement Sekera75e7d132017-09-20 08:26:30 +02001137 fragments.extend(i)
1138 fragments.extend(j)
Paul Vinciguerrac7834e02019-03-02 10:43:05 -08001139 fragments.pop()
Klement Sekera75e7d132017-09-20 08:26:30 +02001140
1141 dropped_packet_indexes = set(
1142 index for (index, _, frags) in self.pkt_infos if len(frags) > 1
1143 )
1144
1145 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +01001146 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +02001147 self.pg_start()
1148
Klement Sekera4c533132018-02-22 11:41:12 +01001149 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +02001150 len(self.pkt_infos) - len(dropped_packet_indexes))
Klement Sekera947a85c2019-07-24 12:40:37 +00001151 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +01001152 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +02001153
Klement Sekera947a85c2019-07-24 12:40:37 +00001154 def test_timeout_inline(self):
Klement Sekera75e7d132017-09-20 08:26:30 +02001155 """ timeout (inline) """
1156
1157 dropped_packet_indexes = set(
1158 index for (index, frags, _) in self.pkt_infos if len(frags) > 1
1159 )
1160
Klement Sekera947a85c2019-07-24 12:40:37 +00001161 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
1162 max_reassembly_length=3,
1163 expire_walk_interval_ms=10000, is_ip6=1)
1164
1165 self.pg_enable_capture()
1166 self.src_if.add_stream(self.fragments_400)
1167 self.pg_start()
1168
1169 packets = self.dst_if.get_capture(
1170 len(self.pkt_infos) - len(dropped_packet_indexes))
1171 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +01001172 pkts = self.src_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +02001173 expected_count=len(dropped_packet_indexes))
1174 for icmp in pkts:
1175 self.assertIn(ICMPv6TimeExceeded, icmp)
1176 self.assertIn(IPv6ExtHdrFragment, icmp)
1177 self.assertIn(icmp[IPv6ExtHdrFragment].id, dropped_packet_indexes)
1178 dropped_packet_indexes.remove(icmp[IPv6ExtHdrFragment].id)
1179
1180 def test_timeout_cleanup(self):
1181 """ timeout (cleanup) """
1182
1183 # whole packets + fragmented packets sans last fragment
1184 fragments = [
1185 x for (_, frags_400, _) in self.pkt_infos
1186 for x in frags_400[:-1 if len(frags_400) > 1 else None]
1187 ]
1188
1189 # last fragments for fragmented packets
1190 fragments2 = [frags_400[-1]
1191 for (_, frags_400, _) in self.pkt_infos
1192 if len(frags_400) > 1]
1193
1194 dropped_packet_indexes = set(
1195 index for (index, frags_400, _) in self.pkt_infos
1196 if len(frags_400) > 1)
1197
1198 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +02001199 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +02001200 expire_walk_interval_ms=50)
1201
1202 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +02001203 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +02001204 expire_walk_interval_ms=50, is_ip6=1)
1205
1206 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +01001207 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +02001208 self.pg_start()
1209
1210 self.sleep(.25, "wait before sending rest of fragments")
1211
Klement Sekera4c533132018-02-22 11:41:12 +01001212 self.src_if.add_stream(fragments2)
Klement Sekera75e7d132017-09-20 08:26:30 +02001213 self.pg_start()
Klement Sekera75e7d132017-09-20 08:26:30 +02001214
Klement Sekera4c533132018-02-22 11:41:12 +01001215 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +02001216 len(self.pkt_infos) - len(dropped_packet_indexes))
Klement Sekera947a85c2019-07-24 12:40:37 +00001217 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +01001218 pkts = self.src_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +02001219 expected_count=len(dropped_packet_indexes))
1220 for icmp in pkts:
1221 self.assertIn(ICMPv6TimeExceeded, icmp)
1222 self.assertIn(IPv6ExtHdrFragment, icmp)
1223 self.assertIn(icmp[IPv6ExtHdrFragment].id, dropped_packet_indexes)
1224 dropped_packet_indexes.remove(icmp[IPv6ExtHdrFragment].id)
1225
Klement Sekera947a85c2019-07-24 12:40:37 +00001226 def test_disabled(self):
Klement Sekera75e7d132017-09-20 08:26:30 +02001227 """ reassembly disabled """
1228
1229 dropped_packet_indexes = set(
1230 index for (index, frags_400, _) in self.pkt_infos
1231 if len(frags_400) > 1)
Klement Sekera947a85c2019-07-24 12:40:37 +00001232
1233 self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=0,
1234 max_reassembly_length=3,
1235 expire_walk_interval_ms=10000, is_ip6=1)
1236
1237 self.pg_enable_capture()
1238 self.src_if.add_stream(self.fragments_400)
1239 self.pg_start()
1240
1241 packets = self.dst_if.get_capture(
1242 len(self.pkt_infos) - len(dropped_packet_indexes))
1243 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +01001244 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +02001245
1246 def test_missing_upper(self):
1247 """ missing upper layer """
Klement Sekera4c533132018-02-22 11:41:12 +01001248 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1249 IPv6(src=self.src_if.remote_ip6,
1250 dst=self.src_if.local_ip6) /
1251 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +02001252 Raw())
1253 self.extend_packet(p, 1000, self.padding)
1254 fragments = fragment_rfc8200(p, 1, 500)
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07001255 bad_fragment = p.__class__(scapy.compat.raw(fragments[1]))
Klement Sekera75e7d132017-09-20 08:26:30 +02001256 bad_fragment[IPv6ExtHdrFragment].nh = 59
1257 bad_fragment[IPv6ExtHdrFragment].offset = 0
1258 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +01001259 self.src_if.add_stream([bad_fragment])
Klement Sekera75e7d132017-09-20 08:26:30 +02001260 self.pg_start()
Klement Sekera4c533132018-02-22 11:41:12 +01001261 pkts = self.src_if.get_capture(expected_count=1)
Klement Sekera75e7d132017-09-20 08:26:30 +02001262 icmp = pkts[0]
1263 self.assertIn(ICMPv6ParamProblem, icmp)
1264 self.assert_equal(icmp[ICMPv6ParamProblem].code, 3, "ICMP code")
1265
1266 def test_invalid_frag_size(self):
1267 """ fragment size not a multiple of 8 """
Klement Sekera4c533132018-02-22 11:41:12 +01001268 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1269 IPv6(src=self.src_if.remote_ip6,
1270 dst=self.src_if.local_ip6) /
1271 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +02001272 Raw())
1273 self.extend_packet(p, 1000, self.padding)
1274 fragments = fragment_rfc8200(p, 1, 500)
1275 bad_fragment = fragments[0]
1276 self.extend_packet(bad_fragment, len(bad_fragment) + 5)
1277 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +01001278 self.src_if.add_stream([bad_fragment])
Klement Sekera75e7d132017-09-20 08:26:30 +02001279 self.pg_start()
Klement Sekera4c533132018-02-22 11:41:12 +01001280 pkts = self.src_if.get_capture(expected_count=1)
Klement Sekera75e7d132017-09-20 08:26:30 +02001281 icmp = pkts[0]
1282 self.assertIn(ICMPv6ParamProblem, icmp)
1283 self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code")
1284
1285 def test_invalid_packet_size(self):
1286 """ total packet size > 65535 """
Klement Sekera4c533132018-02-22 11:41:12 +01001287 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1288 IPv6(src=self.src_if.remote_ip6,
1289 dst=self.src_if.local_ip6) /
1290 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +02001291 Raw())
1292 self.extend_packet(p, 1000, self.padding)
1293 fragments = fragment_rfc8200(p, 1, 500)
1294 bad_fragment = fragments[1]
1295 bad_fragment[IPv6ExtHdrFragment].offset = 65500
1296 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +01001297 self.src_if.add_stream([bad_fragment])
Klement Sekera75e7d132017-09-20 08:26:30 +02001298 self.pg_start()
Klement Sekera4c533132018-02-22 11:41:12 +01001299 pkts = self.src_if.get_capture(expected_count=1)
Klement Sekera75e7d132017-09-20 08:26:30 +02001300 icmp = pkts[0]
1301 self.assertIn(ICMPv6ParamProblem, icmp)
1302 self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code")
1303
1304
Klement Sekera630ab582019-07-19 09:14:19 +00001305class TestIPv6MWReassembly(VppTestCase):
1306 """ IPv6 Reassembly (multiple workers) """
1307 worker_config = "workers %d" % worker_count
1308
1309 @classmethod
1310 def setUpClass(cls):
1311 super(TestIPv6MWReassembly, cls).setUpClass()
1312
1313 cls.create_pg_interfaces(range(worker_count+1))
1314 cls.src_if = cls.pg0
1315 cls.send_ifs = cls.pg_interfaces[:-1]
1316 cls.dst_if = cls.pg_interfaces[-1]
1317
1318 # setup all interfaces
1319 for i in cls.pg_interfaces:
1320 i.admin_up()
1321 i.config_ip6()
1322 i.resolve_ndp()
1323
1324 # packets sizes reduced here because we are generating packets without
1325 # Ethernet headers, which are added later (diff fragments go via
1326 # different interfaces)
1327 cls.packet_sizes = [64-len(Ether()), 512-len(Ether()),
1328 1518-len(Ether()), 9018-len(Ether())]
1329 cls.padding = " abcdefghijklmn"
1330 cls.create_stream(cls.packet_sizes)
1331 cls.create_fragments()
1332
1333 @classmethod
1334 def tearDownClass(cls):
1335 super(TestIPv6MWReassembly, cls).tearDownClass()
1336
1337 def setUp(self):
1338 """ Test setup - force timeout on existing reassemblies """
1339 super(TestIPv6MWReassembly, self).setUp()
1340 for intf in self.send_ifs:
1341 self.vapi.ip_reassembly_enable_disable(
1342 sw_if_index=intf.sw_if_index, enable_ip6=True)
1343 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
1344 max_reassembly_length=1000,
1345 expire_walk_interval_ms=10, is_ip6=1)
1346 self.sleep(.25)
1347 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
1348 max_reassembly_length=1000,
1349 expire_walk_interval_ms=1000, is_ip6=1)
1350
1351 def tearDown(self):
1352 super(TestIPv6MWReassembly, self).tearDown()
1353
1354 def show_commands_at_teardown(self):
Klement Sekera896c8962019-06-24 11:52:49 +00001355 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
Klement Sekera630ab582019-07-19 09:14:19 +00001356 self.logger.debug(self.vapi.ppcli("show buffers"))
1357
1358 @classmethod
1359 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
1360 """Create input packet stream
1361
1362 :param list packet_sizes: Required packet sizes.
1363 """
1364 for i in range(0, packet_count):
1365 info = cls.create_packet_info(cls.src_if, cls.src_if)
1366 payload = cls.info_to_payload(info)
1367 p = (IPv6(src=cls.src_if.remote_ip6,
1368 dst=cls.dst_if.remote_ip6) /
1369 UDP(sport=1234, dport=5678) /
1370 Raw(payload))
1371 size = packet_sizes[(i // 2) % len(packet_sizes)]
1372 cls.extend_packet(p, size, cls.padding)
1373 info.data = p
1374
1375 @classmethod
1376 def create_fragments(cls):
1377 infos = cls._packet_infos
1378 cls.pkt_infos = []
1379 for index, info in six.iteritems(infos):
1380 p = info.data
1381 # cls.logger.debug(ppp("Packet:",
1382 # p.__class__(scapy.compat.raw(p))))
1383 fragments_400 = fragment_rfc8200(p, index, 400)
1384 cls.pkt_infos.append((index, fragments_400))
1385 cls.fragments_400 = [
1386 x for (_, frags) in cls.pkt_infos for x in frags]
1387 cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, " %
1388 (len(infos), len(cls.fragments_400)))
1389
1390 def verify_capture(self, capture, dropped_packet_indexes=[]):
1391 """Verify captured packet strea .
1392
1393 :param list capture: Captured packet stream.
1394 """
1395 info = None
1396 seen = set()
1397 for packet in capture:
1398 try:
1399 self.logger.debug(ppp("Got packet:", packet))
1400 ip = packet[IPv6]
1401 udp = packet[UDP]
1402 payload_info = self.payload_to_info(packet[Raw])
1403 packet_index = payload_info.index
1404 self.assertTrue(
1405 packet_index not in dropped_packet_indexes,
1406 ppp("Packet received, but should be dropped:", packet))
1407 if packet_index in seen:
1408 raise Exception(ppp("Duplicate packet received", packet))
1409 seen.add(packet_index)
1410 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
1411 info = self._packet_infos[packet_index]
1412 self.assertTrue(info is not None)
1413 self.assertEqual(packet_index, info.index)
1414 saved_packet = info.data
1415 self.assertEqual(ip.src, saved_packet[IPv6].src)
1416 self.assertEqual(ip.dst, saved_packet[IPv6].dst)
1417 self.assertEqual(udp.payload, saved_packet[UDP].payload)
1418 except Exception:
1419 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1420 raise
1421 for index in self._packet_infos:
1422 self.assertTrue(index in seen or index in dropped_packet_indexes,
1423 "Packet with packet_index %d not received" % index)
1424
1425 def send_packets(self, packets):
1426 for counter in range(worker_count):
1427 if 0 == len(packets[counter]):
1428 continue
1429 send_if = self.send_ifs[counter]
1430 send_if.add_stream(
1431 (Ether(dst=send_if.local_mac, src=send_if.remote_mac) / x
1432 for x in packets[counter]),
1433 worker=counter)
1434 self.pg_start()
1435
1436 def test_worker_conflict(self):
1437 """ 1st and FO=0 fragments on different workers """
1438
1439 # in first wave we send fragments which don't start at offset 0
1440 # then we send fragments with offset 0 on a different thread
1441 # then the rest of packets on a random thread
1442 first_packets = [[] for n in range(worker_count)]
1443 second_packets = [[] for n in range(worker_count)]
1444 rest_of_packets = [[] for n in range(worker_count)]
1445 for (_, p) in self.pkt_infos:
1446 wi = randrange(worker_count)
1447 second_packets[wi].append(p[0])
1448 if len(p) <= 1:
1449 continue
1450 wi2 = wi
1451 while wi2 == wi:
1452 wi2 = randrange(worker_count)
1453 first_packets[wi2].append(p[1])
1454 wi3 = randrange(worker_count)
1455 rest_of_packets[wi3].extend(p[2:])
1456
1457 self.pg_enable_capture()
1458 self.send_packets(first_packets)
1459 self.send_packets(second_packets)
1460 self.send_packets(rest_of_packets)
1461
1462 packets = self.dst_if.get_capture(len(self.pkt_infos))
1463 self.verify_capture(packets)
1464 for send_if in self.send_ifs:
1465 send_if.assert_nothing_captured()
1466
1467 self.pg_enable_capture()
1468 self.send_packets(first_packets)
1469 self.send_packets(second_packets)
1470 self.send_packets(rest_of_packets)
1471
1472 packets = self.dst_if.get_capture(len(self.pkt_infos))
1473 self.verify_capture(packets)
1474 for send_if in self.send_ifs:
1475 send_if.assert_nothing_captured()
1476
1477
Klement Sekerade34c352019-06-25 11:19:22 +00001478class TestIPv6SVReassembly(VppTestCase):
1479 """ IPv6 Shallow Virtual Reassembly """
1480
1481 @classmethod
1482 def setUpClass(cls):
1483 super(TestIPv6SVReassembly, cls).setUpClass()
1484
1485 cls.create_pg_interfaces([0, 1])
1486 cls.src_if = cls.pg0
1487 cls.dst_if = cls.pg1
1488
1489 # setup all interfaces
1490 for i in cls.pg_interfaces:
1491 i.admin_up()
1492 i.config_ip6()
1493 i.resolve_ndp()
1494
1495 def setUp(self):
1496 """ Test setup - force timeout on existing reassemblies """
1497 super(TestIPv6SVReassembly, self).setUp()
1498 self.vapi.ip_reassembly_enable_disable(
1499 sw_if_index=self.src_if.sw_if_index, enable_ip6=True,
1500 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL)
1501 self.vapi.ip_reassembly_set(
1502 timeout_ms=0, max_reassemblies=1000,
1503 max_reassembly_length=1000,
1504 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
1505 expire_walk_interval_ms=10, is_ip6=1)
1506 self.sleep(.25)
1507 self.vapi.ip_reassembly_set(
1508 timeout_ms=1000000, max_reassemblies=1000,
1509 max_reassembly_length=1000,
1510 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
1511 expire_walk_interval_ms=10000, is_ip6=1)
1512
1513 def tearDown(self):
1514 super(TestIPv6SVReassembly, self).tearDown()
1515 self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details"))
1516 self.logger.debug(self.vapi.ppcli("show buffers"))
1517
1518 def test_basic(self):
1519 """ basic reassembly """
1520 payload_len = 1000
1521 payload = ""
1522 counter = 0
1523 while len(payload) < payload_len:
1524 payload += "%u " % counter
1525 counter += 1
1526
1527 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1528 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1529 UDP(sport=1234, dport=5678) /
1530 Raw(payload))
1531 fragments = fragment_rfc8200(p, 1, payload_len/4)
1532
1533 # send fragment #2 - should be cached inside reassembly
1534 self.pg_enable_capture()
1535 self.src_if.add_stream(fragments[1])
1536 self.pg_start()
1537 self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details"))
1538 self.logger.debug(self.vapi.ppcli("show buffers"))
1539 self.logger.debug(self.vapi.ppcli("show trace"))
1540 self.dst_if.assert_nothing_captured()
1541
1542 # send fragment #1 - reassembly is finished now and both fragments
1543 # forwarded
1544 self.pg_enable_capture()
1545 self.src_if.add_stream(fragments[0])
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 c = self.dst_if.get_capture(2)
1551 for sent, recvd in zip([fragments[1], fragments[0]], c):
1552 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
1553 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
1554 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
1555
1556 # send rest of fragments - should be immediately forwarded
1557 self.pg_enable_capture()
1558 self.src_if.add_stream(fragments[2:])
1559 self.pg_start()
1560 c = self.dst_if.get_capture(len(fragments[2:]))
1561 for sent, recvd in zip(fragments[2:], 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 def test_timeout(self):
1567 """ reassembly timeout """
1568 payload_len = 1000
1569 payload = ""
1570 counter = 0
1571 while len(payload) < payload_len:
1572 payload += "%u " % counter
1573 counter += 1
1574
1575 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1576 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1577 UDP(sport=1234, dport=5678) /
1578 Raw(payload))
1579 fragments = fragment_rfc8200(p, 1, payload_len/4)
1580
1581 self.vapi.ip_reassembly_set(
1582 timeout_ms=100, max_reassemblies=1000,
1583 max_reassembly_length=1000,
1584 expire_walk_interval_ms=50,
1585 is_ip6=1,
1586 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL)
1587
1588 # send fragments #2 and #1 - should be forwarded
1589 self.pg_enable_capture()
1590 self.src_if.add_stream(fragments[0:2])
1591 self.pg_start()
1592 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
1593 self.logger.debug(self.vapi.ppcli("show buffers"))
1594 self.logger.debug(self.vapi.ppcli("show trace"))
1595 c = self.dst_if.get_capture(2)
1596 for sent, recvd in zip([fragments[1], fragments[0]], c):
1597 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
1598 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
1599 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
1600
1601 # wait for cleanup
1602 self.sleep(.25, "wait before sending rest of fragments")
1603
1604 # send rest of fragments - shouldn't be forwarded
1605 self.pg_enable_capture()
1606 self.src_if.add_stream(fragments[2:])
1607 self.pg_start()
1608 self.dst_if.assert_nothing_captured()
1609
1610 def test_lru(self):
1611 """ reassembly reuses LRU element """
1612
1613 self.vapi.ip_reassembly_set(
1614 timeout_ms=1000000, max_reassemblies=1,
1615 max_reassembly_length=1000,
1616 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
1617 is_ip6=1, expire_walk_interval_ms=10000)
1618
1619 payload_len = 1000
1620 payload = ""
1621 counter = 0
1622 while len(payload) < payload_len:
1623 payload += "%u " % counter
1624 counter += 1
1625
1626 packet_count = 10
1627
1628 fragments = [f
1629 for i in range(packet_count)
1630 for p in (Ether(dst=self.src_if.local_mac,
1631 src=self.src_if.remote_mac) /
1632 IPv6(src=self.src_if.remote_ip6,
1633 dst=self.dst_if.remote_ip6) /
1634 UDP(sport=1234, dport=5678) /
1635 Raw(payload))
1636 for f in fragment_rfc8200(p, i, payload_len/4)]
1637
1638 self.pg_enable_capture()
1639 self.src_if.add_stream(fragments)
1640 self.pg_start()
1641 c = self.dst_if.get_capture(len(fragments))
1642 for sent, recvd in zip(fragments, c):
1643 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
1644 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
1645 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
1646
1647
Juraj Sloboda3048b632018-10-02 11:13:53 +02001648class TestIPv4ReassemblyLocalNode(VppTestCase):
1649 """ IPv4 Reassembly for packets coming to ip4-local node """
1650
1651 @classmethod
1652 def setUpClass(cls):
1653 super(TestIPv4ReassemblyLocalNode, cls).setUpClass()
1654
1655 cls.create_pg_interfaces([0])
1656 cls.src_dst_if = cls.pg0
1657
1658 # setup all interfaces
1659 for i in cls.pg_interfaces:
1660 i.admin_up()
1661 i.config_ip4()
1662 i.resolve_arp()
1663
1664 cls.padding = " abcdefghijklmn"
1665 cls.create_stream()
1666 cls.create_fragments()
1667
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07001668 @classmethod
1669 def tearDownClass(cls):
1670 super(TestIPv4ReassemblyLocalNode, cls).tearDownClass()
1671
Juraj Sloboda3048b632018-10-02 11:13:53 +02001672 def setUp(self):
1673 """ Test setup - force timeout on existing reassemblies """
1674 super(TestIPv4ReassemblyLocalNode, self).setUp()
1675 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +02001676 max_reassembly_length=1000,
Juraj Sloboda3048b632018-10-02 11:13:53 +02001677 expire_walk_interval_ms=10)
1678 self.sleep(.25)
1679 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +02001680 max_reassembly_length=1000,
Juraj Sloboda3048b632018-10-02 11:13:53 +02001681 expire_walk_interval_ms=10000)
1682
1683 def tearDown(self):
1684 super(TestIPv4ReassemblyLocalNode, self).tearDown()
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -07001685
1686 def show_commands_at_teardown(self):
Klement Sekera896c8962019-06-24 11:52:49 +00001687 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
Klement Sekeracae98b72019-02-19 13:53:43 +01001688 self.logger.debug(self.vapi.ppcli("show buffers"))
Juraj Sloboda3048b632018-10-02 11:13:53 +02001689
1690 @classmethod
1691 def create_stream(cls, packet_count=test_packet_count):
1692 """Create input packet stream for defined interface.
1693
1694 :param list packet_sizes: Required packet sizes.
1695 """
1696 for i in range(0, packet_count):
1697 info = cls.create_packet_info(cls.src_dst_if, cls.src_dst_if)
1698 payload = cls.info_to_payload(info)
1699 p = (Ether(dst=cls.src_dst_if.local_mac,
1700 src=cls.src_dst_if.remote_mac) /
1701 IP(id=info.index, src=cls.src_dst_if.remote_ip4,
1702 dst=cls.src_dst_if.local_ip4) /
1703 ICMP(type='echo-request', id=1234) /
1704 Raw(payload))
1705 cls.extend_packet(p, 1518, cls.padding)
1706 info.data = p
1707
1708 @classmethod
1709 def create_fragments(cls):
1710 infos = cls._packet_infos
1711 cls.pkt_infos = []
Paul Vinciguerraf1f2aa62018-11-25 08:36:47 -08001712 for index, info in six.iteritems(infos):
Juraj Sloboda3048b632018-10-02 11:13:53 +02001713 p = info.data
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07001714 # cls.logger.debug(ppp("Packet:",
1715 # p.__class__(scapy.compat.raw(p))))
Juraj Sloboda3048b632018-10-02 11:13:53 +02001716 fragments_300 = fragment_rfc791(p, 300)
1717 cls.pkt_infos.append((index, fragments_300))
1718 cls.fragments_300 = [x for (_, frags) in cls.pkt_infos for x in frags]
1719 cls.logger.debug("Fragmented %s packets into %s 300-byte fragments" %
1720 (len(infos), len(cls.fragments_300)))
1721
1722 def verify_capture(self, capture):
1723 """Verify captured packet stream.
1724
1725 :param list capture: Captured packet stream.
1726 """
1727 info = None
1728 seen = set()
1729 for packet in capture:
1730 try:
1731 self.logger.debug(ppp("Got packet:", packet))
1732 ip = packet[IP]
1733 icmp = packet[ICMP]
Paul Vinciguerraeaea4212019-03-06 11:58:06 -08001734 payload_info = self.payload_to_info(packet[Raw])
Juraj Sloboda3048b632018-10-02 11:13:53 +02001735 packet_index = payload_info.index
1736 if packet_index in seen:
1737 raise Exception(ppp("Duplicate packet received", packet))
1738 seen.add(packet_index)
1739 self.assertEqual(payload_info.dst, self.src_dst_if.sw_if_index)
1740 info = self._packet_infos[packet_index]
Klement Sekera14d7e902018-12-10 13:46:09 +01001741 self.assertIsNotNone(info)
Juraj Sloboda3048b632018-10-02 11:13:53 +02001742 self.assertEqual(packet_index, info.index)
1743 saved_packet = info.data
1744 self.assertEqual(ip.src, saved_packet[IP].dst)
1745 self.assertEqual(ip.dst, saved_packet[IP].src)
1746 self.assertEqual(icmp.type, 0) # echo reply
1747 self.assertEqual(icmp.id, saved_packet[ICMP].id)
1748 self.assertEqual(icmp.payload, saved_packet[ICMP].payload)
1749 except Exception:
1750 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1751 raise
1752 for index in self._packet_infos:
Klement Sekera14d7e902018-12-10 13:46:09 +01001753 self.assertIn(index, seen,
1754 "Packet with packet_index %d not received" % index)
Juraj Sloboda3048b632018-10-02 11:13:53 +02001755
1756 def test_reassembly(self):
1757 """ basic reassembly """
1758
1759 self.pg_enable_capture()
1760 self.src_dst_if.add_stream(self.fragments_300)
1761 self.pg_start()
1762
1763 packets = self.src_dst_if.get_capture(len(self.pkt_infos))
1764 self.verify_capture(packets)
1765
1766 # run it all again to verify correctness
1767 self.pg_enable_capture()
1768 self.src_dst_if.add_stream(self.fragments_300)
1769 self.pg_start()
1770
1771 packets = self.src_dst_if.get_capture(len(self.pkt_infos))
1772 self.verify_capture(packets)
1773
1774
Klement Sekera75e7d132017-09-20 08:26:30 +02001775class TestFIFReassembly(VppTestCase):
1776 """ Fragments in fragments reassembly """
1777
1778 @classmethod
1779 def setUpClass(cls):
1780 super(TestFIFReassembly, cls).setUpClass()
1781
Klement Sekera4c533132018-02-22 11:41:12 +01001782 cls.create_pg_interfaces([0, 1])
1783 cls.src_if = cls.pg0
1784 cls.dst_if = cls.pg1
1785 for i in cls.pg_interfaces:
1786 i.admin_up()
1787 i.config_ip4()
1788 i.resolve_arp()
1789 i.config_ip6()
1790 i.resolve_ndp()
Klement Sekera75e7d132017-09-20 08:26:30 +02001791
Klement Sekera75e7d132017-09-20 08:26:30 +02001792 cls.packet_sizes = [64, 512, 1518, 9018]
1793 cls.padding = " abcdefghijklmn"
1794
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07001795 @classmethod
1796 def tearDownClass(cls):
1797 super(TestFIFReassembly, cls).tearDownClass()
1798
Klement Sekera75e7d132017-09-20 08:26:30 +02001799 def setUp(self):
1800 """ Test setup - force timeout on existing reassemblies """
1801 super(TestFIFReassembly, self).setUp()
Klement Sekera4c533132018-02-22 11:41:12 +01001802 self.vapi.ip_reassembly_enable_disable(
1803 sw_if_index=self.src_if.sw_if_index, enable_ip4=True,
1804 enable_ip6=True)
1805 self.vapi.ip_reassembly_enable_disable(
1806 sw_if_index=self.dst_if.sw_if_index, enable_ip4=True,
1807 enable_ip6=True)
Klement Sekera75e7d132017-09-20 08:26:30 +02001808 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +02001809 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +02001810 expire_walk_interval_ms=10)
1811 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +02001812 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +02001813 expire_walk_interval_ms=10, is_ip6=1)
1814 self.sleep(.25)
1815 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
Klement Sekera3a343d42019-05-16 14:35:46 +02001816 max_reassembly_length=1000,
Klement Sekera75e7d132017-09-20 08:26:30 +02001817 expire_walk_interval_ms=10000)
1818 self.vapi.ip_reassembly_set(timeout_ms=1000000, 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=10000, is_ip6=1)
1821
1822 def tearDown(self):
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -07001823 super(TestFIFReassembly, self).tearDown()
1824
1825 def show_commands_at_teardown(self):
Klement Sekera896c8962019-06-24 11:52:49 +00001826 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
1827 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
Klement Sekeracae98b72019-02-19 13:53:43 +01001828 self.logger.debug(self.vapi.ppcli("show buffers"))
Klement Sekera75e7d132017-09-20 08:26:30 +02001829
1830 def verify_capture(self, capture, ip_class, dropped_packet_indexes=[]):
1831 """Verify captured packet stream.
1832
1833 :param list capture: Captured packet stream.
1834 """
1835 info = None
1836 seen = set()
1837 for packet in capture:
1838 try:
Klement Sekera4c533132018-02-22 11:41:12 +01001839 self.logger.debug(ppp("Got packet:", packet))
Klement Sekera75e7d132017-09-20 08:26:30 +02001840 ip = packet[ip_class]
1841 udp = packet[UDP]
Paul Vinciguerraeaea4212019-03-06 11:58:06 -08001842 payload_info = self.payload_to_info(packet[Raw])
Klement Sekera75e7d132017-09-20 08:26:30 +02001843 packet_index = payload_info.index
1844 self.assertTrue(
1845 packet_index not in dropped_packet_indexes,
1846 ppp("Packet received, but should be dropped:", packet))
1847 if packet_index in seen:
1848 raise Exception(ppp("Duplicate packet received", packet))
1849 seen.add(packet_index)
Klement Sekera4c533132018-02-22 11:41:12 +01001850 self.assertEqual(payload_info.dst, self.dst_if.sw_if_index)
Klement Sekera75e7d132017-09-20 08:26:30 +02001851 info = self._packet_infos[packet_index]
1852 self.assertTrue(info is not None)
1853 self.assertEqual(packet_index, info.index)
1854 saved_packet = info.data
1855 self.assertEqual(ip.src, saved_packet[ip_class].src)
1856 self.assertEqual(ip.dst, saved_packet[ip_class].dst)
1857 self.assertEqual(udp.payload, saved_packet[UDP].payload)
Klement Sekera4c533132018-02-22 11:41:12 +01001858 except Exception:
Klement Sekera75e7d132017-09-20 08:26:30 +02001859 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1860 raise
1861 for index in self._packet_infos:
1862 self.assertTrue(index in seen or index in dropped_packet_indexes,
1863 "Packet with packet_index %d not received" % index)
1864
1865 def test_fif4(self):
1866 """ Fragments in fragments (4o4) """
1867
1868 # TODO this should be ideally in setUpClass, but then we hit a bug
1869 # with VppIpRoute incorrectly reporting it's present when it's not
1870 # so we need to manually remove the vpp config, thus we cannot have
1871 # it shared for multiple test cases
1872 self.tun_ip4 = "1.1.1.2"
1873
Klement Sekera4c533132018-02-22 11:41:12 +01001874 self.gre4 = VppGreInterface(self, self.src_if.local_ip4, self.tun_ip4)
Klement Sekera75e7d132017-09-20 08:26:30 +02001875 self.gre4.add_vpp_config()
1876 self.gre4.admin_up()
1877 self.gre4.config_ip4()
1878
Klement Sekera4c533132018-02-22 11:41:12 +01001879 self.vapi.ip_reassembly_enable_disable(
1880 sw_if_index=self.gre4.sw_if_index, enable_ip4=True)
1881
Klement Sekera75e7d132017-09-20 08:26:30 +02001882 self.route4 = VppIpRoute(self, self.tun_ip4, 32,
Klement Sekera4c533132018-02-22 11:41:12 +01001883 [VppRoutePath(self.src_if.remote_ip4,
1884 self.src_if.sw_if_index)])
Klement Sekera75e7d132017-09-20 08:26:30 +02001885 self.route4.add_vpp_config()
1886
1887 self.reset_packet_infos()
1888 for i in range(test_packet_count):
Klement Sekera4c533132018-02-22 11:41:12 +01001889 info = self.create_packet_info(self.src_if, self.dst_if)
Klement Sekera75e7d132017-09-20 08:26:30 +02001890 payload = self.info_to_payload(info)
Klement Sekera4c533132018-02-22 11:41:12 +01001891 # Ethernet header here is only for size calculation, thus it
1892 # doesn't matter how it's initialized. This is to ensure that
1893 # reassembled packet is not > 9000 bytes, so that it's not dropped
1894 p = (Ether() /
1895 IP(id=i, src=self.src_if.remote_ip4,
1896 dst=self.dst_if.remote_ip4) /
1897 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +02001898 Raw(payload))
1899 size = self.packet_sizes[(i // 2) % len(self.packet_sizes)]
1900 self.extend_packet(p, size, self.padding)
Klement Sekera4c533132018-02-22 11:41:12 +01001901 info.data = p[IP] # use only IP part, without ethernet header
Klement Sekera75e7d132017-09-20 08:26:30 +02001902
Paul Vinciguerraf1f2aa62018-11-25 08:36:47 -08001903 fragments = [x for _, p in six.iteritems(self._packet_infos)
Klement Sekera75e7d132017-09-20 08:26:30 +02001904 for x in fragment_rfc791(p.data, 400)]
1905
1906 encapped_fragments = \
Klement Sekera4c533132018-02-22 11:41:12 +01001907 [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1908 IP(src=self.tun_ip4, dst=self.src_if.local_ip4) /
Klement Sekera75e7d132017-09-20 08:26:30 +02001909 GRE() /
1910 p
1911 for p in fragments]
1912
1913 fragmented_encapped_fragments = \
1914 [x for p in encapped_fragments
1915 for x in fragment_rfc791(p, 200)]
1916
Klement Sekera4c533132018-02-22 11:41:12 +01001917 self.src_if.add_stream(fragmented_encapped_fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +02001918
1919 self.pg_enable_capture(self.pg_interfaces)
1920 self.pg_start()
1921
Klement Sekera4c533132018-02-22 11:41:12 +01001922 self.src_if.assert_nothing_captured()
1923 packets = self.dst_if.get_capture(len(self._packet_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +02001924 self.verify_capture(packets, IP)
1925
1926 # TODO remove gre vpp config by hand until VppIpRoute gets fixed
1927 # so that it's query_vpp_config() works as it should
1928 self.gre4.remove_vpp_config()
Klement Sekera4c533132018-02-22 11:41:12 +01001929 self.logger.debug(self.vapi.ppcli("show interface"))
Klement Sekera75e7d132017-09-20 08:26:30 +02001930
1931 def test_fif6(self):
1932 """ Fragments in fragments (6o6) """
1933 # TODO this should be ideally in setUpClass, but then we hit a bug
1934 # with VppIpRoute incorrectly reporting it's present when it's not
1935 # so we need to manually remove the vpp config, thus we cannot have
1936 # it shared for multiple test cases
1937 self.tun_ip6 = "1002::1"
1938
Neale Ranns5a8844b2019-04-16 07:15:35 +00001939 self.gre6 = VppGreInterface(self, self.src_if.local_ip6, self.tun_ip6)
Klement Sekera75e7d132017-09-20 08:26:30 +02001940 self.gre6.add_vpp_config()
1941 self.gre6.admin_up()
1942 self.gre6.config_ip6()
1943
Klement Sekera4c533132018-02-22 11:41:12 +01001944 self.vapi.ip_reassembly_enable_disable(
1945 sw_if_index=self.gre6.sw_if_index, enable_ip6=True)
1946
Klement Sekera75e7d132017-09-20 08:26:30 +02001947 self.route6 = VppIpRoute(self, self.tun_ip6, 128,
Neale Ranns097fa662018-05-01 05:17:55 -07001948 [VppRoutePath(
1949 self.src_if.remote_ip6,
1950 self.src_if.sw_if_index)])
Klement Sekera75e7d132017-09-20 08:26:30 +02001951 self.route6.add_vpp_config()
1952
1953 self.reset_packet_infos()
1954 for i in range(test_packet_count):
Klement Sekera4c533132018-02-22 11:41:12 +01001955 info = self.create_packet_info(self.src_if, self.dst_if)
Klement Sekera75e7d132017-09-20 08:26:30 +02001956 payload = self.info_to_payload(info)
Klement Sekera4c533132018-02-22 11:41:12 +01001957 # Ethernet header here is only for size calculation, thus it
1958 # doesn't matter how it's initialized. This is to ensure that
1959 # reassembled packet is not > 9000 bytes, so that it's not dropped
1960 p = (Ether() /
1961 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1962 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +02001963 Raw(payload))
1964 size = self.packet_sizes[(i // 2) % len(self.packet_sizes)]
1965 self.extend_packet(p, size, self.padding)
Klement Sekera4c533132018-02-22 11:41:12 +01001966 info.data = p[IPv6] # use only IPv6 part, without ethernet header
Klement Sekera75e7d132017-09-20 08:26:30 +02001967
Paul Vinciguerraf1f2aa62018-11-25 08:36:47 -08001968 fragments = [x for _, i in six.iteritems(self._packet_infos)
Klement Sekera75e7d132017-09-20 08:26:30 +02001969 for x in fragment_rfc8200(
1970 i.data, i.index, 400)]
1971
1972 encapped_fragments = \
Klement Sekera4c533132018-02-22 11:41:12 +01001973 [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1974 IPv6(src=self.tun_ip6, dst=self.src_if.local_ip6) /
Klement Sekera75e7d132017-09-20 08:26:30 +02001975 GRE() /
1976 p
1977 for p in fragments]
1978
1979 fragmented_encapped_fragments = \
1980 [x for p in encapped_fragments for x in (
1981 fragment_rfc8200(
1982 p,
1983 2 * len(self._packet_infos) + p[IPv6ExtHdrFragment].id,
1984 200)
1985 if IPv6ExtHdrFragment in p else [p]
1986 )
1987 ]
1988
Klement Sekera4c533132018-02-22 11:41:12 +01001989 self.src_if.add_stream(fragmented_encapped_fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +02001990
1991 self.pg_enable_capture(self.pg_interfaces)
1992 self.pg_start()
1993
Klement Sekera4c533132018-02-22 11:41:12 +01001994 self.src_if.assert_nothing_captured()
1995 packets = self.dst_if.get_capture(len(self._packet_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +02001996 self.verify_capture(packets, IPv6)
1997
1998 # TODO remove gre vpp config by hand until VppIpRoute gets fixed
1999 # so that it's query_vpp_config() works as it should
Klement Sekera3ecc2212018-03-27 10:34:43 +02002000 self.gre6.remove_vpp_config()
Klement Sekera75e7d132017-09-20 08:26:30 +02002001
2002
2003if __name__ == '__main__':
2004 unittest.main(testRunner=VppTestRunner)