svm: use default SVM address in fifo unit tests
[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   svm_fifo_t *f;
1198   u32 old_tail;
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
1282   prev = 0;
1283   for (i = 0; i < 5; i++)
1284     {
1285       c = clib_mem_alloc (sizeof (svm_fifo_chunk_t) + 100);
1286       c->length = 100;
1287       c->start_byte = ~0;
1288       c->next = prev;
1289       prev = c;
1290     }
1291
1292   svm_fifo_add_chunk (f, c);
1293   SFIFO_TEST (f->size == fifo_size + 200, "size expected %u is %u",
1294               fifo_size + 200, f->size);
1295
1296   old_tail = f->tail;
1297   svm_fifo_dequeue (f, 101, data_buf);
1298
1299   SFIFO_TEST (f->size == fifo_size + 200 + 10 * 100, "size expected %u is %u",
1300               fifo_size + 200 + 10 * 100, f->size);
1301   SFIFO_TEST (f->tail == old_tail, "new tail expected %u is %u", old_tail,
1302               f->tail);
1303   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1304
1305   /*
1306    * Enqueue/dequeue tests
1307    */
1308
1309   test_n_bytes = f->nitems;
1310   vec_validate (test_data, test_n_bytes - 1);
1311   vec_validate (data_buf, vec_len (test_data));
1312   n_deqs = n_enqs = 6;
1313   deq_bytes = enq_bytes = vec_len (test_data) / n_deqs;
1314
1315   for (i = 0; i < vec_len (test_data); i++)
1316     test_data[i] = i;
1317
1318   /*
1319    * Enqueue/deq boundary conditions
1320    */
1321   svm_fifo_init_pointers (f, 201, 201);
1322   SFIFO_TEST (f->tail_chunk->start_byte == 201, "start byte expected %u is "
1323               "%u", 201, f->tail_chunk->start_byte);
1324
1325   svm_fifo_enqueue (f, 200, test_data);
1326   SFIFO_TEST (f->tail_chunk->start_byte == 401, "start byte expected %u is "
1327               "%u", 401, f->tail_chunk->start_byte);
1328
1329   svm_fifo_dequeue (f, 200, data_buf);
1330   SFIFO_TEST (f->head_chunk->start_byte == 401, "start byte expected %u is "
1331               "%u", 401, f->head_chunk->start_byte);
1332
1333   /*
1334    * Simple enqueue/deq and data validation (1)
1335    */
1336   svm_fifo_init_pointers (f, f->nitems / 2, f->nitems / 2);
1337   for (i = 0; i < test_n_bytes; i++)
1338     {
1339       rv = svm_fifo_enqueue (f, sizeof (u8), &test_data[i]);
1340       if (rv < 0)
1341         {
1342           clib_warning ("enqueue returned %d", rv);
1343           goto cleanup;
1344         }
1345     }
1346
1347   SFIFO_TEST (svm_fifo_max_dequeue (f) == test_n_bytes, "max deq expected %u "
1348               "is %u", test_n_bytes, svm_fifo_max_dequeue (f));
1349
1350   for (i = 0; i < test_n_bytes; i++)
1351     svm_fifo_dequeue (f, 1, &data_buf[i]);
1352
1353   rv = compare_data (data_buf, test_data, 0, vec_len (test_data),
1354                      (u32 *) & j);
1355   if (rv)
1356     vlib_cli_output (vm, "[%d] dequeued %u expected %u", j, data_buf[j],
1357                      test_data[j]);
1358   SFIFO_TEST ((rv == 0), "dequeued compared to original returned %d", rv);
1359   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1360
1361   /*
1362    * Simple enqueue/deq and data validation (2)
1363    */
1364   for (i = 0; i <= n_enqs; i++)
1365     {
1366       rv = svm_fifo_enqueue (f, enq_bytes, test_data + i * enq_bytes);
1367       if (rv < 0)
1368         {
1369           clib_warning ("enqueue returned %d", rv);
1370           goto cleanup;
1371         }
1372     }
1373
1374   SFIFO_TEST (svm_fifo_max_dequeue (f) == test_n_bytes, "max deq expected %u "
1375               "is %u", test_n_bytes, svm_fifo_max_dequeue (f));
1376
1377   for (i = 0; i <= n_deqs; i++)
1378     svm_fifo_dequeue (f, deq_bytes, data_buf + i * deq_bytes);
1379
1380   rv = compare_data (data_buf, test_data, 0, vec_len (test_data),
1381                      (u32 *) & j);
1382   if (rv)
1383     vlib_cli_output (vm, "[%d] dequeued %u expected %u", j, data_buf[j],
1384                      test_data[j]);
1385   SFIFO_TEST ((rv == 0), "dequeued compared to original returned %d", rv);
1386   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1387
1388   /*
1389    * Simple enqueue and drop
1390    */
1391   for (i = 0; i <= n_enqs; i++)
1392     {
1393       rv = svm_fifo_enqueue (f, enq_bytes, test_data + i * enq_bytes);
1394       if (rv < 0)
1395         SFIFO_TEST (0, "failed to enqueue");
1396     }
1397
1398   rv = svm_fifo_dequeue_drop (f, test_n_bytes / 2);
1399   SFIFO_TEST (rv == test_n_bytes / 2, "drop should be equal");
1400   SFIFO_TEST (svm_fifo_is_sane (f), "head chunk should be valid");
1401   rv = svm_fifo_dequeue_drop (f, test_n_bytes / 2);
1402   SFIFO_TEST (rv == test_n_bytes / 2, "drop should be equal");
1403   SFIFO_TEST (svm_fifo_is_sane (f), "head chunk should be valid");
1404   SFIFO_TEST (svm_fifo_max_dequeue (f) == 0, "should be empty");
1405
1406   /*
1407    * Simple enqueue and drop all
1408    */
1409
1410   /* Enqueue just enough data to make sure fifo is not full */
1411   for (i = 0; i <= n_enqs / 2; i++)
1412     {
1413       rv = svm_fifo_enqueue (f, enq_bytes, test_data + i * enq_bytes);
1414       if (rv < 0)
1415         SFIFO_TEST (0, "failed to enqueue");
1416     }
1417
1418   /* check drop all as well */
1419   svm_fifo_dequeue_drop_all (f);
1420   SFIFO_TEST (svm_fifo_is_sane (f), "head chunk should be valid");
1421   SFIFO_TEST (svm_fifo_max_dequeue (f) == 0, "should be empty");
1422
1423   /*
1424    * OOO enqueues/dequeues and data validation (1)
1425    */
1426   for (i = test_n_bytes - 1; i > 0; i--)
1427     {
1428       rv = svm_fifo_enqueue_with_offset (f, i, sizeof (u8), &test_data[i]);
1429       if (verbose)
1430         vlib_cli_output (vm, "add [%d] [%d, %d]", i, i, i + sizeof (u8));
1431       if (rv)
1432         {
1433           clib_warning ("enqueue returned %d", rv);
1434           goto cleanup;
1435         }
1436     }
1437
1438   SFIFO_TEST (svm_fifo_max_dequeue (f) == 0, "max deq expected %u is %u",
1439               0, svm_fifo_max_dequeue (f));
1440
1441   svm_fifo_enqueue (f, sizeof (u8), &test_data[0]);
1442
1443   memset (data_buf, 0, vec_len (data_buf));
1444   for (i = 0; i <= n_deqs; i++)
1445     svm_fifo_dequeue (f, deq_bytes, data_buf + i * deq_bytes);
1446
1447   rv = compare_data (data_buf, test_data, 0, vec_len (test_data),
1448                      (u32 *) & j);
1449   if (rv)
1450     vlib_cli_output (vm, "[%d] dequeued %u expected %u", j, data_buf[j],
1451                      test_data[j]);
1452   SFIFO_TEST ((rv == 0), "dequeued compared to original returned %d", rv);
1453   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1454
1455   /*
1456    * OOO enqueues/dequeues and data validation (2)
1457    */
1458
1459   for (i = n_enqs; i > 0; i--)
1460     {
1461       u32 enq_now = clib_min (enq_bytes, vec_len (test_data) - i * enq_bytes);
1462       rv = svm_fifo_enqueue_with_offset (f, i * enq_bytes, enq_now,
1463                                          test_data + i * enq_bytes);
1464       if (verbose)
1465         vlib_cli_output (vm, "add [%d, %d]", i * enq_bytes,
1466                          i * enq_bytes + enq_now);
1467       if (rv)
1468         {
1469           clib_warning ("enqueue returned %d", rv);
1470           goto cleanup;
1471         }
1472     }
1473   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1474
1475   svm_fifo_enqueue (f, enq_bytes, &test_data[0]);
1476   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1477
1478   memset (data_buf, 0, vec_len (data_buf));
1479   for (i = 0; i <= n_deqs; i++)
1480     svm_fifo_dequeue (f, deq_bytes, data_buf + i * deq_bytes);
1481
1482   rv = compare_data (data_buf, test_data, 0, vec_len (test_data),
1483                      (u32 *) & j);
1484   if (rv)
1485     vlib_cli_output (vm, "[%d] dequeued %u expected %u", j, data_buf[j],
1486                      test_data[j]);
1487   SFIFO_TEST ((rv == 0), "dequeued compared to original returned %d", rv);
1488   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1489
1490   /*
1491    * Cleanup
1492    */
1493
1494 cleanup:
1495
1496   c = f->start_chunk->next;
1497   while (c && c != f->start_chunk)
1498     {
1499       next = c->next;
1500       clib_mem_free (c);
1501       c = next;
1502     }
1503
1504   svm_fifo_free (f);
1505   vec_free (test_data);
1506   vec_free (data_buf);
1507   return 0;
1508 }
1509
1510 static int
1511 chunk_list_len (svm_fifo_chunk_t * c)
1512 {
1513   svm_fifo_chunk_t *it;
1514   int count = 0;
1515
1516   if (!c)
1517     return 0;
1518
1519   count = 1;
1520   it = c->next;
1521   while (it && it != c)
1522     {
1523       it = it->next;
1524       count++;
1525     }
1526   return count;
1527 }
1528
1529 static void
1530 chunk_list_free (svm_fifo_chunk_t * c, svm_fifo_chunk_t * stop)
1531 {
1532   svm_fifo_chunk_t *it, *next;
1533
1534   it = c;
1535   while (it && it != stop)
1536     {
1537       next = it->next;
1538       clib_mem_free (it);
1539       it = next;
1540     }
1541 }
1542
1543 static void
1544 chunk_list_splice (svm_fifo_chunk_t * a, svm_fifo_chunk_t * b)
1545 {
1546   svm_fifo_chunk_t *it;
1547
1548   it = a;
1549   while (it->next)
1550     it = it->next;
1551   it->next = b;
1552 }
1553
1554 static int
1555 sfifo_test_fifo_shrink (vlib_main_t * vm, unformat_input_t * input)
1556 {
1557   int __clib_unused verbose = 0, fifo_size = 101, chunk_size = 100;
1558   int i, rv, test_n_bytes, diff, deq_bytes;
1559   svm_fifo_chunk_t *c, *prev, *collected;
1560   u8 *test_data = 0, *data_buf = 0;
1561   svm_fifo_t *f;
1562
1563   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1564     {
1565       if (unformat (input, "verbose"))
1566         verbose = 1;
1567       else
1568         {
1569           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
1570                            input);
1571           return -1;
1572         }
1573     }
1574
1575   /*
1576    * Init fifo with multiple chunks
1577    */
1578   f = fifo_prepare (fifo_size);
1579   svm_fifo_init_pointers (f, 0, 0);
1580
1581   prev = 0;
1582   for (i = 0; i < 11; i++)
1583     {
1584       c = clib_mem_alloc (sizeof (svm_fifo_chunk_t) + chunk_size);
1585       c->length = 100;
1586       c->start_byte = ~0;
1587       c->next = prev;
1588       prev = c;
1589     }
1590
1591   svm_fifo_add_chunk (f, c);
1592   SFIFO_TEST (f->size == 12 * chunk_size + 1, "size expected %u is %u",
1593               12 * chunk_size + 1, f->size);
1594
1595   /*
1596    * No fifo wrap and no chunk used (one chunk)
1597    */
1598   rv = svm_fifo_reduce_size (f, chunk_size, 0);
1599   SFIFO_TEST (rv == chunk_size, "len expected %u is %u", chunk_size, rv);
1600   SFIFO_TEST (f->size == 12 * chunk_size + 1, "size expected %u is %u",
1601               12 * chunk_size + 1, f->size);
1602   SFIFO_TEST (f->flags & SVM_FIFO_F_SHRINK, "shrink flag should be set");
1603   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1604
1605   /* Check enqueue space to force size reduction */
1606   (void) svm_fifo_max_enqueue (f);
1607
1608   SFIFO_TEST (f->size == 11 * chunk_size + 1, "size expected %u is %u",
1609               11 * chunk_size + 1, f->size);
1610   SFIFO_TEST (f->flags & SVM_FIFO_F_COLLECT_CHUNKS, "collect flag should"
1611               " be set");
1612   SFIFO_TEST (!(f->flags & SVM_FIFO_F_SHRINK), "shrink flag should not be"
1613               " set");
1614   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1615
1616   collected = c = svm_fifo_collect_chunks (f);
1617   rv = chunk_list_len (c);
1618   SFIFO_TEST (rv == 1, "expected %u chunks got %u", 1, rv);
1619   rv = chunk_list_len (f->start_chunk);
1620   SFIFO_TEST (rv == 11, "expected %u chunks got %u", 11, rv);
1621   SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should"
1622               " not be set");
1623   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1624
1625   /*
1626    * Fifo wrap and multiple chunks used
1627    */
1628
1629   /* Init test data and fifo */
1630   test_n_bytes = f->nitems;
1631   vec_validate (test_data, test_n_bytes - 1);
1632   vec_validate (data_buf, vec_len (test_data));
1633
1634   for (i = 0; i < vec_len (test_data); i++)
1635     test_data[i] = i;
1636
1637   svm_fifo_init_pointers (f, f->size / 2, f->size / 2);
1638   for (i = 0; i < test_n_bytes; i++)
1639     {
1640       rv = svm_fifo_enqueue (f, sizeof (u8), &test_data[i]);
1641       if (rv < 0)
1642         SFIFO_TEST (0, "enqueue returned");
1643     }
1644
1645   /* Try to reduce fifo size with fifo full */
1646   rv = svm_fifo_reduce_size (f, 3.5 * chunk_size, 0);
1647   SFIFO_TEST (rv == 3 * chunk_size, "len expected %u is %u", 3 * chunk_size,
1648               rv);
1649   SFIFO_TEST (f->size == 11 * chunk_size + 1, "size expected %u is %u",
1650               11 * chunk_size + 1, f->size);
1651   SFIFO_TEST (f->flags & SVM_FIFO_F_SHRINK, "shrink flag should be set");
1652   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1653
1654   /* Check enqueue space to try size reduction. Should not work */
1655   rv = svm_fifo_max_enqueue (f);
1656
1657   SFIFO_TEST (rv == 0, "free space expected %u is %u", 0, 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 (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should"
1662               " not be set");
1663   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1664
1665   /* Dequeue byte-by-byte up to last byte on last chunk */
1666   deq_bytes = f->size - f->size / 2 - 1;
1667   for (i = 0; i < deq_bytes; i++)
1668     {
1669       (void) svm_fifo_max_enqueue (f);
1670       rv = svm_fifo_dequeue (f, 1, &data_buf[i]);
1671       if (rv < 0)
1672         SFIFO_TEST (0, "dequeue returned");
1673     }
1674   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1675
1676   rv = svm_fifo_max_enqueue (f);
1677
1678   /* We've dequeued more than 3*chunk_size so nitems should be updated */
1679   SFIFO_TEST (f->nitems == 8 * chunk_size, "nitems expected %u is %u",
1680               8 * chunk_size, f->nitems);
1681   /* Free space should be what was dequeued - 3 * chunk_size, which was
1682    * consumed by shrinking the fifo */
1683   diff = deq_bytes - 3 * chunk_size;
1684   SFIFO_TEST (rv == diff, "free space expected %u is %u", diff, rv);
1685   SFIFO_TEST (f->size == 11 * chunk_size + 1, "size expected %u is %u",
1686               11 * chunk_size + 1, f->size);
1687   SFIFO_TEST (f->flags & SVM_FIFO_F_SHRINK, "shrink flag should be set");
1688   SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should"
1689               " not be set");
1690   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1691
1692   /* Dequeue one more such that head goes beyond last chunk */
1693   rv = svm_fifo_dequeue (f, 1, &data_buf[deq_bytes]);
1694   if (rv < 0)
1695     SFIFO_TEST (0, "dequeue returned");
1696
1697   rv = svm_fifo_max_enqueue (f);
1698   SFIFO_TEST (f->nitems == 8 * chunk_size, "nitems expected %u is %u",
1699               8 * chunk_size, f->nitems);
1700   SFIFO_TEST (rv == diff + 1, "free space expected %u is %u", diff + 1, rv);
1701   SFIFO_TEST (f->size == 8 * chunk_size + 1, "size expected %u is %u",
1702               8 * chunk_size + 1, f->size);
1703   SFIFO_TEST (!(f->flags & SVM_FIFO_F_SHRINK), "shrink flag should not be"
1704               " set");
1705   SFIFO_TEST (f->flags & SVM_FIFO_F_COLLECT_CHUNKS, "collect flag should"
1706               " be set");
1707   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1708
1709   /* Dequeue the rest of the data */
1710   deq_bytes += 1;
1711   for (i = 0; i < test_n_bytes - deq_bytes; i++)
1712     {
1713       rv = svm_fifo_dequeue (f, 1, &data_buf[i + deq_bytes]);
1714       if (rv < 0)
1715         SFIFO_TEST (0, "dequeue returned");
1716     }
1717
1718   rv = svm_fifo_max_enqueue (f);
1719
1720   SFIFO_TEST (f->size == 8 * chunk_size + 1, "size expected %u is %u",
1721               8 * chunk_size + 1, f->size);
1722   SFIFO_TEST (rv == 8 * chunk_size, "free space expected %u is %u",
1723               8 * chunk_size, rv);
1724
1725   rv = compare_data (data_buf, test_data, 0, vec_len (test_data),
1726                      (u32 *) & i);
1727   if (rv)
1728     SFIFO_TEST (0, "[%d] dequeued %u expected %u", i, data_buf[i],
1729                 test_data[i]);
1730
1731   c = svm_fifo_collect_chunks (f);
1732   rv = chunk_list_len (c);
1733   SFIFO_TEST (rv == 3, "expected %u chunks got %u", 3, rv);
1734   rv = chunk_list_len (f->start_chunk);
1735   SFIFO_TEST (rv == 8, "expected %u chunks got %u", 8, rv);
1736   SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should"
1737               " not be set");
1738   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1739
1740   /*
1741    * OOO segment on chunk that should be removed
1742    */
1743
1744   svm_fifo_add_chunk (f, c);
1745   SFIFO_TEST (f->size == 11 * chunk_size + 1, "size expected %u is %u",
1746               11 * chunk_size + 1, f->size);
1747
1748   memset (data_buf, 0, vec_len (data_buf));
1749   svm_fifo_init_pointers (f, f->size / 2, f->size / 2);
1750   svm_fifo_enqueue (f, 200, test_data);
1751   svm_fifo_enqueue_with_offset (f, 50, vec_len (test_data) - 250,
1752                                 &test_data[250]);
1753
1754   /* Free space */
1755   rv = svm_fifo_max_enqueue (f);
1756   SFIFO_TEST (rv == vec_len (test_data) - 200, "free space expected %u is %u",
1757               vec_len (test_data) - 200, rv);
1758   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1759
1760   /* Ask to reduce size */
1761   rv = svm_fifo_reduce_size (f, 3.5 * chunk_size, 0);
1762   SFIFO_TEST (rv == 3 * chunk_size, "len expected %u is %u", 3 * chunk_size,
1763               rv);
1764   SFIFO_TEST (f->size == 11 * chunk_size + 1, "size expected %u is %u",
1765               11 * chunk_size + 1, f->size);
1766   SFIFO_TEST (f->flags & SVM_FIFO_F_SHRINK, "shrink flag should be set");
1767   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1768
1769   /* Try to force size reduction but it should fail */
1770   rv = svm_fifo_max_enqueue (f);
1771
1772   SFIFO_TEST (rv == vec_len (test_data) - 200, "free space expected %u is %u",
1773               vec_len (test_data) - 200, 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 (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should"
1778               " not be set");
1779   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1780
1781   /* Dequeue the in order data. This should shrink nitems */
1782   rv = svm_fifo_dequeue (f, 200, data_buf);
1783   if (rv < 0)
1784     SFIFO_TEST (0, "dequeue returned");
1785
1786   rv = svm_fifo_max_enqueue (f);
1787   SFIFO_TEST (rv == vec_len (test_data) - 200, "free space expected %u is %u",
1788               vec_len (test_data) - 200, rv);
1789   SFIFO_TEST (f->size == 11 * chunk_size + 1, "size expected %u is %u",
1790               11 * chunk_size + 1, f->size);
1791   SFIFO_TEST (f->nitems == 11 * chunk_size - 200, "nitems expected %u is %u",
1792               11 * chunk_size - 200, f->nitems);
1793   SFIFO_TEST (f->flags & SVM_FIFO_F_SHRINK, "shrink flag should be set");
1794   SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should"
1795               " not be set");
1796   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1797
1798   /* Enqueue the missing 50 bytes. Fifo will become full */
1799   rv = svm_fifo_enqueue (f, 50, &test_data[200]);
1800   SFIFO_TEST (rv == vec_len (test_data) - 200, "free space expected %u is %u",
1801               vec_len (test_data) - 200, rv);
1802   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1803
1804   rv = svm_fifo_max_enqueue (f);
1805
1806   SFIFO_TEST (rv == 0, "free space expected %u is %u", 0, rv);
1807   SFIFO_TEST (f->size == 11 * chunk_size + 1, "size expected %u is %u",
1808               11 * chunk_size + 1, f->size);
1809   SFIFO_TEST (f->flags & SVM_FIFO_F_SHRINK, "shrink flag should be set");
1810   SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should"
1811               " not be set");
1812   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1813
1814
1815   /* Dequeue a chunk and check nitems shrink but fifo still full */
1816   svm_fifo_dequeue (f, 100, &data_buf[200]);
1817
1818   rv = svm_fifo_max_enqueue (f);
1819
1820   SFIFO_TEST (rv == 0, "free space expected %u is %u", 0, rv);
1821   SFIFO_TEST (f->size == 11 * chunk_size + 1, "size expected %u is %u",
1822               11 * chunk_size + 1, f->size);
1823   SFIFO_TEST (f->nitems == 11 * chunk_size - 300, "nitems expected %u is %u",
1824               11 * chunk_size - 300, f->nitems);
1825   SFIFO_TEST (f->flags & SVM_FIFO_F_SHRINK, "shrink flag should be set");
1826   SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should"
1827               " not be set");
1828   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1829
1830   /* Dequeue enough to unwrap the fifo */
1831   deq_bytes = f->size - f->size / 2 - 300;
1832   svm_fifo_dequeue (f, deq_bytes, &data_buf[300]);
1833   rv = svm_fifo_max_enqueue (f);
1834
1835   /* Overall we've dequeued deq_bytes + 300, but fifo size shrunk 300 */
1836   SFIFO_TEST (rv == 300 + deq_bytes - 300, "free space expected %u is %u",
1837               300 + deq_bytes - 300, rv);
1838   SFIFO_TEST (f->size == 8 * chunk_size + 1, "size expected %u is %u",
1839               8 * chunk_size + 1, f->size);
1840   SFIFO_TEST (f->nitems == 8 * chunk_size, "nitems expected %u is %u",
1841               8 * chunk_size, f->nitems);
1842   SFIFO_TEST (!(f->flags & SVM_FIFO_F_SHRINK), "shrink flag should not be"
1843               " set");
1844   SFIFO_TEST (f->flags & SVM_FIFO_F_COLLECT_CHUNKS, "collect flag should"
1845               " be set");
1846   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1847
1848   /* Dequeue the rest */
1849   svm_fifo_dequeue (f, test_n_bytes / 2, &data_buf[300 + deq_bytes]);
1850   rv = compare_data (data_buf, test_data, 0, vec_len (test_data),
1851                      (u32 *) & i);
1852   if (rv)
1853     SFIFO_TEST (0, "[%d] dequeued %u expected %u", i, data_buf[i],
1854                 test_data[i]);
1855
1856   c = svm_fifo_collect_chunks (f);
1857   rv = chunk_list_len (c);
1858   SFIFO_TEST (rv == 3, "expected %u chunks got %u", 3, rv);
1859   rv = chunk_list_len (f->start_chunk);
1860   SFIFO_TEST (rv == 8, "expected %u chunks got %u", 8, rv);
1861   SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should"
1862               " not be set");
1863   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1864
1865   chunk_list_splice (collected, c);
1866
1867   /*
1868    * Remove all chunks possible (1)
1869    *
1870    * Tail and head are in first chunk that is not removed
1871    */
1872   svm_fifo_init_pointers (f, 600, 600);
1873   rv = svm_fifo_reduce_size (f, 8 * chunk_size, 1);
1874   SFIFO_TEST (rv == 7 * chunk_size, "actual len expected %u is %u",
1875               7 * chunk_size, rv);
1876   SFIFO_TEST (f->size == 6 * chunk_size + 1, "size expected %u is %u",
1877               6 * chunk_size + 1, f->size);
1878   SFIFO_TEST (f->nitems == 1 * chunk_size, "nitems expected %u is %u",
1879               1 * chunk_size, f->nitems);
1880   SFIFO_TEST (f->flags & SVM_FIFO_F_SHRINK, "shrink flag should be set");
1881   SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should"
1882               " not be set");
1883   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1884
1885   rv = svm_fifo_max_enqueue (f);
1886   SFIFO_TEST (rv == chunk_size, "free space expected %u is %u", chunk_size,
1887               rv);
1888   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1889
1890   /* Force head/tail to move to first chunk */
1891   svm_fifo_enqueue (f, 1, test_data);
1892   svm_fifo_dequeue (f, 1, data_buf);
1893   rv = svm_fifo_max_enqueue (f);
1894
1895   SFIFO_TEST (rv == chunk_size, "free space expected %u is %u", chunk_size,
1896               rv);
1897   SFIFO_TEST (f->size == chunk_size + 1, "size expected %u is %u",
1898               chunk_size + 1, f->size);
1899   SFIFO_TEST (!(f->flags & SVM_FIFO_F_SHRINK), "shrink flag should not be"
1900               " set");
1901   SFIFO_TEST (f->flags & SVM_FIFO_F_COLLECT_CHUNKS, "collect flag should"
1902               " be set");
1903   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1904
1905   c = svm_fifo_collect_chunks (f);
1906   rv = chunk_list_len (c);
1907   SFIFO_TEST (rv == 7, "expected %u chunks got %u", 7, rv);
1908   SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should"
1909               " not be set");
1910   SFIFO_TEST (!(f->flags & SVM_FIFO_F_MULTI_CHUNK), "multi-chunk flag should"
1911               " not be set");
1912   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1913
1914   /* re-add chunks for next test */
1915   svm_fifo_add_chunk (f, c);
1916
1917   /*
1918    * Remove all chunks possible (2)
1919    *
1920    * Tail and head are in the first chunk that should eventually be removed
1921    */
1922   svm_fifo_init_pointers (f, 601, 601);
1923   rv = svm_fifo_reduce_size (f, 8 * chunk_size, 1);
1924   SFIFO_TEST (rv == 7 * chunk_size, "actual len expected %u is %u",
1925               7 * chunk_size, rv);
1926   SFIFO_TEST (f->size == 7 * chunk_size + 1, "size expected %u is %u",
1927               7 * chunk_size + 1, f->size);
1928   SFIFO_TEST (f->nitems == 1 * chunk_size, "nitems expected %u is %u",
1929               1 * chunk_size, f->nitems);
1930   SFIFO_TEST (f->flags & SVM_FIFO_F_SHRINK, "shrink flag should be set");
1931   SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should"
1932               " not be set");
1933   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1934
1935   rv = svm_fifo_max_enqueue (f);
1936   SFIFO_TEST (rv == chunk_size, "free space expected %u is %u", chunk_size,
1937               rv);
1938   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1939
1940   /* Force head/tail to move to first chunk */
1941   svm_fifo_enqueue (f, chunk_size, test_data);
1942   svm_fifo_dequeue (f, chunk_size, data_buf);
1943   rv = svm_fifo_max_enqueue (f);
1944
1945   SFIFO_TEST (rv == chunk_size, "free space expected %u is %u", chunk_size,
1946               rv);
1947   SFIFO_TEST (f->size == chunk_size + 1, "size expected %u is %u",
1948               chunk_size + 1, f->size);
1949   SFIFO_TEST (!(f->flags & SVM_FIFO_F_SHRINK), "shrink flag should not be"
1950               " set");
1951   SFIFO_TEST (f->flags & SVM_FIFO_F_COLLECT_CHUNKS, "collect flag should"
1952               " be set");
1953   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1954
1955   c = svm_fifo_collect_chunks (f);
1956   rv = chunk_list_len (c);
1957   SFIFO_TEST (rv == 7, "expected %u chunks got %u", 7, rv);
1958   SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should"
1959               " not be set");
1960   SFIFO_TEST (!(f->flags & SVM_FIFO_F_MULTI_CHUNK), "multi-chunk flag should"
1961               " not be set");
1962   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
1963
1964   chunk_list_splice (collected, c);
1965
1966   /*
1967    * Cleanup
1968    */
1969
1970   chunk_list_free (f->start_chunk->next, f->start_chunk);
1971   chunk_list_free (collected, 0);
1972   svm_fifo_free (f);
1973   vec_free (test_data);
1974   vec_free (data_buf);
1975
1976   return 0;
1977 }
1978
1979 /* *INDENT-OFF* */
1980 svm_fifo_trace_elem_t fifo_trace[] = {};
1981 /* *INDENT-ON* */
1982
1983 static int
1984 sfifo_test_fifo_replay (vlib_main_t * vm, unformat_input_t * input)
1985 {
1986   svm_fifo_t f;
1987   int verbose = 0;
1988   u8 no_read = 0, *str = 0;
1989
1990   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1991     {
1992       if (unformat (input, "verbose"))
1993         verbose = 1;
1994       else if (unformat (input, "no-read"))
1995         no_read = 1;
1996       else
1997         {
1998           clib_error_t *e = clib_error_return
1999             (0, "unknown input `%U'", format_unformat_error, input);
2000           clib_error_report (e);
2001           return -1;
2002         }
2003     }
2004
2005 #if SVMF_FIFO_TRACE
2006   f.trace = fifo_trace;
2007 #endif
2008
2009   str = svm_fifo_replay (str, &f, no_read, verbose);
2010   vlib_cli_output (vm, "%v", str);
2011   return 0;
2012 }
2013
2014 static fifo_segment_main_t segment_main;
2015
2016 static svm_fifo_t *
2017 fifo_segment_alloc_fifo (fifo_segment_t * fs, u32 data_bytes,
2018                          fifo_segment_ftype_t ftype)
2019 {
2020   return fifo_segment_alloc_fifo_w_slice (fs, 0, data_bytes, ftype);
2021 }
2022
2023 static int
2024 sfifo_test_fifo_segment_hello_world (int verbose)
2025 {
2026   fifo_segment_create_args_t _a, *a = &_a;
2027   fifo_segment_main_t *sm = &segment_main;
2028   u8 *test_data, *retrieved_data = 0;
2029   fifo_segment_t *fs;
2030   svm_fifo_t *f;
2031   int rv;
2032
2033   clib_memset (a, 0, sizeof (*a));
2034   a->segment_name = "fifo-test1";
2035   a->segment_size = 256 << 10;
2036
2037   rv = fifo_segment_create (sm, a);
2038   SFIFO_TEST (!rv, "svm_fifo_segment_create returned %d", rv);
2039
2040   fs = fifo_segment_get_segment (sm, a->new_segment_indices[0]);
2041   f = fifo_segment_alloc_fifo (fs, 4096, FIFO_SEGMENT_RX_FIFO);
2042
2043   SFIFO_TEST (f != 0, "svm_fifo_segment_alloc_fifo");
2044
2045   test_data = format (0, "Hello world%c", 0);
2046   vec_validate (retrieved_data, vec_len (test_data) - 1);
2047
2048   while (svm_fifo_max_enqueue (f) >= vec_len (test_data))
2049     svm_fifo_enqueue (f, vec_len (test_data), test_data);
2050
2051   while (svm_fifo_max_dequeue (f) >= vec_len (test_data))
2052     svm_fifo_dequeue (f, vec_len (retrieved_data), retrieved_data);
2053
2054   while (svm_fifo_max_enqueue (f) >= vec_len (test_data))
2055     svm_fifo_enqueue (f, vec_len (test_data), test_data);
2056
2057   while (svm_fifo_max_dequeue (f) >= vec_len (test_data))
2058     svm_fifo_dequeue (f, vec_len (retrieved_data), retrieved_data);
2059
2060   SFIFO_TEST (!memcmp (retrieved_data, test_data, vec_len (test_data)),
2061               "data should be identical");
2062
2063   vec_free (test_data);
2064   vec_free (retrieved_data);
2065   vec_free (a->new_segment_indices);
2066   fifo_segment_free_fifo (fs, f);
2067   fifo_segment_delete (sm, fs);
2068   return 0;
2069 }
2070
2071 static int
2072 sfifo_test_fifo_segment_fifo_grow (int verbose)
2073 {
2074   int rv, fifo_size = 4096, n_chunks, n_batch;
2075   fifo_segment_main_t *sm = &segment_main;
2076   fifo_segment_create_args_t _a, *a = &_a;
2077   u32 n_free_chunk_bytes;
2078   fifo_segment_t *fs;
2079   svm_fifo_t *f;
2080
2081   clib_memset (a, 0, sizeof (*a));
2082   a->segment_name = "fifo-test1";
2083   /* size chosen to be able to force multi chunk allocation lower */
2084   a->segment_size = 256 << 10;
2085
2086   /* fifo allocation allocates chunks in batch */
2087   n_batch = FIFO_SEGMENT_ALLOC_BATCH_SIZE;
2088
2089   rv = fifo_segment_create (sm, a);
2090
2091   SFIFO_TEST (!rv, "svm_fifo_segment_create returned %d", rv);
2092
2093   /*
2094    * Alloc and grow fifo
2095    */
2096   fs = fifo_segment_get_segment (sm, a->new_segment_indices[0]);
2097   f = fifo_segment_alloc_fifo (fs, fifo_size, FIFO_SEGMENT_RX_FIFO);
2098
2099   SFIFO_TEST (f != 0, "svm_fifo_segment_alloc_fifo");
2100
2101   n_chunks = fifo_segment_num_free_chunks (fs, fifo_size);
2102   SFIFO_TEST (n_chunks == n_batch - 1, "free 2^10B chunks "
2103               "should be %u is %u", n_batch - 1, n_chunks);
2104   rv = fifo_segment_fl_chunk_bytes (fs);
2105   SFIFO_TEST (rv == (n_batch - 1) * fifo_size, "free chunk bytes %u "
2106               "expected %u", rv, (n_batch - 1) * fifo_size);
2107
2108   /* Grow by preallocated fifo_size chunk */
2109   fifo_segment_grow_fifo (fs, f, fifo_size);
2110   SFIFO_TEST (f->size == 2 * fifo_size, "fifo size should be %u is %u",
2111               2 * fifo_size, f->size);
2112   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
2113
2114   n_chunks = fifo_segment_num_free_chunks (fs, fifo_size);
2115   SFIFO_TEST (n_chunks == n_batch - 2, "free 2^10B chunks "
2116               "should be %u is %u", n_batch - 2, n_chunks);
2117   rv = fifo_segment_fl_chunk_bytes (fs);
2118   SFIFO_TEST (rv == (n_batch - 2) * fifo_size, "free chunk bytes %u "
2119               "expected %u", rv, (n_batch - 2) * fifo_size);
2120
2121   /* Grow by a size not preallocated but first make sure there's space */
2122   rv = fifo_segment_free_bytes (fs);
2123   SFIFO_TEST (rv > 16 * fifo_size, "free bytes %u more than %u", rv,
2124               16 * fifo_size);
2125
2126   fifo_segment_grow_fifo (fs, f, 16 * fifo_size);
2127   SFIFO_TEST (f->size == 18 * fifo_size, "fifo size should be %u is %u",
2128               18 * fifo_size, f->size);
2129
2130   rv = fifo_segment_fl_chunk_bytes (fs);
2131   SFIFO_TEST (rv == (n_batch - 2) * fifo_size, "free chunk bytes %u "
2132               "expected %u", rv, (n_batch - 2) * fifo_size);
2133
2134   /*
2135    * Free and test free list size
2136    */
2137   fifo_segment_free_fifo (fs, f);
2138
2139   rv = fifo_segment_fl_chunk_bytes (fs);
2140   SFIFO_TEST (rv == (16 + n_batch) * fifo_size, "free chunk bytes expected %u"
2141               " is %u", (16 + n_batch) * fifo_size, rv);
2142   n_chunks = fifo_segment_num_free_chunks (fs, fifo_size);
2143   SFIFO_TEST (n_chunks == n_batch, "free 2^10B chunks "
2144               "should be %u is %u", n_batch, n_chunks);
2145   n_chunks = fifo_segment_num_free_chunks (fs, 16 * fifo_size);
2146   SFIFO_TEST (n_chunks == 1, "free 2^14B chunks should be %u is %u", 1,
2147               n_chunks);
2148   n_chunks = fifo_segment_num_free_chunks (fs, ~0);
2149   SFIFO_TEST (n_chunks == 1 + n_batch, "free chunks should be %u is %u",
2150               1 + n_batch, n_chunks);
2151
2152   /*
2153    * Realloc fifo
2154    */
2155   f = fifo_segment_alloc_fifo (fs, fifo_size, FIFO_SEGMENT_RX_FIFO);
2156
2157   fifo_segment_grow_fifo (fs, f, fifo_size);
2158   n_chunks = fifo_segment_num_free_chunks (fs, fifo_size);
2159   SFIFO_TEST (n_chunks == n_batch - 2, "free 2^10B chunks should be %u is %u",
2160               n_batch - 2, n_chunks);
2161
2162   fifo_segment_grow_fifo (fs, f, 16 * fifo_size);
2163   n_chunks = fifo_segment_num_free_chunks (fs, 16 * fifo_size);
2164   SFIFO_TEST (n_chunks == 0, "free 2^14B chunks should be %u is %u", 0,
2165               n_chunks);
2166   n_chunks = fifo_segment_num_free_chunks (fs, ~0);
2167   SFIFO_TEST (n_chunks == n_batch - 2, "free chunks should be %u is %u",
2168               n_batch - 2, n_chunks);
2169
2170   /*
2171    * Free again
2172    */
2173   fifo_segment_free_fifo (fs, f);
2174   n_chunks = fifo_segment_num_free_chunks (fs, ~0);
2175   SFIFO_TEST (n_chunks == 1 + n_batch, "free chunks should be %u is %u",
2176               1 + n_batch, n_chunks);
2177
2178   rv = fifo_segment_fl_chunk_bytes (fs);
2179   SFIFO_TEST (rv == (16 + n_batch) * fifo_size, "free chunk bytes expected %u"
2180               " is %u", (16 + n_batch) * fifo_size, rv);
2181
2182   n_free_chunk_bytes = rv;
2183
2184   /*
2185    * Allocate non power of 2 fifo/chunk and check that free chunk bytes
2186    * is correctly updated
2187    */
2188
2189   f = fifo_segment_alloc_fifo (fs, 16 * fifo_size - 1, FIFO_SEGMENT_RX_FIFO);
2190   rv = fifo_segment_fl_chunk_bytes (fs);
2191
2192   SFIFO_TEST (n_free_chunk_bytes - 16 * fifo_size == rv, "free chunk bytes "
2193               "expected %u is %u", n_free_chunk_bytes - 16 * fifo_size, rv);
2194   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
2195
2196   fifo_segment_free_fifo (fs, f);
2197   rv = fifo_segment_fl_chunk_bytes (fs);
2198
2199   SFIFO_TEST (n_free_chunk_bytes == rv, "free chunk bytes expected %u is %u",
2200               n_free_chunk_bytes, rv);
2201
2202   /*
2203    * Force multi chunk fifo allocation
2204    */
2205
2206   /* Check that we can force multi chunk allocation. Note that fifo size
2207    * rounded up to power of 2, i.e., 17 becomes 32 */
2208   rv = fifo_segment_free_bytes (fs);
2209   SFIFO_TEST (rv < 32 * fifo_size, "free bytes %u less than %u", rv,
2210               32 * fifo_size);
2211
2212   f = fifo_segment_alloc_fifo (fs, 17 * fifo_size, FIFO_SEGMENT_RX_FIFO);
2213   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
2214
2215   rv = fifo_segment_fl_chunk_bytes (fs);
2216
2217   /* Make sure that the non-power of two chunk freed above is correctly
2218    * accounted for in the chunk free bytes reduction due to chunk allocation
2219    * for the fifo, i.e., it's rounded up by 1 */
2220   SFIFO_TEST (n_free_chunk_bytes - 17 * fifo_size == rv, "free chunk bytes "
2221               "expected %u is %u", n_free_chunk_bytes - 17 * fifo_size, rv);
2222
2223   fifo_segment_free_fifo (fs, f);
2224
2225   rv = fifo_segment_fl_chunk_bytes (fs);
2226   SFIFO_TEST (n_free_chunk_bytes == rv, "free chunk bytes expected %u is %u",
2227               n_free_chunk_bytes, rv);
2228
2229   /*
2230    * Allocate fifo that has all chunks
2231    */
2232   f = fifo_segment_alloc_fifo (fs, n_free_chunk_bytes, FIFO_SEGMENT_RX_FIFO);
2233   SFIFO_TEST (f != 0, "allocation should work");
2234   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
2235
2236   fifo_segment_free_fifo (fs, f);
2237
2238   rv = fifo_segment_fl_chunk_bytes (fs);
2239   SFIFO_TEST (n_free_chunk_bytes == rv, "free chunk bytes expected %u is %u",
2240               n_free_chunk_bytes, rv);
2241
2242   /*
2243    * Try to allocate more than space available
2244    */
2245
2246   f = fifo_segment_alloc_fifo (fs, n_free_chunk_bytes + fifo_size,
2247                                FIFO_SEGMENT_RX_FIFO);
2248   SFIFO_TEST (f == 0, "allocation should fail");
2249
2250   /*
2251    * Allocate fifo and try to grow beyond available space
2252    */
2253   f = fifo_segment_alloc_fifo (fs, fifo_size, FIFO_SEGMENT_RX_FIFO);
2254   rv = fifo_segment_grow_fifo (fs, f, n_free_chunk_bytes);
2255
2256   SFIFO_TEST (rv == -1, "grow should fail");
2257
2258   fifo_segment_free_fifo (fs, f);
2259
2260   /*
2261    * Cleanup
2262    */
2263   fifo_segment_delete (sm, fs);
2264   vec_free (a->new_segment_indices);
2265   return 0;
2266 }
2267
2268 static int
2269 sfifo_test_fifo_segment_fifo_shrink (int verbose)
2270 {
2271   int i, rv, chunk_size = 4096, n_chunks, n_free;
2272   fifo_segment_main_t *sm = &segment_main;
2273   fifo_segment_create_args_t _a, *a = &_a;
2274   fifo_segment_t *fs;
2275   svm_fifo_t *f;
2276
2277   clib_memset (a, 0, sizeof (*a));
2278   a->segment_name = "fifo-test1";
2279   a->segment_size = 256 << 10;
2280
2281   rv = fifo_segment_create (sm, a);
2282
2283   SFIFO_TEST (!rv, "svm_fifo_segment_create returned %d", rv);
2284
2285   /*
2286    * Alloc and grow fifo
2287    */
2288   fs = fifo_segment_get_segment (sm, a->new_segment_indices[0]);
2289   f = fifo_segment_alloc_fifo (fs, chunk_size, FIFO_SEGMENT_RX_FIFO);
2290   n_free = FIFO_SEGMENT_ALLOC_BATCH_SIZE - 1;
2291
2292   SFIFO_TEST (f != 0, "svm_fifo_segment_alloc_fifo");
2293
2294   for (i = 0; i < 9; i++)
2295     {
2296       fifo_segment_grow_fifo (fs, f, chunk_size);
2297       n_free -= 1;
2298       if (f->size != (i + 2) * chunk_size)
2299         SFIFO_TEST (0, "fifo size should be %u is %u",
2300                     (i + 2) * chunk_size, f->size);
2301     }
2302
2303   rv = svm_fifo_reduce_size (f, 3.5 * chunk_size, 1 /* is producer */ );
2304   SFIFO_TEST (rv == 3 * chunk_size, "len expected %u is %u", 3 * chunk_size,
2305               rv);
2306
2307   n_chunks = fifo_segment_num_free_chunks (fs, chunk_size);
2308   SFIFO_TEST (n_chunks == n_free, "free chunks should be %u is %u", n_free,
2309               n_chunks);
2310
2311   fifo_segment_collect_fifo_chunks (fs, f);
2312
2313   n_free += 3;
2314   n_chunks = fifo_segment_num_free_chunks (fs, chunk_size);
2315   SFIFO_TEST (n_chunks == n_free, "free chunks should be %u is %u", n_free,
2316               n_chunks);
2317
2318   rv = svm_fifo_reduce_size (f, 7 * chunk_size - 1, 1 /* is producer */ );
2319   SFIFO_TEST (rv == 6 * chunk_size, "len expected %u is %u", 6 * chunk_size,
2320               rv);
2321
2322   fifo_segment_collect_fifo_chunks (fs, f);
2323
2324   n_free += 6;
2325   n_chunks = fifo_segment_num_free_chunks (fs, chunk_size);
2326   SFIFO_TEST (n_chunks == n_free, "free chunks should be %u is %u", n_free,
2327               n_chunks);
2328   /*
2329    * Free
2330    */
2331   fifo_segment_free_fifo (fs, f);
2332   n_free += 1;
2333   n_chunks = fifo_segment_num_free_chunks (fs, ~0);
2334   SFIFO_TEST (n_chunks == n_free, "free chunks should be %u is %u", n_free,
2335               n_chunks);
2336
2337   /*
2338    * Cleanup
2339    */
2340   fifo_segment_delete (sm, fs);
2341   vec_free (a->new_segment_indices);
2342   return 0;
2343 }
2344
2345 static int
2346 sfifo_test_fifo_segment_slave (int verbose)
2347 {
2348   fifo_segment_create_args_t _a, *a = &_a;
2349   fifo_segment_main_t *sm = &segment_main;
2350   u8 *test_data, *retrieved_data = 0;
2351   fifo_segment_t *fs;
2352   svm_fifo_t *f;
2353   u32 *result;
2354   int rv, i;
2355
2356   sleep (2);
2357
2358   sm->timeout_in_seconds = 5;
2359   clib_memset (a, 0, sizeof (*a));
2360   a->segment_name = "fifo-test1";
2361
2362   rv = fifo_segment_attach (sm, a);
2363
2364   SFIFO_TEST (!rv, "svm_fifo_segment_attach returned %d", rv);
2365
2366   fs = fifo_segment_get_segment (sm, a->new_segment_indices[0]);
2367   vec_free (a->new_segment_indices);
2368
2369   /* might wanna wait.. */
2370   f = fifo_segment_get_slice_fifo_list (fs, 0);
2371
2372   /* Lazy bastards united */
2373   test_data = format (0, "Hello world%c", 0);
2374   vec_validate (retrieved_data, vec_len (test_data) - 1);
2375
2376   for (i = 0; i < 1000; i++)
2377     {
2378       svm_fifo_dequeue (f, vec_len (retrieved_data), retrieved_data);
2379       if (memcmp (retrieved_data, test_data, vec_len (retrieved_data)))
2380         {
2381           result = (u32 *) f->head_chunk->data;
2382           *result = 1;
2383           _exit (0);
2384         }
2385     }
2386
2387   result = (u32 *) f->head_chunk->data;
2388   *result = 0;
2389
2390   vec_free (test_data);
2391   vec_free (retrieved_data);
2392   _exit (0);
2393 }
2394
2395 static int
2396 sfifo_test_fifo_segment_master_slave (int verbose)
2397 {
2398   fifo_segment_create_args_t _a, *a = &_a;
2399   fifo_segment_main_t *sm = &segment_main;
2400   fifo_segment_t *sp;
2401   svm_fifo_t *f;
2402   u8 *test_data;
2403   u32 *result;
2404   int rv, i;
2405   pid_t pid;
2406
2407   pid = fork ();
2408   if (pid < 0)
2409     SFIFO_TEST (0, "fork failed");
2410
2411   if (!pid)
2412     sfifo_test_fifo_segment_slave (verbose);
2413
2414   clib_memset (a, 0, sizeof (*a));
2415   a->segment_name = "fifo-test1";
2416   a->segment_size = 256 << 10;
2417
2418   rv = fifo_segment_create (sm, a);
2419
2420   SFIFO_TEST (!rv, "svm_fifo_segment_create returned %d", rv);
2421
2422   sp = fifo_segment_get_segment (sm, a->new_segment_indices[0]);
2423   f = fifo_segment_alloc_fifo (sp, 4096, FIFO_SEGMENT_RX_FIFO);
2424
2425   SFIFO_TEST (f != 0, "svm_fifo_segment_alloc_fifo alloc");
2426
2427   test_data = format (0, "Hello world%c", 0);
2428
2429   usleep (200e3);
2430
2431   for (i = 0; i < 1000; i++)
2432     svm_fifo_enqueue (f, vec_len (test_data), test_data);
2433
2434   /* Wait for slave */
2435   i = 0;
2436   while (svm_fifo_max_dequeue (f) && i++ < 1e10)
2437     ;
2438
2439   usleep (1e3);
2440
2441   result = (u32 *) f->head_chunk->data;
2442   SFIFO_TEST (*result == 0, "slave reported no error");
2443
2444   vec_free (a->new_segment_indices);
2445   vec_free (test_data);
2446   fifo_segment_free_fifo (sp, f);
2447   fifo_segment_delete (sm, sp);
2448   return 0;
2449 }
2450
2451 static int
2452 sfifo_test_fifo_segment_mempig (int verbose)
2453 {
2454   fifo_segment_create_args_t _a, *a = &_a;
2455   fifo_segment_main_t *sm = &segment_main;
2456   fifo_segment_t *sp;
2457   svm_fifo_t *f;
2458   svm_fifo_t **flist = 0;
2459   int rv;
2460   int i;
2461
2462   clib_memset (a, 0, sizeof (*a));
2463
2464   a->segment_name = "fifo-test1";
2465   a->segment_size = 256 << 10;
2466
2467   rv = fifo_segment_create (sm, a);
2468
2469   SFIFO_TEST (!rv, "svm_fifo_segment_create returned %d", rv);
2470
2471   sp = fifo_segment_get_segment (sm, a->new_segment_indices[0]);
2472
2473   for (i = 0; i < 1000; i++)
2474     {
2475       f = fifo_segment_alloc_fifo (sp, 4096, FIFO_SEGMENT_RX_FIFO);
2476       if (f == 0)
2477         break;
2478       vec_add1 (flist, f);
2479     }
2480
2481   SFIFO_TEST (vec_len (flist), "created %d fifos", vec_len (flist));
2482
2483   for (i = 0; i < vec_len (flist); i++)
2484     {
2485       f = flist[i];
2486       fifo_segment_free_fifo (sp, f);
2487     }
2488
2489   _vec_len (flist) = 0;
2490
2491   for (i = 0; i < 1000; i++)
2492     {
2493       f = fifo_segment_alloc_fifo (sp, 4096, FIFO_SEGMENT_RX_FIFO);
2494       if (f == 0)
2495         break;
2496       vec_add1 (flist, f);
2497     }
2498
2499   SFIFO_TEST (vec_len (flist), "second try created %d fifos",
2500               vec_len (flist));
2501   for (i = 0; i < vec_len (flist); i++)
2502     {
2503       f = flist[i];
2504       fifo_segment_free_fifo (sp, f);
2505     }
2506
2507   fifo_segment_delete (sm, sp);
2508   return 0;
2509 }
2510
2511 static int
2512 sfifo_test_fifo_segment_prealloc (int verbose)
2513 {
2514   fifo_segment_create_args_t _a, *a = &_a;
2515   fifo_segment_main_t *sm = &segment_main;
2516   u32 max_pairs, pairs_req, free_space, pair_mem;
2517   svm_fifo_t *f, *old;
2518   fifo_segment_t *fs;
2519   int rv, alloc;
2520
2521   clib_memset (a, 0, sizeof (*a));
2522
2523   a->segment_name = "fifo-test-prealloc";
2524   a->segment_size = 256 << 10;
2525   a->segment_type = SSVM_SEGMENT_MEMFD;
2526
2527   rv = fifo_segment_create (sm, a);
2528   SFIFO_TEST (!rv, "svm_fifo_segment_create returned %d", rv);
2529   fs = fifo_segment_get_segment (sm, a->new_segment_indices[0]);
2530
2531   /*
2532    * Prealloc chunks and headers
2533    */
2534   free_space = fifo_segment_free_bytes (fs);
2535   SFIFO_TEST (free_space <= 256 << 10, "free space expected %u is %u",
2536               256 << 10, free_space);
2537   rv = fifo_segment_prealloc_fifo_chunks (fs, 0, 4096, 50);
2538   SFIFO_TEST (rv == 0, "chunk prealloc should work");
2539   rv = fifo_segment_num_free_chunks (fs, 4096);
2540   SFIFO_TEST (rv == 50, "prealloc chunks expected %u is %u", 50, rv);
2541   rv = fifo_segment_free_bytes (fs);
2542   free_space -= (sizeof (svm_fifo_chunk_t) + 4096) * 50;
2543   SFIFO_TEST (rv == free_space, "free space expected %u is %u", free_space,
2544               rv);
2545   rv = fifo_segment_fl_chunk_bytes (fs);
2546   SFIFO_TEST (rv == 4096 * 50, "chunk free space expected %u is %u",
2547               4096 * 50, rv);
2548
2549   rv = fifo_segment_prealloc_fifo_hdrs (fs, 0, 50);
2550   SFIFO_TEST (rv == 0, "fifo hdr prealloc should work");
2551   rv = fifo_segment_num_free_fifos (fs);
2552   SFIFO_TEST (rv == 50, "prealloc fifo hdrs expected %u is %u", 50, rv);
2553   rv = fifo_segment_free_bytes (fs);
2554   free_space -= sizeof (svm_fifo_t) * 50;
2555   SFIFO_TEST (rv == free_space, "free space expected %u is %u", free_space,
2556               rv);
2557
2558   fifo_segment_update_free_bytes (fs);
2559   rv = fifo_segment_free_bytes (fs);
2560   SFIFO_TEST (clib_abs (rv - (int) free_space) < 512,
2561               "free space expected %u is %u", free_space, rv);
2562
2563   f = fifo_segment_alloc_fifo (fs, 200 << 10, FIFO_SEGMENT_RX_FIFO);
2564   SFIFO_TEST (f != 0, "fifo allocated");
2565   rv = fifo_segment_num_free_chunks (fs, 4096);
2566   SFIFO_TEST (rv == 0, "prealloc chunks expected %u is %u", 0, rv);
2567   rv = fifo_segment_fl_chunk_bytes (fs);
2568   SFIFO_TEST (rv == 0, "chunk free space expected %u is %u", 0, rv);
2569   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
2570
2571   /*
2572    * Multiple preallocs that consume the remaining space
2573    */
2574   fifo_segment_update_free_bytes (fs);
2575   free_space = fifo_segment_free_bytes (fs);
2576   pair_mem = 2 * (4096 + sizeof (*f) + sizeof (svm_fifo_chunk_t));
2577   max_pairs = pairs_req = (free_space / pair_mem) - 1;
2578   fifo_segment_preallocate_fifo_pairs (fs, 4096, 4096, &pairs_req);
2579   SFIFO_TEST (pairs_req == 0, "prealloc pairs should work req %u", max_pairs);
2580   rv = fifo_segment_num_free_chunks (fs, 4096);
2581   SFIFO_TEST (rv == max_pairs * 2, "prealloc chunks expected %u is %u",
2582               max_pairs * 2, rv);
2583
2584   fifo_segment_update_free_bytes (fs);
2585   rv = fifo_segment_free_bytes (fs);
2586   SFIFO_TEST (rv < 2 * pair_mem, "free bytes %u less than %u", rv,
2587               2 * pair_mem);
2588
2589   /* Preallocate as many more chunks as possible. Heap is almost full
2590    * so we may not use all the free space*/
2591   alloc = 0;
2592   while (!fifo_segment_prealloc_fifo_chunks (fs, 0, 4096, 1))
2593     alloc++;
2594   SFIFO_TEST (alloc, "chunk prealloc should work %u", alloc);
2595   rv = fifo_segment_num_free_chunks (fs, 4096);
2596   SFIFO_TEST (rv == max_pairs * 2 + alloc, "prealloc chunks expected %u "
2597               "is %u", max_pairs * 2 + alloc, rv);
2598
2599   rv = fifo_segment_free_bytes (fs);
2600   SFIFO_TEST (rv < pair_mem, "free bytes expected less than %u is %u",
2601               pair_mem, rv);
2602
2603   /*
2604    * Test negative prealloc cases
2605    */
2606   pairs_req = 1;
2607   fifo_segment_preallocate_fifo_pairs (fs, 4096, 4096, &pairs_req);
2608   SFIFO_TEST (pairs_req == 1, "prealloc pairs should not work");
2609
2610   old = f;
2611   f = fifo_segment_alloc_fifo (fs, 200 << 10, FIFO_SEGMENT_RX_FIFO);
2612   SFIFO_TEST (f == 0, "fifo alloc should fail");
2613
2614   rv = fifo_segment_prealloc_fifo_chunks (fs, 0, 4096, 50);
2615   SFIFO_TEST (rv == -1, "chunk prealloc should fail");
2616
2617   rv = fifo_segment_prealloc_fifo_hdrs (fs, 0, 50);
2618   SFIFO_TEST (rv == -1, "fifo hdr prealloc should fail");
2619
2620   /*
2621    * Cleanup
2622    */
2623   fifo_segment_free_fifo (fs, old);
2624   close (fs->ssvm.fd);
2625   fifo_segment_delete (sm, fs);
2626   return 0;
2627 }
2628
2629 static int
2630 sfifo_test_fifo_segment (vlib_main_t * vm, unformat_input_t * input)
2631 {
2632   int rv, verbose = 0;
2633
2634   fifo_segment_main_init (&segment_main, HIGH_SEGMENT_BASEVA, 5);
2635   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2636     {
2637       if (unformat (input, "verbose"))
2638         verbose = 1;
2639       else if (unformat (input, "masterslave"))
2640         {
2641           if ((rv = sfifo_test_fifo_segment_master_slave (verbose)))
2642             return -1;
2643         }
2644       else if (unformat (input, "basic"))
2645         {
2646           if ((rv = sfifo_test_fifo_segment_hello_world (verbose)))
2647             return -1;
2648         }
2649       else if (unformat (input, "mempig"))
2650         {
2651           if ((rv = sfifo_test_fifo_segment_mempig (verbose)))
2652             return -1;
2653         }
2654       else if (unformat (input, "grow fifo"))
2655         {
2656           if ((rv = sfifo_test_fifo_segment_fifo_grow (verbose)))
2657             return -1;
2658         }
2659       else if (unformat (input, "shrink fifo"))
2660         {
2661           if ((rv = sfifo_test_fifo_segment_fifo_shrink (verbose)))
2662             return -1;
2663         }
2664       else if (unformat (input, "prealloc"))
2665         {
2666           if ((rv = sfifo_test_fifo_segment_prealloc (verbose)))
2667             return -1;
2668         }
2669       else if (unformat (input, "all"))
2670         {
2671           if ((rv = sfifo_test_fifo_segment_hello_world (verbose)))
2672             return -1;
2673           if ((rv = sfifo_test_fifo_segment_mempig (verbose)))
2674             return -1;
2675           if ((rv = sfifo_test_fifo_segment_fifo_grow (verbose)))
2676             return -1;
2677           if ((rv = sfifo_test_fifo_segment_fifo_shrink (verbose)))
2678             return -1;
2679           if ((rv = sfifo_test_fifo_segment_prealloc (verbose)))
2680             return -1;
2681           /* Pretty slow so avoid running it always
2682              if ((rv = sfifo_test_fifo_segment_master_slave (verbose)))
2683              return -1;
2684            */
2685         }
2686       else
2687         {
2688           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
2689                            input);
2690           return -1;
2691         }
2692     }
2693   return 0;
2694 }
2695
2696 static clib_error_t *
2697 svm_fifo_test (vlib_main_t * vm, unformat_input_t * input,
2698                vlib_cli_command_t * cmd_arg)
2699 {
2700   int res = 0;
2701   char *str;
2702
2703
2704   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2705     {
2706       if (unformat (input, "fifo1"))
2707         res = sfifo_test_fifo1 (vm, input);
2708       else if (unformat (input, "fifo2"))
2709         res = sfifo_test_fifo2 (vm);
2710       else if (unformat (input, "fifo3"))
2711         res = sfifo_test_fifo3 (vm, input);
2712       else if (unformat (input, "fifo4"))
2713         res = sfifo_test_fifo4 (vm, input);
2714       else if (unformat (input, "fifo5"))
2715         res = sfifo_test_fifo5 (vm, input);
2716       else if (unformat (input, "fifo6"))
2717         res = sfifo_test_fifo6 (vm, input);
2718       else if (unformat (input, "fifo7"))
2719         res = sfifo_test_fifo7 (vm, input);
2720       else if (unformat (input, "large"))
2721         res = sfifo_test_fifo_large (vm, input);
2722       else if (unformat (input, "replay"))
2723         res = sfifo_test_fifo_replay (vm, input);
2724       else if (unformat (input, "grow"))
2725         res = sfifo_test_fifo_grow (vm, input);
2726       else if (unformat (input, "shrink"))
2727         res = sfifo_test_fifo_shrink (vm, input);
2728       else if (unformat (input, "segment"))
2729         res = sfifo_test_fifo_segment (vm, input);
2730       else if (unformat (input, "all"))
2731         {
2732           if ((res = sfifo_test_fifo1 (vm, input)))
2733             goto done;
2734
2735           if ((res = sfifo_test_fifo2 (vm)))
2736             goto done;
2737
2738           /*
2739            * Run a number of fifo3 configs
2740            */
2741           str = "nsegs 10 overlap seed 123";
2742           unformat_init_cstring (input, str);
2743           if ((res = sfifo_test_fifo3 (vm, input)))
2744             goto done;
2745           unformat_free (input);
2746
2747           str = "nsegs 10 overlap seed 123 in-seq-all";
2748           unformat_init_cstring (input, str);
2749           if ((res = sfifo_test_fifo3 (vm, input)))
2750             goto done;
2751           unformat_free (input);
2752
2753           str = "nsegs 10 overlap seed 123 initial-offset 3917";
2754           unformat_init_cstring (input, str);
2755           if ((res = sfifo_test_fifo3 (vm, input)))
2756             goto done;
2757           unformat_free (input);
2758
2759           str = "nsegs 10 overlap seed 123 initial-offset 3917 drop";
2760           unformat_init_cstring (input, str);
2761           if ((res = sfifo_test_fifo3 (vm, input)))
2762             goto done;
2763           unformat_free (input);
2764
2765           str = "nsegs 10 seed 123 initial-offset 3917 drop no-randomize";
2766           unformat_init_cstring (input, str);
2767           if ((res = sfifo_test_fifo3 (vm, input)))
2768             goto done;
2769           unformat_free (input);
2770
2771           if ((res = sfifo_test_fifo4 (vm, input)))
2772             goto done;
2773
2774           if ((res = sfifo_test_fifo5 (vm, input)))
2775             goto done;
2776
2777           if ((res = sfifo_test_fifo6 (vm, input)))
2778             goto done;
2779
2780           if ((res = sfifo_test_fifo7 (vm, input)))
2781             goto done;
2782
2783           if ((res = sfifo_test_fifo_grow (vm, input)))
2784             goto done;
2785
2786           if ((res = sfifo_test_fifo_shrink (vm, input)))
2787             goto done;
2788
2789           str = "all";
2790           unformat_init_cstring (input, str);
2791           if ((res = sfifo_test_fifo_segment (vm, input)))
2792             goto done;
2793         }
2794       else
2795         {
2796           vlib_cli_output (vm, "unknown input `%U'", format_unformat_error,
2797                            input);
2798           res = -1;
2799           goto done;
2800         }
2801
2802     }
2803
2804 done:
2805   if (res)
2806     return clib_error_return (0, "svm fifo unit test failed");
2807   return 0;
2808 }
2809
2810 /* *INDENT-OFF* */
2811 VLIB_CLI_COMMAND (svm_fifo_test_command, static) =
2812 {
2813   .path = "test svm fifo",
2814   .short_help = "internal svm fifo unit tests",
2815   .function = svm_fifo_test,
2816 };
2817 /* *INDENT-ON* */
2818
2819 /*
2820  * fd.io coding-style-patch-verification: ON
2821  *
2822  * Local Variables:
2823  * eval: (c-set-style "gnu")
2824  * End:
2825  */