LCOV - code coverage report
Current view: top level - lib - routemap.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 176 517 34.0 %
Date: 2015-11-19 Functions: 21 47 44.7 %

          Line data    Source code
       1             : /* Route map function.
       2             :    Copyright (C) 1998, 1999 Kunihiro Ishiguro
       3             : 
       4             : This file is part of GNU Zebra.
       5             : 
       6             : GNU Zebra is free software; you can redistribute it and/or modify it
       7             : under the terms of the GNU General Public License as published by the
       8             : Free Software Foundation; either version 2, or (at your option) any
       9             : later version.
      10             : 
      11             : GNU Zebra is distributed in the hope that it will be useful, but
      12             : WITHOUT ANY WARRANTY; without even the implied warranty of
      13             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             : General Public License for more details.
      15             : 
      16             : You should have received a copy of the GNU General Public License
      17             : along with GNU Zebra; see the file COPYING.  If not, write to the Free
      18             : Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
      19             : 02111-1307, USA.  */
      20             : 
      21             : #include <zebra.h>
      22             : 
      23             : #include "linklist.h"
      24             : #include "memory.h"
      25             : #include "vector.h"
      26             : #include "prefix.h"
      27             : #include "routemap.h"
      28             : #include "command.h"
      29             : #include "vty.h"
      30             : #include "log.h"
      31             : 
      32             : /* Vector for route match rules. */
      33             : static vector route_match_vec;
      34             : 
      35             : /* Vector for route set rules. */
      36             : static vector route_set_vec;
      37             : 
      38             : /* Route map rule. This rule has both `match' rule and `set' rule. */
      39             : struct route_map_rule
      40             : {
      41             :   /* Rule type. */
      42             :   struct route_map_rule_cmd *cmd;
      43             : 
      44             :   /* For pretty printing. */
      45             :   char *rule_str;
      46             : 
      47             :   /* Pre-compiled match rule. */
      48             :   void *value;
      49             : 
      50             :   /* Linked list. */
      51             :   struct route_map_rule *next;
      52             :   struct route_map_rule *prev;
      53             : };
      54             : 
      55             : /* Making route map list. */
      56             : struct route_map_list
      57             : {
      58             :   struct route_map *head;
      59             :   struct route_map *tail;
      60             : 
      61             :   void (*add_hook) (const char *);
      62             :   void (*delete_hook) (const char *);
      63             :   void (*event_hook) (route_map_event_t, const char *); 
      64             : };
      65             : 
      66             : /* Master list of route map. */
      67             : static struct route_map_list route_map_master = { NULL, NULL, NULL, NULL };
      68             : 
      69             : static void
      70             : route_map_rule_delete (struct route_map_rule_list *,
      71             :                        struct route_map_rule *);
      72             : 
      73             : static void
      74             : route_map_index_delete (struct route_map_index *, int);
      75             : 
      76             : /* New route map allocation. Please note route map's name must be
      77             :    specified. */
      78             : static struct route_map *
      79          13 : route_map_new (const char *name)
      80             : {
      81             :   struct route_map *new;
      82             : 
      83          13 :   new =  XCALLOC (MTYPE_ROUTE_MAP, sizeof (struct route_map));
      84          13 :   new->name = XSTRDUP (MTYPE_ROUTE_MAP_NAME, name);
      85          13 :   return new;
      86             : }
      87             : 
      88             : /* Add new name to route_map. */
      89             : static struct route_map *
      90          13 : route_map_add (const char *name)
      91             : {
      92             :   struct route_map *map;
      93             :   struct route_map_list *list;
      94             : 
      95          13 :   map = route_map_new (name);
      96          13 :   list = &route_map_master;
      97             :     
      98          13 :   map->next = NULL;
      99          13 :   map->prev = list->tail;
     100          13 :   if (list->tail)
     101           0 :     list->tail->next = map;
     102             :   else
     103          13 :     list->head = map;
     104          13 :   list->tail = map;
     105             : 
     106             :   /* Execute hook. */
     107          13 :   if (route_map_master.add_hook)
     108           0 :     (*route_map_master.add_hook) (name);
     109             : 
     110          13 :   return map;
     111             : }
     112             : 
     113             : /* Route map delete from list. */
     114             : static void
     115           0 : route_map_delete (struct route_map *map)
     116             : {
     117             :   struct route_map_list *list;
     118             :   struct route_map_index *index;
     119             :   char *name;
     120             :   
     121           0 :   while ((index = map->head) != NULL)
     122           0 :     route_map_index_delete (index, 0);
     123             : 
     124           0 :   name = map->name;
     125             : 
     126           0 :   list = &route_map_master;
     127             : 
     128           0 :   if (map->next)
     129           0 :     map->next->prev = map->prev;
     130             :   else
     131           0 :     list->tail = map->prev;
     132             : 
     133           0 :   if (map->prev)
     134           0 :     map->prev->next = map->next;
     135             :   else
     136           0 :     list->head = map->next;
     137             : 
     138           0 :   XFREE (MTYPE_ROUTE_MAP, map);
     139             : 
     140             :   /* Execute deletion hook. */
     141           0 :   if (route_map_master.delete_hook)
     142           0 :     (*route_map_master.delete_hook) (name);
     143             : 
     144           0 :   if (name)
     145           0 :     XFREE (MTYPE_ROUTE_MAP_NAME, name);
     146             : 
     147           0 : }
     148             : 
     149             : /* Lookup route map by route map name string. */
     150             : struct route_map *
     151          81 : route_map_lookup_by_name (const char *name)
     152             : {
     153             :   struct route_map *map;
     154             : 
     155          81 :   for (map = route_map_master.head; map; map = map->next)
     156          68 :     if (strcmp (map->name, name) == 0)
     157          68 :       return map;
     158          13 :   return NULL;
     159             : }
     160             : 
     161             : /* Lookup route map.  If there isn't route map create one and return
     162             :    it. */
     163             : static struct route_map *
     164          20 : route_map_get (const char *name)
     165             : {
     166             :   struct route_map *map;
     167             : 
     168          20 :   map = route_map_lookup_by_name (name);
     169          20 :   if (map == NULL)
     170          13 :     map = route_map_add (name);
     171          20 :   return map;
     172             : }
     173             : 
     174             : /* Return route map's type string. */
     175             : static const char *
     176           0 : route_map_type_str (enum route_map_type type)
     177             : {
     178           0 :   switch (type)
     179             :     {
     180             :     case RMAP_PERMIT:
     181           0 :       return "permit";
     182             :       break;
     183             :     case RMAP_DENY:
     184           0 :       return "deny";
     185             :       break;
     186             :     default:
     187           0 :       return "";
     188             :       break;
     189             :     }
     190             : }
     191             : 
     192             : static int
     193           0 : route_map_empty (struct route_map *map)
     194             : {
     195           0 :   if (map->head == NULL && map->tail == NULL)
     196           0 :     return 1;
     197             :   else
     198           0 :     return 0;
     199             : }
     200             : 
     201             : /* show route-map */
     202             : static void
     203           0 : vty_show_route_map_entry (struct vty *vty, struct route_map *map)
     204             : {
     205             :   struct route_map_index *index;
     206             :   struct route_map_rule *rule;
     207             : 
     208             :   /* Print the name of the protocol */
     209           0 :   if (zlog_default)
     210           0 :     vty_out (vty, "%s:%s", zlog_proto_names[zlog_default->protocol],
     211           0 :              VTY_NEWLINE);
     212             : 
     213           0 :   for (index = map->head; index; index = index->next)
     214             :     {
     215           0 :       vty_out (vty, "route-map %s, %s, sequence %d%s",
     216             :                map->name, route_map_type_str (index->type),
     217           0 :                index->pref, VTY_NEWLINE);
     218             : 
     219             :       /* Description */
     220           0 :       if (index->description)
     221           0 :         vty_out (vty, "  Description:%s    %s%s", VTY_NEWLINE,
     222           0 :                  index->description, VTY_NEWLINE);
     223             :       
     224             :       /* Match clauses */
     225           0 :       vty_out (vty, "  Match clauses:%s", VTY_NEWLINE);
     226           0 :       for (rule = index->match_list.head; rule; rule = rule->next)
     227           0 :         vty_out (vty, "    %s %s%s", 
     228           0 :                  rule->cmd->str, rule->rule_str, VTY_NEWLINE);
     229             :       
     230           0 :       vty_out (vty, "  Set clauses:%s", VTY_NEWLINE);
     231           0 :       for (rule = index->set_list.head; rule; rule = rule->next)
     232           0 :         vty_out (vty, "    %s %s%s",
     233           0 :                  rule->cmd->str, rule->rule_str, VTY_NEWLINE);
     234             :       
     235             :       /* Call clause */
     236           0 :       vty_out (vty, "  Call clause:%s", VTY_NEWLINE);
     237           0 :       if (index->nextrm)
     238           0 :         vty_out (vty, "    Call %s%s", index->nextrm, VTY_NEWLINE);
     239             :       
     240             :       /* Exit Policy */
     241           0 :       vty_out (vty, "  Action:%s", VTY_NEWLINE);
     242           0 :       if (index->exitpolicy == RMAP_GOTO)
     243           0 :         vty_out (vty, "    Goto %d%s", index->nextpref, VTY_NEWLINE);
     244           0 :       else if (index->exitpolicy == RMAP_NEXT)
     245           0 :         vty_out (vty, "    Continue to next entry%s", VTY_NEWLINE);
     246           0 :       else if (index->exitpolicy == RMAP_EXIT)
     247           0 :         vty_out (vty, "    Exit routemap%s", VTY_NEWLINE);
     248             :     }
     249           0 : }
     250             : 
     251             : static int
     252           0 : vty_show_route_map (struct vty *vty, const char *name)
     253             : {
     254             :   struct route_map *map;
     255             : 
     256           0 :   if (name)
     257             :     {
     258           0 :       map = route_map_lookup_by_name (name);
     259             : 
     260           0 :       if (map)
     261             :         {
     262           0 :           vty_show_route_map_entry (vty, map);
     263           0 :           return CMD_SUCCESS;
     264             :         }
     265             :       else
     266             :         {
     267           0 :           vty_out (vty, "%%route-map %s not found%s", name, VTY_NEWLINE);
     268           0 :           return CMD_WARNING;
     269             :         }
     270             :     }
     271             :   else
     272             :     {
     273           0 :       for (map = route_map_master.head; map; map = map->next)
     274           0 :         vty_show_route_map_entry (vty, map);
     275             :     }
     276           0 :   return CMD_SUCCESS;
     277             : }
     278             : 
     279             : 
     280             : /* New route map allocation. Please note route map's name must be
     281             :    specified. */
     282             : static struct route_map_index *
     283          20 : route_map_index_new (void)
     284             : {
     285             :   struct route_map_index *new;
     286             : 
     287          20 :   new =  XCALLOC (MTYPE_ROUTE_MAP_INDEX, sizeof (struct route_map_index));
     288          20 :   new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */
     289          20 :   return new;
     290             : }
     291             : 
     292             : /* Free route map index. */
     293             : static void
     294           0 : route_map_index_delete (struct route_map_index *index, int notify)
     295             : {
     296             :   struct route_map_rule *rule;
     297             : 
     298             :   /* Free route match. */
     299           0 :   while ((rule = index->match_list.head) != NULL)
     300           0 :     route_map_rule_delete (&index->match_list, rule);
     301             : 
     302             :   /* Free route set. */
     303           0 :   while ((rule = index->set_list.head) != NULL)
     304           0 :     route_map_rule_delete (&index->set_list, rule);
     305             : 
     306             :   /* Remove index from route map list. */
     307           0 :   if (index->next)
     308           0 :     index->next->prev = index->prev;
     309             :   else
     310           0 :     index->map->tail = index->prev;
     311             : 
     312           0 :   if (index->prev)
     313           0 :     index->prev->next = index->next;
     314             :   else
     315           0 :     index->map->head = index->next;
     316             : 
     317             :   /* Free 'char *nextrm' if not NULL */
     318           0 :   if (index->nextrm)
     319           0 :     XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
     320             : 
     321             :     /* Execute event hook. */
     322           0 :   if (route_map_master.event_hook && notify)
     323           0 :     (*route_map_master.event_hook) (RMAP_EVENT_INDEX_DELETED,
     324           0 :                                     index->map->name);
     325             : 
     326           0 :   XFREE (MTYPE_ROUTE_MAP_INDEX, index);
     327           0 : }
     328             : 
     329             : /* Lookup index from route map. */
     330             : static struct route_map_index *
     331          20 : route_map_index_lookup (struct route_map *map, enum route_map_type type,
     332             :                         int pref)
     333             : {
     334             :   struct route_map_index *index;
     335             : 
     336          27 :   for (index = map->head; index; index = index->next)
     337           7 :     if ((index->type == type || type == RMAP_ANY)
     338           7 :         && index->pref == pref)
     339           0 :       return index;
     340          20 :   return NULL;
     341             : }
     342             : 
     343             : /* Add new index to route map. */
     344             : static struct route_map_index *
     345          20 : route_map_index_add (struct route_map *map, enum route_map_type type,
     346             :                      int pref)
     347             : {
     348             :   struct route_map_index *index;
     349             :   struct route_map_index *point;
     350             : 
     351             :   /* Allocate new route map inex. */
     352          20 :   index = route_map_index_new ();
     353          20 :   index->map = map;
     354          20 :   index->type = type;
     355          20 :   index->pref = pref;
     356             :   
     357             :   /* Compare preference. */
     358          27 :   for (point = map->head; point; point = point->next)
     359           7 :     if (point->pref >= pref)
     360           0 :       break;
     361             : 
     362          20 :   if (map->head == NULL)
     363             :     {
     364          13 :       map->head = map->tail = index;
     365             :     }
     366           7 :   else if (point == NULL)
     367             :     {
     368           7 :       index->prev = map->tail;
     369           7 :       map->tail->next = index;
     370           7 :       map->tail = index;
     371             :     }
     372           0 :   else if (point == map->head)
     373             :     {
     374           0 :       index->next = map->head;
     375           0 :       map->head->prev = index;
     376           0 :       map->head = index;
     377             :     }
     378             :   else
     379             :     {
     380           0 :       index->next = point;
     381           0 :       index->prev = point->prev;
     382           0 :       if (point->prev)
     383           0 :         point->prev->next = index;
     384           0 :       point->prev = index;
     385             :     }
     386             : 
     387             :   /* Execute event hook. */
     388          20 :   if (route_map_master.event_hook)
     389           0 :     (*route_map_master.event_hook) (RMAP_EVENT_INDEX_ADDED,
     390           0 :                                     map->name);
     391             : 
     392          20 :   return index;
     393             : }
     394             : 
     395             : /* Get route map index. */
     396             : static struct route_map_index *
     397          20 : route_map_index_get (struct route_map *map, enum route_map_type type, 
     398             :                      int pref)
     399             : {
     400             :   struct route_map_index *index;
     401             : 
     402          20 :   index = route_map_index_lookup (map, RMAP_ANY, pref);
     403          20 :   if (index && index->type != type)
     404             :     {
     405             :       /* Delete index from route map. */
     406           0 :       route_map_index_delete (index, 1);
     407           0 :       index = NULL;
     408             :     }
     409          20 :   if (index == NULL)
     410          20 :     index = route_map_index_add (map, type, pref);
     411          20 :   return index;
     412             : }
     413             : 
     414             : /* New route map rule */
     415             : static struct route_map_rule *
     416          13 : route_map_rule_new (void)
     417             : {
     418             :   struct route_map_rule *new;
     419             : 
     420          13 :   new = XCALLOC (MTYPE_ROUTE_MAP_RULE, sizeof (struct route_map_rule));
     421          13 :   return new;
     422             : }
     423             : 
     424             : /* Install rule command to the match list. */
     425             : void
     426         225 : route_map_install_match (struct route_map_rule_cmd *cmd)
     427             : {
     428         225 :   vector_set (route_match_vec, cmd);
     429         225 : }
     430             : 
     431             : /* Install rule command to the set list. */
     432             : void
     433          45 : route_map_install_set (struct route_map_rule_cmd *cmd)
     434             : {
     435          45 :   vector_set (route_set_vec, cmd);
     436          45 : }
     437             : 
     438             : /* Lookup rule command from match list. */
     439             : static struct route_map_rule_cmd *
     440           7 : route_map_lookup_match (const char *name)
     441             : {
     442             :   unsigned int i;
     443             :   struct route_map_rule_cmd *rule;
     444             : 
     445          15 :   for (i = 0; i < vector_active (route_match_vec); i++)
     446          15 :     if ((rule = vector_slot (route_match_vec, i)) != NULL)
     447          15 :       if (strcmp (rule->str, name) == 0)
     448           7 :         return rule;
     449           0 :   return NULL;
     450             : }
     451             : 
     452             : /* Lookup rule command from set list. */
     453             : static struct route_map_rule_cmd *
     454           6 : route_map_lookup_set (const char *name)
     455             : {
     456             :   unsigned int i;
     457             :   struct route_map_rule_cmd *rule;
     458             : 
     459           6 :   for (i = 0; i < vector_active (route_set_vec); i++)
     460           6 :     if ((rule = vector_slot (route_set_vec, i)) != NULL)
     461           6 :       if (strcmp (rule->str, name) == 0)
     462           6 :         return rule;
     463           0 :   return NULL;
     464             : }
     465             : 
     466             : /* Add match and set rule to rule list. */
     467             : static void
     468          13 : route_map_rule_add (struct route_map_rule_list *list,
     469             :                     struct route_map_rule *rule)
     470             : {
     471          13 :   rule->next = NULL;
     472          13 :   rule->prev = list->tail;
     473          13 :   if (list->tail)
     474           0 :     list->tail->next = rule;
     475             :   else
     476          13 :     list->head = rule;
     477          13 :   list->tail = rule;
     478          13 : }
     479             : 
     480             : /* Delete rule from rule list. */
     481             : static void
     482           0 : route_map_rule_delete (struct route_map_rule_list *list,
     483             :                        struct route_map_rule *rule)
     484             : {
     485           0 :   if (rule->cmd->func_free)
     486           0 :     (*rule->cmd->func_free) (rule->value);
     487             : 
     488           0 :   if (rule->rule_str)
     489           0 :     XFREE (MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str);
     490             : 
     491           0 :   if (rule->next)
     492           0 :     rule->next->prev = rule->prev;
     493             :   else
     494           0 :     list->tail = rule->prev;
     495           0 :   if (rule->prev)
     496           0 :     rule->prev->next = rule->next;
     497             :   else
     498           0 :     list->head = rule->next;
     499             : 
     500           0 :   XFREE (MTYPE_ROUTE_MAP_RULE, rule);
     501           0 : }
     502             : 
     503             : /* strcmp wrapper function which don't crush even argument is NULL. */
     504             : static int
     505           0 : rulecmp (const char *dst, const char *src)
     506             : {
     507           0 :   if (dst == NULL)
     508             :     {
     509           0 :       if (src ==  NULL)
     510           0 :         return 0;
     511             :       else
     512           0 :         return 1;
     513             :     }
     514             :   else
     515             :     {
     516           0 :       if (src == NULL)
     517           0 :         return 1;
     518             :       else
     519           0 :         return strcmp (dst, src);
     520             :     }
     521             :   return 1;
     522             : }
     523             : 
     524             : /* Add match statement to route map. */
     525             : int
     526           7 : route_map_add_match (struct route_map_index *index, const char *match_name,
     527             :                      const char *match_arg)
     528             : {
     529             :   struct route_map_rule *rule;
     530             :   struct route_map_rule *next;
     531             :   struct route_map_rule_cmd *cmd;
     532             :   void *compile;
     533           7 :   int replaced = 0;
     534             : 
     535             :   /* First lookup rule for add match statement. */
     536           7 :   cmd = route_map_lookup_match (match_name);
     537           7 :   if (cmd == NULL)
     538           0 :     return RMAP_RULE_MISSING;
     539             : 
     540             :   /* Next call compile function for this match statement. */
     541           7 :   if (cmd->func_compile)
     542             :     {
     543           7 :       compile= (*cmd->func_compile)(match_arg);
     544           7 :       if (compile == NULL)
     545           0 :         return RMAP_COMPILE_ERROR;
     546             :     }
     547             :   else
     548           0 :     compile = NULL;
     549             : 
     550             :   /* If argument is completely same ignore it. */
     551           7 :   for (rule = index->match_list.head; rule; rule = next)
     552             :     {
     553           0 :       next = rule->next;
     554           0 :       if (rule->cmd == cmd)
     555             :         {       
     556           0 :           route_map_rule_delete (&index->match_list, rule);
     557           0 :           replaced = 1;
     558             :         }
     559             :     }
     560             : 
     561             :   /* Add new route map match rule. */
     562           7 :   rule = route_map_rule_new ();
     563           7 :   rule->cmd = cmd;
     564           7 :   rule->value = compile;
     565           7 :   if (match_arg)
     566           7 :     rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, match_arg);
     567             :   else
     568           0 :     rule->rule_str = NULL;
     569             : 
     570             :   /* Add new route match rule to linked list. */
     571           7 :   route_map_rule_add (&index->match_list, rule);
     572             : 
     573             :   /* Execute event hook. */
     574           7 :   if (route_map_master.event_hook)
     575           0 :     (*route_map_master.event_hook) (replaced ?
     576             :                                     RMAP_EVENT_MATCH_REPLACED:
     577             :                                     RMAP_EVENT_MATCH_ADDED,
     578           0 :                                     index->map->name);
     579             : 
     580           7 :   return 0;
     581             : }
     582             : 
     583             : /* Delete specified route match rule. */
     584             : int
     585           0 : route_map_delete_match (struct route_map_index *index, const char *match_name,
     586             :                         const char *match_arg)
     587             : {
     588             :   struct route_map_rule *rule;
     589             :   struct route_map_rule_cmd *cmd;
     590             : 
     591           0 :   cmd = route_map_lookup_match (match_name);
     592           0 :   if (cmd == NULL)
     593           0 :     return 1;
     594             :   
     595           0 :   for (rule = index->match_list.head; rule; rule = rule->next)
     596           0 :     if (rule->cmd == cmd && 
     597           0 :         (rulecmp (rule->rule_str, match_arg) == 0 || match_arg == NULL))
     598             :       {
     599           0 :         route_map_rule_delete (&index->match_list, rule);
     600             :         /* Execute event hook. */
     601           0 :         if (route_map_master.event_hook)
     602           0 :           (*route_map_master.event_hook) (RMAP_EVENT_MATCH_DELETED,
     603           0 :                                           index->map->name);
     604           0 :         return 0;
     605             :       }
     606             :   /* Can't find matched rule. */
     607           0 :   return 1;
     608             : }
     609             : 
     610             : /* Add route-map set statement to the route map. */
     611             : int
     612           6 : route_map_add_set (struct route_map_index *index, const char *set_name,
     613             :                    const char *set_arg)
     614             : {
     615             :   struct route_map_rule *rule;
     616             :   struct route_map_rule *next;
     617             :   struct route_map_rule_cmd *cmd;
     618             :   void *compile;
     619           6 :   int replaced = 0;
     620             : 
     621           6 :   cmd = route_map_lookup_set (set_name);
     622           6 :   if (cmd == NULL)
     623           0 :     return RMAP_RULE_MISSING;
     624             : 
     625             :   /* Next call compile function for this match statement. */
     626           6 :   if (cmd->func_compile)
     627             :     {
     628           6 :       compile= (*cmd->func_compile)(set_arg);
     629           6 :       if (compile == NULL)
     630           0 :         return RMAP_COMPILE_ERROR;
     631             :     }
     632             :   else
     633           0 :     compile = NULL;
     634             : 
     635             :  /* Add by WJL. if old set command of same kind exist, delete it first
     636             :     to ensure only one set command of same kind exist under a
     637             :     route_map_index. */
     638           6 :   for (rule = index->set_list.head; rule; rule = next)
     639             :     {
     640           0 :       next = rule->next;
     641           0 :       if (rule->cmd == cmd)
     642             :         {
     643           0 :           route_map_rule_delete (&index->set_list, rule);
     644           0 :           replaced = 1;
     645             :         }
     646             :     }
     647             : 
     648             :   /* Add new route map match rule. */
     649           6 :   rule = route_map_rule_new ();
     650           6 :   rule->cmd = cmd;
     651           6 :   rule->value = compile;
     652           6 :   if (set_arg)
     653           6 :     rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, set_arg);
     654             :   else
     655           0 :     rule->rule_str = NULL;
     656             : 
     657             :   /* Add new route match rule to linked list. */
     658           6 :   route_map_rule_add (&index->set_list, rule);
     659             : 
     660             :   /* Execute event hook. */
     661           6 :   if (route_map_master.event_hook)
     662           0 :     (*route_map_master.event_hook) (replaced ?
     663             :                                     RMAP_EVENT_SET_REPLACED:
     664             :                                     RMAP_EVENT_SET_ADDED,
     665           0 :                                     index->map->name);
     666           6 :   return 0;
     667             : }
     668             : 
     669             : /* Delete route map set rule. */
     670             : int
     671           0 : route_map_delete_set (struct route_map_index *index, const char *set_name,
     672             :                       const char *set_arg)
     673             : {
     674             :   struct route_map_rule *rule;
     675             :   struct route_map_rule_cmd *cmd;
     676             : 
     677           0 :   cmd = route_map_lookup_set (set_name);
     678           0 :   if (cmd == NULL)
     679           0 :     return 1;
     680             :   
     681           0 :   for (rule = index->set_list.head; rule; rule = rule->next)
     682           0 :     if ((rule->cmd == cmd) &&
     683           0 :          (rulecmp (rule->rule_str, set_arg) == 0 || set_arg == NULL))
     684             :       {
     685           0 :         route_map_rule_delete (&index->set_list, rule);
     686             :         /* Execute event hook. */
     687           0 :         if (route_map_master.event_hook)
     688           0 :           (*route_map_master.event_hook) (RMAP_EVENT_SET_DELETED,
     689           0 :                                           index->map->name);
     690           0 :         return 0;
     691             :       }
     692             :   /* Can't find matched rule. */
     693           0 :   return 1;
     694             : }
     695             : 
     696             : /* Apply route map's each index to the object.
     697             : 
     698             :    The matrix for a route-map looks like this:
     699             :    (note, this includes the description for the "NEXT"
     700             :    and "GOTO" frobs now
     701             :   
     702             :               Match   |   No Match
     703             :                       |
     704             :     permit    action  |     cont
     705             :                       |
     706             :     ------------------+---------------
     707             :                       |
     708             :     deny      deny    |     cont
     709             :                       |
     710             :   
     711             :    action)
     712             :       -Apply Set statements, accept route
     713             :       -If Call statement is present jump to the specified route-map, if it
     714             :          denies the route we finish.
     715             :       -If NEXT is specified, goto NEXT statement
     716             :       -If GOTO is specified, goto the first clause where pref > nextpref
     717             :       -If nothing is specified, do as Cisco and finish
     718             :    deny)
     719             :       -Route is denied by route-map.
     720             :    cont)
     721             :       -Goto Next index
     722             :   
     723             :    If we get no matches after we've processed all updates, then the route
     724             :    is dropped too.
     725             :   
     726             :    Some notes on the new "CALL", "NEXT" and "GOTO"
     727             :      call WORD        - If this clause is matched, then the set statements
     728             :                         are executed and then we jump to route-map 'WORD'. If
     729             :                         this route-map denies the route, we finish, in other case we
     730             :                         do whatever the exit policy (EXIT, NEXT or GOTO) tells.
     731             :      on-match next    - If this clause is matched, then the set statements
     732             :                         are executed and then we drop through to the next clause
     733             :      on-match goto n  - If this clause is matched, then the set statments
     734             :                         are executed and then we goto the nth clause, or the
     735             :                         first clause greater than this. In order to ensure
     736             :                         route-maps *always* exit, you cannot jump backwards.
     737             :                         Sorry ;)
     738             :   
     739             :    We need to make sure our route-map processing matches the above
     740             : */
     741             : 
     742             : static route_map_result_t
     743          74 : route_map_apply_match (struct route_map_rule_list *match_list,
     744             :                        struct prefix *prefix, route_map_object_t type,
     745             :                        void *object)
     746             : {
     747          74 :   route_map_result_t ret = RMAP_NOMATCH;
     748             :   struct route_map_rule *match;
     749             : 
     750             : 
     751             :   /* Check all match rule and if there is no match rule, go to the
     752             :      set statement. */
     753          74 :   if (!match_list->head)
     754          40 :     ret = RMAP_MATCH;
     755             :   else
     756             :     {
     757          55 :       for (match = match_list->head; match; match = match->next)
     758             :         {
     759             :           /* Try each match statement in turn, If any do not return
     760             :              RMAP_MATCH, return, otherwise continue on to next match 
     761             :              statement. All match statements must match for end-result
     762             :              to be a match. */
     763          34 :           ret = (*match->cmd->func_apply) (match->value, prefix,
     764             :                                            type, object);
     765          34 :           if (ret != RMAP_MATCH)
     766          13 :             return ret;
     767             :         }
     768             :     }
     769          61 :   return ret;
     770             : }
     771             : 
     772             : /* Apply route map to the object. */
     773             : route_map_result_t
     774          61 : route_map_apply (struct route_map *map, struct prefix *prefix,
     775             :                  route_map_object_t type, void *object)
     776             : {
     777             :   static int recursion = 0;
     778          61 :   int ret = 0;
     779             :   struct route_map_index *index;
     780             :   struct route_map_rule *set;
     781             : 
     782          61 :   if (recursion > RMAP_RECURSION_LIMIT)
     783             :     {
     784           0 :       zlog (NULL, LOG_WARNING,
     785             :             "route-map recursion limit (%d) reached, discarding route",
     786             :             RMAP_RECURSION_LIMIT);
     787           0 :       recursion = 0;
     788           0 :       return RMAP_DENYMATCH;
     789             :     }
     790             : 
     791          61 :   if (map == NULL)
     792           0 :     return RMAP_DENYMATCH;
     793             : 
     794          74 :   for (index = map->head; index; index = index->next)
     795             :     {
     796             :       /* Apply this index. */
     797          74 :       ret = route_map_apply_match (&index->match_list, prefix, type, object);
     798             : 
     799             :       /* Now we apply the matrix from above */
     800          74 :       if (ret == RMAP_NOMATCH)
     801             :         /* 'cont' from matrix - continue to next route-map sequence */
     802          13 :         continue;
     803          61 :       else if (ret == RMAP_MATCH)
     804             :         {
     805          61 :           if (index->type == RMAP_PERMIT)
     806             :             /* 'action' */
     807             :             {
     808             :               /* permit+match must execute sets */
     809          75 :               for (set = index->set_list.head; set; set = set->next)
     810          27 :                 ret = (*set->cmd->func_apply) (set->value, prefix,
     811             :                                                type, object);
     812             : 
     813             :               /* Call another route-map if available */
     814          48 :               if (index->nextrm)
     815             :                 {
     816           0 :                   struct route_map *nextrm =
     817           0 :                                     route_map_lookup_by_name (index->nextrm);
     818             : 
     819           0 :                   if (nextrm) /* Target route-map found, jump to it */
     820             :                     {
     821           0 :                       recursion++;
     822           0 :                       ret = route_map_apply (nextrm, prefix, type, object);
     823           0 :                       recursion--;
     824             :                     }
     825             : 
     826             :                   /* If nextrm returned 'deny', finish. */
     827           0 :                   if (ret == RMAP_DENYMATCH)
     828           0 :                     return ret;
     829             :                 }
     830             :                 
     831          48 :               switch (index->exitpolicy)
     832             :                 {
     833             :                   case RMAP_EXIT:
     834          48 :                     return ret;
     835             :                   case RMAP_NEXT:
     836           0 :                     continue;
     837             :                   case RMAP_GOTO:
     838             :                     {
     839             :                       /* Find the next clause to jump to */
     840           0 :                       struct route_map_index *next = index->next;
     841           0 :                       int nextpref = index->nextpref;
     842             : 
     843           0 :                       while (next && next->pref < nextpref)
     844             :                         {
     845           0 :                           index = next;
     846           0 :                           next = next->next;
     847             :                         }
     848           0 :                       if (next == NULL)
     849             :                         {
     850             :                           /* No clauses match! */
     851           0 :                           return ret;
     852             :                         }
     853             :                     }
     854             :                 }
     855             :             }
     856          13 :           else if (index->type == RMAP_DENY)
     857             :             /* 'deny' */
     858             :             {
     859          13 :                 return RMAP_DENYMATCH;
     860             :             }
     861             :         }
     862             :     }
     863             :   /* Finally route-map does not match at all. */
     864           0 :   return RMAP_DENYMATCH;
     865             : }
     866             : 
     867             : void
     868           0 : route_map_add_hook (void (*func) (const char *))
     869             : {
     870           0 :   route_map_master.add_hook = func;
     871           0 : }
     872             : 
     873             : void
     874           0 : route_map_delete_hook (void (*func) (const char *))
     875             : {
     876           0 :   route_map_master.delete_hook = func;
     877           0 : }
     878             : 
     879             : void
     880           0 : route_map_event_hook (void (*func) (route_map_event_t, const char *))
     881             : {
     882           0 :   route_map_master.event_hook = func;
     883           0 : }
     884             : 
     885             : void
     886          45 : route_map_init (void)
     887             : {
     888             :   /* Make vector for match and set. */
     889          45 :   route_match_vec = vector_init (1);
     890          45 :   route_set_vec = vector_init (1);
     891          45 : }
     892             : 
     893             : void
     894           0 : route_map_finish (void)
     895             : {
     896           0 :   vector_free (route_match_vec);
     897           0 :   route_match_vec = NULL;
     898           0 :   vector_free (route_set_vec);
     899           0 :   route_set_vec = NULL;
     900           0 : }
     901             : 
     902             : /* VTY related functions. */
     903          20 : DEFUN (route_map,
     904             :        route_map_cmd,
     905             :        "route-map WORD (deny|permit) <1-65535>",
     906             :        "Create route-map or enter route-map command mode\n"
     907             :        "Route map tag\n"
     908             :        "Route map denies set operations\n"
     909             :        "Route map permits set operations\n"
     910             :        "Sequence to insert to/delete from existing route-map entry\n")
     911             : {
     912             :   int permit;
     913             :   unsigned long pref;
     914             :   struct route_map *map;
     915             :   struct route_map_index *index;
     916          20 :   char *endptr = NULL;
     917             : 
     918             :   /* Permit check. */
     919          20 :   if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
     920          13 :     permit = RMAP_PERMIT;
     921           7 :   else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
     922           7 :     permit = RMAP_DENY;
     923             :   else
     924             :     {
     925           0 :       vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
     926           0 :       return CMD_WARNING;
     927             :     }
     928             : 
     929             :   /* Preference check. */
     930          20 :   pref = strtoul (argv[2], &endptr, 10);
     931          20 :   if (pref == ULONG_MAX || *endptr != '\0')
     932             :     {
     933           0 :       vty_out (vty, "the fourth field must be positive integer%s",
     934           0 :                VTY_NEWLINE);
     935           0 :       return CMD_WARNING;
     936             :     }
     937          20 :   if (pref == 0 || pref > 65535)
     938             :     {
     939           0 :       vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
     940           0 :       return CMD_WARNING;
     941             :     }
     942             : 
     943             :   /* Get route map. */
     944          20 :   map = route_map_get (argv[0]);
     945          20 :   index = route_map_index_get (map, permit, pref);
     946             : 
     947          20 :   vty->index = index;
     948          20 :   vty->node = RMAP_NODE;
     949          20 :   return CMD_SUCCESS;
     950             : }
     951             : 
     952           0 : DEFUN (no_route_map_all,
     953             :        no_route_map_all_cmd,
     954             :        "no route-map WORD",
     955             :        NO_STR
     956             :        "Create route-map or enter route-map command mode\n"
     957             :        "Route map tag\n")
     958             : {
     959             :   struct route_map *map;
     960             : 
     961           0 :   map = route_map_lookup_by_name (argv[0]);
     962           0 :   if (map == NULL)
     963             :     {
     964           0 :       vty_out (vty, "%% Could not find route-map %s%s",
     965           0 :                argv[0], VTY_NEWLINE);
     966           0 :       return CMD_WARNING;
     967             :     }
     968             : 
     969           0 :   route_map_delete (map);
     970             : 
     971           0 :   return CMD_SUCCESS;
     972             : }
     973             : 
     974           0 : DEFUN (no_route_map,
     975             :        no_route_map_cmd,
     976             :        "no route-map WORD (deny|permit) <1-65535>",
     977             :        NO_STR
     978             :        "Create route-map or enter route-map command mode\n"
     979             :        "Route map tag\n"
     980             :        "Route map denies set operations\n"
     981             :        "Route map permits set operations\n"
     982             :        "Sequence to insert to/delete from existing route-map entry\n")
     983             : {
     984             :   int permit;
     985             :   unsigned long pref;
     986             :   struct route_map *map;
     987             :   struct route_map_index *index;
     988           0 :   char *endptr = NULL;
     989             : 
     990             :   /* Permit check. */
     991           0 :   if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
     992           0 :     permit = RMAP_PERMIT;
     993           0 :   else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
     994           0 :     permit = RMAP_DENY;
     995             :   else
     996             :     {
     997           0 :       vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
     998           0 :       return CMD_WARNING;
     999             :     }
    1000             : 
    1001             :   /* Preference. */
    1002           0 :   pref = strtoul (argv[2], &endptr, 10);
    1003           0 :   if (pref == ULONG_MAX || *endptr != '\0')
    1004             :     {
    1005           0 :       vty_out (vty, "the fourth field must be positive integer%s",
    1006           0 :                VTY_NEWLINE);
    1007           0 :       return CMD_WARNING;
    1008             :     }
    1009           0 :   if (pref == 0 || pref > 65535)
    1010             :     {
    1011           0 :       vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
    1012           0 :       return CMD_WARNING;
    1013             :     }
    1014             : 
    1015             :   /* Existence check. */
    1016           0 :   map = route_map_lookup_by_name (argv[0]);
    1017           0 :   if (map == NULL)
    1018             :     {
    1019           0 :       vty_out (vty, "%% Could not find route-map %s%s",
    1020           0 :                argv[0], VTY_NEWLINE);
    1021           0 :       return CMD_WARNING;
    1022             :     }
    1023             : 
    1024             :   /* Lookup route map index. */
    1025           0 :   index = route_map_index_lookup (map, permit, pref);
    1026           0 :   if (index == NULL)
    1027             :     {
    1028           0 :       vty_out (vty, "%% Could not find route-map entry %s %s%s", 
    1029           0 :                argv[0], argv[2], VTY_NEWLINE);
    1030           0 :       return CMD_WARNING;
    1031             :     }
    1032             : 
    1033             :   /* Delete index from route map. */
    1034           0 :   route_map_index_delete (index, 1);
    1035             : 
    1036             :   /* If this route rule is the last one, delete route map itself. */
    1037           0 :   if (route_map_empty (map))
    1038           0 :     route_map_delete (map);
    1039             : 
    1040           0 :   return CMD_SUCCESS;
    1041             : }
    1042             : 
    1043           0 : DEFUN (rmap_onmatch_next,
    1044             :        rmap_onmatch_next_cmd,
    1045             :        "on-match next",
    1046             :        "Exit policy on matches\n"
    1047             :        "Next clause\n")
    1048             : {
    1049             :   struct route_map_index *index;
    1050             : 
    1051           0 :   index = vty->index;
    1052             : 
    1053           0 :   if (index)
    1054           0 :     index->exitpolicy = RMAP_NEXT;
    1055             : 
    1056           0 :   return CMD_SUCCESS;
    1057             : }
    1058             : 
    1059           0 : DEFUN (no_rmap_onmatch_next,
    1060             :        no_rmap_onmatch_next_cmd,
    1061             :        "no on-match next",
    1062             :        NO_STR
    1063             :        "Exit policy on matches\n"
    1064             :        "Next clause\n")
    1065             : {
    1066             :   struct route_map_index *index;
    1067             : 
    1068           0 :   index = vty->index;
    1069             :   
    1070           0 :   if (index)
    1071           0 :     index->exitpolicy = RMAP_EXIT;
    1072             : 
    1073           0 :   return CMD_SUCCESS;
    1074             : }
    1075             : 
    1076           0 : DEFUN (rmap_onmatch_goto,
    1077             :        rmap_onmatch_goto_cmd,
    1078             :        "on-match goto <1-65535>",
    1079             :        "Exit policy on matches\n"
    1080             :        "Goto Clause number\n"
    1081             :        "Number\n")
    1082             : {
    1083           0 :   struct route_map_index *index = vty->index;
    1084           0 :   int d = 0;
    1085             : 
    1086           0 :   if (index)
    1087             :     {
    1088           0 :       if (argc == 1 && argv[0])
    1089           0 :         VTY_GET_INTEGER_RANGE("route-map index", d, argv[0], 1, 65536);
    1090             :       else
    1091           0 :         d = index->pref + 1;
    1092             :       
    1093           0 :       if (d <= index->pref)
    1094             :         {
    1095             :           /* Can't allow you to do that, Dave */
    1096           0 :           vty_out (vty, "can't jump backwards in route-maps%s", 
    1097           0 :                    VTY_NEWLINE);
    1098           0 :           return CMD_WARNING;
    1099             :         }
    1100             :       else
    1101             :         {
    1102           0 :           index->exitpolicy = RMAP_GOTO;
    1103           0 :           index->nextpref = d;
    1104             :         }
    1105             :     }
    1106           0 :   return CMD_SUCCESS;
    1107             : }
    1108             : 
    1109           0 : DEFUN (no_rmap_onmatch_goto,
    1110             :        no_rmap_onmatch_goto_cmd,
    1111             :        "no on-match goto",
    1112             :        NO_STR
    1113             :        "Exit policy on matches\n"
    1114             :        "Goto Clause number\n")
    1115             : {
    1116             :   struct route_map_index *index;
    1117             : 
    1118           0 :   index = vty->index;
    1119             : 
    1120           0 :   if (index)
    1121           0 :     index->exitpolicy = RMAP_EXIT;
    1122             :   
    1123           0 :   return CMD_SUCCESS;
    1124             : }
    1125             : 
    1126             : /* Cisco/GNU Zebra compatible ALIASes for on-match next */
    1127             : ALIAS (rmap_onmatch_goto,
    1128             :        rmap_continue_cmd,
    1129             :        "continue",
    1130             :        "Continue on a different entry within the route-map\n")
    1131             : 
    1132             : ALIAS (no_rmap_onmatch_goto,
    1133             :        no_rmap_continue_cmd,
    1134             :        "no continue",
    1135             :        NO_STR
    1136             :        "Continue on a different entry within the route-map\n")
    1137             : 
    1138             : /* GNU Zebra compatible */
    1139             : ALIAS (rmap_onmatch_goto,
    1140             :        rmap_continue_seq_cmd,
    1141             :        "continue <1-65535>",
    1142             :        "Continue on a different entry within the route-map\n"
    1143             :        "Route-map entry sequence number\n")
    1144             : 
    1145             : ALIAS (no_rmap_onmatch_goto,
    1146             :        no_rmap_continue_seq,
    1147             :        "no continue <1-65535>",
    1148             :        NO_STR
    1149             :        "Continue on a different entry within the route-map\n"
    1150             :        "Route-map entry sequence number\n")
    1151             : 
    1152           0 : DEFUN (rmap_show_name,
    1153             :        rmap_show_name_cmd,
    1154             :        "show route-map [WORD]",
    1155             :        SHOW_STR
    1156             :        "route-map information\n"
    1157             :        "route-map name\n")
    1158             : {
    1159           0 :     const char *name = NULL;
    1160           0 :     if (argc)
    1161           0 :       name = argv[0];
    1162           0 :     return vty_show_route_map (vty, name);
    1163             : }
    1164             : 
    1165             : ALIAS (rmap_onmatch_goto,
    1166             :       rmap_continue_index_cmd,
    1167             :       "continue <1-65536>",
    1168             :       "Exit policy on matches\n"
    1169             :       "Goto Clause number\n")
    1170             : 
    1171           0 : DEFUN (rmap_call,
    1172             :        rmap_call_cmd,
    1173             :        "call WORD",
    1174             :        "Jump to another Route-Map after match+set\n"
    1175             :        "Target route-map name\n")
    1176             : {
    1177             :   struct route_map_index *index;
    1178             : 
    1179           0 :   index = vty->index;
    1180           0 :   if (index)
    1181             :     {
    1182           0 :       if (index->nextrm)
    1183           0 :           XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
    1184           0 :       index->nextrm = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[0]);
    1185             :     }
    1186           0 :   return CMD_SUCCESS;
    1187             : }
    1188             : 
    1189           0 : DEFUN (no_rmap_call,
    1190             :        no_rmap_call_cmd,
    1191             :        "no call",
    1192             :        NO_STR
    1193             :        "Jump to another Route-Map after match+set\n")
    1194             : {
    1195             :   struct route_map_index *index;
    1196             : 
    1197           0 :   index = vty->index;
    1198             : 
    1199           0 :   if (index->nextrm)
    1200             :     {
    1201           0 :       XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
    1202           0 :       index->nextrm = NULL;
    1203             :     }
    1204             : 
    1205           0 :   return CMD_SUCCESS;
    1206             : }
    1207             : 
    1208           0 : DEFUN (rmap_description,
    1209             :        rmap_description_cmd,
    1210             :        "description .LINE",
    1211             :        "Route-map comment\n"
    1212             :        "Comment describing this route-map rule\n")
    1213             : {
    1214             :   struct route_map_index *index;
    1215             : 
    1216           0 :   index = vty->index;
    1217           0 :   if (index)
    1218             :     {
    1219           0 :       if (index->description)
    1220           0 :         XFREE (MTYPE_TMP, index->description);
    1221           0 :       index->description = argv_concat (argv, argc, 0);
    1222             :     }
    1223           0 :   return CMD_SUCCESS;
    1224             : }
    1225             : 
    1226           0 : DEFUN (no_rmap_description,
    1227             :        no_rmap_description_cmd,
    1228             :        "no description",
    1229             :        NO_STR
    1230             :        "Route-map comment\n")
    1231             : {
    1232             :   struct route_map_index *index;
    1233             : 
    1234           0 :   index = vty->index;
    1235           0 :   if (index)
    1236             :     {
    1237           0 :       if (index->description)
    1238           0 :         XFREE (MTYPE_TMP, index->description);
    1239           0 :       index->description = NULL;
    1240             :     }
    1241           0 :   return CMD_SUCCESS;
    1242             : }
    1243             : 
    1244             : /* Configuration write function. */
    1245             : static int
    1246           0 : route_map_config_write (struct vty *vty)
    1247             : {
    1248             :   struct route_map *map;
    1249             :   struct route_map_index *index;
    1250             :   struct route_map_rule *rule;
    1251           0 :   int first = 1;
    1252           0 :   int write = 0;
    1253             : 
    1254           0 :   for (map = route_map_master.head; map; map = map->next)
    1255           0 :     for (index = map->head; index; index = index->next)
    1256             :       {
    1257           0 :         if (!first)
    1258           0 :           vty_out (vty, "!%s", VTY_NEWLINE);
    1259             :         else
    1260           0 :           first = 0;
    1261             : 
    1262           0 :         vty_out (vty, "route-map %s %s %d%s", 
    1263             :                  map->name,
    1264             :                  route_map_type_str (index->type),
    1265           0 :                  index->pref, VTY_NEWLINE);
    1266             : 
    1267           0 :         if (index->description)
    1268           0 :           vty_out (vty, " description %s%s", index->description, VTY_NEWLINE);
    1269             : 
    1270           0 :         for (rule = index->match_list.head; rule; rule = rule->next)
    1271           0 :           vty_out (vty, " match %s %s%s", rule->cmd->str, 
    1272           0 :                    rule->rule_str ? rule->rule_str : "",
    1273           0 :                    VTY_NEWLINE);
    1274             : 
    1275           0 :         for (rule = index->set_list.head; rule; rule = rule->next)
    1276           0 :           vty_out (vty, " set %s %s%s", rule->cmd->str,
    1277           0 :                    rule->rule_str ? rule->rule_str : "",
    1278           0 :                    VTY_NEWLINE);
    1279           0 :    if (index->nextrm)
    1280           0 :      vty_out (vty, " call %s%s", index->nextrm, VTY_NEWLINE);
    1281           0 :         if (index->exitpolicy == RMAP_GOTO)
    1282           0 :       vty_out (vty, " on-match goto %d%s", index->nextpref, VTY_NEWLINE);
    1283           0 :         if (index->exitpolicy == RMAP_NEXT)
    1284           0 :           vty_out (vty," on-match next%s", VTY_NEWLINE);
    1285             :         
    1286           0 :         write++;
    1287             :       }
    1288           0 :   return write;
    1289             : }
    1290             : 
    1291             : /* Route map node structure. */
    1292             : static struct cmd_node rmap_node =
    1293             : {
    1294             :   RMAP_NODE,
    1295             :   "%s(config-route-map)# ",
    1296             :   1
    1297             : };
    1298             : 
    1299             : /* Initialization of route map vector. */
    1300             : void
    1301          45 : route_map_init_vty (void)
    1302             : {
    1303             :   /* Install route map top node. */
    1304          45 :   install_node (&rmap_node, route_map_config_write);
    1305             : 
    1306             :   /* Install route map commands. */
    1307          45 :   install_default (RMAP_NODE);
    1308          45 :   install_element (CONFIG_NODE, &route_map_cmd);
    1309          45 :   install_element (CONFIG_NODE, &no_route_map_cmd);
    1310          45 :   install_element (CONFIG_NODE, &no_route_map_all_cmd);
    1311             : 
    1312             :   /* Install the on-match stuff */
    1313          45 :   install_element (RMAP_NODE, &route_map_cmd);
    1314          45 :   install_element (RMAP_NODE, &rmap_onmatch_next_cmd);
    1315          45 :   install_element (RMAP_NODE, &no_rmap_onmatch_next_cmd);
    1316          45 :   install_element (RMAP_NODE, &rmap_onmatch_goto_cmd);
    1317          45 :   install_element (RMAP_NODE, &no_rmap_onmatch_goto_cmd);
    1318             :   
    1319             :   /* Install the continue stuff (ALIAS of on-match). */
    1320          45 :   install_element (RMAP_NODE, &rmap_continue_cmd);
    1321          45 :   install_element (RMAP_NODE, &no_rmap_continue_cmd);
    1322          45 :   install_element (RMAP_NODE, &rmap_continue_index_cmd);
    1323             :   
    1324             :   /* Install the call stuff. */
    1325          45 :   install_element (RMAP_NODE, &rmap_call_cmd);
    1326          45 :   install_element (RMAP_NODE, &no_rmap_call_cmd);
    1327             : 
    1328             :   /* Install description commands. */
    1329          45 :   install_element (RMAP_NODE, &rmap_description_cmd);
    1330          45 :   install_element (RMAP_NODE, &no_rmap_description_cmd);
    1331             :    
    1332             :   /* Install show command */
    1333          45 :   install_element (ENABLE_NODE, &rmap_show_name_cmd);
    1334          45 : }

Generated by: LCOV version 1.10