Skip to content

Commit d75477d

Browse files
committed
WIP: improve BBR throughput on links with very low latency
1 parent 7262433 commit d75477d

File tree

8 files changed

+62
-51
lines changed

8 files changed

+62
-51
lines changed

include/haproxy/quic_cc-t.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ struct quic_cc {
9191
/* <conn> is there only for debugging purpose. */
9292
struct quic_conn *qc;
9393
struct quic_cc_algo *algo;
94-
uint32_t priv[158];
94+
uint32_t priv[164];
9595
};
9696

9797
struct quic_cc_path {

include/haproxy/quic_cc_drs.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ struct quic_cc_rs {
1010
uint64_t lost;
1111
uint64_t prior_lost;
1212
int64_t last_end_seq;
13-
uint32_t interval;
14-
uint32_t prior_time;
15-
uint32_t send_elapsed;
16-
uint32_t ack_elapsed;
13+
uint64_t interval_ns;
14+
uint64_t prior_time_ns;
15+
uint64_t send_elapsed_ns;
16+
uint64_t ack_elapsed_ns;
1717
uint32_t is_app_limited;
1818
};
1919

@@ -26,8 +26,8 @@ struct quic_cc_drs {
2626
uint64_t delivered;
2727
uint64_t lost;
2828
int64_t last_seq;
29-
uint32_t delivered_time;
30-
uint32_t first_sent_time;
29+
uint64_t delivered_time_ns;
30+
uint64_t first_sent_time_ns;
3131
int is_cwnd_limited; /* boolean */
3232
int app_limited; /* boolean */
3333
};
@@ -36,6 +36,6 @@ void quic_cc_drs_init(struct quic_cc_drs *drs);
3636
void quic_cc_drs_on_pkt_sent(struct quic_cc_path *path,
3737
struct quic_tx_packet *pkt, struct quic_cc_drs *drs);
3838
void quic_cc_drs_update_rate_sample(struct quic_cc_drs *drs,
39-
struct quic_tx_packet *pkt);
39+
struct quic_tx_packet *pkt, uint64_t time_ns);
4040
void quic_cc_drs_on_ack_recv(struct quic_cc_drs *drs, struct quic_cc_path *path,
4141
uint64_t pkt_delivered);

