Skip to content

Commit

Permalink
WIP: Just to not lose this.
Browse files Browse the repository at this point in the history
  • Loading branch information
haproxyFred committed Aug 13, 2024
1 parent 6577cc5 commit 51100c1
Show file tree
Hide file tree
Showing 5 changed files with 305 additions and 3 deletions.
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -651,7 +651,8 @@ OPTIONS_OBJS += src/quic_rx.o src/mux_quic.o src/h3.o src/quic_tx.o \
src/quic_cc_nocc.o src/qpack-dec.o src/quic_cc.o \
src/cfgparse-quic.o src/qmux_trace.o src/qpack-enc.o \
src/qpack-tbl.o src/h3_stats.o src/quic_stats.o \
src/quic_fctl.o src/cbuf.o src/quic_rules.o
src/quic_fctl.o src/cbuf.o src/quic_rules.o \
src/quic_cc_bbr.o
endif
ifneq ($(USE_QUIC_OPENSSL_COMPAT:0=),)
Expand Down
4 changes: 3 additions & 1 deletion include/haproxy/quic_cc-t.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@

extern struct quic_cc_algo quic_cc_algo_nr;
extern struct quic_cc_algo quic_cc_algo_cubic;
extern struct quic_cc_algo quic_cc_algo_bbr;
extern struct quic_cc_algo *default_quic_cc_algo;

