]> git.proxmox.com Git - mirror_frr.git/blob - lib/frrscript.h
lib: Add frrscript_get_result
[mirror_frr.git] / lib / frrscript.h
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
22 #include <zebra.h>
23
24 #ifdef HAVE_SCRIPTING
25
26 #include <lua.h>
27 #include "frrlua.h"
28 #include "../bgpd/bgp_script.h"
29
30 #ifdef __cplusplus
31 extern "C" {
32 #endif
33
34 typedef void (*encoder_func)(lua_State *, const void *);
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 };
42
43 struct lua_function_state {
44 const char *name;
45 lua_State *L;
46 };
47
48 struct frrscript {
49 /* Script name */
50 char *name;
51
52 /* Hash of Lua function name to Lua function state */
53 struct hash *lua_function_hash;
54 };
55
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
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 };
77
78 /*
79 * Create new FRR script.
80 */
81 struct frrscript *frrscript_new(const char *name);
82
83 /*
84 * Load a function into frrscript, run callback if any
85 */
86 int frrscript_load(struct frrscript *fs, const char *function_name,
87 int (*load_cb)(struct frrscript *));
88
89 /*
90 * Destroy FRR script.
91 */
92 void frrscript_unload(struct frrscript *fs);
93
94 /*
95 * Register a Lua codec for a type.
96 *
97 * tname
98 * Name of type; e.g., "peer", "ospf_interface", etc. Chosen at will.
99 *
100 * codec(s)
101 * Function pointer to codec struct. Encoder function should push a Lua
102 * table representing the passed argument - which will have the C type
103 * associated with the chosen 'tname' to the provided stack. The decoder
104 * function should pop a value from the top of the stack and return a heap
105 * chunk containing that value. Allocations should be made with MTYPE_TMP.
106 *
107 * If using the plural function variant, pass a NULL-terminated array.
108 *
109 */
110 void frrscript_register_type_codec(struct frrscript_codec *codec);
111 void frrscript_register_type_codecs(struct frrscript_codec *codecs);
112
113 /*
114 * Initialize scripting subsystem. Call this before anything else.
115 *
116 * scriptdir
117 * Directory in which to look for scripts
118 */
119 void frrscript_init(const char *scriptdir);
120
121 #define ENCODE_ARGS(name, value) ENCODE_ARGS_WITH_STATE(lfs->L, value)
122
123 #define DECODE_ARGS(name, value) \
124 do { \
125 lua_getfield(lfs->L, 1, name); \
126 if (lua_isnil(lfs->L, 2)) { \
127 lua_pop(lfs->L, 1); \
128 } else { \
129 DECODE_ARGS_WITH_STATE(lfs->L, value); \
130 } \
131 assert(lua_gettop(lfs->L) == 1); \
132 } while (0)
133
134 /*
135 * Maps the type of value to its encoder/decoder.
136 * Add new mappings here.
137 *
138 * L
139 * Lua state
140 * scriptdir
141 * Directory in which to look for scripts
142 */
143 #define ENCODE_ARGS_WITH_STATE(L, value) \
144 _Generic((value), \
145 long long * : lua_pushintegerp, \
146 struct prefix * : lua_pushprefix, \
147 struct interface * : lua_pushinterface, \
148 struct in_addr * : lua_pushinaddr, \
149 struct in6_addr * : lua_pushin6addr, \
150 union sockunion * : lua_pushsockunion, \
151 time_t * : lua_pushtimet, \
152 char * : lua_pushstring_wrapper, \
153 struct attr * : lua_pushattr, \
154 struct peer * : lua_pushpeer, \
155 const struct prefix * : lua_pushprefix \
156 )(L, value)
157
158 #define DECODE_ARGS_WITH_STATE(L, value) \
159 _Generic((value), \
160 long long * : lua_decode_integerp, \
161 struct prefix * : lua_decode_prefix, \
162 struct interface * : lua_decode_interface, \
163 struct in_addr * : lua_decode_inaddr, \
164 struct in6_addr * : lua_decode_in6addr, \
165 union sockunion * : lua_decode_sockunion, \
166 time_t * : lua_decode_timet, \
167 char * : lua_decode_stringp, \
168 struct attr * : lua_decode_attr, \
169 struct peer * : lua_decode_noop, \
170 const struct prefix * : lua_decode_noop \
171 )(L, -1, value)
172
173 /*
174 * Call script.
175 *
176 * fs
177 * The script to call; this is obtained from frrscript_load().
178 *
179 * Returns:
180 * 0 if the script ran successfully, nonzero otherwise.
181 */
182 int _frrscript_call_lua(struct lua_function_state *lfs, int nargs);
183
184 /*
185 * Wrapper for call script. Maps values passed in to their encoder
186 * and decoder types.
187 *
188 * fs
189 * The script to call; this is obtained from frrscript_load().
190 *
191 * Returns:
192 * 0 if the script ran successfully, nonzero otherwise.
193 */
194
195 #define frrscript_call(fs, f, ...) \
196 ({ \
197 struct lua_function_state lookup = {.name = f}; \
198 struct lua_function_state *lfs; \
199 lfs = hash_lookup(fs->lua_function_hash, &lookup); \
200 lfs == NULL ? ({ \
201 zlog_err( \
202 "Lua script call: tried to call '%s' in '%s' which was not loaded", \
203 f, fs->name); \
204 1; \
205 }) \
206 : ({ \
207 MAP_LISTS(ENCODE_ARGS, ##__VA_ARGS__); \
208 _frrscript_call_lua(lfs, PP_NARG(__VA_ARGS__)); \
209 }) != 0 \
210 ? ({ \
211 zlog_err( \
212 "Lua script call: '%s' in '%s' returned non-zero exit code", \
213 f, fs->name); \
214 1; \
215 }) \
216 : ({ \
217 MAP_LISTS(DECODE_ARGS, ##__VA_ARGS__); \
218 0; \
219 }); \
220 })
221
222 /*
223 * Get result from finished script.
224 *
225 * fs
226 * The script. This script must have been run already.
227 *
228 * result
229 * The result to extract from the script.
230 * This reuses the frrscript_env type, but only the typename and name fields
231 * need to be set. The value is returned directly.
232 *
233 * Returns:
234 * The script result of the specified name and type, or NULL.
235 */
236 void *frrscript_get_result(struct frrscript *fs, const char *function_name,
237 const char *name,
238 void *(*lua_to)(lua_State *L, int idx));
239
240 #ifdef __cplusplus
241 }
242 #endif /* __cplusplus */
243
244 #endif /* HAVE_SCRIPTING */
245
246 #endif /* __FRRSCRIPT_H__ */