mirror of
https://github.com/NLnetLabs/unbound.git
synced 2024-09-21 06:37:08 +00:00
Merge branch 'tilan7663-subnet_cache_prefetch' into subnet_cache_prefetch
This commit is contained in:
commit
a952ac17be
@ -817,7 +817,8 @@ reply_and_prefetch(struct worker* worker, struct query_info* qinfo,
|
||||
if(modstack_find(&worker->env.mesh->mods, "subnetcache") != -1
|
||||
&& worker->env.unique_mesh) {
|
||||
mesh_new_prefetch(worker->env.mesh, qinfo, flags, leeway +
|
||||
PREFETCH_EXPIRY_ADD, rpz_passthru, repinfo, opt_list);
|
||||
PREFETCH_EXPIRY_ADD, rpz_passthru,
|
||||
&repinfo->client_addr, opt_list);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
@ -352,7 +352,7 @@ update_cache(struct module_qstate *qstate, int id)
|
||||
((struct subnet_qstate*)qstate->minfo[id])->qinfo_hash :
|
||||
query_info_hash(&qstate->qinfo, qstate->query_flags);
|
||||
/* 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);
|
||||
int need_to_insert = (lru_entry == NULL);
|
||||
if (!lru_entry) {
|
||||
@ -396,7 +396,7 @@ update_cache(struct module_qstate *qstate, int id)
|
||||
log_err("subnetcache: cache insertion failed");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* store RRsets */
|
||||
for(i=0; i<rep->rrset_count; i++) {
|
||||
rep->ref[i].key = rep->rrsets[i];
|
||||
@ -421,7 +421,7 @@ update_cache(struct module_qstate *qstate, int id)
|
||||
|
||||
/** Lookup in cache and reply true iff reply is sent. */
|
||||
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 module_env *env = qstate->env;
|
||||
@ -473,6 +473,10 @@ lookup_and_reply(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
|
||||
INET6_SIZE);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -509,7 +513,7 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
|
||||
* module_finished */
|
||||
return module_finished;
|
||||
}
|
||||
|
||||
|
||||
/* We have not asked for subnet data */
|
||||
if (!sq->subnet_sent) {
|
||||
if (s_in->subnet_validdata)
|
||||
@ -518,7 +522,7 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
|
||||
cp_edns_bad_response(c_out, c_in);
|
||||
return module_finished;
|
||||
}
|
||||
|
||||
|
||||
/* subnet sent but nothing came back */
|
||||
if (!s_in->subnet_validdata) {
|
||||
/* The authority indicated no support for edns subnet. As a
|
||||
@ -535,11 +539,11 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
|
||||
cp_edns_bad_response(c_out, c_in);
|
||||
return module_finished;
|
||||
}
|
||||
|
||||
|
||||
/* Being here means we have asked for and got a subnet specific
|
||||
* answer. Also, the answer from the authority is not yet cached
|
||||
* anywhere. */
|
||||
|
||||
|
||||
/* can we accept response? */
|
||||
if(s_out->subnet_addr_fam != s_in->subnet_addr_fam ||
|
||||
s_out->subnet_source_mask != s_in->subnet_source_mask ||
|
||||
@ -807,7 +811,9 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event,
|
||||
|
||||
if(!sq->started_no_cache_lookup && !qstate->blacklist) {
|
||||
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++;
|
||||
lock_rw_unlock(&sne->biglock);
|
||||
verbose(VERB_QUERY, "subnetcache: answered from cache");
|
||||
|
@ -705,7 +705,7 @@ static void mesh_schedule_prefetch(struct mesh_area* mesh,
|
||||
* 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 comm_reply* rep, struct edns_option* edns_list)
|
||||
int rpz_passthru, struct sockaddr_storage* addr, struct edns_option* edns_list)
|
||||
{
|
||||
struct mesh_state* s = NULL;
|
||||
struct edns_option* opt = NULL;
|
||||
@ -738,7 +738,7 @@ static void mesh_schedule_prefetch_subnet(struct mesh_area* mesh,
|
||||
/* Store the client's address. Later in the subnet module,
|
||||
* it is decided whether to include an ECS option or not.
|
||||
*/
|
||||
s->s.client_addr = rep->client_addr;
|
||||
s->s.client_addr = *addr;
|
||||
}
|
||||
#ifdef UNBOUND_DEBUG
|
||||
n =
|
||||
@ -785,14 +785,14 @@ static void mesh_schedule_prefetch_subnet(struct mesh_area* mesh,
|
||||
|
||||
void mesh_new_prefetch(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
uint16_t qflags, time_t leeway, int rpz_passthru,
|
||||
struct comm_reply* rep, struct edns_option* opt_list)
|
||||
struct sockaddr_storage* addr, struct edns_option* opt_list)
|
||||
{
|
||||
(void)addr;
|
||||
(void)opt_list;
|
||||
(void)rep;
|
||||
#ifdef CLIENT_SUBNET
|
||||
if(rep)
|
||||
if(addr)
|
||||
mesh_schedule_prefetch_subnet(mesh, qinfo, qflags, leeway, 1,
|
||||
rpz_passthru, rep, opt_list);
|
||||
rpz_passthru, addr, opt_list);
|
||||
else
|
||||
#endif
|
||||
mesh_schedule_prefetch(mesh, qinfo, qflags, leeway, 1,
|
||||
@ -1794,9 +1794,21 @@ mesh_continue(struct mesh_area* mesh, struct mesh_state* mstate,
|
||||
if(s == module_finished) {
|
||||
if(mstate->s.curmod == 0) {
|
||||
struct query_info* qinfo = NULL;
|
||||
struct edns_option* opt_list = NULL;
|
||||
struct sockaddr_storage addr;
|
||||
uint16_t qflags;
|
||||
int rpz_p = 0;
|
||||
|
||||
#ifdef CLIENT_SUBNET
|
||||
struct edns_option* ecs;
|
||||
if(mstate->s.need_refetch && mstate->reply_list &&
|
||||
modstack_find(&mesh->mods, "subnetcache") != -1 &&
|
||||
mstate->s.env->unique_mesh) {
|
||||
addr = mstate->reply_list->query_reply.client_addr;
|
||||
} else
|
||||
#endif
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
|
||||
mesh_query_done(mstate);
|
||||
mesh_walk_supers(mesh, mstate);
|
||||
|
||||
@ -1806,13 +1818,28 @@ mesh_continue(struct mesh_area* mesh, struct mesh_state* mstate,
|
||||
* we need to make a copy of the query info here. */
|
||||
if(mstate->s.need_refetch) {
|
||||
mesh_copy_qinfo(mstate, &qinfo, &qflags);
|
||||
#ifdef CLIENT_SUBNET
|
||||
/* Make also a copy of the ecs option if any */
|
||||
if((ecs = edns_opt_list_find(
|
||||
mstate->s.edns_opts_front_in,
|
||||
mstate->s.env->cfg->client_subnet_opcode)) != NULL) {
|
||||
(void)edns_opt_list_append(&opt_list,
|
||||
ecs->opt_code, ecs->opt_len,
|
||||
ecs->opt_data,
|
||||
mstate->s.env->scratch);
|
||||
}
|
||||
#endif
|
||||
rpz_p = mstate->s.rpz_passthru;
|
||||
}
|
||||
|
||||
mesh_state_delete(&mstate->s);
|
||||
if(qinfo) {
|
||||
mesh_schedule_prefetch(mesh, qinfo, qflags,
|
||||
0, 1, rpz_p);
|
||||
mesh_state_delete(&mstate->s);
|
||||
mesh_new_prefetch(mesh, qinfo, qflags, 0,
|
||||
rpz_p,
|
||||
addr.ss_family!=AF_UNSPEC?&addr:NULL,
|
||||
opt_list);
|
||||
} else {
|
||||
mesh_state_delete(&mstate->s);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -337,13 +337,13 @@ int mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
* @param leeway: TTL leeway what to expire earlier for this update.
|
||||
* @param rpz_passthru: if true, the rpz passthru was previously found and
|
||||
* further rpz processing is stopped.
|
||||
* @param rep: comm_reply for the client; to be used when subnet is enabled.
|
||||
* @param addr: sockaddr_storage for the client; to be used with subnet.
|
||||
* @param opt_list: edns opt_list from the client; to be used when subnet is
|
||||
* enabled.
|
||||
*/
|
||||
void mesh_new_prefetch(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
uint16_t qflags, time_t leeway, int rpz_passthru,
|
||||
struct comm_reply* rep, struct edns_option* opt_list);
|
||||
struct sockaddr_storage* addr, struct edns_option* opt_list);
|
||||
|
||||
/**
|
||||
* Handle new event from the wire. A serviced query has returned.
|
||||
|
75
testdata/subnet_prefetch.crpl
vendored
75
testdata/subnet_prefetch.crpl
vendored
@ -1,12 +1,12 @@
|
||||
; Check if the prefetch option works properly for messages stored in the global
|
||||
; cache for non-ECS clients. The prefetch query needs to result in an ECS
|
||||
; outgoing query based on the client's IP.
|
||||
; Check if the prefetch option works properly for messages stored in ECS cache
|
||||
; for non-ECS clients.
|
||||
|
||||
server:
|
||||
trust-anchor-signaling: no
|
||||
target-fetch-policy: "0 0 0 0 0"
|
||||
send-client-subnet: 1.2.3.4
|
||||
max-client-subnet-ipv4: 21
|
||||
client-subnet-always-forward: yes
|
||||
module-config: "subnetcache iterator"
|
||||
verbosity: 3
|
||||
access-control: 127.0.0.1 allow_snoop
|
||||
@ -19,7 +19,7 @@ stub-zone:
|
||||
stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET.
|
||||
CONFIG_END
|
||||
|
||||
SCENARIO_BEGIN Test prefetch option for global cache with ECS enabled
|
||||
SCENARIO_BEGIN Test prefetch option for ECS cache
|
||||
|
||||
; K.ROOT-SERVERS.NET.
|
||||
RANGE_BEGIN 0 100
|
||||
@ -78,38 +78,7 @@ RANGE_BEGIN 0 100
|
||||
RANGE_END
|
||||
|
||||
; ns.example.com.
|
||||
RANGE_BEGIN 0 10
|
||||
ADDRESS 1.2.3.4
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN NS
|
||||
SECTION ANSWER
|
||||
example.com. IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
|
||||
; response to query of interest
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
www.example.com. IN A
|
||||
SECTION ANSWER
|
||||
www.example.com. 10 IN A 10.20.30.40
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
; ns.example.com.
|
||||
RANGE_BEGIN 11 100
|
||||
RANGE_BEGIN 0 100
|
||||
ADDRESS 1.2.3.4
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
@ -154,7 +123,7 @@ SECTION QUESTION
|
||||
www.example.com. IN A
|
||||
ENTRY_END
|
||||
|
||||
; This answer should be in the global cache (because no ECS from upstream)
|
||||
; This answer will end up in the subnet cache
|
||||
STEP 2 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
@ -172,53 +141,51 @@ ENTRY_END
|
||||
; Try to trigger a prefetch
|
||||
STEP 3 TIME_PASSES ELAPSE 9
|
||||
|
||||
STEP 11 QUERY
|
||||
STEP 4 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
www.example.com. IN A
|
||||
ENTRY_END
|
||||
|
||||
; This record came from the global cache and a prefetch was triggered
|
||||
STEP 12 CHECK_ANSWER
|
||||
; This record came from the cache and a prefetch is triggered
|
||||
STEP 5 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all ttl
|
||||
REPLY QR RD RA NOERROR
|
||||
SECTION QUESTION
|
||||
www.example.com. IN A
|
||||
SECTION ANSWER
|
||||
www.example.com. 1 IN A 10.20.30.40
|
||||
www.example.com. 1 IN A 10.20.30.40
|
||||
SECTION AUTHORITY
|
||||
example.com. 3591 IN NS ns.example.com.
|
||||
example.com. 3591 IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. 3591 IN A 1.2.3.4
|
||||
ns.example.com. 3591 IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
|
||||
; Allow time to pass so that the global cache record is expired
|
||||
STEP 13 TIME_PASSES ELAPSE 2
|
||||
; Allow for some time to pass to differentiate from a cached vs resolved answer
|
||||
STEP 6 TIME_PASSES ELAPSE 1
|
||||
|
||||
; Query again to verify that the record was prefetched and stored in the ECS
|
||||
; cache (because the server replied with ECS this time)
|
||||
STEP 14 QUERY
|
||||
STEP 7 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
www.example.com. IN A
|
||||
ENTRY_END
|
||||
|
||||
; This record came from the ECS cache
|
||||
STEP 15 CHECK_ANSWER
|
||||
; This prefetched record came from the ECS cache
|
||||
STEP 8 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all ttl
|
||||
REPLY QR RD RA NOERROR
|
||||
SECTION QUESTION
|
||||
www.example.com. IN A
|
||||
www.example.com. IN A
|
||||
SECTION ANSWER
|
||||
www.example.com. 8 IN A 10.20.30.40
|
||||
www.example.com. 9 IN A 10.20.30.40
|
||||
SECTION AUTHORITY
|
||||
example.com. 3598 IN NS ns.example.com.
|
||||
example.com. 3599 IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. 3598 IN A 1.2.3.4
|
||||
ns.example.com. 3599 IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
|
||||
SCENARIO_END
|
||||
|
@ -1195,7 +1195,7 @@ int inplace_cb_query_response_call(struct module_env* env,
|
||||
}
|
||||
|
||||
struct edns_option* edns_opt_copy_region(struct edns_option* list,
|
||||
struct regional* region)
|
||||
struct regional* region)
|
||||
{
|
||||
struct edns_option* result = NULL, *cur = NULL, *s;
|
||||
while(list) {
|
||||
@ -1224,6 +1224,42 @@ struct edns_option* edns_opt_copy_region(struct edns_option* list,
|
||||
return result;
|
||||
}
|
||||
|
||||
struct edns_option* edns_opt_copy_filter_region(struct edns_option* list,
|
||||
uint16_t* filter_list, size_t filter_list_len, struct regional* region)
|
||||
{
|
||||
struct edns_option* result = NULL, *cur = NULL, *s;
|
||||
size_t i;
|
||||
while(list) {
|
||||
for(i=0; i<filter_list_len; i++)
|
||||
if(filter_list[i] == list->opt_code) goto found;
|
||||
if(i == filter_list_len) goto next;
|
||||
found:
|
||||
/* copy edns option structure */
|
||||
s = regional_alloc_init(region, list, sizeof(*list));
|
||||
if(!s) return NULL;
|
||||
s->next = NULL;
|
||||
|
||||
/* copy option data */
|
||||
if(s->opt_data) {
|
||||
s->opt_data = regional_alloc_init(region, s->opt_data,
|
||||
s->opt_len);
|
||||
if(!s->opt_data)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* link into list */
|
||||
if(cur)
|
||||
cur->next = s;
|
||||
else result = s;
|
||||
cur = s;
|
||||
|
||||
next:
|
||||
/* examine next element */
|
||||
list = list->next;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int edns_opt_compare(struct edns_option* p, struct edns_option* q)
|
||||
{
|
||||
if(!p && !q) return 0;
|
||||
|
@ -718,6 +718,12 @@ int inplace_cb_query_response_call(struct module_env* env,
|
||||
struct edns_option* edns_opt_copy_region(struct edns_option* list,
|
||||
struct regional* region);
|
||||
|
||||
/**
|
||||
* Copy a filtered edns option list allocated to the new region
|
||||
*/
|
||||
struct edns_option* edns_opt_copy_filter_region(struct edns_option* list,
|
||||
uint16_t* filter_list, size_t filter_list_len, struct regional* region);
|
||||
|
||||
/**
|
||||
* Copy edns option list allocated with malloc
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user