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->snd_una_adv == 0), "snd_una_adv %u", sb->snd_una_adv);
129 TCP_TEST ((sb->last_sacked_bytes == 400),
130 "last sacked bytes %d", sb->last_sacked_bytes);
131 TCP_TEST ((sb->high_sacked == 900), "high sacked %u", sb->high_sacked);
132 TCP_TEST ((sb->lost_bytes == 300), "lost bytes %u", sb->lost_bytes);
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->snd_una_adv == 0), "snd_una_adv %u", sb->snd_una_adv);
157 TCP_TEST ((sb->high_sacked == 1000), "high sacked %u", sb->high_sacked);
158 TCP_TEST ((sb->last_sacked_bytes == 500),
159 "last sacked bytes %d", sb->last_sacked_bytes);
160 TCP_TEST ((sb->lost_bytes == 100), "lost bytes %u", sb->lost_bytes);
163 * Ack until byte 100, all bytes are now acked + sacked
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),
171 "scoreboard has %d elements", pool_elts (sb->holes));
172 TCP_TEST ((sb->snd_una_adv == 900),
173 "snd_una_adv after ack %u", sb->snd_una_adv);
174 TCP_TEST ((sb->high_sacked == 1000), "max sacked byte %u", sb->high_sacked);
175 TCP_TEST ((sb->sacked_bytes == 0), "sacked bytes %d", sb->sacked_bytes);
176 TCP_TEST ((sb->last_sacked_bytes == 0),
177 "last sacked bytes %d", sb->last_sacked_bytes);
178 TCP_TEST ((sb->lost_bytes == 0), "lost bytes %u", sb->lost_bytes);
184 vec_reset_length (tc->rcv_opts.sacks);
188 vec_add1 (tc->rcv_opts.sacks, block);
190 tc->snd_una_max = 1500;
193 tcp_rcv_sacks (tc, 1000);
196 vlib_cli_output (vm, "\nadd [1200, 1300] snd_una_max 1500, snd_una 1000:"
197 " \n%U", format_tcp_scoreboard, sb, tc);
199 TCP_TEST ((sb->snd_una_adv == 0),
200 "snd_una_adv after ack %u", sb->snd_una_adv);
201 TCP_TEST ((pool_elts (sb->holes) == 2),
202 "scoreboard has %d holes", pool_elts (sb->holes));
203 hole = scoreboard_first_hole (sb);
204 TCP_TEST ((hole->start == 1000 && hole->end == 1200),
205 "first hole start %u end %u", hole->start, hole->end);
206 TCP_TEST ((sb->snd_una_adv == 0),
207 "snd_una_adv after ack %u", sb->snd_una_adv);
208 TCP_TEST ((sb->high_sacked == 1300), "max sacked byte %u", sb->high_sacked);
209 hole = scoreboard_last_hole (sb);
210 TCP_TEST ((hole->start == 1300 && hole->end == 1500),
211 "last hole start %u end %u", hole->start, hole->end);
212 TCP_TEST ((sb->sacked_bytes == 100), "sacked bytes %d", sb->sacked_bytes);
213 TCP_TEST ((sb->lost_bytes == 0), "lost bytes %u", sb->lost_bytes);
219 vec_reset_length (tc->rcv_opts.sacks);
220 tcp_rcv_sacks (tc, 1200);
223 vlib_cli_output (vm, "\nsb ack up to byte 1200:\n%U",
224 format_tcp_scoreboard, sb, tc);
226 TCP_TEST ((sb->snd_una_adv == 100),
227 "snd_una_adv after ack %u", sb->snd_una_adv);
228 TCP_TEST ((sb->sacked_bytes == 0), "sacked bytes %d", sb->sacked_bytes);
229 TCP_TEST ((pool_elts (sb->holes) == 0),
230 "scoreboard has %d elements", pool_elts (sb->holes));
231 TCP_TEST ((sb->last_bytes_delivered == 100), "last bytes delivered %d",
232 sb->last_bytes_delivered);
233 TCP_TEST ((sb->lost_bytes == 0), "lost bytes %u", sb->lost_bytes);
234 TCP_TEST ((sb->head == TCP_INVALID_SACK_HOLE_INDEX), "head %u", sb->head);
235 TCP_TEST ((sb->tail == TCP_INVALID_SACK_HOLE_INDEX), "tail %u", sb->tail);
238 * Add some more blocks and then remove all
240 vec_reset_length (tc->rcv_opts.sacks);
241 tc->snd_una += sb->snd_una_adv;
242 tc->snd_nxt = tc->snd_una_max = 1900;
243 for (i = 0; i < 5; i++)
245 block.start = i * 100 + 1200;
246 block.end = (i + 1) * 100 + 1200;
247 vec_add1 (tc->rcv_opts.sacks, block);
249 tcp_rcv_sacks (tc, 1900);
251 scoreboard_clear (sb);
253 vlib_cli_output (vm, "\nsb cleared all:\n%U", format_tcp_scoreboard, sb,
256 TCP_TEST ((pool_elts (sb->holes) == 0),
257 "number of holes %d", pool_elts (sb->holes));
258 TCP_TEST ((sb->head == TCP_INVALID_SACK_HOLE_INDEX), "head %u", sb->head);
259 TCP_TEST ((sb->tail == TCP_INVALID_SACK_HOLE_INDEX), "tail %u", sb->tail);
262 * Re-inject odd blocks and ack them all
266 tc->snd_una_max = 1000;
268 for (i = 0; i < 5; i++)
270 vec_add1 (tc->rcv_opts.sacks, sacks[i * 2 + 1]);
272 tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
273 tcp_rcv_sacks (tc, 0);
275 vlib_cli_output (vm, "\nsb added odd blocks snd_una 0 snd_una_max 1500:"
276 "\n%U", format_tcp_scoreboard, sb, tc);
277 TCP_TEST ((pool_elts (sb->holes) == 5),
278 "scoreboard has %d elements", pool_elts (sb->holes));
279 TCP_TEST ((sb->lost_bytes == 300), "lost bytes %u", sb->lost_bytes);
281 tcp_rcv_sacks (tc, 950);
284 vlib_cli_output (vm, "\nack [0, 950]:\n%U", format_tcp_scoreboard, sb,
287 TCP_TEST ((pool_elts (sb->holes) == 0),
288 "scoreboard has %d elements", pool_elts (sb->holes));
289 TCP_TEST ((sb->snd_una_adv == 50), "snd_una_adv %u", sb->snd_una_adv);
290 TCP_TEST ((sb->sacked_bytes == 0), "sacked bytes %d", sb->sacked_bytes);
291 TCP_TEST ((sb->last_sacked_bytes == 0),
292 "last sacked bytes %d", sb->last_sacked_bytes);
293 TCP_TEST ((sb->lost_bytes == 0), "lost bytes %u", sb->lost_bytes);
296 * Inject one block, ack it and overlap hole
300 tc->snd_una_max = 1000;
305 vec_add1 (tc->rcv_opts.sacks, block);
306 tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
308 tcp_rcv_sacks (tc, 0);
311 vlib_cli_output (vm, "\nsb added [100, 500] snd_una 0 snd_una_max 1000:"
312 "\n%U", format_tcp_scoreboard, sb, tc);
314 tcp_rcv_sacks (tc, 800);
317 vlib_cli_output (vm, "\nsb ack [0, 800]:\n%U", format_tcp_scoreboard, sb,
320 TCP_TEST ((pool_elts (sb->holes) == 0),
321 "scoreboard has %d elements", pool_elts (sb->holes));
322 TCP_TEST ((sb->snd_una_adv == 0), "snd_una_adv %u", sb->snd_una_adv);
323 TCP_TEST ((sb->sacked_bytes == 0), "sacked bytes %d", sb->sacked_bytes);
324 TCP_TEST ((sb->last_sacked_bytes == 0), "last sacked bytes %d",
325 sb->last_sacked_bytes);
326 TCP_TEST ((sb->last_bytes_delivered == 400),
327 "last bytes delivered %d", sb->last_bytes_delivered);
328 TCP_TEST ((sb->lost_bytes == 0), "lost bytes %u", sb->lost_bytes);
329 TCP_TEST ((sb->head == TCP_INVALID_SACK_HOLE_INDEX), "head %u", sb->head);
330 TCP_TEST ((sb->tail == TCP_INVALID_SACK_HOLE_INDEX), "tail %u", sb->tail);
333 * One hole close to head, patch head, split in two and start acking
336 scoreboard_clear (sb);
338 tc->snd_una_max = 1000;
343 vec_add1 (tc->rcv_opts.sacks, block);
344 tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
346 tcp_rcv_sacks (tc, 0);
348 vlib_cli_output (vm, "\nsb added [500, 1000]:\n%U",
349 format_tcp_scoreboard, sb, tc);
350 TCP_TEST ((sb->sacked_bytes == 500), "sacked bytes %d", sb->sacked_bytes);
351 TCP_TEST ((sb->last_sacked_bytes == 500), "last sacked bytes %d",
352 sb->last_sacked_bytes);
353 TCP_TEST ((sb->lost_bytes == 500), "lost bytes %u", sb->lost_bytes);
355 vec_reset_length (tc->rcv_opts.sacks);
358 vec_add1 (tc->rcv_opts.sacks, block);
359 tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
360 tcp_rcv_sacks (tc, 100);
362 vlib_cli_output (vm, "\nsb added [0, 100] [300, 400]:\n%U",
363 format_tcp_scoreboard, sb, tc);
364 TCP_TEST ((pool_elts (sb->holes) == 2),
365 "scoreboard has %d elements", pool_elts (sb->holes));
366 TCP_TEST ((sb->sacked_bytes == 600), "sacked bytes %d", sb->sacked_bytes);
367 TCP_TEST ((sb->last_sacked_bytes == 100), "last sacked bytes %d",
368 sb->last_sacked_bytes);
369 TCP_TEST ((sb->last_bytes_delivered == 0), "last bytes delivered %d",
370 sb->last_bytes_delivered);
371 TCP_TEST ((sb->lost_bytes == 300), "lost bytes %u", sb->lost_bytes);
374 tcp_rcv_sacks (tc, 200);
376 tcp_rcv_sacks (tc, 300);
378 vlib_cli_output (vm, "\nacked [0, 300] in two steps:\n%U",
379 format_tcp_scoreboard, sb, tc);
380 TCP_TEST ((sb->sacked_bytes == 500), "sacked bytes %d", sb->sacked_bytes);
381 TCP_TEST ((sb->lost_bytes == 100), "lost bytes %u", sb->lost_bytes);
382 TCP_TEST ((sb->last_bytes_delivered == 100), "last bytes delivered %d",
383 sb->last_bytes_delivered);
386 tcp_rcv_sacks (tc, 500);
388 vlib_cli_output (vm, "\nacked [400, 500]:\n%U", format_tcp_scoreboard, sb,
390 TCP_TEST ((pool_elts (sb->holes) == 0),
391 "scoreboard has %d elements", pool_elts (sb->holes));
392 TCP_TEST ((sb->sacked_bytes == 0), "sacked bytes %d", sb->sacked_bytes);
393 TCP_TEST ((sb->last_sacked_bytes == 0), "last sacked bytes %d",
394 sb->last_sacked_bytes);
395 TCP_TEST ((sb->last_bytes_delivered == 500), "last bytes delivered %d",
396 sb->last_bytes_delivered);
397 TCP_TEST ((sb->lost_bytes == 0), "lost bytes %u", sb->lost_bytes);
398 TCP_TEST ((sb->snd_una_adv == 500), "snd_una_adv %u", sb->snd_una_adv);
399 TCP_TEST ((sb->head == TCP_INVALID_SACK_HOLE_INDEX), "head %u", sb->head);
400 TCP_TEST ((sb->tail == TCP_INVALID_SACK_HOLE_INDEX), "tail %u", sb->tail);
403 * Re-ack high sacked, to make sure last_bytes_delivered and
404 * snd_una_adv are 0-ed
406 tcp_rcv_sacks (tc, 1000);
408 vlib_cli_output (vm, "\nAck high sacked:\n%U", format_tcp_scoreboard, sb,
410 TCP_TEST ((sb->last_bytes_delivered == 0), "last bytes delivered %d",
411 sb->last_bytes_delivered);
412 TCP_TEST ((sb->snd_una_adv == 0), "snd_una_adv %u", sb->snd_una_adv);
415 * Add [1200, 1500] and test that [1000, 1200] is lost (bytes condition)
416 * snd_una = 1000 and snd_una_max = 1600
419 tc->snd_nxt = tc->snd_una_max = 1600;
420 vec_reset_length (tc->rcv_opts.sacks);
423 vec_add1 (tc->rcv_opts.sacks, block);
424 tc->rcv_opts.n_sack_blocks = vec_len (tc->rcv_opts.sacks);
425 tcp_rcv_sacks (tc, 1000);
427 vlib_cli_output (vm, "\nacked [1200, 1500] test first hole is lost:\n%U",
428 format_tcp_scoreboard, sb, tc);
429 TCP_TEST ((pool_elts (sb->holes) == 2), "scoreboard has %d elements",
430 pool_elts (sb->holes));
431 TCP_TEST ((sb->sacked_bytes == 300), "sacked bytes %d", sb->sacked_bytes);
432 TCP_TEST ((sb->last_sacked_bytes == 300), "last sacked bytes %d",
433 sb->last_sacked_bytes);
434 TCP_TEST ((sb->last_bytes_delivered == 0), "last bytes delivered %d",
435 sb->last_bytes_delivered);
436 TCP_TEST ((sb->lost_bytes == 200), "lost bytes %u", sb->lost_bytes);
437 TCP_TEST ((sb->snd_una_adv == 0), "snd_una_adv %u", sb->snd_una_adv);
443 tcp_test_sack_tx (vlib_main_t * vm, unformat_input_t * input)
445 tcp_connection_t _tc, *tc = &_tc;
447 int i, verbose = 0, expected;
449 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
451 if (unformat (input, "verbose"))
455 vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
461 clib_memset (tc, 0, sizeof (*tc));
464 * Add odd sack block pairs
466 for (i = 1; i < 10; i += 2)
468 tcp_update_sack_list (tc, i * 100, (i + 1) * 100);
471 TCP_TEST ((vec_len (tc->snd_sacks) == 5), "sack blocks %d expected %d",
472 vec_len (tc->snd_sacks), 5);
473 TCP_TEST ((tc->snd_sacks[0].start = 900),
474 "first sack block start %u expected %u", tc->snd_sacks[0].start,
478 * Try to add one extra
480 sacks = vec_dup (tc->snd_sacks);
482 tcp_update_sack_list (tc, 1100, 1200);
484 vlib_cli_output (vm, "add new segment [1100, 1200]\n%U",
485 format_tcp_sacks, tc);
486 expected = 5 < TCP_MAX_SACK_BLOCKS ? 6 : 5;
487 TCP_TEST ((vec_len (tc->snd_sacks) == expected),
488 "sack blocks %d expected %d", vec_len (tc->snd_sacks), expected);
489 TCP_TEST ((tc->snd_sacks[0].start == 1100),
490 "first sack block start %u expected %u", tc->snd_sacks[0].start,
494 vec_free (tc->snd_sacks);
495 tc->snd_sacks = sacks;
498 * Overlap first 2 segment
501 tcp_update_sack_list (tc, 300, 300);
503 vlib_cli_output (vm, "overlap first 2 segments:\n%U",
504 format_tcp_sacks, tc);
505 TCP_TEST ((vec_len (tc->snd_sacks) == 3), "sack blocks %d expected %d",
506 vec_len (tc->snd_sacks), 3);
507 TCP_TEST ((tc->snd_sacks[0].start == 900),
508 "first sack block start %u expected %u", tc->snd_sacks[0].start,
514 tcp_update_sack_list (tc, 1100, 1200);
516 vlib_cli_output (vm, "add new segment [1100, 1200]\n%U",
517 format_tcp_sacks, tc);
518 TCP_TEST ((vec_len (tc->snd_sacks) == 4), "sack blocks %d expected %d",
519 vec_len (tc->snd_sacks), 4);
520 TCP_TEST ((tc->snd_sacks[0].start == 1100),
521 "first sack block start %u expected %u", tc->snd_sacks[0].start,
525 * Join middle segments
527 tcp_update_sack_list (tc, 800, 900);
529 vlib_cli_output (vm, "join middle segments [800, 900]\n%U",
530 format_tcp_sacks, tc);
532 TCP_TEST ((vec_len (tc->snd_sacks) == 3), "sack blocks %d expected %d",
533 vec_len (tc->snd_sacks), 3);
534 TCP_TEST ((tc->snd_sacks[0].start == 700),
535 "first sack block start %u expected %u", tc->snd_sacks[0].start,
539 * Advance rcv_nxt to overlap all
542 tcp_update_sack_list (tc, 1200, 1200);
544 vlib_cli_output (vm, "advance rcv_nxt to 1200\n%U", format_tcp_sacks, tc);
545 TCP_TEST ((vec_len (tc->snd_sacks) == 0), "sack blocks %d expected %d",
546 vec_len (tc->snd_sacks), 0);
550 * Add 2 blocks, overwrite first and update rcv_nxt to also remove it
553 vec_reset_length (tc->snd_sacks);
556 tcp_update_sack_list (tc, 100, 200);
557 tcp_update_sack_list (tc, 300, 400);
560 vlib_cli_output (vm, "add [100, 200] [300, 400]\n%U",
561 format_tcp_sacks, tc);
562 TCP_TEST ((vec_len (tc->snd_sacks) == 2),
563 "sack blocks %d expected %d", vec_len (tc->snd_sacks), 2);
564 TCP_TEST ((tc->snd_sacks[0].start == 300),
565 "first sack block start %u expected %u", tc->snd_sacks[0].start,
569 tcp_update_sack_list (tc, 100, 100);
571 vlib_cli_output (vm, "add [100, 200] rcv_nxt = 100\n%U",
572 format_tcp_sacks, tc);
573 TCP_TEST ((vec_len (tc->snd_sacks) == 1),
574 "sack blocks %d expected %d", vec_len (tc->snd_sacks), 1);
575 TCP_TEST ((tc->snd_sacks[0].start == 300),
576 "first sack block start %u expected %u", tc->snd_sacks[0].start,
582 tcp_test_sack (vlib_main_t * vm, unformat_input_t * input)
587 if (unformat_check_input (input) == UNFORMAT_END_OF_INPUT)
589 if (tcp_test_sack_tx (vm, input))
594 if (tcp_test_sack_rx (vm, input))
601 if (unformat (input, "tx"))
603 res = tcp_test_sack_tx (vm, input);
605 else if (unformat (input, "rx"))
607 res = tcp_test_sack_rx (vm, input);
615 tcp_test_lookup (vlib_main_t * vm, unformat_input_t * input)
617 session_main_t *smm = &session_main;
618 tcp_main_t *tm = &tcp_main;
619 transport_connection_t _tc1, *tc1 = &_tc1, _tc2, *tc2 = &_tc2, *tconn;
620 tcp_connection_t *tc;
622 u8 cmp = 0, is_filtered = 0;
626 * Allocate fake session and connection 1
628 pool_get (smm->wrk[0].sessions, s);
629 clib_memset (s, 0, sizeof (*s));
630 s->session_index = sidx = s - smm->wrk[0].sessions;
632 pool_get (tm->connections[0], tc);
633 clib_memset (tc, 0, sizeof (*tc));
634 tc->connection.c_index = tc - tm->connections[0];
635 tc->connection.s_index = s->session_index;
636 s->connection_index = tc->connection.c_index;
638 tc->connection.lcl_ip.ip4.as_u32 = clib_host_to_net_u32 (0x06000101);
639 tc->connection.rmt_ip.ip4.as_u32 = clib_host_to_net_u32 (0x06000103);
640 tc->connection.lcl_port = 35051;
641 tc->connection.rmt_port = 53764;
642 tc->connection.proto = TRANSPORT_PROTO_TCP;
643 tc->connection.is_ip4 = 1;
644 clib_memcpy_fast (tc1, &tc->connection, sizeof (*tc1));
647 * Allocate fake session and connection 2
649 pool_get (smm->wrk[0].sessions, s);
650 clib_memset (s, 0, sizeof (*s));
651 s->session_index = s - smm->wrk[0].sessions;
653 pool_get (tm->connections[0], tc);
654 clib_memset (tc, 0, sizeof (*tc));
655 tc->connection.c_index = tc - tm->connections[0];
656 tc->connection.s_index = s->session_index;
657 s->connection_index = tc->connection.c_index;
659 tc->connection.lcl_ip.ip4.as_u32 = clib_host_to_net_u32 (0x06000101);
660 tc->connection.rmt_ip.ip4.as_u32 = clib_host_to_net_u32 (0x06000102);
661 tc->connection.lcl_port = 38225;
662 tc->connection.rmt_port = 53764;
663 tc->connection.proto = TRANSPORT_PROTO_TCP;
664 tc->connection.is_ip4 = 1;
665 clib_memcpy_fast (tc2, &tc->connection, sizeof (*tc2));
668 * Confirm that connection lookup works
671 s1 = pool_elt_at_index (smm->wrk[0].sessions, sidx);
672 session_lookup_add_connection (tc1, session_handle (s1));
673 tconn = session_lookup_connection_wt4 (0, &tc1->lcl_ip.ip4,
675 tc1->lcl_port, tc1->rmt_port,
676 tc1->proto, 0, &is_filtered);
678 TCP_TEST ((tconn != 0), "connection exists");
679 cmp = (memcmp (&tconn->rmt_ip, &tc1->rmt_ip, sizeof (tc1->rmt_ip)) == 0);
680 TCP_TEST ((cmp), "rmt ip is identical %d", cmp);
681 TCP_TEST ((tconn->lcl_port == tc1->lcl_port),
682 "rmt port is identical %d", tconn->lcl_port == tc1->lcl_port);
685 * Non-existing connection lookup should not work
688 tconn = session_lookup_connection_wt4 (0, &tc2->lcl_ip.ip4,
690 tc2->lcl_port, tc2->rmt_port,
691 tc2->proto, 0, &is_filtered);
692 TCP_TEST ((tconn == 0), "lookup result should be null");
695 * Delete and lookup again
697 session_lookup_del_connection (tc1);
698 tconn = session_lookup_connection_wt4 (0, &tc1->lcl_ip.ip4,
700 tc1->lcl_port, tc1->rmt_port,
701 tc1->proto, 0, &is_filtered);
702 TCP_TEST ((tconn == 0), "lookup result should be null");
703 tconn = session_lookup_connection_wt4 (0, &tc2->lcl_ip.ip4,
705 tc2->lcl_port, tc2->rmt_port,
706 tc2->proto, 0, &is_filtered);
707 TCP_TEST ((tconn == 0), "lookup result should be null");
710 * Re-add and lookup tc2
712 session_lookup_add_connection (tc1, tc1->s_index);
713 tconn = session_lookup_connection_wt4 (0, &tc2->lcl_ip.ip4,
715 tc2->lcl_port, tc2->rmt_port,
716 tc2->proto, 0, &is_filtered);
717 TCP_TEST ((tconn == 0), "lookup result should be null");
723 tcp_test_session (vlib_main_t * vm, unformat_input_t * input)
726 tcp_connection_t *tc0;
727 ip4_address_t local, remote;
728 u16 local_port, remote_port;
729 tcp_main_t *tm = vnet_get_tcp_main ();
733 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
735 if (unformat (input, "del"))
737 else if (unformat (input, "add"))
745 local.as_u32 = clib_host_to_net_u32 (0x06000101);
746 remote.as_u32 = clib_host_to_net_u32 (0x06000102);
747 local_port = clib_host_to_net_u16 (1234);
748 remote_port = clib_host_to_net_u16 (11234);
750 pool_get (tm->connections[0], tc0);
751 clib_memset (tc0, 0, sizeof (*tc0));
753 tc0->state = TCP_STATE_ESTABLISHED;
755 tc0->c_c_index = tc0 - tm->connections[0];
756 tc0->c_lcl_port = local_port;
757 tc0->c_rmt_port = remote_port;
759 tc0->c_thread_index = 0;
760 tc0->c_lcl_ip4.as_u32 = local.as_u32;
761 tc0->c_rmt_ip4.as_u32 = remote.as_u32;
762 tc0->rcv_opts.mss = 1450;
763 tcp_connection_init_vars (tc0);
765 TCP_EVT (TCP_EVT_OPEN, tc0);
767 if (session_stream_accept (&tc0->connection, 0 /* listener index */ ,
768 0 /* thread index */ , 0 /* notify */ ))
769 clib_warning ("stream_session_accept failed");
771 session_stream_accept_notify (&tc0->connection);
775 tc0 = tcp_connection_get (0 /* connection index */ , 0 /* thread */ );
776 tc0->state = TCP_STATE_CLOSED;
777 session_transport_closing_notify (&tc0->connection);
784 tbt_seq_lt (u32 a, u32 b)
786 return seq_lt (a, b);
790 approx_equal (u32 a, u32 b)
792 if (b > 0.99 * a && b < 1.01 * a)
798 tcp_test_delivery (vlib_main_t * vm, unformat_input_t * input)
800 u32 thread_index = 0, snd_una, *min_seqs = 0;
801 tcp_rate_sample_t _rs = { 0 }, *rs = &_rs;
802 tcp_connection_t _tc, *tc = &_tc;
803 sack_scoreboard_t *sb = &tc->sack_sb;
804 int __clib_unused verbose = 0, i;
805 u64 rate = 1000, burst = 100;
806 sack_block_t *sacks = 0;
807 tcp_byte_tracker_t *bt;
808 rb_node_t *root, *rbn;
809 tcp_bt_sample_t *bts;
811 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
813 if (unformat (input, "verbose"))
817 vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
823 /* Init data structures */
824 memset (tc, 0, sizeof (*tc));
825 session_main.wrk[thread_index].last_vlib_time = 1;
826 transport_connection_tx_pacer_update (&tc->connection, rate);
832 * Track simple bursts without rxt
835 /* 1) track first burst a time 1 */
836 tcp_bt_track_tx (tc);
838 TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
839 TCP_TEST (pool_elts (bt->samples) == 1, "should have 1 sample");
840 bts = pool_elt_at_index (bt->samples, bt->head);
841 TCP_TEST (bts->min_seq == tc->snd_una, "min seq should be snd_una");
842 TCP_TEST (bts->next == TCP_BTS_INVALID_INDEX, "next should be invalid");
843 TCP_TEST (bts->prev == TCP_BTS_INVALID_INDEX, "prev should be invalid");
844 TCP_TEST (bts->delivered_time == 1, "delivered time should be 1");
845 TCP_TEST (bts->delivered == 0, "delivered should be 0");
846 TCP_TEST (!(bts->flags & TCP_BTS_IS_RXT), "not retransmitted");
847 TCP_TEST (!(bts->flags & TCP_BTS_IS_APP_LIMITED), "not app limited");
849 /* 2) check delivery rate at time 2 */
850 session_main.wrk[thread_index].last_vlib_time = 2;
851 tc->snd_una = tc->snd_nxt = burst;
852 tc->bytes_acked = burst;
854 tcp_bt_sample_delivery_rate (tc, rs);
856 TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
857 TCP_TEST (pool_elts (bt->samples) == 0, "sample should've been consumed");
858 TCP_TEST (tc->delivered_time == 2, "delivered time should be 2");
859 TCP_TEST (tc->delivered == burst, "delivered should be 100");
860 TCP_TEST (rs->interval_time == 1, "ack time should be 1");
861 TCP_TEST (rs->delivered == burst, "delivered should be 100");
862 TCP_TEST (rs->prior_delivered == 0, "sample delivered should be 0");
863 TCP_TEST (approx_equal (rate, rs->tx_rate), "rate should be %u is %u", rate,
865 TCP_TEST (!(rs->flags & TCP_BTS_IS_RXT), "not retransmitted");
867 /* 3) track second burst at time 2 */
868 tcp_bt_track_tx (tc);
869 tc->snd_nxt += burst;
871 /* 4) track second burst at time 3 */
872 session_main.wrk[thread_index].last_vlib_time = 3;
873 tcp_bt_track_tx (tc);
874 tc->snd_nxt += burst;
876 TCP_TEST (pool_elts (bt->samples) == 2, "should have 2 samples");
878 TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
879 bts = pool_elt_at_index (bt->samples, bt->head);
880 TCP_TEST (bts->min_seq == tc->snd_una, "min seq should be snd_una");
881 TCP_TEST (bts->next == bt->tail, "next should tail");
883 bts = pool_elt_at_index (bt->samples, bt->tail);
884 TCP_TEST (bts->min_seq == tc->snd_nxt - burst,
885 "min seq should be snd_nxt prior to burst");
886 TCP_TEST (bts->prev == bt->head, "prev should be head");
888 /* 5) check delivery rate at time 4 */
889 session_main.wrk[thread_index].last_vlib_time = 4;
890 tc->snd_una = tc->snd_nxt;
891 tc->bytes_acked = 2 * burst;
893 tcp_bt_sample_delivery_rate (tc, rs);
895 TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
896 TCP_TEST (pool_elts (bt->samples) == 0, "sample should've been consumed");
897 TCP_TEST (tc->delivered_time == 4, "delivered time should be 4");
898 TCP_TEST (tc->delivered == 3 * burst, "delivered should be 300 is %u",
900 TCP_TEST (rs->interval_time == 2, "ack time should be 2");
901 TCP_TEST (rs->delivered == 2 * burst, "delivered should be 200");
902 TCP_TEST (rs->prior_delivered == burst, "delivered should be 100");
903 TCP_TEST (approx_equal (rate, rs->tx_rate), "rate should be %u is %u", rate,
905 TCP_TEST (!(rs->flags & TCP_BTS_IS_RXT), "not retransmitted");
906 TCP_TEST (!(bts->flags & TCP_BTS_IS_APP_LIMITED), "not app limited");
909 * Track retransmissions
911 * snd_una should be 300 at this point
914 snd_una = tc->snd_una;
916 /* 1) track first burst a time 4 */
917 tcp_bt_track_tx (tc);
918 tc->snd_nxt += burst;
920 /* 2) track second burst at time 5 */
921 session_main.wrk[thread_index].last_vlib_time = 5;
922 tcp_bt_track_tx (tc);
923 tc->snd_nxt += burst;
925 /* 3) track third burst at time 6 */
926 session_main.wrk[thread_index].last_vlib_time = 6;
927 tcp_bt_track_tx (tc);
928 tc->snd_nxt += burst;
930 /* 4) track fourth burst at time 7 */
931 session_main.wrk[thread_index].last_vlib_time = 7;
932 /* Limited until last burst is acked */
933 tc->app_limited = snd_una + 4 * burst - 1;
934 tcp_bt_track_tx (tc);
935 tc->snd_nxt += burst;
937 /* 5) check delivery rate at time 8
939 * tc->snd_una = snd_una + 10
941 * [snd_una + burst, snd_una + burst + 10]
942 * [snd_una + 2 * burst + 10, snd_una + 2 * burst + 20]
944 session_main.wrk[thread_index].last_vlib_time = 8;
946 tc->bytes_acked = 10;
947 sb->last_sacked_bytes = 20;
949 TCP_TEST (pool_elts (bt->samples) == 4, "there should be 4 samples");
951 vec_validate (sacks, 1);
952 sacks[0].start = snd_una + burst;
953 sacks[0].end = snd_una + burst + 10;
954 sacks[1].start = snd_una + 2 * burst + 10;
955 sacks[1].end = snd_una + 2 * burst + 20;
956 tc->rcv_opts.sacks = sacks;
958 tcp_bt_sample_delivery_rate (tc, rs);
960 TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
961 TCP_TEST (pool_elts (bt->samples) == 4, "there should be 4 samples");
962 TCP_TEST (tc->delivered_time == 8, "delivered time should be 8");
963 TCP_TEST (tc->delivered == 3 * burst + 30, "delivered should be %u is %u",
964 3 * burst + 30, tc->delivered);
965 /* All 3 samples have the same delivered number of bytes. So the first is
966 * the reference for delivery estimate. */
967 TCP_TEST (rs->interval_time == 4, "ack time should be 4 is %.2f",
969 TCP_TEST (rs->delivered == 30, "delivered should be 30");
970 TCP_TEST (rs->prior_delivered == 3 * burst,
971 "sample delivered should be %u", 3 * burst);
972 TCP_TEST (approx_equal (rate, rs->tx_rate), "rate should be %u is %u", rate,
974 TCP_TEST (!(rs->flags & TCP_BTS_IS_RXT), "not retransmitted");
975 TCP_TEST (!(rs->flags & TCP_BTS_IS_APP_LIMITED), "not app limited");
977 /* 6) Retransmit and track at time 9
979 * delivered = 3 * burst + 30
980 * delivered_time = 8 (last ack)
983 * [snd_una + 10, snd_una + burst]
984 * [snd_una + burst + 10, snd_una + 2 * burst + 10]
985 * [snd_una + 2 * burst + 20, snd_una + 4 * burst]
987 session_main.wrk[thread_index].last_vlib_time = 9;
989 tcp_bt_track_rxt (tc, snd_una + 10, snd_una + burst);
990 TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
991 /* The retransmit covers everything left from first burst */
992 TCP_TEST (pool_elts (bt->samples) == 4, "there should be 4 samples");
994 tcp_bt_track_rxt (tc, snd_una + burst + 10, snd_una + 2 * burst + 10);
995 TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
996 TCP_TEST (pool_elts (bt->samples) == 5, "there should be 5 samples");
998 /* Retransmit covers last sample entirely so it should be removed */
999 tcp_bt_track_rxt (tc, snd_una + 2 * burst + 20, snd_una + 4 * burst);
1000 TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
1001 TCP_TEST (pool_elts (bt->samples) == 5, "there should be 5 samples");
1003 vec_validate (min_seqs, 4);
1004 min_seqs[0] = snd_una + 10;
1005 min_seqs[1] = snd_una + burst;
1006 min_seqs[2] = snd_una + burst + 10;
1007 min_seqs[3] = snd_una + 2 * burst + 10;
1008 min_seqs[4] = snd_una + 2 * burst + 20;
1010 root = bt->sample_lookup.nodes + bt->sample_lookup.root;
1011 bts = bt->samples + bt->head;
1012 for (i = 0; i < vec_len (min_seqs); i++)
1014 if (bts->min_seq != min_seqs[i])
1015 TCP_TEST (0, "should be %u is %u", min_seqs[i], bts->min_seq);
1016 rbn = rb_tree_search_subtree_custom (&bt->sample_lookup, root,
1017 bts->min_seq, tbt_seq_lt);
1018 if (rbn->opaque != bts - bt->samples)
1019 TCP_TEST (0, "lookup should work");
1020 bts = bt->samples + bts->next;
1023 /* 7) check delivery rate at time 10
1025 * tc->snd_una = snd_una + 2 * burst
1027 * [snd_una + 2 * burst + 20, snd_una + 2 * burst + 30]
1028 * [snd_una + 2 * burst + 50, snd_una + 2 * burst + 60]
1030 session_main.wrk[thread_index].last_vlib_time = 10;
1031 tc->snd_una = snd_una + 2 * burst;
1032 tc->bytes_acked = 2 * burst - 10;
1033 sb->last_sacked_bytes = 20;
1035 sacks[0].start = snd_una + 2 * burst + 20;
1036 sacks[0].end = snd_una + 2 * burst + 30;
1037 sacks[1].start = snd_una + 2 * burst + 50;
1038 sacks[1].end = snd_una + 2 * burst + 60;
1040 tcp_bt_sample_delivery_rate (tc, rs);
1042 TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
1043 TCP_TEST (pool_elts (bt->samples) == 3, "num samples should be 3 is %u",
1044 pool_elts (bt->samples));
1045 TCP_TEST (tc->delivered_time == 10, "delivered time should be 10");
1046 TCP_TEST (tc->delivered == 5 * burst + 40, "delivered should be %u is %u",
1047 5 * burst + 40, tc->delivered);
1048 /* A rxt was acked and delivered time for it is 8 (last ack time) */
1049 TCP_TEST (rs->interval_time == 2, "ack time should be 2 is %.2f",
1051 /* delivered_now - delivered_rxt ~ 5 * burst + 40 - 3 * burst - 30 */
1052 TCP_TEST (rs->delivered == 2 * burst + 10, "delivered should be 210 is %u",
1054 TCP_TEST (rs->prior_delivered == 3 * burst + 30,
1055 "sample delivered should be %u", 3 * burst + 30);
1056 TCP_TEST (approx_equal (rate, rs->tx_rate), "rate should be %u is %u", rate,
1058 TCP_TEST (rs->flags & TCP_BTS_IS_RXT, "is retransmitted");
1059 /* Sample is app limited because of the retransmits */
1060 TCP_TEST (rs->flags & TCP_BTS_IS_APP_LIMITED, "is app limited");
1061 TCP_TEST (tc->app_limited, "app limited should be set");
1064 * 8) check delivery rate at time 11
1066 session_main.wrk[thread_index].last_vlib_time = 11;
1067 tc->snd_una = tc->snd_nxt;
1068 tc->bytes_acked = 2 * burst;
1069 sb->last_sacked_bytes = 0;
1070 sb->last_bytes_delivered = 40;
1072 memset (rs, 0, sizeof (*rs));
1073 tcp_bt_sample_delivery_rate (tc, rs);
1075 TCP_TEST (tcp_bt_is_sane (bt), "tracker should be sane");
1076 TCP_TEST (pool_elts (bt->samples) == 0, "num samples should be 0 is %u",
1077 pool_elts (bt->samples));
1078 TCP_TEST (tc->delivered_time == 11, "delivered time should be 11");
1079 TCP_TEST (tc->delivered == 7 * burst, "delivered should be %u is %u",
1080 7 * burst, tc->delivered);
1081 /* Last rxt was at time 8 */
1082 TCP_TEST (rs->interval_time == 3, "ack time should be 3 is %.2f",
1084 /* delivered_now - delivered_rxt ~ 7 * burst - 3 * burst - 30.
1085 * That's because we didn't retransmit any new segment. */
1086 TCP_TEST (rs->delivered == 4 * burst - 30, "delivered should be 160 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 TCP_TEST (rs->flags & TCP_BTS_IS_APP_LIMITED, "is app limited");
1094 TCP_TEST (tc->app_limited == 0, "app limited should be cleared");
1100 tcp_bt_track_tx (tc);
1101 tc->snd_nxt += burst;
1103 session_main.wrk[thread_index].last_vlib_time = 12;
1104 tcp_bt_track_tx (tc);
1105 tc->snd_nxt += burst;
1107 tcp_bt_flush_samples (tc);
1113 vec_free (min_seqs);
1114 tcp_bt_cleanup (tc);
1118 static clib_error_t *
1119 tcp_test (vlib_main_t * vm,
1120 unformat_input_t * input, vlib_cli_command_t * cmd_arg)
1124 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1126 if (unformat (input, "sack"))
1128 res = tcp_test_sack (vm, input);
1130 else if (unformat (input, "session"))
1132 res = tcp_test_session (vm, input);
1134 else if (unformat (input, "lookup"))
1136 res = tcp_test_lookup (vm, input);
1138 else if (unformat (input, "delivery"))
1140 res = tcp_test_delivery (vm, input);
1142 else if (unformat (input, "all"))
1144 if ((res = tcp_test_sack (vm, input)))
1146 if ((res = tcp_test_lookup (vm, input)))
1148 if ((res = tcp_test_delivery (vm, input)))
1157 return clib_error_return (0, "TCP unit test failed");
1162 VLIB_CLI_COMMAND (tcp_test_command, static) =
1165 .short_help = "internal tcp unit tests",
1166 .function = tcp_test,
1171 * fd.io coding-style-patch-verification: ON
1174 * eval: (c-set-style "gnu")