6f9ee0168f75b9ff48940a242765a9582bd20336
[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_bt.h>
20 #include <vnet/tcp/tcp.h>
21 #include <vnet/tcp/tcp_inlines.h>
22
23 static tcp_bt_sample_t *
24 bt_get_sample (tcp_byte_tracker_t * bt, u32 bts_index)
25 {
26   if (pool_is_free_index (bt->samples, bts_index))
27     return 0;
28   return pool_elt_at_index (bt->samples, bts_index);
29 }
30
31 static tcp_bt_sample_t *
32 bt_next_sample (tcp_byte_tracker_t * bt, tcp_bt_sample_t * bts)
33 {
34   return bt_get_sample (bt, bts->next);
35 }
36
37 static tcp_bt_sample_t *
38 bt_prev_sample (tcp_byte_tracker_t * bt, tcp_bt_sample_t * bts)
39 {
40   return bt_get_sample (bt, bts->prev);
41 }
42
43 static u32
44 bt_sample_index (tcp_byte_tracker_t * bt, tcp_bt_sample_t * bts)
45 {
46   if (!bts)
47     return TCP_BTS_INVALID_INDEX;
48   return bts - bt->samples;
49 }
50
51 static inline int
52 bt_seq_lt (u32 a, u32 b)
53 {
54   return seq_lt (a, b);
55 }
56
57 static tcp_bt_sample_t *
58 bt_alloc_sample (tcp_byte_tracker_t * bt, u32 min_seq, u32 max_seq)
59 {
60   tcp_bt_sample_t *bts;
61
62   pool_get_zero (bt->samples, bts);
63   bts->next = bts->prev = TCP_BTS_INVALID_INDEX;
64   bts->min_seq = min_seq;
65   bts->max_seq = max_seq;
66   rb_tree_add_custom (&bt->sample_lookup, bts->min_seq, bts - bt->samples,
67                       bt_seq_lt);
68   return bts;
69 }
70
71 static void
72 bt_free_sample (tcp_byte_tracker_t * bt, tcp_bt_sample_t * bts)
73 {
74   if (bts->prev != TCP_BTS_INVALID_INDEX)
75     {
76       tcp_bt_sample_t *prev = bt_prev_sample (bt, bts);
77       prev->next = bts->next;
78     }
79   else
80     bt->head = bts->next;
81
82   if (bts->next != TCP_BTS_INVALID_INDEX)
83     {
84       tcp_bt_sample_t *next = bt_next_sample (bt, bts);
85       next->prev = bts->prev;
86     }
87   else
88     bt->tail = bts->prev;
89
90   rb_tree_del_custom (&bt->sample_lookup, bts->min_seq, bt_seq_lt);
91   if (CLIB_DEBUG)
92     memset (bts, 0xfc, sizeof (*bts));
93   pool_put (bt->samples, bts);
94 }
95
96 static tcp_bt_sample_t *
97 bt_split_sample (tcp_byte_tracker_t * bt, tcp_bt_sample_t * bts, u32 seq)
98 {
99   tcp_bt_sample_t *ns, *next;
100   u32 bts_index;
101
102   bts_index = bt_sample_index (bt, bts);
103
104   ASSERT (seq_leq (bts->min_seq, seq) && seq_lt (seq, bts->max_seq));
105
106   ns = bt_alloc_sample (bt, seq, bts->max_seq);
107   bts = bt_get_sample (bt, bts_index);
108
109   *ns = *bts;
110   ns->min_seq = seq;
111   bts->max_seq = seq;
112
113   next = bt_next_sample (bt, bts);
114   if (next)
115     next->prev = bt_sample_index (bt, ns);
116   else
117     bt->tail = bt_sample_index (bt, ns);
118
119   bts->next = bt_sample_index (bt, ns);
120   ns->prev = bt_sample_index (bt, bts);
121
122   return ns;
123 }
124
125 static tcp_bt_sample_t *
126 bt_merge_sample (tcp_byte_tracker_t * bt, tcp_bt_sample_t * prev,
127                  tcp_bt_sample_t * cur)
128 {
129   ASSERT (prev->max_seq == cur->min_seq);
130   prev->max_seq = cur->max_seq;
131   if (bt_sample_index (bt, cur) == bt->tail)
132     bt->tail = bt_sample_index (bt, prev);
133   bt_free_sample (bt, cur);
134   return prev;
135 }
136
137 static tcp_bt_sample_t *
138 bt_lookup_seq (tcp_byte_tracker_t * bt, u32 seq)
139 {
140   rb_tree_t *rt = &bt->sample_lookup;
141   rb_node_t *cur, *prev;
142   tcp_bt_sample_t *bts;
143
144   cur = rb_node (rt, rt->root);
145   if (rb_node_is_tnil (rt, cur))
146     return 0;
147
148   while (seq != cur->key)
149     {
150       prev = cur;
151       if (seq_lt (seq, cur->key))
152         cur = rb_node_left (rt, cur);
153       else
154         cur = rb_node_right (rt, cur);
155
156       if (rb_node_is_tnil (rt, cur))
157         {
158           /* Hit tnil as a left child. Find predecessor */
159           if (seq_lt (seq, prev->key))
160             {
161               cur = rb_tree_predecessor (rt, prev);
162               if (rb_node_is_tnil (rt, cur))
163                 return 0;
164               bts = bt_get_sample (bt, cur->opaque);
165             }
166           /* Hit tnil as a right child */
167           else
168             {
169               bts = bt_get_sample (bt, prev->opaque);
170             }
171
172           if (seq_geq (seq, bts->min_seq))
173             return bts;
174
175           return 0;
176         }
177     }
178
179   if (!rb_node_is_tnil (rt, cur))
180     return bt_get_sample (bt, cur->opaque);
181
182   return 0;
183 }
184
185 static void
186 bt_update_sample (tcp_byte_tracker_t * bt, tcp_bt_sample_t * bts, u32 seq)
187 {
188   rb_tree_del_custom (&bt->sample_lookup, bts->min_seq, bt_seq_lt);
189   bts->min_seq = seq;
190   rb_tree_add_custom (&bt->sample_lookup, bts->min_seq,
191                       bt_sample_index (bt, bts), bt_seq_lt);
192 }
193
194 static tcp_bt_sample_t *
195 bt_fix_overlapped (tcp_byte_tracker_t * bt, tcp_bt_sample_t * start,
196                    u32 seq, u8 is_end)
197 {
198   tcp_bt_sample_t *cur, *next;
199
200   cur = start;
201   while (cur && seq_leq (cur->max_seq, seq))
202     {
203       next = bt_next_sample (bt, cur);
204       bt_free_sample (bt, cur);
205       cur = next;
206     }
207
208   if (cur && seq_lt (cur->min_seq, seq))
209     bt_update_sample (bt, cur, seq);
210
211   return cur;
212 }
213
214 int
215 tcp_bt_is_sane (tcp_byte_tracker_t * bt)
216 {
217   tcp_bt_sample_t *bts, *tmp;
218
219   if (pool_elts (bt->samples) != pool_elts (bt->sample_lookup.nodes) - 1)
220     return 0;
221
222   if (bt->head == TCP_BTS_INVALID_INDEX)
223     {
224       if (bt->tail != TCP_BTS_INVALID_INDEX)
225         return 0;
226       if (pool_elts (bt->samples) != 0)
227         return 0;
228       return 1;
229     }
230
231   bts = bt_get_sample (bt, bt->tail);
232   if (!bts)
233     return 0;
234
235   bts = bt_get_sample (bt, bt->head);
236   if (!bts || bts->prev != TCP_BTS_INVALID_INDEX)
237     return 0;
238
239   while (bts)
240     {
241       tmp = bt_lookup_seq (bt, bts->min_seq);
242       if (!tmp)
243         return 0;
244       if (tmp != bts)
245         return 0;
246       tmp = bt_next_sample (bt, bts);
247       if (tmp)
248         {
249           if (tmp->prev != bt_sample_index (bt, bts))
250             {
251               clib_warning ("next %u thinks prev is %u should be %u",
252                             bts->next, tmp->prev, bt_sample_index (bt, bts));
253               return 0;
254             }
255           if (!seq_lt (bts->min_seq, tmp->min_seq))
256             return 0;
257         }
258       else
259         {
260           if (bt->tail != bt_sample_index (bt, bts))
261             return 0;
262           if (bts->next != TCP_BTS_INVALID_INDEX)
263             return 0;
264         }
265       bts = tmp;
266     }
267   return 1;
268 }
269
270 static tcp_bt_sample_t *
271 tcp_bt_alloc_tx_sample (tcp_connection_t * tc, u32 min_seq, u32 max_seq)
272 {
273   tcp_bt_sample_t *bts;
274   bts = bt_alloc_sample (tc->bt, min_seq, max_seq);
275   bts->delivered = tc->delivered;
276   bts->delivered_time = tc->delivered_time;
277   bts->tx_time = tcp_time_now_us (tc->c_thread_index);
278   bts->first_tx_time = tc->first_tx_time;
279   bts->flags |= tc->app_limited ? TCP_BTS_IS_APP_LIMITED : 0;
280   bts->tx_in_flight = tcp_flight_size (tc);
281   bts->tx_lost = tc->lost;
282   return bts;
283 }
284
285 void
286 tcp_bt_check_app_limited (tcp_connection_t * tc)
287 {
288   u32 available_bytes, flight_size;
289
290   available_bytes = transport_max_tx_dequeue (&tc->connection);
291   flight_size = tcp_flight_size (tc);
292
293   /* Not enough bytes to fill the cwnd */
294   if (available_bytes + flight_size + tc->snd_mss < tc->cwnd
295       /* Bytes considered lost have been retransmitted */
296       && tc->sack_sb.lost_bytes <= tc->snd_rxt_bytes)
297     tc->app_limited = tc->delivered + flight_size ? : 1;
298 }
299
300 void
301 tcp_bt_track_tx (tcp_connection_t * tc, u32 len)
302 {
303   tcp_byte_tracker_t *bt = tc->bt;
304   tcp_bt_sample_t *bts, *tail;
305   u32 bts_index;
306
307   tail = bt_get_sample (bt, bt->tail);
308   if (tail && tail->max_seq == tc->snd_nxt
309       && tail->tx_time == tcp_time_now_us (tc->c_thread_index))
310     {
311       tail->max_seq += len;
312       return;
313     }
314
315   if (tc->snd_una == tc->snd_nxt)
316     {
317       tc->delivered_time = tcp_time_now_us (tc->c_thread_index);
318       tc->first_tx_time = tc->delivered_time;
319     }
320
321   bts = tcp_bt_alloc_tx_sample (tc, tc->snd_nxt, tc->snd_nxt + len);
322   bts_index = bt_sample_index (bt, bts);
323   tail = bt_get_sample (bt, bt->tail);
324   if (tail)
325     {
326       tail->next = bts_index;
327       bts->prev = bt->tail;
328       bt->tail = bts_index;
329     }
330   else
331     {
332       bt->tail = bt->head = bts_index;
333     }
334 }
335
336 void
337 tcp_bt_track_rxt (tcp_connection_t * tc, u32 start, u32 end)
338 {
339   tcp_byte_tracker_t *bt = tc->bt;
340   tcp_bt_sample_t *bts, *next, *cur, *prev, *nbts;
341   u32 bts_index, cur_index, next_index, prev_index, max_seq;
342   u8 is_end = end == tc->snd_nxt;
343
344   /* Contiguous blocks retransmitted at the same time */
345   bts = bt_get_sample (bt, bt->last_ooo);
346   if (bts && bts->max_seq == start
347       && bts->tx_time == tcp_time_now_us (tc->c_thread_index))
348     {
349       bts->max_seq = end;
350       next = bt_next_sample (bt, bts);
351       if (next)
352         bt_fix_overlapped (bt, next, end, is_end);
353
354       return;
355     }
356
357   /* Find original tx sample */
358   bts = bt_lookup_seq (bt, start);
359
360   ASSERT (bts != 0 && seq_geq (start, bts->min_seq));
361
362   /* Head in the past */
363   if (seq_lt (bts->min_seq, tc->snd_una))
364     bt_update_sample (bt, bts, tc->snd_una);
365
366   /* Head overlap */
367   if (bts->min_seq == start)
368     {
369       prev_index = bts->prev;
370       next = bt_fix_overlapped (bt, bts, end, is_end);
371       next_index = bt_sample_index (bt, next);
372
373       cur = tcp_bt_alloc_tx_sample (tc, start, end);
374       cur->flags |= TCP_BTS_IS_RXT;
375       if (bts->flags & TCP_BTS_IS_RXT)
376         cur->flags |= TCP_BTS_IS_RXT_LOST;
377       cur->next = next_index;
378       cur->prev = prev_index;
379
380       cur_index = bt_sample_index (bt, cur);
381
382       if (next_index != TCP_BTS_INVALID_INDEX)
383         {
384           next = bt_get_sample (bt, next_index);
385           next->prev = cur_index;
386         }
387       else
388         {
389           bt->tail = cur_index;
390         }
391
392       if (prev_index != TCP_BTS_INVALID_INDEX)
393         {
394           prev = bt_get_sample (bt, prev_index);
395           prev->next = cur_index;
396         }
397       else
398         {
399           bt->head = cur_index;
400         }
401
402       bt->last_ooo = cur_index;
403       return;
404     }
405
406   bts_index = bt_sample_index (bt, bts);
407   next = bt_next_sample (bt, bts);
408   if (next)
409     bt_fix_overlapped (bt, next, end, is_end);
410
411   max_seq = bts->max_seq;
412   ASSERT (seq_lt (start, max_seq));
413
414   /* Have to split or tail overlap */
415   cur = tcp_bt_alloc_tx_sample (tc, start, end);
416   cur->flags |= TCP_BTS_IS_RXT;
417   if (bts->flags & TCP_BTS_IS_RXT)
418     cur->flags |= TCP_BTS_IS_RXT_LOST;
419   cur->prev = bts_index;
420   cur_index = bt_sample_index (bt, cur);
421
422   /* Split. Allocate another sample */
423   if (seq_lt (end, max_seq))
424     {
425       nbts = tcp_bt_alloc_tx_sample (tc, end, bts->max_seq);
426       cur = bt_get_sample (bt, cur_index);
427       bts = bt_get_sample (bt, bts_index);
428
429       *nbts = *bts;
430       nbts->min_seq = end;
431
432       if (nbts->next != TCP_BTS_INVALID_INDEX)
433         {
434           next = bt_get_sample (bt, nbts->next);
435           next->prev = bt_sample_index (bt, nbts);
436         }
437       else
438         bt->tail = bt_sample_index (bt, nbts);
439
440       bts->next = nbts->prev = cur_index;
441       cur->next = bt_sample_index (bt, nbts);
442
443       bts->max_seq = start;
444       bt->last_ooo = cur_index;
445     }
446   /* Tail completely overlapped */
447   else
448     {
449       bts = bt_get_sample (bt, bts_index);
450       bts->max_seq = start;
451
452       if (bts->next != TCP_BTS_INVALID_INDEX)
453         {
454           next = bt_get_sample (bt, bts->next);
455           next->prev = cur_index;
456         }
457       else
458         bt->tail = cur_index;
459
460       cur->next = bts->next;
461       bts->next = cur_index;
462
463       bt->last_ooo = cur_index;
464     }
465 }
466
467 static void
468 tcp_bt_sample_to_rate_sample (tcp_connection_t * tc, tcp_bt_sample_t * bts,
469                               tcp_rate_sample_t * rs)
470 {
471   if (bts->flags & TCP_BTS_IS_SACKED)
472     return;
473
474   if (rs->prior_delivered && rs->prior_delivered >= bts->delivered)
475     return;
476
477   rs->prior_delivered = bts->delivered;
478   rs->prior_time = bts->delivered_time;
479   rs->interval_time = bts->tx_time - bts->first_tx_time;
480   rs->rtt_time = tc->delivered_time - bts->tx_time;
481   rs->flags = bts->flags;
482   rs->tx_in_flight = bts->tx_in_flight;
483   rs->tx_lost = bts->tx_lost;
484   tc->first_tx_time = bts->tx_time;
485 }
486
487 static void
488 tcp_bt_walk_samples (tcp_connection_t * tc, tcp_rate_sample_t * rs)
489 {
490   tcp_byte_tracker_t *bt = tc->bt;
491   tcp_bt_sample_t *next, *cur;
492
493   cur = bt_get_sample (bt, bt->head);
494   while (cur && seq_leq (cur->max_seq, tc->snd_una))
495     {
496       next = bt_next_sample (bt, cur);
497       tcp_bt_sample_to_rate_sample (tc, cur, rs);
498       bt_free_sample (bt, cur);
499       cur = next;
500     }
501
502   if (cur && seq_lt (cur->min_seq, tc->snd_una))
503     tcp_bt_sample_to_rate_sample (tc, cur, rs);
504 }
505
506 static void
507 tcp_bt_walk_samples_ooo (tcp_connection_t * tc, tcp_rate_sample_t * rs)
508 {
509   sack_block_t *blks = tc->rcv_opts.sacks, *blk;
510   tcp_byte_tracker_t *bt = tc->bt;
511   tcp_bt_sample_t *cur, *prev, *next;
512   int i;
513
514   for (i = 0; i < vec_len (blks); i++)
515     {
516       blk = &blks[i];
517
518       /* Ignore blocks that are already covered by snd_una */
519       if (seq_lt (blk->end, tc->snd_una))
520         continue;
521
522       cur = bt_lookup_seq (bt, blk->start);
523       if (!cur)
524         continue;
525
526       ASSERT (seq_geq (blk->start, cur->min_seq)
527               && seq_lt (blk->start, cur->max_seq));
528
529       /* Current should be split. Second part will be consumed */
530       if (PREDICT_FALSE (cur->min_seq != blk->start))
531         {
532           cur = bt_split_sample (bt, cur, blk->start);
533           prev = bt_prev_sample (bt, cur);
534         }
535       else
536         prev = bt_prev_sample (bt, cur);
537
538       while (cur && seq_leq (cur->max_seq, blk->end))
539         {
540           if (!(cur->flags & TCP_BTS_IS_SACKED))
541             {
542               tcp_bt_sample_to_rate_sample (tc, cur, rs);
543               cur->flags |= TCP_BTS_IS_SACKED;
544               if (prev && (prev->flags & TCP_BTS_IS_SACKED))
545                 {
546                   cur = bt_merge_sample (bt, prev, cur);
547                   next = bt_next_sample (bt, cur);
548                 }
549               else
550                 {
551                   next = bt_next_sample (bt, cur);
552                   if (next && (next->flags & TCP_BTS_IS_SACKED))
553                     {
554                       cur = bt_merge_sample (bt, cur, next);
555                       next = bt_next_sample (bt, cur);
556                     }
557                 }
558             }
559           else
560             next = bt_next_sample (bt, cur);
561
562           prev = cur;
563           cur = next;
564         }
565
566       if (cur && seq_lt (cur->min_seq, blk->end))
567         {
568           tcp_bt_sample_to_rate_sample (tc, cur, rs);
569           prev = bt_prev_sample (bt, cur);
570           /* Extend previous to include the newly sacked bytes */
571           if (prev && (prev->flags & TCP_BTS_IS_SACKED))
572             {
573               prev->max_seq = blk->end;
574               bt_update_sample (bt, cur, blk->end);
575             }
576           /* Split sample into two. First part is consumed */
577           else
578             {
579               next = bt_split_sample (bt, cur, blk->end);
580               cur = bt_prev_sample (bt, next);
581               cur->flags |= TCP_BTS_IS_SACKED;
582             }
583         }
584     }
585 }
586
587 void
588 tcp_bt_sample_delivery_rate (tcp_connection_t * tc, tcp_rate_sample_t * rs)
589 {
590   u32 delivered;
591
592   if (PREDICT_FALSE (tc->flags & TCP_CONN_FINSNT))
593     return;
594
595   tc->lost += tc->sack_sb.last_lost_bytes;
596
597   delivered = tc->bytes_acked + tc->sack_sb.last_sacked_bytes;
598   if (!delivered || tc->bt->head == TCP_BTS_INVALID_INDEX)
599     return;
600
601   /* Do not count bytes that were previously sacked again */
602   tc->delivered += delivered - tc->sack_sb.last_bytes_delivered;
603   tc->delivered_time = tcp_time_now_us (tc->c_thread_index);
604
605   if (tc->app_limited && tc->delivered > tc->app_limited)
606     tc->app_limited = 0;
607
608   if (tc->bytes_acked)
609     tcp_bt_walk_samples (tc, rs);
610
611   if (tc->sack_sb.last_sacked_bytes)
612     tcp_bt_walk_samples_ooo (tc, rs);
613
614   rs->interval_time = clib_max ((tc->delivered_time - rs->prior_time),
615                                 rs->interval_time);
616   rs->delivered = tc->delivered - rs->prior_delivered;
617   rs->acked_and_sacked = delivered;
618   rs->last_lost = tc->sack_sb.last_lost_bytes;
619   rs->lost = tc->lost - rs->tx_lost;
620 }
621
622 void
623 tcp_bt_flush_samples (tcp_connection_t * tc)
624 {
625   tcp_byte_tracker_t *bt = tc->bt;
626   tcp_bt_sample_t *bts;
627   u32 *samples = 0, *si;
628
629   vec_validate (samples, pool_elts (bt->samples) - 1);
630   vec_reset_length (samples);
631
632   /* *INDENT-OFF* */
633   pool_foreach (bts, bt->samples, ({
634     vec_add1 (samples, bts - bt->samples);
635   }));
636   /* *INDENT-ON* */
637
638   vec_foreach (si, samples)
639   {
640     bts = bt_get_sample (bt, *si);
641     bt_free_sample (bt, bts);
642   }
643
644   vec_free (samples);
645 }
646
647 void
648 tcp_bt_cleanup (tcp_connection_t * tc)
649 {
650   tcp_byte_tracker_t *bt = tc->bt;
651
652   rb_tree_free_nodes (&bt->sample_lookup);
653   pool_free (bt->samples);
654   clib_mem_free (bt);
655   tc->bt = 0;
656 }
657
658 void
659 tcp_bt_init (tcp_connection_t * tc)
660 {
661   tcp_byte_tracker_t *bt;
662
663   bt = clib_mem_alloc (sizeof (tcp_byte_tracker_t));
664   clib_memset (bt, 0, sizeof (tcp_byte_tracker_t));
665
666   rb_tree_init (&bt->sample_lookup);
667   bt->head = bt->tail = TCP_BTS_INVALID_INDEX;
668   tc->bt = bt;
669 }
670
671 u8 *
672 format_tcp_bt_sample (u8 * s, va_list * args)
673 {
674   tcp_connection_t *tc = va_arg (*args, tcp_connection_t *);
675   tcp_bt_sample_t *bts = va_arg (*args, tcp_bt_sample_t *);
676   f64 now = tcp_time_now_us (tc->c_thread_index);
677   s = format (s, "[%u, %u] d %u dt %.3f txt %.3f ftxt %.3f flags 0x%x",
678               bts->min_seq - tc->iss, bts->max_seq - tc->iss, bts->delivered,
679               now - bts->delivered_time, now - bts->tx_time,
680               now - bts->first_tx_time, bts->flags);
681   return s;
682 }
683
684 u8 *
685 format_tcp_bt (u8 * s, va_list * args)
686 {
687   tcp_connection_t *tc = va_arg (*args, tcp_connection_t *);
688   tcp_byte_tracker_t *bt = tc->bt;
689   tcp_bt_sample_t *bts;
690
691   bts = bt_get_sample (bt, bt->head);
692   while (bts)
693     {
694       s = format (s, "%U\n", format_tcp_bt_sample, tc, bts);
695       bts = bt_next_sample (bt, bts);
696     }
697
698   return s;
699 }
700
701 /*
702  * fd.io coding-style-patch-verification: ON
703  *
704  * Local Variables:
705  * eval: (c-set-style "gnu")
706  * End:
707  */