routemap.c
上传用户:xiaozhuqw
上传日期:2009-11-15
资源大小:1338k
文件大小:27k
源码类别:

网络

开发平台:

Unix_Linux

  1. /* Route map function.
  2.    Copyright (C) 1998, 1999 Kunihiro Ishiguro
  3. This file is part of GNU Zebra.
  4. GNU Zebra is free software; you can redistribute it and/or modify it
  5. under the terms of the GNU General Public License as published by the
  6. Free Software Foundation; either version 2, or (at your option) any
  7. later version.
  8. GNU Zebra is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNU Zebra; see the file COPYING.  If not, write to the Free
  14. Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  15. 02111-1307, USA.  */
  16. #include <zebra.h>
  17. #include "linklist.h"
  18. #include "memory.h"
  19. #include "vector.h"
  20. #include "prefix.h"
  21. #include "routemap.h"
  22. #include "command.h"
  23. /* Vector for route match rules. */
  24. static vector route_match_vec;
  25. /* Vector for route set rules. */
  26. static vector route_set_vec;
  27. /* Route map rule. This rule has both `match' rule and `set' rule. */
  28. struct route_map_rule
  29. {
  30.   /* Rule type. */
  31.   struct route_map_rule_cmd *cmd;
  32.   /* For pretty printing. */
  33.   char *rule_str;
  34.   /* Pre-compiled match rule. */
  35.   void *value;
  36.   /* Linked list. */
  37.   struct route_map_rule *next;
  38.   struct route_map_rule *prev;
  39. };
  40. /* Making route map list. */
  41. struct route_map_list
  42. {
  43.   struct route_map *head;
  44.   struct route_map *tail;
  45.   void (*add_hook) (char *);
  46.   void (*delete_hook) (char *);
  47.   void (*event_hook) (route_map_event_t, char *); 
  48. };
  49. /* Master list of route map. */
  50. static struct route_map_list route_map_master = { NULL, NULL, NULL, NULL };
  51. static void
  52. route_map_rule_delete (struct route_map_rule_list *,
  53.        struct route_map_rule *);
  54. static void
  55. route_map_index_delete (struct route_map_index *, int);
  56. /* New route map allocation. Please note route map's name must be
  57.    specified. */
  58. static struct route_map *
  59. route_map_new (char *name)
  60. {
  61.   struct route_map *new;
  62.   new =  XCALLOC (MTYPE_ROUTE_MAP, sizeof (struct route_map));
  63.   new->name = XSTRDUP (MTYPE_ROUTE_MAP_NAME, name);
  64.   return new;
  65. }
  66. /* Add new name to route_map. */
  67. static struct route_map *
  68. route_map_add (char *name)
  69. {
  70.   struct route_map *map;
  71.   struct route_map_list *list;
  72.   map = route_map_new (name);
  73.   list = &route_map_master;
  74.     
  75.   map->next = NULL;
  76.   map->prev = list->tail;
  77.   if (list->tail)
  78.     list->tail->next = map;
  79.   else
  80.     list->head = map;
  81.   list->tail = map;
  82.   /* Execute hook. */
  83.   if (route_map_master.add_hook)
  84.     (*route_map_master.add_hook) (name);
  85.   return map;
  86. }
  87. /* Route map delete from list. */
  88. static void
  89. route_map_delete (struct route_map *map)
  90. {
  91.   struct route_map_list *list;
  92.   struct route_map_index *index;
  93.   char *name;
  94.   
  95.   while ((index = map->head) != NULL)
  96.     route_map_index_delete (index, 0);
  97.   name = map->name;
  98.   list = &route_map_master;
  99.   if (map->next)
  100.     map->next->prev = map->prev;
  101.   else
  102.     list->tail = map->prev;
  103.   if (map->prev)
  104.     map->prev->next = map->next;
  105.   else
  106.     list->head = map->next;
  107.   XFREE (MTYPE_ROUTE_MAP, map);
  108.   /* Execute deletion hook. */
  109.   if (route_map_master.delete_hook)
  110.     (*route_map_master.delete_hook) (name);
  111.   if (name)
  112.     XFREE (MTYPE_ROUTE_MAP_NAME, name);
  113. }
  114. /* Lookup route map by route map name string. */
  115. struct route_map *
  116. route_map_lookup_by_name (char *name)
  117. {
  118.   struct route_map *map;
  119.   for (map = route_map_master.head; map; map = map->next)
  120.     if (strcmp (map->name, name) == 0)
  121.       return map;
  122.   return NULL;
  123. }
  124. /* Lookup route map.  If there isn't route map create one and return
  125.    it. */
  126. struct route_map *
  127. route_map_get (char *name)
  128. {
  129.   struct route_map *map;
  130.   map = route_map_lookup_by_name (name);
  131.   if (map == NULL)
  132.     map = route_map_add (name);
  133.   return map;
  134. }
  135. /* Return route map's type string. */
  136. static char *
  137. route_map_type_str (enum route_map_type type)
  138. {
  139.   switch (type)
  140.     {
  141.     case RMAP_PERMIT:
  142.       return "permit";
  143.       break;
  144.     case RMAP_DENY:
  145.       return "deny";
  146.       break;
  147.     default:
  148.       return "";
  149.       break;
  150.     }
  151. }
  152. int
  153. route_map_empty (struct route_map *map)
  154. {
  155.   if (map->head == NULL && map->tail == NULL)
  156.     return 1;
  157.   else
  158.     return 0;
  159. }
  160. /* show route-map */
  161. void
  162. vty_show_route_map_entry (struct vty *vty, struct route_map *map)
  163. {
  164.   struct route_map_rule *rule;
  165.   struct route_map_index *index;
  166.   for (index = map->head; index; index = index->next)
  167.     {
  168.       vty_out (vty, "route-map %s, %s, sequence %d%s", 
  169.        map->name,
  170.        route_map_type_str (index->type),
  171.        index->pref,
  172.        VTY_NEWLINE);
  173.       /* Match clauses */
  174.       vty_out (vty, "  Match clauses:%s", VTY_NEWLINE);
  175.       for (rule = index->match_list.head; rule; rule = rule->next)
  176. vty_out (vty, "    %s %s%s", rule->cmd->str, rule->rule_str, VTY_NEWLINE);
  177.       if (index->exitpolicy == RMAP_GOTO)
  178. vty_out (vty, "  Continue: sequence %d%s", index->nextpref, VTY_NEWLINE);
  179.       if (index->exitpolicy == RMAP_NEXT)
  180. {
  181.   vty_out (vty, "  Continue: to next entry");
  182.   if (index->next)
  183.     vty_out (vty, " %d%s", index->next->pref, VTY_NEWLINE);
  184.   else
  185.     vty_out (vty, " is undefined%s", VTY_NEWLINE);
  186. }
  187.       /* Set clauses */
  188.       vty_out (vty, "  Set clauses:%s", VTY_NEWLINE);
  189.       for (rule = index->set_list.head; rule; rule = rule->next)
  190. vty_out (vty, "    %s %s%s", rule->cmd->str, rule->rule_str, VTY_NEWLINE);
  191.     }
  192. }
  193. int
  194. vty_show_route_map (struct vty *vty, char *name)
  195. {
  196.   struct route_map *map;
  197.   if (name)
  198.     {
  199.       map = route_map_lookup_by_name (name);
  200.       if (map)
  201. {
  202.   vty_show_route_map_entry (vty, map);
  203.   return CMD_SUCCESS;
  204. }
  205.       else
  206. {
  207.   vty_out (vty, "%%route-map %s not found%s", name, VTY_NEWLINE);
  208.   return CMD_WARNING;
  209. }
  210.     }
  211.   for (map = route_map_master.head; map; map = map->next)
  212.     vty_show_route_map_entry (vty, map);
  213.   return CMD_SUCCESS;
  214. }
  215. /* New route map allocation. Please note route map's name must be
  216.    specified. */
  217. struct route_map_index *
  218. route_map_index_new ()
  219. {
  220.   struct route_map_index *new;
  221.   new =  XCALLOC (MTYPE_ROUTE_MAP_INDEX, sizeof (struct route_map_index));
  222.   new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */
  223.   return new;
  224. }
  225. /* Free route map index. */
  226. static void
  227. route_map_index_delete (struct route_map_index *index, int notify)
  228. {
  229.   struct route_map_rule *rule;
  230.   /* Free route match. */
  231.   while ((rule = index->match_list.head) != NULL)
  232.     route_map_rule_delete (&index->match_list, rule);
  233.   /* Free route set. */
  234.   while ((rule = index->set_list.head) != NULL)
  235.     route_map_rule_delete (&index->set_list, rule);
  236.   /* Remove index from route map list. */
  237.   if (index->next)
  238.     index->next->prev = index->prev;
  239.   else
  240.     index->map->tail = index->prev;
  241.   if (index->prev)
  242.     index->prev->next = index->next;
  243.   else
  244.     index->map->head = index->next;
  245.     /* Execute event hook. */
  246.   if (route_map_master.event_hook && notify)
  247.     (*route_map_master.event_hook) (RMAP_EVENT_INDEX_DELETED,
  248.     index->map->name);
  249.   XFREE (MTYPE_ROUTE_MAP_INDEX, index);
  250. }
  251. /* Lookup index from route map. */
  252. struct route_map_index *
  253. route_map_index_lookup (struct route_map *map, enum route_map_type type,
  254. int pref)
  255. {
  256.   struct route_map_index *index;
  257.   for (index = map->head; index; index = index->next)
  258.     if ((index->type == type || type == RMAP_ANY)
  259. && index->pref == pref)
  260.       return index;
  261.   return NULL;
  262. }
  263. /* Add new index to route map. */
  264. struct route_map_index *
  265. route_map_index_add (struct route_map *map, enum route_map_type type,
  266.      int pref)
  267. {
  268.   struct route_map_index *index;
  269.   struct route_map_index *point;
  270.   /* Allocate new route map inex. */
  271.   index = route_map_index_new ();
  272.   index->map = map;
  273.   index->type = type;
  274.   index->pref = pref;
  275.   
  276.   /* Compare preference. */
  277.   for (point = map->head; point; point = point->next)
  278.     if (point->pref >= pref)
  279.       break;
  280.   if (map->head == NULL)
  281.     {
  282.       map->head = map->tail = index;
  283.     }
  284.   else if (point == NULL)
  285.     {
  286.       index->prev = map->tail;
  287.       map->tail->next = index;
  288.       map->tail = index;
  289.     }
  290.   else if (point == map->head)
  291.     {
  292.       index->next = map->head;
  293.       map->head->prev = index;
  294.       map->head = index;
  295.     }
  296.   else
  297.     {
  298.       index->next = point;
  299.       index->prev = point->prev;
  300.       if (point->prev)
  301. point->prev->next = index;
  302.       point->prev = index;
  303.     }
  304.   /* Execute event hook. */
  305.   if (route_map_master.event_hook)
  306.     (*route_map_master.event_hook) (RMAP_EVENT_INDEX_ADDED,
  307.     map->name);
  308.   return index;
  309. }
  310. /* Get route map index. */
  311. struct route_map_index *
  312. route_map_index_get (struct route_map *map, enum route_map_type type, 
  313.      int pref)
  314. {
  315.   struct route_map_index *index;
  316.   index = route_map_index_lookup (map, RMAP_ANY, pref);
  317.   if (index && index->type != type)
  318.     {
  319.       /* Delete index from route map. */
  320.       route_map_index_delete (index, 1);
  321.       index = NULL;
  322.     }
  323.   if (index == NULL)
  324.     index = route_map_index_add (map, type, pref);
  325.   return index;
  326. }
  327. /* New route map rule */
  328. struct route_map_rule *
  329. route_map_rule_new ()
  330. {
  331.   struct route_map_rule *new;
  332.   new = XCALLOC (MTYPE_ROUTE_MAP_RULE, sizeof (struct route_map_rule));
  333.   return new;
  334. }
  335. /* Install rule command to the match list. */
  336. void
  337. route_map_install_match (struct route_map_rule_cmd *cmd)
  338. {
  339.   vector_set (route_match_vec, cmd);
  340. }
  341. /* Install rule command to the set list. */
  342. void
  343. route_map_install_set (struct route_map_rule_cmd *cmd)
  344. {
  345.   vector_set (route_set_vec, cmd);
  346. }
  347. /* Lookup rule command from match list. */
  348. struct route_map_rule_cmd *
  349. route_map_lookup_match (char *name)
  350. {
  351.   int i;
  352.   struct route_map_rule_cmd *rule;
  353.   for (i = 0; i < vector_max (route_match_vec); i++)
  354.     if ((rule = vector_slot (route_match_vec, i)) != NULL)
  355.       if (strcmp (rule->str, name) == 0)
  356. return rule;
  357.   return NULL;
  358. }
  359. /* Lookup rule command from set list. */
  360. struct route_map_rule_cmd *
  361. route_map_lookup_set (char *name)
  362. {
  363.   int i;
  364.   struct route_map_rule_cmd *rule;
  365.   for (i = 0; i < vector_max (route_set_vec); i++)
  366.     if ((rule = vector_slot (route_set_vec, i)) != NULL)
  367.       if (strcmp (rule->str, name) == 0)
  368. return rule;
  369.   return NULL;
  370. }
  371. /* Add match and set rule to rule list. */
  372. static void
  373. route_map_rule_add (struct route_map_rule_list *list,
  374.     struct route_map_rule *rule)
  375. {
  376.   rule->next = NULL;
  377.   rule->prev = list->tail;
  378.   if (list->tail)
  379.     list->tail->next = rule;
  380.   else
  381.     list->head = rule;
  382.   list->tail = rule;
  383. }
  384. /* Delete rule from rule list. */
  385. static void
  386. route_map_rule_delete (struct route_map_rule_list *list,
  387.        struct route_map_rule *rule)
  388. {
  389.   if (rule->cmd->func_free)
  390.     (*rule->cmd->func_free) (rule->value);
  391.   if (rule->rule_str)
  392.     XFREE (MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str);
  393.   if (rule->next)
  394.     rule->next->prev = rule->prev;
  395.   else
  396.     list->tail = rule->prev;
  397.   if (rule->prev)
  398.     rule->prev->next = rule->next;
  399.   else
  400.     list->head = rule->next;
  401.   XFREE (MTYPE_ROUTE_MAP_RULE, rule);
  402. }
  403. /* strcmp wrapper function which don't crush even argument is NULL. */
  404. int
  405. rulecmp (char *dst, char *src)
  406. {
  407.   if (dst == NULL)
  408.     {
  409.       if (src ==  NULL)
  410. return 0;
  411.       else
  412. return 1;
  413.     }
  414.   else
  415.     {
  416.       if (src == NULL)
  417. return 1;
  418.       else
  419. return strcmp (dst, src);
  420.     }
  421.   return 1;
  422. }
  423. /* Add match statement to route map. */
  424. int
  425. route_map_add_match (struct route_map_index *index, char *match_name,
  426.      char *match_arg)
  427. {
  428.   struct route_map_rule *rule;
  429.   struct route_map_rule *next;
  430.   struct route_map_rule_cmd *cmd;
  431.   void *compile;
  432.   int replaced = 0;
  433.   /* First lookup rule for add match statement. */
  434.   cmd = route_map_lookup_match (match_name);
  435.   if (cmd == NULL)
  436.     return RMAP_RULE_MISSING;
  437.   /* Next call compile function for this match statement. */
  438.   if (cmd->func_compile)
  439.     {
  440.       compile= (*cmd->func_compile)(match_arg);
  441.       if (compile == NULL)
  442. return RMAP_COMPILE_ERROR;
  443.     }
  444.   else
  445.     compile = NULL;
  446.   /* If argument is completely same ignore it. */
  447.   for (rule = index->match_list.head; rule; rule = next)
  448.     {
  449.       next = rule->next;
  450.       if (rule->cmd == cmd)
  451. {
  452.   route_map_rule_delete (&index->match_list, rule);
  453.   replaced = 1;
  454. }
  455.     }
  456.   /* Add new route map match rule. */
  457.   rule = route_map_rule_new ();
  458.   rule->cmd = cmd;
  459.   rule->value = compile;
  460.   if (match_arg)
  461.     rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, match_arg);
  462.   else
  463.     rule->rule_str = NULL;
  464.   /* Add new route match rule to linked list. */
  465.   route_map_rule_add (&index->match_list, rule);
  466.   /* Execute event hook. */
  467.   if (route_map_master.event_hook)
  468.     (*route_map_master.event_hook) (replaced ?
  469.     RMAP_EVENT_MATCH_REPLACED:
  470.     RMAP_EVENT_MATCH_ADDED,
  471.     index->map->name);
  472.   return 0;
  473. }
  474. /* Delete specified route match rule. */
  475. int
  476. route_map_delete_match (struct route_map_index *index, char *match_name,
  477. char *match_arg)
  478. {
  479.   struct route_map_rule *rule;
  480.   struct route_map_rule_cmd *cmd;
  481.   cmd = route_map_lookup_match (match_name);
  482.   if (cmd == NULL)
  483.     return 1;
  484.   
  485.   for (rule = index->match_list.head; rule; rule = rule->next)
  486.     if (rule->cmd == cmd && 
  487. (rulecmp (rule->rule_str, match_arg) == 0 || match_arg == NULL))
  488.       {
  489. route_map_rule_delete (&index->match_list, rule);
  490. /* Execute event hook. */
  491. if (route_map_master.event_hook)
  492.   (*route_map_master.event_hook) (RMAP_EVENT_MATCH_DELETED,
  493.   index->map->name);
  494. return 0;
  495.       }
  496.   /* Can't find matched rule. */
  497.   return 1;
  498. }
  499. /* Add route-map set statement to the route map. */
  500. int
  501. route_map_add_set (struct route_map_index *index, char *set_name,
  502.    char *set_arg)
  503. {
  504.   struct route_map_rule *rule;
  505.   struct route_map_rule *next;
  506.   struct route_map_rule_cmd *cmd;
  507.   void *compile;
  508.   int replaced = 0;
  509.   cmd = route_map_lookup_set (set_name);
  510.   if (cmd == NULL)
  511.     return RMAP_RULE_MISSING;
  512.   /* Next call compile function for this match statement. */
  513.   if (cmd->func_compile)
  514.     {
  515.       compile= (*cmd->func_compile)(set_arg);
  516.       if (compile == NULL)
  517. return RMAP_COMPILE_ERROR;
  518.     }
  519.   else
  520.     compile = NULL;
  521.  /* Add by WJL. if old set command of same kind exist, delete it first
  522.     to ensure only one set command of same kind exist under a
  523.     route_map_index. */
  524.   for (rule = index->set_list.head; rule; rule = next)
  525.     {
  526.       next = rule->next;
  527.       if (rule->cmd == cmd)
  528. {
  529.   route_map_rule_delete (&index->set_list, rule);
  530.   replaced = 1;
  531. }
  532.     }
  533.   /* Add new route map match rule. */
  534.   rule = route_map_rule_new ();
  535.   rule->cmd = cmd;
  536.   rule->value = compile;
  537.   if (set_arg)
  538.     rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, set_arg);
  539.   else
  540.     rule->rule_str = NULL;
  541.   /* Add new route match rule to linked list. */
  542.   route_map_rule_add (&index->set_list, rule);
  543.   /* Execute event hook. */
  544.   if (route_map_master.event_hook)
  545.     (*route_map_master.event_hook) (replaced ?
  546.     RMAP_EVENT_SET_REPLACED:
  547.     RMAP_EVENT_SET_ADDED,
  548.     index->map->name);
  549.   return 0;
  550. }
  551. /* Delete route map set rule. */
  552. int
  553. route_map_delete_set (struct route_map_index *index, char *set_name,
  554. char *set_arg)
  555. {
  556.   struct route_map_rule *rule;
  557.   struct route_map_rule_cmd *cmd;
  558.   cmd = route_map_lookup_set (set_name);
  559.   if (cmd == NULL)
  560.     return 1;
  561.   
  562.   for (rule = index->set_list.head; rule; rule = rule->next)
  563.     if ((rule->cmd == cmd) &&
  564.          (rulecmp (rule->rule_str, set_arg) == 0 || set_arg == NULL))
  565.       {
  566.         route_map_rule_delete (&index->set_list, rule);
  567. /* Execute event hook. */
  568. if (route_map_master.event_hook)
  569.   (*route_map_master.event_hook) (RMAP_EVENT_SET_DELETED,
  570.   index->map->name);
  571.         return 0;
  572.       }
  573.   /* Can't find matched rule. */
  574.   return 1;
  575. }
  576. /* Apply route map's each index to the object.
  577.    The matrix for a route-map looks like this:
  578.    (note, this includes the description for the "NEXT"
  579.    and "GOTO" frobs now
  580.   
  581.               Match   |   No Match
  582.                       |
  583.     permit      a     |      c
  584.                       |
  585.     ------------------+---------------
  586.                       |
  587.     deny        b     |      d
  588.                       |
  589.   
  590.    a) Apply Set statements, accept route
  591.       If NEXT is specified, goto NEXT statement
  592.       If GOTO is specified, goto the first clause where pref > nextpref
  593.       If nothing is specified, do as Cisco and finish
  594.    b) If NEXT is specified, goto NEXT statement
  595.       If nothing is specified, finally will be denied by route-map.
  596.    c) & d)   Goto Next index
  597.   
  598.    If we get no matches after we've processed all updates, then the route
  599.    is dropped too.
  600.   
  601.    Some notes on the new "NEXT" and "GOTO"
  602.      continue         - If this clause is matched, then the set statements
  603.                         are executed and then we drop through to the next clause
  604.      continue n       - If this clause is matched, then the set statments
  605.                         are executed and then we goto the nth clause, or the
  606.                         first clause greater than this. In order to ensure
  607.                         route-maps *always* exit, you cannot jump backwards.
  608.                         Sorry ;)
  609.   
  610.    We need to make sure our route-map processing matches the above
  611. */
  612. route_map_result_t
  613. route_map_apply_index (struct route_map_index *index, struct prefix *prefix,
  614.                        route_map_object_t type, void *object)
  615. {
  616.   int ret = 0;
  617.   struct route_map_rule *match;
  618.   struct route_map_rule *set;
  619.   /* Check all match rule and if there is no match rule, go to the
  620.      set statement. */
  621.   if (! index->match_list.head)
  622.     ret = RMAP_MATCH;
  623.   else
  624.     {
  625.       for (match = index->match_list.head; match; match = match->next)
  626.         {
  627.           /* Try each match statement in turn, If any return
  628.              RMAP_MATCH, go direct to set statement, otherwise, walk
  629.              to next match statement. */ 
  630.           ret = (*match->cmd->func_apply)(match->value, prefix, type, object);
  631.           if (ret == RMAP_MATCH)
  632.             break;
  633. }
  634.     }
  635.   /* If end of match statement, still can't get any RMAP_MATCH return,
  636.      just return to next rout-map statement. */
  637.   if (ret != RMAP_MATCH)
  638.     return ret;
  639.   /* We get here if all match statements matched From the matrix
  640.      above, if this is PERMIT we go on and apply the SET functions.
  641.      If we're deny, we return indicating we matched a deny */
  642.   /* Apply set statement to the object. */
  643.   if (index->type == RMAP_PERMIT)
  644.     {
  645.       for (set = index->set_list.head; set; set = set->next)
  646. ret = (*set->cmd->func_apply)(set->value, prefix, type, object);
  647.       return RMAP_MATCH;
  648.     }
  649.   else 
  650.     {
  651.       return RMAP_DENYMATCH;
  652.     }
  653.   /* Should not get here! */
  654.   return RMAP_MATCH;
  655. }
  656. /* Apply route map to the object. */
  657. route_map_result_t
  658. route_map_apply (struct route_map *map, struct prefix *prefix, 
  659.  route_map_object_t type, void *object)
  660. {
  661.   int ret = 0;
  662.   struct route_map_index *index;
  663.   if (map == NULL)
  664.     return RMAP_DENYMATCH;
  665.   for (index = map->head; index; index = index->next)
  666.     {
  667.       /* Apply this index. End here if we get a RM_NOMATCH */
  668.       ret = route_map_apply_index (index, prefix, type, object);
  669.       if (ret == RMAP_DENYMATCH)
  670.         return ret;
  671.       else if (ret == RMAP_MATCH)
  672. {
  673.   /* We now have to handle the NEXT and GOTO clauses */
  674.   if(index->exitpolicy == RMAP_EXIT)
  675.     return ret;
  676.   if(index->exitpolicy == RMAP_GOTO)
  677.     {
  678.       /* Find the next clause to jump to */
  679.       struct route_map_index *next;
  680.       next = index->next;
  681.       while (next && next->pref < index->nextpref)
  682. {
  683.   index = next;
  684.   next = next->next;
  685. }
  686.       if (next == NULL)
  687. {
  688.   /* No clauses match! */
  689.   return ret;
  690. }
  691.     }
  692.   /* Otherwise, we fall through as it was a NEXT */
  693. }
  694.     }
  695.   /* Finally route-map does not match at all. */
  696.   return RMAP_DENYMATCH;
  697. }
  698. void
  699. route_map_add_hook (void (*func) (char *))
  700. {
  701.   route_map_master.add_hook = func;
  702. }
  703. void
  704. route_map_delete_hook (void (*func) (char *))
  705. {
  706.   route_map_master.delete_hook = func;
  707. }
  708. void
  709. route_map_event_hook (void (*func) (route_map_event_t, char *))
  710. {
  711.   route_map_master.event_hook = func;
  712. }
  713. void
  714. route_map_init ()
  715. {
  716.   /* Make vector for match and set. */
  717.   route_match_vec = vector_init (1);
  718.   route_set_vec = vector_init (1);
  719. }
  720. /* VTY related functions. */
  721. DEFUN (route_map,
  722.        route_map_cmd,
  723.        "route-map WORD (deny|permit) <1-65535>",
  724.        "Create route-map or enter route-map command moden"
  725.        "Route map tagn"
  726.        "Route map denies set operationsn"
  727.        "Route map permits set operationsn"
  728.        "Sequence to insert to/delete from existing route-map entryn")
  729. {
  730.   int permit;
  731.   unsigned long pref;
  732.   struct route_map *map;
  733.   struct route_map_index *index;
  734.   char *endptr = NULL;
  735.   /* Permit check. */
  736.   if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
  737.     permit = RMAP_PERMIT;
  738.   else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
  739.     permit = RMAP_DENY;
  740.   else
  741.     {
  742.       vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
  743.       return CMD_WARNING;
  744.     }
  745.   /* Preference check. */
  746.   pref = strtoul (argv[2], &endptr, 10);
  747.   if (pref == ULONG_MAX || *endptr != '')
  748.     {
  749.       vty_out (vty, "the fourth field must be positive integer%s",
  750.        VTY_NEWLINE);
  751.       return CMD_WARNING;
  752.     }
  753.   if (pref == 0 || pref > 65535)
  754.     {
  755.       vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
  756.       return CMD_WARNING;
  757.     }
  758.   /* Get route map. */
  759.   map = route_map_get (argv[0]);
  760.   index = route_map_index_get (map, permit, pref);
  761.   vty->index = index;
  762.   vty->node = RMAP_NODE;
  763.   return CMD_SUCCESS;
  764. }
  765. DEFUN (no_route_map_all,
  766.        no_route_map_all_cmd,
  767.        "no route-map WORD",
  768.        NO_STR
  769.        "Create route-map or enter route-map command moden"
  770.        "Route map tagn")
  771. {
  772.   struct route_map *map;
  773.   map = route_map_lookup_by_name (argv[0]);
  774.   if (map == NULL)
  775.     {
  776.       vty_out (vty, "%% Could not find route-map %s%s",
  777.        argv[0], VTY_NEWLINE);
  778.       return CMD_WARNING;
  779.     }
  780.   route_map_delete (map);
  781.   return CMD_SUCCESS;
  782. }
  783. DEFUN (no_route_map,
  784.        no_route_map_cmd,
  785.        "no route-map WORD (deny|permit) <1-65535>",
  786.        NO_STR
  787.        "Create route-map or enter route-map command moden"
  788.        "Route map tagn"
  789.        "Route map denies set operationsn"
  790.        "Route map permits set operationsn"
  791.        "Sequence to insert to/delete from existing route-map entryn")
  792. {
  793.   int permit;
  794.   unsigned long pref;
  795.   struct route_map *map;
  796.   struct route_map_index *index;
  797.   char *endptr = NULL;
  798.   /* Permit check. */
  799.   if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
  800.     permit = RMAP_PERMIT;
  801.   else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
  802.     permit = RMAP_DENY;
  803.   else
  804.     {
  805.       vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
  806.       return CMD_WARNING;
  807.     }
  808.   /* Preference. */
  809.   pref = strtoul (argv[2], &endptr, 10);
  810.   if (pref == ULONG_MAX || *endptr != '')
  811.     {
  812.       vty_out (vty, "the fourth field must be positive integer%s",
  813.        VTY_NEWLINE);
  814.       return CMD_WARNING;
  815.     }
  816.   if (pref == 0 || pref > 65535)
  817.     {
  818.       vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
  819.       return CMD_WARNING;
  820.     }
  821.   /* Existence check. */
  822.   map = route_map_lookup_by_name (argv[0]);
  823.   if (map == NULL)
  824.     {
  825.       vty_out (vty, "%% Could not find route-map %s%s",
  826.        argv[0], VTY_NEWLINE);
  827.       return CMD_WARNING;
  828.     }
  829.   /* Lookup route map index. */
  830.   index = route_map_index_lookup (map, permit, pref);
  831.   if (index == NULL)
  832.     {
  833.       vty_out (vty, "%% Could not find route-map entry %s %s%s", 
  834.        argv[0], argv[2], VTY_NEWLINE);
  835.       return CMD_WARNING;
  836.     }
  837.   /* Delete index from route map. */
  838.   route_map_index_delete (index, 1);
  839.   /* If this route rule is the last one, delete route map itself. */
  840.   if (route_map_empty (map))
  841.     route_map_delete (map);
  842.   return CMD_SUCCESS;
  843. }
  844. DEFUN (rmap_continue,
  845.        rmap_continue_cmd,
  846.        "continue",
  847.        "Continue on a different entry within the route-mapn")
  848. {
  849.   struct route_map_index *index;
  850.   index = vty->index;
  851.   if (index)
  852.     index->exitpolicy = RMAP_NEXT;
  853.   return CMD_SUCCESS;
  854. }
  855. DEFUN (no_rmap_continue,
  856.        no_rmap_continue_cmd,
  857.        "no continue",
  858.        NO_STR
  859.        "Continue on a different entry within the route-mapn")
  860. {
  861.   struct route_map_index *index;
  862.   index = vty->index;
  863.   
  864.   if (index)
  865.     index->exitpolicy = RMAP_EXIT;
  866.   return CMD_SUCCESS;
  867. }
  868. DEFUN (rmap_continue_seq,
  869.        rmap_continue_seq_cmd,
  870.        "continue <1-65535>",
  871.        "Continue on a different entry within the route-mapn"
  872.        "Route-map entry sequence numbern")
  873. {
  874.   struct route_map_index *index;
  875.   int d = 0;
  876.   if (argv[0])
  877.     d = atoi(argv[0]);
  878.   index = vty->index;
  879.   if (index)
  880.     {
  881.       if (d <= index->pref)
  882. {
  883.   /* Can't allow you to do that, Dave */
  884.   vty_out (vty, "%%Loop in the route-map%s", VTY_NEWLINE);
  885.   return CMD_WARNING;
  886. }
  887.       else
  888. {
  889.   index->exitpolicy = RMAP_GOTO;
  890.   index->nextpref = d;
  891. }
  892.     }
  893.   return CMD_SUCCESS;
  894. }
  895. DEFUN (no_rmap_continue_seq,
  896.        no_rmap_continue_seq_cmd,
  897.        "no continue <1-65535>",
  898.        NO_STR
  899.        "Continue on a different entry within the route-mapn"
  900.        "Route-map entry sequence numbern")
  901. {
  902.   struct route_map_index *index;
  903.   index = vty->index;
  904.   if (index)
  905.     index->exitpolicy = RMAP_EXIT;
  906.   
  907.   return CMD_SUCCESS;
  908. }
  909. DEFUN (rmap_show,
  910.        rmap_show_cmd,
  911.        "show route-map",
  912.        SHOW_STR
  913.        "route-map informationn")
  914. {
  915.     return vty_show_route_map (vty, NULL);
  916. }
  917. DEFUN (rmap_show_name,
  918.        rmap_show_name_cmd,
  919.        "show route-map WORD",
  920.        SHOW_STR
  921.        "route-map informationn"
  922.        "route-map namen")
  923. {
  924.     return vty_show_route_map (vty, argv[0]);
  925. }
  926. /* Configuration write function. */
  927. int
  928. route_map_config_write (struct vty *vty)
  929. {
  930.   struct route_map *map;
  931.   struct route_map_index *index;
  932.   struct route_map_rule *rule;
  933.   int first = 1;
  934.   int write = 0;
  935.   for (map = route_map_master.head; map; map = map->next)
  936.     for (index = map->head; index; index = index->next)
  937.       {
  938. if (!first)
  939.   vty_out (vty, "!%s", VTY_NEWLINE);
  940. else
  941.   first = 0;
  942. vty_out (vty, "route-map %s %s %d%s", 
  943.  map->name,
  944.  route_map_type_str (index->type),
  945.  index->pref, VTY_NEWLINE);
  946. for (rule = index->match_list.head; rule; rule = rule->next)
  947.   vty_out (vty, " match %s %s%s", rule->cmd->str, 
  948.    rule->rule_str ? rule->rule_str : "",
  949.    VTY_NEWLINE);
  950. if (index->exitpolicy == RMAP_GOTO)
  951.   vty_out (vty, " continue %d%s", index->nextpref,
  952.    VTY_NEWLINE);
  953. if (index->exitpolicy == RMAP_NEXT)
  954.   vty_out (vty," continue%s", VTY_NEWLINE);
  955. for (rule = index->set_list.head; rule; rule = rule->next)
  956.   vty_out (vty, " set %s %s%s", rule->cmd->str,
  957.    rule->rule_str ? rule->rule_str : "",
  958.    VTY_NEWLINE);
  959. write++;
  960.       }
  961.   return write;
  962. }
  963. /* Route map node structure. */
  964. struct cmd_node rmap_node =
  965. {
  966.   RMAP_NODE,
  967.   "%s(config-route-map)# ",
  968.   1
  969. };
  970. /* Initialization of route map vector. */
  971. void
  972. route_map_init_vty ()
  973. {
  974.   /* Install route map top node. */
  975.   install_node (&rmap_node, route_map_config_write);
  976.   /* Install route map commands. */
  977.   install_default (RMAP_NODE);
  978.   install_element (CONFIG_NODE, &route_map_cmd);
  979.   install_element (CONFIG_NODE, &no_route_map_cmd);
  980.   install_element (CONFIG_NODE, &no_route_map_all_cmd);
  981.   /* Install the on-match stuff */
  982.   install_element (RMAP_NODE, &route_map_cmd);
  983.   install_element (RMAP_NODE, &rmap_continue_cmd);
  984.   install_element (RMAP_NODE, &no_rmap_continue_cmd);
  985.   install_element (RMAP_NODE, &rmap_continue_seq_cmd);
  986.   install_element (RMAP_NODE, &no_rmap_continue_seq_cmd);
  987.   /* Install show command */
  988.   install_element (ENABLE_NODE, &rmap_show_cmd);
  989.   install_element (ENABLE_NODE, &rmap_show_name_cmd);
  990. }