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 /* Vector for route match rules. */
42 static vector route_match_vec
;
44 /* Vector for route set rules. */
45 static vector route_set_vec
;
47 /* Route map rule. This rule has both `match' rule and `set' rule. */
51 struct route_map_rule_cmd
*cmd
;
53 /* For pretty printing. */
56 /* Pre-compiled match rule. */
60 struct route_map_rule
*next
;
61 struct route_map_rule
*prev
;
64 /* Making route map list. */
67 struct route_map
*head
;
68 struct route_map
*tail
;
70 void (*add_hook
) (const char *);
71 void (*delete_hook
) (const char *);
72 void (*event_hook
) (route_map_event_t
, const char *);
75 /* Master list of route map. */
76 static struct route_map_list route_map_master
= { NULL
, NULL
, NULL
, NULL
, NULL
};
77 struct hash
*route_map_master_hash
= NULL
;
80 route_map_hash_key_make (void *p
)
82 const struct route_map
*map
= p
;
83 return string_hash_make (map
->name
);
87 route_map_hash_cmp(const void *p1
, const void *p2
)
89 const struct route_map
*map1
= p1
;
90 const struct route_map
*map2
= p2
;
92 if (map1
->deleted
== map2
->deleted
)
94 if (map1
->name
&& map2
->name
)
96 if (!strcmp (map1
->name
, map2
->name
))
101 else if (!map1
->name
&& !map2
->name
)
110 enum route_map_upd8_type
116 /* all possible route-map dependency types */
117 enum route_map_dep_type
119 ROUTE_MAP_DEP_RMAP
= 1,
121 ROUTE_MAP_DEP_ECLIST
,
123 ROUTE_MAP_DEP_ASPATH
,
124 ROUTE_MAP_DEP_FILTER
,
131 struct hash
*dep_rmap_hash
;
132 struct hash
*this_hash
; /* ptr to the hash structure this is part of */
135 /* Hashes maintaining dependency between various sublists used by route maps */
136 struct hash
*route_map_dep_hash
[ROUTE_MAP_DEP_MAX
];
138 static unsigned int route_map_dep_hash_make_key (void *p
);
139 static int route_map_dep_hash_cmp (const void *p1
, const void *p2
);
140 static void route_map_init_dep_hashes (void);
141 static void route_map_clear_all_references (char *rmap_name
);
142 static void route_map_rule_delete (struct route_map_rule_list
*,
143 struct route_map_rule
*);
144 static int rmap_debug
= 0;
147 route_map_index_delete (struct route_map_index
*, int);
149 /* New route map allocation. Please note route map's name must be
151 static struct route_map
*
152 route_map_new (const char *name
)
154 struct route_map
*new;
156 new = XCALLOC (MTYPE_ROUTE_MAP
, sizeof (struct route_map
));
157 new->name
= XSTRDUP (MTYPE_ROUTE_MAP_NAME
, name
);
161 /* Add new name to route_map. */
162 static struct route_map
*
163 route_map_add (const char *name
)
165 struct route_map
*map
;
166 struct route_map_list
*list
;
168 map
= route_map_new (name
);
169 list
= &route_map_master
;
171 /* Add map to the hash */
172 hash_get(route_map_master_hash
, map
, hash_alloc_intern
);
174 /* Add new entry to the head of the list to match how it is added in the
175 * hash table. This is to ensure that if the same route-map has been
176 * created more than once and then marked for deletion (which can happen
177 * if prior deletions haven't completed as BGP hasn't yet done the
178 * route-map processing), the order of the entities is the same in both
179 * the list and the hash table. Otherwise, since there is nothing to
180 * distinguish between the two entries, the wrong entry could get freed.
181 * TODO: This needs to be re-examined to handle it better - e.g., revive
182 * a deleted entry if the route-map is created again.
185 map
->next
= list
->head
;
187 list
->head
->prev
= map
;
193 if (route_map_master
.add_hook
)
195 (*route_map_master
.add_hook
) (name
);
196 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_ADDED
);
201 /* this is supposed to be called post processing by
202 * the delete hook function. Don't invoke delete_hook
203 * again in this routine.
206 route_map_free_map (struct route_map
*map
)
208 struct route_map_list
*list
;
209 struct route_map_index
*index
;
211 while ((index
= map
->head
) != NULL
)
212 route_map_index_delete (index
, 0);
214 list
= &route_map_master
;
219 map
->next
->prev
= map
->prev
;
221 list
->tail
= map
->prev
;
224 map
->prev
->next
= map
->next
;
226 list
->head
= map
->next
;
228 hash_release(route_map_master_hash
, map
);
229 XFREE (MTYPE_ROUTE_MAP_NAME
, map
->name
);
230 XFREE (MTYPE_ROUTE_MAP
, map
);
234 /* Route map delete from list. */
236 route_map_delete (struct route_map
*map
)
238 struct route_map_index
*index
;
241 while ((index
= map
->head
) != NULL
)
242 route_map_index_delete (index
, 0);
247 /* Clear all dependencies */
248 route_map_clear_all_references(name
);
250 /* Execute deletion hook. */
251 if (route_map_master
.delete_hook
)
253 (*route_map_master
.delete_hook
) (name
);
254 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_DELETED
);
257 if (!map
->to_be_processed
)
259 route_map_free_map (map
);
263 /* Lookup route map by route map name string. */
265 route_map_lookup_by_name (const char *name
)
267 struct route_map
*map
;
268 struct route_map tmp_map
;
273 // map.deleted is 0 via memset
274 memset(&tmp_map
, 0, sizeof(struct route_map
));
275 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
276 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
277 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
282 route_map_mark_updated (const char *name
, int del_later
)
284 struct route_map
*map
;
286 struct route_map tmp_map
;
291 map
= route_map_lookup_by_name(name
);
293 /* If we did not find the routemap with deleted=0 try again
298 memset(&tmp_map
, 0, sizeof(struct route_map
));
299 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
301 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
302 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
307 map
->to_be_processed
= 1;
315 route_map_clear_updated (struct route_map
*map
)
321 map
->to_be_processed
= 0;
323 route_map_free_map(map
);
329 /* Lookup route map. If there isn't route map create one and return
331 static struct route_map
*
332 route_map_get (const char *name
)
334 struct route_map
*map
;
336 map
= route_map_lookup_by_name (name
);
338 map
= route_map_add (name
);
344 route_map_walk_update_list (int (*route_map_update_fn
) (char *name
))
346 struct route_map
*node
;
347 struct route_map
*nnode
= NULL
;
349 for (node
= route_map_master
.head
; node
; node
= nnode
)
351 if (node
->to_be_processed
)
353 /* DD: Should we add any thread yield code here */
354 route_map_update_fn(node
->name
);
356 route_map_clear_updated(node
);
363 /* Return route map's type string. */
365 route_map_type_str (enum route_map_type type
)
382 route_map_empty (struct route_map
*map
)
384 if (map
->head
== NULL
&& map
->tail
== NULL
)
392 vty_show_route_map_entry (struct vty
*vty
, struct route_map
*map
)
394 struct route_map_index
*index
;
395 struct route_map_rule
*rule
;
397 /* Print the name of the protocol */
399 vty_out (vty
, "%s", zlog_proto_names
[zlog_default
->protocol
]);
400 if (zlog_default
->instance
)
401 vty_out (vty
, " %d", zlog_default
->instance
);
402 vty_out (vty
, ":%s", VTY_NEWLINE
);
404 for (index
= map
->head
; index
; index
= index
->next
)
406 vty_out (vty
, "route-map %s, %s, sequence %d%s",
407 map
->name
, route_map_type_str (index
->type
),
408 index
->pref
, VTY_NEWLINE
);
411 if (index
->description
)
412 vty_out (vty
, " Description:%s %s%s", VTY_NEWLINE
,
413 index
->description
, VTY_NEWLINE
);
416 vty_out (vty
, " Match clauses:%s", VTY_NEWLINE
);
417 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
418 vty_out (vty
, " %s %s%s",
419 rule
->cmd
->str
, rule
->rule_str
, VTY_NEWLINE
);
421 vty_out (vty
, " Set clauses:%s", VTY_NEWLINE
);
422 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
423 vty_out (vty
, " %s %s%s",
424 rule
->cmd
->str
, rule
->rule_str
, VTY_NEWLINE
);
427 vty_out (vty
, " Call clause:%s", VTY_NEWLINE
);
429 vty_out (vty
, " Call %s%s", index
->nextrm
, VTY_NEWLINE
);
432 vty_out (vty
, " Action:%s", VTY_NEWLINE
);
433 if (index
->exitpolicy
== RMAP_GOTO
)
434 vty_out (vty
, " Goto %d%s", index
->nextpref
, VTY_NEWLINE
);
435 else if (index
->exitpolicy
== RMAP_NEXT
)
436 vty_out (vty
, " Continue to next entry%s", VTY_NEWLINE
);
437 else if (index
->exitpolicy
== RMAP_EXIT
)
438 vty_out (vty
, " Exit routemap%s", VTY_NEWLINE
);
443 vty_show_route_map (struct vty
*vty
, const char *name
)
445 struct route_map
*map
;
449 map
= route_map_lookup_by_name (name
);
453 vty_show_route_map_entry (vty
, map
);
459 vty_out (vty
, "%s", zlog_proto_names
[zlog_default
->protocol
]);
460 if (zlog_default
->instance
)
461 vty_out (vty
, " %d", zlog_default
->instance
);
462 vty_out (vty
, ": 'route-map %s' not found%s", name
, VTY_NEWLINE
);
468 for (map
= route_map_master
.head
; map
; map
= map
->next
)
470 vty_show_route_map_entry (vty
, map
);
476 /* New route map allocation. Please note route map's name must be
478 static struct route_map_index
*
479 route_map_index_new (void)
481 struct route_map_index
*new;
483 new = XCALLOC (MTYPE_ROUTE_MAP_INDEX
, sizeof (struct route_map_index
));
484 new->exitpolicy
= RMAP_EXIT
; /* Default to Cisco-style */
488 /* Free route map index. */
490 route_map_index_delete (struct route_map_index
*index
, int notify
)
492 struct route_map_rule
*rule
;
494 /* Free route match. */
495 while ((rule
= index
->match_list
.head
) != NULL
)
496 route_map_rule_delete (&index
->match_list
, rule
);
498 /* Free route set. */
499 while ((rule
= index
->set_list
.head
) != NULL
)
500 route_map_rule_delete (&index
->set_list
, rule
);
502 /* Remove index from route map list. */
504 index
->next
->prev
= index
->prev
;
506 index
->map
->tail
= index
->prev
;
509 index
->prev
->next
= index
->next
;
511 index
->map
->head
= index
->next
;
513 /* Free 'char *nextrm' if not NULL */
515 XFREE (MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
517 /* Execute event hook. */
518 if (route_map_master
.event_hook
&& notify
)
520 (*route_map_master
.event_hook
) (RMAP_EVENT_INDEX_DELETED
,
522 route_map_notify_dependencies(index
->map
->name
, RMAP_EVENT_CALL_ADDED
);
524 XFREE (MTYPE_ROUTE_MAP_INDEX
, index
);
527 /* Lookup index from route map. */
528 static struct route_map_index
*
529 route_map_index_lookup (struct route_map
*map
, enum route_map_type type
,
532 struct route_map_index
*index
;
534 for (index
= map
->head
; index
; index
= index
->next
)
535 if ((index
->type
== type
|| type
== RMAP_ANY
)
536 && index
->pref
== pref
)
541 /* Add new index to route map. */
542 static struct route_map_index
*
543 route_map_index_add (struct route_map
*map
, enum route_map_type type
,
546 struct route_map_index
*index
;
547 struct route_map_index
*point
;
549 /* Allocate new route map inex. */
550 index
= route_map_index_new ();
555 /* Compare preference. */
556 for (point
= map
->head
; point
; point
= point
->next
)
557 if (point
->pref
>= pref
)
560 if (map
->head
== NULL
)
562 map
->head
= map
->tail
= index
;
564 else if (point
== NULL
)
566 index
->prev
= map
->tail
;
567 map
->tail
->next
= index
;
570 else if (point
== map
->head
)
572 index
->next
= map
->head
;
573 map
->head
->prev
= index
;
579 index
->prev
= point
->prev
;
581 point
->prev
->next
= index
;
585 /* Execute event hook. */
586 if (route_map_master
.event_hook
)
588 (*route_map_master
.event_hook
) (RMAP_EVENT_INDEX_ADDED
,
590 route_map_notify_dependencies (map
->name
, RMAP_EVENT_CALL_ADDED
);
595 /* Get route map index. */
596 static struct route_map_index
*
597 route_map_index_get (struct route_map
*map
, enum route_map_type type
,
600 struct route_map_index
*index
;
602 index
= route_map_index_lookup (map
, RMAP_ANY
, pref
);
603 if (index
&& index
->type
!= type
)
605 /* Delete index from route map. */
606 route_map_index_delete (index
, 1);
610 index
= route_map_index_add (map
, type
, pref
);
614 /* New route map rule */
615 static struct route_map_rule
*
616 route_map_rule_new (void)
618 struct route_map_rule
*new;
620 new = XCALLOC (MTYPE_ROUTE_MAP_RULE
, sizeof (struct route_map_rule
));
624 /* Install rule command to the match list. */
626 route_map_install_match (struct route_map_rule_cmd
*cmd
)
628 vector_set (route_match_vec
, cmd
);
631 /* Install rule command to the set list. */
633 route_map_install_set (struct route_map_rule_cmd
*cmd
)
635 vector_set (route_set_vec
, cmd
);
638 /* Lookup rule command from match list. */
639 static struct route_map_rule_cmd
*
640 route_map_lookup_match (const char *name
)
643 struct route_map_rule_cmd
*rule
;
645 for (i
= 0; i
< vector_active (route_match_vec
); i
++)
646 if ((rule
= vector_slot (route_match_vec
, i
)) != NULL
)
647 if (strcmp (rule
->str
, name
) == 0)
652 /* Lookup rule command from set list. */
653 static struct route_map_rule_cmd
*
654 route_map_lookup_set (const char *name
)
657 struct route_map_rule_cmd
*rule
;
659 for (i
= 0; i
< vector_active (route_set_vec
); i
++)
660 if ((rule
= vector_slot (route_set_vec
, i
)) != NULL
)
661 if (strcmp (rule
->str
, name
) == 0)
666 /* Add match and set rule to rule list. */
668 route_map_rule_add (struct route_map_rule_list
*list
,
669 struct route_map_rule
*rule
)
672 rule
->prev
= list
->tail
;
674 list
->tail
->next
= rule
;
680 /* Delete rule from rule list. */
682 route_map_rule_delete (struct route_map_rule_list
*list
,
683 struct route_map_rule
*rule
)
685 if (rule
->cmd
->func_free
)
686 (*rule
->cmd
->func_free
) (rule
->value
);
689 XFREE (MTYPE_ROUTE_MAP_RULE_STR
, rule
->rule_str
);
692 rule
->next
->prev
= rule
->prev
;
694 list
->tail
= rule
->prev
;
696 rule
->prev
->next
= rule
->next
;
698 list
->head
= rule
->next
;
700 XFREE (MTYPE_ROUTE_MAP_RULE
, rule
);
703 /* strcmp wrapper function which don't crush even argument is NULL. */
705 rulecmp (const char *dst
, const char *src
)
719 return strcmp (dst
, src
);
724 /* Use this to return the already specified argument for this match. This is
725 * useful to get the specified argument with a route map match rule when the
726 * rule is being deleted and the argument is not provided.
729 route_map_get_match_arg(struct route_map_index
*index
, const char *match_name
)
731 struct route_map_rule
*rule
;
732 struct route_map_rule_cmd
*cmd
;
734 /* First lookup rule for add match statement. */
735 cmd
= route_map_lookup_match (match_name
);
739 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
740 if (rule
->cmd
== cmd
&& rule
->rule_str
!= NULL
)
741 return (rule
->rule_str
);
746 /* Add match statement to route map. */
748 route_map_add_match (struct route_map_index
*index
, const char *match_name
,
749 const char *match_arg
)
751 struct route_map_rule
*rule
;
752 struct route_map_rule
*next
;
753 struct route_map_rule_cmd
*cmd
;
757 /* First lookup rule for add match statement. */
758 cmd
= route_map_lookup_match (match_name
);
760 return RMAP_RULE_MISSING
;
762 /* Next call compile function for this match statement. */
763 if (cmd
->func_compile
)
765 compile
= (*cmd
->func_compile
)(match_arg
);
767 return RMAP_COMPILE_ERROR
;
772 /* If argument is completely same ignore it. */
773 for (rule
= index
->match_list
.head
; rule
; rule
= next
)
776 if (rule
->cmd
== cmd
)
778 route_map_rule_delete (&index
->match_list
, rule
);
783 /* Add new route map match rule. */
784 rule
= route_map_rule_new ();
786 rule
->value
= compile
;
788 rule
->rule_str
= XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR
, match_arg
);
790 rule
->rule_str
= NULL
;
792 /* Add new route match rule to linked list. */
793 route_map_rule_add (&index
->match_list
, rule
);
795 /* Execute event hook. */
796 if (route_map_master
.event_hook
)
798 (*route_map_master
.event_hook
) (replaced
?
799 RMAP_EVENT_MATCH_REPLACED
:
800 RMAP_EVENT_MATCH_ADDED
,
802 route_map_notify_dependencies(index
->map
->name
, RMAP_EVENT_CALL_ADDED
);
808 /* Delete specified route match rule. */
810 route_map_delete_match (struct route_map_index
*index
, const char *match_name
,
811 const char *match_arg
)
813 struct route_map_rule
*rule
;
814 struct route_map_rule_cmd
*cmd
;
816 cmd
= route_map_lookup_match (match_name
);
820 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
821 if (rule
->cmd
== cmd
&&
822 (rulecmp (rule
->rule_str
, match_arg
) == 0 || match_arg
== NULL
))
824 route_map_rule_delete (&index
->match_list
, rule
);
825 /* Execute event hook. */
826 if (route_map_master
.event_hook
)
828 (*route_map_master
.event_hook
) (RMAP_EVENT_MATCH_DELETED
,
830 route_map_notify_dependencies(index
->map
->name
, RMAP_EVENT_CALL_ADDED
);
834 /* Can't find matched rule. */
838 /* Add route-map set statement to the route map. */
840 route_map_add_set (struct route_map_index
*index
, const char *set_name
,
843 struct route_map_rule
*rule
;
844 struct route_map_rule
*next
;
845 struct route_map_rule_cmd
*cmd
;
849 cmd
= route_map_lookup_set (set_name
);
851 return RMAP_RULE_MISSING
;
853 /* Next call compile function for this match statement. */
854 if (cmd
->func_compile
)
856 compile
= (*cmd
->func_compile
)(set_arg
);
858 return RMAP_COMPILE_ERROR
;
863 /* Add by WJL. if old set command of same kind exist, delete it first
864 to ensure only one set command of same kind exist under a
866 for (rule
= index
->set_list
.head
; rule
; rule
= next
)
869 if (rule
->cmd
== cmd
)
871 route_map_rule_delete (&index
->set_list
, rule
);
876 /* Add new route map match rule. */
877 rule
= route_map_rule_new ();
879 rule
->value
= compile
;
881 rule
->rule_str
= XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR
, set_arg
);
883 rule
->rule_str
= NULL
;
885 /* Add new route match rule to linked list. */
886 route_map_rule_add (&index
->set_list
, rule
);
888 /* Execute event hook. */
889 if (route_map_master
.event_hook
)
891 (*route_map_master
.event_hook
) (replaced
?
892 RMAP_EVENT_SET_REPLACED
:
893 RMAP_EVENT_SET_ADDED
,
895 route_map_notify_dependencies(index
->map
->name
, RMAP_EVENT_CALL_ADDED
);
900 /* Delete route map set rule. */
902 route_map_delete_set (struct route_map_index
*index
, const char *set_name
,
905 struct route_map_rule
*rule
;
906 struct route_map_rule_cmd
*cmd
;
908 cmd
= route_map_lookup_set (set_name
);
912 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
913 if ((rule
->cmd
== cmd
) &&
914 (rulecmp (rule
->rule_str
, set_arg
) == 0 || set_arg
== NULL
))
916 route_map_rule_delete (&index
->set_list
, rule
);
917 /* Execute event hook. */
918 if (route_map_master
.event_hook
)
920 (*route_map_master
.event_hook
) (RMAP_EVENT_SET_DELETED
,
922 route_map_notify_dependencies(index
->map
->name
, RMAP_EVENT_CALL_ADDED
);
926 /* Can't find matched rule. */
930 /* Apply route map's each index to the object.
932 The matrix for a route-map looks like this:
933 (note, this includes the description for the "NEXT"
940 ------------------+---------------
946 -Apply Set statements, accept route
947 -If Call statement is present jump to the specified route-map, if it
948 denies the route we finish.
949 -If NEXT is specified, goto NEXT statement
950 -If GOTO is specified, goto the first clause where pref > nextpref
951 -If nothing is specified, do as Cisco and finish
953 -Route is denied by route-map.
957 If we get no matches after we've processed all updates, then the route
960 Some notes on the new "CALL", "NEXT" and "GOTO"
961 call WORD - If this clause is matched, then the set statements
962 are executed and then we jump to route-map 'WORD'. If
963 this route-map denies the route, we finish, in other case we
964 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
965 on-match next - If this clause is matched, then the set statements
966 are executed and then we drop through to the next clause
967 on-match goto n - If this clause is matched, then the set statments
968 are executed and then we goto the nth clause, or the
969 first clause greater than this. In order to ensure
970 route-maps *always* exit, you cannot jump backwards.
973 We need to make sure our route-map processing matches the above
976 static route_map_result_t
977 route_map_apply_match (struct route_map_rule_list
*match_list
,
978 struct prefix
*prefix
, route_map_object_t type
,
981 route_map_result_t ret
= RMAP_NOMATCH
;
982 struct route_map_rule
*match
;
985 /* Check all match rule and if there is no match rule, go to the
987 if (!match_list
->head
)
991 for (match
= match_list
->head
; match
; match
= match
->next
)
993 /* Try each match statement in turn, If any do not return
994 RMAP_MATCH, return, otherwise continue on to next match
995 statement. All match statements must match for end-result
997 ret
= (*match
->cmd
->func_apply
) (match
->value
, prefix
,
999 if (ret
!= RMAP_MATCH
)
1006 /* Apply route map to the object. */
1008 route_map_apply (struct route_map
*map
, struct prefix
*prefix
,
1009 route_map_object_t type
, void *object
)
1011 static int recursion
= 0;
1013 struct route_map_index
*index
;
1014 struct route_map_rule
*set
;
1016 if (recursion
> RMAP_RECURSION_LIMIT
)
1018 zlog (NULL
, LOG_WARNING
,
1019 "route-map recursion limit (%d) reached, discarding route",
1020 RMAP_RECURSION_LIMIT
);
1022 return RMAP_DENYMATCH
;
1026 return RMAP_DENYMATCH
;
1028 for (index
= map
->head
; index
; index
= index
->next
)
1030 /* Apply this index. */
1031 ret
= route_map_apply_match (&index
->match_list
, prefix
, type
, object
);
1033 /* Now we apply the matrix from above */
1034 if (ret
== RMAP_NOMATCH
)
1035 /* 'cont' from matrix - continue to next route-map sequence */
1037 else if (ret
== RMAP_MATCH
)
1039 if (index
->type
== RMAP_PERMIT
)
1042 /* permit+match must execute sets */
1043 for (set
= index
->set_list
.head
; set
; set
= set
->next
)
1044 ret
= (*set
->cmd
->func_apply
) (set
->value
, prefix
,
1047 /* Call another route-map if available */
1050 struct route_map
*nextrm
=
1051 route_map_lookup_by_name (index
->nextrm
);
1053 if (nextrm
) /* Target route-map found, jump to it */
1056 ret
= route_map_apply (nextrm
, prefix
, type
, object
);
1060 /* If nextrm returned 'deny', finish. */
1061 if (ret
== RMAP_DENYMATCH
)
1065 switch (index
->exitpolicy
)
1073 /* Find the next clause to jump to */
1074 struct route_map_index
*next
= index
->next
;
1075 int nextpref
= index
->nextpref
;
1077 while (next
&& next
->pref
< nextpref
)
1084 /* No clauses match! */
1090 else if (index
->type
== RMAP_DENY
)
1093 return RMAP_DENYMATCH
;
1097 /* Finally route-map does not match at all. */
1098 return RMAP_DENYMATCH
;
1102 route_map_add_hook (void (*func
) (const char *))
1104 route_map_master
.add_hook
= func
;
1108 route_map_delete_hook (void (*func
) (const char *))
1110 route_map_master
.delete_hook
= func
;
1114 route_map_event_hook (void (*func
) (route_map_event_t
, const char *))
1116 route_map_master
.event_hook
= func
;
1120 route_map_init (void)
1122 /* Make vector for match and set. */
1123 route_match_vec
= vector_init (1);
1124 route_set_vec
= vector_init (1);
1125 route_map_master_hash
= hash_create(route_map_hash_key_make
, route_map_hash_cmp
);
1129 route_map_finish (void)
1131 vector_free (route_match_vec
);
1132 route_match_vec
= NULL
;
1133 vector_free (route_set_vec
);
1134 route_set_vec
= NULL
;
1137 /* Routines for route map dependency lists and dependency processing */
1139 route_map_rmap_hash_cmp (const void *p1
, const void *p2
)
1141 return (strcmp((const char *)p1
, (const char *)p2
) == 0);
1145 route_map_dep_hash_cmp (const void *p1
, const void *p2
)
1148 return (strcmp (((const struct route_map_dep
*)p1
)->dep_name
, (const char *)p2
) == 0);
1152 route_map_clear_reference(struct hash_backet
*backet
, void *arg
)
1154 struct route_map_dep
*dep
= (struct route_map_dep
*)backet
->data
;
1159 rmap_name
= (char *)hash_release(dep
->dep_rmap_hash
, (void *)arg
);
1162 XFREE(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
1164 if (!dep
->dep_rmap_hash
->count
)
1166 dep
= hash_release(dep
->this_hash
, (void *)dep
->dep_name
);
1167 hash_free(dep
->dep_rmap_hash
);
1168 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
1169 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
1175 route_map_clear_all_references (char *rmap_name
)
1179 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++)
1181 hash_iterate(route_map_dep_hash
[i
], route_map_clear_reference
,
1187 route_map_dep_hash_alloc(void *p
)
1189 char *dep_name
= (char *)p
;
1190 struct route_map_dep
*dep_entry
;
1192 dep_entry
= XCALLOC(MTYPE_ROUTE_MAP_DEP
, sizeof(struct route_map_dep
));
1193 dep_entry
->dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1194 dep_entry
->dep_rmap_hash
= hash_create(route_map_dep_hash_make_key
,
1195 route_map_rmap_hash_cmp
);
1196 dep_entry
->this_hash
= NULL
;
1198 return((void *)dep_entry
);
1202 route_map_name_hash_alloc(void *p
)
1204 return((void *)XSTRDUP(MTYPE_ROUTE_MAP_NAME
, (const char *)p
));
1208 route_map_dep_hash_make_key (void *p
)
1210 return (string_hash_make((char *)p
));
1214 route_map_print_dependency (struct hash_backet
*backet
, void *data
)
1216 char *rmap_name
= (char *)backet
->data
;
1217 char *dep_name
= (char *)data
;
1220 zlog_debug("%s: Dependency for %s: %s", __FUNCTION__
, dep_name
, rmap_name
);
1224 route_map_dep_update (struct hash
*dephash
, const char *dep_name
,
1225 const char *rmap_name
,
1226 route_map_event_t type
)
1228 struct route_map_dep
*dep
= NULL
;
1230 char *dname
, *rname
;
1233 dname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1234 rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
1238 case RMAP_EVENT_PLIST_ADDED
:
1239 case RMAP_EVENT_CLIST_ADDED
:
1240 case RMAP_EVENT_ECLIST_ADDED
:
1241 case RMAP_EVENT_ASLIST_ADDED
:
1242 case RMAP_EVENT_CALL_ADDED
:
1243 case RMAP_EVENT_FILTER_ADDED
:
1245 zlog_debug("%s: Adding dependency for %s in %s", __FUNCTION__
,
1246 dep_name
, rmap_name
);
1247 dep
= (struct route_map_dep
*) hash_get (dephash
, dname
,
1248 route_map_dep_hash_alloc
);
1254 if (!dep
->this_hash
)
1255 dep
->this_hash
= dephash
;
1257 hash_get(dep
->dep_rmap_hash
, rname
, route_map_name_hash_alloc
);
1259 case RMAP_EVENT_PLIST_DELETED
:
1260 case RMAP_EVENT_CLIST_DELETED
:
1261 case RMAP_EVENT_ECLIST_DELETED
:
1262 case RMAP_EVENT_ASLIST_DELETED
:
1263 case RMAP_EVENT_CALL_DELETED
:
1264 case RMAP_EVENT_FILTER_DELETED
:
1266 zlog_debug("%s: Deleting dependency for %s in %s", __FUNCTION__
,
1267 dep_name
, rmap_name
);
1268 dep
= (struct route_map_dep
*) hash_get (dephash
, dname
, NULL
);
1273 ret_map_name
= (char *)hash_release(dep
->dep_rmap_hash
, rname
);
1275 XFREE(MTYPE_ROUTE_MAP_NAME
, ret_map_name
);
1277 if (!dep
->dep_rmap_hash
->count
)
1279 dep
= hash_release(dephash
, dname
);
1280 hash_free(dep
->dep_rmap_hash
);
1281 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
1282 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
1293 hash_iterate (dep
->dep_rmap_hash
, route_map_print_dependency
, dname
);
1297 XFREE(MTYPE_ROUTE_MAP_NAME
, rname
);
1298 XFREE(MTYPE_ROUTE_MAP_NAME
, dname
);
1302 static struct hash
*
1303 route_map_get_dep_hash (route_map_event_t event
)
1305 struct hash
*upd8_hash
= NULL
;
1309 case RMAP_EVENT_PLIST_ADDED
:
1310 case RMAP_EVENT_PLIST_DELETED
:
1311 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_PLIST
];
1313 case RMAP_EVENT_CLIST_ADDED
:
1314 case RMAP_EVENT_CLIST_DELETED
:
1315 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_CLIST
];
1317 case RMAP_EVENT_ECLIST_ADDED
:
1318 case RMAP_EVENT_ECLIST_DELETED
:
1319 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ECLIST
];
1321 case RMAP_EVENT_ASLIST_ADDED
:
1322 case RMAP_EVENT_ASLIST_DELETED
:
1323 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ASPATH
];
1325 case RMAP_EVENT_CALL_ADDED
:
1326 case RMAP_EVENT_CALL_DELETED
:
1327 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_RMAP
];
1329 case RMAP_EVENT_FILTER_ADDED
:
1330 case RMAP_EVENT_FILTER_DELETED
:
1331 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_FILTER
];
1341 route_map_process_dependency (struct hash_backet
*backet
, void *data
)
1344 route_map_event_t type
= (route_map_event_t
)data
;
1346 rmap_name
= (char *)backet
->data
;
1351 zlog_debug("%s: Notifying %s of dependency", __FUNCTION__
,
1353 if (route_map_master
.event_hook
)
1354 (*route_map_master
.event_hook
) (type
, rmap_name
);
1359 route_map_upd8_dependency (route_map_event_t type
, const char *arg
,
1360 const char *rmap_name
)
1362 struct hash
*upd8_hash
= NULL
;
1364 if ((upd8_hash
= route_map_get_dep_hash(type
)))
1365 route_map_dep_update (upd8_hash
, arg
, rmap_name
, type
);
1369 route_map_notify_dependencies (const char *affected_name
, route_map_event_t event
)
1371 struct route_map_dep
*dep
;
1372 struct hash
*upd8_hash
;
1378 name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, affected_name
);
1380 if ((upd8_hash
= route_map_get_dep_hash(event
)) == NULL
)
1382 XFREE (MTYPE_ROUTE_MAP_NAME
, name
);
1386 dep
= (struct route_map_dep
*)hash_get (upd8_hash
, name
,
1390 if (!dep
->this_hash
)
1391 dep
->this_hash
= upd8_hash
;
1393 hash_iterate (dep
->dep_rmap_hash
, route_map_process_dependency
, (void *)event
);
1396 XFREE (MTYPE_ROUTE_MAP_NAME
, name
);
1399 /* VTY related functions. */
1402 "route-map WORD (deny|permit) <1-65535>",
1403 "Create route-map or enter route-map command mode\n"
1405 "Route map denies set operations\n"
1406 "Route map permits set operations\n"
1407 "Sequence to insert to/delete from existing route-map entry\n")
1411 struct route_map
*map
;
1412 struct route_map_index
*index
;
1413 char *endptr
= NULL
;
1416 if (strncmp (argv
[1], "permit", strlen (argv
[1])) == 0)
1417 permit
= RMAP_PERMIT
;
1418 else if (strncmp (argv
[1], "deny", strlen (argv
[1])) == 0)
1422 vty_out (vty
, "the third field must be [permit|deny]%s", VTY_NEWLINE
);
1426 /* Preference check. */
1427 pref
= strtoul (argv
[2], &endptr
, 10);
1428 if (pref
== ULONG_MAX
|| *endptr
!= '\0')
1430 vty_out (vty
, "the fourth field must be positive integer%s",
1434 if (pref
== 0 || pref
> 65535)
1436 vty_out (vty
, "the fourth field must be <1-65535>%s", VTY_NEWLINE
);
1440 /* Get route map. */
1441 map
= route_map_get (argv
[0]);
1442 index
= route_map_index_get (map
, permit
, pref
);
1445 vty
->node
= RMAP_NODE
;
1449 DEFUN (no_route_map_all
,
1450 no_route_map_all_cmd
,
1451 "no route-map WORD",
1453 "Create route-map or enter route-map command mode\n"
1456 struct route_map
*map
;
1458 map
= route_map_lookup_by_name (argv
[0]);
1461 vty_out (vty
, "%% Could not find route-map %s%s",
1462 argv
[0], VTY_NEWLINE
);
1466 route_map_delete (map
);
1471 DEFUN (no_route_map
,
1473 "no route-map WORD (deny|permit) <1-65535>",
1475 "Create route-map or enter route-map command mode\n"
1477 "Route map denies set operations\n"
1478 "Route map permits set operations\n"
1479 "Sequence to insert to/delete from existing route-map entry\n")
1483 struct route_map
*map
;
1484 struct route_map_index
*index
;
1485 char *endptr
= NULL
;
1488 if (strncmp (argv
[1], "permit", strlen (argv
[1])) == 0)
1489 permit
= RMAP_PERMIT
;
1490 else if (strncmp (argv
[1], "deny", strlen (argv
[1])) == 0)
1494 vty_out (vty
, "the third field must be [permit|deny]%s", VTY_NEWLINE
);
1499 pref
= strtoul (argv
[2], &endptr
, 10);
1500 if (pref
== ULONG_MAX
|| *endptr
!= '\0')
1502 vty_out (vty
, "the fourth field must be positive integer%s",
1506 if (pref
== 0 || pref
> 65535)
1508 vty_out (vty
, "the fourth field must be <1-65535>%s", VTY_NEWLINE
);
1512 /* Existence check. */
1513 map
= route_map_lookup_by_name (argv
[0]);
1516 vty_out (vty
, "%% Could not find route-map %s%s",
1517 argv
[0], VTY_NEWLINE
);
1521 /* Lookup route map index. */
1522 index
= route_map_index_lookup (map
, permit
, pref
);
1525 vty_out (vty
, "%% Could not find route-map entry %s %s%s",
1526 argv
[0], argv
[2], VTY_NEWLINE
);
1530 /* Delete index from route map. */
1531 route_map_index_delete (index
, 1);
1533 /* If this route rule is the last one, delete route map itself. */
1534 if (route_map_empty (map
))
1535 route_map_delete (map
);
1540 DEFUN (rmap_onmatch_next
,
1541 rmap_onmatch_next_cmd
,
1543 "Exit policy on matches\n"
1546 struct route_map_index
*index
;
1552 if (index
->type
== RMAP_DENY
)
1554 /* Under a deny clause, match means it's finished. No need to set next */
1555 vty_out (vty
, "on-match next not supported under route-map deny%s",
1559 index
->exitpolicy
= RMAP_NEXT
;
1564 DEFUN (no_rmap_onmatch_next
,
1565 no_rmap_onmatch_next_cmd
,
1568 "Exit policy on matches\n"
1571 struct route_map_index
*index
;
1576 index
->exitpolicy
= RMAP_EXIT
;
1581 DEFUN (rmap_onmatch_goto
,
1582 rmap_onmatch_goto_cmd
,
1583 "on-match goto <1-65535>",
1584 "Exit policy on matches\n"
1585 "Goto Clause number\n"
1588 struct route_map_index
*index
= vty
->index
;
1593 if (index
->type
== RMAP_DENY
)
1595 /* Under a deny clause, match means it's finished. No need to go anywhere */
1596 vty_out (vty
, "on-match goto not supported under route-map deny%s",
1601 if (argc
== 1 && argv
[0])
1602 VTY_GET_INTEGER_RANGE("route-map index", d
, argv
[0], 1, 65535);
1604 d
= index
->pref
+ 1;
1606 if (d
<= index
->pref
)
1608 /* Can't allow you to do that, Dave */
1609 vty_out (vty
, "can't jump backwards in route-maps%s",
1615 index
->exitpolicy
= RMAP_GOTO
;
1616 index
->nextpref
= d
;
1622 DEFUN (no_rmap_onmatch_goto
,
1623 no_rmap_onmatch_goto_cmd
,
1626 "Exit policy on matches\n"
1627 "Goto Clause number\n")
1629 struct route_map_index
*index
;
1634 index
->exitpolicy
= RMAP_EXIT
;
1639 /* Cisco/GNU Zebra compatible ALIASes for on-match next */
1640 ALIAS (rmap_onmatch_goto
,
1643 "Continue on a different entry within the route-map\n")
1645 ALIAS (no_rmap_onmatch_goto
,
1646 no_rmap_continue_cmd
,
1649 "Continue on a different entry within the route-map\n")
1651 /* GNU Zebra compatible */
1652 ALIAS (rmap_onmatch_goto
,
1653 rmap_continue_seq_cmd
,
1654 "continue <1-65535>",
1655 "Continue on a different entry within the route-map\n"
1656 "Route-map entry sequence number\n")
1658 ALIAS (no_rmap_onmatch_goto
,
1659 no_rmap_continue_seq
,
1660 "no continue <1-65535>",
1662 "Continue on a different entry within the route-map\n"
1663 "Route-map entry sequence number\n")
1665 DEFUN (rmap_show_name
,
1667 "show route-map [WORD]",
1669 "route-map information\n"
1672 const char *name
= NULL
;
1675 return vty_show_route_map (vty
, name
);
1678 ALIAS (rmap_onmatch_goto
,
1679 rmap_continue_index_cmd
,
1680 "continue <1-65535>",
1681 "Exit policy on matches\n"
1682 "Goto Clause number\n")
1687 "Jump to another Route-Map after match+set\n"
1688 "Target route-map name\n")
1690 struct route_map_index
*index
;
1697 route_map_upd8_dependency (RMAP_EVENT_CALL_DELETED
,
1700 XFREE (MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
1702 index
->nextrm
= XSTRDUP (MTYPE_ROUTE_MAP_NAME
, argv
[0]);
1705 /* Execute event hook. */
1706 route_map_upd8_dependency (RMAP_EVENT_CALL_ADDED
,
1712 DEFUN (no_rmap_call
,
1716 "Jump to another Route-Map after match+set\n")
1718 struct route_map_index
*index
;
1724 route_map_upd8_dependency (RMAP_EVENT_CALL_DELETED
,
1727 XFREE (MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
1728 index
->nextrm
= NULL
;
1734 DEFUN (rmap_description
,
1735 rmap_description_cmd
,
1736 "description .LINE",
1737 "Route-map comment\n"
1738 "Comment describing this route-map rule\n")
1740 struct route_map_index
*index
;
1745 if (index
->description
)
1746 XFREE (MTYPE_TMP
, index
->description
);
1747 index
->description
= argv_concat (argv
, argc
, 0);
1752 DEFUN (no_rmap_description
,
1753 no_rmap_description_cmd
,
1756 "Route-map comment\n")
1758 struct route_map_index
*index
;
1763 if (index
->description
)
1764 XFREE (MTYPE_TMP
, index
->description
);
1765 index
->description
= NULL
;
1770 /* Configuration write function. */
1772 route_map_config_write (struct vty
*vty
)
1774 struct route_map
*map
;
1775 struct route_map_index
*index
;
1776 struct route_map_rule
*rule
;
1780 for (map
= route_map_master
.head
; map
; map
= map
->next
)
1781 for (index
= map
->head
; index
; index
= index
->next
)
1784 vty_out (vty
, "!%s", VTY_NEWLINE
);
1788 vty_out (vty
, "route-map %s %s %d%s",
1790 route_map_type_str (index
->type
),
1791 index
->pref
, VTY_NEWLINE
);
1793 if (index
->description
)
1794 vty_out (vty
, " description %s%s", index
->description
, VTY_NEWLINE
);
1796 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1797 vty_out (vty
, " match %s %s%s", rule
->cmd
->str
,
1798 rule
->rule_str
? rule
->rule_str
: "",
1801 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
1802 vty_out (vty
, " set %s %s%s", rule
->cmd
->str
,
1803 rule
->rule_str
? rule
->rule_str
: "",
1806 vty_out (vty
, " call %s%s", index
->nextrm
, VTY_NEWLINE
);
1807 if (index
->exitpolicy
== RMAP_GOTO
)
1808 vty_out (vty
, " on-match goto %d%s", index
->nextpref
, VTY_NEWLINE
);
1809 if (index
->exitpolicy
== RMAP_NEXT
)
1810 vty_out (vty
," on-match next%s", VTY_NEWLINE
);
1817 /* Route map node structure. */
1818 static struct cmd_node rmap_node
=
1821 "%s(config-route-map)# ",
1826 route_map_init_dep_hashes (void)
1830 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++)
1831 route_map_dep_hash
[i
] = hash_create(route_map_dep_hash_make_key
,
1832 route_map_dep_hash_cmp
);
1835 /* Initialization of route map vector. */
1837 route_map_init_vty (void)
1839 route_map_init_dep_hashes();
1841 /* Install route map top node. */
1842 install_node (&rmap_node
, route_map_config_write
);
1844 /* Install route map commands. */
1845 install_default (RMAP_NODE
);
1846 install_element (CONFIG_NODE
, &route_map_cmd
);
1847 install_element (CONFIG_NODE
, &no_route_map_cmd
);
1848 install_element (CONFIG_NODE
, &no_route_map_all_cmd
);
1850 /* Install the on-match stuff */
1851 install_element (RMAP_NODE
, &route_map_cmd
);
1852 install_element (RMAP_NODE
, &rmap_onmatch_next_cmd
);
1853 install_element (RMAP_NODE
, &no_rmap_onmatch_next_cmd
);
1854 install_element (RMAP_NODE
, &rmap_onmatch_goto_cmd
);
1855 install_element (RMAP_NODE
, &no_rmap_onmatch_goto_cmd
);
1857 /* Install the continue stuff (ALIAS of on-match). */
1858 install_element (RMAP_NODE
, &rmap_continue_cmd
);
1859 install_element (RMAP_NODE
, &no_rmap_continue_cmd
);
1860 install_element (RMAP_NODE
, &rmap_continue_index_cmd
);
1862 /* Install the call stuff. */
1863 install_element (RMAP_NODE
, &rmap_call_cmd
);
1864 install_element (RMAP_NODE
, &no_rmap_call_cmd
);
1866 /* Install description commands. */
1867 install_element (RMAP_NODE
, &rmap_description_cmd
);
1868 install_element (RMAP_NODE
, &no_rmap_description_cmd
);
1870 /* Install show command */
1871 install_element (ENABLE_NODE
, &rmap_show_name_cmd
);