/* Fake algorithm with its fixed window */
Expand Down Expand Up @@ -80,14 +81,15 @@ struct quic_cc_event {
enum quic_cc_algo_type {
QUIC_CC_ALGO_TP_NEWRENO,
QUIC_CC_ALGO_TP_CUBIC,
QUIC_CC_ALGO_TP_BBR,
QUIC_CC_ALGO_TP_NOCC,
};

struct quic_cc {
/* <conn> is there only for debugging purpose. */
struct quic_conn *qc;
struct quic_cc_algo *algo;
uint32_t priv[18];
uint32_t priv[248];
};

struct quic_cc_path {
Expand Down
18 changes: 18 additions & 0 deletions include/haproxy/quic_cc_rs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/* Rate sample. */
struct quic_rs {
uint64_t delivered;
uint64_t prior_delivered;
uint32_t interval;
uint32_t prior_time;
uint32_t send_elapsed;
uint32_t ack_elapsed;
uint32_t is_app_limited;
};

/* Delivery rate sampling. */
struct quic_drs {
struct quic_rs rs;
uint64_t delivered;
uint64_t lost;
int app_limited;
}
2 changes: 1 addition & 1 deletion src/quic_cc.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

#include <haproxy/quic_cc.h>

struct quic_cc_algo *default_quic_cc_algo = &quic_cc_algo_cubic;
struct quic_cc_algo *default_quic_cc_algo = &quic_cc_algo_bbr;

/*
* Initialize <cc> congestion control with <algo> as algorithm depending on <ipv4>
Expand Down
281 changes: 281 additions & 0 deletions src/quic_cc_bbr.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,281 @@
#include <inttypes.h>

#include <haproxy/quic_cc.h>
#include <haproxy/ticks.h>
#include <haproxy/window_filter.h>

/* XXX TO BE REMOVED */
#define true 1
#define false 0

#define BBR_STARTUP_PACING_GAIN 277 /* percent: 4 * ln(2)=2.77 */
#define BBR_STARTUP_CWND_GAIN 200 /* percent */

/* BBRLossThresh (2%) */
#define BBR_LOSS_THRESH_MULT 2
#define BBR_LOSS_THRESH_DIVI 100
/* BBRBeta (0.7) */
#define BBR_BETA_MULT 7
#define BBR_BETA_DIVI 10
/* BBRHeadroom (0.15) */
#define BBR_HEADROOM_MULT 15
#define BBR_HEADROOM_DIVI 100

#define BBR_MAX_BW_FILTERLEN 2
#define BBR_EXTRA_ACKED_FILTERLEN 10

#define BBR_MIN_RTT_FILTERLEN 10000 /* ms */
#define BBR_PROBE_RTT_CWND_GAIN 50 /* 50% */
#define BBR_PROBE_RTT_DURATION 200 /* ms */
#define BBR_PROBE_RTT_INTERVAL 5000 /* ms */

/* 4.1.1: State Transition Diagram */
/* BBR state */
enum bbr_state {
BBR_ST_STARTUP,
BBR_ST_DRAIN,
BBR_ST_PROBE_BW_DOWN,
BBR_ST_PROBE_BW_CRUISE,
BBR_ST_PROBE_BW_REFILL,
BBR_ST_PROBE_BW_UP,
BBR_ST_PROBE_RTT,
};

struct bbr {
/* 2.4 Output Control Parameters */
uint64_t pacing_rate;
uint64_t send_quantum;
/* 2.5 Pacing State and Parameters */
uint64_t pacing_gain;
//uint32_t next_departure_time; /* XXX check this XXX */
/* 2.6. cwnd State and Parameters */
uint64_t cwnd_gain;
/* 2.7 General Algorithm State */
enum bbr_state state;
uint64_t round_count;
int round_start; /* boolean */
uint64_t next_round_delivered;
int idle_restart; /* boolean */
/* 2.9.1 Data Rate Network Path Model Parameters */
uint64_t max_bw;
uint64_t bw_lo;
uint64_t bw;
uint64_t prior_cwnd;
/* 2.9.2 Data Volume Network Path Model Parameters */
uint32_t min_rtt;
uint64_t extra_acked;
uint64_t offload_budget;
uint64_t max_inflight;
uint64_t inflight_hi;
uint64_t inflight_lo;
/* 2.10 State for Responding to Congestion */
uint64_t bw_latest;
uint64_t loss_in_round;
uint64_t inflight_latest;
/* 2.11 Estimating BBR.max_bw */
struct window_filter max_bw_filter;
uint64_t cycle_count;
/* 2.12 Estimating BBR.extra_acked */
uint32_t extra_acked_interval_start;
uint64_t extra_acked_delivered;
struct window_filter extra_acked_filter;
/* 2.13 Startup Parameters and State */
int full_bw_reached; /* boolean */
int full_bw_now; /* boolean */
uint64_t full_bw;
int full_bw_count;
/* 2.14 ProbeRTT and min_rtt Parameters and State */
/* 2.14.1 Parameters for Estimating BBR.min_rtt */
uint32_t min_rtt_stamp;
/* 2.14.2 Parameters for Scheduling ProbeRTT */
uint32_t probe_rtt_min_delay; /* ms */
uint32_t probe_rtt_min_stamp; /* ms */
uint32_t probe_rtt_done_stamp;
int probe_rtt_round_done; /* boolean */
int probe_rtt_expired; /* boolean */
};

static void bbr_reset_congestion_signals(struct bbr *bbr)
{
bbr->loss_in_round = 0;
bbr->bw_latest = 0;
bbr->inflight_latest = 0;
}

static void bbr_reset_lower_bounds(struct bbr *bbr)
{
bbr->bw_lo = UINT64_MAX;
bbr->inflight_lo = UINT64_MAX;
}

static void bbr_init_round_counting(struct bbr *bbr)
{
bbr->next_round_delivered = 0;
bbr->round_start = false;
bbr->round_count = 0;
}

static void bbr_reset_full_bw(struct bbr *bbr)
{
bbr->full_bw = 0;
bbr->full_bw_count = 0;
bbr->full_bw_now = false;
}

static void bbr_init_pacing_rate(struct bbr *bbr)
{
/* XXX Not clear at this time XXX */
}

static void bbr_enter_startup(struct bbr *bbr)
{
bbr->state = BBR_ST_STARTUP;
bbr->pacing_gain = BBR_STARTUP_PACING_GAIN;
bbr->cwnd_gain = BBR_STARTUP_CWND_GAIN;
}

static int quic_cc_bbr_init(struct quic_cc *cc)
{
struct bbr *bbr = quic_cc_priv(cc);

window_filter_init(&bbr->max_bw_filter, BBR_MAX_BW_FILTERLEN);
window_filter_init(&bbr->extra_acked_filter, BBR_EXTRA_ACKED_FILTERLEN);
/* InitWindowedMaxFilter() */
bbr->min_rtt = 1; /* ms */ /* XXX check this XXX */
bbr->min_rtt_stamp = now_ms;
bbr->probe_rtt_done_stamp = TICK_ETERNITY; /* XXX check this XXX */
bbr->probe_rtt_round_done = false;
bbr->prior_cwnd = 0;
bbr->idle_restart = false;
bbr->extra_acked_interval_start = now_ms;
bbr->extra_acked_delivered = 0;
bbr->full_bw_reached = false;

bbr_reset_congestion_signals(bbr);
bbr_reset_lower_bounds(bbr);
bbr_init_round_counting(bbr);
bbr_reset_full_bw(bbr);
bbr_init_pacing_rate(bbr);
bbr_enter_startup(bbr);

/* Not in RFC */
bbr->send_quantum = 0; /* XXX check this */
bbr->max_bw = 0;
bbr->bw = 0;
bbr->extra_acked = 0;
bbr->offload_budget = 0;
bbr->max_inflight = 0;
bbr->inflight_hi = UINT64_MAX;
bbr->cycle_count = 0;
bbr->probe_rtt_min_delay = TICK_ETERNITY;
bbr->probe_rtt_min_stamp = now_ms;
bbr->probe_rtt_expired = false;

return 1;
}

static void bbr_handle_restart_from_idle(struct bbr *bbr)
{
}

static void bbr_on_transmit(struct bbr *bbr)
{
bbr_handle_restart_from_idle(bbr);
}

static bbr_check_startup_high_loss()
{
}

static void bbr_check_startup_done(struct bbr *bbr)
{
bbr_check_startup_high_loss();
if (bbr->state == BBR_ST_STARTUP and bbr->full_bw_reached)
bbr_enter_drain();
}

static void bbr_update_model_and_state()
{
bbr_update_latest_delivery_signals();
bbr_update_congestion_signals();
bbr_update_ack_aggregation();
bbr_check_full_bw_reached();
bbr_check_startup_done();
bbr_check_drain_done();
bbr_update_probe_bw_cycle_phase();
bbr_update_min_rtt();
bbr_check_probe_rtt();
bbr_advance_latest_delivery_signals();
bbr_bound_bw_for_model();
}

static void bbr_update_control_parameters()
{
bbr_set_pacing_rate();
bbr_set_send_quantum();
bbr_set_cwnd();
}

static void bbr_update_on_ack()
{
bbr_update_model_and_state();
bbr_update_control_parameters();
}

static void bbr_note_loss(struct bbr *bbr)
{
if (!bbr->loss_in_round) /* first loss in this round trip? */
bbr->loss_round_delivered = C.delivered;
bbr->loss_in_round = 1;
}

/* At what prefix of packet did losses exceed BBRLossThresh? */
static uint64_t bbr_inflight_hi_from_lost_packet(struct quic *rs, packet)
{
size = packet.size;
/* What was in flight before this packet? */
inflight_prev = rs->tx_in_flight - size;
/* What was lost before this packet? */
lost_prev = rs->lost - size;
lost_prefix = (BBR_LOSS_THRESH * inflight_prev - lost_prev) /
(1 - BBR_LOSS_THRESH);
/* At what inflight value did losses cross BBRLossThresh? */
inflight = inflight_prev + lost_prefix;

return inflight;
}

static bbr_handle_lost_packet(packet)
{
struct quic_rs *rs;

bbr_note_loss();
if (!bbr->bw_probe_samples)
return /* not a packet sent while probing bandwidth */

rs->tx_in_flight = packet.tx_in_flight; /* inflight at transmit */
rs->lost = C.lost - packet.lost; /* data lost since transmit */
rs->is_app_limited = packet.is_app_limited;
if (is_flight_too_high(rs)) {
rs->tx_in_flight = bbr_inflight_hi_from_lost_packet(rs, packet);
bbr_handle_inflight_too_high(rs)
}
}

static bbr_update_on_loss(packet)
{
bbr_handle_lost_packet(packet);
}

struct quic_cc_algo quic_cc_algo_bbr = {
.type = QUIC_CC_ALGO_TP_BBR,
.init = quic_cc_bbr_init,
};

void quic_cc_bbr_check(void)
{
struct quic_cc *cc;
BUG_ON_HOT(sizeof(struct bbr) > sizeof(cc->priv));
}

INITCALL0(STG_REGISTER, quic_cc_bbr_check);

0 comments on commit 51100c1

Please sign in to comment.