Skip to content

Commit a2ea06a

Browse files
authored
BBR Congestion Control (holepunchto#256)
* BBR (wip) * rebase windowed rtt-min patch * fixes bugs * clean up todos, remove excess debug logging * clean up * track bw as floating point * forgot to set stream->app_limited when needed * wip: stream-bbr-state test * fix race condition in test stream closing * fix: socket only closes in debug build * fix: socket only closes in debug build * add udx_stream_get_bw() and udx_stream_get_min_rtt() user api * remove lt_bw (dead) code * fix: set first_send_ts and delivery_ts on start from idle, also renames interval_start_time and delivery_time to first_send_ts and delivery_ts for clarity * skip multicast test for now, fails on macOS15
1 parent 9e2f116 commit a2ea06a

12 files changed

Lines changed: 1193 additions & 272 deletions

File tree

CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ target_sources(
4040
src/udx_rate.c
4141
src/win_filter.h
4242
src/win_filter.c
43+
src/win_filter_f64.h
44+
src/win_filter_f64.c
45+
src/udx_bbr.c
4346
)
4447

4548
target_include_directories(

examples/udxperf.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ print_interval (udxperf_client_t *client, uint64_t bytes, uint64_t start, uint64
276276

277277
printf("[%3d] %6.4f-%6.4f sec %s %s/sec", stream->local_id, (start - client->start_time) / 1000.0, (end - client->start_time) / 1000.0, bytes_buf, bps_buf);
278278
if (is_client && extra_wanted) {
279-
printf(" cwnd=%d ssthresh=%d fast_recovery_count=%d rto_count=%d rtx_count=%d", stream->cwnd, stream->ssthresh, stream->fast_recovery_count, stream->rto_count, stream->retransmit_count);
279+
printf(" cwnd=%d ssthresh=%d pacing_rate=%u fast_recovery_count=%d rto_count=%d rtx_count=%d", stream->cwnd, stream->pacing_bytes_per_ms, stream->ssthresh, stream->fast_recovery_count, stream->rto_count, stream->retransmit_count);
280280
}
281281
printf("\n");
282282
}

include/udx.h

Lines changed: 69 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,15 @@ typedef struct {
8787
win_filter_entry_t entries[3];
8888
} win_filter_t;
8989

90+
typedef struct {
91+
uint64_t t;
92+
double v;
93+
} win_filter_f64_entry_t;
94+
95+
typedef struct {
96+
win_filter_f64_entry_t entries[3];
97+
} win_filter_f64_t;
98+
9099
typedef enum {
91100
UDX_LOOKUP_FAMILY_IPV4 = 1,
92101
UDX_LOOKUP_FAMILY_IPV6 = 2,
@@ -190,19 +199,6 @@ struct udx_socket_s {
190199
int64_t packets_dropped_by_kernel;
191200
};
192201

193-
typedef struct udx_cong_s {
194-
uint32_t K;
195-
uint32_t ack_cnt;
196-
uint32_t origin_point;
197-
uint32_t delay_min;
198-
uint32_t cnt;
199-
uint64_t last_time;
200-
uint64_t start_time;
201-
uint32_t last_max_cwnd;
202-
uint32_t last_cwnd;
203-
uint32_t tcp_cwnd;
204-
} udx_cong_t;
205-
206202
#define UDX_CA_OPEN 1
207203
#define UDX_CA_RECOVERY 2
208204
#define UDX_CA_LOSS 3
@@ -268,14 +264,14 @@ struct udx_stream_s {
268264
uint32_t remote_ended;
269265

270266
// rate control
271-
uint32_t delivered; // number of packets delivered, including retransmits
272-
uint32_t lost; // number of packets lost, including retransmits
273-
uint32_t app_limited; // we are 'app limited' until delivered reaches this value
274-
uint64_t interval_start_time; // start of window send phase
275-
uint64_t delivered_time; // time we reached 'delivered'
276-
uint32_t rate_delivered; // saved rate sample: packets delivered
277-
uint32_t rate_interval_ms; // saved rate sample: time elapsed
278-
bool rate_sample_is_app_limited;
267+
uint32_t delivered; // number of packets delivered, including retransmits
268+
uint32_t lost; // number of packets lost, including retransmits
269+
uint32_t app_limited; // we are 'app limited' until delivered reaches this value
270+
uint64_t first_sent_ts; // start of window send interval
271+
uint64_t delivered_ts; // time we reached 'delivered'
272+
uint32_t rate_delivered; // saved rate sample: packets delivered
273+
uint32_t rate_interval_ms; // saved rate sample: time elapsed
274+
bool rate_sample_is_app_limited; // saved rate sample: app limited?
279275

280276
uint32_t srtt;
281277
uint32_t rttvar;
@@ -289,6 +285,45 @@ struct udx_stream_s {
289285
uint32_t rack_next_seq;
290286
uint32_t rack_fack;
291287

288+
// packet delivery rate measured in packets/ms
289+
290+
struct {
291+
uint32_t min_rtt_ms; // min RTT in past min_rtt_win (10 seconds). BBR.rtprop in IETF draft
292+
uint64_t min_rtt_stamp; // timestamp min_rtt_ms sample was taken. BBR.rtprop_stamp in IETF draft
293+
uint64_t probe_rtt_done_time; // end time for UDX_BBR_STATE_PROBE_RTT
294+
win_filter_f64_t bw; // maximum recent delivery rate in packets/ms. BBR.BtlBwFilter in IETF draft.
295+
uint32_t rtt_count; // count of packet-timed round trips. BBR.round_count in IETF draft
296+
uint32_t next_rtt_delivered; // pkt.delivered at end of round
297+
uint64_t cycle_timestamp; // time of this phase start
298+
uint8_t state; // UDX_BBR_STATE_*.
299+
uint8_t prev_ca_state; // TCP_Ca_*.
300+
301+
// flags
302+
bool use_packet_conservation; // flag set on transition into fast recovery, limits packets sent in fast recovery
303+
bool round_start; // flag set when ack advances round_count
304+
bool idle_restart; // flag set on transmit start on send path
305+
bool probe_rtt_round_done; // flag set during PROBE_RTT when connection has been in PROBE_RTT for more than 1 rtt
306+
307+
float pacing_gain;
308+
float cwnd_gain;
309+
bool full_bw_reached; // full bw reached during startup
310+
uint8_t full_bw_count;
311+
uint8_t cycle_index;
312+
bool has_seen_rtt;
313+
314+
uint32_t prior_cwnd;
315+
double full_bw;
316+
317+
uint64_t ack_epoch_start;
318+
uint16_t extra_acked[2]; // volume of data that estimates the degree of aggregation in the network path.
319+
uint32_t ack_epoch_acked; // packets (S)ACKed in sampling epoch
320+
uint8_t extra_acked_win_rtts;
321+
uint8_t extra_acked_win_index;
322+
323+
} bbr;
324+
325+
uint32_t pacing_bytes_per_ms; // computed by bbr module. 'BBR.pacing_rate' in IETF draft
326+
292327
uint32_t pkts_buffered; // how many (data) packets received but not processed (out of order)?
293328

294329
// pacing (tb = token bucket)
@@ -312,18 +347,14 @@ struct udx_stream_s {
312347
size_t inflight;
313348

314349
uint32_t sacks;
315-
uint32_t ssthresh;
316-
uint32_t cwnd; // packets
317-
uint32_t cwnd_cnt;
350+
uint32_t cwnd; // packets
351+
uint32_t ssthresh; // packets
318352
uint32_t send_rwnd; // remote advertised rwnd
319353
uint32_t recv_rwnd_max; // default: UDX_DEFAULT_RWND_MAX
320354

321355
uint32_t send_wl1; // seq at last window update
322356
uint32_t send_wl2; // ack at last window update
323357

324-
// congestion state
325-
udx_cong_t cong;
326-
327358
udx_queue_t write_queue;
328359

329360
udx_cirbuf_t outgoing;
@@ -357,11 +388,11 @@ struct udx_packet_s {
357388

358389
uint64_t time_sent;
359390

360-
// rate info
361-
uint64_t interval_start_time;
362-
uint64_t delivered_time;
363-
uint32_t delivered;
364-
bool is_app_limited;
391+
// rate sampling state
392+
uint64_t first_sent_ts; // not the same as pkt->time_sent! this is the time sent of the most recently acked packet, used for the start interval of a rate sample
393+
uint64_t delivered_ts; // time stamp when the 'delivered' value was taken
394+
uint32_t delivered; // #pkts delivered when packet was transmitted
395+
bool is_app_limited; // was throughput app-limited (vs network limited) at the time the packet was transmitted?
365396

366397
struct sockaddr_storage dest;
367398
int dest_len;
@@ -534,6 +565,12 @@ udx_stream_get_ack (udx_stream_t *stream, uint32_t *ack);
534565
int
535566
udx_stream_set_ack (udx_stream_t *stream, uint32_t ack);
536567

568+
int
569+
udx_stream_get_bw (udx_stream_t *stream, uint64_t *bw_bytes_per_sec_out);
570+
571+
int
572+
udx_stream_get_min_rtt (udx_stream_t *stream, uint32_t *min_rtt_ms_out);
573+
537574
int
538575
udx_stream_get_rwnd_max (udx_stream_t *stream, uint32_t *rwnd_max);
539576

src/internal.h

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ typedef struct {
1616
int64_t interval_ms;
1717
uint32_t snd_interval_ms;
1818
uint32_t rcv_interval_ms;
19-
long rtt_ms;
19+
int64_t rtt_ms; // rs.rtt in IETF draft
2020
int losses;
2121
uint32_t acked_sacked;
2222
uint32_t prior_in_flight;
@@ -26,6 +26,36 @@ typedef struct {
2626
bool is_ack_delayed;
2727
} udx_rate_sample_t;
2828

29+
static inline uint32_t
30+
max_uint32 (uint32_t a, uint32_t b) {
31+
return a < b ? b : a;
32+
}
33+
34+
static inline uint32_t
35+
min_uint32 (uint32_t a, uint32_t b) {
36+
return a < b ? a : b;
37+
}
38+
39+
static inline int32_t
40+
max_int32 (int32_t a, int32_t b) {
41+
return a < b ? b : a;
42+
}
43+
44+
static inline int64_t
45+
max_int64 (int64_t a, int64_t b) {
46+
return a < b ? b : a;
47+
}
48+
49+
static inline uint64_t
50+
min_uint64 (uint64_t a, uint64_t b) {
51+
return a < b ? a : b;
52+
}
53+
54+
static inline uint64_t
55+
max_uint64 (uint64_t a, uint64_t b) {
56+
return a < b ? b : a;
57+
}
58+
2959
static inline int32_t
3060
seq_diff (uint32_t a, uint32_t b) {
3161
return a - b;
@@ -61,4 +91,18 @@ udx__rate_gen (udx_stream_t *stream, uint32_t delivered, uint32_t lost, udx_rate
6191
void
6292
udx__rate_check_app_limited (udx_stream_t *stream);
6393

94+
// bbr
95+
96+
void
97+
bbr_init (udx_stream_t *stream);
98+
99+
void
100+
bbr_on_rto (udx_stream_t *stream);
101+
102+
void
103+
bbr_main (udx_stream_t *stream, udx_rate_sample_t *rs);
104+
105+
void
106+
bbr_on_transmit_start (udx_stream_t *stream, uint64_t now_ms);
107+
64108
#endif // UDX_INTERNAL_H

0 commit comments

Comments
 (0)