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
31 /* Vector for route match rules. */
32 static vector route_match_vec
;
34 /* Vector for route set rules. */
35 static vector route_set_vec
;
37 /* Route map rule. This rule has both `match' rule and `set' rule. */
41 struct route_map_rule_cmd
*cmd
;
43 /* For pretty printing. */
46 /* Pre-compiled match rule. */
50 struct route_map_rule
*next
;
51 struct route_map_rule
*prev
;
54 /* Making route map list. */
57 struct route_map
*head
;
58 struct route_map
*tail
;
60 void (*add_hook
) (const char *);
61 void (*delete_hook
) (const char *);
62 void (*event_hook
) (route_map_event_t
, const char *);
65 /* Master list of route map. */
66 static struct route_map_list route_map_master
= { NULL
, NULL
, NULL
, NULL
};
69 route_map_rule_delete (struct route_map_rule_list
*,
70 struct route_map_rule
*);
73 route_map_index_delete (struct route_map_index
*, int);
75 /* New route map allocation. Please note route map's name must be
77 static struct route_map
*
78 route_map_new (const char *name
)
80 struct route_map
*new;
82 new = XCALLOC (MTYPE_ROUTE_MAP
, sizeof (struct route_map
));
83 new->name
= XSTRDUP (MTYPE_ROUTE_MAP_NAME
, name
);
87 /* Add new name to route_map. */
88 static struct route_map
*
89 route_map_add (const char *name
)
91 struct route_map
*map
;
92 struct route_map_list
*list
;
94 map
= route_map_new (name
);
95 list
= &route_map_master
;
98 map
->prev
= list
->tail
;
100 list
->tail
->next
= map
;
106 if (route_map_master
.add_hook
)
107 (*route_map_master
.add_hook
) (name
);
112 /* Route map delete from list. */
114 route_map_delete (struct route_map
*map
)
116 struct route_map_list
*list
;
117 struct route_map_index
*index
;
120 while ((index
= map
->head
) != NULL
)
121 route_map_index_delete (index
, 0);
125 list
= &route_map_master
;
128 map
->next
->prev
= map
->prev
;
130 list
->tail
= map
->prev
;
133 map
->prev
->next
= map
->next
;
135 list
->head
= map
->next
;
137 XFREE (MTYPE_ROUTE_MAP
, map
);
139 /* Execute deletion hook. */
140 if (route_map_master
.delete_hook
)
141 (*route_map_master
.delete_hook
) (name
);
144 XFREE (MTYPE_ROUTE_MAP_NAME
, name
);
148 /* Lookup route map by route map name string. */
150 route_map_lookup_by_name (const char *name
)
152 struct route_map
*map
;
154 for (map
= route_map_master
.head
; map
; map
= map
->next
)
155 if (strcmp (map
->name
, name
) == 0)
160 /* Lookup route map. If there isn't route map create one and return
162 static struct route_map
*
163 route_map_get (const char *name
)
165 struct route_map
*map
;
167 map
= route_map_lookup_by_name (name
);
169 map
= route_map_add (name
);
173 /* Return route map's type string. */
175 route_map_type_str (enum route_map_type type
)
192 route_map_empty (struct route_map
*map
)
194 if (map
->head
== NULL
&& map
->tail
== NULL
)
202 vty_show_route_map_entry (struct vty
*vty
, struct route_map
*map
)
204 struct route_map_index
*index
;
205 struct route_map_rule
*rule
;
207 for (index
= map
->head
; index
; index
= index
->next
)
209 vty_out (vty
, "route-map %s, %s, sequence %d%s",
210 map
->name
, route_map_type_str (index
->type
),
211 index
->pref
, VTY_NEWLINE
);
214 if (index
->description
)
215 vty_out (vty
, " Description:%s %s%s", VTY_NEWLINE
,
216 index
->description
, VTY_NEWLINE
);
219 vty_out (vty
, " Match clauses:%s", VTY_NEWLINE
);
220 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
221 vty_out (vty
, " %s %s%s",
222 rule
->cmd
->str
, rule
->rule_str
, VTY_NEWLINE
);
224 vty_out (vty
, " Set clauses:%s", VTY_NEWLINE
);
225 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
226 vty_out (vty
, " %s %s%s",
227 rule
->cmd
->str
, rule
->rule_str
, VTY_NEWLINE
);
229 vty_out (vty
, " Action:%s", VTY_NEWLINE
);
232 vty_out (vty
, " Call %s%s", index
->nextrm
, VTY_NEWLINE
);
233 else if (index
->exitpolicy
== RMAP_GOTO
)
234 vty_out (vty
, " Goto %d%s", index
->nextpref
, VTY_NEWLINE
);
235 else if (index
->exitpolicy
== RMAP_NEXT
)
237 vty_out (vty
, " Goto next, (entry ");
239 vty_out (vty
, " %d)%s", index
->next
->pref
, VTY_NEWLINE
);
241 vty_out (vty
, " undefined)%s", VTY_NEWLINE
);
243 else if (index
->exitpolicy
== RMAP_EXIT
)
244 vty_out (vty
, " Exit routemap%s", VTY_NEWLINE
);
249 vty_show_route_map (struct vty
*vty
, const char *name
)
251 struct route_map
*map
;
255 map
= route_map_lookup_by_name (name
);
259 vty_show_route_map_entry (vty
, map
);
264 vty_out (vty
, "%%route-map %s not found%s", name
, VTY_NEWLINE
);
272 /* New route map allocation. Please note route map's name must be
274 static struct route_map_index
*
275 route_map_index_new (void)
277 struct route_map_index
*new;
279 new = XCALLOC (MTYPE_ROUTE_MAP_INDEX
, sizeof (struct route_map_index
));
280 new->exitpolicy
= RMAP_EXIT
; /* Default to Cisco-style */
284 /* Free route map index. */
286 route_map_index_delete (struct route_map_index
*index
, int notify
)
288 struct route_map_rule
*rule
;
290 /* Free route match. */
291 while ((rule
= index
->match_list
.head
) != NULL
)
292 route_map_rule_delete (&index
->match_list
, rule
);
294 /* Free route set. */
295 while ((rule
= index
->set_list
.head
) != NULL
)
296 route_map_rule_delete (&index
->set_list
, rule
);
298 /* Remove index from route map list. */
300 index
->next
->prev
= index
->prev
;
302 index
->map
->tail
= index
->prev
;
305 index
->prev
->next
= index
->next
;
307 index
->map
->head
= index
->next
;
309 /* Free 'char *nextrm' if not NULL */
311 free (index
->nextrm
);
313 /* Execute event hook. */
314 if (route_map_master
.event_hook
&& notify
)
315 (*route_map_master
.event_hook
) (RMAP_EVENT_INDEX_DELETED
,
318 XFREE (MTYPE_ROUTE_MAP_INDEX
, index
);
321 /* Lookup index from route map. */
322 static struct route_map_index
*
323 route_map_index_lookup (struct route_map
*map
, enum route_map_type type
,
326 struct route_map_index
*index
;
328 for (index
= map
->head
; index
; index
= index
->next
)
329 if ((index
->type
== type
|| type
== RMAP_ANY
)
330 && index
->pref
== pref
)
335 /* Add new index to route map. */
336 static struct route_map_index
*
337 route_map_index_add (struct route_map
*map
, enum route_map_type type
,
340 struct route_map_index
*index
;
341 struct route_map_index
*point
;
343 /* Allocate new route map inex. */
344 index
= route_map_index_new ();
349 /* Compare preference. */
350 for (point
= map
->head
; point
; point
= point
->next
)
351 if (point
->pref
>= pref
)
354 if (map
->head
== NULL
)
356 map
->head
= map
->tail
= index
;
358 else if (point
== NULL
)
360 index
->prev
= map
->tail
;
361 map
->tail
->next
= index
;
364 else if (point
== map
->head
)
366 index
->next
= map
->head
;
367 map
->head
->prev
= index
;
373 index
->prev
= point
->prev
;
375 point
->prev
->next
= index
;
379 /* Execute event hook. */
380 if (route_map_master
.event_hook
)
381 (*route_map_master
.event_hook
) (RMAP_EVENT_INDEX_ADDED
,
387 /* Get route map index. */
388 static struct route_map_index
*
389 route_map_index_get (struct route_map
*map
, enum route_map_type type
,
392 struct route_map_index
*index
;
394 index
= route_map_index_lookup (map
, RMAP_ANY
, pref
);
395 if (index
&& index
->type
!= type
)
397 /* Delete index from route map. */
398 route_map_index_delete (index
, 1);
402 index
= route_map_index_add (map
, type
, pref
);
406 /* New route map rule */
407 static struct route_map_rule
*
408 route_map_rule_new (void)
410 struct route_map_rule
*new;
412 new = XCALLOC (MTYPE_ROUTE_MAP_RULE
, sizeof (struct route_map_rule
));
416 /* Install rule command to the match list. */
418 route_map_install_match (struct route_map_rule_cmd
*cmd
)
420 vector_set (route_match_vec
, cmd
);
423 /* Install rule command to the set list. */
425 route_map_install_set (struct route_map_rule_cmd
*cmd
)
427 vector_set (route_set_vec
, cmd
);
430 /* Lookup rule command from match list. */
431 static struct route_map_rule_cmd
*
432 route_map_lookup_match (const char *name
)
435 struct route_map_rule_cmd
*rule
;
437 for (i
= 0; i
< vector_active (route_match_vec
); i
++)
438 if ((rule
= vector_slot (route_match_vec
, i
)) != NULL
)
439 if (strcmp (rule
->str
, name
) == 0)
444 /* Lookup rule command from set list. */
445 static struct route_map_rule_cmd
*
446 route_map_lookup_set (const char *name
)
449 struct route_map_rule_cmd
*rule
;
451 for (i
= 0; i
< vector_active (route_set_vec
); i
++)
452 if ((rule
= vector_slot (route_set_vec
, i
)) != NULL
)
453 if (strcmp (rule
->str
, name
) == 0)
458 /* Add match and set rule to rule list. */
460 route_map_rule_add (struct route_map_rule_list
*list
,
461 struct route_map_rule
*rule
)
464 rule
->prev
= list
->tail
;
466 list
->tail
->next
= rule
;
472 /* Delete rule from rule list. */
474 route_map_rule_delete (struct route_map_rule_list
*list
,
475 struct route_map_rule
*rule
)
477 if (rule
->cmd
->func_free
)
478 (*rule
->cmd
->func_free
) (rule
->value
);
481 XFREE (MTYPE_ROUTE_MAP_RULE_STR
, rule
->rule_str
);
484 rule
->next
->prev
= rule
->prev
;
486 list
->tail
= rule
->prev
;
488 rule
->prev
->next
= rule
->next
;
490 list
->head
= rule
->next
;
492 XFREE (MTYPE_ROUTE_MAP_RULE
, rule
);
495 /* strcmp wrapper function which don't crush even argument is NULL. */
497 rulecmp (const char *dst
, const char *src
)
511 return strcmp (dst
, src
);
516 /* Add match statement to route map. */
518 route_map_add_match (struct route_map_index
*index
, const char *match_name
,
519 const char *match_arg
)
521 struct route_map_rule
*rule
;
522 struct route_map_rule
*next
;
523 struct route_map_rule_cmd
*cmd
;
527 /* First lookup rule for add match statement. */
528 cmd
= route_map_lookup_match (match_name
);
530 return RMAP_RULE_MISSING
;
532 /* Next call compile function for this match statement. */
533 if (cmd
->func_compile
)
535 compile
= (*cmd
->func_compile
)(match_arg
);
537 return RMAP_COMPILE_ERROR
;
542 /* If argument is completely same ignore it. */
543 for (rule
= index
->match_list
.head
; rule
; rule
= next
)
546 if (rule
->cmd
== cmd
)
548 route_map_rule_delete (&index
->match_list
, rule
);
553 /* Add new route map match rule. */
554 rule
= route_map_rule_new ();
556 rule
->value
= compile
;
558 rule
->rule_str
= XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR
, match_arg
);
560 rule
->rule_str
= NULL
;
562 /* Add new route match rule to linked list. */
563 route_map_rule_add (&index
->match_list
, rule
);
565 /* Execute event hook. */
566 if (route_map_master
.event_hook
)
567 (*route_map_master
.event_hook
) (replaced
?
568 RMAP_EVENT_MATCH_REPLACED
:
569 RMAP_EVENT_MATCH_ADDED
,
575 /* Delete specified route match rule. */
577 route_map_delete_match (struct route_map_index
*index
, const char *match_name
,
578 const char *match_arg
)
580 struct route_map_rule
*rule
;
581 struct route_map_rule_cmd
*cmd
;
583 cmd
= route_map_lookup_match (match_name
);
587 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
588 if (rule
->cmd
== cmd
&&
589 (rulecmp (rule
->rule_str
, match_arg
) == 0 || match_arg
== NULL
))
591 route_map_rule_delete (&index
->match_list
, rule
);
592 /* Execute event hook. */
593 if (route_map_master
.event_hook
)
594 (*route_map_master
.event_hook
) (RMAP_EVENT_MATCH_DELETED
,
598 /* Can't find matched rule. */
602 /* Add route-map set statement to the route map. */
604 route_map_add_set (struct route_map_index
*index
, const char *set_name
,
607 struct route_map_rule
*rule
;
608 struct route_map_rule
*next
;
609 struct route_map_rule_cmd
*cmd
;
613 cmd
= route_map_lookup_set (set_name
);
615 return RMAP_RULE_MISSING
;
617 /* Next call compile function for this match statement. */
618 if (cmd
->func_compile
)
620 compile
= (*cmd
->func_compile
)(set_arg
);
622 return RMAP_COMPILE_ERROR
;
627 /* Add by WJL. if old set command of same kind exist, delete it first
628 to ensure only one set command of same kind exist under a
630 for (rule
= index
->set_list
.head
; rule
; rule
= next
)
633 if (rule
->cmd
== cmd
)
635 route_map_rule_delete (&index
->set_list
, rule
);
640 /* Add new route map match rule. */
641 rule
= route_map_rule_new ();
643 rule
->value
= compile
;
645 rule
->rule_str
= XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR
, set_arg
);
647 rule
->rule_str
= NULL
;
649 /* Add new route match rule to linked list. */
650 route_map_rule_add (&index
->set_list
, rule
);
652 /* Execute event hook. */
653 if (route_map_master
.event_hook
)
654 (*route_map_master
.event_hook
) (replaced
?
655 RMAP_EVENT_SET_REPLACED
:
656 RMAP_EVENT_SET_ADDED
,
661 /* Delete route map set rule. */
663 route_map_delete_set (struct route_map_index
*index
, const char *set_name
,
666 struct route_map_rule
*rule
;
667 struct route_map_rule_cmd
*cmd
;
669 cmd
= route_map_lookup_set (set_name
);
673 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
674 if ((rule
->cmd
== cmd
) &&
675 (rulecmp (rule
->rule_str
, set_arg
) == 0 || set_arg
== NULL
))
677 route_map_rule_delete (&index
->set_list
, rule
);
678 /* Execute event hook. */
679 if (route_map_master
.event_hook
)
680 (*route_map_master
.event_hook
) (RMAP_EVENT_SET_DELETED
,
684 /* Can't find matched rule. */
688 /* Apply route map's each index to the object.
690 The matrix for a route-map looks like this:
691 (note, this includes the description for the "NEXT"
698 ------------------+---------------
704 -Apply Set statements, accept route
705 -If Call statement is present jump to the specified route-map, if it
706 denies the route we finish.
707 -If NEXT is specified, goto NEXT statement
708 -If GOTO is specified, goto the first clause where pref > nextpref
709 -If nothing is specified, do as Cisco and finish
711 -Route is denied by route-map.
715 If we get no matches after we've processed all updates, then the route
718 Some notes on the new "CALL", "NEXT" and "GOTO"
719 call WORD - If this clause is matched, then the set statements
720 are executed and then we jump to route-map 'WORD'. If
721 this route-map denies the route, we finish, in other case we
722 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
723 on-match next - If this clause is matched, then the set statements
724 are executed and then we drop through to the next clause
725 on-match goto n - If this clause is matched, then the set statments
726 are executed and then we goto the nth clause, or the
727 first clause greater than this. In order to ensure
728 route-maps *always* exit, you cannot jump backwards.
731 We need to make sure our route-map processing matches the above
734 static route_map_result_t
735 route_map_apply_match (struct route_map_rule_list
*match_list
,
736 struct prefix
*prefix
, route_map_object_t type
,
739 route_map_result_t ret
= RMAP_NOMATCH
;
740 struct route_map_rule
*match
;
743 /* Check all match rule and if there is no match rule, go to the
745 if (!match_list
->head
)
749 for (match
= match_list
->head
; match
; match
= match
->next
)
751 /* Try each match statement in turn, If any do not return
752 RMAP_MATCH, return, otherwise continue on to next match
753 statement. All match statements must match for end-result
755 ret
= (*match
->cmd
->func_apply
) (match
->value
, prefix
,
757 if (ret
!= RMAP_MATCH
)
764 /* Apply route map to the object. */
766 route_map_apply (struct route_map
*map
, struct prefix
*prefix
,
767 route_map_object_t type
, void *object
)
769 static int recursion
= 0;
771 struct route_map_index
*index
;
772 struct route_map_rule
*set
;
774 if (recursion
> RMAP_RECURSION_LIMIT
)
776 zlog (NULL
, LOG_WARNING
,
777 "route-map recursion limit (%d) reached, discarding route",
778 RMAP_RECURSION_LIMIT
);
780 return RMAP_DENYMATCH
;
784 return RMAP_DENYMATCH
;
786 for (index
= map
->head
; index
; index
= index
->next
)
788 /* Apply this index. */
789 ret
= route_map_apply_match (&index
->match_list
, prefix
, type
, object
);
791 /* Now we apply the matrix from above */
792 if (ret
== RMAP_NOMATCH
)
793 /* 'cont' from matrix - continue to next route-map sequence */
795 else if (ret
== RMAP_MATCH
)
797 if (index
->type
== RMAP_PERMIT
)
800 /* permit+match must execute sets */
801 for (set
= index
->set_list
.head
; set
; set
= set
->next
)
802 ret
= (*set
->cmd
->func_apply
) (set
->value
, prefix
,
805 /* Call another route-map if available */
808 struct route_map
*nextrm
=
809 route_map_lookup_by_name (index
->nextrm
);
811 if (nextrm
) /* Target route-map found, jump to it */
814 ret
= route_map_apply (nextrm
, prefix
, type
, object
);
818 /* If nextrm returned 'deny', finish. */
819 if (ret
== RMAP_DENYMATCH
)
823 switch (index
->exitpolicy
)
831 /* Find the next clause to jump to */
832 struct route_map_index
*next
= index
->next
;
833 int nextpref
= index
->nextpref
;
835 while (next
&& next
->pref
< nextpref
)
842 /* No clauses match! */
848 else if (index
->type
== RMAP_DENY
)
851 return RMAP_DENYMATCH
;
855 /* Finally route-map does not match at all. */
856 return RMAP_DENYMATCH
;
860 route_map_add_hook (void (*func
) (const char *))
862 route_map_master
.add_hook
= func
;
866 route_map_delete_hook (void (*func
) (const char *))
868 route_map_master
.delete_hook
= func
;
872 route_map_event_hook (void (*func
) (route_map_event_t
, const char *))
874 route_map_master
.event_hook
= func
;
878 route_map_init (void)
880 /* Make vector for match and set. */
881 route_match_vec
= vector_init (1);
882 route_set_vec
= vector_init (1);
885 /* VTY related functions. */
888 "route-map WORD (deny|permit) <1-65535>",
889 "Create route-map or enter route-map command mode\n"
891 "Route map denies set operations\n"
892 "Route map permits set operations\n"
893 "Sequence to insert to/delete from existing route-map entry\n")
897 struct route_map
*map
;
898 struct route_map_index
*index
;
902 if (strncmp (argv
[1], "permit", strlen (argv
[1])) == 0)
903 permit
= RMAP_PERMIT
;
904 else if (strncmp (argv
[1], "deny", strlen (argv
[1])) == 0)
908 vty_out (vty
, "the third field must be [permit|deny]%s", VTY_NEWLINE
);
912 /* Preference check. */
913 pref
= strtoul (argv
[2], &endptr
, 10);
914 if (pref
== ULONG_MAX
|| *endptr
!= '\0')
916 vty_out (vty
, "the fourth field must be positive integer%s",
920 if (pref
== 0 || pref
> 65535)
922 vty_out (vty
, "the fourth field must be <1-65535>%s", VTY_NEWLINE
);
927 map
= route_map_get (argv
[0]);
928 index
= route_map_index_get (map
, permit
, pref
);
931 vty
->node
= RMAP_NODE
;
935 DEFUN (no_route_map_all
,
936 no_route_map_all_cmd
,
939 "Create route-map or enter route-map command mode\n"
942 struct route_map
*map
;
944 map
= route_map_lookup_by_name (argv
[0]);
947 vty_out (vty
, "%% Could not find route-map %s%s",
948 argv
[0], VTY_NEWLINE
);
952 route_map_delete (map
);
959 "no route-map WORD (deny|permit) <1-65535>",
961 "Create route-map or enter route-map command mode\n"
963 "Route map denies set operations\n"
964 "Route map permits set operations\n"
965 "Sequence to insert to/delete from existing route-map entry\n")
969 struct route_map
*map
;
970 struct route_map_index
*index
;
974 if (strncmp (argv
[1], "permit", strlen (argv
[1])) == 0)
975 permit
= RMAP_PERMIT
;
976 else if (strncmp (argv
[1], "deny", strlen (argv
[1])) == 0)
980 vty_out (vty
, "the third field must be [permit|deny]%s", VTY_NEWLINE
);
985 pref
= strtoul (argv
[2], &endptr
, 10);
986 if (pref
== ULONG_MAX
|| *endptr
!= '\0')
988 vty_out (vty
, "the fourth field must be positive integer%s",
992 if (pref
== 0 || pref
> 65535)
994 vty_out (vty
, "the fourth field must be <1-65535>%s", VTY_NEWLINE
);
998 /* Existence check. */
999 map
= route_map_lookup_by_name (argv
[0]);
1002 vty_out (vty
, "%% Could not find route-map %s%s",
1003 argv
[0], VTY_NEWLINE
);
1007 /* Lookup route map index. */
1008 index
= route_map_index_lookup (map
, permit
, pref
);
1011 vty_out (vty
, "%% Could not find route-map entry %s %s%s",
1012 argv
[0], argv
[2], VTY_NEWLINE
);
1016 /* Delete index from route map. */
1017 route_map_index_delete (index
, 1);
1019 /* If this route rule is the last one, delete route map itself. */
1020 if (route_map_empty (map
))
1021 route_map_delete (map
);
1026 DEFUN (rmap_onmatch_next
,
1027 rmap_onmatch_next_cmd
,
1029 "Exit policy on matches\n"
1032 struct route_map_index
*index
;
1037 index
->exitpolicy
= RMAP_NEXT
;
1042 DEFUN (no_rmap_onmatch_next
,
1043 no_rmap_onmatch_next_cmd
,
1046 "Exit policy on matches\n"
1049 struct route_map_index
*index
;
1054 index
->exitpolicy
= RMAP_EXIT
;
1059 DEFUN (rmap_onmatch_goto
,
1060 rmap_onmatch_goto_cmd
,
1061 "on-match goto <1-65535>",
1062 "Exit policy on matches\n"
1063 "Goto Clause number\n"
1066 struct route_map_index
*index
;
1075 if (d
<= index
->pref
)
1077 /* Can't allow you to do that, Dave */
1078 vty_out (vty
, "can't jump backwards in route-maps%s",
1084 index
->exitpolicy
= RMAP_GOTO
;
1085 index
->nextpref
= d
;
1091 DEFUN (no_rmap_onmatch_goto
,
1092 no_rmap_onmatch_goto_cmd
,
1095 "Exit policy on matches\n"
1096 "Goto Clause number\n")
1098 struct route_map_index
*index
;
1103 index
->exitpolicy
= RMAP_EXIT
;
1108 /* Cisco/GNU Zebra compatible ALIASes for on-match next */
1109 ALIAS (rmap_onmatch_goto
,
1112 "Continue on a different entry within the route-map\n")
1114 ALIAS (no_rmap_onmatch_goto
,
1115 no_rmap_continue_cmd
,
1118 "Continue on a different entry within the route-map\n")
1120 /* GNU Zebra compatible */
1121 ALIAS (rmap_onmatch_goto
,
1122 rmap_continue_seq_cmd
,
1123 "continue <1-65535>",
1124 "Continue on a different entry within the route-map\n"
1125 "Route-map entry sequence number\n")
1127 ALIAS (no_rmap_onmatch_goto
,
1128 no_rmap_continue_seq
,
1129 "no continue <1-65535>",
1131 "Continue on a different entry within the route-map\n"
1132 "Route-map entry sequence number\n")
1138 "route-map information\n")
1140 return vty_show_route_map (vty
, NULL
);
1143 DEFUN (rmap_show_name
,
1145 "show route-map WORD",
1147 "route-map information\n"
1150 return vty_show_route_map (vty
, argv
[0]);
1153 ALIAS (rmap_onmatch_goto
,
1154 rmap_continue_index_cmd
,
1155 "continue <1-65536>",
1156 "Exit policy on matches\n"
1157 "Goto Clause number\n")
1162 "Jump to another Route-Map after match+set\n"
1163 "Target route-map name\n")
1165 struct route_map_index
*index
;
1171 free (index
->nextrm
);
1172 index
->nextrm
= strdup (argv
[0]);
1177 DEFUN (no_rmap_call
,
1181 "Jump to another Route-Map after match+set\n")
1183 struct route_map_index
*index
;
1189 free (index
->nextrm
);
1190 index
->nextrm
= NULL
;
1196 DEFUN (rmap_description
,
1197 rmap_description_cmd
,
1198 "description .LINE",
1199 "Route-map comment\n"
1200 "Comment describing this route-map rule\n")
1202 struct route_map_index
*index
;
1207 if (index
->description
)
1208 XFREE (MTYPE_TMP
, index
->description
);
1209 index
->description
= argv_concat (argv
, argc
, 0);
1214 DEFUN (no_rmap_description
,
1215 no_rmap_description_cmd
,
1218 "Route-map comment\n")
1220 struct route_map_index
*index
;
1225 if (index
->description
)
1226 XFREE (MTYPE_TMP
, index
->description
);
1227 index
->description
= NULL
;
1232 /* Configuration write function. */
1234 route_map_config_write (struct vty
*vty
)
1236 struct route_map
*map
;
1237 struct route_map_index
*index
;
1238 struct route_map_rule
*rule
;
1242 for (map
= route_map_master
.head
; map
; map
= map
->next
)
1243 for (index
= map
->head
; index
; index
= index
->next
)
1246 vty_out (vty
, "!%s", VTY_NEWLINE
);
1250 vty_out (vty
, "route-map %s %s %d%s",
1252 route_map_type_str (index
->type
),
1253 index
->pref
, VTY_NEWLINE
);
1255 if (index
->description
)
1256 vty_out (vty
, " description %s%s", index
->description
, VTY_NEWLINE
);
1258 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1259 vty_out (vty
, " match %s %s%s", rule
->cmd
->str
,
1260 rule
->rule_str
? rule
->rule_str
: "",
1263 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
1264 vty_out (vty
, " set %s %s%s", rule
->cmd
->str
,
1265 rule
->rule_str
? rule
->rule_str
: "",
1268 vty_out (vty
, " call %s%s", index
->nextrm
, VTY_NEWLINE
);
1269 if (index
->exitpolicy
== RMAP_GOTO
)
1270 vty_out (vty
, " on-match goto %d%s", index
->nextpref
, VTY_NEWLINE
);
1271 if (index
->exitpolicy
== RMAP_NEXT
)
1272 vty_out (vty
," on-match next%s", VTY_NEWLINE
);
1279 /* Route map node structure. */
1280 struct cmd_node rmap_node
=
1283 "%s(config-route-map)# ",
1287 /* Initialization of route map vector. */
1289 route_map_init_vty (void)
1291 /* Install route map top node. */
1292 install_node (&rmap_node
, route_map_config_write
);
1294 /* Install route map commands. */
1295 install_default (RMAP_NODE
);
1296 install_element (CONFIG_NODE
, &route_map_cmd
);
1297 install_element (CONFIG_NODE
, &no_route_map_cmd
);
1298 install_element (CONFIG_NODE
, &no_route_map_all_cmd
);
1300 /* Install the on-match stuff */
1301 install_element (RMAP_NODE
, &route_map_cmd
);
1302 install_element (RMAP_NODE
, &rmap_onmatch_next_cmd
);
1303 install_element (RMAP_NODE
, &no_rmap_onmatch_next_cmd
);
1304 install_element (RMAP_NODE
, &rmap_onmatch_goto_cmd
);
1305 install_element (RMAP_NODE
, &no_rmap_onmatch_goto_cmd
);
1307 /* Install the continue stuff (ALIAS of on-match). */
1308 install_element (RMAP_NODE
, &rmap_continue_cmd
);
1309 install_element (RMAP_NODE
, &no_rmap_continue_cmd
);
1310 install_element (RMAP_NODE
, &rmap_continue_index_cmd
);
1312 /* Install the call stuff. */
1313 install_element (RMAP_NODE
, &rmap_call_cmd
);
1314 install_element (RMAP_NODE
, &no_rmap_call_cmd
);
1316 /* Install description commands. */
1317 install_element (RMAP_NODE
, &rmap_description_cmd
);
1318 install_element (RMAP_NODE
, &no_rmap_description_cmd
);
1320 /* Install show command */
1321 install_element (ENABLE_NODE
, &rmap_show_cmd
);
1322 install_element (ENABLE_NODE
, &rmap_show_name_cmd
);