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
);
106 return snhe
->script_name
;
109 uint32_t frrscript_names_hash_key(const struct frrscript_names_entry
*snhe
)
111 return string_hash_make(snhe
->function_name
);
114 int frrscript_names_hash_cmp(const struct frrscript_names_entry
*snhe1
,
115 const struct frrscript_names_entry
*snhe2
)
117 return strncmp(snhe1
->function_name
, snhe2
->function_name
,
118 sizeof(snhe1
->function_name
));
123 struct frrscript_codec frrscript_codecs_lib
[] = {
124 {.typename
= "integer",
125 .encoder
= (encoder_func
)lua_pushintegerp
,
126 .decoder
= lua_tointegerp
},
127 {.typename
= "string",
128 .encoder
= (encoder_func
)lua_pushstring_wrapper
,
129 .decoder
= lua_tostringp
},
130 {.typename
= "prefix",
131 .encoder
= (encoder_func
)lua_pushprefix
,
132 .decoder
= lua_toprefix
},
133 {.typename
= "interface",
134 .encoder
= (encoder_func
)lua_pushinterface
,
135 .decoder
= lua_tointerface
},
136 {.typename
= "in_addr",
137 .encoder
= (encoder_func
)lua_pushinaddr
,
138 .decoder
= lua_toinaddr
},
139 {.typename
= "in6_addr",
140 .encoder
= (encoder_func
)lua_pushin6addr
,
141 .decoder
= lua_toin6addr
},
142 {.typename
= "sockunion",
143 .encoder
= (encoder_func
)lua_pushsockunion
,
144 .decoder
= lua_tosockunion
},
145 {.typename
= "time_t",
146 .encoder
= (encoder_func
)lua_pushtimet
,
147 .decoder
= lua_totimet
},
152 struct hash
*codec_hash
;
153 char scriptdir
[MAXPATHLEN
];
155 static unsigned int codec_hash_key(const void *data
)
157 const struct frrscript_codec
*c
= data
;
159 return string_hash_make(c
->typename
);
162 static bool codec_hash_cmp(const void *d1
, const void *d2
)
164 const struct frrscript_codec
*e1
= d1
;
165 const struct frrscript_codec
*e2
= d2
;
167 return strmatch(e1
->typename
, e2
->typename
);
170 static void *codec_alloc(void *arg
)
172 struct frrscript_codec
*tmp
= arg
;
174 struct frrscript_codec
*e
=
175 XCALLOC(MTYPE_SCRIPT
, sizeof(struct frrscript_codec
));
176 e
->typename
= XSTRDUP(MTYPE_SCRIPT
, tmp
->typename
);
177 e
->encoder
= tmp
->encoder
;
178 e
->decoder
= tmp
->decoder
;
184 static void codec_free(struct codec
*c
)
186 XFREE(MTYPE_TMP
, c
->typename
);
191 /* Lua function hash utils */
193 unsigned int lua_function_hash_key(const void *data
)
195 const struct lua_function_state
*lfs
= data
;
197 return string_hash_make(lfs
->name
);
200 bool lua_function_hash_cmp(const void *d1
, const void *d2
)
202 const struct lua_function_state
*lfs1
= d1
;
203 const struct lua_function_state
*lfs2
= d2
;
205 return strmatch(lfs1
->name
, lfs2
->name
);
208 void *lua_function_alloc(void *arg
)
210 struct lua_function_state
*tmp
= arg
;
212 struct lua_function_state
*lfs
=
213 XCALLOC(MTYPE_SCRIPT
, sizeof(struct lua_function_state
));
214 lfs
->name
= tmp
->name
;
219 static void lua_function_free(struct hash_bucket
*b
, void *data
)
221 struct lua_function_state
*lfs
= (struct lua_function_state
*)b
->data
;
223 XFREE(MTYPE_SCRIPT
, lfs
);
226 /* internal frrscript APIs */
228 int _frrscript_call_lua(struct lua_function_state
*lfs
, int nargs
)
232 ret
= lua_pcall(lfs
->L
, nargs
, 1, 0);
238 zlog_err("Lua hook call '%s' : runtime error: %s", lfs
->name
,
239 lua_tostring(lfs
->L
, -1));
242 zlog_err("Lua hook call '%s' : memory error: %s", lfs
->name
,
243 lua_tostring(lfs
->L
, -1));
246 zlog_err("Lua hook call '%s' : error handler error: %s",
247 lfs
->name
, lua_tostring(lfs
->L
, -1));
250 zlog_err("Lua hook call '%s' : garbage collector error: %s",
251 lfs
->name
, lua_tostring(lfs
->L
, -1));
254 zlog_err("Lua hook call '%s' : unknown error: %s", lfs
->name
,
255 lua_tostring(lfs
->L
, -1));
264 if (lua_gettop(lfs
->L
) != 1) {
266 "Lua hook call '%s': Lua function should return only 1 result",
272 if (lua_istable(lfs
->L
, 1) != 1) {
274 "Lua hook call '%s': Lua function should return a Lua table",
280 /* LUA_OK is 0, so we can just return lua_pcall's result directly */
284 void *frrscript_get_result(struct frrscript
*fs
, const char *function_name
,
286 void *(*lua_to
)(lua_State
*L
, int idx
))
289 struct lua_function_state
*lfs
;
290 struct lua_function_state lookup
= {.name
= function_name
};
292 lfs
= hash_lookup(fs
->lua_function_hash
, &lookup
);
297 /* At this point, the Lua state should have only the returned table.
298 * We will then search the table for the key/value we're interested in.
299 * Then if the value is present (i.e. non-nil), call the lua_to*
302 assert(lua_gettop(lfs
->L
) == 1);
303 assert(lua_istable(lfs
->L
, -1) == 1);
304 lua_getfield(lfs
->L
, -1, name
);
305 if (lua_isnil(lfs
->L
, -1)) {
308 "frrscript: '%s.lua': '%s': tried to decode '%s' as result but failed",
309 fs
->name
, function_name
, name
);
312 p
= lua_to(lfs
->L
, 2);
314 /* At the end, the Lua state should be same as it was at the start
315 * i.e. containing solely the returned table.
317 assert(lua_gettop(lfs
->L
) == 1);
318 assert(lua_istable(lfs
->L
, -1) == 1);
323 void frrscript_register_type_codec(struct frrscript_codec
*codec
)
325 struct frrscript_codec c
= *codec
;
327 if (hash_lookup(codec_hash
, &c
)) {
328 zlog_backtrace(LOG_ERR
);
329 assert(!"Type codec double-registered.");
332 assert(hash_get(codec_hash
, &c
, codec_alloc
));
335 void frrscript_register_type_codecs(struct frrscript_codec
*codecs
)
337 for (int i
= 0; codecs
[i
].typename
!= NULL
; i
++)
338 frrscript_register_type_codec(&codecs
[i
]);
341 struct frrscript
*frrscript_new(const char *name
)
343 struct frrscript
*fs
= XCALLOC(MTYPE_SCRIPT
, sizeof(struct frrscript
));
345 fs
->name
= XSTRDUP(MTYPE_SCRIPT
, name
);
346 fs
->lua_function_hash
=
347 hash_create(lua_function_hash_key
, lua_function_hash_cmp
,
348 "Lua function state hash");
352 int frrscript_load(struct frrscript
*fs
, const char *function_name
,
353 int (*load_cb
)(struct frrscript
*))
356 /* Set up the Lua script */
357 lua_State
*L
= luaL_newstate();
359 frrlua_export_logging(L
);
361 char script_name
[MAXPATHLEN
];
363 if (snprintf(script_name
, sizeof(script_name
), "%s/%s.lua", scriptdir
,
365 >= (int)sizeof(script_name
)) {
366 zlog_err("frrscript: path to script %s/%s.lua is too long",
367 scriptdir
, fs
->name
);
371 if (luaL_dofile(L
, script_name
) != 0) {
372 zlog_err("frrscript: failed loading script '%s.lua': error: %s",
373 script_name
, lua_tostring(L
, -1));
377 /* To check the Lua function, we get it from the global table */
378 lua_getglobal(L
, function_name
);
379 if (lua_isfunction(L
, lua_gettop(L
)) == 0) {
380 zlog_err("frrscript: loaded script '%s.lua' but %s not found",
381 script_name
, function_name
);
384 /* Then pop the function (frrscript_call will push it when it needs it)
388 if (load_cb
&& (*load_cb
)(fs
) != 0) {
390 "frrscript: '%s.lua': %s: loaded but callback returned non-zero exit code",
391 script_name
, function_name
);
395 /* Add the Lua function state to frrscript */
396 struct lua_function_state key
= {.name
= function_name
, .L
= L
};
398 hash_get(fs
->lua_function_hash
, &key
, lua_function_alloc
);
406 void frrscript_delete(struct frrscript
*fs
)
408 hash_iterate(fs
->lua_function_hash
, lua_function_free
, NULL
);
409 XFREE(MTYPE_SCRIPT
, fs
->name
);
410 XFREE(MTYPE_SCRIPT
, fs
);
413 void frrscript_init(const char *sd
)
415 codec_hash
= hash_create(codec_hash_key
, codec_hash_cmp
,
416 "Lua type encoders");
418 strlcpy(scriptdir
, sd
, sizeof(scriptdir
));
420 /* Register core library types */
421 frrscript_register_type_codecs(frrscript_codecs_lib
);
424 #endif /* HAVE_SCRIPTING */