]>
Commit | Line | Data |
---|---|---|
5f98c815 QY |
1 | /* Scripting foo |
2 | * Copyright (C) 2020 NVIDIA Corporation | |
3 | * Quentin Young | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms of the GNU General Public License as published by the Free | |
7 | * Software Foundation; either version 2 of the License, or (at your option) | |
8 | * any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
13 | * more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License along | |
16 | * with this program; see the file COPYING; if not, write to the Free Software | |
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
18 | */ | |
19 | #ifndef __FRRSCRIPT_H__ | |
20 | #define __FRRSCRIPT_H__ | |
21 | ||
fa22080d QY |
22 | #include <zebra.h> |
23 | ||
24 | #ifdef HAVE_SCRIPTING | |
25 | ||
9e47ee98 | 26 | #include <lua.h> |
263951c1 DL |
27 | #include <nexthop.h> |
28 | #include <nexthop_group.h> | |
5f98c815 | 29 | #include "frrlua.h" |
6ffeb9f7 | 30 | #include "bgpd/bgp_script.h" // for peer and attr encoders/decoders |
5f98c815 QY |
31 | |
32 | #ifdef __cplusplus | |
33 | extern "C" { | |
34 | #endif | |
35 | ||
263951c1 DL |
36 | /* Forward declarations */ |
37 | extern struct zebra_dplane_ctx ctx; | |
38 | extern void lua_pushzebra_dplane_ctx(lua_State *L, | |
39 | const struct zebra_dplane_ctx *ctx); | |
40 | extern void lua_decode_zebra_dplane_ctx(lua_State *L, int idx, | |
41 | struct zebra_dplane_ctx *ctx); | |
42 | ||
a3ef7ae8 DL |
43 | /* |
44 | * Script name hash | |
45 | */ | |
46 | PREDECL_HASH(frrscript_names); | |
47 | ||
48 | struct frrscript_names_entry { | |
49 | /* Name of a Lua hook call */ | |
50 | char function_name[MAXPATHLEN]; | |
51 | ||
52 | /* Lua script in which to look for it */ | |
53 | char script_name[MAXPATHLEN]; | |
54 | ||
55 | struct frrscript_names_item item; | |
56 | }; | |
57 | ||
58 | extern struct frrscript_names_head frrscript_names_hash; | |
59 | ||
60 | int frrscript_names_hash_cmp(const struct frrscript_names_entry *snhe1, | |
61 | const struct frrscript_names_entry *snhe2); | |
62 | uint32_t frrscript_names_hash_key(const struct frrscript_names_entry *snhe); | |
63 | ||
64 | DECLARE_HASH(frrscript_names, struct frrscript_names_entry, item, | |
65 | frrscript_names_hash_cmp, frrscript_names_hash_key); | |
66 | ||
67 | int frrscript_names_add_function_name(const char *function_name); | |
68 | void frrscript_names_destroy(void); | |
69 | int frrscript_names_set_script_name(const char *function_name, | |
70 | const char *script_name); | |
71 | char *frrscript_names_get_script_name(const char *function_name); | |
72 | ||
47dd8736 | 73 | typedef void (*encoder_func)(lua_State *, const void *); |
f869ab17 QY |
74 | typedef void *(*decoder_func)(lua_State *, int); |
75 | ||
76 | struct frrscript_codec { | |
77 | const char *typename; | |
78 | encoder_func encoder; | |
79 | decoder_func decoder; | |
80 | }; | |
f944ec67 | 81 | |
105ba9af DL |
82 | struct lua_function_state { |
83 | const char *name; | |
84 | lua_State *L; | |
85 | }; | |
86 | ||
5f98c815 QY |
87 | struct frrscript { |
88 | /* Script name */ | |
89 | char *name; | |
90 | ||
105ba9af DL |
91 | /* Hash of Lua function name to Lua function state */ |
92 | struct hash *lua_function_hash; | |
5f98c815 QY |
93 | }; |
94 | ||
105ba9af DL |
95 | |
96 | /* | |
97 | * Hash related functions for lua_function_hash | |
98 | */ | |
99 | ||
100 | void *lua_function_alloc(void *arg); | |
101 | ||
102 | unsigned int lua_function_hash_key(const void *data); | |
103 | ||
104 | bool lua_function_hash_cmp(const void *d1, const void *d2); | |
105 | ||
f869ab17 QY |
106 | struct frrscript_env { |
107 | /* Value type */ | |
108 | const char *typename; | |
109 | ||
110 | /* Binding name */ | |
111 | const char *name; | |
112 | ||
113 | /* Value */ | |
114 | const void *val; | |
115 | }; | |
5f98c815 QY |
116 | |
117 | /* | |
7472871e DL |
118 | * Create new struct frrscript for a Lua script. |
119 | * This will hold the states for the Lua functions in this script. | |
120 | * | |
121 | * scriptname | |
122 | * Name of the Lua script file, without the .lua | |
5f98c815 | 123 | */ |
7472871e | 124 | struct frrscript *frrscript_new(const char *scriptname); |
f0cddf95 DL |
125 | |
126 | /* | |
127 | * Load a function into frrscript, run callback if any | |
128 | */ | |
129 | int frrscript_load(struct frrscript *fs, const char *function_name, | |
130 | int (*load_cb)(struct frrscript *)); | |
5f98c815 QY |
131 | |
132 | /* | |
7472871e | 133 | * Delete Lua function states and frrscript |
5f98c815 | 134 | */ |
64d457d7 | 135 | void frrscript_delete(struct frrscript *fs); |
5f98c815 QY |
136 | |
137 | /* | |
f869ab17 | 138 | * Register a Lua codec for a type. |
5f98c815 QY |
139 | * |
140 | * tname | |
141 | * Name of type; e.g., "peer", "ospf_interface", etc. Chosen at will. | |
142 | * | |
f869ab17 QY |
143 | * codec(s) |
144 | * Function pointer to codec struct. Encoder function should push a Lua | |
5f98c815 | 145 | * table representing the passed argument - which will have the C type |
f869ab17 QY |
146 | * associated with the chosen 'tname' to the provided stack. The decoder |
147 | * function should pop a value from the top of the stack and return a heap | |
148 | * chunk containing that value. Allocations should be made with MTYPE_TMP. | |
149 | * | |
150 | * If using the plural function variant, pass a NULL-terminated array. | |
5f98c815 QY |
151 | * |
152 | */ | |
f869ab17 QY |
153 | void frrscript_register_type_codec(struct frrscript_codec *codec); |
154 | void frrscript_register_type_codecs(struct frrscript_codec *codecs); | |
5f98c815 QY |
155 | |
156 | /* | |
157 | * Initialize scripting subsystem. Call this before anything else. | |
e4e0229a QY |
158 | * |
159 | * scriptdir | |
160 | * Directory in which to look for scripts | |
5f98c815 | 161 | */ |
e4e0229a | 162 | void frrscript_init(const char *scriptdir); |
5f98c815 | 163 | |
ca28a0f6 DS |
164 | /* |
165 | * On shutdown clean up memory associated with the scripting subsystem | |
166 | */ | |
167 | void frrscript_fini(void); | |
168 | ||
70d995ab DL |
169 | /* |
170 | * This macro is mapped to every (name, value) in frrscript_call, | |
171 | * so this in turn maps them onto their encoders | |
172 | */ | |
b5e790ee | 173 | #define ENCODE_ARGS(name, value) ENCODE_ARGS_WITH_STATE(lfs->L, (value)) |
43a5106d | 174 | |
70d995ab DL |
175 | /* |
176 | * This macro is also mapped to every (name, value) in frrscript_call, but | |
177 | * not every value can be mapped to its decoder - only those that appear | |
178 | * in the returned table will. To find out if they appear in the returned | |
179 | * table, first pop the value and check if its nil. Only call the decoder | |
180 | * if non-nil. | |
181 | * | |
182 | * At the end, the only thing left on the stack should be the | |
183 | * returned table. | |
184 | */ | |
43a5106d DL |
185 | #define DECODE_ARGS(name, value) \ |
186 | do { \ | |
b5e790ee | 187 | lua_getfield(lfs->L, 1, (name)); \ |
24ff8520 DL |
188 | if (lua_isnil(lfs->L, 2)) { \ |
189 | lua_pop(lfs->L, 1); \ | |
190 | } else { \ | |
b5e790ee | 191 | DECODE_ARGS_WITH_STATE(lfs->L, (value)); \ |
24ff8520 DL |
192 | } \ |
193 | assert(lua_gettop(lfs->L) == 1); \ | |
43a5106d DL |
194 | } while (0) |
195 | ||
19eee398 DL |
196 | /* |
197 | * Maps the type of value to its encoder/decoder. | |
198 | * Add new mappings here. | |
199 | * | |
200 | * L | |
201 | * Lua state | |
202 | * scriptdir | |
203 | * Directory in which to look for scripts | |
204 | */ | |
c2642aab DL |
205 | #define ENCODE_ARGS_WITH_STATE(L, value) \ |
206 | _Generic((value), \ | |
2ce634e2 | 207 | int : lua_pushinteger, \ |
c2642aab DL |
208 | long long * : lua_pushintegerp, \ |
209 | struct prefix * : lua_pushprefix, \ | |
210 | struct interface * : lua_pushinterface, \ | |
211 | struct in_addr * : lua_pushinaddr, \ | |
212 | struct in6_addr * : lua_pushin6addr, \ | |
213 | union sockunion * : lua_pushsockunion, \ | |
214 | time_t * : lua_pushtimet, \ | |
b7da61c1 DL |
215 | char * : lua_pushstring_wrapper, \ |
216 | struct attr * : lua_pushattr, \ | |
81fde499 | 217 | struct peer * : lua_pushpeer, \ |
263951c1 DL |
218 | const struct prefix * : lua_pushprefix, \ |
219 | const struct ipaddr * : lua_pushipaddr, \ | |
220 | const struct ethaddr * : lua_pushethaddr, \ | |
221 | const struct nexthop_group * : lua_pushnexthop_group, \ | |
222 | const struct nexthop * : lua_pushnexthop, \ | |
223 | struct zebra_dplane_ctx * : lua_pushzebra_dplane_ctx \ | |
b5e790ee | 224 | )((L), (value)) |
43a5106d | 225 | |
3a3cfe47 DL |
226 | #define DECODE_ARGS_WITH_STATE(L, value) \ |
227 | _Generic((value), \ | |
36cf58c7 | 228 | int : lua_decode_integer_noop, \ |
3a3cfe47 DL |
229 | long long * : lua_decode_integerp, \ |
230 | struct prefix * : lua_decode_prefix, \ | |
231 | struct interface * : lua_decode_interface, \ | |
232 | struct in_addr * : lua_decode_inaddr, \ | |
233 | struct in6_addr * : lua_decode_in6addr, \ | |
234 | union sockunion * : lua_decode_sockunion, \ | |
235 | time_t * : lua_decode_timet, \ | |
b7da61c1 | 236 | char * : lua_decode_stringp, \ |
81fde499 DL |
237 | struct attr * : lua_decode_attr, \ |
238 | struct peer * : lua_decode_noop, \ | |
263951c1 DL |
239 | const struct prefix * : lua_decode_noop, \ |
240 | const struct ipaddr * : lua_decode_noop, \ | |
241 | const struct ethaddr * : lua_decode_noop, \ | |
242 | const struct nexthop_group * : lua_decode_noop, \ | |
243 | const struct nexthop * : lua_decode_noop, \ | |
244 | struct zebra_dplane_ctx * : lua_decode_noop \ | |
b5e790ee | 245 | )((L), -1, (value)) |
5f98c815 QY |
246 | |
247 | /* | |
7472871e | 248 | * Call Lua function state (abstraction for a single Lua function) |
3b002f19 | 249 | * |
7472871e | 250 | * lfs |
2ce634e2 | 251 | * The Lua function to call; this should have been loaded in by |
08bf2b41 | 252 | * frrscript_load(). nargs Number of arguments the function accepts |
3b002f19 | 253 | * |
f869ab17 QY |
254 | * Returns: |
255 | * 0 if the script ran successfully, nonzero otherwise. | |
3b002f19 | 256 | */ |
40d038d2 | 257 | int _frrscript_call_lua(struct lua_function_state *lfs, int nargs); |
43a5106d | 258 | |
19eee398 | 259 | /* |
2ed598ba DL |
260 | * Wrapper for calling Lua function state. |
261 | * | |
262 | * The Lua function name (f) to run should have already been checked by | |
263 | * frrscript_load. So this wrapper will: | |
264 | * 1) Find the Lua function state, which contains the Lua state | |
265 | * 2) Clear the Lua state (there may be leftovers items from previous call) | |
266 | * 3) Push the Lua function (f) | |
267 | * 4) Map frrscript_call arguments onto their encoder and decoders, push those | |
268 | * 5) Call _frrscript_call_lua (Lua execution takes place) | |
269 | * 6) Write back to frrscript_call arguments using their decoders | |
270 | * | |
271 | * This wrapper can be called multiple times (after one frrscript_load). | |
19eee398 DL |
272 | * |
273 | * fs | |
7472871e DL |
274 | * The struct frrscript in which the Lua fuction was loaded into |
275 | * f | |
276 | * Name of the Lua function. | |
19eee398 DL |
277 | * |
278 | * Returns: | |
279 | * 0 if the script ran successfully, nonzero otherwise. | |
280 | */ | |
2ce634e2 DL |
281 | #define frrscript_call(fs, f, ...) \ |
282 | ({ \ | |
67b64027 | 283 | struct lua_function_state lookup = {.name = (f)}; \ |
2ce634e2 | 284 | struct lua_function_state *lfs; \ |
67b64027 | 285 | lfs = hash_lookup((fs)->lua_function_hash, &lookup); \ |
2ce634e2 DL |
286 | lfs == NULL ? ({ \ |
287 | zlog_err( \ | |
288 | "frrscript: '%s.lua': '%s': tried to call this function but it was not loaded", \ | |
67b64027 | 289 | (fs)->name, (f)); \ |
2ce634e2 DL |
290 | 1; \ |
291 | }) \ | |
292 | : ({ \ | |
2ed598ba DL |
293 | lua_settop(lfs->L, 0); \ |
294 | lua_getglobal(lfs->L, f); \ | |
2ce634e2 DL |
295 | MAP_LISTS(ENCODE_ARGS, ##__VA_ARGS__); \ |
296 | _frrscript_call_lua( \ | |
297 | lfs, PP_NARG(__VA_ARGS__)); \ | |
298 | }) != 0 \ | |
299 | ? ({ \ | |
300 | zlog_err( \ | |
301 | "frrscript: '%s.lua': '%s': this function called but returned non-zero exit code. No variables modified.", \ | |
67b64027 | 302 | (fs)->name, (f)); \ |
2ce634e2 DL |
303 | 1; \ |
304 | }) \ | |
305 | : ({ \ | |
306 | MAP_LISTS(DECODE_ARGS, \ | |
307 | ##__VA_ARGS__); \ | |
308 | 0; \ | |
309 | }); \ | |
43a5106d | 310 | }) |
3b002f19 QY |
311 | |
312 | /* | |
7472871e | 313 | * Get result from finished function |
3b002f19 | 314 | * |
f869ab17 QY |
315 | * fs |
316 | * The script. This script must have been run already. | |
7472871e DL |
317 | * function_name |
318 | * Name of the Lua function. | |
319 | * name | |
320 | * Name of the result. | |
321 | * This will be used as a string key to retrieve from the table that the | |
322 | * Lua function returns. | |
323 | * The name here should *not* appear in frrscript_call. | |
324 | * lua_to | |
325 | * Function pointer to a lua_to decoder function. | |
326 | * This function should allocate and decode a value from the Lua state. | |
3b002f19 | 327 | * |
f869ab17 | 328 | * Returns: |
7472871e DL |
329 | * A pointer to the decoded value from the Lua state, or NULL if no such |
330 | * value. | |
3b002f19 | 331 | */ |
06947dde DL |
332 | void *frrscript_get_result(struct frrscript *fs, const char *function_name, |
333 | const char *name, | |
334 | void *(*lua_to)(lua_State *L, int idx)); | |
3b002f19 | 335 | |
5f98c815 QY |
336 | #ifdef __cplusplus |
337 | } | |
338 | #endif /* __cplusplus */ | |
339 | ||
fa22080d QY |
340 | #endif /* HAVE_SCRIPTING */ |
341 | ||
5f98c815 | 342 | #endif /* __FRRSCRIPT_H__ */ |