9#define TOR_CONGESTION_CONTROL_COMMON_PRIVATE
10#define TOR_CONGESTION_CONTROL_PRIVATE
17#include "core/or/or_circuit_st.h"
28#include "core/or/trace_probes_cc.h"
33#include "trunnel/congestion_control.h"
34#include "trunnel/extension.h"
40#define SENDME_INC_DFLT (TLS_RECORD_MAX_CELLS)
41#define CIRCWINDOW_INIT (4*SENDME_INC_DFLT)
43#define CC_ALG_DFLT (CC_ALG_VEGAS)
44#define CC_ALG_DFLT_ALWAYS (CC_ALG_VEGAS)
46#define CWND_INC_DFLT (1)
47#define CWND_INC_PCT_SS_DFLT (100)
48#define CWND_INC_RATE_DFLT (SENDME_INC_DFLT)
50#define CWND_MIN_DFLT (CIRCWINDOW_INIT)
51#define CWND_MAX_DFLT (INT32_MAX)
53#define BWE_SENDME_MIN_DFLT (5)
55#define N_EWMA_CWND_PCT_DFLT (50)
56#define N_EWMA_MAX_DFLT (10)
57#define N_EWMA_SS_DFLT (2)
59#define RTT_RESET_PCT_DFLT (100)
63#define WESTWOOD_BDP_ALG BDP_ALG_PIECEWISE
64#define VEGAS_BDP_MIX_ALG BDP_ALG_PIECEWISE
65#define NOLA_BDP_ALG BDP_ALG_PIECEWISE
76#define OR_CONN_HIGHWATER_DFLT (32*1024)
77#define OR_CONN_LOWWATER_DFLT (16*1024)
84#define CELL_QUEUE_LOW_DFLT (10)
85#define CELL_QUEUE_HIGH_DFLT (256)
91static uint64_t num_rtt_reset;
94static uint64_t num_clock_stalls;
97static uint32_t cwnd_max = CWND_MAX_DFLT;
98int32_t cell_queue_high = CELL_QUEUE_HIGH_DFLT;
99int32_t cell_queue_low = CELL_QUEUE_LOW_DFLT;
100uint32_t or_conn_highwater = OR_CONN_HIGHWATER_DFLT;
101uint32_t or_conn_lowwater = OR_CONN_LOWWATER_DFLT;
102uint8_t cc_sendme_inc = SENDME_INC_DFLT;
138 return num_rtt_reset;
145 return num_clock_stalls;
155#define CELL_QUEUE_HIGH_MIN (1)
156#define CELL_QUEUE_HIGH_MAX (1000)
158 CELL_QUEUE_HIGH_DFLT,
160 CELL_QUEUE_HIGH_MAX);
162#define CELL_QUEUE_LOW_MIN (1)
163#define CELL_QUEUE_LOW_MAX (1000)
169#define OR_CONN_HIGHWATER_MIN (CELL_PAYLOAD_SIZE)
170#define OR_CONN_HIGHWATER_MAX (INT32_MAX)
173 OR_CONN_HIGHWATER_DFLT,
174 OR_CONN_HIGHWATER_MIN,
175 OR_CONN_HIGHWATER_MAX);
177#define OR_CONN_LOWWATER_MIN (CELL_PAYLOAD_SIZE)
178#define OR_CONN_LOWWATER_MAX (INT32_MAX)
181 OR_CONN_LOWWATER_DFLT,
182 OR_CONN_LOWWATER_MIN,
183 OR_CONN_LOWWATER_MAX);
185#define CWND_MAX_MIN 500
186#define CWND_MAX_MAX (INT32_MAX)
193#define RTT_RESET_PCT_MIN (0)
194#define RTT_RESET_PCT_MAX (100)
201#define SENDME_INC_MIN 1
202#define SENDME_INC_MAX (254)
210#define CC_ALG_MAX (NUM_CC_ALGS-1)
219 log_warn(
LD_BUG,
"Unsupported congestion control algorithm %d",
221 cc_alg = CC_ALG_DFLT;
224#define BWE_SENDME_MIN_MIN 2
225#define BWE_SENDME_MIN_MAX (20)
232#define N_EWMA_CWND_PCT_MIN 1
233#define N_EWMA_CWND_PCT_MAX (255)
236 N_EWMA_CWND_PCT_DFLT,
238 N_EWMA_CWND_PCT_MAX);
240#define N_EWMA_MAX_MIN 2
241#define N_EWMA_MAX_MAX (INT32_MAX)
248#define N_EWMA_SS_MIN 2
249#define N_EWMA_SS_MAX (INT32_MAX)
274#define CWND_INIT_MIN SENDME_INC_DFLT
275#define CWND_INIT_MAX (10000)
282#define CWND_INC_PCT_SS_MIN 1
283#define CWND_INC_PCT_SS_MAX (500)
286 CWND_INC_PCT_SS_DFLT,
288 CWND_INC_PCT_SS_MAX);
290#define CWND_INC_MIN 1
291#define CWND_INC_MAX (1000)
298#define CWND_INC_RATE_MIN 1
299#define CWND_INC_RATE_MAX (250)
306#define CWND_MIN_MIN SENDME_INC_DFLT
307#define CWND_MIN_MAX (1000)
318 cc->
cc_alg = CC_ALG_DFLT_ALWAYS;
328 log_warn(
LD_BUG,
"Unknown congestion control algorithm %d",
373congestion_control_set_cc_enabled(
void)
383congestion_control_set_cc_disabled(
void)
444 uint64_t *timestamp_ptr = tor_malloc(
sizeof(uint64_t));
445 *timestamp_ptr = timestamp_usec;
454static inline uint64_t
457 uint64_t *timestamp_ptr = smartlist_get(timestamps_u64_usecs, 0);
458 uint64_t timestamp_u64;
460 if (BUG(!timestamp_ptr)) {
461 log_err(
LD_CIRC,
"Congestion control timestamp list became empty!");
465 timestamp_u64 = *timestamp_ptr;
469 return timestamp_u64;
479static inline uint64_t
482 uint64_t ewma_cnt = 0;
494 ewma_cnt =
MAX(ewma_cnt, 2);
521 return package_window;
688STATIC bool is_monotime_clock_broken =
false;
701 uint64_t old_delta, uint64_t new_delta)
703#define DELTA_DISCREPENCY_RATIO_MAX 5000
705 if (new_delta == 0) {
706 static ratelim_t stall_info_limit = RATELIM_INIT(60);
708 "Congestion control cannot measure RTT due to monotime stall.");
710 is_monotime_clock_broken =
true;
731 if (old_delta > new_delta * DELTA_DISCREPENCY_RATIO_MAX) {
732 static ratelim_t dec_notice_limit = RATELIM_INIT(300);
734 "Sudden decrease in circuit RTT (%"PRIu64
" vs %"PRIu64
735 "), likely due to clock jump.",
736 new_delta/1000, old_delta/1000);
738 return is_monotime_clock_broken;
746 if (new_delta > old_delta * DELTA_DISCREPENCY_RATIO_MAX) {
747 static ratelim_t dec_notice_limit = RATELIM_INIT(300);
749 "Sudden increase in circuit RTT (%"PRIu64
" vs %"PRIu64
750 "), likely due to clock jump or suspended remote endpoint.",
751 new_delta/1000, old_delta/1000);
757 is_monotime_clock_broken =
false;
768 return !is_monotime_clock_broken;
785 uint64_t rtt, ewma_cnt;
786 uint64_t sent_at_timestamp;
794 rtt = now_usec - sent_at_timestamp;
806 if (rtt > cc->max_rtt_usec) {
807 cc->max_rtt_usec = rtt;
810 if (cc->min_rtt_usec == 0) {
819 static ratelim_t rtt_notice_limit = RATELIM_INIT(300);
821 "Resetting circ RTT from %"PRIu64
" to %"PRIu64
" due to low cwnd",
822 cc->min_rtt_usec/1000, new_rtt/1000);
824 cc->min_rtt_usec = new_rtt;
850 uint64_t curr_rtt_usec)
853 unsigned int blocked_on_chan = 0;
871 uint64_t cwnd = cc->
cwnd;
873 tor_assert_nonfatal(cc->
cwnd <= cwnd_max);
877 if (blocked_on_chan) {
879 if (chan_q >= (int64_t)cwnd) {
881 "Clock stall with large chanq: %d %"PRIu64, chan_q, cwnd);
893 static ratelim_t dec_notice_limit = RATELIM_INIT(300);
895 "Our clock has been stalled for the entire lifetime of a circuit. "
896 "Performance may be sub-optimal.");
898 return blocked_on_chan;
913 if (blocked_on_chan) {
914 log_info(
LD_CIRC,
"CC: Streams blocked on circ channel. Chanq: %d",
929 log_info(
LD_CIRC,
"CC: Streams un-blocked on circ channel. Chanq: %d",
938 "SENDME RTT: %"PRIu64
", %"PRIu64
", %"PRIu64
", %"PRIu64
", "
939 "BDP estimate: %"PRIu64,
940 CONST_TO_ORIGIN_CIRCUIT(circ)->global_identifier,
941 cc->min_rtt_usec/1000,
944 cc->max_rtt_usec/1000,
948 "CC: Circuit %"PRIu64
":%d "
949 "SENDME RTT: %"PRIu64
", %"PRIu64
", %"PRIu64
", %"PRIu64
", "
951 CONST_TO_OR_CIRCUIT(circ)->p_chan->global_identifier,
952 CONST_TO_OR_CIRCUIT(circ)->p_circ_id,
953 cc->min_rtt_usec/1000,
956 cc->max_rtt_usec/1000,
963 bool ret = (blocked_on_chan || curr_rtt_usec != 0);
965 tor_trace(
TR_SUBSYS(cc), TR_EV(bdp_update), circ, cc, curr_rtt_usec);
977 int ret = -END_CIRC_REASON_INTERNAL;
982 if (cc->
cwnd > cwnd_max) {
983 static ratelim_t cwnd_limit = RATELIM_INIT(60);
985 "Congestion control cwnd %"PRIu64
" exceeds max %d, clamping.",
1015 uint8_t *request = NULL;
1016 trn_extension_t *ext = NULL;
1017 trn_extension_field_t *field = NULL;
1019 ext = trn_extension_new();
1026 field = trn_extension_field_new();
1027 trn_extension_field_set_field_type(field,
1028 TRUNNEL_EXT_TYPE_CC_FIELD_REQUEST);
1031 trn_extension_field_set_field_len(field, 0);
1034 trn_extension_add_fields(ext, field);
1035 trn_extension_set_num(ext, 1);
1039 ssize_t ret = trn_extension_encoded_len(ext);
1043 size_t request_len = ret;
1044 request = tor_malloc_zero(request_len);
1045 ret = trn_extension_encode(request, request_len, ext);
1051 *msg_len_out = request_len;
1057 trn_extension_free(ext);
1075 trn_extension_t *ext = NULL;
1076 size_t num_fields = 0;
1079 ret = trn_extension_parse(&ext, msg, msg_len);
1086 if ((num_fields = trn_extension_get_num(ext)) == 0) {
1093 for (
size_t f = 0; f < num_fields; f++) {
1094 const trn_extension_field_t *field = trn_extension_get_fields(ext, f);
1095 if (field == NULL) {
1101 if (trn_extension_field_get_field_type(field) ==
1102 TRUNNEL_EXT_TYPE_CC_FIELD_REQUEST) {
1109 trn_extension_free(ext);
1135 uint8_t **msg_out,
size_t *msg_len_out)
1138 uint8_t *request = NULL;
1139 trn_extension_t *ext = NULL;
1140 trn_extension_field_t *field = NULL;
1141 trn_extension_field_cc_t *cc_field = NULL;
1148 ext = trn_extension_new();
1152 field = trn_extension_field_new();
1153 trn_extension_field_set_field_type(field,
1154 TRUNNEL_EXT_TYPE_CC_FIELD_RESPONSE);
1157 cc_field = trn_extension_field_cc_new();
1158 trn_extension_field_cc_set_sendme_inc(cc_field,
1161 ret = trn_extension_field_cc_encoded_len(cc_field);
1162 if (BUG(ret <= 0)) {
1163 trn_extension_field_free(field);
1166 size_t field_len = ret;
1167 trn_extension_field_set_field_len(field, field_len);
1168 trn_extension_field_setlen_field(field, field_len);
1170 uint8_t *field_array = trn_extension_field_getarray_field(field);
1171 ret = trn_extension_field_cc_encode(field_array,
1172 trn_extension_field_getlen_field(field), cc_field);
1173 if (BUG(ret <= 0)) {
1174 trn_extension_field_free(field);
1179 trn_extension_add_fields(ext, field);
1180 trn_extension_set_num(ext, 1);
1184 ret = trn_extension_encoded_len(ext);
1188 size_t request_len = ret;
1189 request = tor_malloc_zero(request_len);
1190 ret = trn_extension_encode(request, request_len, ext);
1196 *msg_len_out = request_len;
1202 trn_extension_free(ext);
1203 trn_extension_field_cc_free(cc_field);
1218 if (sendme_inc == 0)
1232 const size_t msg_len,
1236 size_t num_fields = 0;
1237 trn_extension_t *ext = NULL;
1238 trn_extension_field_cc_t *cc_field = NULL;
1245#define MAX_SENDME_INC_NEGOTIATE_FACTOR 2
1248 ret = trn_extension_parse(&ext, msg, msg_len);
1253 if ((num_fields = trn_extension_get_num(ext)) == 0) {
1260 for (
size_t f = 0; f < num_fields; f++) {
1261 const trn_extension_field_t *field = trn_extension_get_fields(ext, f);
1262 if (field == NULL) {
1268 if (trn_extension_field_get_field_type(field) ==
1269 TRUNNEL_EXT_TYPE_CC_FIELD_RESPONSE) {
1272 ret = trn_extension_field_cc_parse(&cc_field,
1273 trn_extension_field_getconstarray_field(field),
1274 trn_extension_field_getlen_field(field));
1279 uint8_t sendme_inc_cells =
1280 trn_extension_field_cc_get_sendme_inc(cc_field);
1294 trn_extension_free(ext);
1295 trn_extension_field_cc_free(cc_field);
1330 " SS=%d CWND=%"PRIu64
" RTT=%"PRIu64
" MIN_RTT=%"PRIu64,
1333 ccontrol->min_rtt_usec/1000);
1335 log_warn(
LD_BUG,
"Unable to format event for controller.");
Header file for channel.c.
Header file for circuitlist.c.
#define CIRCUIT_IS_ORIGIN(c)
uint64_t monotime_absolute_usec(void)
Functions and types for monotonic times.
const or_options_t * get_options(void)
Header file for config.c.
void conflux_update_rtt(conflux_t *cfx, circuit_t *circ, uint64_t rtt_usec)
Public APIs for conflux multipath support.
Header file for conflux_util.c.
bool congestion_control_validate_sendme_increment(uint8_t sendme_inc)
bool congestion_control_update_circuit_estimates(congestion_control_t *cc, const circuit_t *circ)
static uint64_t n_ewma_count(const congestion_control_t *cc)
int sendme_get_inc_count(const circuit_t *circ, const crypt_path_t *layer_hint)
static uint64_t dequeue_timestamp(smartlist_t *timestamps_u64_usecs)
congestion_control_t * congestion_control_new(const circuit_params_t *params, cc_path_t path)
static uint8_t rtt_reset_pct
static uint8_t n_ewma_max
void congestion_control_free_(congestion_control_t *cc)
STATIC bool time_delta_stalled_or_jumped(const congestion_control_t *cc, uint64_t old_delta, uint64_t new_delta)
static void congestion_control_init(congestion_control_t *cc, const circuit_params_t *params, cc_path_t path)
bool circuit_sent_cell_for_sendme(const circuit_t *circ, const crypt_path_t *layer_hint)
uint64_t congestion_control_get_num_clock_stalls(void)
static bool time_delta_should_use_heuristics(const congestion_control_t *cc)
uint64_t congestion_control_get_num_rtt_reset(void)
void congestion_control_note_cell_sent(congestion_control_t *cc, const circuit_t *circ, const crypt_path_t *cpath)
int congestion_control_build_ext_response(const circuit_params_t *our_params, const circuit_params_t *circ_params, uint8_t **msg_out, size_t *msg_len_out)
int congestion_control_parse_ext_request(const uint8_t *msg, const size_t msg_len)
int congestion_control_build_ext_request(uint8_t **msg_out, size_t *msg_len_out)
static bool congestion_control_update_circuit_bdp(congestion_control_t *, const circuit_t *, uint64_t)
static void congestion_control_init_params(congestion_control_t *cc, const circuit_params_t *params, cc_path_t path)
int congestion_control_parse_ext_response(const uint8_t *msg, const size_t msg_len, circuit_params_t *params_out)
static uint8_t bwe_sendme_min
STATIC void enqueue_timestamp(smartlist_t *timestamps_u64, uint64_t timestamp_usec)
bool congestion_control_enabled(void)
int congestion_control_dispatch_cc_alg(congestion_control_t *cc, circuit_t *circ)
uint64_t cc_stats_circs_created
char * congestion_control_get_control_port_fields(const origin_circuit_t *circ)
bool is_monotime_clock_reliable(void)
int congestion_control_get_package_window(const circuit_t *circ, const crypt_path_t *cpath)
static uint8_t n_ewma_cwnd_pct
void congestion_control_new_consensus_params(const networkstatus_t *ns)
STATIC uint64_t congestion_control_update_circuit_rtt(congestion_control_t *cc, uint64_t now_usec)
Public APIs for congestion control.
static uint64_t n_count_ewma(uint64_t curr, uint64_t prev, uint64_t N)
static uint64_t percent_max_mix(uint64_t a, uint64_t b, uint8_t pct_max)
static uint8_t congestion_control_sendme_inc(void)
Structure definitions for congestion control.
static uint64_t CWND_UPDATE_RATE(const struct congestion_control_t *cc)
void congestion_control_vegas_set_params(congestion_control_t *cc, cc_path_t path)
int congestion_control_vegas_process_sendme(congestion_control_t *cc, const circuit_t *circ)
Private-ish APIs for the TOR_VEGAS congestion control algorithm.
Header file for connection.c.
Header file for crypt_path.c.
#define log_fn_ratelim(ratelim, severity, domain, args,...)
int32_t networkstatus_get_param(const networkstatus_t *ns, const char *param_name, int32_t default_val, int32_t min_val, int32_t max_val)
Header file for networkstatus.c.
Header file for onion_crypto.c.
Master header file for Tor-specific functionality.
#define CIRCWINDOW_INCREMENT
Origin circuit structure.
int tor_asprintf(char **strp, const char *fmt,...)
Header file for sendme.c.
smartlist_t * smartlist_new(void)
void smartlist_add(smartlist_t *sl, void *element)
void smartlist_del_keeporder(smartlist_t *sl, int idx)
#define SMARTLIST_FOREACH(sl, type, var, cmd)
unsigned int circuit_blocked_on_n_chan
unsigned int circuit_blocked_on_p_chan
cell_queue_t n_chan_cells
struct conflux_t * conflux
struct congestion_control_t * ccontrol
smartlist_t * sendme_pending_timestamps
struct crypt_path_t * prev
struct congestion_control_t * ccontrol
cell_queue_t p_chan_cells
int AlwaysCongestionControl