mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-20 23:00:56 -05:00
Merge branch 'subnet_cache_prefetch' of https://github.com/tilan7663/unbound into tilan7663-subnet_cache_prefetch
This commit is contained in:
commit
91c298c901
2 changed files with 140 additions and 12 deletions
|
|
@ -330,11 +330,15 @@ update_cache(struct module_qstate *qstate, int id)
|
||||||
struct slabhash *subnet_msg_cache = sne->subnet_msg_cache;
|
struct slabhash *subnet_msg_cache = sne->subnet_msg_cache;
|
||||||
struct ecs_data *edns = &sq->ecs_client_in;
|
struct ecs_data *edns = &sq->ecs_client_in;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
hashvalue_type h;
|
||||||
|
|
||||||
|
/* qinfo_hash is not set if it is prefetch request */
|
||||||
|
if (qstate->minfo[id] && ((struct subnet_qstate*)qstate->minfo[id])->qinfo_hash) {
|
||||||
|
h = ((struct subnet_qstate*)qstate->minfo[id])->qinfo_hash;
|
||||||
|
} else {
|
||||||
|
h = query_info_hash(&qstate->qinfo, qstate->query_flags);
|
||||||
|
}
|
||||||
|
|
||||||
/* We already calculated hash upon lookup */
|
|
||||||
hashvalue_type h = qstate->minfo[id] ?
|
|
||||||
((struct subnet_qstate*)qstate->minfo[id])->qinfo_hash :
|
|
||||||
query_info_hash(&qstate->qinfo, qstate->query_flags);
|
|
||||||
/* Step 1, general qinfo lookup */
|
/* Step 1, general qinfo lookup */
|
||||||
struct lruhash_entry *lru_entry = slabhash_lookup(subnet_msg_cache, h,
|
struct lruhash_entry *lru_entry = slabhash_lookup(subnet_msg_cache, h,
|
||||||
&qstate->qinfo, 1);
|
&qstate->qinfo, 1);
|
||||||
|
|
@ -402,7 +406,7 @@ update_cache(struct module_qstate *qstate, int id)
|
||||||
|
|
||||||
/** Lookup in cache and reply true iff reply is sent. */
|
/** Lookup in cache and reply true iff reply is sent. */
|
||||||
static int
|
static int
|
||||||
lookup_and_reply(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
|
lookup_and_reply(struct module_qstate *qstate, int id, struct subnet_qstate *sq, int prefetch)
|
||||||
{
|
{
|
||||||
struct lruhash_entry *e;
|
struct lruhash_entry *e;
|
||||||
struct module_env *env = qstate->env;
|
struct module_env *env = qstate->env;
|
||||||
|
|
@ -451,6 +455,10 @@ lookup_and_reply(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
|
||||||
INET6_SIZE);
|
INET6_SIZE);
|
||||||
sq->ecs_client_out.subnet_validdata = 1;
|
sq->ecs_client_out.subnet_validdata = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (prefetch && *qstate->env->now > ((struct reply_info *)node->elem)->prefetch_ttl) {
|
||||||
|
qstate->need_refetch = 1;
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -759,7 +767,7 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event,
|
||||||
}
|
}
|
||||||
|
|
||||||
lock_rw_wrlock(&sne->biglock);
|
lock_rw_wrlock(&sne->biglock);
|
||||||
if (lookup_and_reply(qstate, id, sq)) {
|
if (qstate->mesh_info->reply_list && lookup_and_reply(qstate, id, sq, qstate->env->cfg->prefetch)) {
|
||||||
sne->num_msg_cache++;
|
sne->num_msg_cache++;
|
||||||
lock_rw_unlock(&sne->biglock);
|
lock_rw_unlock(&sne->biglock);
|
||||||
verbose(VERB_QUERY, "subnetcache: answered from cache");
|
verbose(VERB_QUERY, "subnetcache: answered from cache");
|
||||||
|
|
|
||||||
122
services/mesh.c
122
services/mesh.c
|
|
@ -688,6 +688,107 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CLIENT_SUBNET
|
||||||
|
/* Same logic as mesh_schedule_prefetch but tailored to the subnet module logic
|
||||||
|
* like passing along the comm_reply info. This will be faked into an EDNS
|
||||||
|
* option for processing by the subnet module if the client has not already
|
||||||
|
* attached its own ECS data. */
|
||||||
|
static void mesh_schedule_prefetch_subnet(struct mesh_area* mesh,
|
||||||
|
struct query_info* qinfo, uint16_t qflags, time_t leeway, int run,
|
||||||
|
int rpz_passthru, struct mesh_state* mstate,
|
||||||
|
struct sockaddr_storage *client_addr)
|
||||||
|
{
|
||||||
|
struct mesh_state* s = NULL;
|
||||||
|
struct edns_option* opt = NULL;
|
||||||
|
#ifdef UNBOUND_DEBUG
|
||||||
|
struct rbnode_type* n;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(!mesh_make_new_space(mesh, NULL)) {
|
||||||
|
verbose(VERB_ALGO, "Too many queries. dropped prefetch.");
|
||||||
|
mesh->stats_dropped ++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = mesh_state_create(mesh->env, qinfo, NULL,
|
||||||
|
qflags&(BIT_RD|BIT_CD), 0, 0);
|
||||||
|
if(!s) {
|
||||||
|
log_err("prefetch_subnet mesh_state_create: out of memory");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mesh_state_make_unique(s);
|
||||||
|
|
||||||
|
opt = edns_opt_list_find(mstate->s.edns_opts_front_in, mesh->env->cfg->client_subnet_opcode);
|
||||||
|
if(opt) {
|
||||||
|
/* Use the client's ECS data */
|
||||||
|
if(!edns_opt_list_append(&s->s.edns_opts_front_in, opt->opt_code,
|
||||||
|
opt->opt_len, opt->opt_data, s->s.region)) {
|
||||||
|
log_err("prefetch_subnet edns_opt_list_append: out of memory");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Fake the ECS data from the client's IP */
|
||||||
|
struct ecs_data ecs;
|
||||||
|
memset(&ecs, 0, sizeof(ecs));
|
||||||
|
subnet_option_from_ss(client_addr, &ecs, mesh->env->cfg);
|
||||||
|
|
||||||
|
if(ecs.subnet_validdata == 0) {
|
||||||
|
log_err("prefetch_subnet subnet_option_from_ss: invalid data");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
subnet_ecs_opt_list_append(&ecs, &s->s.edns_opts_front_in, &s->s);
|
||||||
|
if(!s->s.edns_opts_front_in) {
|
||||||
|
log_err("prefetch_subnet subnet_ecs_opt_list_append: out of memory");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef UNBOUND_DEBUG
|
||||||
|
n =
|
||||||
|
#else
|
||||||
|
(void)
|
||||||
|
#endif
|
||||||
|
rbtree_insert(&mesh->all, &s->node);
|
||||||
|
log_assert(n != NULL);
|
||||||
|
/* set detached (it is now) */
|
||||||
|
mesh->num_detached_states++;
|
||||||
|
/* make it ignore the cache */
|
||||||
|
sock_list_insert(&s->s.blacklist, NULL, 0, s->s.region);
|
||||||
|
s->s.prefetch_leeway = leeway;
|
||||||
|
|
||||||
|
if(s->list_select == mesh_no_list) {
|
||||||
|
/* move to either the forever or the jostle_list */
|
||||||
|
if(mesh->num_forever_states < mesh->max_forever_states) {
|
||||||
|
mesh->num_forever_states ++;
|
||||||
|
mesh_list_insert(s, &mesh->forever_first,
|
||||||
|
&mesh->forever_last);
|
||||||
|
s->list_select = mesh_forever_list;
|
||||||
|
} else {
|
||||||
|
mesh_list_insert(s, &mesh->jostle_first,
|
||||||
|
&mesh->jostle_last);
|
||||||
|
s->list_select = mesh_jostle_list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s->s.rpz_passthru = rpz_passthru;
|
||||||
|
|
||||||
|
if(!run) {
|
||||||
|
#ifdef UNBOUND_DEBUG
|
||||||
|
n =
|
||||||
|
#else
|
||||||
|
(void)
|
||||||
|
#endif
|
||||||
|
rbtree_insert(&mesh->run, &s->run_node);
|
||||||
|
log_assert(n != NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mesh_state_delete(&mstate->s);
|
||||||
|
mesh_run(mesh, s, module_event_new, NULL);
|
||||||
|
}
|
||||||
|
#endif /* CLIENT_SUBNET */
|
||||||
|
|
||||||
/* Internal backend routine of mesh_new_prefetch(). It takes one additional
|
/* Internal backend routine of mesh_new_prefetch(). It takes one additional
|
||||||
* parameter, 'run', which controls whether to run the prefetch state
|
* parameter, 'run', which controls whether to run the prefetch state
|
||||||
* immediately. When this function is called internally 'run' could be
|
* immediately. When this function is called internally 'run' could be
|
||||||
|
|
@ -1840,6 +1941,11 @@ mesh_continue(struct mesh_area* mesh, struct mesh_state* mstate,
|
||||||
struct query_info* qinfo = NULL;
|
struct query_info* qinfo = NULL;
|
||||||
uint16_t qflags;
|
uint16_t qflags;
|
||||||
int rpz_p = 0;
|
int rpz_p = 0;
|
||||||
|
struct sockaddr_storage client_addr;
|
||||||
|
|
||||||
|
if (mstate->reply_list) {
|
||||||
|
client_addr = mstate->reply_list->query_reply.addr;
|
||||||
|
}
|
||||||
|
|
||||||
mesh_query_done(mstate);
|
mesh_query_done(mstate);
|
||||||
mesh_walk_supers(mesh, mstate);
|
mesh_walk_supers(mesh, mstate);
|
||||||
|
|
@ -1853,11 +1959,25 @@ mesh_continue(struct mesh_area* mesh, struct mesh_state* mstate,
|
||||||
rpz_p = mstate->s.rpz_passthru;
|
rpz_p = mstate->s.rpz_passthru;
|
||||||
}
|
}
|
||||||
|
|
||||||
mesh_state_delete(&mstate->s);
|
|
||||||
if(qinfo) {
|
if(qinfo) {
|
||||||
|
#ifdef CLIENT_SUBNET
|
||||||
|
if(modstack_find(&mesh->mods, "subnetcache") != -1 ) {
|
||||||
|
mesh_schedule_prefetch_subnet(mesh, qinfo, qflags,
|
||||||
|
0, 1, rpz_p, mstate, &client_addr);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mesh_state_delete(&mstate->s);
|
||||||
mesh_schedule_prefetch(mesh, qinfo, qflags,
|
mesh_schedule_prefetch(mesh, qinfo, qflags,
|
||||||
0, 1, rpz_p);
|
0, 1, rpz_p);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
mesh_state_delete(&mstate->s);
|
||||||
|
mesh_schedule_prefetch(mesh, qinfo, qflags,
|
||||||
|
0, 1, rpz_p);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
mesh_state_delete(&mstate->s);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* pass along the locus of control */
|
/* pass along the locus of control */
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue