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
;
187 static void codec_free(void *data
)
189 struct frrscript_codec
*c
= data
;
190 char *constworkaroundandihateit
= (char *)c
->typename
;
192 XFREE(MTYPE_SCRIPT
, constworkaroundandihateit
);
193 XFREE(MTYPE_SCRIPT
, c
);
196 /* Lua function hash utils */
198 unsigned int lua_function_hash_key(const void *data
)
200 const struct lua_function_state
*lfs
= data
;
202 return string_hash_make(lfs
->name
);
205 bool lua_function_hash_cmp(const void *d1
, const void *d2
)
207 const struct lua_function_state
*lfs1
= d1
;
208 const struct lua_function_state
*lfs2
= d2
;
210 return strmatch(lfs1
->name
, lfs2
->name
);
213 void *lua_function_alloc(void *arg
)
215 struct lua_function_state
*tmp
= arg
;
216 struct lua_function_state
*lfs
=
217 XCALLOC(MTYPE_SCRIPT
, sizeof(struct lua_function_state
));
219 lfs
->name
= tmp
->name
;
224 static void lua_function_free(void *data
)
226 struct lua_function_state
*lfs
= data
;
229 XFREE(MTYPE_SCRIPT
, lfs
);
232 /* internal frrscript APIs */
234 int _frrscript_call_lua(struct lua_function_state
*lfs
, int nargs
)
238 ret
= lua_pcall(lfs
->L
, nargs
, 1, 0);
244 zlog_err("Lua hook call '%s' : runtime error: %s", lfs
->name
,
245 lua_tostring(lfs
->L
, -1));
248 zlog_err("Lua hook call '%s' : memory error: %s", lfs
->name
,
249 lua_tostring(lfs
->L
, -1));
252 zlog_err("Lua hook call '%s' : error handler error: %s",
253 lfs
->name
, lua_tostring(lfs
->L
, -1));
256 zlog_err("Lua hook call '%s' : garbage collector error: %s",
257 lfs
->name
, lua_tostring(lfs
->L
, -1));
260 zlog_err("Lua hook call '%s' : unknown error: %s", lfs
->name
,
261 lua_tostring(lfs
->L
, -1));
270 if (lua_gettop(lfs
->L
) != 1) {
272 "Lua hook call '%s': Lua function should return only 1 result",
278 if (lua_istable(lfs
->L
, 1) != 1) {
280 "Lua hook call '%s': Lua function should return a Lua table",
286 /* LUA_OK is 0, so we can just return lua_pcall's result directly */
290 void *frrscript_get_result(struct frrscript
*fs
, const char *function_name
,
292 void *(*lua_to
)(lua_State
*L
, int idx
))
295 struct lua_function_state
*lfs
;
296 struct lua_function_state lookup
= {.name
= function_name
};
298 lfs
= hash_lookup(fs
->lua_function_hash
, &lookup
);
303 /* At this point, the Lua state should have only the returned table.
304 * We will then search the table for the key/value we're interested in.
305 * Then if the value is present (i.e. non-nil), call the lua_to*
308 assert(lua_gettop(lfs
->L
) == 1);
309 assert(lua_istable(lfs
->L
, -1) == 1);
310 lua_getfield(lfs
->L
, -1, name
);
311 if (lua_isnil(lfs
->L
, -1)) {
314 "frrscript: '%s.lua': '%s': tried to decode '%s' as result but failed",
315 fs
->name
, function_name
, name
);
318 p
= lua_to(lfs
->L
, 2);
320 /* At the end, the Lua state should be same as it was at the start
321 * i.e. containing solely the returned table.
323 assert(lua_gettop(lfs
->L
) == 1);
324 assert(lua_istable(lfs
->L
, -1) == 1);
329 void frrscript_register_type_codec(struct frrscript_codec
*codec
)
331 struct frrscript_codec c
= *codec
;
333 if (hash_lookup(codec_hash
, &c
)) {
334 zlog_backtrace(LOG_ERR
);
335 assert(!"Type codec double-registered.");
338 (void)hash_get(codec_hash
, &c
, codec_alloc
);
341 void frrscript_register_type_codecs(struct frrscript_codec
*codecs
)
343 for (int i
= 0; codecs
[i
].typename
!= NULL
; i
++)
344 frrscript_register_type_codec(&codecs
[i
]);
347 struct frrscript
*frrscript_new(const char *name
)
349 struct frrscript
*fs
= XCALLOC(MTYPE_SCRIPT
, sizeof(struct frrscript
));
351 fs
->name
= XSTRDUP(MTYPE_SCRIPT
, name
);
352 fs
->lua_function_hash
=
353 hash_create(lua_function_hash_key
, lua_function_hash_cmp
,
354 "Lua function state hash");
358 int frrscript_load(struct frrscript
*fs
, const char *function_name
,
359 int (*load_cb
)(struct frrscript
*))
362 /* Set up the Lua script */
363 lua_State
*L
= luaL_newstate();
365 frrlua_export_logging(L
);
367 char script_name
[MAXPATHLEN
];
369 if (snprintf(script_name
, sizeof(script_name
), "%s/%s.lua", scriptdir
,
371 >= (int)sizeof(script_name
)) {
372 zlog_err("frrscript: path to script %s/%s.lua is too long",
373 scriptdir
, fs
->name
);
377 if (luaL_dofile(L
, script_name
) != 0) {
378 zlog_err("frrscript: failed loading script '%s': error: %s",
379 script_name
, lua_tostring(L
, -1));
383 /* To check the Lua function, we get it from the global table */
384 lua_getglobal(L
, function_name
);
385 if (lua_isfunction(L
, lua_gettop(L
)) == 0) {
386 zlog_err("frrscript: loaded script '%s' but %s not found",
387 script_name
, function_name
);
390 /* Then pop the function (frrscript_call will push it when it needs it)
394 if (load_cb
&& (*load_cb
)(fs
) != 0) {
396 "frrscript: '%s': %s: loaded but callback returned non-zero exit code",
397 script_name
, function_name
);
401 /* Add the Lua function state to frrscript */
402 struct lua_function_state key
= {.name
= function_name
, .L
= L
};
404 (void)hash_get(fs
->lua_function_hash
, &key
, lua_function_alloc
);
412 void frrscript_delete(struct frrscript
*fs
)
414 hash_clean(fs
->lua_function_hash
, lua_function_free
);
415 hash_free(fs
->lua_function_hash
);
416 XFREE(MTYPE_SCRIPT
, fs
->name
);
417 XFREE(MTYPE_SCRIPT
, fs
);
420 void frrscript_init(const char *sd
)
422 codec_hash
= hash_create(codec_hash_key
, codec_hash_cmp
,
423 "Lua type encoders");
425 strlcpy(scriptdir
, sd
, sizeof(scriptdir
));
427 /* Register core library types */
428 frrscript_register_type_codecs(frrscript_codecs_lib
);
431 void frrscript_fini(void)
433 hash_clean(codec_hash
, codec_free
);
434 hash_free(codec_hash
);
436 frrscript_names_destroy();
438 #endif /* HAVE_SCRIPTING */