• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 (bbr_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 (ack->pkt_delivered >= cc->congestion_recovery_next_round_delivered) {
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     cc->congestion_recovery_next_round_delivered = cc->rst->delivered;
317   }
318 }
319 
bbr_update_btl_bw(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat,const ngtcp2_cc_ack * ack)320 static void bbr_update_btl_bw(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
321                               const ngtcp2_cc_ack *ack) {
322   bbr_update_round(cc, ack);
323   bbr_handle_recovery(cc, cstat, ack);
324 
325   if (cstat->delivery_rate_sec < cc->btl_bw && cc->rst->rs.is_app_limited) {
326     return;
327   }
328 
329   ngtcp2_window_filter_update(&cc->btl_bw_filter, cstat->delivery_rate_sec,
330                               cc->round_count);
331 
332   cc->btl_bw = ngtcp2_window_filter_get_best(&cc->btl_bw_filter);
333 }
334 
bbr_update_rtprop(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat,ngtcp2_tstamp ts)335 static void bbr_update_rtprop(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
336                               ngtcp2_tstamp ts) {
337   cc->rtprop_expired = ts > cc->rtprop_stamp + NGTCP2_RTPROP_FILTERLEN;
338 
339   /* Need valid RTT sample */
340   if (cstat->latest_rtt &&
341       (cstat->latest_rtt <= cc->rt_prop || cc->rtprop_expired)) {
342     cc->rt_prop = cstat->latest_rtt;
343     cc->rtprop_stamp = ts;
344 
345     ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV,
346                     "bbr update RTprop=%" PRIu64, cc->rt_prop);
347   }
348 }
349 
bbr_init_pacing_rate(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat)350 static void bbr_init_pacing_rate(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) {
351   double nominal_bandwidth =
352       (double)cc->initial_cwnd / (double)NGTCP2_MILLISECONDS;
353 
354   cstat->pacing_rate = cc->pacing_gain * nominal_bandwidth;
355 }
356 
bbr_set_pacing_rate_with_gain(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat,double pacing_gain)357 static void bbr_set_pacing_rate_with_gain(ngtcp2_bbr_cc *cc,
358                                           ngtcp2_conn_stat *cstat,
359                                           double pacing_gain) {
360   double rate = pacing_gain * (double)cc->btl_bw / NGTCP2_SECONDS;
361 
362   if (cc->filled_pipe || rate > cstat->pacing_rate) {
363     cstat->pacing_rate = rate;
364   }
365 }
366 
bbr_set_pacing_rate(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat)367 static void bbr_set_pacing_rate(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) {
368   bbr_set_pacing_rate_with_gain(cc, cstat, cc->pacing_gain);
369 }
370 
bbr_set_send_quantum(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat)371 static void bbr_set_send_quantum(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) {
372   uint64_t send_quantum;
373   (void)cc;
374 
375   if (cstat->pacing_rate < 1.2 * 1024 * 1024 / 8 / NGTCP2_SECONDS) {
376     cstat->send_quantum = cstat->max_udp_payload_size;
377   } else if (cstat->pacing_rate < 24.0 * 1024 * 1024 / 8 / NGTCP2_SECONDS) {
378     cstat->send_quantum = cstat->max_udp_payload_size * 2;
379   } else {
380     send_quantum =
381         (uint64_t)(cstat->pacing_rate * (double)(cstat->min_rtt == UINT64_MAX
382                                                      ? NGTCP2_MILLISECONDS
383                                                      : cstat->min_rtt));
384     cstat->send_quantum = (size_t)ngtcp2_min(send_quantum, 64 * 1024);
385   }
386 
387   cstat->send_quantum =
388       ngtcp2_max(cstat->send_quantum, cstat->max_udp_payload_size * 10);
389 }
390 
bbr_inflight(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat,double gain)391 static uint64_t bbr_inflight(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
392                              double gain) {
393   uint64_t quanta = 3 * cstat->send_quantum;
394   double estimated_bdp;
395 
396   if (cc->rt_prop == UINT64_MAX) {
397     /* no valid RTT samples yet */
398     return cc->initial_cwnd;
399   }
400 
401   estimated_bdp = (double)cc->btl_bw * (double)cc->rt_prop / NGTCP2_SECONDS;
402 
403   return (uint64_t)(gain * estimated_bdp) + quanta;
404 }
405 
bbr_update_target_cwnd(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat)406 static void bbr_update_target_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) {
407   cc->target_cwnd = bbr_inflight(cc, cstat, cc->cwnd_gain);
408 }
409 
bbr_modulate_cwnd_for_recovery(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat,const ngtcp2_cc_ack * ack)410 static void bbr_modulate_cwnd_for_recovery(ngtcp2_bbr_cc *cc,
411                                            ngtcp2_conn_stat *cstat,
412                                            const ngtcp2_cc_ack *ack) {
413   if (ack->bytes_lost > 0) {
414     if (cstat->cwnd > ack->bytes_lost) {
415       cstat->cwnd -= ack->bytes_lost;
416       cstat->cwnd = ngtcp2_max(cstat->cwnd, 2 * cstat->max_udp_payload_size);
417     } else {
418       cstat->cwnd = cstat->max_udp_payload_size;
419     }
420   }
421 
422   if (cc->packet_conservation) {
423     cstat->cwnd =
424         ngtcp2_max(cstat->cwnd, cstat->bytes_in_flight + ack->bytes_delivered);
425   }
426 }
427 
bbr_save_cwnd(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat)428 static void bbr_save_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) {
429   if (!cc->in_loss_recovery && cc->state != NGTCP2_BBR_STATE_PROBE_RTT) {
430     cc->prior_cwnd = cstat->cwnd;
431     return;
432   }
433 
434   cc->prior_cwnd = ngtcp2_max(cc->prior_cwnd, cstat->cwnd);
435 }
436 
bbr_restore_cwnd(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat)437 static void bbr_restore_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) {
438   cstat->cwnd = ngtcp2_max(cstat->cwnd, cc->prior_cwnd);
439 }
440 
min_pipe_cwnd(size_t max_udp_payload_size)441 static uint64_t min_pipe_cwnd(size_t max_udp_payload_size) {
442   return max_udp_payload_size * 4;
443 }
444 
bbr_modulate_cwnd_for_probe_rtt(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat)445 static void bbr_modulate_cwnd_for_probe_rtt(ngtcp2_bbr_cc *cc,
446                                             ngtcp2_conn_stat *cstat) {
447   if (cc->state == NGTCP2_BBR_STATE_PROBE_RTT) {
448     cstat->cwnd =
449         ngtcp2_min(cstat->cwnd, min_pipe_cwnd(cstat->max_udp_payload_size));
450   }
451 }
452 
bbr_set_cwnd(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat,const ngtcp2_cc_ack * ack)453 static void bbr_set_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
454                          const ngtcp2_cc_ack *ack) {
455   bbr_update_target_cwnd(cc, cstat);
456   bbr_modulate_cwnd_for_recovery(cc, cstat, ack);
457 
458   if (!cc->packet_conservation) {
459     if (cc->filled_pipe) {
460       cstat->cwnd =
461           ngtcp2_min(cstat->cwnd + ack->bytes_delivered, cc->target_cwnd);
462     } else if (cstat->cwnd < cc->target_cwnd ||
463                cc->rst->delivered < cc->initial_cwnd) {
464       cstat->cwnd += ack->bytes_delivered;
465     }
466 
467     cstat->cwnd =
468         ngtcp2_max(cstat->cwnd, min_pipe_cwnd(cstat->max_udp_payload_size));
469   }
470 
471   bbr_modulate_cwnd_for_probe_rtt(cc, cstat);
472 }
473 
bbr_init(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat,ngtcp2_tstamp initial_ts)474 static void bbr_init(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
475                      ngtcp2_tstamp initial_ts) {
476   cc->pacing_gain = NGTCP2_BBR_HIGH_GAIN;
477   cc->prior_cwnd = 0;
478   cc->target_cwnd = 0;
479   cc->btl_bw = 0;
480   cc->rt_prop = UINT64_MAX;
481   cc->rtprop_stamp = initial_ts;
482   cc->cycle_stamp = UINT64_MAX;
483   cc->probe_rtt_done_stamp = UINT64_MAX;
484   cc->cycle_index = 0;
485   cc->rtprop_expired = 0;
486   cc->idle_restart = 0;
487   cc->packet_conservation = 0;
488   cc->probe_rtt_round_done = 0;
489 
490   cc->congestion_recovery_start_ts = UINT64_MAX;
491   cc->congestion_recovery_next_round_delivered = 0;
492   cc->in_loss_recovery = 0;
493 
494   cstat->send_quantum = cstat->max_udp_payload_size * 10;
495 
496   ngtcp2_window_filter_init(&cc->btl_bw_filter, NGTCP2_BBR_BTL_BW_FILTERLEN);
497 
498   bbr_init_round_counting(cc);
499   bbr_init_full_pipe(cc);
500   bbr_init_pacing_rate(cc, cstat);
501   bbr_enter_startup(cc);
502 }
503 
bbr_enter_startup(ngtcp2_bbr_cc * cc)504 static void bbr_enter_startup(ngtcp2_bbr_cc *cc) {
505   cc->state = NGTCP2_BBR_STATE_STARTUP;
506   cc->pacing_gain = NGTCP2_BBR_HIGH_GAIN;
507   cc->cwnd_gain = NGTCP2_BBR_HIGH_GAIN;
508 }
509 
bbr_init_full_pipe(ngtcp2_bbr_cc * cc)510 static void bbr_init_full_pipe(ngtcp2_bbr_cc *cc) {
511   cc->filled_pipe = 0;
512   cc->full_bw = 0;
513   cc->full_bw_count = 0;
514 }
515 
bbr_check_full_pipe(ngtcp2_bbr_cc * cc)516 static void bbr_check_full_pipe(ngtcp2_bbr_cc *cc) {
517   if (cc->filled_pipe || !cc->round_start || cc->rst->rs.is_app_limited) {
518     /* no need to check for a full pipe now. */
519     return;
520   }
521 
522   /* cc->btl_bw still growing? */
523   if (cc->btl_bw * 100 >= cc->full_bw * 125) {
524     /* record new baseline level */
525     cc->full_bw = cc->btl_bw;
526     cc->full_bw_count = 0;
527     return;
528   }
529   /* another round w/o much growth */
530   ++cc->full_bw_count;
531   if (cc->full_bw_count >= 3) {
532     cc->filled_pipe = 1;
533     ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV,
534                     "bbr filled pipe, btl_bw=%" PRIu64, cc->btl_bw);
535   }
536 }
537 
bbr_enter_drain(ngtcp2_bbr_cc * cc)538 static void bbr_enter_drain(ngtcp2_bbr_cc *cc) {
539   cc->state = NGTCP2_BBR_STATE_DRAIN;
540   /* pace slowly */
541   cc->pacing_gain = 1.0 / NGTCP2_BBR_HIGH_GAIN;
542   /* maintain cwnd */
543   cc->cwnd_gain = NGTCP2_BBR_HIGH_GAIN;
544 }
545 
bbr_check_drain(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat,ngtcp2_tstamp ts)546 static void bbr_check_drain(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
547                             ngtcp2_tstamp ts) {
548   if (cc->state == NGTCP2_BBR_STATE_STARTUP && cc->filled_pipe) {
549     ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV,
550                     "bbr exit Startup and enter Drain");
551 
552     bbr_enter_drain(cc);
553   }
554 
555   if (cc->state == NGTCP2_BBR_STATE_DRAIN &&
556       cstat->bytes_in_flight <= bbr_inflight(cc, cstat, 1.0)) {
557     ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV,
558                     "bbr exit Drain and enter ProbeBW");
559 
560     /* we estimate queue is drained */
561     bbr_enter_probe_bw(cc, ts);
562   }
563 }
564 
bbr_enter_probe_bw(ngtcp2_bbr_cc * cc,ngtcp2_tstamp ts)565 static void bbr_enter_probe_bw(ngtcp2_bbr_cc *cc, ngtcp2_tstamp ts) {
566   uint8_t rand;
567 
568   cc->state = NGTCP2_BBR_STATE_PROBE_BW;
569   cc->pacing_gain = 1;
570   cc->cwnd_gain = 2;
571 
572   assert(cc->rand);
573 
574   cc->rand(&rand, 1, &cc->rand_ctx);
575 
576   cc->cycle_index = NGTCP2_BBR_GAIN_CYCLELEN - 1 - (size_t)(rand * 7 / 256);
577   bbr_advance_cycle_phase(cc, ts);
578 }
579 
bbr_check_cycle_phase(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat,const ngtcp2_cc_ack * ack,ngtcp2_tstamp ts)580 static void bbr_check_cycle_phase(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
581                                   const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) {
582   if (cc->state == NGTCP2_BBR_STATE_PROBE_BW &&
583       bbr_is_next_cycle_phase(cc, cstat, ack, ts)) {
584     bbr_advance_cycle_phase(cc, ts);
585   }
586 }
587 
bbr_advance_cycle_phase(ngtcp2_bbr_cc * cc,ngtcp2_tstamp ts)588 static void bbr_advance_cycle_phase(ngtcp2_bbr_cc *cc, ngtcp2_tstamp ts) {
589   cc->cycle_stamp = ts;
590   cc->cycle_index = (cc->cycle_index + 1) & (NGTCP2_BBR_GAIN_CYCLELEN - 1);
591   cc->pacing_gain = pacing_gain_cycle[cc->cycle_index];
592 }
593 
bbr_is_next_cycle_phase(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat,const ngtcp2_cc_ack * ack,ngtcp2_tstamp ts)594 static int bbr_is_next_cycle_phase(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
595                                    const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) {
596   int is_full_length = (ts - cc->cycle_stamp) > cc->rt_prop;
597 
598   if (cc->pacing_gain > 1) {
599     return is_full_length && (ack->bytes_lost > 0 ||
600                               ack->prior_bytes_in_flight >=
601                                   bbr_inflight(cc, cstat, cc->pacing_gain));
602   }
603 
604   if (cc->pacing_gain < 1) {
605     return is_full_length ||
606            ack->prior_bytes_in_flight <= bbr_inflight(cc, cstat, 1);
607   }
608 
609   return is_full_length;
610 }
611 
bbr_handle_restart_from_idle(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat)612 static void bbr_handle_restart_from_idle(ngtcp2_bbr_cc *cc,
613                                          ngtcp2_conn_stat *cstat) {
614   if (cstat->bytes_in_flight == 0 && cc->rst->app_limited) {
615     ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, "bbr restart from idle");
616 
617     cc->idle_restart = 1;
618 
619     if (cc->state == NGTCP2_BBR_STATE_PROBE_BW) {
620       bbr_set_pacing_rate_with_gain(cc, cstat, 1);
621     }
622   }
623 }
624 
bbr_check_probe_rtt(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat,ngtcp2_tstamp ts)625 static void bbr_check_probe_rtt(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
626                                 ngtcp2_tstamp ts) {
627   if (cc->state != NGTCP2_BBR_STATE_PROBE_RTT && cc->rtprop_expired &&
628       !cc->idle_restart) {
629     ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, "bbr enter ProbeRTT");
630 
631     bbr_enter_probe_rtt(cc);
632     bbr_save_cwnd(cc, cstat);
633     cc->probe_rtt_done_stamp = UINT64_MAX;
634   }
635 
636   if (cc->state == NGTCP2_BBR_STATE_PROBE_RTT) {
637     bbr_handle_probe_rtt(cc, cstat, ts);
638   }
639 
640   cc->idle_restart = 0;
641 }
642 
bbr_enter_probe_rtt(ngtcp2_bbr_cc * cc)643 static void bbr_enter_probe_rtt(ngtcp2_bbr_cc *cc) {
644   cc->state = NGTCP2_BBR_STATE_PROBE_RTT;
645   cc->pacing_gain = 1;
646   cc->cwnd_gain = 1;
647 }
648 
bbr_handle_probe_rtt(ngtcp2_bbr_cc * cc,ngtcp2_conn_stat * cstat,ngtcp2_tstamp ts)649 static void bbr_handle_probe_rtt(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
650                                  ngtcp2_tstamp ts) {
651   uint64_t app_limited = cc->rst->delivered + cstat->bytes_in_flight;
652 
653   /* Ignore low rate samples during NGTCP2_BBR_STATE_PROBE_RTT. */
654   cc->rst->app_limited = app_limited ? app_limited : 1;
655 
656   if (cc->probe_rtt_done_stamp == UINT64_MAX &&
657       cstat->bytes_in_flight <= min_pipe_cwnd(cstat->max_udp_payload_size)) {
658     cc->probe_rtt_done_stamp = ts + NGTCP2_BBR_PROBE_RTT_DURATION;
659     cc->probe_rtt_round_done = 0;
660     cc->next_round_delivered = cc->rst->delivered;
661 
662     return;
663   }
664 
665   if (cc->probe_rtt_done_stamp != UINT64_MAX) {
666     if (cc->round_start) {
667       cc->probe_rtt_round_done = 1;
668     }
669 
670     if (cc->probe_rtt_round_done && ts > cc->probe_rtt_done_stamp) {
671       cc->rtprop_stamp = ts;
672       bbr_restore_cwnd(cc, cstat);
673       bbr_exit_probe_rtt(cc, ts);
674     }
675   }
676 }
677 
bbr_exit_probe_rtt(ngtcp2_bbr_cc * cc,ngtcp2_tstamp ts)678 static void bbr_exit_probe_rtt(ngtcp2_bbr_cc *cc, ngtcp2_tstamp ts) {
679   if (cc->filled_pipe) {
680     ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV,
681                     "bbr exit ProbeRTT and enter ProbeBW");
682 
683     bbr_enter_probe_bw(cc, ts);
684 
685     return;
686   }
687 
688   ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV,
689                   "bbr exit ProbeRTT and enter Startup");
690 
691   bbr_enter_startup(cc);
692 }
693