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

new serve_stale module

Decision function is separated out.
parent c6427405
...@@ -97,6 +97,7 @@ struct kr_qflags { ...@@ -97,6 +97,7 @@ struct kr_qflags {
_Bool NONAUTH : 1; _Bool NONAUTH : 1;
_Bool FORWARD : 1; _Bool FORWARD : 1;
_Bool DNS64_MARK : 1; _Bool DNS64_MARK : 1;
_Bool CACHE_TRIED : 1;
}; };
typedef struct { typedef struct {
knot_rrset_t **at; knot_rrset_t **at;
...@@ -185,6 +186,9 @@ struct kr_cache { ...@@ -185,6 +186,9 @@ struct kr_cache {
struct timeval last_clear_walltime; struct timeval last_clear_walltime;
uint64_t last_clear_monotime; 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 { struct knot_rrset {
knot_dname_t *_owner; knot_dname_t *_owner;
uint16_t type; uint16_t type;
...@@ -219,6 +223,7 @@ struct kr_query { ...@@ -219,6 +223,7 @@ struct kr_query {
uint32_t uid; uint32_t uid;
struct kr_query *cname_parent; struct kr_query *cname_parent;
struct kr_request *request; struct kr_request *request;
kr_stale_cb stale_cb;
}; };
struct kr_context { struct kr_context {
struct kr_qflags options; struct kr_qflags options;
...@@ -280,6 +285,7 @@ struct sockaddr *kr_straddr_socket(const char *, int); ...@@ -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 *); 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_set(struct kr_qflags *, struct kr_qflags);
void kr_qflags_clear(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 *); 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 *); void kr_zonecut_set(struct kr_zonecut *, const knot_dname_t *);
uint64_t kr_now(); uint64_t kr_now();
......
...@@ -65,6 +65,11 @@ typedef void (*trace_callback_f)(struct kr_request *); ...@@ -65,6 +65,11 @@ typedef void (*trace_callback_f)(struct kr_request *);
struct kr_cache struct kr_cache
EOF 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() { genResType() {
echo "$1" | ./scripts/gen-cdefs.sh libkres types echo "$1" | ./scripts/gen-cdefs.sh libkres types
} }
...@@ -147,6 +152,7 @@ EOF ...@@ -147,6 +152,7 @@ EOF
kr_ranked_rrarray_add kr_ranked_rrarray_add
kr_qflags_set kr_qflags_set
kr_qflags_clear kr_qflags_clear
kr_query_set_stale_cb
kr_zonecut_add kr_zonecut_add
kr_zonecut_set kr_zonecut_set
kr_now kr_now
......
...@@ -28,5 +28,6 @@ Knot DNS Resolver modules ...@@ -28,5 +28,6 @@ Knot DNS Resolver modules
.. include:: ../modules/ta_signal_query/README.rst .. include:: ../modules/ta_signal_query/README.rst
.. include:: ../modules/ta_sentinel/README.rst .. include:: ../modules/ta_sentinel/README.rst
.. include:: ../modules/priming/README.rst .. include:: ../modules/priming/README.rst
.. include:: ../modules/serve_stale/README.rst
.. include:: ../modules/detect_time_skew/README.rst .. include:: ../modules/detect_time_skew/README.rst
.. include:: ../modules/detect_time_jump/README.rst .. include:: ../modules/detect_time_jump/README.rst
...@@ -224,12 +224,11 @@ int32_t get_new_ttl(const struct entry_h *entry, const struct kr_query *qry, ...@@ -224,12 +224,11 @@ int32_t get_new_ttl(const struct entry_h *entry, const struct kr_query *qry,
diff = 0; diff = 0;
} }
int32_t res = entry->ttl - diff; 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. */ /* Stale-serving decision. FIXME: modularize or make configurable, etc. */
if (res + 3600 * 24 > 0) { int res_stale = qry->stale_cb(res, owner, type, qry);
VERBOSE_MSG(qry, "stale TTL accepted: %d -> 1\n", (int)res); if (res_stale >= 0)
return 1; return res_stale;
}
} }
return res; return res;
} }
...@@ -315,6 +314,7 @@ int cache_peek(kr_layer_t *ctx, knot_pkt_t *pkt) ...@@ -315,6 +314,7 @@ int cache_peek(kr_layer_t *ctx, knot_pkt_t *pkt)
struct kr_query *qry = req->current_query; struct kr_query *qry = req->current_query;
if (ctx->state & (KR_STATE_FAIL|KR_STATE_DONE) || qry->flags.NO_CACHE 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->stype == KNOT_RRTYPE_RRSIG /* LATER: some other behavior for this STYPE? */
|| qry->sclass != KNOT_CLASS_IN) { || qry->sclass != KNOT_CLASS_IN) {
return ctx->state; /* Already resolved/failed or already tried, etc. */ 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) ...@@ -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 /* ATM cache only peeks for qry->sname and that would be useless
* to repeat on every iteration, so disable it from now on. * to repeat on every iteration, so disable it from now on.
* LATER(optim.): assist with more precise QNAME minimization. */ * 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; struct key k_storage, *k = &k_storage;
if (qry->stype == KNOT_RRTYPE_NSEC) { if (qry->stype == KNOT_RRTYPE_NSEC) {
......
...@@ -27,6 +27,11 @@ ...@@ -27,6 +27,11 @@
#define QUERY_PROVIDES(q, name, cls, type) \ #define QUERY_PROVIDES(q, name, cls, type) \
((q)->sclass == (cls) && (q)->stype == type && knot_dname_is_equal((q)->sname, name)) ((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) inline static unsigned char chars_or(const unsigned char a, const unsigned char b)
{ {
return a | b; return a | b;
......
...@@ -61,6 +61,7 @@ struct kr_qflags { ...@@ -61,6 +61,7 @@ struct kr_qflags {
* TODO: utilize this also outside cache. */ * TODO: utilize this also outside cache. */
bool FORWARD : 1; /**< Forward all queries to upstream; validate answers. */ bool FORWARD : 1; /**< Forward all queries to upstream; validate answers. */
bool DNS64_MARK : 1; /**< Internal mark for dns64 module. */ 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. */ /** 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); ...@@ -71,6 +72,17 @@ void kr_qflags_set(struct kr_qflags *fl1, struct kr_qflags fl2);
KR_EXPORT KR_EXPORT
void kr_qflags_clear(struct kr_qflags *fl1, struct kr_qflags fl2); 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. * Single query representation.
*/ */
...@@ -97,6 +109,7 @@ struct kr_query { ...@@ -97,6 +109,7 @@ struct kr_query {
/** Pointer to the query that originated this one because of following a CNAME (or NULL). */ /** Pointer to the query that originated this one because of following a CNAME (or NULL). */
struct kr_query *cname_parent; struct kr_query *cname_parent;
struct kr_request *request; /**< Parent resolution request. */ struct kr_request *request; /**< Parent resolution request. */
kr_stale_cb stale_cb; /**< See the type */
}; };
/** @cond internal Array of queries. */ /** @cond internal Array of queries. */
......
...@@ -36,6 +36,7 @@ modules_TARGETS += etcd \ ...@@ -36,6 +36,7 @@ modules_TARGETS += etcd \
version \ version \
ta_signal_query \ ta_signal_query \
priming \ priming \
serve_stale \
detect_time_skew \ detect_time_skew \
detect_time_jump detect_time_jump
endif endif
......
.. _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
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
serve_stale_SOURCES := serve_stale.lua
$(call make_lua_module,serve_stale)
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