cycle detection

git-svn-id: file:///svn/unbound/trunk@452 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2007-07-26 09:29:21 +00:00
parent 9bd8d5a929
commit 85bfa1bd35
8 changed files with 97 additions and 8 deletions

View file

@ -712,6 +712,7 @@ worker_init(struct worker* worker, struct config_file *cfg,
worker->env.kill_sub = &mesh_state_delete;
worker->env.query_done = &mesh_query_done;
worker->env.walk_supers = &mesh_walk_supers;
worker->env.detect_cycle = &mesh_detect_cycle;
if(!worker->env.mesh) {
worker_delete(worker);
return 0;

View file

@ -1,3 +1,7 @@
26 July 2007: Wouter
- cycle detection, for query state dependencies. Will attempt to
circumvent the cycle, but if no other targets available fails.
25 July 2007: Wouter
- testbound read ADDRESS and check it.
- test for version.bind and friends.

View file

@ -354,3 +354,32 @@ iter_ns_probability(struct ub_randstate* rnd, int n, int m)
sel = ub_random(rnd) % m;
return (sel < n);
}
/** detect dependency cycle for query and target */
static int
causes_cycle(struct module_qstate* qstate, uint8_t* name, size_t namelen,
uint16_t t, uint16_t c)
{
struct query_info qinf;
qinf.qname = name;
qinf.qname_len = namelen;
qinf.qtype = t;
qinf.qclass = c;
return (*qstate->env->detect_cycle)(qstate, &qinf);
}
void
iter_mark_cycle_targets(struct module_qstate* qstate, struct delegpt* dp)
{
struct delegpt_ns* ns;
for(ns = dp->nslist; ns; ns = ns->next) {
if(ns->resolved)
continue;
/* see if this ns as target causes dependency cycle */
if(causes_cycle(qstate, ns->name, ns->namelen,
LDNS_RR_TYPE_AAAA, qstate->qinfo.qclass) ||
causes_cycle(qstate, ns->name, ns->namelen,
LDNS_RR_TYPE_A, qstate->qinfo.qclass))
ns->resolved = 1;
}
}

View file

@ -52,6 +52,7 @@ struct msg_parse;
struct ub_randstate;
struct query_info;
struct reply_info;
struct module_qstate;
/**
* Process config options and set iterator module state.
@ -119,4 +120,12 @@ int iter_dns_store(struct module_env* env, struct query_info* qinf,
*/
int iter_ns_probability(struct ub_randstate* rnd, int n, int m);
/**
* Mark targets that result in a dependency cycle as done, so they
* will not get selected as targets.
* @param qstate: query state.
* @param dp: delegpt to mark ns in.
*/
void iter_mark_cycle_targets(struct module_qstate* qstate, struct delegpt* dp);
#endif /* ITERATOR_ITER_UTILS_H */

View file

@ -811,8 +811,11 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq,
{
int query_count = 0;
struct delegpt_ns* ns = iq->dp->nslist;
int missing = (int)delegpt_count_missing_targets(iq->dp);
int missing;
int toget = 0;
iter_mark_cycle_targets(qstate, iq->dp);
missing = (int)delegpt_count_missing_targets(iq->dp);
log_assert(maxtargets != 0); /* that would not be useful */
/* Generate target requests. Basically, any missing targets
@ -840,13 +843,6 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq,
missing --;
continue;
}
if(iq->refetch_glue && dname_subdomain_c(ns->name,
iq->dp->name)) {
log_nametypeclass(VERB_DETAIL, "skip double glue "
"refetch", ns->name, LDNS_RR_TYPE_A,
iq->qchase.qclass);
continue;
}
if(ie->supports_ipv6) {
/* Send the AAAA request. */

View file

@ -588,3 +588,28 @@ mesh_get_mem(struct mesh_area* mesh)
}
return s;
}
/** helper recursive rbtree find routine */
static int
find_in_subsub(struct mesh_state* m, struct mesh_state* tofind)
{
struct mesh_state_ref* r;
RBTREE_FOR(r, struct mesh_state_ref*, &m->sub_set) {
if(r->s == tofind || find_in_subsub(r->s, tofind))
return 1;
}
return 0;
}
int
mesh_detect_cycle(struct module_qstate* qstate, struct query_info* qinfo)
{
struct mesh_area* mesh = qstate->env->mesh;
struct mesh_state* cyc_m = qstate->mesh_info;
struct mesh_state* dep_m = mesh_area_find(mesh, qinfo, BIT_RD, 0);
if(!dep_m)
return 0;
if(dep_m == cyc_m || find_in_subsub(dep_m, cyc_m))
return 1;
return 0;
}

View file

@ -357,4 +357,15 @@ void mesh_stats(struct mesh_area* mesh, const char* str);
*/
size_t mesh_get_mem(struct mesh_area* mesh);
/**
* Find cycle; see if the given mesh is in the targets sub, or sub-sub, ...
* trees.
* @param qstate: given mesh querystate.
* @param qinfo: query info for dependency.
* @return true if the name,type,class exists and the given qstate mesh exists
* as a dependency of that name. Thus if qstate becomes dependent on
* name,type,class then a cycle is created.
*/
int mesh_detect_cycle(struct module_qstate* qstate, struct query_info* qinfo);
#endif /* SERVICES_MESH_H */

View file

@ -196,6 +196,20 @@ struct module_env {
void (*walk_supers)(struct module_qstate* qstate, int id,
void (*cb)(struct module_qstate*, int, struct module_qstate*));
/**
* Detect if adding a dependency for qstate on name,type,class will
* create a dependency cycle.
* @param qstate: given mesh querystate.
* @param qinfo: query info for dependency. Assumed RDflag and not
* priming.
* @return true if the name,type,class exists and the given
* qstate mesh exists as a dependency of that name. Thus
* if qstate becomes dependent on name,type,class then a
* cycle is created.
*/
int (*detect_cycle)(struct module_qstate* qstate,
struct query_info* qinfo);
/** region for temporary usage. May be cleared after operate() call. */
struct region* scratch;
/** internal data for daemon - worker thread. */