File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / lib / routemap.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:09:11 2016 UTC (8 years ago) by misho
Branches: quagga, MAIN
CVS tags: v1_0_20160315, HEAD
quagga 1.0.20160315

    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:   /* cleanup route_map */                                                    
  901:   while (route_map_master.head)                                              
  902:     route_map_delete (route_map_master.head); 
  903: }
  904: 
  905: /* VTY related functions. */
  906: DEFUN (route_map,
  907:        route_map_cmd,
  908:        "route-map WORD (deny|permit) <1-65535>",
  909:        "Create route-map or enter route-map command mode\n"
  910:        "Route map tag\n"
  911:        "Route map denies set operations\n"
  912:        "Route map permits set operations\n"
  913:        "Sequence to insert to/delete from existing route-map entry\n")
  914: {
  915:   int permit;
  916:   unsigned long pref;
  917:   struct route_map *map;
  918:   struct route_map_index *index;
  919:   char *endptr = NULL;
  920: 
  921:   /* Permit check. */
  922:   if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
  923:     permit = RMAP_PERMIT;
  924:   else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
  925:     permit = RMAP_DENY;
  926:   else
  927:     {
  928:       vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
  929:       return CMD_WARNING;
  930:     }
  931: 
  932:   /* Preference check. */
  933:   pref = strtoul (argv[2], &endptr, 10);
  934:   if (pref == ULONG_MAX || *endptr != '\0')
  935:     {
  936:       vty_out (vty, "the fourth field must be positive integer%s",
  937: 	       VTY_NEWLINE);
  938:       return CMD_WARNING;
  939:     }
  940:   if (pref == 0 || pref > 65535)
  941:     {
  942:       vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
  943:       return CMD_WARNING;
  944:     }
  945: 
  946:   /* Get route map. */
  947:   map = route_map_get (argv[0]);
  948:   index = route_map_index_get (map, permit, pref);
  949: 
  950:   vty->index = index;
  951:   vty->node = RMAP_NODE;
  952:   return CMD_SUCCESS;
  953: }
  954: 
  955: DEFUN (no_route_map_all,
  956:        no_route_map_all_cmd,
  957:        "no route-map WORD",
  958:        NO_STR
  959:        "Create route-map or enter route-map command mode\n"
  960:        "Route map tag\n")
  961: {
  962:   struct route_map *map;
  963: 
  964:   map = route_map_lookup_by_name (argv[0]);
  965:   if (map == NULL)
  966:     {
  967:       vty_out (vty, "%% Could not find route-map %s%s",
  968: 	       argv[0], VTY_NEWLINE);
  969:       return CMD_WARNING;
  970:     }
  971: 
  972:   route_map_delete (map);
  973: 
  974:   return CMD_SUCCESS;
  975: }
  976: 
  977: DEFUN (no_route_map,
  978:        no_route_map_cmd,
  979:        "no route-map WORD (deny|permit) <1-65535>",
  980:        NO_STR
  981:        "Create route-map or enter route-map command mode\n"
  982:        "Route map tag\n"
  983:        "Route map denies set operations\n"
  984:        "Route map permits set operations\n"
  985:        "Sequence to insert to/delete from existing route-map entry\n")
  986: {
  987:   int permit;
  988:   unsigned long pref;
  989:   struct route_map *map;
  990:   struct route_map_index *index;
  991:   char *endptr = NULL;
  992: 
  993:   /* Permit check. */
  994:   if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
  995:     permit = RMAP_PERMIT;
  996:   else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
  997:     permit = RMAP_DENY;
  998:   else
  999:     {
 1000:       vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
 1001:       return CMD_WARNING;
 1002:     }
 1003: 
 1004:   /* Preference. */
 1005:   pref = strtoul (argv[2], &endptr, 10);
 1006:   if (pref == ULONG_MAX || *endptr != '\0')
 1007:     {
 1008:       vty_out (vty, "the fourth field must be positive integer%s",
 1009: 	       VTY_NEWLINE);
 1010:       return CMD_WARNING;
 1011:     }
 1012:   if (pref == 0 || pref > 65535)
 1013:     {
 1014:       vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
 1015:       return CMD_WARNING;
 1016:     }
 1017: 
 1018:   /* Existence check. */
 1019:   map = route_map_lookup_by_name (argv[0]);
 1020:   if (map == NULL)
 1021:     {
 1022:       vty_out (vty, "%% Could not find route-map %s%s",
 1023: 	       argv[0], VTY_NEWLINE);
 1024:       return CMD_WARNING;
 1025:     }
 1026: 
 1027:   /* Lookup route map index. */
 1028:   index = route_map_index_lookup (map, permit, pref);
 1029:   if (index == NULL)
 1030:     {
 1031:       vty_out (vty, "%% Could not find route-map entry %s %s%s", 
 1032: 	       argv[0], argv[2], VTY_NEWLINE);
 1033:       return CMD_WARNING;
 1034:     }
 1035: 
 1036:   /* Delete index from route map. */
 1037:   route_map_index_delete (index, 1);
 1038: 
 1039:   /* If this route rule is the last one, delete route map itself. */
 1040:   if (route_map_empty (map))
 1041:     route_map_delete (map);
 1042: 
 1043:   return CMD_SUCCESS;
 1044: }
 1045: 
 1046: DEFUN (rmap_onmatch_next,
 1047:        rmap_onmatch_next_cmd,
 1048:        "on-match next",
 1049:        "Exit policy on matches\n"
 1050:        "Next clause\n")
 1051: {
 1052:   struct route_map_index *index;
 1053: 
 1054:   index = vty->index;
 1055: 
 1056:   if (index)
 1057:     index->exitpolicy = RMAP_NEXT;
 1058: 
 1059:   return CMD_SUCCESS;
 1060: }
 1061: 
 1062: DEFUN (no_rmap_onmatch_next,
 1063:        no_rmap_onmatch_next_cmd,
 1064:        "no on-match next",
 1065:        NO_STR
 1066:        "Exit policy on matches\n"
 1067:        "Next clause\n")
 1068: {
 1069:   struct route_map_index *index;
 1070: 
 1071:   index = vty->index;
 1072:   
 1073:   if (index)
 1074:     index->exitpolicy = RMAP_EXIT;
 1075: 
 1076:   return CMD_SUCCESS;
 1077: }
 1078: 
 1079: DEFUN (rmap_onmatch_goto,
 1080:        rmap_onmatch_goto_cmd,
 1081:        "on-match goto <1-65535>",
 1082:        "Exit policy on matches\n"
 1083:        "Goto Clause number\n"
 1084:        "Number\n")
 1085: {
 1086:   struct route_map_index *index = vty->index;
 1087:   int d = 0;
 1088: 
 1089:   if (index)
 1090:     {
 1091:       if (argc == 1 && argv[0])
 1092:         VTY_GET_INTEGER_RANGE("route-map index", d, argv[0], 1, 65536);
 1093:       else
 1094:         d = index->pref + 1;
 1095:       
 1096:       if (d <= index->pref)
 1097: 	{
 1098: 	  /* Can't allow you to do that, Dave */
 1099: 	  vty_out (vty, "can't jump backwards in route-maps%s", 
 1100: 		   VTY_NEWLINE);
 1101: 	  return CMD_WARNING;
 1102: 	}
 1103:       else
 1104: 	{
 1105: 	  index->exitpolicy = RMAP_GOTO;
 1106: 	  index->nextpref = d;
 1107: 	}
 1108:     }
 1109:   return CMD_SUCCESS;
 1110: }
 1111: 
 1112: DEFUN (no_rmap_onmatch_goto,
 1113:        no_rmap_onmatch_goto_cmd,
 1114:        "no on-match goto",
 1115:        NO_STR
 1116:        "Exit policy on matches\n"
 1117:        "Goto Clause number\n")
 1118: {
 1119:   struct route_map_index *index;
 1120: 
 1121:   index = vty->index;
 1122: 
 1123:   if (index)
 1124:     index->exitpolicy = RMAP_EXIT;
 1125:   
 1126:   return CMD_SUCCESS;
 1127: }
 1128: 
 1129: /* Cisco/GNU Zebra compatible ALIASes for on-match next */
 1130: ALIAS (rmap_onmatch_goto,
 1131:        rmap_continue_cmd,
 1132:        "continue",
 1133:        "Continue on a different entry within the route-map\n")
 1134: 
 1135: ALIAS (no_rmap_onmatch_goto,
 1136:        no_rmap_continue_cmd,
 1137:        "no continue",
 1138:        NO_STR
 1139:        "Continue on a different entry within the route-map\n")
 1140: 
 1141: /* GNU Zebra compatible */
 1142: ALIAS (rmap_onmatch_goto,
 1143:        rmap_continue_seq_cmd,
 1144:        "continue <1-65535>",
 1145:        "Continue on a different entry within the route-map\n"
 1146:        "Route-map entry sequence number\n")
 1147: 
 1148: ALIAS (no_rmap_onmatch_goto,
 1149:        no_rmap_continue_seq,
 1150:        "no continue <1-65535>",
 1151:        NO_STR
 1152:        "Continue on a different entry within the route-map\n"
 1153:        "Route-map entry sequence number\n")
 1154: 
 1155: DEFUN (rmap_show_name,
 1156:        rmap_show_name_cmd,
 1157:        "show route-map [WORD]",
 1158:        SHOW_STR
 1159:        "route-map information\n"
 1160:        "route-map name\n")
 1161: {
 1162:     const char *name = NULL;
 1163:     if (argc)
 1164:       name = argv[0];
 1165:     return vty_show_route_map (vty, name);
 1166: }
 1167: 
 1168: ALIAS (rmap_onmatch_goto,
 1169:       rmap_continue_index_cmd,
 1170:       "continue <1-65536>",
 1171:       "Exit policy on matches\n"
 1172:       "Goto Clause number\n")
 1173: 
 1174: DEFUN (rmap_call,
 1175:        rmap_call_cmd,
 1176:        "call WORD",
 1177:        "Jump to another Route-Map after match+set\n"
 1178:        "Target route-map name\n")
 1179: {
 1180:   struct route_map_index *index;
 1181: 
 1182:   index = vty->index;
 1183:   if (index)
 1184:     {
 1185:       if (index->nextrm)
 1186:           XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
 1187:       index->nextrm = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[0]);
 1188:     }
 1189:   return CMD_SUCCESS;
 1190: }
 1191: 
 1192: DEFUN (no_rmap_call,
 1193:        no_rmap_call_cmd,
 1194:        "no call",
 1195:        NO_STR
 1196:        "Jump to another Route-Map after match+set\n")
 1197: {
 1198:   struct route_map_index *index;
 1199: 
 1200:   index = vty->index;
 1201: 
 1202:   if (index->nextrm)
 1203:     {
 1204:       XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
 1205:       index->nextrm = NULL;
 1206:     }
 1207: 
 1208:   return CMD_SUCCESS;
 1209: }
 1210: 
 1211: DEFUN (rmap_description,
 1212:        rmap_description_cmd,
 1213:        "description .LINE",
 1214:        "Route-map comment\n"
 1215:        "Comment describing this route-map rule\n")
 1216: {
 1217:   struct route_map_index *index;
 1218: 
 1219:   index = vty->index;
 1220:   if (index)
 1221:     {
 1222:       if (index->description)
 1223: 	XFREE (MTYPE_TMP, index->description);
 1224:       index->description = argv_concat (argv, argc, 0);
 1225:     }
 1226:   return CMD_SUCCESS;
 1227: }
 1228: 
 1229: DEFUN (no_rmap_description,
 1230:        no_rmap_description_cmd,
 1231:        "no description",
 1232:        NO_STR
 1233:        "Route-map comment\n")
 1234: {
 1235:   struct route_map_index *index;
 1236: 
 1237:   index = vty->index;
 1238:   if (index)
 1239:     {
 1240:       if (index->description)
 1241: 	XFREE (MTYPE_TMP, index->description);
 1242:       index->description = NULL;
 1243:     }
 1244:   return CMD_SUCCESS;
 1245: }
 1246: 
 1247: /* Configuration write function. */
 1248: static int
 1249: route_map_config_write (struct vty *vty)
 1250: {
 1251:   struct route_map *map;
 1252:   struct route_map_index *index;
 1253:   struct route_map_rule *rule;
 1254:   int first = 1;
 1255:   int write = 0;
 1256: 
 1257:   for (map = route_map_master.head; map; map = map->next)
 1258:     for (index = map->head; index; index = index->next)
 1259:       {
 1260: 	if (!first)
 1261: 	  vty_out (vty, "!%s", VTY_NEWLINE);
 1262: 	else
 1263: 	  first = 0;
 1264: 
 1265: 	vty_out (vty, "route-map %s %s %d%s", 
 1266: 		 map->name,
 1267: 		 route_map_type_str (index->type),
 1268: 		 index->pref, VTY_NEWLINE);
 1269: 
 1270: 	if (index->description)
 1271: 	  vty_out (vty, " description %s%s", index->description, VTY_NEWLINE);
 1272: 
 1273: 	for (rule = index->match_list.head; rule; rule = rule->next)
 1274: 	  vty_out (vty, " match %s %s%s", rule->cmd->str, 
 1275: 		   rule->rule_str ? rule->rule_str : "",
 1276: 		   VTY_NEWLINE);
 1277: 
 1278: 	for (rule = index->set_list.head; rule; rule = rule->next)
 1279: 	  vty_out (vty, " set %s %s%s", rule->cmd->str,
 1280: 		   rule->rule_str ? rule->rule_str : "",
 1281: 		   VTY_NEWLINE);
 1282:    if (index->nextrm)
 1283:      vty_out (vty, " call %s%s", index->nextrm, VTY_NEWLINE);
 1284: 	if (index->exitpolicy == RMAP_GOTO)
 1285:       vty_out (vty, " on-match goto %d%s", index->nextpref, VTY_NEWLINE);
 1286: 	if (index->exitpolicy == RMAP_NEXT)
 1287: 	  vty_out (vty," on-match next%s", VTY_NEWLINE);
 1288: 	
 1289: 	write++;
 1290:       }
 1291:   return write;
 1292: }
 1293: 
 1294: /* Route map node structure. */
 1295: static struct cmd_node rmap_node =
 1296: {
 1297:   RMAP_NODE,
 1298:   "%s(config-route-map)# ",
 1299:   1
 1300: };
 1301: 
 1302: /* Initialization of route map vector. */
 1303: void
 1304: route_map_init_vty (void)
 1305: {
 1306:   /* Install route map top node. */
 1307:   install_node (&rmap_node, route_map_config_write);
 1308: 
 1309:   /* Install route map commands. */
 1310:   install_default (RMAP_NODE);
 1311:   install_element (CONFIG_NODE, &route_map_cmd);
 1312:   install_element (CONFIG_NODE, &no_route_map_cmd);
 1313:   install_element (CONFIG_NODE, &no_route_map_all_cmd);
 1314: 
 1315:   /* Install the on-match stuff */
 1316:   install_element (RMAP_NODE, &route_map_cmd);
 1317:   install_element (RMAP_NODE, &rmap_onmatch_next_cmd);
 1318:   install_element (RMAP_NODE, &no_rmap_onmatch_next_cmd);
 1319:   install_element (RMAP_NODE, &rmap_onmatch_goto_cmd);
 1320:   install_element (RMAP_NODE, &no_rmap_onmatch_goto_cmd);
 1321:   
 1322:   /* Install the continue stuff (ALIAS of on-match). */
 1323:   install_element (RMAP_NODE, &rmap_continue_cmd);
 1324:   install_element (RMAP_NODE, &no_rmap_continue_cmd);
 1325:   install_element (RMAP_NODE, &rmap_continue_index_cmd);
 1326:   
 1327:   /* Install the call stuff. */
 1328:   install_element (RMAP_NODE, &rmap_call_cmd);
 1329:   install_element (RMAP_NODE, &no_rmap_call_cmd);
 1330: 
 1331:   /* Install description commands. */
 1332:   install_element (RMAP_NODE, &rmap_description_cmd);
 1333:   install_element (RMAP_NODE, &no_rmap_description_cmd);
 1334:    
 1335:   /* Install show command */
 1336:   install_element (ENABLE_NODE, &rmap_show_name_cmd);
 1337: }

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