1 /*
2  * ngtcp2
3  *
4  * Copyright (c) 2021 ngtcp2 contributors
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25 #include "ngtcp2_bbr.h"
26 
27 #include <assert.h>
28 
29 #include "ngtcp2_log.h"
30 #include "ngtcp2_macro.h"
31 #include "ngtcp2_mem.h"
32 #include "ngtcp2_rcvry.h"
33 #include "ngtcp2_rst.h"
34 
35 static const double pacing_gain_cycle[] = {1.25, 0.75, 1, 1, 1, 1, 1, 1};
36 
37 #define NGTCP2_BBR_GAIN_CYCLELEN                                               \
38   (sizeof(pacing_gain_cycle) / sizeof(pacing_gain_cycle[0]))
39 
40 #define NGTCP2_BBR_HIGH_GAIN 2.89
41 #define NGTCP2_BBR_PROBE_RTT_DURATION (200 * NGTCP2_MILLISECONDS)
42 #define NGTCP2_RTPROP_FILTERLEN (10 * NGTCP2_SECONDS)
43 #define NGTCP2_BBR_BTL_BW_FILTERLEN 10
44 
45 static void bbr_update_on_ack(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
46                               const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts);
47 static void bbr_update_model_and_state(ngtcp2_bbr_cc *cc,
48                                        ngtcp2_conn_stat *cstat,
49                                        const ngtcp2_cc_ack *ack,
50                                        ngtcp2_tstamp ts);
51 static void bbr_update_control_parameters(ngtcp2_bbr_cc *cc,
52                                           ngtcp2_conn_stat *cstat,
53                                           const ngtcp2_cc_ack *ack);
54 static void bbr_on_transmit(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat);
55 static void bbr_init_round_counting(ngtcp2_bbr_cc *cc);
56 static void bbr_update_round(ngtcp2_bbr_cc *cc, const ngtcp2_cc_ack *ack);
57 static void bbr_update_btl_bw(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
58                               const ngtcp2_cc_ack *ack);
59 static void bbr_update_rtprop(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
60                               ngtcp2_tstamp ts);
61 static void bbr_init_pacing_rate(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat);
62 static void bbr_set_pacing_rate_with_gain(ngtcp2_bbr_cc *cc,
63                                           ngtcp2_conn_stat *cstat,
64                                           double pacing_gain);
65 static void bbr_set_pacing_rate(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat);
66 static void bbr_set_send_quantum(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat);
67 static void bbr_update_target_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat);
68 static void bbr_modulate_cwnd_for_recovery(ngtcp2_bbr_cc *cc,
69                                            ngtcp2_conn_stat *cstat,
70                                            const ngtcp2_cc_ack *ack);
71 static void bbr_save_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat);
72 static void bbr_restore_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat);
73 static void bbr_modulate_cwnd_for_probe_rtt(ngtcp2_bbr_cc *cc,
74                                             ngtcp2_conn_stat *cstat);
75 static void bbr_set_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
76                          const ngtcp2_cc_ack *ack);
77 static void bbr_init(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
78                      ngtcp2_tstamp initial_ts);
79 static void bbr_enter_startup(ngtcp2_bbr_cc *cc);
80 static void bbr_init_full_pipe(ngtcp2_bbr_cc *cc);
81 static void bbr_check_full_pipe(ngtcp2_bbr_cc *cc);
82 static void bbr_enter_drain(ngtcp2_bbr_cc *cc);
83 static void bbr_check_drain(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
84                             ngtcp2_tstamp ts);
85 static void bbr_enter_probe_bw(ngtcp2_bbr_cc *cc, ngtcp2_tstamp ts);
86 static void bbr_check_cycle_phase(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
87                                   const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts);
88 static void bbr_advance_cycle_phase(ngtcp2_bbr_cc *cc, ngtcp2_tstamp ts);
89 static int bbr_is_next_cycle_phase(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
90                                    const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts);
91 static void bbr_handle_restart_from_idle(ngtcp2_bbr_cc *cc,
92                                          ngtcp2_conn_stat *cstat);
93 static void bbr_check_probe_rtt(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
94                                 ngtcp2_tstamp ts);
95 static void bbr_enter_probe_rtt(ngtcp2_bbr_cc *cc);
96 static void bbr_handle_probe_rtt(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
97                                  ngtcp2_tstamp ts);
98 static void bbr_exit_probe_rtt(ngtcp2_bbr_cc *cc, ngtcp2_tstamp ts);
99 
ngtcp2_bbr_cc_init(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat,ngtcp2_rst * rst,ngtcp2_tstamp initial_ts,ngtcp2_rand rand,const ngtcp2_rand_ctx * rand_ctx,ngtcp2_log * log)100 void ngtcp2_bbr_cc_init(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
101                         ngtcp2_rst *rst, ngtcp2_tstamp initial_ts,
102                         ngtcp2_rand rand, const ngtcp2_rand_ctx *rand_ctx,
103                         ngtcp2_log *log) {
104   cc->ccb.log = log;
105   cc->rst = rst;
106   cc->rand = rand;
107   cc->rand_ctx = *rand_ctx;
108   cc->initial_cwnd = cstat->cwnd;
109   bbr_init(cc, cstat, initial_ts);
110 }
111 
ngtcp2_bbr_cc_free(ngtcp2_bbr_cc * cc)112 void ngtcp2_bbr_cc_free(ngtcp2_bbr_cc *cc) { (void)cc; }
113 
ngtcp2_cc_bbr_cc_init(ngtcp2_cc * cc,ngtcp2_log * log,ngtcp2_conn_stat * cstat,ngtcp2_rst * rst,ngtcp2_tstamp initial_ts,ngtcp2_rand rand,const ngtcp2_rand_ctx * rand_ctx,const ngtcp2_mem * mem)114 int ngtcp2_cc_bbr_cc_init(ngtcp2_cc *cc, ngtcp2_log *log,
115                           ngtcp2_conn_stat *cstat, ngtcp2_rst *rst,
116                           ngtcp2_tstamp initial_ts, ngtcp2_rand rand,
117                           const ngtcp2_rand_ctx *rand_ctx,
118                           const ngtcp2_mem *mem) {
119   ngtcp2_bbr_cc *bbr_cc;
120 
121   bbr_cc = ngtcp2_mem_calloc(mem, 1, sizeof(ngtcp2_bbr_cc));
122   if (cc == NULL) {
123     return NGTCP2_ERR_NOMEM;
124   }
125 
126   ngtcp2_bbr_cc_init(bbr_cc, cstat, rst, initial_ts, rand, rand_ctx, log);
127 
128   cc->ccb = &bbr_cc->ccb;
129   cc->on_pkt_acked = ngtcp2_cc_bbr_cc_on_pkt_acked;
130   cc->congestion_event = ngtcp2_cc_bbr_cc_congestion_event;
131   cc->on_spurious_congestion = ngtcp2_cc_bbr_cc_on_spurious_congestion;
132   cc->on_persistent_congestion = ngtcp2_cc_bbr_cc_on_persistent_congestion;
133   cc->on_ack_recv = ngtcp2_cc_bbr_cc_on_ack_recv;
134   cc->on_pkt_sent = ngtcp2_cc_bbr_cc_on_pkt_sent;
135   cc->new_rtt_sample = ngtcp2_cc_bbr_cc_new_rtt_sample;
136   cc->reset = ngtcp2_cc_bbr_cc_reset;
137   cc->event = ngtcp2_cc_bbr_cc_event;
138 
139   return 0;
140 }
141 
ngtcp2_cc_bbr_cc_free(ngtcp2_cc * cc,const ngtcp2_mem * mem)142 void ngtcp2_cc_bbr_cc_free(ngtcp2_cc *cc, const ngtcp2_mem *mem) {
143   ngtcp2_bbr_cc *bbr_cc = ngtcp2_struct_of(cc->ccb, ngtcp2_bbr_cc, ccb);
144 
145   ngtcp2_bbr_cc_free(bbr_cc);
146   ngtcp2_mem_free(mem, bbr_cc);
147 }
148 
ngtcp2_cc_bbr_cc_on_pkt_acked(ngtcp2_cc * ccx,ngtcp2_conn_stat * cstat,const ngtcp2_cc_pkt * pkt,ngtcp2_tstamp ts)149 void ngtcp2_cc_bbr_cc_on_pkt_acked(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat,
150                                    const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts) {
151   (void)ccx;
152   (void)cstat;
153   (void)pkt;
154   (void)ts;
155 }
156 
in_congestion_recovery(const ngtcp2_conn_stat * cstat,ngtcp2_tstamp sent_time)157 static int in_congestion_recovery(const ngtcp2_conn_stat *cstat,
158                                   ngtcp2_tstamp sent_time) {
159   return cstat->congestion_recovery_start_ts != UINT64_MAX &&
160          sent_time <= cstat->congestion_recovery_start_ts;
161 }
162 
ngtcp2_cc_bbr_cc_congestion_event(ngtcp2_cc * ccx,ngtcp2_conn_stat * cstat,ngtcp2_tstamp sent_ts,ngtcp2_tstamp ts)163 void ngtcp2_cc_bbr_cc_congestion_event(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat,
164                                        ngtcp2_tstamp sent_ts,
165                                        ngtcp2_tstamp ts) {
166   ngtcp2_bbr_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr_cc, ccb);
167 
168   if (cc->in_loss_recovery || cc->congestion_recovery_start_ts != UINT64_MAX ||
169       in_congestion_recovery(cstat, sent_ts)) {
170     return;
171   }
172 
173   cc->congestion_recovery_start_ts = ts;
174 }
175 
ngtcp2_cc_bbr_cc_on_spurious_congestion(ngtcp2_cc * ccx,ngtcp2_conn_stat * cstat,ngtcp2_tstamp ts)176 void ngtcp2_cc_bbr_cc_on_spurious_congestion(ngtcp2_cc *ccx,
177                                              ngtcp2_conn_stat *cstat,
178                                              ngtcp2_tstamp ts) {
179   ngtcp2_bbr_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr_cc, ccb);
180   (void)ts;
181 
182   cc->congestion_recovery_start_ts = UINT64_MAX;
183   cstat->congestion_recovery_start_ts = UINT64_MAX;
184 
185   if (cc->in_loss_recovery) {
186     cc->in_loss_recovery = 0;
187     cc->packet_conservation = 0;
188     bbr_restore_cwnd(cc, cstat);
189   }
190 }
191 
ngtcp2_cc_bbr_cc_on_persistent_congestion(ngtcp2_cc * ccx,ngtcp2_conn_stat * cstat,ngtcp2_tstamp ts)192 void ngtcp2_cc_bbr_cc_on_persistent_congestion(ngtcp2_cc *ccx,
193                                                ngtcp2_conn_stat *cstat,
194                                                ngtcp2_tstamp ts) {
195   ngtcp2_bbr_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr_cc, ccb);
196   (void)ts;
197 
198   cstat->congestion_recovery_start_ts = UINT64_MAX;
199   cc->congestion_recovery_start_ts = UINT64_MAX;
200   cc->in_loss_recovery = 0;
201   cc->packet_conservation = 0;
202 
203   bbr_save_cwnd(cc, cstat);
204   cstat->cwnd = 2 * cstat->max_udp_payload_size;
205 }
206 
ngtcp2_cc_bbr_cc_on_ack_recv(ngtcp2_cc * ccx,ngtcp2_conn_stat * cstat,const ngtcp2_cc_ack * ack,ngtcp2_tstamp ts)207 void ngtcp2_cc_bbr_cc_on_ack_recv(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat,
208                                   const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) {
209   ngtcp2_bbr_cc *bbr_cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr_cc, ccb);
210 
211   bbr_update_on_ack(bbr_cc, cstat, ack, ts);
212 }
213 
ngtcp2_cc_bbr_cc_on_pkt_sent(ngtcp2_cc * ccx,ngtcp2_conn_stat * cstat,const ngtcp2_cc_pkt * pkt)214 void ngtcp2_cc_bbr_cc_on_pkt_sent(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat,
215                                   const ngtcp2_cc_pkt *pkt) {
216   ngtcp2_bbr_cc *bbr_cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr_cc, ccb);
217   (void)pkt;
218 
219   bbr_on_transmit(bbr_cc, cstat);
220 }
221 
ngtcp2_cc_bbr_cc_new_rtt_sample(ngtcp2_cc * ccx,ngtcp2_conn_stat * cstat,ngtcp2_tstamp ts)222 void ngtcp2_cc_bbr_cc_new_rtt_sample(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat,
223                                      ngtcp2_tstamp ts) {
224   (void)ccx;
225   (void)cstat;
226   (void)ts;
227 }
228 
ngtcp2_cc_bbr_cc_reset(ngtcp2_cc * ccx,ngtcp2_conn_stat * cstat,ngtcp2_tstamp ts)229 void ngtcp2_cc_bbr_cc_reset(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat,
230                             ngtcp2_tstamp ts) {
231   ngtcp2_bbr_cc *bbr_cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr_cc, ccb);
232   bbr_init(bbr_cc, cstat, ts);
233 }
234 
ngtcp2_cc_bbr_cc_event(ngtcp2_cc * ccx,ngtcp2_conn_stat * cstat,ngtcp2_cc_event_type event,ngtcp2_tstamp ts)235 void ngtcp2_cc_bbr_cc_event(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat,
236                             ngtcp2_cc_event_type event, ngtcp2_tstamp ts) {
237   (void)ccx;
238   (void)cstat;
239   (void)event;
240   (void)ts;
241 }
242 
bbr_update_on_ack(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat,const ngtcp2_cc_ack * ack,ngtcp2_tstamp ts)243 static void bbr_update_on_ack(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
244                               const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) {
245   bbr_update_model_and_state(cc, cstat, ack, ts);
246   bbr_update_control_parameters(cc, cstat, ack);
247 }
248 
bbr_update_model_and_state(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat,const ngtcp2_cc_ack * ack,ngtcp2_tstamp ts)249 static void bbr_update_model_and_state(ngtcp2_bbr_cc *cc,
250                                        ngtcp2_conn_stat *cstat,
251                                        const ngtcp2_cc_ack *ack,
252                                        ngtcp2_tstamp ts) {
253   bbr_update_btl_bw(cc, cstat, ack);
254   bbr_check_cycle_phase(cc, cstat, ack, ts);
255   bbr_check_full_pipe(cc);
256   bbr_check_drain(cc, cstat, ts);
257   bbr_update_rtprop(cc, cstat, ts);
258   bbr_check_probe_rtt(cc, cstat, ts);
259 }
260 
bbr_update_control_parameters(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat,const ngtcp2_cc_ack * ack)261 static void bbr_update_control_parameters(ngtcp2_bbr_cc *cc,
262                                           ngtcp2_conn_stat *cstat,
263                                           const ngtcp2_cc_ack *ack) {
264   bbr_set_pacing_rate(cc, cstat);
265   bbr_set_send_quantum(cc, cstat);
266   bbr_set_cwnd(cc, cstat, ack);
267 }
268 
bbr_on_transmit(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat)269 static void bbr_on_transmit(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) {
270   bbr_handle_restart_from_idle(cc, cstat);
271 }
272 
bbr_init_round_counting(ngtcp2_bbr_cc * cc)273 static void bbr_init_round_counting(ngtcp2_bbr_cc *cc) {
274   cc->next_round_delivered = 0;
275   cc->round_start = 0;
276   cc->round_count = 0;
277 }
278 
bbr_update_round(ngtcp2_bbr_cc * cc,const ngtcp2_cc_ack * ack)279 static void bbr_update_round(ngtcp2_bbr_cc *cc, const ngtcp2_cc_ack *ack) {
280   if (ack->pkt_delivered >= cc->next_round_delivered) {
281     cc->next_round_delivered = cc->rst->delivered;
282     ++cc->round_count;
283     cc->round_start = 1;
284 
285     return;
286   }
287 
288   cc->round_start = 0;
289 }
290 
bbr_handle_recovery(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat,const ngtcp2_cc_ack * ack)291 static void bbr_handle_recovery(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
292                                 const ngtcp2_cc_ack *ack) {
293   if (cc->in_loss_recovery) {
294     if (cc->round_start) {
295       cc->packet_conservation = 0;
296     }
297 
298     if (!in_congestion_recovery(cstat, ack->largest_acked_sent_ts)) {
299       cc->in_loss_recovery = 0;
300       cc->packet_conservation = 0;
301       bbr_restore_cwnd(cc, cstat);
302     }
303 
304     return;
305   }
306 
307   if (cc->congestion_recovery_start_ts != UINT64_MAX) {
308     cc->in_loss_recovery = 1;
309     bbr_save_cwnd(cc, cstat);
310     cstat->cwnd = cstat->bytes_in_flight +
311                   ngtcp2_max(ack->bytes_delivered, cstat->max_udp_payload_size);
312 
313     cstat->congestion_recovery_start_ts = cc->congestion_recovery_start_ts;
314     cc->congestion_recovery_start_ts = UINT64_MAX;
315     cc->packet_conservation = 1;
316   }
317 }
318 
bbr_update_btl_bw(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat,const ngtcp2_cc_ack * ack)319 static void bbr_update_btl_bw(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
320                               const ngtcp2_cc_ack *ack) {
321   bbr_update_round(cc, ack);
322   bbr_handle_recovery(cc, cstat, ack);
323 
324   if (cstat->delivery_rate_sec < cc->btl_bw && cc->rst->rs.is_app_limited) {
325     return;
326   }
327 
328   ngtcp2_window_filter_update(&cc->btl_bw_filter, cstat->delivery_rate_sec,
329                               cc->round_count);
330 
331   cc->btl_bw = ngtcp2_window_filter_get_best(&cc->btl_bw_filter);
332 }
333 
bbr_update_rtprop(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat,ngtcp2_tstamp ts)334 static void bbr_update_rtprop(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
335                               ngtcp2_tstamp ts) {
336   cc->rtprop_expired = ts > cc->rtprop_stamp + NGTCP2_RTPROP_FILTERLEN;
337 
338   /* Need valid RTT sample */
339   if (cstat->latest_rtt &&
340       (cstat->latest_rtt <= cc->rt_prop || cc->rtprop_expired)) {
341     cc->rt_prop = cstat->latest_rtt;
342     cc->rtprop_stamp = ts;
343 
344     ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV,
345                     "bbr update RTprop=%" PRIu64, cc->rt_prop);
346   }
347 }
348 
bbr_init_pacing_rate(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat)349 static void bbr_init_pacing_rate(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) {
350   double nominal_bandwidth =
351       (double)cc->initial_cwnd / (double)NGTCP2_MILLISECONDS;
352 
353   cstat->pacing_rate = cc->pacing_gain * nominal_bandwidth;
354 }
355 
bbr_set_pacing_rate_with_gain(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat,double pacing_gain)356 static void bbr_set_pacing_rate_with_gain(ngtcp2_bbr_cc *cc,
357                                           ngtcp2_conn_stat *cstat,
358                                           double pacing_gain) {
359   double rate = pacing_gain * (double)cc->btl_bw / NGTCP2_SECONDS;
360 
361   if (cc->filled_pipe || rate > cstat->pacing_rate) {
362     cstat->pacing_rate = rate;
363   }
364 }
365 
bbr_set_pacing_rate(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat)366 static void bbr_set_pacing_rate(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) {
367   bbr_set_pacing_rate_with_gain(cc, cstat, cc->pacing_gain);
368 }
369 
bbr_set_send_quantum(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat)370 static void bbr_set_send_quantum(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) {
371   uint64_t send_quantum;
372   (void)cc;
373 
374   if (cstat->pacing_rate < 1.2 * 1024 * 1024 / 8 / NGTCP2_SECONDS) {
375     cstat->send_quantum = cstat->max_udp_payload_size;
376   } else if (cstat->pacing_rate < 24.0 * 1024 * 1024 / 8 / NGTCP2_SECONDS) {
377     cstat->send_quantum = cstat->max_udp_payload_size * 2;
378   } else {
379     send_quantum =
380         (uint64_t)(cstat->pacing_rate * (double)(cstat->min_rtt == UINT64_MAX
381                                                      ? NGTCP2_MILLISECONDS
382                                                      : cstat->min_rtt));
383     cstat->send_quantum = (size_t)ngtcp2_min(send_quantum, 64 * 1024);
384   }
385 
386   cstat->send_quantum =
387       ngtcp2_max(cstat->send_quantum, cstat->max_udp_payload_size * 10);
388 }
389 
bbr_inflight(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat,double gain)390 static uint64_t bbr_inflight(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
391                              double gain) {
392   uint64_t quanta = 3 * cstat->send_quantum;
393   double estimated_bdp;
394 
395   if (cc->rt_prop == UINT64_MAX) {
396     /* no valid RTT samples yet */
397     return cc->initial_cwnd;
398   }
399 
400   estimated_bdp = (double)cc->btl_bw * (double)cc->rt_prop / NGTCP2_SECONDS;
401 
402   return (uint64_t)(gain * estimated_bdp) + quanta;
403 }
404 
bbr_update_target_cwnd(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat)405 static void bbr_update_target_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) {
406   cc->target_cwnd = bbr_inflight(cc, cstat, cc->cwnd_gain);
407 }
408 
bbr_modulate_cwnd_for_recovery(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat,const ngtcp2_cc_ack * ack)409 static void bbr_modulate_cwnd_for_recovery(ngtcp2_bbr_cc *cc,
410                                            ngtcp2_conn_stat *cstat,
411                                            const ngtcp2_cc_ack *ack) {
412   if (ack->bytes_lost > 0) {
413     if (cstat->cwnd > ack->bytes_lost) {
414       cstat->cwnd -= ack->bytes_lost;
415       cstat->cwnd = ngtcp2_max(cstat->cwnd, cstat->max_udp_payload_size);
416     } else {
417       cstat->cwnd = cstat->max_udp_payload_size;
418     }
419   }
420 
421   if (cc->packet_conservation) {
422     cstat->cwnd =
423         ngtcp2_max(cstat->cwnd, cstat->bytes_in_flight + ack->bytes_delivered);
424   }
425 }
426 
bbr_save_cwnd(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat)427 static void bbr_save_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) {
428   if (!cc->in_loss_recovery && cc->state != NGTCP2_BBR_STATE_PROBE_RTT) {
429     cc->prior_cwnd = cstat->cwnd;
430     return;
431   }
432 
433   cc->prior_cwnd = ngtcp2_max(cc->prior_cwnd, cstat->cwnd);
434 }
435 
bbr_restore_cwnd(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat)436 static void bbr_restore_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) {
437   cstat->cwnd = ngtcp2_max(cstat->cwnd, cc->prior_cwnd);
438 }
439 
min_pipe_cwnd(size_t max_udp_payload_size)440 static uint64_t min_pipe_cwnd(size_t max_udp_payload_size) {
441   return max_udp_payload_size * 4;
442 }
443 
bbr_modulate_cwnd_for_probe_rtt(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat)444 static void bbr_modulate_cwnd_for_probe_rtt(ngtcp2_bbr_cc *cc,
445                                             ngtcp2_conn_stat *cstat) {
446   if (cc->state == NGTCP2_BBR_STATE_PROBE_RTT) {
447     cstat->cwnd =
448         ngtcp2_min(cstat->cwnd, min_pipe_cwnd(cstat->max_udp_payload_size));
449   }
450 }
451 
bbr_set_cwnd(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat,const ngtcp2_cc_ack * ack)452 static void bbr_set_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
453                          const ngtcp2_cc_ack *ack) {
454   bbr_update_target_cwnd(cc, cstat);
455   bbr_modulate_cwnd_for_recovery(cc, cstat, ack);
456 
457   if (!cc->packet_conservation) {
458     if (cc->filled_pipe) {
459       cstat->cwnd =
460           ngtcp2_min(cstat->cwnd + ack->bytes_delivered, cc->target_cwnd);
461     } else if (cstat->cwnd < cc->target_cwnd ||
462                cc->rst->delivered < cc->initial_cwnd) {
463       cstat->cwnd += ack->bytes_delivered;
464     }
465 
466     cstat->cwnd =
467         ngtcp2_max(cstat->cwnd, min_pipe_cwnd(cstat->max_udp_payload_size));
468   }
469 
470   bbr_modulate_cwnd_for_probe_rtt(cc, cstat);
471 }
472 
bbr_init(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat,ngtcp2_tstamp initial_ts)473 static void bbr_init(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
474                      ngtcp2_tstamp initial_ts) {
475   cc->pacing_gain = NGTCP2_BBR_HIGH_GAIN;
476   cc->prior_cwnd = 0;
477   cc->target_cwnd = 0;
478   cc->btl_bw = 0;
479   cc->rt_prop = UINT64_MAX;
480   cc->rtprop_stamp = initial_ts;
481   cc->cycle_stamp = UINT64_MAX;
482   cc->probe_rtt_done_stamp = UINT64_MAX;
483   cc->cycle_index = 0;
484   cc->rtprop_expired = 0;
485   cc->idle_restart = 0;
486   cc->packet_conservation = 0;
487   cc->probe_rtt_round_done = 0;
488 
489   cc->congestion_recovery_start_ts = UINT64_MAX;
490   cc->in_loss_recovery = 0;
491 
492   cstat->send_quantum = cstat->max_udp_payload_size * 10;
493 
494   ngtcp2_window_filter_init(&cc->btl_bw_filter, NGTCP2_BBR_BTL_BW_FILTERLEN);
495 
496   bbr_init_round_counting(cc);
497   bbr_init_full_pipe(cc);
498   bbr_init_pacing_rate(cc, cstat);
499   bbr_enter_startup(cc);
500 }
501 
bbr_enter_startup(ngtcp2_bbr_cc * cc)502 static void bbr_enter_startup(ngtcp2_bbr_cc *cc) {
503   cc->state = NGTCP2_BBR_STATE_STARTUP;
504   cc->pacing_gain = NGTCP2_BBR_HIGH_GAIN;
505   cc->cwnd_gain = NGTCP2_BBR_HIGH_GAIN;
506 }
507 
bbr_init_full_pipe(ngtcp2_bbr_cc * cc)508 static void bbr_init_full_pipe(ngtcp2_bbr_cc *cc) {
509   cc->filled_pipe = 0;
510   cc->full_bw = 0;
511   cc->full_bw_count = 0;
512 }
513 
bbr_check_full_pipe(ngtcp2_bbr_cc * cc)514 static void bbr_check_full_pipe(ngtcp2_bbr_cc *cc) {
515   if (cc->filled_pipe || !cc->round_start || cc->rst->rs.is_app_limited) {
516     /* no need to check for a full pipe now. */
517     return;
518   }
519 
520   /* cc->btl_bw still growing? */
521   if (cc->btl_bw * 100 >= cc->full_bw * 125) {
522     /* record new baseline level */
523     cc->full_bw = cc->btl_bw;
524     cc->full_bw_count = 0;
525     return;
526   }
527   /* another round w/o much growth */
528   ++cc->full_bw_count;
529   if (cc->full_bw_count >= 3) {
530     cc->filled_pipe = 1;
531     ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV,
532                     "bbr filled pipe, btl_bw=%" PRIu64, cc->btl_bw);
533   }
534 }
535 
bbr_enter_drain(ngtcp2_bbr_cc * cc)536 static void bbr_enter_drain(ngtcp2_bbr_cc *cc) {
537   cc->state = NGTCP2_BBR_STATE_DRAIN;
538   /* pace slowly */
539   cc->pacing_gain = 1.0 / NGTCP2_BBR_HIGH_GAIN;
540   /* maintain cwnd */
541   cc->cwnd_gain = NGTCP2_BBR_HIGH_GAIN;
542 }
543 
bbr_check_drain(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat,ngtcp2_tstamp ts)544 static void bbr_check_drain(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
545                             ngtcp2_tstamp ts) {
546   if (cc->state == NGTCP2_BBR_STATE_STARTUP && cc->filled_pipe) {
547     ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV,
548                     "bbr exit Startup and enter Drain");
549 
550     bbr_enter_drain(cc);
551   }
552 
553   if (cc->state == NGTCP2_BBR_STATE_DRAIN &&
554       cstat->bytes_in_flight <= bbr_inflight(cc, cstat, 1.0)) {
555     ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV,
556                     "bbr exit Drain and enter ProbeBW");
557 
558     /* we estimate queue is drained */
559     bbr_enter_probe_bw(cc, ts);
560   }
561 }
562 
bbr_enter_probe_bw(ngtcp2_bbr_cc * cc,ngtcp2_tstamp ts)563 static void bbr_enter_probe_bw(ngtcp2_bbr_cc *cc, ngtcp2_tstamp ts) {
564   uint8_t rand;
565 
566   cc->state = NGTCP2_BBR_STATE_PROBE_BW;
567   cc->pacing_gain = 1;
568   cc->cwnd_gain = 2;
569 
570   assert(cc->rand);
571 
572   cc->rand(&rand, 1, &cc->rand_ctx);
573 
574   cc->cycle_index = NGTCP2_BBR_GAIN_CYCLELEN - 1 - (size_t)(rand * 7 / 256);
575   bbr_advance_cycle_phase(cc, ts);
576 }
577 
bbr_check_cycle_phase(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat,const ngtcp2_cc_ack * ack,ngtcp2_tstamp ts)578 static void bbr_check_cycle_phase(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
579                                   const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) {
580   if (cc->state == NGTCP2_BBR_STATE_PROBE_BW &&
581       bbr_is_next_cycle_phase(cc, cstat, ack, ts)) {
582     bbr_advance_cycle_phase(cc, ts);
583   }
584 }
585 
bbr_advance_cycle_phase(ngtcp2_bbr_cc * cc,ngtcp2_tstamp ts)586 static void bbr_advance_cycle_phase(ngtcp2_bbr_cc *cc, ngtcp2_tstamp ts) {
587   cc->cycle_stamp = ts;
588   cc->cycle_index = (cc->cycle_index + 1) & (NGTCP2_BBR_GAIN_CYCLELEN - 1);
589   cc->pacing_gain = pacing_gain_cycle[cc->cycle_index];
590 }
591 
bbr_is_next_cycle_phase(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat,const ngtcp2_cc_ack * ack,ngtcp2_tstamp ts)592 static int bbr_is_next_cycle_phase(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
593                                    const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) {
594   int is_full_length = (ts - cc->cycle_stamp) > cc->rt_prop;
595 
596   if (cc->pacing_gain > 1) {
597     return is_full_length && (ack->bytes_lost > 0 ||
598                               ack->prior_bytes_in_flight >=
599                                   bbr_inflight(cc, cstat, cc->pacing_gain));
600   }
601 
602   if (cc->pacing_gain < 1) {
603     return is_full_length ||
604            ack->prior_bytes_in_flight <= bbr_inflight(cc, cstat, 1);
605   }
606 
607   return is_full_length;
608 }
609 
bbr_handle_restart_from_idle(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat)610 static void bbr_handle_restart_from_idle(ngtcp2_bbr_cc *cc,
611                                          ngtcp2_conn_stat *cstat) {
612   if (cstat->bytes_in_flight == 0 && cc->rst->app_limited) {
613     ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, "bbr restart from idle");
614 
615     cc->idle_restart = 1;
616 
617     if (cc->state == NGTCP2_BBR_STATE_PROBE_BW) {
618       bbr_set_pacing_rate_with_gain(cc, cstat, 1);
619     }
620   }
621 }
622 
bbr_check_probe_rtt(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat,ngtcp2_tstamp ts)623 static void bbr_check_probe_rtt(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
624                                 ngtcp2_tstamp ts) {
625   if (cc->state != NGTCP2_BBR_STATE_PROBE_RTT && cc->rtprop_expired &&
626       !cc->idle_restart) {
627     ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, "bbr enter ProbeRTT");
628 
629     bbr_enter_probe_rtt(cc);
630     bbr_save_cwnd(cc, cstat);
631     cc->probe_rtt_done_stamp = UINT64_MAX;
632   }
633 
634   if (cc->state == NGTCP2_BBR_STATE_PROBE_RTT) {
635     bbr_handle_probe_rtt(cc, cstat, ts);
636   }
637 
638   cc->idle_restart = 0;
639 }
640 
bbr_enter_probe_rtt(ngtcp2_bbr_cc * cc)641 static void bbr_enter_probe_rtt(ngtcp2_bbr_cc *cc) {
642   cc->state = NGTCP2_BBR_STATE_PROBE_RTT;
643   cc->pacing_gain = 1;
644   cc->cwnd_gain = 1;
645 }
646 
bbr_handle_probe_rtt(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat,ngtcp2_tstamp ts)647 static void bbr_handle_probe_rtt(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
648                                  ngtcp2_tstamp ts) {
649   uint64_t app_limited = cc->rst->delivered + cstat->bytes_in_flight;
650 
651   /* Ignore low rate samples during NGTCP2_BBR_STATE_PROBE_RTT. */
652   cc->rst->app_limited = app_limited ? app_limited : 1;
653 
654   if (cc->probe_rtt_done_stamp == UINT64_MAX &&
655       cstat->bytes_in_flight <= min_pipe_cwnd(cstat->max_udp_payload_size)) {
656     cc->probe_rtt_done_stamp = ts + NGTCP2_BBR_PROBE_RTT_DURATION;
657     cc->probe_rtt_round_done = 0;
658     cc->next_round_delivered = cc->rst->delivered;
659 
660     return;
661   }
662 
663   if (cc->probe_rtt_done_stamp != UINT64_MAX) {
664     if (cc->round_start) {
665       cc->probe_rtt_round_done = 1;
666     }
667 
668     if (cc->probe_rtt_round_done && ts > cc->probe_rtt_done_stamp) {
669       cc->rtprop_stamp = ts;
670       bbr_restore_cwnd(cc, cstat);
671       bbr_exit_probe_rtt(cc, ts);
672     }
673   }
674 }
675 
bbr_exit_probe_rtt(ngtcp2_bbr_cc * cc,ngtcp2_tstamp ts)676 static void bbr_exit_probe_rtt(ngtcp2_bbr_cc *cc, ngtcp2_tstamp ts) {
677   if (cc->filled_pipe) {
678     ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV,
679                     "bbr exit ProbeRTT and enter ProbeBW");
680 
681     bbr_enter_probe_bw(cc, ts);
682 
683     return;
684   }
685 
686   ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV,
687                   "bbr exit ProbeRTT and enter Startup");
688 
689   bbr_enter_startup(cc);
690 }
691