tcp: delivery rate estimator
[vpp.git] / src / vnet / tcp / tcp_bt.c
1 /*
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
21 static tcp_bt_sample_t *
22 bt_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
29 static tcp_bt_sample_t *
30 bt_next_sample (tcp_byte_tracker_t * bt, tcp_bt_sample_t * bts)
31 {
32   return bt_get_sample (bt, bts->next);
33 }
34
35 static tcp_bt_sample_t *
36 bt_prev_sample (tcp_byte_tracker_t * bt, tcp_bt_sample_t * bts)
37 {
38   return bt_get_sample (bt, bts->prev);
39 }
40
41 static u32
42 bt_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
49 static inline int
50 bt_seq_lt (u32 a, u32 b)
51 {
52   return seq_lt (a, b);
53 }
54
55 static tcp_bt_sample_t *
56 bt_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
68 static void
69 bt_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
93 static tcp_bt_sample_t *
94 bt_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
141 static void
142 bt_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
150 static tcp_bt_sample_t *
151 bt_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
181 int
182 tcp_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
237 static tcp_bt_sample_t *
238 tcp_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
249 void
250 tcp_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
264 void
265 tcp_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
289 void
290 tcp_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
414 static void
415 tcp_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
428 static void
429 tcp_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
462 static void
463 tcp_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
506 void
507 tcp_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
532 void
533 tcp_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
556 void
557 tcp_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
567 void
568 tcp_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  */