Skip to content

Commit 51100c1

Browse files
committed
WIP: Just to not lose this.
1 parent 6577cc5 commit 51100c1

File tree

5 files changed

+305
-3
lines changed

5 files changed

+305
-3
lines changed

Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -651,7 +651,8 @@ OPTIONS_OBJS += src/quic_rx.o src/mux_quic.o src/h3.o src/quic_tx.o \
651651
src/quic_cc_nocc.o src/qpack-dec.o src/quic_cc.o \
652652
src/cfgparse-quic.o src/qmux_trace.o src/qpack-enc.o \
653653
src/qpack-tbl.o src/h3_stats.o src/quic_stats.o \
654-
src/quic_fctl.o src/cbuf.o src/quic_rules.o
654+
src/quic_fctl.o src/cbuf.o src/quic_rules.o \
655+
src/quic_cc_bbr.o
655656
endif
656657
657658
ifneq ($(USE_QUIC_OPENSSL_COMPAT:0=),)

include/haproxy/quic_cc-t.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636

3737
extern struct quic_cc_algo quic_cc_algo_nr;
3838
extern struct quic_cc_algo quic_cc_algo_cubic;
39+
extern struct quic_cc_algo quic_cc_algo_bbr;
3940
extern struct quic_cc_algo *default_quic_cc_algo;
4041

