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
25 class TestIPv4Reassembly(VppTestCase):
26 """ IPv4 Reassembly """
30 super(TestIPv4Reassembly, cls).setUpClass()
32 cls.create_pg_interfaces([0, 1])
36 # setup all interfaces
37 for i in cls.pg_interfaces:
43 cls.packet_sizes = [64, 512, 1518, 9018]
44 cls.padding = " abcdefghijklmn"
45 cls.create_stream(cls.packet_sizes)
46 cls.create_fragments()
49 def tearDownClass(cls):
50 super(TestIPv4Reassembly, cls).tearDownClass()
53 """ Test setup - force timeout on existing reassemblies """
54 super(TestIPv4Reassembly, self).setUp()
55 self.vapi.ip_reassembly_enable_disable(
56 sw_if_index=self.src_if.sw_if_index, enable_ip4=True)
57 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
58 max_reassembly_length=1000,
59 expire_walk_interval_ms=10)
61 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
62 max_reassembly_length=1000,
63 expire_walk_interval_ms=10000)
66 super(TestIPv4Reassembly, self).tearDown()
68 def show_commands_at_teardown(self):
69 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
70 self.logger.debug(self.vapi.ppcli("show buffers"))
73 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
74 """Create input packet stream
76 :param list packet_sizes: Required packet sizes.
78 for i in range(0, packet_count):
79 info = cls.create_packet_info(cls.src_if, cls.src_if)
80 payload = cls.info_to_payload(info)
81 p = (Ether(dst=cls.src_if.local_mac, src=cls.src_if.remote_mac) /
82 IP(id=info.index, src=cls.src_if.remote_ip4,
83 dst=cls.dst_if.remote_ip4) /
84 UDP(sport=1234, dport=5678) /
86 size = packet_sizes[(i // 2) % len(packet_sizes)]
87 cls.extend_packet(p, size, cls.padding)
91 def create_fragments(cls):
92 infos = cls._packet_infos
94 for index, info in infos.items():
96 # cls.logger.debug(ppp("Packet:",
97 # p.__class__(scapy.compat.raw(p))))
98 fragments_400 = fragment_rfc791(p, 400)
99 fragments_300 = fragment_rfc791(p, 300)
101 x for f in fragments_400 for x in fragment_rfc791(f, 200)]
102 cls.pkt_infos.append(
103 (index, fragments_400, fragments_300, fragments_200))
104 cls.fragments_400 = [
105 x for (_, frags, _, _) in cls.pkt_infos for x in frags]
106 cls.fragments_300 = [
107 x for (_, _, frags, _) in cls.pkt_infos for x in frags]
108 cls.fragments_200 = [
109 x for (_, _, _, frags) in cls.pkt_infos for x in frags]
110 cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, "
111 "%s 300-byte fragments and %s 200-byte fragments" %
112 (len(infos), len(cls.fragments_400),
113 len(cls.fragments_300), len(cls.fragments_200)))
115 def verify_capture(self, capture, dropped_packet_indexes=[]):
116 """Verify captured packet stream.
118 :param list capture: Captured packet stream.
122 for packet in capture:
124 self.logger.debug(ppp("Got packet:", packet))
127 payload_info = self.payload_to_info(packet[Raw])
128 packet_index = payload_info.index
130 packet_index not in dropped_packet_indexes,
131 ppp("Packet received, but should be dropped:", packet))
132 if packet_index in seen:
133 raise Exception(ppp("Duplicate packet received", packet))
134 seen.add(packet_index)
135 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
136 info = self._packet_infos[packet_index]
137 self.assertTrue(info is not None)
138 self.assertEqual(packet_index, info.index)
139 saved_packet = info.data
140 self.assertEqual(ip.src, saved_packet[IP].src)
141 self.assertEqual(ip.dst, saved_packet[IP].dst)
142 self.assertEqual(udp.payload, saved_packet[UDP].payload)
144 self.logger.error(ppp("Unexpected or invalid packet:", packet))
146 for index in self._packet_infos:
147 self.assertTrue(index in seen or index in dropped_packet_indexes,
148 "Packet with packet_index %d not received" % index)
150 def test_reassembly(self):
151 """ basic reassembly """
153 self.pg_enable_capture()
154 self.src_if.add_stream(self.fragments_200)
157 packets = self.dst_if.get_capture(len(self.pkt_infos))
158 self.verify_capture(packets)
159 self.src_if.assert_nothing_captured()
161 # run it all again to verify correctness
162 self.pg_enable_capture()
163 self.src_if.add_stream(self.fragments_200)
166 packets = self.dst_if.get_capture(len(self.pkt_infos))
167 self.verify_capture(packets)
168 self.src_if.assert_nothing_captured()
170 def test_verify_clear_trace_mid_reassembly(self):
171 """ verify clear trace works mid-reassembly """
173 self.pg_enable_capture()
174 self.src_if.add_stream(self.fragments_200[0:-1])
177 self.logger.debug(self.vapi.cli("show trace"))
178 self.vapi.cli("clear trace")
180 self.src_if.add_stream(self.fragments_200[-1])
182 packets = self.dst_if.get_capture(len(self.pkt_infos))
183 self.verify_capture(packets)
185 def test_reversed(self):
186 """ reverse order reassembly """
188 fragments = list(self.fragments_200)
191 self.pg_enable_capture()
192 self.src_if.add_stream(fragments)
195 packets = self.dst_if.get_capture(len(self.packet_infos))
196 self.verify_capture(packets)
197 self.src_if.assert_nothing_captured()
199 # run it all again to verify correctness
200 self.pg_enable_capture()
201 self.src_if.add_stream(fragments)
204 packets = self.dst_if.get_capture(len(self.packet_infos))
205 self.verify_capture(packets)
206 self.src_if.assert_nothing_captured()
208 def test_long_fragment_chain(self):
209 """ long fragment chain """
212 "/err/ip4-full-reassembly-feature/fragment chain too long (drop)"
214 error_cnt = self.statistics.get_err_counter(error_cnt_str)
216 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
217 max_reassembly_length=3,
218 expire_walk_interval_ms=50)
220 p1 = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
221 IP(id=1000, src=self.src_if.remote_ip4,
222 dst=self.dst_if.remote_ip4) /
223 UDP(sport=1234, dport=5678) /
225 p2 = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
226 IP(id=1001, src=self.src_if.remote_ip4,
227 dst=self.dst_if.remote_ip4) /
228 UDP(sport=1234, dport=5678) /
230 frags = fragment_rfc791(p1, 200) + fragment_rfc791(p2, 500)
232 self.pg_enable_capture()
233 self.src_if.add_stream(frags)
236 self.dst_if.get_capture(1)
237 self.assert_error_counter_equal(error_cnt_str, error_cnt + 1)
240 """ fragment length + ip header size > 65535 """
241 self.vapi.cli("clear errors")
242 raw = b'''E\x00\x00\x88,\xf8\x1f\xfe@\x01\x98\x00\xc0\xa8\n-\xc0\xa8\n\
243 \x01\x08\x00\xf0J\xed\xcb\xf1\xf5Test-group: IPv4.IPv4.ipv4-message.\
244 Ethernet-Payload.IPv4-Packet.IPv4-Header.Fragment-Offset; Test-case: 5737'''
245 malformed_packet = (Ether(dst=self.src_if.local_mac,
246 src=self.src_if.remote_mac) /
248 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
249 IP(id=1000, src=self.src_if.remote_ip4,
250 dst=self.dst_if.remote_ip4) /
251 UDP(sport=1234, dport=5678) /
253 valid_fragments = fragment_rfc791(p, 400)
255 counter = "/err/ip4-full-reassembly-feature/malformed packets"
256 error_counter = self.statistics.get_err_counter(counter)
257 self.pg_enable_capture()
258 self.src_if.add_stream([malformed_packet] + valid_fragments)
261 self.dst_if.get_capture(1)
262 self.logger.debug(self.vapi.ppcli("show error"))
263 self.assertEqual(self.statistics.get_err_counter(counter),
266 def test_44924(self):
267 """ compress tiny fragments """
268 packets = [(Ether(dst=self.src_if.local_mac,
269 src=self.src_if.remote_mac) /
270 IP(id=24339, flags="MF", frag=0, ttl=64,
271 src=self.src_if.remote_ip4,
272 dst=self.dst_if.remote_ip4) /
273 ICMP(type="echo-request", code=0, id=0x1fe6, seq=0x2407) /
274 Raw(load='Test-group: IPv4')),
275 (Ether(dst=self.src_if.local_mac,
276 src=self.src_if.remote_mac) /
277 IP(id=24339, flags="MF", frag=3, ttl=64,
278 src=self.src_if.remote_ip4,
279 dst=self.dst_if.remote_ip4) /
280 ICMP(type="echo-request", code=0, id=0x1fe6, seq=0x2407) /
281 Raw(load='.IPv4.Fragmentation.vali')),
282 (Ether(dst=self.src_if.local_mac,
283 src=self.src_if.remote_mac) /
284 IP(id=24339, frag=6, ttl=64,
285 src=self.src_if.remote_ip4,
286 dst=self.dst_if.remote_ip4) /
287 ICMP(type="echo-request", code=0, id=0x1fe6, seq=0x2407) /
288 Raw(load='d; Test-case: 44924'))
291 self.pg_enable_capture()
292 self.src_if.add_stream(packets)
295 self.dst_if.get_capture(1)
297 def test_frag_1(self):
298 """ fragment of size 1 """
299 self.vapi.cli("clear errors")
300 malformed_packets = [(Ether(dst=self.src_if.local_mac,
301 src=self.src_if.remote_mac) /
302 IP(id=7, len=21, flags="MF", frag=0, ttl=64,
303 src=self.src_if.remote_ip4,
304 dst=self.dst_if.remote_ip4) /
305 ICMP(type="echo-request")),
306 (Ether(dst=self.src_if.local_mac,
307 src=self.src_if.remote_mac) /
308 IP(id=7, len=21, frag=1, ttl=64,
309 src=self.src_if.remote_ip4,
310 dst=self.dst_if.remote_ip4) /
314 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
315 IP(id=1000, src=self.src_if.remote_ip4,
316 dst=self.dst_if.remote_ip4) /
317 UDP(sport=1234, dport=5678) /
319 valid_fragments = fragment_rfc791(p, 400)
321 self.pg_enable_capture()
322 self.src_if.add_stream(malformed_packets + valid_fragments)
325 self.dst_if.get_capture(1)
327 self.assert_packet_counter_equal("ip4-full-reassembly-feature", 1)
328 # TODO remove above, uncomment below once clearing of counters
330 # self.assert_packet_counter_equal(
331 # "/err/ip4-full-reassembly-feature/malformed packets", 1)
333 def test_random(self):
334 """ random order reassembly """
336 fragments = list(self.fragments_200)
339 self.pg_enable_capture()
340 self.src_if.add_stream(fragments)
343 packets = self.dst_if.get_capture(len(self.packet_infos))
344 self.verify_capture(packets)
345 self.src_if.assert_nothing_captured()
347 # run it all again to verify correctness
348 self.pg_enable_capture()
349 self.src_if.add_stream(fragments)
352 packets = self.dst_if.get_capture(len(self.packet_infos))
353 self.verify_capture(packets)
354 self.src_if.assert_nothing_captured()
356 def test_duplicates(self):
357 """ duplicate fragments """
360 x for (_, frags, _, _) in self.pkt_infos
362 for _ in range(0, min(2, len(frags)))
365 self.pg_enable_capture()
366 self.src_if.add_stream(fragments)
369 packets = self.dst_if.get_capture(len(self.pkt_infos))
370 self.verify_capture(packets)
371 self.src_if.assert_nothing_captured()
373 def test_overlap1(self):
374 """ overlapping fragments case #1 """
377 for _, _, frags_300, frags_200 in self.pkt_infos:
378 if len(frags_300) == 1:
379 fragments.extend(frags_300)
381 for i, j in zip(frags_200, frags_300):
385 self.pg_enable_capture()
386 self.src_if.add_stream(fragments)
389 packets = self.dst_if.get_capture(len(self.pkt_infos))
390 self.verify_capture(packets)
391 self.src_if.assert_nothing_captured()
393 # run it all to verify correctness
394 self.pg_enable_capture()
395 self.src_if.add_stream(fragments)
398 packets = self.dst_if.get_capture(len(self.pkt_infos))
399 self.verify_capture(packets)
400 self.src_if.assert_nothing_captured()
402 def test_overlap2(self):
403 """ overlapping fragments case #2 """
406 for _, _, frags_300, frags_200 in self.pkt_infos:
407 if len(frags_300) == 1:
408 fragments.extend(frags_300)
410 # care must be taken here so that there are no fragments
411 # received by vpp after reassembly is finished, otherwise
412 # new reassemblies will be started and packet generator will
413 # freak out when it detects unfreed buffers
414 zipped = zip(frags_300, frags_200)
420 self.pg_enable_capture()
421 self.src_if.add_stream(fragments)
424 packets = self.dst_if.get_capture(len(self.pkt_infos))
425 self.verify_capture(packets)
426 self.src_if.assert_nothing_captured()
428 # run it all to verify correctness
429 self.pg_enable_capture()
430 self.src_if.add_stream(fragments)
433 packets = self.dst_if.get_capture(len(self.pkt_infos))
434 self.verify_capture(packets)
435 self.src_if.assert_nothing_captured()
437 def test_timeout_inline(self):
438 """ timeout (inline) """
440 dropped_packet_indexes = set(
441 index for (index, frags, _, _) in self.pkt_infos if len(frags) > 1
444 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
445 max_reassembly_length=3,
446 expire_walk_interval_ms=10000)
448 self.pg_enable_capture()
449 self.src_if.add_stream(self.fragments_400)
452 packets = self.dst_if.get_capture(
453 len(self.pkt_infos) - len(dropped_packet_indexes))
454 self.verify_capture(packets, dropped_packet_indexes)
455 self.src_if.assert_nothing_captured()
457 def test_timeout_cleanup(self):
458 """ timeout (cleanup) """
460 # whole packets + fragmented packets sans last fragment
462 x for (_, frags_400, _, _) in self.pkt_infos
463 for x in frags_400[:-1 if len(frags_400) > 1 else None]
466 # last fragments for fragmented packets
467 fragments2 = [frags_400[-1]
468 for (_, frags_400, _, _) in self.pkt_infos
469 if len(frags_400) > 1]
471 dropped_packet_indexes = set(
472 index for (index, frags_400, _, _) in self.pkt_infos
473 if len(frags_400) > 1)
475 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
476 max_reassembly_length=1000,
477 expire_walk_interval_ms=50)
479 self.pg_enable_capture()
480 self.src_if.add_stream(fragments)
483 self.sleep(.25, "wait before sending rest of fragments")
485 self.src_if.add_stream(fragments2)
488 packets = self.dst_if.get_capture(
489 len(self.pkt_infos) - len(dropped_packet_indexes))
490 self.verify_capture(packets, dropped_packet_indexes)
491 self.src_if.assert_nothing_captured()
493 def test_disabled(self):
494 """ reassembly disabled """
496 dropped_packet_indexes = set(
497 index for (index, frags_400, _, _) in self.pkt_infos
498 if len(frags_400) > 1)
500 self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=0,
501 max_reassembly_length=3,
502 expire_walk_interval_ms=10000)
504 self.pg_enable_capture()
505 self.src_if.add_stream(self.fragments_400)
508 packets = self.dst_if.get_capture(
509 len(self.pkt_infos) - len(dropped_packet_indexes))
510 self.verify_capture(packets, dropped_packet_indexes)
511 self.src_if.assert_nothing_captured()
514 class TestIPv4SVReassembly(VppTestCase):
515 """ IPv4 Shallow Virtual Reassembly """
519 super(TestIPv4SVReassembly, cls).setUpClass()
521 cls.create_pg_interfaces([0, 1])
525 # setup all interfaces
526 for i in cls.pg_interfaces:
532 """ Test setup - force timeout on existing reassemblies """
533 super(TestIPv4SVReassembly, self).setUp()
534 self.vapi.ip_reassembly_enable_disable(
535 sw_if_index=self.src_if.sw_if_index, enable_ip4=True,
536 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL)
537 self.vapi.ip_reassembly_set(
538 timeout_ms=0, max_reassemblies=1000,
539 max_reassembly_length=1000,
540 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
541 expire_walk_interval_ms=10)
543 self.vapi.ip_reassembly_set(
544 timeout_ms=1000000, max_reassemblies=1000,
545 max_reassembly_length=1000,
546 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
547 expire_walk_interval_ms=10000)
550 super(TestIPv4SVReassembly, self).tearDown()
551 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
552 self.logger.debug(self.vapi.ppcli("show buffers"))
554 def test_basic(self):
555 """ basic reassembly """
559 while len(payload) < payload_len:
560 payload += "%u " % counter
563 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
564 IP(id=1, src=self.src_if.remote_ip4,
565 dst=self.dst_if.remote_ip4) /
566 UDP(sport=1234, dport=5678) /
568 fragments = fragment_rfc791(p, payload_len/4)
570 # send fragment #2 - should be cached inside reassembly
571 self.pg_enable_capture()
572 self.src_if.add_stream(fragments[1])
574 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
575 self.logger.debug(self.vapi.ppcli("show buffers"))
576 self.logger.debug(self.vapi.ppcli("show trace"))
577 self.dst_if.assert_nothing_captured()
579 # send fragment #1 - reassembly is finished now and both fragments
581 self.pg_enable_capture()
582 self.src_if.add_stream(fragments[0])
584 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
585 self.logger.debug(self.vapi.ppcli("show buffers"))
586 self.logger.debug(self.vapi.ppcli("show trace"))
587 c = self.dst_if.get_capture(2)
588 for sent, recvd in zip([fragments[1], fragments[0]], c):
589 self.assertEqual(sent[IP].src, recvd[IP].src)
590 self.assertEqual(sent[IP].dst, recvd[IP].dst)
591 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
593 # send rest of fragments - should be immediately forwarded
594 self.pg_enable_capture()
595 self.src_if.add_stream(fragments[2:])
597 c = self.dst_if.get_capture(len(fragments[2:]))
598 for sent, recvd in zip(fragments[2:], c):
599 self.assertEqual(sent[IP].src, recvd[IP].src)
600 self.assertEqual(sent[IP].dst, recvd[IP].dst)
601 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
603 def test_verify_clear_trace_mid_reassembly(self):
604 """ verify clear trace works mid-reassembly """
608 while len(payload) < payload_len:
609 payload += "%u " % counter
612 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
613 IP(id=1, src=self.src_if.remote_ip4,
614 dst=self.dst_if.remote_ip4) /
615 UDP(sport=1234, dport=5678) /
617 fragments = fragment_rfc791(p, payload_len/4)
619 self.pg_enable_capture()
620 self.src_if.add_stream(fragments[1])
623 self.logger.debug(self.vapi.cli("show trace"))
624 self.vapi.cli("clear trace")
626 self.pg_enable_capture()
627 self.src_if.add_stream(fragments[0])
629 self.dst_if.get_capture(2)
631 self.logger.debug(self.vapi.cli("show trace"))
632 self.vapi.cli("clear trace")
634 self.pg_enable_capture()
635 self.src_if.add_stream(fragments[2:])
637 self.dst_if.get_capture(len(fragments[2:]))
639 def test_timeout(self):
640 """ reassembly timeout """
644 while len(payload) < payload_len:
645 payload += "%u " % counter
648 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
649 IP(id=1, src=self.src_if.remote_ip4,
650 dst=self.dst_if.remote_ip4) /
651 UDP(sport=1234, dport=5678) /
653 fragments = fragment_rfc791(p, payload_len/4)
655 self.vapi.ip_reassembly_set(
656 timeout_ms=100, max_reassemblies=1000,
657 max_reassembly_length=1000,
658 expire_walk_interval_ms=50,
659 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL)
661 # send fragments #2 and #1 - should be forwarded
662 self.pg_enable_capture()
663 self.src_if.add_stream(fragments[0:2])
665 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
666 self.logger.debug(self.vapi.ppcli("show buffers"))
667 self.logger.debug(self.vapi.ppcli("show trace"))
668 c = self.dst_if.get_capture(2)
669 for sent, recvd in zip([fragments[1], fragments[0]], c):
670 self.assertEqual(sent[IP].src, recvd[IP].src)
671 self.assertEqual(sent[IP].dst, recvd[IP].dst)
672 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
675 self.sleep(.25, "wait before sending rest of fragments")
677 # send rest of fragments - shouldn't be forwarded
678 self.pg_enable_capture()
679 self.src_if.add_stream(fragments[2:])
681 self.dst_if.assert_nothing_captured()
684 """ reassembly reuses LRU element """
686 self.vapi.ip_reassembly_set(
687 timeout_ms=1000000, max_reassemblies=1,
688 max_reassembly_length=1000,
689 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
690 expire_walk_interval_ms=10000)
695 while len(payload) < payload_len:
696 payload += "%u " % counter
702 for i in range(packet_count)
703 for p in (Ether(dst=self.src_if.local_mac,
704 src=self.src_if.remote_mac) /
705 IP(id=i, src=self.src_if.remote_ip4,
706 dst=self.dst_if.remote_ip4) /
707 UDP(sport=1234, dport=5678) /
709 for f in fragment_rfc791(p, payload_len/4)]
711 self.pg_enable_capture()
712 self.src_if.add_stream(fragments)
714 c = self.dst_if.get_capture(len(fragments))
715 for sent, recvd in zip(fragments, c):
716 self.assertEqual(sent[IP].src, recvd[IP].src)
717 self.assertEqual(sent[IP].dst, recvd[IP].dst)
718 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
720 def send_mixed_and_verify_capture(self, traffic):
723 for c in range(t['count']):
725 (Ether(dst=self.src_if.local_mac,
726 src=self.src_if.remote_mac) /
729 src=self.src_if.remote_ip4,
730 dst=self.dst_if.remote_ip4) /
731 UDP(sport=1234, dport=5678) /
733 self.counter = self.counter + 1
735 self.pg_enable_capture()
736 self.src_if.add_stream(stream)
738 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
739 self.logger.debug(self.vapi.ppcli("show buffers"))
740 self.logger.debug(self.vapi.ppcli("show trace"))
741 self.dst_if.get_capture(len(stream))
743 def test_mixed(self):
744 """ mixed traffic correctly passes through SVR """
747 self.send_mixed_and_verify_capture([{'count': 1, 'flags': ''}])
748 self.send_mixed_and_verify_capture([{'count': 2, 'flags': ''}])
749 self.send_mixed_and_verify_capture([{'count': 3, 'flags': ''}])
750 self.send_mixed_and_verify_capture([{'count': 8, 'flags': ''}])
751 self.send_mixed_and_verify_capture([{'count': 257, 'flags': ''}])
753 self.send_mixed_and_verify_capture([{'count': 1, 'flags': 'MF'}])
754 self.send_mixed_and_verify_capture([{'count': 2, 'flags': 'MF'}])
755 self.send_mixed_and_verify_capture([{'count': 3, 'flags': 'MF'}])
756 self.send_mixed_and_verify_capture([{'count': 8, 'flags': 'MF'}])
757 self.send_mixed_and_verify_capture([{'count': 257, 'flags': 'MF'}])
759 self.send_mixed_and_verify_capture(
760 [{'count': 1, 'flags': ''}, {'count': 1, 'flags': 'MF'}])
761 self.send_mixed_and_verify_capture(
762 [{'count': 2, 'flags': ''}, {'count': 2, 'flags': 'MF'}])
763 self.send_mixed_and_verify_capture(
764 [{'count': 3, 'flags': ''}, {'count': 3, 'flags': 'MF'}])
765 self.send_mixed_and_verify_capture(
766 [{'count': 8, 'flags': ''}, {'count': 8, 'flags': 'MF'}])
767 self.send_mixed_and_verify_capture(
768 [{'count': 129, 'flags': ''}, {'count': 129, 'flags': 'MF'}])
770 self.send_mixed_and_verify_capture(
771 [{'count': 1, 'flags': ''}, {'count': 1, 'flags': 'MF'},
772 {'count': 1, 'flags': ''}, {'count': 1, 'flags': 'MF'}])
773 self.send_mixed_and_verify_capture(
774 [{'count': 2, 'flags': ''}, {'count': 2, 'flags': 'MF'},
775 {'count': 2, 'flags': ''}, {'count': 2, 'flags': 'MF'}])
776 self.send_mixed_and_verify_capture(
777 [{'count': 3, 'flags': ''}, {'count': 3, 'flags': 'MF'},
778 {'count': 3, 'flags': ''}, {'count': 3, 'flags': 'MF'}])
779 self.send_mixed_and_verify_capture(
780 [{'count': 8, 'flags': ''}, {'count': 8, 'flags': 'MF'},
781 {'count': 8, 'flags': ''}, {'count': 8, 'flags': 'MF'}])
782 self.send_mixed_and_verify_capture(
783 [{'count': 65, 'flags': ''}, {'count': 65, 'flags': 'MF'},
784 {'count': 65, 'flags': ''}, {'count': 65, 'flags': 'MF'}])
787 class TestIPv4MWReassembly(VppTestCase):
788 """ IPv4 Reassembly (multiple workers) """
793 super(TestIPv4MWReassembly, cls).setUpClass()
795 cls.create_pg_interfaces(range(cls.vpp_worker_count+1))
797 cls.send_ifs = cls.pg_interfaces[:-1]
798 cls.dst_if = cls.pg_interfaces[-1]
800 # setup all interfaces
801 for i in cls.pg_interfaces:
806 # packets sizes reduced here because we are generating packets without
807 # Ethernet headers, which are added later (diff fragments go via
808 # different interfaces)
809 cls.packet_sizes = [64-len(Ether()), 512-len(Ether()),
810 1518-len(Ether()), 9018-len(Ether())]
811 cls.padding = " abcdefghijklmn"
812 cls.create_stream(cls.packet_sizes)
813 cls.create_fragments()
816 def tearDownClass(cls):
817 super(TestIPv4MWReassembly, cls).tearDownClass()
820 """ Test setup - force timeout on existing reassemblies """
821 super(TestIPv4MWReassembly, self).setUp()
822 for intf in self.send_ifs:
823 self.vapi.ip_reassembly_enable_disable(
824 sw_if_index=intf.sw_if_index, enable_ip4=True)
825 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
826 max_reassembly_length=1000,
827 expire_walk_interval_ms=10)
829 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
830 max_reassembly_length=1000,
831 expire_walk_interval_ms=10000)
834 super(TestIPv4MWReassembly, self).tearDown()
836 def show_commands_at_teardown(self):
837 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
838 self.logger.debug(self.vapi.ppcli("show buffers"))
841 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
842 """Create input packet stream
844 :param list packet_sizes: Required packet sizes.
846 for i in range(0, packet_count):
847 info = cls.create_packet_info(cls.src_if, cls.src_if)
848 payload = cls.info_to_payload(info)
849 p = (IP(id=info.index, src=cls.src_if.remote_ip4,
850 dst=cls.dst_if.remote_ip4) /
851 UDP(sport=1234, dport=5678) /
853 size = packet_sizes[(i // 2) % len(packet_sizes)]
854 cls.extend_packet(p, size, cls.padding)
858 def create_fragments(cls):
859 infos = cls._packet_infos
861 for index, info in infos.items():
863 # cls.logger.debug(ppp("Packet:",
864 # p.__class__(scapy.compat.raw(p))))
865 fragments_400 = fragment_rfc791(p, 400)
866 cls.pkt_infos.append((index, fragments_400))
867 cls.fragments_400 = [
868 x for (_, frags) in cls.pkt_infos for x in frags]
869 cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, " %
870 (len(infos), len(cls.fragments_400)))
872 def verify_capture(self, capture, dropped_packet_indexes=[]):
873 """Verify captured packet stream.
875 :param list capture: Captured packet stream.
879 for packet in capture:
881 self.logger.debug(ppp("Got packet:", packet))
884 payload_info = self.payload_to_info(packet[Raw])
885 packet_index = payload_info.index
887 packet_index not in dropped_packet_indexes,
888 ppp("Packet received, but should be dropped:", packet))
889 if packet_index in seen:
890 raise Exception(ppp("Duplicate packet received", packet))
891 seen.add(packet_index)
892 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
893 info = self._packet_infos[packet_index]
894 self.assertTrue(info is not None)
895 self.assertEqual(packet_index, info.index)
896 saved_packet = info.data
897 self.assertEqual(ip.src, saved_packet[IP].src)
898 self.assertEqual(ip.dst, saved_packet[IP].dst)
899 self.assertEqual(udp.payload, saved_packet[UDP].payload)
901 self.logger.error(ppp("Unexpected or invalid packet:", packet))
903 for index in self._packet_infos:
904 self.assertTrue(index in seen or index in dropped_packet_indexes,
905 "Packet with packet_index %d not received" % index)
907 def send_packets(self, packets):
908 for counter in range(self.vpp_worker_count):
909 if 0 == len(packets[counter]):
911 send_if = self.send_ifs[counter]
913 (Ether(dst=send_if.local_mac, src=send_if.remote_mac) / x
914 for x in packets[counter]),
918 def test_worker_conflict(self):
919 """ 1st and FO=0 fragments on different workers """
921 # in first wave we send fragments which don't start at offset 0
922 # then we send fragments with offset 0 on a different thread
923 # then the rest of packets on a random thread
924 first_packets = [[] for n in range(self.vpp_worker_count)]
925 second_packets = [[] for n in range(self.vpp_worker_count)]
926 rest_of_packets = [[] for n in range(self.vpp_worker_count)]
927 for (_, p) in self.pkt_infos:
928 wi = randrange(self.vpp_worker_count)
929 second_packets[wi].append(p[0])
934 wi2 = randrange(self.vpp_worker_count)
935 first_packets[wi2].append(p[1])
936 wi3 = randrange(self.vpp_worker_count)
937 rest_of_packets[wi3].extend(p[2:])
939 self.pg_enable_capture()
940 self.send_packets(first_packets)
941 self.send_packets(second_packets)
942 self.send_packets(rest_of_packets)
944 packets = self.dst_if.get_capture(len(self.pkt_infos))
945 self.verify_capture(packets)
946 for send_if in self.send_ifs:
947 send_if.assert_nothing_captured()
949 self.logger.debug(self.vapi.ppcli("show trace"))
950 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
951 self.logger.debug(self.vapi.ppcli("show buffers"))
952 self.vapi.cli("clear trace")
954 self.pg_enable_capture()
955 self.send_packets(first_packets)
956 self.send_packets(second_packets)
957 self.send_packets(rest_of_packets)
959 packets = self.dst_if.get_capture(len(self.pkt_infos))
960 self.verify_capture(packets)
961 for send_if in self.send_ifs:
962 send_if.assert_nothing_captured()
965 class TestIPv6Reassembly(VppTestCase):
966 """ IPv6 Reassembly """
970 super(TestIPv6Reassembly, cls).setUpClass()
972 cls.create_pg_interfaces([0, 1])
976 # setup all interfaces
977 for i in cls.pg_interfaces:
983 cls.packet_sizes = [64, 512, 1518, 9018]
984 cls.padding = " abcdefghijklmn"
985 cls.create_stream(cls.packet_sizes)
986 cls.create_fragments()
989 def tearDownClass(cls):
990 super(TestIPv6Reassembly, cls).tearDownClass()
993 """ Test setup - force timeout on existing reassemblies """
994 super(TestIPv6Reassembly, self).setUp()
995 self.vapi.ip_reassembly_enable_disable(
996 sw_if_index=self.src_if.sw_if_index, enable_ip6=True)
997 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
998 max_reassembly_length=1000,
999 expire_walk_interval_ms=10, is_ip6=1)
1001 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
1002 max_reassembly_length=1000,
1003 expire_walk_interval_ms=10000, is_ip6=1)
1004 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
1005 self.logger.debug(self.vapi.ppcli("show buffers"))
1008 super(TestIPv6Reassembly, self).tearDown()
1010 def show_commands_at_teardown(self):
1011 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
1012 self.logger.debug(self.vapi.ppcli("show buffers"))
1015 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
1016 """Create input packet stream for defined interface.
1018 :param list packet_sizes: Required packet sizes.
1020 for i in range(0, packet_count):
1021 info = cls.create_packet_info(cls.src_if, cls.src_if)
1022 payload = cls.info_to_payload(info)
1023 p = (Ether(dst=cls.src_if.local_mac, src=cls.src_if.remote_mac) /
1024 IPv6(src=cls.src_if.remote_ip6,
1025 dst=cls.dst_if.remote_ip6) /
1026 UDP(sport=1234, dport=5678) /
1028 size = packet_sizes[(i // 2) % len(packet_sizes)]
1029 cls.extend_packet(p, size, cls.padding)
1033 def create_fragments(cls):
1034 infos = cls._packet_infos
1036 for index, info in infos.items():
1038 # cls.logger.debug(ppp("Packet:",
1039 # p.__class__(scapy.compat.raw(p))))
1040 fragments_400 = fragment_rfc8200(p, info.index, 400)
1041 fragments_300 = fragment_rfc8200(p, info.index, 300)
1042 cls.pkt_infos.append((index, fragments_400, fragments_300))
1043 cls.fragments_400 = [
1044 x for _, frags, _ in cls.pkt_infos for x in frags]
1045 cls.fragments_300 = [
1046 x for _, _, frags in cls.pkt_infos for x in frags]
1047 cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, "
1048 "and %s 300-byte fragments" %
1049 (len(infos), len(cls.fragments_400),
1050 len(cls.fragments_300)))
1052 def verify_capture(self, capture, dropped_packet_indexes=[]):
1053 """Verify captured packet strea .
1055 :param list capture: Captured packet stream.
1059 for packet in capture:
1061 self.logger.debug(ppp("Got packet:", packet))
1064 payload_info = self.payload_to_info(packet[Raw])
1065 packet_index = payload_info.index
1067 packet_index not in dropped_packet_indexes,
1068 ppp("Packet received, but should be dropped:", packet))
1069 if packet_index in seen:
1070 raise Exception(ppp("Duplicate packet received", packet))
1071 seen.add(packet_index)
1072 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
1073 info = self._packet_infos[packet_index]
1074 self.assertTrue(info is not None)
1075 self.assertEqual(packet_index, info.index)
1076 saved_packet = info.data
1077 self.assertEqual(ip.src, saved_packet[IPv6].src)
1078 self.assertEqual(ip.dst, saved_packet[IPv6].dst)
1079 self.assertEqual(udp.payload, saved_packet[UDP].payload)
1081 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1083 for index in self._packet_infos:
1084 self.assertTrue(index in seen or index in dropped_packet_indexes,
1085 "Packet with packet_index %d not received" % index)
1087 def test_reassembly(self):
1088 """ basic reassembly """
1090 self.pg_enable_capture()
1091 self.src_if.add_stream(self.fragments_400)
1094 packets = self.dst_if.get_capture(len(self.pkt_infos))
1095 self.verify_capture(packets)
1096 self.src_if.assert_nothing_captured()
1098 # run it all again to verify correctness
1099 self.pg_enable_capture()
1100 self.src_if.add_stream(self.fragments_400)
1103 packets = self.dst_if.get_capture(len(self.pkt_infos))
1104 self.verify_capture(packets)
1105 self.src_if.assert_nothing_captured()
1107 def test_buffer_boundary(self):
1108 """ fragment header crossing buffer boundary """
1110 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1111 IPv6(src=self.src_if.remote_ip6,
1112 dst=self.src_if.local_ip6) /
1114 options=[HBHOptUnknown(otype=0xff, optlen=0)] * 1000) /
1115 IPv6ExtHdrFragment(m=1) /
1116 UDP(sport=1234, dport=5678) /
1118 self.pg_enable_capture()
1119 self.src_if.add_stream([p])
1121 self.src_if.assert_nothing_captured()
1122 self.dst_if.assert_nothing_captured()
1124 def test_verify_clear_trace_mid_reassembly(self):
1125 """ verify clear trace works mid-reassembly """
1127 self.pg_enable_capture()
1128 self.src_if.add_stream(self.fragments_400[0:-1])
1131 self.logger.debug(self.vapi.cli("show trace"))
1132 self.vapi.cli("clear trace")
1134 self.src_if.add_stream(self.fragments_400[-1])
1136 packets = self.dst_if.get_capture(len(self.pkt_infos))
1137 self.verify_capture(packets)
1139 def test_reversed(self):
1140 """ reverse order reassembly """
1142 fragments = list(self.fragments_400)
1145 self.pg_enable_capture()
1146 self.src_if.add_stream(fragments)
1149 packets = self.dst_if.get_capture(len(self.pkt_infos))
1150 self.verify_capture(packets)
1151 self.src_if.assert_nothing_captured()
1153 # run it all again to verify correctness
1154 self.pg_enable_capture()
1155 self.src_if.add_stream(fragments)
1158 packets = self.dst_if.get_capture(len(self.pkt_infos))
1159 self.verify_capture(packets)
1160 self.src_if.assert_nothing_captured()
1162 def test_random(self):
1163 """ random order reassembly """
1165 fragments = list(self.fragments_400)
1168 self.pg_enable_capture()
1169 self.src_if.add_stream(fragments)
1172 packets = self.dst_if.get_capture(len(self.pkt_infos))
1173 self.verify_capture(packets)
1174 self.src_if.assert_nothing_captured()
1176 # run it all again to verify correctness
1177 self.pg_enable_capture()
1178 self.src_if.add_stream(fragments)
1181 packets = self.dst_if.get_capture(len(self.pkt_infos))
1182 self.verify_capture(packets)
1183 self.src_if.assert_nothing_captured()
1185 def test_duplicates(self):
1186 """ duplicate fragments """
1189 x for (_, frags, _) in self.pkt_infos
1191 for _ in range(0, min(2, len(frags)))
1194 self.pg_enable_capture()
1195 self.src_if.add_stream(fragments)
1198 packets = self.dst_if.get_capture(len(self.pkt_infos))
1199 self.verify_capture(packets)
1200 self.src_if.assert_nothing_captured()
1202 def test_long_fragment_chain(self):
1203 """ long fragment chain """
1206 "/err/ip6-full-reassembly-feature/fragment chain too long (drop)"
1208 error_cnt = self.statistics.get_err_counter(error_cnt_str)
1210 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
1211 max_reassembly_length=3,
1212 expire_walk_interval_ms=50, is_ip6=1)
1214 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1215 IPv6(src=self.src_if.remote_ip6,
1216 dst=self.dst_if.remote_ip6) /
1217 UDP(sport=1234, dport=5678) /
1219 frags = fragment_rfc8200(p, 1, 300) + fragment_rfc8200(p, 2, 500)
1221 self.pg_enable_capture()
1222 self.src_if.add_stream(frags)
1225 self.dst_if.get_capture(1)
1226 self.assert_error_counter_equal(error_cnt_str, error_cnt + 1)
1228 def test_overlap1(self):
1229 """ overlapping fragments case #1 """
1232 for _, frags_400, frags_300 in self.pkt_infos:
1233 if len(frags_300) == 1:
1234 fragments.extend(frags_400)
1236 for i, j in zip(frags_300, frags_400):
1240 dropped_packet_indexes = set(
1241 index for (index, _, frags) in self.pkt_infos if len(frags) > 1
1244 self.pg_enable_capture()
1245 self.src_if.add_stream(fragments)
1248 packets = self.dst_if.get_capture(
1249 len(self.pkt_infos) - len(dropped_packet_indexes))
1250 self.verify_capture(packets, dropped_packet_indexes)
1251 self.src_if.assert_nothing_captured()
1253 def test_overlap2(self):
1254 """ overlapping fragments case #2 """
1257 for _, frags_400, frags_300 in self.pkt_infos:
1258 if len(frags_400) == 1:
1259 fragments.extend(frags_400)
1261 # care must be taken here so that there are no fragments
1262 # received by vpp after reassembly is finished, otherwise
1263 # new reassemblies will be started and packet generator will
1264 # freak out when it detects unfreed buffers
1265 zipped = zip(frags_400, frags_300)
1271 dropped_packet_indexes = set(
1272 index for (index, _, frags) in self.pkt_infos if len(frags) > 1
1275 self.pg_enable_capture()
1276 self.src_if.add_stream(fragments)
1279 packets = self.dst_if.get_capture(
1280 len(self.pkt_infos) - len(dropped_packet_indexes))
1281 self.verify_capture(packets, dropped_packet_indexes)
1282 self.src_if.assert_nothing_captured()
1284 def test_timeout_inline(self):
1285 """ timeout (inline) """
1287 dropped_packet_indexes = set(
1288 index for (index, frags, _) in self.pkt_infos if len(frags) > 1
1291 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
1292 max_reassembly_length=3,
1293 expire_walk_interval_ms=10000, is_ip6=1)
1295 self.pg_enable_capture()
1296 self.src_if.add_stream(self.fragments_400)
1299 packets = self.dst_if.get_capture(
1300 len(self.pkt_infos) - len(dropped_packet_indexes))
1301 self.verify_capture(packets, dropped_packet_indexes)
1302 pkts = self.src_if.get_capture(
1303 expected_count=len(dropped_packet_indexes))
1305 self.assertIn(ICMPv6TimeExceeded, icmp)
1306 self.assertIn(IPv6ExtHdrFragment, icmp)
1307 self.assertIn(icmp[IPv6ExtHdrFragment].id, dropped_packet_indexes)
1308 dropped_packet_indexes.remove(icmp[IPv6ExtHdrFragment].id)
1310 def test_timeout_cleanup(self):
1311 """ timeout (cleanup) """
1313 # whole packets + fragmented packets sans last fragment
1315 x for (_, frags_400, _) in self.pkt_infos
1316 for x in frags_400[:-1 if len(frags_400) > 1 else None]
1319 # last fragments for fragmented packets
1320 fragments2 = [frags_400[-1]
1321 for (_, frags_400, _) in self.pkt_infos
1322 if len(frags_400) > 1]
1324 dropped_packet_indexes = set(
1325 index for (index, frags_400, _) in self.pkt_infos
1326 if len(frags_400) > 1)
1328 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
1329 max_reassembly_length=1000,
1330 expire_walk_interval_ms=50)
1332 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
1333 max_reassembly_length=1000,
1334 expire_walk_interval_ms=50, is_ip6=1)
1336 self.pg_enable_capture()
1337 self.src_if.add_stream(fragments)
1340 self.sleep(.25, "wait before sending rest of fragments")
1342 self.src_if.add_stream(fragments2)
1345 packets = self.dst_if.get_capture(
1346 len(self.pkt_infos) - len(dropped_packet_indexes))
1347 self.verify_capture(packets, dropped_packet_indexes)
1348 pkts = self.src_if.get_capture(
1349 expected_count=len(dropped_packet_indexes))
1351 self.assertIn(ICMPv6TimeExceeded, icmp)
1352 self.assertIn(IPv6ExtHdrFragment, icmp)
1353 self.assertIn(icmp[IPv6ExtHdrFragment].id, dropped_packet_indexes)
1354 dropped_packet_indexes.remove(icmp[IPv6ExtHdrFragment].id)
1356 def test_disabled(self):
1357 """ reassembly disabled """
1359 dropped_packet_indexes = set(
1360 index for (index, frags_400, _) in self.pkt_infos
1361 if len(frags_400) > 1)
1363 self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=0,
1364 max_reassembly_length=3,
1365 expire_walk_interval_ms=10000, is_ip6=1)
1367 self.pg_enable_capture()
1368 self.src_if.add_stream(self.fragments_400)
1371 packets = self.dst_if.get_capture(
1372 len(self.pkt_infos) - len(dropped_packet_indexes))
1373 self.verify_capture(packets, dropped_packet_indexes)
1374 self.src_if.assert_nothing_captured()
1376 def test_missing_upper(self):
1377 """ missing upper layer """
1378 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1379 IPv6(src=self.src_if.remote_ip6,
1380 dst=self.src_if.local_ip6) /
1381 UDP(sport=1234, dport=5678) /
1383 self.extend_packet(p, 1000, self.padding)
1384 fragments = fragment_rfc8200(p, 1, 500)
1385 bad_fragment = p.__class__(scapy.compat.raw(fragments[1]))
1386 bad_fragment[IPv6ExtHdrFragment].nh = 59
1387 bad_fragment[IPv6ExtHdrFragment].offset = 0
1388 self.pg_enable_capture()
1389 self.src_if.add_stream([bad_fragment])
1391 pkts = self.src_if.get_capture(expected_count=1)
1393 self.assertIn(ICMPv6ParamProblem, icmp)
1394 self.assert_equal(icmp[ICMPv6ParamProblem].code, 3, "ICMP code")
1396 def test_invalid_frag_size(self):
1397 """ fragment size not a multiple of 8 """
1398 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1399 IPv6(src=self.src_if.remote_ip6,
1400 dst=self.src_if.local_ip6) /
1401 UDP(sport=1234, dport=5678) /
1403 self.extend_packet(p, 1000, self.padding)
1404 fragments = fragment_rfc8200(p, 1, 500)
1405 bad_fragment = fragments[0]
1406 self.extend_packet(bad_fragment, len(bad_fragment) + 5)
1407 self.pg_enable_capture()
1408 self.src_if.add_stream([bad_fragment])
1410 pkts = self.src_if.get_capture(expected_count=1)
1412 self.assertIn(ICMPv6ParamProblem, icmp)
1413 self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code")
1415 def test_invalid_packet_size(self):
1416 """ total packet size > 65535 """
1417 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1418 IPv6(src=self.src_if.remote_ip6,
1419 dst=self.src_if.local_ip6) /
1420 UDP(sport=1234, dport=5678) /
1422 self.extend_packet(p, 1000, self.padding)
1423 fragments = fragment_rfc8200(p, 1, 500)
1424 bad_fragment = fragments[1]
1425 bad_fragment[IPv6ExtHdrFragment].offset = 65500
1426 self.pg_enable_capture()
1427 self.src_if.add_stream([bad_fragment])
1429 pkts = self.src_if.get_capture(expected_count=1)
1431 self.assertIn(ICMPv6ParamProblem, icmp)
1432 self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code")
1435 class TestIPv6MWReassembly(VppTestCase):
1436 """ IPv6 Reassembly (multiple workers) """
1437 vpp_worker_count = 3
1440 def setUpClass(cls):
1441 super(TestIPv6MWReassembly, cls).setUpClass()
1443 cls.create_pg_interfaces(range(cls.vpp_worker_count+1))
1444 cls.src_if = cls.pg0
1445 cls.send_ifs = cls.pg_interfaces[:-1]
1446 cls.dst_if = cls.pg_interfaces[-1]
1448 # setup all interfaces
1449 for i in cls.pg_interfaces:
1454 # packets sizes reduced here because we are generating packets without
1455 # Ethernet headers, which are added later (diff fragments go via
1456 # different interfaces)
1457 cls.packet_sizes = [64-len(Ether()), 512-len(Ether()),
1458 1518-len(Ether()), 9018-len(Ether())]
1459 cls.padding = " abcdefghijklmn"
1460 cls.create_stream(cls.packet_sizes)
1461 cls.create_fragments()
1464 def tearDownClass(cls):
1465 super(TestIPv6MWReassembly, cls).tearDownClass()
1468 """ Test setup - force timeout on existing reassemblies """
1469 super(TestIPv6MWReassembly, self).setUp()
1470 for intf in self.send_ifs:
1471 self.vapi.ip_reassembly_enable_disable(
1472 sw_if_index=intf.sw_if_index, enable_ip6=True)
1473 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
1474 max_reassembly_length=1000,
1475 expire_walk_interval_ms=10, is_ip6=1)
1477 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
1478 max_reassembly_length=1000,
1479 expire_walk_interval_ms=1000, is_ip6=1)
1482 super(TestIPv6MWReassembly, self).tearDown()
1484 def show_commands_at_teardown(self):
1485 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
1486 self.logger.debug(self.vapi.ppcli("show buffers"))
1489 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
1490 """Create input packet stream
1492 :param list packet_sizes: Required packet sizes.
1494 for i in range(0, packet_count):
1495 info = cls.create_packet_info(cls.src_if, cls.src_if)
1496 payload = cls.info_to_payload(info)
1497 p = (IPv6(src=cls.src_if.remote_ip6,
1498 dst=cls.dst_if.remote_ip6) /
1499 UDP(sport=1234, dport=5678) /
1501 size = packet_sizes[(i // 2) % len(packet_sizes)]
1502 cls.extend_packet(p, size, cls.padding)
1506 def create_fragments(cls):
1507 infos = cls._packet_infos
1509 for index, info in infos.items():
1511 # cls.logger.debug(ppp("Packet:",
1512 # p.__class__(scapy.compat.raw(p))))
1513 fragments_400 = fragment_rfc8200(p, index, 400)
1514 cls.pkt_infos.append((index, fragments_400))
1515 cls.fragments_400 = [
1516 x for (_, frags) in cls.pkt_infos for x in frags]
1517 cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, " %
1518 (len(infos), len(cls.fragments_400)))
1520 def verify_capture(self, capture, dropped_packet_indexes=[]):
1521 """Verify captured packet strea .
1523 :param list capture: Captured packet stream.
1527 for packet in capture:
1529 self.logger.debug(ppp("Got packet:", packet))
1532 payload_info = self.payload_to_info(packet[Raw])
1533 packet_index = payload_info.index
1535 packet_index not in dropped_packet_indexes,
1536 ppp("Packet received, but should be dropped:", packet))
1537 if packet_index in seen:
1538 raise Exception(ppp("Duplicate packet received", packet))
1539 seen.add(packet_index)
1540 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
1541 info = self._packet_infos[packet_index]
1542 self.assertTrue(info is not None)
1543 self.assertEqual(packet_index, info.index)
1544 saved_packet = info.data
1545 self.assertEqual(ip.src, saved_packet[IPv6].src)
1546 self.assertEqual(ip.dst, saved_packet[IPv6].dst)
1547 self.assertEqual(udp.payload, saved_packet[UDP].payload)
1549 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1551 for index in self._packet_infos:
1552 self.assertTrue(index in seen or index in dropped_packet_indexes,
1553 "Packet with packet_index %d not received" % index)
1555 def send_packets(self, packets):
1556 for counter in range(self.vpp_worker_count):
1557 if 0 == len(packets[counter]):
1559 send_if = self.send_ifs[counter]
1561 (Ether(dst=send_if.local_mac, src=send_if.remote_mac) / x
1562 for x in packets[counter]),
1566 def test_worker_conflict(self):
1567 """ 1st and FO=0 fragments on different workers """
1569 # in first wave we send fragments which don't start at offset 0
1570 # then we send fragments with offset 0 on a different thread
1571 # then the rest of packets on a random thread
1572 first_packets = [[] for n in range(self.vpp_worker_count)]
1573 second_packets = [[] for n in range(self.vpp_worker_count)]
1574 rest_of_packets = [[] for n in range(self.vpp_worker_count)]
1575 for (_, p) in self.pkt_infos:
1576 wi = randrange(self.vpp_worker_count)
1577 second_packets[wi].append(p[0])
1582 wi2 = randrange(self.vpp_worker_count)
1583 first_packets[wi2].append(p[1])
1584 wi3 = randrange(self.vpp_worker_count)
1585 rest_of_packets[wi3].extend(p[2:])
1587 self.pg_enable_capture()
1588 self.send_packets(first_packets)
1589 self.send_packets(second_packets)
1590 self.send_packets(rest_of_packets)
1592 packets = self.dst_if.get_capture(len(self.pkt_infos))
1593 self.verify_capture(packets)
1594 for send_if in self.send_ifs:
1595 send_if.assert_nothing_captured()
1597 self.logger.debug(self.vapi.ppcli("show trace"))
1598 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
1599 self.logger.debug(self.vapi.ppcli("show buffers"))
1600 self.vapi.cli("clear trace")
1602 self.pg_enable_capture()
1603 self.send_packets(first_packets)
1604 self.send_packets(second_packets)
1605 self.send_packets(rest_of_packets)
1607 packets = self.dst_if.get_capture(len(self.pkt_infos))
1608 self.verify_capture(packets)
1609 for send_if in self.send_ifs:
1610 send_if.assert_nothing_captured()
1613 class TestIPv6SVReassembly(VppTestCase):
1614 """ IPv6 Shallow Virtual Reassembly """
1617 def setUpClass(cls):
1618 super(TestIPv6SVReassembly, cls).setUpClass()
1620 cls.create_pg_interfaces([0, 1])
1621 cls.src_if = cls.pg0
1622 cls.dst_if = cls.pg1
1624 # setup all interfaces
1625 for i in cls.pg_interfaces:
1631 """ Test setup - force timeout on existing reassemblies """
1632 super(TestIPv6SVReassembly, self).setUp()
1633 self.vapi.ip_reassembly_enable_disable(
1634 sw_if_index=self.src_if.sw_if_index, enable_ip6=True,
1635 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL)
1636 self.vapi.ip_reassembly_set(
1637 timeout_ms=0, max_reassemblies=1000,
1638 max_reassembly_length=1000,
1639 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
1640 expire_walk_interval_ms=10, is_ip6=1)
1642 self.vapi.ip_reassembly_set(
1643 timeout_ms=1000000, max_reassemblies=1000,
1644 max_reassembly_length=1000,
1645 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
1646 expire_walk_interval_ms=10000, is_ip6=1)
1649 super(TestIPv6SVReassembly, self).tearDown()
1650 self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details"))
1651 self.logger.debug(self.vapi.ppcli("show buffers"))
1653 def test_basic(self):
1654 """ basic reassembly """
1658 while len(payload) < payload_len:
1659 payload += "%u " % counter
1662 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1663 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1664 UDP(sport=1234, dport=5678) /
1666 fragments = fragment_rfc8200(p, 1, payload_len/4)
1668 # send fragment #2 - should be cached inside reassembly
1669 self.pg_enable_capture()
1670 self.src_if.add_stream(fragments[1])
1672 self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details"))
1673 self.logger.debug(self.vapi.ppcli("show buffers"))
1674 self.logger.debug(self.vapi.ppcli("show trace"))
1675 self.dst_if.assert_nothing_captured()
1677 # send fragment #1 - reassembly is finished now and both fragments
1679 self.pg_enable_capture()
1680 self.src_if.add_stream(fragments[0])
1682 self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details"))
1683 self.logger.debug(self.vapi.ppcli("show buffers"))
1684 self.logger.debug(self.vapi.ppcli("show trace"))
1685 c = self.dst_if.get_capture(2)
1686 for sent, recvd in zip([fragments[1], fragments[0]], c):
1687 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
1688 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
1689 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
1691 # send rest of fragments - should be immediately forwarded
1692 self.pg_enable_capture()
1693 self.src_if.add_stream(fragments[2:])
1695 c = self.dst_if.get_capture(len(fragments[2:]))
1696 for sent, recvd in zip(fragments[2:], c):
1697 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
1698 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
1699 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
1701 def test_verify_clear_trace_mid_reassembly(self):
1702 """ verify clear trace works mid-reassembly """
1706 while len(payload) < payload_len:
1707 payload += "%u " % counter
1710 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1711 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1712 UDP(sport=1234, dport=5678) /
1714 fragments = fragment_rfc8200(p, 1, payload_len/4)
1716 self.pg_enable_capture()
1717 self.src_if.add_stream(fragments[1])
1720 self.logger.debug(self.vapi.cli("show trace"))
1721 self.vapi.cli("clear trace")
1723 self.pg_enable_capture()
1724 self.src_if.add_stream(fragments[0])
1726 self.dst_if.get_capture(2)
1728 self.logger.debug(self.vapi.cli("show trace"))
1729 self.vapi.cli("clear trace")
1731 self.pg_enable_capture()
1732 self.src_if.add_stream(fragments[2:])
1734 self.dst_if.get_capture(len(fragments[2:]))
1736 def test_timeout(self):
1737 """ reassembly timeout """
1741 while len(payload) < payload_len:
1742 payload += "%u " % counter
1745 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1746 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1747 UDP(sport=1234, dport=5678) /
1749 fragments = fragment_rfc8200(p, 1, payload_len/4)
1751 self.vapi.ip_reassembly_set(
1752 timeout_ms=100, max_reassemblies=1000,
1753 max_reassembly_length=1000,
1754 expire_walk_interval_ms=50,
1756 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL)
1758 # send fragments #2 and #1 - should be forwarded
1759 self.pg_enable_capture()
1760 self.src_if.add_stream(fragments[0:2])
1762 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
1763 self.logger.debug(self.vapi.ppcli("show buffers"))
1764 self.logger.debug(self.vapi.ppcli("show trace"))
1765 c = self.dst_if.get_capture(2)
1766 for sent, recvd in zip([fragments[1], fragments[0]], c):
1767 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
1768 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
1769 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
1772 self.sleep(.25, "wait before sending rest of fragments")
1774 # send rest of fragments - shouldn't be forwarded
1775 self.pg_enable_capture()
1776 self.src_if.add_stream(fragments[2:])
1778 self.dst_if.assert_nothing_captured()
1781 """ reassembly reuses LRU element """
1783 self.vapi.ip_reassembly_set(
1784 timeout_ms=1000000, max_reassemblies=1,
1785 max_reassembly_length=1000,
1786 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
1787 is_ip6=1, expire_walk_interval_ms=10000)
1792 while len(payload) < payload_len:
1793 payload += "%u " % counter
1799 for i in range(packet_count)
1800 for p in (Ether(dst=self.src_if.local_mac,
1801 src=self.src_if.remote_mac) /
1802 IPv6(src=self.src_if.remote_ip6,
1803 dst=self.dst_if.remote_ip6) /
1804 UDP(sport=1234, dport=5678) /
1806 for f in fragment_rfc8200(p, i, payload_len/4)]
1808 self.pg_enable_capture()
1809 self.src_if.add_stream(fragments)
1811 c = self.dst_if.get_capture(len(fragments))
1812 for sent, recvd in zip(fragments, c):
1813 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
1814 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
1815 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
1818 class TestIPv4ReassemblyLocalNode(VppTestCase):
1819 """ IPv4 Reassembly for packets coming to ip4-local node """
1822 def setUpClass(cls):
1823 super(TestIPv4ReassemblyLocalNode, cls).setUpClass()
1825 cls.create_pg_interfaces([0])
1826 cls.src_dst_if = cls.pg0
1828 # setup all interfaces
1829 for i in cls.pg_interfaces:
1834 cls.padding = " abcdefghijklmn"
1836 cls.create_fragments()
1839 def tearDownClass(cls):
1840 super(TestIPv4ReassemblyLocalNode, cls).tearDownClass()
1843 """ Test setup - force timeout on existing reassemblies """
1844 super(TestIPv4ReassemblyLocalNode, self).setUp()
1845 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
1846 max_reassembly_length=1000,
1847 expire_walk_interval_ms=10)
1849 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
1850 max_reassembly_length=1000,
1851 expire_walk_interval_ms=10000)
1854 super(TestIPv4ReassemblyLocalNode, self).tearDown()
1856 def show_commands_at_teardown(self):
1857 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
1858 self.logger.debug(self.vapi.ppcli("show buffers"))
1861 def create_stream(cls, packet_count=test_packet_count):
1862 """Create input packet stream for defined interface.
1864 :param list packet_sizes: Required packet sizes.
1866 for i in range(0, packet_count):
1867 info = cls.create_packet_info(cls.src_dst_if, cls.src_dst_if)
1868 payload = cls.info_to_payload(info)
1869 p = (Ether(dst=cls.src_dst_if.local_mac,
1870 src=cls.src_dst_if.remote_mac) /
1871 IP(id=info.index, src=cls.src_dst_if.remote_ip4,
1872 dst=cls.src_dst_if.local_ip4) /
1873 ICMP(type='echo-request', id=1234) /
1875 cls.extend_packet(p, 1518, cls.padding)
1879 def create_fragments(cls):
1880 infos = cls._packet_infos
1882 for index, info in infos.items():
1884 # cls.logger.debug(ppp("Packet:",
1885 # p.__class__(scapy.compat.raw(p))))
1886 fragments_300 = fragment_rfc791(p, 300)
1887 cls.pkt_infos.append((index, fragments_300))
1888 cls.fragments_300 = [x for (_, frags) in cls.pkt_infos for x in frags]
1889 cls.logger.debug("Fragmented %s packets into %s 300-byte fragments" %
1890 (len(infos), len(cls.fragments_300)))
1892 def verify_capture(self, capture):
1893 """Verify captured packet stream.
1895 :param list capture: Captured packet stream.
1899 for packet in capture:
1901 self.logger.debug(ppp("Got packet:", packet))
1904 payload_info = self.payload_to_info(packet[Raw])
1905 packet_index = payload_info.index
1906 if packet_index in seen:
1907 raise Exception(ppp("Duplicate packet received", packet))
1908 seen.add(packet_index)
1909 self.assertEqual(payload_info.dst, self.src_dst_if.sw_if_index)
1910 info = self._packet_infos[packet_index]
1911 self.assertIsNotNone(info)
1912 self.assertEqual(packet_index, info.index)
1913 saved_packet = info.data
1914 self.assertEqual(ip.src, saved_packet[IP].dst)
1915 self.assertEqual(ip.dst, saved_packet[IP].src)
1916 self.assertEqual(icmp.type, 0) # echo reply
1917 self.assertEqual(icmp.id, saved_packet[ICMP].id)
1918 self.assertEqual(icmp.payload, saved_packet[ICMP].payload)
1920 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1922 for index in self._packet_infos:
1923 self.assertIn(index, seen,
1924 "Packet with packet_index %d not received" % index)
1926 def test_reassembly(self):
1927 """ basic reassembly """
1929 self.pg_enable_capture()
1930 self.src_dst_if.add_stream(self.fragments_300)
1933 packets = self.src_dst_if.get_capture(len(self.pkt_infos))
1934 self.verify_capture(packets)
1936 # run it all again to verify correctness
1937 self.pg_enable_capture()
1938 self.src_dst_if.add_stream(self.fragments_300)
1941 packets = self.src_dst_if.get_capture(len(self.pkt_infos))
1942 self.verify_capture(packets)
1945 class TestFIFReassembly(VppTestCase):
1946 """ Fragments in fragments reassembly """
1949 def setUpClass(cls):
1950 super(TestFIFReassembly, cls).setUpClass()
1952 cls.create_pg_interfaces([0, 1])
1953 cls.src_if = cls.pg0
1954 cls.dst_if = cls.pg1
1955 for i in cls.pg_interfaces:
1962 cls.packet_sizes = [64, 512, 1518, 9018]
1963 cls.padding = " abcdefghijklmn"
1966 def tearDownClass(cls):
1967 super(TestFIFReassembly, cls).tearDownClass()
1970 """ Test setup - force timeout on existing reassemblies """
1971 super(TestFIFReassembly, self).setUp()
1972 self.vapi.ip_reassembly_enable_disable(
1973 sw_if_index=self.src_if.sw_if_index, enable_ip4=True,
1975 self.vapi.ip_reassembly_enable_disable(
1976 sw_if_index=self.dst_if.sw_if_index, enable_ip4=True,
1978 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
1979 max_reassembly_length=1000,
1980 expire_walk_interval_ms=10)
1981 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
1982 max_reassembly_length=1000,
1983 expire_walk_interval_ms=10, is_ip6=1)
1985 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
1986 max_reassembly_length=1000,
1987 expire_walk_interval_ms=10000)
1988 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
1989 max_reassembly_length=1000,
1990 expire_walk_interval_ms=10000, is_ip6=1)
1993 super(TestFIFReassembly, self).tearDown()
1995 def show_commands_at_teardown(self):
1996 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
1997 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
1998 self.logger.debug(self.vapi.ppcli("show buffers"))
2000 def verify_capture(self, capture, ip_class, dropped_packet_indexes=[]):
2001 """Verify captured packet stream.
2003 :param list capture: Captured packet stream.
2007 for packet in capture:
2009 self.logger.debug(ppp("Got packet:", packet))
2010 ip = packet[ip_class]
2012 payload_info = self.payload_to_info(packet[Raw])
2013 packet_index = payload_info.index
2015 packet_index not in dropped_packet_indexes,
2016 ppp("Packet received, but should be dropped:", packet))
2017 if packet_index in seen:
2018 raise Exception(ppp("Duplicate packet received", packet))
2019 seen.add(packet_index)
2020 self.assertEqual(payload_info.dst, self.dst_if.sw_if_index)
2021 info = self._packet_infos[packet_index]
2022 self.assertTrue(info is not None)
2023 self.assertEqual(packet_index, info.index)
2024 saved_packet = info.data
2025 self.assertEqual(ip.src, saved_packet[ip_class].src)
2026 self.assertEqual(ip.dst, saved_packet[ip_class].dst)
2027 self.assertEqual(udp.payload, saved_packet[UDP].payload)
2029 self.logger.error(ppp("Unexpected or invalid packet:", packet))
2031 for index in self._packet_infos:
2032 self.assertTrue(index in seen or index in dropped_packet_indexes,
2033 "Packet with packet_index %d not received" % index)
2035 def test_fif4(self):
2036 """ Fragments in fragments (4o4) """
2038 # TODO this should be ideally in setUpClass, but then we hit a bug
2039 # with VppIpRoute incorrectly reporting it's present when it's not
2040 # so we need to manually remove the vpp config, thus we cannot have
2041 # it shared for multiple test cases
2042 self.tun_ip4 = "1.1.1.2"
2044 self.gre4 = VppGreInterface(self, self.src_if.local_ip4, self.tun_ip4)
2045 self.gre4.add_vpp_config()
2046 self.gre4.admin_up()
2047 self.gre4.config_ip4()
2049 self.vapi.ip_reassembly_enable_disable(
2050 sw_if_index=self.gre4.sw_if_index, enable_ip4=True)
2052 self.route4 = VppIpRoute(self, self.tun_ip4, 32,
2053 [VppRoutePath(self.src_if.remote_ip4,
2054 self.src_if.sw_if_index)])
2055 self.route4.add_vpp_config()
2057 self.reset_packet_infos()
2058 for i in range(test_packet_count):
2059 info = self.create_packet_info(self.src_if, self.dst_if)
2060 payload = self.info_to_payload(info)
2061 # Ethernet header here is only for size calculation, thus it
2062 # doesn't matter how it's initialized. This is to ensure that
2063 # reassembled packet is not > 9000 bytes, so that it's not dropped
2065 IP(id=i, src=self.src_if.remote_ip4,
2066 dst=self.dst_if.remote_ip4) /
2067 UDP(sport=1234, dport=5678) /
2069 size = self.packet_sizes[(i // 2) % len(self.packet_sizes)]
2070 self.extend_packet(p, size, self.padding)
2071 info.data = p[IP] # use only IP part, without ethernet header
2073 fragments = [x for _, p in self._packet_infos.items()
2074 for x in fragment_rfc791(p.data, 400)]
2076 encapped_fragments = \
2077 [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
2078 IP(src=self.tun_ip4, dst=self.src_if.local_ip4) /
2083 fragmented_encapped_fragments = \
2084 [x for p in encapped_fragments
2085 for x in fragment_rfc791(p, 200)]
2087 self.src_if.add_stream(fragmented_encapped_fragments)
2089 self.pg_enable_capture(self.pg_interfaces)
2092 self.src_if.assert_nothing_captured()
2093 packets = self.dst_if.get_capture(len(self._packet_infos))
2094 self.verify_capture(packets, IP)
2096 # TODO remove gre vpp config by hand until VppIpRoute gets fixed
2097 # so that it's query_vpp_config() works as it should
2098 self.gre4.remove_vpp_config()
2099 self.logger.debug(self.vapi.ppcli("show interface"))
2101 def test_fif6(self):
2102 """ Fragments in fragments (6o6) """
2103 # TODO this should be ideally in setUpClass, but then we hit a bug
2104 # with VppIpRoute incorrectly reporting it's present when it's not
2105 # so we need to manually remove the vpp config, thus we cannot have
2106 # it shared for multiple test cases
2107 self.tun_ip6 = "1002::1"
2109 self.gre6 = VppGreInterface(self, self.src_if.local_ip6, self.tun_ip6)
2110 self.gre6.add_vpp_config()
2111 self.gre6.admin_up()
2112 self.gre6.config_ip6()
2114 self.vapi.ip_reassembly_enable_disable(
2115 sw_if_index=self.gre6.sw_if_index, enable_ip6=True)
2117 self.route6 = VppIpRoute(self, self.tun_ip6, 128,
2119 self.src_if.remote_ip6,
2120 self.src_if.sw_if_index)])
2121 self.route6.add_vpp_config()
2123 self.reset_packet_infos()
2124 for i in range(test_packet_count):
2125 info = self.create_packet_info(self.src_if, self.dst_if)
2126 payload = self.info_to_payload(info)
2127 # Ethernet header here is only for size calculation, thus it
2128 # doesn't matter how it's initialized. This is to ensure that
2129 # reassembled packet is not > 9000 bytes, so that it's not dropped
2131 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
2132 UDP(sport=1234, dport=5678) /
2134 size = self.packet_sizes[(i // 2) % len(self.packet_sizes)]
2135 self.extend_packet(p, size, self.padding)
2136 info.data = p[IPv6] # use only IPv6 part, without ethernet header
2138 fragments = [x for _, i in self._packet_infos.items()
2139 for x in fragment_rfc8200(
2140 i.data, i.index, 400)]
2142 encapped_fragments = \
2143 [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
2144 IPv6(src=self.tun_ip6, dst=self.src_if.local_ip6) /
2149 fragmented_encapped_fragments = \
2150 [x for p in encapped_fragments for x in (
2153 2 * len(self._packet_infos) + p[IPv6ExtHdrFragment].id,
2155 if IPv6ExtHdrFragment in p else [p]
2159 self.src_if.add_stream(fragmented_encapped_fragments)
2161 self.pg_enable_capture(self.pg_interfaces)
2164 self.src_if.assert_nothing_captured()
2165 packets = self.dst_if.get_capture(len(self._packet_infos))
2166 self.verify_capture(packets, IPv6)
2168 # TODO remove gre vpp config by hand until VppIpRoute gets fixed
2169 # so that it's query_vpp_config() works as it should
2170 self.gre6.remove_vpp_config()
2173 if __name__ == '__main__':
2174 unittest.main(testRunner=VppTestRunner)