Commit a9cbecab authored by Vladimír Čunát's avatar Vladimír Čunát

Merge !318: lib/resolve: use RTT tracking to choose forwarders

Closes #125 and #208.
parents 95edeb40 ac55abb4
Pipeline #7407 canceled with stages
in 74 minutes and 46 seconds
......@@ -4,6 +4,7 @@ Knot Resolver 1.3.2 (2017-07-xx)
Bugfixes
--------
- daemon: check existence of config file even if rundir isn't specified
- policy.FORWARD and STUB: use RTT tracking to choose servers (#125, #208)
Knot Resolver 1.3.1 (2017-06-23)
......
......@@ -19,6 +19,8 @@
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include "lib/nsrep.h"
#include "lib/rplan.h"
#include "lib/resolve.h"
......@@ -269,8 +271,8 @@ int kr_nsrep_update_rtt(struct kr_nsrep *ns, const struct sockaddr *addr,
return kr_error(EINVAL);
}
const char *addr_in = kr_nsrep_inaddr(ns->addr[0]);
size_t addr_len = kr_nsrep_inaddr_len(ns->addr[0]);
const char *addr_in = kr_inaddr(&ns->addr[0].ip);
size_t addr_len = kr_inaddr_len(&ns->addr[0].ip);
if (addr) { /* Caller provided specific address */
if (addr->sa_family == AF_INET) {
addr_in = (const char *)&((struct sockaddr_in *)addr)->sin_addr;
......@@ -335,3 +337,69 @@ int kr_nsrep_copy_set(struct kr_nsrep *dst, const struct kr_nsrep *src)
return kr_ok();
}
int kr_nsrep_sort(struct kr_nsrep *ns, kr_nsrep_lru_t *cache)
{
if (!ns || !cache) {
assert(false);
return kr_error(EINVAL);
}
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();
}
/* Compute the scores. Unfortunately there's no space for scores
* along the addresses. */
unsigned scores[KR_NSREP_MAXADDR];
int i;
for (i = 0; i < KR_NSREP_MAXADDR; ++i) {
const struct sockaddr *sa = &ns->addr[i].ip;
if (sa->sa_family == AF_UNSPEC) {
break;
}
unsigned *score = lru_get_try(cache, kr_inaddr(sa),
kr_family_len(sa->sa_family));
if (!score) {
scores[i] = 1; /* prefer unknown to probe RTT */
} else if ((kr_rand_uint(100) < 10)
&& (kr_rand_uint(KR_NS_MAX_SCORE) >= *score)) {
/* some probability to bump bad ones up for re-probe */
scores[i] = 1;
} else {
scores[i] = *score;
}
WITH_VERBOSE {
char sa_str[INET6_ADDRSTRLEN];
inet_ntop(sa->sa_family, kr_inaddr(sa), sa_str, sizeof(sa_str));
kr_log_verbose("[ ][nsre] score %d for %s;\t cached RTT: %d\n",
scores[i], sa_str, score ? *score : -1);
}
}
/* Select-sort the addresses. */
const int count = i;
for (i = 0; i < count - 1; ++i) {
/* find min from i onwards */
int min_i = i;
for (int j = i + 1; j < count; ++j) {
if (scores[j] < scores[min_i]) {
min_i = j;
}
}
/* swap the indices */
if (min_i != i) {
SWAP(scores[min_i], scores[i]);
SWAP(ns->addr[min_i], ns->addr[i]);
}
}
ns->score = scores[0];
ns->reputation = 0;
return kr_ok();
}
......@@ -81,13 +81,6 @@ struct kr_nsrep
union inaddr addr[KR_NSREP_MAXADDR]; /**< NS address(es) */
};
/** @internal Address bytes for given family. */
#define kr_nsrep_inaddr(addr) \
((addr).ip.sa_family == AF_INET ? (void *)&((addr).ip4.sin_addr) : (void *)&((addr).ip6.sin6_addr))
/** @internal Address length for given family. */
#define kr_nsrep_inaddr_len(addr) \
((addr).ip.sa_family == AF_INET ? sizeof(struct in_addr) : sizeof(struct in6_addr))
/**
* Set given NS address.
* @param qry updated query
......@@ -150,3 +143,15 @@ 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);
/**
* Sort addresses in the query nsrep list
* @param ns updated kr_nsrep
* @param cache RTT cache
* @return 0 or an error code
* @note ns reputation is zeroed, as KR_NS_NOIP{4,6} flags are useless
* in STUB/FORWARD mode.
*/
KR_EXPORT
int kr_nsrep_sort(struct kr_nsrep *ns, kr_nsrep_lru_t *cache);
......@@ -149,11 +149,11 @@ static void randomized_qname_case(knot_dname_t * restrict qname, uint32_t secret
static int invalidate_ns(struct kr_rplan *rplan, struct kr_query *qry)
{
if (qry->ns.addr[0].ip.sa_family != AF_UNSPEC) {
uint8_t *addr = kr_nsrep_inaddr(qry->ns.addr[0]);
size_t addr_len = kr_nsrep_inaddr_len(qry->ns.addr[0]);
const char *addr = kr_inaddr(&qry->ns.addr[0].ip);
size_t addr_len = kr_inaddr_len(&qry->ns.addr[0].ip);
/* @warning _NOT_ thread-safe */
static knot_rdata_t rdata_arr[RDATA_ARR_MAX];
knot_rdata_init(rdata_arr, addr_len, addr, 0);
knot_rdata_init(rdata_arr, addr_len, (const uint8_t *)addr, 0);
return kr_zonecut_del(&qry->zone_cut, qry->ns.name, rdata_arr);
} else {
return kr_zonecut_del_all(&qry->zone_cut, qry->ns.name);
......@@ -1378,9 +1378,11 @@ int kr_resolve_produce(struct kr_request *request, struct sockaddr **dst, int *t
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_BADCOOKIE_AGAIN));
if (qry->flags & (QUERY_AWAIT_IPV4|QUERY_AWAIT_IPV6)) {
kr_nsrep_elect_addr(qry, request->ctx);
} else if (qry->flags & (QUERY_FORWARD|QUERY_STUB)) {
kr_nsrep_sort(&qry->ns, request->ctx->cache_rtt);
} 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) {
......@@ -1506,7 +1508,7 @@ int kr_resolve_checkout(struct kr_request *request, struct sockaddr *src,
if (!kr_inaddr_equal(dst, addr)) {
continue;
}
inet_ntop(addr->sa_family, kr_nsrep_inaddr(qry->ns.addr[i]), ns_str, sizeof(ns_str));
inet_ntop(addr->sa_family, kr_inaddr(&qry->ns.addr[i].ip), ns_str, sizeof(ns_str));
VERBOSE_MSG(qry, "=> querying: '%s' score: %u zone cut: '%s' m12n: '%s' type: '%s' proto: '%s'\n",
ns_str, qry->ns.score, zonecut_str, qname_str, type_str, (qry->flags & QUERY_TCP) ? "tcp" : "udp");
break;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment