File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / lib / routemap.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:26:12 2012 UTC (12 years, 4 months ago) by misho
Branches: quagga, MAIN
CVS tags: v0_99_22p0, v0_99_22, v0_99_21, v0_99_20_1, v0_99_20, HEAD
quagga

    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>