From: Štěpán Balážik Date: Sat, 29 Aug 2020 13:09:35 +0000 (+0200) Subject: selection: shuffle before choosing X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7be8acb8ea69915cd57e6ba08948f802e63fc51a;p=thirdparty%2Fknot-resolver.git selection: shuffle before choosing this ensures fair distribution of queries after resolver start e.g. in priming --- diff --git a/lib/selection.c b/lib/selection.c index 4d2f31153..85ec6fdeb 100644 --- a/lib/selection.c +++ b/lib/selection.c @@ -36,6 +36,9 @@ void *prefix_key(const uint8_t *ip, size_t len) { #undef PREFIX +#define DEFAULT_TIMEOUT 400 +const struct rtt_state default_rtt_state = {0, DEFAULT_TIMEOUT/4}; + struct rtt_state get_rtt_state(const uint8_t *ip, size_t len, struct kr_cache *cache) { struct rtt_state state = {0,0}; knot_db_val_t value; @@ -46,7 +49,7 @@ struct rtt_state get_rtt_state(const uint8_t *ip, size_t len, struct kr_cache *c knot_db_val_t key = {.len = len + 1, .data = prefixed_ip}; if(cache->api->read(db, stats, &key, &value, 1)) { - state = (struct rtt_state){-1, -1}; // No value + state = default_rtt_state; } else { assert(value.len == sizeof(struct rtt_state)); state = *(struct rtt_state *)value.data; @@ -97,20 +100,20 @@ uint8_t* ip_to_bytes(const union inaddr *src, size_t len) { } } -#define DEFAULT_TIMEOUT 200 +bool no_rtt_info(struct rtt_state s) { + return s.srtt == 0; +} + #define MINIMAL_TIMEOUT_ADDITION 20 // This is verbatim (minus the default timeout value and minimal variance) RFC2988, sec. 2 int32_t calc_timeout(struct rtt_state state) { - if (state.srtt == -1 && state.variance == -1) { - return DEFAULT_TIMEOUT; - } return state.srtt + MAX(4 * state.variance, MINIMAL_TIMEOUT_ADDITION); } // This is verbatim RFC2988, sec. 2 struct rtt_state calc_rtt_state(struct rtt_state old, unsigned new_rtt) { - if (old.srtt == -1 && old.variance == -1) { + if (no_rtt_info(old)) { return (struct rtt_state){new_rtt, new_rtt/2}; } @@ -122,10 +125,6 @@ struct rtt_state calc_rtt_state(struct rtt_state old, unsigned new_rtt) { return ret; } -bool no_rtt_info(struct rtt_state s) { - return s.srtt == -1 && s.variance == -1; -} - void check_tls_capable(struct address_state *address_state, struct kr_request *req, struct sockaddr *address) { address_state->tls_capable = req->selection_context.is_tls_capable ? req->selection_context.is_tls_capable(address) : false; } @@ -149,6 +148,9 @@ int cmp_choices(const void *a, const void *b) { struct choice *b_ = (struct choice *) b; int diff; + if ((diff = no_rtt_info(b_->address_state->rtt_state) - no_rtt_info(a_->address_state->rtt_state))) { + return diff; + } if ((diff = a_->address_state->error_count - b_->address_state->error_count)) { return diff; } @@ -158,6 +160,16 @@ int cmp_choices(const void *a, const void *b) { return 0; } +void shuffle_choices(struct choice choices[], int choices_len) { + struct choice tmp; + for (int i = choices_len - 1; i > 0; i--) { + int j = kr_rand_bytes(1) % (i+1); + tmp = choices[i]; + choices[i] = choices[j]; + choices[j] = tmp; + } +} + #define ERROR_LIMIT 2 // Performs the actual selection (currently epsilon-greedy with epsilon = 0.05). @@ -189,6 +201,7 @@ struct kr_transport *choose_transport(struct choice choices[], } } else { // EXPLOIT + shuffle_choices(choices, choices_len); qsort(choices, choices_len, sizeof(struct choice), cmp_choices); if (choices[0].address_state->error_count > ERROR_LIMIT) { return NULL; diff --git a/lib/selection_iter.c b/lib/selection_iter.c index 620a16add..9429882cc 100644 --- a/lib/selection_iter.c +++ b/lib/selection_iter.c @@ -182,8 +182,8 @@ void iter_choose_transport(struct kr_query *qry, struct kr_transport **transport KR_DNAME_GET_STR(ns_name, (*transport)->name); const char *ns_str = kr_straddr(&(*transport)->address.ip); VERBOSE_MSG(qry, - "=> id: '%05u' choosing: '%s'@'%s' zone cut: '%s'\n", - qry->id, ns_name, ns_str ? ns_str : "", zonecut_str); + "=> id: '%05u' choosing: '%s'@'%s' with timeout %d ms zone cut: '%s'\n", + qry->id, ns_name, ns_str ? ns_str : "", (*transport)->timeout, zonecut_str); } else { VERBOSE_MSG(qry, "=> id: '%05u' no suitable transport, zone cut: '%s'\n",