lsquic_sfcw.c revision 5392f7a3
1229fce07SDmitri Tikhonov/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc.  See LICENSE. */
250aadb33SDmitri Tikhonov#include <inttypes.h>
350aadb33SDmitri Tikhonov#include <stdint.h>
450aadb33SDmitri Tikhonov#include <stdlib.h>
550aadb33SDmitri Tikhonov#include <string.h>
650aadb33SDmitri Tikhonov#include <sys/queue.h>
750aadb33SDmitri Tikhonov
850aadb33SDmitri Tikhonov#include "lsquic.h"
950aadb33SDmitri Tikhonov#include "lsquic_int_types.h"
1050aadb33SDmitri Tikhonov#include "lsquic_conn_flow.h"
1150aadb33SDmitri Tikhonov#include "lsquic_types.h"
1250aadb33SDmitri Tikhonov#include "lsquic_rtt.h"
135392f7a3SLiteSpeed Tech#include "lsquic_varint.h"
1450aadb33SDmitri Tikhonov#include "lsquic_sfcw.h"
155392f7a3SLiteSpeed Tech#include "lsquic_varint.h"
165392f7a3SLiteSpeed Tech#include "lsquic_hq.h"
175392f7a3SLiteSpeed Tech#include "lsquic_hash.h"
1850aadb33SDmitri Tikhonov#include "lsquic_stream.h"
1950aadb33SDmitri Tikhonov#include "lsquic_conn_public.h"
2050aadb33SDmitri Tikhonov#include "lsquic_mm.h"
2150aadb33SDmitri Tikhonov#include "lsquic_engine_public.h"
2250aadb33SDmitri Tikhonov#include "lsquic_util.h"
2350aadb33SDmitri Tikhonov#include "lsquic_conn.h"
2450aadb33SDmitri Tikhonov#include "lsquic_ev_log.h"
2550aadb33SDmitri Tikhonov
2650aadb33SDmitri Tikhonov#define LSQUIC_LOGGER_MODULE LSQLM_SFCW
275392f7a3SLiteSpeed Tech#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(fc->sf_conn_pub->lconn)
2850aadb33SDmitri Tikhonov#define LSQUIC_LOG_STREAM_ID fc->sf_stream_id
2950aadb33SDmitri Tikhonov#include "lsquic_logger.h"
3050aadb33SDmitri Tikhonov
3150aadb33SDmitri Tikhonovvoid
3250aadb33SDmitri Tikhonovlsquic_sfcw_init (struct lsquic_sfcw *fc, unsigned max_recv_window,
3350aadb33SDmitri Tikhonov                  struct lsquic_cfcw *cfcw, struct lsquic_conn_public *cpub,
345392f7a3SLiteSpeed Tech                  lsquic_stream_id_t stream_id)
3550aadb33SDmitri Tikhonov{
3650aadb33SDmitri Tikhonov    memset(fc, 0, sizeof(*fc));
3750aadb33SDmitri Tikhonov    fc->sf_max_recv_win = max_recv_window;
3850aadb33SDmitri Tikhonov    fc->sf_cfcw = cfcw;
3950aadb33SDmitri Tikhonov    fc->sf_conn_pub = cpub;
4050aadb33SDmitri Tikhonov    fc->sf_stream_id = stream_id;
4150aadb33SDmitri Tikhonov    (void) lsquic_sfcw_fc_offsets_changed(fc);
4250aadb33SDmitri Tikhonov}
4350aadb33SDmitri Tikhonov
4450aadb33SDmitri Tikhonov
4550aadb33SDmitri Tikhonovstatic void
4650aadb33SDmitri Tikhonovsfcw_maybe_increase_max_window (struct lsquic_sfcw *fc)
4750aadb33SDmitri Tikhonov{
4850aadb33SDmitri Tikhonov    unsigned new_max_window, max_conn_window;
4950aadb33SDmitri Tikhonov
5050aadb33SDmitri Tikhonov    new_max_window = fc->sf_max_recv_win * 2;
5150aadb33SDmitri Tikhonov
5250aadb33SDmitri Tikhonov    /* Do not increase past explicitly specified maximum */
5350aadb33SDmitri Tikhonov    if (new_max_window > fc->sf_conn_pub->enpub->enp_settings.es_max_sfcw)
5450aadb33SDmitri Tikhonov        new_max_window = fc->sf_conn_pub->enpub->enp_settings.es_max_sfcw;
5550aadb33SDmitri Tikhonov
560ae3fccdSDmitri Tikhonov    if (fc->sf_cfcw)
570ae3fccdSDmitri Tikhonov    {
580ae3fccdSDmitri Tikhonov        /* Do not increase past the connection's maximum window size.  The
590ae3fccdSDmitri Tikhonov         * connection's window will be increased separately, if possible.
600ae3fccdSDmitri Tikhonov         *
610ae3fccdSDmitri Tikhonov         * The reference implementation has the logic backwards:  Imagine
620ae3fccdSDmitri Tikhonov         * several concurrent streams that are not being read from fast
630ae3fccdSDmitri Tikhonov         * enough by the user code.  Each of them uses only a fraction
640ae3fccdSDmitri Tikhonov         * of bandwidth.  Does it mean that the connection window must
650ae3fccdSDmitri Tikhonov         * increase?  No.
660ae3fccdSDmitri Tikhonov         */
670ae3fccdSDmitri Tikhonov        max_conn_window = lsquic_cfcw_get_max_recv_window(fc->sf_cfcw);
680ae3fccdSDmitri Tikhonov        if (new_max_window > max_conn_window)
690ae3fccdSDmitri Tikhonov            new_max_window = max_conn_window;
700ae3fccdSDmitri Tikhonov    }
710ae3fccdSDmitri Tikhonov    else
720ae3fccdSDmitri Tikhonov    {
730ae3fccdSDmitri Tikhonov        /* This means that this stream is not affected by connection flow
740ae3fccdSDmitri Tikhonov         * controller.  No need to adjust under connection window.
750ae3fccdSDmitri Tikhonov         */
760ae3fccdSDmitri Tikhonov    }
7750aadb33SDmitri Tikhonov
7850aadb33SDmitri Tikhonov    if (new_max_window > fc->sf_max_recv_win)
7950aadb33SDmitri Tikhonov    {
8050aadb33SDmitri Tikhonov        LSQ_DEBUG("max window increase %u -> %u",
8150aadb33SDmitri Tikhonov            fc->sf_max_recv_win, new_max_window);
8250aadb33SDmitri Tikhonov        EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID,
8350aadb33SDmitri Tikhonov            "max SFCW increase %u -> %u", fc->sf_max_recv_win,
8450aadb33SDmitri Tikhonov                                                            new_max_window);
8550aadb33SDmitri Tikhonov        fc->sf_max_recv_win = new_max_window;
8650aadb33SDmitri Tikhonov    }
8750aadb33SDmitri Tikhonov    else
8850aadb33SDmitri Tikhonov        LSQ_DEBUG("max window could use an increase, but we're stuck "
8950aadb33SDmitri Tikhonov            "at %u", fc->sf_max_recv_win);
9050aadb33SDmitri Tikhonov}
9150aadb33SDmitri Tikhonov
9250aadb33SDmitri Tikhonov
9350aadb33SDmitri Tikhonovint
9450aadb33SDmitri Tikhonovlsquic_sfcw_fc_offsets_changed (struct lsquic_sfcw *fc)
9550aadb33SDmitri Tikhonov{
9650aadb33SDmitri Tikhonov    lsquic_time_t since_last_update, srtt, now;
9750aadb33SDmitri Tikhonov
9850aadb33SDmitri Tikhonov    if (fc->sf_recv_off - fc->sf_read_off >= fc->sf_max_recv_win / 2)
9950aadb33SDmitri Tikhonov    {
10050aadb33SDmitri Tikhonov        LSQ_DEBUG("recv_off has not changed, still at %"PRIu64,
10150aadb33SDmitri Tikhonov                                                            fc->sf_recv_off);
10250aadb33SDmitri Tikhonov        return 0;
10350aadb33SDmitri Tikhonov    }
10450aadb33SDmitri Tikhonov
10550aadb33SDmitri Tikhonov    now = lsquic_time_now();
10650aadb33SDmitri Tikhonov    since_last_update = now - fc->sf_last_updated;
10750aadb33SDmitri Tikhonov    fc->sf_last_updated = now;
10850aadb33SDmitri Tikhonov
10950aadb33SDmitri Tikhonov    srtt = lsquic_rtt_stats_get_srtt(&fc->sf_conn_pub->rtt_stats);
11050aadb33SDmitri Tikhonov    if (since_last_update < srtt * 2)
11150aadb33SDmitri Tikhonov        sfcw_maybe_increase_max_window(fc);
11250aadb33SDmitri Tikhonov
11350aadb33SDmitri Tikhonov    fc->sf_recv_off = fc->sf_read_off + fc->sf_max_recv_win;
11450aadb33SDmitri Tikhonov    LSQ_DEBUG("recv_off changed: read_off: %"PRIu64"; "
11550aadb33SDmitri Tikhonov        "recv_off: %"PRIu64, fc->sf_read_off, fc->sf_recv_off);
11650aadb33SDmitri Tikhonov    return 1;
11750aadb33SDmitri Tikhonov}
11850aadb33SDmitri Tikhonov
11950aadb33SDmitri Tikhonov
12050aadb33SDmitri Tikhonovint
12150aadb33SDmitri Tikhonovlsquic_sfcw_set_max_recv_off (struct lsquic_sfcw *fc, uint64_t max_recv_off)
12250aadb33SDmitri Tikhonov{
12350aadb33SDmitri Tikhonov    if (max_recv_off <= fc->sf_recv_off)
12450aadb33SDmitri Tikhonov    {
12550aadb33SDmitri Tikhonov        if (!fc->sf_cfcw || lsquic_cfcw_incr_max_recv_off(fc->sf_cfcw,
12650aadb33SDmitri Tikhonov                                        max_recv_off - fc->sf_max_recv_off))
12750aadb33SDmitri Tikhonov        {
12850aadb33SDmitri Tikhonov            LSQ_DEBUG("max_recv_off goes from %"PRIu64" to %"PRIu64,
12950aadb33SDmitri Tikhonov                                            fc->sf_max_recv_off, max_recv_off);
13050aadb33SDmitri Tikhonov            fc->sf_max_recv_off = max_recv_off;
13150aadb33SDmitri Tikhonov            return 1;
13250aadb33SDmitri Tikhonov        }
13350aadb33SDmitri Tikhonov        else
13450aadb33SDmitri Tikhonov        {
13550aadb33SDmitri Tikhonov            /* cfcw prints its own warning */
13650aadb33SDmitri Tikhonov            return 0;
13750aadb33SDmitri Tikhonov        }
13850aadb33SDmitri Tikhonov    }
13950aadb33SDmitri Tikhonov    else
14050aadb33SDmitri Tikhonov    {
14150aadb33SDmitri Tikhonov        LSQ_WARN("flow control violation: received at offset %"PRIu64", "
14250aadb33SDmitri Tikhonov            "while flow control receive offset is %"PRIu64,
14350aadb33SDmitri Tikhonov            max_recv_off, fc->sf_recv_off);
14450aadb33SDmitri Tikhonov        return 0;
14550aadb33SDmitri Tikhonov    }
14650aadb33SDmitri Tikhonov}
14750aadb33SDmitri Tikhonov
14850aadb33SDmitri Tikhonov
14950aadb33SDmitri Tikhonovvoid
15050aadb33SDmitri Tikhonovlsquic_sfcw_set_read_off (struct lsquic_sfcw *fc, uint64_t off)
15150aadb33SDmitri Tikhonov{
15250aadb33SDmitri Tikhonov    if (fc->sf_cfcw)
15350aadb33SDmitri Tikhonov        lsquic_cfcw_incr_read_off(fc->sf_cfcw, off - fc->sf_read_off);
15450aadb33SDmitri Tikhonov    LSQ_DEBUG("read_off goes from %"PRIu64" to %"PRIu64,
15550aadb33SDmitri Tikhonov                                                fc->sf_read_off, off);
15650aadb33SDmitri Tikhonov    fc->sf_read_off = off;
15750aadb33SDmitri Tikhonov}
158