]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Use optimal message sizes to improve compression in AXFRs (#40996)
authorMukund Sivaraman <muks@isc.org>
Tue, 15 Dec 2015 07:52:15 +0000 (13:22 +0530)
committerMukund Sivaraman <muks@isc.org>
Tue, 15 Dec 2015 07:54:14 +0000 (13:24 +0530)
15 files changed:
CHANGES
bin/named/config.c
bin/named/include/named/server.h
bin/named/named.conf.docbook
bin/named/server.c
bin/named/xfrout.c
bin/tests/system/xfer/clean.sh
bin/tests/system/xfer/ns8/.gitignore [new file with mode: 0644]
bin/tests/system/xfer/ns8/example.db [new file with mode: 0644]
bin/tests/system/xfer/ns8/named.conf [new file with mode: 0644]
bin/tests/system/xfer/setup.sh
bin/tests/system/xfer/tests.sh
doc/arm/Bv9ARM-book.xml
doc/misc/options
lib/isccfg/namedconf.c

diff --git a/CHANGES b/CHANGES
index 9d3d8a6b5b2dc21339be2d3fb8f831dee4e53d2c..6dcd77eea8ffcf0dc57f3b6500d1871b7e175e06 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,6 @@
+4280.  [performance]   Use optimal message sizes to improve compression
+                       in AXFRs. This reduces network traffic. [RT #40996]
+
 4279.  [test]          Don't use fixed ports when unit testing. [RT #41194]
 
 4278.  [bug]           'delv +short +[no]split[=##]' didn't work as expected.
index 2b7d0c94567de196ad27771703f5d48e0aec7e9f..b0af1be2c37bb24bd1dacca40ffde2c287e12e61 100644 (file)
@@ -113,6 +113,7 @@ options {\n\
 #      tkey-dhkey <none>\n\
 #      tkey-gssapi-credential <none>\n\
 #      tkey-domain <none>\n\
+       transfer-message-size 20480;\n\
        transfers-per-ns 2;\n\
        transfers-in 10;\n\
        transfers-out 10;\n\
index a2f9a726abeb1c7f72e27aa913d388abeb1dac70..3f2943fac0402b46841777646fe42dcb4c4ac65c 100644 (file)
@@ -126,6 +126,8 @@ struct ns_server {
        dns_dtenv_t             *dtenv;         /*%< Dnstap environment */
 
        char *                  lockfile;
+
+       isc_uint16_t            transfer_tcp_message_size;
 };
 
 #define NS_SERVER_MAGIC                        ISC_MAGIC('S','V','E','R')
index a6a31070ed5c5afff2c894485c926a6ebb33a66b..4416b1e32a73d43112552664d1975fbf0ca2fe0e 100644 (file)
@@ -237,6 +237,7 @@ options {
        tkey-gssapi-credential <replaceable>quoted_string</replaceable>;
        tkey-gssapi-keytab <replaceable>quoted_string</replaceable>;
        tkey-domain <replaceable>quoted_string</replaceable>;
+       transfer-message-size <replaceable>integer</replaceable>;
        transfers-per-ns <replaceable>integer</replaceable>;
        transfers-in <replaceable>integer</replaceable>;
        transfers-out <replaceable>integer</replaceable>;
index 7ef8488ff4c5e276031cb7f34a28dd780dda36cc..f65a3488daed074469827ea591b4213362a23155 100644 (file)
@@ -5814,6 +5814,7 @@ load_configuration(const char *filename, ns_server_t *server,
        isc_uint32_t interface_interval;
        isc_uint32_t reserved;
        isc_uint32_t udpsize;
+       isc_uint32_t transfer_message_size;
        ns_cache_t *nsc;
        ns_cachelist_t cachelist, tmpcachelist;
        ns_cfgctx_t *nzctx;
@@ -6128,6 +6129,17 @@ load_configuration(const char *filename, ns_server_t *server,
                udpsize = 4096;
        ns_g_udpsize = (isc_uint16_t)udpsize;
 
+       /* Set the transfer message size for TCP */
+       obj = NULL;
+       result = ns_config_get(maps, "transfer-message-size", &obj);
+       INSIST(result == ISC_R_SUCCESS);
+       transfer_message_size = cfg_obj_asuint32(obj);
+       if (transfer_message_size < 512)
+               transfer_message_size = 512;
+       else if (transfer_message_size > 65535)
+               transfer_message_size = 65535;
+       server->transfer_tcp_message_size = (isc_uint16_t) transfer_message_size;
+
        /*
         * Configure the zone manager.
         */
index 2fa495dad3096628452f81f60334301648dec907..15ce3e0e380edfb512aa0ae48199b974d164fce8 100644 (file)
@@ -1273,6 +1273,7 @@ sendstream(xfrout_ctx_t *xfr) {
        dns_rdataset_t *msgrds = NULL;
        dns_compress_t cctx;
        isc_boolean_t cleanup_cctx = ISC_FALSE;
+       isc_boolean_t is_tcp;
 
        int n_rrs;
 
@@ -1280,7 +1281,8 @@ sendstream(xfrout_ctx_t *xfr) {
        isc_buffer_clear(&xfr->txlenbuf);
        isc_buffer_clear(&xfr->txbuf);
 
-       if ((xfr->client->attributes & NS_CLIENTATTR_TCP) == 0) {
+       is_tcp = ISC_TF((xfr->client->attributes & NS_CLIENTATTR_TCP) != 0);
+       if (!is_tcp) {
                /*
                 * In the UDP case, we put the response data directly into
                 * the client message.
@@ -1482,9 +1484,17 @@ sendstream(xfrout_ctx_t *xfr) {
 
                if (! xfr->many_answers)
                        break;
+               /*
+                * At this stage, at least 1 RR has been rendered into
+                * the message. Check if we want to clamp this message
+                * here (TCP only).
+                */
+               if ((isc_buffer_usedlength(&xfr->buf) >=
+                    ns_g_server->transfer_tcp_message_size) && is_tcp)
+                       break;
        }
 
-       if ((xfr->client->attributes & NS_CLIENTATTR_TCP) != 0) {
+       if (is_tcp) {
                CHECK(dns_compress_init(&cctx, -1, xfr->mctx));
                dns_compress_setsensitive(&cctx, ISC_TRUE);
                cleanup_cctx = ISC_TRUE;
index ed7443484efe221c4e915b58719ad486460f43f0..78a3ed12f9c74a2cef1e17f70ea2db1dcd523f18 100644 (file)
@@ -24,6 +24,7 @@
 rm -f dig.out.ns1 dig.out.ns2 dig.out.ns3 dig.out.ns4
 rm -f dig.out.ns5 dig.out.ns6 dig.out.ns7
 rm -f dig.out.soa.ns3
+rm -f dig.out.msgsize
 rm -f axfr.out
 rm -f ns1/slave.db ns2/slave.db
 rm -f ns1/edns-expire.db
@@ -33,6 +34,7 @@ rm -f ns3/master.bk ns3/master.bk.jnl
 rm -f ns4/named.conf ns4/nil.db ns4/root.db
 rm -f ns6/*.db ns6/*.bk ns6/*.jnl
 rm -f ns7/*.db ns7/*.bk ns7/*.jnl
+rm -f ns8/large.db ns8/small.db
 
 rm -f */named.memstats
 rm -f */named.run
diff --git a/bin/tests/system/xfer/ns8/.gitignore b/bin/tests/system/xfer/ns8/.gitignore
new file mode 100644 (file)
index 0000000..3eedd36
--- /dev/null
@@ -0,0 +1,2 @@
+/large.db
+/small.db
diff --git a/bin/tests/system/xfer/ns8/example.db b/bin/tests/system/xfer/ns8/example.db
new file mode 100644 (file)
index 0000000..36990a8
--- /dev/null
@@ -0,0 +1,28 @@
+; Copyright (C) 2004, 2007, 2011, 2012, 2014  Internet Systems Consortium, Inc. ("ISC")
+; Copyright (C) 2000, 2001  Internet Software Consortium.
+;
+; Permission to use, copy, modify, and/or distribute this software for any
+; purpose with or without fee is hereby granted, provided that the above
+; copyright notice and this permission notice appear in all copies.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+$TTL 300       ; 5 minutes
+@                      SOA     mname1. . (
+                               2000062101 ; serial
+                               20         ; refresh (20 seconds)
+                               20         ; retry (20 seconds)
+                               1814400    ; expire (3 weeks)
+                               3600       ; minimum (1 hour)
+                               )
+                       NS      ns
+ns                     A       10.53.0.1
+
+$INCLUDE large.db
+$INCLUDE small.db
diff --git a/bin/tests/system/xfer/ns8/named.conf b/bin/tests/system/xfer/ns8/named.conf
new file mode 100644 (file)
index 0000000..d955bad
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2004, 2007, 2011, 2014, 2015  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+include "../../common/rndc.key";
+
+controls {
+       inet 10.53.0.8 port 9953 allow { any; } keys { rndc_key; };
+};
+
+options {
+       query-source address 10.53.0.8;
+       notify-source 10.53.0.8;
+       transfer-source 10.53.0.8;
+       port 5300;
+       pid-file "named.pid";
+       listen-on { 10.53.0.8; };
+       listen-on-v6 { none; };
+       recursion no;
+       notify no;
+       transfer-message-size 1024;
+};
+
+key key1. {
+       algorithm hmac-md5;
+       secret "1234abcd8765";
+};
+
+acl tzkey {
+       key key1.;
+};
+
+zone "example." {
+       type master;
+       file "example.db";
+       allow-transfer { tzkey; };
+};
index 7df04dd4e409a1ae9abd9f6019a3790aef1dbd3c..c05e226b365161714b27b9363dd4cd23f15986de 100644 (file)
@@ -34,3 +34,6 @@ cp -f ns4/named.conf.base ns4/named.conf
 
 cp ns2/slave.db.in ns2/slave.db
 touch -t 200101010000 ns2/slave.db
+
+$PERL -e 'for ($i=0;$i<4096;$i++){ printf("name%u 259200 A 1.2.3.4\nname%u 259200 TXT \"Hello World %u\"\n", $i, $i, $i);}' > ns8/small.db
+$PERL -e 'printf("large IN TYPE45234 \\# 48000 "); for ($i=0;$i<16*3000;$i++) { printf("%02x", $i % 256); } printf("\n");' > ns8/large.db
index 90d4a9b4d2f422b0822f983ddb14cd57c64c82a3..299b6dde398d6cf8b1e908e9d09830c6c6601c9c 100644 (file)
@@ -380,5 +380,21 @@ test ${expire:-0} -gt 0 -a ${expire:-0} -lt 1814400 || {
     status=1
 }
 
+echo "I:test smaller transfer TCP message size"
+$DIG $DIGOPTS example. @10.53.0.8 axfr -p 5300 \
+       -y key1.:1234abcd8765 > dig.out.msgsize || status=1
+
+bytes=`wc -c < dig.out.msgsize`
+if [ $bytes -ne 459357 ]; then
+       echo "I:failed axfr size check"
+       status=1
+fi
+
+num_messages=`cat ns8/named.run | grep "sending TCP message of" | wc -l`
+if [ $num_messages -le 300 ]; then
+       echo "I:failed transfer message count check"
+       status=1
+fi
+
 echo "I:exit status: $status"
 exit $status
index 393822e06c6c2746638bb89dd42fdf86eef75adc..9133ec60c798b99b12de81ecad7bd1d7f1b08a05 100644 (file)
@@ -4540,6 +4540,7 @@ badresp:1,adberr:0,findfail:0,valfail:0]
     <optional> serial-queries <replaceable>number</replaceable>; </optional>
     <optional> tcp-listen-queue <replaceable>number</replaceable>; </optional>
     <optional> transfer-format <replaceable>( one-answer | many-answers )</replaceable>; </optional>
+    <optional> transfer-message-size  <replaceable>number</replaceable>; </optional>
     <optional> transfers-in  <replaceable>number</replaceable>; </optional>
     <optional> transfers-out <replaceable>number</replaceable>; </optional>
     <optional> transfers-per-ns <replaceable>number</replaceable>; </optional>
@@ -7924,6 +7925,37 @@ avoid-v6-udp-ports {};
              </listitem>
            </varlistentry>
 
+           <varlistentry>
+             <term><command>transfer-message-size</command></term>
+             <listitem>
+               <para>
+                 This is an upper bound on the uncompressed size of DNS
+                 messages used in zone transfers over TCP.  If a message
+                 grows larger than this size, additional messages will be
+                 used to complete the zone transfer.  (Note, however,
+                 that this is a hint, not a hard limit; if a message
+                 contains a single resource record whose RDATA does not
+                 fit within the size limit, a larger message will be
+                 permitted so the record can be transferred.)
+               </para>
+               <para>
+                 Valid values are between 512 and 65535 octets, and any
+                 values outside that range will be adjusted to the nearest
+                 value within it.  The default is <literal>20480</literal>,
+                 which was selected to improve message compression:
+                 most DNS messages of this size will compress to less
+                 than 16536 bytes.  Larger messages cannot be compressed
+                 as effectively, because 16536 is the largest permissible
+                 compression offset pointer in a DNS message.
+               </para>
+               <para>
+                 This option is mainly intended for server testing;
+                 there is rarely any benefit in setting a value other
+                 than the default.
+               </para>
+             </listitem>
+           </varlistentry>
+
            <varlistentry>
              <term><command>transfers-in</command></term>
              <listitem>
index 7564d96d334e3e6b3521b25395dc53eef30027b9..52e3f37b726141e702c37fc1cc00316ff08720fe 100644 (file)
@@ -311,6 +311,7 @@ options {
             dscp <integer> ];
         transfer-source-v6 ( <ipv6_address> | * ) [ port ( <integer> | * )
             ] [ dscp <integer> ];
+        transfer-message-size <integer>;
         transfers-in <integer>;
         transfers-out <integer>;
         transfers-per-ns <integer>;
index d236ed0caef19b182c1fbd4a8040cc99de8808e4..ec3895aebdcf8221f90833310bfc50eb2b6a9b9f 100644 (file)
@@ -1085,6 +1085,7 @@ options_clauses[] = {
        { "tkey-gssapi-credential", &cfg_type_qstring, 0 },
        { "tkey-gssapi-keytab", &cfg_type_qstring, 0 },
        { "tkey-domain", &cfg_type_qstring, 0 },
+       { "transfer-message-size", &cfg_type_uint32, 0 },
        { "transfers-per-ns", &cfg_type_uint32, 0 },
        { "transfers-in", &cfg_type_uint32, 0 },
        { "transfers-out", &cfg_type_uint32, 0 },