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
34 #include "lib_errors.h"
38 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP
, "Route map");
39 DEFINE_MTYPE(LIB
, ROUTE_MAP_NAME
, "Route map name");
40 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_INDEX
, "Route map index");
41 DEFINE_MTYPE(LIB
, ROUTE_MAP_RULE
, "Route map rule");
42 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_RULE_STR
, "Route map rule str");
43 DEFINE_MTYPE(LIB
, ROUTE_MAP_COMPILED
, "Route map compiled");
44 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_DEP
, "Route map dependency");
45 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_DEP_DATA
, "Route map dependency data");
47 DEFINE_QOBJ_TYPE(route_map_index
);
48 DEFINE_QOBJ_TYPE(route_map
);
50 #define IPv4_PREFIX_LIST "ip address prefix-list"
51 #define IPv6_PREFIX_LIST "ipv6 address prefix-list"
53 #define IS_RULE_IPv4_PREFIX_LIST(S) \
54 (strncmp(S, IPv4_PREFIX_LIST, strlen(IPv4_PREFIX_LIST)) == 0)
55 #define IS_RULE_IPv6_PREFIX_LIST(S) \
56 (strncmp(S, IPv6_PREFIX_LIST, strlen(IPv6_PREFIX_LIST)) == 0)
58 struct route_map_pentry_dep
{
59 struct prefix_list_entry
*pentry
;
60 const char *plist_name
;
61 route_map_event_t event
;
64 /* Vector for route match rules. */
65 static vector route_match_vec
;
67 /* Vector for route set rules. */
68 static vector route_set_vec
;
70 static void route_map_pfx_tbl_update(route_map_event_t event
,
71 struct route_map_index
*index
, afi_t afi
,
72 const char *plist_name
);
73 static void route_map_pfx_table_add_default(afi_t afi
,
74 struct route_map_index
*index
);
75 static void route_map_pfx_table_del_default(afi_t afi
,
76 struct route_map_index
*index
);
77 static void route_map_add_plist_entries(afi_t afi
,
78 struct route_map_index
*index
,
79 const char *plist_name
,
80 struct prefix_list_entry
*entry
);
81 static void route_map_del_plist_entries(afi_t afi
,
82 struct route_map_index
*index
,
83 const char *plist_name
,
84 struct prefix_list_entry
*entry
);
86 static struct hash
*route_map_get_dep_hash(route_map_event_t event
);
88 struct route_map_match_set_hooks rmap_match_set_hook
;
91 void route_map_match_interface_hook(int (*func
)(
92 struct route_map_index
*index
, const char *command
,
93 const char *arg
, route_map_event_t type
,
94 char *errmsg
, size_t errmsg_len
))
96 rmap_match_set_hook
.match_interface
= func
;
99 /* no match interface */
100 void route_map_no_match_interface_hook(int (*func
)(
101 struct route_map_index
*index
, const char *command
,
102 const char *arg
, route_map_event_t type
,
103 char *errmsg
, size_t errmsg_len
))
105 rmap_match_set_hook
.no_match_interface
= func
;
108 /* match ip address */
109 void route_map_match_ip_address_hook(int (*func
)(
110 struct route_map_index
*index
, const char *command
,
111 const char *arg
, route_map_event_t type
,
112 char *errmsg
, size_t errmsg_len
))
114 rmap_match_set_hook
.match_ip_address
= func
;
117 /* no match ip address */
118 void route_map_no_match_ip_address_hook(int (*func
)(
119 struct route_map_index
*index
, const char *command
,
120 const char *arg
, route_map_event_t type
,
121 char *errmsg
, size_t errmsg_len
))
123 rmap_match_set_hook
.no_match_ip_address
= func
;
126 /* match ip address prefix list */
127 void route_map_match_ip_address_prefix_list_hook(int (*func
)(
128 struct route_map_index
*index
, const char *command
,
129 const char *arg
, route_map_event_t type
,
130 char *errmsg
, size_t errmsg_len
))
132 rmap_match_set_hook
.match_ip_address_prefix_list
= func
;
135 /* no match ip address prefix list */
136 void route_map_no_match_ip_address_prefix_list_hook(int (*func
)(
137 struct route_map_index
*index
, const char *command
,
138 const char *arg
, route_map_event_t type
,
139 char *errmsg
, size_t errmsg_len
))
141 rmap_match_set_hook
.no_match_ip_address_prefix_list
= func
;
144 /* match ip next hop */
145 void route_map_match_ip_next_hop_hook(int (*func
)(
146 struct route_map_index
*index
, const char *command
,
147 const char *arg
, route_map_event_t type
,
148 char *errmsg
, size_t errmsg_len
))
150 rmap_match_set_hook
.match_ip_next_hop
= func
;
153 /* no match ip next hop */
154 void route_map_no_match_ip_next_hop_hook(int (*func
)(
155 struct route_map_index
*index
, const char *command
,
156 const char *arg
, route_map_event_t type
,
157 char *errmsg
, size_t errmsg_len
))
159 rmap_match_set_hook
.no_match_ip_next_hop
= func
;
162 /* match ip next hop prefix list */
163 void route_map_match_ip_next_hop_prefix_list_hook(int (*func
)(
164 struct route_map_index
*index
, const char *command
,
165 const char *arg
, route_map_event_t type
,
166 char *errmsg
, size_t errmsg_len
))
168 rmap_match_set_hook
.match_ip_next_hop_prefix_list
= func
;
171 /* no match ip next hop prefix list */
172 void route_map_no_match_ip_next_hop_prefix_list_hook(int (*func
)(
173 struct route_map_index
*index
, const char *command
,
174 const char *arg
, route_map_event_t type
,
175 char *errmsg
, size_t errmsg_len
))
177 rmap_match_set_hook
.no_match_ip_next_hop_prefix_list
= func
;
180 /* match ip next-hop type */
181 void route_map_match_ip_next_hop_type_hook(int (*func
)(
182 struct route_map_index
*index
, const char *command
,
183 const char *arg
, route_map_event_t type
,
184 char *errmsg
, size_t errmsg_len
))
186 rmap_match_set_hook
.match_ip_next_hop_type
= func
;
189 /* no match ip next-hop type */
190 void route_map_no_match_ip_next_hop_type_hook(int (*func
)(
191 struct route_map_index
*index
, const char *command
,
192 const char *arg
, route_map_event_t type
,
193 char *errmsg
, size_t errmsg_len
))
195 rmap_match_set_hook
.no_match_ip_next_hop_type
= func
;
198 /* match ipv6 address */
199 void route_map_match_ipv6_address_hook(int (*func
)(
200 struct route_map_index
*index
, const char *command
,
201 const char *arg
, route_map_event_t type
,
202 char *errmsg
, size_t errmsg_len
))
204 rmap_match_set_hook
.match_ipv6_address
= func
;
207 /* no match ipv6 address */
208 void route_map_no_match_ipv6_address_hook(int (*func
)(
209 struct route_map_index
*index
, const char *command
,
210 const char *arg
, route_map_event_t type
,
211 char *errmsg
, size_t errmsg_len
))
213 rmap_match_set_hook
.no_match_ipv6_address
= func
;
217 /* match ipv6 address prefix list */
218 void route_map_match_ipv6_address_prefix_list_hook(int (*func
)(
219 struct route_map_index
*index
, const char *command
,
220 const char *arg
, route_map_event_t type
,
221 char *errmsg
, size_t errmsg_len
))
223 rmap_match_set_hook
.match_ipv6_address_prefix_list
= func
;
226 /* no match ipv6 address prefix list */
227 void route_map_no_match_ipv6_address_prefix_list_hook(int (*func
)(
228 struct route_map_index
*index
, const char *command
,
229 const char *arg
, route_map_event_t type
,
230 char *errmsg
, size_t errmsg_len
))
232 rmap_match_set_hook
.no_match_ipv6_address_prefix_list
= func
;
235 /* match ipv6 next-hop type */
236 void route_map_match_ipv6_next_hop_type_hook(int (*func
)(
237 struct route_map_index
*index
, const char *command
,
238 const char *arg
, route_map_event_t type
,
239 char *errmsg
, size_t errmsg_len
))
241 rmap_match_set_hook
.match_ipv6_next_hop_type
= func
;
244 /* no match ipv6 next-hop type */
245 void route_map_no_match_ipv6_next_hop_type_hook(int (*func
)(
246 struct route_map_index
*index
, const char *command
,
247 const char *arg
, route_map_event_t type
,
248 char *errmsg
, size_t errmsg_len
))
250 rmap_match_set_hook
.no_match_ipv6_next_hop_type
= func
;
254 void route_map_match_metric_hook(int (*func
)(
255 struct route_map_index
*index
, const char *command
,
256 const char *arg
, route_map_event_t type
,
257 char *errmsg
, size_t errmsg_len
))
259 rmap_match_set_hook
.match_metric
= func
;
262 /* no match metric */
263 void route_map_no_match_metric_hook(int (*func
)(
264 struct route_map_index
*index
, const char *command
,
265 const char *arg
, route_map_event_t type
,
266 char *errmsg
, size_t errmsg_len
))
268 rmap_match_set_hook
.no_match_metric
= func
;
272 void route_map_match_tag_hook(int (*func
)(struct route_map_index
*index
,
273 const char *command
, const char *arg
,
274 route_map_event_t type
,
275 char *errmsg
, size_t errmsg_len
))
277 rmap_match_set_hook
.match_tag
= func
;
281 void route_map_no_match_tag_hook(int (*func
)(
282 struct route_map_index
*index
, const char *command
,
283 const char *arg
, route_map_event_t type
,
284 char *errmsg
, size_t errmsg_len
))
286 rmap_match_set_hook
.no_match_tag
= func
;
289 /* set sr-te color */
290 void route_map_set_srte_color_hook(int (*func
)(struct route_map_index
*index
,
293 char *errmsg
, size_t errmsg_len
))
295 rmap_match_set_hook
.set_srte_color
= func
;
298 /* no set sr-te color */
299 void route_map_no_set_srte_color_hook(int (*func
)(struct route_map_index
*index
,
302 char *errmsg
, size_t errmsg_len
))
304 rmap_match_set_hook
.no_set_srte_color
= func
;
308 void route_map_set_ip_nexthop_hook(int (*func
)(struct route_map_index
*index
,
311 char *errmsg
, size_t errmsg_len
))
313 rmap_match_set_hook
.set_ip_nexthop
= func
;
316 /* no set ip nexthop */
317 void route_map_no_set_ip_nexthop_hook(int (*func
)(struct route_map_index
*index
,
323 rmap_match_set_hook
.no_set_ip_nexthop
= func
;
326 /* set ipv6 nexthop local */
327 void route_map_set_ipv6_nexthop_local_hook(
328 int (*func
)(struct route_map_index
*index
,
329 const char *command
, const char *arg
,
330 char *errmsg
, size_t errmsg_len
))
332 rmap_match_set_hook
.set_ipv6_nexthop_local
= func
;
335 /* no set ipv6 nexthop local */
336 void route_map_no_set_ipv6_nexthop_local_hook(
337 int (*func
)(struct route_map_index
*index
,
338 const char *command
, const char *arg
,
339 char *errmsg
, size_t errmsg_len
))
341 rmap_match_set_hook
.no_set_ipv6_nexthop_local
= func
;
345 void route_map_set_metric_hook(int (*func
)(struct route_map_index
*index
,
348 char *errmsg
, size_t errmsg_len
))
350 rmap_match_set_hook
.set_metric
= func
;
354 void route_map_no_set_metric_hook(int (*func
)(struct route_map_index
*index
,
357 char *errmsg
, size_t errmsg_len
))
359 rmap_match_set_hook
.no_set_metric
= func
;
363 void route_map_set_tag_hook(int (*func
)(struct route_map_index
*index
,
364 const char *command
, const char *arg
,
365 char *errmsg
, size_t errmsg_len
))
367 rmap_match_set_hook
.set_tag
= func
;
371 void route_map_no_set_tag_hook(int (*func
)(struct route_map_index
*index
,
374 char *errmsg
, size_t errmsg_len
))
376 rmap_match_set_hook
.no_set_tag
= func
;
379 int generic_match_add(struct route_map_index
*index
,
380 const char *command
, const char *arg
,
381 route_map_event_t type
,
382 char *errmsg
, size_t errmsg_len
)
384 enum rmap_compile_rets ret
;
386 ret
= route_map_add_match(index
, command
, arg
, type
);
388 case RMAP_RULE_MISSING
:
389 snprintf(errmsg
, errmsg_len
, "%% [%s] Can't find rule.",
391 return CMD_WARNING_CONFIG_FAILED
;
392 case RMAP_COMPILE_ERROR
:
393 snprintf(errmsg
, errmsg_len
,
394 "%% [%s] Argument form is unsupported or malformed.",
396 return CMD_WARNING_CONFIG_FAILED
;
397 case RMAP_COMPILE_SUCCESS
:
399 * Nothing to do here move along
407 int generic_match_delete(struct route_map_index
*index
,
408 const char *command
, const char *arg
,
409 route_map_event_t type
,
410 char *errmsg
, size_t errmsg_len
)
412 enum rmap_compile_rets ret
;
413 int retval
= CMD_SUCCESS
;
414 char *dep_name
= NULL
;
416 char *rmap_name
= NULL
;
418 if (type
!= RMAP_EVENT_MATCH_DELETED
) {
419 /* ignore the mundane, the types without any dependency */
421 if ((tmpstr
= route_map_get_match_arg(index
, command
))
424 XSTRDUP(MTYPE_ROUTE_MAP_RULE
, tmpstr
);
426 dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_RULE
, arg
);
428 rmap_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, index
->map
->name
);
431 ret
= route_map_delete_match(index
, command
, dep_name
, type
);
433 case RMAP_RULE_MISSING
:
434 snprintf(errmsg
, errmsg_len
, "%% [%s] Can't find rule.",
436 retval
= CMD_WARNING_CONFIG_FAILED
;
438 case RMAP_COMPILE_ERROR
:
439 snprintf(errmsg
, errmsg_len
,
440 "%% [%s] Argument form is unsupported or malformed.",
442 retval
= CMD_WARNING_CONFIG_FAILED
;
444 case RMAP_COMPILE_SUCCESS
:
451 XFREE(MTYPE_ROUTE_MAP_RULE
, dep_name
);
452 XFREE(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
457 int generic_set_add(struct route_map_index
*index
,
458 const char *command
, const char *arg
,
459 char *errmsg
, size_t errmsg_len
)
461 enum rmap_compile_rets ret
;
463 ret
= route_map_add_set(index
, command
, arg
);
465 case RMAP_RULE_MISSING
:
466 snprintf(errmsg
, errmsg_len
,
467 "%% [%s] Can't find rule.", frr_protonameinst
);
468 return CMD_WARNING_CONFIG_FAILED
;
469 case RMAP_COMPILE_ERROR
:
470 snprintf(errmsg
, errmsg_len
,
471 "%% [%s] Argument form is unsupported or malformed.",
473 return CMD_WARNING_CONFIG_FAILED
;
474 case RMAP_COMPILE_SUCCESS
:
481 int generic_set_delete(struct route_map_index
*index
,
482 const char *command
, const char *arg
,
483 char *errmsg
, size_t errmsg_len
)
485 enum rmap_compile_rets ret
;
487 ret
= route_map_delete_set(index
, command
, arg
);
489 case RMAP_RULE_MISSING
:
490 snprintf(errmsg
, errmsg_len
, "%% [%s] Can't find rule.",
492 return CMD_WARNING_CONFIG_FAILED
;
493 case RMAP_COMPILE_ERROR
:
494 snprintf(errmsg
, errmsg_len
,
495 "%% [%s] Argument form is unsupported or malformed.",
497 return CMD_WARNING_CONFIG_FAILED
;
498 case RMAP_COMPILE_SUCCESS
:
506 /* Master list of route map. */
507 struct route_map_list route_map_master
= {NULL
, NULL
, NULL
, NULL
, NULL
};
508 struct hash
*route_map_master_hash
= NULL
;
510 static unsigned int route_map_hash_key_make(const void *p
)
512 const struct route_map
*map
= p
;
513 return string_hash_make(map
->name
);
516 static bool route_map_hash_cmp(const void *p1
, const void *p2
)
518 const struct route_map
*map1
= p1
;
519 const struct route_map
*map2
= p2
;
521 if (map1
->deleted
== map2
->deleted
) {
522 if (map1
->name
&& map2
->name
) {
523 if (!strcmp(map1
->name
, map2
->name
)) {
526 } else if (!map1
->name
&& !map2
->name
) {
534 enum route_map_upd8_type
{
539 /* all possible route-map dependency types */
540 enum route_map_dep_type
{
541 ROUTE_MAP_DEP_RMAP
= 1,
543 ROUTE_MAP_DEP_ECLIST
,
544 ROUTE_MAP_DEP_LCLIST
,
546 ROUTE_MAP_DEP_ASPATH
,
547 ROUTE_MAP_DEP_FILTER
,
551 struct route_map_dep
{
553 struct hash
*dep_rmap_hash
;
554 struct hash
*this_hash
; /* ptr to the hash structure this is part of */
557 struct route_map_dep_data
{
561 /* Count of number of sequences of this
562 * route-map that depend on the same entity.
567 /* Hashes maintaining dependency between various sublists used by route maps */
568 static struct hash
*route_map_dep_hash
[ROUTE_MAP_DEP_MAX
];
570 static unsigned int route_map_dep_hash_make_key(const void *p
);
571 static void route_map_clear_all_references(char *rmap_name
);
572 static void route_map_rule_delete(struct route_map_rule_list
*,
573 struct route_map_rule
*);
574 static bool rmap_debug
;
576 /* New route map allocation. Please note route map's name must be
578 static struct route_map
*route_map_new(const char *name
)
580 struct route_map
*new;
582 new = XCALLOC(MTYPE_ROUTE_MAP
, sizeof(struct route_map
));
583 new->name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
584 QOBJ_REG(new, route_map
);
588 /* Add new name to route_map. */
589 static struct route_map
*route_map_add(const char *name
)
591 struct route_map
*map
;
592 struct route_map_list
*list
;
594 map
= route_map_new(name
);
595 list
= &route_map_master
;
597 /* Add map to the hash */
598 hash_get(route_map_master_hash
, map
, hash_alloc_intern
);
600 /* Add new entry to the head of the list to match how it is added in the
601 * hash table. This is to ensure that if the same route-map has been
602 * created more than once and then marked for deletion (which can happen
603 * if prior deletions haven't completed as BGP hasn't yet done the
604 * route-map processing), the order of the entities is the same in both
605 * the list and the hash table. Otherwise, since there is nothing to
606 * distinguish between the two entries, the wrong entry could get freed.
607 * TODO: This needs to be re-examined to handle it better - e.g., revive
608 * a deleted entry if the route-map is created again.
611 map
->next
= list
->head
;
613 list
->head
->prev
= map
;
619 if (route_map_master
.add_hook
) {
620 (*route_map_master
.add_hook
)(name
);
621 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_ADDED
);
624 if (!map
->ipv4_prefix_table
)
625 map
->ipv4_prefix_table
= route_table_init();
627 if (!map
->ipv6_prefix_table
)
628 map
->ipv6_prefix_table
= route_table_init();
631 zlog_debug("Add route-map %s", name
);
635 /* this is supposed to be called post processing by
636 * the delete hook function. Don't invoke delete_hook
637 * again in this routine.
639 static void route_map_free_map(struct route_map
*map
)
641 struct route_map_list
*list
;
642 struct route_map_index
*index
;
647 while ((index
= map
->head
) != NULL
)
648 route_map_index_delete(index
, 0);
651 zlog_debug("Deleting route-map %s", map
->name
);
653 list
= &route_map_master
;
658 map
->next
->prev
= map
->prev
;
660 list
->tail
= map
->prev
;
663 map
->prev
->next
= map
->next
;
665 list
->head
= map
->next
;
667 hash_release(route_map_master_hash
, map
);
668 XFREE(MTYPE_ROUTE_MAP_NAME
, map
->name
);
669 XFREE(MTYPE_ROUTE_MAP
, map
);
672 /* Route map delete from list. */
673 void route_map_delete(struct route_map
*map
)
675 struct route_map_index
*index
;
678 while ((index
= map
->head
) != NULL
)
679 route_map_index_delete(index
, 0);
684 /* Clear all dependencies */
685 route_map_clear_all_references(name
);
687 /* Execute deletion hook. */
688 if (route_map_master
.delete_hook
) {
689 (*route_map_master
.delete_hook
)(name
);
690 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_DELETED
);
693 if (!map
->to_be_processed
) {
694 route_map_free_map(map
);
698 /* Lookup route map by route map name string. */
699 struct route_map
*route_map_lookup_by_name(const char *name
)
701 struct route_map
*map
;
702 struct route_map tmp_map
;
707 // map.deleted is 0 via memset
708 memset(&tmp_map
, 0, sizeof(struct route_map
));
709 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
710 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
711 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
715 /* Simple helper to warn if route-map does not exist. */
716 struct route_map
*route_map_lookup_warn_noexist(struct vty
*vty
, const char *name
)
718 struct route_map
*route_map
= route_map_lookup_by_name(name
);
721 if (vty_shell_serv(vty
))
722 vty_out(vty
, "The route-map '%s' does not exist.\n", name
);
727 int route_map_mark_updated(const char *name
)
729 struct route_map
*map
;
731 struct route_map tmp_map
;
736 map
= route_map_lookup_by_name(name
);
738 /* If we did not find the routemap with deleted=false try again
742 memset(&tmp_map
, 0, sizeof(struct route_map
));
743 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
744 tmp_map
.deleted
= true;
745 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
746 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
750 map
->to_be_processed
= true;
757 static int route_map_clear_updated(struct route_map
*map
)
762 map
->to_be_processed
= false;
764 route_map_free_map(map
);
770 /* Lookup route map. If there isn't route map create one and return
772 struct route_map
*route_map_get(const char *name
)
774 struct route_map
*map
;
776 map
= route_map_lookup_by_name(name
);
778 map
= route_map_add(name
);
783 void route_map_walk_update_list(void (*route_map_update_fn
)(char *name
))
785 struct route_map
*node
;
786 struct route_map
*nnode
= NULL
;
788 for (node
= route_map_master
.head
; node
; node
= nnode
) {
789 if (node
->to_be_processed
) {
790 /* DD: Should we add any thread yield code here */
791 route_map_update_fn(node
->name
);
793 route_map_clear_updated(node
);
799 /* Return route map's type string. */
800 static const char *route_map_type_str(enum route_map_type type
)
814 static const char *route_map_cmd_result_str(enum route_map_cmd_result_t res
)
832 static const char *route_map_result_str(route_map_result_t res
)
837 case RMAP_PERMITMATCH
:
845 static void vty_show_route_map_entry(struct vty
*vty
, struct route_map
*map
,
848 struct route_map_index
*index
;
849 struct route_map_rule
*rule
;
850 json_object
*json_rmap
= NULL
;
851 json_object
*json_rules
= NULL
;
854 json_rmap
= json_object_new_object();
855 json_object_object_add(json
, map
->name
, json_rmap
);
857 json_rules
= json_object_new_array();
858 json_object_int_add(json_rmap
, "invoked",
859 map
->applied
- map
->applied_clear
);
860 json_object_boolean_add(json_rmap
, "disabledOptimization",
861 map
->optimization_disabled
);
862 json_object_boolean_add(json_rmap
, "processedChange",
863 map
->to_be_processed
);
864 json_object_object_add(json_rmap
, "rules", json_rules
);
867 "route-map: %s Invoked: %" PRIu64
868 " Optimization: %s Processed Change: %s\n",
869 map
->name
, map
->applied
- map
->applied_clear
,
870 map
->optimization_disabled
? "disabled" : "enabled",
871 map
->to_be_processed
? "true" : "false");
874 for (index
= map
->head
; index
; index
= index
->next
) {
876 json_object
*json_rule
;
877 json_object
*json_matches
;
878 json_object
*json_sets
;
879 char action
[BUFSIZ
] = {};
881 json_rule
= json_object_new_object();
882 json_object_array_add(json_rules
, json_rule
);
884 json_object_int_add(json_rule
, "sequenceNumber",
886 json_object_string_add(json_rule
, "type",
887 route_map_type_str(index
->type
));
888 json_object_int_add(json_rule
, "invoked",
890 - index
->applied_clear
);
893 if (index
->description
)
894 json_object_string_add(json_rule
, "description",
898 json_matches
= json_object_new_array();
899 json_object_object_add(json_rule
, "matchClauses",
901 for (rule
= index
->match_list
.head
; rule
;
905 snprintf(buf
, sizeof(buf
), "%s %s",
906 rule
->cmd
->str
, rule
->rule_str
);
907 json_array_string_add(json_matches
, buf
);
911 json_sets
= json_object_new_array();
912 json_object_object_add(json_rule
, "setClauses",
914 for (rule
= index
->set_list
.head
; rule
;
918 snprintf(buf
, sizeof(buf
), "%s %s",
919 rule
->cmd
->str
, rule
->rule_str
);
920 json_array_string_add(json_sets
, buf
);
925 json_object_string_add(json_rule
, "callClause",
929 if (index
->exitpolicy
== RMAP_GOTO
)
930 snprintf(action
, sizeof(action
), "Goto %d",
932 else if (index
->exitpolicy
== RMAP_NEXT
)
933 snprintf(action
, sizeof(action
),
934 "Continue to next entry");
935 else if (index
->exitpolicy
== RMAP_EXIT
)
936 snprintf(action
, sizeof(action
),
938 if (action
[0] != '\0')
939 json_object_string_add(json_rule
, "action",
942 vty_out(vty
, " %s, sequence %d Invoked %" PRIu64
"\n",
943 route_map_type_str(index
->type
), index
->pref
,
944 index
->applied
- index
->applied_clear
);
947 if (index
->description
)
948 vty_out(vty
, " Description:\n %s\n",
952 vty_out(vty
, " Match clauses:\n");
953 for (rule
= index
->match_list
.head
; rule
;
955 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
959 vty_out(vty
, " Set clauses:\n");
960 for (rule
= index
->set_list
.head
; rule
;
962 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
966 vty_out(vty
, " Call clause:\n");
968 vty_out(vty
, " Call %s\n", index
->nextrm
);
971 vty_out(vty
, " Action:\n");
972 if (index
->exitpolicy
== RMAP_GOTO
)
973 vty_out(vty
, " Goto %d\n", index
->nextpref
);
974 else if (index
->exitpolicy
== RMAP_NEXT
)
975 vty_out(vty
, " Continue to next entry\n");
976 else if (index
->exitpolicy
== RMAP_EXIT
)
977 vty_out(vty
, " Exit routemap\n");
982 static int sort_route_map(const void **map1
, const void **map2
)
984 const struct route_map
*m1
= *map1
;
985 const struct route_map
*m2
= *map2
;
987 return strcmp(m1
->name
, m2
->name
);
990 static int vty_show_route_map(struct vty
*vty
, const char *name
, bool use_json
)
992 struct route_map
*map
;
993 json_object
*json
= NULL
;
994 json_object
*json_proto
= NULL
;
997 json
= json_object_new_object();
998 json_proto
= json_object_new_object();
999 json_object_object_add(json
, frr_protonameinst
, json_proto
);
1001 vty_out(vty
, "%s:\n", frr_protonameinst
);
1004 map
= route_map_lookup_by_name(name
);
1007 vty_show_route_map_entry(vty
, map
, json_proto
);
1009 } else if (!use_json
) {
1010 vty_out(vty
, "%s: 'route-map %s' not found\n",
1011 frr_protonameinst
, name
);
1015 struct list
*maplist
= list_new();
1016 struct listnode
*ln
;
1018 for (map
= route_map_master
.head
; map
; map
= map
->next
)
1019 listnode_add(maplist
, map
);
1021 list_sort(maplist
, sort_route_map
);
1023 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
1024 vty_show_route_map_entry(vty
, map
, json_proto
);
1026 list_delete(&maplist
);
1030 vty_out(vty
, "%s\n",
1031 json_object_to_json_string_ext(
1032 json
, JSON_C_TO_STRING_PRETTY
));
1033 json_object_free(json
);
1039 /* Unused route map details */
1040 static int vty_show_unused_route_map(struct vty
*vty
)
1042 struct list
*maplist
= list_new();
1043 struct listnode
*ln
;
1044 struct route_map
*map
;
1046 for (map
= route_map_master
.head
; map
; map
= map
->next
) {
1047 /* If use_count is zero, No protocol is using this routemap.
1048 * so adding to the list.
1050 if (!map
->use_count
)
1051 listnode_add(maplist
, map
);
1054 if (maplist
->count
> 0) {
1055 vty_out(vty
, "\n%s:\n", frr_protonameinst
);
1056 list_sort(maplist
, sort_route_map
);
1058 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
1059 vty_show_route_map_entry(vty
, map
, NULL
);
1061 vty_out(vty
, "\n%s: None\n", frr_protonameinst
);
1064 list_delete(&maplist
);
1068 /* New route map allocation. Please note route map's name must be
1070 static struct route_map_index
*route_map_index_new(void)
1072 struct route_map_index
*new;
1074 new = XCALLOC(MTYPE_ROUTE_MAP_INDEX
, sizeof(struct route_map_index
));
1075 new->exitpolicy
= RMAP_EXIT
; /* Default to Cisco-style */
1076 TAILQ_INIT(&new->rhclist
);
1077 QOBJ_REG(new, route_map_index
);
1081 /* Free route map index. */
1082 void route_map_index_delete(struct route_map_index
*index
, int notify
)
1084 struct routemap_hook_context
*rhc
;
1085 struct route_map_rule
*rule
;
1090 zlog_debug("Deleting route-map %s sequence %d",
1091 index
->map
->name
, index
->pref
);
1093 /* Free route map entry description. */
1094 XFREE(MTYPE_TMP
, index
->description
);
1096 /* Free route map northbound hook contexts. */
1097 while ((rhc
= TAILQ_FIRST(&index
->rhclist
)) != NULL
)
1098 routemap_hook_context_free(rhc
);
1100 /* Free route match. */
1101 while ((rule
= index
->match_list
.head
) != NULL
) {
1102 if (IS_RULE_IPv4_PREFIX_LIST(rule
->cmd
->str
))
1103 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_DELETED
,
1104 index
, AFI_IP
, rule
->rule_str
);
1105 else if (IS_RULE_IPv6_PREFIX_LIST(rule
->cmd
->str
))
1106 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_DELETED
,
1110 route_map_rule_delete(&index
->match_list
, rule
);
1113 /* Free route set. */
1114 while ((rule
= index
->set_list
.head
) != NULL
)
1115 route_map_rule_delete(&index
->set_list
, rule
);
1117 /* Remove index from route map list. */
1119 index
->next
->prev
= index
->prev
;
1121 index
->map
->tail
= index
->prev
;
1124 index
->prev
->next
= index
->next
;
1126 index
->map
->head
= index
->next
;
1128 /* Free 'char *nextrm' if not NULL */
1129 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
1131 route_map_pfx_tbl_update(RMAP_EVENT_INDEX_DELETED
, index
, 0, NULL
);
1133 /* Execute event hook. */
1134 if (route_map_master
.event_hook
&& notify
) {
1135 (*route_map_master
.event_hook
)(index
->map
->name
);
1136 route_map_notify_dependencies(index
->map
->name
,
1137 RMAP_EVENT_CALL_ADDED
);
1139 XFREE(MTYPE_ROUTE_MAP_INDEX
, index
);
1142 /* Lookup index from route map. */
1143 static struct route_map_index
*route_map_index_lookup(struct route_map
*map
,
1144 enum route_map_type type
,
1147 struct route_map_index
*index
;
1149 for (index
= map
->head
; index
; index
= index
->next
)
1150 if ((index
->type
== type
|| type
== RMAP_ANY
)
1151 && index
->pref
== pref
)
1156 /* Add new index to route map. */
1157 static struct route_map_index
*
1158 route_map_index_add(struct route_map
*map
, enum route_map_type type
, int pref
)
1160 struct route_map_index
*index
;
1161 struct route_map_index
*point
;
1163 /* Allocate new route map inex. */
1164 index
= route_map_index_new();
1169 /* Compare preference. */
1170 for (point
= map
->head
; point
; point
= point
->next
)
1171 if (point
->pref
>= pref
)
1174 if (map
->head
== NULL
) {
1175 map
->head
= map
->tail
= index
;
1176 } else if (point
== NULL
) {
1177 index
->prev
= map
->tail
;
1178 map
->tail
->next
= index
;
1180 } else if (point
== map
->head
) {
1181 index
->next
= map
->head
;
1182 map
->head
->prev
= index
;
1185 index
->next
= point
;
1186 index
->prev
= point
->prev
;
1188 point
->prev
->next
= index
;
1189 point
->prev
= index
;
1192 route_map_pfx_tbl_update(RMAP_EVENT_INDEX_ADDED
, index
, 0, NULL
);
1194 /* Execute event hook. */
1195 if (route_map_master
.event_hook
) {
1196 (*route_map_master
.event_hook
)(map
->name
);
1197 route_map_notify_dependencies(map
->name
, RMAP_EVENT_CALL_ADDED
);
1201 zlog_debug("Route-map %s add sequence %d, type: %s",
1202 map
->name
, pref
, route_map_type_str(type
));
1207 /* Get route map index. */
1208 struct route_map_index
*
1209 route_map_index_get(struct route_map
*map
, enum route_map_type type
, int pref
)
1211 struct route_map_index
*index
;
1213 index
= route_map_index_lookup(map
, RMAP_ANY
, pref
);
1214 if (index
&& index
->type
!= type
) {
1215 /* Delete index from route map. */
1216 route_map_index_delete(index
, 1);
1220 index
= route_map_index_add(map
, type
, pref
);
1224 /* New route map rule */
1225 static struct route_map_rule
*route_map_rule_new(void)
1227 struct route_map_rule
*new;
1229 new = XCALLOC(MTYPE_ROUTE_MAP_RULE
, sizeof(struct route_map_rule
));
1233 /* Install rule command to the match list. */
1234 void route_map_install_match(const struct route_map_rule_cmd
*cmd
)
1236 vector_set(route_match_vec
, (void *)cmd
);
1239 /* Install rule command to the set list. */
1240 void route_map_install_set(const struct route_map_rule_cmd
*cmd
)
1242 vector_set(route_set_vec
, (void *)cmd
);
1245 /* Lookup rule command from match list. */
1246 static const struct route_map_rule_cmd
*route_map_lookup_match(const char *name
)
1249 const struct route_map_rule_cmd
*rule
;
1251 for (i
= 0; i
< vector_active(route_match_vec
); i
++)
1252 if ((rule
= vector_slot(route_match_vec
, i
)) != NULL
)
1253 if (strcmp(rule
->str
, name
) == 0)
1258 /* Lookup rule command from set list. */
1259 static const struct route_map_rule_cmd
*route_map_lookup_set(const char *name
)
1262 const struct route_map_rule_cmd
*rule
;
1264 for (i
= 0; i
< vector_active(route_set_vec
); i
++)
1265 if ((rule
= vector_slot(route_set_vec
, i
)) != NULL
)
1266 if (strcmp(rule
->str
, name
) == 0)
1271 /* Add match and set rule to rule list. */
1272 static void route_map_rule_add(struct route_map_rule_list
*list
,
1273 struct route_map_rule
*rule
)
1276 rule
->prev
= list
->tail
;
1278 list
->tail
->next
= rule
;
1284 /* Delete rule from rule list. */
1285 static void route_map_rule_delete(struct route_map_rule_list
*list
,
1286 struct route_map_rule
*rule
)
1288 if (rule
->cmd
->func_free
)
1289 (*rule
->cmd
->func_free
)(rule
->value
);
1291 XFREE(MTYPE_ROUTE_MAP_RULE_STR
, rule
->rule_str
);
1294 rule
->next
->prev
= rule
->prev
;
1296 list
->tail
= rule
->prev
;
1298 rule
->prev
->next
= rule
->next
;
1300 list
->head
= rule
->next
;
1302 XFREE(MTYPE_ROUTE_MAP_RULE
, rule
);
1305 /* strcmp wrapper function which don't crush even argument is NULL. */
1306 static int rulecmp(const char *dst
, const char *src
)
1317 return strcmp(dst
, src
);
1322 /* Use this to return the already specified argument for this match. This is
1323 * useful to get the specified argument with a route map match rule when the
1324 * rule is being deleted and the argument is not provided.
1326 const char *route_map_get_match_arg(struct route_map_index
*index
,
1327 const char *match_name
)
1329 struct route_map_rule
*rule
;
1330 const struct route_map_rule_cmd
*cmd
;
1332 /* First lookup rule for add match statement. */
1333 cmd
= route_map_lookup_match(match_name
);
1337 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1338 if (rule
->cmd
== cmd
&& rule
->rule_str
!= NULL
)
1339 return (rule
->rule_str
);
1344 static route_map_event_t
get_route_map_delete_event(route_map_event_t type
)
1347 case RMAP_EVENT_CALL_ADDED
:
1348 return RMAP_EVENT_CALL_DELETED
;
1349 case RMAP_EVENT_PLIST_ADDED
:
1350 return RMAP_EVENT_PLIST_DELETED
;
1351 case RMAP_EVENT_CLIST_ADDED
:
1352 return RMAP_EVENT_CLIST_DELETED
;
1353 case RMAP_EVENT_ECLIST_ADDED
:
1354 return RMAP_EVENT_ECLIST_DELETED
;
1355 case RMAP_EVENT_LLIST_ADDED
:
1356 return RMAP_EVENT_LLIST_DELETED
;
1357 case RMAP_EVENT_ASLIST_ADDED
:
1358 return RMAP_EVENT_ASLIST_DELETED
;
1359 case RMAP_EVENT_FILTER_ADDED
:
1360 return RMAP_EVENT_FILTER_DELETED
;
1361 case RMAP_EVENT_SET_ADDED
:
1362 case RMAP_EVENT_SET_DELETED
:
1363 case RMAP_EVENT_SET_REPLACED
:
1364 case RMAP_EVENT_MATCH_ADDED
:
1365 case RMAP_EVENT_MATCH_DELETED
:
1366 case RMAP_EVENT_MATCH_REPLACED
:
1367 case RMAP_EVENT_INDEX_ADDED
:
1368 case RMAP_EVENT_INDEX_DELETED
:
1369 case RMAP_EVENT_CALL_DELETED
:
1370 case RMAP_EVENT_PLIST_DELETED
:
1371 case RMAP_EVENT_CLIST_DELETED
:
1372 case RMAP_EVENT_ECLIST_DELETED
:
1373 case RMAP_EVENT_LLIST_DELETED
:
1374 case RMAP_EVENT_ASLIST_DELETED
:
1375 case RMAP_EVENT_FILTER_DELETED
:
1376 /* This function returns the appropriate 'deleted' event type
1377 * for every 'added' event type passed to this function.
1378 * This is done only for named entities used in the
1379 * route-map match commands.
1380 * This function is not to be invoked for any of the other event
1388 * Return to make c happy but if we get here something has gone
1389 * terribly terribly wrong, so yes this return makes no sense.
1391 return RMAP_EVENT_CALL_ADDED
;
1394 /* Add match statement to route map. */
1395 enum rmap_compile_rets
route_map_add_match(struct route_map_index
*index
,
1396 const char *match_name
,
1397 const char *match_arg
,
1398 route_map_event_t type
)
1400 struct route_map_rule
*rule
;
1401 struct route_map_rule
*next
;
1402 const struct route_map_rule_cmd
*cmd
;
1404 int8_t delete_rmap_event_type
= 0;
1405 const char *rule_key
;
1407 /* First lookup rule for add match statement. */
1408 cmd
= route_map_lookup_match(match_name
);
1410 return RMAP_RULE_MISSING
;
1412 /* Next call compile function for this match statement. */
1413 if (cmd
->func_compile
) {
1414 compile
= (*cmd
->func_compile
)(match_arg
);
1415 if (compile
== NULL
)
1416 return RMAP_COMPILE_ERROR
;
1419 /* use the compiled results if applicable */
1420 if (compile
&& cmd
->func_get_rmap_rule_key
)
1421 rule_key
= (*cmd
->func_get_rmap_rule_key
)
1424 rule_key
= match_arg
;
1426 /* If argument is completely same ignore it. */
1427 for (rule
= index
->match_list
.head
; rule
; rule
= next
) {
1429 if (rule
->cmd
== cmd
) {
1430 /* If the configured route-map match rule is exactly
1431 * the same as the existing configuration then,
1432 * ignore the duplicate configuration.
1434 if (rulecmp(match_arg
, rule
->rule_str
) == 0) {
1436 (*cmd
->func_free
)(compile
);
1438 return RMAP_COMPILE_SUCCESS
;
1441 /* If IPv4 or IPv6 prefix-list match criteria
1442 * has been delete to the route-map index, update
1443 * the route-map's prefix table.
1445 if (IS_RULE_IPv4_PREFIX_LIST(match_name
))
1446 route_map_pfx_tbl_update(
1447 RMAP_EVENT_PLIST_DELETED
, index
, AFI_IP
,
1449 else if (IS_RULE_IPv6_PREFIX_LIST(match_name
))
1450 route_map_pfx_tbl_update(
1451 RMAP_EVENT_PLIST_DELETED
, index
,
1452 AFI_IP6
, rule
->rule_str
);
1454 /* Remove the dependency of the route-map on the rule
1455 * that is being replaced.
1457 if (type
>= RMAP_EVENT_CALL_ADDED
) {
1458 delete_rmap_event_type
=
1459 get_route_map_delete_event(type
);
1460 route_map_upd8_dependency(
1461 delete_rmap_event_type
,
1466 route_map_rule_delete(&index
->match_list
, rule
);
1470 /* Add new route map match rule. */
1471 rule
= route_map_rule_new();
1473 rule
->value
= compile
;
1475 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, match_arg
);
1477 rule
->rule_str
= NULL
;
1479 /* Add new route match rule to linked list. */
1480 route_map_rule_add(&index
->match_list
, rule
);
1482 /* If IPv4 or IPv6 prefix-list match criteria
1483 * has been added to the route-map index, update
1484 * the route-map's prefix table.
1486 if (IS_RULE_IPv4_PREFIX_LIST(match_name
)) {
1487 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_ADDED
, index
, AFI_IP
,
1489 } else if (IS_RULE_IPv6_PREFIX_LIST(match_name
)) {
1490 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_ADDED
, index
, AFI_IP6
,
1494 /* Execute event hook. */
1495 if (route_map_master
.event_hook
) {
1496 (*route_map_master
.event_hook
)(index
->map
->name
);
1497 route_map_notify_dependencies(index
->map
->name
,
1498 RMAP_EVENT_CALL_ADDED
);
1500 if (type
!= RMAP_EVENT_MATCH_ADDED
)
1501 route_map_upd8_dependency(type
, rule_key
, index
->map
->name
);
1503 return RMAP_COMPILE_SUCCESS
;
1506 /* Delete specified route match rule. */
1507 enum rmap_compile_rets
route_map_delete_match(struct route_map_index
*index
,
1508 const char *match_name
,
1509 const char *match_arg
,
1510 route_map_event_t type
)
1512 struct route_map_rule
*rule
;
1513 const struct route_map_rule_cmd
*cmd
;
1514 const char *rule_key
;
1516 cmd
= route_map_lookup_match(match_name
);
1518 return RMAP_RULE_MISSING
;
1520 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1521 if (rule
->cmd
== cmd
&& (rulecmp(rule
->rule_str
, match_arg
) == 0
1522 || match_arg
== NULL
)) {
1523 /* Execute event hook. */
1524 if (route_map_master
.event_hook
) {
1525 (*route_map_master
.event_hook
)(index
->map
->name
);
1526 route_map_notify_dependencies(
1528 RMAP_EVENT_CALL_ADDED
);
1530 if (cmd
->func_get_rmap_rule_key
)
1531 rule_key
= (*cmd
->func_get_rmap_rule_key
)
1534 rule_key
= match_arg
;
1536 if (type
!= RMAP_EVENT_MATCH_DELETED
&& rule_key
)
1537 route_map_upd8_dependency(type
, rule_key
,
1540 route_map_rule_delete(&index
->match_list
, rule
);
1542 /* If IPv4 or IPv6 prefix-list match criteria
1543 * has been delete from the route-map index, update
1544 * the route-map's prefix table.
1546 if (IS_RULE_IPv4_PREFIX_LIST(match_name
)) {
1547 route_map_pfx_tbl_update(
1548 RMAP_EVENT_PLIST_DELETED
, index
, AFI_IP
,
1550 } else if (IS_RULE_IPv6_PREFIX_LIST(match_name
)) {
1551 route_map_pfx_tbl_update(
1552 RMAP_EVENT_PLIST_DELETED
, index
,
1553 AFI_IP6
, match_arg
);
1556 return RMAP_COMPILE_SUCCESS
;
1558 /* Can't find matched rule. */
1559 return RMAP_RULE_MISSING
;
1562 /* Add route-map set statement to the route map. */
1563 enum rmap_compile_rets
route_map_add_set(struct route_map_index
*index
,
1564 const char *set_name
,
1565 const char *set_arg
)
1567 struct route_map_rule
*rule
;
1568 struct route_map_rule
*next
;
1569 const struct route_map_rule_cmd
*cmd
;
1572 cmd
= route_map_lookup_set(set_name
);
1574 return RMAP_RULE_MISSING
;
1576 /* Next call compile function for this match statement. */
1577 if (cmd
->func_compile
) {
1578 compile
= (*cmd
->func_compile
)(set_arg
);
1579 if (compile
== NULL
)
1580 return RMAP_COMPILE_ERROR
;
1584 /* Add by WJL. if old set command of same kind exist, delete it first
1585 to ensure only one set command of same kind exist under a
1587 for (rule
= index
->set_list
.head
; rule
; rule
= next
) {
1589 if (rule
->cmd
== cmd
)
1590 route_map_rule_delete(&index
->set_list
, rule
);
1593 /* Add new route map match rule. */
1594 rule
= route_map_rule_new();
1596 rule
->value
= compile
;
1598 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, set_arg
);
1600 rule
->rule_str
= NULL
;
1602 /* Add new route match rule to linked list. */
1603 route_map_rule_add(&index
->set_list
, rule
);
1605 /* Execute event hook. */
1606 if (route_map_master
.event_hook
) {
1607 (*route_map_master
.event_hook
)(index
->map
->name
);
1608 route_map_notify_dependencies(index
->map
->name
,
1609 RMAP_EVENT_CALL_ADDED
);
1611 return RMAP_COMPILE_SUCCESS
;
1614 /* Delete route map set rule. */
1615 enum rmap_compile_rets
route_map_delete_set(struct route_map_index
*index
,
1616 const char *set_name
,
1617 const char *set_arg
)
1619 struct route_map_rule
*rule
;
1620 const struct route_map_rule_cmd
*cmd
;
1622 cmd
= route_map_lookup_set(set_name
);
1624 return RMAP_RULE_MISSING
;
1626 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
1627 if ((rule
->cmd
== cmd
) && (rulecmp(rule
->rule_str
, set_arg
) == 0
1628 || set_arg
== NULL
)) {
1629 route_map_rule_delete(&index
->set_list
, rule
);
1630 /* Execute event hook. */
1631 if (route_map_master
.event_hook
) {
1632 (*route_map_master
.event_hook
)(index
->map
->name
);
1633 route_map_notify_dependencies(
1635 RMAP_EVENT_CALL_ADDED
);
1637 return RMAP_COMPILE_SUCCESS
;
1639 /* Can't find matched rule. */
1640 return RMAP_RULE_MISSING
;
1643 static enum route_map_cmd_result_t
1644 route_map_apply_match(struct route_map_rule_list
*match_list
,
1645 const struct prefix
*prefix
, void *object
)
1647 enum route_map_cmd_result_t ret
= RMAP_NOMATCH
;
1648 struct route_map_rule
*match
;
1649 bool is_matched
= false;
1652 /* Check all match rule and if there is no match rule, go to the
1654 if (!match_list
->head
)
1657 for (match
= match_list
->head
; match
; match
= match
->next
) {
1659 * Try each match statement. If any match does not
1660 * return RMAP_MATCH or RMAP_NOOP, return.
1661 * Otherwise continue on to next match statement.
1662 * All match statements must MATCH for
1663 * end-result to be a match.
1664 * (Exception:If match stmts result in a mix of
1665 * MATCH/NOOP, then also end-result is a match)
1666 * If all result in NOOP, end-result is NOOP.
1668 ret
= (*match
->cmd
->func_apply
)(match
->value
, prefix
,
1672 * If the consolidated result of func_apply is:
1673 * -----------------------------------------------
1674 * | MATCH | NOMATCH | NOOP | Final Result |
1675 * ------------------------------------------------
1676 * | yes | yes | yes | NOMATCH |
1677 * | no | no | yes | NOOP |
1678 * | yes | no | yes | MATCH |
1679 * | no | yes | yes | NOMATCH |
1680 * |-----------------------------------------------
1682 * Traditionally, all rules within route-map
1683 * should match for it to MATCH.
1684 * If there are noops within the route-map rules,
1685 * it follows the above matrix.
1687 * Eg: route-map rm1 permit 10
1692 * route-map rm1 permit 20
1720 static struct list
*route_map_get_index_list(struct route_node
**rn
,
1721 const struct prefix
*prefix
,
1722 struct route_table
*table
)
1724 struct route_node
*tmp_rn
= NULL
;
1727 *rn
= route_node_match(table
, prefix
);
1733 return (struct list
*)((*rn
)->info
);
1735 /* If rn->info is NULL, get the parent.
1736 * Store the rn in tmp_rn and unlock it later.
1742 *rn
= (*rn
)->parent
;
1744 route_unlock_node(tmp_rn
);
1750 route_lock_node(*rn
);
1751 return (struct list
*)((*rn
)->info
);
1753 } while (!(*rn
)->info
);
1759 * This function returns the route-map index that best matches the prefix.
1761 static struct route_map_index
*route_map_get_index(struct route_map
*map
,
1762 const struct prefix
*prefix
,
1767 struct list
*candidate_rmap_list
= NULL
;
1768 struct route_node
*rn
= NULL
;
1769 struct listnode
*ln
= NULL
, *nn
= NULL
;
1770 struct route_map_index
*index
= NULL
, *best_index
= NULL
;
1771 struct route_map_index
*head_index
= NULL
;
1772 struct route_table
*table
= NULL
;
1773 unsigned char family
= prefix
->family
;
1775 if (family
== AF_INET
)
1776 table
= map
->ipv4_prefix_table
;
1778 table
= map
->ipv6_prefix_table
;
1784 candidate_rmap_list
=
1785 route_map_get_index_list(&rn
, prefix
, table
);
1789 /* If the index at the head of the list is of seq higher
1790 * than that in best_index, ignore the list and get the
1791 * parent node's list.
1793 head_index
= (struct route_map_index
*)(listgetdata(
1794 listhead(candidate_rmap_list
)));
1795 if (best_index
&& head_index
1796 && (best_index
->pref
< head_index
->pref
)) {
1797 route_unlock_node(rn
);
1801 for (ALL_LIST_ELEMENTS(candidate_rmap_list
, ln
, nn
, index
)) {
1802 /* If the index is of seq higher than that in
1803 * best_index, ignore the list and get the parent
1806 if (best_index
&& (best_index
->pref
< index
->pref
))
1809 ret
= route_map_apply_match(&index
->match_list
, prefix
,
1812 if (ret
== RMAP_MATCH
) {
1816 } else if (ret
== RMAP_NOOP
) {
1818 * If match_ret is denymatch, even if we see
1819 * more noops, we retain this return value and
1820 * return this eventually if there are no
1822 * If a best match route-map index already
1823 * exists, do not reset the match_ret.
1825 if (!best_index
&& (*match_ret
!= RMAP_NOMATCH
))
1829 * ret is RMAP_NOMATCH.
1830 * If a best match route-map index already
1831 * exists, do not reset the match_ret.
1838 route_unlock_node(rn
);
1845 static int route_map_candidate_list_cmp(struct route_map_index
*idx1
,
1846 struct route_map_index
*idx2
)
1853 return (idx1
->pref
- idx2
->pref
);
1857 * This function adds the route-map index into the default route's
1858 * route-node in the route-map's IPv4/IPv6 prefix-table.
1860 static void route_map_pfx_table_add_default(afi_t afi
,
1861 struct route_map_index
*index
)
1863 struct route_node
*rn
= NULL
;
1864 struct list
*rmap_candidate_list
= NULL
;
1866 bool updated_rn
= false;
1867 struct route_table
*table
= NULL
;
1869 memset(&p
, 0, sizeof(p
));
1870 p
.family
= afi2family(afi
);
1873 if (p
.family
== AF_INET
) {
1874 table
= index
->map
->ipv4_prefix_table
;
1876 index
->map
->ipv4_prefix_table
= route_table_init();
1878 table
= index
->map
->ipv4_prefix_table
;
1880 table
= index
->map
->ipv6_prefix_table
;
1882 index
->map
->ipv6_prefix_table
= route_table_init();
1884 table
= index
->map
->ipv6_prefix_table
;
1887 /* Add default route to table */
1888 rn
= route_node_get(table
, &p
);
1894 rmap_candidate_list
= list_new();
1895 rmap_candidate_list
->cmp
=
1896 (int (*)(void *, void *))route_map_candidate_list_cmp
;
1897 rn
->info
= rmap_candidate_list
;
1899 rmap_candidate_list
= (struct list
*)rn
->info
;
1903 listnode_add_sort_nodup(rmap_candidate_list
, index
);
1905 route_unlock_node(rn
);
1909 * This function removes the route-map index from the default route's
1910 * route-node in the route-map's IPv4/IPv6 prefix-table.
1912 static void route_map_pfx_table_del_default(afi_t afi
,
1913 struct route_map_index
*index
)
1915 struct route_node
*rn
= NULL
;
1916 struct list
*rmap_candidate_list
= NULL
;
1918 struct route_table
*table
= NULL
;
1920 memset(&p
, 0, sizeof(p
));
1921 p
.family
= afi2family(afi
);
1924 if (p
.family
== AF_INET
)
1925 table
= index
->map
->ipv4_prefix_table
;
1927 table
= index
->map
->ipv6_prefix_table
;
1929 /* Remove RMAP index from default route in table */
1930 rn
= route_node_lookup(table
, &p
);
1931 if (!rn
|| !rn
->info
)
1934 rmap_candidate_list
= (struct list
*)rn
->info
;
1936 listnode_delete(rmap_candidate_list
, index
);
1938 if (listcount(rmap_candidate_list
) == 0) {
1939 list_delete(&rmap_candidate_list
);
1941 route_unlock_node(rn
);
1943 route_unlock_node(rn
);
1947 * This function adds the route-map index to the route-node for
1948 * the prefix-entry in the route-map's IPv4/IPv6 prefix-table.
1950 static void route_map_pfx_table_add(struct route_table
*table
,
1951 struct route_map_index
*index
,
1952 struct prefix_list_entry
*pentry
)
1954 struct route_node
*rn
= NULL
;
1955 struct list
*rmap_candidate_list
= NULL
;
1956 bool updated_rn
= false;
1958 rn
= route_node_get(table
, &pentry
->prefix
);
1963 rmap_candidate_list
= list_new();
1964 rmap_candidate_list
->cmp
=
1965 (int (*)(void *, void *))route_map_candidate_list_cmp
;
1966 rn
->info
= rmap_candidate_list
;
1968 rmap_candidate_list
= (struct list
*)rn
->info
;
1972 listnode_add_sort_nodup(rmap_candidate_list
, index
);
1974 route_unlock_node(rn
);
1978 * This function removes the route-map index from the route-node for
1979 * the prefix-entry in the route-map's IPv4/IPv6 prefix-table.
1981 static void route_map_pfx_table_del(struct route_table
*table
,
1982 struct route_map_index
*index
,
1983 struct prefix_list_entry
*pentry
)
1985 struct route_node
*rn
= NULL
;
1986 struct list
*rmap_candidate_list
= NULL
;
1988 rn
= route_node_lookup(table
, &pentry
->prefix
);
1989 if (!rn
|| !rn
->info
)
1992 rmap_candidate_list
= (struct list
*)rn
->info
;
1994 listnode_delete(rmap_candidate_list
, index
);
1996 if (listcount(rmap_candidate_list
) == 0) {
1997 list_delete(&rmap_candidate_list
);
1999 route_unlock_node(rn
);
2001 route_unlock_node(rn
);
2004 /* This function checks for the presence of an IPv4 prefix-list
2005 * match rule in the given route-map index.
2007 static bool route_map_is_ip_pfx_list_rule_present(struct route_map_index
*index
)
2009 struct route_map_rule_list
*match_list
= NULL
;
2010 struct route_map_rule
*rule
= NULL
;
2012 match_list
= &index
->match_list
;
2013 for (rule
= match_list
->head
; rule
; rule
= rule
->next
)
2014 if (IS_RULE_IPv4_PREFIX_LIST(rule
->cmd
->str
))
2020 /* This function checks for the presence of an IPv6 prefix-list
2021 * match rule in the given route-map index.
2024 route_map_is_ipv6_pfx_list_rule_present(struct route_map_index
*index
)
2026 struct route_map_rule_list
*match_list
= NULL
;
2027 struct route_map_rule
*rule
= NULL
;
2029 match_list
= &index
->match_list
;
2030 for (rule
= match_list
->head
; rule
; rule
= rule
->next
)
2031 if (IS_RULE_IPv6_PREFIX_LIST(rule
->cmd
->str
))
2037 /* This function does the following:
2038 * 1) If plist_name is not present, search for a IPv4 or IPv6 prefix-list
2039 * match clause (based on the afi passed to this foo) and get the
2041 * 2) Look up the prefix-list using the name.
2042 * 3) If the prefix-list is not found then, add the index to the IPv4/IPv6
2043 * default-route's node in the trie (based on the afi passed to this foo).
2044 * 4) If the prefix-list is found then, remove the index from the IPv4/IPv6
2045 * default-route's node in the trie (based on the afi passed to this foo).
2046 * 5) If a prefix-entry is passed then, create a route-node for this entry and
2047 * add this index to the route-node.
2048 * 6) If prefix-entry is not passed then, for every prefix-entry in the
2049 * prefix-list, create a route-node for this entry and
2050 * add this index to the route-node.
2052 static void route_map_add_plist_entries(afi_t afi
,
2053 struct route_map_index
*index
,
2054 const char *plist_name
,
2055 struct prefix_list_entry
*entry
)
2057 struct route_map_rule_list
*match_list
= NULL
;
2058 struct route_map_rule
*match
= NULL
;
2059 struct prefix_list
*plist
= NULL
;
2060 struct prefix_list_entry
*pentry
= NULL
;
2061 bool plist_rule_is_present
= false;
2064 match_list
= &index
->match_list
;
2066 for (match
= match_list
->head
; match
; match
= match
->next
) {
2067 if (afi
== AFI_IP
) {
2068 if (IS_RULE_IPv4_PREFIX_LIST(match
->cmd
->str
)) {
2069 plist_rule_is_present
= true;
2073 if (IS_RULE_IPv6_PREFIX_LIST(match
->cmd
->str
)) {
2074 plist_rule_is_present
= true;
2080 if (plist_rule_is_present
)
2081 plist
= prefix_list_lookup(afi
, match
->rule_str
);
2083 plist
= prefix_list_lookup(afi
, plist_name
);
2087 route_map_pfx_table_add_default(afi
, index
);
2091 /* Default entry should be deleted only if the first entry of the
2092 * prefix-list is created.
2095 if (plist
->count
== 1)
2096 route_map_pfx_table_del_default(afi
, index
);
2098 route_map_pfx_table_del_default(afi
, index
);
2102 if (afi
== AFI_IP
) {
2103 route_map_pfx_table_add(index
->map
->ipv4_prefix_table
,
2106 route_map_pfx_table_add(index
->map
->ipv6_prefix_table
,
2110 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
2111 if (afi
== AFI_IP
) {
2112 route_map_pfx_table_add(
2113 index
->map
->ipv4_prefix_table
, index
,
2116 route_map_pfx_table_add(
2117 index
->map
->ipv6_prefix_table
, index
,
2124 /* This function does the following:
2125 * 1) If plist_name is not present, search for a IPv4 or IPv6 prefix-list
2126 * match clause (based on the afi passed to this foo) and get the
2128 * 2) Look up the prefix-list using the name.
2129 * 3) If the prefix-list is not found then, delete the index from the IPv4/IPv6
2130 * default-route's node in the trie (based on the afi passed to this foo).
2131 * 4) If a prefix-entry is passed then, remove this index from the route-node
2132 * for the prefix in this prefix-entry.
2133 * 5) If prefix-entry is not passed then, for every prefix-entry in the
2134 * prefix-list, remove this index from the route-node
2135 * for the prefix in this prefix-entry.
2137 static void route_map_del_plist_entries(afi_t afi
,
2138 struct route_map_index
*index
,
2139 const char *plist_name
,
2140 struct prefix_list_entry
*entry
)
2142 struct route_map_rule_list
*match_list
= NULL
;
2143 struct route_map_rule
*match
= NULL
;
2144 struct prefix_list
*plist
= NULL
;
2145 struct prefix_list_entry
*pentry
= NULL
;
2146 bool plist_rule_is_present
= false;
2149 match_list
= &index
->match_list
;
2151 for (match
= match_list
->head
; match
; match
= match
->next
) {
2152 if (afi
== AFI_IP
) {
2153 if (IS_RULE_IPv4_PREFIX_LIST(match
->cmd
->str
)) {
2154 plist_rule_is_present
= true;
2158 if (IS_RULE_IPv6_PREFIX_LIST(match
->cmd
->str
)) {
2159 plist_rule_is_present
= true;
2165 if (plist_rule_is_present
)
2166 plist
= prefix_list_lookup(afi
, match
->rule_str
);
2168 plist
= prefix_list_lookup(afi
, plist_name
);
2172 route_map_pfx_table_del_default(afi
, index
);
2177 if (afi
== AFI_IP
) {
2178 route_map_pfx_table_del(index
->map
->ipv4_prefix_table
,
2181 route_map_pfx_table_del(index
->map
->ipv6_prefix_table
,
2185 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
2186 if (afi
== AFI_IP
) {
2187 route_map_pfx_table_del(
2188 index
->map
->ipv4_prefix_table
, index
,
2191 route_map_pfx_table_del(
2192 index
->map
->ipv6_prefix_table
, index
,
2200 * This function handles the cases where a prefix-list is added/removed
2201 * as a match command from a particular route-map index.
2202 * It updates the prefix-table of the route-map accordingly.
2204 static void route_map_trie_update(afi_t afi
, route_map_event_t event
,
2205 struct route_map_index
*index
,
2206 const char *plist_name
)
2208 if (event
== RMAP_EVENT_PLIST_ADDED
) {
2209 if (afi
== AFI_IP
) {
2210 if (!route_map_is_ipv6_pfx_list_rule_present(index
)) {
2211 route_map_pfx_table_del_default(AFI_IP6
, index
);
2212 route_map_add_plist_entries(afi
, index
,
2215 route_map_del_plist_entries(AFI_IP6
, index
,
2219 if (!route_map_is_ip_pfx_list_rule_present(index
)) {
2220 route_map_pfx_table_del_default(AFI_IP
, index
);
2221 route_map_add_plist_entries(afi
, index
,
2224 route_map_del_plist_entries(AFI_IP
, index
, NULL
,
2228 } else if (event
== RMAP_EVENT_PLIST_DELETED
) {
2229 if (afi
== AFI_IP
) {
2230 route_map_del_plist_entries(afi
, index
, plist_name
,
2233 /* If IPv6 prefix-list match rule is not present,
2234 * add this index to the IPv4 default route's trie
2236 * Also, add this index to the trie nodes created
2237 * for each of the prefix-entries within the IPv6
2238 * prefix-list, if the IPv6 prefix-list match rule
2239 * is present. Else, add this index to the IPv6
2240 * default route's trie node.
2242 if (!route_map_is_ipv6_pfx_list_rule_present(index
))
2243 route_map_pfx_table_add_default(afi
, index
);
2245 route_map_add_plist_entries(AFI_IP6
, index
, NULL
, NULL
);
2247 route_map_del_plist_entries(afi
, index
, plist_name
,
2250 /* If IPv4 prefix-list match rule is not present,
2251 * add this index to the IPv6 default route's trie
2253 * Also, add this index to the trie nodes created
2254 * for each of the prefix-entries within the IPv4
2255 * prefix-list, if the IPv4 prefix-list match rule
2256 * is present. Else, add this index to the IPv4
2257 * default route's trie node.
2259 if (!route_map_is_ip_pfx_list_rule_present(index
))
2260 route_map_pfx_table_add_default(afi
, index
);
2262 route_map_add_plist_entries(AFI_IP
, index
, NULL
, NULL
);
2268 * This function handles the cases where a route-map index and
2269 * prefix-list is added/removed.
2270 * It updates the prefix-table of the route-map accordingly.
2272 static void route_map_pfx_tbl_update(route_map_event_t event
,
2273 struct route_map_index
*index
, afi_t afi
,
2274 const char *plist_name
)
2276 struct route_map
*rmap
= NULL
;
2281 if (event
== RMAP_EVENT_INDEX_ADDED
) {
2282 route_map_pfx_table_add_default(AFI_IP
, index
);
2283 route_map_pfx_table_add_default(AFI_IP6
, index
);
2287 if (event
== RMAP_EVENT_INDEX_DELETED
) {
2288 route_map_pfx_table_del_default(AFI_IP
, index
);
2289 route_map_pfx_table_del_default(AFI_IP6
, index
);
2291 if ((index
->map
->head
== NULL
) && (index
->map
->tail
== NULL
)) {
2294 if (rmap
->ipv4_prefix_table
) {
2295 route_table_finish(rmap
->ipv4_prefix_table
);
2296 rmap
->ipv4_prefix_table
= NULL
;
2299 if (rmap
->ipv6_prefix_table
) {
2300 route_table_finish(rmap
->ipv6_prefix_table
);
2301 rmap
->ipv6_prefix_table
= NULL
;
2307 /* Handle prefix-list match rule addition/deletion.
2309 route_map_trie_update(afi
, event
, index
, plist_name
);
2313 * This function handles the cases where a new prefix-entry is added to
2314 * a prefix-list or, an existing prefix-entry is removed from the prefix-list.
2315 * It updates the prefix-table of the route-map accordingly.
2317 static void route_map_pentry_update(route_map_event_t event
,
2318 const char *plist_name
,
2319 struct route_map_index
*index
,
2320 struct prefix_list_entry
*pentry
)
2322 struct prefix_list
*plist
= NULL
;
2324 unsigned char family
= pentry
->prefix
.family
;
2326 if (family
== AF_INET
) {
2328 plist
= prefix_list_lookup(AFI_IP
, plist_name
);
2331 plist
= prefix_list_lookup(AFI_IP6
, plist_name
);
2334 if (event
== RMAP_EVENT_PLIST_ADDED
) {
2335 if (afi
== AFI_IP
) {
2336 if (!route_map_is_ipv6_pfx_list_rule_present(index
))
2337 route_map_add_plist_entries(afi
, index
,
2338 plist_name
, pentry
);
2340 if (!route_map_is_ip_pfx_list_rule_present(index
))
2341 route_map_add_plist_entries(afi
, index
,
2342 plist_name
, pentry
);
2344 } else if (event
== RMAP_EVENT_PLIST_DELETED
) {
2345 route_map_del_plist_entries(afi
, index
, plist_name
, pentry
);
2347 if (plist
->count
== 1) {
2348 if (afi
== AFI_IP
) {
2349 if (!route_map_is_ipv6_pfx_list_rule_present(
2351 route_map_pfx_table_add_default(afi
,
2354 if (!route_map_is_ip_pfx_list_rule_present(
2356 route_map_pfx_table_add_default(afi
,
2363 static void route_map_pentry_process_dependency(struct hash_bucket
*bucket
,
2366 char *rmap_name
= NULL
;
2367 struct route_map
*rmap
= NULL
;
2368 struct route_map_index
*index
= NULL
;
2369 struct route_map_rule_list
*match_list
= NULL
;
2370 struct route_map_rule
*match
= NULL
;
2371 struct route_map_dep_data
*dep_data
= NULL
;
2372 struct route_map_pentry_dep
*pentry_dep
=
2373 (struct route_map_pentry_dep
*)data
;
2374 unsigned char family
= pentry_dep
->pentry
->prefix
.family
;
2376 dep_data
= (struct route_map_dep_data
*)bucket
->data
;
2380 rmap_name
= dep_data
->rname
;
2381 rmap
= route_map_lookup_by_name(rmap_name
);
2382 if (!rmap
|| !rmap
->head
)
2385 for (index
= rmap
->head
; index
; index
= index
->next
) {
2386 match_list
= &index
->match_list
;
2391 for (match
= match_list
->head
; match
; match
= match
->next
) {
2392 if (strcmp(match
->rule_str
, pentry_dep
->plist_name
)
2394 if (IS_RULE_IPv4_PREFIX_LIST(match
->cmd
->str
)
2395 && family
== AF_INET
) {
2396 route_map_pentry_update(
2398 pentry_dep
->plist_name
, index
,
2399 pentry_dep
->pentry
);
2400 } else if (IS_RULE_IPv6_PREFIX_LIST(
2402 && family
== AF_INET6
) {
2403 route_map_pentry_update(
2405 pentry_dep
->plist_name
, index
,
2406 pentry_dep
->pentry
);
2413 void route_map_notify_pentry_dependencies(const char *affected_name
,
2414 struct prefix_list_entry
*pentry
,
2415 route_map_event_t event
)
2417 struct route_map_dep
*dep
= NULL
;
2418 struct hash
*upd8_hash
= NULL
;
2419 struct route_map_pentry_dep pentry_dep
;
2421 if (!affected_name
|| !pentry
)
2424 upd8_hash
= route_map_get_dep_hash(event
);
2428 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, (void *)affected_name
,
2431 if (!dep
->this_hash
)
2432 dep
->this_hash
= upd8_hash
;
2434 memset(&pentry_dep
, 0, sizeof(struct route_map_pentry_dep
));
2435 pentry_dep
.pentry
= pentry
;
2436 pentry_dep
.plist_name
= affected_name
;
2437 pentry_dep
.event
= event
;
2439 hash_iterate(dep
->dep_rmap_hash
,
2440 route_map_pentry_process_dependency
,
2441 (void *)&pentry_dep
);
2445 /* Apply route map's each index to the object.
2447 The matrix for a route-map looks like this:
2448 (note, this includes the description for the "NEXT"
2449 and "GOTO" frobs now
2451 | Match | No Match | No op
2452 |-----------|--------------|-------
2453 permit | action | cont | cont.
2454 | | default:deny | default:permit
2455 -------------------+-----------------------
2456 | deny | cont | cont.
2457 deny | | default:deny | default:permit
2458 |-----------|--------------|--------
2461 -Apply Set statements, accept route
2462 -If Call statement is present jump to the specified route-map, if it
2463 denies the route we finish.
2464 -If NEXT is specified, goto NEXT statement
2465 -If GOTO is specified, goto the first clause where pref > nextpref
2466 -If nothing is specified, do as Cisco and finish
2468 -Route is denied by route-map.
2472 If we get no matches after we've processed all updates, then the route
2475 Some notes on the new "CALL", "NEXT" and "GOTO"
2476 call WORD - If this clause is matched, then the set statements
2477 are executed and then we jump to route-map 'WORD'. If
2478 this route-map denies the route, we finish, in other
2480 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
2481 on-match next - If this clause is matched, then the set statements
2482 are executed and then we drop through to the next clause
2483 on-match goto n - If this clause is matched, then the set statements
2484 are executed and then we goto the nth clause, or the
2485 first clause greater than this. In order to ensure
2486 route-maps *always* exit, you cannot jump backwards.
2489 We need to make sure our route-map processing matches the above
2491 route_map_result_t
route_map_apply_ext(struct route_map
*map
,
2492 const struct prefix
*prefix
,
2493 void *match_object
, void *set_object
)
2495 static int recursion
= 0;
2496 enum route_map_cmd_result_t match_ret
= RMAP_NOMATCH
;
2497 route_map_result_t ret
= RMAP_PERMITMATCH
;
2498 struct route_map_index
*index
= NULL
;
2499 struct route_map_rule
*set
= NULL
;
2500 bool skip_match_clause
= false;
2502 if (recursion
> RMAP_RECURSION_LIMIT
) {
2504 EC_LIB_RMAP_RECURSION_LIMIT
,
2505 "route-map recursion limit (%d) reached, discarding route",
2506 RMAP_RECURSION_LIMIT
);
2508 return RMAP_DENYMATCH
;
2511 if (map
== NULL
|| map
->head
== NULL
) {
2512 ret
= RMAP_DENYMATCH
;
2513 goto route_map_apply_end
;
2518 if ((!map
->optimization_disabled
)
2519 && (map
->ipv4_prefix_table
|| map
->ipv6_prefix_table
)) {
2520 index
= route_map_get_index(map
, prefix
, match_object
,
2521 (uint8_t *)&match_ret
);
2526 "Best match route-map: %s, sequence: %d for pfx: %pFX, result: %s",
2527 map
->name
, index
->pref
, prefix
,
2528 route_map_cmd_result_str(match_ret
));
2532 "No best match sequence for pfx: %pFX in route-map: %s, result: %s",
2534 route_map_cmd_result_str(match_ret
));
2536 * No index matches this prefix. Return deny unless,
2537 * match_ret = RMAP_NOOP.
2539 if (match_ret
== RMAP_NOOP
)
2540 ret
= RMAP_PERMITMATCH
;
2542 ret
= RMAP_DENYMATCH
;
2543 goto route_map_apply_end
;
2545 skip_match_clause
= true;
2550 for (; index
; index
= index
->next
) {
2551 if (!skip_match_clause
) {
2553 /* Apply this index. */
2554 match_ret
= route_map_apply_match(&index
->match_list
,
2555 prefix
, match_object
);
2558 "Route-map: %s, sequence: %d, prefix: %pFX, result: %s",
2559 map
->name
, index
->pref
, prefix
,
2560 route_map_cmd_result_str(match_ret
));
2563 skip_match_clause
= false;
2566 /* Now we apply the matrix from above */
2567 if (match_ret
== RMAP_NOOP
)
2569 * Do not change the return value. Retain the previous
2570 * return value. Previous values can be:
2571 * 1)permitmatch (if a nomatch was never
2572 * seen before in this route-map.)
2573 * 2)denymatch (if a nomatch was seen earlier in one
2574 * of the previous sequences)
2578 * 'cont' from matrix - continue to next route-map
2582 else if (match_ret
== RMAP_NOMATCH
) {
2585 * The return value is now changed to denymatch.
2586 * So from here on out, even if we see more noops,
2587 * we retain this return value and return this
2588 * eventually if there are no matches.
2590 ret
= RMAP_DENYMATCH
;
2593 * 'cont' from matrix - continue to next route-map
2597 } else if (match_ret
== RMAP_MATCH
) {
2598 if (index
->type
== RMAP_PERMIT
)
2601 /* Match succeeded, rmap is of type permit */
2602 ret
= RMAP_PERMITMATCH
;
2604 /* permit+match must execute sets */
2605 for (set
= index
->set_list
.head
; set
;
2608 * set cmds return RMAP_OKAY or
2609 * RMAP_ERROR. We do not care if
2610 * set succeeded or not. So, ignore
2613 (void)(*set
->cmd
->func_apply
)(
2614 set
->value
, prefix
, set_object
);
2616 /* Call another route-map if available */
2617 if (index
->nextrm
) {
2618 struct route_map
*nextrm
=
2619 route_map_lookup_by_name(
2622 if (nextrm
) /* Target route-map found,
2626 ret
= route_map_apply_ext(
2633 /* If nextrm returned 'deny', finish. */
2634 if (ret
== RMAP_DENYMATCH
)
2635 goto route_map_apply_end
;
2638 switch (index
->exitpolicy
) {
2640 goto route_map_apply_end
;
2644 /* Find the next clause to jump to */
2645 struct route_map_index
*next
=
2647 int nextpref
= index
->nextpref
;
2649 while (next
&& next
->pref
< nextpref
) {
2654 /* No clauses match! */
2655 goto route_map_apply_end
;
2659 } else if (index
->type
== RMAP_DENY
)
2662 ret
= RMAP_DENYMATCH
;
2663 goto route_map_apply_end
;
2668 route_map_apply_end
:
2670 zlog_debug("Route-map: %s, prefix: %pFX, result: %s",
2671 (map
? map
->name
: "null"), prefix
,
2672 route_map_result_str(ret
));
2677 void route_map_add_hook(void (*func
)(const char *))
2679 route_map_master
.add_hook
= func
;
2682 void route_map_delete_hook(void (*func
)(const char *))
2684 route_map_master
.delete_hook
= func
;
2687 void route_map_event_hook(void (*func
)(const char *name
))
2689 route_map_master
.event_hook
= func
;
2692 /* Routines for route map dependency lists and dependency processing */
2693 static bool route_map_rmap_hash_cmp(const void *p1
, const void *p2
)
2695 return strcmp(((const struct route_map_dep_data
*)p1
)->rname
,
2696 ((const struct route_map_dep_data
*)p2
)->rname
)
2700 static bool route_map_dep_hash_cmp(const void *p1
, const void *p2
)
2703 return (strcmp(((const struct route_map_dep
*)p1
)->dep_name
,
2708 static void route_map_clear_reference(struct hash_bucket
*bucket
, void *arg
)
2710 struct route_map_dep
*dep
= bucket
->data
;
2711 struct route_map_dep_data
*dep_data
= NULL
, tmp_dep_data
;
2713 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
2714 tmp_dep_data
.rname
= arg
;
2715 dep_data
= hash_release(dep
->dep_rmap_hash
, &tmp_dep_data
);
2718 zlog_debug("Clearing reference for %s to %s count: %d",
2719 dep
->dep_name
, tmp_dep_data
.rname
,
2722 XFREE(MTYPE_ROUTE_MAP_NAME
, dep_data
->rname
);
2723 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, dep_data
);
2725 if (!dep
->dep_rmap_hash
->count
) {
2726 dep
= hash_release(dep
->this_hash
, (void *)dep
->dep_name
);
2727 hash_free(dep
->dep_rmap_hash
);
2728 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
2729 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
2733 static void route_map_clear_all_references(char *rmap_name
)
2738 zlog_debug("Clearing references for %s", rmap_name
);
2740 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
2741 hash_iterate(route_map_dep_hash
[i
], route_map_clear_reference
,
2746 static unsigned int route_map_dep_data_hash_make_key(const void *p
)
2748 const struct route_map_dep_data
*dep_data
= p
;
2750 return string_hash_make(dep_data
->rname
);
2753 static void *route_map_dep_hash_alloc(void *p
)
2755 char *dep_name
= (char *)p
;
2756 struct route_map_dep
*dep_entry
;
2758 dep_entry
= XCALLOC(MTYPE_ROUTE_MAP_DEP
, sizeof(struct route_map_dep
));
2759 dep_entry
->dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
2760 dep_entry
->dep_rmap_hash
=
2761 hash_create_size(8, route_map_dep_data_hash_make_key
,
2762 route_map_rmap_hash_cmp
, "Route Map Dep Hash");
2763 dep_entry
->this_hash
= NULL
;
2768 static void *route_map_name_hash_alloc(void *p
)
2770 struct route_map_dep_data
*dep_data
= NULL
, *tmp_dep_data
= NULL
;
2772 dep_data
= XCALLOC(MTYPE_ROUTE_MAP_DEP_DATA
,
2773 sizeof(struct route_map_dep_data
));
2775 dep_data
->rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, tmp_dep_data
->rname
);
2779 static unsigned int route_map_dep_hash_make_key(const void *p
)
2781 return (string_hash_make((char *)p
));
2784 static void route_map_print_dependency(struct hash_bucket
*bucket
, void *data
)
2786 struct route_map_dep_data
*dep_data
= bucket
->data
;
2787 char *rmap_name
= dep_data
->rname
;
2788 char *dep_name
= data
;
2790 zlog_debug("%s: Dependency for %s: %s", __func__
, dep_name
, rmap_name
);
2793 static int route_map_dep_update(struct hash
*dephash
, const char *dep_name
,
2794 const char *rmap_name
, route_map_event_t type
)
2796 struct route_map_dep
*dep
= NULL
;
2797 char *dname
, *rname
;
2799 struct route_map_dep_data
*dep_data
= NULL
, *ret_dep_data
= NULL
;
2800 struct route_map_dep_data tmp_dep_data
;
2802 dname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
2803 rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
2806 case RMAP_EVENT_PLIST_ADDED
:
2807 case RMAP_EVENT_CLIST_ADDED
:
2808 case RMAP_EVENT_ECLIST_ADDED
:
2809 case RMAP_EVENT_ASLIST_ADDED
:
2810 case RMAP_EVENT_LLIST_ADDED
:
2811 case RMAP_EVENT_CALL_ADDED
:
2812 case RMAP_EVENT_FILTER_ADDED
:
2814 zlog_debug("Adding dependency for filter %s in route-map %s",
2815 dep_name
, rmap_name
);
2816 dep
= (struct route_map_dep
*)hash_get(
2817 dephash
, dname
, route_map_dep_hash_alloc
);
2823 if (!dep
->this_hash
)
2824 dep
->this_hash
= dephash
;
2826 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
2827 tmp_dep_data
.rname
= rname
;
2828 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
2830 dep_data
= hash_get(dep
->dep_rmap_hash
, &tmp_dep_data
,
2831 route_map_name_hash_alloc
);
2835 case RMAP_EVENT_PLIST_DELETED
:
2836 case RMAP_EVENT_CLIST_DELETED
:
2837 case RMAP_EVENT_ECLIST_DELETED
:
2838 case RMAP_EVENT_ASLIST_DELETED
:
2839 case RMAP_EVENT_LLIST_DELETED
:
2840 case RMAP_EVENT_CALL_DELETED
:
2841 case RMAP_EVENT_FILTER_DELETED
:
2843 zlog_debug("Deleting dependency for filter %s in route-map %s",
2844 dep_name
, rmap_name
);
2845 dep
= (struct route_map_dep
*)hash_get(dephash
, dname
, NULL
);
2850 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
2851 tmp_dep_data
.rname
= rname
;
2852 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
2854 * If dep_data is NULL then something has gone seriously
2855 * wrong in route-map handling. Note it and prevent
2860 "route-map dependency for route-map %s: %s is not correct",
2861 rmap_name
, dep_name
);
2867 if (!dep_data
->refcnt
) {
2868 ret_dep_data
= hash_release(dep
->dep_rmap_hash
,
2871 XFREE(MTYPE_ROUTE_MAP_NAME
,
2872 ret_dep_data
->rname
);
2873 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, ret_dep_data
);
2877 if (!dep
->dep_rmap_hash
->count
) {
2878 dep
= hash_release(dephash
, dname
);
2879 hash_free(dep
->dep_rmap_hash
);
2880 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
2881 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
2884 case RMAP_EVENT_SET_ADDED
:
2885 case RMAP_EVENT_SET_DELETED
:
2886 case RMAP_EVENT_SET_REPLACED
:
2887 case RMAP_EVENT_MATCH_ADDED
:
2888 case RMAP_EVENT_MATCH_DELETED
:
2889 case RMAP_EVENT_MATCH_REPLACED
:
2890 case RMAP_EVENT_INDEX_ADDED
:
2891 case RMAP_EVENT_INDEX_DELETED
:
2897 hash_iterate(dep
->dep_rmap_hash
,
2898 route_map_print_dependency
, dname
);
2902 XFREE(MTYPE_ROUTE_MAP_NAME
, rname
);
2903 XFREE(MTYPE_ROUTE_MAP_NAME
, dname
);
2907 static struct hash
*route_map_get_dep_hash(route_map_event_t event
)
2909 struct hash
*upd8_hash
= NULL
;
2912 case RMAP_EVENT_PLIST_ADDED
:
2913 case RMAP_EVENT_PLIST_DELETED
:
2914 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_PLIST
];
2916 case RMAP_EVENT_CLIST_ADDED
:
2917 case RMAP_EVENT_CLIST_DELETED
:
2918 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_CLIST
];
2920 case RMAP_EVENT_ECLIST_ADDED
:
2921 case RMAP_EVENT_ECLIST_DELETED
:
2922 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ECLIST
];
2924 case RMAP_EVENT_ASLIST_ADDED
:
2925 case RMAP_EVENT_ASLIST_DELETED
:
2926 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ASPATH
];
2928 case RMAP_EVENT_LLIST_ADDED
:
2929 case RMAP_EVENT_LLIST_DELETED
:
2930 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_LCLIST
];
2932 case RMAP_EVENT_CALL_ADDED
:
2933 case RMAP_EVENT_CALL_DELETED
:
2934 case RMAP_EVENT_MATCH_ADDED
:
2935 case RMAP_EVENT_MATCH_DELETED
:
2936 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_RMAP
];
2938 case RMAP_EVENT_FILTER_ADDED
:
2939 case RMAP_EVENT_FILTER_DELETED
:
2940 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_FILTER
];
2943 * Should we actually be ignoring these?
2944 * I am not sure but at this point in time, let
2945 * us get them into this switch and we can peel
2946 * them into the appropriate place in the future
2948 case RMAP_EVENT_SET_ADDED
:
2949 case RMAP_EVENT_SET_DELETED
:
2950 case RMAP_EVENT_SET_REPLACED
:
2951 case RMAP_EVENT_MATCH_REPLACED
:
2952 case RMAP_EVENT_INDEX_ADDED
:
2953 case RMAP_EVENT_INDEX_DELETED
:
2960 static void route_map_process_dependency(struct hash_bucket
*bucket
, void *data
)
2962 struct route_map_dep_data
*dep_data
= NULL
;
2963 char *rmap_name
= NULL
;
2965 dep_data
= bucket
->data
;
2966 rmap_name
= dep_data
->rname
;
2969 zlog_debug("Notifying %s of dependency", rmap_name
);
2970 if (route_map_master
.event_hook
)
2971 (*route_map_master
.event_hook
)(rmap_name
);
2974 void route_map_upd8_dependency(route_map_event_t type
, const char *arg
,
2975 const char *rmap_name
)
2977 struct hash
*upd8_hash
= NULL
;
2979 if ((upd8_hash
= route_map_get_dep_hash(type
))) {
2980 route_map_dep_update(upd8_hash
, arg
, rmap_name
, type
);
2982 if (type
== RMAP_EVENT_CALL_ADDED
) {
2984 if (route_map_master
.add_hook
)
2985 (*route_map_master
.add_hook
)(rmap_name
);
2986 } else if (type
== RMAP_EVENT_CALL_DELETED
) {
2988 if (route_map_master
.delete_hook
)
2989 (*route_map_master
.delete_hook
)(rmap_name
);
2994 void route_map_notify_dependencies(const char *affected_name
,
2995 route_map_event_t event
)
2997 struct route_map_dep
*dep
;
2998 struct hash
*upd8_hash
;
3004 name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, affected_name
);
3006 if ((upd8_hash
= route_map_get_dep_hash(event
)) == NULL
) {
3007 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
3011 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, name
, NULL
);
3013 if (!dep
->this_hash
)
3014 dep
->this_hash
= upd8_hash
;
3017 zlog_debug("Filter %s updated", dep
->dep_name
);
3018 hash_iterate(dep
->dep_rmap_hash
, route_map_process_dependency
,
3022 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
3025 /* VTY related functions. */
3026 static void clear_route_map_helper(struct route_map
*map
)
3028 struct route_map_index
*index
;
3030 map
->applied_clear
= map
->applied
;
3031 for (index
= map
->head
; index
; index
= index
->next
)
3032 index
->applied_clear
= index
->applied
;
3035 DEFUN (rmap_clear_counters
,
3036 rmap_clear_counters_cmd
,
3037 "clear route-map counters [WORD]",
3039 "route-map information\n"
3040 "counters associated with the specified route-map\n"
3044 struct route_map
*map
;
3046 const char *name
= (argc
== 3 ) ? argv
[idx_word
]->arg
: NULL
;
3049 map
= route_map_lookup_by_name(name
);
3052 clear_route_map_helper(map
);
3054 vty_out(vty
, "%s: 'route-map %s' not found\n",
3055 frr_protonameinst
, name
);
3059 for (map
= route_map_master
.head
; map
; map
= map
->next
)
3060 clear_route_map_helper(map
);
3067 DEFUN (rmap_show_name
,
3069 "show route-map [WORD] [json]",
3071 "route-map information\n"
3075 bool uj
= use_json(argc
, argv
);
3077 const char *name
= NULL
;
3079 if (argv_find(argv
, argc
, "WORD", &idx
))
3080 name
= argv
[idx
]->arg
;
3082 return vty_show_route_map(vty
, name
, uj
);
3085 DEFUN (rmap_show_unused
,
3086 rmap_show_unused_cmd
,
3087 "show route-map-unused",
3089 "unused route-map information\n")
3091 return vty_show_unused_route_map(vty
);
3098 "Debug option set for route-maps\n")
3104 DEFUN (no_debug_rmap
,
3106 "no debug route-map",
3109 "Debug option set for route-maps\n")
3116 static int rmap_config_write_debug(struct vty
*vty
);
3117 static struct cmd_node rmap_debug_node
= {
3118 .name
= "route-map debug",
3119 .node
= RMAP_DEBUG_NODE
,
3121 .config_write
= rmap_config_write_debug
,
3124 /* Configuration write function. */
3125 static int rmap_config_write_debug(struct vty
*vty
)
3130 vty_out(vty
, "debug route-map\n");
3137 /* Common route map rules */
3139 void *route_map_rule_tag_compile(const char *arg
)
3141 unsigned long int tmp
;
3146 tmp
= strtoul(arg
, &endptr
, 0);
3147 if (arg
[0] == '\0' || *endptr
!= '\0' || errno
|| tmp
> ROUTE_TAG_MAX
)
3150 tag
= XMALLOC(MTYPE_ROUTE_MAP_COMPILED
, sizeof(*tag
));
3156 void route_map_rule_tag_free(void *rule
)
3158 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
3161 void route_map_finish(void)
3165 vector_free(route_match_vec
);
3166 route_match_vec
= NULL
;
3167 vector_free(route_set_vec
);
3168 route_set_vec
= NULL
;
3171 * All protocols are setting these to NULL
3172 * by default on shutdown( route_map_finish )
3173 * Why are we making them do this work?
3175 route_map_master
.add_hook
= NULL
;
3176 route_map_master
.delete_hook
= NULL
;
3177 route_map_master
.event_hook
= NULL
;
3179 /* cleanup route_map */
3180 while (route_map_master
.head
) {
3181 struct route_map
*map
= route_map_master
.head
;
3182 map
->to_be_processed
= false;
3183 route_map_delete(map
);
3186 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
3187 hash_free(route_map_dep_hash
[i
]);
3188 route_map_dep_hash
[i
] = NULL
;
3191 hash_free(route_map_master_hash
);
3192 route_map_master_hash
= NULL
;
3195 /* Increment the use_count counter while attaching the route map */
3196 void route_map_counter_increment(struct route_map
*map
)
3202 /* Decrement the use_count counter while detaching the route map. */
3203 void route_map_counter_decrement(struct route_map
*map
)
3206 if (map
->use_count
<= 0)
3212 DEFUN_HIDDEN(show_route_map_pfx_tbl
, show_route_map_pfx_tbl_cmd
,
3213 "show route-map WORD prefix-table",
3217 "internal prefix-table\n")
3219 const char *rmap_name
= argv
[2]->arg
;
3220 struct route_map
*rmap
= NULL
;
3221 struct route_table
*rm_pfx_tbl4
= NULL
;
3222 struct route_table
*rm_pfx_tbl6
= NULL
;
3223 struct route_node
*rn
= NULL
, *prn
= NULL
;
3224 struct list
*rmap_index_list
= NULL
;
3225 struct listnode
*ln
= NULL
, *nln
= NULL
;
3226 struct route_map_index
*index
= NULL
;
3229 vty_out(vty
, "%s:\n", frr_protonameinst
);
3230 rmap
= route_map_lookup_by_name(rmap_name
);
3232 rm_pfx_tbl4
= rmap
->ipv4_prefix_table
;
3234 vty_out(vty
, "\n%s%43s%s\n", "IPv4 Prefix", "",
3235 "Route-map Index List");
3236 vty_out(vty
, "%s%39s%s\n", "_______________", "",
3237 "____________________");
3238 for (rn
= route_top(rm_pfx_tbl4
); rn
;
3239 rn
= route_next(rn
)) {
3240 vty_out(vty
, " %pRN (%d)\n", rn
,
3241 route_node_get_lock_count(rn
));
3243 vty_out(vty
, "(P) ");
3246 vty_out(vty
, "%pRN\n", prn
);
3250 rmap_index_list
= (struct list
*)rn
->info
;
3251 if (!rmap_index_list
3252 || !listcount(rmap_index_list
))
3253 vty_out(vty
, "%*s%s\n", len
, "", "-");
3255 for (ALL_LIST_ELEMENTS(rmap_index_list
,
3258 vty_out(vty
, "%*s%s seq %d\n",
3267 rm_pfx_tbl6
= rmap
->ipv6_prefix_table
;
3269 vty_out(vty
, "\n%s%43s%s\n", "IPv6 Prefix", "",
3270 "Route-map Index List");
3271 vty_out(vty
, "%s%39s%s\n", "_______________", "",
3272 "____________________");
3273 for (rn
= route_top(rm_pfx_tbl6
); rn
;
3274 rn
= route_next(rn
)) {
3275 vty_out(vty
, " %pRN (%d)\n", rn
,
3276 route_node_get_lock_count(rn
));
3278 vty_out(vty
, "(P) ");
3281 vty_out(vty
, "%pRN\n", prn
);
3285 rmap_index_list
= (struct list
*)rn
->info
;
3286 if (!rmap_index_list
3287 || !listcount(rmap_index_list
))
3288 vty_out(vty
, "%*s%s\n", len
, "", "-");
3290 for (ALL_LIST_ELEMENTS(rmap_index_list
,
3293 vty_out(vty
, "%*s%s seq %d\n",
3307 /* Initialization of route map vector. */
3308 void route_map_init(void)
3312 /* Make vector for match and set. */
3313 route_match_vec
= vector_init(1);
3314 route_set_vec
= vector_init(1);
3315 route_map_master_hash
=
3316 hash_create_size(8, route_map_hash_key_make
, route_map_hash_cmp
,
3317 "Route Map Master Hash");
3319 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++)
3320 route_map_dep_hash
[i
] = hash_create_size(
3321 8, route_map_dep_hash_make_key
, route_map_dep_hash_cmp
,
3322 "Route Map Dep Hash");
3326 route_map_cli_init();
3328 /* Install route map top node. */
3329 install_node(&rmap_debug_node
);
3331 /* Install route map commands. */
3332 install_element(CONFIG_NODE
, &debug_rmap_cmd
);
3333 install_element(CONFIG_NODE
, &no_debug_rmap_cmd
);
3335 /* Install show command */
3336 install_element(ENABLE_NODE
, &rmap_clear_counters_cmd
);
3338 install_element(ENABLE_NODE
, &rmap_show_name_cmd
);
3339 install_element(ENABLE_NODE
, &rmap_show_unused_cmd
);
3341 install_element(ENABLE_NODE
, &debug_rmap_cmd
);
3342 install_element(ENABLE_NODE
, &no_debug_rmap_cmd
);
3344 install_element(ENABLE_NODE
, &show_route_map_pfx_tbl_cmd
);