2 * Copyright (C) 2020 NVIDIA Corporation
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)
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
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
26 #include "frrscript.h"
33 DEFINE_MTYPE_STATIC(LIB
, SCRIPT
, "Scripting");
36 * Script name hash utilities
39 struct frrscript_names_head frrscript_names_hash
;
42 * Wrapper for frrscript_names_add
43 * Use this to register hook calls when a daemon starts up
45 int frrscript_names_add_function_name(const char *function_name
)
47 struct frrscript_names_entry
*insert
=
48 XCALLOC(MTYPE_SCRIPT
, sizeof(*insert
));
49 strlcpy(insert
->function_name
, function_name
,
50 sizeof(insert
->function_name
));
52 if (frrscript_names_add(&frrscript_names_hash
, insert
)) {
54 "Failed to add hook call function name to script_names");
60 void frrscript_names_destroy(void)
62 struct frrscript_names_entry
*ne
;
64 while ((ne
= frrscript_names_pop(&frrscript_names_hash
)))
65 XFREE(MTYPE_SCRIPT
, ne
);
69 * Given a function_name, set its script_name. function_names and script_names
70 * are one-to-one. Each set will wipe the previous script_name.
71 * Return 0 if set was successful, else 1.
73 * script_name is the base name of the file, without .lua.
75 int frrscript_names_set_script_name(const char *function_name
,
76 const char *script_name
)
78 struct frrscript_names_entry lookup
;
80 strlcpy(lookup
.function_name
, function_name
,
81 sizeof(lookup
.function_name
));
82 struct frrscript_names_entry
*snhe
=
83 frrscript_names_find(&frrscript_names_hash
, &lookup
);
86 strlcpy(snhe
->script_name
, script_name
, sizeof(snhe
->script_name
));
91 * Given a function_name, get its script_name.
92 * Return NULL if function_name not found.
94 * script_name is the base name of the file, without .lua.
96 char *frrscript_names_get_script_name(const char *function_name
)
98 struct frrscript_names_entry lookup
;
100 strlcpy(lookup
.function_name
, function_name
,
101 sizeof(lookup
.function_name
));
102 struct frrscript_names_entry
*snhe
=
103 frrscript_names_find(&frrscript_names_hash
, &lookup
);
107 if (snhe
->script_name
[0] == '\0')
110 return snhe
->script_name
;
113 uint32_t frrscript_names_hash_key(const struct frrscript_names_entry
*snhe
)
115 return string_hash_make(snhe
->function_name
);
118 int frrscript_names_hash_cmp(const struct frrscript_names_entry
*snhe1
,
119 const struct frrscript_names_entry
*snhe2
)
121 return strncmp(snhe1
->function_name
, snhe2
->function_name
,
122 sizeof(snhe1
->function_name
));
127 struct frrscript_codec frrscript_codecs_lib
[] = {
128 {.typename
= "integer",
129 .encoder
= (encoder_func
)lua_pushintegerp
,
130 .decoder
= lua_tointegerp
},
131 {.typename
= "string",
132 .encoder
= (encoder_func
)lua_pushstring_wrapper
,
133 .decoder
= lua_tostringp
},
134 {.typename
= "prefix",
135 .encoder
= (encoder_func
)lua_pushprefix
,
136 .decoder
= lua_toprefix
},
137 {.typename
= "interface",
138 .encoder
= (encoder_func
)lua_pushinterface
,
139 .decoder
= lua_tointerface
},
140 {.typename
= "in_addr",
141 .encoder
= (encoder_func
)lua_pushinaddr
,
142 .decoder
= lua_toinaddr
},
143 {.typename
= "in6_addr",
144 .encoder
= (encoder_func
)lua_pushin6addr
,
145 .decoder
= lua_toin6addr
},
146 {.typename
= "sockunion",
147 .encoder
= (encoder_func
)lua_pushsockunion
,
148 .decoder
= lua_tosockunion
},
149 {.typename
= "time_t",
150 .encoder
= (encoder_func
)lua_pushtimet
,
151 .decoder
= lua_totimet
},
156 struct hash
*codec_hash
;
157 char scriptdir
[MAXPATHLEN
];
159 static unsigned int codec_hash_key(const void *data
)
161 const struct frrscript_codec
*c
= data
;
163 return string_hash_make(c
->typename
);
166 static bool codec_hash_cmp(const void *d1
, const void *d2
)
168 const struct frrscript_codec
*e1
= d1
;
169 const struct frrscript_codec
*e2
= d2
;
171 return strmatch(e1
->typename
, e2
->typename
);
174 static void *codec_alloc(void *arg
)
176 struct frrscript_codec
*tmp
= arg
;
178 struct frrscript_codec
*e
=
179 XCALLOC(MTYPE_SCRIPT
, sizeof(struct frrscript_codec
));
180 e
->typename
= XSTRDUP(MTYPE_SCRIPT
, tmp
->typename
);
181 e
->encoder
= tmp
->encoder
;
182 e
->decoder
= tmp
->decoder
;
188 static void codec_free(struct codec
*c
)
190 XFREE(MTYPE_TMP
, c
->typename
);
195 /* Lua function hash utils */
197 unsigned int lua_function_hash_key(const void *data
)
199 const struct lua_function_state
*lfs
= data
;
201 return string_hash_make(lfs
->name
);
204 bool lua_function_hash_cmp(const void *d1
, const void *d2
)
206 const struct lua_function_state
*lfs1
= d1
;
207 const struct lua_function_state
*lfs2
= d2
;
209 return strmatch(lfs1
->name
, lfs2
->name
);
212 void *lua_function_alloc(void *arg
)
214 struct lua_function_state
*tmp
= arg
;
216 struct lua_function_state
*lfs
=
217 XCALLOC(MTYPE_SCRIPT
, sizeof(struct lua_function_state
));
218 lfs
->name
= tmp
->name
;
223 static void lua_function_free(struct hash_bucket
*b
, void *data
)
225 struct lua_function_state
*lfs
= (struct lua_function_state
*)b
->data
;
227 XFREE(MTYPE_SCRIPT
, lfs
);
230 /* internal frrscript APIs */
232 int _frrscript_call_lua(struct lua_function_state
*lfs
, int nargs
)
236 ret
= lua_pcall(lfs
->L
, nargs
, 1, 0);
242 zlog_err("Lua hook call '%s' : runtime error: %s", lfs
->name
,
243 lua_tostring(lfs
->L
, -1));
246 zlog_err("Lua hook call '%s' : memory error: %s", lfs
->name
,
247 lua_tostring(lfs
->L
, -1));
250 zlog_err("Lua hook call '%s' : error handler error: %s",
251 lfs
->name
, lua_tostring(lfs
->L
, -1));
254 zlog_err("Lua hook call '%s' : garbage collector error: %s",
255 lfs
->name
, lua_tostring(lfs
->L
, -1));
258 zlog_err("Lua hook call '%s' : unknown error: %s", lfs
->name
,
259 lua_tostring(lfs
->L
, -1));
268 if (lua_gettop(lfs
->L
) != 1) {
270 "Lua hook call '%s': Lua function should return only 1 result",
276 if (lua_istable(lfs
->L
, 1) != 1) {
278 "Lua hook call '%s': Lua function should return a Lua table",
284 /* LUA_OK is 0, so we can just return lua_pcall's result directly */
288 void *frrscript_get_result(struct frrscript
*fs
, const char *function_name
,
290 void *(*lua_to
)(lua_State
*L
, int idx
))
293 struct lua_function_state
*lfs
;
294 struct lua_function_state lookup
= {.name
= function_name
};
296 lfs
= hash_lookup(fs
->lua_function_hash
, &lookup
);
301 /* At this point, the Lua state should have only the returned table.
302 * We will then search the table for the key/value we're interested in.
303 * Then if the value is present (i.e. non-nil), call the lua_to*
306 assert(lua_gettop(lfs
->L
) == 1);
307 assert(lua_istable(lfs
->L
, -1) == 1);
308 lua_getfield(lfs
->L
, -1, name
);
309 if (lua_isnil(lfs
->L
, -1)) {
312 "frrscript: '%s.lua': '%s': tried to decode '%s' as result but failed",
313 fs
->name
, function_name
, name
);
316 p
= lua_to(lfs
->L
, 2);
318 /* At the end, the Lua state should be same as it was at the start
319 * i.e. containing solely the returned table.
321 assert(lua_gettop(lfs
->L
) == 1);
322 assert(lua_istable(lfs
->L
, -1) == 1);
327 void frrscript_register_type_codec(struct frrscript_codec
*codec
)
329 struct frrscript_codec c
= *codec
;
331 if (hash_lookup(codec_hash
, &c
)) {
332 zlog_backtrace(LOG_ERR
);
333 assert(!"Type codec double-registered.");
336 assert(hash_get(codec_hash
, &c
, codec_alloc
));
339 void frrscript_register_type_codecs(struct frrscript_codec
*codecs
)
341 for (int i
= 0; codecs
[i
].typename
!= NULL
; i
++)
342 frrscript_register_type_codec(&codecs
[i
]);
345 struct frrscript
*frrscript_new(const char *name
)
347 struct frrscript
*fs
= XCALLOC(MTYPE_SCRIPT
, sizeof(struct frrscript
));
349 fs
->name
= XSTRDUP(MTYPE_SCRIPT
, name
);
350 fs
->lua_function_hash
=
351 hash_create(lua_function_hash_key
, lua_function_hash_cmp
,
352 "Lua function state hash");
356 int frrscript_load(struct frrscript
*fs
, const char *function_name
,
357 int (*load_cb
)(struct frrscript
*))
360 /* Set up the Lua script */
361 lua_State
*L
= luaL_newstate();
363 frrlua_export_logging(L
);
365 char script_name
[MAXPATHLEN
];
367 if (snprintf(script_name
, sizeof(script_name
), "%s/%s.lua", scriptdir
,
369 >= (int)sizeof(script_name
)) {
370 zlog_err("frrscript: path to script %s/%s.lua is too long",
371 scriptdir
, fs
->name
);
375 if (luaL_dofile(L
, script_name
) != 0) {
376 zlog_err("frrscript: failed loading script '%s.lua': error: %s",
377 script_name
, lua_tostring(L
, -1));
381 /* To check the Lua function, we get it from the global table */
382 lua_getglobal(L
, function_name
);
383 if (lua_isfunction(L
, lua_gettop(L
)) == 0) {
384 zlog_err("frrscript: loaded script '%s.lua' but %s not found",
385 script_name
, function_name
);
388 /* Then pop the function (frrscript_call will push it when it needs it)
392 if (load_cb
&& (*load_cb
)(fs
) != 0) {
394 "frrscript: '%s.lua': %s: loaded but callback returned non-zero exit code",
395 script_name
, function_name
);
399 /* Add the Lua function state to frrscript */
400 struct lua_function_state key
= {.name
= function_name
, .L
= L
};
402 hash_get(fs
->lua_function_hash
, &key
, lua_function_alloc
);
410 void frrscript_delete(struct frrscript
*fs
)
412 hash_iterate(fs
->lua_function_hash
, lua_function_free
, NULL
);
413 XFREE(MTYPE_SCRIPT
, fs
->name
);
414 XFREE(MTYPE_SCRIPT
, fs
);
417 void frrscript_init(const char *sd
)
419 codec_hash
= hash_create(codec_hash_key
, codec_hash_cmp
,
420 "Lua type encoders");
422 strlcpy(scriptdir
, sd
, sizeof(scriptdir
));
424 /* Register core library types */
425 frrscript_register_type_codecs(frrscript_codecs_lib
);
428 #endif /* HAVE_SCRIPTING */