mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-28 06:13:31 +01:00
Add a separate set of token buckets for relayed traffic. Right
now that's just defined as answers to directory requests. svn:r9881
This commit is contained in:
parent
4ab0b979b2
commit
b4f743562f
17
doc/tor.1.in
17
doc/tor.1.in
@ -65,8 +65,7 @@ bandwidth usage to that same value. (Default: 3 MB)
|
|||||||
.TP
|
.TP
|
||||||
\fBBandwidthBurst \fR\fIN\fR \fBbytes\fR|\fBKB\fR|\fBMB\fR|\fBGB\fR|\fBTB\fP
|
\fBBandwidthBurst \fR\fIN\fR \fBbytes\fR|\fBKB\fR|\fBMB\fR|\fBGB\fR|\fBTB\fP
|
||||||
Limit the maximum token bucket size (also known as the burst) to the
|
Limit the maximum token bucket size (also known as the burst) to the
|
||||||
given number of bytes in each direction. This value should be at least
|
given number of bytes in each direction. (Default: 6 MB)
|
||||||
twice your BandwidthRate. (Default: 6 MB)
|
|
||||||
.LP
|
.LP
|
||||||
.TP
|
.TP
|
||||||
\fBMaxAdvertisedBandwidth \fR\fIN\fR \fBbytes\fR|\fBKB\fR|\fBMB\fR|\fBGB\fR|\fBTB\fP
|
\fBMaxAdvertisedBandwidth \fR\fIN\fR \fBbytes\fR|\fBKB\fR|\fBMB\fR|\fBGB\fR|\fBTB\fP
|
||||||
@ -77,6 +76,20 @@ advertised bandwidth rate) can thus reduce the CPU demands on their
|
|||||||
server without impacting network performance.
|
server without impacting network performance.
|
||||||
.LP
|
.LP
|
||||||
.TP
|
.TP
|
||||||
|
\fBRelayBandwidthRate \fR\fIN\fR \fBbytes\fR|\fBKB\fR|\fBMB\fR|\fBGB\fR|\fBTB\fP
|
||||||
|
If defined, a separate token bucket limits the average incoming bandwidth
|
||||||
|
usage for _relayed traffic_ on this node to the specified number of
|
||||||
|
bytes per second, and the average outgoing bandwidth usage to that same
|
||||||
|
value. Relayed traffic is currently defined as answers to directory
|
||||||
|
requests, but that may change. (Default: 0)
|
||||||
|
.LP
|
||||||
|
.TP
|
||||||
|
\fBRelayBandwidthBurst \fR\fIN\fR \fBbytes\fR|\fBKB\fR|\fBMB\fR|\fBGB\fR|\fBTB\fP
|
||||||
|
Limit the maximum token bucket size (also known as the burst) for
|
||||||
|
_relayed traffic_ to the
|
||||||
|
given number of bytes in each direction. (Default: 0)
|
||||||
|
.LP
|
||||||
|
.TP
|
||||||
\fBConnLimit \fR\fINUM\fP
|
\fBConnLimit \fR\fINUM\fP
|
||||||
The minimum number of file descriptors that must be available to
|
The minimum number of file descriptors that must be available to
|
||||||
the Tor process before it will start. Tor will ask the OS for as
|
the Tor process before it will start. Tor will ask the OS for as
|
||||||
|
@ -216,6 +216,8 @@ static config_var_t _option_vars[] = {
|
|||||||
VAR("RecommendedClientVersions", LINELIST, RecommendedClientVersions, NULL),
|
VAR("RecommendedClientVersions", LINELIST, RecommendedClientVersions, NULL),
|
||||||
VAR("RecommendedServerVersions", LINELIST, RecommendedServerVersions, NULL),
|
VAR("RecommendedServerVersions", LINELIST, RecommendedServerVersions, NULL),
|
||||||
VAR("RedirectExit", LINELIST, RedirectExit, NULL),
|
VAR("RedirectExit", LINELIST, RedirectExit, NULL),
|
||||||
|
VAR("RelayBandwidthBurst", MEMUNIT, RelayBandwidthBurst, "0"),
|
||||||
|
VAR("RelayBandwidthRate", MEMUNIT, RelayBandwidthRate, "0"),
|
||||||
VAR("RendExcludeNodes", STRING, RendExcludeNodes, NULL),
|
VAR("RendExcludeNodes", STRING, RendExcludeNodes, NULL),
|
||||||
VAR("RendNodes", STRING, RendNodes, NULL),
|
VAR("RendNodes", STRING, RendNodes, NULL),
|
||||||
VAR("RendPostPeriod", INTERVAL, RendPostPeriod, "1 hour"),
|
VAR("RendPostPeriod", INTERVAL, RendPostPeriod, "1 hour"),
|
||||||
@ -2666,6 +2668,19 @@ options_validate(or_options_t *old_options, or_options_t *options,
|
|||||||
*msg = tor_strdup(r >= 0 ? buf : "internal error");
|
*msg = tor_strdup(r >= 0 ? buf : "internal error");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
if (options->RelayBandwidthRate > options->RelayBandwidthBurst)
|
||||||
|
REJECT("RelayBandwidthBurst must be at least equal "
|
||||||
|
"to RelayBandwidthRate.");
|
||||||
|
if (options->RelayBandwidthRate &&
|
||||||
|
options->RelayBandwidthRate < ROUTER_REQUIRED_MIN_BANDWIDTH) {
|
||||||
|
r = tor_snprintf(buf, sizeof(buf),
|
||||||
|
"RelayBandwidthRate is set to %d bytes/second. "
|
||||||
|
"For servers, it must be at least %d.",
|
||||||
|
(int)options->RelayBandwidthRate,
|
||||||
|
ROUTER_REQUIRED_MIN_BANDWIDTH);
|
||||||
|
*msg = tor_strdup(r >= 0 ? buf : "internal error");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options->BandwidthRate > options->BandwidthBurst)
|
if (options->BandwidthRate > options->BandwidthBurst)
|
||||||
|
@ -1105,11 +1105,28 @@ connection_is_rate_limited(connection_t *conn)
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern int global_read_bucket, global_write_bucket;
|
extern int global_read_bucket, global_write_bucket;
|
||||||
|
extern int global_relayed_read_bucket, global_relayed_write_bucket;
|
||||||
|
|
||||||
/** Did our global write bucket run dry last second? If so, we are
|
/** Did our either global write bucket run dry last second? If so,
|
||||||
* likely to run dry again this second, so be stingy with the tokens
|
* we are likely to run dry again this second, so be stingy with the
|
||||||
* we just put in. */
|
* tokens we just put in. */
|
||||||
static int global_write_bucket_empty_last_second = 0;
|
static int write_buckets_empty_last_second = 0;
|
||||||
|
|
||||||
|
/** Return 1 if <b>conn</b> should use tokens from the "relayed"
|
||||||
|
* bandwidth rates, else 0. Currently, only OR conns with bandwidth
|
||||||
|
* class 1, and directory conns that are serving data out, count.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
connection_counts_as_relayed_traffic(connection_t *conn)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
if (conn->type == CONN_TYPE_OR && TO_OR_CONN(conn)->bandwidth_class)
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
if (conn->type == CONN_TYPE_DIR && DIR_CONN_IS_SERVER(conn))
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/** Helper function to decide how many bytes out of <b>global_bucket</b>
|
/** Helper function to decide how many bytes out of <b>global_bucket</b>
|
||||||
* we're willing to use for this transaction. <b>base</b> is the size
|
* we're willing to use for this transaction. <b>base</b> is the size
|
||||||
@ -1153,16 +1170,25 @@ connection_bucket_read_limit(connection_t *conn)
|
|||||||
CELL_NETWORK_SIZE : RELAY_PAYLOAD_SIZE;
|
CELL_NETWORK_SIZE : RELAY_PAYLOAD_SIZE;
|
||||||
int priority = conn->type != CONN_TYPE_DIR;
|
int priority = conn->type != CONN_TYPE_DIR;
|
||||||
int conn_bucket = -1;
|
int conn_bucket = -1;
|
||||||
if (connection_speaks_cells(conn) && conn->state == OR_CONN_STATE_OPEN) {
|
int global_bucket = global_read_bucket;
|
||||||
|
|
||||||
|
if (connection_speaks_cells(conn)) {
|
||||||
or_connection_t *or_conn = TO_OR_CONN(conn);
|
or_connection_t *or_conn = TO_OR_CONN(conn);
|
||||||
conn_bucket = or_conn->read_bucket;
|
if (conn->state == OR_CONN_STATE_OPEN)
|
||||||
|
conn_bucket = or_conn->read_bucket;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!connection_is_rate_limited(conn)) {
|
if (!connection_is_rate_limited(conn)) {
|
||||||
/* be willing to read on local conns even if our buckets are empty */
|
/* be willing to read on local conns even if our buckets are empty */
|
||||||
return conn_bucket>=0 ? conn_bucket : 1<<14;
|
return conn_bucket>=0 ? conn_bucket : 1<<14;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (connection_counts_as_relayed_traffic(conn) &&
|
||||||
|
global_relayed_read_bucket <= global_read_bucket)
|
||||||
|
global_bucket = global_relayed_read_bucket;
|
||||||
|
|
||||||
return connection_bucket_round_robin(base, priority,
|
return connection_bucket_round_robin(base, priority,
|
||||||
global_read_bucket, conn_bucket);
|
global_bucket, conn_bucket);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** How many bytes at most can we write onto this connection? */
|
/** How many bytes at most can we write onto this connection? */
|
||||||
@ -1172,24 +1198,31 @@ connection_bucket_write_limit(connection_t *conn)
|
|||||||
int base = connection_speaks_cells(conn) ?
|
int base = connection_speaks_cells(conn) ?
|
||||||
CELL_NETWORK_SIZE : RELAY_PAYLOAD_SIZE;
|
CELL_NETWORK_SIZE : RELAY_PAYLOAD_SIZE;
|
||||||
int priority = conn->type != CONN_TYPE_DIR;
|
int priority = conn->type != CONN_TYPE_DIR;
|
||||||
|
int global_bucket = global_write_bucket;
|
||||||
|
|
||||||
if (!connection_is_rate_limited(conn)) {
|
if (!connection_is_rate_limited(conn)) {
|
||||||
/* be willing to write to local conns even if our buckets are empty */
|
/* be willing to write to local conns even if our buckets are empty */
|
||||||
return conn->outbuf_flushlen;
|
return conn->outbuf_flushlen;
|
||||||
}
|
}
|
||||||
return connection_bucket_round_robin(base, priority, global_write_bucket,
|
|
||||||
|
if (connection_counts_as_relayed_traffic(conn) &&
|
||||||
|
global_relayed_write_bucket <= global_write_bucket)
|
||||||
|
global_bucket = global_relayed_write_bucket;
|
||||||
|
|
||||||
|
return connection_bucket_round_robin(base, priority, global_bucket,
|
||||||
conn->outbuf_flushlen);
|
conn->outbuf_flushlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return 1 if the global write bucket is low enough that we shouldn't
|
/** Return 1 if the global write buckets are low enough that we
|
||||||
* send <b>attempt</b> bytes of low-priority directory stuff out to
|
* shouldn't send <b>attempt</b> bytes of low-priority directory stuff
|
||||||
* <b>conn</b>. Else return 0.
|
* out to <b>conn</b>. Else return 0.
|
||||||
|
|
||||||
* Priority is 1 for v1 requests (directories and running-routers),
|
* Priority is 1 for v1 requests (directories and running-routers),
|
||||||
* and 2 for v2 requests (statuses and descriptors). But see FFFF in
|
* and 2 for v2 requests (statuses and descriptors). But see FFFF in
|
||||||
* directory_handle_command_get() for why we don't use priority 2 yet.
|
* directory_handle_command_get() for why we don't use priority 2 yet.
|
||||||
*
|
*
|
||||||
* There are a lot of parameters we could use here:
|
* There are a lot of parameters we could use here:
|
||||||
|
* - global_relayed_write_bucket. Low is bad.
|
||||||
* - global_write_bucket. Low is bad.
|
* - global_write_bucket. Low is bad.
|
||||||
* - bandwidthrate. Low is bad.
|
* - bandwidthrate. Low is bad.
|
||||||
* - bandwidthburst. Not a big factor?
|
* - bandwidthburst. Not a big factor?
|
||||||
@ -1203,22 +1236,26 @@ connection_bucket_write_limit(connection_t *conn)
|
|||||||
int
|
int
|
||||||
global_write_bucket_low(connection_t *conn, size_t attempt, int priority)
|
global_write_bucket_low(connection_t *conn, size_t attempt, int priority)
|
||||||
{
|
{
|
||||||
|
int smaller_bucket = global_write_bucket < global_relayed_write_bucket ?
|
||||||
|
global_write_bucket : global_relayed_write_bucket;
|
||||||
if (authdir_mode(get_options()) && priority>1)
|
if (authdir_mode(get_options()) && priority>1)
|
||||||
return 0; /* there's always room to answer v2 if we're an auth dir */
|
return 0; /* there's always room to answer v2 if we're an auth dir */
|
||||||
|
|
||||||
if (!connection_is_rate_limited(conn))
|
if (!connection_is_rate_limited(conn))
|
||||||
return 0; /* local conns don't get limited */
|
return 0; /* local conns don't get limited */
|
||||||
|
|
||||||
if (global_write_bucket < (int)attempt)
|
if (smaller_bucket < (int)attempt)
|
||||||
return 1; /* not enough space no matter the priority */
|
return 1; /* not enough space no matter the priority */
|
||||||
|
|
||||||
if (global_write_bucket_empty_last_second)
|
if (write_buckets_empty_last_second)
|
||||||
return 1; /* we're already hitting our limits, no more please */
|
return 1; /* we're already hitting our limits, no more please */
|
||||||
|
|
||||||
if (priority == 1) { /* old-style v1 query */
|
if (priority == 1) { /* old-style v1 query */
|
||||||
/* Could we handle *two* of these requests within the next two seconds? */
|
/* Could we handle *two* of these requests within the next two seconds? */
|
||||||
int64_t can_write = (int64_t)global_write_bucket
|
or_options_t *options = get_options();
|
||||||
+ 2*get_options()->BandwidthRate;
|
int64_t can_write = (int64_t)smaller_bucket
|
||||||
|
+ 2*(options->RelayBandwidthRate ? options->RelayBandwidthRate :
|
||||||
|
options->BandwidthRate);
|
||||||
if (can_write < 2*(int64_t)attempt)
|
if (can_write < 2*(int64_t)attempt)
|
||||||
return 1;
|
return 1;
|
||||||
} else { /* v2 query */
|
} else { /* v2 query */
|
||||||
@ -1227,14 +1264,28 @@ global_write_bucket_low(connection_t *conn, size_t attempt, int priority)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** We just read num_read onto conn. Decrement buckets appropriately. */
|
/** We just read num_read and wrote num_written onto conn.
|
||||||
|
* Decrement buckets appropriately. */
|
||||||
static void
|
static void
|
||||||
connection_read_bucket_decrement(connection_t *conn, int num_read)
|
connection_buckets_decrement(connection_t *conn, time_t now,
|
||||||
|
int num_read, int num_written)
|
||||||
{
|
{
|
||||||
global_read_bucket -= num_read;
|
if (!connection_is_rate_limited(conn))
|
||||||
if (connection_speaks_cells(conn) && conn->state == OR_CONN_STATE_OPEN) {
|
return; /* local IPs are free */
|
||||||
TO_OR_CONN(conn)->read_bucket -= num_read;
|
|
||||||
|
if (num_read > 0)
|
||||||
|
rep_hist_note_bytes_read(num_read, now);
|
||||||
|
if (num_written > 0)
|
||||||
|
rep_hist_note_bytes_written(num_written, now);
|
||||||
|
|
||||||
|
if (connection_counts_as_relayed_traffic(conn)) {
|
||||||
|
global_relayed_read_bucket -= num_read;
|
||||||
|
global_relayed_write_bucket -= num_written;
|
||||||
}
|
}
|
||||||
|
global_read_bucket -= num_read;
|
||||||
|
global_write_bucket -= num_written;
|
||||||
|
if (connection_speaks_cells(conn) && conn->state == OR_CONN_STATE_OPEN)
|
||||||
|
TO_OR_CONN(conn)->read_bucket -= num_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** If we have exhausted our global buckets, or the buckets for conn,
|
/** If we have exhausted our global buckets, or the buckets for conn,
|
||||||
@ -1242,21 +1293,23 @@ connection_read_bucket_decrement(connection_t *conn, int num_read)
|
|||||||
static void
|
static void
|
||||||
connection_consider_empty_read_buckets(connection_t *conn)
|
connection_consider_empty_read_buckets(connection_t *conn)
|
||||||
{
|
{
|
||||||
|
const char *reason;
|
||||||
|
|
||||||
if (global_read_bucket <= 0) {
|
if (global_read_bucket <= 0) {
|
||||||
LOG_FN_CONN(conn, (LOG_DEBUG,LD_NET,
|
reason = "global read bucket exhausted. Pausing.";
|
||||||
"global read bucket exhausted. Pausing."));
|
} else if (connection_counts_as_relayed_traffic(conn) &&
|
||||||
conn->wants_to_read = 1;
|
global_relayed_read_bucket <= 0) {
|
||||||
connection_stop_reading(conn);
|
reason = "global relayed read bucket exhausted. Pausing.";
|
||||||
return;
|
} else if (connection_speaks_cells(conn) &&
|
||||||
}
|
conn->state == OR_CONN_STATE_OPEN &&
|
||||||
if (connection_speaks_cells(conn) &&
|
TO_OR_CONN(conn)->read_bucket <= 0) {
|
||||||
conn->state == OR_CONN_STATE_OPEN &&
|
reason = "connection read bucket exhausted. Pausing.";
|
||||||
TO_OR_CONN(conn)->read_bucket <= 0) {
|
} else
|
||||||
LOG_FN_CONN(conn,
|
return; /* all good, no need to stop it */
|
||||||
(LOG_DEBUG,LD_NET,"read bucket exhausted. Pausing."));
|
|
||||||
conn->wants_to_read = 1;
|
LOG_FN_CONN(conn, (LOG_DEBUG, LD_NET, "%s", reason));
|
||||||
connection_stop_reading(conn);
|
conn->wants_to_read = 1;
|
||||||
}
|
connection_stop_reading(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** If we have exhausted our global buckets, or the buckets for conn,
|
/** If we have exhausted our global buckets, or the buckets for conn,
|
||||||
@ -1264,26 +1317,28 @@ connection_consider_empty_read_buckets(connection_t *conn)
|
|||||||
static void
|
static void
|
||||||
connection_consider_empty_write_buckets(connection_t *conn)
|
connection_consider_empty_write_buckets(connection_t *conn)
|
||||||
{
|
{
|
||||||
|
const char *reason;
|
||||||
|
|
||||||
if (global_write_bucket <= 0) {
|
if (global_write_bucket <= 0) {
|
||||||
LOG_FN_CONN(conn, (LOG_DEBUG,LD_NET,
|
reason = "global write bucket exhausted. Pausing.";
|
||||||
"global write bucket exhausted. Pausing."));
|
} else if (connection_counts_as_relayed_traffic(conn) &&
|
||||||
conn->wants_to_write = 1;
|
global_relayed_write_bucket <= 0) {
|
||||||
connection_stop_writing(conn);
|
reason = "global relayed write bucket exhausted. Pausing.";
|
||||||
return;
|
|
||||||
}
|
|
||||||
#if 0
|
#if 0
|
||||||
if (connection_speaks_cells(conn) &&
|
} else if (connection_speaks_cells(conn) &&
|
||||||
conn->state == OR_CONN_STATE_OPEN &&
|
conn->state == OR_CONN_STATE_OPEN &&
|
||||||
TO_OR_CONN(conn)->write_bucket <= 0) {
|
TO_OR_CONN(conn)->write_bucket <= 0) {
|
||||||
LOG_FN_CONN(conn,
|
reason = "connection write bucket exhausted. Pausing.";
|
||||||
(LOG_DEBUG,LD_NET,"write bucket exhausted. Pausing."));
|
|
||||||
conn->wants_to_write = 1;
|
|
||||||
connection_stop_writing(conn);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
} else
|
||||||
|
return; /* all good, no need to stop it */
|
||||||
|
|
||||||
|
LOG_FN_CONN(conn, (LOG_DEBUG, LD_NET, "%s", reason));
|
||||||
|
conn->wants_to_write = 1;
|
||||||
|
connection_stop_writing(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Initialize the global read bucket to options->BandwidthBurst. */
|
/** Initialize the global read bucket to options-\>BandwidthBurst. */
|
||||||
void
|
void
|
||||||
connection_bucket_init(void)
|
connection_bucket_init(void)
|
||||||
{
|
{
|
||||||
@ -1291,8 +1346,28 @@ connection_bucket_init(void)
|
|||||||
/* start it at max traffic */
|
/* start it at max traffic */
|
||||||
global_read_bucket = (int)options->BandwidthBurst;
|
global_read_bucket = (int)options->BandwidthBurst;
|
||||||
global_write_bucket = (int)options->BandwidthBurst;
|
global_write_bucket = (int)options->BandwidthBurst;
|
||||||
|
if (options->RelayBandwidthRate) {
|
||||||
|
global_relayed_read_bucket = (int)options->RelayBandwidthBurst;
|
||||||
|
global_relayed_write_bucket = (int)options->RelayBandwidthBurst;
|
||||||
|
} else {
|
||||||
|
global_relayed_read_bucket = (int)options->BandwidthBurst;
|
||||||
|
global_relayed_write_bucket = (int)options->BandwidthBurst;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
connection_bucket_refill_helper(int *bucket, int rate, int burst,
|
||||||
|
int seconds_elapsed, const char *name)
|
||||||
|
{
|
||||||
|
if (*bucket < burst) {
|
||||||
|
*bucket += rate*seconds_elapsed;
|
||||||
|
if (*bucket > burst)
|
||||||
|
*bucket = burst;
|
||||||
|
log(LOG_DEBUG, LD_NET,"%s now %d.", name, *bucket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** A second has rolled over; increment buckets appropriately. */
|
/** A second has rolled over; increment buckets appropriately. */
|
||||||
void
|
void
|
||||||
connection_bucket_refill(int seconds_elapsed)
|
connection_bucket_refill(int seconds_elapsed)
|
||||||
@ -1301,23 +1376,36 @@ connection_bucket_refill(int seconds_elapsed)
|
|||||||
connection_t *conn;
|
connection_t *conn;
|
||||||
connection_t **carray;
|
connection_t **carray;
|
||||||
or_options_t *options = get_options();
|
or_options_t *options = get_options();
|
||||||
|
int relayrate, relayburst;
|
||||||
|
|
||||||
|
if (options->RelayBandwidthRate) {
|
||||||
|
relayrate = (int)options->RelayBandwidthRate;
|
||||||
|
relayburst = (int)options->RelayBandwidthBurst;
|
||||||
|
} else {
|
||||||
|
relayrate = (int)options->BandwidthRate;
|
||||||
|
relayburst = (int)options->BandwidthBurst;
|
||||||
|
}
|
||||||
|
|
||||||
tor_assert(seconds_elapsed >= 0);
|
tor_assert(seconds_elapsed >= 0);
|
||||||
|
|
||||||
|
write_buckets_empty_last_second =
|
||||||
|
global_relayed_write_bucket == 0 || global_write_bucket == 0;
|
||||||
|
|
||||||
/* refill the global buckets */
|
/* refill the global buckets */
|
||||||
if (global_read_bucket < (int)options->BandwidthBurst) {
|
connection_bucket_refill_helper(&global_read_bucket,
|
||||||
global_read_bucket += (int)options->BandwidthRate*seconds_elapsed;
|
(int)options->BandwidthRate,
|
||||||
if (global_read_bucket > (int)options->BandwidthBurst)
|
(int)options->BandwidthBurst,
|
||||||
global_read_bucket = (int)options->BandwidthBurst;
|
seconds_elapsed, "global_read_bucket");
|
||||||
log(LOG_DEBUG, LD_NET,"global_read_bucket now %d.", global_read_bucket);
|
connection_bucket_refill_helper(&global_write_bucket,
|
||||||
}
|
(int)options->BandwidthRate,
|
||||||
if (global_write_bucket < (int)options->BandwidthBurst) {
|
(int)options->BandwidthBurst,
|
||||||
global_write_bucket_empty_last_second = global_write_bucket == 0;
|
seconds_elapsed, "global_write_bucket");
|
||||||
global_write_bucket += (int)options->BandwidthRate*seconds_elapsed;
|
connection_bucket_refill_helper(&global_relayed_read_bucket,
|
||||||
if (global_write_bucket > (int)options->BandwidthBurst)
|
relayrate, relayburst, seconds_elapsed,
|
||||||
global_write_bucket = (int)options->BandwidthBurst;
|
"global_relayed_read_bucket");
|
||||||
log(LOG_DEBUG, LD_NET,"global_write_bucket now %d.", global_write_bucket);
|
connection_bucket_refill_helper(&global_relayed_write_bucket,
|
||||||
}
|
relayrate, relayburst, seconds_elapsed,
|
||||||
|
"global_relayed_write_bucket");
|
||||||
|
|
||||||
/* refill the per-connection buckets */
|
/* refill the per-connection buckets */
|
||||||
get_connection_array(&carray,&n);
|
get_connection_array(&carray,&n);
|
||||||
@ -1337,19 +1425,25 @@ connection_bucket_refill(int seconds_elapsed)
|
|||||||
|
|
||||||
if (conn->wants_to_read == 1 /* it's marked to turn reading back on now */
|
if (conn->wants_to_read == 1 /* it's marked to turn reading back on now */
|
||||||
&& global_read_bucket > 0 /* and we're allowed to read */
|
&& global_read_bucket > 0 /* and we're allowed to read */
|
||||||
|
&& (!connection_counts_as_relayed_traffic(conn) ||
|
||||||
|
global_relayed_read_bucket > 0) /* even if we're relayed traffic */
|
||||||
&& (!connection_speaks_cells(conn) ||
|
&& (!connection_speaks_cells(conn) ||
|
||||||
conn->state != OR_CONN_STATE_OPEN ||
|
conn->state != OR_CONN_STATE_OPEN ||
|
||||||
TO_OR_CONN(conn)->read_bucket > 0)) {
|
TO_OR_CONN(conn)->read_bucket > 0)) {
|
||||||
/* and either a non-cell conn or a cell conn with non-empty bucket */
|
/* and either a non-cell conn or a cell conn with non-empty bucket */
|
||||||
LOG_FN_CONN(conn, (LOG_DEBUG,LD_NET,
|
LOG_FN_CONN(conn, (LOG_DEBUG,LD_NET,
|
||||||
"waking up conn (fd %d) for read",conn->s));
|
"waking up conn (fd %d) for read", conn->s));
|
||||||
conn->wants_to_read = 0;
|
conn->wants_to_read = 0;
|
||||||
connection_start_reading(conn);
|
connection_start_reading(conn);
|
||||||
}
|
}
|
||||||
if (conn->wants_to_write == 1 &&
|
|
||||||
global_write_bucket > 0) { /* and we're allowed to write */
|
if (conn->wants_to_write == 1
|
||||||
|
&& global_write_bucket > 0 /* and we're allowed to write */
|
||||||
|
&& (!connection_counts_as_relayed_traffic(conn) ||
|
||||||
|
global_relayed_write_bucket > 0)) {
|
||||||
|
/* even if we're relayed traffic */
|
||||||
LOG_FN_CONN(conn, (LOG_DEBUG,LD_NET,
|
LOG_FN_CONN(conn, (LOG_DEBUG,LD_NET,
|
||||||
"waking up conn (fd %d) for write",conn->s));
|
"waking up conn (fd %d) for write", conn->s));
|
||||||
conn->wants_to_write = 0;
|
conn->wants_to_write = 0;
|
||||||
connection_start_writing(conn);
|
connection_start_writing(conn);
|
||||||
}
|
}
|
||||||
@ -1561,18 +1655,7 @@ connection_read_to_buf(connection_t *conn, int *max_to_read)
|
|||||||
edge_conn->n_read += n_read;
|
edge_conn->n_read += n_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connection_is_rate_limited(conn)) {
|
connection_buckets_decrement(conn, time(NULL), n_read, n_written);
|
||||||
/* For non-local IPs, remember if we flushed any bytes over the wire. */
|
|
||||||
time_t now = time(NULL);
|
|
||||||
if (n_read > 0) {
|
|
||||||
rep_hist_note_bytes_read(n_read, now);
|
|
||||||
connection_read_bucket_decrement(conn, n_read);
|
|
||||||
}
|
|
||||||
if (n_written > 0) {
|
|
||||||
rep_hist_note_bytes_written(n_written, now);
|
|
||||||
global_write_bucket -= n_written;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (more_to_read && result == at_most) {
|
if (more_to_read && result == at_most) {
|
||||||
bytes_in_buf = buf_capacity(conn->inbuf) - buf_datalen(conn->inbuf);
|
bytes_in_buf = buf_capacity(conn->inbuf) - buf_datalen(conn->inbuf);
|
||||||
@ -1762,18 +1845,7 @@ connection_handle_write(connection_t *conn, int force)
|
|||||||
edge_conn->n_written += n_written;
|
edge_conn->n_written += n_written;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connection_is_rate_limited(conn)) {
|
connection_buckets_decrement(conn, time(NULL), n_read, n_written);
|
||||||
/* For non-local IPs, remember if we flushed any bytes over the wire. */
|
|
||||||
time_t now = time(NULL);
|
|
||||||
if (n_written > 0) {
|
|
||||||
rep_hist_note_bytes_written(n_written, now);
|
|
||||||
global_write_bucket -= n_written;
|
|
||||||
}
|
|
||||||
if (n_read > 0) {
|
|
||||||
rep_hist_note_bytes_read(n_read, now);
|
|
||||||
connection_read_bucket_decrement(conn, n_read);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result > 0) {
|
if (result > 0) {
|
||||||
/* If we wrote any bytes from our buffer, then call the appropriate
|
/* If we wrote any bytes from our buffer, then call the appropriate
|
||||||
|
@ -34,12 +34,18 @@ static int conn_close_if_marked(int i);
|
|||||||
int global_read_bucket; /**< Max number of bytes I can read this second. */
|
int global_read_bucket; /**< Max number of bytes I can read this second. */
|
||||||
int global_write_bucket; /**< Max number of bytes I can write this second. */
|
int global_write_bucket; /**< Max number of bytes I can write this second. */
|
||||||
|
|
||||||
|
/** Max number of relayed (bandwidth class 1) bytes I can read this second. */
|
||||||
|
int global_relayed_read_bucket;
|
||||||
|
/** Max number of relayed (bandwidth class 1) bytes I can write this second. */
|
||||||
|
int global_relayed_write_bucket;
|
||||||
|
|
||||||
/** What was the read bucket before the last call to prepare_for_pool?
|
/** What was the read bucket before the last call to prepare_for_pool?
|
||||||
* (used to determine how many bytes we've read). */
|
* (used to determine how many bytes we've read). */
|
||||||
static int stats_prev_global_read_bucket;
|
static int stats_prev_global_read_bucket;
|
||||||
/** What was the write bucket before the last call to prepare_for_pool?
|
/** What was the write bucket before the last call to prepare_for_pool?
|
||||||
* (used to determine how many bytes we've written). */
|
* (used to determine how many bytes we've written). */
|
||||||
static int stats_prev_global_write_bucket;
|
static int stats_prev_global_write_bucket;
|
||||||
|
/* XXX we might want to keep stats about global_relayed_*_bucket too. Or not.*/
|
||||||
/** How many bytes have we read/written since we started the process? */
|
/** How many bytes have we read/written since we started the process? */
|
||||||
static uint64_t stats_n_bytes_read = 0;
|
static uint64_t stats_n_bytes_read = 0;
|
||||||
static uint64_t stats_n_bytes_written = 0;
|
static uint64_t stats_n_bytes_written = 0;
|
||||||
|
@ -804,7 +804,7 @@ typedef struct or_connection_t {
|
|||||||
int n_circuits; /**< How many circuits use this connection as p_conn or
|
int n_circuits; /**< How many circuits use this connection as p_conn or
|
||||||
* n_conn ? */
|
* n_conn ? */
|
||||||
struct or_connection_t *next_with_same_id; /**< Next connection with same
|
struct or_connection_t *next_with_same_id; /**< Next connection with same
|
||||||
* identity digest as this one. */
|
* identity digest as this one. */
|
||||||
/** Linked list of bridged dirserver connections that can't write until
|
/** Linked list of bridged dirserver connections that can't write until
|
||||||
* this connection's outbuf is less full. */
|
* this connection's outbuf is less full. */
|
||||||
struct dir_connection_t *blocked_dir_connections;
|
struct dir_connection_t *blocked_dir_connections;
|
||||||
@ -1697,6 +1697,10 @@ typedef struct {
|
|||||||
* to use in a second? */
|
* to use in a second? */
|
||||||
uint64_t MaxAdvertisedBandwidth; /**< How much bandwidth are we willing to
|
uint64_t MaxAdvertisedBandwidth; /**< How much bandwidth are we willing to
|
||||||
* tell people we have? */
|
* tell people we have? */
|
||||||
|
uint64_t RelayBandwidthRate; /**< How much bandwidth, on average, are we
|
||||||
|
* willing to use for all relayed conns? */
|
||||||
|
uint64_t RelayBandwidthBurst; /**< How much bandwidth, at maximum, will we
|
||||||
|
* use in a second for all relayed conns? */
|
||||||
int NumCpus; /**< How many CPUs should we try to use? */
|
int NumCpus; /**< How many CPUs should we try to use? */
|
||||||
int RunTesting; /**< If true, create testing circuits to measure how well the
|
int RunTesting; /**< If true, create testing circuits to measure how well the
|
||||||
* other ORs are running. */
|
* other ORs are running. */
|
||||||
|
Loading…
Reference in New Issue
Block a user