#pragma once #include #ifdef __cplusplus extern "C" { #endif #define BBR_SCALE 8 #define BBR_UNIT (1 << BBR_SCALE) #define BW_SCALE 24 #define BW_UNIT (1 << BW_SCALE) #define BBR_STARTUP_PACING_GAIN (BBR_UNIT * 277 / 100 + 1) #define BBR_STARTUP_CWND_GAIN (BBR_UNIT * 2) #define BBR_DRAIN_GAIN (BBR_UNIT * 1000 / 2885) #define BBR_CWND_GAIN (BBR_UNIT * 2) #define BBR_PROBE_RTT_CWND_GAIN (BBR_UNIT * 1 / 2) #define BBR_CWND_MIN_TARGET 4 #define BBR_FULL_BW_THRESH (BBR_UNIT * 5 / 4) #define BBR_FULL_BW_CNT 3 #define BBR_LOSS_THRESH (BBR_UNIT * 2 / 100) #define BBR_BETA (BBR_UNIT * 30 / 100) #define BBR_INFLIGHT_HEADROOM (BBR_UNIT * 15 / 100) #define BBR_EXTRA_ACKED_GAIN BBR_UNIT #define BBR_EXTRA_ACKED_WIN_RTTS 5 #define BBR_ACK_EPOCH_ACKED_RESET_THRESH (1U << 20) #define BBR_EXTRA_ACKED_MAX_US (100 * 1000) #define BBR_FULL_LOSS_CNT 6 #define BBR_BW_PROBE_MAX_ROUNDS 63 #define BBR_BW_PROBE_RAND_ROUNDS 2 #define BBR_BW_PROBE_BASE_US (2 * 1000000) #define BBR_BW_PROBE_RAND_US (1 * 1000000) #define BBR_PROBE_RTT_WIN_MS 5000 #define BBR_MIN_RTT_WIN_SEC 10 #define BBR_PROBE_RTT_MS 200 enum bbr_mode { BBR_STARTUP = 0, BBR_DRAIN = 1, BBR_PROBE_BW = 2, BBR_PROBE_RTT = 3 }; enum bbr_bw_probe_cyc { BBR_BW_PROBE_UP = 0, BBR_BW_PROBE_DOWN = 1, BBR_BW_PROBE_CRUISE = 2, BBR_BW_PROBE_REFILL = 3 }; enum bbr_ack_phase { BBR_ACKS_INIT = 0, BBR_ACKS_REFILLING, BBR_ACKS_PROBE_STARTING, BBR_ACKS_PROBE_FEEDBACK, BBR_ACKS_PROBE_STOPPING }; struct bbr_rate_sample { uint32_t delivered; uint32_t interval_us; uint32_t rtt_us; uint32_t acked_sacked; uint32_t prior_delivered; uint32_t tx_in_flight; int lost; int is_app_limited; }; typedef void (*bbr_cwnd_update_fn)(void* ctx, uint32_t new_cwnd); struct bbr { uint32_t min_rtt_us; uint32_t bw_lo; uint32_t bw_hi[2]; uint32_t inflight_lo; uint32_t inflight_hi; uint32_t bw_latest; uint32_t inflight_latest; uint8_t mode; uint8_t cycle_idx; uint16_t pacing_gain; uint16_t cwnd_gain; uint32_t next_rtt_delivered; uint8_t round_start : 1; uint8_t full_bw_reached : 1; uint8_t loss_in_round : 1; uint8_t loss_in_cycle : 1; uint8_t idle_restart : 1; uint8_t try_fast_path : 1; uint8_t has_seen_rtt : 1; uint8_t initialized : 1; uint32_t loss_round_delivered; uint32_t bw_probe_up_cnt; uint32_t bw_probe_up_acks; uint8_t bw_probe_up_rounds; uint8_t bw_probe_samples : 1; uint8_t prev_probe_too_high: 1; uint8_t stopped_risky_probe: 1; uint8_t rounds_since_probe; uint32_t probe_wait_us; uint64_t cycle_mstamp_tb; uint32_t probe_rtt_min_us; uint64_t probe_rtt_min_stamp_tb; uint64_t probe_rtt_done_stamp_tb; uint8_t probe_rtt_round_done : 1; uint16_t extra_acked[2]; uint32_t ack_epoch_acked; uint64_t ack_epoch_mstamp_tb; uint8_t extra_acked_win_idx : 1; uint8_t extra_acked_win_rtts : 5; uint32_t prior_cwnd; uint8_t init_cwnd : 7; uint8_t full_bw_cnt : 2; uint8_t ack_phase : 3; uint8_t loss_events_in_round : 4; uint32_t delivered; uint32_t full_bw; uint64_t min_rtt_stamp_tb; uint8_t loss_round_start : 1; uint8_t full_bw_now : 1; uint8_t pad_unused : 6; uint8_t link_id; // local_link_id for debug logging uint64_t now_tb; // 0 = real get_time_tb(); >0 = test-controlled time bbr_cwnd_update_fn on_cwnd_update; void* cwnd_update_ctx; }; void bbr_init(struct bbr* bbr); void bbr_main(struct bbr* bbr, const struct bbr_rate_sample* rs, uint32_t* cwnd_out, uint32_t* pacing_rate_out, uint32_t mss, uint32_t inflight_bytes, int is_cwnd_limited); void bbr_note_loss(struct bbr* bbr); void bbr_tx_start(struct bbr* bbr); #ifdef __cplusplus } #endif