return ctx->state;
}
-static int query_cache_append(knot_pkt_t *answer, namedb_txn_t *txn, knot_rrset_t *cache_rr, uint32_t timestamp)
+static int read_cache_append(knot_pkt_t *answer, namedb_txn_t *txn, knot_rrset_t *cache_rr, uint32_t timestamp)
{
unsigned drift = timestamp;
return KNOT_EOK;
}
-static int query_cache_zonecut(struct kr_zonecut *cut, namedb_txn_t *txn, knot_rrset_t *cache_rr, uint32_t timestamp)
+static int read_cache_zonecut(struct kr_zonecut *cut, namedb_txn_t *txn, knot_rrset_t *cache_rr, uint32_t timestamp)
{
/* Query cache for requested record */
if (kr_cache_query(txn, cache_rr, ×tamp) != KNOT_EOK) {
}
}
-static int query_cache(knot_layer_t *ctx, knot_pkt_t *pkt)
+static int read_cache(knot_layer_t *ctx, knot_pkt_t *pkt)
{
assert(pkt && ctx);
struct kr_layer_param *param = ctx->data;
/* Check if updating current zone cut. */
if (cur != kr_rplan_last(param->rplan)) {
- ret = query_cache_zonecut(¶m->rplan->zone_cut, txn, &cache_rr, timestamp);
+ ret = read_cache_zonecut(¶m->rplan->zone_cut, txn, &cache_rr, timestamp);
if (ret == KNOT_EOK) {
kr_rplan_pop(param->rplan, cur);
return KNOT_NS_PROC_DONE;
/* Try to find a CNAME/DNAME chain first. */
cache_rr.type = KNOT_RRTYPE_CNAME;
- ret = query_cache_append(param->answer, txn, &cache_rr, timestamp);
+ ret = read_cache_append(param->answer, txn, &cache_rr, timestamp);
if (ret == KNOT_EOK) {
if (cur->stype != KNOT_RRTYPE_CNAME) {
const knot_dname_t *cname = knot_cname_name(&cache_rr.rrs);
/* Try to find expected record then. */
cache_rr.type = cur->stype;
- ret = query_cache_append(param->answer, txn, &cache_rr, timestamp);
+ ret = read_cache_append(param->answer, txn, &cache_rr, timestamp);
if (ret == KNOT_EOK) {
kr_rplan_pop(param->rplan, cur);
return KNOT_NS_PROC_DONE;
static int merge_in_section(knot_rrset_t *cache_rr, const knot_pktsection_t *section, unsigned from, mm_ctx_t *pool)
{
int ret = KNOT_EOK;
-
for (unsigned i = from; i < section->count; ++i) {
ret = merge_cache_rr(cache_rr, knot_pkt_rr(section, i), pool);
if (ret != KNOT_EOK) {
}
}
+ if (cache_rr->rrs.rr_count == 0) {
+ return KNOT_ENOENT;
+ }
return ret;
}
/*! \brief Cache direct answer. */
-static int update_cache_answer(knot_pkt_t *pkt, namedb_txn_t *txn, mm_ctx_t *pool, uint32_t timestamp)
+static int write_cache_rr(const knot_pktsection_t *section, knot_rrset_t *rr, namedb_txn_t *txn, mm_ctx_t *pool, uint32_t timestamp)
{
- const knot_pktsection_t *an = knot_pkt_section(pkt, KNOT_ANSWER);
- knot_dname_t name_buf[KNOT_DNAME_MAXLEN];
- knot_dname_to_wire(name_buf, knot_pkt_qname(pkt), sizeof(name_buf));
-
- /* Cache only direct answer. */
- knot_rrset_t cache_rr;
- knot_rrset_init(&cache_rr, name_buf, KNOT_RRTYPE_CNAME, knot_pkt_qclass(pkt));
- int ret = merge_in_section(&cache_rr, an, 0, pool);
- if (ret != KNOT_EOK) {
- return ret;
- }
-
/* Cache CNAME chain. */
- while(cache_rr.rrs.rr_count > 0) {
- /* Cache the merged RRSet (may fail) */
- (void) kr_cache_insert(txn, &cache_rr, timestamp);
- /* Follow the chain */
- knot_dname_to_wire(name_buf, knot_ns_name(&cache_rr.rrs, 0), sizeof(name_buf));
- knot_rdataset_clear(&cache_rr.rrs, pool);
- ret = merge_in_section(&cache_rr, an, 0, pool);
+ int ret = KNOT_EOK;
+ uint16_t orig_rrtype = rr->type;
+ rr->type = KNOT_RRTYPE_CNAME;
+ while((merge_in_section(rr, section, 0, pool)) == KNOT_EOK) {
+ /* Cache the merged RRSet */
+ ret = kr_cache_insert(txn, rr, timestamp);
if (ret != KNOT_EOK) {
return ret;
}
+ /* Follow the chain */
+ rr->owner = (knot_dname_t *)knot_ns_name(&rr->rrs, 0);
+ knot_rdataset_clear(&rr->rrs, pool);
+
}
/* Now there may be a terminal record. */
- cache_rr.type = knot_pkt_qtype(pkt);
- knot_rdataset_clear(&cache_rr.rrs, pool);
- ret = merge_in_section(&cache_rr, an, 0, pool);
+ rr->type = orig_rrtype;
+ ret = merge_in_section(rr, section, 0, pool);
if (ret == KNOT_EOK) {
- kr_cache_insert(txn, &cache_rr, timestamp);
+ kr_cache_insert(txn, rr, timestamp);
+ knot_rdataset_clear(&rr->rrs, pool);
}
return ret;
}
-/*! \brief Cache stub nameservers. */
-static int update_cache_authority(knot_pkt_t *pkt, namedb_txn_t *txn, mm_ctx_t *pool, uint32_t timestamp)
+/*! \brief Cache direct answer. */
+static int write_cache_answer(knot_pkt_t *pkt, namedb_txn_t *txn, mm_ctx_t *pool, uint32_t timestamp)
{
- bool found_ns_rr = false;
knot_rrset_t cache_rr;
+ knot_rrset_init(&cache_rr, (knot_dname_t *)knot_pkt_qname(pkt), knot_pkt_qtype(pkt), knot_pkt_qclass(pkt));
- /* Take first NS and merge with rest. */
+ const knot_pktsection_t *an = knot_pkt_section(pkt, KNOT_ANSWER);
+ return write_cache_rr(an, &cache_rr, txn, pool, timestamp);
+}
+
+/*! \brief Cache stub nameservers. */
+static int write_cache_authority(knot_pkt_t *pkt, namedb_txn_t *txn, mm_ctx_t *pool, uint32_t timestamp)
+{
+ knot_rrset_t glue_rr = { NULL, 0, 0 };
+ knot_rrset_t cache_rr = { NULL, 0, 0 };
const knot_pktsection_t *ns = knot_pkt_section(pkt, KNOT_AUTHORITY);
+ const knot_pktsection_t *ar = knot_pkt_section(pkt, KNOT_ADDITIONAL);
+ static const uint16_t type_list[] = { KNOT_RRTYPE_A, KNOT_RRTYPE_AAAA };
+
+ /* Scan for NS records, cache glue. */
for (unsigned i = 0; i < ns->count; ++i) {
const knot_rrset_t *rr = knot_pkt_rr(ns, i);
if (rr->type == KNOT_RRTYPE_NS) {
- knot_rrset_init(&cache_rr, (knot_dname_t *)rr->owner, rr->type, rr->rclass);
- found_ns_rr = true;
- break;
+ /* Cache glue (if contains) */
+ for (unsigned i = 0; i < sizeof(type_list)/sizeof(uint16_t); ++i) {
+ knot_dname_t *owner = (knot_dname_t *)knot_ns_name(&rr->rrs, 0);
+ knot_rrset_init(&glue_rr, owner, type_list[i], rr->rclass);
+ (void) write_cache_rr(ar, &glue_rr, txn, pool, timestamp);
+ }
+ /* Keep first NS */
+ if (cache_rr.owner == NULL) {
+ knot_rrset_init(&cache_rr, (knot_dname_t *)rr->owner, rr->type, rr->rclass);
+ }
}
}
- /* Not found any viable NS */
- if (!found_ns_rr) {
- return KNOT_EOK;
- }
-
- int ret = merge_in_section(&cache_rr, ns, 0, pool);
- if (ret != KNOT_EOK) {
- return ret;
- }
-
- /* Cache the merged RRSet (may fail) */
- return kr_cache_insert(txn, &cache_rr, timestamp);
-}
-
-static void update_cache_pkt(knot_pkt_t *pkt, namedb_txn_t *txn, mm_ctx_t *pool, uint32_t timestamp)
-{
- /* Cache only positive answers. */
- if (knot_wire_get_rcode(pkt->wire) != KNOT_RCODE_NOERROR) {
- return;
- }
-
- /* If authoritative, cache answer for current query. */
- int ret = KNOT_EOK;
- if (knot_wire_get_aa(pkt->wire)) {
- ret = update_cache_answer(pkt, txn, pool, timestamp);
- } else {
- /* Cache authority records, but not glue. */
- ret = update_cache_authority(pkt, txn, pool, timestamp);
+ /* Merge and cache NS record. */
+ if (cache_rr.owner == NULL) {
+ return KNOT_ENOENT;
}
- /* Cache full, do what we must. */
- if (ret == KNOT_ESPACE) {
- kr_cache_clear(txn);
- }
+ return write_cache_rr(ns, &cache_rr, txn, pool, timestamp);
}
-static int update_cache(knot_layer_t *ctx, knot_pkt_t *pkt)
+static int write_cache(knot_layer_t *ctx, knot_pkt_t *pkt)
{
struct kr_layer_param *param = ctx->data;
struct kr_query *last_query = kr_rplan_last(param->rplan);
}
/* Open write transaction */
+ mm_ctx_t *pool = param->rplan->pool;
uint32_t timestamp = last_query->timestamp.tv_sec;
namedb_txn_t *txn = kr_rplan_txn_acquire(param->rplan, 0);
if (txn == NULL) {
return ctx->state; /* Couldn't acquire cache, ignore. */
}
- /* Selectively cache records from the packet. */
- update_cache_pkt(pkt, txn, param->rplan->pool, timestamp);
+ /* Cache only positive answers. */
+ /*! \todo Negative answers cache support */
+ if (knot_wire_get_rcode(pkt->wire) != KNOT_RCODE_NOERROR) {
+ return ctx->state;
+ }
+
+ /* If authoritative, cache answer for current query. */
+ int ret = KNOT_EOK;
+ if (knot_wire_get_aa(pkt->wire)) {
+ ret = write_cache_answer(pkt, txn, pool, timestamp);
+ } else {
+ ret = write_cache_authority(pkt, txn, pool, timestamp);
+ }
+
+ /* Cache full, do what we must. */
+ if (ret == KNOT_ESPACE) {
+ kr_cache_clear(txn);
+ }
return ctx->state;
}
&begin,
NULL,
NULL,
- &update_cache,
- &query_cache,
+ &write_cache,
+ &read_cache,
NULL
};