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