AC_SUBST(pkgsrcdir)
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,
AS_HELP_STRING([--enable-tcmalloc], [Turn on tcmalloc]),
[case "${enableval}" in
AC_DEFINE_UNQUOTED(AS_TR_CPP(SNMP_${SNMP_METHOD}),,SNMP method to interface with snmpd)
fi
+dnl ------
+dnl dlopen
+dnl ------
+AC_SEARCH_LIBS(dlopen, [dl dld], [], [
+ AC_MSG_ERROR([unable to find the dlopen()])
+])
+
+
dnl ---------------------------
dnl sockaddr and netinet checks
dnl ---------------------------
CFG_SYSCONF="$sysconfdir"
CFG_SBIN="$sbindir"
CFG_STATE="$frr_statedir"
+CFG_MODULE="$moduledir"
for I in 1 2 3 4 5 6 7 8 9 10; do
eval CFG_SYSCONF="\"$CFG_SYSCONF\""
eval CFG_SBIN="\"$CFG_SBIN\""
eval CFG_STATE="\"$CFG_STATE\""
+ eval CFG_MODULE="\"$CFG_MODULE\""
done
AC_SUBST(CFG_SYSCONF)
AC_SUBST(CFG_SBIN)
AC_SUBST(CFG_STATE)
+AC_SUBST(CFG_MODULE)
+AC_DEFINE_UNQUOTED(MODULE_PATH, "$CFG_MODULE", path to modules)
dnl ---------------------------
dnl Check htonl works correctly
state file directory : ${frr_statedir}
config file directory : `eval echo \`echo ${sysconfdir}\``
example directory : `eval echo \`echo ${exampledir}\``
+module directory : ${CFG_MODULE}
user to run as : ${enable_user}
group to run as : ${enable_group}
group for vty sockets : ${enable_vty_group}
spf_backoff.c \
libfrr.c \
strlcpy.c \
- strlcat.c
+ strlcat.c \
+ module.c \
+ # end
BUILT_SOURCES = route_types.h gitversion.h command_parse.h command_lex.h
monotime.h \
spf_backoff.h \
srcdest_table.h \
+ module.h \
libfrr.h \
# end
#include "memory_vty.h"
#include "zclient.h"
#include "log_int.h"
+#include "module.h"
const char frr_sysconfdir[] = SYSCONFDIR;
const char frr_vtydir[] = DAEMON_VTY_DIR;
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'v' },
{ "daemon", no_argument, NULL, 'd' },
+ { "module", no_argument, NULL, 'M' },
{ "vty_socket", required_argument, NULL, OPTION_VTYSOCK },
{ NULL }
};
static const struct optspec os_always = {
- "hvdi:",
+ "hvdM:",
" -h, --help Display this help and exit\n"
" -v, --version Print program version\n"
" -d, --daemon Runs in daemon mode\n"
+ " -M, --module Load specified module\n"
" --vty_socket Override vty socket path\n",
lo_always
};
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 frr_opt(int opt)
{
static int vty_port_set = 0;
static int vty_addr_set = 0;
+ struct option_chain *oc;
char *err;
switch (opt) {
case 'd':
di->daemon_mode = 1;
break;
+ case 'M':
+ oc = XMALLOC(MTYPE_TMP, sizeof(*oc));
+ oc->arg = optarg;
+ oc->next = NULL;
+ *modnext = oc;
+ modnext = &oc->next;
+ break;
case 'i':
if (di->flags & FRR_NO_CFG_PID_DRY)
return 1;
struct thread_master *frr_init(void)
{
struct thread_master *master;
+ struct option_chain *oc;
+ struct frrmod_runtime *module;
+ char moderr[256];
srandom(time(NULL));
zlog_set_level (ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
#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);
master = thread_master_create();
#include "thread.h"
#include "log.h"
#include "getopt.h"
+#include "module.h"
#define FRR_NO_PRIVSEP (1 << 0)
#define FRR_NO_TCPVTY (1 << 1)
const char *name;
const char *logname;
unsigned short instance;
+ struct frrmod_runtime *module;
char *vty_addr;
int vty_port;
* i.e. "ZEBRA" or "BGP"
*
* 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.
*/
#define FRR_DAEMON_INFO(execname, constname, ...) \
static struct frr_daemon_info execname ##_di = { \
.name = # execname, \
.logname = # constname, \
+ .module = THIS_MODULE, \
__VA_ARGS__ \
- };
+ }; \
+ FRR_COREMOD_SETUP( \
+ .name = # execname, \
+ .description = # execname " daemon", \
+ .version = FRR_VERSION, \
+ ) \
+ /* end */
extern void frr_preinit(struct frr_daemon_info *daemon,
int argc, char **argv);
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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 */