#$DIG -p ${PORT} @10.53.0.2 nodata.example TXT
#$DIG -p ${PORT} @10.53.0.2 nxdomain.example TXT
+#
+# First test server with serve-stale options set.
+#
+echo_i "test server with serve-stale options set"
+
n=`expr $n + 1`
echo_i "prime cache longttl.example ($n)"
ret=0
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
+n=`expr $n + 1`
+echo_i "verify prime cache statistics ($n)"
+ret=0
+rm -f ns1/named.stats
+$RNDCCMD 10.53.0.1 stats > /dev/null 2>&1
+[ -f ns1/named.stats ] || ret=1
+cp ns1/named.stats ns1/named.stats.$n
+# Check first 10 lines of Cache DB statistics. After prime queries, we expect
+# two active TXT one nxrrset TXT, and one NXDOMAIN.
+grep -A 10 "++ Cache DB RRsets ++" ns1/named.stats.$n > ns1/named.stats.$n.cachedb || ret=1
+grep "2 TXT" ns1/named.stats.$n.cachedb > /dev/null || ret=1
+grep "1 !TXT" ns1/named.stats.$n.cachedb > /dev/null || ret=1
+grep "1 NXDOMAIN" ns1/named.stats.$n.cachedb > /dev/null || ret=1
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=`expr $status + $ret`
+
n=`expr $n + 1`
echo_i "disable responses from authoritative server ($n)"
ret=0
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
+n=`expr $n + 1`
+echo_i "verify stale cache statistics ($n)"
+ret=0
+rm -f ns1/named.stats
+$RNDCCMD 10.53.0.1 stats > /dev/null 2>&1
+[ -f ns1/named.stats ] || ret=1
+cp ns1/named.stats ns1/named.stats.$n
+# Check first 10 lines of Cache DB statistics. After serve-stale queries, we
+# expect one active TXT RRset, one stale TXT, one stale nxrrset TXT, and one
+# stale NXDOMAIN.
+grep -A 10 "++ Cache DB RRsets ++" ns1/named.stats.$n > ns1/named.stats.$n.cachedb || ret=1
+grep "1 TXT" ns1/named.stats.$n.cachedb > /dev/null || ret=1
+grep "1 #TXT" ns1/named.stats.$n.cachedb > /dev/null || ret=1
+grep "1 #!TXT" ns1/named.stats.$n.cachedb > /dev/null || ret=1
+grep "1 #NXDOMAIN" ns1/named.stats.$n.cachedb > /dev/null || ret=1
+status=`expr $status + $ret`
+if [ $ret != 0 ]; then echo_i "failed"; fi
+
n=`expr $n + 1`
echo_i "running 'rndc serve-stale off' ($n)"
ret=0
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
+#
+# Update named.conf.
+# Test server with low max-stale-ttl.
+#
+echo_i "test server with serve-stale options set, low max-stale-ttl"
+
n=`expr $n + 1`
echo_i "updating ns1/named.conf ($n)"
ret=0
echo_i "check 'rndc serve-stale status' ($n)"
ret=0
$RNDCCMD 10.53.0.1 serve-stale status > rndc.out.test$n 2>&1 || ret=1
-grep '_default: off (rndc) (stale-answer-ttl=3 max-stale-ttl=7200)' rndc.out.test$n > /dev/null || ret=1
+grep '_default: off (rndc) (stale-answer-ttl=3 max-stale-ttl=35)' rndc.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
-echo_i "check 'rndc serve-stale' ($n)"
+echo_i "flush cache, re-enable serve-stale and query again ($n)"
ret=0
-$RNDCCMD 10.53.0.1 serve-stale > rndc.out.test$n 2>&1 && ret=1
-grep "unexpected end of input" rndc.out.test$n > /dev/null || ret=1
+$RNDCCMD 10.53.0.1 flushtree example > rndc.out.test$n.1 2>&1 || ret=1
+$RNDCCMD 10.53.0.1 serve-stale on > rndc.out.test$n.2 2>&1 || ret=1
+$DIG -p ${PORT} @10.53.0.1 data.example TXT > dig.out.test$n
+grep "status: SERVFAIL" dig.out.test$n > /dev/null || ret=1
+grep "ANSWER: 0," dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
-echo_i "check 'rndc serve-stale unknown' ($n)"
+echo_i "check 'rndc serve-stale status' ($n)"
ret=0
-$RNDCCMD 10.53.0.1 serve-stale unknown > rndc.out.test$n 2>&1 && ret=1
-grep "syntax error" rndc.out.test$n > /dev/null || ret=1
+$RNDCCMD 10.53.0.1 serve-stale status > rndc.out.test$n 2>&1 || ret=1
+grep '_default: on (rndc) (stale-answer-ttl=3 max-stale-ttl=35)' rndc.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
-echo_i "flush cache, re-enable serve-stale and query again ($n)"
+echo_i "enable responses from authoritative server ($n)"
+ret=0
+$DIG -p ${PORT} @10.53.0.2 txt enable > dig.out.test$n
+grep "ANSWER: 1," dig.out.test$n > /dev/null || ret=1
+grep "TXT.\"1\"" dig.out.test$n > /dev/null || ret=1
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=`expr $status + $ret`
+
+sleep 1
+
+n=`expr $n + 1`
+echo_i "prime cache longttl.example (low max-stale-ttl) ($n)"
+ret=0
+$DIG -p ${PORT} @10.53.0.1 longttl.example TXT > dig.out.test$n
+grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
+grep "ANSWER: 1," dig.out.test$n > /dev/null || ret=1
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=`expr $status + $ret`
+
+n=`expr $n + 1`
+echo_i "prime cache data.example (low max-stale-ttl) ($n)"
ret=0
-$RNDCCMD 10.53.0.1 flushtree example > rndc.out.test$n.1 2>&1 || ret=1
-$RNDCCMD 10.53.0.1 serve-stale on > rndc.out.test$n.2 2>&1 || ret=1
$DIG -p ${PORT} @10.53.0.1 data.example TXT > dig.out.test$n
+grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
+grep "ANSWER: 1," dig.out.test$n > /dev/null || ret=1
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=`expr $status + $ret`
+
+n=`expr $n + 1`
+echo_i "prime cache nodata.example (low max-stale-ttl) ($n)"
+ret=0
+$DIG -p ${PORT} @10.53.0.1 nodata.example TXT > dig.out.test$n
+grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
+grep "ANSWER: 0," dig.out.test$n > /dev/null || ret=1
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=`expr $status + $ret`
+
+n=`expr $n + 1`
+echo_i "prime cache nxdomain.example (low max-stale-ttl) ($n)"
+ret=0
+$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT > dig.out.test$n
+grep "status: NXDOMAIN" dig.out.test$n > /dev/null || ret=1
+grep "ANSWER: 0," dig.out.test$n > /dev/null || ret=1
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=`expr $status + $ret`
+
+n=`expr $n + 1`
+echo_i "verify prime cache statistics (low max-stale-ttl) ($n)"
+ret=0
+rm -f ns1/named.stats
+$RNDCCMD 10.53.0.1 stats > /dev/null 2>&1
+[ -f ns1/named.stats ] || ret=1
+cp ns1/named.stats ns1/named.stats.$n
+# Check first 10 lines of Cache DB statistics. After prime queries, we expect
+# two active TXT RRsets, one nxrrset TXT, and one NXDOMAIN.
+grep -A 10 "++ Cache DB RRsets ++" ns1/named.stats.$n > ns1/named.stats.$n.cachedb || ret=1
+grep "2 TXT" ns1/named.stats.$n.cachedb > /dev/null || ret=1
+grep "1 !TXT" ns1/named.stats.$n.cachedb > /dev/null || ret=1
+grep "1 NXDOMAIN" ns1/named.stats.$n.cachedb > /dev/null || ret=1
+status=`expr $status + $ret`
+if [ $ret != 0 ]; then echo_i "failed"; fi
+
+n=`expr $n + 1`
+echo_i "disable responses from authoritative server ($n)"
+ret=0
+$DIG -p ${PORT} @10.53.0.2 txt disable > dig.out.test$n
+grep "ANSWER: 1," dig.out.test$n > /dev/null || ret=1
+grep "TXT.\"0\"" dig.out.test$n > /dev/null || ret=1
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=`expr $status + $ret`
+
+sleep 1
+
+n=`expr $n + 1`
+echo_i "check stale data.example (low max-stale-ttl) ($n)"
+ret=0
+$DIG -p ${PORT} @10.53.0.1 data.example TXT > dig.out.test$n
+grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
+grep "ANSWER: 1," dig.out.test$n > /dev/null || ret=1
+grep "data\.example\..*3.*IN.*TXT.*A text record with a 1 second ttl" dig.out.test$n > /dev/null || ret=1
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=`expr $status + $ret`
+
+n=`expr $n + 1`
+echo_i "check stale nodata.example (low max-stale-ttl) ($n)"
+ret=0
+$DIG -p ${PORT} @10.53.0.1 nodata.example TXT > dig.out.test$n
+grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
+grep "ANSWER: 0," dig.out.test$n > /dev/null || ret=1
+grep "example\..*3.*IN.*SOA" dig.out.test$n > /dev/null || ret=1
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=`expr $status + $ret`
+
+n=`expr $n + 1`
+echo_i "check stale nxdomain.example (low max-stale-ttl) ($n)"
+ret=0
+$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT > dig.out.test$n
+grep "status: NXDOMAIN" dig.out.test$n > /dev/null || ret=1
+grep "ANSWER: 0," dig.out.test$n > /dev/null || ret=1
+grep "example\..*3.*IN.*SOA" dig.out.test$n > /dev/null || ret=1
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=`expr $status + $ret`
+
+n=`expr $n + 1`
+echo_i "verify stale cache statistics (low max-stale-ttl) ($n)"
+ret=0
+rm -f ns1/named.stats
+$RNDCCMD 10.53.0.1 stats > /dev/null 2>&1
+[ -f ns1/named.stats ] || ret=1
+cp ns1/named.stats ns1/named.stats.$n
+# Check first 10 lines of Cache DB statistics. After serve-stale queries, we
+# expect one active TXT RRset, one stale TXT, one stale nxrrset TXT, and one
+# stale NXDOMAIN.
+grep -A 10 "++ Cache DB RRsets ++" ns1/named.stats.$n > ns1/named.stats.$n.cachedb || ret=1
+grep "1 TXT" ns1/named.stats.$n.cachedb > /dev/null || ret=1
+grep "1 #TXT" ns1/named.stats.$n.cachedb > /dev/null || ret=1
+grep "1 #!TXT" ns1/named.stats.$n.cachedb > /dev/null || ret=1
+grep "1 #NXDOMAIN" ns1/named.stats.$n.cachedb > /dev/null || ret=1
+status=`expr $status + $ret`
+if [ $ret != 0 ]; then echo_i "failed"; fi
+
+sleep 1
+
+n=`expr $n + 1`
+echo_i "check ancient data.example (low max-stale-ttl) ($n)"
+ret=0
+$DIG -p ${PORT} @10.53.0.1 data.example TXT > dig.out.test$n
+grep "status: SERVFAIL" dig.out.test$n > /dev/null || ret=1
+grep "ANSWER: 0," dig.out.test$n > /dev/null || ret=1
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=`expr $status + $ret`
+
+n=`expr $n + 1`
+echo_i "check ancient nodata.example (low max-stale-ttl) ($n)"
+ret=0
+$DIG -p ${PORT} @10.53.0.1 nodata.example TXT > dig.out.test$n
grep "status: SERVFAIL" dig.out.test$n > /dev/null || ret=1
grep "ANSWER: 0," dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
+n=`expr $n + 1`
+echo_i "check ancient nxdomain.example (low max-stale-ttl) ($n)"
+ret=0
+$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT > dig.out.test$n
+grep "status: SERVFAIL" dig.out.test$n > /dev/null || ret=1
+grep "ANSWER: 0," dig.out.test$n > /dev/null || ret=1
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=`expr $status + $ret`
+
+#
+# Now test server with no serve-stale options set.
+#
+echo_i "test server with no serve-stale options set"
+
n=`expr $n + 1`
echo_i "enable responses from authoritative server ($n)"
ret=0
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
+n=`expr $n + 1`
+echo_i "prime cache longttl.example (max-stale-ttl default) ($n)"
+ret=0
+$DIG -p ${PORT} @10.53.0.3 longttl.example TXT > dig.out.test$n
+grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
+grep "ANSWER: 1," dig.out.test$n > /dev/null || ret=1
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=`expr $status + $ret`
+
n=`expr $n + 1`
echo_i "prime cache data.example (max-stale-ttl default) ($n)"
ret=0
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
+n=`expr $n + 1`
+echo_i "verify prime cache statistics (max-stale-ttl default) ($n)"
+ret=0
+rm -f ns3/named.stats
+$RNDCCMD 10.53.0.3 stats > /dev/null 2>&1
+[ -f ns3/named.stats ] || ret=1
+cp ns3/named.stats ns3/named.stats.$n
+# Check first 10 lines of Cache DB statistics. After prime queries, we expect
+# two active TXT RRsets, one nxrrset TXT, and one NXDOMAIN.
+grep -A 10 "++ Cache DB RRsets ++" ns3/named.stats.$n > ns3/named.stats.$n.cachedb || ret=1
+grep "2 TXT" ns3/named.stats.$n.cachedb > /dev/null || ret=1
+grep "1 !TXT" ns3/named.stats.$n.cachedb > /dev/null || ret=1
+grep "1 NXDOMAIN" ns3/named.stats.$n.cachedb > /dev/null || ret=1
+status=`expr $status + $ret`
+if [ $ret != 0 ]; then echo_i "failed"; fi
+
sleep 1
n=`expr $n + 1`
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
+n=`expr $n + 1`
+echo_i "verify stale cache statistics (max-stale-ttl default) ($n)"
+ret=0
+rm -f ns3/named.stats
+$RNDCCMD 10.53.0.3 stats > /dev/null 2>&1
+[ -f ns3/named.stats ] || ret=1
+cp ns3/named.stats ns3/named.stats.$n
+# Check first 10 lines of Cache DB statistics. After last queries, we expect
+# one active TXT RRset, one stale TXT, one stale nxrrset TXT, and one
+# stale NXDOMAIN.
+grep -A 10 "++ Cache DB RRsets ++" ns3/named.stats.$n > ns3/named.stats.$n.cachedb || ret=1
+grep "1 TXT" ns3/named.stats.$n.cachedb > /dev/null || ret=1
+grep "1 #TXT" ns3/named.stats.$n.cachedb > /dev/null || ret=1
+grep "1 #!TXT" ns3/named.stats.$n.cachedb > /dev/null || ret=1
+grep "1 #NXDOMAIN" ns3/named.stats.$n.cachedb > /dev/null || ret=1
+status=`expr $status + $ret`
+if [ $ret != 0 ]; then echo_i "failed"; fi
+
n=`expr $n + 1`
echo_i "check 'rndc serve-stale on' ($n)"
ret=0
rbtdb_serial_t serial;
dns_ttl_t rdh_ttl;
rbtdb_rdatatype_t type;
- uint16_t attributes;
+ uint16_t attributes;
dns_trust_t trust;
struct noqname *noqname;
struct noqname *closest;
statattributes = DNS_RDATASTATSTYPE_ATTR_NXRRSET;
base = RBTDB_RDATATYPE_EXT(header->type);
}
- } else
+ } else {
base = RBTDB_RDATATYPE_BASE(header->type);
+ }
- if (STALE(header))
+ if (STALE(header)) {
statattributes |= DNS_RDATASTATSTYPE_ATTR_STALE;
+ }
+ if (ANCIENT(header)) {
+ statattributes |= DNS_RDATASTATSTYPE_ATTR_ANCIENT;
+ }
type = DNS_RDATASTATSTYPE_VALUE(base, statattributes);
- if (increment)
+ if (increment) {
dns_rdatasetstats_increment(rbtdb->rrsetstats, type);
- else
+ } else {
dns_rdatasetstats_decrement(rbtdb->rrsetstats, type);
+ }
}
static void
static inline void
mark_header_ancient(dns_rbtdb_t *rbtdb, rdatasetheader_t *header) {
+ bool do_stats = false;
/*
* If we are already ancient there is nothing to do.
*/
- if (ANCIENT(header))
+ if (ANCIENT(header)) {
return;
+ }
+
+ if ((header->attributes & RDATASET_ATTR_STATCOUNT) != 0) {
+ do_stats = EXISTS(header);
+ }
+
+ if (do_stats) {
+ /*
+ * Decrement the stats counter for the appropriate RRtype.
+ * If the STALE attribute is set, this will decrement the
+ * stale type counter, otherwise it decrements the active
+ * stats type counter.
+ */
+ update_rrsetstats(rbtdb, header, false);
+ }
header->attributes |= RDATASET_ATTR_ANCIENT;
header->node->dirty = 1;
+ if (do_stats) {
+ /* Increment the stats counter for the ancient RRtype. */
+ update_rrsetstats(rbtdb, header, true);
+ }
+}
+
+static inline void
+mark_header_stale(dns_rbtdb_t *rbtdb, rdatasetheader_t *header) {
+ bool do_stats = false;
+
/*
- * If we have not been counted then there is nothing to do.
+ * If we are already stale there is nothing to do.
*/
- if ((header->attributes & RDATASET_ATTR_STATCOUNT) == 0)
+ if (STALE(header)) {
return;
+ }
- if (EXISTS(header))
+ if ((header->attributes & RDATASET_ATTR_STATCOUNT) != 0) {
+ do_stats = EXISTS(header);
+ }
+
+ if (do_stats) {
+ /* Decrement the stats counter for the appropriate RRtype.
+ * If the ANCIENT attribute is set (although it is very
+ * unlikely that an RRset goes from ANCIENT to STALE), this
+ * will decrement the ancient stale type counter, otherwise it
+ * decrements the active stats type counter.
+ */
+ update_rrsetstats(rbtdb, header, false);
+ }
+
+ header->attributes |= RDATASET_ATTR_STALE;
+
+ if (do_stats) {
update_rrsetstats(rbtdb, header, true);
+ }
}
static inline void
* skip this record.
*/
if (KEEPSTALE(search->rbtdb) && stale > search->now) {
- header->attributes |= RDATASET_ATTR_STALE;
+ mark_header_stale(search->rbtdb, header);
*header_prev = header;
return ((search->options & DNS_DBFIND_STALEOK) == 0);
}
/*
* This rdataset is stale. If no one else is using the
* node, we can clean it up right now, otherwise we mark
- * it as stale, and the node as dirty, so it will get
+ * it as ancient, and the node as dirty, so it will get
* cleaned up later.
*/
if ((header->rdh_ttl < search->now - RBTDB_VIRTUAL) &&
mark_header_ancient(rbtdb, header);
if (log)
isc_log_write(dns_lctx, category, module,
- level, "overmem cache: stale %s",
+ level,
+ "overmem cache: ancient %s",
printname);
} else if (force_expire) {
if (! RETAIN(header)) {
* which covers all types (NXDOMAIN,
* NODATA(QTYPE=ANY)),
*
- * We make all other data stale so that the
+ * We make all other data ancient so that the
* only rdataset that can be found at this
* node is the negative cache entry.
*/
}
/*
* Otherwise look for any RRSIGs of the given
- * type so they can be marked stale later.
+ * type so they can be marked ancient later.
*/
for (topheader = rbtnode->data;
topheader != NULL;
/*
* We're adding something that isn't a
* negative cache entry. Look for an extant
- * non-stale NXDOMAIN/NODATA(QTYPE=ANY) negative
+ * non-ancient NXDOMAIN/NODATA(QTYPE=ANY) negative
* cache entry. If we're adding an RRSIG, also
- * check for an extant non-stale NODATA ncache
+ * check for an extant non-ancient NODATA ncache
* entry which covers the same type as the RRSIG.
*/
for (topheader = rbtnode->data;
* If we're adding a delegation type, adding to the auxiliary NSEC tree,
* or the DB is a cache in an overmem state, hold an exclusive lock on
* the tree. In the latter case the lock does not necessarily have to
- * be acquired but it will help purge stale entries more effectively.
+ * be acquired but it will help purge ancient entries more effectively.
*/
if (IS_CACHE(rbtdb) && isc_mem_isovermem(rbtdb->common.mctx))
cache_is_overmem = true;