Merge branch 'unixninja_ticket15989_squashed'

This commit is contained in:
Nick Mathewson 2016-01-08 15:52:22 -08:00
commit 95f5910810
10 changed files with 94 additions and 16 deletions

9
changes/ticket15989 Normal file
View File

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

View File

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

View File

@ -3458,8 +3458,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) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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. " "Heartbeat: Accounting enabled. Sent: %s, Received: %s, Used: %s / "
"The current accounting interval ends on %s, in %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 */