From: Grigorii Demidov Date: Mon, 26 Jun 2017 10:20:39 +0000 (+0200) Subject: lib/resolve: better support for forwarder choice X-Git-Tag: v1.3.2~14^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cd2755bf635573251bea46f33f68f68f3f8a6b22;p=thirdparty%2Fknot-resolver.git lib/resolve: better support for forwarder choice --- diff --git a/lib/nsrep.c b/lib/nsrep.c index 564caf30c..dd089e13f 100644 --- a/lib/nsrep.c +++ b/lib/nsrep.c @@ -335,3 +335,56 @@ int kr_nsrep_copy_set(struct kr_nsrep *dst, const struct kr_nsrep *src) return kr_ok(); } + +int kr_nsrep_elect_min_rtt(struct kr_query *qry) +{ + /* TODO - sorting instead of searching minimum? */ + struct kr_nsrep *ns = &qry->ns; + + if (ns->addr[0].ip.sa_family == AF_UNSPEC) { + return kr_error(EINVAL); + } + + if (ns->addr[1].ip.sa_family == AF_UNSPEC) { + /* We have only one entry here, do nothing */ + return kr_ok(); + } + + const struct kr_context *ctx = ns->ctx; + if (!ctx) { + return kr_ok(); + } + + const struct sockaddr *sock = (const struct sockaddr *)(&ns->addr[0]); + unsigned *score = lru_get_try(ctx->cache_rtt, kr_inaddr(sock), + kr_family_len(sock->sa_family)); + unsigned minimal_score = (score) ? *score : KR_NS_MAX_SCORE + 1; + int i = 1; + sock = (const struct sockaddr *)(&ns->addr[i]); + do { + score = lru_get_try(ctx->cache_rtt, kr_inaddr(sock), + kr_family_len(sock->sa_family)); + if (score) { + if (*score < minimal_score) { + union inaddr temp_addr = ns->addr[0]; + ns->addr[0] = ns->addr[i]; + ns->addr[i] = temp_addr; + ns->score = *score; + ns->reputation = 0; + minimal_score = ns->score; + } else if ((kr_rand_uint(100) < 10) && + (kr_rand_uint(KR_NS_MAX_SCORE) >= *score)) { + /* long distance probe */ + union inaddr temp_addr = ns->addr[0]; + ns->addr[0] = ns->addr[i]; + ns->addr[i] = temp_addr; + ns->score = *score; + ns->reputation = 0; + break; + } + } + sock = (const struct sockaddr *)(&ns->addr[++i]); + } while ((i < KR_NSREP_MAXADDR) && (sock->sa_family != AF_UNSPEC)); + + return kr_ok(); +} diff --git a/lib/nsrep.h b/lib/nsrep.h index 302d984c1..9ca108c4c 100644 --- a/lib/nsrep.h +++ b/lib/nsrep.h @@ -150,3 +150,12 @@ int kr_nsrep_update_rep(struct kr_nsrep *ns, unsigned reputation, kr_nsrep_lru_t * @return 0 on success, error code on failure */ int kr_nsrep_copy_set(struct kr_nsrep *dst, const struct kr_nsrep *src); + +/** + * Elect address with minimal rtt within current query nsrep list + * @note ns reputation is zeroed + * @param qry updated query + * @return 0 or an error code + */ +KR_EXPORT +int kr_nsrep_elect_min_rtt(struct kr_query *qry); diff --git a/lib/resolve.c b/lib/resolve.c index 3b2c008c7..2ef2cd0a3 100644 --- a/lib/resolve.c +++ b/lib/resolve.c @@ -1378,9 +1378,11 @@ ns_election: return KR_STATE_FAIL; } - const bool retry = (qry->flags & (QUERY_TCP|QUERY_STUB|QUERY_FORWARD|QUERY_BADCOOKIE_AGAIN)); + const bool retry = (qry->flags & (QUERY_TCP|QUERY_STUB|QUERY_BADCOOKIE_AGAIN)); if (qry->flags & (QUERY_AWAIT_IPV4|QUERY_AWAIT_IPV6)) { kr_nsrep_elect_addr(qry, request->ctx); + } else if (qry->flags & QUERY_FORWARD) { + kr_nsrep_elect_min_rtt(qry); } else if (!qry->ns.name || !retry) { /* Keep NS when requerying/stub/badcookie. */ /* Root DNSKEY must be fetched from the hints to avoid chicken and egg problem. */ if (qry->sname[0] == '\0' && qry->stype == KNOT_RRTYPE_DNSKEY) {