From 04fdf242a853e146f785ece339ab6e14f55d7cf8 Mon Sep 17 00:00:00 2001 From: Alessio Podda Date: Mon, 24 Nov 2025 09:07:26 +0100 Subject: [PATCH 1/7] Add slist.h Add a macro-based singly-linked list implementation to the codebase, inspired by the doubly-linked list in list.h. --- lib/isc/include/isc/slist.h | 82 +++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 lib/isc/include/isc/slist.h diff --git a/lib/isc/include/isc/slist.h b/lib/isc/include/isc/slist.h new file mode 100644 index 0000000000..91a8dc6b52 --- /dev/null +++ b/lib/isc/include/isc/slist.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#pragma once + +/*! \file isc/slist.h + * \brief + * Implements macros for singly-linked lists. + * + * This module provides a generic implementation of singly-linked lists + * similar to isc/list.h but optimized for forward-only traversal. + */ + +#define ISC_SLIST_INITIALIZER \ + { \ + .head = NULL, \ + } + +#define ISC_SLINK_INITIALIZER \ + { \ + .next = NULL, \ + } + +#define ISC_SLIST(type) \ + struct { \ + type *head; \ + } + +#define ISC_SLINK(type) \ + struct { \ + type *next; \ + } + +#define ISC_SLIST_HEAD(list) ((list).head) +#define ISC_SLIST_EMPTY(list) ((list).head == NULL) + +#define ISC_SLIST_PREPEND(list, elt, link) \ + ({ \ + (elt)->link.next = (list).head; \ + (list).head = (elt); \ + }) + +#define ISC_SLIST_INSERTAFTER(after, elt, link) \ + ({ \ + (elt)->link.next = (after)->link.next; \ + (after)->link.next = (elt); \ + }) + +#define ISC_SLIST_NEXT(elt, link) ((elt)->link.next) + +/* clang-format off */ +#define ISC_SLIST_FOREACH_FROM(elt, list, link, first) \ + for (typeof(first) elt = first, \ + elt##_next = (elt != NULL) ? ISC_SLIST_NEXT(elt, link) : NULL; \ + elt != NULL; \ + elt = elt##_next, \ + elt##_next = (elt != NULL) ? ISC_SLIST_NEXT(elt, link) : NULL) + +#define ISC_SLIST_FOREACH(elt, list, link) \ + ISC_SLIST_FOREACH_FROM(elt, list, link, ISC_SLIST_HEAD(list)) + +/* clang-format on */ + +/* Iteration over pointer-to-pointer for safe operations */ +#define ISC_SLIST_FOREACH_PTR(p, head) \ + for (typeof(head) p = (head); *p != NULL; ) + +#define ISC_SLIST_PTR_REMOVE(p, elt, link_field) \ + (*(p) = ISC_SLIST_NEXT(elt, link_field)) + +#define ISC_SLIST_PTR_ADVANCE(p, link_field) \ + (p = &ISC_SLIST_NEXT(*p, link_field)) From b2cad77aa78b0b0280ded46cccaa5ae00bc2aef8 Mon Sep 17 00:00:00 2001 From: Alessio Podda Date: Mon, 24 Nov 2025 09:16:18 +0100 Subject: [PATCH 2/7] Add rdatavec Add an implementation of rdataset specialized for authoritative workloads. For now, it is a copy of rdataslab, with redundant fields from the header removed. --- lib/dns/include/dns/rdataset.h | 15 + lib/dns/include/dns/rdatavec.h | 272 +++++++++ lib/dns/meson.build | 1 + lib/dns/rdatavec.c | 995 +++++++++++++++++++++++++++++++++ lib/dns/rdatavec_p.h | 69 +++ 5 files changed, 1352 insertions(+) create mode 100644 lib/dns/include/dns/rdatavec.h create mode 100644 lib/dns/rdatavec.c create mode 100644 lib/dns/rdatavec_p.h diff --git a/lib/dns/include/dns/rdataset.h b/lib/dns/include/dns/rdataset.h index e2917b8675..81de51f080 100644 --- a/lib/dns/include/dns/rdataset.h +++ b/lib/dns/include/dns/rdataset.h @@ -51,6 +51,7 @@ #include #include +#include #include #include @@ -200,6 +201,20 @@ struct dns_rdataset { dns_slabheader_proof_t *noqname, *closest; } slab; + /* + * A vec rdataset provides access to an rdatavec. In + * a QP database, 'header' points to the vecheader + * structure. (There is an exception in the case of + * rdatasets returned by the `getnoqname` and `getclosest` + * methods; see comments in rdatavec.c for details.) + */ + struct { + struct dns_db *db; + dns_dbnode_t *node; + dns_vecheader_t *header; + rdatavec_iter_t iter; + } vec; + /* * A simple rdatalist, plus an optional dbnode used by * builtin and sdlz. diff --git a/lib/dns/include/dns/rdatavec.h b/lib/dns/include/dns/rdatavec.h new file mode 100644 index 0000000000..04534eca07 --- /dev/null +++ b/lib/dns/include/dns/rdatavec.h @@ -0,0 +1,272 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#pragma once + +/*! \file dns/rdatavec.h + * \brief + * Implements storage of rdatasets into vectors of memory. + * + * MP: + *\li Clients of this module must impose any required synchronization. + * + * Reliability: + *\li This module deals with low-level byte streams. Errors in any of + * the functions are likely to crash the server or corrupt memory. + * + *\li If the caller passes invalid memory references, these functions are + * likely to crash the server or corrupt memory. + * + * Resources: + *\li None. + * + * Security: + *\li None. + * + * Standards: + *\li None. + */ + +/*** + *** Imports + ***/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#define DNS_RDATAVEC_FORCE 0x1 +#define DNS_RDATAVEC_EXACT 0x2 + +#define DNS_RDATAVEC_OFFLINE 0x01 /* RRSIG is for offline DNSKEY */ + + +typedef struct dns_vectop dns_vectop_t; +typedef struct dns_vecheader dns_vecheader_t; + +struct rdatavec_iter { + unsigned char *iter_pos; + unsigned int iter_count; + dns_rdataclass_t iter_rdclass; + dns_rdatatype_t iter_type; +}; + +typedef struct rdatavec_iter rdatavec_iter_t; + +struct dns_vectop { + ISC_SLINK(dns_vectop_t) next_type; + ISC_SLIST(dns_vecheader_t) headers; + + dns_typepair_t typepair; +}; + +struct dns_vecheader { + _Atomic(uint16_t) attributes; + _Atomic(dns_trust_t) trust; + + /*% + * Locked by the owning node's lock. + */ + uint16_t resign_lsb : 1; + unsigned int heap_index : 31; + uint32_t serial; + dns_ttl_t ttl; + dns_typepair_t typepair; + + /* resigning (zone). The lsb is not adjacent for struct packing reasons */ + isc_stdtime_t resign; + + /*% + * Link to the other versions of this rdataset. + */ + ISC_SLINK(dns_vecheader_t) next_header; + + /*% + * The database node objects containing this rdataset, if any. + */ + dns_dbnode_t *node; + + /*% + * Cached glue records for an rdataset of type NS (zone only). + */ + dns_gluelist_t *gluelist; + + /*% + * Case vector. If the bit is set then the corresponding + * character in the owner name needs to be AND'd with 0x20, + * rendering that character upper case. + */ + unsigned char upper[32]; + + /*% + * Flexible member indicates the address of the raw data + * following this header. + */ + unsigned char raw[]; +}; + + +enum { + DNS_VECHEADERATTR_NONEXISTENT = 1 << 0, + DNS_VECHEADERATTR_IGNORE = 1 << 1, + DNS_VECHEADERATTR_RESIGN = 1 << 2, + DNS_VECHEADERATTR_OPTOUT = 1 << 3, + DNS_VECHEADERATTR_CASESET = 1 << 4, + DNS_VECHEADERATTR_ZEROTTL = 1 << 5, + DNS_VECHEADERATTR_CASEFULLYLOWER = 1 << 6, +}; + +/* clang-format off : RemoveParentheses */ +#define DNS_VECHEADER_GETATTR(header, attribute) \ + (atomic_load_acquire(&(header)->attributes) & (attribute)) +/* clang-format on */ +#define DNS_VECHEADER_SETATTR(header, attribute) \ + atomic_fetch_or_release(&(header)->attributes, attribute) +#define DNS_VECHEADER_CLRATTR(header, attribute) \ + atomic_fetch_and_release(&(header)->attributes, ~(attribute)) + +extern dns_rdatasetmethods_t dns_rdatavec_rdatasetmethods; + +/*** + *** Functions + ***/ + +isc_result_t +dns_rdatavec_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx, + isc_region_t *region, uint32_t limit); +/*%< + * Allocate space for a vec to hold the data in rdataset, and copy the + * data into it. The resulting vec will be returned in 'region'. + * + * dns_rdatavec_fromrdataset() allocates space for a dns_vecheader object + * and the memory needed for a raw vec, and partially initializes + * it, setting the type, trust, and TTL fields to match rdataset->type, + * rdataset->covers, rdataset->trust, and rdataset->ttl. (Note that the + * last field needs to be overridden when used in the cache database, + * since cache headers use an expire time instead of a TTL.) + * + * Requires: + *\li 'rdataset' is valid. + * + * Ensures: + *\li 'region' will have base pointing to the start of allocated memory, + * with the vecified region beginning at region->base + reservelen. + * region->length contains the total length allocated. + * + * Returns: + *\li ISC_R_SUCCESS - successful completion + *\li ISC_R_NOSPACE - more than 64k RRs + *\li DNS_R_TOOMANYRECORDS - more than max-records-per-rrset RRs + *\li DNS_R_SINGLETON - singleton type has more than one RR + */ + +unsigned int +dns_rdatavec_size(dns_vecheader_t *header); +/*%< + * Return the total size of the rdatavec following 'header'. + * + * Requires: + *\li 'header' points to a vecheader with an rdatavec following it. + * + * Returns: + *\li The number of bytes in the vec, plus the header. + */ + +unsigned int +dns_rdatavec_count(dns_vecheader_t *header); +/*%< + * Return the number of records in the rdatavec following 'header'. + * + * Requires: + *\li 'header' points to a vecheader with an rdatavec following it. + * + * Returns: + *\li The number of records in the vec. + */ + +isc_result_t +dns_rdatavec_merge(dns_vecheader_t *oheader, dns_vecheader_t *nheader, + isc_mem_t *mctx, dns_rdataclass_t rdclass, + dns_rdatatype_t type, unsigned int flags, + uint32_t maxrrperset, dns_vecheader_t **theaderp); +/*%< + * Merge the vecs following 'oheader' and 'nheader'. + */ + +isc_result_t +dns_rdatavec_subtract(dns_vecheader_t *mheader, dns_vecheader_t *sheader, + isc_mem_t *mctx, dns_rdataclass_t rdclass, + dns_rdatatype_t type, unsigned int flags, + dns_vecheader_t **theaderp); +/*%< + * Subtract the vec following 'sheader' from the one following 'mheader'. + * If 'exact' is true then all elements from the 'sheader' vec must exist + * in the 'mheader' vec. + * + * XXX + * valid flags are DNS_RDATAVEC_EXACT + */ + + +void +dns_vecheader_setownercase(dns_vecheader_t *header, const dns_name_t *name); +/*%< + * Store the casing of 'name', into a bitfield in 'header'. + * + * Requires: + * \li 'header' is a valid vecheader. + * \li 'name' is a valid name. + */ + + +void +dns_vecheader_reset(dns_vecheader_t *h, dns_dbnode_t *node); +/*%< + * Reset an rdatavec header 'h' so it can be used to store data in + * database node 'node'. + */ + +dns_vecheader_t * +dns_vecheader_new(isc_mem_t *mctx, dns_dbnode_t *node); +/*%< + * Allocate memory for an rdatavec header and initialize it for use + * in database node 'node'. + */ + +void +dns_vecheader_destroy(dns_vecheader_t **headerp); +/*%< + * Free all memory associated with '*headerp'. + */ + + +dns_vectop_t * +dns_vectop_new(isc_mem_t *mctx, dns_typepair_t typepair); +/*%< + * Allocate memory for an rdatavec top and initialize it for use + * with 'typepair' type and covers pair. + */ + +void +dns_vectop_destroy(isc_mem_t *mctx, dns_vectop_t **topp); +/*%< + * Free all memory associated with '*vectopp'. + */ diff --git a/lib/dns/meson.build b/lib/dns/meson.build index f6628079d6..92174973ff 100644 --- a/lib/dns/meson.build +++ b/lib/dns/meson.build @@ -140,6 +140,7 @@ dns_srcset.add( 'rdataset.c', 'rdatasetiter.c', 'rdataslab.c', + 'rdatavec.c', 'remote.c', 'request.c', 'resconf.c', diff --git a/lib/dns/rdatavec.c b/lib/dns/rdatavec.c new file mode 100644 index 0000000000..3dd9eeb2cb --- /dev/null +++ b/lib/dns/rdatavec.c @@ -0,0 +1,995 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "rdatavec_p.h" + +/* + * The memory structure of an rdatavec is as follows: + * + * header (dns_vecheader_t) + * record count (2 bytes) + * data records + * data length (2 bytes) + * order (2 bytes) + * meta data (1 byte for RRSIG, 0 for all other types) + * data (data length bytes) + * + * A "bare" rdatavec is everything after "header". + * + * When a vec is created, data records are sorted into DNSSEC order. + */ + +static void +rdataset_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG); +static isc_result_t +rdataset_first(dns_rdataset_t *rdataset); +static isc_result_t +rdataset_next(dns_rdataset_t *rdataset); +static void +rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata); +static void +rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target DNS__DB_FLARG); +static unsigned int +rdataset_count(dns_rdataset_t *rdataset); +static void +rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust); +static void +rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name); + +dns_rdatasetmethods_t dns_rdatavec_rdatasetmethods = { + .disassociate = rdataset_disassociate, + .first = rdataset_first, + .next = rdataset_next, + .current = rdataset_current, + .clone = rdataset_clone, + .count = rdataset_count, + .settrust = rdataset_settrust, + .expire = NULL, + .clearprefetch = NULL, + .getownercase = rdataset_getownercase, +}; + +/*% Note: the "const void *" are just to make qsort happy. */ +static int +compare_rdata(const void *p1, const void *p2) { + return dns_rdata_compare(p1, p2); +} + +static size_t +header_size(const dns_vecheader_t* header) { + UNUSED(header); + return sizeof(dns_vecheader_t); +} + +static unsigned char* +rdatavec_raw(dns_vecheader_t* header) { + unsigned char *as_char_star = (unsigned char*) header; + unsigned char* raw = as_char_star + header_size(header); + + return raw; +} + +static unsigned char* +rdatavec_data(dns_vecheader_t* header) { + return rdatavec_raw(header) + 2; +} + +static unsigned int +rdatavec_count(dns_vecheader_t* header) { + unsigned char* raw = rdatavec_raw(header); + unsigned int count = get_uint16(raw); + + return count; +} + +static isc_result_t +makevec(dns_rdataset_t *rdataset, isc_mem_t *mctx, isc_region_t *region, + uint32_t maxrrperset) { + /* + * Use &removed as a sentinel pointer for duplicate + * rdata as rdata.data == NULL is valid. + */ + static unsigned char removed; + dns_rdata_t *rdata = NULL; + unsigned char *rawbuf = NULL; + unsigned int headerlen = sizeof(dns_vecheader_t); + unsigned int buflen = headerlen + 2; + isc_result_t result; + unsigned int nitems; + unsigned int nalloc; + unsigned int length; + size_t i; + size_t rdatasize; + + /* + * If the source rdataset is also a vec, we don't need + * to do anything special, just copy the whole vec to a + * new buffer. + */ + if (rdataset->methods == &dns_rdatavec_rdatasetmethods) { + dns_vecheader_t *header = dns_vecheader_getheader(rdataset); + buflen = dns_rdatavec_size(header); + + rawbuf = isc_mem_get(mctx, buflen); + region->base = rawbuf; + region->length = buflen; + + memmove(rawbuf, header, buflen); + return ISC_R_SUCCESS; + } + + /* + * If there are no rdata then we just need to allocate a header + * with a zero record count. + */ + nitems = dns_rdataset_count(rdataset); + if (nitems == 0) { + if (rdataset->type != 0) { + return ISC_R_FAILURE; + } + rawbuf = isc_mem_get(mctx, buflen); + region->base = rawbuf; + region->length = buflen; + rawbuf += headerlen; + put_uint16(rawbuf, 0); + return ISC_R_SUCCESS; + } + + if (maxrrperset > 0 && nitems > maxrrperset) { + return DNS_R_TOOMANYRECORDS; + } + + if (nitems > 0xffff) { + return ISC_R_NOSPACE; + } + + /* + * Remember the original number of items. + */ + nalloc = nitems; + + RUNTIME_CHECK(!ckd_mul(&rdatasize, nalloc, sizeof(rdata[0]))); + rdata = isc_mem_get(mctx, rdatasize); + + /* + * Save all of the rdata members into an array. + */ + result = dns_rdataset_first(rdataset); + if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE) { + goto free_rdatas; + } + for (i = 0; i < nalloc && result == ISC_R_SUCCESS; i++) { + INSIST(result == ISC_R_SUCCESS); + dns_rdata_init(&rdata[i]); + dns_rdataset_current(rdataset, &rdata[i]); + INSIST(rdata[i].data != &removed); + result = dns_rdataset_next(rdataset); + } + if (i != nalloc || result != ISC_R_NOMORE) { + /* + * Somehow we iterated over fewer rdatas than + * dns_rdataset_count() said there were or there + * were more items than dns_rdataset_count said + * there were. + */ + result = ISC_R_FAILURE; + goto free_rdatas; + } + + /* + * Put into DNSSEC order. + */ + if (nalloc > 1U) { + qsort(rdata, nalloc, sizeof(rdata[0]), compare_rdata); + } + + /* + * Remove duplicates and compute the total storage required. + * + * If an rdata is not a duplicate, accumulate the storage size + * required for the rdata. We do not store the class, type, etc, + * just the rdata, so our overhead is 2 bytes for the number of + * records, and 2 bytes for the length of each rdata, plus the + * rdata itself. + */ + for (i = 1; i < nalloc; i++) { + if (compare_rdata(&rdata[i - 1], &rdata[i]) == 0) { + rdata[i - 1].data = &removed; + nitems--; + } else { + buflen += (2 + rdata[i - 1].length); + /* + * Provide space to store the per RR meta data. + */ + if (rdataset->type == dns_rdatatype_rrsig) { + buflen++; + } + } + } + + /* + * Don't forget the last item! + */ + buflen += (2 + rdata[i - 1].length); + + /* + * Provide space to store the per RR meta data. + */ + if (rdataset->type == dns_rdatatype_rrsig) { + buflen++; + } + + /* + * Ensure that singleton types are actually singletons. + */ + if (nitems > 1 && dns_rdatatype_issingleton(rdataset->type)) { + /* + * We have a singleton type, but there's more than one + * RR in the rdataset. + */ + result = DNS_R_SINGLETON; + goto free_rdatas; + } + + /* + * Allocate the memory, set up a buffer, start copying in + * data. + */ + rawbuf = isc_mem_get(mctx, buflen); + + region->base = rawbuf; + region->length = buflen; + rawbuf += headerlen; + put_uint16(rawbuf, nitems); + + for (i = 0; i < nalloc; i++) { + if (rdata[i].data == &removed) { + continue; + } + length = rdata[i].length; + if (rdataset->type == dns_rdatatype_rrsig) { + length++; + } + INSIST(length <= 0xffff); + + put_uint16(rawbuf, length); + + /* + * Store the per RR meta data. + */ + if (rdataset->type == dns_rdatatype_rrsig) { + *rawbuf++ = (rdata[i].flags & DNS_RDATA_OFFLINE) + ? DNS_RDATAVEC_OFFLINE + : 0; + } + if (rdata[i].length != 0) { + memmove(rawbuf, rdata[i].data, rdata[i].length); + } + rawbuf += rdata[i].length; + } + + result = ISC_R_SUCCESS; + +free_rdatas: + isc_mem_put(mctx, rdata, rdatasize); + return result; +} + +isc_result_t +dns_rdatavec_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx, + isc_region_t *region, uint32_t maxrrperset) { + isc_result_t result; + + if (rdataset->type == dns_rdatatype_none && + rdataset->covers == dns_rdatatype_none) + { + return DNS_R_DISALLOWED; + } + + result = makevec(rdataset, mctx, region, maxrrperset); + if (result == ISC_R_SUCCESS) { + dns_vecheader_t *new = (dns_vecheader_t *)region->base; + dns_typepair_t typepair; + + if (rdataset->attributes.negative) { + INSIST(rdataset->type == dns_rdatatype_none); + INSIST(rdataset->covers != dns_rdatatype_none); + typepair = DNS_TYPEPAIR_VALUE(rdataset->covers, + dns_rdatatype_none); + } else { + INSIST(rdataset->type != dns_rdatatype_none); + INSIST(dns_rdatatype_issig(rdataset->type) || + rdataset->covers == dns_rdatatype_none); + typepair = DNS_TYPEPAIR_VALUE(rdataset->type, + rdataset->covers); + } + + *new = (dns_vecheader_t){ + .next_header = ISC_SLINK_INITIALIZER, + .typepair = typepair, + .trust = rdataset->trust, + .ttl = rdataset->ttl, + }; + } + + return result; +} + +unsigned int +dns_rdatavec_size(dns_vecheader_t *header) { + REQUIRE(header != NULL); + + unsigned char *vec = rdatavec_raw(header); + INSIST(vec != NULL); + + unsigned char *current = rdatavec_data(header); + uint16_t count = rdatavec_count(header); + + while (count-- > 0) { + uint16_t length = get_uint16(current); + current += length; + } + + return (unsigned int)(current - vec) + header_size(header); +} + +unsigned int +dns_rdatavec_count(dns_vecheader_t *header) { + REQUIRE(header != NULL); + + return rdatavec_count(header); +} + +/* + * Make the dns_rdata_t 'rdata' refer to the vec item + * beginning at '*current' (which is part of a vec of type + * 'type' and class 'rdclass') and advance '*current' to + * point to the next item in the vec. + */ +static void +rdata_from_vecitem(unsigned char **current, dns_rdataclass_t rdclass, + dns_rdatatype_t type, dns_rdata_t *rdata) { + unsigned char *tcurrent = *current; + isc_region_t region; + bool offline = false; + uint16_t length = get_uint16(tcurrent); + + if (type == dns_rdatatype_rrsig) { + if ((*tcurrent & DNS_RDATAVEC_OFFLINE) != 0) { + offline = true; + } + length--; + tcurrent++; + } + region.length = length; + region.base = tcurrent; + tcurrent += region.length; + dns_rdata_fromregion(rdata, rdclass, type, ®ion); + if (offline) { + rdata->flags |= DNS_RDATA_OFFLINE; + } + *current = tcurrent; +} + +static void +rdata_to_vecitem(unsigned char **current, dns_rdatatype_t type, + dns_rdata_t *rdata) { + unsigned int length = rdata->length; + unsigned char *data = rdata->data; + unsigned char *p = *current; + + if (type == dns_rdatatype_rrsig) { + length++; + data--; + } + + put_uint16(p, length); + memmove(p, data, length); + p += length; + + *current = p; +} + +typedef struct vecinfo { + unsigned char *pos; + dns_rdata_t rdata; + bool dup; +} vecinfo_t; + +isc_result_t +dns_rdatavec_merge(dns_vecheader_t *oheader, dns_vecheader_t *nheader, + isc_mem_t *mctx, dns_rdataclass_t rdclass, + dns_rdatatype_t type, unsigned int flags, + uint32_t maxrrperset, dns_vecheader_t **theaderp) { + isc_result_t result = ISC_R_SUCCESS; + unsigned char *ocurrent = NULL, *ncurrent = NULL, *tcurrent = NULL; + unsigned int ocount, ncount, tlength, tcount = 0; + vecinfo_t *oinfo = NULL, *ninfo = NULL; + size_t o = 0, n = 0; + + REQUIRE(theaderp != NULL && *theaderp == NULL); + REQUIRE(oheader != NULL && nheader != NULL); + + ocurrent = rdatavec_data(oheader); + ocount = rdatavec_count(oheader); + + ncurrent = rdatavec_data(nheader); + ncount = rdatavec_count(nheader); + + INSIST(ocount > 0 && ncount > 0); + + if (maxrrperset > 0 && ocount + ncount > maxrrperset) { + return DNS_R_TOOMANYRECORDS; + } + + /* + * Figure out the target length. Start with the header, + * plus 2 octets for the count. + */ + tlength = header_size(oheader) + 2; + + /* + * Gather the rdatas in the old vec and add their lengths to + * the larget length. + */ + oinfo = isc_mem_cget(mctx, ocount, sizeof(struct vecinfo)); + for (size_t i = 0; i < ocount; i++) { + oinfo[i].pos = ocurrent; + dns_rdata_init(&oinfo[i].rdata); + rdata_from_vecitem(&ocurrent, rdclass, type, &oinfo[i].rdata); + tlength += ocurrent - oinfo[i].pos; + } + + /* + * Then add the length of rdatas in the new vec that aren't + * duplicated in the old vec. + */ + ninfo = isc_mem_cget(mctx, ncount, sizeof(struct vecinfo)); + for (size_t i = 0; i < ncount; i++) { + ninfo[i].pos = ncurrent; + dns_rdata_init(&ninfo[i].rdata); + rdata_from_vecitem(&ncurrent, rdclass, type, &ninfo[i].rdata); + + for (size_t j = 0; j < ocount; j++) { + if (oinfo[j].dup) { + /* + * This was already found to be + * duplicated; no need to compare + * it again. + */ + continue; + } + + if (dns_rdata_compare(&oinfo[j].rdata, + &ninfo[i].rdata) == 0) + { + /* + * Found a dup. Mark the old copy as a + * duplicate so we don't check it again; + * mark the new copy as a duplicate so we + * don't copy it to the target. + */ + oinfo[j].dup = ninfo[i].dup = true; + break; + } + } + + if (ninfo[i].dup) { + continue; + } + + /* + * We will be copying this item to the target, so + * add its length to tlength and increment tcount. + */ + tlength += ncurrent - ninfo[i].pos; + tcount++; + } + + /* + * If the EXACT flag is set, there can't be any rdata in + * the new vec that was also in the old. If tcount is less + * than ncount, then we found such a duplicate. + */ + if (((flags & DNS_RDATAVEC_EXACT) != 0) && (tcount < ncount)) { + CLEANUP(DNS_R_NOTEXACT); + } + + /* + * If nothing's being copied in from the new vec, and the + * FORCE flag isn't set, we're done. + */ + if (tcount == 0 && (flags & DNS_RDATAVEC_FORCE) == 0) { + CLEANUP(DNS_R_UNCHANGED); + } + + /* Add to tcount the total number of items from the old vec. */ + tcount += ocount; + + /* Resposition ncurrent at the first item. */ + ncurrent = rdatavec_data(nheader); + + /* Single types can't have more than one RR. */ + if (tcount > 1 && dns_rdatatype_issingleton(type)) { + CLEANUP(DNS_R_SINGLETON); + } + + if (tcount > 0xffff) { + CLEANUP(ISC_R_NOSPACE); + } + + /* Allocate the target buffer and copy the new vec's header */ + unsigned char *tstart = isc_mem_get(mctx, tlength); + dns_vecheader_t *as_header = (dns_vecheader_t*) tstart; + + /* + * Preserve the case of the old header, but the rest from the new + * header + */ + memmove(tstart, nheader, header_size(nheader)); + memmove(as_header->upper, oheader->upper, sizeof(oheader->upper)); + uint16_t case_attrs = DNS_VECHEADER_GETATTR( + oheader, + DNS_VECHEADERATTR_CASESET | DNS_VECHEADERATTR_CASEFULLYLOWER); + DNS_VECHEADER_CLRATTR(as_header, + DNS_VECHEADERATTR_CASESET | + DNS_VECHEADERATTR_CASEFULLYLOWER); + DNS_VECHEADER_SETATTR(as_header, case_attrs); + + tcurrent = tstart + header_size(nheader); + + /* Write the new count, then start merging the vecs. */ + put_uint16(tcurrent, tcount); + + /* + * Now walk the sets together, adding each item in DNSSEC order, + * and skipping over any more dups in the new vec. + */ + while (o < ocount || n < ncount) { + bool fromold; + + /* Skip to the next non-duplicate in the new vec. */ + for (; n < ncount && ninfo[n].dup; n++) + ; + + if (o == ocount) { + fromold = false; + } else if (n == ncount) { + fromold = true; + } else { + fromold = dns_rdata_compare(&oinfo[o].rdata, + &ninfo[n].rdata) < 0; + } + + if (fromold) { + rdata_to_vecitem(&tcurrent, type, &oinfo[o].rdata); + if (++o < ocount) { + /* Skip to the next rdata in the old vec */ + continue; + } + } else { + rdata_to_vecitem(&tcurrent, type, &ninfo[n++].rdata); + } + } + + INSIST(tcurrent == tstart + tlength); + + *theaderp = (dns_vecheader_t *)tstart; + +cleanup: + isc_mem_cput(mctx, oinfo, ocount, sizeof(struct vecinfo)); + isc_mem_cput(mctx, ninfo, ncount, sizeof(struct vecinfo)); + + return result; +} + +isc_result_t +dns_rdatavec_subtract(dns_vecheader_t *oheader, dns_vecheader_t *sheader, + isc_mem_t *mctx, dns_rdataclass_t rdclass, + dns_rdatatype_t type, unsigned int flags, + dns_vecheader_t **theaderp) { + isc_result_t result = ISC_R_SUCCESS; + unsigned char *ocurrent = NULL, *scurrent = NULL; + unsigned char *tstart = NULL, *tcurrent = NULL; + unsigned int ocount, scount, tlength; + unsigned int tcount = 0, rcount = 0; + vecinfo_t *oinfo = NULL, *sinfo = NULL; + + REQUIRE(theaderp != NULL && *theaderp == NULL); + REQUIRE(oheader != NULL && sheader != NULL); + + ocurrent = rdatavec_data(oheader); + ocount = rdatavec_count(oheader); + + scurrent = rdatavec_data(sheader); + scount = rdatavec_count(sheader); + + INSIST(ocount > 0 && scount > 0); + + /* Get info about the rdatas being subtracted */ + sinfo = isc_mem_cget(mctx, scount, sizeof(struct vecinfo)); + for (size_t i = 0; i < scount; i++) { + sinfo[i].pos = scurrent; + dns_rdata_init(&sinfo[i].rdata); + rdata_from_vecitem(&scurrent, rdclass, type, &sinfo[i].rdata); + } + + /* + * Figure out the target length. Start with the header, + * plus 2 octets for the count. + */ + tlength = header_size(oheader) + 2; + + /* + * Add the length of the rdatas in the old vec that + * aren't being subtracted. + */ + oinfo = isc_mem_cget(mctx, ocount, sizeof(struct vecinfo)); + for (size_t i = 0; i < ocount; i++) { + bool matched = false; + + oinfo[i].pos = ocurrent; + dns_rdata_init(&oinfo[i].rdata); + rdata_from_vecitem(&ocurrent, rdclass, type, &oinfo[i].rdata); + + for (size_t j = 0; j < scount; j++) { + if (sinfo[j].dup) { + continue; + } else if (dns_rdata_compare(&oinfo[i].rdata, + &sinfo[j].rdata) == 0) + { + matched = true; + oinfo[i].dup = sinfo[j].dup = true; + break; + } + } + + if (matched) { + /* This item will be subtracted. */ + rcount++; + } else { + /* + * This rdata wasn't in the vec to be subtracted, + * so copy it to the target. Add its length to + * tlength and increment tcount. + */ + tlength += ocurrent - oinfo[i].pos; + tcount++; + } + } + + /* + * If the EXACT flag wasn't set, check that all the records that + * were to be subtracted actually did exist in the original vec. + * (The numeric check works here because rdatavecs do not contain + * duplicates.) + */ + if ((flags & DNS_RDATAVEC_EXACT) != 0 && rcount != scount) { + CLEANUP(DNS_R_NOTEXACT); + } + + /* + * If the resulting rdatavec would be empty, don't bother to + * create a new buffer, just return. + */ + if (tcount == 0) { + CLEANUP(DNS_R_NXRRSET); + } + + /* + * If nothing is going to change, stop. + */ + if (rcount == 0) { + CLEANUP(DNS_R_UNCHANGED); + } + + /* + * Allocate the target buffer and copy the old vec's header. + */ + tstart = isc_mem_get(mctx, tlength); + memmove(tstart, oheader, header_size(oheader)); + tcurrent = tstart + header_size(oheader); + + /* + * Write the new count. + */ + put_uint16(tcurrent, tcount); + + /* + * Copy the parts of the old vec that didn't have duplicates. + */ + for (size_t i = 0; i < ocount; i++) { + if (!oinfo[i].dup) { + rdata_to_vecitem(&tcurrent, type, &oinfo[i].rdata); + } + } + + INSIST(tcurrent == tstart + tlength); + + *theaderp = (dns_vecheader_t *)tstart; + +cleanup: + isc_mem_cput(mctx, oinfo, ocount, sizeof(struct vecinfo)); + isc_mem_cput(mctx, sinfo, scount, sizeof(struct vecinfo)); + + return result; +} + + +void +dns_vecheader_setownercase(dns_vecheader_t *header, const dns_name_t *name) { + REQUIRE(!CASESET(header)); + + bool casefullylower = true; + + /* + * We do not need to worry about label lengths as they are all + * less than or equal to 63. + */ + memset(header->upper, 0, sizeof(header->upper)); + for (size_t i = 0; i < name->length; i++) { + if (isupper(name->ndata[i])) { + header->upper[i / 8] |= 1 << (i % 8); + casefullylower = false; + } + } + if (casefullylower) { + DNS_VECHEADER_SETATTR(header, + DNS_VECHEADERATTR_CASEFULLYLOWER); + } + DNS_VECHEADER_SETATTR(header, DNS_VECHEADERATTR_CASESET); +} + +void +dns_vecheader_reset(dns_vecheader_t *h, dns_dbnode_t *node) { + h->heap_index = 0; + h->node = node; + + atomic_init(&h->attributes, 0); + + STATIC_ASSERT(sizeof(h->attributes) == 2, + "The .attributes field of dns_vecheader_t needs to be " + "16-bit int type exactly."); +} + +dns_vecheader_t * +dns_vecheader_new(isc_mem_t *mctx, dns_dbnode_t *node) { + dns_vecheader_t *h = NULL; + + h = isc_mem_get(mctx, sizeof(*h)); + *h = (dns_vecheader_t){ + .node = node, + }; + return h; +} + +void +dns_vecheader_destroy(dns_vecheader_t **headerp) { + unsigned int size; + dns_vecheader_t *header = *headerp; + + *headerp = NULL; + + isc_mem_t *mctx = header->node->mctx; + dns_db_deletedata(header->node, header); + + if (EXISTS(header)) { + size = dns_rdatavec_size(header); + } else { + size = sizeof(*header); + } + + isc_mem_put(mctx, header, size); +} + +/* Iterators for already bound rdatavec */ + +isc_result_t +vecheader_first(rdatavec_iter_t *iter, dns_vecheader_t *header, dns_rdataclass_t rdclass) { + unsigned char *raw = rdatavec_data(header); + uint16_t count = rdatavec_count(header); + if (count == 0) { + iter->iter_pos = NULL; + iter->iter_count = 0; + return ISC_R_NOMORE; + } + + /* + * iter.iter_count is the number of rdata beyond the cursor + * position, so we decrement the total count by one before + * storing it. + * + * 'raw' points to the first record. + */ + iter->iter_pos = raw; + iter->iter_count = count - 1; + iter->iter_rdclass = rdclass; + iter->iter_type = DNS_TYPEPAIR_TYPE(header->typepair); + + return ISC_R_SUCCESS; +} + +isc_result_t +vecheader_next(rdatavec_iter_t *iter) { + uint16_t count = iter->iter_count; + if (count == 0) { + iter->iter_pos = NULL; + return ISC_R_NOMORE; + } + iter->iter_count = count - 1; + + /* + * Skip forward one record (length + 4) or one offset (4). + */ + unsigned char *raw = iter->iter_pos; + uint16_t length = peek_uint16(raw); + raw += length; + iter->iter_pos = raw + sizeof(uint16_t); + + return ISC_R_SUCCESS; +} + +void +vecheader_current(rdatavec_iter_t *iter, dns_rdata_t *rdata) { + unsigned char *raw = NULL; + unsigned int length; + isc_region_t r; + unsigned int flags = 0; + + raw = iter->iter_pos; + REQUIRE(raw != NULL); + + /* + * Find the start of the record if not already in iter_pos + * then skip the length and order fields. + */ + length = get_uint16(raw); + + if (iter->iter_type == dns_rdatatype_rrsig) { + if (*raw & DNS_RDATAVEC_OFFLINE) { + flags |= DNS_RDATA_OFFLINE; + } + length--; + raw++; + } + r.length = length; + r.base = raw; + dns_rdata_fromregion(rdata, iter->iter_rdclass, iter->iter_type, &r); + rdata->flags |= flags; +} + + +/* Fixed RRSet helper macros */ + +static void +rdataset_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG) { + dns_dbnode_t *node = rdataset->vec.node; + + dns__db_detachnode(&node DNS__DB_FLARG_PASS); +} + +static isc_result_t +rdataset_first(dns_rdataset_t *rdataset) { + return vecheader_first(&rdataset->vec.iter, rdataset->vec.header, rdataset->rdclass); +} + +static isc_result_t +rdataset_next(dns_rdataset_t *rdataset) { + return vecheader_next(&rdataset->vec.iter); +} + +static void +rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) { + vecheader_current(&rdataset->vec.iter, rdata); +} + +static void +rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target DNS__DB_FLARG) { + dns_dbnode_t *node = source->vec.node; + dns_dbnode_t *cloned_node = NULL; + + dns__db_attachnode(node, &cloned_node DNS__DB_FLARG_PASS); + INSIST(!ISC_LINK_LINKED(target, link)); + *target = *source; + ISC_LINK_INIT(target, link); + + target->vec.iter.iter_pos = NULL; + target->vec.iter.iter_count = 0; +} + +static unsigned int +rdataset_count(dns_rdataset_t *rdataset) { + return rdatavec_count(rdataset->vec.header); +} + +static void +rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) { + dns_vecheader_t *header = dns_vecheader_getheader(rdataset); + + rdataset->trust = trust; + atomic_store(&header->trust, trust); +} + +static void +rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name) { + dns_vecheader_t *header = dns_vecheader_getheader(rdataset); + uint8_t mask = (1 << 7); + uint8_t bits = 0; + + if (!CASESET(header)) { + return; + } + + if (CASEFULLYLOWER(header)) { + isc_ascii_lowercopy(name->ndata, name->ndata, name->length); + return; + } + + uint8_t *nd = name->ndata; + for (size_t i = 0; i < name->length; i++) { + if (mask == (1 << 7)) { + bits = header->upper[i / 8]; + mask = 1; + } else { + mask <<= 1; + } + nd[i] = (bits & mask) ? isc_ascii_toupper(nd[i]) + : isc_ascii_tolower(nd[i]); + } +} + +dns_vecheader_t * +dns_vecheader_getheader(const dns_rdataset_t *rdataset) { + return rdataset->vec.header; +} + +dns_vectop_t * +dns_vectop_new(isc_mem_t *mctx, dns_typepair_t typepair) { + dns_vectop_t *top = isc_mem_get(mctx, sizeof(*top)); + *top = (dns_vectop_t){ + .next_type = ISC_SLINK_INITIALIZER, + .headers = ISC_SLIST_INITIALIZER, + .typepair = typepair, + }; + + return top; +} + +void +dns_vectop_destroy(isc_mem_t *mctx, dns_vectop_t **topp) { + REQUIRE(topp != NULL && *topp != NULL); + dns_vectop_t *top = *topp; + *topp = NULL; + isc_mem_put(mctx, top, sizeof(*top)); +} diff --git a/lib/dns/rdatavec_p.h b/lib/dns/rdatavec_p.h new file mode 100644 index 0000000000..f26371656a --- /dev/null +++ b/lib/dns/rdatavec_p.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#pragma once + +#include + +#include + +#define CASEFULLYLOWER(header) \ + ((atomic_load_acquire(&(header)->attributes) & \ + DNS_VECHEADERATTR_CASEFULLYLOWER) != 0) +#define CASESET(header) \ + ((atomic_load_acquire(&(header)->attributes) & \ + DNS_VECHEADERATTR_CASESET) != 0) +#define EXISTS(header) \ + ((atomic_load_acquire(&(header)->attributes) & \ + DNS_VECHEADERATTR_NONEXISTENT) == 0) +#define IGNORE(header) \ + ((atomic_load_acquire(&(header)->attributes) & \ + DNS_VECHEADERATTR_IGNORE) != 0) +#define OPTOUT(header) \ + ((atomic_load_acquire(&(header)->attributes) & \ + DNS_VECHEADERATTR_OPTOUT) != 0) +#define RESIGN(header) \ + ((atomic_load_acquire(&(header)->attributes) & \ + DNS_VECHEADERATTR_RESIGN) != 0) + +#define peek_uint16(buffer) ISC_U8TO16_BE(buffer) +#define get_uint16(buffer) \ + ({ \ + uint16_t __ret = peek_uint16(buffer); \ + buffer += sizeof(uint16_t); \ + __ret; \ + }) +#define put_uint16(buffer, val) \ + { \ + ISC_U16TO8_BE(buffer, val); \ + (buffer) += sizeof(uint16_t); \ + } + +dns_vecheader_t * +dns_vecheader_getheader(const dns_rdataset_t *rdataset); +/*%< + * Return a pointer to the vecheader for a vec rdataset. + * + * Requires: + * \li 'rdataset' is a valid rdataset using rdatavec methods. + */ + + +isc_result_t +vecheader_first(rdatavec_iter_t *iter, dns_vecheader_t *header, dns_rdataclass_t rdclass); + +isc_result_t +vecheader_next(rdatavec_iter_t *iter); + +void +vecheader_current(rdatavec_iter_t *iter, dns_rdata_t *rdata); From f465976536f25ae1816243e4b38c902800d6f254 Mon Sep 17 00:00:00 2001 From: Alessio Podda Date: Wed, 10 Dec 2025 11:11:39 +0100 Subject: [PATCH 3/7] Document the memory layout of rdatavec --- lib/dns/rdatavec.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/lib/dns/rdatavec.c b/lib/dns/rdatavec.c index 3dd9eeb2cb..7f7c38045d 100644 --- a/lib/dns/rdatavec.c +++ b/lib/dns/rdatavec.c @@ -38,16 +38,26 @@ * The memory structure of an rdatavec is as follows: * * header (dns_vecheader_t) - * record count (2 bytes) + * record count (2 bytes, big endian) * data records - * data length (2 bytes) - * order (2 bytes) - * meta data (1 byte for RRSIG, 0 for all other types) + * data length (2 bytes, big endian) + * meta data (1 byte for RRSIG, 0 bytes for all other types) * data (data length bytes) * - * A "bare" rdatavec is everything after "header". + * A "bare" rdatavec is everything after the header. The first two bytes + * contain the count of rdata records in the rdatavec. For records with + * the DNS_VECHEADERATTR_NONEXISTENT attribute, the record count is omitted + * entirely. * - * When a vec is created, data records are sorted into DNSSEC order. + * After the count, the rdata records are stored sequentially in memory. + * Each record consists of a length field, optional metadata, and the actual + * rdata bytes. + * + * The rdata format depends on the RR type and is defined by the type-specific + * *_fromwire and *_towire functions (e.g., lib/dns/rdata/in_1/a_1.c for A + * records). The data is typically stored in wire format. + * + * When a vec is created, data records are sorted into DNSSEC canonical order. */ static void From 4eb0b23efcb6a3c441a48c33856e66fcd0345699 Mon Sep 17 00:00:00 2001 From: Alessio Podda Date: Mon, 24 Nov 2025 09:32:43 +0100 Subject: [PATCH 4/7] Switch qpzone to rdatavec Replaces rdataslab with rdatavec inside qpzone.c. This leads to a 19.92% reduction of used memory across perflab workloads. --- lib/dns/db_p.h | 3 +- lib/dns/include/dns/rdataset.h | 11 - lib/dns/qpzone.c | 504 ++++++++++++++++----------------- lib/dns/rdataset.c | 11 - lib/dns/rdataslab.c | 11 +- tests/dns/qpzone_test.c | 28 +- 6 files changed, 259 insertions(+), 309 deletions(-) diff --git a/lib/dns/db_p.h b/lib/dns/db_p.h index 4763d2bd7d..eaee9207f9 100644 --- a/lib/dns/db_p.h +++ b/lib/dns/db_p.h @@ -17,6 +17,7 @@ #include #include +#include #include #ifdef STRONG_RWLOCK_CHECK @@ -97,7 +98,7 @@ struct dns_gluelist { isc_mem_t *mctx; const dns_dbversion_t *version; - dns_slabheader_t *header; + dns_vecheader_t *header; struct dns_glue *glue; diff --git a/lib/dns/include/dns/rdataset.h b/lib/dns/include/dns/rdataset.h index 81de51f080..938e725ede 100644 --- a/lib/dns/include/dns/rdataset.h +++ b/lib/dns/include/dns/rdataset.h @@ -87,7 +87,6 @@ struct dns_rdatasetmethods { void (*getownercase)(const dns_rdataset_t *rdataset, dns_name_t *name); isc_result_t (*addglue)(dns_rdataset_t *rdataset, dns_dbversion_t *version, dns_message_t *msg); - dns_slabheader_t *(*getheader)(const dns_rdataset_t *rdataset); }; #define DNS_RDATASET_MAGIC ISC_MAGIC('D', 'N', 'S', 'R') @@ -636,16 +635,6 @@ dns_trust_totext(dns_trust_t trust); * Display trust in textual form. */ -dns_slabheader_t * -dns_rdataset_getheader(const dns_rdataset_t *rdataset); -/*%< - * Return a pointer to the slabheader for a slab rdataset. If 'rdataset' - * is not a slab rdataset or if the slab is raw (lacking a header), return - * NULL. - * - * Requires: - * \li 'rdataset' is a valid rdataset. - */ isc_stdtime_t dns_rdataset_minresign(dns_rdataset_t *rdataset); diff --git a/lib/dns/qpzone.c b/lib/dns/qpzone.c index 9a3273ddfd..706d218ff2 100644 --- a/lib/dns/qpzone.c +++ b/lib/dns/qpzone.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -53,7 +54,9 @@ #include #include #include -#include +#include + +#include "rdatavec_p.h" #include #include #include @@ -63,7 +66,7 @@ #include "db_p.h" #include "qpzone_p.h" -#include "rdataslab_p.h" +#include "rdatavec_p.h" #define HEADERNODE(h) ((qpznode_t *)((h)->node)) @@ -117,7 +120,7 @@ typedef struct qpz_changed { typedef ISC_LIST(qpz_changed_t) qpz_changedlist_t; typedef struct qpz_resigned { - dns_slabheader_t *header; + dns_vecheader_t *header; ISC_LINK(struct qpz_resigned) link; } qpz_resigned_t; @@ -201,8 +204,7 @@ struct qpznode { atomic_bool delegating; atomic_bool dirty; - struct cds_list_head types_list; - struct cds_list_head *data; + ISC_SLIST(dns_vectop_t) next_type; }; struct qpzonedb { @@ -263,8 +265,8 @@ typedef struct { bool need_cleanup; bool wild; qpznode_t *zonecut; - dns_slabheader_t *zonecut_header; - dns_slabheader_t *zonecut_sigheader; + dns_vecheader_t *zonecut_header; + dns_vecheader_t *zonecut_sigheader; dns_fixedname_t zonecut_name; } qpz_search_t; @@ -324,8 +326,8 @@ static dns_rdatasetitermethods_t rdatasetiter_methods = { typedef struct qpdb_rdatasetiter { dns_rdatasetiter_t common; - dns_slabtop_t *currenttop; - dns_slabheader_t *current; + dns_vectop_t *currenttop; + dns_vecheader_t *current; } qpdb_rdatasetiter_t; /* @@ -415,8 +417,8 @@ qpzone_get_locknum(void) { */ static bool resign_sooner(void *v1, void *v2) { - dns_slabheader_t *h1 = v1; - dns_slabheader_t *h2 = v2; + dns_vecheader_t *h1 = v1; + dns_vecheader_t *h2 = v2; return h1->resign < h2->resign || (h1->resign == h2->resign && h1->resign_lsb < h2->resign_lsb) || @@ -429,7 +431,7 @@ resign_sooner(void *v1, void *v2) { */ static void set_index(void *what, unsigned int idx) { - dns_slabheader_t *h = what; + dns_vecheader_t *h = what; h->heap_index = idx; } @@ -496,7 +498,7 @@ cleanup_gluelists(struct cds_wfs_stack *glue_stack) { cds_wfs_for_each_blocking_safe(head, node, next) { dns_gluelist_t *gluelist = caa_container_of(node, dns_gluelist_t, wfs_node); - dns_slabheader_t *header = rcu_xchg_pointer(&gluelist->header, + dns_vecheader_t *header = rcu_xchg_pointer(&gluelist->header, NULL); (void)rcu_cmpxchg_pointer(&header->gluelist, gluelist, NULL); @@ -609,7 +611,7 @@ new_qpz_heap(isc_mem_t *mctx) { * 3. The qpznode reference is finally released * * When the qpznode reference is released, it needs to unregister all its - * slabheaders from the resigning heap. The heap is a separate refcounted + * vecheaders from the resigning heap. The heap is a separate refcounted * object with references from both the database and every qpznode. This * design ensures that even after the database is destroyed, if nodes are * still alive, the heap remains accessible for safe cleanup. @@ -620,7 +622,7 @@ new_qpz_heap(isc_mem_t *mctx) { * to the heap lock regardless of the database's lifecycle. */ static isc_mutex_t * -get_heap_lock(dns_slabheader_t *header) { +get_heap_lock(dns_vecheader_t *header) { return &HEADERNODE(header)->heap->lock; } @@ -635,8 +637,7 @@ static qpznode_t * new_qpznode(qpzonedb_t *qpdb, const dns_name_t *name, dns_namespace_t nspace) { qpznode_t *newdata = isc_mem_get(qpdb->common.mctx, sizeof(*newdata)); *newdata = (qpznode_t){ - .types_list = CDS_LIST_HEAD_INIT(newdata->types_list), - .data = &newdata->types_list, + .next_type = ISC_SLIST_INITIALIZER, .methods = &qpznode_methods, .name = DNS_NAME_INITEMPTY, .nspace = nspace, @@ -807,25 +808,15 @@ qpznode_acquire(qpznode_t *node DNS__DB_FLARG) { qpznode_erefs_increment(node DNS__DB_FLARG_PASS); } -static dns_slabheader_t * -first_header(dns_slabtop_t *top) { - dns_slabheader_t *header = NULL; - cds_list_for_each_entry(header, &top->headers, headers_link) { - return header; - } - return NULL; +static dns_vecheader_t * +first_header(dns_vectop_t *top) { + return ISC_SLIST_HEAD(top->headers); } -static dns_slabheader_t * -next_header(dns_slabheader_t *header) { - return cds_list_entry((header)->headers_link.next, dns_slabheader_t, - headers_link); -} -static dns_slabheader_t * -first_existing_header(dns_slabtop_t *top, uint32_t serial) { - dns_slabheader_t *header = NULL; - cds_list_for_each_entry(header, &top->headers, headers_link) { +static dns_vecheader_t * +first_existing_header(dns_vectop_t *top, uint32_t serial) { + ISC_SLIST_FOREACH(header, top->headers, next_header) { if (header->serial <= serial && !IGNORE(header)) { if (EXISTS(header)) { return header; @@ -836,52 +827,60 @@ first_existing_header(dns_slabtop_t *top, uint32_t serial) { return NULL; } -static void -clean_multiple_headers(dns_slabtop_t *top) { - dns_slabheader_t *parent = first_header(top); - if (parent == NULL) { - return; - } +static dns_vecheader_t ** +first_existing_header_indirect(dns_vectop_t *top, uint32_t serial) { + REQUIRE(top != NULL); + dns_vecheader_t **result = &ISC_SLIST_HEAD(top->headers); - dns_slabheader_t *header = next_header(parent), *header_next = NULL; - cds_list_for_each_entry_safe_from(header, header_next, &top->headers, - headers_link) { - INSIST(header->serial <= parent->serial); - if (header->serial == parent->serial || IGNORE(header)) { - cds_list_del(&header->headers_link); - dns_slabheader_destroy(&header); + ISC_SLIST_FOREACH_PTR(p, &ISC_SLIST_HEAD(top->headers)) { + dns_vecheader_t *header = *p; + result = p; + + if (header->serial <= serial && !IGNORE(header)) { + break; + } + } + return result; +} + +static void +clean_multiple_headers(dns_vectop_t *top) { + uint32_t parent_serial = UINT32_MAX; + + REQUIRE(top != NULL); + + ISC_SLIST_FOREACH_PTR(p, &ISC_SLIST_HEAD(top->headers)) { + dns_vecheader_t *header = *p; + INSIST(header->serial <= parent_serial); + + if (header->serial == parent_serial || IGNORE(header)) { + ISC_SLIST_PTR_REMOVE(p, header, next_header); + dns_vecheader_destroy(&header); } else { - parent = header; + parent_serial = header->serial; + ISC_SLIST_PTR_ADVANCE(p, next_header); } } } -static void -check_top_header(dns_slabtop_t *top) { - dns_slabheader_t *header = first_header(top); - if (header != NULL && IGNORE(header)) { - cds_list_del(&header->headers_link); - dns_slabheader_destroy(&header); - } -} - static bool -clean_multiple_versions(dns_slabtop_t *top, uint32_t least_serial) { - dns_slabheader_t *parent = first_header(top); - if (parent == NULL) { +clean_multiple_versions(dns_vectop_t *top, uint32_t least_serial) { + REQUIRE(top != NULL); + + if (ISC_SLIST_EMPTY(top->headers)) { return false; } bool multiple = false; - dns_slabheader_t *header = next_header(parent), *header_next = NULL; - cds_list_for_each_entry_safe_from(header, header_next, &top->headers, - headers_link) { + dns_vecheader_t **pointer_to_second_header = &ISC_SLIST_NEXT(ISC_SLIST_HEAD(top->headers), next_header); + ISC_SLIST_FOREACH_PTR(p, pointer_to_second_header) { + dns_vecheader_t *header = *p; if (header->serial < least_serial) { - cds_list_del(&header->headers_link); - dns_slabheader_destroy(&header); + ISC_SLIST_PTR_REMOVE(p, header, next_header); + dns_vecheader_destroy(&header); } else { multiple = true; - parent = header; + ISC_SLIST_PTR_ADVANCE(p, next_header); } } return multiple; @@ -894,9 +893,13 @@ clean_zone_node(qpznode_t *node, uint32_t least_serial) { /* * Caller must be holding the node lock. */ + REQUIRE(node != NULL); REQUIRE(least_serial != 0); - DNS_SLABTOP_FOREACH(top, node->data) { + /* + * First pass: clean all header lists + */ + ISC_SLIST_FOREACH(top, node->next_type, next_type) { /* * First, we clean up any instances of multiple rdatasets * with the same serial number, or that have the IGNORE @@ -904,16 +907,7 @@ clean_zone_node(qpznode_t *node, uint32_t least_serial) { */ clean_multiple_headers(top); - /* - * All IGNORE datasets have been eliminated with the possible - * exception of the top header, which we now check. - */ - check_top_header(top); - - if (first_header(top) == NULL) { - cds_list_del(&top->types_link); - dns_slabtop_destroy(node->mctx, &top); - } else { + if (first_header(top) != NULL) { /* * Try to find the first down node less than the least * serial, and if there are such rdatasets, delete it @@ -927,6 +921,20 @@ clean_zone_node(qpznode_t *node, uint32_t least_serial) { least_serial); } } + + /* + * Second pass: remove all empty vectops + */ + ISC_SLIST_FOREACH_PTR(iter, &ISC_SLIST_HEAD(node->next_type)) { + dns_vectop_t *next = *iter; + if (ISC_SLIST_EMPTY(next->headers)) { + ISC_SLIST_PTR_REMOVE(iter, next, next_type); + dns_vectop_destroy(node->mctx, &next); + } else { + ISC_SLIST_PTR_ADVANCE(iter, next_type); + } + } + if (!still_dirty) { node->dirty = false; } @@ -974,7 +982,7 @@ qpznode_release(qpznode_t *node, uint32_t least_serial, } /* Handle easy and typical case first. */ - if (!node->dirty && !cds_list_empty(node->data)) { + if (!node->dirty && !ISC_SLIST_EMPTY(node->next_type)) { goto unref; } @@ -998,7 +1006,7 @@ unref: } static void -bindrdataset(qpzonedb_t *qpdb, qpznode_t *node, dns_slabheader_t *header, +bindrdataset(qpzonedb_t *qpdb, qpznode_t *node, dns_vecheader_t *header, dns_rdataset_t *rdataset DNS__DB_FLARG) { if (rdataset == NULL) { return; @@ -1008,7 +1016,7 @@ bindrdataset(qpzonedb_t *qpdb, qpznode_t *node, dns_slabheader_t *header, INSIST(rdataset->methods == NULL); /* We must be disassociated. */ - rdataset->methods = &dns_rdataslab_rdatasetmethods; + rdataset->methods = &dns_rdatavec_rdatasetmethods; rdataset->rdclass = qpdb->common.rdclass; rdataset->type = DNS_TYPEPAIR_TYPE(header->typepair); rdataset->covers = DNS_TYPEPAIR_COVERS(header->typepair); @@ -1019,23 +1027,15 @@ bindrdataset(qpzonedb_t *qpdb, qpznode_t *node, dns_slabheader_t *header, rdataset->attributes.optout = true; } - rdataset->slab.db = (dns_db_t *)qpdb; - rdataset->slab.node = (dns_dbnode_t *)node; - rdataset->slab.raw = header->raw; - rdataset->slab.iter_pos = NULL; - rdataset->slab.iter_count = 0; + rdataset->vec.db = (dns_db_t *)qpdb; + rdataset->vec.node = (dns_dbnode_t *)node; + rdataset->vec.header = header; + rdataset->vec.iter.iter_pos = NULL; + rdataset->vec.iter.iter_count = 0; /* * Add noqname proof. */ - rdataset->slab.noqname = header->noqname; - if (header->noqname != NULL) { - rdataset->attributes.noqname = true; - } - rdataset->slab.closest = header->closest; - if (header->closest != NULL) { - rdataset->attributes.closest = true; - } /* * Copy out re-signing information. @@ -1052,14 +1052,10 @@ static void setnsec3parameters(dns_db_t *db, qpz_version_t *version) { qpznode_t *node = NULL; dns_rdata_nsec3param_t nsec3param; - isc_region_t region; - isc_result_t result; - unsigned char *raw; /* RDATASLAB */ - unsigned int count, length; qpzonedb_t *qpdb = (qpzonedb_t *)db; isc_rwlocktype_t nlocktype = isc_rwlocktype_none; isc_rwlock_t *nlock = NULL; - dns_slabheader_t *found = NULL; + dns_vecheader_t *found = NULL; version->havensec3 = false; node = qpdb->origin; @@ -1067,7 +1063,7 @@ setnsec3parameters(dns_db_t *db, qpz_version_t *version) { NODE_RDLOCK(nlock, &nlocktype); - DNS_SLABTOP_FOREACH(top, node->data) { + ISC_SLIST_FOREACH(top, node->next_type, next_type) { if (top->typepair != dns_rdatatype_nsec3param) { continue; } @@ -1078,18 +1074,16 @@ setnsec3parameters(dns_db_t *db, qpz_version_t *version) { /* * Find an NSEC3PARAM with a supported algorithm. */ - raw = found->raw; - count = get_uint16(raw); - while (count-- > 0U) { - dns_rdata_t rdata = DNS_RDATA_INIT; - length = get_uint16(raw); - region.base = raw; - region.length = length; - raw += length; - dns_rdata_fromregion(&rdata, qpdb->common.rdclass, - dns_rdatatype_nsec3param, ®ion); - result = dns_rdata_tostruct(&rdata, &nsec3param, NULL); + rdatavec_iter_t iter; + for (isc_result_t res = vecheader_first(&iter, found, qpdb->common.rdclass); + res == ISC_R_SUCCESS; + res = vecheader_next(&iter)) + { + dns_rdata_t rdata = DNS_RDATA_INIT; + vecheader_current(&iter, &rdata); + + isc_result_t result = dns_rdata_tostruct(&rdata, &nsec3param, NULL); INSIST(result == ISC_R_SUCCESS); if (nsec3param.hash != DNS_NSEC3_UNKNOWNALG && @@ -1114,11 +1108,11 @@ setnsec3parameters(dns_db_t *db, qpz_version_t *version) { * unknown test algorithm. */ if (nsec3param.hash != DNS_NSEC3_UNKNOWNALG) { - goto unlock; + break; } } } -unlock: + NODE_UNLOCK(nlock, &nlocktype); } @@ -1256,7 +1250,7 @@ newversion(dns_db_t *db, dns_dbversion_t **versionp) { } static void -resigninsert(dns_slabheader_t *newheader) { +resigninsert(dns_vecheader_t *newheader) { REQUIRE(newheader->heap_index == 0); LOCK(get_heap_lock(newheader)); @@ -1266,7 +1260,7 @@ resigninsert(dns_slabheader_t *newheader) { static void resigndelete(qpzonedb_t *qpdb ISC_ATTR_UNUSED, qpz_version_t *version, - dns_slabheader_t *header DNS__DB_FLARG) { + dns_vecheader_t *header DNS__DB_FLARG) { if (header == NULL || header->heap_index == 0) { return; } @@ -1305,12 +1299,11 @@ rollback_node(qpznode_t *node, uint32_t serial) { * 'serial'. When the reference count goes to zero, these rdatasets * will be cleaned up; until that time, they will be ignored. */ - DNS_SLABTOP_FOREACH(top, node->data) { - dns_slabheader_t *header = NULL; - cds_list_for_each_entry(header, &top->headers, headers_link) { + ISC_SLIST_FOREACH(top, node->next_type, next_type) { + ISC_SLIST_FOREACH(header, top->headers, next_header) { if (header->serial == serial) { - DNS_SLABHEADER_SETATTR( - header, DNS_SLABHEADERATTR_IGNORE); + DNS_VECHEADER_SETATTR( + header, DNS_VECHEADERATTR_IGNORE); make_dirty = true; } } @@ -1506,7 +1499,7 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, ISC_LIST_FOREACH(resigned_list, resigned, link) { isc_rwlock_t *nlock = NULL; isc_rwlocktype_t nlocktype = isc_rwlocktype_none; - dns_slabheader_t *header = resigned->header; + dns_vecheader_t *header = resigned->header; ISC_LIST_UNLINK(resigned_list, resigned, link); @@ -1557,7 +1550,7 @@ qpzone_findrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_rdataset_t *sigrdataset DNS__DB_FLARG) { qpzonedb_t *qpdb = (qpzonedb_t *)db; qpznode_t *node = (qpznode_t *)dbnode; - dns_slabheader_t *found = NULL, *foundsig = NULL; + dns_vecheader_t *found = NULL, *foundsig = NULL; uint32_t serial; qpz_version_t *version = (qpz_version_t *)dbversion; bool close_version = false; @@ -1589,8 +1582,8 @@ qpzone_findrdataset(dns_db_t *db, dns_dbnode_t *dbnode, sigpair = dns_typepair_none; } - DNS_SLABTOP_FOREACH(top, node->data) { - dns_slabheader_t *header = first_existing_header(top, serial); + ISC_SLIST_FOREACH(top, node->next_type, next_type) { + dns_vecheader_t *header = first_existing_header(top, serial); if (header != NULL) { /* * We have an active, extant rdataset. If it's a @@ -1705,7 +1698,7 @@ cname_and_other(qpznode_t *node, uint32_t serial) { * ("Other data" is any rdataset whose type is not KEY, NSEC, SIG * or RRSIG. */ - DNS_SLABTOP_FOREACH(top, node->data) { + ISC_SLIST_FOREACH(top, node->next_type, next_type) { dns_rdatatype_t rdtype = DNS_TYPEPAIR_TYPE(top->typepair); if (rdtype == dns_rdatatype_cname) { if (first_existing_header(top, serial) != NULL) { @@ -1739,7 +1732,7 @@ cname_and_other(qpznode_t *node, uint32_t serial) { } static qpz_changed_t * -add_changed(qpzonedb_t *qpdb, dns_slabheader_t *header, +add_changed(qpzonedb_t *qpdb, dns_vecheader_t *header, qpz_version_t *version DNS__DB_FLARG) { qpz_changed_t *changed = NULL; qpznode_t *node = HEADERNODE(header); @@ -1758,24 +1751,24 @@ add_changed(qpzonedb_t *qpdb, dns_slabheader_t *header, } static uint64_t -recordsize(dns_slabheader_t *header, unsigned int namelen) { - return dns_rdataslab_size(header) + sizeof(dns_ttl_t) + +recordsize(dns_vecheader_t *header, unsigned int namelen) { + return dns_rdatavec_size(header) + sizeof(dns_ttl_t) + sizeof(dns_rdatatype_t) + sizeof(dns_rdataclass_t) + namelen; } static void maybe_update_recordsandsize(bool add, qpz_version_t *version, - dns_slabheader_t *header, unsigned int namelen) { + dns_vecheader_t *header, unsigned int namelen) { if (!EXISTS(header)) { return; } RWLOCK(&version->rwlock, isc_rwlocktype_write); if (add) { - version->records += dns_rdataslab_count(header); + version->records += dns_rdatavec_count(header); version->xfrsize += recordsize(header, namelen); } else { - version->records -= dns_rdataslab_count(header); + version->records -= dns_rdatavec_count(header); version->xfrsize -= recordsize(header, namelen); } RWUNLOCK(&version->rwlock, isc_rwlocktype_write); @@ -1783,13 +1776,13 @@ maybe_update_recordsandsize(bool add, qpz_version_t *version, static isc_result_t add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename, - qpz_version_t *version, dns_slabheader_t *newheader, unsigned int options, + qpz_version_t *version, dns_vecheader_t *newheader, unsigned int options, bool loading, dns_rdataset_t *addedrdataset, isc_stdtime_t now ISC_ATTR_UNUSED DNS__DB_FLARG) { qpz_changed_t *changed = NULL; - dns_slabtop_t *foundtop = NULL; - dns_slabtop_t *priotop = NULL; - dns_slabheader_t *merged = NULL; + dns_vectop_t *foundtop = NULL; + dns_vectop_t *priotop = NULL; + dns_vecheader_t *merged = NULL; isc_result_t result; bool merge = false; uint32_t ntypes; @@ -1810,7 +1803,7 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename, } ntypes = 0; - DNS_SLABTOP_FOREACH(top, node->data) { + ISC_SLIST_FOREACH(top, node->next_type, next_type) { ++ntypes; if (prio_type(top->typepair)) { priotop = top; @@ -1826,15 +1819,12 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename, * IGNORE rdatasets between the top of the chain and the first real * data. We skip over them. */ - dns_slabheader_t *header = NULL; + dns_vecheader_t **header_p = NULL; + dns_vecheader_t *header = NULL; if (foundtop != NULL) { - dns_slabheader_t *tmp = NULL; - cds_list_for_each_entry(tmp, &top->headers, headers_link) { - if (!IGNORE(tmp)) { - header = tmp; - break; - } - } + header_p = first_existing_header_indirect(foundtop, UINT32_MAX); + INSIST(header_p != NULL); + header = EXISTS(*header_p) ? *header_p : NULL; } if (header != NULL) { @@ -1860,7 +1850,7 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename, flags |= DNS_RDATASLAB_FORCE; } if (result == ISC_R_SUCCESS) { - result = dns_rdataslab_merge( + result = dns_rdatavec_merge( header, newheader, qpdb->common.mctx, qpdb->common.rdclass, DNS_TYPEPAIR_TYPE(header->typepair), @@ -1875,11 +1865,14 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename, * alone. It will get cleaned up when * clean_zone_node() runs. */ - dns_slabheader_destroy(&newheader); + dns_vecheader_destroy(&newheader); newheader = merged; - dns_slabheader_reset(newheader, + dns_vecheader_reset(newheader, (dns_dbnode_t *)node); - dns_slabheader_copycase(newheader, header); + /* + * dns_rdatavec_subtract takes the header from + * the first argument, so it preserves the case + */ if (loading && RESIGN(newheader) && RESIGN(header) && resign_sooner(header, newheader)) @@ -1896,7 +1889,7 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename, header->typepair), "updating", qpdb->maxrrperset); } - dns_slabheader_destroy(&newheader); + dns_vecheader_destroy(&newheader); return result; } } @@ -1916,14 +1909,12 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename, * Since we don't generate changed records when * loading, we MUST clean up 'header' now. */ - newheader->top = foundtop; - cds_list_del(&header->headers_link); - cds_list_add(&newheader->headers_link, - &foundtop->headers); + *header_p = ISC_SLIST_NEXT(header, next_header); + ISC_SLIST_PREPEND(foundtop->headers, newheader, next_header); maybe_update_recordsandsize(false, version, header, nodename->length); - dns_slabheader_destroy(&header); + dns_vecheader_destroy(&header); } else { if (RESIGN(newheader)) { resigninsert(newheader); @@ -1931,9 +1922,7 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename, header DNS__DB_FLARG_PASS); } - newheader->top = foundtop; - cds_list_add(&newheader->headers_link, - &foundtop->headers); + ISC_SLIST_PREPEND(foundtop->headers, newheader, next_header); node->dirty = true; if (changed != NULL) { @@ -1950,7 +1939,7 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename, * If we're trying to delete the type, don't bother. */ if (!EXISTS(newheader)) { - dns_slabheader_destroy(&newheader); + dns_vecheader_destroy(&newheader); return DNS_R_UNCHANGED; } @@ -1970,9 +1959,7 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename, */ INSIST(!loading); - newheader->top = foundtop; - cds_list_add(&newheader->headers_link, - &foundtop->headers); + ISC_SLIST_PREPEND(foundtop->headers, newheader, next_header); if (changed != NULL) { changed->dirty = true; @@ -1986,27 +1973,24 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename, if (qpdb->maxtypepername > 0 && ntypes >= qpdb->maxtypepername) { - dns_slabheader_destroy(&newheader); + dns_vecheader_destroy(&newheader); return DNS_R_TOOMANYRECORDS; } - dns_slabtop_t *newtop = dns_slabtop_new( + dns_vectop_t *newtop = dns_vectop_new( node->mctx, newheader->typepair); - newheader->top = newtop; - cds_list_add(&newheader->headers_link, - &newtop->headers); + ISC_SLIST_PREPEND(newtop->headers, newheader, next_header); if (prio_type(newheader->typepair)) { /* This is a priority type, prepend it */ - cds_list_add(&newtop->types_link, node->data); + ISC_SLIST_PREPEND(node->next_type, newtop, next_type); } else if (priotop != NULL) { /* Append after the priority headers */ - cds_list_add(&newtop->types_link, - &priotop->types_link); + ISC_SLIST_INSERTAFTER(priotop, newtop, next_type); } else { /* There were no priority headers */ - cds_list_add(&newtop->types_link, node->data); + ISC_SLIST_PREPEND(node->next_type, newtop, next_type); } } } @@ -2080,7 +2064,6 @@ loading_addrdataset(void *arg, const dns_name_t *name, dns_rdataset_t *rdataset, qpznode_t *node = NULL; isc_result_t result = ISC_R_SUCCESS; isc_region_t region; - dns_slabheader_t *newheader = NULL; isc_rwlocktype_t nlocktype = isc_rwlocktype_none; isc_rwlock_t *nlock = NULL; @@ -2121,7 +2104,7 @@ loading_addrdataset(void *arg, const dns_name_t *name, dns_rdataset_t *rdataset, } loading_addnode(loadctx, name, rdataset->type, rdataset->covers, &node); - result = dns_rdataslab_fromrdataset(rdataset, node->mctx, ®ion, + result = dns_rdatavec_fromrdataset(rdataset, node->mctx, ®ion, qpdb->maxrrperset); if (result != ISC_R_SUCCESS) { if (result == DNS_R_TOOMANYRECORDS) { @@ -2132,16 +2115,16 @@ loading_addrdataset(void *arg, const dns_name_t *name, dns_rdataset_t *rdataset, return result; } - newheader = (dns_slabheader_t *)region.base; - dns_slabheader_reset(newheader, (dns_dbnode_t *)node); + dns_vecheader_t *newheader = (dns_vecheader_t *)region.base; + dns_vecheader_reset(newheader, (dns_dbnode_t *)node); newheader->ttl = rdataset->ttl; - atomic_store(&newheader->trust, rdataset->trust); newheader->serial = 1; + atomic_store(&newheader->trust, rdataset->trust); - dns_slabheader_setownercase(newheader, name); + dns_vecheader_setownercase(newheader, name); if (rdataset->attributes.resign) { - DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_RESIGN); + DNS_VECHEADER_SETATTR(newheader, DNS_VECHEADERATTR_RESIGN); newheader->resign = (isc_stdtime_t)(dns_time64_from32(rdataset->resign) >> 1); @@ -2329,15 +2312,15 @@ getsize(dns_db_t *db, dns_dbversion_t *dbversion, uint64_t *records, static isc_result_t setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, isc_stdtime_t resign) { qpzonedb_t *qpdb = (qpzonedb_t *)db; - dns_slabheader_t *header = NULL, oldheader; + dns_vecheader_t *header = NULL, oldheader; isc_rwlocktype_t nlocktype = isc_rwlocktype_none; isc_rwlock_t *nlock = NULL; REQUIRE(VALID_QPZONE(qpdb)); REQUIRE(rdataset != NULL); - REQUIRE(rdataset->methods == &dns_rdataslab_rdatasetmethods); + REQUIRE(rdataset->methods == &dns_rdatavec_rdatasetmethods); - header = dns_rdataset_getheader(rdataset); + header = dns_vecheader_getheader(rdataset); nlock = qpzone_get_lock(HEADERNODE(header)); NODE_WRLOCK(nlock, &nlocktype); @@ -2370,7 +2353,7 @@ setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, isc_stdtime_t resign) { } UNLOCK(get_heap_lock(header)); } else if (resign != 0) { - DNS_SLABHEADER_SETATTR(header, DNS_SLABHEADERATTR_RESIGN); + DNS_VECHEADER_SETATTR(header, DNS_VECHEADERATTR_RESIGN); resigninsert(header); } NODE_UNLOCK(nlock, &nlocktype); @@ -2381,7 +2364,7 @@ static isc_result_t getsigningtime(dns_db_t *db, isc_stdtime_t *resign, dns_name_t *foundname, dns_typepair_t *typepair) { qpzonedb_t *qpdb = (qpzonedb_t *)db; - dns_slabheader_t *header = NULL; + dns_vecheader_t *header = NULL; isc_rwlocktype_t nlocktype = isc_rwlocktype_none; isc_rwlock_t *nlock = NULL; isc_result_t result = ISC_R_NOTFOUND; @@ -2574,29 +2557,23 @@ qpzone_findnsec3node(dns_db_t *db, const dns_name_t *name, bool create, } static bool -matchparams(dns_slabheader_t *header, qpz_search_t *search) { +matchparams(dns_vecheader_t *header, qpz_search_t *search) { dns_rdata_nsec3_t nsec3; - unsigned char *raw = NULL; - unsigned int rdlen, count; - isc_region_t region; isc_result_t result; REQUIRE(header->typepair == DNS_TYPEPAIR(dns_rdatatype_nsec3)); - raw = (unsigned char *)header + sizeof(*header); - count = get_uint16(raw); - - while (count-- > 0) { + rdatavec_iter_t iter; + for (isc_result_t res = vecheader_first(&iter, header, search->qpdb->common.rdclass); + res == ISC_R_SUCCESS; + res = vecheader_next(&iter)) + { dns_rdata_t rdata = DNS_RDATA_INIT; + vecheader_current(&iter, &rdata); - rdlen = get_uint16(raw); - region.base = raw; - region.length = rdlen; - dns_rdata_fromregion(&rdata, search->qpdb->common.rdclass, - dns_rdatatype_nsec3, ®ion); - raw += rdlen; result = dns_rdata_tostruct(&rdata, &nsec3, NULL); INSIST(result == ISC_R_SUCCESS); + if (nsec3.hash == search->version->hash && nsec3.iterations == search->version->iterations && nsec3.salt_length == search->version->salt_length && @@ -2606,6 +2583,7 @@ matchparams(dns_slabheader_t *header, qpz_search_t *search) { return true; } } + return false; } @@ -2691,10 +2669,10 @@ step(qpz_search_t *search, dns_qpiter_t *it, direction_t direction, while (result == ISC_R_SUCCESS) { isc_rwlock_t *nlock = qpzone_get_lock(node); isc_rwlocktype_t nlocktype = isc_rwlocktype_none; - dns_slabheader_t *found = NULL; + dns_vecheader_t *found = NULL; NODE_RDLOCK(nlock, &nlocktype); - DNS_SLABTOP_FOREACH(top, node->data) { + ISC_SLIST_FOREACH(top, node->next_type, next_type) { found = first_existing_header(top, search->serial); } NODE_UNLOCK(nlock, &nlocktype); @@ -2817,7 +2795,7 @@ wildcard_blocked(qpz_search_t *search, const dns_name_t *qname, static bool node_active(qpz_search_t *search, qpznode_t *node) { - DNS_SLABTOP_FOREACH(top, node->data) { + ISC_SLIST_FOREACH(top, node->next_type, next_type) { if (first_existing_header(top, search->serial) != NULL) { return true; } @@ -3077,16 +3055,16 @@ find_closest_nsec(qpz_search_t *search, dns_dbnode_t **nodep, dns_name_copy(&node->name, name); again: do { - dns_slabheader_t *found = NULL, *foundsig = NULL; + dns_vecheader_t *found = NULL, *foundsig = NULL; isc_rwlocktype_t nlocktype = isc_rwlocktype_none; isc_rwlock_t *nlock = qpzone_get_lock(node); NODE_RDLOCK(nlock, &nlocktype); empty_node = true; - DNS_SLABTOP_FOREACH(top, node->data) { + ISC_SLIST_FOREACH(top, node->next_type, next_type) { /* * Look for an active, extant NSEC or RRSIG NSEC. */ - dns_slabheader_t *header = + dns_vecheader_t *header = first_existing_header(top, search->serial); if (header != NULL) { /* @@ -3202,9 +3180,9 @@ again: static isc_result_t qpzone_check_zonecut(qpznode_t *node, void *arg DNS__DB_FLARG) { qpz_search_t *search = arg; - dns_slabheader_t *dname_header = NULL, *sigdname_header = NULL; - dns_slabheader_t *ns_header = NULL; - dns_slabheader_t *found = NULL; + dns_vecheader_t *dname_header = NULL, *sigdname_header = NULL; + dns_vecheader_t *ns_header = NULL; + dns_vecheader_t *found = NULL; isc_result_t result = DNS_R_CONTINUE; isc_rwlocktype_t nlocktype = isc_rwlocktype_none; isc_rwlock_t *nlock = qpzone_get_lock(node); @@ -3214,12 +3192,12 @@ qpzone_check_zonecut(qpznode_t *node, void *arg DNS__DB_FLARG) { /* * Look for an NS or DNAME rdataset active in our version. */ - DNS_SLABTOP_FOREACH(top, node->data) { + ISC_SLIST_FOREACH(top, node->next_type, next_type) { if (top->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) || top->typepair == DNS_TYPEPAIR(dns_rdatatype_dname) || top->typepair == DNS_SIGTYPEPAIR(dns_rdatatype_dname)) { - dns_slabheader_t *header = + dns_vecheader_t *header = first_existing_header(top, search->serial); if (header != NULL) { if (top->typepair == @@ -3359,8 +3337,8 @@ qpzone_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, bool maybe_zonecut = false, at_zonecut = false; bool wild = false, empty_node = false; bool nsec3 = false; - dns_slabheader_t *found = NULL, *nsecheader = NULL; - dns_slabheader_t *foundsig = NULL, *cnamesig = NULL, *nsecsig = NULL; + dns_vecheader_t *found = NULL, *nsecheader = NULL; + dns_vecheader_t *foundsig = NULL, *cnamesig = NULL, *nsecsig = NULL; dns_typepair_t sigpair; bool active; isc_rwlock_t *nlock = NULL; @@ -3536,11 +3514,11 @@ found: sigpair = DNS_SIGTYPEPAIR(type); empty_node = true; - DNS_SLABTOP_FOREACH(top, node->data) { + ISC_SLIST_FOREACH(top, node->next_type, next_type) { /* * Look for an active, extant rdataset. */ - dns_slabheader_t *header = first_existing_header(top, + dns_vecheader_t *header = first_existing_header(top, search.serial); if (header != NULL) { /* @@ -3962,7 +3940,7 @@ getoriginnode(dns_db_t *db, dns_dbnode_t **nodep DNS__DB_FLARG) { static void deletedata(dns_dbnode_t *node ISC_ATTR_UNUSED, void *data) { - dns_slabheader_t *header = data; + dns_vecheader_t *header = data; if (header->heap_index != 0) { LOCK(get_heap_lock(header)); @@ -4006,7 +3984,7 @@ rdatasetiter_first(dns_rdatasetiter_t *iterator DNS__DB_FLARG) { NODE_RDLOCK(nlock, &nlocktype); - DNS_SLABTOP_FOREACH(top, node->data) { + ISC_SLIST_FOREACH(top, node->next_type, next_type) { qrditer->current = first_existing_header(top, version->serial); if (qrditer->current != NULL) { @@ -4031,7 +4009,7 @@ rdatasetiter_next(dns_rdatasetiter_t *iterator DNS__DB_FLARG) { qpz_version_t *version = (qpz_version_t *)qrditer->common.version; isc_rwlocktype_t nlocktype = isc_rwlocktype_none; isc_rwlock_t *nlock = qpzone_get_lock(node); - dns_slabtop_t *from = NULL; + dns_vectop_t *from = NULL; if (qrditer->currenttop == NULL) { return ISC_R_NOMORE; @@ -4039,8 +4017,7 @@ rdatasetiter_next(dns_rdatasetiter_t *iterator DNS__DB_FLARG) { NODE_RDLOCK(nlock, &nlocktype); - from = cds_list_entry(qrditer->currenttop->types_link.next, - dns_slabtop_t, types_link); + from = ISC_SLIST_NEXT(qrditer->currenttop, next_type); qrditer->currenttop = NULL; qrditer->current = NULL; @@ -4048,7 +4025,7 @@ rdatasetiter_next(dns_rdatasetiter_t *iterator DNS__DB_FLARG) { * Find the start of the header chain for the next type. */ if (from != NULL) { - DNS_SLABTOP_FOREACH_FROM(top, node->data, from) { + ISC_SLIST_FOREACH_FROM(top, node->next_type, next_type, from) { qrditer->current = first_existing_header(top, version->serial); if (qrditer->current != NULL) { @@ -4075,7 +4052,7 @@ rdatasetiter_current(dns_rdatasetiter_t *iterator, qpznode_t *qpnode = (qpznode_t *)qrditer->common.node; isc_rwlocktype_t nlocktype = isc_rwlocktype_none; isc_rwlock_t *nlock = qpzone_get_lock(qpnode); - dns_slabheader_t *header = qrditer->current; + dns_vecheader_t *header = qrditer->current; REQUIRE(header != NULL); @@ -4695,7 +4672,6 @@ qpzone_addrdataset_inner(dns_db_t *db, dns_dbnode_t *dbnode, qpznode_t *node = (qpznode_t *)dbnode; qpz_version_t *version = (qpz_version_t *)dbversion; isc_region_t region; - dns_slabheader_t *newheader = NULL; isc_rwlocktype_t nlocktype = isc_rwlocktype_none; isc_rwlock_t *nlock = NULL; dns_fixedname_t fn; @@ -4718,7 +4694,7 @@ qpzone_addrdataset_inner(dns_db_t *db, dns_dbnode_t *dbnode, rdataset->type != dns_rdatatype_nsec3 && rdataset->covers != dns_rdatatype_nsec3)); - result = dns_rdataslab_fromrdataset(rdataset, node->mctx, ®ion, + result = dns_rdatavec_fromrdataset(rdataset, node->mctx, ®ion, qpdb->maxrrperset); if (result != ISC_R_SUCCESS) { if (result == DNS_R_TOOMANYRECORDS) { @@ -4732,18 +4708,19 @@ qpzone_addrdataset_inner(dns_db_t *db, dns_dbnode_t *dbnode, dns_name_copy(&node->name, name); dns_rdataset_getownercase(rdataset, name); - newheader = (dns_slabheader_t *)region.base; - dns_slabheader_reset(newheader, (dns_dbnode_t *)node); - dns_slabheader_setownercase(newheader, name); + dns_vecheader_t *newheader = (dns_vecheader_t *)region.base; + dns_vecheader_reset(newheader, (dns_dbnode_t *)node); + + dns_vecheader_setownercase(newheader, name); newheader->ttl = rdataset->ttl; if (rdataset->ttl == 0U) { - DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_ZEROTTL); + DNS_VECHEADER_SETATTR(newheader, DNS_VECHEADERATTR_ZEROTTL); } newheader->serial = version->serial; if (rdataset->attributes.resign) { - DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_RESIGN); + DNS_VECHEADER_SETATTR(newheader, DNS_VECHEADERATTR_RESIGN); newheader->resign = (isc_stdtime_t)(dns_time64_from32(rdataset->resign) >> 1); @@ -4848,9 +4825,9 @@ qpzone_subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode, qpz_version_t *version = (qpz_version_t *)dbversion; dns_fixedname_t fname; dns_name_t *nodename = dns_fixedname_initname(&fname); - dns_slabtop_t *foundtop = NULL; - dns_slabheader_t *newheader = NULL; - dns_slabheader_t *subresult = NULL; + dns_vectop_t *foundtop = NULL; + dns_vecheader_t *newheader = NULL; + dns_vecheader_t *subresult = NULL; isc_region_t region; isc_result_t result; qpz_changed_t *changed = NULL; @@ -4868,18 +4845,18 @@ qpzone_subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode, rdataset->covers != dns_rdatatype_nsec3)); dns_name_copy(&node->name, nodename); - result = dns_rdataslab_fromrdataset(rdataset, node->mctx, ®ion, 0); + result = dns_rdatavec_fromrdataset(rdataset, node->mctx, ®ion, 0); if (result != ISC_R_SUCCESS) { return result; } - newheader = (dns_slabheader_t *)region.base; - dns_slabheader_reset(newheader, (dns_dbnode_t *)node); + newheader = (dns_vecheader_t *)region.base; + dns_vecheader_reset(newheader, (dns_dbnode_t *)node); newheader->ttl = rdataset->ttl; atomic_init(&newheader->attributes, 0); newheader->serial = version->serial; if (rdataset->attributes.resign) { - DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_RESIGN); + DNS_VECHEADER_SETATTR(newheader, DNS_VECHEADERATTR_RESIGN); newheader->resign = (isc_stdtime_t)(dns_time64_from32(rdataset->resign) >> 1); @@ -4890,7 +4867,7 @@ qpzone_subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode, NODE_WRLOCK(nlock, &nlocktype); changed = add_changed(qpdb, newheader, version DNS__DB_FLARG_PASS); - DNS_SLABTOP_FOREACH(top, node->data) { + ISC_SLIST_FOREACH(top, node->next_type, next_type) { if (top->typepair == newheader->typepair) { foundtop = top; break; @@ -4901,10 +4878,9 @@ qpzone_subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode, * IGNORE rdatasets between the top of the chain and the first real * data. We skip over them. */ - dns_slabheader_t *header = NULL; + dns_vecheader_t *header = NULL; if (foundtop != NULL) { - dns_slabheader_t *tmp = NULL; - cds_list_for_each_entry(tmp, &foundtop->headers, headers_link) { + ISC_SLIST_FOREACH(tmp, foundtop->headers, next_header) { if (!IGNORE(tmp)) { header = tmp; break; @@ -4922,32 +4898,35 @@ qpzone_subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode, } } if (result == ISC_R_SUCCESS) { - result = dns_rdataslab_subtract( + result = dns_rdatavec_subtract( header, newheader, qpdb->common.mctx, qpdb->common.rdclass, DNS_TYPEPAIR_TYPE(foundtop->typepair), flags, &subresult); } if (result == ISC_R_SUCCESS) { - dns_slabheader_destroy(&newheader); + dns_vecheader_destroy(&newheader); newheader = subresult; - dns_slabheader_reset(newheader, (dns_dbnode_t *)node); - dns_slabheader_copycase(newheader, header); + dns_vecheader_reset(newheader, (dns_dbnode_t *)node); + /* + * dns_rdatavec_subtract takes the header from the first + * argument, so it preserves the case + */ if (RESIGN(header)) { - DNS_SLABHEADER_SETATTR( - newheader, DNS_SLABHEADERATTR_RESIGN); + DNS_VECHEADER_SETATTR( + newheader, DNS_VECHEADERATTR_RESIGN); newheader->resign = header->resign; newheader->resign_lsb = header->resign_lsb; resigninsert(newheader); } /* - * We have to set the serial since the rdataslab + * We have to set the serial since the rdatavec * subtraction routine copies the reserved portion of * header, not newheader. */ newheader->serial = version->serial; /* - * XXXJT: dns_rdataslab_subtract() copied the pointers + * XXXJT: dns_rdatavec_subtract() copied the pointers * to additional info. We need to clear these fields * to avoid having duplicated references. */ @@ -4958,16 +4937,16 @@ qpzone_subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode, * This subtraction would remove all of the rdata; * add a nonexistent header instead. */ - dns_slabheader_destroy(&newheader); - newheader = dns_slabheader_new(db->mctx, + dns_vecheader_destroy(&newheader); + newheader = dns_vecheader_new(db->mctx, (dns_dbnode_t *)node); newheader->ttl = 0; newheader->typepair = foundtop->typepair; atomic_init(&newheader->attributes, - DNS_SLABHEADERATTR_NONEXISTENT); + DNS_VECHEADERATTR_NONEXISTENT); newheader->serial = version->serial; } else { - dns_slabheader_destroy(&newheader); + dns_vecheader_destroy(&newheader); goto unlock; } @@ -4977,8 +4956,7 @@ qpzone_subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode, maybe_update_recordsandsize(false, version, header, nodename->length); - newheader->top = foundtop; - cds_list_add(&newheader->headers_link, &foundtop->headers); + ISC_SLIST_PREPEND(foundtop->headers, newheader, next_header); node->dirty = true; changed->dirty = true; @@ -4988,7 +4966,7 @@ qpzone_subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode, * The rdataset doesn't exist, so we don't need to do anything * to satisfy the deletion request. */ - dns_slabheader_destroy(&newheader); + dns_vecheader_destroy(&newheader); if ((options & DNS_DBSUB_EXACT) != 0) { result = DNS_R_NOTEXACT; } else { @@ -5023,7 +5001,7 @@ qpzone_deleterdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_fixedname_t fname; dns_name_t *nodename = dns_fixedname_initname(&fname); isc_result_t result; - dns_slabheader_t *newheader = NULL; + dns_vecheader_t *newheader = NULL; isc_rwlocktype_t nlocktype = isc_rwlocktype_none; isc_rwlock_t *nlock = NULL; @@ -5037,10 +5015,10 @@ qpzone_deleterdataset(dns_db_t *db, dns_dbnode_t *dbnode, return ISC_R_NOTIMPLEMENTED; } - newheader = dns_slabheader_new(db->mctx, (dns_dbnode_t *)node); + newheader = dns_vecheader_new(db->mctx, (dns_dbnode_t *)node); newheader->typepair = DNS_TYPEPAIR_VALUE(type, covers); newheader->ttl = 0; - atomic_init(&newheader->attributes, DNS_SLABHEADERATTR_NONEXISTENT); + atomic_init(&newheader->attributes, DNS_VECHEADERATTR_NONEXISTENT); newheader->serial = version->serial; dns_name_copy(&node->name, nodename); @@ -5066,7 +5044,7 @@ new_glue(isc_mem_t *mctx, const dns_name_t *name) { } static dns_gluelist_t * -new_gluelist(dns_db_t *db, dns_slabheader_t *header, +new_gluelist(dns_db_t *db, dns_vecheader_t *header, const dns_dbversion_t *dbversion) { dns_gluelist_t *gluelist = isc_mem_get(db->mctx, sizeof(*gluelist)); *gluelist = (dns_gluelist_t){ @@ -5288,7 +5266,7 @@ addglue_to_message(dns_glue_t *ge, dns_message_t *msg) { static dns_gluelist_t * create_gluelist(qpzonedb_t *qpdb, qpz_version_t *version, qpznode_t *node, dns_rdataset_t *rdataset) { - dns_slabheader_t *header = dns_rdataset_getheader(rdataset); + dns_vecheader_t *header = dns_vecheader_getheader(rdataset); dns_glue_additionaldata_ctx_t ctx = { .db = (dns_db_t *)qpdb, .version = (dns_dbversion_t *)version, @@ -5316,13 +5294,13 @@ addglue(dns_db_t *db, dns_dbversion_t *dbversion, dns_rdataset_t *rdataset, dns_message_t *msg) { qpzonedb_t *qpdb = (qpzonedb_t *)db; qpz_version_t *version = (qpz_version_t *)dbversion; - qpznode_t *node = (qpznode_t *)rdataset->slab.node; - dns_slabheader_t *header = dns_rdataset_getheader(rdataset); + qpznode_t *node = (qpznode_t *)rdataset->vec.node; + dns_vecheader_t *header = dns_vecheader_getheader(rdataset); dns_glue_t *glue = NULL; isc_statscounter_t counter = dns_gluecachestatscounter_hits_absent; REQUIRE(rdataset->type == dns_rdatatype_ns); - REQUIRE(qpdb == (qpzonedb_t *)rdataset->slab.db); + REQUIRE(qpdb == (qpzonedb_t *)rdataset->vec.db); REQUIRE(qpdb == version->qpdb); REQUIRE(!IS_STUB(qpdb)); @@ -5585,16 +5563,12 @@ static dns_dbnode_methods_t qpznode_methods = (dns_dbnode_methods_t){ static void destroy_qpznode(qpznode_t *node) { - DNS_SLABTOP_FOREACH(top, node->data) { - dns_slabheader_t *header = NULL, *header_next = NULL; - cds_list_for_each_entry_safe(header, header_next, &top->headers, - headers_link) - { - cds_list_del(&header->headers_link); - dns_slabheader_destroy(&header); + ISC_SLIST_FOREACH(top, node->next_type, next_type) { + ISC_SLIST_FOREACH(header, top->headers, next_header) { + dns_vecheader_destroy(&header); } - dns_slabtop_destroy(node->mctx, &top); + dns_vectop_destroy(node->mctx, &top); } qpz_heap_unref(node->heap); diff --git a/lib/dns/rdataset.c b/lib/dns/rdataset.c index 533b9b9556..3d629109ed 100644 --- a/lib/dns/rdataset.c +++ b/lib/dns/rdataset.c @@ -588,17 +588,6 @@ dns_rdataset_trimttl(dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, sigrdataset->ttl = ttl; } -dns_slabheader_t * -dns_rdataset_getheader(const dns_rdataset_t *rdataset) { - REQUIRE(DNS_RDATASET_VALID(rdataset)); - - if (rdataset->methods->getheader != NULL) { - return (rdataset->methods->getheader)(rdataset); - } - - return NULL; -} - isc_stdtime_t dns_rdataset_minresign(dns_rdataset_t *rdataset) { dns_rdata_t rdata = DNS_RDATA_INIT; diff --git a/lib/dns/rdataslab.c b/lib/dns/rdataslab.c index 2754b9ec70..578e84ae50 100644 --- a/lib/dns/rdataslab.c +++ b/lib/dns/rdataslab.c @@ -92,7 +92,6 @@ dns_rdatasetmethods_t dns_rdataslab_rdatasetmethods = { .expire = rdataset_expire, .clearprefetch = rdataset_clearprefetch, .getownercase = rdataset_getownercase, - .getheader = rdataset_getheader, }; /*% Note: the "const void *" are just to make qsort happy. */ @@ -126,7 +125,7 @@ makeslab(dns_rdataset_t *rdataset, isc_mem_t *mctx, isc_region_t *region, * new buffer. */ if (rdataset->methods == &dns_rdataslab_rdatasetmethods) { - dns_slabheader_t *header = dns_rdataset_getheader(rdataset); + dns_slabheader_t *header = rdataset_getheader(rdataset); buflen = dns_rdataslab_size(header); rawbuf = isc_mem_get(mctx, buflen); @@ -1120,7 +1119,7 @@ rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name, static void rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) { - dns_slabheader_t *header = dns_rdataset_getheader(rdataset); + dns_slabheader_t *header = rdataset_getheader(rdataset); rdataset->trust = trust; atomic_store(&header->trust, trust); @@ -1128,21 +1127,21 @@ rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) { static void rdataset_expire(dns_rdataset_t *rdataset DNS__DB_FLARG) { - dns_slabheader_t *header = dns_rdataset_getheader(rdataset); + dns_slabheader_t *header = rdataset_getheader(rdataset); dns_db_expiredata(header->node, header); } static void rdataset_clearprefetch(dns_rdataset_t *rdataset) { - dns_slabheader_t *header = dns_rdataset_getheader(rdataset); + dns_slabheader_t *header = rdataset_getheader(rdataset); DNS_SLABHEADER_CLRATTR(header, DNS_SLABHEADERATTR_PREFETCH); } static void rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name) { - dns_slabheader_t *header = dns_rdataset_getheader(rdataset); + dns_slabheader_t *header = rdataset_getheader(rdataset); uint8_t mask = (1 << 7); uint8_t bits = 0; diff --git a/tests/dns/qpzone_test.c b/tests/dns/qpzone_test.c index 5a369ec29e..479c6f8d71 100644 --- a/tests/dns/qpzone_test.c +++ b/tests/dns/qpzone_test.c @@ -33,11 +33,11 @@ #include #include #include -#include +#include #include #define KEEP_BEFORE -#include "rdataslab_p.h" +#include "rdatavec_p.h" /* Include the main file */ @@ -187,17 +187,16 @@ ownercase_test_one(const char *str1, const char *str2) { .common.mctx = isc_g_mctx, }; qpznode_t node = { .methods = &qpznode_methods, .locknum = 0 }; - dns_slabheader_t header = { + dns_vecheader_t header = { .node = (dns_dbnode_t *)&node, }; - unsigned char *raw = (unsigned char *)(&header) + sizeof(header); dns_rdataset_t rdataset = { .magic = DNS_RDATASET_MAGIC, - .slab = { .db = (dns_db_t *)qpdb, - .node = (dns_dbnode_t *)&node, - .raw = raw, + .vec = { .db = (dns_db_t *)qpdb, + .node = (dns_dbnode_t *)&node, + .header = &header, }, - .methods = &dns_rdataslab_rdatasetmethods, + .methods = &dns_rdatavec_rdatasetmethods, }; isc_buffer_t b; dns_fixedname_t fname1, fname2; @@ -216,7 +215,7 @@ ownercase_test_one(const char *str1, const char *str2) { assert_int_equal(result, ISC_R_SUCCESS); /* Store the case from name1 */ - dns_slabheader_setownercase(&header, name1); + dns_vecheader_setownercase(&header, name1); assert_true(CASESET(&header)); @@ -361,17 +360,16 @@ ISC_RUN_TEST_IMPL(setownercase) { .common.mctx = isc_g_mctx, }; qpznode_t node = { .methods = &qpznode_methods, .locknum = 0 }; - dns_slabheader_t header = { + dns_vecheader_t header = { .node = (dns_dbnode_t *)&node, }; - unsigned char *raw = (unsigned char *)(&header) + sizeof(header); dns_rdataset_t rdataset = { .magic = DNS_RDATASET_MAGIC, - .slab = { .db = (dns_db_t *)qpdb, - .node = (dns_dbnode_t *)&node, - .raw = raw, + .vec = { .db = (dns_db_t *)qpdb, + .node = (dns_dbnode_t *)&node, + .header = &header, }, - .methods = &dns_rdataslab_rdatasetmethods, + .methods = &dns_rdatavec_rdatasetmethods, }; const char *str1 = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"; From 9d74a913019248f4ea8a787563b3ba1023826fc9 Mon Sep 17 00:00:00 2001 From: Alessio Podda Date: Tue, 9 Dec 2025 21:05:27 +0100 Subject: [PATCH 5/7] Add DNS_VECHEADER_FOREACH Add a FOREACH macro modelled around the DNS_RDATASET_FOREACH one, that uses vecheader directly. Useful when you want to manipulate a vecheader without binding it to avoid having to take the node lock inside qpzone.c. --- lib/dns/qpzone.c | 10 ++-------- lib/dns/rdatavec_p.h | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/lib/dns/qpzone.c b/lib/dns/qpzone.c index 706d218ff2..d2317774f2 100644 --- a/lib/dns/qpzone.c +++ b/lib/dns/qpzone.c @@ -1076,10 +1076,7 @@ setnsec3parameters(dns_db_t *db, qpz_version_t *version) { */ rdatavec_iter_t iter; - for (isc_result_t res = vecheader_first(&iter, found, qpdb->common.rdclass); - res == ISC_R_SUCCESS; - res = vecheader_next(&iter)) - { + DNS_VECHEADER_FOREACH(&iter, found, qpdb->common.rdclass) { dns_rdata_t rdata = DNS_RDATA_INIT; vecheader_current(&iter, &rdata); @@ -2564,10 +2561,7 @@ matchparams(dns_vecheader_t *header, qpz_search_t *search) { REQUIRE(header->typepair == DNS_TYPEPAIR(dns_rdatatype_nsec3)); rdatavec_iter_t iter; - for (isc_result_t res = vecheader_first(&iter, header, search->qpdb->common.rdclass); - res == ISC_R_SUCCESS; - res = vecheader_next(&iter)) - { + DNS_VECHEADER_FOREACH(&iter, header, search->qpdb->common.rdclass) { dns_rdata_t rdata = DNS_RDATA_INIT; vecheader_current(&iter, &rdata); diff --git a/lib/dns/rdatavec_p.h b/lib/dns/rdatavec_p.h index f26371656a..62717f10f7 100644 --- a/lib/dns/rdatavec_p.h +++ b/lib/dns/rdatavec_p.h @@ -67,3 +67,17 @@ vecheader_next(rdatavec_iter_t *iter); void vecheader_current(rdatavec_iter_t *iter, dns_rdata_t *rdata); + +/* clang-format off */ +/* + * An adaptation of DNS_RDATASET_FOREACH from rdataset.h. Used to manipulate a + * vecheader without going through the rdataset interface, e.g. in qpzone.c. + */ +#define DNS__VECHEADER_CONNECT(x,y) x##y +#define DNS__VECHEADER_CONCAT(x,y) DNS__VECHEADER_CONNECT(x,y) +#define DNS_VECHEADER_FOREACH_RES(iter, header, rdclass, res) \ + for (isc_result_t res = vecheader_first((iter), (header), (rdclass)); \ + res == ISC_R_SUCCESS; res = vecheader_next((iter))) +#define DNS_VECHEADER_FOREACH(iter, header, rdclass) \ + DNS_VECHEADER_FOREACH_RES(iter, header, rdclass, DNS__VECHEADER_CONCAT(x, __LINE__)) +/* clang-format on */ From 852041457ec981bdb2248c83cfcdd8bfab6359c2 Mon Sep 17 00:00:00 2001 From: Alessio Podda Date: Mon, 24 Nov 2025 09:55:31 +0100 Subject: [PATCH 6/7] Add vecheader unit tests Adds unit tests for the new rdatavec, doing basic size and case checking. --- tests/dns/meson.build | 1 + tests/dns/vecheader_test.c | 290 +++++++++++++++++++++++++++++++++++++ 2 files changed, 291 insertions(+) create mode 100644 tests/dns/vecheader_test.c diff --git a/tests/dns/meson.build b/tests/dns/meson.build index 8d765013a8..dcbf853c72 100644 --- a/tests/dns/meson.build +++ b/tests/dns/meson.build @@ -44,6 +44,7 @@ dns_tests = [ 'tsig', 'unreachcache', 'update', + 'vecheader', 'zonefile', 'zonemgr', 'zt', diff --git a/tests/dns/vecheader_test.c b/tests/dns/vecheader_test.c new file mode 100644 index 0000000000..4f7590f198 --- /dev/null +++ b/tests/dns/vecheader_test.c @@ -0,0 +1,290 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include /* IWYU pragma: keep */ +#include +#include +#include +#include +#include + +#define UNIT_TESTING +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* Helper function to create a vecheader directly */ +static isc_result_t +create_vecheader(isc_mem_t *mctx, dns_rdatatype_t type, dns_rdataclass_t rdclass, + dns_ttl_t ttl, const char *rdata_text, dns_vecheader_t **headerp) +{ + dns_rdataset_t rdataset; + dns_rdatalist_t *rdatalist; + dns_rdata_t *rdata; + unsigned char *data; + isc_region_t region; + isc_result_t result; + + /* Allocate temporary structures */ + data = isc_mem_get(mctx, 256); + rdatalist = isc_mem_get(mctx, sizeof(*rdatalist)); + rdata = isc_mem_get(mctx, sizeof(*rdata)); + + /* Initialize rdataset and rdatalist */ + dns_rdataset_init(&rdataset); + dns_rdatalist_init(rdatalist); + rdatalist->type = type; + rdatalist->rdclass = rdclass; + rdatalist->ttl = ttl; + + /* Create rdata */ + dns_rdata_init(rdata); + CHECK(dns_test_rdatafromstring(rdata, rdclass, type, data, + 256, rdata_text, false)); + + ISC_LIST_APPEND(rdatalist->rdata, rdata, link); + dns_rdatalist_tordataset(rdatalist, &rdataset); + + /* Convert to vecheader */ + CHECK(dns_rdatavec_fromrdataset(&rdataset, mctx, ®ion, 0)); + *headerp = (dns_vecheader_t *)region.base; + + /* Cleanup rdataset */ + dns_rdataset_disassociate(&rdataset); + +cleanup: + /* Cleanup temporary structures */ + isc_mem_put(mctx, rdata, sizeof(*rdata)); + isc_mem_put(mctx, rdatalist, sizeof(*rdatalist)); + isc_mem_put(mctx, data, 256); + + return result; +} + +/* Helper function to create an rdataset from a vecheader */ +static void +create_rdataset_from_vecheader(dns_vecheader_t *header, dns_rdataclass_t rdclass, + dns_rdatatype_t type, dns_rdataset_t *rdataset) +{ + dns_rdataset_init(rdataset); + rdataset->methods = &dns_rdatavec_rdatasetmethods; + rdataset->rdclass = rdclass; + rdataset->type = type; + rdataset->vec.header = header; +} + +/* Test merging two headers */ +ISC_RUN_TEST_IMPL(merge_headers) { + isc_mem_t *mctx = isc_g_mctx; + UNUSED(state); + dns_vecheader_t *header1 = NULL, *header2 = NULL, *merged_header = NULL; + unsigned int size1, size2, merged_size, expected_size; + unsigned int count1, count2, merged_count, expected_count; + isc_result_t result; + + /* Create vecheaders with A records */ + CHECK(create_vecheader(mctx, dns_rdatatype_a, dns_rdataclass_in, + 300, "192.168.1.1", &header1)); + + CHECK(create_vecheader(mctx, dns_rdatatype_a, dns_rdataclass_in, + 300, "192.168.1.2", &header2)); + + /* Get sizes and counts before merging */ + size1 = dns_rdatavec_size(header1); + size2 = dns_rdatavec_size(header2); + count1 = dns_rdatavec_count(header1); + count2 = dns_rdatavec_count(header2); + + /* Merge headers */ + CHECK(dns_rdatavec_merge(header1, header2, mctx, dns_rdataclass_in, + dns_rdatatype_a, 0, 0, &merged_header)); + assert_non_null(merged_header); + + /* Get merged size and count */ + merged_size = dns_rdatavec_size(merged_header); + merged_count = dns_rdatavec_count(merged_header); + + /* Test: merged size should be first_size + second_size - sizeof(header) - count_field_size */ + expected_size = size1 + size2 - sizeof(dns_vecheader_t) - 2; + assert_int_equal(merged_size, expected_size); + + /* Test: merged count should be first_count + second_count */ + expected_count = count1 + count2; + assert_int_equal(merged_count, expected_count); + +cleanup: + /* Cleanup */ + if (header1 != NULL) { + size1 = dns_rdatavec_size(header1); + isc_mem_put(mctx, header1, size1); + } + if (header2 != NULL) { + size2 = dns_rdatavec_size(header2); + isc_mem_put(mctx, header2, size2); + } + if (merged_header != NULL) { + merged_size = dns_rdatavec_size(merged_header); + isc_mem_put(mctx, merged_header, merged_size); + } +} + +/* Test case preservation during merge */ +ISC_RUN_TEST_IMPL(merge_case_preservation) { + isc_mem_t *mctx = isc_g_mctx; + UNUSED(state); + dns_vecheader_t *header1 = NULL, *header2 = NULL, *merged_header = NULL; + dns_fixedname_t fname1, fname2, fmerged_name; + dns_name_t *name1 = dns_fixedname_initname(&fname1); + dns_name_t *name2 = dns_fixedname_initname(&fname2); + dns_name_t *merged_name = dns_fixedname_initname(&fmerged_name); + unsigned int size1, size2, merged_size; + isc_result_t result; + + dns_test_namefromstring("Example.COM", &fname1); + dns_test_namefromstring("example.com", &fname2); + + /* Create vecheaders */ + CHECK(create_vecheader(mctx, dns_rdatatype_a, dns_rdataclass_in, + 300, "192.168.1.1", &header1)); + + CHECK(create_vecheader(mctx, dns_rdatatype_a, dns_rdataclass_in, + 300, "192.168.1.2", &header2)); + + /* Set case on first header */ + dns_vecheader_setownercase(header1, name1); + + /* Set case on second header */ + dns_vecheader_setownercase(header2, name2); + + /* Get sizes */ + size1 = dns_rdatavec_size(header1); + size2 = dns_rdatavec_size(header2); + + /* Merge headers */ + CHECK(dns_rdatavec_merge(header1, header2, mctx, dns_rdataclass_in, + dns_rdatatype_a, 0, 0, &merged_header)); + assert_non_null(merged_header); + + /* Test: case should be the same as the first header */ + /* Copy the name for testing */ + dns_name_copy(name1, merged_name); + + /* Create a test rdataset from merged header to test case */ + dns_rdataset_t test_rdataset; + create_rdataset_from_vecheader(merged_header, dns_rdataclass_in, + dns_rdatatype_a, &test_rdataset); + + /* Apply case from merged header */ + dns_rdataset_getownercase(&test_rdataset, merged_name); + + /* The case should match the original first name */ + assert_true(dns_name_caseequal(name1, merged_name)); + +cleanup: + /* Cleanup */ + if (header1 != NULL) { + size1 = dns_rdatavec_size(header1); + isc_mem_put(mctx, header1, size1); + } + if (header2 != NULL) { + size2 = dns_rdatavec_size(header2); + isc_mem_put(mctx, header2, size2); + } + if (merged_header != NULL) { + merged_size = dns_rdatavec_size(merged_header); + isc_mem_put(mctx, merged_header, merged_size); + } +} + +/* Test size consistency after setting case */ +ISC_RUN_TEST_IMPL(setcase_size_consistency) { + isc_mem_t *mctx = isc_g_mctx; + UNUSED(state); + dns_vecheader_t *header = NULL; + dns_fixedname_t fname, flower_fname, fretrieved_fname; + dns_name_t *name = dns_fixedname_initname(&fname); + dns_name_t *lower_name = dns_fixedname_initname(&flower_fname); + dns_name_t *retrieved_name = dns_fixedname_initname(&fretrieved_fname); + unsigned int original_size, cased_size; + dns_rdataset_t test_rdataset; + isc_result_t result; + + /* Initialize name */ + dns_test_namefromstring("Example.COM", &fname); + + /* Create vecheader */ + CHECK(create_vecheader(mctx, dns_rdatatype_a, dns_rdataclass_in, + 300, "192.168.1.1", &header)); + + /* Get original size */ + original_size = dns_rdatavec_size(header); + + /* Set case */ + dns_vecheader_setownercase(header, name); + + /* Get size after setting case */ + cased_size = dns_rdatavec_size(header); + + /* Test: size should be the same after setting case */ + assert_int_equal(cased_size, original_size); + + /* Create lowercase version of the original name */ + dns_test_namefromstring("example.com", &flower_fname); + + /* Copy lowercase name to retrieved_name for testing */ + dns_name_copy(lower_name, retrieved_name); + + /* Create a test rdataset from cased header */ + create_rdataset_from_vecheader(header, dns_rdataclass_in, + dns_rdatatype_a, &test_rdataset); + + /* Apply case from cased header to retrieved_name */ + dns_rdataset_getownercase(&test_rdataset, retrieved_name); + + /* Test: retrieved case should match the original mixed case */ + assert_true(dns_name_caseequal(name, retrieved_name)); + +cleanup: + /* Cleanup */ + if (header != NULL) { + cased_size = dns_rdatavec_size(header); + isc_mem_put(mctx, header, cased_size); + } +} + +ISC_TEST_LIST_START +ISC_TEST_ENTRY_CUSTOM(merge_headers, setup_mctx, teardown_mctx) +ISC_TEST_ENTRY_CUSTOM(merge_case_preservation, setup_mctx, teardown_mctx) +ISC_TEST_ENTRY_CUSTOM(setcase_size_consistency, setup_mctx, teardown_mctx) +ISC_TEST_LIST_END + +ISC_TEST_MAIN From f1d8c3059caaee0b24d3364681cd759bd37490c6 Mon Sep 17 00:00:00 2001 From: Alessio Podda Date: Tue, 9 Dec 2025 22:49:16 +0100 Subject: [PATCH 7/7] Fix formatting --- lib/dns/include/dns/rdataset.h | 11 +++--- lib/dns/include/dns/rdatavec.h | 36 +++++++++---------- lib/dns/qpzone.c | 64 +++++++++++++++++++--------------- lib/dns/rdatavec.c | 55 ++++++++++++++--------------- lib/dns/rdatavec_p.h | 4 +-- lib/isc/include/isc/slist.h | 18 +++++----- tests/dns/qpzone_test.c | 2 +- tests/dns/vecheader_test.c | 39 +++++++++++---------- 8 files changed, 115 insertions(+), 114 deletions(-) diff --git a/lib/dns/include/dns/rdataset.h b/lib/dns/include/dns/rdataset.h index 938e725ede..49b8a9e1a3 100644 --- a/lib/dns/include/dns/rdataset.h +++ b/lib/dns/include/dns/rdataset.h @@ -51,8 +51,8 @@ #include #include -#include #include +#include #include #define DNS_RDATASET_MAXADDITIONAL 13 @@ -208,10 +208,10 @@ struct dns_rdataset { * methods; see comments in rdatavec.c for details.) */ struct { - struct dns_db *db; - dns_dbnode_t *node; - dns_vecheader_t *header; - rdatavec_iter_t iter; + struct dns_db *db; + dns_dbnode_t *node; + dns_vecheader_t *header; + rdatavec_iter_t iter; } vec; /* @@ -635,7 +635,6 @@ dns_trust_totext(dns_trust_t trust); * Display trust in textual form. */ - isc_stdtime_t dns_rdataset_minresign(dns_rdataset_t *rdataset); /*%< diff --git a/lib/dns/include/dns/rdatavec.h b/lib/dns/include/dns/rdatavec.h index 04534eca07..f7ba2e1a26 100644 --- a/lib/dns/include/dns/rdatavec.h +++ b/lib/dns/include/dns/rdatavec.h @@ -58,15 +58,14 @@ #define DNS_RDATAVEC_OFFLINE 0x01 /* RRSIG is for offline DNSKEY */ - -typedef struct dns_vectop dns_vectop_t; +typedef struct dns_vectop dns_vectop_t; typedef struct dns_vecheader dns_vecheader_t; struct rdatavec_iter { - unsigned char *iter_pos; - unsigned int iter_count; + unsigned char *iter_pos; + unsigned int iter_count; dns_rdataclass_t iter_rdclass; - dns_rdatatype_t iter_type; + dns_rdatatype_t iter_type; }; typedef struct rdatavec_iter rdatavec_iter_t; @@ -91,7 +90,8 @@ struct dns_vecheader { dns_ttl_t ttl; dns_typepair_t typepair; - /* resigning (zone). The lsb is not adjacent for struct packing reasons */ + /* resigning (zone). The lsb is not adjacent for struct packing reasons + */ isc_stdtime_t resign; /*% @@ -102,7 +102,7 @@ struct dns_vecheader { /*% * The database node objects containing this rdataset, if any. */ - dns_dbnode_t *node; + dns_dbnode_t *node; /*% * Cached glue records for an rdataset of type NS (zone only). @@ -114,16 +114,15 @@ struct dns_vecheader { * character in the owner name needs to be AND'd with 0x20, * rendering that character upper case. */ - unsigned char upper[32]; + unsigned char upper[32]; /*% * Flexible member indicates the address of the raw data * following this header. */ - unsigned char raw[]; + unsigned char raw[]; }; - enum { DNS_VECHEADERATTR_NONEXISTENT = 1 << 0, DNS_VECHEADERATTR_IGNORE = 1 << 1, @@ -151,7 +150,7 @@ extern dns_rdatasetmethods_t dns_rdatavec_rdatasetmethods; isc_result_t dns_rdatavec_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx, - isc_region_t *region, uint32_t limit); + isc_region_t *region, uint32_t limit); /*%< * Allocate space for a vec to hold the data in rdataset, and copy the * data into it. The resulting vec will be returned in 'region'. @@ -204,18 +203,18 @@ dns_rdatavec_count(dns_vecheader_t *header); isc_result_t dns_rdatavec_merge(dns_vecheader_t *oheader, dns_vecheader_t *nheader, - isc_mem_t *mctx, dns_rdataclass_t rdclass, - dns_rdatatype_t type, unsigned int flags, - uint32_t maxrrperset, dns_vecheader_t **theaderp); + isc_mem_t *mctx, dns_rdataclass_t rdclass, + dns_rdatatype_t type, unsigned int flags, + uint32_t maxrrperset, dns_vecheader_t **theaderp); /*%< * Merge the vecs following 'oheader' and 'nheader'. */ isc_result_t dns_rdatavec_subtract(dns_vecheader_t *mheader, dns_vecheader_t *sheader, - isc_mem_t *mctx, dns_rdataclass_t rdclass, - dns_rdatatype_t type, unsigned int flags, - dns_vecheader_t **theaderp); + isc_mem_t *mctx, dns_rdataclass_t rdclass, + dns_rdatatype_t type, unsigned int flags, + dns_vecheader_t **theaderp); /*%< * Subtract the vec following 'sheader' from the one following 'mheader'. * If 'exact' is true then all elements from the 'sheader' vec must exist @@ -225,7 +224,6 @@ dns_rdatavec_subtract(dns_vecheader_t *mheader, dns_vecheader_t *sheader, * valid flags are DNS_RDATAVEC_EXACT */ - void dns_vecheader_setownercase(dns_vecheader_t *header, const dns_name_t *name); /*%< @@ -236,7 +234,6 @@ dns_vecheader_setownercase(dns_vecheader_t *header, const dns_name_t *name); * \li 'name' is a valid name. */ - void dns_vecheader_reset(dns_vecheader_t *h, dns_dbnode_t *node); /*%< @@ -257,7 +254,6 @@ dns_vecheader_destroy(dns_vecheader_t **headerp); * Free all memory associated with '*headerp'. */ - dns_vectop_t * dns_vectop_new(isc_mem_t *mctx, dns_typepair_t typepair); /*%< diff --git a/lib/dns/qpzone.c b/lib/dns/qpzone.c index d2317774f2..fadcd0996d 100644 --- a/lib/dns/qpzone.c +++ b/lib/dns/qpzone.c @@ -32,8 +32,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -54,10 +54,8 @@ #include #include #include -#include - -#include "rdatavec_p.h" #include +#include #include #include #include @@ -499,7 +497,7 @@ cleanup_gluelists(struct cds_wfs_stack *glue_stack) { dns_gluelist_t *gluelist = caa_container_of(node, dns_gluelist_t, wfs_node); dns_vecheader_t *header = rcu_xchg_pointer(&gluelist->header, - NULL); + NULL); (void)rcu_cmpxchg_pointer(&header->gluelist, gluelist, NULL); call_rcu(&gluelist->rcu_head, free_gluelist_rcu); @@ -813,7 +811,6 @@ first_header(dns_vectop_t *top) { return ISC_SLIST_HEAD(top->headers); } - static dns_vecheader_t * first_existing_header(dns_vectop_t *top, uint32_t serial) { ISC_SLIST_FOREACH(header, top->headers, next_header) { @@ -872,7 +869,8 @@ clean_multiple_versions(dns_vectop_t *top, uint32_t least_serial) { } bool multiple = false; - dns_vecheader_t **pointer_to_second_header = &ISC_SLIST_NEXT(ISC_SLIST_HEAD(top->headers), next_header); + dns_vecheader_t **pointer_to_second_header = + &ISC_SLIST_NEXT(ISC_SLIST_HEAD(top->headers), next_header); ISC_SLIST_FOREACH_PTR(p, pointer_to_second_header) { dns_vecheader_t *header = *p; if (header->serial < least_serial) { @@ -922,7 +920,7 @@ clean_zone_node(qpznode_t *node, uint32_t least_serial) { } } - /* + /* * Second pass: remove all empty vectops */ ISC_SLIST_FOREACH_PTR(iter, &ISC_SLIST_HEAD(node->next_type)) { @@ -1080,7 +1078,8 @@ setnsec3parameters(dns_db_t *db, qpz_version_t *version) { dns_rdata_t rdata = DNS_RDATA_INIT; vecheader_current(&iter, &rdata); - isc_result_t result = dns_rdata_tostruct(&rdata, &nsec3param, NULL); + isc_result_t result = + dns_rdata_tostruct(&rdata, &nsec3param, NULL); INSIST(result == ISC_R_SUCCESS); if (nsec3param.hash != DNS_NSEC3_UNKNOWNALG && @@ -1299,8 +1298,8 @@ rollback_node(qpznode_t *node, uint32_t serial) { ISC_SLIST_FOREACH(top, node->next_type, next_type) { ISC_SLIST_FOREACH(header, top->headers, next_header) { if (header->serial == serial) { - DNS_VECHEADER_SETATTR( - header, DNS_VECHEADERATTR_IGNORE); + DNS_VECHEADER_SETATTR(header, + DNS_VECHEADERATTR_IGNORE); make_dirty = true; } } @@ -1865,8 +1864,8 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename, dns_vecheader_destroy(&newheader); newheader = merged; dns_vecheader_reset(newheader, - (dns_dbnode_t *)node); - /* + (dns_dbnode_t *)node); + /* * dns_rdatavec_subtract takes the header from * the first argument, so it preserves the case */ @@ -1907,7 +1906,8 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename, * loading, we MUST clean up 'header' now. */ *header_p = ISC_SLIST_NEXT(header, next_header); - ISC_SLIST_PREPEND(foundtop->headers, newheader, next_header); + ISC_SLIST_PREPEND(foundtop->headers, newheader, + next_header); maybe_update_recordsandsize(false, version, header, nodename->length); @@ -1919,7 +1919,8 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename, header DNS__DB_FLARG_PASS); } - ISC_SLIST_PREPEND(foundtop->headers, newheader, next_header); + ISC_SLIST_PREPEND(foundtop->headers, newheader, + next_header); node->dirty = true; if (changed != NULL) { @@ -1956,7 +1957,8 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename, */ INSIST(!loading); - ISC_SLIST_PREPEND(foundtop->headers, newheader, next_header); + ISC_SLIST_PREPEND(foundtop->headers, newheader, + next_header); if (changed != NULL) { changed->dirty = true; @@ -1974,20 +1976,24 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename, return DNS_R_TOOMANYRECORDS; } - dns_vectop_t *newtop = dns_vectop_new( - node->mctx, newheader->typepair); + dns_vectop_t *newtop = + dns_vectop_new(node->mctx, newheader->typepair); - ISC_SLIST_PREPEND(newtop->headers, newheader, next_header); + ISC_SLIST_PREPEND(newtop->headers, newheader, + next_header); if (prio_type(newheader->typepair)) { /* This is a priority type, prepend it */ - ISC_SLIST_PREPEND(node->next_type, newtop, next_type); + ISC_SLIST_PREPEND(node->next_type, newtop, + next_type); } else if (priotop != NULL) { /* Append after the priority headers */ - ISC_SLIST_INSERTAFTER(priotop, newtop, next_type); + ISC_SLIST_INSERTAFTER(priotop, newtop, + next_type); } else { /* There were no priority headers */ - ISC_SLIST_PREPEND(node->next_type, newtop, next_type); + ISC_SLIST_PREPEND(node->next_type, newtop, + next_type); } } } @@ -2102,7 +2108,7 @@ loading_addrdataset(void *arg, const dns_name_t *name, dns_rdataset_t *rdataset, loading_addnode(loadctx, name, rdataset->type, rdataset->covers, &node); result = dns_rdatavec_fromrdataset(rdataset, node->mctx, ®ion, - qpdb->maxrrperset); + qpdb->maxrrperset); if (result != ISC_R_SUCCESS) { if (result == DNS_R_TOOMANYRECORDS) { dns__db_logtoomanyrecords((dns_db_t *)qpdb, name, @@ -3513,7 +3519,7 @@ found: * Look for an active, extant rdataset. */ dns_vecheader_t *header = first_existing_header(top, - search.serial); + search.serial); if (header != NULL) { /* * We now know that there is at least one active @@ -4689,7 +4695,7 @@ qpzone_addrdataset_inner(dns_db_t *db, dns_dbnode_t *dbnode, rdataset->covers != dns_rdatatype_nsec3)); result = dns_rdatavec_fromrdataset(rdataset, node->mctx, ®ion, - qpdb->maxrrperset); + qpdb->maxrrperset); if (result != ISC_R_SUCCESS) { if (result == DNS_R_TOOMANYRECORDS) { dns__db_logtoomanyrecords((dns_db_t *)qpdb, &node->name, @@ -4902,13 +4908,13 @@ qpzone_subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_vecheader_destroy(&newheader); newheader = subresult; dns_vecheader_reset(newheader, (dns_dbnode_t *)node); - /* + /* * dns_rdatavec_subtract takes the header from the first * argument, so it preserves the case */ if (RESIGN(header)) { - DNS_VECHEADER_SETATTR( - newheader, DNS_VECHEADERATTR_RESIGN); + DNS_VECHEADER_SETATTR(newheader, + DNS_VECHEADERATTR_RESIGN); newheader->resign = header->resign; newheader->resign_lsb = header->resign_lsb; resigninsert(newheader); @@ -4933,7 +4939,7 @@ qpzone_subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode, */ dns_vecheader_destroy(&newheader); newheader = dns_vecheader_new(db->mctx, - (dns_dbnode_t *)node); + (dns_dbnode_t *)node); newheader->ttl = 0; newheader->typepair = foundtop->typepair; atomic_init(&newheader->attributes, diff --git a/lib/dns/rdatavec.c b/lib/dns/rdatavec.c index 7f7c38045d..9b69bf5e6e 100644 --- a/lib/dns/rdatavec.c +++ b/lib/dns/rdatavec.c @@ -97,27 +97,27 @@ compare_rdata(const void *p1, const void *p2) { } static size_t -header_size(const dns_vecheader_t* header) { +header_size(const dns_vecheader_t *header) { UNUSED(header); return sizeof(dns_vecheader_t); } -static unsigned char* -rdatavec_raw(dns_vecheader_t* header) { - unsigned char *as_char_star = (unsigned char*) header; - unsigned char* raw = as_char_star + header_size(header); +static unsigned char * +rdatavec_raw(dns_vecheader_t *header) { + unsigned char *as_char_star = (unsigned char *)header; + unsigned char *raw = as_char_star + header_size(header); return raw; } -static unsigned char* -rdatavec_data(dns_vecheader_t* header) { +static unsigned char * +rdatavec_data(dns_vecheader_t *header) { return rdatavec_raw(header) + 2; } -static unsigned int -rdatavec_count(dns_vecheader_t* header) { - unsigned char* raw = rdatavec_raw(header); +static unsigned int +rdatavec_count(dns_vecheader_t *header) { + unsigned char *raw = rdatavec_raw(header); unsigned int count = get_uint16(raw); return count; @@ -125,7 +125,7 @@ rdatavec_count(dns_vecheader_t* header) { static isc_result_t makevec(dns_rdataset_t *rdataset, isc_mem_t *mctx, isc_region_t *region, - uint32_t maxrrperset) { + uint32_t maxrrperset) { /* * Use &removed as a sentinel pointer for duplicate * rdata as rdata.data == NULL is valid. @@ -318,7 +318,7 @@ free_rdatas: isc_result_t dns_rdatavec_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx, - isc_region_t *region, uint32_t maxrrperset) { + isc_region_t *region, uint32_t maxrrperset) { isc_result_t result; if (rdataset->type == dns_rdatatype_none && @@ -389,7 +389,7 @@ dns_rdatavec_count(dns_vecheader_t *header) { */ static void rdata_from_vecitem(unsigned char **current, dns_rdataclass_t rdclass, - dns_rdatatype_t type, dns_rdata_t *rdata) { + dns_rdatatype_t type, dns_rdata_t *rdata) { unsigned char *tcurrent = *current; isc_region_t region; bool offline = false; @@ -414,7 +414,7 @@ rdata_from_vecitem(unsigned char **current, dns_rdataclass_t rdclass, static void rdata_to_vecitem(unsigned char **current, dns_rdatatype_t type, - dns_rdata_t *rdata) { + dns_rdata_t *rdata) { unsigned int length = rdata->length; unsigned char *data = rdata->data; unsigned char *p = *current; @@ -439,9 +439,9 @@ typedef struct vecinfo { isc_result_t dns_rdatavec_merge(dns_vecheader_t *oheader, dns_vecheader_t *nheader, - isc_mem_t *mctx, dns_rdataclass_t rdclass, - dns_rdatatype_t type, unsigned int flags, - uint32_t maxrrperset, dns_vecheader_t **theaderp) { + isc_mem_t *mctx, dns_rdataclass_t rdclass, + dns_rdatatype_t type, unsigned int flags, + uint32_t maxrrperset, dns_vecheader_t **theaderp) { isc_result_t result = ISC_R_SUCCESS; unsigned char *ocurrent = NULL, *ncurrent = NULL, *tcurrent = NULL; unsigned int ocount, ncount, tlength, tcount = 0; @@ -561,9 +561,9 @@ dns_rdatavec_merge(dns_vecheader_t *oheader, dns_vecheader_t *nheader, /* Allocate the target buffer and copy the new vec's header */ unsigned char *tstart = isc_mem_get(mctx, tlength); - dns_vecheader_t *as_header = (dns_vecheader_t*) tstart; + dns_vecheader_t *as_header = (dns_vecheader_t *)tstart; - /* + /* * Preserve the case of the old header, but the rest from the new * header */ @@ -626,9 +626,9 @@ cleanup: isc_result_t dns_rdatavec_subtract(dns_vecheader_t *oheader, dns_vecheader_t *sheader, - isc_mem_t *mctx, dns_rdataclass_t rdclass, - dns_rdatatype_t type, unsigned int flags, - dns_vecheader_t **theaderp) { + isc_mem_t *mctx, dns_rdataclass_t rdclass, + dns_rdatatype_t type, unsigned int flags, + dns_vecheader_t **theaderp) { isc_result_t result = ISC_R_SUCCESS; unsigned char *ocurrent = NULL, *scurrent = NULL; unsigned char *tstart = NULL, *tcurrent = NULL; @@ -756,7 +756,6 @@ cleanup: return result; } - void dns_vecheader_setownercase(dns_vecheader_t *header, const dns_name_t *name) { REQUIRE(!CASESET(header)); @@ -775,8 +774,7 @@ dns_vecheader_setownercase(dns_vecheader_t *header, const dns_name_t *name) { } } if (casefullylower) { - DNS_VECHEADER_SETATTR(header, - DNS_VECHEADERATTR_CASEFULLYLOWER); + DNS_VECHEADER_SETATTR(header, DNS_VECHEADERATTR_CASEFULLYLOWER); } DNS_VECHEADER_SETATTR(header, DNS_VECHEADERATTR_CASESET); } @@ -826,7 +824,8 @@ dns_vecheader_destroy(dns_vecheader_t **headerp) { /* Iterators for already bound rdatavec */ isc_result_t -vecheader_first(rdatavec_iter_t *iter, dns_vecheader_t *header, dns_rdataclass_t rdclass) { +vecheader_first(rdatavec_iter_t *iter, dns_vecheader_t *header, + dns_rdataclass_t rdclass) { unsigned char *raw = rdatavec_data(header); uint16_t count = rdatavec_count(header); if (count == 0) { @@ -899,7 +898,6 @@ vecheader_current(rdatavec_iter_t *iter, dns_rdata_t *rdata) { rdata->flags |= flags; } - /* Fixed RRSet helper macros */ static void @@ -911,7 +909,8 @@ rdataset_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG) { static isc_result_t rdataset_first(dns_rdataset_t *rdataset) { - return vecheader_first(&rdataset->vec.iter, rdataset->vec.header, rdataset->rdclass); + return vecheader_first(&rdataset->vec.iter, rdataset->vec.header, + rdataset->rdclass); } static isc_result_t diff --git a/lib/dns/rdatavec_p.h b/lib/dns/rdatavec_p.h index 62717f10f7..b2e93e73a2 100644 --- a/lib/dns/rdatavec_p.h +++ b/lib/dns/rdatavec_p.h @@ -58,9 +58,9 @@ dns_vecheader_getheader(const dns_rdataset_t *rdataset); * \li 'rdataset' is a valid rdataset using rdatavec methods. */ - isc_result_t -vecheader_first(rdatavec_iter_t *iter, dns_vecheader_t *header, dns_rdataclass_t rdclass); +vecheader_first(rdatavec_iter_t *iter, dns_vecheader_t *header, + dns_rdataclass_t rdclass); isc_result_t vecheader_next(rdatavec_iter_t *iter); diff --git a/lib/isc/include/isc/slist.h b/lib/isc/include/isc/slist.h index 91a8dc6b52..e9490accf2 100644 --- a/lib/isc/include/isc/slist.h +++ b/lib/isc/include/isc/slist.h @@ -21,9 +21,9 @@ * similar to isc/list.h but optimized for forward-only traversal. */ -#define ISC_SLIST_INITIALIZER \ - { \ - .head = NULL, \ +#define ISC_SLIST_INITIALIZER \ + { \ + .head = NULL, \ } #define ISC_SLINK_INITIALIZER \ @@ -44,16 +44,16 @@ #define ISC_SLIST_HEAD(list) ((list).head) #define ISC_SLIST_EMPTY(list) ((list).head == NULL) -#define ISC_SLIST_PREPEND(list, elt, link) \ - ({ \ +#define ISC_SLIST_PREPEND(list, elt, link) \ + ({ \ (elt)->link.next = (list).head; \ (list).head = (elt); \ }) -#define ISC_SLIST_INSERTAFTER(after, elt, link) \ - ({ \ +#define ISC_SLIST_INSERTAFTER(after, elt, link) \ + ({ \ (elt)->link.next = (after)->link.next; \ - (after)->link.next = (elt); \ + (after)->link.next = (elt); \ }) #define ISC_SLIST_NEXT(elt, link) ((elt)->link.next) @@ -73,7 +73,7 @@ /* Iteration over pointer-to-pointer for safe operations */ #define ISC_SLIST_FOREACH_PTR(p, head) \ - for (typeof(head) p = (head); *p != NULL; ) + for (typeof(head) p = (head); *p != NULL;) #define ISC_SLIST_PTR_REMOVE(p, elt, link_field) \ (*(p) = ISC_SLIST_NEXT(elt, link_field)) diff --git a/tests/dns/qpzone_test.c b/tests/dns/qpzone_test.c index 479c6f8d71..46c3cd7448 100644 --- a/tests/dns/qpzone_test.c +++ b/tests/dns/qpzone_test.c @@ -33,8 +33,8 @@ #include #include #include -#include #include +#include #define KEEP_BEFORE #include "rdatavec_p.h" diff --git a/tests/dns/vecheader_test.c b/tests/dns/vecheader_test.c index 4f7590f198..fd486bd88f 100644 --- a/tests/dns/vecheader_test.c +++ b/tests/dns/vecheader_test.c @@ -44,9 +44,9 @@ /* Helper function to create a vecheader directly */ static isc_result_t -create_vecheader(isc_mem_t *mctx, dns_rdatatype_t type, dns_rdataclass_t rdclass, - dns_ttl_t ttl, const char *rdata_text, dns_vecheader_t **headerp) -{ +create_vecheader(isc_mem_t *mctx, dns_rdatatype_t type, + dns_rdataclass_t rdclass, dns_ttl_t ttl, + const char *rdata_text, dns_vecheader_t **headerp) { dns_rdataset_t rdataset; dns_rdatalist_t *rdatalist; dns_rdata_t *rdata; @@ -68,8 +68,8 @@ create_vecheader(isc_mem_t *mctx, dns_rdatatype_t type, dns_rdataclass_t rdclass /* Create rdata */ dns_rdata_init(rdata); - CHECK(dns_test_rdatafromstring(rdata, rdclass, type, data, - 256, rdata_text, false)); + CHECK(dns_test_rdatafromstring(rdata, rdclass, type, data, 256, + rdata_text, false)); ISC_LIST_APPEND(rdatalist->rdata, rdata, link); dns_rdatalist_tordataset(rdatalist, &rdataset); @@ -92,9 +92,9 @@ cleanup: /* Helper function to create an rdataset from a vecheader */ static void -create_rdataset_from_vecheader(dns_vecheader_t *header, dns_rdataclass_t rdclass, - dns_rdatatype_t type, dns_rdataset_t *rdataset) -{ +create_rdataset_from_vecheader(dns_vecheader_t *header, + dns_rdataclass_t rdclass, dns_rdatatype_t type, + dns_rdataset_t *rdataset) { dns_rdataset_init(rdataset); rdataset->methods = &dns_rdatavec_rdatasetmethods; rdataset->rdclass = rdclass; @@ -112,11 +112,11 @@ ISC_RUN_TEST_IMPL(merge_headers) { isc_result_t result; /* Create vecheaders with A records */ - CHECK(create_vecheader(mctx, dns_rdatatype_a, dns_rdataclass_in, - 300, "192.168.1.1", &header1)); + CHECK(create_vecheader(mctx, dns_rdatatype_a, dns_rdataclass_in, 300, + "192.168.1.1", &header1)); - CHECK(create_vecheader(mctx, dns_rdatatype_a, dns_rdataclass_in, - 300, "192.168.1.2", &header2)); + CHECK(create_vecheader(mctx, dns_rdatatype_a, dns_rdataclass_in, 300, + "192.168.1.2", &header2)); /* Get sizes and counts before merging */ size1 = dns_rdatavec_size(header1); @@ -133,7 +133,8 @@ ISC_RUN_TEST_IMPL(merge_headers) { merged_size = dns_rdatavec_size(merged_header); merged_count = dns_rdatavec_count(merged_header); - /* Test: merged size should be first_size + second_size - sizeof(header) - count_field_size */ + /* Test: merged size should be first_size + second_size - sizeof(header) + * - count_field_size */ expected_size = size1 + size2 - sizeof(dns_vecheader_t) - 2; assert_int_equal(merged_size, expected_size); @@ -173,11 +174,11 @@ ISC_RUN_TEST_IMPL(merge_case_preservation) { dns_test_namefromstring("example.com", &fname2); /* Create vecheaders */ - CHECK(create_vecheader(mctx, dns_rdatatype_a, dns_rdataclass_in, - 300, "192.168.1.1", &header1)); + CHECK(create_vecheader(mctx, dns_rdatatype_a, dns_rdataclass_in, 300, + "192.168.1.1", &header1)); - CHECK(create_vecheader(mctx, dns_rdatatype_a, dns_rdataclass_in, - 300, "192.168.1.2", &header2)); + CHECK(create_vecheader(mctx, dns_rdatatype_a, dns_rdataclass_in, 300, + "192.168.1.2", &header2)); /* Set case on first header */ dns_vecheader_setownercase(header1, name1); @@ -242,8 +243,8 @@ ISC_RUN_TEST_IMPL(setcase_size_consistency) { dns_test_namefromstring("Example.COM", &fname); /* Create vecheader */ - CHECK(create_vecheader(mctx, dns_rdatatype_a, dns_rdataclass_in, - 300, "192.168.1.1", &header)); + CHECK(create_vecheader(mctx, dns_rdatatype_a, dns_rdataclass_in, 300, + "192.168.1.1", &header)); /* Get original size */ original_size = dns_rdatavec_size(header);