1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2020 NVIDIA Corporation
13 #include "frrscript.h"
20 DEFINE_MTYPE_STATIC(LIB
, SCRIPT
, "Scripting");
23 * Script name hash utilities
26 struct frrscript_names_head frrscript_names_hash
;
29 * Wrapper for frrscript_names_add
30 * Use this to register hook calls when a daemon starts up
32 int frrscript_names_add_function_name(const char *function_name
)
34 struct frrscript_names_entry
*insert
=
35 XCALLOC(MTYPE_SCRIPT
, sizeof(*insert
));
36 strlcpy(insert
->function_name
, function_name
,
37 sizeof(insert
->function_name
));
39 if (frrscript_names_add(&frrscript_names_hash
, insert
)) {
41 "Failed to add hook call function name to script_names");
47 void frrscript_names_destroy(void)
49 struct frrscript_names_entry
*ne
;
51 while ((ne
= frrscript_names_pop(&frrscript_names_hash
)))
52 XFREE(MTYPE_SCRIPT
, ne
);
56 * Given a function_name, set its script_name. function_names and script_names
57 * are one-to-one. Each set will wipe the previous script_name.
58 * Return 0 if set was successful, else 1.
60 * script_name is the base name of the file, without .lua.
62 int frrscript_names_set_script_name(const char *function_name
,
63 const char *script_name
)
65 struct frrscript_names_entry lookup
;
67 strlcpy(lookup
.function_name
, function_name
,
68 sizeof(lookup
.function_name
));
69 struct frrscript_names_entry
*snhe
=
70 frrscript_names_find(&frrscript_names_hash
, &lookup
);
73 strlcpy(snhe
->script_name
, script_name
, sizeof(snhe
->script_name
));
78 * Given a function_name, get its script_name.
79 * Return NULL if function_name not found.
81 * script_name is the base name of the file, without .lua.
83 char *frrscript_names_get_script_name(const char *function_name
)
85 struct frrscript_names_entry lookup
;
87 strlcpy(lookup
.function_name
, function_name
,
88 sizeof(lookup
.function_name
));
89 struct frrscript_names_entry
*snhe
=
90 frrscript_names_find(&frrscript_names_hash
, &lookup
);
94 if (snhe
->script_name
[0] == '\0')
97 return snhe
->script_name
;
100 uint32_t frrscript_names_hash_key(const struct frrscript_names_entry
*snhe
)
102 return string_hash_make(snhe
->function_name
);
105 int frrscript_names_hash_cmp(const struct frrscript_names_entry
*snhe1
,
106 const struct frrscript_names_entry
*snhe2
)
108 return strncmp(snhe1
->function_name
, snhe2
->function_name
,
109 sizeof(snhe1
->function_name
));
114 struct frrscript_codec frrscript_codecs_lib
[] = {
115 {.typename
= "integer",
116 .encoder
= (encoder_func
)lua_pushintegerp
,
117 .decoder
= lua_tointegerp
},
118 {.typename
= "string",
119 .encoder
= (encoder_func
)lua_pushstring_wrapper
,
120 .decoder
= lua_tostringp
},
121 {.typename
= "prefix",
122 .encoder
= (encoder_func
)lua_pushprefix
,
123 .decoder
= lua_toprefix
},
124 {.typename
= "interface",
125 .encoder
= (encoder_func
)lua_pushinterface
,
126 .decoder
= lua_tointerface
},
127 {.typename
= "in_addr",
128 .encoder
= (encoder_func
)lua_pushinaddr
,
129 .decoder
= lua_toinaddr
},
130 {.typename
= "in6_addr",
131 .encoder
= (encoder_func
)lua_pushin6addr
,
132 .decoder
= lua_toin6addr
},
133 {.typename
= "sockunion",
134 .encoder
= (encoder_func
)lua_pushsockunion
,
135 .decoder
= lua_tosockunion
},
136 {.typename
= "time_t",
137 .encoder
= (encoder_func
)lua_pushtimet
,
138 .decoder
= lua_totimet
},
143 struct hash
*codec_hash
;
144 char scriptdir
[MAXPATHLEN
];
146 static unsigned int codec_hash_key(const void *data
)
148 const struct frrscript_codec
*c
= data
;
150 return string_hash_make(c
->typename
);
153 static bool codec_hash_cmp(const void *d1
, const void *d2
)
155 const struct frrscript_codec
*e1
= d1
;
156 const struct frrscript_codec
*e2
= d2
;
158 return strmatch(e1
->typename
, e2
->typename
);
161 static void *codec_alloc(void *arg
)
163 struct frrscript_codec
*tmp
= arg
;
165 struct frrscript_codec
*e
=
166 XCALLOC(MTYPE_SCRIPT
, sizeof(struct frrscript_codec
));
167 e
->typename
= XSTRDUP(MTYPE_SCRIPT
, tmp
->typename
);
168 e
->encoder
= tmp
->encoder
;
169 e
->decoder
= tmp
->decoder
;
174 static void codec_free(void *data
)
176 struct frrscript_codec
*c
= data
;
177 char *constworkaroundandihateit
= (char *)c
->typename
;
179 XFREE(MTYPE_SCRIPT
, constworkaroundandihateit
);
180 XFREE(MTYPE_SCRIPT
, c
);
183 /* Lua function hash utils */
185 unsigned int lua_function_hash_key(const void *data
)
187 const struct lua_function_state
*lfs
= data
;
189 return string_hash_make(lfs
->name
);
192 bool lua_function_hash_cmp(const void *d1
, const void *d2
)
194 const struct lua_function_state
*lfs1
= d1
;
195 const struct lua_function_state
*lfs2
= d2
;
197 return strmatch(lfs1
->name
, lfs2
->name
);
200 void *lua_function_alloc(void *arg
)
202 struct lua_function_state
*tmp
= arg
;
203 struct lua_function_state
*lfs
=
204 XCALLOC(MTYPE_SCRIPT
, sizeof(struct lua_function_state
));
206 lfs
->name
= tmp
->name
;
211 static void lua_function_free(void *data
)
213 struct lua_function_state
*lfs
= data
;
216 XFREE(MTYPE_SCRIPT
, lfs
);
219 /* internal frrscript APIs */
221 int _frrscript_call_lua(struct lua_function_state
*lfs
, int nargs
)
225 ret
= lua_pcall(lfs
->L
, nargs
, 1, 0);
231 zlog_err("Lua hook call '%s' : runtime error: %s", lfs
->name
,
232 lua_tostring(lfs
->L
, -1));
235 zlog_err("Lua hook call '%s' : memory error: %s", lfs
->name
,
236 lua_tostring(lfs
->L
, -1));
239 zlog_err("Lua hook call '%s' : error handler error: %s",
240 lfs
->name
, lua_tostring(lfs
->L
, -1));
243 zlog_err("Lua hook call '%s' : garbage collector error: %s",
244 lfs
->name
, lua_tostring(lfs
->L
, -1));
247 zlog_err("Lua hook call '%s' : unknown error: %s", lfs
->name
,
248 lua_tostring(lfs
->L
, -1));
257 if (lua_gettop(lfs
->L
) != 1) {
259 "Lua hook call '%s': Lua function should return only 1 result",
265 if (lua_istable(lfs
->L
, 1) != 1) {
267 "Lua hook call '%s': Lua function should return a Lua table",
273 /* LUA_OK is 0, so we can just return lua_pcall's result directly */
277 void *frrscript_get_result(struct frrscript
*fs
, const char *function_name
,
279 void *(*lua_to
)(lua_State
*L
, int idx
))
282 struct lua_function_state
*lfs
;
283 struct lua_function_state lookup
= {.name
= function_name
};
285 lfs
= hash_lookup(fs
->lua_function_hash
, &lookup
);
290 /* At this point, the Lua state should have only the returned table.
291 * We will then search the table for the key/value we're interested in.
292 * Then if the value is present (i.e. non-nil), call the lua_to*
295 assert(lua_gettop(lfs
->L
) == 1);
296 assert(lua_istable(lfs
->L
, -1) == 1);
297 lua_getfield(lfs
->L
, -1, name
);
298 if (lua_isnil(lfs
->L
, -1)) {
301 "frrscript: '%s.lua': '%s': tried to decode '%s' as result but failed",
302 fs
->name
, function_name
, name
);
305 p
= lua_to(lfs
->L
, 2);
307 /* At the end, the Lua state should be same as it was at the start
308 * i.e. containing solely the returned table.
310 assert(lua_gettop(lfs
->L
) == 1);
311 assert(lua_istable(lfs
->L
, -1) == 1);
316 void frrscript_register_type_codec(struct frrscript_codec
*codec
)
318 struct frrscript_codec c
= *codec
;
320 if (hash_lookup(codec_hash
, &c
)) {
321 zlog_backtrace(LOG_ERR
);
322 assert(!"Type codec double-registered.");
325 (void)hash_get(codec_hash
, &c
, codec_alloc
);
328 void frrscript_register_type_codecs(struct frrscript_codec
*codecs
)
330 for (int i
= 0; codecs
[i
].typename
!= NULL
; i
++)
331 frrscript_register_type_codec(&codecs
[i
]);
334 struct frrscript
*frrscript_new(const char *name
)
336 struct frrscript
*fs
= XCALLOC(MTYPE_SCRIPT
, sizeof(struct frrscript
));
338 fs
->name
= XSTRDUP(MTYPE_SCRIPT
, name
);
339 fs
->lua_function_hash
=
340 hash_create(lua_function_hash_key
, lua_function_hash_cmp
,
341 "Lua function state hash");
345 int frrscript_load(struct frrscript
*fs
, const char *function_name
,
346 int (*load_cb
)(struct frrscript
*))
349 /* Set up the Lua script */
350 lua_State
*L
= luaL_newstate();
352 frrlua_export_logging(L
);
354 char script_name
[MAXPATHLEN
];
356 if (snprintf(script_name
, sizeof(script_name
), "%s/%s.lua", scriptdir
,
358 >= (int)sizeof(script_name
)) {
359 zlog_err("frrscript: path to script %s/%s.lua is too long",
360 scriptdir
, fs
->name
);
364 if (luaL_dofile(L
, script_name
) != 0) {
365 zlog_err("frrscript: failed loading script '%s': error: %s",
366 script_name
, lua_tostring(L
, -1));
370 /* To check the Lua function, we get it from the global table */
371 lua_getglobal(L
, function_name
);
372 if (lua_isfunction(L
, lua_gettop(L
)) == 0) {
373 zlog_err("frrscript: loaded script '%s' but %s not found",
374 script_name
, function_name
);
377 /* Then pop the function (frrscript_call will push it when it needs it)
381 if (load_cb
&& (*load_cb
)(fs
) != 0) {
383 "frrscript: '%s': %s: loaded but callback returned non-zero exit code",
384 script_name
, function_name
);
388 /* Add the Lua function state to frrscript */
389 struct lua_function_state key
= {.name
= function_name
, .L
= L
};
391 (void)hash_get(fs
->lua_function_hash
, &key
, lua_function_alloc
);
399 void frrscript_delete(struct frrscript
*fs
)
401 hash_clean_and_free(&fs
->lua_function_hash
, lua_function_free
);
402 XFREE(MTYPE_SCRIPT
, fs
->name
);
403 XFREE(MTYPE_SCRIPT
, fs
);
406 void frrscript_init(const char *sd
)
408 codec_hash
= hash_create(codec_hash_key
, codec_hash_cmp
,
409 "Lua type encoders");
411 strlcpy(scriptdir
, sd
, sizeof(scriptdir
));
413 /* Register core library types */
414 frrscript_register_type_codecs(frrscript_codecs_lib
);
417 void frrscript_fini(void)
419 hash_clean_and_free(&codec_hash
, codec_free
);
421 frrscript_names_destroy();
423 #endif /* HAVE_SCRIPTING */