mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-09 20:22:36 +00:00
bgpd: update routemap scripting example
- Change from "match command <foo>" to "match script <script>" - Use new scripting API Signed-off-by: Quentin Young <qlyoung@nvidia.com>
This commit is contained in:
parent
1a3a91e211
commit
b4becb063f
@ -60,6 +60,7 @@
|
|||||||
#include "bgpd/bgp_keepalives.h"
|
#include "bgpd/bgp_keepalives.h"
|
||||||
#include "bgpd/bgp_network.h"
|
#include "bgpd/bgp_network.h"
|
||||||
#include "bgpd/bgp_errors.h"
|
#include "bgpd/bgp_errors.h"
|
||||||
|
#include "bgpd/bgp_script.h"
|
||||||
#include "lib/routing_nb.h"
|
#include "lib/routing_nb.h"
|
||||||
#include "bgpd/bgp_nb.h"
|
#include "bgpd/bgp_nb.h"
|
||||||
#include "bgpd/bgp_evpn_mh.h"
|
#include "bgpd/bgp_evpn_mh.h"
|
||||||
@ -506,6 +507,8 @@ int main(int argc, char **argv)
|
|||||||
/* Initializations. */
|
/* Initializations. */
|
||||||
bgp_vrf_init();
|
bgp_vrf_init();
|
||||||
|
|
||||||
|
bgp_script_init();
|
||||||
|
|
||||||
hook_register(routing_conf_event,
|
hook_register(routing_conf_event,
|
||||||
routing_control_plane_protocols_name_validate);
|
routing_control_plane_protocols_name_validate);
|
||||||
|
|
||||||
|
@ -65,6 +65,7 @@
|
|||||||
#include "bgpd/bgp_flowspec_util.h"
|
#include "bgpd/bgp_flowspec_util.h"
|
||||||
#include "bgpd/bgp_encap_types.h"
|
#include "bgpd/bgp_encap_types.h"
|
||||||
#include "bgpd/bgp_mpath.h"
|
#include "bgpd/bgp_mpath.h"
|
||||||
|
#include "bgpd/bgp_script.h"
|
||||||
|
|
||||||
#ifdef ENABLE_BGP_VNC
|
#ifdef ENABLE_BGP_VNC
|
||||||
#include "bgpd/rfapi/bgp_rfapi_cfg.h"
|
#include "bgpd/rfapi/bgp_rfapi_cfg.h"
|
||||||
@ -341,8 +342,7 @@ static const struct route_map_rule_cmd route_match_peer_cmd = {
|
|||||||
|
|
||||||
enum frrlua_rm_status {
|
enum frrlua_rm_status {
|
||||||
/*
|
/*
|
||||||
* Script function run failure. This will translate into a
|
* Script function run failure. This will translate into a deny
|
||||||
* deny
|
|
||||||
*/
|
*/
|
||||||
LUA_RM_FAILURE = 0,
|
LUA_RM_FAILURE = 0,
|
||||||
/*
|
/*
|
||||||
@ -350,122 +350,123 @@ enum frrlua_rm_status {
|
|||||||
*/
|
*/
|
||||||
LUA_RM_NOMATCH,
|
LUA_RM_NOMATCH,
|
||||||
/*
|
/*
|
||||||
* Match was found but no changes were made to the
|
* Match was found but no changes were made to the incoming data.
|
||||||
* incoming data.
|
|
||||||
*/
|
*/
|
||||||
LUA_RM_MATCH,
|
LUA_RM_MATCH,
|
||||||
/*
|
/*
|
||||||
* Match was found and data was modified, so
|
* Match was found and data was modified, so figure out what changed
|
||||||
* figure out what changed
|
|
||||||
*/
|
*/
|
||||||
LUA_RM_MATCH_AND_CHANGE,
|
LUA_RM_MATCH_AND_CHANGE,
|
||||||
};
|
};
|
||||||
|
|
||||||
static enum frrlua_rm_status frrlua_run_rm_rule(lua_State *L, const char *rule)
|
static enum route_map_cmd_result_t
|
||||||
|
route_match_script(void *rule, const struct prefix *prefix, void *object)
|
||||||
{
|
{
|
||||||
int status;
|
const char *scriptname = rule;
|
||||||
|
struct bgp_path_info *path = (struct bgp_path_info *)object;
|
||||||
|
|
||||||
lua_getglobal(L, rule);
|
struct frrscript *fs = frrscript_load(scriptname, NULL);
|
||||||
status = lua_pcall(L, 0, 1, 0);
|
|
||||||
if (status) {
|
if (!fs) {
|
||||||
zlog_debug("Executing Failure with function: %s: %d",
|
zlog_err("Issue loading script rule; defaulting to no match");
|
||||||
rule, status);
|
return RMAP_NOMATCH;
|
||||||
return LUA_RM_FAILURE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
status = lua_tonumber(L, -1);
|
enum frrlua_rm_status status_failure = LUA_RM_FAILURE,
|
||||||
return status;
|
status_nomatch = LUA_RM_NOMATCH,
|
||||||
}
|
status_match = LUA_RM_MATCH,
|
||||||
|
status_match_and_change = LUA_RM_MATCH_AND_CHANGE;
|
||||||
|
|
||||||
|
/* Make result values available */
|
||||||
|
struct frrscript_env env[] = {
|
||||||
|
{"integer", "RM_FAILURE", &status_failure},
|
||||||
|
{"integer", "RM_NOMATCH", &status_nomatch},
|
||||||
|
{"integer", "RM_MATCH", &status_match},
|
||||||
|
{"integer", "RM_MATCH_AND_CHANGE", &status_match_and_change},
|
||||||
|
{"integer", "action", &status_failure},
|
||||||
|
{"prefix", "prefix", prefix},
|
||||||
|
{"attr", "attributes", path->attr},
|
||||||
|
{"peer", "peer", path->peer},
|
||||||
|
{}};
|
||||||
|
|
||||||
|
struct frrscript_env results[] = {
|
||||||
|
{"integer", "action"},
|
||||||
|
{"attr", "attributes"},
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
|
||||||
|
int result = frrscript_call(fs, env);
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
zlog_err("Issue running script rule; defaulting to no match");
|
||||||
|
return RMAP_NOMATCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum frrlua_rm_status *lrm_status =
|
||||||
|
frrscript_get_result(fs, &results[0]);
|
||||||
|
|
||||||
static enum route_map_cmd_result_t
|
|
||||||
route_match_command(void *rule, const struct prefix *prefix, void *object)
|
|
||||||
{
|
|
||||||
int status = RMAP_NOMATCH;
|
int status = RMAP_NOMATCH;
|
||||||
u_int32_t locpref = 0;
|
|
||||||
u_int32_t newlocpref = 0;
|
|
||||||
enum frrlua_rm_status lrm_status;
|
|
||||||
struct bgp_path_info *path = (struct bgp_path_info *)object;
|
|
||||||
lua_State *L = luaL_newstate();;
|
|
||||||
luaL_openlibs(L);
|
|
||||||
|
|
||||||
if (L == NULL)
|
switch (*lrm_status) {
|
||||||
return status;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Setup the prefix information to pass in
|
|
||||||
*/
|
|
||||||
lua_pushprefix(L, prefix);
|
|
||||||
/*
|
|
||||||
* Setup the bgp_path_info information
|
|
||||||
*/
|
|
||||||
lua_newtable(L);
|
|
||||||
lua_pushinteger(L, path->attr->med);
|
|
||||||
lua_setfield(L, -2, "metric");
|
|
||||||
lua_pushinteger(L, path->attr->nh_ifindex);
|
|
||||||
lua_setfield(L, -2, "ifindex");
|
|
||||||
lua_pushstring(L, path->attr->aspath->str);
|
|
||||||
lua_setfield(L, -2, "aspath");
|
|
||||||
lua_pushinteger(L, path->attr->local_pref);
|
|
||||||
lua_setfield(L, -2, "localpref");
|
|
||||||
zlog_debug("%s %d", path->attr->aspath->str, path->attr->nh_ifindex);
|
|
||||||
lua_setglobal(L, "nexthop");
|
|
||||||
|
|
||||||
zlog_debug("Set up nexthop information");
|
|
||||||
/*
|
|
||||||
* Run the rule
|
|
||||||
*/
|
|
||||||
lrm_status = frrlua_run_rm_rule(L, rule);
|
|
||||||
switch (lrm_status) {
|
|
||||||
case LUA_RM_FAILURE:
|
case LUA_RM_FAILURE:
|
||||||
zlog_debug("RM_FAILURE");
|
zlog_err(
|
||||||
|
"Executing route-map match script '%s' failed; defaulting to no match",
|
||||||
|
scriptname);
|
||||||
|
status = RMAP_NOMATCH;
|
||||||
break;
|
break;
|
||||||
case LUA_RM_NOMATCH:
|
case LUA_RM_NOMATCH:
|
||||||
zlog_debug("RM_NOMATCH");
|
status = RMAP_NOMATCH;
|
||||||
break;
|
break;
|
||||||
case LUA_RM_MATCH_AND_CHANGE:
|
case LUA_RM_MATCH_AND_CHANGE:
|
||||||
zlog_debug("MATCH AND CHANGE");
|
status = RMAP_MATCH;
|
||||||
lua_getglobal(L, "nexthop");
|
zlog_debug("Updating attribute based on script's values");
|
||||||
path->attr->med = frrlua_table_get_integer(L, "metric");
|
|
||||||
/*
|
uint32_t locpref = 0;
|
||||||
* This needs to be abstraced with the set function
|
struct attr *newattr = frrscript_get_result(fs, &results[1]);
|
||||||
*/
|
|
||||||
|
path->attr->med = newattr->med;
|
||||||
|
|
||||||
if (path->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF))
|
if (path->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF))
|
||||||
locpref = path->attr->local_pref;
|
locpref = path->attr->local_pref;
|
||||||
newlocpref = frrlua_table_get_integer(L, "localpref");
|
if (locpref != newattr->local_pref) {
|
||||||
if (newlocpref != locpref) {
|
SET_FLAG(path->attr->flag,
|
||||||
path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF);
|
ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF));
|
||||||
path->attr->local_pref = newlocpref;
|
path->attr->local_pref = newattr->local_pref;
|
||||||
}
|
}
|
||||||
status = RMAP_MATCH;
|
|
||||||
|
aspath_free(newattr->aspath);
|
||||||
|
XFREE(MTYPE_TMP, newattr);
|
||||||
break;
|
break;
|
||||||
case LUA_RM_MATCH:
|
case LUA_RM_MATCH:
|
||||||
zlog_debug("MATCH ONLY");
|
|
||||||
status = RMAP_MATCH;
|
status = RMAP_MATCH;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
lua_close(L);
|
|
||||||
|
XFREE(MTYPE_TMP, lrm_status);
|
||||||
|
frrscript_unload(fs);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *route_match_command_compile(const char *arg)
|
static void *route_match_script_compile(const char *arg)
|
||||||
{
|
{
|
||||||
char *command;
|
char *scriptname;
|
||||||
|
|
||||||
command = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
|
scriptname = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
|
||||||
return command;
|
|
||||||
|
return scriptname;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void route_match_script_free(void *rule)
|
||||||
route_match_command_free(void *rule)
|
|
||||||
{
|
{
|
||||||
XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
|
XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct route_map_rule_cmd route_match_command_cmd = {
|
static const struct route_map_rule_cmd route_match_script_cmd = {
|
||||||
"command",
|
"script",
|
||||||
route_match_command,
|
route_match_script,
|
||||||
route_match_command_compile,
|
route_match_script_compile,
|
||||||
route_match_command_free
|
route_match_script_free
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -4134,27 +4135,26 @@ DEFUN (no_match_peer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined(HAVE_LUA)
|
#if defined(HAVE_LUA)
|
||||||
DEFUN (match_command,
|
DEFUN (match_script,
|
||||||
match_command_cmd,
|
match_script_cmd,
|
||||||
"match command WORD",
|
"[no] match script WORD",
|
||||||
MATCH_STR
|
|
||||||
"Run a command to match\n"
|
|
||||||
"The command to run\n")
|
|
||||||
{
|
|
||||||
return bgp_route_match_add(vty, "command", argv[2]->arg,
|
|
||||||
RMAP_EVENT_FILTER_ADDED);
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFUN (no_match_command,
|
|
||||||
no_match_command_cmd,
|
|
||||||
"no match command WORD",
|
|
||||||
NO_STR
|
NO_STR
|
||||||
MATCH_STR
|
MATCH_STR
|
||||||
"Run a command to match\n"
|
"Execute script to determine match\n"
|
||||||
"The command to run\n")
|
"The script name to run, without .lua; e.g. 'myroutemap' to run myroutemap.lua\n")
|
||||||
{
|
{
|
||||||
return bgp_route_match_delete(vty, "command", argv[3]->arg,
|
bool no = strmatch(argv[0]->text, "no");
|
||||||
RMAP_EVENT_FILTER_DELETED);
|
int i = 0;
|
||||||
|
argv_find(argv, argc, "WORD", &i);
|
||||||
|
const char *script = argv[i]->arg;
|
||||||
|
|
||||||
|
if (no) {
|
||||||
|
return bgp_route_match_delete(vty, "script", script,
|
||||||
|
RMAP_EVENT_FILTER_DELETED);
|
||||||
|
} else {
|
||||||
|
return bgp_route_match_add(vty, "script", script,
|
||||||
|
RMAP_EVENT_FILTER_ADDED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -5671,7 +5671,7 @@ void bgp_route_map_init(void)
|
|||||||
route_map_install_match(&route_match_peer_cmd);
|
route_map_install_match(&route_match_peer_cmd);
|
||||||
route_map_install_match(&route_match_local_pref_cmd);
|
route_map_install_match(&route_match_local_pref_cmd);
|
||||||
#if defined(HAVE_LUA)
|
#if defined(HAVE_LUA)
|
||||||
route_map_install_match(&route_match_command_cmd);
|
route_map_install_match(&route_match_script_cmd);
|
||||||
#endif
|
#endif
|
||||||
route_map_install_match(&route_match_ip_address_cmd);
|
route_map_install_match(&route_match_ip_address_cmd);
|
||||||
route_map_install_match(&route_match_ip_next_hop_cmd);
|
route_map_install_match(&route_match_ip_next_hop_cmd);
|
||||||
@ -5836,8 +5836,7 @@ void bgp_route_map_init(void)
|
|||||||
install_element(RMAP_NODE, &set_ipv6_nexthop_peer_cmd);
|
install_element(RMAP_NODE, &set_ipv6_nexthop_peer_cmd);
|
||||||
install_element(RMAP_NODE, &no_set_ipv6_nexthop_peer_cmd);
|
install_element(RMAP_NODE, &no_set_ipv6_nexthop_peer_cmd);
|
||||||
#if defined(HAVE_LUA)
|
#if defined(HAVE_LUA)
|
||||||
install_element(RMAP_NODE, &match_command_cmd);
|
install_element(RMAP_NODE, &match_script_cmd);
|
||||||
install_element(RMAP_NODE, &no_match_command_cmd);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
188
bgpd/bgp_script.c
Normal file
188
bgpd/bgp_script.c
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
/* BGP scripting foo
|
||||||
|
* Copyright (C) 2020 NVIDIA Corporation
|
||||||
|
* Quentin Young
|
||||||
|
*
|
||||||
|
* 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.h>
|
||||||
|
#include <lua.h>
|
||||||
|
|
||||||
|
#include "bgpd.h"
|
||||||
|
#include "bgp_script.h"
|
||||||
|
#include "bgp_debug.h"
|
||||||
|
#include "bgp_aspath.h"
|
||||||
|
#include "frratomic.h"
|
||||||
|
#include "frrscript.h"
|
||||||
|
|
||||||
|
static void lua_pushpeer(lua_State *L, const struct peer *peer)
|
||||||
|
{
|
||||||
|
lua_newtable(L);
|
||||||
|
lua_pushinteger(L, peer->as);
|
||||||
|
lua_setfield(L, -2, "remote_as");
|
||||||
|
lua_pushinteger(L, peer->local_as);
|
||||||
|
lua_setfield(L, -2, "local_as");
|
||||||
|
lua_pushinaddr(L, &peer->remote_id);
|
||||||
|
lua_setfield(L, -2, "remote_id");
|
||||||
|
lua_pushinaddr(L, &peer->local_id);
|
||||||
|
lua_setfield(L, -2, "local_id");
|
||||||
|
lua_pushstring(L, lookup_msg(bgp_status_msg, peer->status, NULL));
|
||||||
|
lua_setfield(L, -2, "state");
|
||||||
|
lua_pushstring(L, peer->desc ? peer->desc : "");
|
||||||
|
lua_setfield(L, -2, "description");
|
||||||
|
lua_pushtimet(L, &peer->uptime);
|
||||||
|
lua_setfield(L, -2, "uptime");
|
||||||
|
lua_pushtimet(L, &peer->readtime);
|
||||||
|
lua_setfield(L, -2, "last_readtime");
|
||||||
|
lua_pushtimet(L, &peer->resettime);
|
||||||
|
lua_setfield(L, -2, "last_resettime");
|
||||||
|
lua_pushsockunion(L, peer->su_local);
|
||||||
|
lua_setfield(L, -2, "local_address");
|
||||||
|
lua_pushsockunion(L, peer->su_remote);
|
||||||
|
lua_setfield(L, -2, "remote_address");
|
||||||
|
lua_pushinteger(L, peer->cap);
|
||||||
|
lua_setfield(L, -2, "capabilities");
|
||||||
|
lua_pushinteger(L, peer->flags);
|
||||||
|
lua_setfield(L, -2, "flags");
|
||||||
|
lua_pushstring(L, peer->password ? peer->password : "");
|
||||||
|
lua_setfield(L, -2, "password");
|
||||||
|
|
||||||
|
/* Nested tables here */
|
||||||
|
lua_newtable(L);
|
||||||
|
{
|
||||||
|
lua_newtable(L);
|
||||||
|
{
|
||||||
|
lua_pushinteger(L, peer->holdtime);
|
||||||
|
lua_setfield(L, -2, "hold");
|
||||||
|
lua_pushinteger(L, peer->keepalive);
|
||||||
|
lua_setfield(L, -2, "keepalive");
|
||||||
|
lua_pushinteger(L, peer->connect);
|
||||||
|
lua_setfield(L, -2, "connect");
|
||||||
|
lua_pushinteger(L, peer->routeadv);
|
||||||
|
lua_setfield(L, -2, "route_advertisement");
|
||||||
|
}
|
||||||
|
lua_setfield(L, -2, "configured");
|
||||||
|
|
||||||
|
lua_newtable(L);
|
||||||
|
{
|
||||||
|
lua_pushinteger(L, peer->v_holdtime);
|
||||||
|
lua_setfield(L, -2, "hold");
|
||||||
|
lua_pushinteger(L, peer->v_keepalive);
|
||||||
|
lua_setfield(L, -2, "keepalive");
|
||||||
|
lua_pushinteger(L, peer->v_connect);
|
||||||
|
lua_setfield(L, -2, "connect");
|
||||||
|
lua_pushinteger(L, peer->v_routeadv);
|
||||||
|
lua_setfield(L, -2, "route_advertisement");
|
||||||
|
}
|
||||||
|
lua_setfield(L, -2, "negotiated");
|
||||||
|
}
|
||||||
|
lua_setfield(L, -2, "timers");
|
||||||
|
|
||||||
|
lua_newtable(L);
|
||||||
|
{
|
||||||
|
lua_pushinteger(L, atomic_load_explicit(&peer->open_in,
|
||||||
|
memory_order_relaxed));
|
||||||
|
lua_setfield(L, -2, "open_in");
|
||||||
|
lua_pushinteger(L, atomic_load_explicit(&peer->open_out,
|
||||||
|
memory_order_relaxed));
|
||||||
|
lua_setfield(L, -2, "open_out");
|
||||||
|
lua_pushinteger(L, atomic_load_explicit(&peer->update_in,
|
||||||
|
memory_order_relaxed));
|
||||||
|
lua_setfield(L, -2, "update_in");
|
||||||
|
lua_pushinteger(L, atomic_load_explicit(&peer->update_out,
|
||||||
|
memory_order_relaxed));
|
||||||
|
lua_setfield(L, -2, "update_out");
|
||||||
|
lua_pushinteger(L, atomic_load_explicit(&peer->update_time,
|
||||||
|
memory_order_relaxed));
|
||||||
|
lua_setfield(L, -2, "update_time");
|
||||||
|
lua_pushinteger(L, atomic_load_explicit(&peer->keepalive_in,
|
||||||
|
memory_order_relaxed));
|
||||||
|
lua_setfield(L, -2, "keepalive_in");
|
||||||
|
lua_pushinteger(L, atomic_load_explicit(&peer->keepalive_out,
|
||||||
|
memory_order_relaxed));
|
||||||
|
lua_setfield(L, -2, "keepalive_out");
|
||||||
|
lua_pushinteger(L, atomic_load_explicit(&peer->notify_in,
|
||||||
|
memory_order_relaxed));
|
||||||
|
lua_setfield(L, -2, "notify_in");
|
||||||
|
lua_pushinteger(L, atomic_load_explicit(&peer->notify_out,
|
||||||
|
memory_order_relaxed));
|
||||||
|
lua_setfield(L, -2, "notify_out");
|
||||||
|
lua_pushinteger(L, atomic_load_explicit(&peer->refresh_in,
|
||||||
|
memory_order_relaxed));
|
||||||
|
lua_setfield(L, -2, "refresh_in");
|
||||||
|
lua_pushinteger(L, atomic_load_explicit(&peer->refresh_out,
|
||||||
|
memory_order_relaxed));
|
||||||
|
lua_setfield(L, -2, "refresh_out");
|
||||||
|
lua_pushinteger(L, atomic_load_explicit(&peer->dynamic_cap_in,
|
||||||
|
memory_order_relaxed));
|
||||||
|
lua_setfield(L, -2, "dynamic_cap_in");
|
||||||
|
lua_pushinteger(L, atomic_load_explicit(&peer->dynamic_cap_out,
|
||||||
|
memory_order_relaxed));
|
||||||
|
lua_setfield(L, -2, "dynamic_cap_out");
|
||||||
|
lua_pushinteger(L, peer->established);
|
||||||
|
lua_setfield(L, -2, "times_established");
|
||||||
|
lua_pushinteger(L, peer->dropped);
|
||||||
|
lua_setfield(L, -2, "times_dropped");
|
||||||
|
}
|
||||||
|
lua_setfield(L, -2, "stats");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lua_pushattr(lua_State *L, const struct attr *attr)
|
||||||
|
{
|
||||||
|
lua_newtable(L);
|
||||||
|
lua_pushinteger(L, attr->med);
|
||||||
|
lua_setfield(L, -2, "metric");
|
||||||
|
lua_pushinteger(L, attr->nh_ifindex);
|
||||||
|
lua_setfield(L, -2, "ifindex");
|
||||||
|
lua_pushstring(L, attr->aspath->str);
|
||||||
|
lua_setfield(L, -2, "aspath");
|
||||||
|
lua_pushinteger(L, attr->local_pref);
|
||||||
|
lua_setfield(L, -2, "localpref");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *lua_toattr(lua_State *L, int idx)
|
||||||
|
{
|
||||||
|
struct attr *attr = XCALLOC(MTYPE_TMP, sizeof(struct attr));
|
||||||
|
|
||||||
|
lua_getfield(L, -1, "metric");
|
||||||
|
attr->med = lua_tointeger(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
lua_getfield(L, -1, "ifindex");
|
||||||
|
attr->nh_ifindex = lua_tointeger(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
lua_getfield(L, -1, "aspath");
|
||||||
|
attr->aspath = aspath_str2aspath(lua_tostring(L, -1));
|
||||||
|
lua_pop(L, 1);
|
||||||
|
lua_getfield(L, -1, "localpref");
|
||||||
|
attr->local_pref = lua_tointeger(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
return attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct frrscript_codec frrscript_codecs_bgpd[] = {
|
||||||
|
{.typename = "peer",
|
||||||
|
.encoder = (encoder_func)lua_pushpeer,
|
||||||
|
.decoder = NULL},
|
||||||
|
{.typename = "attr",
|
||||||
|
.encoder = (encoder_func)lua_pushattr,
|
||||||
|
.decoder = lua_toattr},
|
||||||
|
{}};
|
||||||
|
|
||||||
|
void bgp_script_init(void)
|
||||||
|
{
|
||||||
|
frrscript_register_type_codecs(frrscript_codecs_bgpd);
|
||||||
|
}
|
26
bgpd/bgp_script.h
Normal file
26
bgpd/bgp_script.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/* BGP scripting foo
|
||||||
|
* Copyright (C) 2020 NVIDIA Corporation
|
||||||
|
* Quentin Young
|
||||||
|
*
|
||||||
|
* 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.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize scripting stuff.
|
||||||
|
*/
|
||||||
|
void bgp_script_init(void);
|
@ -95,6 +95,7 @@ bgpd_libbgp_a_SOURCES = \
|
|||||||
bgpd/bgp_regex.c \
|
bgpd/bgp_regex.c \
|
||||||
bgpd/bgp_route.c \
|
bgpd/bgp_route.c \
|
||||||
bgpd/bgp_routemap.c \
|
bgpd/bgp_routemap.c \
|
||||||
|
bgpd/bgp_script.c \
|
||||||
bgpd/bgp_table.c \
|
bgpd/bgp_table.c \
|
||||||
bgpd/bgp_updgrp.c \
|
bgpd/bgp_updgrp.c \
|
||||||
bgpd/bgp_updgrp_adv.c \
|
bgpd/bgp_updgrp_adv.c \
|
||||||
@ -174,6 +175,7 @@ noinst_HEADERS += \
|
|||||||
bgpd/bgp_rd.h \
|
bgpd/bgp_rd.h \
|
||||||
bgpd/bgp_regex.h \
|
bgpd/bgp_regex.h \
|
||||||
bgpd/bgp_route.h \
|
bgpd/bgp_route.h \
|
||||||
|
bgpd/bgp_script.h \
|
||||||
bgpd/bgp_table.h \
|
bgpd/bgp_table.h \
|
||||||
bgpd/bgp_updgrp.h \
|
bgpd/bgp_updgrp.h \
|
||||||
bgpd/bgp_vpn.h \
|
bgpd/bgp_vpn.h \
|
||||||
|
Loading…
Reference in New Issue
Block a user