Commit 997f779a authored by Matthew Finkel's avatar Matthew Finkel Committed by Nick Mathewson
Browse files

Add new DirCache configuration option

This will give relay operators the ability of disabling the caching of
directory data. In general, this should not be necessary, but on some
lower-resource systems it may beneficial.
parent e0bd6cde
......@@ -1987,6 +1987,12 @@ if DirPort is non-zero):
except that port specifiers are ignored. Any address not matched by
some entry in the policy is accepted.
[[DirCache]] **DirCache** **0**|**1**::
When this option is set, Tor caches all current directory documents and
accepts client requests for them. Setting DirPort is not required for this,
because clients connect via the ORPort by default. Setting either DirPort
or BridgeRelay and setting DirCache to 0 is not supported. (Default: 1)
DIRECTORY AUTHORITY SERVER OPTIONS
----------------------------------
......
......@@ -222,6 +222,7 @@ static config_var_t option_vars_[] = {
V(DirPortFrontPage, FILENAME, NULL),
VAR("DirReqStatistics", BOOL, DirReqStatistics_option, "1"),
VAR("DirAuthority", LINELIST, DirAuthorities, NULL),
V(DirCache, BOOL, "1"),
V(DirAuthorityFallbackRate, DOUBLE, "1.0"),
V(DisableAllSwap, BOOL, "0"),
V(DisableDebuggerAttachment, BOOL, "1"),
......@@ -3457,6 +3458,24 @@ options_validate(or_options_t *old_options, or_options_t *options,
REJECT("AccountingRule must be 'sum' or 'max'");
}
if (options->DirPort_set && !options->DirCache) {
REJECT("DirPort configured but DirCache disabled. DirPort requires "
"DirCache.");
}
if (options->BridgeRelay && !options->DirCache) {
REJECT("We're a bridge but DirCache is disabled. BridgeRelay requires "
"DirCache.");
}
if (server_mode(options)) {
char *msg = NULL;
if (have_enough_mem_for_dircache(options, 0, &msg)) {
log_warn(LD_CONFIG, "%s", msg);
tor_free(msg);
}
}
if (options->HTTPProxy) { /* parse it now */
if (tor_addr_port_lookup(options->HTTPProxy,
&options->HTTPProxyAddr, &options->HTTPProxyPort) < 0)
......@@ -4065,6 +4084,48 @@ compute_real_max_mem_in_queues(const uint64_t val, int log_guess)
}
}
/* If we have less than 300 MB suggest disabling dircache */
#define DIRCACHE_MIN_MB_BANDWIDTH 300
#define DIRCACHE_MIN_BANDWIDTH (DIRCACHE_MIN_MB_BANDWIDTH*ONE_MEGABYTE)
#define STRINGIFY(val) #val
/** Create a warning message for emitting if we are a dircache but may not have
* enough system memory, or if we are not a dircache but probably should be.
* Return -1 when a message is returned in *msg*, else return 0. */
STATIC int
have_enough_mem_for_dircache(const or_options_t *options, size_t total_mem,
char **msg)
{
*msg = NULL;
if (total_mem == 0) {
if (get_total_system_memory(&total_mem) < 0)
total_mem = options->MaxMemInQueues;
}
if (options->DirCache) {
if (total_mem < DIRCACHE_MIN_BANDWIDTH) {
if (options->BridgeRelay) {
*msg = strdup("Running a Bridge with less than "
STRINGIFY(DIRCACHE_MIN_MB_BANDWIDTH) " MB of memory is "
"not recommended.");
} else {
*msg = strdup("Being a directory cache (default) with less than "
STRINGIFY(DIRCACHE_MIN_MB_BANDWIDTH) " MB of memory is "
"not recommended and may consume most of the available "
"resources, consider disabling this functionality by "
"setting the DirCache option to 0.");
}
}
} else {
if (total_mem >= DIRCACHE_MIN_BANDWIDTH) {
*msg = strdup("DirCache is disabled and we are configured as a "
"relay. This may disqualify us from becoming a guard in the "
"future.");
}
}
return *msg == NULL ? 0 : -1;
}
#undef STRINGIFY
/** Helper: return true iff s1 and s2 are both NULL, or both non-NULL
* equal strings. */
static int
......
......@@ -158,6 +158,8 @@ STATIC int parse_dir_authority_line(const char *line,
dirinfo_type_t required_type,
int validate_only);
STATIC int parse_dir_fallback_line(const char *line, int validate_only);
STATIC int have_enough_mem_for_dircache(const or_options_t *options,
size_t total_mem, char **msg);
#endif
#endif
......
......@@ -3969,6 +3969,10 @@ typedef struct {
/** Should we fetch our dir info at the start of the consensus period? */
int FetchDirInfoExtraEarly;
int DirCache; /**< Cache all directory documents and accept requests via
* tunnelled dir conns from clients. If 1, enabled (default);
* If 0, disabled. */
char *VirtualAddrNetworkIPv4; /**< Address and mask to hand out for virtual
* MAPADDRESS requests for IPv4 addresses */
char *VirtualAddrNetworkIPv6; /**< Address and mask to hand out for virtual
......
......@@ -1176,7 +1176,9 @@ router_should_be_directory_server(const or_options_t *options, int dir_port)
int
dir_server_mode(const or_options_t *options)
{
return (server_mode(options) || options->DirPort_set) &&
if (!options->DirCache)
return 0;
return (server_mode(options) || options->DirPort_set) &&
router_should_be_directory_server(options, 0);
}
......
......@@ -69,22 +69,29 @@ clear_log_messages(void)
messages = NULL;
}
#define setup_options(opt,dflt) \
do { \
opt = options_new(); \
opt->command = CMD_RUN_TOR; \
options_init(opt); \
\
dflt = config_dup(&options_format, opt); \
clear_log_messages(); \
} while (0)
static void
test_options_validate_impl(const char *configuration,
const char *expect_errmsg,
int expect_log_severity,
const char *expect_log)
{
or_options_t *opt = options_new();
or_options_t *opt=NULL;
or_options_t *dflt;
config_line_t *cl=NULL;
char *msg=NULL;
int r;
opt->command = CMD_RUN_TOR;
options_init(opt);
dflt = config_dup(&options_format, opt);
clear_log_messages();
setup_options(opt, dflt);
r = config_get_lines(configuration, &cl, 1);
tt_int_op(r, OP_EQ, 0);
......@@ -159,12 +166,110 @@ test_options_validate(void *arg)
"ServerTransportOptions did not parse",
LOG_WARN, "\"slingsnappy\" is not a k=v");
WANT_ERR("DirPort 8080\nDirCache 0",
"DirPort configured but DirCache disabled.");
WANT_ERR("BridgeRelay 1\nDirCache 0",
"We're a bridge but DirCache is disabled.");
clear_log_messages();
return;
}
#define MEGABYTEIFY(mb) (U64_LITERAL(mb) << 20)
static void
test_have_enough_mem_for_dircache(void *arg)
{
(void)arg;
or_options_t *opt=NULL;
or_options_t *dflt;
config_line_t *cl=NULL;
char *msg=NULL;;
int r;
const char *configuration = "ORPort 8080\nDirCache 1", *expect_errmsg;
setup_options(opt, dflt);
setup_log_callback();
(void)dflt;
r = config_get_lines(configuration, &cl, 1);
tt_int_op(r, OP_EQ, 0);
r = config_assign(&options_format, opt, cl, 0, 0, &msg);
tt_int_op(r, OP_EQ, 0);
/* 300 MB RAM available, DirCache enabled */
r = have_enough_mem_for_dircache(opt, MEGABYTEIFY(300), &msg);
tt_int_op(r, OP_EQ, 0);
tt_assert(!msg);
/* 200 MB RAM available, DirCache enabled */
r = have_enough_mem_for_dircache(opt, MEGABYTEIFY(200), &msg);
tt_int_op(r, OP_EQ, -1);
expect_errmsg = "Being a directory cache (default) with less than ";
if (!strstr(msg, expect_errmsg)) {
TT_DIE(("Expected error message <%s> from <%s>, but got <%s>.",
expect_errmsg, configuration, msg));
}
tor_free(msg);
configuration = "ORPort 8080\nDirCache 1\nBridgeRelay 1";
r = config_get_lines(configuration, &cl, 1);
tt_int_op(r, OP_EQ, 0);
r = config_assign(&options_format, opt, cl, 0, 0, &msg);
tt_int_op(r, OP_EQ, 0);
/* 300 MB RAM available, DirCache enabled, Bridge */
r = have_enough_mem_for_dircache(opt, MEGABYTEIFY(300), &msg);
tt_int_op(r, OP_EQ, 0);
tt_assert(!msg);
/* 200 MB RAM available, DirCache enabled, Bridge */
r = have_enough_mem_for_dircache(opt, MEGABYTEIFY(200), &msg);
tt_int_op(r, OP_EQ, -1);
expect_errmsg = "Running a Bridge with less than ";
if (!strstr(msg, expect_errmsg)) {
TT_DIE(("Expected error message <%s> from <%s>, but got <%s>.",
expect_errmsg, configuration, msg));
}
tor_free(msg);
configuration = "ORPort 8080\nDirCache 0";
r = config_get_lines(configuration, &cl, 1);
tt_int_op(r, OP_EQ, 0);
r = config_assign(&options_format, opt, cl, 0, 0, &msg);
tt_int_op(r, OP_EQ, 0);
/* 200 MB RAM available, DirCache disabled */
r = have_enough_mem_for_dircache(opt, MEGABYTEIFY(200), &msg);
tt_int_op(r, OP_EQ, 0);
tt_assert(!msg);
/* 300 MB RAM available, DirCache disabled */
r = have_enough_mem_for_dircache(opt, MEGABYTEIFY(300), &msg);
tt_int_op(r, OP_EQ, -1);
expect_errmsg = "DirCache is disabled and we are configured as a ";
if (!strstr(msg, expect_errmsg)) {
TT_DIE(("Expected error message <%s> from <%s>, but got <%s>.",
expect_errmsg, configuration, msg));
}
tor_free(msg);
clear_log_messages();
done:
if (msg)
tor_free(msg);
tor_free(dflt);
tor_free(opt);
tor_free(cl);
return;
}
struct testcase_t options_tests[] = {
{ "validate", test_options_validate, TT_FORK, NULL, NULL },
{ "mem_dircache", test_have_enough_mem_for_dircache, TT_FORK, NULL, NULL },
END_OF_TESTCASES
};
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment