1933707f3Ssthen /*
2933707f3Ssthen * util/rtt.c - UDP round trip time estimator for resend timeouts.
3933707f3Ssthen *
4933707f3Ssthen * Copyright (c) 2007, NLnet Labs. All rights reserved.
5933707f3Ssthen *
6933707f3Ssthen * This software is open source.
7933707f3Ssthen *
8933707f3Ssthen * Redistribution and use in source and binary forms, with or without
9933707f3Ssthen * modification, are permitted provided that the following conditions
10933707f3Ssthen * are met:
11933707f3Ssthen *
12933707f3Ssthen * Redistributions of source code must retain the above copyright notice,
13933707f3Ssthen * this list of conditions and the following disclaimer.
14933707f3Ssthen *
15933707f3Ssthen * Redistributions in binary form must reproduce the above copyright notice,
16933707f3Ssthen * this list of conditions and the following disclaimer in the documentation
17933707f3Ssthen * and/or other materials provided with the distribution.
18933707f3Ssthen *
19933707f3Ssthen * Neither the name of the NLNET LABS nor the names of its contributors may
20933707f3Ssthen * be used to endorse or promote products derived from this software without
21933707f3Ssthen * specific prior written permission.
22933707f3Ssthen *
23933707f3Ssthen * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
245d76a658Ssthen * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
255d76a658Ssthen * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
265d76a658Ssthen * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
275d76a658Ssthen * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
285d76a658Ssthen * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
295d76a658Ssthen * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
305d76a658Ssthen * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
315d76a658Ssthen * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
325d76a658Ssthen * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
335d76a658Ssthen * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34933707f3Ssthen */
35933707f3Ssthen
36933707f3Ssthen /**
37933707f3Ssthen * \file
38933707f3Ssthen *
39933707f3Ssthen * This file contains a data type and functions to help estimate good
40933707f3Ssthen * round trip times for UDP resend timeout values.
41933707f3Ssthen */
42933707f3Ssthen #include "config.h"
43933707f3Ssthen #include "util/rtt.h"
447bc20e6dSsthen #include "iterator/iterator.h"
45933707f3Ssthen
46b2cdf21fSsthen /* overwritten by config: infra_cache_min_rtt: */
47b2cdf21fSsthen int RTT_MIN_TIMEOUT = 50;
48*1996a427Ssthen /* overwritten by config: infra_cache_max_rtt: */
49*1996a427Ssthen int RTT_MAX_TIMEOUT = 120000;
50*1996a427Ssthen
51933707f3Ssthen /** calculate RTO from rtt information */
52933707f3Ssthen static int
calc_rto(const struct rtt_info * rtt)53933707f3Ssthen calc_rto(const struct rtt_info* rtt)
54933707f3Ssthen {
55933707f3Ssthen /* From Stevens, Unix Network Programming, Vol1, 3rd ed., p.598 */
56933707f3Ssthen int rto = rtt->srtt + 4*rtt->rttvar;
57933707f3Ssthen if(rto < RTT_MIN_TIMEOUT)
58933707f3Ssthen rto = RTT_MIN_TIMEOUT;
59933707f3Ssthen if(rto > RTT_MAX_TIMEOUT)
60933707f3Ssthen rto = RTT_MAX_TIMEOUT;
61933707f3Ssthen return rto;
62933707f3Ssthen }
63933707f3Ssthen
64933707f3Ssthen void
rtt_init(struct rtt_info * rtt)65933707f3Ssthen rtt_init(struct rtt_info* rtt)
66933707f3Ssthen {
67933707f3Ssthen rtt->srtt = 0;
687bc20e6dSsthen rtt->rttvar = UNKNOWN_SERVER_NICENESS/4;
69933707f3Ssthen rtt->rto = calc_rto(rtt);
70933707f3Ssthen /* default value from the book is 0 + 4*0.75 = 3 seconds */
71933707f3Ssthen /* first RTO is 0 + 4*0.094 = 0.376 seconds */
72933707f3Ssthen }
73933707f3Ssthen
74933707f3Ssthen int
rtt_timeout(const struct rtt_info * rtt)75933707f3Ssthen rtt_timeout(const struct rtt_info* rtt)
76933707f3Ssthen {
77933707f3Ssthen return rtt->rto;
78933707f3Ssthen }
79933707f3Ssthen
80933707f3Ssthen int
rtt_unclamped(const struct rtt_info * rtt)81933707f3Ssthen rtt_unclamped(const struct rtt_info* rtt)
82933707f3Ssthen {
83933707f3Ssthen if(calc_rto(rtt) != rtt->rto) {
84933707f3Ssthen /* timeout fallback has happened */
85933707f3Ssthen return rtt->rto;
86933707f3Ssthen }
87933707f3Ssthen /* return unclamped value */
88933707f3Ssthen return rtt->srtt + 4*rtt->rttvar;
89933707f3Ssthen }
90933707f3Ssthen
91933707f3Ssthen void
rtt_update(struct rtt_info * rtt,int ms)92933707f3Ssthen rtt_update(struct rtt_info* rtt, int ms)
93933707f3Ssthen {
94933707f3Ssthen int delta = ms - rtt->srtt;
95933707f3Ssthen rtt->srtt += delta / 8; /* g = 1/8 */
96933707f3Ssthen if(delta < 0)
97933707f3Ssthen delta = -delta; /* |delta| */
98933707f3Ssthen rtt->rttvar += (delta - rtt->rttvar) / 4; /* h = 1/4 */
99933707f3Ssthen rtt->rto = calc_rto(rtt);
100933707f3Ssthen }
101933707f3Ssthen
102933707f3Ssthen void
rtt_lost(struct rtt_info * rtt,int orig)103933707f3Ssthen rtt_lost(struct rtt_info* rtt, int orig)
104933707f3Ssthen {
105933707f3Ssthen /* exponential backoff */
106933707f3Ssthen
107933707f3Ssthen /* if a query succeeded and put down the rto meanwhile, ignore this */
108933707f3Ssthen if(rtt->rto < orig)
109933707f3Ssthen return;
110933707f3Ssthen
111933707f3Ssthen /* the original rto is doubled, not the current one to make sure
112933707f3Ssthen * that the values in the cache are not increased by lots of
113933707f3Ssthen * queries simultaneously as they time out at the same time */
114933707f3Ssthen orig *= 2;
115933707f3Ssthen if(rtt->rto <= orig) {
116933707f3Ssthen rtt->rto = orig;
117933707f3Ssthen if(rtt->rto > RTT_MAX_TIMEOUT)
118933707f3Ssthen rtt->rto = RTT_MAX_TIMEOUT;
119933707f3Ssthen }
120933707f3Ssthen }
121933707f3Ssthen
rtt_notimeout(const struct rtt_info * rtt)122933707f3Ssthen int rtt_notimeout(const struct rtt_info* rtt)
123933707f3Ssthen {
124933707f3Ssthen return calc_rto(rtt);
125933707f3Ssthen }
126