4142
/* Fake algorithm with its fixed window */
@@ -80,14 +81,15 @@ struct quic_cc_event {
8081
enum quic_cc_algo_type {
8182
QUIC_CC_ALGO_TP_NEWRENO,
8283
QUIC_CC_ALGO_TP_CUBIC,
84+
QUIC_CC_ALGO_TP_BBR,
8385
QUIC_CC_ALGO_TP_NOCC,
8486
};
8587

8688
struct quic_cc {
8789
/* <conn> is there only for debugging purpose. */
8890
struct quic_conn *qc;
8991
struct quic_cc_algo *algo;
90-
uint32_t priv[18];
92+
uint32_t priv[248];
9193
};
9294

9395
struct quic_cc_path {

include/haproxy/quic_cc_rs.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/* Rate sample. */
2+
struct quic_rs {
3+
uint64_t delivered;
4+
uint64_t prior_delivered;
5+
uint32_t interval;
6+
uint32_t prior_time;
7+
uint32_t send_elapsed;
8+
uint32_t ack_elapsed;
9+
uint32_t is_app_limited;
10+
};
11+
12+
/* Delivery rate sampling. */
13+
struct quic_drs {
14+
struct quic_rs rs;
15+
uint64_t delivered;
16+
uint64_t lost;
17+
int app_limited;
18+
}

src/quic_cc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
#include <haproxy/quic_cc.h>
2424

25-
struct quic_cc_algo *default_quic_cc_algo = &quic_cc_algo_cubic;
25+
struct quic_cc_algo *default_quic_cc_algo = &quic_cc_algo_bbr;
2626

2727
/*
2828
* Initialize <cc> congestion control with <algo> as algorithm depending on <ipv4>

src/quic_cc_bbr.c

Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
1+
#include <inttypes.h>
2+
3+
#include <haproxy/quic_cc.h>
4+
#include <haproxy/ticks.h>
5+
#include <haproxy/window_filter.h>
6+
7+
/* XXX TO BE REMOVED */
8+
#define true 1
9+
#define false 0
10+
11+
#define BBR_STARTUP_PACING_GAIN 277 /* percent: 4 * ln(2)=2.77 */
12+
#define BBR_STARTUP_CWND_GAIN 200 /* percent */
13+
14+
/* BBRLossThresh (2%) */
15+
#define BBR_LOSS_THRESH_MULT 2
16+
#define BBR_LOSS_THRESH_DIVI 100
17+
/* BBRBeta (0.7) */
18+
#define BBR_BETA_MULT 7
19+
#define BBR_BETA_DIVI 10
20+
/* BBRHeadroom (0.15) */
21+
#define BBR_HEADROOM_MULT 15
22+
#define BBR_HEADROOM_DIVI 100
23+
24+
#define BBR_MAX_BW_FILTERLEN 2
25+
#define BBR_EXTRA_ACKED_FILTERLEN 10
26+
27+
#define BBR_MIN_RTT_FILTERLEN 10000 /* ms */
28+
#define BBR_PROBE_RTT_CWND_GAIN 50 /* 50% */
29+
#define BBR_PROBE_RTT_DURATION 200 /* ms */
30+
#define BBR_PROBE_RTT_INTERVAL 5000 /* ms */
31+
32+
/* 4.1.1: State Transition Diagram */
33+
/* BBR state */
34+
enum bbr_state {
35+
BBR_ST_STARTUP,
36+
BBR_ST_DRAIN,
37+
BBR_ST_PROBE_BW_DOWN,
38+
BBR_ST_PROBE_BW_CRUISE,
39+
BBR_ST_PROBE_BW_REFILL,
40+
BBR_ST_PROBE_BW_UP,
41+
BBR_ST_PROBE_RTT,
42+
};
43+
44+
struct bbr {
45+
/* 2.4 Output Control Parameters */
46+
uint64_t pacing_rate;
47+
uint64_t send_quantum;
48+
/* 2.5 Pacing State and Parameters */
49+
uint64_t pacing_gain;
50+
//uint32_t next_departure_time; /* XXX check this XXX */
51+
/* 2.6. cwnd State and Parameters */
52+
uint64_t cwnd_gain;
53+
/* 2.7 General Algorithm State */
54+
enum bbr_state state;
55+
uint64_t round_count;
56+
int round_start; /* boolean */
57+
uint64_t next_round_delivered;
58+
int idle_restart; /* boolean */
59+
/* 2.9.1 Data Rate Network Path Model Parameters */
60+
uint64_t max_bw;
61+
uint64_t bw_lo;
62+
uint64_t bw;
63+
uint64_t prior_cwnd;
64+
/* 2.9.2 Data Volume Network Path Model Parameters */
65+
uint32_t min_rtt;
66+
uint64_t extra_acked;
67+
uint64_t offload_budget;
68+
uint64_t max_inflight;
69+
uint64_t inflight_hi;
70+
uint64_t inflight_lo;
71+
/* 2.10 State for Responding to Congestion */
72+
uint64_t bw_latest;
73+
uint64_t loss_in_round;
74+
uint64_t inflight_latest;
75+
/* 2.11 Estimating BBR.max_bw */
76+
struct window_filter max_bw_filter;
77+
uint64_t cycle_count;
78+
/* 2.12 Estimating BBR.extra_acked */
79+
uint32_t extra_acked_interval_start;
80+
uint64_t extra_acked_delivered;
81+
struct window_filter extra_acked_filter;
82+
/* 2.13 Startup Parameters and State */
83+
int full_bw_reached; /* boolean */
84+
int full_bw_now; /* boolean */
85+
uint64_t full_bw;
86+
int full_bw_count;
87+
/* 2.14 ProbeRTT and min_rtt Parameters and State */
88+
/* 2.14.1 Parameters for Estimating BBR.min_rtt */
89+
uint32_t min_rtt_stamp;
90+
/* 2.14.2 Parameters for Scheduling ProbeRTT */
91+
uint32_t probe_rtt_min_delay; /* ms */
92+
uint32_t probe_rtt_min_stamp; /* ms */
93+
uint32_t probe_rtt_done_stamp;
94+
int probe_rtt_round_done; /* boolean */
95+
int probe_rtt_expired; /* boolean */
96+
};
97+
98+
static void bbr_reset_congestion_signals(struct bbr *bbr)
99+
{
100+
bbr->loss_in_round = 0;
101+
bbr->bw_latest = 0;
102+
bbr->inflight_latest = 0;
103+
}
104+
105+
static void bbr_reset_lower_bounds(struct bbr *bbr)
106+
{
107+
bbr->bw_lo = UINT64_MAX;
108+
bbr->inflight_lo = UINT64_MAX;
109+
}
110+
111+
static void bbr_init_round_counting(struct bbr *bbr)
112+
{
113+
bbr->next_round_delivered = 0;
114+
bbr->round_start = false;
115+
bbr->round_count = 0;
116+
}
117+
118+
static void bbr_reset_full_bw(struct bbr *bbr)
119+
{
120+
bbr->full_bw = 0;
121+
bbr->full_bw_count = 0;
122+
bbr->full_bw_now = false;
123+
}
124+
125+
static void bbr_init_pacing_rate(struct bbr *bbr)
126+
{
127+
/* XXX Not clear at this time XXX */
128+
}
129+
130+
static void bbr_enter_startup(struct bbr *bbr)
131+
{
132+
bbr->state = BBR_ST_STARTUP;
133+
bbr->pacing_gain = BBR_STARTUP_PACING_GAIN;
134+
bbr->cwnd_gain = BBR_STARTUP_CWND_GAIN;
135+
}
136+
137+
static int quic_cc_bbr_init(struct quic_cc *cc)
138+
{
139+
struct bbr *bbr = quic_cc_priv(cc);
140+
141+
window_filter_init(&bbr->max_bw_filter, BBR_MAX_BW_FILTERLEN);
142+
window_filter_init(&bbr->extra_acked_filter, BBR_EXTRA_ACKED_FILTERLEN);
143+
/* InitWindowedMaxFilter() */
144+
bbr->min_rtt = 1; /* ms */ /* XXX check this XXX */
145+
bbr->min_rtt_stamp = now_ms;
146+
bbr->probe_rtt_done_stamp = TICK_ETERNITY; /* XXX check this XXX */
147+
bbr->probe_rtt_round_done = false;
148+
bbr->prior_cwnd = 0;
149+
bbr->idle_restart = false;
150+
bbr->extra_acked_interval_start = now_ms;
151+
bbr->extra_acked_delivered = 0;
152+
bbr->full_bw_reached = false;
153+
154+
bbr_reset_congestion_signals(bbr);
155+
bbr_reset_lower_bounds(bbr);
156+
bbr_init_round_counting(bbr);
157+
bbr_reset_full_bw(bbr);
158+
bbr_init_pacing_rate(bbr);
159+
bbr_enter_startup(bbr);
160+
161+
/* Not in RFC */
162+
bbr->send_quantum = 0; /* XXX check this */
163+
bbr->max_bw = 0;
164+
bbr->bw = 0;
165+
bbr->extra_acked = 0;
166+
bbr->offload_budget = 0;
167+
bbr->max_inflight = 0;
168+
bbr->inflight_hi = UINT64_MAX;
169+
bbr->cycle_count = 0;
170+
bbr->probe_rtt_min_delay = TICK_ETERNITY;
171+
bbr->probe_rtt_min_stamp = now_ms;
172+
bbr->probe_rtt_expired = false;
173+
174+
return 1;
175+
}
176+
177+
static void bbr_handle_restart_from_idle(struct bbr *bbr)
178+
{
179+
}
180+
181+
static void bbr_on_transmit(struct bbr *bbr)
182+
{
183+
bbr_handle_restart_from_idle(bbr);
184+
}
185+
186+
static bbr_check_startup_high_loss()
187+
{
188+
}
189+
190+
static void bbr_check_startup_done(struct bbr *bbr)
191+
{
192+
bbr_check_startup_high_loss();
193+
if (bbr->state == BBR_ST_STARTUP and bbr->full_bw_reached)
194+
bbr_enter_drain();
195+
}
196+
197+
static void bbr_update_model_and_state()
198+
{
199+
bbr_update_latest_delivery_signals();
200+
bbr_update_congestion_signals();
201+
bbr_update_ack_aggregation();
202+
bbr_check_full_bw_reached();
203+
bbr_check_startup_done();
204+
bbr_check_drain_done();
205+
bbr_update_probe_bw_cycle_phase();
206+
bbr_update_min_rtt();
207+
bbr_check_probe_rtt();
208+
bbr_advance_latest_delivery_signals();
209+
bbr_bound_bw_for_model();
210+
}
211+
212+
static void bbr_update_control_parameters()
213+
{
214+
bbr_set_pacing_rate();
215+
bbr_set_send_quantum();
216+
bbr_set_cwnd();
217+
}
218+
219+
static void bbr_update_on_ack()
220+
{
221+
bbr_update_model_and_state();
222+
bbr_update_control_parameters();
223+
}
224+
225+
static void bbr_note_loss(struct bbr *bbr)
226+
{
227+
if (!bbr->loss_in_round) /* first loss in this round trip? */
228+
bbr->loss_round_delivered = C.delivered;
229+
bbr->loss_in_round = 1;
230+
}
231+
232+
/* At what prefix of packet did losses exceed BBRLossThresh? */
233+
static uint64_t bbr_inflight_hi_from_lost_packet(struct quic *rs, packet)
234+
{
235+
size = packet.size;
236+
/* What was in flight before this packet? */
237+
inflight_prev = rs->tx_in_flight - size;
238+
/* What was lost before this packet? */
239+
lost_prev = rs->lost - size;
240+
lost_prefix = (BBR_LOSS_THRESH * inflight_prev - lost_prev) /
241+
(1 - BBR_LOSS_THRESH);
242+
/* At what inflight value did losses cross BBRLossThresh? */
243+
inflight = inflight_prev + lost_prefix;
244+
245+
return inflight;
246+
}
247+
248+
static bbr_handle_lost_packet(packet)
249+
{
250+
struct quic_rs *rs;
251+
252+
bbr_note_loss();
253+
if (!bbr->bw_probe_samples)
254+
return /* not a packet sent while probing bandwidth */
255+
256+
rs->tx_in_flight = packet.tx_in_flight; /* inflight at transmit */
257+
rs->lost = C.lost - packet.lost; /* data lost since transmit */
258+
rs->is_app_limited = packet.is_app_limited;
259+
if (is_flight_too_high(rs)) {
260+
rs->tx_in_flight = bbr_inflight_hi_from_lost_packet(rs, packet);
261+
bbr_handle_inflight_too_high(rs)
262+
}
263+
}
264+
265+
static bbr_update_on_loss(packet)
266+
{
267+
bbr_handle_lost_packet(packet);
268+
}
269+
270+
struct quic_cc_algo quic_cc_algo_bbr = {
271+
.type = QUIC_CC_ALGO_TP_BBR,
272+
.init = quic_cc_bbr_init,
273+
};
274+
275+
void quic_cc_bbr_check(void)
276+
{
277+
struct quic_cc *cc;
278+
BUG_ON_HOT(sizeof(struct bbr) > sizeof(cc->priv));
279+
}
280+
281+
INITCALL0(STG_REGISTER, quic_cc_bbr_check);

0 commit comments

Comments
 (0)