#include "bgpd/bgp_flowspec_util.h"
#include "bgpd/bgp_encap_types.h"
#include "bgpd/bgp_mpath.h"
+#include "bgpd/bgp_script.h"
#ifdef ENABLE_BGP_VNC
#include "bgpd/rfapi/bgp_rfapi_cfg.h"
route_match_peer_free
};
-#if defined(HAVE_LUA)
-static enum route_map_cmd_result_t
-route_match_command(void *rule, const struct prefix *prefix, void *object)
-{
- int status = RMAP_NOMATCH;
- u_int32_t locpref = 0;
- u_int32_t newlocpref = 0;
- enum lua_rm_status lrm_status;
- struct bgp_path_info *path = (struct bgp_path_info *)object;
- lua_State *L = lua_initialize("/etc/frr/lua.scr");
-
- if (L == NULL)
- return status;
+#ifdef HAVE_SCRIPTING
+enum frrlua_rm_status {
/*
- * Setup the prefix information to pass in
+ * Script function run failure. This will translate into a deny
*/
- lua_setup_prefix_table(L, prefix);
-
- zlog_debug("Set up prefix table");
+ LUA_RM_FAILURE = 0,
/*
- * Setup the bgp_path_info information
+ * No Match was found for the route map function
*/
- 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");
+ LUA_RM_NOMATCH,
/*
- * Run the rule
+ * Match was found but no changes were made to the incoming data.
*/
- lrm_status = lua_run_rm_rule(L, rule);
- switch (lrm_status) {
+ LUA_RM_MATCH,
+ /*
+ * Match was found and data was modified, so figure out what changed
+ */
+ LUA_RM_MATCH_AND_CHANGE,
+};
+
+static enum route_map_cmd_result_t
+route_match_script(void *rule, const struct prefix *prefix, void *object)
+{
+ const char *scriptname = rule;
+ struct bgp_path_info *path = (struct bgp_path_info *)object;
+
+ struct frrscript *fs = frrscript_load(scriptname, NULL);
+
+ if (!fs) {
+ zlog_err("Issue loading script rule; defaulting to no match");
+ return RMAP_NOMATCH;
+ }
+
+ enum frrlua_rm_status status_failure = LUA_RM_FAILURE,
+ 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]);
+
+ int status = RMAP_NOMATCH;
+
+ switch (*lrm_status) {
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;
case LUA_RM_NOMATCH:
- zlog_debug("RM_NOMATCH");
+ status = RMAP_NOMATCH;
break;
case LUA_RM_MATCH_AND_CHANGE:
- zlog_debug("MATCH AND CHANGE");
- lua_getglobal(L, "nexthop");
- path->attr->med = get_integer(L, "metric");
- /*
- * This needs to be abstraced with the set function
- */
+ status = RMAP_MATCH;
+ zlog_debug("Updating attribute based on script's values");
+
+ uint32_t locpref = 0;
+ 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))
locpref = path->attr->local_pref;
- newlocpref = get_integer(L, "localpref");
- if (newlocpref != locpref) {
- path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF);
- path->attr->local_pref = newlocpref;
+ if (locpref != newattr->local_pref) {
+ SET_FLAG(path->attr->flag,
+ ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF));
+ path->attr->local_pref = newattr->local_pref;
}
- status = RMAP_MATCH;
+
+ aspath_free(newattr->aspath);
+ XFREE(MTYPE_TMP, newattr);
break;
case LUA_RM_MATCH:
- zlog_debug("MATCH ONLY");
status = RMAP_MATCH;
break;
}
- lua_close(L);
+
+ XFREE(MTYPE_TMP, lrm_status);
+ frrscript_unload(fs);
+
return status;
}
-static void *route_match_command_compile(const char *arg)
+static void *route_match_script_compile(const char *arg)
{
- char *command;
+ char *scriptname;
+
+ scriptname = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
- command = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
- return command;
+ return scriptname;
}
-static void
-route_match_command_free(void *rule)
+static void route_match_script_free(void *rule)
{
XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
}
-static const struct route_map_rule_cmd route_match_command_cmd = {
- "command",
- route_match_command,
- route_match_command_compile,
- route_match_command_free
+static const struct route_map_rule_cmd route_match_script_cmd = {
+ "script",
+ route_match_script,
+ route_match_script_compile,
+ route_match_script_free
};
-#endif
+
+#endif /* HAVE_SCRIPTING */
/* `match ip address IP_ACCESS_LIST' */
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",
+#ifdef HAVE_SCRIPTING
+DEFUN (match_script,
+ match_script_cmd,
+ "[no] match script WORD",
NO_STR
MATCH_STR
- "Run a command to match\n"
- "The command to run\n")
+ "Execute script to determine match\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,
- RMAP_EVENT_FILTER_DELETED);
+ bool no = strmatch(argv[0]->text, "no");
+ 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 /* HAVE_SCRIPTING */
/* match probability */
DEFUN (match_probability,
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);
+#ifdef HAVE_SCRIPTING
+ route_map_install_match(&route_match_script_cmd);
#endif
route_map_install_match(&route_match_ip_address_cmd);
route_map_install_match(&route_match_ip_next_hop_cmd);
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);
+#ifdef HAVE_SCRIPTING
+ install_element(RMAP_NODE, &match_script_cmd);
#endif
}