]>
Commit | Line | Data |
---|---|---|
634949ae DS |
1 | /* |
2 | * This file defines the lua interface into | |
3 | * FRRouting. | |
4 | * | |
60219659 QY |
5 | * Copyright (C) 2016-2019 Cumulus Networks, Inc. |
6 | * Donald Sharp, Quentin Young | |
634949ae | 7 | * |
60219659 QY |
8 | * This program is free software; you can redistribute it and/or modify it |
9 | * under the terms of the GNU General Public License as published by the Free | |
10 | * Software Foundation; either version 2 of the License, or (at your option) | |
11 | * any later version. | |
634949ae | 12 | * |
60219659 QY |
13 | * This program is distributed in the hope that it will be useful, but WITHOUT |
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
16 | * more details. | |
634949ae DS |
17 | * |
18 | * You should have received a copy of the GNU General Public License along | |
60219659 QY |
19 | * with this program; see the file COPYING; if not, write to the Free Software |
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
634949ae | 21 | */ |
fa22080d | 22 | |
634949ae DS |
23 | #include <zebra.h> |
24 | ||
fa22080d QY |
25 | #ifdef HAVE_SCRIPTING |
26 | ||
634949ae | 27 | #include "prefix.h" |
5dbb0a7b | 28 | #include "frrlua.h" |
634949ae | 29 | #include "log.h" |
e93f19fb | 30 | #include "buffer.h" |
5f98c815 | 31 | |
78f1ac25 DL |
32 | DEFINE_MTYPE(LIB, SCRIPT_RES, "Scripting results"); |
33 | ||
5f98c815 | 34 | /* Lua stuff */ |
634949ae | 35 | |
60219659 QY |
36 | /* |
37 | * FRR convenience functions. | |
38 | * | |
39 | * This section has convenience functions used to make interacting with the Lua | |
40 | * stack easier. | |
41 | */ | |
42 | ||
60219659 | 43 | int frrlua_table_get_integer(lua_State *L, const char *key) |
634949ae DS |
44 | { |
45 | int result; | |
46 | ||
47 | lua_pushstring(L, key); | |
48 | lua_gettable(L, -2); | |
49 | ||
50 | result = lua_tointeger(L, -1); | |
51 | lua_pop(L, 1); | |
52 | ||
53 | return result; | |
54 | } | |
55 | ||
60219659 | 56 | /* |
60219659 | 57 | * This section has functions that convert internal FRR datatypes into Lua |
19eee398 DL |
58 | * datatypes: one encoder function and two decoder functions for each type. |
59 | * | |
60219659 | 60 | */ |
634949ae | 61 | |
47dd8736 | 62 | void lua_pushprefix(lua_State *L, const struct prefix *prefix) |
634949ae | 63 | { |
bf6e7265 | 64 | char buffer[PREFIX_STRLEN]; |
634949ae DS |
65 | |
66 | lua_newtable(L); | |
bf6e7265 | 67 | lua_pushstring(L, prefix2str(prefix, buffer, PREFIX_STRLEN)); |
00d9e83a QY |
68 | lua_setfield(L, -2, "network"); |
69 | lua_pushinteger(L, prefix->prefixlen); | |
70 | lua_setfield(L, -2, "length"); | |
634949ae DS |
71 | lua_pushinteger(L, prefix->family); |
72 | lua_setfield(L, -2, "family"); | |
634949ae DS |
73 | } |
74 | ||
3a3cfe47 | 75 | void lua_decode_prefix(lua_State *L, int idx, struct prefix *prefix) |
f869ab17 | 76 | { |
f869ab17 | 77 | lua_getfield(L, idx, "network"); |
3a3cfe47 | 78 | (void)str2prefix(lua_tostring(L, -1), prefix); |
f869ab17 | 79 | lua_pop(L, 1); |
8192b471 DL |
80 | /* pop the table */ |
81 | lua_pop(L, 1); | |
3a3cfe47 | 82 | } |
f869ab17 | 83 | |
3a3cfe47 DL |
84 | void *lua_toprefix(lua_State *L, int idx) |
85 | { | |
78f1ac25 | 86 | struct prefix *p = XCALLOC(MTYPE_SCRIPT_RES, sizeof(struct prefix)); |
3a3cfe47 | 87 | lua_decode_prefix(L, idx, p); |
f869ab17 QY |
88 | return p; |
89 | } | |
90 | ||
47dd8736 | 91 | void lua_pushinterface(lua_State *L, const struct interface *ifp) |
cd6ca660 | 92 | { |
cd6ca660 QY |
93 | lua_newtable(L); |
94 | lua_pushstring(L, ifp->name); | |
95 | lua_setfield(L, -2, "name"); | |
96 | lua_pushinteger(L, ifp->ifindex); | |
97 | lua_setfield(L, -2, "ifindex"); | |
98 | lua_pushinteger(L, ifp->status); | |
99 | lua_setfield(L, -2, "status"); | |
100 | lua_pushinteger(L, ifp->flags); | |
101 | lua_setfield(L, -2, "flags"); | |
102 | lua_pushinteger(L, ifp->metric); | |
103 | lua_setfield(L, -2, "metric"); | |
104 | lua_pushinteger(L, ifp->speed); | |
105 | lua_setfield(L, -2, "speed"); | |
106 | lua_pushinteger(L, ifp->mtu); | |
107 | lua_setfield(L, -2, "mtu"); | |
108 | lua_pushinteger(L, ifp->mtu6); | |
109 | lua_setfield(L, -2, "mtu6"); | |
110 | lua_pushinteger(L, ifp->bandwidth); | |
111 | lua_setfield(L, -2, "bandwidth"); | |
112 | lua_pushinteger(L, ifp->link_ifindex); | |
113 | lua_setfield(L, -2, "link_ifindex"); | |
114 | lua_pushinteger(L, ifp->ll_type); | |
115 | lua_setfield(L, -2, "linklayer_type"); | |
116 | } | |
117 | ||
3a3cfe47 | 118 | void lua_decode_interface(lua_State *L, int idx, struct interface *ifp) |
f869ab17 | 119 | { |
f869ab17 QY |
120 | lua_getfield(L, idx, "name"); |
121 | strlcpy(ifp->name, lua_tostring(L, -1), sizeof(ifp->name)); | |
122 | lua_pop(L, 1); | |
123 | lua_getfield(L, idx, "ifindex"); | |
124 | ifp->ifindex = lua_tointeger(L, -1); | |
125 | lua_pop(L, 1); | |
126 | lua_getfield(L, idx, "status"); | |
127 | ifp->status = lua_tointeger(L, -1); | |
128 | lua_pop(L, 1); | |
129 | lua_getfield(L, idx, "flags"); | |
130 | ifp->flags = lua_tointeger(L, -1); | |
131 | lua_pop(L, 1); | |
132 | lua_getfield(L, idx, "metric"); | |
133 | ifp->metric = lua_tointeger(L, -1); | |
134 | lua_pop(L, 1); | |
135 | lua_getfield(L, idx, "speed"); | |
136 | ifp->speed = lua_tointeger(L, -1); | |
137 | lua_pop(L, 1); | |
138 | lua_getfield(L, idx, "mtu"); | |
139 | ifp->mtu = lua_tointeger(L, -1); | |
140 | lua_pop(L, 1); | |
141 | lua_getfield(L, idx, "mtu6"); | |
142 | ifp->mtu6 = lua_tointeger(L, -1); | |
143 | lua_pop(L, 1); | |
144 | lua_getfield(L, idx, "bandwidth"); | |
145 | ifp->bandwidth = lua_tointeger(L, -1); | |
146 | lua_pop(L, 1); | |
147 | lua_getfield(L, idx, "link_ifindex"); | |
148 | ifp->link_ifindex = lua_tointeger(L, -1); | |
149 | lua_pop(L, 1); | |
150 | lua_getfield(L, idx, "linklayer_type"); | |
151 | ifp->ll_type = lua_tointeger(L, -1); | |
152 | lua_pop(L, 1); | |
8192b471 DL |
153 | /* pop the table */ |
154 | lua_pop(L, 1); | |
3a3cfe47 DL |
155 | } |
156 | void *lua_tointerface(lua_State *L, int idx) | |
157 | { | |
78f1ac25 DL |
158 | struct interface *ifp = |
159 | XCALLOC(MTYPE_SCRIPT_RES, sizeof(struct interface)); | |
f869ab17 | 160 | |
3a3cfe47 | 161 | lua_decode_interface(L, idx, ifp); |
f869ab17 QY |
162 | return ifp; |
163 | } | |
164 | ||
47dd8736 | 165 | void lua_pushinaddr(lua_State *L, const struct in_addr *addr) |
42ae55b5 | 166 | { |
42ae55b5 | 167 | char buf[INET_ADDRSTRLEN]; |
3a3cfe47 | 168 | |
42ae55b5 QY |
169 | inet_ntop(AF_INET, addr, buf, sizeof(buf)); |
170 | ||
171 | lua_newtable(L); | |
172 | lua_pushinteger(L, addr->s_addr); | |
173 | lua_setfield(L, -2, "value"); | |
174 | lua_pushstring(L, buf); | |
175 | lua_setfield(L, -2, "string"); | |
42ae55b5 QY |
176 | } |
177 | ||
3a3cfe47 | 178 | void lua_decode_inaddr(lua_State *L, int idx, struct in_addr *inaddr) |
f869ab17 | 179 | { |
f869ab17 QY |
180 | lua_getfield(L, idx, "value"); |
181 | inaddr->s_addr = lua_tointeger(L, -1); | |
182 | lua_pop(L, 1); | |
8192b471 DL |
183 | /* pop the table */ |
184 | lua_pop(L, 1); | |
3a3cfe47 | 185 | } |
f869ab17 | 186 | |
3a3cfe47 DL |
187 | void *lua_toinaddr(lua_State *L, int idx) |
188 | { | |
78f1ac25 DL |
189 | struct in_addr *inaddr = |
190 | XCALLOC(MTYPE_SCRIPT_RES, sizeof(struct in_addr)); | |
3a3cfe47 | 191 | lua_decode_inaddr(L, idx, inaddr); |
f869ab17 QY |
192 | return inaddr; |
193 | } | |
194 | ||
42ae55b5 | 195 | |
47dd8736 | 196 | void lua_pushin6addr(lua_State *L, const struct in6_addr *addr) |
42ae55b5 | 197 | { |
42ae55b5 | 198 | char buf[INET6_ADDRSTRLEN]; |
3a3cfe47 | 199 | |
42ae55b5 QY |
200 | inet_ntop(AF_INET6, addr, buf, sizeof(buf)); |
201 | ||
202 | lua_newtable(L); | |
203 | lua_pushlstring(L, (const char *)addr->s6_addr, 16); | |
204 | lua_setfield(L, -2, "value"); | |
205 | lua_pushstring(L, buf); | |
206 | lua_setfield(L, -2, "string"); | |
42ae55b5 QY |
207 | } |
208 | ||
3a3cfe47 | 209 | void lua_decode_in6addr(lua_State *L, int idx, struct in6_addr *in6addr) |
f869ab17 | 210 | { |
f869ab17 QY |
211 | lua_getfield(L, idx, "string"); |
212 | inet_pton(AF_INET6, lua_tostring(L, -1), in6addr); | |
213 | lua_pop(L, 1); | |
8192b471 DL |
214 | /* pop the table */ |
215 | lua_pop(L, 1); | |
3a3cfe47 | 216 | } |
f869ab17 | 217 | |
3a3cfe47 DL |
218 | void *lua_toin6addr(lua_State *L, int idx) |
219 | { | |
78f1ac25 DL |
220 | struct in6_addr *in6addr = |
221 | XCALLOC(MTYPE_SCRIPT_RES, sizeof(struct in6_addr)); | |
3a3cfe47 | 222 | lua_decode_in6addr(L, idx, in6addr); |
f869ab17 QY |
223 | return in6addr; |
224 | } | |
225 | ||
e6f42b94 DL |
226 | void lua_pushipaddr(lua_State *L, const struct ipaddr *addr) |
227 | { | |
228 | if (IS_IPADDR_V4(addr)) | |
229 | lua_pushinaddr(L, &addr->ipaddr_v4); | |
230 | else | |
231 | lua_pushin6addr(L, &addr->ipaddr_v6); | |
232 | } | |
233 | ||
234 | void lua_pushethaddr(lua_State *L, const struct ethaddr *addr) | |
235 | { | |
236 | lua_newtable(L); | |
237 | lua_pushinteger(L, *(addr->octet)); | |
238 | lua_setfield(L, -2, "octet"); | |
239 | } | |
240 | ||
47dd8736 | 241 | void lua_pushsockunion(lua_State *L, const union sockunion *su) |
42ae55b5 | 242 | { |
42ae55b5 | 243 | char buf[SU_ADDRSTRLEN]; |
3a3cfe47 | 244 | |
42ae55b5 QY |
245 | sockunion2str(su, buf, sizeof(buf)); |
246 | ||
247 | lua_newtable(L); | |
248 | lua_pushlstring(L, (const char *)sockunion_get_addr(su), | |
249 | sockunion_get_addrlen(su)); | |
250 | lua_setfield(L, -2, "value"); | |
251 | lua_pushstring(L, buf); | |
252 | lua_setfield(L, -2, "string"); | |
42ae55b5 QY |
253 | } |
254 | ||
3a3cfe47 | 255 | void lua_decode_sockunion(lua_State *L, int idx, union sockunion *su) |
f869ab17 | 256 | { |
f869ab17 | 257 | lua_getfield(L, idx, "string"); |
0db2bfc5 | 258 | if (str2sockunion(lua_tostring(L, -1), su) < 0) |
a852e5a6 | 259 | zlog_err("Lua hook call: Failed to decode sockunion"); |
0db2bfc5 | 260 | |
8192b471 DL |
261 | lua_pop(L, 1); |
262 | /* pop the table */ | |
263 | lua_pop(L, 1); | |
3a3cfe47 DL |
264 | } |
265 | ||
266 | void *lua_tosockunion(lua_State *L, int idx) | |
267 | { | |
78f1ac25 DL |
268 | union sockunion *su = |
269 | XCALLOC(MTYPE_SCRIPT_RES, sizeof(union sockunion)); | |
f869ab17 | 270 | |
3a3cfe47 | 271 | lua_decode_sockunion(L, idx, su); |
f869ab17 QY |
272 | return su; |
273 | } | |
274 | ||
47dd8736 | 275 | void lua_pushtimet(lua_State *L, const time_t *time) |
42ae55b5 QY |
276 | { |
277 | lua_pushinteger(L, *time); | |
42ae55b5 QY |
278 | } |
279 | ||
3a3cfe47 DL |
280 | void lua_decode_timet(lua_State *L, int idx, time_t *t) |
281 | { | |
282 | *t = lua_tointeger(L, idx); | |
8192b471 | 283 | lua_pop(L, 1); |
3a3cfe47 DL |
284 | } |
285 | ||
f869ab17 QY |
286 | void *lua_totimet(lua_State *L, int idx) |
287 | { | |
78f1ac25 | 288 | time_t *t = XCALLOC(MTYPE_SCRIPT_RES, sizeof(time_t)); |
f869ab17 | 289 | |
3a3cfe47 | 290 | lua_decode_timet(L, idx, t); |
f869ab17 QY |
291 | return t; |
292 | } | |
293 | ||
294 | void lua_pushintegerp(lua_State *L, const long long *num) | |
eeb61724 QY |
295 | { |
296 | lua_pushinteger(L, *num); | |
297 | } | |
298 | ||
3a3cfe47 | 299 | void lua_decode_integerp(lua_State *L, int idx, long long *num) |
f869ab17 QY |
300 | { |
301 | int isnum; | |
f869ab17 | 302 | *num = lua_tonumberx(L, idx, &isnum); |
8192b471 | 303 | lua_pop(L, 1); |
f869ab17 | 304 | assert(isnum); |
3a3cfe47 DL |
305 | } |
306 | ||
307 | void *lua_tointegerp(lua_State *L, int idx) | |
308 | { | |
78f1ac25 | 309 | long long *num = XCALLOC(MTYPE_SCRIPT_RES, sizeof(long long)); |
f869ab17 | 310 | |
3a3cfe47 | 311 | lua_decode_integerp(L, idx, num); |
f869ab17 QY |
312 | return num; |
313 | } | |
314 | ||
9b851b74 DL |
315 | void lua_pushnexthop(lua_State *L, const struct nexthop *nexthop) |
316 | { | |
317 | lua_newtable(L); | |
318 | lua_pushinteger(L, nexthop->vrf_id); | |
319 | lua_setfield(L, -2, "vrf_id"); | |
320 | lua_pushinteger(L, nexthop->ifindex); | |
321 | lua_setfield(L, -2, "ifindex"); | |
322 | lua_pushinteger(L, nexthop->type); | |
323 | lua_setfield(L, -2, "type"); | |
324 | lua_pushinteger(L, nexthop->flags); | |
325 | lua_setfield(L, -2, "flags"); | |
326 | if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) { | |
327 | lua_pushinteger(L, nexthop->bh_type); | |
328 | lua_setfield(L, -2, "bh_type"); | |
329 | } else if (nexthop->type == NEXTHOP_TYPE_IPV4) { | |
330 | lua_pushinaddr(L, &nexthop->gate.ipv4); | |
331 | lua_setfield(L, -2, "gate"); | |
332 | } else if (nexthop->type == NEXTHOP_TYPE_IPV6) { | |
333 | lua_pushin6addr(L, &nexthop->gate.ipv6); | |
334 | lua_setfield(L, -2, "gate"); | |
335 | } | |
336 | lua_pushinteger(L, nexthop->nh_label_type); | |
337 | lua_setfield(L, -2, "nh_label_type"); | |
338 | lua_pushinteger(L, nexthop->weight); | |
339 | lua_setfield(L, -2, "weight"); | |
340 | lua_pushinteger(L, nexthop->backup_num); | |
341 | lua_setfield(L, -2, "backup_num"); | |
342 | lua_pushinteger(L, *(nexthop->backup_idx)); | |
343 | lua_setfield(L, -2, "backup_idx"); | |
344 | if (nexthop->nh_encap_type == NET_VXLAN) { | |
345 | lua_pushinteger(L, nexthop->nh_encap.vni); | |
346 | lua_setfield(L, -2, "vni"); | |
347 | } | |
348 | lua_pushinteger(L, nexthop->nh_encap_type); | |
349 | lua_setfield(L, -2, "nh_encap_type"); | |
350 | lua_pushinteger(L, nexthop->srte_color); | |
351 | lua_setfield(L, -2, "srte_color"); | |
352 | } | |
353 | ||
354 | void lua_pushnexthop_group(lua_State *L, const struct nexthop_group *ng) | |
355 | { | |
356 | lua_newtable(L); | |
357 | struct nexthop *nexthop; | |
358 | int i = 0; | |
359 | ||
360 | for (ALL_NEXTHOPS_PTR(ng, nexthop)) { | |
361 | lua_pushnexthop(L, nexthop); | |
362 | lua_seti(L, -2, i); | |
363 | i++; | |
364 | } | |
365 | } | |
366 | ||
3a3cfe47 DL |
367 | void lua_decode_stringp(lua_State *L, int idx, char *str) |
368 | { | |
369 | strlcpy(str, lua_tostring(L, idx), strlen(str) + 1); | |
370 | lua_pop(L, 1); | |
371 | } | |
372 | ||
f869ab17 QY |
373 | void *lua_tostringp(lua_State *L, int idx) |
374 | { | |
78f1ac25 | 375 | char *string = XSTRDUP(MTYPE_SCRIPT_RES, lua_tostring(L, idx)); |
f869ab17 QY |
376 | |
377 | return string; | |
378 | } | |
379 | ||
19eee398 DL |
380 | /* |
381 | * Decoder for const values, since we cannot modify them. | |
382 | */ | |
7e058da5 DL |
383 | void lua_decode_noop(lua_State *L, int idx, const void *ptr) |
384 | { | |
385 | } | |
386 | ||
2b67227e DL |
387 | |
388 | /* | |
389 | * Noop decoder for int. | |
390 | */ | |
36cf58c7 | 391 | void lua_decode_integer_noop(lua_State *L, int idx, int i) |
2b67227e DL |
392 | { |
393 | } | |
394 | ||
d473bdc7 QY |
395 | /* |
396 | * Logging. | |
397 | * | |
398 | * Lua-compatible wrappers for FRR logging functions. | |
399 | */ | |
400 | static const char *frrlua_log_thunk(lua_State *L) | |
401 | { | |
402 | int nargs; | |
403 | ||
404 | nargs = lua_gettop(L); | |
405 | assert(nargs == 1); | |
406 | ||
407 | return lua_tostring(L, 1); | |
408 | } | |
409 | ||
410 | static int frrlua_log_debug(lua_State *L) | |
411 | { | |
412 | zlog_debug("%s", frrlua_log_thunk(L)); | |
413 | return 0; | |
414 | } | |
415 | ||
416 | static int frrlua_log_info(lua_State *L) | |
417 | { | |
418 | zlog_info("%s", frrlua_log_thunk(L)); | |
419 | return 0; | |
420 | } | |
421 | ||
422 | static int frrlua_log_notice(lua_State *L) | |
423 | { | |
424 | zlog_notice("%s", frrlua_log_thunk(L)); | |
425 | return 0; | |
426 | } | |
427 | ||
428 | static int frrlua_log_warn(lua_State *L) | |
429 | { | |
430 | zlog_warn("%s", frrlua_log_thunk(L)); | |
431 | return 0; | |
432 | } | |
433 | ||
434 | static int frrlua_log_error(lua_State *L) | |
435 | { | |
436 | zlog_err("%s", frrlua_log_thunk(L)); | |
437 | return 0; | |
438 | } | |
439 | ||
440 | static const luaL_Reg log_funcs[] = { | |
441 | {"debug", frrlua_log_debug}, | |
442 | {"info", frrlua_log_info}, | |
443 | {"notice", frrlua_log_notice}, | |
444 | {"warn", frrlua_log_warn}, | |
445 | {"error", frrlua_log_error}, | |
446 | {}, | |
447 | }; | |
448 | ||
449 | void frrlua_export_logging(lua_State *L) | |
450 | { | |
451 | lua_newtable(L); | |
452 | luaL_setfuncs(L, log_funcs, 0); | |
a3ce06c4 | 453 | lua_setglobal(L, "log"); |
d473bdc7 QY |
454 | } |
455 | ||
e93f19fb QY |
456 | /* |
457 | * Debugging. | |
458 | */ | |
459 | ||
460 | char *frrlua_stackdump(lua_State *L) | |
461 | { | |
462 | int top = lua_gettop(L); | |
463 | ||
464 | char tmpbuf[64]; | |
465 | struct buffer *buf = buffer_new(4098); | |
466 | ||
467 | for (int i = 1; i <= top; i++) { | |
468 | int t = lua_type(L, i); | |
469 | ||
470 | switch (t) { | |
471 | case LUA_TSTRING: /* strings */ | |
472 | snprintf(tmpbuf, sizeof(tmpbuf), "\"%s\"\n", | |
473 | lua_tostring(L, i)); | |
474 | buffer_putstr(buf, tmpbuf); | |
475 | break; | |
476 | case LUA_TBOOLEAN: /* booleans */ | |
477 | snprintf(tmpbuf, sizeof(tmpbuf), "%s\n", | |
478 | lua_toboolean(L, i) ? "true" : "false"); | |
479 | buffer_putstr(buf, tmpbuf); | |
480 | break; | |
481 | case LUA_TNUMBER: /* numbers */ | |
482 | snprintf(tmpbuf, sizeof(tmpbuf), "%g\n", | |
483 | lua_tonumber(L, i)); | |
484 | buffer_putstr(buf, tmpbuf); | |
485 | break; | |
486 | default: /* other values */ | |
487 | snprintf(tmpbuf, sizeof(tmpbuf), "%s\n", | |
488 | lua_typename(L, t)); | |
489 | buffer_putstr(buf, tmpbuf); | |
490 | break; | |
491 | } | |
492 | } | |
493 | ||
494 | char *result = XSTRDUP(MTYPE_TMP, buffer_getstr(buf)); | |
495 | ||
496 | buffer_free(buf); | |
497 | ||
498 | return result; | |
499 | } | |
500 | ||
fa22080d | 501 | #endif /* HAVE_SCRIPTING */ |