#include "plist.h"
#include "memory.h"
#include "log.h"
+#include "lua.h"
#ifdef HAVE_LIBPCREPOSIX
#include <pcreposix.h>
#else
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
route_match_ip_next_hop_prefix_list_compile,
route_match_ip_next_hop_prefix_list_free};
+ /* `match ip next-hop type <blackhole>' */
+
+ static route_map_result_t
+ route_match_ip_next_hop_type(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
+ {
+ struct bgp_info *bgp_info;
+
+ if (type == RMAP_BGP && prefix->family == AF_INET) {
+ bgp_info = (struct bgp_info *)object;
+ if (!bgp_info || !bgp_info->attr)
+ return RMAP_DENYMATCH;
+
+ /* If nexthop interface's index can't be resolved and nexthop is
+ set to any address then mark it as type `blackhole`.
+ This logic works for matching kernel/static routes like:
+ `ip route add blackhole 10.0.0.1`. */
+ if (bgp_info->attr->nexthop.s_addr == INADDR_ANY
+ && !bgp_info->attr->nh_ifindex)
+ return RMAP_MATCH;
+ }
+ return RMAP_NOMATCH;
+ }
+
+ static void *route_match_ip_next_hop_type_compile(const char *arg)
+ {
+ return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
+ }
+
+ static void route_match_ip_next_hop_type_free(void *rule)
+ {
+ XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
+ }
+
+ static struct route_map_rule_cmd route_match_ip_next_hop_type_cmd = {
+ "ip next-hop type", route_match_ip_next_hop_type,
+ route_match_ip_next_hop_type_compile,
+ route_match_ip_next_hop_type_free};
+
/* `match ip route-source prefix-list PREFIX_LIST' */
static route_map_result_t
route_match_ipv6_address_prefix_list_compile,
route_match_ipv6_address_prefix_list_free};
+ /* `match ipv6 next-hop type <TYPE>' */
+
+ static route_map_result_t
+ route_match_ipv6_next_hop_type(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
+ {
+ struct bgp_info *bgp_info;
+ struct in6_addr *addr = rule;
+
+ if (type == RMAP_BGP && prefix->family == AF_INET6) {
+ bgp_info = (struct bgp_info *)object;
+ if (!bgp_info || !bgp_info->attr)
+ return RMAP_DENYMATCH;
+
+ if (IPV6_ADDR_SAME(&bgp_info->attr->mp_nexthop_global, addr)
+ && !bgp_info->attr->nh_ifindex)
+ return RMAP_MATCH;
+ }
+ return RMAP_NOMATCH;
+ }
+
+ static void *route_match_ipv6_next_hop_type_compile(const char *arg)
+ {
+ struct in6_addr *address;
+ int ret;
+
+ address = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct in6_addr));
+
+ ret = inet_pton(AF_INET6, "::0", address);
+ if (!ret) {
+ XFREE(MTYPE_ROUTE_MAP_COMPILED, address);
+ return NULL;
+ }
+
+ return address;
+ }
+
+ static void route_match_ipv6_next_hop_type_free(void *rule)
+ {
+ XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
+ }
+
+ struct route_map_rule_cmd route_match_ipv6_next_hop_type_cmd = {
+ "ipv6 next-hop type", route_match_ipv6_next_hop_type,
+ route_match_ipv6_next_hop_type_compile,
+ route_match_ipv6_next_hop_type_free};
+
/* `set ipv6 nexthop global IP_ADDRESS' */
/* Set nexthop to object. ojbect must be pointer to struct attr. */
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,
route_map_match_ip_next_hop_prefix_list_hook(generic_match_add);
route_map_no_match_ip_next_hop_prefix_list_hook(generic_match_delete);
+ route_map_match_ip_next_hop_type_hook(generic_match_add);
+ route_map_no_match_ip_next_hop_type_hook(generic_match_delete);
+
route_map_match_ipv6_address_hook(generic_match_add);
route_map_no_match_ipv6_address_hook(generic_match_delete);
route_map_match_ipv6_address_prefix_list_hook(generic_match_add);
route_map_no_match_ipv6_address_prefix_list_hook(generic_match_delete);
+ route_map_match_ipv6_next_hop_type_hook(generic_match_add);
+ route_map_no_match_ipv6_next_hop_type_hook(generic_match_delete);
+
route_map_match_metric_hook(generic_match_add);
route_map_no_match_metric_hook(generic_match_delete);
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);
route_map_install_match(&route_match_ip_address_prefix_list_cmd);
route_map_install_match(&route_match_ip_next_hop_prefix_list_cmd);
+ route_map_install_match(&route_match_ip_next_hop_type_cmd);
route_map_install_match(&route_match_ip_route_source_prefix_list_cmd);
route_map_install_match(&route_match_aspath_cmd);
route_map_install_match(&route_match_community_cmd);
route_map_install_match(&route_match_ipv6_address_cmd);
route_map_install_match(&route_match_ipv6_next_hop_cmd);
route_map_install_match(&route_match_ipv6_address_prefix_list_cmd);
+ route_map_install_match(&route_match_ipv6_next_hop_type_cmd);
route_map_install_set(&route_set_ipv6_nexthop_global_cmd);
route_map_install_set(&route_set_ipv6_nexthop_prefer_global_cmd);
route_map_install_set(&route_set_ipv6_nexthop_local_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);
+#endif
}
void bgp_route_map_terminate(void)
const char *arg,
route_map_event_t type);
+ /* match ip next hop type */
+ int (*match_ip_next_hop_type)(struct vty *vty,
+ struct route_map_index *index,
+ const char *command,
+ const char *arg,
+ route_map_event_t type);
+
+ /* no match ip next hop type */
+ int (*no_match_ip_next_hop_type)(struct vty *vty,
+ struct route_map_index *index,
+ const char *command,
+ const char *arg,
+ route_map_event_t type);
+
/* match ipv6 address */
int (*match_ipv6_address)(struct vty *vty,
struct route_map_index *index,
const char *arg,
route_map_event_t type);
+ /* match ipv6 next-hop type */
+ int (*match_ipv6_next_hop_type)(struct vty *vty,
+ struct route_map_index *index,
+ const char *command,
+ const char *arg,
+ route_map_event_t type);
+
+ /* no match ipv6next-hop type */
+ int (*no_match_ipv6_next_hop_type)(struct vty *vty,
+ struct route_map_index *index,
+ const char *command, const char *arg,
+ route_map_event_t type);
+
/* match metric */
int (*match_metric)(struct vty *vty, struct route_map_index *index,
const char *command, const char *arg,
rmap_match_set_hook.no_match_ip_next_hop_prefix_list = func;
}
+ /* match ip next hop type */
+ void route_map_match_ip_next_hop_type_hook(int (*func)(
+ struct vty *vty, struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type))
+ {
+ rmap_match_set_hook.match_ip_next_hop_type = func;
+ }
+
+ /* no match ip next hop type */
+ void route_map_no_match_ip_next_hop_type_hook(int (*func)(
+ struct vty *vty, struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type))
+ {
+ rmap_match_set_hook.no_match_ip_next_hop_type = func;
+ }
+
/* match ipv6 address */
void route_map_match_ipv6_address_hook(int (*func)(
struct vty *vty, struct route_map_index *index, const char *command,
rmap_match_set_hook.no_match_ipv6_address_prefix_list = func;
}
+ /* match ipv6 next-hop type */
+ void route_map_match_ipv6_next_hop_type_hook(int (*func)(
+ struct vty *vty, struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type))
+ {
+ rmap_match_set_hook.match_ipv6_next_hop_type = func;
+ }
+
+ /* no match ipv6 next-hop type */
+ void route_map_no_match_ipv6_next_hop_type_hook(int (*func)(
+ struct vty *vty, struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type))
+ {
+ rmap_match_set_hook.no_match_ipv6_next_hop_type = func;
+ }
+
/* match metric */
void route_map_match_metric_hook(int (*func)(
struct vty *vty, struct route_map_index *index, const char *command,
struct route_map_index *index;
struct route_map_rule *rule;
- vty_out(vty, "%s:\n", frr_protonameinst);
+ vty_out(vty, "route-map: %s Invoked: %" PRIu64 "\n",
+ map->name, map->applied);
for (index = map->head; index; index = index->next) {
- vty_out(vty, "route-map %s, %s, sequence %d\n", map->name,
- route_map_type_str(index->type), index->pref);
+ vty_out(vty, " %s, sequence %d Invoked %" PRIu64 "\n",
+ route_map_type_str(index->type), index->pref,
+ index->applied);
/* Description */
if (index->description)
{
struct route_map *map;
+ vty_out(vty, "%s:\n", frr_protonameinst);
+
if (name) {
map = route_map_lookup_by_name(name);
if (map == NULL)
return RMAP_DENYMATCH;
+ map->applied++;
for (index = map->head; index; index = index->next) {
/* Apply this index. */
+ index->applied++;
ret = route_map_apply_match(&index->match_list, prefix, type,
object);
return CMD_SUCCESS;
}
+ DEFUN(match_ip_next_hop_type, match_ip_next_hop_type_cmd,
+ "match ip next-hop type <blackhole>",
+ MATCH_STR IP_STR
+ "Match next-hop address of route\n"
+ "Match entries by type\n"
+ "Blackhole\n")
+ {
+ int idx_word = 4;
+ VTY_DECLVAR_CONTEXT(route_map_index, index);
+
+ if (rmap_match_set_hook.match_ip_next_hop_type)
+ return rmap_match_set_hook.match_ip_next_hop_type(
+ vty, index, "ip next-hop type", argv[idx_word]->arg,
+ RMAP_EVENT_MATCH_ADDED);
+ return CMD_SUCCESS;
+ }
+
+ DEFUN(no_match_ip_next_hop_type, no_match_ip_next_hop_type_cmd,
+ "no match ip next-hop type [<blackhole>]",
+ NO_STR MATCH_STR IP_STR
+ "Match next-hop address of route\n"
+ "Match entries by type\n"
+ "Blackhole\n")
+ {
+ int idx_word = 5;
+ VTY_DECLVAR_CONTEXT(route_map_index, index);
+
+ if (rmap_match_set_hook.no_match_ip_next_hop) {
+ if (argc <= idx_word)
+ return rmap_match_set_hook.no_match_ip_next_hop(
+ vty, index, "ip next-hop type", NULL,
+ RMAP_EVENT_MATCH_DELETED);
+ return rmap_match_set_hook.no_match_ip_next_hop(
+ vty, index, "ip next-hop type", argv[idx_word]->arg,
+ RMAP_EVENT_MATCH_DELETED);
+ }
+ return CMD_SUCCESS;
+ }
+
DEFUN (match_ipv6_address,
match_ipv6_address_cmd,
return CMD_SUCCESS;
}
+ DEFUN(match_ipv6_next_hop_type, match_ipv6_next_hop_type_cmd,
+ "match ipv6 next-hop type <blackhole>",
+ MATCH_STR IPV6_STR
+ "Match address of route\n"
+ "Match entries by type\n"
+ "Blackhole\n")
+ {
+ int idx_word = 4;
+ VTY_DECLVAR_CONTEXT(route_map_index, index);
+
+ if (rmap_match_set_hook.match_ipv6_next_hop_type)
+ return rmap_match_set_hook.match_ipv6_next_hop_type(
+ vty, index, "ipv6 next-hop type", argv[idx_word]->arg,
+ RMAP_EVENT_MATCH_ADDED);
+ return CMD_SUCCESS;
+ }
+
+ DEFUN(no_match_ipv6_next_hop_type, no_match_ipv6_next_hop_type_cmd,
+ "no match ipv6 next-hop type [<blackhole>]",
+ NO_STR MATCH_STR IPV6_STR
+ "Match address of route\n"
+ "Match entries by type\n"
+ "Blackhole\n")
+ {
+ int idx_word = 5;
+ VTY_DECLVAR_CONTEXT(route_map_index, index);
+
+ if (rmap_match_set_hook.no_match_ipv6_next_hop_type)
+ return rmap_match_set_hook.no_match_ipv6_next_hop_type(
+ vty, index, "ipv6 next-hop type", argv[idx_word]->arg,
+ RMAP_EVENT_MATCH_DELETED);
+ return CMD_SUCCESS;
+ }
DEFUN (match_metric,
match_metric_cmd,
install_element(RMAP_NODE, &match_ip_next_hop_prefix_list_cmd);
install_element(RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd);
+ install_element(RMAP_NODE, &match_ip_next_hop_type_cmd);
+ install_element(RMAP_NODE, &no_match_ip_next_hop_type_cmd);
+
install_element(RMAP_NODE, &match_ipv6_address_cmd);
install_element(RMAP_NODE, &no_match_ipv6_address_cmd);
install_element(RMAP_NODE, &match_ipv6_address_prefix_list_cmd);
install_element(RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd);
+ install_element(RMAP_NODE, &match_ipv6_next_hop_type_cmd);
+ install_element(RMAP_NODE, &no_match_ipv6_next_hop_type_cmd);
+
install_element(RMAP_NODE, &match_metric_cmd);
install_element(RMAP_NODE, &no_match_metric_cmd);
struct route_map_index *next;
struct route_map_index *prev;
+ /* Keep track how many times we've try to apply */
+ uint64_t applied;
+
QOBJ_FIELDS
};
DECLARE_QOBJ_TYPE(route_map_index)
bool to_be_processed; /* True if modification isn't acted on yet */
bool deleted; /* If 1, then this node will be deleted */
+ /* How many times have we applied this route-map */
+ uint64_t applied;
+
QOBJ_FIELDS
};
DECLARE_QOBJ_TYPE(route_map)
extern void route_map_no_match_ip_next_hop_prefix_list_hook(int (*func)(
struct vty *vty, struct route_map_index *index, const char *command,
const char *arg, route_map_event_t type));
+ /* match ip next hop type */
+ extern void route_map_match_ip_next_hop_type_hook(int (*func)(
+ struct vty *vty, struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type));
+ /* no match ip next hop type */
+ extern void route_map_no_match_ip_next_hop_type_hook(int (*func)(
+ struct vty *vty, struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type));
/* match ipv6 address */
extern void route_map_match_ipv6_address_hook(int (*func)(
struct vty *vty, struct route_map_index *index, const char *command,
extern void route_map_no_match_ipv6_address_prefix_list_hook(int (*func)(
struct vty *vty, struct route_map_index *index, const char *command,
const char *arg, route_map_event_t type));
+ /* match ipv6 next-hop type */
+ extern void route_map_match_ipv6_next_hop_type_hook(int (*func)(
+ struct vty *vty, struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type));
+ /* no match ipv6 next-hop type */
+ extern void route_map_no_match_ipv6_next_hop_type_hook(int (*func)(
+ struct vty *vty, struct route_map_index *index, const char *command,
+ const char *arg, route_map_event_t type));
/* match metric */
extern void route_map_match_metric_hook(int (*func)(
struct vty *vty, struct route_map_index *index, const char *command,