char buf[257];
struct delegpt_addr* a;
int lame, dlame, rlame, rtt, edns_vs, to, lost;
+ int entry_ttl, clean_rtt, backoff;
uint8_t edns_lame_known;
for(a = dp->target_list; a; a = a->next_target) {
addr_to_str(&a->addr, a->addrlen, buf, sizeof(buf));
return;
}
/* lookup in infra cache */
+ entry_ttl = infra_get_host_rto(worker->env.infra_cache,
+ &a->addr, a->addrlen, &clean_rtt, &rtt, &backoff,
+ *worker->env.now);
+ if(entry_ttl == -1) {
+ if(!ssl_printf(ssl, "not in infra cache.\n"))
+ return;
+ continue; /* skip stuff not in infra cache */
+ } else if(entry_ttl == -2) {
+ if(!ssl_printf(ssl, "not in infra cache "
+ "(backoff %d).\n", backoff))
+ return;
+ continue; /* skip stuff not in infra cache */
+ }
+
/* uses type_A because most often looked up, but other
* lameness won't be reported then */
if(!infra_get_lame_rtt(worker->env.infra_cache,
return;
continue; /* skip stuff not in infra cache */
}
- if(!ssl_printf(ssl, "%s%s%s%srtt %d msec, %d lost. ",
+ if(!ssl_printf(ssl, "%s%s%s%srtt %d msec, %d lost, ttl %d",
lame?"LAME ":"", dlame?"NoDNSSEC ":"",
a->lame?"AddrWasParentSide ":"",
- rlame?"NoAuthButRecursive ":"", rtt, lost))
+ rlame?"NoAuthButRecursive ":"", rtt, lost, entry_ttl))
return;
+ if(rtt != clean_rtt && clean_rtt != 376 /* unknown */) {
+ if(!ssl_printf(ssl, ", ping %d", clean_rtt))
+ return;
+ }
+ if(backoff != INFRA_BACKOFF_INITIAL) {
+ if(!ssl_printf(ssl, ", backoff %d", backoff))
+ return;
+ }
if(infra_host(worker->env.infra_cache, &a->addr, a->addrlen,
*worker->env.now, &edns_vs, &edns_lame_known, &to)) {
if(edns_vs == -1) {
- if(!ssl_printf(ssl, "noEDNS%s.",
- edns_lame_known?" probed":""))
+ if(!ssl_printf(ssl, ", noEDNS%s.",
+ edns_lame_known?" probed":" assumed"))
return;
} else {
- if(!ssl_printf(ssl, "EDNS %d%s.",
- edns_vs, edns_lame_known?" probed":""))
+ if(!ssl_printf(ssl, ", EDNS %d%s.", edns_vs,
+ edns_lame_known?" probed":" assumed"))
return;
}
}
+21 October 2010: Wouter
+ - Fix bug where fallback_tcp causes wrong roundtrip and edns
+ observation to be noted in cache. Fix bug where EDNSprobe halted
+ exponential backoff if EDNS status unknown.
+ - new unresponsive host method, exponentially increasing block backoff.
+ - iana portlist updated.
+
20 October 2010: Wouter
- interface automatic works for some people with ip6 disabled.
Therefore the error check is removed, so they can use the option.
a->lame?" ADDR_LAME":"");
if(lame)
return -1; /* server is lame */
- else if(rtt >= USEFUL_SERVER_TOP_TIMEOUT &&
- lost >= USEFUL_SERVER_MAX_LOST) {
+ else if(rtt >= USEFUL_SERVER_TOP_TIMEOUT)
/* server is unresponsive */
return USEFUL_SERVER_TOP_TIMEOUT;
- }
/* select remainder from worst to best */
else if(reclame)
return rtt+USEFUL_SERVER_TOP_TIMEOUT*3; /* nonpref */
return rtt+USEFUL_SERVER_TOP_TIMEOUT*2; /* nonpref */
else if(a->lame)
return rtt+USEFUL_SERVER_TOP_TIMEOUT+1; /* nonpref */
- else if(rtt >= USEFUL_SERVER_TOP_TIMEOUT) /* not blacklisted*/
- return USEFUL_SERVER_TOP_TIMEOUT+1;
else return rtt;
}
/* no server information present */
* Chosen so that the UNKNOWN_SERVER_NICENESS falls within the band of a
* fast server, this causes server exploration as a side benefit. msec. */
#define RTT_BAND 400
+/** Start value for blacklisting a host, 2*USEFUL_SERVER_TOP_TIMEOUT in sec */
+#define INFRA_BACKOFF_INITIAL 240
/**
* Global state for the iterator.
return data;
}
-/** init the host elements (not lame elems) */
+/** init the host elements (not lame elems, not backoff) */
static void
host_entry_init(struct infra_cache* infra, struct lruhash_entry* e,
uint32_t timenow)
key->addrlen = addrlen;
memcpy(&key->addr, addr, addrlen);
data->lameness = NULL;
+ data->backoff = INFRA_BACKOFF_INITIAL;
host_entry_init(infra, &key->entry, tm);
return &key->entry;
}
/* use existing entry */
data = (struct infra_host_data*)e->data;
*to = rtt_timeout(&data->rtt);
- if(*to >= USEFUL_SERVER_TOP_TIMEOUT &&
- data->num_timeouts < USEFUL_SERVER_MAX_LOST)
- /* use smaller timeout, backoff does not work
- * The server seems to still reply but sporadically.
- * Perhaps it has rate-limited the traffic, or it
- * drops particular queries (AAAA). ignore timeouts,
- * and use the jostle timeout for rtt estimate. */
- *to = (int)infra->jostle;
*edns_vs = data->edns_version;
*edns_lame_known = data->edns_lame_known;
lock_rw_unlock(&e->lock);
/* have an entry, update the rtt */
data = (struct infra_host_data*)e->data;
if(roundtrip == -1) {
+ int o = rtt_timeout(&data->rtt);
rtt_lost(&data->rtt, orig_rtt);
+ if(rtt_timeout(&data->rtt) >= USEFUL_SERVER_TOP_TIMEOUT
+ && o < USEFUL_SERVER_TOP_TIMEOUT) {
+ /* backoff the blacklisted timeout */
+ log_addr(VERB_ALGO, "backoff for", addr, addrlen);
+ data->backoff *= 2;
+ if(data->backoff >= 24*3600)
+ data->backoff = 24*3600;
+ verbose(VERB_ALGO, "backoff to %d", data->backoff);
+ /* increase the infra item TTL */
+ data->ttl = timenow + data->backoff;
+ }
+
if(data->num_timeouts<255)
data->num_timeouts++;
} else {
rtt_update(&data->rtt, roundtrip);
+ /* un-backoff the element */
+ if(data->backoff > (uint32_t)infra->host_ttl*2)
+ data->backoff = (uint32_t)infra->host_ttl*2;
+ else data->backoff = INFRA_BACKOFF_INITIAL;
+
data->num_timeouts = 0;
}
if(data->rtt.rto > 0)
return rto;
}
+int infra_get_host_rto(struct infra_cache* infra,
+ struct sockaddr_storage* addr, socklen_t addrlen,
+ int* rtt, int* rto, int* backoff, uint32_t timenow)
+{
+ struct lruhash_entry* e = infra_lookup_host_nottl(infra, addr,
+ addrlen, 0);
+ struct infra_host_data* data;
+ int ttl = -2;
+ if(!e) return -1;
+ data = (struct infra_host_data*)e->data;
+ *backoff = (int)data->backoff;
+ if(data->ttl >= timenow) {
+ ttl = (int)(data->ttl - timenow);
+ *rtt = rtt_notimeout(&data->rtt);
+ *rto = rtt_unclamped(&data->rtt);
+ }
+ lock_rw_unlock(&e->lock);
+ return ttl;
+}
+
int
infra_edns_update(struct infra_cache* infra,
struct sockaddr_storage* addr, socklen_t addrlen,
struct infra_host_data {
/** TTL value for this entry. absolute time. */
uint32_t ttl;
+ /** backoff time if blacklisted unresponsive. in seconds. */
+ uint32_t backoff;
/** round trip times for timeout calculation */
struct rtt_info rtt;
/** Names of the zones that are lame. NULL=no lame zones. */
int* lame, int* dnsseclame, int* reclame, int* rtt, int* lost,
uint32_t timenow);
+/**
+ * Get additional (debug) info on timing.
+ * @param infra: infra cache.
+ * @param addr: host address.
+ * @param addrlen: length of addr.
+ * @param rtt: the clean rtt time (of working replies).
+ * @param rto: the rtt with timeouts applied. (rtt as returned by other funcs).
+ * @param backoff: the backoff time for blacked entries.
+ * @param timenow: what time it is now.
+ * @return TTL the infra host element is valid for. If -1: not found in cache.
+ * If -2: found in cache, but TTL was not valid, only backoff is filled.
+ */
+int infra_get_host_rto(struct infra_cache* infra,
+ struct sockaddr_storage* addr, socklen_t addrlen,
+ int* rtt, int* rto, int* backoff, uint32_t timenow);
+
/**
* Get memory used by the infra cache.
* @param infra: infrastructure cache.
if(!infra_host(sq->outnet->infra, &sq->addr, sq->addrlen, now, &vs,
&edns_lame_known, &rtt))
return 0;
+ sq->last_rtt = rtt;
if(sq->status == serviced_initial) {
if(edns_lame_known == 0 && rtt > 5000 && rtt < 10001) {
/* perform EDNS lame probe - check if server is
}
serviced_encode(sq, buff, sq->status == serviced_query_UDP_EDNS);
sq->last_sent_time = *sq->outnet->now_tv;
- sq->last_rtt = rtt;
sq->edns_lame_known = (int)edns_lame_known;
verbose(VERB_ALGO, "serviced query UDP timeout=%d msec", rtt);
sq->pending = pending_udp_query(sq->outnet, buff, &sq->addr,
serviced_callbacks(sq, error, c, rep);
return 0;
}
- if(sq->status == serviced_query_UDP_EDNS
+ if(!fallback_tcp) {
+ if(sq->status == serviced_query_UDP_EDNS
&& (LDNS_RCODE_WIRE(ldns_buffer_begin(c->buffer))
== LDNS_RCODE_FORMERR || LDNS_RCODE_WIRE(
ldns_buffer_begin(c->buffer)) == LDNS_RCODE_NOTIMPL)) {
serviced_callbacks(sq, NETEVENT_CLOSED, c, rep);
}
return 0;
- } else if(sq->status == serviced_query_PROBE_EDNS) {
+ } else if(sq->status == serviced_query_PROBE_EDNS) {
/* probe without EDNS succeeds, so we conclude that this
* host likely has EDNS packets dropped */
log_addr(VERB_DETAIL, "timeouts, concluded that connection to "
log_err("Out of memory caching no edns for host");
}
sq->status = serviced_query_UDP;
- } else if(sq->status == serviced_query_UDP_EDNS &&
+ } else if(sq->status == serviced_query_UDP_EDNS &&
!sq->edns_lame_known) {
/* now we know that edns queries received answers store that */
if(!infra_edns_update(outnet->infra, &sq->addr, sq->addrlen,
log_err("Out of memory caching edns works");
}
sq->edns_lame_known = 1;
- } else if(sq->status == serviced_query_UDP_EDNS_fallback &&
+ } else if(sq->status == serviced_query_UDP_EDNS_fallback &&
!sq->edns_lame_known && (LDNS_RCODE_WIRE(
ldns_buffer_begin(c->buffer)) == LDNS_RCODE_NOERROR ||
LDNS_RCODE_WIRE(ldns_buffer_begin(c->buffer)) ==
log_err("Out of memory caching no edns for host");
}
sq->status = serviced_query_UDP;
- }
- if(now.tv_sec > sq->last_sent_time.tv_sec ||
+ }
+ if(now.tv_sec > sq->last_sent_time.tv_sec ||
(now.tv_sec == sq->last_sent_time.tv_sec &&
now.tv_usec > sq->last_sent_time.tv_usec)) {
/* convert from microseconds to milliseconds */
if(!infra_rtt_update(outnet->infra, &sq->addr, sq->addrlen,
roundtime, sq->last_rtt, (uint32_t)now.tv_sec))
log_err("out of memory noting rtt.");
- }
+ }
+ } /* end of if_!fallback_tcp */
/* perform TC flag check and TCP fallback after updating our
* cache entries for EDNS status and RTT times */
if(LDNS_TC_WIRE(ldns_buffer_begin(c->buffer)) || fallback_tcp) {
5100,
5101,
5102,
+5104,
+5105,
5111,
5112,
5113,
rtt->rto = RTT_MAX_TIMEOUT;
}
}
+
+int rtt_notimeout(const struct rtt_info* rtt)
+{
+ return calc_rto(rtt);
+}
*/
int rtt_unclamped(const struct rtt_info* rtt);
+/**
+ * RTT for valid responses. Without timeouts.
+ * @param rtt: round trip statistics structure.
+ * @return: value in msec.
+ */
+int rtt_notimeout(const struct rtt_info* rtt);
+
/**
* Update the statistics with a new roundtrip estimate observation.
* @param rtt: round trip statistics structure.