mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-20 23:00:56 -05:00
failover to next server.
git-svn-id: file:///svn/unbound/trunk@691 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
f12875c910
commit
907ab3d99a
8 changed files with 58 additions and 9 deletions
|
|
@ -17,6 +17,7 @@
|
||||||
- fixup removal of nonsecure items from the additional.
|
- fixup removal of nonsecure items from the additional.
|
||||||
- reduced timeout values to more realistic, 376 msec (262 msec has
|
- reduced timeout values to more realistic, 376 msec (262 msec has
|
||||||
90% of roundtrip times, 512 msec has 99% of roundtrip times.)
|
90% of roundtrip times, 512 msec has 99% of roundtrip times.)
|
||||||
|
- server selection failover to next server after timeout (376 msec).
|
||||||
|
|
||||||
16 October 2007: Wouter
|
16 October 2007: Wouter
|
||||||
- no malloc in log_hex.
|
- no malloc in log_hex.
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,7 @@ delegpt_add_addr(struct delegpt* dp, struct region* region,
|
||||||
dp->usable_list = a;
|
dp->usable_list = a;
|
||||||
memcpy(&a->addr, addr, addrlen);
|
memcpy(&a->addr, addr, addrlen);
|
||||||
a->addrlen = addrlen;
|
a->addrlen = addrlen;
|
||||||
|
a->attempts = 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,8 @@ struct delegpt_addr {
|
||||||
struct sockaddr_storage addr;
|
struct sockaddr_storage addr;
|
||||||
/** length of addr */
|
/** length of addr */
|
||||||
socklen_t addrlen;
|
socklen_t addrlen;
|
||||||
|
/** number of attempts for this addr */
|
||||||
|
int attempts;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -214,6 +214,8 @@ iter_server_selection(struct iter_env* iter_env,
|
||||||
return NULL;
|
return NULL;
|
||||||
if(num == 1) {
|
if(num == 1) {
|
||||||
a = dp->result_list;
|
a = dp->result_list;
|
||||||
|
if(++a->attempts < OUTBOUND_MSG_RETRY)
|
||||||
|
return a;
|
||||||
dp->result_list = a->next_result;
|
dp->result_list = a->next_result;
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
@ -231,6 +233,8 @@ iter_server_selection(struct iter_env* iter_env,
|
||||||
}
|
}
|
||||||
if(!a) /* robustness */
|
if(!a) /* robustness */
|
||||||
return NULL;
|
return NULL;
|
||||||
|
if(++a->attempts < OUTBOUND_MSG_RETRY)
|
||||||
|
return a;
|
||||||
/* remove it from the delegation point result list */
|
/* remove it from the delegation point result list */
|
||||||
if(prev)
|
if(prev)
|
||||||
prev->next_result = a->next_result;
|
prev->next_result = a->next_result;
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,8 @@ struct iter_prep_list;
|
||||||
* Equals RTT_MAX_TIMEOUT
|
* Equals RTT_MAX_TIMEOUT
|
||||||
*/
|
*/
|
||||||
#define USEFUL_SERVER_TOP_TIMEOUT 120000
|
#define USEFUL_SERVER_TOP_TIMEOUT 120000
|
||||||
|
/** number of retries on outgoing queries */
|
||||||
|
#define OUTBOUND_MSG_RETRY 4
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Global state for the iterator.
|
* Global state for the iterator.
|
||||||
|
|
|
||||||
22
services/cache/infra.c
vendored
22
services/cache/infra.c
vendored
|
|
@ -401,6 +401,23 @@ infra_set_lame(struct infra_cache* infra,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
infra_update_tcp_works(struct infra_cache* infra,
|
||||||
|
struct sockaddr_storage* addr, socklen_t addrlen)
|
||||||
|
{
|
||||||
|
struct lruhash_entry* e = infra_lookup_host_nottl(infra, addr,
|
||||||
|
addrlen, 1);
|
||||||
|
struct infra_host_data* data;
|
||||||
|
if(!e)
|
||||||
|
return; /* doesn't exist */
|
||||||
|
data = (struct infra_host_data*)e->data;
|
||||||
|
if(data->rtt.rto >= RTT_MAX_TIMEOUT)
|
||||||
|
/* do not disqualify this server altogether, it is better
|
||||||
|
* than nothing */
|
||||||
|
data->rtt.rto = RTT_MAX_TIMEOUT-1;
|
||||||
|
lock_rw_unlock(&e->lock);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
infra_rtt_update(struct infra_cache* infra,
|
infra_rtt_update(struct infra_cache* infra,
|
||||||
struct sockaddr_storage* addr, socklen_t addrlen,
|
struct sockaddr_storage* addr, socklen_t addrlen,
|
||||||
|
|
@ -410,6 +427,7 @@ infra_rtt_update(struct infra_cache* infra,
|
||||||
addrlen, 1);
|
addrlen, 1);
|
||||||
struct infra_host_data* data;
|
struct infra_host_data* data;
|
||||||
int needtoinsert = 0;
|
int needtoinsert = 0;
|
||||||
|
int rto = 1;
|
||||||
if(!e) {
|
if(!e) {
|
||||||
if(!(e = new_host_entry(infra, addr, addrlen, timenow)))
|
if(!(e = new_host_entry(infra, addr, addrlen, timenow)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -421,11 +439,13 @@ infra_rtt_update(struct infra_cache* infra,
|
||||||
if(roundtrip == -1)
|
if(roundtrip == -1)
|
||||||
rtt_lost(&data->rtt);
|
rtt_lost(&data->rtt);
|
||||||
else rtt_update(&data->rtt, roundtrip);
|
else rtt_update(&data->rtt, roundtrip);
|
||||||
|
if(data->rtt.rto > 0)
|
||||||
|
rto = data->rtt.rto;
|
||||||
|
|
||||||
if(needtoinsert)
|
if(needtoinsert)
|
||||||
slabhash_insert(infra->hosts, e->hash, e, e->data, NULL);
|
slabhash_insert(infra->hosts, e->hash, e, e->data, NULL);
|
||||||
else { lock_rw_unlock(&e->lock); }
|
else { lock_rw_unlock(&e->lock); }
|
||||||
return 1;
|
return rto;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
|
||||||
11
services/cache/infra.h
vendored
11
services/cache/infra.h
vendored
|
|
@ -199,12 +199,21 @@ int infra_set_lame(struct infra_cache* infra,
|
||||||
* @param roundtrip: estimate of roundtrip time in milliseconds or -1 for
|
* @param roundtrip: estimate of roundtrip time in milliseconds or -1 for
|
||||||
* timeout.
|
* timeout.
|
||||||
* @param timenow: what time it is now.
|
* @param timenow: what time it is now.
|
||||||
* @return: 0 on error.
|
* @return: 0 on error. new rto otherwise.
|
||||||
*/
|
*/
|
||||||
int infra_rtt_update(struct infra_cache* infra,
|
int infra_rtt_update(struct infra_cache* infra,
|
||||||
struct sockaddr_storage* addr, socklen_t addrlen,
|
struct sockaddr_storage* addr, socklen_t addrlen,
|
||||||
int roundtrip, time_t timenow);
|
int roundtrip, time_t timenow);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update information for the host, store that a TCP transaction works.
|
||||||
|
* @param infra: infrastructure cache.
|
||||||
|
* @param addr: host address.
|
||||||
|
* @param addrlen: length of addr.
|
||||||
|
*/
|
||||||
|
void infra_update_tcp_works(struct infra_cache* infra,
|
||||||
|
struct sockaddr_storage* addr, socklen_t addrlen);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update edns information for the host.
|
* Update edns information for the host.
|
||||||
* @param infra: infrastructure cache.
|
* @param infra: infrastructure cache.
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@
|
||||||
/** number of times to retry making a random ID that is unique. */
|
/** number of times to retry making a random ID that is unique. */
|
||||||
#define MAX_ID_RETRY 1000
|
#define MAX_ID_RETRY 1000
|
||||||
/** number of retries on outgoing UDP queries */
|
/** number of retries on outgoing UDP queries */
|
||||||
#define OUTBOUND_UDP_RETRY 4
|
#define OUTBOUND_UDP_RETRY 1
|
||||||
|
|
||||||
/** initiate TCP transaction for serviced query */
|
/** initiate TCP transaction for serviced query */
|
||||||
static void serviced_tcp_initiate(struct outside_network* outnet,
|
static void serviced_tcp_initiate(struct outside_network* outnet,
|
||||||
|
|
@ -1021,6 +1021,9 @@ serviced_tcp_callback(struct comm_point* c, void* arg, int error,
|
||||||
sq->pending = NULL; /* removed after this callback */
|
sq->pending = NULL; /* removed after this callback */
|
||||||
if(error != NETEVENT_NOERROR && verbosity >= VERB_DETAIL)
|
if(error != NETEVENT_NOERROR && verbosity >= VERB_DETAIL)
|
||||||
log_addr("tcp error for address", &sq->addr, sq->addrlen);
|
log_addr("tcp error for address", &sq->addr, sq->addrlen);
|
||||||
|
if(error==NETEVENT_NOERROR)
|
||||||
|
infra_update_tcp_works(sq->outnet->infra, &sq->addr,
|
||||||
|
sq->addrlen);
|
||||||
if(error==NETEVENT_NOERROR && LDNS_RCODE_WIRE(ldns_buffer_begin(
|
if(error==NETEVENT_NOERROR && LDNS_RCODE_WIRE(ldns_buffer_begin(
|
||||||
c->buffer)) == LDNS_RCODE_FORMERR &&
|
c->buffer)) == LDNS_RCODE_FORMERR &&
|
||||||
sq->status == serviced_query_TCP_EDNS) {
|
sq->status == serviced_query_TCP_EDNS) {
|
||||||
|
|
@ -1066,6 +1069,7 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error,
|
||||||
struct serviced_query* sq = (struct serviced_query*)arg;
|
struct serviced_query* sq = (struct serviced_query*)arg;
|
||||||
struct outside_network* outnet = sq->outnet;
|
struct outside_network* outnet = sq->outnet;
|
||||||
struct timeval now;
|
struct timeval now;
|
||||||
|
int fallback_tcp = 0;
|
||||||
if(gettimeofday(&now, NULL) < 0) {
|
if(gettimeofday(&now, NULL) < 0) {
|
||||||
log_err("gettimeofday: %s", strerror(errno));
|
log_err("gettimeofday: %s", strerror(errno));
|
||||||
/* this option does not need current time */
|
/* this option does not need current time */
|
||||||
|
|
@ -1073,9 +1077,10 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error,
|
||||||
}
|
}
|
||||||
sq->pending = NULL; /* removed after callback */
|
sq->pending = NULL; /* removed after callback */
|
||||||
if(error == NETEVENT_TIMEOUT) {
|
if(error == NETEVENT_TIMEOUT) {
|
||||||
|
int rto = 0;
|
||||||
sq->retry++;
|
sq->retry++;
|
||||||
if(!infra_rtt_update(outnet->infra, &sq->addr, sq->addrlen,
|
if(!(rto=infra_rtt_update(outnet->infra, &sq->addr, sq->addrlen,
|
||||||
-1, (time_t)now.tv_sec))
|
-1, (time_t)now.tv_sec)))
|
||||||
log_err("out of memory in UDP exponential backoff");
|
log_err("out of memory in UDP exponential backoff");
|
||||||
if(sq->retry < OUTBOUND_UDP_RETRY) {
|
if(sq->retry < OUTBOUND_UDP_RETRY) {
|
||||||
log_name_addr(VERB_ALGO, "retry query", sq->qbuf+10,
|
log_name_addr(VERB_ALGO, "retry query", sq->qbuf+10,
|
||||||
|
|
@ -1085,8 +1090,13 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error,
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
error = NETEVENT_TIMEOUT;
|
if(rto >= RTT_MAX_TIMEOUT) {
|
||||||
/* UDP does not work, fallback to TCP below */
|
fallback_tcp = 1;
|
||||||
|
/* UDP does not work, fallback to TCP below */
|
||||||
|
} else {
|
||||||
|
serviced_callbacks(sq, NETEVENT_TIMEOUT, c, rep);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(error == NETEVENT_NOERROR && sq->status == serviced_query_UDP_EDNS
|
if(error == NETEVENT_NOERROR && sq->status == serviced_query_UDP_EDNS
|
||||||
&& LDNS_RCODE_WIRE(ldns_buffer_begin(c->buffer))
|
&& LDNS_RCODE_WIRE(ldns_buffer_begin(c->buffer))
|
||||||
|
|
@ -1103,8 +1113,8 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error,
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if(error != NETEVENT_NOERROR ||
|
if(LDNS_TC_WIRE(ldns_buffer_begin(c->buffer)) ||
|
||||||
LDNS_TC_WIRE(ldns_buffer_begin(c->buffer))) {
|
(error != NETEVENT_NOERROR && fallback_tcp) ) {
|
||||||
/* fallback to TCP */
|
/* fallback to TCP */
|
||||||
/* this discards partial UDP contents */
|
/* this discards partial UDP contents */
|
||||||
if(sq->status == serviced_query_UDP_EDNS)
|
if(sq->status == serviced_query_UDP_EDNS)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue