return (ISC_R_SUCCESS);
}
+static bool
+overmaxtype(qpcache_t *qpdb, uint32_t ntypes) {
+ if (qpdb->maxtypepername == 0) {
+ return (false);
+ }
+
+ return (ntypes >= qpdb->maxtypepername);
+}
+
+static bool
+prio_header(dns_slabheader_t *header) {
+ if (NEGATIVE(header) && prio_type(DNS_TYPEPAIR_COVERS(header->type))) {
+ return (true);
+ }
+
+ return (prio_type(header->type));
+}
+
static isc_result_t
add(qpcache_t *qpdb, qpcnode_t *qpnode,
const dns_name_t *nodename ISC_ATTR_UNUSED, dns_slabheader_t *newheader,
isc_rwlocktype_t tlocktype DNS__DB_FLARG) {
dns_slabheader_t *topheader = NULL, *topheader_prev = NULL;
dns_slabheader_t *header = NULL, *sigheader = NULL;
- dns_slabheader_t *prioheader = NULL;
+ dns_slabheader_t *prioheader = NULL, *expireheader = NULL;
bool header_nx;
bool newheader_nx;
- dns_rdatatype_t rdtype, covers;
- dns_typepair_t negtype = 0, sigtype;
+ dns_typepair_t negtype = 0;
dns_trust_t trust;
int idx;
- uint32_t ntypes;
+ uint32_t ntypes = 0;
if ((options & DNS_DBADD_FORCE) != 0) {
trust = dns_trust_ultimate;
}
newheader_nx = NONEXISTENT(newheader) ? true : false;
+
if (!newheader_nx) {
- rdtype = DNS_TYPEPAIR_TYPE(newheader->type);
- covers = DNS_TYPEPAIR_COVERS(newheader->type);
- sigtype = DNS_SIGTYPE(covers);
+ dns_rdatatype_t rdtype = DNS_TYPEPAIR_TYPE(newheader->type);
+ dns_rdatatype_t covers = DNS_TYPEPAIR_COVERS(newheader->type);
+ dns_typepair_t sigtype = DNS_SIGTYPE(covers);
if (NEGATIVE(newheader)) {
/*
* We're adding a negative cache entry.
{
mark_ancient(topheader);
}
- ntypes = 0; /* Always add the negative entry */
goto find_header;
}
/*
{
if (topheader->type == sigtype) {
sigheader = topheader;
+ break;
}
}
negtype = DNS_TYPEPAIR_VALUE(covers, 0);
* check for an extant non-ancient NODATA ncache
* entry which covers the same type as the RRSIG.
*/
- ntypes = 0;
for (topheader = qpnode->data; topheader != NULL;
topheader = topheader->next)
{
- ++ntypes;
if ((topheader->type == RDATATYPE_NCACHEANY) ||
(newheader->type == sigtype &&
topheader->type ==
}
}
- ntypes = 0;
for (topheader = qpnode->data; topheader != NULL;
topheader = topheader->next)
{
- ++ntypes;
-
- if (prio_type(topheader->type)) {
+ if (ACTIVE(topheader, now)) {
+ ++ntypes;
+ expireheader = topheader;
+ }
+ if (prio_header(topheader)) {
prioheader = topheader;
}
+
if (topheader->type == newheader->type ||
topheader->type == negtype)
{
/*
* No rdatasets of the given type exist at the node.
*/
- if (trust != dns_trust_ultimate &&
- qpdb->maxtypepername > 0 &&
- ntypes >= qpdb->maxtypepername)
- {
- dns_slabheader_destroy(&newheader);
- return (DNS_R_TOOMANYRECORDS);
- }
-
INSIST(newheader->down == NULL);
- if (prio_type(newheader->type)) {
+ if (prio_header(newheader)) {
/* This is a priority type, prepend it */
newheader->next = qpnode->data;
qpnode->data = newheader;
newheader->next = qpnode->data;
qpnode->data = newheader;
}
+
+ if (overmaxtype(qpdb, ntypes)) {
+ if (expireheader == NULL) {
+ expireheader = newheader;
+ }
+ if (NEGATIVE(newheader) &&
+ !prio_header(newheader))
+ {
+ /*
+ * Add the new non-priority negative
+ * header to the database only
+ * temporarily.
+ */
+ expireheader = newheader;
+ }
+
+ mark_ancient(expireheader);
+ /*
+ * FIXME: In theory, we should mark the RRSIG
+ * and the header at the same time, but there is
+ * no direct link between those two header, so
+ * we would have to check the whole list again.
+ */
+ }
}
}
RWUNLOCK(&rbtversion->rwlock, isc_rwlocktype_write);
}
+static bool
+overmaxtype(dns_rbtdb_t *rbtdb, uint32_t ntypes) {
+ if (rbtdb->maxtypepername == 0) {
+ return (false);
+ }
+
+ return (ntypes >= rbtdb->maxtypepername);
+}
+
+static bool
+prio_header(dns_slabheader_t *header) {
+ if (NEGATIVE(header) && prio_type(DNS_TYPEPAIR_COVERS(header->type))) {
+ return (true);
+ }
+
+ return (prio_type(header->type));
+}
+
isc_result_t
dns__rbtdb_add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode,
const dns_name_t *nodename, dns_rbtdb_version_t *rbtversion,
rbtdb_changed_t *changed = NULL;
dns_slabheader_t *topheader = NULL, *topheader_prev = NULL;
dns_slabheader_t *header = NULL, *sigheader = NULL;
- dns_slabheader_t *prioheader = NULL;
+ dns_slabheader_t *prioheader = NULL, *expireheader = NULL;
unsigned char *merged = NULL;
isc_result_t result;
bool header_nx;
{
mark_ancient(topheader);
}
- ntypes = 0; /* Always add the negative entry */
goto find_header;
}
/*
{
if (topheader->type == sigtype) {
sigheader = topheader;
+ break;
}
}
negtype = DNS_TYPEPAIR_VALUE(covers, 0);
* check for an extant non-ancient NODATA ncache
* entry which covers the same type as the RRSIG.
*/
- ntypes = 0;
for (topheader = rbtnode->data; topheader != NULL;
topheader = topheader->next)
{
- ++ntypes;
if ((topheader->type == RDATATYPE_NCACHEANY) ||
(newheader->type == sigtype &&
topheader->type ==
}
}
- ntypes = 0;
for (topheader = rbtnode->data; topheader != NULL;
topheader = topheader->next)
{
- ++ntypes;
- if (prio_type(topheader->type)) {
+ if (IS_CACHE(rbtdb) && ACTIVE(topheader, now)) {
+ ++ntypes;
+ expireheader = topheader;
+ } else if (!IS_CACHE(rbtdb)) {
+ ++ntypes;
+ }
+ if (prio_header(topheader)) {
prioheader = topheader;
}
if (topheader->type == newheader->type ||
/*
* No rdatasets of the given type exist at the node.
*/
+ INSIST(newheader->down == NULL);
- if (rbtdb->maxtypepername > 0 &&
- ntypes >= rbtdb->maxtypepername)
- {
+ if (!IS_CACHE(rbtdb) && overmaxtype(rbtdb, ntypes)) {
dns_slabheader_destroy(&newheader);
return (DNS_R_TOOMANYRECORDS);
}
- INSIST(newheader->down == NULL);
-
- if (prio_type(newheader->type)) {
+ if (prio_header(newheader)) {
/* This is a priority type, prepend it */
newheader->next = rbtnode->data;
rbtnode->data = newheader;
newheader->next = rbtnode->data;
rbtnode->data = newheader;
}
+
+ if (IS_CACHE(rbtdb) && overmaxtype(rbtdb, ntypes)) {
+ if (expireheader == NULL) {
+ expireheader = newheader;
+ }
+ if (NEGATIVE(newheader) &&
+ !prio_header(newheader))
+ {
+ /*
+ * Add the new non-priority negative
+ * header to the database only
+ * temporarily.
+ */
+ expireheader = newheader;
+ }
+
+ mark_ancient(expireheader);
+ /*
+ * FIXME: In theory, we should mark the RRSIG
+ * and the header at the same time, but there is
+ * no direct link between those two header, so
+ * we would have to check the whole list again.
+ */
+ }
}
}