]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
lib: basic nameserver election
authorMarek Vavruša <marek.vavrusa@nic.cz>
Sat, 18 Apr 2015 21:42:15 +0000 (23:42 +0200)
committerMarek Vavruša <marek.vavrusa@nic.cz>
Sat, 18 Apr 2015 21:42:15 +0000 (23:42 +0200)
nameservers with addresses are preferred, the rest
has same weight

no blacklisting, penalization or rtt scoring yet

lib/nsrep.c
lib/nsrep.h
lib/resolve.c

index e49e5312413f60053e5adde032e06e93bfd640e6..02f9bf9af5aa45b4dc58125662d93a6819a18552 100644 (file)
  */
 
 #include "lib/nsrep.h"
+#include "lib/generic/pack.h"
 
-int kr_nsrep_score(const knot_dname_t *ns, struct kr_layer_param *param)
+/** @internal Macro to set address structure. */
+#define ADDR_SET(sa, family, addr, len) do {\
+       memcpy(&sa ## _addr, (addr), (len)); \
+       sa ## _family = (family); \
+       sa ## _port = htons(KR_DNS_PORT); \
+} while (0)
+
+/** Update nameserver representation with current name/address pair. */
+static void update_nsrep(struct kr_nsrep *ns, const knot_dname_t *name, uint8_t *addr, unsigned score)
+{
+       ns->name = name;
+       ns->score = score;
+       if (addr == NULL) {
+               return;
+       }
+
+       size_t len = pack_obj_len(addr);
+       void *addr_val = pack_obj_val(addr);
+       switch(len) {
+       case sizeof(struct in_addr):
+               ADDR_SET(ns->addr.ip4.sin, AF_INET, addr_val, len); break;
+       case sizeof(struct in6_addr):
+               ADDR_SET(ns->addr.ip6.sin6, AF_INET6, addr_val, len); break;
+       default: assert(0); break;
+       }
+}
+
+#undef ADDR_SET
+
+static int eval_nsrep(const char *k, void *v, void *baton)
+{
+       unsigned score = KR_NS_VALID;
+       struct kr_nsrep *ns = baton;
+       pack_t *addr_set = v;
+       uint8_t *addr = NULL;
+
+       /* Name server is better candidate if it has address record. */
+       if (addr_set->len > 0) {
+               addr = pack_head(*addr_set);
+               score += 1;
+       }
+
+       /* Update best scoring nameserver. */
+       if (ns->score < score) {
+               update_nsrep(ns, (const knot_dname_t *)k, addr, score);
+       }
+
+       return kr_ok();
+}
+
+int kr_nsrep_elect(struct kr_nsrep *ns, map_t *nsset)
 {
-       /* TODO: stub, always returns valid */
-       return KR_NS_VALID;
+       ns->addr.ip.sa_family = AF_UNSPEC;
+       ns->score = KR_NS_INVALID;
+       return map_walk(nsset, eval_nsrep, ns);
 }
index 922912a8ded8a55daa916221d0aeda36dec1717b..e61f063f2897545e13c5b834e315685b03fcc8a4 100644 (file)
 
 #pragma once
 
+#include <netinet/in.h>
+
+#include "lib/generic/map.h"
 #include "lib/layer.h"
 
 enum kr_ns_score {
-    KR_NS_INVALID = -1,
-    KR_NS_VALID   = 0
+       KR_NS_INVALID = 0,
+       KR_NS_VALID   = 1
+};
+
+struct kr_nsrep
+{
+       unsigned score;
+       const knot_dname_t *name;
+       union {
+               struct sockaddr ip;
+               struct sockaddr_in ip4;
+               struct sockaddr_in6 ip6;
+       } addr;
 };
 
-/** Return name server score (KR_NS_VALID is baseline, the higher the better).
- * @param ns evaluated NS name
- * @param param layer parameters
- * @return enum kr_ns_score or higher positive value
+/** @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))
+
+/**
+ * Elect best nameserver/address pair from the nsset.
+ * @param  ns    updated NS representation
+ * @param  nsset NS set to choose from
+ * @return       0 if success (ns is updated), error otherwise
  */
-int kr_nsrep_score(const knot_dname_t *ns, struct kr_layer_param *param);
+int kr_nsrep_elect(struct kr_nsrep *ns, map_t *nsset);
 
 /** @} */
index 3f76aa61fe43ed01cb8c20d09c1ccfbd89efa173..47d84133aab28ebb93d2d39c90c54f55484afd4a 100644 (file)
@@ -70,10 +70,17 @@ static int iterate(struct knot_requestor *requestor, struct kr_layer_param *para
        DEBUG_MSG("query '%s %s'\n", name_str, type_str);
 #endif
 
-       /* Invalid address for current zone cut. */
-       if (sockaddr_len((struct sockaddr *)&cur->zone_cut.addr) < 1) {
-               DEBUG_MSG("=> ns missing A/AAAA, fetching\n");
-               return ns_resolve_addr(cur, param);
+       /* Elect best nameserver candidate. */
+       kr_nsrep_elect(&cur->ns, &cur->zone_cut.nsset);
+       if (cur->ns.score < KR_NS_VALID) {
+               DEBUG_MSG("=> no valid NS left\n");
+               kr_rplan_pop(param->rplan, cur);
+               return KNOT_EOK;
+       } else {
+               if (cur->ns.addr.ip.sa_family == AF_UNSPEC) {
+                       DEBUG_MSG("=> ns missing A/AAAA, fetching\n");
+                       return ns_resolve_addr(cur, param);
+               }
        }
 
        /* Prepare query resolution. */
@@ -120,7 +127,7 @@ static void prepare_layers(struct knot_requestor *req, struct kr_layer_param *pa
 
 static int resolve_iterative(struct kr_layer_param *param, mm_ctx_t *pool)
 {
-       /* Initialize requestor. */
+/* Initialize requestor. */
        struct knot_requestor requestor;
        knot_requestor_init(&requestor, pool);
        prepare_layers(&requestor, param);
@@ -143,6 +150,7 @@ static int resolve_iterative(struct kr_layer_param *param, mm_ctx_t *pool)
                }
        }
 
+       DEBUG_MSG("finished: %s, mempool: %llu B\n", knot_strerror(ret), mp_total_size(pool->ctx));
        knot_requestor_clear(&requestor);
        return ret;
 }