Commit b94945e6 authored by Evan Hunt's avatar Evan Hunt
Browse files

refactor to support multiple module instances

- use a per-view module list instead of global hook_modules
- create an 'instance' pointer when registering modules, store it in
  the module structure, and use it as action_data when calling
  hook functions - this enables multiple module instances to be set
  up in parallel
- also some nomenclature changes and cleanup
parent 9df0bdc9
......@@ -46,6 +46,7 @@
#include <dns/rdataset.h>
#include <dns/result.h>
#include <dns/types.h>
#include <dns/view.h>
#define CHECK(op) \
do { \
......@@ -76,15 +77,27 @@ typedef struct filter_data {
uint32_t flags;
} filter_data_t;
/*
* Memory pool for use with persistent data.
*/
static isc_mempool_t *datapool = NULL;
typedef struct filter_instance {
ns_module_t *module;
isc_mem_t *mctx;
/*
* Hash table associating a client object with its persistent data.
*/
static isc_ht_t *client_ht = NULL;
/*
* Memory pool for use with persistent data.
*/
isc_mempool_t *datapool;
/*
* Hash table associating a client object with its persistent data.
*/
isc_ht_t *ht;
/*
* Values configured when the module is loaded.
*/
filter_aaaa_t v4_aaaa;
filter_aaaa_t v6_aaaa;
dns_acl_t *aaaa_acl;
} filter_instance_t;
/*
* Per-client flags set by this module
......@@ -100,62 +113,79 @@ static isc_ht_t *client_ht = NULL;
NS_QUERYATTR_RECURSIONOK) != 0)
/*
* Hook registration structures: pointers to these structures will
* be added to a hook table when this module is registered.
* Forward declarations of functions referenced in install_hooks().
*/
static bool
filter_qctx_initialize(void *arg, void *cbdata, isc_result_t *resp);
static const ns_hook_t filter_init = {
.action = filter_qctx_initialize,
.action_data = &client_ht,
};
static bool
filter_respond_begin(void *arg, void *cbdata, isc_result_t *resp);
static const ns_hook_t filter_respbegin = {
.action = filter_respond_begin,
.action_data = &client_ht,
};
static bool
filter_respond_any_found(void *arg, void *cbdata, isc_result_t *resp);
static const ns_hook_t filter_respanyfound = {
.action = filter_respond_any_found,
.action_data = &client_ht,
};
static bool
filter_prep_response_begin(void *arg, void *cbdata, isc_result_t *resp);
static const ns_hook_t filter_prepresp = {
.action = filter_prep_response_begin,
.action_data = &client_ht,
};
static bool
filter_query_done_send(void *arg, void *cbdata, isc_result_t *resp);
static const ns_hook_t filter_donesend = {
.action = filter_query_done_send,
.action_data = &client_ht,
};
static bool
filter_qctx_destroy(void *arg, void *cbdata, isc_result_t *resp);
static const ns_hook_t filter_destroy = {
.action = filter_qctx_destroy,
.action_data = &client_ht,
};
/*%
* Register the functions to be called at each hook point in 'hooktable', using
* memory context 'mctx' for allocating copies of stack-allocated structures
* passed to ns_hook_add(). Make sure 'inst' will be passed as the 'cbdata'
* argument to every callback.
*/
static void
install_hooks(ns_hooktable_t *hooktable, isc_mem_t *mctx,
filter_instance_t *inst)
{
const ns_hook_t filter_init = {
.action = filter_qctx_initialize,
.action_data = inst,
};
const ns_hook_t filter_respbegin = {
.action = filter_respond_begin,
.action_data = inst,
};
const ns_hook_t filter_respanyfound = {
.action = filter_respond_any_found,
.action_data = inst,
};
const ns_hook_t filter_prepresp = {
.action = filter_prep_response_begin,
.action_data = inst,
};
const ns_hook_t filter_donesend = {
.action = filter_query_done_send,
.action_data = inst,
};
const ns_hook_t filter_destroy = {
.action = filter_qctx_destroy,
.action_data = inst,
};
ns_hook_add(hooktable, mctx, -
NS_QUERY_QCTX_INITIALIZED, &filter_init);
ns_hook_add(hooktable, mctx,
NS_QUERY_RESPOND_BEGIN, &filter_respbegin);
ns_hook_add(hooktable, mctx,
NS_QUERY_RESPOND_ANY_FOUND, &filter_respanyfound);
ns_hook_add(hooktable, mctx,
NS_QUERY_PREP_RESPONSE_BEGIN, &filter_prepresp);
ns_hook_add(hooktable, mctx,
NS_QUERY_DONE_SEND, &filter_donesend);
ns_hook_add(hooktable, mctx,
NS_QUERY_QCTX_DESTROYED, &filter_destroy);
}
/**
** Support for parsing of parameters and configuration of the module.
**/
/*
* Values configured when the module is loaded.
*/
static filter_aaaa_t v4_aaaa = NONE;
static filter_aaaa_t v6_aaaa = NONE;
static dns_acl_t *aaaa_acl = NULL;
/*
* Support for parsing of parameters.
*/
......@@ -220,8 +250,8 @@ parse_filter_aaaa_on(const cfg_obj_t *param_obj, const char *param_name,
}
static isc_result_t
parse_parameters(const char *parameters, const void *cfg,
void *actx, ns_hookctx_t *hctx)
parse_parameters(filter_instance_t *inst, const char *parameters,
const void *cfg, void *actx, ns_hookctx_t *hctx)
{
isc_result_t result = ISC_R_SUCCESS;
cfg_parser_t *parser = NULL;
......@@ -236,18 +266,18 @@ parse_parameters(const char *parameters, const void *cfg,
CHECK(cfg_parse_buffer(parser, &b, &cfg_type_parameters,
&param_obj));
CHECK(parse_filter_aaaa_on(param_obj, "filter-aaaa-on-v4", &v4_aaaa));
CHECK(parse_filter_aaaa_on(param_obj, "filter-aaaa-on-v6", &v6_aaaa));
CHECK(parse_filter_aaaa_on(param_obj, "filter-aaaa-on-v4",
&inst->v4_aaaa));
CHECK(parse_filter_aaaa_on(param_obj, "filter-aaaa-on-v6",
&inst->v6_aaaa));
obj = NULL;
result = cfg_map_get(param_obj, "filter-aaaa", &obj);
if (result == ISC_R_SUCCESS) {
CHECK(cfg_acl_fromconfig(obj, (const cfg_obj_t *) cfg,
hctx->lctx,
(cfg_aclconfctx_t *) actx,
hctx->mctx, 0, &aaaa_acl));
hctx->lctx, (cfg_aclconfctx_t *) actx,
hctx->mctx, 0, &inst->aaaa_acl));
} else {
CHECK(dns_acl_any(hctx->mctx, &aaaa_acl));
CHECK(dns_acl_any(hctx->mctx, &inst->aaaa_acl));
}
cleanup:
......@@ -269,46 +299,36 @@ parse_parameters(const char *parameters, const void *cfg,
**/
/*
* Called by ns_hookmodule_load() to register hook functions into
* Called by ns_module_load() to register hook functions into
* a hook table.
*/
isc_result_t
hook_register(const char *parameters,
const char *cfg_file, unsigned long cfg_line,
const void *cfg, void *actx,
ns_hookctx_t *hctx, ns_hooktable_t *hooktable, void **instp)
const void *cfg, void *actx, ns_hookctx_t *hctx,
ns_hooktable_t *hooktable, void **instp)
{
filter_instance_t *inst = NULL;
isc_result_t result;
UNUSED(instp);
isc_log_write(hctx->lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_HOOKS, ISC_LOG_INFO,
"loading 'filter-aaaa' "
"registering 'filter-aaaa' "
"module from %s:%lu, %s parameters",
cfg_file, cfg_line, parameters != NULL ? "with" : "no");
inst = isc_mem_get(hctx->mctx, sizeof(*inst));
memset(inst, 0, sizeof(*inst));
isc_mem_attach(hctx->mctx, &inst->mctx);
if (parameters != NULL) {
CHECK(parse_parameters(parameters, cfg, actx, hctx));
CHECK(parse_parameters(inst, parameters, cfg, actx, hctx));
}
ns_hook_add(hooktable, hctx->mctx, NS_QUERY_QCTX_INITIALIZED,
&filter_init);
ns_hook_add(hooktable, hctx->mctx, NS_QUERY_RESPOND_BEGIN,
&filter_respbegin);
ns_hook_add(hooktable, hctx->mctx, NS_QUERY_RESPOND_ANY_FOUND,
&filter_respanyfound);
ns_hook_add(hooktable, hctx->mctx, NS_QUERY_PREP_RESPONSE_BEGIN,
&filter_prepresp);
ns_hook_add(hooktable, hctx->mctx, NS_QUERY_DONE_SEND,
&filter_donesend);
ns_hook_add(hooktable, hctx->mctx, NS_QUERY_QCTX_DESTROYED,
&filter_destroy);
CHECK(isc_mempool_create(hctx->mctx, sizeof(filter_data_t),
&datapool));
CHECK(isc_ht_init(&client_ht, hctx->mctx, 16));
&inst->datapool));
CHECK(isc_ht_init(&inst->ht, hctx->mctx, 16));
/*
* Fill the mempool with 1K filter_aaaa state objects at
......@@ -320,36 +340,45 @@ hook_register(const char *parameters,
* so that they'll always be returned to the pool and not
* freed until the pool is destroyed on shutdown.
*/
isc_mempool_setfillcount(datapool, 1024);
isc_mempool_setfreemax(datapool, UINT_MAX);
isc_mempool_setfillcount(inst->datapool, 1024);
isc_mempool_setfreemax(inst->datapool, UINT_MAX);
/*
* Set hook points in the view's hooktable.
*/
install_hooks(hooktable, hctx->mctx, inst);
*instp = inst;
cleanup:
if (result != ISC_R_SUCCESS) {
if (datapool != NULL) {
isc_mempool_destroy(&datapool);
}
if (result != ISC_R_SUCCESS && inst != NULL) {
hook_destroy((void **) &inst);
}
return (result);
}
/*
* Called by ns_hookmodule_unload_all(); frees memory allocated by
* Called by ns_module_unload(); frees memory allocated by
* the module when it was registered.
*/
void
hook_destroy(void **instp) {
UNUSED(instp);
filter_instance_t *inst = (filter_instance_t *) *instp;
if (client_ht != NULL) {
isc_ht_destroy(&client_ht);
if (inst->ht != NULL) {
isc_ht_destroy(&inst->ht);
}
if (datapool != NULL) {
isc_mempool_destroy(&datapool);
if (inst->datapool != NULL) {
isc_mempool_destroy(&inst->datapool);
}
if (aaaa_acl != NULL) {
dns_acl_detach(&aaaa_acl);
if (inst->aaaa_acl != NULL) {
dns_acl_detach(&inst->aaaa_acl);
}
isc_mem_putanddetach(&inst->mctx, inst, sizeof(*inst));
*instp = NULL;
return;
}
......@@ -407,22 +436,22 @@ is_v6_client(ns_client_t *client) {
}
static filter_data_t *
client_state_get(const query_ctx_t *qctx, isc_ht_t **htp) {
client_state_get(const query_ctx_t *qctx, filter_instance_t *inst) {
filter_data_t *client_state = NULL;
isc_result_t result;
result = isc_ht_find(*htp, (const unsigned char *)&qctx->client,
result = isc_ht_find(inst->ht, (const unsigned char *)&qctx->client,
sizeof(qctx->client), (void **)&client_state);
return (result == ISC_R_SUCCESS ? client_state : NULL);
}
static void
client_state_create(const query_ctx_t *qctx, isc_ht_t **htp) {
client_state_create(const query_ctx_t *qctx, filter_instance_t *inst) {
filter_data_t *client_state;
isc_result_t result;
client_state = isc_mempool_get(datapool);
client_state = isc_mempool_get(inst->datapool);
if (client_state == NULL) {
return;
}
......@@ -430,25 +459,25 @@ client_state_create(const query_ctx_t *qctx, isc_ht_t **htp) {
client_state->mode = NONE;
client_state->flags = 0;
result = isc_ht_add(*htp, (const unsigned char *)&qctx->client,
result = isc_ht_add(inst->ht, (const unsigned char *)&qctx->client,
sizeof(qctx->client), client_state);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
}
static void
client_state_destroy(const query_ctx_t *qctx, isc_ht_t **htp) {
filter_data_t *client_state = client_state_get(qctx, htp);
client_state_destroy(const query_ctx_t *qctx, filter_instance_t *inst) {
filter_data_t *client_state = client_state_get(qctx, inst);
isc_result_t result;
if (client_state == NULL) {
return;
}
result = isc_ht_delete(*htp, (const unsigned char *)&qctx->client,
result = isc_ht_delete(inst->ht, (const unsigned char *)&qctx->client,
sizeof(qctx->client));
RUNTIME_CHECK(result == ISC_R_SUCCESS);
isc_mempool_put(datapool, client_state);
isc_mempool_put(inst->datapool, client_state);
}
/*%
......@@ -570,14 +599,14 @@ process_section(const section_filter_t *filter) {
static bool
filter_qctx_initialize(void *arg, void *cbdata, isc_result_t *resp) {
query_ctx_t *qctx = (query_ctx_t *) arg;
isc_ht_t **htp = (isc_ht_t **) cbdata;
filter_instance_t *inst = (filter_instance_t *) cbdata;
filter_data_t *client_state;
*resp = ISC_R_UNSET;
client_state = client_state_get(qctx, htp);
client_state = client_state_get(qctx, inst);
if (client_state == NULL) {
client_state_create(qctx, htp);
client_state_create(qctx, inst);
}
return (false);
......@@ -591,8 +620,8 @@ filter_qctx_initialize(void *arg, void *cbdata, isc_result_t *resp) {
static bool
filter_prep_response_begin(void *arg, void *cbdata, isc_result_t *resp) {
query_ctx_t *qctx = (query_ctx_t *) arg;
isc_ht_t **htp = (isc_ht_t **) cbdata;
filter_data_t *client_state = client_state_get(qctx, htp);
filter_instance_t *inst = (filter_instance_t *) cbdata;
filter_data_t *client_state = client_state_get(qctx, inst);
isc_result_t result;
*resp = ISC_R_UNSET;
......@@ -601,19 +630,19 @@ filter_prep_response_begin(void *arg, void *cbdata, isc_result_t *resp) {
return (false);
}
if (v4_aaaa != NONE || v6_aaaa != NONE) {
if (inst->v4_aaaa != NONE || inst->v6_aaaa != NONE) {
result = ns_client_checkaclsilent(qctx->client, NULL,
aaaa_acl, true);
inst->aaaa_acl, true);
if (result == ISC_R_SUCCESS &&
v4_aaaa != NONE &&
inst->v4_aaaa != NONE &&
is_v4_client(qctx->client))
{
client_state->mode = v4_aaaa;
client_state->mode = inst->v4_aaaa;
} else if (result == ISC_R_SUCCESS &&
v6_aaaa != NONE &&
inst->v6_aaaa != NONE &&
is_v6_client(qctx->client))
{
client_state->mode = v6_aaaa;
client_state->mode = inst->v6_aaaa;
}
}
......@@ -630,8 +659,8 @@ filter_prep_response_begin(void *arg, void *cbdata, isc_result_t *resp) {
static bool
filter_respond_begin(void *arg, void *cbdata, isc_result_t *resp) {
query_ctx_t *qctx = (query_ctx_t *) arg;
isc_ht_t **htp = (isc_ht_t **) cbdata;
filter_data_t *client_state = client_state_get(qctx, htp);
filter_instance_t *inst = (filter_instance_t *) cbdata;
filter_data_t *client_state = client_state_get(qctx, inst);
isc_result_t result = ISC_R_UNSET;
*resp = ISC_R_UNSET;
......@@ -734,8 +763,8 @@ filter_respond_begin(void *arg, void *cbdata, isc_result_t *resp) {
static bool
filter_respond_any_found(void *arg, void *cbdata, isc_result_t *resp) {
query_ctx_t *qctx = (query_ctx_t *) arg;
isc_ht_t **htp = (isc_ht_t **) cbdata;
filter_data_t *client_state = client_state_get(qctx, htp);
filter_instance_t *inst = (filter_instance_t *) cbdata;
filter_data_t *client_state = client_state_get(qctx, inst);
*resp = ISC_R_UNSET;
......@@ -769,8 +798,8 @@ filter_respond_any_found(void *arg, void *cbdata, isc_result_t *resp) {
static bool
filter_query_done_send(void *arg, void *cbdata, isc_result_t *resp) {
query_ctx_t *qctx = (query_ctx_t *) arg;
isc_ht_t **htp = (isc_ht_t **) cbdata;
filter_data_t *client_state = client_state_get(qctx, htp);
filter_instance_t *inst = (filter_instance_t *) cbdata;
filter_data_t *client_state = client_state_get(qctx, inst);
*resp = ISC_R_UNSET;
......@@ -805,7 +834,7 @@ filter_query_done_send(void *arg, void *cbdata, isc_result_t *resp) {
static bool
filter_qctx_destroy(void *arg, void *cbdata, isc_result_t *resp) {
query_ctx_t *qctx = (query_ctx_t *) arg;
isc_ht_t **htp = (isc_ht_t **) cbdata;
filter_instance_t *inst = (filter_instance_t *) cbdata;
*resp = ISC_R_UNSET;
......@@ -813,7 +842,7 @@ filter_qctx_destroy(void *arg, void *cbdata, isc_result_t *resp) {
return (false);
}
client_state_destroy(qctx, htp);
client_state_destroy(qctx, inst);
return (false);
}
......@@ -1537,7 +1537,7 @@ configure_dyndb(const cfg_obj_t *dyndb, isc_mem_t *mctx,
}
static isc_result_t
configure_hook(ns_hooktable_t *hooktable, const cfg_obj_t *hook,
configure_hook(dns_view_t *view, const cfg_obj_t *hook,
const cfg_obj_t *config, ns_hookctx_t *hctx)
{
isc_result_t result = ISC_R_SUCCESS;
......@@ -1562,14 +1562,14 @@ configure_hook(ns_hooktable_t *hooktable, const cfg_obj_t *hook,
if (obj != NULL && cfg_obj_isstring(obj)) {
parameters = cfg_obj_asstring(obj);
}
result = ns_hookmodule_load(library, parameters,
cfg_obj_file(obj), cfg_obj_line(obj),
config, named_g_aclconfctx,
hctx, hooktable);
result = ns_module_load(library, parameters,
cfg_obj_file(obj), cfg_obj_line(obj),
config, named_g_aclconfctx,
hctx, view->modlist, view->hooktable);
if (result != ISC_R_SUCCESS) {
isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
"%s: hook module configuration failed: %s",
"%s: module configuration failed: %s",
library, isc_result_totext(result));
}
return (result);
......@@ -5314,6 +5314,9 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
CHECK(ns_hooktable_create(view->mctx,
(ns_hooktable_t **) &view->hooktable));
view->hooktable_free = ns_hooktable_free;
ns_modlist_create(view->mctx, (ns_modlist_t **)&view->modlist);
view->modlist_free = ns_modlist_free;
}
for (element = cfg_list_first(hook_list);
......@@ -5322,7 +5325,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
{
const cfg_obj_t *hook = cfg_listelt_value(element);
CHECK(configure_hook(view->hooktable, hook, config, hctx));
CHECK(configure_hook(view, hook, config, hctx));
}
#endif
......@@ -8062,10 +8065,9 @@ load_configuration(const char *filename, named_server_t *server,
CHECK(cfg_aclconfctx_create(named_g_mctx, &named_g_aclconfctx));
/*
* Shut down all dyndb and hook module instances.
* Shut down all dyndb instances.
*/
dns_dyndb_cleanup(false);
ns_hookmodule_unload_all();
/*
* Parse the global default pseudo-config file.
......@@ -9547,10 +9549,9 @@ shutdown_server(isc_task_t *task, isc_event_t *event) {
}
/*
* Shut down all dyndb and hook module instances.
* Shut down all dyndb instances.
*/
dns_dyndb_cleanup(true);
ns_hookmodule_unload_all();
while ((nsc = ISC_LIST_HEAD(server->cachelist)) != NULL) {
ISC_LIST_UNLINK(server->cachelist, nsc, link);
......
......@@ -236,8 +236,14 @@ struct dns_view {
dns_dtmsgtype_t dttypes; /* Dnstap message types
to log */
/* Registered module instances */
void *modlist;
void (*modlist_free)(isc_mem_t *, void **);
/* Hook table */
void *hooktable; /* ns_hooktable */
void (*hooktable_free)(isc_mem_t *, void **);
};
#define DNS_VIEW_MAGIC ISC_MAGIC('V','i','e','w')
......
......@@ -256,6 +256,8 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
view->dtenv = NULL;
view->dttypes = 0;
view->modlist = NULL;
view->modlist_free = NULL;
view->hooktable = NULL;
view->hooktable_free = NULL;
......@@ -551,6 +553,9 @@ destroy(dns_view_t *view) {
if (view->hooktable != NULL && view->hooktable_free != NULL) {
view->hooktable_free(view->mctx, &view->hooktable);
}
if (view->modlist != NULL && view->modlist_free != NULL) {
view->modlist_free(view->mctx, &view->modlist);
}
isc_mem_putanddetach(&view->mctx, view, sizeof(*view));
}
......
......@@ -42,29 +42,19 @@
} \
} while (0)
typedef struct ns_hook_module ns_hook_module_t;
struct ns_hook_module {
isc_mem_t *mctx;
void *handle;
char *modpath;
ns_hook_register_t *register_func;
ns_hook_destroy_t *destroy_func;
void *inst;
LINK(ns_hook_module_t) link;
struct ns_module {
isc_mem_t *mctx;
void *handle;
void *inst;
char *modpath;
ns_hook_register_t *register_func;
ns_hook_destroy_t *destroy_func;
LINK(ns_module_t) link;
};
static ns_hooklist_t default_hooktable[NS_HOOKPOINTS_COUNT];
LIBNS_EXTERNAL_DATA ns_hooktable_t *ns__hook_table = &default_hooktable;
/*
* List of hook modules.
*
* These are stored here so they can be cleaned up on shutdown.
* (The order in which they are stored is not important.)
*/
static ISC_LIST(ns_hook_module_t) hook_modules;
static bool hook_modules_initialized = false;
#if HAVE_DLFCN_H && HAVE_DLOPEN
static isc_result_t
load_symbol(void *handle, const char *modpath,
......@@ -103,10 +93,10 @@ load_symbol(void *handle, const char *modpath,
}
static isc_result_t
load_library(isc_mem_t *mctx, const char *modpath, ns_hook_module_t **hmodp) {
load_library(isc_mem_t *mctx, const char *modpath, ns_module_t **hmodp) {