2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-22 01:59:26 +00:00

chg: dev: Split the top level slabheader hierarchy and the individual slabheaders

Merge branch 'ondrej/split-dns_slabheader' into 'main'

See merge request isc-projects/bind9!10826
This commit is contained in:
Ondřej Surý 2025-08-18 13:16:14 +02:00
commit 68153104fa
6 changed files with 622 additions and 647 deletions

View File

@ -64,6 +64,18 @@ struct dns_slabheader_proof {
dns_rdatatype_t type;
};
typedef struct dns_slabtop dns_slabtop_t;
struct dns_slabtop {
dns_slabtop_t *next;
dns_slabheader_t *header;
dns_typepair_t typepair;
/*% Used for SIEVE-LRU (cache) and changed_list (zone) */
ISC_LINK(struct dns_slabtop) link;
/*% Used for SIEVE-LRU */
bool visited;
};
struct dns_slabheader {
_Atomic(uint16_t) attributes;
@ -101,10 +113,8 @@ struct dns_slabheader {
* both head and tail pointers, and is doubly linked.
*/
union {
struct dns_slabheader *next;
struct dns_slabheader *up;
};
dns_slabtop_t *top;
/*%<
* If this is the top header for an rdataset, 'next' points
* to the top header for the next rdataset (i.e., the next type).
@ -127,17 +137,18 @@ struct dns_slabheader {
dns_gluelist_t *gluelist;
/*% Used for SIEVE-LRU (cache) and changed_list (zone) */
ISC_LINK(struct dns_slabheader) link;
/*% Used for SIEVE-LRU */
bool visited;
/*%
* 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 {
@ -273,12 +284,6 @@ dns_rdataslab_equalx(dns_slabheader_t *header1, dns_slabheader_t *header2,
*\li true if the slabs are equal, #false otherwise.
*/
void *
dns_slabheader_raw(dns_slabheader_t *header);
/*%
* Returns the address of the raw memory following a dns_slabheader.
*/
void
dns_slabheader_setownercase(dns_slabheader_t *header, const dns_name_t *name);
/*%<
@ -295,14 +300,14 @@ void
dns_slabheader_reset(dns_slabheader_t *h, dns_dbnode_t *node);
/*%<
* Reset an rdataslab header 'h' so it can be used to store data in
* database 'db' and node 'node'.
* database node 'node'.
*/
dns_slabheader_t *
dns_slabheader_new(dns_db_t *db, dns_dbnode_t *node);
dns_slabheader_new(isc_mem_t *mctx, dns_dbnode_t *node);
/*%<
* Allocate memory for an rdataslab header and initialize it for use
* in database 'db'/node 'node'.
* in database node 'node'.
*/
void
@ -317,8 +322,15 @@ dns_slabheader_freeproof(isc_mem_t *mctx, dns_slabheader_proof_t **proof);
* Free all memory associated with a nonexistence proof.
*/
dns_slabheader_t *
dns_slabheader_top(dns_slabheader_t *header);
dns_slabtop_t *
dns_slabtop_new(isc_mem_t *mctx, dns_typepair_t typepair);
/*%<
* Return the top header for the type or the negtype
* Allocate memory for an rdataslab top and initialize it for use
* with 'typepair' type and covers pair.
*/
void
dns_slabtop_destroy(isc_mem_t *mctx, dns_slabtop_t **topp);
/*%<
* Free all memory associated with '*slabtopp'.
*/

View File

@ -154,23 +154,22 @@ typedef uint8_t dns_secproto_t;
typedef struct dns_signature dns_signature_t;
typedef struct dns_skr dns_skr_t;
typedef struct dns_slabheader dns_slabheader_t;
typedef ISC_LIST(dns_slabheader_t) dns_slabheaderlist_t;
typedef struct dns_ssurule dns_ssurule_t;
typedef struct dns_ssutable dns_ssutable_t;
typedef struct dns_stats dns_stats_t;
typedef uint32_t dns_rdatastatstype_t;
typedef struct dns_tkeyctx dns_tkeyctx_t;
typedef struct dns_transport dns_transport_t;
typedef struct dns_transport_list dns_transport_list_t;
typedef uint16_t dns_trust_t;
typedef struct dns_tsigkeyring dns_tsigkeyring_t;
typedef struct dns_tsigkey dns_tsigkey_t;
typedef uint32_t dns_ttl_t;
typedef uint32_t dns_typepair_t;
typedef struct dns_unreachcache dns_unreachcache_t;
typedef struct dns_update_state dns_update_state_t;
typedef struct dns_validator dns_validator_t;
typedef struct dns_view dns_view_t;
typedef struct dns_ssurule dns_ssurule_t;
typedef struct dns_ssutable dns_ssutable_t;
typedef struct dns_stats dns_stats_t;
typedef uint32_t dns_rdatastatstype_t;
typedef struct dns_tkeyctx dns_tkeyctx_t;
typedef struct dns_transport dns_transport_t;
typedef struct dns_transport_list dns_transport_list_t;
typedef uint16_t dns_trust_t;
typedef struct dns_tsigkeyring dns_tsigkeyring_t;
typedef struct dns_tsigkey dns_tsigkey_t;
typedef uint32_t dns_ttl_t;
typedef uint32_t dns_typepair_t;
typedef struct dns_unreachcache dns_unreachcache_t;
typedef struct dns_update_state dns_update_state_t;
typedef struct dns_validator dns_validator_t;
typedef struct dns_view dns_view_t;
typedef ISC_LIST(dns_view_t) dns_viewlist_t;
typedef struct dns_zone dns_zone_t;
typedef ISC_LIST(dns_zone_t) dns_zonelist_t;

View File

@ -156,7 +156,8 @@ struct qpcnode {
*/
isc_refcount_t references;
isc_refcount_t erefs;
void *data;
dns_slabtop_t *data;
/*%
* NOTE: The 'dirty' flag is protected by the node lock, so
@ -200,13 +201,13 @@ typedef struct qpcache_bucket {
isc_heap_t *heap;
/* SIEVE-LRU cache cleaning state. */
ISC_SIEVE(dns_slabheader_t) sieve;
ISC_SIEVE(dns_slabtop_t) sieve;
/* Padding to prevent false sharing between locks. */
uint8_t __padding[ISC_OS_CACHELINE_SIZE -
(sizeof(isc_queue_t) + sizeof(isc_rwlock_t) +
sizeof(isc_heap_t *) +
sizeof(ISC_SIEVE(dns_slabheader_t))) %
sizeof(ISC_SIEVE(dns_slabtop_t))) %
ISC_OS_CACHELINE_SIZE];
} qpcache_bucket_t;
@ -381,7 +382,7 @@ static dns_rdatasetitermethods_t rdatasetiter_methods = {
typedef struct qpc_rditer {
dns_rdatasetiter_t common;
dns_slabheader_t *current;
dns_slabtop_t *current;
} qpc_rditer_t;
static void
@ -485,13 +486,15 @@ expire_lru_headers(qpcache_t *qpdb, uint32_t idx, size_t requested,
size_t expired = 0;
do {
dns_slabheader_t *header =
ISC_SIEVE_NEXT(qpdb->buckets[idx].sieve, visited, link);
if (header == NULL) {
dns_slabtop_t *top = ISC_SIEVE_NEXT(qpdb->buckets[idx].sieve,
visited, link);
if (top == NULL) {
return;
}
ISC_SIEVE_UNLINK(qpdb->buckets[idx].sieve, header, link);
ISC_SIEVE_UNLINK(qpdb->buckets[idx].sieve, top, link);
dns_slabheader_t *header = top->header;
expired += rdataset_size(header);
@ -528,7 +531,7 @@ qpcache_miss(qpcache_t *qpdb, dns_slabheader_t *newheader,
tlocktypep DNS__DB_FLARG_PASS);
}
ISC_SIEVE_INSERT(qpdb->buckets[idx].sieve, newheader, link);
ISC_SIEVE_INSERT(qpdb->buckets[idx].sieve, newheader->top, link);
}
static void
@ -536,7 +539,7 @@ qpcache_hit(qpcache_t *qpdb ISC_ATTR_UNUSED, dns_slabheader_t *header) {
/*
* On cache hit, we only mark the header as seen.
*/
ISC_SIEVE_MARK(header, visited);
ISC_SIEVE_MARK(header->top, visited);
}
/*
@ -556,30 +559,44 @@ clean_stale_headers(dns_slabheader_t *top) {
static void
clean_cache_node(qpcache_t *qpdb, qpcnode_t *node) {
dns_slabheader_t *current = NULL, *top_prev = NULL, *top_next = NULL;
dns_slabtop_t *top = NULL, *top_prev = NULL, *top_next = NULL;
/*
* Caller must be holding the node lock.
*/
for (current = node->data; current != NULL; current = top_next) {
top_next = current->next;
clean_stale_headers(current);
for (top = node->data; top != NULL; top = top_next) {
top_next = top->next;
clean_stale_headers(top->header);
/*
* If current is nonexistent, ancient, or stale and
* If current header is nonexistent, ancient, or stale and
* we are not keeping stale, we can clean it up.
*/
if (!EXISTS(current) || ANCIENT(current) ||
(STALE(current) && !KEEPSTALE(qpdb)))
if (!EXISTS(top->header) || ANCIENT(top->header) ||
(STALE(top->header) && !KEEPSTALE(qpdb)))
{
dns_slabheader_destroy(&top->header);
}
/*
* If current slabtype is empty, we can also clean it up.
*/
if (top->header == NULL) {
if (top_prev != NULL) {
top_prev->next = current->next;
top_prev->next = top->next;
} else {
node->data = current->next;
node->data = top->next;
}
dns_slabheader_destroy(&current);
if (ISC_LINK_LINKED(top, link)) {
ISC_SIEVE_UNLINK(
qpdb->buckets[node->locknum].sieve, top,
link);
}
dns_slabtop_destroy(((dns_db_t *)qpdb)->mctx, &top);
} else {
top_prev = current;
top_prev = top;
}
}
node->dirty = 0;
@ -1055,7 +1072,7 @@ bindrdataset(qpcache_t *qpdb, qpcnode_t *node, dns_slabheader_t *header,
rdataset->slab.db = (dns_db_t *)qpdb;
rdataset->slab.node = (dns_dbnode_t *)node;
rdataset->slab.raw = dns_slabheader_raw(header);
rdataset->slab.raw = header->raw;
rdataset->slab.iter_pos = NULL;
rdataset->slab.iter_count = 0;
@ -1134,10 +1151,8 @@ setup_delegation(qpc_search_t *search, dns_dbnode_t **nodep,
}
static bool
check_stale_header(dns_slabheader_t *header, qpc_search_t *search,
dns_slabheader_t **header_prev) {
check_stale_header(dns_slabheader_t *header, qpc_search_t *search) {
if (ACTIVE(header, search->now)) {
*header_prev = header;
return false;
}
@ -1153,7 +1168,6 @@ check_stale_header(dns_slabheader_t *header, qpc_search_t *search,
if (!ZEROTTL(header) && KEEPSTALE(search->qpdb) && stale > search->now)
{
mark(header, DNS_SLABHEADERATTR_STALE);
*header_prev = header;
/*
* If DNS_DBFIND_STALESTART is set then it means we
* failed to resolve the name during recursion, in
@ -1188,7 +1202,6 @@ check_stale_header(dns_slabheader_t *header, qpc_search_t *search,
return (search->options & DNS_DBFIND_STALEOK) == 0;
}
*header_prev = header;
return true;
}
@ -1262,8 +1275,7 @@ both_headers(dns_slabheader_t *header, dns_rdatatype_t type,
static isc_result_t
check_zonecut(qpcnode_t *node, void *arg DNS__DB_FLARG) {
qpc_search_t *search = arg;
dns_slabheader_t *header = NULL;
dns_slabheader_t *header_prev = NULL, *header_next = NULL;
dns_slabtop_t *top = NULL;
dns_slabheader_t *found = NULL, *foundsig = NULL;
isc_result_t result;
isc_rwlock_t *nlock = NULL;
@ -1277,13 +1289,12 @@ check_zonecut(qpcnode_t *node, void *arg DNS__DB_FLARG) {
/*
* Look for a DNAME or RRSIG DNAME rdataset.
*/
for (header = node->data; header != NULL; header = header_next) {
header_next = header->next;
if (check_stale_header(header, search, &header_prev)) {
for (top = node->data; top != NULL; top = top->next) {
if (check_stale_header(top->header, search)) {
continue;
}
if (both_headers(header, dns_rdatatype_dname, &found,
if (both_headers(top->header, dns_rdatatype_dname, &found,
&foundsig))
{
break;
@ -1328,8 +1339,7 @@ find_deepest_zonecut(qpc_search_t *search, qpcnode_t *node,
qpdb = search->qpdb;
for (int i = dns_qpchain_length(&search->chain) - 1; i >= 0; i--) {
dns_slabheader_t *header = NULL;
dns_slabheader_t *header_prev = NULL, *header_next = NULL;
dns_slabtop_t *top = NULL;
dns_slabheader_t *found = NULL, *foundsig = NULL;
isc_rwlock_t *nlock = NULL;
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
@ -1342,14 +1352,12 @@ find_deepest_zonecut(qpc_search_t *search, qpcnode_t *node,
/*
* Look for NS and RRSIG NS rdatasets.
*/
for (header = node->data; header != NULL; header = header_next)
{
header_next = header->next;
if (check_stale_header(header, search, &header_prev)) {
for (top = node->data; top != NULL; top = top->next) {
if (check_stale_header(top->header, search)) {
continue;
}
if (both_headers(header, dns_rdatatype_ns, &found,
if (both_headers(top->header, dns_rdatatype_ns, &found,
&foundsig))
{
break;
@ -1407,8 +1415,7 @@ find_coveringnsec(qpc_search_t *search, const dns_name_t *name,
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
isc_rwlock_t *nlock = NULL;
dns_slabheader_t *found = NULL, *foundsig = NULL;
dns_slabheader_t *header = NULL;
dns_slabheader_t *header_next = NULL, *header_prev = NULL;
dns_slabtop_t *top = NULL;
/*
* Look for the node in the auxilary tree.
@ -1449,13 +1456,13 @@ find_coveringnsec(qpc_search_t *search, const dns_name_t *name,
nlock = &search->qpdb->buckets[node->locknum].lock;
NODE_RDLOCK(nlock, &nlocktype);
for (header = node->data; header != NULL; header = header_next) {
header_next = header->next;
if (check_stale_header(header, search, &header_prev)) {
for (top = node->data; top != NULL; top = top->next) {
if (check_stale_header(top->header, search)) {
continue;
}
if (both_headers(header, dns_rdatatype_nsec, &found, &foundsig))
if (both_headers(top->header, dns_rdatatype_nsec, &found,
&foundsig))
{
break;
}
@ -1527,8 +1534,7 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
isc_rwlock_t *nlock = NULL;
isc_rwlocktype_t tlocktype = isc_rwlocktype_none;
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
dns_slabheader_t *header = NULL;
dns_slabheader_t *header_prev = NULL, *header_next = NULL;
dns_slabtop_t *top = NULL;
dns_slabheader_t *found = NULL, *nsheader = NULL;
dns_slabheader_t *foundsig = NULL, *nssig = NULL, *cnamesig = NULL;
dns_slabheader_t *nsecheader = NULL, *nsecsig = NULL;
@ -1647,14 +1653,12 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
nsecsig = NULL;
cnamesig = NULL;
empty_node = true;
header_prev = NULL;
for (header = node->data; header != NULL; header = header_next) {
header_next = header->next;
if (check_stale_header(header, &search, &header_prev)) {
for (top = node->data; top != NULL; top = top->next) {
if (check_stale_header(top->header, &search)) {
continue;
}
if (!EXISTS(header) || ANCIENT(header)) {
if (!EXISTS(top->header) || ANCIENT(top->header)) {
continue;
}
@ -1664,18 +1668,18 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
*/
empty_node = false;
if (header->noqname != NULL &&
header->trust == dns_trust_secure)
if (top->header->noqname != NULL &&
top->header->trust == dns_trust_secure)
{
found_noqname = true;
}
if (!NEGATIVE(header)) {
if (!NEGATIVE(top->header)) {
all_negative = false;
}
bool match = false;
if (related_headers(header, typepair, sigpair, &found,
if (related_headers(top->header, typepair, sigpair, &found,
&foundsig, &match) &&
!MISSING_ANSWER(found, options))
{
@ -1694,7 +1698,7 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
continue;
}
if (NEGATIVE(header)) {
if (NEGATIVE(top->header)) {
/*
* FIXME: As of now, we are not interested in
* the negative headers. This could be
@ -1706,13 +1710,13 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
continue;
}
switch (header->typepair) {
switch (top->typepair) {
case dns_rdatatype_cname:
if (!cname_ok) {
break;
}
found = header;
found = top->header;
if (cnamesig != NULL) {
/* We already have CNAME signature */
foundsig = cnamesig;
@ -1727,28 +1731,28 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
break;
}
cnamesig = header;
cnamesig = top->header;
break;
case dns_rdatatype_ns:
/* Remember the NS rdataset */
nsheader = header;
nsheader = top->header;
break;
case DNS_SIGTYPEPAIR(dns_rdatatype_ns):
/* ...and its signature */
nssig = header;
nssig = top->header;
break;
case dns_rdatatype_nsec:
nsecheader = header;
nsecheader = top->header;
break;
case DNS_SIGTYPEPAIR(dns_rdatatype_nsec):
nsecsig = header;
nsecsig = top->header;
break;
default:
if (typepair == dns_typepair_any) {
/* QTYPE==ANY, so any anwers will do */
found = header;
found = top->header;
break;
}
}
@ -1909,19 +1913,17 @@ seek_ns_headers(qpc_search_t *search, qpcnode_t *node, dns_dbnode_t **nodep,
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
dns_name_t *foundname, dns_name_t *dcname,
isc_rwlocktype_t *tlocktype) {
dns_slabheader_t *header = NULL;
dns_slabheader_t *header_prev = NULL, *header_next = NULL;
dns_slabtop_t *top = NULL;
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
isc_rwlock_t *nlock = &search->qpdb->buckets[node->locknum].lock;
dns_slabheader_t *found = NULL, *foundsig = NULL;
NODE_RDLOCK(nlock, &nlocktype);
for (header = node->data; header != NULL; header = header_next) {
header_next = header->next;
bool ns = header->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) ||
header->typepair == DNS_SIGTYPEPAIR(dns_rdatatype_ns);
if (check_stale_header(header, search, &header_prev)) {
for (top = node->data; top != NULL; top = top->next) {
bool ns = top->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) ||
top->typepair == DNS_SIGTYPEPAIR(dns_rdatatype_ns);
if (check_stale_header(top->header, search)) {
if (ns) {
/*
* We found a cached NS, but was either
@ -1936,7 +1938,9 @@ seek_ns_headers(qpc_search_t *search, qpcnode_t *node, dns_dbnode_t **nodep,
continue;
}
if (both_headers(header, dns_rdatatype_ns, &found, &foundsig)) {
if (both_headers(top->header, dns_rdatatype_ns, &found,
&foundsig))
{
break;
}
}
@ -2060,8 +2064,7 @@ qpcache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
qpcache_t *qpdb = (qpcache_t *)db;
qpcnode_t *qpnode = (qpcnode_t *)node;
dns_slabheader_t *header = NULL;
dns_slabheader_t *header_prev = NULL, *header_next = NULL;
dns_slabtop_t *top = NULL;
dns_slabheader_t *found = NULL, *foundsig = NULL;
dns_typepair_t typepair, sigpair;
isc_result_t result = ISC_R_SUCCESS;
@ -2091,14 +2094,12 @@ qpcache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
sigpair = !dns_rdatatype_issig(type) ? DNS_SIGTYPEPAIR(type)
: dns_typepair_none;
for (header = qpnode->data; header != NULL; header = header_next) {
header_next = header->next;
if (check_stale_header(header, &search, &header_prev)) {
for (top = qpnode->data; top != NULL; top = top->next) {
if (check_stale_header(top->header, &search)) {
continue;
}
if (related_headers(header, typepair, sigpair, &found,
if (related_headers(top->header, typepair, sigpair, &found,
&foundsig, NULL))
{
break;
@ -2487,8 +2488,8 @@ overmaxtype(qpcache_t *qpdb, uint32_t ntypes) {
}
static bool
prio_header(dns_slabheader_t *header) {
return prio_type(header->typepair);
prio_header(dns_slabtop_t *top) {
return prio_type(top->typepair);
}
static void
@ -2538,13 +2539,12 @@ qpcnode_detachnode(dns_dbnode_t **nodep DNS__DB_FLARG) {
}
static isc_result_t
add(qpcache_t *qpdb, qpcnode_t *qpnode,
const dns_name_t *nodename ISC_ATTR_UNUSED, dns_slabheader_t *newheader,
add(qpcache_t *qpdb, qpcnode_t *qpnode, dns_slabheader_t *newheader,
unsigned int options, dns_rdataset_t *addedrdataset, isc_stdtime_t now,
isc_rwlocktype_t nlocktype, isc_rwlocktype_t tlocktype DNS__DB_FLARG) {
dns_slabheader_t *topheader = NULL, *topheader_prev = NULL;
dns_slabtop_t *top = NULL;
dns_slabtop_t *priotop = NULL, *expiretop = NULL;
dns_slabheader_t *header = NULL, *sigheader = NULL;
dns_slabheader_t *prioheader = NULL, *expireheader = NULL;
dns_trust_t trust;
uint32_t ntypes = 0;
dns_rdatatype_t rdtype = DNS_TYPEPAIR_TYPE(newheader->typepair);
@ -2586,11 +2586,10 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode,
* only rdataset that can be found at this
* node is the negative cache entry.
*/
for (topheader = qpnode->data;
topheader != NULL;
topheader = topheader->next)
for (top = qpnode->data; top != NULL;
top = top->next)
{
mark_ancient(topheader);
mark_ancient(top->header);
}
goto find_header;
}
@ -2598,11 +2597,9 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode,
* Otherwise look for any RRSIGs of the given
* type so they can be marked ancient later.
*/
for (topheader = qpnode->data; topheader != NULL;
topheader = topheader->next)
{
if (topheader->typepair == sigpair) {
sigheader = topheader;
for (top = qpnode->data; top != NULL; top = top->next) {
if (top->typepair == sigpair) {
sigheader = top->header;
break;
}
}
@ -2611,14 +2608,12 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode,
* We're adding something that isn't a
* negative cache entry.
*/
for (topheader = qpnode->data; topheader != NULL;
topheader = topheader->next)
{
for (top = qpnode->data; top != NULL; top = top->next) {
/*
* Look for any existing negative cache
* entries.
*/
if (!NEGATIVE(topheader)) {
if (!NEGATIVE(top->header)) {
continue;
}
@ -2626,7 +2621,7 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode,
* If we find a cached NXDOMAIN, don't
* cache anything else.
*/
if (topheader->typepair == dns_typepair_any) {
if (top->typepair == dns_typepair_any) {
break;
}
@ -2635,28 +2630,27 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode,
* for which we have a cached NODATA record.
*/
if (newheader->typepair == sigpair &&
DNS_TYPEPAIR_TYPE(topheader->typepair) ==
covers)
DNS_TYPEPAIR_TYPE(top->typepair) == covers)
{
break;
}
}
if (topheader != NULL && EXISTS(topheader) &&
ACTIVE(topheader, now))
if (top != NULL && EXISTS(top->header) &&
ACTIVE(top->header, now))
{
/*
* Found one.
*/
if (trust < topheader->trust) {
if (trust < top->header->trust) {
/*
* The NXDOMAIN/NODATA(QTYPE=ANY)
* is more trusted.
*/
if (addedrdataset != NULL) {
bindrdataset(
qpdb, qpnode, topheader,
now, nlocktype,
tlocktype,
qpdb, qpnode,
top->header, now,
nlocktype, tlocktype,
addedrdataset
DNS__DB_FLARG_PASS);
}
@ -2666,36 +2660,33 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode,
* The new rdataset is better. Expire the
* ncache entry.
*/
mark_ancient(topheader);
topheader = NULL;
mark_ancient(top->header);
top = NULL;
goto find_header;
}
}
}
for (topheader = qpnode->data; topheader != NULL;
topheader = topheader->next)
{
if (ACTIVE(topheader, now)) {
for (top = qpnode->data; top != NULL; top = top->next) {
if (ACTIVE(top->header, now)) {
++ntypes;
expireheader = topheader;
expiretop = top;
}
if (prio_header(topheader)) {
prioheader = topheader;
if (prio_header(top)) {
priotop = top;
}
if (topheader->typepair == newheader->typepair) {
if (top->typepair == newheader->typepair) {
break;
}
topheader_prev = topheader;
}
find_header:
/*
* If header isn't NULL, we've found the right type.
* If top isn't NULL, we've found the right type.
*/
header = topheader;
if (header != NULL) {
if (top != NULL) {
header = top->header;
/*
* Deleting an already non-existent rdataset has no effect.
*/
@ -2730,12 +2721,12 @@ find_header:
* normally further down.
*/
if (ACTIVE(header, now) &&
header->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) &&
top->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) &&
EXISTS(header) && EXISTS(newheader) &&
header->trust >= newheader->trust &&
dns_rdataslab_equalx(header, newheader,
qpdb->common.rdclass,
DNS_TYPEPAIR_TYPE(header->typepair)))
DNS_TYPEPAIR_TYPE(top->typepair)))
{
/*
* Honour the new ttl if it is less than the
@ -2773,7 +2764,7 @@ find_header:
* ensures the delegations that are withdrawn are honoured.
*/
if (ACTIVE(header, now) &&
header->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) &&
top->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) &&
EXISTS(header) && EXISTS(newheader) &&
header->trust <= newheader->trust)
{
@ -2783,10 +2774,10 @@ find_header:
}
if (ACTIVE(header, now) &&
(options & DNS_DBADD_PREFETCH) == 0 &&
(header->typepair == DNS_TYPEPAIR(dns_rdatatype_a) ||
header->typepair == DNS_TYPEPAIR(dns_rdatatype_aaaa) ||
header->typepair == DNS_TYPEPAIR(dns_rdatatype_ds) ||
header->typepair == DNS_SIGTYPEPAIR(dns_rdatatype_ds)) &&
(top->typepair == DNS_TYPEPAIR(dns_rdatatype_a) ||
top->typepair == DNS_TYPEPAIR(dns_rdatatype_aaaa) ||
top->typepair == DNS_TYPEPAIR(dns_rdatatype_ds) ||
top->typepair == DNS_SIGTYPEPAIR(dns_rdatatype_ds)) &&
EXISTS(header) && EXISTS(newheader) &&
header->trust >= newheader->trust &&
dns_rdataslab_equal(header, newheader))
@ -2821,17 +2812,16 @@ find_header:
return DNS_R_UNCHANGED;
}
top->header = newheader;
newheader->top = top;
newheader->down = header;
ISC_SIEVE_UNLINK(qpdb->buckets[qpnode->locknum].sieve, top,
link);
qpcache_miss(qpdb, newheader, &nlocktype,
&tlocktype DNS__DB_FLARG_PASS);
if (topheader_prev != NULL) {
topheader_prev->next = newheader;
} else {
qpnode->data = newheader;
}
newheader->next = topheader->next;
newheader->down = topheader;
topheader->next = newheader;
mark_ancient(header);
if (sigheader != NULL) {
mark_ancient(sigheader);
@ -2846,36 +2836,42 @@ find_header:
/* No rdatasets of the given type exist at the node. */
INSIST(newheader->down == NULL);
dns_slabtop_t *newtop = dns_slabtop_new(
((dns_db_t *)qpdb)->mctx, newheader->typepair);
newtop->header = newheader;
newheader->top = newtop;
qpcache_miss(qpdb, newheader, &nlocktype,
&tlocktype DNS__DB_FLARG_PASS);
if (prio_header(newheader)) {
if (prio_header(newtop)) {
/* This is a priority type, prepend it */
newheader->next = qpnode->data;
qpnode->data = newheader;
} else if (prioheader != NULL) {
newtop->next = qpnode->data;
qpnode->data = newtop;
} else if (priotop != NULL) {
/* Append after the priority headers */
newheader->next = prioheader->next;
prioheader->next = newheader;
newtop->next = priotop->next;
priotop->next = newtop;
} else {
/* There were no priority headers */
newheader->next = qpnode->data;
qpnode->data = newheader;
newtop->next = qpnode->data;
qpnode->data = newtop;
}
if (overmaxtype(qpdb, ntypes)) {
if (expireheader == NULL) {
expireheader = newheader;
if (expiretop == NULL) {
expiretop = newtop;
}
if (NEGATIVE(newheader) && !prio_header(newheader)) {
if (NEGATIVE(newheader) && !prio_header(newtop)) {
/*
* Add the new non-priority negative
* header to the database only
* temporarily.
*/
expireheader = newheader;
expiretop = newtop;
}
mark_ancient(expireheader);
mark_ancient(expiretop->header);
/*
* FIXME: In theory, we should mark the RRSIG
* and the header at the same time, but there is
@ -2917,8 +2913,8 @@ addnoqname(isc_mem_t *mctx, dns_slabheader_t *newheader, uint32_t maxrrperset,
noqname = isc_mem_get(mctx, sizeof(*noqname));
*noqname = (dns_slabheader_proof_t){
.neg = dns_slabheader_raw((dns_slabheader_t *)r1.base),
.negsig = dns_slabheader_raw((dns_slabheader_t *)r2.base),
.neg = ((dns_slabheader_t *)r1.base)->raw,
.negsig = ((dns_slabheader_t *)r2.base)->raw,
.type = neg.type,
.name = DNS_NAME_INITEMPTY,
};
@ -2956,8 +2952,8 @@ addclosest(isc_mem_t *mctx, dns_slabheader_t *newheader, uint32_t maxrrperset,
closest = isc_mem_get(mctx, sizeof(*closest));
*closest = (dns_slabheader_proof_t){
.neg = dns_slabheader_raw((dns_slabheader_t *)r1.base),
.negsig = dns_slabheader_raw((dns_slabheader_t *)r2.base),
.neg = ((dns_slabheader_t *)r1.base)->raw,
.negsig = ((dns_slabheader_t *)r2.base)->raw,
.name = DNS_NAME_INITEMPTY,
.type = neg.type,
};
@ -3105,7 +3101,7 @@ qpcache_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
qpnode->havensec = true;
}
result = add(qpdb, qpnode, name, newheader, options, addedrdataset, now,
result = add(qpdb, qpnode, newheader, options, addedrdataset, now,
nlocktype, tlocktype DNS__DB_FLARG_PASS);
if (result == ISC_R_SUCCESS) {
@ -3163,14 +3159,14 @@ qpcache_deleterdataset(dns_db_t *db, dns_dbnode_t *node,
return ISC_R_NOTIMPLEMENTED;
}
newheader = dns_slabheader_new(db, node);
newheader = dns_slabheader_new(db->mctx, node);
newheader->typepair = DNS_TYPEPAIR_VALUE(type, covers);
setttl(newheader, 0);
atomic_init(&newheader->attributes, attributes);
nlock = &qpdb->buckets[qpnode->locknum].lock;
NODE_WRLOCK(nlock, &nlocktype);
result = add(qpdb, qpnode, NULL, newheader, DNS_DBADD_FORCE, NULL, 0,
result = add(qpdb, qpnode, newheader, DNS_DBADD_FORCE, NULL, 0,
nlocktype, isc_rwlocktype_none DNS__DB_FLARG_PASS);
if (result != ISC_R_SUCCESS) {
dns_slabheader_destroy(&newheader);
@ -3320,13 +3316,6 @@ iterator_active(qpcache_t *qpdb, qpc_rditer_t *iterator,
dns_slabheader_t *header) {
dns_ttl_t stale_ttl = header->expire + STALE_TTL(header, qpdb);
/*
* Is this a "this rdataset doesn't exist" record?
*/
if (!EXISTS(header)) {
return false;
}
/*
* If this header is still active then return it.
*/
@ -3349,15 +3338,16 @@ rdatasetiter_first(dns_rdatasetiter_t *it DNS__DB_FLARG) {
qpc_rditer_t *iterator = (qpc_rditer_t *)it;
qpcache_t *qpdb = (qpcache_t *)(iterator->common.db);
qpcnode_t *qpnode = (qpcnode_t *)iterator->common.node;
dns_slabheader_t *header = NULL;
dns_slabtop_t *top = NULL;
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
isc_rwlock_t *nlock = &qpdb->buckets[qpnode->locknum].lock;
NODE_RDLOCK(nlock, &nlocktype);
for (header = qpnode->data; header != NULL; header = header->next) {
if ((EXPIREDOK(iterator) && EXISTS(header)) ||
iterator_active(qpdb, iterator, header))
for (top = qpnode->data; top != NULL; top = top->next) {
if (EXISTS(top->header) &&
(EXPIREDOK(iterator) ||
iterator_active(qpdb, iterator, top->header)))
{
break;
}
@ -3365,9 +3355,9 @@ rdatasetiter_first(dns_rdatasetiter_t *it DNS__DB_FLARG) {
NODE_UNLOCK(nlock, &nlocktype);
iterator->current = header;
iterator->current = top;
if (header == NULL) {
if (top == NULL) {
return ISC_R_NOMORE;
}
@ -3379,20 +3369,21 @@ rdatasetiter_next(dns_rdatasetiter_t *it DNS__DB_FLARG) {
qpc_rditer_t *iterator = (qpc_rditer_t *)it;
qpcache_t *qpdb = (qpcache_t *)(iterator->common.db);
qpcnode_t *qpnode = (qpcnode_t *)iterator->common.node;
dns_slabheader_t *header = NULL;
dns_slabtop_t *top = NULL;
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
isc_rwlock_t *nlock = &qpdb->buckets[qpnode->locknum].lock;
header = iterator->current;
if (header == NULL) {
top = iterator->current;
if (top == NULL) {
return ISC_R_NOMORE;
}
NODE_RDLOCK(nlock, &nlocktype);
for (header = header->next; header != NULL; header = header->next) {
if ((EXPIREDOK(iterator) && EXISTS(header)) ||
iterator_active(qpdb, iterator, header))
for (top = top->next; top != NULL; top = top->next) {
if (EXISTS(top->header) &&
(EXPIREDOK(iterator) ||
iterator_active(qpdb, iterator, top->header)))
{
break;
}
@ -3400,9 +3391,9 @@ rdatasetiter_next(dns_rdatasetiter_t *it DNS__DB_FLARG) {
NODE_UNLOCK(nlock, &nlocktype);
iterator->current = header;
iterator->current = top;
if (header == NULL) {
if (top == NULL) {
return ISC_R_NOMORE;
}
@ -3415,16 +3406,16 @@ rdatasetiter_current(dns_rdatasetiter_t *it,
qpc_rditer_t *iterator = (qpc_rditer_t *)it;
qpcache_t *qpdb = (qpcache_t *)(iterator->common.db);
qpcnode_t *qpnode = (qpcnode_t *)iterator->common.node;
dns_slabheader_t *header = NULL;
dns_slabtop_t *top = NULL;
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
isc_rwlock_t *nlock = &qpdb->buckets[qpnode->locknum].lock;
header = iterator->current;
REQUIRE(header != NULL);
top = iterator->current;
REQUIRE(top != NULL);
NODE_RDLOCK(nlock, &nlocktype);
bindrdataset(qpdb, qpnode, header, iterator->common.now, nlocktype,
bindrdataset(qpdb, qpnode, top->header, iterator->common.now, nlocktype,
isc_rwlocktype_none, rdataset DNS__DB_FLARG_PASS);
NODE_UNLOCK(nlock, &nlocktype);
@ -3771,19 +3762,16 @@ qpcnode_deletedata(dns_dbnode_t *node ISC_ATTR_UNUSED, void *data) {
dns_slabheader_t *header = data;
qpcache_t *qpdb = HEADERNODE(header)->qpdb;
int idx = HEADERNODE(header)->locknum;
if (header->heap != NULL && header->heap_index != 0) {
isc_heap_delete(header->heap, header->heap_index);
}
/*
* This place is the only place where we actually need header->typepair.
*/
update_rrsetstats(qpdb->rrsetstats, header->typepair,
atomic_load_acquire(&header->attributes), false);
if (ISC_LINK_LINKED(header, link)) {
ISC_SIEVE_UNLINK(qpdb->buckets[idx].sieve, header, link);
}
if (header->noqname != NULL) {
dns_slabheader_freeproof(qpdb->common.mctx, &header->noqname);
}
@ -3866,24 +3854,29 @@ static dns_dbmethods_t qpdb_cachemethods = {
};
static void
qpcnode_destroy(qpcnode_t *data) {
dns_slabheader_t *current = NULL, *next = NULL;
qpcnode_destroy(qpcnode_t *qpnode) {
dns_slabtop_t *top = NULL, *top_next = NULL;
qpcache_t *qpdb = qpnode->qpdb;
for (current = data->data; current != NULL; current = next) {
dns_slabheader_t *down = current->down, *down_next = NULL;
for (top = qpnode->data; top != NULL; top = top_next) {
top_next = top->next;
next = current->next;
for (down = current->down; down != NULL; down = down_next) {
dns_slabheader_t *down = NULL, *down_next = NULL;
for (down = top->header; down != NULL; down = down_next) {
down_next = down->down;
dns_slabheader_destroy(&down);
}
top->header = NULL;
dns_slabheader_destroy(&current);
if (ISC_LINK_LINKED(top, link)) {
ISC_SIEVE_UNLINK(qpdb->buckets[qpnode->locknum].sieve,
top, link);
}
dns_slabtop_destroy(((dns_db_t *)qpdb)->mctx, &top);
}
dns_name_free(&data->name, data->mctx);
isc_mem_putanddetach(&data->mctx, data, sizeof(qpcnode_t));
dns_name_free(&qpnode->name, qpnode->mctx);
isc_mem_putanddetach(&qpnode->mctx, qpnode, sizeof(qpcnode_t));
}
#ifdef DNS_DB_NODETRACE

File diff suppressed because it is too large Load Diff

View File

@ -34,47 +34,21 @@
#include "rdataslab_p.h"
/*
* The rdataslab structure allows iteration to occur in both load order
* and DNSSEC order. The structure is as follows:
* The memory structure of an rdataslab is as follows:
*
* header (dns_slabheader_t)
* record count (2 bytes)
* offset table (4 x record count bytes in load order)
* data records
* data length (2 bytes)
* order (2 bytes)
* meta data (1 byte for RRSIG's)
* meta data (1 byte for RRSIG, 0 for all other types)
* data (data length bytes)
*
* A "raw" rdataslab is the same but without the header.
* A "bare" rdataslab is everything after "header".
*
* DNSSEC order traversal is performed by walking the data records.
*
* The order is stored with record to allow for efficient reconstruction
* of the offset table following a merge or subtraction.
*
* The iterator methods in rbtdb support both load order and DNSSEC order
* iteration.
*
* WARNING:
* rbtdb.c directly interacts with the slab's raw structures. If the
* structure changes then rbtdb.c also needs to be updated to reflect
* the changes. See the areas tagged with "RDATASLAB".
* When a slab is created, data records are sorted into DNSSEC order.
*/
#define peek_uint16(buffer) ({ ((uint16_t)*(buffer) << 8) | *((buffer) + 1); })
#define get_uint16(buffer) \
({ \
uint16_t __ret = peek_uint16(buffer); \
buffer += sizeof(uint16_t); \
__ret; \
})
#define put_uint16(buffer, val) \
({ \
*buffer++ = (val & 0xff00) >> 8; \
*buffer++ = (val & 0x00ff); \
})
static void
rdataset_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG);
static isc_result_t
@ -240,8 +214,8 @@ makeslab(dns_rdataset_t *rdataset, isc_mem_t *mctx, isc_region_t *region,
* 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 8 for each rdata, (length(2), offset(4) and order(2))
* and then the rdata itself.
* 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) {
@ -359,7 +333,6 @@ dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
.typepair = typepair,
.trust = rdataset->trust,
.ttl = rdataset->ttl,
.link = ISC_LINK_INITIALIZER,
};
}
@ -397,8 +370,8 @@ dns_rdataslab_count(dns_slabheader_t *header) {
/*
* Make the dns_rdata_t 'rdata' refer to the slab item
* beginning at '*current', which is part of a slab of type
* 'type' and class 'rdclass', and advance '*current' to
* beginning at '*current' (which is part of a slab of type
* 'type' and class 'rdclass') and advance '*current' to
* point to the next item in the slab.
*/
static void
@ -827,11 +800,6 @@ dns_rdataslab_equalx(dns_slabheader_t *slab1, dns_slabheader_t *slab2,
return true;
}
void *
dns_slabheader_raw(dns_slabheader_t *header) {
return header + 1;
}
void
dns_slabheader_setownercase(dns_slabheader_t *header, const dns_name_t *name) {
REQUIRE(!CASESET(header));
@ -871,11 +839,9 @@ dns_slabheader_copycase(dns_slabheader_t *dest, dns_slabheader_t *src) {
void
dns_slabheader_reset(dns_slabheader_t *h, dns_dbnode_t *node) {
ISC_LINK_INIT(h, link);
h->heap_index = 0;
h->heap = NULL;
h->node = node;
h->visited = false;
atomic_init(&h->attributes, 0);
atomic_init(&h->last_refresh_fail_ts, 0);
@ -886,14 +852,13 @@ dns_slabheader_reset(dns_slabheader_t *h, dns_dbnode_t *node) {
}
dns_slabheader_t *
dns_slabheader_new(dns_db_t *db, dns_dbnode_t *node) {
dns_slabheader_new(isc_mem_t *mctx, dns_dbnode_t *node) {
dns_slabheader_t *h = NULL;
h = isc_mem_get(db->mctx, sizeof(*h));
h = isc_mem_get(mctx, sizeof(*h));
*h = (dns_slabheader_t){
.link = ISC_LINK_INITIALIZER,
.node = node,
};
dns_slabheader_reset(h, node);
return h;
}
@ -943,23 +908,8 @@ dns_slabheader_freeproof(isc_mem_t *mctx, dns_slabheader_proof_t **proofp) {
isc_mem_put(mctx, proof, sizeof(*proof));
}
dns_slabheader_t *
dns_slabheader_top(dns_slabheader_t *header) {
/*
* Find the start of the header chain for the next type
* by walking back up the list.
*/
while (header->up != NULL && header->up->typepair == header->typepair) {
header = header->up;
}
return header;
}
/* Fixed RRSet helper macros */
#define DNS_RDATASET_LENGTH 2;
static void
rdataset_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG) {
dns_dbnode_t *node = rdataset->slab.node;
@ -984,7 +934,7 @@ rdataset_first(dns_rdataset_t *rdataset) {
*
* 'raw' points to the first record.
*/
rdataset->slab.iter_pos = raw + DNS_RDATASET_LENGTH;
rdataset->slab.iter_pos = raw + sizeof(uint16_t);
rdataset->slab.iter_count = count - 1;
return ISC_R_SUCCESS;
@ -1005,7 +955,7 @@ rdataset_next(dns_rdataset_t *rdataset) {
unsigned char *raw = rdataset->slab.iter_pos;
uint16_t length = peek_uint16(raw);
raw += length;
rdataset->slab.iter_pos = raw + DNS_RDATASET_LENGTH;
rdataset->slab.iter_pos = raw + sizeof(uint16_t);
return ISC_R_SUCCESS;
}
@ -1024,9 +974,7 @@ rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
* Find the start of the record if not already in iter_pos
* then skip the length and order fields.
*/
length = peek_uint16(raw);
raw += DNS_RDATASET_LENGTH;
length = get_uint16(raw);
if (rdataset->type == dns_rdatatype_rrsig) {
if (*raw & DNS_RDATASLAB_OFFLINE) {
@ -1075,7 +1023,12 @@ rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
const dns_slabheader_proof_t *noqname = rdataset->slab.noqname;
/*
* The _KEEPCASE attribute is set to prevent setownercase and
* Normally, rdataset->slab.raw points to the data immediately
* following a dns_slabheader in memory. Here, though, it will
* point to a bare rdataslab, a pointer to which is stored in
* the dns_slabheader's `noqname` field.
*
* The 'keepcase' attribute is set to prevent setownercase and
* getownercase methods from affecting the case of NSEC/NSEC3
* owner names.
*/
@ -1128,9 +1081,14 @@ rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name,
const dns_slabheader_proof_t *closest = rdataset->slab.closest;
/*
* As mentioned above, rdataset->slab.raw usually refers the data
* following an dns_slabheader, but in this case it points to a bare
* rdataslab belonging to the dns_slabheader's `closest` field.
* Normally, rdataset->slab.raw points to the data immediately
* following a dns_slabheader in memory. Here, though, it will
* point to a bare rdataslab, a pointer to which is stored in
* the dns_slabheader's `closest` field.
*
* The 'keepcase' attribute is set to prevent setownercase and
* getownercase methods from affecting the case of NSEC/NSEC3
* owner names.
*/
dns__db_attachnode(node, &(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS);
*nsec = (dns_rdataset_t){
@ -1260,3 +1218,22 @@ rdataset_equals(const dns_rdataset_t *rdataset1,
return dns_rdataslab_equalx(header1, header2, rdataset1->rdclass,
rdataset2->type);
}
dns_slabtop_t *
dns_slabtop_new(isc_mem_t *mctx, dns_typepair_t typepair) {
dns_slabtop_t *top = isc_mem_get(mctx, sizeof(*top));
*top = (dns_slabtop_t){
.typepair = typepair,
.link = ISC_LINK_INITIALIZER,
};
return top;
}
void
dns_slabtop_destroy(isc_mem_t *mctx, dns_slabtop_t **topp) {
REQUIRE(topp != NULL && *topp != NULL);
dns_slabtop_t *top = *topp;
*topp = NULL;
isc_mem_put(mctx, top, sizeof(*top));
}

View File

@ -13,6 +13,8 @@
#pragma once
#include <isc/endian.h>
#include <dns/rdataslab.h>
#define ANCIENT(header) \
@ -57,3 +59,16 @@
#define ZEROTTL(header) \
((atomic_load_acquire(&(header)->attributes) & \
DNS_SLABHEADERATTR_ZEROTTL) != 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); \
}