xref: /netbsd-src/external/bsd/unbound/dist/util/rtt.c (revision 7a540f2bd4f5b968566c2607d6462c7f2fb452cf)
13b6c3722Schristos /*
23b6c3722Schristos  * util/rtt.c - UDP round trip time estimator for resend timeouts.
33b6c3722Schristos  *
43b6c3722Schristos  * Copyright (c) 2007, NLnet Labs. All rights reserved.
53b6c3722Schristos  *
63b6c3722Schristos  * This software is open source.
73b6c3722Schristos  *
83b6c3722Schristos  * Redistribution and use in source and binary forms, with or without
93b6c3722Schristos  * modification, are permitted provided that the following conditions
103b6c3722Schristos  * are met:
113b6c3722Schristos  *
123b6c3722Schristos  * Redistributions of source code must retain the above copyright notice,
133b6c3722Schristos  * this list of conditions and the following disclaimer.
143b6c3722Schristos  *
153b6c3722Schristos  * Redistributions in binary form must reproduce the above copyright notice,
163b6c3722Schristos  * this list of conditions and the following disclaimer in the documentation
173b6c3722Schristos  * and/or other materials provided with the distribution.
183b6c3722Schristos  *
193b6c3722Schristos  * Neither the name of the NLNET LABS nor the names of its contributors may
203b6c3722Schristos  * be used to endorse or promote products derived from this software without
213b6c3722Schristos  * specific prior written permission.
223b6c3722Schristos  *
233b6c3722Schristos  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
243b6c3722Schristos  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
253b6c3722Schristos  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
263b6c3722Schristos  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
273b6c3722Schristos  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
283b6c3722Schristos  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
293b6c3722Schristos  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
303b6c3722Schristos  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
313b6c3722Schristos  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
323b6c3722Schristos  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
333b6c3722Schristos  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
343b6c3722Schristos  */
353b6c3722Schristos 
363b6c3722Schristos /**
373b6c3722Schristos  * \file
383b6c3722Schristos  *
393b6c3722Schristos  * This file contains a data type and functions to help estimate good
403b6c3722Schristos  * round trip times for UDP resend timeout values.
413b6c3722Schristos  */
423b6c3722Schristos #include "config.h"
433b6c3722Schristos #include "util/rtt.h"
44f42d8de7Schristos #include "iterator/iterator.h"
453b6c3722Schristos 
463b6c3722Schristos /* overwritten by config: infra_cache_min_rtt: */
473b6c3722Schristos int RTT_MIN_TIMEOUT = 50;
48*7a540f2bSchristos /* overwritten by config: infra_cache_max_rtt: */
49*7a540f2bSchristos int RTT_MAX_TIMEOUT = 120000;
50*7a540f2bSchristos 
513b6c3722Schristos /** calculate RTO from rtt information */
523b6c3722Schristos static int
calc_rto(const struct rtt_info * rtt)533b6c3722Schristos calc_rto(const struct rtt_info* rtt)
543b6c3722Schristos {
553b6c3722Schristos 	/* From Stevens, Unix Network Programming, Vol1, 3rd ed., p.598 */
563b6c3722Schristos 	int rto = rtt->srtt + 4*rtt->rttvar;
573b6c3722Schristos 	if(rto < RTT_MIN_TIMEOUT)
583b6c3722Schristos 		rto = RTT_MIN_TIMEOUT;
593b6c3722Schristos 	if(rto > RTT_MAX_TIMEOUT)
603b6c3722Schristos 		rto = RTT_MAX_TIMEOUT;
613b6c3722Schristos 	return rto;
623b6c3722Schristos }
633b6c3722Schristos 
643b6c3722Schristos void
rtt_init(struct rtt_info * rtt)653b6c3722Schristos rtt_init(struct rtt_info* rtt)
663b6c3722Schristos {
673b6c3722Schristos 	rtt->srtt = 0;
68f42d8de7Schristos 	rtt->rttvar = UNKNOWN_SERVER_NICENESS/4;
693b6c3722Schristos 	rtt->rto = calc_rto(rtt);
703b6c3722Schristos 	/* default value from the book is 0 + 4*0.75 = 3 seconds */
713b6c3722Schristos 	/* first RTO is 0 + 4*0.094 = 0.376 seconds */
723b6c3722Schristos }
733b6c3722Schristos 
743b6c3722Schristos int
rtt_timeout(const struct rtt_info * rtt)753b6c3722Schristos rtt_timeout(const struct rtt_info* rtt)
763b6c3722Schristos {
773b6c3722Schristos 	return rtt->rto;
783b6c3722Schristos }
793b6c3722Schristos 
803b6c3722Schristos int
rtt_unclamped(const struct rtt_info * rtt)813b6c3722Schristos rtt_unclamped(const struct rtt_info* rtt)
823b6c3722Schristos {
833b6c3722Schristos 	if(calc_rto(rtt) != rtt->rto) {
843b6c3722Schristos 		/* timeout fallback has happened */
853b6c3722Schristos 		return rtt->rto;
863b6c3722Schristos 	}
873b6c3722Schristos 	/* return unclamped value */
883b6c3722Schristos 	return rtt->srtt + 4*rtt->rttvar;
893b6c3722Schristos }
903b6c3722Schristos 
913b6c3722Schristos void
rtt_update(struct rtt_info * rtt,int ms)923b6c3722Schristos rtt_update(struct rtt_info* rtt, int ms)
933b6c3722Schristos {
943b6c3722Schristos 	int delta = ms - rtt->srtt;
953b6c3722Schristos 	rtt->srtt += delta / 8; /* g = 1/8 */
963b6c3722Schristos 	if(delta < 0)
973b6c3722Schristos 		delta = -delta; /* |delta| */
983b6c3722Schristos 	rtt->rttvar += (delta - rtt->rttvar) / 4; /* h = 1/4 */
993b6c3722Schristos 	rtt->rto = calc_rto(rtt);
1003b6c3722Schristos }
1013b6c3722Schristos 
1023b6c3722Schristos void
rtt_lost(struct rtt_info * rtt,int orig)1033b6c3722Schristos rtt_lost(struct rtt_info* rtt, int orig)
1043b6c3722Schristos {
1053b6c3722Schristos 	/* exponential backoff */
1063b6c3722Schristos 
1073b6c3722Schristos 	/* if a query succeeded and put down the rto meanwhile, ignore this */
1083b6c3722Schristos 	if(rtt->rto < orig)
1093b6c3722Schristos 		return;
1103b6c3722Schristos 
1113b6c3722Schristos 	/* the original rto is doubled, not the current one to make sure
1123b6c3722Schristos 	 * that the values in the cache are not increased by lots of
1133b6c3722Schristos 	 * queries simultaneously as they time out at the same time */
1143b6c3722Schristos 	orig *= 2;
1153b6c3722Schristos 	if(rtt->rto <= orig) {
1163b6c3722Schristos 		rtt->rto = orig;
1173b6c3722Schristos 		if(rtt->rto > RTT_MAX_TIMEOUT)
1183b6c3722Schristos 			rtt->rto = RTT_MAX_TIMEOUT;
1193b6c3722Schristos 	}
1203b6c3722Schristos }
1213b6c3722Schristos 
rtt_notimeout(const struct rtt_info * rtt)1223b6c3722Schristos int rtt_notimeout(const struct rtt_info* rtt)
1233b6c3722Schristos {
1243b6c3722Schristos 	return calc_rto(rtt);
1253b6c3722Schristos }
126