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
33 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP
, "Route map")
34 DEFINE_MTYPE( LIB
, ROUTE_MAP_NAME
, "Route map name")
35 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_INDEX
, "Route map index")
36 DEFINE_MTYPE( LIB
, ROUTE_MAP_RULE
, "Route map rule")
37 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_RULE_STR
, "Route map rule str")
38 DEFINE_MTYPE( LIB
, ROUTE_MAP_COMPILED
, "Route map compiled")
39 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_DEP
, "Route map dependency")
41 DEFINE_QOBJ_TYPE(route_map_index
)
42 DEFINE_QOBJ_TYPE(route_map
)
44 /* Vector for route match rules. */
45 static vector route_match_vec
;
47 /* Vector for route set rules. */
48 static vector route_set_vec
;
50 /* Route map rule. This rule has both `match' rule and `set' rule. */
54 struct route_map_rule_cmd
*cmd
;
56 /* For pretty printing. */
59 /* Pre-compiled match rule. */
63 struct route_map_rule
*next
;
64 struct route_map_rule
*prev
;
67 /* Making route map list. */
70 struct route_map
*head
;
71 struct route_map
*tail
;
73 void (*add_hook
) (const char *);
74 void (*delete_hook
) (const char *);
75 void (*event_hook
) (route_map_event_t
, const char *);
78 /* Master list of route map. */
79 static struct route_map_list route_map_master
= { NULL
, NULL
, NULL
, NULL
, NULL
};
80 struct hash
*route_map_master_hash
= NULL
;
83 route_map_hash_key_make (void *p
)
85 const struct route_map
*map
= p
;
86 return string_hash_make (map
->name
);
90 route_map_hash_cmp(const void *p1
, const void *p2
)
92 const struct route_map
*map1
= p1
;
93 const struct route_map
*map2
= p2
;
95 if (map1
->deleted
== map2
->deleted
)
97 if (map1
->name
&& map2
->name
)
99 if (!strcmp (map1
->name
, map2
->name
))
104 else if (!map1
->name
&& !map2
->name
)
113 enum route_map_upd8_type
119 /* all possible route-map dependency types */
120 enum route_map_dep_type
122 ROUTE_MAP_DEP_RMAP
= 1,
124 ROUTE_MAP_DEP_ECLIST
,
126 ROUTE_MAP_DEP_ASPATH
,
127 ROUTE_MAP_DEP_FILTER
,
134 struct hash
*dep_rmap_hash
;
135 struct hash
*this_hash
; /* ptr to the hash structure this is part of */
138 /* Hashes maintaining dependency between various sublists used by route maps */
139 struct hash
*route_map_dep_hash
[ROUTE_MAP_DEP_MAX
];
141 static unsigned int route_map_dep_hash_make_key (void *p
);
142 static int route_map_dep_hash_cmp (const void *p1
, const void *p2
);
143 static void route_map_clear_all_references (char *rmap_name
);
144 static void route_map_rule_delete (struct route_map_rule_list
*,
145 struct route_map_rule
*);
146 static int rmap_debug
= 0;
149 route_map_index_delete (struct route_map_index
*, int);
151 /* New route map allocation. Please note route map's name must be
153 static struct route_map
*
154 route_map_new (const char *name
)
156 struct route_map
*new;
158 new = XCALLOC (MTYPE_ROUTE_MAP
, sizeof (struct route_map
));
159 new->name
= XSTRDUP (MTYPE_ROUTE_MAP_NAME
, name
);
160 QOBJ_REG (new, route_map
);
164 /* Add new name to route_map. */
165 static struct route_map
*
166 route_map_add (const char *name
)
168 struct route_map
*map
;
169 struct route_map_list
*list
;
171 map
= route_map_new (name
);
172 list
= &route_map_master
;
174 /* Add map to the hash */
175 hash_get(route_map_master_hash
, map
, hash_alloc_intern
);
177 /* Add new entry to the head of the list to match how it is added in the
178 * hash table. This is to ensure that if the same route-map has been
179 * created more than once and then marked for deletion (which can happen
180 * if prior deletions haven't completed as BGP hasn't yet done the
181 * route-map processing), the order of the entities is the same in both
182 * the list and the hash table. Otherwise, since there is nothing to
183 * distinguish between the two entries, the wrong entry could get freed.
184 * TODO: This needs to be re-examined to handle it better - e.g., revive
185 * a deleted entry if the route-map is created again.
188 map
->next
= list
->head
;
190 list
->head
->prev
= map
;
196 if (route_map_master
.add_hook
)
198 (*route_map_master
.add_hook
) (name
);
199 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_ADDED
);
204 /* this is supposed to be called post processing by
205 * the delete hook function. Don't invoke delete_hook
206 * again in this routine.
209 route_map_free_map (struct route_map
*map
)
211 struct route_map_list
*list
;
212 struct route_map_index
*index
;
214 while ((index
= map
->head
) != NULL
)
215 route_map_index_delete (index
, 0);
217 list
= &route_map_master
;
224 map
->next
->prev
= map
->prev
;
226 list
->tail
= map
->prev
;
229 map
->prev
->next
= map
->next
;
231 list
->head
= map
->next
;
233 hash_release(route_map_master_hash
, map
);
234 XFREE (MTYPE_ROUTE_MAP_NAME
, map
->name
);
235 XFREE (MTYPE_ROUTE_MAP
, map
);
239 /* Route map delete from list. */
241 route_map_delete (struct route_map
*map
)
243 struct route_map_index
*index
;
246 while ((index
= map
->head
) != NULL
)
247 route_map_index_delete (index
, 0);
252 /* Clear all dependencies */
253 route_map_clear_all_references(name
);
255 /* Execute deletion hook. */
256 if (route_map_master
.delete_hook
)
258 (*route_map_master
.delete_hook
) (name
);
259 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_DELETED
);
262 if (!map
->to_be_processed
)
264 route_map_free_map (map
);
268 /* Lookup route map by route map name string. */
270 route_map_lookup_by_name (const char *name
)
272 struct route_map
*map
;
273 struct route_map tmp_map
;
278 // map.deleted is 0 via memset
279 memset(&tmp_map
, 0, sizeof(struct route_map
));
280 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
281 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
282 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
287 route_map_mark_updated (const char *name
, int del_later
)
289 struct route_map
*map
;
291 struct route_map tmp_map
;
296 map
= route_map_lookup_by_name(name
);
298 /* If we did not find the routemap with deleted=0 try again
303 memset(&tmp_map
, 0, sizeof(struct route_map
));
304 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
306 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
307 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
312 map
->to_be_processed
= 1;
320 route_map_clear_updated (struct route_map
*map
)
326 map
->to_be_processed
= 0;
328 route_map_free_map(map
);
334 /* Lookup route map. If there isn't route map create one and return
336 static struct route_map
*
337 route_map_get (const char *name
)
339 struct route_map
*map
;
341 map
= route_map_lookup_by_name (name
);
343 map
= route_map_add (name
);
349 route_map_walk_update_list (int (*route_map_update_fn
) (char *name
))
351 struct route_map
*node
;
352 struct route_map
*nnode
= NULL
;
354 for (node
= route_map_master
.head
; node
; node
= nnode
)
356 if (node
->to_be_processed
)
358 /* DD: Should we add any thread yield code here */
359 route_map_update_fn(node
->name
);
361 route_map_clear_updated(node
);
368 /* Return route map's type string. */
370 route_map_type_str (enum route_map_type type
)
387 route_map_empty (struct route_map
*map
)
389 if (map
->head
== NULL
&& map
->tail
== NULL
)
397 vty_show_route_map_entry (struct vty
*vty
, struct route_map
*map
)
399 struct route_map_index
*index
;
400 struct route_map_rule
*rule
;
402 /* Print the name of the protocol */
404 vty_out (vty
, "%s", zlog_proto_names
[zlog_default
->protocol
]);
405 if (zlog_default
->instance
)
406 vty_out (vty
, " %d", zlog_default
->instance
);
407 vty_out (vty
, ":%s", VTY_NEWLINE
);
409 for (index
= map
->head
; index
; index
= index
->next
)
411 vty_out (vty
, "route-map %s, %s, sequence %d%s",
412 map
->name
, route_map_type_str (index
->type
),
413 index
->pref
, VTY_NEWLINE
);
416 if (index
->description
)
417 vty_out (vty
, " Description:%s %s%s", VTY_NEWLINE
,
418 index
->description
, VTY_NEWLINE
);
421 vty_out (vty
, " Match clauses:%s", VTY_NEWLINE
);
422 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
423 vty_out (vty
, " %s %s%s",
424 rule
->cmd
->str
, rule
->rule_str
, VTY_NEWLINE
);
426 vty_out (vty
, " Set clauses:%s", VTY_NEWLINE
);
427 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
428 vty_out (vty
, " %s %s%s",
429 rule
->cmd
->str
, rule
->rule_str
, VTY_NEWLINE
);
432 vty_out (vty
, " Call clause:%s", VTY_NEWLINE
);
434 vty_out (vty
, " Call %s%s", index
->nextrm
, VTY_NEWLINE
);
437 vty_out (vty
, " Action:%s", VTY_NEWLINE
);
438 if (index
->exitpolicy
== RMAP_GOTO
)
439 vty_out (vty
, " Goto %d%s", index
->nextpref
, VTY_NEWLINE
);
440 else if (index
->exitpolicy
== RMAP_NEXT
)
441 vty_out (vty
, " Continue to next entry%s", VTY_NEWLINE
);
442 else if (index
->exitpolicy
== RMAP_EXIT
)
443 vty_out (vty
, " Exit routemap%s", VTY_NEWLINE
);
448 vty_show_route_map (struct vty
*vty
, const char *name
)
450 struct route_map
*map
;
454 map
= route_map_lookup_by_name (name
);
458 vty_show_route_map_entry (vty
, map
);
464 vty_out (vty
, "%s", zlog_proto_names
[zlog_default
->protocol
]);
465 if (zlog_default
->instance
)
466 vty_out (vty
, " %d", zlog_default
->instance
);
467 vty_out (vty
, ": 'route-map %s' not found%s", name
, VTY_NEWLINE
);
473 for (map
= route_map_master
.head
; map
; map
= map
->next
)
475 vty_show_route_map_entry (vty
, map
);
481 /* New route map allocation. Please note route map's name must be
483 static struct route_map_index
*
484 route_map_index_new (void)
486 struct route_map_index
*new;
488 new = XCALLOC (MTYPE_ROUTE_MAP_INDEX
, sizeof (struct route_map_index
));
489 new->exitpolicy
= RMAP_EXIT
; /* Default to Cisco-style */
490 QOBJ_REG (new, route_map_index
);
494 /* Free route map index. */
496 route_map_index_delete (struct route_map_index
*index
, int notify
)
498 struct route_map_rule
*rule
;
502 /* Free route match. */
503 while ((rule
= index
->match_list
.head
) != NULL
)
504 route_map_rule_delete (&index
->match_list
, rule
);
506 /* Free route set. */
507 while ((rule
= index
->set_list
.head
) != NULL
)
508 route_map_rule_delete (&index
->set_list
, rule
);
510 /* Remove index from route map list. */
512 index
->next
->prev
= index
->prev
;
514 index
->map
->tail
= index
->prev
;
517 index
->prev
->next
= index
->next
;
519 index
->map
->head
= index
->next
;
521 /* Free 'char *nextrm' if not NULL */
523 XFREE (MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
525 /* Execute event hook. */
526 if (route_map_master
.event_hook
&& notify
)
528 (*route_map_master
.event_hook
) (RMAP_EVENT_INDEX_DELETED
,
530 route_map_notify_dependencies(index
->map
->name
, RMAP_EVENT_CALL_ADDED
);
532 XFREE (MTYPE_ROUTE_MAP_INDEX
, index
);
535 /* Lookup index from route map. */
536 static struct route_map_index
*
537 route_map_index_lookup (struct route_map
*map
, enum route_map_type type
,
540 struct route_map_index
*index
;
542 for (index
= map
->head
; index
; index
= index
->next
)
543 if ((index
->type
== type
|| type
== RMAP_ANY
)
544 && index
->pref
== pref
)
549 /* Add new index to route map. */
550 static struct route_map_index
*
551 route_map_index_add (struct route_map
*map
, enum route_map_type type
,
554 struct route_map_index
*index
;
555 struct route_map_index
*point
;
557 /* Allocate new route map inex. */
558 index
= route_map_index_new ();
563 /* Compare preference. */
564 for (point
= map
->head
; point
; point
= point
->next
)
565 if (point
->pref
>= pref
)
568 if (map
->head
== NULL
)
570 map
->head
= map
->tail
= index
;
572 else if (point
== NULL
)
574 index
->prev
= map
->tail
;
575 map
->tail
->next
= index
;
578 else if (point
== map
->head
)
580 index
->next
= map
->head
;
581 map
->head
->prev
= index
;
587 index
->prev
= point
->prev
;
589 point
->prev
->next
= index
;
593 /* Execute event hook. */
594 if (route_map_master
.event_hook
)
596 (*route_map_master
.event_hook
) (RMAP_EVENT_INDEX_ADDED
,
598 route_map_notify_dependencies (map
->name
, RMAP_EVENT_CALL_ADDED
);
603 /* Get route map index. */
604 static struct route_map_index
*
605 route_map_index_get (struct route_map
*map
, enum route_map_type type
,
608 struct route_map_index
*index
;
610 index
= route_map_index_lookup (map
, RMAP_ANY
, pref
);
611 if (index
&& index
->type
!= type
)
613 /* Delete index from route map. */
614 route_map_index_delete (index
, 1);
618 index
= route_map_index_add (map
, type
, pref
);
622 /* New route map rule */
623 static struct route_map_rule
*
624 route_map_rule_new (void)
626 struct route_map_rule
*new;
628 new = XCALLOC (MTYPE_ROUTE_MAP_RULE
, sizeof (struct route_map_rule
));
632 /* Install rule command to the match list. */
634 route_map_install_match (struct route_map_rule_cmd
*cmd
)
636 vector_set (route_match_vec
, cmd
);
639 /* Install rule command to the set list. */
641 route_map_install_set (struct route_map_rule_cmd
*cmd
)
643 vector_set (route_set_vec
, cmd
);
646 /* Lookup rule command from match list. */
647 static struct route_map_rule_cmd
*
648 route_map_lookup_match (const char *name
)
651 struct route_map_rule_cmd
*rule
;
653 for (i
= 0; i
< vector_active (route_match_vec
); i
++)
654 if ((rule
= vector_slot (route_match_vec
, i
)) != NULL
)
655 if (strcmp (rule
->str
, name
) == 0)
660 /* Lookup rule command from set list. */
661 static struct route_map_rule_cmd
*
662 route_map_lookup_set (const char *name
)
665 struct route_map_rule_cmd
*rule
;
667 for (i
= 0; i
< vector_active (route_set_vec
); i
++)
668 if ((rule
= vector_slot (route_set_vec
, i
)) != NULL
)
669 if (strcmp (rule
->str
, name
) == 0)
674 /* Add match and set rule to rule list. */
676 route_map_rule_add (struct route_map_rule_list
*list
,
677 struct route_map_rule
*rule
)
680 rule
->prev
= list
->tail
;
682 list
->tail
->next
= rule
;
688 /* Delete rule from rule list. */
690 route_map_rule_delete (struct route_map_rule_list
*list
,
691 struct route_map_rule
*rule
)
693 if (rule
->cmd
->func_free
)
694 (*rule
->cmd
->func_free
) (rule
->value
);
697 XFREE (MTYPE_ROUTE_MAP_RULE_STR
, rule
->rule_str
);
700 rule
->next
->prev
= rule
->prev
;
702 list
->tail
= rule
->prev
;
704 rule
->prev
->next
= rule
->next
;
706 list
->head
= rule
->next
;
708 XFREE (MTYPE_ROUTE_MAP_RULE
, rule
);
711 /* strcmp wrapper function which don't crush even argument is NULL. */
713 rulecmp (const char *dst
, const char *src
)
727 return strcmp (dst
, src
);
732 /* Use this to return the already specified argument for this match. This is
733 * useful to get the specified argument with a route map match rule when the
734 * rule is being deleted and the argument is not provided.
737 route_map_get_match_arg(struct route_map_index
*index
, const char *match_name
)
739 struct route_map_rule
*rule
;
740 struct route_map_rule_cmd
*cmd
;
742 /* First lookup rule for add match statement. */
743 cmd
= route_map_lookup_match (match_name
);
747 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
748 if (rule
->cmd
== cmd
&& rule
->rule_str
!= NULL
)
749 return (rule
->rule_str
);
754 /* Add match statement to route map. */
756 route_map_add_match (struct route_map_index
*index
, const char *match_name
,
757 const char *match_arg
)
759 struct route_map_rule
*rule
;
760 struct route_map_rule
*next
;
761 struct route_map_rule_cmd
*cmd
;
765 /* First lookup rule for add match statement. */
766 cmd
= route_map_lookup_match (match_name
);
768 return RMAP_RULE_MISSING
;
770 /* Next call compile function for this match statement. */
771 if (cmd
->func_compile
)
773 compile
= (*cmd
->func_compile
)(match_arg
);
775 return RMAP_COMPILE_ERROR
;
780 /* If argument is completely same ignore it. */
781 for (rule
= index
->match_list
.head
; rule
; rule
= next
)
784 if (rule
->cmd
== cmd
)
786 route_map_rule_delete (&index
->match_list
, rule
);
791 /* Add new route map match rule. */
792 rule
= route_map_rule_new ();
794 rule
->value
= compile
;
796 rule
->rule_str
= XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR
, match_arg
);
798 rule
->rule_str
= NULL
;
800 /* Add new route match rule to linked list. */
801 route_map_rule_add (&index
->match_list
, rule
);
803 /* Execute event hook. */
804 if (route_map_master
.event_hook
)
806 (*route_map_master
.event_hook
) (replaced
?
807 RMAP_EVENT_MATCH_REPLACED
:
808 RMAP_EVENT_MATCH_ADDED
,
810 route_map_notify_dependencies(index
->map
->name
, RMAP_EVENT_CALL_ADDED
);
816 /* Delete specified route match rule. */
818 route_map_delete_match (struct route_map_index
*index
, const char *match_name
,
819 const char *match_arg
)
821 struct route_map_rule
*rule
;
822 struct route_map_rule_cmd
*cmd
;
824 cmd
= route_map_lookup_match (match_name
);
828 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
829 if (rule
->cmd
== cmd
&&
830 (rulecmp (rule
->rule_str
, match_arg
) == 0 || match_arg
== NULL
))
832 route_map_rule_delete (&index
->match_list
, rule
);
833 /* Execute event hook. */
834 if (route_map_master
.event_hook
)
836 (*route_map_master
.event_hook
) (RMAP_EVENT_MATCH_DELETED
,
838 route_map_notify_dependencies(index
->map
->name
, RMAP_EVENT_CALL_ADDED
);
842 /* Can't find matched rule. */
846 /* Add route-map set statement to the route map. */
848 route_map_add_set (struct route_map_index
*index
, const char *set_name
,
851 struct route_map_rule
*rule
;
852 struct route_map_rule
*next
;
853 struct route_map_rule_cmd
*cmd
;
857 cmd
= route_map_lookup_set (set_name
);
859 return RMAP_RULE_MISSING
;
861 /* Next call compile function for this match statement. */
862 if (cmd
->func_compile
)
864 compile
= (*cmd
->func_compile
)(set_arg
);
866 return RMAP_COMPILE_ERROR
;
871 /* Add by WJL. if old set command of same kind exist, delete it first
872 to ensure only one set command of same kind exist under a
874 for (rule
= index
->set_list
.head
; rule
; rule
= next
)
877 if (rule
->cmd
== cmd
)
879 route_map_rule_delete (&index
->set_list
, rule
);
884 /* Add new route map match rule. */
885 rule
= route_map_rule_new ();
887 rule
->value
= compile
;
889 rule
->rule_str
= XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR
, set_arg
);
891 rule
->rule_str
= NULL
;
893 /* Add new route match rule to linked list. */
894 route_map_rule_add (&index
->set_list
, rule
);
896 /* Execute event hook. */
897 if (route_map_master
.event_hook
)
899 (*route_map_master
.event_hook
) (replaced
?
900 RMAP_EVENT_SET_REPLACED
:
901 RMAP_EVENT_SET_ADDED
,
903 route_map_notify_dependencies(index
->map
->name
, RMAP_EVENT_CALL_ADDED
);
908 /* Delete route map set rule. */
910 route_map_delete_set (struct route_map_index
*index
, const char *set_name
,
913 struct route_map_rule
*rule
;
914 struct route_map_rule_cmd
*cmd
;
916 cmd
= route_map_lookup_set (set_name
);
920 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
921 if ((rule
->cmd
== cmd
) &&
922 (rulecmp (rule
->rule_str
, set_arg
) == 0 || set_arg
== NULL
))
924 route_map_rule_delete (&index
->set_list
, rule
);
925 /* Execute event hook. */
926 if (route_map_master
.event_hook
)
928 (*route_map_master
.event_hook
) (RMAP_EVENT_SET_DELETED
,
930 route_map_notify_dependencies(index
->map
->name
, RMAP_EVENT_CALL_ADDED
);
934 /* Can't find matched rule. */
938 /* Apply route map's each index to the object.
940 The matrix for a route-map looks like this:
941 (note, this includes the description for the "NEXT"
948 ------------------+---------------
954 -Apply Set statements, accept route
955 -If Call statement is present jump to the specified route-map, if it
956 denies the route we finish.
957 -If NEXT is specified, goto NEXT statement
958 -If GOTO is specified, goto the first clause where pref > nextpref
959 -If nothing is specified, do as Cisco and finish
961 -Route is denied by route-map.
965 If we get no matches after we've processed all updates, then the route
968 Some notes on the new "CALL", "NEXT" and "GOTO"
969 call WORD - If this clause is matched, then the set statements
970 are executed and then we jump to route-map 'WORD'. If
971 this route-map denies the route, we finish, in other case we
972 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
973 on-match next - If this clause is matched, then the set statements
974 are executed and then we drop through to the next clause
975 on-match goto n - If this clause is matched, then the set statments
976 are executed and then we goto the nth clause, or the
977 first clause greater than this. In order to ensure
978 route-maps *always* exit, you cannot jump backwards.
981 We need to make sure our route-map processing matches the above
984 static route_map_result_t
985 route_map_apply_match (struct route_map_rule_list
*match_list
,
986 struct prefix
*prefix
, route_map_object_t type
,
989 route_map_result_t ret
= RMAP_NOMATCH
;
990 struct route_map_rule
*match
;
993 /* Check all match rule and if there is no match rule, go to the
995 if (!match_list
->head
)
999 for (match
= match_list
->head
; match
; match
= match
->next
)
1001 /* Try each match statement in turn, If any do not return
1002 RMAP_MATCH, return, otherwise continue on to next match
1003 statement. All match statements must match for end-result
1005 ret
= (*match
->cmd
->func_apply
) (match
->value
, prefix
,
1007 if (ret
!= RMAP_MATCH
)
1014 /* Apply route map to the object. */
1016 route_map_apply (struct route_map
*map
, struct prefix
*prefix
,
1017 route_map_object_t type
, void *object
)
1019 static int recursion
= 0;
1021 struct route_map_index
*index
;
1022 struct route_map_rule
*set
;
1024 if (recursion
> RMAP_RECURSION_LIMIT
)
1026 zlog (NULL
, LOG_WARNING
,
1027 "route-map recursion limit (%d) reached, discarding route",
1028 RMAP_RECURSION_LIMIT
);
1030 return RMAP_DENYMATCH
;
1034 return RMAP_DENYMATCH
;
1036 for (index
= map
->head
; index
; index
= index
->next
)
1038 /* Apply this index. */
1039 ret
= route_map_apply_match (&index
->match_list
, prefix
, type
, object
);
1041 /* Now we apply the matrix from above */
1042 if (ret
== RMAP_NOMATCH
)
1043 /* 'cont' from matrix - continue to next route-map sequence */
1045 else if (ret
== RMAP_MATCH
)
1047 if (index
->type
== RMAP_PERMIT
)
1050 /* permit+match must execute sets */
1051 for (set
= index
->set_list
.head
; set
; set
= set
->next
)
1052 ret
= (*set
->cmd
->func_apply
) (set
->value
, prefix
,
1055 /* Call another route-map if available */
1058 struct route_map
*nextrm
=
1059 route_map_lookup_by_name (index
->nextrm
);
1061 if (nextrm
) /* Target route-map found, jump to it */
1064 ret
= route_map_apply (nextrm
, prefix
, type
, object
);
1068 /* If nextrm returned 'deny', finish. */
1069 if (ret
== RMAP_DENYMATCH
)
1073 switch (index
->exitpolicy
)
1081 /* Find the next clause to jump to */
1082 struct route_map_index
*next
= index
->next
;
1083 int nextpref
= index
->nextpref
;
1085 while (next
&& next
->pref
< nextpref
)
1092 /* No clauses match! */
1098 else if (index
->type
== RMAP_DENY
)
1101 return RMAP_DENYMATCH
;
1105 /* Finally route-map does not match at all. */
1106 return RMAP_DENYMATCH
;
1110 route_map_add_hook (void (*func
) (const char *))
1112 route_map_master
.add_hook
= func
;
1116 route_map_delete_hook (void (*func
) (const char *))
1118 route_map_master
.delete_hook
= func
;
1122 route_map_event_hook (void (*func
) (route_map_event_t
, const char *))
1124 route_map_master
.event_hook
= func
;
1127 /* Routines for route map dependency lists and dependency processing */
1129 route_map_rmap_hash_cmp (const void *p1
, const void *p2
)
1131 return (strcmp((const char *)p1
, (const char *)p2
) == 0);
1135 route_map_dep_hash_cmp (const void *p1
, const void *p2
)
1138 return (strcmp (((const struct route_map_dep
*)p1
)->dep_name
, (const char *)p2
) == 0);
1142 route_map_clear_reference(struct hash_backet
*backet
, void *arg
)
1144 struct route_map_dep
*dep
= (struct route_map_dep
*)backet
->data
;
1149 rmap_name
= (char *)hash_release(dep
->dep_rmap_hash
, (void *)arg
);
1152 XFREE(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
1154 if (!dep
->dep_rmap_hash
->count
)
1156 dep
= hash_release(dep
->this_hash
, (void *)dep
->dep_name
);
1157 hash_free(dep
->dep_rmap_hash
);
1158 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
1159 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
1165 route_map_clear_all_references (char *rmap_name
)
1169 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++)
1171 hash_iterate(route_map_dep_hash
[i
], route_map_clear_reference
,
1177 route_map_dep_hash_alloc(void *p
)
1179 char *dep_name
= (char *)p
;
1180 struct route_map_dep
*dep_entry
;
1182 dep_entry
= XCALLOC(MTYPE_ROUTE_MAP_DEP
, sizeof(struct route_map_dep
));
1183 dep_entry
->dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1184 dep_entry
->dep_rmap_hash
= hash_create(route_map_dep_hash_make_key
,
1185 route_map_rmap_hash_cmp
);
1186 dep_entry
->this_hash
= NULL
;
1188 return((void *)dep_entry
);
1192 route_map_name_hash_alloc(void *p
)
1194 return((void *)XSTRDUP(MTYPE_ROUTE_MAP_NAME
, (const char *)p
));
1198 route_map_dep_hash_make_key (void *p
)
1200 return (string_hash_make((char *)p
));
1204 route_map_print_dependency (struct hash_backet
*backet
, void *data
)
1206 char *rmap_name
= (char *)backet
->data
;
1207 char *dep_name
= (char *)data
;
1210 zlog_debug("%s: Dependency for %s: %s", __FUNCTION__
, dep_name
, rmap_name
);
1214 route_map_dep_update (struct hash
*dephash
, const char *dep_name
,
1215 const char *rmap_name
,
1216 route_map_event_t type
)
1218 struct route_map_dep
*dep
= NULL
;
1220 char *dname
, *rname
;
1223 dname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1224 rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
1228 case RMAP_EVENT_PLIST_ADDED
:
1229 case RMAP_EVENT_CLIST_ADDED
:
1230 case RMAP_EVENT_ECLIST_ADDED
:
1231 case RMAP_EVENT_ASLIST_ADDED
:
1232 case RMAP_EVENT_CALL_ADDED
:
1233 case RMAP_EVENT_FILTER_ADDED
:
1235 zlog_debug("%s: Adding dependency for %s in %s", __FUNCTION__
,
1236 dep_name
, rmap_name
);
1237 dep
= (struct route_map_dep
*) hash_get (dephash
, dname
,
1238 route_map_dep_hash_alloc
);
1244 if (!dep
->this_hash
)
1245 dep
->this_hash
= dephash
;
1247 hash_get(dep
->dep_rmap_hash
, rname
, route_map_name_hash_alloc
);
1249 case RMAP_EVENT_PLIST_DELETED
:
1250 case RMAP_EVENT_CLIST_DELETED
:
1251 case RMAP_EVENT_ECLIST_DELETED
:
1252 case RMAP_EVENT_ASLIST_DELETED
:
1253 case RMAP_EVENT_CALL_DELETED
:
1254 case RMAP_EVENT_FILTER_DELETED
:
1256 zlog_debug("%s: Deleting dependency for %s in %s", __FUNCTION__
,
1257 dep_name
, rmap_name
);
1258 dep
= (struct route_map_dep
*) hash_get (dephash
, dname
, NULL
);
1263 ret_map_name
= (char *)hash_release(dep
->dep_rmap_hash
, rname
);
1265 XFREE(MTYPE_ROUTE_MAP_NAME
, ret_map_name
);
1267 if (!dep
->dep_rmap_hash
->count
)
1269 dep
= hash_release(dephash
, dname
);
1270 hash_free(dep
->dep_rmap_hash
);
1271 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
1272 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
1283 hash_iterate (dep
->dep_rmap_hash
, route_map_print_dependency
, dname
);
1287 XFREE(MTYPE_ROUTE_MAP_NAME
, rname
);
1288 XFREE(MTYPE_ROUTE_MAP_NAME
, dname
);
1292 static struct hash
*
1293 route_map_get_dep_hash (route_map_event_t event
)
1295 struct hash
*upd8_hash
= NULL
;
1299 case RMAP_EVENT_PLIST_ADDED
:
1300 case RMAP_EVENT_PLIST_DELETED
:
1301 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_PLIST
];
1303 case RMAP_EVENT_CLIST_ADDED
:
1304 case RMAP_EVENT_CLIST_DELETED
:
1305 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_CLIST
];
1307 case RMAP_EVENT_ECLIST_ADDED
:
1308 case RMAP_EVENT_ECLIST_DELETED
:
1309 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ECLIST
];
1311 case RMAP_EVENT_ASLIST_ADDED
:
1312 case RMAP_EVENT_ASLIST_DELETED
:
1313 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ASPATH
];
1315 case RMAP_EVENT_CALL_ADDED
:
1316 case RMAP_EVENT_CALL_DELETED
:
1317 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_RMAP
];
1319 case RMAP_EVENT_FILTER_ADDED
:
1320 case RMAP_EVENT_FILTER_DELETED
:
1321 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_FILTER
];
1331 route_map_process_dependency (struct hash_backet
*backet
, void *data
)
1334 route_map_event_t type
= (route_map_event_t
)(ptrdiff_t)data
;
1336 rmap_name
= (char *)backet
->data
;
1341 zlog_debug("%s: Notifying %s of dependency", __FUNCTION__
,
1343 if (route_map_master
.event_hook
)
1344 (*route_map_master
.event_hook
) (type
, rmap_name
);
1349 route_map_upd8_dependency (route_map_event_t type
, const char *arg
,
1350 const char *rmap_name
)
1352 struct hash
*upd8_hash
= NULL
;
1354 if ((upd8_hash
= route_map_get_dep_hash(type
)))
1355 route_map_dep_update (upd8_hash
, arg
, rmap_name
, type
);
1359 route_map_notify_dependencies (const char *affected_name
, route_map_event_t event
)
1361 struct route_map_dep
*dep
;
1362 struct hash
*upd8_hash
;
1368 name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, affected_name
);
1370 if ((upd8_hash
= route_map_get_dep_hash(event
)) == NULL
)
1372 XFREE (MTYPE_ROUTE_MAP_NAME
, name
);
1376 dep
= (struct route_map_dep
*)hash_get (upd8_hash
, name
,
1380 if (!dep
->this_hash
)
1381 dep
->this_hash
= upd8_hash
;
1383 hash_iterate (dep
->dep_rmap_hash
, route_map_process_dependency
, (void *)event
);
1386 XFREE (MTYPE_ROUTE_MAP_NAME
, name
);
1389 /* VTY related functions. */
1392 "route-map WORD (deny|permit) <1-65535>",
1393 "Create route-map or enter route-map command mode\n"
1395 "Route map denies set operations\n"
1396 "Route map permits set operations\n"
1397 "Sequence to insert to/delete from existing route-map entry\n")
1401 struct route_map
*map
;
1402 struct route_map_index
*index
;
1403 char *endptr
= NULL
;
1406 if (strncmp (argv
[1], "permit", strlen (argv
[1])) == 0)
1407 permit
= RMAP_PERMIT
;
1408 else if (strncmp (argv
[1], "deny", strlen (argv
[1])) == 0)
1412 vty_out (vty
, "the third field must be [permit|deny]%s", VTY_NEWLINE
);
1416 /* Preference check. */
1417 pref
= strtoul (argv
[2], &endptr
, 10);
1418 if (pref
== ULONG_MAX
|| *endptr
!= '\0')
1420 vty_out (vty
, "the fourth field must be positive integer%s",
1424 if (pref
== 0 || pref
> 65535)
1426 vty_out (vty
, "the fourth field must be <1-65535>%s", VTY_NEWLINE
);
1430 /* Get route map. */
1431 map
= route_map_get (argv
[0]);
1432 index
= route_map_index_get (map
, permit
, pref
);
1434 VTY_PUSH_CONTEXT_COMPAT (RMAP_NODE
, index
);
1438 DEFUN (no_route_map_all
,
1439 no_route_map_all_cmd
,
1440 "no route-map WORD",
1442 "Create route-map or enter route-map command mode\n"
1445 struct route_map
*map
;
1447 map
= route_map_lookup_by_name (argv
[0]);
1450 vty_out (vty
, "%% Could not find route-map %s%s",
1451 argv
[0], VTY_NEWLINE
);
1455 route_map_delete (map
);
1460 DEFUN (no_route_map
,
1462 "no route-map WORD (deny|permit) <1-65535>",
1464 "Create route-map or enter route-map command mode\n"
1466 "Route map denies set operations\n"
1467 "Route map permits set operations\n"
1468 "Sequence to insert to/delete from existing route-map entry\n")
1472 struct route_map
*map
;
1473 struct route_map_index
*index
;
1474 char *endptr
= NULL
;
1477 if (strncmp (argv
[1], "permit", strlen (argv
[1])) == 0)
1478 permit
= RMAP_PERMIT
;
1479 else if (strncmp (argv
[1], "deny", strlen (argv
[1])) == 0)
1483 vty_out (vty
, "the third field must be [permit|deny]%s", VTY_NEWLINE
);
1488 pref
= strtoul (argv
[2], &endptr
, 10);
1489 if (pref
== ULONG_MAX
|| *endptr
!= '\0')
1491 vty_out (vty
, "the fourth field must be positive integer%s",
1495 if (pref
== 0 || pref
> 65535)
1497 vty_out (vty
, "the fourth field must be <1-65535>%s", VTY_NEWLINE
);
1501 /* Existence check. */
1502 map
= route_map_lookup_by_name (argv
[0]);
1505 vty_out (vty
, "%% Could not find route-map %s%s",
1506 argv
[0], VTY_NEWLINE
);
1510 /* Lookup route map index. */
1511 index
= route_map_index_lookup (map
, permit
, pref
);
1514 vty_out (vty
, "%% Could not find route-map entry %s %s%s",
1515 argv
[0], argv
[2], VTY_NEWLINE
);
1519 /* Delete index from route map. */
1520 route_map_index_delete (index
, 1);
1522 /* If this route rule is the last one, delete route map itself. */
1523 if (route_map_empty (map
))
1524 route_map_delete (map
);
1529 DEFUN (rmap_onmatch_next
,
1530 rmap_onmatch_next_cmd
,
1532 "Exit policy on matches\n"
1535 struct route_map_index
*index
= VTY_GET_CONTEXT (route_map_index
);
1539 if (index
->type
== RMAP_DENY
)
1541 /* Under a deny clause, match means it's finished. No need to set next */
1542 vty_out (vty
, "on-match next not supported under route-map deny%s",
1546 index
->exitpolicy
= RMAP_NEXT
;
1551 DEFUN (no_rmap_onmatch_next
,
1552 no_rmap_onmatch_next_cmd
,
1555 "Exit policy on matches\n"
1558 struct route_map_index
*index
= VTY_GET_CONTEXT (route_map_index
);
1561 index
->exitpolicy
= RMAP_EXIT
;
1566 DEFUN (rmap_onmatch_goto
,
1567 rmap_onmatch_goto_cmd
,
1568 "on-match goto <1-65535>",
1569 "Exit policy on matches\n"
1570 "Goto Clause number\n"
1573 struct route_map_index
*index
= VTY_GET_CONTEXT (route_map_index
);
1578 if (index
->type
== RMAP_DENY
)
1580 /* Under a deny clause, match means it's finished. No need to go anywhere */
1581 vty_out (vty
, "on-match goto not supported under route-map deny%s",
1586 if (argc
== 1 && argv
[0])
1587 VTY_GET_INTEGER_RANGE("route-map index", d
, argv
[0], 1, 65535);
1589 d
= index
->pref
+ 1;
1591 if (d
<= index
->pref
)
1593 /* Can't allow you to do that, Dave */
1594 vty_out (vty
, "can't jump backwards in route-maps%s",
1600 index
->exitpolicy
= RMAP_GOTO
;
1601 index
->nextpref
= d
;
1607 DEFUN (no_rmap_onmatch_goto
,
1608 no_rmap_onmatch_goto_cmd
,
1611 "Exit policy on matches\n"
1612 "Goto Clause number\n")
1614 struct route_map_index
*index
= VTY_GET_CONTEXT (route_map_index
);
1617 index
->exitpolicy
= RMAP_EXIT
;
1622 /* Cisco/GNU Zebra compatible ALIASes for on-match next */
1623 ALIAS (rmap_onmatch_goto
,
1626 "Continue on a different entry within the route-map\n")
1628 ALIAS (no_rmap_onmatch_goto
,
1629 no_rmap_continue_cmd
,
1632 "Continue on a different entry within the route-map\n")
1634 /* GNU Zebra compatible */
1635 ALIAS (rmap_onmatch_goto
,
1636 rmap_continue_seq_cmd
,
1637 "continue <1-65535>",
1638 "Continue on a different entry within the route-map\n"
1639 "Route-map entry sequence number\n")
1641 ALIAS (no_rmap_onmatch_goto
,
1642 no_rmap_continue_seq
,
1643 "no continue <1-65535>",
1645 "Continue on a different entry within the route-map\n"
1646 "Route-map entry sequence number\n")
1648 DEFUN (rmap_show_name
,
1650 "show route-map [WORD]",
1652 "route-map information\n"
1655 const char *name
= NULL
;
1658 return vty_show_route_map (vty
, name
);
1661 ALIAS (rmap_onmatch_goto
,
1662 rmap_continue_index_cmd
,
1663 "continue <1-65535>",
1664 "Exit policy on matches\n"
1665 "Goto Clause number\n")
1670 "Jump to another Route-Map after match+set\n"
1671 "Target route-map name\n")
1673 struct route_map_index
*index
= VTY_GET_CONTEXT (route_map_index
);
1679 route_map_upd8_dependency (RMAP_EVENT_CALL_DELETED
,
1682 XFREE (MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
1684 index
->nextrm
= XSTRDUP (MTYPE_ROUTE_MAP_NAME
, argv
[0]);
1687 /* Execute event hook. */
1688 route_map_upd8_dependency (RMAP_EVENT_CALL_ADDED
,
1694 DEFUN (no_rmap_call
,
1698 "Jump to another Route-Map after match+set\n")
1700 struct route_map_index
*index
= VTY_GET_CONTEXT (route_map_index
);
1704 route_map_upd8_dependency (RMAP_EVENT_CALL_DELETED
,
1707 XFREE (MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
1708 index
->nextrm
= NULL
;
1714 DEFUN (rmap_description
,
1715 rmap_description_cmd
,
1716 "description .LINE",
1717 "Route-map comment\n"
1718 "Comment describing this route-map rule\n")
1720 struct route_map_index
*index
= VTY_GET_CONTEXT (route_map_index
);
1724 if (index
->description
)
1725 XFREE (MTYPE_TMP
, index
->description
);
1726 index
->description
= argv_concat (argv
, argc
, 0);
1731 DEFUN (no_rmap_description
,
1732 no_rmap_description_cmd
,
1735 "Route-map comment\n")
1737 struct route_map_index
*index
= VTY_GET_CONTEXT (route_map_index
);
1741 if (index
->description
)
1742 XFREE (MTYPE_TMP
, index
->description
);
1743 index
->description
= NULL
;
1748 /* Configuration write function. */
1750 route_map_config_write (struct vty
*vty
)
1752 struct route_map
*map
;
1753 struct route_map_index
*index
;
1754 struct route_map_rule
*rule
;
1758 for (map
= route_map_master
.head
; map
; map
= map
->next
)
1759 for (index
= map
->head
; index
; index
= index
->next
)
1762 vty_out (vty
, "!%s", VTY_NEWLINE
);
1766 vty_out (vty
, "route-map %s %s %d%s",
1768 route_map_type_str (index
->type
),
1769 index
->pref
, VTY_NEWLINE
);
1771 if (index
->description
)
1772 vty_out (vty
, " description %s%s", index
->description
, VTY_NEWLINE
);
1774 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1775 vty_out (vty
, " match %s %s%s", rule
->cmd
->str
,
1776 rule
->rule_str
? rule
->rule_str
: "",
1779 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
1780 vty_out (vty
, " set %s %s%s", rule
->cmd
->str
,
1781 rule
->rule_str
? rule
->rule_str
: "",
1784 vty_out (vty
, " call %s%s", index
->nextrm
, VTY_NEWLINE
);
1785 if (index
->exitpolicy
== RMAP_GOTO
)
1786 vty_out (vty
, " on-match goto %d%s", index
->nextpref
, VTY_NEWLINE
);
1787 if (index
->exitpolicy
== RMAP_NEXT
)
1788 vty_out (vty
," on-match next%s", VTY_NEWLINE
);
1795 /* Route map node structure. */
1796 static struct cmd_node rmap_node
=
1799 "%s(config-route-map)# ",
1803 /* Common route map rules */
1806 route_map_rule_tag_compile (const char *arg
)
1808 unsigned long int tmp
;
1813 tmp
= strtoul(arg
, &endptr
, 0);
1814 if (arg
[0] == '\0' || *endptr
!= '\0' || errno
|| tmp
> ROUTE_TAG_MAX
)
1817 tag
= XMALLOC(MTYPE_ROUTE_MAP_COMPILED
, sizeof(*tag
));
1824 route_map_rule_tag_free (void *rule
)
1826 XFREE (MTYPE_ROUTE_MAP_COMPILED
, rule
);
1830 route_map_finish (void)
1834 vector_free (route_match_vec
);
1835 route_match_vec
= NULL
;
1836 vector_free (route_set_vec
);
1837 route_set_vec
= NULL
;
1839 /* cleanup route_map */
1840 while (route_map_master
.head
)
1842 struct route_map
*map
= route_map_master
.head
;
1843 map
->to_be_processed
= 0;
1844 route_map_delete (map
);
1847 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++)
1849 hash_free(route_map_dep_hash
[i
]);
1850 route_map_dep_hash
[i
] = NULL
;
1853 hash_free (route_map_master_hash
);
1854 route_map_master_hash
= NULL
;
1857 /* Initialization of route map vector. */
1859 route_map_init (void)
1863 /* Make vector for match and set. */
1864 route_match_vec
= vector_init (1);
1865 route_set_vec
= vector_init (1);
1866 route_map_master_hash
= hash_create(route_map_hash_key_make
, route_map_hash_cmp
);
1868 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++)
1869 route_map_dep_hash
[i
] = hash_create(route_map_dep_hash_make_key
,
1870 route_map_dep_hash_cmp
);
1872 /* Install route map top node. */
1873 install_node (&rmap_node
, route_map_config_write
);
1875 /* Install route map commands. */
1876 install_default (RMAP_NODE
);
1877 install_element (CONFIG_NODE
, &route_map_cmd
);
1878 install_element (CONFIG_NODE
, &no_route_map_cmd
);
1879 install_element (CONFIG_NODE
, &no_route_map_all_cmd
);
1881 /* Install the on-match stuff */
1882 install_element (RMAP_NODE
, &route_map_cmd
);
1883 install_element (RMAP_NODE
, &rmap_onmatch_next_cmd
);
1884 install_element (RMAP_NODE
, &no_rmap_onmatch_next_cmd
);
1885 install_element (RMAP_NODE
, &rmap_onmatch_goto_cmd
);
1886 install_element (RMAP_NODE
, &no_rmap_onmatch_goto_cmd
);
1888 /* Install the continue stuff (ALIAS of on-match). */
1889 install_element (RMAP_NODE
, &rmap_continue_cmd
);
1890 install_element (RMAP_NODE
, &no_rmap_continue_cmd
);
1891 install_element (RMAP_NODE
, &rmap_continue_index_cmd
);
1893 /* Install the call stuff. */
1894 install_element (RMAP_NODE
, &rmap_call_cmd
);
1895 install_element (RMAP_NODE
, &no_rmap_call_cmd
);
1897 /* Install description commands. */
1898 install_element (RMAP_NODE
, &rmap_description_cmd
);
1899 install_element (RMAP_NODE
, &no_rmap_description_cmd
);
1901 /* Install show command */
1902 install_element (ENABLE_NODE
, &rmap_show_name_cmd
);