mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-30 23:53:32 +01:00
Add metric on uni/bidirectional connection usage.
This commit is contained in:
parent
520182579a
commit
5dfdf075ac
@ -848,6 +848,30 @@
|
|||||||
Mean number of circuits that are included in any of the deciles,
|
Mean number of circuits that are included in any of the deciles,
|
||||||
rounded up to the next integer.
|
rounded up to the next integer.
|
||||||
|
|
||||||
|
"conn-stats-end" YYYY-MM-DD HH:MM:SS (NSEC s) NL
|
||||||
|
[At most once]
|
||||||
|
|
||||||
|
YYYY-MM-DD HH:MM:SS defines the end of the included connection
|
||||||
|
statistics measurement interval of length NSEC seconds (86400
|
||||||
|
seconds by default).
|
||||||
|
|
||||||
|
A "conn-stats-end" line, as well as any other "conn-*" line,
|
||||||
|
is first added after the relay has been running for at least 24
|
||||||
|
hours.
|
||||||
|
|
||||||
|
"conn-bi-direct" BELOW,READ,WRITE,BOTH NL
|
||||||
|
[At most once]
|
||||||
|
|
||||||
|
Number of connections, split into 10-second intervals, that are
|
||||||
|
used uni-directionally or bi-directionally. Every 10 seconds,
|
||||||
|
we determine for every connection whether we read and wrote less
|
||||||
|
than a threshold of 20 KiB (BELOW), read at least 10 times more
|
||||||
|
than we wrote (READ), wrote at least 10 times more than we read
|
||||||
|
(WRITE), or read and wrote more than the threshold, but not 10
|
||||||
|
times more in either direction (BOTH). After classifying a
|
||||||
|
connection, read and write counters are reset for the next
|
||||||
|
10-second interval.
|
||||||
|
|
||||||
"exit-stats-end" YYYY-MM-DD HH:MM:SS (NSEC s) NL
|
"exit-stats-end" YYYY-MM-DD HH:MM:SS (NSEC s) NL
|
||||||
[At most once.]
|
[At most once.]
|
||||||
|
|
||||||
|
@ -200,6 +200,7 @@ static config_var_t _option_vars[] = {
|
|||||||
V(ClientOnly, BOOL, "0"),
|
V(ClientOnly, BOOL, "0"),
|
||||||
V(ConsensusParams, STRING, NULL),
|
V(ConsensusParams, STRING, NULL),
|
||||||
V(ConnLimit, UINT, "1000"),
|
V(ConnLimit, UINT, "1000"),
|
||||||
|
V(ConnStatistics, BOOL, "0"),
|
||||||
V(ConstrainedSockets, BOOL, "0"),
|
V(ConstrainedSockets, BOOL, "0"),
|
||||||
V(ConstrainedSockSize, MEMUNIT, "8192"),
|
V(ConstrainedSockSize, MEMUNIT, "8192"),
|
||||||
V(ContactInfo, STRING, NULL),
|
V(ContactInfo, STRING, NULL),
|
||||||
@ -1391,7 +1392,8 @@ options_act(or_options_t *old_options)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (options->CellStatistics || options->DirReqStatistics ||
|
if (options->CellStatistics || options->DirReqStatistics ||
|
||||||
options->EntryStatistics || options->ExitPortStatistics) {
|
options->EntryStatistics || options->ExitPortStatistics ||
|
||||||
|
options->ConnStatistics) {
|
||||||
time_t now = time(NULL);
|
time_t now = time(NULL);
|
||||||
if ((!old_options || !old_options->CellStatistics) &&
|
if ((!old_options || !old_options->CellStatistics) &&
|
||||||
options->CellStatistics)
|
options->CellStatistics)
|
||||||
@ -1405,6 +1407,9 @@ options_act(or_options_t *old_options)
|
|||||||
if ((!old_options || !old_options->ExitPortStatistics) &&
|
if ((!old_options || !old_options->ExitPortStatistics) &&
|
||||||
options->ExitPortStatistics)
|
options->ExitPortStatistics)
|
||||||
rep_hist_exit_stats_init(now);
|
rep_hist_exit_stats_init(now);
|
||||||
|
if ((!old_options || !old_options->ConnStatistics) &&
|
||||||
|
options->ConnStatistics)
|
||||||
|
rep_hist_conn_stats_init(now);
|
||||||
if (!old_options)
|
if (!old_options)
|
||||||
log_notice(LD_CONFIG, "Configured to measure statistics. Look for "
|
log_notice(LD_CONFIG, "Configured to measure statistics. Look for "
|
||||||
"the *-stats files that will first be written to the "
|
"the *-stats files that will first be written to the "
|
||||||
@ -1423,6 +1428,9 @@ options_act(or_options_t *old_options)
|
|||||||
if (old_options && old_options->ExitPortStatistics &&
|
if (old_options && old_options->ExitPortStatistics &&
|
||||||
!options->ExitPortStatistics)
|
!options->ExitPortStatistics)
|
||||||
rep_hist_exit_stats_term();
|
rep_hist_exit_stats_term();
|
||||||
|
if (old_options && old_options->ConnStatistics &&
|
||||||
|
!options->ConnStatistics)
|
||||||
|
rep_hist_conn_stats_term();
|
||||||
|
|
||||||
/* Check if we need to parse and add the EntryNodes config option. */
|
/* Check if we need to parse and add the EntryNodes config option. */
|
||||||
if (options->EntryNodes &&
|
if (options->EntryNodes &&
|
||||||
|
@ -2185,6 +2185,11 @@ connection_buckets_decrement(connection_t *conn, time_t now,
|
|||||||
|
|
||||||
if (!connection_is_rate_limited(conn))
|
if (!connection_is_rate_limited(conn))
|
||||||
return; /* local IPs are free */
|
return; /* local IPs are free */
|
||||||
|
|
||||||
|
if (conn->type == CONN_TYPE_OR)
|
||||||
|
rep_hist_note_or_conn_bytes(conn->global_identifier, num_read,
|
||||||
|
num_written, now);
|
||||||
|
|
||||||
if (num_read > 0) {
|
if (num_read > 0) {
|
||||||
rep_hist_note_bytes_read(num_read, now);
|
rep_hist_note_bytes_read(num_read, now);
|
||||||
}
|
}
|
||||||
|
@ -1204,6 +1204,11 @@ run_scheduled_events(time_t now)
|
|||||||
if (next_write && next_write < next_time_to_write_stats_files)
|
if (next_write && next_write < next_time_to_write_stats_files)
|
||||||
next_time_to_write_stats_files = next_write;
|
next_time_to_write_stats_files = next_write;
|
||||||
}
|
}
|
||||||
|
if (options->ConnStatistics) {
|
||||||
|
time_t next_write = rep_hist_conn_stats_write(time_to_write_stats_files);
|
||||||
|
if (next_write && next_write < next_time_to_write_stats_files)
|
||||||
|
next_time_to_write_stats_files = next_write;
|
||||||
|
}
|
||||||
time_to_write_stats_files = next_time_to_write_stats_files;
|
time_to_write_stats_files = next_time_to_write_stats_files;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2894,6 +2894,9 @@ typedef struct {
|
|||||||
/** If true, the user wants us to collect statistics on port usage. */
|
/** If true, the user wants us to collect statistics on port usage. */
|
||||||
int ExitPortStatistics;
|
int ExitPortStatistics;
|
||||||
|
|
||||||
|
/** If true, the user wants us to collect connection statistics. */
|
||||||
|
int ConnStatistics;
|
||||||
|
|
||||||
/** If true, the user wants us to collect cell statistics. */
|
/** If true, the user wants us to collect cell statistics. */
|
||||||
int CellStatistics;
|
int CellStatistics;
|
||||||
|
|
||||||
|
198
src/or/rephist.c
198
src/or/rephist.c
@ -7,7 +7,7 @@
|
|||||||
* \brief Basic history and "reputation" functionality to remember
|
* \brief Basic history and "reputation" functionality to remember
|
||||||
* which servers have worked in the past, how much bandwidth we've
|
* which servers have worked in the past, how much bandwidth we've
|
||||||
* been using, which ports we tend to want, and so on; further,
|
* been using, which ports we tend to want, and so on; further,
|
||||||
* exit port statistics and cell statistics.
|
* exit port statistics, cell statistics, and connection statistics.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
#include "or.h"
|
#include "or.h"
|
||||||
@ -2418,6 +2418,201 @@ rep_hist_buffer_stats_write(time_t now)
|
|||||||
return start_of_buffer_stats_interval + WRITE_STATS_INTERVAL;
|
return start_of_buffer_stats_interval + WRITE_STATS_INTERVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*** Connection statistics ***/
|
||||||
|
|
||||||
|
/** Start of the current connection stats interval or 0 if we're not
|
||||||
|
* collecting connection statistics. */
|
||||||
|
static time_t start_of_conn_stats_interval;
|
||||||
|
|
||||||
|
/** Initialize connection stats. */
|
||||||
|
void
|
||||||
|
rep_hist_conn_stats_init(time_t now)
|
||||||
|
{
|
||||||
|
start_of_conn_stats_interval = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BIDI_THRESHOLD 20480
|
||||||
|
|
||||||
|
#define BIDI_FACTOR 10
|
||||||
|
|
||||||
|
#define BIDI_INTERVAL 10
|
||||||
|
|
||||||
|
/* Start of next BIDI_INTERVAL second interval. */
|
||||||
|
static time_t bidi_next_interval = 0;
|
||||||
|
|
||||||
|
/* Number of connections that we read and wrote less than BIDI_THRESHOLD
|
||||||
|
* bytes from/to in BIDI_INTERVAL seconds. */
|
||||||
|
static uint32_t below_threshold = 0;
|
||||||
|
|
||||||
|
/* Number of connections that we read at least BIDI_FACTOR times more
|
||||||
|
* bytes from than we wrote to in BIDI_INTERVAL seconds. */
|
||||||
|
static uint32_t mostly_read = 0;
|
||||||
|
|
||||||
|
/* Number of connections that we wrote at least BIDI_FACTOR times more
|
||||||
|
* bytes to than we read from in BIDI_INTERVAL seconds. */
|
||||||
|
static uint32_t mostly_written = 0;
|
||||||
|
|
||||||
|
/* Number of connections that we read and wrote at least BIDI_THRESHOLD
|
||||||
|
* bytes from/to, but not BIDI_FACTOR times more in either direction in
|
||||||
|
* BIDI_INTERVAL seconds. */
|
||||||
|
static uint32_t both_read_and_written = 0;
|
||||||
|
|
||||||
|
/* Entry in a map from connection ID to the number of read and written
|
||||||
|
* bytes on this connection in a BIDI_INTERVAL second interval. */
|
||||||
|
typedef struct bidi_map_entry_t {
|
||||||
|
HT_ENTRY(bidi_map_entry_t) node;
|
||||||
|
uint64_t conn_id; /**< Connection ID */
|
||||||
|
size_t read; /**< Number of read bytes */
|
||||||
|
size_t written; /**< Number of written bytes */
|
||||||
|
} bidi_map_entry_t;
|
||||||
|
|
||||||
|
/** Map of OR connections together with the number of read and written
|
||||||
|
* bytes in the current BIDI_INTERVAL second interval. */
|
||||||
|
static HT_HEAD(bidimap, bidi_map_entry_t) bidi_map =
|
||||||
|
HT_INITIALIZER();
|
||||||
|
|
||||||
|
static int
|
||||||
|
bidi_map_ent_eq(const bidi_map_entry_t *a, const bidi_map_entry_t *b)
|
||||||
|
{
|
||||||
|
return a->conn_id == b->conn_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned
|
||||||
|
bidi_map_ent_hash(const bidi_map_entry_t *entry)
|
||||||
|
{
|
||||||
|
return (unsigned) entry->conn_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
HT_PROTOTYPE(bidimap, bidi_map_entry_t, node, bidi_map_ent_hash,
|
||||||
|
bidi_map_ent_eq);
|
||||||
|
HT_GENERATE(bidimap, bidi_map_entry_t, node, bidi_map_ent_hash,
|
||||||
|
bidi_map_ent_eq, 0.6, malloc, realloc, free);
|
||||||
|
|
||||||
|
static void
|
||||||
|
bidi_map_free(void)
|
||||||
|
{
|
||||||
|
bidi_map_entry_t **ptr, **next, *ent;
|
||||||
|
for (ptr = HT_START(bidimap, &bidi_map); ptr; ptr = next) {
|
||||||
|
ent = *ptr;
|
||||||
|
next = HT_NEXT_RMV(bidimap, &bidi_map, ptr);
|
||||||
|
tor_free(ent);
|
||||||
|
}
|
||||||
|
HT_CLEAR(bidimap, &bidi_map);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Stop collecting connection stats in a way that we can re-start doing
|
||||||
|
* so in rep_hist_conn_stats_init(). */
|
||||||
|
void
|
||||||
|
rep_hist_conn_stats_term(void)
|
||||||
|
{
|
||||||
|
below_threshold = 0;
|
||||||
|
mostly_read = 0;
|
||||||
|
mostly_written = 0;
|
||||||
|
both_read_and_written = 0;
|
||||||
|
start_of_conn_stats_interval = 0;
|
||||||
|
bidi_map_free();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** We read <b>num_read</b> bytes and wrote <b>num_written</b> from/to OR
|
||||||
|
* connection <b>conn_id</b> in second <b>when</b>. If this is the first
|
||||||
|
* observation in a new interval, sum up the last observations. Add bytes
|
||||||
|
* for this connection. */
|
||||||
|
void
|
||||||
|
rep_hist_note_or_conn_bytes(uint64_t conn_id, size_t num_read,
|
||||||
|
size_t num_written, time_t when)
|
||||||
|
{
|
||||||
|
if (!start_of_conn_stats_interval)
|
||||||
|
return;
|
||||||
|
/* Initialize */
|
||||||
|
if (bidi_next_interval == 0)
|
||||||
|
bidi_next_interval = when + BIDI_INTERVAL;
|
||||||
|
/* Sum up last period's statistics */
|
||||||
|
if (when >= bidi_next_interval) {
|
||||||
|
bidi_map_entry_t **ptr, **next, *ent;
|
||||||
|
for (ptr = HT_START(bidimap, &bidi_map); ptr; ptr = next) {
|
||||||
|
ent = *ptr;
|
||||||
|
if (ent->read + ent->written < BIDI_THRESHOLD)
|
||||||
|
below_threshold++;
|
||||||
|
else if (ent->read >= ent->written * BIDI_FACTOR)
|
||||||
|
mostly_read++;
|
||||||
|
else if (ent->written >= ent->read * BIDI_FACTOR)
|
||||||
|
mostly_written++;
|
||||||
|
else
|
||||||
|
both_read_and_written++;
|
||||||
|
next = HT_NEXT_RMV(bidimap, &bidi_map, ptr);
|
||||||
|
tor_free(ent);
|
||||||
|
}
|
||||||
|
while (when >= bidi_next_interval)
|
||||||
|
bidi_next_interval += BIDI_INTERVAL;
|
||||||
|
log_info(LD_GENERAL, "%d below threshold, %d mostly read, "
|
||||||
|
"%d mostly written, %d both read and written.",
|
||||||
|
below_threshold, mostly_read, mostly_written,
|
||||||
|
both_read_and_written);
|
||||||
|
}
|
||||||
|
/* Add this connection's bytes. */
|
||||||
|
if (num_read > 0 || num_written > 0) {
|
||||||
|
bidi_map_entry_t *entry, lookup;
|
||||||
|
lookup.conn_id = conn_id;
|
||||||
|
entry = HT_FIND(bidimap, &bidi_map, &lookup);
|
||||||
|
if (entry) {
|
||||||
|
entry->written += num_written;
|
||||||
|
entry->read += num_read;
|
||||||
|
} else {
|
||||||
|
entry = tor_malloc_zero(sizeof(bidi_map_entry_t));
|
||||||
|
entry->conn_id = conn_id;
|
||||||
|
entry->written = num_written;
|
||||||
|
entry->read = num_read;
|
||||||
|
HT_INSERT(bidimap, &bidi_map, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Write conn statistics to $DATADIR/stats/conn-stats and return when
|
||||||
|
* we would next want to write conn stats. */
|
||||||
|
time_t
|
||||||
|
rep_hist_conn_stats_write(time_t now)
|
||||||
|
{
|
||||||
|
char *statsdir = NULL, *filename = NULL;
|
||||||
|
char written[ISO_TIME_LEN+1];
|
||||||
|
open_file_t *open_file = NULL;
|
||||||
|
FILE *out;
|
||||||
|
|
||||||
|
if (!start_of_conn_stats_interval)
|
||||||
|
return 0; /* Not initialized. */
|
||||||
|
if (start_of_conn_stats_interval + WRITE_STATS_INTERVAL > now)
|
||||||
|
goto done; /* Not ready to write */
|
||||||
|
|
||||||
|
/* write to file */
|
||||||
|
statsdir = get_datadir_fname("stats");
|
||||||
|
if (check_private_dir(statsdir, CPD_CREATE) < 0)
|
||||||
|
goto done;
|
||||||
|
filename = get_datadir_fname2("stats", "conn-stats");
|
||||||
|
out = start_writing_to_stdio_file(filename, OPEN_FLAGS_APPEND,
|
||||||
|
0600, &open_file);
|
||||||
|
if (!out)
|
||||||
|
goto done;
|
||||||
|
format_iso_time(written, now);
|
||||||
|
if (fprintf(out, "conn-stats-end %s (%d s)\n", written,
|
||||||
|
(unsigned) (now - start_of_conn_stats_interval)) < 0)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
if (fprintf(out, "conn-bi-direct %d,%d,%d,%d\n",
|
||||||
|
below_threshold, mostly_read, mostly_written,
|
||||||
|
both_read_and_written) < 0)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
finish_writing_to_file(open_file);
|
||||||
|
open_file = NULL;
|
||||||
|
start_of_conn_stats_interval = now;
|
||||||
|
done:
|
||||||
|
if (open_file)
|
||||||
|
abort_writing_to_file(open_file);
|
||||||
|
tor_free(filename);
|
||||||
|
tor_free(statsdir);
|
||||||
|
return start_of_conn_stats_interval + WRITE_STATS_INTERVAL;
|
||||||
|
}
|
||||||
|
|
||||||
/** Free all storage held by the OR/link history caches, by the
|
/** Free all storage held by the OR/link history caches, by the
|
||||||
* bandwidth history arrays, by the port history, or by statistics . */
|
* bandwidth history arrays, by the port history, or by statistics . */
|
||||||
void
|
void
|
||||||
@ -2432,5 +2627,6 @@ rep_hist_free_all(void)
|
|||||||
tor_free(exit_streams);
|
tor_free(exit_streams);
|
||||||
built_last_stability_doc_at = 0;
|
built_last_stability_doc_at = 0;
|
||||||
predicted_ports_free();
|
predicted_ports_free();
|
||||||
|
bidi_map_free();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,5 +76,11 @@ void rep_hist_buffer_stats_add_circ(circuit_t *circ,
|
|||||||
time_t rep_hist_buffer_stats_write(time_t now);
|
time_t rep_hist_buffer_stats_write(time_t now);
|
||||||
void rep_hist_buffer_stats_term(void);
|
void rep_hist_buffer_stats_term(void);
|
||||||
|
|
||||||
|
void rep_hist_conn_stats_init(time_t now);
|
||||||
|
void rep_hist_note_or_conn_bytes(uint64_t conn_id, size_t num_read,
|
||||||
|
size_t num_written, time_t when);
|
||||||
|
time_t rep_hist_conn_stats_write(time_t now);
|
||||||
|
void rep_hist_conn_stats_term(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -2051,6 +2051,19 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
|
|||||||
"exit-stats-end", now, &contents) > 0) {
|
"exit-stats-end", now, &contents) > 0) {
|
||||||
smartlist_add(chunks, contents);
|
smartlist_add(chunks, contents);
|
||||||
}
|
}
|
||||||
|
if (options->ConnStatistics &&
|
||||||
|
load_stats_file("stats"PATH_SEPARATOR"conn-stats",
|
||||||
|
"conn-stats-end", now, &contents) > 0) {
|
||||||
|
size_t pos = strlen(s);
|
||||||
|
if (strlcpy(s + pos, contents, maxlen - strlen(s)) !=
|
||||||
|
strlen(contents)) {
|
||||||
|
log_warn(LD_DIR, "Could not write conn-stats to extra-info "
|
||||||
|
"descriptor.");
|
||||||
|
s[pos] = '\0';
|
||||||
|
write_stats_to_extrainfo = 0;
|
||||||
|
}
|
||||||
|
tor_free(contents);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (should_record_bridge_info(options) && write_stats_to_extrainfo) {
|
if (should_record_bridge_info(options) && write_stats_to_extrainfo) {
|
||||||
|
Loading…
Reference in New Issue
Block a user