diff --git a/include/haproxy/quic_cc-t.h b/include/haproxy/quic_cc-t.h index b4e72e78d..d06b22116 100644 --- a/include/haproxy/quic_cc-t.h +++ b/include/haproxy/quic_cc-t.h @@ -123,6 +123,9 @@ struct quic_cc_algo { void (*state_trace)(struct buffer *buf, const struct quic_cc *cc); void (*state_cli)(struct buffer *buf, const struct quic_cc_path *path); void (*hystart_start_round)(struct quic_cc *cc, uint64_t pn); + + /* Defined only if pacing is used. */ + uint (*pacing_rate)(const struct quic_cc *cc); }; #endif /* USE_QUIC */ diff --git a/include/haproxy/quic_cc.h b/include/haproxy/quic_cc.h index 269a93101..b9ae6ccd3 100644 --- a/include/haproxy/quic_cc.h +++ b/include/haproxy/quic_cc.h @@ -37,6 +37,9 @@ void quic_cc_init(struct quic_cc *cc, struct quic_cc_algo *algo, struct quic_con void quic_cc_event(struct quic_cc *cc, struct quic_cc_event *ev); void quic_cc_state_trace(struct buffer *buf, const struct quic_cc *cc); +/* Pacing callbacks */ +uint quic_cc_default_pacing_rate(const struct quic_cc *cc); + static inline const char *quic_cc_state_str(enum quic_cc_algo_state_type state) { switch (state) { @@ -107,6 +110,5 @@ static inline size_t quic_cc_path_prep_data(struct quic_cc_path *path) return path->cwnd - path->prep_in_flight; } - #endif /* USE_QUIC */ #endif /* _PROTO_QUIC_CC_H */ diff --git a/include/haproxy/quic_pacing-t.h b/include/haproxy/quic_pacing-t.h index 2315c2f65..01e3776fd 100644 --- a/include/haproxy/quic_pacing-t.h +++ b/include/haproxy/quic_pacing-t.h @@ -6,6 +6,7 @@ struct quic_pacer { const struct quic_cc *cc; /* Congestion controler algo used for this connection */ + ullong next; /* Nanosecond timestamp at which the next emission should be conducted */ }; #endif /* _HAPROXY_QUIC_PACING_T_H */ diff --git a/include/haproxy/quic_pacing.h b/include/haproxy/quic_pacing.h index 5ef11a531..f6e9228f0 100644 --- a/include/haproxy/quic_pacing.h +++ b/include/haproxy/quic_pacing.h @@ -10,6 +10,11 @@ static inline void quic_pacing_init(struct quic_pacer *pacer, const struct quic_cc *cc) { pacer->cc = cc; + pacer->next = 0; } +int quic_pacing_expired(const struct quic_pacer *pacer); + +void quic_pacing_sent_done(struct quic_pacer *pacer); + #endif /* _HAPROXY_QUIC_PACING_H */ diff --git a/src/quic_cc.c b/src/quic_cc.c index 8fd99d3c1..c09b9d890 100644 --- a/src/quic_cc.c +++ b/src/quic_cc.c @@ -47,3 +47,10 @@ void quic_cc_state_trace(struct buffer *buf, const struct quic_cc *cc) { cc->algo->state_trace(buf, cc); } + +/* Return rate in nanoseconds between each datagram emission for a smooth pacing. */ +uint quic_cc_default_pacing_rate(const struct quic_cc *cc) +{ + struct quic_cc_path *path = container_of(cc, struct quic_cc_path, cc); + return path->loss.srtt * 1000000 / (path->cwnd / path->mtu + 1); +} diff --git a/src/quic_pacing.c b/src/quic_pacing.c index faee5e81c..9afe95709 100644 --- a/src/quic_pacing.c +++ b/src/quic_pacing.c @@ -1 +1,15 @@ #include + +#include + +/* Returns true if timer is expired and emission can be retried. */ +int quic_pacing_expired(const struct quic_pacer *pacer) +{ + return !pacer->next || pacer->next <= now_mono_time(); +} + +/* Notify about an emission of one datagram. */ +void quic_pacing_sent_done(struct quic_pacer *pacer) +{ + pacer->next = now_mono_time() + pacer->cc->algo->pacing_rate(pacer->cc); +}