4 from random import shuffle, choice, randrange
6 from framework import VppTestCase, VppTestRunner
9 from scapy.packet import Raw
10 from scapy.layers.l2 import Ether, GRE
11 from scapy.layers.inet import IP, UDP, ICMP
12 from scapy.layers.inet6 import HBHOptUnknown, ICMPv6ParamProblem,\
13 ICMPv6TimeExceeded, IPv6, IPv6ExtHdrFragment, IPv6ExtHdrHopByHop
14 from framework import VppTestCase, VppTestRunner
15 from util import ppp, ppc, fragment_rfc791, fragment_rfc8200
16 from vpp_gre_interface import VppGreInterface
17 from vpp_ip import DpoProto
18 from vpp_ip_route import VppIpRoute, VppRoutePath, FibPathProto
19 from vpp_papi import VppEnum
21 # 35 is enough to have >257 400-byte fragments
22 test_packet_count = 35
24 # number of workers used for multi-worker test cases
28 class TestIPv4Reassembly(VppTestCase):
29 """ IPv4 Reassembly """
33 super(TestIPv4Reassembly, cls).setUpClass()
35 cls.create_pg_interfaces([0, 1])
39 # setup all interfaces
40 for i in cls.pg_interfaces:
46 cls.packet_sizes = [64, 512, 1518, 9018]
47 cls.padding = " abcdefghijklmn"
48 cls.create_stream(cls.packet_sizes)
49 cls.create_fragments()
52 def tearDownClass(cls):
53 super(TestIPv4Reassembly, cls).tearDownClass()
56 """ Test setup - force timeout on existing reassemblies """
57 super(TestIPv4Reassembly, self).setUp()
58 self.vapi.ip_reassembly_enable_disable(
59 sw_if_index=self.src_if.sw_if_index, enable_ip4=True)
60 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
61 max_reassembly_length=1000,
62 expire_walk_interval_ms=10)
64 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
65 max_reassembly_length=1000,
66 expire_walk_interval_ms=10000)
69 super(TestIPv4Reassembly, self).tearDown()
71 def show_commands_at_teardown(self):
72 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
73 self.logger.debug(self.vapi.ppcli("show buffers"))
76 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
77 """Create input packet stream
79 :param list packet_sizes: Required packet sizes.
81 for i in range(0, packet_count):
82 info = cls.create_packet_info(cls.src_if, cls.src_if)
83 payload = cls.info_to_payload(info)
84 p = (Ether(dst=cls.src_if.local_mac, src=cls.src_if.remote_mac) /
85 IP(id=info.index, src=cls.src_if.remote_ip4,
86 dst=cls.dst_if.remote_ip4) /
87 UDP(sport=1234, dport=5678) /
89 size = packet_sizes[(i // 2) % len(packet_sizes)]
90 cls.extend_packet(p, size, cls.padding)
94 def create_fragments(cls):
95 infos = cls._packet_infos
97 for index, info in infos.items():
99 # cls.logger.debug(ppp("Packet:",
100 # p.__class__(scapy.compat.raw(p))))
101 fragments_400 = fragment_rfc791(p, 400)
102 fragments_300 = fragment_rfc791(p, 300)
104 x for f in fragments_400 for x in fragment_rfc791(f, 200)]
105 cls.pkt_infos.append(
106 (index, fragments_400, fragments_300, fragments_200))
107 cls.fragments_400 = [
108 x for (_, frags, _, _) in cls.pkt_infos for x in frags]
109 cls.fragments_300 = [
110 x for (_, _, frags, _) in cls.pkt_infos for x in frags]
111 cls.fragments_200 = [
112 x for (_, _, _, frags) in cls.pkt_infos for x in frags]
113 cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, "
114 "%s 300-byte fragments and %s 200-byte fragments" %
115 (len(infos), len(cls.fragments_400),
116 len(cls.fragments_300), len(cls.fragments_200)))
118 def verify_capture(self, capture, dropped_packet_indexes=[]):
119 """Verify captured packet stream.
121 :param list capture: Captured packet stream.
125 for packet in capture:
127 self.logger.debug(ppp("Got packet:", packet))
130 payload_info = self.payload_to_info(packet[Raw])
131 packet_index = payload_info.index
133 packet_index not in dropped_packet_indexes,
134 ppp("Packet received, but should be dropped:", packet))
135 if packet_index in seen:
136 raise Exception(ppp("Duplicate packet received", packet))
137 seen.add(packet_index)
138 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
139 info = self._packet_infos[packet_index]
140 self.assertTrue(info is not None)
141 self.assertEqual(packet_index, info.index)
142 saved_packet = info.data
143 self.assertEqual(ip.src, saved_packet[IP].src)
144 self.assertEqual(ip.dst, saved_packet[IP].dst)
145 self.assertEqual(udp.payload, saved_packet[UDP].payload)
147 self.logger.error(ppp("Unexpected or invalid packet:", packet))
149 for index in self._packet_infos:
150 self.assertTrue(index in seen or index in dropped_packet_indexes,
151 "Packet with packet_index %d not received" % index)
153 def test_reassembly(self):
154 """ basic reassembly """
156 self.pg_enable_capture()
157 self.src_if.add_stream(self.fragments_200)
160 packets = self.dst_if.get_capture(len(self.pkt_infos))
161 self.verify_capture(packets)
162 self.src_if.assert_nothing_captured()
164 # run it all again to verify correctness
165 self.pg_enable_capture()
166 self.src_if.add_stream(self.fragments_200)
169 packets = self.dst_if.get_capture(len(self.pkt_infos))
170 self.verify_capture(packets)
171 self.src_if.assert_nothing_captured()
173 def test_verify_clear_trace_mid_reassembly(self):
174 """ verify clear trace works mid-reassembly """
176 self.pg_enable_capture()
177 self.src_if.add_stream(self.fragments_200[0:-1])
180 self.logger.debug(self.vapi.cli("show trace"))
181 self.vapi.cli("clear trace")
183 self.src_if.add_stream(self.fragments_200[-1])
185 packets = self.dst_if.get_capture(len(self.pkt_infos))
186 self.verify_capture(packets)
188 def test_reversed(self):
189 """ reverse order reassembly """
191 fragments = list(self.fragments_200)
194 self.pg_enable_capture()
195 self.src_if.add_stream(fragments)
198 packets = self.dst_if.get_capture(len(self.packet_infos))
199 self.verify_capture(packets)
200 self.src_if.assert_nothing_captured()
202 # run it all again to verify correctness
203 self.pg_enable_capture()
204 self.src_if.add_stream(fragments)
207 packets = self.dst_if.get_capture(len(self.packet_infos))
208 self.verify_capture(packets)
209 self.src_if.assert_nothing_captured()
211 def test_long_fragment_chain(self):
212 """ long fragment chain """
215 "/err/ip4-full-reassembly-feature/fragment chain too long (drop)"
217 error_cnt = self.statistics.get_err_counter(error_cnt_str)
219 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
220 max_reassembly_length=3,
221 expire_walk_interval_ms=50)
223 p1 = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
224 IP(id=1000, src=self.src_if.remote_ip4,
225 dst=self.dst_if.remote_ip4) /
226 UDP(sport=1234, dport=5678) /
228 p2 = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
229 IP(id=1001, src=self.src_if.remote_ip4,
230 dst=self.dst_if.remote_ip4) /
231 UDP(sport=1234, dport=5678) /
233 frags = fragment_rfc791(p1, 200) + fragment_rfc791(p2, 500)
235 self.pg_enable_capture()
236 self.src_if.add_stream(frags)
239 self.dst_if.get_capture(1)
240 self.assert_error_counter_equal(error_cnt_str, error_cnt + 1)
243 """ fragment length + ip header size > 65535 """
244 self.vapi.cli("clear errors")
245 raw = b'''E\x00\x00\x88,\xf8\x1f\xfe@\x01\x98\x00\xc0\xa8\n-\xc0\xa8\n\
246 \x01\x08\x00\xf0J\xed\xcb\xf1\xf5Test-group: IPv4.IPv4.ipv4-message.\
247 Ethernet-Payload.IPv4-Packet.IPv4-Header.Fragment-Offset; Test-case: 5737'''
248 malformed_packet = (Ether(dst=self.src_if.local_mac,
249 src=self.src_if.remote_mac) /
251 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
252 IP(id=1000, src=self.src_if.remote_ip4,
253 dst=self.dst_if.remote_ip4) /
254 UDP(sport=1234, dport=5678) /
256 valid_fragments = fragment_rfc791(p, 400)
258 counter = "/err/ip4-full-reassembly-feature/malformed packets"
259 error_counter = self.statistics.get_err_counter(counter)
260 self.pg_enable_capture()
261 self.src_if.add_stream([malformed_packet] + valid_fragments)
264 self.dst_if.get_capture(1)
265 self.logger.debug(self.vapi.ppcli("show error"))
266 self.assertEqual(self.statistics.get_err_counter(counter),
269 def test_44924(self):
270 """ compress tiny fragments """
271 packets = [(Ether(dst=self.src_if.local_mac,
272 src=self.src_if.remote_mac) /
273 IP(id=24339, flags="MF", frag=0, 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='Test-group: IPv4')),
278 (Ether(dst=self.src_if.local_mac,
279 src=self.src_if.remote_mac) /
280 IP(id=24339, flags="MF", frag=3, ttl=64,
281 src=self.src_if.remote_ip4,
282 dst=self.dst_if.remote_ip4) /
283 ICMP(type="echo-request", code=0, id=0x1fe6, seq=0x2407) /
284 Raw(load='.IPv4.Fragmentation.vali')),
285 (Ether(dst=self.src_if.local_mac,
286 src=self.src_if.remote_mac) /
287 IP(id=24339, frag=6, ttl=64,
288 src=self.src_if.remote_ip4,
289 dst=self.dst_if.remote_ip4) /
290 ICMP(type="echo-request", code=0, id=0x1fe6, seq=0x2407) /
291 Raw(load='d; Test-case: 44924'))
294 self.pg_enable_capture()
295 self.src_if.add_stream(packets)
298 self.dst_if.get_capture(1)
300 def test_frag_1(self):
301 """ fragment of size 1 """
302 self.vapi.cli("clear errors")
303 malformed_packets = [(Ether(dst=self.src_if.local_mac,
304 src=self.src_if.remote_mac) /
305 IP(id=7, len=21, flags="MF", frag=0, ttl=64,
306 src=self.src_if.remote_ip4,
307 dst=self.dst_if.remote_ip4) /
308 ICMP(type="echo-request")),
309 (Ether(dst=self.src_if.local_mac,
310 src=self.src_if.remote_mac) /
311 IP(id=7, len=21, frag=1, ttl=64,
312 src=self.src_if.remote_ip4,
313 dst=self.dst_if.remote_ip4) /
317 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
318 IP(id=1000, src=self.src_if.remote_ip4,
319 dst=self.dst_if.remote_ip4) /
320 UDP(sport=1234, dport=5678) /
322 valid_fragments = fragment_rfc791(p, 400)
324 self.pg_enable_capture()
325 self.src_if.add_stream(malformed_packets + valid_fragments)
328 self.dst_if.get_capture(1)
330 self.assert_packet_counter_equal("ip4-full-reassembly-feature", 1)
331 # TODO remove above, uncomment below once clearing of counters
333 # self.assert_packet_counter_equal(
334 # "/err/ip4-full-reassembly-feature/malformed packets", 1)
336 def test_random(self):
337 """ random order reassembly """
339 fragments = list(self.fragments_200)
342 self.pg_enable_capture()
343 self.src_if.add_stream(fragments)
346 packets = self.dst_if.get_capture(len(self.packet_infos))
347 self.verify_capture(packets)
348 self.src_if.assert_nothing_captured()
350 # run it all again to verify correctness
351 self.pg_enable_capture()
352 self.src_if.add_stream(fragments)
355 packets = self.dst_if.get_capture(len(self.packet_infos))
356 self.verify_capture(packets)
357 self.src_if.assert_nothing_captured()
359 def test_duplicates(self):
360 """ duplicate fragments """
363 x for (_, frags, _, _) in self.pkt_infos
365 for _ in range(0, min(2, len(frags)))
368 self.pg_enable_capture()
369 self.src_if.add_stream(fragments)
372 packets = self.dst_if.get_capture(len(self.pkt_infos))
373 self.verify_capture(packets)
374 self.src_if.assert_nothing_captured()
376 def test_overlap1(self):
377 """ overlapping fragments case #1 """
380 for _, _, frags_300, frags_200 in self.pkt_infos:
381 if len(frags_300) == 1:
382 fragments.extend(frags_300)
384 for i, j in zip(frags_200, frags_300):
388 self.pg_enable_capture()
389 self.src_if.add_stream(fragments)
392 packets = self.dst_if.get_capture(len(self.pkt_infos))
393 self.verify_capture(packets)
394 self.src_if.assert_nothing_captured()
396 # run it all to verify correctness
397 self.pg_enable_capture()
398 self.src_if.add_stream(fragments)
401 packets = self.dst_if.get_capture(len(self.pkt_infos))
402 self.verify_capture(packets)
403 self.src_if.assert_nothing_captured()
405 def test_overlap2(self):
406 """ overlapping fragments case #2 """
409 for _, _, frags_300, frags_200 in self.pkt_infos:
410 if len(frags_300) == 1:
411 fragments.extend(frags_300)
413 # care must be taken here so that there are no fragments
414 # received by vpp after reassembly is finished, otherwise
415 # new reassemblies will be started and packet generator will
416 # freak out when it detects unfreed buffers
417 zipped = zip(frags_300, frags_200)
423 self.pg_enable_capture()
424 self.src_if.add_stream(fragments)
427 packets = self.dst_if.get_capture(len(self.pkt_infos))
428 self.verify_capture(packets)
429 self.src_if.assert_nothing_captured()
431 # run it all to verify correctness
432 self.pg_enable_capture()
433 self.src_if.add_stream(fragments)
436 packets = self.dst_if.get_capture(len(self.pkt_infos))
437 self.verify_capture(packets)
438 self.src_if.assert_nothing_captured()
440 def test_timeout_inline(self):
441 """ timeout (inline) """
443 dropped_packet_indexes = set(
444 index for (index, frags, _, _) in self.pkt_infos if len(frags) > 1
447 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
448 max_reassembly_length=3,
449 expire_walk_interval_ms=10000)
451 self.pg_enable_capture()
452 self.src_if.add_stream(self.fragments_400)
455 packets = self.dst_if.get_capture(
456 len(self.pkt_infos) - len(dropped_packet_indexes))
457 self.verify_capture(packets, dropped_packet_indexes)
458 self.src_if.assert_nothing_captured()
460 def test_timeout_cleanup(self):
461 """ timeout (cleanup) """
463 # whole packets + fragmented packets sans last fragment
465 x for (_, frags_400, _, _) in self.pkt_infos
466 for x in frags_400[:-1 if len(frags_400) > 1 else None]
469 # last fragments for fragmented packets
470 fragments2 = [frags_400[-1]
471 for (_, frags_400, _, _) in self.pkt_infos
472 if len(frags_400) > 1]
474 dropped_packet_indexes = set(
475 index for (index, frags_400, _, _) in self.pkt_infos
476 if len(frags_400) > 1)
478 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
479 max_reassembly_length=1000,
480 expire_walk_interval_ms=50)
482 self.pg_enable_capture()
483 self.src_if.add_stream(fragments)
486 self.sleep(.25, "wait before sending rest of fragments")
488 self.src_if.add_stream(fragments2)
491 packets = self.dst_if.get_capture(
492 len(self.pkt_infos) - len(dropped_packet_indexes))
493 self.verify_capture(packets, dropped_packet_indexes)
494 self.src_if.assert_nothing_captured()
496 def test_disabled(self):
497 """ reassembly disabled """
499 dropped_packet_indexes = set(
500 index for (index, frags_400, _, _) in self.pkt_infos
501 if len(frags_400) > 1)
503 self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=0,
504 max_reassembly_length=3,
505 expire_walk_interval_ms=10000)
507 self.pg_enable_capture()
508 self.src_if.add_stream(self.fragments_400)
511 packets = self.dst_if.get_capture(
512 len(self.pkt_infos) - len(dropped_packet_indexes))
513 self.verify_capture(packets, dropped_packet_indexes)
514 self.src_if.assert_nothing_captured()
517 class TestIPv4SVReassembly(VppTestCase):
518 """ IPv4 Shallow Virtual Reassembly """
522 super(TestIPv4SVReassembly, cls).setUpClass()
524 cls.create_pg_interfaces([0, 1])
528 # setup all interfaces
529 for i in cls.pg_interfaces:
535 """ Test setup - force timeout on existing reassemblies """
536 super(TestIPv4SVReassembly, self).setUp()
537 self.vapi.ip_reassembly_enable_disable(
538 sw_if_index=self.src_if.sw_if_index, enable_ip4=True,
539 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL)
540 self.vapi.ip_reassembly_set(
541 timeout_ms=0, max_reassemblies=1000,
542 max_reassembly_length=1000,
543 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
544 expire_walk_interval_ms=10)
546 self.vapi.ip_reassembly_set(
547 timeout_ms=1000000, max_reassemblies=1000,
548 max_reassembly_length=1000,
549 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
550 expire_walk_interval_ms=10000)
553 super(TestIPv4SVReassembly, self).tearDown()
554 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
555 self.logger.debug(self.vapi.ppcli("show buffers"))
557 def test_basic(self):
558 """ basic reassembly """
562 while len(payload) < payload_len:
563 payload += "%u " % counter
566 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
567 IP(id=1, src=self.src_if.remote_ip4,
568 dst=self.dst_if.remote_ip4) /
569 UDP(sport=1234, dport=5678) /
571 fragments = fragment_rfc791(p, payload_len/4)
573 # send fragment #2 - should be cached inside reassembly
574 self.pg_enable_capture()
575 self.src_if.add_stream(fragments[1])
577 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
578 self.logger.debug(self.vapi.ppcli("show buffers"))
579 self.logger.debug(self.vapi.ppcli("show trace"))
580 self.dst_if.assert_nothing_captured()
582 # send fragment #1 - reassembly is finished now and both fragments
584 self.pg_enable_capture()
585 self.src_if.add_stream(fragments[0])
587 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
588 self.logger.debug(self.vapi.ppcli("show buffers"))
589 self.logger.debug(self.vapi.ppcli("show trace"))
590 c = self.dst_if.get_capture(2)
591 for sent, recvd in zip([fragments[1], fragments[0]], c):
592 self.assertEqual(sent[IP].src, recvd[IP].src)
593 self.assertEqual(sent[IP].dst, recvd[IP].dst)
594 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
596 # send rest of fragments - should be immediately forwarded
597 self.pg_enable_capture()
598 self.src_if.add_stream(fragments[2:])
600 c = self.dst_if.get_capture(len(fragments[2:]))
601 for sent, recvd in zip(fragments[2:], c):
602 self.assertEqual(sent[IP].src, recvd[IP].src)
603 self.assertEqual(sent[IP].dst, recvd[IP].dst)
604 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
606 def test_verify_clear_trace_mid_reassembly(self):
607 """ verify clear trace works mid-reassembly """
611 while len(payload) < payload_len:
612 payload += "%u " % counter
615 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
616 IP(id=1, src=self.src_if.remote_ip4,
617 dst=self.dst_if.remote_ip4) /
618 UDP(sport=1234, dport=5678) /
620 fragments = fragment_rfc791(p, payload_len/4)
622 self.pg_enable_capture()
623 self.src_if.add_stream(fragments[1])
626 self.logger.debug(self.vapi.cli("show trace"))
627 self.vapi.cli("clear trace")
629 self.pg_enable_capture()
630 self.src_if.add_stream(fragments[0])
632 self.dst_if.get_capture(2)
634 self.logger.debug(self.vapi.cli("show trace"))
635 self.vapi.cli("clear trace")
637 self.pg_enable_capture()
638 self.src_if.add_stream(fragments[2:])
640 self.dst_if.get_capture(len(fragments[2:]))
642 def test_timeout(self):
643 """ reassembly timeout """
647 while len(payload) < payload_len:
648 payload += "%u " % counter
651 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
652 IP(id=1, src=self.src_if.remote_ip4,
653 dst=self.dst_if.remote_ip4) /
654 UDP(sport=1234, dport=5678) /
656 fragments = fragment_rfc791(p, payload_len/4)
658 self.vapi.ip_reassembly_set(
659 timeout_ms=100, max_reassemblies=1000,
660 max_reassembly_length=1000,
661 expire_walk_interval_ms=50,
662 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL)
664 # send fragments #2 and #1 - should be forwarded
665 self.pg_enable_capture()
666 self.src_if.add_stream(fragments[0:2])
668 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
669 self.logger.debug(self.vapi.ppcli("show buffers"))
670 self.logger.debug(self.vapi.ppcli("show trace"))
671 c = self.dst_if.get_capture(2)
672 for sent, recvd in zip([fragments[1], fragments[0]], c):
673 self.assertEqual(sent[IP].src, recvd[IP].src)
674 self.assertEqual(sent[IP].dst, recvd[IP].dst)
675 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
678 self.sleep(.25, "wait before sending rest of fragments")
680 # send rest of fragments - shouldn't be forwarded
681 self.pg_enable_capture()
682 self.src_if.add_stream(fragments[2:])
684 self.dst_if.assert_nothing_captured()
687 """ reassembly reuses LRU element """
689 self.vapi.ip_reassembly_set(
690 timeout_ms=1000000, max_reassemblies=1,
691 max_reassembly_length=1000,
692 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
693 expire_walk_interval_ms=10000)
698 while len(payload) < payload_len:
699 payload += "%u " % counter
705 for i in range(packet_count)
706 for p in (Ether(dst=self.src_if.local_mac,
707 src=self.src_if.remote_mac) /
708 IP(id=i, src=self.src_if.remote_ip4,
709 dst=self.dst_if.remote_ip4) /
710 UDP(sport=1234, dport=5678) /
712 for f in fragment_rfc791(p, payload_len/4)]
714 self.pg_enable_capture()
715 self.src_if.add_stream(fragments)
717 c = self.dst_if.get_capture(len(fragments))
718 for sent, recvd in zip(fragments, c):
719 self.assertEqual(sent[IP].src, recvd[IP].src)
720 self.assertEqual(sent[IP].dst, recvd[IP].dst)
721 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
723 def send_mixed_and_verify_capture(self, traffic):
726 for c in range(t['count']):
728 (Ether(dst=self.src_if.local_mac,
729 src=self.src_if.remote_mac) /
732 src=self.src_if.remote_ip4,
733 dst=self.dst_if.remote_ip4) /
734 UDP(sport=1234, dport=5678) /
736 self.counter = self.counter + 1
738 self.pg_enable_capture()
739 self.src_if.add_stream(stream)
741 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
742 self.logger.debug(self.vapi.ppcli("show buffers"))
743 self.logger.debug(self.vapi.ppcli("show trace"))
744 self.dst_if.get_capture(len(stream))
746 def test_mixed(self):
747 """ mixed traffic correctly passes through SVR """
750 self.send_mixed_and_verify_capture([{'count': 1, 'flags': ''}])
751 self.send_mixed_and_verify_capture([{'count': 2, 'flags': ''}])
752 self.send_mixed_and_verify_capture([{'count': 3, 'flags': ''}])
753 self.send_mixed_and_verify_capture([{'count': 8, 'flags': ''}])
754 self.send_mixed_and_verify_capture([{'count': 257, 'flags': ''}])
756 self.send_mixed_and_verify_capture([{'count': 1, 'flags': 'MF'}])
757 self.send_mixed_and_verify_capture([{'count': 2, 'flags': 'MF'}])
758 self.send_mixed_and_verify_capture([{'count': 3, 'flags': 'MF'}])
759 self.send_mixed_and_verify_capture([{'count': 8, 'flags': 'MF'}])
760 self.send_mixed_and_verify_capture([{'count': 257, 'flags': 'MF'}])
762 self.send_mixed_and_verify_capture(
763 [{'count': 1, 'flags': ''}, {'count': 1, 'flags': 'MF'}])
764 self.send_mixed_and_verify_capture(
765 [{'count': 2, 'flags': ''}, {'count': 2, 'flags': 'MF'}])
766 self.send_mixed_and_verify_capture(
767 [{'count': 3, 'flags': ''}, {'count': 3, 'flags': 'MF'}])
768 self.send_mixed_and_verify_capture(
769 [{'count': 8, 'flags': ''}, {'count': 8, 'flags': 'MF'}])
770 self.send_mixed_and_verify_capture(
771 [{'count': 129, 'flags': ''}, {'count': 129, 'flags': 'MF'}])
773 self.send_mixed_and_verify_capture(
774 [{'count': 1, 'flags': ''}, {'count': 1, 'flags': 'MF'},
775 {'count': 1, 'flags': ''}, {'count': 1, 'flags': 'MF'}])
776 self.send_mixed_and_verify_capture(
777 [{'count': 2, 'flags': ''}, {'count': 2, 'flags': 'MF'},
778 {'count': 2, 'flags': ''}, {'count': 2, 'flags': 'MF'}])
779 self.send_mixed_and_verify_capture(
780 [{'count': 3, 'flags': ''}, {'count': 3, 'flags': 'MF'},
781 {'count': 3, 'flags': ''}, {'count': 3, 'flags': 'MF'}])
782 self.send_mixed_and_verify_capture(
783 [{'count': 8, 'flags': ''}, {'count': 8, 'flags': 'MF'},
784 {'count': 8, 'flags': ''}, {'count': 8, 'flags': 'MF'}])
785 self.send_mixed_and_verify_capture(
786 [{'count': 65, 'flags': ''}, {'count': 65, 'flags': 'MF'},
787 {'count': 65, 'flags': ''}, {'count': 65, 'flags': 'MF'}])
790 class TestIPv4MWReassembly(VppTestCase):
791 """ IPv4 Reassembly (multiple workers) """
792 worker_config = "workers %d" % worker_count
796 super(TestIPv4MWReassembly, cls).setUpClass()
798 cls.create_pg_interfaces(range(worker_count+1))
800 cls.send_ifs = cls.pg_interfaces[:-1]
801 cls.dst_if = cls.pg_interfaces[-1]
803 # setup all interfaces
804 for i in cls.pg_interfaces:
809 # packets sizes reduced here because we are generating packets without
810 # Ethernet headers, which are added later (diff fragments go via
811 # different interfaces)
812 cls.packet_sizes = [64-len(Ether()), 512-len(Ether()),
813 1518-len(Ether()), 9018-len(Ether())]
814 cls.padding = " abcdefghijklmn"
815 cls.create_stream(cls.packet_sizes)
816 cls.create_fragments()
819 def tearDownClass(cls):
820 super(TestIPv4MWReassembly, cls).tearDownClass()
823 """ Test setup - force timeout on existing reassemblies """
824 super(TestIPv4MWReassembly, self).setUp()
825 for intf in self.send_ifs:
826 self.vapi.ip_reassembly_enable_disable(
827 sw_if_index=intf.sw_if_index, enable_ip4=True)
828 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
829 max_reassembly_length=1000,
830 expire_walk_interval_ms=10)
832 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
833 max_reassembly_length=1000,
834 expire_walk_interval_ms=10000)
837 super(TestIPv4MWReassembly, self).tearDown()
839 def show_commands_at_teardown(self):
840 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
841 self.logger.debug(self.vapi.ppcli("show buffers"))
844 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
845 """Create input packet stream
847 :param list packet_sizes: Required packet sizes.
849 for i in range(0, packet_count):
850 info = cls.create_packet_info(cls.src_if, cls.src_if)
851 payload = cls.info_to_payload(info)
852 p = (IP(id=info.index, src=cls.src_if.remote_ip4,
853 dst=cls.dst_if.remote_ip4) /
854 UDP(sport=1234, dport=5678) /
856 size = packet_sizes[(i // 2) % len(packet_sizes)]
857 cls.extend_packet(p, size, cls.padding)
861 def create_fragments(cls):
862 infos = cls._packet_infos
864 for index, info in infos.items():
866 # cls.logger.debug(ppp("Packet:",
867 # p.__class__(scapy.compat.raw(p))))
868 fragments_400 = fragment_rfc791(p, 400)
869 cls.pkt_infos.append((index, fragments_400))
870 cls.fragments_400 = [
871 x for (_, frags) in cls.pkt_infos for x in frags]
872 cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, " %
873 (len(infos), len(cls.fragments_400)))
875 def verify_capture(self, capture, dropped_packet_indexes=[]):
876 """Verify captured packet stream.
878 :param list capture: Captured packet stream.
882 for packet in capture:
884 self.logger.debug(ppp("Got packet:", packet))
887 payload_info = self.payload_to_info(packet[Raw])
888 packet_index = payload_info.index
890 packet_index not in dropped_packet_indexes,
891 ppp("Packet received, but should be dropped:", packet))
892 if packet_index in seen:
893 raise Exception(ppp("Duplicate packet received", packet))
894 seen.add(packet_index)
895 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
896 info = self._packet_infos[packet_index]
897 self.assertTrue(info is not None)
898 self.assertEqual(packet_index, info.index)
899 saved_packet = info.data
900 self.assertEqual(ip.src, saved_packet[IP].src)
901 self.assertEqual(ip.dst, saved_packet[IP].dst)
902 self.assertEqual(udp.payload, saved_packet[UDP].payload)
904 self.logger.error(ppp("Unexpected or invalid packet:", packet))
906 for index in self._packet_infos:
907 self.assertTrue(index in seen or index in dropped_packet_indexes,
908 "Packet with packet_index %d not received" % index)
910 def send_packets(self, packets):
911 for counter in range(worker_count):
912 if 0 == len(packets[counter]):
914 send_if = self.send_ifs[counter]
916 (Ether(dst=send_if.local_mac, src=send_if.remote_mac) / x
917 for x in packets[counter]),
921 def test_worker_conflict(self):
922 """ 1st and FO=0 fragments on different workers """
924 # in first wave we send fragments which don't start at offset 0
925 # then we send fragments with offset 0 on a different thread
926 # then the rest of packets on a random thread
927 first_packets = [[] for n in range(worker_count)]
928 second_packets = [[] for n in range(worker_count)]
929 rest_of_packets = [[] for n in range(worker_count)]
930 for (_, p) in self.pkt_infos:
931 wi = randrange(worker_count)
932 second_packets[wi].append(p[0])
937 wi2 = randrange(worker_count)
938 first_packets[wi2].append(p[1])
939 wi3 = randrange(worker_count)
940 rest_of_packets[wi3].extend(p[2:])
942 self.pg_enable_capture()
943 self.send_packets(first_packets)
944 self.send_packets(second_packets)
945 self.send_packets(rest_of_packets)
947 packets = self.dst_if.get_capture(len(self.pkt_infos))
948 self.verify_capture(packets)
949 for send_if in self.send_ifs:
950 send_if.assert_nothing_captured()
952 self.logger.debug(self.vapi.ppcli("show trace"))
953 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
954 self.logger.debug(self.vapi.ppcli("show buffers"))
955 self.vapi.cli("clear trace")
957 self.pg_enable_capture()
958 self.send_packets(first_packets)
959 self.send_packets(second_packets)
960 self.send_packets(rest_of_packets)
962 packets = self.dst_if.get_capture(len(self.pkt_infos))
963 self.verify_capture(packets)
964 for send_if in self.send_ifs:
965 send_if.assert_nothing_captured()
968 class TestIPv6Reassembly(VppTestCase):
969 """ IPv6 Reassembly """
973 super(TestIPv6Reassembly, cls).setUpClass()
975 cls.create_pg_interfaces([0, 1])
979 # setup all interfaces
980 for i in cls.pg_interfaces:
986 cls.packet_sizes = [64, 512, 1518, 9018]
987 cls.padding = " abcdefghijklmn"
988 cls.create_stream(cls.packet_sizes)
989 cls.create_fragments()
992 def tearDownClass(cls):
993 super(TestIPv6Reassembly, cls).tearDownClass()
996 """ Test setup - force timeout on existing reassemblies """
997 super(TestIPv6Reassembly, self).setUp()
998 self.vapi.ip_reassembly_enable_disable(
999 sw_if_index=self.src_if.sw_if_index, enable_ip6=True)
1000 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
1001 max_reassembly_length=1000,
1002 expire_walk_interval_ms=10, is_ip6=1)
1004 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
1005 max_reassembly_length=1000,
1006 expire_walk_interval_ms=10000, is_ip6=1)
1007 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
1008 self.logger.debug(self.vapi.ppcli("show buffers"))
1011 super(TestIPv6Reassembly, self).tearDown()
1013 def show_commands_at_teardown(self):
1014 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
1015 self.logger.debug(self.vapi.ppcli("show buffers"))
1018 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
1019 """Create input packet stream for defined interface.
1021 :param list packet_sizes: Required packet sizes.
1023 for i in range(0, packet_count):
1024 info = cls.create_packet_info(cls.src_if, cls.src_if)
1025 payload = cls.info_to_payload(info)
1026 p = (Ether(dst=cls.src_if.local_mac, src=cls.src_if.remote_mac) /
1027 IPv6(src=cls.src_if.remote_ip6,
1028 dst=cls.dst_if.remote_ip6) /
1029 UDP(sport=1234, dport=5678) /
1031 size = packet_sizes[(i // 2) % len(packet_sizes)]
1032 cls.extend_packet(p, size, cls.padding)
1036 def create_fragments(cls):
1037 infos = cls._packet_infos
1039 for index, info in infos.items():
1041 # cls.logger.debug(ppp("Packet:",
1042 # p.__class__(scapy.compat.raw(p))))
1043 fragments_400 = fragment_rfc8200(p, info.index, 400)
1044 fragments_300 = fragment_rfc8200(p, info.index, 300)
1045 cls.pkt_infos.append((index, fragments_400, fragments_300))
1046 cls.fragments_400 = [
1047 x for _, frags, _ in cls.pkt_infos for x in frags]
1048 cls.fragments_300 = [
1049 x for _, _, frags in cls.pkt_infos for x in frags]
1050 cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, "
1051 "and %s 300-byte fragments" %
1052 (len(infos), len(cls.fragments_400),
1053 len(cls.fragments_300)))
1055 def verify_capture(self, capture, dropped_packet_indexes=[]):
1056 """Verify captured packet strea .
1058 :param list capture: Captured packet stream.
1062 for packet in capture:
1064 self.logger.debug(ppp("Got packet:", packet))
1067 payload_info = self.payload_to_info(packet[Raw])
1068 packet_index = payload_info.index
1070 packet_index not in dropped_packet_indexes,
1071 ppp("Packet received, but should be dropped:", packet))
1072 if packet_index in seen:
1073 raise Exception(ppp("Duplicate packet received", packet))
1074 seen.add(packet_index)
1075 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
1076 info = self._packet_infos[packet_index]
1077 self.assertTrue(info is not None)
1078 self.assertEqual(packet_index, info.index)
1079 saved_packet = info.data
1080 self.assertEqual(ip.src, saved_packet[IPv6].src)
1081 self.assertEqual(ip.dst, saved_packet[IPv6].dst)
1082 self.assertEqual(udp.payload, saved_packet[UDP].payload)
1084 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1086 for index in self._packet_infos:
1087 self.assertTrue(index in seen or index in dropped_packet_indexes,
1088 "Packet with packet_index %d not received" % index)
1090 def test_reassembly(self):
1091 """ basic reassembly """
1093 self.pg_enable_capture()
1094 self.src_if.add_stream(self.fragments_400)
1097 packets = self.dst_if.get_capture(len(self.pkt_infos))
1098 self.verify_capture(packets)
1099 self.src_if.assert_nothing_captured()
1101 # run it all again to verify correctness
1102 self.pg_enable_capture()
1103 self.src_if.add_stream(self.fragments_400)
1106 packets = self.dst_if.get_capture(len(self.pkt_infos))
1107 self.verify_capture(packets)
1108 self.src_if.assert_nothing_captured()
1110 def test_buffer_boundary(self):
1111 """ fragment header crossing buffer boundary """
1113 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1114 IPv6(src=self.src_if.remote_ip6,
1115 dst=self.src_if.local_ip6) /
1117 options=[HBHOptUnknown(otype=0xff, optlen=0)] * 1000) /
1118 IPv6ExtHdrFragment(m=1) /
1119 UDP(sport=1234, dport=5678) /
1121 self.pg_enable_capture()
1122 self.src_if.add_stream([p])
1124 self.src_if.assert_nothing_captured()
1125 self.dst_if.assert_nothing_captured()
1127 def test_verify_clear_trace_mid_reassembly(self):
1128 """ verify clear trace works mid-reassembly """
1130 self.pg_enable_capture()
1131 self.src_if.add_stream(self.fragments_400[0:-1])
1134 self.logger.debug(self.vapi.cli("show trace"))
1135 self.vapi.cli("clear trace")
1137 self.src_if.add_stream(self.fragments_400[-1])
1139 packets = self.dst_if.get_capture(len(self.pkt_infos))
1140 self.verify_capture(packets)
1142 def test_reversed(self):
1143 """ reverse order reassembly """
1145 fragments = list(self.fragments_400)
1148 self.pg_enable_capture()
1149 self.src_if.add_stream(fragments)
1152 packets = self.dst_if.get_capture(len(self.pkt_infos))
1153 self.verify_capture(packets)
1154 self.src_if.assert_nothing_captured()
1156 # run it all again to verify correctness
1157 self.pg_enable_capture()
1158 self.src_if.add_stream(fragments)
1161 packets = self.dst_if.get_capture(len(self.pkt_infos))
1162 self.verify_capture(packets)
1163 self.src_if.assert_nothing_captured()
1165 def test_random(self):
1166 """ random order reassembly """
1168 fragments = list(self.fragments_400)
1171 self.pg_enable_capture()
1172 self.src_if.add_stream(fragments)
1175 packets = self.dst_if.get_capture(len(self.pkt_infos))
1176 self.verify_capture(packets)
1177 self.src_if.assert_nothing_captured()
1179 # run it all again to verify correctness
1180 self.pg_enable_capture()
1181 self.src_if.add_stream(fragments)
1184 packets = self.dst_if.get_capture(len(self.pkt_infos))
1185 self.verify_capture(packets)
1186 self.src_if.assert_nothing_captured()
1188 def test_duplicates(self):
1189 """ duplicate fragments """
1192 x for (_, frags, _) in self.pkt_infos
1194 for _ in range(0, min(2, len(frags)))
1197 self.pg_enable_capture()
1198 self.src_if.add_stream(fragments)
1201 packets = self.dst_if.get_capture(len(self.pkt_infos))
1202 self.verify_capture(packets)
1203 self.src_if.assert_nothing_captured()
1205 def test_long_fragment_chain(self):
1206 """ long fragment chain """
1209 "/err/ip6-full-reassembly-feature/fragment chain too long (drop)"
1211 error_cnt = self.statistics.get_err_counter(error_cnt_str)
1213 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
1214 max_reassembly_length=3,
1215 expire_walk_interval_ms=50, is_ip6=1)
1217 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1218 IPv6(src=self.src_if.remote_ip6,
1219 dst=self.dst_if.remote_ip6) /
1220 UDP(sport=1234, dport=5678) /
1222 frags = fragment_rfc8200(p, 1, 300) + fragment_rfc8200(p, 2, 500)
1224 self.pg_enable_capture()
1225 self.src_if.add_stream(frags)
1228 self.dst_if.get_capture(1)
1229 self.assert_error_counter_equal(error_cnt_str, error_cnt + 1)
1231 def test_overlap1(self):
1232 """ overlapping fragments case #1 """
1235 for _, frags_400, frags_300 in self.pkt_infos:
1236 if len(frags_300) == 1:
1237 fragments.extend(frags_400)
1239 for i, j in zip(frags_300, frags_400):
1243 dropped_packet_indexes = set(
1244 index for (index, _, frags) in self.pkt_infos if len(frags) > 1
1247 self.pg_enable_capture()
1248 self.src_if.add_stream(fragments)
1251 packets = self.dst_if.get_capture(
1252 len(self.pkt_infos) - len(dropped_packet_indexes))
1253 self.verify_capture(packets, dropped_packet_indexes)
1254 self.src_if.assert_nothing_captured()
1256 def test_overlap2(self):
1257 """ overlapping fragments case #2 """
1260 for _, frags_400, frags_300 in self.pkt_infos:
1261 if len(frags_400) == 1:
1262 fragments.extend(frags_400)
1264 # care must be taken here so that there are no fragments
1265 # received by vpp after reassembly is finished, otherwise
1266 # new reassemblies will be started and packet generator will
1267 # freak out when it detects unfreed buffers
1268 zipped = zip(frags_400, frags_300)
1274 dropped_packet_indexes = set(
1275 index for (index, _, frags) in self.pkt_infos if len(frags) > 1
1278 self.pg_enable_capture()
1279 self.src_if.add_stream(fragments)
1282 packets = self.dst_if.get_capture(
1283 len(self.pkt_infos) - len(dropped_packet_indexes))
1284 self.verify_capture(packets, dropped_packet_indexes)
1285 self.src_if.assert_nothing_captured()
1287 def test_timeout_inline(self):
1288 """ timeout (inline) """
1290 dropped_packet_indexes = set(
1291 index for (index, frags, _) in self.pkt_infos if len(frags) > 1
1294 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
1295 max_reassembly_length=3,
1296 expire_walk_interval_ms=10000, is_ip6=1)
1298 self.pg_enable_capture()
1299 self.src_if.add_stream(self.fragments_400)
1302 packets = self.dst_if.get_capture(
1303 len(self.pkt_infos) - len(dropped_packet_indexes))
1304 self.verify_capture(packets, dropped_packet_indexes)
1305 pkts = self.src_if.get_capture(
1306 expected_count=len(dropped_packet_indexes))
1308 self.assertIn(ICMPv6TimeExceeded, icmp)
1309 self.assertIn(IPv6ExtHdrFragment, icmp)
1310 self.assertIn(icmp[IPv6ExtHdrFragment].id, dropped_packet_indexes)
1311 dropped_packet_indexes.remove(icmp[IPv6ExtHdrFragment].id)
1313 def test_timeout_cleanup(self):
1314 """ timeout (cleanup) """
1316 # whole packets + fragmented packets sans last fragment
1318 x for (_, frags_400, _) in self.pkt_infos
1319 for x in frags_400[:-1 if len(frags_400) > 1 else None]
1322 # last fragments for fragmented packets
1323 fragments2 = [frags_400[-1]
1324 for (_, frags_400, _) in self.pkt_infos
1325 if len(frags_400) > 1]
1327 dropped_packet_indexes = set(
1328 index for (index, frags_400, _) in self.pkt_infos
1329 if len(frags_400) > 1)
1331 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
1332 max_reassembly_length=1000,
1333 expire_walk_interval_ms=50)
1335 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
1336 max_reassembly_length=1000,
1337 expire_walk_interval_ms=50, is_ip6=1)
1339 self.pg_enable_capture()
1340 self.src_if.add_stream(fragments)
1343 self.sleep(.25, "wait before sending rest of fragments")
1345 self.src_if.add_stream(fragments2)
1348 packets = self.dst_if.get_capture(
1349 len(self.pkt_infos) - len(dropped_packet_indexes))
1350 self.verify_capture(packets, dropped_packet_indexes)
1351 pkts = self.src_if.get_capture(
1352 expected_count=len(dropped_packet_indexes))
1354 self.assertIn(ICMPv6TimeExceeded, icmp)
1355 self.assertIn(IPv6ExtHdrFragment, icmp)
1356 self.assertIn(icmp[IPv6ExtHdrFragment].id, dropped_packet_indexes)
1357 dropped_packet_indexes.remove(icmp[IPv6ExtHdrFragment].id)
1359 def test_disabled(self):
1360 """ reassembly disabled """
1362 dropped_packet_indexes = set(
1363 index for (index, frags_400, _) in self.pkt_infos
1364 if len(frags_400) > 1)
1366 self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=0,
1367 max_reassembly_length=3,
1368 expire_walk_interval_ms=10000, is_ip6=1)
1370 self.pg_enable_capture()
1371 self.src_if.add_stream(self.fragments_400)
1374 packets = self.dst_if.get_capture(
1375 len(self.pkt_infos) - len(dropped_packet_indexes))
1376 self.verify_capture(packets, dropped_packet_indexes)
1377 self.src_if.assert_nothing_captured()
1379 def test_missing_upper(self):
1380 """ missing upper layer """
1381 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1382 IPv6(src=self.src_if.remote_ip6,
1383 dst=self.src_if.local_ip6) /
1384 UDP(sport=1234, dport=5678) /
1386 self.extend_packet(p, 1000, self.padding)
1387 fragments = fragment_rfc8200(p, 1, 500)
1388 bad_fragment = p.__class__(scapy.compat.raw(fragments[1]))
1389 bad_fragment[IPv6ExtHdrFragment].nh = 59
1390 bad_fragment[IPv6ExtHdrFragment].offset = 0
1391 self.pg_enable_capture()
1392 self.src_if.add_stream([bad_fragment])
1394 pkts = self.src_if.get_capture(expected_count=1)
1396 self.assertIn(ICMPv6ParamProblem, icmp)
1397 self.assert_equal(icmp[ICMPv6ParamProblem].code, 3, "ICMP code")
1399 def test_invalid_frag_size(self):
1400 """ fragment size not a multiple of 8 """
1401 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1402 IPv6(src=self.src_if.remote_ip6,
1403 dst=self.src_if.local_ip6) /
1404 UDP(sport=1234, dport=5678) /
1406 self.extend_packet(p, 1000, self.padding)
1407 fragments = fragment_rfc8200(p, 1, 500)
1408 bad_fragment = fragments[0]
1409 self.extend_packet(bad_fragment, len(bad_fragment) + 5)
1410 self.pg_enable_capture()
1411 self.src_if.add_stream([bad_fragment])
1413 pkts = self.src_if.get_capture(expected_count=1)
1415 self.assertIn(ICMPv6ParamProblem, icmp)
1416 self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code")
1418 def test_invalid_packet_size(self):
1419 """ total packet size > 65535 """
1420 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1421 IPv6(src=self.src_if.remote_ip6,
1422 dst=self.src_if.local_ip6) /
1423 UDP(sport=1234, dport=5678) /
1425 self.extend_packet(p, 1000, self.padding)
1426 fragments = fragment_rfc8200(p, 1, 500)
1427 bad_fragment = fragments[1]
1428 bad_fragment[IPv6ExtHdrFragment].offset = 65500
1429 self.pg_enable_capture()
1430 self.src_if.add_stream([bad_fragment])
1432 pkts = self.src_if.get_capture(expected_count=1)
1434 self.assertIn(ICMPv6ParamProblem, icmp)
1435 self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code")
1438 class TestIPv6MWReassembly(VppTestCase):
1439 """ IPv6 Reassembly (multiple workers) """
1440 worker_config = "workers %d" % worker_count
1443 def setUpClass(cls):
1444 super(TestIPv6MWReassembly, cls).setUpClass()
1446 cls.create_pg_interfaces(range(worker_count+1))
1447 cls.src_if = cls.pg0
1448 cls.send_ifs = cls.pg_interfaces[:-1]
1449 cls.dst_if = cls.pg_interfaces[-1]
1451 # setup all interfaces
1452 for i in cls.pg_interfaces:
1457 # packets sizes reduced here because we are generating packets without
1458 # Ethernet headers, which are added later (diff fragments go via
1459 # different interfaces)
1460 cls.packet_sizes = [64-len(Ether()), 512-len(Ether()),
1461 1518-len(Ether()), 9018-len(Ether())]
1462 cls.padding = " abcdefghijklmn"
1463 cls.create_stream(cls.packet_sizes)
1464 cls.create_fragments()
1467 def tearDownClass(cls):
1468 super(TestIPv6MWReassembly, cls).tearDownClass()
1471 """ Test setup - force timeout on existing reassemblies """
1472 super(TestIPv6MWReassembly, self).setUp()
1473 for intf in self.send_ifs:
1474 self.vapi.ip_reassembly_enable_disable(
1475 sw_if_index=intf.sw_if_index, enable_ip6=True)
1476 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
1477 max_reassembly_length=1000,
1478 expire_walk_interval_ms=10, is_ip6=1)
1480 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
1481 max_reassembly_length=1000,
1482 expire_walk_interval_ms=1000, is_ip6=1)
1485 super(TestIPv6MWReassembly, self).tearDown()
1487 def show_commands_at_teardown(self):
1488 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
1489 self.logger.debug(self.vapi.ppcli("show buffers"))
1492 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
1493 """Create input packet stream
1495 :param list packet_sizes: Required packet sizes.
1497 for i in range(0, packet_count):
1498 info = cls.create_packet_info(cls.src_if, cls.src_if)
1499 payload = cls.info_to_payload(info)
1500 p = (IPv6(src=cls.src_if.remote_ip6,
1501 dst=cls.dst_if.remote_ip6) /
1502 UDP(sport=1234, dport=5678) /
1504 size = packet_sizes[(i // 2) % len(packet_sizes)]
1505 cls.extend_packet(p, size, cls.padding)
1509 def create_fragments(cls):
1510 infos = cls._packet_infos
1512 for index, info in infos.items():
1514 # cls.logger.debug(ppp("Packet:",
1515 # p.__class__(scapy.compat.raw(p))))
1516 fragments_400 = fragment_rfc8200(p, index, 400)
1517 cls.pkt_infos.append((index, fragments_400))
1518 cls.fragments_400 = [
1519 x for (_, frags) in cls.pkt_infos for x in frags]
1520 cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, " %
1521 (len(infos), len(cls.fragments_400)))
1523 def verify_capture(self, capture, dropped_packet_indexes=[]):
1524 """Verify captured packet strea .
1526 :param list capture: Captured packet stream.
1530 for packet in capture:
1532 self.logger.debug(ppp("Got packet:", packet))
1535 payload_info = self.payload_to_info(packet[Raw])
1536 packet_index = payload_info.index
1538 packet_index not in dropped_packet_indexes,
1539 ppp("Packet received, but should be dropped:", packet))
1540 if packet_index in seen:
1541 raise Exception(ppp("Duplicate packet received", packet))
1542 seen.add(packet_index)
1543 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
1544 info = self._packet_infos[packet_index]
1545 self.assertTrue(info is not None)
1546 self.assertEqual(packet_index, info.index)
1547 saved_packet = info.data
1548 self.assertEqual(ip.src, saved_packet[IPv6].src)
1549 self.assertEqual(ip.dst, saved_packet[IPv6].dst)
1550 self.assertEqual(udp.payload, saved_packet[UDP].payload)
1552 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1554 for index in self._packet_infos:
1555 self.assertTrue(index in seen or index in dropped_packet_indexes,
1556 "Packet with packet_index %d not received" % index)
1558 def send_packets(self, packets):
1559 for counter in range(worker_count):
1560 if 0 == len(packets[counter]):
1562 send_if = self.send_ifs[counter]
1564 (Ether(dst=send_if.local_mac, src=send_if.remote_mac) / x
1565 for x in packets[counter]),
1569 def test_worker_conflict(self):
1570 """ 1st and FO=0 fragments on different workers """
1572 # in first wave we send fragments which don't start at offset 0
1573 # then we send fragments with offset 0 on a different thread
1574 # then the rest of packets on a random thread
1575 first_packets = [[] for n in range(worker_count)]
1576 second_packets = [[] for n in range(worker_count)]
1577 rest_of_packets = [[] for n in range(worker_count)]
1578 for (_, p) in self.pkt_infos:
1579 wi = randrange(worker_count)
1580 second_packets[wi].append(p[0])
1585 wi2 = randrange(worker_count)
1586 first_packets[wi2].append(p[1])
1587 wi3 = randrange(worker_count)
1588 rest_of_packets[wi3].extend(p[2:])
1590 self.pg_enable_capture()
1591 self.send_packets(first_packets)
1592 self.send_packets(second_packets)
1593 self.send_packets(rest_of_packets)
1595 packets = self.dst_if.get_capture(len(self.pkt_infos))
1596 self.verify_capture(packets)
1597 for send_if in self.send_ifs:
1598 send_if.assert_nothing_captured()
1600 self.logger.debug(self.vapi.ppcli("show trace"))
1601 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
1602 self.logger.debug(self.vapi.ppcli("show buffers"))
1603 self.vapi.cli("clear trace")
1605 self.pg_enable_capture()
1606 self.send_packets(first_packets)
1607 self.send_packets(second_packets)
1608 self.send_packets(rest_of_packets)
1610 packets = self.dst_if.get_capture(len(self.pkt_infos))
1611 self.verify_capture(packets)
1612 for send_if in self.send_ifs:
1613 send_if.assert_nothing_captured()
1616 class TestIPv6SVReassembly(VppTestCase):
1617 """ IPv6 Shallow Virtual Reassembly """
1620 def setUpClass(cls):
1621 super(TestIPv6SVReassembly, cls).setUpClass()
1623 cls.create_pg_interfaces([0, 1])
1624 cls.src_if = cls.pg0
1625 cls.dst_if = cls.pg1
1627 # setup all interfaces
1628 for i in cls.pg_interfaces:
1634 """ Test setup - force timeout on existing reassemblies """
1635 super(TestIPv6SVReassembly, self).setUp()
1636 self.vapi.ip_reassembly_enable_disable(
1637 sw_if_index=self.src_if.sw_if_index, enable_ip6=True,
1638 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL)
1639 self.vapi.ip_reassembly_set(
1640 timeout_ms=0, max_reassemblies=1000,
1641 max_reassembly_length=1000,
1642 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
1643 expire_walk_interval_ms=10, is_ip6=1)
1645 self.vapi.ip_reassembly_set(
1646 timeout_ms=1000000, max_reassemblies=1000,
1647 max_reassembly_length=1000,
1648 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
1649 expire_walk_interval_ms=10000, is_ip6=1)
1652 super(TestIPv6SVReassembly, self).tearDown()
1653 self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details"))
1654 self.logger.debug(self.vapi.ppcli("show buffers"))
1656 def test_basic(self):
1657 """ basic reassembly """
1661 while len(payload) < payload_len:
1662 payload += "%u " % counter
1665 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1666 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1667 UDP(sport=1234, dport=5678) /
1669 fragments = fragment_rfc8200(p, 1, payload_len/4)
1671 # send fragment #2 - should be cached inside reassembly
1672 self.pg_enable_capture()
1673 self.src_if.add_stream(fragments[1])
1675 self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details"))
1676 self.logger.debug(self.vapi.ppcli("show buffers"))
1677 self.logger.debug(self.vapi.ppcli("show trace"))
1678 self.dst_if.assert_nothing_captured()
1680 # send fragment #1 - reassembly is finished now and both fragments
1682 self.pg_enable_capture()
1683 self.src_if.add_stream(fragments[0])
1685 self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details"))
1686 self.logger.debug(self.vapi.ppcli("show buffers"))
1687 self.logger.debug(self.vapi.ppcli("show trace"))
1688 c = self.dst_if.get_capture(2)
1689 for sent, recvd in zip([fragments[1], fragments[0]], c):
1690 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
1691 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
1692 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
1694 # send rest of fragments - should be immediately forwarded
1695 self.pg_enable_capture()
1696 self.src_if.add_stream(fragments[2:])
1698 c = self.dst_if.get_capture(len(fragments[2:]))
1699 for sent, recvd in zip(fragments[2:], c):
1700 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
1701 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
1702 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
1704 def test_verify_clear_trace_mid_reassembly(self):
1705 """ verify clear trace works mid-reassembly """
1709 while len(payload) < payload_len:
1710 payload += "%u " % counter
1713 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1714 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1715 UDP(sport=1234, dport=5678) /
1717 fragments = fragment_rfc8200(p, 1, payload_len/4)
1719 self.pg_enable_capture()
1720 self.src_if.add_stream(fragments[1])
1723 self.logger.debug(self.vapi.cli("show trace"))
1724 self.vapi.cli("clear trace")
1726 self.pg_enable_capture()
1727 self.src_if.add_stream(fragments[0])
1729 self.dst_if.get_capture(2)
1731 self.logger.debug(self.vapi.cli("show trace"))
1732 self.vapi.cli("clear trace")
1734 self.pg_enable_capture()
1735 self.src_if.add_stream(fragments[2:])
1737 self.dst_if.get_capture(len(fragments[2:]))
1739 def test_timeout(self):
1740 """ reassembly timeout """
1744 while len(payload) < payload_len:
1745 payload += "%u " % counter
1748 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1749 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1750 UDP(sport=1234, dport=5678) /
1752 fragments = fragment_rfc8200(p, 1, payload_len/4)
1754 self.vapi.ip_reassembly_set(
1755 timeout_ms=100, max_reassemblies=1000,
1756 max_reassembly_length=1000,
1757 expire_walk_interval_ms=50,
1759 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL)
1761 # send fragments #2 and #1 - should be forwarded
1762 self.pg_enable_capture()
1763 self.src_if.add_stream(fragments[0:2])
1765 self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details"))
1766 self.logger.debug(self.vapi.ppcli("show buffers"))
1767 self.logger.debug(self.vapi.ppcli("show trace"))
1768 c = self.dst_if.get_capture(2)
1769 for sent, recvd in zip([fragments[1], fragments[0]], c):
1770 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
1771 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
1772 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
1775 self.sleep(.25, "wait before sending rest of fragments")
1777 # send rest of fragments - shouldn't be forwarded
1778 self.pg_enable_capture()
1779 self.src_if.add_stream(fragments[2:])
1781 self.dst_if.assert_nothing_captured()
1784 """ reassembly reuses LRU element """
1786 self.vapi.ip_reassembly_set(
1787 timeout_ms=1000000, max_reassemblies=1,
1788 max_reassembly_length=1000,
1789 type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL,
1790 is_ip6=1, expire_walk_interval_ms=10000)
1795 while len(payload) < payload_len:
1796 payload += "%u " % counter
1802 for i in range(packet_count)
1803 for p in (Ether(dst=self.src_if.local_mac,
1804 src=self.src_if.remote_mac) /
1805 IPv6(src=self.src_if.remote_ip6,
1806 dst=self.dst_if.remote_ip6) /
1807 UDP(sport=1234, dport=5678) /
1809 for f in fragment_rfc8200(p, i, payload_len/4)]
1811 self.pg_enable_capture()
1812 self.src_if.add_stream(fragments)
1814 c = self.dst_if.get_capture(len(fragments))
1815 for sent, recvd in zip(fragments, c):
1816 self.assertEqual(sent[IPv6].src, recvd[IPv6].src)
1817 self.assertEqual(sent[IPv6].dst, recvd[IPv6].dst)
1818 self.assertEqual(sent[Raw].payload, recvd[Raw].payload)
1821 class TestIPv4ReassemblyLocalNode(VppTestCase):
1822 """ IPv4 Reassembly for packets coming to ip4-local node """
1825 def setUpClass(cls):
1826 super(TestIPv4ReassemblyLocalNode, cls).setUpClass()
1828 cls.create_pg_interfaces([0])
1829 cls.src_dst_if = cls.pg0
1831 # setup all interfaces
1832 for i in cls.pg_interfaces:
1837 cls.padding = " abcdefghijklmn"
1839 cls.create_fragments()
1842 def tearDownClass(cls):
1843 super(TestIPv4ReassemblyLocalNode, cls).tearDownClass()
1846 """ Test setup - force timeout on existing reassemblies """
1847 super(TestIPv4ReassemblyLocalNode, self).setUp()
1848 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
1849 max_reassembly_length=1000,
1850 expire_walk_interval_ms=10)
1852 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
1853 max_reassembly_length=1000,
1854 expire_walk_interval_ms=10000)
1857 super(TestIPv4ReassemblyLocalNode, self).tearDown()
1859 def show_commands_at_teardown(self):
1860 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
1861 self.logger.debug(self.vapi.ppcli("show buffers"))
1864 def create_stream(cls, packet_count=test_packet_count):
1865 """Create input packet stream for defined interface.
1867 :param list packet_sizes: Required packet sizes.
1869 for i in range(0, packet_count):
1870 info = cls.create_packet_info(cls.src_dst_if, cls.src_dst_if)
1871 payload = cls.info_to_payload(info)
1872 p = (Ether(dst=cls.src_dst_if.local_mac,
1873 src=cls.src_dst_if.remote_mac) /
1874 IP(id=info.index, src=cls.src_dst_if.remote_ip4,
1875 dst=cls.src_dst_if.local_ip4) /
1876 ICMP(type='echo-request', id=1234) /
1878 cls.extend_packet(p, 1518, cls.padding)
1882 def create_fragments(cls):
1883 infos = cls._packet_infos
1885 for index, info in infos.items():
1887 # cls.logger.debug(ppp("Packet:",
1888 # p.__class__(scapy.compat.raw(p))))
1889 fragments_300 = fragment_rfc791(p, 300)
1890 cls.pkt_infos.append((index, fragments_300))
1891 cls.fragments_300 = [x for (_, frags) in cls.pkt_infos for x in frags]
1892 cls.logger.debug("Fragmented %s packets into %s 300-byte fragments" %
1893 (len(infos), len(cls.fragments_300)))
1895 def verify_capture(self, capture):
1896 """Verify captured packet stream.
1898 :param list capture: Captured packet stream.
1902 for packet in capture:
1904 self.logger.debug(ppp("Got packet:", packet))
1907 payload_info = self.payload_to_info(packet[Raw])
1908 packet_index = payload_info.index
1909 if packet_index in seen:
1910 raise Exception(ppp("Duplicate packet received", packet))
1911 seen.add(packet_index)
1912 self.assertEqual(payload_info.dst, self.src_dst_if.sw_if_index)
1913 info = self._packet_infos[packet_index]
1914 self.assertIsNotNone(info)
1915 self.assertEqual(packet_index, info.index)
1916 saved_packet = info.data
1917 self.assertEqual(ip.src, saved_packet[IP].dst)
1918 self.assertEqual(ip.dst, saved_packet[IP].src)
1919 self.assertEqual(icmp.type, 0) # echo reply
1920 self.assertEqual(icmp.id, saved_packet[ICMP].id)
1921 self.assertEqual(icmp.payload, saved_packet[ICMP].payload)
1923 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1925 for index in self._packet_infos:
1926 self.assertIn(index, seen,
1927 "Packet with packet_index %d not received" % index)
1929 def test_reassembly(self):
1930 """ basic reassembly """
1932 self.pg_enable_capture()
1933 self.src_dst_if.add_stream(self.fragments_300)
1936 packets = self.src_dst_if.get_capture(len(self.pkt_infos))
1937 self.verify_capture(packets)
1939 # run it all again to verify correctness
1940 self.pg_enable_capture()
1941 self.src_dst_if.add_stream(self.fragments_300)
1944 packets = self.src_dst_if.get_capture(len(self.pkt_infos))
1945 self.verify_capture(packets)
1948 class TestFIFReassembly(VppTestCase):
1949 """ Fragments in fragments reassembly """
1952 def setUpClass(cls):
1953 super(TestFIFReassembly, cls).setUpClass()
1955 cls.create_pg_interfaces([0, 1])
1956 cls.src_if = cls.pg0
1957 cls.dst_if = cls.pg1
1958 for i in cls.pg_interfaces:
1965 cls.packet_sizes = [64, 512, 1518, 9018]
1966 cls.padding = " abcdefghijklmn"
1969 def tearDownClass(cls):
1970 super(TestFIFReassembly, cls).tearDownClass()
1973 """ Test setup - force timeout on existing reassemblies """
1974 super(TestFIFReassembly, self).setUp()
1975 self.vapi.ip_reassembly_enable_disable(
1976 sw_if_index=self.src_if.sw_if_index, enable_ip4=True,
1978 self.vapi.ip_reassembly_enable_disable(
1979 sw_if_index=self.dst_if.sw_if_index, enable_ip4=True,
1981 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
1982 max_reassembly_length=1000,
1983 expire_walk_interval_ms=10)
1984 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
1985 max_reassembly_length=1000,
1986 expire_walk_interval_ms=10, is_ip6=1)
1988 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
1989 max_reassembly_length=1000,
1990 expire_walk_interval_ms=10000)
1991 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
1992 max_reassembly_length=1000,
1993 expire_walk_interval_ms=10000, is_ip6=1)
1996 super(TestFIFReassembly, self).tearDown()
1998 def show_commands_at_teardown(self):
1999 self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details"))
2000 self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details"))
2001 self.logger.debug(self.vapi.ppcli("show buffers"))
2003 def verify_capture(self, capture, ip_class, dropped_packet_indexes=[]):
2004 """Verify captured packet stream.
2006 :param list capture: Captured packet stream.
2010 for packet in capture:
2012 self.logger.debug(ppp("Got packet:", packet))
2013 ip = packet[ip_class]
2015 payload_info = self.payload_to_info(packet[Raw])
2016 packet_index = payload_info.index
2018 packet_index not in dropped_packet_indexes,
2019 ppp("Packet received, but should be dropped:", packet))
2020 if packet_index in seen:
2021 raise Exception(ppp("Duplicate packet received", packet))
2022 seen.add(packet_index)
2023 self.assertEqual(payload_info.dst, self.dst_if.sw_if_index)
2024 info = self._packet_infos[packet_index]
2025 self.assertTrue(info is not None)
2026 self.assertEqual(packet_index, info.index)
2027 saved_packet = info.data
2028 self.assertEqual(ip.src, saved_packet[ip_class].src)
2029 self.assertEqual(ip.dst, saved_packet[ip_class].dst)
2030 self.assertEqual(udp.payload, saved_packet[UDP].payload)
2032 self.logger.error(ppp("Unexpected or invalid packet:", packet))
2034 for index in self._packet_infos:
2035 self.assertTrue(index in seen or index in dropped_packet_indexes,
2036 "Packet with packet_index %d not received" % index)
2038 def test_fif4(self):
2039 """ Fragments in fragments (4o4) """
2041 # TODO this should be ideally in setUpClass, but then we hit a bug
2042 # with VppIpRoute incorrectly reporting it's present when it's not
2043 # so we need to manually remove the vpp config, thus we cannot have
2044 # it shared for multiple test cases
2045 self.tun_ip4 = "1.1.1.2"
2047 self.gre4 = VppGreInterface(self, self.src_if.local_ip4, self.tun_ip4)
2048 self.gre4.add_vpp_config()
2049 self.gre4.admin_up()
2050 self.gre4.config_ip4()
2052 self.vapi.ip_reassembly_enable_disable(
2053 sw_if_index=self.gre4.sw_if_index, enable_ip4=True)
2055 self.route4 = VppIpRoute(self, self.tun_ip4, 32,
2056 [VppRoutePath(self.src_if.remote_ip4,
2057 self.src_if.sw_if_index)])
2058 self.route4.add_vpp_config()
2060 self.reset_packet_infos()
2061 for i in range(test_packet_count):
2062 info = self.create_packet_info(self.src_if, self.dst_if)
2063 payload = self.info_to_payload(info)
2064 # Ethernet header here is only for size calculation, thus it
2065 # doesn't matter how it's initialized. This is to ensure that
2066 # reassembled packet is not > 9000 bytes, so that it's not dropped
2068 IP(id=i, src=self.src_if.remote_ip4,
2069 dst=self.dst_if.remote_ip4) /
2070 UDP(sport=1234, dport=5678) /
2072 size = self.packet_sizes[(i // 2) % len(self.packet_sizes)]
2073 self.extend_packet(p, size, self.padding)
2074 info.data = p[IP] # use only IP part, without ethernet header
2076 fragments = [x for _, p in self._packet_infos.items()
2077 for x in fragment_rfc791(p.data, 400)]
2079 encapped_fragments = \
2080 [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
2081 IP(src=self.tun_ip4, dst=self.src_if.local_ip4) /
2086 fragmented_encapped_fragments = \
2087 [x for p in encapped_fragments
2088 for x in fragment_rfc791(p, 200)]
2090 self.src_if.add_stream(fragmented_encapped_fragments)
2092 self.pg_enable_capture(self.pg_interfaces)
2095 self.src_if.assert_nothing_captured()
2096 packets = self.dst_if.get_capture(len(self._packet_infos))
2097 self.verify_capture(packets, IP)
2099 # TODO remove gre vpp config by hand until VppIpRoute gets fixed
2100 # so that it's query_vpp_config() works as it should
2101 self.gre4.remove_vpp_config()
2102 self.logger.debug(self.vapi.ppcli("show interface"))
2104 def test_fif6(self):
2105 """ Fragments in fragments (6o6) """
2106 # TODO this should be ideally in setUpClass, but then we hit a bug
2107 # with VppIpRoute incorrectly reporting it's present when it's not
2108 # so we need to manually remove the vpp config, thus we cannot have
2109 # it shared for multiple test cases
2110 self.tun_ip6 = "1002::1"
2112 self.gre6 = VppGreInterface(self, self.src_if.local_ip6, self.tun_ip6)
2113 self.gre6.add_vpp_config()
2114 self.gre6.admin_up()
2115 self.gre6.config_ip6()
2117 self.vapi.ip_reassembly_enable_disable(
2118 sw_if_index=self.gre6.sw_if_index, enable_ip6=True)
2120 self.route6 = VppIpRoute(self, self.tun_ip6, 128,
2122 self.src_if.remote_ip6,
2123 self.src_if.sw_if_index)])
2124 self.route6.add_vpp_config()
2126 self.reset_packet_infos()
2127 for i in range(test_packet_count):
2128 info = self.create_packet_info(self.src_if, self.dst_if)
2129 payload = self.info_to_payload(info)
2130 # Ethernet header here is only for size calculation, thus it
2131 # doesn't matter how it's initialized. This is to ensure that
2132 # reassembled packet is not > 9000 bytes, so that it's not dropped
2134 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
2135 UDP(sport=1234, dport=5678) /
2137 size = self.packet_sizes[(i // 2) % len(self.packet_sizes)]
2138 self.extend_packet(p, size, self.padding)
2139 info.data = p[IPv6] # use only IPv6 part, without ethernet header
2141 fragments = [x for _, i in self._packet_infos.items()
2142 for x in fragment_rfc8200(
2143 i.data, i.index, 400)]
2145 encapped_fragments = \
2146 [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
2147 IPv6(src=self.tun_ip6, dst=self.src_if.local_ip6) /
2152 fragmented_encapped_fragments = \
2153 [x for p in encapped_fragments for x in (
2156 2 * len(self._packet_infos) + p[IPv6ExtHdrFragment].id,
2158 if IPv6ExtHdrFragment in p else [p]
2162 self.src_if.add_stream(fragmented_encapped_fragments)
2164 self.pg_enable_capture(self.pg_interfaces)
2167 self.src_if.assert_nothing_captured()
2168 packets = self.dst_if.get_capture(len(self._packet_infos))
2169 self.verify_capture(packets, IPv6)
2171 # TODO remove gre vpp config by hand until VppIpRoute gets fixed
2172 # so that it's query_vpp_config() works as it should
2173 self.gre6.remove_vpp_config()
2176 if __name__ == '__main__':
2177 unittest.main(testRunner=VppTestRunner)