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 {
_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();
......
......@@ -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
......
......@@ -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
......@@ -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) {
......
......@@ -27,6 +27,11 @@
#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;
......
......@@ -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. */
......
......@@ -36,6 +36,7 @@ modules_TARGETS += etcd \
version \
ta_signal_query \
priming \
serve_stale \
detect_time_skew \
detect_time_jump
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