Merge pull request #9440 from dlqs/dplanehook2

This commit is contained in:
Quentin Young 2021-10-26 15:26:32 -04:00 committed by GitHub
commit 0c124f75db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 1000 additions and 13 deletions

View File

@ -1,22 +1,31 @@
.. _scripting:
.. _scripting-user:
*********
Scripting
*********
The behavior of FRR may be extended or customized using its built-in scripting
capabilities.
capabilities. The scripting language is Lua 5.3. This guide assumes Lua
knowledge. For more information on Lua, consult the Lua 5.3 reference manual, or
*Programming in Lua* (note that the free version covers only Lua 5.0).
Some configuration commands accept the name of a Lua script to call to perform
some task or make some decision. These scripts have their environments
populated with some set of inputs, and are expected to populate some set of
output variables, which are read by FRR after the script completes. The names
and expected contents of these scripts are documented alongside the commands
that support them.
https://www.lua.org/manual/5.3/
These scripts live in :file:`/etc/frr/scripts/` by default. This is
configurable at compile time via ``--with-scriptdir``. It may be
overriden at runtime with the ``--scriptdir`` daemon option.
http://www.lua.org/pil/contents.html
Scripting
=========
.. seealso:: Developer docs for scripting
How to use
----------
1. Identify the Lua function name. See :ref:`lua-hook-calls`.
2. Write the Lua script
3. Configure FRR to use the Lua script
In order to use scripting, FRR must be built with ``--enable-scripting``.
@ -26,3 +35,51 @@ In order to use scripting, FRR must be built with ``--enable-scripting``.
contents of a script that is in use without restarting FRR. Not all
scripting locations may behave this way; refer to the documentation for the
particular location.
Example: on_rib_process_dplane_results
--------------------------------------
This example shows how to write a Lua script that logs changes when a route is
added.
First, identify the Lua hook call to attach a Lua function to: this will be the
name of the Lua function. In this case, since the hook call is
`on_rib_process_dplane_results`:
.. code-block:: lua
function on_rib_process_dplane_results(ctx)
log.info(ctx.rinfo.zd_dest.network)
return {}
The documentation for :ref:`on-rib-process-dplane-results` tells us its
arguments. Here, the destination prefix for a route is being logged out.
Scripts live in :file:`/etc/frr/scripts/` by default. This is configurable at
compile time via ``--with-scriptdir``. It may be overriden at runtime with the
``--scriptdir`` daemon option.
The documentation for :ref:`on-rib-process-dplane-results` indicates that the
``script`` command should be used to set the script. Assuming that the above
function was created in :file:`/etc/frr/scripts/my_dplane_script.lua`, the
following vtysh command sets the script for the hook call:
.. code-block:: console
script on_rib_process_dplane_results my_dplane_script
After the script is set, when the hook call is hit, FRR will look for a
*on_rib_process_dplane_results* function in
:file:`/etc/frr/scripts/my_dplane_script.lua` and run it with the ``ctx`` object
as its argument.
.. _lua-hook-calls:
Available Lua hook calls
========================
:ref:`on-rib-process-dplane-results`

View File

