Switch from LOOKUP() to lookup() for rtm_type (see bug #401 for details).
[jleu-quagga.git] / lib / routemap.c
blob58ed09a7cf7a049360796131e18195a04a3aa381
1 /* Route map function.
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
9 later version.
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
19 02111-1307, USA. */
21 #include <zebra.h>
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"
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. */
39 struct route_map_rule
41 /* Rule type. */
42 struct route_map_rule_cmd *cmd;
44 /* For pretty printing. */
45 char *rule_str;
47 /* Pre-compiled match rule. */
48 void *value;
50 /* Linked list. */
51 struct route_map_rule *next;
52 struct route_map_rule *prev;
55 /* Making route map list. */
56 struct 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 };
69 static void
70 route_map_rule_delete (struct route_map_rule_list *,
71 struct route_map_rule *);
73 static void
74 route_map_index_delete (struct route_map_index *, int);
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)
81 struct route_map *new;
83 new = XCALLOC (MTYPE_ROUTE_MAP, sizeof (struct route_map));
84 new->name = XSTRDUP (MTYPE_ROUTE_MAP_NAME, name);
85 return new;
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;
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;
106 /* Execute hook. */
107 if (route_map_master.add_hook)
108 (*route_map_master.add_hook) (name);
110 return map;
113 /* Route map delete from list. */
114 static void
115 route_map_delete (struct route_map *map)
117 struct route_map_list *list;
118 struct route_map_index *index;
119 char *name;
121 while ((index = map->head) != NULL)
122 route_map_index_delete (index, 0);
124 name = map->name;
126 list = &route_map_master;
128 if (map->next)
129 map->next->prev = map->prev;
130 else
131 list->tail = map->prev;
133 if (map->prev)
134 map->prev->next = map->next;
135 else
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);
144 if (name)
145 XFREE (MTYPE_ROUTE_MAP_NAME, name);
149 /* Lookup route map by route map name string. */
150 struct route_map *
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)
157 return map;
158 return NULL;
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)
166 struct route_map *map;
168 map = route_map_lookup_by_name (name);
169 if (map == NULL)
170 map = route_map_add (name);
171 return map;
174 /* Return route map's type string. */
175 static const char *
176 route_map_type_str (enum route_map_type type)
178 switch (type)
180 case RMAP_PERMIT:
181 return "permit";
182 break;
183 case RMAP_DENY:
184 return "deny";
185 break;
186 default:
187 return "";
188 break;
192 static int
193 route_map_empty (struct route_map *map)
195 if (map->head == NULL && map->tail == NULL)
196 return 1;
197 else
198 return 0;
201 /* show route-map */
202 static void
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 */
209 if (zlog_default)
210 vty_out (vty, "%s:%s", zlog_proto_names[zlog_default->protocol],
211 VTY_NEWLINE);
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);
219 /* Description */
220 if (index->description)
221 vty_out (vty, " Description:%s %s%s", VTY_NEWLINE,
222 index->description, VTY_NEWLINE);
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);
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);
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);
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);
251 static int
252 vty_show_route_map (struct vty *vty, const char *name)
254 struct route_map *map;
256 if (name)
258 map = route_map_lookup_by_name (name);
260 if (map)
262 vty_show_route_map_entry (vty, map);
263 return CMD_SUCCESS;
265 else
267 vty_out (vty, "%%route-map %s not found%s", name, VTY_NEWLINE);
268 return CMD_WARNING;
271 else
273 for (map = route_map_master.head; map; map = map->next)
274 vty_show_route_map_entry (vty, map);
276 return CMD_SUCCESS;
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)
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 */
289 return new;
292 /* Free route map index. */
293 static void
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. */
307 if (index->next)
308 index->next->prev = index->prev;
309 else
310 index->map->tail = index->prev;
312 if (index->prev)
313 index->prev->next = index->next;
314 else
315 index->map->head = index->next;
317 /* Free 'char *nextrm' if not NULL */
318 if (index->nextrm)
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,
324 index->map->name);
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,
332 int pref)
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)
339 return index;
340 return NULL;
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)
348 struct route_map_index *index;
349 struct route_map_index *point;
351 /* Allocate new route map inex. */
352 index = route_map_index_new ();
353 index->map = map;
354 index->type = type;
355 index->pref = pref;
357 /* Compare preference. */
358 for (point = map->head; point; point = point->next)
359 if (point->pref >= pref)
360 break;
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;
370 map->tail = index;
372 else if (point == map->head)
374 index->next = map->head;
375 map->head->prev = index;
376 map->head = index;
378 else
380 index->next = point;
381 index->prev = point->prev;
382 if (point->prev)
383 point->prev->next = index;
384 point->prev = index;
387 /* Execute event hook. */
388 if (route_map_master.event_hook)
389 (*route_map_master.event_hook) (RMAP_EVENT_INDEX_ADDED,
390 map->name);
392 return index;
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)
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);
407 index = NULL;
409 if (index == NULL)
410 index = route_map_index_add (map, type, pref);
411 return index;
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));
421 return new;
424 /* Install rule command to the match list. */
425 void
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. */
432 void
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)
442 unsigned int i;
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)
448 return rule;
449 return NULL;
452 /* Lookup rule command from set list. */
453 static struct route_map_rule_cmd *
454 route_map_lookup_set (const char *name)
456 unsigned int i;
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)
462 return rule;
463 return NULL;
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)
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;
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)
485 if (rule->cmd->func_free)
486 (*rule->cmd->func_free) (rule->value);
488 if (rule->rule_str)
489 XFREE (MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str);
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;
500 XFREE (MTYPE_ROUTE_MAP_RULE, rule);
503 /* strcmp wrapper function which don't crush even argument is NULL. */
504 static int
505 rulecmp (const char *dst, const char *src)
507 if (dst == NULL)
509 if (src == NULL)
510 return 0;
511 else
512 return 1;
514 else
516 if (src == NULL)
517 return 1;
518 else
519 return strcmp (dst, src);
521 return 1;
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;
532 void *compile;
533 int replaced = 0;
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;
540 /* Next call compile function for this match statement. */
541 if (cmd->func_compile)
543 compile= (*cmd->func_compile)(match_arg);
544 if (compile == NULL)
545 return RMAP_COMPILE_ERROR;
547 else
548 compile = NULL;
550 /* If argument is completely same ignore it. */
551 for (rule = index->match_list.head; rule; rule = next)
553 next = rule->next;
554 if (rule->cmd == cmd)
556 route_map_rule_delete (&index->match_list, rule);
557 replaced = 1;
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;
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,
578 index->map->name);
580 return 0;
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);
592 if (cmd == NULL)
593 return 1;
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,
603 index->map->name);
604 return 0;
606 /* Can't find matched rule. */
607 return 1;
610 /* Add route-map set statement to the route map. */
612 route_map_add_set (struct route_map_index *index, const char *set_name,
613 const char *set_arg)
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;
621 cmd = route_map_lookup_set (set_name);
622 if (cmd == NULL)
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);
629 if (compile == NULL)
630 return RMAP_COMPILE_ERROR;
632 else
633 compile = NULL;
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)
640 next = rule->next;
641 if (rule->cmd == cmd)
643 route_map_rule_delete (&index->set_list, rule);
644 replaced = 1;
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;
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,
665 index->map->name);
666 return 0;
669 /* Delete route map set rule. */
671 route_map_delete_set (struct route_map_index *index, const char *set_name,
672 const char *set_arg)
674 struct route_map_rule *rule;
675 struct route_map_rule_cmd *cmd;
677 cmd = route_map_lookup_set (set_name);
678 if (cmd == NULL)
679 return 1;
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,
689 index->map->name);
690 return 0;
692 /* Can't find matched rule. */
693 return 1;
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"
700 and "GOTO" frobs now
702 Match | No Match
704 permit action | cont
706 ------------------+---------------
708 deny deny | cont
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
723 If we get no matches after we've processed all updates, then the route
724 is dropped too.
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 ;)
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,
745 void *object)
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
752 set statement. */
753 if (!match_list->head)
754 ret = RMAP_MATCH;
755 else
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
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;
769 return ret;
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)
777 static int recursion = 0;
778 int ret = 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);
787 recursion = 0;
788 return RMAP_DENYMATCH;
791 if (map == NULL)
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 */
802 continue;
803 else if (ret == RMAP_MATCH)
805 if (index->type == RMAP_PERMIT)
806 /* 'action' */
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);
813 /* Call another route-map if available */
814 if (index->nextrm)
816 struct route_map *nextrm =
817 route_map_lookup_by_name (index->nextrm);
819 if (nextrm) /* Target route-map found, jump to it */
821 recursion++;
822 ret = route_map_apply (nextrm, prefix, type, object);
823 recursion--;
826 /* If nextrm returned 'deny', finish. */
827 if (ret == RMAP_DENYMATCH)
828 return ret;
831 switch (index->exitpolicy)
833 case RMAP_EXIT:
834 return ret;
835 case RMAP_NEXT:
836 continue;
837 case RMAP_GOTO:
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)
845 index = next;
846 next = next->next;
848 if (next == NULL)
850 /* No clauses match! */
851 return ret;
856 else if (index->type == RMAP_DENY)
857 /* 'deny' */
859 return RMAP_DENYMATCH;
863 /* Finally route-map does not match at all. */
864 return RMAP_DENYMATCH;
867 void
868 route_map_add_hook (void (*func) (const char *))
870 route_map_master.add_hook = func;
873 void
874 route_map_delete_hook (void (*func) (const char *))
876 route_map_master.delete_hook = func;
879 void
880 route_map_event_hook (void (*func) (route_map_event_t, const char *))
882 route_map_master.event_hook = func;
885 void
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);
893 /* VTY related functions. */
894 DEFUN (route_map,
895 route_map_cmd,
896 "route-map WORD (deny|permit) <1-65535>",
897 "Create route-map or enter route-map command mode\n"
898 "Route map tag\n"
899 "Route map denies set operations\n"
900 "Route map permits set operations\n"
901 "Sequence to insert to/delete from existing route-map entry\n")
903 int permit;
904 unsigned long pref;
905 struct route_map *map;
906 struct route_map_index *index;
907 char *endptr = NULL;
909 /* Permit check. */
910 if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
911 permit = RMAP_PERMIT;
912 else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
913 permit = RMAP_DENY;
914 else
916 vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
917 return CMD_WARNING;
920 /* Preference check. */
921 pref = strtoul (argv[2], &endptr, 10);
922 if (pref == ULONG_MAX || *endptr != '\0')
924 vty_out (vty, "the fourth field must be positive integer%s",
925 VTY_NEWLINE);
926 return CMD_WARNING;
928 if (pref == 0 || pref > 65535)
930 vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
931 return CMD_WARNING;
934 /* Get route map. */
935 map = route_map_get (argv[0]);
936 index = route_map_index_get (map, permit, pref);
938 vty->index = index;
939 vty->node = RMAP_NODE;
940 return CMD_SUCCESS;
943 DEFUN (no_route_map_all,
944 no_route_map_all_cmd,
945 "no route-map WORD",
946 NO_STR
947 "Create route-map or enter route-map command mode\n"
948 "Route map tag\n")
950 struct route_map *map;
952 map = route_map_lookup_by_name (argv[0]);
953 if (map == NULL)
955 vty_out (vty, "%% Could not find route-map %s%s",
956 argv[0], VTY_NEWLINE);
957 return CMD_WARNING;
960 route_map_delete (map);
962 return CMD_SUCCESS;
965 DEFUN (no_route_map,
966 no_route_map_cmd,
967 "no route-map WORD (deny|permit) <1-65535>",
968 NO_STR
969 "Create route-map or enter route-map command mode\n"
970 "Route map tag\n"
971 "Route map denies set operations\n"
972 "Route map permits set operations\n"
973 "Sequence to insert to/delete from existing route-map entry\n")
975 int permit;
976 unsigned long pref;
977 struct route_map *map;
978 struct route_map_index *index;
979 char *endptr = NULL;
981 /* Permit check. */
982 if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
983 permit = RMAP_PERMIT;
984 else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
985 permit = RMAP_DENY;
986 else
988 vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
989 return CMD_WARNING;
992 /* Preference. */
993 pref = strtoul (argv[2], &endptr, 10);
994 if (pref == ULONG_MAX || *endptr != '\0')
996 vty_out (vty, "the fourth field must be positive integer%s",
997 VTY_NEWLINE);
998 return CMD_WARNING;
1000 if (pref == 0 || pref > 65535)
1002 vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
1003 return CMD_WARNING;
1006 /* Existence check. */
1007 map = route_map_lookup_by_name (argv[0]);
1008 if (map == NULL)
1010 vty_out (vty, "%% Could not find route-map %s%s",
1011 argv[0], VTY_NEWLINE);
1012 return CMD_WARNING;
1015 /* Lookup route map index. */
1016 index = route_map_index_lookup (map, permit, pref);
1017 if (index == NULL)
1019 vty_out (vty, "%% Could not find route-map entry %s %s%s",
1020 argv[0], argv[2], VTY_NEWLINE);
1021 return CMD_WARNING;
1024 /* Delete index from route map. */
1025 route_map_index_delete (index, 1);
1027 /* If this route rule is the last one, delete route map itself. */
1028 if (route_map_empty (map))
1029 route_map_delete (map);
1031 return CMD_SUCCESS;
1034 DEFUN (rmap_onmatch_next,
1035 rmap_onmatch_next_cmd,
1036 "on-match next",
1037 "Exit policy on matches\n"
1038 "Next clause\n")
1040 struct route_map_index *index;
1042 index = vty->index;
1044 if (index)
1045 index->exitpolicy = RMAP_NEXT;
1047 return CMD_SUCCESS;
1050 DEFUN (no_rmap_onmatch_next,
1051 no_rmap_onmatch_next_cmd,
1052 "no on-match next",
1053 NO_STR
1054 "Exit policy on matches\n"
1055 "Next clause\n")
1057 struct route_map_index *index;
1059 index = vty->index;
1061 if (index)
1062 index->exitpolicy = RMAP_EXIT;
1064 return CMD_SUCCESS;
1067 DEFUN (rmap_onmatch_goto,
1068 rmap_onmatch_goto_cmd,
1069 "on-match goto <1-65535>",
1070 "Exit policy on matches\n"
1071 "Goto Clause number\n"
1072 "Number\n")
1074 struct route_map_index *index = vty->index;
1075 int d = 0;
1077 if (index)
1079 if (argc == 1 && argv[0])
1080 VTY_GET_INTEGER_RANGE("route-map index", d, argv[0], 1, 65536);
1081 else
1082 d = index->pref + 1;
1084 if (d <= index->pref)
1086 /* Can't allow you to do that, Dave */
1087 vty_out (vty, "can't jump backwards in route-maps%s",
1088 VTY_NEWLINE);
1089 return CMD_WARNING;
1091 else
1093 index->exitpolicy = RMAP_GOTO;
1094 index->nextpref = d;
1097 return CMD_SUCCESS;
1100 DEFUN (no_rmap_onmatch_goto,
1101 no_rmap_onmatch_goto_cmd,
1102 "no on-match goto",
1103 NO_STR
1104 "Exit policy on matches\n"
1105 "Goto Clause number\n")
1107 struct route_map_index *index;
1109 index = vty->index;
1111 if (index)
1112 index->exitpolicy = RMAP_EXIT;
1114 return CMD_SUCCESS;
1117 /* Cisco/GNU Zebra compatible ALIASes for on-match next */
1118 ALIAS (rmap_onmatch_goto,
1119 rmap_continue_cmd,
1120 "continue",
1121 "Continue on a different entry within the route-map\n")
1123 ALIAS (no_rmap_onmatch_goto,
1124 no_rmap_continue_cmd,
1125 "no continue",
1126 NO_STR
1127 "Continue on a different entry within the route-map\n")
1129 /* GNU Zebra compatible */
1130 ALIAS (rmap_onmatch_goto,
1131 rmap_continue_seq_cmd,
1132 "continue <1-65535>",
1133 "Continue on a different entry within the route-map\n"
1134 "Route-map entry sequence number\n")
1136 ALIAS (no_rmap_onmatch_goto,
1137 no_rmap_continue_seq,
1138 "no continue <1-65535>",
1139 NO_STR
1140 "Continue on a different entry within the route-map\n"
1141 "Route-map entry sequence number\n")
1143 DEFUN (rmap_show_name,
1144 rmap_show_name_cmd,
1145 "show route-map [WORD]",
1146 SHOW_STR
1147 "route-map information\n"
1148 "route-map name\n")
1150 const char *name = NULL;
1151 if (argc)
1152 name = argv[0];
1153 return vty_show_route_map (vty, name);
1156 ALIAS (rmap_onmatch_goto,
1157 rmap_continue_index_cmd,
1158 "continue <1-65536>",
1159 "Exit policy on matches\n"
1160 "Goto Clause number\n")
1162 DEFUN (rmap_call,
1163 rmap_call_cmd,
1164 "call WORD",
1165 "Jump to another Route-Map after match+set\n"
1166 "Target route-map name\n")
1168 struct route_map_index *index;
1170 index = vty->index;
1171 if (index)
1173 if (index->nextrm)
1174 XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
1175 index->nextrm = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[0]);
1177 return CMD_SUCCESS;
1180 DEFUN (no_rmap_call,
1181 no_rmap_call_cmd,
1182 "no call",
1183 NO_STR
1184 "Jump to another Route-Map after match+set\n")
1186 struct route_map_index *index;
1188 index = vty->index;
1190 if (index->nextrm)
1192 XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
1193 index->nextrm = NULL;
1196 return CMD_SUCCESS;
1199 DEFUN (rmap_description,
1200 rmap_description_cmd,
1201 "description .LINE",
1202 "Route-map comment\n"
1203 "Comment describing this route-map rule\n")
1205 struct route_map_index *index;
1207 index = vty->index;
1208 if (index)
1210 if (index->description)
1211 XFREE (MTYPE_TMP, index->description);
1212 index->description = argv_concat (argv, argc, 0);
1214 return CMD_SUCCESS;
1217 DEFUN (no_rmap_description,
1218 no_rmap_description_cmd,
1219 "no description",
1220 NO_STR
1221 "Route-map comment\n")
1223 struct route_map_index *index;
1225 index = vty->index;
1226 if (index)
1228 if (index->description)
1229 XFREE (MTYPE_TMP, index->description);
1230 index->description = NULL;
1232 return CMD_SUCCESS;
1235 /* Configuration write function. */
1236 static int
1237 route_map_config_write (struct vty *vty)
1239 struct route_map *map;
1240 struct route_map_index *index;
1241 struct route_map_rule *rule;
1242 int first = 1;
1243 int write = 0;
1245 for (map = route_map_master.head; map; map = map->next)
1246 for (index = map->head; index; index = index->next)
1248 if (!first)
1249 vty_out (vty, "!%s", VTY_NEWLINE);
1250 else
1251 first = 0;
1253 vty_out (vty, "route-map %s %s %d%s",
1254 map->name,
1255 route_map_type_str (index->type),
1256 index->pref, VTY_NEWLINE);
1258 if (index->description)
1259 vty_out (vty, " description %s%s", index->description, VTY_NEWLINE);
1261 for (rule = index->match_list.head; rule; rule = rule->next)
1262 vty_out (vty, " match %s %s%s", rule->cmd->str,
1263 rule->rule_str ? rule->rule_str : "",
1264 VTY_NEWLINE);
1266 for (rule = index->set_list.head; rule; rule = rule->next)
1267 vty_out (vty, " set %s %s%s", rule->cmd->str,
1268 rule->rule_str ? rule->rule_str : "",
1269 VTY_NEWLINE);
1270 if (index->nextrm)
1271 vty_out (vty, " call %s%s", index->nextrm, VTY_NEWLINE);
1272 if (index->exitpolicy == RMAP_GOTO)
1273 vty_out (vty, " on-match goto %d%s", index->nextpref, VTY_NEWLINE);
1274 if (index->exitpolicy == RMAP_NEXT)
1275 vty_out (vty," on-match next%s", VTY_NEWLINE);
1277 write++;
1279 return write;
1282 /* Route map node structure. */
1283 struct cmd_node rmap_node =
1285 RMAP_NODE,
1286 "%s(config-route-map)# ",
1290 /* Initialization of route map vector. */
1291 void
1292 route_map_init_vty (void)
1294 /* Install route map top node. */
1295 install_node (&rmap_node, route_map_config_write);
1297 /* Install route map commands. */
1298 install_default (RMAP_NODE);
1299 install_element (CONFIG_NODE, &route_map_cmd);
1300 install_element (CONFIG_NODE, &no_route_map_cmd);
1301 install_element (CONFIG_NODE, &no_route_map_all_cmd);
1303 /* Install the on-match stuff */
1304 install_element (RMAP_NODE, &route_map_cmd);
1305 install_element (RMAP_NODE, &rmap_onmatch_next_cmd);
1306 install_element (RMAP_NODE, &no_rmap_onmatch_next_cmd);
1307 install_element (RMAP_NODE, &rmap_onmatch_goto_cmd);
1308 install_element (RMAP_NODE, &no_rmap_onmatch_goto_cmd);
1310 /* Install the continue stuff (ALIAS of on-match). */
1311 install_element (RMAP_NODE, &rmap_continue_cmd);
1312 install_element (RMAP_NODE, &no_rmap_continue_cmd);
1313 install_element (RMAP_NODE, &rmap_continue_index_cmd);
1315 /* Install the call stuff. */
1316 install_element (RMAP_NODE, &rmap_call_cmd);
1317 install_element (RMAP_NODE, &no_rmap_call_cmd);
1319 /* Install description commands. */
1320 install_element (RMAP_NODE, &rmap_description_cmd);
1321 install_element (RMAP_NODE, &no_rmap_description_cmd);
1323 /* Install show command */
1324 install_element (ENABLE_NODE, &rmap_show_name_cmd);