LCOV - code coverage report
Current view: top level - plugins/unittest - tcp_test.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 609 863 70.6 %
Date: 2023-07-05 22:20:52 Functions: 10 13 76.9 %

          Line data    Source code
       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             : #include <vnet/tcp/tcp_inlines.h>
      17             : 
      18             : #define TCP_TEST_I(_cond, _comment, _args...)                   \
      19             : ({                                                              \
      20             :   int _evald = (_cond);                                         \
      21             :   if (!(_evald)) {                                              \
      22             :     fformat(stderr, "FAIL:%d: " _comment "\n",                      \
      23             :             __LINE__, ##_args);                                 \
      24             :   } else {                                                      \
      25             :     fformat(stderr, "PASS:%d: " _comment "\n",                      \
      26             :             __LINE__, ##_args);                                 \
      27             :   }                                                             \
      28             :   _evald;                                                       \
      29             : })
      30             : 
      31             : #define TCP_TEST(_cond, _comment, _args...)                     \
      32             : {                                                               \
      33             :     if (!TCP_TEST_I(_cond, _comment, ##_args)) {                \
      34             :         return 1;                                               \
      35             :     }                                                           \
      36             : }
      37             : 
      38             : /* *INDENT-OFF* */
      39             : scoreboard_trace_elt_t sb_trace[] = {};
      40             : /* *INDENT-ON* */
      41             : 
      42             : static int
      43           0 : tcp_test_scoreboard_replay (vlib_main_t * vm, unformat_input_t * input)
      44             : {
      45           0 :   int verbose = 0;
      46           0 :   tcp_connection_t _tc, *tc = &_tc;
      47           0 :   u8 *s = 0;
      48             : 
      49           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
      50             :     {
      51           0 :       if (unformat (input, "detail"))
      52           0 :         verbose = 1;
      53             :       else
      54             :         {
      55           0 :           clib_error_t *e = clib_error_return
      56             :             (0, "unknown input `%U'", format_unformat_error, input);
      57           0 :           clib_error_report (e);
      58           0 :           return -1;
      59             :         }
      60             :     }
      61             : 
      62             : #if TCP_SCOREBOARD_TRACE
      63             :   tc->sack_sb.trace = sb_trace;
      64             : #endif
      65           0 :   s = tcp_scoreboard_replay (s, tc, verbose);
      66           0 :   vlib_cli_output (vm, "%v", s);
      67           0 :   return 0;
      68             : }
      69             : 
      70             : static int
      71           1 : tcp_test_sack_rx (vlib_main_t * vm, unformat_input_t * input)
      72             : {
      73           1 :   tcp_connection_t _tc, *tc = &_tc;
      74           1 :   sack_scoreboard_t *sb = &tc->sack_sb;
      75           1 :   sack_block_t *sacks = 0, block;
      76             :   sack_scoreboard_hole_t *hole;
      77           1 :   int i, verbose = 0;
      78             : 
      79           1 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
      80             :     {
      81           0 :       if (unformat (input, "verbose"))
      82           0 :         verbose = 1;
      83           0 :       else if (unformat (input, "replay"))
      84           0 :         return tcp_test_scoreboard_replay (vm, input);
      85             :     }
      86             : 
      87           1 :   clib_memset (tc, 0, sizeof (*tc));
      88             : 
      89           1 :   tc->flags |= TCP_CONN_FAST_RECOVERY | TCP_CONN_RECOVERY;
      90           1 :   tc->snd_una = 0;
      91           1 :   tc->snd_nxt = 1000;
      92           1 :   tc->rcv_opts.flags |= TCP_OPTS_FLAG_SACK;
      93           1 :   tc->snd_mss = 150;
      94           1 :   scoreboard_init (&tc->sack_sb);
      95             : 
      96          11 :   for (i = 0; i < 1000 / 100; i++)
      97             :     {
      98          10 :       block.start = i * 100;
      99          10 :       block.end = (i + 1) * 100;
     100          10 :       vec_add1 (sacks, block);
     101             :     }
     102             : 
     103             :   /*
     104             :    * Inject even blocks
     105             :    */
     106             : 
     107           6 :   for (i = 0; i < 1000 / 200; i++)
     108             :     {
     109           5 :       vec_add1 (tc->rcv_opts.sacks, sacks[i * 2]);
     110             :     }
     111           1 :   tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
     112           1 :   tcp_rcv_sacks (tc, 0);
     113             : 
     114           1 :   if (verbose)
     115           0 :     vlib_cli_output (vm, "sb after even blocks (mss %u):\n%U",
     116           0 :                      tc->snd_mss, format_tcp_scoreboard, sb, tc);
     117             : 
     118           1 :   TCP_TEST ((pool_elts (sb->holes) == 5),
     119             :             "scoreboard has %d elements", pool_elts (sb->holes));
     120             : 
     121             :   /* First SACK block should be rejected */
     122           1 :   hole = scoreboard_first_hole (sb);
     123           1 :   TCP_TEST ((hole->start == 0 && hole->end == 200),
     124             :             "first hole start %u end %u", hole->start, hole->end);
     125           1 :   hole = scoreboard_last_hole (sb);
     126           1 :   TCP_TEST ((hole->start == 900 && hole->end == 1000),
     127             :             "last hole start %u end %u", hole->start, hole->end);
     128           1 :   TCP_TEST ((sb->sacked_bytes == 400), "sacked bytes %d", sb->sacked_bytes);
     129           1 :   TCP_TEST ((!sb->is_reneging), "is not reneging");
     130           1 :   TCP_TEST ((sb->last_sacked_bytes == 400),
     131             :             "last sacked bytes %d", sb->last_sacked_bytes);
     132           1 :   TCP_TEST ((sb->high_sacked == 900), "high sacked %u", sb->high_sacked);
     133           1 :   TCP_TEST ((sb->lost_bytes == 300), "lost bytes %u", sb->lost_bytes);
     134             : 
     135             :   /*
     136             :    * Inject odd blocks except the last
     137             :    *
     138             :    */
     139             : 
     140           1 :   vec_reset_length (tc->rcv_opts.sacks);
     141           5 :   for (i = 0; i < 800 / 200; i++)
     142             :     {
     143           4 :       vec_add1 (tc->rcv_opts.sacks, sacks[i * 2 + 1]);
     144             :     }
     145           1 :   tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
     146           1 :   tcp_rcv_sacks (tc, 0);
     147             : 
     148           1 :   if (verbose)
     149           0 :     vlib_cli_output (vm, "\nsb after odd blocks:\n%U", format_tcp_scoreboard,
     150             :                      sb, tc);
     151             : 
     152           1 :   hole = scoreboard_first_hole (sb);
     153           1 :   TCP_TEST ((pool_elts (sb->holes) == 2),
     154             :             "scoreboard has %d holes", pool_elts (sb->holes));
     155           1 :   TCP_TEST ((hole->start == 0 && hole->end == 100),
     156             :             "first hole start %u end %u", hole->start, hole->end);
     157           1 :   TCP_TEST ((sb->sacked_bytes == 800), "sacked bytes %d", sb->sacked_bytes);
     158           1 :   TCP_TEST ((!sb->is_reneging), "is not reneging");
     159           1 :   TCP_TEST ((sb->high_sacked == 900), "high sacked %u", sb->high_sacked);
     160           1 :   TCP_TEST ((sb->last_sacked_bytes == 400),
     161             :             "last sacked bytes %d", sb->last_sacked_bytes);
     162           1 :   TCP_TEST ((sb->lost_bytes == 100), "lost bytes %u", sb->lost_bytes);
     163             : 
     164             :   /*
     165             :    *  Ack until byte 100 - this is reneging because we should ack until 900
     166             :    */
     167           1 :   tcp_rcv_sacks (tc, 100);
     168           1 :   if (verbose)
     169           0 :     vlib_cli_output (vm, "\nack until byte 100:\n%U", format_tcp_scoreboard,
     170             :                      sb, tc);
     171             : 
     172           1 :   TCP_TEST ((pool_elts (sb->holes) == 1), "scoreboard has %d elements",
     173             :             pool_elts (sb->holes));
     174           1 :   TCP_TEST ((sb->is_reneging), "is reneging");
     175             : 
     176             :   /*
     177             :    * Make sure we accept duplicate acks while reneging.
     178             :    */
     179           1 :   tc->snd_una = 100;
     180           1 :   sb->high_rxt = 950;
     181             : 
     182           1 :   block.start = 900;
     183           1 :   block.end = 950;
     184           1 :   vec_add1 (tc->rcv_opts.sacks, block);
     185             : 
     186           1 :   tcp_rcv_sacks (tc, 100);
     187           1 :   TCP_TEST ((pool_elts (sb->holes) == 1), "scoreboard has %d elements",
     188             :             pool_elts (sb->holes));
     189           1 :   TCP_TEST ((sb->is_reneging), "is reneging");
     190           1 :   TCP_TEST ((sb->last_sacked_bytes == 50), "last sacked bytes %d",
     191             :             sb->last_sacked_bytes);
     192           1 :   TCP_TEST ((sb->rxt_sacked == 50), "last rxt sacked bytes %d",
     193             :             sb->rxt_sacked);
     194             : 
     195             :   /*
     196             :    * Sack all up to 950
     197             :    */
     198           1 :   tcp_rcv_sacks (tc, 950);
     199           1 :   TCP_TEST ((sb->high_sacked == 950), "max sacked byte %u", sb->high_sacked);
     200           1 :   TCP_TEST ((sb->sacked_bytes == 0), "sacked bytes %d", sb->sacked_bytes);
     201           1 :   TCP_TEST ((sb->last_sacked_bytes == 0),
     202             :             "last sacked bytes %d", sb->last_sacked_bytes);
     203           1 :   TCP_TEST ((sb->lost_bytes == 0), "lost bytes %u", sb->lost_bytes);
     204           1 :   TCP_TEST ((!sb->is_reneging), "is not reneging");
     205             : 
     206             :   /*
     207             :    * Sack [960 970] [980 990]
     208             :    */
     209           1 :   sb->high_rxt = 985;
     210             : 
     211           1 :   tc->snd_una = 950;
     212           1 :   vec_reset_length (tc->rcv_opts.sacks);
     213           1 :   block.start = 960;
     214           1 :   block.end = 970;
     215           1 :   vec_add1 (tc->rcv_opts.sacks, block);
     216             : 
     217           1 :   block.start = 980;
     218           1 :   block.end = 990;
     219           1 :   vec_add1 (tc->rcv_opts.sacks, block);
     220             : 
     221           1 :   tcp_rcv_sacks (tc, 950);
     222           1 :   TCP_TEST ((sb->high_sacked == 990), "max sacked byte %u", sb->high_sacked);
     223           1 :   TCP_TEST ((sb->sacked_bytes == 20), "sacked bytes %d", sb->sacked_bytes);
     224           1 :   TCP_TEST ((sb->last_sacked_bytes == 20),
     225             :             "last sacked bytes %d", sb->last_sacked_bytes);
     226           1 :   TCP_TEST ((sb->lost_bytes == 0), "lost bytes %u", sb->lost_bytes);
     227           1 :   TCP_TEST ((!sb->is_reneging), "is not reneging");
     228           1 :   TCP_TEST ((sb->rxt_sacked == 15), "last rxt sacked bytes %d",
     229             :             sb->rxt_sacked);
     230             : 
     231             :   /*
     232             :    * Ack up to 960 (reneging) + [961 971]
     233             :    */
     234           1 :   tc->rcv_opts.sacks[0].start = 961;
     235           1 :   tc->rcv_opts.sacks[0].end = 971;
     236             : 
     237           1 :   tcp_rcv_sacks (tc, 960);
     238             : 
     239           1 :   TCP_TEST ((sb->is_reneging), "is reneging");
     240           1 :   TCP_TEST ((sb->sacked_bytes == 21), "sacked bytes %d", sb->sacked_bytes);
     241           1 :   TCP_TEST ((sb->last_sacked_bytes == 1),
     242             :             "last sacked bytes %d", sb->last_sacked_bytes);
     243           1 :   TCP_TEST ((sb->rxt_sacked == 11), "last rxt sacked bytes %d",
     244             :             sb->rxt_sacked);
     245           1 :   TCP_TEST ((sb->last_bytes_delivered == 0), "last bytes delivered %d",
     246             :             sb->last_bytes_delivered);
     247             : 
     248             :   /*
     249             :    * Ack up to 960 (reneging) + [961 990]
     250             :    */
     251           1 :   tc->snd_una = 960;
     252           1 :   tc->rcv_opts.sacks[0].start = 961;
     253           1 :   tc->rcv_opts.sacks[0].end = 990;
     254             : 
     255           1 :   tcp_rcv_sacks (tc, 960);
     256             : 
     257           1 :   TCP_TEST ((sb->is_reneging), "is reneging");
     258           1 :   TCP_TEST ((sb->sacked_bytes == 30), "sacked bytes %d", sb->sacked_bytes);
     259           1 :   TCP_TEST ((sb->last_sacked_bytes == 9),
     260             :             "last sacked bytes %d", sb->last_sacked_bytes);
     261           1 :   TCP_TEST ((sb->rxt_sacked == 9), "last rxt sacked bytes %d",
     262             :             sb->rxt_sacked);
     263             : 
     264             :   /*
     265             :    * Sack remaining bytes [990 1000]
     266             :    */
     267           1 :   tc->rcv_opts.sacks[0].start = 990;
     268           1 :   tc->rcv_opts.sacks[0].end = 1000;
     269             : 
     270           1 :   tcp_rcv_sacks (tc, 960);
     271             : 
     272           1 :   TCP_TEST ((sb->is_reneging), "is reneging");
     273           1 :   TCP_TEST ((sb->sacked_bytes == 40), "sacked bytes %d", sb->sacked_bytes);
     274           1 :   TCP_TEST ((sb->last_sacked_bytes == 10),
     275             :             "last sacked bytes %d", sb->last_sacked_bytes);
     276           1 :   TCP_TEST ((sb->rxt_sacked == 0), "last rxt sacked bytes %d",
     277             :             sb->rxt_sacked);
     278           1 :   TCP_TEST (pool_elts (sb->holes) == 0, "no holes left");
     279             : 
     280             :   /*
     281             :    * Ack up to 970 no sack blocks
     282             :    */
     283           1 :   vec_reset_length (tc->rcv_opts.sacks);
     284           1 :   tc->rcv_opts.flags &= ~TCP_OPTS_FLAG_SACK;
     285           1 :   tcp_rcv_sacks (tc, 970);
     286             : 
     287           1 :   TCP_TEST ((sb->is_reneging), "is reneging");
     288           1 :   TCP_TEST ((sb->sacked_bytes == 30), "sacked bytes %d", sb->sacked_bytes);
     289           1 :   TCP_TEST ((sb->last_sacked_bytes == 0),
     290             :             "last sacked bytes %d", sb->last_sacked_bytes);
     291           1 :   TCP_TEST ((sb->rxt_sacked == 0), "last rxt sacked bytes %d",
     292             :             sb->rxt_sacked);
     293             : 
     294             :   /*
     295             :    * Ack all up to 1000
     296             :    */
     297           1 :   tc->snd_una = 970;
     298           1 :   tcp_rcv_sacks (tc, 1000);
     299           1 :   TCP_TEST ((sb->high_sacked == 1000), "max sacked byte %u", sb->high_sacked);
     300           1 :   TCP_TEST ((sb->sacked_bytes == 0), "sacked bytes %d", sb->sacked_bytes);
     301           1 :   TCP_TEST (sb->last_bytes_delivered == 30, "last bytes delivered %d",
     302             :             sb->last_bytes_delivered);
     303           1 :   TCP_TEST ((sb->last_sacked_bytes == 0),
     304             :             "last sacked bytes %d", sb->last_sacked_bytes);
     305           1 :   TCP_TEST ((sb->lost_bytes == 0), "lost bytes %u", sb->lost_bytes);
     306           1 :   TCP_TEST ((!sb->is_reneging), "is not reneging");
     307             : 
     308             :   /*
     309             :    * Add new block
     310             :    */
     311           1 :   tc->flags = 0;
     312           1 :   tc->rcv_opts.flags |= TCP_OPTS_FLAG_SACK;
     313           1 :   vec_reset_length (tc->rcv_opts.sacks);
     314             : 
     315           1 :   block.start = 1200;
     316           1 :   block.end = 1300;
     317           1 :   vec_add1 (tc->rcv_opts.sacks, block);
     318             : 
     319           1 :   tc->snd_una = 1000;
     320           1 :   tc->snd_nxt = 1500;
     321           1 :   tcp_rcv_sacks (tc, 1000);
     322             : 
     323           1 :   if (verbose)
     324           0 :     vlib_cli_output (vm, "\nadd [1200, 1300] snd_una_max 1500, snd_una 1000:"
     325             :                      " \n%U", format_tcp_scoreboard, sb, tc);
     326             : 
     327           1 :   TCP_TEST ((!sb->is_reneging), "is not reneging");
     328           1 :   TCP_TEST ((pool_elts (sb->holes) == 2),
     329             :             "scoreboard has %d holes", pool_elts (sb->holes));
     330           1 :   hole = scoreboard_first_hole (sb);
     331           1 :   TCP_TEST ((hole->start == 1000 && hole->end == 1200),
     332             :             "first hole start %u end %u", hole->start, hole->end);
     333           1 :   TCP_TEST ((sb->high_sacked == 1300), "max sacked byte %u", sb->high_sacked);
     334           1 :   hole = scoreboard_last_hole (sb);
     335           1 :   TCP_TEST ((hole->start == 1300 && hole->end == 1500),
     336             :             "last hole start %u end %u", hole->start, hole->end);
     337           1 :   TCP_TEST ((sb->sacked_bytes == 100), "sacked bytes %d", sb->sacked_bytes);
     338           1 :   TCP_TEST ((sb->lost_bytes == 0), "lost bytes %u", sb->lost_bytes);
     339             : 
     340             :   /*
     341             :    * Ack first hole
     342             :    */
     343             : 
     344           1 :   vec_reset_length (tc->rcv_opts.sacks);
     345             :   /* Ack up to 1300 to avoid reneging */
     346           1 :   tcp_rcv_sacks (tc, 1300);
     347             : 
     348           1 :   if (verbose)
     349           0 :     vlib_cli_output (vm, "\nsb ack up to byte 1300:\n%U",
     350             :                      format_tcp_scoreboard, sb, tc);
     351             : 
     352           1 :   TCP_TEST ((sb->sacked_bytes == 0), "sacked bytes %d", sb->sacked_bytes);
     353           1 :   TCP_TEST ((pool_elts (sb->holes) == 1),
     354             :             "scoreboard has %d elements", pool_elts (sb->holes));
     355           1 :   TCP_TEST ((sb->last_bytes_delivered == 100), "last bytes delivered %d",
     356             :             sb->last_bytes_delivered);
     357           1 :   TCP_TEST ((sb->lost_bytes == 0), "lost bytes %u", sb->lost_bytes);
     358           1 :   TCP_TEST ((sb->head != TCP_INVALID_SACK_HOLE_INDEX), "head %u", sb->head);
     359           1 :   TCP_TEST ((sb->tail != TCP_INVALID_SACK_HOLE_INDEX), "tail %u", sb->tail);
     360           1 :   TCP_TEST ((!sb->is_reneging), "is not reneging");
     361             : 
     362             :   /*
     363             :    * Add some more blocks and then remove all
     364             :    */
     365           1 :   vec_reset_length (tc->rcv_opts.sacks);
     366           1 :   tc->snd_una = 1300;
     367           1 :   tc->snd_nxt = 1900;
     368           6 :   for (i = 0; i < 5; i++)
     369             :     {
     370           5 :       block.start = i * 100 + 1200;
     371           5 :       block.end = (i + 1) * 100 + 1200;
     372           5 :       vec_add1 (tc->rcv_opts.sacks, block);
     373             :     }
     374           1 :   tcp_rcv_sacks (tc, 1900);
     375             : 
     376           1 :   scoreboard_clear (sb);
     377           1 :   if (verbose)
     378           0 :     vlib_cli_output (vm, "\nsb cleared all:\n%U", format_tcp_scoreboard, sb,
     379             :                      tc);
     380             : 
     381           1 :   TCP_TEST ((pool_elts (sb->holes) == 0),
     382             :             "number of holes %d", pool_elts (sb->holes));
     383           1 :   TCP_TEST ((sb->head == TCP_INVALID_SACK_HOLE_INDEX), "head %u", sb->head);
     384           1 :   TCP_TEST ((sb->tail == TCP_INVALID_SACK_HOLE_INDEX), "tail %u", sb->tail);
     385             : 
     386             :   /*
     387             :    * Re-inject odd blocks and ack them all
     388             :    */
     389             : 
     390           1 :   tc->snd_una = 0;
     391           1 :   tc->snd_nxt = 1000;
     392           1 :   vec_reset_length (tc->rcv_opts.sacks);
     393           6 :   for (i = 0; i < 5; i++)
     394             :     {
     395           5 :       vec_add1 (tc->rcv_opts.sacks, sacks[i * 2 + 1]);
     396             :     }
     397           1 :   tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
     398           1 :   tcp_rcv_sacks (tc, 0);
     399           1 :   if (verbose)
     400           0 :     vlib_cli_output (vm, "\nsb added odd blocks snd_una 0 snd_una_max 1000:"
     401             :                      "\n%U", format_tcp_scoreboard, sb, tc);
     402           1 :   TCP_TEST ((pool_elts (sb->holes) == 5),
     403             :             "scoreboard has %d elements", pool_elts (sb->holes));
     404           1 :   TCP_TEST ((sb->lost_bytes == 300), "lost bytes %u", sb->lost_bytes);
     405           1 :   hole = scoreboard_last_hole (sb);
     406           1 :   TCP_TEST ((hole->end == 900), "last hole end %u", hole->end);
     407           1 :   TCP_TEST ((sb->high_sacked == 1000), "high sacked %u", sb->high_sacked);
     408             : 
     409             :   /*
     410             :    * Renege bytes from 950 to 1000
     411             :    */
     412           1 :   tcp_rcv_sacks (tc, 950);
     413             : 
     414           1 :   if (verbose)
     415           0 :     vlib_cli_output (vm, "\nack [0, 950]:\n%U", format_tcp_scoreboard, sb,
     416             :                      tc);
     417             : 
     418           1 :   TCP_TEST ((pool_elts (sb->holes) == 0), "scoreboard has %d elements",
     419             :             pool_elts (sb->holes));
     420           1 :   TCP_TEST ((sb->is_reneging), "is reneging");
     421           1 :   TCP_TEST ((sb->sacked_bytes == 50), "sacked bytes %d", sb->sacked_bytes);
     422           1 :   TCP_TEST ((sb->last_sacked_bytes == 0), "last sacked bytes %d",
     423             :             sb->last_sacked_bytes);
     424           1 :   TCP_TEST ((sb->lost_bytes == 0), "lost bytes %u", sb->lost_bytes);
     425           1 :   TCP_TEST ((sb->high_sacked == 1000), "high sacked %u", sb->high_sacked);
     426             : 
     427           1 :   scoreboard_clear (sb);
     428             : 
     429             :   /*
     430             :    * Inject one block, ack it and overlap hole
     431             :    */
     432             : 
     433           1 :   tc->snd_una = 0;
     434           1 :   tc->snd_nxt = 1000;
     435             : 
     436           1 :   block.start = 100;
     437           1 :   block.end = 500;
     438           1 :   vec_add1 (tc->rcv_opts.sacks, block);
     439           1 :   tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
     440             : 
     441           1 :   tcp_rcv_sacks (tc, 0);
     442             : 
     443           1 :   if (verbose)
     444           0 :     vlib_cli_output (vm, "\nsb added [100, 500] snd_una 0 snd_una_max 1000:"
     445             :                      "\n%U", format_tcp_scoreboard, sb, tc);
     446             : 
     447           1 :   tcp_rcv_sacks (tc, 800);
     448             : 
     449           1 :   if (verbose)
     450           0 :     vlib_cli_output (vm, "\nsb ack [0, 800]:\n%U", format_tcp_scoreboard, sb,
     451             :                      tc);
     452             : 
     453           1 :   TCP_TEST ((pool_elts (sb->holes) == 1),
     454             :             "scoreboard has %d elements", pool_elts (sb->holes));
     455           1 :   TCP_TEST ((!sb->is_reneging), "is not reneging");
     456           1 :   TCP_TEST ((sb->sacked_bytes == 0), "sacked bytes %d", sb->sacked_bytes);
     457           1 :   TCP_TEST ((sb->last_sacked_bytes == 0), "last sacked bytes %d",
     458             :             sb->last_sacked_bytes);
     459           1 :   TCP_TEST ((sb->last_bytes_delivered == 400),
     460             :             "last bytes delivered %d", sb->last_bytes_delivered);
     461           1 :   TCP_TEST ((sb->lost_bytes == 0), "lost bytes %u", sb->lost_bytes);
     462           1 :   TCP_TEST ((sb->head != TCP_INVALID_SACK_HOLE_INDEX), "head %u", sb->head);
     463           1 :   TCP_TEST ((sb->tail != TCP_INVALID_SACK_HOLE_INDEX), "tail %u", sb->tail);
     464             : 
     465             :   /*
     466             :    * One hole close to head, patch head, split in two and start acking
     467             :    * the lowest part
     468             :    */
     469           1 :   scoreboard_clear (sb);
     470           1 :   tc->snd_una = 0;
     471           1 :   tc->snd_nxt = 1000;
     472             : 
     473           1 :   block.start = 500;
     474           1 :   block.end = 1000;
     475           1 :   vec_add1 (tc->rcv_opts.sacks, block);
     476           1 :   tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
     477             : 
     478           1 :   tcp_rcv_sacks (tc, 0);
     479           1 :   if (verbose)
     480           0 :     vlib_cli_output (vm, "\nsb added [500, 1000]:\n%U",
     481             :                      format_tcp_scoreboard, sb, tc);
     482           1 :   TCP_TEST ((sb->sacked_bytes == 500), "sacked bytes %d", sb->sacked_bytes);
     483           1 :   TCP_TEST ((sb->last_sacked_bytes == 500), "last sacked bytes %d",
     484             :             sb->last_sacked_bytes);
     485           1 :   TCP_TEST ((sb->lost_bytes == 500), "lost bytes %u", sb->lost_bytes);
     486             : 
     487           1 :   vec_reset_length (tc->rcv_opts.sacks);
     488           1 :   block.start = 300;
     489           1 :   block.end = 400;
     490           1 :   vec_add1 (tc->rcv_opts.sacks, block);
     491           1 :   tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
     492           1 :   tcp_rcv_sacks (tc, 100);
     493           1 :   if (verbose)
     494           0 :     vlib_cli_output (vm, "\nsb added [0, 100] [300, 400]:\n%U",
     495             :                      format_tcp_scoreboard, sb, tc);
     496           1 :   TCP_TEST ((pool_elts (sb->holes) == 2),
     497             :             "scoreboard has %d elements", pool_elts (sb->holes));
     498           1 :   TCP_TEST ((sb->sacked_bytes == 600), "sacked bytes %d", sb->sacked_bytes);
     499           1 :   TCP_TEST ((sb->last_sacked_bytes == 100), "last sacked bytes %d",
     500             :             sb->last_sacked_bytes);
     501           1 :   TCP_TEST ((sb->last_bytes_delivered == 0), "last bytes delivered %d",
     502             :             sb->last_bytes_delivered);
     503             :   /* Hole should be split in 2 lost holes that add up to 300 */
     504           1 :   TCP_TEST ((sb->lost_bytes == 300), "lost bytes %u", sb->lost_bytes);
     505           1 :   TCP_TEST ((sb->reorder == 7), "reorder %u", sb->reorder);
     506             : 
     507             :   /*
     508             :    * Ack [100 300] in two steps
     509             :    *
     510             :    * Step 1. Ack [100 200] which delivers 100 of the bytes lost
     511             :    */
     512           1 :   tc->snd_una = 100;
     513           1 :   tcp_rcv_sacks (tc, 200);
     514           1 :   TCP_TEST ((sb->sacked_bytes == 600), "sacked bytes %d", sb->sacked_bytes);
     515           1 :   TCP_TEST ((sb->last_bytes_delivered == 0), "last bytes delivered %d",
     516             :             sb->last_bytes_delivered);
     517           1 :   TCP_TEST ((sb->lost_bytes == 200), "lost bytes %u", sb->lost_bytes);
     518             : 
     519             :   /*
     520             :    * Step 2. Ack up to 300, although 300 400 is sacked, so this is interpreted
     521             :    * as reneging.
     522             :    */
     523           1 :   tc->snd_una = 200;
     524           1 :   tcp_rcv_sacks (tc, 300);
     525           1 :   if (verbose)
     526           0 :     vlib_cli_output (vm, "\nacked [100, 300] in two steps:\n%U",
     527             :                      format_tcp_scoreboard, sb, tc);
     528           1 :   TCP_TEST ((sb->sacked_bytes == 600), "sacked bytes %d", sb->sacked_bytes);
     529           1 :   TCP_TEST ((sb->lost_bytes == 100), "lost bytes %u", sb->lost_bytes);
     530           1 :   TCP_TEST ((sb->last_bytes_delivered == 0), "last bytes delivered %d",
     531             :             sb->last_bytes_delivered);
     532           1 :   TCP_TEST ((sb->is_reneging), "is reneging");
     533             : 
     534             :   /*
     535             :    * Ack [300 500]. Delivers reneged segment [300 400] and reneges bytes
     536             :    * above 500
     537             :    */
     538           1 :   tc->snd_una = 300;
     539           1 :   tcp_rcv_sacks (tc, 500);
     540           1 :   if (verbose)
     541           0 :     vlib_cli_output (vm, "\nacked [400, 500]:\n%U", format_tcp_scoreboard, sb,
     542             :                      tc);
     543           1 :   TCP_TEST ((pool_elts (sb->holes) == 0),
     544             :             "scoreboard has %d elements", pool_elts (sb->holes));
     545           1 :   TCP_TEST ((sb->sacked_bytes == 500), "sacked bytes %d", sb->sacked_bytes);
     546           1 :   TCP_TEST ((sb->last_sacked_bytes == 0), "last sacked bytes %d",
     547             :             sb->last_sacked_bytes);
     548           1 :   TCP_TEST ((sb->last_bytes_delivered == 100), "last bytes delivered %d",
     549             :             sb->last_bytes_delivered);
     550           1 :   TCP_TEST ((sb->is_reneging), "is reneging");
     551           1 :   TCP_TEST ((sb->head == TCP_INVALID_SACK_HOLE_INDEX), "head %u", sb->head);
     552           1 :   TCP_TEST ((sb->tail == TCP_INVALID_SACK_HOLE_INDEX), "tail %u", sb->tail);
     553             : 
     554             :   /*
     555             :    * Ack up to 1000 to deliver all bytes
     556             :    */
     557           1 :   tc->snd_una = 500;
     558           1 :   tcp_rcv_sacks (tc, 1000);
     559           1 :   if (verbose)
     560           0 :     vlib_cli_output (vm, "\nAck high sacked:\n%U", format_tcp_scoreboard, sb,
     561             :                      tc);
     562           1 :   TCP_TEST ((sb->last_sacked_bytes == 0), "last sacked bytes %d",
     563             :             sb->last_sacked_bytes);
     564           1 :   TCP_TEST ((sb->last_bytes_delivered == 500), "last bytes delivered %d",
     565             :             sb->last_bytes_delivered);
     566           1 :   TCP_TEST ((!sb->is_reneging), "is not reneging");
     567             : 
     568             :   /*
     569             :    * Add [1200, 1500] and test that [1000, 1200] is lost (bytes condition)
     570             :    * snd_una = 1000 and snd_una_max = 1600
     571             :    */
     572           1 :   tc->snd_una = 1000;
     573           1 :   tc->snd_nxt = 1600;
     574           1 :   vec_reset_length (tc->rcv_opts.sacks);
     575           1 :   block.start = 1200;
     576           1 :   block.end = 1500;
     577           1 :   vec_add1 (tc->rcv_opts.sacks, block);
     578           1 :   tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
     579           1 :   tcp_rcv_sacks (tc, 1000);
     580           1 :   if (verbose)
     581           0 :     vlib_cli_output (vm, "\nacked [1200, 1500] test first hole is lost:\n%U",
     582             :                      format_tcp_scoreboard, sb, tc);
     583           1 :   TCP_TEST ((pool_elts (sb->holes) == 2), "scoreboard has %d elements",
     584             :             pool_elts (sb->holes));
     585           1 :   TCP_TEST ((sb->sacked_bytes == 300), "sacked bytes %d", sb->sacked_bytes);
     586           1 :   TCP_TEST ((sb->last_sacked_bytes == 300), "last sacked bytes %d",
     587             :             sb->last_sacked_bytes);
     588           1 :   TCP_TEST ((sb->last_bytes_delivered == 0), "last bytes delivered %d",
     589             :             sb->last_bytes_delivered);
     590             :   /* No bytes lost because of reorder */
     591           1 :   TCP_TEST ((sb->lost_bytes == 0), "lost bytes %u", sb->lost_bytes);
     592           1 :   TCP_TEST ((sb->reorder == 7), "reorder %u", sb->reorder);
     593           1 :   TCP_TEST ((!sb->is_reneging), "is not reneging");
     594             : 
     595             :   /*
     596             :    * Restart
     597             :    */
     598           1 :   scoreboard_clear (sb);
     599           1 :   vec_reset_length (tc->rcv_opts.sacks);
     600             : 
     601             :   /*
     602             :    * Inject [100 500]
     603             :    */
     604             : 
     605           1 :   tc->flags |= TCP_CONN_FAST_RECOVERY | TCP_CONN_RECOVERY;
     606           1 :   tc->snd_una = 0;
     607           1 :   tc->snd_nxt = 1000;
     608           1 :   sb->high_rxt = 0;
     609             : 
     610           1 :   block.start = 100;
     611           1 :   block.end = 500;
     612           1 :   vec_add1 (tc->rcv_opts.sacks, block);
     613           1 :   tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
     614             : 
     615           1 :   tcp_rcv_sacks (tc, 0);
     616             : 
     617           1 :   TCP_TEST ((sb->sacked_bytes == 400), "sacked bytes %d", sb->sacked_bytes);
     618           1 :   TCP_TEST ((sb->last_sacked_bytes == 400), "last sacked bytes %d",
     619             :             sb->last_sacked_bytes);
     620           1 :   TCP_TEST ((!sb->is_reneging), "is not reneging");
     621             : 
     622             :   /*
     623             :    * Renege, sack all of the remaining bytes and cover some rxt bytes
     624             :    */
     625           1 :   sb->high_rxt = 700;
     626           1 :   tc->rcv_opts.sacks[0].start = 500;
     627           1 :   tc->rcv_opts.sacks[0].end = 1000;
     628             : 
     629           1 :   tcp_rcv_sacks (tc, 100);
     630             : 
     631           1 :   TCP_TEST ((sb->sacked_bytes == 900), "sacked bytes %d", sb->sacked_bytes);
     632           1 :   TCP_TEST ((sb->last_sacked_bytes == 500), "last sacked bytes %d",
     633             :             sb->last_sacked_bytes);
     634           1 :   TCP_TEST (sb->is_reneging, "is reneging");
     635           1 :   TCP_TEST ((sb->rxt_sacked == 300), "last rxt sacked bytes %d",
     636             :             sb->rxt_sacked);
     637             : 
     638             :   /*
     639             :    * Restart
     640             :    */
     641           1 :   scoreboard_clear (sb);
     642           1 :   vec_reset_length (tc->rcv_opts.sacks);
     643             : 
     644             :   /*
     645             :    * Broken sacks:
     646             :    * block.start > snd_nxt
     647             :    * && block.start < blk.end
     648             :    * && block.end <= snd_nxt
     649             :    */
     650           1 :   tc->flags = 0;
     651           1 :   block.start = 2147483647;
     652           1 :   block.end = 4294967295;
     653           1 :   vec_add1 (tc->rcv_opts.sacks, block);
     654           1 :   tc->snd_una = tc->snd_nxt = 1969067947;
     655             : 
     656           1 :   tcp_rcv_sacks (tc, tc->snd_una);
     657             : 
     658             :   /*
     659             :    * Clear
     660             :    */
     661           1 :   scoreboard_clear (sb);
     662           1 :   vec_reset_length (tc->rcv_opts.sacks);
     663             : 
     664           1 :   return 0;
     665             : }
     666             : 
     667             : static int
     668           1 : tcp_test_sack_tx (vlib_main_t * vm, unformat_input_t * input)
     669             : {
     670           1 :   tcp_connection_t _tc, *tc = &_tc;
     671             :   sack_block_t *sacks;
     672           1 :   int i, verbose = 0, expected;
     673             : 
     674           1 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     675             :     {
     676           0 :       if (unformat (input, "verbose"))
     677           0 :         verbose = 1;
     678             :       else
     679             :         {
     680           0 :           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
     681             :                            input);
     682           0 :           return -1;
     683             :         }
     684             :     }
     685             : 
     686           1 :   clib_memset (tc, 0, sizeof (*tc));
     687             : 
     688             :   /*
     689             :    * Add odd sack block pairs
     690             :    */
     691           6 :   for (i = 1; i < 10; i += 2)
     692             :     {
     693           5 :       tcp_update_sack_list (tc, i * 100, (i + 1) * 100);
     694             :     }
     695             : 
     696           1 :   TCP_TEST ((vec_len (tc->snd_sacks) == 5), "sack blocks %d expected %d",
     697             :             vec_len (tc->snd_sacks), 5);
     698           1 :   TCP_TEST ((tc->snd_sacks[0].start = 900),
     699             :             "first sack block start %u expected %u", tc->snd_sacks[0].start,
     700             :             900);
     701             : 
     702             :   /*
     703             :    * Try to add one extra
     704             :    */
     705           1 :   sacks = vec_dup (tc->snd_sacks);
     706             : 
     707           1 :   tcp_update_sack_list (tc, 1100, 1200);
     708           1 :   if (verbose)
     709           0 :     vlib_cli_output (vm, "add new segment [1100, 1200]\n%U",
     710             :                      format_tcp_sacks, tc);
     711           1 :   expected = 5 < TCP_MAX_SACK_BLOCKS ? 6 : 5;
     712           1 :   TCP_TEST ((vec_len (tc->snd_sacks) == expected),
     713             :             "sack blocks %d expected %d", vec_len (tc->snd_sacks), expected);
     714           1 :   TCP_TEST ((tc->snd_sacks[0].start == 1100),
     715             :             "first sack block start %u expected %u", tc->snd_sacks[0].start,
     716             :             1100);
     717             : 
     718             :   /* restore */
     719           1 :   vec_free (tc->snd_sacks);
     720           1 :   tc->snd_sacks = sacks;
     721             : 
     722             :   /*
     723             :    * Overlap first 2 segment
     724             :    */
     725           1 :   tc->rcv_nxt = 300;
     726           1 :   tcp_update_sack_list (tc, 300, 300);
     727           1 :   if (verbose)
     728           0 :     vlib_cli_output (vm, "overlap first 2 segments:\n%U",
     729             :                      format_tcp_sacks, tc);
     730           1 :   TCP_TEST ((vec_len (tc->snd_sacks) == 3), "sack blocks %d expected %d",
     731             :             vec_len (tc->snd_sacks), 3);
     732           1 :   TCP_TEST ((tc->snd_sacks[0].start == 900),
     733             :             "first sack block start %u expected %u", tc->snd_sacks[0].start,
     734             :             500);
     735             : 
     736             :   /*
     737             :    * Add a new segment
     738             :    */
     739           1 :   tcp_update_sack_list (tc, 1100, 1200);
     740           1 :   if (verbose)
     741           0 :     vlib_cli_output (vm, "add new segment [1100, 1200]\n%U",
     742             :                      format_tcp_sacks, tc);
     743           1 :   TCP_TEST ((vec_len (tc->snd_sacks) == 4), "sack blocks %d expected %d",
     744             :             vec_len (tc->snd_sacks), 4);
     745           1 :   TCP_TEST ((tc->snd_sacks[0].start == 1100),
     746             :             "first sack block start %u expected %u", tc->snd_sacks[0].start,
     747             :             1100);
     748             : 
     749             :   /*
     750             :    * Join middle segments
     751             :    */
     752           1 :   tcp_update_sack_list (tc, 800, 900);
     753           1 :   if (verbose)
     754           0 :     vlib_cli_output (vm, "join middle segments [800, 900]\n%U",
     755             :                      format_tcp_sacks, tc);
     756             : 
     757           1 :   TCP_TEST ((vec_len (tc->snd_sacks) == 3), "sack blocks %d expected %d",
     758             :             vec_len (tc->snd_sacks), 3);
     759           1 :   TCP_TEST ((tc->snd_sacks[0].start == 700),
     760             :             "first sack block start %u expected %u", tc->snd_sacks[0].start,
     761             :             1100);
     762             : 
     763             :   /*
     764             :    * Advance rcv_nxt to overlap all
     765             :    */
     766           1 :   tc->rcv_nxt = 1200;
     767           1 :   tcp_update_sack_list (tc, 1200, 1200);
     768           1 :   if (verbose)
     769           0 :     vlib_cli_output (vm, "advance rcv_nxt to 1200\n%U", format_tcp_sacks, tc);
     770           1 :   TCP_TEST ((vec_len (tc->snd_sacks) == 0), "sack blocks %d expected %d",
     771             :             vec_len (tc->snd_sacks), 0);
     772             : 
     773             : 
     774             :   /*
     775             :    * Add 2 blocks, overwrite first and update rcv_nxt to also remove it
     776             :    */
     777             : 
     778           1 :   vec_reset_length (tc->snd_sacks);
     779           1 :   tc->rcv_nxt = 0;
     780             : 
     781           1 :   tcp_update_sack_list (tc, 100, 200);
     782           1 :   tcp_update_sack_list (tc, 300, 400);
     783             : 
     784           1 :   if (verbose)
     785           0 :     vlib_cli_output (vm, "add [100, 200] [300, 400]\n%U",
     786             :                      format_tcp_sacks, tc);
     787           1 :   TCP_TEST ((vec_len (tc->snd_sacks) == 2),
     788             :             "sack blocks %d expected %d", vec_len (tc->snd_sacks), 2);
     789           1 :   TCP_TEST ((tc->snd_sacks[0].start == 300),
     790             :             "first sack block start %u expected %u", tc->snd_sacks[0].start,
     791             :             300);
     792             : 
     793           1 :   tc->rcv_nxt = 100;
     794           1 :   tcp_update_sack_list (tc, 100, 100);
     795           1 :   if (verbose)
     796           0 :     vlib_cli_output (vm, "add [100, 200] rcv_nxt = 100\n%U",
     797             :                      format_tcp_sacks, tc);
     798           1 :   TCP_TEST ((vec_len (tc->snd_sacks) == 1),
     799             :             "sack blocks %d expected %d", vec_len (tc->snd_sacks), 1);
     800           1 :   TCP_TEST ((tc->snd_sacks[0].start == 300),
     801             :             "first sack block start %u expected %u", tc->snd_sacks[0].start,
     802             :             300);
     803           1 :   return 0;
     804             : }
     805             : 
     806             : static int
     807           1 : tcp_test_sack (vlib_main_t * vm, unformat_input_t * input)
     808             : {
     809           1 :   int res = 0;
     810             : 
     811             :   /* Run all tests */
     812           1 :   if (unformat_check_input (input) == UNFORMAT_END_OF_INPUT)
     813             :     {
     814           1 :       if (tcp_test_sack_tx (vm, input))
     815             :         {
     816           0 :           return -1;
     817             :         }
     818             : 
     819           1 :       if (tcp_test_sack_rx (vm, input))
     820             :         {
     821           0 :           return -1;
     822             :         }
     823             :     }
     824             :   else
     825             :     {
     826           0 :       if (unformat (input, "tx"))
     827             :         {
     828           0 :           res = tcp_test_sack_tx (vm, input);
     829             :         }
     830           0 :       else if (unformat (input, "rx"))
     831             :         {
     832           0 :           res = tcp_test_sack_rx (vm, input);
     833             :         }
     834             :     }
     835             : 
     836           1 :   return res;
     837             : }
     838             : 
     839             : static int
     840           1 : tcp_test_lookup (vlib_main_t * vm, unformat_input_t * input)
     841             : {
     842           1 :   session_main_t *smm = &session_main;
     843           1 :   transport_connection_t _tc1, *tc1 = &_tc1, _tc2, *tc2 = &_tc2, *tconn;
     844             :   tcp_connection_t *tc;
     845             :   session_t *s, *s1;
     846           1 :   u8 cmp = 0, is_filtered = 0;
     847             :   u32 sidx;
     848             : 
     849             :   /*
     850             :    * Allocate fake session and connection 1
     851             :    */
     852           1 :   pool_get (smm->wrk[0].sessions, s);
     853           1 :   clib_memset (s, 0, sizeof (*s));
     854           1 :   s->session_index = sidx = s - smm->wrk[0].sessions;
     855             : 
     856           1 :   tc = tcp_connection_alloc (0);
     857           1 :   tc->connection.s_index = s->session_index;
     858           1 :   s->connection_index = tc->connection.c_index;
     859             : 
     860           1 :   tc->connection.lcl_ip.ip4.as_u32 = clib_host_to_net_u32 (0x06000101);
     861           1 :   tc->connection.rmt_ip.ip4.as_u32 = clib_host_to_net_u32 (0x06000103);
     862           1 :   tc->connection.lcl_port = 35051;
     863           1 :   tc->connection.rmt_port = 53764;
     864           1 :   tc->connection.proto = TRANSPORT_PROTO_TCP;
     865           1 :   tc->connection.is_ip4 = 1;
     866           1 :   clib_memcpy_fast (tc1, &tc->connection, sizeof (*tc1));
     867             : 
     868             :   /*
     869             :    * Allocate fake session and connection 2
     870             :    */
     871           1 :   pool_get (smm->wrk[0].sessions, s);
     872           1 :   clib_memset (s, 0, sizeof (*s));
     873           1 :   s->session_index = s - smm->wrk[0].sessions;
     874             : 
     875           1 :   tc = tcp_connection_alloc (0);
     876           1 :   tc->connection.s_index = s->session_index;
     877           1 :   s->connection_index = tc->connection.c_index;
     878             : 
     879           1 :   tc->connection.lcl_ip.ip4.as_u32 = clib_host_to_net_u32 (0x06000101);
     880           1 :   tc->connection.rmt_ip.ip4.as_u32 = clib_host_to_net_u32 (0x06000102);
     881           1 :   tc->connection.lcl_port = 38225;
     882           1 :   tc->connection.rmt_port = 53764;
     883           1 :   tc->connection.proto = TRANSPORT_PROTO_TCP;
     884           1 :   tc->connection.is_ip4 = 1;
     885           1 :   clib_memcpy_fast (tc2, &tc->connection, sizeof (*tc2));
     886             : 
     887             :   /*
     888             :    * Confirm that connection lookup works
     889             :    */
     890             : 
     891           1 :   s1 = pool_elt_at_index (smm->wrk[0].sessions, sidx);
     892           1 :   session_lookup_add_connection (tc1, session_handle (s1));
     893           1 :   tconn = session_lookup_connection_wt4 (0, &tc1->lcl_ip.ip4,
     894             :                                          &tc1->rmt_ip.ip4,
     895           1 :                                          tc1->lcl_port, tc1->rmt_port,
     896           1 :                                          tc1->proto, 0, &is_filtered);
     897             : 
     898           1 :   TCP_TEST ((tconn != 0), "connection exists");
     899           1 :   cmp = (memcmp (&tconn->rmt_ip, &tc1->rmt_ip, sizeof (tc1->rmt_ip)) == 0);
     900           1 :   TCP_TEST ((cmp), "rmt ip is identical %d", cmp);
     901           1 :   TCP_TEST ((tconn->lcl_port == tc1->lcl_port),
     902             :             "rmt port is identical %d", tconn->lcl_port == tc1->lcl_port);
     903             : 
     904             :   /*
     905             :    * Non-existing connection lookup should not work
     906             :    */
     907             : 
     908           1 :   tconn = session_lookup_connection_wt4 (0, &tc2->lcl_ip.ip4,
     909             :                                          &tc2->rmt_ip.ip4,
     910           1 :                                          tc2->lcl_port, tc2->rmt_port,
     911           1 :                                          tc2->proto, 0, &is_filtered);
     912           1 :   TCP_TEST ((tconn == 0), "lookup result should be null");
     913             : 
     914             :   /*
     915             :    * Delete and lookup again
     916             :    */
     917           1 :   session_lookup_del_connection (tc1);
     918           1 :   tconn = session_lookup_connection_wt4 (0, &tc1->lcl_ip.ip4,
     919             :                                          &tc1->rmt_ip.ip4,
     920           1 :                                          tc1->lcl_port, tc1->rmt_port,
     921           1 :                                          tc1->proto, 0, &is_filtered);
     922           1 :   TCP_TEST ((tconn == 0), "lookup result should be null");
     923           1 :   tconn = session_lookup_connection_wt4 (0, &tc2->lcl_ip.ip4,
     924             :                                          &tc2->rmt_ip.ip4,
     925           1 :                                          tc2->lcl_port, tc2->rmt_port,
     926           1 :                                          tc2->proto, 0, &is_filtered);
     927           1 :   TCP_TEST ((tconn == 0), "lookup result should be null");
     928             : 
     929             :   /*
     930             :    * Re-add and lookup tc2
     931             :    */
     932           1 :   session_lookup_add_connection (tc1, tc1->s_index);
     933           1 :   tconn = session_lookup_connection_wt4 (0, &tc2->lcl_ip.ip4,
     934             :                                          &tc2->rmt_ip.ip4,
     935           1 :                                          tc2->lcl_port, tc2->rmt_port,
     936           1 :                                          tc2->proto, 0, &is_filtered);
     937           1 :   TCP_TEST ((tconn == 0), "lookup result should be null");
     938             : 
     939           1 :   return 0;
     940             : }
     941             : 
     942             : static int
     943           0 : tcp_test_session (vlib_main_t * vm, unformat_input_t * input)
     944             : {
     945           0 :   int rv = 0;
     946             :   tcp_connection_t *tc0;
     947             :   ip4_address_t local, remote;
     948             :   u16 local_port, remote_port;
     949           0 :   int is_add = 1;
     950             : 
     951             : 
     952           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     953             :     {
     954           0 :       if (unformat (input, "del"))
     955           0 :         is_add = 0;
     956           0 :       else if (unformat (input, "add"))
     957           0 :         is_add = 1;
     958             :       else
     959           0 :         break;
     960             :     }
     961             : 
     962           0 :   if (is_add)
     963             :     {
     964           0 :       local.as_u32 = clib_host_to_net_u32 (0x06000101);
     965           0 :       remote.as_u32 = clib_host_to_net_u32 (0x06000102);
     966           0 :       local_port = clib_host_to_net_u16 (1234);
     967           0 :       remote_port = clib_host_to_net_u16 (11234);
     968             : 
     969           0 :       tc0 = tcp_connection_alloc (0);
     970             : 
     971           0 :       tc0->state = TCP_STATE_ESTABLISHED;
     972           0 :       tc0->rcv_las = 1;
     973           0 :       tc0->c_lcl_port = local_port;
     974           0 :       tc0->c_rmt_port = remote_port;
     975           0 :       tc0->c_is_ip4 = 1;
     976           0 :       tc0->c_thread_index = 0;
     977           0 :       tc0->c_lcl_ip4.as_u32 = local.as_u32;
     978           0 :       tc0->c_rmt_ip4.as_u32 = remote.as_u32;
     979           0 :       tc0->rcv_opts.mss = 1450;
     980           0 :       tcp_connection_init_vars (tc0);
     981             : 
     982             :       TCP_EVT (TCP_EVT_OPEN, tc0);
     983             : 
     984           0 :       if (session_stream_accept (&tc0->connection, 0 /* listener index */ ,
     985             :                                  0 /* thread index */ , 0 /* notify */ ))
     986           0 :         clib_warning ("stream_session_accept failed");
     987             : 
     988           0 :       session_stream_accept_notify (&tc0->connection);
     989             :     }
     990             :   else
     991             :     {
     992           0 :       tc0 = tcp_connection_get (0 /* connection index */ , 0 /* thread */ );
     993           0 :       tc0->state = TCP_STATE_CLOSED;
     994           0 :       session_transport_closing_notify (&tc0->connection);
     995             :     }
     996             : 
     997           0 :   return rv;
     998             : }
     999             : 
    1000             : static inline int
    1001           6 : tbt_seq_lt (u32 a, u32 b)
    1002             : {
    1003           6 :   return seq_lt (a, b);
    1004             : }
    1005             : 
    1006             : static void
    1007          12 : tcp_test_set_time (u32 thread_index, u32 val)
    1008             : {
    1009          12 :   session_main.wrk[thread_index].last_vlib_time = val;
    1010          12 :   tcp_set_time_now (&tcp_main.wrk_ctx[thread_index], val);
    1011          12 : }
    1012             : 
    1013             : static int
    1014           1 : tcp_test_delivery (vlib_main_t * vm, unformat_input_t * input)
    1015             : {
    1016           1 :   u32 thread_index = 0, snd_una, *min_seqs = 0;
    1017           1 :   tcp_rate_sample_t _rs = { 0 }, *rs = &_rs;
    1018           1 :   tcp_connection_t _tc, *tc = &_tc;
    1019           1 :   sack_scoreboard_t *sb = &tc->sack_sb;
    1020           1 :   int __clib_unused verbose = 0, i;
    1021           1 :   u64 rate = 1000, burst = 100;
    1022           1 :   sack_block_t *sacks = 0;
    1023             :   tcp_byte_tracker_t *bt;
    1024             :   rb_node_t *root, *rbn;
    1025             :   tcp_bt_sample_t *bts;
    1026             : 
    1027           1 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    1028             :     {
    1029           0 :       if (unformat (input, "verbose"))
    1030           0 :         verbose = 1;
    1031             :       else
    1032             :         {
    1033           0 :           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
    1034             :                            input);
    1035           0 :           return -1;
    1036             :         }
    1037             :     }
    1038             : 
    1039             :   /* Init data structures */
    1040           1 :   memset (tc, 0, sizeof (*tc));
    1041           1 :   tcp_test_set_time (thread_index, 1);
    1042           1 :   transport_connection_tx_pacer_update (&tc->connection, rate, 1e6);
    1043             : 
    1044           1 :   tcp_bt_init (tc);
    1045           1 :   bt = tc->bt;
    1046             : 
    1047             :   /*
    1048             :    * Track simple bursts without rxt
    1049             :    */
    1050             : 
    1051             :   /* 1) track first burst a time 1 */
    1052           1 :   tcp_bt_track_tx (tc, burst);
    1053             : 
    1054           1 :   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
    1055           1 :   TCP_TEST (pool_elts (bt->samples) == 1, "should have 1 sample");
    1056           1 :   bts = pool_elt_at_index (bt->samples, bt->head);
    1057           1 :   TCP_TEST (bts->min_seq == tc->snd_una, "min seq should be snd_una");
    1058           1 :   TCP_TEST (bts->next == TCP_BTS_INVALID_INDEX, "next should be invalid");
    1059           1 :   TCP_TEST (bts->prev == TCP_BTS_INVALID_INDEX, "prev should be invalid");
    1060           1 :   TCP_TEST (bts->delivered_time == 1, "delivered time should be 1");
    1061           1 :   TCP_TEST (bts->delivered == 0, "delivered should be 0");
    1062           1 :   TCP_TEST (!(bts->flags & TCP_BTS_IS_RXT), "not retransmitted");
    1063           1 :   TCP_TEST (!(bts->flags & TCP_BTS_IS_APP_LIMITED), "not app limited");
    1064             : 
    1065             :   /* 2) check delivery rate at time 2 */
    1066           1 :   tcp_test_set_time (thread_index, 2);
    1067           1 :   tc->snd_una = tc->snd_nxt = burst;
    1068           1 :   tc->bytes_acked = burst;
    1069             : 
    1070           1 :   tcp_bt_sample_delivery_rate (tc, rs);
    1071             : 
    1072           1 :   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
    1073           1 :   TCP_TEST (pool_elts (bt->samples) == 0, "sample should've been consumed");
    1074           1 :   TCP_TEST (tc->delivered_time == 2, "delivered time should be 2");
    1075           1 :   TCP_TEST (tc->delivered == burst, "delivered should be 100");
    1076           1 :   TCP_TEST (rs->interval_time == 1, "ack time should be 1");
    1077           1 :   TCP_TEST (rs->delivered == burst, "delivered should be 100");
    1078           1 :   TCP_TEST (rs->prior_delivered == 0, "sample delivered should be 0");
    1079           1 :   TCP_TEST (!(rs->flags & TCP_BTS_IS_RXT), "not retransmitted");
    1080           1 :   TCP_TEST (tc->first_tx_time == 1, "first_tx_time %u", tc->first_tx_time);
    1081             : 
    1082             :   /* 3) track second burst at time 2 */
    1083           1 :   tcp_bt_track_tx (tc, burst);
    1084           1 :   tc->snd_nxt += burst;
    1085             : 
    1086             :   /* 4) track second burst at time 3 */
    1087           1 :   tcp_test_set_time (thread_index, 3);
    1088           1 :   tcp_bt_track_tx (tc, burst);
    1089           1 :   tc->snd_nxt += burst;
    1090             : 
    1091           1 :   TCP_TEST (pool_elts (bt->samples) == 2, "should have 2 samples");
    1092             : 
    1093           1 :   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
    1094           1 :   bts = pool_elt_at_index (bt->samples, bt->head);
    1095           1 :   TCP_TEST (bts->min_seq == tc->snd_una, "min seq should be snd_una");
    1096           1 :   TCP_TEST (bts->next == bt->tail, "next should tail");
    1097             : 
    1098           1 :   bts = pool_elt_at_index (bt->samples, bt->tail);
    1099           1 :   TCP_TEST (bts->min_seq == tc->snd_nxt - burst,
    1100             :             "min seq should be snd_nxt prior to burst");
    1101           1 :   TCP_TEST (bts->prev == bt->head, "prev should be head");
    1102             : 
    1103             :   /* 5) check delivery rate at time 4 */
    1104           1 :   tcp_test_set_time (thread_index, 4);
    1105           1 :   tc->snd_una = tc->snd_nxt;
    1106           1 :   tc->bytes_acked = 2 * burst;
    1107             : 
    1108           1 :   tcp_bt_sample_delivery_rate (tc, rs);
    1109             : 
    1110           1 :   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
    1111           1 :   TCP_TEST (pool_elts (bt->samples) == 0, "sample should've been consumed");
    1112           1 :   TCP_TEST (tc->delivered_time == 4, "delivered time should be 4");
    1113           1 :   TCP_TEST (tc->delivered == 3 * burst, "delivered should be 300 is %u",
    1114             :             tc->delivered);
    1115           1 :   TCP_TEST (rs->interval_time == 2, "ack time should be 2");
    1116           1 :   TCP_TEST (rs->delivered == 2 * burst, "delivered should be 200");
    1117           1 :   TCP_TEST (rs->prior_delivered == burst, "delivered should be 100");
    1118           1 :   TCP_TEST (!(rs->flags & TCP_BTS_IS_RXT), "not retransmitted");
    1119           1 :   TCP_TEST (tc->first_tx_time == 2, "first_tx_time %u", tc->first_tx_time);
    1120             : 
    1121             :   /*
    1122             :    * Track retransmissions
    1123             :    *
    1124             :    * snd_una should be 300 at this point
    1125             :    */
    1126             : 
    1127           1 :   snd_una = tc->snd_una;
    1128             : 
    1129             :   /* 1) track first burst at time 4 */
    1130           1 :   tcp_bt_track_tx (tc, burst);
    1131           1 :   tc->snd_nxt += burst;
    1132             : 
    1133             :   /* 2) track second burst at time 5 */
    1134           1 :   tcp_test_set_time (thread_index, 5);
    1135           1 :   tcp_bt_track_tx (tc, burst);
    1136           1 :   tc->snd_nxt += burst;
    1137             : 
    1138             :   /* 3) track third burst at time 6 */
    1139           1 :   tcp_test_set_time (thread_index, 6);
    1140           1 :   tcp_bt_track_tx (tc, burst);
    1141           1 :   tc->snd_nxt += burst;
    1142             : 
    1143             :   /* 4) track fourth burst at time 7 */
    1144           1 :   tcp_test_set_time (thread_index, 7);
    1145             :   /* Limited until last burst is acked */
    1146           1 :   tc->app_limited = snd_una + 4 * burst - 1;
    1147           1 :   tcp_bt_track_tx (tc, burst);
    1148           1 :   tc->snd_nxt += burst;
    1149             : 
    1150             :   /* 5) check delivery rate at time 8
    1151             :    *
    1152             :    * tc->snd_una = snd_una + 10
    1153             :    * sacks:
    1154             :    * [snd_una + burst, snd_una + burst + 10]
    1155             :    * [snd_una + 2 * burst + 10, snd_una + 2 * burst + 20]
    1156             :    */
    1157           1 :   tcp_test_set_time (thread_index, 8);
    1158           1 :   tc->snd_una += 10;
    1159           1 :   tc->bytes_acked = 10;
    1160           1 :   sb->last_sacked_bytes = 20;
    1161             : 
    1162           1 :   TCP_TEST (pool_elts (bt->samples) == 4, "there should be 4 samples");
    1163             : 
    1164           1 :   vec_validate (sacks, 1);
    1165           1 :   sacks[0].start = snd_una + burst;
    1166           1 :   sacks[0].end = snd_una + burst + 10;
    1167           1 :   sacks[1].start = snd_una + 2 * burst + 10;
    1168           1 :   sacks[1].end = snd_una + 2 * burst + 20;
    1169           1 :   tc->rcv_opts.sacks = sacks;
    1170             : 
    1171           1 :   tcp_bt_sample_delivery_rate (tc, rs);
    1172             : 
    1173           1 :   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
    1174           1 :   TCP_TEST (pool_elts (bt->samples) == 7, "there should be 7 samples %u",
    1175             :             pool_elts (bt->samples));
    1176           1 :   TCP_TEST (tc->delivered_time == 8, "delivered time should be 8");
    1177           1 :   TCP_TEST (tc->delivered == 3 * burst + 30, "delivered should be %u is %u",
    1178             :             3 * burst + 30, tc->delivered);
    1179             :   /* All 3 samples have the same delivered number of bytes. So the first is
    1180             :    * the reference for delivery estimate. */
    1181           1 :   TCP_TEST (rs->interval_time == 4, "ack time should be 4 is %.2f",
    1182             :             rs->interval_time);
    1183           1 :   TCP_TEST (rs->delivered == 30, "delivered should be 30");
    1184           1 :   TCP_TEST (rs->prior_delivered == 3 * burst,
    1185             :             "sample delivered should be %u", 3 * burst);
    1186           1 :   TCP_TEST (!(rs->flags & TCP_BTS_IS_RXT), "not retransmitted");
    1187           1 :   TCP_TEST (!(rs->flags & TCP_BTS_IS_APP_LIMITED), "not app limited");
    1188             :   /* All 3 samples have the same delivered number of bytes. The first
    1189             :    * sets the first tx time */
    1190           1 :   TCP_TEST (tc->first_tx_time == 4, "first_tx_time %u", tc->first_tx_time);
    1191             : 
    1192             :   /* 6) Retransmit and track at time 9
    1193             :    *
    1194             :    * delivered = 3 * burst + 30
    1195             :    * delivered_time = 8 (last ack)
    1196             :    *
    1197             :    * segments:
    1198             :    * [snd_una + 10, snd_una + burst]
    1199             :    * [snd_una + burst + 10, snd_una + 2 * burst + 10]
    1200             :    * [snd_una + 2 * burst + 20, snd_una + 4 * burst]
    1201             :    */
    1202           1 :   tcp_test_set_time (thread_index, 9);
    1203             : 
    1204           1 :   tcp_bt_track_rxt (tc, snd_una + 10, snd_una + burst);
    1205           1 :   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
    1206             :   /* The retransmit covers everything left from first burst */
    1207           1 :   TCP_TEST (pool_elts (bt->samples) == 7, "there should be 7 samples %u",
    1208             :             pool_elts (bt->samples));
    1209             : 
    1210           1 :   tcp_bt_track_rxt (tc, snd_una + burst + 10, snd_una + 2 * burst + 10);
    1211           1 :   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
    1212           1 :   TCP_TEST (pool_elts (bt->samples) == 6, "there should be 6 samples %u",
    1213             :             pool_elts (bt->samples));
    1214             : 
    1215             :   /* Retransmit covers last sample entirely so it should be removed */
    1216           1 :   tcp_bt_track_rxt (tc, snd_una + 2 * burst + 20, snd_una + 4 * burst);
    1217           1 :   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
    1218           1 :   TCP_TEST (pool_elts (bt->samples) == 5, "there should be 5 samples %u",
    1219             :             pool_elts (bt->samples));
    1220             : 
    1221           1 :   vec_validate (min_seqs, 4);
    1222           1 :   min_seqs[0] = snd_una + 10;
    1223           1 :   min_seqs[1] = snd_una + burst;
    1224           1 :   min_seqs[2] = snd_una + burst + 10;
    1225           1 :   min_seqs[3] = snd_una + 2 * burst + 10;
    1226           1 :   min_seqs[4] = snd_una + 2 * burst + 20;
    1227             : 
    1228           1 :   root = bt->sample_lookup.nodes + bt->sample_lookup.root;
    1229           1 :   bts = bt->samples + bt->head;
    1230           6 :   for (i = 0; i < vec_len (min_seqs); i++)
    1231             :     {
    1232           5 :       if (bts->min_seq != min_seqs[i])
    1233           0 :         TCP_TEST (0, "should be %u is %u", min_seqs[i], bts->min_seq);
    1234           5 :       rbn = rb_tree_search_subtree_custom (&bt->sample_lookup, root,
    1235             :                                            bts->min_seq, tbt_seq_lt);
    1236           5 :       if (rbn->opaque != bts - bt->samples)
    1237           0 :         TCP_TEST (0, "lookup should work");
    1238           5 :       bts = bt->samples + bts->next;
    1239             :     }
    1240             : 
    1241             :   /* 7) check delivery rate at time 10
    1242             :    *
    1243             :    * tc->snd_una = snd_una + 2 * burst
    1244             :    * sacks:
    1245             :    * [snd_una + 2 * burst + 20, snd_una + 2 * burst + 30]
    1246             :    * [snd_una + 2 * burst + 50, snd_una + 2 * burst + 60]
    1247             :    */
    1248           1 :   tcp_test_set_time (thread_index, 10);
    1249           1 :   tc->snd_una = snd_una + 2 * burst;
    1250           1 :   tc->bytes_acked = 2 * burst - 10;
    1251           1 :   sb->last_sacked_bytes = 20;
    1252             : 
    1253           1 :   sacks[0].start = snd_una + 2 * burst + 20;
    1254           1 :   sacks[0].end = snd_una + 2 * burst + 30;
    1255           1 :   sacks[1].start = snd_una + 2 * burst + 50;
    1256           1 :   sacks[1].end = snd_una + 2 * burst + 60;
    1257             : 
    1258           1 :   tcp_bt_sample_delivery_rate (tc, rs);
    1259             : 
    1260           1 :   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
    1261           1 :   TCP_TEST (pool_elts (bt->samples) == 5, "num samples should be 5 is %u",
    1262             :             pool_elts (bt->samples));
    1263           1 :   TCP_TEST (tc->delivered_time == 10, "delivered time should be 10");
    1264           1 :   TCP_TEST (tc->delivered == 5 * burst + 40, "delivered should be %u is %u",
    1265             :             5 * burst + 40, tc->delivered);
    1266             :   /* A rxt was acked and delivered time for it is 8 (last ack time) so
    1267             :    * ack_time is 2 (8 - 10). However, first_tx_time for rxt was 4 and rxt
    1268             :    * time 9. Therefore snd_time is 5 (9 - 4)*/
    1269           1 :   TCP_TEST (rs->interval_time == 5, "ack time should be 5 is %.2f",
    1270             :             rs->interval_time);
    1271             :   /* delivered_now - delivered_rxt ~ 5 * burst + 40 - 3 * burst - 30 */
    1272           1 :   TCP_TEST (rs->delivered == 2 * burst + 10, "delivered should be 210 is %u",
    1273             :             rs->delivered);
    1274           1 :   TCP_TEST (rs->prior_delivered == 3 * burst + 30,
    1275             :             "sample delivered should be %u", 3 * burst + 30);
    1276           1 :   TCP_TEST (rs->flags & TCP_BTS_IS_RXT, "is retransmitted");
    1277             :   /* Sample is app limited because of the retransmits */
    1278           1 :   TCP_TEST (rs->flags & TCP_BTS_IS_APP_LIMITED, "is app limited");
    1279           1 :   TCP_TEST (tc->app_limited, "app limited should be set");
    1280           1 :   TCP_TEST (tc->first_tx_time == 9, "first_tx_time %u", tc->first_tx_time);
    1281             : 
    1282             : 
    1283             :   /*
    1284             :    * 8) check delivery rate at time 11
    1285             :    */
    1286           1 :   tcp_test_set_time (thread_index, 11);
    1287           1 :   tc->snd_una = tc->snd_nxt;
    1288           1 :   tc->bytes_acked = 2 * burst;
    1289           1 :   sb->last_sacked_bytes = 0;
    1290           1 :   sb->last_bytes_delivered = 40;
    1291             : 
    1292           1 :   memset (rs, 0, sizeof (*rs));
    1293           1 :   tcp_bt_sample_delivery_rate (tc, rs);
    1294             : 
    1295           1 :   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
    1296           1 :   TCP_TEST (pool_elts (bt->samples) == 0, "num samples should be 0 is %u",
    1297             :             pool_elts (bt->samples));
    1298           1 :   TCP_TEST (tc->delivered_time == 11, "delivered time should be 11");
    1299           1 :   TCP_TEST (tc->delivered == 7 * burst, "delivered should be %u is %u",
    1300             :             7 * burst, tc->delivered);
    1301             :   /* Delivered time at retransmit was 8 so ack_time is 11 - 8 = 3. However,
    1302             :    * first_tx_time for rxt was 4 and rxt time was 9. Therefore snd_time
    1303             :    * is 9 - 4 = 5 */
    1304           1 :   TCP_TEST (rs->interval_time == 5, "ack time should be 5 is %.2f",
    1305             :             rs->interval_time);
    1306             :   /* delivered_now - delivered_rxt ~ 7 * burst - 3 * burst - 30.
    1307             :    * That's because we didn't retransmit any new segment. */
    1308           1 :   TCP_TEST (rs->delivered == 4 * burst - 30, "delivered should be 160 is %u",
    1309             :             rs->delivered);
    1310           1 :   TCP_TEST (rs->prior_delivered == 3 * burst + 30,
    1311             :             "sample delivered should be %u", 3 * burst + 30);
    1312           1 :   TCP_TEST (rs->flags & TCP_BTS_IS_RXT, "is retransmitted");
    1313           1 :   TCP_TEST (rs->flags & TCP_BTS_IS_APP_LIMITED, "is app limited");
    1314           1 :   TCP_TEST (tc->app_limited == 0, "app limited should be cleared");
    1315           1 :   TCP_TEST (tc->first_tx_time == 9, "first_tx_time %u", tc->first_tx_time);
    1316             : 
    1317             :   /*
    1318             :    * 9) test flush
    1319             :    */
    1320             : 
    1321           1 :   tcp_bt_track_tx (tc, burst);
    1322           1 :   tc->snd_nxt += burst;
    1323             : 
    1324           1 :   tcp_test_set_time (thread_index, 12);
    1325           1 :   tcp_bt_track_tx (tc, burst);
    1326           1 :   tc->snd_nxt += burst;
    1327             : 
    1328           1 :   tcp_bt_flush_samples (tc);
    1329             : 
    1330             :   /*
    1331             :    * Cleanup
    1332             :    */
    1333           1 :   vec_free (sacks);
    1334           1 :   vec_free (min_seqs);
    1335           1 :   tcp_bt_cleanup (tc);
    1336           1 :   return 0;
    1337             : }
    1338             : 
    1339             : static int
    1340           0 : tcp_test_bt (vlib_main_t * vm, unformat_input_t * input)
    1341             : {
    1342           0 :   u32 thread_index = 0;
    1343           0 :   tcp_rate_sample_t _rs = { 0 }, *rs = &_rs;
    1344           0 :   tcp_connection_t _tc, *tc = &_tc;
    1345           0 :   int __clib_unused verbose = 0, i;
    1346             :   tcp_byte_tracker_t *bt;
    1347             :   tcp_bt_sample_t *bts;
    1348             :   u32 head;
    1349             :   sack_block_t *blk;
    1350             : 
    1351             :   /* Init data structures */
    1352           0 :   memset (tc, 0, sizeof (*tc));
    1353           0 :   tcp_bt_init (tc);
    1354           0 :   bt = tc->bt;
    1355             : 
    1356             :   /* 1) track first burst at time 1 */
    1357             :   /* [] --> [0:100] */
    1358           0 :   session_main.wrk[thread_index].last_vlib_time = 1;
    1359           0 :   tcp_bt_track_tx (tc, 100);
    1360           0 :   tc->snd_nxt += 100;
    1361             : 
    1362           0 :   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
    1363           0 :   TCP_TEST (pool_elts (bt->samples) == 1, "should have 1 sample");
    1364           0 :   bts = pool_elt_at_index (bt->samples, bt->head);
    1365           0 :   head = bt->head;
    1366           0 :   TCP_TEST (bts->min_seq == tc->snd_una, "min seq should be snd_una");
    1367           0 :   TCP_TEST (bts->next == TCP_BTS_INVALID_INDEX, "next should be invalid");
    1368           0 :   TCP_TEST (bts->prev == TCP_BTS_INVALID_INDEX, "prev should be invalid");
    1369           0 :   TCP_TEST (bts->tx_time == 1, "tx time should be 1");
    1370           0 :   TCP_TEST (!(bts->flags & TCP_BTS_IS_RXT), "not retransmitted");
    1371           0 :   TCP_TEST (!(bts->flags & TCP_BTS_IS_SACKED), "not sacked");
    1372             : 
    1373             :   /* 2) track second butst at time 2 */
    1374             :   /* --> [0:100][100:200] */
    1375           0 :   session_main.wrk[thread_index].last_vlib_time = 2;
    1376           0 :   tcp_bt_track_tx (tc, 100);
    1377           0 :   tc->snd_nxt += 100;
    1378             : 
    1379           0 :   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
    1380           0 :   TCP_TEST (pool_elts (bt->samples) == 2, "should have 2 samples");
    1381           0 :   bts = pool_elt_at_index (bt->samples, bt->head);
    1382           0 :   TCP_TEST (head == bt->head, "head is not updated");
    1383           0 :   TCP_TEST (bts->min_seq == tc->snd_una, "min seq should be snd_una");
    1384           0 :   TCP_TEST (bts->tx_time == 1, "tx time of head should be 1");
    1385             : 
    1386             :   /* 3) acked partially at time 3 */
    1387             :   /* ACK:150 */
    1388             :   /* --> [150:200] */
    1389           0 :   session_main.wrk[thread_index].last_vlib_time = 3;
    1390           0 :   tc->snd_una = 150;
    1391           0 :   tc->bytes_acked = 150;
    1392           0 :   tc->sack_sb.last_sacked_bytes = 0;
    1393           0 :   tcp_bt_sample_delivery_rate (tc, rs);
    1394             : 
    1395           0 :   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
    1396           0 :   TCP_TEST (pool_elts (bt->samples) == 1, "should have 1 sample");
    1397           0 :   TCP_TEST (head != bt->head, "head is updated");
    1398           0 :   head = bt->head;
    1399           0 :   bts = pool_elt_at_index (bt->samples, bt->head);
    1400           0 :   TCP_TEST (bts->min_seq == tc->snd_una, "min seq should be snd_una");
    1401           0 :   TCP_TEST (bts->tx_time == 2, "tx time should be 2");
    1402             : 
    1403             :   /* 4) track another burst at time 4 */
    1404             :   /* --> [150:200][200:300] */
    1405           0 :   session_main.wrk[thread_index].last_vlib_time = 4;
    1406           0 :   tcp_bt_track_tx (tc, 100);
    1407           0 :   tc->snd_nxt += 100;
    1408             : 
    1409           0 :   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
    1410           0 :   TCP_TEST (pool_elts (bt->samples) == 2, "should have 2 samples");
    1411           0 :   bts = pool_elt_at_index (bt->samples, bt->head);
    1412           0 :   TCP_TEST (head == bt->head, "head is not updated");
    1413           0 :   TCP_TEST (bts->min_seq == tc->snd_una, "min seq should be snd_una");
    1414           0 :   TCP_TEST (bts->tx_time == 2, "tx time of head should be 2");
    1415             : 
    1416             :   /* 5) track another burst at time 5 */
    1417             :   /* --> [150:200][200:300][300:400] */
    1418           0 :   session_main.wrk[thread_index].last_vlib_time = 5;
    1419           0 :   tcp_bt_track_tx (tc, 100);
    1420           0 :   tc->snd_nxt += 100;
    1421             : 
    1422           0 :   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
    1423           0 :   TCP_TEST (pool_elts (bt->samples) == 3, "should have 3 samples");
    1424           0 :   bts = pool_elt_at_index (bt->samples, bt->head);
    1425           0 :   TCP_TEST (head == bt->head, "head is not updated");
    1426           0 :   TCP_TEST (bts->min_seq == tc->snd_una, "min seq should be snd_una");
    1427           0 :   TCP_TEST (bts->tx_time == 2, "tx time of head should be 2");
    1428             : 
    1429             :   /* 6) acked with SACK option at time 6 */
    1430             :   /* ACK:250 + SACK[350:400] */
    1431             :   /* --> [250:300][300:350][350:400/sacked] */
    1432           0 :   session_main.wrk[thread_index].last_vlib_time = 6;
    1433           0 :   tc->snd_una = 250;
    1434           0 :   tc->bytes_acked = 100;
    1435           0 :   tc->sack_sb.last_sacked_bytes = 50;
    1436           0 :   vec_add2 (tc->rcv_opts.sacks, blk, 1);
    1437           0 :   blk->start = 350;
    1438           0 :   blk->end = 400;
    1439           0 :   tcp_bt_sample_delivery_rate (tc, rs);
    1440             : 
    1441           0 :   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
    1442           0 :   TCP_TEST (pool_elts (bt->samples) == 3, "should have 3 samples");
    1443           0 :   TCP_TEST (head != bt->head, "head is updated");
    1444           0 :   head = bt->head;
    1445           0 :   bts = pool_elt_at_index (bt->samples, bt->head);
    1446           0 :   TCP_TEST (bts->min_seq == tc->snd_una, "min seq should be snd_una");
    1447           0 :   TCP_TEST (bts->tx_time == 4, "tx time of head should be 4");
    1448           0 :   TCP_TEST (!(bts->flags & TCP_BTS_IS_SACKED), "not sacked");
    1449           0 :   bts = pool_elt_at_index (bt->samples, bts->next);
    1450           0 :   TCP_TEST (bts->tx_time == 5, "tx time of next should be 5");
    1451           0 :   TCP_TEST (!(bts->flags & TCP_BTS_IS_SACKED), "not sacked");
    1452           0 :   bts = pool_elt_at_index (bt->samples, bt->tail);
    1453           0 :   TCP_TEST (bts->tx_time == 5, "tx time of tail should be 5");
    1454           0 :   TCP_TEST ((bts->flags & TCP_BTS_IS_SACKED), "sacked");
    1455             : 
    1456             :   /* 7) track another burst at time 7 */
    1457             :   /* --> [250:300][300:350][350:400/sacked][400-500] */
    1458           0 :   session_main.wrk[thread_index].last_vlib_time = 7;
    1459           0 :   tcp_bt_track_tx (tc, 100);
    1460           0 :   tc->snd_nxt += 100;
    1461             : 
    1462           0 :   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
    1463           0 :   TCP_TEST (pool_elts (bt->samples) == 4, "should have 4 samples");
    1464           0 :   bts = pool_elt_at_index (bt->samples, bt->head);
    1465           0 :   TCP_TEST (head == bt->head, "head is not updated");
    1466           0 :   bts = pool_elt_at_index (bt->samples, bt->head);
    1467           0 :   TCP_TEST (bts->min_seq == tc->snd_una, "min seq should be snd_una");
    1468           0 :   TCP_TEST (bts->tx_time == 4, "tx time of head should be 4");
    1469           0 :   TCP_TEST (!(bts->flags & TCP_BTS_IS_SACKED), "not sacked");
    1470           0 :   bts = pool_elt_at_index (bt->samples, bts->next);
    1471           0 :   TCP_TEST (bts->tx_time == 5, "tx time of next should be 5");
    1472           0 :   TCP_TEST (!(bts->flags & TCP_BTS_IS_SACKED), "not sacked");
    1473           0 :   bts = pool_elt_at_index (bt->samples, bts->next);
    1474           0 :   TCP_TEST (bts->tx_time == 5, "tx time of next should be 5");
    1475           0 :   TCP_TEST ((bts->flags & TCP_BTS_IS_SACKED), "sacked");
    1476           0 :   bts = pool_elt_at_index (bt->samples, bt->tail);
    1477           0 :   TCP_TEST (bts->tx_time == 7, "tx time of tail should be 7");
    1478           0 :   TCP_TEST (!(bts->flags & TCP_BTS_IS_SACKED), "not sacked");
    1479             : 
    1480             :   /* 8) retransmit lost one at time 8 */
    1481             :   /* retransmit [250:300] */
    1482             :   /* --> [250:300][300:350][350:400/sacked][400-500] */
    1483           0 :   session_main.wrk[thread_index].last_vlib_time = 8;
    1484           0 :   tcp_bt_track_rxt (tc, 250, 300);
    1485           0 :   tcp_bt_sample_delivery_rate (tc, rs);
    1486             : 
    1487           0 :   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
    1488           0 :   TCP_TEST (pool_elts (bt->samples) == 4, "should have 4 samples");
    1489           0 :   TCP_TEST (head == bt->head, "head is not updated");
    1490           0 :   bts = pool_elt_at_index (bt->samples, bt->head);
    1491           0 :   TCP_TEST (bts->min_seq == tc->snd_una, "min seq should be snd_una");
    1492           0 :   TCP_TEST (bts->tx_time == 8, "tx time of head should be 8");
    1493           0 :   bts = pool_elt_at_index (bt->samples, bts->next);
    1494           0 :   TCP_TEST (bts->tx_time == 5, "tx time of next should be 5");
    1495           0 :   TCP_TEST (!(bts->flags & TCP_BTS_IS_SACKED), "not sacked");
    1496           0 :   bts = pool_elt_at_index (bt->samples, bts->next);
    1497           0 :   TCP_TEST (bts->tx_time == 5, "tx time of next should be 5");
    1498           0 :   TCP_TEST ((bts->flags & TCP_BTS_IS_SACKED), "sacked");
    1499           0 :   bts = pool_elt_at_index (bt->samples, bt->tail);
    1500           0 :   TCP_TEST (bts->tx_time == 7, "tx time of tail should be 7");
    1501           0 :   TCP_TEST (!(bts->flags & TCP_BTS_IS_SACKED), "not sacked");
    1502             : 
    1503             :   /* 9) acked with SACK option at time 9 */
    1504             :   /* ACK:350 + SACK[420:450] */
    1505             :   /* --> [400:420][420:450/sacked][450:400] */
    1506           0 :   session_main.wrk[thread_index].last_vlib_time = 6;
    1507           0 :   tc->snd_una = 400;
    1508           0 :   tc->bytes_acked = 150;
    1509           0 :   tc->sack_sb.last_sacked_bytes = 30;
    1510           0 :   vec_add2 (tc->rcv_opts.sacks, blk, 1);
    1511           0 :   blk->start = 420;
    1512           0 :   blk->end = 450;
    1513           0 :   tcp_bt_sample_delivery_rate (tc, rs);
    1514             : 
    1515           0 :   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
    1516           0 :   TCP_TEST (pool_elts (bt->samples) == 3, "should have 3 samples");
    1517           0 :   TCP_TEST (head != bt->head, "head is updated");
    1518           0 :   head = bt->head;
    1519           0 :   bts = pool_elt_at_index (bt->samples, bt->head);
    1520           0 :   TCP_TEST (bts->min_seq == tc->snd_una, "min seq should be snd_una");
    1521           0 :   TCP_TEST (bts->min_seq == 400 && bts->max_seq == 420, "bts [400:420]");
    1522           0 :   TCP_TEST (bts->tx_time == 7, "tx time of head should be 7");
    1523           0 :   TCP_TEST (!(bts->flags & TCP_BTS_IS_SACKED), "not sacked");
    1524           0 :   bts = pool_elt_at_index (bt->samples, bts->next);
    1525           0 :   TCP_TEST (bts->min_seq == 420 && bts->max_seq == 450, "bts [420:450]");
    1526           0 :   TCP_TEST (bts->tx_time == 7, "tx time of head should be 7");
    1527           0 :   TCP_TEST ((bts->flags & TCP_BTS_IS_SACKED), "sacked");
    1528           0 :   bts = pool_elt_at_index (bt->samples, bts->next);
    1529           0 :   TCP_TEST (bts->min_seq == 450 && bts->max_seq == 500, "bts [450:500]");
    1530           0 :   TCP_TEST (bts->tx_time == 7, "tx time of head should be 7");
    1531           0 :   TCP_TEST (!(bts->flags & TCP_BTS_IS_SACKED), "not sacked");
    1532             : 
    1533             :   /* 10) acked partially at time 10 */
    1534             :   /* ACK:500 */
    1535             :   /* --> [] */
    1536           0 :   session_main.wrk[thread_index].last_vlib_time = 3;
    1537           0 :   tc->snd_una = 500;
    1538           0 :   tc->bytes_acked = 100;
    1539           0 :   tc->sack_sb.last_sacked_bytes = 0;
    1540           0 :   tcp_bt_sample_delivery_rate (tc, rs);
    1541             : 
    1542           0 :   TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
    1543           0 :   TCP_TEST (pool_elts (bt->samples) == 0, "should have 0 samples");
    1544           0 :   TCP_TEST (bt->head == TCP_BTS_INVALID_INDEX, "bt->head is invalidated");
    1545           0 :   TCP_TEST (tc->snd_una == tc->snd_nxt, "snd_una == snd_nxt");
    1546             : 
    1547           0 :   return 0;
    1548             : }
    1549             : 
    1550             : static clib_error_t *
    1551           1 : tcp_test (vlib_main_t * vm,
    1552             :           unformat_input_t * input, vlib_cli_command_t * cmd_arg)
    1553             : {
    1554           1 :   int res = 0;
    1555             : 
    1556           1 :   vnet_session_enable_disable (vm, 1);
    1557             : 
    1558           2 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    1559             :     {
    1560           1 :       if (unformat (input, "sack"))
    1561             :         {
    1562           0 :           res = tcp_test_sack (vm, input);
    1563             :         }
    1564           1 :       else if (unformat (input, "session"))
    1565             :         {
    1566           0 :           res = tcp_test_session (vm, input);
    1567             :         }
    1568           1 :       else if (unformat (input, "lookup"))
    1569             :         {
    1570           0 :           res = tcp_test_lookup (vm, input);
    1571             :         }
    1572           1 :       else if (unformat (input, "delivery"))
    1573             :         {
    1574           0 :           res = tcp_test_delivery (vm, input);
    1575             :         }
    1576           1 :       else if (unformat (input, "bt"))
    1577             :         {
    1578           0 :           res = tcp_test_bt (vm, input);
    1579             :         }
    1580           1 :       else if (unformat (input, "all"))
    1581             :         {
    1582           1 :           if ((res = tcp_test_sack (vm, input)))
    1583           0 :             goto done;
    1584           1 :           if ((res = tcp_test_lookup (vm, input)))
    1585           0 :             goto done;
    1586           1 :           if ((res = tcp_test_delivery (vm, input)))
    1587           0 :             goto done;
    1588             :         }
    1589             :       else
    1590           0 :         break;
    1591             :     }
    1592             : 
    1593           1 : done:
    1594           1 :   if (res)
    1595           0 :     return clib_error_return (0, "TCP unit test failed");
    1596           1 :   return 0;
    1597             : }
    1598             : 
    1599             : /* *INDENT-OFF* */
    1600       16239 : VLIB_CLI_COMMAND (tcp_test_command, static) =
    1601             : {
    1602             :   .path = "test tcp",
    1603             :   .short_help = "internal tcp unit tests",
    1604             :   .function = tcp_test,
    1605             : };
    1606             : /* *INDENT-ON* */
    1607             : 
    1608             : /*
    1609             :  * fd.io coding-style-patch-verification: ON
    1610             :  *
    1611             :  * Local Variables:
    1612             :  * eval: (c-set-style "gnu")
    1613             :  * End:
    1614             :  */

Generated by: LCOV version 1.14