/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */ /* lsquic_adaptive_cc.c -- adaptive congestion controller */ #include #include #include #include #include #include #ifdef WIN32 #include #endif #include "lsquic_int_types.h" #include "lsquic_types.h" #include "lsquic_hash.h" #include "lsquic_util.h" #include "lsquic_cong_ctl.h" #include "lsquic_sfcw.h" #include "lsquic_conn_flow.h" #include "lsquic_varint.h" #include "lsquic_hq.h" #include "lsquic_stream.h" #include "lsquic_rtt.h" #include "lsquic_conn_public.h" #include "lsquic_packet_common.h" #include "lsquic_packet_out.h" #include "lsquic_bw_sampler.h" #include "lsquic_minmax.h" #include "lsquic_bbr.h" #include "lsquic_cubic.h" #include "lsquic_adaptive_cc.h" #define LSQUIC_LOGGER_MODULE LSQLM_ADAPTIVE_CC #define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(acc->acc_cubic.cu_conn) #include "lsquic_logger.h" #define CALL_BOTH(method, ...) do { \ lsquic_cong_bbr_if.method(&acc->acc_bbr, __VA_ARGS__); \ lsquic_cong_cubic_if.method(&acc->acc_cubic, __VA_ARGS__); \ } while (0) #define CALL_BOTH_MAYBE(method, ...) do { \ if (lsquic_cong_bbr_if.method) \ lsquic_cong_bbr_if.method(&acc->acc_bbr, __VA_ARGS__); \ if (lsquic_cong_cubic_if.method) \ lsquic_cong_cubic_if.method(&acc->acc_cubic, __VA_ARGS__); \ } while (0) #define CALL_BOTH0(method) do { \ lsquic_cong_bbr_if.method(&acc->acc_bbr); \ lsquic_cong_cubic_if.method(&acc->acc_cubic); \ } while (0) static void adaptive_cc_init (void *cong_ctl, const struct lsquic_conn_public *conn_pub, enum quic_ft_bit retx_frames) { struct adaptive_cc *const acc = cong_ctl; CALL_BOTH(cci_init, conn_pub, retx_frames); LSQ_DEBUG("initialized"); } static void adaptive_cc_reinit (void *cong_ctl) { struct adaptive_cc *const acc = cong_ctl; CALL_BOTH0(cci_reinit); } static void adaptive_cc_ack (void *cong_ctl, struct lsquic_packet_out *packet_out, unsigned packet_sz, lsquic_time_t now, int app_limited) { struct adaptive_cc *const acc = cong_ctl; CALL_BOTH(cci_ack, packet_out, packet_sz, now, app_limited); } static void adaptive_cc_loss (void *cong_ctl) { struct adaptive_cc *const acc = cong_ctl; CALL_BOTH0(cci_loss); } static void adaptive_cc_begin_ack (void *cong_ctl, lsquic_time_t ack_time, uint64_t in_flight) { struct adaptive_cc *const acc = cong_ctl; CALL_BOTH_MAYBE(cci_begin_ack, ack_time, in_flight); } static void adaptive_cc_end_ack (void *cong_ctl, uint64_t in_flight) { struct adaptive_cc *const acc = cong_ctl; CALL_BOTH_MAYBE(cci_end_ack, in_flight); } static void adaptive_cc_sent (void *cong_ctl, struct lsquic_packet_out *packet_out, uint64_t in_flight, int app_limited) { struct adaptive_cc *const acc = cong_ctl; CALL_BOTH_MAYBE(cci_sent, packet_out, in_flight, app_limited); } static void adaptive_cc_lost (void *cong_ctl, struct lsquic_packet_out *packet_out, unsigned packet_sz) { struct adaptive_cc *const acc = cong_ctl; CALL_BOTH_MAYBE(cci_lost, packet_out, packet_sz); } static void adaptive_cc_timeout (void *cong_ctl) { struct adaptive_cc *const acc = cong_ctl; CALL_BOTH0(cci_timeout); } static void adaptive_cc_was_quiet (void *cong_ctl, lsquic_time_t now, uint64_t in_flight) { struct adaptive_cc *const acc = cong_ctl; CALL_BOTH(cci_was_quiet, now, in_flight); } static uint64_t adaptive_cc_get_cwnd (void *cong_ctl) { struct adaptive_cc *const acc = cong_ctl; uint64_t rv[2]; rv[0] = lsquic_cong_cubic_if.cci_get_cwnd(&acc->acc_cubic); rv[1] = lsquic_cong_bbr_if.cci_get_cwnd(&acc->acc_bbr); if (acc->acc_flags & ACC_CUBIC) return rv[0]; else return rv[1]; } static uint64_t adaptive_cc_pacing_rate (void *cong_ctl, int in_recovery) { struct adaptive_cc *const acc = cong_ctl; uint64_t rv[2]; rv[0] = lsquic_cong_cubic_if.cci_pacing_rate(&acc->acc_cubic, in_recovery); rv[1] = lsquic_cong_bbr_if.cci_pacing_rate(&acc->acc_bbr, in_recovery); if (acc->acc_flags & ACC_CUBIC) return rv[0]; else return rv[1]; } static void adaptive_cc_cleanup (void *cong_ctl) { struct adaptive_cc *const acc = cong_ctl; CALL_BOTH0(cci_cleanup); LSQ_DEBUG("cleanup"); } const struct cong_ctl_if lsquic_cong_adaptive_if = { .cci_ack = adaptive_cc_ack, .cci_begin_ack = adaptive_cc_begin_ack, .cci_end_ack = adaptive_cc_end_ack, .cci_cleanup = adaptive_cc_cleanup, .cci_get_cwnd = adaptive_cc_get_cwnd, .cci_init = adaptive_cc_init, .cci_pacing_rate = adaptive_cc_pacing_rate, .cci_loss = adaptive_cc_loss, .cci_lost = adaptive_cc_lost, .cci_reinit = adaptive_cc_reinit, .cci_timeout = adaptive_cc_timeout, .cci_sent = adaptive_cc_sent, .cci_was_quiet = adaptive_cc_was_quiet, };