Commit f910a5c6 authored by Marek Vavruša's avatar Marek Vavruša

lib: delegation point map basic implementation

parent 86da3b4c
......@@ -15,5 +15,5 @@ lib/resolve.c
lib/resolve.h
tests/context.c
tests/resolve.c
lib/nslist.h
lib/nslist.c
lib/delegpt.h
lib/delegpt.c
......@@ -12,5 +12,5 @@ libknotresolve_la_SOURCES = \
context.c \
resolve.h \
resolve.c \
nslist.c \
nslist.h
delegpt.c \
delegpt.h
......@@ -9,22 +9,19 @@ int kr_context_init(struct kr_context *ctx, mm_ctx_t *mm)
memset(ctx, 0, sizeof(struct kr_context));
ctx->pool = mm;
kr_slist_init(ctx);
kr_delegmap_init(&ctx->dp_map, mm);
return 0;
}
int kr_context_reset(struct kr_context *ctx)
{
kr_slist_clear(ctx);
kr_slist_init(ctx);
return 0;
}
int kr_context_deinit(struct kr_context *ctx)
{
kr_slist_clear(ctx);
kr_delegmap_deinit(&ctx->dp_map);
return -1;
}
......
......@@ -21,7 +21,7 @@ limitations under the License.
#warning TODO: this is private define
#include <common/sockaddr.h>
#include "lib/nslist.h"
#include "lib/delegpt.h"
/*! \brief Name resolution result. */
struct kr_result {
......@@ -39,7 +39,7 @@ struct kr_context
const knot_dname_t *sname;
uint16_t stype;
uint16_t sclass;
list_t slist;
struct kr_delegmap dp_map;
mm_ctx_t *pool;
unsigned state;
unsigned options;
......
#include "lib/delegpt.h"
#include <common/mempool.h>
static void delegpt_free(struct kr_delegpt *dp, mm_ctx_t *mm)
{
mm_free(mm, dp->name);
mm_free(mm, dp);
}
static void delegmap_clear(struct kr_delegmap *map)
{
hattrie_iter_t *i = hattrie_iter_begin(map->trie, false);
while(!hattrie_iter_finished(i)) {
delegpt_free(*hattrie_iter_val(i), map->pool);
hattrie_iter_next(i);
}
hattrie_iter_free(i);
hattrie_clear(map->trie);
}
int kr_delegmap_init(struct kr_delegmap *map, mm_ctx_t *mm)
{
map->pool = mm;
map->trie = hattrie_create_n(TRIE_BUCKET_SIZE, mm);
if (map->trie == NULL) {
return -1;
}
return 0;
}
void kr_delegmap_deinit(struct kr_delegmap *map)
{
delegmap_clear(map);
hattrie_free(map->trie);
}
list_t *kr_delegmap_get(struct kr_delegmap *map, const knot_dname_t *name)
{
value_t *val = hattrie_get(map->trie, (const char *)name, knot_dname_size(name));
if (*val == NULL) {
*val = mm_alloc(map->pool, sizeof(list_t));
if (*val == NULL) {
return NULL;
}
init_list((list_t *)*val);
}
return *val;
}
list_t *kr_delegmap_find(struct kr_delegmap *map, const knot_dname_t *name)
{
value_t *val = NULL;
while(val == NULL) {
val = hattrie_tryget(map->trie, (const char *)name, knot_dname_size(name));
if (val == NULL || EMPTY_LIST(*((list_t *)*val))) {
/* No root delegation, failure. */
if (*name == '\0') {
assert(0);
return NULL;
}
/* Look up parent. */
name = knot_wire_next_label(name, NULL);
val = NULL;
}
}
return *val;
}
struct kr_delegpt *kr_delegpt_create(const knot_dname_t *name, mm_ctx_t *mm)
{
struct kr_delegpt *dp = mm_alloc(mm, sizeof(struct kr_delegpt));
memset(dp, 0, sizeof(struct kr_delegpt));
dp->name = knot_dname_copy(name, mm);
dp->flags = DP_LAME;
return dp;
}
void kr_delegpt_add(list_t *list, struct kr_delegpt *dp)
{
add_tail(list, (node_t *)dp);
}
void kr_delegpt_remove(struct kr_delegpt *dp, mm_ctx_t *mm)
{
rem_node((node_t *)dp);
delegpt_free(dp, mm);
}
......@@ -20,21 +20,42 @@ limitations under the License.
#warning TODO: this is private define
#include <common/lists.h>
#include <common/sockaddr.h>
#include <common/trie/hat-trie.h>
/*! \brief Delegation point flag. */
enum kr_deleg_flag {
DP_LAME = 0,
DP_RESOLVED
};
struct kr_context;
/*! \brief Name server information. */
struct kr_ns {
/*! \brief Delegation point. */
struct kr_delegpt {
node_t node;
knot_dname_t *name;
struct sockaddr_storage addr;
unsigned valid_until;
unsigned mean_rtt;
unsigned closeness;
unsigned flags;
};
struct kr_delegmap {
mm_ctx_t *pool;
hattrie_t *trie;
};
int kr_slist_init(struct kr_context *ctx);
int kr_slist_clear(struct kr_context *ctx);
int kr_slist_add(struct kr_context *ctx, const knot_dname_t *name, const struct sockaddr *addr);
struct kr_ns *kr_slist_top(struct kr_context *ctx);
int kr_slist_sort(struct kr_context *ctx);
int kr_slist_pop(struct kr_context *ctx);
\ No newline at end of file
int kr_delegmap_init(struct kr_delegmap *map, mm_ctx_t *mm);
void kr_delegmap_deinit(struct kr_delegmap *map);
list_t *kr_delegmap_get(struct kr_delegmap *map, const knot_dname_t *name);
list_t *kr_delegmap_find(struct kr_delegmap *map, const knot_dname_t *name);
/* TODO: find out how to do expire/refresh efficiently, maybe a sweep point and
* evaluate only DPs with validity before or around the sweep point, then
* choose next and move DPs from the other half for next sweep.
*/
struct kr_delegpt *kr_delegpt_create(const knot_dname_t *name, mm_ctx_t *mm);
void kr_delegpt_add(list_t *list, struct kr_delegpt *dp);
void kr_delegpt_remove(struct kr_delegpt *dp, mm_ctx_t *mm);
int kr_delegpt_resolve(struct kr_delegpt *dp);
......@@ -60,17 +60,28 @@ static int evaluate_dp(const knot_rrset_t *dp, knot_pkt_t *pkt, struct kr_layer_
{
struct kr_context *resolve = param->ctx;
/* Check if there's a glue for the record. */
struct sockaddr_storage ss;
/* Fetch delegation point. */
list_t *dplist = kr_delegmap_get(&resolve->dp_map, dp->owner);
if (dplist == NULL) {
return -1;
}
const knot_dname_t *dp_name = knot_ns_name(&dp->rrs, 0);
int ret = glue_record(pkt, dp_name, (struct sockaddr *)&ss);
struct kr_delegpt *ns_new = kr_delegpt_create(dp_name, resolve->dp_map.pool);
/* Check if there's a glue for the record. */
int ret = glue_record(pkt, dp_name, (struct sockaddr *)&ns_new->addr);
if (ret != 0) {
/* TODO: lookup delegation if not provided in additionals */
/* TODO: API for duplicates? */
ns_new->flags |= DP_LAME;
/* TODO: resolve. */
kr_delegpt_add(dplist, ns_new);
return -1;
}
/* Add delegation to the SLIST. */
kr_slist_add(resolve, dp->owner, (struct sockaddr *)&ss);
/* Add name server. */
ns_new->flags |= DP_RESOLVED;
kr_delegpt_add(dplist, ns_new);
return 0;
}
......
......@@ -14,6 +14,7 @@ limitations under the License.
*/
#include "lib/layer/static.h"
#include "lib/delegpt.h"
/* \brief Root hint descriptor. */
struct hint_info {
......@@ -42,7 +43,7 @@ static const struct hint_info SBELT[HINT_COUNT] = {
static int reset(knot_layer_t *ctx)
{
printf("loading sbelt\n");
/* TODO: sync cache, cleanup */
return ctx->state;
}
......@@ -54,11 +55,19 @@ static int begin(knot_layer_t *ctx, void *param)
struct kr_context *resolve = ((struct kr_layer_param *)param)->ctx;
assert(resolve);
list_t *dp = kr_delegmap_get(&resolve->dp_map, U8(""));
if (dp == NULL) {
return ctx->state;
}
/* Initialize static root hints. */
struct sockaddr_storage ss;
for (unsigned i = 0; i < HINT_COUNT; ++i) {
sockaddr_set(&ss, AF_INET, SBELT[i].addr, 53);
kr_slist_add(resolve, U8(""), (struct sockaddr *)&ss);
struct kr_delegpt *ns = kr_delegpt_create(SBELT[i].name, resolve->dp_map.pool);
if (ns != NULL) {
sockaddr_set(&ns->addr, AF_INET, SBELT[i].addr, 53);
ns->flags |= DP_RESOLVED;
kr_delegpt_add(dp, ns);
}
}
return ctx->state;
......
#include "lib/nslist.h"
#include "lib/context.h"
/* TODO: debug, remove */
#ifndef NDEBUG
static void print_slist(struct kr_context *ctx)
{
char *sname = knot_dname_to_str(ctx->sname);
printf("SLIST(%s): \n", sname);
free(sname);
struct kr_ns *ns = NULL;
WALK_LIST(ns, ctx->slist) {
char *strname = knot_dname_to_str(ns->name);
char addr_str[SOCKADDR_STRLEN];
sockaddr_tostr(&ns->addr, addr_str, sizeof(addr_str));
printf("[%d] %s:%s ", ns->closeness, strname, addr_str);
free(strname);
}
printf("\n");
}
#endif
/*! \brief Initialize NS descriptor. */
static struct kr_ns *init_ns(mm_ctx_t *mm, const knot_dname_t *name,
const struct sockaddr *addr)
{
struct kr_ns *ns = mm_alloc(mm, sizeof(struct kr_ns));
if (ns == NULL) {
return NULL;
}
memset(ns, 0, sizeof(struct kr_ns));
ns->name = knot_dname_copy(name, mm);
if (ns->name == NULL) {
mm_free(mm, ns);
return NULL;
}
memcpy(&ns->addr, addr, sockaddr_len(addr));
return ns;
}
/*! \brief Insert before an item. */
static void insert_before(struct kr_ns *cur, struct kr_ns *inserted)
{
insert_node((node_t *)inserted, (node_t *)cur);
rem_node((node_t *)cur);
insert_node((node_t *)cur, (node_t *)inserted);
}
/*! \brief Calculate closeness (# of common labels with sname). */
static unsigned closeness_score(const knot_dname_t *sname, const knot_dname_t *zone)
{
/* Longer or non-equal names of the same length can't contain delegations. */
if (sname && (knot_dname_is_sub(sname, zone) || knot_dname_is_equal(zone, sname))) {
return KNOT_DNAME_MAXLABELS - knot_dname_matched_labels(zone, sname);
}
return KNOT_DNAME_MAXLABELS + 1; /* N/A */
}
/* \brief (Re)insert name server to SLIST. */
static void insert_ns(struct kr_context *ctx, struct kr_ns *ns)
{
struct kr_ns *it = NULL;
WALK_LIST(it, ctx->slist) {
if (it->closeness > ns->closeness) {
insert_before(it, ns);
return;
}
}
/* No closer match found. */
add_tail(&ctx->slist, (node_t *)ns);
}
/*! \brief Remove NS descriptor. */
static void remove_ns(mm_ctx_t *mm, struct kr_ns *ns)
{
rem_node((node_t *)ns);
mm_free(mm, ns->name);
mm_free(mm, ns);
}
int kr_slist_init(struct kr_context *ctx)
{
init_list(&ctx->slist);
return 0;
}
int kr_slist_clear(struct kr_context *ctx)
{
while(kr_slist_pop(ctx) == 0)
;
return 0;
}
int kr_slist_add(struct kr_context *ctx, const knot_dname_t *name, const struct sockaddr *addr)
{
struct kr_ns *ns = init_ns(ctx->pool, name, addr);
if (ns == NULL) {
return -1;
}
insert_ns(ctx, ns);
return 0;
}
struct kr_ns *kr_slist_top(struct kr_context *ctx)
{
if (EMPTY_LIST(ctx->slist)) {
return NULL;
}
return (struct kr_ns *)HEAD(ctx->slist);
}
int kr_slist_sort(struct kr_context *ctx)
{
list_t copy = ctx->slist;
init_list(&ctx->slist);
/* Recalculate closeness and reinsert. */
struct kr_ns *it = NULL, *next = NULL;
WALK_LIST_DELSAFE(it, next, copy) {
it->closeness = closeness_score(ctx->sname, it->name);
insert_ns(ctx, it);
}
return 0;
}
int kr_slist_pop(struct kr_context *ctx)
{
struct kr_ns *top = kr_slist_top(ctx);
if (top == NULL) {
return -1;
}
remove_ns(ctx->pool, top);
return 0;
}
\ No newline at end of file
......@@ -10,9 +10,9 @@
#include <libknot/rrset-dump.h>
#include <common/print.h>
#ifndef NDEBUG
static void print_result(struct kr_result *result)
{
#ifndef NDEBUG
char *qnamestr = knot_dname_to_str(knot_pkt_qname(result->ans));
char *cnamestr = knot_dname_to_str(result->cname);
printf("resolution of %s -> %s\n", qnamestr, cnamestr);
......@@ -30,52 +30,44 @@ static void print_result(struct kr_result *result)
printf("%s", strbuf);
printf("queries: %u\n", result->nr_queries);
printf("rtt %.02f msecs\n", time_diff(&result->t_start, &result->t_end));
}
#define print_step(s...) \
do { \
char *_qstr = knot_dname_to_str(ctx->sname); \
char _astr[SOCKADDR_STRLEN]; \
sockaddr_tostr(&kr_slist_top(ctx)->addr, _astr, sizeof(_astr)); \
char *_soastr = knot_dname_to_str(kr_slist_top(ctx)->name); \
printf("[%s] at %s (soa %s) ", _qstr, _astr, _soastr); \
printf(s); \
printf("\n"); \
free(_qstr); \
free(_soastr); \
} while(0)
#else
static void print_result(struct kr_result *result) {}
#define print_step
#endif
}
static void iterate(struct knot_requestor *requestor, struct kr_context* ctx)
{
struct timeval timeout = { 5, 0 };
/* Sort preference list to the SNAME and pick a NS. */
kr_slist_sort(ctx);
struct kr_ns *ns = kr_slist_top(ctx);
if (ns == NULL) {
/* Find closest delegation point. */
list_t *dp = kr_delegmap_find(&ctx->dp_map, ctx->sname);
if (dp == NULL) {
ctx->state = NS_PROC_FAIL;
return;
}
print_step("iterating");
struct kr_delegpt *ns = NULL;
WALK_LIST(ns, *dp) {
if (ns->flags & DP_RESOLVED) {
break;
}
/* TODO: validity */
}
assert(ns->flags & DP_RESOLVED);
/* Build query. */
knot_pkt_t *query = knot_pkt_new(NULL, KNOT_WIRE_MAX_PKTSIZE, requestor->mm);
/* Resolve. */
struct knot_request *tx = knot_request_make(requestor->mm,
(const struct sockaddr *)&ns->addr,
(struct sockaddr *)&ns->addr,
NULL, query, 0);
knot_requestor_enqueue(requestor, tx);
int ret = knot_requestor_exec(requestor, &timeout);
/* TODO: soft remove, retry later */
if (ret != 0) {
print_step("server failure %d", ret);
kr_slist_pop(ctx);
/* Move to the tail, and disable. */
rem_node((node_t *)ns);
add_tail(dp, (node_t *)ns);
ns->flags = DP_LAME;
}
}
......@@ -103,13 +95,11 @@ int kr_resolve(struct kr_context* ctx, struct kr_result* result,
knot_requestor_init(&requestor, ctx->pool);
knot_requestor_overlay(&requestor, LAYER_STATIC, &param);
knot_requestor_overlay(&requestor, LAYER_ITERATE, &param);
while(ctx->state != NS_PROC_DONE) {
while(ctx->state & (NS_PROC_MORE|NS_PROC_FULL)) {
iterate(&requestor, ctx);
}
/* Clean up. */
knot_requestor_clear(&requestor);
print_result(result);
......
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