Browse Source

Added AccountRule in and AccountingRule out options

unixninja92 8 years ago
parent
commit
4f0e28977d
10 changed files with 94 additions and 16 deletions
  1. 9 0
      changes/ticket15989
  2. 4 2
      doc/tor.1.txt
  3. 5 1
      src/or/config.c
  4. 18 2
      src/or/hibernate.c
  5. 1 0
      src/or/hibernate.h
  6. 4 2
      src/or/or.h
  7. 5 2
      src/or/router.c
  8. 18 4
      src/or/status.c
  9. 26 0
      src/test/test_accounting.c
  10. 4 3
      src/test/test_status.c

+ 9 - 0
changes/ticket15989

@@ -0,0 +1,9 @@
+  o Minor enhancement (accounting):
+    - Added two modes to AccountingRule in torrc for
+      limiting just input or just output.
+      Closes ticket 15989; patch from "unixninja92".
+
+  o Minor bugfixe (accounting):
+    - The max bandwidth when using AccountRule sum
+      is now correctly logged.
+      Patch from "unixninja92".

+ 4 - 2
doc/tor.1.txt

@@ -1773,12 +1773,14 @@ is non-zero):
     of the time, which is more useful than a set of slow servers that are
     of the time, which is more useful than a set of slow servers that are
     always "available".
     always "available".
 
 
-[[AccountingRule]] **AccountingRule** **sum**|**max**::
+[[AccountingRule]] **AccountingRule** **sum**|**max**|**in**|**out**::
     How we determine when our AccountingMax has been reached (when we
     How we determine when our AccountingMax has been reached (when we
     should hibernate) during a time interval. Set to "max" to calculate
     should hibernate) during a time interval. Set to "max" to calculate
     using the higher of either the sent or received bytes (this is the
     using the higher of either the sent or received bytes (this is the
     default functionality). Set to "sum" to calculate using the sent
     default functionality). Set to "sum" to calculate using the sent
-    plus received bytes. (Default: max)
+    plus received bytes. Set to "in" to calculate using only the
+    received bytes. Set to "out" to calculate using only the sent bytes.
+    (Default: max)
 
 
 [[AccountingStart]] **AccountingStart** **day**|**week**|**month** [__day__] __HH:MM__::
 [[AccountingStart]] **AccountingStart** **day**|**week**|**month** [__day__] __HH:MM__::
     Specify how long accounting periods last. If **month** is given, each
     Specify how long accounting periods last. If **month** is given, each

+ 5 - 1
src/or/config.c

