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 */
+ ullong cur; /* Nanosecond timestamp of the last credit reloading */
+ uint credit; /* Number of packets which can be emitted in a single burst */
int last_sent; /* Number of datagrams sent during last paced emission */
};
const struct quic_cc *cc)
{
pacer->cc = cc;
- pacer->next = 0;
+ pacer->cur = 0;
+ pacer->credit = cc->algo->pacing_burst(cc);
}
int quic_pacing_expired(const struct quic_pacer *pacer);
void quic_pacing_sent_done(struct quic_pacer *pacer, int sent);
+int quic_pacing_reload(struct quic_pacer *pacer);
+
#endif /* _HAPROXY_QUIC_PACING_H */
goto out;
}
- if (qcc_is_pacing_active(qcc->conn)) {
- if (!LIST_ISEMPTY(frms) && !quic_pacing_expired(&qcc->tx.pacer)) {
+ if (!LIST_ISEMPTY(frms) && qcc_is_pacing_active(qcc->conn)) {
+ if (!quic_pacing_reload(&qcc->tx.pacer)) {
if (!after_pacing)
++qcc->tx.paced_sent_ctr;
tasklet_wakeup(qcc->wait_event.tasklet, TASK_F_UEVT1);
uint quic_cc_default_pacing_inter(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);
+ return path->loss.srtt * 1000000 / (path->cwnd / path->mtu + 1) + 1;
}
/* Return the max number of datagrams which can be emitted in a burst with
/* Returns true if <pacer> timer is expired and emission can be retried. */
int quic_pacing_expired(const struct quic_pacer *pacer)
{
- return !pacer->next || pacer->next <= task_mono_time();
+ return pacer->credit;
}
/* Notify <pacer> about an emission of <sent> count of datagrams. */
void quic_pacing_sent_done(struct quic_pacer *pacer, int sent)
{
- pacer->next = task_mono_time() + pacer->cc->algo->pacing_inter(pacer->cc) * sent;
+ BUG_ON(!pacer->credit || pacer->credit < sent);
+ pacer->credit -= sent;
+
pacer->last_sent = sent;
}
+
+/* Reload <pacer> credit when a new emission sequence is initiated. A maximal
+ * value is calculated if previous emission occurred long time enough.
+ *
+ * Returns the remaining credit or 0 if emission cannot be conducted this time.
+ */
+int quic_pacing_reload(struct quic_pacer *pacer)
+{
+ const uint64_t task_now_ns = task_mono_time();
+ const uint64_t inter = pacer->cc->algo->pacing_inter(pacer->cc);
+ uint64_t inc;
+ uint credit_max;
+
+ if (task_now_ns > pacer->cur) {
+ /* Calculate number of packets which could have been emitted since last emission sequence. Result is rounded up. */
+ inc = (task_now_ns - pacer->cur + inter - 1) / inter;
+
+ credit_max = pacer->cc->algo->pacing_burst(pacer->cc);
+ pacer->credit = MIN(pacer->credit + inc, credit_max);
+
+ /* Refresh pacing reload timer. */
+ pacer->cur = task_now_ns;
+ }
+
+ return pacer->credit;
+}
}
if (pacer) {
- max_dgram = qc->path->cc.algo->pacing_burst(&qc->path->cc);
+ max_dgram = pacer->credit;
BUG_ON(max_dgram <= 0); /* pacer must specify a positive burst value. */
}