/* Check cache ABI version */
kr_cache_make_checkpoint(cache);
(void) assert_right_version(cache);
+ /* Create LRU cache for packets */
+ cache->pkt_cache = lru_create_impl(KR_CACHE_DEFAULT_LRU_SIZE, mm, NULL);
+ if (cache->pkt_cache == NULL) {
+ return kr_error(ENOMEM);
+ }
return 0;
}
if (cache_isvalid(cache)) {
cache_op(cache, close);
cache->db = NULL;
+ lru_free_impl(cache->pkt_cache);
+ cache->pkt_cache = NULL;
}
}
const uint8_t lowest_rank = get_lowest_rank(req, qry);
/** 1. find the name or the closest (available) zone, not considering wildcards
- * 1a. exact name+type match (can be negative answer in insecure zones)
+ * 1a. exact name+type match in packet cache (LRU)
+ * 1b. exact name+type match (can be negative answer in insecure zones)
*/
knot_db_val_t key = key_exact_type_maypkt(k, qry->stype);
knot_db_val_t val = { NULL, 0 };
- ret = cache_op(cache, read, &key, &val, 1);
+ ret = find_from_pkt_cache(req, &key, &val, lowest_rank);
+ if (ret != 0) {
+ ret = cache_op(cache, read, &key, &val, 1);
+ }
+
if (!ret) {
/* found an entry: test conditions, materialize into pkt, etc. */
ret = found_exact_hit(ctx, pkt, val, lowest_rank);
#include <libknot/consts.h>
#include <libknot/rrset.h>
#include <sys/time.h>
+
#include "lib/cache/cdb_api.h"
#include "lib/defines.h"
+#include "lib/generic/lru.h"
#include "contrib/ucw/config.h" /*uint*/
/** When knot_pkt is passed from cache without ->wire, this is the ->size. */
/* A pair of stamps for detection of real-time shifts during runtime. */
struct timeval checkpoint_walltime; /**< Wall time on the last check-point. */
uint64_t checkpoint_monotime; /**< Monotonic milliseconds on the last check-point. */
+
+ struct lru *pkt_cache; /**< LRU cache for packets */
};
/**
/* For now we stash the full packet byte-exactly as it came from upstream. */
const uint16_t pkt_size = pkt->size;
- knot_db_val_t val_new_entry = {
- .data = NULL,
- .len = offsetof(struct entry_h, data) + sizeof(pkt_size) + pkt->size,
- };
+ const size_t entry_len = offsetof(struct entry_h, data) + sizeof(pkt_size) + pkt_size;
+
/* Prepare raw memory for the new entry and fill it. */
struct kr_cache *cache = &req->ctx->cache;
- ret = entry_h_splice(&val_new_entry, rank, key, k->type, pkt_type,
- owner, qry, cache, qry->timestamp.tv_sec);
- if (ret) return; /* some aren't really errors */
- assert(val_new_entry.data);
- struct entry_h *eh = val_new_entry.data;
+ if (cache->pkt_cache == NULL) {
+ return;
+ }
+
+ struct entry_h *eh = lru_get_impl(cache->pkt_cache, key.data, (uint)key.len, (uint)entry_len, true, NULL);
+ if (eh == NULL) {
+ return;
+ }
+
+ memset(eh, 0, offsetof(struct entry_h, data));
eh->time = qry->timestamp.tv_sec;
eh->ttl = MAX(MIN(packet_ttl(pkt, is_negative), cache->ttl_max), cache->ttl_min);
eh->rank = rank;
auto_free char *type_str = kr_rrtype_text(pkt_type),
*owner_str = kr_dname_text(owner);
VERBOSE_MSG(qry, "=> stashed packet: rank 0%.2o, TTL %d, "
- "%s %s (%d B)\n",
+ "%s %s (%zu B)\n",
eh->rank, eh->ttl,
- type_str, owner_str, (int)val_new_entry.len);
+ type_str, owner_str, entry_len);
+ }
+}
+
+int find_from_pkt_cache(struct kr_request *req, knot_db_val_t *key, knot_db_val_t *val, uint8_t lowest_rank)
+{
+ struct kr_query *qry = req->current_query;
+ struct kr_cache *cache = &req->ctx->cache;
+ if (cache->pkt_cache == NULL) {
+ return kr_error(EINVAL);
+ }
+
+ /* Only check if key-value exists in LRU, don't insert */
+ struct entry_h *eh = lru_get_impl(cache->pkt_cache, key->data, (uint)key->len, 0, false, NULL);
+ if (eh == NULL) {
+ return kr_error(ENOENT);
+ }
+
+ int32_t new_ttl = get_new_ttl(eh, qry, qry->sname, qry->stype, qry->timestamp.tv_sec);
+ if (new_ttl < 0 || eh->rank < lowest_rank) {
+ return kr_error(ENOENT);
}
+
+ /* Calculate value size */
+ uint16_t pkt_len;
+ memcpy(&pkt_len, eh->data, sizeof(pkt_len));
+
+ val->data = eh;
+ val->len = offsetof(struct entry_h, data) + sizeof(pkt_len) + pkt_len;
+ return kr_ok();
}
int answer_from_pkt(kr_layer_t *ctx, knot_pkt_t *pkt, uint16_t type,
const struct entry_h *eh, const void *eh_bound, uint32_t new_ttl);
+/** Try to find answer from packet cache.
+ */
+int find_from_pkt_cache(struct kr_request *req, knot_db_val_t *key, knot_db_val_t *val, uint8_t lowest_rank);
/** Record is expiring if it has less than 1% TTL (or less than 5s) */
static inline bool is_expiring(uint32_t orig_ttl, uint32_t new_ttl)
#define KR_EDNS_PAYLOAD 4096 /* Default UDP payload (max unfragmented UDP is 1452B) */
#define KR_CACHE_DEFAULT_TTL_MIN (5) /* avoid bursts of queries */
#define KR_CACHE_DEFAULT_TTL_MAX (6 * 24 * 3600) /* 6 days, like the root NS TTL */
+#ifndef KR_CACHE_DEFAULT_LRU_SIZE
+#define KR_CACHE_DEFAULT_LRU_SIZE 65536 /**< LRU packet cache size. */
+#endif
#define KR_DNAME_STR_MAXLEN (KNOT_DNAME_TXT_MAXLEN + 1)
#define KR_RRTYPE_STR_MAXLEN (16 + 1)