]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
new serve_stale module
authorVladimír Čunát <vladimir.cunat@nic.cz>
Mon, 15 Jan 2018 16:22:01 +0000 (17:22 +0100)
committerVladimír Čunát <vladimir.cunat@nic.cz>
Wed, 31 Jan 2018 08:36:38 +0000 (09:36 +0100)
Decision function is separated out.

daemon/lua/kres-gen.lua
daemon/lua/kres-gen.sh
doc/modules.rst
lib/cache/api.c
lib/rplan.c
lib/rplan.h
modules/modules.mk
modules/serve_stale/README.rst [new file with mode: 0644]
modules/serve_stale/serve_stale.lua [new file with mode: 0644]
modules/serve_stale/serve_stale.mk [new file with mode: 0644]

index 68d0dd268b04e1ca14a33e57771f360b5da84747..8fdd010aca79f7471dd83f81d9ce42a8f20a8b85 100644 (file)
@@ -97,6 +97,7 @@ struct kr_qflags {
        _Bool NONAUTH : 1;
        _Bool FORWARD : 1;
        _Bool DNS64_MARK : 1;
+       _Bool CACHE_TRIED : 1;
 };
 typedef struct {
        knot_rrset_t **at;
@@ -185,6 +186,9 @@ struct kr_cache {
        struct timeval last_clear_walltime;
        uint64_t last_clear_monotime;
 };
+
+typedef int32_t (*kr_stale_cb)(int32_t ttl, const knot_dname_t *owner, uint16_t type,
+                               const struct kr_query *qry);
 struct knot_rrset {
        knot_dname_t *_owner;
        uint16_t type;
@@ -219,6 +223,7 @@ struct kr_query {
        uint32_t uid;
        struct kr_query *cname_parent;
        struct kr_request *request;
+       kr_stale_cb stale_cb;
 };
 struct kr_context {
        struct kr_qflags options;
@@ -280,6 +285,7 @@ struct sockaddr *kr_straddr_socket(const char *, int);
 int kr_ranked_rrarray_add(ranked_rr_array_t *, const knot_rrset_t *, uint8_t, _Bool, uint32_t, knot_mm_t *);
 void kr_qflags_set(struct kr_qflags *, struct kr_qflags);
 void kr_qflags_clear(struct kr_qflags *, struct kr_qflags);
+void kr_query_set_stale_cb(struct kr_query *, kr_stale_cb);
 int kr_zonecut_add(struct kr_zonecut *, const knot_dname_t *, const knot_rdata_t *);
 void kr_zonecut_set(struct kr_zonecut *, const knot_dname_t *);
 uint64_t kr_now();
index ff673a517cf3b7b9590ab8f22e7f5b6bbc8e5b70..59fafce76e9b736ae1177f5fcf42408370026816 100755 (executable)
@@ -65,6 +65,11 @@ typedef void (*trace_callback_f)(struct kr_request *);
        struct kr_cache
 EOF
 
+printf "
+typedef int32_t (*kr_stale_cb)(int32_t ttl, const knot_dname_t *owner, uint16_t type,
+                               const struct kr_query *qry);
+"
+
 genResType() {
        echo "$1" | ./scripts/gen-cdefs.sh libkres types
 }
@@ -147,6 +152,7 @@ EOF
        kr_ranked_rrarray_add
        kr_qflags_set
        kr_qflags_clear
+       kr_query_set_stale_cb
        kr_zonecut_add
        kr_zonecut_set
        kr_now
index 5e01e981b29d5678fb23bfd2d3a33e9f29702d86..f109b3c8850b28f7fd42fb5e4592a5629013a198 100644 (file)
@@ -28,5 +28,6 @@ Knot DNS Resolver modules
 .. include:: ../modules/ta_signal_query/README.rst
 .. include:: ../modules/ta_sentinel/README.rst
 .. include:: ../modules/priming/README.rst
+.. include:: ../modules/serve_stale/README.rst
 .. include:: ../modules/detect_time_skew/README.rst
 .. include:: ../modules/detect_time_jump/README.rst
index b2937bc33a45bdafe81f910841880dab0c6fd7e8..6860dd52e6c2c5c03f2c370f61431d4a535d0119 100644 (file)
@@ -224,12 +224,11 @@ int32_t get_new_ttl(const struct entry_h *entry, const struct kr_query *qry,
                diff = 0;
        }
        int32_t res = entry->ttl - diff;
-       if (res < 0 && owner && false/*qry->flags.SERVE_STALE*/) {
+       if (res < 0 && owner && qry->stale_cb) {
                /* Stale-serving decision.  FIXME: modularize or make configurable, etc. */
-               if (res + 3600 * 24 > 0) {
-                       VERBOSE_MSG(qry, "stale TTL accepted: %d -> 1\n", (int)res);
-                       return 1;
-               }
+               int res_stale = qry->stale_cb(res, owner, type, qry);
+               if (res_stale >= 0)
+                       return res_stale;
        }
        return res;
 }
@@ -315,6 +314,7 @@ int cache_peek(kr_layer_t *ctx, knot_pkt_t *pkt)
        struct kr_query *qry = req->current_query;
 
        if (ctx->state & (KR_STATE_FAIL|KR_STATE_DONE) || qry->flags.NO_CACHE
+           || (qry->flags.CACHE_TRIED && !qry->stale_cb)
            || qry->stype == KNOT_RRTYPE_RRSIG /* LATER: some other behavior for this STYPE? */
            || qry->sclass != KNOT_CLASS_IN) {
                return ctx->state; /* Already resolved/failed or already tried, etc. */
@@ -337,7 +337,7 @@ static int cache_peek_real(kr_layer_t *ctx, knot_pkt_t *pkt)
        /* ATM cache only peeks for qry->sname and that would be useless
         * to repeat on every iteration, so disable it from now on.
         * LATER(optim.): assist with more precise QNAME minimization. */
-       qry->flags.NO_CACHE = true;
+       qry->flags.CACHE_TRIED = true;
 
        struct key k_storage, *k = &k_storage;
        if (qry->stype == KNOT_RRTYPE_NSEC) {
index e18d96a13aa9204277ac9376c345160300e6cb66..a21e05a760461c6916b45c00418990c7c9e0f22c 100644 (file)
 #define QUERY_PROVIDES(q, name, cls, type) \
     ((q)->sclass == (cls) && (q)->stype == type && knot_dname_is_equal((q)->sname, name))
 
+void kr_query_set_stale_cb(struct kr_query *qry, kr_stale_cb cb)
+{
+       qry->stale_cb = cb;
+}
+
 inline static unsigned char chars_or(const unsigned char a, const unsigned char b)
 {
        return a | b;
index 52b3e242c161e96489b3f31d05b1c067018c9de9..2d3810c601f9912a438bdab00fef71dcbabb8f42 100644 (file)
@@ -61,6 +61,7 @@ struct kr_qflags {
                                  * TODO: utilize this also outside cache. */
        bool FORWARD : 1;        /**< Forward all queries to upstream; validate answers. */
        bool DNS64_MARK : 1;     /**< Internal mark for dns64 module. */
+       bool CACHE_TRIED : 1;    /**< Internal to cache module. */
 };
 
 /** Combine flags together.  This means set union for simple flags. */
@@ -71,6 +72,17 @@ void kr_qflags_set(struct kr_qflags *fl1, struct kr_qflags fl2);
 KR_EXPORT
 void kr_qflags_clear(struct kr_qflags *fl1, struct kr_qflags fl2);
 
+/** Callback for serve-stale decisions.
+ * @param ttl the expired TTL (i.e. it's < 0)
+ * @return the adjusted TTL (typically 1) or < 0.
+ */
+typedef int32_t (*kr_stale_cb)(int32_t ttl, const knot_dname_t *owner, uint16_t type,
+                               const struct kr_query *qry);
+/** Trivial wrapper to set kr_query::stale_cb.
+ * For some unknown reason, direct setting via lua doesn't work. */
+KR_EXPORT
+void kr_query_set_stale_cb(struct kr_query *qry, kr_stale_cb cb);
+
 /**
  * Single query representation.
  */
@@ -97,6 +109,7 @@ struct kr_query {
        /** Pointer to the query that originated this one because of following a CNAME (or NULL). */
        struct kr_query *cname_parent;
        struct kr_request *request; /**< Parent resolution request. */
+       kr_stale_cb stale_cb; /**< See the type */
 };
 
 /** @cond internal Array of queries. */
index ea63491c6fa62303663e3120458324224506d9f2..864058f679bfcd2271e4ad501462a96b9060d868 100644 (file)
@@ -36,6 +36,7 @@ modules_TARGETS += etcd \
                    version \
                    ta_signal_query \
                    priming \
+                   serve_stale \
                    detect_time_skew \
                    detect_time_jump
 endif
diff --git a/modules/serve_stale/README.rst b/modules/serve_stale/README.rst
new file mode 100644 (file)
index 0000000..74ee09b
--- /dev/null
@@ -0,0 +1,21 @@
+.. _mod-serve_stale:
+
+Serve stale
+-----------
+
+Demo module that allows using timed-out records in case kresd is
+unable to contact upstream servers.
+
+By default it allows stale-ness by up to one day,
+after roughly four seconds trying to contact the servers.
+It's quite configurable/flexible; see the beginning of the module source for details.
+See also the RFC draft_ (not fully followed).
+
+Running
+^^^^^^^
+.. code-block:: lua
+
+    modules = { 'serve_stale < cache' }
+
+.. _draft: https://tools.ietf.org/html/draft-ietf-dnsop-serve-stale-00
+
diff --git a/modules/serve_stale/serve_stale.lua b/modules/serve_stale/serve_stale.lua
new file mode 100644 (file)
index 0000000..c052766
--- /dev/null
@@ -0,0 +1,42 @@
+local M = {} -- the module
+
+local ffi = require('ffi')
+
+-- Beware that the timeout is only considered at certain points in time;
+-- approximately at multiples of KR_CONN_RTT_MAX.
+M.timeout = 3*sec
+
+M.callback = ffi.cast("kr_stale_cb",
+       function (ttl) --, name, type, qry)
+               --log('[     ][stal]   => called back with TTL: ' .. tostring(ttl))
+               if ttl + 3600 * 24 > 0 then -- at most one day stale
+                       return 1
+               else
+                       return -1
+               end
+       end)
+
+M.layer = {
+       produce = function (state, req)
+               req = kres.request_t(req)
+               local qry = req:current()
+               -- Don't do anything for priming, prefetching, etc.
+               -- TODO: not all cases detected ATM.
+               if qry.flags.NO_CACHE then return state end
+
+               local now = ffi.C.kr_now()
+               local deadline = qry.creation_time_mono + M.timeout
+               if now > deadline then
+                       --log('[     ][stal]   => deadline has passed')
+                       ffi.C.kr_query_set_stale_cb(qry, M.callback)
+                       -- TODO: probably start the same request that doesn't stale-serve,
+                       -- but first we need some detection of non-interactive / internal requests.
+                       -- resolve(kres.dname2str(qry.sname), qry.stype, qry.sclass)
+               end
+
+               return state
+       end,
+}
+
+return M
+
diff --git a/modules/serve_stale/serve_stale.mk b/modules/serve_stale/serve_stale.mk
new file mode 100644 (file)
index 0000000..46c6f64
--- /dev/null
@@ -0,0 +1,2 @@
+serve_stale_SOURCES := serve_stale.lua
+$(call make_lua_module,serve_stale)