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