Skip to content
Snippets Groups Projects
Commit 30eb8bd5 authored by Vladimír Čunát's avatar Vladimír Čunát
Browse files

Merge branch 'p/reorder' into 'master'

add option to reorder cached RRs in answers

Fixes https://gitlab.labs.nic.cz/knot/resolver/issues/93.
API of a KR_EXPORT function is changed, so ABIVER is bumped.

See merge request !47
parents 162e1821 aa880bca
No related branches found
No related tags found
1 merge request!47add option to reorder cached RRs in answers
Knot Resolver 1.x.y (2016-xx-yy)
================================
- It now requires knot >= 2.3.1 to link successfully.
Knot Resolver 1.1.1 (2016-08-24) Knot Resolver 1.1.1 (2016-08-24)
================================ ================================
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
MAJOR := 1 MAJOR := 1
MINOR := 1 MINOR := 1
PATCH := 1 PATCH := 1
ABIVER := 1 ABIVER := 2
BUILDMODE := dynamic BUILDMODE := dynamic
HARDENING := yes HARDENING := yes
......
...@@ -394,6 +394,14 @@ Environment ...@@ -394,6 +394,14 @@ Environment
"Use in-bailiwick glue", "normal, permissive" "Use in-bailiwick glue", "normal, permissive"
"Use any glue records", "permissive" "Use any glue records", "permissive"
.. function:: reorder_RR([true | false])
:param boolean value: New value for the option *(optional)*
:return: The (new) value of the option
If set, resolver will vary the order of resource records within RR-sets
every time when answered from cache. It is disabled by default.
.. function:: user(name, [group]) .. function:: user(name, [group])
:param string name: user name :param string name: user name
......
...@@ -66,6 +66,7 @@ static int l_help(lua_State *L) ...@@ -66,6 +66,7 @@ static int l_help(lua_State *L)
"verbose(true|false)\n toggle verbose mode\n" "verbose(true|false)\n toggle verbose mode\n"
"option(opt[, new_val])\n get/set server option\n" "option(opt[, new_val])\n get/set server option\n"
"mode(strict|normal|permissive)\n set resolver strictness level\n" "mode(strict|normal|permissive)\n set resolver strictness level\n"
"reorder_RR([true|false])\n set/get reordering of RRs within RRsets\n"
"resolve(name, type[, class, flags, callback])\n resolve query, callback when it's finished\n" "resolve(name, type[, class, flags, callback])\n resolve query, callback when it's finished\n"
"todname(name)\n convert name to wire format\n" "todname(name)\n convert name to wire format\n"
"tojson(val)\n convert value to JSON\n" "tojson(val)\n convert value to JSON\n"
......
...@@ -49,6 +49,11 @@ function mode(m) ...@@ -49,6 +49,11 @@ function mode(m)
return true return true
end end
-- Trivial option alias
function reorder_RR(val)
return option('REORDER_RR', val)
end
-- Function aliases -- Function aliases
-- `env.VAR returns os.getenv(VAR)` -- `env.VAR returns os.getenv(VAR)`
env = {} env = {}
......
...@@ -326,7 +326,8 @@ int kr_cache_peek_rank(struct kr_cache *cache, uint8_t tag, const knot_dname_t * ...@@ -326,7 +326,8 @@ int kr_cache_peek_rank(struct kr_cache *cache, uint8_t tag, const knot_dname_t *
return found->rank; return found->rank;
} }
int kr_cache_materialize(knot_rrset_t *dst, const knot_rrset_t *src, uint32_t drift, knot_mm_t *mm) int kr_cache_materialize(knot_rrset_t *dst, const knot_rrset_t *src, uint32_t drift,
uint reorder, knot_mm_t *mm)
{ {
if (!dst || !src || dst == src) { if (!dst || !src || dst == src) {
return kr_error(EINVAL); return kr_error(EINVAL);
...@@ -339,17 +340,36 @@ int kr_cache_materialize(knot_rrset_t *dst, const knot_rrset_t *src, uint32_t dr ...@@ -339,17 +340,36 @@ int kr_cache_materialize(knot_rrset_t *dst, const knot_rrset_t *src, uint32_t dr
return kr_error(ENOMEM); return kr_error(ENOMEM);
} }
/* Copy valid records */ /* Find valid records */
knot_rdata_t **valid = malloc(sizeof(knot_rdata_t *) * src->rrs.rr_count);
uint16_t valid_count = 0;
knot_rdata_t *rd = src->rrs.data; knot_rdata_t *rd = src->rrs.data;
for (uint16_t i = 0; i < src->rrs.rr_count; ++i) { for (uint16_t i = 0; i < src->rrs.rr_count; ++i) {
if (knot_rdata_ttl(rd) >= drift) { if (knot_rdata_ttl(rd) >= drift) {
if (knot_rdataset_add(&dst->rrs, rd, mm) != 0) { valid[valid_count++] = rd;
knot_rrset_clear(dst, mm);
return kr_error(ENOMEM);
}
} }
rd = kr_rdataset_next(rd); rd = kr_rdataset_next(rd);
} }
if (reorder && valid_count > 1) {
/* Reorder the valid part; it's a reversed rotation,
* done by two array reversals. */
uint16_t shift = reorder % valid_count;
for (uint16_t i = 0; i < shift / 2; ++i) {
SWAP(valid[i], valid[shift - 1 - i]);
}
for (uint16_t i = 0; i < (valid_count - shift) / 2; ++i) {
SWAP(valid[shift + i], valid[valid_count - 1 - i]);
}
}
int err = knot_rdataset_gather(&dst->rrs, valid, valid_count, mm);
free(valid);
if (err) {
knot_rrset_clear(dst, mm);
return kr_error(err);
}
/* Fixup TTL by time passed */ /* Fixup TTL by time passed */
rd = dst->rrs.data; rd = dst->rrs.data;
for (uint16_t i = 0; i < dst->rrs.rr_count; ++i) { for (uint16_t i = 0; i < dst->rrs.rr_count; ++i) {
......
...@@ -207,11 +207,13 @@ int kr_cache_peek_rr(struct kr_cache *cache, knot_rrset_t *rr, uint8_t *rank, ui ...@@ -207,11 +207,13 @@ int kr_cache_peek_rr(struct kr_cache *cache, knot_rrset_t *rr, uint8_t *rank, ui
* @param dst destination for materialized RRSet * @param dst destination for materialized RRSet
* @param src read-only RRSet (its rdataset may be changed depending on the result) * @param src read-only RRSet (its rdataset may be changed depending on the result)
* @param drift time passed between cache time and now * @param drift time passed between cache time and now
* @param reorder (pseudo)-random seed to reorder the data or zero
* @param mm memory context * @param mm memory context
* @return 0 or an errcode * @return 0 or an errcode
*/ */
KR_EXPORT KR_EXPORT
int kr_cache_materialize(knot_rrset_t *dst, const knot_rrset_t *src, uint32_t drift, knot_mm_t *mm); int kr_cache_materialize(knot_rrset_t *dst, const knot_rrset_t *src, uint32_t drift,
uint reorder, knot_mm_t *mm);
/** /**
* Insert RRSet into cache, replacing any existing data. * Insert RRSet into cache, replacing any existing data.
......
...@@ -78,7 +78,7 @@ static int loot_rr(struct kr_cache *cache, knot_pkt_t *pkt, const knot_dname_t * ...@@ -78,7 +78,7 @@ static int loot_rr(struct kr_cache *cache, knot_pkt_t *pkt, const knot_dname_t *
/* Update packet answer */ /* Update packet answer */
knot_rrset_t rr_copy; knot_rrset_t rr_copy;
ret = kr_cache_materialize(&rr_copy, &cache_rr, drift, &pkt->mm); ret = kr_cache_materialize(&rr_copy, &cache_rr, drift, qry->reorder, &pkt->mm);
if (ret == 0) { if (ret == 0) {
ret = knot_pkt_put(pkt, KNOT_COMPR_HINT_QNAME, &rr_copy, KNOT_PF_FREE); ret = knot_pkt_put(pkt, KNOT_COMPR_HINT_QNAME, &rr_copy, KNOT_PF_FREE);
if (ret != 0) { if (ret != 0) {
......
...@@ -132,6 +132,9 @@ static struct kr_query *kr_rplan_push_query(struct kr_rplan *rplan, ...@@ -132,6 +132,9 @@ static struct kr_query *kr_rplan_push_query(struct kr_rplan *rplan,
qry->ns.addr[0].ip.sa_family = AF_UNSPEC; qry->ns.addr[0].ip.sa_family = AF_UNSPEC;
gettimeofday(&qry->timestamp, NULL); gettimeofday(&qry->timestamp, NULL);
kr_zonecut_init(&qry->zone_cut, (const uint8_t *)"", rplan->pool); kr_zonecut_init(&qry->zone_cut, (const uint8_t *)"", rplan->pool);
qry->reorder = qry->flags & QUERY_REORDER_RR
? knot_wire_get_id(rplan->request->answer->wire)
: 0;
array_push(rplan->pending, qry); array_push(rplan->pending, qry);
return qry; return qry;
......
...@@ -48,7 +48,8 @@ ...@@ -48,7 +48,8 @@
X(PERMISSIVE, 1 << 20) /**< Permissive resolver mode. */ \ X(PERMISSIVE, 1 << 20) /**< Permissive resolver mode. */ \
X(STRICT, 1 << 21) /**< Strict resolver mode. */ \ X(STRICT, 1 << 21) /**< Strict resolver mode. */ \
X(BADCOOKIE_AGAIN, 1 << 22) /**< Query again because bad cookie returned. */ \ X(BADCOOKIE_AGAIN, 1 << 22) /**< Query again because bad cookie returned. */ \
X(CNAME, 1 << 23) /**< Query response contains CNAME in answer section. */ X(CNAME, 1 << 23) /**< Query response contains CNAME in answer section. */ \
X(REORDER_RR, 1 << 24) /**< Reorder cached RRs. */
/** Query flags */ /** Query flags */
enum kr_query_flag { enum kr_query_flag {
...@@ -73,6 +74,7 @@ struct kr_query { ...@@ -73,6 +74,7 @@ struct kr_query {
uint32_t flags; uint32_t flags;
uint32_t secret; uint32_t secret;
uint16_t fails; uint16_t fails;
uint16_t reorder; /**< Seed to reorder (cached) RRs in answer or zero. */
struct timeval timestamp; struct timeval timestamp;
struct kr_zonecut zone_cut; struct kr_zonecut zone_cut;
struct kr_nsrep ns; struct kr_nsrep ns;
......
...@@ -166,3 +166,12 @@ int kr_rrarray_add(rr_array_t *array, const knot_rrset_t *rr, knot_mm_t *pool); ...@@ -166,3 +166,12 @@ int kr_rrarray_add(rr_array_t *array, const knot_rrset_t *rr, knot_mm_t *pool);
*/ */
KR_EXPORT KR_EXPORT
char *kr_module_call(struct kr_context *ctx, const char *module, const char *prop, const char *input); char *kr_module_call(struct kr_context *ctx, const char *module, const char *prop, const char *input);
/** Swap two places. Note: the parameters need to be without side effects. */
#define SWAP(x, y) do { /* http://stackoverflow.com/a/3982430/587396 */ \
unsigned char swap_temp[sizeof(x) == sizeof(y) ? (ssize_t)sizeof(x) : -1]; \
memcpy(swap_temp, &y, sizeof(x)); \
memcpy(&y, &x, sizeof(x)); \
memcpy(&x, swap_temp, sizeof(x)); \
} while(0)
...@@ -330,7 +330,7 @@ static int fetch_ns(struct kr_context *ctx, struct kr_zonecut *cut, const knot_d ...@@ -330,7 +330,7 @@ static int fetch_ns(struct kr_context *ctx, struct kr_zonecut *cut, const knot_d
/* Materialize as we'll going to do more cache lookups. */ /* Materialize as we'll going to do more cache lookups. */
knot_rrset_t rr_copy; knot_rrset_t rr_copy;
ret = kr_cache_materialize(&rr_copy, &cached_rr, drift, cut->pool); ret = kr_cache_materialize(&rr_copy, &cached_rr, drift, 0, cut->pool);
if (ret != 0) { if (ret != 0) {
return ret; return ret;
} }
...@@ -380,7 +380,7 @@ static int fetch_rrset(knot_rrset_t **rr, struct kr_cache *cache, ...@@ -380,7 +380,7 @@ static int fetch_rrset(knot_rrset_t **rr, struct kr_cache *cache,
return kr_error(ENOMEM); return kr_error(ENOMEM);
} }
ret = kr_cache_materialize(*rr, &cached_rr, drift, pool); ret = kr_cache_materialize(*rr, &cached_rr, drift, 0, pool);
if (ret != 0) { if (ret != 0) {
knot_rrset_free(rr, pool); knot_rrset_free(rr, pool);
return ret; return ret;
......
...@@ -39,17 +39,19 @@ knot_db_val_t global_namedb_data = {namedb_data, NAMEDB_DATA_SIZE}; ...@@ -39,17 +39,19 @@ knot_db_val_t global_namedb_data = {namedb_data, NAMEDB_DATA_SIZE};
#define CACHE_TTL 10 #define CACHE_TTL 10
#define CACHE_TIME 0 #define CACHE_TIME 0
int (*original_knot_rdataset_add)(knot_rdataset_t *rrs, const knot_rdata_t *rr, knot_mm_t *mm) = NULL; int (*original_knot_rdataset_gather)(knot_rdataset_t *dst, knot_rdata_t **src,
uint16_t count, knot_mm_t *mm) = NULL;
int knot_rdataset_add(knot_rdataset_t *rrs, const knot_rdata_t *rr, knot_mm_t *mm) int knot_rdataset_gather(knot_rdataset_t *dst, knot_rdata_t **src, uint16_t count,
knot_mm_t *mm)
{ {
int err, err_mock; int err, err_mock;
err_mock = (int)mock(); err_mock = (int)mock();
if (original_knot_rdataset_add == NULL) { if (original_knot_rdataset_gather == NULL) {
original_knot_rdataset_add = dlsym(RTLD_NEXT,"knot_rdataset_add"); original_knot_rdataset_gather = dlsym(RTLD_NEXT,"knot_rdataset_gather");
assert_non_null (original_knot_rdataset_add); assert_non_null (original_knot_rdataset_gather);
} }
err = original_knot_rdataset_add(rrs, rr, mm); err = original_knot_rdataset_gather(dst, src, count, mm);
if (err_mock != 0) if (err_mock != 0)
err = err_mock; err = err_mock;
return err; return err;
...@@ -235,7 +237,7 @@ static void test_materialize(void **state) ...@@ -235,7 +237,7 @@ static void test_materialize(void **state)
global_rr.owner = NULL; global_rr.owner = NULL;
knot_rrset_init(&output_rr, NULL, 0, 0); knot_rrset_init(&output_rr, NULL, 0, 0);
kr_cache_materialize(&output_rr, &global_rr, 0, &global_mm); kr_cache_materialize(&output_rr, &global_rr, 0, 0, &global_mm);
res_cmp_ok_empty = knot_rrset_equal(&global_rr, &output_rr, KNOT_RRSET_COMPARE_HEADER); res_cmp_ok_empty = knot_rrset_equal(&global_rr, &output_rr, KNOT_RRSET_COMPARE_HEADER);
res_cmp_fail_empty = knot_rrset_equal(&global_rr, &output_rr, KNOT_RRSET_COMPARE_WHOLE); res_cmp_fail_empty = knot_rrset_equal(&global_rr, &output_rr, KNOT_RRSET_COMPARE_WHOLE);
knot_rrset_clear(&output_rr, &global_mm); knot_rrset_clear(&output_rr, &global_mm);
...@@ -244,15 +246,15 @@ static void test_materialize(void **state) ...@@ -244,15 +246,15 @@ static void test_materialize(void **state)
assert_false(res_cmp_fail_empty); assert_false(res_cmp_fail_empty);
knot_rrset_init(&output_rr, NULL, 0, 0); knot_rrset_init(&output_rr, NULL, 0, 0);
will_return (knot_rdataset_add, 0); will_return (knot_rdataset_gather, 0);
kr_cache_materialize(&output_rr, &global_rr, 0, &global_mm); kr_cache_materialize(&output_rr, &global_rr, 0, 0, &global_mm);
res_cmp_ok = knot_rrset_equal(&global_rr, &output_rr, KNOT_RRSET_COMPARE_WHOLE); res_cmp_ok = knot_rrset_equal(&global_rr, &output_rr, KNOT_RRSET_COMPARE_WHOLE);
knot_rrset_clear(&output_rr, &global_mm); knot_rrset_clear(&output_rr, &global_mm);
assert_true(res_cmp_ok); assert_true(res_cmp_ok);
knot_rrset_init(&output_rr, NULL, 0, 0); knot_rrset_init(&output_rr, NULL, 0, 0);
will_return (knot_rdataset_add, KNOT_EINVAL); will_return (knot_rdataset_gather, KNOT_ENOMEM);
kr_cache_materialize(&output_rr, &global_rr, 0, &global_mm); kr_cache_materialize(&output_rr, &global_rr, 0, 0, &global_mm);
res_cmp_fail = knot_rrset_equal(&global_rr, &output_rr, KNOT_RRSET_COMPARE_WHOLE); res_cmp_fail = knot_rrset_equal(&global_rr, &output_rr, KNOT_RRSET_COMPARE_WHOLE);
knot_rrset_clear(&output_rr, &global_mm); knot_rrset_clear(&output_rr, &global_mm);
assert_false(res_cmp_fail); assert_false(res_cmp_fail);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment