a461e3b8b7dadf2f3a8e602b5572046b1e15a136
[vpp.git] / src / vnet / tcp / tcp_test.c
1 /*
2  * Copyright (c) 2017 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 <vnet/tcp/tcp.h>
16
17 #define TCP_TEST_I(_cond, _comment, _args...)                   \
18 ({                                                              \
19   int _evald = (_cond);                                         \
20   if (!(_evald)) {                                              \
21     fformat(stderr, "FAIL:%d: " _comment "\n",                  \
22             __LINE__, ##_args);                                 \
23   } else {                                                      \
24     fformat(stderr, "PASS:%d: " _comment "\n",                  \
25             __LINE__, ##_args);                                 \
26   }                                                             \
27   _evald;                                                       \
28 })
29
30 #define TCP_TEST(_cond, _comment, _args...)                     \
31 {                                                               \
32     if (!TCP_TEST_I(_cond, _comment, ##_args)) {                \
33         return 1;                                               \
34     }                                                           \
35 }
36
37 static int
38 tcp_test_sack_rx (vlib_main_t * vm, unformat_input_t * input)
39 {
40   tcp_connection_t _tc, *tc = &_tc;
41   sack_scoreboard_t *sb = &tc->sack_sb;
42   sack_block_t *sacks = 0, block;
43   sack_scoreboard_hole_t *hole;
44   int i, verbose = 0;
45
46   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
47     {
48       if (unformat (input, "verbose"))
49         verbose = 1;
50     }
51
52   memset (tc, 0, sizeof (*tc));
53
54   tc->snd_una = 0;
55   tc->snd_una_max = 1000;
56   tc->snd_nxt = 1000;
57   tc->rcv_opts.flags |= TCP_OPTS_FLAG_SACK;
58   scoreboard_init (&tc->sack_sb);
59
60   for (i = 0; i < 1000 / 100; i++)
61     {
62       block.start = i * 100;
63       block.end = (i + 1) * 100;
64       vec_add1 (sacks, block);
65     }
66
67   /*
68    * Inject even blocks
69    */
70
71   for (i = 0; i < 1000 / 200; i++)
72     {
73       vec_add1 (tc->rcv_opts.sacks, sacks[i * 2]);
74     }
75   tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
76   tcp_rcv_sacks (tc, 0);
77
78   if (verbose)
79     vlib_cli_output (vm, "sb after even blocks:\n%U", format_tcp_scoreboard,
80                      sb);
81
82   TCP_TEST ((pool_elts (sb->holes) == 5),
83             "scoreboard has %d elements", pool_elts (sb->holes));
84
85   /* First SACK block should be rejected */
86   hole = scoreboard_first_hole (sb);
87   TCP_TEST ((hole->start == 0 && hole->end == 200),
88             "first hole start %u end %u", hole->start, hole->end);
89   hole = scoreboard_last_hole (sb);
90   TCP_TEST ((hole->start == 900 && hole->end == 1000),
91             "last hole start %u end %u", hole->start, hole->end);
92   TCP_TEST ((sb->sacked_bytes == 400), "sacked bytes %d", sb->sacked_bytes);
93   TCP_TEST ((sb->snd_una_adv == 0), "snd_una_adv %u", sb->snd_una_adv);
94   TCP_TEST ((sb->last_sacked_bytes == 400),
95             "last sacked bytes %d", sb->last_sacked_bytes);
96   TCP_TEST ((sb->high_sacked == 900), "max byte sacked %u", sb->high_sacked);
97   /*
98    * Inject odd blocks
99    */
100
101   vec_reset_length (tc->rcv_opts.sacks);
102   for (i = 0; i < 1000 / 200; i++)
103     {
104       vec_add1 (tc->rcv_opts.sacks, sacks[i * 2 + 1]);
105     }
106   tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
107   tcp_rcv_sacks (tc, 0);
108
109   if (verbose)
110     vlib_cli_output (vm, "sb after odd blocks:\n%U", format_tcp_scoreboard,
111                      sb);
112
113   hole = scoreboard_first_hole (sb);
114   TCP_TEST ((pool_elts (sb->holes) == 1),
115             "scoreboard has %d holes", pool_elts (sb->holes));
116   TCP_TEST ((hole->start == 0 && hole->end == 100),
117             "first hole start %u end %u", hole->start, hole->end);
118   TCP_TEST ((sb->sacked_bytes == 900), "sacked bytes %d", sb->sacked_bytes);
119   TCP_TEST ((sb->snd_una_adv == 0), "snd_una_adv %u", sb->snd_una_adv);
120   TCP_TEST ((sb->high_sacked == 1000), "max sacked byte %u", sb->high_sacked);
121   TCP_TEST ((sb->last_sacked_bytes == 500),
122             "last sacked bytes %d", sb->last_sacked_bytes);
123
124   /*
125    *  Ack until byte 100, all bytes are now acked + sacked
126    */
127   tcp_rcv_sacks (tc, 100);
128   if (verbose)
129     vlib_cli_output (vm, "ack until byte 100:\n%U", format_tcp_scoreboard,
130                      sb);
131
132   TCP_TEST ((pool_elts (sb->holes) == 0),
133             "scoreboard has %d elements", pool_elts (sb->holes));
134   TCP_TEST ((sb->snd_una_adv == 900),
135             "snd_una_adv after ack %u", sb->snd_una_adv);
136   TCP_TEST ((sb->high_sacked == 1000), "max sacked byte %u", sb->high_sacked);
137   TCP_TEST ((sb->sacked_bytes == 0), "sacked bytes %d", sb->sacked_bytes);
138   TCP_TEST ((sb->last_sacked_bytes == 0),
139             "last sacked bytes %d", sb->last_sacked_bytes);
140
141   /*
142    * Add new block
143    */
144
145   vec_reset_length (tc->rcv_opts.sacks);
146
147   block.start = 1200;
148   block.end = 1300;
149   vec_add1 (tc->rcv_opts.sacks, block);
150
151   if (verbose)
152     vlib_cli_output (vm, "add [1200, 1300]:\n%U", format_tcp_scoreboard, sb);
153   tc->snd_una_max = 1500;
154   tc->snd_una = 1000;
155   tc->snd_nxt = 1500;
156   tcp_rcv_sacks (tc, 1000);
157
158   if (verbose)
159     vlib_cli_output (vm, "sb snd_una_max 1500, snd_una 1000:\n%U",
160                      format_tcp_scoreboard, sb);
161
162   TCP_TEST ((sb->snd_una_adv == 0),
163             "snd_una_adv after ack %u", sb->snd_una_adv);
164   TCP_TEST ((pool_elts (sb->holes) == 2),
165             "scoreboard has %d holes", pool_elts (sb->holes));
166   hole = scoreboard_first_hole (sb);
167   TCP_TEST ((hole->start == 1000 && hole->end == 1200),
168             "first hole start %u end %u", hole->start, hole->end);
169   TCP_TEST ((sb->snd_una_adv == 0),
170             "snd_una_adv after ack %u", sb->snd_una_adv);
171   TCP_TEST ((sb->high_sacked == 1300), "max sacked byte %u", sb->high_sacked);
172   hole = scoreboard_last_hole (sb);
173   TCP_TEST ((hole->start == 1300 && hole->end == 1500),
174             "last hole start %u end %u", hole->start, hole->end);
175   TCP_TEST ((sb->sacked_bytes == 100), "sacked bytes %d", sb->sacked_bytes);
176
177   /*
178    * Ack first hole
179    */
180
181   vec_reset_length (tc->rcv_opts.sacks);
182   tcp_rcv_sacks (tc, 1200);
183
184   if (verbose)
185     vlib_cli_output (vm, "sb ack up to byte 1200:\n%U", format_tcp_scoreboard,
186                      sb);
187
188   TCP_TEST ((sb->snd_una_adv == 100),
189             "snd_una_adv after ack %u", sb->snd_una_adv);
190   TCP_TEST ((sb->sacked_bytes == 0), "sacked bytes %d", sb->sacked_bytes);
191   TCP_TEST ((pool_elts (sb->holes) == 1),
192             "scoreboard has %d elements", pool_elts (sb->holes));
193   hole = scoreboard_first_hole (sb);
194   TCP_TEST ((hole->prev == TCP_INVALID_SACK_HOLE_INDEX
195              && hole->next == TCP_INVALID_SACK_HOLE_INDEX), "hole is valid");
196   TCP_TEST ((sb->last_bytes_delivered == 100), "last bytes delivered %d",
197             sb->last_bytes_delivered);
198
199   /*
200    * Add some more blocks and then remove all
201    */
202   vec_reset_length (tc->rcv_opts.sacks);
203   tc->snd_una += sb->snd_una_adv;
204   tc->snd_una_max = 1900;
205   for (i = 0; i < 5; i++)
206     {
207       block.start = i * 100 + 1200;
208       block.end = (i + 1) * 100 + 1200;
209       vec_add1 (tc->rcv_opts.sacks, block);
210     }
211   tcp_rcv_sacks (tc, 1900);
212
213   scoreboard_clear (sb);
214   if (verbose)
215     vlib_cli_output (vm, "sb cleared all:\n%U", format_tcp_scoreboard, sb);
216
217   TCP_TEST ((pool_elts (sb->holes) == 0),
218             "number of holes %d", pool_elts (sb->holes));
219   TCP_TEST ((sb->head == TCP_INVALID_SACK_HOLE_INDEX), "head %u", sb->head);
220   TCP_TEST ((sb->tail == TCP_INVALID_SACK_HOLE_INDEX), "tail %u", sb->tail);
221
222   /*
223    * Re-inject odd blocks and ack them all
224    */
225
226   tc->snd_una = 0;
227   tc->snd_una_max = 1000;
228   tc->snd_nxt = 1000;
229   for (i = 0; i < 5; i++)
230     {
231       vec_add1 (tc->rcv_opts.sacks, sacks[i * 2 + 1]);
232     }
233   tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
234   tcp_rcv_sacks (tc, 0);
235   if (verbose)
236     vlib_cli_output (vm, "sb added odd blocks and ack [0, 950]:\n%U",
237                      format_tcp_scoreboard, sb);
238
239   tcp_rcv_sacks (tc, 950);
240
241   if (verbose)
242     vlib_cli_output (vm, "sb added odd blocks and ack [0, 950]:\n%U",
243                      format_tcp_scoreboard, sb);
244
245   TCP_TEST ((pool_elts (sb->holes) == 0),
246             "scoreboard has %d elements", pool_elts (sb->holes));
247   TCP_TEST ((sb->snd_una_adv == 50), "snd_una_adv %u", sb->snd_una_adv);
248   TCP_TEST ((sb->sacked_bytes == 0), "sacked bytes %d", sb->sacked_bytes);
249   TCP_TEST ((sb->last_sacked_bytes == 0),
250             "last sacked bytes %d", sb->last_sacked_bytes);
251
252   /*
253    * Inject one block, ack it and overlap hole
254    */
255
256   tc->snd_una = 0;
257   tc->snd_una_max = 1000;
258   tc->snd_nxt = 1000;
259
260   block.start = 100;
261   block.end = 500;
262   vec_add1 (tc->rcv_opts.sacks, block);
263   tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
264
265   tcp_rcv_sacks (tc, 0);
266
267   if (verbose)
268     vlib_cli_output (vm, "sb added [100, 500]:\n%U",
269                      format_tcp_scoreboard, sb);
270
271   tcp_rcv_sacks (tc, 800);
272
273   if (verbose)
274     vlib_cli_output (vm, "sb ack [0, 800]:\n%U", format_tcp_scoreboard, sb);
275
276   TCP_TEST ((pool_elts (sb->holes) == 1),
277             "scoreboard has %d elements", pool_elts (sb->holes));
278   TCP_TEST ((sb->snd_una_adv == 0), "snd_una_adv %u", sb->snd_una_adv);
279   TCP_TEST ((sb->sacked_bytes == 0), "sacked bytes %d", sb->sacked_bytes);
280   TCP_TEST ((sb->last_sacked_bytes == 0),
281             "last sacked bytes %d", sb->last_sacked_bytes);
282   TCP_TEST ((sb->last_bytes_delivered == 400),
283             "last bytes delivered %d", sb->last_bytes_delivered);
284
285   return 0;
286 }
287
288 static int
289 tcp_test_sack_tx (vlib_main_t * vm, unformat_input_t * input)
290 {
291   tcp_connection_t _tc, *tc = &_tc;
292   sack_block_t *sacks;
293   int i, verbose = 0;
294
295   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
296     {
297       if (unformat (input, "verbose"))
298         verbose = 1;
299       else
300         {
301           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
302                            input);
303           return -1;
304         }
305     }
306
307   memset (tc, 0, sizeof (*tc));
308
309   /*
310    * Add odd sack block pairs
311    */
312   for (i = 1; i < 10; i += 2)
313     {
314       tcp_update_sack_list (tc, i * 100, (i + 1) * 100);
315     }
316
317   TCP_TEST ((vec_len (tc->snd_sacks) == 5), "sack blocks %d expected %d",
318             vec_len (tc->snd_sacks), 5);
319   TCP_TEST ((tc->snd_sacks[0].start = 900),
320             "first sack block start %u expected %u", tc->snd_sacks[0].start,
321             900);
322
323   /*
324    * Try to add one extra
325    */
326   sacks = vec_dup (tc->snd_sacks);
327
328   tcp_update_sack_list (tc, 1100, 1200);
329   TCP_TEST ((vec_len (tc->snd_sacks) == 5), "sack blocks %d expected %d",
330             vec_len (tc->snd_sacks), 5);
331   TCP_TEST ((tc->snd_sacks[0].start == 1100),
332             "first sack block start %u expected %u", tc->snd_sacks[0].start,
333             1100);
334
335   /* restore */
336   vec_free (tc->snd_sacks);
337   tc->snd_sacks = sacks;
338
339   /*
340    * Overlap first 2 segment
341    */
342   tc->rcv_nxt = 300;
343   tcp_update_sack_list (tc, 300, 300);
344   if (verbose)
345     vlib_cli_output (vm, "overlap first 2 segments:\n%U",
346                      format_tcp_sacks, tc);
347   TCP_TEST ((vec_len (tc->snd_sacks) == 3), "sack blocks %d expected %d",
348             vec_len (tc->snd_sacks), 3);
349   TCP_TEST ((tc->snd_sacks[0].start == 900),
350             "first sack block start %u expected %u", tc->snd_sacks[0].start,
351             500);
352
353   /*
354    * Add a new segment
355    */
356   tcp_update_sack_list (tc, 1100, 1200);
357   if (verbose)
358     vlib_cli_output (vm, "add new segment [1100, 1200]\n%U",
359                      format_tcp_sacks, tc);
360   TCP_TEST ((vec_len (tc->snd_sacks) == 4), "sack blocks %d expected %d",
361             vec_len (tc->snd_sacks), 4);
362   TCP_TEST ((tc->snd_sacks[0].start == 1100),
363             "first sack block start %u expected %u", tc->snd_sacks[0].start,
364             1100);
365
366   /*
367    * Join middle segments
368    */
369   tcp_update_sack_list (tc, 800, 900);
370   if (verbose)
371     vlib_cli_output (vm, "join middle segments [800, 900]\n%U",
372                      format_tcp_sacks, tc);
373
374   TCP_TEST ((vec_len (tc->snd_sacks) == 3), "sack blocks %d expected %d",
375             vec_len (tc->snd_sacks), 3);
376   TCP_TEST ((tc->snd_sacks[0].start == 700),
377             "first sack block start %u expected %u", tc->snd_sacks[0].start,
378             1100);
379
380   /*
381    * Advance rcv_nxt to overlap all
382    */
383   tc->rcv_nxt = 1200;
384   tcp_update_sack_list (tc, 1200, 1200);
385   if (verbose)
386     vlib_cli_output (vm, "advance rcv_nxt to 1200\n%U", format_tcp_sacks, tc);
387   TCP_TEST ((vec_len (tc->snd_sacks) == 0), "sack blocks %d expected %d",
388             vec_len (tc->snd_sacks), 0);
389   return 0;
390 }
391
392 static int
393 tcp_test_sack (vlib_main_t * vm, unformat_input_t * input)
394 {
395   int res = 0;
396
397   /* Run all tests */
398   if (unformat_check_input (input) == UNFORMAT_END_OF_INPUT)
399     {
400       if (tcp_test_sack_tx (vm, input))
401         {
402           return -1;
403         }
404
405       if (tcp_test_sack_rx (vm, input))
406         {
407           return -1;
408         }
409     }
410   else
411     {
412       if (unformat (input, "tx"))
413         {
414           res = tcp_test_sack_tx (vm, input);
415         }
416       else if (unformat (input, "rx"))
417         {
418           res = tcp_test_sack_rx (vm, input);
419         }
420     }
421
422   return res;
423 }
424
425
426 typedef struct
427 {
428   u32 offset;
429   u32 len;
430 } test_pattern_t;
431
432 /* *INDENT-OFF* */
433 test_pattern_t test_pattern[] = {
434   {380, 8}, {768, 8}, {1156, 8}, {1544, 8}, {1932, 8}, {2320, 8}, {2708, 8},
435   {2992, 8}, {372, 8}, {760, 8}, {1148, 8}, {1536, 8}, {1924, 8}, {2312, 8},
436   {2700, 8}, {2984, 8}, {364, 8}, {752, 8}, {1140, 8}, {1528, 8}, {1916, 8},
437   {2304, 8}, {2692, 8}, {2976, 8}, {356, 8}, {744, 8}, {1132, 8}, {1520, 8},
438   {1908, 8}, {2296, 8}, {2684, 8}, {2968, 8}, {348, 8}, {736, 8}, {1124, 8},
439   {1512, 8}, {1900, 8}, {2288, 8}, {2676, 8}, {2960, 8}, {340, 8}, {728, 8},
440   {1116, 8}, {1504, 8}, {1892, 8}, {2280, 8}, {2668, 8}, {2952, 8}, {332, 8},
441   {720, 8}, {1108, 8}, {1496, 8}, {1884, 8}, {2272, 8}, {2660, 8}, {2944, 8},
442   {324, 8}, {712, 8}, {1100, 8}, {1488, 8}, {1876, 8}, {2264, 8}, {2652, 8},
443   {2936, 8}, {316, 8}, {704, 8}, {1092, 8}, {1480, 8}, {1868, 8}, {2256, 8},
444   {2644, 8}, {2928, 8}, {308, 8}, {696, 8}, {1084, 8}, {1472, 8}, {1860, 8},
445   {2248, 8}, {2636, 8}, {2920, 8}, {300, 8}, {688, 8}, {1076, 8}, {1464, 8},
446   {1852, 8}, {2240, 8}, {2628, 8}, {2912, 8}, {292, 8}, {680, 8}, {1068, 8},
447   {1456, 8}, {1844, 8}, {2232, 8}, {2620, 8}, {2904, 8}, {284, 8}, {672, 8},
448   {1060, 8}, {1448, 8}, {1836, 8}, {2224, 8}, {2612, 8}, {2896, 8}, {276, 8},
449   {664, 8}, {1052, 8}, {1440, 8}, {1828, 8},  {2216, 8}, {2604, 8}, {2888, 8},
450   {268, 8}, {656, 8}, {1044, 8}, {1432, 8}, {1820, 8}, {2208, 8}, {2596, 8},
451   {2880, 8}, {260, 8}, {648, 8}, {1036, 8}, {1424, 8}, {1812, 8}, {2200, 8},
452   {2588, 8}, {2872, 8}, {252, 8}, {640, 8}, {1028, 8}, {1416, 8}, {1804, 8},
453   {2192, 8}, {2580, 8}, {2864, 8}, {244, 8}, {632, 8}, {1020, 8}, {1408, 8},
454   {1796, 8}, {2184, 8}, {2572, 8}, {2856, 8}, {236, 8}, {624, 8}, {1012, 8},
455   {1400, 8}, {1788, 8}, {2176, 8}, {2564, 8}, {2848, 8}, {228, 8}, {616, 8},
456   {1004, 8}, {1392, 8}, {1780, 8}, {2168, 8}, {2556, 8}, {2840, 8}, {220, 8},
457   {608, 8}, {996, 8}, {1384, 8}, {1772, 8}, {2160, 8}, {2548, 8}, {2832, 8},
458   {212, 8}, {600, 8}, {988, 8}, {1376, 8}, {1764, 8}, {2152, 8}, {2540, 8},
459   {2824, 8}, {204, 8}, {592, 8}, {980, 8}, {1368, 8}, {1756, 8}, {2144, 8},
460   {2532, 8}, {2816, 8}, {196, 8}, {584, 8}, {972, 8}, {1360, 8}, {1748, 8},
461   {2136, 8}, {2524, 8}, {2808, 8}, {188, 8}, {576, 8}, {964, 8}, {1352, 8},
462   {1740, 8}, {2128, 8}, {2516, 8}, {2800, 8}, {180, 8}, {568, 8}, {956, 8},
463   {1344, 8}, {1732, 8}, {2120, 8}, {2508, 8}, {2792, 8}, {172, 8}, {560, 8},
464   {948, 8}, {1336, 8}, {1724, 8}, {2112, 8}, {2500, 8}, {2784, 8}, {164, 8},
465   {552, 8}, {940, 8}, {1328, 8}, {1716, 8}, {2104, 8}, {2492, 8}, {2776, 8},
466   {156, 8}, {544, 8}, {932, 8}, {1320, 8}, {1708, 8}, {2096, 8}, {2484, 8},
467   {2768, 8}, {148, 8}, {536, 8}, {924, 8}, {1312, 8}, {1700, 8}, {2088, 8},
468   {2476, 8}, {2760, 8}, {140, 8}, {528, 8}, {916, 8}, {1304, 8}, {1692, 8},
469   {2080, 8}, {2468, 8}, {2752, 8}, {132, 8}, {520, 8}, {908, 8}, {1296, 8},
470   {1684, 8}, {2072, 8}, {2460, 8}, {2744, 8}, {124, 8}, {512, 8}, {900, 8},
471   {1288, 8}, {1676, 8}, {2064, 8}, {2452, 8}, {2736, 8}, {116, 8}, {504, 8},
472   {892, 8}, {1280, 8}, {1668, 8}, {2056, 8}, {2444, 8}, {2728, 8}, {108, 8},
473   {496, 8}, {884, 8}, {1272, 8}, {1660, 8}, {2048, 8}, {2436, 8}, {2720, 8},
474   {100, 8}, {488, 8}, {876, 8}, {1264, 8}, {1652, 8}, {2040, 8}, {2428, 8},
475   {2716, 4}, {92, 8}, {480, 8}, {868, 8}, {1256, 8}, {1644, 8}, {2032, 8},
476   {2420, 8}, {84, 8}, {472, 8}, {860, 8}, {1248, 8}, {1636, 8}, {2024, 8},
477   {2412, 8}, {76, 8}, {464, 8}, {852, 8}, {1240, 8}, {1628, 8}, {2016, 8},
478   {2404, 8}, {68, 8}, {456, 8}, {844, 8}, {1232, 8}, {1620, 8}, {2008, 8},
479   {2396, 8}, {60, 8}, {448, 8}, {836, 8}, {1224, 8}, {1612, 8}, {2000, 8},
480   {2388, 8}, {52, 8}, {440, 8}, {828, 8}, {1216, 8}, {1604, 8}, {1992, 8},
481   {2380, 8}, {44, 8}, {432, 8}, {820, 8}, {1208, 8}, {1596, 8}, {1984, 8},
482   {2372, 8}, {36, 8}, {424, 8}, {812, 8}, {1200, 8}, {1588, 8}, {1976, 8},
483   {2364, 8}, {28, 8}, {416, 8}, {804, 8}, {1192, 8}, {1580, 8}, {1968, 8},
484   {2356, 8}, {20, 8}, {408, 8}, {796, 8}, {1184, 8}, {1572, 8}, {1960, 8},
485   {2348, 8}, {12, 8}, {400, 8}, {788, 8}, {1176, 8}, {1564, 8}, {1952, 8},
486   {2340, 8}, {4, 8}, {392, 8}, {780, 8}, {1168, 8}, {1556, 8}, {1944, 8},
487   {2332, 8},
488   /* missing from original data set */
489   {388, 4}, {776, 4}, {1164, 4}, {1552, 4}, {1940, 4}, {2328, 4},
490 };
491 /* *INDENT-ON* */
492
493 int
494 pattern_cmp (const void *arg1, const void *arg2)
495 {
496   test_pattern_t *a1 = (test_pattern_t *) arg1;
497   test_pattern_t *a2 = (test_pattern_t *) arg2;
498
499   if (a1->offset < a2->offset)
500     return -1;
501   else if (a1->offset > a2->offset)
502     return 1;
503   return 0;
504 }
505
506 static u8
507 fifo_validate_pattern (vlib_main_t * vm, test_pattern_t * pattern,
508                        u32 pattern_length)
509 {
510   test_pattern_t *tp = pattern;
511   int i;
512
513   /* Go through the pattern and make 100% sure it's sane */
514   for (i = 0; i < pattern_length - 1; i++)
515     {
516       if (tp->offset + tp->len != (tp + 1)->offset)
517         {
518           vlib_cli_output (vm, "[%d] missing {%d, %d}", i,
519                            (tp->offset + tp->len),
520                            (tp + 1)->offset - (tp->offset + tp->len));
521           return 0;
522         }
523       tp++;
524     }
525   return 1;
526 }
527
528 static test_pattern_t *
529 fifo_get_validate_pattern (vlib_main_t * vm, test_pattern_t * test_data,
530                            u32 test_data_len)
531 {
532   test_pattern_t *validate_pattern = 0;
533
534   /* Validate, and try segments in order... */
535   vec_validate (validate_pattern, test_data_len - 1);
536   memcpy (validate_pattern, test_data,
537           test_data_len * sizeof (test_pattern_t));
538   qsort ((u8 *) validate_pattern, test_data_len, sizeof (test_pattern_t),
539          pattern_cmp);
540
541   if (fifo_validate_pattern (vm, validate_pattern, test_data_len) == 0)
542     return 0;
543
544   return validate_pattern;
545 }
546
547 static svm_fifo_t *
548 fifo_prepare (u32 fifo_size)
549 {
550   svm_fifo_t *f;
551   f = svm_fifo_create (fifo_size);
552
553   /* Paint fifo data vector with -1's */
554   memset (f->data, 0xFF, fifo_size);
555
556   return f;
557 }
558
559 static int
560 compare_data (u8 * data1, u8 * data2, u32 start, u32 len, u32 * index)
561 {
562   int i;
563
564   for (i = start; i < len; i++)
565     {
566       if (data1[i] != data2[i])
567         {
568           *index = i;
569           return 1;
570         }
571     }
572   return 0;
573 }
574
575 int
576 tcp_test_fifo1 (vlib_main_t * vm, unformat_input_t * input)
577 {
578   svm_fifo_t *f;
579   u32 fifo_size = 1 << 20;
580   u32 *test_data = 0;
581   u32 offset;
582   int i, rv, verbose = 0;
583   u32 data_word, test_data_len, j;
584   ooo_segment_t *ooo_seg;
585   u8 *data, *s, *data_buf = 0;
586
587   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
588     {
589       if (unformat (input, "verbose"))
590         verbose = 1;
591     }
592
593   test_data_len = fifo_size / sizeof (u32);
594   vec_validate (test_data, test_data_len - 1);
595
596   for (i = 0; i < vec_len (test_data); i++)
597     test_data[i] = i;
598
599   f = fifo_prepare (fifo_size);
600
601   /*
602    * Enqueue an initial (un-dequeued) chunk
603    */
604   rv = svm_fifo_enqueue_nowait (f, sizeof (u32), (u8 *) test_data);
605   TCP_TEST ((rv == sizeof (u32)), "enqueued %d", rv);
606   TCP_TEST ((f->tail == 4), "fifo tail %u", f->tail);
607
608   /*
609    * Create 3 chunks in the future. The offsets are relative
610    * to the current fifo tail
611    */
612   for (i = 0; i < 3; i++)
613     {
614       offset = (2 * i + 1) * sizeof (u32) - f->tail;
615       data = (u8 *) (test_data + (2 * i + 1));
616       if (i == 0)
617         {
618           rv = svm_fifo_enqueue_nowait (f, sizeof (u32), data);
619           rv = rv > 0 ? 0 : rv;
620         }
621       else
622         rv = svm_fifo_enqueue_with_offset (f, offset, sizeof (u32), data);
623       if (verbose)
624         vlib_cli_output (vm, "add [%d] [%d, %d]", 2 * i + 1, offset,
625                          offset + sizeof (u32));
626       if (rv)
627         {
628           clib_warning ("enqueue returned %d", rv);
629           goto err;
630         }
631     }
632
633   if (verbose)
634     vlib_cli_output (vm, "fifo after odd segs: %U", format_svm_fifo, f, 1);
635
636   TCP_TEST ((f->tail == 8), "fifo tail %u", f->tail);
637   TCP_TEST ((svm_fifo_number_ooo_segments (f) == 2),
638             "number of ooo segments %u", svm_fifo_number_ooo_segments (f));
639
640   /*
641    * Try adding a completely overlapped segment
642    */
643   offset = 3 * sizeof (u32) - f->tail;
644   data = (u8 *) (test_data + 3);
645   rv = svm_fifo_enqueue_with_offset (f, offset, sizeof (u32), data);
646   if (rv)
647     {
648       clib_warning ("enqueue returned %d", rv);
649       goto err;
650     }
651
652   if (verbose)
653     vlib_cli_output (vm, "fifo after overlap seg: %U", format_svm_fifo, f, 1);
654
655   TCP_TEST ((svm_fifo_number_ooo_segments (f) == 2),
656             "number of ooo segments %u", svm_fifo_number_ooo_segments (f));
657
658   /*
659    * Make sure format functions are not buggy
660    */
661   s = format (0, "%U", format_svm_fifo, f, 2);
662   vec_free (s);
663
664   /*
665    * Paint some of missing data backwards
666    */
667   for (i = 3; i > 1; i--)
668     {
669       offset = (2 * i + 0) * sizeof (u32) - f->tail;
670       data = (u8 *) (test_data + (2 * i + 0));
671       rv = svm_fifo_enqueue_with_offset (f, offset, sizeof (u32), data);
672       if (verbose)
673         vlib_cli_output (vm, "add [%d] [%d, %d]", 2 * i, offset,
674                          offset + sizeof (u32));
675       if (rv)
676         {
677           clib_warning ("enqueue returned %d", rv);
678           goto err;
679         }
680     }
681
682   if (verbose)
683     vlib_cli_output (vm, "fifo before missing link: %U", format_svm_fifo, f,
684                      1);
685   TCP_TEST ((svm_fifo_number_ooo_segments (f) == 1),
686             "number of ooo segments %u", svm_fifo_number_ooo_segments (f));
687   ooo_seg = svm_fifo_first_ooo_segment (f);
688   TCP_TEST ((ooo_seg->start == 12),
689             "first ooo seg position %u", ooo_seg->start);
690   TCP_TEST ((ooo_seg->length == 16),
691             "first ooo seg length %u", ooo_seg->length);
692
693   /*
694    * Enqueue the missing u32
695    */
696   rv = svm_fifo_enqueue_nowait (f, sizeof (u32), (u8 *) (test_data + 2));
697   if (verbose)
698     vlib_cli_output (vm, "fifo after missing link: %U", format_svm_fifo, f,
699                      1);
700   TCP_TEST ((rv == 20), "bytes to be enqueued %u", rv);
701   TCP_TEST ((svm_fifo_number_ooo_segments (f) == 0),
702             "number of ooo segments %u", svm_fifo_number_ooo_segments (f));
703
704   /*
705    * Collect results
706    */
707   for (i = 0; i < 7; i++)
708     {
709       rv = svm_fifo_dequeue_nowait (f, sizeof (u32), (u8 *) & data_word);
710       if (rv != sizeof (u32))
711         {
712           clib_warning ("bytes dequeues %u", rv);
713           goto err;
714         }
715       if (data_word != test_data[i])
716         {
717           clib_warning ("recovered [%d] %d not %d", i, data_word,
718                         test_data[i]);
719           goto err;
720         }
721     }
722
723   /*
724    * Test segment overlaps: last ooo segment overlaps all
725    */
726   svm_fifo_free (f);
727   f = fifo_prepare (fifo_size);
728
729   for (i = 0; i < 4; i++)
730     {
731       offset = (2 * i + 1) * sizeof (u32) - f->tail;
732       data = (u8 *) (test_data + (2 * i + 1));
733       rv = svm_fifo_enqueue_with_offset (f, offset, sizeof (u32), data);
734       if (verbose)
735         vlib_cli_output (vm, "add [%d] [%d, %d]", 2 * i + 1, offset,
736                          offset + sizeof (u32));
737       if (rv)
738         {
739           clib_warning ("enqueue returned %d", rv);
740           goto err;
741         }
742     }
743
744   rv = svm_fifo_enqueue_with_offset (f, 8 - f->tail, 21, data);
745   TCP_TEST ((rv == 0), "ooo enqueued %u", rv);
746   TCP_TEST ((svm_fifo_number_ooo_segments (f) == 1),
747             "number of ooo segments %u", svm_fifo_number_ooo_segments (f));
748
749   vec_validate (data_buf, vec_len (data));
750   svm_fifo_peek (f, 0, vec_len (data), data_buf);
751   if (compare_data (data_buf, data, 8, vec_len (data), &j))
752     {
753       TCP_TEST (0, "[%d] peeked %u expected %u", j, data_buf[j], data[j]);
754     }
755   vec_reset_length (data_buf);
756
757   /*
758    * Test segment overlaps: enqueue and overlap ooo segments
759    */
760   svm_fifo_free (f);
761   f = fifo_prepare (fifo_size);
762
763   for (i = 0; i < 4; i++)
764     {
765       offset = (2 * i + 1) * sizeof (u32) - f->tail;
766       data = (u8 *) (test_data + (2 * i + 1));
767       rv = svm_fifo_enqueue_with_offset (f, offset, sizeof (u32), data);
768       if (verbose)
769         vlib_cli_output (vm, "add [%d] [%d, %d]", 2 * i + 1, offset,
770                          offset + sizeof (u32));
771       if (rv)
772         {
773           clib_warning ("enqueue returned %d", rv);
774           goto err;
775         }
776     }
777
778   if (verbose)
779     vlib_cli_output (vm, "fifo after enqueue: %U", format_svm_fifo, f, 1);
780
781   rv = svm_fifo_enqueue_nowait (f, 29, data);
782   if (verbose)
783     vlib_cli_output (vm, "fifo after enqueueing 29: %U", format_svm_fifo, f,
784                      1);
785   TCP_TEST ((rv == 32), "ooo enqueued %u", rv);
786   TCP_TEST ((svm_fifo_number_ooo_segments (f) == 0),
787             "number of ooo segments %u", svm_fifo_number_ooo_segments (f));
788
789   vec_validate (data_buf, vec_len (data));
790   svm_fifo_peek (f, 0, vec_len (data), data_buf);
791   if (compare_data (data_buf, data, 0, vec_len (data), &j))
792     {
793       TCP_TEST (0, "[%d] peeked %u expected %u", j, data_buf[j], data[j]);
794     }
795
796   /* Try to peek beyond the data */
797   rv = svm_fifo_peek (f, svm_fifo_max_dequeue (f), vec_len (data), data_buf);
798   TCP_TEST ((rv == 0), "peeked %u expected 0", rv);
799
800   vec_free (data_buf);
801   svm_fifo_free (f);
802   vec_free (test_data);
803
804   return 0;
805
806 err:
807   svm_fifo_free (f);
808   vec_free (test_data);
809   return -1;
810 }
811
812 static int
813 tcp_test_fifo2 (vlib_main_t * vm)
814 {
815   svm_fifo_t *f;
816   u32 fifo_size = 1 << 20;
817   int i, rv, test_data_len;
818   u64 data64;
819   test_pattern_t *tp, *vp, *test_data;
820   ooo_segment_t *ooo_seg;
821
822   test_data = test_pattern;
823   test_data_len = ARRAY_LEN (test_pattern);
824
825   vp = fifo_get_validate_pattern (vm, test_data, test_data_len);
826
827   /* Create a fifo */
828   f = fifo_prepare (fifo_size);
829
830   /*
831    * Try with sorted data
832    */
833   for (i = 0; i < test_data_len; i++)
834     {
835       tp = vp + i;
836       data64 = tp->offset;
837       svm_fifo_enqueue_with_offset (f, tp->offset - f->tail, tp->len,
838                                     (u8 *) & data64);
839     }
840
841   /* Expected result: one big fat chunk at offset 4 */
842   TCP_TEST ((svm_fifo_number_ooo_segments (f) == 1),
843             "number of ooo segments %u", svm_fifo_number_ooo_segments (f));
844   ooo_seg = svm_fifo_first_ooo_segment (f);
845   TCP_TEST ((ooo_seg->start == 4),
846             "first ooo seg position %u", ooo_seg->start);
847   TCP_TEST ((ooo_seg->length == 2996),
848             "first ooo seg length %u", ooo_seg->length);
849
850   data64 = 0;
851   rv = svm_fifo_enqueue_nowait (f, sizeof (u32), (u8 *) & data64);
852   TCP_TEST ((rv == 3000), "bytes to be enqueued %u", rv);
853
854   svm_fifo_free (f);
855   vec_free (vp);
856
857   /*
858    * Now try it again w/ unsorted data...
859    */
860
861   f = fifo_prepare (fifo_size);
862
863   for (i = 0; i < test_data_len; i++)
864     {
865       tp = &test_data[i];
866       data64 = tp->offset;
867       rv = svm_fifo_enqueue_with_offset (f, tp->offset - f->tail, tp->len,
868                                          (u8 *) & data64);
869       if (rv)
870         {
871           clib_warning ("enqueue returned %d", rv);
872         }
873     }
874
875   /* Expecting the same result: one big fat chunk at offset 4 */
876   TCP_TEST ((svm_fifo_number_ooo_segments (f) == 1),
877             "number of ooo segments %u", svm_fifo_number_ooo_segments (f));
878   ooo_seg = svm_fifo_first_ooo_segment (f);
879   TCP_TEST ((ooo_seg->start == 4),
880             "first ooo seg position %u", ooo_seg->start);
881   TCP_TEST ((ooo_seg->length == 2996),
882             "first ooo seg length %u", ooo_seg->length);
883
884   data64 = 0;
885   rv = svm_fifo_enqueue_nowait (f, sizeof (u32), (u8 *) & data64);
886
887   TCP_TEST ((rv == 3000), "bytes to be enqueued %u", rv);
888
889   svm_fifo_free (f);
890
891   return 0;
892 }
893
894 static int
895 tcp_test_fifo3 (vlib_main_t * vm, unformat_input_t * input)
896 {
897   svm_fifo_t *f;
898   u32 fifo_size = 4 << 10;
899   u32 fifo_initial_offset = 0;
900   u32 total_size = 2 << 10;
901   int overlap = 0, verbose = 0, randomize = 1, drop = 0, in_seq_all = 0;
902   u8 *data_pattern = 0, *data_buf = 0;
903   test_pattern_t *tp, *generate = 0;
904   u32 nsegs = 2, seg_size, length_so_far;
905   u32 current_offset, offset_increment, len_this_chunk;
906   u32 seed = 0xdeaddabe, j;
907   int i, rv;
908
909   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
910     {
911       if (unformat (input, "fifo-size %d", &fifo_size))
912         ;
913       else if (unformat (input, "total-size %d", &total_size))
914         ;
915       else if (unformat (input, "verbose"))
916         verbose = 1;
917       else if (unformat (input, "overlap"))
918         overlap = 1;
919       else if (unformat (input, "initial-offset %d", &fifo_initial_offset))
920         ;
921       else if (unformat (input, "seed %d", &seed))
922         ;
923       else if (unformat (input, "nsegs %d", &nsegs))
924         ;
925       else if (unformat (input, "no-randomize"))
926         randomize = 0;
927       else if (unformat (input, "in-seq-all"))
928         in_seq_all = 1;
929       else if (unformat (input, "drop"))
930         drop = 1;
931       else
932         {
933           clib_error_t *e = clib_error_return
934             (0, "unknown input `%U'", format_unformat_error, input);
935           clib_error_report (e);
936           return -1;
937         }
938     }
939
940   if (total_size > fifo_size)
941     {
942       clib_warning ("total_size %d greater than fifo size %d", total_size,
943                     fifo_size);
944       return -1;
945     }
946   if (overlap && randomize == 0)
947     {
948       clib_warning ("Can't enqueue in-order with overlap");
949       return -1;
950     }
951
952   /*
953    * Generate data
954    */
955   vec_validate (data_pattern, total_size - 1);
956   for (i = 0; i < vec_len (data_pattern); i++)
957     data_pattern[i] = i & 0xff;
958
959   /*
960    * Generate segments
961    */
962   seg_size = total_size / nsegs;
963   length_so_far = 0;
964   current_offset = randomize;
965   while (length_so_far < total_size)
966     {
967       vec_add2 (generate, tp, 1);
968       len_this_chunk = clib_min (seg_size, total_size - length_so_far);
969       tp->offset = current_offset;
970       tp->len = len_this_chunk;
971
972       if (overlap && (len_this_chunk == seg_size))
973         do
974           {
975             offset_increment = len_this_chunk
976               % (1 + (random_u32 (&seed) % len_this_chunk));
977           }
978         while (offset_increment == 0);
979       else
980         offset_increment = len_this_chunk;
981
982       current_offset += offset_increment;
983       length_so_far = tp->offset + tp->len;
984     }
985
986   /*
987    * Validate segment list. Only valid for non-overlap cases.
988    */
989   if (overlap == 0)
990     fifo_validate_pattern (vm, generate, vec_len (generate));
991
992   if (verbose)
993     {
994       vlib_cli_output (vm, "raw data pattern:");
995       for (i = 0; i < vec_len (generate); i++)
996         {
997           vlib_cli_output (vm, "[%d] offset %u len %u", i,
998                            generate[i].offset, generate[i].len);
999         }
1000     }
1001
1002   /* Randomize data pattern */
1003   if (randomize)
1004     {
1005       for (i = 0; i < vec_len (generate) / 2; i++)
1006         {
1007           u32 src_index, dst_index;
1008           test_pattern_t _tmp, *tmp = &_tmp;
1009
1010           src_index = random_u32 (&seed) % vec_len (generate);
1011           dst_index = random_u32 (&seed) % vec_len (generate);
1012
1013           tmp[0] = generate[dst_index];
1014           generate[dst_index] = generate[src_index];
1015           generate[src_index] = tmp[0];
1016         }
1017       if (verbose)
1018         {
1019           vlib_cli_output (vm, "randomized data pattern:");
1020           for (i = 0; i < vec_len (generate); i++)
1021             {
1022               vlib_cli_output (vm, "[%d] offset %u len %u", i,
1023                                generate[i].offset, generate[i].len);
1024             }
1025         }
1026     }
1027
1028   /*
1029    * Create a fifo and add segments
1030    */
1031   f = fifo_prepare (fifo_size);
1032
1033   /* manually set head and tail pointers to validate modular arithmetic */
1034   fifo_initial_offset = fifo_initial_offset % fifo_size;
1035   f->head = fifo_initial_offset;
1036   f->tail = fifo_initial_offset;
1037
1038   for (i = !randomize; i < vec_len (generate); i++)
1039     {
1040       tp = generate + i;
1041       svm_fifo_enqueue_with_offset (f,
1042                                     fifo_initial_offset + tp->offset -
1043                                     f->tail, tp->len,
1044                                     (u8 *) data_pattern + tp->offset);
1045     }
1046
1047   /* Add the first segment in order for non random data */
1048   if (!randomize)
1049     svm_fifo_enqueue_nowait (f, generate[0].len, (u8 *) data_pattern);
1050
1051   /*
1052    * Expected result: one big fat chunk at offset 1 if randomize == 1
1053    */
1054
1055   if (verbose)
1056     vlib_cli_output (vm, "fifo before missing link: %U",
1057                      format_svm_fifo, f, 1 /* verbose */ );
1058
1059   /*
1060    * Add the missing byte if segments were randomized
1061    */
1062   if (randomize)
1063     {
1064       u32 bytes_to_enq = 1;
1065       if (in_seq_all)
1066         bytes_to_enq = total_size;
1067       rv = svm_fifo_enqueue_nowait (f, bytes_to_enq, data_pattern + 0);
1068
1069       if (verbose)
1070         vlib_cli_output (vm, "in-order enqueue returned %d", rv);
1071
1072       TCP_TEST ((rv == total_size), "enqueued %u expected %u", rv,
1073                 total_size);
1074
1075     }
1076
1077   TCP_TEST ((svm_fifo_has_ooo_data (f) == 0), "number of ooo segments %u",
1078             svm_fifo_number_ooo_segments (f));
1079
1080   /*
1081    * Test if peeked data is the same as original data
1082    */
1083   vec_validate (data_buf, vec_len (data_pattern));
1084   svm_fifo_peek (f, 0, vec_len (data_pattern), data_buf);
1085   if (compare_data (data_buf, data_pattern, 0, vec_len (data_pattern), &j))
1086     {
1087       TCP_TEST (0, "[%d] peeked %u expected %u", j, data_buf[j],
1088                 data_pattern[j]);
1089     }
1090   vec_reset_length (data_buf);
1091
1092   /*
1093    * Dequeue or drop all data
1094    */
1095   if (drop)
1096     {
1097       svm_fifo_dequeue_drop (f, vec_len (data_pattern));
1098     }
1099   else
1100     {
1101       svm_fifo_dequeue_nowait (f, vec_len (data_pattern), data_buf);
1102       if (compare_data
1103           (data_buf, data_pattern, 0, vec_len (data_pattern), &j))
1104         {
1105           TCP_TEST (0, "[%d] dequeued %u expected %u", j, data_buf[j],
1106                     data_pattern[j]);
1107         }
1108     }
1109
1110   TCP_TEST ((svm_fifo_max_dequeue (f) == 0), "fifo has %d bytes",
1111             svm_fifo_max_dequeue (f));
1112
1113   svm_fifo_free (f);
1114   vec_free (data_pattern);
1115   vec_free (data_buf);
1116
1117   return 0;
1118 }
1119
1120 static int
1121 tcp_test_fifo4 (vlib_main_t * vm, unformat_input_t * input)
1122 {
1123   svm_fifo_t *f;
1124   u32 fifo_size = 6 << 10;
1125   u32 fifo_initial_offset = 1000000000;
1126   u32 test_n_bytes = 5000, j;
1127   u8 *test_data = 0, *data_buf = 0;
1128   int i, rv, verbose = 0;
1129
1130   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1131     {
1132       if (unformat (input, "verbose"))
1133         verbose = 1;
1134       else
1135         {
1136           clib_error_t *e = clib_error_return
1137             (0, "unknown input `%U'", format_unformat_error, input);
1138           clib_error_report (e);
1139           return -1;
1140         }
1141     }
1142
1143   /*
1144    * Create a fifo and add segments
1145    */
1146   f = fifo_prepare (fifo_size);
1147
1148   /* Set head and tail pointers */
1149   fifo_initial_offset = fifo_initial_offset % fifo_size;
1150   svm_fifo_init_pointers (f, fifo_initial_offset);
1151
1152   vec_validate (test_data, test_n_bytes - 1);
1153   for (i = 0; i < vec_len (test_data); i++)
1154     test_data[i] = i;
1155
1156   for (i = test_n_bytes - 1; i > 0; i--)
1157     {
1158       rv = svm_fifo_enqueue_with_offset (f, fifo_initial_offset + i - f->tail,
1159                                          sizeof (u8), &test_data[i]);
1160       if (verbose)
1161         vlib_cli_output (vm, "add [%d] [%d, %d]", i, i, i + sizeof (u8));
1162       if (rv)
1163         {
1164           clib_warning ("enqueue returned %d", rv);
1165           svm_fifo_free (f);
1166           vec_free (test_data);
1167           return -1;
1168         }
1169     }
1170
1171   svm_fifo_enqueue_nowait (f, sizeof (u8), &test_data[0]);
1172
1173   vec_validate (data_buf, vec_len (test_data));
1174
1175   svm_fifo_dequeue_nowait (f, vec_len (test_data), data_buf);
1176   rv = compare_data (data_buf, test_data, 0, vec_len (test_data), &j);
1177   if (rv)
1178     vlib_cli_output (vm, "[%d] dequeued %u expected %u", j, data_buf[j],
1179                      test_data[j]);
1180   TCP_TEST ((rv == 0), "dequeued compared to original returned %d", rv);
1181
1182   svm_fifo_free (f);
1183   vec_free (test_data);
1184   return 0;
1185 }
1186
1187 static int
1188 tcp_test_fifo (vlib_main_t * vm, unformat_input_t * input)
1189 {
1190   int res = 0;
1191   char *str;
1192
1193   /* Run all tests */
1194   if (unformat_check_input (input) == UNFORMAT_END_OF_INPUT)
1195     {
1196       res = tcp_test_fifo1 (vm, input);
1197       if (res)
1198         return res;
1199
1200       res = tcp_test_fifo2 (vm);
1201       if (res)
1202         return res;
1203
1204       /*
1205        * Run a number of fifo3 configs
1206        */
1207       str = "nsegs 10 overlap seed 123";
1208       unformat_init_cstring (input, str);
1209       if (tcp_test_fifo3 (vm, input))
1210         return -1;
1211       unformat_free (input);
1212
1213       str = "nsegs 10 overlap seed 123 in-seq-all";
1214       unformat_init_cstring (input, str);
1215       if (tcp_test_fifo3 (vm, input))
1216         return -1;
1217       unformat_free (input);
1218
1219       str = "nsegs 10 overlap seed 123 initial-offset 3917";
1220       unformat_init_cstring (input, str);
1221       if (tcp_test_fifo3 (vm, input))
1222         return -1;
1223       unformat_free (input);
1224
1225       str = "nsegs 10 overlap seed 123 initial-offset 3917 drop";
1226       unformat_init_cstring (input, str);
1227       if (tcp_test_fifo3 (vm, input))
1228         return -1;
1229       unformat_free (input);
1230
1231       str = "nsegs 10 seed 123 initial-offset 3917 drop no-randomize";
1232       unformat_init_cstring (input, str);
1233       if (tcp_test_fifo3 (vm, input))
1234         return -1;
1235       unformat_free (input);
1236     }
1237   else
1238     {
1239       if (unformat (input, "fifo3"))
1240         {
1241           res = tcp_test_fifo3 (vm, input);
1242         }
1243       else if (unformat (input, "fifo2"))
1244         {
1245           res = tcp_test_fifo2 (vm);
1246         }
1247       else if (unformat (input, "fifo1"))
1248         {
1249           res = tcp_test_fifo1 (vm, input);
1250         }
1251       else if (unformat (input, "fifo4"))
1252         {
1253           res = tcp_test_fifo4 (vm, input);
1254         }
1255     }
1256
1257   return res;
1258 }
1259
1260 static int
1261 tcp_test_session (vlib_main_t * vm, unformat_input_t * input)
1262 {
1263   int rv = 0;
1264   tcp_connection_t *tc0;
1265   u8 sst = SESSION_TYPE_IP4_TCP;
1266   ip4_address_t local, remote;
1267   u16 local_port, remote_port;
1268   tcp_main_t *tm = vnet_get_tcp_main ();
1269   int is_add = 1;
1270
1271
1272   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1273     {
1274       if (unformat (input, "del"))
1275         is_add = 0;
1276       else if (unformat (input, "add"))
1277         is_add = 1;
1278       else
1279         break;
1280     }
1281
1282   if (is_add)
1283     {
1284       local.as_u32 = clib_host_to_net_u32 (0x06000101);
1285       remote.as_u32 = clib_host_to_net_u32 (0x06000102);
1286       local_port = clib_host_to_net_u16 (1234);
1287       remote_port = clib_host_to_net_u16 (11234);
1288
1289       pool_get (tm->connections[0], tc0);
1290       memset (tc0, 0, sizeof (*tc0));
1291
1292       tc0->state = TCP_STATE_ESTABLISHED;
1293       tc0->rcv_las = 1;
1294       tc0->c_c_index = tc0 - tm->connections[0];
1295       tc0->c_lcl_port = local_port;
1296       tc0->c_rmt_port = remote_port;
1297       tc0->c_is_ip4 = 1;
1298       tc0->c_thread_index = 0;
1299       tc0->c_lcl_ip4.as_u32 = local.as_u32;
1300       tc0->c_rmt_ip4.as_u32 = remote.as_u32;
1301       tc0->rcv_opts.mss = 1450;
1302       tcp_connection_init_vars (tc0);
1303
1304       TCP_EVT_DBG (TCP_EVT_OPEN, tc0);
1305
1306       if (stream_session_accept (&tc0->connection, 0 /* listener index */ ,
1307                                  sst, 0 /* notify */ ))
1308         clib_warning ("stream_session_accept failed");
1309
1310       stream_session_accept_notify (&tc0->connection);
1311     }
1312   else
1313     {
1314       tc0 = tcp_connection_get (0 /* connection index */ , 0 /* thread */ );
1315       tc0->state = TCP_STATE_CLOSED;
1316       stream_session_disconnect_notify (&tc0->connection);
1317     }
1318
1319   return rv;
1320 }
1321
1322 static clib_error_t *
1323 tcp_test (vlib_main_t * vm,
1324           unformat_input_t * input, vlib_cli_command_t * cmd_arg)
1325 {
1326   int res = 0;
1327
1328   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1329     {
1330       if (unformat (input, "sack"))
1331         {
1332           res = tcp_test_sack (vm, input);
1333         }
1334       else if (unformat (input, "fifo"))
1335         {
1336           res = tcp_test_fifo (vm, input);
1337         }
1338       else if (unformat (input, "session"))
1339         {
1340           res = tcp_test_session (vm, input);
1341         }
1342       else
1343         break;
1344     }
1345
1346   if (res)
1347     {
1348       return clib_error_return (0, "TCP unit test failed");
1349     }
1350   else
1351     {
1352       return 0;
1353     }
1354 }
1355
1356 /* *INDENT-OFF* */
1357 VLIB_CLI_COMMAND (tcp_test_command, static) =
1358 {
1359   .path = "test tcp",
1360   .short_help = "internal tcp unit tests",
1361   .function = tcp_test,
1362 };
1363 /* *INDENT-ON* */
1364
1365
1366 /*
1367  * fd.io coding-style-patch-verification: ON
1368  *
1369  * Local Variables:
1370  * eval: (c-set-style "gnu")
1371  * End:
1372  */