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