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 along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
33 #include "lib_errors.h"
35 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP
, "Route map")
36 DEFINE_MTYPE(LIB
, ROUTE_MAP_NAME
, "Route map name")
37 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_INDEX
, "Route map index")
38 DEFINE_MTYPE(LIB
, ROUTE_MAP_RULE
, "Route map rule")
39 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_RULE_STR
, "Route map rule str")
40 DEFINE_MTYPE(LIB
, ROUTE_MAP_COMPILED
, "Route map compiled")
41 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_DEP
, "Route map dependency")
42 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_DEP_DATA
, "Route map dependency data")
44 DEFINE_QOBJ_TYPE(route_map_index
)
45 DEFINE_QOBJ_TYPE(route_map
)
47 /* Vector for route match rules. */
48 static vector route_match_vec
;
50 /* Vector for route set rules. */
51 static vector route_set_vec
;
53 struct route_map_match_set_hooks rmap_match_set_hook
;
56 void route_map_match_interface_hook(int (*func
)(
57 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
58 const char *arg
, route_map_event_t type
))
60 rmap_match_set_hook
.match_interface
= func
;
63 /* no match interface */
64 void route_map_no_match_interface_hook(int (*func
)(
65 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
66 const char *arg
, route_map_event_t type
))
68 rmap_match_set_hook
.no_match_interface
= func
;
71 /* match ip address */
72 void route_map_match_ip_address_hook(int (*func
)(
73 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
74 const char *arg
, route_map_event_t type
))
76 rmap_match_set_hook
.match_ip_address
= func
;
79 /* no match ip address */
80 void route_map_no_match_ip_address_hook(int (*func
)(
81 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
82 const char *arg
, route_map_event_t type
))
84 rmap_match_set_hook
.no_match_ip_address
= func
;
87 /* match ip address prefix list */
88 void route_map_match_ip_address_prefix_list_hook(int (*func
)(
89 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
90 const char *arg
, route_map_event_t type
))
92 rmap_match_set_hook
.match_ip_address_prefix_list
= func
;
95 /* no match ip address prefix list */
96 void route_map_no_match_ip_address_prefix_list_hook(int (*func
)(
97 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
98 const char *arg
, route_map_event_t type
))
100 rmap_match_set_hook
.no_match_ip_address_prefix_list
= func
;
103 /* match ip next hop */
104 void route_map_match_ip_next_hop_hook(int (*func
)(
105 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
106 const char *arg
, route_map_event_t type
))
108 rmap_match_set_hook
.match_ip_next_hop
= func
;
111 /* no match ip next hop */
112 void route_map_no_match_ip_next_hop_hook(int (*func
)(
113 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
114 const char *arg
, route_map_event_t type
))
116 rmap_match_set_hook
.no_match_ip_next_hop
= func
;
119 /* match ip next hop prefix list */
120 void route_map_match_ip_next_hop_prefix_list_hook(int (*func
)(
121 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
122 const char *arg
, route_map_event_t type
))
124 rmap_match_set_hook
.match_ip_next_hop_prefix_list
= func
;
127 /* no match ip next hop prefix list */
128 void route_map_no_match_ip_next_hop_prefix_list_hook(int (*func
)(
129 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
130 const char *arg
, route_map_event_t type
))
132 rmap_match_set_hook
.no_match_ip_next_hop_prefix_list
= func
;
135 /* match ip next-hop type */
136 void route_map_match_ip_next_hop_type_hook(int (*func
)(
137 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
138 const char *arg
, route_map_event_t type
))
140 rmap_match_set_hook
.match_ip_next_hop_type
= func
;
143 /* no match ip next-hop type */
144 void route_map_no_match_ip_next_hop_type_hook(int (*func
)(
145 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
146 const char *arg
, route_map_event_t type
))
148 rmap_match_set_hook
.no_match_ip_next_hop_type
= func
;
151 /* match ipv6 address */
152 void route_map_match_ipv6_address_hook(int (*func
)(
153 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
154 const char *arg
, route_map_event_t type
))
156 rmap_match_set_hook
.match_ipv6_address
= func
;
159 /* no match ipv6 address */
160 void route_map_no_match_ipv6_address_hook(int (*func
)(
161 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
162 const char *arg
, route_map_event_t type
))
164 rmap_match_set_hook
.no_match_ipv6_address
= func
;
168 /* match ipv6 address prefix list */
169 void route_map_match_ipv6_address_prefix_list_hook(int (*func
)(
170 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
171 const char *arg
, route_map_event_t type
))
173 rmap_match_set_hook
.match_ipv6_address_prefix_list
= func
;
176 /* no match ipv6 address prefix list */
177 void route_map_no_match_ipv6_address_prefix_list_hook(int (*func
)(
178 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
179 const char *arg
, route_map_event_t type
))
181 rmap_match_set_hook
.no_match_ipv6_address_prefix_list
= func
;
184 /* match ipv6 next-hop type */
185 void route_map_match_ipv6_next_hop_type_hook(int (*func
)(
186 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
187 const char *arg
, route_map_event_t type
))
189 rmap_match_set_hook
.match_ipv6_next_hop_type
= func
;
192 /* no match ipv6 next-hop type */
193 void route_map_no_match_ipv6_next_hop_type_hook(int (*func
)(
194 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
195 const char *arg
, route_map_event_t type
))
197 rmap_match_set_hook
.no_match_ipv6_next_hop_type
= func
;
201 void route_map_match_metric_hook(int (*func
)(
202 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
203 const char *arg
, route_map_event_t type
))
205 rmap_match_set_hook
.match_metric
= func
;
208 /* no match metric */
209 void route_map_no_match_metric_hook(int (*func
)(
210 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
211 const char *arg
, route_map_event_t type
))
213 rmap_match_set_hook
.no_match_metric
= func
;
217 void route_map_match_tag_hook(int (*func
)(struct vty
*vty
,
218 struct route_map_index
*index
,
219 const char *command
, const char *arg
,
220 route_map_event_t type
))
222 rmap_match_set_hook
.match_tag
= func
;
226 void route_map_no_match_tag_hook(int (*func
)(
227 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
228 const char *arg
, route_map_event_t type
))
230 rmap_match_set_hook
.no_match_tag
= func
;
234 void route_map_set_ip_nexthop_hook(int (*func
)(struct vty
*vty
,
235 struct route_map_index
*index
,
239 rmap_match_set_hook
.set_ip_nexthop
= func
;
242 /* no set ip nexthop */
243 void route_map_no_set_ip_nexthop_hook(int (*func
)(struct vty
*vty
,
244 struct route_map_index
*index
,
248 rmap_match_set_hook
.no_set_ip_nexthop
= func
;
251 /* set ipv6 nexthop local */
252 void route_map_set_ipv6_nexthop_local_hook(
253 int (*func
)(struct vty
*vty
, struct route_map_index
*index
,
254 const char *command
, const char *arg
))
256 rmap_match_set_hook
.set_ipv6_nexthop_local
= func
;
259 /* no set ipv6 nexthop local */
260 void route_map_no_set_ipv6_nexthop_local_hook(
261 int (*func
)(struct vty
*vty
, struct route_map_index
*index
,
262 const char *command
, const char *arg
))
264 rmap_match_set_hook
.no_set_ipv6_nexthop_local
= func
;
268 void route_map_set_metric_hook(int (*func
)(struct vty
*vty
,
269 struct route_map_index
*index
,
273 rmap_match_set_hook
.set_metric
= func
;
277 void route_map_no_set_metric_hook(int (*func
)(struct vty
*vty
,
278 struct route_map_index
*index
,
282 rmap_match_set_hook
.no_set_metric
= func
;
286 void route_map_set_tag_hook(int (*func
)(struct vty
*vty
,
287 struct route_map_index
*index
,
288 const char *command
, const char *arg
))
290 rmap_match_set_hook
.set_tag
= func
;
294 void route_map_no_set_tag_hook(int (*func
)(struct vty
*vty
,
295 struct route_map_index
*index
,
299 rmap_match_set_hook
.no_set_tag
= func
;
302 int generic_match_add(struct vty
*vty
, struct route_map_index
*index
,
303 const char *command
, const char *arg
,
304 route_map_event_t type
)
306 enum rmap_compile_rets ret
;
308 ret
= route_map_add_match(index
, command
, arg
, type
);
310 case RMAP_RULE_MISSING
:
311 vty_out(vty
, "%% [%s] Can't find rule.\n", frr_protonameinst
);
312 return CMD_WARNING_CONFIG_FAILED
;
314 case RMAP_COMPILE_ERROR
:
316 "%% [%s] Argument form is unsupported or malformed.\n",
318 return CMD_WARNING_CONFIG_FAILED
;
320 case RMAP_COMPILE_SUCCESS
:
322 * Nothing to do here move along
330 int generic_match_delete(struct vty
*vty
, struct route_map_index
*index
,
331 const char *command
, const char *arg
,
332 route_map_event_t type
)
334 enum rmap_compile_rets ret
;
335 int retval
= CMD_SUCCESS
;
336 char *dep_name
= NULL
;
338 char *rmap_name
= NULL
;
340 if (type
!= RMAP_EVENT_MATCH_DELETED
) {
341 /* ignore the mundane, the types without any dependency */
343 if ((tmpstr
= route_map_get_match_arg(index
, command
))
346 XSTRDUP(MTYPE_ROUTE_MAP_RULE
, tmpstr
);
348 dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_RULE
, arg
);
350 rmap_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, index
->map
->name
);
353 ret
= route_map_delete_match(index
, command
, dep_name
, type
);
355 case RMAP_RULE_MISSING
:
356 vty_out(vty
, "%% [%s] Can't find rule.\n", frr_protonameinst
);
357 retval
= CMD_WARNING_CONFIG_FAILED
;
359 case RMAP_COMPILE_ERROR
:
361 "%% [%s] Argument form is unsupported or malformed.\n",
363 retval
= CMD_WARNING_CONFIG_FAILED
;
365 case RMAP_COMPILE_SUCCESS
:
372 XFREE(MTYPE_ROUTE_MAP_RULE
, dep_name
);
373 XFREE(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
378 int generic_set_add(struct vty
*vty
, struct route_map_index
*index
,
379 const char *command
, const char *arg
)
381 enum rmap_compile_rets ret
;
383 ret
= route_map_add_set(index
, command
, arg
);
385 case RMAP_RULE_MISSING
:
386 vty_out(vty
, "%% [%s] Can't find rule.\n", frr_protonameinst
);
387 return CMD_WARNING_CONFIG_FAILED
;
389 case RMAP_COMPILE_ERROR
:
391 "%% [%s] Argument form is unsupported or malformed.\n",
393 return CMD_WARNING_CONFIG_FAILED
;
395 case RMAP_COMPILE_SUCCESS
:
402 int generic_set_delete(struct vty
*vty
, struct route_map_index
*index
,
403 const char *command
, const char *arg
)
405 enum rmap_compile_rets ret
;
407 ret
= route_map_delete_set(index
, command
, arg
);
409 case RMAP_RULE_MISSING
:
410 vty_out(vty
, "%% [%s] Can't find rule.\n", frr_protonameinst
);
411 return CMD_WARNING_CONFIG_FAILED
;
413 case RMAP_COMPILE_ERROR
:
415 "%% [%s] Argument form is unsupported or malformed.\n",
417 return CMD_WARNING_CONFIG_FAILED
;
419 case RMAP_COMPILE_SUCCESS
:
427 /* Master list of route map. */
428 struct route_map_list route_map_master
= {NULL
, NULL
, NULL
, NULL
, NULL
};
429 struct hash
*route_map_master_hash
= NULL
;
431 static unsigned int route_map_hash_key_make(const void *p
)
433 const struct route_map
*map
= p
;
434 return string_hash_make(map
->name
);
437 static bool route_map_hash_cmp(const void *p1
, const void *p2
)
439 const struct route_map
*map1
= p1
;
440 const struct route_map
*map2
= p2
;
442 if (map1
->deleted
== map2
->deleted
) {
443 if (map1
->name
&& map2
->name
) {
444 if (!strcmp(map1
->name
, map2
->name
)) {
447 } else if (!map1
->name
&& !map2
->name
) {
455 enum route_map_upd8_type
{
460 /* all possible route-map dependency types */
461 enum route_map_dep_type
{
462 ROUTE_MAP_DEP_RMAP
= 1,
464 ROUTE_MAP_DEP_ECLIST
,
465 ROUTE_MAP_DEP_LCLIST
,
467 ROUTE_MAP_DEP_ASPATH
,
468 ROUTE_MAP_DEP_FILTER
,
472 struct route_map_dep
{
474 struct hash
*dep_rmap_hash
;
475 struct hash
*this_hash
; /* ptr to the hash structure this is part of */
478 struct route_map_dep_data
{
482 /* Count of number of sequences of this
483 * route-map that depend on the same entity.
488 /* Hashes maintaining dependency between various sublists used by route maps */
489 static struct hash
*route_map_dep_hash
[ROUTE_MAP_DEP_MAX
];
491 static unsigned int route_map_dep_hash_make_key(const void *p
);
492 static void route_map_clear_all_references(char *rmap_name
);
493 static void route_map_rule_delete(struct route_map_rule_list
*,
494 struct route_map_rule
*);
495 static bool rmap_debug
;
497 /* New route map allocation. Please note route map's name must be
499 static struct route_map
*route_map_new(const char *name
)
501 struct route_map
*new;
503 new = XCALLOC(MTYPE_ROUTE_MAP
, sizeof(struct route_map
));
504 new->name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
505 QOBJ_REG(new, route_map
);
509 /* Add new name to route_map. */
510 static struct route_map
*route_map_add(const char *name
)
512 struct route_map
*map
;
513 struct route_map_list
*list
;
515 map
= route_map_new(name
);
516 list
= &route_map_master
;
518 /* Add map to the hash */
519 hash_get(route_map_master_hash
, map
, hash_alloc_intern
);
521 /* Add new entry to the head of the list to match how it is added in the
522 * hash table. This is to ensure that if the same route-map has been
523 * created more than once and then marked for deletion (which can happen
524 * if prior deletions haven't completed as BGP hasn't yet done the
525 * route-map processing), the order of the entities is the same in both
526 * the list and the hash table. Otherwise, since there is nothing to
527 * distinguish between the two entries, the wrong entry could get freed.
528 * TODO: This needs to be re-examined to handle it better - e.g., revive
529 * a deleted entry if the route-map is created again.
532 map
->next
= list
->head
;
534 list
->head
->prev
= map
;
540 if (route_map_master
.add_hook
) {
541 (*route_map_master
.add_hook
)(name
);
542 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_ADDED
);
546 zlog_debug("Add route-map %s", name
);
550 /* this is supposed to be called post processing by
551 * the delete hook function. Don't invoke delete_hook
552 * again in this routine.
554 static void route_map_free_map(struct route_map
*map
)
556 struct route_map_list
*list
;
557 struct route_map_index
*index
;
562 while ((index
= map
->head
) != NULL
)
563 route_map_index_delete(index
, 0);
566 zlog_debug("Deleting route-map %s", map
->name
);
568 list
= &route_map_master
;
573 map
->next
->prev
= map
->prev
;
575 list
->tail
= map
->prev
;
578 map
->prev
->next
= map
->next
;
580 list
->head
= map
->next
;
582 hash_release(route_map_master_hash
, map
);
583 XFREE(MTYPE_ROUTE_MAP_NAME
, map
->name
);
584 XFREE(MTYPE_ROUTE_MAP
, map
);
587 /* Route map delete from list. */
588 void route_map_delete(struct route_map
*map
)
590 struct route_map_index
*index
;
593 while ((index
= map
->head
) != NULL
)
594 route_map_index_delete(index
, 0);
599 /* Clear all dependencies */
600 route_map_clear_all_references(name
);
602 /* Execute deletion hook. */
603 if (route_map_master
.delete_hook
) {
604 (*route_map_master
.delete_hook
)(name
);
605 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_DELETED
);
608 if (!map
->to_be_processed
) {
609 route_map_free_map(map
);
613 /* Lookup route map by route map name string. */
614 struct route_map
*route_map_lookup_by_name(const char *name
)
616 struct route_map
*map
;
617 struct route_map tmp_map
;
622 // map.deleted is 0 via memset
623 memset(&tmp_map
, 0, sizeof(struct route_map
));
624 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
625 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
626 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
630 /* Simple helper to warn if route-map does not exist. */
631 struct route_map
*route_map_lookup_warn_noexist(struct vty
*vty
, const char *name
)
633 struct route_map
*route_map
= route_map_lookup_by_name(name
);
636 if (vty_shell_serv(vty
))
637 vty_out(vty
, "The route-map '%s' does not exist.\n", name
);
642 int route_map_mark_updated(const char *name
)
644 struct route_map
*map
;
646 struct route_map tmp_map
;
651 map
= route_map_lookup_by_name(name
);
653 /* If we did not find the routemap with deleted=false try again
657 memset(&tmp_map
, 0, sizeof(struct route_map
));
658 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
659 tmp_map
.deleted
= true;
660 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
661 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
665 map
->to_be_processed
= true;
672 static int route_map_clear_updated(struct route_map
*map
)
677 map
->to_be_processed
= false;
679 route_map_free_map(map
);
685 /* Lookup route map. If there isn't route map create one and return
687 struct route_map
*route_map_get(const char *name
)
689 struct route_map
*map
;
691 map
= route_map_lookup_by_name(name
);
693 map
= route_map_add(name
);
698 void route_map_walk_update_list(void (*route_map_update_fn
)(char *name
))
700 struct route_map
*node
;
701 struct route_map
*nnode
= NULL
;
703 for (node
= route_map_master
.head
; node
; node
= nnode
) {
704 if (node
->to_be_processed
) {
705 /* DD: Should we add any thread yield code here */
706 route_map_update_fn(node
->name
);
708 route_map_clear_updated(node
);
714 /* Return route map's type string. */
715 static const char *route_map_type_str(enum route_map_type type
)
732 static const char *route_map_cmd_result_str(enum route_map_cmd_result_t res
)
750 static const char *route_map_result_str(route_map_result_t res
)
755 case RMAP_PERMITMATCH
:
763 static void vty_show_route_map_entry(struct vty
*vty
, struct route_map
*map
)
765 struct route_map_index
*index
;
766 struct route_map_rule
*rule
;
768 vty_out(vty
, "route-map: %s Invoked: %" PRIu64
"\n",
769 map
->name
, map
->applied
- map
->applied_clear
);
771 for (index
= map
->head
; index
; index
= index
->next
) {
772 vty_out(vty
, " %s, sequence %d Invoked %" PRIu64
"\n",
773 route_map_type_str(index
->type
), index
->pref
,
774 index
->applied
- index
->applied_clear
);
777 if (index
->description
)
778 vty_out(vty
, " Description:\n %s\n",
782 vty_out(vty
, " Match clauses:\n");
783 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
784 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
787 vty_out(vty
, " Set clauses:\n");
788 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
789 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
793 vty_out(vty
, " Call clause:\n");
795 vty_out(vty
, " Call %s\n", index
->nextrm
);
798 vty_out(vty
, " Action:\n");
799 if (index
->exitpolicy
== RMAP_GOTO
)
800 vty_out(vty
, " Goto %d\n", index
->nextpref
);
801 else if (index
->exitpolicy
== RMAP_NEXT
)
802 vty_out(vty
, " Continue to next entry\n");
803 else if (index
->exitpolicy
== RMAP_EXIT
)
804 vty_out(vty
, " Exit routemap\n");
808 static int sort_route_map(const void **map1
, const void **map2
)
810 const struct route_map
*m1
= *map1
;
811 const struct route_map
*m2
= *map2
;
813 return strcmp(m1
->name
, m2
->name
);
816 static int vty_show_route_map(struct vty
*vty
, const char *name
)
818 struct route_map
*map
;
820 vty_out(vty
, "%s:\n", frr_protonameinst
);
823 map
= route_map_lookup_by_name(name
);
826 vty_show_route_map_entry(vty
, map
);
829 vty_out(vty
, "%s: 'route-map %s' not found\n",
830 frr_protonameinst
, name
);
835 struct list
*maplist
= list_new();
838 for (map
= route_map_master
.head
; map
; map
= map
->next
)
839 listnode_add(maplist
, map
);
841 list_sort(maplist
, sort_route_map
);
843 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
844 vty_show_route_map_entry(vty
, map
);
846 list_delete(&maplist
);
851 /* Unused route map details */
852 static int vty_show_unused_route_map(struct vty
*vty
)
854 struct list
*maplist
= list_new();
856 struct route_map
*map
;
858 for (map
= route_map_master
.head
; map
; map
= map
->next
) {
859 /* If use_count is zero, No protocol is using this routemap.
860 * so adding to the list.
863 listnode_add(maplist
, map
);
866 if (maplist
->count
> 0) {
867 vty_out(vty
, "\n%s:\n", frr_protonameinst
);
868 list_sort(maplist
, sort_route_map
);
870 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
871 vty_show_route_map_entry(vty
, map
);
873 vty_out(vty
, "\n%s: None\n", frr_protonameinst
);
876 list_delete(&maplist
);
880 /* New route map allocation. Please note route map's name must be
882 static struct route_map_index
*route_map_index_new(void)
884 struct route_map_index
*new;
886 new = XCALLOC(MTYPE_ROUTE_MAP_INDEX
, sizeof(struct route_map_index
));
887 new->exitpolicy
= RMAP_EXIT
; /* Default to Cisco-style */
888 QOBJ_REG(new, route_map_index
);
892 /* Free route map index. */
893 void route_map_index_delete(struct route_map_index
*index
, int notify
)
895 struct route_map_rule
*rule
;
900 zlog_debug("Deleting route-map %s sequence %d",
901 index
->map
->name
, index
->pref
);
903 /* Free route match. */
904 while ((rule
= index
->match_list
.head
) != NULL
)
905 route_map_rule_delete(&index
->match_list
, rule
);
907 /* Free route set. */
908 while ((rule
= index
->set_list
.head
) != NULL
)
909 route_map_rule_delete(&index
->set_list
, rule
);
911 /* Remove index from route map list. */
913 index
->next
->prev
= index
->prev
;
915 index
->map
->tail
= index
->prev
;
918 index
->prev
->next
= index
->next
;
920 index
->map
->head
= index
->next
;
922 /* Free 'char *nextrm' if not NULL */
923 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
925 /* Execute event hook. */
926 if (route_map_master
.event_hook
&& notify
) {
927 (*route_map_master
.event_hook
)(index
->map
->name
);
928 route_map_notify_dependencies(index
->map
->name
,
929 RMAP_EVENT_CALL_ADDED
);
931 XFREE(MTYPE_ROUTE_MAP_INDEX
, index
);
934 /* Lookup index from route map. */
935 static struct route_map_index
*route_map_index_lookup(struct route_map
*map
,
936 enum route_map_type type
,
939 struct route_map_index
*index
;
941 for (index
= map
->head
; index
; index
= index
->next
)
942 if ((index
->type
== type
|| type
== RMAP_ANY
)
943 && index
->pref
== pref
)
948 /* Add new index to route map. */
949 static struct route_map_index
*
950 route_map_index_add(struct route_map
*map
, enum route_map_type type
, int pref
)
952 struct route_map_index
*index
;
953 struct route_map_index
*point
;
955 /* Allocate new route map inex. */
956 index
= route_map_index_new();
961 /* Compare preference. */
962 for (point
= map
->head
; point
; point
= point
->next
)
963 if (point
->pref
>= pref
)
966 if (map
->head
== NULL
) {
967 map
->head
= map
->tail
= index
;
968 } else if (point
== NULL
) {
969 index
->prev
= map
->tail
;
970 map
->tail
->next
= index
;
972 } else if (point
== map
->head
) {
973 index
->next
= map
->head
;
974 map
->head
->prev
= index
;
978 index
->prev
= point
->prev
;
980 point
->prev
->next
= index
;
984 /* Execute event hook. */
985 if (route_map_master
.event_hook
) {
986 (*route_map_master
.event_hook
)(map
->name
);
987 route_map_notify_dependencies(map
->name
, RMAP_EVENT_CALL_ADDED
);
991 zlog_debug("Route-map %s add sequence %d, type: %s",
992 map
->name
, pref
, route_map_type_str(type
));
997 /* Get route map index. */
998 struct route_map_index
*
999 route_map_index_get(struct route_map
*map
, enum route_map_type type
, int pref
)
1001 struct route_map_index
*index
;
1003 index
= route_map_index_lookup(map
, RMAP_ANY
, pref
);
1004 if (index
&& index
->type
!= type
) {
1005 /* Delete index from route map. */
1006 route_map_index_delete(index
, 1);
1010 index
= route_map_index_add(map
, type
, pref
);
1014 /* New route map rule */
1015 static struct route_map_rule
*route_map_rule_new(void)
1017 struct route_map_rule
*new;
1019 new = XCALLOC(MTYPE_ROUTE_MAP_RULE
, sizeof(struct route_map_rule
));
1023 /* Install rule command to the match list. */
1024 void route_map_install_match(const struct route_map_rule_cmd
*cmd
)
1026 vector_set(route_match_vec
, (void *)cmd
);
1029 /* Install rule command to the set list. */
1030 void route_map_install_set(const struct route_map_rule_cmd
*cmd
)
1032 vector_set(route_set_vec
, (void *)cmd
);
1035 /* Lookup rule command from match list. */
1036 static const struct route_map_rule_cmd
*route_map_lookup_match(const char *name
)
1039 const struct route_map_rule_cmd
*rule
;
1041 for (i
= 0; i
< vector_active(route_match_vec
); i
++)
1042 if ((rule
= vector_slot(route_match_vec
, i
)) != NULL
)
1043 if (strcmp(rule
->str
, name
) == 0)
1048 /* Lookup rule command from set list. */
1049 static const struct route_map_rule_cmd
*route_map_lookup_set(const char *name
)
1052 const struct route_map_rule_cmd
*rule
;
1054 for (i
= 0; i
< vector_active(route_set_vec
); i
++)
1055 if ((rule
= vector_slot(route_set_vec
, i
)) != NULL
)
1056 if (strcmp(rule
->str
, name
) == 0)
1061 /* Add match and set rule to rule list. */
1062 static void route_map_rule_add(struct route_map_rule_list
*list
,
1063 struct route_map_rule
*rule
)
1066 rule
->prev
= list
->tail
;
1068 list
->tail
->next
= rule
;
1074 /* Delete rule from rule list. */
1075 static void route_map_rule_delete(struct route_map_rule_list
*list
,
1076 struct route_map_rule
*rule
)
1078 if (rule
->cmd
->func_free
)
1079 (*rule
->cmd
->func_free
)(rule
->value
);
1081 XFREE(MTYPE_ROUTE_MAP_RULE_STR
, rule
->rule_str
);
1084 rule
->next
->prev
= rule
->prev
;
1086 list
->tail
= rule
->prev
;
1088 rule
->prev
->next
= rule
->next
;
1090 list
->head
= rule
->next
;
1092 XFREE(MTYPE_ROUTE_MAP_RULE
, rule
);
1095 /* strcmp wrapper function which don't crush even argument is NULL. */
1096 static int rulecmp(const char *dst
, const char *src
)
1107 return strcmp(dst
, src
);
1112 /* Use this to return the already specified argument for this match. This is
1113 * useful to get the specified argument with a route map match rule when the
1114 * rule is being deleted and the argument is not provided.
1116 const char *route_map_get_match_arg(struct route_map_index
*index
,
1117 const char *match_name
)
1119 struct route_map_rule
*rule
;
1120 const struct route_map_rule_cmd
*cmd
;
1122 /* First lookup rule for add match statement. */
1123 cmd
= route_map_lookup_match(match_name
);
1127 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1128 if (rule
->cmd
== cmd
&& rule
->rule_str
!= NULL
)
1129 return (rule
->rule_str
);
1134 static route_map_event_t
get_route_map_delete_event(route_map_event_t type
)
1137 case RMAP_EVENT_CALL_ADDED
:
1138 return RMAP_EVENT_CALL_DELETED
;
1139 case RMAP_EVENT_PLIST_ADDED
:
1140 return RMAP_EVENT_PLIST_DELETED
;
1141 case RMAP_EVENT_CLIST_ADDED
:
1142 return RMAP_EVENT_CLIST_DELETED
;
1143 case RMAP_EVENT_ECLIST_ADDED
:
1144 return RMAP_EVENT_ECLIST_DELETED
;
1145 case RMAP_EVENT_LLIST_ADDED
:
1146 return RMAP_EVENT_LLIST_DELETED
;
1147 case RMAP_EVENT_ASLIST_ADDED
:
1148 return RMAP_EVENT_ASLIST_DELETED
;
1149 case RMAP_EVENT_FILTER_ADDED
:
1150 return RMAP_EVENT_FILTER_DELETED
;
1151 case RMAP_EVENT_SET_ADDED
:
1152 case RMAP_EVENT_SET_DELETED
:
1153 case RMAP_EVENT_SET_REPLACED
:
1154 case RMAP_EVENT_MATCH_ADDED
:
1155 case RMAP_EVENT_MATCH_DELETED
:
1156 case RMAP_EVENT_MATCH_REPLACED
:
1157 case RMAP_EVENT_INDEX_ADDED
:
1158 case RMAP_EVENT_INDEX_DELETED
:
1159 case RMAP_EVENT_CALL_DELETED
:
1160 case RMAP_EVENT_PLIST_DELETED
:
1161 case RMAP_EVENT_CLIST_DELETED
:
1162 case RMAP_EVENT_ECLIST_DELETED
:
1163 case RMAP_EVENT_LLIST_DELETED
:
1164 case RMAP_EVENT_ASLIST_DELETED
:
1165 case RMAP_EVENT_FILTER_DELETED
:
1166 /* This function returns the appropriate 'deleted' event type
1167 * for every 'added' event type passed to this function.
1168 * This is done only for named entities used in the
1169 * route-map match commands.
1170 * This function is not to be invoked for any of the other event
1178 * Return to make c happy but if we get here something has gone
1179 * terribly terribly wrong, so yes this return makes no sense.
1181 return RMAP_EVENT_CALL_ADDED
;
1184 /* Add match statement to route map. */
1185 enum rmap_compile_rets
route_map_add_match(struct route_map_index
*index
,
1186 const char *match_name
,
1187 const char *match_arg
,
1188 route_map_event_t type
)
1190 struct route_map_rule
*rule
;
1191 struct route_map_rule
*next
;
1192 const struct route_map_rule_cmd
*cmd
;
1194 int8_t delete_rmap_event_type
= 0;
1195 const char *rule_key
;
1197 /* First lookup rule for add match statement. */
1198 cmd
= route_map_lookup_match(match_name
);
1200 return RMAP_RULE_MISSING
;
1202 /* Next call compile function for this match statement. */
1203 if (cmd
->func_compile
) {
1204 compile
= (*cmd
->func_compile
)(match_arg
);
1205 if (compile
== NULL
)
1206 return RMAP_COMPILE_ERROR
;
1209 /* use the compiled results if applicable */
1210 if (compile
&& cmd
->func_get_rmap_rule_key
)
1211 rule_key
= (*cmd
->func_get_rmap_rule_key
)
1214 rule_key
= match_arg
;
1216 /* If argument is completely same ignore it. */
1217 for (rule
= index
->match_list
.head
; rule
; rule
= next
) {
1219 if (rule
->cmd
== cmd
) {
1220 /* If the configured route-map match rule is exactly
1221 * the same as the existing configuration then,
1222 * ignore the duplicate configuration.
1224 if (strcmp(match_arg
, rule
->rule_str
) == 0) {
1226 (*cmd
->func_free
)(compile
);
1228 return RMAP_COMPILE_SUCCESS
;
1231 /* Remove the dependency of the route-map on the rule
1232 * that is being replaced.
1234 if (type
>= RMAP_EVENT_CALL_ADDED
) {
1235 delete_rmap_event_type
=
1236 get_route_map_delete_event(type
);
1237 route_map_upd8_dependency(
1238 delete_rmap_event_type
,
1243 route_map_rule_delete(&index
->match_list
, rule
);
1247 /* Add new route map match rule. */
1248 rule
= route_map_rule_new();
1250 rule
->value
= compile
;
1252 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, match_arg
);
1254 rule
->rule_str
= NULL
;
1256 /* Add new route match rule to linked list. */
1257 route_map_rule_add(&index
->match_list
, rule
);
1259 /* Execute event hook. */
1260 if (route_map_master
.event_hook
) {
1261 (*route_map_master
.event_hook
)(index
->map
->name
);
1262 route_map_notify_dependencies(index
->map
->name
,
1263 RMAP_EVENT_CALL_ADDED
);
1265 if (type
!= RMAP_EVENT_MATCH_ADDED
)
1266 route_map_upd8_dependency(type
, rule_key
, index
->map
->name
);
1268 return RMAP_COMPILE_SUCCESS
;
1271 /* Delete specified route match rule. */
1272 enum rmap_compile_rets
route_map_delete_match(struct route_map_index
*index
,
1273 const char *match_name
,
1274 const char *match_arg
,
1275 route_map_event_t type
)
1277 struct route_map_rule
*rule
;
1278 const struct route_map_rule_cmd
*cmd
;
1279 const char *rule_key
;
1281 cmd
= route_map_lookup_match(match_name
);
1283 return RMAP_RULE_MISSING
;
1285 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1286 if (rule
->cmd
== cmd
&& (rulecmp(rule
->rule_str
, match_arg
) == 0
1287 || match_arg
== NULL
)) {
1288 /* Execute event hook. */
1289 if (route_map_master
.event_hook
) {
1290 (*route_map_master
.event_hook
)(index
->map
->name
);
1291 route_map_notify_dependencies(
1293 RMAP_EVENT_CALL_ADDED
);
1295 if (cmd
->func_get_rmap_rule_key
)
1296 rule_key
= (*cmd
->func_get_rmap_rule_key
)
1299 rule_key
= match_arg
;
1301 if (type
!= RMAP_EVENT_MATCH_DELETED
&& rule_key
)
1302 route_map_upd8_dependency(type
, rule_key
,
1305 route_map_rule_delete(&index
->match_list
, rule
);
1306 return RMAP_COMPILE_SUCCESS
;
1308 /* Can't find matched rule. */
1309 return RMAP_RULE_MISSING
;
1312 /* Add route-map set statement to the route map. */
1313 enum rmap_compile_rets
route_map_add_set(struct route_map_index
*index
,
1314 const char *set_name
,
1315 const char *set_arg
)
1317 struct route_map_rule
*rule
;
1318 struct route_map_rule
*next
;
1319 const struct route_map_rule_cmd
*cmd
;
1322 cmd
= route_map_lookup_set(set_name
);
1324 return RMAP_RULE_MISSING
;
1326 /* Next call compile function for this match statement. */
1327 if (cmd
->func_compile
) {
1328 compile
= (*cmd
->func_compile
)(set_arg
);
1329 if (compile
== NULL
)
1330 return RMAP_COMPILE_ERROR
;
1334 /* Add by WJL. if old set command of same kind exist, delete it first
1335 to ensure only one set command of same kind exist under a
1337 for (rule
= index
->set_list
.head
; rule
; rule
= next
) {
1339 if (rule
->cmd
== cmd
)
1340 route_map_rule_delete(&index
->set_list
, rule
);
1343 /* Add new route map match rule. */
1344 rule
= route_map_rule_new();
1346 rule
->value
= compile
;
1348 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, set_arg
);
1350 rule
->rule_str
= NULL
;
1352 /* Add new route match rule to linked list. */
1353 route_map_rule_add(&index
->set_list
, rule
);
1355 /* Execute event hook. */
1356 if (route_map_master
.event_hook
) {
1357 (*route_map_master
.event_hook
)(index
->map
->name
);
1358 route_map_notify_dependencies(index
->map
->name
,
1359 RMAP_EVENT_CALL_ADDED
);
1361 return RMAP_COMPILE_SUCCESS
;
1364 /* Delete route map set rule. */
1365 enum rmap_compile_rets
route_map_delete_set(struct route_map_index
*index
,
1366 const char *set_name
,
1367 const char *set_arg
)
1369 struct route_map_rule
*rule
;
1370 const struct route_map_rule_cmd
*cmd
;
1372 cmd
= route_map_lookup_set(set_name
);
1374 return RMAP_RULE_MISSING
;
1376 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
1377 if ((rule
->cmd
== cmd
) && (rulecmp(rule
->rule_str
, set_arg
) == 0
1378 || set_arg
== NULL
)) {
1379 route_map_rule_delete(&index
->set_list
, rule
);
1380 /* Execute event hook. */
1381 if (route_map_master
.event_hook
) {
1382 (*route_map_master
.event_hook
)(index
->map
->name
);
1383 route_map_notify_dependencies(
1385 RMAP_EVENT_CALL_ADDED
);
1387 return RMAP_COMPILE_SUCCESS
;
1389 /* Can't find matched rule. */
1390 return RMAP_RULE_MISSING
;
1393 static enum route_map_cmd_result_t
1394 route_map_apply_match(struct route_map_rule_list
*match_list
,
1395 const struct prefix
*prefix
, route_map_object_t type
,
1398 enum route_map_cmd_result_t ret
= RMAP_NOMATCH
;
1399 struct route_map_rule
*match
;
1400 bool is_matched
= false;
1403 /* Check all match rule and if there is no match rule, go to the
1405 if (!match_list
->head
)
1408 for (match
= match_list
->head
; match
; match
= match
->next
) {
1410 * Try each match statement. If any match does not
1411 * return RMAP_MATCH or RMAP_NOOP, return.
1412 * Otherwise continue on to next match statement.
1413 * All match statements must MATCH for
1414 * end-result to be a match.
1415 * (Exception:If match stmts result in a mix of
1416 * MATCH/NOOP, then also end-result is a match)
1417 * If all result in NOOP, end-result is NOOP.
1419 ret
= (*match
->cmd
->func_apply
)(match
->value
, prefix
,
1423 * If the consolidated result of func_apply is:
1424 * -----------------------------------------------
1425 * | MATCH | NOMATCH | NOOP | Final Result |
1426 * ------------------------------------------------
1427 * | yes | yes | yes | NOMATCH |
1428 * | no | no | yes | NOOP |
1429 * | yes | no | yes | MATCH |
1430 * | no | yes | yes | NOMATCH |
1431 * |-----------------------------------------------
1433 * Traditionally, all rules within route-map
1434 * should match for it to MATCH.
1435 * If there are noops within the route-map rules,
1436 * it follows the above matrix.
1438 * Eg: route-map rm1 permit 10
1443 * route-map rm1 permit 20
1471 /* Apply route map's each index to the object.
1473 The matrix for a route-map looks like this:
1474 (note, this includes the description for the "NEXT"
1475 and "GOTO" frobs now
1477 | Match | No Match | No op
1478 |-----------|--------------|-------
1479 permit | action | cont | cont.
1480 | | default:deny | default:permit
1481 -------------------+-----------------------
1482 | deny | cont | cont.
1483 deny | | default:deny | default:permit
1484 |-----------|--------------|--------
1487 -Apply Set statements, accept route
1488 -If Call statement is present jump to the specified route-map, if it
1489 denies the route we finish.
1490 -If NEXT is specified, goto NEXT statement
1491 -If GOTO is specified, goto the first clause where pref > nextpref
1492 -If nothing is specified, do as Cisco and finish
1494 -Route is denied by route-map.
1498 If we get no matches after we've processed all updates, then the route
1501 Some notes on the new "CALL", "NEXT" and "GOTO"
1502 call WORD - If this clause is matched, then the set statements
1503 are executed and then we jump to route-map 'WORD'. If
1504 this route-map denies the route, we finish, in other
1506 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
1507 on-match next - If this clause is matched, then the set statements
1508 are executed and then we drop through to the next clause
1509 on-match goto n - If this clause is matched, then the set statments
1510 are executed and then we goto the nth clause, or the
1511 first clause greater than this. In order to ensure
1512 route-maps *always* exit, you cannot jump backwards.
1515 We need to make sure our route-map processing matches the above
1517 route_map_result_t
route_map_apply(struct route_map
*map
,
1518 const struct prefix
*prefix
,
1519 route_map_object_t type
, void *object
)
1521 static int recursion
= 0;
1522 enum route_map_cmd_result_t match_ret
= RMAP_NOMATCH
;
1523 route_map_result_t ret
= RMAP_PERMITMATCH
;
1524 struct route_map_index
*index
;
1525 struct route_map_rule
*set
;
1526 char buf
[PREFIX_STRLEN
];
1528 if (recursion
> RMAP_RECURSION_LIMIT
) {
1530 EC_LIB_RMAP_RECURSION_LIMIT
,
1531 "route-map recursion limit (%d) reached, discarding route",
1532 RMAP_RECURSION_LIMIT
);
1534 return RMAP_DENYMATCH
;
1537 if (map
== NULL
|| map
->head
== NULL
) {
1538 ret
= RMAP_DENYMATCH
;
1539 goto route_map_apply_end
;
1543 for (index
= map
->head
; index
; index
= index
->next
) {
1544 /* Apply this index. */
1546 match_ret
= route_map_apply_match(&index
->match_list
, prefix
,
1550 zlog_debug("Route-map: %s, sequence: %d, prefix: %s, result: %s",
1551 map
->name
, index
->pref
,
1552 prefix2str(prefix
, buf
, sizeof(buf
)),
1553 route_map_cmd_result_str(match_ret
));
1556 /* Now we apply the matrix from above */
1557 if (match_ret
== RMAP_NOOP
)
1559 * Do not change the return value. Retain the previous
1560 * return value. Previous values can be:
1561 * 1)permitmatch (if a nomatch was never
1562 * seen before in this route-map.)
1563 * 2)denymatch (if a nomatch was seen earlier in one
1564 * of the previous sequences)
1568 * 'cont' from matrix - continue to next route-map
1572 else if (match_ret
== RMAP_NOMATCH
) {
1575 * The return value is now changed to denymatch.
1576 * So from here on out, even if we see more noops,
1577 * we retain this return value and return this
1578 * eventually if there are no matches.
1580 ret
= RMAP_DENYMATCH
;
1583 * 'cont' from matrix - continue to next route-map
1587 } else if (match_ret
== RMAP_MATCH
) {
1588 if (index
->type
== RMAP_PERMIT
)
1591 /* Match succeeded, rmap is of type permit */
1592 ret
= RMAP_PERMITMATCH
;
1594 /* permit+match must execute sets */
1595 for (set
= index
->set_list
.head
; set
;
1598 * set cmds return RMAP_OKAY or
1599 * RMAP_ERROR. We do not care if
1600 * set succeeded or not. So, ignore
1603 (void) (*set
->cmd
->func_apply
)(
1604 set
->value
, prefix
, type
,
1607 /* Call another route-map if available */
1608 if (index
->nextrm
) {
1609 struct route_map
*nextrm
=
1610 route_map_lookup_by_name(
1613 if (nextrm
) /* Target route-map found,
1617 ret
= route_map_apply(
1618 nextrm
, prefix
, type
,
1623 /* If nextrm returned 'deny', finish. */
1624 if (ret
== RMAP_DENYMATCH
)
1625 goto route_map_apply_end
;
1628 switch (index
->exitpolicy
) {
1630 goto route_map_apply_end
;
1634 /* Find the next clause to jump to */
1635 struct route_map_index
*next
=
1637 int nextpref
= index
->nextpref
;
1639 while (next
&& next
->pref
< nextpref
) {
1644 /* No clauses match! */
1645 goto route_map_apply_end
;
1649 } else if (index
->type
== RMAP_DENY
)
1652 ret
= RMAP_DENYMATCH
;
1653 goto route_map_apply_end
;
1658 route_map_apply_end
:
1660 zlog_debug("Route-map: %s, prefix: %s, result: %s",
1661 (map
? map
->name
: "null"),
1662 prefix2str(prefix
, buf
, sizeof(buf
)),
1663 route_map_result_str(ret
));
1669 void route_map_add_hook(void (*func
)(const char *))
1671 route_map_master
.add_hook
= func
;
1674 void route_map_delete_hook(void (*func
)(const char *))
1676 route_map_master
.delete_hook
= func
;
1679 void route_map_event_hook(void (*func
)(const char *name
))
1681 route_map_master
.event_hook
= func
;
1684 /* Routines for route map dependency lists and dependency processing */
1685 static bool route_map_rmap_hash_cmp(const void *p1
, const void *p2
)
1687 return strcmp(((const struct route_map_dep_data
*)p1
)->rname
,
1688 ((const struct route_map_dep_data
*)p2
)->rname
)
1692 static bool route_map_dep_hash_cmp(const void *p1
, const void *p2
)
1695 return (strcmp(((const struct route_map_dep
*)p1
)->dep_name
,
1700 static void route_map_clear_reference(struct hash_bucket
*bucket
, void *arg
)
1702 struct route_map_dep
*dep
= bucket
->data
;
1703 struct route_map_dep_data
*dep_data
= NULL
, tmp_dep_data
;
1706 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
1707 tmp_dep_data
.rname
= arg
;
1708 dep_data
= hash_release(dep
->dep_rmap_hash
,
1711 XFREE(MTYPE_ROUTE_MAP_NAME
, dep_data
->rname
);
1712 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, dep_data
);
1714 if (!dep
->dep_rmap_hash
->count
) {
1715 dep
= hash_release(dep
->this_hash
,
1716 (void *)dep
->dep_name
);
1717 hash_free(dep
->dep_rmap_hash
);
1718 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
1719 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
1724 static void route_map_clear_all_references(char *rmap_name
)
1728 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
1729 hash_iterate(route_map_dep_hash
[i
], route_map_clear_reference
,
1734 static unsigned int route_map_dep_data_hash_make_key(const void *p
)
1736 const struct route_map_dep_data
*dep_data
= p
;
1738 return string_hash_make(dep_data
->rname
);
1741 static void *route_map_dep_hash_alloc(void *p
)
1743 char *dep_name
= (char *)p
;
1744 struct route_map_dep
*dep_entry
;
1746 dep_entry
= XCALLOC(MTYPE_ROUTE_MAP_DEP
, sizeof(struct route_map_dep
));
1747 dep_entry
->dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1748 dep_entry
->dep_rmap_hash
=
1749 hash_create_size(8, route_map_dep_data_hash_make_key
,
1750 route_map_rmap_hash_cmp
, "Route Map Dep Hash");
1751 dep_entry
->this_hash
= NULL
;
1756 static void *route_map_name_hash_alloc(void *p
)
1758 struct route_map_dep_data
*dep_data
= NULL
, *tmp_dep_data
= NULL
;
1760 dep_data
= XCALLOC(MTYPE_ROUTE_MAP_DEP_DATA
,
1761 sizeof(struct route_map_dep_data
));
1763 dep_data
->rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, tmp_dep_data
->rname
);
1767 static unsigned int route_map_dep_hash_make_key(const void *p
)
1769 return (string_hash_make((char *)p
));
1772 static void route_map_print_dependency(struct hash_bucket
*bucket
, void *data
)
1774 struct route_map_dep_data
*dep_data
= bucket
->data
;
1775 char *rmap_name
= dep_data
->rname
;
1776 char *dep_name
= data
;
1778 zlog_debug("%s: Dependency for %s: %s", __FUNCTION__
, dep_name
,
1782 static int route_map_dep_update(struct hash
*dephash
, const char *dep_name
,
1783 const char *rmap_name
, route_map_event_t type
)
1785 struct route_map_dep
*dep
= NULL
;
1786 char *dname
, *rname
;
1788 struct route_map_dep_data
*dep_data
= NULL
, *ret_dep_data
= NULL
;
1789 struct route_map_dep_data tmp_dep_data
;
1791 dname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1792 rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
1795 case RMAP_EVENT_PLIST_ADDED
:
1796 case RMAP_EVENT_CLIST_ADDED
:
1797 case RMAP_EVENT_ECLIST_ADDED
:
1798 case RMAP_EVENT_ASLIST_ADDED
:
1799 case RMAP_EVENT_LLIST_ADDED
:
1800 case RMAP_EVENT_CALL_ADDED
:
1801 case RMAP_EVENT_FILTER_ADDED
:
1803 zlog_debug("Adding dependency for filter %s in route-map %s",
1804 dep_name
, rmap_name
);
1805 dep
= (struct route_map_dep
*)hash_get(
1806 dephash
, dname
, route_map_dep_hash_alloc
);
1812 if (!dep
->this_hash
)
1813 dep
->this_hash
= dephash
;
1815 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
1816 tmp_dep_data
.rname
= rname
;
1817 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
1819 dep_data
= hash_get(dep
->dep_rmap_hash
, &tmp_dep_data
,
1820 route_map_name_hash_alloc
);
1824 case RMAP_EVENT_PLIST_DELETED
:
1825 case RMAP_EVENT_CLIST_DELETED
:
1826 case RMAP_EVENT_ECLIST_DELETED
:
1827 case RMAP_EVENT_ASLIST_DELETED
:
1828 case RMAP_EVENT_LLIST_DELETED
:
1829 case RMAP_EVENT_CALL_DELETED
:
1830 case RMAP_EVENT_FILTER_DELETED
:
1832 zlog_debug("Deleting dependency for filter %s in route-map %s",
1833 dep_name
, rmap_name
);
1834 dep
= (struct route_map_dep
*)hash_get(dephash
, dname
, NULL
);
1839 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
1840 tmp_dep_data
.rname
= rname
;
1841 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
1844 if (!dep_data
->refcnt
) {
1845 ret_dep_data
= hash_release(dep
->dep_rmap_hash
,
1848 XFREE(MTYPE_ROUTE_MAP_NAME
,
1849 ret_dep_data
->rname
);
1850 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, ret_dep_data
);
1854 if (!dep
->dep_rmap_hash
->count
) {
1855 dep
= hash_release(dephash
, dname
);
1856 hash_free(dep
->dep_rmap_hash
);
1857 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
1858 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
1862 case RMAP_EVENT_SET_ADDED
:
1863 case RMAP_EVENT_SET_DELETED
:
1864 case RMAP_EVENT_SET_REPLACED
:
1865 case RMAP_EVENT_MATCH_ADDED
:
1866 case RMAP_EVENT_MATCH_DELETED
:
1867 case RMAP_EVENT_MATCH_REPLACED
:
1868 case RMAP_EVENT_INDEX_ADDED
:
1869 case RMAP_EVENT_INDEX_DELETED
:
1875 hash_iterate(dep
->dep_rmap_hash
,
1876 route_map_print_dependency
, dname
);
1880 XFREE(MTYPE_ROUTE_MAP_NAME
, rname
);
1881 XFREE(MTYPE_ROUTE_MAP_NAME
, dname
);
1885 static struct hash
*route_map_get_dep_hash(route_map_event_t event
)
1887 struct hash
*upd8_hash
= NULL
;
1890 case RMAP_EVENT_PLIST_ADDED
:
1891 case RMAP_EVENT_PLIST_DELETED
:
1892 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_PLIST
];
1894 case RMAP_EVENT_CLIST_ADDED
:
1895 case RMAP_EVENT_CLIST_DELETED
:
1896 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_CLIST
];
1898 case RMAP_EVENT_ECLIST_ADDED
:
1899 case RMAP_EVENT_ECLIST_DELETED
:
1900 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ECLIST
];
1902 case RMAP_EVENT_ASLIST_ADDED
:
1903 case RMAP_EVENT_ASLIST_DELETED
:
1904 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ASPATH
];
1906 case RMAP_EVENT_LLIST_ADDED
:
1907 case RMAP_EVENT_LLIST_DELETED
:
1908 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_LCLIST
];
1910 case RMAP_EVENT_CALL_ADDED
:
1911 case RMAP_EVENT_CALL_DELETED
:
1912 case RMAP_EVENT_MATCH_ADDED
:
1913 case RMAP_EVENT_MATCH_DELETED
:
1914 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_RMAP
];
1916 case RMAP_EVENT_FILTER_ADDED
:
1917 case RMAP_EVENT_FILTER_DELETED
:
1918 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_FILTER
];
1921 * Should we actually be ignoring these?
1922 * I am not sure but at this point in time, let
1923 * us get them into this switch and we can peel
1924 * them into the appropriate place in the future
1926 case RMAP_EVENT_SET_ADDED
:
1927 case RMAP_EVENT_SET_DELETED
:
1928 case RMAP_EVENT_SET_REPLACED
:
1929 case RMAP_EVENT_MATCH_REPLACED
:
1930 case RMAP_EVENT_INDEX_ADDED
:
1931 case RMAP_EVENT_INDEX_DELETED
:
1938 static void route_map_process_dependency(struct hash_bucket
*bucket
, void *data
)
1940 struct route_map_dep_data
*dep_data
= NULL
;
1941 char *rmap_name
= NULL
;
1943 dep_data
= bucket
->data
;
1944 rmap_name
= dep_data
->rname
;
1947 zlog_debug("Notifying %s of dependency", rmap_name
);
1948 if (route_map_master
.event_hook
)
1949 (*route_map_master
.event_hook
)(rmap_name
);
1952 void route_map_upd8_dependency(route_map_event_t type
, const char *arg
,
1953 const char *rmap_name
)
1955 struct hash
*upd8_hash
= NULL
;
1957 if ((upd8_hash
= route_map_get_dep_hash(type
))) {
1958 route_map_dep_update(upd8_hash
, arg
, rmap_name
, type
);
1960 if (type
== RMAP_EVENT_CALL_ADDED
) {
1962 if (route_map_master
.add_hook
)
1963 (*route_map_master
.add_hook
)(rmap_name
);
1964 } else if (type
== RMAP_EVENT_CALL_DELETED
) {
1966 if (route_map_master
.delete_hook
)
1967 (*route_map_master
.delete_hook
)(rmap_name
);
1972 void route_map_notify_dependencies(const char *affected_name
,
1973 route_map_event_t event
)
1975 struct route_map_dep
*dep
;
1976 struct hash
*upd8_hash
;
1982 name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, affected_name
);
1984 if ((upd8_hash
= route_map_get_dep_hash(event
)) == NULL
) {
1985 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
1989 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, name
, NULL
);
1991 if (!dep
->this_hash
)
1992 dep
->this_hash
= upd8_hash
;
1995 zlog_debug("Filter %s updated", dep
->dep_name
);
1996 hash_iterate(dep
->dep_rmap_hash
, route_map_process_dependency
,
2000 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
2004 /* VTY related functions. */
2005 static void clear_route_map_helper(struct route_map
*map
)
2007 struct route_map_index
*index
;
2009 map
->applied_clear
= map
->applied
;
2010 for (index
= map
->head
; index
; index
= index
->next
)
2011 index
->applied_clear
= index
->applied
;
2014 DEFUN (rmap_clear_counters
,
2015 rmap_clear_counters_cmd
,
2016 "clear route-map counters [WORD]",
2018 "route-map information\n"
2019 "counters associated with the specified route-map\n"
2023 struct route_map
*map
;
2025 const char *name
= (argc
== 3 ) ? argv
[idx_word
]->arg
: NULL
;
2028 map
= route_map_lookup_by_name(name
);
2031 clear_route_map_helper(map
);
2033 vty_out(vty
, "%s: 'route-map %s' not found\n",
2034 frr_protonameinst
, name
);
2038 for (map
= route_map_master
.head
; map
; map
= map
->next
)
2039 clear_route_map_helper(map
);
2046 DEFUN (rmap_show_name
,
2048 "show route-map [WORD]",
2050 "route-map information\n"
2054 const char *name
= (argc
== 3) ? argv
[idx_word
]->arg
: NULL
;
2055 return vty_show_route_map(vty
, name
);
2058 DEFUN (rmap_show_unused
,
2059 rmap_show_unused_cmd
,
2060 "show route-map-unused",
2062 "unused route-map information\n")
2064 return vty_show_unused_route_map(vty
);
2071 "Debug option set for route-maps\n")
2077 DEFUN (no_debug_rmap
,
2079 "no debug route-map",
2082 "Debug option set for route-maps\n")
2089 static struct cmd_node rmap_debug_node
= {RMAP_DEBUG_NODE
, "", 1};
2091 /* Configuration write function. */
2092 static int rmap_config_write_debug(struct vty
*vty
)
2097 vty_out(vty
, "debug route-map\n");
2104 /* Common route map rules */
2106 void *route_map_rule_tag_compile(const char *arg
)
2108 unsigned long int tmp
;
2113 tmp
= strtoul(arg
, &endptr
, 0);
2114 if (arg
[0] == '\0' || *endptr
!= '\0' || errno
|| tmp
> ROUTE_TAG_MAX
)
2117 tag
= XMALLOC(MTYPE_ROUTE_MAP_COMPILED
, sizeof(*tag
));
2123 void route_map_rule_tag_free(void *rule
)
2125 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
2128 void route_map_finish(void)
2132 vector_free(route_match_vec
);
2133 route_match_vec
= NULL
;
2134 vector_free(route_set_vec
);
2135 route_set_vec
= NULL
;
2138 * All protocols are setting these to NULL
2139 * by default on shutdown( route_map_finish )
2140 * Why are we making them do this work?
2142 route_map_master
.add_hook
= NULL
;
2143 route_map_master
.delete_hook
= NULL
;
2144 route_map_master
.event_hook
= NULL
;
2146 /* cleanup route_map */
2147 while (route_map_master
.head
) {
2148 struct route_map
*map
= route_map_master
.head
;
2149 map
->to_be_processed
= false;
2150 route_map_delete(map
);
2153 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
2154 hash_free(route_map_dep_hash
[i
]);
2155 route_map_dep_hash
[i
] = NULL
;
2158 hash_free(route_map_master_hash
);
2159 route_map_master_hash
= NULL
;
2162 /* Increment the use_count counter while attaching the route map */
2163 void route_map_counter_increment(struct route_map
*map
)
2169 /* Decrement the use_count counter while detaching the route map. */
2170 void route_map_counter_decrement(struct route_map
*map
)
2173 if (map
->use_count
<= 0)
2179 /* Initialization of route map vector. */
2180 void route_map_init(void)
2184 /* Make vector for match and set. */
2185 route_match_vec
= vector_init(1);
2186 route_set_vec
= vector_init(1);
2187 route_map_master_hash
=
2188 hash_create_size(8, route_map_hash_key_make
, route_map_hash_cmp
,
2189 "Route Map Master Hash");
2191 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++)
2192 route_map_dep_hash
[i
] = hash_create_size(
2193 8, route_map_dep_hash_make_key
, route_map_dep_hash_cmp
,
2194 "Route Map Dep Hash");
2198 route_map_cli_init();
2200 /* Install route map top node. */
2201 install_node(&rmap_debug_node
, rmap_config_write_debug
);
2203 /* Install route map commands. */
2204 install_element(CONFIG_NODE
, &debug_rmap_cmd
);
2205 install_element(CONFIG_NODE
, &no_debug_rmap_cmd
);
2207 /* Install show command */
2208 install_element(ENABLE_NODE
, &rmap_clear_counters_cmd
);
2210 install_element(ENABLE_NODE
, &rmap_show_name_cmd
);
2211 install_element(ENABLE_NODE
, &rmap_show_unused_cmd
);
2213 install_element(ENABLE_NODE
, &debug_rmap_cmd
);
2214 install_element(ENABLE_NODE
, &no_debug_rmap_cmd
);