diff options
| author | David Lamparter <equinox@opensourcerouting.org> | 2016-05-31 19:25:46 +0200 |
|---|---|---|
| committer | David Lamparter <equinox@opensourcerouting.org> | 2017-03-24 13:02:05 +0100 |
| commit | 30771d65b23e4ef15a8298357b70fc083c699750 (patch) | |
| tree | 3916bace6127d166780fdd187b4908f2f7e12e7b /lib/module.c | |
| parent | 4c0a782d477d527fb795640225c5f22767105f32 (diff) | |
lib: dynamic module loading
This adds a "-M" option to each daemon, to load dynamic modules at
startup. Modules are by default located in /usr/lib/frr/modules (lib64
if appropriate). Unloading or loading at runtime is not supported at
this point to keep things simple.
Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
Diffstat (limited to 'lib/module.c')
| -rw-r--r-- | lib/module.c | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/lib/module.c b/lib/module.c new file mode 100644 index 0000000000..4ebe3c0da2 --- /dev/null +++ b/lib/module.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2015-16 David Lamparter, for NetDEF, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "config.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <limits.h> +#include <dlfcn.h> + +#include "module.h" +#include "memory.h" +#include "version.h" + +DEFINE_MTYPE_STATIC(LIB, MODULE_LOADNAME, "Module loading name") +DEFINE_MTYPE_STATIC(LIB, MODULE_LOADARGS, "Module loading arguments") + +static struct frrmod_info frrmod_default_info = { + .name = "libfrr", + .version = FRR_VERSION, + .description = "libfrr core module", +}; +union _frrmod_runtime_u frrmod_default = { + .r.info = &frrmod_default_info, + .r.finished_loading = 1, +}; + +// if defined(HAVE_SYS_WEAK_ALIAS_ATTRIBUTE) +// union _frrmod_runtime_u _frrmod_this_module +// __attribute__((weak, alias("frrmod_default"))); +// elif defined(HAVE_SYS_WEAK_ALIAS_PRAGMA) +#pragma weak _frrmod_this_module = frrmod_default +// else +// error need weak symbol support +// endif + +struct frrmod_runtime *frrmod_list = &frrmod_default.r; +static struct frrmod_runtime **frrmod_last = &frrmod_default.r.next; +static const char *execname = NULL; + +void frrmod_init(struct frrmod_runtime *modinfo) +{ + modinfo->finished_loading = 1; + *frrmod_last = modinfo; + frrmod_last = &modinfo->next; + + execname = modinfo->info->name; +} + +struct frrmod_runtime *frrmod_load(const char *spec, + char *err, size_t err_len) +{ + void *handle = NULL; + char name[PATH_MAX], fullpath[PATH_MAX], *args; + struct frrmod_runtime *rtinfo, **rtinfop; + const struct frrmod_info *info; + + snprintf(name, sizeof(name), "%s", spec); + args = strchr(name, ':'); + if (args) + *args++ = '\0'; + + if (!strchr(name, '/')) { + if (!handle && execname) { + snprintf(fullpath, sizeof(fullpath), "%s/%s_%s.so", + MODULE_PATH, execname, name); + handle = dlopen(fullpath, RTLD_NOW | RTLD_GLOBAL); + } + if (!handle) { + snprintf(fullpath, sizeof(fullpath), "%s/%s.so", + MODULE_PATH, name); + handle = dlopen(fullpath, RTLD_NOW | RTLD_GLOBAL); + } + } + if (!handle) { + snprintf(fullpath, sizeof(fullpath), "%s", name); + handle = dlopen(fullpath, RTLD_NOW | RTLD_GLOBAL); + } + if (!handle) { + if (err) + snprintf(err, err_len, + "loading module \"%s\" failed: %s", + name, dlerror()); + return NULL; + } + + rtinfop = dlsym(handle, "frr_module"); + if (!rtinfop) { + dlclose(handle); + if (err) + snprintf(err, err_len, + "\"%s\" is not a Quagga module: %s", + name, dlerror()); + return NULL; + } + rtinfo = *rtinfop; + rtinfo->load_name = XSTRDUP(MTYPE_MODULE_LOADNAME, name); + rtinfo->dl_handle = handle; + if (args) + rtinfo->load_args = XSTRDUP(MTYPE_MODULE_LOADARGS, args); + info = rtinfo->info; + + if (rtinfo->finished_loading) { + dlclose(handle); + if (err) + snprintf(err, err_len, + "module \"%s\" already loaded", + name); + goto out_fail; + } + + if (info->init && info->init()) { + dlclose(handle); + if (err) + snprintf(err, err_len, + "module \"%s\" initialisation failed", + name); + goto out_fail; + } + + rtinfo->finished_loading = 1; + + *frrmod_last = rtinfo; + frrmod_last = &rtinfo->next; + return rtinfo; + +out_fail: + if (rtinfo->load_args) + XFREE(MTYPE_MODULE_LOADARGS, rtinfo->load_args); + XFREE(MTYPE_MODULE_LOADNAME, rtinfo->load_name); + return NULL; +} + +#if 0 +void frrmod_unload(struct frrmod_runtime *module) +{ +} +#endif |
