summaryrefslogtreecommitdiffstats
path: root/zebra/zebra_routemap.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/zebra_routemap.c')
-rw-r--r--zebra/zebra_routemap.c953
1 files changed, 910 insertions, 43 deletions
diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c
index da9cb130..5184589c 100644
--- a/zebra/zebra_routemap.c
+++ b/zebra/zebra_routemap.c
@@ -29,13 +29,34 @@
#include "filter.h"
#include "plist.h"
#include "vrf.h"
+#include "nexthop.h"
#include "zebra/zserv.h"
+#include "zebra/debug.h"
+#include "zebra/zebra_rnh.h"
+
+static u_int32_t zebra_rmap_update_timer = ZEBRA_RMAP_DEFAULT_UPDATE_TIMER;
+static struct thread *zebra_t_rmap_update = NULL;
+char *proto_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1]; /* "any" == ZEBRA_ROUTE_MAX */
+/* NH Tracking route map */
+char *nht_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1]; /* "any" == ZEBRA_ROUTE_MAX */
+
+extern struct zebra_t zebrad;
+struct nh_rmap_obj
+{
+ struct nexthop *nexthop;
+ vrf_id_t vrf_id;
+ u_int32_t source_protocol;
+ int metric;
+};
+
+static void zebra_route_map_set_delay_timer(u_int32_t value);
/* Add zebra route map rule */
static int
zebra_route_match_add(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg)
+ const char *command, const char *arg,
+ route_map_event_t type)
{
int ret;
@@ -45,22 +66,42 @@ zebra_route_match_add(struct vty *vty, struct route_map_index *index,
switch (ret)
{
case RMAP_RULE_MISSING:
- vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ vty_out (vty, "%% Zebra Can't find rule.%s", VTY_NEWLINE);
return CMD_WARNING;
case RMAP_COMPILE_ERROR:
- vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ vty_out (vty, "%% Zebra Argument is malformed.%s", VTY_NEWLINE);
return CMD_WARNING;
}
}
+
+ if (type != RMAP_EVENT_MATCH_ADDED)
+ {
+ route_map_upd8_dependency (type, arg, index->map->name);
+ }
return CMD_SUCCESS;
}
/* Delete zebra route map rule. */
static int
zebra_route_match_delete (struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg)
+ const char *command, const char *arg,
+ route_map_event_t type)
{
int ret;
+ char *dep_name = (char *)arg;
+ const char *tmpstr;
+ char *rmap_name = NULL;
+
+ if (type != RMAP_EVENT_MATCH_DELETED)
+ {
+ /* ignore the mundane, the types without any dependency */
+ if (arg == NULL)
+ {
+ if ((tmpstr = route_map_get_match_arg(index, command)) != NULL)
+ dep_name = XSTRDUP(MTYPE_ROUTE_MAP_RULE, tmpstr);
+ }
+ rmap_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, index->map->name);
+ }
ret = route_map_delete_match (index, command, arg);
if (ret)
@@ -68,13 +109,22 @@ zebra_route_match_delete (struct vty *vty, struct route_map_index *index,
switch (ret)
{
case RMAP_RULE_MISSING:
- vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ vty_out (vty, "%% Zebra Can't find rule.%s", VTY_NEWLINE);
return CMD_WARNING;
case RMAP_COMPILE_ERROR:
- vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ vty_out (vty, "%% Zebra Argument is malformed.%s", VTY_NEWLINE);
return CMD_WARNING;
}
}
+
+ if (type != RMAP_EVENT_MATCH_DELETED && dep_name)
+ route_map_upd8_dependency(type, dep_name, rmap_name);
+
+ if (arg == NULL && dep_name)
+ XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
+ if (rmap_name)
+ XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
+
return CMD_SUCCESS;
}
@@ -91,10 +141,10 @@ zebra_route_set_add (struct vty *vty, struct route_map_index *index,
switch (ret)
{
case RMAP_RULE_MISSING:
- vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ vty_out (vty, "%% Zebra Can't find rule.%s", VTY_NEWLINE);
return CMD_WARNING;
case RMAP_COMPILE_ERROR:
- vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ vty_out (vty, "%% Zebra Argument is malformed.%s", VTY_NEWLINE);
return CMD_WARNING;
}
}
@@ -114,10 +164,10 @@ zebra_route_set_delete (struct vty *vty, struct route_map_index *index,
switch (ret)
{
case RMAP_RULE_MISSING:
- vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ vty_out (vty, "%% Zebra Can't find rule.%s", VTY_NEWLINE);
return CMD_WARNING;
case RMAP_COMPILE_ERROR:
- vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ vty_out (vty, "%% Zebra Argument is malformed.%s", VTY_NEWLINE);
return CMD_WARNING;
}
}
@@ -131,7 +181,7 @@ static route_map_result_t
route_match_interface (void *rule, struct prefix *prefix,
route_map_object_t type, void *object)
{
- struct nexthop_vrfid *nh_vrf;
+ struct nh_rmap_obj *nh_data;
struct nexthop *nexthop;
char *ifname = rule;
ifindex_t ifindex;
@@ -140,13 +190,13 @@ route_match_interface (void *rule, struct prefix *prefix,
{
if (strcasecmp(ifname, "any") == 0)
return RMAP_MATCH;
- nh_vrf = object;
- if (!nh_vrf)
+ nh_data = object;
+ if (!nh_data)
return RMAP_NOMATCH;
- ifindex = ifname2ifindex_vrf (ifname, nh_vrf->vrf_id);
+ ifindex = ifname2ifindex_vrf (ifname, nh_data->vrf_id);
if (ifindex == 0)
return RMAP_NOMATCH;
- nexthop = nh_vrf->nexthop;
+ nexthop = nh_data->nexthop;
if (!nexthop)
return RMAP_NOMATCH;
if (nexthop->ifindex == ifindex)
@@ -185,7 +235,8 @@ DEFUN (match_interface,
"match first hop interface of route\n"
"Interface name\n")
{
- return zebra_route_match_add (vty, vty->index, "interface", argv[0]);
+ return zebra_route_match_add (vty, vty->index, "interface", argv[0],
+ RMAP_EVENT_MATCH_ADDED);
}
DEFUN (no_match_interface,
@@ -196,9 +247,9 @@ DEFUN (no_match_interface,
"Match first hop interface of route\n")
{
if (argc == 0)
- return zebra_route_match_delete (vty, vty->index, "interface", NULL);
+ return zebra_route_match_delete (vty, vty->index, "interface", NULL, RMAP_EVENT_MATCH_DELETED);
- return zebra_route_match_delete (vty, vty->index, "interface", argv[0]);
+ return zebra_route_match_delete (vty, vty->index, "interface", argv[0], RMAP_EVENT_MATCH_DELETED);
}
ALIAS (no_match_interface,
@@ -219,7 +270,7 @@ DEFUN (match_ip_next_hop,
"IP access-list number (expanded range)\n"
"IP Access-list name\n")
{
- return zebra_route_match_add (vty, vty->index, "ip next-hop", argv[0]);
+ return zebra_route_match_add (vty, vty->index, "ip next-hop", argv[0], RMAP_EVENT_FILTER_ADDED);
}
DEFUN (no_match_ip_next_hop,
@@ -231,9 +282,11 @@ DEFUN (no_match_ip_next_hop,
"Match next-hop address of route\n")
{
if (argc == 0)
- return zebra_route_match_delete (vty, vty->index, "ip next-hop", NULL);
+ return zebra_route_match_delete (vty, vty->index, "ip next-hop", NULL,
+ RMAP_EVENT_FILTER_DELETED);
- return zebra_route_match_delete (vty, vty->index, "ip next-hop", argv[0]);
+ return zebra_route_match_delete (vty, vty->index, "ip next-hop", argv[0],
+ RMAP_EVENT_FILTER_DELETED);
}
ALIAS (no_match_ip_next_hop,
@@ -256,7 +309,8 @@ DEFUN (match_ip_next_hop_prefix_list,
"Match entries of prefix-lists\n"
"IP prefix-list name\n")
{
- return zebra_route_match_add (vty, vty->index, "ip next-hop prefix-list", argv[0]);
+ return zebra_route_match_add (vty, vty->index, "ip next-hop prefix-list",
+ argv[0], RMAP_EVENT_PLIST_ADDED);
}
DEFUN (no_match_ip_next_hop_prefix_list,
@@ -269,9 +323,13 @@ DEFUN (no_match_ip_next_hop_prefix_list,
"Match entries of prefix-lists\n")
{
if (argc == 0)
- return zebra_route_match_delete (vty, vty->index, "ip next-hop prefix-list", NULL);
+ return zebra_route_match_delete (vty, vty->index,
+ "ip next-hop prefix-list", NULL,
+ RMAP_EVENT_PLIST_DELETED);
- return zebra_route_match_delete (vty, vty->index, "ip next-hop prefix-list", argv[0]);
+ return zebra_route_match_delete (vty, vty->index,
+ "ip next-hop prefix-list", argv[0],
+ RMAP_EVENT_PLIST_DELETED);
}
ALIAS (no_match_ip_next_hop_prefix_list,
@@ -295,7 +353,8 @@ DEFUN (match_ip_address,
"IP Access-list name\n")
{
- return zebra_route_match_add (vty, vty->index, "ip address", argv[0]);
+ return zebra_route_match_add (vty, vty->index, "ip address", argv[0],
+ RMAP_EVENT_FILTER_ADDED);
}
DEFUN (no_match_ip_address,
@@ -307,9 +366,11 @@ DEFUN (no_match_ip_address,
"Match address of route\n")
{
if (argc == 0)
- return zebra_route_match_delete (vty, vty->index, "ip address", NULL);
+ return zebra_route_match_delete (vty, vty->index, "ip address", NULL,
+ RMAP_EVENT_FILTER_DELETED);
- return zebra_route_match_delete (vty, vty->index, "ip address", argv[0]);
+ return zebra_route_match_delete (vty, vty->index, "ip address", argv[0],
+ RMAP_EVENT_FILTER_DELETED);
}
ALIAS (no_match_ip_address,
@@ -332,7 +393,8 @@ DEFUN (match_ip_address_prefix_list,
"Match entries of prefix-lists\n"
"IP prefix-list name\n")
{
- return zebra_route_match_add (vty, vty->index, "ip address prefix-list", argv[0]);
+ return zebra_route_match_add (vty, vty->index, "ip address prefix-list",
+ argv[0], RMAP_EVENT_PLIST_ADDED);
}
DEFUN (no_match_ip_address_prefix_list,
@@ -345,9 +407,13 @@ DEFUN (no_match_ip_address_prefix_list,
"Match entries of prefix-lists\n")
{
if (argc == 0)
- return zebra_route_match_delete (vty, vty->index, "ip address prefix-list", NULL);
+ return zebra_route_match_delete (vty, vty->index,
+ "ip address prefix-list", NULL,
+ RMAP_EVENT_PLIST_DELETED);
- return zebra_route_match_delete (vty, vty->index, "ip address prefix-list", argv[0]);
+ return zebra_route_match_delete (vty, vty->index,
+ "ip address prefix-list", argv[0],
+ RMAP_EVENT_PLIST_DELETED);
}
ALIAS (no_match_ip_address_prefix_list,
@@ -360,6 +426,129 @@ ALIAS (no_match_ip_address_prefix_list,
"Match entries of prefix-lists\n"
"IP prefix-list name\n")
+DEFUN (match_ip_address_prefix_len,
+ match_ip_address_prefix_len_cmd,
+ "match ip address prefix-len NUMBER",
+ MATCH_STR
+ IP_STR
+ "Match prefix length of ip address\n"
+ "Match prefix length of ip address\n"
+ "Prefix length\n")
+{
+ return zebra_route_match_add (vty, vty->index, "ip address prefix-len",
+ argv[0], RMAP_EVENT_MATCH_ADDED);
+}
+
+DEFUN (no_match_ip_address_prefix_len,
+ no_match_ip_address_prefix_len_cmd,
+ "no match ip address prefix-len",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match prefixlen of ip address of route\n"
+ "prefix length of ip address\n")
+{
+ if (argc == 0)
+ return zebra_route_match_delete (vty, vty->index,
+ "ip address prefix-len", NULL,
+ RMAP_EVENT_MATCH_DELETED);
+
+ return zebra_route_match_delete (vty, vty->index,
+ "ip address prefix-len", argv[0],
+ RMAP_EVENT_MATCH_DELETED);
+}
+
+ALIAS (no_match_ip_address_prefix_len,
+ no_match_ip_address_prefix_len_val_cmd,
+ "no match ip address prefix-len NUMBER",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match prefixlen of ip address of route\n"
+ "prefix length of ip address\n")
+
+DEFUN (match_ip_nexthop_prefix_len,
+ match_ip_nexthop_prefix_len_cmd,
+ "match ip next-hop prefix-len NUMBER",
+ MATCH_STR
+ IP_STR
+ "Match prefixlen of nexthop ip address\n"
+ "Match prefixlen of given nexthop\n"
+ "Prefix length\n")
+{
+ return zebra_route_match_add (vty, vty->index, "ip next-hop prefix-len",
+ argv[0], RMAP_EVENT_MATCH_ADDED);
+}
+
+DEFUN (no_match_ip_nexthop_prefix_len,
+ no_match_ip_nexthop_prefix_len_cmd,
+ "no match ip next-hop prefix-len",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match prefixlen of nexthop ip address\n"
+ "Match prefix length of nexthop\n")
+{
+ if (argc == 0)
+ return zebra_route_match_delete (vty, vty->index,
+ "ip next-hop prefix-len", NULL,
+ RMAP_EVENT_MATCH_DELETED);
+
+ return zebra_route_match_delete (vty, vty->index,
+ "ip next-hop prefix-len", argv[0],
+ RMAP_EVENT_MATCH_DELETED);
+}
+
+ALIAS (no_match_ip_nexthop_prefix_len,
+ no_match_ip_nexthop_prefix_len_val_cmd,
+ "no match ip next-hop prefix-len NUMBER",
+ MATCH_STR
+ "Match prefixlen of ip address of route\n"
+ "prefix length of ip address\n")
+
+DEFUN (match_source_protocol,
+ match_source_protocol_cmd,
+ "match source-protocol (bgp|ospf|rip|ripng|isis|ospf6|connected|system|kernel|static)",
+ MATCH_STR
+ "Match protocol via which the route was learnt\n")
+{
+ int i;
+
+ i = proto_name2num(argv[0]);
+ if (i < 0)
+ {
+ vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ return zebra_route_match_add (vty, vty->index, "source-protocol",
+ argv[0], RMAP_EVENT_MATCH_ADDED);
+}
+
+DEFUN (no_match_source_protocol,
+ no_match_source_protocol_cmd,
+ "no match source-protocol (bgp|ospf|rip|ripng|isis|ospf6|connected|system|kernel|static)",
+ NO_STR
+ MATCH_STR
+ "No match protocol via which the route was learnt\n")
+{
+ int i;
+
+ if (argc >= 1)
+ {
+ i = proto_name2num(argv[0]);
+ if (i < 0)
+ {
+ vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+ return zebra_route_match_delete (vty, vty->index,
+ "source-protocol", argv[0] ? argv[0] : NULL,
+ RMAP_EVENT_MATCH_DELETED);
+}
+
/* set functions */
DEFUN (set_src,
@@ -413,6 +602,340 @@ ALIAS (no_set_src,
"src address for route\n"
"src address\n")
+DEFUN (zebra_route_map_timer,
+ zebra_route_map_timer_cmd,
+ "zebra route-map delay-timer <0-600>",
+ "Time to wait before route-map updates are processed\n"
+ "0 means event-driven updates are disabled\n")
+{
+ u_int32_t rmap_delay_timer;
+
+ VTY_GET_INTEGER_RANGE ("delay-timer", rmap_delay_timer, argv[0], 0, 600);
+ zebra_route_map_set_delay_timer(rmap_delay_timer);
+
+ return (CMD_SUCCESS);
+}
+
+DEFUN (no_zebra_route_map_timer,
+ no_zebra_route_map_timer_cmd,
+ "no zebra route-map delay-timer",
+ NO_STR
+ "Time to wait before route-map updates are processed\n"
+ "Reset delay-timer to default value, 30 secs\n")
+{
+ zebra_route_map_set_delay_timer(ZEBRA_RMAP_DEFAULT_UPDATE_TIMER);
+
+ return (CMD_SUCCESS);
+}
+
+DEFUN (ip_protocol,
+ ip_protocol_cmd,
+ "ip protocol " QUAGGA_IP_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP",
+ IP_STR
+ "Filter routing info exchanged between zebra and protocol\n"
+ QUAGGA_IP_PROTOCOL_MAP_HELP_STR_ZEBRA
+ "Route map name\n")
+{
+ int i;
+
+ if (strcasecmp(argv[0], "any") == 0)
+ i = ZEBRA_ROUTE_MAX;
+ else
+ i = proto_name2num(argv[0]);
+ if (i < 0)
+ {
+ vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (proto_rm[AFI_IP][i])
+ {
+ if (strcmp(proto_rm[AFI_IP][i], argv[1]) == 0)
+ return CMD_SUCCESS;
+
+ XFREE (MTYPE_ROUTE_MAP_NAME, proto_rm[AFI_IP][i]);
+ }
+ proto_rm[AFI_IP][i] = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[1]);
+ rib_update(VRF_DEFAULT);
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_protocol,
+ no_ip_protocol_cmd,
+ "no ip protocol " QUAGGA_IP_PROTOCOL_MAP_STR_ZEBRA,
+ NO_STR
+ IP_STR
+ "Stop filtering routing info between zebra and protocol\n"
+ QUAGGA_IP_PROTOCOL_MAP_HELP_STR_ZEBRA
+ "Protocol from which to stop filtering routes\n")
+{
+ int i;
+
+ if (strcasecmp(argv[0], "any") == 0)
+ i = ZEBRA_ROUTE_MAX;
+ else
+ i = proto_name2num(argv[0]);
+ if (i < 0)
+ {
+ vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (!proto_rm[AFI_IP][i])
+ return CMD_SUCCESS;
+
+ if ((argc == 2 && strcmp(argv[1], proto_rm[AFI_IP][i]) == 0) ||
+ (argc < 2))
+ {
+ XFREE (MTYPE_ROUTE_MAP_NAME, proto_rm[AFI_IP][i]);
+ proto_rm[AFI_IP][i] = NULL;
+ rib_update(VRF_DEFAULT);
+ }
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_ip_protocol,
+ no_ip_protocol_val_cmd,
+ "no ip protocol " QUAGGA_IP_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP",
+ NO_STR
+ IP_STR
+ "Stop filtering routing info between zebra and protocol\n"
+ QUAGGA_IP_PROTOCOL_MAP_HELP_STR_ZEBRA
+ "route map name")
+
+DEFUN (show_ip_protocol,
+ show_ip_protocol_cmd,
+ "show ip protocol",
+ SHOW_STR
+ IP_STR
+ "IP protocol filtering status\n")
+{
+ int i;
+
+ vty_out(vty, "Protocol : route-map %s", VTY_NEWLINE);
+ vty_out(vty, "------------------------%s", VTY_NEWLINE);
+ for (i=0;i<ZEBRA_ROUTE_MAX;i++)
+ {
+ if (proto_rm[AFI_IP][i])
+ vty_out (vty, "%-10s : %-10s%s", zebra_route_string(i),
+ proto_rm[AFI_IP][i],
+ VTY_NEWLINE);
+ else
+ vty_out (vty, "%-10s : none%s", zebra_route_string(i), VTY_NEWLINE);
+ }
+ if (proto_rm[AFI_IP][i])
+ vty_out (vty, "%-10s : %-10s%s", "any", proto_rm[AFI_IP][i],
+ VTY_NEWLINE);
+ else
+ vty_out (vty, "%-10s : none%s", "any", VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (ip_protocol_nht_rmap,
+ ip_protocol_nht_rmap_cmd,
+ "ip nht " QUAGGA_IP_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP",
+ IP_STR
+ "Filter Next Hop tracking route resolution\n"
+ QUAGGA_IP_PROTOCOL_MAP_HELP_STR_ZEBRA
+ "Route map name\n")
+{
+ int i;
+
+ if (strcasecmp(argv[0], "any") == 0)
+ i = ZEBRA_ROUTE_MAX;
+ else
+ i = proto_name2num(argv[0]);
+ if (i < 0)
+ {
+ vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (nht_rm[AFI_IP][i])
+ {
+ if (strcmp(nht_rm[AFI_IP][i], argv[1]) == 0)
+ return CMD_SUCCESS;
+
+ XFREE (MTYPE_ROUTE_MAP_NAME, nht_rm[AFI_IP][i]);
+ }
+
+ nht_rm[AFI_IP][i] = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[1]);
+ zebra_evaluate_rnh_table(0, AF_INET, 1);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_protocol_nht_rmap,
+ no_ip_protocol_nht_rmap_cmd,
+ "no ip nht " QUAGGA_IP_PROTOCOL_MAP_STR_ZEBRA,
+ NO_STR
+ IP_STR
+ "Filter Next Hop tracking route resolution\n"
+ QUAGGA_IP_PROTOCOL_MAP_HELP_STR_ZEBRA)
+{
+ int i;
+
+ if (strcasecmp(argv[0], "any") == 0)
+ i = ZEBRA_ROUTE_MAX;
+ else
+ i = proto_name2num(argv[0]);
+ if (i < 0)
+ {
+ vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (!nht_rm[AFI_IP][i])
+ return CMD_SUCCESS;
+
+ if ((argc == 2 && strcmp(argv[1], nht_rm[AFI_IP][i]) == 0) ||
+ (argc < 2))
+ {
+ XFREE (MTYPE_ROUTE_MAP_NAME, nht_rm[AFI_IP][i]);
+ nht_rm[AFI_IP][i] = NULL;
+ zebra_evaluate_rnh_table(0, AF_INET, 1);
+ }
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_ip_protocol_nht_rmap,
+ no_ip_protocol_nht_rmap_val_cmd,
+ "no ip nht " QUAGGA_IP_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP",
+ IP_STR
+ "Filter Next Hop tracking route resolution\n"
+ QUAGGA_IP_PROTOCOL_MAP_HELP_STR_ZEBRA
+ "Route map name\n")
+
+DEFUN (show_ip_protocol_nht,
+ show_ip_protocol_nht_cmd,
+ "show ip nht route-map",
+ SHOW_STR
+ IP_STR
+ "IP Next Hop tracking filtering status\n")
+{
+ int i;
+
+ vty_out(vty, "Protocol : route-map %s", VTY_NEWLINE);
+ vty_out(vty, "------------------------%s", VTY_NEWLINE);
+ for (i=0;i<ZEBRA_ROUTE_MAX;i++)
+ {
+ if (nht_rm[AFI_IP][i])
+ vty_out (vty, "%-10s : %-10s%s", zebra_route_string(i),
+ nht_rm[AFI_IP][i],
+ VTY_NEWLINE);
+ else
+ vty_out (vty, "%-10s : none%s", zebra_route_string(i), VTY_NEWLINE);
+ }
+ if (nht_rm[AFI_IP][i])
+ vty_out (vty, "%-10s : %-10s%s", "any", nht_rm[AFI_IP][i],
+ VTY_NEWLINE);
+ else
+ vty_out (vty, "%-10s : none%s", "any", VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_protocol_nht_rmap,
+ ipv6_protocol_nht_rmap_cmd,
+ "ipv6 nht " QUAGGA_IP6_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP",
+ IP6_STR
+ "Filter Next Hop tracking route resolution\n"
+ QUAGGA_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA
+ "Route map name\n")
+{
+ int i;
+
+ if (strcasecmp(argv[0], "any") == 0)
+ i = ZEBRA_ROUTE_MAX;
+ else
+ i = proto_name2num(argv[0]);
+ if (i < 0)
+ {
+ vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (nht_rm[AFI_IP6][i])
+ XFREE (MTYPE_ROUTE_MAP_NAME, nht_rm[AFI_IP6][i]);
+ nht_rm[AFI_IP6][i] = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[1]);
+ zebra_evaluate_rnh_table(0, AF_INET6, 1);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_protocol_nht_rmap,
+ no_ipv6_protocol_nht_rmap_cmd,
+ "no ipv6 nht " QUAGGA_IP6_PROTOCOL_MAP_STR_ZEBRA,
+ NO_STR
+ IP6_STR
+ "Filter Next Hop tracking route resolution\n"
+ QUAGGA_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA)
+{
+ int i;
+
+ if (strcasecmp(argv[0], "any") == 0)
+ i = ZEBRA_ROUTE_MAX;
+ else
+ i = proto_name2num(argv[0]);
+ if (i < 0)
+ {
+ vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (nht_rm[AFI_IP6][i])
+ XFREE (MTYPE_ROUTE_MAP_NAME, nht_rm[AFI_IP6][i]);
+
+ if ((argc == 2 && strcmp(argv[1], nht_rm[AFI_IP6][i]) == 0) ||
+ (argc < 2))
+ {
+ XFREE (MTYPE_ROUTE_MAP_NAME, nht_rm[AFI_IP6][i]);
+ nht_rm[AFI_IP6][i] = NULL;
+ zebra_evaluate_rnh_table(0, AF_INET6, 1);
+ }
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_ipv6_protocol_nht_rmap,
+ no_ipv6_protocol_nht_rmap_val_cmd,
+ "no ipv6 nht " QUAGGA_IP6_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP",
+ NO_STR
+ IP6_STR
+ "Filter Next Hop tracking route resolution\n"
+ QUAGGA_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA
+ "Route map name\n")
+
+DEFUN (show_ipv6_protocol_nht,
+ show_ipv6_protocol_nht_cmd,
+ "show ipv6 nht route-map",
+ SHOW_STR
+ IP6_STR
+ "IPv6 protocol Next Hop filtering status\n")
+{
+ int i;
+
+ vty_out(vty, "Protocol : route-map %s", VTY_NEWLINE);
+ vty_out(vty, "------------------------%s", VTY_NEWLINE);
+ for (i=0;i<ZEBRA_ROUTE_MAX;i++)
+ {
+ if (nht_rm[AFI_IP6][i])
+ vty_out (vty, "%-10s : %-10s%s", zebra_route_string(i),
+ nht_rm[AFI_IP6][i],
+ VTY_NEWLINE);
+ else
+ vty_out (vty, "%-10s : none%s", zebra_route_string(i), VTY_NEWLINE);
+ }
+ if (nht_rm[AFI_IP][i])
+ vty_out (vty, "%-10s : %-10s%s", "any", nht_rm[AFI_IP6][i],
+ VTY_NEWLINE);
+ else
+ vty_out (vty, "%-10s : none%s", "any", VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
/*XXXXXXXXXXXXXXXXXXXXXXXXXXXX*/
/* `match ip next-hop IP_ACCESS_LIST' */
@@ -423,13 +946,16 @@ route_match_ip_next_hop (void *rule, struct prefix *prefix,
route_map_object_t type, void *object)
{
struct access_list *alist;
- struct nexthop *nexthop;
+ struct nh_rmap_obj *nh_data;
struct prefix_ipv4 p;
if (type == RMAP_ZEBRA)
{
- nexthop = object;
- switch (nexthop->type) {
+ nh_data = object;
+ if (!nh_data)
+ return RMAP_DENYMATCH;
+
+ switch (nh_data->nexthop->type) {
case NEXTHOP_TYPE_IFINDEX:
case NEXTHOP_TYPE_IFNAME:
/* Interface routes can't match ip next-hop */
@@ -438,7 +964,7 @@ route_match_ip_next_hop (void *rule, struct prefix *prefix,
case NEXTHOP_TYPE_IPV4_IFNAME:
case NEXTHOP_TYPE_IPV4:
p.family = AF_INET;
- p.prefix = nexthop->gate.ipv4;
+ p.prefix = nh_data->nexthop->gate.ipv4;
p.prefixlen = IPV4_MAX_BITLEN;
break;
default:
@@ -485,13 +1011,16 @@ route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix,
route_map_object_t type, void *object)
{
struct prefix_list *plist;
- struct nexthop *nexthop;
+ struct nh_rmap_obj *nh_data;
struct prefix_ipv4 p;
if (type == RMAP_ZEBRA)
{
- nexthop = object;
- switch (nexthop->type) {
+ nh_data = (struct nh_rmap_obj *)object;
+ if (!nh_data)
+ return RMAP_DENYMATCH;
+
+ switch (nh_data->nexthop->type) {
case NEXTHOP_TYPE_IFINDEX:
case NEXTHOP_TYPE_IFNAME:
/* Interface routes can't match ip next-hop */
@@ -500,7 +1029,7 @@ route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix,
case NEXTHOP_TYPE_IPV4_IFNAME:
case NEXTHOP_TYPE_IPV4:
p.family = AF_INET;
- p.prefix = nexthop->gate.ipv4;
+ p.prefix = nh_data->nexthop->gate.ipv4;
p.prefixlen = IPV4_MAX_BITLEN;
break;
default:
@@ -623,6 +1152,154 @@ static struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd =
};
+/* `match ip address prefix-len PREFIXLEN' */
+
+static route_map_result_t
+route_match_ip_address_prefix_len (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ u_int32_t *prefixlen = (u_int32_t *)rule;
+
+ if (type == RMAP_ZEBRA)
+ {
+ return ((prefix->prefixlen == *prefixlen) ? RMAP_MATCH : RMAP_NOMATCH);
+ }
+ return RMAP_NOMATCH;
+}
+
+static void *
+route_match_ip_address_prefix_len_compile (const char *arg)
+{
+ u_int32_t *prefix_len;
+ char *endptr = NULL;
+ unsigned long tmpval;
+
+ /* prefix len value shoud be integer. */
+ if (! all_digit (arg))
+ return NULL;
+
+ errno = 0;
+ tmpval = strtoul (arg, &endptr, 10);
+ if (*endptr != '\0' || errno || tmpval > UINT32_MAX)
+ return NULL;
+
+ prefix_len = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
+
+ if (!prefix_len)
+ return prefix_len;
+
+ *prefix_len = tmpval;
+ return prefix_len;
+}
+
+static void
+route_match_ip_address_prefix_len_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+static struct route_map_rule_cmd route_match_ip_address_prefix_len_cmd =
+{
+ "ip address prefix-len",
+ route_match_ip_address_prefix_len,
+ route_match_ip_address_prefix_len_compile,
+ route_match_ip_address_prefix_len_free
+};
+
+
+/* `match ip nexthop prefix-len PREFIXLEN' */
+
+static route_map_result_t
+route_match_ip_nexthop_prefix_len (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ u_int32_t *prefixlen = (u_int32_t *)rule;
+ struct nh_rmap_obj *nh_data;
+ struct prefix_ipv4 p;
+
+ if (type == RMAP_ZEBRA)
+ {
+ nh_data = (struct nh_rmap_obj *)object;
+ if (!nh_data || !nh_data->nexthop)
+ return RMAP_DENYMATCH;
+
+ switch (nh_data->nexthop->type) {
+ case NEXTHOP_TYPE_IFINDEX:
+ case NEXTHOP_TYPE_IFNAME:
+ /* Interface routes can't match ip next-hop */
+ return RMAP_NOMATCH;
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ case NEXTHOP_TYPE_IPV4_IFNAME:
+ case NEXTHOP_TYPE_IPV4:
+ p.family = AF_INET;
+ p.prefix = nh_data->nexthop->gate.ipv4;
+ p.prefixlen = IPV4_MAX_BITLEN;
+ break;
+ default:
+ return RMAP_NOMATCH;
+ }
+ return ((p.prefixlen == *prefixlen) ? RMAP_MATCH : RMAP_NOMATCH);
+ }
+ return RMAP_NOMATCH;
+}
+
+static struct route_map_rule_cmd route_match_ip_nexthop_prefix_len_cmd =
+{
+ "ip next-hop prefix-len",
+ route_match_ip_nexthop_prefix_len,
+ route_match_ip_address_prefix_len_compile, /* reuse */
+ route_match_ip_address_prefix_len_free /* reuse */
+};
+
+/* `match source-protocol PROTOCOL' */
+
+static route_map_result_t
+route_match_source_protocol (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ u_int32_t *rib_type = (u_int32_t *)rule;
+ struct nh_rmap_obj *nh_data;
+
+ if (type == RMAP_ZEBRA)
+ {
+ nh_data = (struct nh_rmap_obj *)object;
+ if (!nh_data)
+ return RMAP_DENYMATCH;
+
+ return ((nh_data->source_protocol == *rib_type)
+ ? RMAP_MATCH : RMAP_NOMATCH);
+ }
+ return RMAP_NOMATCH;
+}
+
+static void *
+route_match_source_protocol_compile (const char *arg)
+{
+ u_int32_t *rib_type;
+ int i;
+
+ i = proto_name2num(arg);
+ rib_type = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
+
+ *rib_type = i;
+
+ return rib_type;
+}
+
+static void
+route_match_source_protocol_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+static struct route_map_rule_cmd route_match_source_protocol_cmd =
+{
+ "source-protocol",
+ route_match_source_protocol,
+ route_match_source_protocol_compile,
+ route_match_source_protocol_free
+};
+
/* `set src A.B.C.D' */
/* Set src. */
@@ -630,12 +1307,12 @@ static route_map_result_t
route_set_src (void *rule, struct prefix *prefix,
route_map_object_t type, void *object)
{
+ struct nh_rmap_obj *nh_data;
+
if (type == RMAP_ZEBRA)
{
- struct nexthop *nexthop;
-
- nexthop = object;
- nexthop->src = *(union g_addr *)rule;
+ nh_data = (struct nh_rmap_obj *)object;
+ nh_data->nexthop->rmap_src = *(union g_addr *)rule;
}
return RMAP_OKAY;
}
@@ -675,17 +1352,199 @@ static struct route_map_rule_cmd route_set_src_cmd =
route_set_src_free,
};
+static int
+zebra_route_map_update_timer (struct thread *thread)
+{
+ zebra_t_rmap_update = NULL;
+
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug("Event driven route-map update triggered");
+
+ rib_update(VRF_DEFAULT);
+ zebra_evaluate_rnh_table(0, AF_INET, 1);
+ zebra_evaluate_rnh_table(0, AF_INET6, 1);
+
+ return (0);
+}
+
+static void
+zebra_route_map_set_delay_timer(u_int32_t value)
+{
+ zebra_rmap_update_timer = value;
+ if (!value && zebra_t_rmap_update)
+ {
+ /* Event driven route map updates is being disabled */
+ /* But there's a pending timer. Fire it off now */
+ thread_cancel(zebra_t_rmap_update);
+ zebra_route_map_update_timer(zebra_t_rmap_update);
+ }
+}
+
+void
+zebra_route_map_write_delay_timer (struct vty *vty)
+{
+ if (vty && (zebra_rmap_update_timer != ZEBRA_RMAP_DEFAULT_UPDATE_TIMER))
+ vty_out (vty, "zebra route-map delay-timer %d%s", zebra_rmap_update_timer,
+ VTY_NEWLINE);
+ return;
+}
+
+route_map_result_t
+zebra_route_map_check (int family, int rib_type, struct prefix *p,
+ struct nexthop *nexthop, vrf_id_t vrf_id)
+{
+ struct route_map *rmap = NULL;
+ route_map_result_t ret = RMAP_MATCH;
+ struct nh_rmap_obj nh_obj;
+
+ nh_obj.nexthop = nexthop;
+ nh_obj.vrf_id = vrf_id;
+ nh_obj.source_protocol = rib_type;
+ nh_obj.metric = 0;
+
+ if (rib_type >= 0 && rib_type < ZEBRA_ROUTE_MAX)
+ rmap = route_map_lookup_by_name (proto_rm[family][rib_type]);
+ if (!rmap && proto_rm[family][ZEBRA_ROUTE_MAX])
+ rmap = route_map_lookup_by_name (proto_rm[family][ZEBRA_ROUTE_MAX]);
+ if (rmap) {
+ ret = route_map_apply(rmap, p, RMAP_ZEBRA, &nh_obj);
+ }
+
+ return (ret);
+}
+
+route_map_result_t
+zebra_nht_route_map_check (int family, int client_proto, struct prefix *p,
+ struct rib * rib, struct nexthop *nexthop)
+{
+ struct route_map *rmap = NULL;
+ route_map_result_t ret = RMAP_MATCH;
+ struct nh_rmap_obj nh_obj;
+
+ nh_obj.nexthop = nexthop;
+ nh_obj.vrf_id = rib->vrf_id;
+ nh_obj.source_protocol = rib->type;
+ nh_obj.metric = rib->metric;
+
+ if (client_proto >= 0 && client_proto < ZEBRA_ROUTE_MAX)
+ rmap = route_map_lookup_by_name (nht_rm[family][client_proto]);
+ if (!rmap && nht_rm[family][ZEBRA_ROUTE_MAX])
+ rmap = route_map_lookup_by_name (nht_rm[family][ZEBRA_ROUTE_MAX]);
+ if (rmap) {
+ ret = route_map_apply(rmap, p, RMAP_ZEBRA, &nh_obj);
+ }
+
+ return (ret);
+}
+
+static void
+zebra_route_map_mark_update (const char *rmap_name)
+{
+ /* rmap_update_timer of 0 means don't do route updates */
+ if (zebra_rmap_update_timer && !zebra_t_rmap_update)
+ zebra_t_rmap_update =
+ thread_add_timer(zebrad.master, zebra_route_map_update_timer, NULL,
+ zebra_rmap_update_timer);
+}
+
+static void
+zebra_route_map_add (const char *rmap_name)
+{
+ zebra_route_map_mark_update(rmap_name);
+ route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
+}
+
+static void
+zebra_route_map_delete (const char *rmap_name)
+{
+ zebra_route_map_mark_update(rmap_name);
+ route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_DELETED);
+}
+
+static void
+zebra_route_map_event (route_map_event_t event, const char *rmap_name)
+{
+ zebra_route_map_mark_update(rmap_name);
+ route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
+}
+
+/* ip protocol configuration write function */
+static int config_write_protocol(struct vty *vty)
+{
+ int i;
+
+ for (i=0;i<ZEBRA_ROUTE_MAX;i++)
+ {
+ if (proto_rm[AFI_IP][i])
+ vty_out (vty, "ip protocol %s route-map %s%s", zebra_route_string(i),
+ proto_rm[AFI_IP][i], VTY_NEWLINE);
+
+ if (nht_rm[AFI_IP][i])
+ vty_out (vty, "ip nht %s route-map %s%s", zebra_route_string(i),
+ nht_rm[AFI_IP][i], VTY_NEWLINE);
+
+ if (nht_rm[AFI_IP6][i])
+ vty_out (vty, "ipv6 nht %s route-map %s%s", zebra_route_string(i),
+ nht_rm[AFI_IP6][i], VTY_NEWLINE);
+ }
+
+ if (proto_rm[AFI_IP][ZEBRA_ROUTE_MAX])
+ vty_out (vty, "ip protocol %s route-map %s%s", "any",
+ proto_rm[AFI_IP][ZEBRA_ROUTE_MAX], VTY_NEWLINE);
+
+ if (nht_rm[AFI_IP][ZEBRA_ROUTE_MAX])
+ vty_out (vty, "ip nht %s route-map %s%s", "any",
+ nht_rm[AFI_IP][ZEBRA_ROUTE_MAX], VTY_NEWLINE);
+
+ if (nht_rm[AFI_IP6][ZEBRA_ROUTE_MAX])
+ vty_out (vty, "ipv6 nht %s route-map %s%s", "any",
+ nht_rm[AFI_IP6][ZEBRA_ROUTE_MAX], VTY_NEWLINE);
+
+ if (zebra_rmap_update_timer != ZEBRA_RMAP_DEFAULT_UPDATE_TIMER)
+ vty_out (vty, "zebra route-map delay-timer %d%s", zebra_rmap_update_timer,
+ VTY_NEWLINE);
+ return 1;
+}
+/* table node for protocol filtering */
+static struct cmd_node protocol_node = { PROTOCOL_NODE, "", 1 };
+
void
zebra_route_map_init ()
{
+ install_node (&protocol_node, config_write_protocol);
+ install_element (CONFIG_NODE, &ip_protocol_cmd);
+ install_element (CONFIG_NODE, &no_ip_protocol_cmd);
+ install_element (CONFIG_NODE, &no_ip_protocol_val_cmd);
+ install_element (VIEW_NODE, &show_ip_protocol_cmd);
+ install_element (ENABLE_NODE, &show_ip_protocol_cmd);
+ install_element (CONFIG_NODE, &ip_protocol_nht_rmap_cmd);
+ install_element (CONFIG_NODE, &no_ip_protocol_nht_rmap_cmd);
+ install_element (CONFIG_NODE, &no_ip_protocol_nht_rmap_val_cmd);
+ install_element (VIEW_NODE, &show_ip_protocol_nht_cmd);
+ install_element (ENABLE_NODE, &show_ip_protocol_nht_cmd);
+ install_element (CONFIG_NODE, &ipv6_protocol_nht_rmap_cmd);
+ install_element (CONFIG_NODE, &no_ipv6_protocol_nht_rmap_cmd);
+ install_element (ENABLE_NODE, &no_ipv6_protocol_nht_rmap_val_cmd);
+ install_element (VIEW_NODE, &show_ipv6_protocol_nht_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_protocol_nht_cmd);
+ install_element (CONFIG_NODE, &zebra_route_map_timer_cmd);
+ install_element (CONFIG_NODE, &no_zebra_route_map_timer_cmd);
+
route_map_init ();
route_map_init_vty ();
+ route_map_add_hook (zebra_route_map_add);
+ route_map_delete_hook (zebra_route_map_delete);
+ route_map_event_hook (zebra_route_map_event);
+
route_map_install_match (&route_match_interface_cmd);
route_map_install_match (&route_match_ip_next_hop_cmd);
route_map_install_match (&route_match_ip_next_hop_prefix_list_cmd);
route_map_install_match (&route_match_ip_address_cmd);
route_map_install_match (&route_match_ip_address_prefix_list_cmd);
+ route_map_install_match (&route_match_ip_address_prefix_len_cmd);
+ route_map_install_match (&route_match_ip_nexthop_prefix_len_cmd);
+ route_map_install_match (&route_match_source_protocol_cmd);
/* */
route_map_install_set (&route_set_src_cmd);
/* */
@@ -704,7 +1563,15 @@ zebra_route_map_init ()
install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd);
install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd);
install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd);
-/* */
+ install_element (RMAP_NODE, &match_ip_nexthop_prefix_len_cmd);
+ install_element (RMAP_NODE, &no_match_ip_nexthop_prefix_len_cmd);
+ install_element (RMAP_NODE, &no_match_ip_nexthop_prefix_len_val_cmd);
+ install_element (RMAP_NODE, &match_ip_address_prefix_len_cmd);
+ install_element (RMAP_NODE, &no_match_ip_address_prefix_len_cmd);
+ install_element (RMAP_NODE, &no_match_ip_address_prefix_len_val_cmd);
+ install_element (RMAP_NODE, &match_source_protocol_cmd);
+ install_element (RMAP_NODE, &no_match_source_protocol_cmd);
+ /* */
install_element (RMAP_NODE, &set_src_cmd);
install_element (RMAP_NODE, &no_set_src_cmd);
}