mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-13 22:53:44 +01:00
ns: Add a before and after consensus has changed notification
In 0.3.2.1-alpha, we've added notify_networkstatus_changed() in order to have a way to notify other subsystems that the consensus just changed. The old and new consensus are passed to it. Before this patch, this was done _before_ the new consensus was set globally (thus NOT accessible by getting the latest consensus). The scheduler notification was assuming that it was set and select_scheduler() is looking at the latest consensus to get the parameters it might needs. This was very wrong because at that point it is still the old consensus set globally. This commit changes the notify_networkstatus_changed() to be the "before" function and adds an "after" notification from which the scheduler subsystem is notified. Fixes #24975
This commit is contained in:
parent
c85f78e74c
commit
fbc455cbd2
6
changes/bug24975
Normal file
6
changes/bug24975
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
o Major bugfixes (scheduler, consensus):
|
||||||
|
- A logic in the code was preventing the scheduler subystem to properly
|
||||||
|
make a decision based on the latest consensus when it arrives. This lead
|
||||||
|
to the scheduler failing to notice any consensus parameters that might
|
||||||
|
have changed between consensuses. Fixes bug 24975; bugfix on
|
||||||
|
0.3.2.1-alpha.
|
@ -1564,13 +1564,20 @@ notify_control_networkstatus_changed(const networkstatus_t *old_c,
|
|||||||
smartlist_free(changed);
|
smartlist_free(changed);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called when the consensus has changed from old_c to new_c. */
|
/* Called before the consensus changes from old_c to new_c. */
|
||||||
static void
|
static void
|
||||||
notify_networkstatus_changed(const networkstatus_t *old_c,
|
notify_before_networkstatus_changes(const networkstatus_t *old_c,
|
||||||
const networkstatus_t *new_c)
|
const networkstatus_t *new_c)
|
||||||
{
|
{
|
||||||
notify_control_networkstatus_changed(old_c, new_c);
|
notify_control_networkstatus_changed(old_c, new_c);
|
||||||
scheduler_notify_networkstatus_changed(old_c, new_c);
|
}
|
||||||
|
|
||||||
|
/* Called after a new consensus has been put in the global state. It is safe
|
||||||
|
* to use the consensus getters in this function. */
|
||||||
|
static void
|
||||||
|
notify_after_networkstatus_changes(void)
|
||||||
|
{
|
||||||
|
scheduler_notify_networkstatus_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Copy all the ancillary information (like router download status and so on)
|
/** Copy all the ancillary information (like router download status and so on)
|
||||||
@ -1897,8 +1904,11 @@ networkstatus_set_current_consensus(const char *consensus,
|
|||||||
|
|
||||||
const int is_usable_flavor = flav == usable_consensus_flavor();
|
const int is_usable_flavor = flav == usable_consensus_flavor();
|
||||||
|
|
||||||
|
/* Before we switch to the new consensus, notify that we are about to change
|
||||||
|
* it using the old consensus and the new one. */
|
||||||
if (is_usable_flavor) {
|
if (is_usable_flavor) {
|
||||||
notify_networkstatus_changed(networkstatus_get_latest_consensus(), c);
|
notify_before_networkstatus_changes(networkstatus_get_latest_consensus(),
|
||||||
|
c);
|
||||||
}
|
}
|
||||||
if (flav == FLAV_NS) {
|
if (flav == FLAV_NS) {
|
||||||
if (current_ns_consensus) {
|
if (current_ns_consensus) {
|
||||||
@ -1941,6 +1951,10 @@ networkstatus_set_current_consensus(const char *consensus,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (is_usable_flavor) {
|
if (is_usable_flavor) {
|
||||||
|
/* Notify that we just changed the consensus so the current global value
|
||||||
|
* can be looked at. */
|
||||||
|
notify_after_networkstatus_changes();
|
||||||
|
|
||||||
/* The "current" consensus has just been set and it is a usable flavor so
|
/* The "current" consensus has just been set and it is a usable flavor so
|
||||||
* the first thing we need to do is recalculate the voting schedule static
|
* the first thing we need to do is recalculate the voting schedule static
|
||||||
* object so we can use the timings in there needed by some subsystems
|
* object so we can use the timings in there needed by some subsystems
|
||||||
|
@ -435,15 +435,14 @@ scheduler_conf_changed(void)
|
|||||||
* Whenever we get a new consensus, this function is called.
|
* Whenever we get a new consensus, this function is called.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
scheduler_notify_networkstatus_changed(const networkstatus_t *old_c,
|
scheduler_notify_networkstatus_changed(void)
|
||||||
const networkstatus_t *new_c)
|
|
||||||
{
|
{
|
||||||
/* Maybe the consensus param made us change the scheduler. */
|
/* Maybe the consensus param made us change the scheduler. */
|
||||||
set_scheduler();
|
set_scheduler();
|
||||||
|
|
||||||
/* Then tell the (possibly new) scheduler that we have a new consensus */
|
/* Then tell the (possibly new) scheduler that we have a new consensus */
|
||||||
if (the_scheduler->on_new_consensus) {
|
if (the_scheduler->on_new_consensus) {
|
||||||
the_scheduler->on_new_consensus(old_c, new_c);
|
the_scheduler->on_new_consensus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,8 +80,7 @@ typedef struct scheduler_s {
|
|||||||
* (which might be new) will call this so it has the chance to react to the
|
* (which might be new) will call this so it has the chance to react to the
|
||||||
* new consensus too. If there's a consensus parameter that your scheduler
|
* new consensus too. If there's a consensus parameter that your scheduler
|
||||||
* wants to keep an eye on, this is where you should check for it. */
|
* wants to keep an eye on, this is where you should check for it. */
|
||||||
void (*on_new_consensus)(const networkstatus_t *old_c,
|
void (*on_new_consensus)(void);
|
||||||
const networkstatus_t *new_c);
|
|
||||||
|
|
||||||
/* (Optional) To be called when a channel is being freed. Sometimes channels
|
/* (Optional) To be called when a channel is being freed. Sometimes channels
|
||||||
* go away (for example: the relay on the other end is shutting down). If
|
* go away (for example: the relay on the other end is shutting down). If
|
||||||
@ -119,8 +118,7 @@ typedef struct scheduler_s {
|
|||||||
void scheduler_init(void);
|
void scheduler_init(void);
|
||||||
void scheduler_free_all(void);
|
void scheduler_free_all(void);
|
||||||
void scheduler_conf_changed(void);
|
void scheduler_conf_changed(void);
|
||||||
void scheduler_notify_networkstatus_changed(const networkstatus_t *old_c,
|
void scheduler_notify_networkstatus_changed(void);
|
||||||
const networkstatus_t *new_c);
|
|
||||||
MOCK_DECL(void, scheduler_release_channel, (channel_t *chan));
|
MOCK_DECL(void, scheduler_release_channel, (channel_t *chan));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -197,7 +195,7 @@ int scheduler_can_use_kist(void);
|
|||||||
void scheduler_kist_set_full_mode(void);
|
void scheduler_kist_set_full_mode(void);
|
||||||
void scheduler_kist_set_lite_mode(void);
|
void scheduler_kist_set_lite_mode(void);
|
||||||
scheduler_t *get_kist_scheduler(void);
|
scheduler_t *get_kist_scheduler(void);
|
||||||
int kist_scheduler_run_interval(const networkstatus_t *ns);
|
int kist_scheduler_run_interval(void);
|
||||||
|
|
||||||
#ifdef TOR_UNIT_TESTS
|
#ifdef TOR_UNIT_TESTS
|
||||||
extern int32_t sched_run_interval;
|
extern int32_t sched_run_interval;
|
||||||
|
@ -362,10 +362,10 @@ outbuf_table_remove(outbuf_table_t *table, channel_t *chan)
|
|||||||
|
|
||||||
/* Set the scheduler running interval. */
|
/* Set the scheduler running interval. */
|
||||||
static void
|
static void
|
||||||
set_scheduler_run_interval(const networkstatus_t *ns)
|
set_scheduler_run_interval(void)
|
||||||
{
|
{
|
||||||
int old_sched_run_interval = sched_run_interval;
|
int old_sched_run_interval = sched_run_interval;
|
||||||
sched_run_interval = kist_scheduler_run_interval(ns);
|
sched_run_interval = kist_scheduler_run_interval();
|
||||||
if (old_sched_run_interval != sched_run_interval) {
|
if (old_sched_run_interval != sched_run_interval) {
|
||||||
log_info(LD_SCHED, "Scheduler KIST changing its running interval "
|
log_info(LD_SCHED, "Scheduler KIST changing its running interval "
|
||||||
"from %" PRId32 " to %" PRId32,
|
"from %" PRId32 " to %" PRId32,
|
||||||
@ -481,13 +481,9 @@ kist_on_channel_free(const channel_t *chan)
|
|||||||
|
|
||||||
/* Function of the scheduler interface: on_new_consensus() */
|
/* Function of the scheduler interface: on_new_consensus() */
|
||||||
static void
|
static void
|
||||||
kist_scheduler_on_new_consensus(const networkstatus_t *old_c,
|
kist_scheduler_on_new_consensus(void)
|
||||||
const networkstatus_t *new_c)
|
|
||||||
{
|
{
|
||||||
(void) old_c;
|
set_scheduler_run_interval();
|
||||||
(void) new_c;
|
|
||||||
|
|
||||||
set_scheduler_run_interval(new_c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Function of the scheduler interface: on_new_options() */
|
/* Function of the scheduler interface: on_new_options() */
|
||||||
@ -497,7 +493,7 @@ kist_scheduler_on_new_options(void)
|
|||||||
sock_buf_size_factor = get_options()->KISTSockBufSizeFactor;
|
sock_buf_size_factor = get_options()->KISTSockBufSizeFactor;
|
||||||
|
|
||||||
/* Calls kist_scheduler_run_interval which calls get_options(). */
|
/* Calls kist_scheduler_run_interval which calls get_options(). */
|
||||||
set_scheduler_run_interval(NULL);
|
set_scheduler_run_interval();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Function of the scheduler interface: init() */
|
/* Function of the scheduler interface: init() */
|
||||||
@ -770,7 +766,7 @@ get_kist_scheduler(void)
|
|||||||
* - If consensus doesn't say anything, return 10 milliseconds, default.
|
* - If consensus doesn't say anything, return 10 milliseconds, default.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
kist_scheduler_run_interval(const networkstatus_t *ns)
|
kist_scheduler_run_interval(void)
|
||||||
{
|
{
|
||||||
int run_interval = get_options()->KISTSchedRunInterval;
|
int run_interval = get_options()->KISTSchedRunInterval;
|
||||||
|
|
||||||
@ -784,7 +780,7 @@ kist_scheduler_run_interval(const networkstatus_t *ns)
|
|||||||
|
|
||||||
/* Will either be the consensus value or the default. Note that 0 can be
|
/* Will either be the consensus value or the default. Note that 0 can be
|
||||||
* returned which means the consensus wants us to NOT use KIST. */
|
* returned which means the consensus wants us to NOT use KIST. */
|
||||||
return networkstatus_get_param(ns, "KISTSchedRunInterval",
|
return networkstatus_get_param(NULL, "KISTSchedRunInterval",
|
||||||
KIST_SCHED_RUN_INTERVAL_DEFAULT,
|
KIST_SCHED_RUN_INTERVAL_DEFAULT,
|
||||||
KIST_SCHED_RUN_INTERVAL_MIN,
|
KIST_SCHED_RUN_INTERVAL_MIN,
|
||||||
KIST_SCHED_RUN_INTERVAL_MAX);
|
KIST_SCHED_RUN_INTERVAL_MAX);
|
||||||
@ -823,7 +819,7 @@ scheduler_can_use_kist(void)
|
|||||||
|
|
||||||
/* We do have the support, time to check if we can get the interval that the
|
/* We do have the support, time to check if we can get the interval that the
|
||||||
* consensus can be disabling. */
|
* consensus can be disabling. */
|
||||||
int run_interval = kist_scheduler_run_interval(NULL);
|
int run_interval = kist_scheduler_run_interval();
|
||||||
log_debug(LD_SCHED, "Determined KIST sched_run_interval should be "
|
log_debug(LD_SCHED, "Determined KIST sched_run_interval should be "
|
||||||
"%" PRId32 ". Can%s use KIST.",
|
"%" PRId32 ". Can%s use KIST.",
|
||||||
run_interval, (run_interval > 0 ? "" : " not"));
|
run_interval, (run_interval > 0 ? "" : " not"));
|
||||||
|
@ -959,7 +959,7 @@ test_scheduler_can_use_kist(void *arg)
|
|||||||
clear_options();
|
clear_options();
|
||||||
mocked_options.KISTSchedRunInterval = 1234;
|
mocked_options.KISTSchedRunInterval = 1234;
|
||||||
res_should = scheduler_can_use_kist();
|
res_should = scheduler_can_use_kist();
|
||||||
res_freq = kist_scheduler_run_interval(NULL);
|
res_freq = kist_scheduler_run_interval();
|
||||||
#ifdef HAVE_KIST_SUPPORT
|
#ifdef HAVE_KIST_SUPPORT
|
||||||
tt_int_op(res_should, ==, 1);
|
tt_int_op(res_should, ==, 1);
|
||||||
#else /* HAVE_KIST_SUPPORT */
|
#else /* HAVE_KIST_SUPPORT */
|
||||||
@ -971,7 +971,7 @@ test_scheduler_can_use_kist(void *arg)
|
|||||||
clear_options();
|
clear_options();
|
||||||
mocked_options.KISTSchedRunInterval = 0;
|
mocked_options.KISTSchedRunInterval = 0;
|
||||||
res_should = scheduler_can_use_kist();
|
res_should = scheduler_can_use_kist();
|
||||||
res_freq = kist_scheduler_run_interval(NULL);
|
res_freq = kist_scheduler_run_interval();
|
||||||
#ifdef HAVE_KIST_SUPPORT
|
#ifdef HAVE_KIST_SUPPORT
|
||||||
tt_int_op(res_should, ==, 1);
|
tt_int_op(res_should, ==, 1);
|
||||||
#else /* HAVE_KIST_SUPPORT */
|
#else /* HAVE_KIST_SUPPORT */
|
||||||
@ -984,7 +984,7 @@ test_scheduler_can_use_kist(void *arg)
|
|||||||
clear_options();
|
clear_options();
|
||||||
mocked_options.KISTSchedRunInterval = 0;
|
mocked_options.KISTSchedRunInterval = 0;
|
||||||
res_should = scheduler_can_use_kist();
|
res_should = scheduler_can_use_kist();
|
||||||
res_freq = kist_scheduler_run_interval(NULL);
|
res_freq = kist_scheduler_run_interval();
|
||||||
#ifdef HAVE_KIST_SUPPORT
|
#ifdef HAVE_KIST_SUPPORT
|
||||||
tt_int_op(res_should, ==, 1);
|
tt_int_op(res_should, ==, 1);
|
||||||
#else /* HAVE_KIST_SUPPORT */
|
#else /* HAVE_KIST_SUPPORT */
|
||||||
@ -998,7 +998,7 @@ test_scheduler_can_use_kist(void *arg)
|
|||||||
clear_options();
|
clear_options();
|
||||||
mocked_options.KISTSchedRunInterval = 0;
|
mocked_options.KISTSchedRunInterval = 0;
|
||||||
res_should = scheduler_can_use_kist();
|
res_should = scheduler_can_use_kist();
|
||||||
res_freq = kist_scheduler_run_interval(NULL);
|
res_freq = kist_scheduler_run_interval();
|
||||||
tt_int_op(res_should, ==, 0);
|
tt_int_op(res_should, ==, 0);
|
||||||
tt_int_op(res_freq, ==, 0);
|
tt_int_op(res_freq, ==, 0);
|
||||||
UNMOCK(networkstatus_get_param);
|
UNMOCK(networkstatus_get_param);
|
||||||
@ -1032,7 +1032,7 @@ test_scheduler_ns_changed(void *arg)
|
|||||||
/* Change from vanilla to kist via consensus */
|
/* Change from vanilla to kist via consensus */
|
||||||
the_scheduler = get_vanilla_scheduler();
|
the_scheduler = get_vanilla_scheduler();
|
||||||
MOCK(networkstatus_get_param, mock_kist_networkstatus_get_param);
|
MOCK(networkstatus_get_param, mock_kist_networkstatus_get_param);
|
||||||
scheduler_notify_networkstatus_changed(NULL, NULL);
|
scheduler_notify_networkstatus_changed();
|
||||||
UNMOCK(networkstatus_get_param);
|
UNMOCK(networkstatus_get_param);
|
||||||
#ifdef HAVE_KIST_SUPPORT
|
#ifdef HAVE_KIST_SUPPORT
|
||||||
tt_ptr_op(the_scheduler, ==, get_kist_scheduler());
|
tt_ptr_op(the_scheduler, ==, get_kist_scheduler());
|
||||||
@ -1043,14 +1043,14 @@ test_scheduler_ns_changed(void *arg)
|
|||||||
/* Change from kist to vanilla via consensus */
|
/* Change from kist to vanilla via consensus */
|
||||||
the_scheduler = get_kist_scheduler();
|
the_scheduler = get_kist_scheduler();
|
||||||
MOCK(networkstatus_get_param, mock_vanilla_networkstatus_get_param);
|
MOCK(networkstatus_get_param, mock_vanilla_networkstatus_get_param);
|
||||||
scheduler_notify_networkstatus_changed(NULL, NULL);
|
scheduler_notify_networkstatus_changed();
|
||||||
UNMOCK(networkstatus_get_param);
|
UNMOCK(networkstatus_get_param);
|
||||||
tt_ptr_op(the_scheduler, ==, get_vanilla_scheduler());
|
tt_ptr_op(the_scheduler, ==, get_vanilla_scheduler());
|
||||||
|
|
||||||
/* Doesn't change when using KIST */
|
/* Doesn't change when using KIST */
|
||||||
the_scheduler = get_kist_scheduler();
|
the_scheduler = get_kist_scheduler();
|
||||||
MOCK(networkstatus_get_param, mock_kist_networkstatus_get_param);
|
MOCK(networkstatus_get_param, mock_kist_networkstatus_get_param);
|
||||||
scheduler_notify_networkstatus_changed(NULL, NULL);
|
scheduler_notify_networkstatus_changed();
|
||||||
UNMOCK(networkstatus_get_param);
|
UNMOCK(networkstatus_get_param);
|
||||||
#ifdef HAVE_KIST_SUPPORT
|
#ifdef HAVE_KIST_SUPPORT
|
||||||
tt_ptr_op(the_scheduler, ==, get_kist_scheduler());
|
tt_ptr_op(the_scheduler, ==, get_kist_scheduler());
|
||||||
@ -1061,7 +1061,7 @@ test_scheduler_ns_changed(void *arg)
|
|||||||
/* Doesn't change when using vanilla */
|
/* Doesn't change when using vanilla */
|
||||||
the_scheduler = get_vanilla_scheduler();
|
the_scheduler = get_vanilla_scheduler();
|
||||||
MOCK(networkstatus_get_param, mock_vanilla_networkstatus_get_param);
|
MOCK(networkstatus_get_param, mock_vanilla_networkstatus_get_param);
|
||||||
scheduler_notify_networkstatus_changed(NULL, NULL);
|
scheduler_notify_networkstatus_changed();
|
||||||
UNMOCK(networkstatus_get_param);
|
UNMOCK(networkstatus_get_param);
|
||||||
tt_ptr_op(the_scheduler, ==, get_vanilla_scheduler());
|
tt_ptr_op(the_scheduler, ==, get_vanilla_scheduler());
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user