From: Wouter Wijngaards Date: Fri, 22 Jun 2007 10:09:21 +0000 (+0000) Subject: Mesh design and preparatory cleanup. X-Git-Tag: release-0.4~48 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fcd489a12a11b010338f897cee055bc8fd03ee54;p=thirdparty%2Funbound.git Mesh design and preparatory cleanup. - removed unused _node iterator value from rbtree_t. Takes up space. - iterator can handle querytargets state without a delegation point set, so that a priming(stub) subquery error can be handled. - iterator stores if it is priming or not. - log_query_info() neater logging. git-svn-id: file:///svn/unbound/trunk@418 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/daemon/worker.c b/daemon/worker.c index 4070908a5..46c3e74fc 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -215,8 +215,7 @@ run_debug(struct module_qstate* p, int d) } buf[i++] = 'o'; buf[i] = 0; - log_nametypeclass(VERB_ALGO, buf, p->qinfo.qname, p->qinfo.qtype, - p->qinfo.qclass); + log_query_info(VERB_ALGO, buf, &p->qinfo); for(p = p->subquery_first; p; p = p->subquery_next) { run_debug(p, d+1); } diff --git a/doc/Changelog b/doc/Changelog index f5e00da23..0710624b8 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,10 @@ +22 June 2007: Wouter + - removed unused _node iterator value from rbtree_t. Takes up space. + - iterator can handle querytargets state without a delegation point + set, so that a priming(stub) subquery error can be handled. + - iterator stores if it is priming or not. + - log_query_info() neater logging. + 21 June 2007: Wouter - Fixup secondary buffer in case of error callback. - cleanup slumber list of runnable states. diff --git a/iterator/iterator.c b/iterator/iterator.c index 2decfac19..0c977b337 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -108,6 +108,7 @@ iter_new(struct module_qstate* qstate, int id) iq->num_current_queries = 0; iq->query_restart_count = 0; iq->referral_count = 0; + iq->priming = 0; iq->priming_stub = 0; iq->orig_qflags = qstate->query_flags; /* remove all weird bits from the query flags */ @@ -554,6 +555,7 @@ prime_root(struct module_qstate* qstate, struct iter_qstate* iq, subiq->dp = dp; /* suppress any target queries. */ subiq->num_target_queries = 0; + subiq->priming = 1; /* this module stops, our submodule starts, and does the query. */ qstate->ext_state[id] = module_wait_subquery; @@ -608,6 +610,7 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq, /* suppress any target queries -- although there wouldn't be anyway, * since stub hints never have missing targets.*/ subiq->num_target_queries = 0; + subiq->priming = 1; subiq->priming_stub = 1; /* this module stops, our submodule starts, and does the query. */ @@ -641,8 +644,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, size_t delnamelen; struct dns_msg* msg; - log_nametypeclass(VERB_DETAIL, "resolving", qstate->qinfo.qname, - qstate->qinfo.qtype, qstate->qinfo.qclass); + log_query_info(VERB_DETAIL, "resolving", &qstate->qinfo); /* check effort */ /* We enforce a maximum number of query restarts. This is primarily a @@ -801,8 +803,8 @@ static int processInitRequest2(struct module_qstate* qstate, struct iter_qstate* iq, struct iter_env* ie, int id) { - log_nametypeclass(VERB_DETAIL, "resolving (init part 2): ", - qstate->qinfo.qname, qstate->qinfo.qtype, qstate->qinfo.qclass); + log_query_info(VERB_DETAIL, "resolving (init part 2): ", + &qstate->qinfo); /* Check to see if we need to prime a stub zone. */ if(prime_stub(qstate, iq, ie, id, qstate->qinfo.qname, @@ -828,8 +830,8 @@ processInitRequest2(struct module_qstate* qstate, struct iter_qstate* iq, static int processInitRequest3(struct module_qstate* qstate, struct iter_qstate* iq) { - log_nametypeclass(VERB_DETAIL, "resolving (init part 3): ", - qstate->qinfo.qname, qstate->qinfo.qtype, qstate->qinfo.qclass); + log_query_info(VERB_DETAIL, "resolving (init part 3): ", + &qstate->qinfo); /* If the RD flag wasn't set, then we just finish with the * cached referral as the response. */ if(!(qstate->query_flags & BIT_RD)) { @@ -987,8 +989,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, * needs to send a query to. That is, at least one per referral, * more if some targets timeout or return throwaway answers. */ - log_nametypeclass(VERB_DETAIL, "processQueryTargets:", - qstate->qinfo.qname, qstate->qinfo.qtype, qstate->qinfo.qclass); + log_query_info(VERB_DETAIL, "processQueryTargets:", &qstate->qinfo); verbose(VERB_ALGO, "processQueryTargets: targetqueries %d, " "currentqueries %d", iq->num_target_queries, iq->num_current_queries); @@ -1001,6 +1002,13 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, "number of referrrals with %d", iq->referral_count); return error_response(qstate, id, LDNS_RCODE_SERVFAIL); } + + /* Make sure we have a delegation point, otherwise priming failed + * or another failure occurred */ + if(!iq->dp) { + verbose(VERB_DETAIL, "Failed to get a delegation, giving up"); + return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + } tf_policy = 0; if(iq->depth <= ie->max_dependency_depth) { @@ -1088,8 +1096,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, } /* We have a valid target. */ - log_nametypeclass(VERB_DETAIL, "sending query:", qstate->qinfo.qname, - qstate->qinfo.qtype, qstate->qinfo.qclass); + log_query_info(VERB_DETAIL, "sending query:", &qstate->qinfo); log_name_addr(VERB_DETAIL, "sending to target:", iq->dp->name, &target->addr, target->addrlen); outq = (*qstate->env->send_query)( @@ -1291,8 +1298,7 @@ processPrimeResponse(struct module_qstate* qstate, struct iter_qstate* iq, return error_response(qstate, id, LDNS_RCODE_SERVFAIL); } - log_nametypeclass(VERB_DETAIL, "priming successful for", - qstate->qinfo.qname, qstate->qinfo.qtype, qstate->qinfo.qclass); + log_query_info(VERB_DETAIL, "priming successful for", &qstate->qinfo); delegpt_log(dp); foriq = (struct iter_qstate*)forq->minfo[id]; foriq->dp = dp; @@ -1400,8 +1406,8 @@ static int processFinished(struct module_qstate* qstate, struct iter_qstate* iq, int id) { - log_nametypeclass(VERB_DETAIL, "finishing processing for", - qstate->qinfo.qname, qstate->qinfo.qtype, qstate->qinfo.qclass); + log_query_info(VERB_DETAIL, "finishing processing for", + &qstate->qinfo); if(!iq->response) { verbose(VERB_ALGO, "No response is set, servfail"); @@ -1603,8 +1609,7 @@ process_subq_error(struct module_qstate* qstate, struct iter_qstate* iq, if(!dpns) { /* not interested */ verbose(VERB_ALGO, "got subq error, but not interested"); - log_nametypeclass(VERB_ALGO, "errname", - errinf.qname, errinf.qtype, errinf.qclass); + log_query_info(VERB_ALGO, "errname", &errinf); delegpt_log(iq->dp); return; } @@ -1623,8 +1628,8 @@ iter_operate(struct module_qstate* qstate, enum module_ev event, int id, struct iter_qstate* iq = (struct iter_qstate*)qstate->minfo[id]; verbose(VERB_DETAIL, "iterator[module %d] operate: extstate:%s event:%s", id, strextstate(qstate->ext_state[id]), strmodulevent(event)); - if(iq) log_nametypeclass(VERB_DETAIL, "iterator operate: query", - qstate->qinfo.qname, qstate->qinfo.qtype, qstate->qinfo.qclass); + if(iq) log_query_info(VERB_DETAIL, "iterator operate: query", + &qstate->qinfo); if(ie->fwd_addrlen != 0) { perform_forward(qstate, event, id, outbound); return; diff --git a/iterator/iterator.h b/iterator/iterator.h index 0535f7e75..e79bb599e 100644 --- a/iterator/iterator.h +++ b/iterator/iterator.h @@ -212,6 +212,12 @@ struct iter_qstate { /** the number of times this query as followed a referral. */ int referral_count; + /** + * This flag, if true, means that this event is a priming query. + * In that case priming stub may be set as well. + */ + int priming; + /** * This is flag that, if true, means that this event is * representing a stub priming query. It is meaningless unless diff --git a/services/mesh.c b/services/mesh.c index 3f5c6a0dd..d285b34f3 100644 --- a/services/mesh.c +++ b/services/mesh.c @@ -44,4 +44,62 @@ */ #include "config.h" #include "services/mesh.h" +#include "util/log.h" +#include "util/net_help.h" +#include "util/module.h" +#include "util/region-allocator.h" +/** compare two mesh_states */ +static int +mesh_state_compare(const void* ap, const void* bp) +{ + struct mesh_state* a = (struct mesh_state*)ap; + struct mesh_state* b = (struct mesh_state*)bp; + + if(a->is_priming && !b->is_priming) + return -1; + if(!a->is_priming && b->is_priming) + return 1; + + if((a->state->query_flags&BIT_RD) && !(b->state->query_flags&BIT_RD)) + return -1; + if(!(a->state->query_flags&BIT_RD) && (b->state->query_flags&BIT_RD)) + return 1; + + return query_info_compare(&a->state->qinfo, &b->state->qinfo); +} + +/** compare two mesh references */ +static int +mesh_state_ref_compare(const void* ap, const void* bp) +{ + struct mesh_state_ref* a = (struct mesh_state_ref*)ap; + struct mesh_state_ref* b = (struct mesh_state_ref*)bp; + return mesh_state_compare(a->s, b->s); +} + +struct mesh_area* +mesh_create(struct worker* worker) +{ + struct mesh_area* mesh = calloc(1, sizeof(struct mesh_area)); + if(!mesh) { + log_err("mesh area alloc: out of memory"); + return NULL; + } + mesh->worker = worker; + rbtree_init(&mesh->run, &mesh_state_compare); + rbtree_init(&mesh->all, &mesh_state_compare); + mesh->num_reply_addrs = 0; + mesh->num_reply_states = 0; + mesh->num_detached_states = 0; + return mesh; +} + +void +mesh_delete(struct mesh_area* mesh) +{ + if(!mesh) + return; + /* free all query states */ + free(mesh); +} diff --git a/services/mesh.h b/services/mesh.h index 798a65316..b0883b24f 100644 --- a/services/mesh.h +++ b/services/mesh.h @@ -55,42 +55,49 @@ struct mesh_reply; struct worker; struct query_info; struct reply_info; +struct outbound_entry; /** * Mesh of query states */ -struct query_mesh { +struct mesh_area { /** what worker this is a part of */ struct worker* worker; - /** set of runnable queries (mesh_state_ref*) */ + /** set of runnable queries (mesh_state.run_node) */ rbtree_t run; - /** rbtree of all current queries */ + /** rbtree of all current queries (mesh_state.node)*/ rbtree_t all; - /** count of the number of mesh_reply entries */ - size_t reply_count; - /** count of the number of mesh_states that have no mesh_replies - * i.e. are for internal use. */ - size_t internal_count; + + /** count of the total number of mesh_reply entries */ + size_t num_reply_addrs; + /** count of the number of mesh_states that have mesh_replies + * Because a state can send results to multiple reply addresses, + * this number must be equal or lower than num_reply_addrs. */ + size_t num_reply_states; + /** number of mesh_states that have no mesh_replies, and also + * an empty set of super-states, thus are 'toplevel' or detached + * internal opportunistic queries */ + size_t num_detached_states; }; /** * A mesh query state - * Unique per qname, qtype, qclass. + * Unique per qname, qtype, qclass (from the qstate). * And RD flag; in case a client turns it off. * And priming queries are different from ordinary queries (because of hints). + * + * The entire structure is allocated in a region, this region is the qstate + * region. All parts (rbtree nodes etc) are also allocated in the region. */ struct mesh_state { - /** node in query_mesh all tree, key is this struct */ + /** node in mesh_area all tree, key is this struct */ rbnode_t node; - /** node in query_mesh runnable tree, key is this struct */ + /** node in mesh_area runnable tree, key is this struct */ rbnode_t run_node; - /** unique identity for this mesh state: what is it for */ - /* Note that qstate qinfo is changed by iterator */ - - /** if this is a priming query (with hints) */ + /** if this is a (stub or root) priming query (with hints) */ int is_priming; - - /** the query state */ + /** the query state. Note that the qinfo and query_flags + * may not change. */ struct module_qstate* state; /** the list of replies to clients for the results */ struct mesh_reply* reply_list; @@ -123,38 +130,59 @@ struct mesh_reply { struct comm_reply query_reply; /** edns data from query */ struct edns_data edns; + /** the time when request was entered */ + struct timeval start_time; /** id of query, in network byteorder. */ uint16_t qid; /** flags of query, for reply flags */ uint16_t qflags; }; +/* ------------------- Functions for worker -------------------- */ + /** * Allocate mesh, to empty. * @param worker: what worker it is part of. * @return mesh: the new mesh or NULL on error. */ -struct query_mesh* mesh_create(struct worker* worker); +struct mesh_area* mesh_create(struct worker* worker); /** * Delete mesh, and all query states and replies in it. * @param mesh: the mesh to delete. */ -void mesh_delete(struct query_mesh* mesh); +void mesh_delete(struct mesh_area* mesh); /** * New query incoming from clients. Create new query state if needed, and * add mesh_reply to it. Returns error to client on malloc failures. + * Will run the mesh area queries to process if a new query state is created. + * * @param mesh: the mesh. * @param qinfo: query from client. * @param qflags: flags from client query. * @param edns: edns data from client query. * @param rep: where to reply to. - * @param id: query id to reply with. + * @param qid: query id to reply with. */ -void mesh_new_client(struct query_mesh* mesh, struct query_info* qinfo, +void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, uint16_t qflags, struct edns_data* edns, struct comm_reply* rep, - uint16_t id); + uint16_t qid); + +/** + * Handle new event from the wire. A serviced query has returned. + * The query state will be made runnable, and the mesh_area will process + * query states until processing is complete. + * + * @param mesh: the query mesh. + * @param e: outbound entry, with query state to run and reply pointer. + * @param is_ok: if true, reply is OK, otherwise a timeout happened. + * @param reply: the comm point reply info. + */ +void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e, + int is_ok, struct comm_reply* reply); + +/* ------------------- Functions for module environment --------------- */ /** * Detach-subqueries. @@ -179,7 +207,7 @@ void mesh_detach_subs(struct module_qstate* qstate); * the results from the new subquery. * @param qinfo: what to query for (copied). * @param qflags: what flags to use (RD flag or not). - * @param prime: if it is a priming query. + * @param prime: if it is a (stub) priming query. * @param newq: If the new subquery needs initialisation, it is returned, * otherwise NULL is returned. * @return: false on error, true if success (and init may be needed). @@ -221,4 +249,15 @@ void mesh_query_done(struct module_qstate* qstate, int rcode, void mesh_walk_supers(struct module_qstate* qstate, int id, int rcode, void (*cb)(struct module_qstate*, int, struct module_qstate*, int)); +/* ------------------- Functions for mesh -------------------- */ + +/** + * Create and initialize a new mesh state and its query state + */ + +/** + * Cleanup a mesh state and its query state. Does not do rbtree or + * reference cleanup. + */ + #endif /* SERVICES_MESH_H */ diff --git a/util/data/msgreply.c b/util/data/msgreply.c index 312a2cb9a..c634b4e0b 100644 --- a/util/data/msgreply.c +++ b/util/data/msgreply.c @@ -691,3 +691,10 @@ log_dns_msg(const char* str, struct query_info* qinfo, struct reply_info* rep) ldns_buffer_free(buf); region_destroy(region); } + +void +log_query_info(enum verbosity_value v, const char* str, + struct query_info* qinf) +{ + log_nametypeclass(v, str, qinf->qname, qinf->qtype, qinf->qclass); +} diff --git a/util/data/msgreply.h b/util/data/msgreply.h index d301fb27d..04f471e21 100644 --- a/util/data/msgreply.h +++ b/util/data/msgreply.h @@ -309,4 +309,13 @@ struct ub_packed_rrset_key* reply_find_answer_rrset(struct query_info* qinfo, void log_dns_msg(const char* str, struct query_info* qinfo, struct reply_info* rep); +/** + * Print string with neat domain name, type, class from query info. + * @param v: at what verbosity level to print this. + * @param str: string of message. + * @param qinf: query info structure with name, type and class. + */ +void log_query_info(enum verbosity_value v, const char* str, + struct query_info* qinf); + #endif /* UTIL_DATA_MSGREPLY_H */ diff --git a/util/rbtree.h b/util/rbtree.h index 401f2aa5b..879804dd8 100644 --- a/util/rbtree.h +++ b/util/rbtree.h @@ -80,9 +80,6 @@ struct rbtree_t { /** The number of the nodes in the tree */ size_t count; - /** Current node for walks... */ - rbnode_t *_node; - /** * Key compare function. <0,0,>0 like strcmp. * Return 0 on two NULL ptrs. @@ -169,14 +166,6 @@ rbnode_t *rbtree_next(rbnode_t *rbtree); */ rbnode_t *rbtree_previous(rbnode_t *rbtree); -/** - * Macro to walk through the tree, sets k to key, d to data, for every element. - */ -#define RBTREE_WALK(rbtree, k, d) \ - for((rbtree)->_node = rbtree_first(rbtree);\ - (rbtree)->_node != RBTREE_NULL && ((k) = (rbtree)->_node->key) && \ - ((d) = (void *) (rbtree)->_node); (rbtree)->_node = rbtree_next((rbtree)->_node)) - /** * Call with node=variable of struct* with rbnode_t as first element. * with type is the type of a pointer to that struct.