forked from Mirror/frr
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>
This commit is contained in:
parent
4c0a782d47
commit
30771d65b2
20
configure.ac
20
configure.ac
|
@ -55,6 +55,13 @@ dnl XXX add --pkgsrcrcdir to autoconf standard directory list somehow
|
||||||
AC_SUBST(pkgsrcdir)
|
AC_SUBST(pkgsrcdir)
|
||||||
AC_SUBST(pkgsrcrcdir)
|
AC_SUBST(pkgsrcrcdir)
|
||||||
|
|
||||||
|
AC_ARG_WITH([moduledir], [AS_HELP_STRING([--with-moduledir=DIR], [module directory (${libdir}/frr/modules)])], [
|
||||||
|
moduledir="$withval"
|
||||||
|
], [
|
||||||
|
moduledir="\${libdir}/frr/modules"
|
||||||
|
])
|
||||||
|
AC_SUBST([moduledir], [$moduledir])
|
||||||
|
|
||||||
AC_ARG_ENABLE(tcmalloc,
|
AC_ARG_ENABLE(tcmalloc,
|
||||||
AS_HELP_STRING([--enable-tcmalloc], [Turn on tcmalloc]),
|
AS_HELP_STRING([--enable-tcmalloc], [Turn on tcmalloc]),
|
||||||
[case "${enableval}" in
|
[case "${enableval}" in
|
||||||
|
@ -1347,6 +1354,14 @@ int main(void);
|
||||||
AC_DEFINE_UNQUOTED(AS_TR_CPP(SNMP_${SNMP_METHOD}),,SNMP method to interface with snmpd)
|
AC_DEFINE_UNQUOTED(AS_TR_CPP(SNMP_${SNMP_METHOD}),,SNMP method to interface with snmpd)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
dnl ------
|
||||||
|
dnl dlopen
|
||||||
|
dnl ------
|
||||||
|
AC_SEARCH_LIBS(dlopen, [dl dld], [], [
|
||||||
|
AC_MSG_ERROR([unable to find the dlopen()])
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
dnl ---------------------------
|
dnl ---------------------------
|
||||||
dnl sockaddr and netinet checks
|
dnl sockaddr and netinet checks
|
||||||
dnl ---------------------------
|
dnl ---------------------------
|
||||||
|
@ -1646,14 +1661,18 @@ AC_DEFINE_UNQUOTED(VTYSH_BIN_PATH, "$vtysh_bin",path to vtysh binary)
|
||||||
CFG_SYSCONF="$sysconfdir"
|
CFG_SYSCONF="$sysconfdir"
|
||||||
CFG_SBIN="$sbindir"
|
CFG_SBIN="$sbindir"
|
||||||
CFG_STATE="$frr_statedir"
|
CFG_STATE="$frr_statedir"
|
||||||
|
CFG_MODULE="$moduledir"
|
||||||
for I in 1 2 3 4 5 6 7 8 9 10; do
|
for I in 1 2 3 4 5 6 7 8 9 10; do
|
||||||
eval CFG_SYSCONF="\"$CFG_SYSCONF\""
|
eval CFG_SYSCONF="\"$CFG_SYSCONF\""
|
||||||
eval CFG_SBIN="\"$CFG_SBIN\""
|
eval CFG_SBIN="\"$CFG_SBIN\""
|
||||||
eval CFG_STATE="\"$CFG_STATE\""
|
eval CFG_STATE="\"$CFG_STATE\""
|
||||||
|
eval CFG_MODULE="\"$CFG_MODULE\""
|
||||||
done
|
done
|
||||||
AC_SUBST(CFG_SYSCONF)
|
AC_SUBST(CFG_SYSCONF)
|
||||||
AC_SUBST(CFG_SBIN)
|
AC_SUBST(CFG_SBIN)
|
||||||
AC_SUBST(CFG_STATE)
|
AC_SUBST(CFG_STATE)
|
||||||
|
AC_SUBST(CFG_MODULE)
|
||||||
|
AC_DEFINE_UNQUOTED(MODULE_PATH, "$CFG_MODULE", path to modules)
|
||||||
|
|
||||||
dnl ---------------------------
|
dnl ---------------------------
|
||||||
dnl Check htonl works correctly
|
dnl Check htonl works correctly
|
||||||
|
@ -1728,6 +1747,7 @@ linker flags : ${LDFLAGS} ${LIBS} ${LIBCAP} ${LIBREADLINE} ${LIBM}
|
||||||
state file directory : ${frr_statedir}
|
state file directory : ${frr_statedir}
|
||||||
config file directory : `eval echo \`echo ${sysconfdir}\``
|
config file directory : `eval echo \`echo ${sysconfdir}\``
|
||||||
example directory : `eval echo \`echo ${exampledir}\``
|
example directory : `eval echo \`echo ${exampledir}\``
|
||||||
|
module directory : ${CFG_MODULE}
|
||||||
user to run as : ${enable_user}
|
user to run as : ${enable_user}
|
||||||
group to run as : ${enable_group}
|
group to run as : ${enable_group}
|
||||||
group for vty sockets : ${enable_vty_group}
|
group for vty sockets : ${enable_vty_group}
|
||||||
|
|
|
@ -31,7 +31,9 @@ libfrr_la_SOURCES = \
|
||||||
spf_backoff.c \
|
spf_backoff.c \
|
||||||
libfrr.c \
|
libfrr.c \
|
||||||
strlcpy.c \
|
strlcpy.c \
|
||||||
strlcat.c
|
strlcat.c \
|
||||||
|
module.c \
|
||||||
|
# end
|
||||||
|
|
||||||
BUILT_SOURCES = route_types.h gitversion.h command_parse.h command_lex.h
|
BUILT_SOURCES = route_types.h gitversion.h command_parse.h command_lex.h
|
||||||
|
|
||||||
|
@ -54,6 +56,7 @@ pkginclude_HEADERS = \
|
||||||
monotime.h \
|
monotime.h \
|
||||||
spf_backoff.h \
|
spf_backoff.h \
|
||||||
srcdest_table.h \
|
srcdest_table.h \
|
||||||
|
module.h \
|
||||||
libfrr.h \
|
libfrr.h \
|
||||||
# end
|
# end
|
||||||
|
|
||||||
|
|
32
lib/libfrr.c
32
lib/libfrr.c
|
@ -28,6 +28,7 @@
|
||||||
#include "memory_vty.h"
|
#include "memory_vty.h"
|
||||||
#include "zclient.h"
|
#include "zclient.h"
|
||||||
#include "log_int.h"
|
#include "log_int.h"
|
||||||
|
#include "module.h"
|
||||||
|
|
||||||
const char frr_sysconfdir[] = SYSCONFDIR;
|
const char frr_sysconfdir[] = SYSCONFDIR;
|
||||||
const char frr_vtydir[] = DAEMON_VTY_DIR;
|
const char frr_vtydir[] = DAEMON_VTY_DIR;
|
||||||
|
@ -64,14 +65,16 @@ static const struct option lo_always[] = {
|
||||||
{ "help", no_argument, NULL, 'h' },
|
{ "help", no_argument, NULL, 'h' },
|
||||||
{ "version", no_argument, NULL, 'v' },
|
{ "version", no_argument, NULL, 'v' },
|
||||||
{ "daemon", no_argument, NULL, 'd' },
|
{ "daemon", no_argument, NULL, 'd' },
|
||||||
|
{ "module", no_argument, NULL, 'M' },
|
||||||
{ "vty_socket", required_argument, NULL, OPTION_VTYSOCK },
|
{ "vty_socket", required_argument, NULL, OPTION_VTYSOCK },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
static const struct optspec os_always = {
|
static const struct optspec os_always = {
|
||||||
"hvdi:",
|
"hvdM:",
|
||||||
" -h, --help Display this help and exit\n"
|
" -h, --help Display this help and exit\n"
|
||||||
" -v, --version Print program version\n"
|
" -v, --version Print program version\n"
|
||||||
" -d, --daemon Runs in daemon mode\n"
|
" -d, --daemon Runs in daemon mode\n"
|
||||||
|
" -M, --module Load specified module\n"
|
||||||
" --vty_socket Override vty socket path\n",
|
" --vty_socket Override vty socket path\n",
|
||||||
lo_always
|
lo_always
|
||||||
};
|
};
|
||||||
|
@ -184,12 +187,18 @@ void frr_help_exit(int status)
|
||||||
exit(status);
|
exit(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct option_chain {
|
||||||
|
struct option_chain *next;
|
||||||
|
const char *arg;
|
||||||
|
};
|
||||||
|
static struct option_chain *modules = NULL, **modnext = &modules;
|
||||||
static int errors = 0;
|
static int errors = 0;
|
||||||
|
|
||||||
static int frr_opt(int opt)
|
static int frr_opt(int opt)
|
||||||
{
|
{
|
||||||
static int vty_port_set = 0;
|
static int vty_port_set = 0;
|
||||||
static int vty_addr_set = 0;
|
static int vty_addr_set = 0;
|
||||||
|
struct option_chain *oc;
|
||||||
char *err;
|
char *err;
|
||||||
|
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
|
@ -203,6 +212,13 @@ static int frr_opt(int opt)
|
||||||
case 'd':
|
case 'd':
|
||||||
di->daemon_mode = 1;
|
di->daemon_mode = 1;
|
||||||
break;
|
break;
|
||||||
|
case 'M':
|
||||||
|
oc = XMALLOC(MTYPE_TMP, sizeof(*oc));
|
||||||
|
oc->arg = optarg;
|
||||||
|
oc->next = NULL;
|
||||||
|
*modnext = oc;
|
||||||
|
modnext = &oc->next;
|
||||||
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
if (di->flags & FRR_NO_CFG_PID_DRY)
|
if (di->flags & FRR_NO_CFG_PID_DRY)
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -298,6 +314,9 @@ int frr_getopt(int argc, char * const argv[], int *longindex)
|
||||||
struct thread_master *frr_init(void)
|
struct thread_master *frr_init(void)
|
||||||
{
|
{
|
||||||
struct thread_master *master;
|
struct thread_master *master;
|
||||||
|
struct option_chain *oc;
|
||||||
|
struct frrmod_runtime *module;
|
||||||
|
char moderr[256];
|
||||||
|
|
||||||
srandom(time(NULL));
|
srandom(time(NULL));
|
||||||
|
|
||||||
|
@ -307,6 +326,17 @@ struct thread_master *frr_init(void)
|
||||||
zlog_set_level (ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
|
zlog_set_level (ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
frrmod_init(di->module);
|
||||||
|
while (modules) {
|
||||||
|
modules = (oc = modules)->next;
|
||||||
|
module = frrmod_load(oc->arg, moderr, sizeof(moderr));
|
||||||
|
if (!module) {
|
||||||
|
fprintf(stderr, "%s\n", moderr);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
XFREE(MTYPE_TMP, oc);
|
||||||
|
}
|
||||||
|
|
||||||
zprivs_init(di->privs);
|
zprivs_init(di->privs);
|
||||||
|
|
||||||
master = thread_master_create();
|
master = thread_master_create();
|
||||||
|
|
13
lib/libfrr.h
13
lib/libfrr.h
|
@ -26,6 +26,7 @@
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "getopt.h"
|
#include "getopt.h"
|
||||||
|
#include "module.h"
|
||||||
|
|
||||||
#define FRR_NO_PRIVSEP (1 << 0)
|
#define FRR_NO_PRIVSEP (1 << 0)
|
||||||
#define FRR_NO_TCPVTY (1 << 1)
|
#define FRR_NO_TCPVTY (1 << 1)
|
||||||
|
@ -40,6 +41,7 @@ struct frr_daemon_info {
|
||||||
const char *name;
|
const char *name;
|
||||||
const char *logname;
|
const char *logname;
|
||||||
unsigned short instance;
|
unsigned short instance;
|
||||||
|
struct frrmod_runtime *module;
|
||||||
|
|
||||||
char *vty_addr;
|
char *vty_addr;
|
||||||
int vty_port;
|
int vty_port;
|
||||||
|
@ -67,15 +69,22 @@ struct frr_daemon_info {
|
||||||
* i.e. "ZEBRA" or "BGP"
|
* i.e. "ZEBRA" or "BGP"
|
||||||
*
|
*
|
||||||
* note that this macro is also a latch-on point for other changes (e.g.
|
* note that this macro is also a latch-on point for other changes (e.g.
|
||||||
* upcoming plugin support) that need to place some per-daemon things. Each
|
* upcoming module support) that need to place some per-daemon things. Each
|
||||||
* daemon should have one of these.
|
* daemon should have one of these.
|
||||||
*/
|
*/
|
||||||
#define FRR_DAEMON_INFO(execname, constname, ...) \
|
#define FRR_DAEMON_INFO(execname, constname, ...) \
|
||||||
static struct frr_daemon_info execname ##_di = { \
|
static struct frr_daemon_info execname ##_di = { \
|
||||||
.name = # execname, \
|
.name = # execname, \
|
||||||
.logname = # constname, \
|
.logname = # constname, \
|
||||||
|
.module = THIS_MODULE, \
|
||||||
__VA_ARGS__ \
|
__VA_ARGS__ \
|
||||||
};
|
}; \
|
||||||
|
FRR_COREMOD_SETUP( \
|
||||||
|
.name = # execname, \
|
||||||
|
.description = # execname " daemon", \
|
||||||
|
.version = FRR_VERSION, \
|
||||||
|
) \
|
||||||
|
/* end */
|
||||||
|
|
||||||
extern void frr_preinit(struct frr_daemon_info *daemon,
|
extern void frr_preinit(struct frr_daemon_info *daemon,
|
||||||
int argc, char **argv);
|
int argc, char **argv);
|
||||||
|
|
159
lib/module.c
Normal file
159
lib/module.c
Normal file
|
@ -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
|
104
lib/module.h
Normal file
104
lib/module.h
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _FRR_MODULE_H
|
||||||
|
#define _FRR_MODULE_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#if !defined(__GNUC__)
|
||||||
|
# error module code needs GCC visibility extensions
|
||||||
|
#elif __GNUC__ < 4
|
||||||
|
# error module code needs GCC visibility extensions
|
||||||
|
#else
|
||||||
|
# define DSO_PUBLIC __attribute__ ((visibility ("default")))
|
||||||
|
# define DSO_SELF __attribute__ ((visibility ("protected")))
|
||||||
|
# define DSO_LOCAL __attribute__ ((visibility ("hidden")))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct frrmod_runtime;
|
||||||
|
|
||||||
|
struct frrmod_info {
|
||||||
|
/* single-line few-word title */
|
||||||
|
const char *name;
|
||||||
|
/* human-readable version number, should not contain spaces */
|
||||||
|
const char *version;
|
||||||
|
/* one-paragraph description */
|
||||||
|
const char *description;
|
||||||
|
|
||||||
|
int (*init)(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* primary entry point structure to be present in loadable module under
|
||||||
|
* "_frrmod_this_module" dlsym() name
|
||||||
|
*
|
||||||
|
* note space for future extensions is reserved below, so other modules
|
||||||
|
* (e.g. memory management, hooks) can add fields
|
||||||
|
*
|
||||||
|
* const members/info are in frrmod_info.
|
||||||
|
*/
|
||||||
|
struct frrmod_runtime {
|
||||||
|
struct frrmod_runtime *next;
|
||||||
|
|
||||||
|
const struct frrmod_info *info;
|
||||||
|
void *dl_handle;
|
||||||
|
bool finished_loading;
|
||||||
|
|
||||||
|
char *load_name;
|
||||||
|
char *load_args;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* space-reserving foo */
|
||||||
|
struct _frrmod_runtime_size {
|
||||||
|
struct frrmod_runtime r;
|
||||||
|
/* this will barf if frrmod_runtime exceeds 1024 bytes ... */
|
||||||
|
uint8_t space[1024 - sizeof(struct frrmod_runtime)];
|
||||||
|
};
|
||||||
|
union _frrmod_runtime_u {
|
||||||
|
struct frrmod_runtime r;
|
||||||
|
struct _frrmod_runtime_size s;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern union _frrmod_runtime_u _frrmod_this_module;
|
||||||
|
#define THIS_MODULE (&_frrmod_this_module.r)
|
||||||
|
|
||||||
|
#define FRR_COREMOD_SETUP(...) \
|
||||||
|
static const struct frrmod_info _frrmod_info = { __VA_ARGS__ }; \
|
||||||
|
DSO_LOCAL union _frrmod_runtime_u _frrmod_this_module = { \
|
||||||
|
.r.info = &_frrmod_info, \
|
||||||
|
};
|
||||||
|
#define FRR_MODULE_SETUP(...) \
|
||||||
|
FRR_COREMOD_SETUP(__VA_ARGS__) \
|
||||||
|
DSO_SELF struct frrmod_runtime *frr_module = &_frrmod_this_module.r;
|
||||||
|
|
||||||
|
extern struct frrmod_runtime *frrmod_list;
|
||||||
|
|
||||||
|
extern void frrmod_init(struct frrmod_runtime *modinfo);
|
||||||
|
extern struct frrmod_runtime *frrmod_load(const char *spec,
|
||||||
|
char *err, size_t err_len);
|
||||||
|
#if 0
|
||||||
|
/* not implemented yet */
|
||||||
|
extern void frrmod_unload(struct frrmod_runtime *module);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _FRR_MODULE_H */
|
Loading…
Reference in a new issue