tests: Revert "Tests: Example duplicate code refactoring."
[vpp.git] / test / test_reassembly.py
1 #!/usr/bin/env python
2
3 import six
4 import unittest
5 from random import shuffle
6
7 from framework import VppTestCase, VppTestRunner
8
9 import scapy.compat
10 from scapy.packet import Raw
11 from scapy.layers.l2 import Ether, GRE
12 from scapy.layers.inet import IP, UDP, ICMP
13 from util import ppp, fragment_rfc791, fragment_rfc8200
14 from scapy.layers.inet6 import IPv6, IPv6ExtHdrFragment, ICMPv6ParamProblem,\
15     ICMPv6TimeExceeded
16 from framework import VppTestCase, VppTestRunner
17 from util import ppp, fragment_rfc791, fragment_rfc8200
18 from vpp_gre_interface import VppGreInterface
19 from vpp_ip import DpoProto
20 from vpp_ip_route import VppIpRoute, VppRoutePath, FibPathProto
21
22 # 35 is enough to have >257 400-byte fragments
23 test_packet_count = 35
24
25
26 class TestIPv4Reassembly(VppTestCase):
27     """ IPv4 Reassembly """
28
29     @classmethod
30     def setUpClass(cls):
31         super(TestIPv4Reassembly, cls).setUpClass()
32
33         cls.create_pg_interfaces([0, 1])
34         cls.src_if = cls.pg0
35         cls.dst_if = cls.pg1
36
37         # setup all interfaces
38         for i in cls.pg_interfaces:
39             i.admin_up()
40             i.config_ip4()
41             i.resolve_arp()
42
43         # packet sizes
44         cls.packet_sizes = [64, 512, 1518, 9018]
45         cls.padding = " abcdefghijklmn"
46         cls.create_stream(cls.packet_sizes)
47         cls.create_fragments()
48
49     @classmethod
50     def tearDownClass(cls):
51         super(TestIPv4Reassembly, cls).tearDownClass()
52
53     def setUp(self):
54         """ Test setup - force timeout on existing reassemblies """
55         super(TestIPv4Reassembly, self).setUp()
56         self.vapi.ip_reassembly_enable_disable(
57             sw_if_index=self.src_if.sw_if_index, enable_ip4=True)
58         self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
59                                     max_reassembly_length=1000,
60                                     expire_walk_interval_ms=10)
61         self.sleep(.25)
62         self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
63                                     max_reassembly_length=1000,
64                                     expire_walk_interval_ms=10000)
65
66     def tearDown(self):
67         super(TestIPv4Reassembly, self).tearDown()
68
69     def show_commands_at_teardown(self):
70         self.logger.debug(self.vapi.ppcli("show ip4-reassembly details"))
71         self.logger.debug(self.vapi.ppcli("show buffers"))
72
73     @classmethod
74     def create_stream(cls, packet_sizes, packet_count=test_packet_count):
75         """Create input packet stream
76
77         :param list packet_sizes: Required packet sizes.
78         """
79         for i in range(0, packet_count):
80             info = cls.create_packet_info(cls.src_if, cls.src_if)
81             payload = cls.info_to_payload(info)
82             p = (Ether(dst=cls.src_if.local_mac, src=cls.src_if.remote_mac) /
83                  IP(id=info.index, src=cls.src_if.remote_ip4,
84                     dst=cls.dst_if.remote_ip4) /
85                  UDP(sport=1234, dport=5678) /
86                  Raw(payload))
87             size = packet_sizes[(i // 2) % len(packet_sizes)]
88             cls.extend_packet(p, size, cls.padding)
89             info.data = p
90
91     @classmethod
92     def create_fragments(cls):
93         infos = cls._packet_infos
94         cls.pkt_infos = []
95         for index, info in six.iteritems(infos):
96             p = info.data
97             # cls.logger.debug(ppp("Packet:",
98             #                      p.__class__(scapy.compat.raw(p))))
99             fragments_400 = fragment_rfc791(p, 400)
100             fragments_300 = fragment_rfc791(p, 300)
101             fragments_200 = [
102                 x for f in fragments_400 for x in fragment_rfc791(f, 200)]
103             cls.pkt_infos.append(
104                 (index, fragments_400, fragments_300, fragments_200))
105         cls.fragments_400 = [
106             x for (_, frags, _, _) in cls.pkt_infos for x in frags]
107         cls.fragments_300 = [
108             x for (_, _, frags, _) in cls.pkt_infos for x in frags]
109         cls.fragments_200 = [
110             x for (_, _, _, frags) in cls.pkt_infos for x in frags]
111         cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, "
112                          "%s 300-byte fragments and %s 200-byte fragments" %
113                          (len(infos), len(cls.fragments_400),
114                              len(cls.fragments_300), len(cls.fragments_200)))
115
116     def verify_capture(self, capture, dropped_packet_indexes=[]):
117         """Verify captured packet stream.
118
119         :param list capture: Captured packet stream.
120         """
121         info = None
122         seen = set()
123         for packet in capture:
124             try:
125                 self.logger.debug(ppp("Got packet:", packet))
126                 ip = packet[IP]
127                 udp = packet[UDP]
128                 payload_info = self.payload_to_info(packet[Raw])
129                 packet_index = payload_info.index
130                 self.assertTrue(
131                     packet_index not in dropped_packet_indexes,
132                     ppp("Packet received, but should be dropped:", packet))
133                 if packet_index in seen:
134                     raise Exception(ppp("Duplicate packet received", packet))
135                 seen.add(packet_index)
136                 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
137                 info = self._packet_infos[packet_index]
138                 self.assertTrue(info is not None)
139                 self.assertEqual(packet_index, info.index)
140                 saved_packet = info.data
141                 self.assertEqual(ip.src, saved_packet[IP].src)
142                 self.assertEqual(ip.dst, saved_packet[IP].dst)
143                 self.assertEqual(udp.payload, saved_packet[UDP].payload)
144             except Exception:
145                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
146                 raise
147         for index in self._packet_infos:
148             self.assertTrue(index in seen or index in dropped_packet_indexes,
149                             "Packet with packet_index %d not received" % index)
150
151     def test_reassembly(self):
152         """ basic reassembly """
153
154         self.pg_enable_capture()
155         self.src_if.add_stream(self.fragments_200)
156         self.pg_start()
157
158         packets = self.dst_if.get_capture(len(self.pkt_infos))
159         self.verify_capture(packets)
160         self.src_if.assert_nothing_captured()
161
162         # run it all again to verify correctness
163         self.pg_enable_capture()
164         self.src_if.add_stream(self.fragments_200)
165         self.pg_start()
166
167         packets = self.dst_if.get_capture(len(self.pkt_infos))
168         self.verify_capture(packets)
169         self.src_if.assert_nothing_captured()
170
171     def test_reversed(self):
172         """ reverse order reassembly """
173
174         fragments = list(self.fragments_200)
175         fragments.reverse()
176
177         self.pg_enable_capture()
178         self.src_if.add_stream(fragments)
179         self.pg_start()
180
181         packets = self.dst_if.get_capture(len(self.packet_infos))
182         self.verify_capture(packets)
183         self.src_if.assert_nothing_captured()
184
185         # run it all again to verify correctness
186         self.pg_enable_capture()
187         self.src_if.add_stream(fragments)
188         self.pg_start()
189
190         packets = self.dst_if.get_capture(len(self.packet_infos))
191         self.verify_capture(packets)
192         self.src_if.assert_nothing_captured()
193
194     def test_long_fragment_chain(self):
195         """ long fragment chain """
196
197         error_cnt_str = \
198             "/err/ip4-reassembly-feature/fragment chain too long (drop)"
199
200         error_cnt = self.statistics.get_err_counter(error_cnt_str)
201
202         self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
203                                     max_reassembly_length=3,
204                                     expire_walk_interval_ms=50)
205
206         p1 = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
207               IP(id=1000, src=self.src_if.remote_ip4,
208                  dst=self.dst_if.remote_ip4) /
209               UDP(sport=1234, dport=5678) /
210               Raw("X" * 1000))
211         p2 = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
212               IP(id=1001, src=self.src_if.remote_ip4,
213                  dst=self.dst_if.remote_ip4) /
214               UDP(sport=1234, dport=5678) /
215               Raw("X" * 1000))
216         frags = fragment_rfc791(p1, 200) + fragment_rfc791(p2, 500)
217
218         self.pg_enable_capture()
219         self.src_if.add_stream(frags)
220         self.pg_start()
221
222         self.dst_if.get_capture(1)
223         self.assert_error_counter_equal(error_cnt_str, error_cnt + 1)
224
225     def test_5737(self):
226         """ fragment length + ip header size > 65535 """
227         self.vapi.cli("clear errors")
228         raw = ('E\x00\x00\x88,\xf8\x1f\xfe@\x01\x98\x00\xc0\xa8\n-\xc0\xa8\n'
229                '\x01\x08\x00\xf0J\xed\xcb\xf1\xf5Test-group: IPv4.IPv4.ipv4-'
230                'message.Ethernet-Payload.IPv4-Packet.IPv4-Header.Fragment-Of'
231                'fset; Test-case: 5737')
232
233         malformed_packet = (Ether(dst=self.src_if.local_mac,
234                                   src=self.src_if.remote_mac) /
235                             IP(raw))
236         p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
237              IP(id=1000, src=self.src_if.remote_ip4,
238                 dst=self.dst_if.remote_ip4) /
239              UDP(sport=1234, dport=5678) /
240              Raw("X" * 1000))
241         valid_fragments = fragment_rfc791(p, 400)
242
243         self.pg_enable_capture()
244         self.src_if.add_stream([malformed_packet] + valid_fragments)
245         self.pg_start()
246
247         self.dst_if.get_capture(1)
248         self.assert_packet_counter_equal("ip4-reassembly-feature", 1)
249         # TODO remove above, uncomment below once clearing of counters
250         # is supported
251         # self.assert_packet_counter_equal(
252         #     "/err/ip4-reassembly-feature/malformed packets", 1)
253
254     def test_44924(self):
255         """ compress tiny fragments """
256         packets = [(Ether(dst=self.src_if.local_mac,
257                           src=self.src_if.remote_mac) /
258                     IP(id=24339, flags="MF", frag=0, ttl=64,
259                        src=self.src_if.remote_ip4,
260                        dst=self.dst_if.remote_ip4) /
261                     ICMP(type="echo-request", code=0, id=0x1fe6, seq=0x2407) /
262                     Raw(load='Test-group: IPv4')),
263                    (Ether(dst=self.src_if.local_mac,
264                           src=self.src_if.remote_mac) /
265                     IP(id=24339, flags="MF", frag=3, ttl=64,
266                        src=self.src_if.remote_ip4,
267                        dst=self.dst_if.remote_ip4) /
268                     ICMP(type="echo-request", code=0, id=0x1fe6, seq=0x2407) /
269                     Raw(load='.IPv4.Fragmentation.vali')),
270                    (Ether(dst=self.src_if.local_mac,
271                           src=self.src_if.remote_mac) /
272                     IP(id=24339, frag=6, ttl=64,
273                        src=self.src_if.remote_ip4,
274                        dst=self.dst_if.remote_ip4) /
275                     ICMP(type="echo-request", code=0, id=0x1fe6, seq=0x2407) /
276                     Raw(load='d; Test-case: 44924'))
277                    ]
278
279         self.pg_enable_capture()
280         self.src_if.add_stream(packets)
281         self.pg_start()
282
283         self.dst_if.get_capture(1)
284
285     def test_frag_1(self):
286         """ fragment of size 1 """
287         self.vapi.cli("clear errors")
288         malformed_packets = [(Ether(dst=self.src_if.local_mac,
289                                     src=self.src_if.remote_mac) /
290                               IP(id=7, len=21, flags="MF", frag=0, ttl=64,
291                                  src=self.src_if.remote_ip4,
292                                  dst=self.dst_if.remote_ip4) /
293                               ICMP(type="echo-request")),
294                              (Ether(dst=self.src_if.local_mac,
295                                     src=self.src_if.remote_mac) /
296                               IP(id=7, len=21, frag=1, ttl=64,
297                                  src=self.src_if.remote_ip4,
298                                  dst=self.dst_if.remote_ip4) /
299                               Raw(load='\x08')),
300                              ]
301
302         p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
303              IP(id=1000, src=self.src_if.remote_ip4,
304                 dst=self.dst_if.remote_ip4) /
305              UDP(sport=1234, dport=5678) /
306              Raw("X" * 1000))
307         valid_fragments = fragment_rfc791(p, 400)
308
309         self.pg_enable_capture()
310         self.src_if.add_stream(malformed_packets + valid_fragments)
311         self.pg_start()
312
313         self.dst_if.get_capture(1)
314
315         self.assert_packet_counter_equal("ip4-reassembly-feature", 1)
316         # TODO remove above, uncomment below once clearing of counters
317         # is supported
318         # self.assert_packet_counter_equal(
319         #     "/err/ip4-reassembly-feature/malformed packets", 1)
320
321     def test_random(self):
322         """ random order reassembly """
323
324         fragments = list(self.fragments_200)
325         shuffle(fragments)
326
327         self.pg_enable_capture()
328         self.src_if.add_stream(fragments)
329         self.pg_start()
330
331         packets = self.dst_if.get_capture(len(self.packet_infos))
332         self.verify_capture(packets)
333         self.src_if.assert_nothing_captured()
334
335         # run it all again to verify correctness
336         self.pg_enable_capture()
337         self.src_if.add_stream(fragments)
338         self.pg_start()
339
340         packets = self.dst_if.get_capture(len(self.packet_infos))
341         self.verify_capture(packets)
342         self.src_if.assert_nothing_captured()
343
344     def test_duplicates(self):
345         """ duplicate fragments """
346
347         fragments = [
348             x for (_, frags, _, _) in self.pkt_infos
349             for x in frags
350             for _ in range(0, min(2, len(frags)))
351         ]
352
353         self.pg_enable_capture()
354         self.src_if.add_stream(fragments)
355         self.pg_start()
356
357         packets = self.dst_if.get_capture(len(self.pkt_infos))
358         self.verify_capture(packets)
359         self.src_if.assert_nothing_captured()
360
361     def test_overlap1(self):
362         """ overlapping fragments case #1 """
363
364         fragments = []
365         for _, _, frags_300, frags_200 in self.pkt_infos:
366             if len(frags_300) == 1:
367                 fragments.extend(frags_300)
368             else:
369                 for i, j in zip(frags_200, frags_300):
370                     fragments.extend(i)
371                     fragments.extend(j)
372
373         self.pg_enable_capture()
374         self.src_if.add_stream(fragments)
375         self.pg_start()
376
377         packets = self.dst_if.get_capture(len(self.pkt_infos))
378         self.verify_capture(packets)
379         self.src_if.assert_nothing_captured()
380
381         # run it all to verify correctness
382         self.pg_enable_capture()
383         self.src_if.add_stream(fragments)
384         self.pg_start()
385
386         packets = self.dst_if.get_capture(len(self.pkt_infos))
387         self.verify_capture(packets)
388         self.src_if.assert_nothing_captured()
389
390     def test_overlap2(self):
391         """ overlapping fragments case #2 """
392
393         fragments = []
394         for _, _, frags_300, frags_200 in self.pkt_infos:
395             if len(frags_300) == 1:
396                 fragments.extend(frags_300)
397             else:
398                 # care must be taken here so that there are no fragments
399                 # received by vpp after reassembly is finished, otherwise
400                 # new reassemblies will be started and packet generator will
401                 # freak out when it detects unfreed buffers
402                 zipped = zip(frags_300, frags_200)
403                 for i, j in zipped:
404                     fragments.extend(i)
405                     fragments.extend(j)
406                 fragments.pop()
407
408         self.pg_enable_capture()
409         self.src_if.add_stream(fragments)
410         self.pg_start()
411
412         packets = self.dst_if.get_capture(len(self.pkt_infos))
413         self.verify_capture(packets)
414         self.src_if.assert_nothing_captured()
415
416         # run it all to verify correctness
417         self.pg_enable_capture()
418         self.src_if.add_stream(fragments)
419         self.pg_start()
420
421         packets = self.dst_if.get_capture(len(self.pkt_infos))
422         self.verify_capture(packets)
423         self.src_if.assert_nothing_captured()
424
425     def test_timeout_inline(self):
426         """ timeout (inline) """
427
428         dropped_packet_indexes = set(
429             index for (index, frags, _, _) in self.pkt_infos if len(frags) > 1
430         )
431
432         self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
433                                     max_reassembly_length=3,
434                                     expire_walk_interval_ms=10000)
435
436         self.pg_enable_capture()
437         self.src_if.add_stream(self.fragments_400)
438         self.pg_start()
439
440         packets = self.dst_if.get_capture(
441             len(self.pkt_infos) - len(dropped_packet_indexes))
442         self.verify_capture(packets, dropped_packet_indexes)
443         self.src_if.assert_nothing_captured()
444
445     def test_timeout_cleanup(self):
446         """ timeout (cleanup) """
447
448         # whole packets + fragmented packets sans last fragment
449         fragments = [
450             x for (_, frags_400, _, _) in self.pkt_infos
451             for x in frags_400[:-1 if len(frags_400) > 1 else None]
452         ]
453
454         # last fragments for fragmented packets
455         fragments2 = [frags_400[-1]
456                       for (_, frags_400, _, _) in self.pkt_infos
457                       if len(frags_400) > 1]
458
459         dropped_packet_indexes = set(
460             index for (index, frags_400, _, _) in self.pkt_infos
461             if len(frags_400) > 1)
462
463         self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
464                                     max_reassembly_length=1000,
465                                     expire_walk_interval_ms=50)
466
467         self.pg_enable_capture()
468         self.src_if.add_stream(fragments)
469         self.pg_start()
470
471         self.sleep(.25, "wait before sending rest of fragments")
472
473         self.src_if.add_stream(fragments2)
474         self.pg_start()
475
476         packets = self.dst_if.get_capture(
477             len(self.pkt_infos) - len(dropped_packet_indexes))
478         self.verify_capture(packets, dropped_packet_indexes)
479         self.src_if.assert_nothing_captured()
480
481     def test_disabled(self):
482         """ reassembly disabled """
483
484         dropped_packet_indexes = set(
485             index for (index, frags_400, _, _) in self.pkt_infos
486             if len(frags_400) > 1)
487
488         self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=0,
489                                     max_reassembly_length=3,
490                                     expire_walk_interval_ms=10000)
491
492         self.pg_enable_capture()
493         self.src_if.add_stream(self.fragments_400)
494         self.pg_start()
495
496         packets = self.dst_if.get_capture(
497             len(self.pkt_infos) - len(dropped_packet_indexes))
498         self.verify_capture(packets, dropped_packet_indexes)
499         self.src_if.assert_nothing_captured()
500
501
502 class TestIPv6Reassembly(VppTestCase):
503     """ IPv6 Reassembly """
504
505     @classmethod
506     def setUpClass(cls):
507         super(TestIPv6Reassembly, cls).setUpClass()
508
509         cls.create_pg_interfaces([0, 1])
510         cls.src_if = cls.pg0
511         cls.dst_if = cls.pg1
512
513         # setup all interfaces
514         for i in cls.pg_interfaces:
515             i.admin_up()
516             i.config_ip6()
517             i.resolve_ndp()
518
519         # packet sizes
520         cls.packet_sizes = [64, 512, 1518, 9018]
521         cls.padding = " abcdefghijklmn"
522         cls.create_stream(cls.packet_sizes)
523         cls.create_fragments()
524
525     @classmethod
526     def tearDownClass(cls):
527         super(TestIPv6Reassembly, cls).tearDownClass()
528
529     def setUp(self):
530         """ Test setup - force timeout on existing reassemblies """
531         super(TestIPv6Reassembly, self).setUp()
532         self.vapi.ip_reassembly_enable_disable(
533             sw_if_index=self.src_if.sw_if_index, enable_ip6=True)
534         self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
535                                     max_reassembly_length=1000,
536                                     expire_walk_interval_ms=10, is_ip6=1)
537         self.sleep(.25)
538         self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
539                                     max_reassembly_length=1000,
540                                     expire_walk_interval_ms=10000, is_ip6=1)
541         self.logger.debug(self.vapi.ppcli("show ip6-reassembly details"))
542         self.logger.debug(self.vapi.ppcli("show buffers"))
543
544     def tearDown(self):
545         super(TestIPv6Reassembly, self).tearDown()
546
547     def show_commands_at_teardown(self):
548         self.logger.debug(self.vapi.ppcli("show ip6-reassembly details"))
549         self.logger.debug(self.vapi.ppcli("show buffers"))
550
551     @classmethod
552     def create_stream(cls, packet_sizes, packet_count=test_packet_count):
553         """Create input packet stream for defined interface.
554
555         :param list packet_sizes: Required packet sizes.
556         """
557         for i in range(0, packet_count):
558             info = cls.create_packet_info(cls.src_if, cls.src_if)
559             payload = cls.info_to_payload(info)
560             p = (Ether(dst=cls.src_if.local_mac, src=cls.src_if.remote_mac) /
561                  IPv6(src=cls.src_if.remote_ip6,
562                       dst=cls.dst_if.remote_ip6) /
563                  UDP(sport=1234, dport=5678) /
564                  Raw(payload))
565             size = packet_sizes[(i // 2) % len(packet_sizes)]
566             cls.extend_packet(p, size, cls.padding)
567             info.data = p
568
569     @classmethod
570     def create_fragments(cls):
571         infos = cls._packet_infos
572         cls.pkt_infos = []
573         for index, info in six.iteritems(infos):
574             p = info.data
575             # cls.logger.debug(ppp("Packet:",
576             #                      p.__class__(scapy.compat.raw(p))))
577             fragments_400 = fragment_rfc8200(p, info.index, 400)
578             fragments_300 = fragment_rfc8200(p, info.index, 300)
579             cls.pkt_infos.append((index, fragments_400, fragments_300))
580         cls.fragments_400 = [
581             x for _, frags, _ in cls.pkt_infos for x in frags]
582         cls.fragments_300 = [
583             x for _, _, frags in cls.pkt_infos for x in frags]
584         cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, "
585                          "and %s 300-byte fragments" %
586                          (len(infos), len(cls.fragments_400),
587                              len(cls.fragments_300)))
588
589     def verify_capture(self, capture, dropped_packet_indexes=[]):
590         """Verify captured packet strea .
591
592         :param list capture: Captured packet stream.
593         """
594         info = None
595         seen = set()
596         for packet in capture:
597             try:
598                 self.logger.debug(ppp("Got packet:", packet))
599                 ip = packet[IPv6]
600                 udp = packet[UDP]
601                 payload_info = self.payload_to_info(packet[Raw])
602                 packet_index = payload_info.index
603                 self.assertTrue(
604                     packet_index not in dropped_packet_indexes,
605                     ppp("Packet received, but should be dropped:", packet))
606                 if packet_index in seen:
607                     raise Exception(ppp("Duplicate packet received", packet))
608                 seen.add(packet_index)
609                 self.assertEqual(payload_info.dst, self.src_if.sw_if_index)
610                 info = self._packet_infos[packet_index]
611                 self.assertTrue(info is not None)
612                 self.assertEqual(packet_index, info.index)
613                 saved_packet = info.data
614                 self.assertEqual(ip.src, saved_packet[IPv6].src)
615                 self.assertEqual(ip.dst, saved_packet[IPv6].dst)
616                 self.assertEqual(udp.payload, saved_packet[UDP].payload)
617             except Exception:
618                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
619                 raise
620         for index in self._packet_infos:
621             self.assertTrue(index in seen or index in dropped_packet_indexes,
622                             "Packet with packet_index %d not received" % index)
623
624     def test_reassembly(self):
625         """ basic reassembly """
626
627         self.pg_enable_capture()
628         self.src_if.add_stream(self.fragments_400)
629         self.pg_start()
630
631         packets = self.dst_if.get_capture(len(self.pkt_infos))
632         self.verify_capture(packets)
633         self.src_if.assert_nothing_captured()
634
635         # run it all again to verify correctness
636         self.pg_enable_capture()
637         self.src_if.add_stream(self.fragments_400)
638         self.pg_start()
639
640         packets = self.dst_if.get_capture(len(self.pkt_infos))
641         self.verify_capture(packets)
642         self.src_if.assert_nothing_captured()
643
644     def test_reversed(self):
645         """ reverse order reassembly """
646
647         fragments = list(self.fragments_400)
648         fragments.reverse()
649
650         self.pg_enable_capture()
651         self.src_if.add_stream(fragments)
652         self.pg_start()
653
654         packets = self.dst_if.get_capture(len(self.pkt_infos))
655         self.verify_capture(packets)
656         self.src_if.assert_nothing_captured()
657
658         # run it all again to verify correctness
659         self.pg_enable_capture()
660         self.src_if.add_stream(fragments)
661         self.pg_start()
662
663         packets = self.dst_if.get_capture(len(self.pkt_infos))
664         self.verify_capture(packets)
665         self.src_if.assert_nothing_captured()
666
667     def test_random(self):
668         """ random order reassembly """
669
670         fragments = list(self.fragments_400)
671         shuffle(fragments)
672
673         self.pg_enable_capture()
674         self.src_if.add_stream(fragments)
675         self.pg_start()
676
677         packets = self.dst_if.get_capture(len(self.pkt_infos))
678         self.verify_capture(packets)
679         self.src_if.assert_nothing_captured()
680
681         # run it all again to verify correctness
682         self.pg_enable_capture()
683         self.src_if.add_stream(fragments)
684         self.pg_start()
685
686         packets = self.dst_if.get_capture(len(self.pkt_infos))
687         self.verify_capture(packets)
688         self.src_if.assert_nothing_captured()
689
690     def test_duplicates(self):
691         """ duplicate fragments """
692
693         fragments = [
694             x for (_, frags, _) in self.pkt_infos
695             for x in frags
696             for _ in range(0, min(2, len(frags)))
697         ]
698
699         self.pg_enable_capture()
700         self.src_if.add_stream(fragments)
701         self.pg_start()
702
703         packets = self.dst_if.get_capture(len(self.pkt_infos))
704         self.verify_capture(packets)
705         self.src_if.assert_nothing_captured()
706
707     def test_long_fragment_chain(self):
708         """ long fragment chain """
709
710         error_cnt_str = \
711             "/err/ip6-reassembly-feature/fragment chain too long (drop)"
712
713         error_cnt = self.statistics.get_err_counter(error_cnt_str)
714
715         self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
716                                     max_reassembly_length=3,
717                                     expire_walk_interval_ms=50, is_ip6=1)
718
719         p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
720              IPv6(src=self.src_if.remote_ip6,
721                   dst=self.dst_if.remote_ip6) /
722              UDP(sport=1234, dport=5678) /
723              Raw("X" * 1000))
724         frags = fragment_rfc8200(p, 1, 300) + fragment_rfc8200(p, 2, 500)
725
726         self.pg_enable_capture()
727         self.src_if.add_stream(frags)
728         self.pg_start()
729
730         self.dst_if.get_capture(1)
731         self.assert_error_counter_equal(error_cnt_str, error_cnt + 1)
732
733     def test_overlap1(self):
734         """ overlapping fragments case #1 """
735
736         fragments = []
737         for _, frags_400, frags_300 in self.pkt_infos:
738             if len(frags_300) == 1:
739                 fragments.extend(frags_400)
740             else:
741                 for i, j in zip(frags_300, frags_400):
742                     fragments.extend(i)
743                     fragments.extend(j)
744
745         dropped_packet_indexes = set(
746             index for (index, _, frags) in self.pkt_infos if len(frags) > 1
747         )
748
749         self.pg_enable_capture()
750         self.src_if.add_stream(fragments)
751         self.pg_start()
752
753         packets = self.dst_if.get_capture(
754             len(self.pkt_infos) - len(dropped_packet_indexes))
755         self.verify_capture(packets, dropped_packet_indexes)
756         self.src_if.assert_nothing_captured()
757
758     def test_overlap2(self):
759         """ overlapping fragments case #2 """
760
761         fragments = []
762         for _, frags_400, frags_300 in self.pkt_infos:
763             if len(frags_400) == 1:
764                 fragments.extend(frags_400)
765             else:
766                 # care must be taken here so that there are no fragments
767                 # received by vpp after reassembly is finished, otherwise
768                 # new reassemblies will be started and packet generator will
769                 # freak out when it detects unfreed buffers
770                 zipped = zip(frags_400, frags_300)
771                 for i, j in zipped:
772                     fragments.extend(i)
773                     fragments.extend(j)
774                 fragments.pop()
775
776         dropped_packet_indexes = set(
777             index for (index, _, frags) in self.pkt_infos if len(frags) > 1
778         )
779
780         self.pg_enable_capture()
781         self.src_if.add_stream(fragments)
782         self.pg_start()
783
784         packets = self.dst_if.get_capture(
785             len(self.pkt_infos) - len(dropped_packet_indexes))
786         self.verify_capture(packets, dropped_packet_indexes)
787         self.src_if.assert_nothing_captured()
788
789     def test_timeout_inline(self):
790         """ timeout (inline) """
791
792         dropped_packet_indexes = set(
793             index for (index, frags, _) in self.pkt_infos if len(frags) > 1
794         )
795
796         self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
797                                     max_reassembly_length=3,
798                                     expire_walk_interval_ms=10000, is_ip6=1)
799
800         self.pg_enable_capture()
801         self.src_if.add_stream(self.fragments_400)
802         self.pg_start()
803
804         packets = self.dst_if.get_capture(
805             len(self.pkt_infos) - len(dropped_packet_indexes))
806         self.verify_capture(packets, dropped_packet_indexes)
807         pkts = self.src_if.get_capture(
808             expected_count=len(dropped_packet_indexes))
809         for icmp in pkts:
810             self.assertIn(ICMPv6TimeExceeded, icmp)
811             self.assertIn(IPv6ExtHdrFragment, icmp)
812             self.assertIn(icmp[IPv6ExtHdrFragment].id, dropped_packet_indexes)
813             dropped_packet_indexes.remove(icmp[IPv6ExtHdrFragment].id)
814
815     def test_timeout_cleanup(self):
816         """ timeout (cleanup) """
817
818         # whole packets + fragmented packets sans last fragment
819         fragments = [
820             x for (_, frags_400, _) in self.pkt_infos
821             for x in frags_400[:-1 if len(frags_400) > 1 else None]
822         ]
823
824         # last fragments for fragmented packets
825         fragments2 = [frags_400[-1]
826                       for (_, frags_400, _) in self.pkt_infos
827                       if len(frags_400) > 1]
828
829         dropped_packet_indexes = set(
830             index for (index, frags_400, _) in self.pkt_infos
831             if len(frags_400) > 1)
832
833         self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
834                                     max_reassembly_length=1000,
835                                     expire_walk_interval_ms=50)
836
837         self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000,
838                                     max_reassembly_length=1000,
839                                     expire_walk_interval_ms=50, is_ip6=1)
840
841         self.pg_enable_capture()
842         self.src_if.add_stream(fragments)
843         self.pg_start()
844
845         self.sleep(.25, "wait before sending rest of fragments")
846
847         self.src_if.add_stream(fragments2)
848         self.pg_start()
849
850         packets = self.dst_if.get_capture(
851             len(self.pkt_infos) - len(dropped_packet_indexes))
852         self.verify_capture(packets, dropped_packet_indexes)
853         pkts = self.src_if.get_capture(
854             expected_count=len(dropped_packet_indexes))
855         for icmp in pkts:
856             self.assertIn(ICMPv6TimeExceeded, icmp)
857             self.assertIn(IPv6ExtHdrFragment, icmp)
858             self.assertIn(icmp[IPv6ExtHdrFragment].id, dropped_packet_indexes)
859             dropped_packet_indexes.remove(icmp[IPv6ExtHdrFragment].id)
860
861     def test_disabled(self):
862         """ reassembly disabled """
863
864         dropped_packet_indexes = set(
865             index for (index, frags_400, _) in self.pkt_infos
866             if len(frags_400) > 1)
867
868         self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=0,
869                                     max_reassembly_length=3,
870                                     expire_walk_interval_ms=10000, is_ip6=1)
871
872         self.pg_enable_capture()
873         self.src_if.add_stream(self.fragments_400)
874         self.pg_start()
875
876         packets = self.dst_if.get_capture(
877             len(self.pkt_infos) - len(dropped_packet_indexes))
878         self.verify_capture(packets, dropped_packet_indexes)
879         self.src_if.assert_nothing_captured()
880
881     def test_missing_upper(self):
882         """ missing upper layer """
883         p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
884              IPv6(src=self.src_if.remote_ip6,
885                   dst=self.src_if.local_ip6) /
886              UDP(sport=1234, dport=5678) /
887              Raw())
888         self.extend_packet(p, 1000, self.padding)
889         fragments = fragment_rfc8200(p, 1, 500)
890         bad_fragment = p.__class__(scapy.compat.raw(fragments[1]))
891         bad_fragment[IPv6ExtHdrFragment].nh = 59
892         bad_fragment[IPv6ExtHdrFragment].offset = 0
893         self.pg_enable_capture()
894         self.src_if.add_stream([bad_fragment])
895         self.pg_start()
896         pkts = self.src_if.get_capture(expected_count=1)
897         icmp = pkts[0]
898         self.assertIn(ICMPv6ParamProblem, icmp)
899         self.assert_equal(icmp[ICMPv6ParamProblem].code, 3, "ICMP code")
900
901     def test_invalid_frag_size(self):
902         """ fragment size not a multiple of 8 """
903         p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
904              IPv6(src=self.src_if.remote_ip6,
905                   dst=self.src_if.local_ip6) /
906              UDP(sport=1234, dport=5678) /
907              Raw())
908         self.extend_packet(p, 1000, self.padding)
909         fragments = fragment_rfc8200(p, 1, 500)
910         bad_fragment = fragments[0]
911         self.extend_packet(bad_fragment, len(bad_fragment) + 5)
912         self.pg_enable_capture()
913         self.src_if.add_stream([bad_fragment])
914         self.pg_start()
915         pkts = self.src_if.get_capture(expected_count=1)
916         icmp = pkts[0]
917         self.assertIn(ICMPv6ParamProblem, icmp)
918         self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code")
919
920     def test_invalid_packet_size(self):
921         """ total packet size > 65535 """
922         p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
923              IPv6(src=self.src_if.remote_ip6,
924                   dst=self.src_if.local_ip6) /
925              UDP(sport=1234, dport=5678) /
926              Raw())
927         self.extend_packet(p, 1000, self.padding)
928         fragments = fragment_rfc8200(p, 1, 500)
929         bad_fragment = fragments[1]
930         bad_fragment[IPv6ExtHdrFragment].offset = 65500
931         self.pg_enable_capture()
932         self.src_if.add_stream([bad_fragment])
933         self.pg_start()
934         pkts = self.src_if.get_capture(expected_count=1)
935         icmp = pkts[0]
936         self.assertIn(ICMPv6ParamProblem, icmp)
937         self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code")
938
939
940 class TestIPv4ReassemblyLocalNode(VppTestCase):
941     """ IPv4 Reassembly for packets coming to ip4-local node """
942
943     @classmethod
944     def setUpClass(cls):
945         super(TestIPv4ReassemblyLocalNode, cls).setUpClass()
946
947         cls.create_pg_interfaces([0])
948         cls.src_dst_if = cls.pg0
949
950         # setup all interfaces
951         for i in cls.pg_interfaces:
952             i.admin_up()
953             i.config_ip4()
954             i.resolve_arp()
955
956         cls.padding = " abcdefghijklmn"
957         cls.create_stream()
958         cls.create_fragments()
959
960     @classmethod
961     def tearDownClass(cls):
962         super(TestIPv4ReassemblyLocalNode, cls).tearDownClass()
963
964     def setUp(self):
965         """ Test setup - force timeout on existing reassemblies """
966         super(TestIPv4ReassemblyLocalNode, self).setUp()
967         self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
968                                     max_reassembly_length=1000,
969                                     expire_walk_interval_ms=10)
970         self.sleep(.25)
971         self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
972                                     max_reassembly_length=1000,
973                                     expire_walk_interval_ms=10000)
974
975     def tearDown(self):
976         super(TestIPv4ReassemblyLocalNode, self).tearDown()
977
978     def show_commands_at_teardown(self):
979         self.logger.debug(self.vapi.ppcli("show ip4-reassembly details"))
980         self.logger.debug(self.vapi.ppcli("show buffers"))
981
982     @classmethod
983     def create_stream(cls, packet_count=test_packet_count):
984         """Create input packet stream for defined interface.
985
986         :param list packet_sizes: Required packet sizes.
987         """
988         for i in range(0, packet_count):
989             info = cls.create_packet_info(cls.src_dst_if, cls.src_dst_if)
990             payload = cls.info_to_payload(info)
991             p = (Ether(dst=cls.src_dst_if.local_mac,
992                        src=cls.src_dst_if.remote_mac) /
993                  IP(id=info.index, src=cls.src_dst_if.remote_ip4,
994                     dst=cls.src_dst_if.local_ip4) /
995                  ICMP(type='echo-request', id=1234) /
996                  Raw(payload))
997             cls.extend_packet(p, 1518, cls.padding)
998             info.data = p
999
1000     @classmethod
1001     def create_fragments(cls):
1002         infos = cls._packet_infos
1003         cls.pkt_infos = []
1004         for index, info in six.iteritems(infos):
1005             p = info.data
1006             # cls.logger.debug(ppp("Packet:",
1007             #                      p.__class__(scapy.compat.raw(p))))
1008             fragments_300 = fragment_rfc791(p, 300)
1009             cls.pkt_infos.append((index, fragments_300))
1010         cls.fragments_300 = [x for (_, frags) in cls.pkt_infos for x in frags]
1011         cls.logger.debug("Fragmented %s packets into %s 300-byte fragments" %
1012                          (len(infos), len(cls.fragments_300)))
1013
1014     def verify_capture(self, capture):
1015         """Verify captured packet stream.
1016
1017         :param list capture: Captured packet stream.
1018         """
1019         info = None
1020         seen = set()
1021         for packet in capture:
1022             try:
1023                 self.logger.debug(ppp("Got packet:", packet))
1024                 ip = packet[IP]
1025                 icmp = packet[ICMP]
1026                 payload_info = self.payload_to_info(packet[Raw])
1027                 packet_index = payload_info.index
1028                 if packet_index in seen:
1029                     raise Exception(ppp("Duplicate packet received", packet))
1030                 seen.add(packet_index)
1031                 self.assertEqual(payload_info.dst, self.src_dst_if.sw_if_index)
1032                 info = self._packet_infos[packet_index]
1033                 self.assertIsNotNone(info)
1034                 self.assertEqual(packet_index, info.index)
1035                 saved_packet = info.data
1036                 self.assertEqual(ip.src, saved_packet[IP].dst)
1037                 self.assertEqual(ip.dst, saved_packet[IP].src)
1038                 self.assertEqual(icmp.type, 0)  # echo reply
1039                 self.assertEqual(icmp.id, saved_packet[ICMP].id)
1040                 self.assertEqual(icmp.payload, saved_packet[ICMP].payload)
1041             except Exception:
1042                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1043                 raise
1044         for index in self._packet_infos:
1045             self.assertIn(index, seen,
1046                           "Packet with packet_index %d not received" % index)
1047
1048     def test_reassembly(self):
1049         """ basic reassembly """
1050
1051         self.pg_enable_capture()
1052         self.src_dst_if.add_stream(self.fragments_300)
1053         self.pg_start()
1054
1055         packets = self.src_dst_if.get_capture(len(self.pkt_infos))
1056         self.verify_capture(packets)
1057
1058         # run it all again to verify correctness
1059         self.pg_enable_capture()
1060         self.src_dst_if.add_stream(self.fragments_300)
1061         self.pg_start()
1062
1063         packets = self.src_dst_if.get_capture(len(self.pkt_infos))
1064         self.verify_capture(packets)
1065
1066
1067 class TestFIFReassembly(VppTestCase):
1068     """ Fragments in fragments reassembly """
1069
1070     @classmethod
1071     def setUpClass(cls):
1072         super(TestFIFReassembly, cls).setUpClass()
1073
1074         cls.create_pg_interfaces([0, 1])
1075         cls.src_if = cls.pg0
1076         cls.dst_if = cls.pg1
1077         for i in cls.pg_interfaces:
1078             i.admin_up()
1079             i.config_ip4()
1080             i.resolve_arp()
1081             i.config_ip6()
1082             i.resolve_ndp()
1083
1084         cls.packet_sizes = [64, 512, 1518, 9018]
1085         cls.padding = " abcdefghijklmn"
1086
1087     @classmethod
1088     def tearDownClass(cls):
1089         super(TestFIFReassembly, cls).tearDownClass()
1090
1091     def setUp(self):
1092         """ Test setup - force timeout on existing reassemblies """
1093         super(TestFIFReassembly, self).setUp()
1094         self.vapi.ip_reassembly_enable_disable(
1095             sw_if_index=self.src_if.sw_if_index, enable_ip4=True,
1096             enable_ip6=True)
1097         self.vapi.ip_reassembly_enable_disable(
1098             sw_if_index=self.dst_if.sw_if_index, enable_ip4=True,
1099             enable_ip6=True)
1100         self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
1101                                     max_reassembly_length=1000,
1102                                     expire_walk_interval_ms=10)
1103         self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000,
1104                                     max_reassembly_length=1000,
1105                                     expire_walk_interval_ms=10, is_ip6=1)
1106         self.sleep(.25)
1107         self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
1108                                     max_reassembly_length=1000,
1109                                     expire_walk_interval_ms=10000)
1110         self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000,
1111                                     max_reassembly_length=1000,
1112                                     expire_walk_interval_ms=10000, is_ip6=1)
1113
1114     def tearDown(self):
1115         super(TestFIFReassembly, self).tearDown()
1116
1117     def show_commands_at_teardown(self):
1118         self.logger.debug(self.vapi.ppcli("show ip4-reassembly details"))
1119         self.logger.debug(self.vapi.ppcli("show ip6-reassembly details"))
1120         self.logger.debug(self.vapi.ppcli("show buffers"))
1121
1122     def verify_capture(self, capture, ip_class, dropped_packet_indexes=[]):
1123         """Verify captured packet stream.
1124
1125         :param list capture: Captured packet stream.
1126         """
1127         info = None
1128         seen = set()
1129         for packet in capture:
1130             try:
1131                 self.logger.debug(ppp("Got packet:", packet))
1132                 ip = packet[ip_class]
1133                 udp = packet[UDP]
1134                 payload_info = self.payload_to_info(packet[Raw])
1135                 packet_index = payload_info.index
1136                 self.assertTrue(
1137                     packet_index not in dropped_packet_indexes,
1138                     ppp("Packet received, but should be dropped:", packet))
1139                 if packet_index in seen:
1140                     raise Exception(ppp("Duplicate packet received", packet))
1141                 seen.add(packet_index)
1142                 self.assertEqual(payload_info.dst, self.dst_if.sw_if_index)
1143                 info = self._packet_infos[packet_index]
1144                 self.assertTrue(info is not None)
1145                 self.assertEqual(packet_index, info.index)
1146                 saved_packet = info.data
1147                 self.assertEqual(ip.src, saved_packet[ip_class].src)
1148                 self.assertEqual(ip.dst, saved_packet[ip_class].dst)
1149                 self.assertEqual(udp.payload, saved_packet[UDP].payload)
1150             except Exception:
1151                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1152                 raise
1153         for index in self._packet_infos:
1154             self.assertTrue(index in seen or index in dropped_packet_indexes,
1155                             "Packet with packet_index %d not received" % index)
1156
1157     def test_fif4(self):
1158         """ Fragments in fragments (4o4) """
1159
1160         # TODO this should be ideally in setUpClass, but then we hit a bug
1161         # with VppIpRoute incorrectly reporting it's present when it's not
1162         # so we need to manually remove the vpp config, thus we cannot have
1163         # it shared for multiple test cases
1164         self.tun_ip4 = "1.1.1.2"
1165
1166         self.gre4 = VppGreInterface(self, self.src_if.local_ip4, self.tun_ip4)
1167         self.gre4.add_vpp_config()
1168         self.gre4.admin_up()
1169         self.gre4.config_ip4()
1170
1171         self.vapi.ip_reassembly_enable_disable(
1172             sw_if_index=self.gre4.sw_if_index, enable_ip4=True)
1173
1174         self.route4 = VppIpRoute(self, self.tun_ip4, 32,
1175                                  [VppRoutePath(self.src_if.remote_ip4,
1176                                                self.src_if.sw_if_index)])
1177         self.route4.add_vpp_config()
1178
1179         self.reset_packet_infos()
1180         for i in range(test_packet_count):
1181             info = self.create_packet_info(self.src_if, self.dst_if)
1182             payload = self.info_to_payload(info)
1183             # Ethernet header here is only for size calculation, thus it
1184             # doesn't matter how it's initialized. This is to ensure that
1185             # reassembled packet is not > 9000 bytes, so that it's not dropped
1186             p = (Ether() /
1187                  IP(id=i, src=self.src_if.remote_ip4,
1188                     dst=self.dst_if.remote_ip4) /
1189                  UDP(sport=1234, dport=5678) /
1190                  Raw(payload))
1191             size = self.packet_sizes[(i // 2) % len(self.packet_sizes)]
1192             self.extend_packet(p, size, self.padding)
1193             info.data = p[IP]  # use only IP part, without ethernet header
1194
1195         fragments = [x for _, p in six.iteritems(self._packet_infos)
1196                      for x in fragment_rfc791(p.data, 400)]
1197
1198         encapped_fragments = \
1199             [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1200              IP(src=self.tun_ip4, dst=self.src_if.local_ip4) /
1201                 GRE() /
1202                 p
1203                 for p in fragments]
1204
1205         fragmented_encapped_fragments = \
1206             [x for p in encapped_fragments
1207              for x in fragment_rfc791(p, 200)]
1208
1209         self.src_if.add_stream(fragmented_encapped_fragments)
1210
1211         self.pg_enable_capture(self.pg_interfaces)
1212         self.pg_start()
1213
1214         self.src_if.assert_nothing_captured()
1215         packets = self.dst_if.get_capture(len(self._packet_infos))
1216         self.verify_capture(packets, IP)
1217
1218         # TODO remove gre vpp config by hand until VppIpRoute gets fixed
1219         # so that it's query_vpp_config() works as it should
1220         self.gre4.remove_vpp_config()
1221         self.logger.debug(self.vapi.ppcli("show interface"))
1222
1223     def test_fif6(self):
1224         """ Fragments in fragments (6o6) """
1225         # TODO this should be ideally in setUpClass, but then we hit a bug
1226         # with VppIpRoute incorrectly reporting it's present when it's not
1227         # so we need to manually remove the vpp config, thus we cannot have
1228         # it shared for multiple test cases
1229         self.tun_ip6 = "1002::1"
1230
1231         self.gre6 = VppGreInterface(self, self.src_if.local_ip6, self.tun_ip6)
1232         self.gre6.add_vpp_config()
1233         self.gre6.admin_up()
1234         self.gre6.config_ip6()
1235
1236         self.vapi.ip_reassembly_enable_disable(
1237             sw_if_index=self.gre6.sw_if_index, enable_ip6=True)
1238
1239         self.route6 = VppIpRoute(self, self.tun_ip6, 128,
1240                                  [VppRoutePath(
1241                                      self.src_if.remote_ip6,
1242                                      self.src_if.sw_if_index)])
1243         self.route6.add_vpp_config()
1244
1245         self.reset_packet_infos()
1246         for i in range(test_packet_count):
1247             info = self.create_packet_info(self.src_if, self.dst_if)
1248             payload = self.info_to_payload(info)
1249             # Ethernet header here is only for size calculation, thus it
1250             # doesn't matter how it's initialized. This is to ensure that
1251             # reassembled packet is not > 9000 bytes, so that it's not dropped
1252             p = (Ether() /
1253                  IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) /
1254                  UDP(sport=1234, dport=5678) /
1255                  Raw(payload))
1256             size = self.packet_sizes[(i // 2) % len(self.packet_sizes)]
1257             self.extend_packet(p, size, self.padding)
1258             info.data = p[IPv6]  # use only IPv6 part, without ethernet header
1259
1260         fragments = [x for _, i in six.iteritems(self._packet_infos)
1261                      for x in fragment_rfc8200(
1262                          i.data, i.index, 400)]
1263
1264         encapped_fragments = \
1265             [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1266              IPv6(src=self.tun_ip6, dst=self.src_if.local_ip6) /
1267                 GRE() /
1268                 p
1269                 for p in fragments]
1270
1271         fragmented_encapped_fragments = \
1272             [x for p in encapped_fragments for x in (
1273                 fragment_rfc8200(
1274                     p,
1275                     2 * len(self._packet_infos) + p[IPv6ExtHdrFragment].id,
1276                     200)
1277                 if IPv6ExtHdrFragment in p else [p]
1278             )
1279             ]
1280
1281         self.src_if.add_stream(fragmented_encapped_fragments)
1282
1283         self.pg_enable_capture(self.pg_interfaces)
1284         self.pg_start()
1285
1286         self.src_if.assert_nothing_captured()
1287         packets = self.dst_if.get_capture(len(self._packet_infos))
1288         self.verify_capture(packets, IPv6)
1289
1290         # TODO remove gre vpp config by hand until VppIpRoute gets fixed
1291         # so that it's query_vpp_config() works as it should
1292         self.gre6.remove_vpp_config()
1293
1294
1295 if __name__ == '__main__':
1296     unittest.main(testRunner=VppTestRunner)