blob: e8dc5c9c068f454dbf581323929a7943010b355b [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 *
Florin Corasd6ae4bf2019-10-12 18:10:20 -070056bt_alloc_sample (tcp_byte_tracker_t * bt, u32 min_seq, u32 max_seq)
Florin Coras52814732019-06-12 15:38:19 -070057{
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;
Florin Corasd6ae4bf2019-10-12 18:10:20 -070063 bts->max_seq = max_seq;
Florin Coras52814732019-06-12 15:38:19 -070064 rb_tree_add_custom (&bt->sample_lookup, bts->min_seq, bts - bt->samples,
65 bt_seq_lt);
66 return bts;
67}
68
69static void
70bt_free_sample (tcp_byte_tracker_t * bt, tcp_bt_sample_t * bts)
71{
72 if (bts->prev != TCP_BTS_INVALID_INDEX)
73 {
74 tcp_bt_sample_t *prev = bt_prev_sample (bt, bts);
75 prev->next = bts->next;
76 }
77 else
78 bt->head = bts->next;
79
80 if (bts->next != TCP_BTS_INVALID_INDEX)
81 {
82 tcp_bt_sample_t *next = bt_next_sample (bt, bts);
83 next->prev = bts->prev;
84 }
85 else
86 bt->tail = bts->prev;
87
88 rb_tree_del_custom (&bt->sample_lookup, bts->min_seq, bt_seq_lt);
89 if (CLIB_DEBUG)
90 memset (bts, 0xfc, sizeof (*bts));
91 pool_put (bt->samples, bts);
92}
93
94static tcp_bt_sample_t *
Florin Corasd6ae4bf2019-10-12 18:10:20 -070095bt_split_sample (tcp_byte_tracker_t * bt, tcp_bt_sample_t * bts, u32 seq)
96{
97 tcp_bt_sample_t *ns, *next;
98 u32 bts_index;
99
100 bts_index = bt_sample_index (bt, bts);
101
102 ASSERT (seq_leq (bts->min_seq, seq) && seq_lt (seq, bts->max_seq));
103
104 ns = bt_alloc_sample (bt, seq, bts->max_seq);
105 bts = bt_get_sample (bt, bts_index);
106
107 *ns = *bts;
108 ns->min_seq = seq;
109 bts->max_seq = seq;
110
111 next = bt_next_sample (bt, bts);
112 if (next)
113 next->prev = bt_sample_index (bt, ns);
114 else
115 bt->tail = bt_sample_index (bt, ns);
116
117 bts->next = bt_sample_index (bt, ns);
118 ns->prev = bt_sample_index (bt, bts);
119
120 return ns;
121}
122
123static tcp_bt_sample_t *
124bt_merge_sample (tcp_byte_tracker_t * bt, tcp_bt_sample_t * prev,
125 tcp_bt_sample_t * cur)
126{
127 ASSERT (prev->max_seq == cur->min_seq);
128 prev->max_seq = cur->max_seq;
129 if (bt_sample_index (bt, cur) == bt->tail)
130 bt->tail = bt_sample_index (bt, prev);
131 bt_free_sample (bt, cur);
132 return prev;
133}
134
135static tcp_bt_sample_t *
Florin Coras52814732019-06-12 15:38:19 -0700136bt_lookup_seq (tcp_byte_tracker_t * bt, u32 seq)
137{
138 rb_tree_t *rt = &bt->sample_lookup;
139 rb_node_t *cur, *prev;
140 tcp_bt_sample_t *bts;
141
142 cur = rb_node (rt, rt->root);
143 if (rb_node_is_tnil (rt, cur))
144 return 0;
145
146 while (seq != cur->key)
147 {
148 prev = cur;
149 if (seq_lt (seq, cur->key))
150 cur = rb_node_left (rt, cur);
151 else
152 cur = rb_node_right (rt, cur);
153
154 if (rb_node_is_tnil (rt, cur))
155 {
156 /* Hit tnil as a left child. Find predecessor */
157 if (seq_lt (seq, prev->key))
158 {
159 cur = rb_tree_predecessor (rt, prev);
160 if (rb_node_is_tnil (rt, cur))
161 return 0;
162 bts = bt_get_sample (bt, cur->opaque);
163 }
164 /* Hit tnil as a right child */
165 else
166 {
167 bts = bt_get_sample (bt, prev->opaque);
168 }
169
170 if (seq_geq (seq, bts->min_seq))
171 return bts;
172
173 return 0;
174 }
175 }
176
177 if (!rb_node_is_tnil (rt, cur))
178 return bt_get_sample (bt, cur->opaque);
179
180 return 0;
181}
182
183static void
184bt_update_sample (tcp_byte_tracker_t * bt, tcp_bt_sample_t * bts, u32 seq)
185{
186 rb_tree_del_custom (&bt->sample_lookup, bts->min_seq, bt_seq_lt);
187 bts->min_seq = seq;
188 rb_tree_add_custom (&bt->sample_lookup, bts->min_seq,
189 bt_sample_index (bt, bts), bt_seq_lt);
190}
191
192static tcp_bt_sample_t *
193bt_fix_overlapped (tcp_byte_tracker_t * bt, tcp_bt_sample_t * start,
194 u32 seq, u8 is_end)
195{
196 tcp_bt_sample_t *cur, *next;
197
198 cur = start;
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700199 while (cur && seq_leq (cur->max_seq, seq))
Florin Coras52814732019-06-12 15:38:19 -0700200 {
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700201 next = bt_next_sample (bt, cur);
Florin Coras52814732019-06-12 15:38:19 -0700202 bt_free_sample (bt, cur);
203 cur = next;
204 }
205
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700206 if (cur && seq_lt (cur->min_seq, seq))
207 bt_update_sample (bt, cur, seq);
Florin Coras52814732019-06-12 15:38:19 -0700208
Florin Coras52814732019-06-12 15:38:19 -0700209 return cur;
210}
211
212int
213tcp_bt_is_sane (tcp_byte_tracker_t * bt)
214{
215 tcp_bt_sample_t *bts, *tmp;
216
217 if (pool_elts (bt->samples) != pool_elts (bt->sample_lookup.nodes) - 1)
218 return 0;
219
220 if (bt->head == TCP_BTS_INVALID_INDEX)
221 {
222 if (bt->tail != TCP_BTS_INVALID_INDEX)
223 return 0;
224 if (pool_elts (bt->samples) != 0)
225 return 0;
226 return 1;
227 }
228
229 bts = bt_get_sample (bt, bt->tail);
230 if (!bts)
231 return 0;
232
233 bts = bt_get_sample (bt, bt->head);
234 if (!bts || bts->prev != TCP_BTS_INVALID_INDEX)
235 return 0;
236
237 while (bts)
238 {
239 tmp = bt_lookup_seq (bt, bts->min_seq);
240 if (!tmp)
241 return 0;
242 if (tmp != bts)
243 return 0;
244 tmp = bt_next_sample (bt, bts);
245 if (tmp)
246 {
247 if (tmp->prev != bt_sample_index (bt, bts))
248 {
249 clib_warning ("next %u thinks prev is %u should be %u",
250 bts->next, tmp->prev, bt_sample_index (bt, bts));
251 return 0;
252 }
253 if (!seq_lt (bts->min_seq, tmp->min_seq))
254 return 0;
255 }
256 else
257 {
258 if (bt->tail != bt_sample_index (bt, bts))
259 return 0;
260 if (bts->next != TCP_BTS_INVALID_INDEX)
261 return 0;
262 }
263 bts = tmp;
264 }
265 return 1;
266}
267
268static tcp_bt_sample_t *
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700269tcp_bt_alloc_tx_sample (tcp_connection_t * tc, u32 min_seq, u32 max_seq)
Florin Coras52814732019-06-12 15:38:19 -0700270{
271 tcp_bt_sample_t *bts;
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700272 bts = bt_alloc_sample (tc->bt, min_seq, max_seq);
Florin Coras52814732019-06-12 15:38:19 -0700273 bts->delivered = tc->delivered;
274 bts->delivered_time = tc->delivered_time;
Florin Coras85fc1302019-06-26 09:12:34 -0700275 bts->tx_time = tcp_time_now_us (tc->c_thread_index);
Florin Coras7436b432019-09-10 23:26:27 -0700276 bts->first_tx_time = tc->first_tx_time;
Florin Coras52814732019-06-12 15:38:19 -0700277 bts->flags |= tc->app_limited ? TCP_BTS_IS_APP_LIMITED : 0;
Florin Corasdb88ffb2020-03-11 18:30:48 +0000278 bts->tx_in_flight = tcp_flight_size (tc);
279 bts->tx_lost = tc->lost;
Florin Coras52814732019-06-12 15:38:19 -0700280 return bts;
281}
282
283void
284tcp_bt_check_app_limited (tcp_connection_t * tc)
285{
286 u32 available_bytes, flight_size;
287
288 available_bytes = transport_max_tx_dequeue (&tc->connection);
289 flight_size = tcp_flight_size (tc);
290
291 /* Not enough bytes to fill the cwnd */
292 if (available_bytes + flight_size + tc->snd_mss < tc->cwnd
293 /* Bytes considered lost have been retransmitted */
294 && tc->sack_sb.lost_bytes <= tc->snd_rxt_bytes)
295 tc->app_limited = tc->delivered + flight_size ? : 1;
296}
297
298void
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700299tcp_bt_track_tx (tcp_connection_t * tc, u32 len)
Florin Coras52814732019-06-12 15:38:19 -0700300{
301 tcp_byte_tracker_t *bt = tc->bt;
302 tcp_bt_sample_t *bts, *tail;
303 u32 bts_index;
304
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700305 tail = bt_get_sample (bt, bt->tail);
306 if (tail && tail->max_seq == tc->snd_nxt
307 && tail->tx_time == tcp_time_now_us (tc->c_thread_index))
308 {
309 tail->max_seq += len;
310 return;
311 }
312
Florin Coras85fc1302019-06-26 09:12:34 -0700313 if (tc->snd_una == tc->snd_nxt)
Florin Coras7436b432019-09-10 23:26:27 -0700314 {
315 tc->delivered_time = tcp_time_now_us (tc->c_thread_index);
316 tc->first_tx_time = tc->delivered_time;
317 }
Florin Coras52814732019-06-12 15:38:19 -0700318
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700319 bts = tcp_bt_alloc_tx_sample (tc, tc->snd_nxt, tc->snd_nxt + len);
Florin Coras52814732019-06-12 15:38:19 -0700320 bts_index = bt_sample_index (bt, bts);
321 tail = bt_get_sample (bt, bt->tail);
322 if (tail)
323 {
324 tail->next = bts_index;
325 bts->prev = bt->tail;
326 bt->tail = bts_index;
327 }
328 else
329 {
330 bt->tail = bt->head = bts_index;
331 }
332}
333
334void
335tcp_bt_track_rxt (tcp_connection_t * tc, u32 start, u32 end)
336{
337 tcp_byte_tracker_t *bt = tc->bt;
338 tcp_bt_sample_t *bts, *next, *cur, *prev, *nbts;
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700339 u32 bts_index, cur_index, next_index, prev_index, max_seq;
Florin Coras52814732019-06-12 15:38:19 -0700340 u8 is_end = end == tc->snd_nxt;
341
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700342 /* Contiguous blocks retransmitted at the same time */
Florin Coras52814732019-06-12 15:38:19 -0700343 bts = bt_get_sample (bt, bt->last_ooo);
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700344 if (bts && bts->max_seq == start
345 && bts->tx_time == tcp_time_now_us (tc->c_thread_index))
Florin Coras52814732019-06-12 15:38:19 -0700346 {
347 bts->max_seq = end;
348 next = bt_next_sample (bt, bts);
349 if (next)
350 bt_fix_overlapped (bt, next, end, is_end);
351
352 return;
353 }
354
355 /* Find original tx sample */
356 bts = bt_lookup_seq (bt, start);
357
358 ASSERT (bts != 0 && seq_geq (start, bts->min_seq));
359
360 /* Head in the past */
361 if (seq_lt (bts->min_seq, tc->snd_una))
362 bt_update_sample (bt, bts, tc->snd_una);
363
364 /* Head overlap */
365 if (bts->min_seq == start)
366 {
367 prev_index = bts->prev;
368 next = bt_fix_overlapped (bt, bts, end, is_end);
369 next_index = bt_sample_index (bt, next);
370
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700371 cur = tcp_bt_alloc_tx_sample (tc, start, end);
Florin Coras52814732019-06-12 15:38:19 -0700372 cur->flags |= TCP_BTS_IS_RXT;
Florin Coras46ec6e02019-10-22 13:34:30 -0700373 if (bts->flags & TCP_BTS_IS_RXT)
374 cur->flags |= TCP_BTS_IS_RXT_LOST;
Florin Coras52814732019-06-12 15:38:19 -0700375 cur->next = next_index;
376 cur->prev = prev_index;
377
378 cur_index = bt_sample_index (bt, cur);
379
380 if (next_index != TCP_BTS_INVALID_INDEX)
381 {
382 next = bt_get_sample (bt, next_index);
383 next->prev = cur_index;
384 }
385 else
386 {
387 bt->tail = cur_index;
388 }
389
390 if (prev_index != TCP_BTS_INVALID_INDEX)
391 {
392 prev = bt_get_sample (bt, prev_index);
393 prev->next = cur_index;
394 }
395 else
396 {
397 bt->head = cur_index;
398 }
399
400 bt->last_ooo = cur_index;
401 return;
402 }
403
404 bts_index = bt_sample_index (bt, bts);
405 next = bt_next_sample (bt, bts);
406 if (next)
Florin Coras62a7fe22020-02-20 16:04:03 +0000407 bt_fix_overlapped (bt, next, end, is_end);
Florin Coras52814732019-06-12 15:38:19 -0700408
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700409 max_seq = bts->max_seq;
410 ASSERT (seq_lt (start, max_seq));
Florin Coras52814732019-06-12 15:38:19 -0700411
412 /* Have to split or tail overlap */
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700413 cur = tcp_bt_alloc_tx_sample (tc, start, end);
Florin Coras52814732019-06-12 15:38:19 -0700414 cur->flags |= TCP_BTS_IS_RXT;
Florin Coras46ec6e02019-10-22 13:34:30 -0700415 if (bts->flags & TCP_BTS_IS_RXT)
416 cur->flags |= TCP_BTS_IS_RXT_LOST;
Florin Coras52814732019-06-12 15:38:19 -0700417 cur->prev = bts_index;
418 cur_index = bt_sample_index (bt, cur);
419
420 /* Split. Allocate another sample */
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700421 if (seq_lt (end, max_seq))
Florin Coras52814732019-06-12 15:38:19 -0700422 {
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700423 nbts = tcp_bt_alloc_tx_sample (tc, end, bts->max_seq);
Florin Coras52814732019-06-12 15:38:19 -0700424 cur = bt_get_sample (bt, cur_index);
425 bts = bt_get_sample (bt, bts_index);
426
427 *nbts = *bts;
428 nbts->min_seq = end;
429
430 if (nbts->next != TCP_BTS_INVALID_INDEX)
431 {
432 next = bt_get_sample (bt, nbts->next);
433 next->prev = bt_sample_index (bt, nbts);
434 }
435 else
436 bt->tail = bt_sample_index (bt, nbts);
437
438 bts->next = nbts->prev = cur_index;
439 cur->next = bt_sample_index (bt, nbts);
440
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700441 bts->max_seq = start;
Florin Coras52814732019-06-12 15:38:19 -0700442 bt->last_ooo = cur_index;
443 }
444 /* Tail completely overlapped */
445 else
446 {
447 bts = bt_get_sample (bt, bts_index);
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700448 bts->max_seq = start;
Florin Coras52814732019-06-12 15:38:19 -0700449
450 if (bts->next != TCP_BTS_INVALID_INDEX)
451 {
452 next = bt_get_sample (bt, bts->next);
453 next->prev = cur_index;
454 }
455 else
456 bt->tail = cur_index;
457
458 cur->next = bts->next;
459 bts->next = cur_index;
460
461 bt->last_ooo = cur_index;
462 }
463}
464
465static void
466tcp_bt_sample_to_rate_sample (tcp_connection_t * tc, tcp_bt_sample_t * bts,
467 tcp_rate_sample_t * rs)
468{
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700469 if (bts->flags & TCP_BTS_IS_SACKED)
470 return;
471
Florin Coras85fc1302019-06-26 09:12:34 -0700472 if (rs->prior_delivered && rs->prior_delivered >= bts->delivered)
Florin Coras52814732019-06-12 15:38:19 -0700473 return;
474
Florin Coras85fc1302019-06-26 09:12:34 -0700475 rs->prior_delivered = bts->delivered;
476 rs->prior_time = bts->delivered_time;
Florin Coras7436b432019-09-10 23:26:27 -0700477 rs->interval_time = bts->tx_time - bts->first_tx_time;
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700478 rs->rtt_time = tc->delivered_time - bts->tx_time;
Florin Coras52814732019-06-12 15:38:19 -0700479 rs->flags = bts->flags;
Florin Corasdb88ffb2020-03-11 18:30:48 +0000480 rs->tx_in_flight = bts->tx_in_flight;
481 rs->tx_lost = bts->tx_lost;
Florin Coras7436b432019-09-10 23:26:27 -0700482 tc->first_tx_time = bts->tx_time;
Florin Coras52814732019-06-12 15:38:19 -0700483}
484
485static void
486tcp_bt_walk_samples (tcp_connection_t * tc, tcp_rate_sample_t * rs)
487{
488 tcp_byte_tracker_t *bt = tc->bt;
489 tcp_bt_sample_t *next, *cur;
490
491 cur = bt_get_sample (bt, bt->head);
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700492 while (cur && seq_leq (cur->max_seq, tc->snd_una))
Florin Coras52814732019-06-12 15:38:19 -0700493 {
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700494 next = bt_next_sample (bt, cur);
495 tcp_bt_sample_to_rate_sample (tc, cur, rs);
Florin Coras52814732019-06-12 15:38:19 -0700496 bt_free_sample (bt, cur);
497 cur = next;
498 }
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700499
500 if (cur && seq_lt (cur->min_seq, tc->snd_una))
501 tcp_bt_sample_to_rate_sample (tc, cur, rs);
Florin Coras52814732019-06-12 15:38:19 -0700502}
503
504static void
505tcp_bt_walk_samples_ooo (tcp_connection_t * tc, tcp_rate_sample_t * rs)
506{
507 sack_block_t *blks = tc->rcv_opts.sacks, *blk;
508 tcp_byte_tracker_t *bt = tc->bt;
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700509 tcp_bt_sample_t *cur, *prev, *next;
Florin Coras52814732019-06-12 15:38:19 -0700510 int i;
511
512 for (i = 0; i < vec_len (blks); i++)
513 {
514 blk = &blks[i];
515
516 /* Ignore blocks that are already covered by snd_una */
517 if (seq_lt (blk->end, tc->snd_una))
518 continue;
519
520 cur = bt_lookup_seq (bt, blk->start);
521 if (!cur)
522 continue;
523
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700524 ASSERT (seq_geq (blk->start, cur->min_seq)
525 && seq_lt (blk->start, cur->max_seq));
Florin Coras52814732019-06-12 15:38:19 -0700526
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700527 /* Current should be split. Second part will be consumed */
528 if (PREDICT_FALSE (cur->min_seq != blk->start))
Florin Coras52814732019-06-12 15:38:19 -0700529 {
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700530 cur = bt_split_sample (bt, cur, blk->start);
531 prev = bt_prev_sample (bt, cur);
Florin Coras52814732019-06-12 15:38:19 -0700532 }
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700533 else
534 prev = bt_prev_sample (bt, cur);
Florin Coras52814732019-06-12 15:38:19 -0700535
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700536 while (cur && seq_leq (cur->max_seq, blk->end))
Florin Coras52814732019-06-12 15:38:19 -0700537 {
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700538 if (!(cur->flags & TCP_BTS_IS_SACKED))
539 {
540 tcp_bt_sample_to_rate_sample (tc, cur, rs);
541 cur->flags |= TCP_BTS_IS_SACKED;
542 if (prev && (prev->flags & TCP_BTS_IS_SACKED))
543 {
544 cur = bt_merge_sample (bt, prev, cur);
545 next = bt_next_sample (bt, cur);
546 }
547 else
548 {
549 next = bt_next_sample (bt, cur);
550 if (next && (next->flags & TCP_BTS_IS_SACKED))
551 {
552 cur = bt_merge_sample (bt, cur, next);
553 next = bt_next_sample (bt, cur);
554 }
555 }
556 }
557 else
558 next = bt_next_sample (bt, cur);
559
560 prev = cur;
Florin Coras52814732019-06-12 15:38:19 -0700561 cur = next;
562 }
563
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700564 if (cur && seq_lt (cur->min_seq, blk->end))
565 {
566 tcp_bt_sample_to_rate_sample (tc, cur, rs);
567 prev = bt_prev_sample (bt, cur);
568 /* Extend previous to include the newly sacked bytes */
569 if (prev && (prev->flags & TCP_BTS_IS_SACKED))
570 {
571 prev->max_seq = blk->end;
572 bt_update_sample (bt, cur, blk->end);
573 }
574 /* Split sample into two. First part is consumed */
575 else
576 {
577 next = bt_split_sample (bt, cur, blk->end);
578 cur = bt_prev_sample (bt, next);
579 cur->flags |= TCP_BTS_IS_SACKED;
580 }
581 }
Florin Coras52814732019-06-12 15:38:19 -0700582 }
583}
584
585void
586tcp_bt_sample_delivery_rate (tcp_connection_t * tc, tcp_rate_sample_t * rs)
587{
588 u32 delivered;
589
590 if (PREDICT_FALSE (tc->flags & TCP_CONN_FINSNT))
591 return;
592
Florin Corasdb88ffb2020-03-11 18:30:48 +0000593 tc->lost += tc->sack_sb.last_lost_bytes;
594
Florin Coras52814732019-06-12 15:38:19 -0700595 delivered = tc->bytes_acked + tc->sack_sb.last_sacked_bytes;
596 if (!delivered || tc->bt->head == TCP_BTS_INVALID_INDEX)
597 return;
598
599 /* Do not count bytes that were previously sacked again */
600 tc->delivered += delivered - tc->sack_sb.last_bytes_delivered;
601 tc->delivered_time = tcp_time_now_us (tc->c_thread_index);
602
603 if (tc->app_limited && tc->delivered > tc->app_limited)
604 tc->app_limited = 0;
605
606 if (tc->bytes_acked)
607 tcp_bt_walk_samples (tc, rs);
608
609 if (tc->sack_sb.last_sacked_bytes)
610 tcp_bt_walk_samples_ooo (tc, rs);
Florin Coras85fc1302019-06-26 09:12:34 -0700611
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700612 rs->interval_time = clib_max ((tc->delivered_time - rs->prior_time),
Florin Coras7436b432019-09-10 23:26:27 -0700613 rs->interval_time);
Florin Coras85fc1302019-06-26 09:12:34 -0700614 rs->delivered = tc->delivered - rs->prior_delivered;
Florin Coras85fc1302019-06-26 09:12:34 -0700615 rs->acked_and_sacked = delivered;
Florin Corasdb88ffb2020-03-11 18:30:48 +0000616 rs->last_lost = tc->sack_sb.last_lost_bytes;
617 rs->lost = tc->lost - rs->tx_lost;
Florin Coras52814732019-06-12 15:38:19 -0700618}
619
620void
621tcp_bt_flush_samples (tcp_connection_t * tc)
622{
623 tcp_byte_tracker_t *bt = tc->bt;
624 tcp_bt_sample_t *bts;
625 u32 *samples = 0, *si;
626
627 vec_validate (samples, pool_elts (bt->samples) - 1);
Florin Coras92f190a2019-08-23 10:28:01 -0700628 vec_reset_length (samples);
Florin Coras52814732019-06-12 15:38:19 -0700629
630 /* *INDENT-OFF* */
631 pool_foreach (bts, bt->samples, ({
632 vec_add1 (samples, bts - bt->samples);
633 }));
634 /* *INDENT-ON* */
635
636 vec_foreach (si, samples)
637 {
638 bts = bt_get_sample (bt, *si);
639 bt_free_sample (bt, bts);
640 }
641
642 vec_free (samples);
643}
644
645void
646tcp_bt_cleanup (tcp_connection_t * tc)
647{
648 tcp_byte_tracker_t *bt = tc->bt;
649
650 rb_tree_free_nodes (&bt->sample_lookup);
651 pool_free (bt->samples);
652 clib_mem_free (bt);
653 tc->bt = 0;
654}
655
656void
657tcp_bt_init (tcp_connection_t * tc)
658{
659 tcp_byte_tracker_t *bt;
660
661 bt = clib_mem_alloc (sizeof (tcp_byte_tracker_t));
662 clib_memset (bt, 0, sizeof (tcp_byte_tracker_t));
663
664 rb_tree_init (&bt->sample_lookup);
665 bt->head = bt->tail = TCP_BTS_INVALID_INDEX;
666 tc->bt = bt;
667}
668
Florin Corasd6ae4bf2019-10-12 18:10:20 -0700669u8 *
670format_tcp_bt_sample (u8 * s, va_list * args)
671{
672 tcp_connection_t *tc = va_arg (*args, tcp_connection_t *);
673 tcp_bt_sample_t *bts = va_arg (*args, tcp_bt_sample_t *);
674 f64 now = tcp_time_now_us (tc->c_thread_index);
675 s = format (s, "[%u, %u] d %u dt %.3f txt %.3f ftxt %.3f flags 0x%x",
676 bts->min_seq - tc->iss, bts->max_seq - tc->iss, bts->delivered,
677 now - bts->delivered_time, now - bts->tx_time,
678 now - bts->first_tx_time, bts->flags);
679 return s;
680}
681
682u8 *
683format_tcp_bt (u8 * s, va_list * args)
684{
685 tcp_connection_t *tc = va_arg (*args, tcp_connection_t *);
686 tcp_byte_tracker_t *bt = tc->bt;
687 tcp_bt_sample_t *bts;
688
689 bts = bt_get_sample (bt, bt->head);
690 while (bts)
691 {
692 s = format (s, "%U\n", format_tcp_bt_sample, tc, bts);
693 bts = bt_next_sample (bt, bts);
694 }
695
696 return s;
697}
698
Florin Coras52814732019-06-12 15:38:19 -0700699/*
700 * fd.io coding-style-patch-verification: ON
701 *
702 * Local Variables:
703 * eval: (c-set-style "gnu")
704 * End:
705 */