]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
lib/resolve: better support for forwarder choice
authorGrigorii Demidov <grigorii.demidov@nic.cz>
Mon, 26 Jun 2017 10:20:39 +0000 (12:20 +0200)
committerVladimír Čunát <vladimir.cunat@nic.cz>
Fri, 30 Jun 2017 13:51:20 +0000 (15:51 +0200)
lib/nsrep.c
lib/nsrep.h
lib/resolve.c

index 564caf30c540a1b5525775d35836e861c02e3da3..dd089e13ff750a3609e24e13f1b5d7a586d8db0b 100644 (file)
@@ -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();
+}
index 302d984c1dc25f0614f2c5c7c8a6af7d6990d7b4..9ca108c4cdb45c61ecf65416b77f2440af312932 100644 (file)
@@ -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);
index 3b2c008c797d49b0757a506224b6fe88b187577f..2ef2cd0a357fd5141d64a5efd4514ac8b2677fcb 100644 (file)
@@ -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) {