@ -1416,3 +1416,199 @@ Debugging
Nexthop and nexthop-group events.
Scripting
=========
.. clicmd:: zebra on-rib-process script SCRIPT
Set a Lua script for :ref:`on-rib-process-dplane-results` hook call.
SCRIPT is the basename of the script, without `.lua`.
Data structures
---------------
.. _const-struct-zebra-dplane-ctx:
const struct zebra_dplane_ctx
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: console
* integer zd_op
* integer zd_status
* integer zd_provider
* integer zd_vrf_id
* integer zd_table_id
* integer zd_ifname
* integer zd_ifindex
* table rinfo (if zd_op is DPLANE_OP_ROUTE*, DPLANE_NH_*)
* prefix zd_dest
* prefix zd_src
* integer zd_afi
* integer zd_safi
* integer zd_type
* integer zd_old_type
* integer zd_tag
* integer zd_old_tag
* integer zd_metric
* integer zd_old_metric
* integer zd_instance
* integer zd_old_instance
* integer zd_distance
* integer zd_old_distance
* integer zd_mtu
* integer zd_nexthop_mtu
* table nhe
* integer id
* integer old_id
* integer afi
* integer vrf_id
* integer type
* nexthop_group ng
* nh_grp
* integer nh_grp_count
* integer zd_nhg_id
* nexthop_group zd_ng
* nexthop_group backup_ng
* nexthop_group zd_old_ng
* nexthop_group old_backup_ng
* integer label (if zd_op is DPLANE_OP_LSP_*)
* table pw (if zd_op is DPLANE_OP_PW_*)
* integer type
* integer af
* integer status
* integer flags
* integer local_label
* integer remote_label
* table macinfo (if zd_op is DPLANE_OP_MAC_*)
* integer vid
* integer br_ifindex
* ethaddr mac
* integer vtep_ip
* integer is_sticky
* integer nhg_id
* integer update_flags
* table rule (if zd_op is DPLANE_OP_RULE_*)
* integer sock
* integer unique
* integer seq
* string ifname
* integer priority
* integer old_priority
* integer table
* integer old_table
* integer filter_bm
* integer old_filter_bm
* integer fwmark
* integer old_fwmark
* integer dsfield
* integer old_dsfield
* integer ip_proto
* integer old_ip_proto
* prefix src_ip
* prefix old_src_ip
* prefix dst_ip
* prefix old_dst_ip
* table iptable (if zd_op is DPLANE_OP_IPTABLE_*)
* integer sock
* integer vrf_id
* integer unique
* integer type
* integer filter_bm
* integer fwmark
* integer action
* integer pkt_len_min
* integer pkt_len_max
* integer tcp_flags
* integer dscp_value
* integer fragment
* integer protocol
* integer nb_interface
* integer flow_label
* integer family
* string ipset_name
* table ipset (if zd_op is DPLANE_OP_IPSET_*)
* integer sock
* integer vrf_id
* integer unique
* integer type
* integer family
* string ipset_name
* table neigh (if zd_op is DPLANE_OP_NEIGH_*)
* ipaddr ip_addr
* table link
* ethaddr mac
* ipaddr ip_addr
* integer flags
* integer state
* integer update_flags
* table br_port (if zd_op is DPLANE_OP_BR_PORT_UPDATE)
* integer sph_filter_cnt
* integer flags
* integer backup_nhg_id
* table neightable (if zd_op is DPLANE_OP_NEIGH_TABLE_UPDATE)
* integer family
* integer app_probes
* integer ucast_probes
* integer mcast_probes
* table gre (if zd_op is DPLANE_OP_GRE_SET)**
* integer link_ifindex
* integer mtu
.. _const-struct-nh-grp:
const struct nh_grp
^^^^^^^^^^^^^^^^^^^
.. code-block:: console
* integer id
* integer weight
.. _zebra-hook-calls:
Zebra Hook calls
----------------
.. _on-rib-process-dplane-results:
on_rib_process_dplane_results
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Called when RIB processes dataplane events.
Set script location with the ``zebra on-rib-process script SCRIPT`` command.
**Arguments**
* :ref:`const struct zebra_dplane_ctx<const-struct-zebra-dplane-ctx>` ctx
.. code-block:: lua
function on_rib_process_dplane_results(ctx)
log.info(ctx.rinfo.zd_dest.network)
return {}

View File

@ -223,6 +223,21 @@ void *lua_toin6addr(lua_State *L, int idx)
return in6addr;
}
void lua_pushipaddr(lua_State *L, const struct ipaddr *addr)
{
if (IS_IPADDR_V4(addr))
lua_pushinaddr(L, &addr->ipaddr_v4);
else
lua_pushin6addr(L, &addr->ipaddr_v6);
}
void lua_pushethaddr(lua_State *L, const struct ethaddr *addr)
{
lua_newtable(L);
lua_pushinteger(L, *(addr->octet));
lua_setfield(L, -2, "octet");
}
void lua_pushsockunion(lua_State *L, const union sockunion *su)
{
char buf[SU_ADDRSTRLEN];
@ -297,6 +312,58 @@ void *lua_tointegerp(lua_State *L, int idx)
return num;
}
void lua_pushnexthop(lua_State *L, const struct nexthop *nexthop)
{
lua_newtable(L);
lua_pushinteger(L, nexthop->vrf_id);
lua_setfield(L, -2, "vrf_id");
lua_pushinteger(L, nexthop->ifindex);
lua_setfield(L, -2, "ifindex");
lua_pushinteger(L, nexthop->type);
lua_setfield(L, -2, "type");
lua_pushinteger(L, nexthop->flags);
lua_setfield(L, -2, "flags");
if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) {
lua_pushinteger(L, nexthop->bh_type);
lua_setfield(L, -2, "bh_type");
} else if (nexthop->type == NEXTHOP_TYPE_IPV4) {
lua_pushinaddr(L, &nexthop->gate.ipv4);
lua_setfield(L, -2, "gate");
} else if (nexthop->type == NEXTHOP_TYPE_IPV6) {
lua_pushin6addr(L, &nexthop->gate.ipv6);
lua_setfield(L, -2, "gate");
}
lua_pushinteger(L, nexthop->nh_label_type);
lua_setfield(L, -2, "nh_label_type");
lua_pushinteger(L, nexthop->weight);
lua_setfield(L, -2, "weight");
lua_pushinteger(L, nexthop->backup_num);
lua_setfield(L, -2, "backup_num");
lua_pushinteger(L, *(nexthop->backup_idx));
lua_setfield(L, -2, "backup_idx");
if (nexthop->nh_encap_type == NET_VXLAN) {
lua_pushinteger(L, nexthop->nh_encap.vni);
lua_setfield(L, -2, "vni");
}
lua_pushinteger(L, nexthop->nh_encap_type);
lua_setfield(L, -2, "nh_encap_type");
lua_pushinteger(L, nexthop->srte_color);
lua_setfield(L, -2, "srte_color");
}
void lua_pushnexthop_group(lua_State *L, const struct nexthop_group *ng)
{
lua_newtable(L);
struct nexthop *nexthop;
int i = 0;
for (ALL_NEXTHOPS_PTR(ng, nexthop)) {
lua_pushnexthop(L, nexthop);
lua_seti(L, -2, i);
i++;
}
}
void lua_decode_stringp(lua_State *L, int idx, char *str)
{
strlcpy(str, lua_tostring(L, idx), strlen(str) + 1);

View File

@ -100,6 +100,10 @@ void lua_pushin6addr(lua_State *L, const struct in6_addr *addr);
void lua_decode_in6addr(lua_State *L, int idx, struct in6_addr *addr);
void lua_pushipaddr(lua_State *L, const struct ipaddr *addr);
void lua_pushethaddr(lua_State *L, const struct ethaddr *addr);
/*
* Converts the Lua value at idx to an in6_addr.
*
@ -138,6 +142,10 @@ void lua_decode_sockunion(lua_State *L, int idx, union sockunion *su);
*/
void *lua_tosockunion(lua_State *L, int idx);
void lua_pushnexthop_group(lua_State *L, const struct nexthop_group *ng);
void lua_pushnexthop(lua_State *L, const struct nexthop *nexthop);
/*
* Converts an int to a Lua value and pushes it on the stack.
*/

View File

@ -32,6 +32,92 @@
DEFINE_MTYPE_STATIC(LIB, SCRIPT, "Scripting");
/*
* Script name hash utilities
*/
struct frrscript_names_head frrscript_names_hash;
/*
* Wrapper for frrscript_names_add
* Use this to register hook calls when a daemon starts up
*/
int frrscript_names_add_function_name(const char *function_name)
{
struct frrscript_names_entry *insert =
XCALLOC(MTYPE_SCRIPT, sizeof(*insert));
strlcpy(insert->function_name, function_name,
sizeof(insert->function_name));
if (frrscript_names_add(&frrscript_names_hash, insert)) {
zlog_warn(
"Failed to add hook call function name to script_names");
return 1;
}
return 0;
}
void frrscript_names_destroy(void)
{
struct frrscript_names_entry *ne;
while ((ne = frrscript_names_pop(&frrscript_names_hash)))
XFREE(MTYPE_SCRIPT, ne);
}
/*
* Given a function_name, set its script_name. function_names and script_names
* are one-to-one. Each set will wipe the previous script_name.
* Return 0 if set was successful, else 1.
*
* script_name is the base name of the file, without .lua.
*/
int frrscript_names_set_script_name(const char *function_name,
const char *script_name)
{
struct frrscript_names_entry lookup;
strlcpy(lookup.function_name, function_name,
sizeof(lookup.function_name));
struct frrscript_names_entry *snhe =
frrscript_names_find(&frrscript_names_hash, &lookup);
if (!snhe)
return 1;
strlcpy(snhe->script_name, script_name, sizeof(snhe->script_name));
return 0;
}
/*
* Given a function_name, get its script_name.
* Return NULL if function_name not found.
*
* script_name is the base name of the file, without .lua.
*/
char *frrscript_names_get_script_name(const char *function_name)
{
struct frrscript_names_entry lookup;
strlcpy(lookup.function_name, function_name,
sizeof(lookup.function_name));
struct frrscript_names_entry *snhe =
frrscript_names_find(&frrscript_names_hash, &lookup);
if (!snhe)
return NULL;
return snhe->script_name;
}
uint32_t frrscript_names_hash_key(const struct frrscript_names_entry *snhe)
{
return string_hash_make(snhe->function_name);
}
int frrscript_names_hash_cmp(const struct frrscript_names_entry *snhe1,
const struct frrscript_names_entry *snhe2)
{
return strncmp(snhe1->function_name, snhe2->function_name,
sizeof(snhe1->function_name));
}
/* Codecs */
struct frrscript_codec frrscript_codecs_lib[] = {

View File

@ -24,6 +24,8 @@
#ifdef HAVE_SCRIPTING
#include <lua.h>
#include <nexthop.h>
#include <nexthop_group.h>
#include "frrlua.h"
#include "bgpd/bgp_script.h" // for peer and attr encoders/decoders
@ -31,6 +33,43 @@
extern "C" {
#endif
/* Forward declarations */
extern struct zebra_dplane_ctx ctx;
extern void lua_pushzebra_dplane_ctx(lua_State *L,
const struct zebra_dplane_ctx *ctx);
extern void lua_decode_zebra_dplane_ctx(lua_State *L, int idx,
struct zebra_dplane_ctx *ctx);
/*
* Script name hash
*/
PREDECL_HASH(frrscript_names);
struct frrscript_names_entry {
/* Name of a Lua hook call */
char function_name[MAXPATHLEN];
/* Lua script in which to look for it */
char script_name[MAXPATHLEN];
struct frrscript_names_item item;
};
extern struct frrscript_names_head frrscript_names_hash;
int frrscript_names_hash_cmp(const struct frrscript_names_entry *snhe1,
const struct frrscript_names_entry *snhe2);
uint32_t frrscript_names_hash_key(const struct frrscript_names_entry *snhe);
DECLARE_HASH(frrscript_names, struct frrscript_names_entry, item,
frrscript_names_hash_cmp, frrscript_names_hash_key);
int frrscript_names_add_function_name(const char *function_name);
void frrscript_names_destroy(void);
int frrscript_names_set_script_name(const char *function_name,
const char *script_name);
char *frrscript_names_get_script_name(const char *function_name);
typedef void (*encoder_func)(lua_State *, const void *);
typedef void *(*decoder_func)(lua_State *, int);
@ -171,7 +210,12 @@ time_t * : lua_pushtimet, \
char * : lua_pushstring_wrapper, \
struct attr * : lua_pushattr, \
struct peer * : lua_pushpeer, \
const struct prefix * : lua_pushprefix \
const struct prefix * : lua_pushprefix, \
const struct ipaddr * : lua_pushipaddr, \
const struct ethaddr * : lua_pushethaddr, \
const struct nexthop_group * : lua_pushnexthop_group, \
const struct nexthop * : lua_pushnexthop, \
struct zebra_dplane_ctx * : lua_pushzebra_dplane_ctx \
)((L), (value))
#define DECODE_ARGS_WITH_STATE(L, value) \
@ -187,7 +231,12 @@ time_t * : lua_decode_timet, \
char * : lua_decode_stringp, \
struct attr * : lua_decode_attr, \
struct peer * : lua_decode_noop, \
const struct prefix * : lua_decode_noop \
const struct prefix * : lua_decode_noop, \
const struct ipaddr * : lua_decode_noop, \
const struct ethaddr * : lua_decode_noop, \
const struct nexthop_group * : lua_decode_noop, \
const struct nexthop * : lua_decode_noop, \
struct zebra_dplane_ctx * : lua_decode_noop \
)((L), -1, (value))
/*

View File

@ -383,6 +383,9 @@ typedef uint32_t route_tag_t;
#define ROUTE_TAG_MAX UINT32_MAX
#define ROUTE_TAG_PRI PRIu32
/* Name of hook calls */
#define ZEBRA_ON_RIB_PROCESS_HOOK_CALL "on_rib_process_dplane_results"
#ifdef __cplusplus
}
#endif