include/haproxy/quic_tx-t.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ struct quic_tx_packet {
5151
/* The list of frames of this packet. */
5252
struct list frms;
5353
/* The time this packet was sent (ms). */
54-
unsigned int time_sent;
54+
unsigned int time_sent_ms;
55+
uint64_t time_sent_ns;
5556
/* Packet number spakce. */
5657
struct quic_pktns *pktns;
5758
/* Flags. */
@@ -70,8 +71,8 @@ struct quic_tx_packet {
7071
uint64_t tx_in_flight;
7172
uint64_t lost;
7273
int64_t end_seq;
73-
uint32_t delivered_time;
74-
uint32_t first_sent_time;
74+
uint64_t delivered_time_ns;
75+
uint64_t first_sent_time_ns;
7576
int is_app_limited;
7677
} rs;
7778
unsigned char type;

src/quic_cc_drs.c

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,21 @@
44
#include <haproxy/quic_cc-t.h>
55
#include <haproxy/quic_cc_drs.h>
66
#include <haproxy/quic_tx-t.h>
7+
#include <haproxy/task.h>
78
#include <haproxy/ticks.h>
89
#include <haproxy/window_filter.h>
910

1011
static void quic_cc_rs_init(struct quic_cc_rs *rs)
1112
{
12-
rs->interval = UINT32_MAX;
13+
rs->interval_ns = UINT64_MAX;
1314
rs->delivered = 0;
1415
rs->prior_delivered = 0;
15-
rs->prior_time = TICK_ETERNITY;
16+
rs->prior_time_ns = 0;
1617
rs->tx_in_flight = 0;
1718
rs->lost = 0;
1819
rs->prior_lost = 0;
19-
rs->send_elapsed = 0;
20-
rs->ack_elapsed = 0;
20+
rs->send_elapsed_ns = 0;
21+
rs->ack_elapsed_ns = 0;
2122
rs->last_end_seq = -1;
2223
rs->is_app_limited = 0;
2324
}
@@ -31,8 +32,8 @@ void quic_cc_drs_init(struct quic_cc_drs *drs)
3132
drs->delivered = 0;
3233
drs->lost = 0;
3334
drs->last_seq = -1;
34-
drs->delivered_time = TICK_ETERNITY;
35-
drs->first_sent_time = TICK_ETERNITY;
35+
drs->delivered_time_ns = 0;
36+
drs->first_sent_time_ns = 0;
3637
drs->app_limited = 0;
3738
drs->is_cwnd_limited = 0;
3839
}
@@ -44,12 +45,12 @@ void quic_cc_drs_on_pkt_sent(struct quic_cc_path *path,
4445
struct quic_tx_packet *pkt, struct quic_cc_drs *drs)
4546
{
4647
if (!path->in_flight)
47-
drs->first_sent_time = drs->delivered_time = pkt->time_sent;
48+
drs->first_sent_time_ns = drs->delivered_time_ns = pkt->time_sent_ns;
4849

49-
pkt->rs.first_sent_time = drs->first_sent_time;
50-
pkt->rs.delivered_time = drs->delivered_time;
51-
pkt->rs.delivered = drs->delivered;
52-
pkt->rs.is_app_limited = drs->app_limited != 0;
50+
pkt->rs.first_sent_time_ns = drs->first_sent_time_ns;
51+
pkt->rs.delivered_time_ns = drs->delivered_time_ns;
52+
pkt->rs.delivered = drs->delivered;
53+
pkt->rs.is_app_limited = drs->app_limited != 0;
5354

5455
pkt->rs.tx_in_flight = path->in_flight + pkt->len;
5556
pkt->rs.lost = drs->lost;
@@ -62,8 +63,8 @@ void quic_cc_drs_on_pkt_sent(struct quic_cc_path *path,
6263
static inline int quic_cc_drs_is_newest_packet(struct quic_cc_drs *drs,
6364
struct quic_tx_packet *pkt)
6465
{
65-
return tick_is_lt(drs->first_sent_time, pkt->time_sent) ||
66-
(pkt->time_sent == drs->first_sent_time &&
66+
return drs->first_sent_time_ns < pkt->time_sent_ns ||
67+
(pkt->time_sent_ns == drs->first_sent_time_ns &&
6768
pkt->rs.end_seq > drs->rs.last_end_seq);
6869
}
6970

@@ -83,32 +84,32 @@ static inline int quic_cc_drs_is_newest_packet(struct quic_cc_drs *drs,
8384
* RFC UpdateRateSample() called from first part of GenerateRateSample().
8485
*/
8586
void quic_cc_drs_update_rate_sample(struct quic_cc_drs *drs,
86-
struct quic_tx_packet *pkt)
87+
struct quic_tx_packet *pkt, uint64_t time_ns)
8788
{
8889
struct quic_cc_rs *rs = &drs->rs;
8990

90-
if (!tick_isset(pkt->rs.delivered_time))
91+
if (!pkt->rs.delivered_time_ns)
9192
return;
9293

9394
drs->delivered += pkt->len;
94-
drs->delivered_time = now_ms;
95+
drs->delivered_time_ns = time_ns;
9596
/* Update info using the newest packet. */
96-
if (tick_isset(rs->prior_time) && !quic_cc_drs_is_newest_packet(drs, pkt))
97+
if (rs->prior_time_ns && !quic_cc_drs_is_newest_packet(drs, pkt))
9798
return;
9899

99100
rs->prior_delivered = pkt->rs.delivered;
100-
rs->prior_time = pkt->rs.delivered_time;
101+
rs->prior_time_ns = pkt->rs.delivered_time_ns;
101102
rs->is_app_limited = pkt->rs.is_app_limited;
102-
rs->send_elapsed = pkt->time_sent - pkt->rs.first_sent_time;
103-
rs->ack_elapsed = drs->delivered_time - pkt->rs.delivered_time;
103+
rs->send_elapsed_ns = pkt->time_sent_ns - pkt->rs.first_sent_time_ns;
104+
rs->ack_elapsed_ns = drs->delivered_time_ns - pkt->rs.delivered_time_ns;
104105
rs->tx_in_flight = pkt->rs.tx_in_flight;
105106
rs->prior_lost = pkt->rs.lost;
106107
rs->last_end_seq = pkt->rs.end_seq;
107-
drs->first_sent_time = pkt->time_sent;
108+
drs->first_sent_time_ns = pkt->time_sent_ns;
108109
/* Mark the packet as delivered once it's SACKed to
109110
* avoid being used again when it's cumulatively acked.
110111
*/
111-
pkt->rs.delivered_time = TICK_ETERNITY;
112+
pkt->rs.delivered_time_ns = 0;
112113
}
113114

114115
/* RFC https://datatracker.ietf.org/doc/draft-ietf-ccwg-bbr/
@@ -131,25 +132,25 @@ void quic_cc_drs_on_ack_recv(struct quic_cc_drs *drs, struct quic_cc_path *path,
131132
++drs->round_count;
132133
}
133134

134-
if (!tick_isset(rs->prior_time))
135+
if (!rs->prior_time_ns)
135136
return;
136137

137-
rs->interval = MAX(rs->send_elapsed, rs->ack_elapsed);
138+
rs->interval_ns = MAX(rs->send_elapsed_ns, rs->ack_elapsed_ns);
138139

139140
BUG_ON(drs->delivered <= rs->prior_delivered);
140141
rs->delivered = drs->delivered - rs->prior_delivered;
141142
BUG_ON(drs->lost < rs->prior_lost);
142143
rs->lost = drs->lost - rs->prior_lost;
143144

144-
if (rs->interval < path->loss.rtt_min) {
145-
rs->interval = UINT32_MAX;
145+
if (rs->interval_ns < path->loss.rtt_min * 1000000) {
146+
rs->interval_ns = UINT64_MAX;
146147
return;
147148
}
148149

149-
if (!rs->interval)
150+
if (!rs->interval_ns)
150151
return;
151152

152-
rate = rs->delivered * 1000 / rs->interval;
153+
rate = rs->delivered * 1000000000 / rs->interval_ns;
153154
if (rate >= wf_get_max(&drs->wf) || !drs->app_limited)
154155
path->delivery_rate = wf_max_update(&drs->wf, rate, drs->round_count);
155156
}

src/quic_conn.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1247,6 +1247,7 @@ struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4,
12471247
}
12481248
qc->wait_event.tasklet->process = quic_conn_io_cb;
12491249
qc->wait_event.tasklet->context = qc;
1250+
qc->wait_event.tasklet->state |= TASK_F_WANTS_TIME;
12501251
qc->wait_event.events = 0;
12511252
qc->subs = NULL;
12521253

src/quic_loss.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ void qc_packet_loss_lookup(struct quic_pktns *pktns, struct quic_conn *qc,
206206
if ((int64_t)pkt->pn_node.key > largest_acked_pn)
207207
break;
208208

209-
time_sent = pkt->time_sent;
209+
time_sent = pkt->time_sent_ms;
210210
loss_time_limit = tick_add(time_sent, loss_delay);
211211

212212
reordered = (int64_t)largest_acked_pn >= pkt->pn_node.key + pktthresh;
@@ -290,12 +290,12 @@ int qc_release_lost_pkts(struct quic_conn *qc, struct quic_pktns *pktns,
290290
struct quic_cc_event ev = { };
291291

292292
ev.type = QUIC_CC_EVT_LOSS;
293-
ev.loss.time_sent = newest_lost->time_sent;
293+
ev.loss.time_sent = newest_lost->time_sent_ms;
294294
ev.loss.count = tot_lost;
295295

296296
quic_cc_event(cc, &ev);
297297
if (cc->algo->congestion_event)
298-
cc->algo->congestion_event(cc, newest_lost->time_sent);
298+
cc->algo->congestion_event(cc, newest_lost->time_sent_ms);
299299
}
300300

301301
/* If an RTT have been already sampled, <rtt_min> has been set.
@@ -304,7 +304,7 @@ int qc_release_lost_pkts(struct quic_conn *qc, struct quic_pktns *pktns,
304304
* slow start state.
305305
*/
306306
if (qc->path->loss.rtt_min && newest_lost != oldest_lost) {
307-
unsigned int period = newest_lost->time_sent - oldest_lost->time_sent;
307+
unsigned int period = newest_lost->time_sent_ms - oldest_lost->time_sent_ms;
308308

309309
if (quic_loss_persistent_congestion(&qc->path->loss, period,
310310
now_ms, qc->max_ack_delay) &&

src/quic_rx.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -432,9 +432,13 @@ static void qc_notify_cc_of_newly_acked_pkts(struct quic_conn *qc,
432432
struct quic_cc_drs *drs =
433433
p->cc.algo->get_drs ? p->cc.algo->get_drs(&p->cc) : NULL;
434434
unsigned int bytes_delivered = 0, pkt_delivered = 0;
435+
uint64_t time_ns;
435436

436437
TRACE_ENTER(QUIC_EV_CONN_PRSAFRM, qc);
437438

439+
if (drs)
440+
time_ns = task_mono_time();
441+
438442
list_for_each_entry_safe(pkt, tmp, newly_acked_pkts, list) {
439443
pkt->pktns->tx.in_flight -= pkt->in_flight_len;
440444
p->prep_in_flight -= pkt->in_flight_len;
@@ -450,12 +454,12 @@ static void qc_notify_cc_of_newly_acked_pkts(struct quic_conn *qc,
450454
bytes_delivered += pkt->len;
451455
pkt_delivered = pkt->rs.delivered;
452456
ev.ack.acked = pkt->in_flight_len;
453-
ev.ack.time_sent = pkt->time_sent;
457+
ev.ack.time_sent = pkt->time_sent_ms;
454458
ev.ack.pn = pkt->pn_node.key;
455459
/* Note that this event is not emitted for BBR. */
456460
quic_cc_event(&p->cc, &ev);
457461
if (drs && (pkt->flags & QUIC_FL_TX_PACKET_ACK_ELICITING))
458-
quic_cc_drs_update_rate_sample(drs, pkt);
462+
quic_cc_drs_update_rate_sample(drs, pkt, time_ns);
459463
LIST_DEL_INIT(&pkt->list);
460464
quic_tx_packet_refdec(pkt);
461465
}
@@ -523,7 +527,7 @@ static int qc_parse_ack_frm(struct quic_conn *qc,
523527
}
524528
else {
525529
time_sent = eb64_entry(largest_node,
526-
struct quic_tx_packet, pn_node)->time_sent;
530+
struct quic_tx_packet, pn_node)->time_sent_ms;
527531
new_largest_acked_pn = 1;
528532
}
529533
}

src/quic_tx.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,8 @@ static int qc_send_ppkts(struct buffer *buf, struct ssl_sock_ctx *ctx)
295295
struct buffer tmpbuf = { };
296296
struct quic_tx_packet *first_pkt, *pkt, *next_pkt;
297297
uint16_t dglen, gso = 0, gso_fallback = 0;
298-
unsigned int time_sent;
298+
uint64_t time_sent_ns;
299+
unsigned int time_sent_ms;
299300

300301
pos = (unsigned char *)b_head(buf);
301302
dglen = read_u16(pos);
@@ -360,7 +361,8 @@ static int qc_send_ppkts(struct buffer *buf, struct ssl_sock_ctx *ctx)
360361

361362
b_del(buf, dglen + QUIC_DGRAM_HEADLEN);
362363
qc->bytes.tx += tmpbuf.data;
363-
time_sent = now_ms;
364+
time_sent_ms = now_ms;
365+
time_sent_ns = task_mono_time();
364366

365367
for (pkt = first_pkt; pkt; pkt = next_pkt) {
366368
struct quic_cc *cc = &qc->path->cc;
@@ -391,9 +393,10 @@ static int qc_send_ppkts(struct buffer *buf, struct ssl_sock_ctx *ctx)
391393

392394
qc->cntrs.sent_pkt++;
393395

394-
pkt->time_sent = time_sent;
396+
pkt->time_sent_ns = time_sent_ns;
397+
pkt->time_sent_ms = time_sent_ms;
395398
if (pkt->flags & QUIC_FL_TX_PACKET_ACK_ELICITING) {
396-
pkt->pktns->tx.time_of_last_eliciting = time_sent;
399+
pkt->pktns->tx.time_of_last_eliciting = time_sent_ms;
397400
qc->path->ifae_pkts++;
398401
if (qc->flags & QUIC_FL_CONN_IDLE_TIMER_RESTARTED_AFTER_READ)
399402
qc_idle_timer_rearm(qc, 0, 0);
@@ -2202,7 +2205,8 @@ static inline void quic_tx_packet_init(struct quic_tx_packet *pkt, int type)
22022205
pkt->in_flight_len = 0;
22032206
pkt->pn_node.key = (uint64_t)-1;
22042207
LIST_INIT(&pkt->frms);
2205-
pkt->time_sent = TICK_ETERNITY;
2208+
pkt->time_sent_ns = 0;
2209+
pkt->time_sent_ms = TICK_ETERNITY;
22062210
pkt->next = NULL;
22072211
pkt->prev = NULL;
22082212
pkt->largest_acked_pn = -1;

0 commit comments

Comments
 (0)