]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
3703. [func] Prefetch about to expire records if they are queried
authorMark Andrews <marka@isc.org>
Sun, 12 Jan 2014 10:29:15 +0000 (21:29 +1100)
committerMark Andrews <marka@isc.org>
Sun, 12 Jan 2014 10:29:15 +0000 (21:29 +1100)
                        for, see prefetch option for details. [RT #35041]

23 files changed:
CHANGES
bin/named/config.c
bin/named/include/named/query.h
bin/named/query.c
bin/named/server.c
bin/tests/system/resolver/clean.sh
bin/tests/system/resolver/ns4/tld1.db
bin/tests/system/resolver/ns4/tld2.db
bin/tests/system/resolver/ns5/named.conf
bin/tests/system/resolver/ns6/example.net.db.in
bin/tests/system/resolver/ns6/named.conf
bin/tests/system/resolver/ns7/named1.conf
bin/tests/system/resolver/ns7/named2.conf
bin/tests/system/resolver/tests.sh
doc/arm/Bv9ARM-book.xml
doc/misc/options
lib/dns/include/dns/db.h
lib/dns/include/dns/rdataset.h
lib/dns/include/dns/resolver.h
lib/dns/include/dns/view.h
lib/dns/rbtdb.c
lib/dns/resolver.c
lib/isccfg/namedconf.c

diff --git a/CHANGES b/CHANGES
index 5014103180ea4c3e07b954df154763863d161a7a..fccec231a63f18c5681d2b9c0872f69f82e11de1 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,6 @@
+3703.  [func]          Prefetch about to expire records if they are queried
+                       for, see prefetch option for details. [RT #35041]
+
 3702.  [func]          'dnssec-coverage -l' option specifies a length
                        of time to check for coverage; events further into
                        the future are ignored.  'dnssec-coverage -z'
index d3a2ed90435f5bcad60eedba7f85f7d85b208b9b..8d4498c7707a2cfc2e33b840cef042f5175297f4 100644 (file)
@@ -80,6 +80,7 @@ options {\n\
 #      pid-file \"" NS_LOCALSTATEDIR "/run/named/named.pid\"; /* or /lwresd.pid */\n\
        bindkeys-file \"" NS_SYSCONFDIR "/bind.keys\";\n\
        port 53;\n\
+       prefetch 2 9;\n\
        recursing-file \"named.recursing\";\n\
        secroots-file \"named.secroots\";\n\
 "
index a14d5169c703901d9bb72ec4f4b2ca682ca1010b..7843e8ffe60044cad9abf02ad8dd03dcc23df12a 100644 (file)
@@ -57,6 +57,7 @@ struct ns_query {
        isc_boolean_t                   isreferral;
        isc_mutex_t                     fetchlock;
        dns_fetch_t *                   fetch;
+       dns_fetch_t *                   prefetch;
        dns_rpz_st_t *                  rpz_st;
        isc_bufferlist_t                namebufs;
        ISC_LIST(ns_dbversion_t)        activeversions;
index 47766917c2d22505c821976171d733f7129e7eca..514c2ebbaacab43f127f29918ef6619c2d2fde9d 100644 (file)
@@ -615,6 +615,7 @@ ns_query_init(ns_client_t *client) {
        if (result != ISC_R_SUCCESS)
                return (result);
        client->query.fetch = NULL;
+       client->query.prefetch = NULL;
        client->query.authdb = NULL;
        client->query.authzone = NULL;
        client->query.authdbset = ISC_FALSE;
@@ -3786,6 +3787,79 @@ query_resume(isc_task_t *task, isc_event_t *event) {
        dns_resolver_destroyfetch(&fetch);
 }
 
+static void
+prefetch_done(isc_task_t *task, isc_event_t *event) {
+       dns_fetchevent_t *devent = (dns_fetchevent_t *)event;
+       ns_client_t *client;
+
+       UNUSED(task);
+
+       REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
+       client = devent->ev_arg;
+       REQUIRE(NS_CLIENT_VALID(client));
+       REQUIRE(task == client->task);
+
+       LOCK(&client->query.fetchlock);
+       if (client->query.prefetch != NULL) {
+               INSIST(devent->fetch == client->query.prefetch);
+               client->query.prefetch = NULL;
+       }
+       UNLOCK(&client->query.fetchlock);
+       if (devent->fetch != NULL)
+               dns_resolver_destroyfetch(&devent->fetch);
+       if (devent->node != NULL)
+               dns_db_detachnode(devent->db, &devent->node);
+       if (devent->db != NULL)
+               dns_db_detach(&devent->db);
+       query_putrdataset(client, &devent->rdataset);
+       isc_event_free(&event);
+       ns_client_detach(&client);
+}
+
+static void
+query_prefetch(ns_client_t *client, dns_name_t *qname,
+              dns_rdataset_t *rdataset)
+{
+       isc_result_t result;
+       isc_sockaddr_t *peeraddr;
+       dns_rdataset_t *tmprdataset;
+       ns_client_t *dummy = NULL;
+
+       if (client->view->prefetch_trigger == 0U ||
+            rdataset->ttl > client->view->prefetch_trigger ||
+           (rdataset->attributes & DNS_RDATASETATTR_PREFETCH) == 0)
+               return;
+
+       if (client->recursionquota == NULL) {
+               result = isc_quota_attach(&ns_g_server->recursionquota,
+                                         &client->recursionquota);
+               if (result != ISC_R_SUCCESS)
+                       return;
+       }
+       if (client->query.prefetch != NULL)
+               return;
+
+       tmprdataset = query_newrdataset(client);
+       if (tmprdataset == NULL)
+               return;
+       if ((client->attributes & NS_CLIENTATTR_TCP) == 0)
+               peeraddr = &client->peeraddr;
+       else
+               peeraddr = NULL;
+       ns_client_attach(client, &dummy);
+       unsigned options = client->query.fetchoptions | DNS_FETCHOPT_PREFETCH;
+       result = dns_resolver_createfetch2(client->view->resolver,
+                                          qname, rdataset->type, NULL, NULL,
+                                          NULL, peeraddr, client->message->id,
+                                          options, client->task,
+                                          prefetch_done, client, tmprdataset,
+                                          NULL, &client->query.prefetch);
+       if (result != ISC_R_SUCCESS) {
+               query_putrdataset(client, &tmprdataset);
+               ns_client_detach(&dummy);
+       }
+}
+
 static isc_result_t
 query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname,
              dns_name_t *qdomain, dns_rdataset_t *nameservers,
@@ -7271,6 +7345,8 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
                        noqname = rdataset;
                else
                        noqname = NULL;
+               if (!is_zone && RECURSIONOK(client))
+                       query_prefetch(client, fname, rdataset);
                query_addrrset(client, &fname, &rdataset, sigrdatasetp, dbuf,
                               DNS_SECTION_ANSWER);
                if (noqname != NULL)
@@ -7343,6 +7419,8 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
                                      NULL);
                        need_wildcardproof = ISC_TRUE;
                }
+               if (!is_zone && RECURSIONOK(client))
+                       query_prefetch(client, fname, rdataset);
                query_addrrset(client, &fname, &rdataset, sigrdatasetp, dbuf,
                               DNS_SECTION_ANSWER);
                /*
@@ -7547,6 +7625,8 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
                                if (rpz_st != NULL)
                                        rdataset->ttl = ISC_MIN(rdataset->ttl,
                                                            rpz_st->m.ttl);
+                               if (!is_zone && RECURSIONOK(client))
+                                       query_prefetch(client, fname, rdataset);
                                query_addrrset(client,
                                               fname != NULL ? &fname : &tname,
                                               &rdataset, NULL,
@@ -7801,9 +7881,12 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
                        query_filter64(client, &fname, rdataset, dbuf,
                                       DNS_SECTION_ANSWER);
                        query_putrdataset(client, &rdataset);
-               } else
+               } else {
+                       if (!is_zone && RECURSIONOK(client))
+                               query_prefetch(client, fname, rdataset);
                        query_addrrset(client, &fname, &rdataset,
                                       sigrdatasetp, dbuf, DNS_SECTION_ANSWER);
+               }
 
                if (noqname != NULL)
                        query_addnoqnameproof(client, noqname);
index 0b427cd71b61cc22b22b15738b35c8b4892bca3e..ac423fcd3e2387b6f8e76240f5e2ae391a9a5539 100644 (file)
@@ -3401,6 +3401,33 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
        CHECK(configure_view_acl(vconfig, config, "filter-aaaa", NULL,
                                 actx, ns_g_mctx, &view->aaaa_acl));
 #endif
+       obj = NULL;
+       result = ns_config_get(maps, "prefetch", &obj);
+       if (result == ISC_R_SUCCESS) {
+               const cfg_obj_t *trigger, *eligible;
+
+               trigger = cfg_tuple_get(obj, "trigger");
+               view->prefetch_trigger = cfg_obj_asuint32(trigger);
+               if (view->prefetch_trigger > 10)
+                       view->prefetch_trigger = 10;
+               eligible = cfg_tuple_get(obj, "eligible");
+               if (cfg_obj_isvoid(eligible)) {
+                       int i;
+                       for (i = 1; maps[i] != NULL; i++) {
+                               obj = NULL;
+                               result = ns_config_get(&maps[i],
+                                                      "prefetch", &obj);
+                               INSIST(result == ISC_R_SUCCESS);
+                               eligible = cfg_tuple_get(obj, "eligible");
+                               if (cfg_obj_isuint32(eligible))
+                                       break;
+                       }
+                       INSIST(cfg_obj_isuint32(eligible));
+               }
+               view->prefetch_eligible = cfg_obj_asuint32(eligible);
+               if (view->prefetch_eligible < view->prefetch_trigger + 6)
+                       view->prefetch_eligible = view->prefetch_trigger + 6;
+       }
 
        obj = NULL;
        result = ns_config_get(maps, "dnssec-enable", &obj);
index 5317120864227b56ab9c803946484ea493304c16..5a0c8fcdd8657944be47727c79ac19f16192f1b2 100644 (file)
@@ -20,7 +20,9 @@
 # Clean up after resolver tests.
 #
 rm -f */named.memstats
-rm -f dig.out dig.*.out.*
+rm -f */*.jdb
+rm -f dig.out dig.out.*
+rm -f dig.*.out.*
 rm -f dig.*.foo.*
 rm -f dig.*.bar.*
 rm -f dig.*.prime.*
index a2f55984d9bdf631705d0408d3c1788597a3496d..3c28f42167d9b79ae92698553ba9aca57bfa66b1 100644 (file)
@@ -27,3 +27,4 @@ ns                    A       10.53.0.4
 $TTL 5
 to-be-removed          NS      ns.to-be-removed
 ns.to-be-removed       A       10.53.0.6
+fetch  10              TXT     A short ttl
index 6bd751438f37310e8bf4643eb09e5e80c5163cd7..dadacd43feb153a51b789b82371b46a27afcb88f 100644 (file)
@@ -24,3 +24,4 @@ $TTL 300
                                )
 @                      NS      ns.tld.
 ns                     A       10.53.0.4
+fetch  10              TXT     A short ttl
index 374fa797fbc997e47adf348c00535b4b58d20836..71d233674defd8db4e329137a071d6cf802eaccb 100644 (file)
@@ -16,7 +16,7 @@
 
 /* $Id: named.conf,v 1.4 2011/03/13 23:47:36 tbox Exp $ */
 
-// NS4
+// NS5
 
 controls { /* empty */ };
 
index 103cab4c887b5df5efa7af2db88b202fd9eacc77..0402ec9edfe8f41f0fc4101590b6eee275d90b90 100644 (file)
@@ -20,3 +20,4 @@ $TTL 600
 @      IN MX   0 mail
 ns     IN A    10.53.0.6
 mail   IN A    10.53.0.6
+fetch 10 IN TXT A short ttl
index bb10d8d667b088c095084ecda70ed798d8ecbd41..2075b1446c39b21b2bcbdea9a1471c47ff2b7b67 100644 (file)
@@ -16,7 +16,7 @@
 
 /* $Id: named.conf,v 1.4 2012/02/09 23:47:18 tbox Exp $ */
 
-// NS4
+// NS6
 
 controls { /* empty */ };
 
index 103a40dfe9f2072489ccae13c6e7407912fe3fdc..07784aaec737f8db0be84be9fe34617cfac6e44e 100644 (file)
@@ -14,7 +14,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-// NS4
+// NS7
 
 controls { /* empty */ };
 
@@ -29,6 +29,7 @@ options {
        recursion yes;
        empty-zones-enable yes;
        disable-empty-zone 20.172.in-addr.arpa;
+       prefetch 0;
 };
 
 key rndc_key {
index ad7221fbaf1ae3cab2c08b4d52e69cdd138089b9..149bf526dc53654f678984c1e70ff2e6739bdeb7 100644 (file)
@@ -14,7 +14,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-// NS4
+// NS7
 
 controls { /* empty */ };
 
@@ -29,6 +29,7 @@ options {
        recursion yes;
        empty-zones-enable yes;
        disable-empty-zone 20.172.in-addr.arpa;
+       prefetch 0;
 };
 
 key rndc_key {
index 7f3e6c92fca449cfa7a15c93dc90bdaf2dd0bbd0..23e59d3759d5045611ad55ec1a9cb00ea0addc6f 100755 (executable)
@@ -403,7 +403,6 @@ grep "not subdomain of zone" ns1/named.run > /dev/null || ret=1
 if [ $ret != 0 ]; then echo "I:failed"; fi
 status=`expr $status + $ret`
 
-#HERE <<<
 cp ns7/named2.conf ns7/named.conf
 $RNDC -c ../common/rndc.conf -s 10.53.0.7 -p 9953 reconfig 2>&1 | sed 's/^/I:ns7 /'
 
@@ -415,7 +414,49 @@ grep "status: NOERROR" dig.ns7.out.${n} > /dev/null || ret=1
 grep "ANSWER: 1" dig.ns7.out.${n} > /dev/null || ret=1
 if [ $ret != 0 ]; then echo "I:failed"; ret=1; fi
 status=`expr $status + $ret`
-#HERE >>>
+
+n=`expr $n + 1`
+echo "I:check prefetch (${n})"
+ret=0
+$DIG @10.53.0.5 -p 5300 fetch.tld txt > dig.out.1.${n} || ret=1
+ttl1=`awk '/"A" "short" "ttl"/ { print $2 - 2 }' dig.out.1.${n}`
+# sleep so we are in prefetch range
+sleep ${ttl1:-0}
+# trigger prefetch
+$DIG @10.53.0.5 -p 5300 fetch.tld txt > dig.out.2.${n} || ret=1
+ttl2=`awk '/"A" "short" "ttl"/ { print $2 }' dig.out.2.${n}`
+sleep 1
+# check that prefetch occured
+$DIG @10.53.0.5 -p 5300 fetch.tld txt > dig.out.3.${n} || ret=1
+ttl=`awk '/"A" "short" "ttl"/ { print $2 }' dig.out.3.${n}`
+test ${ttl:-0} -gt ${ttl2:-1} || ret=1
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+n=`expr $n + 1`
+echo "I:check prefetch disabled (${n})"
+ret=0
+$DIG @10.53.0.7 -p 5300 fetch.example.net txt > dig.out.1.${n} || ret=1
+ttl1=`awk '/"A" "short" "ttl"/ { print $2 - 1 }' dig.out.1.${n}`
+# sleep so we are in expire range
+sleep ${ttl1:-0}
+# look for zero ttl, allow for one miss at getting zero ttl
+for i in 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
+do 
+       $DIG @10.53.0.7 -p 5300 fetch.example.net txt > dig.out.2.${n} || ret=1
+       ttl2=`awk '/"A" "short" "ttl"/ { print $2 }' dig.out.2.${n}`
+       test ${ttl2:-1} -eq 0 && break
+       sleep 1
+done
+test ${ttl2:-1} -eq 0 || ret=1
+# delay so that any prefetched record will have a lower ttl than expected
+sleep 3
+# check that prefetch has not occured
+$DIG @10.53.0.7 -p 5300 fetch.example.net txt > dig.out.3.${n} || ret=1
+ttl=`awk '/"A" "short" "ttl"/ { print $2 - 1 }' dig.out.3.${n}`
+test ${ttl:-0} -eq ${ttl1:-1} || ret=1
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
 
 echo "I:exit status: $status"
 exit $status
index 1bb4de8b77a23d98648146e462bffd5827c0255d..b1dd4169e5a23f4f2afeb64cce93b7ca486f6083 100644 (file)
@@ -8736,6 +8736,21 @@ avoid-v6-udp-ports { 40000; range 50000 60000; };
                </para>
               </listitem>
             </varlistentry>
+
+            <varlistentry>
+              <term><command>prefetch</command></term>
+              <listitem>
+               <para>
+                 Specifies the trigger ttl value (range [1..10])
+                 at which prefetch of the current query will be
+                 made and optionally the minimum ttl value that will be
+                 accepted for the records to be candidates for
+                 prefetching.  The defaults are 2 and 9 respectively.
+                 Setting a trigger ttl value of 0 will disable
+                 prefetching.  A minimum delta of 6 is enforced.
+               </para>
+             </listitem>
+           </varlistentry>
          </variablelist>
 
         </sect3>
index c034ad47695712110bcd16e444e1e23734652123..fae4ed15ca6fc8373473d8e4740dbefac781e31e 100644 (file)
@@ -139,9 +139,9 @@ options {
         fake-iquery <boolean>; // obsolete
         fetch-glue <boolean>; // obsolete
         files <size>;
-        filter-aaaa { <address_match_element>; ... }; // not configured
-        filter-aaaa-on-v4 <filter_aaaa>; // not configured
-        filter-aaaa-on-v6 <filter_aaaa>; // not configured
+        filter-aaaa { <address_match_element>; ... };
+        filter-aaaa-on-v4 <filter_aaaa>;
+        filter-aaaa-on-v6 <filter_aaaa>;
         flush-zones-on-shutdown <boolean>;
         forward ( first | only );
         forwarders [ port <integer> ] [ dscp <integer> ] { ( <ipv4_address>
@@ -199,6 +199,7 @@ options {
         pid-file ( <quoted_string> | none );
         port <integer>;
         preferred-glue <string>;
+        prefetch <integer> [ <integer> ];
         provide-ixfr <boolean>;
         query-source <querysource4>;
         query-source-v6 <querysource6>;
@@ -397,9 +398,9 @@ view <string> <optional_class> {
         empty-server <string>;
         empty-zones-enable <boolean>;
         fetch-glue <boolean>; // obsolete
-        filter-aaaa { <address_match_element>; ... }; // not configured
-        filter-aaaa-on-v4 <filter_aaaa>; // not configured
-        filter-aaaa-on-v6 <filter_aaaa>; // not configured
+        filter-aaaa { <address_match_element>; ... };
+        filter-aaaa-on-v4 <filter_aaaa>;
+        filter-aaaa-on-v6 <filter_aaaa>;
         forward ( first | only );
         forwarders [ port <integer> ] [ dscp <integer> ] { ( <ipv4_address>
             | <ipv6_address> ) [ port <integer> ] [ dscp <integer> ]; ... };
@@ -446,6 +447,7 @@ view <string> <optional_class> {
         notify-to-soa <boolean>;
         nsec3-test-zone <boolean>; // test only
         preferred-glue <string>;
+        prefetch <integer> [ <integer> ];
         provide-ixfr <boolean>;
         query-source <querysource4>;
         query-source-v6 <querysource6>;
index 229083a18245d2639bb4306e32f827870f7103f7..ab50a91e7bb57bc0782bf0a5a9c92c66dcc6b90f 100644 (file)
@@ -252,6 +252,7 @@ struct dns_db {
 #define DNS_DBADD_FORCE                        0x02
 #define DNS_DBADD_EXACT                        0x04
 #define DNS_DBADD_EXACTTTL             0x08
+#define DNS_DBADD_PREFETCH             0x10
 /*@}*/
 
 /*%
index 31bcd15f1424ec211dd72aac40cfb166c8122bae..a3ba5e3500c3c724bbe499ac0d93ef9e0e19b9a3 100644 (file)
@@ -205,6 +205,7 @@ struct dns_rdataset {
 #define DNS_RDATASETATTR_CLOSEST       0x00080000
 #define DNS_RDATASETATTR_OPTOUT                0x00100000      /*%< OPTOUT proof */
 #define DNS_RDATASETATTR_NEGATIVE      0x00200000
+#define DNS_RDATASETATTR_PREFETCH      0x00400000
 
 /*%
  * _OMITDNSSEC:
index 075fa8acb8aa5496bd406d816f2590cceba6fd29..2bc25a424fb86acb0e9328e48052468a2cb4357d 100644 (file)
@@ -87,15 +87,16 @@ typedef struct dns_fetchevent {
 /*
  * Options that modify how a 'fetch' is done.
  */
-#define DNS_FETCHOPT_TCP               0x0        /*%< Use TCP. */
-#define DNS_FETCHOPT_UNSHARED          0x0        /*%< See below. */
-#define DNS_FETCHOPT_RECURSIVE         0x0        /*%< Set RD? */
-#define DNS_FETCHOPT_NOEDNS0           0x0        /*%< Do not use EDNS. */
-#define DNS_FETCHOPT_FORWARDONLY       0x10         /*%< Only use forwarders. */
-#define DNS_FETCHOPT_NOVALIDATE                0x20         /*%< Disable validation. */
-#define DNS_FETCHOPT_EDNS512           0x40         /*%< Advertise a 512 byte
+#define DNS_FETCHOPT_TCP               0x001        /*%< Use TCP. */
+#define DNS_FETCHOPT_UNSHARED          0x002        /*%< See below. */
+#define DNS_FETCHOPT_RECURSIVE         0x004        /*%< Set RD? */
+#define DNS_FETCHOPT_NOEDNS0           0x008        /*%< Do not use EDNS. */
+#define DNS_FETCHOPT_FORWARDONLY       0x010        /*%< Only use forwarders. */
+#define DNS_FETCHOPT_NOVALIDATE                0x020        /*%< Disable validation. */
+#define DNS_FETCHOPT_EDNS512           0x040        /*%< Advertise a 512 byte
                                                          UDP buffer. */
-#define DNS_FETCHOPT_WANTNSID           0x80         /*%< Request NSID */
+#define DNS_FETCHOPT_WANTNSID           0x080         /*%< Request NSID */
+#define DNS_FETCHOPT_PREFETCH           0x100         /*%< Request NSID */
 
 #define        DNS_FETCHOPT_EDNSVERSIONSET     0x00800000
 #define        DNS_FETCHOPT_EDNSVERSIONMASK    0xff000000
index b287869aef2e3114e5b14fc7ec91734534277dfc..5f7f0e7dbf9ce983e503e6343e3877cb79a624aa 100644 (file)
@@ -149,6 +149,8 @@ struct dns_view {
        isc_boolean_t                   requestnsid;
        dns_ttl_t                       maxcachettl;
        dns_ttl_t                       maxncachettl;
+       dns_ttl_t                       prefetch_trigger;
+       dns_ttl_t                       prefetch_eligible;
        in_port_t                       dstport;
        dns_aclenv_t                    aclenv;
        dns_rdatatype_t                 preferred_glue;
index 825fd427f076a76d0a45d907a4cb555eb9ec7b11..3b0da11c0a66101c167f76dfc1e37608c0618001 100644 (file)
@@ -330,8 +330,9 @@ typedef ISC_LIST(dns_rbtnode_t)         rbtnodelist_t;
 #define RDATASET_ATTR_NXDOMAIN          0x0010
 #define RDATASET_ATTR_RESIGN            0x0020
 #define RDATASET_ATTR_STATCOUNT         0x0040
-#define RDATASET_ATTR_OPTOUT           0x0080
+#define RDATASET_ATTR_OPTOUT            0x0080
 #define RDATASET_ATTR_NEGATIVE          0x0100
+#define RDATASET_ATTR_PREFETCH          0x0200
 
 typedef struct acache_cbarg {
        dns_rdatasetadditional_t        type;
@@ -372,6 +373,8 @@ struct acachectl {
        (((header)->attributes & RDATASET_ATTR_OPTOUT) != 0)
 #define NEGATIVE(header) \
        (((header)->attributes & RDATASET_ATTR_NEGATIVE) != 0)
+#define PREFETCH(header) \
+       (((header)->attributes & RDATASET_ATTR_PREFETCH) != 0)
 
 #define DEFAULT_NODE_LOCK_COUNT         7       /*%< Should be prime. */
 
@@ -2944,6 +2947,8 @@ bind_rdataset(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
                rdataset->attributes |= DNS_RDATASETATTR_NXDOMAIN;
        if (OPTOUT(header))
                rdataset->attributes |= DNS_RDATASETATTR_OPTOUT;
+       if (PREFETCH(header))
+               rdataset->attributes |= DNS_RDATASETATTR_PREFETCH;
        rdataset->private1 = rbtdb;
        rdataset->private2 = node;
        raw = (unsigned char *)header + sizeof(*header);
@@ -6127,6 +6132,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
                        }
                }
                if (IS_CACHE(rbtdb) && header->rdh_ttl >= now &&
+                   (options & DNS_DBADD_PREFETCH) == 0 &&
                    (header->type == dns_rdatatype_a ||
                     header->type == dns_rdatatype_aaaa ||
                     header->type == dns_rdatatype_ds ||
@@ -6456,6 +6462,8 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
        } else {
                newheader->serial = 1;
                newheader->resign = 0;
+               if ((rdataset->attributes & DNS_RDATASETATTR_PREFETCH) != 0)
+                       newheader->attributes |= RDATASET_ATTR_PREFETCH;
                if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0)
                        newheader->attributes |= RDATASET_ATTR_NEGATIVE;
                if ((rdataset->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
index 028bc17be08eae544716a78d5f209ed73195a03b..bf0ce47a89c5a8869871bdd3c5b199643e351405 100644 (file)
@@ -4382,8 +4382,11 @@ validated(isc_task_t *task, isc_event_t *event) {
        if (result != ISC_R_SUCCESS)
                goto noanswer_response;
 
+       unsigned options = 0;
+       if ((fctx->options & DNS_FETCHOPT_PREFETCH) != 0)
+               options = DNS_DBADD_PREFETCH;
        result = dns_db_addrdataset(fctx->cache, node, NULL, now,
-                                   vevent->rdataset, 0, ardataset);
+                                   vevent->rdataset, options, ardataset);
        if (result != ISC_R_SUCCESS &&
            result != DNS_R_UNCHANGED)
                goto noanswer_response;
@@ -4793,6 +4796,12 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo,
                if (rdataset->ttl > res->view->maxcachettl)
                        rdataset->ttl = res->view->maxcachettl;
 
+               /*
+                * Mark the rdataset as being prefetch eligible.
+                */
+               if (rdataset->ttl > fctx->res->view->prefetch_eligible)
+                       rdataset->attributes |= DNS_RDATASETATTR_PREFETCH;
+
                /*
                 * Find the SIG for this rdataset, if we have it.
                 */
@@ -4844,6 +4853,13 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo,
                                sigrdataset->ttl = rdataset->ttl;
                        }
 
+                       /*
+                        * Mark the rdataset as being prefetch eligible.
+                        */
+                       if (rdataset->ttl > fctx->res->view->prefetch_eligible)
+                               rdataset->attributes |= DNS_RDATASETATTR_PREFETCH;
+
+
                        /*
                         * Cache this rdataset/sigrdataset pair as
                         * pending data.  Track whether it was additional
@@ -4858,6 +4874,7 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo,
                        if (sigrdataset != NULL)
                                sigrdataset->trust = trust;
                        if (!need_validation || !ANSWER(rdataset)) {
+                               options = 0;
                                if (ANSWER(rdataset) &&
                                   rdataset->type != dns_rdatatype_rrsig) {
                                        isc_result_t tresult;
@@ -4874,10 +4891,13 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo,
                                                              ISC_R_SUCCESS);
                                        }
                                }
+                               if ((fctx->options & DNS_FETCHOPT_PREFETCH) != 0)
+                                               options = DNS_DBADD_PREFETCH;
                                addedrdataset = ardataset;
                                result = dns_db_addrdataset(fctx->cache, node,
                                                            NULL, now, rdataset,
-                                                           0, addedrdataset);
+                                                           options,
+                                                           addedrdataset);
                                if (result == DNS_R_UNCHANGED) {
                                        result = ISC_R_SUCCESS;
                                        if (!need_validation &&
@@ -4911,7 +4931,8 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo,
                                        addedrdataset = asigrdataset;
                                        result = dns_db_addrdataset(fctx->cache,
                                                                node, NULL, now,
-                                                               sigrdataset, 0,
+                                                               sigrdataset, 
+                                                               options,
                                                                addedrdataset);
                                        if (result == DNS_R_UNCHANGED)
                                                result = ISC_R_SUCCESS;
@@ -4999,7 +5020,9 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo,
                                 * over the existing cache contents.
                                 */
                                options = DNS_DBADD_FORCE;
-                       } else
+                       } else if ((fctx->options & DNS_FETCHOPT_PREFETCH) != 0)
+                               options = DNS_DBADD_PREFETCH;
+                       else
                                options = 0;
 
                        if (ANSWER(rdataset) &&
index 225cdf01371360ce2df3178b7c5b454544d4a59c..dc979c6935eb581e13c9b79d5c7b6d2fddfb7386 100644 (file)
@@ -1402,6 +1402,43 @@ static cfg_type_t cfg_type_lookaside = {
        &cfg_rep_tuple, lookaside_fields
 };
 
+static isc_result_t
+parse_optional_uint32(cfg_parser_t *pctx, const cfg_type_t *type,
+                     cfg_obj_t **ret)
+{
+       isc_result_t result;
+       UNUSED(type);
+
+       CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER));
+       if (pctx->token.type == isc_tokentype_number) {
+               CHECK(cfg_parse_obj(pctx, &cfg_type_uint32, ret));
+       } else {
+               CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret));
+       }
+ cleanup:
+       return (result);
+}
+
+static void
+doc_optional_uint32(cfg_printer_t *pctx, const cfg_type_t *type) {
+       UNUSED(type);
+       cfg_print_cstr(pctx, "[ <integer> ]");
+}
+
+static cfg_type_t cfg_type_optional_uint32 = {
+       "optional_uint32", parse_optional_uint32, NULL, doc_optional_uint32,
+       NULL, NULL };
+
+static cfg_tuplefielddef_t prefetch_fields[] = {
+       { "trigger", &cfg_type_uint32, 0 },
+       { "eligible", &cfg_type_optional_uint32, 0 },
+       { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_prefetch = {
+       "prefetch", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+       &cfg_rep_tuple, prefetch_fields
+};
 /*
  * DNS64.
  */
@@ -1483,6 +1520,7 @@ view_clauses[] = {
        { "max-udp-size", &cfg_type_uint32, 0 },
        { "min-roots", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP },
        { "minimal-responses", &cfg_type_boolean, 0 },
+       { "prefetch", &cfg_type_prefetch, 0 },
        { "preferred-glue", &cfg_type_astring, 0 },
        { "provide-ixfr", &cfg_type_boolean, 0 },
        /*
@@ -1537,32 +1575,6 @@ view_only_clauses[] = {
 /*%
  * Sig-validity-interval.
  */
-static isc_result_t
-parse_optional_uint32(cfg_parser_t *pctx, const cfg_type_t *type,
-                     cfg_obj_t **ret)
-{
-       isc_result_t result;
-       UNUSED(type);
-
-       CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER));
-       if (pctx->token.type == isc_tokentype_number) {
-               CHECK(cfg_parse_obj(pctx, &cfg_type_uint32, ret));
-       } else {
-               CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret));
-       }
- cleanup:
-       return (result);
-}
-
-static void
-doc_optional_uint32(cfg_printer_t *pctx, const cfg_type_t *type) {
-       UNUSED(type);
-       cfg_print_cstr(pctx, "[ <integer> ]");
-}
-
-static cfg_type_t cfg_type_optional_uint32 = {
-       "optional_uint32", parse_optional_uint32, NULL, doc_optional_uint32,
-       NULL, NULL };
 
 static cfg_tuplefielddef_t validityinterval_fields[] = {
        { "validity", &cfg_type_uint32, 0 },