View File

@ -116,6 +116,7 @@ zebra_zebra_SOURCES = \
zebra/zebra_routemap.c \
zebra/zebra_routemap_nb.c \
zebra/zebra_routemap_nb_config.c \
zebra/zebra_script.c \
zebra/zebra_srte.c \
zebra/zebra_vrf.c \
zebra/zebra_vty.c \
@ -185,6 +186,7 @@ noinst_HEADERS += \
zebra/zebra_routemap.h \
zebra/zebra_routemap_nb.h \
zebra/zebra_router.h \
zebra/zebra_script.h \
zebra/zebra_srte.h \
zebra/zebra_vrf.h \
zebra/zebra_vxlan.h \

View File

@ -39,6 +39,7 @@
#include "nexthop_group_private.h"
#include "frr_pthread.h"
#include "printfrr.h"
#include "frrscript.h"
#include "zebra/zebra_router.h"
#include "zebra/connected.h"
@ -57,6 +58,7 @@
#include "zebra/zapi_msg.h"
#include "zebra/zebra_dplane.h"
#include "zebra/zebra_evpn_mh.h"
#include "zebra/zebra_script.h"
DEFINE_MGROUP(ZEBRA, "zebra");
@ -4135,7 +4137,31 @@ static int rib_process_dplane_results(struct thread *thread)
continue;
}
#ifdef HAVE_SCRIPTING
char *script_name = frrscript_names_get_script_name(
ZEBRA_ON_RIB_PROCESS_HOOK_CALL);
int ret = 1;
struct frrscript *fs;
if (script_name) {
fs = frrscript_new(script_name);
if (fs)
ret = frrscript_load(
fs, ZEBRA_ON_RIB_PROCESS_HOOK_CALL,
NULL);
}
#endif /* HAVE_SCRIPTING */
while (ctx) {
#ifdef HAVE_SCRIPTING
if (ret == 0)
frrscript_call(fs,
ZEBRA_ON_RIB_PROCESS_HOOK_CALL,
("ctx", ctx));
#endif /* HAVE_SCRIPTING */
switch (dplane_ctx_get_op(ctx)) {
case DPLANE_OP_ROUTE_INSTALL:
case DPLANE_OP_ROUTE_UPDATE:

View File

@ -255,6 +255,10 @@ void zebra_router_terminate(void)
hash_free(zrouter.ipset_entry_hash);
hash_clean(zrouter.iptable_hash, zebra_pbr_iptable_free);
hash_free(zrouter.iptable_hash);
#ifdef HAVE_SCRIPTING
zebra_script_destroy();
#endif
}
bool zebra_router_notify_on_ack(void)
@ -296,4 +300,8 @@ void zebra_router_init(bool asic_offload, bool notify_on_ack)
zrouter.asic_offloaded = asic_offload;
zrouter.notify_on_ack = notify_on_ack;
#ifdef HAVE_SCRIPTING
zebra_script_init();
#endif
}

415
zebra/zebra_script.c Normal file
View File

