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