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
:
312 vty_out(vty
, "%% [%s] Can't find rule.\n",
315 zlog_warn("Can't find rule: %s", command
);
316 return CMD_WARNING_CONFIG_FAILED
;
317 case RMAP_COMPILE_ERROR
:
320 "%% [%s] Argument form is unsupported or malformed.\n",
323 zlog_warn("Argument form is unsupported or malformed: "
324 "%s %s", command
, arg
);
325 return CMD_WARNING_CONFIG_FAILED
;
326 case RMAP_COMPILE_SUCCESS
:
328 * Nothing to do here move along
336 int generic_match_delete(struct vty
*vty
, struct route_map_index
*index
,
337 const char *command
, const char *arg
,
338 route_map_event_t type
)
340 enum rmap_compile_rets ret
;
341 int retval
= CMD_SUCCESS
;
342 char *dep_name
= NULL
;
344 char *rmap_name
= NULL
;
346 if (type
!= RMAP_EVENT_MATCH_DELETED
) {
347 /* ignore the mundane, the types without any dependency */
349 if ((tmpstr
= route_map_get_match_arg(index
, command
))
352 XSTRDUP(MTYPE_ROUTE_MAP_RULE
, tmpstr
);
354 dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_RULE
, arg
);
356 rmap_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, index
->map
->name
);
359 ret
= route_map_delete_match(index
, command
, dep_name
, type
);
361 case RMAP_RULE_MISSING
:
363 vty_out(vty
, "%% [%s] Can't find rule.\n",
366 zlog_warn("Can't find rule: %s", command
);
367 retval
= CMD_WARNING_CONFIG_FAILED
;
369 case RMAP_COMPILE_ERROR
:
372 "%% [%s] Argument form is unsupported or malformed.\n",
375 zlog_warn("Argument form is unsupported or malformed: "
376 "%s %s", command
, arg
);
377 retval
= CMD_WARNING_CONFIG_FAILED
;
379 case RMAP_COMPILE_SUCCESS
:
386 XFREE(MTYPE_ROUTE_MAP_RULE
, dep_name
);
387 XFREE(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
392 int generic_set_add(struct vty
*vty
, struct route_map_index
*index
,
393 const char *command
, const char *arg
)
395 enum rmap_compile_rets ret
;
397 ret
= route_map_add_set(index
, command
, arg
);
399 case RMAP_RULE_MISSING
:
401 vty_out(vty
, "%% [%s] Can't find rule.\n", frr_protonameinst
);
403 zlog_warn("Can't find rule: %s", command
);
404 return CMD_WARNING_CONFIG_FAILED
;
405 case RMAP_COMPILE_ERROR
:
408 "%% [%s] Argument form is unsupported or malformed.\n",
411 zlog_warn("Argument form is unsupported or malformed: "
412 "%s %s", command
, arg
);
413 return CMD_WARNING_CONFIG_FAILED
;
414 case RMAP_COMPILE_SUCCESS
:
421 int generic_set_delete(struct vty
*vty
, struct route_map_index
*index
,
422 const char *command
, const char *arg
)
424 enum rmap_compile_rets ret
;
426 ret
= route_map_delete_set(index
, command
, arg
);
428 case RMAP_RULE_MISSING
:
430 vty_out(vty
, "%% [%s] Can't find rule.\n", frr_protonameinst
);
432 zlog_warn("Can't find rule: %s", command
);
433 return CMD_WARNING_CONFIG_FAILED
;
434 case RMAP_COMPILE_ERROR
:
437 "%% [%s] Argument form is unsupported or malformed.\n",
440 zlog_warn("Argument form is unsupported or malformed: "
441 "%s %s", command
, arg
);
442 return CMD_WARNING_CONFIG_FAILED
;
443 case RMAP_COMPILE_SUCCESS
:
451 /* Master list of route map. */
452 struct route_map_list route_map_master
= {NULL
, NULL
, NULL
, NULL
, NULL
};
453 struct hash
*route_map_master_hash
= NULL
;
455 static unsigned int route_map_hash_key_make(const void *p
)
457 const struct route_map
*map
= p
;
458 return string_hash_make(map
->name
);
461 static bool route_map_hash_cmp(const void *p1
, const void *p2
)
463 const struct route_map
*map1
= p1
;
464 const struct route_map
*map2
= p2
;
466 if (map1
->deleted
== map2
->deleted
) {
467 if (map1
->name
&& map2
->name
) {
468 if (!strcmp(map1
->name
, map2
->name
)) {
471 } else if (!map1
->name
&& !map2
->name
) {
479 enum route_map_upd8_type
{
484 /* all possible route-map dependency types */
485 enum route_map_dep_type
{
486 ROUTE_MAP_DEP_RMAP
= 1,
488 ROUTE_MAP_DEP_ECLIST
,
489 ROUTE_MAP_DEP_LCLIST
,
491 ROUTE_MAP_DEP_ASPATH
,
492 ROUTE_MAP_DEP_FILTER
,
496 struct route_map_dep
{
498 struct hash
*dep_rmap_hash
;
499 struct hash
*this_hash
; /* ptr to the hash structure this is part of */
502 struct route_map_dep_data
{
506 /* Count of number of sequences of this
507 * route-map that depend on the same entity.
512 /* Hashes maintaining dependency between various sublists used by route maps */
513 static struct hash
*route_map_dep_hash
[ROUTE_MAP_DEP_MAX
];
515 static unsigned int route_map_dep_hash_make_key(const void *p
);
516 static void route_map_clear_all_references(char *rmap_name
);
517 static void route_map_rule_delete(struct route_map_rule_list
*,
518 struct route_map_rule
*);
519 static bool rmap_debug
;
521 /* New route map allocation. Please note route map's name must be
523 static struct route_map
*route_map_new(const char *name
)
525 struct route_map
*new;
527 new = XCALLOC(MTYPE_ROUTE_MAP
, sizeof(struct route_map
));
528 new->name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
529 QOBJ_REG(new, route_map
);
533 /* Add new name to route_map. */
534 static struct route_map
*route_map_add(const char *name
)
536 struct route_map
*map
;
537 struct route_map_list
*list
;
539 map
= route_map_new(name
);
540 list
= &route_map_master
;
542 /* Add map to the hash */
543 hash_get(route_map_master_hash
, map
, hash_alloc_intern
);
545 /* Add new entry to the head of the list to match how it is added in the
546 * hash table. This is to ensure that if the same route-map has been
547 * created more than once and then marked for deletion (which can happen
548 * if prior deletions haven't completed as BGP hasn't yet done the
549 * route-map processing), the order of the entities is the same in both
550 * the list and the hash table. Otherwise, since there is nothing to
551 * distinguish between the two entries, the wrong entry could get freed.
552 * TODO: This needs to be re-examined to handle it better - e.g., revive
553 * a deleted entry if the route-map is created again.
556 map
->next
= list
->head
;
558 list
->head
->prev
= map
;
564 if (route_map_master
.add_hook
) {
565 (*route_map_master
.add_hook
)(name
);
566 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_ADDED
);
570 zlog_debug("Add route-map %s", name
);
574 /* this is supposed to be called post processing by
575 * the delete hook function. Don't invoke delete_hook
576 * again in this routine.
578 static void route_map_free_map(struct route_map
*map
)
580 struct route_map_list
*list
;
581 struct route_map_index
*index
;
586 while ((index
= map
->head
) != NULL
)
587 route_map_index_delete(index
, 0);
590 zlog_debug("Deleting route-map %s", map
->name
);
592 list
= &route_map_master
;
597 map
->next
->prev
= map
->prev
;
599 list
->tail
= map
->prev
;
602 map
->prev
->next
= map
->next
;
604 list
->head
= map
->next
;
606 hash_release(route_map_master_hash
, map
);
607 XFREE(MTYPE_ROUTE_MAP_NAME
, map
->name
);
608 XFREE(MTYPE_ROUTE_MAP
, map
);
611 /* Route map delete from list. */
612 void route_map_delete(struct route_map
*map
)
614 struct route_map_index
*index
;
617 while ((index
= map
->head
) != NULL
)
618 route_map_index_delete(index
, 0);
623 /* Clear all dependencies */
624 route_map_clear_all_references(name
);
626 /* Execute deletion hook. */
627 if (route_map_master
.delete_hook
) {
628 (*route_map_master
.delete_hook
)(name
);
629 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_DELETED
);
632 if (!map
->to_be_processed
) {
633 route_map_free_map(map
);
637 /* Lookup route map by route map name string. */
638 struct route_map
*route_map_lookup_by_name(const char *name
)
640 struct route_map
*map
;
641 struct route_map tmp_map
;
646 // map.deleted is 0 via memset
647 memset(&tmp_map
, 0, sizeof(struct route_map
));
648 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
649 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
650 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
654 /* Simple helper to warn if route-map does not exist. */
655 struct route_map
*route_map_lookup_warn_noexist(struct vty
*vty
, const char *name
)
657 struct route_map
*route_map
= route_map_lookup_by_name(name
);
660 if (vty_shell_serv(vty
))
661 vty_out(vty
, "The route-map '%s' does not exist.\n", name
);
666 int route_map_mark_updated(const char *name
)
668 struct route_map
*map
;
670 struct route_map tmp_map
;
675 map
= route_map_lookup_by_name(name
);
677 /* If we did not find the routemap with deleted=false try again
681 memset(&tmp_map
, 0, sizeof(struct route_map
));
682 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
683 tmp_map
.deleted
= true;
684 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
685 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
689 map
->to_be_processed
= true;
696 static int route_map_clear_updated(struct route_map
*map
)
701 map
->to_be_processed
= false;
703 route_map_free_map(map
);
709 /* Lookup route map. If there isn't route map create one and return
711 struct route_map
*route_map_get(const char *name
)
713 struct route_map
*map
;
715 map
= route_map_lookup_by_name(name
);
717 map
= route_map_add(name
);
722 void route_map_walk_update_list(void (*route_map_update_fn
)(char *name
))
724 struct route_map
*node
;
725 struct route_map
*nnode
= NULL
;
727 for (node
= route_map_master
.head
; node
; node
= nnode
) {
728 if (node
->to_be_processed
) {
729 /* DD: Should we add any thread yield code here */
730 route_map_update_fn(node
->name
);
732 route_map_clear_updated(node
);
738 /* Return route map's type string. */
739 static const char *route_map_type_str(enum route_map_type type
)
756 static const char *route_map_cmd_result_str(enum route_map_cmd_result_t res
)
774 static const char *route_map_result_str(route_map_result_t res
)
779 case RMAP_PERMITMATCH
:
787 static void vty_show_route_map_entry(struct vty
*vty
, struct route_map
*map
)
789 struct route_map_index
*index
;
790 struct route_map_rule
*rule
;
792 vty_out(vty
, "route-map: %s Invoked: %" PRIu64
"\n",
793 map
->name
, map
->applied
- map
->applied_clear
);
795 for (index
= map
->head
; index
; index
= index
->next
) {
796 vty_out(vty
, " %s, sequence %d Invoked %" PRIu64
"\n",
797 route_map_type_str(index
->type
), index
->pref
,
798 index
->applied
- index
->applied_clear
);
801 if (index
->description
)
802 vty_out(vty
, " Description:\n %s\n",
806 vty_out(vty
, " Match clauses:\n");
807 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
808 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
811 vty_out(vty
, " Set clauses:\n");
812 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
813 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
817 vty_out(vty
, " Call clause:\n");
819 vty_out(vty
, " Call %s\n", index
->nextrm
);
822 vty_out(vty
, " Action:\n");
823 if (index
->exitpolicy
== RMAP_GOTO
)
824 vty_out(vty
, " Goto %d\n", index
->nextpref
);
825 else if (index
->exitpolicy
== RMAP_NEXT
)
826 vty_out(vty
, " Continue to next entry\n");
827 else if (index
->exitpolicy
== RMAP_EXIT
)
828 vty_out(vty
, " Exit routemap\n");
832 static int sort_route_map(const void **map1
, const void **map2
)
834 const struct route_map
*m1
= *map1
;
835 const struct route_map
*m2
= *map2
;
837 return strcmp(m1
->name
, m2
->name
);
840 static int vty_show_route_map(struct vty
*vty
, const char *name
)
842 struct route_map
*map
;
844 vty_out(vty
, "%s:\n", frr_protonameinst
);
847 map
= route_map_lookup_by_name(name
);
850 vty_show_route_map_entry(vty
, map
);
853 vty_out(vty
, "%s: 'route-map %s' not found\n",
854 frr_protonameinst
, name
);
859 struct list
*maplist
= list_new();
862 for (map
= route_map_master
.head
; map
; map
= map
->next
)
863 listnode_add(maplist
, map
);
865 list_sort(maplist
, sort_route_map
);
867 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
868 vty_show_route_map_entry(vty
, map
);
870 list_delete(&maplist
);
875 /* Unused route map details */
876 static int vty_show_unused_route_map(struct vty
*vty
)
878 struct list
*maplist
= list_new();
880 struct route_map
*map
;
882 for (map
= route_map_master
.head
; map
; map
= map
->next
) {
883 /* If use_count is zero, No protocol is using this routemap.
884 * so adding to the list.
887 listnode_add(maplist
, map
);
890 if (maplist
->count
> 0) {
891 vty_out(vty
, "\n%s:\n", frr_protonameinst
);
892 list_sort(maplist
, sort_route_map
);
894 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
895 vty_show_route_map_entry(vty
, map
);
897 vty_out(vty
, "\n%s: None\n", frr_protonameinst
);
900 list_delete(&maplist
);
904 /* New route map allocation. Please note route map's name must be
906 static struct route_map_index
*route_map_index_new(void)
908 struct route_map_index
*new;
910 new = XCALLOC(MTYPE_ROUTE_MAP_INDEX
, sizeof(struct route_map_index
));
911 new->exitpolicy
= RMAP_EXIT
; /* Default to Cisco-style */
912 TAILQ_INIT(&new->rhclist
);
913 QOBJ_REG(new, route_map_index
);
917 /* Free route map index. */
918 void route_map_index_delete(struct route_map_index
*index
, int notify
)
920 struct route_map_rule
*rule
;
925 zlog_debug("Deleting route-map %s sequence %d",
926 index
->map
->name
, index
->pref
);
928 /* Free route map northbound hook contexts. */
929 while (!TAILQ_EMPTY(&index
->rhclist
))
930 routemap_hook_context_free(TAILQ_FIRST(&index
->rhclist
));
932 /* Free route match. */
933 while ((rule
= index
->match_list
.head
) != NULL
)
934 route_map_rule_delete(&index
->match_list
, rule
);
936 /* Free route set. */
937 while ((rule
= index
->set_list
.head
) != NULL
)
938 route_map_rule_delete(&index
->set_list
, rule
);
940 /* Remove index from route map list. */
942 index
->next
->prev
= index
->prev
;
944 index
->map
->tail
= index
->prev
;
947 index
->prev
->next
= index
->next
;
949 index
->map
->head
= index
->next
;
951 /* Free 'char *nextrm' if not NULL */
952 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
954 /* Execute event hook. */
955 if (route_map_master
.event_hook
&& notify
) {
956 (*route_map_master
.event_hook
)(index
->map
->name
);
957 route_map_notify_dependencies(index
->map
->name
,
958 RMAP_EVENT_CALL_ADDED
);
960 XFREE(MTYPE_ROUTE_MAP_INDEX
, index
);
963 /* Lookup index from route map. */
964 static struct route_map_index
*route_map_index_lookup(struct route_map
*map
,
965 enum route_map_type type
,
968 struct route_map_index
*index
;
970 for (index
= map
->head
; index
; index
= index
->next
)
971 if ((index
->type
== type
|| type
== RMAP_ANY
)
972 && index
->pref
== pref
)
977 /* Add new index to route map. */
978 static struct route_map_index
*
979 route_map_index_add(struct route_map
*map
, enum route_map_type type
, int pref
)
981 struct route_map_index
*index
;
982 struct route_map_index
*point
;
984 /* Allocate new route map inex. */
985 index
= route_map_index_new();
990 /* Compare preference. */
991 for (point
= map
->head
; point
; point
= point
->next
)
992 if (point
->pref
>= pref
)
995 if (map
->head
== NULL
) {
996 map
->head
= map
->tail
= index
;
997 } else if (point
== NULL
) {
998 index
->prev
= map
->tail
;
999 map
->tail
->next
= index
;
1001 } else if (point
== map
->head
) {
1002 index
->next
= map
->head
;
1003 map
->head
->prev
= index
;
1006 index
->next
= point
;
1007 index
->prev
= point
->prev
;
1009 point
->prev
->next
= index
;
1010 point
->prev
= index
;
1013 /* Execute event hook. */
1014 if (route_map_master
.event_hook
) {
1015 (*route_map_master
.event_hook
)(map
->name
);
1016 route_map_notify_dependencies(map
->name
, RMAP_EVENT_CALL_ADDED
);
1020 zlog_debug("Route-map %s add sequence %d, type: %s",
1021 map
->name
, pref
, route_map_type_str(type
));
1026 /* Get route map index. */
1027 struct route_map_index
*
1028 route_map_index_get(struct route_map
*map
, enum route_map_type type
, int pref
)
1030 struct route_map_index
*index
;
1032 index
= route_map_index_lookup(map
, RMAP_ANY
, pref
);
1033 if (index
&& index
->type
!= type
) {
1034 /* Delete index from route map. */
1035 route_map_index_delete(index
, 1);
1039 index
= route_map_index_add(map
, type
, pref
);
1043 /* New route map rule */
1044 static struct route_map_rule
*route_map_rule_new(void)
1046 struct route_map_rule
*new;
1048 new = XCALLOC(MTYPE_ROUTE_MAP_RULE
, sizeof(struct route_map_rule
));
1052 /* Install rule command to the match list. */
1053 void route_map_install_match(const struct route_map_rule_cmd
*cmd
)
1055 vector_set(route_match_vec
, (void *)cmd
);
1058 /* Install rule command to the set list. */
1059 void route_map_install_set(const struct route_map_rule_cmd
*cmd
)
1061 vector_set(route_set_vec
, (void *)cmd
);
1064 /* Lookup rule command from match list. */
1065 static const struct route_map_rule_cmd
*route_map_lookup_match(const char *name
)
1068 const struct route_map_rule_cmd
*rule
;
1070 for (i
= 0; i
< vector_active(route_match_vec
); i
++)
1071 if ((rule
= vector_slot(route_match_vec
, i
)) != NULL
)
1072 if (strcmp(rule
->str
, name
) == 0)
1077 /* Lookup rule command from set list. */
1078 static const struct route_map_rule_cmd
*route_map_lookup_set(const char *name
)
1081 const struct route_map_rule_cmd
*rule
;
1083 for (i
= 0; i
< vector_active(route_set_vec
); i
++)
1084 if ((rule
= vector_slot(route_set_vec
, i
)) != NULL
)
1085 if (strcmp(rule
->str
, name
) == 0)
1090 /* Add match and set rule to rule list. */
1091 static void route_map_rule_add(struct route_map_rule_list
*list
,
1092 struct route_map_rule
*rule
)
1095 rule
->prev
= list
->tail
;
1097 list
->tail
->next
= rule
;
1103 /* Delete rule from rule list. */
1104 static void route_map_rule_delete(struct route_map_rule_list
*list
,
1105 struct route_map_rule
*rule
)
1107 if (rule
->cmd
->func_free
)
1108 (*rule
->cmd
->func_free
)(rule
->value
);
1110 XFREE(MTYPE_ROUTE_MAP_RULE_STR
, rule
->rule_str
);
1113 rule
->next
->prev
= rule
->prev
;
1115 list
->tail
= rule
->prev
;
1117 rule
->prev
->next
= rule
->next
;
1119 list
->head
= rule
->next
;
1121 XFREE(MTYPE_ROUTE_MAP_RULE
, rule
);
1124 /* strcmp wrapper function which don't crush even argument is NULL. */
1125 static int rulecmp(const char *dst
, const char *src
)
1136 return strcmp(dst
, src
);
1141 /* Use this to return the already specified argument for this match. This is
1142 * useful to get the specified argument with a route map match rule when the
1143 * rule is being deleted and the argument is not provided.
1145 const char *route_map_get_match_arg(struct route_map_index
*index
,
1146 const char *match_name
)
1148 struct route_map_rule
*rule
;
1149 const struct route_map_rule_cmd
*cmd
;
1151 /* First lookup rule for add match statement. */
1152 cmd
= route_map_lookup_match(match_name
);
1156 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1157 if (rule
->cmd
== cmd
&& rule
->rule_str
!= NULL
)
1158 return (rule
->rule_str
);
1163 static route_map_event_t
get_route_map_delete_event(route_map_event_t type
)
1166 case RMAP_EVENT_CALL_ADDED
:
1167 return RMAP_EVENT_CALL_DELETED
;
1168 case RMAP_EVENT_PLIST_ADDED
:
1169 return RMAP_EVENT_PLIST_DELETED
;
1170 case RMAP_EVENT_CLIST_ADDED
:
1171 return RMAP_EVENT_CLIST_DELETED
;
1172 case RMAP_EVENT_ECLIST_ADDED
:
1173 return RMAP_EVENT_ECLIST_DELETED
;
1174 case RMAP_EVENT_LLIST_ADDED
:
1175 return RMAP_EVENT_LLIST_DELETED
;
1176 case RMAP_EVENT_ASLIST_ADDED
:
1177 return RMAP_EVENT_ASLIST_DELETED
;
1178 case RMAP_EVENT_FILTER_ADDED
:
1179 return RMAP_EVENT_FILTER_DELETED
;
1180 case RMAP_EVENT_SET_ADDED
:
1181 case RMAP_EVENT_SET_DELETED
:
1182 case RMAP_EVENT_SET_REPLACED
:
1183 case RMAP_EVENT_MATCH_ADDED
:
1184 case RMAP_EVENT_MATCH_DELETED
:
1185 case RMAP_EVENT_MATCH_REPLACED
:
1186 case RMAP_EVENT_INDEX_ADDED
:
1187 case RMAP_EVENT_INDEX_DELETED
:
1188 case RMAP_EVENT_CALL_DELETED
:
1189 case RMAP_EVENT_PLIST_DELETED
:
1190 case RMAP_EVENT_CLIST_DELETED
:
1191 case RMAP_EVENT_ECLIST_DELETED
:
1192 case RMAP_EVENT_LLIST_DELETED
:
1193 case RMAP_EVENT_ASLIST_DELETED
:
1194 case RMAP_EVENT_FILTER_DELETED
:
1195 /* This function returns the appropriate 'deleted' event type
1196 * for every 'added' event type passed to this function.
1197 * This is done only for named entities used in the
1198 * route-map match commands.
1199 * This function is not to be invoked for any of the other event
1207 * Return to make c happy but if we get here something has gone
1208 * terribly terribly wrong, so yes this return makes no sense.
1210 return RMAP_EVENT_CALL_ADDED
;
1213 /* Add match statement to route map. */
1214 enum rmap_compile_rets
route_map_add_match(struct route_map_index
*index
,
1215 const char *match_name
,
1216 const char *match_arg
,
1217 route_map_event_t type
)
1219 struct route_map_rule
*rule
;
1220 struct route_map_rule
*next
;
1221 const struct route_map_rule_cmd
*cmd
;
1223 int8_t delete_rmap_event_type
= 0;
1224 const char *rule_key
;
1226 /* First lookup rule for add match statement. */
1227 cmd
= route_map_lookup_match(match_name
);
1229 return RMAP_RULE_MISSING
;
1231 /* Next call compile function for this match statement. */
1232 if (cmd
->func_compile
) {
1233 compile
= (*cmd
->func_compile
)(match_arg
);
1234 if (compile
== NULL
)
1235 return RMAP_COMPILE_ERROR
;
1238 /* use the compiled results if applicable */
1239 if (compile
&& cmd
->func_get_rmap_rule_key
)
1240 rule_key
= (*cmd
->func_get_rmap_rule_key
)
1243 rule_key
= match_arg
;
1245 /* If argument is completely same ignore it. */
1246 for (rule
= index
->match_list
.head
; rule
; rule
= next
) {
1248 if (rule
->cmd
== cmd
) {
1249 /* If the configured route-map match rule is exactly
1250 * the same as the existing configuration then,
1251 * ignore the duplicate configuration.
1253 if (strcmp(match_arg
, rule
->rule_str
) == 0) {
1255 (*cmd
->func_free
)(compile
);
1257 return RMAP_COMPILE_SUCCESS
;
1260 /* Remove the dependency of the route-map on the rule
1261 * that is being replaced.
1263 if (type
>= RMAP_EVENT_CALL_ADDED
) {
1264 delete_rmap_event_type
=
1265 get_route_map_delete_event(type
);
1266 route_map_upd8_dependency(
1267 delete_rmap_event_type
,
1272 route_map_rule_delete(&index
->match_list
, rule
);
1276 /* Add new route map match rule. */
1277 rule
= route_map_rule_new();
1279 rule
->value
= compile
;
1281 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, match_arg
);
1283 rule
->rule_str
= NULL
;
1285 /* Add new route match rule to linked list. */
1286 route_map_rule_add(&index
->match_list
, rule
);
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(index
->map
->name
,
1292 RMAP_EVENT_CALL_ADDED
);
1294 if (type
!= RMAP_EVENT_MATCH_ADDED
)
1295 route_map_upd8_dependency(type
, rule_key
, index
->map
->name
);
1297 return RMAP_COMPILE_SUCCESS
;
1300 /* Delete specified route match rule. */
1301 enum rmap_compile_rets
route_map_delete_match(struct route_map_index
*index
,
1302 const char *match_name
,
1303 const char *match_arg
,
1304 route_map_event_t type
)
1306 struct route_map_rule
*rule
;
1307 const struct route_map_rule_cmd
*cmd
;
1308 const char *rule_key
;
1310 cmd
= route_map_lookup_match(match_name
);
1312 return RMAP_RULE_MISSING
;
1314 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1315 if (rule
->cmd
== cmd
&& (rulecmp(rule
->rule_str
, match_arg
) == 0
1316 || match_arg
== NULL
)) {
1317 /* Execute event hook. */
1318 if (route_map_master
.event_hook
) {
1319 (*route_map_master
.event_hook
)(index
->map
->name
);
1320 route_map_notify_dependencies(
1322 RMAP_EVENT_CALL_ADDED
);
1324 if (cmd
->func_get_rmap_rule_key
)
1325 rule_key
= (*cmd
->func_get_rmap_rule_key
)
1328 rule_key
= match_arg
;
1330 if (type
!= RMAP_EVENT_MATCH_DELETED
&& rule_key
)
1331 route_map_upd8_dependency(type
, rule_key
,
1334 route_map_rule_delete(&index
->match_list
, rule
);
1335 return RMAP_COMPILE_SUCCESS
;
1337 /* Can't find matched rule. */
1338 return RMAP_RULE_MISSING
;
1341 /* Add route-map set statement to the route map. */
1342 enum rmap_compile_rets
route_map_add_set(struct route_map_index
*index
,
1343 const char *set_name
,
1344 const char *set_arg
)
1346 struct route_map_rule
*rule
;
1347 struct route_map_rule
*next
;
1348 const struct route_map_rule_cmd
*cmd
;
1351 cmd
= route_map_lookup_set(set_name
);
1353 return RMAP_RULE_MISSING
;
1355 /* Next call compile function for this match statement. */
1356 if (cmd
->func_compile
) {
1357 compile
= (*cmd
->func_compile
)(set_arg
);
1358 if (compile
== NULL
)
1359 return RMAP_COMPILE_ERROR
;
1363 /* Add by WJL. if old set command of same kind exist, delete it first
1364 to ensure only one set command of same kind exist under a
1366 for (rule
= index
->set_list
.head
; rule
; rule
= next
) {
1368 if (rule
->cmd
== cmd
)
1369 route_map_rule_delete(&index
->set_list
, rule
);
1372 /* Add new route map match rule. */
1373 rule
= route_map_rule_new();
1375 rule
->value
= compile
;
1377 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, set_arg
);
1379 rule
->rule_str
= NULL
;
1381 /* Add new route match rule to linked list. */
1382 route_map_rule_add(&index
->set_list
, rule
);
1384 /* Execute event hook. */
1385 if (route_map_master
.event_hook
) {
1386 (*route_map_master
.event_hook
)(index
->map
->name
);
1387 route_map_notify_dependencies(index
->map
->name
,
1388 RMAP_EVENT_CALL_ADDED
);
1390 return RMAP_COMPILE_SUCCESS
;
1393 /* Delete route map set rule. */
1394 enum rmap_compile_rets
route_map_delete_set(struct route_map_index
*index
,
1395 const char *set_name
,
1396 const char *set_arg
)
1398 struct route_map_rule
*rule
;
1399 const struct route_map_rule_cmd
*cmd
;
1401 cmd
= route_map_lookup_set(set_name
);
1403 return RMAP_RULE_MISSING
;
1405 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
1406 if ((rule
->cmd
== cmd
) && (rulecmp(rule
->rule_str
, set_arg
) == 0
1407 || set_arg
== NULL
)) {
1408 route_map_rule_delete(&index
->set_list
, rule
);
1409 /* Execute event hook. */
1410 if (route_map_master
.event_hook
) {
1411 (*route_map_master
.event_hook
)(index
->map
->name
);
1412 route_map_notify_dependencies(
1414 RMAP_EVENT_CALL_ADDED
);
1416 return RMAP_COMPILE_SUCCESS
;
1418 /* Can't find matched rule. */
1419 return RMAP_RULE_MISSING
;
1422 static enum route_map_cmd_result_t
1423 route_map_apply_match(struct route_map_rule_list
*match_list
,
1424 const struct prefix
*prefix
, route_map_object_t type
,
1427 enum route_map_cmd_result_t ret
= RMAP_NOMATCH
;
1428 struct route_map_rule
*match
;
1429 bool is_matched
= false;
1432 /* Check all match rule and if there is no match rule, go to the
1434 if (!match_list
->head
)
1437 for (match
= match_list
->head
; match
; match
= match
->next
) {
1439 * Try each match statement. If any match does not
1440 * return RMAP_MATCH or RMAP_NOOP, return.
1441 * Otherwise continue on to next match statement.
1442 * All match statements must MATCH for
1443 * end-result to be a match.
1444 * (Exception:If match stmts result in a mix of
1445 * MATCH/NOOP, then also end-result is a match)
1446 * If all result in NOOP, end-result is NOOP.
1448 ret
= (*match
->cmd
->func_apply
)(match
->value
, prefix
,
1452 * If the consolidated result of func_apply is:
1453 * -----------------------------------------------
1454 * | MATCH | NOMATCH | NOOP | Final Result |
1455 * ------------------------------------------------
1456 * | yes | yes | yes | NOMATCH |
1457 * | no | no | yes | NOOP |
1458 * | yes | no | yes | MATCH |
1459 * | no | yes | yes | NOMATCH |
1460 * |-----------------------------------------------
1462 * Traditionally, all rules within route-map
1463 * should match for it to MATCH.
1464 * If there are noops within the route-map rules,
1465 * it follows the above matrix.
1467 * Eg: route-map rm1 permit 10
1472 * route-map rm1 permit 20
1500 /* Apply route map's each index to the object.
1502 The matrix for a route-map looks like this:
1503 (note, this includes the description for the "NEXT"
1504 and "GOTO" frobs now
1506 | Match | No Match | No op
1507 |-----------|--------------|-------
1508 permit | action | cont | cont.
1509 | | default:deny | default:permit
1510 -------------------+-----------------------
1511 | deny | cont | cont.
1512 deny | | default:deny | default:permit
1513 |-----------|--------------|--------
1516 -Apply Set statements, accept route
1517 -If Call statement is present jump to the specified route-map, if it
1518 denies the route we finish.
1519 -If NEXT is specified, goto NEXT statement
1520 -If GOTO is specified, goto the first clause where pref > nextpref
1521 -If nothing is specified, do as Cisco and finish
1523 -Route is denied by route-map.
1527 If we get no matches after we've processed all updates, then the route
1530 Some notes on the new "CALL", "NEXT" and "GOTO"
1531 call WORD - If this clause is matched, then the set statements
1532 are executed and then we jump to route-map 'WORD'. If
1533 this route-map denies the route, we finish, in other
1535 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
1536 on-match next - If this clause is matched, then the set statements
1537 are executed and then we drop through to the next clause
1538 on-match goto n - If this clause is matched, then the set statments
1539 are executed and then we goto the nth clause, or the
1540 first clause greater than this. In order to ensure
1541 route-maps *always* exit, you cannot jump backwards.
1544 We need to make sure our route-map processing matches the above
1546 route_map_result_t
route_map_apply(struct route_map
*map
,
1547 const struct prefix
*prefix
,
1548 route_map_object_t type
, void *object
)
1550 static int recursion
= 0;
1551 enum route_map_cmd_result_t match_ret
= RMAP_NOMATCH
;
1552 route_map_result_t ret
= RMAP_PERMITMATCH
;
1553 struct route_map_index
*index
;
1554 struct route_map_rule
*set
;
1555 char buf
[PREFIX_STRLEN
];
1557 if (recursion
> RMAP_RECURSION_LIMIT
) {
1559 EC_LIB_RMAP_RECURSION_LIMIT
,
1560 "route-map recursion limit (%d) reached, discarding route",
1561 RMAP_RECURSION_LIMIT
);
1563 return RMAP_DENYMATCH
;
1566 if (map
== NULL
|| map
->head
== NULL
) {
1567 ret
= RMAP_DENYMATCH
;
1568 goto route_map_apply_end
;
1572 for (index
= map
->head
; index
; index
= index
->next
) {
1573 /* Apply this index. */
1575 match_ret
= route_map_apply_match(&index
->match_list
, prefix
,
1579 zlog_debug("Route-map: %s, sequence: %d, prefix: %s, result: %s",
1580 map
->name
, index
->pref
,
1581 prefix2str(prefix
, buf
, sizeof(buf
)),
1582 route_map_cmd_result_str(match_ret
));
1585 /* Now we apply the matrix from above */
1586 if (match_ret
== RMAP_NOOP
)
1588 * Do not change the return value. Retain the previous
1589 * return value. Previous values can be:
1590 * 1)permitmatch (if a nomatch was never
1591 * seen before in this route-map.)
1592 * 2)denymatch (if a nomatch was seen earlier in one
1593 * of the previous sequences)
1597 * 'cont' from matrix - continue to next route-map
1601 else if (match_ret
== RMAP_NOMATCH
) {
1604 * The return value is now changed to denymatch.
1605 * So from here on out, even if we see more noops,
1606 * we retain this return value and return this
1607 * eventually if there are no matches.
1609 ret
= RMAP_DENYMATCH
;
1612 * 'cont' from matrix - continue to next route-map
1616 } else if (match_ret
== RMAP_MATCH
) {
1617 if (index
->type
== RMAP_PERMIT
)
1620 /* Match succeeded, rmap is of type permit */
1621 ret
= RMAP_PERMITMATCH
;
1623 /* permit+match must execute sets */
1624 for (set
= index
->set_list
.head
; set
;
1627 * set cmds return RMAP_OKAY or
1628 * RMAP_ERROR. We do not care if
1629 * set succeeded or not. So, ignore
1632 (void) (*set
->cmd
->func_apply
)(
1633 set
->value
, prefix
, type
,
1636 /* Call another route-map if available */
1637 if (index
->nextrm
) {
1638 struct route_map
*nextrm
=
1639 route_map_lookup_by_name(
1642 if (nextrm
) /* Target route-map found,
1646 ret
= route_map_apply(
1647 nextrm
, prefix
, type
,
1652 /* If nextrm returned 'deny', finish. */
1653 if (ret
== RMAP_DENYMATCH
)
1654 goto route_map_apply_end
;
1657 switch (index
->exitpolicy
) {
1659 goto route_map_apply_end
;
1663 /* Find the next clause to jump to */
1664 struct route_map_index
*next
=
1666 int nextpref
= index
->nextpref
;
1668 while (next
&& next
->pref
< nextpref
) {
1673 /* No clauses match! */
1674 goto route_map_apply_end
;
1678 } else if (index
->type
== RMAP_DENY
)
1681 ret
= RMAP_DENYMATCH
;
1682 goto route_map_apply_end
;
1687 route_map_apply_end
:
1689 zlog_debug("Route-map: %s, prefix: %s, result: %s",
1690 (map
? map
->name
: "null"),
1691 prefix2str(prefix
, buf
, sizeof(buf
)),
1692 route_map_result_str(ret
));
1698 void route_map_add_hook(void (*func
)(const char *))
1700 route_map_master
.add_hook
= func
;
1703 void route_map_delete_hook(void (*func
)(const char *))
1705 route_map_master
.delete_hook
= func
;
1708 void route_map_event_hook(void (*func
)(const char *name
))
1710 route_map_master
.event_hook
= func
;
1713 /* Routines for route map dependency lists and dependency processing */
1714 static bool route_map_rmap_hash_cmp(const void *p1
, const void *p2
)
1716 return strcmp(((const struct route_map_dep_data
*)p1
)->rname
,
1717 ((const struct route_map_dep_data
*)p2
)->rname
)
1721 static bool route_map_dep_hash_cmp(const void *p1
, const void *p2
)
1724 return (strcmp(((const struct route_map_dep
*)p1
)->dep_name
,
1729 static void route_map_clear_reference(struct hash_bucket
*bucket
, void *arg
)
1731 struct route_map_dep
*dep
= bucket
->data
;
1732 struct route_map_dep_data
*dep_data
= NULL
, tmp_dep_data
;
1735 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
1736 tmp_dep_data
.rname
= arg
;
1737 dep_data
= hash_release(dep
->dep_rmap_hash
,
1740 XFREE(MTYPE_ROUTE_MAP_NAME
, dep_data
->rname
);
1741 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, dep_data
);
1743 if (!dep
->dep_rmap_hash
->count
) {
1744 dep
= hash_release(dep
->this_hash
,
1745 (void *)dep
->dep_name
);
1746 hash_free(dep
->dep_rmap_hash
);
1747 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
1748 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
1753 static void route_map_clear_all_references(char *rmap_name
)
1757 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
1758 hash_iterate(route_map_dep_hash
[i
], route_map_clear_reference
,
1763 static unsigned int route_map_dep_data_hash_make_key(const void *p
)
1765 const struct route_map_dep_data
*dep_data
= p
;
1767 return string_hash_make(dep_data
->rname
);
1770 static void *route_map_dep_hash_alloc(void *p
)
1772 char *dep_name
= (char *)p
;
1773 struct route_map_dep
*dep_entry
;
1775 dep_entry
= XCALLOC(MTYPE_ROUTE_MAP_DEP
, sizeof(struct route_map_dep
));
1776 dep_entry
->dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1777 dep_entry
->dep_rmap_hash
=
1778 hash_create_size(8, route_map_dep_data_hash_make_key
,
1779 route_map_rmap_hash_cmp
, "Route Map Dep Hash");
1780 dep_entry
->this_hash
= NULL
;
1785 static void *route_map_name_hash_alloc(void *p
)
1787 struct route_map_dep_data
*dep_data
= NULL
, *tmp_dep_data
= NULL
;
1789 dep_data
= XCALLOC(MTYPE_ROUTE_MAP_DEP_DATA
,
1790 sizeof(struct route_map_dep_data
));
1792 dep_data
->rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, tmp_dep_data
->rname
);
1796 static unsigned int route_map_dep_hash_make_key(const void *p
)
1798 return (string_hash_make((char *)p
));
1801 static void route_map_print_dependency(struct hash_bucket
*bucket
, void *data
)
1803 struct route_map_dep_data
*dep_data
= bucket
->data
;
1804 char *rmap_name
= dep_data
->rname
;
1805 char *dep_name
= data
;
1807 zlog_debug("%s: Dependency for %s: %s", __FUNCTION__
, dep_name
,
1811 static int route_map_dep_update(struct hash
*dephash
, const char *dep_name
,
1812 const char *rmap_name
, route_map_event_t type
)
1814 struct route_map_dep
*dep
= NULL
;
1815 char *dname
, *rname
;
1817 struct route_map_dep_data
*dep_data
= NULL
, *ret_dep_data
= NULL
;
1818 struct route_map_dep_data tmp_dep_data
;
1820 dname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1821 rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
1824 case RMAP_EVENT_PLIST_ADDED
:
1825 case RMAP_EVENT_CLIST_ADDED
:
1826 case RMAP_EVENT_ECLIST_ADDED
:
1827 case RMAP_EVENT_ASLIST_ADDED
:
1828 case RMAP_EVENT_LLIST_ADDED
:
1829 case RMAP_EVENT_CALL_ADDED
:
1830 case RMAP_EVENT_FILTER_ADDED
:
1832 zlog_debug("Adding dependency for filter %s in route-map %s",
1833 dep_name
, rmap_name
);
1834 dep
= (struct route_map_dep
*)hash_get(
1835 dephash
, dname
, route_map_dep_hash_alloc
);
1841 if (!dep
->this_hash
)
1842 dep
->this_hash
= dephash
;
1844 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
1845 tmp_dep_data
.rname
= rname
;
1846 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
1848 dep_data
= hash_get(dep
->dep_rmap_hash
, &tmp_dep_data
,
1849 route_map_name_hash_alloc
);
1853 case RMAP_EVENT_PLIST_DELETED
:
1854 case RMAP_EVENT_CLIST_DELETED
:
1855 case RMAP_EVENT_ECLIST_DELETED
:
1856 case RMAP_EVENT_ASLIST_DELETED
:
1857 case RMAP_EVENT_LLIST_DELETED
:
1858 case RMAP_EVENT_CALL_DELETED
:
1859 case RMAP_EVENT_FILTER_DELETED
:
1861 zlog_debug("Deleting dependency for filter %s in route-map %s",
1862 dep_name
, rmap_name
);
1863 dep
= (struct route_map_dep
*)hash_get(dephash
, dname
, NULL
);
1868 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
1869 tmp_dep_data
.rname
= rname
;
1870 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
1873 if (!dep_data
->refcnt
) {
1874 ret_dep_data
= hash_release(dep
->dep_rmap_hash
,
1877 XFREE(MTYPE_ROUTE_MAP_NAME
,
1878 ret_dep_data
->rname
);
1879 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, ret_dep_data
);
1883 if (!dep
->dep_rmap_hash
->count
) {
1884 dep
= hash_release(dephash
, dname
);
1885 hash_free(dep
->dep_rmap_hash
);
1886 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
1887 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
1890 case RMAP_EVENT_SET_ADDED
:
1891 case RMAP_EVENT_SET_DELETED
:
1892 case RMAP_EVENT_SET_REPLACED
:
1893 case RMAP_EVENT_MATCH_ADDED
:
1894 case RMAP_EVENT_MATCH_DELETED
:
1895 case RMAP_EVENT_MATCH_REPLACED
:
1896 case RMAP_EVENT_INDEX_ADDED
:
1897 case RMAP_EVENT_INDEX_DELETED
:
1903 hash_iterate(dep
->dep_rmap_hash
,
1904 route_map_print_dependency
, dname
);
1908 XFREE(MTYPE_ROUTE_MAP_NAME
, rname
);
1909 XFREE(MTYPE_ROUTE_MAP_NAME
, dname
);
1913 static struct hash
*route_map_get_dep_hash(route_map_event_t event
)
1915 struct hash
*upd8_hash
= NULL
;
1918 case RMAP_EVENT_PLIST_ADDED
:
1919 case RMAP_EVENT_PLIST_DELETED
:
1920 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_PLIST
];
1922 case RMAP_EVENT_CLIST_ADDED
:
1923 case RMAP_EVENT_CLIST_DELETED
:
1924 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_CLIST
];
1926 case RMAP_EVENT_ECLIST_ADDED
:
1927 case RMAP_EVENT_ECLIST_DELETED
:
1928 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ECLIST
];
1930 case RMAP_EVENT_ASLIST_ADDED
:
1931 case RMAP_EVENT_ASLIST_DELETED
:
1932 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ASPATH
];
1934 case RMAP_EVENT_LLIST_ADDED
:
1935 case RMAP_EVENT_LLIST_DELETED
:
1936 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_LCLIST
];
1938 case RMAP_EVENT_CALL_ADDED
:
1939 case RMAP_EVENT_CALL_DELETED
:
1940 case RMAP_EVENT_MATCH_ADDED
:
1941 case RMAP_EVENT_MATCH_DELETED
:
1942 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_RMAP
];
1944 case RMAP_EVENT_FILTER_ADDED
:
1945 case RMAP_EVENT_FILTER_DELETED
:
1946 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_FILTER
];
1949 * Should we actually be ignoring these?
1950 * I am not sure but at this point in time, let
1951 * us get them into this switch and we can peel
1952 * them into the appropriate place in the future
1954 case RMAP_EVENT_SET_ADDED
:
1955 case RMAP_EVENT_SET_DELETED
:
1956 case RMAP_EVENT_SET_REPLACED
:
1957 case RMAP_EVENT_MATCH_REPLACED
:
1958 case RMAP_EVENT_INDEX_ADDED
:
1959 case RMAP_EVENT_INDEX_DELETED
:
1966 static void route_map_process_dependency(struct hash_bucket
*bucket
, void *data
)
1968 struct route_map_dep_data
*dep_data
= NULL
;
1969 char *rmap_name
= NULL
;
1971 dep_data
= bucket
->data
;
1972 rmap_name
= dep_data
->rname
;
1975 zlog_debug("Notifying %s of dependency", rmap_name
);
1976 if (route_map_master
.event_hook
)
1977 (*route_map_master
.event_hook
)(rmap_name
);
1980 void route_map_upd8_dependency(route_map_event_t type
, const char *arg
,
1981 const char *rmap_name
)
1983 struct hash
*upd8_hash
= NULL
;
1985 if ((upd8_hash
= route_map_get_dep_hash(type
))) {
1986 route_map_dep_update(upd8_hash
, arg
, rmap_name
, type
);
1988 if (type
== RMAP_EVENT_CALL_ADDED
) {
1990 if (route_map_master
.add_hook
)
1991 (*route_map_master
.add_hook
)(rmap_name
);
1992 } else if (type
== RMAP_EVENT_CALL_DELETED
) {
1994 if (route_map_master
.delete_hook
)
1995 (*route_map_master
.delete_hook
)(rmap_name
);
2000 void route_map_notify_dependencies(const char *affected_name
,
2001 route_map_event_t event
)
2003 struct route_map_dep
*dep
;
2004 struct hash
*upd8_hash
;
2010 name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, affected_name
);
2012 if ((upd8_hash
= route_map_get_dep_hash(event
)) == NULL
) {
2013 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
2017 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, name
, NULL
);
2019 if (!dep
->this_hash
)
2020 dep
->this_hash
= upd8_hash
;
2023 zlog_debug("Filter %s updated", dep
->dep_name
);
2024 hash_iterate(dep
->dep_rmap_hash
, route_map_process_dependency
,
2028 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
2032 /* VTY related functions. */
2033 static void clear_route_map_helper(struct route_map
*map
)
2035 struct route_map_index
*index
;
2037 map
->applied_clear
= map
->applied
;
2038 for (index
= map
->head
; index
; index
= index
->next
)
2039 index
->applied_clear
= index
->applied
;
2042 DEFUN (rmap_clear_counters
,
2043 rmap_clear_counters_cmd
,
2044 "clear route-map counters [WORD]",
2046 "route-map information\n"
2047 "counters associated with the specified route-map\n"
2051 struct route_map
*map
;
2053 const char *name
= (argc
== 3 ) ? argv
[idx_word
]->arg
: NULL
;
2056 map
= route_map_lookup_by_name(name
);
2059 clear_route_map_helper(map
);
2061 vty_out(vty
, "%s: 'route-map %s' not found\n",
2062 frr_protonameinst
, name
);
2066 for (map
= route_map_master
.head
; map
; map
= map
->next
)
2067 clear_route_map_helper(map
);
2074 DEFUN (rmap_show_name
,
2076 "show route-map [WORD]",
2078 "route-map information\n"
2082 const char *name
= (argc
== 3) ? argv
[idx_word
]->arg
: NULL
;
2083 return vty_show_route_map(vty
, name
);
2086 DEFUN (rmap_show_unused
,
2087 rmap_show_unused_cmd
,
2088 "show route-map-unused",
2090 "unused route-map information\n")
2092 return vty_show_unused_route_map(vty
);
2099 "Debug option set for route-maps\n")
2105 DEFUN (no_debug_rmap
,
2107 "no debug route-map",
2110 "Debug option set for route-maps\n")
2117 static struct cmd_node rmap_debug_node
= {RMAP_DEBUG_NODE
, "", 1};
2119 /* Configuration write function. */
2120 static int rmap_config_write_debug(struct vty
*vty
)
2125 vty_out(vty
, "debug route-map\n");
2132 /* Common route map rules */
2134 void *route_map_rule_tag_compile(const char *arg
)
2136 unsigned long int tmp
;
2141 tmp
= strtoul(arg
, &endptr
, 0);
2142 if (arg
[0] == '\0' || *endptr
!= '\0' || errno
|| tmp
> ROUTE_TAG_MAX
)
2145 tag
= XMALLOC(MTYPE_ROUTE_MAP_COMPILED
, sizeof(*tag
));
2151 void route_map_rule_tag_free(void *rule
)
2153 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
2156 void route_map_finish(void)
2160 vector_free(route_match_vec
);
2161 route_match_vec
= NULL
;
2162 vector_free(route_set_vec
);
2163 route_set_vec
= NULL
;
2166 * All protocols are setting these to NULL
2167 * by default on shutdown( route_map_finish )
2168 * Why are we making them do this work?
2170 route_map_master
.add_hook
= NULL
;
2171 route_map_master
.delete_hook
= NULL
;
2172 route_map_master
.event_hook
= NULL
;
2174 /* cleanup route_map */
2175 while (route_map_master
.head
) {
2176 struct route_map
*map
= route_map_master
.head
;
2177 map
->to_be_processed
= false;
2178 route_map_delete(map
);
2181 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
2182 hash_free(route_map_dep_hash
[i
]);
2183 route_map_dep_hash
[i
] = NULL
;
2186 hash_free(route_map_master_hash
);
2187 route_map_master_hash
= NULL
;
2190 /* Increment the use_count counter while attaching the route map */
2191 void route_map_counter_increment(struct route_map
*map
)
2197 /* Decrement the use_count counter while detaching the route map. */
2198 void route_map_counter_decrement(struct route_map
*map
)
2201 if (map
->use_count
<= 0)
2207 /* Initialization of route map vector. */
2208 void route_map_init(void)
2212 /* Make vector for match and set. */
2213 route_match_vec
= vector_init(1);
2214 route_set_vec
= vector_init(1);
2215 route_map_master_hash
=
2216 hash_create_size(8, route_map_hash_key_make
, route_map_hash_cmp
,
2217 "Route Map Master Hash");
2219 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++)
2220 route_map_dep_hash
[i
] = hash_create_size(
2221 8, route_map_dep_hash_make_key
, route_map_dep_hash_cmp
,
2222 "Route Map Dep Hash");
2226 route_map_cli_init();
2228 /* Install route map top node. */
2229 install_node(&rmap_debug_node
, rmap_config_write_debug
);
2231 /* Install route map commands. */
2232 install_element(CONFIG_NODE
, &debug_rmap_cmd
);
2233 install_element(CONFIG_NODE
, &no_debug_rmap_cmd
);
2235 /* Install show command */
2236 install_element(ENABLE_NODE
, &rmap_clear_counters_cmd
);
2238 install_element(ENABLE_NODE
, &rmap_show_name_cmd
);
2239 install_element(ENABLE_NODE
, &rmap_show_unused_cmd
);
2241 install_element(ENABLE_NODE
, &debug_rmap_cmd
);
2242 install_element(ENABLE_NODE
, &no_debug_rmap_cmd
);