f6a389c5c8804bc1604bb4be56bea6ac1cdce7bb
[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->is_reneging), "is not reneging");
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->is_reneging), "is not reneging");
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 - this is reneging because we should ack until 1000
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), "scoreboard has %d elements",
171             pool_elts (sb->holes));
172   TCP_TEST ((sb->is_reneging), "is reneging");
173
174   /*
175    * Sack all up to 1000
176    */
177   tc->snd_una = 100;
178   tcp_rcv_sacks (tc, 1000);
179   TCP_TEST ((sb->high_sacked == 1000), "max sacked byte %u", sb->high_sacked);
180   TCP_TEST ((sb->sacked_bytes == 0), "sacked bytes %d", sb->sacked_bytes);
181   TCP_TEST ((sb->last_sacked_bytes == 0),
182             "last sacked bytes %d", sb->last_sacked_bytes);
183   TCP_TEST ((sb->lost_bytes == 0), "lost bytes %u", sb->lost_bytes);
184   TCP_TEST ((!sb->is_reneging), "is not reneging");
185
186
187   /*
188    * Add new block
189    */
190
191   vec_reset_length (tc->rcv_opts.sacks);
192
193   block.start = 1200;
194   block.end = 1300;
195   vec_add1 (tc->rcv_opts.sacks, block);
196
197   tc->snd_una_max = 1500;
198   tc->snd_una = 1000;
199   tc->snd_nxt = 1500;
200   tcp_rcv_sacks (tc, 1000);
201
202   if (verbose)
203     vlib_cli_output (vm, "\nadd [1200, 1300] snd_una_max 1500, snd_una 1000:"
204                      " \n%U", format_tcp_scoreboard, sb, tc);
205
206   TCP_TEST ((!sb->is_reneging), "is not reneging");
207   TCP_TEST ((pool_elts (sb->holes) == 2),
208             "scoreboard has %d holes", pool_elts (sb->holes));
209   hole = scoreboard_first_hole (sb);
210   TCP_TEST ((hole->start == 1000 && hole->end == 1200),
211             "first hole start %u end %u", hole->start, hole->end);
212   TCP_TEST ((sb->high_sacked == 1300), "max sacked byte %u", sb->high_sacked);
213   hole = scoreboard_last_hole (sb);
214   TCP_TEST ((hole->start == 1300 && hole->end == 1500),
215             "last hole start %u end %u", hole->start, hole->end);
216   TCP_TEST ((sb->sacked_bytes == 100), "sacked bytes %d", sb->sacked_bytes);
217   TCP_TEST ((sb->lost_bytes == 0), "lost bytes %u", sb->lost_bytes);
218
219   /*
220    * Ack first hole
221    */
222
223   vec_reset_length (tc->rcv_opts.sacks);
224   /* Ack up to 1300 to avoid reneging */
225   tcp_rcv_sacks (tc, 1300);
226
227   if (verbose)
228     vlib_cli_output (vm, "\nsb ack up to byte 1300:\n%U",
229                      format_tcp_scoreboard, sb, tc);
230
231   TCP_TEST ((sb->sacked_bytes == 0), "sacked bytes %d", sb->sacked_bytes);
232   TCP_TEST ((pool_elts (sb->holes) == 1),
233             "scoreboard has %d elements", pool_elts (sb->holes));
234   TCP_TEST ((sb->last_bytes_delivered == 100), "last bytes delivered %d",
235             sb->last_bytes_delivered);
236   TCP_TEST ((sb->lost_bytes == 0), "lost bytes %u", sb->lost_bytes);
237   TCP_TEST ((sb->head != TCP_INVALID_SACK_HOLE_INDEX), "head %u", sb->head);
238   TCP_TEST ((sb->tail != TCP_INVALID_SACK_HOLE_INDEX), "tail %u", sb->tail);
239   TCP_TEST ((!sb->is_reneging), "is not reneging");
240
241   /*
242    * Add some more blocks and then remove all
243    */
244   vec_reset_length (tc->rcv_opts.sacks);
245   tc->snd_una = 1300;
246   tc->snd_nxt = tc->snd_una_max = 1900;
247   for (i = 0; i < 5; i++)
248     {
249       block.start = i * 100 + 1200;
250       block.end = (i + 1) * 100 + 1200;
251       vec_add1 (tc->rcv_opts.sacks, block);
252     }
253   tcp_rcv_sacks (tc, 1900);
254
255   scoreboard_clear (sb);
256   if (verbose)
257     vlib_cli_output (vm, "\nsb cleared all:\n%U", format_tcp_scoreboard, sb,
258                      tc);
259
260   TCP_TEST ((pool_elts (sb->holes) == 0),
261             "number of holes %d", pool_elts (sb->holes));
262   TCP_TEST ((sb->head == TCP_INVALID_SACK_HOLE_INDEX), "head %u", sb->head);
263   TCP_TEST ((sb->tail == TCP_INVALID_SACK_HOLE_INDEX), "tail %u", sb->tail);
264
265   /*
266    * Re-inject odd blocks and ack them all
267    */
268
269   tc->snd_una = 0;
270   tc->snd_una_max = 1000;
271   tc->snd_nxt = 1000;
272   vec_reset_length (tc->rcv_opts.sacks);
273   for (i = 0; i < 5; i++)
274     {
275       vec_add1 (tc->rcv_opts.sacks, sacks[i * 2 + 1]);
276     }
277   tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
278   tcp_rcv_sacks (tc, 0);
279   if (verbose)
280     vlib_cli_output (vm, "\nsb added odd blocks snd_una 0 snd_una_max 1000:"
281                      "\n%U", format_tcp_scoreboard, sb, tc);
282   TCP_TEST ((pool_elts (sb->holes) == 5),
283             "scoreboard has %d elements", pool_elts (sb->holes));
284   TCP_TEST ((sb->lost_bytes == 300), "lost bytes %u", sb->lost_bytes);
285   hole = scoreboard_last_hole (sb);
286   TCP_TEST ((hole->end == 900), "last hole end %u", hole->end);
287   TCP_TEST ((sb->high_sacked == 1000), "high sacked %u", sb->high_sacked);
288
289   /*
290    * Renege bytes from 950 to 1000
291    */
292   tcp_rcv_sacks (tc, 950);
293
294   if (verbose)
295     vlib_cli_output (vm, "\nack [0, 950]:\n%U", format_tcp_scoreboard, sb,
296                      tc);
297
298   TCP_TEST ((pool_elts (sb->holes) == 0), "scoreboard has %d elements",
299             pool_elts (sb->holes));
300   TCP_TEST ((sb->is_reneging), "is reneging");
301   TCP_TEST ((sb->sacked_bytes == 50), "sacked bytes %d", sb->sacked_bytes);
302   TCP_TEST ((sb->last_sacked_bytes == 0), "last sacked bytes %d",
303             sb->last_sacked_bytes);
304   TCP_TEST ((sb->lost_bytes == 0), "lost bytes %u", sb->lost_bytes);
305   TCP_TEST ((sb->high_sacked == 1000), "high sacked %u", sb->high_sacked);
306
307   scoreboard_clear (sb);
308
309   /*
310    * Inject one block, ack it and overlap hole
311    */
312
313   tc->snd_una = 0;
314   tc->snd_una_max = 1000;
315   tc->snd_nxt = 1000;
316
317   block.start = 100;
318   block.end = 500;
319   vec_add1 (tc->rcv_opts.sacks, block);
320   tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
321
322   tcp_rcv_sacks (tc, 0);
323
324   if (verbose)
325     vlib_cli_output (vm, "\nsb added [100, 500] snd_una 0 snd_una_max 1000:"
326                      "\n%U", format_tcp_scoreboard, sb, tc);
327
328   tcp_rcv_sacks (tc, 800);
329
330   if (verbose)
331     vlib_cli_output (vm, "\nsb ack [0, 800]:\n%U", format_tcp_scoreboard, sb,
332                      tc);
333
334   TCP_TEST ((pool_elts (sb->holes) == 1),
335             "scoreboard has %d elements", pool_elts (sb->holes));
336   TCP_TEST ((!sb->is_reneging), "is not reneging");
337   TCP_TEST ((sb->sacked_bytes == 0), "sacked bytes %d", sb->sacked_bytes);
338   TCP_TEST ((sb->last_sacked_bytes == 0), "last sacked bytes %d",
339             sb->last_sacked_bytes);
340   TCP_TEST ((sb->last_bytes_delivered == 400),
341             "last bytes delivered %d", sb->last_bytes_delivered);
342   TCP_TEST ((sb->lost_bytes == 0), "lost bytes %u", sb->lost_bytes);
343   TCP_TEST ((sb->head != TCP_INVALID_SACK_HOLE_INDEX), "head %u", sb->head);
344   TCP_TEST ((sb->tail != TCP_INVALID_SACK_HOLE_INDEX), "tail %u", sb->tail);
345
346   /*
347    * One hole close to head, patch head, split in two and start acking
348    * the lowest part
349    */
350   scoreboard_clear (sb);
351   tc->snd_una = 0;
352   tc->snd_una_max = 1000;
353   tc->snd_nxt = 1000;
354
355   block.start = 500;
356   block.end = 1000;
357   vec_add1 (tc->rcv_opts.sacks, block);
358   tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
359
360   tcp_rcv_sacks (tc, 0);
361   if (verbose)
362     vlib_cli_output (vm, "\nsb added [500, 1000]:\n%U",
363                      format_tcp_scoreboard, sb, tc);
364   TCP_TEST ((sb->sacked_bytes == 500), "sacked bytes %d", sb->sacked_bytes);
365   TCP_TEST ((sb->last_sacked_bytes == 500), "last sacked bytes %d",
366             sb->last_sacked_bytes);
367   TCP_TEST ((sb->lost_bytes == 500), "lost bytes %u", sb->lost_bytes);
368
369   vec_reset_length (tc->rcv_opts.sacks);
370   block.start = 300;
371   block.end = 400;
372   vec_add1 (tc->rcv_opts.sacks, block);
373   tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
374   tcp_rcv_sacks (tc, 100);
375   if (verbose)
376     vlib_cli_output (vm, "\nsb added [0, 100] [300, 400]:\n%U",
377                      format_tcp_scoreboard, sb, tc);
378   TCP_TEST ((pool_elts (sb->holes) == 2),
379             "scoreboard has %d elements", pool_elts (sb->holes));
380   TCP_TEST ((sb->sacked_bytes == 600), "sacked bytes %d", sb->sacked_bytes);
381   TCP_TEST ((sb->last_sacked_bytes == 100), "last sacked bytes %d",
382             sb->last_sacked_bytes);
383   TCP_TEST ((sb->last_bytes_delivered == 0), "last bytes delivered %d",
384             sb->last_bytes_delivered);
385   TCP_TEST ((sb->lost_bytes == 300), "lost bytes %u", sb->lost_bytes);
386
387   /*
388    * Ack [100 300] in two steps
389    *
390    * Step 1. Ack [100 200] which delivers 100 of the bytes lost
391    */
392   tc->snd_una = 100;
393   tcp_rcv_sacks (tc, 200);
394   TCP_TEST ((sb->sacked_bytes == 600), "sacked bytes %d", sb->sacked_bytes);
395   TCP_TEST ((sb->last_bytes_delivered == 0), "last bytes delivered %d",
396             sb->last_bytes_delivered);
397   TCP_TEST ((sb->lost_bytes == 200), "lost bytes %u", sb->lost_bytes);
398
399   /*
400    * Step 2. Ack up to 300, although 300 400 is sacked, so this is interpreted
401    * as reneging.
402    */
403   tc->snd_una = 200;
404   tcp_rcv_sacks (tc, 300);
405   if (verbose)
406     vlib_cli_output (vm, "\nacked [100, 300] in two steps:\n%U",
407                      format_tcp_scoreboard, sb, tc);
408   TCP_TEST ((sb->sacked_bytes == 600), "sacked bytes %d", sb->sacked_bytes);
409   TCP_TEST ((sb->lost_bytes == 100), "lost bytes %u", sb->lost_bytes);
410   TCP_TEST ((sb->last_bytes_delivered == 0), "last bytes delivered %d",
411             sb->last_bytes_delivered);
412   TCP_TEST ((sb->is_reneging), "is reneging");
413
414   /*
415    * Ack [300 500]. Delivers reneged segment [300 400] and reneges bytes
416    * above 500
417    */
418   tc->snd_una = 300;
419   tcp_rcv_sacks (tc, 500);
420   if (verbose)
421     vlib_cli_output (vm, "\nacked [400, 500]:\n%U", format_tcp_scoreboard, sb,
422                      tc);
423   TCP_TEST ((pool_elts (sb->holes) == 0),
424             "scoreboard has %d elements", pool_elts (sb->holes));
425   TCP_TEST ((sb->sacked_bytes == 500), "sacked bytes %d", sb->sacked_bytes);
426   TCP_TEST ((sb->last_sacked_bytes == 0), "last sacked bytes %d",
427             sb->last_sacked_bytes);
428   TCP_TEST ((sb->last_bytes_delivered == 100), "last bytes delivered %d",
429             sb->last_bytes_delivered);
430   TCP_TEST ((sb->is_reneging), "is reneging");
431   TCP_TEST ((sb->head == TCP_INVALID_SACK_HOLE_INDEX), "head %u", sb->head);
432   TCP_TEST ((sb->tail == TCP_INVALID_SACK_HOLE_INDEX), "tail %u", sb->tail);
433
434   /*
435    * Ack up to 1000 to deliver all bytes
436    */
437   tc->snd_una = 500;
438   tcp_rcv_sacks (tc, 1000);
439   if (verbose)
440     vlib_cli_output (vm, "\nAck high sacked:\n%U", format_tcp_scoreboard, sb,
441                      tc);
442   TCP_TEST ((sb->last_sacked_bytes == 0), "last sacked bytes %d",
443             sb->last_sacked_bytes);
444   TCP_TEST ((sb->last_bytes_delivered == 500), "last bytes delivered %d",
445             sb->last_bytes_delivered);
446   TCP_TEST ((!sb->is_reneging), "is not reneging");
447
448   /*
449    * Add [1200, 1500] and test that [1000, 1200] is lost (bytes condition)
450    * snd_una = 1000 and snd_una_max = 1600
451    */
452   tc->snd_una = 1000;
453   tc->snd_nxt = tc->snd_una_max = 1600;
454   vec_reset_length (tc->rcv_opts.sacks);
455   block.start = 1200;
456   block.end = 1500;
457   vec_add1 (tc->rcv_opts.sacks, block);
458   tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
459   tcp_rcv_sacks (tc, 1000);
460   if (verbose)
461     vlib_cli_output (vm, "\nacked [1200, 1500] test first hole is lost:\n%U",
462                      format_tcp_scoreboard, sb, tc);
463   TCP_TEST ((pool_elts (sb->holes) == 2), "scoreboard has %d elements",
464             pool_elts (sb->holes));
465   TCP_TEST ((sb->sacked_bytes == 300), "sacked bytes %d", sb->sacked_bytes);
466   TCP_TEST ((sb->last_sacked_bytes == 300), "last sacked bytes %d",
467             sb->last_sacked_bytes);
468   TCP_TEST ((sb->last_bytes_delivered == 0), "last bytes delivered %d",
469             sb->last_bytes_delivered);
470   TCP_TEST ((sb->lost_bytes == 200), "lost bytes %u", sb->lost_bytes);
471   TCP_TEST ((!sb->is_reneging), "is not reneging");
472
473   return 0;
474 }
475
476 static int
477 tcp_test_sack_tx (vlib_main_t * vm, unformat_input_t * input)
478 {
479   tcp_connection_t _tc, *tc = &_tc;
480   sack_block_t *sacks;
481   int i, verbose = 0, expected;
482
483   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
484     {
485       if (unformat (input, "verbose"))
486         verbose = 1;
487       else
488         {
489           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
490                            input);
491           return -1;
492         }
493     }
494
495   clib_memset (tc, 0, sizeof (*tc));
496
497   /*
498    * Add odd sack block pairs
499    */
500   for (i = 1; i < 10; i += 2)
501     {
502       tcp_update_sack_list (tc, i * 100, (i + 1) * 100);
503     }
504
505   TCP_TEST ((vec_len (tc->snd_sacks) == 5), "sack blocks %d expected %d",
506             vec_len (tc->snd_sacks), 5);
507   TCP_TEST ((tc->snd_sacks[0].start = 900),
508             "first sack block start %u expected %u", tc->snd_sacks[0].start,
509             900);
510
511   /*
512    * Try to add one extra
513    */
514   sacks = vec_dup (tc->snd_sacks);
515
516   tcp_update_sack_list (tc, 1100, 1200);
517   if (verbose)
518     vlib_cli_output (vm, "add new segment [1100, 1200]\n%U",
519                      format_tcp_sacks, tc);
520   expected = 5 < TCP_MAX_SACK_BLOCKS ? 6 : 5;
521   TCP_TEST ((vec_len (tc->snd_sacks) == expected),
522             "sack blocks %d expected %d", vec_len (tc->snd_sacks), expected);
523   TCP_TEST ((tc->snd_sacks[0].start == 1100),
524             "first sack block start %u expected %u", tc->snd_sacks[0].start,
525             1100);
526
527   /* restore */
528   vec_free (tc->snd_sacks);
529   tc->snd_sacks = sacks;
530
531   /*
532    * Overlap first 2 segment
533    */
534   tc->rcv_nxt = 300;
535   tcp_update_sack_list (tc, 300, 300);
536   if (verbose)
537     vlib_cli_output (vm, "overlap first 2 segments:\n%U",
538                      format_tcp_sacks, tc);
539   TCP_TEST ((vec_len (tc->snd_sacks) == 3), "sack blocks %d expected %d",
540             vec_len (tc->snd_sacks), 3);
541   TCP_TEST ((tc->snd_sacks[0].start == 900),
542             "first sack block start %u expected %u", tc->snd_sacks[0].start,
543             500);
544
545   /*
546    * Add a new segment
547    */
548   tcp_update_sack_list (tc, 1100, 1200);
549   if (verbose)
550     vlib_cli_output (vm, "add new segment [1100, 1200]\n%U",
551                      format_tcp_sacks, tc);
552   TCP_TEST ((vec_len (tc->snd_sacks) == 4), "sack blocks %d expected %d",
553             vec_len (tc->snd_sacks), 4);
554   TCP_TEST ((tc->snd_sacks[0].start == 1100),
555             "first sack block start %u expected %u", tc->snd_sacks[0].start,
556             1100);
557
558   /*
559    * Join middle segments
560    */
561   tcp_update_sack_list (tc, 800, 900);
562   if (verbose)
563     vlib_cli_output (vm, "join middle segments [800, 900]\n%U",
564                      format_tcp_sacks, tc);
565
566   TCP_TEST ((vec_len (tc->snd_sacks) == 3), "sack blocks %d expected %d",
567             vec_len (tc->snd_sacks), 3);
568   TCP_TEST ((tc->snd_sacks[0].start == 700),
569             "first sack block start %u expected %u", tc->snd_sacks[0].start,
570             1100);
571
572   /*
573    * Advance rcv_nxt to overlap all
574    */
575   tc->rcv_nxt = 1200;
576   tcp_update_sack_list (tc, 1200, 1200);
577   if (verbose)
578     vlib_cli_output (vm, "advance rcv_nxt to 1200\n%U", format_tcp_sacks, tc);
579   TCP_TEST ((vec_len (tc->snd_sacks) == 0), "sack blocks %d expected %d",
580             vec_len (tc->snd_sacks), 0);
581
582
583   /*
584    * Add 2 blocks, overwrite first and update rcv_nxt to also remove it
585    */
586
587   vec_reset_length (tc->snd_sacks);
588   tc->rcv_nxt = 0;
589
590   tcp_update_sack_list (tc, 100, 200);
591   tcp_update_sack_list (tc, 300, 400);
592
593   if (verbose)
594     vlib_cli_output (vm, "add [100, 200] [300, 400]\n%U",
595                      format_tcp_sacks, tc);
596   TCP_TEST ((vec_len (tc->snd_sacks) == 2),
597             "sack blocks %d expected %d", vec_len (tc->snd_sacks), 2);
598   TCP_TEST ((tc->snd_sacks[0].start == 300),
599             "first sack block start %u expected %u", tc->snd_sacks[0].start,
600             300);
601
602   tc->rcv_nxt = 100;
603   tcp_update_sack_list (tc, 100, 100);
604   if (verbose)
605     vlib_cli_output (vm, "add [100, 200] rcv_nxt = 100\n%U",
606                      format_tcp_sacks, tc);
607   TCP_TEST ((vec_len (tc->snd_sacks) == 1),
608             "sack blocks %d expected %d", vec_len (tc->snd_sacks), 1);
609   TCP_TEST ((tc->snd_sacks[0].start == 300),
610             "first sack block start %u expected %u", tc->snd_sacks[0].start,
611             300);
612   return 0;
613 }
614
615 static int
616 tcp_test_sack (vlib_main_t * vm, unformat_input_t * input)
617 {
618   int res = 0;
619
620   /* Run all tests */
621   if (unformat_check_input (input) == UNFORMAT_END_OF_INPUT)
622     {
623       if (tcp_test_sack_tx (vm, input))
624         {
625           return -1;
626         }
627
628       if (tcp_test_sack_rx (vm, input))
629         {
630           return -1;
631         }
632     }
633   else
634     {
635       if (unformat (input, "tx"))
636         {
637           res = tcp_test_sack_tx (vm, input);
638         }
639       else if (unformat (input, "rx"))
640         {
641           res = tcp_test_sack_rx (vm, input);
642         }
643     }
644
645   return res;
646 }
647
648 static int
649 tcp_test_lookup (vlib_main_t * vm, unformat_input_t * input)
650 {
651   session_main_t *smm = &session_main;
652   tcp_main_t *tm = &tcp_main;
653   transport_connection_t _tc1, *tc1 = &_tc1, _tc2, *tc2 = &_tc2, *tconn;
654   tcp_connection_t *tc;
655   session_t *s, *s1;
656   u8 cmp = 0, is_filtered = 0;
657   u32 sidx;
658
659   /*
660    * Allocate fake session and connection 1
661    */
662   pool_get (smm->wrk[0].sessions, s);
663   clib_memset (s, 0, sizeof (*s));
664   s->session_index = sidx = s - smm->wrk[0].sessions;
665
666   pool_get (tm->connections[0], tc);
667   clib_memset (tc, 0, sizeof (*tc));
668   tc->connection.c_index = tc - tm->connections[0];
669   tc->connection.s_index = s->session_index;
670   s->connection_index = tc->connection.c_index;
671
672   tc->connection.lcl_ip.ip4.as_u32 = clib_host_to_net_u32 (0x06000101);
673   tc->connection.rmt_ip.ip4.as_u32 = clib_host_to_net_u32 (0x06000103);
674   tc->connection.lcl_port = 35051;
675   tc->connection.rmt_port = 53764;
676   tc->connection.proto = TRANSPORT_PROTO_TCP;
677   tc->connection.is_ip4 = 1;
678   clib_memcpy_fast (tc1, &tc->connection, sizeof (*tc1));
679
680   /*
681    * Allocate fake session and connection 2
682    */
683   pool_get (smm->wrk[0].sessions, s);
684   clib_memset (s, 0, sizeof (*s));
685   s->session_index = s - smm->wrk[0].sessions;
686
687   pool_get (tm->connections[0], tc);
688   clib_memset (tc, 0, sizeof (*tc));
689   tc->connection.c_index = tc - tm->connections[0];
690   tc->connection.s_index = s->session_index;
691   s->connection_index = tc->connection.c_index;
692
693   tc->connection.lcl_ip.ip4.as_u32 = clib_host_to_net_u32 (0x06000101);
694   tc->connection.rmt_ip.ip4.as_u32 = clib_host_to_net_u32 (0x06000102);
695   tc->connection.lcl_port = 38225;
696   tc->connection.rmt_port = 53764;
697   tc->connection.proto = TRANSPORT_PROTO_TCP;
698   tc->connection.is_ip4 = 1;
699   clib_memcpy_fast (tc2, &tc->connection, sizeof (*tc2));
700
701   /*
702    * Confirm that connection lookup works
703    */
704
705   s1 = pool_elt_at_index (smm->wrk[0].sessions, sidx);
706   session_lookup_add_connection (tc1, session_handle (s1));
707   tconn = session_lookup_connection_wt4 (0, &tc1->lcl_ip.ip4,
708                                          &tc1->rmt_ip.ip4,
709                                          tc1->lcl_port, tc1->rmt_port,
710                                          tc1->proto, 0, &is_filtered);
711
712   TCP_TEST ((tconn != 0), "connection exists");
713   cmp = (memcmp (&tconn->rmt_ip, &tc1->rmt_ip, sizeof (tc1->rmt_ip)) == 0);
714   TCP_TEST ((cmp), "rmt ip is identical %d", cmp);
715   TCP_TEST ((tconn->lcl_port == tc1->lcl_port),
716             "rmt port is identical %d", tconn->lcl_port == tc1->lcl_port);
717
718   /*
719    * Non-existing connection lookup should not work
720    */
721
722   tconn = session_lookup_connection_wt4 (0, &tc2->lcl_ip.ip4,
723                                          &tc2->rmt_ip.ip4,
724                                          tc2->lcl_port, tc2->rmt_port,
725                                          tc2->proto, 0, &is_filtered);
726   TCP_TEST ((tconn == 0), "lookup result should be null");
727
728   /*
729    * Delete and lookup again
730    */
731   session_lookup_del_connection (tc1);
732   tconn = session_lookup_connection_wt4 (0, &tc1->lcl_ip.ip4,
733                                          &tc1->rmt_ip.ip4,
734                                          tc1->lcl_port, tc1->rmt_port,
735                                          tc1->proto, 0, &is_filtered);
736   TCP_TEST ((tconn == 0), "lookup result should be null");
737   tconn = session_lookup_connection_wt4 (0, &tc2->lcl_ip.ip4,
738                                          &tc2->rmt_ip.ip4,
739                                          tc2->lcl_port, tc2->rmt_port,
740                                          tc2->proto, 0, &is_filtered);
741   TCP_TEST ((tconn == 0), "lookup result should be null");
742
743   /*
744    * Re-add and lookup tc2
745    */
746   session_lookup_add_connection (tc1, tc1->s_index);
747   tconn = session_lookup_connection_wt4 (0, &tc2->lcl_ip.ip4,
748                                          &tc2->rmt_ip.ip4,
749                                          tc2->lcl_port, tc2->rmt_port,
750                                          tc2->proto, 0, &is_filtered);
751   TCP_TEST ((tconn == 0), "lookup result should be null");
752
753   return 0;
754 }
755
756 static int
757 tcp_test_session (vlib_main_t * vm, unformat_input_t * input)
758 {
759   int rv = 0;
760   tcp_connection_t *tc0;
761   ip4_address_t local, remote;
762   u16 local_port, remote_port;
763   tcp_main_t *tm = vnet_get_tcp_main ();
764   int is_add = 1;
765
766
767   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
768     {
769       if (unformat (input, "del"))
770         is_add = 0;
771       else if (unformat (input, "add"))
772         is_add = 1;
773       else
774         break;
775     }
776
777   if (is_add)
778     {
779       local.as_u32 = clib_host_to_net_u32 (0x06000101);
780       remote.as_u32 = clib_host_to_net_u32 (0x06000102);
781       local_port = clib_host_to_net_u16 (1234);
782       remote_port = clib_host_to_net_u16 (11234);
783
784       pool_get (tm->connections[0], tc0);
785       clib_memset (tc0, 0, sizeof (*tc0));
786
787       tc0->state = TCP_STATE_ESTABLISHED;
788       tc0->rcv_las = 1;
789       tc0->c_c_index = tc0 - tm->connections[0];
790       tc0->c_lcl_port = local_port;
791       tc0->c_rmt_port = remote_port;
792       tc0->c_is_ip4 = 1;
793       tc0->c_thread_index = 0;
794       tc0->c_lcl_ip4.as_u32 = local.as_u32;
795       tc0->c_rmt_ip4.as_u32 = remote.as_u32;
796       tc0->rcv_opts.mss = 1450;
797       tcp_connection_init_vars (tc0);
798
799       TCP_EVT (TCP_EVT_OPEN, tc0);
800
801       if (session_stream_accept (&tc0->connection, 0 /* listener index */ ,
802                                  0 /* thread index */ , 0 /* notify */ ))
803         clib_warning ("stream_session_accept failed");
804
805       session_stream_accept_notify (&tc0->connection);
806     }
807   else
808     {
809       tc0 = tcp_connection_get (0 /* connection index */ , 0 /* thread */ );
810       tc0->state = TCP_STATE_CLOSED;
811       session_transport_closing_notify (&tc0->connection);
812     }
813
814   return rv;
815 }
816
817 static inline int
818 tbt_seq_lt (u32 a, u32 b)
819 {
820   return seq_lt (a, b);
821 }
822
823 static int
824 tcp_test_delivery (vlib_main_t * vm, unformat_input_t * input)
825 {
826   u32 thread_index = 0, snd_una, *min_seqs = 0;
827   tcp_rate_sample_t _rs = { 0 }, *rs = &_rs;
828   tcp_connection_t _tc, *tc = &_tc;
829   sack_scoreboard_t *sb = &tc->sack_sb;
830   int __clib_unused verbose = 0, i;
831   u64 rate = 1000, burst = 100;
832   sack_block_t *sacks = 0;
833   tcp_byte_tracker_t *bt;
834   rb_node_t *root, *rbn;
835   tcp_bt_sample_t *bts;
836
837   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
838     {
839       if (unformat (input, "verbose"))
840         verbose = 1;
841       else
842         {
843           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
844                            input);
845           return -1;
846         }
847     }
848
849   /* Init data structures */
850   memset (tc, 0, sizeof (*tc));
851   session_main.wrk[thread_index].last_vlib_time = 1;
852   transport_connection_tx_pacer_update (&tc->connection, rate);
853
854   tcp_bt_init (tc);
855   bt = tc->bt;
856
857   /*
858    * Track simple bursts without rxt
859    */
860
861   /* 1) track first burst a time 1 */
862   tcp_bt_track_tx (tc);
863
864   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
865   TCP_TEST (pool_elts (bt->samples) == 1, "should have 1 sample");
866   bts = pool_elt_at_index (bt->samples, bt->head);
867   TCP_TEST (bts->min_seq == tc->snd_una, "min seq should be snd_una");
868   TCP_TEST (bts->next == TCP_BTS_INVALID_INDEX, "next should be invalid");
869   TCP_TEST (bts->prev == TCP_BTS_INVALID_INDEX, "prev should be invalid");
870   TCP_TEST (bts->delivered_time == 1, "delivered time should be 1");
871   TCP_TEST (bts->delivered == 0, "delivered should be 0");
872   TCP_TEST (!(bts->flags & TCP_BTS_IS_RXT), "not retransmitted");
873   TCP_TEST (!(bts->flags & TCP_BTS_IS_APP_LIMITED), "not app limited");
874
875   /* 2) check delivery rate at time 2 */
876   session_main.wrk[thread_index].last_vlib_time = 2;
877   tc->snd_una = tc->snd_nxt = burst;
878   tc->bytes_acked = burst;
879
880   tcp_bt_sample_delivery_rate (tc, rs);
881
882   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
883   TCP_TEST (pool_elts (bt->samples) == 0, "sample should've been consumed");
884   TCP_TEST (tc->delivered_time == 2, "delivered time should be 2");
885   TCP_TEST (tc->delivered == burst, "delivered should be 100");
886   TCP_TEST (rs->interval_time == 1, "ack time should be 1");
887   TCP_TEST (rs->delivered == burst, "delivered should be 100");
888   TCP_TEST (rs->prior_delivered == 0, "sample delivered should be 0");
889   TCP_TEST (!(rs->flags & TCP_BTS_IS_RXT), "not retransmitted");
890   TCP_TEST (tc->first_tx_time == 1, "first_tx_time %u", tc->first_tx_time);
891
892   /* 3) track second burst at time 2 */
893   tcp_bt_track_tx (tc);
894   tc->snd_nxt += burst;
895
896   /* 4) track second burst at time 3 */
897   session_main.wrk[thread_index].last_vlib_time = 3;
898   tcp_bt_track_tx (tc);
899   tc->snd_nxt += burst;
900
901   TCP_TEST (pool_elts (bt->samples) == 2, "should have 2 samples");
902
903   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
904   bts = pool_elt_at_index (bt->samples, bt->head);
905   TCP_TEST (bts->min_seq == tc->snd_una, "min seq should be snd_una");
906   TCP_TEST (bts->next == bt->tail, "next should tail");
907
908   bts = pool_elt_at_index (bt->samples, bt->tail);
909   TCP_TEST (bts->min_seq == tc->snd_nxt - burst,
910             "min seq should be snd_nxt prior to burst");
911   TCP_TEST (bts->prev == bt->head, "prev should be head");
912
913   /* 5) check delivery rate at time 4 */
914   session_main.wrk[thread_index].last_vlib_time = 4;
915   tc->snd_una = tc->snd_nxt;
916   tc->bytes_acked = 2 * burst;
917
918   tcp_bt_sample_delivery_rate (tc, rs);
919
920   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
921   TCP_TEST (pool_elts (bt->samples) == 0, "sample should've been consumed");
922   TCP_TEST (tc->delivered_time == 4, "delivered time should be 4");
923   TCP_TEST (tc->delivered == 3 * burst, "delivered should be 300 is %u",
924             tc->delivered);
925   TCP_TEST (rs->interval_time == 2, "ack time should be 2");
926   TCP_TEST (rs->delivered == 2 * burst, "delivered should be 200");
927   TCP_TEST (rs->prior_delivered == burst, "delivered should be 100");
928   TCP_TEST (!(rs->flags & TCP_BTS_IS_RXT), "not retransmitted");
929   TCP_TEST (!(bts->flags & TCP_BTS_IS_APP_LIMITED), "not app limited");
930   TCP_TEST (tc->first_tx_time == 2, "first_tx_time %u", tc->first_tx_time);
931
932   /*
933    * Track retransmissions
934    *
935    * snd_una should be 300 at this point
936    */
937
938   snd_una = tc->snd_una;
939
940   /* 1) track first burst at time 4 */
941   tcp_bt_track_tx (tc);
942   tc->snd_nxt += burst;
943
944   /* 2) track second burst at time 5 */
945   session_main.wrk[thread_index].last_vlib_time = 5;
946   tcp_bt_track_tx (tc);
947   tc->snd_nxt += burst;
948
949   /* 3) track third burst at time 6 */
950   session_main.wrk[thread_index].last_vlib_time = 6;
951   tcp_bt_track_tx (tc);
952   tc->snd_nxt += burst;
953
954   /* 4) track fourth burst at time 7 */
955   session_main.wrk[thread_index].last_vlib_time = 7;
956   /* Limited until last burst is acked */
957   tc->app_limited = snd_una + 4 * burst - 1;
958   tcp_bt_track_tx (tc);
959   tc->snd_nxt += burst;
960
961   /* 5) check delivery rate at time 8
962    *
963    * tc->snd_una = snd_una + 10
964    * sacks:
965    * [snd_una + burst, snd_una + burst + 10]
966    * [snd_una + 2 * burst + 10, snd_una + 2 * burst + 20]
967    */
968   session_main.wrk[thread_index].last_vlib_time = 8;
969   tc->snd_una += 10;
970   tc->bytes_acked = 10;
971   sb->last_sacked_bytes = 20;
972
973   TCP_TEST (pool_elts (bt->samples) == 4, "there should be 4 samples");
974
975   vec_validate (sacks, 1);
976   sacks[0].start = snd_una + burst;
977   sacks[0].end = snd_una + burst + 10;
978   sacks[1].start = snd_una + 2 * burst + 10;
979   sacks[1].end = snd_una + 2 * burst + 20;
980   tc->rcv_opts.sacks = sacks;
981
982   tcp_bt_sample_delivery_rate (tc, rs);
983
984   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
985   TCP_TEST (pool_elts (bt->samples) == 4, "there should be 4 samples");
986   TCP_TEST (tc->delivered_time == 8, "delivered time should be 8");
987   TCP_TEST (tc->delivered == 3 * burst + 30, "delivered should be %u is %u",
988             3 * burst + 30, tc->delivered);
989   /* All 3 samples have the same delivered number of bytes. So the first is
990    * the reference for delivery estimate. */
991   TCP_TEST (rs->interval_time == 4, "ack time should be 4 is %.2f",
992             rs->interval_time);
993   TCP_TEST (rs->delivered == 30, "delivered should be 30");
994   TCP_TEST (rs->prior_delivered == 3 * burst,
995             "sample delivered should be %u", 3 * burst);
996   TCP_TEST (!(rs->flags & TCP_BTS_IS_RXT), "not retransmitted");
997   TCP_TEST (!(rs->flags & TCP_BTS_IS_APP_LIMITED), "not app limited");
998   /* All 3 samples have the same delivered number of bytes. The first
999    * sets the first tx time */
1000   TCP_TEST (tc->first_tx_time == 4, "first_tx_time %u", tc->first_tx_time);
1001
1002   /* 6) Retransmit and track at time 9
1003    *
1004    * delivered = 3 * burst + 30
1005    * delivered_time = 8 (last ack)
1006    *
1007    * segments:
1008    * [snd_una + 10, snd_una + burst]
1009    * [snd_una + burst + 10, snd_una + 2 * burst + 10]
1010    * [snd_una + 2 * burst + 20, snd_una + 4 * burst]
1011    */
1012   session_main.wrk[thread_index].last_vlib_time = 9;
1013
1014   tcp_bt_track_rxt (tc, snd_una + 10, snd_una + burst);
1015   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
1016   /* The retransmit covers everything left from first burst */
1017   TCP_TEST (pool_elts (bt->samples) == 4, "there should be 4 samples");
1018
1019   tcp_bt_track_rxt (tc, snd_una + burst + 10, snd_una + 2 * burst + 10);
1020   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
1021   TCP_TEST (pool_elts (bt->samples) == 5, "there should be 5 samples");
1022
1023   /* Retransmit covers last sample entirely so it should be removed */
1024   tcp_bt_track_rxt (tc, snd_una + 2 * burst + 20, snd_una + 4 * burst);
1025   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
1026   TCP_TEST (pool_elts (bt->samples) == 5, "there should be 5 samples");
1027
1028   vec_validate (min_seqs, 4);
1029   min_seqs[0] = snd_una + 10;
1030   min_seqs[1] = snd_una + burst;
1031   min_seqs[2] = snd_una + burst + 10;
1032   min_seqs[3] = snd_una + 2 * burst + 10;
1033   min_seqs[4] = snd_una + 2 * burst + 20;
1034
1035   root = bt->sample_lookup.nodes + bt->sample_lookup.root;
1036   bts = bt->samples + bt->head;
1037   for (i = 0; i < vec_len (min_seqs); i++)
1038     {
1039       if (bts->min_seq != min_seqs[i])
1040         TCP_TEST (0, "should be %u is %u", min_seqs[i], bts->min_seq);
1041       rbn = rb_tree_search_subtree_custom (&bt->sample_lookup, root,
1042                                            bts->min_seq, tbt_seq_lt);
1043       if (rbn->opaque != bts - bt->samples)
1044         TCP_TEST (0, "lookup should work");
1045       bts = bt->samples + bts->next;
1046     }
1047
1048   /* 7) check delivery rate at time 10
1049    *
1050    * tc->snd_una = snd_una + 2 * burst
1051    * sacks:
1052    * [snd_una + 2 * burst + 20, snd_una + 2 * burst + 30]
1053    * [snd_una + 2 * burst + 50, snd_una + 2 * burst + 60]
1054    */
1055   session_main.wrk[thread_index].last_vlib_time = 10;
1056   tc->snd_una = snd_una + 2 * burst;
1057   tc->bytes_acked = 2 * burst - 10;
1058   sb->last_sacked_bytes = 20;
1059
1060   sacks[0].start = snd_una + 2 * burst + 20;
1061   sacks[0].end = snd_una + 2 * burst + 30;
1062   sacks[1].start = snd_una + 2 * burst + 50;
1063   sacks[1].end = snd_una + 2 * burst + 60;
1064
1065   tcp_bt_sample_delivery_rate (tc, rs);
1066
1067   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
1068   TCP_TEST (pool_elts (bt->samples) == 3, "num samples should be 3 is %u",
1069             pool_elts (bt->samples));
1070   TCP_TEST (tc->delivered_time == 10, "delivered time should be 10");
1071   TCP_TEST (tc->delivered == 5 * burst + 40, "delivered should be %u is %u",
1072             5 * burst + 40, tc->delivered);
1073   /* A rxt was acked and delivered time for it is 8 (last ack time) so
1074    * ack_time is 2 (8 - 10). However, first_tx_time for rxt was 4 and rxt
1075    * time 9. Therefore snd_time is 5 (9 - 4)*/
1076   TCP_TEST (rs->interval_time == 5, "ack time should be 5 is %.2f",
1077             rs->interval_time);
1078   /* delivered_now - delivered_rxt ~ 5 * burst + 40 - 3 * burst - 30 */
1079   TCP_TEST (rs->delivered == 2 * burst + 10, "delivered should be 210 is %u",
1080             rs->delivered);
1081   TCP_TEST (rs->prior_delivered == 3 * burst + 30,
1082             "sample delivered should be %u", 3 * burst + 30);
1083   TCP_TEST (rs->flags & TCP_BTS_IS_RXT, "is retransmitted");
1084   /* Sample is app limited because of the retransmits */
1085   TCP_TEST (rs->flags & TCP_BTS_IS_APP_LIMITED, "is app limited");
1086   TCP_TEST (tc->app_limited, "app limited should be set");
1087   TCP_TEST (tc->first_tx_time == 9, "first_tx_time %u", tc->first_tx_time);
1088
1089
1090   /*
1091    * 8) check delivery rate at time 11
1092    */
1093   session_main.wrk[thread_index].last_vlib_time = 11;
1094   tc->snd_una = tc->snd_nxt;
1095   tc->bytes_acked = 2 * burst;
1096   sb->last_sacked_bytes = 0;
1097   sb->last_bytes_delivered = 40;
1098
1099   memset (rs, 0, sizeof (*rs));
1100   tcp_bt_sample_delivery_rate (tc, rs);
1101
1102   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
1103   TCP_TEST (pool_elts (bt->samples) == 0, "num samples should be 0 is %u",
1104             pool_elts (bt->samples));
1105   TCP_TEST (tc->delivered_time == 11, "delivered time should be 11");
1106   TCP_TEST (tc->delivered == 7 * burst, "delivered should be %u is %u",
1107             7 * burst, tc->delivered);
1108   /* Delivered time at retransmit was 8 so ack_time is 11 - 8 = 3. However,
1109    * first_tx_time for rxt was 4 and rxt time was 9. Therefore snd_time
1110    * is 9 - 4 = 5 */
1111   TCP_TEST (rs->interval_time == 5, "ack time should be 5 is %.2f",
1112             rs->interval_time);
1113   /* delivered_now - delivered_rxt ~ 7 * burst - 3 * burst - 30.
1114    * That's because we didn't retransmit any new segment. */
1115   TCP_TEST (rs->delivered == 4 * burst - 30, "delivered should be 160 is %u",
1116             rs->delivered);
1117   TCP_TEST (rs->prior_delivered == 3 * burst + 30,
1118             "sample delivered should be %u", 3 * burst + 30);
1119   TCP_TEST (rs->flags & TCP_BTS_IS_RXT, "is retransmitted");
1120   TCP_TEST (rs->flags & TCP_BTS_IS_APP_LIMITED, "is app limited");
1121   TCP_TEST (tc->app_limited == 0, "app limited should be cleared");
1122   TCP_TEST (tc->first_tx_time == 9, "first_tx_time %u", tc->first_tx_time);
1123
1124   /*
1125    * 9) test flush
1126    */
1127
1128   tcp_bt_track_tx (tc);
1129   tc->snd_nxt += burst;
1130
1131   session_main.wrk[thread_index].last_vlib_time = 12;
1132   tcp_bt_track_tx (tc);
1133   tc->snd_nxt += burst;
1134
1135   tcp_bt_flush_samples (tc);
1136
1137   /*
1138    * Cleanup
1139    */
1140   vec_free (sacks);
1141   vec_free (min_seqs);
1142   tcp_bt_cleanup (tc);
1143   return 0;
1144 }
1145
1146 static clib_error_t *
1147 tcp_test (vlib_main_t * vm,
1148           unformat_input_t * input, vlib_cli_command_t * cmd_arg)
1149 {
1150   int res = 0;
1151
1152   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1153     {
1154       if (unformat (input, "sack"))
1155         {
1156           res = tcp_test_sack (vm, input);
1157         }
1158       else if (unformat (input, "session"))
1159         {
1160           res = tcp_test_session (vm, input);
1161         }
1162       else if (unformat (input, "lookup"))
1163         {
1164           res = tcp_test_lookup (vm, input);
1165         }
1166       else if (unformat (input, "delivery"))
1167         {
1168           res = tcp_test_delivery (vm, input);
1169         }
1170       else if (unformat (input, "all"))
1171         {
1172           if ((res = tcp_test_sack (vm, input)))
1173             goto done;
1174           if ((res = tcp_test_lookup (vm, input)))
1175             goto done;
1176           if ((res = tcp_test_delivery (vm, input)))
1177             goto done;
1178         }
1179       else
1180         break;
1181     }
1182
1183 done:
1184   if (res)
1185     return clib_error_return (0, "TCP unit test failed");
1186   return 0;
1187 }
1188
1189 /* *INDENT-OFF* */
1190 VLIB_CLI_COMMAND (tcp_test_command, static) =
1191 {
1192   .path = "test tcp",
1193   .short_help = "internal tcp unit tests",
1194   .function = tcp_test,
1195 };
1196 /* *INDENT-ON* */
1197
1198 /*
1199  * fd.io coding-style-patch-verification: ON
1200  *
1201  * Local Variables:
1202  * eval: (c-set-style "gnu")
1203  * End:
1204  */