1a74702c6SGeorge Wang/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc.  See LICENSE. */
2b1a7c3f9SDmitri Tikhonov/* lsquic_adaptive_cc.c -- adaptive congestion controller */
3b1a7c3f9SDmitri Tikhonov
4b1a7c3f9SDmitri Tikhonov#include <inttypes.h>
5b1a7c3f9SDmitri Tikhonov#include <math.h>
6b1a7c3f9SDmitri Tikhonov#include <stddef.h>
7b1a7c3f9SDmitri Tikhonov#include <stdlib.h>
8b1a7c3f9SDmitri Tikhonov#include <string.h>
9b1a7c3f9SDmitri Tikhonov#include <sys/queue.h>
10b1a7c3f9SDmitri Tikhonov#ifdef WIN32
11b1a7c3f9SDmitri Tikhonov#include <vc_compat.h>
12b1a7c3f9SDmitri Tikhonov#endif
13b1a7c3f9SDmitri Tikhonov
14b1a7c3f9SDmitri Tikhonov#include "lsquic_int_types.h"
15b1a7c3f9SDmitri Tikhonov#include "lsquic_types.h"
16b1a7c3f9SDmitri Tikhonov#include "lsquic_hash.h"
17b1a7c3f9SDmitri Tikhonov#include "lsquic_util.h"
18b1a7c3f9SDmitri Tikhonov#include "lsquic_cong_ctl.h"
19b1a7c3f9SDmitri Tikhonov#include "lsquic_sfcw.h"
20b1a7c3f9SDmitri Tikhonov#include "lsquic_conn_flow.h"
21b1a7c3f9SDmitri Tikhonov#include "lsquic_varint.h"
22b1a7c3f9SDmitri Tikhonov#include "lsquic_hq.h"
23b1a7c3f9SDmitri Tikhonov#include "lsquic_stream.h"
24b1a7c3f9SDmitri Tikhonov#include "lsquic_rtt.h"
25b1a7c3f9SDmitri Tikhonov#include "lsquic_conn_public.h"
26b1a7c3f9SDmitri Tikhonov#include "lsquic_packet_common.h"
27b1a7c3f9SDmitri Tikhonov#include "lsquic_packet_out.h"
28b1a7c3f9SDmitri Tikhonov#include "lsquic_bw_sampler.h"
29b1a7c3f9SDmitri Tikhonov#include "lsquic_minmax.h"
30b1a7c3f9SDmitri Tikhonov#include "lsquic_bbr.h"
31b1a7c3f9SDmitri Tikhonov#include "lsquic_cubic.h"
32b1a7c3f9SDmitri Tikhonov#include "lsquic_adaptive_cc.h"
33b1a7c3f9SDmitri Tikhonov
34b1a7c3f9SDmitri Tikhonov#define LSQUIC_LOGGER_MODULE LSQLM_ADAPTIVE_CC
35b1a7c3f9SDmitri Tikhonov#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(acc->acc_cubic.cu_conn)
36b1a7c3f9SDmitri Tikhonov#include "lsquic_logger.h"
37b1a7c3f9SDmitri Tikhonov
38b1a7c3f9SDmitri Tikhonov
39b1a7c3f9SDmitri Tikhonov#define CALL_BOTH(method, ...) do {                             \
40b1a7c3f9SDmitri Tikhonov    lsquic_cong_bbr_if.method(&acc->acc_bbr, __VA_ARGS__);      \
41b1a7c3f9SDmitri Tikhonov    lsquic_cong_cubic_if.method(&acc->acc_cubic, __VA_ARGS__);  \
42b1a7c3f9SDmitri Tikhonov} while (0)
43b1a7c3f9SDmitri Tikhonov
44b1a7c3f9SDmitri Tikhonov
45b1a7c3f9SDmitri Tikhonov#define CALL_BOTH_MAYBE(method, ...) do {                           \
46b1a7c3f9SDmitri Tikhonov    if (lsquic_cong_bbr_if.method)                                  \
47b1a7c3f9SDmitri Tikhonov        lsquic_cong_bbr_if.method(&acc->acc_bbr, __VA_ARGS__);      \
48b1a7c3f9SDmitri Tikhonov    if (lsquic_cong_cubic_if.method)                                \
49b1a7c3f9SDmitri Tikhonov        lsquic_cong_cubic_if.method(&acc->acc_cubic, __VA_ARGS__);  \
50b1a7c3f9SDmitri Tikhonov} while (0)
51b1a7c3f9SDmitri Tikhonov
52b1a7c3f9SDmitri Tikhonov
53b1a7c3f9SDmitri Tikhonov#define CALL_BOTH0(method) do {                                 \
54b1a7c3f9SDmitri Tikhonov    lsquic_cong_bbr_if.method(&acc->acc_bbr);                   \
55b1a7c3f9SDmitri Tikhonov    lsquic_cong_cubic_if.method(&acc->acc_cubic);               \
56b1a7c3f9SDmitri Tikhonov} while (0)
57b1a7c3f9SDmitri Tikhonov
58b1a7c3f9SDmitri Tikhonov
59b1a7c3f9SDmitri Tikhonovstatic void
60b1a7c3f9SDmitri Tikhonovadaptive_cc_init (void *cong_ctl, const struct lsquic_conn_public *conn_pub,
61b1a7c3f9SDmitri Tikhonov                                                enum quic_ft_bit retx_frames)
62b1a7c3f9SDmitri Tikhonov{
63b1a7c3f9SDmitri Tikhonov    struct adaptive_cc *const acc = cong_ctl;
64b1a7c3f9SDmitri Tikhonov
65b1a7c3f9SDmitri Tikhonov    CALL_BOTH(cci_init, conn_pub, retx_frames);
66b1a7c3f9SDmitri Tikhonov    LSQ_DEBUG("initialized");
67b1a7c3f9SDmitri Tikhonov}
68b1a7c3f9SDmitri Tikhonov
69b1a7c3f9SDmitri Tikhonov
70b1a7c3f9SDmitri Tikhonovstatic void
71b1a7c3f9SDmitri Tikhonovadaptive_cc_reinit (void *cong_ctl)
72b1a7c3f9SDmitri Tikhonov{
73b1a7c3f9SDmitri Tikhonov    struct adaptive_cc *const acc = cong_ctl;
74b1a7c3f9SDmitri Tikhonov
75b1a7c3f9SDmitri Tikhonov    CALL_BOTH0(cci_reinit);
76b1a7c3f9SDmitri Tikhonov}
77b1a7c3f9SDmitri Tikhonov
78b1a7c3f9SDmitri Tikhonov
79b1a7c3f9SDmitri Tikhonovstatic void
80b1a7c3f9SDmitri Tikhonovadaptive_cc_ack (void *cong_ctl, struct lsquic_packet_out *packet_out,
81b1a7c3f9SDmitri Tikhonov                    unsigned packet_sz, lsquic_time_t now, int app_limited)
82b1a7c3f9SDmitri Tikhonov{
83b1a7c3f9SDmitri Tikhonov    struct adaptive_cc *const acc = cong_ctl;
84b1a7c3f9SDmitri Tikhonov
85b1a7c3f9SDmitri Tikhonov    CALL_BOTH(cci_ack, packet_out, packet_sz, now, app_limited);
86b1a7c3f9SDmitri Tikhonov}
87b1a7c3f9SDmitri Tikhonov
88b1a7c3f9SDmitri Tikhonov
89b1a7c3f9SDmitri Tikhonovstatic void
90b1a7c3f9SDmitri Tikhonovadaptive_cc_loss (void *cong_ctl)
91b1a7c3f9SDmitri Tikhonov{
92b1a7c3f9SDmitri Tikhonov    struct adaptive_cc *const acc = cong_ctl;
93b1a7c3f9SDmitri Tikhonov
94b1a7c3f9SDmitri Tikhonov    CALL_BOTH0(cci_loss);
95b1a7c3f9SDmitri Tikhonov}
96b1a7c3f9SDmitri Tikhonov
97b1a7c3f9SDmitri Tikhonov
98b1a7c3f9SDmitri Tikhonovstatic void
99b1a7c3f9SDmitri Tikhonovadaptive_cc_begin_ack (void *cong_ctl, lsquic_time_t ack_time,
100b1a7c3f9SDmitri Tikhonov                                                        uint64_t in_flight)
101b1a7c3f9SDmitri Tikhonov{
102b1a7c3f9SDmitri Tikhonov    struct adaptive_cc *const acc = cong_ctl;
103b1a7c3f9SDmitri Tikhonov
104b1a7c3f9SDmitri Tikhonov    CALL_BOTH_MAYBE(cci_begin_ack, ack_time, in_flight);
105b1a7c3f9SDmitri Tikhonov}
106b1a7c3f9SDmitri Tikhonov
107b1a7c3f9SDmitri Tikhonov
108b1a7c3f9SDmitri Tikhonovstatic void
109b1a7c3f9SDmitri Tikhonovadaptive_cc_end_ack (void *cong_ctl, uint64_t in_flight)
110b1a7c3f9SDmitri Tikhonov{
111b1a7c3f9SDmitri Tikhonov    struct adaptive_cc *const acc = cong_ctl;
112b1a7c3f9SDmitri Tikhonov
113b1a7c3f9SDmitri Tikhonov    CALL_BOTH_MAYBE(cci_end_ack, in_flight);
114b1a7c3f9SDmitri Tikhonov}
115b1a7c3f9SDmitri Tikhonov
116b1a7c3f9SDmitri Tikhonov
117b1a7c3f9SDmitri Tikhonovstatic void
118b1a7c3f9SDmitri Tikhonovadaptive_cc_sent (void *cong_ctl, struct lsquic_packet_out *packet_out,
119b1a7c3f9SDmitri Tikhonov                                        uint64_t in_flight, int app_limited)
120b1a7c3f9SDmitri Tikhonov{
121b1a7c3f9SDmitri Tikhonov    struct adaptive_cc *const acc = cong_ctl;
122b1a7c3f9SDmitri Tikhonov
123b1a7c3f9SDmitri Tikhonov    CALL_BOTH_MAYBE(cci_sent, packet_out, in_flight, app_limited);
124b1a7c3f9SDmitri Tikhonov}
125b1a7c3f9SDmitri Tikhonov
126b1a7c3f9SDmitri Tikhonov
127b1a7c3f9SDmitri Tikhonovstatic void
128b1a7c3f9SDmitri Tikhonovadaptive_cc_lost (void *cong_ctl, struct lsquic_packet_out *packet_out,
129b1a7c3f9SDmitri Tikhonov                                                        unsigned packet_sz)
130b1a7c3f9SDmitri Tikhonov{
131b1a7c3f9SDmitri Tikhonov    struct adaptive_cc *const acc = cong_ctl;
132b1a7c3f9SDmitri Tikhonov
133b1a7c3f9SDmitri Tikhonov    CALL_BOTH_MAYBE(cci_lost, packet_out, packet_sz);
134b1a7c3f9SDmitri Tikhonov}
135b1a7c3f9SDmitri Tikhonov
136b1a7c3f9SDmitri Tikhonov
137b1a7c3f9SDmitri Tikhonovstatic void
138b1a7c3f9SDmitri Tikhonovadaptive_cc_timeout (void *cong_ctl)
139b1a7c3f9SDmitri Tikhonov{
140b1a7c3f9SDmitri Tikhonov    struct adaptive_cc *const acc = cong_ctl;
141b1a7c3f9SDmitri Tikhonov
142b1a7c3f9SDmitri Tikhonov    CALL_BOTH0(cci_timeout);
143b1a7c3f9SDmitri Tikhonov}
144b1a7c3f9SDmitri Tikhonov
145b1a7c3f9SDmitri Tikhonov
146b1a7c3f9SDmitri Tikhonovstatic void
147b1a7c3f9SDmitri Tikhonovadaptive_cc_was_quiet (void *cong_ctl, lsquic_time_t now, uint64_t in_flight)
148b1a7c3f9SDmitri Tikhonov{
149b1a7c3f9SDmitri Tikhonov    struct adaptive_cc *const acc = cong_ctl;
150b1a7c3f9SDmitri Tikhonov
151b1a7c3f9SDmitri Tikhonov    CALL_BOTH(cci_was_quiet, now, in_flight);
152b1a7c3f9SDmitri Tikhonov}
153b1a7c3f9SDmitri Tikhonov
154b1a7c3f9SDmitri Tikhonov
155b1a7c3f9SDmitri Tikhonovstatic uint64_t
156b1a7c3f9SDmitri Tikhonovadaptive_cc_get_cwnd (void *cong_ctl)
157b1a7c3f9SDmitri Tikhonov{
158b1a7c3f9SDmitri Tikhonov    struct adaptive_cc *const acc = cong_ctl;
159b1a7c3f9SDmitri Tikhonov    uint64_t rv[2];
160b1a7c3f9SDmitri Tikhonov
161b1a7c3f9SDmitri Tikhonov    rv[0] = lsquic_cong_cubic_if.cci_get_cwnd(&acc->acc_cubic);
162b1a7c3f9SDmitri Tikhonov    rv[1] = lsquic_cong_bbr_if.cci_get_cwnd(&acc->acc_bbr);
163b1a7c3f9SDmitri Tikhonov
164b1a7c3f9SDmitri Tikhonov    if (acc->acc_flags & ACC_CUBIC)
165b1a7c3f9SDmitri Tikhonov        return rv[0];
166b1a7c3f9SDmitri Tikhonov    else
167b1a7c3f9SDmitri Tikhonov        return rv[1];
168b1a7c3f9SDmitri Tikhonov}
169b1a7c3f9SDmitri Tikhonov
170b1a7c3f9SDmitri Tikhonov
171b1a7c3f9SDmitri Tikhonovstatic uint64_t
172b1a7c3f9SDmitri Tikhonovadaptive_cc_pacing_rate (void *cong_ctl, int in_recovery)
173b1a7c3f9SDmitri Tikhonov{
174b1a7c3f9SDmitri Tikhonov    struct adaptive_cc *const acc = cong_ctl;
175b1a7c3f9SDmitri Tikhonov    uint64_t rv[2];
176b1a7c3f9SDmitri Tikhonov
177b1a7c3f9SDmitri Tikhonov    rv[0] = lsquic_cong_cubic_if.cci_pacing_rate(&acc->acc_cubic, in_recovery);
178b1a7c3f9SDmitri Tikhonov    rv[1] = lsquic_cong_bbr_if.cci_pacing_rate(&acc->acc_bbr, in_recovery);
179b1a7c3f9SDmitri Tikhonov
180b1a7c3f9SDmitri Tikhonov    if (acc->acc_flags & ACC_CUBIC)
181b1a7c3f9SDmitri Tikhonov        return rv[0];
182b1a7c3f9SDmitri Tikhonov    else
183b1a7c3f9SDmitri Tikhonov        return rv[1];
184b1a7c3f9SDmitri Tikhonov}
185b1a7c3f9SDmitri Tikhonov
186b1a7c3f9SDmitri Tikhonov
187b1a7c3f9SDmitri Tikhonovstatic void
188b1a7c3f9SDmitri Tikhonovadaptive_cc_cleanup (void *cong_ctl)
189b1a7c3f9SDmitri Tikhonov{
190b1a7c3f9SDmitri Tikhonov    struct adaptive_cc *const acc = cong_ctl;
191b1a7c3f9SDmitri Tikhonov
192b1a7c3f9SDmitri Tikhonov    CALL_BOTH0(cci_cleanup);
193b1a7c3f9SDmitri Tikhonov    LSQ_DEBUG("cleanup");
194b1a7c3f9SDmitri Tikhonov}
195b1a7c3f9SDmitri Tikhonov
196b1a7c3f9SDmitri Tikhonov
197b1a7c3f9SDmitri Tikhonovconst struct cong_ctl_if lsquic_cong_adaptive_if =
198b1a7c3f9SDmitri Tikhonov{
199b1a7c3f9SDmitri Tikhonov    .cci_ack           = adaptive_cc_ack,
200b1a7c3f9SDmitri Tikhonov    .cci_begin_ack     = adaptive_cc_begin_ack,
201b1a7c3f9SDmitri Tikhonov    .cci_end_ack       = adaptive_cc_end_ack,
202b1a7c3f9SDmitri Tikhonov    .cci_cleanup       = adaptive_cc_cleanup,
203b1a7c3f9SDmitri Tikhonov    .cci_get_cwnd      = adaptive_cc_get_cwnd,
204b1a7c3f9SDmitri Tikhonov    .cci_init          = adaptive_cc_init,
205b1a7c3f9SDmitri Tikhonov    .cci_pacing_rate   = adaptive_cc_pacing_rate,
206b1a7c3f9SDmitri Tikhonov    .cci_loss          = adaptive_cc_loss,
207b1a7c3f9SDmitri Tikhonov    .cci_lost          = adaptive_cc_lost,
208b1a7c3f9SDmitri Tikhonov    .cci_reinit        = adaptive_cc_reinit,
209b1a7c3f9SDmitri Tikhonov    .cci_timeout       = adaptive_cc_timeout,
210b1a7c3f9SDmitri Tikhonov    .cci_sent          = adaptive_cc_sent,
211b1a7c3f9SDmitri Tikhonov    .cci_was_quiet     = adaptive_cc_was_quiet,
212b1a7c3f9SDmitri Tikhonov};
213