]>
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> |
5f98c815 | 27 | #include "frrlua.h" |
8878080b | 28 | #include "bgpd/bgp_script.h" |
5f98c815 QY |
29 | |
30 | #ifdef __cplusplus | |
31 | extern "C" { | |
32 | #endif | |
33 | ||
47dd8736 | 34 | typedef void (*encoder_func)(lua_State *, const void *); |
f869ab17 QY |
35 | typedef void *(*decoder_func)(lua_State *, int); |
36 | ||
37 | struct frrscript_codec { | |
38 | const char *typename; | |
39 | encoder_func encoder; | |
40 | decoder_func decoder; | |
41 | }; | |
f944ec67 | 42 | |
105ba9af DL |
43 | struct lua_function_state { |
44 | const char *name; | |
45 | lua_State *L; | |
46 | }; | |
47 | ||
5f98c815 QY |
48 | struct frrscript { |
49 | /* Script name */ | |
50 | char *name; | |
51 | ||
105ba9af DL |
52 | /* Hash of Lua function name to Lua function state */ |
53 | struct hash *lua_function_hash; | |
5f98c815 QY |
54 | }; |
55 | ||
105ba9af DL |
56 | |
57 | /* | |
58 | * Hash related functions for lua_function_hash | |
59 | */ | |
60 | ||
61 | void *lua_function_alloc(void *arg); | |
62 | ||
63 | unsigned int lua_function_hash_key(const void *data); | |
64 | ||
65 | bool lua_function_hash_cmp(const void *d1, const void *d2); | |
66 | ||
f869ab17 QY |
67 | struct frrscript_env { |
68 | /* Value type */ | |
69 | const char *typename; | |
70 | ||
71 | /* Binding name */ | |
72 | const char *name; | |
73 | ||
74 | /* Value */ | |
75 | const void *val; | |
76 | }; | |
5f98c815 QY |
77 | |
78 | /* | |
7472871e DL |
79 | * Create new struct frrscript for a Lua script. |
80 | * This will hold the states for the Lua functions in this script. | |
81 | * | |
82 | * scriptname | |
83 | * Name of the Lua script file, without the .lua | |
5f98c815 | 84 | */ |
7472871e | 85 | struct frrscript *frrscript_new(const char *scriptname); |
f0cddf95 DL |
86 | |
87 | /* | |
88 | * Load a function into frrscript, run callback if any | |
89 | */ | |
90 | int frrscript_load(struct frrscript *fs, const char *function_name, | |
91 | int (*load_cb)(struct frrscript *)); | |
5f98c815 QY |
92 | |
93 | /* | |
7472871e | 94 | * Delete Lua function states and frrscript |
5f98c815 | 95 | */ |
64d457d7 | 96 | void frrscript_delete(struct frrscript *fs); |
5f98c815 QY |
97 | |
98 | /* | |
f869ab17 | 99 | * Register a Lua codec for a type. |
5f98c815 QY |
100 | * |
101 | * tname | |
102 | * Name of type; e.g., "peer", "ospf_interface", etc. Chosen at will. | |
103 | * | |
f869ab17 QY |
104 | * codec(s) |
105 | * Function pointer to codec struct. Encoder function should push a Lua | |
5f98c815 | 106 | * table representing the passed argument - which will have the C type |
f869ab17 QY |
107 | * associated with the chosen 'tname' to the provided stack. The decoder |
108 | * function should pop a value from the top of the stack and return a heap | |
109 | * chunk containing that value. Allocations should be made with MTYPE_TMP. | |
110 | * | |
111 | * If using the plural function variant, pass a NULL-terminated array. | |
5f98c815 QY |
112 | * |
113 | */ | |
f869ab17 QY |
114 | void frrscript_register_type_codec(struct frrscript_codec *codec); |
115 | void frrscript_register_type_codecs(struct frrscript_codec *codecs); | |
5f98c815 QY |
116 | |
117 | /* | |
118 | * Initialize scripting subsystem. Call this before anything else. | |
e4e0229a QY |
119 | * |
120 | * scriptdir | |
121 | * Directory in which to look for scripts | |
5f98c815 | 122 | */ |
e4e0229a | 123 | void frrscript_init(const char *scriptdir); |
5f98c815 | 124 | |
70d995ab DL |
125 | /* |
126 | * This macro is mapped to every (name, value) in frrscript_call, | |
127 | * so this in turn maps them onto their encoders | |
128 | */ | |
40d038d2 | 129 | #define ENCODE_ARGS(name, value) ENCODE_ARGS_WITH_STATE(lfs->L, value) |
43a5106d | 130 | |
70d995ab DL |
131 | /* |
132 | * This macro is also mapped to every (name, value) in frrscript_call, but | |
133 | * not every value can be mapped to its decoder - only those that appear | |
134 | * in the returned table will. To find out if they appear in the returned | |
135 | * table, first pop the value and check if its nil. Only call the decoder | |
136 | * if non-nil. | |
137 | * | |
138 | * At the end, the only thing left on the stack should be the | |
139 | * returned table. | |
140 | */ | |
43a5106d DL |
141 | #define DECODE_ARGS(name, value) \ |
142 | do { \ | |
40d038d2 | 143 | lua_getfield(lfs->L, 1, name); \ |
24ff8520 DL |
144 | if (lua_isnil(lfs->L, 2)) { \ |
145 | lua_pop(lfs->L, 1); \ | |
146 | } else { \ | |
147 | DECODE_ARGS_WITH_STATE(lfs->L, value); \ | |
148 | } \ | |
149 | assert(lua_gettop(lfs->L) == 1); \ | |
43a5106d DL |
150 | } while (0) |
151 | ||
19eee398 DL |
152 | /* |
153 | * Maps the type of value to its encoder/decoder. | |
154 | * Add new mappings here. | |
155 | * | |
156 | * L | |
157 | * Lua state | |
158 | * scriptdir | |
159 | * Directory in which to look for scripts | |
160 | */ | |
c2642aab DL |
161 | #define ENCODE_ARGS_WITH_STATE(L, value) \ |
162 | _Generic((value), \ | |
2ce634e2 | 163 | int : lua_pushinteger, \ |
c2642aab DL |
164 | long long * : lua_pushintegerp, \ |
165 | struct prefix * : lua_pushprefix, \ | |
166 | struct interface * : lua_pushinterface, \ | |
167 | struct in_addr * : lua_pushinaddr, \ | |
168 | struct in6_addr * : lua_pushin6addr, \ | |
169 | union sockunion * : lua_pushsockunion, \ | |
170 | time_t * : lua_pushtimet, \ | |
b7da61c1 DL |
171 | char * : lua_pushstring_wrapper, \ |
172 | struct attr * : lua_pushattr, \ | |
81fde499 DL |
173 | struct peer * : lua_pushpeer, \ |
174 | const struct prefix * : lua_pushprefix \ | |
c2642aab | 175 | )(L, value) |
43a5106d | 176 | |
3a3cfe47 DL |
177 | #define DECODE_ARGS_WITH_STATE(L, value) \ |
178 | _Generic((value), \ | |
36cf58c7 | 179 | int : lua_decode_integer_noop, \ |
3a3cfe47 DL |
180 | long long * : lua_decode_integerp, \ |
181 | struct prefix * : lua_decode_prefix, \ | |
182 | struct interface * : lua_decode_interface, \ | |
183 | struct in_addr * : lua_decode_inaddr, \ | |
184 | struct in6_addr * : lua_decode_in6addr, \ | |
185 | union sockunion * : lua_decode_sockunion, \ | |
186 | time_t * : lua_decode_timet, \ | |
b7da61c1 | 187 | char * : lua_decode_stringp, \ |
81fde499 DL |
188 | struct attr * : lua_decode_attr, \ |
189 | struct peer * : lua_decode_noop, \ | |
190 | const struct prefix * : lua_decode_noop \ | |
3a3cfe47 | 191 | )(L, -1, value) |
5f98c815 QY |
192 | |
193 | /* | |
7472871e | 194 | * Call Lua function state (abstraction for a single Lua function) |
3b002f19 | 195 | * |
7472871e | 196 | * lfs |
2ce634e2 | 197 | * The Lua function to call; this should have been loaded in by |
08bf2b41 | 198 | * frrscript_load(). nargs Number of arguments the function accepts |
3b002f19 | 199 | * |
f869ab17 QY |
200 | * Returns: |
201 | * 0 if the script ran successfully, nonzero otherwise. | |
3b002f19 | 202 | */ |
40d038d2 | 203 | int _frrscript_call_lua(struct lua_function_state *lfs, int nargs); |
43a5106d | 204 | |
19eee398 | 205 | /* |
7472871e DL |
206 | * Wrapper for calling Lua function state. Maps values passed in to their |
207 | * encoder and decoder types. | |
19eee398 DL |
208 | * |
209 | * fs | |
7472871e DL |
210 | * The struct frrscript in which the Lua fuction was loaded into |
211 | * f | |
212 | * Name of the Lua function. | |
19eee398 DL |
213 | * |
214 | * Returns: | |
215 | * 0 if the script ran successfully, nonzero otherwise. | |
216 | */ | |
2ce634e2 DL |
217 | #define frrscript_call(fs, f, ...) \ |
218 | ({ \ | |
67b64027 | 219 | struct lua_function_state lookup = {.name = (f)}; \ |
2ce634e2 | 220 | struct lua_function_state *lfs; \ |
67b64027 | 221 | lfs = hash_lookup((fs)->lua_function_hash, &lookup); \ |
2ce634e2 DL |
222 | lfs == NULL ? ({ \ |
223 | zlog_err( \ | |
224 | "frrscript: '%s.lua': '%s': tried to call this function but it was not loaded", \ | |
67b64027 | 225 | (fs)->name, (f)); \ |
2ce634e2 DL |
226 | 1; \ |
227 | }) \ | |
228 | : ({ \ | |
229 | MAP_LISTS(ENCODE_ARGS, ##__VA_ARGS__); \ | |
230 | _frrscript_call_lua( \ | |
231 | lfs, PP_NARG(__VA_ARGS__)); \ | |
232 | }) != 0 \ | |
233 | ? ({ \ | |
234 | zlog_err( \ | |
235 | "frrscript: '%s.lua': '%s': this function called but returned non-zero exit code. No variables modified.", \ | |
67b64027 | 236 | (fs)->name, (f)); \ |
2ce634e2 DL |
237 | 1; \ |
238 | }) \ | |
239 | : ({ \ | |
240 | MAP_LISTS(DECODE_ARGS, \ | |
241 | ##__VA_ARGS__); \ | |
242 | 0; \ | |
243 | }); \ | |
43a5106d | 244 | }) |
3b002f19 QY |
245 | |
246 | /* | |
7472871e | 247 | * Get result from finished function |
3b002f19 | 248 | * |
f869ab17 QY |
249 | * fs |
250 | * The script. This script must have been run already. | |
7472871e DL |
251 | * function_name |
252 | * Name of the Lua function. | |
253 | * name | |
254 | * Name of the result. | |
255 | * This will be used as a string key to retrieve from the table that the | |
256 | * Lua function returns. | |
257 | * The name here should *not* appear in frrscript_call. | |
258 | * lua_to | |
259 | * Function pointer to a lua_to decoder function. | |
260 | * This function should allocate and decode a value from the Lua state. | |
3b002f19 | 261 | * |
f869ab17 | 262 | * Returns: |
7472871e DL |
263 | * A pointer to the decoded value from the Lua state, or NULL if no such |
264 | * value. | |
3b002f19 | 265 | */ |
06947dde DL |
266 | void *frrscript_get_result(struct frrscript *fs, const char *function_name, |
267 | const char *name, | |
268 | void *(*lua_to)(lua_State *L, int idx)); | |
3b002f19 | 269 | |
5f98c815 QY |
270 | #ifdef __cplusplus |
271 | } | |
272 | #endif /* __cplusplus */ | |
273 | ||
fa22080d QY |
274 | #endif /* HAVE_SCRIPTING */ |
275 | ||
5f98c815 | 276 | #endif /* __FRRSCRIPT_H__ */ |