소스 검색

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.
Matthew Finkel 9 년 전
부모
커밋
997f779a7f
6개의 변경된 파일186개의 추가작업 그리고 6개의 파일을 삭제
  1. 6 0
      doc/tor.1.txt
  2. 61 0
      src/or/config.c
  3. 2 0
      src/or/config.h
  4. 4 0
      src/or/or.h
  5. 3 1
      src/or/router.c
  6. 110 5
      src/test/test_options.c

+ 6 - 0
doc/tor.1.txt

@@ -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
 ----------------------------------

+ 61 - 0
src/or/config.c

@@ -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

+ 2 - 0
src/or/config.h

@@ -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

+ 4 - 0
src/or/or.h

@@ -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

+ 3 - 1
src/or/router.c

@@ -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);
 }
 

+ 110 - 5
src/test/test_options.c

@@ -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
 };