From: Dinesh Dutt <[email protected]> It is sometimes useful to restrict the resolution of recursive routes to only specific via's. For example, in some configurations resolving a route through a default route is not acceptable.
This patch adds a new route-map attach point, to zebra's next-hop-tracking server. Whenever NHT is considering sending notification of a route resolution, it applies a specified route-map and only if it passes, is the NHT reachable message sent to the appropriate client protocol (BGP, OSPF etc.). If the route-map filters the resolution, then a withdraw is sent to the client protocol. The route-map is sent the ip address of the route via which the resolution is happening as well as the valid NHs associated with that route. We also add support for matching on IP addr prefix len and source protocol to ensure that resolution happens only via a very specific route. Signed-off-by: Dinesh Dutt <[email protected]> Signed-off-by: Donald Sharp <[email protected]> --- lib/route_types.pl | 23 +- zebra/rib.h | 9 - zebra/zebra_rib.c | 6 +- zebra/zebra_rnh.c | 96 ++++++-- zebra/zebra_rnh.h | 3 +- zebra/zebra_rnh_null.c | 2 +- zebra/zebra_routemap.c | 655 ++++++++++++++++++++++++++++++++++++++++++++++--- zebra/zserv.c | 4 +- zebra/zserv.h | 8 +- 9 files changed, 723 insertions(+), 83 deletions(-) mode change 100755 => 100644 lib/route_types.pl diff --git a/lib/route_types.pl b/lib/route_types.pl old mode 100755 new mode 100644 index e1595af..1e2f20c --- a/lib/route_types.pl +++ b/lib/route_types.pl @@ -89,7 +89,7 @@ printf <<EOF, $ARGV[0]; #ifndef _QUAGGA_ROUTE_TYPES_H #define _QUAGGA_ROUTE_TYPES_H -/* Zebra route's types. */ +/* Zebra route's' types. */ EOF push @protos, "ZEBRA_ROUTE_MAX"; @@ -133,7 +133,7 @@ printf "#define SHOW_ROUTE_V6_HEADER \\\n%s\n", codelist(@protosv6); print "\n"; sub collect { - my ($daemon, $ipv4, $ipv6) = @_; + my ($daemon, $ipv4, $ipv6, $any) = @_; my (@names, @help) = ((), ()); for my $p (@protos) { next if ($protodetail{$p}->{"daemon"} eq $daemon && $daemon ne "zebra"); @@ -142,6 +142,10 @@ sub collect { push @names, $protodetail{$p}->{"cname"}; push @help, " \"".$protodetail{$p}->{"longhelp"}."\\n\""; } + if ($any == 1) { + push @names, "any"; + push @help, " \"Any of the above protocols\\n\""; + } return ("\"(" . join("|", @names) . ")\"", join(" \\\n", @help)); } @@ -149,18 +153,25 @@ for my $daemon (sort keys %daemons) { next unless ($daemons{$daemon}->{"ipv4"} || $daemons{$daemon}->{"ipv6"}); printf "/* %s */\n", $daemon; if ($daemons{$daemon}->{"ipv4"} && $daemons{$daemon}->{"ipv6"}) { - my ($names, $help) = collect($daemon, 1, 1); + my ($names, $help) = collect($daemon, 1, 1, 0); printf "#define QUAGGA_REDIST_STR_%s \\\n %s\n", uc $daemon, $names; printf "#define QUAGGA_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help; - ($names, $help) = collect($daemon, 1, 0); + ($names, $help) = collect($daemon, 1, 0, 0); printf "#define QUAGGA_IP_REDIST_STR_%s \\\n %s\n", uc $daemon, $names; printf "#define QUAGGA_IP_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help; - ($names, $help) = collect($daemon, 0, 1); + ($names, $help) = collect($daemon, 0, 1, 0); printf "#define QUAGGA_IP6_REDIST_STR_%s \\\n %s\n", uc $daemon, $names; printf "#define QUAGGA_IP6_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help; + ($names, $help) = collect($daemon, 0, 1, 1); + if ($daemon eq "zebra") { + printf "#define QUAGGA_IP_PROTOCOL_MAP_STR_%s \\\n %s\n", uc $daemon, $names; + printf "#define QUAGGA_IP_PROTOCOL_MAP_HELP_STR_%s \\\n%s\n", uc $daemon, $help; + printf "#define QUAGGA_IP6_PROTOCOL_MAP_STR_%s \\\n %s\n", uc $daemon, $names; + printf "#define QUAGGA_IP6_PROTOCOL_MAP_HELP_STR_%s \\\n%s\n", uc $daemon, $help; + } } else { my ($names, $help) = collect($daemon, - $daemons{$daemon}->{"ipv4"}, $daemons{$daemon}->{"ipv6"}); + $daemons{$daemon}->{"ipv4"}, $daemons{$daemon}->{"ipv6"}, 0); printf "#define QUAGGA_REDIST_STR_%s \\\n %s\n", uc $daemon, $names; printf "#define QUAGGA_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help; } diff --git a/zebra/rib.h b/zebra/rib.h index c8bc46d..94c7d1f 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -250,15 +250,6 @@ struct static_route : ((tnexthop) = (nexthop)->next)) \ : (((recursing) = 0),((tnexthop) = (tnexthop)->next))) -/* Structure holding nexthop & VRF identifier, - * used for applying the route-map. */ -struct nexthop_vrfid -{ - struct nexthop *nexthop; - vrf_id_t vrf_id; -}; - - #if defined (HAVE_RTADV) /* Structure which hold status of router advertisement. */ struct rtadv diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 734d57c..474b13c 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -989,7 +989,7 @@ nexthop_active_check (struct route_node *rn, struct rib *rib, if (!family) family = info->afi; - ret = zebra_route_map_check(family, rib->type, &rn->p, nexthop); + ret = zebra_route_map_check(family, rib->type, &rn->p, nexthop, rib->vrf_id); if (ret == RMAP_DENYMATCH) { if (IS_ZEBRA_DEBUG_RIB) @@ -1438,9 +1438,9 @@ process_subq (struct list * subq, u_char qindex) static void meta_queue_process_complete (struct work_queue *dummy) { - zebra_evaluate_rnh_table(0, AF_INET); + zebra_evaluate_rnh_table(0, AF_INET, 0); #ifdef HAVE_IPV6 - zebra_evaluate_rnh_table(0, AF_INET6); + zebra_evaluate_rnh_table(0, AF_INET6, 0); #endif /* HAVE_IPV6 */ } diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 3e02812..5f25307 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -183,7 +183,7 @@ zebra_remove_rnh_client (struct rnh *rnh, struct zserv *client) } int -zebra_evaluate_rnh_table (vrf_id_t vrfid, int family) +zebra_evaluate_rnh_table (vrf_id_t vrfid, int family, int force) { struct route_table *ptable; struct route_table *ntable; @@ -193,6 +193,15 @@ zebra_evaluate_rnh_table (vrf_id_t vrfid, int family) struct zserv *client; struct listnode *node; struct rib *rib; + int rmap_family; /* Route map has diff AF family enum */ + route_map_result_t ret = RMAP_MATCH; + struct nexthop *nexthop; + int state_changed = 0; + int at_least_one = 0; + char bufn[INET6_ADDRSTRLEN]; + char bufp[INET6_ADDRSTRLEN]; + + rmap_family = (family == AF_INET) ? AFI_IP : AFI_IP6; ntable = lookup_rnh_table(vrfid, family); if (!ntable) @@ -213,6 +222,7 @@ zebra_evaluate_rnh_table (vrf_id_t vrfid, int family) if (!nrn->info) continue; + rnh = nrn->info; prn = route_node_match(ptable, &nrn->p); if (!prn) rib = NULL; @@ -227,26 +237,71 @@ zebra_evaluate_rnh_table (vrf_id_t vrfid, int family) } } - rnh = nrn->info; + state_changed = 0; + if (compare_state(rib, rnh->state)) { - if (IS_ZEBRA_DEBUG_NHT) - { - char bufn[INET6_ADDRSTRLEN]; - char bufp[INET6_ADDRSTRLEN]; - prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN); - if (prn) - prefix2str(&prn->p, bufp, INET6_ADDRSTRLEN); - else - strcpy(bufp, "null"); - zlog_debug("rnh %s resolved through route %s - sending " - "nexthop %s event to clients", bufn, bufp, - rib ? "reachable" : "unreachable"); - } copy_state(rnh, rib); - for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) - send_client(rnh, client, vrfid); + state_changed = 1; + } + + if (IS_ZEBRA_DEBUG_NHT && (state_changed || force)) + { + prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN); + if (prn) + prefix2str(&prn->p, bufp, INET6_ADDRSTRLEN); + else + strcpy(bufp, "null"); } + + /* Notify registered clients */ + if (state_changed || force) + for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) + { + rib = rnh->state; + if (prn && rib) + { + at_least_one = 0; + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + { + ret = zebra_nht_route_map_check(rmap_family, client->proto, + &prn->p, rib, nexthop); + if (ret == RMAP_DENYMATCH) + { + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + } + else + { + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + at_least_one++; /* at least one valid NH */ + } + } + if (at_least_one) + rnh->filtered[client->proto] = 0; + else + rnh->filtered[client->proto] = 1; + + if (IS_ZEBRA_DEBUG_NHT && (state_changed || force)) + zlog_debug("%srnh %s resolved through route %s - sending " + "nexthop %s event to clients", + at_least_one ? "":"(filtered)", bufn, bufp, + rib ? "reachable" : "unreachable"); + + send_client(rnh, client, vrfid); /* Route-map passed */ + } + else if (state_changed) + { + if (IS_ZEBRA_DEBUG_NHT && (state_changed || force)) + zlog_debug("rnh %s resolved through route %s - sending " + "nexthop %s event to clients", bufn, bufp, + rib ? "reachable" : "unreachable"); + rnh->filtered[client->proto] = 0; + send_client(rnh, client, vrfid); + /* We don't need to send a RNH update on force since no + * update really happened, just a route-map change. + */ + } + } } return 1; } @@ -490,7 +545,8 @@ send_client (struct rnh *rnh, struct zserv *client, vrf_id_t vrf_id) nump = stream_get_endp(s); stream_putc (s, 0); for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) - if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) && + CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) { stream_putc (s, nexthop->type); switch (nexthop->type) @@ -597,7 +653,7 @@ print_rnh (struct route_node *rn, struct vty *vty) vty_out(vty, " Client list:"); for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) - vty_out(vty, " %s(fd %d)", zebra_route_string(client->proto), - client->sock); + vty_out(vty, " %s(fd %d)%s", zebra_route_string(client->proto), + client->sock, rnh->filtered[client->proto] ? "(filtered)" : ""); vty_out(vty, "%s", VTY_NEWLINE); } diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h index 97dbba7..e034c4d 100644 --- a/zebra/zebra_rnh.h +++ b/zebra/zebra_rnh.h @@ -33,6 +33,7 @@ struct rnh struct rib *state; struct list *client_list; struct route_node *node; + int filtered[ZEBRA_ROUTE_MAX]; /* if this has been filtered for client */ }; extern struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid); @@ -40,7 +41,7 @@ extern struct rnh *zebra_lookup_rnh(struct prefix *p, vrf_id_t vrfid); extern void zebra_delete_rnh(struct rnh *rnh); extern void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client, vrf_id_t vrf_id_t); extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client); -extern int zebra_evaluate_rnh_table(vrf_id_t vrfid, int family); +extern int zebra_evaluate_rnh_table(vrf_id_t vrfid, int family, int force); extern int zebra_dispatch_rnh_table(vrf_id_t vrfid, int family, struct zserv *cl); extern void zebra_print_rnh_table(vrf_id_t vrfid, int family, struct vty *vty); extern char *rnh_str(struct rnh *rnh, char *buf, int size); diff --git a/zebra/zebra_rnh_null.c b/zebra/zebra_rnh_null.c index 4e3eb46..f45cba3 100644 --- a/zebra/zebra_rnh_null.c +++ b/zebra/zebra_rnh_null.c @@ -5,7 +5,7 @@ #include "zebra/zserv.h" #include "zebra/zebra_rnh.h" -int zebra_evaluate_rnh_table (vrf_id_t vrfid, int family) +int zebra_evaluate_rnh_table (vrf_id_t vrfid, int family, int force) { return 0; } void zebra_print_rnh_table (vrf_id_t vrfid, int family, struct vty *vty) diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index 192c818..e0b6e3e 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -33,14 +33,24 @@ #include "zebra/zserv.h" #include "zebra/debug.h" - -void zebra_route_map_set_delay_timer(u_int32_t value); +#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 @@ -171,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; unsigned int ifindex; @@ -180,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) @@ -226,7 +236,7 @@ DEFUN (match_interface, "Interface name\n") { return zebra_route_match_add (vty, vty->index, "interface", argv[0], - RMAP_EVENT_FILTER_ADDED); + RMAP_EVENT_MATCH_ADDED); } DEFUN (no_match_interface, @@ -416,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, @@ -472,11 +605,8 @@ ALIAS (no_set_src, 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\n" - "processed. 0 means disable event driven\n" - "route-map updates. Set this to a larger\n" - "value than protocol route-map delay timer\n" - "to avoid unnecessary churn in routing tables\n") + "Time to wait before route-map updates are processed\n" + "0 means event-driven updates are disabled\n") { u_int32_t rmap_delay_timer; @@ -490,6 +620,7 @@ 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); @@ -499,10 +630,10 @@ DEFUN (no_zebra_route_map_timer, DEFUN (ip_protocol, ip_protocol_cmd, - "ip protocol PROTO route-map ROUTE-MAP", - NO_STR - "Apply route map to PROTO\n" - "Protocol name\n" + "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; @@ -531,10 +662,12 @@ DEFUN (ip_protocol, DEFUN (no_ip_protocol, no_ip_protocol_cmd, - "no ip protocol PROTO", + "no ip protocol " QUAGGA_IP_PROTOCOL_MAP_STR_ZEBRA, NO_STR - "Remove route map from PROTO\n" - "Protocol name\n") + 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; @@ -551,12 +684,25 @@ DEFUN (no_ip_protocol, if (!proto_rm[AFI_IP][i]) return CMD_SUCCESS; - XFREE (MTYPE_ROUTE_MAP_NAME, proto_rm[AFI_IP][i]); - proto_rm[AFI_IP][i] = NULL; - rib_update(VRF_DEFAULT); + 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", @@ -586,6 +732,210 @@ DEFUN (show_ip_protocol, 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' */ @@ -596,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 */ @@ -611,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: @@ -658,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 */ @@ -673,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: @@ -796,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. */ @@ -803,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->src = *(union g_addr *)rule; } return RMAP_OKAY; } @@ -857,11 +1361,13 @@ zebra_route_map_update_timer (struct thread *thread) 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; + return (0); } -void +static void zebra_route_map_set_delay_timer(u_int32_t value) { zebra_rmap_update_timer = value; @@ -885,17 +1391,47 @@ zebra_route_map_write_delay_timer (struct vty *vty) route_map_result_t zebra_route_map_check (int family, int rib_type, struct prefix *p, - struct nexthop *nexthop) + 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, nexthop); + 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); @@ -942,11 +1478,28 @@ static int config_write_protocol(struct vty *vty) 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); @@ -961,8 +1514,19 @@ 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); @@ -978,6 +1542,9 @@ zebra_route_map_init () 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); /* */ @@ -996,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); } diff --git a/zebra/zserv.c b/zebra/zserv.c index a368ba5..15d1bd6 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -851,8 +851,8 @@ zserv_nexthop_register (struct zserv *client, int sock, u_short length, vrf_id_t rnh = zebra_add_rnh(&p, 0); zebra_add_rnh_client(rnh, client, vrf_id); } - zebra_evaluate_rnh_table(0, AF_INET); - zebra_evaluate_rnh_table(0, AF_INET6); + zebra_evaluate_rnh_table(0, AF_INET, 0); + zebra_evaluate_rnh_table(0, AF_INET6, 0); return 0; } diff --git a/zebra/zserv.h b/zebra/zserv.h index 6c0e661..3aee505 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -128,6 +128,12 @@ extern int zebra_server_send_message(struct zserv *client); extern void zebra_route_map_write_delay_timer(struct vty *); extern route_map_result_t zebra_route_map_check (int family, int rib_type, struct prefix *p, - struct nexthop *nexthop); + struct nexthop *nexthop, + vrf_id_t vrf_id); +extern route_map_result_t zebra_nht_route_map_check (int family, + int client_proto, + struct prefix *p, + struct rib *, + struct nexthop *nexthop); #endif /* _ZEBRA_ZEBRA_H */ -- 1.9.1 _______________________________________________ Quagga-dev mailing list [email protected] https://lists.quagga.net/mailman/listinfo/quagga-dev
