blob: 74947474b5381fbc8c56b71a6197a514258ca418 [file] [log] [blame]
Florin Coras52814732019-06-12 15:38:19 -07001/*
2 * Copyright (c) 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 * TCP byte tracker that can generate delivery rate estimates. Based on
16 * draft-cheng-iccrg-delivery-rate-estimation-00
17 */
18
19#include <vnet/tcp/tcp.h>
20
21static tcp_bt_sample_t *
22bt_get_sample (tcp_byte_tracker_t * bt, u32 bts_index)
23{
24 if (pool_is_free_index (bt->samples, bts_index))
25 return 0;
26 return pool_elt_at_index (bt->samples, bts_index);
27}
28
29static tcp_bt_sample_t *
30bt_next_sample (tcp_byte_tracker_t * bt, tcp_bt_sample_t * bts)
31{
32 return bt_get_sample (bt, bts->next);
33}
34
35static tcp_bt_sample_t *
36bt_prev_sample (tcp_byte_tracker_t * bt, tcp_bt_sample_t * bts)
37{
38 return bt_get_sample (bt, bts->prev);
39}
40
41static u32
42bt_sample_index (tcp_byte_tracker_t * bt, tcp_bt_sample_t * bts)
43{
44 if (!bts)
45 return TCP_BTS_INVALID_INDEX;
46 return bts - bt->samples;
47}
48
49static inline int
50bt_seq_lt (u32 a, u32 b)
51{
52 return seq_lt (a, b);
53}
54
55static tcp_bt_sample_t *
56bt_alloc_sample (tcp_byte_tracker_t * bt, u32 min_seq)
57{
58 tcp_bt_sample_t *bts;
59
60 pool_get_zero (bt->samples, bts);
61 bts->next = bts->prev = TCP_BTS_INVALID_INDEX;
62 bts->min_seq = min_seq;
63 rb_tree_add_custom (&bt->sample_lookup, bts->min_seq, bts - bt->samples,
64 bt_seq_lt);
65 return bts;
66}
67
68static void
69bt_free_sample (tcp_byte_tracker_t * bt, tcp_bt_sample_t * bts)
70{
71 if (bts->prev != TCP_BTS_INVALID_INDEX)
72 {
73 tcp_bt_sample_t *prev = bt_prev_sample (bt, bts);
74 prev->next = bts->next;
75 }
76 else
77 bt->head = bts->next;
78
79 if (bts->next != TCP_BTS_INVALID_INDEX)
80 {
81 tcp_bt_sample_t *next = bt_next_sample (bt, bts);
82 next->prev = bts->prev;
83 }
84 else
85 bt->tail = bts->prev;
86
87 rb_tree_del_custom (&bt->sample_lookup, bts->min_seq, bt_seq_lt);
88 if (CLIB_DEBUG)
89 memset (bts, 0xfc, sizeof (*bts));
90 pool_put (bt->samples, bts);
91}
92
93static tcp_bt_sample_t *
94bt_lookup_seq (tcp_byte_tracker_t * bt, u32 seq)
95{
96 rb_tree_t *rt = &bt->sample_lookup;
97 rb_node_t *cur, *prev;
98 tcp_bt_sample_t *bts;
99
100 cur = rb_node (rt, rt->root);
101 if (rb_node_is_tnil (rt, cur))
102 return 0;
103
104 while (seq != cur->key)
105 {
106 prev = cur;
107 if (seq_lt (seq, cur->key))
108 cur = rb_node_left (rt, cur);
109 else
110 cur = rb_node_right (rt, cur);
111
112 if (rb_node_is_tnil (rt, cur))
113 {
114 /* Hit tnil as a left child. Find predecessor */
115 if (seq_lt (seq, prev->key))
116 {
117 cur = rb_tree_predecessor (rt, prev);
118 if (rb_node_is_tnil (rt, cur))
119 return 0;
120 bts = bt_get_sample (bt, cur->opaque);
121 }
122 /* Hit tnil as a right child */
123 else
124 {
125 bts = bt_get_sample (bt, prev->opaque);
126 }
127
128 if (seq_geq (seq, bts->min_seq))
129 return bts;
130
131 return 0;
132 }
133 }
134
135 if (!rb_node_is_tnil (rt, cur))
136 return bt_get_sample (bt, cur->opaque);
137
138 return 0;
139}
140
141static void
142bt_update_sample (tcp_byte_tracker_t * bt, tcp_bt_sample_t * bts, u32 seq)
143{
144 rb_tree_del_custom (&bt->sample_lookup, bts->min_seq, bt_seq_lt);
145 bts->min_seq = seq;
146 rb_tree_add_custom (&bt->sample_lookup, bts->min_seq,
147 bt_sample_index (bt, bts), bt_seq_lt);
148}
149
150static tcp_bt_sample_t *
151bt_fix_overlapped (tcp_byte_tracker_t * bt, tcp_bt_sample_t * start,
152 u32 seq, u8 is_end)
153{
154 tcp_bt_sample_t *cur, *next;
155
156 cur = start;
157 while ((next = bt_next_sample (bt, cur)) && seq_lt (next->min_seq, seq))
158 {
159 bt_free_sample (bt, cur);
160 cur = next;
161 }
162
163 if (next)
164 {
165 bt_free_sample (bt, cur);
166 return next;
167 }
168
169 /* Overlapping current entirely */
170 if (is_end)
171 {
172 bt_free_sample (bt, cur);
173 return 0;
174 }
175
176 /* Overlapping head of current but not all */
177 bt_update_sample (bt, cur, seq);
178 return cur;
179}
180
181int
182tcp_bt_is_sane (tcp_byte_tracker_t * bt)
183{
184 tcp_bt_sample_t *bts, *tmp;
185
186 if (pool_elts (bt->samples) != pool_elts (bt->sample_lookup.nodes) - 1)
187 return 0;
188
189 if (bt->head == TCP_BTS_INVALID_INDEX)
190 {
191 if (bt->tail != TCP_BTS_INVALID_INDEX)
192 return 0;
193 if (pool_elts (bt->samples) != 0)
194 return 0;
195 return 1;
196 }
197
198 bts = bt_get_sample (bt, bt->tail);
199 if (!bts)
200 return 0;
201
202 bts = bt_get_sample (bt, bt->head);
203 if (!bts || bts->prev != TCP_BTS_INVALID_INDEX)
204 return 0;
205
206 while (bts)
207 {
208 tmp = bt_lookup_seq (bt, bts->min_seq);
209 if (!tmp)
210 return 0;
211 if (tmp != bts)
212 return 0;
213 tmp = bt_next_sample (bt, bts);
214 if (tmp)
215 {
216 if (tmp->prev != bt_sample_index (bt, bts))
217 {
218 clib_warning ("next %u thinks prev is %u should be %u",
219 bts->next, tmp->prev, bt_sample_index (bt, bts));
220 return 0;
221 }
222 if (!seq_lt (bts->min_seq, tmp->min_seq))
223 return 0;
224 }
225 else
226 {
227 if (bt->tail != bt_sample_index (bt, bts))
228 return 0;
229 if (bts->next != TCP_BTS_INVALID_INDEX)
230 return 0;
231 }
232 bts = tmp;
233 }
234 return 1;
235}
236
237static tcp_bt_sample_t *
238tcp_bt_alloc_tx_sample (tcp_connection_t * tc, u32 min_seq)
239{
240 tcp_bt_sample_t *bts;
241 bts = bt_alloc_sample (tc->bt, min_seq);
242 bts->delivered = tc->delivered;
243 bts->delivered_time = tc->delivered_time;
244 bts->tx_rate = transport_connection_tx_pacer_rate (&tc->connection);
245 bts->flags |= tc->app_limited ? TCP_BTS_IS_APP_LIMITED : 0;
246 return bts;
247}
248
249void
250tcp_bt_check_app_limited (tcp_connection_t * tc)
251{
252 u32 available_bytes, flight_size;
253
254 available_bytes = transport_max_tx_dequeue (&tc->connection);
255 flight_size = tcp_flight_size (tc);
256
257 /* Not enough bytes to fill the cwnd */
258 if (available_bytes + flight_size + tc->snd_mss < tc->cwnd
259 /* Bytes considered lost have been retransmitted */
260 && tc->sack_sb.lost_bytes <= tc->snd_rxt_bytes)
261 tc->app_limited = tc->delivered + flight_size ? : 1;
262}
263
264void
265tcp_bt_track_tx (tcp_connection_t * tc)
266{
267 tcp_byte_tracker_t *bt = tc->bt;
268 tcp_bt_sample_t *bts, *tail;
269 u32 bts_index;
270
271 if (!tcp_flight_size (tc))
272 tc->delivered_time = tcp_time_now_us (tc->c_thread_index);
273
274 bts = tcp_bt_alloc_tx_sample (tc, tc->snd_nxt);
275 bts_index = bt_sample_index (bt, bts);
276 tail = bt_get_sample (bt, bt->tail);
277 if (tail)
278 {
279 tail->next = bts_index;
280 bts->prev = bt->tail;
281 bt->tail = bts_index;
282 }
283 else
284 {
285 bt->tail = bt->head = bts_index;
286 }
287}
288
289void
290tcp_bt_track_rxt (tcp_connection_t * tc, u32 start, u32 end)
291{
292 tcp_byte_tracker_t *bt = tc->bt;
293 tcp_bt_sample_t *bts, *next, *cur, *prev, *nbts;
294 u32 bts_index, cur_index, next_index, prev_index, min_seq;
295 u8 is_end = end == tc->snd_nxt;
296
297 bts = bt_get_sample (bt, bt->last_ooo);
298 if (bts && bts->max_seq == start)
299 {
300 bts->max_seq = end;
301 next = bt_next_sample (bt, bts);
302 if (next)
303 bt_fix_overlapped (bt, next, end, is_end);
304
305 return;
306 }
307
308 /* Find original tx sample */
309 bts = bt_lookup_seq (bt, start);
310
311 ASSERT (bts != 0 && seq_geq (start, bts->min_seq));
312
313 /* Head in the past */
314 if (seq_lt (bts->min_seq, tc->snd_una))
315 bt_update_sample (bt, bts, tc->snd_una);
316
317 /* Head overlap */
318 if (bts->min_seq == start)
319 {
320 prev_index = bts->prev;
321 next = bt_fix_overlapped (bt, bts, end, is_end);
322 next_index = bt_sample_index (bt, next);
323
324 cur = tcp_bt_alloc_tx_sample (tc, start);
325 cur->max_seq = end;
326 cur->flags |= TCP_BTS_IS_RXT;
327 cur->next = next_index;
328 cur->prev = prev_index;
329
330 cur_index = bt_sample_index (bt, cur);
331
332 if (next_index != TCP_BTS_INVALID_INDEX)
333 {
334 next = bt_get_sample (bt, next_index);
335 next->prev = cur_index;
336 }
337 else
338 {
339 bt->tail = cur_index;
340 }
341
342 if (prev_index != TCP_BTS_INVALID_INDEX)
343 {
344 prev = bt_get_sample (bt, prev_index);
345 prev->next = cur_index;
346 }
347 else
348 {
349 bt->head = cur_index;
350 }
351
352 bt->last_ooo = cur_index;
353 return;
354 }
355
356 bts_index = bt_sample_index (bt, bts);
357 next = bt_next_sample (bt, bts);
358 if (next)
359 next = bt_fix_overlapped (bt, next, end, is_end);
360
361 min_seq = next ? next->min_seq : tc->snd_nxt;
362 ASSERT (seq_lt (start, min_seq));
363
364 /* Have to split or tail overlap */
365 cur = tcp_bt_alloc_tx_sample (tc, start);
366 cur->max_seq = end;
367 cur->flags |= TCP_BTS_IS_RXT;
368 cur->prev = bts_index;
369 cur_index = bt_sample_index (bt, cur);
370
371 /* Split. Allocate another sample */
372 if (seq_lt (end, min_seq))
373 {
374 nbts = tcp_bt_alloc_tx_sample (tc, end);
375 cur = bt_get_sample (bt, cur_index);
376 bts = bt_get_sample (bt, bts_index);
377
378 *nbts = *bts;
379 nbts->min_seq = end;
380
381 if (nbts->next != TCP_BTS_INVALID_INDEX)
382 {
383 next = bt_get_sample (bt, nbts->next);
384 next->prev = bt_sample_index (bt, nbts);
385 }
386 else
387 bt->tail = bt_sample_index (bt, nbts);
388
389 bts->next = nbts->prev = cur_index;
390 cur->next = bt_sample_index (bt, nbts);
391
392 bt->last_ooo = cur_index;
393 }
394 /* Tail completely overlapped */
395 else
396 {
397 bts = bt_get_sample (bt, bts_index);
398
399 if (bts->next != TCP_BTS_INVALID_INDEX)
400 {
401 next = bt_get_sample (bt, bts->next);
402 next->prev = cur_index;
403 }
404 else
405 bt->tail = cur_index;
406
407 cur->next = bts->next;
408 bts->next = cur_index;
409
410 bt->last_ooo = cur_index;
411 }
412}
413
414static void
415tcp_bt_sample_to_rate_sample (tcp_connection_t * tc, tcp_bt_sample_t * bts,
416 tcp_rate_sample_t * rs)
417{
418 if (rs->sample_delivered && rs->sample_delivered >= bts->delivered)
419 return;
420
421 rs->sample_delivered = bts->delivered;
422 rs->delivered = tc->delivered - bts->delivered;
423 rs->ack_time = tc->delivered_time - bts->delivered_time;
424 rs->tx_rate = bts->tx_rate;
425 rs->flags = bts->flags;
426}
427
428static void
429tcp_bt_walk_samples (tcp_connection_t * tc, tcp_rate_sample_t * rs)
430{
431 tcp_byte_tracker_t *bt = tc->bt;
432 tcp_bt_sample_t *next, *cur;
433
434 cur = bt_get_sample (bt, bt->head);
435 tcp_bt_sample_to_rate_sample (tc, cur, rs);
436 while ((next = bt_get_sample (bt, cur->next))
437 && seq_lt (next->min_seq, tc->snd_una))
438 {
439 bt_free_sample (bt, cur);
440 tcp_bt_sample_to_rate_sample (tc, next, rs);
441 cur = next;
442 }
443
444 ASSERT (seq_lt (cur->min_seq, tc->snd_una));
445
446 /* All samples acked */
447 if (tc->snd_una == tc->snd_nxt)
448 {
449 ASSERT (pool_elts (bt->samples) == 1);
450 bt_free_sample (bt, cur);
451 return;
452 }
453
454 /* Current sample completely consumed */
455 if (next && next->min_seq == tc->snd_una)
456 {
457 bt_free_sample (bt, cur);
458 cur = next;
459 }
460}
461
462static void
463tcp_bt_walk_samples_ooo (tcp_connection_t * tc, tcp_rate_sample_t * rs)
464{
465 sack_block_t *blks = tc->rcv_opts.sacks, *blk;
466 tcp_byte_tracker_t *bt = tc->bt;
467 tcp_bt_sample_t *next, *cur;
468 int i;
469
470 for (i = 0; i < vec_len (blks); i++)
471 {
472 blk = &blks[i];
473
474 /* Ignore blocks that are already covered by snd_una */
475 if (seq_lt (blk->end, tc->snd_una))
476 continue;
477
478 cur = bt_lookup_seq (bt, blk->start);
479 if (!cur)
480 continue;
481
482 tcp_bt_sample_to_rate_sample (tc, cur, rs);
483
484 /* Current shouldn't be removed */
485 if (cur->min_seq != blk->start)
486 {
487 cur = bt_next_sample (bt, cur);
488 if (!cur)
489 continue;
490 }
491
492 while ((next = bt_get_sample (bt, cur->next))
493 && seq_lt (next->min_seq, blk->end))
494 {
495 bt_free_sample (bt, cur);
496 tcp_bt_sample_to_rate_sample (tc, next, rs);
497 cur = next;
498 }
499
500 /* Current consumed entirely */
501 if (next && next->min_seq == blk->end)
502 bt_free_sample (bt, cur);
503 }
504}
505
506void
507tcp_bt_sample_delivery_rate (tcp_connection_t * tc, tcp_rate_sample_t * rs)
508{
509 u32 delivered;
510
511 if (PREDICT_FALSE (tc->flags & TCP_CONN_FINSNT))
512 return;
513
514 delivered = tc->bytes_acked + tc->sack_sb.last_sacked_bytes;
515 if (!delivered || tc->bt->head == TCP_BTS_INVALID_INDEX)
516 return;
517
518 /* Do not count bytes that were previously sacked again */
519 tc->delivered += delivered - tc->sack_sb.last_bytes_delivered;
520 tc->delivered_time = tcp_time_now_us (tc->c_thread_index);
521
522 if (tc->app_limited && tc->delivered > tc->app_limited)
523 tc->app_limited = 0;
524
525 if (tc->bytes_acked)
526 tcp_bt_walk_samples (tc, rs);
527
528 if (tc->sack_sb.last_sacked_bytes)
529 tcp_bt_walk_samples_ooo (tc, rs);
530}
531
532void
533tcp_bt_flush_samples (tcp_connection_t * tc)
534{
535 tcp_byte_tracker_t *bt = tc->bt;
536 tcp_bt_sample_t *bts;
537 u32 *samples = 0, *si;
538
539 vec_validate (samples, pool_elts (bt->samples) - 1);
540
541 /* *INDENT-OFF* */
542 pool_foreach (bts, bt->samples, ({
543 vec_add1 (samples, bts - bt->samples);
544 }));
545 /* *INDENT-ON* */
546
547 vec_foreach (si, samples)
548 {
549 bts = bt_get_sample (bt, *si);
550 bt_free_sample (bt, bts);
551 }
552
553 vec_free (samples);
554}
555
556void
557tcp_bt_cleanup (tcp_connection_t * tc)
558{
559 tcp_byte_tracker_t *bt = tc->bt;
560
561 rb_tree_free_nodes (&bt->sample_lookup);
562 pool_free (bt->samples);
563 clib_mem_free (bt);
564 tc->bt = 0;
565}
566
567void
568tcp_bt_init (tcp_connection_t * tc)
569{
570 tcp_byte_tracker_t *bt;
571
572 bt = clib_mem_alloc (sizeof (tcp_byte_tracker_t));
573 clib_memset (bt, 0, sizeof (tcp_byte_tracker_t));
574
575 rb_tree_init (&bt->sample_lookup);
576 bt->head = bt->tail = TCP_BTS_INVALID_INDEX;
577 tc->bt = bt;
578}
579
580/*
581 * fd.io coding-style-patch-verification: ON
582 *
583 * Local Variables:
584 * eval: (c-set-style "gnu")
585 * End:
586 */