]> git.proxmox.com Git - mirror_frr.git/blame - lib/hook.h
tools: fix frr-reload.py daemon option
[mirror_frr.git] / lib / hook.h
CommitLineData
a5b38c5b
DL
1/*
2 * Copyright (c) 2016 David Lamparter, for NetDEF, Inc.
3 *
bbfeedb5
DL
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
a5b38c5b
DL
15 */
16
17#ifndef _FRR_HOOK_H
18#define _FRR_HOOK_H
19
20#include <stdbool.h>
21
22#include "module.h"
23#include "memory.h"
24
5e244469
RW
25#ifdef __cplusplus
26extern "C" {
27#endif
28
a5b38c5b
DL
29/* type-safe subscribable hook points
30 *
31 * where "type-safe" applies to the function pointers used for subscriptions
32 *
33 * overall usage:
34 * - to create a hook:
35 *
36 * mydaemon.h:
37 * #include "hook.h"
38 * DECLARE_HOOK (some_update_event, (struct eventinfo *info), (info))
39 *
40 * mydaemon.c:
41 * DEFINE_HOOK (some_update_event, (struct eventinfo *info), (info))
42 * ...
43 * hook_call (some_update_event, info)
44 *
45 * Note: the second and third macro args must be the hook function's
46 * parameter list, with the same names for each parameter. The second
47 * macro arg is with types (used for defining things), the third arg is
48 * just the names (used for passing along parameters).
49 *
50 * Do not use parameter names starting with "hook", these can collide with
51 * names used by the hook code itself.
52 *
53 * The return value is always "int" for now; hook_call will sum up the
54 * return values from each registered user. Default is 0.
55 *
56 * There are no pre-defined semantics for the value, in most cases it is
57 * ignored. For success/failure indication, 0 should be success, and
58 * handlers should make sure to only return 0 or 1 (not -1 or other values).
59 *
60 *
61 * - to use a hook / create a handler:
62 *
63 * #include "mydaemon.h"
64 * int event_handler (struct eventinfo *info) { ... }
65 * hook_register (some_update_event, event_handler);
66 *
67 * or, if you need an argument to be passed along (addonptr will be added
68 * as first argument when calling the handler):
69 *
70 * #include "mydaemon.h"
71 * int event_handler (void *addonptr, struct eventinfo *info) { ... }
72 * hook_register_arg (some_update_event, event_handler, addonptr);
73 *
74 * (addonptr isn't typesafe, but that should be manageable.)
08c4c73b
DL
75 *
76 * Hooks also support a "priority" value for ordering registered calls
77 * relative to each other. The priority is a signed integer where lower
78 * values are called earlier. There is also "Koohs", which is hooks with
79 * reverse priority ordering (for cleanup/deinit hooks, so you can use the
80 * same priority value).
81 *
82 * Recommended priority value ranges are:
83 *
84 * -999 ... 0 ... 999 - main executable / daemon, or library
85 * -1999 ... -1000 - modules registering calls that should run before
86 * the daemon's bits
87 * 1000 ... 1999 - modules calls that should run after daemon's
88 *
89 * Note: the default value is 1000, based on the following 2 expectations:
90 * - most hook_register() usage will be in loadable modules
91 * - usage of hook_register() in the daemon itself may need relative ordering
92 * to itself, making an explicit value the expected case
93 *
94 * The priority value is passed as extra argument on hook_register_prio() /
95 * hook_register_arg_prio(). Whether a hook runs in reverse is determined
96 * solely by the code defining / calling the hook. (DECLARE_KOOH is actually
97 * the same thing as DECLARE_HOOK, it's just there to make it obvious.)
a5b38c5b
DL
98 */
99
100/* TODO:
101 * - hook_unregister_all_module()
102 * - introspection / CLI / debug
103 * - testcases ;)
104 *
105 * For loadable modules, the idea is that hooks could be automatically
106 * unregistered when a module is unloaded.
107 *
108 * It's also possible to add a constructor (MTYPE style) to DEFINE_HOOK,
109 * which would make it possible for the CLI to show all hooks and all
110 * registered handlers.
111 */
112
113struct hookent {
114 struct hookent *next;
d62a17ae 115 void *hookfn; /* actually a function pointer */
a5b38c5b 116 void *hookarg;
8d0a2918
DL
117 bool has_arg : 1;
118 bool ent_on_heap : 1;
119 bool ent_used : 1;
08c4c73b 120 int priority;
a5b38c5b
DL
121 struct frrmod_runtime *module;
122 const char *fnname;
123};
124
125struct hook {
126 const char *name;
127 struct hookent *entries;
08c4c73b 128 bool reverse;
a5b38c5b
DL
129};
130
08c4c73b
DL
131#define HOOK_DEFAULT_PRIORITY 1000
132
a5b38c5b
DL
133/* subscribe/add callback function to a hook
134 *
135 * always use hook_register(), which uses the static inline helper from
136 * DECLARE_HOOK in order to get type safety
137 */
8d0a2918
DL
138extern void _hook_register(struct hook *hook, struct hookent *stackent,
139 void *funcptr, void *arg, bool has_arg,
140 struct frrmod_runtime *module,
08c4c73b 141 const char *funcname, int priority);
8d0a2918
DL
142
143/* most hook_register calls are not in a loop or similar and can use a
144 * statically allocated "struct hookent" from the data segment
145 */
146#define _hook_reg_svar(hook, funcptr, arg, has_arg, module, funcname, prio) \
147 do { \
e01a788c 148 static struct hookent stack_hookent = {}; \
8d0a2918
DL
149 _hook_register(hook, &stack_hookent, funcptr, arg, has_arg, \
150 module, funcname, prio); \
151 } while (0)
152
d62a17ae 153#define hook_register(hookname, func) \
8d0a2918 154 _hook_reg_svar(&_hook_##hookname, _hook_typecheck_##hookname(func), \
08c4c73b 155 NULL, false, THIS_MODULE, #func, HOOK_DEFAULT_PRIORITY)
d62a17ae 156#define hook_register_arg(hookname, func, arg) \
8d0a2918 157 _hook_reg_svar(&_hook_##hookname, \
d62a17ae 158 _hook_typecheck_arg_##hookname(func), arg, true, \
08c4c73b
DL
159 THIS_MODULE, #func, HOOK_DEFAULT_PRIORITY)
160#define hook_register_prio(hookname, prio, func) \
8d0a2918 161 _hook_reg_svar(&_hook_##hookname, _hook_typecheck_##hookname(func), \
08c4c73b
DL
162 NULL, false, THIS_MODULE, #func, prio)
163#define hook_register_arg_prio(hookname, prio, func, arg) \
8d0a2918 164 _hook_reg_svar(&_hook_##hookname, \
996c9314
LB
165 _hook_typecheck_arg_##hookname(func), arg, true, \
166 THIS_MODULE, #func, prio)
a5b38c5b
DL
167
168extern void _hook_unregister(struct hook *hook, void *funcptr, void *arg,
169 bool has_arg);
d62a17ae 170#define hook_unregister(hookname, func) \
171 _hook_unregister(&_hook_##hookname, _hook_typecheck_##hookname(func), \
172 NULL, false)
173#define hook_unregister_arg(hookname, func, arg) \
174 _hook_unregister(&_hook_##hookname, \
175 _hook_typecheck_arg_##hookname(func), arg, true)
a5b38c5b
DL
176
177/* invoke hooks
178 * this is private (static) to the file that has the DEFINE_HOOK statement
179 */
d62a17ae 180#define hook_call(hookname, ...) hook_call_##hookname(__VA_ARGS__)
a5b38c5b
DL
181
182/* helpers to add the void * arg */
183#define HOOK_ADDDEF(...) (void *hookarg , ## __VA_ARGS__)
184#define HOOK_ADDARG(...) (hookarg , ## __VA_ARGS__)
185
186/* use in header file - declares the hook and its arguments
187 * usage: DECLARE_HOOK(my_hook, (int arg1, struct foo *arg2), (arg1, arg2))
188 * as above, "passlist" must use the same order and same names as "arglist"
189 *
190 * theoretically passlist is not neccessary, but let's keep things simple and
191 * use exact same args on DECLARE and DEFINE.
192 */
d62a17ae 193#define DECLARE_HOOK(hookname, arglist, passlist) \
194 extern struct hook _hook_##hookname; \
195 __attribute__((unused)) static void *_hook_typecheck_##hookname( \
196 int(*funcptr) arglist) \
197 { \
198 return (void *)funcptr; \
199 } \
200 __attribute__((unused)) static void *_hook_typecheck_arg_##hookname( \
201 int(*funcptr) HOOK_ADDDEF arglist) \
202 { \
203 return (void *)funcptr; \
204 }
996c9314 205#define DECLARE_KOOH(hookname, arglist, passlist) \
08c4c73b 206 DECLARE_HOOK(hookname, arglist, passlist)
a5b38c5b
DL
207
208/* use in source file - contains hook-related definitions.
209 */
08c4c73b 210#define DEFINE_HOOK_INT(hookname, arglist, passlist, rev) \
d62a17ae 211 struct hook _hook_##hookname = { \
08c4c73b 212 .name = #hookname, .entries = NULL, .reverse = rev, \
d62a17ae 213 }; \
214 static int hook_call_##hookname arglist \
215 { \
216 int hooksum = 0; \
217 struct hookent *he = _hook_##hookname.entries; \
218 void *hookarg; \
219 union { \
220 void *voidptr; \
221 int(*fptr) arglist; \
222 int(*farg) HOOK_ADDDEF arglist; \
223 } hookp; \
224 for (; he; he = he->next) { \
225 hookarg = he->hookarg; \
226 hookp.voidptr = he->hookfn; \
227 if (!he->has_arg) \
228 hooksum += hookp.fptr passlist; \
229 else \
230 hooksum += hookp.farg HOOK_ADDARG passlist; \
231 } \
232 return hooksum; \
a5b38c5b
DL
233 }
234
996c9314 235#define DEFINE_HOOK(hookname, arglist, passlist) \
08c4c73b 236 DEFINE_HOOK_INT(hookname, arglist, passlist, false)
996c9314 237#define DEFINE_KOOH(hookname, arglist, passlist) \
08c4c73b
DL
238 DEFINE_HOOK_INT(hookname, arglist, passlist, true)
239
5e244469
RW
240#ifdef __cplusplus
241}
242#endif
243
a5b38c5b 244#endif /* _FRR_HOOK_H */