]> git.puffer.fish Git - mirror/frr.git/commitdiff
zebra: zebra-nht-routemap.patch
authorDonald Sharp <sharpd@cumulusnetworks.com>
Wed, 20 May 2015 00:47:20 +0000 (17:47 -0700)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Wed, 20 May 2015 00:47:20 +0000 (17:47 -0700)
Zebra: Add route-map support for Next Hop Tracking

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.

lib/route_types.pl [changed mode: 0755->0644]
zebra/zebra_rib.c
zebra/zebra_rnh.c
zebra/zebra_rnh.h
zebra/zebra_rnh_null.c
zebra/zebra_routemap.c
zebra/zserv.c
zebra/zserv.h

old mode 100755 (executable)
new mode 100644 (file)
index e1595af..1e2f20c
@@ -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;
        }
index 7caa793f24fd0f736a6c80d7c58a2fa9574c0f52..ee50ad70306647fa034f3f262e453956729c13ea 100644 (file)
@@ -1456,9 +1456,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 */
 }
 
index 117a2659cb4c9e5418bffc2c483640fda6c3285f..05e10ce73ee9067f13b658e3cbe4a49d0b7d5485 100644 (file)
@@ -183,7 +183,7 @@ zebra_remove_rnh_client (struct rnh *rnh, struct zserv *client)
 }
 
 int
-zebra_evaluate_rnh_table (int vrfid, int family)
+zebra_evaluate_rnh_table (int vrfid, int family, int force)
 {
   struct route_table *ptable;
   struct route_table *ntable;
@@ -193,6 +193,15 @@ zebra_evaluate_rnh_table (int 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 (int 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 (int 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);
+         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); /* 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);
+               /* 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)
       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);
 }
index 212bab602aa781266758dc6970598b7ea6c3049c..0843c0eb56edbe03e954da12f2408fdc365190af 100644 (file)
@@ -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, u_int32_t vrfid);
@@ -40,7 +41,7 @@ extern struct rnh *zebra_lookup_rnh(struct prefix *p, u_int32_t vrfid);
 extern void zebra_delete_rnh(struct rnh *rnh);
 extern void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client);
 extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client);
-extern int zebra_evaluate_rnh_table(int vrfid, int family);
+extern int zebra_evaluate_rnh_table(int vrfid, int family, int force);
 extern int zebra_dispatch_rnh_table(int vrfid, int family, struct zserv *cl);
 extern void zebra_print_rnh_table(int vrfid, int family, struct vty *vty);
 extern char *rnh_str(struct rnh *rnh, char *buf, int size);
index 68b58ce3eba46ad7160230f86a9d93967a5c8cee..40f0c87288dd98990ea49393c677d3326fb05e81 100644 (file)
@@ -3,7 +3,7 @@
 #include "zebra/zserv.h"
 #include "zebra/zebra_rnh.h"
 
-int zebra_evaluate_rnh_table (int vrfid, int family)
+int zebra_evaluate_rnh_table (int vrfid, int family, int force)
 { return 0; }
 
 void zebra_print_rnh_table (int vrfid, int family, struct vty *vty)
index 045ee6a697dc39f64f09faeda04257cb89c5df84..d5e1bf18bbbbdd663d1cbd0b2493fa028a346c45 100644 (file)
 
 #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;
+  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
@@ -168,7 +179,7 @@ static route_map_result_t
 route_match_interface (void *rule, struct prefix *prefix,
                       route_map_object_t type, void *object)
 {
-  struct nexthop *nexthop;
+  struct nh_rmap_obj *nh_data;
   char *ifname = rule;
   unsigned int ifindex;
 
@@ -179,10 +190,10 @@ route_match_interface (void *rule, struct prefix *prefix,
       ifindex = ifname2ifindex(ifname);
       if (ifindex == 0)
        return RMAP_NOMATCH;
-      nexthop = object;
-      if (!nexthop)
+      nh_data = object;
+      if (!nh_data || !nh_data->nexthop)
        return RMAP_NOMATCH;
-      if (nexthop->ifindex == ifindex)
+      if (nh_data->nexthop->ifindex == ifindex)
        return RMAP_MATCH;
     }
   return RMAP_NOMATCH;
@@ -219,7 +230,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,
@@ -409,6 +420,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,
@@ -460,11 +594,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;
 
@@ -478,6 +609,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);
@@ -487,10 +619,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;
@@ -519,10 +651,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;
 
@@ -539,12 +673,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();
+  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();
+    }
   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",
@@ -574,6 +721,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' */
@@ -584,13 +935,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 */
@@ -599,7 +953,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:
@@ -646,13 +1000,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 */
@@ -661,7 +1018,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:
@@ -784,6 +1141,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. */
@@ -791,12 +1296,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;
 }
@@ -845,9 +1350,13 @@ zebra_route_map_update_timer (struct thread *thread)
     zlog_debug("Event driven route-map update triggered");
 
   rib_update();
+  zebra_evaluate_rnh_table(0, AF_INET, 1);
+  zebra_evaluate_rnh_table(0, AF_INET6, 1);
+
+  return (0);
 }
 
-void
+static void
 zebra_route_map_set_delay_timer(u_int32_t value)
 {
   zebra_rmap_update_timer = value;
@@ -875,20 +1384,48 @@ zebra_route_map_check (int family, int rib_type, struct prefix *p,
 {
   struct route_map *rmap = NULL;
   route_map_result_t ret = RMAP_MATCH;
+  struct nh_rmap_obj nh_obj;
+
+  nh_obj.nexthop = nexthop;
+  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.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 (char *rmap_name)
+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)
@@ -928,11 +1465,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);
@@ -947,8 +1501,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);
 
@@ -964,6 +1529,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);
 /* */
@@ -982,7 +1550,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);
 }
index 471e2c668c051740c8b3df417030b33f6e879f9d..69efcc00409997d64edd94196826ce2ccc364073 100644 (file)
@@ -772,8 +772,8 @@ zserv_nexthop_register (struct zserv *client, int sock, u_short length)
       rnh = zebra_add_rnh(&p, 0);
       zebra_add_rnh_client(rnh, client);
     }
-  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;
 }
 
index 58fcf31ad279953fc3ee62be179afe55d2ed5122..c5236367f4e64d7566e9fc4d55ffbc1313b61dc8 100644 (file)
@@ -126,5 +126,10 @@ 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);
+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 */