diff --git a/changes/ticket40569 b/changes/ticket40569 new file mode 100644 index 0000000000..d4ffb829ec --- /dev/null +++ b/changes/ticket40569 @@ -0,0 +1,4 @@ + o Minor bugfix (congestion control): + - Reduce the accepted range of a circuit's negotiated 'cc_sendme_inc' + to be +/- 1 from the consensus parameter value. Fixes bug 40569; + bugfix on 0.4.7.4-alpha. diff --git a/changes/ticket40709 b/changes/ticket40709 new file mode 100644 index 0000000000..16c4d6205f --- /dev/null +++ b/changes/ticket40709 @@ -0,0 +1,3 @@ + o Minor bugfix (congestion control): + - Update default congestion control parameters to match consensus. + Fixes bug 40709; bugfix on 0.4.7.4-alpha. diff --git a/src/core/or/congestion_control_common.c b/src/core/or/congestion_control_common.c index 1e0f504df1..f747987957 100644 --- a/src/core/or/congestion_control_common.c +++ b/src/core/or/congestion_control_common.c @@ -7,6 +7,7 @@ */ #define TOR_CONGESTION_CONTROL_COMMON_PRIVATE +#define TOR_CONGESTION_CONTROL_PRIVATE #include "core/or/or.h" @@ -18,6 +19,7 @@ #include "core/or/channel.h" #include "core/mainloop/connection.h" #include "core/or/sendme.h" +#include "core/or/congestion_control_st.h" #include "core/or/congestion_control_common.h" #include "core/or/congestion_control_vegas.h" #include "core/or/congestion_control_nola.h" @@ -40,14 +42,14 @@ #define SENDME_INC_DFLT (TLS_RECORD_MAX_CELLS) #define CIRCWINDOW_INIT (4*SENDME_INC_DFLT) -#define CC_ALG_DFLT (CC_ALG_SENDME) +#define CC_ALG_DFLT (CC_ALG_VEGAS) #define CC_ALG_DFLT_ALWAYS (CC_ALG_VEGAS) -#define CWND_INC_DFLT (TLS_RECORD_MAX_CELLS) +#define CWND_INC_DFLT (1) #define CWND_INC_PCT_SS_DFLT (100) -#define CWND_INC_RATE_DFLT (1) +#define CWND_INC_RATE_DFLT (SENDME_INC_DFLT) -#define CWND_MIN_DFLT (2*SENDME_INC_DFLT) +#define CWND_MIN_DFLT (CIRCWINDOW_INIT) #define CWND_MAX_DFLT (INT32_MAX) #define BWE_SENDME_MIN_DFLT (5) @@ -84,15 +86,10 @@ #define CELL_QUEUE_LOW_DFLT (10) #define CELL_QUEUE_HIGH_DFLT (256) -static uint64_t congestion_control_update_circuit_rtt(congestion_control_t *, - uint64_t); static bool congestion_control_update_circuit_bdp(congestion_control_t *, const circuit_t *, const crypt_path_t *, uint64_t, uint64_t); -/* For unit tests */ -void congestion_control_set_cc_enabled(void); - /* Number of times the RTT value was reset. For MetricsPort. */ static uint64_t num_rtt_reset; @@ -106,33 +103,33 @@ int32_t cell_queue_low = CELL_QUEUE_LOW_DFLT; uint32_t or_conn_highwater = OR_CONN_HIGHWATER_DFLT; uint32_t or_conn_lowwater = OR_CONN_LOWWATER_DFLT; uint8_t cc_sendme_inc = SENDME_INC_DFLT; -static cc_alg_t cc_alg = CC_ALG_DFLT; +STATIC cc_alg_t cc_alg = CC_ALG_DFLT; /** * Number of cwnd worth of sendme acks to smooth RTT and BDP with, * using N_EWMA */ -static uint8_t n_ewma_cwnd_pct; +static uint8_t n_ewma_cwnd_pct = N_EWMA_CWND_PCT_DFLT; /** * Maximum number N for the N-count EWMA averaging of RTT and BDP. */ -static uint8_t n_ewma_max; +static uint8_t n_ewma_max = N_EWMA_MAX_DFLT; /** * Maximum number N for the N-count EWMA averaging of RTT in Slow Start. */ -static uint8_t n_ewma_ss; +static uint8_t n_ewma_ss = N_EWMA_SS_DFLT; /** * Minimum number of sendmes before we begin BDP estimates */ -static uint8_t bwe_sendme_min; +static uint8_t bwe_sendme_min = BWE_SENDME_MIN_DFLT; /** * Percentage of the current RTT to use when resetting the minimum RTT * for a circuit. (RTT is reset when the cwnd hits cwnd_min). */ -static uint8_t rtt_reset_pct; +static uint8_t rtt_reset_pct = RTT_RESET_PCT_DFLT; /** Metric to count the number of congestion control circuits **/ uint64_t cc_stats_circs_created = 0; @@ -205,7 +202,7 @@ congestion_control_new_consensus_params(const networkstatus_t *ns) RTT_RESET_PCT_MAX); #define SENDME_INC_MIN 1 -#define SENDME_INC_MAX (255) +#define SENDME_INC_MAX (254) cc_sendme_inc = networkstatus_get_param(NULL, "cc_sendme_inc", SENDME_INC_DFLT, @@ -387,6 +384,7 @@ congestion_control_enabled(void) return cc_alg != CC_ALG_SENDME; } +#ifdef TOR_UNIT_TESTS /** * For unit tests only: set the cached consensus cc alg to * specified value. @@ -397,6 +395,17 @@ congestion_control_set_cc_enabled(void) cc_alg = CC_ALG_VEGAS; } +/** + * For unit tests only: set the cached consensus cc alg to + * specified value. + */ +void +congestion_control_set_cc_disabled(void) +{ + cc_alg = CC_ALG_SENDME; +} +#endif + /** * Allocate and initialize fields in congestion control object. * @@ -452,7 +461,7 @@ congestion_control_free_(congestion_control_t *cc) /** * Enqueue a u64 timestamp to the end of a queue of timestamps. */ -static inline void +STATIC inline void enqueue_timestamp(smartlist_t *timestamps_u64, uint64_t timestamp_usec) { uint64_t *timestamp_ptr = tor_malloc(sizeof(uint64_t)); @@ -779,7 +788,7 @@ time_delta_should_use_heuristics(const congestion_control_t *cc) return false; } -static bool is_monotime_clock_broken = false; +STATIC bool is_monotime_clock_broken = false; /** * Returns true if the monotime delta is 0, or is significantly @@ -790,7 +799,7 @@ static bool is_monotime_clock_broken = false; * so we can also provide a is_monotime_clock_reliable() function, * used by flow control rate timing. */ -static bool +STATIC bool time_delta_stalled_or_jumped(const congestion_control_t *cc, uint64_t old_delta, uint64_t new_delta) { @@ -872,7 +881,7 @@ is_monotime_clock_reliable(void) * Returns the current circuit RTT in usecs, or 0 if it could not be * measured (due to clock jump, stall, etc). */ -static uint64_t +STATIC uint64_t congestion_control_update_circuit_rtt(congestion_control_t *cc, uint64_t now_usec) { @@ -1443,19 +1452,16 @@ bool congestion_control_validate_sendme_increment(uint8_t sendme_inc) { /* We will only accept this response (and this circuit) if sendme_inc - * is within a factor of 2 of our consensus value. We should not need + * is within +/- 1 of the current consensus value. We should not need * to change cc_sendme_inc much, and if we do, we can spread out those * changes over smaller increments once every 4 hours. Exits that * violate this range should just not be used. */ -#define MAX_SENDME_INC_NEGOTIATE_FACTOR 2 if (sendme_inc == 0) return false; - if (sendme_inc > - MAX_SENDME_INC_NEGOTIATE_FACTOR * congestion_control_sendme_inc() || - sendme_inc < - congestion_control_sendme_inc() / MAX_SENDME_INC_NEGOTIATE_FACTOR) { + if (sendme_inc > (congestion_control_sendme_inc() + 1) || + sendme_inc < (congestion_control_sendme_inc() - 1)) { return false; } return true; diff --git a/src/core/or/congestion_control_common.h b/src/core/or/congestion_control_common.h index cf3e9d4fdb..92c78c5ebd 100644 --- a/src/core/or/congestion_control_common.h +++ b/src/core/or/congestion_control_common.h @@ -174,14 +174,25 @@ percent_max_mix(uint64_t a, uint64_t b, uint8_t pct_max) } /* Private section starts. */ -#ifdef TOR_CONGESTION_CONTROL_PRIVATE +#ifdef TOR_CONGESTION_CONTROL_COMMON_PRIVATE +STATIC uint64_t congestion_control_update_circuit_rtt(congestion_control_t *, + uint64_t); + +STATIC bool time_delta_stalled_or_jumped(const congestion_control_t *cc, + uint64_t old_delta, uint64_t new_delta); + +STATIC void enqueue_timestamp(smartlist_t *timestamps_u64, + uint64_t timestamp_usec); /* * Unit tests declaractions. */ #ifdef TOR_UNIT_TESTS +extern bool is_monotime_clock_broken; +extern cc_alg_t cc_alg; void congestion_control_set_cc_enabled(void); +void congestion_control_set_cc_disabled(void); #endif /* defined(TOR_UNIT_TESTS) */ diff --git a/src/core/or/congestion_control_vegas.c b/src/core/or/congestion_control_vegas.c index f903624d23..b611fc50c4 100644 --- a/src/core/or/congestion_control_vegas.c +++ b/src/core/or/congestion_control_vegas.c @@ -37,30 +37,30 @@ #define VEGAS_SSCAP_SBWS_DFLT (400) /* Exits are three hops, so params are based on 3 outbufs of cells */ -#define VEGAS_ALPHA_EXIT_DFLT (2*OUTBUF_CELLS) +#define VEGAS_ALPHA_EXIT_DFLT (3*OUTBUF_CELLS) #define VEGAS_BETA_EXIT_DFLT (4*OUTBUF_CELLS) #define VEGAS_GAMMA_EXIT_DFLT (3*OUTBUF_CELLS) -#define VEGAS_DELTA_EXIT_DFLT (6*OUTBUF_CELLS) -#define VEGAS_SSCAP_EXIT_DFLT (500) +#define VEGAS_DELTA_EXIT_DFLT (5*OUTBUF_CELLS) +#define VEGAS_SSCAP_EXIT_DFLT (600) /* Onion rends are six hops, so params are based on 6 outbufs of cells */ #define VEGAS_ALPHA_ONION_DFLT (3*OUTBUF_CELLS) -#define VEGAS_BETA_ONION_DFLT (7*OUTBUF_CELLS) -#define VEGAS_GAMMA_ONION_DFLT (5*OUTBUF_CELLS) -#define VEGAS_DELTA_ONION_DFLT (9*OUTBUF_CELLS) -#define VEGAS_SSCAP_ONION_DFLT (600) +#define VEGAS_BETA_ONION_DFLT (6*OUTBUF_CELLS) +#define VEGAS_GAMMA_ONION_DFLT (4*OUTBUF_CELLS) +#define VEGAS_DELTA_ONION_DFLT (7*OUTBUF_CELLS) +#define VEGAS_SSCAP_ONION_DFLT (475) /** * Number of sendme_incs between cwnd and inflight for cwnd to be * still considered full */ -#define VEGAS_CWND_FULL_GAP_DFLT (1) +#define VEGAS_CWND_FULL_GAP_DFLT (4) static int cc_vegas_cwnd_full_gap = VEGAS_CWND_FULL_GAP_DFLT; /** * If the cwnd becomes less than this percent full at any point, * we declare it not full immediately. */ -#define VEGAS_CWND_FULL_MINPCT_DFLT (75) +#define VEGAS_CWND_FULL_MINPCT_DFLT (25) static int cc_vegas_cwnd_full_minpct = VEGAS_CWND_FULL_MINPCT_DFLT; /** diff --git a/src/test/include.am b/src/test/include.am index 4d4bfb8938..b3e3f8bbf2 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -151,6 +151,7 @@ src_test_test_SOURCES += \ src/test/test_conflux_pool.c \ src/test/test_confmgr.c \ src/test/test_confparse.c \ + src/test/test_congestion_control.c \ src/test/test_connection.c \ src/test/test_conscache.c \ src/test/test_consdiff.c \ diff --git a/src/test/test.c b/src/test/test.c index 5ffb06e882..2030a8336e 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -780,6 +780,7 @@ struct testgroup_t testgroups[] = { { "config/parse/", confparse_tests }, { "conflux/cell/", conflux_cell_tests }, { "conflux/pool/", conflux_pool_tests }, + { "congestion_control/", congestion_control_tests }, { "connection/", connection_tests }, { "conscache/", conscache_tests }, { "consdiff/", consdiff_tests }, diff --git a/src/test/test.h b/src/test/test.h index ffac069e39..7a405b649e 100644 --- a/src/test/test.h +++ b/src/test/test.h @@ -111,6 +111,7 @@ extern struct testcase_t conflux_cell_tests[]; extern struct testcase_t conflux_pool_tests[]; extern struct testcase_t confmgr_tests[]; extern struct testcase_t confparse_tests[]; +extern struct testcase_t congestion_control_tests[]; extern struct testcase_t connection_tests[]; extern struct testcase_t conscache_tests[]; extern struct testcase_t consdiff_tests[]; diff --git a/src/test/test_conflux_pool.c b/src/test/test_conflux_pool.c index 3da85705b3..ad78283fe3 100644 --- a/src/test/test_conflux_pool.c +++ b/src/test/test_conflux_pool.c @@ -6,6 +6,7 @@ #define CRYPT_PATH_PRIVATE #define RELAY_PRIVATE #define CONNECTION_PRIVATE +#define TOR_CONGESTION_CONTROL_COMMON_PRIVATE #define TOR_CONGESTION_CONTROL_PRIVATE #include "core/or/or.h" @@ -25,8 +26,8 @@ #include "core/or/circuitstats.h" #include "core/or/circuitbuild.h" #include "core/or/circuituse.h" -#include "core/or/congestion_control_common.h" #include "core/or/congestion_control_st.h" +#include "core/or/congestion_control_common.h" #include "core/or/extendinfo.h" #include "core/mainloop/netstatus.h" #include "core/crypto/relay_crypto.h" diff --git a/src/test/test_congestion_control.c b/src/test/test_congestion_control.c new file mode 100644 index 0000000000..f494515e99 --- /dev/null +++ b/src/test/test_congestion_control.c @@ -0,0 +1,390 @@ +#include "core/or/or.h" +#include "test/test.h" +#include "test/log_test_helpers.h" +#include "lib/testsupport/testsupport.h" +#include "test/fakecircs.h" +#include "test/rng_test_helpers.h" + +#include "lib/time/compat_time.h" + +#include "core/or/circuitlist.h" +#include "core/or/circuitmux.h" +#include "core/or/channel.h" + +#define TOR_CONGESTION_CONTROL_COMMON_PRIVATE +#define TOR_CONGESTION_CONTROL_PRIVATE +#include "core/or/congestion_control_st.h" +#include "core/or/congestion_control_common.h" +#include "core/or/congestion_control_vegas.h" + +void test_congestion_control_rtt(void *arg); +void test_congestion_control_clock(void *arg); +void test_congestion_control_vegas_cwnd(void *arg); + +static void +circuitmux_attach_circuit_mock(circuitmux_t *cmux, circuit_t *circ, + cell_direction_t direction); + +static void +circuitmux_attach_circuit_mock(circuitmux_t *cmux, circuit_t *circ, + cell_direction_t direction) +{ + (void)cmux; + (void)circ; + (void)direction; + + return; +} + +/* =============== Clock Heuristic Test Vectors =============== */ + +typedef struct clock_vec +{ + uint64_t old_delta_in; + uint64_t new_delta_in; + bool in_slow_start_in; + bool cached_result_out; + bool result_out; +} clock_vec_t; + +static void +run_clock_test_vec(congestion_control_t *cc, + clock_vec_t *vec, size_t vec_len) +{ + for (size_t i = 0; i < vec_len; i++) { + cc->in_slow_start = vec[i].in_slow_start_in; + cc->ewma_rtt_usec = vec[i].old_delta_in*1000; + bool ret = time_delta_stalled_or_jumped(cc, + vec[i].old_delta_in, + vec[i].new_delta_in); + + tt_int_op(ret, OP_EQ, vec[i].result_out); + tt_int_op(is_monotime_clock_broken, OP_EQ, vec[i].cached_result_out); + } + + done: + is_monotime_clock_broken = false; +} + +/** + * This test verifies the behavior of Section 2.1.1 of + * Prop#324 (CLOCK_HEURISTICS). + * + * It checks that we declare the clock value stalled, + * and cache that value, on various time deltas. + * + * It also verifies that our heuristics behave correctly + * with respect to slow start and large clock jumps/stalls. + */ +void +test_congestion_control_clock(void *arg) +{ + (void)arg; + clock_vec_t vect1[] = + { + {0, 1, 1, 0, 0}, // old delta 0, slow start -> false + {0, 0, 1, 1, 1}, // New delta 0 -> cache true, return true + {1, 1, 1, 1, 0}, // In slow start -> keep cache, but return false + {1, 4999, 0, 0, 0}, // Not slow start, edge -> update cache, and false + {4999, 1, 0, 0, 0}, // Not slow start, other edge -> false + {5001, 1, 0, 0, 0}, // Not slow start w/ -5000x -> use cache (false) + {5001, 0, 0, 1, 1}, // New delta 0 -> cache true, return true + {5001, 1, 0, 1, 1}, // Not slow start w/ -5000x -> use cache (true) + {5001, 1, 1, 1, 0}, // In slow start w/ -5000x -> false + {0, 5001, 0, 1, 0}, // Not slow start w/ no EWMA -> false + {1, 5001, 1, 1, 0}, // In slow start w/ +5000x -> false + {1, 1, 0, 0, 0}, // Not slow start -> update cache to false + {5001, 1, 0, 0, 0}, // Not slow start w/ -5000x -> use cache (false) + {1, 5001, 0, 0, 1}, // Not slow start w/ +5000x -> true + {0, 5001, 0, 0, 0}, // Not slow start w/ no EWMA -> false + {5001, 1, 1, 0, 0}, // In slow start w/ -5000x change -> false + {1, 1, 0, 0, 0} // Not slow start -> false + }; + + circuit_params_t params; + + params.cc_enabled = 1; + params.sendme_inc_cells = TLS_RECORD_MAX_CELLS; + cc_alg = CC_ALG_VEGAS; + congestion_control_t *cc = congestion_control_new(¶ms, CC_PATH_EXIT); + + run_clock_test_vec(cc, vect1, sizeof(vect1)/sizeof(clock_vec_t)); + + congestion_control_free(cc); +} + +/* =========== RTT Test Vectors ================== */ + +typedef struct rtt_vec { + uint64_t sent_usec_in; + uint64_t got_sendme_usec_in; + uint64_t cwnd_in; + bool ss_in; + uint64_t curr_rtt_usec_out; + uint64_t ewma_rtt_usec_out; + uint64_t min_rtt_usec_out; +} rtt_vec_t; + +static void +run_rtt_test_vec(congestion_control_t *cc, + rtt_vec_t *vec, size_t vec_len) +{ + for (size_t i = 0; i < vec_len; i++) { + enqueue_timestamp(cc->sendme_pending_timestamps, + vec[i].sent_usec_in); + } + + for (size_t i = 0; i < vec_len; i++) { + cc->cwnd = vec[i].cwnd_in; + cc->in_slow_start = vec[i].ss_in; + uint64_t curr_rtt_usec = congestion_control_update_circuit_rtt(cc, + vec[i].got_sendme_usec_in); + + tt_int_op(curr_rtt_usec, OP_EQ, vec[i].curr_rtt_usec_out); + tt_int_op(cc->min_rtt_usec, OP_EQ, vec[i].min_rtt_usec_out); + tt_int_op(cc->ewma_rtt_usec, OP_EQ, vec[i].ewma_rtt_usec_out); + } + done: + is_monotime_clock_broken = false; +} + +/** + * This test validates current, EWMA, and minRTT calculation + * from Sections 2.1 of Prop#324. + * + * We also do NOT exercise the sendme pacing code here. See + * test_sendme_is_next() for that, in test_sendme.c. + */ +void +test_congestion_control_rtt(void *arg) +{ + (void)arg; + rtt_vec_t vect1[] = { + {100000, 200000, 124, 1, 100000, 100000, 100000}, + {200000, 300000, 124, 1, 100000, 100000, 100000}, + {350000, 500000, 124, 1, 150000, 133333, 100000}, + {500000, 550000, 124, 1, 50000, 77777, 77777}, + {600000, 700000, 124, 1, 100000, 92592, 77777}, + {700000, 750000, 124, 1, 50000, 64197, 64197}, + {750000, 875000, 124, 0, 125000, 104732, 104732}, + {875000, 900000, 124, 0, 25000, 51577, 104732}, + {900000, 950000, 200, 0, 50000, 50525, 50525} + }; + + circuit_params_t params; + congestion_control_t *cc = NULL; + + params.cc_enabled = 1; + params.sendme_inc_cells = TLS_RECORD_MAX_CELLS; + cc_alg = CC_ALG_VEGAS; + + cc = congestion_control_new(¶ms, CC_PATH_EXIT); + run_rtt_test_vec(cc, vect1, sizeof(vect1)/sizeof(rtt_vec_t)); + congestion_control_free(cc); + + return; +} + +/* =========== Vegas CWND Test Vectors ============== */ + +typedef struct cwnd_vec { + uint64_t sent_usec_in; + uint64_t got_sendme_usec_in; + bool or_conn_blocked_in; + uint64_t inflight_in; + uint64_t ewma_rtt_usec_out; + uint64_t min_rtt_usec_out; + uint64_t cwnd_out; + bool in_slow_start_out; + bool cwnd_full_out; + bool blocked_chan_out; +} cwnd_vec_t; + +static void +run_vegas_cwnd_test_vec(congestion_control_t *cc, + circuit_t *circ, + cwnd_vec_t *vec, size_t vec_len) +{ + for (size_t i = 0; i < vec_len; i++) { + enqueue_timestamp(cc->sendme_pending_timestamps, + vec[i].sent_usec_in); + } + + for (size_t i = 0; i < vec_len; i++) { + log_notice(LD_CIRC, "Step %d", (int)i); + monotime_set_mock_time_nsec(vec[i].got_sendme_usec_in*1000); + circ->circuit_blocked_on_p_chan = vec[i].or_conn_blocked_in; + cc->inflight = vec[i].inflight_in; + + congestion_control_vegas_process_sendme(cc, circ, NULL); + + /* If the or conn was blocked, ensure we updated our + * CC state */ + if (vec[i].or_conn_blocked_in) { + tt_int_op(cc->next_cc_event, OP_EQ, CWND_UPDATE_RATE(cc)); + } + + tt_int_op(cc->ewma_rtt_usec, OP_EQ, vec[i].ewma_rtt_usec_out); + tt_int_op(cc->min_rtt_usec, OP_EQ, vec[i].min_rtt_usec_out); + tt_int_op(cc->cwnd, OP_EQ, vec[i].cwnd_out); + + tt_int_op(cc->in_slow_start, OP_EQ, vec[i].in_slow_start_out); + tt_int_op(cc->cwnd_full, OP_EQ, vec[i].cwnd_full_out); + tt_int_op(cc->blocked_chan, OP_EQ, vec[i].blocked_chan_out); + } + + done: + is_monotime_clock_broken = false; +} + +/** + * This test validates congestion window updates for the + * TOR_VEGAS congestion control algorithm, from Section 3.3 + * of Prop#324. + * + * It tests updates as a function of the timestamp of the + * cell that would trigger a sendme and the sendme arrival + * timestamp, and as a function of orconn blocking. + * + * It ensures that at least one test vector caused a cwnd update + * due to a blocked OR connection. The orconn blocking logic is + * simulated -- we do NOT actually exercise the orconn code here. + * + * We also do NOT exercise the sendme pacing code here. See + * test_sendme_is_next() for that, in test_sendme.c. + * + * We also do NOT exercise the negotiation code here. See + * test_ntor3_handshake() for that, in test_ntor_v3.c. + */ +void +test_congestion_control_vegas_cwnd(void *arg) +{ + (void)arg; + circuit_params_t params; + /* Replay of RTT edge case checks, plus some extra to exit + * slow start via RTT, and exercise full/not full */ + cwnd_vec_t vect1[] = { + {100000, 200000, 0, 124, 100000, 100000, 155, 1, 0, 0}, + {200000, 300000, 0, 155, 100000, 100000, 186, 1, 1, 0}, + {350000, 500000, 0, 186, 133333, 100000, 217, 1, 1, 0}, + {500000, 550000, 0, 217, 77777, 77777, 248, 1, 1, 0}, + {600000, 700000, 0, 248, 92592, 77777, 279, 1, 1, 0}, + {700000, 750000, 0, 279, 64197, 64197, 310, 1, 0, 0}, // Fullness expiry + {750000, 875000, 0, 310, 104732, 64197, 341, 1, 1, 0}, + {875000, 900000, 0, 341, 51577, 51577, 372, 1, 1, 0}, + {900000, 950000, 0, 279, 50525, 50525, 403, 1, 1, 0}, + {950000, 1000000, 0, 279, 50175, 50175, 434, 1, 1, 0}, + {1000000, 1050000, 0, 279, 50058, 50058, 465, 1, 1, 0}, + {1050000, 1100000, 0, 279, 50019, 50019, 496, 1, 1, 0}, + {1100000, 1150000, 0, 279, 50006, 50006, 527, 1, 1, 0}, + {1150000, 1200000, 0, 279, 50002, 50002, 558, 1, 1, 0}, + {1200000, 1250000, 0, 550, 50000, 50000, 589, 1, 1, 0}, + {1250000, 1300000, 0, 550, 50000, 50000, 620, 1, 0, 0}, // Fullness expiry + {1300000, 1350000, 0, 550, 50000, 50000, 635, 1, 1, 0}, + {1350000, 1400000, 0, 550, 50000, 50000, 650, 1, 1, 0}, + {1400000, 1450000, 0, 150, 50000, 50000, 650, 1, 0, 0}, // cwnd not full + {1450000, 1500000, 0, 150, 50000, 50000, 650, 1, 0, 0}, // cwnd not full + {1500000, 1550000, 0, 550, 50000, 50000, 664, 1, 1, 0}, // cwnd full + {1500000, 1600000, 0, 550, 83333, 50000, 584, 0, 1, 0}, // gamma exit + {1600000, 1650000, 0, 550, 61111, 50000, 585, 0, 1, 0}, // alpha + {1650000, 1700000, 0, 550, 53703, 50000, 586, 0, 1, 0}, + {1700000, 1750000, 0, 100, 51234, 50000, 586, 0, 0, 0}, // alpha, not full + {1750000, 1900000, 0, 100, 117078, 50000, 559, 0, 0, 0}, // delta, not full + {1900000, 2000000, 0, 100, 105692, 50000, 558, 0, 0, 0}, // beta, not full + {2000000, 2075000, 0, 500, 85230, 50000, 558, 0, 1, 0}, // no change + {2075000, 2125000, 1, 500, 61743, 50000, 557, 0, 1, 1}, // beta, blocked + {2125000, 2150000, 0, 500, 37247, 37247, 558, 0, 1, 0}, // alpha + {2150000, 2350000, 0, 500, 145749, 37247, 451, 0, 1, 0} // delta + }; + /* Test exiting slow start via blocked orconn */ + cwnd_vec_t vect2[] = { + {100000, 200000, 0, 124, 100000, 100000, 155, 1, 0, 0}, + {200000, 300000, 0, 155, 100000, 100000, 186, 1, 1, 0}, + {350000, 500000, 0, 186, 133333, 100000, 217, 1, 1, 0}, + {500000, 550000, 1, 217, 77777, 77777, 403, 0, 1, 1}, // ss exit, blocked + {600000, 700000, 0, 248, 92592, 77777, 404, 0, 1, 0}, // alpha + {700000, 750000, 1, 404, 64197, 64197, 403, 0, 0, 1}, // blocked beta + {750000, 875000, 0, 403, 104732, 64197, 404, 0, 1, 0} + }; + /* Real upload 1 */ + cwnd_vec_t vect3[] = { + { 18258527, 19002938, 0, 83, 744411, 744411, 155, 1, 0, 0 }, + { 18258580, 19254257, 0, 52, 911921, 744411, 186, 1, 1, 0 }, + { 20003224, 20645298, 0, 164, 732023, 732023, 217, 1, 1, 0 }, + { 20003367, 21021444, 0, 133, 922725, 732023, 248, 1, 1, 0 }, + { 20003845, 21265508, 0, 102, 1148683, 732023, 279, 1, 1, 0 }, + { 20003975, 21429157, 0, 71, 1333015, 732023, 310, 1, 0, 0 }, + { 20004309, 21707677, 0, 40, 1579917, 732023, 310, 1, 0, 0 } + }; + /* Real upload 2 */ + cwnd_vec_t vect4[] = { + { 358297091, 358854163, 0, 83, 557072, 557072, 155, 1, 0, 0 }, + { 358297649, 359123845, 0, 52, 736488, 557072, 186, 1, 1, 0 }, + { 359492879, 359995330, 0, 186, 580463, 557072, 217, 1, 1, 0 }, + { 359493043, 360489243, 0, 217, 857621, 557072, 248, 1, 1, 0 }, + { 359493232, 360489673, 0, 248, 950167, 557072, 279, 1, 1, 0 }, + { 359493795, 360489971, 0, 279, 980839, 557072, 310, 1, 0, 0 }, + { 359493918, 360490248, 0, 310, 991166, 557072, 341, 1, 1, 0 }, + { 359494029, 360716465, 0, 341, 1145346, 557072, 372, 1, 1, 0 }, + { 359996888, 360948867, 0, 372, 1016434, 557072, 403, 1, 1, 0 }, + { 359996979, 360949330, 0, 403, 973712, 557072, 434, 1, 1, 0 }, + { 360489528, 361113615, 0, 434, 740628, 557072, 465, 1, 1, 0 }, + { 360489656, 361281604, 0, 465, 774841, 557072, 496, 1, 1, 0 }, + { 360489837, 361500461, 0, 496, 932029, 557072, 482, 0, 1, 0 }, + { 360489963, 361500631, 0, 482, 984455, 557072, 482, 0, 1, 0 }, + { 360490117, 361842481, 0, 482, 1229727, 557072, 481, 0, 1, 0 } + }; + + congestion_control_t *cc = NULL; + channel_t dummy_channel = {0}; + + MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock); + testing_enable_reproducible_rng(); + + monotime_init(); + monotime_enable_test_mocking(); + monotime_set_mock_time_nsec(0); + + dummy_channel.cmux = circuitmux_alloc(); + circuit_t *circ = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, + &dummy_channel)); + circ->purpose = CIRCUIT_PURPOSE_OR; + + params.cc_enabled = 1; + params.sendme_inc_cells = TLS_RECORD_MAX_CELLS; + cc_alg = CC_ALG_VEGAS; + + cc = congestion_control_new(¶ms, CC_PATH_EXIT); + run_vegas_cwnd_test_vec(cc, circ, vect1, + sizeof(vect1)/sizeof(cwnd_vec_t)); + congestion_control_free(cc); + + cc = congestion_control_new(¶ms, CC_PATH_EXIT); + run_vegas_cwnd_test_vec(cc, circ, vect2, + sizeof(vect2)/sizeof(cwnd_vec_t)); + congestion_control_free(cc); + + cc = congestion_control_new(¶ms, CC_PATH_EXIT); + run_vegas_cwnd_test_vec(cc, circ, vect3, + sizeof(vect3)/sizeof(cwnd_vec_t)); + congestion_control_free(cc); + + cc = congestion_control_new(¶ms, CC_PATH_EXIT); + run_vegas_cwnd_test_vec(cc, circ, vect4, + sizeof(vect4)/sizeof(cwnd_vec_t)); + congestion_control_free(cc); + + //done: + circuitmux_free(dummy_channel.cmux); + return; +} + +#define TEST_CONGESTION_CONTROL(name, flags) \ + { #name, test_##name, (flags), NULL, NULL } + +struct testcase_t congestion_control_tests[] = { + TEST_CONGESTION_CONTROL(congestion_control_clock, TT_FORK), + TEST_CONGESTION_CONTROL(congestion_control_rtt, TT_FORK), + TEST_CONGESTION_CONTROL(congestion_control_vegas_cwnd, TT_FORK), + END_OF_TESTCASES +}; diff --git a/src/test/test_hs_client.c b/src/test/test_hs_client.c index f873d90212..a02dca1b60 100644 --- a/src/test/test_hs_client.c +++ b/src/test/test_hs_client.c @@ -15,6 +15,7 @@ #define CIRCUITLIST_PRIVATE #define CONNECTION_PRIVATE #define CRYPT_PATH_PRIVATE +#define TOR_CONGESTION_CONTROL_COMMON_PRIVATE #include "test/test.h" #include "test/test_helpers.h" @@ -54,7 +55,7 @@ #include "core/or/origin_circuit_st.h" #include "core/or/socks_request_st.h" -#define TOR_CONGESTION_CONTROL_PRIVATE +#include "core/or/congestion_control_st.h" #include "core/or/congestion_control_common.h" static int diff --git a/src/test/test_hs_descriptor.c b/src/test/test_hs_descriptor.c index d96048a0f6..89815f4858 100644 --- a/src/test/test_hs_descriptor.c +++ b/src/test/test_hs_descriptor.c @@ -7,6 +7,7 @@ */ #define HS_DESCRIPTOR_PRIVATE +#define TOR_CONGESTION_CONTROL_COMMON_PRIVATE #include "lib/crypt_ops/crypto_ed25519.h" #include "lib/crypt_ops/crypto_format.h" @@ -25,6 +26,7 @@ #include "test/rng_test_helpers.h" #define TOR_CONGESTION_CONTROL_PRIVATE +#include "core/or/congestion_control_st.h" #include "core/or/congestion_control_common.h" #ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS @@ -914,30 +916,21 @@ test_validate_sendme(void *arg) { (void)arg; - /* Test basic operation: factors of 2X in either direction are OK */ + /* Test basic operation: +/- 1 in either direction are OK */ cc_sendme_inc = 31; - tt_assert(congestion_control_validate_sendme_increment(15)); - tt_assert(congestion_control_validate_sendme_increment(62)); + tt_assert(congestion_control_validate_sendme_increment(30)); + tt_assert(congestion_control_validate_sendme_increment(32)); - /* Test basic operation: Exceeding 2X fails */ + /* Test basic operation: Exceeding +/- 1 fails */ cc_sendme_inc = 31; - tt_assert(!congestion_control_validate_sendme_increment(14)); - tt_assert(!congestion_control_validate_sendme_increment(63)); + tt_assert(!congestion_control_validate_sendme_increment(29)); + tt_assert(!congestion_control_validate_sendme_increment(33)); /* Test potential overflow conditions */ - cc_sendme_inc = 129; + cc_sendme_inc = 254; tt_assert(congestion_control_validate_sendme_increment(255)); - tt_assert(congestion_control_validate_sendme_increment(64)); - tt_assert(!congestion_control_validate_sendme_increment(63)); - - cc_sendme_inc = 127; - tt_assert(!congestion_control_validate_sendme_increment(255)); - tt_assert(congestion_control_validate_sendme_increment(254)); - - cc_sendme_inc = 255; - tt_assert(congestion_control_validate_sendme_increment(255)); - tt_assert(congestion_control_validate_sendme_increment(127)); - tt_assert(!congestion_control_validate_sendme_increment(126)); + tt_assert(congestion_control_validate_sendme_increment(253)); + tt_assert(!congestion_control_validate_sendme_increment(252)); /* Test 0 case */ cc_sendme_inc = 1; diff --git a/src/test/test_ntor_v3.c b/src/test/test_ntor_v3.c index 1d06403076..0d51c684a0 100644 --- a/src/test/test_ntor_v3.c +++ b/src/test/test_ntor_v3.c @@ -14,6 +14,8 @@ #include "core/or/extend_info_st.h" #include "core/or/crypt_path_st.h" #define TOR_CONGESTION_CONTROL_PRIVATE +#define TOR_CONGESTION_CONTROL_COMMON_PRIVATE +#include "core/or/congestion_control_st.h" #include "core/or/congestion_control_common.h" #include "app/config/config.h" @@ -262,6 +264,7 @@ test_ntor3_handshake(void *arg) tt_int_op(serv_params.cc_enabled, OP_EQ, 0); /* client off, serv on -> off */ + congestion_control_set_cc_disabled(); serv_ns_params.cc_enabled = 1; run_full_handshake(&serv_ns_params, &client_params, &serv_params); tt_int_op(client_params.cc_enabled, OP_EQ, 0);