svm: refactor fifo chunk tracking
[vpp.git] / src / plugins / unittest / svm_fifo_test.c
1 /*
2  * Copyright (c) 2019 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <svm/svm_fifo.h>
16 #include <vlib/vlib.h>
17 #include <svm/svm_common.h>
18 #include <svm/fifo_segment.h>
19
20 #define SFIFO_TEST_I(_cond, _comment, _args...)                 \
21 ({                                                              \
22   int _evald = (_cond);                                         \
23   if (!(_evald)) {                                              \
24     fformat(stderr, "FAIL:%d: " _comment "\n",                  \
25             __LINE__, ##_args);                                 \
26   } else {                                                      \
27     fformat(stderr, "PASS:%d: " _comment "\n",                  \
28             __LINE__, ##_args);                                 \
29   }                                                             \
30   _evald;                                                       \
31 })
32
33 #define SFIFO_TEST(_cond, _comment, _args...)                   \
34 {                                                               \
35     if (!SFIFO_TEST_I(_cond, _comment, ##_args)) {              \
36         return 1;                                               \
37     }                                                           \
38 }
39
40 typedef struct
41 {
42   u32 offset;
43   u32 len;
44 } test_pattern_t;
45
46 /* *INDENT-OFF* */
47 test_pattern_t test_pattern[] = {
48   {380, 8}, {768, 8}, {1156, 8}, {1544, 8}, {1932, 8}, {2320, 8}, {2708, 8},
49   {2992, 8}, {372, 8}, {760, 8}, {1148, 8}, {1536, 8}, {1924, 8}, {2312, 8},
50   {2700, 8}, {2984, 8}, {364, 8}, {752, 8}, {1140, 8}, {1528, 8}, {1916, 8},
51   {2304, 8}, {2692, 8}, {2976, 8}, {356, 8}, {744, 8}, {1132, 8}, {1520, 8},
52   {1908, 8}, {2296, 8}, {2684, 8}, {2968, 8}, {348, 8}, {736, 8}, {1124, 8},
53   {1512, 8}, {1900, 8}, {2288, 8}, {2676, 8}, {2960, 8}, {340, 8}, {728, 8},
54   {1116, 8}, {1504, 8}, {1892, 8}, {2280, 8}, {2668, 8}, {2952, 8}, {332, 8},
55   {720, 8}, {1108, 8}, {1496, 8}, {1884, 8}, {2272, 8}, {2660, 8}, {2944, 8},
56   {324, 8}, {712, 8}, {1100, 8}, {1488, 8}, {1876, 8}, {2264, 8}, {2652, 8},
57   {2936, 8}, {316, 8}, {704, 8}, {1092, 8}, {1480, 8}, {1868, 8}, {2256, 8},
58   {2644, 8}, {2928, 8}, {308, 8}, {696, 8}, {1084, 8}, {1472, 8}, {1860, 8},
59   {2248, 8}, {2636, 8}, {2920, 8}, {300, 8}, {688, 8}, {1076, 8}, {1464, 8},
60   {1852, 8}, {2240, 8}, {2628, 8}, {2912, 8}, {292, 8}, {680, 8}, {1068, 8},
61   {1456, 8}, {1844, 8}, {2232, 8}, {2620, 8}, {2904, 8}, {284, 8}, {672, 8},
62   {1060, 8}, {1448, 8}, {1836, 8}, {2224, 8}, {2612, 8}, {2896, 8}, {276, 8},
63   {664, 8}, {1052, 8}, {1440, 8}, {1828, 8},  {2216, 8}, {2604, 8}, {2888, 8},
64   {268, 8}, {656, 8}, {1044, 8}, {1432, 8}, {1820, 8}, {2208, 8}, {2596, 8},
65   {2880, 8}, {260, 8}, {648, 8}, {1036, 8}, {1424, 8}, {1812, 8}, {2200, 8},
66   {2588, 8}, {2872, 8}, {252, 8}, {640, 8}, {1028, 8}, {1416, 8}, {1804, 8},
67   {2192, 8}, {2580, 8}, {2864, 8}, {244, 8}, {632, 8}, {1020, 8}, {1408, 8},
68   {1796, 8}, {2184, 8}, {2572, 8}, {2856, 8}, {236, 8}, {624, 8}, {1012, 8},
69   {1400, 8}, {1788, 8}, {2176, 8}, {2564, 8}, {2848, 8}, {228, 8}, {616, 8},
70   {1004, 8}, {1392, 8}, {1780, 8}, {2168, 8}, {2556, 8}, {2840, 8}, {220, 8},
71   {608, 8}, {996, 8}, {1384, 8}, {1772, 8}, {2160, 8}, {2548, 8}, {2832, 8},
72   {212, 8}, {600, 8}, {988, 8}, {1376, 8}, {1764, 8}, {2152, 8}, {2540, 8},
73   {2824, 8}, {204, 8}, {592, 8}, {980, 8}, {1368, 8}, {1756, 8}, {2144, 8},
74   {2532, 8}, {2816, 8}, {196, 8}, {584, 8}, {972, 8}, {1360, 8}, {1748, 8},
75   {2136, 8}, {2524, 8}, {2808, 8}, {188, 8}, {576, 8}, {964, 8}, {1352, 8},
76   {1740, 8}, {2128, 8}, {2516, 8}, {2800, 8}, {180, 8}, {568, 8}, {956, 8},
77   {1344, 8}, {1732, 8}, {2120, 8}, {2508, 8}, {2792, 8}, {172, 8}, {560, 8},
78   {948, 8}, {1336, 8}, {1724, 8}, {2112, 8}, {2500, 8}, {2784, 8}, {164, 8},
79   {552, 8}, {940, 8}, {1328, 8}, {1716, 8}, {2104, 8}, {2492, 8}, {2776, 8},
80   {156, 8}, {544, 8}, {932, 8}, {1320, 8}, {1708, 8}, {2096, 8}, {2484, 8},
81   {2768, 8}, {148, 8}, {536, 8}, {924, 8}, {1312, 8}, {1700, 8}, {2088, 8},
82   {2476, 8}, {2760, 8}, {140, 8}, {528, 8}, {916, 8}, {1304, 8}, {1692, 8},
83   {2080, 8}, {2468, 8}, {2752, 8}, {132, 8}, {520, 8}, {908, 8}, {1296, 8},
84   {1684, 8}, {2072, 8}, {2460, 8}, {2744, 8}, {124, 8}, {512, 8}, {900, 8},
85   {1288, 8}, {1676, 8}, {2064, 8}, {2452, 8}, {2736, 8}, {116, 8}, {504, 8},
86   {892, 8}, {1280, 8}, {1668, 8}, {2056, 8}, {2444, 8}, {2728, 8}, {108, 8},
87   {496, 8}, {884, 8}, {1272, 8}, {1660, 8}, {2048, 8}, {2436, 8}, {2720, 8},
88   {100, 8}, {488, 8}, {876, 8}, {1264, 8}, {1652, 8}, {2040, 8}, {2428, 8},
89   {2716, 4}, {92, 8}, {480, 8}, {868, 8}, {1256, 8}, {1644, 8}, {2032, 8},
90   {2420, 8}, {84, 8}, {472, 8}, {860, 8}, {1248, 8}, {1636, 8}, {2024, 8},
91   {2412, 8}, {76, 8}, {464, 8}, {852, 8}, {1240, 8}, {1628, 8}, {2016, 8},
92   {2404, 8}, {68, 8}, {456, 8}, {844, 8}, {1232, 8}, {1620, 8}, {2008, 8},
93   {2396, 8}, {60, 8}, {448, 8}, {836, 8}, {1224, 8}, {1612, 8}, {2000, 8},
94   {2388, 8}, {52, 8}, {440, 8}, {828, 8}, {1216, 8}, {1604, 8}, {1992, 8},
95   {2380, 8}, {44, 8}, {432, 8}, {820, 8}, {1208, 8}, {1596, 8}, {1984, 8},
96   {2372, 8}, {36, 8}, {424, 8}, {812, 8}, {1200, 8}, {1588, 8}, {1976, 8},
97   {2364, 8}, {28, 8}, {416, 8}, {804, 8}, {1192, 8}, {1580, 8}, {1968, 8},
98   {2356, 8}, {20, 8}, {408, 8}, {796, 8}, {1184, 8}, {1572, 8}, {1960, 8},
99   {2348, 8}, {12, 8}, {400, 8}, {788, 8}, {1176, 8}, {1564, 8}, {1952, 8},
100   {2340, 8}, {4, 8}, {392, 8}, {780, 8}, {1168, 8}, {1556, 8}, {1944, 8},
101   {2332, 8},
102   /* missing from original data set */
103   {388, 4}, {776, 4}, {1164, 4}, {1552, 4}, {1940, 4}, {2328, 4},
104 };
105 /* *INDENT-ON* */
106
107 int
108 pattern_cmp (const void *arg1, const void *arg2)
109 {
110   test_pattern_t *a1 = (test_pattern_t *) arg1;
111   test_pattern_t *a2 = (test_pattern_t *) arg2;
112
113   if (a1->offset < a2->offset)
114     return -1;
115   else if (a1->offset > a2->offset)
116     return 1;
117   return 0;
118 }
119
120 static u8
121 fifo_validate_pattern (vlib_main_t * vm, test_pattern_t * pattern,
122                        u32 pattern_length)
123 {
124   test_pattern_t *tp = pattern;
125   int i;
126
127   /* Go through the pattern and make 100% sure it's sane */
128   for (i = 0; i < pattern_length - 1; i++)
129     {
130       if (tp->offset + tp->len != (tp + 1)->offset)
131         {
132           vlib_cli_output (vm, "[%d] missing {%d, %d}", i,
133                            (tp->offset + tp->len),
134                            (tp + 1)->offset - (tp->offset + tp->len));
135           return 0;
136         }
137       tp++;
138     }
139   return 1;
140 }
141
142 static test_pattern_t *
143 fifo_get_validate_pattern (vlib_main_t * vm, test_pattern_t * test_data,
144                            u32 test_data_len)
145 {
146   test_pattern_t *validate_pattern = 0;
147
148   /* Validate, and try segments in order... */
149   vec_validate (validate_pattern, test_data_len - 1);
150   memcpy (validate_pattern, test_data,
151           test_data_len * sizeof (test_pattern_t));
152   qsort ((u8 *) validate_pattern, test_data_len, sizeof (test_pattern_t),
153          pattern_cmp);
154
155   if (fifo_validate_pattern (vm, validate_pattern, test_data_len) == 0)
156     return 0;
157
158   return validate_pattern;
159 }
160
161 static svm_fifo_t *
162 fifo_prepare (u32 fifo_size)
163 {
164   svm_fifo_t *f;
165   f = svm_fifo_create (fifo_size);
166
167   /* Paint fifo data vector with -1's */
168   clib_memset (f->head_chunk->data, 0xFF, fifo_size);
169
170   return f;
171 }
172
173 static int
174 compare_data (u8 * data1, u8 * data2, u32 start, u32 len, u32 * index)
175 {
176   int i;
177
178   for (i = start; i < start + len; i++)
179     {
180       if (data1[i] != data2[i])
181         {
182           *index = i;
183           return 1;
184         }
185     }
186   return 0;
187 }
188
189 int
190 sfifo_test_fifo1 (vlib_main_t * vm, unformat_input_t * input)
191 {
192   svm_fifo_t *f;
193   u32 fifo_size = 1 << 20;
194   u32 *test_data = 0;
195   u32 offset;
196   int i, rv, verbose = 0;
197   u32 data_word, test_data_len, j;
198   ooo_segment_t *ooo_seg;
199   u8 *data, *s, *data_buf = 0;
200
201   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
202     {
203       if (unformat (input, "verbose"))
204         verbose = 1;
205     }
206
207   test_data_len = fifo_size / sizeof (u32);
208   vec_validate (test_data, test_data_len - 1);
209
210   for (i = 0; i < vec_len (test_data); i++)
211     test_data[i] = i;
212
213   f = fifo_prepare (fifo_size);
214
215   /*
216    * Enqueue an initial (un-dequeued) chunk
217    */
218   rv = svm_fifo_enqueue (f, sizeof (u32), (u8 *) test_data);
219   SFIFO_TEST ((rv == sizeof (u32)), "enqueued %d", rv);
220   SFIFO_TEST ((f->tail == 4), "fifo tail %u", f->tail);
221
222   /*
223    * Create 3 chunks in the future. The offsets are relative
224    * to the current fifo tail
225    */
226   for (i = 0; i < 3; i++)
227     {
228       offset = (2 * i + 1) * sizeof (u32) - f->tail;
229       data = (u8 *) (test_data + (2 * i + 1));
230       if (i == 0)
231         {
232           rv = svm_fifo_enqueue (f, sizeof (u32), data);
233           rv = rv > 0 ? 0 : rv;
234         }
235       else
236         rv = svm_fifo_enqueue_with_offset (f, offset, sizeof (u32), data);
237       if (verbose)
238         vlib_cli_output (vm, "add [%d] [%d, %d]", 2 * i + 1, offset,
239                          offset + sizeof (u32));
240       if (rv)
241         {
242           clib_warning ("enqueue returned %d", rv);
243           goto err;
244         }
245     }
246
247   if (verbose)
248     vlib_cli_output (vm, "fifo after odd segs: %U", format_svm_fifo, f, 1);
249
250   SFIFO_TEST ((f->tail == 8), "fifo tail %u", f->tail);
251   SFIFO_TEST ((svm_fifo_n_ooo_segments (f) == 2),
252               "number of ooo segments %u", svm_fifo_n_ooo_segments (f));
253
254   /*
255    * Try adding a completely overlapped segment
256    */
257   offset = 3 * sizeof (u32) - f->tail;
258   data = (u8 *) (test_data + 3);
259   rv = svm_fifo_enqueue_with_offset (f, offset, sizeof (u32), data);
260   if (rv)
261     {
262       clib_warning ("enqueue returned %d", rv);
263       goto err;
264     }
265
266   if (verbose)
267     vlib_cli_output (vm, "fifo after overlap seg: %U", format_svm_fifo, f, 1);
268
269   SFIFO_TEST ((svm_fifo_n_ooo_segments (f) == 2),
270               "number of ooo segments %u", svm_fifo_n_ooo_segments (f));
271
272   /*
273    * Make sure format functions are not buggy
274    */
275   s = format (0, "%U", format_svm_fifo, f, 2);
276   vec_free (s);
277
278   /*
279    * Paint some of missing data backwards
280    */
281   for (i = 3; i > 1; i--)
282     {
283       offset = (2 * i + 0) * sizeof (u32) - f->tail;
284       data = (u8 *) (test_data + (2 * i + 0));
285       rv = svm_fifo_enqueue_with_offset (f, offset, sizeof (u32), data);
286       if (verbose)
287         vlib_cli_output (vm, "add [%d] [%d, %d]", 2 * i, offset,
288                          offset + sizeof (u32));
289       if (rv)
290         {
291           clib_warning ("enqueue returned %d", rv);
292           goto err;
293         }
294     }
295
296   if (verbose)
297     vlib_cli_output (vm, "fifo before missing link: %U", format_svm_fifo, f,
298                      1);
299   SFIFO_TEST ((svm_fifo_n_ooo_segments (f) == 1),
300               "number of ooo segments %u", svm_fifo_n_ooo_segments (f));
301   ooo_seg = svm_fifo_first_ooo_segment (f);
302   SFIFO_TEST ((ooo_seg->start == 12),
303               "first ooo seg position %u", ooo_seg->start);
304   SFIFO_TEST ((ooo_seg->length == 16),
305               "first ooo seg length %u", ooo_seg->length);
306
307   /*
308    * Enqueue the missing u32
309    */
310   rv = svm_fifo_enqueue (f, sizeof (u32), (u8 *) (test_data + 2));
311   if (verbose)
312     vlib_cli_output (vm, "fifo after missing link: %U", format_svm_fifo, f,
313                      1);
314   SFIFO_TEST ((rv == 20), "bytes to be enqueued %u", rv);
315   SFIFO_TEST ((svm_fifo_n_ooo_segments (f) == 0),
316               "number of ooo segments %u", svm_fifo_n_ooo_segments (f));
317
318   /*
319    * Collect results
320    */
321   for (i = 0; i < 7; i++)
322     {
323       rv = svm_fifo_dequeue (f, sizeof (u32), (u8 *) & data_word);
324       if (rv != sizeof (u32))
325         {
326           clib_warning ("bytes dequeues %u", rv);
327           goto err;
328         }
329       if (data_word != test_data[i])
330         {
331           clib_warning ("recovered [%d] %d not %d", i, data_word,
332                         test_data[i]);
333           goto err;
334         }
335     }
336
337   /*
338    * Test segment overlaps: last ooo segment overlaps all
339    */
340   svm_fifo_free (f);
341   f = fifo_prepare (fifo_size);
342
343   for (i = 0; i < 4; i++)
344     {
345       offset = (2 * i + 1) * sizeof (u32) - f->tail;
346       data = (u8 *) (test_data + (2 * i + 1));
347       rv = svm_fifo_enqueue_with_offset (f, offset, sizeof (u32), data);
348       if (verbose)
349         vlib_cli_output (vm, "add [%d] [%d, %d]", 2 * i + 1, offset,
350                          offset + sizeof (u32));
351       if (rv)
352         {
353           clib_warning ("enqueue returned %d", rv);
354           goto err;
355         }
356     }
357
358   rv = svm_fifo_enqueue_with_offset (f, 8 - f->tail, 21, data);
359   SFIFO_TEST ((rv == 0), "ooo enqueued %u", rv);
360   SFIFO_TEST ((svm_fifo_n_ooo_segments (f) == 1),
361               "number of ooo segments %u", svm_fifo_n_ooo_segments (f));
362
363   /* add missing data to be able to dequeue something */
364   rv = svm_fifo_enqueue (f, 4, data);
365   SFIFO_TEST ((rv == 32), "enqueued %u", rv);
366   SFIFO_TEST ((svm_fifo_n_ooo_segments (f) == 0),
367               "number of ooo segments %u", svm_fifo_n_ooo_segments (f));
368
369   vec_validate (data_buf, vec_len (test_data));
370   svm_fifo_peek (f, 0, 4, data_buf);
371   if (compare_data (data_buf, data, 0, 4, &j))
372     SFIFO_TEST (0, "[%d] peeked %u expected %u", j, data_buf[j], data[j]);
373   svm_fifo_peek (f, 8, 21, data_buf);
374   if (compare_data (data_buf, data, 0, 21, &j))
375     SFIFO_TEST (0, "[%d] peeked %u expected %u", j, data_buf[j], data[j]);
376   vec_reset_length (data_buf);
377
378   /*
379    * Test segment overlaps: enqueue and overlap ooo segments
380    */
381   svm_fifo_free (f);
382   f = fifo_prepare (fifo_size);
383
384   for (i = 0; i < 4; i++)
385     {
386       offset = (2 * i + 1) * sizeof (u32) - f->tail;
387       data = (u8 *) (test_data + (2 * i + 1));
388       rv = svm_fifo_enqueue_with_offset (f, offset, sizeof (u32), data);
389       if (verbose)
390         vlib_cli_output (vm, "add [%d] [%d, %d]", 2 * i + 1, offset,
391                          offset + sizeof (u32));
392       if (rv)
393         {
394           clib_warning ("enqueue returned %d", rv);
395           goto err;
396         }
397     }
398
399   if (verbose)
400     vlib_cli_output (vm, "fifo after enqueue: %U", format_svm_fifo, f, 1);
401
402   rv = svm_fifo_enqueue (f, 29, data);
403   if (verbose)
404     vlib_cli_output (vm, "fifo after enqueueing 29: %U", format_svm_fifo, f,
405                      1);
406   SFIFO_TEST ((rv == 32), "ooo enqueued %u", rv);
407   SFIFO_TEST ((svm_fifo_n_ooo_segments (f) == 0),
408               "number of ooo segments %u", svm_fifo_n_ooo_segments (f));
409
410   vec_validate (data_buf, vec_len (data));
411   svm_fifo_peek (f, 0, vec_len (data), data_buf);
412   if (compare_data (data_buf, data, 0, vec_len (data), &j))
413     {
414       SFIFO_TEST (0, "[%d] peeked %u expected %u", j, data_buf[j], data[j]);
415     }
416
417   /* Try to peek beyond the data */
418   rv = svm_fifo_peek (f, svm_fifo_max_dequeue (f), vec_len (data), data_buf);
419   SFIFO_TEST ((rv == 0), "peeked %u expected 0", rv);
420
421   vec_free (data_buf);
422   svm_fifo_free (f);
423   vec_free (test_data);
424
425   return 0;
426
427 err:
428   svm_fifo_free (f);
429   vec_free (test_data);
430   return -1;
431 }
432
433 static int
434 sfifo_test_fifo2 (vlib_main_t * vm)
435 {
436   svm_fifo_t *f;
437   u32 fifo_size = (1 << 20) + 1;
438   int i, rv, test_data_len;
439   u64 data64;
440   test_pattern_t *tp, *vp, *test_data;
441   ooo_segment_t *ooo_seg;
442
443   test_data = test_pattern;
444   test_data_len = ARRAY_LEN (test_pattern);
445
446   vp = fifo_get_validate_pattern (vm, test_data, test_data_len);
447
448   /* Create a fifo */
449   f = fifo_prepare (fifo_size);
450
451   /*
452    * Try with sorted data
453    */
454   for (i = 0; i < test_data_len; i++)
455     {
456       tp = vp + i;
457       data64 = tp->offset;
458       svm_fifo_enqueue_with_offset (f, tp->offset - f->tail, tp->len,
459                                     (u8 *) & data64);
460     }
461
462   /* Expected result: one big fat chunk at offset 4 */
463   SFIFO_TEST ((svm_fifo_n_ooo_segments (f) == 1),
464               "number of ooo segments %u", svm_fifo_n_ooo_segments (f));
465   ooo_seg = svm_fifo_first_ooo_segment (f);
466   SFIFO_TEST ((ooo_seg->start == 4),
467               "first ooo seg position %u", ooo_seg->start);
468   SFIFO_TEST ((ooo_seg->length == 2996),
469               "first ooo seg length %u", ooo_seg->length);
470
471   data64 = 0;
472   rv = svm_fifo_enqueue (f, sizeof (u32), (u8 *) & data64);
473   SFIFO_TEST ((rv == 3000), "bytes to be enqueued %u", rv);
474
475   svm_fifo_free (f);
476   vec_free (vp);
477
478   /*
479    * Now try it again w/ unsorted data...
480    */
481
482   f = fifo_prepare (fifo_size);
483
484   for (i = 0; i < test_data_len; i++)
485     {
486       tp = &test_data[i];
487       data64 = tp->offset;
488       rv = svm_fifo_enqueue_with_offset (f, tp->offset - f->tail, tp->len,
489                                          (u8 *) & data64);
490       if (rv)
491         {
492           clib_warning ("enqueue returned %d", rv);
493         }
494     }
495
496   /* Expecting the same result: one big fat chunk at offset 4 */
497   SFIFO_TEST ((svm_fifo_n_ooo_segments (f) == 1),
498               "number of ooo segments %u", svm_fifo_n_ooo_segments (f));
499   ooo_seg = svm_fifo_first_ooo_segment (f);
500   SFIFO_TEST ((ooo_seg->start == 4),
501               "first ooo seg position %u", ooo_seg->start);
502   SFIFO_TEST ((ooo_seg->length == 2996),
503               "first ooo seg length %u", ooo_seg->length);
504
505   data64 = 0;
506   rv = svm_fifo_enqueue (f, sizeof (u32), (u8 *) & data64);
507
508   SFIFO_TEST ((rv == 3000), "bytes to be enqueued %u", rv);
509
510   svm_fifo_free (f);
511
512   return 0;
513 }
514
515 static int
516 sfifo_test_fifo3 (vlib_main_t * vm, unformat_input_t * input)
517 {
518   svm_fifo_t *f;
519   u32 fifo_size = (4 << 10) + 1;
520   u32 fifo_initial_offset = 0;
521   u32 total_size = 2 << 10;
522   int overlap = 0, verbose = 0, randomize = 1, drop = 0, in_seq_all = 0;
523   u8 *data_pattern = 0, *data_buf = 0;
524   test_pattern_t *tp, *generate = 0;
525   u32 nsegs = 2, seg_size, length_so_far;
526   u32 current_offset, offset_increment, len_this_chunk;
527   u32 seed = 0xdeaddabe, j;
528   int i, rv;
529
530   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
531     {
532       if (unformat (input, "fifo-size %d", &fifo_size))
533         ;
534       else if (unformat (input, "total-size %d", &total_size))
535         ;
536       else if (unformat (input, "verbose"))
537         verbose = 1;
538       else if (unformat (input, "overlap"))
539         overlap = 1;
540       else if (unformat (input, "initial-offset %d", &fifo_initial_offset))
541         ;
542       else if (unformat (input, "seed %d", &seed))
543         ;
544       else if (unformat (input, "nsegs %d", &nsegs))
545         ;
546       else if (unformat (input, "no-randomize"))
547         randomize = 0;
548       else if (unformat (input, "in-seq-all"))
549         in_seq_all = 1;
550       else if (unformat (input, "drop"))
551         drop = 1;
552       else
553         {
554           clib_error_t *e = clib_error_return
555             (0, "unknown input `%U'", format_unformat_error, input);
556           clib_error_report (e);
557           return -1;
558         }
559     }
560
561   if (total_size > fifo_size)
562     {
563       clib_warning ("total_size %d greater than fifo size %d", total_size,
564                     fifo_size);
565       return -1;
566     }
567   if (overlap && randomize == 0)
568     {
569       clib_warning ("Can't enqueue in-order with overlap");
570       return -1;
571     }
572
573   /*
574    * Generate data
575    */
576   vec_validate (data_pattern, total_size - 1);
577   for (i = 0; i < vec_len (data_pattern); i++)
578     data_pattern[i] = i & 0xff;
579
580   /*
581    * Generate segments
582    */
583   seg_size = total_size / nsegs;
584   length_so_far = 0;
585   current_offset = randomize;
586   while (length_so_far < total_size)
587     {
588       vec_add2 (generate, tp, 1);
589       len_this_chunk = clib_min (seg_size, total_size - length_so_far);
590       tp->offset = current_offset;
591       tp->len = len_this_chunk;
592
593       if (overlap && (len_this_chunk == seg_size))
594         do
595           {
596             offset_increment = len_this_chunk
597               % (1 + (random_u32 (&seed) % len_this_chunk));
598           }
599         while (offset_increment == 0);
600       else
601         offset_increment = len_this_chunk;
602
603       current_offset += offset_increment;
604       length_so_far = tp->offset + tp->len;
605     }
606
607   /*
608    * Validate segment list. Only valid for non-overlap cases.
609    */
610   if (overlap == 0)
611     fifo_validate_pattern (vm, generate, vec_len (generate));
612
613   if (verbose)
614     {
615       vlib_cli_output (vm, "raw data pattern:");
616       for (i = 0; i < vec_len (generate); i++)
617         {
618           vlib_cli_output (vm, "[%d] offset %u len %u", i,
619                            generate[i].offset, generate[i].len);
620         }
621     }
622
623   /* Randomize data pattern */
624   if (randomize)
625     {
626       for (i = 0; i < vec_len (generate) / 2; i++)
627         {
628           u32 src_index, dst_index;
629           test_pattern_t _tmp, *tmp = &_tmp;
630
631           src_index = random_u32 (&seed) % vec_len (generate);
632           dst_index = random_u32 (&seed) % vec_len (generate);
633
634           tmp[0] = generate[dst_index];
635           generate[dst_index] = generate[src_index];
636           generate[src_index] = tmp[0];
637         }
638       if (verbose)
639         {
640           vlib_cli_output (vm, "randomized data pattern:");
641           for (i = 0; i < vec_len (generate); i++)
642             {
643               vlib_cli_output (vm, "[%d] offset %u len %u", i,
644                                generate[i].offset, generate[i].len);
645             }
646         }
647     }
648
649   /*
650    * Create a fifo and add segments
651    */
652   f = fifo_prepare (fifo_size);
653
654   /* manually set head and tail pointers to validate modular arithmetic */
655   fifo_initial_offset = fifo_initial_offset % fifo_size;
656   svm_fifo_init_pointers (f, fifo_initial_offset, fifo_initial_offset);
657
658   for (i = !randomize; i < vec_len (generate); i++)
659     {
660       tp = generate + i;
661       svm_fifo_enqueue_with_offset (f,
662                                     fifo_initial_offset + tp->offset -
663                                     f->tail, tp->len,
664                                     (u8 *) data_pattern + tp->offset);
665     }
666
667   /* Add the first segment in order for non random data */
668   if (!randomize)
669     svm_fifo_enqueue (f, generate[0].len, (u8 *) data_pattern);
670
671   /*
672    * Expected result: one big fat chunk at offset 1 if randomize == 1
673    */
674
675   if (verbose)
676     vlib_cli_output (vm, "fifo before missing link: %U",
677                      format_svm_fifo, f, 1 /* verbose */ );
678
679   /*
680    * Add the missing byte if segments were randomized
681    */
682   if (randomize)
683     {
684       u32 bytes_to_enq = 1;
685       if (in_seq_all)
686         bytes_to_enq = total_size;
687       rv = svm_fifo_enqueue (f, bytes_to_enq, data_pattern + 0);
688
689       if (verbose)
690         vlib_cli_output (vm, "in-order enqueue returned %d", rv);
691
692       SFIFO_TEST ((rv == total_size), "enqueued %u expected %u", rv,
693                   total_size);
694
695     }
696
697   SFIFO_TEST ((svm_fifo_has_ooo_data (f) == 0), "number of ooo segments %u",
698               svm_fifo_n_ooo_segments (f));
699
700   /*
701    * Test if peeked data is the same as original data
702    */
703   vec_validate (data_buf, vec_len (data_pattern));
704   svm_fifo_peek (f, 0, vec_len (data_pattern), data_buf);
705   if (compare_data (data_buf, data_pattern, 0, vec_len (data_pattern), &j))
706     {
707       SFIFO_TEST (0, "[%d] peeked %u expected %u", j, data_buf[j],
708                   data_pattern[j]);
709     }
710
711   /*
712    * Dequeue or drop all data
713    */
714   if (drop)
715     {
716       svm_fifo_dequeue_drop (f, vec_len (data_pattern));
717     }
718   else
719     {
720       memset (data_buf, 0, vec_len (data_pattern));
721       svm_fifo_dequeue (f, vec_len (data_pattern), data_buf);
722       if (compare_data
723           (data_buf, data_pattern, 0, vec_len (data_pattern), &j))
724         {
725           SFIFO_TEST (0, "[%d] dequeued %u expected %u", j, data_buf[j],
726                       data_pattern[j]);
727         }
728     }
729
730   SFIFO_TEST ((svm_fifo_max_dequeue (f) == 0), "fifo has %d bytes",
731               svm_fifo_max_dequeue (f));
732
733   svm_fifo_free (f);
734   vec_free (data_pattern);
735   vec_free (data_buf);
736
737   return 0;
738 }
739
740 static int
741 sfifo_test_fifo4 (vlib_main_t * vm, unformat_input_t * input)
742 {
743   svm_fifo_t *f;
744   u32 fifo_size = 6 << 10;
745   u32 fifo_initial_offset = 1000000000;
746   u32 test_n_bytes = 5000, j;
747   u8 *test_data = 0, *data_buf = 0;
748   int i, rv, verbose = 0;
749
750   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
751     {
752       if (unformat (input, "verbose"))
753         verbose = 1;
754       else
755         {
756           clib_error_t *e = clib_error_return
757             (0, "unknown input `%U'", format_unformat_error, input);
758           clib_error_report (e);
759           return -1;
760         }
761     }
762
763   /*
764    * Create a fifo and add segments
765    */
766   f = fifo_prepare (fifo_size);
767
768   /* Set head and tail pointers */
769   fifo_initial_offset = fifo_initial_offset % fifo_size;
770   svm_fifo_init_pointers (f, fifo_initial_offset, fifo_initial_offset);
771
772   vec_validate (test_data, test_n_bytes - 1);
773   for (i = 0; i < vec_len (test_data); i++)
774     test_data[i] = i;
775
776   for (i = test_n_bytes - 1; i > 0; i--)
777     {
778       rv = svm_fifo_enqueue_with_offset (f, fifo_initial_offset + i - f->tail,
779                                          sizeof (u8), &test_data[i]);
780       if (verbose)
781         vlib_cli_output (vm, "add [%d] [%d, %d]", i, i, i + sizeof (u8));
782       if (rv)
783         {
784           clib_warning ("enqueue returned %d", rv);
785           svm_fifo_free (f);
786           vec_free (test_data);
787           return -1;
788         }
789     }
790
791   svm_fifo_enqueue (f, sizeof (u8), &test_data[0]);
792
793   vec_validate (data_buf, vec_len (test_data));
794
795   svm_fifo_dequeue (f, vec_len (test_data), data_buf);
796   rv = compare_data (data_buf, test_data, 0, vec_len (test_data), &j);
797   if (rv)
798     vlib_cli_output (vm, "[%d] dequeued %u expected %u", j, data_buf[j],
799                      test_data[j]);
800   SFIFO_TEST ((rv == 0), "dequeued compared to original returned %d", rv);
801
802   svm_fifo_free (f);
803   vec_free (test_data);
804   return 0;
805 }
806
807 static u32
808 fifo_pos (svm_fifo_t * f, u32 pos)
809 {
810   return pos % f->size;
811 }
812
813 /* Avoids exposing svm_fifo.c internal function */
814 static ooo_segment_t *
815 ooo_seg_next (svm_fifo_t * f, ooo_segment_t * s)
816 {
817   if (pool_is_free_index (f->ooo_segments, s->next))
818     return 0;
819   return pool_elt_at_index (f->ooo_segments, s->next);
820 }
821
822 static int
823 sfifo_test_fifo5 (vlib_main_t * vm, unformat_input_t * input)
824 {
825   svm_fifo_t *f;
826   u32 fifo_size = 401, j = 0, offset = 200;
827   int i, rv, verbose = 0;
828   u8 *test_data = 0, *data_buf = 0;
829   ooo_segment_t *ooo_seg;
830
831   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
832     {
833       if (unformat (input, "verbose"))
834         verbose = 1;
835       else
836         {
837           clib_error_t *e = clib_error_return (0, "unknown input `%U'",
838                                                format_unformat_error, input);
839           clib_error_report (e);
840           return -1;
841         }
842     }
843
844   f = fifo_prepare (fifo_size);
845   svm_fifo_init_pointers (f, offset, offset);
846
847   vec_validate (test_data, 399);
848   for (i = 0; i < vec_len (test_data); i++)
849     test_data[i] = i % 0xff;
850
851   /*
852    * Start with [100, 200] and [300, 400]
853    */
854   svm_fifo_enqueue_with_offset (f, 100, 100, &test_data[100]);
855   svm_fifo_enqueue_with_offset (f, 300, 100, &test_data[300]);
856
857   SFIFO_TEST ((svm_fifo_n_ooo_segments (f) == 2),
858               "number of ooo segments %u", svm_fifo_n_ooo_segments (f));
859   SFIFO_TEST ((f->ooos_newest == 1), "newest %u", f->ooos_newest);
860   if (verbose)
861     vlib_cli_output (vm, "fifo after [100, 200] and [300, 400] : %U",
862                      format_svm_fifo, f, 2 /* verbose */ );
863
864   /*
865    * Add [225, 275]
866    */
867
868   rv = svm_fifo_enqueue_with_offset (f, 225, 50, &test_data[225]);
869   if (verbose)
870     vlib_cli_output (vm, "fifo after [225, 275] : %U",
871                      format_svm_fifo, f, 2 /* verbose */ );
872   SFIFO_TEST ((svm_fifo_n_ooo_segments (f) == 3),
873               "number of ooo segments %u", svm_fifo_n_ooo_segments (f));
874   ooo_seg = svm_fifo_first_ooo_segment (f);
875   SFIFO_TEST ((ooo_seg->start == fifo_pos (f, 100 + offset)),
876               "first seg start %u expected %u", ooo_seg->start,
877               fifo_pos (f, 100 + offset));
878   SFIFO_TEST ((ooo_seg->length == 100), "first seg length %u expected %u",
879               ooo_seg->length, 100);
880   ooo_seg = ooo_seg_next (f, ooo_seg);
881   SFIFO_TEST ((ooo_seg->start == fifo_pos (f, 225 + offset)),
882               "second seg start %u expected %u",
883               ooo_seg->start, fifo_pos (f, 225 + offset));
884   SFIFO_TEST ((ooo_seg->length == 50), "second seg length %u expected %u",
885               ooo_seg->length, 50);
886   ooo_seg = ooo_seg_next (f, ooo_seg);
887   SFIFO_TEST ((ooo_seg->start == fifo_pos (f, 300 + offset)),
888               "third seg start %u expected %u",
889               ooo_seg->start, fifo_pos (f, 300 + offset));
890   SFIFO_TEST ((ooo_seg->length == 100), "third seg length %u expected %u",
891               ooo_seg->length, 100);
892   SFIFO_TEST ((f->ooos_newest == 2), "newest %u", f->ooos_newest);
893   /*
894    * Add [190, 310]
895    */
896   rv = svm_fifo_enqueue_with_offset (f, 190, 120, &test_data[190]);
897   if (verbose)
898     vlib_cli_output (vm, "fifo after [190, 310] : %U",
899                      format_svm_fifo, f, 1 /* verbose */ );
900   SFIFO_TEST ((svm_fifo_n_ooo_segments (f) == 1),
901               "number of ooo segments %u", svm_fifo_n_ooo_segments (f));
902   ooo_seg = svm_fifo_first_ooo_segment (f);
903   SFIFO_TEST ((ooo_seg->start == fifo_pos (f, offset + 100)),
904               "first seg start %u expected %u",
905               ooo_seg->start, fifo_pos (f, offset + 100));
906   SFIFO_TEST ((ooo_seg->length == 300), "first seg length %u expected %u",
907               ooo_seg->length, 300);
908
909   /*
910    * Add [0, 150]
911    */
912   rv = svm_fifo_enqueue (f, 150, test_data);
913
914   if (verbose)
915     vlib_cli_output (vm, "fifo after [0 150] : %U", format_svm_fifo, f,
916                      2 /* verbose */ );
917
918   SFIFO_TEST ((rv == 400), "managed to enqueue %u expected %u", rv, 400);
919   SFIFO_TEST ((svm_fifo_n_ooo_segments (f) == 0),
920               "number of ooo segments %u", svm_fifo_n_ooo_segments (f));
921
922   vec_validate (data_buf, 399);
923   svm_fifo_peek (f, 0, 400, data_buf);
924   if (compare_data (data_buf, test_data, 0, 400, &j))
925     {
926       SFIFO_TEST (0, "[%d] peeked %u expected %u", j, data_buf[j],
927                   test_data[j]);
928     }
929
930   /*
931    * Add [100 200] and overlap it with [50 250]
932    */
933   svm_fifo_free (f);
934   f = fifo_prepare (fifo_size);
935
936   svm_fifo_enqueue_with_offset (f, 100, 100, &test_data[100]);
937   svm_fifo_enqueue_with_offset (f, 50, 200, &test_data[50]);
938   SFIFO_TEST ((svm_fifo_n_ooo_segments (f) == 1),
939               "number of ooo segments %u", svm_fifo_n_ooo_segments (f));
940   ooo_seg = svm_fifo_first_ooo_segment (f);
941   SFIFO_TEST ((ooo_seg->start == 50), "first seg start %u expected %u",
942               ooo_seg->start, 50);
943   SFIFO_TEST ((ooo_seg->length == 200), "first seg length %u expected %u",
944               ooo_seg->length, 200);
945
946   svm_fifo_free (f);
947   vec_free (test_data);
948   return 0;
949 }
950
951 /*
952  * Test ooo head/tail u32 wrapping
953  */
954 static int
955 sfifo_test_fifo6 (vlib_main_t * vm, unformat_input_t * input)
956 {
957   u32 fifo_size = 101, n_test_bytes = 100;
958   int i, j, rv, __clib_unused verbose = 0;
959   u8 *test_data = 0, *data_buf = 0;
960   ooo_segment_t *ooo_seg;
961   svm_fifo_t *f;
962
963   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
964     {
965       if (unformat (input, "verbose"))
966         verbose = 1;
967       else
968         {
969           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
970                            input);
971           return -1;
972         }
973     }
974
975   f = fifo_prepare (fifo_size);
976   vec_validate (test_data, n_test_bytes - 1);
977   vec_validate (data_buf, n_test_bytes - 1);
978   for (i = 0; i < vec_len (test_data); i++)
979     test_data[i] = i % 0xff;
980
981   /*
982    * Test ooo segment distance to/from tail with u32 wrap
983    */
984
985   /*
986    * |0|---[start]--(len5)-->|0|--(len6)-->[end]---|0|
987    */
988   rv = f_distance_from (f, ~0 - 5, 5);
989   SFIFO_TEST (rv == 11, "distance to tail should be %u is %u", 11, rv);
990
991   rv = f_distance_to (f, ~0 - 5, 5);
992   SFIFO_TEST (rv == f->size - 11, "distance from tail should be %u is %u",
993               f->size - 11, rv);
994
995   /*
996    * |0|---[end]--(len5)-->|0|--(len6)-->[start]---|0|
997    */
998   rv = f_distance_to (f, 5, ~0 - 5);
999   SFIFO_TEST (rv == 11, "distance from tail should be %u is %u", 11, rv);
1000
1001   rv = f_distance_from (f, 5, ~0 - 5);
1002   SFIFO_TEST (rv == f->size - 11, "distance to tail should be %u is %u",
1003               f->size - 11, rv);
1004
1005   /*
1006    * Add ooo with tail and ooo segment start u32 wrap
1007    */
1008   svm_fifo_init_pointers (f, ~0, ~0);
1009   svm_fifo_enqueue_with_offset (f, 10, 10, &test_data[10]);
1010   SFIFO_TEST ((svm_fifo_n_ooo_segments (f) == 1),
1011               "number of ooo segments %u", svm_fifo_n_ooo_segments (f));
1012   ooo_seg = svm_fifo_first_ooo_segment (f);
1013   rv = ooo_segment_offset_prod (f, ooo_seg);
1014   SFIFO_TEST (rv == 10, "offset should be %u is %u", 10, rv);
1015
1016   svm_fifo_enqueue (f, 10, test_data);
1017   SFIFO_TEST ((svm_fifo_n_ooo_segments (f) == 0),
1018               "number of ooo segments %u", svm_fifo_n_ooo_segments (f));
1019   SFIFO_TEST (f->ooos_list_head == OOO_SEGMENT_INVALID_INDEX,
1020               "there should be no ooo seg");
1021
1022   svm_fifo_peek (f, 5, 10, &data_buf[5]);
1023   if (compare_data (data_buf, test_data, 5, 10, (u32 *) & j))
1024     SFIFO_TEST (0, "[%d] dequeued %u expected %u", j, data_buf[j],
1025                 test_data[j]);
1026
1027   svm_fifo_dequeue (f, 20, data_buf);
1028   if (compare_data (data_buf, test_data, 0, 20, (u32 *) & j))
1029     SFIFO_TEST (0, "[%d] dequeued %u expected %u", j, data_buf[j],
1030                 test_data[j]);
1031
1032   /*
1033    * Force collect with tail u32 wrap and without ooo segment start u32 wrap
1034    */
1035   svm_fifo_init_pointers (f, ~0 - 10, ~0 - 10);
1036   svm_fifo_enqueue_with_offset (f, 5, 15, &test_data[5]);
1037   svm_fifo_enqueue (f, 12, test_data);
1038
1039   SFIFO_TEST ((svm_fifo_n_ooo_segments (f) == 0),
1040               "number of ooo segments %u", svm_fifo_n_ooo_segments (f));
1041   SFIFO_TEST (f->ooos_list_head == OOO_SEGMENT_INVALID_INDEX,
1042               "there should be no ooo seg");
1043
1044   svm_fifo_dequeue (f, 20, data_buf);
1045   if (compare_data (data_buf, test_data, 0, 20, (u32 *) & j))
1046     SFIFO_TEST (0, "[%d] dequeued %u expected %u", j, data_buf[j],
1047                 test_data[j]);
1048
1049   /*
1050    * Cleanup
1051    */
1052   vec_free (test_data);
1053   vec_free (data_buf);
1054   svm_fifo_free (f);
1055   return 0;
1056 }
1057
1058 /*
1059  * Multiple ooo enqueues and dequeues that force fifo tail/head wrap
1060  */
1061 static int
1062 sfifo_test_fifo7 (vlib_main_t * vm, unformat_input_t * input)
1063 {
1064   u32 fifo_size = 101, n_iterations = 100;
1065   int i, j, rv, __clib_unused verbose = 0;
1066   u8 *test_data = 0, *data_buf = 0;
1067   u64 n_test_bytes = 100;
1068   svm_fifo_t *f;
1069
1070   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1071     {
1072       if (unformat (input, "verbose"))
1073         verbose = 1;
1074       else
1075         {
1076           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
1077                            input);
1078           return -1;
1079         }
1080     }
1081
1082   /*
1083    * Prepare data structures
1084    */
1085   f = fifo_prepare (fifo_size);
1086   svm_fifo_init_pointers (f, ~0, ~0);
1087
1088   vec_validate (test_data, n_test_bytes - 1);
1089   vec_validate (data_buf, n_test_bytes - 1);
1090   for (i = 0; i < vec_len (test_data); i++)
1091     test_data[i] = i % 0xff;
1092
1093   /*
1094    * Run n iterations of test
1095    */
1096   for (i = 0; i < n_iterations; i++)
1097     {
1098       for (j = n_test_bytes - 1; j > 0; j -= 2)
1099         {
1100           svm_fifo_enqueue_with_offset (f, j, 1, &test_data[j]);
1101           rv = svm_fifo_n_ooo_segments (f);
1102           if (rv != (n_test_bytes - j) / 2 + 1)
1103             SFIFO_TEST (0, "number of ooo segments expected %u is %u",
1104                         (n_test_bytes - j) / 2 + 1, rv);
1105         }
1106
1107       svm_fifo_enqueue_with_offset (f, 1, n_test_bytes - 1, &test_data[1]);
1108       rv = svm_fifo_n_ooo_segments (f);
1109       if (rv != 1)
1110         SFIFO_TEST (0, "number of ooo segments %u", rv);
1111
1112       svm_fifo_enqueue (f, 1, test_data);
1113       rv = svm_fifo_n_ooo_segments (f);
1114       if (rv != 0)
1115         SFIFO_TEST (0, "number of ooo segments %u", rv);
1116
1117       svm_fifo_dequeue (f, n_test_bytes, data_buf);
1118       if (compare_data (data_buf, test_data, 0, n_test_bytes, (u32 *) & j))
1119         SFIFO_TEST (0, "[%d] dequeued %u expected %u", j, data_buf[j],
1120                     test_data[j]);
1121       svm_fifo_init_pointers (f, ~0 - i, ~0 - i);
1122     }
1123   SFIFO_TEST (1, "passed multiple ooo enqueue/dequeue");
1124
1125   /*
1126    * Cleanup
1127    */
1128   vec_free (test_data);
1129   vec_free (data_buf);
1130   svm_fifo_free (f);
1131   return 0;
1132 }
1133
1134 /*
1135  * Enqueue more than 4GB
1136  */
1137 static int
1138 sfifo_test_fifo_large (vlib_main_t * vm, unformat_input_t * input)
1139 {
1140   u32 n_iterations = 100, n_bytes_per_iter, half;
1141   int i, j, rv, __clib_unused verbose = 0;
1142   u8 *test_data = 0, *data_buf = 0;
1143   u64 n_test_bytes = 100;
1144   svm_fifo_t *f;
1145
1146   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1147     {
1148       if (unformat (input, "verbose"))
1149         verbose = 1;
1150       else
1151         {
1152           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
1153                            input);
1154           return -1;
1155         }
1156     }
1157
1158
1159   n_test_bytes = 5ULL << 30;
1160   n_iterations = 1 << 10;
1161   n_bytes_per_iter = n_test_bytes / n_iterations;
1162
1163   f = fifo_prepare (n_bytes_per_iter + 1);
1164   svm_fifo_init_pointers (f, ~0, ~0);
1165
1166   vec_validate (test_data, n_bytes_per_iter - 1);
1167   vec_validate (data_buf, n_bytes_per_iter - 1);
1168   for (i = 0; i < vec_len (test_data); i++)
1169     test_data[i] = i % 0xff;
1170
1171   half = n_bytes_per_iter / 2;
1172   for (i = 0; i < n_iterations; i++)
1173     {
1174       svm_fifo_enqueue_with_offset (f, half, half, &test_data[half]);
1175       svm_fifo_enqueue (f, half, test_data);
1176       rv = svm_fifo_n_ooo_segments (f);
1177       if (rv != 0)
1178         SFIFO_TEST (0, "number of ooo segments %u", rv);
1179       svm_fifo_dequeue (f, n_bytes_per_iter, data_buf);
1180       if (compare_data (data_buf, test_data, 0, n_bytes_per_iter,
1181                         (u32 *) & j))
1182         SFIFO_TEST (0, "[%d][%d] dequeued %u expected %u", i, j, data_buf[j],
1183                     test_data[j]);
1184     }
1185   SFIFO_TEST (1, "passed large transfer");
1186
1187   return 0;
1188 }
1189
1190 static int
1191 sfifo_test_fifo_grow (vlib_main_t * vm, unformat_input_t * input)
1192 {
1193   int verbose = 0, fifo_size = 201, start_offset = 100, i, j, rv;
1194   int test_n_bytes, deq_bytes, enq_bytes, n_deqs, n_enqs;
1195   svm_fifo_chunk_t *c, *next, *prev;
1196   u8 *test_data = 0, *data_buf = 0;
1197   u32 old_tail, offset;
1198   svm_fifo_t *f;
1199
1200   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1201     {
1202       if (unformat (input, "verbose"))
1203         verbose = 1;
1204       else
1205         {
1206           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
1207                            input);
1208           return -1;
1209         }
1210     }
1211
1212   f = fifo_prepare (fifo_size);
1213   svm_fifo_init_pointers (f, start_offset, start_offset);
1214
1215   /*
1216    * Add with fifo not wrapped
1217    */
1218   c = clib_mem_alloc (sizeof (svm_fifo_chunk_t) + 100);
1219   c->length = 100;
1220   c->start_byte = ~0;
1221   c->next = 0;
1222
1223   svm_fifo_add_chunk (f, c);
1224
1225   SFIFO_TEST (f->size == fifo_size + 100, "size expected %u is %u",
1226               fifo_size + 100, f->size);
1227   SFIFO_TEST (c->start_byte == fifo_size, "start byte expected %u is %u",
1228               fifo_size, c->start_byte);
1229   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1230
1231   /*
1232    *  Add with fifo wrapped
1233    */
1234
1235   svm_fifo_init_pointers (f, f->nitems - 100, f->nitems + 100);
1236   c = clib_mem_alloc (sizeof (svm_fifo_chunk_t) + 100);
1237   c->length = 100;
1238   c->start_byte = ~0;
1239   c->next = 0;
1240
1241   svm_fifo_add_chunk (f, c);
1242
1243   SFIFO_TEST (f->end_chunk != c, "tail chunk should not be updated");
1244   SFIFO_TEST (f->size == fifo_size + 100, "size expected %u is %u",
1245               fifo_size + 100, f->size);
1246   SFIFO_TEST (c->start_byte == fifo_size + 100, "start byte expected %u is "
1247               " %u", fifo_size + 100, c->start_byte);
1248   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1249
1250   /*
1251    * Unwrap fifo
1252    */
1253   vec_validate (data_buf, 200);
1254   svm_fifo_dequeue (f, 201, data_buf);
1255
1256   SFIFO_TEST (f->end_chunk == c, "tail chunk should be updated");
1257   SFIFO_TEST (f->size == fifo_size + 200, "size expected %u is %u",
1258               fifo_size + 200, f->size);
1259   SFIFO_TEST (c->start_byte == fifo_size + 100, "start byte expected %u is "
1260               "%u", fifo_size + 100, c->start_byte);
1261   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1262
1263   /*
1264    * Add N chunks
1265    */
1266   svm_fifo_init_pointers (f, f->nitems - 100, f->nitems + 100);
1267
1268   prev = 0;
1269   for (i = 0; i < 5; i++)
1270     {
1271       c = clib_mem_alloc (sizeof (svm_fifo_chunk_t) + 100);
1272       c->length = 100;
1273       c->start_byte = ~0;
1274       c->next = prev;
1275       prev = c;
1276     }
1277
1278   svm_fifo_add_chunk (f, c);
1279   SFIFO_TEST (f->size == fifo_size + 200, "size expected %u is %u",
1280               fifo_size + 200, f->size);
1281   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1282
1283   prev = 0;
1284   for (i = 0; i < 5; i++)
1285     {
1286       c = clib_mem_alloc (sizeof (svm_fifo_chunk_t) + 100);
1287       c->length = 100;
1288       c->start_byte = ~0;
1289       c->next = prev;
1290       prev = c;
1291     }
1292
1293   svm_fifo_add_chunk (f, c);
1294   SFIFO_TEST (f->size == fifo_size + 200, "size expected %u is %u",
1295               fifo_size + 200, f->size);
1296
1297   old_tail = f->tail;
1298   svm_fifo_dequeue (f, 101, data_buf);
1299
1300   SFIFO_TEST (f->size == fifo_size + 200 + 10 * 100, "size expected %u is %u",
1301               fifo_size + 200 + 10 * 100, f->size);
1302   SFIFO_TEST (f->tail == old_tail, "new tail expected %u is %u", old_tail,
1303               f->tail);
1304   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1305
1306   /*
1307    * Enqueue/dequeue tests
1308    */
1309
1310   test_n_bytes = f->nitems;
1311   vec_validate (test_data, test_n_bytes - 1);
1312   vec_validate (data_buf, vec_len (test_data));
1313   n_deqs = n_enqs = 6;
1314   deq_bytes = enq_bytes = vec_len (test_data) / n_deqs;
1315
1316   for (i = 0; i < vec_len (test_data); i++)
1317     test_data[i] = i;
1318
1319   /*
1320    * Enqueue/deq boundary conditions
1321    */
1322   svm_fifo_init_pointers (f, 201, 201);
1323   SFIFO_TEST (f->tail_chunk->start_byte == 201, "start byte expected %u is "
1324               "%u", 201, f->tail_chunk->start_byte);
1325
1326   svm_fifo_enqueue (f, 200, test_data);
1327   SFIFO_TEST (f->tail_chunk->start_byte == 401, "start byte expected %u is "
1328               "%u", 401, f->tail_chunk->start_byte);
1329
1330   svm_fifo_dequeue (f, 200, data_buf);
1331   SFIFO_TEST (f->head_chunk->start_byte == 401, "start byte expected %u is "
1332               "%u", 401, f->head_chunk->start_byte);
1333
1334   /*
1335    * Simple enqueue/deq and data validation (1)
1336    */
1337   svm_fifo_init_pointers (f, f->nitems / 2, f->nitems / 2);
1338   for (i = 0; i < test_n_bytes; i++)
1339     {
1340       rv = svm_fifo_enqueue (f, sizeof (u8), &test_data[i]);
1341       if (rv < 0)
1342         {
1343           clib_warning ("enqueue returned %d", rv);
1344           goto cleanup;
1345         }
1346     }
1347
1348   SFIFO_TEST (svm_fifo_max_dequeue (f) == test_n_bytes, "max deq expected %u "
1349               "is %u", test_n_bytes, svm_fifo_max_dequeue (f));
1350
1351   for (i = 0; i < test_n_bytes; i++)
1352     svm_fifo_dequeue (f, 1, &data_buf[i]);
1353
1354   rv = compare_data (data_buf, test_data, 0, vec_len (test_data),
1355                      (u32 *) & j);
1356   if (rv)
1357     vlib_cli_output (vm, "[%d] dequeued %u expected %u", j, data_buf[j],
1358                      test_data[j]);
1359   SFIFO_TEST ((rv == 0), "dequeued compared to original returned %d", rv);
1360   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1361
1362   /*
1363    * Simple enqueue/deq and data validation (2)
1364    */
1365   for (i = 0; i <= n_enqs; i++)
1366     {
1367       rv = svm_fifo_enqueue (f, enq_bytes, test_data + i * enq_bytes);
1368       if (rv < 0)
1369         {
1370           clib_warning ("enqueue returned %d", rv);
1371           goto cleanup;
1372         }
1373     }
1374
1375   SFIFO_TEST (svm_fifo_max_dequeue (f) == test_n_bytes, "max deq expected %u "
1376               "is %u", test_n_bytes, svm_fifo_max_dequeue (f));
1377
1378   for (i = 0; i <= n_deqs; i++)
1379     svm_fifo_dequeue (f, deq_bytes, data_buf + i * deq_bytes);
1380
1381   rv = compare_data (data_buf, test_data, 0, vec_len (test_data),
1382                      (u32 *) & j);
1383   if (rv)
1384     vlib_cli_output (vm, "[%d] dequeued %u expected %u", j, data_buf[j],
1385                      test_data[j]);
1386   SFIFO_TEST ((rv == 0), "dequeued compared to original returned %d", rv);
1387   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1388
1389   /*
1390    * Simple enqueue and drop
1391    */
1392   for (i = 0; i <= n_enqs; i++)
1393     {
1394       rv = svm_fifo_enqueue (f, enq_bytes, test_data + i * enq_bytes);
1395       if (rv < 0)
1396         SFIFO_TEST (0, "failed to enqueue");
1397     }
1398
1399   rv = svm_fifo_dequeue_drop (f, test_n_bytes / 2);
1400   SFIFO_TEST (rv == test_n_bytes / 2, "drop should be equal");
1401   SFIFO_TEST (svm_fifo_is_sane (f), "head chunk should be valid");
1402   rv = svm_fifo_dequeue_drop (f, test_n_bytes / 2);
1403   SFIFO_TEST (rv == test_n_bytes / 2, "drop should be equal");
1404   SFIFO_TEST (svm_fifo_is_sane (f), "head chunk should be valid");
1405   SFIFO_TEST (svm_fifo_max_dequeue (f) == 0, "should be empty");
1406
1407   /*
1408    * Simple enqueue and drop all
1409    */
1410
1411   /* Enqueue just enough data to make sure fifo is not full */
1412   for (i = 0; i <= n_enqs / 2; i++)
1413     {
1414       rv = svm_fifo_enqueue (f, enq_bytes, test_data + i * enq_bytes);
1415       if (rv < 0)
1416         SFIFO_TEST (0, "failed to enqueue");
1417     }
1418
1419   /* check drop all as well */
1420   svm_fifo_dequeue_drop_all (f);
1421   SFIFO_TEST (svm_fifo_is_sane (f), "head chunk should be valid");
1422   SFIFO_TEST (svm_fifo_max_dequeue (f) == 0, "should be empty");
1423
1424   /*
1425    * OOO enqueues/dequeues and data validation (1)
1426    */
1427   for (i = test_n_bytes - 1; i > 0; i--)
1428     {
1429       rv = svm_fifo_enqueue_with_offset (f, i, sizeof (u8), &test_data[i]);
1430       if (verbose)
1431         vlib_cli_output (vm, "add [%d] [%d, %d]", i, i, i + sizeof (u8));
1432       if (rv)
1433         {
1434           clib_warning ("enqueue returned %d", rv);
1435           goto cleanup;
1436         }
1437     }
1438
1439   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1440   SFIFO_TEST (svm_fifo_max_dequeue (f) == 0, "max deq expected %u is %u",
1441               0, svm_fifo_max_dequeue (f));
1442
1443   svm_fifo_enqueue (f, sizeof (u8), &test_data[0]);
1444
1445   memset (data_buf, 0, vec_len (data_buf));
1446   offset = 0;
1447   for (i = 0; i <= n_deqs; i++)
1448     {
1449       rv = svm_fifo_peek (f, offset, deq_bytes, data_buf + i * deq_bytes);
1450       if (rv < 0 || (rv != deq_bytes && i != n_deqs))
1451         SFIFO_TEST (0, "unexpected peek %d", rv);
1452       offset += rv;
1453     }
1454   svm_fifo_dequeue_drop (f, offset);
1455
1456   rv = compare_data (data_buf, test_data, 0, vec_len (test_data),
1457                      (u32 *) & j);
1458   if (rv)
1459     vlib_cli_output (vm, "[%d] dequeued %u expected %u", j, data_buf[j],
1460                      test_data[j]);
1461   SFIFO_TEST ((rv == 0), "dequeued compared to original returned %d", rv);
1462   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1463
1464   /*
1465    * OOO enqueues/dequeues and data validation (2)
1466    */
1467
1468   for (i = n_enqs; i > 0; i--)
1469     {
1470       u32 enq_now = clib_min (enq_bytes, vec_len (test_data) - i * enq_bytes);
1471       rv = svm_fifo_enqueue_with_offset (f, i * enq_bytes, enq_now,
1472                                          test_data + i * enq_bytes);
1473       if (verbose)
1474         vlib_cli_output (vm, "add [%d, %d]", i * enq_bytes,
1475                          i * enq_bytes + enq_now);
1476       if (rv)
1477         {
1478           clib_warning ("enqueue returned %d", rv);
1479           goto cleanup;
1480         }
1481     }
1482   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1483
1484   svm_fifo_enqueue (f, enq_bytes, &test_data[0]);
1485   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1486
1487   memset (data_buf, 0, vec_len (data_buf));
1488   for (i = 0; i <= n_deqs; i++)
1489     svm_fifo_dequeue (f, deq_bytes, data_buf + i * deq_bytes);
1490
1491   rv = compare_data (data_buf, test_data, 0, vec_len (test_data),
1492                      (u32 *) & j);
1493   if (rv)
1494     vlib_cli_output (vm, "[%d] dequeued %u expected %u", j, data_buf[j],
1495                      test_data[j]);
1496   SFIFO_TEST ((rv == 0), "dequeued compared to original returned %d", rv);
1497   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1498
1499   /*
1500    * Cleanup
1501    */
1502
1503 cleanup:
1504
1505   c = f->start_chunk->next;
1506   while (c && c != f->start_chunk)
1507     {
1508       next = c->next;
1509       clib_mem_free (c);
1510       c = next;
1511     }
1512
1513   svm_fifo_free (f);
1514   vec_free (test_data);
1515   vec_free (data_buf);
1516   return 0;
1517 }
1518
1519 static int
1520 chunk_list_len (svm_fifo_chunk_t * c)
1521 {
1522   svm_fifo_chunk_t *it;
1523   int count = 0;
1524
1525   if (!c)
1526     return 0;
1527
1528   count = 1;
1529   it = c->next;
1530   while (it && it != c)
1531     {
1532       it = it->next;
1533       count++;
1534     }
1535   return count;
1536 }
1537
1538 static void
1539 chunk_list_free (svm_fifo_chunk_t * c, svm_fifo_chunk_t * stop)
1540 {
1541   svm_fifo_chunk_t *it, *next;
1542
1543   it = c;
1544   while (it && it != stop)
1545     {
1546       next = it->next;
1547       clib_mem_free (it);
1548       it = next;
1549     }
1550 }
1551
1552 static void
1553 chunk_list_splice (svm_fifo_chunk_t * a, svm_fifo_chunk_t * b)
1554 {
1555   svm_fifo_chunk_t *it;
1556
1557   it = a;
1558   while (it->next)
1559     it = it->next;
1560   it->next = b;
1561 }
1562
1563 static int
1564 sfifo_test_fifo_shrink (vlib_main_t * vm, unformat_input_t * input)
1565 {
1566   int __clib_unused verbose = 0, fifo_size = 101, chunk_size = 100;
1567   int i, rv, test_n_bytes, diff, deq_bytes;
1568   svm_fifo_chunk_t *c, *prev, *collected;
1569   u8 *test_data = 0, *data_buf = 0;
1570   svm_fifo_t *f;
1571
1572   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1573     {
1574       if (unformat (input, "verbose"))
1575         verbose = 1;
1576       else
1577         {
1578           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
1579                            input);
1580           return -1;
1581         }
1582     }
1583
1584   /*
1585    * Init fifo with multiple chunks
1586    */
1587   f = fifo_prepare (fifo_size);
1588   svm_fifo_init_pointers (f, 0, 0);
1589
1590   prev = 0;
1591   for (i = 0; i < 11; i++)
1592     {
1593       c = clib_mem_alloc (sizeof (svm_fifo_chunk_t) + chunk_size);
1594       c->length = 100;
1595       c->start_byte = ~0;
1596       c->next = prev;
1597       prev = c;
1598     }
1599
1600   svm_fifo_add_chunk (f, c);
1601   SFIFO_TEST (f->size == 12 * chunk_size + 1, "size expected %u is %u",
1602               12 * chunk_size + 1, f->size);
1603
1604   /*
1605    * No fifo wrap and no chunk used (one chunk)
1606    */
1607   rv = svm_fifo_reduce_size (f, chunk_size, 0);
1608   SFIFO_TEST (rv == chunk_size, "len expected %u is %u", chunk_size, rv);
1609   SFIFO_TEST (f->size == 12 * chunk_size + 1, "size expected %u is %u",
1610               12 * chunk_size + 1, f->size);
1611   SFIFO_TEST (f->flags & SVM_FIFO_F_SHRINK, "shrink flag should be set");
1612   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1613
1614   /* Check enqueue space to force size reduction */
1615   (void) svm_fifo_max_enqueue (f);
1616
1617   SFIFO_TEST (f->size == 11 * chunk_size + 1, "size expected %u is %u",
1618               11 * chunk_size + 1, f->size);
1619   SFIFO_TEST (f->flags & SVM_FIFO_F_COLLECT_CHUNKS, "collect flag should"
1620               " be set");
1621   SFIFO_TEST (!(f->flags & SVM_FIFO_F_SHRINK), "shrink flag should not be"
1622               " set");
1623   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1624
1625   collected = c = svm_fifo_collect_chunks (f);
1626   rv = chunk_list_len (c);
1627   SFIFO_TEST (rv == 1, "expected %u chunks got %u", 1, rv);
1628   rv = chunk_list_len (f->start_chunk);
1629   SFIFO_TEST (rv == 11, "expected %u chunks got %u", 11, rv);
1630   SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should"
1631               " not be set");
1632   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1633
1634   /*
1635    * Fifo wrap and multiple chunks used
1636    */
1637
1638   /* Init test data and fifo */
1639   test_n_bytes = f->nitems;
1640   vec_validate (test_data, test_n_bytes - 1);
1641   vec_validate (data_buf, vec_len (test_data));
1642
1643   for (i = 0; i < vec_len (test_data); i++)
1644     test_data[i] = i;
1645
1646   svm_fifo_init_pointers (f, f->size / 2, f->size / 2);
1647   for (i = 0; i < test_n_bytes; i++)
1648     {
1649       rv = svm_fifo_enqueue (f, sizeof (u8), &test_data[i]);
1650       if (rv < 0)
1651         SFIFO_TEST (0, "enqueue returned");
1652     }
1653
1654   /* Try to reduce fifo size with fifo full */
1655   rv = svm_fifo_reduce_size (f, 3.5 * chunk_size, 0);
1656   SFIFO_TEST (rv == 3 * chunk_size, "len expected %u is %u", 3 * chunk_size,
1657               rv);
1658   SFIFO_TEST (f->size == 11 * chunk_size + 1, "size expected %u is %u",
1659               11 * chunk_size + 1, f->size);
1660   SFIFO_TEST (f->flags & SVM_FIFO_F_SHRINK, "shrink flag should be set");
1661   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1662
1663   /* Check enqueue space to try size reduction. Should not work */
1664   rv = svm_fifo_max_enqueue (f);
1665
1666   SFIFO_TEST (rv == 0, "free space expected %u is %u", 0, rv);
1667   SFIFO_TEST (f->size == 11 * chunk_size + 1, "size expected %u is %u",
1668               11 * chunk_size + 1, f->size);
1669   SFIFO_TEST (f->flags & SVM_FIFO_F_SHRINK, "shrink flag should be set");
1670   SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should"
1671               " not be set");
1672   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1673
1674   /* Dequeue byte-by-byte up to last byte on last chunk */
1675   deq_bytes = f->size - f->size / 2 - 1;
1676   for (i = 0; i < deq_bytes; i++)
1677     {
1678       (void) svm_fifo_max_enqueue (f);
1679       rv = svm_fifo_dequeue (f, 1, &data_buf[i]);
1680       if (rv < 0)
1681         SFIFO_TEST (0, "dequeue returned");
1682     }
1683   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1684
1685   rv = svm_fifo_max_enqueue (f);
1686
1687   /* We've dequeued more than 3*chunk_size so nitems should be updated */
1688   SFIFO_TEST (f->nitems == 8 * chunk_size, "nitems expected %u is %u",
1689               8 * chunk_size, f->nitems);
1690   /* Free space should be what was dequeued - 3 * chunk_size, which was
1691    * consumed by shrinking the fifo */
1692   diff = deq_bytes - 3 * chunk_size;
1693   SFIFO_TEST (rv == diff, "free space expected %u is %u", diff, rv);
1694   SFIFO_TEST (f->size == 11 * chunk_size + 1, "size expected %u is %u",
1695               11 * chunk_size + 1, f->size);
1696   SFIFO_TEST (f->flags & SVM_FIFO_F_SHRINK, "shrink flag should be set");
1697   SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should"
1698               " not be set");
1699   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1700
1701   /* Dequeue one more such that head goes beyond last chunk */
1702   rv = svm_fifo_dequeue (f, 1, &data_buf[deq_bytes]);
1703   if (rv < 0)
1704     SFIFO_TEST (0, "dequeue returned");
1705
1706   rv = svm_fifo_max_enqueue (f);
1707   SFIFO_TEST (f->nitems == 8 * chunk_size, "nitems expected %u is %u",
1708               8 * chunk_size, f->nitems);
1709   SFIFO_TEST (rv == diff + 1, "free space expected %u is %u", diff + 1, rv);
1710   SFIFO_TEST (f->size == 8 * chunk_size + 1, "size expected %u is %u",
1711               8 * chunk_size + 1, f->size);
1712   SFIFO_TEST (!(f->flags & SVM_FIFO_F_SHRINK), "shrink flag should not be"
1713               " set");
1714   SFIFO_TEST (f->flags & SVM_FIFO_F_COLLECT_CHUNKS, "collect flag should"
1715               " be set");
1716   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1717
1718   /* Dequeue the rest of the data */
1719   deq_bytes += 1;
1720   for (i = 0; i < test_n_bytes - deq_bytes; i++)
1721     {
1722       rv = svm_fifo_dequeue (f, 1, &data_buf[i + deq_bytes]);
1723       if (rv < 0)
1724         SFIFO_TEST (0, "dequeue returned");
1725     }
1726
1727   rv = svm_fifo_max_enqueue (f);
1728
1729   SFIFO_TEST (f->size == 8 * chunk_size + 1, "size expected %u is %u",
1730               8 * chunk_size + 1, f->size);
1731   SFIFO_TEST (rv == 8 * chunk_size, "free space expected %u is %u",
1732               8 * chunk_size, rv);
1733
1734   rv = compare_data (data_buf, test_data, 0, vec_len (test_data),
1735                      (u32 *) & i);
1736   if (rv)
1737     SFIFO_TEST (0, "[%d] dequeued %u expected %u", i, data_buf[i],
1738                 test_data[i]);
1739
1740   c = svm_fifo_collect_chunks (f);
1741   rv = chunk_list_len (c);
1742   SFIFO_TEST (rv == 3, "expected %u chunks got %u", 3, rv);
1743   rv = chunk_list_len (f->start_chunk);
1744   SFIFO_TEST (rv == 8, "expected %u chunks got %u", 8, rv);
1745   SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should"
1746               " not be set");
1747   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1748
1749   /*
1750    * OOO segment on chunk that should be removed
1751    */
1752
1753   svm_fifo_add_chunk (f, c);
1754   SFIFO_TEST (f->size == 11 * chunk_size + 1, "size expected %u is %u",
1755               11 * chunk_size + 1, f->size);
1756
1757   memset (data_buf, 0, vec_len (data_buf));
1758   svm_fifo_init_pointers (f, f->size / 2, f->size / 2);
1759   svm_fifo_enqueue (f, 200, test_data);
1760   svm_fifo_enqueue_with_offset (f, 50, vec_len (test_data) - 250,
1761                                 &test_data[250]);
1762   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1763
1764   /* Free space */
1765   rv = svm_fifo_max_enqueue (f);
1766   SFIFO_TEST (rv == vec_len (test_data) - 200, "free space expected %u is %u",
1767               vec_len (test_data) - 200, rv);
1768   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1769
1770   /* Ask to reduce size */
1771   rv = svm_fifo_reduce_size (f, 3.5 * chunk_size, 0);
1772   SFIFO_TEST (rv == 3 * chunk_size, "len expected %u is %u", 3 * chunk_size,
1773               rv);
1774   SFIFO_TEST (f->size == 11 * chunk_size + 1, "size expected %u is %u",
1775               11 * chunk_size + 1, f->size);
1776   SFIFO_TEST (f->flags & SVM_FIFO_F_SHRINK, "shrink flag should be set");
1777   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1778
1779   /* Try to force size reduction but it should fail */
1780   rv = svm_fifo_max_enqueue (f);
1781
1782   SFIFO_TEST (rv == vec_len (test_data) - 200, "free space expected %u is %u",
1783               vec_len (test_data) - 200, rv);
1784   SFIFO_TEST (f->size == 11 * chunk_size + 1, "size expected %u is %u",
1785               11 * chunk_size + 1, f->size);
1786   SFIFO_TEST (f->flags & SVM_FIFO_F_SHRINK, "shrink flag should be set");
1787   SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should"
1788               " not be set");
1789   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1790
1791   /* Dequeue the in order data. This should shrink nitems */
1792   rv = svm_fifo_dequeue (f, 200, data_buf);
1793   if (rv < 0)
1794     SFIFO_TEST (0, "dequeue returned");
1795
1796   rv = svm_fifo_max_enqueue (f);
1797   SFIFO_TEST (rv == vec_len (test_data) - 200, "free space expected %u is %u",
1798               vec_len (test_data) - 200, rv);
1799   SFIFO_TEST (f->size == 11 * chunk_size + 1, "size expected %u is %u",
1800               11 * chunk_size + 1, f->size);
1801   SFIFO_TEST (f->nitems == 11 * chunk_size - 200, "nitems expected %u is %u",
1802               11 * chunk_size - 200, f->nitems);
1803   SFIFO_TEST (f->flags & SVM_FIFO_F_SHRINK, "shrink flag should be set");
1804   SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should"
1805               " not be set");
1806   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1807
1808   /* Enqueue the missing 50 bytes. Fifo will become full */
1809   rv = svm_fifo_enqueue (f, 50, &test_data[200]);
1810   SFIFO_TEST (rv == vec_len (test_data) - 200, "free space expected %u is %u",
1811               vec_len (test_data) - 200, rv);
1812   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1813
1814   rv = svm_fifo_max_enqueue (f);
1815
1816   SFIFO_TEST (rv == 0, "free space expected %u is %u", 0, rv);
1817   SFIFO_TEST (f->size == 11 * chunk_size + 1, "size expected %u is %u",
1818               11 * chunk_size + 1, f->size);
1819   SFIFO_TEST (f->flags & SVM_FIFO_F_SHRINK, "shrink flag should be set");
1820   SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should"
1821               " not be set");
1822   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1823
1824
1825   /* Dequeue a chunk and check nitems shrink but fifo still full */
1826   svm_fifo_dequeue (f, 100, &data_buf[200]);
1827
1828   rv = svm_fifo_max_enqueue (f);
1829
1830   SFIFO_TEST (rv == 0, "free space expected %u is %u", 0, rv);
1831   SFIFO_TEST (f->size == 11 * chunk_size + 1, "size expected %u is %u",
1832               11 * chunk_size + 1, f->size);
1833   SFIFO_TEST (f->nitems == 11 * chunk_size - 300, "nitems expected %u is %u",
1834               11 * chunk_size - 300, f->nitems);
1835   SFIFO_TEST (f->flags & SVM_FIFO_F_SHRINK, "shrink flag should be set");
1836   SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should"
1837               " not be set");
1838   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1839
1840   /* Dequeue enough to unwrap the fifo */
1841   deq_bytes = f->size - f->size / 2 - 300;
1842   svm_fifo_dequeue (f, deq_bytes, &data_buf[300]);
1843   rv = svm_fifo_max_enqueue (f);
1844
1845   /* Overall we've dequeued deq_bytes + 300, but fifo size shrunk 300 */
1846   SFIFO_TEST (rv == 300 + deq_bytes - 300, "free space expected %u is %u",
1847               300 + deq_bytes - 300, rv);
1848   SFIFO_TEST (f->size == 8 * chunk_size + 1, "size expected %u is %u",
1849               8 * chunk_size + 1, f->size);
1850   SFIFO_TEST (f->nitems == 8 * chunk_size, "nitems expected %u is %u",
1851               8 * chunk_size, f->nitems);
1852   SFIFO_TEST (!(f->flags & SVM_FIFO_F_SHRINK), "shrink flag should not be"
1853               " set");
1854   SFIFO_TEST (f->flags & SVM_FIFO_F_COLLECT_CHUNKS, "collect flag should"
1855               " be set");
1856   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1857
1858   /* Dequeue the rest */
1859   svm_fifo_dequeue (f, test_n_bytes / 2, &data_buf[300 + deq_bytes]);
1860   rv = compare_data (data_buf, test_data, 0, vec_len (test_data),
1861                      (u32 *) & i);
1862   if (rv)
1863     SFIFO_TEST (0, "[%d] dequeued %u expected %u", i, data_buf[i],
1864                 test_data[i]);
1865
1866   c = svm_fifo_collect_chunks (f);
1867   rv = chunk_list_len (c);
1868   SFIFO_TEST (rv == 3, "expected %u chunks got %u", 3, rv);
1869   rv = chunk_list_len (f->start_chunk);
1870   SFIFO_TEST (rv == 8, "expected %u chunks got %u", 8, rv);
1871   SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should"
1872               " not be set");
1873   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1874
1875   chunk_list_splice (collected, c);
1876
1877   /*
1878    * Remove all chunks possible (1)
1879    *
1880    * Tail and head are in first chunk that is not removed
1881    */
1882   svm_fifo_init_pointers (f, 600, 600);
1883   rv = svm_fifo_reduce_size (f, 8 * chunk_size, 1);
1884   SFIFO_TEST (rv == 7 * chunk_size, "actual len expected %u is %u",
1885               7 * chunk_size, rv);
1886   SFIFO_TEST (f->size == 6 * chunk_size + 1, "size expected %u is %u",
1887               6 * chunk_size + 1, f->size);
1888   SFIFO_TEST (f->nitems == 1 * chunk_size, "nitems expected %u is %u",
1889               1 * chunk_size, f->nitems);
1890   SFIFO_TEST (f->flags & SVM_FIFO_F_SHRINK, "shrink flag should be set");
1891   SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should"
1892               " not be set");
1893   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1894
1895   rv = svm_fifo_max_enqueue (f);
1896   SFIFO_TEST (rv == chunk_size, "free space expected %u is %u", chunk_size,
1897               rv);
1898   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1899
1900   /* Force head/tail to move to first chunk */
1901   svm_fifo_enqueue (f, 1, test_data);
1902   svm_fifo_dequeue (f, 1, data_buf);
1903   rv = svm_fifo_max_enqueue (f);
1904
1905   SFIFO_TEST (rv == chunk_size, "free space expected %u is %u", chunk_size,
1906               rv);
1907   SFIFO_TEST (f->size == chunk_size + 1, "size expected %u is %u",
1908               chunk_size + 1, f->size);
1909   SFIFO_TEST (!(f->flags & SVM_FIFO_F_SHRINK), "shrink flag should not be"
1910               " set");
1911   SFIFO_TEST (f->flags & SVM_FIFO_F_COLLECT_CHUNKS, "collect flag should"
1912               " be set");
1913   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1914
1915   c = svm_fifo_collect_chunks (f);
1916   rv = chunk_list_len (c);
1917   SFIFO_TEST (rv == 7, "expected %u chunks got %u", 7, rv);
1918   SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should"
1919               " not be set");
1920   SFIFO_TEST (!(f->flags & SVM_FIFO_F_MULTI_CHUNK), "multi-chunk flag should"
1921               " not be set");
1922   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1923
1924   /* re-add chunks for next test */
1925   svm_fifo_add_chunk (f, c);
1926
1927   /*
1928    * Remove all chunks possible (2)
1929    *
1930    * Tail and head are in the first chunk that should eventually be removed
1931    */
1932   svm_fifo_init_pointers (f, 601, 601);
1933   rv = svm_fifo_reduce_size (f, 8 * chunk_size, 1);
1934   SFIFO_TEST (rv == 7 * chunk_size, "actual len expected %u is %u",
1935               7 * chunk_size, rv);
1936   SFIFO_TEST (f->size == 7 * chunk_size + 1, "size expected %u is %u",
1937               7 * chunk_size + 1, f->size);
1938   SFIFO_TEST (f->nitems == 1 * chunk_size, "nitems expected %u is %u",
1939               1 * chunk_size, f->nitems);
1940   SFIFO_TEST (f->flags & SVM_FIFO_F_SHRINK, "shrink flag should be set");
1941   SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should"
1942               " not be set");
1943   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1944
1945   rv = svm_fifo_max_enqueue (f);
1946   SFIFO_TEST (rv == chunk_size, "free space expected %u is %u", chunk_size,
1947               rv);
1948   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1949
1950   /* Force head/tail to move to first chunk */
1951   svm_fifo_enqueue (f, chunk_size, test_data);
1952   svm_fifo_dequeue (f, chunk_size, data_buf);
1953   rv = svm_fifo_max_enqueue (f);
1954
1955   SFIFO_TEST (rv == chunk_size, "free space expected %u is %u", chunk_size,
1956               rv);
1957   SFIFO_TEST (f->size == chunk_size + 1, "size expected %u is %u",
1958               chunk_size + 1, f->size);
1959   SFIFO_TEST (!(f->flags & SVM_FIFO_F_SHRINK), "shrink flag should not be"
1960               " set");
1961   SFIFO_TEST (f->flags & SVM_FIFO_F_COLLECT_CHUNKS, "collect flag should"
1962               " be set");
1963   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1964
1965   c = svm_fifo_collect_chunks (f);
1966   rv = chunk_list_len (c);
1967   SFIFO_TEST (rv == 7, "expected %u chunks got %u", 7, rv);
1968   SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should"
1969               " not be set");
1970   SFIFO_TEST (!(f->flags & SVM_FIFO_F_MULTI_CHUNK), "multi-chunk flag should"
1971               " not be set");
1972   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1973
1974   chunk_list_splice (collected, c);
1975
1976   /*
1977    * Cleanup
1978    */
1979
1980   chunk_list_free (f->start_chunk->next, f->start_chunk);
1981   chunk_list_free (collected, 0);
1982   svm_fifo_free (f);
1983   vec_free (test_data);
1984   vec_free (data_buf);
1985
1986   return 0;
1987 }
1988
1989 /* *INDENT-OFF* */
1990 svm_fifo_trace_elem_t fifo_trace[] = {};
1991 /* *INDENT-ON* */
1992
1993 static int
1994 sfifo_test_fifo_replay (vlib_main_t * vm, unformat_input_t * input)
1995 {
1996   svm_fifo_t f;
1997   int verbose = 0;
1998   u8 no_read = 0, *str = 0;
1999
2000   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2001     {
2002       if (unformat (input, "verbose"))
2003         verbose = 1;
2004       else if (unformat (input, "no-read"))
2005         no_read = 1;
2006       else
2007         {
2008           clib_error_t *e = clib_error_return
2009             (0, "unknown input `%U'", format_unformat_error, input);
2010           clib_error_report (e);
2011           return -1;
2012         }
2013     }
2014
2015 #if SVMF_FIFO_TRACE
2016   f.trace = fifo_trace;
2017 #endif
2018
2019   str = svm_fifo_replay (str, &f, no_read, verbose);
2020   vlib_cli_output (vm, "%v", str);
2021   return 0;
2022 }
2023
2024 static fifo_segment_main_t segment_main;
2025
2026 static svm_fifo_t *
2027 fifo_segment_alloc_fifo (fifo_segment_t * fs, u32 data_bytes,
2028                          fifo_segment_ftype_t ftype)
2029 {
2030   return fifo_segment_alloc_fifo_w_slice (fs, 0, data_bytes, ftype);
2031 }
2032
2033 static int
2034 sfifo_test_fifo_segment_hello_world (int verbose)
2035 {
2036   fifo_segment_create_args_t _a, *a = &_a;
2037   fifo_segment_main_t *sm = &segment_main;
2038   u8 *test_data, *retrieved_data = 0;
2039   fifo_segment_t *fs;
2040   svm_fifo_t *f;
2041   int rv;
2042
2043   clib_memset (a, 0, sizeof (*a));
2044   a->segment_name = "fifo-test1";
2045   a->segment_size = 256 << 10;
2046
2047   rv = fifo_segment_create (sm, a);
2048   SFIFO_TEST (!rv, "svm_fifo_segment_create returned %d", rv);
2049
2050   fs = fifo_segment_get_segment (sm, a->new_segment_indices[0]);
2051   f = fifo_segment_alloc_fifo (fs, 4096, FIFO_SEGMENT_RX_FIFO);
2052
2053   SFIFO_TEST (f != 0, "svm_fifo_segment_alloc_fifo");
2054
2055   test_data = format (0, "Hello world%c", 0);
2056   vec_validate (retrieved_data, vec_len (test_data) - 1);
2057
2058   while (svm_fifo_max_enqueue (f) >= vec_len (test_data))
2059     svm_fifo_enqueue (f, vec_len (test_data), test_data);
2060
2061   while (svm_fifo_max_dequeue (f) >= vec_len (test_data))
2062     svm_fifo_dequeue (f, vec_len (retrieved_data), retrieved_data);
2063
2064   while (svm_fifo_max_enqueue (f) >= vec_len (test_data))
2065     svm_fifo_enqueue (f, vec_len (test_data), test_data);
2066
2067   while (svm_fifo_max_dequeue (f) >= vec_len (test_data))
2068     svm_fifo_dequeue (f, vec_len (retrieved_data), retrieved_data);
2069
2070   SFIFO_TEST (!memcmp (retrieved_data, test_data, vec_len (test_data)),
2071               "data should be identical");
2072
2073   vec_free (test_data);
2074   vec_free (retrieved_data);
2075   vec_free (a->new_segment_indices);
2076   fifo_segment_free_fifo (fs, f);
2077   fifo_segment_delete (sm, fs);
2078   return 0;
2079 }
2080
2081 static int
2082 sfifo_test_fifo_segment_fifo_grow (int verbose)
2083 {
2084   int rv, fifo_size = 4096, n_chunks, n_batch;
2085   fifo_segment_main_t *sm = &segment_main;
2086   fifo_segment_create_args_t _a, *a = &_a;
2087   u32 n_free_chunk_bytes;
2088   fifo_segment_t *fs;
2089   svm_fifo_t *f;
2090
2091   clib_memset (a, 0, sizeof (*a));
2092   a->segment_name = "fifo-test1";
2093   /* size chosen to be able to force multi chunk allocation lower */
2094   a->segment_size = 256 << 10;
2095
2096   /* fifo allocation allocates chunks in batch */
2097   n_batch = FIFO_SEGMENT_ALLOC_BATCH_SIZE;
2098
2099   rv = fifo_segment_create (sm, a);
2100
2101   SFIFO_TEST (!rv, "svm_fifo_segment_create returned %d", rv);
2102
2103   /*
2104    * Alloc and grow fifo
2105    */
2106   fs = fifo_segment_get_segment (sm, a->new_segment_indices[0]);
2107   f = fifo_segment_alloc_fifo (fs, fifo_size, FIFO_SEGMENT_RX_FIFO);
2108
2109   SFIFO_TEST (f != 0, "svm_fifo_segment_alloc_fifo");
2110
2111   n_chunks = fifo_segment_num_free_chunks (fs, fifo_size);
2112   SFIFO_TEST (n_chunks == n_batch - 1, "free 2^10B chunks "
2113               "should be %u is %u", n_batch - 1, n_chunks);
2114   rv = fifo_segment_fl_chunk_bytes (fs);
2115   SFIFO_TEST (rv == (n_batch - 1) * fifo_size, "free chunk bytes %u "
2116               "expected %u", rv, (n_batch - 1) * fifo_size);
2117
2118   /* Grow by preallocated fifo_size chunk */
2119   fifo_segment_grow_fifo (fs, f, fifo_size);
2120   SFIFO_TEST (f->size == 2 * fifo_size, "fifo size should be %u is %u",
2121               2 * fifo_size, f->size);
2122   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
2123
2124   n_chunks = fifo_segment_num_free_chunks (fs, fifo_size);
2125   SFIFO_TEST (n_chunks == n_batch - 2, "free 2^10B chunks "
2126               "should be %u is %u", n_batch - 2, n_chunks);
2127   rv = fifo_segment_fl_chunk_bytes (fs);
2128   SFIFO_TEST (rv == (n_batch - 2) * fifo_size, "free chunk bytes %u "
2129               "expected %u", rv, (n_batch - 2) * fifo_size);
2130
2131   /* Grow by a size not preallocated but first make sure there's space */
2132   rv = fifo_segment_free_bytes (fs);
2133   SFIFO_TEST (rv > 16 * fifo_size, "free bytes %u more than %u", rv,
2134               16 * fifo_size);
2135
2136   fifo_segment_grow_fifo (fs, f, 16 * fifo_size);
2137   SFIFO_TEST (f->size == 18 * fifo_size, "fifo size should be %u is %u",
2138               18 * fifo_size, f->size);
2139
2140   rv = fifo_segment_fl_chunk_bytes (fs);
2141   SFIFO_TEST (rv == (n_batch - 2) * fifo_size, "free chunk bytes %u "
2142               "expected %u", rv, (n_batch - 2) * fifo_size);
2143
2144   /*
2145    * Free and test free list size
2146    */
2147   fifo_segment_free_fifo (fs, f);
2148
2149   rv = fifo_segment_fl_chunk_bytes (fs);
2150   SFIFO_TEST (rv == (16 + n_batch) * fifo_size, "free chunk bytes expected %u"
2151               " is %u", (16 + n_batch) * fifo_size, rv);
2152   n_chunks = fifo_segment_num_free_chunks (fs, fifo_size);
2153   SFIFO_TEST (n_chunks == n_batch, "free 2^10B chunks "
2154               "should be %u is %u", n_batch, n_chunks);
2155   n_chunks = fifo_segment_num_free_chunks (fs, 16 * fifo_size);
2156   SFIFO_TEST (n_chunks == 1, "free 2^14B chunks should be %u is %u", 1,
2157               n_chunks);
2158   n_chunks = fifo_segment_num_free_chunks (fs, ~0);
2159   SFIFO_TEST (n_chunks == 1 + n_batch, "free chunks should be %u is %u",
2160               1 + n_batch, n_chunks);
2161
2162   /*
2163    * Realloc fifo
2164    */
2165   f = fifo_segment_alloc_fifo (fs, fifo_size, FIFO_SEGMENT_RX_FIFO);
2166
2167   fifo_segment_grow_fifo (fs, f, fifo_size);
2168   n_chunks = fifo_segment_num_free_chunks (fs, fifo_size);
2169   SFIFO_TEST (n_chunks == n_batch - 2, "free 2^10B chunks should be %u is %u",
2170               n_batch - 2, n_chunks);
2171
2172   fifo_segment_grow_fifo (fs, f, 16 * fifo_size);
2173   n_chunks = fifo_segment_num_free_chunks (fs, 16 * fifo_size);
2174   SFIFO_TEST (n_chunks == 0, "free 2^14B chunks should be %u is %u", 0,
2175               n_chunks);
2176   n_chunks = fifo_segment_num_free_chunks (fs, ~0);
2177   SFIFO_TEST (n_chunks == n_batch - 2, "free chunks should be %u is %u",
2178               n_batch - 2, n_chunks);
2179
2180   /*
2181    * Free again
2182    */
2183   fifo_segment_free_fifo (fs, f);
2184   n_chunks = fifo_segment_num_free_chunks (fs, ~0);
2185   SFIFO_TEST (n_chunks == 1 + n_batch, "free chunks should be %u is %u",
2186               1 + n_batch, n_chunks);
2187
2188   rv = fifo_segment_fl_chunk_bytes (fs);
2189   SFIFO_TEST (rv == (16 + n_batch) * fifo_size, "free chunk bytes expected %u"
2190               " is %u", (16 + n_batch) * fifo_size, rv);
2191
2192   n_free_chunk_bytes = rv;
2193
2194   /*
2195    * Allocate non power of 2 fifo/chunk and check that free chunk bytes
2196    * is correctly updated
2197    */
2198
2199   f = fifo_segment_alloc_fifo (fs, 16 * fifo_size - 1, FIFO_SEGMENT_RX_FIFO);
2200   rv = fifo_segment_fl_chunk_bytes (fs);
2201
2202   SFIFO_TEST (n_free_chunk_bytes - 16 * fifo_size == rv, "free chunk bytes "
2203               "expected %u is %u", n_free_chunk_bytes - 16 * fifo_size, rv);
2204   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
2205
2206   fifo_segment_free_fifo (fs, f);
2207   rv = fifo_segment_fl_chunk_bytes (fs);
2208
2209   SFIFO_TEST (n_free_chunk_bytes == rv, "free chunk bytes expected %u is %u",
2210               n_free_chunk_bytes, rv);
2211
2212   /*
2213    * Force multi chunk fifo allocation
2214    */
2215
2216   /* Check that we can force multi chunk allocation. Note that fifo size
2217    * rounded up to power of 2, i.e., 17 becomes 32 */
2218   rv = fifo_segment_free_bytes (fs);
2219   SFIFO_TEST (rv < 32 * fifo_size, "free bytes %u less than %u", rv,
2220               32 * fifo_size);
2221
2222   f = fifo_segment_alloc_fifo (fs, 17 * fifo_size, FIFO_SEGMENT_RX_FIFO);
2223   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
2224
2225   rv = fifo_segment_fl_chunk_bytes (fs);
2226
2227   /* Make sure that the non-power of two chunk freed above is correctly
2228    * accounted for in the chunk free bytes reduction due to chunk allocation
2229    * for the fifo, i.e., it's rounded up by 1 */
2230   SFIFO_TEST (n_free_chunk_bytes - 17 * fifo_size == rv, "free chunk bytes "
2231               "expected %u is %u", n_free_chunk_bytes - 17 * fifo_size, rv);
2232
2233   fifo_segment_free_fifo (fs, f);
2234
2235   rv = fifo_segment_fl_chunk_bytes (fs);
2236   SFIFO_TEST (n_free_chunk_bytes == rv, "free chunk bytes expected %u is %u",
2237               n_free_chunk_bytes, rv);
2238
2239   /*
2240    * Allocate fifo that has all chunks
2241    */
2242   f = fifo_segment_alloc_fifo (fs, n_free_chunk_bytes, FIFO_SEGMENT_RX_FIFO);
2243   SFIFO_TEST (f != 0, "allocation should work");
2244   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
2245
2246   fifo_segment_free_fifo (fs, f);
2247
2248   rv = fifo_segment_fl_chunk_bytes (fs);
2249   SFIFO_TEST (n_free_chunk_bytes == rv, "free chunk bytes expected %u is %u",
2250               n_free_chunk_bytes, rv);
2251
2252   /*
2253    * Try to allocate more than space available
2254    */
2255
2256   f = fifo_segment_alloc_fifo (fs, n_free_chunk_bytes + fifo_size,
2257                                FIFO_SEGMENT_RX_FIFO);
2258   SFIFO_TEST (f == 0, "allocation should fail");
2259
2260   /*
2261    * Allocate fifo and try to grow beyond available space
2262    */
2263   f = fifo_segment_alloc_fifo (fs, fifo_size, FIFO_SEGMENT_RX_FIFO);
2264   rv = fifo_segment_grow_fifo (fs, f, n_free_chunk_bytes);
2265
2266   SFIFO_TEST (rv == -1, "grow should fail");
2267
2268   fifo_segment_free_fifo (fs, f);
2269
2270   /*
2271    * Cleanup
2272    */
2273   fifo_segment_delete (sm, fs);
2274   vec_free (a->new_segment_indices);
2275   return 0;
2276 }
2277
2278 static int
2279 sfifo_test_fifo_segment_fifo_shrink (int verbose)
2280 {
2281   int i, rv, chunk_size = 4096, n_chunks, n_free;
2282   fifo_segment_main_t *sm = &segment_main;
2283   fifo_segment_create_args_t _a, *a = &_a;
2284   fifo_segment_t *fs;
2285   svm_fifo_t *f;
2286
2287   clib_memset (a, 0, sizeof (*a));
2288   a->segment_name = "fifo-test1";
2289   a->segment_size = 256 << 10;
2290
2291   rv = fifo_segment_create (sm, a);
2292
2293   SFIFO_TEST (!rv, "svm_fifo_segment_create returned %d", rv);
2294
2295   /*
2296    * Alloc and grow fifo
2297    */
2298   fs = fifo_segment_get_segment (sm, a->new_segment_indices[0]);
2299   f = fifo_segment_alloc_fifo (fs, chunk_size, FIFO_SEGMENT_RX_FIFO);
2300   n_free = FIFO_SEGMENT_ALLOC_BATCH_SIZE - 1;
2301
2302   SFIFO_TEST (f != 0, "svm_fifo_segment_alloc_fifo");
2303
2304   for (i = 0; i < 9; i++)
2305     {
2306       fifo_segment_grow_fifo (fs, f, chunk_size);
2307       n_free -= 1;
2308       if (f->size != (i + 2) * chunk_size)
2309         SFIFO_TEST (0, "fifo size should be %u is %u",
2310                     (i + 2) * chunk_size, f->size);
2311     }
2312
2313   rv = svm_fifo_reduce_size (f, 3.5 * chunk_size, 1 /* is producer */ );
2314   SFIFO_TEST (rv == 3 * chunk_size, "len expected %u is %u", 3 * chunk_size,
2315               rv);
2316
2317   n_chunks = fifo_segment_num_free_chunks (fs, chunk_size);
2318   SFIFO_TEST (n_chunks == n_free, "free chunks should be %u is %u", n_free,
2319               n_chunks);
2320
2321   fifo_segment_collect_fifo_chunks (fs, f);
2322
2323   n_free += 3;
2324   n_chunks = fifo_segment_num_free_chunks (fs, chunk_size);
2325   SFIFO_TEST (n_chunks == n_free, "free chunks should be %u is %u", n_free,
2326               n_chunks);
2327
2328   rv = svm_fifo_reduce_size (f, 7 * chunk_size - 1, 1 /* is producer */ );
2329   SFIFO_TEST (rv == 6 * chunk_size, "len expected %u is %u", 6 * chunk_size,
2330               rv);
2331
2332   fifo_segment_collect_fifo_chunks (fs, f);
2333
2334   n_free += 6;
2335   n_chunks = fifo_segment_num_free_chunks (fs, chunk_size);
2336   SFIFO_TEST (n_chunks == n_free, "free chunks should be %u is %u", n_free,
2337               n_chunks);
2338   /*
2339    * Free
2340    */
2341   fifo_segment_free_fifo (fs, f);
2342   n_free += 1;
2343   n_chunks = fifo_segment_num_free_chunks (fs, ~0);
2344   SFIFO_TEST (n_chunks == n_free, "free chunks should be %u is %u", n_free,
2345               n_chunks);
2346
2347   /*
2348    * Cleanup
2349    */
2350   fifo_segment_delete (sm, fs);
2351   vec_free (a->new_segment_indices);
2352   return 0;
2353 }
2354
2355 static int
2356 sfifo_test_fifo_segment_slave (int verbose)
2357 {
2358   fifo_segment_create_args_t _a, *a = &_a;
2359   fifo_segment_main_t *sm = &segment_main;
2360   u8 *test_data, *retrieved_data = 0;
2361   fifo_segment_t *fs;
2362   svm_fifo_t *f;
2363   u32 *result;
2364   int rv, i;
2365
2366   sleep (2);
2367
2368   sm->timeout_in_seconds = 5;
2369   clib_memset (a, 0, sizeof (*a));
2370   a->segment_name = "fifo-test1";
2371
2372   rv = fifo_segment_attach (sm, a);
2373
2374   SFIFO_TEST (!rv, "svm_fifo_segment_attach returned %d", rv);
2375
2376   fs = fifo_segment_get_segment (sm, a->new_segment_indices[0]);
2377   vec_free (a->new_segment_indices);
2378
2379   /* might wanna wait.. */
2380   f = fifo_segment_get_slice_fifo_list (fs, 0);
2381
2382   /* Lazy bastards united */
2383   test_data = format (0, "Hello world%c", 0);
2384   vec_validate (retrieved_data, vec_len (test_data) - 1);
2385
2386   for (i = 0; i < 1000; i++)
2387     {
2388       svm_fifo_dequeue (f, vec_len (retrieved_data), retrieved_data);
2389       if (memcmp (retrieved_data, test_data, vec_len (retrieved_data)))
2390         {
2391           result = (u32 *) f->head_chunk->data;
2392           *result = 1;
2393           _exit (0);
2394         }
2395     }
2396
2397   result = (u32 *) f->head_chunk->data;
2398   *result = 0;
2399
2400   vec_free (test_data);
2401   vec_free (retrieved_data);
2402   _exit (0);
2403 }
2404
2405 static int
2406 sfifo_test_fifo_segment_master_slave (int verbose)
2407 {
2408   fifo_segment_create_args_t _a, *a = &_a;
2409   fifo_segment_main_t *sm = &segment_main;
2410   fifo_segment_t *sp;
2411   svm_fifo_t *f;
2412   u8 *test_data;
2413   u32 *result;
2414   int rv, i;
2415   pid_t pid;
2416
2417   pid = fork ();
2418   if (pid < 0)
2419     SFIFO_TEST (0, "fork failed");
2420
2421   if (!pid)
2422     sfifo_test_fifo_segment_slave (verbose);
2423
2424   clib_memset (a, 0, sizeof (*a));
2425   a->segment_name = "fifo-test1";
2426   a->segment_size = 256 << 10;
2427
2428   rv = fifo_segment_create (sm, a);
2429
2430   SFIFO_TEST (!rv, "svm_fifo_segment_create returned %d", rv);
2431
2432   sp = fifo_segment_get_segment (sm, a->new_segment_indices[0]);
2433   f = fifo_segment_alloc_fifo (sp, 4096, FIFO_SEGMENT_RX_FIFO);
2434
2435   SFIFO_TEST (f != 0, "svm_fifo_segment_alloc_fifo alloc");
2436
2437   test_data = format (0, "Hello world%c", 0);
2438
2439   usleep (200e3);
2440
2441   for (i = 0; i < 1000; i++)
2442     svm_fifo_enqueue (f, vec_len (test_data), test_data);
2443
2444   /* Wait for slave */
2445   i = 0;
2446   while (svm_fifo_max_dequeue (f) && i++ < 1e10)
2447     ;
2448
2449   usleep (1e3);
2450
2451   result = (u32 *) f->head_chunk->data;
2452   SFIFO_TEST (*result == 0, "slave reported no error");
2453
2454   vec_free (a->new_segment_indices);
2455   vec_free (test_data);
2456   fifo_segment_free_fifo (sp, f);
2457   fifo_segment_delete (sm, sp);
2458   return 0;
2459 }
2460
2461 static int
2462 sfifo_test_fifo_segment_mempig (int verbose)
2463 {
2464   fifo_segment_create_args_t _a, *a = &_a;
2465   fifo_segment_main_t *sm = &segment_main;
2466   fifo_segment_t *sp;
2467   svm_fifo_t *f;
2468   svm_fifo_t **flist = 0;
2469   int rv;
2470   int i;
2471
2472   clib_memset (a, 0, sizeof (*a));
2473
2474   a->segment_name = "fifo-test1";
2475   a->segment_size = 256 << 10;
2476
2477   rv = fifo_segment_create (sm, a);
2478
2479   SFIFO_TEST (!rv, "svm_fifo_segment_create returned %d", rv);
2480
2481   sp = fifo_segment_get_segment (sm, a->new_segment_indices[0]);
2482
2483   for (i = 0; i < 1000; i++)
2484     {
2485       f = fifo_segment_alloc_fifo (sp, 4096, FIFO_SEGMENT_RX_FIFO);
2486       if (f == 0)
2487         break;
2488       vec_add1 (flist, f);
2489     }
2490
2491   SFIFO_TEST (vec_len (flist), "created %d fifos", vec_len (flist));
2492
2493   for (i = 0; i < vec_len (flist); i++)
2494     {
2495       f = flist[i];
2496       fifo_segment_free_fifo (sp, f);
2497     }
2498
2499   _vec_len (flist) = 0;
2500
2501   for (i = 0; i < 1000; i++)
2502     {
2503       f = fifo_segment_alloc_fifo (sp, 4096, FIFO_SEGMENT_RX_FIFO);
2504       if (f == 0)
2505         break;
2506       vec_add1 (flist, f);
2507     }
2508
2509   SFIFO_TEST (vec_len (flist), "second try created %d fifos",
2510               vec_len (flist));
2511   for (i = 0; i < vec_len (flist); i++)
2512     {
2513       f = flist[i];
2514       fifo_segment_free_fifo (sp, f);
2515     }
2516
2517   fifo_segment_delete (sm, sp);
2518   return 0;
2519 }
2520
2521 static int
2522 sfifo_test_fifo_segment_prealloc (int verbose)
2523 {
2524   fifo_segment_create_args_t _a, *a = &_a;
2525   fifo_segment_main_t *sm = &segment_main;
2526   u32 max_pairs, pairs_req, free_space, pair_mem;
2527   svm_fifo_t *f, *old;
2528   fifo_segment_t *fs;
2529   int rv, alloc;
2530
2531   clib_memset (a, 0, sizeof (*a));
2532
2533   a->segment_name = "fifo-test-prealloc";
2534   a->segment_size = 256 << 10;
2535   a->segment_type = SSVM_SEGMENT_MEMFD;
2536
2537   rv = fifo_segment_create (sm, a);
2538   SFIFO_TEST (!rv, "svm_fifo_segment_create returned %d", rv);
2539   fs = fifo_segment_get_segment (sm, a->new_segment_indices[0]);
2540
2541   /*
2542    * Prealloc chunks and headers
2543    */
2544   free_space = fifo_segment_free_bytes (fs);
2545   SFIFO_TEST (free_space <= 256 << 10, "free space expected %u is %u",
2546               256 << 10, free_space);
2547   rv = fifo_segment_prealloc_fifo_chunks (fs, 0, 4096, 50);
2548   SFIFO_TEST (rv == 0, "chunk prealloc should work");
2549   rv = fifo_segment_num_free_chunks (fs, 4096);
2550   SFIFO_TEST (rv == 50, "prealloc chunks expected %u is %u", 50, rv);
2551   rv = fifo_segment_free_bytes (fs);
2552   free_space -= (sizeof (svm_fifo_chunk_t) + 4096) * 50;
2553   SFIFO_TEST (rv == free_space, "free space expected %u is %u", free_space,
2554               rv);
2555   rv = fifo_segment_fl_chunk_bytes (fs);
2556   SFIFO_TEST (rv == 4096 * 50, "chunk free space expected %u is %u",
2557               4096 * 50, rv);
2558
2559   rv = fifo_segment_prealloc_fifo_hdrs (fs, 0, 50);
2560   SFIFO_TEST (rv == 0, "fifo hdr prealloc should work");
2561   rv = fifo_segment_num_free_fifos (fs);
2562   SFIFO_TEST (rv == 50, "prealloc fifo hdrs expected %u is %u", 50, rv);
2563   rv = fifo_segment_free_bytes (fs);
2564   free_space -= sizeof (svm_fifo_t) * 50;
2565   SFIFO_TEST (rv == free_space, "free space expected %u is %u", free_space,
2566               rv);
2567
2568   fifo_segment_update_free_bytes (fs);
2569   rv = fifo_segment_free_bytes (fs);
2570   SFIFO_TEST (clib_abs (rv - (int) free_space) < 512,
2571               "free space expected %u is %u", free_space, rv);
2572
2573   f = fifo_segment_alloc_fifo (fs, 200 << 10, FIFO_SEGMENT_RX_FIFO);
2574   SFIFO_TEST (f != 0, "fifo allocated");
2575   rv = fifo_segment_num_free_chunks (fs, 4096);
2576   SFIFO_TEST (rv == 0, "prealloc chunks expected %u is %u", 0, rv);
2577   rv = fifo_segment_fl_chunk_bytes (fs);
2578   SFIFO_TEST (rv == 0, "chunk free space expected %u is %u", 0, rv);
2579   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
2580
2581   /*
2582    * Multiple preallocs that consume the remaining space
2583    */
2584   fifo_segment_update_free_bytes (fs);
2585   free_space = fifo_segment_free_bytes (fs);
2586   pair_mem = 2 * (4096 + sizeof (*f) + sizeof (svm_fifo_chunk_t));
2587   max_pairs = pairs_req = (free_space / pair_mem) - 1;
2588   fifo_segment_preallocate_fifo_pairs (fs, 4096, 4096, &pairs_req);
2589   SFIFO_TEST (pairs_req == 0, "prealloc pairs should work req %u", max_pairs);
2590   rv = fifo_segment_num_free_chunks (fs, 4096);
2591   SFIFO_TEST (rv == max_pairs * 2, "prealloc chunks expected %u is %u",
2592               max_pairs * 2, rv);
2593
2594   fifo_segment_update_free_bytes (fs);
2595   rv = fifo_segment_free_bytes (fs);
2596   SFIFO_TEST (rv < 2 * pair_mem, "free bytes %u less than %u", rv,
2597               2 * pair_mem);
2598
2599   /* Preallocate as many more chunks as possible. Heap is almost full
2600    * so we may not use all the free space*/
2601   alloc = 0;
2602   while (!fifo_segment_prealloc_fifo_chunks (fs, 0, 4096, 1))
2603     alloc++;
2604   SFIFO_TEST (alloc, "chunk prealloc should work %u", alloc);
2605   rv = fifo_segment_num_free_chunks (fs, 4096);
2606   SFIFO_TEST (rv == max_pairs * 2 + alloc, "prealloc chunks expected %u "
2607               "is %u", max_pairs * 2 + alloc, rv);
2608
2609   rv = fifo_segment_free_bytes (fs);
2610   SFIFO_TEST (rv < pair_mem, "free bytes expected less than %u is %u",
2611               pair_mem, rv);
2612
2613   /*
2614    * Test negative prealloc cases
2615    */
2616   pairs_req = 1;
2617   fifo_segment_preallocate_fifo_pairs (fs, 4096, 4096, &pairs_req);
2618   SFIFO_TEST (pairs_req == 1, "prealloc pairs should not work");
2619
2620   old = f;
2621   f = fifo_segment_alloc_fifo (fs, 200 << 10, FIFO_SEGMENT_RX_FIFO);
2622   SFIFO_TEST (f == 0, "fifo alloc should fail");
2623
2624   rv = fifo_segment_prealloc_fifo_chunks (fs, 0, 4096, 50);
2625   SFIFO_TEST (rv == -1, "chunk prealloc should fail");
2626
2627   rv = fifo_segment_prealloc_fifo_hdrs (fs, 0, 50);
2628   SFIFO_TEST (rv == -1, "fifo hdr prealloc should fail");
2629
2630   /*
2631    * Cleanup
2632    */
2633   fifo_segment_free_fifo (fs, old);
2634   close (fs->ssvm.fd);
2635   fifo_segment_delete (sm, fs);
2636   return 0;
2637 }
2638
2639 static int
2640 sfifo_test_fifo_segment (vlib_main_t * vm, unformat_input_t * input)
2641 {
2642   int rv, verbose = 0;
2643
2644   fifo_segment_main_init (&segment_main, HIGH_SEGMENT_BASEVA, 5);
2645   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2646     {
2647       if (unformat (input, "verbose"))
2648         verbose = 1;
2649       else if (unformat (input, "masterslave"))
2650         {
2651           if ((rv = sfifo_test_fifo_segment_master_slave (verbose)))
2652             return -1;
2653         }
2654       else if (unformat (input, "basic"))
2655         {
2656           if ((rv = sfifo_test_fifo_segment_hello_world (verbose)))
2657             return -1;
2658         }
2659       else if (unformat (input, "mempig"))
2660         {
2661           if ((rv = sfifo_test_fifo_segment_mempig (verbose)))
2662             return -1;
2663         }
2664       else if (unformat (input, "grow fifo"))
2665         {
2666           if ((rv = sfifo_test_fifo_segment_fifo_grow (verbose)))
2667             return -1;
2668         }
2669       else if (unformat (input, "shrink fifo"))
2670         {
2671           if ((rv = sfifo_test_fifo_segment_fifo_shrink (verbose)))
2672             return -1;
2673         }
2674       else if (unformat (input, "prealloc"))
2675         {
2676           if ((rv = sfifo_test_fifo_segment_prealloc (verbose)))
2677             return -1;
2678         }
2679       else if (unformat (input, "all"))
2680         {
2681           if ((rv = sfifo_test_fifo_segment_hello_world (verbose)))
2682             return -1;
2683           if ((rv = sfifo_test_fifo_segment_mempig (verbose)))
2684             return -1;
2685           if ((rv = sfifo_test_fifo_segment_fifo_grow (verbose)))
2686             return -1;
2687           if ((rv = sfifo_test_fifo_segment_fifo_shrink (verbose)))
2688             return -1;
2689           if ((rv = sfifo_test_fifo_segment_prealloc (verbose)))
2690             return -1;
2691           /* Pretty slow so avoid running it always
2692              if ((rv = sfifo_test_fifo_segment_master_slave (verbose)))
2693              return -1;
2694            */
2695         }
2696       else
2697         {
2698           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
2699                            input);
2700           return -1;
2701         }
2702     }
2703   return 0;
2704 }
2705
2706 static clib_error_t *
2707 svm_fifo_test (vlib_main_t * vm, unformat_input_t * input,
2708                vlib_cli_command_t * cmd_arg)
2709 {
2710   int res = 0;
2711   char *str;
2712
2713
2714   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2715     {
2716       if (unformat (input, "fifo1"))
2717         res = sfifo_test_fifo1 (vm, input);
2718       else if (unformat (input, "fifo2"))
2719         res = sfifo_test_fifo2 (vm);
2720       else if (unformat (input, "fifo3"))
2721         res = sfifo_test_fifo3 (vm, input);
2722       else if (unformat (input, "fifo4"))
2723         res = sfifo_test_fifo4 (vm, input);
2724       else if (unformat (input, "fifo5"))
2725         res = sfifo_test_fifo5 (vm, input);
2726       else if (unformat (input, "fifo6"))
2727         res = sfifo_test_fifo6 (vm, input);
2728       else if (unformat (input, "fifo7"))
2729         res = sfifo_test_fifo7 (vm, input);
2730       else if (unformat (input, "large"))
2731         res = sfifo_test_fifo_large (vm, input);
2732       else if (unformat (input, "replay"))
2733         res = sfifo_test_fifo_replay (vm, input);
2734       else if (unformat (input, "grow"))
2735         res = sfifo_test_fifo_grow (vm, input);
2736       else if (unformat (input, "shrink"))
2737         res = sfifo_test_fifo_shrink (vm, input);
2738       else if (unformat (input, "segment"))
2739         res = sfifo_test_fifo_segment (vm, input);
2740       else if (unformat (input, "all"))
2741         {
2742           if ((res = sfifo_test_fifo1 (vm, input)))
2743             goto done;
2744
2745           if ((res = sfifo_test_fifo2 (vm)))
2746             goto done;
2747
2748           /*
2749            * Run a number of fifo3 configs
2750            */
2751           str = "nsegs 10 overlap seed 123";
2752           unformat_init_cstring (input, str);
2753           if ((res = sfifo_test_fifo3 (vm, input)))
2754             goto done;
2755           unformat_free (input);
2756
2757           str = "nsegs 10 overlap seed 123 in-seq-all";
2758           unformat_init_cstring (input, str);
2759           if ((res = sfifo_test_fifo3 (vm, input)))
2760             goto done;
2761           unformat_free (input);
2762
2763           str = "nsegs 10 overlap seed 123 initial-offset 3917";
2764           unformat_init_cstring (input, str);
2765           if ((res = sfifo_test_fifo3 (vm, input)))
2766             goto done;
2767           unformat_free (input);
2768
2769           str = "nsegs 10 overlap seed 123 initial-offset 3917 drop";
2770           unformat_init_cstring (input, str);
2771           if ((res = sfifo_test_fifo3 (vm, input)))
2772             goto done;
2773           unformat_free (input);
2774
2775           str = "nsegs 10 seed 123 initial-offset 3917 drop no-randomize";
2776           unformat_init_cstring (input, str);
2777           if ((res = sfifo_test_fifo3 (vm, input)))
2778             goto done;
2779           unformat_free (input);
2780
2781           if ((res = sfifo_test_fifo4 (vm, input)))
2782             goto done;
2783
2784           if ((res = sfifo_test_fifo5 (vm, input)))
2785             goto done;
2786
2787           if ((res = sfifo_test_fifo6 (vm, input)))
2788             goto done;
2789
2790           if ((res = sfifo_test_fifo7 (vm, input)))
2791             goto done;
2792
2793           if ((res = sfifo_test_fifo_grow (vm, input)))
2794             goto done;
2795
2796           if ((res = sfifo_test_fifo_shrink (vm, input)))
2797             goto done;
2798
2799           str = "all";
2800           unformat_init_cstring (input, str);
2801           if ((res = sfifo_test_fifo_segment (vm, input)))
2802             goto done;
2803         }
2804       else
2805         {
2806           vlib_cli_output (vm, "unknown input `%U'", format_unformat_error,
2807                            input);
2808           res = -1;
2809           goto done;
2810         }
2811
2812     }
2813
2814 done:
2815   if (res)
2816     return clib_error_return (0, "svm fifo unit test failed");
2817   return 0;
2818 }
2819
2820 /* *INDENT-OFF* */
2821 VLIB_CLI_COMMAND (svm_fifo_test_command, static) =
2822 {
2823   .path = "test svm fifo",
2824   .short_help = "internal svm fifo unit tests",
2825   .function = svm_fifo_test,
2826 };
2827 /* *INDENT-ON* */
2828
2829 /*
2830  * fd.io coding-style-patch-verification: ON
2831  *
2832  * Local Variables:
2833  * eval: (c-set-style "gnu")
2834  * End:
2835  */