1 // SPDX-License-Identifier: ISC
3 * Copyright (c) 2015-16 David Lamparter, for NetDEF, Inc.
17 #include "lib/version.h"
20 DEFINE_MTYPE_STATIC(LIB
, MODULE_LOADNAME
, "Module loading name");
21 DEFINE_MTYPE_STATIC(LIB
, MODULE_LOADARGS
, "Module loading arguments");
22 DEFINE_MTYPE_STATIC(LIB
, MODULE_LOAD_ERR
, "Module loading error");
24 static struct frrmod_info frrmod_default_info
= {
26 .version
= FRR_VERSION
,
27 .description
= "libfrr core module",
29 union _frrmod_runtime_u frrmod_default
= {
32 .info
= &frrmod_default_info
,
33 .finished_loading
= 1,
39 // if defined(HAVE_SYS_WEAK_ALIAS_ATTRIBUTE)
40 // union _frrmod_runtime_u _frrmod_this_module
41 // __attribute__((weak, alias("frrmod_default")));
42 // elif defined(HAVE_SYS_WEAK_ALIAS_PRAGMA)
43 #pragma weak _frrmod_this_module = frrmod_default
45 // error need weak symbol support
48 struct frrmod_runtime
*frrmod_list
= &frrmod_default
.r
;
49 static struct frrmod_runtime
**frrmod_last
= &frrmod_default
.r
.next
;
50 static const char *execname
= NULL
;
52 void frrmod_init(struct frrmod_runtime
*modinfo
)
54 modinfo
->finished_loading
= true;
55 *frrmod_last
= modinfo
;
56 frrmod_last
= &modinfo
->next
;
58 execname
= modinfo
->info
->name
;
62 * If caller wants error strings, it should define non-NULL pFerrlog
63 * which will be called with 0-terminated error messages. These
64 * messages will NOT contain newlines, and the (*pFerrlog)() function
65 * could be called multiple times for a single call to frrmod_load().
67 * The (*pFerrlog)() function may copy these strings if needed, but
68 * should expect them to be freed by frrmod_load() before frrmod_load()
71 * frrmod_load() is coded such that (*pFerrlog)() will be called only
72 * in the case where frrmod_load() returns an error.
74 struct frrmod_runtime
*frrmod_load(const char *spec
, const char *dir
,
75 void (*pFerrlog
)(const void *, const char *),
76 const void *pErrlogCookie
)
79 char name
[PATH_MAX
], fullpath
[PATH_MAX
* 2], *args
;
80 struct frrmod_runtime
*rtinfo
, **rtinfop
;
81 const struct frrmod_info
*info
;
83 #define FRRMOD_LOAD_N_ERRSTR 10
84 char *aErr
[FRRMOD_LOAD_N_ERRSTR
];
85 unsigned int iErr
= 0;
87 memset(aErr
, 0, sizeof(aErr
));
89 #define ERR_RECORD(...) \
91 if (pFerrlog && (iErr < FRRMOD_LOAD_N_ERRSTR)) { \
92 aErr[iErr++] = asprintfrr(MTYPE_MODULE_LOAD_ERR, \
102 for (i = 0; i < iErr; ++i) { \
103 (*pFerrlog)(pErrlogCookie, aErr[i]); \
112 for (i = 0; i < iErr; ++i) { \
113 XFREE(MTYPE_MODULE_LOAD_ERR, aErr[i]); \
119 snprintf(name
, sizeof(name
), "%s", spec
);
120 args
= strchr(name
, ':');
124 if (!strchr(name
, '/')) {
126 snprintf(fullpath
, sizeof(fullpath
), "%s/%s_%s.so", dir
,
128 handle
= dlopen(fullpath
, RTLD_NOW
| RTLD_GLOBAL
);
130 ERR_RECORD("loader error: dlopen(%s): %s",
131 fullpath
, dlerror());
134 snprintf(fullpath
, sizeof(fullpath
), "%s/%s.so", dir
,
136 handle
= dlopen(fullpath
, RTLD_NOW
| RTLD_GLOBAL
);
138 ERR_RECORD("loader error: dlopen(%s): %s",
139 fullpath
, dlerror());
143 snprintf(fullpath
, sizeof(fullpath
), "%s", name
);
144 handle
= dlopen(fullpath
, RTLD_NOW
| RTLD_GLOBAL
);
146 ERR_RECORD("loader error: dlopen(%s): %s", fullpath
,
155 /* previous dlopen() errors are no longer relevant */
158 rtinfop
= dlsym(handle
, "frr_module");
161 ERR_RECORD("\"%s\" is not an FRR module: %s", name
, dlerror());
167 rtinfo
->load_name
= XSTRDUP(MTYPE_MODULE_LOADNAME
, name
);
168 rtinfo
->dl_handle
= handle
;
170 rtinfo
->load_args
= XSTRDUP(MTYPE_MODULE_LOADARGS
, args
);
173 if (rtinfo
->finished_loading
) {
175 ERR_RECORD("module \"%s\" already loaded", name
);
179 if (info
->init
&& info
->init()) {
181 ERR_RECORD("module \"%s\" initialisation failed", name
);
185 rtinfo
->finished_loading
= true;
187 *frrmod_last
= rtinfo
;
188 frrmod_last
= &rtinfo
->next
;
193 XFREE(MTYPE_MODULE_LOADARGS
, rtinfo
->load_args
);
194 XFREE(MTYPE_MODULE_LOADNAME
, rtinfo
->load_name
);
201 void frrmod_unload(struct frrmod_runtime
*module
)