Merge branch 'subnet_cache_prefetch' of https://github.com/tilan7663/unbound into tilan7663-subnet_cache_prefetch

This commit is contained in:
George Thessalonikefs 2022-05-17 16:16:09 +03:00
commit 91c298c901
2 changed files with 140 additions and 12 deletions

View file

@ -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");

View file

@ -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 */