]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
lib/nsrep: probabilistic NS probing strategy
authorMarek Vavruša <marek.vavrusa@nic.cz>
Tue, 2 Jun 2015 08:34:38 +0000 (10:34 +0200)
committerMarek Vavruša <marek.vavrusa@nic.cz>
Wed, 3 Jun 2015 00:38:48 +0000 (02:38 +0200)
simplified bee foraging strategy, by default each query goes to the most rewarding NS
however with a chance proportional to the NS RTT, a server may be probed even if it isn’t the most rewarding

lib/nsrep.c
lib/nsrep.h
lib/zonecut.c

index 45b0be77069516b9e9525ec7431bf559df580618..9e7e990905882b241acc7283e00ac7c9ff1fa889 100644 (file)
@@ -24,6 +24,9 @@
 #include "lib/defines.h"
 #include "lib/generic/pack.h"
 
+/** Some built-in unfairness ... */
+#define FAVOUR_IPV6 20 /* 20ms bonus for v6 */
+
 /** @internal Macro to set address structure. */
 #define ADDR_SET(sa, family, addr, len) do {\
        memcpy(&sa ## _addr, (addr), (len)); \
@@ -54,35 +57,55 @@ static void update_nsrep(struct kr_nsrep *ns, const knot_dname_t *name, uint8_t
 
 #undef ADDR_SET
 
-static int eval_nsrep(const char *k, void *v, void *baton)
+static unsigned eval_addr_set(pack_t *addr_set, kr_nsrep_lru_t *rttcache, unsigned score, uint8_t **addr)
 {
-       struct kr_nsrep *ns = baton;
-       unsigned score = ns->score;
-       pack_t *addr_set = v;
-       uint8_t *addr = NULL;
-
        /* Name server is better candidate if it has address record. */
        uint8_t *it = pack_head(*addr_set);
        while (it != pack_tail(*addr_set)) {
                void *val = pack_obj_val(it);
                size_t len = pack_obj_len(it);
-               unsigned *cached = lru_get(ns->repcache, val, len);
+               /* Get RTT for this address (if known) */
+               unsigned *cached = rttcache ? lru_get(rttcache, val, len) : NULL;
                unsigned addr_score = (cached) ? *cached : KR_NS_UNKNOWN / 2;
-               /** @todo Favorize IPv6 */
-               if (addr_score <= score) {
-                       addr = it;
+               /* Give v6 a head start */
+               unsigned favour = (len == sizeof(struct in6_addr)) ? FAVOUR_IPV6 : 0;
+               if (addr_score < score + favour) {
+                       *addr = it;
                        score = addr_score;
                }
                it = pack_obj_next(it);
        }
-       /* No known address */
-       if (!addr) {
+       return score;
+}
+
+static int eval_nsrep(const char *k, void *v, void *baton)
+{
+       struct kr_nsrep *ns = baton;
+       unsigned score = KR_NS_MAX_SCORE;
+       uint8_t *addr = NULL;
+
+       /* Favour nameservers with unknown addresses to probe them,
+        * otherwise discover the current best address for the NS. */
+       pack_t *addr_set = (pack_t *)v;
+       if (addr_set->len == 0) {
                score = KR_NS_UNKNOWN;
+       } else {
+               score = eval_addr_set(addr_set, ns->repcache, score, &addr);
        }
 
-       /* Update best scoring nameserver. */
-       if (score < ns->score) {
+       /* Probabilistic bee foraging strategy (naive).
+        * The fastest NS is preferred by workers until it is depleted (timeouts or degrades),
+        * at the same time long distance scouts probe other sources (low probability).
+        * Servers on TIMEOUT (depleted) can be probed by the dice roll only */
+       if (score < ns->score && score < KR_NS_TIMEOUT) {
                update_nsrep(ns, (const knot_dname_t *)k, addr, score);
+       } else {
+               /* With 5% chance, probe server with a probability given by its RTT / MAX_RTT */
+               unsigned roll = rand() % KR_NS_MAX_SCORE;
+               if ((roll % 100 < 5) && (roll >= score)) {
+                       update_nsrep(ns, (const knot_dname_t *)k, addr, score);
+                       return 1; /* Stop evaluation */
+               }
        }
 
        return kr_ok();
index 11dbc7e40f989b4029204ec0f06e16b76d507124..eeda40b7227f1653f0a13df8ed15cfa08769f176 100644 (file)
@@ -20,6 +20,7 @@
 #include <libknot/dname.h>
 #include <limits.h>
 
+#include "lib/defines.h"
 #include "lib/generic/map.h"
 #include "lib/generic/lru.h"
 
@@ -27,8 +28,8 @@
   * Special values for nameserver score (RTT in miliseconds)
   */
 enum kr_ns_score {
-       KR_NS_MAX_SCORE = 10 * 1000,
-       KR_NS_TIMEOUT   = KR_NS_MAX_SCORE,
+       KR_NS_MAX_SCORE = KR_CONN_RTT_MAX,
+       KR_NS_TIMEOUT   = (90 * KR_NS_MAX_SCORE) / 100,
        KR_NS_UNKNOWN   = 10
 };
 
index 0fb3dfb91d14881c4f1731540019dfbe7b588910..ec150fe0b4d97217febfa5dd4430276c1e7a4205 100644 (file)
@@ -210,6 +210,11 @@ static int fetch_ns(struct kr_zonecut *cut, const knot_dname_t *name, struct kr_
                kr_zonecut_add(cut, ns_name, NULL);
        }
 
+       /* Always keep SBELT as a backup for root */
+       if (name[0] == '\0') {
+               kr_zonecut_set_sbelt(cut);
+       }
+
        return kr_ok();
 }