]> git.proxmox.com Git - mirror_frr.git/blob - lib/frrscript.c
Merge pull request #9783 from mjstapp/fix_bgp_lu_lsp
[mirror_frr.git] / lib / frrscript.c
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 #include <zebra.h>
20
21 #ifdef HAVE_SCRIPTING
22
23 #include <stdarg.h>
24 #include <lua.h>
25
26 #include "frrscript.h"
27 #include "frrlua.h"
28 #include "memory.h"
29 #include "hash.h"
30 #include "log.h"
31
32
33 DEFINE_MTYPE_STATIC(LIB, SCRIPT, "Scripting");
34
35 /* Codecs */
36
37 struct frrscript_codec frrscript_codecs_lib[] = {
38 {.typename = "integer",
39 .encoder = (encoder_func)lua_pushintegerp,
40 .decoder = lua_tointegerp},
41 {.typename = "string",
42 .encoder = (encoder_func)lua_pushstring_wrapper,
43 .decoder = lua_tostringp},
44 {.typename = "prefix",
45 .encoder = (encoder_func)lua_pushprefix,
46 .decoder = lua_toprefix},
47 {.typename = "interface",
48 .encoder = (encoder_func)lua_pushinterface,
49 .decoder = lua_tointerface},
50 {.typename = "in_addr",
51 .encoder = (encoder_func)lua_pushinaddr,
52 .decoder = lua_toinaddr},
53 {.typename = "in6_addr",
54 .encoder = (encoder_func)lua_pushin6addr,
55 .decoder = lua_toin6addr},
56 {.typename = "sockunion",
57 .encoder = (encoder_func)lua_pushsockunion,
58 .decoder = lua_tosockunion},
59 {.typename = "time_t",
60 .encoder = (encoder_func)lua_pushtimet,
61 .decoder = lua_totimet},
62 {}};
63
64 /* Type codecs */
65
66 struct hash *codec_hash;
67 char scriptdir[MAXPATHLEN];
68
69 static unsigned int codec_hash_key(const void *data)
70 {
71 const struct frrscript_codec *c = data;
72
73 return string_hash_make(c->typename);
74 }
75
76 static bool codec_hash_cmp(const void *d1, const void *d2)
77 {
78 const struct frrscript_codec *e1 = d1;
79 const struct frrscript_codec *e2 = d2;
80
81 return strmatch(e1->typename, e2->typename);
82 }
83
84 static void *codec_alloc(void *arg)
85 {
86 struct frrscript_codec *tmp = arg;
87
88 struct frrscript_codec *e =
89 XCALLOC(MTYPE_SCRIPT, sizeof(struct frrscript_codec));
90 e->typename = XSTRDUP(MTYPE_SCRIPT, tmp->typename);
91 e->encoder = tmp->encoder;
92 e->decoder = tmp->decoder;
93
94 return e;
95 }
96
97 #if 0
98 static void codec_free(struct codec *c)
99 {
100 XFREE(MTYPE_TMP, c->typename);
101 XFREE(MTYPE_TMP, c);
102 }
103 #endif
104
105 /* Lua function hash utils */
106
107 unsigned int lua_function_hash_key(const void *data)
108 {
109 const struct lua_function_state *lfs = data;
110
111 return string_hash_make(lfs->name);
112 }
113
114 bool lua_function_hash_cmp(const void *d1, const void *d2)
115 {
116 const struct lua_function_state *lfs1 = d1;
117 const struct lua_function_state *lfs2 = d2;
118
119 return strmatch(lfs1->name, lfs2->name);
120 }
121
122 void *lua_function_alloc(void *arg)
123 {
124 struct lua_function_state *tmp = arg;
125
126 struct lua_function_state *lfs =
127 XCALLOC(MTYPE_SCRIPT, sizeof(struct lua_function_state));
128 lfs->name = tmp->name;
129 lfs->L = tmp->L;
130 return lfs;
131 }
132
133 static void lua_function_free(struct hash_bucket *b, void *data)
134 {
135 struct lua_function_state *lfs = (struct lua_function_state *)b->data;
136 lua_close(lfs->L);
137 XFREE(MTYPE_SCRIPT, lfs);
138 }
139
140 /* internal frrscript APIs */
141
142 int _frrscript_call_lua(struct lua_function_state *lfs, int nargs)
143 {
144
145 int ret;
146 ret = lua_pcall(lfs->L, nargs, 1, 0);
147
148 switch (ret) {
149 case LUA_OK:
150 break;
151 case LUA_ERRRUN:
152 zlog_err("Lua hook call '%s' : runtime error: %s", lfs->name,
153 lua_tostring(lfs->L, -1));
154 break;
155 case LUA_ERRMEM:
156 zlog_err("Lua hook call '%s' : memory error: %s", lfs->name,
157 lua_tostring(lfs->L, -1));
158 break;
159 case LUA_ERRERR:
160 zlog_err("Lua hook call '%s' : error handler error: %s",
161 lfs->name, lua_tostring(lfs->L, -1));
162 break;
163 case LUA_ERRGCMM:
164 zlog_err("Lua hook call '%s' : garbage collector error: %s",
165 lfs->name, lua_tostring(lfs->L, -1));
166 break;
167 default:
168 zlog_err("Lua hook call '%s' : unknown error: %s", lfs->name,
169 lua_tostring(lfs->L, -1));
170 break;
171 }
172
173 if (ret != LUA_OK) {
174 lua_pop(lfs->L, 1);
175 goto done;
176 }
177
178 if (lua_gettop(lfs->L) != 1) {
179 zlog_err(
180 "Lua hook call '%s': Lua function should return only 1 result",
181 lfs->name);
182 ret = 1;
183 goto done;
184 }
185
186 if (lua_istable(lfs->L, 1) != 1) {
187 zlog_err(
188 "Lua hook call '%s': Lua function should return a Lua table",
189 lfs->name);
190 ret = 1;
191 }
192
193 done:
194 /* LUA_OK is 0, so we can just return lua_pcall's result directly */
195 return ret;
196 }
197
198 void *frrscript_get_result(struct frrscript *fs, const char *function_name,
199 const char *name,
200 void *(*lua_to)(lua_State *L, int idx))
201 {
202 void *p;
203 struct lua_function_state *lfs;
204 struct lua_function_state lookup = {.name = function_name};
205
206 lfs = hash_lookup(fs->lua_function_hash, &lookup);
207
208 if (lfs == NULL)
209 return NULL;
210
211 /* At this point, the Lua state should have only the returned table.
212 * We will then search the table for the key/value we're interested in.
213 * Then if the value is present (i.e. non-nil), call the lua_to*
214 * decoder.
215 */
216 assert(lua_gettop(lfs->L) == 1);
217 assert(lua_istable(lfs->L, -1) == 1);
218 lua_getfield(lfs->L, -1, name);
219 if (lua_isnil(lfs->L, -1)) {
220 lua_pop(lfs->L, 1);
221 zlog_warn(
222 "frrscript: '%s.lua': '%s': tried to decode '%s' as result but failed",
223 fs->name, function_name, name);
224 return NULL;
225 }
226 p = lua_to(lfs->L, 2);
227
228 /* At the end, the Lua state should be same as it was at the start
229 * i.e. containing solely the returned table.
230 */
231 assert(lua_gettop(lfs->L) == 1);
232 assert(lua_istable(lfs->L, -1) == 1);
233
234 return p;
235 }
236
237 void frrscript_register_type_codec(struct frrscript_codec *codec)
238 {
239 struct frrscript_codec c = *codec;
240
241 if (hash_lookup(codec_hash, &c)) {
242 zlog_backtrace(LOG_ERR);
243 assert(!"Type codec double-registered.");
244 }
245
246 assert(hash_get(codec_hash, &c, codec_alloc));
247 }
248
249 void frrscript_register_type_codecs(struct frrscript_codec *codecs)
250 {
251 for (int i = 0; codecs[i].typename != NULL; i++)
252 frrscript_register_type_codec(&codecs[i]);
253 }
254
255 struct frrscript *frrscript_new(const char *name)
256 {
257 struct frrscript *fs = XCALLOC(MTYPE_SCRIPT, sizeof(struct frrscript));
258
259 fs->name = XSTRDUP(MTYPE_SCRIPT, name);
260 fs->lua_function_hash =
261 hash_create(lua_function_hash_key, lua_function_hash_cmp,
262 "Lua function state hash");
263 return fs;
264 }
265
266 int frrscript_load(struct frrscript *fs, const char *function_name,
267 int (*load_cb)(struct frrscript *))
268 {
269
270 /* Set up the Lua script */
271 lua_State *L = luaL_newstate();
272
273 frrlua_export_logging(L);
274
275 char script_name[MAXPATHLEN];
276
277 if (snprintf(script_name, sizeof(script_name), "%s/%s.lua", scriptdir,
278 fs->name)
279 >= (int)sizeof(script_name)) {
280 zlog_err("frrscript: path to script %s/%s.lua is too long",
281 scriptdir, fs->name);
282 goto fail;
283 }
284
285 if (luaL_dofile(L, script_name) != 0) {
286 zlog_err("frrscript: failed loading script '%s.lua': error: %s",
287 script_name, lua_tostring(L, -1));
288 goto fail;
289 }
290
291 /* To check the Lua function, we get it from the global table */
292 lua_getglobal(L, function_name);
293 if (lua_isfunction(L, lua_gettop(L)) == 0) {
294 zlog_err("frrscript: loaded script '%s.lua' but %s not found",
295 script_name, function_name);
296 goto fail;
297 }
298 /* Then pop the function (frrscript_call will push it when it needs it)
299 */
300 lua_pop(L, 1);
301
302 if (load_cb && (*load_cb)(fs) != 0) {
303 zlog_err(
304 "frrscript: '%s.lua': %s: loaded but callback returned non-zero exit code",
305 script_name, function_name);
306 goto fail;
307 }
308
309 /* Add the Lua function state to frrscript */
310 struct lua_function_state key = {.name = function_name, .L = L};
311
312 hash_get(fs->lua_function_hash, &key, lua_function_alloc);
313
314 return 0;
315 fail:
316 lua_close(L);
317 return 1;
318 }
319
320 void frrscript_delete(struct frrscript *fs)
321 {
322 hash_iterate(fs->lua_function_hash, lua_function_free, NULL);
323 XFREE(MTYPE_SCRIPT, fs->name);
324 XFREE(MTYPE_SCRIPT, fs);
325 }
326
327 void frrscript_init(const char *sd)
328 {
329 codec_hash = hash_create(codec_hash_key, codec_hash_cmp,
330 "Lua type encoders");
331
332 strlcpy(scriptdir, sd, sizeof(scriptdir));
333
334 /* Register core library types */
335 frrscript_register_type_codecs(frrscript_codecs_lib);
336 }
337
338 #endif /* HAVE_SCRIPTING */