]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
lib/nsrep: NS reputation cache in addition to RTT cache
authorMarek Vavruša <marek.vavrusa@nic.cz>
Sat, 6 Jun 2015 19:03:26 +0000 (21:03 +0200)
committerMarek Vavruša <marek.vavrusa@nic.cz>
Sat, 6 Jun 2015 20:02:20 +0000 (22:02 +0200)
this LRU-like cache tracks lame nameservers, unresolvable
nameservers (to not waste resources in trying to resolve them),
and possibly other features (extension support, …)

daemon/engine.c
daemon/engine.h
daemon/main.c
lib/nsrep.c
lib/nsrep.h
lib/resolve.c
lib/resolve.h
lib/zonecut.c
lib/zonecut.h
tests/test_integration.c
tests/test_zonecut.c

index e0d3742b6a485689354824d7cdc917857bc94942..22203a027eed8fd45b0963b06870b4031eb32df8 100644 (file)
@@ -158,10 +158,14 @@ static int init_resolver(struct engine *engine)
 {
        /* Open resolution context */
        engine->resolver.modules = &engine->modules;
-       /* Open NS reputation cache */
-       engine->resolver.nsrep = malloc(lru_size(kr_nsrep_lru_t, DEFAULT_NSREP_SIZE));
-       if (engine->resolver.nsrep) {
-               lru_init(engine->resolver.nsrep, DEFAULT_NSREP_SIZE);
+       /* Open NS rtt + reputation cache */
+       engine->resolver.cache_rtt = malloc(lru_size(kr_nsrep_lru_t, LRU_RTT_SIZE));
+       if (engine->resolver.cache_rtt) {
+               lru_init(engine->resolver.cache_rtt, LRU_RTT_SIZE);
+       }
+       engine->resolver.cache_rep = malloc(lru_size(kr_nsrep_lru_t, LRU_REP_SIZE));
+       if (engine->resolver.cache_rep) {
+               lru_init(engine->resolver.cache_rep, LRU_REP_SIZE);
        }
 
        /* Load basic modules */
@@ -244,7 +248,8 @@ void engine_deinit(struct engine *engine)
 
        network_deinit(&engine->net);
        kr_cache_close(&engine->resolver.cache);
-       lru_deinit(engine->resolver.nsrep);
+       lru_deinit(engine->resolver.cache_rtt);
+       lru_deinit(engine->resolver.cache_rep);
 
        /* Unload modules. */
        for (size_t i = 0; i < engine->modules.len; ++i) {
index 2f3b0794c54c270cd390168bd7744a62aa7bca02..1eb546c1dac1b5cf452098c254a630e3ea453e0c 100644 (file)
 #pragma once
 
 /* Magic defaults */
-#ifndef DEFAULT_NSREP_SIZE
-#define DEFAULT_NSREP_SIZE 4096 /**< Default NS reputation cache size */
+#ifndef LRU_RTT_SIZE
+#define LRU_RTT_SIZE 4096 /**< NS RTT cache size */
+#endif
+#ifndef LRU_REP_SIZE
+#define LRU_REP_SIZE (LRU_RTT_SIZE / 2) /**< NS reputation cache size */
 #endif
 
 /*
index d7125381dccc14f4e4317fa29d46ab9f4d58021a..39af6abb3359d5d54cd0b2003d206c3226e83ad1 100644 (file)
@@ -129,7 +129,7 @@ int main(int argc, char **argv)
 
        /* Create a server engine. */
        mm_ctx_t pool;
-       mm_ctx_mempool(&pool, 4096);
+       mm_ctx_mempool(&pool, MM_DEFAULT_BLKSIZE);
        struct engine engine;
        ret = engine_init(&engine, &pool);
        if (ret != 0) {
index 967c5c89bdb7eef371f73abbe507eb71dae8c2ae..5d6ef551e2c53630c3bcaa7579f4be50a312f7ae 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "lib/nsrep.h"
 #include "lib/rplan.h"
+#include "lib/resolve.h"
 #include "lib/defines.h"
 #include "lib/generic/pack.h"
 
@@ -81,30 +82,48 @@ static unsigned eval_addr_set(pack_t *addr_set, kr_nsrep_lru_t *rttcache, unsign
 
 static int eval_nsrep(const char *k, void *v, void *baton)
 {
-       struct kr_nsrep *ns = baton;
+       struct kr_query *qry = baton;
+       struct kr_nsrep *ns = &qry->ns;
+       struct kr_context *ctx = ns->ctx;
        unsigned score = KR_NS_MAX_SCORE;
+       unsigned reputation = 0;
        uint8_t *addr = NULL;
 
+       /* Fetch NS reputation */
+       if (ctx->cache_rep) {
+               unsigned *cached = lru_get(ctx->cache_rep, k, knot_dname_size((const uint8_t *)k));
+               if (cached) {
+                       reputation = *cached;
+               }
+       }
+
        /* Favour nameservers with unknown addresses to probe them,
         * otherwise discover the current best address for the NS. */
        pack_t *addr_set = (pack_t *)v;
        if (addr_set->len == 0) {
                score = KR_NS_UNKNOWN;
+               /* If the server is unknown but has rep record, treat it as timeouted */
+               if ((reputation & KR_NS_NOIP4) && (reputation & KR_NS_NOIP6)) {
+                       score = KR_NS_TIMEOUT;
+                       reputation = 0; /* Start with clean slate */
+               }
        } else {
-               score = eval_addr_set(addr_set, ns->repcache, score, &addr);
+               score = eval_addr_set(addr_set, ctx->cache_rtt, score, &addr);
        }
 
        /* Probabilistic bee foraging strategy (naive).
         * The fastest NS is preferred by workers until it is depleted (timeouts or degrades),
         * at the same time long distance scouts probe other sources (low probability).
         * Servers on TIMEOUT (depleted) can be probed by the dice roll only */
-       if (score < ns->score && (ns->flags & QUERY_NO_THROTTLE || score < KR_NS_TIMEOUT)) {
+       if (score < ns->score && (qry->flags & QUERY_NO_THROTTLE || score < KR_NS_TIMEOUT)) {
                update_nsrep(ns, (const knot_dname_t *)k, addr, score);
+               ns->reputation = reputation;
        } else {
                /* With 5% chance, probe server with a probability given by its RTT / MAX_RTT */
                unsigned roll = rand() % KR_NS_MAX_SCORE;
                if ((roll % 100 < 5) && (roll >= score)) {
                        update_nsrep(ns, (const knot_dname_t *)k, addr, score);
+                       ns->reputation = reputation;
                        return 1; /* Stop evaluation */
                }
        }
@@ -112,23 +131,29 @@ static int eval_nsrep(const char *k, void *v, void *baton)
        return kr_ok();
 }
 
-int kr_nsrep_elect(struct kr_nsrep *ns, map_t *nsset, kr_nsrep_lru_t *repcache)
+int kr_nsrep_elect(struct kr_query *qry, struct kr_context *ctx)
 {
-       ns->repcache = repcache;
+       if (!qry || !ctx) {
+               return kr_error(EINVAL);
+       }
+
+       struct kr_nsrep *ns = &qry->ns;
+       ns->ctx = ctx;
        ns->addr.ip.sa_family = AF_UNSPEC;
+       ns->reputation = 0;
        ns->score = KR_NS_MAX_SCORE + 1;
-       return map_walk(nsset, eval_nsrep, ns);
+       return map_walk(&qry->zone_cut.nsset, eval_nsrep, qry);
 }
 
-int kr_nsrep_update(struct kr_nsrep *ns, unsigned score, kr_nsrep_lru_t *repcache)
+int kr_nsrep_update_rtt(struct kr_nsrep *ns, unsigned score, kr_nsrep_lru_t *cache)
 {
-       if (!ns || !repcache || ns->addr.ip.sa_family == AF_UNSPEC) {
+       if (!ns || !cache || ns->addr.ip.sa_family == AF_UNSPEC) {
                return kr_error(EINVAL);
        }
 
        char *addr = kr_nsrep_inaddr(ns->addr);
        size_t addr_len = kr_nsrep_inaddr_len(ns->addr);
-       unsigned *cur = lru_set(repcache, addr, addr_len);
+       unsigned *cur = lru_set(cache, addr, addr_len);
        if (!cur) {
                return kr_error(ENOMEM);
        }
@@ -148,3 +173,20 @@ int kr_nsrep_update(struct kr_nsrep *ns, unsigned score, kr_nsrep_lru_t *repcach
        }
        return kr_ok();
 }
+
+int kr_nsrep_update_rep(struct kr_nsrep *ns, unsigned reputation, kr_nsrep_lru_t *cache)
+{
+       if (!ns || !cache ) {
+               return kr_error(EINVAL);
+       }
+
+       /* Store in the struct */
+       ns->reputation = reputation;
+       /* Store reputation in the LRU cache */
+       unsigned *cur = lru_set(cache, (const char *)ns->name, knot_dname_size(ns->name));
+       if (!cur) {
+               return kr_error(ENOMEM);
+       }
+       *cur = reputation;
+       return kr_ok();
+}
\ No newline at end of file
index 7df5493d08d778c13a0867860fbf292782f7e4be..7b397fc77e878af4e8f9b4ef751a475053d5e4aa 100644 (file)
 #include "lib/generic/map.h"
 #include "lib/generic/lru.h"
 
+struct kr_query;
+
 /** 
-  * Special values for nameserver score (RTT in miliseconds)
+  * NS RTT score (special values).
+  * @note RTT is measured in milliseconds.
   */
 enum kr_ns_score {
        KR_NS_MAX_SCORE = KR_CONN_RTT_MAX,
@@ -33,6 +36,15 @@ enum kr_ns_score {
        KR_NS_UNKNOWN   = 10
 };
 
+/**
+ * NS QoS flags.
+ */
+enum kr_ns_rep {
+       KR_NS_NOIP4  = 1 << 0, /**< NS has no IPv4 */
+       KR_NS_NOIP6  = 1 << 1, /**< NS has no IPv6 */
+       KR_NS_NOEDNS = 1 << 2  /**< NS has no EDNS support */
+};
+
 /**
  * NS reputation/QoS tracking.
  */
@@ -45,15 +57,15 @@ typedef lru_hash(unsigned) kr_nsrep_lru_t;
  */
 struct kr_nsrep
 {
-       unsigned score;                  /**< Server score */
-       unsigned flags;                  /**< Server flags */
-       const knot_dname_t *name;        /**< Server name */
-       kr_nsrep_lru_t *repcache;        /**< Reputation cache pointer */
+       unsigned score;                  /**< NS score */
+       unsigned reputation;             /**< NS reputation */
+       const knot_dname_t *name;        /**< NS name */
+       struct kr_context *ctx;          /**< Resolution context */
        union {
                struct sockaddr ip;
                struct sockaddr_in ip4;
                struct sockaddr_in6 ip6;
-       } addr;                          /**< Server address */
+       } addr;                          /**< NS address */
 };
 
 /** @internal Address bytes for given family. */
@@ -65,21 +77,32 @@ struct kr_nsrep
 
 /**
  * Elect best nameserver/address pair from the nsset.
- * @param  ns           updated NS representation
- * @param  nsset        NS set to choose from
- * @param  repcache     reputation storage
- * @return              score, see enum kr_ns_score
+ * @param  qry          updated query
+ * @param  ctx          resolution context
+ * @return              0 or an error code
  */
-int kr_nsrep_elect(struct kr_nsrep *ns, map_t *nsset, kr_nsrep_lru_t *repcache);
+int kr_nsrep_elect(struct kr_query *qry, struct kr_context *ctx);
 
 /**
- * Update NS quality information.
+ * Update NS address RTT information.
  *
  * @brief Reputation is smoothed over last N measurements.
  * 
  * @param  ns           updated NS representation
  * @param  score        new score (i.e. RTT), see enum kr_ns_score
- * @param  reputation   reputation storage
+ * @param  cache        LRU cache
+ * @return              0 on success, error code on failure
+ */
+int kr_nsrep_update_rtt(struct kr_nsrep *ns, unsigned score, kr_nsrep_lru_t *cache);
+
+/**
+ * Update NS name quality information.
+ *
+ * @brief Reputation is smoothed over last N measurements.
+ * 
+ * @param  ns           updated NS representation
+ * @param  reputation   combined reputation flags, see enum kr_ns_rep
+ * @param  cache        LRU cache
  * @return              0 on success, error code on failure
  */
-int kr_nsrep_update(struct kr_nsrep *ns, unsigned score, kr_nsrep_lru_t *repcache);
+int kr_nsrep_update_rep(struct kr_nsrep *ns, unsigned reputation, kr_nsrep_lru_t *cache);
index 68779cc593d2e6b75d2a6a87514395ae3904057b..49c9280556fb4360a8946913f05c6936d81ef413 100644 (file)
@@ -64,7 +64,7 @@ static void ns_fetch_cut(struct kr_query *qry, struct kr_request *req)
                        start_from = parent->zone_cut.name;
                }
                /* Find closest zone cut from cache */
-               kr_zonecut_find_cached(&qry->zone_cut, start_from, &txn, qry->timestamp.tv_sec);
+               kr_zonecut_find_cached(req->ctx, &qry->zone_cut, start_from, &txn, qry->timestamp.tv_sec);
                kr_cache_txn_abort(&txn);
        }
 }
@@ -72,6 +72,8 @@ static void ns_fetch_cut(struct kr_query *qry, struct kr_request *req)
 static int ns_resolve_addr(struct kr_query *qry, struct kr_request *param)
 {
        struct kr_rplan *rplan = &param->rplan;
+       struct kr_context *ctx = param->ctx;
+
 
        /* Start NS queries from root, to avoid certain cases
         * where a NS drops out of cache and the rest is unavailable,
@@ -85,10 +87,14 @@ static int ns_resolve_addr(struct kr_query *qry, struct kr_request *param)
        } else if (!(qry->flags & QUERY_AWAIT_IPV4)) {
                next_type = KNOT_RRTYPE_A;
                qry->flags |= QUERY_AWAIT_IPV4;
+               /* Hmm, no useable IPv6 then. */
+               kr_nsrep_update_rep(&qry->ns, qry->ns.reputation | KR_NS_NOIP6, ctx->cache_rep);
        }
        /* Bail out if the query is already pending or dependency loop. */
        if (!next_type || kr_rplan_satisfies(qry->parent, qry->ns.name, KNOT_CLASS_IN, next_type)) {
-               DEBUG_MSG("=> dependency loop, bailing out\n");
+               /* No IPv4 nor IPv6, flag server as unuseable. */
+               DEBUG_MSG("=> unresolvable NS address, bailing out\n");
+               kr_nsrep_update_rep(&qry->ns, qry->ns.reputation | (KR_NS_NOIP4|KR_NS_NOIP6), ctx->cache_rep);
                invalidate_ns(rplan, qry);
                return kr_error(EHOSTUNREACH);
        }
@@ -343,6 +349,7 @@ int kr_resolve_query(struct kr_request *request, const knot_dname_t *qname, uint
 int kr_resolve_consume(struct kr_request *request, knot_pkt_t *packet)
 {
        struct kr_rplan *rplan = &request->rplan;
+       struct kr_context *ctx = request->ctx;
        struct kr_query *qry = kr_rplan_current(rplan);
 
        /* Empty resolution plan, push packet as the new query */
@@ -366,8 +373,6 @@ int kr_resolve_consume(struct kr_request *request, knot_pkt_t *packet)
                        DEBUG_MSG("=> ns unreachable, retrying over TCP\n");
                        qry->flags |= QUERY_TCP;
                        return KNOT_STATE_CONSUME; /* Try again */
-               } else {
-                       kr_nsrep_update(&qry->ns, KR_NS_TIMEOUT, qry->ns.repcache);
                }
        } else {
                state = knot_overlay_consume(&request->overlay, packet);
@@ -376,6 +381,7 @@ int kr_resolve_consume(struct kr_request *request, knot_pkt_t *packet)
        /* Resolution failed, invalidate current NS and reset to UDP. */
        if (state == KNOT_STATE_FAIL) {
                DEBUG_MSG("=> resolution failed, invalidating\n");
+               kr_nsrep_update_rtt(&qry->ns, KR_NS_TIMEOUT, ctx->cache_rtt);
                if (invalidate_ns(rplan, qry) == 0) {
                        qry->flags &= ~QUERY_TCP;
                }
@@ -383,7 +389,7 @@ int kr_resolve_consume(struct kr_request *request, knot_pkt_t *packet)
        } else if (!(qry->flags & QUERY_CACHED)) {
                struct timeval now;
                gettimeofday(&now, NULL);
-               kr_nsrep_update(&qry->ns, time_diff(&qry->timestamp, &now), qry->ns.repcache);
+               kr_nsrep_update_rtt(&qry->ns, time_diff(&qry->timestamp, &now), ctx->cache_rtt);
        }
 
        /* Pop query if resolved. */
@@ -451,18 +457,21 @@ int kr_resolve_produce(struct kr_request *request, struct sockaddr **dst, int *t
 ns_election:
        /* Elect best nameserver candidate */
        assert(++ns_election_iter < KR_ITER_LIMIT);
-       /* Set slow NS throttling mode */
-       qry->ns.flags = 0;
-       if (qry->flags & QUERY_NO_THROTTLE) {
-               qry->ns.flags = QUERY_NO_THROTTLE;
-       }
-       kr_nsrep_elect(&qry->ns, &qry->zone_cut.nsset, request->ctx->nsrep);
+       kr_nsrep_elect(qry, request->ctx);
        if (qry->ns.score > KR_NS_MAX_SCORE) {
                DEBUG_MSG("=> no valid NS left\n");
                knot_overlay_reset(&request->overlay);
                kr_rplan_pop(rplan, qry);
                return KNOT_STATE_PRODUCE;
        } else {
+               /* Update query flags based on the NS reputation */
+               if (qry->ns.reputation & KR_NS_NOIP6) {
+                       qry->flags |= QUERY_AWAIT_IPV6;
+               }
+               if (qry->ns.reputation & KR_NS_NOIP4) {
+                       qry->flags |= QUERY_AWAIT_IPV4;
+               }
+               /* Resolve address records */
                if (qry->ns.addr.ip.sa_family == AF_UNSPEC) {
                        if (ns_resolve_addr(qry, request) != 0) {
                                qry->flags &= ~(QUERY_AWAIT_IPV6|QUERY_AWAIT_IPV4);
index e03629bd89c11528ec724d73d8699cc105f0b8fd..7c1c66430f095af16cd9fff884b25e59ad070acb 100644 (file)
@@ -101,7 +101,8 @@ struct kr_context
 {
        mm_ctx_t *pool;
        struct kr_cache cache;
-       kr_nsrep_lru_t *nsrep;
+       kr_nsrep_lru_t *cache_rtt;
+       kr_nsrep_lru_t *cache_rep;
        module_array_t *modules;
        uint32_t options;
 };
index 1ed1288416189669284227a72ec66b9218f9caf4..c13419a44cd570ed6f1ad8457bd51412176e1b98 100644 (file)
@@ -211,7 +211,7 @@ static void fetch_addr(struct kr_zonecut *cut, const knot_dname_t *ns, uint16_t
 }
 
 /** Fetch best NS for zone cut. */
-static int fetch_ns(struct kr_zonecut *cut, const knot_dname_t *name, struct kr_cache_txn *txn, uint32_t timestamp)
+static int fetch_ns(struct kr_context *ctx, struct kr_zonecut *cut, const knot_dname_t *name, struct kr_cache_txn *txn, uint32_t timestamp)
 {
        uint32_t drift = timestamp;
        knot_rrset_t cached_rr;
@@ -226,8 +226,15 @@ static int fetch_ns(struct kr_zonecut *cut, const knot_dname_t *name, struct kr_
        for (unsigned i = 0; i < cached_rr.rrs.rr_count; ++i) {
                const knot_dname_t *ns_name = knot_ns_name(&cached_rr.rrs, i);
                kr_zonecut_add(cut, ns_name, NULL);
-               fetch_addr(cut, ns_name, KNOT_RRTYPE_A, txn, timestamp);
-               fetch_addr(cut, ns_name, KNOT_RRTYPE_AAAA, txn, timestamp);
+               /* Fetch NS reputation and decide whether to prefetch A/AAAA records. */
+               unsigned *cached = lru_get(ctx->cache_rep, (const char *)ns_name, knot_dname_size(ns_name));
+               unsigned reputation = (cached) ? *cached : 0;
+               if (!(reputation & KR_NS_NOIP4)) {
+                       fetch_addr(cut, ns_name, KNOT_RRTYPE_A, txn, timestamp);
+               }
+               if (!(reputation & KR_NS_NOIP6)) {
+                       fetch_addr(cut, ns_name, KNOT_RRTYPE_AAAA, txn, timestamp);
+               }
        }
 
        /* Always keep SBELT as a backup for root */
@@ -238,7 +245,8 @@ static int fetch_ns(struct kr_zonecut *cut, const knot_dname_t *name, struct kr_
        return kr_ok();
 }
 
-int kr_zonecut_find_cached(struct kr_zonecut *cut, const knot_dname_t *name, struct kr_cache_txn *txn, uint32_t timestamp)
+int kr_zonecut_find_cached(struct kr_context *ctx, struct kr_zonecut *cut, const knot_dname_t *name,
+                           struct kr_cache_txn *txn, uint32_t timestamp)
 {
        if (cut == NULL) {
                return kr_error(EINVAL);
@@ -247,7 +255,7 @@ int kr_zonecut_find_cached(struct kr_zonecut *cut, const knot_dname_t *name, str
        /* Start at QNAME parent. */
        name = knot_wire_next_label(name, NULL);
        while (txn) {
-               if (fetch_ns(cut, name, txn, timestamp) == 0) {
+               if (fetch_ns(ctx, cut, name, txn, timestamp) == 0) {
                        update_cut_name(cut, name);
                        return kr_ok();
                }
index 545098d32cad716d16d90009b2bf61b540178e50..990220aba43e714456307ff13e18817488300575 100644 (file)
@@ -21,6 +21,7 @@
 #include "lib/cache.h"
 
 struct kr_rplan;
+struct kr_context;
 
 /**
  * Current zone cut representation.
@@ -98,11 +99,13 @@ int kr_zonecut_set_sbelt(struct kr_zonecut *cut);
 
 /**
  * Populate zone cut address set from cache.
- * 
+ *
+ * @param ctx       resolution context (to fetch data from LRU caches)
  * @param cut       zone cut to be populated
  * @param name      QNAME to start finding zone cut for
  * @param txn       cache transaction (read)
  * @param timestamp transaction timestamp
  * @return 0 or error code
  */
-int kr_zonecut_find_cached(struct kr_zonecut *cut, const knot_dname_t *name, struct kr_cache_txn *txn, uint32_t timestamp);
+int kr_zonecut_find_cached(struct kr_context *ctx, struct kr_zonecut *cut, const knot_dname_t *name,
+                           struct kr_cache_txn *txn, uint32_t timestamp);
index 4ea1517cc818d379c27484c5e905513a3038ee56..c43c34999331dd84fff7bce92812c770b9154499 100644 (file)
@@ -77,10 +77,13 @@ static PyObject* init(PyObject* self, PyObject* args)
            return NULL;
        }
 
-       /* Create RTT tracking */
-       global_context.nsrep = malloc(lru_size(kr_nsrep_lru_t, 1000));
-       assert(global_context.nsrep);
-       lru_init(global_context.nsrep, 1000);
+       /* Create RTT + reputation tracking */
+       global_context.cache_rtt = malloc(lru_size(kr_nsrep_lru_t, 1024));
+       assert(global_context.cache_rtt);
+       lru_init(global_context.cache_rtt, 1024);
+       global_context.cache_rep = malloc(lru_size(kr_nsrep_lru_t, 512));
+       assert(global_context.cache_rep);
+       lru_init(global_context.cache_rep, 512);
        global_context.options = QUERY_NO_THROTTLE;
 
        /* No configuration parsing support yet. */
@@ -102,8 +105,10 @@ static PyObject* deinit(PyObject* self, PyObject* args)
        }
        array_clear(global_modules);
        kr_cache_close(&global_context.cache);
-       lru_deinit(global_context.nsrep);
-       free(global_context.nsrep);
+       lru_deinit(global_context.cache_rtt);
+       lru_deinit(global_context.cache_rep);
+       free(global_context.cache_rtt);
+       free(global_context.cache_rep);
 
        test_tmpdir_remove(global_tmpdir);
        global_tmpdir = NULL;
index a9401cbffcde3a61fd7cc537d4936a1374edb946..24b9a8fec5408b9b9cf2f7ce0d637c06a6946395 100644 (file)
@@ -30,7 +30,7 @@ static void test_zonecut_params(void **state)
        assert_null((void *)kr_zonecut_find(NULL, NULL));
        assert_null((void *)kr_zonecut_find(&cut, NULL));
        assert_int_not_equal(kr_zonecut_set_sbelt(NULL), 0);
-       assert_int_not_equal(kr_zonecut_find_cached(NULL, NULL, NULL, 0), 0);
+       assert_int_not_equal(kr_zonecut_find_cached(NULL, NULL, NULL, NULL, 0), 0);
 }
 
 int main(void)