From: Štěpán Balážik Date: Tue, 1 Sep 2020 07:55:06 +0000 (+0200) Subject: selection: fix reporting of deduplicated packet X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1bc3206cd51ae4be5d2b5ac0c8d83cfbecce91f0;p=thirdparty%2Fknot-resolver.git selection: fix reporting of deduplicated packet --- diff --git a/daemon/worker.c b/daemon/worker.c index b01ef73d9..133592420 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -1115,7 +1115,12 @@ static void subreq_finalize(struct qr_task *task, const struct sockaddr *packet_ struct kr_query *qry = array_tail(follower->ctx->req.rplan.pending); qry->id = leader_qry->id; qry->secret = leader_qry->secret; + + // Note that this transport may not be present in `leader_qry`'s server selection follower->transport = task->transport; + if(follower->transport) { + follower->transport->deduplicated = true; + } leader_qry->secret = 0; /* Next will be already decoded */ } qr_task_step(follower, packet_source, pkt); diff --git a/lib/selection.c b/lib/selection.c index 20eddcd19..1af07fe32 100644 --- a/lib/selection.c +++ b/lib/selection.c @@ -274,7 +274,7 @@ struct kr_transport *choose_transport(struct choice choices[], } void update_rtt(struct kr_query *qry, struct address_state *addr_state, const struct kr_transport *transport, unsigned rtt) { - if (!transport) { + if (!transport || !addr_state) { return; } @@ -298,6 +298,11 @@ void update_rtt(struct kr_query *qry, struct address_state *addr_state, const st } void cache_timeout(const struct kr_transport *transport, struct address_state *addr_state, struct kr_cache *cache) { + if (transport->deduplicated) { + // Transport was chosen by a different query, that one will cache the result. + return; + } + uint8_t *address = ip_to_bytes(&transport->address, transport->address_len); struct rtt_state old_state = addr_state->rtt_state; struct rtt_state cur_state = get_rtt_state(address, transport->address_len, cache); @@ -311,7 +316,7 @@ void cache_timeout(const struct kr_transport *transport, struct address_state *a void error(struct kr_query *qry, struct address_state *addr_state, const struct kr_transport *transport, enum kr_selection_error sel_error) { - if (!transport) { + if (!transport || !addr_state) { return; } @@ -321,7 +326,10 @@ void error(struct kr_query *qry, struct address_state *addr_state, const struct if (sel_error == KR_SELECTION_TIMEOUT) { qry->server_selection.timeouts++; - cache_timeout(transport, addr_state, &qry->request->ctx->cache); + if (!transport->deduplicated) { + // Make sure the query was chosen by this query + cache_timeout(transport, addr_state, &qry->request->ctx->cache); + } } addr_state->errors[sel_error]++; diff --git a/lib/selection.h b/lib/selection.h index 55335902d..1251e302a 100644 --- a/lib/selection.h +++ b/lib/selection.h @@ -41,6 +41,8 @@ struct kr_transport { size_t address_len; enum kr_transport_protocol protocol; unsigned timeout; + bool deduplicated; // True iff transport was set in worker.c:subreq_finalize, + // that means it may be different from the one originally chosen one. }; struct kr_server_selection diff --git a/lib/selection_forward.c b/lib/selection_forward.c index a4dda3023..23385368f 100644 --- a/lib/selection_forward.c +++ b/lib/selection_forward.c @@ -77,12 +77,19 @@ void forward_success(struct kr_query *qry, const struct kr_transport *transport) } void forward_error(struct kr_query *qry, const struct kr_transport *transport, enum kr_selection_error sel_error) { + if (!qry->server_selection.initialized) { + return; + } struct forward_local_state *local_state = qry->server_selection.local_state; struct address_state *addr_state = &local_state->addr_states[local_state->last_choice_index]; error(qry, addr_state, transport, sel_error); } void forward_update_rtt(struct kr_query *qry, const struct kr_transport *transport, unsigned rtt) { + if (!qry->server_selection.initialized) { + return; + } + if (!transport) { return; } diff --git a/lib/selection_iter.c b/lib/selection_iter.c index 6019cdf75..ea97f8f42 100644 --- a/lib/selection_iter.c +++ b/lib/selection_iter.c @@ -25,18 +25,27 @@ struct iter_name_state { unsigned int generation; }; -void iter_local_state_init(struct knot_mm *mm, void **local_state) { +void iter_local_state_alloc(struct knot_mm *mm, void **local_state) { *local_state = mm_alloc(mm, sizeof(struct iter_local_state)); memset(*local_state, 0, sizeof(struct iter_local_state)); } struct address_state *get_address_state(struct iter_local_state *local_state, const struct kr_transport *transport) { + if (!transport) { + return NULL; + } + trie_t *addresses = local_state->addresses; uint8_t *address = ip_to_bytes(&transport->address, transport->address_len); trie_val_t *address_state = trie_get_try(addresses, (char *)address, transport->address_len); if (!address_state) { + if (transport->deduplicated) { + // Transport was chosen by a different query + return NULL; + } + assert(0); } return (struct address_state *)*address_state; @@ -196,12 +205,18 @@ void iter_success(struct kr_query *qry, const struct kr_transport *transport) { } void iter_error(struct kr_query *qry, const struct kr_transport *transport, enum kr_selection_error sel_error) { + if (!qry->server_selection.initialized) { + return; + } struct iter_local_state *local_state = qry->server_selection.local_state; struct address_state *addr_state = get_address_state(local_state, transport); error(qry, addr_state, transport, sel_error); } void iter_update_rtt(struct kr_query *qry, const struct kr_transport *transport, unsigned rtt) { + if (!qry->server_selection.initialized) { + return; + } struct iter_local_state *local_state = qry->server_selection.local_state; struct address_state *addr_state = get_address_state(local_state, transport); update_rtt(qry, addr_state, transport, rtt);