5 from random import shuffle, choice, randrange
7 from framework import VppTestCase, VppTestRunner
10 from scapy.packet import Raw
11 from scapy.layers.l2 import Ether, GRE
12 from scapy.layers.inet import IP, UDP, ICMP
13 from scapy.layers.inet6 import HBHOptUnknown, ICMPv6ParamProblem,\
14 ICMPv6TimeExceeded, IPv6, IPv6ExtHdrFragment, IPv6ExtHdrHopByHop
15 from framework import VppTestCase, VppTestRunner
16 from util import ppp, ppc, fragment_rfc791, fragment_rfc8200
17 from vpp_gre_interface import VppGreInterface
18 from vpp_ip import DpoProto
19 from vpp_ip_route import VppIpRoute, VppRoutePath, FibPathProto
20 from vpp_papi import VppEnum
22 # 35 is enough to have >257 400-byte fragments
23 test_packet_count = 35
25 # number of workers used for multi-worker test cases
29 class TestIPv4Reassembly(VppTestCase):
30 """ IPv4 Reassembly """
34 super(TestIPv4Reassembly, cls).setUpClass()
36 cls.create_pg_interfaces([0, 1])
40 # setup all interfaces
41 for i in cls.pg_interfaces:
47 cls.packet_sizes = [64, 512, 1518, 9018]
48 cls.padding = " abcdefghijklmn"
49 cls.create_stream(cls.packet_sizes)
50 cls.create_fragments()
53 def tearDownClass(cls):
54 super(TestIPv4Reassembly, cls).tearDownClass()
57 """ Test setup - force timeout on existing reassemblies """
58 super(TestIPv4Reassembly, self).setUp()
59 self.vapi.ip_reassembly_enable_disable(
60 sw_if_index=self.src_if.sw_if_index, enable_ip4=True)
61 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
62 max_reassembly_length=1000,
63 expire_walk_interval_ms=10)
65 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
66 max_reassembly_length=1000,
67 expire_walk_interval_ms=10000)
70 super(TestIPv4Reassembly, self).tearDown()
72 def show_commands_at_teardown(self):
73 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
74 self.logger.debug(self.vapi.ppcli("show buffers"))
77 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
78 """Create input packet stream
80 :param list packet_sizes: Required packet sizes.
82 for i in range(0, packet_count):
83 info = cls.create_packet_info(cls.src_if, cls.src_if)
84 payload = cls.info_to_payload(info)
85 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) /
90 size = packet_sizes[(i // 2) % len(packet_sizes)]
91 cls.extend_packet(p, size, cls.padding)
95 def create_fragments(cls):
96 infos = cls._packet_infos
98 for index, info in six.iteritems(infos):
100 # cls.logger.debug(ppp("Packet:",
101 # p.__class__(scapy.compat.raw(p))))
102 fragments_400 = fragment_rfc791(p, 400)
103 fragments_300 = fragment_rfc791(p, 300)
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)))
119 def verify_capture(self, capture, dropped_packet_indexes=[]):
120 """Verify captured packet stream.
122 :param list capture: Captured packet stream.
126 for packet in capture:
128 self.logger.debug(ppp("Got packet:", packet))
131 payload_info = self.payload_to_info(packet[Raw])
132 packet_index = payload_info.index
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)
148 self.logger.error(ppp("Unexpected or invalid packet:", packet))
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)
154 def test_reassembly(self):
155 """ basic reassembly """
157 self.pg_enable_capture()
158 self.src_if.add_stream(self.fragments_200)
161 packets = self.dst_if.get_capture(len(self.pkt_infos))
162 self.verify_capture(packets)
163 self.src_if.assert_nothing_captured()
165 # run it all again to verify correctness
166 self.pg_enable_capture()
167 self.src_if.add_stream(self.fragments_200)
170 packets = self.dst_if.get_capture(len(self.pkt_infos))
171 self.verify_capture(packets)
172 self.src_if.assert_nothing_captured()
174 def test_reversed(self):
175 """ reverse order reassembly """
177 fragments = list(self.fragments_200)
180 self.pg_enable_capture()
181 self.src_if.add_stream(fragments)
184 packets = self.dst_if.get_capture(len(self.packet_infos))
185 self.verify_capture(packets)
186 self.src_if.assert_nothing_captured()
188 # run it all again to verify correctness
189 self.pg_enable_capture()
190 self.src_if.add_stream(fragments)
193 packets = self.dst_if.get_capture(len(self.packet_infos))
194 self.verify_capture(packets)
195 self.src_if.assert_nothing_captured()
197 def test_long_fragment_chain(self):
198 """ long fragment chain """
201 "/err/ip4-full-reassembly-feature/fragment chain too long (drop)"
203 error_cnt = self.statistics.get_err_counter(error_cnt_str)
205 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
206 max_reassembly_length=3,
207 expire_walk_interval_ms=50)
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) /
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) /
219 frags = fragment_rfc791(p1, 200) + fragment_rfc791(p2, 500)
221 self.pg_enable_capture()
222 self.src_if.add_stream(frags)
225 self.dst_if.get_capture(1)
226 self.assert_error_counter_equal(error_cnt_str, error_cnt + 1)
229 """ fragment length + ip header size > 65535 """
230 self.vapi.cli("clear errors")
231 raw = b'''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-message.\
233 Ethernet-Payload.IPv4-Packet.IPv4-Header.Fragment-Offset; Test-case: 5737'''
234 malformed_packet = (Ether(dst=self.src_if.local_mac,
235 src=self.src_if.remote_mac) /
237 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
238 IP(id=1000, src=self.src_if.remote_ip4,
239 dst=self.dst_if.remote_ip4) /
240 UDP(sport=1234, dport=5678) /
242 valid_fragments = fragment_rfc791(p, 400)
244 counter = "/err/ip4-full-reassembly-feature/malformed packets"
245 error_counter = self.statistics.get_err_counter(counter)
246 self.pg_enable_capture()
247 self.src_if.add_stream([malformed_packet] + valid_fragments)
250 self.dst_if.get_capture(1)
251 self.logger.debug(self.vapi.ppcli("show error"))
252 self.assertEqual(self.statistics.get_err_counter(counter),
255 def test_44924(self):
256 """ compress tiny fragments """
257 packets = [(Ether(dst=self.src_if.local_mac,
258 src=self.src_if.remote_mac) /
259 IP(id=24339, flags="MF", frag=0, ttl=64,
260 src=self.src_if.remote_ip4,
261 dst=self.dst_if.remote_ip4) /
262 ICMP(type="echo-request", code=0, id=0x1fe6, seq=0x2407) /
263 Raw(load='Test-group: IPv4')),
264 (Ether(dst=self.src_if.local_mac,
265 src=self.src_if.remote_mac) /
266 IP(id=24339, flags="MF", frag=3, ttl=64,
267 src=self.src_if.remote_ip4,
268 dst=self.dst_if.remote_ip4) /
269 ICMP(type="echo-request", code=0, id=0x1fe6, seq=0x2407) /
270 Raw(load='.IPv4.Fragmentation.vali')),
271 (Ether(dst=self.src_if.local_mac,
272 src=self.src_if.remote_mac) /
273 IP(id=24339, frag=6, ttl=64,
274 src=self.src_if.remote_ip4,
275 dst=self.dst_if.remote_ip4) /
276 ICMP(type="echo-request", code=0, id=0x1fe6, seq=0x2407) /
277 Raw(load='d; Test-case: 44924'))
280 self.pg_enable_capture()
281 self.src_if.add_stream(packets)
284 self.dst_if.get_capture(1)
286 def test_frag_1(self):
287 """ fragment of size 1 """
288 self.vapi.cli("clear errors")
289 malformed_packets = [(Ether(dst=self.src_if.local_mac,
290 src=self.src_if.remote_mac) /
291 IP(id=7, len=21, flags="MF", frag=0, ttl=64,
292 src=self.src_if.remote_ip4,
293 dst=self.dst_if.remote_ip4) /
294 ICMP(type="echo-request")),
295 (Ether(dst=self.src_if.local_mac,
296 src=self.src_if.remote_mac) /
297 IP(id=7, len=21, frag=1, ttl=64,
298 src=self.src_if.remote_ip4,
299 dst=self.dst_if.remote_ip4) /
303 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
304 IP(id=1000, src=self.src_if.remote_ip4,
305 dst=self.dst_if.remote_ip4) /
306 UDP(sport=1234, dport=5678) /
308 valid_fragments = fragment_rfc791(p, 400)
310 self.pg_enable_capture()
311 self.src_if.add_stream(malformed_packets + valid_fragments)
314 self.dst_if.get_capture(1)
316 self.assert_packet_counter_equal("ip4-full-reassembly-feature", 1)
317 # TODO remove above, uncomment below once clearing of counters
319 # self.assert_packet_counter_equal(
320 # "/err/ip4-full-reassembly-feature/malformed packets", 1)
322 def test_random(self):
323 """ random order reassembly """
325 fragments = list(self.fragments_200)
328 self.pg_enable_capture()
329 self.src_if.add_stream(fragments)
332 packets = self.dst_if.get_capture(len(self.packet_infos))
333 self.verify_capture(packets)
334 self.src_if.assert_nothing_captured()
336 # run it all again to verify correctness
337 self.pg_enable_capture()
338 self.src_if.add_stream(fragments)
341 packets = self.dst_if.get_capture(len(self.packet_infos))
342 self.verify_capture(packets)
343 self.src_if.assert_nothing_captured()
345 def test_duplicates(self):
346 """ duplicate fragments """
349 x for (_, frags, _, _) in self.pkt_infos
351 for _ in range(0, min(2, len(frags)))
354 self.pg_enable_capture()
355 self.src_if.add_stream(fragments)
358 packets = self.dst_if.get_capture(len(self.pkt_infos))
359 self.verify_capture(packets)
360 self.src_if.assert_nothing_captured()
362 def test_overlap1(self):
363 """ overlapping fragments case #1 """
366 for _, _, frags_300, frags_200 in self.pkt_infos:
367 if len(frags_300) == 1:
368 fragments.extend(frags_300)
370 for i, j in zip(frags_200, frags_300):
374 self.pg_enable_capture()
375 self.src_if.add_stream(fragments)
378 packets = self.dst_if.get_capture(len(self.pkt_infos))
379 self.verify_capture(packets)
380 self.src_if.assert_nothing_captured()
382 # run it all to verify correctness
383 self.pg_enable_capture()
384 self.src_if.add_stream(fragments)
387 packets = self.dst_if.get_capture(len(self.pkt_infos))
388 self.verify_capture(packets)
389 self.src_if.assert_nothing_captured()
391 def test_overlap2(self):
392 """ overlapping fragments case #2 """
395 for _, _, frags_300, frags_200 in self.pkt_infos:
396 if len(frags_300) == 1:
397 fragments.extend(frags_300)
399 # care must be taken here so that there are no fragments
400 # received by vpp after reassembly is finished, otherwise
401 # new reassemblies will be started and packet generator will
402 # freak out when it detects unfreed buffers
403 zipped = zip(frags_300, frags_200)
409 self.pg_enable_capture()
410 self.src_if.add_stream(fragments)
413 packets = self.dst_if.get_capture(len(self.pkt_infos))
414 self.verify_capture(packets)
415 self.src_if.assert_nothing_captured()
417 # run it all to verify correctness
418 self.pg_enable_capture()
419 self.src_if.add_stream(fragments)
422 packets = self.dst_if.get_capture(len(self.pkt_infos))
423 self.verify_capture(packets)
424 self.src_if.assert_nothing_captured()
426 def test_timeout_inline(self):
427 """ timeout (inline) """
429 dropped_packet_indexes = set(
430 index for (index, frags, _, _) in self.pkt_infos if len(frags) > 1
433 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
434 max_reassembly_length=3,
435 expire_walk_interval_ms=10000)
437 self.pg_enable_capture()
438 self.src_if.add_stream(self.fragments_400)
441 packets = self.dst_if.get_capture(
442 len(self.pkt_infos) - len(dropped_packet_indexes))
443 self.verify_capture(packets, dropped_packet_indexes)
444 self.src_if.assert_nothing_captured()
446 def test_timeout_cleanup(self):
447 """ timeout (cleanup) """
449 # whole packets + fragmented packets sans last fragment
451 x for (_, frags_400, _, _) in self.pkt_infos
452 for x in frags_400[:-1 if len(frags_400) > 1 else None]
455 # last fragments for fragmented packets
456 fragments2 = [frags_400[-1]
457 for (_, frags_400, _, _) in self.pkt_infos
458 if len(frags_400) > 1]
460 dropped_packet_indexes = set(
461 index for (index, frags_400, _, _) in self.pkt_infos
462 if len(frags_400) > 1)
464 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
465 max_reassembly_length=1000,
466 expire_walk_interval_ms=50)
468 self.pg_enable_capture()
469 self.src_if.add_stream(fragments)
472 self.sleep(.25, "wait before sending rest of fragments")
474 self.src_if.add_stream(fragments2)
477 packets = self.dst_if.get_capture(
478 len(self.pkt_infos) - len(dropped_packet_indexes))
479 self.verify_capture(packets, dropped_packet_indexes)
480 self.src_if.assert_nothing_captured()
482 def test_disabled(self):
483 """ reassembly disabled """
485 dropped_packet_indexes = set(
486 index for (index, frags_400, _, _) in self.pkt_infos
487 if len(frags_400) > 1)
489 self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=0,
490 max_reassembly_length=3,
491 expire_walk_interval_ms=10000)
493 self.pg_enable_capture()
494 self.src_if.add_stream(self.fragments_400)
497 packets = self.dst_if.get_capture(
498 len(self.pkt_infos) - len(dropped_packet_indexes))
499 self.verify_capture(packets, dropped_packet_indexes)
500 self.src_if.assert_nothing_captured()
503 class TestIPv4SVReassembly(VppTestCase):
504 """ IPv4 Shallow Virtual Reassembly """
508 super(TestIPv4SVReassembly, cls).setUpClass()
510 cls.create_pg_interfaces([0, 1])
514 # setup all interfaces
515 for i in cls.pg_interfaces:
521 """ Test setup - force timeout on existing reassemblies """
522 super(TestIPv4SVReassembly, self).setUp()
523 self.vapi.ip_reassembly_enable_disable(
524 sw_if_index=self.src_if.sw_if_index, enable_ip4=True,
525 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL)
526 self.vapi.ip_reassembly_set(
527 timeout_ms=0, max_reassemblies=1000,
528 max_reassembly_length=1000,
529 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
530 expire_walk_interval_ms=10)
532 self.vapi.ip_reassembly_set(
533 timeout_ms=1000000, max_reassemblies=1000,
534 max_reassembly_length=1000,
535 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
536 expire_walk_interval_ms=10000)
539 super(TestIPv4SVReassembly, self).tearDown()
540 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
541 self.logger.debug(self.vapi.ppcli("show buffers"))
543 def test_basic(self):
544 """ basic reassembly """
548 while len(payload) < payload_len:
549 payload += "%u " % counter
552 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
553 IP(id=1, src=self.src_if.remote_ip4,
554 dst=self.dst_if.remote_ip4) /
555 UDP(sport=1234, dport=5678) /
557 fragments = fragment_rfc791(p, payload_len/4)
559 # send fragment #2 - should be cached inside reassembly
560 self.pg_enable_capture()
561 self.src_if.add_stream(fragments[1])
563 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
564 self.logger.debug(self.vapi.ppcli("show buffers"))
565 self.logger.debug(self.vapi.ppcli("show trace"))
566 self.dst_if.assert_nothing_captured()
568 # send fragment #1 - reassembly is finished now and both fragments
570 self.pg_enable_capture()
571 self.src_if.add_stream(fragments[0])
573 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
574 self.logger.debug(self.vapi.ppcli("show buffers"))
575 self.logger.debug(self.vapi.ppcli("show trace"))
576 c = self.dst_if.get_capture(2)
577 for sent, recvd in zip([fragments[1], fragments[0]], c):
578 self.assertEqual(sent[IP].src, recvd[IP].src)
579 self.assertEqual(sent[IP].dst, recvd[IP].dst)
580 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
582 # send rest of fragments - should be immediately forwarded
583 self.pg_enable_capture()
584 self.src_if.add_stream(fragments[2:])
586 c = self.dst_if.get_capture(len(fragments[2:]))
587 for sent, recvd in zip(fragments[2:], c):
588 self.assertEqual(sent[IP].src, recvd[IP].src)
589 self.assertEqual(sent[IP].dst, recvd[IP].dst)
590 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
592 def test_timeout(self):
593 """ reassembly timeout """
597 while len(payload) < payload_len:
598 payload += "%u " % counter
601 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
602 IP(id=1, src=self.src_if.remote_ip4,
603 dst=self.dst_if.remote_ip4) /
604 UDP(sport=1234, dport=5678) /
606 fragments = fragment_rfc791(p, payload_len/4)
608 self.vapi.ip_reassembly_set(
609 timeout_ms=100, max_reassemblies=1000,
610 max_reassembly_length=1000,
611 expire_walk_interval_ms=50,
612 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL)
614 # send fragments #2 and #1 - should be forwarded
615 self.pg_enable_capture()
616 self.src_if.add_stream(fragments[0:2])
618 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
619 self.logger.debug(self.vapi.ppcli("show buffers"))
620 self.logger.debug(self.vapi.ppcli("show trace"))
621 c = self.dst_if.get_capture(2)
622 for sent, recvd in zip([fragments[1], fragments[0]], c):
623 self.assertEqual(sent[IP].src, recvd[IP].src)
624 self.assertEqual(sent[IP].dst, recvd[IP].dst)
625 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
628 self.sleep(.25, "wait before sending rest of fragments")
630 # send rest of fragments - shouldn't be forwarded
631 self.pg_enable_capture()
632 self.src_if.add_stream(fragments[2:])
634 self.dst_if.assert_nothing_captured()
637 """ reassembly reuses LRU element """
639 self.vapi.ip_reassembly_set(
640 timeout_ms=1000000, max_reassemblies=1,
641 max_reassembly_length=1000,
642 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
643 expire_walk_interval_ms=10000)
648 while len(payload) < payload_len:
649 payload += "%u " % counter
655 for i in range(packet_count)
656 for p in (Ether(dst=self.src_if.local_mac,
657 src=self.src_if.remote_mac) /
658 IP(id=i, src=self.src_if.remote_ip4,
659 dst=self.dst_if.remote_ip4) /
660 UDP(sport=1234, dport=5678) /
662 for f in fragment_rfc791(p, payload_len/4)]
664 self.pg_enable_capture()
665 self.src_if.add_stream(fragments)
667 c = self.dst_if.get_capture(len(fragments))
668 for sent, recvd in zip(fragments, c):
669 self.assertEqual(sent[IP].src, recvd[IP].src)
670 self.assertEqual(sent[IP].dst, recvd[IP].dst)
671 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
673 def send_mixed_and_verify_capture(self, traffic):
676 for c in range(t['count']):
678 (Ether(dst=self.src_if.local_mac,
679 src=self.src_if.remote_mac) /
682 src=self.src_if.remote_ip4,
683 dst=self.dst_if.remote_ip4) /
684 UDP(sport=1234, dport=5678) /
686 self.counter = self.counter + 1
688 self.pg_enable_capture()
689 self.src_if.add_stream(stream)
691 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
692 self.logger.debug(self.vapi.ppcli("show buffers"))
693 self.logger.debug(self.vapi.ppcli("show trace"))
694 self.dst_if.get_capture(len(stream))
696 def test_mixed(self):
697 """ mixed traffic correctly passes through SVR """
700 self.send_mixed_and_verify_capture([{'count': 1, 'flags': ''}])
701 self.send_mixed_and_verify_capture([{'count': 2, 'flags': ''}])
702 self.send_mixed_and_verify_capture([{'count': 3, 'flags': ''}])
703 self.send_mixed_and_verify_capture([{'count': 8, 'flags': ''}])
704 self.send_mixed_and_verify_capture([{'count': 257, 'flags': ''}])
706 self.send_mixed_and_verify_capture([{'count': 1, 'flags': 'MF'}])
707 self.send_mixed_and_verify_capture([{'count': 2, 'flags': 'MF'}])
708 self.send_mixed_and_verify_capture([{'count': 3, 'flags': 'MF'}])
709 self.send_mixed_and_verify_capture([{'count': 8, 'flags': 'MF'}])
710 self.send_mixed_and_verify_capture([{'count': 257, 'flags': 'MF'}])
712 self.send_mixed_and_verify_capture(
713 [{'count': 1, 'flags': ''}, {'count': 1, 'flags': 'MF'}])
714 self.send_mixed_and_verify_capture(
715 [{'count': 2, 'flags': ''}, {'count': 2, 'flags': 'MF'}])
716 self.send_mixed_and_verify_capture(
717 [{'count': 3, 'flags': ''}, {'count': 3, 'flags': 'MF'}])
718 self.send_mixed_and_verify_capture(
719 [{'count': 8, 'flags': ''}, {'count': 8, 'flags': 'MF'}])
720 self.send_mixed_and_verify_capture(
721 [{'count': 129, 'flags': ''}, {'count': 129, 'flags': 'MF'}])
723 self.send_mixed_and_verify_capture(
724 [{'count': 1, 'flags': ''}, {'count': 1, 'flags': 'MF'},
725 {'count': 1, 'flags': ''}, {'count': 1, 'flags': 'MF'}])
726 self.send_mixed_and_verify_capture(
727 [{'count': 2, 'flags': ''}, {'count': 2, 'flags': 'MF'},
728 {'count': 2, 'flags': ''}, {'count': 2, 'flags': 'MF'}])
729 self.send_mixed_and_verify_capture(
730 [{'count': 3, 'flags': ''}, {'count': 3, 'flags': 'MF'},
731 {'count': 3, 'flags': ''}, {'count': 3, 'flags': 'MF'}])
732 self.send_mixed_and_verify_capture(
733 [{'count': 8, 'flags': ''}, {'count': 8, 'flags': 'MF'},
734 {'count': 8, 'flags': ''}, {'count': 8, 'flags': 'MF'}])
735 self.send_mixed_and_verify_capture(
736 [{'count': 65, 'flags': ''}, {'count': 65, 'flags': 'MF'},
737 {'count': 65, 'flags': ''}, {'count': 65, 'flags': 'MF'}])
740 class TestIPv4MWReassembly(VppTestCase):
741 """ IPv4 Reassembly (multiple workers) """
742 worker_config = "workers %d" % worker_count
746 super(TestIPv4MWReassembly, cls).setUpClass()
748 cls.create_pg_interfaces(range(worker_count+1))
750 cls.send_ifs = cls.pg_interfaces[:-1]
751 cls.dst_if = cls.pg_interfaces[-1]
753 # setup all interfaces
754 for i in cls.pg_interfaces:
759 # packets sizes reduced here because we are generating packets without
760 # Ethernet headers, which are added later (diff fragments go via
761 # different interfaces)
762 cls.packet_sizes = [64-len(Ether()), 512-len(Ether()),
763 1518-len(Ether()), 9018-len(Ether())]
764 cls.padding = " abcdefghijklmn"
765 cls.create_stream(cls.packet_sizes)
766 cls.create_fragments()
769 def tearDownClass(cls):
770 super(TestIPv4MWReassembly, cls).tearDownClass()
773 """ Test setup - force timeout on existing reassemblies """
774 super(TestIPv4MWReassembly, self).setUp()
775 for intf in self.send_ifs:
776 self.vapi.ip_reassembly_enable_disable(
777 sw_if_index=intf.sw_if_index, enable_ip4=True)
778 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
779 max_reassembly_length=1000,
780 expire_walk_interval_ms=10)
782 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
783 max_reassembly_length=1000,
784 expire_walk_interval_ms=10000)
787 super(TestIPv4MWReassembly, self).tearDown()
789 def show_commands_at_teardown(self):
790 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
791 self.logger.debug(self.vapi.ppcli("show buffers"))
794 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
795 """Create input packet stream
797 :param list packet_sizes: Required packet sizes.
799 for i in range(0, packet_count):
800 info = cls.create_packet_info(cls.src_if, cls.src_if)
801 payload = cls.info_to_payload(info)
802 p = (IP(id=info.index, src=cls.src_if.remote_ip4,
803 dst=cls.dst_if.remote_ip4) /
804 UDP(sport=1234, dport=5678) /
806 size = packet_sizes[(i // 2) % len(packet_sizes)]
807 cls.extend_packet(p, size, cls.padding)
811 def create_fragments(cls):
812 infos = cls._packet_infos
814 for index, info in six.iteritems(infos):
816 # cls.logger.debug(ppp("Packet:",
817 # p.__class__(scapy.compat.raw(p))))
818 fragments_400 = fragment_rfc791(p, 400)
819 cls.pkt_infos.append((index, fragments_400))
820 cls.fragments_400 = [
821 x for (_, frags) in cls.pkt_infos for x in frags]
822 cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, " %
823 (len(infos), len(cls.fragments_400)))
825 def verify_capture(self, capture, dropped_packet_indexes=[]):
826 """Verify captured packet stream.
828 :param list capture: Captured packet stream.
832 for packet in capture:
834 self.logger.debug(ppp("Got packet:", packet))
837 payload_info = self.payload_to_info(packet[Raw])
838 packet_index = payload_info.index
840 packet_index not in dropped_packet_indexes,
841 ppp("Packet received, but should be dropped:", packet))
842 if packet_index in seen:
843 raise Exception(ppp("Duplicate packet received", packet))
844 seen.add(packet_index)
845 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
846 info = self._packet_infos[packet_index]
847 self.assertTrue(info is not None)
848 self.assertEqual(packet_index, info.index)
849 saved_packet = info.data
850 self.assertEqual(ip.src, saved_packet[IP].src)
851 self.assertEqual(ip.dst, saved_packet[IP].dst)
852 self.assertEqual(udp.payload, saved_packet[UDP].payload)
854 self.logger.error(ppp("Unexpected or invalid packet:", packet))
856 for index in self._packet_infos:
857 self.assertTrue(index in seen or index in dropped_packet_indexes,
858 "Packet with packet_index %d not received" % index)
860 def send_packets(self, packets):
861 for counter in range(worker_count):
862 if 0 == len(packets[counter]):
864 send_if = self.send_ifs[counter]
866 (Ether(dst=send_if.local_mac, src=send_if.remote_mac) / x
867 for x in packets[counter]),
871 def test_worker_conflict(self):
872 """ 1st and FO=0 fragments on different workers """
874 # in first wave we send fragments which don't start at offset 0
875 # then we send fragments with offset 0 on a different thread
876 # then the rest of packets on a random thread
877 first_packets = [[] for n in range(worker_count)]
878 second_packets = [[] for n in range(worker_count)]
879 rest_of_packets = [[] for n in range(worker_count)]
880 for (_, p) in self.pkt_infos:
881 wi = randrange(worker_count)
882 second_packets[wi].append(p[0])
887 wi2 = randrange(worker_count)
888 first_packets[wi2].append(p[1])
889 wi3 = randrange(worker_count)
890 rest_of_packets[wi3].extend(p[2:])
892 self.pg_enable_capture()
893 self.send_packets(first_packets)
894 self.send_packets(second_packets)
895 self.send_packets(rest_of_packets)
897 packets = self.dst_if.get_capture(len(self.pkt_infos))
898 self.verify_capture(packets)
899 for send_if in self.send_ifs:
900 send_if.assert_nothing_captured()
902 self.logger.debug(self.vapi.ppcli("show trace"))
903 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
904 self.logger.debug(self.vapi.ppcli("show buffers"))
905 self.vapi.cli("clear trace")
907 self.pg_enable_capture()
908 self.send_packets(first_packets)
909 self.send_packets(second_packets)
910 self.send_packets(rest_of_packets)
912 packets = self.dst_if.get_capture(len(self.pkt_infos))
913 self.verify_capture(packets)
914 for send_if in self.send_ifs:
915 send_if.assert_nothing_captured()
918 class TestIPv6Reassembly(VppTestCase):
919 """ IPv6 Reassembly """
923 super(TestIPv6Reassembly, cls).setUpClass()
925 cls.create_pg_interfaces([0, 1])
929 # setup all interfaces
930 for i in cls.pg_interfaces:
936 cls.packet_sizes = [64, 512, 1518, 9018]
937 cls.padding = " abcdefghijklmn"
938 cls.create_stream(cls.packet_sizes)
939 cls.create_fragments()
942 def tearDownClass(cls):
943 super(TestIPv6Reassembly, cls).tearDownClass()
946 """ Test setup - force timeout on existing reassemblies """
947 super(TestIPv6Reassembly, self).setUp()
948 self.vapi.ip_reassembly_enable_disable(
949 sw_if_index=self.src_if.sw_if_index, enable_ip6=True)
950 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
951 max_reassembly_length=1000,
952 expire_walk_interval_ms=10, is_ip6=1)
954 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
955 max_reassembly_length=1000,
956 expire_walk_interval_ms=10000, is_ip6=1)
957 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
958 self.logger.debug(self.vapi.ppcli("show buffers"))
961 super(TestIPv6Reassembly, self).tearDown()
963 def show_commands_at_teardown(self):
964 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
965 self.logger.debug(self.vapi.ppcli("show buffers"))
968 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
969 """Create input packet stream for defined interface.
971 :param list packet_sizes: Required packet sizes.
973 for i in range(0, packet_count):
974 info = cls.create_packet_info(cls.src_if, cls.src_if)
975 payload = cls.info_to_payload(info)
976 p = (Ether(dst=cls.src_if.local_mac, src=cls.src_if.remote_mac) /
977 IPv6(src=cls.src_if.remote_ip6,
978 dst=cls.dst_if.remote_ip6) /
979 UDP(sport=1234, dport=5678) /
981 size = packet_sizes[(i // 2) % len(packet_sizes)]
982 cls.extend_packet(p, size, cls.padding)
986 def create_fragments(cls):
987 infos = cls._packet_infos
989 for index, info in six.iteritems(infos):
991 # cls.logger.debug(ppp("Packet:",
992 # p.__class__(scapy.compat.raw(p))))
993 fragments_400 = fragment_rfc8200(p, info.index, 400)
994 fragments_300 = fragment_rfc8200(p, info.index, 300)
995 cls.pkt_infos.append((index, fragments_400, fragments_300))
996 cls.fragments_400 = [
997 x for _, frags, _ in cls.pkt_infos for x in frags]
998 cls.fragments_300 = [
999 x for _, _, frags in cls.pkt_infos for x in frags]
1000 cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, "
1001 "and %s 300-byte fragments" %
1002 (len(infos), len(cls.fragments_400),
1003 len(cls.fragments_300)))
1005 def verify_capture(self, capture, dropped_packet_indexes=[]):
1006 """Verify captured packet strea .
1008 :param list capture: Captured packet stream.
1012 for packet in capture:
1014 self.logger.debug(ppp("Got packet:", packet))
1017 payload_info = self.payload_to_info(packet[Raw])
1018 packet_index = payload_info.index
1020 packet_index not in dropped_packet_indexes,
1021 ppp("Packet received, but should be dropped:", packet))
1022 if packet_index in seen:
1023 raise Exception(ppp("Duplicate packet received", packet))
1024 seen.add(packet_index)
1025 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
1026 info = self._packet_infos[packet_index]
1027 self.assertTrue(info is not None)
1028 self.assertEqual(packet_index, info.index)
1029 saved_packet = info.data
1030 self.assertEqual(ip.src, saved_packet[IPv6].src)
1031 self.assertEqual(ip.dst, saved_packet[IPv6].dst)
1032 self.assertEqual(udp.payload, saved_packet[UDP].payload)
1034 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1036 for index in self._packet_infos:
1037 self.assertTrue(index in seen or index in dropped_packet_indexes,
1038 "Packet with packet_index %d not received" % index)
1040 def test_reassembly(self):
1041 """ basic reassembly """
1043 self.pg_enable_capture()
1044 self.src_if.add_stream(self.fragments_400)
1047 packets = self.dst_if.get_capture(len(self.pkt_infos))
1048 self.verify_capture(packets)
1049 self.src_if.assert_nothing_captured()
1051 # run it all again to verify correctness
1052 self.pg_enable_capture()
1053 self.src_if.add_stream(self.fragments_400)
1056 packets = self.dst_if.get_capture(len(self.pkt_infos))
1057 self.verify_capture(packets)
1058 self.src_if.assert_nothing_captured()
1060 def test_buffer_boundary(self):
1061 """ fragment header crossing buffer boundary """
1063 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1064 IPv6(src=self.src_if.remote_ip6,
1065 dst=self.src_if.local_ip6) /
1067 options=[HBHOptUnknown(otype=0xff, optlen=0)] * 1000) /
1068 IPv6ExtHdrFragment(m=1) /
1069 UDP(sport=1234, dport=5678) /
1071 self.pg_enable_capture()
1072 self.src_if.add_stream([p])
1074 self.src_if.assert_nothing_captured()
1075 self.dst_if.assert_nothing_captured()
1077 def test_reversed(self):
1078 """ reverse order reassembly """
1080 fragments = list(self.fragments_400)
1083 self.pg_enable_capture()
1084 self.src_if.add_stream(fragments)
1087 packets = self.dst_if.get_capture(len(self.pkt_infos))
1088 self.verify_capture(packets)
1089 self.src_if.assert_nothing_captured()
1091 # run it all again to verify correctness
1092 self.pg_enable_capture()
1093 self.src_if.add_stream(fragments)
1096 packets = self.dst_if.get_capture(len(self.pkt_infos))
1097 self.verify_capture(packets)
1098 self.src_if.assert_nothing_captured()
1100 def test_random(self):
1101 """ random order reassembly """
1103 fragments = list(self.fragments_400)
1106 self.pg_enable_capture()
1107 self.src_if.add_stream(fragments)
1110 packets = self.dst_if.get_capture(len(self.pkt_infos))
1111 self.verify_capture(packets)
1112 self.src_if.assert_nothing_captured()
1114 # run it all again to verify correctness
1115 self.pg_enable_capture()
1116 self.src_if.add_stream(fragments)
1119 packets = self.dst_if.get_capture(len(self.pkt_infos))
1120 self.verify_capture(packets)
1121 self.src_if.assert_nothing_captured()
1123 def test_duplicates(self):
1124 """ duplicate fragments """
1127 x for (_, frags, _) in self.pkt_infos
1129 for _ in range(0, min(2, len(frags)))
1132 self.pg_enable_capture()
1133 self.src_if.add_stream(fragments)
1136 packets = self.dst_if.get_capture(len(self.pkt_infos))
1137 self.verify_capture(packets)
1138 self.src_if.assert_nothing_captured()
1140 def test_long_fragment_chain(self):
1141 """ long fragment chain """
1144 "/err/ip6-full-reassembly-feature/fragment chain too long (drop)"
1146 error_cnt = self.statistics.get_err_counter(error_cnt_str)
1148 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
1149 max_reassembly_length=3,
1150 expire_walk_interval_ms=50, is_ip6=1)
1152 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1153 IPv6(src=self.src_if.remote_ip6,
1154 dst=self.dst_if.remote_ip6) /
1155 UDP(sport=1234, dport=5678) /
1157 frags = fragment_rfc8200(p, 1, 300) + fragment_rfc8200(p, 2, 500)
1159 self.pg_enable_capture()
1160 self.src_if.add_stream(frags)
1163 self.dst_if.get_capture(1)
1164 self.assert_error_counter_equal(error_cnt_str, error_cnt + 1)
1166 def test_overlap1(self):
1167 """ overlapping fragments case #1 """
1170 for _, frags_400, frags_300 in self.pkt_infos:
1171 if len(frags_300) == 1:
1172 fragments.extend(frags_400)
1174 for i, j in zip(frags_300, frags_400):
1178 dropped_packet_indexes = set(
1179 index for (index, _, frags) in self.pkt_infos if len(frags) > 1
1182 self.pg_enable_capture()
1183 self.src_if.add_stream(fragments)
1186 packets = self.dst_if.get_capture(
1187 len(self.pkt_infos) - len(dropped_packet_indexes))
1188 self.verify_capture(packets, dropped_packet_indexes)
1189 self.src_if.assert_nothing_captured()
1191 def test_overlap2(self):
1192 """ overlapping fragments case #2 """
1195 for _, frags_400, frags_300 in self.pkt_infos:
1196 if len(frags_400) == 1:
1197 fragments.extend(frags_400)
1199 # care must be taken here so that there are no fragments
1200 # received by vpp after reassembly is finished, otherwise
1201 # new reassemblies will be started and packet generator will
1202 # freak out when it detects unfreed buffers
1203 zipped = zip(frags_400, frags_300)
1209 dropped_packet_indexes = set(
1210 index for (index, _, frags) in self.pkt_infos if len(frags) > 1
1213 self.pg_enable_capture()
1214 self.src_if.add_stream(fragments)
1217 packets = self.dst_if.get_capture(
1218 len(self.pkt_infos) - len(dropped_packet_indexes))
1219 self.verify_capture(packets, dropped_packet_indexes)
1220 self.src_if.assert_nothing_captured()
1222 def test_timeout_inline(self):
1223 """ timeout (inline) """
1225 dropped_packet_indexes = set(
1226 index for (index, frags, _) in self.pkt_infos if len(frags) > 1
1229 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
1230 max_reassembly_length=3,
1231 expire_walk_interval_ms=10000, is_ip6=1)
1233 self.pg_enable_capture()
1234 self.src_if.add_stream(self.fragments_400)
1237 packets = self.dst_if.get_capture(
1238 len(self.pkt_infos) - len(dropped_packet_indexes))
1239 self.verify_capture(packets, dropped_packet_indexes)
1240 pkts = self.src_if.get_capture(
1241 expected_count=len(dropped_packet_indexes))
1243 self.assertIn(ICMPv6TimeExceeded, icmp)
1244 self.assertIn(IPv6ExtHdrFragment, icmp)
1245 self.assertIn(icmp[IPv6ExtHdrFragment].id, dropped_packet_indexes)
1246 dropped_packet_indexes.remove(icmp[IPv6ExtHdrFragment].id)
1248 def test_timeout_cleanup(self):
1249 """ timeout (cleanup) """
1251 # whole packets + fragmented packets sans last fragment
1253 x for (_, frags_400, _) in self.pkt_infos
1254 for x in frags_400[:-1 if len(frags_400) > 1 else None]
1257 # last fragments for fragmented packets
1258 fragments2 = [frags_400[-1]
1259 for (_, frags_400, _) in self.pkt_infos
1260 if len(frags_400) > 1]
1262 dropped_packet_indexes = set(
1263 index for (index, frags_400, _) in self.pkt_infos
1264 if len(frags_400) > 1)
1266 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
1267 max_reassembly_length=1000,
1268 expire_walk_interval_ms=50)
1270 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
1271 max_reassembly_length=1000,
1272 expire_walk_interval_ms=50, is_ip6=1)
1274 self.pg_enable_capture()
1275 self.src_if.add_stream(fragments)
1278 self.sleep(.25, "wait before sending rest of fragments")
1280 self.src_if.add_stream(fragments2)
1283 packets = self.dst_if.get_capture(
1284 len(self.pkt_infos) - len(dropped_packet_indexes))
1285 self.verify_capture(packets, dropped_packet_indexes)
1286 pkts = self.src_if.get_capture(
1287 expected_count=len(dropped_packet_indexes))
1289 self.assertIn(ICMPv6TimeExceeded, icmp)
1290 self.assertIn(IPv6ExtHdrFragment, icmp)
1291 self.assertIn(icmp[IPv6ExtHdrFragment].id, dropped_packet_indexes)
1292 dropped_packet_indexes.remove(icmp[IPv6ExtHdrFragment].id)
1294 def test_disabled(self):
1295 """ reassembly disabled """
1297 dropped_packet_indexes = set(
1298 index for (index, frags_400, _) in self.pkt_infos
1299 if len(frags_400) > 1)
1301 self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=0,
1302 max_reassembly_length=3,
1303 expire_walk_interval_ms=10000, is_ip6=1)
1305 self.pg_enable_capture()
1306 self.src_if.add_stream(self.fragments_400)
1309 packets = self.dst_if.get_capture(
1310 len(self.pkt_infos) - len(dropped_packet_indexes))
1311 self.verify_capture(packets, dropped_packet_indexes)
1312 self.src_if.assert_nothing_captured()
1314 def test_missing_upper(self):
1315 """ missing upper layer """
1316 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1317 IPv6(src=self.src_if.remote_ip6,
1318 dst=self.src_if.local_ip6) /
1319 UDP(sport=1234, dport=5678) /
1321 self.extend_packet(p, 1000, self.padding)
1322 fragments = fragment_rfc8200(p, 1, 500)
1323 bad_fragment = p.__class__(scapy.compat.raw(fragments[1]))
1324 bad_fragment[IPv6ExtHdrFragment].nh = 59
1325 bad_fragment[IPv6ExtHdrFragment].offset = 0
1326 self.pg_enable_capture()
1327 self.src_if.add_stream([bad_fragment])
1329 pkts = self.src_if.get_capture(expected_count=1)
1331 self.assertIn(ICMPv6ParamProblem, icmp)
1332 self.assert_equal(icmp[ICMPv6ParamProblem].code, 3, "ICMP code")
1334 def test_invalid_frag_size(self):
1335 """ fragment size not a multiple of 8 """
1336 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1337 IPv6(src=self.src_if.remote_ip6,
1338 dst=self.src_if.local_ip6) /
1339 UDP(sport=1234, dport=5678) /
1341 self.extend_packet(p, 1000, self.padding)
1342 fragments = fragment_rfc8200(p, 1, 500)
1343 bad_fragment = fragments[0]
1344 self.extend_packet(bad_fragment, len(bad_fragment) + 5)
1345 self.pg_enable_capture()
1346 self.src_if.add_stream([bad_fragment])
1348 pkts = self.src_if.get_capture(expected_count=1)
1350 self.assertIn(ICMPv6ParamProblem, icmp)
1351 self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code")
1353 def test_invalid_packet_size(self):
1354 """ total packet size > 65535 """
1355 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1356 IPv6(src=self.src_if.remote_ip6,
1357 dst=self.src_if.local_ip6) /
1358 UDP(sport=1234, dport=5678) /
1360 self.extend_packet(p, 1000, self.padding)
1361 fragments = fragment_rfc8200(p, 1, 500)
1362 bad_fragment = fragments[1]
1363 bad_fragment[IPv6ExtHdrFragment].offset = 65500
1364 self.pg_enable_capture()
1365 self.src_if.add_stream([bad_fragment])
1367 pkts = self.src_if.get_capture(expected_count=1)
1369 self.assertIn(ICMPv6ParamProblem, icmp)
1370 self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code")
1373 class TestIPv6MWReassembly(VppTestCase):
1374 """ IPv6 Reassembly (multiple workers) """
1375 worker_config = "workers %d" % worker_count
1378 def setUpClass(cls):
1379 super(TestIPv6MWReassembly, cls).setUpClass()
1381 cls.create_pg_interfaces(range(worker_count+1))
1382 cls.src_if = cls.pg0
1383 cls.send_ifs = cls.pg_interfaces[:-1]
1384 cls.dst_if = cls.pg_interfaces[-1]
1386 # setup all interfaces
1387 for i in cls.pg_interfaces:
1392 # packets sizes reduced here because we are generating packets without
1393 # Ethernet headers, which are added later (diff fragments go via
1394 # different interfaces)
1395 cls.packet_sizes = [64-len(Ether()), 512-len(Ether()),
1396 1518-len(Ether()), 9018-len(Ether())]
1397 cls.padding = " abcdefghijklmn"
1398 cls.create_stream(cls.packet_sizes)
1399 cls.create_fragments()
1402 def tearDownClass(cls):
1403 super(TestIPv6MWReassembly, cls).tearDownClass()
1406 """ Test setup - force timeout on existing reassemblies """
1407 super(TestIPv6MWReassembly, self).setUp()
1408 for intf in self.send_ifs:
1409 self.vapi.ip_reassembly_enable_disable(
1410 sw_if_index=intf.sw_if_index, enable_ip6=True)
1411 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
1412 max_reassembly_length=1000,
1413 expire_walk_interval_ms=10, is_ip6=1)
1415 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
1416 max_reassembly_length=1000,
1417 expire_walk_interval_ms=1000, is_ip6=1)
1420 super(TestIPv6MWReassembly, self).tearDown()
1422 def show_commands_at_teardown(self):
1423 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
1424 self.logger.debug(self.vapi.ppcli("show buffers"))
1427 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
1428 """Create input packet stream
1430 :param list packet_sizes: Required packet sizes.
1432 for i in range(0, packet_count):
1433 info = cls.create_packet_info(cls.src_if, cls.src_if)
1434 payload = cls.info_to_payload(info)
1435 p = (IPv6(src=cls.src_if.remote_ip6,
1436 dst=cls.dst_if.remote_ip6) /
1437 UDP(sport=1234, dport=5678) /
1439 size = packet_sizes[(i // 2) % len(packet_sizes)]
1440 cls.extend_packet(p, size, cls.padding)
1444 def create_fragments(cls):
1445 infos = cls._packet_infos
1447 for index, info in six.iteritems(infos):
1449 # cls.logger.debug(ppp("Packet:",
1450 # p.__class__(scapy.compat.raw(p))))
1451 fragments_400 = fragment_rfc8200(p, index, 400)
1452 cls.pkt_infos.append((index, fragments_400))
1453 cls.fragments_400 = [
1454 x for (_, frags) in cls.pkt_infos for x in frags]
1455 cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, " %
1456 (len(infos), len(cls.fragments_400)))
1458 def verify_capture(self, capture, dropped_packet_indexes=[]):
1459 """Verify captured packet strea .
1461 :param list capture: Captured packet stream.
1465 for packet in capture:
1467 self.logger.debug(ppp("Got packet:", packet))
1470 payload_info = self.payload_to_info(packet[Raw])
1471 packet_index = payload_info.index
1473 packet_index not in dropped_packet_indexes,
1474 ppp("Packet received, but should be dropped:", packet))
1475 if packet_index in seen:
1476 raise Exception(ppp("Duplicate packet received", packet))
1477 seen.add(packet_index)
1478 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
1479 info = self._packet_infos[packet_index]
1480 self.assertTrue(info is not None)
1481 self.assertEqual(packet_index, info.index)
1482 saved_packet = info.data
1483 self.assertEqual(ip.src, saved_packet[IPv6].src)
1484 self.assertEqual(ip.dst, saved_packet[IPv6].dst)
1485 self.assertEqual(udp.payload, saved_packet[UDP].payload)
1487 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1489 for index in self._packet_infos:
1490 self.assertTrue(index in seen or index in dropped_packet_indexes,
1491 "Packet with packet_index %d not received" % index)
1493 def send_packets(self, packets):
1494 for counter in range(worker_count):
1495 if 0 == len(packets[counter]):
1497 send_if = self.send_ifs[counter]
1499 (Ether(dst=send_if.local_mac, src=send_if.remote_mac) / x
1500 for x in packets[counter]),
1504 def test_worker_conflict(self):
1505 """ 1st and FO=0 fragments on different workers """
1507 # in first wave we send fragments which don't start at offset 0
1508 # then we send fragments with offset 0 on a different thread
1509 # then the rest of packets on a random thread
1510 first_packets = [[] for n in range(worker_count)]
1511 second_packets = [[] for n in range(worker_count)]
1512 rest_of_packets = [[] for n in range(worker_count)]
1513 for (_, p) in self.pkt_infos:
1514 wi = randrange(worker_count)
1515 second_packets[wi].append(p[0])
1520 wi2 = randrange(worker_count)
1521 first_packets[wi2].append(p[1])
1522 wi3 = randrange(worker_count)
1523 rest_of_packets[wi3].extend(p[2:])
1525 self.pg_enable_capture()
1526 self.send_packets(first_packets)
1527 self.send_packets(second_packets)
1528 self.send_packets(rest_of_packets)
1530 packets = self.dst_if.get_capture(len(self.pkt_infos))
1531 self.verify_capture(packets)
1532 for send_if in self.send_ifs:
1533 send_if.assert_nothing_captured()
1535 self.logger.debug(self.vapi.ppcli("show trace"))
1536 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
1537 self.logger.debug(self.vapi.ppcli("show buffers"))
1538 self.vapi.cli("clear trace")
1540 self.pg_enable_capture()
1541 self.send_packets(first_packets)
1542 self.send_packets(second_packets)
1543 self.send_packets(rest_of_packets)
1545 packets = self.dst_if.get_capture(len(self.pkt_infos))
1546 self.verify_capture(packets)
1547 for send_if in self.send_ifs:
1548 send_if.assert_nothing_captured()
1551 class TestIPv6SVReassembly(VppTestCase):
1552 """ IPv6 Shallow Virtual Reassembly """
1555 def setUpClass(cls):
1556 super(TestIPv6SVReassembly, cls).setUpClass()
1558 cls.create_pg_interfaces([0, 1])
1559 cls.src_if = cls.pg0
1560 cls.dst_if = cls.pg1
1562 # setup all interfaces
1563 for i in cls.pg_interfaces:
1569 """ Test setup - force timeout on existing reassemblies """
1570 super(TestIPv6SVReassembly, self).setUp()
1571 self.vapi.ip_reassembly_enable_disable(
1572 sw_if_index=self.src_if.sw_if_index, enable_ip6=True,
1573 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL)
1574 self.vapi.ip_reassembly_set(
1575 timeout_ms=0, max_reassemblies=1000,
1576 max_reassembly_length=1000,
1577 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
1578 expire_walk_interval_ms=10, is_ip6=1)
1580 self.vapi.ip_reassembly_set(
1581 timeout_ms=1000000, max_reassemblies=1000,
1582 max_reassembly_length=1000,
1583 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
1584 expire_walk_interval_ms=10000, is_ip6=1)
1587 super(TestIPv6SVReassembly, self).tearDown()
1588 self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details"))
1589 self.logger.debug(self.vapi.ppcli("show buffers"))
1591 def test_basic(self):
1592 """ basic reassembly """
1596 while len(payload) < payload_len:
1597 payload += "%u " % counter
1600 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1601 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1602 UDP(sport=1234, dport=5678) /
1604 fragments = fragment_rfc8200(p, 1, payload_len/4)
1606 # send fragment #2 - should be cached inside reassembly
1607 self.pg_enable_capture()
1608 self.src_if.add_stream(fragments[1])
1610 self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details"))
1611 self.logger.debug(self.vapi.ppcli("show buffers"))
1612 self.logger.debug(self.vapi.ppcli("show trace"))
1613 self.dst_if.assert_nothing_captured()
1615 # send fragment #1 - reassembly is finished now and both fragments
1617 self.pg_enable_capture()
1618 self.src_if.add_stream(fragments[0])
1620 self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details"))
1621 self.logger.debug(self.vapi.ppcli("show buffers"))
1622 self.logger.debug(self.vapi.ppcli("show trace"))
1623 c = self.dst_if.get_capture(2)
1624 for sent, recvd in zip([fragments[1], fragments[0]], c):
1625 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
1626 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
1627 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
1629 # send rest of fragments - should be immediately forwarded
1630 self.pg_enable_capture()
1631 self.src_if.add_stream(fragments[2:])
1633 c = self.dst_if.get_capture(len(fragments[2:]))
1634 for sent, recvd in zip(fragments[2:], c):
1635 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
1636 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
1637 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
1639 def test_timeout(self):
1640 """ reassembly timeout """
1644 while len(payload) < payload_len:
1645 payload += "%u " % counter
1648 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1649 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1650 UDP(sport=1234, dport=5678) /
1652 fragments = fragment_rfc8200(p, 1, payload_len/4)
1654 self.vapi.ip_reassembly_set(
1655 timeout_ms=100, max_reassemblies=1000,
1656 max_reassembly_length=1000,
1657 expire_walk_interval_ms=50,
1659 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL)
1661 # send fragments #2 and #1 - should be forwarded
1662 self.pg_enable_capture()
1663 self.src_if.add_stream(fragments[0:2])
1665 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
1666 self.logger.debug(self.vapi.ppcli("show buffers"))
1667 self.logger.debug(self.vapi.ppcli("show trace"))
1668 c = self.dst_if.get_capture(2)
1669 for sent, recvd in zip([fragments[1], fragments[0]], c):
1670 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
1671 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
1672 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
1675 self.sleep(.25, "wait before sending rest of fragments")
1677 # send rest of fragments - shouldn't be forwarded
1678 self.pg_enable_capture()
1679 self.src_if.add_stream(fragments[2:])
1681 self.dst_if.assert_nothing_captured()
1684 """ reassembly reuses LRU element """
1686 self.vapi.ip_reassembly_set(
1687 timeout_ms=1000000, max_reassemblies=1,
1688 max_reassembly_length=1000,
1689 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
1690 is_ip6=1, expire_walk_interval_ms=10000)
1695 while len(payload) < payload_len:
1696 payload += "%u " % counter
1702 for i in range(packet_count)
1703 for p in (Ether(dst=self.src_if.local_mac,
1704 src=self.src_if.remote_mac) /
1705 IPv6(src=self.src_if.remote_ip6,
1706 dst=self.dst_if.remote_ip6) /
1707 UDP(sport=1234, dport=5678) /
1709 for f in fragment_rfc8200(p, i, payload_len/4)]
1711 self.pg_enable_capture()
1712 self.src_if.add_stream(fragments)
1714 c = self.dst_if.get_capture(len(fragments))
1715 for sent, recvd in zip(fragments, c):
1716 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
1717 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
1718 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
1721 class TestIPv4ReassemblyLocalNode(VppTestCase):
1722 """ IPv4 Reassembly for packets coming to ip4-local node """
1725 def setUpClass(cls):
1726 super(TestIPv4ReassemblyLocalNode, cls).setUpClass()
1728 cls.create_pg_interfaces([0])
1729 cls.src_dst_if = cls.pg0
1731 # setup all interfaces
1732 for i in cls.pg_interfaces:
1737 cls.padding = " abcdefghijklmn"
1739 cls.create_fragments()
1742 def tearDownClass(cls):
1743 super(TestIPv4ReassemblyLocalNode, cls).tearDownClass()
1746 """ Test setup - force timeout on existing reassemblies """
1747 super(TestIPv4ReassemblyLocalNode, self).setUp()
1748 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
1749 max_reassembly_length=1000,
1750 expire_walk_interval_ms=10)
1752 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
1753 max_reassembly_length=1000,
1754 expire_walk_interval_ms=10000)
1757 super(TestIPv4ReassemblyLocalNode, self).tearDown()
1759 def show_commands_at_teardown(self):
1760 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
1761 self.logger.debug(self.vapi.ppcli("show buffers"))
1764 def create_stream(cls, packet_count=test_packet_count):
1765 """Create input packet stream for defined interface.
1767 :param list packet_sizes: Required packet sizes.
1769 for i in range(0, packet_count):
1770 info = cls.create_packet_info(cls.src_dst_if, cls.src_dst_if)
1771 payload = cls.info_to_payload(info)
1772 p = (Ether(dst=cls.src_dst_if.local_mac,
1773 src=cls.src_dst_if.remote_mac) /
1774 IP(id=info.index, src=cls.src_dst_if.remote_ip4,
1775 dst=cls.src_dst_if.local_ip4) /
1776 ICMP(type='echo-request', id=1234) /
1778 cls.extend_packet(p, 1518, cls.padding)
1782 def create_fragments(cls):
1783 infos = cls._packet_infos
1785 for index, info in six.iteritems(infos):
1787 # cls.logger.debug(ppp("Packet:",
1788 # p.__class__(scapy.compat.raw(p))))
1789 fragments_300 = fragment_rfc791(p, 300)
1790 cls.pkt_infos.append((index, fragments_300))
1791 cls.fragments_300 = [x for (_, frags) in cls.pkt_infos for x in frags]
1792 cls.logger.debug("Fragmented %s packets into %s 300-byte fragments" %
1793 (len(infos), len(cls.fragments_300)))
1795 def verify_capture(self, capture):
1796 """Verify captured packet stream.
1798 :param list capture: Captured packet stream.
1802 for packet in capture:
1804 self.logger.debug(ppp("Got packet:", packet))
1807 payload_info = self.payload_to_info(packet[Raw])
1808 packet_index = payload_info.index
1809 if packet_index in seen:
1810 raise Exception(ppp("Duplicate packet received", packet))
1811 seen.add(packet_index)
1812 self.assertEqual(payload_info.dst, self.src_dst_if.sw_if_index)
1813 info = self._packet_infos[packet_index]
1814 self.assertIsNotNone(info)
1815 self.assertEqual(packet_index, info.index)
1816 saved_packet = info.data
1817 self.assertEqual(ip.src, saved_packet[IP].dst)
1818 self.assertEqual(ip.dst, saved_packet[IP].src)
1819 self.assertEqual(icmp.type, 0) # echo reply
1820 self.assertEqual(icmp.id, saved_packet[ICMP].id)
1821 self.assertEqual(icmp.payload, saved_packet[ICMP].payload)
1823 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1825 for index in self._packet_infos:
1826 self.assertIn(index, seen,
1827 "Packet with packet_index %d not received" % index)
1829 def test_reassembly(self):
1830 """ basic reassembly """
1832 self.pg_enable_capture()
1833 self.src_dst_if.add_stream(self.fragments_300)
1836 packets = self.src_dst_if.get_capture(len(self.pkt_infos))
1837 self.verify_capture(packets)
1839 # run it all again to verify correctness
1840 self.pg_enable_capture()
1841 self.src_dst_if.add_stream(self.fragments_300)
1844 packets = self.src_dst_if.get_capture(len(self.pkt_infos))
1845 self.verify_capture(packets)
1848 class TestFIFReassembly(VppTestCase):
1849 """ Fragments in fragments reassembly """
1852 def setUpClass(cls):
1853 super(TestFIFReassembly, cls).setUpClass()
1855 cls.create_pg_interfaces([0, 1])
1856 cls.src_if = cls.pg0
1857 cls.dst_if = cls.pg1
1858 for i in cls.pg_interfaces:
1865 cls.packet_sizes = [64, 512, 1518, 9018]
1866 cls.padding = " abcdefghijklmn"
1869 def tearDownClass(cls):
1870 super(TestFIFReassembly, cls).tearDownClass()
1873 """ Test setup - force timeout on existing reassemblies """
1874 super(TestFIFReassembly, self).setUp()
1875 self.vapi.ip_reassembly_enable_disable(
1876 sw_if_index=self.src_if.sw_if_index, enable_ip4=True,
1878 self.vapi.ip_reassembly_enable_disable(
1879 sw_if_index=self.dst_if.sw_if_index, enable_ip4=True,
1881 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
1882 max_reassembly_length=1000,
1883 expire_walk_interval_ms=10)
1884 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
1885 max_reassembly_length=1000,
1886 expire_walk_interval_ms=10, is_ip6=1)
1888 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
1889 max_reassembly_length=1000,
1890 expire_walk_interval_ms=10000)
1891 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
1892 max_reassembly_length=1000,
1893 expire_walk_interval_ms=10000, is_ip6=1)
1896 super(TestFIFReassembly, self).tearDown()
1898 def show_commands_at_teardown(self):
1899 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
1900 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
1901 self.logger.debug(self.vapi.ppcli("show buffers"))
1903 def verify_capture(self, capture, ip_class, dropped_packet_indexes=[]):
1904 """Verify captured packet stream.
1906 :param list capture: Captured packet stream.
1910 for packet in capture:
1912 self.logger.debug(ppp("Got packet:", packet))
1913 ip = packet[ip_class]
1915 payload_info = self.payload_to_info(packet[Raw])
1916 packet_index = payload_info.index
1918 packet_index not in dropped_packet_indexes,
1919 ppp("Packet received, but should be dropped:", packet))
1920 if packet_index in seen:
1921 raise Exception(ppp("Duplicate packet received", packet))
1922 seen.add(packet_index)
1923 self.assertEqual(payload_info.dst, self.dst_if.sw_if_index)
1924 info = self._packet_infos[packet_index]
1925 self.assertTrue(info is not None)
1926 self.assertEqual(packet_index, info.index)
1927 saved_packet = info.data
1928 self.assertEqual(ip.src, saved_packet[ip_class].src)
1929 self.assertEqual(ip.dst, saved_packet[ip_class].dst)
1930 self.assertEqual(udp.payload, saved_packet[UDP].payload)
1932 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1934 for index in self._packet_infos:
1935 self.assertTrue(index in seen or index in dropped_packet_indexes,
1936 "Packet with packet_index %d not received" % index)
1938 def test_fif4(self):
1939 """ Fragments in fragments (4o4) """
1941 # TODO this should be ideally in setUpClass, but then we hit a bug
1942 # with VppIpRoute incorrectly reporting it's present when it's not
1943 # so we need to manually remove the vpp config, thus we cannot have
1944 # it shared for multiple test cases
1945 self.tun_ip4 = "1.1.1.2"
1947 self.gre4 = VppGreInterface(self, self.src_if.local_ip4, self.tun_ip4)
1948 self.gre4.add_vpp_config()
1949 self.gre4.admin_up()
1950 self.gre4.config_ip4()
1952 self.vapi.ip_reassembly_enable_disable(
1953 sw_if_index=self.gre4.sw_if_index, enable_ip4=True)
1955 self.route4 = VppIpRoute(self, self.tun_ip4, 32,
1956 [VppRoutePath(self.src_if.remote_ip4,
1957 self.src_if.sw_if_index)])
1958 self.route4.add_vpp_config()
1960 self.reset_packet_infos()
1961 for i in range(test_packet_count):
1962 info = self.create_packet_info(self.src_if, self.dst_if)
1963 payload = self.info_to_payload(info)
1964 # Ethernet header here is only for size calculation, thus it
1965 # doesn't matter how it's initialized. This is to ensure that
1966 # reassembled packet is not > 9000 bytes, so that it's not dropped
1968 IP(id=i, src=self.src_if.remote_ip4,
1969 dst=self.dst_if.remote_ip4) /
1970 UDP(sport=1234, dport=5678) /
1972 size = self.packet_sizes[(i // 2) % len(self.packet_sizes)]
1973 self.extend_packet(p, size, self.padding)
1974 info.data = p[IP] # use only IP part, without ethernet header
1976 fragments = [x for _, p in six.iteritems(self._packet_infos)
1977 for x in fragment_rfc791(p.data, 400)]
1979 encapped_fragments = \
1980 [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1981 IP(src=self.tun_ip4, dst=self.src_if.local_ip4) /
1986 fragmented_encapped_fragments = \
1987 [x for p in encapped_fragments
1988 for x in fragment_rfc791(p, 200)]
1990 self.src_if.add_stream(fragmented_encapped_fragments)
1992 self.pg_enable_capture(self.pg_interfaces)
1995 self.src_if.assert_nothing_captured()
1996 packets = self.dst_if.get_capture(len(self._packet_infos))
1997 self.verify_capture(packets, IP)
1999 # TODO remove gre vpp config by hand until VppIpRoute gets fixed
2000 # so that it's query_vpp_config() works as it should
2001 self.gre4.remove_vpp_config()
2002 self.logger.debug(self.vapi.ppcli("show interface"))
2004 def test_fif6(self):
2005 """ Fragments in fragments (6o6) """
2006 # TODO this should be ideally in setUpClass, but then we hit a bug
2007 # with VppIpRoute incorrectly reporting it's present when it's not
2008 # so we need to manually remove the vpp config, thus we cannot have
2009 # it shared for multiple test cases
2010 self.tun_ip6 = "1002::1"
2012 self.gre6 = VppGreInterface(self, self.src_if.local_ip6, self.tun_ip6)
2013 self.gre6.add_vpp_config()
2014 self.gre6.admin_up()
2015 self.gre6.config_ip6()
2017 self.vapi.ip_reassembly_enable_disable(
2018 sw_if_index=self.gre6.sw_if_index, enable_ip6=True)
2020 self.route6 = VppIpRoute(self, self.tun_ip6, 128,
2022 self.src_if.remote_ip6,
2023 self.src_if.sw_if_index)])
2024 self.route6.add_vpp_config()
2026 self.reset_packet_infos()
2027 for i in range(test_packet_count):
2028 info = self.create_packet_info(self.src_if, self.dst_if)
2029 payload = self.info_to_payload(info)
2030 # Ethernet header here is only for size calculation, thus it
2031 # doesn't matter how it's initialized. This is to ensure that
2032 # reassembled packet is not > 9000 bytes, so that it's not dropped
2034 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
2035 UDP(sport=1234, dport=5678) /
2037 size = self.packet_sizes[(i // 2) % len(self.packet_sizes)]
2038 self.extend_packet(p, size, self.padding)
2039 info.data = p[IPv6] # use only IPv6 part, without ethernet header
2041 fragments = [x for _, i in six.iteritems(self._packet_infos)
2042 for x in fragment_rfc8200(
2043 i.data, i.index, 400)]
2045 encapped_fragments = \
2046 [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
2047 IPv6(src=self.tun_ip6, dst=self.src_if.local_ip6) /
2052 fragmented_encapped_fragments = \
2053 [x for p in encapped_fragments for x in (
2056 2 * len(self._packet_infos) + p[IPv6ExtHdrFragment].id,
2058 if IPv6ExtHdrFragment in p else [p]
2062 self.src_if.add_stream(fragmented_encapped_fragments)
2064 self.pg_enable_capture(self.pg_interfaces)
2067 self.src_if.assert_nothing_captured()
2068 packets = self.dst_if.get_capture(len(self._packet_infos))
2069 self.verify_capture(packets, IPv6)
2071 # TODO remove gre vpp config by hand until VppIpRoute gets fixed
2072 # so that it's query_vpp_config() works as it should
2073 self.gre6.remove_vpp_config()
2076 if __name__ == '__main__':
2077 unittest.main(testRunner=VppTestRunner)