1238106Sdes/*
2238106Sdes * util/rtt.c - UDP round trip time estimator for resend timeouts.
3238106Sdes *
4238106Sdes * Copyright (c) 2007, NLnet Labs. All rights reserved.
5238106Sdes *
6238106Sdes * This software is open source.
7238106Sdes *
8238106Sdes * Redistribution and use in source and binary forms, with or without
9238106Sdes * modification, are permitted provided that the following conditions
10238106Sdes * are met:
11238106Sdes *
12238106Sdes * Redistributions of source code must retain the above copyright notice,
13238106Sdes * this list of conditions and the following disclaimer.
14238106Sdes *
15238106Sdes * Redistributions in binary form must reproduce the above copyright notice,
16238106Sdes * this list of conditions and the following disclaimer in the documentation
17238106Sdes * and/or other materials provided with the distribution.
18238106Sdes *
19238106Sdes * Neither the name of the NLNET LABS nor the names of its contributors may
20238106Sdes * be used to endorse or promote products derived from this software without
21238106Sdes * specific prior written permission.
22238106Sdes *
23238106Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24266114Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25266114Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26266114Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27266114Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28266114Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29266114Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30266114Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31266114Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32266114Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33266114Sdes * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34238106Sdes */
35238106Sdes
36238106Sdes/**
37238106Sdes * \file
38238106Sdes *
39238106Sdes * This file contains a data type and functions to help estimate good
40238106Sdes * round trip times for UDP resend timeout values.
41238106Sdes */
42238106Sdes#include "config.h"
43238106Sdes#include "util/rtt.h"
44356345Scy#include "iterator/iterator.h"
45238106Sdes
46282089Sdes/* overwritten by config: infra_cache_min_rtt: */
47282089Sdesint RTT_MIN_TIMEOUT = 50;
48238106Sdes/** calculate RTO from rtt information */
49238106Sdesstatic int
50238106Sdescalc_rto(const struct rtt_info* rtt)
51238106Sdes{
52238106Sdes	/* From Stevens, Unix Network Programming, Vol1, 3rd ed., p.598 */
53238106Sdes	int rto = rtt->srtt + 4*rtt->rttvar;
54238106Sdes	if(rto < RTT_MIN_TIMEOUT)
55238106Sdes		rto = RTT_MIN_TIMEOUT;
56238106Sdes	if(rto > RTT_MAX_TIMEOUT)
57238106Sdes		rto = RTT_MAX_TIMEOUT;
58238106Sdes	return rto;
59238106Sdes}
60238106Sdes
61238106Sdesvoid
62238106Sdesrtt_init(struct rtt_info* rtt)
63238106Sdes{
64238106Sdes	rtt->srtt = 0;
65356345Scy	rtt->rttvar = UNKNOWN_SERVER_NICENESS/4;
66238106Sdes	rtt->rto = calc_rto(rtt);
67238106Sdes	/* default value from the book is 0 + 4*0.75 = 3 seconds */
68238106Sdes	/* first RTO is 0 + 4*0.094 = 0.376 seconds */
69238106Sdes}
70238106Sdes
71238106Sdesint
72238106Sdesrtt_timeout(const struct rtt_info* rtt)
73238106Sdes{
74238106Sdes	return rtt->rto;
75238106Sdes}
76238106Sdes
77238106Sdesint
78238106Sdesrtt_unclamped(const struct rtt_info* rtt)
79238106Sdes{
80238106Sdes	if(calc_rto(rtt) != rtt->rto) {
81238106Sdes		/* timeout fallback has happened */
82238106Sdes		return rtt->rto;
83238106Sdes	}
84238106Sdes	/* return unclamped value */
85238106Sdes	return rtt->srtt + 4*rtt->rttvar;
86238106Sdes}
87238106Sdes
88238106Sdesvoid
89238106Sdesrtt_update(struct rtt_info* rtt, int ms)
90238106Sdes{
91238106Sdes	int delta = ms - rtt->srtt;
92238106Sdes	rtt->srtt += delta / 8; /* g = 1/8 */
93238106Sdes	if(delta < 0)
94238106Sdes		delta = -delta; /* |delta| */
95238106Sdes	rtt->rttvar += (delta - rtt->rttvar) / 4; /* h = 1/4 */
96238106Sdes	rtt->rto = calc_rto(rtt);
97238106Sdes}
98238106Sdes
99238106Sdesvoid
100238106Sdesrtt_lost(struct rtt_info* rtt, int orig)
101238106Sdes{
102238106Sdes	/* exponential backoff */
103238106Sdes
104238106Sdes	/* if a query succeeded and put down the rto meanwhile, ignore this */
105238106Sdes	if(rtt->rto < orig)
106238106Sdes		return;
107238106Sdes
108238106Sdes	/* the original rto is doubled, not the current one to make sure
109238106Sdes	 * that the values in the cache are not increased by lots of
110238106Sdes	 * queries simultaneously as they time out at the same time */
111238106Sdes	orig *= 2;
112238106Sdes	if(rtt->rto <= orig) {
113238106Sdes		rtt->rto = orig;
114238106Sdes		if(rtt->rto > RTT_MAX_TIMEOUT)
115238106Sdes			rtt->rto = RTT_MAX_TIMEOUT;
116238106Sdes	}
117238106Sdes}
118238106Sdes
119238106Sdesint rtt_notimeout(const struct rtt_info* rtt)
120238106Sdes{
121238106Sdes	return calc_rto(rtt);
122238106Sdes}
123