tcp: add lost and in flight to byte tracker
[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, u32 max_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   bts->max_seq = max_seq;
64   rb_tree_add_custom (&bt->sample_lookup, bts->min_seq, bts - bt->samples,
65                       bt_seq_lt);
66   return bts;
67 }
68
69 static void
70 bt_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
94 static tcp_bt_sample_t *
95 bt_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
123 static tcp_bt_sample_t *
124 bt_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
135 static tcp_bt_sample_t *
136 bt_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
183 static void
184 bt_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
192 static tcp_bt_sample_t *
193 bt_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;
199   while (cur && seq_leq (cur->max_seq, seq))
200     {
201       next = bt_next_sample (bt, cur);
202       bt_free_sample (bt, cur);
203       cur = next;
204     }
205
206   if (cur && seq_lt (cur->min_seq, seq))
207     bt_update_sample (bt, cur, seq);
208
209   return cur;
210 }
211
212 int
213 tcp_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
268 static tcp_bt_sample_t *
269 tcp_bt_alloc_tx_sample (tcp_connection_t * tc, u32 min_seq, u32 max_seq)
270 {
271   tcp_bt_sample_t *bts;
272   bts = bt_alloc_sample (tc->bt, min_seq, max_seq);
273   bts->delivered = tc->delivered;
274   bts->delivered_time = tc->delivered_time;
275   bts->tx_time = tcp_time_now_us (tc->c_thread_index);
276   bts->first_tx_time = tc->first_tx_time;
277   bts->flags |= tc->app_limited ? TCP_BTS_IS_APP_LIMITED : 0;
278   bts->tx_in_flight = tcp_flight_size (tc);
279   bts->tx_lost = tc->lost;
280   return bts;
281 }
282
283 void
284 tcp_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
298 void
299 tcp_bt_track_tx (tcp_connection_t * tc, u32 len)
300 {
301   tcp_byte_tracker_t *bt = tc->bt;
302   tcp_bt_sample_t *bts, *tail;
303   u32 bts_index;
304
305   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
313   if (tc->snd_una == tc->snd_nxt)
314     {
315       tc->delivered_time = tcp_time_now_us (tc->c_thread_index);
316       tc->first_tx_time = tc->delivered_time;
317     }
318
319   bts = tcp_bt_alloc_tx_sample (tc, tc->snd_nxt, tc->snd_nxt + len);
320   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
334 void
335 tcp_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;
339   u32 bts_index, cur_index, next_index, prev_index, max_seq;
340   u8 is_end = end == tc->snd_nxt;
341
342   /* Contiguous blocks retransmitted at the same time */
343   bts = bt_get_sample (bt, bt->last_ooo);
344   if (bts && bts->max_seq == start
345       && bts->tx_time == tcp_time_now_us (tc->c_thread_index))
346     {
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
371       cur = tcp_bt_alloc_tx_sample (tc, start, end);
372       cur->flags |= TCP_BTS_IS_RXT;
373       if (bts->flags & TCP_BTS_IS_RXT)
374         cur->flags |= TCP_BTS_IS_RXT_LOST;
375       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)
407     bt_fix_overlapped (bt, next, end, is_end);
408
409   max_seq = bts->max_seq;
410   ASSERT (seq_lt (start, max_seq));
411
412   /* Have to split or tail overlap */
413   cur = tcp_bt_alloc_tx_sample (tc, start, end);
414   cur->flags |= TCP_BTS_IS_RXT;
415   if (bts->flags & TCP_BTS_IS_RXT)
416     cur->flags |= TCP_BTS_IS_RXT_LOST;
417   cur->prev = bts_index;
418   cur_index = bt_sample_index (bt, cur);
419
420   /* Split. Allocate another sample */
421   if (seq_lt (end, max_seq))
422     {
423       nbts = tcp_bt_alloc_tx_sample (tc, end, bts->max_seq);
424       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
441       bts->max_seq = start;
442       bt->last_ooo = cur_index;
443     }
444   /* Tail completely overlapped */
445   else
446     {
447       bts = bt_get_sample (bt, bts_index);
448       bts->max_seq = start;
449
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
465 static void
466 tcp_bt_sample_to_rate_sample (tcp_connection_t * tc, tcp_bt_sample_t * bts,
467                               tcp_rate_sample_t * rs)
468 {
469   if (bts->flags & TCP_BTS_IS_SACKED)
470     return;
471
472   if (rs->prior_delivered && rs->prior_delivered >= bts->delivered)
473     return;
474
475   rs->prior_delivered = bts->delivered;
476   rs->prior_time = bts->delivered_time;
477   rs->interval_time = bts->tx_time - bts->first_tx_time;
478   rs->rtt_time = tc->delivered_time - bts->tx_time;
479   rs->flags = bts->flags;
480   rs->tx_in_flight = bts->tx_in_flight;
481   rs->tx_lost = bts->tx_lost;
482   tc->first_tx_time = bts->tx_time;
483 }
484
485 static void
486 tcp_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);
492   while (cur && seq_leq (cur->max_seq, tc->snd_una))
493     {
494       next = bt_next_sample (bt, cur);
495       tcp_bt_sample_to_rate_sample (tc, cur, rs);
496       bt_free_sample (bt, cur);
497       cur = next;
498     }
499
500   if (cur && seq_lt (cur->min_seq, tc->snd_una))
501     tcp_bt_sample_to_rate_sample (tc, cur, rs);
502 }
503
504 static void
505 tcp_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;
509   tcp_bt_sample_t *cur, *prev, *next;
510   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
524       ASSERT (seq_geq (blk->start, cur->min_seq)
525               && seq_lt (blk->start, cur->max_seq));
526
527       /* Current should be split. Second part will be consumed */
528       if (PREDICT_FALSE (cur->min_seq != blk->start))
529         {
530           cur = bt_split_sample (bt, cur, blk->start);
531           prev = bt_prev_sample (bt, cur);
532         }
533       else
534         prev = bt_prev_sample (bt, cur);
535
536       while (cur && seq_leq (cur->max_seq, blk->end))
537         {
538           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;
561           cur = next;
562         }
563
564       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         }
582     }
583 }
584
585 void
586 tcp_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
593   tc->lost += tc->sack_sb.last_lost_bytes;
594
595   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);
611
612   rs->interval_time = clib_max ((tc->delivered_time - rs->prior_time),
613                                 rs->interval_time);
614   rs->delivered = tc->delivered - rs->prior_delivered;
615   rs->acked_and_sacked = delivered;
616   rs->last_lost = tc->sack_sb.last_lost_bytes;
617   rs->lost = tc->lost - rs->tx_lost;
618 }
619
620 void
621 tcp_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);
628   vec_reset_length (samples);
629
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
645 void
646 tcp_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
656 void
657 tcp_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
669 u8 *
670 format_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
682 u8 *
683 format_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
699 /*
700  * fd.io coding-style-patch-verification: ON
701  *
702  * Local Variables:
703  * eval: (c-set-style "gnu")
704  * End:
705  */