tcp session: improvement to tests
[vpp.git] / src / plugins / unittest / tcp_test.c
1 /*
2  * Copyright (c) 2017-2019 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <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   clib_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 == 300), "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_nxt = 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 == 300), "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 == 300), "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
414   /*
415    * Add [1200, 1500] and test that [1000, 1200] is lost (bytes condition)
416    * snd_una = 1000 and snd_una_max = 1600
417    */
418   tc->snd_una = 1000;
419   tc->snd_nxt = tc->snd_una_max = 1600;
420   vec_reset_length (tc->rcv_opts.sacks);
421   block.start = 1200;
422   block.end = 1500;
423   vec_add1 (tc->rcv_opts.sacks, block);
424   tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
425   tcp_rcv_sacks (tc, 1000);
426   if (verbose)
427     vlib_cli_output (vm, "\nacked [1200, 1500] test first hole is lost:\n%U",
428                      format_tcp_scoreboard, sb, tc);
429   TCP_TEST ((pool_elts (sb->holes) == 2), "scoreboard has %d elements",
430             pool_elts (sb->holes));
431   TCP_TEST ((sb->sacked_bytes == 300), "sacked bytes %d", sb->sacked_bytes);
432   TCP_TEST ((sb->last_sacked_bytes == 300), "last sacked bytes %d",
433             sb->last_sacked_bytes);
434   TCP_TEST ((sb->last_bytes_delivered == 0), "last bytes delivered %d",
435             sb->last_bytes_delivered);
436   TCP_TEST ((sb->lost_bytes == 200), "lost bytes %u", sb->lost_bytes);
437   TCP_TEST ((sb->snd_una_adv == 0), "snd_una_adv %u", sb->snd_una_adv);
438
439   return 0;
440 }
441
442 static int
443 tcp_test_sack_tx (vlib_main_t * vm, unformat_input_t * input)
444 {
445   tcp_connection_t _tc, *tc = &_tc;
446   sack_block_t *sacks;
447   int i, verbose = 0, expected;
448
449   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
450     {
451       if (unformat (input, "verbose"))
452         verbose = 1;
453       else
454         {
455           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
456                            input);
457           return -1;
458         }
459     }
460
461   clib_memset (tc, 0, sizeof (*tc));
462
463   /*
464    * Add odd sack block pairs
465    */
466   for (i = 1; i < 10; i += 2)
467     {
468       tcp_update_sack_list (tc, i * 100, (i + 1) * 100);
469     }
470
471   TCP_TEST ((vec_len (tc->snd_sacks) == 5), "sack blocks %d expected %d",
472             vec_len (tc->snd_sacks), 5);
473   TCP_TEST ((tc->snd_sacks[0].start = 900),
474             "first sack block start %u expected %u", tc->snd_sacks[0].start,
475             900);
476
477   /*
478    * Try to add one extra
479    */
480   sacks = vec_dup (tc->snd_sacks);
481
482   tcp_update_sack_list (tc, 1100, 1200);
483   if (verbose)
484     vlib_cli_output (vm, "add new segment [1100, 1200]\n%U",
485                      format_tcp_sacks, tc);
486   expected = 5 < TCP_MAX_SACK_BLOCKS ? 6 : 5;
487   TCP_TEST ((vec_len (tc->snd_sacks) == expected),
488             "sack blocks %d expected %d", vec_len (tc->snd_sacks), expected);
489   TCP_TEST ((tc->snd_sacks[0].start == 1100),
490             "first sack block start %u expected %u", tc->snd_sacks[0].start,
491             1100);
492
493   /* restore */
494   vec_free (tc->snd_sacks);
495   tc->snd_sacks = sacks;
496
497   /*
498    * Overlap first 2 segment
499    */
500   tc->rcv_nxt = 300;
501   tcp_update_sack_list (tc, 300, 300);
502   if (verbose)
503     vlib_cli_output (vm, "overlap first 2 segments:\n%U",
504                      format_tcp_sacks, tc);
505   TCP_TEST ((vec_len (tc->snd_sacks) == 3), "sack blocks %d expected %d",
506             vec_len (tc->snd_sacks), 3);
507   TCP_TEST ((tc->snd_sacks[0].start == 900),
508             "first sack block start %u expected %u", tc->snd_sacks[0].start,
509             500);
510
511   /*
512    * Add a new segment
513    */
514   tcp_update_sack_list (tc, 1100, 1200);
515   if (verbose)
516     vlib_cli_output (vm, "add new segment [1100, 1200]\n%U",
517                      format_tcp_sacks, tc);
518   TCP_TEST ((vec_len (tc->snd_sacks) == 4), "sack blocks %d expected %d",
519             vec_len (tc->snd_sacks), 4);
520   TCP_TEST ((tc->snd_sacks[0].start == 1100),
521             "first sack block start %u expected %u", tc->snd_sacks[0].start,
522             1100);
523
524   /*
525    * Join middle segments
526    */
527   tcp_update_sack_list (tc, 800, 900);
528   if (verbose)
529     vlib_cli_output (vm, "join middle segments [800, 900]\n%U",
530                      format_tcp_sacks, tc);
531
532   TCP_TEST ((vec_len (tc->snd_sacks) == 3), "sack blocks %d expected %d",
533             vec_len (tc->snd_sacks), 3);
534   TCP_TEST ((tc->snd_sacks[0].start == 700),
535             "first sack block start %u expected %u", tc->snd_sacks[0].start,
536             1100);
537
538   /*
539    * Advance rcv_nxt to overlap all
540    */
541   tc->rcv_nxt = 1200;
542   tcp_update_sack_list (tc, 1200, 1200);
543   if (verbose)
544     vlib_cli_output (vm, "advance rcv_nxt to 1200\n%U", format_tcp_sacks, tc);
545   TCP_TEST ((vec_len (tc->snd_sacks) == 0), "sack blocks %d expected %d",
546             vec_len (tc->snd_sacks), 0);
547
548
549   /*
550    * Add 2 blocks, overwrite first and update rcv_nxt to also remove it
551    */
552
553   vec_reset_length (tc->snd_sacks);
554   tc->rcv_nxt = 0;
555
556   tcp_update_sack_list (tc, 100, 200);
557   tcp_update_sack_list (tc, 300, 400);
558
559   if (verbose)
560     vlib_cli_output (vm, "add [100, 200] [300, 400]\n%U",
561                      format_tcp_sacks, tc);
562   TCP_TEST ((vec_len (tc->snd_sacks) == 2),
563             "sack blocks %d expected %d", vec_len (tc->snd_sacks), 2);
564   TCP_TEST ((tc->snd_sacks[0].start == 300),
565             "first sack block start %u expected %u", tc->snd_sacks[0].start,
566             300);
567
568   tc->rcv_nxt = 100;
569   tcp_update_sack_list (tc, 100, 100);
570   if (verbose)
571     vlib_cli_output (vm, "add [100, 200] rcv_nxt = 100\n%U",
572                      format_tcp_sacks, tc);
573   TCP_TEST ((vec_len (tc->snd_sacks) == 1),
574             "sack blocks %d expected %d", vec_len (tc->snd_sacks), 1);
575   TCP_TEST ((tc->snd_sacks[0].start == 300),
576             "first sack block start %u expected %u", tc->snd_sacks[0].start,
577             300);
578   return 0;
579 }
580
581 static int
582 tcp_test_sack (vlib_main_t * vm, unformat_input_t * input)
583 {
584   int res = 0;
585
586   /* Run all tests */
587   if (unformat_check_input (input) == UNFORMAT_END_OF_INPUT)
588     {
589       if (tcp_test_sack_tx (vm, input))
590         {
591           return -1;
592         }
593
594       if (tcp_test_sack_rx (vm, input))
595         {
596           return -1;
597         }
598     }
599   else
600     {
601       if (unformat (input, "tx"))
602         {
603           res = tcp_test_sack_tx (vm, input);
604         }
605       else if (unformat (input, "rx"))
606         {
607           res = tcp_test_sack_rx (vm, input);
608         }
609     }
610
611   return res;
612 }
613
614 static int
615 tcp_test_lookup (vlib_main_t * vm, unformat_input_t * input)
616 {
617   session_main_t *smm = &session_main;
618   tcp_main_t *tm = &tcp_main;
619   transport_connection_t _tc1, *tc1 = &_tc1, _tc2, *tc2 = &_tc2, *tconn;
620   tcp_connection_t *tc;
621   session_t *s, *s1;
622   u8 cmp = 0, is_filtered = 0;
623   u32 sidx;
624
625   /*
626    * Allocate fake session and connection 1
627    */
628   pool_get (smm->wrk[0].sessions, s);
629   clib_memset (s, 0, sizeof (*s));
630   s->session_index = sidx = s - smm->wrk[0].sessions;
631
632   pool_get (tm->connections[0], tc);
633   clib_memset (tc, 0, sizeof (*tc));
634   tc->connection.c_index = tc - tm->connections[0];
635   tc->connection.s_index = s->session_index;
636   s->connection_index = tc->connection.c_index;
637
638   tc->connection.lcl_ip.ip4.as_u32 = clib_host_to_net_u32 (0x06000101);
639   tc->connection.rmt_ip.ip4.as_u32 = clib_host_to_net_u32 (0x06000103);
640   tc->connection.lcl_port = 35051;
641   tc->connection.rmt_port = 53764;
642   tc->connection.proto = TRANSPORT_PROTO_TCP;
643   tc->connection.is_ip4 = 1;
644   clib_memcpy_fast (tc1, &tc->connection, sizeof (*tc1));
645
646   /*
647    * Allocate fake session and connection 2
648    */
649   pool_get (smm->wrk[0].sessions, s);
650   clib_memset (s, 0, sizeof (*s));
651   s->session_index = s - smm->wrk[0].sessions;
652
653   pool_get (tm->connections[0], tc);
654   clib_memset (tc, 0, sizeof (*tc));
655   tc->connection.c_index = tc - tm->connections[0];
656   tc->connection.s_index = s->session_index;
657   s->connection_index = tc->connection.c_index;
658
659   tc->connection.lcl_ip.ip4.as_u32 = clib_host_to_net_u32 (0x06000101);
660   tc->connection.rmt_ip.ip4.as_u32 = clib_host_to_net_u32 (0x06000102);
661   tc->connection.lcl_port = 38225;
662   tc->connection.rmt_port = 53764;
663   tc->connection.proto = TRANSPORT_PROTO_TCP;
664   tc->connection.is_ip4 = 1;
665   clib_memcpy_fast (tc2, &tc->connection, sizeof (*tc2));
666
667   /*
668    * Confirm that connection lookup works
669    */
670
671   s1 = pool_elt_at_index (smm->wrk[0].sessions, sidx);
672   session_lookup_add_connection (tc1, session_handle (s1));
673   tconn = session_lookup_connection_wt4 (0, &tc1->lcl_ip.ip4,
674                                          &tc1->rmt_ip.ip4,
675                                          tc1->lcl_port, tc1->rmt_port,
676                                          tc1->proto, 0, &is_filtered);
677
678   TCP_TEST ((tconn != 0), "connection exists");
679   cmp = (memcmp (&tconn->rmt_ip, &tc1->rmt_ip, sizeof (tc1->rmt_ip)) == 0);
680   TCP_TEST ((cmp), "rmt ip is identical %d", cmp);
681   TCP_TEST ((tconn->lcl_port == tc1->lcl_port),
682             "rmt port is identical %d", tconn->lcl_port == tc1->lcl_port);
683
684   /*
685    * Non-existing connection lookup should not work
686    */
687
688   tconn = session_lookup_connection_wt4 (0, &tc2->lcl_ip.ip4,
689                                          &tc2->rmt_ip.ip4,
690                                          tc2->lcl_port, tc2->rmt_port,
691                                          tc2->proto, 0, &is_filtered);
692   TCP_TEST ((tconn == 0), "lookup result should be null");
693
694   /*
695    * Delete and lookup again
696    */
697   session_lookup_del_connection (tc1);
698   tconn = session_lookup_connection_wt4 (0, &tc1->lcl_ip.ip4,
699                                          &tc1->rmt_ip.ip4,
700                                          tc1->lcl_port, tc1->rmt_port,
701                                          tc1->proto, 0, &is_filtered);
702   TCP_TEST ((tconn == 0), "lookup result should be null");
703   tconn = session_lookup_connection_wt4 (0, &tc2->lcl_ip.ip4,
704                                          &tc2->rmt_ip.ip4,
705                                          tc2->lcl_port, tc2->rmt_port,
706                                          tc2->proto, 0, &is_filtered);
707   TCP_TEST ((tconn == 0), "lookup result should be null");
708
709   /*
710    * Re-add and lookup tc2
711    */
712   session_lookup_add_connection (tc1, tc1->s_index);
713   tconn = session_lookup_connection_wt4 (0, &tc2->lcl_ip.ip4,
714                                          &tc2->rmt_ip.ip4,
715                                          tc2->lcl_port, tc2->rmt_port,
716                                          tc2->proto, 0, &is_filtered);
717   TCP_TEST ((tconn == 0), "lookup result should be null");
718
719   return 0;
720 }
721
722 static int
723 tcp_test_session (vlib_main_t * vm, unformat_input_t * input)
724 {
725   int rv = 0;
726   tcp_connection_t *tc0;
727   ip4_address_t local, remote;
728   u16 local_port, remote_port;
729   tcp_main_t *tm = vnet_get_tcp_main ();
730   int is_add = 1;
731
732
733   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
734     {
735       if (unformat (input, "del"))
736         is_add = 0;
737       else if (unformat (input, "add"))
738         is_add = 1;
739       else
740         break;
741     }
742
743   if (is_add)
744     {
745       local.as_u32 = clib_host_to_net_u32 (0x06000101);
746       remote.as_u32 = clib_host_to_net_u32 (0x06000102);
747       local_port = clib_host_to_net_u16 (1234);
748       remote_port = clib_host_to_net_u16 (11234);
749
750       pool_get (tm->connections[0], tc0);
751       clib_memset (tc0, 0, sizeof (*tc0));
752
753       tc0->state = TCP_STATE_ESTABLISHED;
754       tc0->rcv_las = 1;
755       tc0->c_c_index = tc0 - tm->connections[0];
756       tc0->c_lcl_port = local_port;
757       tc0->c_rmt_port = remote_port;
758       tc0->c_is_ip4 = 1;
759       tc0->c_thread_index = 0;
760       tc0->c_lcl_ip4.as_u32 = local.as_u32;
761       tc0->c_rmt_ip4.as_u32 = remote.as_u32;
762       tc0->rcv_opts.mss = 1450;
763       tcp_connection_init_vars (tc0);
764
765       TCP_EVT_DBG (TCP_EVT_OPEN, tc0);
766
767       if (session_stream_accept (&tc0->connection, 0 /* listener index */ ,
768                                  0 /* thread index */ , 0 /* notify */ ))
769         clib_warning ("stream_session_accept failed");
770
771       session_stream_accept_notify (&tc0->connection);
772     }
773   else
774     {
775       tc0 = tcp_connection_get (0 /* connection index */ , 0 /* thread */ );
776       tc0->state = TCP_STATE_CLOSED;
777       session_transport_closing_notify (&tc0->connection);
778     }
779
780   return rv;
781 }
782
783 static inline int
784 tbt_seq_lt (u32 a, u32 b)
785 {
786   return seq_lt (a, b);
787 }
788
789 static inline int
790 approx_equal (u32 a, u32 b)
791 {
792   if (b > 0.99 * a && b < 1.01 * a)
793     return 1;
794   return 0;
795 }
796
797 static int
798 tcp_test_delivery (vlib_main_t * vm, unformat_input_t * input)
799 {
800   u32 thread_index = 0, snd_una, *min_seqs = 0;
801   tcp_rate_sample_t _rs = { 0 }, *rs = &_rs;
802   tcp_connection_t _tc, *tc = &_tc;
803   sack_scoreboard_t *sb = &tc->sack_sb;
804   int __clib_unused verbose = 0, i;
805   u64 rate = 1000, burst = 100;
806   sack_block_t *sacks = 0;
807   tcp_byte_tracker_t *bt;
808   rb_node_t *root, *rbn;
809   tcp_bt_sample_t *bts;
810
811   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
812     {
813       if (unformat (input, "verbose"))
814         verbose = 1;
815       else
816         {
817           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
818                            input);
819           return -1;
820         }
821     }
822
823   /* Init data structures */
824   memset (tc, 0, sizeof (*tc));
825   session_main.wrk[thread_index].last_vlib_time = 1;
826   transport_connection_tx_pacer_update (&tc->connection, rate);
827
828   tcp_bt_init (tc);
829   bt = tc->bt;
830
831   /*
832    * Track simple bursts without rxt
833    */
834
835   /* 1) track first burst a time 1 */
836   tcp_bt_track_tx (tc);
837
838   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
839   TCP_TEST (pool_elts (bt->samples) == 1, "should have 1 sample");
840   bts = pool_elt_at_index (bt->samples, bt->head);
841   TCP_TEST (bts->min_seq == tc->snd_una, "min seq should be snd_una");
842   TCP_TEST (bts->next == TCP_BTS_INVALID_INDEX, "next should be invalid");
843   TCP_TEST (bts->prev == TCP_BTS_INVALID_INDEX, "prev should be invalid");
844   TCP_TEST (bts->delivered_time == 1, "delivered time should be 1");
845   TCP_TEST (bts->delivered == 0, "delivered should be 0");
846   TCP_TEST (!(bts->flags & TCP_BTS_IS_RXT), "not retransmitted");
847   TCP_TEST (!(bts->flags & TCP_BTS_IS_APP_LIMITED), "not app limited");
848
849   /* 2) check delivery rate at time 2 */
850   session_main.wrk[thread_index].last_vlib_time = 2;
851   tc->snd_una = tc->snd_nxt = burst;
852   tc->bytes_acked = burst;
853
854   tcp_bt_sample_delivery_rate (tc, rs);
855
856   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
857   TCP_TEST (pool_elts (bt->samples) == 0, "sample should've been consumed");
858   TCP_TEST (tc->delivered_time == 2, "delivered time should be 2");
859   TCP_TEST (tc->delivered == burst, "delivered should be 100");
860   TCP_TEST (rs->ack_time == 1, "ack time should be 1");
861   TCP_TEST (rs->delivered == burst, "delivered should be 100");
862   TCP_TEST (rs->sample_delivered == 0, "sample delivered should be 0");
863   TCP_TEST (approx_equal (rate, rs->tx_rate), "rate should be %u is %u", rate,
864             rs->tx_rate);
865   TCP_TEST (!(rs->flags & TCP_BTS_IS_RXT), "not retransmitted");
866
867   /* 3) track second burst at time 2 */
868   tcp_bt_track_tx (tc);
869   tc->snd_nxt += burst;
870
871   /* 4) track second burst at time 3 */
872   session_main.wrk[thread_index].last_vlib_time = 3;
873   tcp_bt_track_tx (tc);
874   tc->snd_nxt += burst;
875
876   TCP_TEST (pool_elts (bt->samples) == 2, "should have 2 samples");
877
878   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
879   bts = pool_elt_at_index (bt->samples, bt->head);
880   TCP_TEST (bts->min_seq == tc->snd_una, "min seq should be snd_una");
881   TCP_TEST (bts->next == bt->tail, "next should tail");
882
883   bts = pool_elt_at_index (bt->samples, bt->tail);
884   TCP_TEST (bts->min_seq == tc->snd_nxt - burst,
885             "min seq should be snd_nxt prior to burst");
886   TCP_TEST (bts->prev == bt->head, "prev should be head");
887
888   /* 5) check delivery rate at time 4 */
889   session_main.wrk[thread_index].last_vlib_time = 4;
890   tc->snd_una = tc->snd_nxt;
891   tc->bytes_acked = 2 * burst;
892
893   tcp_bt_sample_delivery_rate (tc, rs);
894
895   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
896   TCP_TEST (pool_elts (bt->samples) == 0, "sample should've been consumed");
897   TCP_TEST (tc->delivered_time == 4, "delivered time should be 4");
898   TCP_TEST (tc->delivered == 3 * burst, "delivered should be 300 is %u",
899             tc->delivered);
900   TCP_TEST (rs->ack_time == 2, "ack time should be 2");
901   TCP_TEST (rs->delivered == 2 * burst, "delivered should be 200");
902   TCP_TEST (rs->sample_delivered == burst, "delivered should be 100");
903   TCP_TEST (approx_equal (rate, rs->tx_rate), "rate should be %u is %u", rate,
904             rs->tx_rate);
905   TCP_TEST (!(rs->flags & TCP_BTS_IS_RXT), "not retransmitted");
906   TCP_TEST (!(bts->flags & TCP_BTS_IS_APP_LIMITED), "not app limited");
907
908   /*
909    * Track retransmissions
910    *
911    * snd_una should be 300 at this point
912    */
913
914   snd_una = tc->snd_una;
915
916   /* 1) track first burst a time 4 */
917   tcp_bt_track_tx (tc);
918   tc->snd_nxt += burst;
919
920   /* 2) track second burst at time 5 */
921   session_main.wrk[thread_index].last_vlib_time = 5;
922   tcp_bt_track_tx (tc);
923   tc->snd_nxt += burst;
924
925   /* 3) track third burst at time 6 */
926   session_main.wrk[thread_index].last_vlib_time = 6;
927   tcp_bt_track_tx (tc);
928   tc->snd_nxt += burst;
929
930   /* 4) track fourth burst at time 7 */
931   session_main.wrk[thread_index].last_vlib_time = 7;
932   /* Limited until last burst is acked */
933   tc->app_limited = snd_una + 4 * burst - 1;
934   tcp_bt_track_tx (tc);
935   tc->snd_nxt += burst;
936
937   /* 5) check delivery rate at time 8
938    *
939    * tc->snd_una = snd_una + 10
940    * sacks:
941    * [snd_una + burst, snd_una + burst + 10]
942    * [snd_una + 2 * burst + 10, snd_una + 2 * burst + 20]
943    */
944   session_main.wrk[thread_index].last_vlib_time = 8;
945   tc->snd_una += 10;
946   tc->bytes_acked = 10;
947   sb->last_sacked_bytes = 20;
948
949   TCP_TEST (pool_elts (bt->samples) == 4, "there should be 4 samples");
950
951   vec_validate (sacks, 1);
952   sacks[0].start = snd_una + burst;
953   sacks[0].end = snd_una + burst + 10;
954   sacks[1].start = snd_una + 2 * burst + 10;
955   sacks[1].end = snd_una + 2 * burst + 20;
956   tc->rcv_opts.sacks = sacks;
957
958   tcp_bt_sample_delivery_rate (tc, rs);
959
960   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
961   TCP_TEST (pool_elts (bt->samples) == 4, "there should be 4 samples");
962   TCP_TEST (tc->delivered_time == 8, "delivered time should be 8");
963   TCP_TEST (tc->delivered == 3 * burst + 30, "delivered should be %u is %u",
964             3 * burst + 30, tc->delivered);
965   /* All 3 samples have the same delivered number of bytes. So the first is
966    * the reference for delivery estimate. */
967   TCP_TEST (rs->ack_time == 4, "ack time should be 4 is %.2f", rs->ack_time);
968   TCP_TEST (rs->delivered == 30, "delivered should be 30");
969   TCP_TEST (rs->sample_delivered == 3 * burst,
970             "sample delivered should be %u", 3 * burst);
971   TCP_TEST (approx_equal (rate, rs->tx_rate), "rate should be %u is %u", rate,
972             rs->tx_rate);
973   TCP_TEST (!(rs->flags & TCP_BTS_IS_RXT), "not retransmitted");
974   TCP_TEST (!(rs->flags & TCP_BTS_IS_APP_LIMITED), "not app limited");
975
976   /* 6) Retransmit and track at time 9
977    *
978    * delivered = 3 * burst + 30
979    * delivered_time = 8 (last ack)
980    *
981    * segments:
982    * [snd_una + 10, snd_una + burst]
983    * [snd_una + burst + 10, snd_una + 2 * burst + 10]
984    * [snd_una + 2 * burst + 20, snd_una + 4 * burst]
985    */
986   session_main.wrk[thread_index].last_vlib_time = 9;
987
988   tcp_bt_track_rxt (tc, snd_una + 10, snd_una + burst);
989   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
990   /* The retransmit covers everything left from first burst */
991   TCP_TEST (pool_elts (bt->samples) == 4, "there should be 4 samples");
992
993   tcp_bt_track_rxt (tc, snd_una + burst + 10, snd_una + 2 * burst + 10);
994   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
995   TCP_TEST (pool_elts (bt->samples) == 5, "there should be 5 samples");
996
997   /* Retransmit covers last sample entirely so it should be removed */
998   tcp_bt_track_rxt (tc, snd_una + 2 * burst + 20, snd_una + 4 * burst);
999   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
1000   TCP_TEST (pool_elts (bt->samples) == 5, "there should be 5 samples");
1001
1002   vec_validate (min_seqs, 4);
1003   min_seqs[0] = snd_una + 10;
1004   min_seqs[1] = snd_una + burst;
1005   min_seqs[2] = snd_una + burst + 10;
1006   min_seqs[3] = snd_una + 2 * burst + 10;
1007   min_seqs[4] = snd_una + 2 * burst + 20;
1008
1009   root = bt->sample_lookup.nodes + bt->sample_lookup.root;
1010   bts = bt->samples + bt->head;
1011   for (i = 0; i < vec_len (min_seqs); i++)
1012     {
1013       if (bts->min_seq != min_seqs[i])
1014         TCP_TEST (0, "should be %u is %u", min_seqs[i], bts->min_seq);
1015       rbn = rb_tree_search_subtree_custom (&bt->sample_lookup, root,
1016                                            bts->min_seq, tbt_seq_lt);
1017       if (rbn->opaque != bts - bt->samples)
1018         TCP_TEST (0, "lookup should work");
1019       bts = bt->samples + bts->next;
1020     }
1021
1022   /* 7) check delivery rate at time 10
1023    *
1024    * tc->snd_una = snd_una + 2 * burst
1025    * sacks:
1026    * [snd_una + 2 * burst + 20, snd_una + 2 * burst + 30]
1027    * [snd_una + 2 * burst + 50, snd_una + 2 * burst + 60]
1028    */
1029   session_main.wrk[thread_index].last_vlib_time = 10;
1030   tc->snd_una = snd_una + 2 * burst;
1031   tc->bytes_acked = 2 * burst - 10;
1032   sb->last_sacked_bytes = 20;
1033
1034   sacks[0].start = snd_una + 2 * burst + 20;
1035   sacks[0].end = snd_una + 2 * burst + 30;
1036   sacks[1].start = snd_una + 2 * burst + 50;
1037   sacks[1].end = snd_una + 2 * burst + 60;
1038
1039   tcp_bt_sample_delivery_rate (tc, rs);
1040
1041   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
1042   TCP_TEST (pool_elts (bt->samples) == 3, "num samples should be 3 is %u",
1043             pool_elts (bt->samples));
1044   TCP_TEST (tc->delivered_time == 10, "delivered time should be 10");
1045   TCP_TEST (tc->delivered == 5 * burst + 40, "delivered should be %u is %u",
1046             5 * burst + 40, tc->delivered);
1047   /* A rxt was acked and delivered time for it is 8 (last ack time) */
1048   TCP_TEST (rs->ack_time == 2, "ack time should be 2 is %.2f", rs->ack_time);
1049   /* delivered_now - delivered_rxt ~ 5 * burst + 40 - 3 * burst - 30 */
1050   TCP_TEST (rs->delivered == 2 * burst + 10, "delivered should be 210 is %u",
1051             rs->delivered);
1052   TCP_TEST (rs->sample_delivered == 3 * burst + 30,
1053             "sample delivered should be %u", 3 * burst + 30);
1054   TCP_TEST (approx_equal (rate, rs->tx_rate), "rate should be %u is %u", rate,
1055             rs->tx_rate);
1056   TCP_TEST (rs->flags & TCP_BTS_IS_RXT, "is retransmitted");
1057   /* Sample is app limited because of the retransmits */
1058   TCP_TEST (rs->flags & TCP_BTS_IS_APP_LIMITED, "is app limited");
1059   TCP_TEST (tc->app_limited, "app limited should be set");
1060
1061   /*
1062    * 8) check delivery rate at time 11
1063    */
1064   session_main.wrk[thread_index].last_vlib_time = 11;
1065   tc->snd_una = tc->snd_nxt;
1066   tc->bytes_acked = 2 * burst;
1067   sb->last_sacked_bytes = 0;
1068   sb->last_bytes_delivered = 40;
1069
1070   memset (rs, 0, sizeof (*rs));
1071   tcp_bt_sample_delivery_rate (tc, rs);
1072
1073   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
1074   TCP_TEST (pool_elts (bt->samples) == 0, "num samples should be 0 is %u",
1075             pool_elts (bt->samples));
1076   TCP_TEST (tc->delivered_time == 11, "delivered time should be 11");
1077   TCP_TEST (tc->delivered == 7 * burst, "delivered should be %u is %u",
1078             7 * burst, tc->delivered);
1079   /* Last rxt was at time 8 */
1080   TCP_TEST (rs->ack_time == 3, "ack time should be 3 is %.2f", rs->ack_time);
1081   /* delivered_now - delivered_rxt ~ 7 * burst - 3 * burst - 30.
1082    * That's because we didn't retransmit any new segment. */
1083   TCP_TEST (rs->delivered == 4 * burst - 30, "delivered should be 160 is %u",
1084             rs->delivered);
1085   TCP_TEST (rs->sample_delivered == 3 * burst + 30,
1086             "sample delivered should be %u", 3 * burst + 30);
1087   TCP_TEST (approx_equal (rate, rs->tx_rate), "rate should be %u is %u", rate,
1088             rs->tx_rate);
1089   TCP_TEST (rs->flags & TCP_BTS_IS_RXT, "is retransmitted");
1090   TCP_TEST (rs->flags & TCP_BTS_IS_APP_LIMITED, "is app limited");
1091   TCP_TEST (tc->app_limited == 0, "app limited should be cleared");
1092
1093   /*
1094    * Cleanup
1095    */
1096   vec_free (sacks);
1097   vec_free (min_seqs);
1098   tcp_bt_cleanup (tc);
1099   return 0;
1100 }
1101
1102 static clib_error_t *
1103 tcp_test (vlib_main_t * vm,
1104           unformat_input_t * input, vlib_cli_command_t * cmd_arg)
1105 {
1106   int res = 0;
1107
1108   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1109     {
1110       if (unformat (input, "sack"))
1111         {
1112           res = tcp_test_sack (vm, input);
1113         }
1114       else if (unformat (input, "session"))
1115         {
1116           res = tcp_test_session (vm, input);
1117         }
1118       else if (unformat (input, "lookup"))
1119         {
1120           res = tcp_test_lookup (vm, input);
1121         }
1122       else if (unformat (input, "delivery"))
1123         {
1124           res = tcp_test_delivery (vm, input);
1125         }
1126       else if (unformat (input, "all"))
1127         {
1128           if ((res = tcp_test_sack (vm, input)))
1129             goto done;
1130           if ((res = tcp_test_lookup (vm, input)))
1131             goto done;
1132           if ((res = tcp_test_delivery (vm, input)))
1133             goto done;
1134         }
1135       else
1136         break;
1137     }
1138
1139 done:
1140   if (res)
1141     return clib_error_return (0, "TCP unit test failed");
1142   return 0;
1143 }
1144
1145 /* *INDENT-OFF* */
1146 VLIB_CLI_COMMAND (tcp_test_command, static) =
1147 {
1148   .path = "test tcp",
1149   .short_help = "internal tcp unit tests",
1150   .function = tcp_test,
1151 };
1152 /* *INDENT-ON* */
1153
1154 /*
1155  * fd.io coding-style-patch-verification: ON
1156  *
1157  * Local Variables:
1158  * eval: (c-set-style "gnu")
1159  * End:
1160  */