Annotation of embedaddon/quagga/lib/routemap.c, revision 1.1

1.1     ! misho       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: route_map_new (const char *name)
        !            80: {
        !            81:   struct route_map *new;
        !            82: 
        !            83:   new =  XCALLOC (MTYPE_ROUTE_MAP, sizeof (struct route_map));
        !            84:   new->name = XSTRDUP (MTYPE_ROUTE_MAP_NAME, name);
        !            85:   return new;
        !            86: }
        !            87: 
        !            88: /* Add new name to route_map. */
        !            89: static struct route_map *
        !            90: route_map_add (const char *name)
        !            91: {
        !            92:   struct route_map *map;
        !            93:   struct route_map_list *list;
        !            94: 
        !            95:   map = route_map_new (name);
        !            96:   list = &route_map_master;
        !            97:     
        !            98:   map->next = NULL;
        !            99:   map->prev = list->tail;
        !           100:   if (list->tail)
        !           101:     list->tail->next = map;
        !           102:   else
        !           103:     list->head = map;
        !           104:   list->tail = map;
        !           105: 
        !           106:   /* Execute hook. */
        !           107:   if (route_map_master.add_hook)
        !           108:     (*route_map_master.add_hook) (name);
        !           109: 
        !           110:   return map;
        !           111: }
        !           112: 
        !           113: /* Route map delete from list. */
        !           114: static void
        !           115: 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:   while ((index = map->head) != NULL)
        !           122:     route_map_index_delete (index, 0);
        !           123: 
        !           124:   name = map->name;
        !           125: 
        !           126:   list = &route_map_master;
        !           127: 
        !           128:   if (map->next)
        !           129:     map->next->prev = map->prev;
        !           130:   else
        !           131:     list->tail = map->prev;
        !           132: 
        !           133:   if (map->prev)
        !           134:     map->prev->next = map->next;
        !           135:   else
        !           136:     list->head = map->next;
        !           137: 
        !           138:   XFREE (MTYPE_ROUTE_MAP, map);
        !           139: 
        !           140:   /* Execute deletion hook. */
        !           141:   if (route_map_master.delete_hook)
        !           142:     (*route_map_master.delete_hook) (name);
        !           143: 
        !           144:   if (name)
        !           145:     XFREE (MTYPE_ROUTE_MAP_NAME, name);
        !           146: 
        !           147: }
        !           148: 
        !           149: /* Lookup route map by route map name string. */
        !           150: struct route_map *
        !           151: route_map_lookup_by_name (const char *name)
        !           152: {
        !           153:   struct route_map *map;
        !           154: 
        !           155:   for (map = route_map_master.head; map; map = map->next)
        !           156:     if (strcmp (map->name, name) == 0)
        !           157:       return map;
        !           158:   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: route_map_get (const char *name)
        !           165: {
        !           166:   struct route_map *map;
        !           167: 
        !           168:   map = route_map_lookup_by_name (name);
        !           169:   if (map == NULL)
        !           170:     map = route_map_add (name);
        !           171:   return map;
        !           172: }
        !           173: 
        !           174: /* Return route map's type string. */
        !           175: static const char *
        !           176: route_map_type_str (enum route_map_type type)
        !           177: {
        !           178:   switch (type)
        !           179:     {
        !           180:     case RMAP_PERMIT:
        !           181:       return "permit";
        !           182:       break;
        !           183:     case RMAP_DENY:
        !           184:       return "deny";
        !           185:       break;
        !           186:     default:
        !           187:       return "";
        !           188:       break;
        !           189:     }
        !           190: }
        !           191: 
        !           192: static int
        !           193: route_map_empty (struct route_map *map)
        !           194: {
        !           195:   if (map->head == NULL && map->tail == NULL)
        !           196:     return 1;
        !           197:   else
        !           198:     return 0;
        !           199: }
        !           200: 
        !           201: /* show route-map */
        !           202: static void
        !           203: 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:   if (zlog_default)
        !           210:     vty_out (vty, "%s:%s", zlog_proto_names[zlog_default->protocol],
        !           211:              VTY_NEWLINE);
        !           212: 
        !           213:   for (index = map->head; index; index = index->next)
        !           214:     {
        !           215:       vty_out (vty, "route-map %s, %s, sequence %d%s",
        !           216:                map->name, route_map_type_str (index->type),
        !           217:                index->pref, VTY_NEWLINE);
        !           218: 
        !           219:       /* Description */
        !           220:       if (index->description)
        !           221:        vty_out (vty, "  Description:%s    %s%s", VTY_NEWLINE,
        !           222:                 index->description, VTY_NEWLINE);
        !           223:       
        !           224:       /* Match clauses */
        !           225:       vty_out (vty, "  Match clauses:%s", VTY_NEWLINE);
        !           226:       for (rule = index->match_list.head; rule; rule = rule->next)
        !           227:         vty_out (vty, "    %s %s%s", 
        !           228:                  rule->cmd->str, rule->rule_str, VTY_NEWLINE);
        !           229:       
        !           230:       vty_out (vty, "  Set clauses:%s", VTY_NEWLINE);
        !           231:       for (rule = index->set_list.head; rule; rule = rule->next)
        !           232:         vty_out (vty, "    %s %s%s",
        !           233:                  rule->cmd->str, rule->rule_str, VTY_NEWLINE);
        !           234:       
        !           235:       /* Call clause */
        !           236:       vty_out (vty, "  Call clause:%s", VTY_NEWLINE);
        !           237:       if (index->nextrm)
        !           238:         vty_out (vty, "    Call %s%s", index->nextrm, VTY_NEWLINE);
        !           239:       
        !           240:       /* Exit Policy */
        !           241:       vty_out (vty, "  Action:%s", VTY_NEWLINE);
        !           242:       if (index->exitpolicy == RMAP_GOTO)
        !           243:         vty_out (vty, "    Goto %d%s", index->nextpref, VTY_NEWLINE);
        !           244:       else if (index->exitpolicy == RMAP_NEXT)
        !           245:         vty_out (vty, "    Continue to next entry%s", VTY_NEWLINE);
        !           246:       else if (index->exitpolicy == RMAP_EXIT)
        !           247:         vty_out (vty, "    Exit routemap%s", VTY_NEWLINE);
        !           248:     }
        !           249: }
        !           250: 
        !           251: static int
        !           252: vty_show_route_map (struct vty *vty, const char *name)
        !           253: {
        !           254:   struct route_map *map;
        !           255: 
        !           256:   if (name)
        !           257:     {
        !           258:       map = route_map_lookup_by_name (name);
        !           259: 
        !           260:       if (map)
        !           261:         {
        !           262:           vty_show_route_map_entry (vty, map);
        !           263:           return CMD_SUCCESS;
        !           264:         }
        !           265:       else
        !           266:         {
        !           267:           vty_out (vty, "%%route-map %s not found%s", name, VTY_NEWLINE);
        !           268:           return CMD_WARNING;
        !           269:         }
        !           270:     }
        !           271:   else
        !           272:     {
        !           273:       for (map = route_map_master.head; map; map = map->next)
        !           274:        vty_show_route_map_entry (vty, map);
        !           275:     }
        !           276:   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: route_map_index_new (void)
        !           284: {
        !           285:   struct route_map_index *new;
        !           286: 
        !           287:   new =  XCALLOC (MTYPE_ROUTE_MAP_INDEX, sizeof (struct route_map_index));
        !           288:   new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */
        !           289:   return new;
        !           290: }
        !           291: 
        !           292: /* Free route map index. */
        !           293: static void
        !           294: route_map_index_delete (struct route_map_index *index, int notify)
        !           295: {
        !           296:   struct route_map_rule *rule;
        !           297: 
        !           298:   /* Free route match. */
        !           299:   while ((rule = index->match_list.head) != NULL)
        !           300:     route_map_rule_delete (&index->match_list, rule);
        !           301: 
        !           302:   /* Free route set. */
        !           303:   while ((rule = index->set_list.head) != NULL)
        !           304:     route_map_rule_delete (&index->set_list, rule);
        !           305: 
        !           306:   /* Remove index from route map list. */
        !           307:   if (index->next)
        !           308:     index->next->prev = index->prev;
        !           309:   else
        !           310:     index->map->tail = index->prev;
        !           311: 
        !           312:   if (index->prev)
        !           313:     index->prev->next = index->next;
        !           314:   else
        !           315:     index->map->head = index->next;
        !           316: 
        !           317:   /* Free 'char *nextrm' if not NULL */
        !           318:   if (index->nextrm)
        !           319:     XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
        !           320: 
        !           321:     /* Execute event hook. */
        !           322:   if (route_map_master.event_hook && notify)
        !           323:     (*route_map_master.event_hook) (RMAP_EVENT_INDEX_DELETED,
        !           324:                                    index->map->name);
        !           325: 
        !           326:   XFREE (MTYPE_ROUTE_MAP_INDEX, index);
        !           327: }
        !           328: 
        !           329: /* Lookup index from route map. */
        !           330: static struct route_map_index *
        !           331: 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:   for (index = map->head; index; index = index->next)
        !           337:     if ((index->type == type || type == RMAP_ANY)
        !           338:        && index->pref == pref)
        !           339:       return index;
        !           340:   return NULL;
        !           341: }
        !           342: 
        !           343: /* Add new index to route map. */
        !           344: static struct route_map_index *
        !           345: 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:   index = route_map_index_new ();
        !           353:   index->map = map;
        !           354:   index->type = type;
        !           355:   index->pref = pref;
        !           356:   
        !           357:   /* Compare preference. */
        !           358:   for (point = map->head; point; point = point->next)
        !           359:     if (point->pref >= pref)
        !           360:       break;
        !           361: 
        !           362:   if (map->head == NULL)
        !           363:     {
        !           364:       map->head = map->tail = index;
        !           365:     }
        !           366:   else if (point == NULL)
        !           367:     {
        !           368:       index->prev = map->tail;
        !           369:       map->tail->next = index;
        !           370:       map->tail = index;
        !           371:     }
        !           372:   else if (point == map->head)
        !           373:     {
        !           374:       index->next = map->head;
        !           375:       map->head->prev = index;
        !           376:       map->head = index;
        !           377:     }
        !           378:   else
        !           379:     {
        !           380:       index->next = point;
        !           381:       index->prev = point->prev;
        !           382:       if (point->prev)
        !           383:        point->prev->next = index;
        !           384:       point->prev = index;
        !           385:     }
        !           386: 
        !           387:   /* Execute event hook. */
        !           388:   if (route_map_master.event_hook)
        !           389:     (*route_map_master.event_hook) (RMAP_EVENT_INDEX_ADDED,
        !           390:                                    map->name);
        !           391: 
        !           392:   return index;
        !           393: }
        !           394: 
        !           395: /* Get route map index. */
        !           396: static struct route_map_index *
        !           397: 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:   index = route_map_index_lookup (map, RMAP_ANY, pref);
        !           403:   if (index && index->type != type)
        !           404:     {
        !           405:       /* Delete index from route map. */
        !           406:       route_map_index_delete (index, 1);
        !           407:       index = NULL;
        !           408:     }
        !           409:   if (index == NULL)
        !           410:     index = route_map_index_add (map, type, pref);
        !           411:   return index;
        !           412: }
        !           413: 
        !           414: /* New route map rule */
        !           415: static struct route_map_rule *
        !           416: route_map_rule_new (void)
        !           417: {
        !           418:   struct route_map_rule *new;
        !           419: 
        !           420:   new = XCALLOC (MTYPE_ROUTE_MAP_RULE, sizeof (struct route_map_rule));
        !           421:   return new;
        !           422: }
        !           423: 
        !           424: /* Install rule command to the match list. */
        !           425: void
        !           426: route_map_install_match (struct route_map_rule_cmd *cmd)
        !           427: {
        !           428:   vector_set (route_match_vec, cmd);
        !           429: }
        !           430: 
        !           431: /* Install rule command to the set list. */
        !           432: void
        !           433: route_map_install_set (struct route_map_rule_cmd *cmd)
        !           434: {
        !           435:   vector_set (route_set_vec, cmd);
        !           436: }
        !           437: 
        !           438: /* Lookup rule command from match list. */
        !           439: static struct route_map_rule_cmd *
        !           440: route_map_lookup_match (const char *name)
        !           441: {
        !           442:   unsigned int i;
        !           443:   struct route_map_rule_cmd *rule;
        !           444: 
        !           445:   for (i = 0; i < vector_active (route_match_vec); i++)
        !           446:     if ((rule = vector_slot (route_match_vec, i)) != NULL)
        !           447:       if (strcmp (rule->str, name) == 0)
        !           448:        return rule;
        !           449:   return NULL;
        !           450: }
        !           451: 
        !           452: /* Lookup rule command from set list. */
        !           453: static struct route_map_rule_cmd *
        !           454: route_map_lookup_set (const char *name)
        !           455: {
        !           456:   unsigned int i;
        !           457:   struct route_map_rule_cmd *rule;
        !           458: 
        !           459:   for (i = 0; i < vector_active (route_set_vec); i++)
        !           460:     if ((rule = vector_slot (route_set_vec, i)) != NULL)
        !           461:       if (strcmp (rule->str, name) == 0)
        !           462:        return rule;
        !           463:   return NULL;
        !           464: }
        !           465: 
        !           466: /* Add match and set rule to rule list. */
        !           467: static void
        !           468: route_map_rule_add (struct route_map_rule_list *list,
        !           469:                    struct route_map_rule *rule)
        !           470: {
        !           471:   rule->next = NULL;
        !           472:   rule->prev = list->tail;
        !           473:   if (list->tail)
        !           474:     list->tail->next = rule;
        !           475:   else
        !           476:     list->head = rule;
        !           477:   list->tail = rule;
        !           478: }
        !           479: 
        !           480: /* Delete rule from rule list. */
        !           481: static void
        !           482: route_map_rule_delete (struct route_map_rule_list *list,
        !           483:                       struct route_map_rule *rule)
        !           484: {
        !           485:   if (rule->cmd->func_free)
        !           486:     (*rule->cmd->func_free) (rule->value);
        !           487: 
        !           488:   if (rule->rule_str)
        !           489:     XFREE (MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str);
        !           490: 
        !           491:   if (rule->next)
        !           492:     rule->next->prev = rule->prev;
        !           493:   else
        !           494:     list->tail = rule->prev;
        !           495:   if (rule->prev)
        !           496:     rule->prev->next = rule->next;
        !           497:   else
        !           498:     list->head = rule->next;
        !           499: 
        !           500:   XFREE (MTYPE_ROUTE_MAP_RULE, rule);
        !           501: }
        !           502: 
        !           503: /* strcmp wrapper function which don't crush even argument is NULL. */
        !           504: static int
        !           505: rulecmp (const char *dst, const char *src)
        !           506: {
        !           507:   if (dst == NULL)
        !           508:     {
        !           509:       if (src ==  NULL)
        !           510:        return 0;
        !           511:       else
        !           512:        return 1;
        !           513:     }
        !           514:   else
        !           515:     {
        !           516:       if (src == NULL)
        !           517:        return 1;
        !           518:       else
        !           519:        return strcmp (dst, src);
        !           520:     }
        !           521:   return 1;
        !           522: }
        !           523: 
        !           524: /* Add match statement to route map. */
        !           525: int
        !           526: 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:   int replaced = 0;
        !           534: 
        !           535:   /* First lookup rule for add match statement. */
        !           536:   cmd = route_map_lookup_match (match_name);
        !           537:   if (cmd == NULL)
        !           538:     return RMAP_RULE_MISSING;
        !           539: 
        !           540:   /* Next call compile function for this match statement. */
        !           541:   if (cmd->func_compile)
        !           542:     {
        !           543:       compile= (*cmd->func_compile)(match_arg);
        !           544:       if (compile == NULL)
        !           545:        return RMAP_COMPILE_ERROR;
        !           546:     }
        !           547:   else
        !           548:     compile = NULL;
        !           549: 
        !           550:   /* If argument is completely same ignore it. */
        !           551:   for (rule = index->match_list.head; rule; rule = next)
        !           552:     {
        !           553:       next = rule->next;
        !           554:       if (rule->cmd == cmd)
        !           555:        {       
        !           556:          route_map_rule_delete (&index->match_list, rule);
        !           557:          replaced = 1;
        !           558:        }
        !           559:     }
        !           560: 
        !           561:   /* Add new route map match rule. */
        !           562:   rule = route_map_rule_new ();
        !           563:   rule->cmd = cmd;
        !           564:   rule->value = compile;
        !           565:   if (match_arg)
        !           566:     rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, match_arg);
        !           567:   else
        !           568:     rule->rule_str = NULL;
        !           569: 
        !           570:   /* Add new route match rule to linked list. */
        !           571:   route_map_rule_add (&index->match_list, rule);
        !           572: 
        !           573:   /* Execute event hook. */
        !           574:   if (route_map_master.event_hook)
        !           575:     (*route_map_master.event_hook) (replaced ?
        !           576:                                    RMAP_EVENT_MATCH_REPLACED:
        !           577:                                    RMAP_EVENT_MATCH_ADDED,
        !           578:                                    index->map->name);
        !           579: 
        !           580:   return 0;
        !           581: }
        !           582: 
        !           583: /* Delete specified route match rule. */
        !           584: int
        !           585: 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:   cmd = route_map_lookup_match (match_name);
        !           592:   if (cmd == NULL)
        !           593:     return 1;
        !           594:   
        !           595:   for (rule = index->match_list.head; rule; rule = rule->next)
        !           596:     if (rule->cmd == cmd && 
        !           597:        (rulecmp (rule->rule_str, match_arg) == 0 || match_arg == NULL))
        !           598:       {
        !           599:        route_map_rule_delete (&index->match_list, rule);
        !           600:        /* Execute event hook. */
        !           601:        if (route_map_master.event_hook)
        !           602:          (*route_map_master.event_hook) (RMAP_EVENT_MATCH_DELETED,
        !           603:                                          index->map->name);
        !           604:        return 0;
        !           605:       }
        !           606:   /* Can't find matched rule. */
        !           607:   return 1;
        !           608: }
        !           609: 
        !           610: /* Add route-map set statement to the route map. */
        !           611: int
        !           612: 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:   int replaced = 0;
        !           620: 
        !           621:   cmd = route_map_lookup_set (set_name);
        !           622:   if (cmd == NULL)
        !           623:     return RMAP_RULE_MISSING;
        !           624: 
        !           625:   /* Next call compile function for this match statement. */
        !           626:   if (cmd->func_compile)
        !           627:     {
        !           628:       compile= (*cmd->func_compile)(set_arg);
        !           629:       if (compile == NULL)
        !           630:        return RMAP_COMPILE_ERROR;
        !           631:     }
        !           632:   else
        !           633:     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:   for (rule = index->set_list.head; rule; rule = next)
        !           639:     {
        !           640:       next = rule->next;
        !           641:       if (rule->cmd == cmd)
        !           642:        {
        !           643:          route_map_rule_delete (&index->set_list, rule);
        !           644:          replaced = 1;
        !           645:        }
        !           646:     }
        !           647: 
        !           648:   /* Add new route map match rule. */
        !           649:   rule = route_map_rule_new ();
        !           650:   rule->cmd = cmd;
        !           651:   rule->value = compile;
        !           652:   if (set_arg)
        !           653:     rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, set_arg);
        !           654:   else
        !           655:     rule->rule_str = NULL;
        !           656: 
        !           657:   /* Add new route match rule to linked list. */
        !           658:   route_map_rule_add (&index->set_list, rule);
        !           659: 
        !           660:   /* Execute event hook. */
        !           661:   if (route_map_master.event_hook)
        !           662:     (*route_map_master.event_hook) (replaced ?
        !           663:                                    RMAP_EVENT_SET_REPLACED:
        !           664:                                    RMAP_EVENT_SET_ADDED,
        !           665:                                    index->map->name);
        !           666:   return 0;
        !           667: }
        !           668: 
        !           669: /* Delete route map set rule. */
        !           670: int
        !           671: 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:   cmd = route_map_lookup_set (set_name);
        !           678:   if (cmd == NULL)
        !           679:     return 1;
        !           680:   
        !           681:   for (rule = index->set_list.head; rule; rule = rule->next)
        !           682:     if ((rule->cmd == cmd) &&
        !           683:          (rulecmp (rule->rule_str, set_arg) == 0 || set_arg == NULL))
        !           684:       {
        !           685:         route_map_rule_delete (&index->set_list, rule);
        !           686:        /* Execute event hook. */
        !           687:        if (route_map_master.event_hook)
        !           688:          (*route_map_master.event_hook) (RMAP_EVENT_SET_DELETED,
        !           689:                                          index->map->name);
        !           690:         return 0;
        !           691:       }
        !           692:   /* Can't find matched rule. */
        !           693:   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: 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:   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:   if (!match_list->head)
        !           754:     ret = RMAP_MATCH;
        !           755:   else
        !           756:     {
        !           757:       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:           ret = (*match->cmd->func_apply) (match->value, prefix,
        !           764:                                            type, object);
        !           765:           if (ret != RMAP_MATCH)
        !           766:             return ret;
        !           767:         }
        !           768:     }
        !           769:   return ret;
        !           770: }
        !           771: 
        !           772: /* Apply route map to the object. */
        !           773: route_map_result_t
        !           774: 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:   int ret = 0;
        !           779:   struct route_map_index *index;
        !           780:   struct route_map_rule *set;
        !           781: 
        !           782:   if (recursion > RMAP_RECURSION_LIMIT)
        !           783:     {
        !           784:       zlog (NULL, LOG_WARNING,
        !           785:             "route-map recursion limit (%d) reached, discarding route",
        !           786:             RMAP_RECURSION_LIMIT);
        !           787:       recursion = 0;
        !           788:       return RMAP_DENYMATCH;
        !           789:     }
        !           790: 
        !           791:   if (map == NULL)
        !           792:     return RMAP_DENYMATCH;
        !           793: 
        !           794:   for (index = map->head; index; index = index->next)
        !           795:     {
        !           796:       /* Apply this index. */
        !           797:       ret = route_map_apply_match (&index->match_list, prefix, type, object);
        !           798: 
        !           799:       /* Now we apply the matrix from above */
        !           800:       if (ret == RMAP_NOMATCH)
        !           801:         /* 'cont' from matrix - continue to next route-map sequence */
        !           802:         continue;
        !           803:       else if (ret == RMAP_MATCH)
        !           804:         {
        !           805:           if (index->type == RMAP_PERMIT)
        !           806:             /* 'action' */
        !           807:             {
        !           808:               /* permit+match must execute sets */
        !           809:               for (set = index->set_list.head; set; set = set->next)
        !           810:                 ret = (*set->cmd->func_apply) (set->value, prefix,
        !           811:                                                type, object);
        !           812: 
        !           813:               /* Call another route-map if available */
        !           814:               if (index->nextrm)
        !           815:                 {
        !           816:                   struct route_map *nextrm =
        !           817:                                     route_map_lookup_by_name (index->nextrm);
        !           818: 
        !           819:                   if (nextrm) /* Target route-map found, jump to it */
        !           820:                     {
        !           821:                       recursion++;
        !           822:                       ret = route_map_apply (nextrm, prefix, type, object);
        !           823:                       recursion--;
        !           824:                     }
        !           825: 
        !           826:                   /* If nextrm returned 'deny', finish. */
        !           827:                   if (ret == RMAP_DENYMATCH)
        !           828:                     return ret;
        !           829:                 }
        !           830:                 
        !           831:               switch (index->exitpolicy)
        !           832:                 {
        !           833:                   case RMAP_EXIT:
        !           834:                     return ret;
        !           835:                   case RMAP_NEXT:
        !           836:                     continue;
        !           837:                   case RMAP_GOTO:
        !           838:                     {
        !           839:                       /* Find the next clause to jump to */
        !           840:                       struct route_map_index *next = index->next;
        !           841:                       int nextpref = index->nextpref;
        !           842: 
        !           843:                       while (next && next->pref < nextpref)
        !           844:                         {
        !           845:                           index = next;
        !           846:                           next = next->next;
        !           847:                         }
        !           848:                       if (next == NULL)
        !           849:                         {
        !           850:                           /* No clauses match! */
        !           851:                           return ret;
        !           852:                         }
        !           853:                     }
        !           854:                 }
        !           855:             }
        !           856:           else if (index->type == RMAP_DENY)
        !           857:             /* 'deny' */
        !           858:             {
        !           859:                 return RMAP_DENYMATCH;
        !           860:             }
        !           861:         }
        !           862:     }
        !           863:   /* Finally route-map does not match at all. */
        !           864:   return RMAP_DENYMATCH;
        !           865: }
        !           866: 
        !           867: void
        !           868: route_map_add_hook (void (*func) (const char *))
        !           869: {
        !           870:   route_map_master.add_hook = func;
        !           871: }
        !           872: 
        !           873: void
        !           874: route_map_delete_hook (void (*func) (const char *))
        !           875: {
        !           876:   route_map_master.delete_hook = func;
        !           877: }
        !           878: 
        !           879: void
        !           880: route_map_event_hook (void (*func) (route_map_event_t, const char *))
        !           881: {
        !           882:   route_map_master.event_hook = func;
        !           883: }
        !           884: 
        !           885: void
        !           886: route_map_init (void)
        !           887: {
        !           888:   /* Make vector for match and set. */
        !           889:   route_match_vec = vector_init (1);
        !           890:   route_set_vec = vector_init (1);
        !           891: }
        !           892: 
        !           893: void
        !           894: route_map_finish (void)
        !           895: {
        !           896:   vector_free (route_match_vec);
        !           897:   route_match_vec = NULL;
        !           898:   vector_free (route_set_vec);
        !           899:   route_set_vec = NULL;
        !           900: }
        !           901: 
        !           902: /* VTY related functions. */
        !           903: 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:   char *endptr = NULL;
        !           917: 
        !           918:   /* Permit check. */
        !           919:   if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
        !           920:     permit = RMAP_PERMIT;
        !           921:   else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
        !           922:     permit = RMAP_DENY;
        !           923:   else
        !           924:     {
        !           925:       vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
        !           926:       return CMD_WARNING;
        !           927:     }
        !           928: 
        !           929:   /* Preference check. */
        !           930:   pref = strtoul (argv[2], &endptr, 10);
        !           931:   if (pref == ULONG_MAX || *endptr != '\0')
        !           932:     {
        !           933:       vty_out (vty, "the fourth field must be positive integer%s",
        !           934:               VTY_NEWLINE);
        !           935:       return CMD_WARNING;
        !           936:     }
        !           937:   if (pref == 0 || pref > 65535)
        !           938:     {
        !           939:       vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
        !           940:       return CMD_WARNING;
        !           941:     }
        !           942: 
        !           943:   /* Get route map. */
        !           944:   map = route_map_get (argv[0]);
        !           945:   index = route_map_index_get (map, permit, pref);
        !           946: 
        !           947:   vty->index = index;
        !           948:   vty->node = RMAP_NODE;
        !           949:   return CMD_SUCCESS;
        !           950: }
        !           951: 
        !           952: 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:   map = route_map_lookup_by_name (argv[0]);
        !           962:   if (map == NULL)
        !           963:     {
        !           964:       vty_out (vty, "%% Could not find route-map %s%s",
        !           965:               argv[0], VTY_NEWLINE);
        !           966:       return CMD_WARNING;
        !           967:     }
        !           968: 
        !           969:   route_map_delete (map);
        !           970: 
        !           971:   return CMD_SUCCESS;
        !           972: }
        !           973: 
        !           974: 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:   char *endptr = NULL;
        !           989: 
        !           990:   /* Permit check. */
        !           991:   if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
        !           992:     permit = RMAP_PERMIT;
        !           993:   else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
        !           994:     permit = RMAP_DENY;
        !           995:   else
        !           996:     {
        !           997:       vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
        !           998:       return CMD_WARNING;
        !           999:     }
        !          1000: 
        !          1001:   /* Preference. */
        !          1002:   pref = strtoul (argv[2], &endptr, 10);
        !          1003:   if (pref == ULONG_MAX || *endptr != '\0')
        !          1004:     {
        !          1005:       vty_out (vty, "the fourth field must be positive integer%s",
        !          1006:               VTY_NEWLINE);
        !          1007:       return CMD_WARNING;
        !          1008:     }
        !          1009:   if (pref == 0 || pref > 65535)
        !          1010:     {
        !          1011:       vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
        !          1012:       return CMD_WARNING;
        !          1013:     }
        !          1014: 
        !          1015:   /* Existence check. */
        !          1016:   map = route_map_lookup_by_name (argv[0]);
        !          1017:   if (map == NULL)
        !          1018:     {
        !          1019:       vty_out (vty, "%% Could not find route-map %s%s",
        !          1020:               argv[0], VTY_NEWLINE);
        !          1021:       return CMD_WARNING;
        !          1022:     }
        !          1023: 
        !          1024:   /* Lookup route map index. */
        !          1025:   index = route_map_index_lookup (map, permit, pref);
        !          1026:   if (index == NULL)
        !          1027:     {
        !          1028:       vty_out (vty, "%% Could not find route-map entry %s %s%s", 
        !          1029:               argv[0], argv[2], VTY_NEWLINE);
        !          1030:       return CMD_WARNING;
        !          1031:     }
        !          1032: 
        !          1033:   /* Delete index from route map. */
        !          1034:   route_map_index_delete (index, 1);
        !          1035: 
        !          1036:   /* If this route rule is the last one, delete route map itself. */
        !          1037:   if (route_map_empty (map))
        !          1038:     route_map_delete (map);
        !          1039: 
        !          1040:   return CMD_SUCCESS;
        !          1041: }
        !          1042: 
        !          1043: 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:   index = vty->index;
        !          1052: 
        !          1053:   if (index)
        !          1054:     index->exitpolicy = RMAP_NEXT;
        !          1055: 
        !          1056:   return CMD_SUCCESS;
        !          1057: }
        !          1058: 
        !          1059: 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:   index = vty->index;
        !          1069:   
        !          1070:   if (index)
        !          1071:     index->exitpolicy = RMAP_EXIT;
        !          1072: 
        !          1073:   return CMD_SUCCESS;
        !          1074: }
        !          1075: 
        !          1076: 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:   struct route_map_index *index = vty->index;
        !          1084:   int d = 0;
        !          1085: 
        !          1086:   if (index)
        !          1087:     {
        !          1088:       if (argc == 1 && argv[0])
        !          1089:         VTY_GET_INTEGER_RANGE("route-map index", d, argv[0], 1, 65536);
        !          1090:       else
        !          1091:         d = index->pref + 1;
        !          1092:       
        !          1093:       if (d <= index->pref)
        !          1094:        {
        !          1095:          /* Can't allow you to do that, Dave */
        !          1096:          vty_out (vty, "can't jump backwards in route-maps%s", 
        !          1097:                   VTY_NEWLINE);
        !          1098:          return CMD_WARNING;
        !          1099:        }
        !          1100:       else
        !          1101:        {
        !          1102:          index->exitpolicy = RMAP_GOTO;
        !          1103:          index->nextpref = d;
        !          1104:        }
        !          1105:     }
        !          1106:   return CMD_SUCCESS;
        !          1107: }
        !          1108: 
        !          1109: 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:   index = vty->index;
        !          1119: 
        !          1120:   if (index)
        !          1121:     index->exitpolicy = RMAP_EXIT;
        !          1122:   
        !          1123:   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: 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:     const char *name = NULL;
        !          1160:     if (argc)
        !          1161:       name = argv[0];
        !          1162:     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: 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:   index = vty->index;
        !          1180:   if (index)
        !          1181:     {
        !          1182:       if (index->nextrm)
        !          1183:           XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
        !          1184:       index->nextrm = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[0]);
        !          1185:     }
        !          1186:   return CMD_SUCCESS;
        !          1187: }
        !          1188: 
        !          1189: 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:   index = vty->index;
        !          1198: 
        !          1199:   if (index->nextrm)
        !          1200:     {
        !          1201:       XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
        !          1202:       index->nextrm = NULL;
        !          1203:     }
        !          1204: 
        !          1205:   return CMD_SUCCESS;
        !          1206: }
        !          1207: 
        !          1208: 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:   index = vty->index;
        !          1217:   if (index)
        !          1218:     {
        !          1219:       if (index->description)
        !          1220:        XFREE (MTYPE_TMP, index->description);
        !          1221:       index->description = argv_concat (argv, argc, 0);
        !          1222:     }
        !          1223:   return CMD_SUCCESS;
        !          1224: }
        !          1225: 
        !          1226: 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:   index = vty->index;
        !          1235:   if (index)
        !          1236:     {
        !          1237:       if (index->description)
        !          1238:        XFREE (MTYPE_TMP, index->description);
        !          1239:       index->description = NULL;
        !          1240:     }
        !          1241:   return CMD_SUCCESS;
        !          1242: }
        !          1243: 
        !          1244: /* Configuration write function. */
        !          1245: static int
        !          1246: 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:   int first = 1;
        !          1252:   int write = 0;
        !          1253: 
        !          1254:   for (map = route_map_master.head; map; map = map->next)
        !          1255:     for (index = map->head; index; index = index->next)
        !          1256:       {
        !          1257:        if (!first)
        !          1258:          vty_out (vty, "!%s", VTY_NEWLINE);
        !          1259:        else
        !          1260:          first = 0;
        !          1261: 
        !          1262:        vty_out (vty, "route-map %s %s %d%s", 
        !          1263:                 map->name,
        !          1264:                 route_map_type_str (index->type),
        !          1265:                 index->pref, VTY_NEWLINE);
        !          1266: 
        !          1267:        if (index->description)
        !          1268:          vty_out (vty, " description %s%s", index->description, VTY_NEWLINE);
        !          1269: 
        !          1270:        for (rule = index->match_list.head; rule; rule = rule->next)
        !          1271:          vty_out (vty, " match %s %s%s", rule->cmd->str, 
        !          1272:                   rule->rule_str ? rule->rule_str : "",
        !          1273:                   VTY_NEWLINE);
        !          1274: 
        !          1275:        for (rule = index->set_list.head; rule; rule = rule->next)
        !          1276:          vty_out (vty, " set %s %s%s", rule->cmd->str,
        !          1277:                   rule->rule_str ? rule->rule_str : "",
        !          1278:                   VTY_NEWLINE);
        !          1279:    if (index->nextrm)
        !          1280:      vty_out (vty, " call %s%s", index->nextrm, VTY_NEWLINE);
        !          1281:        if (index->exitpolicy == RMAP_GOTO)
        !          1282:       vty_out (vty, " on-match goto %d%s", index->nextpref, VTY_NEWLINE);
        !          1283:        if (index->exitpolicy == RMAP_NEXT)
        !          1284:          vty_out (vty," on-match next%s", VTY_NEWLINE);
        !          1285:        
        !          1286:        write++;
        !          1287:       }
        !          1288:   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: route_map_init_vty (void)
        !          1302: {
        !          1303:   /* Install route map top node. */
        !          1304:   install_node (&rmap_node, route_map_config_write);
        !          1305: 
        !          1306:   /* Install route map commands. */
        !          1307:   install_default (RMAP_NODE);
        !          1308:   install_element (CONFIG_NODE, &route_map_cmd);
        !          1309:   install_element (CONFIG_NODE, &no_route_map_cmd);
        !          1310:   install_element (CONFIG_NODE, &no_route_map_all_cmd);
        !          1311: 
        !          1312:   /* Install the on-match stuff */
        !          1313:   install_element (RMAP_NODE, &route_map_cmd);
        !          1314:   install_element (RMAP_NODE, &rmap_onmatch_next_cmd);
        !          1315:   install_element (RMAP_NODE, &no_rmap_onmatch_next_cmd);
        !          1316:   install_element (RMAP_NODE, &rmap_onmatch_goto_cmd);
        !          1317:   install_element (RMAP_NODE, &no_rmap_onmatch_goto_cmd);
        !          1318:   
        !          1319:   /* Install the continue stuff (ALIAS of on-match). */
        !          1320:   install_element (RMAP_NODE, &rmap_continue_cmd);
        !          1321:   install_element (RMAP_NODE, &no_rmap_continue_cmd);
        !          1322:   install_element (RMAP_NODE, &rmap_continue_index_cmd);
        !          1323:   
        !          1324:   /* Install the call stuff. */
        !          1325:   install_element (RMAP_NODE, &rmap_call_cmd);
        !          1326:   install_element (RMAP_NODE, &no_rmap_call_cmd);
        !          1327: 
        !          1328:   /* Install description commands. */
        !          1329:   install_element (RMAP_NODE, &rmap_description_cmd);
        !          1330:   install_element (RMAP_NODE, &no_rmap_description_cmd);
        !          1331:    
        !          1332:   /* Install show command */
        !          1333:   install_element (ENABLE_NODE, &rmap_show_name_cmd);
        !          1334: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>