4 from random import shuffle, choice, randrange
6 from framework import VppTestCase, VppTestRunner
9 from scapy.packet import Raw
10 from scapy.layers.l2 import Ether, GRE
11 from scapy.layers.inet import IP, UDP, ICMP
12 from scapy.layers.inet6 import HBHOptUnknown, ICMPv6ParamProblem,\
13 ICMPv6TimeExceeded, IPv6, IPv6ExtHdrFragment, IPv6ExtHdrHopByHop
14 from framework import VppTestCase, VppTestRunner
15 from util import ppp, ppc, fragment_rfc791, fragment_rfc8200
16 from vpp_gre_interface import VppGreInterface
17 from vpp_ip import DpoProto
18 from vpp_ip_route import VppIpRoute, VppRoutePath, FibPathProto
19 from vpp_papi import VppEnum
21 # 35 is enough to have >257 400-byte fragments
22 test_packet_count = 35
24 # number of workers used for multi-worker test cases
28 class TestIPv4Reassembly(VppTestCase):
29 """ IPv4 Reassembly """
33 super(TestIPv4Reassembly, cls).setUpClass()
35 cls.create_pg_interfaces([0, 1])
39 # setup all interfaces
40 for i in cls.pg_interfaces:
46 cls.packet_sizes = [64, 512, 1518, 9018]
47 cls.padding = " abcdefghijklmn"
48 cls.create_stream(cls.packet_sizes)
49 cls.create_fragments()
52 def tearDownClass(cls):
53 super(TestIPv4Reassembly, cls).tearDownClass()
56 """ Test setup - force timeout on existing reassemblies """
57 super(TestIPv4Reassembly, self).setUp()
58 self.vapi.ip_reassembly_enable_disable(
59 sw_if_index=self.src_if.sw_if_index, enable_ip4=True)
60 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
61 max_reassembly_length=1000,
62 expire_walk_interval_ms=10)
64 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
65 max_reassembly_length=1000,
66 expire_walk_interval_ms=10000)
69 super(TestIPv4Reassembly, self).tearDown()
71 def show_commands_at_teardown(self):
72 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
73 self.logger.debug(self.vapi.ppcli("show buffers"))
76 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
77 """Create input packet stream
79 :param list packet_sizes: Required packet sizes.
81 for i in range(0, packet_count):
82 info = cls.create_packet_info(cls.src_if, cls.src_if)
83 payload = cls.info_to_payload(info)
84 p = (Ether(dst=cls.src_if.local_mac, src=cls.src_if.remote_mac) /
85 IP(id=info.index, src=cls.src_if.remote_ip4,
86 dst=cls.dst_if.remote_ip4) /
87 UDP(sport=1234, dport=5678) /
89 size = packet_sizes[(i // 2) % len(packet_sizes)]
90 cls.extend_packet(p, size, cls.padding)
94 def create_fragments(cls):
95 infos = cls._packet_infos
97 for index, info in infos.items():
99 # cls.logger.debug(ppp("Packet:",
100 # p.__class__(scapy.compat.raw(p))))
101 fragments_400 = fragment_rfc791(p, 400)
102 fragments_300 = fragment_rfc791(p, 300)
104 x for f in fragments_400 for x in fragment_rfc791(f, 200)]
105 cls.pkt_infos.append(
106 (index, fragments_400, fragments_300, fragments_200))
107 cls.fragments_400 = [
108 x for (_, frags, _, _) in cls.pkt_infos for x in frags]
109 cls.fragments_300 = [
110 x for (_, _, frags, _) in cls.pkt_infos for x in frags]
111 cls.fragments_200 = [
112 x for (_, _, _, frags) in cls.pkt_infos for x in frags]
113 cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, "
114 "%s 300-byte fragments and %s 200-byte fragments" %
115 (len(infos), len(cls.fragments_400),
116 len(cls.fragments_300), len(cls.fragments_200)))
118 def verify_capture(self, capture, dropped_packet_indexes=[]):
119 """Verify captured packet stream.
121 :param list capture: Captured packet stream.
125 for packet in capture:
127 self.logger.debug(ppp("Got packet:", packet))
130 payload_info = self.payload_to_info(packet[Raw])
131 packet_index = payload_info.index
133 packet_index not in dropped_packet_indexes,
134 ppp("Packet received, but should be dropped:", packet))
135 if packet_index in seen:
136 raise Exception(ppp("Duplicate packet received", packet))
137 seen.add(packet_index)
138 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
139 info = self._packet_infos[packet_index]
140 self.assertTrue(info is not None)
141 self.assertEqual(packet_index, info.index)
142 saved_packet = info.data
143 self.assertEqual(ip.src, saved_packet[IP].src)
144 self.assertEqual(ip.dst, saved_packet[IP].dst)
145 self.assertEqual(udp.payload, saved_packet[UDP].payload)
147 self.logger.error(ppp("Unexpected or invalid packet:", packet))
149 for index in self._packet_infos:
150 self.assertTrue(index in seen or index in dropped_packet_indexes,
151 "Packet with packet_index %d not received" % index)
153 def test_reassembly(self):
154 """ basic reassembly """
156 self.pg_enable_capture()
157 self.src_if.add_stream(self.fragments_200)
160 packets = self.dst_if.get_capture(len(self.pkt_infos))
161 self.verify_capture(packets)
162 self.src_if.assert_nothing_captured()
164 # run it all again to verify correctness
165 self.pg_enable_capture()
166 self.src_if.add_stream(self.fragments_200)
169 packets = self.dst_if.get_capture(len(self.pkt_infos))
170 self.verify_capture(packets)
171 self.src_if.assert_nothing_captured()
173 def test_reversed(self):
174 """ reverse order reassembly """
176 fragments = list(self.fragments_200)
179 self.pg_enable_capture()
180 self.src_if.add_stream(fragments)
183 packets = self.dst_if.get_capture(len(self.packet_infos))
184 self.verify_capture(packets)
185 self.src_if.assert_nothing_captured()
187 # run it all again to verify correctness
188 self.pg_enable_capture()
189 self.src_if.add_stream(fragments)
192 packets = self.dst_if.get_capture(len(self.packet_infos))
193 self.verify_capture(packets)
194 self.src_if.assert_nothing_captured()
196 def test_long_fragment_chain(self):
197 """ long fragment chain """
200 "/err/ip4-full-reassembly-feature/fragment chain too long (drop)"
202 error_cnt = self.statistics.get_err_counter(error_cnt_str)
204 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
205 max_reassembly_length=3,
206 expire_walk_interval_ms=50)
208 p1 = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
209 IP(id=1000, src=self.src_if.remote_ip4,
210 dst=self.dst_if.remote_ip4) /
211 UDP(sport=1234, dport=5678) /
213 p2 = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
214 IP(id=1001, src=self.src_if.remote_ip4,
215 dst=self.dst_if.remote_ip4) /
216 UDP(sport=1234, dport=5678) /
218 frags = fragment_rfc791(p1, 200) + fragment_rfc791(p2, 500)
220 self.pg_enable_capture()
221 self.src_if.add_stream(frags)
224 self.dst_if.get_capture(1)
225 self.assert_error_counter_equal(error_cnt_str, error_cnt + 1)
228 """ fragment length + ip header size > 65535 """
229 self.vapi.cli("clear errors")
230 raw = b'''E\x00\x00\x88,\xf8\x1f\xfe@\x01\x98\x00\xc0\xa8\n-\xc0\xa8\n\
231 \x01\x08\x00\xf0J\xed\xcb\xf1\xf5Test-group: IPv4.IPv4.ipv4-message.\
232 Ethernet-Payload.IPv4-Packet.IPv4-Header.Fragment-Offset; Test-case: 5737'''
233 malformed_packet = (Ether(dst=self.src_if.local_mac,
234 src=self.src_if.remote_mac) /
236 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
237 IP(id=1000, src=self.src_if.remote_ip4,
238 dst=self.dst_if.remote_ip4) /
239 UDP(sport=1234, dport=5678) /
241 valid_fragments = fragment_rfc791(p, 400)
243 counter = "/err/ip4-full-reassembly-feature/malformed packets"
244 error_counter = self.statistics.get_err_counter(counter)
245 self.pg_enable_capture()
246 self.src_if.add_stream([malformed_packet] + valid_fragments)
249 self.dst_if.get_capture(1)
250 self.logger.debug(self.vapi.ppcli("show error"))
251 self.assertEqual(self.statistics.get_err_counter(counter),
254 def test_44924(self):
255 """ compress tiny fragments """
256 packets = [(Ether(dst=self.src_if.local_mac,
257 src=self.src_if.remote_mac) /
258 IP(id=24339, flags="MF", frag=0, ttl=64,
259 src=self.src_if.remote_ip4,
260 dst=self.dst_if.remote_ip4) /
261 ICMP(type="echo-request", code=0, id=0x1fe6, seq=0x2407) /
262 Raw(load='Test-group: IPv4')),
263 (Ether(dst=self.src_if.local_mac,
264 src=self.src_if.remote_mac) /
265 IP(id=24339, flags="MF", frag=3, ttl=64,
266 src=self.src_if.remote_ip4,
267 dst=self.dst_if.remote_ip4) /
268 ICMP(type="echo-request", code=0, id=0x1fe6, seq=0x2407) /
269 Raw(load='.IPv4.Fragmentation.vali')),
270 (Ether(dst=self.src_if.local_mac,
271 src=self.src_if.remote_mac) /
272 IP(id=24339, frag=6, ttl=64,
273 src=self.src_if.remote_ip4,
274 dst=self.dst_if.remote_ip4) /
275 ICMP(type="echo-request", code=0, id=0x1fe6, seq=0x2407) /
276 Raw(load='d; Test-case: 44924'))
279 self.pg_enable_capture()
280 self.src_if.add_stream(packets)
283 self.dst_if.get_capture(1)
285 def test_frag_1(self):
286 """ fragment of size 1 """
287 self.vapi.cli("clear errors")
288 malformed_packets = [(Ether(dst=self.src_if.local_mac,
289 src=self.src_if.remote_mac) /
290 IP(id=7, len=21, flags="MF", frag=0, ttl=64,
291 src=self.src_if.remote_ip4,
292 dst=self.dst_if.remote_ip4) /
293 ICMP(type="echo-request")),
294 (Ether(dst=self.src_if.local_mac,
295 src=self.src_if.remote_mac) /
296 IP(id=7, len=21, frag=1, ttl=64,
297 src=self.src_if.remote_ip4,
298 dst=self.dst_if.remote_ip4) /
302 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
303 IP(id=1000, src=self.src_if.remote_ip4,
304 dst=self.dst_if.remote_ip4) /
305 UDP(sport=1234, dport=5678) /
307 valid_fragments = fragment_rfc791(p, 400)
309 self.pg_enable_capture()
310 self.src_if.add_stream(malformed_packets + valid_fragments)
313 self.dst_if.get_capture(1)
315 self.assert_packet_counter_equal("ip4-full-reassembly-feature", 1)
316 # TODO remove above, uncomment below once clearing of counters
318 # self.assert_packet_counter_equal(
319 # "/err/ip4-full-reassembly-feature/malformed packets", 1)
321 def test_random(self):
322 """ random order reassembly """
324 fragments = list(self.fragments_200)
327 self.pg_enable_capture()
328 self.src_if.add_stream(fragments)
331 packets = self.dst_if.get_capture(len(self.packet_infos))
332 self.verify_capture(packets)
333 self.src_if.assert_nothing_captured()
335 # run it all again to verify correctness
336 self.pg_enable_capture()
337 self.src_if.add_stream(fragments)
340 packets = self.dst_if.get_capture(len(self.packet_infos))
341 self.verify_capture(packets)
342 self.src_if.assert_nothing_captured()
344 def test_duplicates(self):
345 """ duplicate fragments """
348 x for (_, frags, _, _) in self.pkt_infos
350 for _ in range(0, min(2, len(frags)))
353 self.pg_enable_capture()
354 self.src_if.add_stream(fragments)
357 packets = self.dst_if.get_capture(len(self.pkt_infos))
358 self.verify_capture(packets)
359 self.src_if.assert_nothing_captured()
361 def test_overlap1(self):
362 """ overlapping fragments case #1 """
365 for _, _, frags_300, frags_200 in self.pkt_infos:
366 if len(frags_300) == 1:
367 fragments.extend(frags_300)
369 for i, j in zip(frags_200, frags_300):
373 self.pg_enable_capture()
374 self.src_if.add_stream(fragments)
377 packets = self.dst_if.get_capture(len(self.pkt_infos))
378 self.verify_capture(packets)
379 self.src_if.assert_nothing_captured()
381 # run it all to verify correctness
382 self.pg_enable_capture()
383 self.src_if.add_stream(fragments)
386 packets = self.dst_if.get_capture(len(self.pkt_infos))
387 self.verify_capture(packets)
388 self.src_if.assert_nothing_captured()
390 def test_overlap2(self):
391 """ overlapping fragments case #2 """
394 for _, _, frags_300, frags_200 in self.pkt_infos:
395 if len(frags_300) == 1:
396 fragments.extend(frags_300)
398 # care must be taken here so that there are no fragments
399 # received by vpp after reassembly is finished, otherwise
400 # new reassemblies will be started and packet generator will
401 # freak out when it detects unfreed buffers
402 zipped = zip(frags_300, frags_200)
408 self.pg_enable_capture()
409 self.src_if.add_stream(fragments)
412 packets = self.dst_if.get_capture(len(self.pkt_infos))
413 self.verify_capture(packets)
414 self.src_if.assert_nothing_captured()
416 # run it all to verify correctness
417 self.pg_enable_capture()
418 self.src_if.add_stream(fragments)
421 packets = self.dst_if.get_capture(len(self.pkt_infos))
422 self.verify_capture(packets)
423 self.src_if.assert_nothing_captured()
425 def test_timeout_inline(self):
426 """ timeout (inline) """
428 dropped_packet_indexes = set(
429 index for (index, frags, _, _) in self.pkt_infos if len(frags) > 1
432 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
433 max_reassembly_length=3,
434 expire_walk_interval_ms=10000)
436 self.pg_enable_capture()
437 self.src_if.add_stream(self.fragments_400)
440 packets = self.dst_if.get_capture(
441 len(self.pkt_infos) - len(dropped_packet_indexes))
442 self.verify_capture(packets, dropped_packet_indexes)
443 self.src_if.assert_nothing_captured()
445 def test_timeout_cleanup(self):
446 """ timeout (cleanup) """
448 # whole packets + fragmented packets sans last fragment
450 x for (_, frags_400, _, _) in self.pkt_infos
451 for x in frags_400[:-1 if len(frags_400) > 1 else None]
454 # last fragments for fragmented packets
455 fragments2 = [frags_400[-1]
456 for (_, frags_400, _, _) in self.pkt_infos
457 if len(frags_400) > 1]
459 dropped_packet_indexes = set(
460 index for (index, frags_400, _, _) in self.pkt_infos
461 if len(frags_400) > 1)
463 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
464 max_reassembly_length=1000,
465 expire_walk_interval_ms=50)
467 self.pg_enable_capture()
468 self.src_if.add_stream(fragments)
471 self.sleep(.25, "wait before sending rest of fragments")
473 self.src_if.add_stream(fragments2)
476 packets = self.dst_if.get_capture(
477 len(self.pkt_infos) - len(dropped_packet_indexes))
478 self.verify_capture(packets, dropped_packet_indexes)
479 self.src_if.assert_nothing_captured()
481 def test_disabled(self):
482 """ reassembly disabled """
484 dropped_packet_indexes = set(
485 index for (index, frags_400, _, _) in self.pkt_infos
486 if len(frags_400) > 1)
488 self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=0,
489 max_reassembly_length=3,
490 expire_walk_interval_ms=10000)
492 self.pg_enable_capture()
493 self.src_if.add_stream(self.fragments_400)
496 packets = self.dst_if.get_capture(
497 len(self.pkt_infos) - len(dropped_packet_indexes))
498 self.verify_capture(packets, dropped_packet_indexes)
499 self.src_if.assert_nothing_captured()
502 class TestIPv4SVReassembly(VppTestCase):
503 """ IPv4 Shallow Virtual Reassembly """
507 super(TestIPv4SVReassembly, cls).setUpClass()
509 cls.create_pg_interfaces([0, 1])
513 # setup all interfaces
514 for i in cls.pg_interfaces:
520 """ Test setup - force timeout on existing reassemblies """
521 super(TestIPv4SVReassembly, self).setUp()
522 self.vapi.ip_reassembly_enable_disable(
523 sw_if_index=self.src_if.sw_if_index, enable_ip4=True,
524 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL)
525 self.vapi.ip_reassembly_set(
526 timeout_ms=0, max_reassemblies=1000,
527 max_reassembly_length=1000,
528 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
529 expire_walk_interval_ms=10)
531 self.vapi.ip_reassembly_set(
532 timeout_ms=1000000, max_reassemblies=1000,
533 max_reassembly_length=1000,
534 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
535 expire_walk_interval_ms=10000)
538 super(TestIPv4SVReassembly, self).tearDown()
539 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
540 self.logger.debug(self.vapi.ppcli("show buffers"))
542 def test_basic(self):
543 """ basic reassembly """
547 while len(payload) < payload_len:
548 payload += "%u " % counter
551 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
552 IP(id=1, src=self.src_if.remote_ip4,
553 dst=self.dst_if.remote_ip4) /
554 UDP(sport=1234, dport=5678) /
556 fragments = fragment_rfc791(p, payload_len/4)
558 # send fragment #2 - should be cached inside reassembly
559 self.pg_enable_capture()
560 self.src_if.add_stream(fragments[1])
562 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
563 self.logger.debug(self.vapi.ppcli("show buffers"))
564 self.logger.debug(self.vapi.ppcli("show trace"))
565 self.dst_if.assert_nothing_captured()
567 # send fragment #1 - reassembly is finished now and both fragments
569 self.pg_enable_capture()
570 self.src_if.add_stream(fragments[0])
572 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
573 self.logger.debug(self.vapi.ppcli("show buffers"))
574 self.logger.debug(self.vapi.ppcli("show trace"))
575 c = self.dst_if.get_capture(2)
576 for sent, recvd in zip([fragments[1], fragments[0]], c):
577 self.assertEqual(sent[IP].src, recvd[IP].src)
578 self.assertEqual(sent[IP].dst, recvd[IP].dst)
579 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
581 # send rest of fragments - should be immediately forwarded
582 self.pg_enable_capture()
583 self.src_if.add_stream(fragments[2:])
585 c = self.dst_if.get_capture(len(fragments[2:]))
586 for sent, recvd in zip(fragments[2:], c):
587 self.assertEqual(sent[IP].src, recvd[IP].src)
588 self.assertEqual(sent[IP].dst, recvd[IP].dst)
589 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
591 def test_timeout(self):
592 """ reassembly timeout """
596 while len(payload) < payload_len:
597 payload += "%u " % counter
600 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
601 IP(id=1, src=self.src_if.remote_ip4,
602 dst=self.dst_if.remote_ip4) /
603 UDP(sport=1234, dport=5678) /
605 fragments = fragment_rfc791(p, payload_len/4)
607 self.vapi.ip_reassembly_set(
608 timeout_ms=100, max_reassemblies=1000,
609 max_reassembly_length=1000,
610 expire_walk_interval_ms=50,
611 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL)
613 # send fragments #2 and #1 - should be forwarded
614 self.pg_enable_capture()
615 self.src_if.add_stream(fragments[0:2])
617 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
618 self.logger.debug(self.vapi.ppcli("show buffers"))
619 self.logger.debug(self.vapi.ppcli("show trace"))
620 c = self.dst_if.get_capture(2)
621 for sent, recvd in zip([fragments[1], fragments[0]], c):
622 self.assertEqual(sent[IP].src, recvd[IP].src)
623 self.assertEqual(sent[IP].dst, recvd[IP].dst)
624 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
627 self.sleep(.25, "wait before sending rest of fragments")
629 # send rest of fragments - shouldn't be forwarded
630 self.pg_enable_capture()
631 self.src_if.add_stream(fragments[2:])
633 self.dst_if.assert_nothing_captured()
636 """ reassembly reuses LRU element """
638 self.vapi.ip_reassembly_set(
639 timeout_ms=1000000, max_reassemblies=1,
640 max_reassembly_length=1000,
641 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
642 expire_walk_interval_ms=10000)
647 while len(payload) < payload_len:
648 payload += "%u " % counter
654 for i in range(packet_count)
655 for p in (Ether(dst=self.src_if.local_mac,
656 src=self.src_if.remote_mac) /
657 IP(id=i, src=self.src_if.remote_ip4,
658 dst=self.dst_if.remote_ip4) /
659 UDP(sport=1234, dport=5678) /
661 for f in fragment_rfc791(p, payload_len/4)]
663 self.pg_enable_capture()
664 self.src_if.add_stream(fragments)
666 c = self.dst_if.get_capture(len(fragments))
667 for sent, recvd in zip(fragments, c):
668 self.assertEqual(sent[IP].src, recvd[IP].src)
669 self.assertEqual(sent[IP].dst, recvd[IP].dst)
670 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
672 def send_mixed_and_verify_capture(self, traffic):
675 for c in range(t['count']):
677 (Ether(dst=self.src_if.local_mac,
678 src=self.src_if.remote_mac) /
681 src=self.src_if.remote_ip4,
682 dst=self.dst_if.remote_ip4) /
683 UDP(sport=1234, dport=5678) /
685 self.counter = self.counter + 1
687 self.pg_enable_capture()
688 self.src_if.add_stream(stream)
690 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
691 self.logger.debug(self.vapi.ppcli("show buffers"))
692 self.logger.debug(self.vapi.ppcli("show trace"))
693 self.dst_if.get_capture(len(stream))
695 def test_mixed(self):
696 """ mixed traffic correctly passes through SVR """
699 self.send_mixed_and_verify_capture([{'count': 1, 'flags': ''}])
700 self.send_mixed_and_verify_capture([{'count': 2, 'flags': ''}])
701 self.send_mixed_and_verify_capture([{'count': 3, 'flags': ''}])
702 self.send_mixed_and_verify_capture([{'count': 8, 'flags': ''}])
703 self.send_mixed_and_verify_capture([{'count': 257, 'flags': ''}])
705 self.send_mixed_and_verify_capture([{'count': 1, 'flags': 'MF'}])
706 self.send_mixed_and_verify_capture([{'count': 2, 'flags': 'MF'}])
707 self.send_mixed_and_verify_capture([{'count': 3, 'flags': 'MF'}])
708 self.send_mixed_and_verify_capture([{'count': 8, 'flags': 'MF'}])
709 self.send_mixed_and_verify_capture([{'count': 257, 'flags': 'MF'}])
711 self.send_mixed_and_verify_capture(
712 [{'count': 1, 'flags': ''}, {'count': 1, 'flags': 'MF'}])
713 self.send_mixed_and_verify_capture(
714 [{'count': 2, 'flags': ''}, {'count': 2, 'flags': 'MF'}])
715 self.send_mixed_and_verify_capture(
716 [{'count': 3, 'flags': ''}, {'count': 3, 'flags': 'MF'}])
717 self.send_mixed_and_verify_capture(
718 [{'count': 8, 'flags': ''}, {'count': 8, 'flags': 'MF'}])
719 self.send_mixed_and_verify_capture(
720 [{'count': 129, 'flags': ''}, {'count': 129, 'flags': 'MF'}])
722 self.send_mixed_and_verify_capture(
723 [{'count': 1, 'flags': ''}, {'count': 1, 'flags': 'MF'},
724 {'count': 1, 'flags': ''}, {'count': 1, 'flags': 'MF'}])
725 self.send_mixed_and_verify_capture(
726 [{'count': 2, 'flags': ''}, {'count': 2, 'flags': 'MF'},
727 {'count': 2, 'flags': ''}, {'count': 2, 'flags': 'MF'}])
728 self.send_mixed_and_verify_capture(
729 [{'count': 3, 'flags': ''}, {'count': 3, 'flags': 'MF'},
730 {'count': 3, 'flags': ''}, {'count': 3, 'flags': 'MF'}])
731 self.send_mixed_and_verify_capture(
732 [{'count': 8, 'flags': ''}, {'count': 8, 'flags': 'MF'},
733 {'count': 8, 'flags': ''}, {'count': 8, 'flags': 'MF'}])
734 self.send_mixed_and_verify_capture(
735 [{'count': 65, 'flags': ''}, {'count': 65, 'flags': 'MF'},
736 {'count': 65, 'flags': ''}, {'count': 65, 'flags': 'MF'}])
739 class TestIPv4MWReassembly(VppTestCase):
740 """ IPv4 Reassembly (multiple workers) """
741 worker_config = "workers %d" % worker_count
745 super(TestIPv4MWReassembly, cls).setUpClass()
747 cls.create_pg_interfaces(range(worker_count+1))
749 cls.send_ifs = cls.pg_interfaces[:-1]
750 cls.dst_if = cls.pg_interfaces[-1]
752 # setup all interfaces
753 for i in cls.pg_interfaces:
758 # packets sizes reduced here because we are generating packets without
759 # Ethernet headers, which are added later (diff fragments go via
760 # different interfaces)
761 cls.packet_sizes = [64-len(Ether()), 512-len(Ether()),
762 1518-len(Ether()), 9018-len(Ether())]
763 cls.padding = " abcdefghijklmn"
764 cls.create_stream(cls.packet_sizes)
765 cls.create_fragments()
768 def tearDownClass(cls):
769 super(TestIPv4MWReassembly, cls).tearDownClass()
772 """ Test setup - force timeout on existing reassemblies """
773 super(TestIPv4MWReassembly, self).setUp()
774 for intf in self.send_ifs:
775 self.vapi.ip_reassembly_enable_disable(
776 sw_if_index=intf.sw_if_index, enable_ip4=True)
777 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
778 max_reassembly_length=1000,
779 expire_walk_interval_ms=10)
781 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
782 max_reassembly_length=1000,
783 expire_walk_interval_ms=10000)
786 super(TestIPv4MWReassembly, self).tearDown()
788 def show_commands_at_teardown(self):
789 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
790 self.logger.debug(self.vapi.ppcli("show buffers"))
793 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
794 """Create input packet stream
796 :param list packet_sizes: Required packet sizes.
798 for i in range(0, packet_count):
799 info = cls.create_packet_info(cls.src_if, cls.src_if)
800 payload = cls.info_to_payload(info)
801 p = (IP(id=info.index, src=cls.src_if.remote_ip4,
802 dst=cls.dst_if.remote_ip4) /
803 UDP(sport=1234, dport=5678) /
805 size = packet_sizes[(i // 2) % len(packet_sizes)]
806 cls.extend_packet(p, size, cls.padding)
810 def create_fragments(cls):
811 infos = cls._packet_infos
813 for index, info in infos.items():
815 # cls.logger.debug(ppp("Packet:",
816 # p.__class__(scapy.compat.raw(p))))
817 fragments_400 = fragment_rfc791(p, 400)
818 cls.pkt_infos.append((index, fragments_400))
819 cls.fragments_400 = [
820 x for (_, frags) in cls.pkt_infos for x in frags]
821 cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, " %
822 (len(infos), len(cls.fragments_400)))
824 def verify_capture(self, capture, dropped_packet_indexes=[]):
825 """Verify captured packet stream.
827 :param list capture: Captured packet stream.
831 for packet in capture:
833 self.logger.debug(ppp("Got packet:", packet))
836 payload_info = self.payload_to_info(packet[Raw])
837 packet_index = payload_info.index
839 packet_index not in dropped_packet_indexes,
840 ppp("Packet received, but should be dropped:", packet))
841 if packet_index in seen:
842 raise Exception(ppp("Duplicate packet received", packet))
843 seen.add(packet_index)
844 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
845 info = self._packet_infos[packet_index]
846 self.assertTrue(info is not None)
847 self.assertEqual(packet_index, info.index)
848 saved_packet = info.data
849 self.assertEqual(ip.src, saved_packet[IP].src)
850 self.assertEqual(ip.dst, saved_packet[IP].dst)
851 self.assertEqual(udp.payload, saved_packet[UDP].payload)
853 self.logger.error(ppp("Unexpected or invalid packet:", packet))
855 for index in self._packet_infos:
856 self.assertTrue(index in seen or index in dropped_packet_indexes,
857 "Packet with packet_index %d not received" % index)
859 def send_packets(self, packets):
860 for counter in range(worker_count):
861 if 0 == len(packets[counter]):
863 send_if = self.send_ifs[counter]
865 (Ether(dst=send_if.local_mac, src=send_if.remote_mac) / x
866 for x in packets[counter]),
870 def test_worker_conflict(self):
871 """ 1st and FO=0 fragments on different workers """
873 # in first wave we send fragments which don't start at offset 0
874 # then we send fragments with offset 0 on a different thread
875 # then the rest of packets on a random thread
876 first_packets = [[] for n in range(worker_count)]
877 second_packets = [[] for n in range(worker_count)]
878 rest_of_packets = [[] for n in range(worker_count)]
879 for (_, p) in self.pkt_infos:
880 wi = randrange(worker_count)
881 second_packets[wi].append(p[0])
886 wi2 = randrange(worker_count)
887 first_packets[wi2].append(p[1])
888 wi3 = randrange(worker_count)
889 rest_of_packets[wi3].extend(p[2:])
891 self.pg_enable_capture()
892 self.send_packets(first_packets)
893 self.send_packets(second_packets)
894 self.send_packets(rest_of_packets)
896 packets = self.dst_if.get_capture(len(self.pkt_infos))
897 self.verify_capture(packets)
898 for send_if in self.send_ifs:
899 send_if.assert_nothing_captured()
901 self.logger.debug(self.vapi.ppcli("show trace"))
902 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
903 self.logger.debug(self.vapi.ppcli("show buffers"))
904 self.vapi.cli("clear trace")
906 self.pg_enable_capture()
907 self.send_packets(first_packets)
908 self.send_packets(second_packets)
909 self.send_packets(rest_of_packets)
911 packets = self.dst_if.get_capture(len(self.pkt_infos))
912 self.verify_capture(packets)
913 for send_if in self.send_ifs:
914 send_if.assert_nothing_captured()
917 class TestIPv6Reassembly(VppTestCase):
918 """ IPv6 Reassembly """
922 super(TestIPv6Reassembly, cls).setUpClass()
924 cls.create_pg_interfaces([0, 1])
928 # setup all interfaces
929 for i in cls.pg_interfaces:
935 cls.packet_sizes = [64, 512, 1518, 9018]
936 cls.padding = " abcdefghijklmn"
937 cls.create_stream(cls.packet_sizes)
938 cls.create_fragments()
941 def tearDownClass(cls):
942 super(TestIPv6Reassembly, cls).tearDownClass()
945 """ Test setup - force timeout on existing reassemblies """
946 super(TestIPv6Reassembly, self).setUp()
947 self.vapi.ip_reassembly_enable_disable(
948 sw_if_index=self.src_if.sw_if_index, enable_ip6=True)
949 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
950 max_reassembly_length=1000,
951 expire_walk_interval_ms=10, is_ip6=1)
953 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
954 max_reassembly_length=1000,
955 expire_walk_interval_ms=10000, is_ip6=1)
956 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
957 self.logger.debug(self.vapi.ppcli("show buffers"))
960 super(TestIPv6Reassembly, self).tearDown()
962 def show_commands_at_teardown(self):
963 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
964 self.logger.debug(self.vapi.ppcli("show buffers"))
967 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
968 """Create input packet stream for defined interface.
970 :param list packet_sizes: Required packet sizes.
972 for i in range(0, packet_count):
973 info = cls.create_packet_info(cls.src_if, cls.src_if)
974 payload = cls.info_to_payload(info)
975 p = (Ether(dst=cls.src_if.local_mac, src=cls.src_if.remote_mac) /
976 IPv6(src=cls.src_if.remote_ip6,
977 dst=cls.dst_if.remote_ip6) /
978 UDP(sport=1234, dport=5678) /
980 size = packet_sizes[(i // 2) % len(packet_sizes)]
981 cls.extend_packet(p, size, cls.padding)
985 def create_fragments(cls):
986 infos = cls._packet_infos
988 for index, info in infos.items():
990 # cls.logger.debug(ppp("Packet:",
991 # p.__class__(scapy.compat.raw(p))))
992 fragments_400 = fragment_rfc8200(p, info.index, 400)
993 fragments_300 = fragment_rfc8200(p, info.index, 300)
994 cls.pkt_infos.append((index, fragments_400, fragments_300))
995 cls.fragments_400 = [
996 x for _, frags, _ in cls.pkt_infos for x in frags]
997 cls.fragments_300 = [
998 x for _, _, frags in cls.pkt_infos for x in frags]
999 cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, "
1000 "and %s 300-byte fragments" %
1001 (len(infos), len(cls.fragments_400),
1002 len(cls.fragments_300)))
1004 def verify_capture(self, capture, dropped_packet_indexes=[]):
1005 """Verify captured packet strea .
1007 :param list capture: Captured packet stream.
1011 for packet in capture:
1013 self.logger.debug(ppp("Got packet:", packet))
1016 payload_info = self.payload_to_info(packet[Raw])
1017 packet_index = payload_info.index
1019 packet_index not in dropped_packet_indexes,
1020 ppp("Packet received, but should be dropped:", packet))
1021 if packet_index in seen:
1022 raise Exception(ppp("Duplicate packet received", packet))
1023 seen.add(packet_index)
1024 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
1025 info = self._packet_infos[packet_index]
1026 self.assertTrue(info is not None)
1027 self.assertEqual(packet_index, info.index)
1028 saved_packet = info.data
1029 self.assertEqual(ip.src, saved_packet[IPv6].src)
1030 self.assertEqual(ip.dst, saved_packet[IPv6].dst)
1031 self.assertEqual(udp.payload, saved_packet[UDP].payload)
1033 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1035 for index in self._packet_infos:
1036 self.assertTrue(index in seen or index in dropped_packet_indexes,
1037 "Packet with packet_index %d not received" % index)
1039 def test_reassembly(self):
1040 """ basic reassembly """
1042 self.pg_enable_capture()
1043 self.src_if.add_stream(self.fragments_400)
1046 packets = self.dst_if.get_capture(len(self.pkt_infos))
1047 self.verify_capture(packets)
1048 self.src_if.assert_nothing_captured()
1050 # run it all again to verify correctness
1051 self.pg_enable_capture()
1052 self.src_if.add_stream(self.fragments_400)
1055 packets = self.dst_if.get_capture(len(self.pkt_infos))
1056 self.verify_capture(packets)
1057 self.src_if.assert_nothing_captured()
1059 def test_buffer_boundary(self):
1060 """ fragment header crossing buffer boundary """
1062 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1063 IPv6(src=self.src_if.remote_ip6,
1064 dst=self.src_if.local_ip6) /
1066 options=[HBHOptUnknown(otype=0xff, optlen=0)] * 1000) /
1067 IPv6ExtHdrFragment(m=1) /
1068 UDP(sport=1234, dport=5678) /
1070 self.pg_enable_capture()
1071 self.src_if.add_stream([p])
1073 self.src_if.assert_nothing_captured()
1074 self.dst_if.assert_nothing_captured()
1076 def test_reversed(self):
1077 """ reverse order reassembly """
1079 fragments = list(self.fragments_400)
1082 self.pg_enable_capture()
1083 self.src_if.add_stream(fragments)
1086 packets = self.dst_if.get_capture(len(self.pkt_infos))
1087 self.verify_capture(packets)
1088 self.src_if.assert_nothing_captured()
1090 # run it all again to verify correctness
1091 self.pg_enable_capture()
1092 self.src_if.add_stream(fragments)
1095 packets = self.dst_if.get_capture(len(self.pkt_infos))
1096 self.verify_capture(packets)
1097 self.src_if.assert_nothing_captured()
1099 def test_random(self):
1100 """ random order reassembly """
1102 fragments = list(self.fragments_400)
1105 self.pg_enable_capture()
1106 self.src_if.add_stream(fragments)
1109 packets = self.dst_if.get_capture(len(self.pkt_infos))
1110 self.verify_capture(packets)
1111 self.src_if.assert_nothing_captured()
1113 # run it all again to verify correctness
1114 self.pg_enable_capture()
1115 self.src_if.add_stream(fragments)
1118 packets = self.dst_if.get_capture(len(self.pkt_infos))
1119 self.verify_capture(packets)
1120 self.src_if.assert_nothing_captured()
1122 def test_duplicates(self):
1123 """ duplicate fragments """
1126 x for (_, frags, _) in self.pkt_infos
1128 for _ in range(0, min(2, len(frags)))
1131 self.pg_enable_capture()
1132 self.src_if.add_stream(fragments)
1135 packets = self.dst_if.get_capture(len(self.pkt_infos))
1136 self.verify_capture(packets)
1137 self.src_if.assert_nothing_captured()
1139 def test_long_fragment_chain(self):
1140 """ long fragment chain """
1143 "/err/ip6-full-reassembly-feature/fragment chain too long (drop)"
1145 error_cnt = self.statistics.get_err_counter(error_cnt_str)
1147 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
1148 max_reassembly_length=3,
1149 expire_walk_interval_ms=50, is_ip6=1)
1151 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1152 IPv6(src=self.src_if.remote_ip6,
1153 dst=self.dst_if.remote_ip6) /
1154 UDP(sport=1234, dport=5678) /
1156 frags = fragment_rfc8200(p, 1, 300) + fragment_rfc8200(p, 2, 500)
1158 self.pg_enable_capture()
1159 self.src_if.add_stream(frags)
1162 self.dst_if.get_capture(1)
1163 self.assert_error_counter_equal(error_cnt_str, error_cnt + 1)
1165 def test_overlap1(self):
1166 """ overlapping fragments case #1 """
1169 for _, frags_400, frags_300 in self.pkt_infos:
1170 if len(frags_300) == 1:
1171 fragments.extend(frags_400)
1173 for i, j in zip(frags_300, frags_400):
1177 dropped_packet_indexes = set(
1178 index for (index, _, frags) in self.pkt_infos if len(frags) > 1
1181 self.pg_enable_capture()
1182 self.src_if.add_stream(fragments)
1185 packets = self.dst_if.get_capture(
1186 len(self.pkt_infos) - len(dropped_packet_indexes))
1187 self.verify_capture(packets, dropped_packet_indexes)
1188 self.src_if.assert_nothing_captured()
1190 def test_overlap2(self):
1191 """ overlapping fragments case #2 """
1194 for _, frags_400, frags_300 in self.pkt_infos:
1195 if len(frags_400) == 1:
1196 fragments.extend(frags_400)
1198 # care must be taken here so that there are no fragments
1199 # received by vpp after reassembly is finished, otherwise
1200 # new reassemblies will be started and packet generator will
1201 # freak out when it detects unfreed buffers
1202 zipped = zip(frags_400, frags_300)
1208 dropped_packet_indexes = set(
1209 index for (index, _, frags) in self.pkt_infos if len(frags) > 1
1212 self.pg_enable_capture()
1213 self.src_if.add_stream(fragments)
1216 packets = self.dst_if.get_capture(
1217 len(self.pkt_infos) - len(dropped_packet_indexes))
1218 self.verify_capture(packets, dropped_packet_indexes)
1219 self.src_if.assert_nothing_captured()
1221 def test_timeout_inline(self):
1222 """ timeout (inline) """
1224 dropped_packet_indexes = set(
1225 index for (index, frags, _) in self.pkt_infos if len(frags) > 1
1228 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
1229 max_reassembly_length=3,
1230 expire_walk_interval_ms=10000, is_ip6=1)
1232 self.pg_enable_capture()
1233 self.src_if.add_stream(self.fragments_400)
1236 packets = self.dst_if.get_capture(
1237 len(self.pkt_infos) - len(dropped_packet_indexes))
1238 self.verify_capture(packets, dropped_packet_indexes)
1239 pkts = self.src_if.get_capture(
1240 expected_count=len(dropped_packet_indexes))
1242 self.assertIn(ICMPv6TimeExceeded, icmp)
1243 self.assertIn(IPv6ExtHdrFragment, icmp)
1244 self.assertIn(icmp[IPv6ExtHdrFragment].id, dropped_packet_indexes)
1245 dropped_packet_indexes.remove(icmp[IPv6ExtHdrFragment].id)
1247 def test_timeout_cleanup(self):
1248 """ timeout (cleanup) """
1250 # whole packets + fragmented packets sans last fragment
1252 x for (_, frags_400, _) in self.pkt_infos
1253 for x in frags_400[:-1 if len(frags_400) > 1 else None]
1256 # last fragments for fragmented packets
1257 fragments2 = [frags_400[-1]
1258 for (_, frags_400, _) in self.pkt_infos
1259 if len(frags_400) > 1]
1261 dropped_packet_indexes = set(
1262 index for (index, frags_400, _) in self.pkt_infos
1263 if len(frags_400) > 1)
1265 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
1266 max_reassembly_length=1000,
1267 expire_walk_interval_ms=50)
1269 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
1270 max_reassembly_length=1000,
1271 expire_walk_interval_ms=50, is_ip6=1)
1273 self.pg_enable_capture()
1274 self.src_if.add_stream(fragments)
1277 self.sleep(.25, "wait before sending rest of fragments")
1279 self.src_if.add_stream(fragments2)
1282 packets = self.dst_if.get_capture(
1283 len(self.pkt_infos) - len(dropped_packet_indexes))
1284 self.verify_capture(packets, dropped_packet_indexes)
1285 pkts = self.src_if.get_capture(
1286 expected_count=len(dropped_packet_indexes))
1288 self.assertIn(ICMPv6TimeExceeded, icmp)
1289 self.assertIn(IPv6ExtHdrFragment, icmp)
1290 self.assertIn(icmp[IPv6ExtHdrFragment].id, dropped_packet_indexes)
1291 dropped_packet_indexes.remove(icmp[IPv6ExtHdrFragment].id)
1293 def test_disabled(self):
1294 """ reassembly disabled """
1296 dropped_packet_indexes = set(
1297 index for (index, frags_400, _) in self.pkt_infos
1298 if len(frags_400) > 1)
1300 self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=0,
1301 max_reassembly_length=3,
1302 expire_walk_interval_ms=10000, is_ip6=1)
1304 self.pg_enable_capture()
1305 self.src_if.add_stream(self.fragments_400)
1308 packets = self.dst_if.get_capture(
1309 len(self.pkt_infos) - len(dropped_packet_indexes))
1310 self.verify_capture(packets, dropped_packet_indexes)
1311 self.src_if.assert_nothing_captured()
1313 def test_missing_upper(self):
1314 """ missing upper layer """
1315 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1316 IPv6(src=self.src_if.remote_ip6,
1317 dst=self.src_if.local_ip6) /
1318 UDP(sport=1234, dport=5678) /
1320 self.extend_packet(p, 1000, self.padding)
1321 fragments = fragment_rfc8200(p, 1, 500)
1322 bad_fragment = p.__class__(scapy.compat.raw(fragments[1]))
1323 bad_fragment[IPv6ExtHdrFragment].nh = 59
1324 bad_fragment[IPv6ExtHdrFragment].offset = 0
1325 self.pg_enable_capture()
1326 self.src_if.add_stream([bad_fragment])
1328 pkts = self.src_if.get_capture(expected_count=1)
1330 self.assertIn(ICMPv6ParamProblem, icmp)
1331 self.assert_equal(icmp[ICMPv6ParamProblem].code, 3, "ICMP code")
1333 def test_invalid_frag_size(self):
1334 """ fragment size not a multiple of 8 """
1335 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1336 IPv6(src=self.src_if.remote_ip6,
1337 dst=self.src_if.local_ip6) /
1338 UDP(sport=1234, dport=5678) /
1340 self.extend_packet(p, 1000, self.padding)
1341 fragments = fragment_rfc8200(p, 1, 500)
1342 bad_fragment = fragments[0]
1343 self.extend_packet(bad_fragment, len(bad_fragment) + 5)
1344 self.pg_enable_capture()
1345 self.src_if.add_stream([bad_fragment])
1347 pkts = self.src_if.get_capture(expected_count=1)
1349 self.assertIn(ICMPv6ParamProblem, icmp)
1350 self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code")
1352 def test_invalid_packet_size(self):
1353 """ total packet size > 65535 """
1354 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1355 IPv6(src=self.src_if.remote_ip6,
1356 dst=self.src_if.local_ip6) /
1357 UDP(sport=1234, dport=5678) /
1359 self.extend_packet(p, 1000, self.padding)
1360 fragments = fragment_rfc8200(p, 1, 500)
1361 bad_fragment = fragments[1]
1362 bad_fragment[IPv6ExtHdrFragment].offset = 65500
1363 self.pg_enable_capture()
1364 self.src_if.add_stream([bad_fragment])
1366 pkts = self.src_if.get_capture(expected_count=1)
1368 self.assertIn(ICMPv6ParamProblem, icmp)
1369 self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code")
1372 class TestIPv6MWReassembly(VppTestCase):
1373 """ IPv6 Reassembly (multiple workers) """
1374 worker_config = "workers %d" % worker_count
1377 def setUpClass(cls):
1378 super(TestIPv6MWReassembly, cls).setUpClass()
1380 cls.create_pg_interfaces(range(worker_count+1))
1381 cls.src_if = cls.pg0
1382 cls.send_ifs = cls.pg_interfaces[:-1]
1383 cls.dst_if = cls.pg_interfaces[-1]
1385 # setup all interfaces
1386 for i in cls.pg_interfaces:
1391 # packets sizes reduced here because we are generating packets without
1392 # Ethernet headers, which are added later (diff fragments go via
1393 # different interfaces)
1394 cls.packet_sizes = [64-len(Ether()), 512-len(Ether()),
1395 1518-len(Ether()), 9018-len(Ether())]
1396 cls.padding = " abcdefghijklmn"
1397 cls.create_stream(cls.packet_sizes)
1398 cls.create_fragments()
1401 def tearDownClass(cls):
1402 super(TestIPv6MWReassembly, cls).tearDownClass()
1405 """ Test setup - force timeout on existing reassemblies """
1406 super(TestIPv6MWReassembly, self).setUp()
1407 for intf in self.send_ifs:
1408 self.vapi.ip_reassembly_enable_disable(
1409 sw_if_index=intf.sw_if_index, enable_ip6=True)
1410 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
1411 max_reassembly_length=1000,
1412 expire_walk_interval_ms=10, is_ip6=1)
1414 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
1415 max_reassembly_length=1000,
1416 expire_walk_interval_ms=1000, is_ip6=1)
1419 super(TestIPv6MWReassembly, self).tearDown()
1421 def show_commands_at_teardown(self):
1422 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
1423 self.logger.debug(self.vapi.ppcli("show buffers"))
1426 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
1427 """Create input packet stream
1429 :param list packet_sizes: Required packet sizes.
1431 for i in range(0, packet_count):
1432 info = cls.create_packet_info(cls.src_if, cls.src_if)
1433 payload = cls.info_to_payload(info)
1434 p = (IPv6(src=cls.src_if.remote_ip6,
1435 dst=cls.dst_if.remote_ip6) /
1436 UDP(sport=1234, dport=5678) /
1438 size = packet_sizes[(i // 2) % len(packet_sizes)]
1439 cls.extend_packet(p, size, cls.padding)
1443 def create_fragments(cls):
1444 infos = cls._packet_infos
1446 for index, info in infos.items():
1448 # cls.logger.debug(ppp("Packet:",
1449 # p.__class__(scapy.compat.raw(p))))
1450 fragments_400 = fragment_rfc8200(p, index, 400)
1451 cls.pkt_infos.append((index, fragments_400))
1452 cls.fragments_400 = [
1453 x for (_, frags) in cls.pkt_infos for x in frags]
1454 cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, " %
1455 (len(infos), len(cls.fragments_400)))
1457 def verify_capture(self, capture, dropped_packet_indexes=[]):
1458 """Verify captured packet strea .
1460 :param list capture: Captured packet stream.
1464 for packet in capture:
1466 self.logger.debug(ppp("Got packet:", packet))
1469 payload_info = self.payload_to_info(packet[Raw])
1470 packet_index = payload_info.index
1472 packet_index not in dropped_packet_indexes,
1473 ppp("Packet received, but should be dropped:", packet))
1474 if packet_index in seen:
1475 raise Exception(ppp("Duplicate packet received", packet))
1476 seen.add(packet_index)
1477 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
1478 info = self._packet_infos[packet_index]
1479 self.assertTrue(info is not None)
1480 self.assertEqual(packet_index, info.index)
1481 saved_packet = info.data
1482 self.assertEqual(ip.src, saved_packet[IPv6].src)
1483 self.assertEqual(ip.dst, saved_packet[IPv6].dst)
1484 self.assertEqual(udp.payload, saved_packet[UDP].payload)
1486 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1488 for index in self._packet_infos:
1489 self.assertTrue(index in seen or index in dropped_packet_indexes,
1490 "Packet with packet_index %d not received" % index)
1492 def send_packets(self, packets):
1493 for counter in range(worker_count):
1494 if 0 == len(packets[counter]):
1496 send_if = self.send_ifs[counter]
1498 (Ether(dst=send_if.local_mac, src=send_if.remote_mac) / x
1499 for x in packets[counter]),
1503 def test_worker_conflict(self):
1504 """ 1st and FO=0 fragments on different workers """
1506 # in first wave we send fragments which don't start at offset 0
1507 # then we send fragments with offset 0 on a different thread
1508 # then the rest of packets on a random thread
1509 first_packets = [[] for n in range(worker_count)]
1510 second_packets = [[] for n in range(worker_count)]
1511 rest_of_packets = [[] for n in range(worker_count)]
1512 for (_, p) in self.pkt_infos:
1513 wi = randrange(worker_count)
1514 second_packets[wi].append(p[0])
1519 wi2 = randrange(worker_count)
1520 first_packets[wi2].append(p[1])
1521 wi3 = randrange(worker_count)
1522 rest_of_packets[wi3].extend(p[2:])
1524 self.pg_enable_capture()
1525 self.send_packets(first_packets)
1526 self.send_packets(second_packets)
1527 self.send_packets(rest_of_packets)
1529 packets = self.dst_if.get_capture(len(self.pkt_infos))
1530 self.verify_capture(packets)
1531 for send_if in self.send_ifs:
1532 send_if.assert_nothing_captured()
1534 self.logger.debug(self.vapi.ppcli("show trace"))
1535 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
1536 self.logger.debug(self.vapi.ppcli("show buffers"))
1537 self.vapi.cli("clear trace")
1539 self.pg_enable_capture()
1540 self.send_packets(first_packets)
1541 self.send_packets(second_packets)
1542 self.send_packets(rest_of_packets)
1544 packets = self.dst_if.get_capture(len(self.pkt_infos))
1545 self.verify_capture(packets)
1546 for send_if in self.send_ifs:
1547 send_if.assert_nothing_captured()
1550 class TestIPv6SVReassembly(VppTestCase):
1551 """ IPv6 Shallow Virtual Reassembly """
1554 def setUpClass(cls):
1555 super(TestIPv6SVReassembly, cls).setUpClass()
1557 cls.create_pg_interfaces([0, 1])
1558 cls.src_if = cls.pg0
1559 cls.dst_if = cls.pg1
1561 # setup all interfaces
1562 for i in cls.pg_interfaces:
1568 """ Test setup - force timeout on existing reassemblies """
1569 super(TestIPv6SVReassembly, self).setUp()
1570 self.vapi.ip_reassembly_enable_disable(
1571 sw_if_index=self.src_if.sw_if_index, enable_ip6=True,
1572 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL)
1573 self.vapi.ip_reassembly_set(
1574 timeout_ms=0, max_reassemblies=1000,
1575 max_reassembly_length=1000,
1576 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
1577 expire_walk_interval_ms=10, is_ip6=1)
1579 self.vapi.ip_reassembly_set(
1580 timeout_ms=1000000, max_reassemblies=1000,
1581 max_reassembly_length=1000,
1582 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
1583 expire_walk_interval_ms=10000, is_ip6=1)
1586 super(TestIPv6SVReassembly, self).tearDown()
1587 self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details"))
1588 self.logger.debug(self.vapi.ppcli("show buffers"))
1590 def test_basic(self):
1591 """ basic reassembly """
1595 while len(payload) < payload_len:
1596 payload += "%u " % counter
1599 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1600 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1601 UDP(sport=1234, dport=5678) /
1603 fragments = fragment_rfc8200(p, 1, payload_len/4)
1605 # send fragment #2 - should be cached inside reassembly
1606 self.pg_enable_capture()
1607 self.src_if.add_stream(fragments[1])
1609 self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details"))
1610 self.logger.debug(self.vapi.ppcli("show buffers"))
1611 self.logger.debug(self.vapi.ppcli("show trace"))
1612 self.dst_if.assert_nothing_captured()
1614 # send fragment #1 - reassembly is finished now and both fragments
1616 self.pg_enable_capture()
1617 self.src_if.add_stream(fragments[0])
1619 self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details"))
1620 self.logger.debug(self.vapi.ppcli("show buffers"))
1621 self.logger.debug(self.vapi.ppcli("show trace"))
1622 c = self.dst_if.get_capture(2)
1623 for sent, recvd in zip([fragments[1], fragments[0]], c):
1624 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
1625 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
1626 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
1628 # send rest of fragments - should be immediately forwarded
1629 self.pg_enable_capture()
1630 self.src_if.add_stream(fragments[2:])
1632 c = self.dst_if.get_capture(len(fragments[2:]))
1633 for sent, recvd in zip(fragments[2:], c):
1634 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
1635 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
1636 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
1638 def test_timeout(self):
1639 """ reassembly timeout """
1643 while len(payload) < payload_len:
1644 payload += "%u " % counter
1647 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1648 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1649 UDP(sport=1234, dport=5678) /
1651 fragments = fragment_rfc8200(p, 1, payload_len/4)
1653 self.vapi.ip_reassembly_set(
1654 timeout_ms=100, max_reassemblies=1000,
1655 max_reassembly_length=1000,
1656 expire_walk_interval_ms=50,
1658 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL)
1660 # send fragments #2 and #1 - should be forwarded
1661 self.pg_enable_capture()
1662 self.src_if.add_stream(fragments[0:2])
1664 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
1665 self.logger.debug(self.vapi.ppcli("show buffers"))
1666 self.logger.debug(self.vapi.ppcli("show trace"))
1667 c = self.dst_if.get_capture(2)
1668 for sent, recvd in zip([fragments[1], fragments[0]], c):
1669 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
1670 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
1671 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
1674 self.sleep(.25, "wait before sending rest of fragments")
1676 # send rest of fragments - shouldn't be forwarded
1677 self.pg_enable_capture()
1678 self.src_if.add_stream(fragments[2:])
1680 self.dst_if.assert_nothing_captured()
1683 """ reassembly reuses LRU element """
1685 self.vapi.ip_reassembly_set(
1686 timeout_ms=1000000, max_reassemblies=1,
1687 max_reassembly_length=1000,
1688 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
1689 is_ip6=1, expire_walk_interval_ms=10000)
1694 while len(payload) < payload_len:
1695 payload += "%u " % counter
1701 for i in range(packet_count)
1702 for p in (Ether(dst=self.src_if.local_mac,
1703 src=self.src_if.remote_mac) /
1704 IPv6(src=self.src_if.remote_ip6,
1705 dst=self.dst_if.remote_ip6) /
1706 UDP(sport=1234, dport=5678) /
1708 for f in fragment_rfc8200(p, i, payload_len/4)]
1710 self.pg_enable_capture()
1711 self.src_if.add_stream(fragments)
1713 c = self.dst_if.get_capture(len(fragments))
1714 for sent, recvd in zip(fragments, c):
1715 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
1716 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
1717 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
1720 class TestIPv4ReassemblyLocalNode(VppTestCase):
1721 """ IPv4 Reassembly for packets coming to ip4-local node """
1724 def setUpClass(cls):
1725 super(TestIPv4ReassemblyLocalNode, cls).setUpClass()
1727 cls.create_pg_interfaces([0])
1728 cls.src_dst_if = cls.pg0
1730 # setup all interfaces
1731 for i in cls.pg_interfaces:
1736 cls.padding = " abcdefghijklmn"
1738 cls.create_fragments()
1741 def tearDownClass(cls):
1742 super(TestIPv4ReassemblyLocalNode, cls).tearDownClass()
1745 """ Test setup - force timeout on existing reassemblies """
1746 super(TestIPv4ReassemblyLocalNode, self).setUp()
1747 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
1748 max_reassembly_length=1000,
1749 expire_walk_interval_ms=10)
1751 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
1752 max_reassembly_length=1000,
1753 expire_walk_interval_ms=10000)
1756 super(TestIPv4ReassemblyLocalNode, self).tearDown()
1758 def show_commands_at_teardown(self):
1759 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
1760 self.logger.debug(self.vapi.ppcli("show buffers"))
1763 def create_stream(cls, packet_count=test_packet_count):
1764 """Create input packet stream for defined interface.
1766 :param list packet_sizes: Required packet sizes.
1768 for i in range(0, packet_count):
1769 info = cls.create_packet_info(cls.src_dst_if, cls.src_dst_if)
1770 payload = cls.info_to_payload(info)
1771 p = (Ether(dst=cls.src_dst_if.local_mac,
1772 src=cls.src_dst_if.remote_mac) /
1773 IP(id=info.index, src=cls.src_dst_if.remote_ip4,
1774 dst=cls.src_dst_if.local_ip4) /
1775 ICMP(type='echo-request', id=1234) /
1777 cls.extend_packet(p, 1518, cls.padding)
1781 def create_fragments(cls):
1782 infos = cls._packet_infos
1784 for index, info in infos.items():
1786 # cls.logger.debug(ppp("Packet:",
1787 # p.__class__(scapy.compat.raw(p))))
1788 fragments_300 = fragment_rfc791(p, 300)
1789 cls.pkt_infos.append((index, fragments_300))
1790 cls.fragments_300 = [x for (_, frags) in cls.pkt_infos for x in frags]
1791 cls.logger.debug("Fragmented %s packets into %s 300-byte fragments" %
1792 (len(infos), len(cls.fragments_300)))
1794 def verify_capture(self, capture):
1795 """Verify captured packet stream.
1797 :param list capture: Captured packet stream.
1801 for packet in capture:
1803 self.logger.debug(ppp("Got packet:", packet))
1806 payload_info = self.payload_to_info(packet[Raw])
1807 packet_index = payload_info.index
1808 if packet_index in seen:
1809 raise Exception(ppp("Duplicate packet received", packet))
1810 seen.add(packet_index)
1811 self.assertEqual(payload_info.dst, self.src_dst_if.sw_if_index)
1812 info = self._packet_infos[packet_index]
1813 self.assertIsNotNone(info)
1814 self.assertEqual(packet_index, info.index)
1815 saved_packet = info.data
1816 self.assertEqual(ip.src, saved_packet[IP].dst)
1817 self.assertEqual(ip.dst, saved_packet[IP].src)
1818 self.assertEqual(icmp.type, 0) # echo reply
1819 self.assertEqual(icmp.id, saved_packet[ICMP].id)
1820 self.assertEqual(icmp.payload, saved_packet[ICMP].payload)
1822 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1824 for index in self._packet_infos:
1825 self.assertIn(index, seen,
1826 "Packet with packet_index %d not received" % index)
1828 def test_reassembly(self):
1829 """ basic reassembly """
1831 self.pg_enable_capture()
1832 self.src_dst_if.add_stream(self.fragments_300)
1835 packets = self.src_dst_if.get_capture(len(self.pkt_infos))
1836 self.verify_capture(packets)
1838 # run it all again to verify correctness
1839 self.pg_enable_capture()
1840 self.src_dst_if.add_stream(self.fragments_300)
1843 packets = self.src_dst_if.get_capture(len(self.pkt_infos))
1844 self.verify_capture(packets)
1847 class TestFIFReassembly(VppTestCase):
1848 """ Fragments in fragments reassembly """
1851 def setUpClass(cls):
1852 super(TestFIFReassembly, cls).setUpClass()
1854 cls.create_pg_interfaces([0, 1])
1855 cls.src_if = cls.pg0
1856 cls.dst_if = cls.pg1
1857 for i in cls.pg_interfaces:
1864 cls.packet_sizes = [64, 512, 1518, 9018]
1865 cls.padding = " abcdefghijklmn"
1868 def tearDownClass(cls):
1869 super(TestFIFReassembly, cls).tearDownClass()
1872 """ Test setup - force timeout on existing reassemblies """
1873 super(TestFIFReassembly, self).setUp()
1874 self.vapi.ip_reassembly_enable_disable(
1875 sw_if_index=self.src_if.sw_if_index, enable_ip4=True,
1877 self.vapi.ip_reassembly_enable_disable(
1878 sw_if_index=self.dst_if.sw_if_index, enable_ip4=True,
1880 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
1881 max_reassembly_length=1000,
1882 expire_walk_interval_ms=10)
1883 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
1884 max_reassembly_length=1000,
1885 expire_walk_interval_ms=10, is_ip6=1)
1887 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
1888 max_reassembly_length=1000,
1889 expire_walk_interval_ms=10000)
1890 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
1891 max_reassembly_length=1000,
1892 expire_walk_interval_ms=10000, is_ip6=1)
1895 super(TestFIFReassembly, self).tearDown()
1897 def show_commands_at_teardown(self):
1898 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
1899 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
1900 self.logger.debug(self.vapi.ppcli("show buffers"))
1902 def verify_capture(self, capture, ip_class, dropped_packet_indexes=[]):
1903 """Verify captured packet stream.
1905 :param list capture: Captured packet stream.
1909 for packet in capture:
1911 self.logger.debug(ppp("Got packet:", packet))
1912 ip = packet[ip_class]
1914 payload_info = self.payload_to_info(packet[Raw])
1915 packet_index = payload_info.index
1917 packet_index not in dropped_packet_indexes,
1918 ppp("Packet received, but should be dropped:", packet))
1919 if packet_index in seen:
1920 raise Exception(ppp("Duplicate packet received", packet))
1921 seen.add(packet_index)
1922 self.assertEqual(payload_info.dst, self.dst_if.sw_if_index)
1923 info = self._packet_infos[packet_index]
1924 self.assertTrue(info is not None)
1925 self.assertEqual(packet_index, info.index)
1926 saved_packet = info.data
1927 self.assertEqual(ip.src, saved_packet[ip_class].src)
1928 self.assertEqual(ip.dst, saved_packet[ip_class].dst)
1929 self.assertEqual(udp.payload, saved_packet[UDP].payload)
1931 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1933 for index in self._packet_infos:
1934 self.assertTrue(index in seen or index in dropped_packet_indexes,
1935 "Packet with packet_index %d not received" % index)
1937 def test_fif4(self):
1938 """ Fragments in fragments (4o4) """
1940 # TODO this should be ideally in setUpClass, but then we hit a bug
1941 # with VppIpRoute incorrectly reporting it's present when it's not
1942 # so we need to manually remove the vpp config, thus we cannot have
1943 # it shared for multiple test cases
1944 self.tun_ip4 = "1.1.1.2"
1946 self.gre4 = VppGreInterface(self, self.src_if.local_ip4, self.tun_ip4)
1947 self.gre4.add_vpp_config()
1948 self.gre4.admin_up()
1949 self.gre4.config_ip4()
1951 self.vapi.ip_reassembly_enable_disable(
1952 sw_if_index=self.gre4.sw_if_index, enable_ip4=True)
1954 self.route4 = VppIpRoute(self, self.tun_ip4, 32,
1955 [VppRoutePath(self.src_if.remote_ip4,
1956 self.src_if.sw_if_index)])
1957 self.route4.add_vpp_config()
1959 self.reset_packet_infos()
1960 for i in range(test_packet_count):
1961 info = self.create_packet_info(self.src_if, self.dst_if)
1962 payload = self.info_to_payload(info)
1963 # Ethernet header here is only for size calculation, thus it
1964 # doesn't matter how it's initialized. This is to ensure that
1965 # reassembled packet is not > 9000 bytes, so that it's not dropped
1967 IP(id=i, src=self.src_if.remote_ip4,
1968 dst=self.dst_if.remote_ip4) /
1969 UDP(sport=1234, dport=5678) /
1971 size = self.packet_sizes[(i // 2) % len(self.packet_sizes)]
1972 self.extend_packet(p, size, self.padding)
1973 info.data = p[IP] # use only IP part, without ethernet header
1975 fragments = [x for _, p in self._packet_infos.items()
1976 for x in fragment_rfc791(p.data, 400)]
1978 encapped_fragments = \
1979 [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1980 IP(src=self.tun_ip4, dst=self.src_if.local_ip4) /
1985 fragmented_encapped_fragments = \
1986 [x for p in encapped_fragments
1987 for x in fragment_rfc791(p, 200)]
1989 self.src_if.add_stream(fragmented_encapped_fragments)
1991 self.pg_enable_capture(self.pg_interfaces)
1994 self.src_if.assert_nothing_captured()
1995 packets = self.dst_if.get_capture(len(self._packet_infos))
1996 self.verify_capture(packets, IP)
1998 # TODO remove gre vpp config by hand until VppIpRoute gets fixed
1999 # so that it's query_vpp_config() works as it should
2000 self.gre4.remove_vpp_config()
2001 self.logger.debug(self.vapi.ppcli("show interface"))
2003 def test_fif6(self):
2004 """ Fragments in fragments (6o6) """
2005 # TODO this should be ideally in setUpClass, but then we hit a bug
2006 # with VppIpRoute incorrectly reporting it's present when it's not
2007 # so we need to manually remove the vpp config, thus we cannot have
2008 # it shared for multiple test cases
2009 self.tun_ip6 = "1002::1"
2011 self.gre6 = VppGreInterface(self, self.src_if.local_ip6, self.tun_ip6)
2012 self.gre6.add_vpp_config()
2013 self.gre6.admin_up()
2014 self.gre6.config_ip6()
2016 self.vapi.ip_reassembly_enable_disable(
2017 sw_if_index=self.gre6.sw_if_index, enable_ip6=True)
2019 self.route6 = VppIpRoute(self, self.tun_ip6, 128,
2021 self.src_if.remote_ip6,
2022 self.src_if.sw_if_index)])
2023 self.route6.add_vpp_config()
2025 self.reset_packet_infos()
2026 for i in range(test_packet_count):
2027 info = self.create_packet_info(self.src_if, self.dst_if)
2028 payload = self.info_to_payload(info)
2029 # Ethernet header here is only for size calculation, thus it
2030 # doesn't matter how it's initialized. This is to ensure that
2031 # reassembled packet is not > 9000 bytes, so that it's not dropped
2033 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
2034 UDP(sport=1234, dport=5678) /
2036 size = self.packet_sizes[(i // 2) % len(self.packet_sizes)]
2037 self.extend_packet(p, size, self.padding)
2038 info.data = p[IPv6] # use only IPv6 part, without ethernet header
2040 fragments = [x for _, i in self._packet_infos.items()
2041 for x in fragment_rfc8200(
2042 i.data, i.index, 400)]
2044 encapped_fragments = \
2045 [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
2046 IPv6(src=self.tun_ip6, dst=self.src_if.local_ip6) /
2051 fragmented_encapped_fragments = \
2052 [x for p in encapped_fragments for x in (
2055 2 * len(self._packet_infos) + p[IPv6ExtHdrFragment].id,
2057 if IPv6ExtHdrFragment in p else [p]
2061 self.src_if.add_stream(fragmented_encapped_fragments)
2063 self.pg_enable_capture(self.pg_interfaces)
2066 self.src_if.assert_nothing_captured()
2067 packets = self.dst_if.get_capture(len(self._packet_infos))
2068 self.verify_capture(packets, IPv6)
2070 # TODO remove gre vpp config by hand until VppIpRoute gets fixed
2071 # so that it's query_vpp_config() works as it should
2072 self.gre6.remove_vpp_config()
2075 if __name__ == '__main__':
2076 unittest.main(testRunner=VppTestRunner)