@@ -3454,8 +3454,12 @@ options_validate(or_options_t *old_options, or_options_t *options,
       options->AccountingRule = ACCT_SUM;
       options->AccountingRule = ACCT_SUM;
     else if (!strcmp(options->AccountingRule_option, "max"))
     else if (!strcmp(options->AccountingRule_option, "max"))
       options->AccountingRule = ACCT_MAX;
       options->AccountingRule = ACCT_MAX;
+    else if (!strcmp(options->AccountingRule_option, "in"))
+      options->AccountingRule = ACCT_IN;
+    else if (!strcmp(options->AccountingRule_option, "out"))
+      options->AccountingRule = ACCT_OUT;
     else
     else
-      REJECT("AccountingRule must be 'sum' or 'max'");
+      REJECT("AccountingRule must be 'sum', 'max', 'in', or 'out'");
   }
   }
 
 
   if (options->DirPort_set && !options->DirCache) {
   if (options->DirPort_set && !options->DirCache) {

+ 18 - 2
src/or/hibernate.c

@@ -412,11 +412,15 @@ configure_accounting(time_t now)
 
 
 /** Return the relevant number of bytes sent/received this interval
 /** Return the relevant number of bytes sent/received this interval
  * based on the set AccountingRule */
  * based on the set AccountingRule */
-static uint64_t
+uint64_t
 get_accounting_bytes(void)
 get_accounting_bytes(void)
 {
 {
   if (get_options()->AccountingRule == ACCT_SUM)
   if (get_options()->AccountingRule == ACCT_SUM)
     return n_bytes_read_in_interval+n_bytes_written_in_interval;
     return n_bytes_read_in_interval+n_bytes_written_in_interval;
+  else if (get_options()->AccountingRule == ACCT_IN)
+    return n_bytes_read_in_interval;
+  else if (get_options()->AccountingRule == ACCT_OUT)
+    return n_bytes_written_in_interval;
   else
   else
     return MAX(n_bytes_read_in_interval, n_bytes_written_in_interval);
     return MAX(n_bytes_read_in_interval, n_bytes_written_in_interval);
 }
 }
@@ -1010,7 +1014,7 @@ getinfo_helper_accounting(control_connection_t *conn,
     else
     else
       *answer = tor_strdup("awake");
       *answer = tor_strdup("awake");
   } else if (!strcmp(question, "accounting/bytes")) {
   } else if (!strcmp(question, "accounting/bytes")) {
-    tor_asprintf(answer, U64_FORMAT" "U64_FORMAT,
+      tor_asprintf(answer, U64_FORMAT" "U64_FORMAT,
                  U64_PRINTF_ARG(n_bytes_read_in_interval),
                  U64_PRINTF_ARG(n_bytes_read_in_interval),
                  U64_PRINTF_ARG(n_bytes_written_in_interval));
                  U64_PRINTF_ARG(n_bytes_written_in_interval));
   } else if (!strcmp(question, "accounting/bytes-left")) {
   } else if (!strcmp(question, "accounting/bytes-left")) {
@@ -1022,6 +1026,18 @@ getinfo_helper_accounting(control_connection_t *conn,
         total_left = limit - total_bytes;
         total_left = limit - total_bytes;
       tor_asprintf(answer, U64_FORMAT" "U64_FORMAT,
       tor_asprintf(answer, U64_FORMAT" "U64_FORMAT,
                    U64_PRINTF_ARG(total_left), U64_PRINTF_ARG(total_left));
                    U64_PRINTF_ARG(total_left), U64_PRINTF_ARG(total_left));
+    } else if (get_options()->AccountingRule == ACCT_IN) {
+      uint64_t read_left = 0;
+      if (n_bytes_read_in_interval < limit)
+        read_left = limit - n_bytes_read_in_interval;
+      tor_asprintf(answer, U64_FORMAT" "U64_FORMAT,
+                   U64_PRINTF_ARG(read_left), U64_PRINTF_ARG(limit));
+    } else if (get_options()->AccountingRule == ACCT_OUT) {
+      uint64_t write_left = 0;
+      if (n_bytes_written_in_interval < limit)
+        write_left = limit - n_bytes_written_in_interval;
+      tor_asprintf(answer, U64_FORMAT" "U64_FORMAT,
+                   U64_PRINTF_ARG(limit), U64_PRINTF_ARG(write_left));
     } else {
     } else {
       uint64_t read_left = 0, write_left = 0;
       uint64_t read_left = 0, write_left = 0;
       if (n_bytes_read_in_interval < limit)
       if (n_bytes_read_in_interval < limit)

+ 1 - 0
src/or/hibernate.h

@@ -19,6 +19,7 @@ MOCK_DECL(int, accounting_is_enabled, (const or_options_t *options));
 int accounting_get_interval_length(void);
 int accounting_get_interval_length(void);
 MOCK_DECL(time_t, accounting_get_end_time, (void));
 MOCK_DECL(time_t, accounting_get_end_time, (void));
 void configure_accounting(time_t now);
 void configure_accounting(time_t now);
+uint64_t get_accounting_bytes(void);
 void accounting_run_housekeeping(time_t now);
 void accounting_run_housekeeping(time_t now);
 void accounting_add_bytes(size_t n_read, size_t n_written, int seconds);
 void accounting_add_bytes(size_t n_read, size_t n_written, int seconds);
 int accounting_record_bandwidth_usage(time_t now, or_state_t *state);
 int accounting_record_bandwidth_usage(time_t now, or_state_t *state);

+ 4 - 2
src/or/or.h

@@ -3893,9 +3893,11 @@ typedef struct {
                            * hibernate." */
                            * hibernate." */
   /** How do we determine when our AccountingMax has been reached?
   /** How do we determine when our AccountingMax has been reached?
    * "max" for when in or out reaches AccountingMax
    * "max" for when in or out reaches AccountingMax
-   * "sum" for when in plus out reaches AccountingMax */
+   * "sum" for when in plus out reaches AccountingMax
+   * "in"  for when in reaches AccountingMax
+   * "out" for when out reaches AccountingMax */
   char *AccountingRule_option;
   char *AccountingRule_option;
-  enum { ACCT_MAX, ACCT_SUM } AccountingRule;
+  enum { ACCT_MAX, ACCT_SUM, ACCT_IN, ACCT_OUT } AccountingRule;
 
 
   /** Base64-encoded hash of accepted passwords for the control system. */
   /** Base64-encoded hash of accepted passwords for the control system. */
   config_line_t *HashedControlPassword;
   config_line_t *HashedControlPassword;

+ 5 - 2
src/or/router.c

@@ -1133,10 +1133,13 @@ router_should_be_directory_server(const or_options_t *options, int dir_port)
   int new_choice=1;
   int new_choice=1;
   const char *reason = NULL;
   const char *reason = NULL;
 
 
-  if (accounting_is_enabled(options)) {
+  if (accounting_is_enabled(options) &&
+    get_options()->AccountingRule != ACCT_IN) {
     /* Don't spend bytes for directory traffic if we could end up hibernating,
     /* Don't spend bytes for directory traffic if we could end up hibernating,
      * but allow DirPort otherwise. Some people set AccountingMax because
      * but allow DirPort otherwise. Some people set AccountingMax because
-     * they're confused or to get statistics. */
+     * they're confused or to get statistics. Directory traffic has a much
+     * larger effect on output than input so there is no reason to turn it
+     * off if using AccountingRule in. */
     int interval_length = accounting_get_interval_length();
     int interval_length = accounting_get_interval_length();
     uint32_t effective_bw = get_effective_bwrate(options);
     uint32_t effective_bw = get_effective_bwrate(options);
     uint64_t acc_bytes;
     uint64_t acc_bytes;

+ 18 - 4
src/or/status.c

@@ -164,24 +164,38 @@ log_accounting(const time_t now, const or_options_t *options)
   or_state_t *state = get_or_state();
   or_state_t *state = get_or_state();
   char *acc_rcvd = bytes_to_usage(state->AccountingBytesReadInInterval);
   char *acc_rcvd = bytes_to_usage(state->AccountingBytesReadInInterval);
   char *acc_sent = bytes_to_usage(state->AccountingBytesWrittenInInterval);
   char *acc_sent = bytes_to_usage(state->AccountingBytesWrittenInInterval);
+  char *acc_used = bytes_to_usage(get_accounting_bytes());
   uint64_t acc_bytes = options->AccountingMax;
   uint64_t acc_bytes = options->AccountingMax;
   char *acc_max;
   char *acc_max;
   time_t interval_end = accounting_get_end_time();
   time_t interval_end = accounting_get_end_time();
   char end_buf[ISO_TIME_LEN + 1];
   char end_buf[ISO_TIME_LEN + 1];
   char *remaining = NULL;
   char *remaining = NULL;
-  if (options->AccountingRule == ACCT_SUM)
-    acc_bytes *= 2;
   acc_max = bytes_to_usage(acc_bytes);
   acc_max = bytes_to_usage(acc_bytes);
   format_local_iso_time(end_buf, interval_end);
   format_local_iso_time(end_buf, interval_end);
   remaining = secs_to_uptime(interval_end - now);
   remaining = secs_to_uptime(interval_end - now);
 
 
+  const char *acc_rule;
+  switch (options->AccountingRule) {
+    case ACCT_MAX: acc_rule = "max";
+    break;
+    case ACCT_SUM: acc_rule = "sum";
+    break;
+    case ACCT_OUT: acc_rule = "out";
+    break;
+    case ACCT_IN: acc_rule = "in";
+    break;
+    default: acc_rule = "max";
+    break;
+  }
+
   log_notice(LD_HEARTBEAT, "Heartbeat: Accounting enabled. "
   log_notice(LD_HEARTBEAT, "Heartbeat: Accounting enabled. "
-      "Sent: %s / %s, Received: %s / %s. The "
+      "Sent: %s, Received: %s, Used: %s / %s, Rule: %s. The "
       "current accounting interval ends on %s, in %s.",
       "current accounting interval ends on %s, in %s.",
-      acc_sent, acc_max, acc_rcvd, acc_max, end_buf, remaining);
+      acc_sent, acc_rcvd, acc_used, acc_max, acc_rule, end_buf, remaining);
 
 
   tor_free(acc_rcvd);
   tor_free(acc_rcvd);
   tor_free(acc_sent);
   tor_free(acc_sent);
+  tor_free(acc_used);
   tor_free(acc_max);
   tor_free(acc_max);
   tor_free(remaining);
   tor_free(remaining);
 }
 }

+ 26 - 0
src/test/test_accounting.c

@@ -61,6 +61,32 @@ test_accounting_limits(void *arg)
   fake_time += 1;
   fake_time += 1;
   consider_hibernation(fake_time);
   consider_hibernation(fake_time);
   tor_assert(we_are_hibernating() == 1);
   tor_assert(we_are_hibernating() == 1);
+
+  options->AccountingRule = ACCT_OUT;
+
+  accounting_add_bytes(100, 10, 1);
+  fake_time += 1;
+  consider_hibernation(fake_time);
+  tor_assert(we_are_hibernating() == 0);
+
+  accounting_add_bytes(0, 90, 1);
+  fake_time += 1;
+  consider_hibernation(fake_time);
+  tor_assert(we_are_hibernating() == 1);
+
+  options->AccountingMax = 300;
+  options->AccountingRule = ACCT_IN;
+
+  accounting_add_bytes(10, 100, 1);
+  fake_time += 1;
+  consider_hibernation(fake_time);
+  tor_assert(we_are_hibernating() == 0);
+
+  accounting_add_bytes(90, 0, 1);
+  fake_time += 1;
+  consider_hibernation(fake_time);
+  tor_assert(we_are_hibernating() == 1);
+
   goto done;
   goto done;
  done:
  done:
   NS_UNMOCK(get_or_state);
   NS_UNMOCK(get_or_state);

+ 4 - 3
src/test/test_status.c

@@ -707,12 +707,13 @@ NS(logv)(int severity, log_domain_mask_t domain,
       tt_ptr_op(strstr(funcname, "log_accounting"), OP_NE, NULL);
       tt_ptr_op(strstr(funcname, "log_accounting"), OP_NE, NULL);
       tt_ptr_op(suffix, OP_EQ, NULL);
       tt_ptr_op(suffix, OP_EQ, NULL);
       tt_str_op(format, OP_EQ,
       tt_str_op(format, OP_EQ,
-          "Heartbeat: Accounting enabled. Sent: %s / %s, Received: %s / %s. "
-          "The current accounting interval ends on %s, in %s.");
+          "Heartbeat: Accounting enabled. Sent: %s, Received: %s, Used: %s / "
+          "%s, Rule: %s. The current accounting interval ends on %s, in %s.");
       tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB");  /* acc_sent */
       tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB");  /* acc_sent */
-      tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB");  /* acc_max */
       tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB");  /* acc_rcvd */
       tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB");  /* acc_rcvd */
+      tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB");  /* acc_used */
       tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB");  /* acc_max */
       tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB");  /* acc_max */
+      tt_str_op(va_arg(ap, char *), OP_EQ, "max");  /* acc_rule */
       /* format_local_iso_time uses local tz, just check mins and secs. */
       /* format_local_iso_time uses local tz, just check mins and secs. */
       tt_ptr_op(strstr(va_arg(ap, char *), ":01:00"),
       tt_ptr_op(strstr(va_arg(ap, char *), ":01:00"),
                 OP_NE, NULL); /* end_buf */
                 OP_NE, NULL); /* end_buf */