1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 1998, 1999 Kunihiro Ishiguro
19 #include "lib_errors.h"
24 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP
, "Route map");
25 DEFINE_MTYPE(LIB
, ROUTE_MAP_NAME
, "Route map name");
26 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_INDEX
, "Route map index");
27 DEFINE_MTYPE(LIB
, ROUTE_MAP_RULE
, "Route map rule");
28 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_RULE_STR
, "Route map rule str");
29 DEFINE_MTYPE(LIB
, ROUTE_MAP_COMPILED
, "Route map compiled");
30 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_DEP
, "Route map dependency");
31 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_DEP_DATA
, "Route map dependency data");
33 DEFINE_QOBJ_TYPE(route_map_index
);
34 DEFINE_QOBJ_TYPE(route_map
);
36 static int rmap_cmd_name_cmp(const struct route_map_rule_cmd_proxy
*a
,
37 const struct route_map_rule_cmd_proxy
*b
)
39 return strcmp(a
->cmd
->str
, b
->cmd
->str
);
42 static uint32_t rmap_cmd_name_hash(const struct route_map_rule_cmd_proxy
*item
)
44 return jhash(item
->cmd
->str
, strlen(item
->cmd
->str
), 0xbfd69320);
47 DECLARE_HASH(rmap_cmd_name
, struct route_map_rule_cmd_proxy
, itm
,
48 rmap_cmd_name_cmp
, rmap_cmd_name_hash
);
50 static struct rmap_cmd_name_head rmap_match_cmds
[1] = {
51 INIT_HASH(rmap_match_cmds
[0]),
53 static struct rmap_cmd_name_head rmap_set_cmds
[1] = {
54 INIT_HASH(rmap_set_cmds
[0]),
57 #define IPv4_PREFIX_LIST "ip address prefix-list"
58 #define IPv6_PREFIX_LIST "ipv6 address prefix-list"
60 #define IS_RULE_IPv4_PREFIX_LIST(S) \
61 (strncmp(S, IPv4_PREFIX_LIST, strlen(IPv4_PREFIX_LIST)) == 0)
62 #define IS_RULE_IPv6_PREFIX_LIST(S) \
63 (strncmp(S, IPv6_PREFIX_LIST, strlen(IPv6_PREFIX_LIST)) == 0)
65 struct route_map_pentry_dep
{
66 struct prefix_list_entry
*pentry
;
67 const char *plist_name
;
68 route_map_event_t event
;
71 static void route_map_pfx_tbl_update(route_map_event_t event
,
72 struct route_map_index
*index
, afi_t afi
,
73 const char *plist_name
);
74 static void route_map_pfx_table_add_default(afi_t afi
,
75 struct route_map_index
*index
);
76 static void route_map_pfx_table_del_default(afi_t afi
,
77 struct route_map_index
*index
);
78 static void route_map_add_plist_entries(afi_t afi
,
79 struct route_map_index
*index
,
80 const char *plist_name
,
81 struct prefix_list_entry
*entry
);
82 static void route_map_del_plist_entries(afi_t afi
,
83 struct route_map_index
*index
,
84 const char *plist_name
,
85 struct prefix_list_entry
*entry
);
87 static struct hash
*route_map_get_dep_hash(route_map_event_t event
);
88 static void route_map_free_map(struct route_map
*map
);
90 struct route_map_match_set_hooks rmap_match_set_hook
;
93 void route_map_match_interface_hook(int (*func
)(
94 struct route_map_index
*index
, const char *command
,
95 const char *arg
, route_map_event_t type
,
96 char *errmsg
, size_t errmsg_len
))
98 rmap_match_set_hook
.match_interface
= func
;
101 /* no match interface */
102 void route_map_no_match_interface_hook(int (*func
)(
103 struct route_map_index
*index
, const char *command
,
104 const char *arg
, route_map_event_t type
,
105 char *errmsg
, size_t errmsg_len
))
107 rmap_match_set_hook
.no_match_interface
= func
;
110 /* match ip address */
111 void route_map_match_ip_address_hook(int (*func
)(
112 struct route_map_index
*index
, const char *command
,
113 const char *arg
, route_map_event_t type
,
114 char *errmsg
, size_t errmsg_len
))
116 rmap_match_set_hook
.match_ip_address
= func
;
119 /* no match ip address */
120 void route_map_no_match_ip_address_hook(int (*func
)(
121 struct route_map_index
*index
, const char *command
,
122 const char *arg
, route_map_event_t type
,
123 char *errmsg
, size_t errmsg_len
))
125 rmap_match_set_hook
.no_match_ip_address
= func
;
128 /* match ip address prefix list */
129 void route_map_match_ip_address_prefix_list_hook(int (*func
)(
130 struct route_map_index
*index
, const char *command
,
131 const char *arg
, route_map_event_t type
,
132 char *errmsg
, size_t errmsg_len
))
134 rmap_match_set_hook
.match_ip_address_prefix_list
= func
;
137 /* no match ip address prefix list */
138 void route_map_no_match_ip_address_prefix_list_hook(int (*func
)(
139 struct route_map_index
*index
, const char *command
,
140 const char *arg
, route_map_event_t type
,
141 char *errmsg
, size_t errmsg_len
))
143 rmap_match_set_hook
.no_match_ip_address_prefix_list
= func
;
146 /* match ip next hop */
147 void route_map_match_ip_next_hop_hook(int (*func
)(
148 struct route_map_index
*index
, const char *command
,
149 const char *arg
, route_map_event_t type
,
150 char *errmsg
, size_t errmsg_len
))
152 rmap_match_set_hook
.match_ip_next_hop
= func
;
155 /* no match ip next hop */
156 void route_map_no_match_ip_next_hop_hook(int (*func
)(
157 struct route_map_index
*index
, const char *command
,
158 const char *arg
, route_map_event_t type
,
159 char *errmsg
, size_t errmsg_len
))
161 rmap_match_set_hook
.no_match_ip_next_hop
= func
;
164 /* match ipv6 next-hop */
165 void route_map_match_ipv6_next_hop_hook(int (*func
)(
166 struct route_map_index
*index
, const char *command
, const char *arg
,
167 route_map_event_t type
, char *errmsg
, size_t errmsg_len
))
169 rmap_match_set_hook
.match_ipv6_next_hop
= func
;
172 /* no match ipv6 next-hop */
173 void route_map_no_match_ipv6_next_hop_hook(int (*func
)(
174 struct route_map_index
*index
, const char *command
, const char *arg
,
175 route_map_event_t type
, char *errmsg
, size_t errmsg_len
))
177 rmap_match_set_hook
.no_match_ipv6_next_hop
= func
;
180 /* match ip next hop prefix list */
181 void route_map_match_ip_next_hop_prefix_list_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_prefix_list
= func
;
189 /* no match ip next hop prefix list */
190 void route_map_no_match_ip_next_hop_prefix_list_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_prefix_list
= func
;
198 /* match ip next-hop type */
199 void route_map_match_ip_next_hop_type_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_ip_next_hop_type
= func
;
207 /* no match ip next-hop type */
208 void route_map_no_match_ip_next_hop_type_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_ip_next_hop_type
= func
;
216 /* match ipv6 address */
217 void route_map_match_ipv6_address_hook(int (*func
)(
218 struct route_map_index
*index
, const char *command
,
219 const char *arg
, route_map_event_t type
,
220 char *errmsg
, size_t errmsg_len
))
222 rmap_match_set_hook
.match_ipv6_address
= func
;
225 /* no match ipv6 address */
226 void route_map_no_match_ipv6_address_hook(int (*func
)(
227 struct route_map_index
*index
, const char *command
,
228 const char *arg
, route_map_event_t type
,
229 char *errmsg
, size_t errmsg_len
))
231 rmap_match_set_hook
.no_match_ipv6_address
= func
;
235 /* match ipv6 address prefix list */
236 void route_map_match_ipv6_address_prefix_list_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_address_prefix_list
= func
;
244 /* no match ipv6 address prefix list */
245 void route_map_no_match_ipv6_address_prefix_list_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_address_prefix_list
= func
;
253 /* match ipv6 next-hop type */
254 void route_map_match_ipv6_next_hop_type_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_ipv6_next_hop_type
= func
;
262 /* no match ipv6 next-hop type */
263 void route_map_no_match_ipv6_next_hop_type_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_ipv6_next_hop_type
= func
;
271 /* match ipv6 next-hop prefix-list */
272 void route_map_match_ipv6_next_hop_prefix_list_hook(int (*func
)(
273 struct route_map_index
*index
, const char *command
, const char *arg
,
274 route_map_event_t type
, char *errmsg
, size_t errmsg_len
))
276 rmap_match_set_hook
.match_ipv6_next_hop_prefix_list
= func
;
279 /* no match ipv6 next-hop prefix-list */
280 void route_map_no_match_ipv6_next_hop_prefix_list_hook(int (*func
)(
281 struct route_map_index
*index
, const char *command
, const char *arg
,
282 route_map_event_t type
, char *errmsg
, size_t errmsg_len
))
284 rmap_match_set_hook
.no_match_ipv6_next_hop_prefix_list
= func
;
288 void route_map_match_metric_hook(int (*func
)(
289 struct route_map_index
*index
, const char *command
,
290 const char *arg
, route_map_event_t type
,
291 char *errmsg
, size_t errmsg_len
))
293 rmap_match_set_hook
.match_metric
= func
;
296 /* no match metric */
297 void route_map_no_match_metric_hook(int (*func
)(
298 struct route_map_index
*index
, const char *command
,
299 const char *arg
, route_map_event_t type
,
300 char *errmsg
, size_t errmsg_len
))
302 rmap_match_set_hook
.no_match_metric
= func
;
306 void route_map_match_tag_hook(int (*func
)(struct route_map_index
*index
,
307 const char *command
, const char *arg
,
308 route_map_event_t type
,
309 char *errmsg
, size_t errmsg_len
))
311 rmap_match_set_hook
.match_tag
= func
;
315 void route_map_no_match_tag_hook(int (*func
)(
316 struct route_map_index
*index
, const char *command
,
317 const char *arg
, route_map_event_t type
,
318 char *errmsg
, size_t errmsg_len
))
320 rmap_match_set_hook
.no_match_tag
= func
;
323 /* set sr-te color */
324 void route_map_set_srte_color_hook(int (*func
)(struct route_map_index
*index
,
327 char *errmsg
, size_t errmsg_len
))
329 rmap_match_set_hook
.set_srte_color
= func
;
332 /* no set sr-te color */
333 void route_map_no_set_srte_color_hook(int (*func
)(struct route_map_index
*index
,
336 char *errmsg
, size_t errmsg_len
))
338 rmap_match_set_hook
.no_set_srte_color
= func
;
342 void route_map_set_ip_nexthop_hook(int (*func
)(struct route_map_index
*index
,
345 char *errmsg
, size_t errmsg_len
))
347 rmap_match_set_hook
.set_ip_nexthop
= func
;
350 /* no set ip nexthop */
351 void route_map_no_set_ip_nexthop_hook(int (*func
)(struct route_map_index
*index
,
357 rmap_match_set_hook
.no_set_ip_nexthop
= func
;
360 /* set ipv6 nexthop local */
361 void route_map_set_ipv6_nexthop_local_hook(
362 int (*func
)(struct route_map_index
*index
,
363 const char *command
, const char *arg
,
364 char *errmsg
, size_t errmsg_len
))
366 rmap_match_set_hook
.set_ipv6_nexthop_local
= func
;
369 /* no set ipv6 nexthop local */
370 void route_map_no_set_ipv6_nexthop_local_hook(
371 int (*func
)(struct route_map_index
*index
,
372 const char *command
, const char *arg
,
373 char *errmsg
, size_t errmsg_len
))
375 rmap_match_set_hook
.no_set_ipv6_nexthop_local
= func
;
379 void route_map_set_metric_hook(int (*func
)(struct route_map_index
*index
,
382 char *errmsg
, size_t errmsg_len
))
384 rmap_match_set_hook
.set_metric
= func
;
388 void route_map_no_set_metric_hook(int (*func
)(struct route_map_index
*index
,
391 char *errmsg
, size_t errmsg_len
))
393 rmap_match_set_hook
.no_set_metric
= func
;
397 void route_map_set_tag_hook(int (*func
)(struct route_map_index
*index
,
398 const char *command
, const char *arg
,
399 char *errmsg
, size_t errmsg_len
))
401 rmap_match_set_hook
.set_tag
= func
;
405 void route_map_no_set_tag_hook(int (*func
)(struct route_map_index
*index
,
408 char *errmsg
, size_t errmsg_len
))
410 rmap_match_set_hook
.no_set_tag
= func
;
413 int generic_match_add(struct route_map_index
*index
,
414 const char *command
, const char *arg
,
415 route_map_event_t type
,
416 char *errmsg
, size_t errmsg_len
)
418 enum rmap_compile_rets ret
;
420 ret
= route_map_add_match(index
, command
, arg
, type
);
422 case RMAP_RULE_MISSING
:
423 snprintf(errmsg
, errmsg_len
, "%% [%s] Can't find rule.",
425 return CMD_WARNING_CONFIG_FAILED
;
426 case RMAP_COMPILE_ERROR
:
427 snprintf(errmsg
, errmsg_len
,
428 "%% [%s] Argument form is unsupported or malformed.",
430 return CMD_WARNING_CONFIG_FAILED
;
431 case RMAP_COMPILE_SUCCESS
:
433 * Nothing to do here move along
441 int generic_match_delete(struct route_map_index
*index
,
442 const char *command
, const char *arg
,
443 route_map_event_t type
,
444 char *errmsg
, size_t errmsg_len
)
446 enum rmap_compile_rets ret
;
447 int retval
= CMD_SUCCESS
;
448 char *dep_name
= NULL
;
450 char *rmap_name
= NULL
;
452 if (type
!= RMAP_EVENT_MATCH_DELETED
) {
453 /* ignore the mundane, the types without any dependency */
455 if ((tmpstr
= route_map_get_match_arg(index
, command
))
458 XSTRDUP(MTYPE_ROUTE_MAP_RULE
, tmpstr
);
460 dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_RULE
, arg
);
462 rmap_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, index
->map
->name
);
465 ret
= route_map_delete_match(index
, command
, dep_name
, type
);
467 case RMAP_RULE_MISSING
:
468 snprintf(errmsg
, errmsg_len
, "%% [%s] Can't find rule.",
470 retval
= CMD_WARNING_CONFIG_FAILED
;
472 case RMAP_COMPILE_ERROR
:
473 snprintf(errmsg
, errmsg_len
,
474 "%% [%s] Argument form is unsupported or malformed.",
476 retval
= CMD_WARNING_CONFIG_FAILED
;
478 case RMAP_COMPILE_SUCCESS
:
485 XFREE(MTYPE_ROUTE_MAP_RULE
, dep_name
);
486 XFREE(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
491 int generic_set_add(struct route_map_index
*index
,
492 const char *command
, const char *arg
,
493 char *errmsg
, size_t errmsg_len
)
495 enum rmap_compile_rets ret
;
497 ret
= route_map_add_set(index
, command
, arg
);
499 case RMAP_RULE_MISSING
:
500 snprintf(errmsg
, errmsg_len
,
501 "%% [%s] Can't find rule.", frr_protonameinst
);
502 return CMD_WARNING_CONFIG_FAILED
;
503 case RMAP_COMPILE_ERROR
:
504 snprintf(errmsg
, errmsg_len
,
505 "%% [%s] Argument form is unsupported or malformed.",
507 return CMD_WARNING_CONFIG_FAILED
;
508 case RMAP_COMPILE_SUCCESS
:
515 int generic_set_delete(struct route_map_index
*index
,
516 const char *command
, const char *arg
,
517 char *errmsg
, size_t errmsg_len
)
519 enum rmap_compile_rets ret
;
521 ret
= route_map_delete_set(index
, command
, arg
);
523 case RMAP_RULE_MISSING
:
524 snprintf(errmsg
, errmsg_len
, "%% [%s] Can't find rule.",
526 return CMD_WARNING_CONFIG_FAILED
;
527 case RMAP_COMPILE_ERROR
:
528 snprintf(errmsg
, errmsg_len
,
529 "%% [%s] Argument form is unsupported or malformed.",
531 return CMD_WARNING_CONFIG_FAILED
;
532 case RMAP_COMPILE_SUCCESS
:
540 /* Master list of route map. */
541 struct route_map_list route_map_master
= {NULL
, NULL
, NULL
, NULL
, NULL
};
542 struct hash
*route_map_master_hash
= NULL
;
544 static unsigned int route_map_hash_key_make(const void *p
)
546 const struct route_map
*map
= p
;
547 return string_hash_make(map
->name
);
550 static bool route_map_hash_cmp(const void *p1
, const void *p2
)
552 const struct route_map
*map1
= p1
;
553 const struct route_map
*map2
= p2
;
555 if (!strcmp(map1
->name
, map2
->name
))
561 enum route_map_upd8_type
{
566 /* all possible route-map dependency types */
567 enum route_map_dep_type
{
568 ROUTE_MAP_DEP_RMAP
= 1,
570 ROUTE_MAP_DEP_ECLIST
,
571 ROUTE_MAP_DEP_LCLIST
,
573 ROUTE_MAP_DEP_ASPATH
,
574 ROUTE_MAP_DEP_FILTER
,
578 struct route_map_dep
{
580 struct hash
*dep_rmap_hash
;
581 struct hash
*this_hash
; /* ptr to the hash structure this is part of */
584 struct route_map_dep_data
{
588 /* Count of number of sequences of this
589 * route-map that depend on the same entity.
594 /* Hashes maintaining dependency between various sublists used by route maps */
595 static struct hash
*route_map_dep_hash
[ROUTE_MAP_DEP_MAX
];
597 static unsigned int route_map_dep_hash_make_key(const void *p
);
598 static void route_map_clear_all_references(char *rmap_name
);
599 static void route_map_rule_delete(struct route_map_rule_list
*,
600 struct route_map_rule
*);
601 static bool rmap_debug
;
603 /* New route map allocation. Please note route map's name must be
605 static struct route_map
*route_map_new(const char *name
)
607 struct route_map
*new;
609 new = XCALLOC(MTYPE_ROUTE_MAP
, sizeof(struct route_map
));
610 new->name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
611 QOBJ_REG(new, route_map
);
615 /* Add new name to route_map. */
616 static struct route_map
*route_map_add(const char *name
)
618 struct route_map
*map
, *exist
;
619 struct route_map_list
*list
;
621 map
= route_map_new(name
);
622 list
= &route_map_master
;
625 * Add map to the hash
627 * If the map already exists in the hash, then we know that
628 * FRR is now in a sequence of delete/create.
629 * All FRR needs to do here is set the to_be_processed
630 * bit (to inherit from the old one
632 exist
= hash_release(route_map_master_hash
, map
);
634 map
->to_be_processed
= exist
->to_be_processed
;
635 route_map_free_map(exist
);
637 hash_get(route_map_master_hash
, map
, hash_alloc_intern
);
639 /* Add new entry to the head of the list to match how it is added in the
640 * hash table. This is to ensure that if the same route-map has been
641 * created more than once and then marked for deletion (which can happen
642 * if prior deletions haven't completed as BGP hasn't yet done the
643 * route-map processing), the order of the entities is the same in both
644 * the list and the hash table. Otherwise, since there is nothing to
645 * distinguish between the two entries, the wrong entry could get freed.
646 * TODO: This needs to be re-examined to handle it better - e.g., revive
647 * a deleted entry if the route-map is created again.
650 map
->next
= list
->head
;
652 list
->head
->prev
= map
;
658 if (route_map_master
.add_hook
) {
659 (*route_map_master
.add_hook
)(name
);
660 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_ADDED
);
663 if (!map
->ipv4_prefix_table
)
664 map
->ipv4_prefix_table
= route_table_init();
666 if (!map
->ipv6_prefix_table
)
667 map
->ipv6_prefix_table
= route_table_init();
670 zlog_debug("Add route-map %s", name
);
674 /* this is supposed to be called post processing by
675 * the delete hook function. Don't invoke delete_hook
676 * again in this routine.
678 static void route_map_free_map(struct route_map
*map
)
680 struct route_map_list
*list
;
681 struct route_map_index
*index
;
686 while ((index
= map
->head
) != NULL
)
687 route_map_index_delete(index
, 0);
690 zlog_debug("Deleting route-map %s", map
->name
);
692 list
= &route_map_master
;
697 map
->next
->prev
= map
->prev
;
699 list
->tail
= map
->prev
;
702 map
->prev
->next
= map
->next
;
704 list
->head
= map
->next
;
706 hash_release(route_map_master_hash
, map
);
707 XFREE(MTYPE_ROUTE_MAP_NAME
, map
->name
);
708 XFREE(MTYPE_ROUTE_MAP
, map
);
711 /* Route map delete from list. */
712 void route_map_delete(struct route_map
*map
)
714 struct route_map_index
*index
;
717 while ((index
= map
->head
) != NULL
)
718 route_map_index_delete(index
, 0);
723 /* Clear all dependencies */
724 route_map_clear_all_references(name
);
726 /* Execute deletion hook. */
727 if (route_map_master
.delete_hook
) {
728 (*route_map_master
.delete_hook
)(name
);
729 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_DELETED
);
732 if (!map
->to_be_processed
) {
733 route_map_free_map(map
);
737 /* Lookup route map by route map name string. */
738 struct route_map
*route_map_lookup_by_name(const char *name
)
740 struct route_map
*map
;
741 struct route_map tmp_map
;
746 // map.deleted is false via memset
747 memset(&tmp_map
, 0, sizeof(tmp_map
));
748 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
749 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
750 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
752 if (map
&& map
->deleted
)
758 /* Simple helper to warn if route-map does not exist. */
759 struct route_map
*route_map_lookup_warn_noexist(struct vty
*vty
, const char *name
)
761 struct route_map
*route_map
= route_map_lookup_by_name(name
);
764 if (vty_shell_serv(vty
))
765 vty_out(vty
, "The route-map '%s' does not exist.\n", name
);
770 int route_map_mark_updated(const char *name
)
772 struct route_map
*map
;
774 struct route_map tmp_map
;
779 map
= route_map_lookup_by_name(name
);
781 /* If we did not find the routemap with deleted=false try again
785 memset(&tmp_map
, 0, sizeof(tmp_map
));
786 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
787 tmp_map
.deleted
= true;
788 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
789 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
793 map
->to_be_processed
= true;
800 static void route_map_clear_updated(struct route_map
*map
)
803 map
->to_be_processed
= false;
805 route_map_free_map(map
);
809 /* Lookup route map. If there isn't route map create one and return
811 struct route_map
*route_map_get(const char *name
)
813 struct route_map
*map
;
815 map
= route_map_lookup_by_name(name
);
817 map
= route_map_add(name
);
822 void route_map_walk_update_list(void (*route_map_update_fn
)(char *name
))
824 struct route_map
*node
;
825 struct route_map
*nnode
= NULL
;
827 for (node
= route_map_master
.head
; node
; node
= nnode
) {
828 if (node
->to_be_processed
) {
829 /* DD: Should we add any thread yield code here */
830 route_map_update_fn(node
->name
);
832 route_map_clear_updated(node
);
838 /* Return route map's type string. */
839 static const char *route_map_type_str(enum route_map_type type
)
853 static const char *route_map_cmd_result_str(enum route_map_cmd_result_t res
)
871 static const char *route_map_result_str(route_map_result_t res
)
876 case RMAP_PERMITMATCH
:
884 static void vty_show_route_map_entry(struct vty
*vty
, struct route_map
*map
,
887 struct route_map_index
*index
;
888 struct route_map_rule
*rule
;
889 json_object
*json_rmap
= NULL
;
890 json_object
*json_rules
= NULL
;
893 json_rmap
= json_object_new_object();
894 json_object_object_add(json
, map
->name
, json_rmap
);
896 json_rules
= json_object_new_array();
897 json_object_int_add(json_rmap
, "invoked",
898 map
->applied
- map
->applied_clear
);
899 json_object_boolean_add(json_rmap
, "disabledOptimization",
900 map
->optimization_disabled
);
901 json_object_boolean_add(json_rmap
, "processedChange",
902 map
->to_be_processed
);
903 json_object_object_add(json_rmap
, "rules", json_rules
);
906 "route-map: %s Invoked: %" PRIu64
907 " Optimization: %s Processed Change: %s\n",
908 map
->name
, map
->applied
- map
->applied_clear
,
909 map
->optimization_disabled
? "disabled" : "enabled",
910 map
->to_be_processed
? "true" : "false");
913 for (index
= map
->head
; index
; index
= index
->next
) {
915 json_object
*json_rule
;
916 json_object
*json_matches
;
917 json_object
*json_sets
;
918 char action
[BUFSIZ
] = {};
920 json_rule
= json_object_new_object();
921 json_object_array_add(json_rules
, json_rule
);
923 json_object_int_add(json_rule
, "sequenceNumber",
925 json_object_string_add(json_rule
, "type",
926 route_map_type_str(index
->type
));
927 json_object_int_add(json_rule
, "invoked",
929 - index
->applied_clear
);
932 if (index
->description
)
933 json_object_string_add(json_rule
, "description",
937 json_matches
= json_object_new_array();
938 json_object_object_add(json_rule
, "matchClauses",
940 for (rule
= index
->match_list
.head
; rule
;
944 snprintf(buf
, sizeof(buf
), "%s %s",
945 rule
->cmd
->str
, rule
->rule_str
);
946 json_array_string_add(json_matches
, buf
);
950 json_sets
= json_object_new_array();
951 json_object_object_add(json_rule
, "setClauses",
953 for (rule
= index
->set_list
.head
; rule
;
957 snprintf(buf
, sizeof(buf
), "%s %s",
958 rule
->cmd
->str
, rule
->rule_str
);
959 json_array_string_add(json_sets
, buf
);
964 json_object_string_add(json_rule
, "callClause",
968 if (index
->exitpolicy
== RMAP_GOTO
)
969 snprintf(action
, sizeof(action
), "Goto %d",
971 else if (index
->exitpolicy
== RMAP_NEXT
)
972 snprintf(action
, sizeof(action
),
973 "Continue to next entry");
974 else if (index
->exitpolicy
== RMAP_EXIT
)
975 snprintf(action
, sizeof(action
),
977 if (action
[0] != '\0')
978 json_object_string_add(json_rule
, "action",
981 vty_out(vty
, " %s, sequence %d Invoked %" PRIu64
"\n",
982 route_map_type_str(index
->type
), index
->pref
,
983 index
->applied
- index
->applied_clear
);
986 if (index
->description
)
987 vty_out(vty
, " Description:\n %s\n",
991 vty_out(vty
, " Match clauses:\n");
992 for (rule
= index
->match_list
.head
; rule
;
994 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
998 vty_out(vty
, " Set clauses:\n");
999 for (rule
= index
->set_list
.head
; rule
;
1001 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
1005 vty_out(vty
, " Call clause:\n");
1007 vty_out(vty
, " Call %s\n", index
->nextrm
);
1010 vty_out(vty
, " Action:\n");
1011 if (index
->exitpolicy
== RMAP_GOTO
)
1012 vty_out(vty
, " Goto %d\n", index
->nextpref
);
1013 else if (index
->exitpolicy
== RMAP_NEXT
)
1014 vty_out(vty
, " Continue to next entry\n");
1015 else if (index
->exitpolicy
== RMAP_EXIT
)
1016 vty_out(vty
, " Exit routemap\n");
1021 static int sort_route_map(const void **map1
, const void **map2
)
1023 const struct route_map
*m1
= *map1
;
1024 const struct route_map
*m2
= *map2
;
1026 return strcmp(m1
->name
, m2
->name
);
1029 static int vty_show_route_map(struct vty
*vty
, const char *name
, bool use_json
)
1031 struct route_map
*map
;
1032 json_object
*json
= NULL
;
1033 json_object
*json_proto
= NULL
;
1036 json
= json_object_new_object();
1037 json_proto
= json_object_new_object();
1038 json_object_object_add(json
, frr_protonameinst
, json_proto
);
1040 vty_out(vty
, "%s:\n", frr_protonameinst
);
1043 map
= route_map_lookup_by_name(name
);
1046 vty_show_route_map_entry(vty
, map
, json_proto
);
1047 } else if (!use_json
) {
1048 vty_out(vty
, "%s: 'route-map %s' not found\n",
1049 frr_protonameinst
, name
);
1053 struct list
*maplist
= list_new();
1054 struct listnode
*ln
;
1056 for (map
= route_map_master
.head
; map
; map
= map
->next
)
1057 listnode_add(maplist
, map
);
1059 list_sort(maplist
, sort_route_map
);
1061 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
1062 vty_show_route_map_entry(vty
, map
, json_proto
);
1064 list_delete(&maplist
);
1067 return vty_json(vty
, json
);
1070 /* Unused route map details */
1071 static int vty_show_unused_route_map(struct vty
*vty
)
1073 struct list
*maplist
= list_new();
1074 struct listnode
*ln
;
1075 struct route_map
*map
;
1077 for (map
= route_map_master
.head
; map
; map
= map
->next
) {
1078 /* If use_count is zero, No protocol is using this routemap.
1079 * so adding to the list.
1081 if (!map
->use_count
)
1082 listnode_add(maplist
, map
);
1085 if (maplist
->count
> 0) {
1086 vty_out(vty
, "\n%s:\n", frr_protonameinst
);
1087 list_sort(maplist
, sort_route_map
);
1089 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
1090 vty_show_route_map_entry(vty
, map
, NULL
);
1092 vty_out(vty
, "\n%s: None\n", frr_protonameinst
);
1095 list_delete(&maplist
);
1099 /* New route map allocation. Please note route map's name must be
1101 static struct route_map_index
*route_map_index_new(void)
1103 struct route_map_index
*new;
1105 new = XCALLOC(MTYPE_ROUTE_MAP_INDEX
, sizeof(struct route_map_index
));
1106 new->exitpolicy
= RMAP_EXIT
; /* Default to Cisco-style */
1107 TAILQ_INIT(&new->rhclist
);
1108 QOBJ_REG(new, route_map_index
);
1112 /* Free route map index. */
1113 void route_map_index_delete(struct route_map_index
*index
, int notify
)
1115 struct routemap_hook_context
*rhc
;
1116 struct route_map_rule
*rule
;
1121 zlog_debug("Deleting route-map %s sequence %d",
1122 index
->map
->name
, index
->pref
);
1124 /* Free route map entry description. */
1125 XFREE(MTYPE_TMP
, index
->description
);
1127 /* Free route map northbound hook contexts. */
1128 while ((rhc
= TAILQ_FIRST(&index
->rhclist
)) != NULL
)
1129 routemap_hook_context_free(rhc
);
1131 /* Free route match. */
1132 while ((rule
= index
->match_list
.head
) != NULL
) {
1133 if (IS_RULE_IPv4_PREFIX_LIST(rule
->cmd
->str
))
1134 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_DELETED
,
1135 index
, AFI_IP
, rule
->rule_str
);
1136 else if (IS_RULE_IPv6_PREFIX_LIST(rule
->cmd
->str
))
1137 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_DELETED
,
1141 route_map_rule_delete(&index
->match_list
, rule
);
1144 /* Free route set. */
1145 while ((rule
= index
->set_list
.head
) != NULL
)
1146 route_map_rule_delete(&index
->set_list
, rule
);
1148 /* Remove index from route map list. */
1150 index
->next
->prev
= index
->prev
;
1152 index
->map
->tail
= index
->prev
;
1155 index
->prev
->next
= index
->next
;
1157 index
->map
->head
= index
->next
;
1159 /* Free 'char *nextrm' if not NULL */
1160 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
1162 route_map_pfx_tbl_update(RMAP_EVENT_INDEX_DELETED
, index
, 0, NULL
);
1164 /* Execute event hook. */
1165 if (route_map_master
.event_hook
&& notify
) {
1166 (*route_map_master
.event_hook
)(index
->map
->name
);
1167 route_map_notify_dependencies(index
->map
->name
,
1168 RMAP_EVENT_CALL_ADDED
);
1170 XFREE(MTYPE_ROUTE_MAP_INDEX
, index
);
1173 /* Lookup index from route map. */
1174 static struct route_map_index
*route_map_index_lookup(struct route_map
*map
,
1175 enum route_map_type type
,
1178 struct route_map_index
*index
;
1180 for (index
= map
->head
; index
; index
= index
->next
)
1181 if ((index
->type
== type
|| type
== RMAP_ANY
)
1182 && index
->pref
== pref
)
1187 /* Add new index to route map. */
1188 static struct route_map_index
*
1189 route_map_index_add(struct route_map
*map
, enum route_map_type type
, int pref
)
1191 struct route_map_index
*index
;
1192 struct route_map_index
*point
;
1194 /* Allocate new route map inex. */
1195 index
= route_map_index_new();
1200 /* Compare preference. */
1201 for (point
= map
->head
; point
; point
= point
->next
)
1202 if (point
->pref
>= pref
)
1205 if (map
->head
== NULL
) {
1206 map
->head
= map
->tail
= index
;
1207 } else if (point
== NULL
) {
1208 index
->prev
= map
->tail
;
1209 map
->tail
->next
= index
;
1211 } else if (point
== map
->head
) {
1212 index
->next
= map
->head
;
1213 map
->head
->prev
= index
;
1216 index
->next
= point
;
1217 index
->prev
= point
->prev
;
1219 point
->prev
->next
= index
;
1220 point
->prev
= index
;
1223 route_map_pfx_tbl_update(RMAP_EVENT_INDEX_ADDED
, index
, 0, NULL
);
1225 /* Execute event hook. */
1226 if (route_map_master
.event_hook
) {
1227 (*route_map_master
.event_hook
)(map
->name
);
1228 route_map_notify_dependencies(map
->name
, RMAP_EVENT_CALL_ADDED
);
1232 zlog_debug("Route-map %s add sequence %d, type: %s",
1233 map
->name
, pref
, route_map_type_str(type
));
1238 /* Get route map index. */
1239 struct route_map_index
*
1240 route_map_index_get(struct route_map
*map
, enum route_map_type type
, int pref
)
1242 struct route_map_index
*index
;
1244 index
= route_map_index_lookup(map
, RMAP_ANY
, pref
);
1245 if (index
&& index
->type
!= type
) {
1246 /* Delete index from route map. */
1247 route_map_index_delete(index
, 1);
1251 index
= route_map_index_add(map
, type
, pref
);
1255 /* New route map rule */
1256 static struct route_map_rule
*route_map_rule_new(void)
1258 struct route_map_rule
*new;
1260 new = XCALLOC(MTYPE_ROUTE_MAP_RULE
, sizeof(struct route_map_rule
));
1264 /* Install rule command to the match list. */
1265 void _route_map_install_match(struct route_map_rule_cmd_proxy
*proxy
)
1267 rmap_cmd_name_add(rmap_match_cmds
, proxy
);
1270 /* Install rule command to the set list. */
1271 void _route_map_install_set(struct route_map_rule_cmd_proxy
*proxy
)
1273 rmap_cmd_name_add(rmap_set_cmds
, proxy
);
1276 /* Lookup rule command from match list. */
1277 static const struct route_map_rule_cmd
*route_map_lookup_match(const char *name
)
1279 struct route_map_rule_cmd refcmd
= {.str
= name
};
1280 struct route_map_rule_cmd_proxy ref
= {.cmd
= &refcmd
};
1281 struct route_map_rule_cmd_proxy
*res
;
1283 res
= rmap_cmd_name_find(rmap_match_cmds
, &ref
);
1289 /* Lookup rule command from set list. */
1290 static const struct route_map_rule_cmd
*route_map_lookup_set(const char *name
)
1292 struct route_map_rule_cmd refcmd
= {.str
= name
};
1293 struct route_map_rule_cmd_proxy ref
= {.cmd
= &refcmd
};
1294 struct route_map_rule_cmd_proxy
*res
;
1296 res
= rmap_cmd_name_find(rmap_set_cmds
, &ref
);
1302 /* Add match and set rule to rule list. */
1303 static void route_map_rule_add(struct route_map_rule_list
*list
,
1304 struct route_map_rule
*rule
)
1307 rule
->prev
= list
->tail
;
1309 list
->tail
->next
= rule
;
1315 /* Delete rule from rule list. */
1316 static void route_map_rule_delete(struct route_map_rule_list
*list
,
1317 struct route_map_rule
*rule
)
1319 if (rule
->cmd
->func_free
)
1320 (*rule
->cmd
->func_free
)(rule
->value
);
1322 XFREE(MTYPE_ROUTE_MAP_RULE_STR
, rule
->rule_str
);
1325 rule
->next
->prev
= rule
->prev
;
1327 list
->tail
= rule
->prev
;
1329 rule
->prev
->next
= rule
->next
;
1331 list
->head
= rule
->next
;
1333 XFREE(MTYPE_ROUTE_MAP_RULE
, rule
);
1336 /* strcmp wrapper function which don't crush even argument is NULL. */
1337 static int rulecmp(const char *dst
, const char *src
)
1348 return strcmp(dst
, src
);
1353 /* Use this to return the already specified argument for this match. This is
1354 * useful to get the specified argument with a route map match rule when the
1355 * rule is being deleted and the argument is not provided.
1357 const char *route_map_get_match_arg(struct route_map_index
*index
,
1358 const char *match_name
)
1360 struct route_map_rule
*rule
;
1361 const struct route_map_rule_cmd
*cmd
;
1363 /* First lookup rule for add match statement. */
1364 cmd
= route_map_lookup_match(match_name
);
1368 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1369 if (rule
->cmd
== cmd
&& rule
->rule_str
!= NULL
)
1370 return (rule
->rule_str
);
1375 static route_map_event_t
get_route_map_delete_event(route_map_event_t type
)
1378 case RMAP_EVENT_CALL_ADDED
:
1379 return RMAP_EVENT_CALL_DELETED
;
1380 case RMAP_EVENT_PLIST_ADDED
:
1381 return RMAP_EVENT_PLIST_DELETED
;
1382 case RMAP_EVENT_CLIST_ADDED
:
1383 return RMAP_EVENT_CLIST_DELETED
;
1384 case RMAP_EVENT_ECLIST_ADDED
:
1385 return RMAP_EVENT_ECLIST_DELETED
;
1386 case RMAP_EVENT_LLIST_ADDED
:
1387 return RMAP_EVENT_LLIST_DELETED
;
1388 case RMAP_EVENT_ASLIST_ADDED
:
1389 return RMAP_EVENT_ASLIST_DELETED
;
1390 case RMAP_EVENT_FILTER_ADDED
:
1391 return RMAP_EVENT_FILTER_DELETED
;
1392 case RMAP_EVENT_SET_ADDED
:
1393 case RMAP_EVENT_SET_DELETED
:
1394 case RMAP_EVENT_SET_REPLACED
:
1395 case RMAP_EVENT_MATCH_ADDED
:
1396 case RMAP_EVENT_MATCH_DELETED
:
1397 case RMAP_EVENT_MATCH_REPLACED
:
1398 case RMAP_EVENT_INDEX_ADDED
:
1399 case RMAP_EVENT_INDEX_DELETED
:
1400 case RMAP_EVENT_CALL_DELETED
:
1401 case RMAP_EVENT_PLIST_DELETED
:
1402 case RMAP_EVENT_CLIST_DELETED
:
1403 case RMAP_EVENT_ECLIST_DELETED
:
1404 case RMAP_EVENT_LLIST_DELETED
:
1405 case RMAP_EVENT_ASLIST_DELETED
:
1406 case RMAP_EVENT_FILTER_DELETED
:
1407 /* This function returns the appropriate 'deleted' event type
1408 * for every 'added' event type passed to this function.
1409 * This is done only for named entities used in the
1410 * route-map match commands.
1411 * This function is not to be invoked for any of the other event
1419 * Return to make c happy but if we get here something has gone
1420 * terribly terribly wrong, so yes this return makes no sense.
1422 return RMAP_EVENT_CALL_ADDED
;
1425 /* Add match statement to route map. */
1426 enum rmap_compile_rets
route_map_add_match(struct route_map_index
*index
,
1427 const char *match_name
,
1428 const char *match_arg
,
1429 route_map_event_t type
)
1431 struct route_map_rule
*rule
;
1432 struct route_map_rule
*next
;
1433 const struct route_map_rule_cmd
*cmd
;
1435 int8_t delete_rmap_event_type
= 0;
1436 const char *rule_key
;
1438 /* First lookup rule for add match statement. */
1439 cmd
= route_map_lookup_match(match_name
);
1441 return RMAP_RULE_MISSING
;
1443 /* Next call compile function for this match statement. */
1444 if (cmd
->func_compile
) {
1445 compile
= (*cmd
->func_compile
)(match_arg
);
1446 if (compile
== NULL
)
1447 return RMAP_COMPILE_ERROR
;
1450 /* use the compiled results if applicable */
1451 if (compile
&& cmd
->func_get_rmap_rule_key
)
1452 rule_key
= (*cmd
->func_get_rmap_rule_key
)
1455 rule_key
= match_arg
;
1457 /* If argument is completely same ignore it. */
1458 for (rule
= index
->match_list
.head
; rule
; rule
= next
) {
1460 if (rule
->cmd
== cmd
) {
1461 /* If the configured route-map match rule is exactly
1462 * the same as the existing configuration then,
1463 * ignore the duplicate configuration.
1465 if (rulecmp(match_arg
, rule
->rule_str
) == 0) {
1467 (*cmd
->func_free
)(compile
);
1469 return RMAP_COMPILE_SUCCESS
;
1472 /* If IPv4 or IPv6 prefix-list match criteria
1473 * has been delete to the route-map index, update
1474 * the route-map's prefix table.
1476 if (IS_RULE_IPv4_PREFIX_LIST(match_name
))
1477 route_map_pfx_tbl_update(
1478 RMAP_EVENT_PLIST_DELETED
, index
, AFI_IP
,
1480 else if (IS_RULE_IPv6_PREFIX_LIST(match_name
))
1481 route_map_pfx_tbl_update(
1482 RMAP_EVENT_PLIST_DELETED
, index
,
1483 AFI_IP6
, rule
->rule_str
);
1485 /* Remove the dependency of the route-map on the rule
1486 * that is being replaced.
1488 if (type
>= RMAP_EVENT_CALL_ADDED
) {
1489 delete_rmap_event_type
=
1490 get_route_map_delete_event(type
);
1491 route_map_upd8_dependency(
1492 delete_rmap_event_type
,
1497 route_map_rule_delete(&index
->match_list
, rule
);
1501 /* Add new route map match rule. */
1502 rule
= route_map_rule_new();
1504 rule
->value
= compile
;
1506 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, match_arg
);
1508 rule
->rule_str
= NULL
;
1510 /* Add new route match rule to linked list. */
1511 route_map_rule_add(&index
->match_list
, rule
);
1513 /* If IPv4 or IPv6 prefix-list match criteria
1514 * has been added to the route-map index, update
1515 * the route-map's prefix table.
1517 if (IS_RULE_IPv4_PREFIX_LIST(match_name
)) {
1518 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_ADDED
, index
, AFI_IP
,
1520 } else if (IS_RULE_IPv6_PREFIX_LIST(match_name
)) {
1521 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_ADDED
, index
, AFI_IP6
,
1525 /* Execute event hook. */
1526 if (route_map_master
.event_hook
) {
1527 (*route_map_master
.event_hook
)(index
->map
->name
);
1528 route_map_notify_dependencies(index
->map
->name
,
1529 RMAP_EVENT_CALL_ADDED
);
1531 if (type
!= RMAP_EVENT_MATCH_ADDED
)
1532 route_map_upd8_dependency(type
, rule_key
, index
->map
->name
);
1534 return RMAP_COMPILE_SUCCESS
;
1537 /* Delete specified route match rule. */
1538 enum rmap_compile_rets
route_map_delete_match(struct route_map_index
*index
,
1539 const char *match_name
,
1540 const char *match_arg
,
1541 route_map_event_t type
)
1543 struct route_map_rule
*rule
;
1544 const struct route_map_rule_cmd
*cmd
;
1545 const char *rule_key
;
1547 cmd
= route_map_lookup_match(match_name
);
1549 return RMAP_RULE_MISSING
;
1551 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1552 if (rule
->cmd
== cmd
&& (rulecmp(rule
->rule_str
, match_arg
) == 0
1553 || match_arg
== NULL
)) {
1554 /* Execute event hook. */
1555 if (route_map_master
.event_hook
) {
1556 (*route_map_master
.event_hook
)(index
->map
->name
);
1557 route_map_notify_dependencies(
1559 RMAP_EVENT_CALL_ADDED
);
1561 if (cmd
->func_get_rmap_rule_key
)
1562 rule_key
= (*cmd
->func_get_rmap_rule_key
)
1565 rule_key
= match_arg
;
1567 if (type
!= RMAP_EVENT_MATCH_DELETED
&& rule_key
)
1568 route_map_upd8_dependency(type
, rule_key
,
1571 route_map_rule_delete(&index
->match_list
, rule
);
1573 /* If IPv4 or IPv6 prefix-list match criteria
1574 * has been delete from the route-map index, update
1575 * the route-map's prefix table.
1577 if (IS_RULE_IPv4_PREFIX_LIST(match_name
)) {
1578 route_map_pfx_tbl_update(
1579 RMAP_EVENT_PLIST_DELETED
, index
, AFI_IP
,
1581 } else if (IS_RULE_IPv6_PREFIX_LIST(match_name
)) {
1582 route_map_pfx_tbl_update(
1583 RMAP_EVENT_PLIST_DELETED
, index
,
1584 AFI_IP6
, match_arg
);
1587 return RMAP_COMPILE_SUCCESS
;
1589 /* Can't find matched rule. */
1590 return RMAP_RULE_MISSING
;
1593 /* Add route-map set statement to the route map. */
1594 enum rmap_compile_rets
route_map_add_set(struct route_map_index
*index
,
1595 const char *set_name
,
1596 const char *set_arg
)
1598 struct route_map_rule
*rule
;
1599 struct route_map_rule
*next
;
1600 const struct route_map_rule_cmd
*cmd
;
1603 cmd
= route_map_lookup_set(set_name
);
1605 return RMAP_RULE_MISSING
;
1607 /* Next call compile function for this match statement. */
1608 if (cmd
->func_compile
) {
1609 compile
= (*cmd
->func_compile
)(set_arg
);
1610 if (compile
== NULL
)
1611 return RMAP_COMPILE_ERROR
;
1615 /* Add by WJL. if old set command of same kind exist, delete it first
1616 to ensure only one set command of same kind exist under a
1618 for (rule
= index
->set_list
.head
; rule
; rule
= next
) {
1620 if (rule
->cmd
== cmd
)
1621 route_map_rule_delete(&index
->set_list
, rule
);
1624 /* Add new route map match rule. */
1625 rule
= route_map_rule_new();
1627 rule
->value
= compile
;
1629 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, set_arg
);
1631 rule
->rule_str
= NULL
;
1633 /* Add new route match rule to linked list. */
1634 route_map_rule_add(&index
->set_list
, rule
);
1636 /* Execute event hook. */
1637 if (route_map_master
.event_hook
) {
1638 (*route_map_master
.event_hook
)(index
->map
->name
);
1639 route_map_notify_dependencies(index
->map
->name
,
1640 RMAP_EVENT_CALL_ADDED
);
1642 return RMAP_COMPILE_SUCCESS
;
1645 /* Delete route map set rule. */
1646 enum rmap_compile_rets
route_map_delete_set(struct route_map_index
*index
,
1647 const char *set_name
,
1648 const char *set_arg
)
1650 struct route_map_rule
*rule
;
1651 const struct route_map_rule_cmd
*cmd
;
1653 cmd
= route_map_lookup_set(set_name
);
1655 return RMAP_RULE_MISSING
;
1657 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
1658 if ((rule
->cmd
== cmd
) && (rulecmp(rule
->rule_str
, set_arg
) == 0
1659 || set_arg
== NULL
)) {
1660 route_map_rule_delete(&index
->set_list
, rule
);
1661 /* Execute event hook. */
1662 if (route_map_master
.event_hook
) {
1663 (*route_map_master
.event_hook
)(index
->map
->name
);
1664 route_map_notify_dependencies(
1666 RMAP_EVENT_CALL_ADDED
);
1668 return RMAP_COMPILE_SUCCESS
;
1670 /* Can't find matched rule. */
1671 return RMAP_RULE_MISSING
;
1674 static enum route_map_cmd_result_t
1675 route_map_apply_match(struct route_map_rule_list
*match_list
,
1676 const struct prefix
*prefix
, void *object
)
1678 enum route_map_cmd_result_t ret
= RMAP_NOMATCH
;
1679 struct route_map_rule
*match
;
1680 bool is_matched
= false;
1683 /* Check all match rule and if there is no match rule, go to the
1685 if (!match_list
->head
)
1688 for (match
= match_list
->head
; match
; match
= match
->next
) {
1690 * Try each match statement. If any match does not
1691 * return RMAP_MATCH or RMAP_NOOP, return.
1692 * Otherwise continue on to next match statement.
1693 * All match statements must MATCH for
1694 * end-result to be a match.
1695 * (Exception:If match stmts result in a mix of
1696 * MATCH/NOOP, then also end-result is a match)
1697 * If all result in NOOP, end-result is NOOP.
1699 ret
= (*match
->cmd
->func_apply
)(match
->value
, prefix
,
1703 * If the consolidated result of func_apply is:
1704 * -----------------------------------------------
1705 * | MATCH | NOMATCH | NOOP | Final Result |
1706 * ------------------------------------------------
1707 * | yes | yes | yes | NOMATCH |
1708 * | no | no | yes | NOOP |
1709 * | yes | no | yes | MATCH |
1710 * | no | yes | yes | NOMATCH |
1711 * |-----------------------------------------------
1713 * Traditionally, all rules within route-map
1714 * should match for it to MATCH.
1715 * If there are noops within the route-map rules,
1716 * it follows the above matrix.
1718 * Eg: route-map rm1 permit 10
1723 * route-map rm1 permit 20
1752 static struct list
*route_map_get_index_list(struct route_node
**rn
,
1753 const struct prefix
*prefix
,
1754 struct route_table
*table
)
1756 struct route_node
*tmp_rn
= NULL
;
1759 *rn
= route_node_match(table
, prefix
);
1765 return (struct list
*)((*rn
)->info
);
1767 /* If rn->info is NULL, get the parent.
1768 * Store the rn in tmp_rn and unlock it later.
1774 *rn
= (*rn
)->parent
;
1776 route_unlock_node(tmp_rn
);
1782 route_lock_node(*rn
);
1783 return (struct list
*)((*rn
)->info
);
1785 } while (!(*rn
)->info
);
1791 * This function returns the route-map index that best matches the prefix.
1793 static struct route_map_index
*
1794 route_map_get_index(struct route_map
*map
, const struct prefix
*prefix
,
1795 void *object
, enum route_map_cmd_result_t
*match_ret
)
1797 enum route_map_cmd_result_t ret
= RMAP_NOMATCH
;
1798 struct list
*candidate_rmap_list
= NULL
;
1799 struct route_node
*rn
= NULL
;
1800 struct listnode
*ln
= NULL
, *nn
= NULL
;
1801 struct route_map_index
*index
= NULL
, *best_index
= NULL
;
1802 struct route_map_index
*head_index
= NULL
;
1803 struct route_table
*table
= NULL
;
1805 unsigned char family
;
1808 * Handling for matching evpn_routes in the prefix table.
1810 * We convert type2/5 prefix to ipv4/6 prefix to do longest
1811 * prefix matching on.
1813 if (prefix
->family
== AF_EVPN
) {
1814 if (evpn_prefix2prefix(prefix
, &conv
) != 0)
1821 family
= prefix
->family
;
1823 if (family
== AF_INET
)
1824 table
= map
->ipv4_prefix_table
;
1826 table
= map
->ipv6_prefix_table
;
1832 candidate_rmap_list
=
1833 route_map_get_index_list(&rn
, prefix
, table
);
1837 /* If the index at the head of the list is of seq higher
1838 * than that in best_index, ignore the list and get the
1839 * parent node's list.
1841 head_index
= (struct route_map_index
*)(listgetdata(
1842 listhead(candidate_rmap_list
)));
1843 if (best_index
&& head_index
1844 && (best_index
->pref
< head_index
->pref
)) {
1845 route_unlock_node(rn
);
1849 for (ALL_LIST_ELEMENTS(candidate_rmap_list
, ln
, nn
, index
)) {
1850 /* If the index is of seq higher than that in
1851 * best_index, ignore the list and get the parent
1854 if (best_index
&& (best_index
->pref
< index
->pref
))
1857 ret
= route_map_apply_match(&index
->match_list
, prefix
,
1860 if (ret
== RMAP_MATCH
) {
1864 } else if (ret
== RMAP_NOOP
) {
1866 * If match_ret is denymatch, even if we see
1867 * more noops, we retain this return value and
1868 * return this eventually if there are no
1870 * If a best match route-map index already
1871 * exists, do not reset the match_ret.
1873 if (!best_index
&& (*match_ret
!= RMAP_NOMATCH
))
1877 * ret is RMAP_NOMATCH.
1878 * If a best match route-map index already
1879 * exists, do not reset the match_ret.
1886 route_unlock_node(rn
);
1893 static int route_map_candidate_list_cmp(struct route_map_index
*idx1
,
1894 struct route_map_index
*idx2
)
1896 return idx1
->pref
- idx2
->pref
;
1900 * This function adds the route-map index into the default route's
1901 * route-node in the route-map's IPv4/IPv6 prefix-table.
1903 static void route_map_pfx_table_add_default(afi_t afi
,
1904 struct route_map_index
*index
)
1906 struct route_node
*rn
= NULL
;
1907 struct list
*rmap_candidate_list
= NULL
;
1909 bool updated_rn
= false;
1910 struct route_table
*table
= NULL
;
1912 memset(&p
, 0, sizeof(p
));
1913 p
.family
= afi2family(afi
);
1916 if (p
.family
== AF_INET
) {
1917 table
= index
->map
->ipv4_prefix_table
;
1919 index
->map
->ipv4_prefix_table
= route_table_init();
1921 table
= index
->map
->ipv4_prefix_table
;
1923 table
= index
->map
->ipv6_prefix_table
;
1925 index
->map
->ipv6_prefix_table
= route_table_init();
1927 table
= index
->map
->ipv6_prefix_table
;
1930 /* Add default route to table */
1931 rn
= route_node_get(table
, &p
);
1937 rmap_candidate_list
= list_new();
1938 rmap_candidate_list
->cmp
=
1939 (int (*)(void *, void *))route_map_candidate_list_cmp
;
1940 rn
->info
= rmap_candidate_list
;
1942 rmap_candidate_list
= (struct list
*)rn
->info
;
1946 listnode_add_sort_nodup(rmap_candidate_list
, index
);
1948 route_unlock_node(rn
);
1952 * This function removes the route-map index from the default route's
1953 * route-node in the route-map's IPv4/IPv6 prefix-table.
1955 static void route_map_pfx_table_del_default(afi_t afi
,
1956 struct route_map_index
*index
)
1958 struct route_node
*rn
= NULL
;
1959 struct list
*rmap_candidate_list
= NULL
;
1961 struct route_table
*table
= NULL
;
1963 memset(&p
, 0, sizeof(p
));
1964 p
.family
= afi2family(afi
);
1967 if (p
.family
== AF_INET
)
1968 table
= index
->map
->ipv4_prefix_table
;
1970 table
= index
->map
->ipv6_prefix_table
;
1972 /* Remove RMAP index from default route in table */
1973 rn
= route_node_lookup(table
, &p
);
1974 if (!rn
|| !rn
->info
)
1977 rmap_candidate_list
= (struct list
*)rn
->info
;
1979 listnode_delete(rmap_candidate_list
, index
);
1981 if (listcount(rmap_candidate_list
) == 0) {
1982 list_delete(&rmap_candidate_list
);
1984 route_unlock_node(rn
);
1986 route_unlock_node(rn
);
1990 * This function adds the route-map index to the route-node for
1991 * the prefix-entry in the route-map's IPv4/IPv6 prefix-table.
1993 static void route_map_pfx_table_add(struct route_table
*table
,
1994 struct route_map_index
*index
,
1995 struct prefix_list_entry
*pentry
)
1997 struct route_node
*rn
= NULL
;
1998 struct list
*rmap_candidate_list
= NULL
;
1999 bool updated_rn
= false;
2001 rn
= route_node_get(table
, &pentry
->prefix
);
2006 rmap_candidate_list
= list_new();
2007 rmap_candidate_list
->cmp
=
2008 (int (*)(void *, void *))route_map_candidate_list_cmp
;
2009 rn
->info
= rmap_candidate_list
;
2011 rmap_candidate_list
= (struct list
*)rn
->info
;
2015 listnode_add_sort_nodup(rmap_candidate_list
, index
);
2017 route_unlock_node(rn
);
2021 * This function removes the route-map index from the route-node for
2022 * the prefix-entry in the route-map's IPv4/IPv6 prefix-table.
2024 static void route_map_pfx_table_del(struct route_table
*table
,
2025 struct route_map_index
*index
,
2026 struct prefix_list_entry
*pentry
)
2028 struct route_node
*rn
= NULL
;
2029 struct list
*rmap_candidate_list
= NULL
;
2031 rn
= route_node_lookup(table
, &pentry
->prefix
);
2032 if (!rn
|| !rn
->info
)
2035 rmap_candidate_list
= (struct list
*)rn
->info
;
2037 listnode_delete(rmap_candidate_list
, index
);
2039 if (listcount(rmap_candidate_list
) == 0) {
2040 list_delete(&rmap_candidate_list
);
2042 route_unlock_node(rn
);
2044 route_unlock_node(rn
);
2047 /* This function checks for the presence of an IPv4 prefix-list
2048 * match rule in the given route-map index.
2050 static bool route_map_is_ip_pfx_list_rule_present(struct route_map_index
*index
)
2052 struct route_map_rule_list
*match_list
= NULL
;
2053 struct route_map_rule
*rule
= NULL
;
2055 match_list
= &index
->match_list
;
2056 for (rule
= match_list
->head
; rule
; rule
= rule
->next
)
2057 if (IS_RULE_IPv4_PREFIX_LIST(rule
->cmd
->str
))
2063 /* This function checks for the presence of an IPv6 prefix-list
2064 * match rule in the given route-map index.
2067 route_map_is_ipv6_pfx_list_rule_present(struct route_map_index
*index
)
2069 struct route_map_rule_list
*match_list
= NULL
;
2070 struct route_map_rule
*rule
= NULL
;
2072 match_list
= &index
->match_list
;
2073 for (rule
= match_list
->head
; rule
; rule
= rule
->next
)
2074 if (IS_RULE_IPv6_PREFIX_LIST(rule
->cmd
->str
))
2080 /* This function does the following:
2081 * 1) If plist_name is not present, search for a IPv4 or IPv6 prefix-list
2082 * match clause (based on the afi passed to this foo) and get the
2084 * 2) Look up the prefix-list using the name.
2085 * 3) If the prefix-list is not found then, add the index to the IPv4/IPv6
2086 * default-route's node in the trie (based on the afi passed to this foo).
2087 * 4) If the prefix-list is found then, remove the index from the IPv4/IPv6
2088 * default-route's node in the trie (based on the afi passed to this foo).
2089 * 5) If a prefix-entry is passed then, create a route-node for this entry and
2090 * add this index to the route-node.
2091 * 6) If prefix-entry is not passed then, for every prefix-entry in the
2092 * prefix-list, create a route-node for this entry and
2093 * add this index to the route-node.
2095 static void route_map_add_plist_entries(afi_t afi
,
2096 struct route_map_index
*index
,
2097 const char *plist_name
,
2098 struct prefix_list_entry
*entry
)
2100 struct route_map_rule_list
*match_list
= NULL
;
2101 struct route_map_rule
*match
= NULL
;
2102 struct prefix_list
*plist
= NULL
;
2103 struct prefix_list_entry
*pentry
= NULL
;
2104 bool plist_rule_is_present
= false;
2107 match_list
= &index
->match_list
;
2109 for (match
= match_list
->head
; match
; match
= match
->next
) {
2110 if (afi
== AFI_IP
) {
2111 if (IS_RULE_IPv4_PREFIX_LIST(match
->cmd
->str
)) {
2112 plist_rule_is_present
= true;
2116 if (IS_RULE_IPv6_PREFIX_LIST(match
->cmd
->str
)) {
2117 plist_rule_is_present
= true;
2123 if (plist_rule_is_present
)
2124 plist
= prefix_list_lookup(afi
, match
->rule_str
);
2126 plist
= prefix_list_lookup(afi
, plist_name
);
2130 route_map_pfx_table_add_default(afi
, index
);
2134 /* Default entry should be deleted only if the first entry of the
2135 * prefix-list is created.
2138 if (plist
->count
== 1)
2139 route_map_pfx_table_del_default(afi
, index
);
2141 route_map_pfx_table_del_default(afi
, index
);
2145 if (afi
== AFI_IP
) {
2146 route_map_pfx_table_add(index
->map
->ipv4_prefix_table
,
2149 route_map_pfx_table_add(index
->map
->ipv6_prefix_table
,
2153 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
2154 if (afi
== AFI_IP
) {
2155 route_map_pfx_table_add(
2156 index
->map
->ipv4_prefix_table
, index
,
2159 route_map_pfx_table_add(
2160 index
->map
->ipv6_prefix_table
, index
,
2167 /* This function does the following:
2168 * 1) If plist_name is not present, search for a IPv4 or IPv6 prefix-list
2169 * match clause (based on the afi passed to this foo) and get the
2171 * 2) Look up the prefix-list using the name.
2172 * 3) If the prefix-list is not found then, delete the index from the IPv4/IPv6
2173 * default-route's node in the trie (based on the afi passed to this foo).
2174 * 4) If a prefix-entry is passed then, remove this index from the route-node
2175 * for the prefix in this prefix-entry.
2176 * 5) If prefix-entry is not passed then, for every prefix-entry in the
2177 * prefix-list, remove this index from the route-node
2178 * for the prefix in this prefix-entry.
2180 static void route_map_del_plist_entries(afi_t afi
,
2181 struct route_map_index
*index
,
2182 const char *plist_name
,
2183 struct prefix_list_entry
*entry
)
2185 struct route_map_rule_list
*match_list
= NULL
;
2186 struct route_map_rule
*match
= NULL
;
2187 struct prefix_list
*plist
= NULL
;
2188 struct prefix_list_entry
*pentry
= NULL
;
2189 bool plist_rule_is_present
= false;
2192 match_list
= &index
->match_list
;
2194 for (match
= match_list
->head
; match
; match
= match
->next
) {
2195 if (afi
== AFI_IP
) {
2196 if (IS_RULE_IPv4_PREFIX_LIST(match
->cmd
->str
)) {
2197 plist_rule_is_present
= true;
2201 if (IS_RULE_IPv6_PREFIX_LIST(match
->cmd
->str
)) {
2202 plist_rule_is_present
= true;
2208 if (plist_rule_is_present
)
2209 plist
= prefix_list_lookup(afi
, match
->rule_str
);
2211 plist
= prefix_list_lookup(afi
, plist_name
);
2215 route_map_pfx_table_del_default(afi
, index
);
2220 if (afi
== AFI_IP
) {
2221 route_map_pfx_table_del(index
->map
->ipv4_prefix_table
,
2224 route_map_pfx_table_del(index
->map
->ipv6_prefix_table
,
2228 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
2229 if (afi
== AFI_IP
) {
2230 route_map_pfx_table_del(
2231 index
->map
->ipv4_prefix_table
, index
,
2234 route_map_pfx_table_del(
2235 index
->map
->ipv6_prefix_table
, index
,
2243 * This function handles the cases where a prefix-list is added/removed
2244 * as a match command from a particular route-map index.
2245 * It updates the prefix-table of the route-map accordingly.
2247 static void route_map_trie_update(afi_t afi
, route_map_event_t event
,
2248 struct route_map_index
*index
,
2249 const char *plist_name
)
2251 if (event
== RMAP_EVENT_PLIST_ADDED
) {
2252 if (afi
== AFI_IP
) {
2253 if (!route_map_is_ipv6_pfx_list_rule_present(index
)) {
2254 route_map_pfx_table_del_default(AFI_IP6
, index
);
2255 route_map_add_plist_entries(afi
, index
,
2258 route_map_del_plist_entries(AFI_IP6
, index
,
2262 if (!route_map_is_ip_pfx_list_rule_present(index
)) {
2263 route_map_pfx_table_del_default(AFI_IP
, index
);
2264 route_map_add_plist_entries(afi
, index
,
2267 route_map_del_plist_entries(AFI_IP
, index
, NULL
,
2271 } else if (event
== RMAP_EVENT_PLIST_DELETED
) {
2272 if (afi
== AFI_IP
) {
2273 route_map_del_plist_entries(afi
, index
, plist_name
,
2276 /* If IPv6 prefix-list match rule is not present,
2277 * add this index to the IPv4 default route's trie
2279 * Also, add this index to the trie nodes created
2280 * for each of the prefix-entries within the IPv6
2281 * prefix-list, if the IPv6 prefix-list match rule
2282 * is present. Else, add this index to the IPv6
2283 * default route's trie node.
2285 if (!route_map_is_ipv6_pfx_list_rule_present(index
))
2286 route_map_pfx_table_add_default(afi
, index
);
2288 route_map_add_plist_entries(AFI_IP6
, index
, NULL
, NULL
);
2290 route_map_del_plist_entries(afi
, index
, plist_name
,
2293 /* If IPv4 prefix-list match rule is not present,
2294 * add this index to the IPv6 default route's trie
2296 * Also, add this index to the trie nodes created
2297 * for each of the prefix-entries within the IPv4
2298 * prefix-list, if the IPv4 prefix-list match rule
2299 * is present. Else, add this index to the IPv4
2300 * default route's trie node.
2302 if (!route_map_is_ip_pfx_list_rule_present(index
))
2303 route_map_pfx_table_add_default(afi
, index
);
2305 route_map_add_plist_entries(AFI_IP
, index
, NULL
, NULL
);
2311 * This function handles the cases where a route-map index and
2312 * prefix-list is added/removed.
2313 * It updates the prefix-table of the route-map accordingly.
2315 static void route_map_pfx_tbl_update(route_map_event_t event
,
2316 struct route_map_index
*index
, afi_t afi
,
2317 const char *plist_name
)
2319 struct route_map
*rmap
= NULL
;
2324 if (event
== RMAP_EVENT_INDEX_ADDED
) {
2325 route_map_pfx_table_add_default(AFI_IP
, index
);
2326 route_map_pfx_table_add_default(AFI_IP6
, index
);
2330 if (event
== RMAP_EVENT_INDEX_DELETED
) {
2331 route_map_pfx_table_del_default(AFI_IP
, index
);
2332 route_map_pfx_table_del_default(AFI_IP6
, index
);
2334 if ((index
->map
->head
== NULL
) && (index
->map
->tail
== NULL
)) {
2337 if (rmap
->ipv4_prefix_table
) {
2338 route_table_finish(rmap
->ipv4_prefix_table
);
2339 rmap
->ipv4_prefix_table
= NULL
;
2342 if (rmap
->ipv6_prefix_table
) {
2343 route_table_finish(rmap
->ipv6_prefix_table
);
2344 rmap
->ipv6_prefix_table
= NULL
;
2350 /* Handle prefix-list match rule addition/deletion.
2352 route_map_trie_update(afi
, event
, index
, plist_name
);
2356 * This function handles the cases where a new prefix-entry is added to
2357 * a prefix-list or, an existing prefix-entry is removed from the prefix-list.
2358 * It updates the prefix-table of the route-map accordingly.
2360 static void route_map_pentry_update(route_map_event_t event
,
2361 const char *plist_name
,
2362 struct route_map_index
*index
,
2363 struct prefix_list_entry
*pentry
)
2365 struct prefix_list
*plist
= NULL
;
2367 unsigned char family
= pentry
->prefix
.family
;
2369 if (family
== AF_INET
) {
2371 plist
= prefix_list_lookup(AFI_IP
, plist_name
);
2374 plist
= prefix_list_lookup(AFI_IP6
, plist_name
);
2377 if (event
== RMAP_EVENT_PLIST_ADDED
) {
2378 if (afi
== AFI_IP
) {
2379 if (!route_map_is_ipv6_pfx_list_rule_present(index
))
2380 route_map_add_plist_entries(afi
, index
,
2381 plist_name
, pentry
);
2383 if (!route_map_is_ip_pfx_list_rule_present(index
))
2384 route_map_add_plist_entries(afi
, index
,
2385 plist_name
, pentry
);
2387 } else if (event
== RMAP_EVENT_PLIST_DELETED
) {
2388 route_map_del_plist_entries(afi
, index
, plist_name
, pentry
);
2390 if (plist
->count
== 1) {
2391 if (afi
== AFI_IP
) {
2392 if (!route_map_is_ipv6_pfx_list_rule_present(
2394 route_map_pfx_table_add_default(afi
,
2397 if (!route_map_is_ip_pfx_list_rule_present(
2399 route_map_pfx_table_add_default(afi
,
2406 static void route_map_pentry_process_dependency(struct hash_bucket
*bucket
,
2409 char *rmap_name
= NULL
;
2410 struct route_map
*rmap
= NULL
;
2411 struct route_map_index
*index
= NULL
;
2412 struct route_map_rule_list
*match_list
= NULL
;
2413 struct route_map_rule
*match
= NULL
;
2414 struct route_map_dep_data
*dep_data
= NULL
;
2415 struct route_map_pentry_dep
*pentry_dep
=
2416 (struct route_map_pentry_dep
*)data
;
2417 unsigned char family
= pentry_dep
->pentry
->prefix
.family
;
2419 dep_data
= (struct route_map_dep_data
*)bucket
->data
;
2423 rmap_name
= dep_data
->rname
;
2424 rmap
= route_map_lookup_by_name(rmap_name
);
2425 if (!rmap
|| !rmap
->head
)
2428 for (index
= rmap
->head
; index
; index
= index
->next
) {
2429 match_list
= &index
->match_list
;
2434 for (match
= match_list
->head
; match
; match
= match
->next
) {
2435 if (strcmp(match
->rule_str
, pentry_dep
->plist_name
)
2437 if (IS_RULE_IPv4_PREFIX_LIST(match
->cmd
->str
)
2438 && family
== AF_INET
) {
2439 route_map_pentry_update(
2441 pentry_dep
->plist_name
, index
,
2442 pentry_dep
->pentry
);
2443 } else if (IS_RULE_IPv6_PREFIX_LIST(
2445 && family
== AF_INET6
) {
2446 route_map_pentry_update(
2448 pentry_dep
->plist_name
, index
,
2449 pentry_dep
->pentry
);
2456 void route_map_notify_pentry_dependencies(const char *affected_name
,
2457 struct prefix_list_entry
*pentry
,
2458 route_map_event_t event
)
2460 struct route_map_dep
*dep
= NULL
;
2461 struct hash
*upd8_hash
= NULL
;
2462 struct route_map_pentry_dep pentry_dep
;
2464 if (!affected_name
|| !pentry
)
2467 upd8_hash
= route_map_get_dep_hash(event
);
2471 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, (void *)affected_name
,
2474 if (!dep
->this_hash
)
2475 dep
->this_hash
= upd8_hash
;
2477 memset(&pentry_dep
, 0, sizeof(pentry_dep
));
2478 pentry_dep
.pentry
= pentry
;
2479 pentry_dep
.plist_name
= affected_name
;
2480 pentry_dep
.event
= event
;
2482 hash_iterate(dep
->dep_rmap_hash
,
2483 route_map_pentry_process_dependency
,
2484 (void *)&pentry_dep
);
2488 /* Apply route map's each index to the object.
2490 The matrix for a route-map looks like this:
2491 (note, this includes the description for the "NEXT"
2492 and "GOTO" frobs now
2494 | Match | No Match | No op
2495 |-----------|--------------|-------
2496 permit | action | cont | cont.
2497 | | default:deny | default:permit
2498 -------------------+-----------------------
2499 | deny | cont | cont.
2500 deny | | default:deny | default:permit
2501 |-----------|--------------|--------
2504 -Apply Set statements, accept route
2505 -If Call statement is present jump to the specified route-map, if it
2506 denies the route we finish.
2507 -If NEXT is specified, goto NEXT statement
2508 -If GOTO is specified, goto the first clause where pref > nextpref
2509 -If nothing is specified, do as Cisco and finish
2511 -Route is denied by route-map.
2515 If we get no matches after we've processed all updates, then the route
2518 Some notes on the new "CALL", "NEXT" and "GOTO"
2519 call WORD - If this clause is matched, then the set statements
2520 are executed and then we jump to route-map 'WORD'. If
2521 this route-map denies the route, we finish, in other
2523 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
2524 on-match next - If this clause is matched, then the set statements
2525 are executed and then we drop through to the next clause
2526 on-match goto n - If this clause is matched, then the set statements
2527 are executed and then we goto the nth clause, or the
2528 first clause greater than this. In order to ensure
2529 route-maps *always* exit, you cannot jump backwards.
2532 We need to make sure our route-map processing matches the above
2534 route_map_result_t
route_map_apply_ext(struct route_map
*map
,
2535 const struct prefix
*prefix
,
2536 void *match_object
, void *set_object
,
2539 static int recursion
= 0;
2540 enum route_map_cmd_result_t match_ret
= RMAP_NOMATCH
;
2541 route_map_result_t ret
= RMAP_PERMITMATCH
;
2542 struct route_map_index
*index
= NULL
;
2543 struct route_map_rule
*set
= NULL
;
2544 bool skip_match_clause
= false;
2546 if (recursion
> RMAP_RECURSION_LIMIT
) {
2548 EC_LIB_RMAP_RECURSION_LIMIT
,
2549 "route-map recursion limit (%d) reached, discarding route",
2550 RMAP_RECURSION_LIMIT
);
2552 return RMAP_DENYMATCH
;
2555 if (map
== NULL
|| map
->head
== NULL
) {
2556 ret
= RMAP_DENYMATCH
;
2557 goto route_map_apply_end
;
2562 if ((!map
->optimization_disabled
)
2563 && (map
->ipv4_prefix_table
|| map
->ipv6_prefix_table
)) {
2564 index
= route_map_get_index(map
, prefix
, match_object
,
2570 "Best match route-map: %s, sequence: %d for pfx: %pFX, result: %s",
2571 map
->name
, index
->pref
, prefix
,
2572 route_map_cmd_result_str(match_ret
));
2576 "No best match sequence for pfx: %pFX in route-map: %s, result: %s",
2578 route_map_cmd_result_str(match_ret
));
2580 * No index matches this prefix. Return deny unless,
2581 * match_ret = RMAP_NOOP.
2583 if (match_ret
== RMAP_NOOP
)
2584 ret
= RMAP_PERMITMATCH
;
2586 ret
= RMAP_DENYMATCH
;
2587 goto route_map_apply_end
;
2589 skip_match_clause
= true;
2594 for (; index
; index
= index
->next
) {
2595 if (!skip_match_clause
) {
2597 /* Apply this index. */
2598 match_ret
= route_map_apply_match(&index
->match_list
,
2599 prefix
, match_object
);
2602 "Route-map: %s, sequence: %d, prefix: %pFX, result: %s",
2603 map
->name
, index
->pref
, prefix
,
2604 route_map_cmd_result_str(match_ret
));
2607 skip_match_clause
= false;
2610 /* Now we apply the matrix from above */
2611 if (match_ret
== RMAP_NOOP
)
2613 * Do not change the return value. Retain the previous
2614 * return value. Previous values can be:
2615 * 1)permitmatch (if a nomatch was never
2616 * seen before in this route-map.)
2617 * 2)denymatch (if a nomatch was seen earlier in one
2618 * of the previous sequences)
2622 * 'cont' from matrix - continue to next route-map
2626 else if (match_ret
== RMAP_NOMATCH
) {
2629 * The return value is now changed to denymatch.
2630 * So from here on out, even if we see more noops,
2631 * we retain this return value and return this
2632 * eventually if there are no matches.
2634 ret
= RMAP_DENYMATCH
;
2637 * 'cont' from matrix - continue to next route-map
2641 } else if (match_ret
== RMAP_MATCH
) {
2642 if (index
->type
== RMAP_PERMIT
)
2645 /* Match succeeded, rmap is of type permit */
2646 ret
= RMAP_PERMITMATCH
;
2648 /* permit+match must execute sets */
2649 for (set
= index
->set_list
.head
; set
;
2652 * set cmds return RMAP_OKAY or
2653 * RMAP_ERROR. We do not care if
2654 * set succeeded or not. So, ignore
2657 (void)(*set
->cmd
->func_apply
)(
2658 set
->value
, prefix
, set_object
);
2660 /* Call another route-map if available */
2661 if (index
->nextrm
) {
2662 struct route_map
*nextrm
=
2663 route_map_lookup_by_name(
2666 if (nextrm
) /* Target route-map found,
2670 ret
= route_map_apply_ext(
2677 /* If nextrm returned 'deny', finish. */
2678 if (ret
== RMAP_DENYMATCH
)
2679 goto route_map_apply_end
;
2682 switch (index
->exitpolicy
) {
2684 goto route_map_apply_end
;
2688 /* Find the next clause to jump to */
2689 struct route_map_index
*next
=
2691 int nextpref
= index
->nextpref
;
2693 while (next
&& next
->pref
< nextpref
) {
2698 /* No clauses match! */
2699 goto route_map_apply_end
;
2703 } else if (index
->type
== RMAP_DENY
)
2706 ret
= RMAP_DENYMATCH
;
2707 goto route_map_apply_end
;
2712 route_map_apply_end
:
2714 zlog_debug("Route-map: %s, prefix: %pFX, result: %s",
2715 (map
? map
->name
: "null"), prefix
,
2716 route_map_result_str(ret
));
2719 if (index
!= NULL
&& ret
== RMAP_PERMITMATCH
)
2720 *pref
= index
->pref
;
2728 void route_map_add_hook(void (*func
)(const char *))
2730 route_map_master
.add_hook
= func
;
2733 void route_map_delete_hook(void (*func
)(const char *))
2735 route_map_master
.delete_hook
= func
;
2738 void route_map_event_hook(void (*func
)(const char *name
))
2740 route_map_master
.event_hook
= func
;
2743 /* Routines for route map dependency lists and dependency processing */
2744 static bool route_map_rmap_hash_cmp(const void *p1
, const void *p2
)
2746 return strcmp(((const struct route_map_dep_data
*)p1
)->rname
,
2747 ((const struct route_map_dep_data
*)p2
)->rname
)
2751 static bool route_map_dep_hash_cmp(const void *p1
, const void *p2
)
2754 return (strcmp(((const struct route_map_dep
*)p1
)->dep_name
,
2759 static void route_map_clear_reference(struct hash_bucket
*bucket
, void *arg
)
2761 struct route_map_dep
*dep
= bucket
->data
;
2762 struct route_map_dep_data
*dep_data
= NULL
, tmp_dep_data
;
2764 memset(&tmp_dep_data
, 0, sizeof(tmp_dep_data
));
2765 tmp_dep_data
.rname
= arg
;
2766 dep_data
= hash_release(dep
->dep_rmap_hash
, &tmp_dep_data
);
2769 zlog_debug("Clearing reference for %s to %s count: %d",
2770 dep
->dep_name
, tmp_dep_data
.rname
,
2773 XFREE(MTYPE_ROUTE_MAP_NAME
, dep_data
->rname
);
2774 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, dep_data
);
2776 if (!dep
->dep_rmap_hash
->count
) {
2777 dep
= hash_release(dep
->this_hash
, (void *)dep
->dep_name
);
2778 hash_free(dep
->dep_rmap_hash
);
2779 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
2780 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
2784 static void route_map_clear_all_references(char *rmap_name
)
2789 zlog_debug("Clearing references for %s", rmap_name
);
2791 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
2792 hash_iterate(route_map_dep_hash
[i
], route_map_clear_reference
,
2797 static unsigned int route_map_dep_data_hash_make_key(const void *p
)
2799 const struct route_map_dep_data
*dep_data
= p
;
2801 return string_hash_make(dep_data
->rname
);
2804 static void *route_map_dep_hash_alloc(void *p
)
2806 char *dep_name
= (char *)p
;
2807 struct route_map_dep
*dep_entry
;
2809 dep_entry
= XCALLOC(MTYPE_ROUTE_MAP_DEP
, sizeof(struct route_map_dep
));
2810 dep_entry
->dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
2811 dep_entry
->dep_rmap_hash
=
2812 hash_create_size(8, route_map_dep_data_hash_make_key
,
2813 route_map_rmap_hash_cmp
, "Route Map Dep Hash");
2814 dep_entry
->this_hash
= NULL
;
2819 static void *route_map_name_hash_alloc(void *p
)
2821 struct route_map_dep_data
*dep_data
= NULL
, *tmp_dep_data
= NULL
;
2823 dep_data
= XCALLOC(MTYPE_ROUTE_MAP_DEP_DATA
,
2824 sizeof(struct route_map_dep_data
));
2826 dep_data
->rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, tmp_dep_data
->rname
);
2830 static unsigned int route_map_dep_hash_make_key(const void *p
)
2832 return (string_hash_make((char *)p
));
2835 static void route_map_print_dependency(struct hash_bucket
*bucket
, void *data
)
2837 struct route_map_dep_data
*dep_data
= bucket
->data
;
2838 char *rmap_name
= dep_data
->rname
;
2839 char *dep_name
= data
;
2841 zlog_debug("%s: Dependency for %s: %s", __func__
, dep_name
, rmap_name
);
2844 static int route_map_dep_update(struct hash
*dephash
, const char *dep_name
,
2845 const char *rmap_name
, route_map_event_t type
)
2847 struct route_map_dep
*dep
= NULL
;
2848 char *dname
, *rname
;
2850 struct route_map_dep_data
*dep_data
= NULL
, *ret_dep_data
= NULL
;
2851 struct route_map_dep_data tmp_dep_data
;
2853 dname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
2854 rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
2857 case RMAP_EVENT_PLIST_ADDED
:
2858 case RMAP_EVENT_CLIST_ADDED
:
2859 case RMAP_EVENT_ECLIST_ADDED
:
2860 case RMAP_EVENT_ASLIST_ADDED
:
2861 case RMAP_EVENT_LLIST_ADDED
:
2862 case RMAP_EVENT_CALL_ADDED
:
2863 case RMAP_EVENT_FILTER_ADDED
:
2865 zlog_debug("Adding dependency for filter %s in route-map %s",
2866 dep_name
, rmap_name
);
2867 dep
= (struct route_map_dep
*)hash_get(
2868 dephash
, dname
, route_map_dep_hash_alloc
);
2874 if (!dep
->this_hash
)
2875 dep
->this_hash
= dephash
;
2877 memset(&tmp_dep_data
, 0, sizeof(tmp_dep_data
));
2878 tmp_dep_data
.rname
= rname
;
2879 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
2881 dep_data
= hash_get(dep
->dep_rmap_hash
, &tmp_dep_data
,
2882 route_map_name_hash_alloc
);
2886 case RMAP_EVENT_PLIST_DELETED
:
2887 case RMAP_EVENT_CLIST_DELETED
:
2888 case RMAP_EVENT_ECLIST_DELETED
:
2889 case RMAP_EVENT_ASLIST_DELETED
:
2890 case RMAP_EVENT_LLIST_DELETED
:
2891 case RMAP_EVENT_CALL_DELETED
:
2892 case RMAP_EVENT_FILTER_DELETED
:
2894 zlog_debug("Deleting dependency for filter %s in route-map %s",
2895 dep_name
, rmap_name
);
2896 dep
= (struct route_map_dep
*)hash_get(dephash
, dname
, NULL
);
2901 memset(&tmp_dep_data
, 0, sizeof(tmp_dep_data
));
2902 tmp_dep_data
.rname
= rname
;
2903 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
2905 * If dep_data is NULL then something has gone seriously
2906 * wrong in route-map handling. Note it and prevent
2911 "route-map dependency for route-map %s: %s is not correct",
2912 rmap_name
, dep_name
);
2918 if (!dep_data
->refcnt
) {
2919 ret_dep_data
= hash_release(dep
->dep_rmap_hash
,
2922 XFREE(MTYPE_ROUTE_MAP_NAME
,
2923 ret_dep_data
->rname
);
2924 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, ret_dep_data
);
2928 if (!dep
->dep_rmap_hash
->count
) {
2929 dep
= hash_release(dephash
, dname
);
2930 hash_free(dep
->dep_rmap_hash
);
2931 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
2932 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
2935 case RMAP_EVENT_SET_ADDED
:
2936 case RMAP_EVENT_SET_DELETED
:
2937 case RMAP_EVENT_SET_REPLACED
:
2938 case RMAP_EVENT_MATCH_ADDED
:
2939 case RMAP_EVENT_MATCH_DELETED
:
2940 case RMAP_EVENT_MATCH_REPLACED
:
2941 case RMAP_EVENT_INDEX_ADDED
:
2942 case RMAP_EVENT_INDEX_DELETED
:
2948 hash_iterate(dep
->dep_rmap_hash
,
2949 route_map_print_dependency
, dname
);
2953 XFREE(MTYPE_ROUTE_MAP_NAME
, rname
);
2954 XFREE(MTYPE_ROUTE_MAP_NAME
, dname
);
2958 static struct hash
*route_map_get_dep_hash(route_map_event_t event
)
2960 struct hash
*upd8_hash
= NULL
;
2963 case RMAP_EVENT_PLIST_ADDED
:
2964 case RMAP_EVENT_PLIST_DELETED
:
2965 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_PLIST
];
2967 case RMAP_EVENT_CLIST_ADDED
:
2968 case RMAP_EVENT_CLIST_DELETED
:
2969 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_CLIST
];
2971 case RMAP_EVENT_ECLIST_ADDED
:
2972 case RMAP_EVENT_ECLIST_DELETED
:
2973 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ECLIST
];
2975 case RMAP_EVENT_ASLIST_ADDED
:
2976 case RMAP_EVENT_ASLIST_DELETED
:
2977 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ASPATH
];
2979 case RMAP_EVENT_LLIST_ADDED
:
2980 case RMAP_EVENT_LLIST_DELETED
:
2981 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_LCLIST
];
2983 case RMAP_EVENT_CALL_ADDED
:
2984 case RMAP_EVENT_CALL_DELETED
:
2985 case RMAP_EVENT_MATCH_ADDED
:
2986 case RMAP_EVENT_MATCH_DELETED
:
2987 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_RMAP
];
2989 case RMAP_EVENT_FILTER_ADDED
:
2990 case RMAP_EVENT_FILTER_DELETED
:
2991 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_FILTER
];
2994 * Should we actually be ignoring these?
2995 * I am not sure but at this point in time, let
2996 * us get them into this switch and we can peel
2997 * them into the appropriate place in the future
2999 case RMAP_EVENT_SET_ADDED
:
3000 case RMAP_EVENT_SET_DELETED
:
3001 case RMAP_EVENT_SET_REPLACED
:
3002 case RMAP_EVENT_MATCH_REPLACED
:
3003 case RMAP_EVENT_INDEX_ADDED
:
3004 case RMAP_EVENT_INDEX_DELETED
:
3011 static void route_map_process_dependency(struct hash_bucket
*bucket
, void *data
)
3013 struct route_map_dep_data
*dep_data
= NULL
;
3014 char *rmap_name
= NULL
;
3016 dep_data
= bucket
->data
;
3017 rmap_name
= dep_data
->rname
;
3020 zlog_debug("Notifying %s of dependency", rmap_name
);
3021 if (route_map_master
.event_hook
)
3022 (*route_map_master
.event_hook
)(rmap_name
);
3025 void route_map_upd8_dependency(route_map_event_t type
, const char *arg
,
3026 const char *rmap_name
)
3028 struct hash
*upd8_hash
= NULL
;
3030 if ((upd8_hash
= route_map_get_dep_hash(type
))) {
3031 route_map_dep_update(upd8_hash
, arg
, rmap_name
, type
);
3033 if (type
== RMAP_EVENT_CALL_ADDED
) {
3035 if (route_map_master
.add_hook
)
3036 (*route_map_master
.add_hook
)(rmap_name
);
3037 } else if (type
== RMAP_EVENT_CALL_DELETED
) {
3039 if (route_map_master
.delete_hook
)
3040 (*route_map_master
.delete_hook
)(rmap_name
);
3045 void route_map_notify_dependencies(const char *affected_name
,
3046 route_map_event_t event
)
3048 struct route_map_dep
*dep
;
3049 struct hash
*upd8_hash
;
3055 name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, affected_name
);
3057 if ((upd8_hash
= route_map_get_dep_hash(event
)) == NULL
) {
3058 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
3062 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, name
, NULL
);
3064 if (!dep
->this_hash
)
3065 dep
->this_hash
= upd8_hash
;
3068 zlog_debug("Filter %s updated", dep
->dep_name
);
3069 hash_iterate(dep
->dep_rmap_hash
, route_map_process_dependency
,
3073 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
3076 /* VTY related functions. */
3077 static void clear_route_map_helper(struct route_map
*map
)
3079 struct route_map_index
*index
;
3081 map
->applied_clear
= map
->applied
;
3082 for (index
= map
->head
; index
; index
= index
->next
)
3083 index
->applied_clear
= index
->applied
;
3086 DEFUN (rmap_clear_counters
,
3087 rmap_clear_counters_cmd
,
3088 "clear route-map counters [WORD]",
3090 "route-map information\n"
3091 "counters associated with the specified route-map\n"
3095 struct route_map
*map
;
3097 const char *name
= (argc
== 3 ) ? argv
[idx_word
]->arg
: NULL
;
3100 map
= route_map_lookup_by_name(name
);
3103 clear_route_map_helper(map
);
3105 vty_out(vty
, "%s: 'route-map %s' not found\n",
3106 frr_protonameinst
, name
);
3110 for (map
= route_map_master
.head
; map
; map
= map
->next
)
3111 clear_route_map_helper(map
);
3118 DEFUN (rmap_show_name
,
3120 "show route-map [WORD] [json]",
3122 "route-map information\n"
3126 bool uj
= use_json(argc
, argv
);
3128 const char *name
= NULL
;
3130 if (argv_find(argv
, argc
, "WORD", &idx
))
3131 name
= argv
[idx
]->arg
;
3133 return vty_show_route_map(vty
, name
, uj
);
3136 DEFUN (rmap_show_unused
,
3137 rmap_show_unused_cmd
,
3138 "show route-map-unused",
3140 "unused route-map information\n")
3142 return vty_show_unused_route_map(vty
);
3149 "Debug option set for route-maps\n")
3155 DEFUN (no_debug_rmap
,
3157 "no debug route-map",
3160 "Debug option set for route-maps\n")
3167 static int rmap_config_write_debug(struct vty
*vty
);
3168 static struct cmd_node rmap_debug_node
= {
3169 .name
= "route-map debug",
3170 .node
= RMAP_DEBUG_NODE
,
3172 .config_write
= rmap_config_write_debug
,
3175 void route_map_show_debug(struct vty
*vty
)
3178 vty_out(vty
, "debug route-map\n");
3181 /* Configuration write function. */
3182 static int rmap_config_write_debug(struct vty
*vty
)
3187 vty_out(vty
, "debug route-map\n");
3194 /* Common route map rules */
3196 void *route_map_rule_tag_compile(const char *arg
)
3198 unsigned long int tmp
;
3203 tmp
= strtoul(arg
, &endptr
, 0);
3204 if (arg
[0] == '\0' || *endptr
!= '\0' || errno
|| tmp
> ROUTE_TAG_MAX
)
3207 tag
= XMALLOC(MTYPE_ROUTE_MAP_COMPILED
, sizeof(*tag
));
3213 void route_map_rule_tag_free(void *rule
)
3215 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
3218 void route_map_finish(void)
3221 struct route_map_rule_cmd_proxy
*proxy
;
3223 /* these 2 hash tables have INIT_HASH initializers, so the "default"
3224 * state is "initialized & empty" => fini() followed by init() to
3225 * return to that same state
3227 while ((proxy
= rmap_cmd_name_pop(rmap_match_cmds
)))
3229 rmap_cmd_name_fini(rmap_match_cmds
);
3230 rmap_cmd_name_init(rmap_match_cmds
);
3232 while ((proxy
= rmap_cmd_name_pop(rmap_set_cmds
)))
3234 rmap_cmd_name_fini(rmap_set_cmds
);
3235 rmap_cmd_name_init(rmap_set_cmds
);
3238 * All protocols are setting these to NULL
3239 * by default on shutdown( route_map_finish )
3240 * Why are we making them do this work?
3242 route_map_master
.add_hook
= NULL
;
3243 route_map_master
.delete_hook
= NULL
;
3244 route_map_master
.event_hook
= NULL
;
3246 /* cleanup route_map */
3247 while (route_map_master
.head
) {
3248 struct route_map
*map
= route_map_master
.head
;
3249 map
->to_be_processed
= false;
3250 route_map_delete(map
);
3253 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
3254 hash_free(route_map_dep_hash
[i
]);
3255 route_map_dep_hash
[i
] = NULL
;
3258 hash_free(route_map_master_hash
);
3259 route_map_master_hash
= NULL
;
3262 /* Increment the use_count counter while attaching the route map */
3263 void route_map_counter_increment(struct route_map
*map
)
3269 /* Decrement the use_count counter while detaching the route map. */
3270 void route_map_counter_decrement(struct route_map
*map
)
3273 if (map
->use_count
<= 0)
3279 DEFUN_HIDDEN(show_route_map_pfx_tbl
, show_route_map_pfx_tbl_cmd
,
3280 "show route-map RMAP_NAME prefix-table",
3284 "internal prefix-table\n")
3286 const char *rmap_name
= argv
[2]->arg
;
3287 struct route_map
*rmap
= NULL
;
3288 struct route_table
*rm_pfx_tbl4
= NULL
;
3289 struct route_table
*rm_pfx_tbl6
= NULL
;
3290 struct route_node
*rn
= NULL
, *prn
= NULL
;
3291 struct list
*rmap_index_list
= NULL
;
3292 struct listnode
*ln
= NULL
, *nln
= NULL
;
3293 struct route_map_index
*index
= NULL
;
3296 vty_out(vty
, "%s:\n", frr_protonameinst
);
3297 rmap
= route_map_lookup_by_name(rmap_name
);
3299 rm_pfx_tbl4
= rmap
->ipv4_prefix_table
;
3301 vty_out(vty
, "\n%s%43s%s\n", "IPv4 Prefix", "",
3302 "Route-map Index List");
3303 vty_out(vty
, "%s%39s%s\n", "_______________", "",
3304 "____________________");
3305 for (rn
= route_top(rm_pfx_tbl4
); rn
;
3306 rn
= route_next(rn
)) {
3307 vty_out(vty
, " %pRN (%d)\n", rn
,
3308 route_node_get_lock_count(rn
));
3310 vty_out(vty
, "(P) ");
3313 vty_out(vty
, "%pRN\n", prn
);
3317 rmap_index_list
= (struct list
*)rn
->info
;
3318 if (!rmap_index_list
3319 || !listcount(rmap_index_list
))
3320 vty_out(vty
, "%*s%s\n", len
, "", "-");
3322 for (ALL_LIST_ELEMENTS(rmap_index_list
,
3325 vty_out(vty
, "%*s%s seq %d\n",
3334 rm_pfx_tbl6
= rmap
->ipv6_prefix_table
;
3336 vty_out(vty
, "\n%s%43s%s\n", "IPv6 Prefix", "",
3337 "Route-map Index List");
3338 vty_out(vty
, "%s%39s%s\n", "_______________", "",
3339 "____________________");
3340 for (rn
= route_top(rm_pfx_tbl6
); rn
;
3341 rn
= route_next(rn
)) {
3342 vty_out(vty
, " %pRN (%d)\n", rn
,
3343 route_node_get_lock_count(rn
));
3345 vty_out(vty
, "(P) ");
3348 vty_out(vty
, "%pRN\n", prn
);
3352 rmap_index_list
= (struct list
*)rn
->info
;
3353 if (!rmap_index_list
3354 || !listcount(rmap_index_list
))
3355 vty_out(vty
, "%*s%s\n", len
, "", "-");
3357 for (ALL_LIST_ELEMENTS(rmap_index_list
,
3360 vty_out(vty
, "%*s%s seq %d\n",
3374 /* Initialization of route map vector. */
3375 void route_map_init(void)
3379 route_map_master_hash
=
3380 hash_create_size(8, route_map_hash_key_make
, route_map_hash_cmp
,
3381 "Route Map Master Hash");
3383 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++)
3384 route_map_dep_hash
[i
] = hash_create_size(
3385 8, route_map_dep_hash_make_key
, route_map_dep_hash_cmp
,
3386 "Route Map Dep Hash");
3390 route_map_cli_init();
3392 /* Install route map top node. */
3393 install_node(&rmap_debug_node
);
3395 /* Install route map commands. */
3396 install_element(CONFIG_NODE
, &debug_rmap_cmd
);
3397 install_element(CONFIG_NODE
, &no_debug_rmap_cmd
);
3399 /* Install show command */
3400 install_element(ENABLE_NODE
, &rmap_clear_counters_cmd
);
3402 install_element(ENABLE_NODE
, &rmap_show_name_cmd
);
3403 install_element(ENABLE_NODE
, &rmap_show_unused_cmd
);
3405 install_element(ENABLE_NODE
, &debug_rmap_cmd
);
3406 install_element(ENABLE_NODE
, &no_debug_rmap_cmd
);
3408 install_element(ENABLE_NODE
, &show_route_map_pfx_tbl_cmd
);