1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 1998, 1999 Kunihiro Ishiguro
19 #include "lib_errors.h"
24 #include "lib/routemap_clippy.c"
26 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP
, "Route map");
27 DEFINE_MTYPE(LIB
, ROUTE_MAP_NAME
, "Route map name");
28 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_INDEX
, "Route map index");
29 DEFINE_MTYPE(LIB
, ROUTE_MAP_RULE
, "Route map rule");
30 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_RULE_STR
, "Route map rule str");
31 DEFINE_MTYPE(LIB
, ROUTE_MAP_COMPILED
, "Route map compiled");
32 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_DEP
, "Route map dependency");
33 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_DEP_DATA
, "Route map dependency data");
35 DEFINE_QOBJ_TYPE(route_map_index
);
36 DEFINE_QOBJ_TYPE(route_map
);
38 static int rmap_cmd_name_cmp(const struct route_map_rule_cmd_proxy
*a
,
39 const struct route_map_rule_cmd_proxy
*b
)
41 return strcmp(a
->cmd
->str
, b
->cmd
->str
);
44 static uint32_t rmap_cmd_name_hash(const struct route_map_rule_cmd_proxy
*item
)
46 return jhash(item
->cmd
->str
, strlen(item
->cmd
->str
), 0xbfd69320);
49 DECLARE_HASH(rmap_cmd_name
, struct route_map_rule_cmd_proxy
, itm
,
50 rmap_cmd_name_cmp
, rmap_cmd_name_hash
);
52 static struct rmap_cmd_name_head rmap_match_cmds
[1] = {
53 INIT_HASH(rmap_match_cmds
[0]),
55 static struct rmap_cmd_name_head rmap_set_cmds
[1] = {
56 INIT_HASH(rmap_set_cmds
[0]),
59 #define IPv4_PREFIX_LIST "ip address prefix-list"
60 #define IPv6_PREFIX_LIST "ipv6 address prefix-list"
62 #define IS_RULE_IPv4_PREFIX_LIST(S) \
63 (strncmp(S, IPv4_PREFIX_LIST, strlen(IPv4_PREFIX_LIST)) == 0)
64 #define IS_RULE_IPv6_PREFIX_LIST(S) \
65 (strncmp(S, IPv6_PREFIX_LIST, strlen(IPv6_PREFIX_LIST)) == 0)
67 struct route_map_pentry_dep
{
68 struct prefix_list_entry
*pentry
;
69 const char *plist_name
;
70 route_map_event_t event
;
73 static void route_map_pfx_tbl_update(route_map_event_t event
,
74 struct route_map_index
*index
, afi_t afi
,
75 const char *plist_name
);
76 static void route_map_pfx_table_add_default(afi_t afi
,
77 struct route_map_index
*index
);
78 static void route_map_pfx_table_del_default(afi_t afi
,
79 struct route_map_index
*index
);
80 static void route_map_add_plist_entries(afi_t afi
,
81 struct route_map_index
*index
,
82 const char *plist_name
,
83 struct prefix_list_entry
*entry
);
84 static void route_map_del_plist_entries(afi_t afi
,
85 struct route_map_index
*index
,
86 const char *plist_name
,
87 struct prefix_list_entry
*entry
);
89 static struct hash
*route_map_get_dep_hash(route_map_event_t event
);
90 static void route_map_free_map(struct route_map
*map
);
92 struct route_map_match_set_hooks rmap_match_set_hook
;
95 void route_map_match_interface_hook(int (*func
)(
96 struct route_map_index
*index
, const char *command
,
97 const char *arg
, route_map_event_t type
,
98 char *errmsg
, size_t errmsg_len
))
100 rmap_match_set_hook
.match_interface
= func
;
103 /* no match interface */
104 void route_map_no_match_interface_hook(int (*func
)(
105 struct route_map_index
*index
, const char *command
,
106 const char *arg
, route_map_event_t type
,
107 char *errmsg
, size_t errmsg_len
))
109 rmap_match_set_hook
.no_match_interface
= func
;
112 /* match ip address */
113 void route_map_match_ip_address_hook(int (*func
)(
114 struct route_map_index
*index
, const char *command
,
115 const char *arg
, route_map_event_t type
,
116 char *errmsg
, size_t errmsg_len
))
118 rmap_match_set_hook
.match_ip_address
= func
;
121 /* no match ip address */
122 void route_map_no_match_ip_address_hook(int (*func
)(
123 struct route_map_index
*index
, const char *command
,
124 const char *arg
, route_map_event_t type
,
125 char *errmsg
, size_t errmsg_len
))
127 rmap_match_set_hook
.no_match_ip_address
= func
;
130 /* match ip address prefix list */
131 void route_map_match_ip_address_prefix_list_hook(int (*func
)(
132 struct route_map_index
*index
, const char *command
,
133 const char *arg
, route_map_event_t type
,
134 char *errmsg
, size_t errmsg_len
))
136 rmap_match_set_hook
.match_ip_address_prefix_list
= func
;
139 /* no match ip address prefix list */
140 void route_map_no_match_ip_address_prefix_list_hook(int (*func
)(
141 struct route_map_index
*index
, const char *command
,
142 const char *arg
, route_map_event_t type
,
143 char *errmsg
, size_t errmsg_len
))
145 rmap_match_set_hook
.no_match_ip_address_prefix_list
= func
;
148 /* match ip next hop */
149 void route_map_match_ip_next_hop_hook(int (*func
)(
150 struct route_map_index
*index
, const char *command
,
151 const char *arg
, route_map_event_t type
,
152 char *errmsg
, size_t errmsg_len
))
154 rmap_match_set_hook
.match_ip_next_hop
= func
;
157 /* no match ip next hop */
158 void route_map_no_match_ip_next_hop_hook(int (*func
)(
159 struct route_map_index
*index
, const char *command
,
160 const char *arg
, route_map_event_t type
,
161 char *errmsg
, size_t errmsg_len
))
163 rmap_match_set_hook
.no_match_ip_next_hop
= func
;
166 /* match ipv6 next-hop */
167 void route_map_match_ipv6_next_hop_hook(int (*func
)(
168 struct route_map_index
*index
, const char *command
, const char *arg
,
169 route_map_event_t type
, char *errmsg
, size_t errmsg_len
))
171 rmap_match_set_hook
.match_ipv6_next_hop
= func
;
174 /* no match ipv6 next-hop */
175 void route_map_no_match_ipv6_next_hop_hook(int (*func
)(
176 struct route_map_index
*index
, const char *command
, const char *arg
,
177 route_map_event_t type
, char *errmsg
, size_t errmsg_len
))
179 rmap_match_set_hook
.no_match_ipv6_next_hop
= func
;
182 /* match ip next hop prefix list */
183 void route_map_match_ip_next_hop_prefix_list_hook(int (*func
)(
184 struct route_map_index
*index
, const char *command
,
185 const char *arg
, route_map_event_t type
,
186 char *errmsg
, size_t errmsg_len
))
188 rmap_match_set_hook
.match_ip_next_hop_prefix_list
= func
;
191 /* no match ip next hop prefix list */
192 void route_map_no_match_ip_next_hop_prefix_list_hook(int (*func
)(
193 struct route_map_index
*index
, const char *command
,
194 const char *arg
, route_map_event_t type
,
195 char *errmsg
, size_t errmsg_len
))
197 rmap_match_set_hook
.no_match_ip_next_hop_prefix_list
= func
;
200 /* match ip next-hop type */
201 void route_map_match_ip_next_hop_type_hook(int (*func
)(
202 struct route_map_index
*index
, const char *command
,
203 const char *arg
, route_map_event_t type
,
204 char *errmsg
, size_t errmsg_len
))
206 rmap_match_set_hook
.match_ip_next_hop_type
= func
;
209 /* no match ip next-hop type */
210 void route_map_no_match_ip_next_hop_type_hook(int (*func
)(
211 struct route_map_index
*index
, const char *command
,
212 const char *arg
, route_map_event_t type
,
213 char *errmsg
, size_t errmsg_len
))
215 rmap_match_set_hook
.no_match_ip_next_hop_type
= func
;
218 /* match ipv6 address */
219 void route_map_match_ipv6_address_hook(int (*func
)(
220 struct route_map_index
*index
, const char *command
,
221 const char *arg
, route_map_event_t type
,
222 char *errmsg
, size_t errmsg_len
))
224 rmap_match_set_hook
.match_ipv6_address
= func
;
227 /* no match ipv6 address */
228 void route_map_no_match_ipv6_address_hook(int (*func
)(
229 struct route_map_index
*index
, const char *command
,
230 const char *arg
, route_map_event_t type
,
231 char *errmsg
, size_t errmsg_len
))
233 rmap_match_set_hook
.no_match_ipv6_address
= func
;
237 /* match ipv6 address prefix list */
238 void route_map_match_ipv6_address_prefix_list_hook(int (*func
)(
239 struct route_map_index
*index
, const char *command
,
240 const char *arg
, route_map_event_t type
,
241 char *errmsg
, size_t errmsg_len
))
243 rmap_match_set_hook
.match_ipv6_address_prefix_list
= func
;
246 /* no match ipv6 address prefix list */
247 void route_map_no_match_ipv6_address_prefix_list_hook(int (*func
)(
248 struct route_map_index
*index
, const char *command
,
249 const char *arg
, route_map_event_t type
,
250 char *errmsg
, size_t errmsg_len
))
252 rmap_match_set_hook
.no_match_ipv6_address_prefix_list
= func
;
255 /* match ipv6 next-hop type */
256 void route_map_match_ipv6_next_hop_type_hook(int (*func
)(
257 struct route_map_index
*index
, const char *command
,
258 const char *arg
, route_map_event_t type
,
259 char *errmsg
, size_t errmsg_len
))
261 rmap_match_set_hook
.match_ipv6_next_hop_type
= func
;
264 /* no match ipv6 next-hop type */
265 void route_map_no_match_ipv6_next_hop_type_hook(int (*func
)(
266 struct route_map_index
*index
, const char *command
,
267 const char *arg
, route_map_event_t type
,
268 char *errmsg
, size_t errmsg_len
))
270 rmap_match_set_hook
.no_match_ipv6_next_hop_type
= func
;
273 /* match ipv6 next-hop prefix-list */
274 void route_map_match_ipv6_next_hop_prefix_list_hook(int (*func
)(
275 struct route_map_index
*index
, const char *command
, const char *arg
,
276 route_map_event_t type
, char *errmsg
, size_t errmsg_len
))
278 rmap_match_set_hook
.match_ipv6_next_hop_prefix_list
= func
;
281 /* no match ipv6 next-hop prefix-list */
282 void route_map_no_match_ipv6_next_hop_prefix_list_hook(int (*func
)(
283 struct route_map_index
*index
, const char *command
, const char *arg
,
284 route_map_event_t type
, char *errmsg
, size_t errmsg_len
))
286 rmap_match_set_hook
.no_match_ipv6_next_hop_prefix_list
= func
;
290 void route_map_match_metric_hook(int (*func
)(
291 struct route_map_index
*index
, const char *command
,
292 const char *arg
, route_map_event_t type
,
293 char *errmsg
, size_t errmsg_len
))
295 rmap_match_set_hook
.match_metric
= func
;
298 /* no match metric */
299 void route_map_no_match_metric_hook(int (*func
)(
300 struct route_map_index
*index
, const char *command
,
301 const char *arg
, route_map_event_t type
,
302 char *errmsg
, size_t errmsg_len
))
304 rmap_match_set_hook
.no_match_metric
= func
;
308 void route_map_match_tag_hook(int (*func
)(struct route_map_index
*index
,
309 const char *command
, const char *arg
,
310 route_map_event_t type
,
311 char *errmsg
, size_t errmsg_len
))
313 rmap_match_set_hook
.match_tag
= func
;
317 void route_map_no_match_tag_hook(int (*func
)(
318 struct route_map_index
*index
, const char *command
,
319 const char *arg
, route_map_event_t type
,
320 char *errmsg
, size_t errmsg_len
))
322 rmap_match_set_hook
.no_match_tag
= func
;
325 /* set sr-te color */
326 void route_map_set_srte_color_hook(int (*func
)(struct route_map_index
*index
,
329 char *errmsg
, size_t errmsg_len
))
331 rmap_match_set_hook
.set_srte_color
= func
;
334 /* no set sr-te color */
335 void route_map_no_set_srte_color_hook(int (*func
)(struct route_map_index
*index
,
338 char *errmsg
, size_t errmsg_len
))
340 rmap_match_set_hook
.no_set_srte_color
= func
;
344 void route_map_set_ip_nexthop_hook(int (*func
)(struct route_map_index
*index
,
347 char *errmsg
, size_t errmsg_len
))
349 rmap_match_set_hook
.set_ip_nexthop
= func
;
352 /* no set ip nexthop */
353 void route_map_no_set_ip_nexthop_hook(int (*func
)(struct route_map_index
*index
,
359 rmap_match_set_hook
.no_set_ip_nexthop
= func
;
362 /* set ipv6 nexthop local */
363 void route_map_set_ipv6_nexthop_local_hook(
364 int (*func
)(struct route_map_index
*index
,
365 const char *command
, const char *arg
,
366 char *errmsg
, size_t errmsg_len
))
368 rmap_match_set_hook
.set_ipv6_nexthop_local
= func
;
371 /* no set ipv6 nexthop local */
372 void route_map_no_set_ipv6_nexthop_local_hook(
373 int (*func
)(struct route_map_index
*index
,
374 const char *command
, const char *arg
,
375 char *errmsg
, size_t errmsg_len
))
377 rmap_match_set_hook
.no_set_ipv6_nexthop_local
= func
;
381 void route_map_set_metric_hook(int (*func
)(struct route_map_index
*index
,
384 char *errmsg
, size_t errmsg_len
))
386 rmap_match_set_hook
.set_metric
= func
;
390 void route_map_no_set_metric_hook(int (*func
)(struct route_map_index
*index
,
393 char *errmsg
, size_t errmsg_len
))
395 rmap_match_set_hook
.no_set_metric
= func
;
399 void route_map_set_tag_hook(int (*func
)(struct route_map_index
*index
,
400 const char *command
, const char *arg
,
401 char *errmsg
, size_t errmsg_len
))
403 rmap_match_set_hook
.set_tag
= func
;
407 void route_map_no_set_tag_hook(int (*func
)(struct route_map_index
*index
,
410 char *errmsg
, size_t errmsg_len
))
412 rmap_match_set_hook
.no_set_tag
= func
;
415 int generic_match_add(struct route_map_index
*index
,
416 const char *command
, const char *arg
,
417 route_map_event_t type
,
418 char *errmsg
, size_t errmsg_len
)
420 enum rmap_compile_rets ret
;
422 ret
= route_map_add_match(index
, command
, arg
, type
);
424 case RMAP_RULE_MISSING
:
425 snprintf(errmsg
, errmsg_len
, "%% [%s] Can't find rule.",
427 return CMD_WARNING_CONFIG_FAILED
;
428 case RMAP_COMPILE_ERROR
:
429 snprintf(errmsg
, errmsg_len
,
430 "%% [%s] Argument form is unsupported or malformed.",
432 return CMD_WARNING_CONFIG_FAILED
;
433 case RMAP_COMPILE_SUCCESS
:
435 * Nothing to do here move along
443 int generic_match_delete(struct route_map_index
*index
,
444 const char *command
, const char *arg
,
445 route_map_event_t type
,
446 char *errmsg
, size_t errmsg_len
)
448 enum rmap_compile_rets ret
;
449 int retval
= CMD_SUCCESS
;
450 char *dep_name
= NULL
;
452 char *rmap_name
= NULL
;
454 if (type
!= RMAP_EVENT_MATCH_DELETED
) {
455 /* ignore the mundane, the types without any dependency */
457 if ((tmpstr
= route_map_get_match_arg(index
, command
))
460 XSTRDUP(MTYPE_ROUTE_MAP_RULE
, tmpstr
);
462 dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_RULE
, arg
);
464 rmap_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, index
->map
->name
);
467 ret
= route_map_delete_match(index
, command
, dep_name
, type
);
469 case RMAP_RULE_MISSING
:
470 snprintf(errmsg
, errmsg_len
, "%% [%s] Can't find rule.",
472 retval
= CMD_WARNING_CONFIG_FAILED
;
474 case RMAP_COMPILE_ERROR
:
475 snprintf(errmsg
, errmsg_len
,
476 "%% [%s] Argument form is unsupported or malformed.",
478 retval
= CMD_WARNING_CONFIG_FAILED
;
480 case RMAP_COMPILE_SUCCESS
:
487 XFREE(MTYPE_ROUTE_MAP_RULE
, dep_name
);
488 XFREE(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
493 int generic_set_add(struct route_map_index
*index
,
494 const char *command
, const char *arg
,
495 char *errmsg
, size_t errmsg_len
)
497 enum rmap_compile_rets ret
;
499 ret
= route_map_add_set(index
, command
, arg
);
501 case RMAP_RULE_MISSING
:
502 snprintf(errmsg
, errmsg_len
,
503 "%% [%s] Can't find rule.", frr_protonameinst
);
504 return CMD_WARNING_CONFIG_FAILED
;
505 case RMAP_COMPILE_ERROR
:
506 snprintf(errmsg
, errmsg_len
,
507 "%% [%s] Argument form is unsupported or malformed.",
509 return CMD_WARNING_CONFIG_FAILED
;
510 case RMAP_COMPILE_SUCCESS
:
517 int generic_set_delete(struct route_map_index
*index
,
518 const char *command
, const char *arg
,
519 char *errmsg
, size_t errmsg_len
)
521 enum rmap_compile_rets ret
;
523 ret
= route_map_delete_set(index
, command
, arg
);
525 case RMAP_RULE_MISSING
:
526 snprintf(errmsg
, errmsg_len
, "%% [%s] Can't find rule.",
528 return CMD_WARNING_CONFIG_FAILED
;
529 case RMAP_COMPILE_ERROR
:
530 snprintf(errmsg
, errmsg_len
,
531 "%% [%s] Argument form is unsupported or malformed.",
533 return CMD_WARNING_CONFIG_FAILED
;
534 case RMAP_COMPILE_SUCCESS
:
542 /* Master list of route map. */
543 struct route_map_list route_map_master
= {NULL
, NULL
, NULL
, NULL
, NULL
};
544 struct hash
*route_map_master_hash
= NULL
;
546 static unsigned int route_map_hash_key_make(const void *p
)
548 const struct route_map
*map
= p
;
549 return string_hash_make(map
->name
);
552 static bool route_map_hash_cmp(const void *p1
, const void *p2
)
554 const struct route_map
*map1
= p1
;
555 const struct route_map
*map2
= p2
;
557 if (!strcmp(map1
->name
, map2
->name
))
563 enum route_map_upd8_type
{
568 /* all possible route-map dependency types */
569 enum route_map_dep_type
{
570 ROUTE_MAP_DEP_RMAP
= 1,
572 ROUTE_MAP_DEP_ECLIST
,
573 ROUTE_MAP_DEP_LCLIST
,
575 ROUTE_MAP_DEP_ASPATH
,
576 ROUTE_MAP_DEP_FILTER
,
580 struct route_map_dep
{
582 struct hash
*dep_rmap_hash
;
583 struct hash
*this_hash
; /* ptr to the hash structure this is part of */
586 struct route_map_dep_data
{
590 /* Count of number of sequences of this
591 * route-map that depend on the same entity.
596 /* Hashes maintaining dependency between various sublists used by route maps */
597 static struct hash
*route_map_dep_hash
[ROUTE_MAP_DEP_MAX
];
599 static unsigned int route_map_dep_hash_make_key(const void *p
);
600 static void route_map_clear_all_references(char *rmap_name
);
601 static void route_map_rule_delete(struct route_map_rule_list
*,
602 struct route_map_rule
*);
606 /* New route map allocation. Please note route map's name must be
608 static struct route_map
*route_map_new(const char *name
)
610 struct route_map
*new;
612 new = XCALLOC(MTYPE_ROUTE_MAP
, sizeof(struct route_map
));
613 new->name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
614 QOBJ_REG(new, route_map
);
618 /* Add new name to route_map. */
619 static struct route_map
*route_map_add(const char *name
)
621 struct route_map
*map
, *exist
;
622 struct route_map_list
*list
;
624 map
= route_map_new(name
);
625 list
= &route_map_master
;
628 * Add map to the hash
630 * If the map already exists in the hash, then we know that
631 * FRR is now in a sequence of delete/create.
632 * All FRR needs to do here is set the to_be_processed
633 * bit (to inherit from the old one
635 exist
= hash_release(route_map_master_hash
, map
);
637 map
->to_be_processed
= exist
->to_be_processed
;
638 route_map_free_map(exist
);
640 hash_get(route_map_master_hash
, map
, hash_alloc_intern
);
642 /* Add new entry to the head of the list to match how it is added in the
643 * hash table. This is to ensure that if the same route-map has been
644 * created more than once and then marked for deletion (which can happen
645 * if prior deletions haven't completed as BGP hasn't yet done the
646 * route-map processing), the order of the entities is the same in both
647 * the list and the hash table. Otherwise, since there is nothing to
648 * distinguish between the two entries, the wrong entry could get freed.
649 * TODO: This needs to be re-examined to handle it better - e.g., revive
650 * a deleted entry if the route-map is created again.
653 map
->next
= list
->head
;
655 list
->head
->prev
= map
;
661 if (route_map_master
.add_hook
) {
662 (*route_map_master
.add_hook
)(name
);
663 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_ADDED
);
666 if (!map
->ipv4_prefix_table
)
667 map
->ipv4_prefix_table
= route_table_init();
669 if (!map
->ipv6_prefix_table
)
670 map
->ipv6_prefix_table
= route_table_init();
672 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
673 zlog_debug("Add route-map %s", name
);
677 /* this is supposed to be called post processing by
678 * the delete hook function. Don't invoke delete_hook
679 * again in this routine.
681 static void route_map_free_map(struct route_map
*map
)
683 struct route_map_list
*list
;
684 struct route_map_index
*index
;
689 while ((index
= map
->head
) != NULL
)
690 route_map_index_delete(index
, 0);
692 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
693 zlog_debug("Deleting route-map %s", map
->name
);
695 list
= &route_map_master
;
700 map
->next
->prev
= map
->prev
;
702 list
->tail
= map
->prev
;
705 map
->prev
->next
= map
->next
;
707 list
->head
= map
->next
;
709 hash_release(route_map_master_hash
, map
);
710 XFREE(MTYPE_ROUTE_MAP_NAME
, map
->name
);
711 XFREE(MTYPE_ROUTE_MAP
, map
);
714 /* Route map delete from list. */
715 void route_map_delete(struct route_map
*map
)
717 struct route_map_index
*index
;
720 while ((index
= map
->head
) != NULL
)
721 route_map_index_delete(index
, 0);
726 /* Clear all dependencies */
727 route_map_clear_all_references(name
);
729 /* Execute deletion hook. */
730 if (route_map_master
.delete_hook
) {
731 (*route_map_master
.delete_hook
)(name
);
732 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_DELETED
);
735 if (!map
->to_be_processed
) {
736 route_map_free_map(map
);
740 /* Lookup route map by route map name string. */
741 struct route_map
*route_map_lookup_by_name(const char *name
)
743 struct route_map
*map
;
744 struct route_map tmp_map
;
749 // map.deleted is false via memset
750 memset(&tmp_map
, 0, sizeof(tmp_map
));
751 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
752 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
753 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
755 if (map
&& map
->deleted
)
761 /* Simple helper to warn if route-map does not exist. */
762 struct route_map
*route_map_lookup_warn_noexist(struct vty
*vty
, const char *name
)
764 struct route_map
*route_map
= route_map_lookup_by_name(name
);
767 if (vty_shell_serv(vty
))
768 vty_out(vty
, "The route-map '%s' does not exist.\n", name
);
773 int route_map_mark_updated(const char *name
)
775 struct route_map
*map
;
777 struct route_map tmp_map
;
782 map
= route_map_lookup_by_name(name
);
784 /* If we did not find the routemap with deleted=false try again
788 memset(&tmp_map
, 0, sizeof(tmp_map
));
789 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
790 tmp_map
.deleted
= true;
791 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
792 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
796 map
->to_be_processed
= true;
803 static void route_map_clear_updated(struct route_map
*map
)
806 map
->to_be_processed
= false;
808 route_map_free_map(map
);
812 /* Lookup route map. If there isn't route map create one and return
814 struct route_map
*route_map_get(const char *name
)
816 struct route_map
*map
;
818 map
= route_map_lookup_by_name(name
);
820 map
= route_map_add(name
);
825 void route_map_walk_update_list(void (*route_map_update_fn
)(char *name
))
827 struct route_map
*node
;
828 struct route_map
*nnode
= NULL
;
830 for (node
= route_map_master
.head
; node
; node
= nnode
) {
831 if (node
->to_be_processed
) {
832 /* DD: Should we add any thread yield code here */
833 route_map_update_fn(node
->name
);
835 route_map_clear_updated(node
);
841 /* Return route map's type string. */
842 static const char *route_map_type_str(enum route_map_type type
)
856 static const char *route_map_cmd_result_str(enum route_map_cmd_result_t res
)
874 static const char *route_map_result_str(route_map_result_t res
)
879 case RMAP_PERMITMATCH
:
887 static void vty_show_route_map_entry(struct vty
*vty
, struct route_map
*map
,
890 struct route_map_index
*index
;
891 struct route_map_rule
*rule
;
892 json_object
*json_rmap
= NULL
;
893 json_object
*json_rules
= NULL
;
896 json_rmap
= json_object_new_object();
897 json_object_object_add(json
, map
->name
, json_rmap
);
899 json_rules
= json_object_new_array();
900 json_object_int_add(json_rmap
, "invoked",
901 map
->applied
- map
->applied_clear
);
902 json_object_boolean_add(json_rmap
, "disabledOptimization",
903 map
->optimization_disabled
);
904 json_object_boolean_add(json_rmap
, "processedChange",
905 map
->to_be_processed
);
906 json_object_object_add(json_rmap
, "rules", json_rules
);
909 "route-map: %s Invoked: %" PRIu64
910 " Optimization: %s Processed Change: %s\n",
911 map
->name
, map
->applied
- map
->applied_clear
,
912 map
->optimization_disabled
? "disabled" : "enabled",
913 map
->to_be_processed
? "true" : "false");
916 for (index
= map
->head
; index
; index
= index
->next
) {
918 json_object
*json_rule
;
919 json_object
*json_matches
;
920 json_object
*json_sets
;
921 char action
[BUFSIZ
] = {};
923 json_rule
= json_object_new_object();
924 json_object_array_add(json_rules
, json_rule
);
926 json_object_int_add(json_rule
, "sequenceNumber",
928 json_object_string_add(json_rule
, "type",
929 route_map_type_str(index
->type
));
930 json_object_int_add(json_rule
, "invoked",
932 - index
->applied_clear
);
935 if (index
->description
)
936 json_object_string_add(json_rule
, "description",
940 json_matches
= json_object_new_array();
941 json_object_object_add(json_rule
, "matchClauses",
943 for (rule
= index
->match_list
.head
; rule
;
947 snprintf(buf
, sizeof(buf
), "%s %s",
948 rule
->cmd
->str
, rule
->rule_str
);
949 json_array_string_add(json_matches
, buf
);
953 json_sets
= json_object_new_array();
954 json_object_object_add(json_rule
, "setClauses",
956 for (rule
= index
->set_list
.head
; rule
;
960 snprintf(buf
, sizeof(buf
), "%s %s",
961 rule
->cmd
->str
, rule
->rule_str
);
962 json_array_string_add(json_sets
, buf
);
967 json_object_string_add(json_rule
, "callClause",
971 if (index
->exitpolicy
== RMAP_GOTO
)
972 snprintf(action
, sizeof(action
), "Goto %d",
974 else if (index
->exitpolicy
== RMAP_NEXT
)
975 snprintf(action
, sizeof(action
),
976 "Continue to next entry");
977 else if (index
->exitpolicy
== RMAP_EXIT
)
978 snprintf(action
, sizeof(action
),
980 if (action
[0] != '\0')
981 json_object_string_add(json_rule
, "action",
984 vty_out(vty
, " %s, sequence %d Invoked %" PRIu64
"\n",
985 route_map_type_str(index
->type
), index
->pref
,
986 index
->applied
- index
->applied_clear
);
989 if (index
->description
)
990 vty_out(vty
, " Description:\n %s\n",
994 vty_out(vty
, " Match clauses:\n");
995 for (rule
= index
->match_list
.head
; rule
;
997 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
1001 vty_out(vty
, " Set clauses:\n");
1002 for (rule
= index
->set_list
.head
; rule
;
1004 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
1008 vty_out(vty
, " Call clause:\n");
1010 vty_out(vty
, " Call %s\n", index
->nextrm
);
1013 vty_out(vty
, " Action:\n");
1014 if (index
->exitpolicy
== RMAP_GOTO
)
1015 vty_out(vty
, " Goto %d\n", index
->nextpref
);
1016 else if (index
->exitpolicy
== RMAP_NEXT
)
1017 vty_out(vty
, " Continue to next entry\n");
1018 else if (index
->exitpolicy
== RMAP_EXIT
)
1019 vty_out(vty
, " Exit routemap\n");
1024 static int sort_route_map(const void **map1
, const void **map2
)
1026 const struct route_map
*m1
= *map1
;
1027 const struct route_map
*m2
= *map2
;
1029 return strcmp(m1
->name
, m2
->name
);
1032 static int vty_show_route_map(struct vty
*vty
, const char *name
, bool use_json
)
1034 struct route_map
*map
;
1035 json_object
*json
= NULL
;
1036 json_object
*json_proto
= NULL
;
1039 json
= json_object_new_object();
1040 json_proto
= json_object_new_object();
1041 json_object_object_add(json
, frr_protonameinst
, json_proto
);
1043 vty_out(vty
, "%s:\n", frr_protonameinst
);
1046 map
= route_map_lookup_by_name(name
);
1049 vty_show_route_map_entry(vty
, map
, json_proto
);
1050 } else if (!use_json
) {
1051 vty_out(vty
, "%s: 'route-map %s' not found\n",
1052 frr_protonameinst
, name
);
1056 struct list
*maplist
= list_new();
1057 struct listnode
*ln
;
1059 for (map
= route_map_master
.head
; map
; map
= map
->next
)
1060 listnode_add(maplist
, map
);
1062 list_sort(maplist
, sort_route_map
);
1064 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
1065 vty_show_route_map_entry(vty
, map
, json_proto
);
1067 list_delete(&maplist
);
1070 return vty_json(vty
, json
);
1073 /* Unused route map details */
1074 static int vty_show_unused_route_map(struct vty
*vty
)
1076 struct list
*maplist
= list_new();
1077 struct listnode
*ln
;
1078 struct route_map
*map
;
1080 for (map
= route_map_master
.head
; map
; map
= map
->next
) {
1081 /* If use_count is zero, No protocol is using this routemap.
1082 * so adding to the list.
1084 if (!map
->use_count
)
1085 listnode_add(maplist
, map
);
1088 if (maplist
->count
> 0) {
1089 vty_out(vty
, "\n%s:\n", frr_protonameinst
);
1090 list_sort(maplist
, sort_route_map
);
1092 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
1093 vty_show_route_map_entry(vty
, map
, NULL
);
1095 vty_out(vty
, "\n%s: None\n", frr_protonameinst
);
1098 list_delete(&maplist
);
1102 /* New route map allocation. Please note route map's name must be
1104 static struct route_map_index
*route_map_index_new(void)
1106 struct route_map_index
*new;
1108 new = XCALLOC(MTYPE_ROUTE_MAP_INDEX
, sizeof(struct route_map_index
));
1109 new->exitpolicy
= RMAP_EXIT
; /* Default to Cisco-style */
1110 TAILQ_INIT(&new->rhclist
);
1111 QOBJ_REG(new, route_map_index
);
1115 /* Free route map index. */
1116 void route_map_index_delete(struct route_map_index
*index
, int notify
)
1118 struct routemap_hook_context
*rhc
;
1119 struct route_map_rule
*rule
;
1123 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
1124 zlog_debug("Deleting route-map %s sequence %d",
1125 index
->map
->name
, index
->pref
);
1127 /* Free route map entry description. */
1128 XFREE(MTYPE_TMP
, index
->description
);
1130 /* Free route map northbound hook contexts. */
1131 while ((rhc
= TAILQ_FIRST(&index
->rhclist
)) != NULL
)
1132 routemap_hook_context_free(rhc
);
1134 /* Free route match. */
1135 while ((rule
= index
->match_list
.head
) != NULL
) {
1136 if (IS_RULE_IPv4_PREFIX_LIST(rule
->cmd
->str
))
1137 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_DELETED
,
1138 index
, AFI_IP
, rule
->rule_str
);
1139 else if (IS_RULE_IPv6_PREFIX_LIST(rule
->cmd
->str
))
1140 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_DELETED
,
1144 route_map_rule_delete(&index
->match_list
, rule
);
1147 /* Free route set. */
1148 while ((rule
= index
->set_list
.head
) != NULL
)
1149 route_map_rule_delete(&index
->set_list
, rule
);
1151 /* Remove index from route map list. */
1153 index
->next
->prev
= index
->prev
;
1155 index
->map
->tail
= index
->prev
;
1158 index
->prev
->next
= index
->next
;
1160 index
->map
->head
= index
->next
;
1162 /* Free 'char *nextrm' if not NULL */
1163 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
1165 route_map_pfx_tbl_update(RMAP_EVENT_INDEX_DELETED
, index
, 0, NULL
);
1167 /* Execute event hook. */
1168 if (route_map_master
.event_hook
&& notify
) {
1169 (*route_map_master
.event_hook
)(index
->map
->name
);
1170 route_map_notify_dependencies(index
->map
->name
,
1171 RMAP_EVENT_CALL_ADDED
);
1173 XFREE(MTYPE_ROUTE_MAP_INDEX
, index
);
1176 /* Lookup index from route map. */
1177 static struct route_map_index
*route_map_index_lookup(struct route_map
*map
,
1178 enum route_map_type type
,
1181 struct route_map_index
*index
;
1183 for (index
= map
->head
; index
; index
= index
->next
)
1184 if ((index
->type
== type
|| type
== RMAP_ANY
)
1185 && index
->pref
== pref
)
1190 /* Add new index to route map. */
1191 static struct route_map_index
*
1192 route_map_index_add(struct route_map
*map
, enum route_map_type type
, int pref
)
1194 struct route_map_index
*index
;
1195 struct route_map_index
*point
;
1197 /* Allocate new route map inex. */
1198 index
= route_map_index_new();
1203 /* Compare preference. */
1204 for (point
= map
->head
; point
; point
= point
->next
)
1205 if (point
->pref
>= pref
)
1208 if (map
->head
== NULL
) {
1209 map
->head
= map
->tail
= index
;
1210 } else if (point
== NULL
) {
1211 index
->prev
= map
->tail
;
1212 map
->tail
->next
= index
;
1214 } else if (point
== map
->head
) {
1215 index
->next
= map
->head
;
1216 map
->head
->prev
= index
;
1219 index
->next
= point
;
1220 index
->prev
= point
->prev
;
1222 point
->prev
->next
= index
;
1223 point
->prev
= index
;
1226 route_map_pfx_tbl_update(RMAP_EVENT_INDEX_ADDED
, index
, 0, NULL
);
1228 /* Execute event hook. */
1229 if (route_map_master
.event_hook
) {
1230 (*route_map_master
.event_hook
)(map
->name
);
1231 route_map_notify_dependencies(map
->name
, RMAP_EVENT_CALL_ADDED
);
1234 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
1235 zlog_debug("Route-map %s add sequence %d, type: %s",
1236 map
->name
, pref
, route_map_type_str(type
));
1241 /* Get route map index. */
1242 struct route_map_index
*
1243 route_map_index_get(struct route_map
*map
, enum route_map_type type
, int pref
)
1245 struct route_map_index
*index
;
1247 index
= route_map_index_lookup(map
, RMAP_ANY
, pref
);
1248 if (index
&& index
->type
!= type
) {
1249 /* Delete index from route map. */
1250 route_map_index_delete(index
, 1);
1254 index
= route_map_index_add(map
, type
, pref
);
1258 /* New route map rule */
1259 static struct route_map_rule
*route_map_rule_new(void)
1261 struct route_map_rule
*new;
1263 new = XCALLOC(MTYPE_ROUTE_MAP_RULE
, sizeof(struct route_map_rule
));
1267 /* Install rule command to the match list. */
1268 void _route_map_install_match(struct route_map_rule_cmd_proxy
*proxy
)
1270 rmap_cmd_name_add(rmap_match_cmds
, proxy
);
1273 /* Install rule command to the set list. */
1274 void _route_map_install_set(struct route_map_rule_cmd_proxy
*proxy
)
1276 rmap_cmd_name_add(rmap_set_cmds
, proxy
);
1279 /* Lookup rule command from match list. */
1280 static const struct route_map_rule_cmd
*route_map_lookup_match(const char *name
)
1282 struct route_map_rule_cmd refcmd
= {.str
= name
};
1283 struct route_map_rule_cmd_proxy ref
= {.cmd
= &refcmd
};
1284 struct route_map_rule_cmd_proxy
*res
;
1286 res
= rmap_cmd_name_find(rmap_match_cmds
, &ref
);
1292 /* Lookup rule command from set list. */
1293 static const struct route_map_rule_cmd
*route_map_lookup_set(const char *name
)
1295 struct route_map_rule_cmd refcmd
= {.str
= name
};
1296 struct route_map_rule_cmd_proxy ref
= {.cmd
= &refcmd
};
1297 struct route_map_rule_cmd_proxy
*res
;
1299 res
= rmap_cmd_name_find(rmap_set_cmds
, &ref
);
1305 /* Add match and set rule to rule list. */
1306 static void route_map_rule_add(struct route_map_rule_list
*list
,
1307 struct route_map_rule
*rule
)
1310 rule
->prev
= list
->tail
;
1312 list
->tail
->next
= rule
;
1318 /* Delete rule from rule list. */
1319 static void route_map_rule_delete(struct route_map_rule_list
*list
,
1320 struct route_map_rule
*rule
)
1322 if (rule
->cmd
->func_free
)
1323 (*rule
->cmd
->func_free
)(rule
->value
);
1325 XFREE(MTYPE_ROUTE_MAP_RULE_STR
, rule
->rule_str
);
1328 rule
->next
->prev
= rule
->prev
;
1330 list
->tail
= rule
->prev
;
1332 rule
->prev
->next
= rule
->next
;
1334 list
->head
= rule
->next
;
1336 XFREE(MTYPE_ROUTE_MAP_RULE
, rule
);
1339 /* strcmp wrapper function which don't crush even argument is NULL. */
1340 static int rulecmp(const char *dst
, const char *src
)
1351 return strcmp(dst
, src
);
1356 /* Use this to return the already specified argument for this match. This is
1357 * useful to get the specified argument with a route map match rule when the
1358 * rule is being deleted and the argument is not provided.
1360 const char *route_map_get_match_arg(struct route_map_index
*index
,
1361 const char *match_name
)
1363 struct route_map_rule
*rule
;
1364 const struct route_map_rule_cmd
*cmd
;
1366 /* First lookup rule for add match statement. */
1367 cmd
= route_map_lookup_match(match_name
);
1371 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1372 if (rule
->cmd
== cmd
&& rule
->rule_str
!= NULL
)
1373 return (rule
->rule_str
);
1378 static route_map_event_t
get_route_map_delete_event(route_map_event_t type
)
1381 case RMAP_EVENT_CALL_ADDED
:
1382 return RMAP_EVENT_CALL_DELETED
;
1383 case RMAP_EVENT_PLIST_ADDED
:
1384 return RMAP_EVENT_PLIST_DELETED
;
1385 case RMAP_EVENT_CLIST_ADDED
:
1386 return RMAP_EVENT_CLIST_DELETED
;
1387 case RMAP_EVENT_ECLIST_ADDED
:
1388 return RMAP_EVENT_ECLIST_DELETED
;
1389 case RMAP_EVENT_LLIST_ADDED
:
1390 return RMAP_EVENT_LLIST_DELETED
;
1391 case RMAP_EVENT_ASLIST_ADDED
:
1392 return RMAP_EVENT_ASLIST_DELETED
;
1393 case RMAP_EVENT_FILTER_ADDED
:
1394 return RMAP_EVENT_FILTER_DELETED
;
1395 case RMAP_EVENT_SET_ADDED
:
1396 case RMAP_EVENT_SET_DELETED
:
1397 case RMAP_EVENT_SET_REPLACED
:
1398 case RMAP_EVENT_MATCH_ADDED
:
1399 case RMAP_EVENT_MATCH_DELETED
:
1400 case RMAP_EVENT_MATCH_REPLACED
:
1401 case RMAP_EVENT_INDEX_ADDED
:
1402 case RMAP_EVENT_INDEX_DELETED
:
1403 case RMAP_EVENT_CALL_DELETED
:
1404 case RMAP_EVENT_PLIST_DELETED
:
1405 case RMAP_EVENT_CLIST_DELETED
:
1406 case RMAP_EVENT_ECLIST_DELETED
:
1407 case RMAP_EVENT_LLIST_DELETED
:
1408 case RMAP_EVENT_ASLIST_DELETED
:
1409 case RMAP_EVENT_FILTER_DELETED
:
1410 /* This function returns the appropriate 'deleted' event type
1411 * for every 'added' event type passed to this function.
1412 * This is done only for named entities used in the
1413 * route-map match commands.
1414 * This function is not to be invoked for any of the other event
1422 * Return to make c happy but if we get here something has gone
1423 * terribly terribly wrong, so yes this return makes no sense.
1425 return RMAP_EVENT_CALL_ADDED
;
1428 /* Add match statement to route map. */
1429 enum rmap_compile_rets
route_map_add_match(struct route_map_index
*index
,
1430 const char *match_name
,
1431 const char *match_arg
,
1432 route_map_event_t type
)
1434 struct route_map_rule
*rule
;
1435 struct route_map_rule
*next
;
1436 const struct route_map_rule_cmd
*cmd
;
1438 int8_t delete_rmap_event_type
= 0;
1439 const char *rule_key
;
1441 /* First lookup rule for add match statement. */
1442 cmd
= route_map_lookup_match(match_name
);
1444 return RMAP_RULE_MISSING
;
1446 /* Next call compile function for this match statement. */
1447 if (cmd
->func_compile
) {
1448 compile
= (*cmd
->func_compile
)(match_arg
);
1449 if (compile
== NULL
)
1450 return RMAP_COMPILE_ERROR
;
1453 /* use the compiled results if applicable */
1454 if (compile
&& cmd
->func_get_rmap_rule_key
)
1455 rule_key
= (*cmd
->func_get_rmap_rule_key
)
1458 rule_key
= match_arg
;
1460 /* If argument is completely same ignore it. */
1461 for (rule
= index
->match_list
.head
; rule
; rule
= next
) {
1463 if (rule
->cmd
== cmd
) {
1464 /* If the configured route-map match rule is exactly
1465 * the same as the existing configuration then,
1466 * ignore the duplicate configuration.
1468 if (rulecmp(match_arg
, rule
->rule_str
) == 0) {
1470 (*cmd
->func_free
)(compile
);
1472 return RMAP_COMPILE_SUCCESS
;
1475 /* If IPv4 or IPv6 prefix-list match criteria
1476 * has been delete to the route-map index, update
1477 * the route-map's prefix table.
1479 if (IS_RULE_IPv4_PREFIX_LIST(match_name
))
1480 route_map_pfx_tbl_update(
1481 RMAP_EVENT_PLIST_DELETED
, index
, AFI_IP
,
1483 else if (IS_RULE_IPv6_PREFIX_LIST(match_name
))
1484 route_map_pfx_tbl_update(
1485 RMAP_EVENT_PLIST_DELETED
, index
,
1486 AFI_IP6
, rule
->rule_str
);
1488 /* Remove the dependency of the route-map on the rule
1489 * that is being replaced.
1491 if (type
>= RMAP_EVENT_CALL_ADDED
) {
1492 delete_rmap_event_type
=
1493 get_route_map_delete_event(type
);
1494 route_map_upd8_dependency(
1495 delete_rmap_event_type
,
1500 route_map_rule_delete(&index
->match_list
, rule
);
1504 /* Add new route map match rule. */
1505 rule
= route_map_rule_new();
1507 rule
->value
= compile
;
1509 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, match_arg
);
1511 rule
->rule_str
= NULL
;
1513 /* Add new route match rule to linked list. */
1514 route_map_rule_add(&index
->match_list
, rule
);
1516 /* If IPv4 or IPv6 prefix-list match criteria
1517 * has been added to the route-map index, update
1518 * the route-map's prefix table.
1520 if (IS_RULE_IPv4_PREFIX_LIST(match_name
)) {
1521 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_ADDED
, index
, AFI_IP
,
1523 } else if (IS_RULE_IPv6_PREFIX_LIST(match_name
)) {
1524 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_ADDED
, index
, AFI_IP6
,
1528 /* Execute event hook. */
1529 if (route_map_master
.event_hook
) {
1530 (*route_map_master
.event_hook
)(index
->map
->name
);
1531 route_map_notify_dependencies(index
->map
->name
,
1532 RMAP_EVENT_CALL_ADDED
);
1534 if (type
!= RMAP_EVENT_MATCH_ADDED
)
1535 route_map_upd8_dependency(type
, rule_key
, index
->map
->name
);
1537 return RMAP_COMPILE_SUCCESS
;
1540 /* Delete specified route match rule. */
1541 enum rmap_compile_rets
route_map_delete_match(struct route_map_index
*index
,
1542 const char *match_name
,
1543 const char *match_arg
,
1544 route_map_event_t type
)
1546 struct route_map_rule
*rule
;
1547 const struct route_map_rule_cmd
*cmd
;
1548 const char *rule_key
;
1550 cmd
= route_map_lookup_match(match_name
);
1552 return RMAP_RULE_MISSING
;
1554 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1555 if (rule
->cmd
== cmd
&& (rulecmp(rule
->rule_str
, match_arg
) == 0
1556 || match_arg
== NULL
)) {
1557 /* Execute event hook. */
1558 if (route_map_master
.event_hook
) {
1559 (*route_map_master
.event_hook
)(index
->map
->name
);
1560 route_map_notify_dependencies(
1562 RMAP_EVENT_CALL_ADDED
);
1564 if (cmd
->func_get_rmap_rule_key
)
1565 rule_key
= (*cmd
->func_get_rmap_rule_key
)
1568 rule_key
= match_arg
;
1570 if (type
!= RMAP_EVENT_MATCH_DELETED
&& rule_key
)
1571 route_map_upd8_dependency(type
, rule_key
,
1574 route_map_rule_delete(&index
->match_list
, rule
);
1576 /* If IPv4 or IPv6 prefix-list match criteria
1577 * has been delete from the route-map index, update
1578 * the route-map's prefix table.
1580 if (IS_RULE_IPv4_PREFIX_LIST(match_name
)) {
1581 route_map_pfx_tbl_update(
1582 RMAP_EVENT_PLIST_DELETED
, index
, AFI_IP
,
1584 } else if (IS_RULE_IPv6_PREFIX_LIST(match_name
)) {
1585 route_map_pfx_tbl_update(
1586 RMAP_EVENT_PLIST_DELETED
, index
,
1587 AFI_IP6
, match_arg
);
1590 return RMAP_COMPILE_SUCCESS
;
1592 /* Can't find matched rule. */
1593 return RMAP_RULE_MISSING
;
1596 /* Add route-map set statement to the route map. */
1597 enum rmap_compile_rets
route_map_add_set(struct route_map_index
*index
,
1598 const char *set_name
,
1599 const char *set_arg
)
1601 struct route_map_rule
*rule
;
1602 struct route_map_rule
*next
;
1603 const struct route_map_rule_cmd
*cmd
;
1606 cmd
= route_map_lookup_set(set_name
);
1608 return RMAP_RULE_MISSING
;
1610 /* Next call compile function for this match statement. */
1611 if (cmd
->func_compile
) {
1612 compile
= (*cmd
->func_compile
)(set_arg
);
1613 if (compile
== NULL
)
1614 return RMAP_COMPILE_ERROR
;
1618 /* Add by WJL. if old set command of same kind exist, delete it first
1619 to ensure only one set command of same kind exist under a
1621 for (rule
= index
->set_list
.head
; rule
; rule
= next
) {
1623 if (rule
->cmd
== cmd
)
1624 route_map_rule_delete(&index
->set_list
, rule
);
1627 /* Add new route map match rule. */
1628 rule
= route_map_rule_new();
1630 rule
->value
= compile
;
1632 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, set_arg
);
1634 rule
->rule_str
= NULL
;
1636 /* Add new route match rule to linked list. */
1637 route_map_rule_add(&index
->set_list
, rule
);
1639 /* Execute event hook. */
1640 if (route_map_master
.event_hook
) {
1641 (*route_map_master
.event_hook
)(index
->map
->name
);
1642 route_map_notify_dependencies(index
->map
->name
,
1643 RMAP_EVENT_CALL_ADDED
);
1645 return RMAP_COMPILE_SUCCESS
;
1648 /* Delete route map set rule. */
1649 enum rmap_compile_rets
route_map_delete_set(struct route_map_index
*index
,
1650 const char *set_name
,
1651 const char *set_arg
)
1653 struct route_map_rule
*rule
;
1654 const struct route_map_rule_cmd
*cmd
;
1656 cmd
= route_map_lookup_set(set_name
);
1658 return RMAP_RULE_MISSING
;
1660 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
1661 if ((rule
->cmd
== cmd
) && (rulecmp(rule
->rule_str
, set_arg
) == 0
1662 || set_arg
== NULL
)) {
1663 route_map_rule_delete(&index
->set_list
, rule
);
1664 /* Execute event hook. */
1665 if (route_map_master
.event_hook
) {
1666 (*route_map_master
.event_hook
)(index
->map
->name
);
1667 route_map_notify_dependencies(
1669 RMAP_EVENT_CALL_ADDED
);
1671 return RMAP_COMPILE_SUCCESS
;
1673 /* Can't find matched rule. */
1674 return RMAP_RULE_MISSING
;
1677 static enum route_map_cmd_result_t
1678 route_map_apply_match(struct route_map_rule_list
*match_list
,
1679 const struct prefix
*prefix
, void *object
)
1681 enum route_map_cmd_result_t ret
= RMAP_NOMATCH
;
1682 struct route_map_rule
*match
;
1683 bool is_matched
= false;
1686 /* Check all match rule and if there is no match rule, go to the
1688 if (!match_list
->head
)
1691 for (match
= match_list
->head
; match
; match
= match
->next
) {
1693 * Try each match statement. If any match does not
1694 * return RMAP_MATCH or RMAP_NOOP, return.
1695 * Otherwise continue on to next match statement.
1696 * All match statements must MATCH for
1697 * end-result to be a match.
1698 * (Exception:If match stmts result in a mix of
1699 * MATCH/NOOP, then also end-result is a match)
1700 * If all result in NOOP, end-result is NOOP.
1702 ret
= (*match
->cmd
->func_apply
)(match
->value
, prefix
,
1706 * If the consolidated result of func_apply is:
1707 * -----------------------------------------------
1708 * | MATCH | NOMATCH | NOOP | Final Result |
1709 * ------------------------------------------------
1710 * | yes | yes | yes | NOMATCH |
1711 * | no | no | yes | NOOP |
1712 * | yes | no | yes | MATCH |
1713 * | no | yes | yes | NOMATCH |
1714 * |-----------------------------------------------
1716 * Traditionally, all rules within route-map
1717 * should match for it to MATCH.
1718 * If there are noops within the route-map rules,
1719 * it follows the above matrix.
1721 * Eg: route-map rm1 permit 10
1726 * route-map rm1 permit 20
1755 static struct list
*route_map_get_index_list(struct route_node
**rn
,
1756 const struct prefix
*prefix
,
1757 struct route_table
*table
)
1759 struct route_node
*tmp_rn
= NULL
;
1762 *rn
= route_node_match(table
, prefix
);
1768 return (struct list
*)((*rn
)->info
);
1770 /* If rn->info is NULL, get the parent.
1771 * Store the rn in tmp_rn and unlock it later.
1777 *rn
= (*rn
)->parent
;
1779 route_unlock_node(tmp_rn
);
1785 route_lock_node(*rn
);
1786 return (struct list
*)((*rn
)->info
);
1788 } while (!(*rn
)->info
);
1794 * This function returns the route-map index that best matches the prefix.
1796 static struct route_map_index
*
1797 route_map_get_index(struct route_map
*map
, const struct prefix
*prefix
,
1798 void *object
, enum route_map_cmd_result_t
*match_ret
)
1800 enum route_map_cmd_result_t ret
= RMAP_NOMATCH
;
1801 struct list
*candidate_rmap_list
= NULL
;
1802 struct route_node
*rn
= NULL
;
1803 struct listnode
*ln
= NULL
, *nn
= NULL
;
1804 struct route_map_index
*index
= NULL
, *best_index
= NULL
;
1805 struct route_map_index
*head_index
= NULL
;
1806 struct route_table
*table
= NULL
;
1808 unsigned char family
;
1811 * Handling for matching evpn_routes in the prefix table.
1813 * We convert type2/5 prefix to ipv4/6 prefix to do longest
1814 * prefix matching on.
1816 if (prefix
->family
== AF_EVPN
) {
1817 if (evpn_prefix2prefix(prefix
, &conv
) != 0)
1824 family
= prefix
->family
;
1826 if (family
== AF_INET
)
1827 table
= map
->ipv4_prefix_table
;
1829 table
= map
->ipv6_prefix_table
;
1835 candidate_rmap_list
=
1836 route_map_get_index_list(&rn
, prefix
, table
);
1840 /* If the index at the head of the list is of seq higher
1841 * than that in best_index, ignore the list and get the
1842 * parent node's list.
1844 head_index
= (struct route_map_index
*)(listgetdata(
1845 listhead(candidate_rmap_list
)));
1846 if (best_index
&& head_index
1847 && (best_index
->pref
< head_index
->pref
)) {
1848 route_unlock_node(rn
);
1852 for (ALL_LIST_ELEMENTS(candidate_rmap_list
, ln
, nn
, index
)) {
1853 /* If the index is of seq higher than that in
1854 * best_index, ignore the list and get the parent
1857 if (best_index
&& (best_index
->pref
< index
->pref
))
1860 ret
= route_map_apply_match(&index
->match_list
, prefix
,
1863 if (ret
== RMAP_MATCH
) {
1867 } else if (ret
== RMAP_NOOP
) {
1869 * If match_ret is denymatch, even if we see
1870 * more noops, we retain this return value and
1871 * return this eventually if there are no
1873 * If a best match route-map index already
1874 * exists, do not reset the match_ret.
1876 if (!best_index
&& (*match_ret
!= RMAP_NOMATCH
))
1880 * ret is RMAP_NOMATCH.
1881 * If a best match route-map index already
1882 * exists, do not reset the match_ret.
1889 route_unlock_node(rn
);
1896 static int route_map_candidate_list_cmp(struct route_map_index
*idx1
,
1897 struct route_map_index
*idx2
)
1899 return idx1
->pref
- idx2
->pref
;
1903 * This function adds the route-map index into the default route's
1904 * route-node in the route-map's IPv4/IPv6 prefix-table.
1906 static void route_map_pfx_table_add_default(afi_t afi
,
1907 struct route_map_index
*index
)
1909 struct route_node
*rn
= NULL
;
1910 struct list
*rmap_candidate_list
= NULL
;
1912 bool updated_rn
= false;
1913 struct route_table
*table
= NULL
;
1915 memset(&p
, 0, sizeof(p
));
1916 p
.family
= afi2family(afi
);
1919 if (p
.family
== AF_INET
) {
1920 table
= index
->map
->ipv4_prefix_table
;
1922 index
->map
->ipv4_prefix_table
= route_table_init();
1924 table
= index
->map
->ipv4_prefix_table
;
1926 table
= index
->map
->ipv6_prefix_table
;
1928 index
->map
->ipv6_prefix_table
= route_table_init();
1930 table
= index
->map
->ipv6_prefix_table
;
1933 /* Add default route to table */
1934 rn
= route_node_get(table
, &p
);
1940 rmap_candidate_list
= list_new();
1941 rmap_candidate_list
->cmp
=
1942 (int (*)(void *, void *))route_map_candidate_list_cmp
;
1943 rn
->info
= rmap_candidate_list
;
1945 rmap_candidate_list
= (struct list
*)rn
->info
;
1949 listnode_add_sort_nodup(rmap_candidate_list
, index
);
1951 route_unlock_node(rn
);
1955 * This function removes the route-map index from the default route's
1956 * route-node in the route-map's IPv4/IPv6 prefix-table.
1958 static void route_map_pfx_table_del_default(afi_t afi
,
1959 struct route_map_index
*index
)
1961 struct route_node
*rn
= NULL
;
1962 struct list
*rmap_candidate_list
= NULL
;
1964 struct route_table
*table
= NULL
;
1966 memset(&p
, 0, sizeof(p
));
1967 p
.family
= afi2family(afi
);
1970 if (p
.family
== AF_INET
)
1971 table
= index
->map
->ipv4_prefix_table
;
1973 table
= index
->map
->ipv6_prefix_table
;
1975 /* Remove RMAP index from default route in table */
1976 rn
= route_node_lookup(table
, &p
);
1977 if (!rn
|| !rn
->info
)
1980 rmap_candidate_list
= (struct list
*)rn
->info
;
1982 listnode_delete(rmap_candidate_list
, index
);
1984 if (listcount(rmap_candidate_list
) == 0) {
1985 list_delete(&rmap_candidate_list
);
1987 route_unlock_node(rn
);
1989 route_unlock_node(rn
);
1993 * This function adds the route-map index to the route-node for
1994 * the prefix-entry in the route-map's IPv4/IPv6 prefix-table.
1996 static void route_map_pfx_table_add(struct route_table
*table
,
1997 struct route_map_index
*index
,
1998 struct prefix_list_entry
*pentry
)
2000 struct route_node
*rn
= NULL
;
2001 struct list
*rmap_candidate_list
= NULL
;
2002 bool updated_rn
= false;
2004 rn
= route_node_get(table
, &pentry
->prefix
);
2009 rmap_candidate_list
= list_new();
2010 rmap_candidate_list
->cmp
=
2011 (int (*)(void *, void *))route_map_candidate_list_cmp
;
2012 rn
->info
= rmap_candidate_list
;
2014 rmap_candidate_list
= (struct list
*)rn
->info
;
2018 listnode_add_sort_nodup(rmap_candidate_list
, index
);
2020 route_unlock_node(rn
);
2024 * This function removes the route-map index from the route-node for
2025 * the prefix-entry in the route-map's IPv4/IPv6 prefix-table.
2027 static void route_map_pfx_table_del(struct route_table
*table
,
2028 struct route_map_index
*index
,
2029 struct prefix_list_entry
*pentry
)
2031 struct route_node
*rn
= NULL
;
2032 struct list
*rmap_candidate_list
= NULL
;
2034 rn
= route_node_lookup(table
, &pentry
->prefix
);
2035 if (!rn
|| !rn
->info
)
2038 rmap_candidate_list
= (struct list
*)rn
->info
;
2040 listnode_delete(rmap_candidate_list
, index
);
2042 if (listcount(rmap_candidate_list
) == 0) {
2043 list_delete(&rmap_candidate_list
);
2045 route_unlock_node(rn
);
2047 route_unlock_node(rn
);
2050 /* This function checks for the presence of an IPv4 prefix-list
2051 * match rule in the given route-map index.
2053 static bool route_map_is_ip_pfx_list_rule_present(struct route_map_index
*index
)
2055 struct route_map_rule_list
*match_list
= NULL
;
2056 struct route_map_rule
*rule
= NULL
;
2058 match_list
= &index
->match_list
;
2059 for (rule
= match_list
->head
; rule
; rule
= rule
->next
)
2060 if (IS_RULE_IPv4_PREFIX_LIST(rule
->cmd
->str
))
2066 /* This function checks for the presence of an IPv6 prefix-list
2067 * match rule in the given route-map index.
2070 route_map_is_ipv6_pfx_list_rule_present(struct route_map_index
*index
)
2072 struct route_map_rule_list
*match_list
= NULL
;
2073 struct route_map_rule
*rule
= NULL
;
2075 match_list
= &index
->match_list
;
2076 for (rule
= match_list
->head
; rule
; rule
= rule
->next
)
2077 if (IS_RULE_IPv6_PREFIX_LIST(rule
->cmd
->str
))
2083 /* This function does the following:
2084 * 1) If plist_name is not present, search for a IPv4 or IPv6 prefix-list
2085 * match clause (based on the afi passed to this foo) and get the
2087 * 2) Look up the prefix-list using the name.
2088 * 3) If the prefix-list is not found then, add the index to the IPv4/IPv6
2089 * default-route's node in the trie (based on the afi passed to this foo).
2090 * 4) If the prefix-list is found then, remove the index from the IPv4/IPv6
2091 * default-route's node in the trie (based on the afi passed to this foo).
2092 * 5) If a prefix-entry is passed then, create a route-node for this entry and
2093 * add this index to the route-node.
2094 * 6) If prefix-entry is not passed then, for every prefix-entry in the
2095 * prefix-list, create a route-node for this entry and
2096 * add this index to the route-node.
2098 static void route_map_add_plist_entries(afi_t afi
,
2099 struct route_map_index
*index
,
2100 const char *plist_name
,
2101 struct prefix_list_entry
*entry
)
2103 struct route_map_rule_list
*match_list
= NULL
;
2104 struct route_map_rule
*match
= NULL
;
2105 struct prefix_list
*plist
= NULL
;
2106 struct prefix_list_entry
*pentry
= NULL
;
2107 bool plist_rule_is_present
= false;
2110 match_list
= &index
->match_list
;
2112 for (match
= match_list
->head
; match
; match
= match
->next
) {
2113 if (afi
== AFI_IP
) {
2114 if (IS_RULE_IPv4_PREFIX_LIST(match
->cmd
->str
)) {
2115 plist_rule_is_present
= true;
2119 if (IS_RULE_IPv6_PREFIX_LIST(match
->cmd
->str
)) {
2120 plist_rule_is_present
= true;
2126 if (plist_rule_is_present
)
2127 plist
= prefix_list_lookup(afi
, match
->rule_str
);
2129 plist
= prefix_list_lookup(afi
, plist_name
);
2133 route_map_pfx_table_add_default(afi
, index
);
2137 /* Default entry should be deleted only if the first entry of the
2138 * prefix-list is created.
2141 if (plist
->count
== 1)
2142 route_map_pfx_table_del_default(afi
, index
);
2144 route_map_pfx_table_del_default(afi
, index
);
2148 if (afi
== AFI_IP
) {
2149 route_map_pfx_table_add(index
->map
->ipv4_prefix_table
,
2152 route_map_pfx_table_add(index
->map
->ipv6_prefix_table
,
2156 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
2157 if (afi
== AFI_IP
) {
2158 route_map_pfx_table_add(
2159 index
->map
->ipv4_prefix_table
, index
,
2162 route_map_pfx_table_add(
2163 index
->map
->ipv6_prefix_table
, index
,
2170 /* This function does the following:
2171 * 1) If plist_name is not present, search for a IPv4 or IPv6 prefix-list
2172 * match clause (based on the afi passed to this foo) and get the
2174 * 2) Look up the prefix-list using the name.
2175 * 3) If the prefix-list is not found then, delete the index from the IPv4/IPv6
2176 * default-route's node in the trie (based on the afi passed to this foo).
2177 * 4) If a prefix-entry is passed then, remove this index from the route-node
2178 * for the prefix in this prefix-entry.
2179 * 5) If prefix-entry is not passed then, for every prefix-entry in the
2180 * prefix-list, remove this index from the route-node
2181 * for the prefix in this prefix-entry.
2183 static void route_map_del_plist_entries(afi_t afi
,
2184 struct route_map_index
*index
,
2185 const char *plist_name
,
2186 struct prefix_list_entry
*entry
)
2188 struct route_map_rule_list
*match_list
= NULL
;
2189 struct route_map_rule
*match
= NULL
;
2190 struct prefix_list
*plist
= NULL
;
2191 struct prefix_list_entry
*pentry
= NULL
;
2192 bool plist_rule_is_present
= false;
2195 match_list
= &index
->match_list
;
2197 for (match
= match_list
->head
; match
; match
= match
->next
) {
2198 if (afi
== AFI_IP
) {
2199 if (IS_RULE_IPv4_PREFIX_LIST(match
->cmd
->str
)) {
2200 plist_rule_is_present
= true;
2204 if (IS_RULE_IPv6_PREFIX_LIST(match
->cmd
->str
)) {
2205 plist_rule_is_present
= true;
2211 if (plist_rule_is_present
)
2212 plist
= prefix_list_lookup(afi
, match
->rule_str
);
2214 plist
= prefix_list_lookup(afi
, plist_name
);
2218 route_map_pfx_table_del_default(afi
, index
);
2223 if (afi
== AFI_IP
) {
2224 route_map_pfx_table_del(index
->map
->ipv4_prefix_table
,
2227 route_map_pfx_table_del(index
->map
->ipv6_prefix_table
,
2231 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
2232 if (afi
== AFI_IP
) {
2233 route_map_pfx_table_del(
2234 index
->map
->ipv4_prefix_table
, index
,
2237 route_map_pfx_table_del(
2238 index
->map
->ipv6_prefix_table
, index
,
2246 * This function handles the cases where a prefix-list is added/removed
2247 * as a match command from a particular route-map index.
2248 * It updates the prefix-table of the route-map accordingly.
2250 static void route_map_trie_update(afi_t afi
, route_map_event_t event
,
2251 struct route_map_index
*index
,
2252 const char *plist_name
)
2254 if (event
== RMAP_EVENT_PLIST_ADDED
) {
2255 if (afi
== AFI_IP
) {
2256 if (!route_map_is_ipv6_pfx_list_rule_present(index
)) {
2257 route_map_pfx_table_del_default(AFI_IP6
, index
);
2258 route_map_add_plist_entries(afi
, index
,
2261 route_map_del_plist_entries(AFI_IP6
, index
,
2265 if (!route_map_is_ip_pfx_list_rule_present(index
)) {
2266 route_map_pfx_table_del_default(AFI_IP
, index
);
2267 route_map_add_plist_entries(afi
, index
,
2270 route_map_del_plist_entries(AFI_IP
, index
, NULL
,
2274 } else if (event
== RMAP_EVENT_PLIST_DELETED
) {
2275 if (afi
== AFI_IP
) {
2276 route_map_del_plist_entries(afi
, index
, plist_name
,
2279 /* If IPv6 prefix-list match rule is not present,
2280 * add this index to the IPv4 default route's trie
2282 * Also, add this index to the trie nodes created
2283 * for each of the prefix-entries within the IPv6
2284 * prefix-list, if the IPv6 prefix-list match rule
2285 * is present. Else, add this index to the IPv6
2286 * default route's trie node.
2288 if (!route_map_is_ipv6_pfx_list_rule_present(index
))
2289 route_map_pfx_table_add_default(afi
, index
);
2291 route_map_add_plist_entries(AFI_IP6
, index
, NULL
, NULL
);
2293 route_map_del_plist_entries(afi
, index
, plist_name
,
2296 /* If IPv4 prefix-list match rule is not present,
2297 * add this index to the IPv6 default route's trie
2299 * Also, add this index to the trie nodes created
2300 * for each of the prefix-entries within the IPv4
2301 * prefix-list, if the IPv4 prefix-list match rule
2302 * is present. Else, add this index to the IPv4
2303 * default route's trie node.
2305 if (!route_map_is_ip_pfx_list_rule_present(index
))
2306 route_map_pfx_table_add_default(afi
, index
);
2308 route_map_add_plist_entries(AFI_IP
, index
, NULL
, NULL
);
2314 * This function handles the cases where a route-map index and
2315 * prefix-list is added/removed.
2316 * It updates the prefix-table of the route-map accordingly.
2318 static void route_map_pfx_tbl_update(route_map_event_t event
,
2319 struct route_map_index
*index
, afi_t afi
,
2320 const char *plist_name
)
2322 struct route_map
*rmap
= NULL
;
2327 if (event
== RMAP_EVENT_INDEX_ADDED
) {
2328 route_map_pfx_table_add_default(AFI_IP
, index
);
2329 route_map_pfx_table_add_default(AFI_IP6
, index
);
2333 if (event
== RMAP_EVENT_INDEX_DELETED
) {
2334 route_map_pfx_table_del_default(AFI_IP
, index
);
2335 route_map_pfx_table_del_default(AFI_IP6
, index
);
2337 if ((index
->map
->head
== NULL
) && (index
->map
->tail
== NULL
)) {
2340 if (rmap
->ipv4_prefix_table
) {
2341 route_table_finish(rmap
->ipv4_prefix_table
);
2342 rmap
->ipv4_prefix_table
= NULL
;
2345 if (rmap
->ipv6_prefix_table
) {
2346 route_table_finish(rmap
->ipv6_prefix_table
);
2347 rmap
->ipv6_prefix_table
= NULL
;
2353 /* Handle prefix-list match rule addition/deletion.
2355 route_map_trie_update(afi
, event
, index
, plist_name
);
2359 * This function handles the cases where a new prefix-entry is added to
2360 * a prefix-list or, an existing prefix-entry is removed from the prefix-list.
2361 * It updates the prefix-table of the route-map accordingly.
2363 static void route_map_pentry_update(route_map_event_t event
,
2364 const char *plist_name
,
2365 struct route_map_index
*index
,
2366 struct prefix_list_entry
*pentry
)
2368 struct prefix_list
*plist
= NULL
;
2370 unsigned char family
= pentry
->prefix
.family
;
2372 if (family
== AF_INET
) {
2374 plist
= prefix_list_lookup(AFI_IP
, plist_name
);
2377 plist
= prefix_list_lookup(AFI_IP6
, plist_name
);
2380 if (event
== RMAP_EVENT_PLIST_ADDED
) {
2381 if (afi
== AFI_IP
) {
2382 if (!route_map_is_ipv6_pfx_list_rule_present(index
))
2383 route_map_add_plist_entries(afi
, index
,
2384 plist_name
, pentry
);
2386 if (!route_map_is_ip_pfx_list_rule_present(index
))
2387 route_map_add_plist_entries(afi
, index
,
2388 plist_name
, pentry
);
2390 } else if (event
== RMAP_EVENT_PLIST_DELETED
) {
2391 route_map_del_plist_entries(afi
, index
, plist_name
, pentry
);
2393 if (plist
->count
== 1) {
2394 if (afi
== AFI_IP
) {
2395 if (!route_map_is_ipv6_pfx_list_rule_present(
2397 route_map_pfx_table_add_default(afi
,
2400 if (!route_map_is_ip_pfx_list_rule_present(
2402 route_map_pfx_table_add_default(afi
,
2409 static void route_map_pentry_process_dependency(struct hash_bucket
*bucket
,
2412 char *rmap_name
= NULL
;
2413 struct route_map
*rmap
= NULL
;
2414 struct route_map_index
*index
= NULL
;
2415 struct route_map_rule_list
*match_list
= NULL
;
2416 struct route_map_rule
*match
= NULL
;
2417 struct route_map_dep_data
*dep_data
= NULL
;
2418 struct route_map_pentry_dep
*pentry_dep
=
2419 (struct route_map_pentry_dep
*)data
;
2420 unsigned char family
= pentry_dep
->pentry
->prefix
.family
;
2422 dep_data
= (struct route_map_dep_data
*)bucket
->data
;
2426 rmap_name
= dep_data
->rname
;
2427 rmap
= route_map_lookup_by_name(rmap_name
);
2428 if (!rmap
|| !rmap
->head
)
2431 for (index
= rmap
->head
; index
; index
= index
->next
) {
2432 match_list
= &index
->match_list
;
2437 for (match
= match_list
->head
; match
; match
= match
->next
) {
2438 if (strcmp(match
->rule_str
, pentry_dep
->plist_name
)
2440 if (IS_RULE_IPv4_PREFIX_LIST(match
->cmd
->str
)
2441 && family
== AF_INET
) {
2442 route_map_pentry_update(
2444 pentry_dep
->plist_name
, index
,
2445 pentry_dep
->pentry
);
2446 } else if (IS_RULE_IPv6_PREFIX_LIST(
2448 && family
== AF_INET6
) {
2449 route_map_pentry_update(
2451 pentry_dep
->plist_name
, index
,
2452 pentry_dep
->pentry
);
2459 void route_map_notify_pentry_dependencies(const char *affected_name
,
2460 struct prefix_list_entry
*pentry
,
2461 route_map_event_t event
)
2463 struct route_map_dep
*dep
= NULL
;
2464 struct hash
*upd8_hash
= NULL
;
2465 struct route_map_pentry_dep pentry_dep
;
2467 if (!affected_name
|| !pentry
)
2470 upd8_hash
= route_map_get_dep_hash(event
);
2474 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, (void *)affected_name
,
2477 if (!dep
->this_hash
)
2478 dep
->this_hash
= upd8_hash
;
2480 memset(&pentry_dep
, 0, sizeof(pentry_dep
));
2481 pentry_dep
.pentry
= pentry
;
2482 pentry_dep
.plist_name
= affected_name
;
2483 pentry_dep
.event
= event
;
2485 hash_iterate(dep
->dep_rmap_hash
,
2486 route_map_pentry_process_dependency
,
2487 (void *)&pentry_dep
);
2491 /* Apply route map's each index to the object.
2493 The matrix for a route-map looks like this:
2494 (note, this includes the description for the "NEXT"
2495 and "GOTO" frobs now
2497 | Match | No Match | No op
2498 |-----------|--------------|-------
2499 permit | action | cont | cont.
2500 | | default:deny | default:permit
2501 -------------------+-----------------------
2502 | deny | cont | cont.
2503 deny | | default:deny | default:permit
2504 |-----------|--------------|--------
2507 -Apply Set statements, accept route
2508 -If Call statement is present jump to the specified route-map, if it
2509 denies the route we finish.
2510 -If NEXT is specified, goto NEXT statement
2511 -If GOTO is specified, goto the first clause where pref > nextpref
2512 -If nothing is specified, do as Cisco and finish
2514 -Route is denied by route-map.
2518 If we get no matches after we've processed all updates, then the route
2521 Some notes on the new "CALL", "NEXT" and "GOTO"
2522 call WORD - If this clause is matched, then the set statements
2523 are executed and then we jump to route-map 'WORD'. If
2524 this route-map denies the route, we finish, in other
2526 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
2527 on-match next - If this clause is matched, then the set statements
2528 are executed and then we drop through to the next clause
2529 on-match goto n - If this clause is matched, then the set statements
2530 are executed and then we goto the nth clause, or the
2531 first clause greater than this. In order to ensure
2532 route-maps *always* exit, you cannot jump backwards.
2535 We need to make sure our route-map processing matches the above
2537 route_map_result_t
route_map_apply_ext(struct route_map
*map
,
2538 const struct prefix
*prefix
,
2539 void *match_object
, void *set_object
,
2542 static int recursion
= 0;
2543 enum route_map_cmd_result_t match_ret
= RMAP_NOMATCH
;
2544 route_map_result_t ret
= RMAP_PERMITMATCH
;
2545 struct route_map_index
*index
= NULL
;
2546 struct route_map_rule
*set
= NULL
;
2547 bool skip_match_clause
= false;
2549 if (recursion
> RMAP_RECURSION_LIMIT
) {
2551 EC_LIB_RMAP_RECURSION_LIMIT
,
2552 "route-map recursion limit (%d) reached, discarding route",
2553 RMAP_RECURSION_LIMIT
);
2555 return RMAP_DENYMATCH
;
2558 if (map
== NULL
|| map
->head
== NULL
) {
2559 ret
= RMAP_DENYMATCH
;
2560 goto route_map_apply_end
;
2565 if ((!map
->optimization_disabled
)
2566 && (map
->ipv4_prefix_table
|| map
->ipv6_prefix_table
)) {
2567 index
= route_map_get_index(map
, prefix
, match_object
,
2571 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
2573 "Best match route-map: %s, sequence: %d for pfx: %pFX, result: %s",
2574 map
->name
, index
->pref
, prefix
,
2575 route_map_cmd_result_str(match_ret
));
2577 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
2579 "No best match sequence for pfx: %pFX in route-map: %s, result: %s",
2581 route_map_cmd_result_str(match_ret
));
2583 * No index matches this prefix. Return deny unless,
2584 * match_ret = RMAP_NOOP.
2586 if (match_ret
== RMAP_NOOP
)
2587 ret
= RMAP_PERMITMATCH
;
2589 ret
= RMAP_DENYMATCH
;
2590 goto route_map_apply_end
;
2592 skip_match_clause
= true;
2597 for (; index
; index
= index
->next
) {
2598 if (!skip_match_clause
) {
2600 /* Apply this index. */
2601 match_ret
= route_map_apply_match(&index
->match_list
,
2602 prefix
, match_object
);
2603 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
)) {
2605 "Route-map: %s, sequence: %d, prefix: %pFX, result: %s",
2606 map
->name
, index
->pref
, prefix
,
2607 route_map_cmd_result_str(match_ret
));
2610 skip_match_clause
= false;
2613 /* Now we apply the matrix from above */
2614 if (match_ret
== RMAP_NOOP
)
2616 * Do not change the return value. Retain the previous
2617 * return value. Previous values can be:
2618 * 1)permitmatch (if a nomatch was never
2619 * seen before in this route-map.)
2620 * 2)denymatch (if a nomatch was seen earlier in one
2621 * of the previous sequences)
2625 * 'cont' from matrix - continue to next route-map
2629 else if (match_ret
== RMAP_NOMATCH
) {
2632 * The return value is now changed to denymatch.
2633 * So from here on out, even if we see more noops,
2634 * we retain this return value and return this
2635 * eventually if there are no matches.
2637 ret
= RMAP_DENYMATCH
;
2640 * 'cont' from matrix - continue to next route-map
2644 } else if (match_ret
== RMAP_MATCH
) {
2645 if (index
->type
== RMAP_PERMIT
)
2648 /* Match succeeded, rmap is of type permit */
2649 ret
= RMAP_PERMITMATCH
;
2651 /* permit+match must execute sets */
2652 for (set
= index
->set_list
.head
; set
;
2655 * set cmds return RMAP_OKAY or
2656 * RMAP_ERROR. We do not care if
2657 * set succeeded or not. So, ignore
2660 (void)(*set
->cmd
->func_apply
)(
2661 set
->value
, prefix
, set_object
);
2663 /* Call another route-map if available */
2664 if (index
->nextrm
) {
2665 struct route_map
*nextrm
=
2666 route_map_lookup_by_name(
2669 if (nextrm
) /* Target route-map found,
2673 ret
= route_map_apply_ext(
2680 /* If nextrm returned 'deny', finish. */
2681 if (ret
== RMAP_DENYMATCH
)
2682 goto route_map_apply_end
;
2685 switch (index
->exitpolicy
) {
2687 goto route_map_apply_end
;
2691 /* Find the next clause to jump to */
2692 struct route_map_index
*next
=
2694 int nextpref
= index
->nextpref
;
2696 while (next
&& next
->pref
< nextpref
) {
2701 /* No clauses match! */
2702 goto route_map_apply_end
;
2706 } else if (index
->type
== RMAP_DENY
)
2709 ret
= RMAP_DENYMATCH
;
2710 goto route_map_apply_end
;
2715 route_map_apply_end
:
2716 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
2717 zlog_debug("Route-map: %s, prefix: %pFX, result: %s",
2718 (map
? map
->name
: "null"), prefix
,
2719 route_map_result_str(ret
));
2722 if (index
!= NULL
&& ret
== RMAP_PERMITMATCH
)
2723 *pref
= index
->pref
;
2731 void route_map_add_hook(void (*func
)(const char *))
2733 route_map_master
.add_hook
= func
;
2736 void route_map_delete_hook(void (*func
)(const char *))
2738 route_map_master
.delete_hook
= func
;
2741 void route_map_event_hook(void (*func
)(const char *name
))
2743 route_map_master
.event_hook
= func
;
2746 /* Routines for route map dependency lists and dependency processing */
2747 static bool route_map_rmap_hash_cmp(const void *p1
, const void *p2
)
2749 return strcmp(((const struct route_map_dep_data
*)p1
)->rname
,
2750 ((const struct route_map_dep_data
*)p2
)->rname
)
2754 static bool route_map_dep_hash_cmp(const void *p1
, const void *p2
)
2757 return (strcmp(((const struct route_map_dep
*)p1
)->dep_name
,
2762 static void route_map_clear_reference(struct hash_bucket
*bucket
, void *arg
)
2764 struct route_map_dep
*dep
= bucket
->data
;
2765 struct route_map_dep_data
*dep_data
= NULL
, tmp_dep_data
;
2767 memset(&tmp_dep_data
, 0, sizeof(tmp_dep_data
));
2768 tmp_dep_data
.rname
= arg
;
2769 dep_data
= hash_release(dep
->dep_rmap_hash
, &tmp_dep_data
);
2771 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
2772 zlog_debug("Clearing reference for %s to %s count: %d",
2773 dep
->dep_name
, tmp_dep_data
.rname
,
2776 XFREE(MTYPE_ROUTE_MAP_NAME
, dep_data
->rname
);
2777 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, dep_data
);
2779 if (!dep
->dep_rmap_hash
->count
) {
2780 dep
= hash_release(dep
->this_hash
, (void *)dep
->dep_name
);
2781 hash_free(dep
->dep_rmap_hash
);
2782 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
2783 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
2787 static void route_map_clear_all_references(char *rmap_name
)
2791 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
2792 zlog_debug("Clearing references for %s", rmap_name
);
2794 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
2795 hash_iterate(route_map_dep_hash
[i
], route_map_clear_reference
,
2800 static unsigned int route_map_dep_data_hash_make_key(const void *p
)
2802 const struct route_map_dep_data
*dep_data
= p
;
2804 return string_hash_make(dep_data
->rname
);
2807 static void *route_map_dep_hash_alloc(void *p
)
2809 char *dep_name
= (char *)p
;
2810 struct route_map_dep
*dep_entry
;
2812 dep_entry
= XCALLOC(MTYPE_ROUTE_MAP_DEP
, sizeof(struct route_map_dep
));
2813 dep_entry
->dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
2814 dep_entry
->dep_rmap_hash
=
2815 hash_create_size(8, route_map_dep_data_hash_make_key
,
2816 route_map_rmap_hash_cmp
, "Route Map Dep Hash");
2817 dep_entry
->this_hash
= NULL
;
2822 static void *route_map_name_hash_alloc(void *p
)
2824 struct route_map_dep_data
*dep_data
= NULL
, *tmp_dep_data
= NULL
;
2826 dep_data
= XCALLOC(MTYPE_ROUTE_MAP_DEP_DATA
,
2827 sizeof(struct route_map_dep_data
));
2829 dep_data
->rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, tmp_dep_data
->rname
);
2833 static unsigned int route_map_dep_hash_make_key(const void *p
)
2835 return (string_hash_make((char *)p
));
2838 static void route_map_print_dependency(struct hash_bucket
*bucket
, void *data
)
2840 struct route_map_dep_data
*dep_data
= bucket
->data
;
2841 char *rmap_name
= dep_data
->rname
;
2842 char *dep_name
= data
;
2844 zlog_debug("%s: Dependency for %s: %s", __func__
, dep_name
, rmap_name
);
2847 static int route_map_dep_update(struct hash
*dephash
, const char *dep_name
,
2848 const char *rmap_name
, route_map_event_t type
)
2850 struct route_map_dep
*dep
= NULL
;
2851 char *dname
, *rname
;
2853 struct route_map_dep_data
*dep_data
= NULL
, *ret_dep_data
= NULL
;
2854 struct route_map_dep_data tmp_dep_data
;
2856 dname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
2857 rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
2860 case RMAP_EVENT_PLIST_ADDED
:
2861 case RMAP_EVENT_CLIST_ADDED
:
2862 case RMAP_EVENT_ECLIST_ADDED
:
2863 case RMAP_EVENT_ASLIST_ADDED
:
2864 case RMAP_EVENT_LLIST_ADDED
:
2865 case RMAP_EVENT_CALL_ADDED
:
2866 case RMAP_EVENT_FILTER_ADDED
:
2867 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
2868 zlog_debug("Adding dependency for filter %s in route-map %s",
2869 dep_name
, rmap_name
);
2870 dep
= (struct route_map_dep
*)hash_get(
2871 dephash
, dname
, route_map_dep_hash_alloc
);
2877 if (!dep
->this_hash
)
2878 dep
->this_hash
= dephash
;
2880 memset(&tmp_dep_data
, 0, sizeof(tmp_dep_data
));
2881 tmp_dep_data
.rname
= rname
;
2882 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
2884 dep_data
= hash_get(dep
->dep_rmap_hash
, &tmp_dep_data
,
2885 route_map_name_hash_alloc
);
2889 case RMAP_EVENT_PLIST_DELETED
:
2890 case RMAP_EVENT_CLIST_DELETED
:
2891 case RMAP_EVENT_ECLIST_DELETED
:
2892 case RMAP_EVENT_ASLIST_DELETED
:
2893 case RMAP_EVENT_LLIST_DELETED
:
2894 case RMAP_EVENT_CALL_DELETED
:
2895 case RMAP_EVENT_FILTER_DELETED
:
2896 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
2897 zlog_debug("Deleting dependency for filter %s in route-map %s",
2898 dep_name
, rmap_name
);
2899 dep
= (struct route_map_dep
*)hash_get(dephash
, dname
, NULL
);
2904 memset(&tmp_dep_data
, 0, sizeof(tmp_dep_data
));
2905 tmp_dep_data
.rname
= rname
;
2906 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
2908 * If dep_data is NULL then something has gone seriously
2909 * wrong in route-map handling. Note it and prevent
2914 "route-map dependency for route-map %s: %s is not correct",
2915 rmap_name
, dep_name
);
2921 if (!dep_data
->refcnt
) {
2922 ret_dep_data
= hash_release(dep
->dep_rmap_hash
,
2925 XFREE(MTYPE_ROUTE_MAP_NAME
,
2926 ret_dep_data
->rname
);
2927 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, ret_dep_data
);
2931 if (!dep
->dep_rmap_hash
->count
) {
2932 dep
= hash_release(dephash
, dname
);
2933 hash_free(dep
->dep_rmap_hash
);
2934 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
2935 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
2938 case RMAP_EVENT_SET_ADDED
:
2939 case RMAP_EVENT_SET_DELETED
:
2940 case RMAP_EVENT_SET_REPLACED
:
2941 case RMAP_EVENT_MATCH_ADDED
:
2942 case RMAP_EVENT_MATCH_DELETED
:
2943 case RMAP_EVENT_MATCH_REPLACED
:
2944 case RMAP_EVENT_INDEX_ADDED
:
2945 case RMAP_EVENT_INDEX_DELETED
:
2950 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
2951 hash_iterate(dep
->dep_rmap_hash
,
2952 route_map_print_dependency
, dname
);
2956 XFREE(MTYPE_ROUTE_MAP_NAME
, rname
);
2957 XFREE(MTYPE_ROUTE_MAP_NAME
, dname
);
2961 static struct hash
*route_map_get_dep_hash(route_map_event_t event
)
2963 struct hash
*upd8_hash
= NULL
;
2966 case RMAP_EVENT_PLIST_ADDED
:
2967 case RMAP_EVENT_PLIST_DELETED
:
2968 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_PLIST
];
2970 case RMAP_EVENT_CLIST_ADDED
:
2971 case RMAP_EVENT_CLIST_DELETED
:
2972 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_CLIST
];
2974 case RMAP_EVENT_ECLIST_ADDED
:
2975 case RMAP_EVENT_ECLIST_DELETED
:
2976 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ECLIST
];
2978 case RMAP_EVENT_ASLIST_ADDED
:
2979 case RMAP_EVENT_ASLIST_DELETED
:
2980 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ASPATH
];
2982 case RMAP_EVENT_LLIST_ADDED
:
2983 case RMAP_EVENT_LLIST_DELETED
:
2984 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_LCLIST
];
2986 case RMAP_EVENT_CALL_ADDED
:
2987 case RMAP_EVENT_CALL_DELETED
:
2988 case RMAP_EVENT_MATCH_ADDED
:
2989 case RMAP_EVENT_MATCH_DELETED
:
2990 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_RMAP
];
2992 case RMAP_EVENT_FILTER_ADDED
:
2993 case RMAP_EVENT_FILTER_DELETED
:
2994 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_FILTER
];
2997 * Should we actually be ignoring these?
2998 * I am not sure but at this point in time, let
2999 * us get them into this switch and we can peel
3000 * them into the appropriate place in the future
3002 case RMAP_EVENT_SET_ADDED
:
3003 case RMAP_EVENT_SET_DELETED
:
3004 case RMAP_EVENT_SET_REPLACED
:
3005 case RMAP_EVENT_MATCH_REPLACED
:
3006 case RMAP_EVENT_INDEX_ADDED
:
3007 case RMAP_EVENT_INDEX_DELETED
:
3014 static void route_map_process_dependency(struct hash_bucket
*bucket
, void *data
)
3016 struct route_map_dep_data
*dep_data
= NULL
;
3017 char *rmap_name
= NULL
;
3019 dep_data
= bucket
->data
;
3020 rmap_name
= dep_data
->rname
;
3022 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
3023 zlog_debug("Notifying %s of dependency", rmap_name
);
3024 if (route_map_master
.event_hook
)
3025 (*route_map_master
.event_hook
)(rmap_name
);
3028 void route_map_upd8_dependency(route_map_event_t type
, const char *arg
,
3029 const char *rmap_name
)
3031 struct hash
*upd8_hash
= NULL
;
3033 if ((upd8_hash
= route_map_get_dep_hash(type
))) {
3034 route_map_dep_update(upd8_hash
, arg
, rmap_name
, type
);
3036 if (type
== RMAP_EVENT_CALL_ADDED
) {
3038 if (route_map_master
.add_hook
)
3039 (*route_map_master
.add_hook
)(rmap_name
);
3040 } else if (type
== RMAP_EVENT_CALL_DELETED
) {
3042 if (route_map_master
.delete_hook
)
3043 (*route_map_master
.delete_hook
)(rmap_name
);
3048 void route_map_notify_dependencies(const char *affected_name
,
3049 route_map_event_t event
)
3051 struct route_map_dep
*dep
;
3052 struct hash
*upd8_hash
;
3058 name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, affected_name
);
3060 if ((upd8_hash
= route_map_get_dep_hash(event
)) == NULL
) {
3061 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
3065 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, name
, NULL
);
3067 if (!dep
->this_hash
)
3068 dep
->this_hash
= upd8_hash
;
3070 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
3071 zlog_debug("Filter %s updated", dep
->dep_name
);
3072 hash_iterate(dep
->dep_rmap_hash
, route_map_process_dependency
,
3076 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
3079 /* VTY related functions. */
3080 static void clear_route_map_helper(struct route_map
*map
)
3082 struct route_map_index
*index
;
3084 map
->applied_clear
= map
->applied
;
3085 for (index
= map
->head
; index
; index
= index
->next
)
3086 index
->applied_clear
= index
->applied
;
3089 DEFUN (rmap_clear_counters
,
3090 rmap_clear_counters_cmd
,
3091 "clear route-map counters [WORD]",
3093 "route-map information\n"
3094 "counters associated with the specified route-map\n"
3098 struct route_map
*map
;
3100 const char *name
= (argc
== 3 ) ? argv
[idx_word
]->arg
: NULL
;
3103 map
= route_map_lookup_by_name(name
);
3106 clear_route_map_helper(map
);
3108 vty_out(vty
, "%s: 'route-map %s' not found\n",
3109 frr_protonameinst
, name
);
3113 for (map
= route_map_master
.head
; map
; map
= map
->next
)
3114 clear_route_map_helper(map
);
3121 DEFUN (rmap_show_name
,
3123 "show route-map [WORD] [json]",
3125 "route-map information\n"
3129 bool uj
= use_json(argc
, argv
);
3131 const char *name
= NULL
;
3133 if (argv_find(argv
, argc
, "WORD", &idx
))
3134 name
= argv
[idx
]->arg
;
3136 return vty_show_route_map(vty
, name
, uj
);
3139 DEFUN (rmap_show_unused
,
3140 rmap_show_unused_cmd
,
3141 "show route-map-unused",
3143 "unused route-map information\n")
3145 return vty_show_unused_route_map(vty
);
3150 "debug route-map [detail]$detail",
3152 "Debug option set for route-maps\n"
3153 "Detailed output\n")
3156 SET_FLAG(rmap_debug
, DEBUG_ROUTEMAP
);
3158 SET_FLAG(rmap_debug
, DEBUG_ROUTEMAP
| DEBUG_ROUTEMAP_DETAIL
);
3163 DEFPY (no_debug_rmap
,
3165 "no debug route-map [detail]$detail",
3168 "Debug option set for route-maps\n"
3169 "Detailed output\n")
3172 UNSET_FLAG(rmap_debug
, DEBUG_ROUTEMAP
);
3174 UNSET_FLAG(rmap_debug
, DEBUG_ROUTEMAP
| DEBUG_ROUTEMAP_DETAIL
);
3180 static int rmap_config_write_debug(struct vty
*vty
);
3181 static struct cmd_node rmap_debug_node
= {
3182 .name
= "route-map debug",
3183 .node
= RMAP_DEBUG_NODE
,
3185 .config_write
= rmap_config_write_debug
,
3188 void route_map_show_debug(struct vty
*vty
)
3190 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
3191 vty_out(vty
, "debug route-map\n");
3194 /* Configuration write function. */
3195 static int rmap_config_write_debug(struct vty
*vty
)
3199 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
)) {
3200 vty_out(vty
, "debug route-map\n");
3207 /* Common route map rules */
3209 void *route_map_rule_tag_compile(const char *arg
)
3211 unsigned long int tmp
;
3216 tmp
= strtoul(arg
, &endptr
, 0);
3217 if (arg
[0] == '\0' || *endptr
!= '\0' || errno
|| tmp
> ROUTE_TAG_MAX
)
3220 tag
= XMALLOC(MTYPE_ROUTE_MAP_COMPILED
, sizeof(*tag
));
3226 void route_map_rule_tag_free(void *rule
)
3228 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
3231 void route_map_finish(void)
3234 struct route_map_rule_cmd_proxy
*proxy
;
3236 /* these 2 hash tables have INIT_HASH initializers, so the "default"
3237 * state is "initialized & empty" => fini() followed by init() to
3238 * return to that same state
3240 while ((proxy
= rmap_cmd_name_pop(rmap_match_cmds
)))
3242 rmap_cmd_name_fini(rmap_match_cmds
);
3243 rmap_cmd_name_init(rmap_match_cmds
);
3245 while ((proxy
= rmap_cmd_name_pop(rmap_set_cmds
)))
3247 rmap_cmd_name_fini(rmap_set_cmds
);
3248 rmap_cmd_name_init(rmap_set_cmds
);
3251 * All protocols are setting these to NULL
3252 * by default on shutdown( route_map_finish )
3253 * Why are we making them do this work?
3255 route_map_master
.add_hook
= NULL
;
3256 route_map_master
.delete_hook
= NULL
;
3257 route_map_master
.event_hook
= NULL
;
3259 /* cleanup route_map */
3260 while (route_map_master
.head
) {
3261 struct route_map
*map
= route_map_master
.head
;
3262 map
->to_be_processed
= false;
3263 route_map_delete(map
);
3266 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
3267 hash_free(route_map_dep_hash
[i
]);
3268 route_map_dep_hash
[i
] = NULL
;
3271 hash_free(route_map_master_hash
);
3272 route_map_master_hash
= NULL
;
3275 /* Increment the use_count counter while attaching the route map */
3276 void route_map_counter_increment(struct route_map
*map
)
3282 /* Decrement the use_count counter while detaching the route map. */
3283 void route_map_counter_decrement(struct route_map
*map
)
3286 if (map
->use_count
<= 0)
3292 DEFUN_HIDDEN(show_route_map_pfx_tbl
, show_route_map_pfx_tbl_cmd
,
3293 "show route-map RMAP_NAME prefix-table",
3297 "internal prefix-table\n")
3299 const char *rmap_name
= argv
[2]->arg
;
3300 struct route_map
*rmap
= NULL
;
3301 struct route_table
*rm_pfx_tbl4
= NULL
;
3302 struct route_table
*rm_pfx_tbl6
= NULL
;
3303 struct route_node
*rn
= NULL
, *prn
= NULL
;
3304 struct list
*rmap_index_list
= NULL
;
3305 struct listnode
*ln
= NULL
, *nln
= NULL
;
3306 struct route_map_index
*index
= NULL
;
3309 vty_out(vty
, "%s:\n", frr_protonameinst
);
3310 rmap
= route_map_lookup_by_name(rmap_name
);
3312 rm_pfx_tbl4
= rmap
->ipv4_prefix_table
;
3314 vty_out(vty
, "\n%s%43s%s\n", "IPv4 Prefix", "",
3315 "Route-map Index List");
3316 vty_out(vty
, "%s%39s%s\n", "_______________", "",
3317 "____________________");
3318 for (rn
= route_top(rm_pfx_tbl4
); rn
;
3319 rn
= route_next(rn
)) {
3320 vty_out(vty
, " %pRN (%d)\n", rn
,
3321 route_node_get_lock_count(rn
));
3323 vty_out(vty
, "(P) ");
3326 vty_out(vty
, "%pRN\n", prn
);
3330 rmap_index_list
= (struct list
*)rn
->info
;
3331 if (!rmap_index_list
3332 || !listcount(rmap_index_list
))
3333 vty_out(vty
, "%*s%s\n", len
, "", "-");
3335 for (ALL_LIST_ELEMENTS(rmap_index_list
,
3338 vty_out(vty
, "%*s%s seq %d\n",
3347 rm_pfx_tbl6
= rmap
->ipv6_prefix_table
;
3349 vty_out(vty
, "\n%s%43s%s\n", "IPv6 Prefix", "",
3350 "Route-map Index List");
3351 vty_out(vty
, "%s%39s%s\n", "_______________", "",
3352 "____________________");
3353 for (rn
= route_top(rm_pfx_tbl6
); rn
;
3354 rn
= route_next(rn
)) {
3355 vty_out(vty
, " %pRN (%d)\n", rn
,
3356 route_node_get_lock_count(rn
));
3358 vty_out(vty
, "(P) ");
3361 vty_out(vty
, "%pRN\n", prn
);
3365 rmap_index_list
= (struct list
*)rn
->info
;
3366 if (!rmap_index_list
3367 || !listcount(rmap_index_list
))
3368 vty_out(vty
, "%*s%s\n", len
, "", "-");
3370 for (ALL_LIST_ELEMENTS(rmap_index_list
,
3373 vty_out(vty
, "%*s%s seq %d\n",
3387 /* Initialization of route map vector. */
3388 void route_map_init(void)
3392 route_map_master_hash
=
3393 hash_create_size(8, route_map_hash_key_make
, route_map_hash_cmp
,
3394 "Route Map Master Hash");
3396 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++)
3397 route_map_dep_hash
[i
] = hash_create_size(
3398 8, route_map_dep_hash_make_key
, route_map_dep_hash_cmp
,
3399 "Route Map Dep Hash");
3401 UNSET_FLAG(rmap_debug
, DEBUG_ROUTEMAP
);
3403 route_map_cli_init();
3405 /* Install route map top node. */
3406 install_node(&rmap_debug_node
);
3408 /* Install route map commands. */
3409 install_element(CONFIG_NODE
, &debug_rmap_cmd
);
3410 install_element(CONFIG_NODE
, &no_debug_rmap_cmd
);
3412 /* Install show command */
3413 install_element(ENABLE_NODE
, &rmap_clear_counters_cmd
);
3415 install_element(ENABLE_NODE
, &rmap_show_name_cmd
);
3416 install_element(ENABLE_NODE
, &rmap_show_unused_cmd
);
3418 install_element(ENABLE_NODE
, &debug_rmap_cmd
);
3419 install_element(ENABLE_NODE
, &no_debug_rmap_cmd
);
3421 install_element(ENABLE_NODE
, &show_route_map_pfx_tbl_cmd
);