2 Copyright (C) 1998, 1999 Kunihiro Ishiguro
4 This file is part of GNU Zebra.
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
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.
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
32 /* Vector for route match rules. */
33 static vector route_match_vec;
35 /* Vector for route set rules. */
36 static vector route_set_vec;
38 /* Route map rule. This rule has both `match' rule and `set' rule. */
42 struct route_map_rule_cmd *cmd;
44 /* For pretty printing. */
47 /* Pre-compiled match rule. */
51 struct route_map_rule *next;
52 struct route_map_rule *prev;
55 /* Making route map list. */
58 struct route_map *head;
59 struct route_map *tail;
61 void (*add_hook) (const char *);
62 void (*delete_hook) (const char *);
63 void (*event_hook) (route_map_event_t, const char *);
66 /* Master list of route map. */
67 static struct route_map_list route_map_master = { NULL, NULL, NULL, NULL };
70 route_map_rule_delete (struct route_map_rule_list *,
71 struct route_map_rule *);
74 route_map_index_delete (struct route_map_index *, int);
76 /* New route map allocation. Please note route map's name must be
78 static struct route_map *
79 route_map_new (const char *name)
81 struct route_map *new;
83 new = XCALLOC (MTYPE_ROUTE_MAP, sizeof (struct route_map));
84 new->name = XSTRDUP (MTYPE_ROUTE_MAP_NAME, name);
88 /* Add new name to route_map. */
89 static struct route_map *
90 route_map_add (const char *name)
92 struct route_map *map;
93 struct route_map_list *list;
95 map = route_map_new (name);
96 list = &route_map_master;
99 map->prev = list->tail;
101 list->tail->next = map;
107 if (route_map_master.add_hook)
108 (*route_map_master.add_hook) (name);
113 /* Route map delete from list. */
115 route_map_delete (struct route_map *map)
117 struct route_map_list *list;
118 struct route_map_index *index;
121 while ((index = map->head) != NULL)
122 route_map_index_delete (index, 0);
126 list = &route_map_master;
129 map->next->prev = map->prev;
131 list->tail = map->prev;
134 map->prev->next = map->next;
136 list->head = map->next;
138 XFREE (MTYPE_ROUTE_MAP, map);
140 /* Execute deletion hook. */
141 if (route_map_master.delete_hook)
142 (*route_map_master.delete_hook) (name);
145 XFREE (MTYPE_ROUTE_MAP_NAME, name);
149 /* Lookup route map by route map name string. */
151 route_map_lookup_by_name (const char *name)
153 struct route_map *map;
155 for (map = route_map_master.head; map; map = map->next)
156 if (strcmp (map->name, name) == 0)
161 /* Lookup route map. If there isn't route map create one and return
163 static struct route_map *
164 route_map_get (const char *name)
166 struct route_map *map;
168 map = route_map_lookup_by_name (name);
170 map = route_map_add (name);
174 /* Return route map's type string. */
176 route_map_type_str (enum route_map_type type)
193 route_map_empty (struct route_map *map)
195 if (map->head == NULL && map->tail == NULL)
203 vty_show_route_map_entry (struct vty *vty, struct route_map *map)
205 struct route_map_index *index;
206 struct route_map_rule *rule;
208 /* Print the name of the protocol */
210 vty_out (vty, "%s:%s", zlog_proto_names[zlog_default->protocol],
213 for (index = map->head; index; index = index->next)
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);
220 if (index->description)
221 vty_out (vty, " Description:%s %s%s", VTY_NEWLINE,
222 index->description, VTY_NEWLINE);
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);
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);
236 vty_out (vty, " Call clause:%s", VTY_NEWLINE);
238 vty_out (vty, " Call %s%s", index->nextrm, VTY_NEWLINE);
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);
252 vty_show_route_map (struct vty *vty, const char *name)
254 struct route_map *map;
258 map = route_map_lookup_by_name (name);
262 vty_show_route_map_entry (vty, map);
267 vty_out (vty, "%%route-map %s not found%s", name, VTY_NEWLINE);
273 for (map = route_map_master.head; map; map = map->next)
274 vty_show_route_map_entry (vty, map);
280 /* New route map allocation. Please note route map's name must be
282 static struct route_map_index *
283 route_map_index_new (void)
285 struct route_map_index *new;
287 new = XCALLOC (MTYPE_ROUTE_MAP_INDEX, sizeof (struct route_map_index));
288 new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */
292 /* Free route map index. */
294 route_map_index_delete (struct route_map_index *index, int notify)
296 struct route_map_rule *rule;
298 /* Free route match. */
299 while ((rule = index->match_list.head) != NULL)
300 route_map_rule_delete (&index->match_list, rule);
302 /* Free route set. */
303 while ((rule = index->set_list.head) != NULL)
304 route_map_rule_delete (&index->set_list, rule);
306 /* Remove index from route map list. */
308 index->next->prev = index->prev;
310 index->map->tail = index->prev;
313 index->prev->next = index->next;
315 index->map->head = index->next;
317 /* Free 'char *nextrm' if not NULL */
319 XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
321 /* Execute event hook. */
322 if (route_map_master.event_hook && notify)
323 (*route_map_master.event_hook) (RMAP_EVENT_INDEX_DELETED,
326 XFREE (MTYPE_ROUTE_MAP_INDEX, index);
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,
334 struct route_map_index *index;
336 for (index = map->head; index; index = index->next)
337 if ((index->type == type || type == RMAP_ANY)
338 && index->pref == pref)
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,
348 struct route_map_index *index;
349 struct route_map_index *point;
351 /* Allocate new route map inex. */
352 index = route_map_index_new ();
357 /* Compare preference. */
358 for (point = map->head; point; point = point->next)
359 if (point->pref >= pref)
362 if (map->head == NULL)
364 map->head = map->tail = index;
366 else if (point == NULL)
368 index->prev = map->tail;
369 map->tail->next = index;
372 else if (point == map->head)
374 index->next = map->head;
375 map->head->prev = index;
381 index->prev = point->prev;
383 point->prev->next = index;
387 /* Execute event hook. */
388 if (route_map_master.event_hook)
389 (*route_map_master.event_hook) (RMAP_EVENT_INDEX_ADDED,
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,
400 struct route_map_index *index;
402 index = route_map_index_lookup (map, RMAP_ANY, pref);
403 if (index && index->type != type)
405 /* Delete index from route map. */
406 route_map_index_delete (index, 1);
410 index = route_map_index_add (map, type, pref);
414 /* New route map rule */
415 static struct route_map_rule *
416 route_map_rule_new (void)
418 struct route_map_rule *new;
420 new = XCALLOC (MTYPE_ROUTE_MAP_RULE, sizeof (struct route_map_rule));
424 /* Install rule command to the match list. */
426 route_map_install_match (struct route_map_rule_cmd *cmd)
428 vector_set (route_match_vec, cmd);
431 /* Install rule command to the set list. */
433 route_map_install_set (struct route_map_rule_cmd *cmd)
435 vector_set (route_set_vec, cmd);
438 /* Lookup rule command from match list. */
439 static struct route_map_rule_cmd *
440 route_map_lookup_match (const char *name)
443 struct route_map_rule_cmd *rule;
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)
452 /* Lookup rule command from set list. */
453 static struct route_map_rule_cmd *
454 route_map_lookup_set (const char *name)
457 struct route_map_rule_cmd *rule;
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)
466 /* Add match and set rule to rule list. */
468 route_map_rule_add (struct route_map_rule_list *list,
469 struct route_map_rule *rule)
472 rule->prev = list->tail;
474 list->tail->next = rule;
480 /* Delete rule from rule list. */
482 route_map_rule_delete (struct route_map_rule_list *list,
483 struct route_map_rule *rule)
485 if (rule->cmd->func_free)
486 (*rule->cmd->func_free) (rule->value);
489 XFREE (MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str);
492 rule->next->prev = rule->prev;
494 list->tail = rule->prev;
496 rule->prev->next = rule->next;
498 list->head = rule->next;
500 XFREE (MTYPE_ROUTE_MAP_RULE, rule);
503 /* strcmp wrapper function which don't crush even argument is NULL. */
505 rulecmp (const char *dst, const char *src)
519 return strcmp (dst, src);
524 /* Add match statement to route map. */
526 route_map_add_match (struct route_map_index *index, const char *match_name,
527 const char *match_arg)
529 struct route_map_rule *rule;
530 struct route_map_rule *next;
531 struct route_map_rule_cmd *cmd;
535 /* First lookup rule for add match statement. */
536 cmd = route_map_lookup_match (match_name);
538 return RMAP_RULE_MISSING;
540 /* Next call compile function for this match statement. */
541 if (cmd->func_compile)
543 compile= (*cmd->func_compile)(match_arg);
545 return RMAP_COMPILE_ERROR;
550 /* If argument is completely same ignore it. */
551 for (rule = index->match_list.head; rule; rule = next)
554 if (rule->cmd == cmd)
556 route_map_rule_delete (&index->match_list, rule);
561 /* Add new route map match rule. */
562 rule = route_map_rule_new ();
564 rule->value = compile;
566 rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, match_arg);
568 rule->rule_str = NULL;
570 /* Add new route match rule to linked list. */
571 route_map_rule_add (&index->match_list, rule);
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,
583 /* Delete specified route match rule. */
585 route_map_delete_match (struct route_map_index *index, const char *match_name,
586 const char *match_arg)
588 struct route_map_rule *rule;
589 struct route_map_rule_cmd *cmd;
591 cmd = route_map_lookup_match (match_name);
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))
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,
606 /* Can't find matched rule. */
610 /* Add route-map set statement to the route map. */
612 route_map_add_set (struct route_map_index *index, const char *set_name,
615 struct route_map_rule *rule;
616 struct route_map_rule *next;
617 struct route_map_rule_cmd *cmd;
621 cmd = route_map_lookup_set (set_name);
623 return RMAP_RULE_MISSING;
625 /* Next call compile function for this match statement. */
626 if (cmd->func_compile)
628 compile= (*cmd->func_compile)(set_arg);
630 return RMAP_COMPILE_ERROR;
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
638 for (rule = index->set_list.head; rule; rule = next)
641 if (rule->cmd == cmd)
643 route_map_rule_delete (&index->set_list, rule);
648 /* Add new route map match rule. */
649 rule = route_map_rule_new ();
651 rule->value = compile;
653 rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, set_arg);
655 rule->rule_str = NULL;
657 /* Add new route match rule to linked list. */
658 route_map_rule_add (&index->set_list, rule);
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,
669 /* Delete route map set rule. */
671 route_map_delete_set (struct route_map_index *index, const char *set_name,
674 struct route_map_rule *rule;
675 struct route_map_rule_cmd *cmd;
677 cmd = route_map_lookup_set (set_name);
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))
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,
692 /* Can't find matched rule. */
696 /* Apply route map's each index to the object.
698 The matrix for a route-map looks like this:
699 (note, this includes the description for the "NEXT"
706 ------------------+---------------
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
719 -Route is denied by route-map.
723 If we get no matches after we've processed all updates, then the route
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.
739 We need to make sure our route-map processing matches the above
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,
747 route_map_result_t ret = RMAP_NOMATCH;
748 struct route_map_rule *match;
751 /* Check all match rule and if there is no match rule, go to the
753 if (!match_list->head)
757 for (match = match_list->head; match; match = match->next)
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
763 ret = (*match->cmd->func_apply) (match->value, prefix,
765 if (ret != RMAP_MATCH)
772 /* Apply route map to the object. */
774 route_map_apply (struct route_map *map, struct prefix *prefix,
775 route_map_object_t type, void *object)
777 static int recursion = 0;
779 struct route_map_index *index;
780 struct route_map_rule *set;
782 if (recursion > RMAP_RECURSION_LIMIT)
784 zlog (NULL, LOG_WARNING,
785 "route-map recursion limit (%d) reached, discarding route",
786 RMAP_RECURSION_LIMIT);
788 return RMAP_DENYMATCH;
792 return RMAP_DENYMATCH;
794 for (index = map->head; index; index = index->next)
796 /* Apply this index. */
797 ret = route_map_apply_match (&index->match_list, prefix, type, object);
799 /* Now we apply the matrix from above */
800 if (ret == RMAP_NOMATCH)
801 /* 'cont' from matrix - continue to next route-map sequence */
803 else if (ret == RMAP_MATCH)
805 if (index->type == RMAP_PERMIT)
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,
813 /* Call another route-map if available */
816 struct route_map *nextrm =
817 route_map_lookup_by_name (index->nextrm);
819 if (nextrm) /* Target route-map found, jump to it */
822 ret = route_map_apply (nextrm, prefix, type, object);
826 /* If nextrm returned 'deny', finish. */
827 if (ret == RMAP_DENYMATCH)
831 switch (index->exitpolicy)
839 /* Find the next clause to jump to */
840 struct route_map_index *next = index->next;
841 int nextpref = index->nextpref;
843 while (next && next->pref < nextpref)
850 /* No clauses match! */
856 else if (index->type == RMAP_DENY)
859 return RMAP_DENYMATCH;
863 /* Finally route-map does not match at all. */
864 return RMAP_DENYMATCH;
868 route_map_add_hook (void (*func) (const char *))
870 route_map_master.add_hook = func;
874 route_map_delete_hook (void (*func) (const char *))
876 route_map_master.delete_hook = func;
880 route_map_event_hook (void (*func) (route_map_event_t, const char *))
882 route_map_master.event_hook = func;
886 route_map_init (void)
888 /* Make vector for match and set. */
889 route_match_vec = vector_init (1);
890 route_set_vec = vector_init (1);
894 route_map_finish (void)
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);
905 /* VTY related functions. */
908 "route-map WORD (deny|permit) <1-65535>",
909 "Create route-map or enter route-map command mode\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")
917 struct route_map *map;
918 struct route_map_index *index;
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)
928 vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
932 /* Preference check. */
933 pref = strtoul (argv[2], &endptr, 10);
934 if (pref == ULONG_MAX || *endptr != '\0')
936 vty_out (vty, "the fourth field must be positive integer%s",
940 if (pref == 0 || pref > 65535)
942 vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
947 map = route_map_get (argv[0]);
948 index = route_map_index_get (map, permit, pref);
951 vty->node = RMAP_NODE;
955 DEFUN (no_route_map_all,
956 no_route_map_all_cmd,
959 "Create route-map or enter route-map command mode\n"
962 struct route_map *map;
964 map = route_map_lookup_by_name (argv[0]);
967 vty_out (vty, "%% Could not find route-map %s%s",
968 argv[0], VTY_NEWLINE);
972 route_map_delete (map);
979 "no route-map WORD (deny|permit) <1-65535>",
981 "Create route-map or enter route-map command mode\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")
989 struct route_map *map;
990 struct route_map_index *index;
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)
1000 vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
1005 pref = strtoul (argv[2], &endptr, 10);
1006 if (pref == ULONG_MAX || *endptr != '\0')
1008 vty_out (vty, "the fourth field must be positive integer%s",
1012 if (pref == 0 || pref > 65535)
1014 vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
1018 /* Existence check. */
1019 map = route_map_lookup_by_name (argv[0]);
1022 vty_out (vty, "%% Could not find route-map %s%s",
1023 argv[0], VTY_NEWLINE);
1027 /* Lookup route map index. */
1028 index = route_map_index_lookup (map, permit, pref);
1031 vty_out (vty, "%% Could not find route-map entry %s %s%s",
1032 argv[0], argv[2], VTY_NEWLINE);
1036 /* Delete index from route map. */
1037 route_map_index_delete (index, 1);
1039 /* If this route rule is the last one, delete route map itself. */
1040 if (route_map_empty (map))
1041 route_map_delete (map);
1046 DEFUN (rmap_onmatch_next,
1047 rmap_onmatch_next_cmd,
1049 "Exit policy on matches\n"
1052 struct route_map_index *index;
1057 index->exitpolicy = RMAP_NEXT;
1062 DEFUN (no_rmap_onmatch_next,
1063 no_rmap_onmatch_next_cmd,
1066 "Exit policy on matches\n"
1069 struct route_map_index *index;
1074 index->exitpolicy = RMAP_EXIT;
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"
1086 struct route_map_index *index = vty->index;
1091 if (argc == 1 && argv[0])
1092 VTY_GET_INTEGER_RANGE("route-map index", d, argv[0], 1, 65536);
1094 d = index->pref + 1;
1096 if (d <= index->pref)
1098 /* Can't allow you to do that, Dave */
1099 vty_out (vty, "can't jump backwards in route-maps%s",
1105 index->exitpolicy = RMAP_GOTO;
1106 index->nextpref = d;
1112 DEFUN (no_rmap_onmatch_goto,
1113 no_rmap_onmatch_goto_cmd,
1116 "Exit policy on matches\n"
1117 "Goto Clause number\n")
1119 struct route_map_index *index;
1124 index->exitpolicy = RMAP_EXIT;
1129 /* Cisco/GNU Zebra compatible ALIASes for on-match next */
1130 ALIAS (rmap_onmatch_goto,
1133 "Continue on a different entry within the route-map\n")
1135 ALIAS (no_rmap_onmatch_goto,
1136 no_rmap_continue_cmd,
1139 "Continue on a different entry within the route-map\n")
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")
1148 ALIAS (no_rmap_onmatch_goto,
1149 no_rmap_continue_seq,
1150 "no continue <1-65535>",
1152 "Continue on a different entry within the route-map\n"
1153 "Route-map entry sequence number\n")
1155 DEFUN (rmap_show_name,
1157 "show route-map [WORD]",
1159 "route-map information\n"
1162 const char *name = NULL;
1165 return vty_show_route_map (vty, name);
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")
1177 "Jump to another Route-Map after match+set\n"
1178 "Target route-map name\n")
1180 struct route_map_index *index;
1186 XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
1187 index->nextrm = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[0]);
1192 DEFUN (no_rmap_call,
1196 "Jump to another Route-Map after match+set\n")
1198 struct route_map_index *index;
1204 XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
1205 index->nextrm = NULL;
1211 DEFUN (rmap_description,
1212 rmap_description_cmd,
1213 "description .LINE",
1214 "Route-map comment\n"
1215 "Comment describing this route-map rule\n")
1217 struct route_map_index *index;
1222 if (index->description)
1223 XFREE (MTYPE_TMP, index->description);
1224 index->description = argv_concat (argv, argc, 0);
1229 DEFUN (no_rmap_description,
1230 no_rmap_description_cmd,
1233 "Route-map comment\n")
1235 struct route_map_index *index;
1240 if (index->description)
1241 XFREE (MTYPE_TMP, index->description);
1242 index->description = NULL;
1247 /* Configuration write function. */
1249 route_map_config_write (struct vty *vty)
1251 struct route_map *map;
1252 struct route_map_index *index;
1253 struct route_map_rule *rule;
1257 for (map = route_map_master.head; map; map = map->next)
1258 for (index = map->head; index; index = index->next)
1261 vty_out (vty, "!%s", VTY_NEWLINE);
1265 vty_out (vty, "route-map %s %s %d%s",
1267 route_map_type_str (index->type),
1268 index->pref, VTY_NEWLINE);
1270 if (index->description)
1271 vty_out (vty, " description %s%s", index->description, VTY_NEWLINE);
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 : "",
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 : "",
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);
1294 /* Route map node structure. */
1295 static struct cmd_node rmap_node =
1298 "%s(config-route-map)# ",
1302 /* Common route map rules */
1305 route_map_rule_tag_compile (const char *arg)
1307 unsigned long int tmp;
1312 tmp = strtoul(arg, &endptr, 0);
1313 if (arg[0] == '\0' || *endptr != '\0' || errno || tmp > ROUTE_TAG_MAX)
1316 tag = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*tag));
1323 route_map_rule_tag_free (void *rule)
1325 XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
1328 /* Initialization of route map vector. */
1330 route_map_init_vty (void)
1332 /* Install route map top node. */
1333 install_node (&rmap_node, route_map_config_write);
1335 /* Install route map commands. */
1336 install_default (RMAP_NODE);
1337 install_element (CONFIG_NODE, &route_map_cmd);
1338 install_element (CONFIG_NODE, &no_route_map_cmd);
1339 install_element (CONFIG_NODE, &no_route_map_all_cmd);
1341 /* Install the on-match stuff */
1342 install_element (RMAP_NODE, &route_map_cmd);
1343 install_element (RMAP_NODE, &rmap_onmatch_next_cmd);
1344 install_element (RMAP_NODE, &no_rmap_onmatch_next_cmd);
1345 install_element (RMAP_NODE, &rmap_onmatch_goto_cmd);
1346 install_element (RMAP_NODE, &no_rmap_onmatch_goto_cmd);
1348 /* Install the continue stuff (ALIAS of on-match). */
1349 install_element (RMAP_NODE, &rmap_continue_cmd);
1350 install_element (RMAP_NODE, &no_rmap_continue_cmd);
1351 install_element (RMAP_NODE, &rmap_continue_index_cmd);
1353 /* Install the call stuff. */
1354 install_element (RMAP_NODE, &rmap_call_cmd);
1355 install_element (RMAP_NODE, &no_rmap_call_cmd);
1357 /* Install description commands. */
1358 install_element (RMAP_NODE, &rmap_description_cmd);
1359 install_element (RMAP_NODE, &no_rmap_description_cmd);
1361 /* Install show command */
1362 install_element (ENABLE_NODE, &rmap_show_name_cmd);