@ -0,0 +1,415 @@
/*
* frrscript encoders and decoders for data structures in Zebra
* Copyright (C) 2021 Donald Lee
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "zebra_script.h"
#ifdef HAVE_SCRIPTING
void zebra_script_init(void)
{
frrscript_names_add_function_name(ZEBRA_ON_RIB_PROCESS_HOOK_CALL);
}
void zebra_script_destroy(void)
{
frrscript_names_destroy();
}
void lua_pushnh_grp(lua_State *L, const struct nh_grp *nh_grp)
{
lua_newtable(L);
lua_pushinteger(L, nh_grp->id);
lua_setfield(L, -2, "id");
lua_pushinteger(L, nh_grp->weight);
lua_setfield(L, -2, "weight");
}
void lua_pushzebra_dplane_ctx(lua_State *L, const struct zebra_dplane_ctx *ctx)
{
lua_newtable(L);
lua_pushinteger(L, dplane_ctx_get_op(ctx));
lua_setfield(L, -2, "zd_op");
lua_pushinteger(L, dplane_ctx_get_status(ctx));
lua_setfield(L, -2, "zd_status");
lua_pushinteger(L, dplane_ctx_get_provider(ctx));
lua_setfield(L, -2, "zd_provider");
lua_pushinteger(L, dplane_ctx_get_vrf(ctx));
lua_setfield(L, -2, "zd_vrf_id");
lua_pushinteger(L, dplane_ctx_get_table(ctx));
lua_setfield(L, -2, "zd_table_id");
lua_pushstring(L, dplane_ctx_get_ifname(ctx));
lua_setfield(L, -2, "zd_ifname");
lua_pushinteger(L, dplane_ctx_get_ifindex(ctx));
lua_setfield(L, -2, "zd_ifindex");
switch (dplane_ctx_get_op(ctx)) {
case DPLANE_OP_ROUTE_INSTALL:
case DPLANE_OP_ROUTE_UPDATE:
case DPLANE_OP_ROUTE_DELETE:
case DPLANE_OP_ROUTE_NOTIFY:
case DPLANE_OP_NH_INSTALL:
case DPLANE_OP_NH_UPDATE:
case DPLANE_OP_NH_DELETE:
/* rinfo */
lua_newtable(L);
{
lua_pushprefix(L, dplane_ctx_get_dest(ctx));
lua_setfield(L, -2, "zd_dest");
const struct prefix *src_pfx = dplane_ctx_get_src(ctx);
if (src_pfx) {
lua_pushprefix(L, src_pfx);
lua_setfield(L, -2, "zd_src");
}
lua_pushinteger(L, dplane_ctx_get_afi(ctx));
lua_setfield(L, -2, "zd_afi");
lua_pushinteger(L, dplane_ctx_get_safi(ctx));
lua_setfield(L, -2, "zd_safi");
lua_pushinteger(L, dplane_ctx_get_type(ctx));
lua_setfield(L, -2, "zd_type");
lua_pushinteger(L, dplane_ctx_get_old_type(ctx));
lua_setfield(L, -2, "zd_old_type");
lua_pushinteger(L, dplane_ctx_get_tag(ctx));
lua_setfield(L, -2, "zd_tag");
lua_pushinteger(L, dplane_ctx_get_old_tag(ctx));
lua_setfield(L, -2, "zd_old_tag");
lua_pushinteger(L, dplane_ctx_get_metric(ctx));
lua_setfield(L, -2, "zd_metric");
lua_pushinteger(L, dplane_ctx_get_old_metric(ctx));
lua_setfield(L, -2, "zd_old_metric");
lua_pushinteger(L, dplane_ctx_get_instance(ctx));
lua_setfield(L, -2, "zd_instance");
lua_pushinteger(L, dplane_ctx_get_old_instance(ctx));
lua_setfield(L, -2, "zd_old_instance");
lua_pushinteger(L, dplane_ctx_get_distance(ctx));
lua_setfield(L, -2, "zd_distance");
lua_pushinteger(L, dplane_ctx_get_old_distance(ctx));
lua_setfield(L, -2, "zd_old_distance");
lua_pushinteger(L, dplane_ctx_get_mtu(ctx));
lua_setfield(L, -2, "zd_mtu");
lua_pushinteger(L, dplane_ctx_get_nh_mtu(ctx));
lua_setfield(L, -2, "zd_nexthop_mtu");
/* nhe */
lua_newtable(L);
{
lua_pushinteger(L, dplane_ctx_get_nhe_id(ctx));
lua_setfield(L, -2, "id");
lua_pushinteger(L,
dplane_ctx_get_old_nhe_id(ctx));
lua_setfield(L, -2, "old_id");
lua_pushinteger(L, dplane_ctx_get_nhe_afi(ctx));
lua_setfield(L, -2, "afi");
lua_pushinteger(L,
dplane_ctx_get_nhe_vrf_id(ctx));
lua_setfield(L, -2, "vrf_id");
lua_pushinteger(L,
dplane_ctx_get_nhe_type(ctx));
lua_setfield(L, -2, "type");
lua_pushnexthop_group(
L, dplane_ctx_get_nhe_ng(ctx));
lua_setfield(L, -2, "ng");
lua_pushnh_grp(L,
dplane_ctx_get_nhe_nh_grp(ctx));
lua_setfield(L, -2, "nh_grp");
lua_pushinteger(
L,
dplane_ctx_get_nhe_nh_grp_count(ctx));
lua_setfield(L, -2, "nh_grp_count");
}
lua_setfield(L, -2, "nhe");
lua_pushinteger(L, dplane_ctx_get_nhg_id(ctx));
lua_setfield(L, -2, "zd_nhg_id");
lua_pushnexthop_group(L, dplane_ctx_get_ng(ctx));
lua_setfield(L, -2, "zd_ng");
lua_pushnexthop_group(L, dplane_ctx_get_backup_ng(ctx));
lua_setfield(L, -2, "backup_ng");
lua_pushnexthop_group(L, dplane_ctx_get_old_ng(ctx));
lua_setfield(L, -2, "zd_old_ng");
lua_pushnexthop_group(
L, dplane_ctx_get_old_backup_ng(ctx));
lua_setfield(L, -2, "old_backup_ng");
}
lua_setfield(L, -2, "rinfo");
break;
case DPLANE_OP_LSP_INSTALL:
case DPLANE_OP_LSP_UPDATE:
case DPLANE_OP_LSP_DELETE:
case DPLANE_OP_LSP_NOTIFY:
lua_pushinteger(L, (int)dplane_ctx_get_in_label(ctx));
lua_setfield(L, -2, "label");
break;
case DPLANE_OP_PW_INSTALL:
case DPLANE_OP_PW_UNINSTALL:
/* pw*/
lua_newtable(L);
{
lua_pushinteger(L, dplane_ctx_get_pw_type(ctx));
lua_setfield(L, -2, "type");
lua_pushinteger(L, dplane_ctx_get_pw_af(ctx));
lua_setfield(L, -2, "af");
lua_pushinteger(L, dplane_ctx_get_pw_status(ctx));
lua_setfield(L, -2, "status");
lua_pushinteger(L, dplane_ctx_get_pw_flags(ctx));
lua_setfield(L, -2, "flags");
lua_pushinteger(L, dplane_ctx_get_pw_local_label(ctx));
lua_setfield(L, -2, "local_label");
lua_pushinteger(L, dplane_ctx_get_pw_remote_label(ctx));
lua_setfield(L, -2, "remote_label");
}
lua_setfield(L, -2, "pw");
break;
case DPLANE_OP_SYS_ROUTE_ADD:
case DPLANE_OP_SYS_ROUTE_DELETE:
/* nothing to encode */
break;
case DPLANE_OP_MAC_INSTALL:
case DPLANE_OP_MAC_DELETE:
/* macinfo */
lua_newtable(L);
{
lua_pushinteger(L, dplane_ctx_mac_get_vlan(ctx));
lua_setfield(L, -2, "vid");
lua_pushinteger(L, dplane_ctx_mac_get_br_ifindex(ctx));
lua_setfield(L, -2, "br_ifindex");
lua_pushethaddr(L, dplane_ctx_mac_get_addr(ctx));
lua_setfield(L, -2, "mac");
lua_pushinaddr(L, dplane_ctx_mac_get_vtep_ip(ctx));
lua_setfield(L, -2, "vtep_ip");
lua_pushinteger(L, dplane_ctx_mac_is_sticky(ctx));
lua_setfield(L, -2, "is_sticky");
lua_pushinteger(L, dplane_ctx_mac_get_nhg_id(ctx));
lua_setfield(L, -2, "nhg_id");
lua_pushinteger(L,
dplane_ctx_mac_get_update_flags(ctx));
lua_setfield(L, -2, "update_flags");
}
lua_setfield(L, -2, "macinfo");
break;
case DPLANE_OP_RULE_ADD:
case DPLANE_OP_RULE_DELETE:
case DPLANE_OP_RULE_UPDATE:
/* rule */
lua_newtable(L);
{
lua_pushinteger(L, dplane_ctx_rule_get_sock(ctx));
lua_setfield(L, -2, "sock");
lua_pushinteger(L, dplane_ctx_rule_get_unique(ctx));
lua_setfield(L, -2, "unique");
lua_pushinteger(L, dplane_ctx_rule_get_seq(ctx));
lua_setfield(L, -2, "seq");
lua_pushstring(L, dplane_ctx_rule_get_ifname(ctx));
lua_setfield(L, -2, "ifname");
lua_pushinteger(L, dplane_ctx_rule_get_priority(ctx));
lua_setfield(L, -2, "priority");
lua_pushinteger(L,
dplane_ctx_rule_get_old_priority(ctx));
lua_setfield(L, -2, "old_priority");
lua_pushinteger(L, dplane_ctx_rule_get_table(ctx));
lua_setfield(L, -2, "table");
lua_pushinteger(L, dplane_ctx_rule_get_old_table(ctx));
lua_setfield(L, -2, "old_table");
lua_pushinteger(L, dplane_ctx_rule_get_filter_bm(ctx));
lua_setfield(L, -2, "filter_bm");
lua_pushinteger(L,
dplane_ctx_rule_get_old_filter_bm(ctx));
lua_setfield(L, -2, "old_filter_bm");
lua_pushinteger(L, dplane_ctx_rule_get_fwmark(ctx));
lua_setfield(L, -2, "fwmark");
lua_pushinteger(L, dplane_ctx_rule_get_old_fwmark(ctx));
lua_setfield(L, -2, "old_fwmark");
lua_pushinteger(L, dplane_ctx_rule_get_dsfield(ctx));
lua_setfield(L, -2, "dsfield");
lua_pushinteger(L,
dplane_ctx_rule_get_old_dsfield(ctx));
lua_setfield(L, -2, "old_dsfield");
lua_pushinteger(L, dplane_ctx_rule_get_ipproto(ctx));
lua_setfield(L, -2, "ip_proto");
lua_pushinteger(L,
dplane_ctx_rule_get_old_ipproto(ctx));
lua_setfield(L, -2, "old_ip_proto");
lua_pushprefix(L, dplane_ctx_rule_get_src_ip(ctx));
lua_setfield(L, -2, "src_ip");
lua_pushprefix(L, dplane_ctx_rule_get_old_src_ip(ctx));
lua_setfield(L, -2, "old_src_ip");
lua_pushprefix(L, dplane_ctx_rule_get_dst_ip(ctx));
lua_setfield(L, -2, "dst_ip");
lua_pushprefix(L, dplane_ctx_rule_get_old_dst_ip(ctx));
lua_setfield(L, -2, "old_dst_ip");
}
lua_setfield(L, -2, "rule");
break;
case DPLANE_OP_IPTABLE_ADD:
case DPLANE_OP_IPTABLE_DELETE:
struct zebra_pbr_iptable iptable;
dplane_ctx_get_pbr_iptable(ctx, &iptable);
/* iptable */
lua_newtable(L);
{
lua_pushinteger(L, iptable.sock);
lua_setfield(L, -2, "sock");
lua_pushinteger(L, iptable.vrf_id);
lua_setfield(L, -2, "vrf_id");
lua_pushinteger(L, iptable.unique);
lua_setfield(L, -2, "unique");
lua_pushinteger(L, iptable.type);
lua_setfield(L, -2, "type");
lua_pushinteger(L, iptable.filter_bm);
lua_setfield(L, -2, "filter_bm");
lua_pushinteger(L, iptable.fwmark);
lua_setfield(L, -2, "fwmark");
lua_pushinteger(L, iptable.action);
lua_setfield(L, -2, "action");
lua_pushinteger(L, iptable.pkt_len_min);
lua_setfield(L, -2, "pkt_len_min");
lua_pushinteger(L, iptable.pkt_len_max);
lua_setfield(L, -2, "pkt_len_max");
lua_pushinteger(L, iptable.tcp_flags);
lua_setfield(L, -2, "tcp_flags");
lua_pushinteger(L, iptable.dscp_value);
lua_setfield(L, -2, "dscp_value");
lua_pushinteger(L, iptable.fragment);
lua_setfield(L, -2, "fragment");
lua_pushinteger(L, iptable.protocol);
lua_setfield(L, -2, "protocol");
lua_pushinteger(L, iptable.nb_interface);
lua_setfield(L, -2, "nb_interface");
lua_pushinteger(L, iptable.flow_label);
lua_setfield(L, -2, "flow_label");
lua_pushinteger(L, iptable.family);
lua_setfield(L, -2, "family");
lua_pushstring(L, iptable.ipset_name);
lua_setfield(L, -2, "ipset_name");
}
lua_setfield(L, -2, "iptable");
break;
case DPLANE_OP_IPSET_ADD:
case DPLANE_OP_IPSET_DELETE:
case DPLANE_OP_IPSET_ENTRY_ADD:
case DPLANE_OP_IPSET_ENTRY_DELETE:
struct zebra_pbr_ipset ipset;
dplane_ctx_get_pbr_ipset(ctx, &ipset);
/* ipset */
lua_newtable(L);
{
lua_pushinteger(L, ipset.sock);
lua_setfield(L, -2, "sock");
lua_pushinteger(L, ipset.vrf_id);
lua_setfield(L, -2, "vrf_id");
lua_pushinteger(L, ipset.unique);
lua_setfield(L, -2, "unique");
lua_pushinteger(L, ipset.type);
lua_setfield(L, -2, "type");
lua_pushinteger(L, ipset.family);
lua_setfield(L, -2, "family");
lua_pushstring(L, ipset.ipset_name);
lua_setfield(L, -2, "ipset_name");
}
lua_setfield(L, -2, "ipset");
break;
case DPLANE_OP_ADDR_INSTALL:
case DPLANE_OP_ADDR_UNINSTALL:
break;
case DPLANE_OP_NEIGH_INSTALL:
case DPLANE_OP_NEIGH_UPDATE:
case DPLANE_OP_NEIGH_DELETE:
case DPLANE_OP_NEIGH_DISCOVER:
case DPLANE_OP_NEIGH_IP_INSTALL:
case DPLANE_OP_NEIGH_IP_DELETE:
/* neigh */
lua_newtable(L);
{
lua_pushipaddr(L, dplane_ctx_neigh_get_ipaddr(ctx));
lua_setfield(L, -2, "ip_addr");
/* link */
lua_newtable(L);
{
lua_pushethaddr(L,
dplane_ctx_neigh_get_mac(ctx));
lua_setfield(L, -2, "mac");
lua_pushipaddr(
L, dplane_ctx_neigh_get_link_ip(ctx));
lua_setfield(L, -2, "ip_addr");
}
lua_setfield(L, -2, "link");
lua_pushinteger(L, dplane_ctx_neigh_get_flags(ctx));
lua_setfield(L, -2, "flags");
lua_pushinteger(L, dplane_ctx_neigh_get_state(ctx));
lua_setfield(L, -2, "state");
lua_pushinteger(L,
dplane_ctx_neigh_get_update_flags(ctx));
lua_setfield(L, -2, "update_flags");
}
lua_setfield(L, -2, "neigh");
break;
case DPLANE_OP_VTEP_ADD:
case DPLANE_OP_VTEP_DELETE:
break;
case DPLANE_OP_BR_PORT_UPDATE:
/* br_port */
lua_newtable(L);
{
lua_pushinteger(
L, dplane_ctx_get_br_port_sph_filter_cnt(ctx));
lua_setfield(L, -2, "sph_filter_cnt");
lua_pushinteger(L, dplane_ctx_get_br_port_flags(ctx));
lua_setfield(L, -2, "flags");
lua_pushinteger(
L, dplane_ctx_get_br_port_backup_nhg_id(ctx));
lua_setfield(L, -2, "backup_nhg_id");
}
lua_setfield(L, -2, "br_port");
break;
case DPLANE_OP_NEIGH_TABLE_UPDATE:
/* neightable */
lua_newtable(L);
{
lua_pushinteger(L,
dplane_ctx_neightable_get_family(ctx));
lua_setfield(L, -2, "family");
lua_pushinteger(
L, dplane_ctx_neightable_get_app_probes(ctx));
lua_setfield(L, -2, "app_probes");
lua_pushinteger(
L, dplane_ctx_neightable_get_mcast_probes(ctx));
lua_setfield(L, -2, "ucast_probes");
lua_pushinteger(
L, dplane_ctx_neightable_get_ucast_probes(ctx));
lua_setfield(L, -2, "mcast_probes");
}
lua_setfield(L, -2, "neightable");
break;
case DPLANE_OP_GRE_SET:
/* gre */
lua_newtable(L);
{
lua_pushinteger(L,
dplane_ctx_gre_get_link_ifindex(ctx));
lua_setfield(L, -2, "link_ifindex");
lua_pushinteger(L, dplane_ctx_gre_get_mtu(ctx));
lua_setfield(L, -2, "mtu");
}
lua_setfield(L, -2, "gre");
case DPLANE_OP_NONE:
} /* Dispatch by op code */
}
#endif /* HAVE_SCRIPTING */

