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