qpcache.c revision 1.1 1 1.1 christos /* $NetBSD: qpcache.c,v 1.1 2025/01/26 16:12:33 christos Exp $ */
2 1.1 christos
3 1.1 christos /*
4 1.1 christos * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 1.1 christos *
6 1.1 christos * SPDX-License-Identifier: MPL-2.0
7 1.1 christos *
8 1.1 christos * This Source Code Form is subject to the terms of the Mozilla Public
9 1.1 christos * License, v. 2.0. If a copy of the MPL was not distributed with this
10 1.1 christos * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11 1.1 christos *
12 1.1 christos * See the COPYRIGHT file distributed with this work for additional
13 1.1 christos * information regarding copyright ownership.
14 1.1 christos */
15 1.1 christos
16 1.1 christos /*! \file */
17 1.1 christos
18 1.1 christos #include <inttypes.h>
19 1.1 christos #include <stdbool.h>
20 1.1 christos #include <sys/mman.h>
21 1.1 christos
22 1.1 christos #include <isc/ascii.h>
23 1.1 christos #include <isc/async.h>
24 1.1 christos #include <isc/atomic.h>
25 1.1 christos #include <isc/crc64.h>
26 1.1 christos #include <isc/file.h>
27 1.1 christos #include <isc/hash.h>
28 1.1 christos #include <isc/hashmap.h>
29 1.1 christos #include <isc/heap.h>
30 1.1 christos #include <isc/hex.h>
31 1.1 christos #include <isc/loop.h>
32 1.1 christos #include <isc/mem.h>
33 1.1 christos #include <isc/mutex.h>
34 1.1 christos #include <isc/once.h>
35 1.1 christos #include <isc/queue.h>
36 1.1 christos #include <isc/random.h>
37 1.1 christos #include <isc/refcount.h>
38 1.1 christos #include <isc/result.h>
39 1.1 christos #include <isc/rwlock.h>
40 1.1 christos #include <isc/stdio.h>
41 1.1 christos #include <isc/string.h>
42 1.1 christos #include <isc/time.h>
43 1.1 christos #include <isc/urcu.h>
44 1.1 christos #include <isc/util.h>
45 1.1 christos
46 1.1 christos #include <dns/callbacks.h>
47 1.1 christos #include <dns/db.h>
48 1.1 christos #include <dns/dbiterator.h>
49 1.1 christos #include <dns/fixedname.h>
50 1.1 christos #include <dns/log.h>
51 1.1 christos #include <dns/masterdump.h>
52 1.1 christos #include <dns/nsec.h>
53 1.1 christos #include <dns/qp.h>
54 1.1 christos #include <dns/rdata.h>
55 1.1 christos #include <dns/rdataset.h>
56 1.1 christos #include <dns/rdatasetiter.h>
57 1.1 christos #include <dns/rdataslab.h>
58 1.1 christos #include <dns/rdatastruct.h>
59 1.1 christos #include <dns/stats.h>
60 1.1 christos #include <dns/time.h>
61 1.1 christos #include <dns/view.h>
62 1.1 christos #include <dns/zonekey.h>
63 1.1 christos
64 1.1 christos #include "db_p.h"
65 1.1 christos #include "qpcache_p.h"
66 1.1 christos
67 1.1 christos #define CHECK(op) \
68 1.1 christos do { \
69 1.1 christos result = (op); \
70 1.1 christos if (result != ISC_R_SUCCESS) \
71 1.1 christos goto failure; \
72 1.1 christos } while (0)
73 1.1 christos
74 1.1 christos #define EXISTS(header) \
75 1.1 christos ((atomic_load_acquire(&(header)->attributes) & \
76 1.1 christos DNS_SLABHEADERATTR_NONEXISTENT) == 0)
77 1.1 christos #define NONEXISTENT(header) \
78 1.1 christos ((atomic_load_acquire(&(header)->attributes) & \
79 1.1 christos DNS_SLABHEADERATTR_NONEXISTENT) != 0)
80 1.1 christos #define IGNORE(header) \
81 1.1 christos ((atomic_load_acquire(&(header)->attributes) & \
82 1.1 christos DNS_SLABHEADERATTR_IGNORE) != 0)
83 1.1 christos #define NXDOMAIN(header) \
84 1.1 christos ((atomic_load_acquire(&(header)->attributes) & \
85 1.1 christos DNS_SLABHEADERATTR_NXDOMAIN) != 0)
86 1.1 christos #define STALE(header) \
87 1.1 christos ((atomic_load_acquire(&(header)->attributes) & \
88 1.1 christos DNS_SLABHEADERATTR_STALE) != 0)
89 1.1 christos #define STALE_WINDOW(header) \
90 1.1 christos ((atomic_load_acquire(&(header)->attributes) & \
91 1.1 christos DNS_SLABHEADERATTR_STALE_WINDOW) != 0)
92 1.1 christos #define OPTOUT(header) \
93 1.1 christos ((atomic_load_acquire(&(header)->attributes) & \
94 1.1 christos DNS_SLABHEADERATTR_OPTOUT) != 0)
95 1.1 christos #define NEGATIVE(header) \
96 1.1 christos ((atomic_load_acquire(&(header)->attributes) & \
97 1.1 christos DNS_SLABHEADERATTR_NEGATIVE) != 0)
98 1.1 christos #define PREFETCH(header) \
99 1.1 christos ((atomic_load_acquire(&(header)->attributes) & \
100 1.1 christos DNS_SLABHEADERATTR_PREFETCH) != 0)
101 1.1 christos #define ZEROTTL(header) \
102 1.1 christos ((atomic_load_acquire(&(header)->attributes) & \
103 1.1 christos DNS_SLABHEADERATTR_ZEROTTL) != 0)
104 1.1 christos #define ANCIENT(header) \
105 1.1 christos ((atomic_load_acquire(&(header)->attributes) & \
106 1.1 christos DNS_SLABHEADERATTR_ANCIENT) != 0)
107 1.1 christos #define STATCOUNT(header) \
108 1.1 christos ((atomic_load_acquire(&(header)->attributes) & \
109 1.1 christos DNS_SLABHEADERATTR_STATCOUNT) != 0)
110 1.1 christos
111 1.1 christos #define STALE_TTL(header, qpdb) \
112 1.1 christos (NXDOMAIN(header) ? 0 : qpdb->common.serve_stale_ttl)
113 1.1 christos
114 1.1 christos #define ACTIVE(header, now) \
115 1.1 christos (((header)->ttl > (now)) || ((header)->ttl == (now) && ZEROTTL(header)))
116 1.1 christos
117 1.1 christos #define EXPIREDOK(iterator) \
118 1.1 christos (((iterator)->common.options & DNS_DB_EXPIREDOK) != 0)
119 1.1 christos
120 1.1 christos #define STALEOK(iterator) (((iterator)->common.options & DNS_DB_STALEOK) != 0)
121 1.1 christos
122 1.1 christos #define KEEPSTALE(qpdb) ((qpdb)->common.serve_stale_ttl > 0)
123 1.1 christos
124 1.1 christos /*%
125 1.1 christos * Note that "impmagic" is not the first four bytes of the struct, so
126 1.1 christos * ISC_MAGIC_VALID cannot be used.
127 1.1 christos */
128 1.1 christos #define QPDB_MAGIC ISC_MAGIC('Q', 'P', 'D', '4')
129 1.1 christos #define VALID_QPDB(qpdb) \
130 1.1 christos ((qpdb) != NULL && (qpdb)->common.impmagic == QPDB_MAGIC)
131 1.1 christos
132 1.1 christos #define HEADERNODE(h) ((qpcnode_t *)((h)->node))
133 1.1 christos
134 1.1 christos /*
135 1.1 christos * Allow clients with a virtual time of up to 5 minutes in the past to see
136 1.1 christos * records that would have otherwise have expired.
137 1.1 christos */
138 1.1 christos #define QPDB_VIRTUAL 300
139 1.1 christos
140 1.1 christos /*%
141 1.1 christos * Whether to rate-limit updating the LRU to avoid possible thread contention.
142 1.1 christos * Updating LRU requires write locking, so we don't do it every time the
143 1.1 christos * record is touched - only after some time passes.
144 1.1 christos */
145 1.1 christos #ifndef DNS_QPDB_LIMITLRUUPDATE
146 1.1 christos #define DNS_QPDB_LIMITLRUUPDATE 1
147 1.1 christos #endif
148 1.1 christos
149 1.1 christos /*% Time after which we update LRU for glue records, 5 minutes */
150 1.1 christos #define DNS_QPDB_LRUUPDATE_GLUE 300
151 1.1 christos /*% Time after which we update LRU for all other records, 10 minutes */
152 1.1 christos #define DNS_QPDB_LRUUPDATE_REGULAR 600
153 1.1 christos
154 1.1 christos /*
155 1.1 christos * This defines the number of headers that we try to expire each time the
156 1.1 christos * expire_ttl_headers() is run. The number should be small enough, so the
157 1.1 christos * TTL-based header expiration doesn't take too long, but it should be large
158 1.1 christos * enough, so we expire enough headers if their TTL is clustered.
159 1.1 christos */
160 1.1 christos #define DNS_QPDB_EXPIRE_TTL_COUNT 10
161 1.1 christos
162 1.1 christos /*%
163 1.1 christos * This is the structure that is used for each node in the qp trie of trees.
164 1.1 christos */
165 1.1 christos typedef struct qpcnode qpcnode_t;
166 1.1 christos struct qpcnode {
167 1.1 christos dns_name_t name;
168 1.1 christos isc_mem_t *mctx;
169 1.1 christos
170 1.1 christos uint8_t : 0;
171 1.1 christos unsigned int delegating : 1;
172 1.1 christos unsigned int nsec : 2; /*%< range is 0..3 */
173 1.1 christos uint8_t : 0;
174 1.1 christos
175 1.1 christos isc_refcount_t references;
176 1.1 christos isc_refcount_t erefs;
177 1.1 christos uint16_t locknum;
178 1.1 christos void *data;
179 1.1 christos
180 1.1 christos /*%
181 1.1 christos * NOTE: The 'dirty' flag is protected by the node lock, so
182 1.1 christos * this bitfield has to be separated from the one above.
183 1.1 christos * We don't want it to share the same qword with bits
184 1.1 christos * that can be accessed without the node lock.
185 1.1 christos */
186 1.1 christos uint8_t : 0;
187 1.1 christos uint8_t dirty : 1;
188 1.1 christos uint8_t : 0;
189 1.1 christos
190 1.1 christos /*%
191 1.1 christos * Used for dead nodes cleaning. This linked list is used to mark nodes
192 1.1 christos * which have no data any longer, but we cannot unlink at that exact
193 1.1 christos * moment because we did not or could not obtain a write lock on the
194 1.1 christos * tree.
195 1.1 christos */
196 1.1 christos isc_queue_node_t deadlink;
197 1.1 christos };
198 1.1 christos
199 1.1 christos typedef struct qpcache qpcache_t;
200 1.1 christos struct qpcache {
201 1.1 christos /* Unlocked. */
202 1.1 christos dns_db_t common;
203 1.1 christos /* Loopmgr */
204 1.1 christos isc_loopmgr_t *loopmgr;
205 1.1 christos /* Locks the data in this struct */
206 1.1 christos isc_rwlock_t lock;
207 1.1 christos /* Locks the tree structure (prevents nodes appearing/disappearing) */
208 1.1 christos isc_rwlock_t tree_lock;
209 1.1 christos /* Locks for individual tree nodes */
210 1.1 christos unsigned int node_lock_count;
211 1.1 christos db_nodelock_t *node_locks;
212 1.1 christos qpcnode_t *origin_node;
213 1.1 christos dns_stats_t *rrsetstats; /* cache DB only */
214 1.1 christos isc_stats_t *cachestats; /* cache DB only */
215 1.1 christos isc_stats_t *gluecachestats; /* zone DB only */
216 1.1 christos /* Locked by lock. */
217 1.1 christos unsigned int active;
218 1.1 christos
219 1.1 christos uint32_t maxrrperset; /* Maximum RRs per RRset */
220 1.1 christos uint32_t maxtypepername; /* Maximum number of RR types per owner */
221 1.1 christos
222 1.1 christos /*
223 1.1 christos * The time after a failed lookup, where stale answers from cache
224 1.1 christos * may be used directly in a DNS response without attempting a
225 1.1 christos * new iterative lookup.
226 1.1 christos */
227 1.1 christos uint32_t serve_stale_refresh;
228 1.1 christos
229 1.1 christos /*
230 1.1 christos * This is an array of linked lists used to implement the LRU cache.
231 1.1 christos * There will be node_lock_count linked lists here. Nodes in bucket 1
232 1.1 christos * will be placed on the linked list lru[1].
233 1.1 christos */
234 1.1 christos dns_slabheaderlist_t *lru;
235 1.1 christos
236 1.1 christos /*
237 1.1 christos * Start point % node_lock_count for next LRU cleanup.
238 1.1 christos */
239 1.1 christos atomic_uint lru_sweep;
240 1.1 christos
241 1.1 christos /*
242 1.1 christos * When performing LRU cleaning limit cleaning to headers that were
243 1.1 christos * last used at or before this.
244 1.1 christos */
245 1.1 christos _Atomic(isc_stdtime_t) last_used;
246 1.1 christos
247 1.1 christos /*%
248 1.1 christos * Temporary storage for stale cache nodes and dynamically deleted
249 1.1 christos * nodes that await being cleaned up.
250 1.1 christos */
251 1.1 christos isc_queue_t *deadnodes;
252 1.1 christos
253 1.1 christos /*
254 1.1 christos * Heaps. These are used for TTL based expiry in a cache,
255 1.1 christos * or for zone resigning in a zone DB. hmctx is the memory
256 1.1 christos * context to use for the heap (which differs from the main
257 1.1 christos * database memory context in the case of a cache).
258 1.1 christos */
259 1.1 christos isc_mem_t *hmctx;
260 1.1 christos isc_heap_t **heaps;
261 1.1 christos
262 1.1 christos /* Locked by tree_lock. */
263 1.1 christos dns_qp_t *tree;
264 1.1 christos dns_qp_t *nsec;
265 1.1 christos };
266 1.1 christos
267 1.1 christos /*%
268 1.1 christos * Search Context
269 1.1 christos */
270 1.1 christos typedef struct {
271 1.1 christos qpcache_t *qpdb;
272 1.1 christos unsigned int options;
273 1.1 christos dns_qpchain_t chain;
274 1.1 christos dns_qpiter_t iter;
275 1.1 christos bool need_cleanup;
276 1.1 christos qpcnode_t *zonecut;
277 1.1 christos dns_slabheader_t *zonecut_header;
278 1.1 christos dns_slabheader_t *zonecut_sigheader;
279 1.1 christos isc_stdtime_t now;
280 1.1 christos } qpc_search_t;
281 1.1 christos
282 1.1 christos #ifdef DNS_DB_NODETRACE
283 1.1 christos #define qpcnode_ref(ptr) qpcnode__ref(ptr, __func__, __FILE__, __LINE__)
284 1.1 christos #define qpcnode_unref(ptr) qpcnode__unref(ptr, __func__, __FILE__, __LINE__)
285 1.1 christos #define qpcnode_attach(ptr, ptrp) \
286 1.1 christos qpcnode__attach(ptr, ptrp, __func__, __FILE__, __LINE__)
287 1.1 christos #define qpcnode_detach(ptrp) qpcnode__detach(ptrp, __func__, __FILE__, __LINE__)
288 1.1 christos ISC_REFCOUNT_STATIC_TRACE_DECL(qpcnode);
289 1.1 christos #else
290 1.1 christos ISC_REFCOUNT_STATIC_DECL(qpcnode);
291 1.1 christos #endif
292 1.1 christos
293 1.1 christos /* QP methods */
294 1.1 christos static void
295 1.1 christos qp_attach(void *uctx, void *pval, uint32_t ival);
296 1.1 christos static void
297 1.1 christos qp_detach(void *uctx, void *pval, uint32_t ival);
298 1.1 christos static size_t
299 1.1 christos qp_makekey(dns_qpkey_t key, void *uctx, void *pval, uint32_t ival);
300 1.1 christos static void
301 1.1 christos qp_triename(void *uctx, char *buf, size_t size);
302 1.1 christos
303 1.1 christos static dns_qpmethods_t qpmethods = {
304 1.1 christos qp_attach,
305 1.1 christos qp_detach,
306 1.1 christos qp_makekey,
307 1.1 christos qp_triename,
308 1.1 christos };
309 1.1 christos
310 1.1 christos static void
311 1.1 christos qp_attach(void *uctx ISC_ATTR_UNUSED, void *pval,
312 1.1 christos uint32_t ival ISC_ATTR_UNUSED) {
313 1.1 christos qpcnode_t *data = pval;
314 1.1 christos qpcnode_ref(data);
315 1.1 christos }
316 1.1 christos
317 1.1 christos static void
318 1.1 christos qp_detach(void *uctx ISC_ATTR_UNUSED, void *pval,
319 1.1 christos uint32_t ival ISC_ATTR_UNUSED) {
320 1.1 christos qpcnode_t *data = pval;
321 1.1 christos qpcnode_detach(&data);
322 1.1 christos }
323 1.1 christos
324 1.1 christos static size_t
325 1.1 christos qp_makekey(dns_qpkey_t key, void *uctx ISC_ATTR_UNUSED, void *pval,
326 1.1 christos uint32_t ival ISC_ATTR_UNUSED) {
327 1.1 christos qpcnode_t *data = pval;
328 1.1 christos return dns_qpkey_fromname(key, &data->name);
329 1.1 christos }
330 1.1 christos
331 1.1 christos static void
332 1.1 christos qp_triename(void *uctx, char *buf, size_t size) {
333 1.1 christos UNUSED(uctx);
334 1.1 christos snprintf(buf, size, "qpdb-lite");
335 1.1 christos }
336 1.1 christos
337 1.1 christos static void
338 1.1 christos rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp DNS__DB_FLARG);
339 1.1 christos static isc_result_t
340 1.1 christos rdatasetiter_first(dns_rdatasetiter_t *iterator DNS__DB_FLARG);
341 1.1 christos static isc_result_t
342 1.1 christos rdatasetiter_next(dns_rdatasetiter_t *iterator DNS__DB_FLARG);
343 1.1 christos static void
344 1.1 christos rdatasetiter_current(dns_rdatasetiter_t *iterator,
345 1.1 christos dns_rdataset_t *rdataset DNS__DB_FLARG);
346 1.1 christos
347 1.1 christos static dns_rdatasetitermethods_t rdatasetiter_methods = {
348 1.1 christos rdatasetiter_destroy, rdatasetiter_first, rdatasetiter_next,
349 1.1 christos rdatasetiter_current
350 1.1 christos };
351 1.1 christos
352 1.1 christos typedef struct qpc_rditer {
353 1.1 christos dns_rdatasetiter_t common;
354 1.1 christos dns_slabheader_t *current;
355 1.1 christos } qpc_rditer_t;
356 1.1 christos
357 1.1 christos static void
358 1.1 christos dbiterator_destroy(dns_dbiterator_t **iteratorp DNS__DB_FLARG);
359 1.1 christos static isc_result_t
360 1.1 christos dbiterator_first(dns_dbiterator_t *iterator DNS__DB_FLARG);
361 1.1 christos static isc_result_t
362 1.1 christos dbiterator_last(dns_dbiterator_t *iterator DNS__DB_FLARG);
363 1.1 christos static isc_result_t
364 1.1 christos dbiterator_seek(dns_dbiterator_t *iterator,
365 1.1 christos const dns_name_t *name DNS__DB_FLARG);
366 1.1 christos static isc_result_t
367 1.1 christos dbiterator_prev(dns_dbiterator_t *iterator DNS__DB_FLARG);
368 1.1 christos static isc_result_t
369 1.1 christos dbiterator_next(dns_dbiterator_t *iterator DNS__DB_FLARG);
370 1.1 christos static isc_result_t
371 1.1 christos dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
372 1.1 christos dns_name_t *name DNS__DB_FLARG);
373 1.1 christos static isc_result_t
374 1.1 christos dbiterator_pause(dns_dbiterator_t *iterator);
375 1.1 christos static isc_result_t
376 1.1 christos dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name);
377 1.1 christos
378 1.1 christos static dns_dbiteratormethods_t dbiterator_methods = {
379 1.1 christos dbiterator_destroy, dbiterator_first, dbiterator_last,
380 1.1 christos dbiterator_seek, dbiterator_prev, dbiterator_next,
381 1.1 christos dbiterator_current, dbiterator_pause, dbiterator_origin
382 1.1 christos };
383 1.1 christos
384 1.1 christos /*
385 1.1 christos * Note that the QP cache database only needs a single QP iterator, because
386 1.1 christos * unlike the QP zone database, NSEC3 records are cached in the main tree.
387 1.1 christos *
388 1.1 christos * If we ever implement synth-from-dnssec using NSEC3 records, we'll need
389 1.1 christos * to have a separate tree for NSEC3 records, and to copy in the more complex
390 1.1 christos * iterator implementation from qpzone.c.
391 1.1 christos */
392 1.1 christos typedef struct qpc_dbit {
393 1.1 christos dns_dbiterator_t common;
394 1.1 christos bool paused;
395 1.1 christos isc_rwlocktype_t tree_locked;
396 1.1 christos isc_result_t result;
397 1.1 christos dns_fixedname_t fixed;
398 1.1 christos dns_name_t *name;
399 1.1 christos dns_qpiter_t iter;
400 1.1 christos qpcnode_t *node;
401 1.1 christos } qpc_dbit_t;
402 1.1 christos
403 1.1 christos static void
404 1.1 christos free_qpdb(qpcache_t *qpdb, bool log);
405 1.1 christos
406 1.1 christos static dns_dbmethods_t qpdb_cachemethods;
407 1.1 christos
408 1.1 christos /*%
409 1.1 christos * 'init_count' is used to initialize 'newheader->count' which in turn
410 1.1 christos * is used to determine where in the cycle rrset-order cyclic starts.
411 1.1 christos * We don't lock this as we don't care about simultaneous updates.
412 1.1 christos */
413 1.1 christos static atomic_uint_fast16_t init_count = 0;
414 1.1 christos
415 1.1 christos /*
416 1.1 christos * Locking
417 1.1 christos *
418 1.1 christos * If a routine is going to lock more than one lock in this module, then
419 1.1 christos * the locking must be done in the following order:
420 1.1 christos *
421 1.1 christos * Tree Lock
422 1.1 christos *
423 1.1 christos * Node Lock (Only one from the set may be locked at one time by
424 1.1 christos * any caller)
425 1.1 christos *
426 1.1 christos * Database Lock
427 1.1 christos *
428 1.1 christos * Failure to follow this hierarchy can result in deadlock.
429 1.1 christos */
430 1.1 christos
431 1.1 christos /*%
432 1.1 christos * Routines for LRU-based cache management.
433 1.1 christos */
434 1.1 christos
435 1.1 christos /*%
436 1.1 christos * See if a given cache entry that is being reused needs to be updated
437 1.1 christos * in the LRU-list. From the LRU management point of view, this function is
438 1.1 christos * expected to return true for almost all cases. When used with threads,
439 1.1 christos * however, this may cause a non-negligible performance penalty because a
440 1.1 christos * writer lock will have to be acquired before updating the list.
441 1.1 christos * If DNS_QPDB_LIMITLRUUPDATE is defined to be non 0 at compilation time, this
442 1.1 christos * function returns true if the entry has not been updated for some period of
443 1.1 christos * time. We differentiate the NS or glue address case and the others since
444 1.1 christos * experiments have shown that the former tends to be accessed relatively
445 1.1 christos * infrequently and the cost of cache miss is higher (e.g., a missing NS records
446 1.1 christos * may cause external queries at a higher level zone, involving more
447 1.1 christos * transactions).
448 1.1 christos *
449 1.1 christos * Caller must hold the node (read or write) lock.
450 1.1 christos */
451 1.1 christos static bool
452 1.1 christos need_headerupdate(dns_slabheader_t *header, isc_stdtime_t now) {
453 1.1 christos if (DNS_SLABHEADER_GETATTR(header, (DNS_SLABHEADERATTR_NONEXISTENT |
454 1.1 christos DNS_SLABHEADERATTR_ANCIENT |
455 1.1 christos DNS_SLABHEADERATTR_ZEROTTL)) != 0)
456 1.1 christos {
457 1.1 christos return false;
458 1.1 christos }
459 1.1 christos
460 1.1 christos #if DNS_QPDB_LIMITLRUUPDATE
461 1.1 christos if (header->type == dns_rdatatype_ns ||
462 1.1 christos (header->trust == dns_trust_glue &&
463 1.1 christos (header->type == dns_rdatatype_a ||
464 1.1 christos header->type == dns_rdatatype_aaaa)))
465 1.1 christos {
466 1.1 christos /*
467 1.1 christos * Glue records are updated if at least DNS_QPDB_LRUUPDATE_GLUE
468 1.1 christos * seconds have passed since the previous update time.
469 1.1 christos */
470 1.1 christos return header->last_used + DNS_QPDB_LRUUPDATE_GLUE <= now;
471 1.1 christos }
472 1.1 christos
473 1.1 christos /*
474 1.1 christos * Other records are updated if DNS_QPDB_LRUUPDATE_REGULAR seconds
475 1.1 christos * have passed.
476 1.1 christos */
477 1.1 christos return header->last_used + DNS_QPDB_LRUUPDATE_REGULAR <= now;
478 1.1 christos #else
479 1.1 christos UNUSED(now);
480 1.1 christos
481 1.1 christos return true;
482 1.1 christos #endif /* if DNS_QPDB_LIMITLRUUPDATE */
483 1.1 christos }
484 1.1 christos
485 1.1 christos /*%
486 1.1 christos * Update the timestamp of a given cache entry and move it to the head
487 1.1 christos * of the corresponding LRU list.
488 1.1 christos *
489 1.1 christos * Caller must hold the node (write) lock.
490 1.1 christos *
491 1.1 christos * Note that the we do NOT touch the heap here, as the TTL has not changed.
492 1.1 christos */
493 1.1 christos static void
494 1.1 christos update_header(qpcache_t *qpdb, dns_slabheader_t *header, isc_stdtime_t now) {
495 1.1 christos /* To be checked: can we really assume this? XXXMLG */
496 1.1 christos INSIST(ISC_LINK_LINKED(header, link));
497 1.1 christos
498 1.1 christos ISC_LIST_UNLINK(qpdb->lru[HEADERNODE(header)->locknum], header, link);
499 1.1 christos header->last_used = now;
500 1.1 christos ISC_LIST_PREPEND(qpdb->lru[HEADERNODE(header)->locknum], header, link);
501 1.1 christos }
502 1.1 christos
503 1.1 christos /*
504 1.1 christos * Locking:
505 1.1 christos * If a routine is going to lock more than one lock in this module, then
506 1.1 christos * the locking must be done in the following order:
507 1.1 christos *
508 1.1 christos * Tree Lock
509 1.1 christos *
510 1.1 christos * Node Lock (Only one from the set may be locked at one time by
511 1.1 christos * any caller)
512 1.1 christos *
513 1.1 christos * Database Lock
514 1.1 christos *
515 1.1 christos * Failure to follow this hierarchy can result in deadlock.
516 1.1 christos *
517 1.1 christos * Deleting Nodes:
518 1.1 christos * For zone databases the node for the origin of the zone MUST NOT be deleted.
519 1.1 christos */
520 1.1 christos
521 1.1 christos /*
522 1.1 christos * DB Routines
523 1.1 christos */
524 1.1 christos
525 1.1 christos static void
526 1.1 christos clean_stale_headers(dns_slabheader_t *top) {
527 1.1 christos dns_slabheader_t *d = NULL, *down_next = NULL;
528 1.1 christos
529 1.1 christos for (d = top->down; d != NULL; d = down_next) {
530 1.1 christos down_next = d->down;
531 1.1 christos dns_slabheader_destroy(&d);
532 1.1 christos }
533 1.1 christos top->down = NULL;
534 1.1 christos }
535 1.1 christos
536 1.1 christos static void
537 1.1 christos clean_cache_node(qpcache_t *qpdb, qpcnode_t *node) {
538 1.1 christos dns_slabheader_t *current = NULL, *top_prev = NULL, *top_next = NULL;
539 1.1 christos
540 1.1 christos /*
541 1.1 christos * Caller must be holding the node lock.
542 1.1 christos */
543 1.1 christos
544 1.1 christos for (current = node->data; current != NULL; current = top_next) {
545 1.1 christos top_next = current->next;
546 1.1 christos clean_stale_headers(current);
547 1.1 christos /*
548 1.1 christos * If current is nonexistent, ancient, or stale and
549 1.1 christos * we are not keeping stale, we can clean it up.
550 1.1 christos */
551 1.1 christos if (NONEXISTENT(current) || ANCIENT(current) ||
552 1.1 christos (STALE(current) && !KEEPSTALE(qpdb)))
553 1.1 christos {
554 1.1 christos if (top_prev != NULL) {
555 1.1 christos top_prev->next = current->next;
556 1.1 christos } else {
557 1.1 christos node->data = current->next;
558 1.1 christos }
559 1.1 christos dns_slabheader_destroy(¤t);
560 1.1 christos } else {
561 1.1 christos top_prev = current;
562 1.1 christos }
563 1.1 christos }
564 1.1 christos node->dirty = 0;
565 1.1 christos }
566 1.1 christos
567 1.1 christos /*
568 1.1 christos * tree_lock(write) must be held.
569 1.1 christos */
570 1.1 christos static void
571 1.1 christos delete_node(qpcache_t *qpdb, qpcnode_t *node) {
572 1.1 christos isc_result_t result = ISC_R_UNEXPECTED;
573 1.1 christos
574 1.1 christos if (isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(1))) {
575 1.1 christos char printname[DNS_NAME_FORMATSIZE];
576 1.1 christos dns_name_format(&node->name, printname, sizeof(printname));
577 1.1 christos isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
578 1.1 christos DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
579 1.1 christos "delete_node(): %p %s (bucket %d)", node,
580 1.1 christos printname, node->locknum);
581 1.1 christos }
582 1.1 christos
583 1.1 christos switch (node->nsec) {
584 1.1 christos case DNS_DB_NSEC_HAS_NSEC:
585 1.1 christos /*
586 1.1 christos * Delete the corresponding node from the auxiliary NSEC
587 1.1 christos * tree before deleting from the main tree.
588 1.1 christos */
589 1.1 christos result = dns_qp_deletename(qpdb->nsec, &node->name, NULL, NULL);
590 1.1 christos if (result != ISC_R_SUCCESS) {
591 1.1 christos isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
592 1.1 christos DNS_LOGMODULE_CACHE, ISC_LOG_WARNING,
593 1.1 christos "delete_node(): "
594 1.1 christos "dns_qp_deletename: %s",
595 1.1 christos isc_result_totext(result));
596 1.1 christos }
597 1.1 christos /* FALLTHROUGH */
598 1.1 christos case DNS_DB_NSEC_NORMAL:
599 1.1 christos result = dns_qp_deletename(qpdb->tree, &node->name, NULL, NULL);
600 1.1 christos break;
601 1.1 christos case DNS_DB_NSEC_NSEC:
602 1.1 christos result = dns_qp_deletename(qpdb->nsec, &node->name, NULL, NULL);
603 1.1 christos break;
604 1.1 christos }
605 1.1 christos if (result != ISC_R_SUCCESS) {
606 1.1 christos isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
607 1.1 christos DNS_LOGMODULE_CACHE, ISC_LOG_WARNING,
608 1.1 christos "delete_node(): "
609 1.1 christos "dns_qp_deletename: %s",
610 1.1 christos isc_result_totext(result));
611 1.1 christos }
612 1.1 christos }
613 1.1 christos
614 1.1 christos /*
615 1.1 christos * The caller must specify its currect node and tree lock status.
616 1.1 christos * It's okay for neither lock to be held if there are existing external
617 1.1 christos * references to the node, but if this is the first external reference,
618 1.1 christos * then the caller must be holding at least one lock.
619 1.1 christos */
620 1.1 christos static void
621 1.1 christos newref(qpcache_t *qpdb, qpcnode_t *node, isc_rwlocktype_t nlocktype,
622 1.1 christos isc_rwlocktype_t tlocktype DNS__DB_FLARG) {
623 1.1 christos uint_fast32_t refs;
624 1.1 christos
625 1.1 christos qpcnode_ref(node);
626 1.1 christos refs = isc_refcount_increment0(&node->erefs);
627 1.1 christos
628 1.1 christos #if DNS_DB_NODETRACE
629 1.1 christos fprintf(stderr, "incr:node:%s:%s:%u:%p->erefs = %" PRIuFAST32 "\n",
630 1.1 christos func, file, line, node, refs + 1);
631 1.1 christos #endif
632 1.1 christos
633 1.1 christos if (refs == 0) {
634 1.1 christos /*
635 1.1 christos * this is the first external reference to the node.
636 1.1 christos *
637 1.1 christos * we need to hold the node or tree lock to avoid
638 1.1 christos * incrementing the reference count while also deleting
639 1.1 christos * the node. delete_node() is always protected by both
640 1.1 christos * tree and node locks being write-locked.
641 1.1 christos */
642 1.1 christos INSIST(nlocktype != isc_rwlocktype_none ||
643 1.1 christos tlocktype != isc_rwlocktype_none);
644 1.1 christos
645 1.1 christos refs = isc_refcount_increment0(
646 1.1 christos &qpdb->node_locks[node->locknum].references);
647 1.1 christos #if DNS_DB_NODETRACE
648 1.1 christos fprintf(stderr,
649 1.1 christos "incr:nodelock:%s:%s:%u:%p:%p->references = "
650 1.1 christos "%" PRIuFAST32 "\n",
651 1.1 christos func, file, line, node,
652 1.1 christos &qpdb->node_locks[node->locknum], refs + 1);
653 1.1 christos #else
654 1.1 christos UNUSED(refs);
655 1.1 christos #endif
656 1.1 christos }
657 1.1 christos }
658 1.1 christos
659 1.1 christos static void
660 1.1 christos cleanup_deadnodes(void *arg);
661 1.1 christos
662 1.1 christos /*
663 1.1 christos * Caller must be holding the node lock; either the read or write lock.
664 1.1 christos * Note that the lock must be held even when node references are
665 1.1 christos * atomically modified; in that case the decrement operation itself does not
666 1.1 christos * have to be protected, but we must avoid a race condition where multiple
667 1.1 christos * threads are decreasing the reference to zero simultaneously and at least
668 1.1 christos * one of them is going to free the node.
669 1.1 christos *
670 1.1 christos * This decrements both the internal and external node reference counters.
671 1.1 christos * If the external reference count drops to zero, then the node lock
672 1.1 christos * reference count is also decremented.
673 1.1 christos *
674 1.1 christos * This function returns true if and only if the node reference decreases
675 1.1 christos * to zero. (NOTE: Decrementing the reference count of a node to zero does
676 1.1 christos * not mean it will be immediately freed.)
677 1.1 christos */
678 1.1 christos static bool
679 1.1 christos decref(qpcache_t *qpdb, qpcnode_t *node, isc_rwlocktype_t *nlocktypep,
680 1.1 christos isc_rwlocktype_t *tlocktypep, bool tryupgrade DNS__DB_FLARG) {
681 1.1 christos isc_result_t result;
682 1.1 christos bool locked = *tlocktypep != isc_rwlocktype_none;
683 1.1 christos bool write_locked = false;
684 1.1 christos db_nodelock_t *nodelock = NULL;
685 1.1 christos int bucket = node->locknum;
686 1.1 christos uint_fast32_t refs;
687 1.1 christos
688 1.1 christos REQUIRE(*nlocktypep != isc_rwlocktype_none);
689 1.1 christos
690 1.1 christos nodelock = &qpdb->node_locks[bucket];
691 1.1 christos
692 1.1 christos #define KEEP_NODE(n, r) ((n)->data != NULL || (n) == (r)->origin_node)
693 1.1 christos
694 1.1 christos /* Handle easy and typical case first. */
695 1.1 christos if (!node->dirty && KEEP_NODE(node, qpdb)) {
696 1.1 christos bool no_reference = false;
697 1.1 christos
698 1.1 christos refs = isc_refcount_decrement(&node->erefs);
699 1.1 christos #if DNS_DB_NODETRACE
700 1.1 christos fprintf(stderr,
701 1.1 christos "decr:node:%s:%s:%u:%p->erefs = %" PRIuFAST32 "\n",
702 1.1 christos func, file, line, node, refs - 1);
703 1.1 christos #else
704 1.1 christos UNUSED(refs);
705 1.1 christos #endif
706 1.1 christos if (refs == 1) {
707 1.1 christos refs = isc_refcount_decrement(&nodelock->references);
708 1.1 christos #if DNS_DB_NODETRACE
709 1.1 christos fprintf(stderr,
710 1.1 christos "decr:nodelock:%s:%s:%u:%p:%p->references = "
711 1.1 christos "%" PRIuFAST32 "\n",
712 1.1 christos func, file, line, node, nodelock, refs - 1);
713 1.1 christos #else
714 1.1 christos UNUSED(refs);
715 1.1 christos #endif
716 1.1 christos no_reference = true;
717 1.1 christos }
718 1.1 christos
719 1.1 christos qpcnode_unref(node);
720 1.1 christos return no_reference;
721 1.1 christos }
722 1.1 christos
723 1.1 christos /* Upgrade the lock? */
724 1.1 christos if (*nlocktypep == isc_rwlocktype_read) {
725 1.1 christos NODE_FORCEUPGRADE(&nodelock->lock, nlocktypep);
726 1.1 christos }
727 1.1 christos
728 1.1 christos refs = isc_refcount_decrement(&node->erefs);
729 1.1 christos #if DNS_DB_NODETRACE
730 1.1 christos fprintf(stderr, "decr:node:%s:%s:%u:%p->erefs = %" PRIuFAST32 "\n",
731 1.1 christos func, file, line, node, refs - 1);
732 1.1 christos #endif
733 1.1 christos
734 1.1 christos if (refs > 1) {
735 1.1 christos qpcnode_unref(node);
736 1.1 christos return false;
737 1.1 christos }
738 1.1 christos
739 1.1 christos INSIST(refs == 1);
740 1.1 christos
741 1.1 christos if (node->dirty) {
742 1.1 christos clean_cache_node(qpdb, node);
743 1.1 christos }
744 1.1 christos
745 1.1 christos /*
746 1.1 christos * Attempt to switch to a write lock on the tree. If this fails,
747 1.1 christos * we will add this node to a linked list of nodes in this locking
748 1.1 christos * bucket which we will free later.
749 1.1 christos *
750 1.1 christos * Locking hierarchy notwithstanding, we don't need to free
751 1.1 christos * the node lock before acquiring the tree write lock because
752 1.1 christos * we only do a trylock.
753 1.1 christos */
754 1.1 christos /* We are allowed to upgrade the tree lock */
755 1.1 christos
756 1.1 christos switch (*tlocktypep) {
757 1.1 christos case isc_rwlocktype_write:
758 1.1 christos result = ISC_R_SUCCESS;
759 1.1 christos break;
760 1.1 christos case isc_rwlocktype_read:
761 1.1 christos if (tryupgrade) {
762 1.1 christos result = TREE_TRYUPGRADE(&qpdb->tree_lock, tlocktypep);
763 1.1 christos } else {
764 1.1 christos result = ISC_R_LOCKBUSY;
765 1.1 christos }
766 1.1 christos break;
767 1.1 christos case isc_rwlocktype_none:
768 1.1 christos result = TREE_TRYWRLOCK(&qpdb->tree_lock, tlocktypep);
769 1.1 christos break;
770 1.1 christos default:
771 1.1 christos UNREACHABLE();
772 1.1 christos }
773 1.1 christos RUNTIME_CHECK(result == ISC_R_SUCCESS || result == ISC_R_LOCKBUSY);
774 1.1 christos if (result == ISC_R_SUCCESS) {
775 1.1 christos write_locked = true;
776 1.1 christos }
777 1.1 christos
778 1.1 christos refs = isc_refcount_decrement(&nodelock->references);
779 1.1 christos #if DNS_DB_NODETRACE
780 1.1 christos fprintf(stderr,
781 1.1 christos "decr:nodelock:%s:%s:%u:%p:%p->references = %" PRIuFAST32 "\n",
782 1.1 christos func, file, line, node, nodelock, refs - 1);
783 1.1 christos #else
784 1.1 christos UNUSED(refs);
785 1.1 christos #endif
786 1.1 christos
787 1.1 christos if (KEEP_NODE(node, qpdb)) {
788 1.1 christos goto restore_locks;
789 1.1 christos }
790 1.1 christos
791 1.1 christos #undef KEEP_NODE
792 1.1 christos
793 1.1 christos if (write_locked) {
794 1.1 christos /*
795 1.1 christos * We can now delete the node.
796 1.1 christos */
797 1.1 christos delete_node(qpdb, node);
798 1.1 christos } else {
799 1.1 christos newref(qpdb, node, *nlocktypep, *tlocktypep DNS__DB_FLARG_PASS);
800 1.1 christos
801 1.1 christos isc_queue_node_init(&node->deadlink);
802 1.1 christos if (!isc_queue_enqueue_entry(&qpdb->deadnodes[bucket], node,
803 1.1 christos deadlink))
804 1.1 christos {
805 1.1 christos /* Queue was empty, trigger new cleaning */
806 1.1 christos isc_loop_t *loop = isc_loop_get(qpdb->loopmgr, bucket);
807 1.1 christos
808 1.1 christos isc_async_run(loop, cleanup_deadnodes, qpdb);
809 1.1 christos }
810 1.1 christos }
811 1.1 christos
812 1.1 christos restore_locks:
813 1.1 christos /*
814 1.1 christos * Relock a read lock, or unlock the write lock if no lock was held.
815 1.1 christos */
816 1.1 christos if (!locked && write_locked) {
817 1.1 christos TREE_UNLOCK(&qpdb->tree_lock, tlocktypep);
818 1.1 christos }
819 1.1 christos
820 1.1 christos qpcnode_unref(node);
821 1.1 christos return true;
822 1.1 christos }
823 1.1 christos
824 1.1 christos static void
825 1.1 christos update_rrsetstats(dns_stats_t *stats, const dns_typepair_t htype,
826 1.1 christos const uint_least16_t hattributes, const bool increment) {
827 1.1 christos dns_rdatastatstype_t statattributes = 0;
828 1.1 christos dns_rdatastatstype_t base = 0;
829 1.1 christos dns_rdatastatstype_t type;
830 1.1 christos dns_slabheader_t *header = &(dns_slabheader_t){
831 1.1 christos .type = htype,
832 1.1 christos .attributes = hattributes,
833 1.1 christos };
834 1.1 christos
835 1.1 christos if (!EXISTS(header) || !STATCOUNT(header)) {
836 1.1 christos return;
837 1.1 christos }
838 1.1 christos
839 1.1 christos if (NEGATIVE(header)) {
840 1.1 christos if (NXDOMAIN(header)) {
841 1.1 christos statattributes = DNS_RDATASTATSTYPE_ATTR_NXDOMAIN;
842 1.1 christos } else {
843 1.1 christos statattributes = DNS_RDATASTATSTYPE_ATTR_NXRRSET;
844 1.1 christos base = DNS_TYPEPAIR_COVERS(header->type);
845 1.1 christos }
846 1.1 christos } else {
847 1.1 christos base = DNS_TYPEPAIR_TYPE(header->type);
848 1.1 christos }
849 1.1 christos
850 1.1 christos if (STALE(header)) {
851 1.1 christos statattributes |= DNS_RDATASTATSTYPE_ATTR_STALE;
852 1.1 christos }
853 1.1 christos if (ANCIENT(header)) {
854 1.1 christos statattributes |= DNS_RDATASTATSTYPE_ATTR_ANCIENT;
855 1.1 christos }
856 1.1 christos
857 1.1 christos type = DNS_RDATASTATSTYPE_VALUE(base, statattributes);
858 1.1 christos if (increment) {
859 1.1 christos dns_rdatasetstats_increment(stats, type);
860 1.1 christos } else {
861 1.1 christos dns_rdatasetstats_decrement(stats, type);
862 1.1 christos }
863 1.1 christos }
864 1.1 christos
865 1.1 christos static void
866 1.1 christos mark(dns_slabheader_t *header, uint_least16_t flag) {
867 1.1 christos uint_least16_t attributes = atomic_load_acquire(&header->attributes);
868 1.1 christos uint_least16_t newattributes = 0;
869 1.1 christos dns_stats_t *stats = NULL;
870 1.1 christos
871 1.1 christos /*
872 1.1 christos * If we are already ancient there is nothing to do.
873 1.1 christos */
874 1.1 christos do {
875 1.1 christos if ((attributes & flag) != 0) {
876 1.1 christos return;
877 1.1 christos }
878 1.1 christos newattributes = attributes | flag;
879 1.1 christos } while (!atomic_compare_exchange_weak_acq_rel(
880 1.1 christos &header->attributes, &attributes, newattributes));
881 1.1 christos
882 1.1 christos /*
883 1.1 christos * Decrement and increment the stats counter for the appropriate
884 1.1 christos * RRtype.
885 1.1 christos */
886 1.1 christos stats = dns_db_getrrsetstats(header->db);
887 1.1 christos if (stats != NULL) {
888 1.1 christos update_rrsetstats(stats, header->type, attributes, false);
889 1.1 christos update_rrsetstats(stats, header->type, newattributes, true);
890 1.1 christos }
891 1.1 christos }
892 1.1 christos
893 1.1 christos static void
894 1.1 christos setttl(dns_slabheader_t *header, dns_ttl_t newttl) {
895 1.1 christos dns_ttl_t oldttl = header->ttl;
896 1.1 christos
897 1.1 christos header->ttl = newttl;
898 1.1 christos
899 1.1 christos if (header->db == NULL || !dns_db_iscache(header->db)) {
900 1.1 christos return;
901 1.1 christos }
902 1.1 christos
903 1.1 christos /*
904 1.1 christos * This is a cache. Adjust the heaps if necessary.
905 1.1 christos */
906 1.1 christos if (header->heap == NULL || header->heap_index == 0 || newttl == oldttl)
907 1.1 christos {
908 1.1 christos return;
909 1.1 christos }
910 1.1 christos
911 1.1 christos if (newttl < oldttl) {
912 1.1 christos isc_heap_increased(header->heap, header->heap_index);
913 1.1 christos } else {
914 1.1 christos isc_heap_decreased(header->heap, header->heap_index);
915 1.1 christos }
916 1.1 christos
917 1.1 christos if (newttl == 0) {
918 1.1 christos isc_heap_delete(header->heap, header->heap_index);
919 1.1 christos }
920 1.1 christos }
921 1.1 christos
922 1.1 christos /*
923 1.1 christos * Caller must hold the node (write) lock.
924 1.1 christos */
925 1.1 christos static void
926 1.1 christos expireheader(dns_slabheader_t *header, isc_rwlocktype_t *nlocktypep,
927 1.1 christos isc_rwlocktype_t *tlocktypep, dns_expire_t reason DNS__DB_FLARG) {
928 1.1 christos setttl(header, 0);
929 1.1 christos mark(header, DNS_SLABHEADERATTR_ANCIENT);
930 1.1 christos HEADERNODE(header)->dirty = 1;
931 1.1 christos
932 1.1 christos if (isc_refcount_current(&HEADERNODE(header)->erefs) == 0) {
933 1.1 christos qpcache_t *qpdb = (qpcache_t *)header->db;
934 1.1 christos
935 1.1 christos /*
936 1.1 christos * If no one else is using the node, we can clean it up now.
937 1.1 christos * We first need to gain a new reference to the node to meet a
938 1.1 christos * requirement of decref().
939 1.1 christos */
940 1.1 christos newref(qpdb, HEADERNODE(header), *nlocktypep,
941 1.1 christos *tlocktypep DNS__DB_FLARG_PASS);
942 1.1 christos decref(qpdb, HEADERNODE(header), nlocktypep, tlocktypep,
943 1.1 christos true DNS__DB_FLARG_PASS);
944 1.1 christos
945 1.1 christos if (qpdb->cachestats == NULL) {
946 1.1 christos return;
947 1.1 christos }
948 1.1 christos
949 1.1 christos switch (reason) {
950 1.1 christos case dns_expire_ttl:
951 1.1 christos isc_stats_increment(qpdb->cachestats,
952 1.1 christos dns_cachestatscounter_deletettl);
953 1.1 christos break;
954 1.1 christos case dns_expire_lru:
955 1.1 christos isc_stats_increment(qpdb->cachestats,
956 1.1 christos dns_cachestatscounter_deletelru);
957 1.1 christos break;
958 1.1 christos default:
959 1.1 christos break;
960 1.1 christos }
961 1.1 christos }
962 1.1 christos }
963 1.1 christos
964 1.1 christos static void
965 1.1 christos update_cachestats(qpcache_t *qpdb, isc_result_t result) {
966 1.1 christos if (qpdb->cachestats == NULL) {
967 1.1 christos return;
968 1.1 christos }
969 1.1 christos
970 1.1 christos switch (result) {
971 1.1 christos case DNS_R_COVERINGNSEC:
972 1.1 christos isc_stats_increment(qpdb->cachestats,
973 1.1 christos dns_cachestatscounter_coveringnsec);
974 1.1 christos FALLTHROUGH;
975 1.1 christos case ISC_R_SUCCESS:
976 1.1 christos case DNS_R_CNAME:
977 1.1 christos case DNS_R_DNAME:
978 1.1 christos case DNS_R_DELEGATION:
979 1.1 christos case DNS_R_NCACHENXDOMAIN:
980 1.1 christos case DNS_R_NCACHENXRRSET:
981 1.1 christos isc_stats_increment(qpdb->cachestats,
982 1.1 christos dns_cachestatscounter_hits);
983 1.1 christos break;
984 1.1 christos default:
985 1.1 christos isc_stats_increment(qpdb->cachestats,
986 1.1 christos dns_cachestatscounter_misses);
987 1.1 christos }
988 1.1 christos }
989 1.1 christos
990 1.1 christos static void
991 1.1 christos bindrdataset(qpcache_t *qpdb, qpcnode_t *node, dns_slabheader_t *header,
992 1.1 christos isc_stdtime_t now, isc_rwlocktype_t nlocktype,
993 1.1 christos isc_rwlocktype_t tlocktype,
994 1.1 christos dns_rdataset_t *rdataset DNS__DB_FLARG) {
995 1.1 christos bool stale = STALE(header);
996 1.1 christos bool ancient = ANCIENT(header);
997 1.1 christos
998 1.1 christos /*
999 1.1 christos * Caller must be holding the node reader lock.
1000 1.1 christos * XXXJT: technically, we need a writer lock, since we'll increment
1001 1.1 christos * the header count below. However, since the actual counter value
1002 1.1 christos * doesn't matter, we prioritize performance here. (We may want to
1003 1.1 christos * use atomic increment when available).
1004 1.1 christos */
1005 1.1 christos
1006 1.1 christos if (rdataset == NULL) {
1007 1.1 christos return;
1008 1.1 christos }
1009 1.1 christos
1010 1.1 christos newref(qpdb, node, nlocktype, tlocktype DNS__DB_FLARG_PASS);
1011 1.1 christos
1012 1.1 christos INSIST(rdataset->methods == NULL); /* We must be disassociated. */
1013 1.1 christos
1014 1.1 christos /*
1015 1.1 christos * Mark header stale or ancient if the RRset is no longer active.
1016 1.1 christos */
1017 1.1 christos if (!ACTIVE(header, now)) {
1018 1.1 christos dns_ttl_t stale_ttl = header->ttl + STALE_TTL(header, qpdb);
1019 1.1 christos /*
1020 1.1 christos * If this data is in the stale window keep it and if
1021 1.1 christos * DNS_DBFIND_STALEOK is not set we tell the caller to
1022 1.1 christos * skip this record. We skip the records with ZEROTTL
1023 1.1 christos * (these records should not be cached anyway).
1024 1.1 christos */
1025 1.1 christos
1026 1.1 christos if (KEEPSTALE(qpdb) && stale_ttl > now) {
1027 1.1 christos stale = true;
1028 1.1 christos } else {
1029 1.1 christos /*
1030 1.1 christos * We are not keeping stale, or it is outside the
1031 1.1 christos * stale window. Mark ancient, i.e. ready for cleanup.
1032 1.1 christos */
1033 1.1 christos ancient = true;
1034 1.1 christos }
1035 1.1 christos }
1036 1.1 christos
1037 1.1 christos rdataset->methods = &dns_rdataslab_rdatasetmethods;
1038 1.1 christos rdataset->rdclass = qpdb->common.rdclass;
1039 1.1 christos rdataset->type = DNS_TYPEPAIR_TYPE(header->type);
1040 1.1 christos rdataset->covers = DNS_TYPEPAIR_COVERS(header->type);
1041 1.1 christos rdataset->ttl = header->ttl - now;
1042 1.1 christos rdataset->trust = header->trust;
1043 1.1 christos rdataset->resign = 0;
1044 1.1 christos
1045 1.1 christos if (NEGATIVE(header)) {
1046 1.1 christos rdataset->attributes |= DNS_RDATASETATTR_NEGATIVE;
1047 1.1 christos }
1048 1.1 christos if (NXDOMAIN(header)) {
1049 1.1 christos rdataset->attributes |= DNS_RDATASETATTR_NXDOMAIN;
1050 1.1 christos }
1051 1.1 christos if (OPTOUT(header)) {
1052 1.1 christos rdataset->attributes |= DNS_RDATASETATTR_OPTOUT;
1053 1.1 christos }
1054 1.1 christos if (PREFETCH(header)) {
1055 1.1 christos rdataset->attributes |= DNS_RDATASETATTR_PREFETCH;
1056 1.1 christos }
1057 1.1 christos
1058 1.1 christos if (stale && !ancient) {
1059 1.1 christos dns_ttl_t stale_ttl = header->ttl + STALE_TTL(header, qpdb);
1060 1.1 christos if (stale_ttl > now) {
1061 1.1 christos rdataset->ttl = stale_ttl - now;
1062 1.1 christos } else {
1063 1.1 christos rdataset->ttl = 0;
1064 1.1 christos }
1065 1.1 christos if (STALE_WINDOW(header)) {
1066 1.1 christos rdataset->attributes |= DNS_RDATASETATTR_STALE_WINDOW;
1067 1.1 christos }
1068 1.1 christos rdataset->attributes |= DNS_RDATASETATTR_STALE;
1069 1.1 christos } else if (!ACTIVE(header, now)) {
1070 1.1 christos rdataset->attributes |= DNS_RDATASETATTR_ANCIENT;
1071 1.1 christos rdataset->ttl = header->ttl;
1072 1.1 christos }
1073 1.1 christos
1074 1.1 christos rdataset->count = atomic_fetch_add_relaxed(&header->count, 1);
1075 1.1 christos
1076 1.1 christos rdataset->slab.db = (dns_db_t *)qpdb;
1077 1.1 christos rdataset->slab.node = (dns_dbnode_t *)node;
1078 1.1 christos rdataset->slab.raw = dns_slabheader_raw(header);
1079 1.1 christos rdataset->slab.iter_pos = NULL;
1080 1.1 christos rdataset->slab.iter_count = 0;
1081 1.1 christos
1082 1.1 christos /*
1083 1.1 christos * Add noqname proof.
1084 1.1 christos */
1085 1.1 christos rdataset->slab.noqname = header->noqname;
1086 1.1 christos if (header->noqname != NULL) {
1087 1.1 christos rdataset->attributes |= DNS_RDATASETATTR_NOQNAME;
1088 1.1 christos }
1089 1.1 christos rdataset->slab.closest = header->closest;
1090 1.1 christos if (header->closest != NULL) {
1091 1.1 christos rdataset->attributes |= DNS_RDATASETATTR_CLOSEST;
1092 1.1 christos }
1093 1.1 christos }
1094 1.1 christos
1095 1.1 christos static isc_result_t
1096 1.1 christos setup_delegation(qpc_search_t *search, dns_dbnode_t **nodep,
1097 1.1 christos dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
1098 1.1 christos isc_rwlocktype_t tlocktype DNS__DB_FLARG) {
1099 1.1 christos dns_typepair_t type;
1100 1.1 christos qpcnode_t *node = NULL;
1101 1.1 christos
1102 1.1 christos REQUIRE(search != NULL);
1103 1.1 christos REQUIRE(search->zonecut != NULL);
1104 1.1 christos REQUIRE(search->zonecut_header != NULL);
1105 1.1 christos
1106 1.1 christos /*
1107 1.1 christos * The caller MUST NOT be holding any node locks.
1108 1.1 christos */
1109 1.1 christos
1110 1.1 christos node = search->zonecut;
1111 1.1 christos type = search->zonecut_header->type;
1112 1.1 christos
1113 1.1 christos if (nodep != NULL) {
1114 1.1 christos /*
1115 1.1 christos * Note that we don't have to increment the node's reference
1116 1.1 christos * count here because we're going to use the reference we
1117 1.1 christos * already have in the search block.
1118 1.1 christos */
1119 1.1 christos *nodep = node;
1120 1.1 christos search->need_cleanup = false;
1121 1.1 christos }
1122 1.1 christos if (rdataset != NULL) {
1123 1.1 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
1124 1.1 christos NODE_RDLOCK(&(search->qpdb->node_locks[node->locknum].lock),
1125 1.1 christos &nlocktype);
1126 1.1 christos bindrdataset(search->qpdb, node, search->zonecut_header,
1127 1.1 christos search->now, nlocktype, tlocktype,
1128 1.1 christos rdataset DNS__DB_FLARG_PASS);
1129 1.1 christos if (sigrdataset != NULL && search->zonecut_sigheader != NULL) {
1130 1.1 christos bindrdataset(search->qpdb, node,
1131 1.1 christos search->zonecut_sigheader, search->now,
1132 1.1 christos nlocktype, tlocktype,
1133 1.1 christos sigrdataset DNS__DB_FLARG_PASS);
1134 1.1 christos }
1135 1.1 christos NODE_UNLOCK(&(search->qpdb->node_locks[node->locknum].lock),
1136 1.1 christos &nlocktype);
1137 1.1 christos }
1138 1.1 christos
1139 1.1 christos if (type == dns_rdatatype_dname) {
1140 1.1 christos return DNS_R_DNAME;
1141 1.1 christos }
1142 1.1 christos return DNS_R_DELEGATION;
1143 1.1 christos }
1144 1.1 christos
1145 1.1 christos static bool
1146 1.1 christos check_stale_header(qpcnode_t *node, dns_slabheader_t *header,
1147 1.1 christos isc_rwlocktype_t *nlocktypep, isc_rwlock_t *lock,
1148 1.1 christos qpc_search_t *search, dns_slabheader_t **header_prev) {
1149 1.1 christos if (!ACTIVE(header, search->now)) {
1150 1.1 christos dns_ttl_t stale = header->ttl + STALE_TTL(header, search->qpdb);
1151 1.1 christos /*
1152 1.1 christos * If this data is in the stale window keep it and if
1153 1.1 christos * DNS_DBFIND_STALEOK is not set we tell the caller to
1154 1.1 christos * skip this record. We skip the records with ZEROTTL
1155 1.1 christos * (these records should not be cached anyway).
1156 1.1 christos */
1157 1.1 christos
1158 1.1 christos DNS_SLABHEADER_CLRATTR(header, DNS_SLABHEADERATTR_STALE_WINDOW);
1159 1.1 christos if (!ZEROTTL(header) && KEEPSTALE(search->qpdb) &&
1160 1.1 christos stale > search->now)
1161 1.1 christos {
1162 1.1 christos mark(header, DNS_SLABHEADERATTR_STALE);
1163 1.1 christos *header_prev = header;
1164 1.1 christos /*
1165 1.1 christos * If DNS_DBFIND_STALESTART is set then it means we
1166 1.1 christos * failed to resolve the name during recursion, in
1167 1.1 christos * this case we mark the time in which the refresh
1168 1.1 christos * failed.
1169 1.1 christos */
1170 1.1 christos if ((search->options & DNS_DBFIND_STALESTART) != 0) {
1171 1.1 christos atomic_store_release(
1172 1.1 christos &header->last_refresh_fail_ts,
1173 1.1 christos search->now);
1174 1.1 christos } else if ((search->options &
1175 1.1 christos DNS_DBFIND_STALEENABLED) != 0 &&
1176 1.1 christos search->now <
1177 1.1 christos (atomic_load_acquire(
1178 1.1 christos &header->last_refresh_fail_ts) +
1179 1.1 christos search->qpdb->serve_stale_refresh))
1180 1.1 christos {
1181 1.1 christos /*
1182 1.1 christos * If we are within interval between last
1183 1.1 christos * refresh failure time + 'stale-refresh-time',
1184 1.1 christos * then don't skip this stale entry but use it
1185 1.1 christos * instead.
1186 1.1 christos */
1187 1.1 christos DNS_SLABHEADER_SETATTR(
1188 1.1 christos header,
1189 1.1 christos DNS_SLABHEADERATTR_STALE_WINDOW);
1190 1.1 christos return false;
1191 1.1 christos } else if ((search->options &
1192 1.1 christos DNS_DBFIND_STALETIMEOUT) != 0)
1193 1.1 christos {
1194 1.1 christos /*
1195 1.1 christos * We want stale RRset due to timeout, so we
1196 1.1 christos * don't skip it.
1197 1.1 christos */
1198 1.1 christos return false;
1199 1.1 christos }
1200 1.1 christos return (search->options & DNS_DBFIND_STALEOK) == 0;
1201 1.1 christos }
1202 1.1 christos
1203 1.1 christos /*
1204 1.1 christos * This rdataset is stale. If no one else is using the
1205 1.1 christos * node, we can clean it up right now, otherwise we mark
1206 1.1 christos * it as ancient, and the node as dirty, so it will get
1207 1.1 christos * cleaned up later.
1208 1.1 christos */
1209 1.1 christos if ((header->ttl < search->now - QPDB_VIRTUAL) &&
1210 1.1 christos (*nlocktypep == isc_rwlocktype_write ||
1211 1.1 christos NODE_TRYUPGRADE(lock, nlocktypep) == ISC_R_SUCCESS))
1212 1.1 christos {
1213 1.1 christos /*
1214 1.1 christos * We update the node's status only when we can
1215 1.1 christos * get write access; otherwise, we leave others
1216 1.1 christos * to this work. Periodical cleaning will
1217 1.1 christos * eventually take the job as the last resort.
1218 1.1 christos * We won't downgrade the lock, since other
1219 1.1 christos * rdatasets are probably stale, too.
1220 1.1 christos */
1221 1.1 christos
1222 1.1 christos if (isc_refcount_current(&node->references) == 0) {
1223 1.1 christos /*
1224 1.1 christos * header->down can be non-NULL if the
1225 1.1 christos * refcount has just decremented to 0
1226 1.1 christos * but decref() has not
1227 1.1 christos * performed clean_cache_node(), in
1228 1.1 christos * which case we need to purge the stale
1229 1.1 christos * headers first.
1230 1.1 christos */
1231 1.1 christos clean_stale_headers(header);
1232 1.1 christos if (*header_prev != NULL) {
1233 1.1 christos (*header_prev)->next = header->next;
1234 1.1 christos } else {
1235 1.1 christos node->data = header->next;
1236 1.1 christos }
1237 1.1 christos dns_slabheader_destroy(&header);
1238 1.1 christos } else {
1239 1.1 christos mark(header, DNS_SLABHEADERATTR_ANCIENT);
1240 1.1 christos HEADERNODE(header)->dirty = 1;
1241 1.1 christos *header_prev = header;
1242 1.1 christos }
1243 1.1 christos } else {
1244 1.1 christos *header_prev = header;
1245 1.1 christos }
1246 1.1 christos return true;
1247 1.1 christos }
1248 1.1 christos return false;
1249 1.1 christos }
1250 1.1 christos
1251 1.1 christos static isc_result_t
1252 1.1 christos check_zonecut(qpcnode_t *node, void *arg DNS__DB_FLARG) {
1253 1.1 christos qpc_search_t *search = arg;
1254 1.1 christos dns_slabheader_t *header = NULL;
1255 1.1 christos dns_slabheader_t *header_prev = NULL, *header_next = NULL;
1256 1.1 christos dns_slabheader_t *dname_header = NULL, *sigdname_header = NULL;
1257 1.1 christos isc_result_t result;
1258 1.1 christos isc_rwlock_t *lock = NULL;
1259 1.1 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
1260 1.1 christos
1261 1.1 christos REQUIRE(search->zonecut == NULL);
1262 1.1 christos
1263 1.1 christos lock = &(search->qpdb->node_locks[node->locknum].lock);
1264 1.1 christos NODE_RDLOCK(lock, &nlocktype);
1265 1.1 christos
1266 1.1 christos /*
1267 1.1 christos * Look for a DNAME or RRSIG DNAME rdataset.
1268 1.1 christos */
1269 1.1 christos for (header = node->data; header != NULL; header = header_next) {
1270 1.1 christos header_next = header->next;
1271 1.1 christos if (check_stale_header(node, header, &nlocktype, lock, search,
1272 1.1 christos &header_prev))
1273 1.1 christos {
1274 1.1 christos /* Do nothing. */
1275 1.1 christos } else if (header->type == dns_rdatatype_dname &&
1276 1.1 christos EXISTS(header) && !ANCIENT(header))
1277 1.1 christos {
1278 1.1 christos dname_header = header;
1279 1.1 christos header_prev = header;
1280 1.1 christos } else if (header->type == DNS_SIGTYPE(dns_rdatatype_dname) &&
1281 1.1 christos EXISTS(header) && !ANCIENT(header))
1282 1.1 christos {
1283 1.1 christos sigdname_header = header;
1284 1.1 christos header_prev = header;
1285 1.1 christos } else {
1286 1.1 christos header_prev = header;
1287 1.1 christos }
1288 1.1 christos }
1289 1.1 christos
1290 1.1 christos if (dname_header != NULL &&
1291 1.1 christos (!DNS_TRUST_PENDING(dname_header->trust) ||
1292 1.1 christos (search->options & DNS_DBFIND_PENDINGOK) != 0))
1293 1.1 christos {
1294 1.1 christos /*
1295 1.1 christos * We increment the reference count on node to ensure that
1296 1.1 christos * search->zonecut_header will still be valid later.
1297 1.1 christos */
1298 1.1 christos newref(search->qpdb, node, nlocktype,
1299 1.1 christos isc_rwlocktype_none DNS__DB_FLARG_PASS);
1300 1.1 christos search->zonecut = node;
1301 1.1 christos search->zonecut_header = dname_header;
1302 1.1 christos search->zonecut_sigheader = sigdname_header;
1303 1.1 christos search->need_cleanup = true;
1304 1.1 christos result = DNS_R_PARTIALMATCH;
1305 1.1 christos } else {
1306 1.1 christos result = DNS_R_CONTINUE;
1307 1.1 christos }
1308 1.1 christos
1309 1.1 christos NODE_UNLOCK(lock, &nlocktype);
1310 1.1 christos
1311 1.1 christos return result;
1312 1.1 christos }
1313 1.1 christos
1314 1.1 christos static isc_result_t
1315 1.1 christos find_deepest_zonecut(qpc_search_t *search, qpcnode_t *node,
1316 1.1 christos dns_dbnode_t **nodep, dns_name_t *foundname,
1317 1.1 christos dns_rdataset_t *rdataset,
1318 1.1 christos dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
1319 1.1 christos isc_result_t result = ISC_R_NOTFOUND;
1320 1.1 christos qpcache_t *qpdb = NULL;
1321 1.1 christos
1322 1.1 christos /*
1323 1.1 christos * Caller must be holding the tree lock.
1324 1.1 christos */
1325 1.1 christos
1326 1.1 christos qpdb = search->qpdb;
1327 1.1 christos
1328 1.1 christos for (int i = dns_qpchain_length(&search->chain) - 1; i >= 0; i--) {
1329 1.1 christos dns_slabheader_t *header = NULL;
1330 1.1 christos dns_slabheader_t *header_prev = NULL, *header_next = NULL;
1331 1.1 christos dns_slabheader_t *found = NULL, *foundsig = NULL;
1332 1.1 christos isc_rwlock_t *lock = NULL;
1333 1.1 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
1334 1.1 christos
1335 1.1 christos dns_qpchain_node(&search->chain, i, NULL, (void **)&node, NULL);
1336 1.1 christos lock = &qpdb->node_locks[node->locknum].lock;
1337 1.1 christos
1338 1.1 christos NODE_RDLOCK(lock, &nlocktype);
1339 1.1 christos
1340 1.1 christos /*
1341 1.1 christos * Look for NS and RRSIG NS rdatasets.
1342 1.1 christos */
1343 1.1 christos for (header = node->data; header != NULL; header = header_next)
1344 1.1 christos {
1345 1.1 christos header_next = header->next;
1346 1.1 christos if (check_stale_header(node, header, &nlocktype, lock,
1347 1.1 christos search, &header_prev))
1348 1.1 christos {
1349 1.1 christos /* Do nothing. */
1350 1.1 christos } else if (EXISTS(header) && !ANCIENT(header)) {
1351 1.1 christos /*
1352 1.1 christos * We've found an extant rdataset. See if
1353 1.1 christos * we're interested in it.
1354 1.1 christos */
1355 1.1 christos if (header->type == dns_rdatatype_ns) {
1356 1.1 christos found = header;
1357 1.1 christos if (foundsig != NULL) {
1358 1.1 christos break;
1359 1.1 christos }
1360 1.1 christos } else if (header->type ==
1361 1.1 christos DNS_SIGTYPE(dns_rdatatype_ns))
1362 1.1 christos {
1363 1.1 christos foundsig = header;
1364 1.1 christos if (found != NULL) {
1365 1.1 christos break;
1366 1.1 christos }
1367 1.1 christos }
1368 1.1 christos header_prev = header;
1369 1.1 christos } else {
1370 1.1 christos header_prev = header;
1371 1.1 christos }
1372 1.1 christos }
1373 1.1 christos
1374 1.1 christos if (found != NULL) {
1375 1.1 christos /*
1376 1.1 christos * If we have to set foundname, we do it before
1377 1.1 christos * anything else.
1378 1.1 christos */
1379 1.1 christos if (foundname != NULL) {
1380 1.1 christos dns_name_copy(&node->name, foundname);
1381 1.1 christos }
1382 1.1 christos result = DNS_R_DELEGATION;
1383 1.1 christos if (nodep != NULL) {
1384 1.1 christos newref(search->qpdb, node, nlocktype,
1385 1.1 christos isc_rwlocktype_none DNS__DB_FLARG_PASS);
1386 1.1 christos *nodep = node;
1387 1.1 christos }
1388 1.1 christos bindrdataset(search->qpdb, node, found, search->now,
1389 1.1 christos nlocktype, isc_rwlocktype_none,
1390 1.1 christos rdataset DNS__DB_FLARG_PASS);
1391 1.1 christos if (foundsig != NULL) {
1392 1.1 christos bindrdataset(search->qpdb, node, foundsig,
1393 1.1 christos search->now, nlocktype,
1394 1.1 christos isc_rwlocktype_none,
1395 1.1 christos sigrdataset DNS__DB_FLARG_PASS);
1396 1.1 christos }
1397 1.1 christos if (need_headerupdate(found, search->now) ||
1398 1.1 christos (foundsig != NULL &&
1399 1.1 christos need_headerupdate(foundsig, search->now)))
1400 1.1 christos {
1401 1.1 christos if (nlocktype != isc_rwlocktype_write) {
1402 1.1 christos NODE_FORCEUPGRADE(lock, &nlocktype);
1403 1.1 christos POST(nlocktype);
1404 1.1 christos }
1405 1.1 christos if (need_headerupdate(found, search->now)) {
1406 1.1 christos update_header(search->qpdb, found,
1407 1.1 christos search->now);
1408 1.1 christos }
1409 1.1 christos if (foundsig != NULL &&
1410 1.1 christos need_headerupdate(foundsig, search->now))
1411 1.1 christos {
1412 1.1 christos update_header(search->qpdb, foundsig,
1413 1.1 christos search->now);
1414 1.1 christos }
1415 1.1 christos }
1416 1.1 christos }
1417 1.1 christos
1418 1.1 christos NODE_UNLOCK(lock, &nlocktype);
1419 1.1 christos
1420 1.1 christos if (found != NULL) {
1421 1.1 christos break;
1422 1.1 christos }
1423 1.1 christos }
1424 1.1 christos
1425 1.1 christos return result;
1426 1.1 christos }
1427 1.1 christos
1428 1.1 christos /*
1429 1.1 christos * Look for a potentially covering NSEC in the cache where `name`
1430 1.1 christos * is known not to exist. This uses the auxiliary NSEC tree to find
1431 1.1 christos * the potential NSEC owner. If found, we update 'foundname', 'nodep',
1432 1.1 christos * 'rdataset' and 'sigrdataset', and return DNS_R_COVERINGNSEC.
1433 1.1 christos * Otherwise, return ISC_R_NOTFOUND.
1434 1.1 christos */
1435 1.1 christos static isc_result_t
1436 1.1 christos find_coveringnsec(qpc_search_t *search, const dns_name_t *name,
1437 1.1 christos dns_dbnode_t **nodep, isc_stdtime_t now,
1438 1.1 christos dns_name_t *foundname, dns_rdataset_t *rdataset,
1439 1.1 christos dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
1440 1.1 christos dns_fixedname_t fpredecessor, fixed;
1441 1.1 christos dns_name_t *predecessor = NULL, *fname = NULL;
1442 1.1 christos qpcnode_t *node = NULL;
1443 1.1 christos dns_qpiter_t iter;
1444 1.1 christos isc_result_t result;
1445 1.1 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
1446 1.1 christos isc_rwlock_t *lock = NULL;
1447 1.1 christos dns_typepair_t matchtype, sigmatchtype;
1448 1.1 christos dns_slabheader_t *found = NULL, *foundsig = NULL;
1449 1.1 christos dns_slabheader_t *header = NULL;
1450 1.1 christos dns_slabheader_t *header_next = NULL, *header_prev = NULL;
1451 1.1 christos
1452 1.1 christos /*
1453 1.1 christos * Look for the node in the auxilary tree.
1454 1.1 christos */
1455 1.1 christos result = dns_qp_lookup(search->qpdb->nsec, name, NULL, &iter, NULL,
1456 1.1 christos (void **)&node, NULL);
1457 1.1 christos if (result != DNS_R_PARTIALMATCH) {
1458 1.1 christos return ISC_R_NOTFOUND;
1459 1.1 christos }
1460 1.1 christos
1461 1.1 christos fname = dns_fixedname_initname(&fixed);
1462 1.1 christos predecessor = dns_fixedname_initname(&fpredecessor);
1463 1.1 christos matchtype = DNS_TYPEPAIR_VALUE(dns_rdatatype_nsec, 0);
1464 1.1 christos sigmatchtype = DNS_SIGTYPE(dns_rdatatype_nsec);
1465 1.1 christos
1466 1.1 christos /*
1467 1.1 christos * Extract predecessor from iterator.
1468 1.1 christos */
1469 1.1 christos result = dns_qpiter_current(&iter, predecessor, NULL, NULL);
1470 1.1 christos if (result != ISC_R_SUCCESS) {
1471 1.1 christos return ISC_R_NOTFOUND;
1472 1.1 christos }
1473 1.1 christos
1474 1.1 christos /*
1475 1.1 christos * Lookup the predecessor in the main tree.
1476 1.1 christos */
1477 1.1 christos node = NULL;
1478 1.1 christos result = dns_qp_getname(search->qpdb->tree, predecessor, (void **)&node,
1479 1.1 christos NULL);
1480 1.1 christos if (result != ISC_R_SUCCESS) {
1481 1.1 christos return result;
1482 1.1 christos }
1483 1.1 christos dns_name_copy(&node->name, fname);
1484 1.1 christos
1485 1.1 christos lock = &(search->qpdb->node_locks[node->locknum].lock);
1486 1.1 christos NODE_RDLOCK(lock, &nlocktype);
1487 1.1 christos for (header = node->data; header != NULL; header = header_next) {
1488 1.1 christos header_next = header->next;
1489 1.1 christos if (check_stale_header(node, header, &nlocktype, lock, search,
1490 1.1 christos &header_prev))
1491 1.1 christos {
1492 1.1 christos continue;
1493 1.1 christos }
1494 1.1 christos if (NONEXISTENT(header) || DNS_TYPEPAIR_TYPE(header->type) == 0)
1495 1.1 christos {
1496 1.1 christos header_prev = header;
1497 1.1 christos continue;
1498 1.1 christos }
1499 1.1 christos if (header->type == matchtype) {
1500 1.1 christos found = header;
1501 1.1 christos if (foundsig != NULL) {
1502 1.1 christos break;
1503 1.1 christos }
1504 1.1 christos } else if (header->type == sigmatchtype) {
1505 1.1 christos foundsig = header;
1506 1.1 christos if (found != NULL) {
1507 1.1 christos break;
1508 1.1 christos }
1509 1.1 christos }
1510 1.1 christos header_prev = header;
1511 1.1 christos }
1512 1.1 christos if (found != NULL) {
1513 1.1 christos bindrdataset(search->qpdb, node, found, now, nlocktype,
1514 1.1 christos isc_rwlocktype_none, rdataset DNS__DB_FLARG_PASS);
1515 1.1 christos if (foundsig != NULL) {
1516 1.1 christos bindrdataset(search->qpdb, node, foundsig, now,
1517 1.1 christos nlocktype, isc_rwlocktype_none,
1518 1.1 christos sigrdataset DNS__DB_FLARG_PASS);
1519 1.1 christos }
1520 1.1 christos newref(search->qpdb, node, nlocktype,
1521 1.1 christos isc_rwlocktype_none DNS__DB_FLARG_PASS);
1522 1.1 christos
1523 1.1 christos dns_name_copy(fname, foundname);
1524 1.1 christos
1525 1.1 christos *nodep = node;
1526 1.1 christos result = DNS_R_COVERINGNSEC;
1527 1.1 christos } else {
1528 1.1 christos result = ISC_R_NOTFOUND;
1529 1.1 christos }
1530 1.1 christos NODE_UNLOCK(lock, &nlocktype);
1531 1.1 christos return result;
1532 1.1 christos }
1533 1.1 christos
1534 1.1 christos static isc_result_t
1535 1.1 christos find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
1536 1.1 christos dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
1537 1.1 christos dns_dbnode_t **nodep, dns_name_t *foundname, dns_rdataset_t *rdataset,
1538 1.1 christos dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
1539 1.1 christos qpcnode_t *node = NULL;
1540 1.1 christos isc_result_t result;
1541 1.1 christos qpc_search_t search;
1542 1.1 christos bool cname_ok = true;
1543 1.1 christos bool found_noqname = false;
1544 1.1 christos bool all_negative = true;
1545 1.1 christos bool empty_node;
1546 1.1 christos isc_rwlock_t *lock = NULL;
1547 1.1 christos isc_rwlocktype_t tlocktype = isc_rwlocktype_none;
1548 1.1 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
1549 1.1 christos dns_slabheader_t *header = NULL;
1550 1.1 christos dns_slabheader_t *header_prev = NULL, *header_next = NULL;
1551 1.1 christos dns_slabheader_t *found = NULL, *nsheader = NULL;
1552 1.1 christos dns_slabheader_t *foundsig = NULL, *nssig = NULL, *cnamesig = NULL;
1553 1.1 christos dns_slabheader_t *update = NULL, *updatesig = NULL;
1554 1.1 christos dns_slabheader_t *nsecheader = NULL, *nsecsig = NULL;
1555 1.1 christos dns_typepair_t sigtype, negtype;
1556 1.1 christos
1557 1.1 christos UNUSED(version);
1558 1.1 christos
1559 1.1 christos REQUIRE(VALID_QPDB((qpcache_t *)db));
1560 1.1 christos REQUIRE(version == NULL);
1561 1.1 christos
1562 1.1 christos if (now == 0) {
1563 1.1 christos now = isc_stdtime_now();
1564 1.1 christos }
1565 1.1 christos
1566 1.1 christos search = (qpc_search_t){
1567 1.1 christos .qpdb = (qpcache_t *)db,
1568 1.1 christos .options = options,
1569 1.1 christos .now = now,
1570 1.1 christos };
1571 1.1 christos
1572 1.1 christos TREE_RDLOCK(&search.qpdb->tree_lock, &tlocktype);
1573 1.1 christos
1574 1.1 christos /*
1575 1.1 christos * Search down from the root of the tree.
1576 1.1 christos */
1577 1.1 christos result = dns_qp_lookup(search.qpdb->tree, name, NULL, NULL,
1578 1.1 christos &search.chain, (void **)&node, NULL);
1579 1.1 christos if (result != ISC_R_NOTFOUND && foundname != NULL) {
1580 1.1 christos dns_name_copy(&node->name, foundname);
1581 1.1 christos }
1582 1.1 christos
1583 1.1 christos /*
1584 1.1 christos * Check the QP chain to see if there's a node above us with a
1585 1.1 christos * active DNAME or NS rdatasets.
1586 1.1 christos *
1587 1.1 christos * We're only interested in nodes above QNAME, so if the result
1588 1.1 christos * was success, then we skip the last item in the chain.
1589 1.1 christos */
1590 1.1 christos unsigned int len = dns_qpchain_length(&search.chain);
1591 1.1 christos if (result == ISC_R_SUCCESS) {
1592 1.1 christos len--;
1593 1.1 christos }
1594 1.1 christos
1595 1.1 christos for (unsigned int i = 0; i < len; i++) {
1596 1.1 christos isc_result_t zcresult;
1597 1.1 christos qpcnode_t *encloser = NULL;
1598 1.1 christos
1599 1.1 christos dns_qpchain_node(&search.chain, i, NULL, (void **)&encloser,
1600 1.1 christos NULL);
1601 1.1 christos
1602 1.1 christos zcresult = check_zonecut(encloser,
1603 1.1 christos (void *)&search DNS__DB_FLARG_PASS);
1604 1.1 christos if (zcresult != DNS_R_CONTINUE) {
1605 1.1 christos result = DNS_R_PARTIALMATCH;
1606 1.1 christos search.chain.len = i - 1;
1607 1.1 christos node = encloser;
1608 1.1 christos if (foundname != NULL) {
1609 1.1 christos dns_name_copy(&node->name, foundname);
1610 1.1 christos }
1611 1.1 christos break;
1612 1.1 christos }
1613 1.1 christos }
1614 1.1 christos
1615 1.1 christos if (result == DNS_R_PARTIALMATCH) {
1616 1.1 christos /*
1617 1.1 christos * If we discovered a covering DNAME skip looking for a covering
1618 1.1 christos * NSEC.
1619 1.1 christos */
1620 1.1 christos if ((search.options & DNS_DBFIND_COVERINGNSEC) != 0 &&
1621 1.1 christos (search.zonecut_header == NULL ||
1622 1.1 christos search.zonecut_header->type != dns_rdatatype_dname))
1623 1.1 christos {
1624 1.1 christos result = find_coveringnsec(
1625 1.1 christos &search, name, nodep, now, foundname, rdataset,
1626 1.1 christos sigrdataset DNS__DB_FLARG_PASS);
1627 1.1 christos if (result == DNS_R_COVERINGNSEC) {
1628 1.1 christos goto tree_exit;
1629 1.1 christos }
1630 1.1 christos }
1631 1.1 christos if (search.zonecut != NULL) {
1632 1.1 christos result = setup_delegation(&search, nodep, rdataset,
1633 1.1 christos sigrdataset,
1634 1.1 christos tlocktype DNS__DB_FLARG_PASS);
1635 1.1 christos goto tree_exit;
1636 1.1 christos } else {
1637 1.1 christos find_ns:
1638 1.1 christos result = find_deepest_zonecut(
1639 1.1 christos &search, node, nodep, foundname, rdataset,
1640 1.1 christos sigrdataset DNS__DB_FLARG_PASS);
1641 1.1 christos goto tree_exit;
1642 1.1 christos }
1643 1.1 christos } else if (result != ISC_R_SUCCESS) {
1644 1.1 christos goto tree_exit;
1645 1.1 christos }
1646 1.1 christos
1647 1.1 christos /*
1648 1.1 christos * Certain DNSSEC types are not subject to CNAME matching
1649 1.1 christos * (RFC4035, section 2.5 and RFC3007).
1650 1.1 christos *
1651 1.1 christos * We don't check for RRSIG, because we don't store RRSIG records
1652 1.1 christos * directly.
1653 1.1 christos */
1654 1.1 christos if (type == dns_rdatatype_key || type == dns_rdatatype_nsec) {
1655 1.1 christos cname_ok = false;
1656 1.1 christos }
1657 1.1 christos
1658 1.1 christos /*
1659 1.1 christos * We now go looking for rdata...
1660 1.1 christos */
1661 1.1 christos
1662 1.1 christos lock = &(search.qpdb->node_locks[node->locknum].lock);
1663 1.1 christos NODE_RDLOCK(lock, &nlocktype);
1664 1.1 christos
1665 1.1 christos /*
1666 1.1 christos * These pointers need to be reset here in case we did
1667 1.1 christos * 'goto find_ns' from somewhere below.
1668 1.1 christos */
1669 1.1 christos found = NULL;
1670 1.1 christos foundsig = NULL;
1671 1.1 christos sigtype = DNS_SIGTYPE(type);
1672 1.1 christos negtype = DNS_TYPEPAIR_VALUE(0, type);
1673 1.1 christos nsheader = NULL;
1674 1.1 christos nsecheader = NULL;
1675 1.1 christos nssig = NULL;
1676 1.1 christos nsecsig = NULL;
1677 1.1 christos cnamesig = NULL;
1678 1.1 christos empty_node = true;
1679 1.1 christos header_prev = NULL;
1680 1.1 christos for (header = node->data; header != NULL; header = header_next) {
1681 1.1 christos header_next = header->next;
1682 1.1 christos if (check_stale_header(node, header, &nlocktype, lock, &search,
1683 1.1 christos &header_prev))
1684 1.1 christos {
1685 1.1 christos /* Do nothing. */
1686 1.1 christos } else if (EXISTS(header) && !ANCIENT(header)) {
1687 1.1 christos /*
1688 1.1 christos * We now know that there is at least one active
1689 1.1 christos * non-stale rdataset at this node.
1690 1.1 christos */
1691 1.1 christos empty_node = false;
1692 1.1 christos if (header->noqname != NULL &&
1693 1.1 christos header->trust == dns_trust_secure)
1694 1.1 christos {
1695 1.1 christos found_noqname = true;
1696 1.1 christos }
1697 1.1 christos if (!NEGATIVE(header)) {
1698 1.1 christos all_negative = false;
1699 1.1 christos }
1700 1.1 christos
1701 1.1 christos /*
1702 1.1 christos * If we found a type we were looking for, remember
1703 1.1 christos * it.
1704 1.1 christos */
1705 1.1 christos if (header->type == type ||
1706 1.1 christos (type == dns_rdatatype_any &&
1707 1.1 christos DNS_TYPEPAIR_TYPE(header->type) != 0) ||
1708 1.1 christos (cname_ok && header->type == dns_rdatatype_cname))
1709 1.1 christos {
1710 1.1 christos /*
1711 1.1 christos * We've found the answer.
1712 1.1 christos */
1713 1.1 christos found = header;
1714 1.1 christos if (header->type == dns_rdatatype_cname &&
1715 1.1 christos cname_ok)
1716 1.1 christos {
1717 1.1 christos /*
1718 1.1 christos * If we've already got the
1719 1.1 christos * CNAME RRSIG, use it.
1720 1.1 christos */
1721 1.1 christos if (cnamesig != NULL) {
1722 1.1 christos foundsig = cnamesig;
1723 1.1 christos } else {
1724 1.1 christos sigtype = DNS_SIGTYPE(
1725 1.1 christos dns_rdatatype_cname);
1726 1.1 christos }
1727 1.1 christos }
1728 1.1 christos } else if (header->type == sigtype) {
1729 1.1 christos /*
1730 1.1 christos * We've found the RRSIG rdataset for our
1731 1.1 christos * target type. Remember it.
1732 1.1 christos */
1733 1.1 christos foundsig = header;
1734 1.1 christos } else if (header->type == RDATATYPE_NCACHEANY ||
1735 1.1 christos header->type == negtype)
1736 1.1 christos {
1737 1.1 christos /*
1738 1.1 christos * We've found a negative cache entry.
1739 1.1 christos */
1740 1.1 christos found = header;
1741 1.1 christos } else if (header->type == dns_rdatatype_ns) {
1742 1.1 christos /*
1743 1.1 christos * Remember a NS rdataset even if we're
1744 1.1 christos * not specifically looking for it, because
1745 1.1 christos * we might need it later.
1746 1.1 christos */
1747 1.1 christos nsheader = header;
1748 1.1 christos } else if (header->type ==
1749 1.1 christos DNS_SIGTYPE(dns_rdatatype_ns))
1750 1.1 christos {
1751 1.1 christos /*
1752 1.1 christos * If we need the NS rdataset, we'll also
1753 1.1 christos * need its signature.
1754 1.1 christos */
1755 1.1 christos nssig = header;
1756 1.1 christos } else if (header->type == dns_rdatatype_nsec) {
1757 1.1 christos nsecheader = header;
1758 1.1 christos } else if (header->type ==
1759 1.1 christos DNS_SIGTYPE(dns_rdatatype_nsec))
1760 1.1 christos {
1761 1.1 christos nsecsig = header;
1762 1.1 christos } else if (cname_ok &&
1763 1.1 christos header->type ==
1764 1.1 christos DNS_SIGTYPE(dns_rdatatype_cname))
1765 1.1 christos {
1766 1.1 christos /*
1767 1.1 christos * If we get a CNAME match, we'll also need
1768 1.1 christos * its signature.
1769 1.1 christos */
1770 1.1 christos cnamesig = header;
1771 1.1 christos }
1772 1.1 christos header_prev = header;
1773 1.1 christos } else {
1774 1.1 christos header_prev = header;
1775 1.1 christos }
1776 1.1 christos }
1777 1.1 christos
1778 1.1 christos if (empty_node) {
1779 1.1 christos /*
1780 1.1 christos * We have an exact match for the name, but there are no
1781 1.1 christos * extant rdatasets. That means that this node doesn't
1782 1.1 christos * meaningfully exist, and that we really have a partial match.
1783 1.1 christos */
1784 1.1 christos NODE_UNLOCK(lock, &nlocktype);
1785 1.1 christos if ((search.options & DNS_DBFIND_COVERINGNSEC) != 0) {
1786 1.1 christos result = find_coveringnsec(
1787 1.1 christos &search, name, nodep, now, foundname, rdataset,
1788 1.1 christos sigrdataset DNS__DB_FLARG_PASS);
1789 1.1 christos if (result == DNS_R_COVERINGNSEC) {
1790 1.1 christos goto tree_exit;
1791 1.1 christos }
1792 1.1 christos }
1793 1.1 christos goto find_ns;
1794 1.1 christos }
1795 1.1 christos
1796 1.1 christos /*
1797 1.1 christos * If we didn't find what we were looking for...
1798 1.1 christos */
1799 1.1 christos if (found == NULL ||
1800 1.1 christos (DNS_TRUST_ADDITIONAL(found->trust) &&
1801 1.1 christos ((options & DNS_DBFIND_ADDITIONALOK) == 0)) ||
1802 1.1 christos (found->trust == dns_trust_glue &&
1803 1.1 christos ((options & DNS_DBFIND_GLUEOK) == 0)) ||
1804 1.1 christos (DNS_TRUST_PENDING(found->trust) &&
1805 1.1 christos ((options & DNS_DBFIND_PENDINGOK) == 0)))
1806 1.1 christos {
1807 1.1 christos /*
1808 1.1 christos * Return covering NODATA NSEC record.
1809 1.1 christos */
1810 1.1 christos if ((search.options & DNS_DBFIND_COVERINGNSEC) != 0 &&
1811 1.1 christos nsecheader != NULL)
1812 1.1 christos {
1813 1.1 christos if (nodep != NULL) {
1814 1.1 christos newref(search.qpdb, node, nlocktype,
1815 1.1 christos tlocktype DNS__DB_FLARG_PASS);
1816 1.1 christos *nodep = node;
1817 1.1 christos }
1818 1.1 christos bindrdataset(search.qpdb, node, nsecheader, search.now,
1819 1.1 christos nlocktype, tlocktype,
1820 1.1 christos rdataset DNS__DB_FLARG_PASS);
1821 1.1 christos if (need_headerupdate(nsecheader, search.now)) {
1822 1.1 christos update = nsecheader;
1823 1.1 christos }
1824 1.1 christos if (nsecsig != NULL) {
1825 1.1 christos bindrdataset(search.qpdb, node, nsecsig,
1826 1.1 christos search.now, nlocktype, tlocktype,
1827 1.1 christos sigrdataset DNS__DB_FLARG_PASS);
1828 1.1 christos if (need_headerupdate(nsecsig, search.now)) {
1829 1.1 christos updatesig = nsecsig;
1830 1.1 christos }
1831 1.1 christos }
1832 1.1 christos result = DNS_R_COVERINGNSEC;
1833 1.1 christos goto node_exit;
1834 1.1 christos }
1835 1.1 christos
1836 1.1 christos /*
1837 1.1 christos * This name was from a wild card. Look for a covering NSEC.
1838 1.1 christos */
1839 1.1 christos if (found == NULL && (found_noqname || all_negative) &&
1840 1.1 christos (search.options & DNS_DBFIND_COVERINGNSEC) != 0)
1841 1.1 christos {
1842 1.1 christos NODE_UNLOCK(lock, &nlocktype);
1843 1.1 christos result = find_coveringnsec(
1844 1.1 christos &search, name, nodep, now, foundname, rdataset,
1845 1.1 christos sigrdataset DNS__DB_FLARG_PASS);
1846 1.1 christos if (result == DNS_R_COVERINGNSEC) {
1847 1.1 christos goto tree_exit;
1848 1.1 christos }
1849 1.1 christos goto find_ns;
1850 1.1 christos }
1851 1.1 christos
1852 1.1 christos /*
1853 1.1 christos * If there is an NS rdataset at this node, then this is the
1854 1.1 christos * deepest zone cut.
1855 1.1 christos */
1856 1.1 christos if (nsheader != NULL) {
1857 1.1 christos if (nodep != NULL) {
1858 1.1 christos newref(search.qpdb, node, nlocktype,
1859 1.1 christos tlocktype DNS__DB_FLARG_PASS);
1860 1.1 christos *nodep = node;
1861 1.1 christos }
1862 1.1 christos bindrdataset(search.qpdb, node, nsheader, search.now,
1863 1.1 christos nlocktype, tlocktype,
1864 1.1 christos rdataset DNS__DB_FLARG_PASS);
1865 1.1 christos if (need_headerupdate(nsheader, search.now)) {
1866 1.1 christos update = nsheader;
1867 1.1 christos }
1868 1.1 christos if (nssig != NULL) {
1869 1.1 christos bindrdataset(search.qpdb, node, nssig,
1870 1.1 christos search.now, nlocktype, tlocktype,
1871 1.1 christos sigrdataset DNS__DB_FLARG_PASS);
1872 1.1 christos if (need_headerupdate(nssig, search.now)) {
1873 1.1 christos updatesig = nssig;
1874 1.1 christos }
1875 1.1 christos }
1876 1.1 christos result = DNS_R_DELEGATION;
1877 1.1 christos goto node_exit;
1878 1.1 christos }
1879 1.1 christos
1880 1.1 christos /*
1881 1.1 christos * Go find the deepest zone cut.
1882 1.1 christos */
1883 1.1 christos NODE_UNLOCK(lock, &nlocktype);
1884 1.1 christos goto find_ns;
1885 1.1 christos }
1886 1.1 christos
1887 1.1 christos /*
1888 1.1 christos * We found what we were looking for, or we found a CNAME.
1889 1.1 christos */
1890 1.1 christos
1891 1.1 christos if (nodep != NULL) {
1892 1.1 christos newref(search.qpdb, node, nlocktype,
1893 1.1 christos tlocktype DNS__DB_FLARG_PASS);
1894 1.1 christos *nodep = node;
1895 1.1 christos }
1896 1.1 christos
1897 1.1 christos if (NEGATIVE(found)) {
1898 1.1 christos /*
1899 1.1 christos * We found a negative cache entry.
1900 1.1 christos */
1901 1.1 christos if (NXDOMAIN(found)) {
1902 1.1 christos result = DNS_R_NCACHENXDOMAIN;
1903 1.1 christos } else {
1904 1.1 christos result = DNS_R_NCACHENXRRSET;
1905 1.1 christos }
1906 1.1 christos } else if (type != found->type && type != dns_rdatatype_any &&
1907 1.1 christos found->type == dns_rdatatype_cname)
1908 1.1 christos {
1909 1.1 christos /*
1910 1.1 christos * We weren't doing an ANY query and we found a CNAME instead
1911 1.1 christos * of the type we were looking for, so we need to indicate
1912 1.1 christos * that result to the caller.
1913 1.1 christos */
1914 1.1 christos result = DNS_R_CNAME;
1915 1.1 christos } else {
1916 1.1 christos /*
1917 1.1 christos * An ordinary successful query!
1918 1.1 christos */
1919 1.1 christos result = ISC_R_SUCCESS;
1920 1.1 christos }
1921 1.1 christos
1922 1.1 christos if (type != dns_rdatatype_any || result == DNS_R_NCACHENXDOMAIN ||
1923 1.1 christos result == DNS_R_NCACHENXRRSET)
1924 1.1 christos {
1925 1.1 christos bindrdataset(search.qpdb, node, found, search.now, nlocktype,
1926 1.1 christos tlocktype, rdataset DNS__DB_FLARG_PASS);
1927 1.1 christos if (need_headerupdate(found, search.now)) {
1928 1.1 christos update = found;
1929 1.1 christos }
1930 1.1 christos if (!NEGATIVE(found) && foundsig != NULL) {
1931 1.1 christos bindrdataset(search.qpdb, node, foundsig, search.now,
1932 1.1 christos nlocktype, tlocktype,
1933 1.1 christos sigrdataset DNS__DB_FLARG_PASS);
1934 1.1 christos if (need_headerupdate(foundsig, search.now)) {
1935 1.1 christos updatesig = foundsig;
1936 1.1 christos }
1937 1.1 christos }
1938 1.1 christos }
1939 1.1 christos
1940 1.1 christos node_exit:
1941 1.1 christos if ((update != NULL || updatesig != NULL) &&
1942 1.1 christos nlocktype != isc_rwlocktype_write)
1943 1.1 christos {
1944 1.1 christos NODE_FORCEUPGRADE(lock, &nlocktype);
1945 1.1 christos POST(nlocktype);
1946 1.1 christos }
1947 1.1 christos if (update != NULL && need_headerupdate(update, search.now)) {
1948 1.1 christos update_header(search.qpdb, update, search.now);
1949 1.1 christos }
1950 1.1 christos if (updatesig != NULL && need_headerupdate(updatesig, search.now)) {
1951 1.1 christos update_header(search.qpdb, updatesig, search.now);
1952 1.1 christos }
1953 1.1 christos
1954 1.1 christos NODE_UNLOCK(lock, &nlocktype);
1955 1.1 christos
1956 1.1 christos tree_exit:
1957 1.1 christos TREE_UNLOCK(&search.qpdb->tree_lock, &tlocktype);
1958 1.1 christos
1959 1.1 christos /*
1960 1.1 christos * If we found a zonecut but aren't going to use it, we have to
1961 1.1 christos * let go of it.
1962 1.1 christos */
1963 1.1 christos if (search.need_cleanup) {
1964 1.1 christos node = search.zonecut;
1965 1.1 christos INSIST(node != NULL);
1966 1.1 christos lock = &(search.qpdb->node_locks[node->locknum].lock);
1967 1.1 christos
1968 1.1 christos NODE_RDLOCK(lock, &nlocktype);
1969 1.1 christos decref(search.qpdb, node, &nlocktype, &tlocktype,
1970 1.1 christos true DNS__DB_FLARG_PASS);
1971 1.1 christos NODE_UNLOCK(lock, &nlocktype);
1972 1.1 christos INSIST(tlocktype == isc_rwlocktype_none);
1973 1.1 christos }
1974 1.1 christos
1975 1.1 christos update_cachestats(search.qpdb, result);
1976 1.1 christos return result;
1977 1.1 christos }
1978 1.1 christos
1979 1.1 christos static isc_result_t
1980 1.1 christos findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
1981 1.1 christos isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname,
1982 1.1 christos dns_name_t *dcname, dns_rdataset_t *rdataset,
1983 1.1 christos dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
1984 1.1 christos qpcnode_t *node = NULL;
1985 1.1 christos isc_rwlock_t *lock = NULL;
1986 1.1 christos isc_result_t result;
1987 1.1 christos qpc_search_t search;
1988 1.1 christos dns_slabheader_t *header = NULL;
1989 1.1 christos dns_slabheader_t *header_prev = NULL, *header_next = NULL;
1990 1.1 christos dns_slabheader_t *found = NULL, *foundsig = NULL;
1991 1.1 christos isc_rwlocktype_t tlocktype = isc_rwlocktype_none;
1992 1.1 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
1993 1.1 christos bool dcnull = (dcname == NULL);
1994 1.1 christos
1995 1.1 christos REQUIRE(VALID_QPDB((qpcache_t *)db));
1996 1.1 christos
1997 1.1 christos if (now == 0) {
1998 1.1 christos now = isc_stdtime_now();
1999 1.1 christos }
2000 1.1 christos
2001 1.1 christos search = (qpc_search_t){
2002 1.1 christos .qpdb = (qpcache_t *)db,
2003 1.1 christos .options = options,
2004 1.1 christos .now = now,
2005 1.1 christos };
2006 1.1 christos
2007 1.1 christos if (dcnull) {
2008 1.1 christos dcname = foundname;
2009 1.1 christos }
2010 1.1 christos
2011 1.1 christos TREE_RDLOCK(&search.qpdb->tree_lock, &tlocktype);
2012 1.1 christos
2013 1.1 christos /*
2014 1.1 christos * Search down from the root of the tree.
2015 1.1 christos */
2016 1.1 christos result = dns_qp_lookup(search.qpdb->tree, name, NULL, NULL,
2017 1.1 christos &search.chain, (void **)&node, NULL);
2018 1.1 christos if (result != ISC_R_NOTFOUND) {
2019 1.1 christos dns_name_copy(&node->name, dcname);
2020 1.1 christos }
2021 1.1 christos if ((options & DNS_DBFIND_NOEXACT) != 0 && result == ISC_R_SUCCESS) {
2022 1.1 christos int len = dns_qpchain_length(&search.chain);
2023 1.1 christos if (len >= 2) {
2024 1.1 christos node = NULL;
2025 1.1 christos dns_qpchain_node(&search.chain, len - 2, NULL,
2026 1.1 christos (void **)&node, NULL);
2027 1.1 christos search.chain.len = len - 1;
2028 1.1 christos result = DNS_R_PARTIALMATCH;
2029 1.1 christos } else {
2030 1.1 christos result = ISC_R_NOTFOUND;
2031 1.1 christos }
2032 1.1 christos }
2033 1.1 christos
2034 1.1 christos if (result == DNS_R_PARTIALMATCH) {
2035 1.1 christos result = find_deepest_zonecut(&search, node, nodep, foundname,
2036 1.1 christos rdataset,
2037 1.1 christos sigrdataset DNS__DB_FLARG_PASS);
2038 1.1 christos goto tree_exit;
2039 1.1 christos } else if (result != ISC_R_SUCCESS) {
2040 1.1 christos goto tree_exit;
2041 1.1 christos } else if (!dcnull) {
2042 1.1 christos dns_name_copy(dcname, foundname);
2043 1.1 christos }
2044 1.1 christos
2045 1.1 christos /*
2046 1.1 christos * We now go looking for an NS rdataset at the node.
2047 1.1 christos */
2048 1.1 christos
2049 1.1 christos lock = &(search.qpdb->node_locks[node->locknum].lock);
2050 1.1 christos NODE_RDLOCK(lock, &nlocktype);
2051 1.1 christos
2052 1.1 christos for (header = node->data; header != NULL; header = header_next) {
2053 1.1 christos header_next = header->next;
2054 1.1 christos if (check_stale_header(node, header, &nlocktype, lock, &search,
2055 1.1 christos &header_prev))
2056 1.1 christos {
2057 1.1 christos /*
2058 1.1 christos * The function dns_qp_lookup found us a matching
2059 1.1 christos * node for 'name' and stored the result in 'dcname'.
2060 1.1 christos * This is the deepest known zonecut in our database.
2061 1.1 christos * However, this node may be stale and if serve-stale
2062 1.1 christos * is not enabled (in other words 'stale-answer-enable'
2063 1.1 christos * is set to no), this node may not be used as a
2064 1.1 christos * zonecut we know about. If so, find the deepest
2065 1.1 christos * zonecut from this node up and return that instead.
2066 1.1 christos */
2067 1.1 christos NODE_UNLOCK(lock, &nlocktype);
2068 1.1 christos result = find_deepest_zonecut(
2069 1.1 christos &search, node, nodep, foundname, rdataset,
2070 1.1 christos sigrdataset DNS__DB_FLARG_PASS);
2071 1.1 christos dns_name_copy(foundname, dcname);
2072 1.1 christos goto tree_exit;
2073 1.1 christos } else if (EXISTS(header) && !ANCIENT(header)) {
2074 1.1 christos /*
2075 1.1 christos * If we found a type we were looking for, remember
2076 1.1 christos * it.
2077 1.1 christos */
2078 1.1 christos if (header->type == dns_rdatatype_ns) {
2079 1.1 christos /*
2080 1.1 christos * Remember a NS rdataset even if we're
2081 1.1 christos * not specifically looking for it, because
2082 1.1 christos * we might need it later.
2083 1.1 christos */
2084 1.1 christos found = header;
2085 1.1 christos } else if (header->type ==
2086 1.1 christos DNS_SIGTYPE(dns_rdatatype_ns))
2087 1.1 christos {
2088 1.1 christos /*
2089 1.1 christos * If we need the NS rdataset, we'll also
2090 1.1 christos * need its signature.
2091 1.1 christos */
2092 1.1 christos foundsig = header;
2093 1.1 christos }
2094 1.1 christos header_prev = header;
2095 1.1 christos } else {
2096 1.1 christos header_prev = header;
2097 1.1 christos }
2098 1.1 christos }
2099 1.1 christos
2100 1.1 christos if (found == NULL) {
2101 1.1 christos /*
2102 1.1 christos * No NS records here.
2103 1.1 christos */
2104 1.1 christos NODE_UNLOCK(lock, &nlocktype);
2105 1.1 christos result = find_deepest_zonecut(&search, node, nodep, foundname,
2106 1.1 christos rdataset,
2107 1.1 christos sigrdataset DNS__DB_FLARG_PASS);
2108 1.1 christos goto tree_exit;
2109 1.1 christos }
2110 1.1 christos
2111 1.1 christos if (nodep != NULL) {
2112 1.1 christos newref(search.qpdb, node, nlocktype,
2113 1.1 christos tlocktype DNS__DB_FLARG_PASS);
2114 1.1 christos *nodep = node;
2115 1.1 christos }
2116 1.1 christos
2117 1.1 christos bindrdataset(search.qpdb, node, found, search.now, nlocktype, tlocktype,
2118 1.1 christos rdataset DNS__DB_FLARG_PASS);
2119 1.1 christos if (foundsig != NULL) {
2120 1.1 christos bindrdataset(search.qpdb, node, foundsig, search.now, nlocktype,
2121 1.1 christos tlocktype, sigrdataset DNS__DB_FLARG_PASS);
2122 1.1 christos }
2123 1.1 christos
2124 1.1 christos if (need_headerupdate(found, search.now) ||
2125 1.1 christos (foundsig != NULL && need_headerupdate(foundsig, search.now)))
2126 1.1 christos {
2127 1.1 christos if (nlocktype != isc_rwlocktype_write) {
2128 1.1 christos NODE_FORCEUPGRADE(lock, &nlocktype);
2129 1.1 christos POST(nlocktype);
2130 1.1 christos }
2131 1.1 christos if (need_headerupdate(found, search.now)) {
2132 1.1 christos update_header(search.qpdb, found, search.now);
2133 1.1 christos }
2134 1.1 christos if (foundsig != NULL && need_headerupdate(foundsig, search.now))
2135 1.1 christos {
2136 1.1 christos update_header(search.qpdb, foundsig, search.now);
2137 1.1 christos }
2138 1.1 christos }
2139 1.1 christos
2140 1.1 christos NODE_UNLOCK(lock, &nlocktype);
2141 1.1 christos
2142 1.1 christos tree_exit:
2143 1.1 christos TREE_UNLOCK(&search.qpdb->tree_lock, &tlocktype);
2144 1.1 christos
2145 1.1 christos INSIST(!search.need_cleanup);
2146 1.1 christos
2147 1.1 christos if (result == DNS_R_DELEGATION) {
2148 1.1 christos result = ISC_R_SUCCESS;
2149 1.1 christos }
2150 1.1 christos
2151 1.1 christos return result;
2152 1.1 christos }
2153 1.1 christos
2154 1.1 christos static isc_result_t
2155 1.1 christos findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
2156 1.1 christos dns_rdatatype_t type, dns_rdatatype_t covers, isc_stdtime_t now,
2157 1.1 christos dns_rdataset_t *rdataset,
2158 1.1 christos dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
2159 1.1 christos qpcache_t *qpdb = (qpcache_t *)db;
2160 1.1 christos qpcnode_t *qpnode = (qpcnode_t *)node;
2161 1.1 christos dns_slabheader_t *header = NULL, *header_next = NULL;
2162 1.1 christos dns_slabheader_t *found = NULL, *foundsig = NULL;
2163 1.1 christos dns_typepair_t matchtype, sigmatchtype, negtype;
2164 1.1 christos isc_result_t result;
2165 1.1 christos isc_rwlock_t *lock = NULL;
2166 1.1 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
2167 1.1 christos
2168 1.1 christos REQUIRE(VALID_QPDB(qpdb));
2169 1.1 christos REQUIRE(type != dns_rdatatype_any);
2170 1.1 christos
2171 1.1 christos UNUSED(version);
2172 1.1 christos
2173 1.1 christos result = ISC_R_SUCCESS;
2174 1.1 christos
2175 1.1 christos if (now == 0) {
2176 1.1 christos now = isc_stdtime_now();
2177 1.1 christos }
2178 1.1 christos
2179 1.1 christos lock = &qpdb->node_locks[qpnode->locknum].lock;
2180 1.1 christos NODE_RDLOCK(lock, &nlocktype);
2181 1.1 christos
2182 1.1 christos matchtype = DNS_TYPEPAIR_VALUE(type, covers);
2183 1.1 christos negtype = DNS_TYPEPAIR_VALUE(0, type);
2184 1.1 christos if (covers == 0) {
2185 1.1 christos sigmatchtype = DNS_SIGTYPE(type);
2186 1.1 christos } else {
2187 1.1 christos sigmatchtype = 0;
2188 1.1 christos }
2189 1.1 christos
2190 1.1 christos for (header = qpnode->data; header != NULL; header = header_next) {
2191 1.1 christos header_next = header->next;
2192 1.1 christos if (!ACTIVE(header, now)) {
2193 1.1 christos if ((header->ttl + STALE_TTL(header, qpdb) <
2194 1.1 christos now - QPDB_VIRTUAL) &&
2195 1.1 christos (nlocktype == isc_rwlocktype_write ||
2196 1.1 christos NODE_TRYUPGRADE(lock, &nlocktype) ==
2197 1.1 christos ISC_R_SUCCESS))
2198 1.1 christos {
2199 1.1 christos /*
2200 1.1 christos * We update the node's status only when we
2201 1.1 christos * can get write access.
2202 1.1 christos *
2203 1.1 christos * We don't check if refcurrent(qpnode) == 0
2204 1.1 christos * and try to free like we do in find(),
2205 1.1 christos * because refcurrent(qpnode) must be
2206 1.1 christos * non-zero. This is so because 'node' is an
2207 1.1 christos * argument to the function.
2208 1.1 christos */
2209 1.1 christos mark(header, DNS_SLABHEADERATTR_ANCIENT);
2210 1.1 christos HEADERNODE(header)->dirty = 1;
2211 1.1 christos }
2212 1.1 christos } else if (EXISTS(header) && !ANCIENT(header)) {
2213 1.1 christos if (header->type == matchtype) {
2214 1.1 christos found = header;
2215 1.1 christos } else if (header->type == RDATATYPE_NCACHEANY ||
2216 1.1 christos header->type == negtype)
2217 1.1 christos {
2218 1.1 christos found = header;
2219 1.1 christos } else if (header->type == sigmatchtype) {
2220 1.1 christos foundsig = header;
2221 1.1 christos }
2222 1.1 christos }
2223 1.1 christos }
2224 1.1 christos if (found != NULL) {
2225 1.1 christos bindrdataset(qpdb, qpnode, found, now, nlocktype,
2226 1.1 christos isc_rwlocktype_none, rdataset DNS__DB_FLARG_PASS);
2227 1.1 christos if (!NEGATIVE(found) && foundsig != NULL) {
2228 1.1 christos bindrdataset(qpdb, qpnode, foundsig, now, nlocktype,
2229 1.1 christos isc_rwlocktype_none,
2230 1.1 christos sigrdataset DNS__DB_FLARG_PASS);
2231 1.1 christos }
2232 1.1 christos }
2233 1.1 christos
2234 1.1 christos NODE_UNLOCK(lock, &nlocktype);
2235 1.1 christos
2236 1.1 christos if (found == NULL) {
2237 1.1 christos return ISC_R_NOTFOUND;
2238 1.1 christos }
2239 1.1 christos
2240 1.1 christos if (NEGATIVE(found)) {
2241 1.1 christos /*
2242 1.1 christos * We found a negative cache entry.
2243 1.1 christos */
2244 1.1 christos if (NXDOMAIN(found)) {
2245 1.1 christos result = DNS_R_NCACHENXDOMAIN;
2246 1.1 christos } else {
2247 1.1 christos result = DNS_R_NCACHENXRRSET;
2248 1.1 christos }
2249 1.1 christos }
2250 1.1 christos
2251 1.1 christos update_cachestats(qpdb, result);
2252 1.1 christos
2253 1.1 christos return result;
2254 1.1 christos }
2255 1.1 christos
2256 1.1 christos static isc_result_t
2257 1.1 christos setcachestats(dns_db_t *db, isc_stats_t *stats) {
2258 1.1 christos qpcache_t *qpdb = (qpcache_t *)db;
2259 1.1 christos
2260 1.1 christos REQUIRE(VALID_QPDB(qpdb));
2261 1.1 christos REQUIRE(stats != NULL);
2262 1.1 christos
2263 1.1 christos isc_stats_attach(stats, &qpdb->cachestats);
2264 1.1 christos return ISC_R_SUCCESS;
2265 1.1 christos }
2266 1.1 christos
2267 1.1 christos static dns_stats_t *
2268 1.1 christos getrrsetstats(dns_db_t *db) {
2269 1.1 christos qpcache_t *qpdb = (qpcache_t *)db;
2270 1.1 christos
2271 1.1 christos REQUIRE(VALID_QPDB(qpdb));
2272 1.1 christos
2273 1.1 christos return qpdb->rrsetstats;
2274 1.1 christos }
2275 1.1 christos
2276 1.1 christos static isc_result_t
2277 1.1 christos setservestalettl(dns_db_t *db, dns_ttl_t ttl) {
2278 1.1 christos qpcache_t *qpdb = (qpcache_t *)db;
2279 1.1 christos
2280 1.1 christos REQUIRE(VALID_QPDB(qpdb));
2281 1.1 christos
2282 1.1 christos /* currently no bounds checking. 0 means disable. */
2283 1.1 christos qpdb->common.serve_stale_ttl = ttl;
2284 1.1 christos return ISC_R_SUCCESS;
2285 1.1 christos }
2286 1.1 christos
2287 1.1 christos static isc_result_t
2288 1.1 christos getservestalettl(dns_db_t *db, dns_ttl_t *ttl) {
2289 1.1 christos qpcache_t *qpdb = (qpcache_t *)db;
2290 1.1 christos
2291 1.1 christos REQUIRE(VALID_QPDB(qpdb));
2292 1.1 christos
2293 1.1 christos *ttl = qpdb->common.serve_stale_ttl;
2294 1.1 christos return ISC_R_SUCCESS;
2295 1.1 christos }
2296 1.1 christos
2297 1.1 christos static isc_result_t
2298 1.1 christos setservestalerefresh(dns_db_t *db, uint32_t interval) {
2299 1.1 christos qpcache_t *qpdb = (qpcache_t *)db;
2300 1.1 christos
2301 1.1 christos REQUIRE(VALID_QPDB(qpdb));
2302 1.1 christos
2303 1.1 christos /* currently no bounds checking. 0 means disable. */
2304 1.1 christos qpdb->serve_stale_refresh = interval;
2305 1.1 christos return ISC_R_SUCCESS;
2306 1.1 christos }
2307 1.1 christos
2308 1.1 christos static isc_result_t
2309 1.1 christos getservestalerefresh(dns_db_t *db, uint32_t *interval) {
2310 1.1 christos qpcache_t *qpdb = (qpcache_t *)db;
2311 1.1 christos
2312 1.1 christos REQUIRE(VALID_QPDB(qpdb));
2313 1.1 christos
2314 1.1 christos *interval = qpdb->serve_stale_refresh;
2315 1.1 christos return ISC_R_SUCCESS;
2316 1.1 christos }
2317 1.1 christos
2318 1.1 christos static void
2319 1.1 christos expiredata(dns_db_t *db, dns_dbnode_t *node, void *data) {
2320 1.1 christos qpcache_t *qpdb = (qpcache_t *)db;
2321 1.1 christos qpcnode_t *qpnode = (qpcnode_t *)node;
2322 1.1 christos dns_slabheader_t *header = data;
2323 1.1 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
2324 1.1 christos isc_rwlocktype_t tlocktype = isc_rwlocktype_none;
2325 1.1 christos
2326 1.1 christos NODE_WRLOCK(&qpdb->node_locks[qpnode->locknum].lock, &nlocktype);
2327 1.1 christos expireheader(header, &nlocktype, &tlocktype,
2328 1.1 christos dns_expire_flush DNS__DB_FILELINE);
2329 1.1 christos NODE_UNLOCK(&qpdb->node_locks[qpnode->locknum].lock, &nlocktype);
2330 1.1 christos INSIST(tlocktype == isc_rwlocktype_none);
2331 1.1 christos }
2332 1.1 christos
2333 1.1 christos static size_t
2334 1.1 christos rdataset_size(dns_slabheader_t *header) {
2335 1.1 christos if (!NONEXISTENT(header)) {
2336 1.1 christos return dns_rdataslab_size((unsigned char *)header,
2337 1.1 christos sizeof(*header));
2338 1.1 christos }
2339 1.1 christos
2340 1.1 christos return sizeof(*header);
2341 1.1 christos }
2342 1.1 christos
2343 1.1 christos static size_t
2344 1.1 christos expire_lru_headers(qpcache_t *qpdb, unsigned int locknum,
2345 1.1 christos isc_rwlocktype_t *nlocktypep, isc_rwlocktype_t *tlocktypep,
2346 1.1 christos size_t purgesize DNS__DB_FLARG) {
2347 1.1 christos dns_slabheader_t *header = NULL;
2348 1.1 christos size_t purged = 0;
2349 1.1 christos
2350 1.1 christos for (header = ISC_LIST_TAIL(qpdb->lru[locknum]);
2351 1.1 christos header != NULL && header->last_used <= qpdb->last_used &&
2352 1.1 christos purged <= purgesize;
2353 1.1 christos header = ISC_LIST_TAIL(qpdb->lru[locknum]))
2354 1.1 christos {
2355 1.1 christos size_t header_size = rdataset_size(header);
2356 1.1 christos
2357 1.1 christos /*
2358 1.1 christos * Unlink the entry at this point to avoid checking it
2359 1.1 christos * again even if it's currently used someone else and
2360 1.1 christos * cannot be purged at this moment. This entry won't be
2361 1.1 christos * referenced any more (so unlinking is safe) since the
2362 1.1 christos * TTL will be reset to 0.
2363 1.1 christos */
2364 1.1 christos ISC_LIST_UNLINK(qpdb->lru[locknum], header, link);
2365 1.1 christos expireheader(header, nlocktypep, tlocktypep,
2366 1.1 christos dns_expire_lru DNS__DB_FLARG_PASS);
2367 1.1 christos purged += header_size;
2368 1.1 christos }
2369 1.1 christos
2370 1.1 christos return purged;
2371 1.1 christos }
2372 1.1 christos
2373 1.1 christos /*%
2374 1.1 christos * Purge some expired and/or stale (i.e. unused for some period) cache entries
2375 1.1 christos * due to an overmem condition. To recover from this condition quickly,
2376 1.1 christos * we clean up entries up to the size of newly added rdata that triggered
2377 1.1 christos * the overmem; this is accessible via newheader.
2378 1.1 christos *
2379 1.1 christos * The LRU lists tails are processed in LRU order to the nearest second.
2380 1.1 christos *
2381 1.1 christos * A write lock on the tree must be held.
2382 1.1 christos */
2383 1.1 christos static void
2384 1.1 christos overmem(qpcache_t *qpdb, dns_slabheader_t *newheader,
2385 1.1 christos isc_rwlocktype_t *tlocktypep DNS__DB_FLARG) {
2386 1.1 christos uint32_t locknum_start = qpdb->lru_sweep++ % qpdb->node_lock_count;
2387 1.1 christos uint32_t locknum = locknum_start;
2388 1.1 christos size_t purgesize, purged = 0;
2389 1.1 christos isc_stdtime_t min_last_used = 0;
2390 1.1 christos size_t max_passes = 8;
2391 1.1 christos
2392 1.1 christos /*
2393 1.1 christos * Maximum estimated size of the data being added: The size
2394 1.1 christos * of the rdataset, plus a new QP database node and nodename,
2395 1.1 christos * and a possible additional NSEC node and nodename. Also add
2396 1.1 christos * a 12k margin for a possible QP-trie chunk allocation.
2397 1.1 christos * (It's okay to overestimate, we want to get cache memory
2398 1.1 christos * down quickly.)
2399 1.1 christos */
2400 1.1 christos purgesize = 2 * (sizeof(qpcnode_t) +
2401 1.1 christos dns_name_size(&HEADERNODE(newheader)->name)) +
2402 1.1 christos rdataset_size(newheader) + 12288;
2403 1.1 christos again:
2404 1.1 christos do {
2405 1.1 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
2406 1.1 christos NODE_WRLOCK(&qpdb->node_locks[locknum].lock, &nlocktype);
2407 1.1 christos
2408 1.1 christos purged += expire_lru_headers(
2409 1.1 christos qpdb, locknum, &nlocktype, tlocktypep,
2410 1.1 christos purgesize - purged DNS__DB_FLARG_PASS);
2411 1.1 christos
2412 1.1 christos /*
2413 1.1 christos * Work out the oldest remaining last_used values of the list
2414 1.1 christos * tails as we walk across the array of lru lists.
2415 1.1 christos */
2416 1.1 christos dns_slabheader_t *header = ISC_LIST_TAIL(qpdb->lru[locknum]);
2417 1.1 christos if (header != NULL &&
2418 1.1 christos (min_last_used == 0 || header->last_used < min_last_used))
2419 1.1 christos {
2420 1.1 christos min_last_used = header->last_used;
2421 1.1 christos }
2422 1.1 christos NODE_UNLOCK(&qpdb->node_locks[locknum].lock, &nlocktype);
2423 1.1 christos locknum = (locknum + 1) % qpdb->node_lock_count;
2424 1.1 christos } while (locknum != locknum_start && purged <= purgesize);
2425 1.1 christos
2426 1.1 christos /*
2427 1.1 christos * Update qpdb->last_used if we have walked all the list tails and have
2428 1.1 christos * not freed the required amount of memory.
2429 1.1 christos */
2430 1.1 christos if (purged < purgesize) {
2431 1.1 christos if (min_last_used != 0) {
2432 1.1 christos qpdb->last_used = min_last_used;
2433 1.1 christos if (max_passes-- > 0) {
2434 1.1 christos goto again;
2435 1.1 christos }
2436 1.1 christos }
2437 1.1 christos }
2438 1.1 christos }
2439 1.1 christos
2440 1.1 christos /*%
2441 1.1 christos * These functions allow the heap code to rank the priority of each
2442 1.1 christos * element. It returns true if v1 happens "sooner" than v2.
2443 1.1 christos */
2444 1.1 christos static bool
2445 1.1 christos ttl_sooner(void *v1, void *v2) {
2446 1.1 christos dns_slabheader_t *h1 = v1;
2447 1.1 christos dns_slabheader_t *h2 = v2;
2448 1.1 christos
2449 1.1 christos return h1->ttl < h2->ttl;
2450 1.1 christos }
2451 1.1 christos
2452 1.1 christos /*%
2453 1.1 christos * This function sets the heap index into the header.
2454 1.1 christos */
2455 1.1 christos static void
2456 1.1 christos set_index(void *what, unsigned int idx) {
2457 1.1 christos dns_slabheader_t *h = what;
2458 1.1 christos
2459 1.1 christos h->heap_index = idx;
2460 1.1 christos }
2461 1.1 christos
2462 1.1 christos static void
2463 1.1 christos free_qpdb(qpcache_t *qpdb, bool log) {
2464 1.1 christos unsigned int i;
2465 1.1 christos char buf[DNS_NAME_FORMATSIZE];
2466 1.1 christos dns_qp_t **treep = NULL;
2467 1.1 christos
2468 1.1 christos for (;;) {
2469 1.1 christos /*
2470 1.1 christos * pick the next tree to (start to) destroy
2471 1.1 christos */
2472 1.1 christos treep = &qpdb->tree;
2473 1.1 christos if (*treep == NULL) {
2474 1.1 christos treep = &qpdb->nsec;
2475 1.1 christos if (*treep == NULL) {
2476 1.1 christos break;
2477 1.1 christos }
2478 1.1 christos }
2479 1.1 christos
2480 1.1 christos dns_qp_destroy(treep);
2481 1.1 christos INSIST(*treep == NULL);
2482 1.1 christos }
2483 1.1 christos
2484 1.1 christos if (log) {
2485 1.1 christos if (dns_name_dynamic(&qpdb->common.origin)) {
2486 1.1 christos dns_name_format(&qpdb->common.origin, buf, sizeof(buf));
2487 1.1 christos } else {
2488 1.1 christos strlcpy(buf, "<UNKNOWN>", sizeof(buf));
2489 1.1 christos }
2490 1.1 christos isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
2491 1.1 christos DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
2492 1.1 christos "done free_qpdb(%s)", buf);
2493 1.1 christos }
2494 1.1 christos if (dns_name_dynamic(&qpdb->common.origin)) {
2495 1.1 christos dns_name_free(&qpdb->common.origin, qpdb->common.mctx);
2496 1.1 christos }
2497 1.1 christos for (i = 0; i < qpdb->node_lock_count; i++) {
2498 1.1 christos isc_refcount_destroy(&qpdb->node_locks[i].references);
2499 1.1 christos NODE_DESTROYLOCK(&qpdb->node_locks[i].lock);
2500 1.1 christos }
2501 1.1 christos
2502 1.1 christos /*
2503 1.1 christos * Clean up LRU / re-signing order lists.
2504 1.1 christos */
2505 1.1 christos if (qpdb->lru != NULL) {
2506 1.1 christos for (i = 0; i < qpdb->node_lock_count; i++) {
2507 1.1 christos INSIST(ISC_LIST_EMPTY(qpdb->lru[i]));
2508 1.1 christos }
2509 1.1 christos isc_mem_cput(qpdb->common.mctx, qpdb->lru,
2510 1.1 christos qpdb->node_lock_count,
2511 1.1 christos sizeof(dns_slabheaderlist_t));
2512 1.1 christos }
2513 1.1 christos /*
2514 1.1 christos * Clean up dead node buckets.
2515 1.1 christos */
2516 1.1 christos for (i = 0; i < qpdb->node_lock_count; i++) {
2517 1.1 christos INSIST(isc_queue_empty(&qpdb->deadnodes[i]));
2518 1.1 christos isc_queue_destroy(&qpdb->deadnodes[i]);
2519 1.1 christos }
2520 1.1 christos isc_mem_cput(qpdb->common.mctx, qpdb->deadnodes, qpdb->node_lock_count,
2521 1.1 christos sizeof(qpdb->deadnodes[0]));
2522 1.1 christos
2523 1.1 christos /*
2524 1.1 christos * Clean up heap objects.
2525 1.1 christos */
2526 1.1 christos if (qpdb->heaps != NULL) {
2527 1.1 christos for (i = 0; i < qpdb->node_lock_count; i++) {
2528 1.1 christos isc_heap_destroy(&qpdb->heaps[i]);
2529 1.1 christos }
2530 1.1 christos isc_mem_cput(qpdb->hmctx, qpdb->heaps, qpdb->node_lock_count,
2531 1.1 christos sizeof(isc_heap_t *));
2532 1.1 christos }
2533 1.1 christos
2534 1.1 christos if (qpdb->rrsetstats != NULL) {
2535 1.1 christos dns_stats_detach(&qpdb->rrsetstats);
2536 1.1 christos }
2537 1.1 christos if (qpdb->cachestats != NULL) {
2538 1.1 christos isc_stats_detach(&qpdb->cachestats);
2539 1.1 christos }
2540 1.1 christos if (qpdb->gluecachestats != NULL) {
2541 1.1 christos isc_stats_detach(&qpdb->gluecachestats);
2542 1.1 christos }
2543 1.1 christos
2544 1.1 christos isc_mem_cput(qpdb->common.mctx, qpdb->node_locks, qpdb->node_lock_count,
2545 1.1 christos sizeof(db_nodelock_t));
2546 1.1 christos TREE_DESTROYLOCK(&qpdb->tree_lock);
2547 1.1 christos isc_refcount_destroy(&qpdb->common.references);
2548 1.1 christos
2549 1.1 christos isc_rwlock_destroy(&qpdb->lock);
2550 1.1 christos qpdb->common.magic = 0;
2551 1.1 christos qpdb->common.impmagic = 0;
2552 1.1 christos isc_mem_detach(&qpdb->hmctx);
2553 1.1 christos
2554 1.1 christos isc_mem_putanddetach(&qpdb->common.mctx, qpdb, sizeof(*qpdb));
2555 1.1 christos }
2556 1.1 christos
2557 1.1 christos static void
2558 1.1 christos qpdb_destroy(dns_db_t *arg) {
2559 1.1 christos qpcache_t *qpdb = (qpcache_t *)arg;
2560 1.1 christos bool want_free = false;
2561 1.1 christos unsigned int i;
2562 1.1 christos unsigned int inactive = 0;
2563 1.1 christos
2564 1.1 christos if (qpdb->origin_node != NULL) {
2565 1.1 christos qpcnode_detach(&qpdb->origin_node);
2566 1.1 christos }
2567 1.1 christos
2568 1.1 christos /*
2569 1.1 christos * Even though there are no external direct references, there still
2570 1.1 christos * may be nodes in use.
2571 1.1 christos */
2572 1.1 christos for (i = 0; i < qpdb->node_lock_count; i++) {
2573 1.1 christos isc_rwlocktype_t nodelock = isc_rwlocktype_none;
2574 1.1 christos NODE_WRLOCK(&qpdb->node_locks[i].lock, &nodelock);
2575 1.1 christos qpdb->node_locks[i].exiting = true;
2576 1.1 christos if (isc_refcount_current(&qpdb->node_locks[i].references) == 0)
2577 1.1 christos {
2578 1.1 christos inactive++;
2579 1.1 christos }
2580 1.1 christos NODE_UNLOCK(&qpdb->node_locks[i].lock, &nodelock);
2581 1.1 christos }
2582 1.1 christos
2583 1.1 christos if (inactive != 0) {
2584 1.1 christos RWLOCK(&qpdb->lock, isc_rwlocktype_write);
2585 1.1 christos qpdb->active -= inactive;
2586 1.1 christos if (qpdb->active == 0) {
2587 1.1 christos want_free = true;
2588 1.1 christos }
2589 1.1 christos RWUNLOCK(&qpdb->lock, isc_rwlocktype_write);
2590 1.1 christos if (want_free) {
2591 1.1 christos char buf[DNS_NAME_FORMATSIZE];
2592 1.1 christos if (dns_name_dynamic(&qpdb->common.origin)) {
2593 1.1 christos dns_name_format(&qpdb->common.origin, buf,
2594 1.1 christos sizeof(buf));
2595 1.1 christos } else {
2596 1.1 christos strlcpy(buf, "<UNKNOWN>", sizeof(buf));
2597 1.1 christos }
2598 1.1 christos isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
2599 1.1 christos DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
2600 1.1 christos "calling free_qpdb(%s)", buf);
2601 1.1 christos free_qpdb(qpdb, true);
2602 1.1 christos }
2603 1.1 christos }
2604 1.1 christos }
2605 1.1 christos
2606 1.1 christos static void
2607 1.1 christos mark_ancient(dns_slabheader_t *header) {
2608 1.1 christos setttl(header, 0);
2609 1.1 christos mark(header, DNS_SLABHEADERATTR_ANCIENT);
2610 1.1 christos HEADERNODE(header)->dirty = 1;
2611 1.1 christos }
2612 1.1 christos
2613 1.1 christos /*%
2614 1.1 christos * Clean up dead nodes. These are nodes which have no references, and
2615 1.1 christos * have no data. They are dead but we could not or chose not to delete
2616 1.1 christos * them when we deleted all the data at that node because we did not want
2617 1.1 christos * to wait for the tree write lock.
2618 1.1 christos */
2619 1.1 christos static void
2620 1.1 christos cleanup_deadnodes(void *arg) {
2621 1.1 christos qpcache_t *qpdb = arg;
2622 1.1 christos uint16_t locknum = isc_tid();
2623 1.1 christos isc_rwlocktype_t tlocktype = isc_rwlocktype_none;
2624 1.1 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
2625 1.1 christos qpcnode_t *qpnode = NULL, *qpnext = NULL;
2626 1.1 christos isc_queue_t deadnodes;
2627 1.1 christos
2628 1.1 christos INSIST(locknum < qpdb->node_lock_count);
2629 1.1 christos
2630 1.1 christos isc_queue_init(&deadnodes);
2631 1.1 christos
2632 1.1 christos TREE_WRLOCK(&qpdb->tree_lock, &tlocktype);
2633 1.1 christos NODE_WRLOCK(&qpdb->node_locks[locknum].lock, &nlocktype);
2634 1.1 christos
2635 1.1 christos RUNTIME_CHECK(isc_queue_splice(&deadnodes, &qpdb->deadnodes[locknum]));
2636 1.1 christos isc_queue_for_each_entry_safe(&deadnodes, qpnode, qpnext, deadlink) {
2637 1.1 christos decref(qpdb, qpnode, &nlocktype, &tlocktype, false);
2638 1.1 christos }
2639 1.1 christos
2640 1.1 christos NODE_UNLOCK(&qpdb->node_locks[locknum].lock, &nlocktype);
2641 1.1 christos TREE_UNLOCK(&qpdb->tree_lock, &tlocktype);
2642 1.1 christos }
2643 1.1 christos
2644 1.1 christos /*
2645 1.1 christos * This function is assumed to be called when a node is newly referenced
2646 1.1 christos * and can be in the deadnode list. In that case the node will be references
2647 1.1 christos * and cleanup_deadnodes() will remove it from the list when the cleaning
2648 1.1 christos * happens.
2649 1.1 christos * Note: while a new reference is gained in multiple places, there are only very
2650 1.1 christos * few cases where the node can be in the deadnode list (only empty nodes can
2651 1.1 christos * have been added to the list).
2652 1.1 christos */
2653 1.1 christos static void
2654 1.1 christos reactivate_node(qpcache_t *qpdb, qpcnode_t *node,
2655 1.1 christos isc_rwlocktype_t tlocktype ISC_ATTR_UNUSED DNS__DB_FLARG) {
2656 1.1 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
2657 1.1 christos isc_rwlock_t *nodelock = &qpdb->node_locks[node->locknum].lock;
2658 1.1 christos
2659 1.1 christos NODE_RDLOCK(nodelock, &nlocktype);
2660 1.1 christos newref(qpdb, node, nlocktype, tlocktype DNS__DB_FLARG_PASS);
2661 1.1 christos NODE_UNLOCK(nodelock, &nlocktype);
2662 1.1 christos }
2663 1.1 christos
2664 1.1 christos static qpcnode_t *
2665 1.1 christos new_qpcnode(qpcache_t *qpdb, const dns_name_t *name) {
2666 1.1 christos qpcnode_t *newdata = isc_mem_get(qpdb->common.mctx, sizeof(*newdata));
2667 1.1 christos *newdata = (qpcnode_t){
2668 1.1 christos .name = DNS_NAME_INITEMPTY,
2669 1.1 christos .references = ISC_REFCOUNT_INITIALIZER(1),
2670 1.1 christos .locknum = isc_random_uniform(qpdb->node_lock_count),
2671 1.1 christos };
2672 1.1 christos
2673 1.1 christos INSIST(newdata->locknum < qpdb->node_lock_count);
2674 1.1 christos
2675 1.1 christos isc_mem_attach(qpdb->common.mctx, &newdata->mctx);
2676 1.1 christos dns_name_dupwithoffsets(name, newdata->mctx, &newdata->name);
2677 1.1 christos
2678 1.1 christos #ifdef DNS_DB_NODETRACE
2679 1.1 christos fprintf(stderr, "new_qpcnode:%s:%s:%d:%p->references = 1\n", __func__,
2680 1.1 christos __FILE__, __LINE__ + 1, name);
2681 1.1 christos #endif
2682 1.1 christos return newdata;
2683 1.1 christos }
2684 1.1 christos
2685 1.1 christos static isc_result_t
2686 1.1 christos findnode(dns_db_t *db, const dns_name_t *name, bool create,
2687 1.1 christos dns_dbnode_t **nodep DNS__DB_FLARG) {
2688 1.1 christos qpcache_t *qpdb = (qpcache_t *)db;
2689 1.1 christos qpcnode_t *node = NULL;
2690 1.1 christos isc_result_t result;
2691 1.1 christos isc_rwlocktype_t tlocktype = isc_rwlocktype_none;
2692 1.1 christos
2693 1.1 christos TREE_RDLOCK(&qpdb->tree_lock, &tlocktype);
2694 1.1 christos result = dns_qp_getname(qpdb->tree, name, (void **)&node, NULL);
2695 1.1 christos if (result != ISC_R_SUCCESS) {
2696 1.1 christos if (!create) {
2697 1.1 christos goto unlock;
2698 1.1 christos }
2699 1.1 christos /*
2700 1.1 christos * Try to upgrade the lock and if that fails unlock then relock.
2701 1.1 christos */
2702 1.1 christos TREE_FORCEUPGRADE(&qpdb->tree_lock, &tlocktype);
2703 1.1 christos result = dns_qp_getname(qpdb->tree, name, (void **)&node, NULL);
2704 1.1 christos if (result != ISC_R_SUCCESS) {
2705 1.1 christos node = new_qpcnode(qpdb, name);
2706 1.1 christos result = dns_qp_insert(qpdb->tree, node, 0);
2707 1.1 christos INSIST(result == ISC_R_SUCCESS);
2708 1.1 christos qpcnode_unref(node);
2709 1.1 christos }
2710 1.1 christos }
2711 1.1 christos
2712 1.1 christos reactivate_node(qpdb, node, tlocktype DNS__DB_FLARG_PASS);
2713 1.1 christos
2714 1.1 christos *nodep = (dns_dbnode_t *)node;
2715 1.1 christos unlock:
2716 1.1 christos TREE_UNLOCK(&qpdb->tree_lock, &tlocktype);
2717 1.1 christos
2718 1.1 christos return result;
2719 1.1 christos }
2720 1.1 christos
2721 1.1 christos static void
2722 1.1 christos attachnode(dns_db_t *db, dns_dbnode_t *source,
2723 1.1 christos dns_dbnode_t **targetp DNS__DB_FLARG) {
2724 1.1 christos REQUIRE(VALID_QPDB((qpcache_t *)db));
2725 1.1 christos REQUIRE(targetp != NULL && *targetp == NULL);
2726 1.1 christos
2727 1.1 christos qpcache_t *qpdb = (qpcache_t *)db;
2728 1.1 christos qpcnode_t *node = (qpcnode_t *)source;
2729 1.1 christos
2730 1.1 christos newref(qpdb, node, isc_rwlocktype_none,
2731 1.1 christos isc_rwlocktype_none DNS__DB_FLARG_PASS);
2732 1.1 christos
2733 1.1 christos *targetp = source;
2734 1.1 christos }
2735 1.1 christos
2736 1.1 christos static void
2737 1.1 christos detachnode(dns_db_t *db, dns_dbnode_t **targetp DNS__DB_FLARG) {
2738 1.1 christos qpcache_t *qpdb = (qpcache_t *)db;
2739 1.1 christos qpcnode_t *node = NULL;
2740 1.1 christos bool want_free = false;
2741 1.1 christos bool inactive = false;
2742 1.1 christos db_nodelock_t *nodelock = NULL;
2743 1.1 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
2744 1.1 christos isc_rwlocktype_t tlocktype = isc_rwlocktype_none;
2745 1.1 christos
2746 1.1 christos REQUIRE(VALID_QPDB(qpdb));
2747 1.1 christos REQUIRE(targetp != NULL && *targetp != NULL);
2748 1.1 christos
2749 1.1 christos node = (qpcnode_t *)(*targetp);
2750 1.1 christos nodelock = &qpdb->node_locks[node->locknum];
2751 1.1 christos
2752 1.1 christos NODE_RDLOCK(&nodelock->lock, &nlocktype);
2753 1.1 christos
2754 1.1 christos if (decref(qpdb, node, &nlocktype, &tlocktype, true DNS__DB_FLARG_PASS))
2755 1.1 christos {
2756 1.1 christos if (isc_refcount_current(&nodelock->references) == 0 &&
2757 1.1 christos nodelock->exiting)
2758 1.1 christos {
2759 1.1 christos inactive = true;
2760 1.1 christos }
2761 1.1 christos }
2762 1.1 christos
2763 1.1 christos NODE_UNLOCK(&nodelock->lock, &nlocktype);
2764 1.1 christos INSIST(tlocktype == isc_rwlocktype_none);
2765 1.1 christos
2766 1.1 christos *targetp = NULL;
2767 1.1 christos
2768 1.1 christos if (inactive) {
2769 1.1 christos RWLOCK(&qpdb->lock, isc_rwlocktype_write);
2770 1.1 christos qpdb->active--;
2771 1.1 christos if (qpdb->active == 0) {
2772 1.1 christos want_free = true;
2773 1.1 christos }
2774 1.1 christos RWUNLOCK(&qpdb->lock, isc_rwlocktype_write);
2775 1.1 christos if (want_free) {
2776 1.1 christos char buf[DNS_NAME_FORMATSIZE];
2777 1.1 christos if (dns_name_dynamic(&qpdb->common.origin)) {
2778 1.1 christos dns_name_format(&qpdb->common.origin, buf,
2779 1.1 christos sizeof(buf));
2780 1.1 christos } else {
2781 1.1 christos strlcpy(buf, "<UNKNOWN>", sizeof(buf));
2782 1.1 christos }
2783 1.1 christos isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
2784 1.1 christos DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
2785 1.1 christos "calling free_qpdb(%s)", buf);
2786 1.1 christos free_qpdb(qpdb, true);
2787 1.1 christos }
2788 1.1 christos }
2789 1.1 christos }
2790 1.1 christos
2791 1.1 christos static isc_result_t
2792 1.1 christos createiterator(dns_db_t *db, unsigned int options ISC_ATTR_UNUSED,
2793 1.1 christos dns_dbiterator_t **iteratorp) {
2794 1.1 christos qpcache_t *qpdb = (qpcache_t *)db;
2795 1.1 christos qpc_dbit_t *qpdbiter = NULL;
2796 1.1 christos
2797 1.1 christos REQUIRE(VALID_QPDB(qpdb));
2798 1.1 christos
2799 1.1 christos qpdbiter = isc_mem_get(qpdb->common.mctx, sizeof(*qpdbiter));
2800 1.1 christos *qpdbiter = (qpc_dbit_t){
2801 1.1 christos .common.methods = &dbiterator_methods,
2802 1.1 christos .common.magic = DNS_DBITERATOR_MAGIC,
2803 1.1 christos .paused = true,
2804 1.1 christos };
2805 1.1 christos
2806 1.1 christos qpdbiter->name = dns_fixedname_initname(&qpdbiter->fixed);
2807 1.1 christos dns_db_attach(db, &qpdbiter->common.db);
2808 1.1 christos dns_qpiter_init(qpdb->tree, &qpdbiter->iter);
2809 1.1 christos
2810 1.1 christos *iteratorp = (dns_dbiterator_t *)qpdbiter;
2811 1.1 christos return ISC_R_SUCCESS;
2812 1.1 christos }
2813 1.1 christos
2814 1.1 christos static isc_result_t
2815 1.1 christos allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
2816 1.1 christos unsigned int options, isc_stdtime_t now,
2817 1.1 christos dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) {
2818 1.1 christos qpcache_t *qpdb = (qpcache_t *)db;
2819 1.1 christos qpcnode_t *qpnode = (qpcnode_t *)node;
2820 1.1 christos qpc_rditer_t *iterator = NULL;
2821 1.1 christos
2822 1.1 christos REQUIRE(VALID_QPDB(qpdb));
2823 1.1 christos
2824 1.1 christos UNUSED(version);
2825 1.1 christos
2826 1.1 christos iterator = isc_mem_get(qpdb->common.mctx, sizeof(*iterator));
2827 1.1 christos
2828 1.1 christos if (now == 0) {
2829 1.1 christos now = isc_stdtime_now();
2830 1.1 christos }
2831 1.1 christos
2832 1.1 christos iterator->common.magic = DNS_RDATASETITER_MAGIC;
2833 1.1 christos iterator->common.methods = &rdatasetiter_methods;
2834 1.1 christos iterator->common.db = db;
2835 1.1 christos iterator->common.node = node;
2836 1.1 christos iterator->common.version = NULL;
2837 1.1 christos iterator->common.options = options;
2838 1.1 christos iterator->common.now = now;
2839 1.1 christos iterator->current = NULL;
2840 1.1 christos
2841 1.1 christos newref(qpdb, qpnode, isc_rwlocktype_none,
2842 1.1 christos isc_rwlocktype_none DNS__DB_FLARG_PASS);
2843 1.1 christos
2844 1.1 christos *iteratorp = (dns_rdatasetiter_t *)iterator;
2845 1.1 christos
2846 1.1 christos return ISC_R_SUCCESS;
2847 1.1 christos }
2848 1.1 christos
2849 1.1 christos static bool
2850 1.1 christos overmaxtype(qpcache_t *qpdb, uint32_t ntypes) {
2851 1.1 christos if (qpdb->maxtypepername == 0) {
2852 1.1 christos return false;
2853 1.1 christos }
2854 1.1 christos
2855 1.1 christos return ntypes >= qpdb->maxtypepername;
2856 1.1 christos }
2857 1.1 christos
2858 1.1 christos static bool
2859 1.1 christos prio_header(dns_slabheader_t *header) {
2860 1.1 christos if (NEGATIVE(header) && prio_type(DNS_TYPEPAIR_COVERS(header->type))) {
2861 1.1 christos return true;
2862 1.1 christos }
2863 1.1 christos
2864 1.1 christos return prio_type(header->type);
2865 1.1 christos }
2866 1.1 christos
2867 1.1 christos static isc_result_t
2868 1.1 christos add(qpcache_t *qpdb, qpcnode_t *qpnode,
2869 1.1 christos const dns_name_t *nodename ISC_ATTR_UNUSED, dns_slabheader_t *newheader,
2870 1.1 christos unsigned int options, bool loading, dns_rdataset_t *addedrdataset,
2871 1.1 christos isc_stdtime_t now, isc_rwlocktype_t nlocktype,
2872 1.1 christos isc_rwlocktype_t tlocktype DNS__DB_FLARG) {
2873 1.1 christos dns_slabheader_t *topheader = NULL, *topheader_prev = NULL;
2874 1.1 christos dns_slabheader_t *header = NULL, *sigheader = NULL;
2875 1.1 christos dns_slabheader_t *prioheader = NULL, *expireheader = NULL;
2876 1.1 christos bool header_nx;
2877 1.1 christos bool newheader_nx;
2878 1.1 christos dns_typepair_t negtype = 0;
2879 1.1 christos dns_trust_t trust;
2880 1.1 christos int idx;
2881 1.1 christos uint32_t ntypes = 0;
2882 1.1 christos
2883 1.1 christos if ((options & DNS_DBADD_FORCE) != 0) {
2884 1.1 christos trust = dns_trust_ultimate;
2885 1.1 christos } else {
2886 1.1 christos trust = newheader->trust;
2887 1.1 christos }
2888 1.1 christos
2889 1.1 christos newheader_nx = NONEXISTENT(newheader) ? true : false;
2890 1.1 christos
2891 1.1 christos if (!newheader_nx) {
2892 1.1 christos dns_rdatatype_t rdtype = DNS_TYPEPAIR_TYPE(newheader->type);
2893 1.1 christos dns_rdatatype_t covers = DNS_TYPEPAIR_COVERS(newheader->type);
2894 1.1 christos dns_typepair_t sigtype = DNS_SIGTYPE(covers);
2895 1.1 christos if (NEGATIVE(newheader)) {
2896 1.1 christos /*
2897 1.1 christos * We're adding a negative cache entry.
2898 1.1 christos */
2899 1.1 christos if (covers == dns_rdatatype_any) {
2900 1.1 christos /*
2901 1.1 christos * If we're adding an negative cache entry
2902 1.1 christos * which covers all types (NXDOMAIN,
2903 1.1 christos * NODATA(QTYPE=ANY)),
2904 1.1 christos *
2905 1.1 christos * We make all other data ancient so that the
2906 1.1 christos * only rdataset that can be found at this
2907 1.1 christos * node is the negative cache entry.
2908 1.1 christos */
2909 1.1 christos for (topheader = qpnode->data;
2910 1.1 christos topheader != NULL;
2911 1.1 christos topheader = topheader->next)
2912 1.1 christos {
2913 1.1 christos mark_ancient(topheader);
2914 1.1 christos }
2915 1.1 christos goto find_header;
2916 1.1 christos }
2917 1.1 christos /*
2918 1.1 christos * Otherwise look for any RRSIGs of the given
2919 1.1 christos * type so they can be marked ancient later.
2920 1.1 christos */
2921 1.1 christos for (topheader = qpnode->data; topheader != NULL;
2922 1.1 christos topheader = topheader->next)
2923 1.1 christos {
2924 1.1 christos if (topheader->type == sigtype) {
2925 1.1 christos sigheader = topheader;
2926 1.1 christos break;
2927 1.1 christos }
2928 1.1 christos }
2929 1.1 christos negtype = DNS_TYPEPAIR_VALUE(covers, 0);
2930 1.1 christos } else {
2931 1.1 christos /*
2932 1.1 christos * We're adding something that isn't a
2933 1.1 christos * negative cache entry. Look for an extant
2934 1.1 christos * non-ancient NXDOMAIN/NODATA(QTYPE=ANY) negative
2935 1.1 christos * cache entry. If we're adding an RRSIG, also
2936 1.1 christos * check for an extant non-ancient NODATA ncache
2937 1.1 christos * entry which covers the same type as the RRSIG.
2938 1.1 christos */
2939 1.1 christos for (topheader = qpnode->data; topheader != NULL;
2940 1.1 christos topheader = topheader->next)
2941 1.1 christos {
2942 1.1 christos if ((topheader->type == RDATATYPE_NCACHEANY) ||
2943 1.1 christos (newheader->type == sigtype &&
2944 1.1 christos topheader->type ==
2945 1.1 christos DNS_TYPEPAIR_VALUE(0, covers)))
2946 1.1 christos {
2947 1.1 christos break;
2948 1.1 christos }
2949 1.1 christos }
2950 1.1 christos if (topheader != NULL && EXISTS(topheader) &&
2951 1.1 christos ACTIVE(topheader, now))
2952 1.1 christos {
2953 1.1 christos /*
2954 1.1 christos * Found one.
2955 1.1 christos */
2956 1.1 christos if (trust < topheader->trust) {
2957 1.1 christos /*
2958 1.1 christos * The NXDOMAIN/NODATA(QTYPE=ANY)
2959 1.1 christos * is more trusted.
2960 1.1 christos */
2961 1.1 christos dns_slabheader_destroy(&newheader);
2962 1.1 christos if (addedrdataset != NULL) {
2963 1.1 christos bindrdataset(
2964 1.1 christos qpdb, qpnode, topheader,
2965 1.1 christos now, nlocktype,
2966 1.1 christos tlocktype,
2967 1.1 christos addedrdataset
2968 1.1 christos DNS__DB_FLARG_PASS);
2969 1.1 christos }
2970 1.1 christos return DNS_R_UNCHANGED;
2971 1.1 christos }
2972 1.1 christos /*
2973 1.1 christos * The new rdataset is better. Expire the
2974 1.1 christos * ncache entry.
2975 1.1 christos */
2976 1.1 christos mark_ancient(topheader);
2977 1.1 christos topheader = NULL;
2978 1.1 christos goto find_header;
2979 1.1 christos }
2980 1.1 christos negtype = DNS_TYPEPAIR_VALUE(0, rdtype);
2981 1.1 christos }
2982 1.1 christos }
2983 1.1 christos
2984 1.1 christos for (topheader = qpnode->data; topheader != NULL;
2985 1.1 christos topheader = topheader->next)
2986 1.1 christos {
2987 1.1 christos if (ACTIVE(topheader, now)) {
2988 1.1 christos ++ntypes;
2989 1.1 christos expireheader = topheader;
2990 1.1 christos }
2991 1.1 christos if (prio_header(topheader)) {
2992 1.1 christos prioheader = topheader;
2993 1.1 christos }
2994 1.1 christos
2995 1.1 christos if (topheader->type == newheader->type ||
2996 1.1 christos topheader->type == negtype)
2997 1.1 christos {
2998 1.1 christos break;
2999 1.1 christos }
3000 1.1 christos topheader_prev = topheader;
3001 1.1 christos }
3002 1.1 christos
3003 1.1 christos find_header:
3004 1.1 christos /*
3005 1.1 christos * If header isn't NULL, we've found the right type. There may be
3006 1.1 christos * IGNORE rdatasets between the top of the chain and the first real
3007 1.1 christos * data. We skip over them.
3008 1.1 christos */
3009 1.1 christos header = topheader;
3010 1.1 christos while (header != NULL && IGNORE(header)) {
3011 1.1 christos header = header->down;
3012 1.1 christos }
3013 1.1 christos if (header != NULL) {
3014 1.1 christos header_nx = NONEXISTENT(header) ? true : false;
3015 1.1 christos
3016 1.1 christos /*
3017 1.1 christos * Deleting an already non-existent rdataset has no effect.
3018 1.1 christos */
3019 1.1 christos if (header_nx && newheader_nx) {
3020 1.1 christos dns_slabheader_destroy(&newheader);
3021 1.1 christos return DNS_R_UNCHANGED;
3022 1.1 christos }
3023 1.1 christos
3024 1.1 christos /*
3025 1.1 christos * Trying to add an rdataset with lower trust to a cache
3026 1.1 christos * DB has no effect, provided that the cache data isn't
3027 1.1 christos * stale. If the cache data is stale, new lower trust
3028 1.1 christos * data will supersede it below. Unclear what the best
3029 1.1 christos * policy is here.
3030 1.1 christos */
3031 1.1 christos if (trust < header->trust && (ACTIVE(header, now) || header_nx))
3032 1.1 christos {
3033 1.1 christos dns_slabheader_destroy(&newheader);
3034 1.1 christos if (addedrdataset != NULL) {
3035 1.1 christos bindrdataset(qpdb, qpnode, header, now,
3036 1.1 christos nlocktype, tlocktype,
3037 1.1 christos addedrdataset DNS__DB_FLARG_PASS);
3038 1.1 christos }
3039 1.1 christos return DNS_R_UNCHANGED;
3040 1.1 christos }
3041 1.1 christos
3042 1.1 christos /*
3043 1.1 christos * Don't replace existing NS, A and AAAA RRsets in the
3044 1.1 christos * cache if they are already exist. This prevents named
3045 1.1 christos * being locked to old servers. Don't lower trust of
3046 1.1 christos * existing record if the update is forced. Nothing
3047 1.1 christos * special to be done w.r.t stale data; it gets replaced
3048 1.1 christos * normally further down.
3049 1.1 christos */
3050 1.1 christos if (ACTIVE(header, now) && header->type == dns_rdatatype_ns &&
3051 1.1 christos !header_nx && !newheader_nx &&
3052 1.1 christos header->trust >= newheader->trust &&
3053 1.1 christos dns_rdataslab_equalx((unsigned char *)header,
3054 1.1 christos (unsigned char *)newheader,
3055 1.1 christos (unsigned int)(sizeof(*newheader)),
3056 1.1 christos qpdb->common.rdclass,
3057 1.1 christos (dns_rdatatype_t)header->type))
3058 1.1 christos {
3059 1.1 christos /*
3060 1.1 christos * Honour the new ttl if it is less than the
3061 1.1 christos * older one.
3062 1.1 christos */
3063 1.1 christos if (header->ttl > newheader->ttl) {
3064 1.1 christos setttl(header, newheader->ttl);
3065 1.1 christos }
3066 1.1 christos if (header->last_used != now) {
3067 1.1 christos ISC_LIST_UNLINK(
3068 1.1 christos qpdb->lru[HEADERNODE(header)->locknum],
3069 1.1 christos header, link);
3070 1.1 christos header->last_used = now;
3071 1.1 christos ISC_LIST_PREPEND(
3072 1.1 christos qpdb->lru[HEADERNODE(header)->locknum],
3073 1.1 christos header, link);
3074 1.1 christos }
3075 1.1 christos if (header->noqname == NULL &&
3076 1.1 christos newheader->noqname != NULL)
3077 1.1 christos {
3078 1.1 christos header->noqname = newheader->noqname;
3079 1.1 christos newheader->noqname = NULL;
3080 1.1 christos }
3081 1.1 christos if (header->closest == NULL &&
3082 1.1 christos newheader->closest != NULL)
3083 1.1 christos {
3084 1.1 christos header->closest = newheader->closest;
3085 1.1 christos newheader->closest = NULL;
3086 1.1 christos }
3087 1.1 christos dns_slabheader_destroy(&newheader);
3088 1.1 christos if (addedrdataset != NULL) {
3089 1.1 christos bindrdataset(qpdb, qpnode, header, now,
3090 1.1 christos nlocktype, tlocktype,
3091 1.1 christos addedrdataset DNS__DB_FLARG_PASS);
3092 1.1 christos }
3093 1.1 christos return ISC_R_SUCCESS;
3094 1.1 christos }
3095 1.1 christos
3096 1.1 christos /*
3097 1.1 christos * If we have will be replacing a NS RRset force its TTL
3098 1.1 christos * to be no more than the current NS RRset's TTL. This
3099 1.1 christos * ensures the delegations that are withdrawn are honoured.
3100 1.1 christos */
3101 1.1 christos if (ACTIVE(header, now) && header->type == dns_rdatatype_ns &&
3102 1.1 christos !header_nx && !newheader_nx &&
3103 1.1 christos header->trust <= newheader->trust)
3104 1.1 christos {
3105 1.1 christos if (newheader->ttl > header->ttl) {
3106 1.1 christos newheader->ttl = header->ttl;
3107 1.1 christos }
3108 1.1 christos }
3109 1.1 christos if (ACTIVE(header, now) &&
3110 1.1 christos (options & DNS_DBADD_PREFETCH) == 0 &&
3111 1.1 christos (header->type == dns_rdatatype_a ||
3112 1.1 christos header->type == dns_rdatatype_aaaa ||
3113 1.1 christos header->type == dns_rdatatype_ds ||
3114 1.1 christos header->type == DNS_SIGTYPE(dns_rdatatype_ds)) &&
3115 1.1 christos !header_nx && !newheader_nx &&
3116 1.1 christos header->trust >= newheader->trust &&
3117 1.1 christos dns_rdataslab_equal((unsigned char *)header,
3118 1.1 christos (unsigned char *)newheader,
3119 1.1 christos (unsigned int)(sizeof(*newheader))))
3120 1.1 christos {
3121 1.1 christos /*
3122 1.1 christos * Honour the new ttl if it is less than the
3123 1.1 christos * older one.
3124 1.1 christos */
3125 1.1 christos if (header->ttl > newheader->ttl) {
3126 1.1 christos setttl(header, newheader->ttl);
3127 1.1 christos }
3128 1.1 christos if (header->last_used != now) {
3129 1.1 christos ISC_LIST_UNLINK(
3130 1.1 christos qpdb->lru[HEADERNODE(header)->locknum],
3131 1.1 christos header, link);
3132 1.1 christos header->last_used = now;
3133 1.1 christos ISC_LIST_PREPEND(
3134 1.1 christos qpdb->lru[HEADERNODE(header)->locknum],
3135 1.1 christos header, link);
3136 1.1 christos }
3137 1.1 christos if (header->noqname == NULL &&
3138 1.1 christos newheader->noqname != NULL)
3139 1.1 christos {
3140 1.1 christos header->noqname = newheader->noqname;
3141 1.1 christos newheader->noqname = NULL;
3142 1.1 christos }
3143 1.1 christos if (header->closest == NULL &&
3144 1.1 christos newheader->closest != NULL)
3145 1.1 christos {
3146 1.1 christos header->closest = newheader->closest;
3147 1.1 christos newheader->closest = NULL;
3148 1.1 christos }
3149 1.1 christos dns_slabheader_destroy(&newheader);
3150 1.1 christos if (addedrdataset != NULL) {
3151 1.1 christos bindrdataset(qpdb, qpnode, header, now,
3152 1.1 christos nlocktype, tlocktype,
3153 1.1 christos addedrdataset DNS__DB_FLARG_PASS);
3154 1.1 christos }
3155 1.1 christos return ISC_R_SUCCESS;
3156 1.1 christos }
3157 1.1 christos
3158 1.1 christos if (loading) {
3159 1.1 christos newheader->down = NULL;
3160 1.1 christos idx = HEADERNODE(newheader)->locknum;
3161 1.1 christos if (ZEROTTL(newheader)) {
3162 1.1 christos newheader->last_used = qpdb->last_used + 1;
3163 1.1 christos ISC_LIST_APPEND(qpdb->lru[idx], newheader,
3164 1.1 christos link);
3165 1.1 christos } else {
3166 1.1 christos ISC_LIST_PREPEND(qpdb->lru[idx], newheader,
3167 1.1 christos link);
3168 1.1 christos }
3169 1.1 christos INSIST(qpdb->heaps != NULL);
3170 1.1 christos isc_heap_insert(qpdb->heaps[idx], newheader);
3171 1.1 christos newheader->heap = qpdb->heaps[idx];
3172 1.1 christos
3173 1.1 christos /*
3174 1.1 christos * There are no other references to 'header' when
3175 1.1 christos * loading, so we MAY clean up 'header' now.
3176 1.1 christos * Since we don't generate changed records when
3177 1.1 christos * loading, we MUST clean up 'header' now.
3178 1.1 christos */
3179 1.1 christos if (topheader_prev != NULL) {
3180 1.1 christos topheader_prev->next = newheader;
3181 1.1 christos } else {
3182 1.1 christos qpnode->data = newheader;
3183 1.1 christos }
3184 1.1 christos newheader->next = topheader->next;
3185 1.1 christos dns_slabheader_destroy(&header);
3186 1.1 christos } else {
3187 1.1 christos idx = HEADERNODE(newheader)->locknum;
3188 1.1 christos INSIST(qpdb->heaps != NULL);
3189 1.1 christos isc_heap_insert(qpdb->heaps[idx], newheader);
3190 1.1 christos newheader->heap = qpdb->heaps[idx];
3191 1.1 christos if (ZEROTTL(newheader)) {
3192 1.1 christos newheader->last_used = qpdb->last_used + 1;
3193 1.1 christos ISC_LIST_APPEND(qpdb->lru[idx], newheader,
3194 1.1 christos link);
3195 1.1 christos } else {
3196 1.1 christos ISC_LIST_PREPEND(qpdb->lru[idx], newheader,
3197 1.1 christos link);
3198 1.1 christos }
3199 1.1 christos if (topheader_prev != NULL) {
3200 1.1 christos topheader_prev->next = newheader;
3201 1.1 christos } else {
3202 1.1 christos qpnode->data = newheader;
3203 1.1 christos }
3204 1.1 christos newheader->next = topheader->next;
3205 1.1 christos newheader->down = topheader;
3206 1.1 christos topheader->next = newheader;
3207 1.1 christos qpnode->dirty = 1;
3208 1.1 christos mark_ancient(header);
3209 1.1 christos if (sigheader != NULL) {
3210 1.1 christos mark_ancient(sigheader);
3211 1.1 christos }
3212 1.1 christos }
3213 1.1 christos } else {
3214 1.1 christos /*
3215 1.1 christos * No non-IGNORED rdatasets of the given type exist at
3216 1.1 christos * this node.
3217 1.1 christos */
3218 1.1 christos
3219 1.1 christos /*
3220 1.1 christos * If we're trying to delete the type, don't bother.
3221 1.1 christos */
3222 1.1 christos if (newheader_nx) {
3223 1.1 christos dns_slabheader_destroy(&newheader);
3224 1.1 christos return DNS_R_UNCHANGED;
3225 1.1 christos }
3226 1.1 christos
3227 1.1 christos idx = HEADERNODE(newheader)->locknum;
3228 1.1 christos isc_heap_insert(qpdb->heaps[idx], newheader);
3229 1.1 christos newheader->heap = qpdb->heaps[idx];
3230 1.1 christos if (ZEROTTL(newheader)) {
3231 1.1 christos ISC_LIST_APPEND(qpdb->lru[idx], newheader, link);
3232 1.1 christos } else {
3233 1.1 christos ISC_LIST_PREPEND(qpdb->lru[idx], newheader, link);
3234 1.1 christos }
3235 1.1 christos
3236 1.1 christos if (topheader != NULL) {
3237 1.1 christos /*
3238 1.1 christos * We have a list of rdatasets of the given type,
3239 1.1 christos * but they're all marked IGNORE. We simply insert
3240 1.1 christos * the new rdataset at the head of the list.
3241 1.1 christos *
3242 1.1 christos * Ignored rdatasets cannot occur during loading, so
3243 1.1 christos * we INSIST on it.
3244 1.1 christos */
3245 1.1 christos INSIST(!loading);
3246 1.1 christos if (topheader_prev != NULL) {
3247 1.1 christos topheader_prev->next = newheader;
3248 1.1 christos } else {
3249 1.1 christos qpnode->data = newheader;
3250 1.1 christos }
3251 1.1 christos newheader->next = topheader->next;
3252 1.1 christos newheader->down = topheader;
3253 1.1 christos topheader->next = newheader;
3254 1.1 christos qpnode->dirty = 1;
3255 1.1 christos } else {
3256 1.1 christos /*
3257 1.1 christos * No rdatasets of the given type exist at the node.
3258 1.1 christos */
3259 1.1 christos INSIST(newheader->down == NULL);
3260 1.1 christos
3261 1.1 christos if (prio_header(newheader)) {
3262 1.1 christos /* This is a priority type, prepend it */
3263 1.1 christos newheader->next = qpnode->data;
3264 1.1 christos qpnode->data = newheader;
3265 1.1 christos } else if (prioheader != NULL) {
3266 1.1 christos /* Append after the priority headers */
3267 1.1 christos newheader->next = prioheader->next;
3268 1.1 christos prioheader->next = newheader;
3269 1.1 christos } else {
3270 1.1 christos /* There were no priority headers */
3271 1.1 christos newheader->next = qpnode->data;
3272 1.1 christos qpnode->data = newheader;
3273 1.1 christos }
3274 1.1 christos
3275 1.1 christos if (overmaxtype(qpdb, ntypes)) {
3276 1.1 christos if (expireheader == NULL) {
3277 1.1 christos expireheader = newheader;
3278 1.1 christos }
3279 1.1 christos if (NEGATIVE(newheader) &&
3280 1.1 christos !prio_header(newheader))
3281 1.1 christos {
3282 1.1 christos /*
3283 1.1 christos * Add the new non-priority negative
3284 1.1 christos * header to the database only
3285 1.1 christos * temporarily.
3286 1.1 christos */
3287 1.1 christos expireheader = newheader;
3288 1.1 christos }
3289 1.1 christos
3290 1.1 christos mark_ancient(expireheader);
3291 1.1 christos /*
3292 1.1 christos * FIXME: In theory, we should mark the RRSIG
3293 1.1 christos * and the header at the same time, but there is
3294 1.1 christos * no direct link between those two header, so
3295 1.1 christos * we would have to check the whole list again.
3296 1.1 christos */
3297 1.1 christos }
3298 1.1 christos }
3299 1.1 christos }
3300 1.1 christos
3301 1.1 christos if (addedrdataset != NULL) {
3302 1.1 christos bindrdataset(qpdb, qpnode, newheader, now, nlocktype, tlocktype,
3303 1.1 christos addedrdataset DNS__DB_FLARG_PASS);
3304 1.1 christos }
3305 1.1 christos
3306 1.1 christos return ISC_R_SUCCESS;
3307 1.1 christos }
3308 1.1 christos
3309 1.1 christos static isc_result_t
3310 1.1 christos addnoqname(isc_mem_t *mctx, dns_slabheader_t *newheader, uint32_t maxrrperset,
3311 1.1 christos dns_rdataset_t *rdataset) {
3312 1.1 christos isc_result_t result;
3313 1.1 christos dns_slabheader_proof_t *noqname = NULL;
3314 1.1 christos dns_name_t name = DNS_NAME_INITEMPTY;
3315 1.1 christos dns_rdataset_t neg = DNS_RDATASET_INIT, negsig = DNS_RDATASET_INIT;
3316 1.1 christos isc_region_t r1, r2;
3317 1.1 christos
3318 1.1 christos result = dns_rdataset_getnoqname(rdataset, &name, &neg, &negsig);
3319 1.1 christos RUNTIME_CHECK(result == ISC_R_SUCCESS);
3320 1.1 christos
3321 1.1 christos result = dns_rdataslab_fromrdataset(&neg, mctx, &r1, 0, maxrrperset);
3322 1.1 christos if (result != ISC_R_SUCCESS) {
3323 1.1 christos goto cleanup;
3324 1.1 christos }
3325 1.1 christos
3326 1.1 christos result = dns_rdataslab_fromrdataset(&negsig, mctx, &r2, 0, maxrrperset);
3327 1.1 christos if (result != ISC_R_SUCCESS) {
3328 1.1 christos goto cleanup;
3329 1.1 christos }
3330 1.1 christos
3331 1.1 christos noqname = isc_mem_get(mctx, sizeof(*noqname));
3332 1.1 christos *noqname = (dns_slabheader_proof_t){
3333 1.1 christos .neg = r1.base,
3334 1.1 christos .negsig = r2.base,
3335 1.1 christos .type = neg.type,
3336 1.1 christos .name = DNS_NAME_INITEMPTY,
3337 1.1 christos };
3338 1.1 christos dns_name_dup(&name, mctx, &noqname->name);
3339 1.1 christos newheader->noqname = noqname;
3340 1.1 christos
3341 1.1 christos cleanup:
3342 1.1 christos dns_rdataset_disassociate(&neg);
3343 1.1 christos dns_rdataset_disassociate(&negsig);
3344 1.1 christos
3345 1.1 christos return result;
3346 1.1 christos }
3347 1.1 christos
3348 1.1 christos static isc_result_t
3349 1.1 christos addclosest(isc_mem_t *mctx, dns_slabheader_t *newheader, uint32_t maxrrperset,
3350 1.1 christos dns_rdataset_t *rdataset) {
3351 1.1 christos isc_result_t result;
3352 1.1 christos dns_slabheader_proof_t *closest = NULL;
3353 1.1 christos dns_name_t name = DNS_NAME_INITEMPTY;
3354 1.1 christos dns_rdataset_t neg = DNS_RDATASET_INIT, negsig = DNS_RDATASET_INIT;
3355 1.1 christos isc_region_t r1, r2;
3356 1.1 christos
3357 1.1 christos result = dns_rdataset_getclosest(rdataset, &name, &neg, &negsig);
3358 1.1 christos RUNTIME_CHECK(result == ISC_R_SUCCESS);
3359 1.1 christos
3360 1.1 christos result = dns_rdataslab_fromrdataset(&neg, mctx, &r1, 0, maxrrperset);
3361 1.1 christos if (result != ISC_R_SUCCESS) {
3362 1.1 christos goto cleanup;
3363 1.1 christos }
3364 1.1 christos
3365 1.1 christos result = dns_rdataslab_fromrdataset(&negsig, mctx, &r2, 0, maxrrperset);
3366 1.1 christos if (result != ISC_R_SUCCESS) {
3367 1.1 christos goto cleanup;
3368 1.1 christos }
3369 1.1 christos
3370 1.1 christos closest = isc_mem_get(mctx, sizeof(*closest));
3371 1.1 christos *closest = (dns_slabheader_proof_t){
3372 1.1 christos .neg = r1.base,
3373 1.1 christos .negsig = r2.base,
3374 1.1 christos .name = DNS_NAME_INITEMPTY,
3375 1.1 christos .type = neg.type,
3376 1.1 christos };
3377 1.1 christos dns_name_dup(&name, mctx, &closest->name);
3378 1.1 christos newheader->closest = closest;
3379 1.1 christos
3380 1.1 christos cleanup:
3381 1.1 christos dns_rdataset_disassociate(&neg);
3382 1.1 christos dns_rdataset_disassociate(&negsig);
3383 1.1 christos return result;
3384 1.1 christos }
3385 1.1 christos
3386 1.1 christos static void
3387 1.1 christos expire_ttl_headers(qpcache_t *qpdb, unsigned int locknum,
3388 1.1 christos isc_rwlocktype_t *nlocktypep, isc_rwlocktype_t *tlocktypep,
3389 1.1 christos isc_stdtime_t now, bool cache_is_overmem DNS__DB_FLARG);
3390 1.1 christos
3391 1.1 christos static isc_result_t
3392 1.1 christos addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
3393 1.1 christos isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
3394 1.1 christos dns_rdataset_t *addedrdataset DNS__DB_FLARG) {
3395 1.1 christos qpcache_t *qpdb = (qpcache_t *)db;
3396 1.1 christos qpcnode_t *qpnode = (qpcnode_t *)node;
3397 1.1 christos isc_region_t region;
3398 1.1 christos dns_slabheader_t *newheader = NULL;
3399 1.1 christos isc_result_t result;
3400 1.1 christos bool delegating = false;
3401 1.1 christos bool newnsec;
3402 1.1 christos isc_rwlocktype_t tlocktype = isc_rwlocktype_none;
3403 1.1 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
3404 1.1 christos bool cache_is_overmem = false;
3405 1.1 christos dns_fixedname_t fixed;
3406 1.1 christos dns_name_t *name = NULL;
3407 1.1 christos
3408 1.1 christos REQUIRE(VALID_QPDB(qpdb));
3409 1.1 christos REQUIRE(version == NULL);
3410 1.1 christos
3411 1.1 christos if (now == 0) {
3412 1.1 christos now = isc_stdtime_now();
3413 1.1 christos }
3414 1.1 christos
3415 1.1 christos result = dns_rdataslab_fromrdataset(rdataset, qpdb->common.mctx,
3416 1.1 christos ®ion, sizeof(dns_slabheader_t),
3417 1.1 christos qpdb->maxrrperset);
3418 1.1 christos if (result != ISC_R_SUCCESS) {
3419 1.1 christos if (result == DNS_R_TOOMANYRECORDS) {
3420 1.1 christos dns__db_logtoomanyrecords((dns_db_t *)qpdb,
3421 1.1 christos &qpnode->name, rdataset->type,
3422 1.1 christos "adding", qpdb->maxrrperset);
3423 1.1 christos }
3424 1.1 christos return result;
3425 1.1 christos }
3426 1.1 christos
3427 1.1 christos name = dns_fixedname_initname(&fixed);
3428 1.1 christos dns_name_copy(&qpnode->name, name);
3429 1.1 christos dns_rdataset_getownercase(rdataset, name);
3430 1.1 christos
3431 1.1 christos newheader = (dns_slabheader_t *)region.base;
3432 1.1 christos *newheader = (dns_slabheader_t){
3433 1.1 christos .type = DNS_TYPEPAIR_VALUE(rdataset->type, rdataset->covers),
3434 1.1 christos .trust = rdataset->trust,
3435 1.1 christos .last_used = now,
3436 1.1 christos .node = qpnode,
3437 1.1 christos };
3438 1.1 christos
3439 1.1 christos dns_slabheader_reset(newheader, db, node);
3440 1.1 christos setttl(newheader, rdataset->ttl + now);
3441 1.1 christos if (rdataset->ttl == 0U) {
3442 1.1 christos DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_ZEROTTL);
3443 1.1 christos }
3444 1.1 christos atomic_init(&newheader->count,
3445 1.1 christos atomic_fetch_add_relaxed(&init_count, 1));
3446 1.1 christos if ((rdataset->attributes & DNS_RDATASETATTR_PREFETCH) != 0) {
3447 1.1 christos DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_PREFETCH);
3448 1.1 christos }
3449 1.1 christos if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) {
3450 1.1 christos DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_NEGATIVE);
3451 1.1 christos }
3452 1.1 christos if ((rdataset->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0) {
3453 1.1 christos DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_NXDOMAIN);
3454 1.1 christos }
3455 1.1 christos if ((rdataset->attributes & DNS_RDATASETATTR_OPTOUT) != 0) {
3456 1.1 christos DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_OPTOUT);
3457 1.1 christos }
3458 1.1 christos if ((rdataset->attributes & DNS_RDATASETATTR_NOQNAME) != 0) {
3459 1.1 christos result = addnoqname(qpdb->common.mctx, newheader,
3460 1.1 christos qpdb->maxrrperset, rdataset);
3461 1.1 christos if (result != ISC_R_SUCCESS) {
3462 1.1 christos dns_slabheader_destroy(&newheader);
3463 1.1 christos return result;
3464 1.1 christos }
3465 1.1 christos }
3466 1.1 christos if ((rdataset->attributes & DNS_RDATASETATTR_CLOSEST) != 0) {
3467 1.1 christos result = addclosest(qpdb->common.mctx, newheader,
3468 1.1 christos qpdb->maxrrperset, rdataset);
3469 1.1 christos if (result != ISC_R_SUCCESS) {
3470 1.1 christos dns_slabheader_destroy(&newheader);
3471 1.1 christos return result;
3472 1.1 christos }
3473 1.1 christos }
3474 1.1 christos
3475 1.1 christos /*
3476 1.1 christos * If we're adding a delegation type (which would be an NS or DNAME
3477 1.1 christos * for a zone, but only DNAME counts for a cache), we need to set
3478 1.1 christos * the callback bit on the node.
3479 1.1 christos */
3480 1.1 christos if (rdataset->type == dns_rdatatype_dname) {
3481 1.1 christos delegating = true;
3482 1.1 christos }
3483 1.1 christos
3484 1.1 christos /*
3485 1.1 christos * Add to the auxiliary NSEC tree if we're adding an NSEC record.
3486 1.1 christos */
3487 1.1 christos TREE_RDLOCK(&qpdb->tree_lock, &tlocktype);
3488 1.1 christos if (qpnode->nsec != DNS_DB_NSEC_HAS_NSEC &&
3489 1.1 christos rdataset->type == dns_rdatatype_nsec)
3490 1.1 christos {
3491 1.1 christos newnsec = true;
3492 1.1 christos } else {
3493 1.1 christos newnsec = false;
3494 1.1 christos }
3495 1.1 christos TREE_UNLOCK(&qpdb->tree_lock, &tlocktype);
3496 1.1 christos
3497 1.1 christos /*
3498 1.1 christos * If we're adding a delegation type, adding to the auxiliary NSEC
3499 1.1 christos * tree, or the DB is a cache in an overmem state, hold an
3500 1.1 christos * exclusive lock on the tree. In the latter case the lock does
3501 1.1 christos * not necessarily have to be acquired but it will help purge
3502 1.1 christos * ancient entries more effectively.
3503 1.1 christos */
3504 1.1 christos if (isc_mem_isovermem(qpdb->common.mctx)) {
3505 1.1 christos cache_is_overmem = true;
3506 1.1 christos }
3507 1.1 christos if (delegating || newnsec || cache_is_overmem) {
3508 1.1 christos TREE_WRLOCK(&qpdb->tree_lock, &tlocktype);
3509 1.1 christos }
3510 1.1 christos
3511 1.1 christos if (cache_is_overmem) {
3512 1.1 christos overmem(qpdb, newheader, &tlocktype DNS__DB_FLARG_PASS);
3513 1.1 christos }
3514 1.1 christos
3515 1.1 christos NODE_WRLOCK(&qpdb->node_locks[qpnode->locknum].lock, &nlocktype);
3516 1.1 christos
3517 1.1 christos if (qpdb->rrsetstats != NULL) {
3518 1.1 christos DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_STATCOUNT);
3519 1.1 christos update_rrsetstats(qpdb->rrsetstats, newheader->type,
3520 1.1 christos atomic_load_acquire(&newheader->attributes),
3521 1.1 christos true);
3522 1.1 christos }
3523 1.1 christos
3524 1.1 christos expire_ttl_headers(qpdb, qpnode->locknum, &nlocktype, &tlocktype, now,
3525 1.1 christos cache_is_overmem DNS__DB_FLARG_PASS);
3526 1.1 christos
3527 1.1 christos /*
3528 1.1 christos * If we've been holding a write lock on the tree just for
3529 1.1 christos * cleaning, we can release it now. However, we still need the
3530 1.1 christos * node lock.
3531 1.1 christos */
3532 1.1 christos if (tlocktype == isc_rwlocktype_write && !delegating && !newnsec) {
3533 1.1 christos TREE_UNLOCK(&qpdb->tree_lock, &tlocktype);
3534 1.1 christos }
3535 1.1 christos
3536 1.1 christos result = ISC_R_SUCCESS;
3537 1.1 christos if (newnsec) {
3538 1.1 christos qpcnode_t *nsecnode = NULL;
3539 1.1 christos
3540 1.1 christos result = dns_qp_getname(qpdb->nsec, name, (void **)&nsecnode,
3541 1.1 christos NULL);
3542 1.1 christos if (result == ISC_R_SUCCESS) {
3543 1.1 christos result = ISC_R_SUCCESS;
3544 1.1 christos } else {
3545 1.1 christos INSIST(nsecnode == NULL);
3546 1.1 christos nsecnode = new_qpcnode(qpdb, name);
3547 1.1 christos nsecnode->nsec = DNS_DB_NSEC_NSEC;
3548 1.1 christos result = dns_qp_insert(qpdb->nsec, nsecnode, 0);
3549 1.1 christos INSIST(result == ISC_R_SUCCESS);
3550 1.1 christos qpcnode_detach(&nsecnode);
3551 1.1 christos }
3552 1.1 christos qpnode->nsec = DNS_DB_NSEC_HAS_NSEC;
3553 1.1 christos }
3554 1.1 christos
3555 1.1 christos if (result == ISC_R_SUCCESS) {
3556 1.1 christos result = add(qpdb, qpnode, name, newheader, options, false,
3557 1.1 christos addedrdataset, now, nlocktype,
3558 1.1 christos tlocktype DNS__DB_FLARG_PASS);
3559 1.1 christos }
3560 1.1 christos if (result == ISC_R_SUCCESS && delegating) {
3561 1.1 christos qpnode->delegating = 1;
3562 1.1 christos }
3563 1.1 christos
3564 1.1 christos NODE_UNLOCK(&qpdb->node_locks[qpnode->locknum].lock, &nlocktype);
3565 1.1 christos
3566 1.1 christos if (tlocktype != isc_rwlocktype_none) {
3567 1.1 christos TREE_UNLOCK(&qpdb->tree_lock, &tlocktype);
3568 1.1 christos }
3569 1.1 christos INSIST(tlocktype == isc_rwlocktype_none);
3570 1.1 christos
3571 1.1 christos return result;
3572 1.1 christos }
3573 1.1 christos
3574 1.1 christos static isc_result_t
3575 1.1 christos deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
3576 1.1 christos dns_rdatatype_t type, dns_rdatatype_t covers DNS__DB_FLARG) {
3577 1.1 christos qpcache_t *qpdb = (qpcache_t *)db;
3578 1.1 christos qpcnode_t *qpnode = (qpcnode_t *)node;
3579 1.1 christos isc_result_t result;
3580 1.1 christos dns_slabheader_t *newheader = NULL;
3581 1.1 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
3582 1.1 christos
3583 1.1 christos REQUIRE(VALID_QPDB(qpdb));
3584 1.1 christos REQUIRE(version == NULL);
3585 1.1 christos
3586 1.1 christos if (type == dns_rdatatype_any) {
3587 1.1 christos return ISC_R_NOTIMPLEMENTED;
3588 1.1 christos }
3589 1.1 christos if (type == dns_rdatatype_rrsig && covers == 0) {
3590 1.1 christos return ISC_R_NOTIMPLEMENTED;
3591 1.1 christos }
3592 1.1 christos
3593 1.1 christos newheader = dns_slabheader_new(db, node);
3594 1.1 christos newheader->type = DNS_TYPEPAIR_VALUE(type, covers);
3595 1.1 christos setttl(newheader, 0);
3596 1.1 christos atomic_init(&newheader->attributes, DNS_SLABHEADERATTR_NONEXISTENT);
3597 1.1 christos
3598 1.1 christos NODE_WRLOCK(&qpdb->node_locks[qpnode->locknum].lock, &nlocktype);
3599 1.1 christos result = add(qpdb, qpnode, NULL, newheader, DNS_DBADD_FORCE, false,
3600 1.1 christos NULL, 0, nlocktype,
3601 1.1 christos isc_rwlocktype_none DNS__DB_FLARG_PASS);
3602 1.1 christos NODE_UNLOCK(&qpdb->node_locks[qpnode->locknum].lock, &nlocktype);
3603 1.1 christos
3604 1.1 christos return result;
3605 1.1 christos }
3606 1.1 christos
3607 1.1 christos static unsigned int
3608 1.1 christos nodecount(dns_db_t *db, dns_dbtree_t tree) {
3609 1.1 christos qpcache_t *qpdb = (qpcache_t *)db;
3610 1.1 christos dns_qp_memusage_t mu;
3611 1.1 christos isc_rwlocktype_t tlocktype = isc_rwlocktype_none;
3612 1.1 christos
3613 1.1 christos REQUIRE(VALID_QPDB(qpdb));
3614 1.1 christos
3615 1.1 christos TREE_RDLOCK(&qpdb->tree_lock, &tlocktype);
3616 1.1 christos switch (tree) {
3617 1.1 christos case dns_dbtree_main:
3618 1.1 christos mu = dns_qp_memusage(qpdb->tree);
3619 1.1 christos break;
3620 1.1 christos case dns_dbtree_nsec:
3621 1.1 christos mu = dns_qp_memusage(qpdb->nsec);
3622 1.1 christos break;
3623 1.1 christos default:
3624 1.1 christos UNREACHABLE();
3625 1.1 christos }
3626 1.1 christos TREE_UNLOCK(&qpdb->tree_lock, &tlocktype);
3627 1.1 christos
3628 1.1 christos return mu.leaves;
3629 1.1 christos }
3630 1.1 christos
3631 1.1 christos static isc_result_t
3632 1.1 christos getoriginnode(dns_db_t *db, dns_dbnode_t **nodep DNS__DB_FLARG) {
3633 1.1 christos qpcache_t *qpdb = (qpcache_t *)db;
3634 1.1 christos qpcnode_t *onode = NULL;
3635 1.1 christos isc_result_t result = ISC_R_SUCCESS;
3636 1.1 christos
3637 1.1 christos REQUIRE(VALID_QPDB(qpdb));
3638 1.1 christos REQUIRE(nodep != NULL && *nodep == NULL);
3639 1.1 christos
3640 1.1 christos /* Note that the access to origin_node doesn't require a DB lock */
3641 1.1 christos onode = (qpcnode_t *)qpdb->origin_node;
3642 1.1 christos if (onode != NULL) {
3643 1.1 christos newref(qpdb, onode, isc_rwlocktype_none,
3644 1.1 christos isc_rwlocktype_none DNS__DB_FLARG_PASS);
3645 1.1 christos *nodep = qpdb->origin_node;
3646 1.1 christos } else {
3647 1.1 christos result = ISC_R_NOTFOUND;
3648 1.1 christos }
3649 1.1 christos
3650 1.1 christos return result;
3651 1.1 christos }
3652 1.1 christos
3653 1.1 christos static void
3654 1.1 christos locknode(dns_db_t *db, dns_dbnode_t *node, isc_rwlocktype_t type) {
3655 1.1 christos qpcache_t *qpdb = (qpcache_t *)db;
3656 1.1 christos qpcnode_t *qpnode = (qpcnode_t *)node;
3657 1.1 christos
3658 1.1 christos RWLOCK(&qpdb->node_locks[qpnode->locknum].lock, type);
3659 1.1 christos }
3660 1.1 christos
3661 1.1 christos static void
3662 1.1 christos unlocknode(dns_db_t *db, dns_dbnode_t *node, isc_rwlocktype_t type) {
3663 1.1 christos qpcache_t *qpdb = (qpcache_t *)db;
3664 1.1 christos qpcnode_t *qpnode = (qpcnode_t *)node;
3665 1.1 christos
3666 1.1 christos RWUNLOCK(&qpdb->node_locks[qpnode->locknum].lock, type);
3667 1.1 christos }
3668 1.1 christos
3669 1.1 christos isc_result_t
3670 1.1 christos dns__qpcache_create(isc_mem_t *mctx, const dns_name_t *origin,
3671 1.1 christos dns_dbtype_t type, dns_rdataclass_t rdclass,
3672 1.1 christos unsigned int argc, char *argv[],
3673 1.1 christos void *driverarg ISC_ATTR_UNUSED, dns_db_t **dbp) {
3674 1.1 christos qpcache_t *qpdb = NULL;
3675 1.1 christos isc_mem_t *hmctx = mctx;
3676 1.1 christos isc_loop_t *loop = isc_loop();
3677 1.1 christos int i;
3678 1.1 christos
3679 1.1 christos /* This database implementation only supports cache semantics */
3680 1.1 christos REQUIRE(type == dns_dbtype_cache);
3681 1.1 christos REQUIRE(loop != NULL);
3682 1.1 christos
3683 1.1 christos qpdb = isc_mem_get(mctx, sizeof(*qpdb));
3684 1.1 christos *qpdb = (qpcache_t){
3685 1.1 christos .common.methods = &qpdb_cachemethods,
3686 1.1 christos .common.origin = DNS_NAME_INITEMPTY,
3687 1.1 christos .common.rdclass = rdclass,
3688 1.1 christos .common.attributes = DNS_DBATTR_CACHE,
3689 1.1 christos .loopmgr = isc_loop_getloopmgr(loop),
3690 1.1 christos };
3691 1.1 christos
3692 1.1 christos isc_refcount_init(&qpdb->common.references, 1);
3693 1.1 christos
3694 1.1 christos /*
3695 1.1 christos * If argv[0] exists, it points to a memory context to use for heap
3696 1.1 christos */
3697 1.1 christos if (argc != 0) {
3698 1.1 christos hmctx = (isc_mem_t *)argv[0];
3699 1.1 christos }
3700 1.1 christos
3701 1.1 christos isc_rwlock_init(&qpdb->lock);
3702 1.1 christos TREE_INITLOCK(&qpdb->tree_lock);
3703 1.1 christos
3704 1.1 christos qpdb->node_lock_count = isc_loopmgr_nloops(qpdb->loopmgr);
3705 1.1 christos qpdb->node_locks = isc_mem_cget(mctx, qpdb->node_lock_count,
3706 1.1 christos sizeof(db_nodelock_t));
3707 1.1 christos
3708 1.1 christos dns_rdatasetstats_create(mctx, &qpdb->rrsetstats);
3709 1.1 christos qpdb->lru = isc_mem_cget(mctx, qpdb->node_lock_count,
3710 1.1 christos sizeof(dns_slabheaderlist_t));
3711 1.1 christos for (i = 0; i < (int)qpdb->node_lock_count; i++) {
3712 1.1 christos ISC_LIST_INIT(qpdb->lru[i]);
3713 1.1 christos }
3714 1.1 christos
3715 1.1 christos /*
3716 1.1 christos * Create the heaps.
3717 1.1 christos */
3718 1.1 christos qpdb->heaps = isc_mem_cget(hmctx, qpdb->node_lock_count,
3719 1.1 christos sizeof(isc_heap_t *));
3720 1.1 christos for (i = 0; i < (int)qpdb->node_lock_count; i++) {
3721 1.1 christos isc_heap_create(hmctx, ttl_sooner, set_index, 0,
3722 1.1 christos &qpdb->heaps[i]);
3723 1.1 christos }
3724 1.1 christos
3725 1.1 christos /*
3726 1.1 christos * Create deadnode lists.
3727 1.1 christos */
3728 1.1 christos qpdb->deadnodes = isc_mem_cget(mctx, qpdb->node_lock_count,
3729 1.1 christos sizeof(qpdb->deadnodes[0]));
3730 1.1 christos for (i = 0; i < (int)(qpdb->node_lock_count); i++) {
3731 1.1 christos isc_queue_init(&qpdb->deadnodes[i]);
3732 1.1 christos }
3733 1.1 christos
3734 1.1 christos qpdb->active = qpdb->node_lock_count;
3735 1.1 christos
3736 1.1 christos for (i = 0; i < (int)(qpdb->node_lock_count); i++) {
3737 1.1 christos NODE_INITLOCK(&qpdb->node_locks[i].lock);
3738 1.1 christos isc_refcount_init(&qpdb->node_locks[i].references, 0);
3739 1.1 christos qpdb->node_locks[i].exiting = false;
3740 1.1 christos }
3741 1.1 christos
3742 1.1 christos /*
3743 1.1 christos * Attach to the mctx. The database will persist so long as there
3744 1.1 christos * are references to it, and attaching to the mctx ensures that our
3745 1.1 christos * mctx won't disappear out from under us.
3746 1.1 christos */
3747 1.1 christos isc_mem_attach(mctx, &qpdb->common.mctx);
3748 1.1 christos isc_mem_attach(hmctx, &qpdb->hmctx);
3749 1.1 christos
3750 1.1 christos /*
3751 1.1 christos * Make a copy of the origin name.
3752 1.1 christos */
3753 1.1 christos dns_name_dupwithoffsets(origin, mctx, &qpdb->common.origin);
3754 1.1 christos
3755 1.1 christos /*
3756 1.1 christos * Make the qp tries.
3757 1.1 christos */
3758 1.1 christos dns_qp_create(mctx, &qpmethods, qpdb, &qpdb->tree);
3759 1.1 christos dns_qp_create(mctx, &qpmethods, qpdb, &qpdb->nsec);
3760 1.1 christos
3761 1.1 christos qpdb->common.magic = DNS_DB_MAGIC;
3762 1.1 christos qpdb->common.impmagic = QPDB_MAGIC;
3763 1.1 christos
3764 1.1 christos *dbp = (dns_db_t *)qpdb;
3765 1.1 christos
3766 1.1 christos return ISC_R_SUCCESS;
3767 1.1 christos }
3768 1.1 christos
3769 1.1 christos /*
3770 1.1 christos * Rdataset Iterator Methods
3771 1.1 christos */
3772 1.1 christos
3773 1.1 christos static void
3774 1.1 christos rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) {
3775 1.1 christos qpc_rditer_t *iterator = NULL;
3776 1.1 christos
3777 1.1 christos iterator = (qpc_rditer_t *)(*iteratorp);
3778 1.1 christos
3779 1.1 christos dns__db_detachnode(iterator->common.db,
3780 1.1 christos &iterator->common.node DNS__DB_FLARG_PASS);
3781 1.1 christos isc_mem_put(iterator->common.db->mctx, iterator, sizeof(*iterator));
3782 1.1 christos
3783 1.1 christos *iteratorp = NULL;
3784 1.1 christos }
3785 1.1 christos
3786 1.1 christos static bool
3787 1.1 christos iterator_active(qpcache_t *qpdb, qpc_rditer_t *iterator,
3788 1.1 christos dns_slabheader_t *header) {
3789 1.1 christos dns_ttl_t stale_ttl = header->ttl + STALE_TTL(header, qpdb);
3790 1.1 christos
3791 1.1 christos /*
3792 1.1 christos * Is this a "this rdataset doesn't exist" record?
3793 1.1 christos */
3794 1.1 christos if (NONEXISTENT(header)) {
3795 1.1 christos return false;
3796 1.1 christos }
3797 1.1 christos
3798 1.1 christos /*
3799 1.1 christos * If this header is still active then return it.
3800 1.1 christos */
3801 1.1 christos if (ACTIVE(header, iterator->common.now)) {
3802 1.1 christos return true;
3803 1.1 christos }
3804 1.1 christos
3805 1.1 christos /*
3806 1.1 christos * If we are not returning stale records or the rdataset is
3807 1.1 christos * too old don't return it.
3808 1.1 christos */
3809 1.1 christos if (!STALEOK(iterator) || (iterator->common.now > stale_ttl)) {
3810 1.1 christos return false;
3811 1.1 christos }
3812 1.1 christos return true;
3813 1.1 christos }
3814 1.1 christos
3815 1.1 christos static isc_result_t
3816 1.1 christos rdatasetiter_first(dns_rdatasetiter_t *it DNS__DB_FLARG) {
3817 1.1 christos qpc_rditer_t *iterator = (qpc_rditer_t *)it;
3818 1.1 christos qpcache_t *qpdb = (qpcache_t *)(iterator->common.db);
3819 1.1 christos qpcnode_t *qpnode = iterator->common.node;
3820 1.1 christos dns_slabheader_t *header = NULL, *top_next = NULL;
3821 1.1 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
3822 1.1 christos
3823 1.1 christos NODE_RDLOCK(&qpdb->node_locks[qpnode->locknum].lock, &nlocktype);
3824 1.1 christos
3825 1.1 christos for (header = qpnode->data; header != NULL; header = top_next) {
3826 1.1 christos top_next = header->next;
3827 1.1 christos do {
3828 1.1 christos if (EXPIREDOK(iterator)) {
3829 1.1 christos if (!NONEXISTENT(header)) {
3830 1.1 christos break;
3831 1.1 christos }
3832 1.1 christos header = header->down;
3833 1.1 christos } else if (!IGNORE(header)) {
3834 1.1 christos if (!iterator_active(qpdb, iterator, header)) {
3835 1.1 christos header = NULL;
3836 1.1 christos }
3837 1.1 christos break;
3838 1.1 christos } else {
3839 1.1 christos header = header->down;
3840 1.1 christos }
3841 1.1 christos } while (header != NULL);
3842 1.1 christos if (header != NULL) {
3843 1.1 christos break;
3844 1.1 christos }
3845 1.1 christos }
3846 1.1 christos
3847 1.1 christos NODE_UNLOCK(&qpdb->node_locks[qpnode->locknum].lock, &nlocktype);
3848 1.1 christos
3849 1.1 christos iterator->current = header;
3850 1.1 christos
3851 1.1 christos if (header == NULL) {
3852 1.1 christos return ISC_R_NOMORE;
3853 1.1 christos }
3854 1.1 christos
3855 1.1 christos return ISC_R_SUCCESS;
3856 1.1 christos }
3857 1.1 christos
3858 1.1 christos static isc_result_t
3859 1.1 christos rdatasetiter_next(dns_rdatasetiter_t *it DNS__DB_FLARG) {
3860 1.1 christos qpc_rditer_t *iterator = (qpc_rditer_t *)it;
3861 1.1 christos qpcache_t *qpdb = (qpcache_t *)(iterator->common.db);
3862 1.1 christos qpcnode_t *qpnode = iterator->common.node;
3863 1.1 christos dns_slabheader_t *header = NULL, *top_next = NULL;
3864 1.1 christos dns_typepair_t type, negtype;
3865 1.1 christos dns_rdatatype_t rdtype, covers;
3866 1.1 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
3867 1.1 christos bool expiredok = EXPIREDOK(iterator);
3868 1.1 christos
3869 1.1 christos header = iterator->current;
3870 1.1 christos if (header == NULL) {
3871 1.1 christos return ISC_R_NOMORE;
3872 1.1 christos }
3873 1.1 christos
3874 1.1 christos NODE_RDLOCK(&qpdb->node_locks[qpnode->locknum].lock, &nlocktype);
3875 1.1 christos
3876 1.1 christos type = header->type;
3877 1.1 christos rdtype = DNS_TYPEPAIR_TYPE(header->type);
3878 1.1 christos if (NEGATIVE(header)) {
3879 1.1 christos covers = DNS_TYPEPAIR_COVERS(header->type);
3880 1.1 christos negtype = DNS_TYPEPAIR_VALUE(covers, 0);
3881 1.1 christos } else {
3882 1.1 christos negtype = DNS_TYPEPAIR_VALUE(0, rdtype);
3883 1.1 christos }
3884 1.1 christos
3885 1.1 christos /*
3886 1.1 christos * Find the start of the header chain for the next type
3887 1.1 christos * by walking back up the list.
3888 1.1 christos */
3889 1.1 christos top_next = header->next;
3890 1.1 christos while (top_next != NULL &&
3891 1.1 christos (top_next->type == type || top_next->type == negtype))
3892 1.1 christos {
3893 1.1 christos top_next = top_next->next;
3894 1.1 christos }
3895 1.1 christos if (expiredok) {
3896 1.1 christos /*
3897 1.1 christos * Keep walking down the list if possible or
3898 1.1 christos * start the next type.
3899 1.1 christos */
3900 1.1 christos header = header->down != NULL ? header->down : top_next;
3901 1.1 christos } else {
3902 1.1 christos header = top_next;
3903 1.1 christos }
3904 1.1 christos for (; header != NULL; header = top_next) {
3905 1.1 christos top_next = header->next;
3906 1.1 christos do {
3907 1.1 christos if (expiredok) {
3908 1.1 christos if (!NONEXISTENT(header)) {
3909 1.1 christos break;
3910 1.1 christos }
3911 1.1 christos header = header->down;
3912 1.1 christos } else if (!IGNORE(header)) {
3913 1.1 christos if (!iterator_active(qpdb, iterator, header)) {
3914 1.1 christos header = NULL;
3915 1.1 christos }
3916 1.1 christos break;
3917 1.1 christos } else {
3918 1.1 christos header = header->down;
3919 1.1 christos }
3920 1.1 christos } while (header != NULL);
3921 1.1 christos if (header != NULL) {
3922 1.1 christos break;
3923 1.1 christos }
3924 1.1 christos /*
3925 1.1 christos * Find the start of the header chain for the next type
3926 1.1 christos * by walking back up the list.
3927 1.1 christos */
3928 1.1 christos while (top_next != NULL &&
3929 1.1 christos (top_next->type == type || top_next->type == negtype))
3930 1.1 christos {
3931 1.1 christos top_next = top_next->next;
3932 1.1 christos }
3933 1.1 christos }
3934 1.1 christos
3935 1.1 christos NODE_UNLOCK(&qpdb->node_locks[qpnode->locknum].lock, &nlocktype);
3936 1.1 christos
3937 1.1 christos iterator->current = header;
3938 1.1 christos
3939 1.1 christos if (header == NULL) {
3940 1.1 christos return ISC_R_NOMORE;
3941 1.1 christos }
3942 1.1 christos
3943 1.1 christos return ISC_R_SUCCESS;
3944 1.1 christos }
3945 1.1 christos
3946 1.1 christos static void
3947 1.1 christos rdatasetiter_current(dns_rdatasetiter_t *it,
3948 1.1 christos dns_rdataset_t *rdataset DNS__DB_FLARG) {
3949 1.1 christos qpc_rditer_t *iterator = (qpc_rditer_t *)it;
3950 1.1 christos qpcache_t *qpdb = (qpcache_t *)(iterator->common.db);
3951 1.1 christos qpcnode_t *qpnode = iterator->common.node;
3952 1.1 christos dns_slabheader_t *header = NULL;
3953 1.1 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
3954 1.1 christos
3955 1.1 christos header = iterator->current;
3956 1.1 christos REQUIRE(header != NULL);
3957 1.1 christos
3958 1.1 christos NODE_RDLOCK(&qpdb->node_locks[qpnode->locknum].lock, &nlocktype);
3959 1.1 christos
3960 1.1 christos bindrdataset(qpdb, qpnode, header, iterator->common.now, nlocktype,
3961 1.1 christos isc_rwlocktype_none, rdataset DNS__DB_FLARG_PASS);
3962 1.1 christos
3963 1.1 christos NODE_UNLOCK(&qpdb->node_locks[qpnode->locknum].lock, &nlocktype);
3964 1.1 christos }
3965 1.1 christos
3966 1.1 christos /*
3967 1.1 christos * Database Iterator Methods
3968 1.1 christos */
3969 1.1 christos
3970 1.1 christos static void
3971 1.1 christos reference_iter_node(qpc_dbit_t *qpdbiter DNS__DB_FLARG) {
3972 1.1 christos qpcache_t *qpdb = (qpcache_t *)qpdbiter->common.db;
3973 1.1 christos qpcnode_t *node = qpdbiter->node;
3974 1.1 christos
3975 1.1 christos if (node == NULL) {
3976 1.1 christos return;
3977 1.1 christos }
3978 1.1 christos
3979 1.1 christos INSIST(qpdbiter->tree_locked != isc_rwlocktype_none);
3980 1.1 christos reactivate_node(qpdb, node, qpdbiter->tree_locked DNS__DB_FLARG_PASS);
3981 1.1 christos }
3982 1.1 christos
3983 1.1 christos static void
3984 1.1 christos dereference_iter_node(qpc_dbit_t *qpdbiter DNS__DB_FLARG) {
3985 1.1 christos qpcache_t *qpdb = (qpcache_t *)qpdbiter->common.db;
3986 1.1 christos qpcnode_t *node = qpdbiter->node;
3987 1.1 christos isc_rwlock_t *lock = NULL;
3988 1.1 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
3989 1.1 christos isc_rwlocktype_t tlocktype = qpdbiter->tree_locked;
3990 1.1 christos
3991 1.1 christos if (node == NULL) {
3992 1.1 christos return;
3993 1.1 christos }
3994 1.1 christos
3995 1.1 christos REQUIRE(tlocktype != isc_rwlocktype_write);
3996 1.1 christos
3997 1.1 christos lock = &qpdb->node_locks[node->locknum].lock;
3998 1.1 christos NODE_RDLOCK(lock, &nlocktype);
3999 1.1 christos decref(qpdb, node, &nlocktype, &qpdbiter->tree_locked,
4000 1.1 christos false DNS__DB_FLARG_PASS);
4001 1.1 christos NODE_UNLOCK(lock, &nlocktype);
4002 1.1 christos
4003 1.1 christos INSIST(qpdbiter->tree_locked == tlocktype);
4004 1.1 christos
4005 1.1 christos qpdbiter->node = NULL;
4006 1.1 christos }
4007 1.1 christos
4008 1.1 christos static void
4009 1.1 christos resume_iteration(qpc_dbit_t *qpdbiter, bool continuing) {
4010 1.1 christos qpcache_t *qpdb = (qpcache_t *)qpdbiter->common.db;
4011 1.1 christos
4012 1.1 christos REQUIRE(qpdbiter->paused);
4013 1.1 christos REQUIRE(qpdbiter->tree_locked == isc_rwlocktype_none);
4014 1.1 christos
4015 1.1 christos TREE_RDLOCK(&qpdb->tree_lock, &qpdbiter->tree_locked);
4016 1.1 christos
4017 1.1 christos /*
4018 1.1 christos * If we're being called from dbiterator_next or _prev,
4019 1.1 christos * then we may need to reinitialize the iterator to the current
4020 1.1 christos * name. The tree could have changed while it was unlocked,
4021 1.1 christos * would make the iterator traversal inconsistent.
4022 1.1 christos *
4023 1.1 christos * As long as the iterator is holding a reference to
4024 1.1 christos * qpdbiter->node, the node won't be removed from the tree,
4025 1.1 christos * so the lookup should always succeed.
4026 1.1 christos */
4027 1.1 christos if (continuing && qpdbiter->node != NULL) {
4028 1.1 christos isc_result_t result;
4029 1.1 christos result = dns_qp_lookup(qpdb->tree, qpdbiter->name, NULL,
4030 1.1 christos &qpdbiter->iter, NULL, NULL, NULL);
4031 1.1 christos INSIST(result == ISC_R_SUCCESS);
4032 1.1 christos }
4033 1.1 christos
4034 1.1 christos qpdbiter->paused = false;
4035 1.1 christos }
4036 1.1 christos
4037 1.1 christos static void
4038 1.1 christos dbiterator_destroy(dns_dbiterator_t **iteratorp DNS__DB_FLARG) {
4039 1.1 christos qpc_dbit_t *qpdbiter = (qpc_dbit_t *)(*iteratorp);
4040 1.1 christos qpcache_t *qpdb = (qpcache_t *)qpdbiter->common.db;
4041 1.1 christos dns_db_t *db = NULL;
4042 1.1 christos
4043 1.1 christos if (qpdbiter->tree_locked == isc_rwlocktype_read) {
4044 1.1 christos TREE_UNLOCK(&qpdb->tree_lock, &qpdbiter->tree_locked);
4045 1.1 christos }
4046 1.1 christos INSIST(qpdbiter->tree_locked == isc_rwlocktype_none);
4047 1.1 christos
4048 1.1 christos dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
4049 1.1 christos
4050 1.1 christos dns_db_attach(qpdbiter->common.db, &db);
4051 1.1 christos dns_db_detach(&qpdbiter->common.db);
4052 1.1 christos
4053 1.1 christos isc_mem_put(db->mctx, qpdbiter, sizeof(*qpdbiter));
4054 1.1 christos dns_db_detach(&db);
4055 1.1 christos
4056 1.1 christos *iteratorp = NULL;
4057 1.1 christos }
4058 1.1 christos
4059 1.1 christos static isc_result_t
4060 1.1 christos dbiterator_first(dns_dbiterator_t *iterator DNS__DB_FLARG) {
4061 1.1 christos isc_result_t result;
4062 1.1 christos qpc_dbit_t *qpdbiter = (qpc_dbit_t *)iterator;
4063 1.1 christos qpcache_t *qpdb = (qpcache_t *)iterator->db;
4064 1.1 christos
4065 1.1 christos if (qpdbiter->result != ISC_R_SUCCESS &&
4066 1.1 christos qpdbiter->result != ISC_R_NOTFOUND &&
4067 1.1 christos qpdbiter->result != DNS_R_PARTIALMATCH &&
4068 1.1 christos qpdbiter->result != ISC_R_NOMORE)
4069 1.1 christos {
4070 1.1 christos return qpdbiter->result;
4071 1.1 christos }
4072 1.1 christos
4073 1.1 christos if (qpdbiter->paused) {
4074 1.1 christos resume_iteration(qpdbiter, false);
4075 1.1 christos }
4076 1.1 christos
4077 1.1 christos dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
4078 1.1 christos
4079 1.1 christos dns_qpiter_init(qpdb->tree, &qpdbiter->iter);
4080 1.1 christos result = dns_qpiter_next(&qpdbiter->iter, NULL,
4081 1.1 christos (void **)&qpdbiter->node, NULL);
4082 1.1 christos
4083 1.1 christos if (result == ISC_R_SUCCESS) {
4084 1.1 christos dns_name_copy(&qpdbiter->node->name, qpdbiter->name);
4085 1.1 christos reference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
4086 1.1 christos } else {
4087 1.1 christos INSIST(result == ISC_R_NOMORE); /* The tree is empty. */
4088 1.1 christos qpdbiter->node = NULL;
4089 1.1 christos }
4090 1.1 christos
4091 1.1 christos qpdbiter->result = result;
4092 1.1 christos
4093 1.1 christos if (result != ISC_R_SUCCESS) {
4094 1.1 christos ENSURE(!qpdbiter->paused);
4095 1.1 christos }
4096 1.1 christos
4097 1.1 christos return result;
4098 1.1 christos }
4099 1.1 christos
4100 1.1 christos static isc_result_t
4101 1.1 christos dbiterator_last(dns_dbiterator_t *iterator DNS__DB_FLARG) {
4102 1.1 christos isc_result_t result;
4103 1.1 christos qpc_dbit_t *qpdbiter = (qpc_dbit_t *)iterator;
4104 1.1 christos qpcache_t *qpdb = (qpcache_t *)iterator->db;
4105 1.1 christos
4106 1.1 christos if (qpdbiter->result != ISC_R_SUCCESS &&
4107 1.1 christos qpdbiter->result != ISC_R_NOTFOUND &&
4108 1.1 christos qpdbiter->result != DNS_R_PARTIALMATCH &&
4109 1.1 christos qpdbiter->result != ISC_R_NOMORE)
4110 1.1 christos {
4111 1.1 christos return qpdbiter->result;
4112 1.1 christos }
4113 1.1 christos
4114 1.1 christos if (qpdbiter->paused) {
4115 1.1 christos resume_iteration(qpdbiter, false);
4116 1.1 christos }
4117 1.1 christos
4118 1.1 christos dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
4119 1.1 christos
4120 1.1 christos dns_qpiter_init(qpdb->tree, &qpdbiter->iter);
4121 1.1 christos result = dns_qpiter_prev(&qpdbiter->iter, NULL,
4122 1.1 christos (void **)&qpdbiter->node, NULL);
4123 1.1 christos
4124 1.1 christos if (result == ISC_R_SUCCESS) {
4125 1.1 christos dns_name_copy(&qpdbiter->node->name, qpdbiter->name);
4126 1.1 christos reference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
4127 1.1 christos } else {
4128 1.1 christos INSIST(result == ISC_R_NOMORE); /* The tree is empty. */
4129 1.1 christos qpdbiter->node = NULL;
4130 1.1 christos }
4131 1.1 christos
4132 1.1 christos qpdbiter->result = result;
4133 1.1 christos return result;
4134 1.1 christos }
4135 1.1 christos
4136 1.1 christos static isc_result_t
4137 1.1 christos dbiterator_seek(dns_dbiterator_t *iterator,
4138 1.1 christos const dns_name_t *name DNS__DB_FLARG) {
4139 1.1 christos isc_result_t result;
4140 1.1 christos qpc_dbit_t *qpdbiter = (qpc_dbit_t *)iterator;
4141 1.1 christos qpcache_t *qpdb = (qpcache_t *)iterator->db;
4142 1.1 christos
4143 1.1 christos if (qpdbiter->result != ISC_R_SUCCESS &&
4144 1.1 christos qpdbiter->result != ISC_R_NOTFOUND &&
4145 1.1 christos qpdbiter->result != DNS_R_PARTIALMATCH &&
4146 1.1 christos qpdbiter->result != ISC_R_NOMORE)
4147 1.1 christos {
4148 1.1 christos return qpdbiter->result;
4149 1.1 christos }
4150 1.1 christos
4151 1.1 christos if (qpdbiter->paused) {
4152 1.1 christos resume_iteration(qpdbiter, false);
4153 1.1 christos }
4154 1.1 christos
4155 1.1 christos dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
4156 1.1 christos
4157 1.1 christos result = dns_qp_lookup(qpdb->tree, name, NULL, &qpdbiter->iter, NULL,
4158 1.1 christos (void **)&qpdbiter->node, NULL);
4159 1.1 christos
4160 1.1 christos if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
4161 1.1 christos dns_name_copy(&qpdbiter->node->name, qpdbiter->name);
4162 1.1 christos reference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
4163 1.1 christos } else {
4164 1.1 christos qpdbiter->node = NULL;
4165 1.1 christos }
4166 1.1 christos
4167 1.1 christos qpdbiter->result = (result == DNS_R_PARTIALMATCH) ? ISC_R_SUCCESS
4168 1.1 christos : result;
4169 1.1 christos return result;
4170 1.1 christos }
4171 1.1 christos
4172 1.1 christos static isc_result_t
4173 1.1 christos dbiterator_prev(dns_dbiterator_t *iterator DNS__DB_FLARG) {
4174 1.1 christos isc_result_t result;
4175 1.1 christos qpc_dbit_t *qpdbiter = (qpc_dbit_t *)iterator;
4176 1.1 christos
4177 1.1 christos REQUIRE(qpdbiter->node != NULL);
4178 1.1 christos
4179 1.1 christos if (qpdbiter->result != ISC_R_SUCCESS) {
4180 1.1 christos return qpdbiter->result;
4181 1.1 christos }
4182 1.1 christos
4183 1.1 christos if (qpdbiter->paused) {
4184 1.1 christos resume_iteration(qpdbiter, true);
4185 1.1 christos }
4186 1.1 christos
4187 1.1 christos dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
4188 1.1 christos
4189 1.1 christos result = dns_qpiter_prev(&qpdbiter->iter, NULL,
4190 1.1 christos (void **)&qpdbiter->node, NULL);
4191 1.1 christos
4192 1.1 christos if (result == ISC_R_SUCCESS) {
4193 1.1 christos dns_name_copy(&qpdbiter->node->name, qpdbiter->name);
4194 1.1 christos reference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
4195 1.1 christos } else {
4196 1.1 christos INSIST(result == ISC_R_NOMORE);
4197 1.1 christos qpdbiter->node = NULL;
4198 1.1 christos }
4199 1.1 christos
4200 1.1 christos qpdbiter->result = result;
4201 1.1 christos return result;
4202 1.1 christos }
4203 1.1 christos
4204 1.1 christos static isc_result_t
4205 1.1 christos dbiterator_next(dns_dbiterator_t *iterator DNS__DB_FLARG) {
4206 1.1 christos isc_result_t result;
4207 1.1 christos qpc_dbit_t *qpdbiter = (qpc_dbit_t *)iterator;
4208 1.1 christos
4209 1.1 christos REQUIRE(qpdbiter->node != NULL);
4210 1.1 christos
4211 1.1 christos if (qpdbiter->result != ISC_R_SUCCESS) {
4212 1.1 christos return qpdbiter->result;
4213 1.1 christos }
4214 1.1 christos
4215 1.1 christos if (qpdbiter->paused) {
4216 1.1 christos resume_iteration(qpdbiter, true);
4217 1.1 christos }
4218 1.1 christos
4219 1.1 christos dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
4220 1.1 christos
4221 1.1 christos result = dns_qpiter_next(&qpdbiter->iter, NULL,
4222 1.1 christos (void **)&qpdbiter->node, NULL);
4223 1.1 christos
4224 1.1 christos if (result == ISC_R_SUCCESS) {
4225 1.1 christos dns_name_copy(&qpdbiter->node->name, qpdbiter->name);
4226 1.1 christos reference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
4227 1.1 christos } else {
4228 1.1 christos INSIST(result == ISC_R_NOMORE);
4229 1.1 christos qpdbiter->node = NULL;
4230 1.1 christos }
4231 1.1 christos
4232 1.1 christos qpdbiter->result = result;
4233 1.1 christos return result;
4234 1.1 christos }
4235 1.1 christos
4236 1.1 christos static isc_result_t
4237 1.1 christos dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
4238 1.1 christos dns_name_t *name DNS__DB_FLARG) {
4239 1.1 christos qpcache_t *qpdb = (qpcache_t *)iterator->db;
4240 1.1 christos qpc_dbit_t *qpdbiter = (qpc_dbit_t *)iterator;
4241 1.1 christos qpcnode_t *node = qpdbiter->node;
4242 1.1 christos
4243 1.1 christos REQUIRE(qpdbiter->result == ISC_R_SUCCESS);
4244 1.1 christos REQUIRE(node != NULL);
4245 1.1 christos
4246 1.1 christos if (qpdbiter->paused) {
4247 1.1 christos resume_iteration(qpdbiter, false);
4248 1.1 christos }
4249 1.1 christos
4250 1.1 christos if (name != NULL) {
4251 1.1 christos dns_name_copy(&node->name, name);
4252 1.1 christos }
4253 1.1 christos
4254 1.1 christos newref(qpdb, node, isc_rwlocktype_none,
4255 1.1 christos qpdbiter->tree_locked DNS__DB_FLARG_PASS);
4256 1.1 christos
4257 1.1 christos *nodep = qpdbiter->node;
4258 1.1 christos return ISC_R_SUCCESS;
4259 1.1 christos }
4260 1.1 christos
4261 1.1 christos static isc_result_t
4262 1.1 christos dbiterator_pause(dns_dbiterator_t *iterator) {
4263 1.1 christos qpcache_t *qpdb = (qpcache_t *)iterator->db;
4264 1.1 christos qpc_dbit_t *qpdbiter = (qpc_dbit_t *)iterator;
4265 1.1 christos
4266 1.1 christos if (qpdbiter->result != ISC_R_SUCCESS &&
4267 1.1 christos qpdbiter->result != ISC_R_NOTFOUND &&
4268 1.1 christos qpdbiter->result != DNS_R_PARTIALMATCH &&
4269 1.1 christos qpdbiter->result != ISC_R_NOMORE)
4270 1.1 christos {
4271 1.1 christos return qpdbiter->result;
4272 1.1 christos }
4273 1.1 christos
4274 1.1 christos if (qpdbiter->paused) {
4275 1.1 christos return ISC_R_SUCCESS;
4276 1.1 christos }
4277 1.1 christos
4278 1.1 christos qpdbiter->paused = true;
4279 1.1 christos
4280 1.1 christos if (qpdbiter->tree_locked == isc_rwlocktype_read) {
4281 1.1 christos TREE_UNLOCK(&qpdb->tree_lock, &qpdbiter->tree_locked);
4282 1.1 christos }
4283 1.1 christos INSIST(qpdbiter->tree_locked == isc_rwlocktype_none);
4284 1.1 christos
4285 1.1 christos return ISC_R_SUCCESS;
4286 1.1 christos }
4287 1.1 christos
4288 1.1 christos static isc_result_t
4289 1.1 christos dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
4290 1.1 christos qpc_dbit_t *qpdbiter = (qpc_dbit_t *)iterator;
4291 1.1 christos
4292 1.1 christos if (qpdbiter->result != ISC_R_SUCCESS) {
4293 1.1 christos return qpdbiter->result;
4294 1.1 christos }
4295 1.1 christos
4296 1.1 christos dns_name_copy(dns_rootname, name);
4297 1.1 christos return ISC_R_SUCCESS;
4298 1.1 christos }
4299 1.1 christos
4300 1.1 christos static void
4301 1.1 christos deletedata(dns_db_t *db ISC_ATTR_UNUSED, dns_dbnode_t *node ISC_ATTR_UNUSED,
4302 1.1 christos void *data) {
4303 1.1 christos dns_slabheader_t *header = data;
4304 1.1 christos qpcache_t *qpdb = (qpcache_t *)header->db;
4305 1.1 christos
4306 1.1 christos if (header->heap != NULL && header->heap_index != 0) {
4307 1.1 christos isc_heap_delete(header->heap, header->heap_index);
4308 1.1 christos }
4309 1.1 christos
4310 1.1 christos update_rrsetstats(qpdb->rrsetstats, header->type,
4311 1.1 christos atomic_load_acquire(&header->attributes), false);
4312 1.1 christos
4313 1.1 christos if (ISC_LINK_LINKED(header, link)) {
4314 1.1 christos int idx = HEADERNODE(header)->locknum;
4315 1.1 christos ISC_LIST_UNLINK(qpdb->lru[idx], header, link);
4316 1.1 christos }
4317 1.1 christos
4318 1.1 christos if (header->noqname != NULL) {
4319 1.1 christos dns_slabheader_freeproof(db->mctx, &header->noqname);
4320 1.1 christos }
4321 1.1 christos if (header->closest != NULL) {
4322 1.1 christos dns_slabheader_freeproof(db->mctx, &header->closest);
4323 1.1 christos }
4324 1.1 christos }
4325 1.1 christos
4326 1.1 christos /*
4327 1.1 christos * Caller must be holding the node write lock.
4328 1.1 christos */
4329 1.1 christos static void
4330 1.1 christos expire_ttl_headers(qpcache_t *qpdb, unsigned int locknum,
4331 1.1 christos isc_rwlocktype_t *nlocktypep, isc_rwlocktype_t *tlocktypep,
4332 1.1 christos isc_stdtime_t now, bool cache_is_overmem DNS__DB_FLARG) {
4333 1.1 christos isc_heap_t *heap = qpdb->heaps[locknum];
4334 1.1 christos
4335 1.1 christos for (size_t i = 0; i < DNS_QPDB_EXPIRE_TTL_COUNT; i++) {
4336 1.1 christos dns_slabheader_t *header = isc_heap_element(heap, 1);
4337 1.1 christos
4338 1.1 christos if (header == NULL) {
4339 1.1 christos /* No headers left on this TTL heap; exit cleaning */
4340 1.1 christos return;
4341 1.1 christos }
4342 1.1 christos
4343 1.1 christos dns_ttl_t ttl = header->ttl;
4344 1.1 christos
4345 1.1 christos if (!cache_is_overmem) {
4346 1.1 christos /* Only account for stale TTL if cache is not overmem */
4347 1.1 christos ttl += STALE_TTL(header, qpdb);
4348 1.1 christos }
4349 1.1 christos
4350 1.1 christos if (ttl >= now - QPDB_VIRTUAL) {
4351 1.1 christos /*
4352 1.1 christos * The header at the top of this TTL heap is not yet
4353 1.1 christos * eligible for expiry, so none of the other headers on
4354 1.1 christos * the same heap can be eligible for expiry, either;
4355 1.1 christos * exit cleaning.
4356 1.1 christos */
4357 1.1 christos return;
4358 1.1 christos }
4359 1.1 christos
4360 1.1 christos expireheader(header, nlocktypep, tlocktypep,
4361 1.1 christos dns_expire_ttl DNS__DB_FLARG_PASS);
4362 1.1 christos }
4363 1.1 christos }
4364 1.1 christos
4365 1.1 christos static void
4366 1.1 christos setmaxrrperset(dns_db_t *db, uint32_t value) {
4367 1.1 christos qpcache_t *qpdb = (qpcache_t *)db;
4368 1.1 christos
4369 1.1 christos REQUIRE(VALID_QPDB(qpdb));
4370 1.1 christos
4371 1.1 christos qpdb->maxrrperset = value;
4372 1.1 christos }
4373 1.1 christos
4374 1.1 christos static void
4375 1.1 christos setmaxtypepername(dns_db_t *db, uint32_t value) {
4376 1.1 christos qpcache_t *qpdb = (qpcache_t *)db;
4377 1.1 christos
4378 1.1 christos REQUIRE(VALID_QPDB(qpdb));
4379 1.1 christos
4380 1.1 christos qpdb->maxtypepername = value;
4381 1.1 christos }
4382 1.1 christos
4383 1.1 christos static dns_dbmethods_t qpdb_cachemethods = {
4384 1.1 christos .destroy = qpdb_destroy,
4385 1.1 christos .findnode = findnode,
4386 1.1 christos .find = find,
4387 1.1 christos .findzonecut = findzonecut,
4388 1.1 christos .attachnode = attachnode,
4389 1.1 christos .detachnode = detachnode,
4390 1.1 christos .createiterator = createiterator,
4391 1.1 christos .findrdataset = findrdataset,
4392 1.1 christos .allrdatasets = allrdatasets,
4393 1.1 christos .addrdataset = addrdataset,
4394 1.1 christos .deleterdataset = deleterdataset,
4395 1.1 christos .nodecount = nodecount,
4396 1.1 christos .getoriginnode = getoriginnode,
4397 1.1 christos .getrrsetstats = getrrsetstats,
4398 1.1 christos .setcachestats = setcachestats,
4399 1.1 christos .setservestalettl = setservestalettl,
4400 1.1 christos .getservestalettl = getservestalettl,
4401 1.1 christos .setservestalerefresh = setservestalerefresh,
4402 1.1 christos .getservestalerefresh = getservestalerefresh,
4403 1.1 christos .locknode = locknode,
4404 1.1 christos .unlocknode = unlocknode,
4405 1.1 christos .expiredata = expiredata,
4406 1.1 christos .deletedata = deletedata,
4407 1.1 christos .setmaxrrperset = setmaxrrperset,
4408 1.1 christos .setmaxtypepername = setmaxtypepername,
4409 1.1 christos };
4410 1.1 christos
4411 1.1 christos static void
4412 1.1 christos qpcnode_destroy(qpcnode_t *data) {
4413 1.1 christos dns_slabheader_t *current = NULL, *next = NULL;
4414 1.1 christos
4415 1.1 christos for (current = data->data; current != NULL; current = next) {
4416 1.1 christos dns_slabheader_t *down = current->down, *down_next = NULL;
4417 1.1 christos
4418 1.1 christos next = current->next;
4419 1.1 christos
4420 1.1 christos for (down = current->down; down != NULL; down = down_next) {
4421 1.1 christos down_next = down->down;
4422 1.1 christos dns_slabheader_destroy(&down);
4423 1.1 christos }
4424 1.1 christos
4425 1.1 christos dns_slabheader_destroy(¤t);
4426 1.1 christos }
4427 1.1 christos
4428 1.1 christos dns_name_free(&data->name, data->mctx);
4429 1.1 christos isc_mem_putanddetach(&data->mctx, data, sizeof(qpcnode_t));
4430 1.1 christos }
4431 1.1 christos
4432 1.1 christos #ifdef DNS_DB_NODETRACE
4433 1.1 christos ISC_REFCOUNT_STATIC_TRACE_IMPL(qpcnode, qpcnode_destroy);
4434 1.1 christos #else
4435 1.1 christos ISC_REFCOUNT_STATIC_IMPL(qpcnode, qpcnode_destroy);
4436 1.1 christos #endif
4437