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 approx_equal (u32 a, u32 b)
826 if (b > 0.99 * a && b < 1.01 * a)
832 tcp_test_delivery (vlib_main_t * vm, unformat_input_t * input)
834 u32 thread_index = 0, snd_una, *min_seqs = 0;
835 tcp_rate_sample_t _rs = { 0 }, *rs = &_rs;
836 tcp_connection_t _tc, *tc = &_tc;
837 sack_scoreboard_t *sb = &tc->sack_sb;
838 int __clib_unused verbose = 0, i;
839 u64 rate = 1000, burst = 100;
840 sack_block_t *sacks = 0;
841 tcp_byte_tracker_t *bt;
842 rb_node_t *root, *rbn;
843 tcp_bt_sample_t *bts;
845 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
847 if (unformat (input, "verbose"))
851 vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
857 /* Init data structures */
858 memset (tc, 0, sizeof (*tc));
859 session_main.wrk[thread_index].last_vlib_time = 1;
860 transport_connection_tx_pacer_update (&tc->connection, rate);
866 * Track simple bursts without rxt
869 /* 1) track first burst a time 1 */
870 tcp_bt_track_tx (tc);
872 TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
873 TCP_TEST (pool_elts (bt->samples) == 1, "should have 1 sample");
874 bts = pool_elt_at_index (bt->samples, bt->head);
875 TCP_TEST (bts->min_seq == tc->snd_una, "min seq should be snd_una");
876 TCP_TEST (bts->next == TCP_BTS_INVALID_INDEX, "next should be invalid");
877 TCP_TEST (bts->prev == TCP_BTS_INVALID_INDEX, "prev should be invalid");
878 TCP_TEST (bts->delivered_time == 1, "delivered time should be 1");
879 TCP_TEST (bts->delivered == 0, "delivered should be 0");
880 TCP_TEST (!(bts->flags & TCP_BTS_IS_RXT), "not retransmitted");
881 TCP_TEST (!(bts->flags & TCP_BTS_IS_APP_LIMITED), "not app limited");
883 /* 2) check delivery rate at time 2 */
884 session_main.wrk[thread_index].last_vlib_time = 2;
885 tc->snd_una = tc->snd_nxt = burst;
886 tc->bytes_acked = burst;
888 tcp_bt_sample_delivery_rate (tc, rs);
890 TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
891 TCP_TEST (pool_elts (bt->samples) == 0, "sample should've been consumed");
892 TCP_TEST (tc->delivered_time == 2, "delivered time should be 2");
893 TCP_TEST (tc->delivered == burst, "delivered should be 100");
894 TCP_TEST (rs->interval_time == 1, "ack time should be 1");
895 TCP_TEST (rs->delivered == burst, "delivered should be 100");
896 TCP_TEST (rs->prior_delivered == 0, "sample delivered should be 0");
897 TCP_TEST (approx_equal (rate, rs->tx_rate), "rate should be %u is %u", rate,
899 TCP_TEST (!(rs->flags & TCP_BTS_IS_RXT), "not retransmitted");
901 /* 3) track second burst at time 2 */
902 tcp_bt_track_tx (tc);
903 tc->snd_nxt += burst;
905 /* 4) track second burst at time 3 */
906 session_main.wrk[thread_index].last_vlib_time = 3;
907 tcp_bt_track_tx (tc);
908 tc->snd_nxt += burst;
910 TCP_TEST (pool_elts (bt->samples) == 2, "should have 2 samples");
912 TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
913 bts = pool_elt_at_index (bt->samples, bt->head);
914 TCP_TEST (bts->min_seq == tc->snd_una, "min seq should be snd_una");
915 TCP_TEST (bts->next == bt->tail, "next should tail");
917 bts = pool_elt_at_index (bt->samples, bt->tail);
918 TCP_TEST (bts->min_seq == tc->snd_nxt - burst,
919 "min seq should be snd_nxt prior to burst");
920 TCP_TEST (bts->prev == bt->head, "prev should be head");
922 /* 5) check delivery rate at time 4 */
923 session_main.wrk[thread_index].last_vlib_time = 4;
924 tc->snd_una = tc->snd_nxt;
925 tc->bytes_acked = 2 * burst;
927 tcp_bt_sample_delivery_rate (tc, rs);
929 TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
930 TCP_TEST (pool_elts (bt->samples) == 0, "sample should've been consumed");
931 TCP_TEST (tc->delivered_time == 4, "delivered time should be 4");
932 TCP_TEST (tc->delivered == 3 * burst, "delivered should be 300 is %u",
934 TCP_TEST (rs->interval_time == 2, "ack time should be 2");
935 TCP_TEST (rs->delivered == 2 * burst, "delivered should be 200");
936 TCP_TEST (rs->prior_delivered == burst, "delivered should be 100");
937 TCP_TEST (approx_equal (rate, rs->tx_rate), "rate should be %u is %u", rate,
939 TCP_TEST (!(rs->flags & TCP_BTS_IS_RXT), "not retransmitted");
940 TCP_TEST (!(bts->flags & TCP_BTS_IS_APP_LIMITED), "not app limited");
943 * Track retransmissions
945 * snd_una should be 300 at this point
948 snd_una = tc->snd_una;
950 /* 1) track first burst a time 4 */
951 tcp_bt_track_tx (tc);
952 tc->snd_nxt += burst;
954 /* 2) track second burst at time 5 */
955 session_main.wrk[thread_index].last_vlib_time = 5;
956 tcp_bt_track_tx (tc);
957 tc->snd_nxt += burst;
959 /* 3) track third burst at time 6 */
960 session_main.wrk[thread_index].last_vlib_time = 6;
961 tcp_bt_track_tx (tc);
962 tc->snd_nxt += burst;
964 /* 4) track fourth burst at time 7 */
965 session_main.wrk[thread_index].last_vlib_time = 7;
966 /* Limited until last burst is acked */
967 tc->app_limited = snd_una + 4 * burst - 1;
968 tcp_bt_track_tx (tc);
969 tc->snd_nxt += burst;
971 /* 5) check delivery rate at time 8
973 * tc->snd_una = snd_una + 10
975 * [snd_una + burst, snd_una + burst + 10]
976 * [snd_una + 2 * burst + 10, snd_una + 2 * burst + 20]
978 session_main.wrk[thread_index].last_vlib_time = 8;
980 tc->bytes_acked = 10;
981 sb->last_sacked_bytes = 20;
983 TCP_TEST (pool_elts (bt->samples) == 4, "there should be 4 samples");
985 vec_validate (sacks, 1);
986 sacks[0].start = snd_una + burst;
987 sacks[0].end = snd_una + burst + 10;
988 sacks[1].start = snd_una + 2 * burst + 10;
989 sacks[1].end = snd_una + 2 * burst + 20;
990 tc->rcv_opts.sacks = sacks;
992 tcp_bt_sample_delivery_rate (tc, rs);
994 TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
995 TCP_TEST (pool_elts (bt->samples) == 4, "there should be 4 samples");
996 TCP_TEST (tc->delivered_time == 8, "delivered time should be 8");
997 TCP_TEST (tc->delivered == 3 * burst + 30, "delivered should be %u is %u",
998 3 * burst + 30, tc->delivered);
999 /* All 3 samples have the same delivered number of bytes. So the first is
1000 * the reference for delivery estimate. */
1001 TCP_TEST (rs->interval_time == 4, "ack time should be 4 is %.2f",
1003 TCP_TEST (rs->delivered == 30, "delivered should be 30");
1004 TCP_TEST (rs->prior_delivered == 3 * burst,
1005 "sample delivered should be %u", 3 * burst);
1006 TCP_TEST (approx_equal (rate, rs->tx_rate), "rate should be %u is %u", rate,
1008 TCP_TEST (!(rs->flags & TCP_BTS_IS_RXT), "not retransmitted");
1009 TCP_TEST (!(rs->flags & TCP_BTS_IS_APP_LIMITED), "not app limited");
1011 /* 6) Retransmit and track at time 9
1013 * delivered = 3 * burst + 30
1014 * delivered_time = 8 (last ack)
1017 * [snd_una + 10, snd_una + burst]
1018 * [snd_una + burst + 10, snd_una + 2 * burst + 10]
1019 * [snd_una + 2 * burst + 20, snd_una + 4 * burst]
1021 session_main.wrk[thread_index].last_vlib_time = 9;
1023 tcp_bt_track_rxt (tc, snd_una + 10, snd_una + burst);
1024 TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
1025 /* The retransmit covers everything left from first burst */
1026 TCP_TEST (pool_elts (bt->samples) == 4, "there should be 4 samples");
1028 tcp_bt_track_rxt (tc, snd_una + burst + 10, snd_una + 2 * burst + 10);
1029 TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
1030 TCP_TEST (pool_elts (bt->samples) == 5, "there should be 5 samples");
1032 /* Retransmit covers last sample entirely so it should be removed */
1033 tcp_bt_track_rxt (tc, snd_una + 2 * burst + 20, snd_una + 4 * burst);
1034 TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
1035 TCP_TEST (pool_elts (bt->samples) == 5, "there should be 5 samples");
1037 vec_validate (min_seqs, 4);
1038 min_seqs[0] = snd_una + 10;
1039 min_seqs[1] = snd_una + burst;
1040 min_seqs[2] = snd_una + burst + 10;
1041 min_seqs[3] = snd_una + 2 * burst + 10;
1042 min_seqs[4] = snd_una + 2 * burst + 20;
1044 root = bt->sample_lookup.nodes + bt->sample_lookup.root;
1045 bts = bt->samples + bt->head;
1046 for (i = 0; i < vec_len (min_seqs); i++)
1048 if (bts->min_seq != min_seqs[i])
1049 TCP_TEST (0, "should be %u is %u", min_seqs[i], bts->min_seq);
1050 rbn = rb_tree_search_subtree_custom (&bt->sample_lookup, root,
1051 bts->min_seq, tbt_seq_lt);
1052 if (rbn->opaque != bts - bt->samples)
1053 TCP_TEST (0, "lookup should work");
1054 bts = bt->samples + bts->next;
1057 /* 7) check delivery rate at time 10
1059 * tc->snd_una = snd_una + 2 * burst
1061 * [snd_una + 2 * burst + 20, snd_una + 2 * burst + 30]
1062 * [snd_una + 2 * burst + 50, snd_una + 2 * burst + 60]
1064 session_main.wrk[thread_index].last_vlib_time = 10;
1065 tc->snd_una = snd_una + 2 * burst;
1066 tc->bytes_acked = 2 * burst - 10;
1067 sb->last_sacked_bytes = 20;
1069 sacks[0].start = snd_una + 2 * burst + 20;
1070 sacks[0].end = snd_una + 2 * burst + 30;
1071 sacks[1].start = snd_una + 2 * burst + 50;
1072 sacks[1].end = snd_una + 2 * burst + 60;
1074 tcp_bt_sample_delivery_rate (tc, rs);
1076 TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
1077 TCP_TEST (pool_elts (bt->samples) == 3, "num samples should be 3 is %u",
1078 pool_elts (bt->samples));
1079 TCP_TEST (tc->delivered_time == 10, "delivered time should be 10");
1080 TCP_TEST (tc->delivered == 5 * burst + 40, "delivered should be %u is %u",
1081 5 * burst + 40, tc->delivered);
1082 /* A rxt was acked and delivered time for it is 8 (last ack time) */
1083 TCP_TEST (rs->interval_time == 2, "ack time should be 2 is %.2f",
1085 /* delivered_now - delivered_rxt ~ 5 * burst + 40 - 3 * burst - 30 */
1086 TCP_TEST (rs->delivered == 2 * burst + 10, "delivered should be 210 is %u",
1088 TCP_TEST (rs->prior_delivered == 3 * burst + 30,
1089 "sample delivered should be %u", 3 * burst + 30);
1090 TCP_TEST (approx_equal (rate, rs->tx_rate), "rate should be %u is %u", rate,
1092 TCP_TEST (rs->flags & TCP_BTS_IS_RXT, "is retransmitted");
1093 /* Sample is app limited because of the retransmits */
1094 TCP_TEST (rs->flags & TCP_BTS_IS_APP_LIMITED, "is app limited");
1095 TCP_TEST (tc->app_limited, "app limited should be set");
1098 * 8) check delivery rate at time 11
1100 session_main.wrk[thread_index].last_vlib_time = 11;
1101 tc->snd_una = tc->snd_nxt;
1102 tc->bytes_acked = 2 * burst;
1103 sb->last_sacked_bytes = 0;
1104 sb->last_bytes_delivered = 40;
1106 memset (rs, 0, sizeof (*rs));
1107 tcp_bt_sample_delivery_rate (tc, rs);
1109 TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
1110 TCP_TEST (pool_elts (bt->samples) == 0, "num samples should be 0 is %u",
1111 pool_elts (bt->samples));
1112 TCP_TEST (tc->delivered_time == 11, "delivered time should be 11");
1113 TCP_TEST (tc->delivered == 7 * burst, "delivered should be %u is %u",
1114 7 * burst, tc->delivered);
1115 /* Last rxt was at time 8 */
1116 TCP_TEST (rs->interval_time == 3, "ack time should be 3 is %.2f",
1118 /* delivered_now - delivered_rxt ~ 7 * burst - 3 * burst - 30.
1119 * That's because we didn't retransmit any new segment. */
1120 TCP_TEST (rs->delivered == 4 * burst - 30, "delivered should be 160 is %u",
1122 TCP_TEST (rs->prior_delivered == 3 * burst + 30,
1123 "sample delivered should be %u", 3 * burst + 30);
1124 TCP_TEST (approx_equal (rate, rs->tx_rate), "rate should be %u is %u", rate,
1126 TCP_TEST (rs->flags & TCP_BTS_IS_RXT, "is retransmitted");
1127 TCP_TEST (rs->flags & TCP_BTS_IS_APP_LIMITED, "is app limited");
1128 TCP_TEST (tc->app_limited == 0, "app limited should be cleared");
1134 tcp_bt_track_tx (tc);
1135 tc->snd_nxt += burst;
1137 session_main.wrk[thread_index].last_vlib_time = 12;
1138 tcp_bt_track_tx (tc);
1139 tc->snd_nxt += burst;
1141 tcp_bt_flush_samples (tc);
1147 vec_free (min_seqs);
1148 tcp_bt_cleanup (tc);
1152 static clib_error_t *
1153 tcp_test (vlib_main_t * vm,
1154 unformat_input_t * input, vlib_cli_command_t * cmd_arg)
1158 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1160 if (unformat (input, "sack"))
1162 res = tcp_test_sack (vm, input);
1164 else if (unformat (input, "session"))
1166 res = tcp_test_session (vm, input);
1168 else if (unformat (input, "lookup"))
1170 res = tcp_test_lookup (vm, input);
1172 else if (unformat (input, "delivery"))
1174 res = tcp_test_delivery (vm, input);
1176 else if (unformat (input, "all"))
1178 if ((res = tcp_test_sack (vm, input)))
1180 if ((res = tcp_test_lookup (vm, input)))
1182 if ((res = tcp_test_delivery (vm, input)))
1191 return clib_error_return (0, "TCP unit test failed");
1196 VLIB_CLI_COMMAND (tcp_test_command, static) =
1199 .short_help = "internal tcp unit tests",
1200 .function = tcp_test,
1205 * fd.io coding-style-patch-verification: ON
1208 * eval: (c-set-style "gnu")