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 /* Route-map optimization relies on LPM lookups of the prefix to reduce
1809 * the amount of route-map clauses a given prefix needs to be processed
1810 * against. These LPM trees are IPv4/IPv6-specific and prefix->family
1811 * must be AF_INET or AF_INET6 in order for the lookup to succeed. So if
1812 * the AF doesn't line up with the LPM trees, skip the optimization.
1814 if (map
->optimization_disabled
||
1815 (prefix
->family
== AF_INET
&& !map
->ipv4_prefix_table
) ||
1816 (prefix
->family
== AF_INET6
&& !map
->ipv6_prefix_table
)) {
1817 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP_DETAIL
))
1819 "Skipping route-map optimization for route-map: %s, pfx: %pFX, family: %d",
1820 map
->name
, prefix
, prefix
->family
);
1824 if (prefix
->family
== AF_INET
)
1825 table
= map
->ipv4_prefix_table
;
1827 table
= map
->ipv6_prefix_table
;
1833 candidate_rmap_list
=
1834 route_map_get_index_list(&rn
, prefix
, table
);
1838 /* If the index at the head of the list is of seq higher
1839 * than that in best_index, ignore the list and get the
1840 * parent node's list.
1842 head_index
= (struct route_map_index
*)(listgetdata(
1843 listhead(candidate_rmap_list
)));
1844 if (best_index
&& head_index
1845 && (best_index
->pref
< head_index
->pref
)) {
1846 route_unlock_node(rn
);
1850 for (ALL_LIST_ELEMENTS(candidate_rmap_list
, ln
, nn
, index
)) {
1851 /* If the index is of seq higher than that in
1852 * best_index, ignore the list and get the parent
1855 if (best_index
&& (best_index
->pref
< index
->pref
))
1858 ret
= route_map_apply_match(&index
->match_list
, prefix
,
1861 if (ret
== RMAP_MATCH
) {
1865 } else if (ret
== RMAP_NOOP
) {
1867 * If match_ret is denymatch, even if we see
1868 * more noops, we retain this return value and
1869 * return this eventually if there are no
1871 * If a best match route-map index already
1872 * exists, do not reset the match_ret.
1874 if (!best_index
&& (*match_ret
!= RMAP_NOMATCH
))
1878 * ret is RMAP_NOMATCH.
1879 * If a best match route-map index already
1880 * exists, do not reset the match_ret.
1887 route_unlock_node(rn
);
1894 static int route_map_candidate_list_cmp(struct route_map_index
*idx1
,
1895 struct route_map_index
*idx2
)
1897 return idx1
->pref
- idx2
->pref
;
1901 * This function adds the route-map index into the default route's
1902 * route-node in the route-map's IPv4/IPv6 prefix-table.
1904 static void route_map_pfx_table_add_default(afi_t afi
,
1905 struct route_map_index
*index
)
1907 struct route_node
*rn
= NULL
;
1908 struct list
*rmap_candidate_list
= NULL
;
1910 bool updated_rn
= false;
1911 struct route_table
*table
= NULL
;
1913 memset(&p
, 0, sizeof(p
));
1914 p
.family
= afi2family(afi
);
1917 if (p
.family
== AF_INET
) {
1918 table
= index
->map
->ipv4_prefix_table
;
1920 index
->map
->ipv4_prefix_table
= route_table_init();
1922 table
= index
->map
->ipv4_prefix_table
;
1924 table
= index
->map
->ipv6_prefix_table
;
1926 index
->map
->ipv6_prefix_table
= route_table_init();
1928 table
= index
->map
->ipv6_prefix_table
;
1931 /* Add default route to table */
1932 rn
= route_node_get(table
, &p
);
1938 rmap_candidate_list
= list_new();
1939 rmap_candidate_list
->cmp
=
1940 (int (*)(void *, void *))route_map_candidate_list_cmp
;
1941 rn
->info
= rmap_candidate_list
;
1943 rmap_candidate_list
= (struct list
*)rn
->info
;
1947 listnode_add_sort_nodup(rmap_candidate_list
, index
);
1949 route_unlock_node(rn
);
1953 * This function removes the route-map index from the default route's
1954 * route-node in the route-map's IPv4/IPv6 prefix-table.
1956 static void route_map_pfx_table_del_default(afi_t afi
,
1957 struct route_map_index
*index
)
1959 struct route_node
*rn
= NULL
;
1960 struct list
*rmap_candidate_list
= NULL
;
1962 struct route_table
*table
= NULL
;
1964 memset(&p
, 0, sizeof(p
));
1965 p
.family
= afi2family(afi
);
1968 if (p
.family
== AF_INET
)
1969 table
= index
->map
->ipv4_prefix_table
;
1971 table
= index
->map
->ipv6_prefix_table
;
1973 /* Remove RMAP index from default route in table */
1974 rn
= route_node_lookup(table
, &p
);
1975 if (!rn
|| !rn
->info
)
1978 rmap_candidate_list
= (struct list
*)rn
->info
;
1980 listnode_delete(rmap_candidate_list
, index
);
1982 if (listcount(rmap_candidate_list
) == 0) {
1983 list_delete(&rmap_candidate_list
);
1985 route_unlock_node(rn
);
1987 route_unlock_node(rn
);
1991 * This function adds the route-map index to the route-node for
1992 * the prefix-entry in the route-map's IPv4/IPv6 prefix-table.
1994 static void route_map_pfx_table_add(struct route_table
*table
,
1995 struct route_map_index
*index
,
1996 struct prefix_list_entry
*pentry
)
1998 struct route_node
*rn
= NULL
;
1999 struct list
*rmap_candidate_list
= NULL
;
2000 bool updated_rn
= false;
2002 rn
= route_node_get(table
, &pentry
->prefix
);
2007 rmap_candidate_list
= list_new();
2008 rmap_candidate_list
->cmp
=
2009 (int (*)(void *, void *))route_map_candidate_list_cmp
;
2010 rn
->info
= rmap_candidate_list
;
2012 rmap_candidate_list
= (struct list
*)rn
->info
;
2016 listnode_add_sort_nodup(rmap_candidate_list
, index
);
2018 route_unlock_node(rn
);
2022 * This function removes the route-map index from the route-node for
2023 * the prefix-entry in the route-map's IPv4/IPv6 prefix-table.
2025 static void route_map_pfx_table_del(struct route_table
*table
,
2026 struct route_map_index
*index
,
2027 struct prefix_list_entry
*pentry
)
2029 struct route_node
*rn
= NULL
;
2030 struct list
*rmap_candidate_list
= NULL
;
2032 rn
= route_node_lookup(table
, &pentry
->prefix
);
2033 if (!rn
|| !rn
->info
)
2036 rmap_candidate_list
= (struct list
*)rn
->info
;
2038 listnode_delete(rmap_candidate_list
, index
);
2040 if (listcount(rmap_candidate_list
) == 0) {
2041 list_delete(&rmap_candidate_list
);
2043 route_unlock_node(rn
);
2045 route_unlock_node(rn
);
2048 /* This function checks for the presence of an IPv4 prefix-list
2049 * match rule in the given route-map index.
2051 static bool route_map_is_ip_pfx_list_rule_present(struct route_map_index
*index
)
2053 struct route_map_rule_list
*match_list
= NULL
;
2054 struct route_map_rule
*rule
= NULL
;
2056 match_list
= &index
->match_list
;
2057 for (rule
= match_list
->head
; rule
; rule
= rule
->next
)
2058 if (IS_RULE_IPv4_PREFIX_LIST(rule
->cmd
->str
))
2064 /* This function checks for the presence of an IPv6 prefix-list
2065 * match rule in the given route-map index.
2068 route_map_is_ipv6_pfx_list_rule_present(struct route_map_index
*index
)
2070 struct route_map_rule_list
*match_list
= NULL
;
2071 struct route_map_rule
*rule
= NULL
;
2073 match_list
= &index
->match_list
;
2074 for (rule
= match_list
->head
; rule
; rule
= rule
->next
)
2075 if (IS_RULE_IPv6_PREFIX_LIST(rule
->cmd
->str
))
2081 /* This function does the following:
2082 * 1) If plist_name is not present, search for a IPv4 or IPv6 prefix-list
2083 * match clause (based on the afi passed to this foo) and get the
2085 * 2) Look up the prefix-list using the name.
2086 * 3) If the prefix-list is not found then, add the index to the IPv4/IPv6
2087 * default-route's node in the trie (based on the afi passed to this foo).
2088 * 4) If the prefix-list is found then, remove the index from the IPv4/IPv6
2089 * default-route's node in the trie (based on the afi passed to this foo).
2090 * 5) If a prefix-entry is passed then, create a route-node for this entry and
2091 * add this index to the route-node.
2092 * 6) If prefix-entry is not passed then, for every prefix-entry in the
2093 * prefix-list, create a route-node for this entry and
2094 * add this index to the route-node.
2096 static void route_map_add_plist_entries(afi_t afi
,
2097 struct route_map_index
*index
,
2098 const char *plist_name
,
2099 struct prefix_list_entry
*entry
)
2101 struct route_map_rule_list
*match_list
= NULL
;
2102 struct route_map_rule
*match
= NULL
;
2103 struct prefix_list
*plist
= NULL
;
2104 struct prefix_list_entry
*pentry
= NULL
;
2105 bool plist_rule_is_present
= false;
2108 match_list
= &index
->match_list
;
2110 for (match
= match_list
->head
; match
; match
= match
->next
) {
2111 if (afi
== AFI_IP
) {
2112 if (IS_RULE_IPv4_PREFIX_LIST(match
->cmd
->str
)) {
2113 plist_rule_is_present
= true;
2117 if (IS_RULE_IPv6_PREFIX_LIST(match
->cmd
->str
)) {
2118 plist_rule_is_present
= true;
2124 if (plist_rule_is_present
)
2125 plist
= prefix_list_lookup(afi
, match
->rule_str
);
2127 plist
= prefix_list_lookup(afi
, plist_name
);
2131 route_map_pfx_table_add_default(afi
, index
);
2135 /* Default entry should be deleted only if the first entry of the
2136 * prefix-list is created.
2139 if (plist
->count
== 1)
2140 route_map_pfx_table_del_default(afi
, index
);
2142 route_map_pfx_table_del_default(afi
, index
);
2146 if (afi
== AFI_IP
) {
2147 route_map_pfx_table_add(index
->map
->ipv4_prefix_table
,
2150 route_map_pfx_table_add(index
->map
->ipv6_prefix_table
,
2154 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
2155 if (afi
== AFI_IP
) {
2156 route_map_pfx_table_add(
2157 index
->map
->ipv4_prefix_table
, index
,
2160 route_map_pfx_table_add(
2161 index
->map
->ipv6_prefix_table
, index
,
2168 /* This function does the following:
2169 * 1) If plist_name is not present, search for a IPv4 or IPv6 prefix-list
2170 * match clause (based on the afi passed to this foo) and get the
2172 * 2) Look up the prefix-list using the name.
2173 * 3) If the prefix-list is not found then, delete the index from the IPv4/IPv6
2174 * default-route's node in the trie (based on the afi passed to this foo).
2175 * 4) If a prefix-entry is passed then, remove this index from the route-node
2176 * for the prefix in this prefix-entry.
2177 * 5) If prefix-entry is not passed then, for every prefix-entry in the
2178 * prefix-list, remove this index from the route-node
2179 * for the prefix in this prefix-entry.
2181 static void route_map_del_plist_entries(afi_t afi
,
2182 struct route_map_index
*index
,
2183 const char *plist_name
,
2184 struct prefix_list_entry
*entry
)
2186 struct route_map_rule_list
*match_list
= NULL
;
2187 struct route_map_rule
*match
= NULL
;
2188 struct prefix_list
*plist
= NULL
;
2189 struct prefix_list_entry
*pentry
= NULL
;
2190 bool plist_rule_is_present
= false;
2193 match_list
= &index
->match_list
;
2195 for (match
= match_list
->head
; match
; match
= match
->next
) {
2196 if (afi
== AFI_IP
) {
2197 if (IS_RULE_IPv4_PREFIX_LIST(match
->cmd
->str
)) {
2198 plist_rule_is_present
= true;
2202 if (IS_RULE_IPv6_PREFIX_LIST(match
->cmd
->str
)) {
2203 plist_rule_is_present
= true;
2209 if (plist_rule_is_present
)
2210 plist
= prefix_list_lookup(afi
, match
->rule_str
);
2212 plist
= prefix_list_lookup(afi
, plist_name
);
2216 route_map_pfx_table_del_default(afi
, index
);
2221 if (afi
== AFI_IP
) {
2222 route_map_pfx_table_del(index
->map
->ipv4_prefix_table
,
2225 route_map_pfx_table_del(index
->map
->ipv6_prefix_table
,
2229 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
2230 if (afi
== AFI_IP
) {
2231 route_map_pfx_table_del(
2232 index
->map
->ipv4_prefix_table
, index
,
2235 route_map_pfx_table_del(
2236 index
->map
->ipv6_prefix_table
, index
,
2244 * This function handles the cases where a prefix-list is added/removed
2245 * as a match command from a particular route-map index.
2246 * It updates the prefix-table of the route-map accordingly.
2248 static void route_map_trie_update(afi_t afi
, route_map_event_t event
,
2249 struct route_map_index
*index
,
2250 const char *plist_name
)
2252 if (event
== RMAP_EVENT_PLIST_ADDED
) {
2253 if (afi
== AFI_IP
) {
2254 if (!route_map_is_ipv6_pfx_list_rule_present(index
)) {
2255 route_map_pfx_table_del_default(AFI_IP6
, index
);
2256 route_map_add_plist_entries(afi
, index
,
2259 route_map_del_plist_entries(AFI_IP6
, index
,
2263 if (!route_map_is_ip_pfx_list_rule_present(index
)) {
2264 route_map_pfx_table_del_default(AFI_IP
, index
);
2265 route_map_add_plist_entries(afi
, index
,
2268 route_map_del_plist_entries(AFI_IP
, index
, NULL
,
2272 } else if (event
== RMAP_EVENT_PLIST_DELETED
) {
2273 if (afi
== AFI_IP
) {
2274 route_map_del_plist_entries(afi
, index
, plist_name
,
2277 /* If IPv6 prefix-list match rule is not present,
2278 * add this index to the IPv4 default route's trie
2280 * Also, add this index to the trie nodes created
2281 * for each of the prefix-entries within the IPv6
2282 * prefix-list, if the IPv6 prefix-list match rule
2283 * is present. Else, add this index to the IPv6
2284 * default route's trie node.
2286 if (!route_map_is_ipv6_pfx_list_rule_present(index
))
2287 route_map_pfx_table_add_default(afi
, index
);
2289 route_map_add_plist_entries(AFI_IP6
, index
, NULL
, NULL
);
2291 route_map_del_plist_entries(afi
, index
, plist_name
,
2294 /* If IPv4 prefix-list match rule is not present,
2295 * add this index to the IPv6 default route's trie
2297 * Also, add this index to the trie nodes created
2298 * for each of the prefix-entries within the IPv4
2299 * prefix-list, if the IPv4 prefix-list match rule
2300 * is present. Else, add this index to the IPv4
2301 * default route's trie node.
2303 if (!route_map_is_ip_pfx_list_rule_present(index
))
2304 route_map_pfx_table_add_default(afi
, index
);
2306 route_map_add_plist_entries(AFI_IP
, index
, NULL
, NULL
);
2312 * This function handles the cases where a route-map index and
2313 * prefix-list is added/removed.
2314 * It updates the prefix-table of the route-map accordingly.
2316 static void route_map_pfx_tbl_update(route_map_event_t event
,
2317 struct route_map_index
*index
, afi_t afi
,
2318 const char *plist_name
)
2320 struct route_map
*rmap
= NULL
;
2325 if (event
== RMAP_EVENT_INDEX_ADDED
) {
2326 route_map_pfx_table_add_default(AFI_IP
, index
);
2327 route_map_pfx_table_add_default(AFI_IP6
, index
);
2331 if (event
== RMAP_EVENT_INDEX_DELETED
) {
2332 route_map_pfx_table_del_default(AFI_IP
, index
);
2333 route_map_pfx_table_del_default(AFI_IP6
, index
);
2335 if ((index
->map
->head
== NULL
) && (index
->map
->tail
== NULL
)) {
2338 if (rmap
->ipv4_prefix_table
) {
2339 route_table_finish(rmap
->ipv4_prefix_table
);
2340 rmap
->ipv4_prefix_table
= NULL
;
2343 if (rmap
->ipv6_prefix_table
) {
2344 route_table_finish(rmap
->ipv6_prefix_table
);
2345 rmap
->ipv6_prefix_table
= NULL
;
2351 /* Handle prefix-list match rule addition/deletion.
2353 route_map_trie_update(afi
, event
, index
, plist_name
);
2357 * This function handles the cases where a new prefix-entry is added to
2358 * a prefix-list or, an existing prefix-entry is removed from the prefix-list.
2359 * It updates the prefix-table of the route-map accordingly.
2361 static void route_map_pentry_update(route_map_event_t event
,
2362 const char *plist_name
,
2363 struct route_map_index
*index
,
2364 struct prefix_list_entry
*pentry
)
2366 struct prefix_list
*plist
= NULL
;
2368 unsigned char family
= pentry
->prefix
.family
;
2370 if (family
== AF_INET
) {
2372 plist
= prefix_list_lookup(AFI_IP
, plist_name
);
2375 plist
= prefix_list_lookup(AFI_IP6
, plist_name
);
2378 if (event
== RMAP_EVENT_PLIST_ADDED
) {
2379 if (afi
== AFI_IP
) {
2380 if (!route_map_is_ipv6_pfx_list_rule_present(index
))
2381 route_map_add_plist_entries(afi
, index
,
2382 plist_name
, pentry
);
2384 if (!route_map_is_ip_pfx_list_rule_present(index
))
2385 route_map_add_plist_entries(afi
, index
,
2386 plist_name
, pentry
);
2388 } else if (event
== RMAP_EVENT_PLIST_DELETED
) {
2389 route_map_del_plist_entries(afi
, index
, plist_name
, pentry
);
2391 if (plist
->count
== 1) {
2392 if (afi
== AFI_IP
) {
2393 if (!route_map_is_ipv6_pfx_list_rule_present(
2395 route_map_pfx_table_add_default(afi
,
2398 if (!route_map_is_ip_pfx_list_rule_present(
2400 route_map_pfx_table_add_default(afi
,
2407 static void route_map_pentry_process_dependency(struct hash_bucket
*bucket
,
2410 char *rmap_name
= NULL
;
2411 struct route_map
*rmap
= NULL
;
2412 struct route_map_index
*index
= NULL
;
2413 struct route_map_rule_list
*match_list
= NULL
;
2414 struct route_map_rule
*match
= NULL
;
2415 struct route_map_dep_data
*dep_data
= NULL
;
2416 struct route_map_pentry_dep
*pentry_dep
=
2417 (struct route_map_pentry_dep
*)data
;
2418 unsigned char family
= pentry_dep
->pentry
->prefix
.family
;
2420 dep_data
= (struct route_map_dep_data
*)bucket
->data
;
2424 rmap_name
= dep_data
->rname
;
2425 rmap
= route_map_lookup_by_name(rmap_name
);
2426 if (!rmap
|| !rmap
->head
)
2429 for (index
= rmap
->head
; index
; index
= index
->next
) {
2430 match_list
= &index
->match_list
;
2435 for (match
= match_list
->head
; match
; match
= match
->next
) {
2436 if (strcmp(match
->rule_str
, pentry_dep
->plist_name
)
2438 if (IS_RULE_IPv4_PREFIX_LIST(match
->cmd
->str
)
2439 && family
== AF_INET
) {
2440 route_map_pentry_update(
2442 pentry_dep
->plist_name
, index
,
2443 pentry_dep
->pentry
);
2444 } else if (IS_RULE_IPv6_PREFIX_LIST(
2446 && family
== AF_INET6
) {
2447 route_map_pentry_update(
2449 pentry_dep
->plist_name
, index
,
2450 pentry_dep
->pentry
);
2457 void route_map_notify_pentry_dependencies(const char *affected_name
,
2458 struct prefix_list_entry
*pentry
,
2459 route_map_event_t event
)
2461 struct route_map_dep
*dep
= NULL
;
2462 struct hash
*upd8_hash
= NULL
;
2463 struct route_map_pentry_dep pentry_dep
;
2465 if (!affected_name
|| !pentry
)
2468 upd8_hash
= route_map_get_dep_hash(event
);
2472 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, (void *)affected_name
,
2475 if (!dep
->this_hash
)
2476 dep
->this_hash
= upd8_hash
;
2478 memset(&pentry_dep
, 0, sizeof(pentry_dep
));
2479 pentry_dep
.pentry
= pentry
;
2480 pentry_dep
.plist_name
= affected_name
;
2481 pentry_dep
.event
= event
;
2483 hash_iterate(dep
->dep_rmap_hash
,
2484 route_map_pentry_process_dependency
,
2485 (void *)&pentry_dep
);
2489 /* Apply route map's each index to the object.
2491 The matrix for a route-map looks like this:
2492 (note, this includes the description for the "NEXT"
2493 and "GOTO" frobs now
2495 | Match | No Match | No op
2496 |-----------|--------------|-------
2497 permit | action | cont | cont.
2498 | | default:deny | default:permit
2499 -------------------+-----------------------
2500 | deny | cont | cont.
2501 deny | | default:deny | default:permit
2502 |-----------|--------------|--------
2505 -Apply Set statements, accept route
2506 -If Call statement is present jump to the specified route-map, if it
2507 denies the route we finish.
2508 -If NEXT is specified, goto NEXT statement
2509 -If GOTO is specified, goto the first clause where pref > nextpref
2510 -If nothing is specified, do as Cisco and finish
2512 -Route is denied by route-map.
2516 If we get no matches after we've processed all updates, then the route
2519 Some notes on the new "CALL", "NEXT" and "GOTO"
2520 call WORD - If this clause is matched, then the set statements
2521 are executed and then we jump to route-map 'WORD'. If
2522 this route-map denies the route, we finish, in other
2524 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
2525 on-match next - If this clause is matched, then the set statements
2526 are executed and then we drop through to the next clause
2527 on-match goto n - If this clause is matched, then the set statements
2528 are executed and then we goto the nth clause, or the
2529 first clause greater than this. In order to ensure
2530 route-maps *always* exit, you cannot jump backwards.
2533 We need to make sure our route-map processing matches the above
2535 route_map_result_t
route_map_apply_ext(struct route_map
*map
,
2536 const struct prefix
*prefix
,
2537 void *match_object
, void *set_object
,
2540 static int recursion
= 0;
2541 enum route_map_cmd_result_t match_ret
= RMAP_NOMATCH
;
2542 route_map_result_t ret
= RMAP_PERMITMATCH
;
2543 struct route_map_index
*index
= NULL
;
2544 struct route_map_rule
*set
= NULL
;
2545 bool skip_match_clause
= false;
2548 if (recursion
> RMAP_RECURSION_LIMIT
) {
2550 EC_LIB_RMAP_RECURSION_LIMIT
,
2551 "route-map recursion limit (%d) reached, discarding route",
2552 RMAP_RECURSION_LIMIT
);
2554 return RMAP_DENYMATCH
;
2557 if (map
== NULL
|| map
->head
== NULL
) {
2558 ret
= RMAP_DENYMATCH
;
2559 goto route_map_apply_end
;
2565 * Handling for matching evpn_routes in the prefix table.
2567 * We convert type2/5 prefix to ipv4/6 prefix to do longest
2568 * prefix matching on.
2570 if (prefix
->family
== AF_EVPN
) {
2571 if (evpn_prefix2prefix(prefix
, &conv
) != 0) {
2573 "Unable to convert EVPN prefix %pFX into IPv4/IPv6 prefix. Falling back to non-optimized route-map lookup",
2577 "Converted EVPN prefix %pFX into %pFX for optimized route-map lookup",
2584 index
= route_map_get_index(map
, prefix
, match_object
, &match_ret
);
2587 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
2589 "Best match route-map: %s, sequence: %d for pfx: %pFX, result: %s",
2590 map
->name
, index
->pref
, prefix
,
2591 route_map_cmd_result_str(match_ret
));
2593 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
2595 "No best match sequence for pfx: %pFX in route-map: %s, result: %s",
2597 route_map_cmd_result_str(match_ret
));
2599 * No index matches this prefix. Return deny unless,
2600 * match_ret = RMAP_NOOP.
2602 if (match_ret
== RMAP_NOOP
)
2603 ret
= RMAP_PERMITMATCH
;
2605 ret
= RMAP_DENYMATCH
;
2606 goto route_map_apply_end
;
2608 skip_match_clause
= true;
2610 for (; index
; index
= index
->next
) {
2611 if (!skip_match_clause
) {
2613 /* Apply this index. */
2614 match_ret
= route_map_apply_match(&index
->match_list
,
2615 prefix
, match_object
);
2616 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
)) {
2618 "Route-map: %s, sequence: %d, prefix: %pFX, result: %s",
2619 map
->name
, index
->pref
, prefix
,
2620 route_map_cmd_result_str(match_ret
));
2623 skip_match_clause
= false;
2626 /* Now we apply the matrix from above */
2627 if (match_ret
== RMAP_NOOP
)
2629 * Do not change the return value. Retain the previous
2630 * return value. Previous values can be:
2631 * 1)permitmatch (if a nomatch was never
2632 * seen before in this route-map.)
2633 * 2)denymatch (if a nomatch was seen earlier in one
2634 * of the previous sequences)
2638 * 'cont' from matrix - continue to next route-map
2642 else if (match_ret
== RMAP_NOMATCH
) {
2645 * The return value is now changed to denymatch.
2646 * So from here on out, even if we see more noops,
2647 * we retain this return value and return this
2648 * eventually if there are no matches.
2650 ret
= RMAP_DENYMATCH
;
2653 * 'cont' from matrix - continue to next route-map
2657 } else if (match_ret
== RMAP_MATCH
) {
2658 if (index
->type
== RMAP_PERMIT
)
2661 /* Match succeeded, rmap is of type permit */
2662 ret
= RMAP_PERMITMATCH
;
2664 /* permit+match must execute sets */
2665 for (set
= index
->set_list
.head
; set
;
2668 * set cmds return RMAP_OKAY or
2669 * RMAP_ERROR. We do not care if
2670 * set succeeded or not. So, ignore
2673 (void)(*set
->cmd
->func_apply
)(
2674 set
->value
, prefix
, set_object
);
2676 /* Call another route-map if available */
2677 if (index
->nextrm
) {
2678 struct route_map
*nextrm
=
2679 route_map_lookup_by_name(
2682 if (nextrm
) /* Target route-map found,
2686 ret
= route_map_apply_ext(
2693 /* If nextrm returned 'deny', finish. */
2694 if (ret
== RMAP_DENYMATCH
)
2695 goto route_map_apply_end
;
2698 switch (index
->exitpolicy
) {
2700 goto route_map_apply_end
;
2704 /* Find the next clause to jump to */
2705 struct route_map_index
*next
=
2707 int nextpref
= index
->nextpref
;
2709 while (next
&& next
->pref
< nextpref
) {
2714 /* No clauses match! */
2715 goto route_map_apply_end
;
2719 } else if (index
->type
== RMAP_DENY
)
2722 ret
= RMAP_DENYMATCH
;
2723 goto route_map_apply_end
;
2728 route_map_apply_end
:
2729 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
2730 zlog_debug("Route-map: %s, prefix: %pFX, result: %s",
2731 (map
? map
->name
: "null"), prefix
,
2732 route_map_result_str(ret
));
2735 if (index
!= NULL
&& ret
== RMAP_PERMITMATCH
)
2736 *pref
= index
->pref
;
2744 void route_map_add_hook(void (*func
)(const char *))
2746 route_map_master
.add_hook
= func
;
2749 void route_map_delete_hook(void (*func
)(const char *))
2751 route_map_master
.delete_hook
= func
;
2754 void route_map_event_hook(void (*func
)(const char *name
))
2756 route_map_master
.event_hook
= func
;
2759 /* Routines for route map dependency lists and dependency processing */
2760 static bool route_map_rmap_hash_cmp(const void *p1
, const void *p2
)
2762 return strcmp(((const struct route_map_dep_data
*)p1
)->rname
,
2763 ((const struct route_map_dep_data
*)p2
)->rname
)
2767 static bool route_map_dep_hash_cmp(const void *p1
, const void *p2
)
2770 return (strcmp(((const struct route_map_dep
*)p1
)->dep_name
,
2775 static void route_map_clear_reference(struct hash_bucket
*bucket
, void *arg
)
2777 struct route_map_dep
*dep
= bucket
->data
;
2778 struct route_map_dep_data
*dep_data
= NULL
, tmp_dep_data
;
2780 memset(&tmp_dep_data
, 0, sizeof(tmp_dep_data
));
2781 tmp_dep_data
.rname
= arg
;
2782 dep_data
= hash_release(dep
->dep_rmap_hash
, &tmp_dep_data
);
2784 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
2785 zlog_debug("Clearing reference for %s to %s count: %d",
2786 dep
->dep_name
, tmp_dep_data
.rname
,
2789 XFREE(MTYPE_ROUTE_MAP_NAME
, dep_data
->rname
);
2790 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, dep_data
);
2792 if (!dep
->dep_rmap_hash
->count
) {
2793 dep
= hash_release(dep
->this_hash
, (void *)dep
->dep_name
);
2794 hash_free(dep
->dep_rmap_hash
);
2795 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
2796 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
2800 static void route_map_clear_all_references(char *rmap_name
)
2804 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
2805 zlog_debug("Clearing references for %s", rmap_name
);
2807 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
2808 hash_iterate(route_map_dep_hash
[i
], route_map_clear_reference
,
2813 static unsigned int route_map_dep_data_hash_make_key(const void *p
)
2815 const struct route_map_dep_data
*dep_data
= p
;
2817 return string_hash_make(dep_data
->rname
);
2820 static void *route_map_dep_hash_alloc(void *p
)
2822 char *dep_name
= (char *)p
;
2823 struct route_map_dep
*dep_entry
;
2825 dep_entry
= XCALLOC(MTYPE_ROUTE_MAP_DEP
, sizeof(struct route_map_dep
));
2826 dep_entry
->dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
2827 dep_entry
->dep_rmap_hash
=
2828 hash_create_size(8, route_map_dep_data_hash_make_key
,
2829 route_map_rmap_hash_cmp
, "Route Map Dep Hash");
2830 dep_entry
->this_hash
= NULL
;
2835 static void *route_map_name_hash_alloc(void *p
)
2837 struct route_map_dep_data
*dep_data
= NULL
, *tmp_dep_data
= NULL
;
2839 dep_data
= XCALLOC(MTYPE_ROUTE_MAP_DEP_DATA
,
2840 sizeof(struct route_map_dep_data
));
2842 dep_data
->rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, tmp_dep_data
->rname
);
2846 static unsigned int route_map_dep_hash_make_key(const void *p
)
2848 return (string_hash_make((char *)p
));
2851 static void route_map_print_dependency(struct hash_bucket
*bucket
, void *data
)
2853 struct route_map_dep_data
*dep_data
= bucket
->data
;
2854 char *rmap_name
= dep_data
->rname
;
2855 char *dep_name
= data
;
2857 zlog_debug("%s: Dependency for %s: %s", __func__
, dep_name
, rmap_name
);
2860 static int route_map_dep_update(struct hash
*dephash
, const char *dep_name
,
2861 const char *rmap_name
, route_map_event_t type
)
2863 struct route_map_dep
*dep
= NULL
;
2864 char *dname
, *rname
;
2866 struct route_map_dep_data
*dep_data
= NULL
, *ret_dep_data
= NULL
;
2867 struct route_map_dep_data tmp_dep_data
;
2869 dname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
2870 rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
2873 case RMAP_EVENT_PLIST_ADDED
:
2874 case RMAP_EVENT_CLIST_ADDED
:
2875 case RMAP_EVENT_ECLIST_ADDED
:
2876 case RMAP_EVENT_ASLIST_ADDED
:
2877 case RMAP_EVENT_LLIST_ADDED
:
2878 case RMAP_EVENT_CALL_ADDED
:
2879 case RMAP_EVENT_FILTER_ADDED
:
2880 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
2881 zlog_debug("Adding dependency for filter %s in route-map %s",
2882 dep_name
, rmap_name
);
2883 dep
= (struct route_map_dep
*)hash_get(
2884 dephash
, dname
, route_map_dep_hash_alloc
);
2890 if (!dep
->this_hash
)
2891 dep
->this_hash
= dephash
;
2893 memset(&tmp_dep_data
, 0, sizeof(tmp_dep_data
));
2894 tmp_dep_data
.rname
= rname
;
2895 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
2897 dep_data
= hash_get(dep
->dep_rmap_hash
, &tmp_dep_data
,
2898 route_map_name_hash_alloc
);
2902 case RMAP_EVENT_PLIST_DELETED
:
2903 case RMAP_EVENT_CLIST_DELETED
:
2904 case RMAP_EVENT_ECLIST_DELETED
:
2905 case RMAP_EVENT_ASLIST_DELETED
:
2906 case RMAP_EVENT_LLIST_DELETED
:
2907 case RMAP_EVENT_CALL_DELETED
:
2908 case RMAP_EVENT_FILTER_DELETED
:
2909 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
2910 zlog_debug("Deleting dependency for filter %s in route-map %s",
2911 dep_name
, rmap_name
);
2912 dep
= (struct route_map_dep
*)hash_get(dephash
, dname
, NULL
);
2917 memset(&tmp_dep_data
, 0, sizeof(tmp_dep_data
));
2918 tmp_dep_data
.rname
= rname
;
2919 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
2921 * If dep_data is NULL then something has gone seriously
2922 * wrong in route-map handling. Note it and prevent
2927 "route-map dependency for route-map %s: %s is not correct",
2928 rmap_name
, dep_name
);
2934 if (!dep_data
->refcnt
) {
2935 ret_dep_data
= hash_release(dep
->dep_rmap_hash
,
2938 XFREE(MTYPE_ROUTE_MAP_NAME
,
2939 ret_dep_data
->rname
);
2940 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, ret_dep_data
);
2944 if (!dep
->dep_rmap_hash
->count
) {
2945 dep
= hash_release(dephash
, dname
);
2946 hash_free(dep
->dep_rmap_hash
);
2947 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
2948 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
2951 case RMAP_EVENT_SET_ADDED
:
2952 case RMAP_EVENT_SET_DELETED
:
2953 case RMAP_EVENT_SET_REPLACED
:
2954 case RMAP_EVENT_MATCH_ADDED
:
2955 case RMAP_EVENT_MATCH_DELETED
:
2956 case RMAP_EVENT_MATCH_REPLACED
:
2957 case RMAP_EVENT_INDEX_ADDED
:
2958 case RMAP_EVENT_INDEX_DELETED
:
2963 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
2964 hash_iterate(dep
->dep_rmap_hash
,
2965 route_map_print_dependency
, dname
);
2969 XFREE(MTYPE_ROUTE_MAP_NAME
, rname
);
2970 XFREE(MTYPE_ROUTE_MAP_NAME
, dname
);
2974 static struct hash
*route_map_get_dep_hash(route_map_event_t event
)
2976 struct hash
*upd8_hash
= NULL
;
2979 case RMAP_EVENT_PLIST_ADDED
:
2980 case RMAP_EVENT_PLIST_DELETED
:
2981 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_PLIST
];
2983 case RMAP_EVENT_CLIST_ADDED
:
2984 case RMAP_EVENT_CLIST_DELETED
:
2985 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_CLIST
];
2987 case RMAP_EVENT_ECLIST_ADDED
:
2988 case RMAP_EVENT_ECLIST_DELETED
:
2989 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ECLIST
];
2991 case RMAP_EVENT_ASLIST_ADDED
:
2992 case RMAP_EVENT_ASLIST_DELETED
:
2993 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ASPATH
];
2995 case RMAP_EVENT_LLIST_ADDED
:
2996 case RMAP_EVENT_LLIST_DELETED
:
2997 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_LCLIST
];
2999 case RMAP_EVENT_CALL_ADDED
:
3000 case RMAP_EVENT_CALL_DELETED
:
3001 case RMAP_EVENT_MATCH_ADDED
:
3002 case RMAP_EVENT_MATCH_DELETED
:
3003 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_RMAP
];
3005 case RMAP_EVENT_FILTER_ADDED
:
3006 case RMAP_EVENT_FILTER_DELETED
:
3007 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_FILTER
];
3010 * Should we actually be ignoring these?
3011 * I am not sure but at this point in time, let
3012 * us get them into this switch and we can peel
3013 * them into the appropriate place in the future
3015 case RMAP_EVENT_SET_ADDED
:
3016 case RMAP_EVENT_SET_DELETED
:
3017 case RMAP_EVENT_SET_REPLACED
:
3018 case RMAP_EVENT_MATCH_REPLACED
:
3019 case RMAP_EVENT_INDEX_ADDED
:
3020 case RMAP_EVENT_INDEX_DELETED
:
3027 static void route_map_process_dependency(struct hash_bucket
*bucket
, void *data
)
3029 struct route_map_dep_data
*dep_data
= NULL
;
3030 char *rmap_name
= NULL
;
3032 dep_data
= bucket
->data
;
3033 rmap_name
= dep_data
->rname
;
3035 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
3036 zlog_debug("Notifying %s of dependency", rmap_name
);
3037 if (route_map_master
.event_hook
)
3038 (*route_map_master
.event_hook
)(rmap_name
);
3041 void route_map_upd8_dependency(route_map_event_t type
, const char *arg
,
3042 const char *rmap_name
)
3044 struct hash
*upd8_hash
= NULL
;
3046 if ((upd8_hash
= route_map_get_dep_hash(type
))) {
3047 route_map_dep_update(upd8_hash
, arg
, rmap_name
, type
);
3049 if (type
== RMAP_EVENT_CALL_ADDED
) {
3051 if (route_map_master
.add_hook
)
3052 (*route_map_master
.add_hook
)(rmap_name
);
3053 } else if (type
== RMAP_EVENT_CALL_DELETED
) {
3055 if (route_map_master
.delete_hook
)
3056 (*route_map_master
.delete_hook
)(rmap_name
);
3061 void route_map_notify_dependencies(const char *affected_name
,
3062 route_map_event_t event
)
3064 struct route_map_dep
*dep
;
3065 struct hash
*upd8_hash
;
3071 name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, affected_name
);
3073 if ((upd8_hash
= route_map_get_dep_hash(event
)) == NULL
) {
3074 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
3078 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, name
, NULL
);
3080 if (!dep
->this_hash
)
3081 dep
->this_hash
= upd8_hash
;
3083 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
3084 zlog_debug("Filter %s updated", dep
->dep_name
);
3085 hash_iterate(dep
->dep_rmap_hash
, route_map_process_dependency
,
3089 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
3092 /* VTY related functions. */
3093 static void clear_route_map_helper(struct route_map
*map
)
3095 struct route_map_index
*index
;
3097 map
->applied_clear
= map
->applied
;
3098 for (index
= map
->head
; index
; index
= index
->next
)
3099 index
->applied_clear
= index
->applied
;
3102 DEFUN (rmap_clear_counters
,
3103 rmap_clear_counters_cmd
,
3104 "clear route-map counters [WORD]",
3106 "route-map information\n"
3107 "counters associated with the specified route-map\n"
3111 struct route_map
*map
;
3113 const char *name
= (argc
== 3 ) ? argv
[idx_word
]->arg
: NULL
;
3116 map
= route_map_lookup_by_name(name
);
3119 clear_route_map_helper(map
);
3121 vty_out(vty
, "%s: 'route-map %s' not found\n",
3122 frr_protonameinst
, name
);
3126 for (map
= route_map_master
.head
; map
; map
= map
->next
)
3127 clear_route_map_helper(map
);
3134 DEFUN (rmap_show_name
,
3136 "show route-map [WORD] [json]",
3138 "route-map information\n"
3142 bool uj
= use_json(argc
, argv
);
3144 const char *name
= NULL
;
3146 if (argv_find(argv
, argc
, "WORD", &idx
))
3147 name
= argv
[idx
]->arg
;
3149 return vty_show_route_map(vty
, name
, uj
);
3152 DEFUN (rmap_show_unused
,
3153 rmap_show_unused_cmd
,
3154 "show route-map-unused",
3156 "unused route-map information\n")
3158 return vty_show_unused_route_map(vty
);
3163 "debug route-map [detail]$detail",
3165 "Debug option set for route-maps\n"
3166 "Detailed output\n")
3169 SET_FLAG(rmap_debug
, DEBUG_ROUTEMAP
);
3171 SET_FLAG(rmap_debug
, DEBUG_ROUTEMAP
| DEBUG_ROUTEMAP_DETAIL
);
3176 DEFPY (no_debug_rmap
,
3178 "no debug route-map [detail]$detail",
3181 "Debug option set for route-maps\n"
3182 "Detailed output\n")
3185 UNSET_FLAG(rmap_debug
, DEBUG_ROUTEMAP
);
3187 UNSET_FLAG(rmap_debug
, DEBUG_ROUTEMAP
| DEBUG_ROUTEMAP_DETAIL
);
3193 static int rmap_config_write_debug(struct vty
*vty
);
3194 static struct cmd_node rmap_debug_node
= {
3195 .name
= "route-map debug",
3196 .node
= RMAP_DEBUG_NODE
,
3198 .config_write
= rmap_config_write_debug
,
3201 void route_map_show_debug(struct vty
*vty
)
3203 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
3204 vty_out(vty
, "debug route-map\n");
3207 /* Configuration write function. */
3208 static int rmap_config_write_debug(struct vty
*vty
)
3212 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
)) {
3213 vty_out(vty
, "debug route-map\n");
3220 /* Common route map rules */
3222 void *route_map_rule_tag_compile(const char *arg
)
3224 unsigned long int tmp
;
3229 tmp
= strtoul(arg
, &endptr
, 0);
3230 if (arg
[0] == '\0' || *endptr
!= '\0' || errno
|| tmp
> ROUTE_TAG_MAX
)
3233 tag
= XMALLOC(MTYPE_ROUTE_MAP_COMPILED
, sizeof(*tag
));
3239 void route_map_rule_tag_free(void *rule
)
3241 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
3244 void route_map_finish(void)
3247 struct route_map_rule_cmd_proxy
*proxy
;
3249 /* these 2 hash tables have INIT_HASH initializers, so the "default"
3250 * state is "initialized & empty" => fini() followed by init() to
3251 * return to that same state
3253 while ((proxy
= rmap_cmd_name_pop(rmap_match_cmds
)))
3255 rmap_cmd_name_fini(rmap_match_cmds
);
3256 rmap_cmd_name_init(rmap_match_cmds
);
3258 while ((proxy
= rmap_cmd_name_pop(rmap_set_cmds
)))
3260 rmap_cmd_name_fini(rmap_set_cmds
);
3261 rmap_cmd_name_init(rmap_set_cmds
);
3264 * All protocols are setting these to NULL
3265 * by default on shutdown( route_map_finish )
3266 * Why are we making them do this work?
3268 route_map_master
.add_hook
= NULL
;
3269 route_map_master
.delete_hook
= NULL
;
3270 route_map_master
.event_hook
= NULL
;
3272 /* cleanup route_map */
3273 while (route_map_master
.head
) {
3274 struct route_map
*map
= route_map_master
.head
;
3275 map
->to_be_processed
= false;
3276 route_map_delete(map
);
3279 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
3280 hash_free(route_map_dep_hash
[i
]);
3281 route_map_dep_hash
[i
] = NULL
;
3284 hash_free(route_map_master_hash
);
3285 route_map_master_hash
= NULL
;
3288 /* Increment the use_count counter while attaching the route map */
3289 void route_map_counter_increment(struct route_map
*map
)
3295 /* Decrement the use_count counter while detaching the route map. */
3296 void route_map_counter_decrement(struct route_map
*map
)
3299 if (map
->use_count
<= 0)
3305 DEFUN_HIDDEN(show_route_map_pfx_tbl
, show_route_map_pfx_tbl_cmd
,
3306 "show route-map RMAP_NAME prefix-table",
3310 "internal prefix-table\n")
3312 const char *rmap_name
= argv
[2]->arg
;
3313 struct route_map
*rmap
= NULL
;
3314 struct route_table
*rm_pfx_tbl4
= NULL
;
3315 struct route_table
*rm_pfx_tbl6
= NULL
;
3316 struct route_node
*rn
= NULL
, *prn
= NULL
;
3317 struct list
*rmap_index_list
= NULL
;
3318 struct listnode
*ln
= NULL
, *nln
= NULL
;
3319 struct route_map_index
*index
= NULL
;
3322 vty_out(vty
, "%s:\n", frr_protonameinst
);
3323 rmap
= route_map_lookup_by_name(rmap_name
);
3325 rm_pfx_tbl4
= rmap
->ipv4_prefix_table
;
3327 vty_out(vty
, "\n%s%43s%s\n", "IPv4 Prefix", "",
3328 "Route-map Index List");
3329 vty_out(vty
, "%s%39s%s\n", "_______________", "",
3330 "____________________");
3331 for (rn
= route_top(rm_pfx_tbl4
); rn
;
3332 rn
= route_next(rn
)) {
3333 vty_out(vty
, " %pRN (%d)\n", rn
,
3334 route_node_get_lock_count(rn
));
3336 vty_out(vty
, "(P) ");
3339 vty_out(vty
, "%pRN\n", prn
);
3343 rmap_index_list
= (struct list
*)rn
->info
;
3344 if (!rmap_index_list
3345 || !listcount(rmap_index_list
))
3346 vty_out(vty
, "%*s%s\n", len
, "", "-");
3348 for (ALL_LIST_ELEMENTS(rmap_index_list
,
3351 vty_out(vty
, "%*s%s seq %d\n",
3360 rm_pfx_tbl6
= rmap
->ipv6_prefix_table
;
3362 vty_out(vty
, "\n%s%43s%s\n", "IPv6 Prefix", "",
3363 "Route-map Index List");
3364 vty_out(vty
, "%s%39s%s\n", "_______________", "",
3365 "____________________");
3366 for (rn
= route_top(rm_pfx_tbl6
); rn
;
3367 rn
= route_next(rn
)) {
3368 vty_out(vty
, " %pRN (%d)\n", rn
,
3369 route_node_get_lock_count(rn
));
3371 vty_out(vty
, "(P) ");
3374 vty_out(vty
, "%pRN\n", prn
);
3378 rmap_index_list
= (struct list
*)rn
->info
;
3379 if (!rmap_index_list
3380 || !listcount(rmap_index_list
))
3381 vty_out(vty
, "%*s%s\n", len
, "", "-");
3383 for (ALL_LIST_ELEMENTS(rmap_index_list
,
3386 vty_out(vty
, "%*s%s seq %d\n",
3400 /* Initialization of route map vector. */
3401 void route_map_init(void)
3405 route_map_master_hash
=
3406 hash_create_size(8, route_map_hash_key_make
, route_map_hash_cmp
,
3407 "Route Map Master Hash");
3409 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++)
3410 route_map_dep_hash
[i
] = hash_create_size(
3411 8, route_map_dep_hash_make_key
, route_map_dep_hash_cmp
,
3412 "Route Map Dep Hash");
3414 UNSET_FLAG(rmap_debug
, DEBUG_ROUTEMAP
);
3416 route_map_cli_init();
3418 /* Install route map top node. */
3419 install_node(&rmap_debug_node
);
3421 /* Install route map commands. */
3422 install_element(CONFIG_NODE
, &debug_rmap_cmd
);
3423 install_element(CONFIG_NODE
, &no_debug_rmap_cmd
);
3425 /* Install show command */
3426 install_element(ENABLE_NODE
, &rmap_clear_counters_cmd
);
3428 install_element(ENABLE_NODE
, &rmap_show_name_cmd
);
3429 install_element(ENABLE_NODE
, &rmap_show_unused_cmd
);
3431 install_element(ENABLE_NODE
, &debug_rmap_cmd
);
3432 install_element(ENABLE_NODE
, &no_debug_rmap_cmd
);
3434 install_element(ENABLE_NODE
, &show_route_map_pfx_tbl_cmd
);