41
zebra/zebra_script.h Normal file
View File

@ -0,0 +1,41 @@
/*
* frrscript encoders and decoders for data structures in Zebra
* Copyright (C) 2021 Donald Lee
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _ZEBRA_SCRIPT_H
#define _ZEBRA_SCRIPT_H
#include "zebra.h"
#include "zebra/zebra_dplane.h"
#include "zebra/zebra_pbr.h"
#ifdef HAVE_SCRIPTING
#include "frrlua.h"
void zebra_script_init(void);
void zebra_script_destroy(void);
void lua_pushnh_grp(lua_State *L, const struct nh_grp *nh_grp);
void lua_pushzebra_dplane_ctx(lua_State *L, const struct zebra_dplane_ctx *ctx);
#endif /* HAVE_SCRIPTING */
#endif /* _ZEBRA_SCRIPT_H */

View File

@ -60,6 +60,7 @@
#include "zebra/zebra_nb.h"
#include "zebra/kernel_netlink.h"
#include "zebra/table_manager.h"
#include "zebra/zebra_script.h"
extern int allow_delete;
@ -4323,6 +4324,30 @@ DEFUN(ip_table_range, ip_table_range_cmd,
return table_manager_range(vty, true, zvrf, argv[3]->arg, argv[4]->arg);
}
#ifdef HAVE_SCRIPTING
DEFUN(zebra_on_rib_process_script, zebra_on_rib_process_script_cmd,
"zebra on-rib-process script SCRIPT",
ZEBRA_STR
"on_rib_process_dplane_results hook call\n"
"Set a script\n"
"Script name (same as filename in /etc/frr/scripts/, without .lua)\n")
{
if (frrscript_names_set_script_name(ZEBRA_ON_RIB_PROCESS_HOOK_CALL,
argv[3]->arg)
== 0) {
vty_out(vty, "Successfully added script %s for hook call %s\n",
argv[3]->arg, ZEBRA_ON_RIB_PROCESS_HOOK_CALL);
} else {
vty_out(vty, "Failed to add script %s for hook call %s\n",
argv[3]->arg, ZEBRA_ON_RIB_PROCESS_HOOK_CALL);
}
return CMD_SUCCESS;
}
#endif /* HAVE_SCRIPTING */
/* IP node for static routes. */
static int zebra_ip_config(struct vty *vty);
static struct cmd_node ip_node = {
@ -4479,5 +4504,9 @@ void zebra_vty_init(void)
install_element(CONFIG_NODE, &no_zebra_kernel_netlink_batch_tx_buf_cmd);
#endif /* HAVE_NETLINK */
#ifdef HAVE_SCRIPTING
install_element(CONFIG_NODE, &zebra_on_rib_process_script_cmd);
#endif /* HAVE_SCRIPTING */
install_element(VIEW_NODE, &zebra_show_routing_tables_summary_cmd);
}