]> git.proxmox.com Git - mirror_frr.git/blob - lib/frrlua.c
doc: Add `show ipv6 rpf X:X::X:X` command to docs
[mirror_frr.git] / lib / frrlua.c
1 /*
2 * This file defines the lua interface into
3 * FRRouting.
4 *
5 * Copyright (C) 2016-2019 Cumulus Networks, Inc.
6 * Donald Sharp, Quentin Young
7 *
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.
12 *
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.
17 *
18 * You should have received a copy of the GNU General Public License along
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
21 */
22
23 #include <zebra.h>
24
25 #ifdef HAVE_SCRIPTING
26
27 #include "prefix.h"
28 #include "frrlua.h"
29 #include "log.h"
30 #include "buffer.h"
31
32 DEFINE_MTYPE(LIB, SCRIPT_RES, "Scripting results");
33
34 /* Lua stuff */
35
36 /*
37 * FRR convenience functions.
38 *
39 * This section has convenience functions used to make interacting with the Lua
40 * stack easier.
41 */
42
43 int frrlua_table_get_integer(lua_State *L, const char *key)
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
56 /*
57 * This section has functions that convert internal FRR datatypes into Lua
58 * datatypes: one encoder function and two decoder functions for each type.
59 *
60 */
61
62 void lua_pushprefix(lua_State *L, const struct prefix *prefix)
63 {
64 char buffer[PREFIX_STRLEN];
65
66 lua_newtable(L);
67 lua_pushstring(L, prefix2str(prefix, buffer, PREFIX_STRLEN));
68 lua_setfield(L, -2, "network");
69 lua_pushinteger(L, prefix->prefixlen);
70 lua_setfield(L, -2, "length");
71 lua_pushinteger(L, prefix->family);
72 lua_setfield(L, -2, "family");
73 }
74
75 void lua_decode_prefix(lua_State *L, int idx, struct prefix *prefix)
76 {
77 lua_getfield(L, idx, "network");
78 (void)str2prefix(lua_tostring(L, -1), prefix);
79 lua_pop(L, 1);
80 /* pop the table */
81 lua_pop(L, 1);
82 }
83
84 void *lua_toprefix(lua_State *L, int idx)
85 {
86 struct prefix *p = XCALLOC(MTYPE_SCRIPT_RES, sizeof(struct prefix));
87 lua_decode_prefix(L, idx, p);
88 return p;
89 }
90
91 void lua_pushinterface(lua_State *L, const struct interface *ifp)
92 {
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
118 void lua_decode_interface(lua_State *L, int idx, struct interface *ifp)
119 {
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);
153 /* pop the table */
154 lua_pop(L, 1);
155 }
156 void *lua_tointerface(lua_State *L, int idx)
157 {
158 struct interface *ifp =
159 XCALLOC(MTYPE_SCRIPT_RES, sizeof(struct interface));
160
161 lua_decode_interface(L, idx, ifp);
162 return ifp;
163 }
164
165 void lua_pushinaddr(lua_State *L, const struct in_addr *addr)
166 {
167 char buf[INET_ADDRSTRLEN];
168
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");
176 }
177
178 void lua_decode_inaddr(lua_State *L, int idx, struct in_addr *inaddr)
179 {
180 lua_getfield(L, idx, "value");
181 inaddr->s_addr = lua_tointeger(L, -1);
182 lua_pop(L, 1);
183 /* pop the table */
184 lua_pop(L, 1);
185 }
186
187 void *lua_toinaddr(lua_State *L, int idx)
188 {
189 struct in_addr *inaddr =
190 XCALLOC(MTYPE_SCRIPT_RES, sizeof(struct in_addr));
191 lua_decode_inaddr(L, idx, inaddr);
192 return inaddr;
193 }
194
195
196 void lua_pushin6addr(lua_State *L, const struct in6_addr *addr)
197 {
198 char buf[INET6_ADDRSTRLEN];
199
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");
207 }
208
209 void lua_decode_in6addr(lua_State *L, int idx, struct in6_addr *in6addr)
210 {
211 lua_getfield(L, idx, "string");
212 inet_pton(AF_INET6, lua_tostring(L, -1), in6addr);
213 lua_pop(L, 1);
214 /* pop the table */
215 lua_pop(L, 1);
216 }
217
218 void *lua_toin6addr(lua_State *L, int idx)
219 {
220 struct in6_addr *in6addr =
221 XCALLOC(MTYPE_SCRIPT_RES, sizeof(struct in6_addr));
222 lua_decode_in6addr(L, idx, in6addr);
223 return in6addr;
224 }
225
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
241 void lua_pushsockunion(lua_State *L, const union sockunion *su)
242 {
243 char buf[SU_ADDRSTRLEN];
244
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");
253 }
254
255 void lua_decode_sockunion(lua_State *L, int idx, union sockunion *su)
256 {
257 lua_getfield(L, idx, "string");
258 if (str2sockunion(lua_tostring(L, -1), su) < 0)
259 zlog_err("Lua hook call: Failed to decode sockunion");
260
261 lua_pop(L, 1);
262 /* pop the table */
263 lua_pop(L, 1);
264 }
265
266 void *lua_tosockunion(lua_State *L, int idx)
267 {
268 union sockunion *su =
269 XCALLOC(MTYPE_SCRIPT_RES, sizeof(union sockunion));
270
271 lua_decode_sockunion(L, idx, su);
272 return su;
273 }
274
275 void lua_pushtimet(lua_State *L, const time_t *time)
276 {
277 lua_pushinteger(L, *time);
278 }
279
280 void lua_decode_timet(lua_State *L, int idx, time_t *t)
281 {
282 *t = lua_tointeger(L, idx);
283 lua_pop(L, 1);
284 }
285
286 void *lua_totimet(lua_State *L, int idx)
287 {
288 time_t *t = XCALLOC(MTYPE_SCRIPT_RES, sizeof(time_t));
289
290 lua_decode_timet(L, idx, t);
291 return t;
292 }
293
294 void lua_pushintegerp(lua_State *L, const long long *num)
295 {
296 lua_pushinteger(L, *num);
297 }
298
299 void lua_decode_integerp(lua_State *L, int idx, long long *num)
300 {
301 int isnum;
302 *num = lua_tonumberx(L, idx, &isnum);
303 lua_pop(L, 1);
304 assert(isnum);
305 }
306
307 void *lua_tointegerp(lua_State *L, int idx)
308 {
309 long long *num = XCALLOC(MTYPE_SCRIPT_RES, sizeof(long long));
310
311 lua_decode_integerp(L, idx, num);
312 return num;
313 }
314
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
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
373 void *lua_tostringp(lua_State *L, int idx)
374 {
375 char *string = XSTRDUP(MTYPE_SCRIPT_RES, lua_tostring(L, idx));
376
377 return string;
378 }
379
380 /*
381 * Decoder for const values, since we cannot modify them.
382 */
383 void lua_decode_noop(lua_State *L, int idx, const void *ptr)
384 {
385 }
386
387
388 /*
389 * Noop decoder for int.
390 */
391 void lua_decode_integer_noop(lua_State *L, int idx, int i)
392 {
393 }
394
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);
453 lua_setglobal(L, "log");
454 }
455
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
501 #endif /* HAVE_SCRIPTING */