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 /* Vector for route match rules. */
34 static vector route_match_vec
;
36 /* Vector for route set rules. */
37 static vector route_set_vec
;
39 /* Route map rule. This rule has both `match' rule and `set' rule. */
43 struct route_map_rule_cmd
*cmd
;
45 /* For pretty printing. */
48 /* Pre-compiled match rule. */
52 struct route_map_rule
*next
;
53 struct route_map_rule
*prev
;
56 /* Making route map list. */
59 struct route_map
*head
;
60 struct route_map
*tail
;
62 void (*add_hook
) (const char *);
63 void (*delete_hook
) (const char *);
64 void (*event_hook
) (route_map_event_t
, const char *);
67 /* Master list of route map. */
68 static struct route_map_list route_map_master
= { NULL
, NULL
, NULL
, NULL
, NULL
};
69 struct hash
*route_map_master_hash
= NULL
;
72 route_map_hash_key_make (void *p
)
74 const struct route_map
*map
= p
;
75 return string_hash_make (map
->name
);
79 route_map_hash_cmp(const void *p1
, const void *p2
)
81 const struct route_map
*map1
= p1
;
82 const struct route_map
*map2
= p2
;
84 if (map1
->deleted
== map2
->deleted
)
86 if (map1
->name
&& map2
->name
)
88 if (!strcmp (map1
->name
, map2
->name
))
93 else if (!map1
->name
&& !map2
->name
)
102 enum route_map_upd8_type
108 /* all possible route-map dependency types */
109 enum route_map_dep_type
111 ROUTE_MAP_DEP_RMAP
= 1,
113 ROUTE_MAP_DEP_ECLIST
,
115 ROUTE_MAP_DEP_ASPATH
,
116 ROUTE_MAP_DEP_FILTER
,
123 struct hash
*dep_rmap_hash
;
124 struct hash
*this_hash
; /* ptr to the hash structure this is part of */
127 /* Hashes maintaining dependency between various sublists used by route maps */
128 struct hash
*route_map_dep_hash
[ROUTE_MAP_DEP_MAX
];
130 static unsigned int route_map_dep_hash_make_key (void *p
);
131 static int route_map_dep_hash_cmp (const void *p1
, const void *p2
);
132 static void route_map_init_dep_hashes (void);
133 static void route_map_clear_all_references (char *rmap_name
);
134 static void route_map_rule_delete (struct route_map_rule_list
*,
135 struct route_map_rule
*);
136 static int rmap_debug
= 0;
139 route_map_index_delete (struct route_map_index
*, int);
141 /* New route map allocation. Please note route map's name must be
143 static struct route_map
*
144 route_map_new (const char *name
)
146 struct route_map
*new;
148 new = XCALLOC (MTYPE_ROUTE_MAP
, sizeof (struct route_map
));
149 new->name
= XSTRDUP (MTYPE_ROUTE_MAP_NAME
, name
);
153 /* Add new name to route_map. */
154 static struct route_map
*
155 route_map_add (const char *name
)
157 struct route_map
*map
;
158 struct route_map_list
*list
;
160 map
= route_map_new (name
);
161 list
= &route_map_master
;
163 /* Add map to the hash */
164 hash_get(route_map_master_hash
, map
, hash_alloc_intern
);
167 map
->prev
= list
->tail
;
169 list
->tail
->next
= map
;
175 if (route_map_master
.add_hook
)
177 (*route_map_master
.add_hook
) (name
);
178 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_ADDED
);
183 /* this is supposed to be called post processing by
184 * the delete hook function. Don't invoke delete_hook
185 * again in this routine.
188 route_map_free_map (struct route_map
*map
)
190 struct route_map_list
*list
;
191 struct route_map_index
*index
;
193 while ((index
= map
->head
) != NULL
)
194 route_map_index_delete (index
, 0);
196 list
= &route_map_master
;
201 map
->next
->prev
= map
->prev
;
203 list
->tail
= map
->prev
;
206 map
->prev
->next
= map
->next
;
208 list
->head
= map
->next
;
210 hash_release(route_map_master_hash
, map
);
211 XFREE (MTYPE_ROUTE_MAP_NAME
, map
->name
);
212 XFREE (MTYPE_ROUTE_MAP
, map
);
216 /* Route map delete from list. */
218 route_map_delete (struct route_map
*map
)
220 struct route_map_index
*index
;
223 while ((index
= map
->head
) != NULL
)
224 route_map_index_delete (index
, 0);
229 /* Clear all dependencies */
230 route_map_clear_all_references(name
);
232 /* Execute deletion hook. */
233 if (route_map_master
.delete_hook
)
235 (*route_map_master
.delete_hook
) (name
);
236 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_DELETED
);
239 if (!map
->to_be_processed
)
241 route_map_free_map (map
);
245 /* Lookup route map by route map name string. */
247 route_map_lookup_by_name (const char *name
)
249 struct route_map
*map
;
250 struct route_map tmp_map
;
255 // map.deleted is 0 via memset
256 memset(&tmp_map
, 0, sizeof(struct route_map
));
257 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
258 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
259 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
264 route_map_mark_updated (const char *name
, int del_later
)
266 struct route_map
*map
;
268 struct route_map tmp_map
;
273 map
= route_map_lookup_by_name(name
);
275 /* If we did not find the routemap with deleted=0 try again
280 memset(&tmp_map
, 0, sizeof(struct route_map
));
281 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
283 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
284 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
289 map
->to_be_processed
= 1;
297 route_map_clear_updated (struct route_map
*map
)
303 map
->to_be_processed
= 0;
305 route_map_free_map(map
);
311 /* Lookup route map. If there isn't route map create one and return
313 static struct route_map
*
314 route_map_get (const char *name
)
316 struct route_map
*map
;
318 map
= route_map_lookup_by_name (name
);
320 map
= route_map_add (name
);
326 route_map_walk_update_list (void *arg
,
327 int (*route_map_update_fn
) (void *arg
, char *name
))
329 struct route_map
*node
;
330 struct route_map
*nnode
= NULL
;
332 for (node
= route_map_master
.head
; node
; node
= nnode
)
334 if (node
->to_be_processed
)
336 /* DD: Should we add any thread yield code here */
337 route_map_update_fn(arg
, node
->name
);
339 route_map_clear_updated(node
);
346 /* Return route map's type string. */
348 route_map_type_str (enum route_map_type type
)
365 route_map_empty (struct route_map
*map
)
367 if (map
->head
== NULL
&& map
->tail
== NULL
)
375 vty_show_route_map_entry (struct vty
*vty
, struct route_map
*map
)
377 struct route_map_index
*index
;
378 struct route_map_rule
*rule
;
380 /* Print the name of the protocol */
382 vty_out (vty
, "%s", zlog_proto_names
[zlog_default
->protocol
]);
383 if (zlog_default
->instance
)
384 vty_out (vty
, " %d", zlog_default
->instance
);
385 vty_out (vty
, ":%s", VTY_NEWLINE
);
387 for (index
= map
->head
; index
; index
= index
->next
)
389 vty_out (vty
, "route-map %s, %s, sequence %d%s",
390 map
->name
, route_map_type_str (index
->type
),
391 index
->pref
, VTY_NEWLINE
);
394 if (index
->description
)
395 vty_out (vty
, " Description:%s %s%s", VTY_NEWLINE
,
396 index
->description
, VTY_NEWLINE
);
399 vty_out (vty
, " Match clauses:%s", VTY_NEWLINE
);
400 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
401 vty_out (vty
, " %s %s%s",
402 rule
->cmd
->str
, rule
->rule_str
, VTY_NEWLINE
);
404 vty_out (vty
, " Set clauses:%s", VTY_NEWLINE
);
405 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
406 vty_out (vty
, " %s %s%s",
407 rule
->cmd
->str
, rule
->rule_str
, VTY_NEWLINE
);
410 vty_out (vty
, " Call clause:%s", VTY_NEWLINE
);
412 vty_out (vty
, " Call %s%s", index
->nextrm
, VTY_NEWLINE
);
415 vty_out (vty
, " Action:%s", VTY_NEWLINE
);
416 if (index
->exitpolicy
== RMAP_GOTO
)
417 vty_out (vty
, " Goto %d%s", index
->nextpref
, VTY_NEWLINE
);
418 else if (index
->exitpolicy
== RMAP_NEXT
)
419 vty_out (vty
, " Continue to next entry%s", VTY_NEWLINE
);
420 else if (index
->exitpolicy
== RMAP_EXIT
)
421 vty_out (vty
, " Exit routemap%s", VTY_NEWLINE
);
426 vty_show_route_map (struct vty
*vty
, const char *name
)
428 struct route_map
*map
;
432 map
= route_map_lookup_by_name (name
);
436 vty_show_route_map_entry (vty
, map
);
442 vty_out (vty
, "%s", zlog_proto_names
[zlog_default
->protocol
]);
443 if (zlog_default
->instance
)
444 vty_out (vty
, " %d", zlog_default
->instance
);
445 vty_out (vty
, ": 'route-map %s' not found%s", name
, VTY_NEWLINE
);
451 for (map
= route_map_master
.head
; map
; map
= map
->next
)
453 vty_show_route_map_entry (vty
, map
);
459 /* New route map allocation. Please note route map's name must be
461 static struct route_map_index
*
462 route_map_index_new (void)
464 struct route_map_index
*new;
466 new = XCALLOC (MTYPE_ROUTE_MAP_INDEX
, sizeof (struct route_map_index
));
467 new->exitpolicy
= RMAP_EXIT
; /* Default to Cisco-style */
471 /* Free route map index. */
473 route_map_index_delete (struct route_map_index
*index
, int notify
)
475 struct route_map_rule
*rule
;
477 /* Free route match. */
478 while ((rule
= index
->match_list
.head
) != NULL
)
479 route_map_rule_delete (&index
->match_list
, rule
);
481 /* Free route set. */
482 while ((rule
= index
->set_list
.head
) != NULL
)
483 route_map_rule_delete (&index
->set_list
, rule
);
485 /* Remove index from route map list. */
487 index
->next
->prev
= index
->prev
;
489 index
->map
->tail
= index
->prev
;
492 index
->prev
->next
= index
->next
;
494 index
->map
->head
= index
->next
;
496 /* Free 'char *nextrm' if not NULL */
498 XFREE (MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
500 /* Execute event hook. */
501 if (route_map_master
.event_hook
&& notify
)
503 (*route_map_master
.event_hook
) (RMAP_EVENT_INDEX_DELETED
,
505 route_map_notify_dependencies(index
->map
->name
, RMAP_EVENT_CALL_ADDED
);
507 XFREE (MTYPE_ROUTE_MAP_INDEX
, index
);
510 /* Lookup index from route map. */
511 static struct route_map_index
*
512 route_map_index_lookup (struct route_map
*map
, enum route_map_type type
,
515 struct route_map_index
*index
;
517 for (index
= map
->head
; index
; index
= index
->next
)
518 if ((index
->type
== type
|| type
== RMAP_ANY
)
519 && index
->pref
== pref
)
524 /* Add new index to route map. */
525 static struct route_map_index
*
526 route_map_index_add (struct route_map
*map
, enum route_map_type type
,
529 struct route_map_index
*index
;
530 struct route_map_index
*point
;
532 /* Allocate new route map inex. */
533 index
= route_map_index_new ();
538 /* Compare preference. */
539 for (point
= map
->head
; point
; point
= point
->next
)
540 if (point
->pref
>= pref
)
543 if (map
->head
== NULL
)
545 map
->head
= map
->tail
= index
;
547 else if (point
== NULL
)
549 index
->prev
= map
->tail
;
550 map
->tail
->next
= index
;
553 else if (point
== map
->head
)
555 index
->next
= map
->head
;
556 map
->head
->prev
= index
;
562 index
->prev
= point
->prev
;
564 point
->prev
->next
= index
;
568 /* Execute event hook. */
569 if (route_map_master
.event_hook
)
571 (*route_map_master
.event_hook
) (RMAP_EVENT_INDEX_ADDED
,
573 route_map_notify_dependencies (map
->name
, RMAP_EVENT_CALL_ADDED
);
578 /* Get route map index. */
579 static struct route_map_index
*
580 route_map_index_get (struct route_map
*map
, enum route_map_type type
,
583 struct route_map_index
*index
;
585 index
= route_map_index_lookup (map
, RMAP_ANY
, pref
);
586 if (index
&& index
->type
!= type
)
588 /* Delete index from route map. */
589 route_map_index_delete (index
, 1);
593 index
= route_map_index_add (map
, type
, pref
);
597 /* New route map rule */
598 static struct route_map_rule
*
599 route_map_rule_new (void)
601 struct route_map_rule
*new;
603 new = XCALLOC (MTYPE_ROUTE_MAP_RULE
, sizeof (struct route_map_rule
));
607 /* Install rule command to the match list. */
609 route_map_install_match (struct route_map_rule_cmd
*cmd
)
611 vector_set (route_match_vec
, cmd
);
614 /* Install rule command to the set list. */
616 route_map_install_set (struct route_map_rule_cmd
*cmd
)
618 vector_set (route_set_vec
, cmd
);
621 /* Lookup rule command from match list. */
622 static struct route_map_rule_cmd
*
623 route_map_lookup_match (const char *name
)
626 struct route_map_rule_cmd
*rule
;
628 for (i
= 0; i
< vector_active (route_match_vec
); i
++)
629 if ((rule
= vector_slot (route_match_vec
, i
)) != NULL
)
630 if (strcmp (rule
->str
, name
) == 0)
635 /* Lookup rule command from set list. */
636 static struct route_map_rule_cmd
*
637 route_map_lookup_set (const char *name
)
640 struct route_map_rule_cmd
*rule
;
642 for (i
= 0; i
< vector_active (route_set_vec
); i
++)
643 if ((rule
= vector_slot (route_set_vec
, i
)) != NULL
)
644 if (strcmp (rule
->str
, name
) == 0)
649 /* Add match and set rule to rule list. */
651 route_map_rule_add (struct route_map_rule_list
*list
,
652 struct route_map_rule
*rule
)
655 rule
->prev
= list
->tail
;
657 list
->tail
->next
= rule
;
663 /* Delete rule from rule list. */
665 route_map_rule_delete (struct route_map_rule_list
*list
,
666 struct route_map_rule
*rule
)
668 if (rule
->cmd
->func_free
)
669 (*rule
->cmd
->func_free
) (rule
->value
);
672 XFREE (MTYPE_ROUTE_MAP_RULE_STR
, rule
->rule_str
);
675 rule
->next
->prev
= rule
->prev
;
677 list
->tail
= rule
->prev
;
679 rule
->prev
->next
= rule
->next
;
681 list
->head
= rule
->next
;
683 XFREE (MTYPE_ROUTE_MAP_RULE
, rule
);
686 /* strcmp wrapper function which don't crush even argument is NULL. */
688 rulecmp (const char *dst
, const char *src
)
702 return strcmp (dst
, src
);
707 /* Use this to return the already specified argument for this match. This is
708 * useful to get the specified argument with a route map match rule when the
709 * rule is being deleted and the argument is not provided.
712 route_map_get_match_arg(struct route_map_index
*index
, const char *match_name
)
714 struct route_map_rule
*rule
;
715 struct route_map_rule_cmd
*cmd
;
717 /* First lookup rule for add match statement. */
718 cmd
= route_map_lookup_match (match_name
);
722 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
723 if (rule
->cmd
== cmd
&& rule
->rule_str
!= NULL
)
724 return (rule
->rule_str
);
729 /* Add match statement to route map. */
731 route_map_add_match (struct route_map_index
*index
, const char *match_name
,
732 const char *match_arg
)
734 struct route_map_rule
*rule
;
735 struct route_map_rule
*next
;
736 struct route_map_rule_cmd
*cmd
;
740 /* First lookup rule for add match statement. */
741 cmd
= route_map_lookup_match (match_name
);
743 return RMAP_RULE_MISSING
;
745 /* Next call compile function for this match statement. */
746 if (cmd
->func_compile
)
748 compile
= (*cmd
->func_compile
)(match_arg
);
750 return RMAP_COMPILE_ERROR
;
755 /* If argument is completely same ignore it. */
756 for (rule
= index
->match_list
.head
; rule
; rule
= next
)
759 if (rule
->cmd
== cmd
)
761 route_map_rule_delete (&index
->match_list
, rule
);
766 /* Add new route map match rule. */
767 rule
= route_map_rule_new ();
769 rule
->value
= compile
;
771 rule
->rule_str
= XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR
, match_arg
);
773 rule
->rule_str
= NULL
;
775 /* Add new route match rule to linked list. */
776 route_map_rule_add (&index
->match_list
, rule
);
778 /* Execute event hook. */
779 if (route_map_master
.event_hook
)
781 (*route_map_master
.event_hook
) (replaced
?
782 RMAP_EVENT_MATCH_REPLACED
:
783 RMAP_EVENT_MATCH_ADDED
,
785 route_map_notify_dependencies(index
->map
->name
, RMAP_EVENT_CALL_ADDED
);
791 /* Delete specified route match rule. */
793 route_map_delete_match (struct route_map_index
*index
, const char *match_name
,
794 const char *match_arg
)
796 struct route_map_rule
*rule
;
797 struct route_map_rule_cmd
*cmd
;
799 cmd
= route_map_lookup_match (match_name
);
803 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
804 if (rule
->cmd
== cmd
&&
805 (rulecmp (rule
->rule_str
, match_arg
) == 0 || match_arg
== NULL
))
807 route_map_rule_delete (&index
->match_list
, rule
);
808 /* Execute event hook. */
809 if (route_map_master
.event_hook
)
811 (*route_map_master
.event_hook
) (RMAP_EVENT_MATCH_DELETED
,
813 route_map_notify_dependencies(index
->map
->name
, RMAP_EVENT_CALL_ADDED
);
817 /* Can't find matched rule. */
821 /* Add route-map set statement to the route map. */
823 route_map_add_set (struct route_map_index
*index
, const char *set_name
,
826 struct route_map_rule
*rule
;
827 struct route_map_rule
*next
;
828 struct route_map_rule_cmd
*cmd
;
832 cmd
= route_map_lookup_set (set_name
);
834 return RMAP_RULE_MISSING
;
836 /* Next call compile function for this match statement. */
837 if (cmd
->func_compile
)
839 compile
= (*cmd
->func_compile
)(set_arg
);
841 return RMAP_COMPILE_ERROR
;
846 /* Add by WJL. if old set command of same kind exist, delete it first
847 to ensure only one set command of same kind exist under a
849 for (rule
= index
->set_list
.head
; rule
; rule
= next
)
852 if (rule
->cmd
== cmd
)
854 route_map_rule_delete (&index
->set_list
, rule
);
859 /* Add new route map match rule. */
860 rule
= route_map_rule_new ();
862 rule
->value
= compile
;
864 rule
->rule_str
= XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR
, set_arg
);
866 rule
->rule_str
= NULL
;
868 /* Add new route match rule to linked list. */
869 route_map_rule_add (&index
->set_list
, rule
);
871 /* Execute event hook. */
872 if (route_map_master
.event_hook
)
874 (*route_map_master
.event_hook
) (replaced
?
875 RMAP_EVENT_SET_REPLACED
:
876 RMAP_EVENT_SET_ADDED
,
878 route_map_notify_dependencies(index
->map
->name
, RMAP_EVENT_CALL_ADDED
);
883 /* Delete route map set rule. */
885 route_map_delete_set (struct route_map_index
*index
, const char *set_name
,
888 struct route_map_rule
*rule
;
889 struct route_map_rule_cmd
*cmd
;
891 cmd
= route_map_lookup_set (set_name
);
895 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
896 if ((rule
->cmd
== cmd
) &&
897 (rulecmp (rule
->rule_str
, set_arg
) == 0 || set_arg
== NULL
))
899 route_map_rule_delete (&index
->set_list
, rule
);
900 /* Execute event hook. */
901 if (route_map_master
.event_hook
)
903 (*route_map_master
.event_hook
) (RMAP_EVENT_SET_DELETED
,
905 route_map_notify_dependencies(index
->map
->name
, RMAP_EVENT_CALL_ADDED
);
909 /* Can't find matched rule. */
913 /* Apply route map's each index to the object.
915 The matrix for a route-map looks like this:
916 (note, this includes the description for the "NEXT"
923 ------------------+---------------
929 -Apply Set statements, accept route
930 -If Call statement is present jump to the specified route-map, if it
931 denies the route we finish.
932 -If NEXT is specified, goto NEXT statement
933 -If GOTO is specified, goto the first clause where pref > nextpref
934 -If nothing is specified, do as Cisco and finish
936 -Route is denied by route-map.
940 If we get no matches after we've processed all updates, then the route
943 Some notes on the new "CALL", "NEXT" and "GOTO"
944 call WORD - If this clause is matched, then the set statements
945 are executed and then we jump to route-map 'WORD'. If
946 this route-map denies the route, we finish, in other case we
947 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
948 on-match next - If this clause is matched, then the set statements
949 are executed and then we drop through to the next clause
950 on-match goto n - If this clause is matched, then the set statments
951 are executed and then we goto the nth clause, or the
952 first clause greater than this. In order to ensure
953 route-maps *always* exit, you cannot jump backwards.
956 We need to make sure our route-map processing matches the above
959 static route_map_result_t
960 route_map_apply_match (struct route_map_rule_list
*match_list
,
961 struct prefix
*prefix
, route_map_object_t type
,
964 route_map_result_t ret
= RMAP_NOMATCH
;
965 struct route_map_rule
*match
;
968 /* Check all match rule and if there is no match rule, go to the
970 if (!match_list
->head
)
974 for (match
= match_list
->head
; match
; match
= match
->next
)
976 /* Try each match statement in turn, If any do not return
977 RMAP_MATCH, return, otherwise continue on to next match
978 statement. All match statements must match for end-result
980 ret
= (*match
->cmd
->func_apply
) (match
->value
, prefix
,
982 if (ret
!= RMAP_MATCH
)
989 /* Apply route map to the object. */
991 route_map_apply (struct route_map
*map
, struct prefix
*prefix
,
992 route_map_object_t type
, void *object
)
994 static int recursion
= 0;
996 struct route_map_index
*index
;
997 struct route_map_rule
*set
;
999 if (recursion
> RMAP_RECURSION_LIMIT
)
1001 zlog (NULL
, LOG_WARNING
,
1002 "route-map recursion limit (%d) reached, discarding route",
1003 RMAP_RECURSION_LIMIT
);
1005 return RMAP_DENYMATCH
;
1009 return RMAP_DENYMATCH
;
1011 for (index
= map
->head
; index
; index
= index
->next
)
1013 /* Apply this index. */
1014 ret
= route_map_apply_match (&index
->match_list
, prefix
, type
, object
);
1016 /* Now we apply the matrix from above */
1017 if (ret
== RMAP_NOMATCH
)
1018 /* 'cont' from matrix - continue to next route-map sequence */
1020 else if (ret
== RMAP_MATCH
)
1022 if (index
->type
== RMAP_PERMIT
)
1025 /* permit+match must execute sets */
1026 for (set
= index
->set_list
.head
; set
; set
= set
->next
)
1027 ret
= (*set
->cmd
->func_apply
) (set
->value
, prefix
,
1030 /* Call another route-map if available */
1033 struct route_map
*nextrm
=
1034 route_map_lookup_by_name (index
->nextrm
);
1036 if (nextrm
) /* Target route-map found, jump to it */
1039 ret
= route_map_apply (nextrm
, prefix
, type
, object
);
1043 /* If nextrm returned 'deny', finish. */
1044 if (ret
== RMAP_DENYMATCH
)
1048 switch (index
->exitpolicy
)
1056 /* Find the next clause to jump to */
1057 struct route_map_index
*next
= index
->next
;
1058 int nextpref
= index
->nextpref
;
1060 while (next
&& next
->pref
< nextpref
)
1067 /* No clauses match! */
1073 else if (index
->type
== RMAP_DENY
)
1076 return RMAP_DENYMATCH
;
1080 /* Finally route-map does not match at all. */
1081 return RMAP_DENYMATCH
;
1085 route_map_add_hook (void (*func
) (const char *))
1087 route_map_master
.add_hook
= func
;
1091 route_map_delete_hook (void (*func
) (const char *))
1093 route_map_master
.delete_hook
= func
;
1097 route_map_event_hook (void (*func
) (route_map_event_t
, const char *))
1099 route_map_master
.event_hook
= func
;
1103 route_map_init (void)
1105 /* Make vector for match and set. */
1106 route_match_vec
= vector_init (1);
1107 route_set_vec
= vector_init (1);
1108 route_map_master_hash
= hash_create(route_map_hash_key_make
, route_map_hash_cmp
);
1112 route_map_finish (void)
1114 vector_free (route_match_vec
);
1115 route_match_vec
= NULL
;
1116 vector_free (route_set_vec
);
1117 route_set_vec
= NULL
;
1120 /* Routines for route map dependency lists and dependency processing */
1122 route_map_rmap_hash_cmp (const void *p1
, const void *p2
)
1124 return (strcmp((const char *)p1
, (const char *)p2
) == 0);
1128 route_map_dep_hash_cmp (const void *p1
, const void *p2
)
1131 return (strcmp (((const struct route_map_dep
*)p1
)->dep_name
, (const char *)p2
) == 0);
1135 route_map_clear_reference(struct hash_backet
*backet
, void *arg
)
1137 struct route_map_dep
*dep
= (struct route_map_dep
*)backet
->data
;
1142 rmap_name
= (char *)hash_release(dep
->dep_rmap_hash
, (void *)arg
);
1145 XFREE(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
1147 if (!dep
->dep_rmap_hash
->count
)
1149 dep
= hash_release(dep
->this_hash
, (void *)dep
->dep_name
);
1150 hash_free(dep
->dep_rmap_hash
);
1151 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
1152 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
1158 route_map_clear_all_references (char *rmap_name
)
1162 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++)
1164 hash_iterate(route_map_dep_hash
[i
], route_map_clear_reference
,
1170 route_map_dep_hash_alloc(void *p
)
1172 char *dep_name
= (char *)p
;
1173 struct route_map_dep
*dep_entry
;
1175 dep_entry
= XCALLOC(MTYPE_ROUTE_MAP_DEP
, sizeof(struct route_map_dep
));
1176 dep_entry
->dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1177 dep_entry
->dep_rmap_hash
= hash_create(route_map_dep_hash_make_key
,
1178 route_map_rmap_hash_cmp
);
1179 dep_entry
->this_hash
= NULL
;
1181 return((void *)dep_entry
);
1185 route_map_name_hash_alloc(void *p
)
1187 return((void *)XSTRDUP(MTYPE_ROUTE_MAP_NAME
, (const char *)p
));
1191 route_map_dep_hash_make_key (void *p
)
1193 return (string_hash_make((char *)p
));
1197 route_map_print_dependency (struct hash_backet
*backet
, void *data
)
1199 char *rmap_name
= (char *)backet
->data
;
1200 char *dep_name
= (char *)data
;
1203 zlog_debug("%s: Dependency for %s: %s", __FUNCTION__
, dep_name
, rmap_name
);
1207 route_map_dep_update (struct hash
*dephash
, const char *dep_name
,
1208 const char *rmap_name
,
1209 route_map_event_t type
)
1211 struct route_map_dep
*dep
;
1213 char *dname
, *rname
;
1216 dname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1217 rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
1221 case RMAP_EVENT_PLIST_ADDED
:
1222 case RMAP_EVENT_CLIST_ADDED
:
1223 case RMAP_EVENT_ECLIST_ADDED
:
1224 case RMAP_EVENT_ASLIST_ADDED
:
1225 case RMAP_EVENT_CALL_ADDED
:
1226 case RMAP_EVENT_FILTER_ADDED
:
1228 zlog_debug("%s: Adding dependency for %s in %s", __FUNCTION__
,
1229 dep_name
, rmap_name
);
1230 dep
= (struct route_map_dep
*) hash_get (dephash
, dname
,
1231 route_map_dep_hash_alloc
);
1237 if (!dep
->this_hash
)
1238 dep
->this_hash
= dephash
;
1240 hash_get(dep
->dep_rmap_hash
, rname
, route_map_name_hash_alloc
);
1242 case RMAP_EVENT_PLIST_DELETED
:
1243 case RMAP_EVENT_CLIST_DELETED
:
1244 case RMAP_EVENT_ECLIST_DELETED
:
1245 case RMAP_EVENT_ASLIST_DELETED
:
1246 case RMAP_EVENT_CALL_DELETED
:
1247 case RMAP_EVENT_FILTER_DELETED
:
1249 zlog_debug("%s: Deleting dependency for %s in %s", __FUNCTION__
,
1250 dep_name
, rmap_name
);
1251 dep
= (struct route_map_dep
*) hash_get (dephash
, dname
, NULL
);
1256 ret_map_name
= (char *)hash_release(dep
->dep_rmap_hash
, rname
);
1258 XFREE(MTYPE_ROUTE_MAP_NAME
, ret_map_name
);
1260 if (!dep
->dep_rmap_hash
->count
)
1262 dep
= hash_release(dephash
, dname
);
1263 hash_free(dep
->dep_rmap_hash
);
1264 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
1265 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
1276 hash_iterate (dep
->dep_rmap_hash
, route_map_print_dependency
, dname
);
1280 XFREE(MTYPE_ROUTE_MAP_NAME
, rname
);
1281 XFREE(MTYPE_ROUTE_MAP_NAME
, dname
);
1285 static struct hash
*
1286 route_map_get_dep_hash (route_map_event_t event
)
1288 struct hash
*upd8_hash
= NULL
;
1292 case RMAP_EVENT_PLIST_ADDED
:
1293 case RMAP_EVENT_PLIST_DELETED
:
1294 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_PLIST
];
1296 case RMAP_EVENT_CLIST_ADDED
:
1297 case RMAP_EVENT_CLIST_DELETED
:
1298 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_CLIST
];
1300 case RMAP_EVENT_ECLIST_ADDED
:
1301 case RMAP_EVENT_ECLIST_DELETED
:
1302 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ECLIST
];
1304 case RMAP_EVENT_ASLIST_ADDED
:
1305 case RMAP_EVENT_ASLIST_DELETED
:
1306 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ASPATH
];
1308 case RMAP_EVENT_CALL_ADDED
:
1309 case RMAP_EVENT_CALL_DELETED
:
1310 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_RMAP
];
1312 case RMAP_EVENT_FILTER_ADDED
:
1313 case RMAP_EVENT_FILTER_DELETED
:
1314 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_FILTER
];
1324 route_map_process_dependency (struct hash_backet
*backet
, void *data
)
1327 route_map_event_t type
= (route_map_event_t
)data
;
1329 rmap_name
= (char *)backet
->data
;
1334 zlog_debug("%s: Notifying %s of dependency", __FUNCTION__
,
1336 if (route_map_master
.event_hook
)
1337 (*route_map_master
.event_hook
) (type
, rmap_name
);
1342 route_map_upd8_dependency (route_map_event_t type
, const char *arg
,
1343 const char *rmap_name
)
1345 struct hash
*upd8_hash
= NULL
;
1347 if ((upd8_hash
= route_map_get_dep_hash(type
)))
1348 route_map_dep_update (upd8_hash
, arg
, rmap_name
, type
);
1352 route_map_notify_dependencies (const char *affected_name
, route_map_event_t event
)
1354 struct route_map_dep
*dep
;
1355 struct hash
*upd8_hash
;
1361 name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, affected_name
);
1363 if ((upd8_hash
= route_map_get_dep_hash(event
)) == NULL
)
1365 XFREE (MTYPE_ROUTE_MAP_NAME
, name
);
1369 dep
= (struct route_map_dep
*)hash_get (upd8_hash
, name
,
1373 if (!dep
->this_hash
)
1374 dep
->this_hash
= upd8_hash
;
1376 hash_iterate (dep
->dep_rmap_hash
, route_map_process_dependency
, (void *)event
);
1379 XFREE (MTYPE_ROUTE_MAP_NAME
, name
);
1382 /* VTY related functions. */
1385 "route-map WORD (deny|permit) <1-65535>",
1386 "Create route-map or enter route-map command mode\n"
1388 "Route map denies set operations\n"
1389 "Route map permits set operations\n"
1390 "Sequence to insert to/delete from existing route-map entry\n")
1394 struct route_map
*map
;
1395 struct route_map_index
*index
;
1396 char *endptr
= NULL
;
1399 if (strncmp (argv
[1], "permit", strlen (argv
[1])) == 0)
1400 permit
= RMAP_PERMIT
;
1401 else if (strncmp (argv
[1], "deny", strlen (argv
[1])) == 0)
1405 vty_out (vty
, "the third field must be [permit|deny]%s", VTY_NEWLINE
);
1409 /* Preference check. */
1410 pref
= strtoul (argv
[2], &endptr
, 10);
1411 if (pref
== ULONG_MAX
|| *endptr
!= '\0')
1413 vty_out (vty
, "the fourth field must be positive integer%s",
1417 if (pref
== 0 || pref
> 65535)
1419 vty_out (vty
, "the fourth field must be <1-65535>%s", VTY_NEWLINE
);
1423 /* Get route map. */
1424 map
= route_map_get (argv
[0]);
1425 index
= route_map_index_get (map
, permit
, pref
);
1428 vty
->node
= RMAP_NODE
;
1432 DEFUN (no_route_map_all
,
1433 no_route_map_all_cmd
,
1434 "no route-map WORD",
1436 "Create route-map or enter route-map command mode\n"
1439 struct route_map
*map
;
1441 map
= route_map_lookup_by_name (argv
[0]);
1444 vty_out (vty
, "%% Could not find route-map %s%s",
1445 argv
[0], VTY_NEWLINE
);
1449 route_map_delete (map
);
1454 DEFUN (no_route_map
,
1456 "no route-map WORD (deny|permit) <1-65535>",
1458 "Create route-map or enter route-map command mode\n"
1460 "Route map denies set operations\n"
1461 "Route map permits set operations\n"
1462 "Sequence to insert to/delete from existing route-map entry\n")
1466 struct route_map
*map
;
1467 struct route_map_index
*index
;
1468 char *endptr
= NULL
;
1471 if (strncmp (argv
[1], "permit", strlen (argv
[1])) == 0)
1472 permit
= RMAP_PERMIT
;
1473 else if (strncmp (argv
[1], "deny", strlen (argv
[1])) == 0)
1477 vty_out (vty
, "the third field must be [permit|deny]%s", VTY_NEWLINE
);
1482 pref
= strtoul (argv
[2], &endptr
, 10);
1483 if (pref
== ULONG_MAX
|| *endptr
!= '\0')
1485 vty_out (vty
, "the fourth field must be positive integer%s",
1489 if (pref
== 0 || pref
> 65535)
1491 vty_out (vty
, "the fourth field must be <1-65535>%s", VTY_NEWLINE
);
1495 /* Existence check. */
1496 map
= route_map_lookup_by_name (argv
[0]);
1499 vty_out (vty
, "%% Could not find route-map %s%s",
1500 argv
[0], VTY_NEWLINE
);
1504 /* Lookup route map index. */
1505 index
= route_map_index_lookup (map
, permit
, pref
);
1508 vty_out (vty
, "%% Could not find route-map entry %s %s%s",
1509 argv
[0], argv
[2], VTY_NEWLINE
);
1513 /* Delete index from route map. */
1514 route_map_index_delete (index
, 1);
1516 /* If this route rule is the last one, delete route map itself. */
1517 if (route_map_empty (map
))
1518 route_map_delete (map
);
1523 DEFUN (rmap_onmatch_next
,
1524 rmap_onmatch_next_cmd
,
1526 "Exit policy on matches\n"
1529 struct route_map_index
*index
;
1534 index
->exitpolicy
= RMAP_NEXT
;
1539 DEFUN (no_rmap_onmatch_next
,
1540 no_rmap_onmatch_next_cmd
,
1543 "Exit policy on matches\n"
1546 struct route_map_index
*index
;
1551 index
->exitpolicy
= RMAP_EXIT
;
1556 DEFUN (rmap_onmatch_goto
,
1557 rmap_onmatch_goto_cmd
,
1558 "on-match goto <1-65535>",
1559 "Exit policy on matches\n"
1560 "Goto Clause number\n"
1563 struct route_map_index
*index
= vty
->index
;
1568 if (argc
== 1 && argv
[0])
1569 VTY_GET_INTEGER_RANGE("route-map index", d
, argv
[0], 1, 65536);
1571 d
= index
->pref
+ 1;
1573 if (d
<= index
->pref
)
1575 /* Can't allow you to do that, Dave */
1576 vty_out (vty
, "can't jump backwards in route-maps%s",
1582 index
->exitpolicy
= RMAP_GOTO
;
1583 index
->nextpref
= d
;
1589 DEFUN (no_rmap_onmatch_goto
,
1590 no_rmap_onmatch_goto_cmd
,
1593 "Exit policy on matches\n"
1594 "Goto Clause number\n")
1596 struct route_map_index
*index
;
1601 index
->exitpolicy
= RMAP_EXIT
;
1606 /* Cisco/GNU Zebra compatible ALIASes for on-match next */
1607 ALIAS (rmap_onmatch_goto
,
1610 "Continue on a different entry within the route-map\n")
1612 ALIAS (no_rmap_onmatch_goto
,
1613 no_rmap_continue_cmd
,
1616 "Continue on a different entry within the route-map\n")
1618 /* GNU Zebra compatible */
1619 ALIAS (rmap_onmatch_goto
,
1620 rmap_continue_seq_cmd
,
1621 "continue <1-65535>",
1622 "Continue on a different entry within the route-map\n"
1623 "Route-map entry sequence number\n")
1625 ALIAS (no_rmap_onmatch_goto
,
1626 no_rmap_continue_seq
,
1627 "no continue <1-65535>",
1629 "Continue on a different entry within the route-map\n"
1630 "Route-map entry sequence number\n")
1632 DEFUN (rmap_show_name
,
1634 "show route-map [WORD]",
1636 "route-map information\n"
1639 const char *name
= NULL
;
1642 return vty_show_route_map (vty
, name
);
1645 ALIAS (rmap_onmatch_goto
,
1646 rmap_continue_index_cmd
,
1647 "continue <1-65536>",
1648 "Exit policy on matches\n"
1649 "Goto Clause number\n")
1654 "Jump to another Route-Map after match+set\n"
1655 "Target route-map name\n")
1657 struct route_map_index
*index
;
1664 route_map_upd8_dependency (RMAP_EVENT_CALL_DELETED
,
1667 XFREE (MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
1669 index
->nextrm
= XSTRDUP (MTYPE_ROUTE_MAP_NAME
, argv
[0]);
1672 /* Execute event hook. */
1673 route_map_upd8_dependency (RMAP_EVENT_CALL_ADDED
,
1679 DEFUN (no_rmap_call
,
1683 "Jump to another Route-Map after match+set\n")
1685 struct route_map_index
*index
;
1691 route_map_upd8_dependency (RMAP_EVENT_CALL_DELETED
,
1694 XFREE (MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
1695 index
->nextrm
= NULL
;
1701 DEFUN (rmap_description
,
1702 rmap_description_cmd
,
1703 "description .LINE",
1704 "Route-map comment\n"
1705 "Comment describing this route-map rule\n")
1707 struct route_map_index
*index
;
1712 if (index
->description
)
1713 XFREE (MTYPE_TMP
, index
->description
);
1714 index
->description
= argv_concat (argv
, argc
, 0);
1719 DEFUN (no_rmap_description
,
1720 no_rmap_description_cmd
,
1723 "Route-map comment\n")
1725 struct route_map_index
*index
;
1730 if (index
->description
)
1731 XFREE (MTYPE_TMP
, index
->description
);
1732 index
->description
= NULL
;
1737 /* Configuration write function. */
1739 route_map_config_write (struct vty
*vty
)
1741 struct route_map
*map
;
1742 struct route_map_index
*index
;
1743 struct route_map_rule
*rule
;
1747 for (map
= route_map_master
.head
; map
; map
= map
->next
)
1748 for (index
= map
->head
; index
; index
= index
->next
)
1751 vty_out (vty
, "!%s", VTY_NEWLINE
);
1755 vty_out (vty
, "route-map %s %s %d%s",
1757 route_map_type_str (index
->type
),
1758 index
->pref
, VTY_NEWLINE
);
1760 if (index
->description
)
1761 vty_out (vty
, " description %s%s", index
->description
, VTY_NEWLINE
);
1763 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1764 vty_out (vty
, " match %s %s%s", rule
->cmd
->str
,
1765 rule
->rule_str
? rule
->rule_str
: "",
1768 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
1769 vty_out (vty
, " set %s %s%s", rule
->cmd
->str
,
1770 rule
->rule_str
? rule
->rule_str
: "",
1773 vty_out (vty
, " call %s%s", index
->nextrm
, VTY_NEWLINE
);
1774 if (index
->exitpolicy
== RMAP_GOTO
)
1775 vty_out (vty
, " on-match goto %d%s", index
->nextpref
, VTY_NEWLINE
);
1776 if (index
->exitpolicy
== RMAP_NEXT
)
1777 vty_out (vty
," on-match next%s", VTY_NEWLINE
);
1784 /* Route map node structure. */
1785 static struct cmd_node rmap_node
=
1788 "%s(config-route-map)# ",
1793 route_map_init_dep_hashes (void)
1797 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++)
1798 route_map_dep_hash
[i
] = hash_create(route_map_dep_hash_make_key
,
1799 route_map_dep_hash_cmp
);
1802 /* Initialization of route map vector. */
1804 route_map_init_vty (void)
1806 route_map_init_dep_hashes();
1808 /* Install route map top node. */
1809 install_node (&rmap_node
, route_map_config_write
);
1811 /* Install route map commands. */
1812 install_default (RMAP_NODE
);
1813 install_element (CONFIG_NODE
, &route_map_cmd
);
1814 install_element (CONFIG_NODE
, &no_route_map_cmd
);
1815 install_element (CONFIG_NODE
, &no_route_map_all_cmd
);
1817 /* Install the on-match stuff */
1818 install_element (RMAP_NODE
, &route_map_cmd
);
1819 install_element (RMAP_NODE
, &rmap_onmatch_next_cmd
);
1820 install_element (RMAP_NODE
, &no_rmap_onmatch_next_cmd
);
1821 install_element (RMAP_NODE
, &rmap_onmatch_goto_cmd
);
1822 install_element (RMAP_NODE
, &no_rmap_onmatch_goto_cmd
);
1824 /* Install the continue stuff (ALIAS of on-match). */
1825 install_element (RMAP_NODE
, &rmap_continue_cmd
);
1826 install_element (RMAP_NODE
, &no_rmap_continue_cmd
);
1827 install_element (RMAP_NODE
, &rmap_continue_index_cmd
);
1829 /* Install the call stuff. */
1830 install_element (RMAP_NODE
, &rmap_call_cmd
);
1831 install_element (RMAP_NODE
, &no_rmap_call_cmd
);
1833 /* Install description commands. */
1834 install_element (RMAP_NODE
, &rmap_description_cmd
);
1835 install_element (RMAP_NODE
, &no_rmap_description_cmd
);
1837 /* Install show command */
1838 install_element (ENABLE_NODE
, &rmap_show_name_cmd
);