]> git.puffer.fish Git - mirror/frr.git/commitdiff
bgpd: Add lua match command 3034/head
authorDonald Sharp <sharpd@cumulusnetworks.com>
Tue, 7 Nov 2017 14:14:32 +0000 (09:14 -0500)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Thu, 27 Sep 2018 01:21:23 +0000 (21:21 -0400)
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>
bgpd/bgp_routemap.c
tools/lua.scr [new file with mode: 0644]

index 0b4355805cf6961c75b3887f79faff5d59bdc8c5..8e7c0a69dd4a77d78ffd5f75ad938225a6cd787a 100644 (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)
diff --git a/tools/lua.scr b/tools/lua.scr
new file mode 100644 (file)
index 0000000..db6bf7d
--- /dev/null
@@ -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