bgpd: Add lua match command

Please note this is a Proof of Concept and not actually something
that is ready to commit at this point.  The file tools/lua.scr
contains some documentation on how we expect it to work currently.
Additionally not all bgp values have been hooked up into the
ability to lua script yet.

There is still significant work to be done here:

1) Add the ability to pass in more data and to adjust the return values
as appropriate.

To set it up:

1) copy tools/lua.scr into /etc/frr (or whereever the config
directory is )

2) Create a route-map match command:
!
router bgp 55
 neighbor 10.50.11.116 remote-as external
 !
 address-family ipv4 unicast
  neighbor 10.50.11.116 route-map TEST in
 exit-address-family
!
route-map TEST permit 10
 match command mooey
!

3) In the lua.scr file make sure that you have a function
named 'mooey' ( as the above example does ):

function mooey ()
   zlog_debug(string.format("Family: %d: %s %d ifindex: %d aspath: %s localpref: %d",
                            prefix.family, prefix.route,
			    nexthop.metric, nexthop.ifindex, nexthop.aspath, nexthop.localpref))

   nexthop.metric =  33
   nexthop.localpref = 13
   return 3
end

This example script modifies the metric and localpref currently.  I've also provided
a zlog_debug function in lua to allow some simple debugging.

Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
This commit is contained in:
Donald Sharp 2017-11-07 09:14:32 -05:00
parent 634949aef8
commit 1d7c7ace3c
2 changed files with 157 additions and 0 deletions

View file

@ -28,6 +28,7 @@
#include "plist.h"
#include "memory.h"
#include "log.h"
#include "lua.h"
#ifdef HAVE_LIBPCREPOSIX
#include <pcreposix.h>
#else
@ -330,6 +331,102 @@ struct route_map_rule_cmd route_match_peer_cmd = {"peer", route_match_peer,
route_match_peer_compile,
route_match_peer_free};
#if defined(HAVE_LUA)
static route_map_result_t route_match_command(void *rule,
const struct prefix *prefix,
route_map_object_t type,
void *object)
{
int status = RMAP_NOMATCH;
u_int32_t locpref = 0;
u_int32_t newlocpref = 0;
enum lua_rm_status lrm_status;
struct bgp_info *info = (struct bgp_info *)object;
lua_State *L = lua_initialize("/etc/frr/lua.scr");
if (L == NULL)
return status;
/*
* Setup the prefix information to pass in
*/
lua_setup_prefix_table(L, prefix);
zlog_debug("Set up prefix table");
/*
* Setup the bgp_info information
*/
lua_newtable(L);
lua_pushinteger(L, info->attr->med);
lua_setfield(L, -2, "metric");
lua_pushinteger(L, info->attr->nh_ifindex);
lua_setfield(L, -2, "ifindex");
lua_pushstring(L, info->attr->aspath->str);
lua_setfield(L, -2, "aspath");
lua_pushinteger(L, info->attr->local_pref);
lua_setfield(L, -2, "localpref");
zlog_debug("%s %d", info->attr->aspath->str, info->attr->nh_ifindex);
lua_setglobal(L, "nexthop");
zlog_debug("Set up nexthop information");
/*
* Run the rule
*/
lrm_status = lua_run_rm_rule(L, rule);
switch (lrm_status) {
case LUA_RM_FAILURE:
zlog_debug("RM_FAILURE");
break;
case LUA_RM_NOMATCH:
zlog_debug("RM_NOMATCH");
break;
case LUA_RM_MATCH_AND_CHANGE:
zlog_debug("MATCH AND CHANGE");
lua_getglobal(L, "nexthop");
info->attr->med = get_integer(L, "metric");
/*
* This needs to be abstraced with the set function
*/
if (info->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF))
locpref = info->attr->local_pref;
newlocpref = get_integer(L, "localpref");
if (newlocpref != locpref) {
info->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF);
info->attr->local_pref = newlocpref;
}
status = RMAP_MATCH;
break;
case LUA_RM_MATCH:
zlog_debug("MATCH ONLY");
status = RMAP_MATCH;
break;
}
lua_close(L);
return status;
}
static void *route_match_command_compile(const char *arg)
{
char *command;
command = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
return command;
}
static void
route_match_command_free(void *rule)
{
XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
}
struct route_map_rule_cmd route_match_command_cmd = {
"command",
route_match_command,
route_match_command_compile,
route_match_command_free
};
#endif
/* `match ip address IP_ACCESS_LIST' */
/* Match function should return 1 if match is success else return
@ -3356,6 +3453,30 @@ DEFUN (no_match_peer,
RMAP_EVENT_MATCH_DELETED);
}
#if defined(HAVE_LUA)
DEFUN (match_command,
match_command_cmd,
"match command 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
MATCH_STR
"Run a command to match\n"
"The command to run\n")
{
return bgp_route_match_delete(vty, "command", argv[3]->arg,
RMAP_EVENT_FILTER_DELETED);
}
#endif
/* match probability */
DEFUN (match_probability,
@ -4671,6 +4792,9 @@ void bgp_route_map_init(void)
route_map_install_match(&route_match_peer_cmd);
route_map_install_match(&route_match_local_pref_cmd);
#if defined(HAVE_LUA)
route_map_install_match(&route_match_command_cmd);
#endif
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_route_source_cmd);
@ -4804,6 +4928,10 @@ void bgp_route_map_init(void)
install_element(RMAP_NODE, &no_set_ipv6_nexthop_prefer_global_cmd);
install_element(RMAP_NODE, &set_ipv6_nexthop_peer_cmd);
install_element(RMAP_NODE, &no_set_ipv6_nexthop_peer_cmd);
#if defined(HAVE_LUA)
install_element(RMAP_NODE, &match_command_cmd);
install_element(RMAP_NODE, &no_match_command_cmd);
#endif
}
void bgp_route_map_terminate(void)

29
tools/lua.scr Normal file
View file

@ -0,0 +1,29 @@
-- Route map functionality
--
-- There are no parameters passed in.
-- Currently we set two global tables
-- prefix
-- .family = The v4 or v6 family we are working in
-- .route = the A.B.C.D/X or Z:A:B::D/X string
-- nexthop
-- .metric = The metric we are going to use
-- .ifindex = The outgoing interface
-- .aspath = The aspath of the route
-- .localpref = The localpref value
--
-- Valid Return Codes:
-- 0 - Some sort of processing failure
-- This turns into a implicit DENY
-- 1 - No match was found, turns into a DENY
-- 2 - Match found, turns into a PERMIT
-- 3 - Match found and data structures changed, turns into a PERMIT
-- and a reread of the prefix and nexthop tables
function mooey ()
zlog_debug(string.format("Family: %d: %s %d ifindex: %d aspath: %s localpref: %d",
prefix.family, prefix.route,
nexthop.metric, nexthop.ifindex, nexthop.aspath, nexthop.localpref))
nexthop.metric = 33
nexthop.localpref = 13
return 3
end