summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/hash.c13
-rw-r--r--lib/hook.c16
-rw-r--r--lib/hook.h51
-rw-r--r--lib/if.c35
-rw-r--r--lib/if.h17
-rw-r--r--lib/libfrr.c21
-rw-r--r--lib/libfrr.h8
-rw-r--r--lib/privs.c4
8 files changed, 114 insertions, 51 deletions
diff --git a/lib/hash.c b/lib/hash.c
index 66341cf2f1..243521bef7 100644
--- a/lib/hash.c
+++ b/lib/hash.c
@@ -335,12 +335,13 @@ void hash_free(struct hash *hash)
/* CLI commands ------------------------------------------------------------ */
-DEFUN(show_hash_stats,
- show_hash_stats_cmd,
- "show hashtable [statistics]",
- SHOW_STR
- "Statistics about hash tables\n"
- "Statistics about hash tables\n")
+DEFUN_NOSH(show_hash_stats,
+ show_hash_stats_cmd,
+ "show debugging hashtable [statistics]",
+ SHOW_STR
+ DEBUG_STR
+ "Statistics about hash tables\n"
+ "Statistics about hash tables\n")
{
struct hash *h;
struct listnode *ln;
diff --git a/lib/hook.c b/lib/hook.c
index 2c877cbf45..1468c4d329 100644
--- a/lib/hook.c
+++ b/lib/hook.c
@@ -26,17 +26,25 @@
DEFINE_MTYPE_STATIC(LIB, HOOK_ENTRY, "Hook entry")
void _hook_register(struct hook *hook, void *funcptr, void *arg, bool has_arg,
- struct frrmod_runtime *module, const char *funcname)
+ struct frrmod_runtime *module, const char *funcname,
+ int priority)
{
- struct hookent *he = XCALLOC(MTYPE_HOOK_ENTRY, sizeof(*he));
+ struct hookent *he = XCALLOC(MTYPE_HOOK_ENTRY, sizeof(*he)), **pos;
he->hookfn = funcptr;
he->hookarg = arg;
he->has_arg = has_arg;
he->module = module;
he->fnname = funcname;
+ he->priority = priority;
- he->next = hook->entries;
- hook->entries = he;
+ for (pos = &hook->entries; *pos; pos = &(*pos)->next)
+ if (hook->reverse
+ ? (*pos)->priority < priority
+ : (*pos)->priority >= priority)
+ break;
+
+ he->next = *pos;
+ *pos = he;
}
void _hook_unregister(struct hook *hook, void *funcptr, void *arg, bool has_arg)
diff --git a/lib/hook.h b/lib/hook.h
index 4a5cee2fd3..5f45e113e7 100644
--- a/lib/hook.h
+++ b/lib/hook.h
@@ -74,6 +74,29 @@
* hook_register_arg (some_update_event, event_handler, addonptr);
*
* (addonptr isn't typesafe, but that should be manageable.)
+ *
+ * Hooks also support a "priority" value for ordering registered calls
+ * relative to each other. The priority is a signed integer where lower
+ * values are called earlier. There is also "Koohs", which is hooks with
+ * reverse priority ordering (for cleanup/deinit hooks, so you can use the
+ * same priority value).
+ *
+ * Recommended priority value ranges are:
+ *
+ * -999 ... 0 ... 999 - main executable / daemon, or library
+ * -1999 ... -1000 - modules registering calls that should run before
+ * the daemon's bits
+ * 1000 ... 1999 - modules calls that should run after daemon's
+ *
+ * Note: the default value is 1000, based on the following 2 expectations:
+ * - most hook_register() usage will be in loadable modules
+ * - usage of hook_register() in the daemon itself may need relative ordering
+ * to itself, making an explicit value the expected case
+ *
+ * The priority value is passed as extra argument on hook_register_prio() /
+ * hook_register_arg_prio(). Whether a hook runs in reverse is determined
+ * solely by the code defining / calling the hook. (DECLARE_KOOH is actually
+ * the same thing as DECLARE_HOOK, it's just there to make it obvious.)
*/
/* TODO:
@@ -94,6 +117,7 @@ struct hookent {
void *hookfn; /* actually a function pointer */
void *hookarg;
bool has_arg;
+ int priority;
struct frrmod_runtime *module;
const char *fnname;
};
@@ -101,8 +125,11 @@ struct hookent {
struct hook {
const char *name;
struct hookent *entries;
+ bool reverse;
};
+#define HOOK_DEFAULT_PRIORITY 1000
+
/* subscribe/add callback function to a hook
*
* always use hook_register(), which uses the static inline helper from
@@ -110,14 +137,21 @@ struct hook {
*/
extern void _hook_register(struct hook *hook, void *funcptr, void *arg,
bool has_arg, struct frrmod_runtime *module,
- const char *funcname);
+ const char *funcname, int priority);
#define hook_register(hookname, func) \
_hook_register(&_hook_##hookname, _hook_typecheck_##hookname(func), \
- NULL, false, THIS_MODULE, #func)
+ NULL, false, THIS_MODULE, #func, HOOK_DEFAULT_PRIORITY)
#define hook_register_arg(hookname, func, arg) \
_hook_register(&_hook_##hookname, \
_hook_typecheck_arg_##hookname(func), arg, true, \
- THIS_MODULE, #func)
+ THIS_MODULE, #func, HOOK_DEFAULT_PRIORITY)
+#define hook_register_prio(hookname, prio, func) \
+ _hook_register(&_hook_##hookname, _hook_typecheck_##hookname(func), \
+ NULL, false, THIS_MODULE, #func, prio)
+#define hook_register_arg_prio(hookname, prio, func, arg) \
+ _hook_register(&_hook_##hookname, \
+ _hook_typecheck_arg_##hookname(func), \
+ arg, true, THIS_MODULE, #func, prio)
extern void _hook_unregister(struct hook *hook, void *funcptr, void *arg,
bool has_arg);
@@ -156,12 +190,14 @@ extern void _hook_unregister(struct hook *hook, void *funcptr, void *arg,
{ \
return (void *)funcptr; \
}
+#define DECLARE_KOOH(hookname, arglist, passlist) \
+ DECLARE_HOOK(hookname, arglist, passlist)
/* use in source file - contains hook-related definitions.
*/
-#define DEFINE_HOOK(hookname, arglist, passlist) \
+#define DEFINE_HOOK_INT(hookname, arglist, passlist, rev) \
struct hook _hook_##hookname = { \
- .name = #hookname, .entries = NULL, \
+ .name = #hookname, .entries = NULL, .reverse = rev, \
}; \
static int hook_call_##hookname arglist \
{ \
@@ -184,4 +220,9 @@ extern void _hook_unregister(struct hook *hook, void *funcptr, void *arg,
return hooksum; \
}
+#define DEFINE_HOOK(hookname, arglist, passlist) \
+ DEFINE_HOOK_INT(hookname, arglist, passlist, false)
+#define DEFINE_KOOH(hookname, arglist, passlist) \
+ DEFINE_HOOK_INT(hookname, arglist, passlist, true)
+
#endif /* _FRR_HOOK_H */
diff --git a/lib/if.c b/lib/if.c
index 4e4534851c..43c382beaa 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -42,17 +42,12 @@ DEFINE_MTYPE_STATIC(LIB, IF_LINK_PARAMS, "Informational Link Parameters")
DEFINE_QOBJ_TYPE(interface)
+DEFINE_HOOK(if_add, (struct interface *ifp), (ifp))
+DEFINE_KOOH(if_del, (struct interface *ifp), (ifp))
+
/* List of interfaces in only the default VRF */
int ptm_enable = 0;
-/* One for each program. This structure is needed to store hooks. */
-struct if_master {
- int (*if_new_hook)(struct interface *);
- int (*if_delete_hook)(struct interface *);
-} if_master = {
- 0,
-};
-
/* Compare interface names, returning an integer greater than, equal to, or
* less than 0, (following the strcmp convention), according to the
* relationship between ifp1 and ifp2. Interface names consist of an
@@ -150,10 +145,7 @@ struct interface *if_create(const char *name, int namelen, vrf_id_t vrf_id)
SET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION);
QOBJ_REG(ifp, interface);
-
- if (if_master.if_new_hook)
- (*if_master.if_new_hook)(ifp);
-
+ hook_call(if_add, ifp);
return ifp;
}
@@ -182,9 +174,7 @@ void if_update_to_new_vrf(struct interface *ifp, vrf_id_t vrf_id)
/* Delete interface structure. */
void if_delete_retain(struct interface *ifp)
{
- if (if_master.if_delete_hook)
- (*if_master.if_delete_hook)(ifp);
-
+ hook_call(if_del, ifp);
QOBJ_UNREG(ifp);
/* Free connected address list */
@@ -209,21 +199,6 @@ void if_delete(struct interface *ifp)
XFREE(MTYPE_IF, ifp);
}
-/* Add hook to interface master. */
-void if_add_hook(int type, int (*func)(struct interface *ifp))
-{
- switch (type) {
- case IF_NEW_HOOK:
- if_master.if_new_hook = func;
- break;
- case IF_DELETE_HOOK:
- if_master.if_delete_hook = func;
- break;
- default:
- break;
- }
-}
-
/* Interface existance check by index. */
struct interface *if_lookup_by_index(ifindex_t ifindex, vrf_id_t vrf_id)
{
diff --git a/lib/if.h b/lib/if.h
index f80ac19179..a592e0ff85 100644
--- a/lib/if.h
+++ b/lib/if.h
@@ -25,6 +25,7 @@
#include "linklist.h"
#include "memory.h"
#include "qobj.h"
+#include "hook.h"
DECLARE_MTYPE(IF)
DECLARE_MTYPE(CONNECTED_LABEL)
@@ -283,6 +284,17 @@ struct interface {
};
DECLARE_QOBJ_TYPE(interface)
+/* called from the library code whenever interfaces are created/deleted
+ * note: interfaces may not be fully realized at that point; also they
+ * may not exist in the system (ifindex = IFINDEX_INTERNAL)
+ *
+ * priority values are important here, daemons should be at 0 while modules
+ * can use 1000+ so they run after the daemon has initialised daemon-specific
+ * interface data
+ */
+DECLARE_HOOK(if_add, (struct interface *ifp), (ifp))
+DECLARE_KOOH(if_del, (struct interface *ifp), (ifp))
+
/* Connected address structure. */
struct connected {
/* Attached interface. */
@@ -355,10 +367,6 @@ struct nbr_connected {
? (C)->destination \
: (C)->address)
-/* Interface hook sort. */
-#define IF_NEW_HOOK 0
-#define IF_DELETE_HOOK 1
-
/* There are some interface flags which are only supported by some
operating system. */
@@ -442,7 +450,6 @@ extern int if_is_loopback(struct interface *);
extern int if_is_broadcast(struct interface *);
extern int if_is_pointopoint(struct interface *);
extern int if_is_multicast(struct interface *);
-extern void if_add_hook(int, int (*)(struct interface *));
extern void if_init(struct list **);
extern void if_cmd_init(void);
extern void if_terminate(struct list **);
diff --git a/lib/libfrr.c b/lib/libfrr.c
index a5c87e6edc..255f91ec71 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -37,6 +37,8 @@
#include "network.h"
DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm))
+DEFINE_KOOH(frr_early_fini, (), ())
+DEFINE_KOOH(frr_fini, (), ())
const char frr_sysconfdir[] = SYSCONFDIR;
const char frr_vtydir[] = DAEMON_VTY_DIR;
@@ -831,3 +833,22 @@ void frr_run(struct thread_master *master)
while (thread_fetch(master, &thread))
thread_call(&thread);
}
+
+void frr_early_fini(void)
+{
+ hook_call(frr_early_fini);
+}
+
+void frr_fini(void)
+{
+ hook_call(frr_fini);
+
+ /* memory_init -> nothing needed */
+ vty_terminate();
+ cmd_terminate();
+ zprivs_terminate(di->privs);
+ /* signal_init -> nothing needed */
+ thread_master_free(master);
+ closezlog();
+ /* frrmod_init -> nothing needed / hooks */
+}
diff --git a/lib/libfrr.h b/lib/libfrr.h
index 1710fc9a84..8a15d168a1 100644
--- a/lib/libfrr.h
+++ b/lib/libfrr.h
@@ -104,6 +104,14 @@ extern void frr_run(struct thread_master *master);
extern bool frr_zclient_addr(struct sockaddr_storage *sa, socklen_t *sa_len,
const char *path);
+/* these two are before the protocol daemon does its own shutdown
+ * it's named this way being the counterpart to frr_late_init */
+DECLARE_KOOH(frr_early_fini, (), ())
+extern void frr_early_fini(void);
+/* and these two are after the daemon did its own cleanup */
+DECLARE_KOOH(frr_fini, (), ())
+extern void frr_fini(void);
+
extern char config_default[256];
extern char frr_zclientpath[256];
extern const char frr_sysconfdir[];
diff --git a/lib/privs.c b/lib/privs.c
index eda3fb02d4..cfe7d6d6f8 100644
--- a/lib/privs.c
+++ b/lib/privs.c
@@ -856,7 +856,9 @@ void zprivs_terminate(struct zebra_privs_t *zprivs)
}
#ifdef HAVE_CAPABILITIES
- zprivs_caps_terminate();
+ if (zprivs->user || zprivs->group || zprivs->cap_num_p
+ || zprivs->cap_num_i)
+ zprivs_caps_terminate();
#else /* !HAVE_CAPABILITIES */
/* only change uid if we don't have the correct one */
if ((zprivs_state.zuid) && (zprivs_state.zsuid != zprivs_state.zuid)) {