blob: 531caa46257c262adc438804ccacef2fb2c2cb5b [file] [log] [blame]
Klement Sekera75e7d132017-09-20 08:26:30 +02001#!/usr/bin/env python
2import unittest
3from random import shuffle
4
5from framework import VppTestCase, VppTestRunner
6
7from scapy.packet import Raw
8from scapy.layers.l2 import Ether, GRE
9from scapy.layers.inet import IP, UDP
10from util import ppp, fragment_rfc791, fragment_rfc8200
Klement Sekera75e7d132017-09-20 08:26:30 +020011from scapy.layers.inet6 import IPv6, IPv6ExtHdrFragment, ICMPv6ParamProblem,\
12 ICMPv6TimeExceeded
13from vpp_gre_interface import VppGreInterface, VppGre6Interface
14from vpp_ip_route import VppIpRoute, VppRoutePath, DpoProto
15
16test_packet_count = 257
17
18
19class TestIPv4Reassembly(VppTestCase):
20 """ IPv4 Reassembly """
21
22 @classmethod
23 def setUpClass(cls):
24 super(TestIPv4Reassembly, cls).setUpClass()
25
Klement Sekera4c533132018-02-22 11:41:12 +010026 cls.create_pg_interfaces([0, 1])
27 cls.src_if = cls.pg0
28 cls.dst_if = cls.pg1
Klement Sekera75e7d132017-09-20 08:26:30 +020029
30 # setup all interfaces
31 for i in cls.pg_interfaces:
32 i.admin_up()
33 i.config_ip4()
34 i.resolve_arp()
35
Klement Sekera75e7d132017-09-20 08:26:30 +020036 # packet sizes
37 cls.packet_sizes = [64, 512, 1518, 9018]
38 cls.padding = " abcdefghijklmn"
39 cls.create_stream(cls.packet_sizes)
40 cls.create_fragments()
41
42 def setUp(self):
43 """ Test setup - force timeout on existing reassemblies """
44 super(TestIPv4Reassembly, self).setUp()
Klement Sekera4c533132018-02-22 11:41:12 +010045 self.vapi.ip_reassembly_enable_disable(
46 sw_if_index=self.src_if.sw_if_index, enable_ip4=True)
Klement Sekera75e7d132017-09-20 08:26:30 +020047 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
48 expire_walk_interval_ms=10)
49 self.sleep(.25)
50 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
51 expire_walk_interval_ms=10000)
52
53 def tearDown(self):
54 super(TestIPv4Reassembly, self).tearDown()
55 self.logger.debug(self.vapi.ppcli("show ip4-reassembly details"))
56
57 @classmethod
58 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
59 """Create input packet stream for defined interface.
60
61 :param list packet_sizes: Required packet sizes.
62 """
63 for i in range(0, packet_count):
Klement Sekera4c533132018-02-22 11:41:12 +010064 info = cls.create_packet_info(cls.src_if, cls.src_if)
Klement Sekera75e7d132017-09-20 08:26:30 +020065 payload = cls.info_to_payload(info)
Klement Sekera4c533132018-02-22 11:41:12 +010066 p = (Ether(dst=cls.src_if.local_mac, src=cls.src_if.remote_mac) /
67 IP(id=info.index, src=cls.src_if.remote_ip4,
68 dst=cls.dst_if.remote_ip4) /
69 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +020070 Raw(payload))
71 size = packet_sizes[(i // 2) % len(packet_sizes)]
72 cls.extend_packet(p, size, cls.padding)
73 info.data = p
74
75 @classmethod
76 def create_fragments(cls):
77 infos = cls._packet_infos
78 cls.pkt_infos = []
79 for index, info in infos.iteritems():
80 p = info.data
Klement Sekera4c533132018-02-22 11:41:12 +010081 # cls.logger.debug(ppp("Packet:", p.__class__(str(p))))
Klement Sekera75e7d132017-09-20 08:26:30 +020082 fragments_400 = fragment_rfc791(p, 400)
83 fragments_300 = fragment_rfc791(p, 300)
84 fragments_200 = [
85 x for f in fragments_400 for x in fragment_rfc791(f, 200)]
86 cls.pkt_infos.append(
87 (index, fragments_400, fragments_300, fragments_200))
88 cls.fragments_400 = [
89 x for (_, frags, _, _) in cls.pkt_infos for x in frags]
90 cls.fragments_300 = [
91 x for (_, _, frags, _) in cls.pkt_infos for x in frags]
92 cls.fragments_200 = [
93 x for (_, _, _, frags) in cls.pkt_infos for x in frags]
94 cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, "
95 "%s 300-byte fragments and %s 200-byte fragments" %
96 (len(infos), len(cls.fragments_400),
97 len(cls.fragments_300), len(cls.fragments_200)))
98
99 def verify_capture(self, capture, dropped_packet_indexes=[]):
100 """Verify captured packet stream.
101
102 :param list capture: Captured packet stream.
103 """
104 info = None
105 seen = set()
106 for packet in capture:
107 try:
Klement Sekera4c533132018-02-22 11:41:12 +0100108 self.logger.debug(ppp("Got packet:", packet))
Klement Sekera75e7d132017-09-20 08:26:30 +0200109 ip = packet[IP]
110 udp = packet[UDP]
111 payload_info = self.payload_to_info(str(packet[Raw]))
112 packet_index = payload_info.index
113 self.assertTrue(
114 packet_index not in dropped_packet_indexes,
115 ppp("Packet received, but should be dropped:", packet))
116 if packet_index in seen:
117 raise Exception(ppp("Duplicate packet received", packet))
118 seen.add(packet_index)
Klement Sekera4c533132018-02-22 11:41:12 +0100119 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
Klement Sekera75e7d132017-09-20 08:26:30 +0200120 info = self._packet_infos[packet_index]
121 self.assertTrue(info is not None)
122 self.assertEqual(packet_index, info.index)
123 saved_packet = info.data
124 self.assertEqual(ip.src, saved_packet[IP].src)
125 self.assertEqual(ip.dst, saved_packet[IP].dst)
126 self.assertEqual(udp.payload, saved_packet[UDP].payload)
Klement Sekera4c533132018-02-22 11:41:12 +0100127 except Exception:
Klement Sekera75e7d132017-09-20 08:26:30 +0200128 self.logger.error(ppp("Unexpected or invalid packet:", packet))
129 raise
130 for index in self._packet_infos:
131 self.assertTrue(index in seen or index in dropped_packet_indexes,
132 "Packet with packet_index %d not received" % index)
133
134 def test_reassembly(self):
135 """ basic reassembly """
136
137 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100138 self.src_if.add_stream(self.fragments_200)
Klement Sekera75e7d132017-09-20 08:26:30 +0200139 self.pg_start()
140
Klement Sekera4c533132018-02-22 11:41:12 +0100141 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200142 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100143 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200144
145 # run it all again to verify correctness
146 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100147 self.src_if.add_stream(self.fragments_200)
Klement Sekera75e7d132017-09-20 08:26:30 +0200148 self.pg_start()
149
Klement Sekera4c533132018-02-22 11:41:12 +0100150 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200151 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100152 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200153
154 def test_reversed(self):
155 """ reverse order reassembly """
156
157 fragments = list(self.fragments_200)
158 fragments.reverse()
159
160 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100161 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200162 self.pg_start()
163
Klement Sekera4c533132018-02-22 11:41:12 +0100164 packets = self.dst_if.get_capture(len(self.packet_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200165 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100166 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200167
168 # run it all again to verify correctness
169 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100170 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200171 self.pg_start()
172
Klement Sekera4c533132018-02-22 11:41:12 +0100173 packets = self.dst_if.get_capture(len(self.packet_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200174 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100175 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200176
177 def test_random(self):
178 """ random order reassembly """
179
180 fragments = list(self.fragments_200)
181 shuffle(fragments)
182
183 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100184 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200185 self.pg_start()
186
Klement Sekera4c533132018-02-22 11:41:12 +0100187 packets = self.dst_if.get_capture(len(self.packet_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200188 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100189 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200190
191 # run it all again to verify correctness
192 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100193 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200194 self.pg_start()
195
Klement Sekera4c533132018-02-22 11:41:12 +0100196 packets = self.dst_if.get_capture(len(self.packet_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200197 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100198 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200199
200 def test_duplicates(self):
201 """ duplicate fragments """
202
203 fragments = [
204 x for (_, frags, _, _) in self.pkt_infos
205 for x in frags
206 for _ in range(0, min(2, len(frags)))
207 ]
208
209 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100210 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200211 self.pg_start()
212
Klement Sekera4c533132018-02-22 11:41:12 +0100213 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200214 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100215 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200216
217 def test_overlap1(self):
218 """ overlapping fragments case #1 """
219
220 fragments = []
221 for _, _, frags_300, frags_200 in self.pkt_infos:
222 if len(frags_300) == 1:
223 fragments.extend(frags_300)
224 else:
225 for i, j in zip(frags_200, frags_300):
226 fragments.extend(i)
227 fragments.extend(j)
228
229 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100230 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200231 self.pg_start()
232
Klement Sekera4c533132018-02-22 11:41:12 +0100233 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200234 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100235 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200236
237 # run it all to verify correctness
238 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100239 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200240 self.pg_start()
241
Klement Sekera4c533132018-02-22 11:41:12 +0100242 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200243 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100244 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200245
246 def test_overlap2(self):
247 """ overlapping fragments case #2 """
248
249 fragments = []
250 for _, _, frags_300, frags_200 in self.pkt_infos:
251 if len(frags_300) == 1:
252 fragments.extend(frags_300)
253 else:
254 # care must be taken here so that there are no fragments
255 # received by vpp after reassembly is finished, otherwise
256 # new reassemblies will be started and packet generator will
257 # freak out when it detects unfreed buffers
258 zipped = zip(frags_300, frags_200)
259 for i, j in zipped[:-1]:
260 fragments.extend(i)
261 fragments.extend(j)
262 fragments.append(zipped[-1][0])
263
264 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100265 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200266 self.pg_start()
267
Klement Sekera4c533132018-02-22 11:41:12 +0100268 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200269 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100270 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200271
272 # run it all to verify correctness
273 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100274 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200275 self.pg_start()
276
Klement Sekera4c533132018-02-22 11:41:12 +0100277 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200278 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100279 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200280
281 def test_timeout_inline(self):
282 """ timeout (inline) """
283
284 dropped_packet_indexes = set(
285 index for (index, frags, _, _) in self.pkt_infos if len(frags) > 1
286 )
287
288 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
289 expire_walk_interval_ms=10000)
290
291 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100292 self.src_if.add_stream(self.fragments_400)
Klement Sekera75e7d132017-09-20 08:26:30 +0200293 self.pg_start()
294
Klement Sekera4c533132018-02-22 11:41:12 +0100295 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +0200296 len(self.pkt_infos) - len(dropped_packet_indexes))
297 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +0100298 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200299
300 def test_timeout_cleanup(self):
301 """ timeout (cleanup) """
302
303 # whole packets + fragmented packets sans last fragment
304 fragments = [
305 x for (_, frags_400, _, _) in self.pkt_infos
306 for x in frags_400[:-1 if len(frags_400) > 1 else None]
307 ]
308
309 # last fragments for fragmented packets
310 fragments2 = [frags_400[-1]
311 for (_, frags_400, _, _) in self.pkt_infos
312 if len(frags_400) > 1]
313
314 dropped_packet_indexes = set(
315 index for (index, frags_400, _, _) in self.pkt_infos
316 if len(frags_400) > 1)
317
318 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
319 expire_walk_interval_ms=50)
320
321 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100322 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200323 self.pg_start()
324
325 self.sleep(.25, "wait before sending rest of fragments")
326
Klement Sekera4c533132018-02-22 11:41:12 +0100327 self.src_if.add_stream(fragments2)
Klement Sekera75e7d132017-09-20 08:26:30 +0200328 self.pg_start()
Klement Sekera75e7d132017-09-20 08:26:30 +0200329
Klement Sekera4c533132018-02-22 11:41:12 +0100330 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +0200331 len(self.pkt_infos) - len(dropped_packet_indexes))
332 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +0100333 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200334
335 def test_disabled(self):
336 """ reassembly disabled """
337
338 dropped_packet_indexes = set(
339 index for (index, frags_400, _, _) in self.pkt_infos
340 if len(frags_400) > 1)
341
342 self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=0,
343 expire_walk_interval_ms=10000)
344
345 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100346 self.src_if.add_stream(self.fragments_400)
Klement Sekera75e7d132017-09-20 08:26:30 +0200347 self.pg_start()
348
Klement Sekera4c533132018-02-22 11:41:12 +0100349 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +0200350 len(self.pkt_infos) - len(dropped_packet_indexes))
351 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +0100352 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200353
354
355class TestIPv6Reassembly(VppTestCase):
356 """ IPv6 Reassembly """
357
358 @classmethod
359 def setUpClass(cls):
360 super(TestIPv6Reassembly, cls).setUpClass()
361
Klement Sekera4c533132018-02-22 11:41:12 +0100362 cls.create_pg_interfaces([0, 1])
363 cls.src_if = cls.pg0
364 cls.dst_if = cls.pg1
Klement Sekera75e7d132017-09-20 08:26:30 +0200365
366 # setup all interfaces
367 for i in cls.pg_interfaces:
368 i.admin_up()
369 i.config_ip6()
370 i.resolve_ndp()
371
Klement Sekera75e7d132017-09-20 08:26:30 +0200372 # packet sizes
373 cls.packet_sizes = [64, 512, 1518, 9018]
374 cls.padding = " abcdefghijklmn"
375 cls.create_stream(cls.packet_sizes)
376 cls.create_fragments()
377
378 def setUp(self):
379 """ Test setup - force timeout on existing reassemblies """
380 super(TestIPv6Reassembly, self).setUp()
Klement Sekera4c533132018-02-22 11:41:12 +0100381 self.vapi.ip_reassembly_enable_disable(
382 sw_if_index=self.src_if.sw_if_index, enable_ip6=True)
Klement Sekera75e7d132017-09-20 08:26:30 +0200383 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
384 expire_walk_interval_ms=10, is_ip6=1)
385 self.sleep(.25)
386 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
387 expire_walk_interval_ms=10000, is_ip6=1)
Klement Sekera4c533132018-02-22 11:41:12 +0100388 self.logger.debug(self.vapi.ppcli("show ip6-reassembly details"))
Klement Sekera75e7d132017-09-20 08:26:30 +0200389
390 def tearDown(self):
391 super(TestIPv6Reassembly, self).tearDown()
392 self.logger.debug(self.vapi.ppcli("show ip6-reassembly details"))
393
394 @classmethod
395 def create_stream(cls, packet_sizes, packet_count=test_packet_count):
396 """Create input packet stream for defined interface.
397
398 :param list packet_sizes: Required packet sizes.
399 """
400 for i in range(0, packet_count):
Klement Sekera4c533132018-02-22 11:41:12 +0100401 info = cls.create_packet_info(cls.src_if, cls.src_if)
Klement Sekera75e7d132017-09-20 08:26:30 +0200402 payload = cls.info_to_payload(info)
Klement Sekera4c533132018-02-22 11:41:12 +0100403 p = (Ether(dst=cls.src_if.local_mac, src=cls.src_if.remote_mac) /
404 IPv6(src=cls.src_if.remote_ip6,
405 dst=cls.dst_if.remote_ip6) /
406 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +0200407 Raw(payload))
408 size = packet_sizes[(i // 2) % len(packet_sizes)]
409 cls.extend_packet(p, size, cls.padding)
410 info.data = p
411
412 @classmethod
413 def create_fragments(cls):
414 infos = cls._packet_infos
415 cls.pkt_infos = []
416 for index, info in infos.iteritems():
417 p = info.data
Klement Sekera4c533132018-02-22 11:41:12 +0100418 # cls.logger.debug(ppp("Packet:", p.__class__(str(p))))
Klement Sekera75e7d132017-09-20 08:26:30 +0200419 fragments_400 = fragment_rfc8200(p, info.index, 400)
420 fragments_300 = fragment_rfc8200(p, info.index, 300)
421 cls.pkt_infos.append((index, fragments_400, fragments_300))
422 cls.fragments_400 = [
423 x for _, frags, _ in cls.pkt_infos for x in frags]
424 cls.fragments_300 = [
425 x for _, _, frags in cls.pkt_infos for x in frags]
426 cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, "
427 "and %s 300-byte fragments" %
428 (len(infos), len(cls.fragments_400),
429 len(cls.fragments_300)))
430
431 def verify_capture(self, capture, dropped_packet_indexes=[]):
432 """Verify captured packet strea .
433
434 :param list capture: Captured packet stream.
435 """
436 info = None
437 seen = set()
438 for packet in capture:
439 try:
Klement Sekera4c533132018-02-22 11:41:12 +0100440 self.logger.debug(ppp("Got packet:", packet))
Klement Sekera75e7d132017-09-20 08:26:30 +0200441 ip = packet[IPv6]
442 udp = packet[UDP]
443 payload_info = self.payload_to_info(str(packet[Raw]))
444 packet_index = payload_info.index
445 self.assertTrue(
446 packet_index not in dropped_packet_indexes,
447 ppp("Packet received, but should be dropped:", packet))
448 if packet_index in seen:
449 raise Exception(ppp("Duplicate packet received", packet))
450 seen.add(packet_index)
Klement Sekera4c533132018-02-22 11:41:12 +0100451 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
Klement Sekera75e7d132017-09-20 08:26:30 +0200452 info = self._packet_infos[packet_index]
453 self.assertTrue(info is not None)
454 self.assertEqual(packet_index, info.index)
455 saved_packet = info.data
456 self.assertEqual(ip.src, saved_packet[IPv6].src)
457 self.assertEqual(ip.dst, saved_packet[IPv6].dst)
458 self.assertEqual(udp.payload, saved_packet[UDP].payload)
Klement Sekera4c533132018-02-22 11:41:12 +0100459 except Exception:
Klement Sekera75e7d132017-09-20 08:26:30 +0200460 self.logger.error(ppp("Unexpected or invalid packet:", packet))
461 raise
462 for index in self._packet_infos:
463 self.assertTrue(index in seen or index in dropped_packet_indexes,
464 "Packet with packet_index %d not received" % index)
465
466 def test_reassembly(self):
467 """ basic reassembly """
468
469 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100470 self.src_if.add_stream(self.fragments_400)
Klement Sekera75e7d132017-09-20 08:26:30 +0200471 self.pg_start()
472
Klement Sekera4c533132018-02-22 11:41:12 +0100473 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200474 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100475 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200476
477 # run it all again to verify correctness
478 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100479 self.src_if.add_stream(self.fragments_400)
Klement Sekera75e7d132017-09-20 08:26:30 +0200480 self.pg_start()
481
Klement Sekera4c533132018-02-22 11:41:12 +0100482 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200483 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100484 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200485
486 def test_reversed(self):
487 """ reverse order reassembly """
488
489 fragments = list(self.fragments_400)
490 fragments.reverse()
491
492 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100493 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200494 self.pg_start()
495
Klement Sekera4c533132018-02-22 11:41:12 +0100496 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200497 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100498 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200499
500 # run it all again to verify correctness
501 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100502 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200503 self.pg_start()
504
Klement Sekera4c533132018-02-22 11:41:12 +0100505 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200506 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100507 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200508
509 def test_random(self):
510 """ random order reassembly """
511
512 fragments = list(self.fragments_400)
513 shuffle(fragments)
514
515 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100516 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200517 self.pg_start()
518
Klement Sekera4c533132018-02-22 11:41:12 +0100519 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200520 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100521 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200522
523 # run it all again to verify correctness
524 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100525 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200526 self.pg_start()
527
Klement Sekera4c533132018-02-22 11:41:12 +0100528 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200529 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100530 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200531
532 def test_duplicates(self):
533 """ duplicate fragments """
534
535 fragments = [
536 x for (_, frags, _) in self.pkt_infos
537 for x in frags
538 for _ in range(0, min(2, len(frags)))
539 ]
540
541 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100542 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200543 self.pg_start()
544
Klement Sekera4c533132018-02-22 11:41:12 +0100545 packets = self.dst_if.get_capture(len(self.pkt_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200546 self.verify_capture(packets)
Klement Sekera4c533132018-02-22 11:41:12 +0100547 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200548
549 def test_overlap1(self):
550 """ overlapping fragments case #1 """
551
552 fragments = []
553 for _, frags_400, frags_300 in self.pkt_infos:
554 if len(frags_300) == 1:
555 fragments.extend(frags_400)
556 else:
557 for i, j in zip(frags_300, frags_400):
558 fragments.extend(i)
559 fragments.extend(j)
560
561 dropped_packet_indexes = set(
562 index for (index, _, frags) in self.pkt_infos if len(frags) > 1
563 )
564
565 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100566 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200567 self.pg_start()
568
Klement Sekera4c533132018-02-22 11:41:12 +0100569 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +0200570 len(self.pkt_infos) - len(dropped_packet_indexes))
571 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +0100572 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200573
574 def test_overlap2(self):
575 """ overlapping fragments case #2 """
576
577 fragments = []
Klement Sekera4c533132018-02-22 11:41:12 +0100578 for _, frags_400, frags_300 in self.pkt_infos:
Klement Sekera75e7d132017-09-20 08:26:30 +0200579 if len(frags_400) == 1:
580 fragments.extend(frags_400)
581 else:
582 # care must be taken here so that there are no fragments
583 # received by vpp after reassembly is finished, otherwise
584 # new reassemblies will be started and packet generator will
585 # freak out when it detects unfreed buffers
Klement Sekera4c533132018-02-22 11:41:12 +0100586 zipped = zip(frags_400, frags_300)
Klement Sekera75e7d132017-09-20 08:26:30 +0200587 for i, j in zipped[:-1]:
588 fragments.extend(i)
589 fragments.extend(j)
590 fragments.append(zipped[-1][0])
591
592 dropped_packet_indexes = set(
593 index for (index, _, frags) in self.pkt_infos if len(frags) > 1
594 )
595
596 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100597 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200598 self.pg_start()
599
Klement Sekera4c533132018-02-22 11:41:12 +0100600 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +0200601 len(self.pkt_infos) - len(dropped_packet_indexes))
602 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +0100603 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200604
605 def test_timeout_inline(self):
606 """ timeout (inline) """
607
608 dropped_packet_indexes = set(
609 index for (index, frags, _) in self.pkt_infos if len(frags) > 1
610 )
611
612 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
613 expire_walk_interval_ms=10000, is_ip6=1)
614
615 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100616 self.src_if.add_stream(self.fragments_400)
Klement Sekera75e7d132017-09-20 08:26:30 +0200617 self.pg_start()
618
Klement Sekera4c533132018-02-22 11:41:12 +0100619 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +0200620 len(self.pkt_infos) - len(dropped_packet_indexes))
621 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +0100622 pkts = self.src_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +0200623 expected_count=len(dropped_packet_indexes))
624 for icmp in pkts:
625 self.assertIn(ICMPv6TimeExceeded, icmp)
626 self.assertIn(IPv6ExtHdrFragment, icmp)
627 self.assertIn(icmp[IPv6ExtHdrFragment].id, dropped_packet_indexes)
628 dropped_packet_indexes.remove(icmp[IPv6ExtHdrFragment].id)
629
630 def test_timeout_cleanup(self):
631 """ timeout (cleanup) """
632
633 # whole packets + fragmented packets sans last fragment
634 fragments = [
635 x for (_, frags_400, _) in self.pkt_infos
636 for x in frags_400[:-1 if len(frags_400) > 1 else None]
637 ]
638
639 # last fragments for fragmented packets
640 fragments2 = [frags_400[-1]
641 for (_, frags_400, _) in self.pkt_infos
642 if len(frags_400) > 1]
643
644 dropped_packet_indexes = set(
645 index for (index, frags_400, _) in self.pkt_infos
646 if len(frags_400) > 1)
647
648 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
649 expire_walk_interval_ms=50)
650
651 self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
652 expire_walk_interval_ms=50, is_ip6=1)
653
654 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100655 self.src_if.add_stream(fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200656 self.pg_start()
657
658 self.sleep(.25, "wait before sending rest of fragments")
659
Klement Sekera4c533132018-02-22 11:41:12 +0100660 self.src_if.add_stream(fragments2)
Klement Sekera75e7d132017-09-20 08:26:30 +0200661 self.pg_start()
Klement Sekera75e7d132017-09-20 08:26:30 +0200662
Klement Sekera4c533132018-02-22 11:41:12 +0100663 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +0200664 len(self.pkt_infos) - len(dropped_packet_indexes))
665 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +0100666 pkts = self.src_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +0200667 expected_count=len(dropped_packet_indexes))
668 for icmp in pkts:
669 self.assertIn(ICMPv6TimeExceeded, icmp)
670 self.assertIn(IPv6ExtHdrFragment, icmp)
671 self.assertIn(icmp[IPv6ExtHdrFragment].id, dropped_packet_indexes)
672 dropped_packet_indexes.remove(icmp[IPv6ExtHdrFragment].id)
673
674 def test_disabled(self):
675 """ reassembly disabled """
676
677 dropped_packet_indexes = set(
678 index for (index, frags_400, _) in self.pkt_infos
679 if len(frags_400) > 1)
680
681 self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=0,
682 expire_walk_interval_ms=10000, is_ip6=1)
683
684 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100685 self.src_if.add_stream(self.fragments_400)
Klement Sekera75e7d132017-09-20 08:26:30 +0200686 self.pg_start()
687
Klement Sekera4c533132018-02-22 11:41:12 +0100688 packets = self.dst_if.get_capture(
Klement Sekera75e7d132017-09-20 08:26:30 +0200689 len(self.pkt_infos) - len(dropped_packet_indexes))
690 self.verify_capture(packets, dropped_packet_indexes)
Klement Sekera4c533132018-02-22 11:41:12 +0100691 self.src_if.assert_nothing_captured()
Klement Sekera75e7d132017-09-20 08:26:30 +0200692
693 def test_missing_upper(self):
694 """ missing upper layer """
Klement Sekera4c533132018-02-22 11:41:12 +0100695 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
696 IPv6(src=self.src_if.remote_ip6,
697 dst=self.src_if.local_ip6) /
698 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +0200699 Raw())
700 self.extend_packet(p, 1000, self.padding)
701 fragments = fragment_rfc8200(p, 1, 500)
702 bad_fragment = p.__class__(str(fragments[1]))
703 bad_fragment[IPv6ExtHdrFragment].nh = 59
704 bad_fragment[IPv6ExtHdrFragment].offset = 0
705 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100706 self.src_if.add_stream([bad_fragment])
Klement Sekera75e7d132017-09-20 08:26:30 +0200707 self.pg_start()
Klement Sekera4c533132018-02-22 11:41:12 +0100708 pkts = self.src_if.get_capture(expected_count=1)
Klement Sekera75e7d132017-09-20 08:26:30 +0200709 icmp = pkts[0]
710 self.assertIn(ICMPv6ParamProblem, icmp)
711 self.assert_equal(icmp[ICMPv6ParamProblem].code, 3, "ICMP code")
712
713 def test_invalid_frag_size(self):
714 """ fragment size not a multiple of 8 """
Klement Sekera4c533132018-02-22 11:41:12 +0100715 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
716 IPv6(src=self.src_if.remote_ip6,
717 dst=self.src_if.local_ip6) /
718 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +0200719 Raw())
720 self.extend_packet(p, 1000, self.padding)
721 fragments = fragment_rfc8200(p, 1, 500)
722 bad_fragment = fragments[0]
723 self.extend_packet(bad_fragment, len(bad_fragment) + 5)
724 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100725 self.src_if.add_stream([bad_fragment])
Klement Sekera75e7d132017-09-20 08:26:30 +0200726 self.pg_start()
Klement Sekera4c533132018-02-22 11:41:12 +0100727 pkts = self.src_if.get_capture(expected_count=1)
Klement Sekera75e7d132017-09-20 08:26:30 +0200728 icmp = pkts[0]
729 self.assertIn(ICMPv6ParamProblem, icmp)
730 self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code")
731
732 def test_invalid_packet_size(self):
733 """ total packet size > 65535 """
Klement Sekera4c533132018-02-22 11:41:12 +0100734 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
735 IPv6(src=self.src_if.remote_ip6,
736 dst=self.src_if.local_ip6) /
737 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +0200738 Raw())
739 self.extend_packet(p, 1000, self.padding)
740 fragments = fragment_rfc8200(p, 1, 500)
741 bad_fragment = fragments[1]
742 bad_fragment[IPv6ExtHdrFragment].offset = 65500
743 self.pg_enable_capture()
Klement Sekera4c533132018-02-22 11:41:12 +0100744 self.src_if.add_stream([bad_fragment])
Klement Sekera75e7d132017-09-20 08:26:30 +0200745 self.pg_start()
Klement Sekera4c533132018-02-22 11:41:12 +0100746 pkts = self.src_if.get_capture(expected_count=1)
Klement Sekera75e7d132017-09-20 08:26:30 +0200747 icmp = pkts[0]
748 self.assertIn(ICMPv6ParamProblem, icmp)
749 self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code")
750
751
Klement Sekera4c533132018-02-22 11:41:12 +0100752@unittest.skip("removing GRE tunnels broken, need fix")
Klement Sekera75e7d132017-09-20 08:26:30 +0200753class TestFIFReassembly(VppTestCase):
754 """ Fragments in fragments reassembly """
755
756 @classmethod
757 def setUpClass(cls):
758 super(TestFIFReassembly, cls).setUpClass()
759
Klement Sekera4c533132018-02-22 11:41:12 +0100760 cls.create_pg_interfaces([0, 1])
761 cls.src_if = cls.pg0
762 cls.dst_if = cls.pg1
763 for i in cls.pg_interfaces:
764 i.admin_up()
765 i.config_ip4()
766 i.resolve_arp()
767 i.config_ip6()
768 i.resolve_ndp()
Klement Sekera75e7d132017-09-20 08:26:30 +0200769
Klement Sekera75e7d132017-09-20 08:26:30 +0200770 cls.packet_sizes = [64, 512, 1518, 9018]
771 cls.padding = " abcdefghijklmn"
772
773 def setUp(self):
774 """ Test setup - force timeout on existing reassemblies """
775 super(TestFIFReassembly, self).setUp()
Klement Sekera4c533132018-02-22 11:41:12 +0100776 self.vapi.ip_reassembly_enable_disable(
777 sw_if_index=self.src_if.sw_if_index, enable_ip4=True,
778 enable_ip6=True)
779 self.vapi.ip_reassembly_enable_disable(
780 sw_if_index=self.dst_if.sw_if_index, enable_ip4=True,
781 enable_ip6=True)
Klement Sekera75e7d132017-09-20 08:26:30 +0200782 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
783 expire_walk_interval_ms=10)
784 self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
785 expire_walk_interval_ms=10, is_ip6=1)
786 self.sleep(.25)
787 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
788 expire_walk_interval_ms=10000)
789 self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
790 expire_walk_interval_ms=10000, is_ip6=1)
791
792 def tearDown(self):
793 self.logger.debug(self.vapi.ppcli("show ip4-reassembly details"))
794 self.logger.debug(self.vapi.ppcli("show ip6-reassembly details"))
795 super(TestFIFReassembly, self).tearDown()
796
797 def verify_capture(self, capture, ip_class, dropped_packet_indexes=[]):
798 """Verify captured packet stream.
799
800 :param list capture: Captured packet stream.
801 """
802 info = None
803 seen = set()
804 for packet in capture:
805 try:
Klement Sekera4c533132018-02-22 11:41:12 +0100806 self.logger.debug(ppp("Got packet:", packet))
Klement Sekera75e7d132017-09-20 08:26:30 +0200807 ip = packet[ip_class]
808 udp = packet[UDP]
809 payload_info = self.payload_to_info(str(packet[Raw]))
810 packet_index = payload_info.index
811 self.assertTrue(
812 packet_index not in dropped_packet_indexes,
813 ppp("Packet received, but should be dropped:", packet))
814 if packet_index in seen:
815 raise Exception(ppp("Duplicate packet received", packet))
816 seen.add(packet_index)
Klement Sekera4c533132018-02-22 11:41:12 +0100817 self.assertEqual(payload_info.dst, self.dst_if.sw_if_index)
Klement Sekera75e7d132017-09-20 08:26:30 +0200818 info = self._packet_infos[packet_index]
819 self.assertTrue(info is not None)
820 self.assertEqual(packet_index, info.index)
821 saved_packet = info.data
822 self.assertEqual(ip.src, saved_packet[ip_class].src)
823 self.assertEqual(ip.dst, saved_packet[ip_class].dst)
824 self.assertEqual(udp.payload, saved_packet[UDP].payload)
Klement Sekera4c533132018-02-22 11:41:12 +0100825 except Exception:
Klement Sekera75e7d132017-09-20 08:26:30 +0200826 self.logger.error(ppp("Unexpected or invalid packet:", packet))
827 raise
828 for index in self._packet_infos:
829 self.assertTrue(index in seen or index in dropped_packet_indexes,
830 "Packet with packet_index %d not received" % index)
831
832 def test_fif4(self):
833 """ Fragments in fragments (4o4) """
834
835 # TODO this should be ideally in setUpClass, but then we hit a bug
836 # with VppIpRoute incorrectly reporting it's present when it's not
837 # so we need to manually remove the vpp config, thus we cannot have
838 # it shared for multiple test cases
839 self.tun_ip4 = "1.1.1.2"
840
Klement Sekera4c533132018-02-22 11:41:12 +0100841 self.gre4 = VppGreInterface(self, self.src_if.local_ip4, self.tun_ip4)
Klement Sekera75e7d132017-09-20 08:26:30 +0200842 self.gre4.add_vpp_config()
843 self.gre4.admin_up()
844 self.gre4.config_ip4()
845
Klement Sekera4c533132018-02-22 11:41:12 +0100846 self.vapi.ip_reassembly_enable_disable(
847 sw_if_index=self.gre4.sw_if_index, enable_ip4=True)
848
Klement Sekera75e7d132017-09-20 08:26:30 +0200849 self.route4 = VppIpRoute(self, self.tun_ip4, 32,
Klement Sekera4c533132018-02-22 11:41:12 +0100850 [VppRoutePath(self.src_if.remote_ip4,
851 self.src_if.sw_if_index)])
Klement Sekera75e7d132017-09-20 08:26:30 +0200852 self.route4.add_vpp_config()
853
854 self.reset_packet_infos()
855 for i in range(test_packet_count):
Klement Sekera4c533132018-02-22 11:41:12 +0100856 info = self.create_packet_info(self.src_if, self.dst_if)
Klement Sekera75e7d132017-09-20 08:26:30 +0200857 payload = self.info_to_payload(info)
Klement Sekera4c533132018-02-22 11:41:12 +0100858 # Ethernet header here is only for size calculation, thus it
859 # doesn't matter how it's initialized. This is to ensure that
860 # reassembled packet is not > 9000 bytes, so that it's not dropped
861 p = (Ether() /
862 IP(id=i, src=self.src_if.remote_ip4,
863 dst=self.dst_if.remote_ip4) /
864 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +0200865 Raw(payload))
866 size = self.packet_sizes[(i // 2) % len(self.packet_sizes)]
867 self.extend_packet(p, size, self.padding)
Klement Sekera4c533132018-02-22 11:41:12 +0100868 info.data = p[IP] # use only IP part, without ethernet header
Klement Sekera75e7d132017-09-20 08:26:30 +0200869
870 fragments = [x for _, p in self._packet_infos.iteritems()
871 for x in fragment_rfc791(p.data, 400)]
872
873 encapped_fragments = \
Klement Sekera4c533132018-02-22 11:41:12 +0100874 [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
875 IP(src=self.tun_ip4, dst=self.src_if.local_ip4) /
Klement Sekera75e7d132017-09-20 08:26:30 +0200876 GRE() /
877 p
878 for p in fragments]
879
880 fragmented_encapped_fragments = \
881 [x for p in encapped_fragments
882 for x in fragment_rfc791(p, 200)]
883
Klement Sekera4c533132018-02-22 11:41:12 +0100884 self.src_if.add_stream(fragmented_encapped_fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200885
886 self.pg_enable_capture(self.pg_interfaces)
887 self.pg_start()
888
Klement Sekera4c533132018-02-22 11:41:12 +0100889 self.src_if.assert_nothing_captured()
890 packets = self.dst_if.get_capture(len(self._packet_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200891 self.verify_capture(packets, IP)
892
893 # TODO remove gre vpp config by hand until VppIpRoute gets fixed
894 # so that it's query_vpp_config() works as it should
895 self.gre4.remove_vpp_config()
Klement Sekera4c533132018-02-22 11:41:12 +0100896 self.logger.debug(self.vapi.ppcli("show interface"))
Klement Sekera75e7d132017-09-20 08:26:30 +0200897
898 def test_fif6(self):
899 """ Fragments in fragments (6o6) """
900 # TODO this should be ideally in setUpClass, but then we hit a bug
901 # with VppIpRoute incorrectly reporting it's present when it's not
902 # so we need to manually remove the vpp config, thus we cannot have
903 # it shared for multiple test cases
904 self.tun_ip6 = "1002::1"
905
Klement Sekera4c533132018-02-22 11:41:12 +0100906 self.gre6 = VppGre6Interface(self, self.src_if.local_ip6, self.tun_ip6)
Klement Sekera75e7d132017-09-20 08:26:30 +0200907 self.gre6.add_vpp_config()
908 self.gre6.admin_up()
909 self.gre6.config_ip6()
910
Klement Sekera4c533132018-02-22 11:41:12 +0100911 self.vapi.ip_reassembly_enable_disable(
912 sw_if_index=self.gre6.sw_if_index, enable_ip6=True)
913
Klement Sekera75e7d132017-09-20 08:26:30 +0200914 self.route6 = VppIpRoute(self, self.tun_ip6, 128,
Klement Sekera4c533132018-02-22 11:41:12 +0100915 [VppRoutePath(self.src_if.remote_ip6,
916 self.src_if.sw_if_index,
Klement Sekera75e7d132017-09-20 08:26:30 +0200917 proto=DpoProto.DPO_PROTO_IP6)],
918 is_ip6=1)
919 self.route6.add_vpp_config()
920
921 self.reset_packet_infos()
922 for i in range(test_packet_count):
Klement Sekera4c533132018-02-22 11:41:12 +0100923 info = self.create_packet_info(self.src_if, self.dst_if)
Klement Sekera75e7d132017-09-20 08:26:30 +0200924 payload = self.info_to_payload(info)
Klement Sekera4c533132018-02-22 11:41:12 +0100925 # Ethernet header here is only for size calculation, thus it
926 # doesn't matter how it's initialized. This is to ensure that
927 # reassembled packet is not > 9000 bytes, so that it's not dropped
928 p = (Ether() /
929 IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
930 UDP(sport=1234, dport=5678) /
Klement Sekera75e7d132017-09-20 08:26:30 +0200931 Raw(payload))
932 size = self.packet_sizes[(i // 2) % len(self.packet_sizes)]
933 self.extend_packet(p, size, self.padding)
Klement Sekera4c533132018-02-22 11:41:12 +0100934 info.data = p[IPv6] # use only IPv6 part, without ethernet header
Klement Sekera75e7d132017-09-20 08:26:30 +0200935
936 fragments = [x for _, i in self._packet_infos.iteritems()
937 for x in fragment_rfc8200(
938 i.data, i.index, 400)]
939
940 encapped_fragments = \
Klement Sekera4c533132018-02-22 11:41:12 +0100941 [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
942 IPv6(src=self.tun_ip6, dst=self.src_if.local_ip6) /
Klement Sekera75e7d132017-09-20 08:26:30 +0200943 GRE() /
944 p
945 for p in fragments]
946
947 fragmented_encapped_fragments = \
948 [x for p in encapped_fragments for x in (
949 fragment_rfc8200(
950 p,
951 2 * len(self._packet_infos) + p[IPv6ExtHdrFragment].id,
952 200)
953 if IPv6ExtHdrFragment in p else [p]
954 )
955 ]
956
Klement Sekera4c533132018-02-22 11:41:12 +0100957 self.src_if.add_stream(fragmented_encapped_fragments)
Klement Sekera75e7d132017-09-20 08:26:30 +0200958
959 self.pg_enable_capture(self.pg_interfaces)
960 self.pg_start()
961
Klement Sekera4c533132018-02-22 11:41:12 +0100962 self.src_if.assert_nothing_captured()
963 packets = self.dst_if.get_capture(len(self._packet_infos))
Klement Sekera75e7d132017-09-20 08:26:30 +0200964 self.verify_capture(packets, IPv6)
965
966 # TODO remove gre vpp config by hand until VppIpRoute gets fixed
967 # so that it's query_vpp_config() works as it should
Klement Sekera4c533132018-02-22 11:41:12 +0100968 # self.gre6.remove_vpp_config()
Klement Sekera75e7d132017-09-20 08:26:30 +0200969
970
971if __name__ == '__main__':
972 unittest.main(testRunner=VppTestRunner)