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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
15 #include <vnet/tcp/tcp.h>
17 #define TCP_TEST_I(_cond, _comment, _args...) \
19 int _evald = (_cond); \
21 fformat(stderr, "FAIL:%d: " _comment "\n", \
24 fformat(stderr, "PASS:%d: " _comment "\n", \
30 #define TCP_TEST(_cond, _comment, _args...) \
32 if (!TCP_TEST_I(_cond, _comment, ##_args)) { \
38 scoreboard_trace_elt_t sb_trace[] = {};
42 tcp_test_scoreboard_replay (vlib_main_t * vm, unformat_input_t * input)
45 tcp_connection_t _tc, *tc = &_tc;
48 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
50 if (unformat (input, "detail"))
54 clib_error_t *e = clib_error_return
55 (0, "unknown input `%U'", format_unformat_error, input);
56 clib_error_report (e);
61 #if TCP_SCOREBOARD_TRACE
62 tc->sack_sb.trace = sb_trace;
64 s = tcp_scoreboard_replay (s, tc, verbose);
65 vlib_cli_output (vm, "%v", s);
70 tcp_test_sack_rx (vlib_main_t * vm, unformat_input_t * input)
72 tcp_connection_t _tc, *tc = &_tc;
73 sack_scoreboard_t *sb = &tc->sack_sb;
74 sack_block_t *sacks = 0, block;
75 sack_scoreboard_hole_t *hole;
78 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
80 if (unformat (input, "verbose"))
82 else if (unformat (input, "replay"))
83 return tcp_test_scoreboard_replay (vm, input);
86 clib_memset (tc, 0, sizeof (*tc));
89 tc->snd_una_max = 1000;
91 tc->rcv_opts.flags |= TCP_OPTS_FLAG_SACK;
93 scoreboard_init (&tc->sack_sb);
95 for (i = 0; i < 1000 / 100; i++)
97 block.start = i * 100;
98 block.end = (i + 1) * 100;
99 vec_add1 (sacks, block);
106 for (i = 0; i < 1000 / 200; i++)
108 vec_add1 (tc->rcv_opts.sacks, sacks[i * 2]);
110 tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
111 tcp_rcv_sacks (tc, 0);
114 vlib_cli_output (vm, "sb after even blocks (mss %u):\n%U",
115 tc->snd_mss, format_tcp_scoreboard, sb, tc);
117 TCP_TEST ((pool_elts (sb->holes) == 5),
118 "scoreboard has %d elements", pool_elts (sb->holes));
120 /* First SACK block should be rejected */
121 hole = scoreboard_first_hole (sb);
122 TCP_TEST ((hole->start == 0 && hole->end == 200),
123 "first hole start %u end %u", hole->start, hole->end);
124 hole = scoreboard_last_hole (sb);
125 TCP_TEST ((hole->start == 900 && hole->end == 1000),
126 "last hole start %u end %u", hole->start, hole->end);
127 TCP_TEST ((sb->sacked_bytes == 400), "sacked bytes %d", sb->sacked_bytes);
128 TCP_TEST ((!sb->is_reneging), "is not reneging");
129 TCP_TEST ((sb->last_sacked_bytes == 400),
130 "last sacked bytes %d", sb->last_sacked_bytes);
131 TCP_TEST ((sb->high_sacked == 900), "high sacked %u", sb->high_sacked);
132 TCP_TEST ((sb->lost_bytes == 300), "lost bytes %u", sb->lost_bytes);
138 vec_reset_length (tc->rcv_opts.sacks);
139 for (i = 0; i < 1000 / 200; i++)
141 vec_add1 (tc->rcv_opts.sacks, sacks[i * 2 + 1]);
143 tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
144 tcp_rcv_sacks (tc, 0);
147 vlib_cli_output (vm, "\nsb after odd blocks:\n%U", format_tcp_scoreboard,
150 hole = scoreboard_first_hole (sb);
151 TCP_TEST ((pool_elts (sb->holes) == 1),
152 "scoreboard has %d holes", pool_elts (sb->holes));
153 TCP_TEST ((hole->start == 0 && hole->end == 100),
154 "first hole start %u end %u", hole->start, hole->end);
155 TCP_TEST ((sb->sacked_bytes == 900), "sacked bytes %d", sb->sacked_bytes);
156 TCP_TEST ((!sb->is_reneging), "is not reneging");
157 TCP_TEST ((sb->high_sacked == 1000), "high sacked %u", sb->high_sacked);
158 TCP_TEST ((sb->last_sacked_bytes == 500),
159 "last sacked bytes %d", sb->last_sacked_bytes);
160 TCP_TEST ((sb->lost_bytes == 100), "lost bytes %u", sb->lost_bytes);
163 * Ack until byte 100 - this is reneging because we should ack until 1000
165 tcp_rcv_sacks (tc, 100);
167 vlib_cli_output (vm, "\nack until byte 100:\n%U", format_tcp_scoreboard,
170 TCP_TEST ((pool_elts (sb->holes) == 0), "scoreboard has %d elements",
171 pool_elts (sb->holes));
172 TCP_TEST ((sb->is_reneging), "is reneging");
175 * Sack all up to 1000
178 tcp_rcv_sacks (tc, 1000);
179 TCP_TEST ((sb->high_sacked == 1000), "max sacked byte %u", sb->high_sacked);
180 TCP_TEST ((sb->sacked_bytes == 0), "sacked bytes %d", sb->sacked_bytes);
181 TCP_TEST ((sb->last_sacked_bytes == 0),
182 "last sacked bytes %d", sb->last_sacked_bytes);
183 TCP_TEST ((sb->lost_bytes == 0), "lost bytes %u", sb->lost_bytes);
184 TCP_TEST ((!sb->is_reneging), "is not reneging");
191 vec_reset_length (tc->rcv_opts.sacks);
195 vec_add1 (tc->rcv_opts.sacks, block);
197 tc->snd_una_max = 1500;
200 tcp_rcv_sacks (tc, 1000);
203 vlib_cli_output (vm, "\nadd [1200, 1300] snd_una_max 1500, snd_una 1000:"
204 " \n%U", format_tcp_scoreboard, sb, tc);
206 TCP_TEST ((!sb->is_reneging), "is not reneging");
207 TCP_TEST ((pool_elts (sb->holes) == 2),
208 "scoreboard has %d holes", pool_elts (sb->holes));
209 hole = scoreboard_first_hole (sb);
210 TCP_TEST ((hole->start == 1000 && hole->end == 1200),
211 "first hole start %u end %u", hole->start, hole->end);
212 TCP_TEST ((sb->high_sacked == 1300), "max sacked byte %u", sb->high_sacked);
213 hole = scoreboard_last_hole (sb);
214 TCP_TEST ((hole->start == 1300 && hole->end == 1500),
215 "last hole start %u end %u", hole->start, hole->end);
216 TCP_TEST ((sb->sacked_bytes == 100), "sacked bytes %d", sb->sacked_bytes);
217 TCP_TEST ((sb->lost_bytes == 0), "lost bytes %u", sb->lost_bytes);
223 vec_reset_length (tc->rcv_opts.sacks);
224 /* Ack up to 1300 to avoid reneging */
225 tcp_rcv_sacks (tc, 1300);
228 vlib_cli_output (vm, "\nsb ack up to byte 1300:\n%U",
229 format_tcp_scoreboard, sb, tc);
231 TCP_TEST ((sb->sacked_bytes == 0), "sacked bytes %d", sb->sacked_bytes);
232 TCP_TEST ((pool_elts (sb->holes) == 1),
233 "scoreboard has %d elements", pool_elts (sb->holes));
234 TCP_TEST ((sb->last_bytes_delivered == 100), "last bytes delivered %d",
235 sb->last_bytes_delivered);
236 TCP_TEST ((sb->lost_bytes == 0), "lost bytes %u", sb->lost_bytes);
237 TCP_TEST ((sb->head != TCP_INVALID_SACK_HOLE_INDEX), "head %u", sb->head);
238 TCP_TEST ((sb->tail != TCP_INVALID_SACK_HOLE_INDEX), "tail %u", sb->tail);
239 TCP_TEST ((!sb->is_reneging), "is not reneging");
242 * Add some more blocks and then remove all
244 vec_reset_length (tc->rcv_opts.sacks);
246 tc->snd_nxt = tc->snd_una_max = 1900;
247 for (i = 0; i < 5; i++)
249 block.start = i * 100 + 1200;
250 block.end = (i + 1) * 100 + 1200;
251 vec_add1 (tc->rcv_opts.sacks, block);
253 tcp_rcv_sacks (tc, 1900);
255 scoreboard_clear (sb);
257 vlib_cli_output (vm, "\nsb cleared all:\n%U", format_tcp_scoreboard, sb,
260 TCP_TEST ((pool_elts (sb->holes) == 0),
261 "number of holes %d", pool_elts (sb->holes));
262 TCP_TEST ((sb->head == TCP_INVALID_SACK_HOLE_INDEX), "head %u", sb->head);
263 TCP_TEST ((sb->tail == TCP_INVALID_SACK_HOLE_INDEX), "tail %u", sb->tail);
266 * Re-inject odd blocks and ack them all
270 tc->snd_una_max = 1000;
272 vec_reset_length (tc->rcv_opts.sacks);
273 for (i = 0; i < 5; i++)
275 vec_add1 (tc->rcv_opts.sacks, sacks[i * 2 + 1]);
277 tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
278 tcp_rcv_sacks (tc, 0);
280 vlib_cli_output (vm, "\nsb added odd blocks snd_una 0 snd_una_max 1000:"
281 "\n%U", format_tcp_scoreboard, sb, tc);
282 TCP_TEST ((pool_elts (sb->holes) == 5),
283 "scoreboard has %d elements", pool_elts (sb->holes));
284 TCP_TEST ((sb->lost_bytes == 300), "lost bytes %u", sb->lost_bytes);
285 hole = scoreboard_last_hole (sb);
286 TCP_TEST ((hole->end == 900), "last hole end %u", hole->end);
287 TCP_TEST ((sb->high_sacked == 1000), "high sacked %u", sb->high_sacked);
290 * Renege bytes from 950 to 1000
292 tcp_rcv_sacks (tc, 950);
295 vlib_cli_output (vm, "\nack [0, 950]:\n%U", format_tcp_scoreboard, sb,
298 TCP_TEST ((pool_elts (sb->holes) == 0), "scoreboard has %d elements",
299 pool_elts (sb->holes));
300 TCP_TEST ((sb->is_reneging), "is reneging");
301 TCP_TEST ((sb->sacked_bytes == 50), "sacked bytes %d", sb->sacked_bytes);
302 TCP_TEST ((sb->last_sacked_bytes == 0), "last sacked bytes %d",
303 sb->last_sacked_bytes);
304 TCP_TEST ((sb->lost_bytes == 0), "lost bytes %u", sb->lost_bytes);
305 TCP_TEST ((sb->high_sacked == 1000), "high sacked %u", sb->high_sacked);
307 scoreboard_clear (sb);
310 * Inject one block, ack it and overlap hole
314 tc->snd_una_max = 1000;
319 vec_add1 (tc->rcv_opts.sacks, block);
320 tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
322 tcp_rcv_sacks (tc, 0);
325 vlib_cli_output (vm, "\nsb added [100, 500] snd_una 0 snd_una_max 1000:"
326 "\n%U", format_tcp_scoreboard, sb, tc);
328 tcp_rcv_sacks (tc, 800);
331 vlib_cli_output (vm, "\nsb ack [0, 800]:\n%U", format_tcp_scoreboard, sb,
334 TCP_TEST ((pool_elts (sb->holes) == 1),
335 "scoreboard has %d elements", pool_elts (sb->holes));
336 TCP_TEST ((!sb->is_reneging), "is not reneging");
337 TCP_TEST ((sb->sacked_bytes == 0), "sacked bytes %d", sb->sacked_bytes);
338 TCP_TEST ((sb->last_sacked_bytes == 0), "last sacked bytes %d",
339 sb->last_sacked_bytes);
340 TCP_TEST ((sb->last_bytes_delivered == 400),
341 "last bytes delivered %d", sb->last_bytes_delivered);
342 TCP_TEST ((sb->lost_bytes == 0), "lost bytes %u", sb->lost_bytes);
343 TCP_TEST ((sb->head != TCP_INVALID_SACK_HOLE_INDEX), "head %u", sb->head);
344 TCP_TEST ((sb->tail != TCP_INVALID_SACK_HOLE_INDEX), "tail %u", sb->tail);
347 * One hole close to head, patch head, split in two and start acking
350 scoreboard_clear (sb);
352 tc->snd_una_max = 1000;
357 vec_add1 (tc->rcv_opts.sacks, block);
358 tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
360 tcp_rcv_sacks (tc, 0);
362 vlib_cli_output (vm, "\nsb added [500, 1000]:\n%U",
363 format_tcp_scoreboard, sb, tc);
364 TCP_TEST ((sb->sacked_bytes == 500), "sacked bytes %d", sb->sacked_bytes);
365 TCP_TEST ((sb->last_sacked_bytes == 500), "last sacked bytes %d",
366 sb->last_sacked_bytes);
367 TCP_TEST ((sb->lost_bytes == 500), "lost bytes %u", sb->lost_bytes);
369 vec_reset_length (tc->rcv_opts.sacks);
372 vec_add1 (tc->rcv_opts.sacks, block);
373 tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
374 tcp_rcv_sacks (tc, 100);
376 vlib_cli_output (vm, "\nsb added [0, 100] [300, 400]:\n%U",
377 format_tcp_scoreboard, sb, tc);
378 TCP_TEST ((pool_elts (sb->holes) == 2),
379 "scoreboard has %d elements", pool_elts (sb->holes));
380 TCP_TEST ((sb->sacked_bytes == 600), "sacked bytes %d", sb->sacked_bytes);
381 TCP_TEST ((sb->last_sacked_bytes == 100), "last sacked bytes %d",
382 sb->last_sacked_bytes);
383 TCP_TEST ((sb->last_bytes_delivered == 0), "last bytes delivered %d",
384 sb->last_bytes_delivered);
385 TCP_TEST ((sb->lost_bytes == 300), "lost bytes %u", sb->lost_bytes);
388 * Ack [100 300] in two steps
390 * Step 1. Ack [100 200] which delivers 100 of the bytes lost
393 tcp_rcv_sacks (tc, 200);
394 TCP_TEST ((sb->sacked_bytes == 600), "sacked bytes %d", sb->sacked_bytes);
395 TCP_TEST ((sb->last_bytes_delivered == 0), "last bytes delivered %d",
396 sb->last_bytes_delivered);
397 TCP_TEST ((sb->lost_bytes == 200), "lost bytes %u", sb->lost_bytes);
400 * Step 2. Ack up to 300, although 300 400 is sacked, so this is interpreted
404 tcp_rcv_sacks (tc, 300);
406 vlib_cli_output (vm, "\nacked [100, 300] in two steps:\n%U",
407 format_tcp_scoreboard, sb, tc);
408 TCP_TEST ((sb->sacked_bytes == 600), "sacked bytes %d", sb->sacked_bytes);
409 TCP_TEST ((sb->lost_bytes == 100), "lost bytes %u", sb->lost_bytes);
410 TCP_TEST ((sb->last_bytes_delivered == 0), "last bytes delivered %d",
411 sb->last_bytes_delivered);
412 TCP_TEST ((sb->is_reneging), "is reneging");
415 * Ack [300 500]. Delivers reneged segment [300 400] and reneges bytes
419 tcp_rcv_sacks (tc, 500);
421 vlib_cli_output (vm, "\nacked [400, 500]:\n%U", format_tcp_scoreboard, sb,
423 TCP_TEST ((pool_elts (sb->holes) == 0),
424 "scoreboard has %d elements", pool_elts (sb->holes));
425 TCP_TEST ((sb->sacked_bytes == 500), "sacked bytes %d", sb->sacked_bytes);
426 TCP_TEST ((sb->last_sacked_bytes == 0), "last sacked bytes %d",
427 sb->last_sacked_bytes);
428 TCP_TEST ((sb->last_bytes_delivered == 100), "last bytes delivered %d",
429 sb->last_bytes_delivered);
430 TCP_TEST ((sb->is_reneging), "is reneging");
431 TCP_TEST ((sb->head == TCP_INVALID_SACK_HOLE_INDEX), "head %u", sb->head);
432 TCP_TEST ((sb->tail == TCP_INVALID_SACK_HOLE_INDEX), "tail %u", sb->tail);
435 * Ack up to 1000 to deliver all bytes
438 tcp_rcv_sacks (tc, 1000);
440 vlib_cli_output (vm, "\nAck high sacked:\n%U", format_tcp_scoreboard, sb,
442 TCP_TEST ((sb->last_sacked_bytes == 0), "last sacked bytes %d",
443 sb->last_sacked_bytes);
444 TCP_TEST ((sb->last_bytes_delivered == 500), "last bytes delivered %d",
445 sb->last_bytes_delivered);
446 TCP_TEST ((!sb->is_reneging), "is not reneging");
449 * Add [1200, 1500] and test that [1000, 1200] is lost (bytes condition)
450 * snd_una = 1000 and snd_una_max = 1600
453 tc->snd_nxt = tc->snd_una_max = 1600;
454 vec_reset_length (tc->rcv_opts.sacks);
457 vec_add1 (tc->rcv_opts.sacks, block);
458 tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
459 tcp_rcv_sacks (tc, 1000);
461 vlib_cli_output (vm, "\nacked [1200, 1500] test first hole is lost:\n%U",
462 format_tcp_scoreboard, sb, tc);
463 TCP_TEST ((pool_elts (sb->holes) == 2), "scoreboard has %d elements",
464 pool_elts (sb->holes));
465 TCP_TEST ((sb->sacked_bytes == 300), "sacked bytes %d", sb->sacked_bytes);
466 TCP_TEST ((sb->last_sacked_bytes == 300), "last sacked bytes %d",
467 sb->last_sacked_bytes);
468 TCP_TEST ((sb->last_bytes_delivered == 0), "last bytes delivered %d",
469 sb->last_bytes_delivered);
470 TCP_TEST ((sb->lost_bytes == 200), "lost bytes %u", sb->lost_bytes);
471 TCP_TEST ((!sb->is_reneging), "is not reneging");
477 tcp_test_sack_tx (vlib_main_t * vm, unformat_input_t * input)
479 tcp_connection_t _tc, *tc = &_tc;
481 int i, verbose = 0, expected;
483 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
485 if (unformat (input, "verbose"))
489 vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
495 clib_memset (tc, 0, sizeof (*tc));
498 * Add odd sack block pairs
500 for (i = 1; i < 10; i += 2)
502 tcp_update_sack_list (tc, i * 100, (i + 1) * 100);
505 TCP_TEST ((vec_len (tc->snd_sacks) == 5), "sack blocks %d expected %d",
506 vec_len (tc->snd_sacks), 5);
507 TCP_TEST ((tc->snd_sacks[0].start = 900),
508 "first sack block start %u expected %u", tc->snd_sacks[0].start,
512 * Try to add one extra
514 sacks = vec_dup (tc->snd_sacks);
516 tcp_update_sack_list (tc, 1100, 1200);
518 vlib_cli_output (vm, "add new segment [1100, 1200]\n%U",
519 format_tcp_sacks, tc);
520 expected = 5 < TCP_MAX_SACK_BLOCKS ? 6 : 5;
521 TCP_TEST ((vec_len (tc->snd_sacks) == expected),
522 "sack blocks %d expected %d", vec_len (tc->snd_sacks), expected);
523 TCP_TEST ((tc->snd_sacks[0].start == 1100),
524 "first sack block start %u expected %u", tc->snd_sacks[0].start,
528 vec_free (tc->snd_sacks);
529 tc->snd_sacks = sacks;
532 * Overlap first 2 segment
535 tcp_update_sack_list (tc, 300, 300);
537 vlib_cli_output (vm, "overlap first 2 segments:\n%U",
538 format_tcp_sacks, tc);
539 TCP_TEST ((vec_len (tc->snd_sacks) == 3), "sack blocks %d expected %d",
540 vec_len (tc->snd_sacks), 3);
541 TCP_TEST ((tc->snd_sacks[0].start == 900),
542 "first sack block start %u expected %u", tc->snd_sacks[0].start,
548 tcp_update_sack_list (tc, 1100, 1200);
550 vlib_cli_output (vm, "add new segment [1100, 1200]\n%U",
551 format_tcp_sacks, tc);
552 TCP_TEST ((vec_len (tc->snd_sacks) == 4), "sack blocks %d expected %d",
553 vec_len (tc->snd_sacks), 4);
554 TCP_TEST ((tc->snd_sacks[0].start == 1100),
555 "first sack block start %u expected %u", tc->snd_sacks[0].start,
559 * Join middle segments
561 tcp_update_sack_list (tc, 800, 900);
563 vlib_cli_output (vm, "join middle segments [800, 900]\n%U",
564 format_tcp_sacks, tc);
566 TCP_TEST ((vec_len (tc->snd_sacks) == 3), "sack blocks %d expected %d",
567 vec_len (tc->snd_sacks), 3);
568 TCP_TEST ((tc->snd_sacks[0].start == 700),
569 "first sack block start %u expected %u", tc->snd_sacks[0].start,
573 * Advance rcv_nxt to overlap all
576 tcp_update_sack_list (tc, 1200, 1200);
578 vlib_cli_output (vm, "advance rcv_nxt to 1200\n%U", format_tcp_sacks, tc);
579 TCP_TEST ((vec_len (tc->snd_sacks) == 0), "sack blocks %d expected %d",
580 vec_len (tc->snd_sacks), 0);
584 * Add 2 blocks, overwrite first and update rcv_nxt to also remove it
587 vec_reset_length (tc->snd_sacks);
590 tcp_update_sack_list (tc, 100, 200);
591 tcp_update_sack_list (tc, 300, 400);
594 vlib_cli_output (vm, "add [100, 200] [300, 400]\n%U",
595 format_tcp_sacks, tc);
596 TCP_TEST ((vec_len (tc->snd_sacks) == 2),
597 "sack blocks %d expected %d", vec_len (tc->snd_sacks), 2);
598 TCP_TEST ((tc->snd_sacks[0].start == 300),
599 "first sack block start %u expected %u", tc->snd_sacks[0].start,
603 tcp_update_sack_list (tc, 100, 100);
605 vlib_cli_output (vm, "add [100, 200] rcv_nxt = 100\n%U",
606 format_tcp_sacks, tc);
607 TCP_TEST ((vec_len (tc->snd_sacks) == 1),
608 "sack blocks %d expected %d", vec_len (tc->snd_sacks), 1);
609 TCP_TEST ((tc->snd_sacks[0].start == 300),
610 "first sack block start %u expected %u", tc->snd_sacks[0].start,
616 tcp_test_sack (vlib_main_t * vm, unformat_input_t * input)
621 if (unformat_check_input (input) == UNFORMAT_END_OF_INPUT)
623 if (tcp_test_sack_tx (vm, input))
628 if (tcp_test_sack_rx (vm, input))
635 if (unformat (input, "tx"))
637 res = tcp_test_sack_tx (vm, input);
639 else if (unformat (input, "rx"))
641 res = tcp_test_sack_rx (vm, input);
649 tcp_test_lookup (vlib_main_t * vm, unformat_input_t * input)
651 session_main_t *smm = &session_main;
652 tcp_main_t *tm = &tcp_main;
653 transport_connection_t _tc1, *tc1 = &_tc1, _tc2, *tc2 = &_tc2, *tconn;
654 tcp_connection_t *tc;
656 u8 cmp = 0, is_filtered = 0;
660 * Allocate fake session and connection 1
662 pool_get (smm->wrk[0].sessions, s);
663 clib_memset (s, 0, sizeof (*s));
664 s->session_index = sidx = s - smm->wrk[0].sessions;
666 pool_get (tm->connections[0], tc);
667 clib_memset (tc, 0, sizeof (*tc));
668 tc->connection.c_index = tc - tm->connections[0];
669 tc->connection.s_index = s->session_index;
670 s->connection_index = tc->connection.c_index;
672 tc->connection.lcl_ip.ip4.as_u32 = clib_host_to_net_u32 (0x06000101);
673 tc->connection.rmt_ip.ip4.as_u32 = clib_host_to_net_u32 (0x06000103);
674 tc->connection.lcl_port = 35051;
675 tc->connection.rmt_port = 53764;
676 tc->connection.proto = TRANSPORT_PROTO_TCP;
677 tc->connection.is_ip4 = 1;
678 clib_memcpy_fast (tc1, &tc->connection, sizeof (*tc1));
681 * Allocate fake session and connection 2
683 pool_get (smm->wrk[0].sessions, s);
684 clib_memset (s, 0, sizeof (*s));
685 s->session_index = s - smm->wrk[0].sessions;
687 pool_get (tm->connections[0], tc);
688 clib_memset (tc, 0, sizeof (*tc));
689 tc->connection.c_index = tc - tm->connections[0];
690 tc->connection.s_index = s->session_index;
691 s->connection_index = tc->connection.c_index;
693 tc->connection.lcl_ip.ip4.as_u32 = clib_host_to_net_u32 (0x06000101);
694 tc->connection.rmt_ip.ip4.as_u32 = clib_host_to_net_u32 (0x06000102);
695 tc->connection.lcl_port = 38225;
696 tc->connection.rmt_port = 53764;
697 tc->connection.proto = TRANSPORT_PROTO_TCP;
698 tc->connection.is_ip4 = 1;
699 clib_memcpy_fast (tc2, &tc->connection, sizeof (*tc2));
702 * Confirm that connection lookup works
705 s1 = pool_elt_at_index (smm->wrk[0].sessions, sidx);
706 session_lookup_add_connection (tc1, session_handle (s1));
707 tconn = session_lookup_connection_wt4 (0, &tc1->lcl_ip.ip4,
709 tc1->lcl_port, tc1->rmt_port,
710 tc1->proto, 0, &is_filtered);
712 TCP_TEST ((tconn != 0), "connection exists");
713 cmp = (memcmp (&tconn->rmt_ip, &tc1->rmt_ip, sizeof (tc1->rmt_ip)) == 0);
714 TCP_TEST ((cmp), "rmt ip is identical %d", cmp);
715 TCP_TEST ((tconn->lcl_port == tc1->lcl_port),
716 "rmt port is identical %d", tconn->lcl_port == tc1->lcl_port);
719 * Non-existing connection lookup should not work
722 tconn = session_lookup_connection_wt4 (0, &tc2->lcl_ip.ip4,
724 tc2->lcl_port, tc2->rmt_port,
725 tc2->proto, 0, &is_filtered);
726 TCP_TEST ((tconn == 0), "lookup result should be null");
729 * Delete and lookup again
731 session_lookup_del_connection (tc1);
732 tconn = session_lookup_connection_wt4 (0, &tc1->lcl_ip.ip4,
734 tc1->lcl_port, tc1->rmt_port,
735 tc1->proto, 0, &is_filtered);
736 TCP_TEST ((tconn == 0), "lookup result should be null");
737 tconn = session_lookup_connection_wt4 (0, &tc2->lcl_ip.ip4,
739 tc2->lcl_port, tc2->rmt_port,
740 tc2->proto, 0, &is_filtered);
741 TCP_TEST ((tconn == 0), "lookup result should be null");
744 * Re-add and lookup tc2
746 session_lookup_add_connection (tc1, tc1->s_index);
747 tconn = session_lookup_connection_wt4 (0, &tc2->lcl_ip.ip4,
749 tc2->lcl_port, tc2->rmt_port,
750 tc2->proto, 0, &is_filtered);
751 TCP_TEST ((tconn == 0), "lookup result should be null");
757 tcp_test_session (vlib_main_t * vm, unformat_input_t * input)
760 tcp_connection_t *tc0;
761 ip4_address_t local, remote;
762 u16 local_port, remote_port;
763 tcp_main_t *tm = vnet_get_tcp_main ();
767 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
769 if (unformat (input, "del"))
771 else if (unformat (input, "add"))
779 local.as_u32 = clib_host_to_net_u32 (0x06000101);
780 remote.as_u32 = clib_host_to_net_u32 (0x06000102);
781 local_port = clib_host_to_net_u16 (1234);
782 remote_port = clib_host_to_net_u16 (11234);
784 pool_get (tm->connections[0], tc0);
785 clib_memset (tc0, 0, sizeof (*tc0));
787 tc0->state = TCP_STATE_ESTABLISHED;
789 tc0->c_c_index = tc0 - tm->connections[0];
790 tc0->c_lcl_port = local_port;
791 tc0->c_rmt_port = remote_port;
793 tc0->c_thread_index = 0;
794 tc0->c_lcl_ip4.as_u32 = local.as_u32;
795 tc0->c_rmt_ip4.as_u32 = remote.as_u32;
796 tc0->rcv_opts.mss = 1450;
797 tcp_connection_init_vars (tc0);
799 TCP_EVT (TCP_EVT_OPEN, tc0);
801 if (session_stream_accept (&tc0->connection, 0 /* listener index */ ,
802 0 /* thread index */ , 0 /* notify */ ))
803 clib_warning ("stream_session_accept failed");
805 session_stream_accept_notify (&tc0->connection);
809 tc0 = tcp_connection_get (0 /* connection index */ , 0 /* thread */ );
810 tc0->state = TCP_STATE_CLOSED;
811 session_transport_closing_notify (&tc0->connection);
818 tbt_seq_lt (u32 a, u32 b)
820 return seq_lt (a, b);
824 tcp_test_delivery (vlib_main_t * vm, unformat_input_t * input)
826 u32 thread_index = 0, snd_una, *min_seqs = 0;
827 tcp_rate_sample_t _rs = { 0 }, *rs = &_rs;
828 tcp_connection_t _tc, *tc = &_tc;
829 sack_scoreboard_t *sb = &tc->sack_sb;
830 int __clib_unused verbose = 0, i;
831 u64 rate = 1000, burst = 100;
832 sack_block_t *sacks = 0;
833 tcp_byte_tracker_t *bt;
834 rb_node_t *root, *rbn;
835 tcp_bt_sample_t *bts;
837 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
839 if (unformat (input, "verbose"))
843 vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
849 /* Init data structures */
850 memset (tc, 0, sizeof (*tc));
851 session_main.wrk[thread_index].last_vlib_time = 1;
852 transport_connection_tx_pacer_update (&tc->connection, rate);
858 * Track simple bursts without rxt
861 /* 1) track first burst a time 1 */
862 tcp_bt_track_tx (tc);
864 TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
865 TCP_TEST (pool_elts (bt->samples) == 1, "should have 1 sample");
866 bts = pool_elt_at_index (bt->samples, bt->head);
867 TCP_TEST (bts->min_seq == tc->snd_una, "min seq should be snd_una");
868 TCP_TEST (bts->next == TCP_BTS_INVALID_INDEX, "next should be invalid");
869 TCP_TEST (bts->prev == TCP_BTS_INVALID_INDEX, "prev should be invalid");
870 TCP_TEST (bts->delivered_time == 1, "delivered time should be 1");
871 TCP_TEST (bts->delivered == 0, "delivered should be 0");
872 TCP_TEST (!(bts->flags & TCP_BTS_IS_RXT), "not retransmitted");
873 TCP_TEST (!(bts->flags & TCP_BTS_IS_APP_LIMITED), "not app limited");
875 /* 2) check delivery rate at time 2 */
876 session_main.wrk[thread_index].last_vlib_time = 2;
877 tc->snd_una = tc->snd_nxt = burst;
878 tc->bytes_acked = burst;
880 tcp_bt_sample_delivery_rate (tc, rs);
882 TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
883 TCP_TEST (pool_elts (bt->samples) == 0, "sample should've been consumed");
884 TCP_TEST (tc->delivered_time == 2, "delivered time should be 2");
885 TCP_TEST (tc->delivered == burst, "delivered should be 100");
886 TCP_TEST (rs->interval_time == 1, "ack time should be 1");
887 TCP_TEST (rs->delivered == burst, "delivered should be 100");
888 TCP_TEST (rs->prior_delivered == 0, "sample delivered should be 0");
889 TCP_TEST (!(rs->flags & TCP_BTS_IS_RXT), "not retransmitted");
890 TCP_TEST (tc->first_tx_time == 1, "first_tx_time %u", tc->first_tx_time);
892 /* 3) track second burst at time 2 */
893 tcp_bt_track_tx (tc);
894 tc->snd_nxt += burst;
896 /* 4) track second burst at time 3 */
897 session_main.wrk[thread_index].last_vlib_time = 3;
898 tcp_bt_track_tx (tc);
899 tc->snd_nxt += burst;
901 TCP_TEST (pool_elts (bt->samples) == 2, "should have 2 samples");
903 TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
904 bts = pool_elt_at_index (bt->samples, bt->head);
905 TCP_TEST (bts->min_seq == tc->snd_una, "min seq should be snd_una");
906 TCP_TEST (bts->next == bt->tail, "next should tail");
908 bts = pool_elt_at_index (bt->samples, bt->tail);
909 TCP_TEST (bts->min_seq == tc->snd_nxt - burst,
910 "min seq should be snd_nxt prior to burst");
911 TCP_TEST (bts->prev == bt->head, "prev should be head");
913 /* 5) check delivery rate at time 4 */
914 session_main.wrk[thread_index].last_vlib_time = 4;
915 tc->snd_una = tc->snd_nxt;
916 tc->bytes_acked = 2 * burst;
918 tcp_bt_sample_delivery_rate (tc, rs);
920 TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
921 TCP_TEST (pool_elts (bt->samples) == 0, "sample should've been consumed");
922 TCP_TEST (tc->delivered_time == 4, "delivered time should be 4");
923 TCP_TEST (tc->delivered == 3 * burst, "delivered should be 300 is %u",
925 TCP_TEST (rs->interval_time == 2, "ack time should be 2");
926 TCP_TEST (rs->delivered == 2 * burst, "delivered should be 200");
927 TCP_TEST (rs->prior_delivered == burst, "delivered should be 100");
928 TCP_TEST (!(rs->flags & TCP_BTS_IS_RXT), "not retransmitted");
929 TCP_TEST (tc->first_tx_time == 2, "first_tx_time %u", tc->first_tx_time);
932 * Track retransmissions
934 * snd_una should be 300 at this point
937 snd_una = tc->snd_una;
939 /* 1) track first burst at time 4 */
940 tcp_bt_track_tx (tc);
941 tc->snd_nxt += burst;
943 /* 2) track second burst at time 5 */
944 session_main.wrk[thread_index].last_vlib_time = 5;
945 tcp_bt_track_tx (tc);
946 tc->snd_nxt += burst;
948 /* 3) track third burst at time 6 */
949 session_main.wrk[thread_index].last_vlib_time = 6;
950 tcp_bt_track_tx (tc);
951 tc->snd_nxt += burst;
953 /* 4) track fourth burst at time 7 */
954 session_main.wrk[thread_index].last_vlib_time = 7;
955 /* Limited until last burst is acked */
956 tc->app_limited = snd_una + 4 * burst - 1;
957 tcp_bt_track_tx (tc);
958 tc->snd_nxt += burst;
960 /* 5) check delivery rate at time 8
962 * tc->snd_una = snd_una + 10
964 * [snd_una + burst, snd_una + burst + 10]
965 * [snd_una + 2 * burst + 10, snd_una + 2 * burst + 20]
967 session_main.wrk[thread_index].last_vlib_time = 8;
969 tc->bytes_acked = 10;
970 sb->last_sacked_bytes = 20;
972 TCP_TEST (pool_elts (bt->samples) == 4, "there should be 4 samples");
974 vec_validate (sacks, 1);
975 sacks[0].start = snd_una + burst;
976 sacks[0].end = snd_una + burst + 10;
977 sacks[1].start = snd_una + 2 * burst + 10;
978 sacks[1].end = snd_una + 2 * burst + 20;
979 tc->rcv_opts.sacks = sacks;
981 tcp_bt_sample_delivery_rate (tc, rs);
983 TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
984 TCP_TEST (pool_elts (bt->samples) == 4, "there should be 4 samples");
985 TCP_TEST (tc->delivered_time == 8, "delivered time should be 8");
986 TCP_TEST (tc->delivered == 3 * burst + 30, "delivered should be %u is %u",
987 3 * burst + 30, tc->delivered);
988 /* All 3 samples have the same delivered number of bytes. So the first is
989 * the reference for delivery estimate. */
990 TCP_TEST (rs->interval_time == 4, "ack time should be 4 is %.2f",
992 TCP_TEST (rs->delivered == 30, "delivered should be 30");
993 TCP_TEST (rs->prior_delivered == 3 * burst,
994 "sample delivered should be %u", 3 * burst);
995 TCP_TEST (!(rs->flags & TCP_BTS_IS_RXT), "not retransmitted");
996 TCP_TEST (!(rs->flags & TCP_BTS_IS_APP_LIMITED), "not app limited");
997 /* All 3 samples have the same delivered number of bytes. The first
998 * sets the first tx time */
999 TCP_TEST (tc->first_tx_time == 4, "first_tx_time %u", tc->first_tx_time);
1001 /* 6) Retransmit and track at time 9
1003 * delivered = 3 * burst + 30
1004 * delivered_time = 8 (last ack)
1007 * [snd_una + 10, snd_una + burst]
1008 * [snd_una + burst + 10, snd_una + 2 * burst + 10]
1009 * [snd_una + 2 * burst + 20, snd_una + 4 * burst]
1011 session_main.wrk[thread_index].last_vlib_time = 9;
1013 tcp_bt_track_rxt (tc, snd_una + 10, snd_una + burst);
1014 TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
1015 /* The retransmit covers everything left from first burst */
1016 TCP_TEST (pool_elts (bt->samples) == 4, "there should be 4 samples");
1018 tcp_bt_track_rxt (tc, snd_una + burst + 10, snd_una + 2 * burst + 10);
1019 TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
1020 TCP_TEST (pool_elts (bt->samples) == 5, "there should be 5 samples");
1022 /* Retransmit covers last sample entirely so it should be removed */
1023 tcp_bt_track_rxt (tc, snd_una + 2 * burst + 20, snd_una + 4 * burst);
1024 TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
1025 TCP_TEST (pool_elts (bt->samples) == 5, "there should be 5 samples");
1027 vec_validate (min_seqs, 4);
1028 min_seqs[0] = snd_una + 10;
1029 min_seqs[1] = snd_una + burst;
1030 min_seqs[2] = snd_una + burst + 10;
1031 min_seqs[3] = snd_una + 2 * burst + 10;
1032 min_seqs[4] = snd_una + 2 * burst + 20;
1034 root = bt->sample_lookup.nodes + bt->sample_lookup.root;
1035 bts = bt->samples + bt->head;
1036 for (i = 0; i < vec_len (min_seqs); i++)
1038 if (bts->min_seq != min_seqs[i])
1039 TCP_TEST (0, "should be %u is %u", min_seqs[i], bts->min_seq);
1040 rbn = rb_tree_search_subtree_custom (&bt->sample_lookup, root,
1041 bts->min_seq, tbt_seq_lt);
1042 if (rbn->opaque != bts - bt->samples)
1043 TCP_TEST (0, "lookup should work");
1044 bts = bt->samples + bts->next;
1047 /* 7) check delivery rate at time 10
1049 * tc->snd_una = snd_una + 2 * burst
1051 * [snd_una + 2 * burst + 20, snd_una + 2 * burst + 30]
1052 * [snd_una + 2 * burst + 50, snd_una + 2 * burst + 60]
1054 session_main.wrk[thread_index].last_vlib_time = 10;
1055 tc->snd_una = snd_una + 2 * burst;
1056 tc->bytes_acked = 2 * burst - 10;
1057 sb->last_sacked_bytes = 20;
1059 sacks[0].start = snd_una + 2 * burst + 20;
1060 sacks[0].end = snd_una + 2 * burst + 30;
1061 sacks[1].start = snd_una + 2 * burst + 50;
1062 sacks[1].end = snd_una + 2 * burst + 60;
1064 tcp_bt_sample_delivery_rate (tc, rs);
1066 TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
1067 TCP_TEST (pool_elts (bt->samples) == 3, "num samples should be 3 is %u",
1068 pool_elts (bt->samples));
1069 TCP_TEST (tc->delivered_time == 10, "delivered time should be 10");
1070 TCP_TEST (tc->delivered == 5 * burst + 40, "delivered should be %u is %u",
1071 5 * burst + 40, tc->delivered);
1072 /* A rxt was acked and delivered time for it is 8 (last ack time) so
1073 * ack_time is 2 (8 - 10). However, first_tx_time for rxt was 4 and rxt
1074 * time 9. Therefore snd_time is 5 (9 - 4)*/
1075 TCP_TEST (rs->interval_time == 5, "ack time should be 5 is %.2f",
1077 /* delivered_now - delivered_rxt ~ 5 * burst + 40 - 3 * burst - 30 */
1078 TCP_TEST (rs->delivered == 2 * burst + 10, "delivered should be 210 is %u",
1080 TCP_TEST (rs->prior_delivered == 3 * burst + 30,
1081 "sample delivered should be %u", 3 * burst + 30);
1082 TCP_TEST (rs->flags & TCP_BTS_IS_RXT, "is retransmitted");
1083 /* Sample is app limited because of the retransmits */
1084 TCP_TEST (rs->flags & TCP_BTS_IS_APP_LIMITED, "is app limited");
1085 TCP_TEST (tc->app_limited, "app limited should be set");
1086 TCP_TEST (tc->first_tx_time == 9, "first_tx_time %u", tc->first_tx_time);
1090 * 8) check delivery rate at time 11
1092 session_main.wrk[thread_index].last_vlib_time = 11;
1093 tc->snd_una = tc->snd_nxt;
1094 tc->bytes_acked = 2 * burst;
1095 sb->last_sacked_bytes = 0;
1096 sb->last_bytes_delivered = 40;
1098 memset (rs, 0, sizeof (*rs));
1099 tcp_bt_sample_delivery_rate (tc, rs);
1101 TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
1102 TCP_TEST (pool_elts (bt->samples) == 0, "num samples should be 0 is %u",
1103 pool_elts (bt->samples));
1104 TCP_TEST (tc->delivered_time == 11, "delivered time should be 11");
1105 TCP_TEST (tc->delivered == 7 * burst, "delivered should be %u is %u",
1106 7 * burst, tc->delivered);
1107 /* Delivered time at retransmit was 8 so ack_time is 11 - 8 = 3. However,
1108 * first_tx_time for rxt was 4 and rxt time was 9. Therefore snd_time
1110 TCP_TEST (rs->interval_time == 5, "ack time should be 5 is %.2f",
1112 /* delivered_now - delivered_rxt ~ 7 * burst - 3 * burst - 30.
1113 * That's because we didn't retransmit any new segment. */
1114 TCP_TEST (rs->delivered == 4 * burst - 30, "delivered should be 160 is %u",
1116 TCP_TEST (rs->prior_delivered == 3 * burst + 30,
1117 "sample delivered should be %u", 3 * burst + 30);
1118 TCP_TEST (rs->flags & TCP_BTS_IS_RXT, "is retransmitted");
1119 TCP_TEST (rs->flags & TCP_BTS_IS_APP_LIMITED, "is app limited");
1120 TCP_TEST (tc->app_limited == 0, "app limited should be cleared");
1121 TCP_TEST (tc->first_tx_time == 9, "first_tx_time %u", tc->first_tx_time);
1127 tcp_bt_track_tx (tc);
1128 tc->snd_nxt += burst;
1130 session_main.wrk[thread_index].last_vlib_time = 12;
1131 tcp_bt_track_tx (tc);
1132 tc->snd_nxt += burst;
1134 tcp_bt_flush_samples (tc);
1140 vec_free (min_seqs);
1141 tcp_bt_cleanup (tc);
1145 static clib_error_t *
1146 tcp_test (vlib_main_t * vm,
1147 unformat_input_t * input, vlib_cli_command_t * cmd_arg)
1151 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1153 if (unformat (input, "sack"))
1155 res = tcp_test_sack (vm, input);
1157 else if (unformat (input, "session"))
1159 res = tcp_test_session (vm, input);
1161 else if (unformat (input, "lookup"))
1163 res = tcp_test_lookup (vm, input);
1165 else if (unformat (input, "delivery"))
1167 res = tcp_test_delivery (vm, input);
1169 else if (unformat (input, "all"))
1171 if ((res = tcp_test_sack (vm, input)))
1173 if ((res = tcp_test_lookup (vm, input)))
1175 if ((res = tcp_test_delivery (vm, input)))
1184 return clib_error_return (0, "TCP unit test failed");
1189 VLIB_CLI_COMMAND (tcp_test_command, static) =
1192 .short_help = "internal tcp unit tests",
1193 .function = tcp_test,
1198 * fd.io coding-style-patch-verification: ON
1201 * eval: (c-set-style "gnu")