summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Goulet <dgoulet@torproject.org>2023-06-27 13:40:15 +0000
committerDavid Goulet <dgoulet@torproject.org>2023-06-27 13:40:15 +0000
commitbcbc5b5ba0b8d1a72128dd6d2fa8d350110944b4 (patch)
treeb408c9ae6dfaba9404785692c2a8f79dc7e251c8
parent633355a88e9c1f5b793e601e43e49b5cbb1fb731 (diff)
parenta945f3c506cbe58f88d8929b125d165b0b593902 (diff)
downloadtor-bcbc5b5ba0b8d1a72128dd6d2fa8d350110944b4.tar.gz
tor-bcbc5b5ba0b8d1a72128dd6d2fa8d350110944b4.zip
Merge branch 'bug40569+40709+40443' into 'main'
Update congestion control params and add test vectors See merge request tpo/core/tor!724
-rw-r--r--changes/ticket405694
-rw-r--r--changes/ticket407093
-rw-r--r--src/core/or/congestion_control_common.c58
-rw-r--r--src/core/or/congestion_control_common.h13
-rw-r--r--src/core/or/congestion_control_vegas.c18
-rw-r--r--src/test/include.am1
-rw-r--r--src/test/test.c1
-rw-r--r--src/test/test.h1
-rw-r--r--src/test/test_conflux_pool.c3
-rw-r--r--src/test/test_congestion_control.c390
-rw-r--r--src/test/test_hs_client.c3
-rw-r--r--src/test/test_hs_descriptor.c29
-rw-r--r--src/test/test_ntor_v3.c3
13 files changed, 471 insertions, 56 deletions
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.
@@ -398,6 +396,17 @@ congestion_control_set_cc_enabled(void)
}
/**
+ * 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.
*
* cc_alg is the negotiated congestion control algorithm.
@@ -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(&params, 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(&params, 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(&params, 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(&params, 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(&params, 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(&params, 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);