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");
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
},
66 struct hash
*codec_hash
;
67 char scriptdir
[MAXPATHLEN
];
69 static unsigned int codec_hash_key(const void *data
)
71 const struct frrscript_codec
*c
= data
;
73 return string_hash_make(c
->typename
);
76 static bool codec_hash_cmp(const void *d1
, const void *d2
)
78 const struct frrscript_codec
*e1
= d1
;
79 const struct frrscript_codec
*e2
= d2
;
81 return strmatch(e1
->typename
, e2
->typename
);
84 static void *codec_alloc(void *arg
)
86 struct frrscript_codec
*tmp
= arg
;
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
;
98 static void codec_free(struct codec
*c
)
100 XFREE(MTYPE_TMP
, c
->typename
);
105 /* Lua function hash utils */
107 unsigned int lua_function_hash_key(const void *data
)
109 const struct lua_function_state
*lfs
= data
;
111 return string_hash_make(lfs
->name
);
114 bool lua_function_hash_cmp(const void *d1
, const void *d2
)
116 const struct lua_function_state
*lfs1
= d1
;
117 const struct lua_function_state
*lfs2
= d2
;
119 return strmatch(lfs1
->name
, lfs2
->name
);
122 void *lua_function_alloc(void *arg
)
124 struct lua_function_state
*tmp
= arg
;
126 struct lua_function_state
*lfs
=
127 XCALLOC(MTYPE_SCRIPT
, sizeof(struct lua_function_state
));
128 lfs
->name
= tmp
->name
;
133 static void lua_function_free(struct hash_bucket
*b
, void *data
)
135 struct lua_function_state
*lfs
= (struct lua_function_state
*)b
->data
;
137 XFREE(MTYPE_SCRIPT
, lfs
);
140 /* internal frrscript APIs */
142 int _frrscript_call_lua(struct lua_function_state
*lfs
, int nargs
)
146 ret
= lua_pcall(lfs
->L
, nargs
, 1, 0);
152 zlog_err("Lua hook call '%s' : runtime error: %s", lfs
->name
,
153 lua_tostring(lfs
->L
, -1));
156 zlog_err("Lua hook call '%s' : memory error: %s", lfs
->name
,
157 lua_tostring(lfs
->L
, -1));
160 zlog_err("Lua hook call '%s' : error handler error: %s",
161 lfs
->name
, lua_tostring(lfs
->L
, -1));
164 zlog_err("Lua hook call '%s' : garbage collector error: %s",
165 lfs
->name
, lua_tostring(lfs
->L
, -1));
168 zlog_err("Lua hook call '%s' : unknown error: %s", lfs
->name
,
169 lua_tostring(lfs
->L
, -1));
178 if (lua_gettop(lfs
->L
) != 1) {
180 "Lua hook call '%s': Lua function should return only 1 result",
186 if (lua_istable(lfs
->L
, 1) != 1) {
188 "Lua hook call '%s': Lua function should return a Lua table",
194 /* LUA_OK is 0, so we can just return lua_pcall's result directly */
198 void *frrscript_get_result(struct frrscript
*fs
, const char *function_name
,
200 void *(*lua_to
)(lua_State
*L
, int idx
))
203 struct lua_function_state
*lfs
;
204 struct lua_function_state lookup
= {.name
= function_name
};
206 lfs
= hash_lookup(fs
->lua_function_hash
, &lookup
);
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*
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)) {
222 "frrscript: '%s.lua': '%s': tried to decode '%s' as result but failed",
223 fs
->name
, function_name
, name
);
226 p
= lua_to(lfs
->L
, 2);
228 /* At the end, the Lua state should be same as it was at the start
229 * i.e. containing solely the returned table.
231 assert(lua_gettop(lfs
->L
) == 1);
232 assert(lua_istable(lfs
->L
, -1) == 1);
237 void frrscript_register_type_codec(struct frrscript_codec
*codec
)
239 struct frrscript_codec c
= *codec
;
241 if (hash_lookup(codec_hash
, &c
)) {
242 zlog_backtrace(LOG_ERR
);
243 assert(!"Type codec double-registered.");
246 assert(hash_get(codec_hash
, &c
, codec_alloc
));
249 void frrscript_register_type_codecs(struct frrscript_codec
*codecs
)
251 for (int i
= 0; codecs
[i
].typename
!= NULL
; i
++)
252 frrscript_register_type_codec(&codecs
[i
]);
255 struct frrscript
*frrscript_new(const char *name
)
257 struct frrscript
*fs
= XCALLOC(MTYPE_SCRIPT
, sizeof(struct frrscript
));
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");
266 int frrscript_load(struct frrscript
*fs
, const char *function_name
,
267 int (*load_cb
)(struct frrscript
*))
270 /* Set up the Lua script */
271 lua_State
*L
= luaL_newstate();
273 frrlua_export_logging(L
);
275 char script_name
[MAXPATHLEN
];
277 if (snprintf(script_name
, sizeof(script_name
), "%s/%s.lua", scriptdir
,
279 >= (int)sizeof(script_name
)) {
280 zlog_err("frrscript: path to script %s/%s.lua is too long",
281 scriptdir
, fs
->name
);
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));
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
);
298 /* Then pop the function (frrscript_call will push it when it needs it)
302 if (load_cb
&& (*load_cb
)(fs
) != 0) {
304 "frrscript: '%s.lua': %s: loaded but callback returned non-zero exit code",
305 script_name
, function_name
);
309 /* Add the Lua function state to frrscript */
310 struct lua_function_state key
= {.name
= function_name
, .L
= L
};
312 hash_get(fs
->lua_function_hash
, &key
, lua_function_alloc
);
320 void frrscript_delete(struct frrscript
*fs
)
322 hash_iterate(fs
->lua_function_hash
, lua_function_free
, NULL
);
323 XFREE(MTYPE_SCRIPT
, fs
->name
);
324 XFREE(MTYPE_SCRIPT
, fs
);
327 void frrscript_init(const char *sd
)
329 codec_hash
= hash_create(codec_hash_key
, codec_hash_cmp
,
330 "Lua type encoders");
332 strlcpy(scriptdir
, sd
, sizeof(scriptdir
));
334 /* Register core library types */
335 frrscript_register_type_codecs(frrscript_codecs_lib
);
338 #endif /* HAVE_SCRIPTING */