tcp: fix sacks lost bytes counting (VPP-1465)
[vpp.git] / src / plugins / unittest / 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 /* *INDENT-OFF* */
38 scoreboard_trace_elt_t sb_trace[] = {};
39 /* *INDENT-ON* */
40
41 static int
42 tcp_test_scoreboard_replay (vlib_main_t * vm, unformat_input_t * input)
43 {
44   int verbose = 0;
45   tcp_connection_t _tc, *tc = &_tc;
46   u8 *s = 0;
47
48   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
49     {
50       if (unformat (input, "detail"))
51         verbose = 1;
52       else
53         {
54           clib_error_t *e = clib_error_return
55             (0, "unknown input `%U'", format_unformat_error, input);
56           clib_error_report (e);
57           return -1;
58         }
59     }
60
61 #if TCP_SCOREBOARD_TRACE
62   tc->sack_sb.trace = sb_trace;
63 #endif
64   s = tcp_scoreboard_replay (s, tc, verbose);
65   vlib_cli_output (vm, "%v", s);
66   return 0;
67 }
68
69 static int
70 tcp_test_sack_rx (vlib_main_t * vm, unformat_input_t * input)
71 {
72   tcp_connection_t _tc, *tc = &_tc;
73   sack_scoreboard_t *sb = &tc->sack_sb;
74   sack_block_t *sacks = 0, block;
75   sack_scoreboard_hole_t *hole;
76   int i, verbose = 0;
77
78   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
79     {
80       if (unformat (input, "verbose"))
81         verbose = 1;
82       else if (unformat (input, "replay"))
83         return tcp_test_scoreboard_replay (vm, input);
84     }
85
86   memset (tc, 0, sizeof (*tc));
87
88   tc->snd_una = 0;
89   tc->snd_una_max = 1000;
90   tc->snd_nxt = 1000;
91   tc->rcv_opts.flags |= TCP_OPTS_FLAG_SACK;
92   tc->snd_mss = 150;
93   scoreboard_init (&tc->sack_sb);
94
95   for (i = 0; i < 1000 / 100; i++)
96     {
97       block.start = i * 100;
98       block.end = (i + 1) * 100;
99       vec_add1 (sacks, block);
100     }
101
102   /*
103    * Inject even blocks
104    */
105
106   for (i = 0; i < 1000 / 200; i++)
107     {
108       vec_add1 (tc->rcv_opts.sacks, sacks[i * 2]);
109     }
110   tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
111   tcp_rcv_sacks (tc, 0);
112
113   if (verbose)
114     vlib_cli_output (vm, "sb after even blocks (mss %u):\n%U",
115                      tc->snd_mss, format_tcp_scoreboard, sb, tc);
116
117   TCP_TEST ((pool_elts (sb->holes) == 5),
118             "scoreboard has %d elements", pool_elts (sb->holes));
119
120   /* First SACK block should be rejected */
121   hole = scoreboard_first_hole (sb);
122   TCP_TEST ((hole->start == 0 && hole->end == 200),
123             "first hole start %u end %u", hole->start, hole->end);
124   hole = scoreboard_last_hole (sb);
125   TCP_TEST ((hole->start == 900 && hole->end == 1000),
126             "last hole start %u end %u", hole->start, hole->end);
127   TCP_TEST ((sb->sacked_bytes == 400), "sacked bytes %d", sb->sacked_bytes);
128   TCP_TEST ((sb->snd_una_adv == 0), "snd_una_adv %u", sb->snd_una_adv);
129   TCP_TEST ((sb->last_sacked_bytes == 400),
130             "last sacked bytes %d", sb->last_sacked_bytes);
131   TCP_TEST ((sb->high_sacked == 900), "high sacked %u", sb->high_sacked);
132   TCP_TEST ((sb->lost_bytes == 200), "lost bytes %u", sb->lost_bytes);
133
134   /*
135    * Inject odd blocks
136    */
137
138   vec_reset_length (tc->rcv_opts.sacks);
139   for (i = 0; i < 1000 / 200; i++)
140     {
141       vec_add1 (tc->rcv_opts.sacks, sacks[i * 2 + 1]);
142     }
143   tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
144   tcp_rcv_sacks (tc, 0);
145
146   if (verbose)
147     vlib_cli_output (vm, "\nsb after odd blocks:\n%U", format_tcp_scoreboard,
148                      sb, tc);
149
150   hole = scoreboard_first_hole (sb);
151   TCP_TEST ((pool_elts (sb->holes) == 1),
152             "scoreboard has %d holes", pool_elts (sb->holes));
153   TCP_TEST ((hole->start == 0 && hole->end == 100),
154             "first hole start %u end %u", hole->start, hole->end);
155   TCP_TEST ((sb->sacked_bytes == 900), "sacked bytes %d", sb->sacked_bytes);
156   TCP_TEST ((sb->snd_una_adv == 0), "snd_una_adv %u", sb->snd_una_adv);
157   TCP_TEST ((sb->high_sacked == 1000), "high sacked %u", sb->high_sacked);
158   TCP_TEST ((sb->last_sacked_bytes == 500),
159             "last sacked bytes %d", sb->last_sacked_bytes);
160   TCP_TEST ((sb->lost_bytes == 100), "lost bytes %u", sb->lost_bytes);
161
162   /*
163    *  Ack until byte 100, all bytes are now acked + sacked
164    */
165   tcp_rcv_sacks (tc, 100);
166   if (verbose)
167     vlib_cli_output (vm, "\nack until byte 100:\n%U", format_tcp_scoreboard,
168                      sb, tc);
169
170   TCP_TEST ((pool_elts (sb->holes) == 0),
171             "scoreboard has %d elements", pool_elts (sb->holes));
172   TCP_TEST ((sb->snd_una_adv == 900),
173             "snd_una_adv after ack %u", sb->snd_una_adv);
174   TCP_TEST ((sb->high_sacked == 1000), "max sacked byte %u", sb->high_sacked);
175   TCP_TEST ((sb->sacked_bytes == 0), "sacked bytes %d", sb->sacked_bytes);
176   TCP_TEST ((sb->last_sacked_bytes == 0),
177             "last sacked bytes %d", sb->last_sacked_bytes);
178   TCP_TEST ((sb->lost_bytes == 0), "lost bytes %u", sb->lost_bytes);
179
180   /*
181    * Add new block
182    */
183
184   vec_reset_length (tc->rcv_opts.sacks);
185
186   block.start = 1200;
187   block.end = 1300;
188   vec_add1 (tc->rcv_opts.sacks, block);
189
190   tc->snd_una_max = 1500;
191   tc->snd_una = 1000;
192   tc->snd_nxt = 1500;
193   tcp_rcv_sacks (tc, 1000);
194
195   if (verbose)
196     vlib_cli_output (vm, "\nadd [1200, 1300] snd_una_max 1500, snd_una 1000:"
197                      " \n%U", format_tcp_scoreboard, sb, tc);
198
199   TCP_TEST ((sb->snd_una_adv == 0),
200             "snd_una_adv after ack %u", sb->snd_una_adv);
201   TCP_TEST ((pool_elts (sb->holes) == 2),
202             "scoreboard has %d holes", pool_elts (sb->holes));
203   hole = scoreboard_first_hole (sb);
204   TCP_TEST ((hole->start == 1000 && hole->end == 1200),
205             "first hole start %u end %u", hole->start, hole->end);
206   TCP_TEST ((sb->snd_una_adv == 0),
207             "snd_una_adv after ack %u", sb->snd_una_adv);
208   TCP_TEST ((sb->high_sacked == 1300), "max sacked byte %u", sb->high_sacked);
209   hole = scoreboard_last_hole (sb);
210   TCP_TEST ((hole->start == 1300 && hole->end == 1500),
211             "last hole start %u end %u", hole->start, hole->end);
212   TCP_TEST ((sb->sacked_bytes == 100), "sacked bytes %d", sb->sacked_bytes);
213   TCP_TEST ((sb->lost_bytes == 0), "lost bytes %u", sb->lost_bytes);
214
215   /*
216    * Ack first hole
217    */
218
219   vec_reset_length (tc->rcv_opts.sacks);
220   tcp_rcv_sacks (tc, 1200);
221
222   if (verbose)
223     vlib_cli_output (vm, "\nsb ack up to byte 1200:\n%U",
224                      format_tcp_scoreboard, sb, tc);
225
226   TCP_TEST ((sb->snd_una_adv == 100),
227             "snd_una_adv after ack %u", sb->snd_una_adv);
228   TCP_TEST ((sb->sacked_bytes == 0), "sacked bytes %d", sb->sacked_bytes);
229   TCP_TEST ((pool_elts (sb->holes) == 0),
230             "scoreboard has %d elements", pool_elts (sb->holes));
231   TCP_TEST ((sb->last_bytes_delivered == 100), "last bytes delivered %d",
232             sb->last_bytes_delivered);
233   TCP_TEST ((sb->lost_bytes == 0), "lost bytes %u", sb->lost_bytes);
234   TCP_TEST ((sb->head == TCP_INVALID_SACK_HOLE_INDEX), "head %u", sb->head);
235   TCP_TEST ((sb->tail == TCP_INVALID_SACK_HOLE_INDEX), "tail %u", sb->tail);
236
237   /*
238    * Add some more blocks and then remove all
239    */
240   vec_reset_length (tc->rcv_opts.sacks);
241   tc->snd_una += sb->snd_una_adv;
242   tc->snd_una_max = 1900;
243   for (i = 0; i < 5; i++)
244     {
245       block.start = i * 100 + 1200;
246       block.end = (i + 1) * 100 + 1200;
247       vec_add1 (tc->rcv_opts.sacks, block);
248     }
249   tcp_rcv_sacks (tc, 1900);
250
251   scoreboard_clear (sb);
252   if (verbose)
253     vlib_cli_output (vm, "\nsb cleared all:\n%U", format_tcp_scoreboard, sb,
254                      tc);
255
256   TCP_TEST ((pool_elts (sb->holes) == 0),
257             "number of holes %d", pool_elts (sb->holes));
258   TCP_TEST ((sb->head == TCP_INVALID_SACK_HOLE_INDEX), "head %u", sb->head);
259   TCP_TEST ((sb->tail == TCP_INVALID_SACK_HOLE_INDEX), "tail %u", sb->tail);
260
261   /*
262    * Re-inject odd blocks and ack them all
263    */
264
265   tc->snd_una = 0;
266   tc->snd_una_max = 1000;
267   tc->snd_nxt = 1000;
268   for (i = 0; i < 5; i++)
269     {
270       vec_add1 (tc->rcv_opts.sacks, sacks[i * 2 + 1]);
271     }
272   tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
273   tcp_rcv_sacks (tc, 0);
274   if (verbose)
275     vlib_cli_output (vm, "\nsb added odd blocks snd_una 0 snd_una_max 1500:"
276                      "\n%U", format_tcp_scoreboard, sb, tc);
277   TCP_TEST ((pool_elts (sb->holes) == 5),
278             "scoreboard has %d elements", pool_elts (sb->holes));
279   TCP_TEST ((sb->lost_bytes == 200), "lost bytes %u", sb->lost_bytes);
280
281   tcp_rcv_sacks (tc, 950);
282
283   if (verbose)
284     vlib_cli_output (vm, "\nack [0, 950]:\n%U", format_tcp_scoreboard, sb,
285                      tc);
286
287   TCP_TEST ((pool_elts (sb->holes) == 0),
288             "scoreboard has %d elements", pool_elts (sb->holes));
289   TCP_TEST ((sb->snd_una_adv == 50), "snd_una_adv %u", sb->snd_una_adv);
290   TCP_TEST ((sb->sacked_bytes == 0), "sacked bytes %d", sb->sacked_bytes);
291   TCP_TEST ((sb->last_sacked_bytes == 0),
292             "last sacked bytes %d", sb->last_sacked_bytes);
293   TCP_TEST ((sb->lost_bytes == 0), "lost bytes %u", sb->lost_bytes);
294
295   /*
296    * Inject one block, ack it and overlap hole
297    */
298
299   tc->snd_una = 0;
300   tc->snd_una_max = 1000;
301   tc->snd_nxt = 1000;
302
303   block.start = 100;
304   block.end = 500;
305   vec_add1 (tc->rcv_opts.sacks, block);
306   tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
307
308   tcp_rcv_sacks (tc, 0);
309
310   if (verbose)
311     vlib_cli_output (vm, "\nsb added [100, 500] snd_una 0 snd_una_max 1000:"
312                      "\n%U", format_tcp_scoreboard, sb, tc);
313
314   tcp_rcv_sacks (tc, 800);
315
316   if (verbose)
317     vlib_cli_output (vm, "\nsb ack [0, 800]:\n%U", format_tcp_scoreboard, sb,
318                      tc);
319
320   TCP_TEST ((pool_elts (sb->holes) == 0),
321             "scoreboard has %d elements", pool_elts (sb->holes));
322   TCP_TEST ((sb->snd_una_adv == 0), "snd_una_adv %u", sb->snd_una_adv);
323   TCP_TEST ((sb->sacked_bytes == 0), "sacked bytes %d", sb->sacked_bytes);
324   TCP_TEST ((sb->last_sacked_bytes == 0), "last sacked bytes %d",
325             sb->last_sacked_bytes);
326   TCP_TEST ((sb->last_bytes_delivered == 400),
327             "last bytes delivered %d", sb->last_bytes_delivered);
328   TCP_TEST ((sb->lost_bytes == 0), "lost bytes %u", sb->lost_bytes);
329   TCP_TEST ((sb->head == TCP_INVALID_SACK_HOLE_INDEX), "head %u", sb->head);
330   TCP_TEST ((sb->tail == TCP_INVALID_SACK_HOLE_INDEX), "tail %u", sb->tail);
331
332   /*
333    * One hole close to head, patch head, split in two and start acking
334    * the lowest part
335    */
336   scoreboard_clear (sb);
337   tc->snd_una = 0;
338   tc->snd_una_max = 1000;
339   tc->snd_nxt = 1000;
340
341   block.start = 500;
342   block.end = 1000;
343   vec_add1 (tc->rcv_opts.sacks, block);
344   tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
345
346   tcp_rcv_sacks (tc, 0);
347   if (verbose)
348     vlib_cli_output (vm, "\nsb added [500, 1000]:\n%U",
349                      format_tcp_scoreboard, sb, tc);
350   TCP_TEST ((sb->sacked_bytes == 500), "sacked bytes %d", sb->sacked_bytes);
351   TCP_TEST ((sb->last_sacked_bytes == 500), "last sacked bytes %d",
352             sb->last_sacked_bytes);
353   TCP_TEST ((sb->lost_bytes == 500), "lost bytes %u", sb->lost_bytes);
354
355   vec_reset_length (tc->rcv_opts.sacks);
356   block.start = 300;
357   block.end = 400;
358   vec_add1 (tc->rcv_opts.sacks, block);
359   tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
360   tcp_rcv_sacks (tc, 100);
361   if (verbose)
362     vlib_cli_output (vm, "\nsb added [0, 100] [300, 400]:\n%U",
363                      format_tcp_scoreboard, sb, tc);
364   TCP_TEST ((pool_elts (sb->holes) == 2),
365             "scoreboard has %d elements", pool_elts (sb->holes));
366   TCP_TEST ((sb->sacked_bytes == 600), "sacked bytes %d", sb->sacked_bytes);
367   TCP_TEST ((sb->last_sacked_bytes == 100), "last sacked bytes %d",
368             sb->last_sacked_bytes);
369   TCP_TEST ((sb->last_bytes_delivered == 0), "last bytes delivered %d",
370             sb->last_bytes_delivered);
371   TCP_TEST ((sb->lost_bytes == 200), "lost bytes %u", sb->lost_bytes);
372
373   tc->snd_una = 100;
374   tcp_rcv_sacks (tc, 200);
375   tc->snd_una = 200;
376   tcp_rcv_sacks (tc, 300);
377   if (verbose)
378     vlib_cli_output (vm, "\nacked [0, 300] in two steps:\n%U",
379                      format_tcp_scoreboard, sb, tc);
380   TCP_TEST ((sb->sacked_bytes == 500), "sacked bytes %d", sb->sacked_bytes);
381   TCP_TEST ((sb->lost_bytes == 100), "lost bytes %u", sb->lost_bytes);
382   TCP_TEST ((sb->last_bytes_delivered == 100), "last bytes delivered %d",
383             sb->last_bytes_delivered);
384
385   tc->snd_una = 400;
386   tcp_rcv_sacks (tc, 500);
387   if (verbose)
388     vlib_cli_output (vm, "\nacked [400, 500]:\n%U", format_tcp_scoreboard, sb,
389                      tc);
390   TCP_TEST ((pool_elts (sb->holes) == 0),
391             "scoreboard has %d elements", pool_elts (sb->holes));
392   TCP_TEST ((sb->sacked_bytes == 0), "sacked bytes %d", sb->sacked_bytes);
393   TCP_TEST ((sb->last_sacked_bytes == 0), "last sacked bytes %d",
394             sb->last_sacked_bytes);
395   TCP_TEST ((sb->last_bytes_delivered == 500), "last bytes delivered %d",
396             sb->last_bytes_delivered);
397   TCP_TEST ((sb->lost_bytes == 0), "lost bytes %u", sb->lost_bytes);
398   TCP_TEST ((sb->snd_una_adv == 500), "snd_una_adv %u", sb->snd_una_adv);
399   TCP_TEST ((sb->head == TCP_INVALID_SACK_HOLE_INDEX), "head %u", sb->head);
400   TCP_TEST ((sb->tail == TCP_INVALID_SACK_HOLE_INDEX), "tail %u", sb->tail);
401
402   /*
403    * Re-ack high sacked, to make sure last_bytes_delivered and
404    * snd_una_adv are 0-ed
405    */
406   tcp_rcv_sacks (tc, 1000);
407   if (verbose)
408     vlib_cli_output (vm, "\nAck high sacked:\n%U", format_tcp_scoreboard, sb,
409                      tc);
410   TCP_TEST ((sb->last_bytes_delivered == 0), "last bytes delivered %d",
411             sb->last_bytes_delivered);
412   TCP_TEST ((sb->snd_una_adv == 0), "snd_una_adv %u", sb->snd_una_adv);
413   return 0;
414 }
415
416 static int
417 tcp_test_sack_tx (vlib_main_t * vm, unformat_input_t * input)
418 {
419   tcp_connection_t _tc, *tc = &_tc;
420   sack_block_t *sacks;
421   int i, verbose = 0, expected;
422
423   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
424     {
425       if (unformat (input, "verbose"))
426         verbose = 1;
427       else
428         {
429           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
430                            input);
431           return -1;
432         }
433     }
434
435   memset (tc, 0, sizeof (*tc));
436
437   /*
438    * Add odd sack block pairs
439    */
440   for (i = 1; i < 10; i += 2)
441     {
442       tcp_update_sack_list (tc, i * 100, (i + 1) * 100);
443     }
444
445   TCP_TEST ((vec_len (tc->snd_sacks) == 5), "sack blocks %d expected %d",
446             vec_len (tc->snd_sacks), 5);
447   TCP_TEST ((tc->snd_sacks[0].start = 900),
448             "first sack block start %u expected %u", tc->snd_sacks[0].start,
449             900);
450
451   /*
452    * Try to add one extra
453    */
454   sacks = vec_dup (tc->snd_sacks);
455
456   tcp_update_sack_list (tc, 1100, 1200);
457   if (verbose)
458     vlib_cli_output (vm, "add new segment [1100, 1200]\n%U",
459                      format_tcp_sacks, tc);
460   expected = 5 < TCP_MAX_SACK_BLOCKS ? 6 : 5;
461   TCP_TEST ((vec_len (tc->snd_sacks) == expected),
462             "sack blocks %d expected %d", vec_len (tc->snd_sacks), expected);
463   TCP_TEST ((tc->snd_sacks[0].start == 1100),
464             "first sack block start %u expected %u", tc->snd_sacks[0].start,
465             1100);
466
467   /* restore */
468   vec_free (tc->snd_sacks);
469   tc->snd_sacks = sacks;
470
471   /*
472    * Overlap first 2 segment
473    */
474   tc->rcv_nxt = 300;
475   tcp_update_sack_list (tc, 300, 300);
476   if (verbose)
477     vlib_cli_output (vm, "overlap first 2 segments:\n%U",
478                      format_tcp_sacks, tc);
479   TCP_TEST ((vec_len (tc->snd_sacks) == 3), "sack blocks %d expected %d",
480             vec_len (tc->snd_sacks), 3);
481   TCP_TEST ((tc->snd_sacks[0].start == 900),
482             "first sack block start %u expected %u", tc->snd_sacks[0].start,
483             500);
484
485   /*
486    * Add a new segment
487    */
488   tcp_update_sack_list (tc, 1100, 1200);
489   if (verbose)
490     vlib_cli_output (vm, "add new segment [1100, 1200]\n%U",
491                      format_tcp_sacks, tc);
492   TCP_TEST ((vec_len (tc->snd_sacks) == 4), "sack blocks %d expected %d",
493             vec_len (tc->snd_sacks), 4);
494   TCP_TEST ((tc->snd_sacks[0].start == 1100),
495             "first sack block start %u expected %u", tc->snd_sacks[0].start,
496             1100);
497
498   /*
499    * Join middle segments
500    */
501   tcp_update_sack_list (tc, 800, 900);
502   if (verbose)
503     vlib_cli_output (vm, "join middle segments [800, 900]\n%U",
504                      format_tcp_sacks, tc);
505
506   TCP_TEST ((vec_len (tc->snd_sacks) == 3), "sack blocks %d expected %d",
507             vec_len (tc->snd_sacks), 3);
508   TCP_TEST ((tc->snd_sacks[0].start == 700),
509             "first sack block start %u expected %u", tc->snd_sacks[0].start,
510             1100);
511
512   /*
513    * Advance rcv_nxt to overlap all
514    */
515   tc->rcv_nxt = 1200;
516   tcp_update_sack_list (tc, 1200, 1200);
517   if (verbose)
518     vlib_cli_output (vm, "advance rcv_nxt to 1200\n%U", format_tcp_sacks, tc);
519   TCP_TEST ((vec_len (tc->snd_sacks) == 0), "sack blocks %d expected %d",
520             vec_len (tc->snd_sacks), 0);
521
522
523   /*
524    * Add 2 blocks, overwrite first and update rcv_nxt to also remove it
525    */
526
527   vec_reset_length (tc->snd_sacks);
528   tc->rcv_nxt = 0;
529
530   tcp_update_sack_list (tc, 100, 200);
531   tcp_update_sack_list (tc, 300, 400);
532
533   if (verbose)
534     vlib_cli_output (vm, "add [100, 200] [300, 400]\n%U",
535                      format_tcp_sacks, tc);
536   TCP_TEST ((vec_len (tc->snd_sacks) == 2),
537             "sack blocks %d expected %d", vec_len (tc->snd_sacks), 2);
538   TCP_TEST ((tc->snd_sacks[0].start == 300),
539             "first sack block start %u expected %u", tc->snd_sacks[0].start,
540             300);
541
542   tc->rcv_nxt = 100;
543   tcp_update_sack_list (tc, 100, 100);
544   if (verbose)
545     vlib_cli_output (vm, "add [100, 200] rcv_nxt = 100\n%U",
546                      format_tcp_sacks, tc);
547   TCP_TEST ((vec_len (tc->snd_sacks) == 1),
548             "sack blocks %d expected %d", vec_len (tc->snd_sacks), 1);
549   TCP_TEST ((tc->snd_sacks[0].start == 300),
550             "first sack block start %u expected %u", tc->snd_sacks[0].start,
551             300);
552   return 0;
553 }
554
555 static int
556 tcp_test_sack (vlib_main_t * vm, unformat_input_t * input)
557 {
558   int res = 0;
559
560   /* Run all tests */
561   if (unformat_check_input (input) == UNFORMAT_END_OF_INPUT)
562     {
563       if (tcp_test_sack_tx (vm, input))
564         {
565           return -1;
566         }
567
568       if (tcp_test_sack_rx (vm, input))
569         {
570           return -1;
571         }
572     }
573   else
574     {
575       if (unformat (input, "tx"))
576         {
577           res = tcp_test_sack_tx (vm, input);
578         }
579       else if (unformat (input, "rx"))
580         {
581           res = tcp_test_sack_rx (vm, input);
582         }
583     }
584
585   return res;
586 }
587
588
589 typedef struct
590 {
591   u32 offset;
592   u32 len;
593 } test_pattern_t;
594
595 /* *INDENT-OFF* */
596 test_pattern_t test_pattern[] = {
597   {380, 8}, {768, 8}, {1156, 8}, {1544, 8}, {1932, 8}, {2320, 8}, {2708, 8},
598   {2992, 8}, {372, 8}, {760, 8}, {1148, 8}, {1536, 8}, {1924, 8}, {2312, 8},
599   {2700, 8}, {2984, 8}, {364, 8}, {752, 8}, {1140, 8}, {1528, 8}, {1916, 8},
600   {2304, 8}, {2692, 8}, {2976, 8}, {356, 8}, {744, 8}, {1132, 8}, {1520, 8},
601   {1908, 8}, {2296, 8}, {2684, 8}, {2968, 8}, {348, 8}, {736, 8}, {1124, 8},
602   {1512, 8}, {1900, 8}, {2288, 8}, {2676, 8}, {2960, 8}, {340, 8}, {728, 8},
603   {1116, 8}, {1504, 8}, {1892, 8}, {2280, 8}, {2668, 8}, {2952, 8}, {332, 8},
604   {720, 8}, {1108, 8}, {1496, 8}, {1884, 8}, {2272, 8}, {2660, 8}, {2944, 8},
605   {324, 8}, {712, 8}, {1100, 8}, {1488, 8}, {1876, 8}, {2264, 8}, {2652, 8},
606   {2936, 8}, {316, 8}, {704, 8}, {1092, 8}, {1480, 8}, {1868, 8}, {2256, 8},
607   {2644, 8}, {2928, 8}, {308, 8}, {696, 8}, {1084, 8}, {1472, 8}, {1860, 8},
608   {2248, 8}, {2636, 8}, {2920, 8}, {300, 8}, {688, 8}, {1076, 8}, {1464, 8},
609   {1852, 8}, {2240, 8}, {2628, 8}, {2912, 8}, {292, 8}, {680, 8}, {1068, 8},
610   {1456, 8}, {1844, 8}, {2232, 8}, {2620, 8}, {2904, 8}, {284, 8}, {672, 8},
611   {1060, 8}, {1448, 8}, {1836, 8}, {2224, 8}, {2612, 8}, {2896, 8}, {276, 8},
612   {664, 8}, {1052, 8}, {1440, 8}, {1828, 8},  {2216, 8}, {2604, 8}, {2888, 8},
613   {268, 8}, {656, 8}, {1044, 8}, {1432, 8}, {1820, 8}, {2208, 8}, {2596, 8},
614   {2880, 8}, {260, 8}, {648, 8}, {1036, 8}, {1424, 8}, {1812, 8}, {2200, 8},
615   {2588, 8}, {2872, 8}, {252, 8}, {640, 8}, {1028, 8}, {1416, 8}, {1804, 8},
616   {2192, 8}, {2580, 8}, {2864, 8}, {244, 8}, {632, 8}, {1020, 8}, {1408, 8},
617   {1796, 8}, {2184, 8}, {2572, 8}, {2856, 8}, {236, 8}, {624, 8}, {1012, 8},
618   {1400, 8}, {1788, 8}, {2176, 8}, {2564, 8}, {2848, 8}, {228, 8}, {616, 8},
619   {1004, 8}, {1392, 8}, {1780, 8}, {2168, 8}, {2556, 8}, {2840, 8}, {220, 8},
620   {608, 8}, {996, 8}, {1384, 8}, {1772, 8}, {2160, 8}, {2548, 8}, {2832, 8},
621   {212, 8}, {600, 8}, {988, 8}, {1376, 8}, {1764, 8}, {2152, 8}, {2540, 8},
622   {2824, 8}, {204, 8}, {592, 8}, {980, 8}, {1368, 8}, {1756, 8}, {2144, 8},
623   {2532, 8}, {2816, 8}, {196, 8}, {584, 8}, {972, 8}, {1360, 8}, {1748, 8},
624   {2136, 8}, {2524, 8}, {2808, 8}, {188, 8}, {576, 8}, {964, 8}, {1352, 8},
625   {1740, 8}, {2128, 8}, {2516, 8}, {2800, 8}, {180, 8}, {568, 8}, {956, 8},
626   {1344, 8}, {1732, 8}, {2120, 8}, {2508, 8}, {2792, 8}, {172, 8}, {560, 8},
627   {948, 8}, {1336, 8}, {1724, 8}, {2112, 8}, {2500, 8}, {2784, 8}, {164, 8},
628   {552, 8}, {940, 8}, {1328, 8}, {1716, 8}, {2104, 8}, {2492, 8}, {2776, 8},
629   {156, 8}, {544, 8}, {932, 8}, {1320, 8}, {1708, 8}, {2096, 8}, {2484, 8},
630   {2768, 8}, {148, 8}, {536, 8}, {924, 8}, {1312, 8}, {1700, 8}, {2088, 8},
631   {2476, 8}, {2760, 8}, {140, 8}, {528, 8}, {916, 8}, {1304, 8}, {1692, 8},
632   {2080, 8}, {2468, 8}, {2752, 8}, {132, 8}, {520, 8}, {908, 8}, {1296, 8},
633   {1684, 8}, {2072, 8}, {2460, 8}, {2744, 8}, {124, 8}, {512, 8}, {900, 8},
634   {1288, 8}, {1676, 8}, {2064, 8}, {2452, 8}, {2736, 8}, {116, 8}, {504, 8},
635   {892, 8}, {1280, 8}, {1668, 8}, {2056, 8}, {2444, 8}, {2728, 8}, {108, 8},
636   {496, 8}, {884, 8}, {1272, 8}, {1660, 8}, {2048, 8}, {2436, 8}, {2720, 8},
637   {100, 8}, {488, 8}, {876, 8}, {1264, 8}, {1652, 8}, {2040, 8}, {2428, 8},
638   {2716, 4}, {92, 8}, {480, 8}, {868, 8}, {1256, 8}, {1644, 8}, {2032, 8},
639   {2420, 8}, {84, 8}, {472, 8}, {860, 8}, {1248, 8}, {1636, 8}, {2024, 8},
640   {2412, 8}, {76, 8}, {464, 8}, {852, 8}, {1240, 8}, {1628, 8}, {2016, 8},
641   {2404, 8}, {68, 8}, {456, 8}, {844, 8}, {1232, 8}, {1620, 8}, {2008, 8},
642   {2396, 8}, {60, 8}, {448, 8}, {836, 8}, {1224, 8}, {1612, 8}, {2000, 8},
643   {2388, 8}, {52, 8}, {440, 8}, {828, 8}, {1216, 8}, {1604, 8}, {1992, 8},
644   {2380, 8}, {44, 8}, {432, 8}, {820, 8}, {1208, 8}, {1596, 8}, {1984, 8},
645   {2372, 8}, {36, 8}, {424, 8}, {812, 8}, {1200, 8}, {1588, 8}, {1976, 8},
646   {2364, 8}, {28, 8}, {416, 8}, {804, 8}, {1192, 8}, {1580, 8}, {1968, 8},
647   {2356, 8}, {20, 8}, {408, 8}, {796, 8}, {1184, 8}, {1572, 8}, {1960, 8},
648   {2348, 8}, {12, 8}, {400, 8}, {788, 8}, {1176, 8}, {1564, 8}, {1952, 8},
649   {2340, 8}, {4, 8}, {392, 8}, {780, 8}, {1168, 8}, {1556, 8}, {1944, 8},
650   {2332, 8},
651   /* missing from original data set */
652   {388, 4}, {776, 4}, {1164, 4}, {1552, 4}, {1940, 4}, {2328, 4},
653 };
654 /* *INDENT-ON* */
655
656 int
657 pattern_cmp (const void *arg1, const void *arg2)
658 {
659   test_pattern_t *a1 = (test_pattern_t *) arg1;
660   test_pattern_t *a2 = (test_pattern_t *) arg2;
661
662   if (a1->offset < a2->offset)
663     return -1;
664   else if (a1->offset > a2->offset)
665     return 1;
666   return 0;
667 }
668
669 static u8
670 fifo_validate_pattern (vlib_main_t * vm, test_pattern_t * pattern,
671                        u32 pattern_length)
672 {
673   test_pattern_t *tp = pattern;
674   int i;
675
676   /* Go through the pattern and make 100% sure it's sane */
677   for (i = 0; i < pattern_length - 1; i++)
678     {
679       if (tp->offset + tp->len != (tp + 1)->offset)
680         {
681           vlib_cli_output (vm, "[%d] missing {%d, %d}", i,
682                            (tp->offset + tp->len),
683                            (tp + 1)->offset - (tp->offset + tp->len));
684           return 0;
685         }
686       tp++;
687     }
688   return 1;
689 }
690
691 static test_pattern_t *
692 fifo_get_validate_pattern (vlib_main_t * vm, test_pattern_t * test_data,
693                            u32 test_data_len)
694 {
695   test_pattern_t *validate_pattern = 0;
696
697   /* Validate, and try segments in order... */
698   vec_validate (validate_pattern, test_data_len - 1);
699   memcpy (validate_pattern, test_data,
700           test_data_len * sizeof (test_pattern_t));
701   qsort ((u8 *) validate_pattern, test_data_len, sizeof (test_pattern_t),
702          pattern_cmp);
703
704   if (fifo_validate_pattern (vm, validate_pattern, test_data_len) == 0)
705     return 0;
706
707   return validate_pattern;
708 }
709
710 static svm_fifo_t *
711 fifo_prepare (u32 fifo_size)
712 {
713   svm_fifo_t *f;
714   f = svm_fifo_create (fifo_size);
715
716   /* Paint fifo data vector with -1's */
717   memset (f->data, 0xFF, fifo_size);
718
719   return f;
720 }
721
722 static int
723 compare_data (u8 * data1, u8 * data2, u32 start, u32 len, u32 * index)
724 {
725   int i;
726
727   for (i = start; i < len; i++)
728     {
729       if (data1[i] != data2[i])
730         {
731           *index = i;
732           return 1;
733         }
734     }
735   return 0;
736 }
737
738 int
739 tcp_test_fifo1 (vlib_main_t * vm, unformat_input_t * input)
740 {
741   svm_fifo_t *f;
742   u32 fifo_size = 1 << 20;
743   u32 *test_data = 0;
744   u32 offset;
745   int i, rv, verbose = 0;
746   u32 data_word, test_data_len, j;
747   ooo_segment_t *ooo_seg;
748   u8 *data, *s, *data_buf = 0;
749
750   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
751     {
752       if (unformat (input, "verbose"))
753         verbose = 1;
754     }
755
756   test_data_len = fifo_size / sizeof (u32);
757   vec_validate (test_data, test_data_len - 1);
758
759   for (i = 0; i < vec_len (test_data); i++)
760     test_data[i] = i;
761
762   f = fifo_prepare (fifo_size);
763
764   /*
765    * Enqueue an initial (un-dequeued) chunk
766    */
767   rv = svm_fifo_enqueue_nowait (f, sizeof (u32), (u8 *) test_data);
768   TCP_TEST ((rv == sizeof (u32)), "enqueued %d", rv);
769   TCP_TEST ((f->tail == 4), "fifo tail %u", f->tail);
770
771   /*
772    * Create 3 chunks in the future. The offsets are relative
773    * to the current fifo tail
774    */
775   for (i = 0; i < 3; i++)
776     {
777       offset = (2 * i + 1) * sizeof (u32) - f->tail;
778       data = (u8 *) (test_data + (2 * i + 1));
779       if (i == 0)
780         {
781           rv = svm_fifo_enqueue_nowait (f, sizeof (u32), data);
782           rv = rv > 0 ? 0 : rv;
783         }
784       else
785         rv = svm_fifo_enqueue_with_offset (f, offset, sizeof (u32), data);
786       if (verbose)
787         vlib_cli_output (vm, "add [%d] [%d, %d]", 2 * i + 1, offset,
788                          offset + sizeof (u32));
789       if (rv)
790         {
791           clib_warning ("enqueue returned %d", rv);
792           goto err;
793         }
794     }
795
796   if (verbose)
797     vlib_cli_output (vm, "fifo after odd segs: %U", format_svm_fifo, f, 1);
798
799   TCP_TEST ((f->tail == 8), "fifo tail %u", f->tail);
800   TCP_TEST ((svm_fifo_number_ooo_segments (f) == 2),
801             "number of ooo segments %u", svm_fifo_number_ooo_segments (f));
802
803   /*
804    * Try adding a completely overlapped segment
805    */
806   offset = 3 * sizeof (u32) - f->tail;
807   data = (u8 *) (test_data + 3);
808   rv = svm_fifo_enqueue_with_offset (f, offset, sizeof (u32), data);
809   if (rv)
810     {
811       clib_warning ("enqueue returned %d", rv);
812       goto err;
813     }
814
815   if (verbose)
816     vlib_cli_output (vm, "fifo after overlap seg: %U", format_svm_fifo, f, 1);
817
818   TCP_TEST ((svm_fifo_number_ooo_segments (f) == 2),
819             "number of ooo segments %u", svm_fifo_number_ooo_segments (f));
820
821   /*
822    * Make sure format functions are not buggy
823    */
824   s = format (0, "%U", format_svm_fifo, f, 2);
825   vec_free (s);
826
827   /*
828    * Paint some of missing data backwards
829    */
830   for (i = 3; i > 1; i--)
831     {
832       offset = (2 * i + 0) * sizeof (u32) - f->tail;
833       data = (u8 *) (test_data + (2 * i + 0));
834       rv = svm_fifo_enqueue_with_offset (f, offset, sizeof (u32), data);
835       if (verbose)
836         vlib_cli_output (vm, "add [%d] [%d, %d]", 2 * i, offset,
837                          offset + sizeof (u32));
838       if (rv)
839         {
840           clib_warning ("enqueue returned %d", rv);
841           goto err;
842         }
843     }
844
845   if (verbose)
846     vlib_cli_output (vm, "fifo before missing link: %U", format_svm_fifo, f,
847                      1);
848   TCP_TEST ((svm_fifo_number_ooo_segments (f) == 1),
849             "number of ooo segments %u", svm_fifo_number_ooo_segments (f));
850   ooo_seg = svm_fifo_first_ooo_segment (f);
851   TCP_TEST ((ooo_seg->start == 12),
852             "first ooo seg position %u", ooo_seg->start);
853   TCP_TEST ((ooo_seg->length == 16),
854             "first ooo seg length %u", ooo_seg->length);
855
856   /*
857    * Enqueue the missing u32
858    */
859   rv = svm_fifo_enqueue_nowait (f, sizeof (u32), (u8 *) (test_data + 2));
860   if (verbose)
861     vlib_cli_output (vm, "fifo after missing link: %U", format_svm_fifo, f,
862                      1);
863   TCP_TEST ((rv == 20), "bytes to be enqueued %u", rv);
864   TCP_TEST ((svm_fifo_number_ooo_segments (f) == 0),
865             "number of ooo segments %u", svm_fifo_number_ooo_segments (f));
866
867   /*
868    * Collect results
869    */
870   for (i = 0; i < 7; i++)
871     {
872       rv = svm_fifo_dequeue_nowait (f, sizeof (u32), (u8 *) & data_word);
873       if (rv != sizeof (u32))
874         {
875           clib_warning ("bytes dequeues %u", rv);
876           goto err;
877         }
878       if (data_word != test_data[i])
879         {
880           clib_warning ("recovered [%d] %d not %d", i, data_word,
881                         test_data[i]);
882           goto err;
883         }
884     }
885
886   /*
887    * Test segment overlaps: last ooo segment overlaps all
888    */
889   svm_fifo_free (f);
890   f = fifo_prepare (fifo_size);
891
892   for (i = 0; i < 4; i++)
893     {
894       offset = (2 * i + 1) * sizeof (u32) - f->tail;
895       data = (u8 *) (test_data + (2 * i + 1));
896       rv = svm_fifo_enqueue_with_offset (f, offset, sizeof (u32), data);
897       if (verbose)
898         vlib_cli_output (vm, "add [%d] [%d, %d]", 2 * i + 1, offset,
899                          offset + sizeof (u32));
900       if (rv)
901         {
902           clib_warning ("enqueue returned %d", rv);
903           goto err;
904         }
905     }
906
907   rv = svm_fifo_enqueue_with_offset (f, 8 - f->tail, 21, data);
908   TCP_TEST ((rv == 0), "ooo enqueued %u", rv);
909   TCP_TEST ((svm_fifo_number_ooo_segments (f) == 1),
910             "number of ooo segments %u", svm_fifo_number_ooo_segments (f));
911
912   vec_validate (data_buf, vec_len (data));
913   svm_fifo_peek (f, 0, vec_len (data), data_buf);
914   if (compare_data (data_buf, data, 8, vec_len (data), &j))
915     {
916       TCP_TEST (0, "[%d] peeked %u expected %u", j, data_buf[j], data[j]);
917     }
918   vec_reset_length (data_buf);
919
920   /*
921    * Test segment overlaps: enqueue and overlap ooo segments
922    */
923   svm_fifo_free (f);
924   f = fifo_prepare (fifo_size);
925
926   for (i = 0; i < 4; i++)
927     {
928       offset = (2 * i + 1) * sizeof (u32) - f->tail;
929       data = (u8 *) (test_data + (2 * i + 1));
930       rv = svm_fifo_enqueue_with_offset (f, offset, sizeof (u32), data);
931       if (verbose)
932         vlib_cli_output (vm, "add [%d] [%d, %d]", 2 * i + 1, offset,
933                          offset + sizeof (u32));
934       if (rv)
935         {
936           clib_warning ("enqueue returned %d", rv);
937           goto err;
938         }
939     }
940
941   if (verbose)
942     vlib_cli_output (vm, "fifo after enqueue: %U", format_svm_fifo, f, 1);
943
944   rv = svm_fifo_enqueue_nowait (f, 29, data);
945   if (verbose)
946     vlib_cli_output (vm, "fifo after enqueueing 29: %U", format_svm_fifo, f,
947                      1);
948   TCP_TEST ((rv == 32), "ooo enqueued %u", rv);
949   TCP_TEST ((svm_fifo_number_ooo_segments (f) == 0),
950             "number of ooo segments %u", svm_fifo_number_ooo_segments (f));
951
952   vec_validate (data_buf, vec_len (data));
953   svm_fifo_peek (f, 0, vec_len (data), data_buf);
954   if (compare_data (data_buf, data, 0, vec_len (data), &j))
955     {
956       TCP_TEST (0, "[%d] peeked %u expected %u", j, data_buf[j], data[j]);
957     }
958
959   /* Try to peek beyond the data */
960   rv = svm_fifo_peek (f, svm_fifo_max_dequeue (f), vec_len (data), data_buf);
961   TCP_TEST ((rv == 0), "peeked %u expected 0", rv);
962
963   vec_free (data_buf);
964   svm_fifo_free (f);
965   vec_free (test_data);
966
967   return 0;
968
969 err:
970   svm_fifo_free (f);
971   vec_free (test_data);
972   return -1;
973 }
974
975 static int
976 tcp_test_fifo2 (vlib_main_t * vm)
977 {
978   svm_fifo_t *f;
979   u32 fifo_size = 1 << 20;
980   int i, rv, test_data_len;
981   u64 data64;
982   test_pattern_t *tp, *vp, *test_data;
983   ooo_segment_t *ooo_seg;
984
985   test_data = test_pattern;
986   test_data_len = ARRAY_LEN (test_pattern);
987
988   vp = fifo_get_validate_pattern (vm, test_data, test_data_len);
989
990   /* Create a fifo */
991   f = fifo_prepare (fifo_size);
992
993   /*
994    * Try with sorted data
995    */
996   for (i = 0; i < test_data_len; i++)
997     {
998       tp = vp + i;
999       data64 = tp->offset;
1000       svm_fifo_enqueue_with_offset (f, tp->offset - f->tail, tp->len,
1001                                     (u8 *) & data64);
1002     }
1003
1004   /* Expected result: one big fat chunk at offset 4 */
1005   TCP_TEST ((svm_fifo_number_ooo_segments (f) == 1),
1006             "number of ooo segments %u", svm_fifo_number_ooo_segments (f));
1007   ooo_seg = svm_fifo_first_ooo_segment (f);
1008   TCP_TEST ((ooo_seg->start == 4),
1009             "first ooo seg position %u", ooo_seg->start);
1010   TCP_TEST ((ooo_seg->length == 2996),
1011             "first ooo seg length %u", ooo_seg->length);
1012
1013   data64 = 0;
1014   rv = svm_fifo_enqueue_nowait (f, sizeof (u32), (u8 *) & data64);
1015   TCP_TEST ((rv == 3000), "bytes to be enqueued %u", rv);
1016
1017   svm_fifo_free (f);
1018   vec_free (vp);
1019
1020   /*
1021    * Now try it again w/ unsorted data...
1022    */
1023
1024   f = fifo_prepare (fifo_size);
1025
1026   for (i = 0; i < test_data_len; i++)
1027     {
1028       tp = &test_data[i];
1029       data64 = tp->offset;
1030       rv = svm_fifo_enqueue_with_offset (f, tp->offset - f->tail, tp->len,
1031                                          (u8 *) & data64);
1032       if (rv)
1033         {
1034           clib_warning ("enqueue returned %d", rv);
1035         }
1036     }
1037
1038   /* Expecting the same result: one big fat chunk at offset 4 */
1039   TCP_TEST ((svm_fifo_number_ooo_segments (f) == 1),
1040             "number of ooo segments %u", svm_fifo_number_ooo_segments (f));
1041   ooo_seg = svm_fifo_first_ooo_segment (f);
1042   TCP_TEST ((ooo_seg->start == 4),
1043             "first ooo seg position %u", ooo_seg->start);
1044   TCP_TEST ((ooo_seg->length == 2996),
1045             "first ooo seg length %u", ooo_seg->length);
1046
1047   data64 = 0;
1048   rv = svm_fifo_enqueue_nowait (f, sizeof (u32), (u8 *) & data64);
1049
1050   TCP_TEST ((rv == 3000), "bytes to be enqueued %u", rv);
1051
1052   svm_fifo_free (f);
1053
1054   return 0;
1055 }
1056
1057 static int
1058 tcp_test_fifo3 (vlib_main_t * vm, unformat_input_t * input)
1059 {
1060   svm_fifo_t *f;
1061   u32 fifo_size = 4 << 10;
1062   u32 fifo_initial_offset = 0;
1063   u32 total_size = 2 << 10;
1064   int overlap = 0, verbose = 0, randomize = 1, drop = 0, in_seq_all = 0;
1065   u8 *data_pattern = 0, *data_buf = 0;
1066   test_pattern_t *tp, *generate = 0;
1067   u32 nsegs = 2, seg_size, length_so_far;
1068   u32 current_offset, offset_increment, len_this_chunk;
1069   u32 seed = 0xdeaddabe, j;
1070   int i, rv;
1071
1072   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1073     {
1074       if (unformat (input, "fifo-size %d", &fifo_size))
1075         ;
1076       else if (unformat (input, "total-size %d", &total_size))
1077         ;
1078       else if (unformat (input, "verbose"))
1079         verbose = 1;
1080       else if (unformat (input, "overlap"))
1081         overlap = 1;
1082       else if (unformat (input, "initial-offset %d", &fifo_initial_offset))
1083         ;
1084       else if (unformat (input, "seed %d", &seed))
1085         ;
1086       else if (unformat (input, "nsegs %d", &nsegs))
1087         ;
1088       else if (unformat (input, "no-randomize"))
1089         randomize = 0;
1090       else if (unformat (input, "in-seq-all"))
1091         in_seq_all = 1;
1092       else if (unformat (input, "drop"))
1093         drop = 1;
1094       else
1095         {
1096           clib_error_t *e = clib_error_return
1097             (0, "unknown input `%U'", format_unformat_error, input);
1098           clib_error_report (e);
1099           return -1;
1100         }
1101     }
1102
1103   if (total_size > fifo_size)
1104     {
1105       clib_warning ("total_size %d greater than fifo size %d", total_size,
1106                     fifo_size);
1107       return -1;
1108     }
1109   if (overlap && randomize == 0)
1110     {
1111       clib_warning ("Can't enqueue in-order with overlap");
1112       return -1;
1113     }
1114
1115   /*
1116    * Generate data
1117    */
1118   vec_validate (data_pattern, total_size - 1);
1119   for (i = 0; i < vec_len (data_pattern); i++)
1120     data_pattern[i] = i & 0xff;
1121
1122   /*
1123    * Generate segments
1124    */
1125   seg_size = total_size / nsegs;
1126   length_so_far = 0;
1127   current_offset = randomize;
1128   while (length_so_far < total_size)
1129     {
1130       vec_add2 (generate, tp, 1);
1131       len_this_chunk = clib_min (seg_size, total_size - length_so_far);
1132       tp->offset = current_offset;
1133       tp->len = len_this_chunk;
1134
1135       if (overlap && (len_this_chunk == seg_size))
1136         do
1137           {
1138             offset_increment = len_this_chunk
1139               % (1 + (random_u32 (&seed) % len_this_chunk));
1140           }
1141         while (offset_increment == 0);
1142       else
1143         offset_increment = len_this_chunk;
1144
1145       current_offset += offset_increment;
1146       length_so_far = tp->offset + tp->len;
1147     }
1148
1149   /*
1150    * Validate segment list. Only valid for non-overlap cases.
1151    */
1152   if (overlap == 0)
1153     fifo_validate_pattern (vm, generate, vec_len (generate));
1154
1155   if (verbose)
1156     {
1157       vlib_cli_output (vm, "raw data pattern:");
1158       for (i = 0; i < vec_len (generate); i++)
1159         {
1160           vlib_cli_output (vm, "[%d] offset %u len %u", i,
1161                            generate[i].offset, generate[i].len);
1162         }
1163     }
1164
1165   /* Randomize data pattern */
1166   if (randomize)
1167     {
1168       for (i = 0; i < vec_len (generate) / 2; i++)
1169         {
1170           u32 src_index, dst_index;
1171           test_pattern_t _tmp, *tmp = &_tmp;
1172
1173           src_index = random_u32 (&seed) % vec_len (generate);
1174           dst_index = random_u32 (&seed) % vec_len (generate);
1175
1176           tmp[0] = generate[dst_index];
1177           generate[dst_index] = generate[src_index];
1178           generate[src_index] = tmp[0];
1179         }
1180       if (verbose)
1181         {
1182           vlib_cli_output (vm, "randomized data pattern:");
1183           for (i = 0; i < vec_len (generate); i++)
1184             {
1185               vlib_cli_output (vm, "[%d] offset %u len %u", i,
1186                                generate[i].offset, generate[i].len);
1187             }
1188         }
1189     }
1190
1191   /*
1192    * Create a fifo and add segments
1193    */
1194   f = fifo_prepare (fifo_size);
1195
1196   /* manually set head and tail pointers to validate modular arithmetic */
1197   fifo_initial_offset = fifo_initial_offset % fifo_size;
1198   f->head = fifo_initial_offset;
1199   f->tail = fifo_initial_offset;
1200
1201   for (i = !randomize; i < vec_len (generate); i++)
1202     {
1203       tp = generate + i;
1204       svm_fifo_enqueue_with_offset (f,
1205                                     fifo_initial_offset + tp->offset -
1206                                     f->tail, tp->len,
1207                                     (u8 *) data_pattern + tp->offset);
1208     }
1209
1210   /* Add the first segment in order for non random data */
1211   if (!randomize)
1212     svm_fifo_enqueue_nowait (f, generate[0].len, (u8 *) data_pattern);
1213
1214   /*
1215    * Expected result: one big fat chunk at offset 1 if randomize == 1
1216    */
1217
1218   if (verbose)
1219     vlib_cli_output (vm, "fifo before missing link: %U",
1220                      format_svm_fifo, f, 1 /* verbose */ );
1221
1222   /*
1223    * Add the missing byte if segments were randomized
1224    */
1225   if (randomize)
1226     {
1227       u32 bytes_to_enq = 1;
1228       if (in_seq_all)
1229         bytes_to_enq = total_size;
1230       rv = svm_fifo_enqueue_nowait (f, bytes_to_enq, data_pattern + 0);
1231
1232       if (verbose)
1233         vlib_cli_output (vm, "in-order enqueue returned %d", rv);
1234
1235       TCP_TEST ((rv == total_size), "enqueued %u expected %u", rv,
1236                 total_size);
1237
1238     }
1239
1240   TCP_TEST ((svm_fifo_has_ooo_data (f) == 0), "number of ooo segments %u",
1241             svm_fifo_number_ooo_segments (f));
1242
1243   /*
1244    * Test if peeked data is the same as original data
1245    */
1246   vec_validate (data_buf, vec_len (data_pattern));
1247   svm_fifo_peek (f, 0, vec_len (data_pattern), data_buf);
1248   if (compare_data (data_buf, data_pattern, 0, vec_len (data_pattern), &j))
1249     {
1250       TCP_TEST (0, "[%d] peeked %u expected %u", j, data_buf[j],
1251                 data_pattern[j]);
1252     }
1253   vec_reset_length (data_buf);
1254
1255   /*
1256    * Dequeue or drop all data
1257    */
1258   if (drop)
1259     {
1260       svm_fifo_dequeue_drop (f, vec_len (data_pattern));
1261     }
1262   else
1263     {
1264       svm_fifo_dequeue_nowait (f, vec_len (data_pattern), data_buf);
1265       if (compare_data
1266           (data_buf, data_pattern, 0, vec_len (data_pattern), &j))
1267         {
1268           TCP_TEST (0, "[%d] dequeued %u expected %u", j, data_buf[j],
1269                     data_pattern[j]);
1270         }
1271     }
1272
1273   TCP_TEST ((svm_fifo_max_dequeue (f) == 0), "fifo has %d bytes",
1274             svm_fifo_max_dequeue (f));
1275
1276   svm_fifo_free (f);
1277   vec_free (data_pattern);
1278   vec_free (data_buf);
1279
1280   return 0;
1281 }
1282
1283 static int
1284 tcp_test_fifo4 (vlib_main_t * vm, unformat_input_t * input)
1285 {
1286   svm_fifo_t *f;
1287   u32 fifo_size = 6 << 10;
1288   u32 fifo_initial_offset = 1000000000;
1289   u32 test_n_bytes = 5000, j;
1290   u8 *test_data = 0, *data_buf = 0;
1291   int i, rv, verbose = 0;
1292
1293   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1294     {
1295       if (unformat (input, "verbose"))
1296         verbose = 1;
1297       else
1298         {
1299           clib_error_t *e = clib_error_return
1300             (0, "unknown input `%U'", format_unformat_error, input);
1301           clib_error_report (e);
1302           return -1;
1303         }
1304     }
1305
1306   /*
1307    * Create a fifo and add segments
1308    */
1309   f = fifo_prepare (fifo_size);
1310
1311   /* Set head and tail pointers */
1312   fifo_initial_offset = fifo_initial_offset % fifo_size;
1313   svm_fifo_init_pointers (f, fifo_initial_offset);
1314
1315   vec_validate (test_data, test_n_bytes - 1);
1316   for (i = 0; i < vec_len (test_data); i++)
1317     test_data[i] = i;
1318
1319   for (i = test_n_bytes - 1; i > 0; i--)
1320     {
1321       rv = svm_fifo_enqueue_with_offset (f, fifo_initial_offset + i - f->tail,
1322                                          sizeof (u8), &test_data[i]);
1323       if (verbose)
1324         vlib_cli_output (vm, "add [%d] [%d, %d]", i, i, i + sizeof (u8));
1325       if (rv)
1326         {
1327           clib_warning ("enqueue returned %d", rv);
1328           svm_fifo_free (f);
1329           vec_free (test_data);
1330           return -1;
1331         }
1332     }
1333
1334   svm_fifo_enqueue_nowait (f, sizeof (u8), &test_data[0]);
1335
1336   vec_validate (data_buf, vec_len (test_data));
1337
1338   svm_fifo_dequeue_nowait (f, vec_len (test_data), data_buf);
1339   rv = compare_data (data_buf, test_data, 0, vec_len (test_data), &j);
1340   if (rv)
1341     vlib_cli_output (vm, "[%d] dequeued %u expected %u", j, data_buf[j],
1342                      test_data[j]);
1343   TCP_TEST ((rv == 0), "dequeued compared to original returned %d", rv);
1344
1345   svm_fifo_free (f);
1346   vec_free (test_data);
1347   return 0;
1348 }
1349
1350 static u32
1351 fifo_pos (svm_fifo_t * f, u32 pos)
1352 {
1353   return pos % f->nitems;
1354 }
1355
1356 static int
1357 tcp_test_fifo5 (vlib_main_t * vm, unformat_input_t * input)
1358 {
1359   svm_fifo_t *f;
1360   u32 fifo_size = 400, j = 0, offset = 200;
1361   int i, rv, verbose = 0;
1362   u8 *test_data = 0, *data_buf = 0;
1363   ooo_segment_t *ooo_seg;
1364
1365   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1366     {
1367       if (unformat (input, "verbose"))
1368         verbose = 1;
1369       else
1370         {
1371           clib_error_t *e = clib_error_return
1372             (0, "unknown input `%U'", format_unformat_error, input);
1373           clib_error_report (e);
1374           return -1;
1375         }
1376     }
1377
1378   f = fifo_prepare (fifo_size);
1379   svm_fifo_init_pointers (f, offset);
1380
1381   vec_validate (test_data, 399);
1382   for (i = 0; i < vec_len (test_data); i++)
1383     test_data[i] = i % 0xff;
1384
1385   /*
1386    * Start with [100, 200] and [300, 400]
1387    */
1388   svm_fifo_enqueue_with_offset (f, 100, 100, &test_data[100]);
1389   svm_fifo_enqueue_with_offset (f, 300, 100, &test_data[300]);
1390
1391   TCP_TEST ((svm_fifo_number_ooo_segments (f) == 2),
1392             "number of ooo segments %u", svm_fifo_number_ooo_segments (f));
1393   TCP_TEST ((f->ooos_newest == 1), "newest %u", f->ooos_newest);
1394   if (verbose)
1395     vlib_cli_output (vm, "fifo after [100, 200] and [300, 400] : %U",
1396                      format_svm_fifo, f, 2 /* verbose */ );
1397
1398   /*
1399    * Add [225, 275]
1400    */
1401
1402   rv = svm_fifo_enqueue_with_offset (f, 225, 50, &test_data[200]);
1403   if (verbose)
1404     vlib_cli_output (vm, "fifo after [225, 275] : %U",
1405                      format_svm_fifo, f, 2 /* verbose */ );
1406   TCP_TEST ((svm_fifo_number_ooo_segments (f) == 3),
1407             "number of ooo segments %u", svm_fifo_number_ooo_segments (f));
1408   ooo_seg = svm_fifo_first_ooo_segment (f);
1409   TCP_TEST ((ooo_seg->start == fifo_pos (f, 100 + offset)),
1410             "first seg start %u expected %u", ooo_seg->start,
1411             fifo_pos (f, 100 + offset));
1412   TCP_TEST ((ooo_seg->length == 100), "first seg length %u expected %u",
1413             ooo_seg->length, 100);
1414   ooo_seg = ooo_segment_next (f, ooo_seg);
1415   TCP_TEST ((ooo_seg->start == fifo_pos (f, 225 + offset)),
1416             "second seg start %u expected %u",
1417             ooo_seg->start, fifo_pos (f, 225 + offset));
1418   TCP_TEST ((ooo_seg->length == 50), "second seg length %u expected %u",
1419             ooo_seg->length, 50);
1420   ooo_seg = ooo_segment_next (f, ooo_seg);
1421   TCP_TEST ((ooo_seg->start == fifo_pos (f, 300 + offset)),
1422             "third seg start %u expected %u",
1423             ooo_seg->start, fifo_pos (f, 300 + offset));
1424   TCP_TEST ((ooo_seg->length == 100), "third seg length %u expected %u",
1425             ooo_seg->length, 100);
1426   TCP_TEST ((f->ooos_newest == 2), "newest %u", f->ooos_newest);
1427   /*
1428    * Add [190, 310]
1429    */
1430   rv = svm_fifo_enqueue_with_offset (f, 190, 120, &test_data[190]);
1431   if (verbose)
1432     vlib_cli_output (vm, "fifo after [190, 310] : %U",
1433                      format_svm_fifo, f, 1 /* verbose */ );
1434   TCP_TEST ((svm_fifo_number_ooo_segments (f) == 1),
1435             "number of ooo segments %u", svm_fifo_number_ooo_segments (f));
1436   ooo_seg = svm_fifo_first_ooo_segment (f);
1437   TCP_TEST ((ooo_seg->start == fifo_pos (f, offset + 100)),
1438             "first seg start %u expected %u",
1439             ooo_seg->start, fifo_pos (f, offset + 100));
1440   TCP_TEST ((ooo_seg->length == 300), "first seg length %u expected %u",
1441             ooo_seg->length, 300);
1442
1443   /*
1444    * Add [0, 150]
1445    */
1446   rv = svm_fifo_enqueue_nowait (f, 150, test_data);
1447
1448   if (verbose)
1449     vlib_cli_output (vm, "fifo after [0 150] : %U", format_svm_fifo, f,
1450                      2 /* verbose */ );
1451
1452   TCP_TEST ((rv == 400), "managed to enqueue %u expected %u", rv, 400);
1453   TCP_TEST ((svm_fifo_number_ooo_segments (f) == 0),
1454             "number of ooo segments %u", svm_fifo_number_ooo_segments (f));
1455
1456   vec_validate (data_buf, 399);
1457   svm_fifo_peek (f, 0, 400, data_buf);
1458   if (compare_data (data_buf, test_data, 0, 400, &j))
1459     {
1460       TCP_TEST (0, "[%d] peeked %u expected %u", j, data_buf[j],
1461                 test_data[j]);
1462     }
1463
1464   /*
1465    * Add [100 200] and overlap it with [50 250]
1466    */
1467   svm_fifo_free (f);
1468   f = fifo_prepare (fifo_size);
1469
1470   svm_fifo_enqueue_with_offset (f, 100, 100, &test_data[100]);
1471   svm_fifo_enqueue_with_offset (f, 50, 200, &test_data[50]);
1472   TCP_TEST ((svm_fifo_number_ooo_segments (f) == 1),
1473             "number of ooo segments %u", svm_fifo_number_ooo_segments (f));
1474   ooo_seg = svm_fifo_first_ooo_segment (f);
1475   TCP_TEST ((ooo_seg->start == 50), "first seg start %u expected %u",
1476             ooo_seg->start, 50);
1477   TCP_TEST ((ooo_seg->length == 200), "first seg length %u expected %u",
1478             ooo_seg->length, 200);
1479
1480   svm_fifo_free (f);
1481   vec_free (test_data);
1482   return 0;
1483 }
1484
1485 /* *INDENT-OFF* */
1486 svm_fifo_trace_elem_t fifo_trace[] = {};
1487 /* *INDENT-ON* */
1488
1489 static int
1490 tcp_test_fifo_replay (vlib_main_t * vm, unformat_input_t * input)
1491 {
1492   svm_fifo_t f;
1493   int verbose = 0;
1494   u8 no_read = 0, *str = 0;
1495
1496   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1497     {
1498       if (unformat (input, "verbose"))
1499         verbose = 1;
1500       else if (unformat (input, "no-read"))
1501         no_read = 1;
1502       else
1503         {
1504           clib_error_t *e = clib_error_return
1505             (0, "unknown input `%U'", format_unformat_error, input);
1506           clib_error_report (e);
1507           return -1;
1508         }
1509     }
1510
1511 #if SVMF_FIFO_TRACE
1512   f.trace = fifo_trace;
1513 #endif
1514
1515   str = svm_fifo_replay (str, &f, no_read, verbose);
1516   vlib_cli_output (vm, "%v", str);
1517   return 0;
1518 }
1519
1520 static int
1521 tcp_test_fifo (vlib_main_t * vm, unformat_input_t * input)
1522 {
1523   int res = 0;
1524   char *str;
1525
1526   /* Run all tests */
1527   if (unformat_check_input (input) == UNFORMAT_END_OF_INPUT)
1528     {
1529       res = tcp_test_fifo1 (vm, input);
1530       if (res)
1531         return res;
1532
1533       res = tcp_test_fifo2 (vm);
1534       if (res)
1535         return res;
1536
1537       /*
1538        * Run a number of fifo3 configs
1539        */
1540       str = "nsegs 10 overlap seed 123";
1541       unformat_init_cstring (input, str);
1542       if (tcp_test_fifo3 (vm, input))
1543         return -1;
1544       unformat_free (input);
1545
1546       str = "nsegs 10 overlap seed 123 in-seq-all";
1547       unformat_init_cstring (input, str);
1548       if (tcp_test_fifo3 (vm, input))
1549         return -1;
1550       unformat_free (input);
1551
1552       str = "nsegs 10 overlap seed 123 initial-offset 3917";
1553       unformat_init_cstring (input, str);
1554       if (tcp_test_fifo3 (vm, input))
1555         return -1;
1556       unformat_free (input);
1557
1558       str = "nsegs 10 overlap seed 123 initial-offset 3917 drop";
1559       unformat_init_cstring (input, str);
1560       if (tcp_test_fifo3 (vm, input))
1561         return -1;
1562       unformat_free (input);
1563
1564       str = "nsegs 10 seed 123 initial-offset 3917 drop no-randomize";
1565       unformat_init_cstring (input, str);
1566       if (tcp_test_fifo3 (vm, input))
1567         return -1;
1568       unformat_free (input);
1569
1570       res = tcp_test_fifo4 (vm, input);
1571       if (res)
1572         return res;
1573
1574       res = tcp_test_fifo5 (vm, input);
1575       if (res)
1576         return res;
1577     }
1578   else
1579     {
1580       if (unformat (input, "fifo3"))
1581         {
1582           res = tcp_test_fifo3 (vm, input);
1583         }
1584       else if (unformat (input, "fifo2"))
1585         {
1586           res = tcp_test_fifo2 (vm);
1587         }
1588       else if (unformat (input, "fifo1"))
1589         {
1590           res = tcp_test_fifo1 (vm, input);
1591         }
1592       else if (unformat (input, "fifo4"))
1593         {
1594           res = tcp_test_fifo4 (vm, input);
1595         }
1596       else if (unformat (input, "fifo5"))
1597         {
1598           res = tcp_test_fifo5 (vm, input);
1599         }
1600       else if (unformat (input, "replay"))
1601         {
1602           res = tcp_test_fifo_replay (vm, input);
1603         }
1604     }
1605
1606   return res;
1607 }
1608
1609 static int
1610 tcp_test_lookup (vlib_main_t * vm, unformat_input_t * input)
1611 {
1612   session_manager_main_t *smm = &session_manager_main;
1613   tcp_main_t *tm = &tcp_main;
1614   transport_connection_t _tc1, *tc1 = &_tc1, _tc2, *tc2 = &_tc2, *tconn;
1615   tcp_connection_t *tc;
1616   stream_session_t *s, *s1;
1617   u8 cmp = 0, is_filtered = 0;
1618   u32 sidx;
1619
1620   /*
1621    * Allocate fake session and connection 1
1622    */
1623   pool_get (smm->sessions[0], s);
1624   memset (s, 0, sizeof (*s));
1625   s->session_index = sidx = s - smm->sessions[0];
1626
1627   pool_get (tm->connections[0], tc);
1628   memset (tc, 0, sizeof (*tc));
1629   tc->connection.c_index = tc - tm->connections[0];
1630   tc->connection.s_index = s->session_index;
1631   s->connection_index = tc->connection.c_index;
1632
1633   tc->connection.lcl_ip.ip4.as_u32 = clib_host_to_net_u32 (0x06000101);
1634   tc->connection.rmt_ip.ip4.as_u32 = clib_host_to_net_u32 (0x06000103);
1635   tc->connection.lcl_port = 35051;
1636   tc->connection.rmt_port = 53764;
1637   tc->connection.proto = TRANSPORT_PROTO_TCP;
1638   tc->connection.is_ip4 = 1;
1639   clib_memcpy (tc1, &tc->connection, sizeof (*tc1));
1640
1641   /*
1642    * Allocate fake session and connection 2
1643    */
1644   pool_get (session_manager_main.sessions[0], s);
1645   memset (s, 0, sizeof (*s));
1646   s->session_index = s - smm->sessions[0];
1647
1648   pool_get (tm->connections[0], tc);
1649   memset (tc, 0, sizeof (*tc));
1650   tc->connection.c_index = tc - tm->connections[0];
1651   tc->connection.s_index = s->session_index;
1652   s->connection_index = tc->connection.c_index;
1653
1654   tc->connection.lcl_ip.ip4.as_u32 = clib_host_to_net_u32 (0x06000101);
1655   tc->connection.rmt_ip.ip4.as_u32 = clib_host_to_net_u32 (0x06000102);
1656   tc->connection.lcl_port = 38225;
1657   tc->connection.rmt_port = 53764;
1658   tc->connection.proto = TRANSPORT_PROTO_TCP;
1659   tc->connection.is_ip4 = 1;
1660   clib_memcpy (tc2, &tc->connection, sizeof (*tc2));
1661
1662   /*
1663    * Confirm that connection lookup works
1664    */
1665
1666   s1 = pool_elt_at_index (smm->sessions[0], sidx);
1667   session_lookup_add_connection (tc1, session_handle (s1));
1668   tconn = session_lookup_connection_wt4 (0, &tc1->lcl_ip.ip4,
1669                                          &tc1->rmt_ip.ip4,
1670                                          tc1->lcl_port, tc1->rmt_port,
1671                                          tc1->proto, 0, &is_filtered);
1672
1673   TCP_TEST ((tconn != 0), "connection exists");
1674   cmp = (memcmp (&tconn->rmt_ip, &tc1->rmt_ip, sizeof (tc1->rmt_ip)) == 0);
1675   TCP_TEST ((cmp), "rmt ip is identical %d", cmp);
1676   TCP_TEST ((tconn->lcl_port == tc1->lcl_port),
1677             "rmt port is identical %d", tconn->lcl_port == tc1->lcl_port);
1678
1679   /*
1680    * Non-existing connection lookup should not work
1681    */
1682
1683   tconn = session_lookup_connection_wt4 (0, &tc2->lcl_ip.ip4,
1684                                          &tc2->rmt_ip.ip4,
1685                                          tc2->lcl_port, tc2->rmt_port,
1686                                          tc2->proto, 0, &is_filtered);
1687   TCP_TEST ((tconn == 0), "lookup result should be null");
1688
1689   /*
1690    * Delete and lookup again
1691    */
1692   session_lookup_del_connection (tc1);
1693   tconn = session_lookup_connection_wt4 (0, &tc1->lcl_ip.ip4,
1694                                          &tc1->rmt_ip.ip4,
1695                                          tc1->lcl_port, tc1->rmt_port,
1696                                          tc1->proto, 0, &is_filtered);
1697   TCP_TEST ((tconn == 0), "lookup result should be null");
1698   tconn = session_lookup_connection_wt4 (0, &tc2->lcl_ip.ip4,
1699                                          &tc2->rmt_ip.ip4,
1700                                          tc2->lcl_port, tc2->rmt_port,
1701                                          tc2->proto, 0, &is_filtered);
1702   TCP_TEST ((tconn == 0), "lookup result should be null");
1703
1704   /*
1705    * Re-add and lookup tc2
1706    */
1707   session_lookup_add_connection (tc1, tc1->s_index);
1708   tconn = session_lookup_connection_wt4 (0, &tc2->lcl_ip.ip4,
1709                                          &tc2->rmt_ip.ip4,
1710                                          tc2->lcl_port, tc2->rmt_port,
1711                                          tc2->proto, 0, &is_filtered);
1712   TCP_TEST ((tconn == 0), "lookup result should be null");
1713
1714   return 0;
1715 }
1716
1717 static int
1718 tcp_test_session (vlib_main_t * vm, unformat_input_t * input)
1719 {
1720   int rv = 0;
1721   tcp_connection_t *tc0;
1722   ip4_address_t local, remote;
1723   u16 local_port, remote_port;
1724   tcp_main_t *tm = vnet_get_tcp_main ();
1725   int is_add = 1;
1726
1727
1728   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1729     {
1730       if (unformat (input, "del"))
1731         is_add = 0;
1732       else if (unformat (input, "add"))
1733         is_add = 1;
1734       else
1735         break;
1736     }
1737
1738   if (is_add)
1739     {
1740       local.as_u32 = clib_host_to_net_u32 (0x06000101);
1741       remote.as_u32 = clib_host_to_net_u32 (0x06000102);
1742       local_port = clib_host_to_net_u16 (1234);
1743       remote_port = clib_host_to_net_u16 (11234);
1744
1745       pool_get (tm->connections[0], tc0);
1746       memset (tc0, 0, sizeof (*tc0));
1747
1748       tc0->state = TCP_STATE_ESTABLISHED;
1749       tc0->rcv_las = 1;
1750       tc0->c_c_index = tc0 - tm->connections[0];
1751       tc0->c_lcl_port = local_port;
1752       tc0->c_rmt_port = remote_port;
1753       tc0->c_is_ip4 = 1;
1754       tc0->c_thread_index = 0;
1755       tc0->c_lcl_ip4.as_u32 = local.as_u32;
1756       tc0->c_rmt_ip4.as_u32 = remote.as_u32;
1757       tc0->rcv_opts.mss = 1450;
1758       tcp_connection_init_vars (tc0);
1759
1760       TCP_EVT_DBG (TCP_EVT_OPEN, tc0);
1761
1762       if (stream_session_accept (&tc0->connection, 0 /* listener index */ ,
1763                                  0 /* notify */ ))
1764         clib_warning ("stream_session_accept failed");
1765
1766       stream_session_accept_notify (&tc0->connection);
1767     }
1768   else
1769     {
1770       tc0 = tcp_connection_get (0 /* connection index */ , 0 /* thread */ );
1771       tc0->state = TCP_STATE_CLOSED;
1772       stream_session_disconnect_notify (&tc0->connection);
1773     }
1774
1775   return rv;
1776 }
1777
1778 static clib_error_t *
1779 tcp_test (vlib_main_t * vm,
1780           unformat_input_t * input, vlib_cli_command_t * cmd_arg)
1781 {
1782   int res = 0;
1783
1784   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1785     {
1786       if (unformat (input, "sack"))
1787         {
1788           res = tcp_test_sack (vm, input);
1789         }
1790       else if (unformat (input, "fifo"))
1791         {
1792           res = tcp_test_fifo (vm, input);
1793         }
1794       else if (unformat (input, "session"))
1795         {
1796           res = tcp_test_session (vm, input);
1797         }
1798       else if (unformat (input, "lookup"))
1799         {
1800           res = tcp_test_lookup (vm, input);
1801         }
1802       else if (unformat (input, "all"))
1803         {
1804           if ((res = tcp_test_sack (vm, input)))
1805             goto done;
1806           if ((res = tcp_test_fifo (vm, input)))
1807             goto done;
1808           if ((res = tcp_test_lookup (vm, input)))
1809             goto done;
1810         }
1811       else
1812         break;
1813     }
1814
1815 done:
1816   if (res)
1817     return clib_error_return (0, "TCP unit test failed");
1818   return 0;
1819 }
1820
1821 /* *INDENT-OFF* */
1822 VLIB_CLI_COMMAND (tcp_test_command, static) =
1823 {
1824   .path = "test tcp",
1825   .short_help = "internal tcp unit tests",
1826   .function = tcp_test,
1827 };
1828 /* *INDENT-ON* */
1829
1830 /*
1831  * fd.io coding-style-patch-verification: ON
1832  *
1833  * Local Variables:
1834  * eval: (c-set-style "gnu")
1835  * End:
1836  */