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
;
398 void route_map_set_min_metric_hook(int (*func
)(struct route_map_index
*index
,
400 const char *arg
, char *errmsg
,
403 rmap_match_set_hook
.set_min_metric
= func
;
406 /* no set min-metric */
407 void route_map_no_set_min_metric_hook(int (*func
)(struct route_map_index
*index
,
409 const char *arg
, char *errmsg
,
412 rmap_match_set_hook
.no_set_min_metric
= func
;
415 void route_map_set_max_metric_hook(int (*func
)(struct route_map_index
*index
,
417 const char *arg
, char *errmsg
,
420 rmap_match_set_hook
.set_max_metric
= func
;
423 /* no set max-metric */
424 void route_map_no_set_max_metric_hook(int (*func
)(struct route_map_index
*index
,
426 const char *arg
, char *errmsg
,
429 rmap_match_set_hook
.no_set_max_metric
= func
;
433 void route_map_set_tag_hook(int (*func
)(struct route_map_index
*index
,
434 const char *command
, const char *arg
,
435 char *errmsg
, size_t errmsg_len
))
437 rmap_match_set_hook
.set_tag
= func
;
441 void route_map_no_set_tag_hook(int (*func
)(struct route_map_index
*index
,
444 char *errmsg
, size_t errmsg_len
))
446 rmap_match_set_hook
.no_set_tag
= func
;
449 int generic_match_add(struct route_map_index
*index
,
450 const char *command
, const char *arg
,
451 route_map_event_t type
,
452 char *errmsg
, size_t errmsg_len
)
454 enum rmap_compile_rets ret
;
456 ret
= route_map_add_match(index
, command
, arg
, type
);
458 case RMAP_RULE_MISSING
:
459 snprintf(errmsg
, errmsg_len
, "%% [%s] Can't find rule.",
461 return CMD_WARNING_CONFIG_FAILED
;
462 case RMAP_COMPILE_ERROR
:
463 snprintf(errmsg
, errmsg_len
,
464 "%% [%s] Argument form is unsupported or malformed.",
466 return CMD_WARNING_CONFIG_FAILED
;
467 case RMAP_COMPILE_SUCCESS
:
469 * Nothing to do here move along
477 int generic_match_delete(struct route_map_index
*index
,
478 const char *command
, const char *arg
,
479 route_map_event_t type
,
480 char *errmsg
, size_t errmsg_len
)
482 enum rmap_compile_rets ret
;
483 int retval
= CMD_SUCCESS
;
484 char *dep_name
= NULL
;
486 char *rmap_name
= NULL
;
488 if (type
!= RMAP_EVENT_MATCH_DELETED
) {
489 /* ignore the mundane, the types without any dependency */
491 if ((tmpstr
= route_map_get_match_arg(index
, command
))
494 XSTRDUP(MTYPE_ROUTE_MAP_RULE
, tmpstr
);
496 dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_RULE
, arg
);
498 rmap_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, index
->map
->name
);
501 ret
= route_map_delete_match(index
, command
, dep_name
, type
);
503 case RMAP_RULE_MISSING
:
504 snprintf(errmsg
, errmsg_len
, "%% [%s] Can't find rule.",
506 retval
= CMD_WARNING_CONFIG_FAILED
;
508 case RMAP_COMPILE_ERROR
:
509 snprintf(errmsg
, errmsg_len
,
510 "%% [%s] Argument form is unsupported or malformed.",
512 retval
= CMD_WARNING_CONFIG_FAILED
;
514 case RMAP_COMPILE_SUCCESS
:
521 XFREE(MTYPE_ROUTE_MAP_RULE
, dep_name
);
522 XFREE(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
527 int generic_set_add(struct route_map_index
*index
,
528 const char *command
, const char *arg
,
529 char *errmsg
, size_t errmsg_len
)
531 enum rmap_compile_rets ret
;
533 ret
= route_map_add_set(index
, command
, arg
);
535 case RMAP_RULE_MISSING
:
536 snprintf(errmsg
, errmsg_len
,
537 "%% [%s] Can't find rule.", frr_protonameinst
);
538 return CMD_WARNING_CONFIG_FAILED
;
539 case RMAP_COMPILE_ERROR
:
540 snprintf(errmsg
, errmsg_len
,
541 "%% [%s] Argument form is unsupported or malformed.",
543 return CMD_WARNING_CONFIG_FAILED
;
544 case RMAP_COMPILE_SUCCESS
:
551 int generic_set_delete(struct route_map_index
*index
,
552 const char *command
, const char *arg
,
553 char *errmsg
, size_t errmsg_len
)
555 enum rmap_compile_rets ret
;
557 ret
= route_map_delete_set(index
, command
, arg
);
559 case RMAP_RULE_MISSING
:
560 snprintf(errmsg
, errmsg_len
, "%% [%s] Can't find rule.",
562 return CMD_WARNING_CONFIG_FAILED
;
563 case RMAP_COMPILE_ERROR
:
564 snprintf(errmsg
, errmsg_len
,
565 "%% [%s] Argument form is unsupported or malformed.",
567 return CMD_WARNING_CONFIG_FAILED
;
568 case RMAP_COMPILE_SUCCESS
:
576 /* Master list of route map. */
577 struct route_map_list route_map_master
= {NULL
, NULL
, NULL
, NULL
, NULL
};
578 struct hash
*route_map_master_hash
= NULL
;
580 static unsigned int route_map_hash_key_make(const void *p
)
582 const struct route_map
*map
= p
;
583 return string_hash_make(map
->name
);
586 static bool route_map_hash_cmp(const void *p1
, const void *p2
)
588 const struct route_map
*map1
= p1
;
589 const struct route_map
*map2
= p2
;
591 if (!strcmp(map1
->name
, map2
->name
))
597 enum route_map_upd8_type
{
602 /* all possible route-map dependency types */
603 enum route_map_dep_type
{
604 ROUTE_MAP_DEP_RMAP
= 1,
606 ROUTE_MAP_DEP_ECLIST
,
607 ROUTE_MAP_DEP_LCLIST
,
609 ROUTE_MAP_DEP_ASPATH
,
610 ROUTE_MAP_DEP_FILTER
,
614 struct route_map_dep
{
616 struct hash
*dep_rmap_hash
;
617 struct hash
*this_hash
; /* ptr to the hash structure this is part of */
620 struct route_map_dep_data
{
624 /* Count of number of sequences of this
625 * route-map that depend on the same entity.
630 /* Hashes maintaining dependency between various sublists used by route maps */
631 static struct hash
*route_map_dep_hash
[ROUTE_MAP_DEP_MAX
];
633 static unsigned int route_map_dep_hash_make_key(const void *p
);
634 static void route_map_clear_all_references(char *rmap_name
);
635 static void route_map_rule_delete(struct route_map_rule_list
*,
636 struct route_map_rule
*);
640 /* New route map allocation. Please note route map's name must be
642 static struct route_map
*route_map_new(const char *name
)
644 struct route_map
*new;
646 new = XCALLOC(MTYPE_ROUTE_MAP
, sizeof(struct route_map
));
647 new->name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
648 QOBJ_REG(new, route_map
);
652 /* Add new name to route_map. */
653 static struct route_map
*route_map_add(const char *name
)
655 struct route_map
*map
, *exist
;
656 struct route_map_list
*list
;
658 map
= route_map_new(name
);
659 list
= &route_map_master
;
662 * Add map to the hash
664 * If the map already exists in the hash, then we know that
665 * FRR is now in a sequence of delete/create.
666 * All FRR needs to do here is set the to_be_processed
667 * bit (to inherit from the old one
669 exist
= hash_release(route_map_master_hash
, map
);
671 map
->to_be_processed
= exist
->to_be_processed
;
672 route_map_free_map(exist
);
674 hash_get(route_map_master_hash
, map
, hash_alloc_intern
);
676 /* Add new entry to the head of the list to match how it is added in the
677 * hash table. This is to ensure that if the same route-map has been
678 * created more than once and then marked for deletion (which can happen
679 * if prior deletions haven't completed as BGP hasn't yet done the
680 * route-map processing), the order of the entities is the same in both
681 * the list and the hash table. Otherwise, since there is nothing to
682 * distinguish between the two entries, the wrong entry could get freed.
683 * TODO: This needs to be re-examined to handle it better - e.g., revive
684 * a deleted entry if the route-map is created again.
687 map
->next
= list
->head
;
689 list
->head
->prev
= map
;
695 if (route_map_master
.add_hook
) {
696 (*route_map_master
.add_hook
)(name
);
697 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_ADDED
);
700 if (!map
->ipv4_prefix_table
)
701 map
->ipv4_prefix_table
= route_table_init();
703 if (!map
->ipv6_prefix_table
)
704 map
->ipv6_prefix_table
= route_table_init();
706 if (unlikely(CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
)))
707 zlog_debug("Add route-map %s", name
);
711 /* this is supposed to be called post processing by
712 * the delete hook function. Don't invoke delete_hook
713 * again in this routine.
715 static void route_map_free_map(struct route_map
*map
)
717 struct route_map_list
*list
;
718 struct route_map_index
*index
;
723 while ((index
= map
->head
) != NULL
)
724 route_map_index_delete(index
, 0);
726 if (unlikely(CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
)))
727 zlog_debug("Deleting route-map %s", map
->name
);
729 list
= &route_map_master
;
734 map
->next
->prev
= map
->prev
;
736 list
->tail
= map
->prev
;
739 map
->prev
->next
= map
->next
;
741 list
->head
= map
->next
;
743 route_table_finish(map
->ipv4_prefix_table
);
744 route_table_finish(map
->ipv6_prefix_table
);
746 hash_release(route_map_master_hash
, map
);
747 XFREE(MTYPE_ROUTE_MAP_NAME
, map
->name
);
748 XFREE(MTYPE_ROUTE_MAP
, map
);
751 /* Route map delete from list. */
752 void route_map_delete(struct route_map
*map
)
754 struct route_map_index
*index
;
757 while ((index
= map
->head
) != NULL
)
758 route_map_index_delete(index
, 0);
763 /* Clear all dependencies */
764 route_map_clear_all_references(name
);
766 /* Execute deletion hook. */
767 if (route_map_master
.delete_hook
) {
768 (*route_map_master
.delete_hook
)(name
);
769 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_DELETED
);
772 if (!map
->to_be_processed
) {
773 route_map_free_map(map
);
777 /* Lookup route map by route map name string. */
778 struct route_map
*route_map_lookup_by_name(const char *name
)
780 struct route_map
*map
;
781 struct route_map tmp_map
;
786 // map.deleted is false via memset
787 memset(&tmp_map
, 0, sizeof(tmp_map
));
788 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
789 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
790 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
792 if (map
&& map
->deleted
)
798 /* Simple helper to warn if route-map does not exist. */
799 struct route_map
*route_map_lookup_warn_noexist(struct vty
*vty
, const char *name
)
801 struct route_map
*route_map
= route_map_lookup_by_name(name
);
804 if (vty_shell_serv(vty
))
805 vty_out(vty
, "The route-map '%s' does not exist.\n", name
);
810 int route_map_mark_updated(const char *name
)
812 struct route_map
*map
;
814 struct route_map tmp_map
;
819 map
= route_map_lookup_by_name(name
);
821 /* If we did not find the routemap with deleted=false try again
825 memset(&tmp_map
, 0, sizeof(tmp_map
));
826 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
827 tmp_map
.deleted
= true;
828 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
829 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
833 map
->to_be_processed
= true;
840 static void route_map_clear_updated(struct route_map
*map
)
843 map
->to_be_processed
= false;
845 route_map_free_map(map
);
849 /* Lookup route map. If there isn't route map create one and return
851 struct route_map
*route_map_get(const char *name
)
853 struct route_map
*map
;
855 map
= route_map_lookup_by_name(name
);
857 map
= route_map_add(name
);
862 void route_map_walk_update_list(void (*route_map_update_fn
)(char *name
))
864 struct route_map
*node
;
865 struct route_map
*nnode
= NULL
;
867 for (node
= route_map_master
.head
; node
; node
= nnode
) {
868 if (node
->to_be_processed
) {
869 /* DD: Should we add any thread yield code here */
870 route_map_update_fn(node
->name
);
872 route_map_clear_updated(node
);
878 /* Return route map's type string. */
879 static const char *route_map_type_str(enum route_map_type type
)
893 static const char *route_map_cmd_result_str(enum route_map_cmd_result_t res
)
911 static const char *route_map_result_str(route_map_result_t res
)
916 case RMAP_PERMITMATCH
:
924 static void vty_show_route_map_entry(struct vty
*vty
, struct route_map
*map
,
927 struct route_map_index
*index
;
928 struct route_map_rule
*rule
;
929 json_object
*json_rmap
= NULL
;
930 json_object
*json_rules
= NULL
;
933 json_rmap
= json_object_new_object();
934 json_object_object_add(json
, map
->name
, json_rmap
);
936 json_rules
= json_object_new_array();
937 json_object_int_add(json_rmap
, "invoked",
938 map
->applied
- map
->applied_clear
);
939 json_object_boolean_add(json_rmap
, "disabledOptimization",
940 map
->optimization_disabled
);
941 json_object_boolean_add(json_rmap
, "processedChange",
942 map
->to_be_processed
);
943 json_object_object_add(json_rmap
, "rules", json_rules
);
946 "route-map: %s Invoked: %" PRIu64
947 " Optimization: %s Processed Change: %s\n",
948 map
->name
, map
->applied
- map
->applied_clear
,
949 map
->optimization_disabled
? "disabled" : "enabled",
950 map
->to_be_processed
? "true" : "false");
953 for (index
= map
->head
; index
; index
= index
->next
) {
955 json_object
*json_rule
;
956 json_object
*json_matches
;
957 json_object
*json_sets
;
958 char action
[BUFSIZ
] = {};
960 json_rule
= json_object_new_object();
961 json_object_array_add(json_rules
, json_rule
);
963 json_object_int_add(json_rule
, "sequenceNumber",
965 json_object_string_add(json_rule
, "type",
966 route_map_type_str(index
->type
));
967 json_object_int_add(json_rule
, "invoked",
969 - index
->applied_clear
);
972 if (index
->description
)
973 json_object_string_add(json_rule
, "description",
977 json_matches
= json_object_new_array();
978 json_object_object_add(json_rule
, "matchClauses",
980 for (rule
= index
->match_list
.head
; rule
;
984 snprintf(buf
, sizeof(buf
), "%s %s",
985 rule
->cmd
->str
, rule
->rule_str
);
986 json_array_string_add(json_matches
, buf
);
990 json_sets
= json_object_new_array();
991 json_object_object_add(json_rule
, "setClauses",
993 for (rule
= index
->set_list
.head
; rule
;
997 snprintf(buf
, sizeof(buf
), "%s %s",
998 rule
->cmd
->str
, rule
->rule_str
);
999 json_array_string_add(json_sets
, buf
);
1004 json_object_string_add(json_rule
, "callClause",
1008 if (index
->exitpolicy
== RMAP_GOTO
)
1009 snprintf(action
, sizeof(action
), "Goto %d",
1011 else if (index
->exitpolicy
== RMAP_NEXT
)
1012 snprintf(action
, sizeof(action
),
1013 "Continue to next entry");
1014 else if (index
->exitpolicy
== RMAP_EXIT
)
1015 snprintf(action
, sizeof(action
),
1017 if (action
[0] != '\0')
1018 json_object_string_add(json_rule
, "action",
1021 vty_out(vty
, " %s, sequence %d Invoked %" PRIu64
"\n",
1022 route_map_type_str(index
->type
), index
->pref
,
1023 index
->applied
- index
->applied_clear
);
1026 if (index
->description
)
1027 vty_out(vty
, " Description:\n %s\n",
1028 index
->description
);
1031 vty_out(vty
, " Match clauses:\n");
1032 for (rule
= index
->match_list
.head
; rule
;
1034 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
1038 vty_out(vty
, " Set clauses:\n");
1039 for (rule
= index
->set_list
.head
; rule
;
1041 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
1045 vty_out(vty
, " Call clause:\n");
1047 vty_out(vty
, " Call %s\n", index
->nextrm
);
1050 vty_out(vty
, " Action:\n");
1051 if (index
->exitpolicy
== RMAP_GOTO
)
1052 vty_out(vty
, " Goto %d\n", index
->nextpref
);
1053 else if (index
->exitpolicy
== RMAP_NEXT
)
1054 vty_out(vty
, " Continue to next entry\n");
1055 else if (index
->exitpolicy
== RMAP_EXIT
)
1056 vty_out(vty
, " Exit routemap\n");
1061 static int sort_route_map(const void **map1
, const void **map2
)
1063 const struct route_map
*m1
= *map1
;
1064 const struct route_map
*m2
= *map2
;
1066 return strcmp(m1
->name
, m2
->name
);
1069 static int vty_show_route_map(struct vty
*vty
, const char *name
, bool use_json
)
1071 struct route_map
*map
;
1072 json_object
*json
= NULL
;
1073 json_object
*json_proto
= NULL
;
1076 json
= json_object_new_object();
1077 json_proto
= json_object_new_object();
1078 json_object_object_add(json
, frr_protonameinst
, json_proto
);
1080 vty_out(vty
, "%s:\n", frr_protonameinst
);
1083 map
= route_map_lookup_by_name(name
);
1086 vty_show_route_map_entry(vty
, map
, json_proto
);
1087 } else if (!use_json
) {
1088 vty_out(vty
, "%s: 'route-map %s' not found\n",
1089 frr_protonameinst
, name
);
1093 struct list
*maplist
= list_new();
1094 struct listnode
*ln
;
1096 for (map
= route_map_master
.head
; map
; map
= map
->next
)
1097 listnode_add(maplist
, map
);
1099 list_sort(maplist
, sort_route_map
);
1101 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
1102 vty_show_route_map_entry(vty
, map
, json_proto
);
1104 list_delete(&maplist
);
1107 return vty_json(vty
, json
);
1110 /* Unused route map details */
1111 static int vty_show_unused_route_map(struct vty
*vty
)
1113 struct list
*maplist
= list_new();
1114 struct listnode
*ln
;
1115 struct route_map
*map
;
1117 for (map
= route_map_master
.head
; map
; map
= map
->next
) {
1118 /* If use_count is zero, No protocol is using this routemap.
1119 * so adding to the list.
1121 if (!map
->use_count
)
1122 listnode_add(maplist
, map
);
1125 if (maplist
->count
> 0) {
1126 vty_out(vty
, "\n%s:\n", frr_protonameinst
);
1127 list_sort(maplist
, sort_route_map
);
1129 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
1130 vty_show_route_map_entry(vty
, map
, NULL
);
1132 vty_out(vty
, "\n%s: None\n", frr_protonameinst
);
1135 list_delete(&maplist
);
1139 /* New route map allocation. Please note route map's name must be
1141 static struct route_map_index
*route_map_index_new(void)
1143 struct route_map_index
*new;
1145 new = XCALLOC(MTYPE_ROUTE_MAP_INDEX
, sizeof(struct route_map_index
));
1146 new->exitpolicy
= RMAP_EXIT
; /* Default to Cisco-style */
1147 TAILQ_INIT(&new->rhclist
);
1148 QOBJ_REG(new, route_map_index
);
1152 /* Free route map index. */
1153 void route_map_index_delete(struct route_map_index
*index
, int notify
)
1155 struct routemap_hook_context
*rhc
;
1156 struct route_map_rule
*rule
;
1160 if (unlikely(CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
)))
1161 zlog_debug("Deleting route-map %s sequence %d",
1162 index
->map
->name
, index
->pref
);
1164 /* Free route map entry description. */
1165 XFREE(MTYPE_TMP
, index
->description
);
1167 /* Free route map northbound hook contexts. */
1168 while ((rhc
= TAILQ_FIRST(&index
->rhclist
)) != NULL
)
1169 routemap_hook_context_free(rhc
);
1171 /* Free route match. */
1172 while ((rule
= index
->match_list
.head
) != NULL
) {
1173 if (IS_RULE_IPv4_PREFIX_LIST(rule
->cmd
->str
))
1174 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_DELETED
,
1175 index
, AFI_IP
, rule
->rule_str
);
1176 else if (IS_RULE_IPv6_PREFIX_LIST(rule
->cmd
->str
))
1177 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_DELETED
,
1181 route_map_rule_delete(&index
->match_list
, rule
);
1184 /* Free route set. */
1185 while ((rule
= index
->set_list
.head
) != NULL
)
1186 route_map_rule_delete(&index
->set_list
, rule
);
1188 /* Remove index from route map list. */
1190 index
->next
->prev
= index
->prev
;
1192 index
->map
->tail
= index
->prev
;
1195 index
->prev
->next
= index
->next
;
1197 index
->map
->head
= index
->next
;
1199 /* Free 'char *nextrm' if not NULL */
1200 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
1202 route_map_pfx_tbl_update(RMAP_EVENT_INDEX_DELETED
, index
, 0, NULL
);
1204 /* Execute event hook. */
1205 if (route_map_master
.event_hook
&& notify
) {
1206 (*route_map_master
.event_hook
)(index
->map
->name
);
1207 route_map_notify_dependencies(index
->map
->name
,
1208 RMAP_EVENT_CALL_ADDED
);
1210 XFREE(MTYPE_ROUTE_MAP_INDEX
, index
);
1213 /* Lookup index from route map. */
1214 static struct route_map_index
*route_map_index_lookup(struct route_map
*map
,
1215 enum route_map_type type
,
1218 struct route_map_index
*index
;
1220 for (index
= map
->head
; index
; index
= index
->next
)
1221 if ((index
->type
== type
|| type
== RMAP_ANY
)
1222 && index
->pref
== pref
)
1227 /* Add new index to route map. */
1228 static struct route_map_index
*
1229 route_map_index_add(struct route_map
*map
, enum route_map_type type
, int pref
)
1231 struct route_map_index
*index
;
1232 struct route_map_index
*point
;
1234 /* Allocate new route map inex. */
1235 index
= route_map_index_new();
1240 /* Compare preference. */
1241 for (point
= map
->head
; point
; point
= point
->next
)
1242 if (point
->pref
>= pref
)
1245 if (map
->head
== NULL
) {
1246 map
->head
= map
->tail
= index
;
1247 } else if (point
== NULL
) {
1248 index
->prev
= map
->tail
;
1249 map
->tail
->next
= index
;
1251 } else if (point
== map
->head
) {
1252 index
->next
= map
->head
;
1253 map
->head
->prev
= index
;
1256 index
->next
= point
;
1257 index
->prev
= point
->prev
;
1259 point
->prev
->next
= index
;
1260 point
->prev
= index
;
1263 route_map_pfx_tbl_update(RMAP_EVENT_INDEX_ADDED
, index
, 0, NULL
);
1265 /* Execute event hook. */
1266 if (route_map_master
.event_hook
) {
1267 (*route_map_master
.event_hook
)(map
->name
);
1268 route_map_notify_dependencies(map
->name
, RMAP_EVENT_CALL_ADDED
);
1271 if (unlikely(CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
)))
1272 zlog_debug("Route-map %s add sequence %d, type: %s",
1273 map
->name
, pref
, route_map_type_str(type
));
1278 /* Get route map index. */
1279 struct route_map_index
*
1280 route_map_index_get(struct route_map
*map
, enum route_map_type type
, int pref
)
1282 struct route_map_index
*index
;
1284 index
= route_map_index_lookup(map
, RMAP_ANY
, pref
);
1285 if (index
&& index
->type
!= type
) {
1286 /* Delete index from route map. */
1287 route_map_index_delete(index
, 1);
1291 index
= route_map_index_add(map
, type
, pref
);
1295 /* New route map rule */
1296 static struct route_map_rule
*route_map_rule_new(void)
1298 struct route_map_rule
*new;
1300 new = XCALLOC(MTYPE_ROUTE_MAP_RULE
, sizeof(struct route_map_rule
));
1304 /* Install rule command to the match list. */
1305 void _route_map_install_match(struct route_map_rule_cmd_proxy
*proxy
)
1307 rmap_cmd_name_add(rmap_match_cmds
, proxy
);
1310 /* Install rule command to the set list. */
1311 void _route_map_install_set(struct route_map_rule_cmd_proxy
*proxy
)
1313 rmap_cmd_name_add(rmap_set_cmds
, proxy
);
1316 /* Lookup rule command from match list. */
1317 static const struct route_map_rule_cmd
*route_map_lookup_match(const char *name
)
1319 struct route_map_rule_cmd refcmd
= {.str
= name
};
1320 struct route_map_rule_cmd_proxy ref
= {.cmd
= &refcmd
};
1321 struct route_map_rule_cmd_proxy
*res
;
1323 res
= rmap_cmd_name_find(rmap_match_cmds
, &ref
);
1329 /* Lookup rule command from set list. */
1330 static const struct route_map_rule_cmd
*route_map_lookup_set(const char *name
)
1332 struct route_map_rule_cmd refcmd
= {.str
= name
};
1333 struct route_map_rule_cmd_proxy ref
= {.cmd
= &refcmd
};
1334 struct route_map_rule_cmd_proxy
*res
;
1336 res
= rmap_cmd_name_find(rmap_set_cmds
, &ref
);
1342 /* Add match and set rule to rule list. */
1343 static void route_map_rule_add(struct route_map_rule_list
*list
,
1344 struct route_map_rule
*rule
)
1347 rule
->prev
= list
->tail
;
1349 list
->tail
->next
= rule
;
1355 /* Delete rule from rule list. */
1356 static void route_map_rule_delete(struct route_map_rule_list
*list
,
1357 struct route_map_rule
*rule
)
1359 if (rule
->cmd
->func_free
)
1360 (*rule
->cmd
->func_free
)(rule
->value
);
1362 XFREE(MTYPE_ROUTE_MAP_RULE_STR
, rule
->rule_str
);
1365 rule
->next
->prev
= rule
->prev
;
1367 list
->tail
= rule
->prev
;
1369 rule
->prev
->next
= rule
->next
;
1371 list
->head
= rule
->next
;
1373 XFREE(MTYPE_ROUTE_MAP_RULE
, rule
);
1376 /* strcmp wrapper function which don't crush even argument is NULL. */
1377 static int rulecmp(const char *dst
, const char *src
)
1388 return strcmp(dst
, src
);
1393 /* Use this to return the already specified argument for this match. This is
1394 * useful to get the specified argument with a route map match rule when the
1395 * rule is being deleted and the argument is not provided.
1397 const char *route_map_get_match_arg(struct route_map_index
*index
,
1398 const char *match_name
)
1400 struct route_map_rule
*rule
;
1401 const struct route_map_rule_cmd
*cmd
;
1403 /* First lookup rule for add match statement. */
1404 cmd
= route_map_lookup_match(match_name
);
1408 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1409 if (rule
->cmd
== cmd
&& rule
->rule_str
!= NULL
)
1410 return (rule
->rule_str
);
1415 static route_map_event_t
get_route_map_delete_event(route_map_event_t type
)
1418 case RMAP_EVENT_CALL_ADDED
:
1419 return RMAP_EVENT_CALL_DELETED
;
1420 case RMAP_EVENT_PLIST_ADDED
:
1421 return RMAP_EVENT_PLIST_DELETED
;
1422 case RMAP_EVENT_CLIST_ADDED
:
1423 return RMAP_EVENT_CLIST_DELETED
;
1424 case RMAP_EVENT_ECLIST_ADDED
:
1425 return RMAP_EVENT_ECLIST_DELETED
;
1426 case RMAP_EVENT_LLIST_ADDED
:
1427 return RMAP_EVENT_LLIST_DELETED
;
1428 case RMAP_EVENT_ASLIST_ADDED
:
1429 return RMAP_EVENT_ASLIST_DELETED
;
1430 case RMAP_EVENT_FILTER_ADDED
:
1431 return RMAP_EVENT_FILTER_DELETED
;
1432 case RMAP_EVENT_SET_ADDED
:
1433 case RMAP_EVENT_SET_DELETED
:
1434 case RMAP_EVENT_SET_REPLACED
:
1435 case RMAP_EVENT_MATCH_ADDED
:
1436 case RMAP_EVENT_MATCH_DELETED
:
1437 case RMAP_EVENT_MATCH_REPLACED
:
1438 case RMAP_EVENT_INDEX_ADDED
:
1439 case RMAP_EVENT_INDEX_DELETED
:
1440 case RMAP_EVENT_CALL_DELETED
:
1441 case RMAP_EVENT_PLIST_DELETED
:
1442 case RMAP_EVENT_CLIST_DELETED
:
1443 case RMAP_EVENT_ECLIST_DELETED
:
1444 case RMAP_EVENT_LLIST_DELETED
:
1445 case RMAP_EVENT_ASLIST_DELETED
:
1446 case RMAP_EVENT_FILTER_DELETED
:
1447 /* This function returns the appropriate 'deleted' event type
1448 * for every 'added' event type passed to this function.
1449 * This is done only for named entities used in the
1450 * route-map match commands.
1451 * This function is not to be invoked for any of the other event
1459 * Return to make c happy but if we get here something has gone
1460 * terribly terribly wrong, so yes this return makes no sense.
1462 return RMAP_EVENT_CALL_ADDED
;
1465 /* Add match statement to route map. */
1466 enum rmap_compile_rets
route_map_add_match(struct route_map_index
*index
,
1467 const char *match_name
,
1468 const char *match_arg
,
1469 route_map_event_t type
)
1471 struct route_map_rule
*rule
;
1472 struct route_map_rule
*next
;
1473 const struct route_map_rule_cmd
*cmd
;
1475 int8_t delete_rmap_event_type
= 0;
1476 const char *rule_key
;
1478 /* First lookup rule for add match statement. */
1479 cmd
= route_map_lookup_match(match_name
);
1481 return RMAP_RULE_MISSING
;
1483 /* Next call compile function for this match statement. */
1484 if (cmd
->func_compile
) {
1485 compile
= (*cmd
->func_compile
)(match_arg
);
1486 if (compile
== NULL
)
1487 return RMAP_COMPILE_ERROR
;
1490 /* use the compiled results if applicable */
1491 if (compile
&& cmd
->func_get_rmap_rule_key
)
1492 rule_key
= (*cmd
->func_get_rmap_rule_key
)
1495 rule_key
= match_arg
;
1497 /* If argument is completely same ignore it. */
1498 for (rule
= index
->match_list
.head
; rule
; rule
= next
) {
1500 if (rule
->cmd
== cmd
) {
1501 /* If the configured route-map match rule is exactly
1502 * the same as the existing configuration then,
1503 * ignore the duplicate configuration.
1505 if (rulecmp(match_arg
, rule
->rule_str
) == 0) {
1507 (*cmd
->func_free
)(compile
);
1509 return RMAP_COMPILE_SUCCESS
;
1512 /* If IPv4 or IPv6 prefix-list match criteria
1513 * has been delete to the route-map index, update
1514 * the route-map's prefix table.
1516 if (IS_RULE_IPv4_PREFIX_LIST(match_name
))
1517 route_map_pfx_tbl_update(
1518 RMAP_EVENT_PLIST_DELETED
, index
, AFI_IP
,
1520 else if (IS_RULE_IPv6_PREFIX_LIST(match_name
))
1521 route_map_pfx_tbl_update(
1522 RMAP_EVENT_PLIST_DELETED
, index
,
1523 AFI_IP6
, rule
->rule_str
);
1525 /* Remove the dependency of the route-map on the rule
1526 * that is being replaced.
1528 if (type
>= RMAP_EVENT_CALL_ADDED
) {
1529 delete_rmap_event_type
=
1530 get_route_map_delete_event(type
);
1531 route_map_upd8_dependency(
1532 delete_rmap_event_type
,
1537 route_map_rule_delete(&index
->match_list
, rule
);
1541 /* Add new route map match rule. */
1542 rule
= route_map_rule_new();
1544 rule
->value
= compile
;
1546 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, match_arg
);
1548 rule
->rule_str
= NULL
;
1550 /* Add new route match rule to linked list. */
1551 route_map_rule_add(&index
->match_list
, rule
);
1553 /* If IPv4 or IPv6 prefix-list match criteria
1554 * has been added to the route-map index, update
1555 * the route-map's prefix table.
1557 if (IS_RULE_IPv4_PREFIX_LIST(match_name
)) {
1558 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_ADDED
, index
, AFI_IP
,
1560 } else if (IS_RULE_IPv6_PREFIX_LIST(match_name
)) {
1561 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_ADDED
, index
, AFI_IP6
,
1565 /* Execute event hook. */
1566 if (route_map_master
.event_hook
) {
1567 (*route_map_master
.event_hook
)(index
->map
->name
);
1568 route_map_notify_dependencies(index
->map
->name
,
1569 RMAP_EVENT_CALL_ADDED
);
1571 if (type
!= RMAP_EVENT_MATCH_ADDED
)
1572 route_map_upd8_dependency(type
, rule_key
, index
->map
->name
);
1574 return RMAP_COMPILE_SUCCESS
;
1577 /* Delete specified route match rule. */
1578 enum rmap_compile_rets
route_map_delete_match(struct route_map_index
*index
,
1579 const char *match_name
,
1580 const char *match_arg
,
1581 route_map_event_t type
)
1583 struct route_map_rule
*rule
;
1584 const struct route_map_rule_cmd
*cmd
;
1585 const char *rule_key
;
1587 cmd
= route_map_lookup_match(match_name
);
1589 return RMAP_RULE_MISSING
;
1591 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1592 if (rule
->cmd
== cmd
&& (rulecmp(rule
->rule_str
, match_arg
) == 0
1593 || match_arg
== NULL
)) {
1594 /* Execute event hook. */
1595 if (route_map_master
.event_hook
) {
1596 (*route_map_master
.event_hook
)(index
->map
->name
);
1597 route_map_notify_dependencies(
1599 RMAP_EVENT_CALL_ADDED
);
1601 if (cmd
->func_get_rmap_rule_key
)
1602 rule_key
= (*cmd
->func_get_rmap_rule_key
)
1605 rule_key
= match_arg
;
1607 if (type
!= RMAP_EVENT_MATCH_DELETED
&& rule_key
)
1608 route_map_upd8_dependency(type
, rule_key
,
1611 route_map_rule_delete(&index
->match_list
, rule
);
1613 /* If IPv4 or IPv6 prefix-list match criteria
1614 * has been delete from the route-map index, update
1615 * the route-map's prefix table.
1617 if (IS_RULE_IPv4_PREFIX_LIST(match_name
)) {
1618 route_map_pfx_tbl_update(
1619 RMAP_EVENT_PLIST_DELETED
, index
, AFI_IP
,
1621 } else if (IS_RULE_IPv6_PREFIX_LIST(match_name
)) {
1622 route_map_pfx_tbl_update(
1623 RMAP_EVENT_PLIST_DELETED
, index
,
1624 AFI_IP6
, match_arg
);
1627 return RMAP_COMPILE_SUCCESS
;
1629 /* Can't find matched rule. */
1630 return RMAP_RULE_MISSING
;
1633 /* Add route-map set statement to the route map. */
1634 enum rmap_compile_rets
route_map_add_set(struct route_map_index
*index
,
1635 const char *set_name
,
1636 const char *set_arg
)
1638 struct route_map_rule
*rule
;
1639 struct route_map_rule
*next
;
1640 const struct route_map_rule_cmd
*cmd
;
1643 cmd
= route_map_lookup_set(set_name
);
1645 return RMAP_RULE_MISSING
;
1647 /* Next call compile function for this match statement. */
1648 if (cmd
->func_compile
) {
1649 compile
= (*cmd
->func_compile
)(set_arg
);
1650 if (compile
== NULL
)
1651 return RMAP_COMPILE_ERROR
;
1655 /* Add by WJL. if old set command of same kind exist, delete it first
1656 to ensure only one set command of same kind exist under a
1658 for (rule
= index
->set_list
.head
; rule
; rule
= next
) {
1660 if (rule
->cmd
== cmd
)
1661 route_map_rule_delete(&index
->set_list
, rule
);
1664 /* Add new route map match rule. */
1665 rule
= route_map_rule_new();
1667 rule
->value
= compile
;
1669 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, set_arg
);
1671 rule
->rule_str
= NULL
;
1673 /* Add new route match rule to linked list. */
1674 route_map_rule_add(&index
->set_list
, rule
);
1676 /* Execute event hook. */
1677 if (route_map_master
.event_hook
) {
1678 (*route_map_master
.event_hook
)(index
->map
->name
);
1679 route_map_notify_dependencies(index
->map
->name
,
1680 RMAP_EVENT_CALL_ADDED
);
1682 return RMAP_COMPILE_SUCCESS
;
1685 /* Delete route map set rule. */
1686 enum rmap_compile_rets
route_map_delete_set(struct route_map_index
*index
,
1687 const char *set_name
,
1688 const char *set_arg
)
1690 struct route_map_rule
*rule
;
1691 const struct route_map_rule_cmd
*cmd
;
1693 cmd
= route_map_lookup_set(set_name
);
1695 return RMAP_RULE_MISSING
;
1697 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
1698 if ((rule
->cmd
== cmd
) && (rulecmp(rule
->rule_str
, set_arg
) == 0
1699 || set_arg
== NULL
)) {
1700 route_map_rule_delete(&index
->set_list
, rule
);
1701 /* Execute event hook. */
1702 if (route_map_master
.event_hook
) {
1703 (*route_map_master
.event_hook
)(index
->map
->name
);
1704 route_map_notify_dependencies(
1706 RMAP_EVENT_CALL_ADDED
);
1708 return RMAP_COMPILE_SUCCESS
;
1710 /* Can't find matched rule. */
1711 return RMAP_RULE_MISSING
;
1714 static enum route_map_cmd_result_t
1715 route_map_apply_match(struct route_map_rule_list
*match_list
,
1716 const struct prefix
*prefix
, void *object
)
1718 enum route_map_cmd_result_t ret
= RMAP_NOMATCH
;
1719 struct route_map_rule
*match
;
1720 bool is_matched
= false;
1723 /* Check all match rule and if there is no match rule, go to the
1725 if (!match_list
->head
)
1728 for (match
= match_list
->head
; match
; match
= match
->next
) {
1730 * Try each match statement. If any match does not
1731 * return RMAP_MATCH or RMAP_NOOP, return.
1732 * Otherwise continue on to next match statement.
1733 * All match statements must MATCH for
1734 * end-result to be a match.
1735 * (Exception:If match stmts result in a mix of
1736 * MATCH/NOOP, then also end-result is a match)
1737 * If all result in NOOP, end-result is NOOP.
1739 ret
= (*match
->cmd
->func_apply
)(match
->value
, prefix
,
1743 * If the consolidated result of func_apply is:
1744 * -----------------------------------------------
1745 * | MATCH | NOMATCH | NOOP | Final Result |
1746 * ------------------------------------------------
1747 * | yes | yes | yes | NOMATCH |
1748 * | no | no | yes | NOOP |
1749 * | yes | no | yes | MATCH |
1750 * | no | yes | yes | NOMATCH |
1751 * |-----------------------------------------------
1753 * Traditionally, all rules within route-map
1754 * should match for it to MATCH.
1755 * If there are noops within the route-map rules,
1756 * it follows the above matrix.
1758 * Eg: route-map rm1 permit 10
1763 * route-map rm1 permit 20
1792 static struct list
*route_map_get_index_list(struct route_node
**rn
,
1793 const struct prefix
*prefix
,
1794 struct route_table
*table
)
1796 struct route_node
*tmp_rn
= NULL
;
1799 *rn
= route_node_match(table
, prefix
);
1805 return (struct list
*)((*rn
)->info
);
1807 /* If rn->info is NULL, get the parent.
1808 * Store the rn in tmp_rn and unlock it later.
1814 *rn
= (*rn
)->parent
;
1816 route_unlock_node(tmp_rn
);
1822 route_lock_node(*rn
);
1823 return (struct list
*)((*rn
)->info
);
1825 } while (!(*rn
)->info
);
1831 * This function returns the route-map index that best matches the prefix.
1833 static struct route_map_index
*
1834 route_map_get_index(struct route_map
*map
, const struct prefix
*prefix
,
1835 void *object
, enum route_map_cmd_result_t
*match_ret
)
1837 enum route_map_cmd_result_t ret
= RMAP_NOMATCH
;
1838 struct list
*candidate_rmap_list
= NULL
;
1839 struct route_node
*rn
= NULL
;
1840 struct listnode
*ln
= NULL
, *nn
= NULL
;
1841 struct route_map_index
*index
= NULL
, *best_index
= NULL
;
1842 struct route_map_index
*head_index
= NULL
;
1843 struct route_table
*table
= NULL
;
1845 /* Route-map optimization relies on LPM lookups of the prefix to reduce
1846 * the amount of route-map clauses a given prefix needs to be processed
1847 * against. These LPM trees are IPv4/IPv6-specific and prefix->family
1848 * must be AF_INET or AF_INET6 in order for the lookup to succeed. So if
1849 * the AF doesn't line up with the LPM trees, skip the optimization.
1851 if (map
->optimization_disabled
) {
1852 if (unlikely(CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP_DETAIL
)))
1854 "Skipping route-map optimization for route-map: %s, pfx: %pFX, family: %d",
1855 map
->name
, prefix
, prefix
->family
);
1859 if (prefix
->family
== AF_INET
)
1860 table
= map
->ipv4_prefix_table
;
1862 table
= map
->ipv6_prefix_table
;
1865 candidate_rmap_list
=
1866 route_map_get_index_list(&rn
, prefix
, table
);
1870 /* If the index at the head of the list is of seq higher
1871 * than that in best_index, ignore the list and get the
1872 * parent node's list.
1874 head_index
= (struct route_map_index
*)(listgetdata(
1875 listhead(candidate_rmap_list
)));
1876 if (best_index
&& head_index
1877 && (best_index
->pref
< head_index
->pref
)) {
1878 route_unlock_node(rn
);
1882 for (ALL_LIST_ELEMENTS(candidate_rmap_list
, ln
, nn
, index
)) {
1883 /* If the index is of seq higher than that in
1884 * best_index, ignore the list and get the parent
1887 if (best_index
&& (best_index
->pref
< index
->pref
))
1890 ret
= route_map_apply_match(&index
->match_list
, prefix
,
1893 if (ret
== RMAP_MATCH
) {
1897 } else if (ret
== RMAP_NOOP
) {
1899 * If match_ret is denymatch, even if we see
1900 * more noops, we retain this return value and
1901 * return this eventually if there are no
1903 * If a best match route-map index already
1904 * exists, do not reset the match_ret.
1906 if (!best_index
&& (*match_ret
!= RMAP_NOMATCH
))
1910 * ret is RMAP_NOMATCH.
1911 * If a best match route-map index already
1912 * exists, do not reset the match_ret.
1919 route_unlock_node(rn
);
1926 static int route_map_candidate_list_cmp(struct route_map_index
*idx1
,
1927 struct route_map_index
*idx2
)
1929 return idx1
->pref
- idx2
->pref
;
1933 * This function adds the route-map index into the default route's
1934 * route-node in the route-map's IPv4/IPv6 prefix-table.
1936 static void route_map_pfx_table_add_default(afi_t afi
,
1937 struct route_map_index
*index
)
1939 struct route_node
*rn
= NULL
;
1940 struct list
*rmap_candidate_list
= NULL
;
1942 bool updated_rn
= false;
1943 struct route_table
*table
= NULL
;
1945 memset(&p
, 0, sizeof(p
));
1946 p
.family
= afi2family(afi
);
1949 if (p
.family
== AF_INET
)
1950 table
= index
->map
->ipv4_prefix_table
;
1952 table
= index
->map
->ipv6_prefix_table
;
1954 /* Add default route to table */
1955 rn
= route_node_get(table
, &p
);
1961 rmap_candidate_list
= list_new();
1962 rmap_candidate_list
->cmp
=
1963 (int (*)(void *, void *))route_map_candidate_list_cmp
;
1964 rn
->info
= rmap_candidate_list
;
1966 rmap_candidate_list
= (struct list
*)rn
->info
;
1970 listnode_add_sort_nodup(rmap_candidate_list
, index
);
1972 route_unlock_node(rn
);
1976 * This function removes the route-map index from the default route's
1977 * route-node in the route-map's IPv4/IPv6 prefix-table.
1979 static void route_map_pfx_table_del_default(afi_t afi
,
1980 struct route_map_index
*index
)
1982 struct route_node
*rn
= NULL
;
1983 struct list
*rmap_candidate_list
= NULL
;
1985 struct route_table
*table
= NULL
;
1987 memset(&p
, 0, sizeof(p
));
1988 p
.family
= afi2family(afi
);
1991 if (p
.family
== AF_INET
)
1992 table
= index
->map
->ipv4_prefix_table
;
1994 table
= index
->map
->ipv6_prefix_table
;
1996 /* Remove RMAP index from default route in table */
1997 rn
= route_node_lookup(table
, &p
);
1998 if (!rn
|| !rn
->info
)
2001 rmap_candidate_list
= (struct list
*)rn
->info
;
2003 listnode_delete(rmap_candidate_list
, index
);
2005 if (listcount(rmap_candidate_list
) == 0) {
2006 list_delete(&rmap_candidate_list
);
2008 route_unlock_node(rn
);
2010 route_unlock_node(rn
);
2014 * This function adds the route-map index to the route-node for
2015 * the prefix-entry in the route-map's IPv4/IPv6 prefix-table.
2017 static void route_map_pfx_table_add(struct route_table
*table
,
2018 struct route_map_index
*index
,
2019 struct prefix_list_entry
*pentry
)
2021 struct route_node
*rn
= NULL
;
2022 struct list
*rmap_candidate_list
= NULL
;
2023 bool updated_rn
= false;
2025 rn
= route_node_get(table
, &pentry
->prefix
);
2030 rmap_candidate_list
= list_new();
2031 rmap_candidate_list
->cmp
=
2032 (int (*)(void *, void *))route_map_candidate_list_cmp
;
2033 rn
->info
= rmap_candidate_list
;
2035 rmap_candidate_list
= (struct list
*)rn
->info
;
2039 listnode_add_sort_nodup(rmap_candidate_list
, index
);
2041 route_unlock_node(rn
);
2045 * This function removes the route-map index from the route-node for
2046 * the prefix-entry in the route-map's IPv4/IPv6 prefix-table.
2048 static void route_map_pfx_table_del(struct route_table
*table
,
2049 struct route_map_index
*index
,
2050 struct prefix_list_entry
*pentry
)
2052 struct route_node
*rn
= NULL
;
2053 struct list
*rmap_candidate_list
= NULL
;
2055 rn
= route_node_lookup(table
, &pentry
->prefix
);
2056 if (!rn
|| !rn
->info
)
2059 rmap_candidate_list
= (struct list
*)rn
->info
;
2061 listnode_delete(rmap_candidate_list
, index
);
2063 if (listcount(rmap_candidate_list
) == 0) {
2064 list_delete(&rmap_candidate_list
);
2066 route_unlock_node(rn
);
2068 route_unlock_node(rn
);
2071 /* This function checks for the presence of an IPv4 prefix-list
2072 * match rule in the given route-map index.
2074 static bool route_map_is_ip_pfx_list_rule_present(struct route_map_index
*index
)
2076 struct route_map_rule_list
*match_list
= NULL
;
2077 struct route_map_rule
*rule
= NULL
;
2079 match_list
= &index
->match_list
;
2080 for (rule
= match_list
->head
; rule
; rule
= rule
->next
)
2081 if (IS_RULE_IPv4_PREFIX_LIST(rule
->cmd
->str
))
2087 /* This function checks for the presence of an IPv6 prefix-list
2088 * match rule in the given route-map index.
2091 route_map_is_ipv6_pfx_list_rule_present(struct route_map_index
*index
)
2093 struct route_map_rule_list
*match_list
= NULL
;
2094 struct route_map_rule
*rule
= NULL
;
2096 match_list
= &index
->match_list
;
2097 for (rule
= match_list
->head
; rule
; rule
= rule
->next
)
2098 if (IS_RULE_IPv6_PREFIX_LIST(rule
->cmd
->str
))
2104 /* This function does the following:
2105 * 1) If plist_name is not present, search for a IPv4 or IPv6 prefix-list
2106 * match clause (based on the afi passed to this foo) and get the
2108 * 2) Look up the prefix-list using the name.
2109 * 3) If the prefix-list is not found then, add the index to the IPv4/IPv6
2110 * default-route's node in the trie (based on the afi passed to this foo).
2111 * 4) If the prefix-list is found then, remove the index from the IPv4/IPv6
2112 * default-route's node in the trie (based on the afi passed to this foo).
2113 * 5) If a prefix-entry is passed then, create a route-node for this entry and
2114 * add this index to the route-node.
2115 * 6) If prefix-entry is not passed then, for every prefix-entry in the
2116 * prefix-list, create a route-node for this entry and
2117 * add this index to the route-node.
2119 static void route_map_add_plist_entries(afi_t afi
,
2120 struct route_map_index
*index
,
2121 const char *plist_name
,
2122 struct prefix_list_entry
*entry
)
2124 struct route_map_rule_list
*match_list
= NULL
;
2125 struct route_map_rule
*match
= NULL
;
2126 struct prefix_list
*plist
= NULL
;
2127 struct prefix_list_entry
*pentry
= NULL
;
2128 bool plist_rule_is_present
= false;
2131 match_list
= &index
->match_list
;
2133 for (match
= match_list
->head
; match
; match
= match
->next
) {
2134 if (afi
== AFI_IP
) {
2135 if (IS_RULE_IPv4_PREFIX_LIST(match
->cmd
->str
)) {
2136 plist_rule_is_present
= true;
2140 if (IS_RULE_IPv6_PREFIX_LIST(match
->cmd
->str
)) {
2141 plist_rule_is_present
= true;
2147 if (plist_rule_is_present
)
2148 plist
= prefix_list_lookup(afi
, match
->rule_str
);
2150 plist
= prefix_list_lookup(afi
, plist_name
);
2154 route_map_pfx_table_add_default(afi
, index
);
2158 /* Default entry should be deleted only if the first entry of the
2159 * prefix-list is created.
2162 if (plist
->count
== 1)
2163 route_map_pfx_table_del_default(afi
, index
);
2165 route_map_pfx_table_del_default(afi
, index
);
2169 if (afi
== AFI_IP
) {
2170 route_map_pfx_table_add(index
->map
->ipv4_prefix_table
,
2173 route_map_pfx_table_add(index
->map
->ipv6_prefix_table
,
2177 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
2178 if (afi
== AFI_IP
) {
2179 route_map_pfx_table_add(
2180 index
->map
->ipv4_prefix_table
, index
,
2183 route_map_pfx_table_add(
2184 index
->map
->ipv6_prefix_table
, index
,
2191 /* This function does the following:
2192 * 1) If plist_name is not present, search for a IPv4 or IPv6 prefix-list
2193 * match clause (based on the afi passed to this foo) and get the
2195 * 2) Look up the prefix-list using the name.
2196 * 3) If the prefix-list is not found then, delete the index from the IPv4/IPv6
2197 * default-route's node in the trie (based on the afi passed to this foo).
2198 * 4) If a prefix-entry is passed then, remove this index from the route-node
2199 * for the prefix in this prefix-entry.
2200 * 5) If prefix-entry is not passed then, for every prefix-entry in the
2201 * prefix-list, remove this index from the route-node
2202 * for the prefix in this prefix-entry.
2204 static void route_map_del_plist_entries(afi_t afi
,
2205 struct route_map_index
*index
,
2206 const char *plist_name
,
2207 struct prefix_list_entry
*entry
)
2209 struct route_map_rule_list
*match_list
= NULL
;
2210 struct route_map_rule
*match
= NULL
;
2211 struct prefix_list
*plist
= NULL
;
2212 struct prefix_list_entry
*pentry
= NULL
;
2213 bool plist_rule_is_present
= false;
2216 match_list
= &index
->match_list
;
2218 for (match
= match_list
->head
; match
; match
= match
->next
) {
2219 if (afi
== AFI_IP
) {
2220 if (IS_RULE_IPv4_PREFIX_LIST(match
->cmd
->str
)) {
2221 plist_rule_is_present
= true;
2225 if (IS_RULE_IPv6_PREFIX_LIST(match
->cmd
->str
)) {
2226 plist_rule_is_present
= true;
2232 if (plist_rule_is_present
)
2233 plist
= prefix_list_lookup(afi
, match
->rule_str
);
2235 plist
= prefix_list_lookup(afi
, plist_name
);
2239 route_map_pfx_table_del_default(afi
, index
);
2244 if (afi
== AFI_IP
) {
2245 route_map_pfx_table_del(index
->map
->ipv4_prefix_table
,
2248 route_map_pfx_table_del(index
->map
->ipv6_prefix_table
,
2252 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
2253 if (afi
== AFI_IP
) {
2254 route_map_pfx_table_del(
2255 index
->map
->ipv4_prefix_table
, index
,
2258 route_map_pfx_table_del(
2259 index
->map
->ipv6_prefix_table
, index
,
2267 * This function handles the cases where a prefix-list is added/removed
2268 * as a match command from a particular route-map index.
2269 * It updates the prefix-table of the route-map accordingly.
2271 static void route_map_trie_update(afi_t afi
, route_map_event_t event
,
2272 struct route_map_index
*index
,
2273 const char *plist_name
)
2275 if (event
== RMAP_EVENT_PLIST_ADDED
) {
2276 if (afi
== AFI_IP
) {
2277 if (!route_map_is_ipv6_pfx_list_rule_present(index
)) {
2278 route_map_pfx_table_del_default(AFI_IP6
, index
);
2279 route_map_add_plist_entries(afi
, index
,
2282 route_map_del_plist_entries(AFI_IP6
, index
,
2286 if (!route_map_is_ip_pfx_list_rule_present(index
)) {
2287 route_map_pfx_table_del_default(AFI_IP
, index
);
2288 route_map_add_plist_entries(afi
, index
,
2291 route_map_del_plist_entries(AFI_IP
, index
, NULL
,
2295 } else if (event
== RMAP_EVENT_PLIST_DELETED
) {
2296 if (afi
== AFI_IP
) {
2297 route_map_del_plist_entries(afi
, index
, plist_name
,
2300 /* If IPv6 prefix-list match rule is not present,
2301 * add this index to the IPv4 default route's trie
2303 * Also, add this index to the trie nodes created
2304 * for each of the prefix-entries within the IPv6
2305 * prefix-list, if the IPv6 prefix-list match rule
2306 * is present. Else, add this index to the IPv6
2307 * default route's trie node.
2309 if (!route_map_is_ipv6_pfx_list_rule_present(index
))
2310 route_map_pfx_table_add_default(afi
, index
);
2312 route_map_add_plist_entries(AFI_IP6
, index
, NULL
, NULL
);
2314 route_map_del_plist_entries(afi
, index
, plist_name
,
2317 /* If IPv4 prefix-list match rule is not present,
2318 * add this index to the IPv6 default route's trie
2320 * Also, add this index to the trie nodes created
2321 * for each of the prefix-entries within the IPv4
2322 * prefix-list, if the IPv4 prefix-list match rule
2323 * is present. Else, add this index to the IPv4
2324 * default route's trie node.
2326 if (!route_map_is_ip_pfx_list_rule_present(index
))
2327 route_map_pfx_table_add_default(afi
, index
);
2329 route_map_add_plist_entries(AFI_IP
, index
, NULL
, NULL
);
2335 * This function handles the cases where a route-map index and
2336 * prefix-list is added/removed.
2337 * It updates the prefix-table of the route-map accordingly.
2339 static void route_map_pfx_tbl_update(route_map_event_t event
,
2340 struct route_map_index
*index
, afi_t afi
,
2341 const char *plist_name
)
2346 if (event
== RMAP_EVENT_INDEX_ADDED
) {
2347 route_map_pfx_table_add_default(AFI_IP
, index
);
2348 route_map_pfx_table_add_default(AFI_IP6
, index
);
2352 if (event
== RMAP_EVENT_INDEX_DELETED
) {
2353 route_map_pfx_table_del_default(AFI_IP
, index
);
2354 route_map_pfx_table_del_default(AFI_IP6
, index
);
2359 /* Handle prefix-list match rule addition/deletion.
2361 route_map_trie_update(afi
, event
, index
, plist_name
);
2365 * This function handles the cases where a new prefix-entry is added to
2366 * a prefix-list or, an existing prefix-entry is removed from the prefix-list.
2367 * It updates the prefix-table of the route-map accordingly.
2369 static void route_map_pentry_update(route_map_event_t event
,
2370 const char *plist_name
,
2371 struct route_map_index
*index
,
2372 struct prefix_list_entry
*pentry
)
2374 struct prefix_list
*plist
= NULL
;
2376 unsigned char family
= pentry
->prefix
.family
;
2378 if (family
== AF_INET
) {
2380 plist
= prefix_list_lookup(AFI_IP
, plist_name
);
2383 plist
= prefix_list_lookup(AFI_IP6
, plist_name
);
2386 if (event
== RMAP_EVENT_PLIST_ADDED
) {
2387 if (afi
== AFI_IP
) {
2388 if (!route_map_is_ipv6_pfx_list_rule_present(index
))
2389 route_map_add_plist_entries(afi
, index
,
2390 plist_name
, pentry
);
2392 if (!route_map_is_ip_pfx_list_rule_present(index
))
2393 route_map_add_plist_entries(afi
, index
,
2394 plist_name
, pentry
);
2396 } else if (event
== RMAP_EVENT_PLIST_DELETED
) {
2397 route_map_del_plist_entries(afi
, index
, plist_name
, pentry
);
2399 if (plist
->count
== 1) {
2400 if (afi
== AFI_IP
) {
2401 if (!route_map_is_ipv6_pfx_list_rule_present(
2403 route_map_pfx_table_add_default(afi
,
2406 if (!route_map_is_ip_pfx_list_rule_present(
2408 route_map_pfx_table_add_default(afi
,
2415 static void route_map_pentry_process_dependency(struct hash_bucket
*bucket
,
2418 char *rmap_name
= NULL
;
2419 struct route_map
*rmap
= NULL
;
2420 struct route_map_index
*index
= NULL
;
2421 struct route_map_rule_list
*match_list
= NULL
;
2422 struct route_map_rule
*match
= NULL
;
2423 struct route_map_dep_data
*dep_data
= NULL
;
2424 struct route_map_pentry_dep
*pentry_dep
=
2425 (struct route_map_pentry_dep
*)data
;
2426 unsigned char family
= pentry_dep
->pentry
->prefix
.family
;
2428 dep_data
= (struct route_map_dep_data
*)bucket
->data
;
2432 rmap_name
= dep_data
->rname
;
2433 rmap
= route_map_lookup_by_name(rmap_name
);
2434 if (!rmap
|| !rmap
->head
)
2437 for (index
= rmap
->head
; index
; index
= index
->next
) {
2438 match_list
= &index
->match_list
;
2443 for (match
= match_list
->head
; match
; match
= match
->next
) {
2444 if (strcmp(match
->rule_str
, pentry_dep
->plist_name
)
2446 if (IS_RULE_IPv4_PREFIX_LIST(match
->cmd
->str
)
2447 && family
== AF_INET
) {
2448 route_map_pentry_update(
2450 pentry_dep
->plist_name
, index
,
2451 pentry_dep
->pentry
);
2452 } else if (IS_RULE_IPv6_PREFIX_LIST(
2454 && family
== AF_INET6
) {
2455 route_map_pentry_update(
2457 pentry_dep
->plist_name
, index
,
2458 pentry_dep
->pentry
);
2465 void route_map_notify_pentry_dependencies(const char *affected_name
,
2466 struct prefix_list_entry
*pentry
,
2467 route_map_event_t event
)
2469 struct route_map_dep
*dep
= NULL
;
2470 struct hash
*upd8_hash
= NULL
;
2471 struct route_map_pentry_dep pentry_dep
;
2473 if (!affected_name
|| !pentry
)
2476 upd8_hash
= route_map_get_dep_hash(event
);
2480 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, (void *)affected_name
,
2483 if (!dep
->this_hash
)
2484 dep
->this_hash
= upd8_hash
;
2486 memset(&pentry_dep
, 0, sizeof(pentry_dep
));
2487 pentry_dep
.pentry
= pentry
;
2488 pentry_dep
.plist_name
= affected_name
;
2489 pentry_dep
.event
= event
;
2491 hash_iterate(dep
->dep_rmap_hash
,
2492 route_map_pentry_process_dependency
,
2493 (void *)&pentry_dep
);
2497 /* Apply route map's each index to the object.
2499 The matrix for a route-map looks like this:
2500 (note, this includes the description for the "NEXT"
2501 and "GOTO" frobs now
2503 | Match | No Match | No op
2504 |-----------|--------------|-------
2505 permit | action | cont | cont.
2506 | | default:deny | default:permit
2507 -------------------+-----------------------
2508 | deny | cont | cont.
2509 deny | | default:deny | default:permit
2510 |-----------|--------------|--------
2513 -Apply Set statements, accept route
2514 -If Call statement is present jump to the specified route-map, if it
2515 denies the route we finish.
2516 -If NEXT is specified, goto NEXT statement
2517 -If GOTO is specified, goto the first clause where pref > nextpref
2518 -If nothing is specified, do as Cisco and finish
2520 -Route is denied by route-map.
2524 If we get no matches after we've processed all updates, then the route
2527 Some notes on the new "CALL", "NEXT" and "GOTO"
2528 call WORD - If this clause is matched, then the set statements
2529 are executed and then we jump to route-map 'WORD'. If
2530 this route-map denies the route, we finish, in other
2532 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
2533 on-match next - If this clause is matched, then the set statements
2534 are executed and then we drop through to the next clause
2535 on-match goto n - If this clause is matched, then the set statements
2536 are executed and then we goto the nth clause, or the
2537 first clause greater than this. In order to ensure
2538 route-maps *always* exit, you cannot jump backwards.
2541 We need to make sure our route-map processing matches the above
2543 route_map_result_t
route_map_apply_ext(struct route_map
*map
,
2544 const struct prefix
*prefix
,
2545 void *match_object
, void *set_object
,
2548 static int recursion
= 0;
2549 enum route_map_cmd_result_t match_ret
= RMAP_NOMATCH
;
2550 route_map_result_t ret
= RMAP_PERMITMATCH
;
2551 struct route_map_index
*index
= NULL
;
2552 struct route_map_rule
*set
= NULL
;
2553 bool skip_match_clause
= false;
2556 if (recursion
> RMAP_RECURSION_LIMIT
) {
2558 EC_LIB_RMAP_RECURSION_LIMIT
,
2559 "route-map recursion limit (%d) reached, discarding route",
2560 RMAP_RECURSION_LIMIT
);
2562 return RMAP_DENYMATCH
;
2565 if (map
== NULL
|| map
->head
== NULL
) {
2566 ret
= RMAP_DENYMATCH
;
2567 goto route_map_apply_end
;
2573 * Handling for matching evpn_routes in the prefix table.
2575 * We convert type2/5 prefix to ipv4/6 prefix to do longest
2576 * prefix matching on.
2578 if (prefix
->family
== AF_EVPN
) {
2579 if (evpn_prefix2prefix(prefix
, &conv
) != 0) {
2580 if (unlikely(CHECK_FLAG(rmap_debug
,
2581 DEBUG_ROUTEMAP_DETAIL
)))
2583 "Unable to convert EVPN prefix %pFX into IPv4/IPv6 prefix. Falling back to non-optimized route-map lookup",
2586 if (unlikely(CHECK_FLAG(rmap_debug
,
2587 DEBUG_ROUTEMAP_DETAIL
)))
2589 "Converted EVPN prefix %pFX into %pFX for optimized route-map lookup",
2596 index
= route_map_get_index(map
, prefix
, match_object
, &match_ret
);
2599 if (unlikely(CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
)))
2601 "Best match route-map: %s, sequence: %d for pfx: %pFX, result: %s",
2602 map
->name
, index
->pref
, prefix
,
2603 route_map_cmd_result_str(match_ret
));
2605 if (unlikely(CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
)))
2607 "No best match sequence for pfx: %pFX in route-map: %s, result: %s",
2609 route_map_cmd_result_str(match_ret
));
2611 * No index matches this prefix. Return deny unless,
2612 * match_ret = RMAP_NOOP.
2614 if (match_ret
== RMAP_NOOP
)
2615 ret
= RMAP_PERMITMATCH
;
2617 ret
= RMAP_DENYMATCH
;
2618 goto route_map_apply_end
;
2620 skip_match_clause
= true;
2622 for (; index
; index
= index
->next
) {
2623 if (!skip_match_clause
) {
2625 /* Apply this index. */
2626 match_ret
= route_map_apply_match(&index
->match_list
,
2627 prefix
, match_object
);
2628 if (unlikely(CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))) {
2630 "Route-map: %s, sequence: %d, prefix: %pFX, result: %s",
2631 map
->name
, index
->pref
, prefix
,
2632 route_map_cmd_result_str(match_ret
));
2635 skip_match_clause
= false;
2638 /* Now we apply the matrix from above */
2639 if (match_ret
== RMAP_NOOP
)
2641 * Do not change the return value. Retain the previous
2642 * return value. Previous values can be:
2643 * 1)permitmatch (if a nomatch was never
2644 * seen before in this route-map.)
2645 * 2)denymatch (if a nomatch was seen earlier in one
2646 * of the previous sequences)
2650 * 'cont' from matrix - continue to next route-map
2654 else if (match_ret
== RMAP_NOMATCH
) {
2657 * The return value is now changed to denymatch.
2658 * So from here on out, even if we see more noops,
2659 * we retain this return value and return this
2660 * eventually if there are no matches.
2662 ret
= RMAP_DENYMATCH
;
2665 * 'cont' from matrix - continue to next route-map
2669 } else if (match_ret
== RMAP_MATCH
) {
2670 if (index
->type
== RMAP_PERMIT
)
2673 /* Match succeeded, rmap is of type permit */
2674 ret
= RMAP_PERMITMATCH
;
2676 /* permit+match must execute sets */
2677 for (set
= index
->set_list
.head
; set
;
2680 * set cmds return RMAP_OKAY or
2681 * RMAP_ERROR. We do not care if
2682 * set succeeded or not. So, ignore
2685 (void)(*set
->cmd
->func_apply
)(
2686 set
->value
, prefix
, set_object
);
2688 /* Call another route-map if available */
2689 if (index
->nextrm
) {
2690 struct route_map
*nextrm
=
2691 route_map_lookup_by_name(
2694 if (nextrm
) /* Target route-map found,
2698 ret
= route_map_apply_ext(
2705 /* If nextrm returned 'deny', finish. */
2706 if (ret
== RMAP_DENYMATCH
)
2707 goto route_map_apply_end
;
2710 switch (index
->exitpolicy
) {
2712 goto route_map_apply_end
;
2716 /* Find the next clause to jump to */
2717 struct route_map_index
*next
=
2719 int nextpref
= index
->nextpref
;
2721 while (next
&& next
->pref
< nextpref
) {
2726 /* No clauses match! */
2727 goto route_map_apply_end
;
2731 } else if (index
->type
== RMAP_DENY
)
2734 ret
= RMAP_DENYMATCH
;
2735 goto route_map_apply_end
;
2740 route_map_apply_end
:
2741 if (unlikely(CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
)))
2742 zlog_debug("Route-map: %s, prefix: %pFX, result: %s",
2743 (map
? map
->name
: "null"), prefix
,
2744 route_map_result_str(ret
));
2747 if (index
!= NULL
&& ret
== RMAP_PERMITMATCH
)
2748 *pref
= index
->pref
;
2756 void route_map_add_hook(void (*func
)(const char *))
2758 route_map_master
.add_hook
= func
;
2761 void route_map_delete_hook(void (*func
)(const char *))
2763 route_map_master
.delete_hook
= func
;
2766 void route_map_event_hook(void (*func
)(const char *name
))
2768 route_map_master
.event_hook
= func
;
2771 /* Routines for route map dependency lists and dependency processing */
2772 static bool route_map_rmap_hash_cmp(const void *p1
, const void *p2
)
2774 return strcmp(((const struct route_map_dep_data
*)p1
)->rname
,
2775 ((const struct route_map_dep_data
*)p2
)->rname
)
2779 static bool route_map_dep_hash_cmp(const void *p1
, const void *p2
)
2782 return (strcmp(((const struct route_map_dep
*)p1
)->dep_name
,
2787 static void route_map_clear_reference(struct hash_bucket
*bucket
, void *arg
)
2789 struct route_map_dep
*dep
= bucket
->data
;
2790 struct route_map_dep_data
*dep_data
= NULL
, tmp_dep_data
;
2792 memset(&tmp_dep_data
, 0, sizeof(tmp_dep_data
));
2793 tmp_dep_data
.rname
= arg
;
2794 dep_data
= hash_release(dep
->dep_rmap_hash
, &tmp_dep_data
);
2796 if (unlikely(CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
)))
2797 zlog_debug("Clearing reference for %s to %s count: %d",
2798 dep
->dep_name
, tmp_dep_data
.rname
,
2801 XFREE(MTYPE_ROUTE_MAP_NAME
, dep_data
->rname
);
2802 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, dep_data
);
2804 if (!dep
->dep_rmap_hash
->count
) {
2805 dep
= hash_release(dep
->this_hash
, (void *)dep
->dep_name
);
2806 hash_free(dep
->dep_rmap_hash
);
2807 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
2808 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
2812 static void route_map_clear_all_references(char *rmap_name
)
2816 if (unlikely(CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
)))
2817 zlog_debug("Clearing references for %s", rmap_name
);
2819 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
2820 hash_iterate(route_map_dep_hash
[i
], route_map_clear_reference
,
2825 static unsigned int route_map_dep_data_hash_make_key(const void *p
)
2827 const struct route_map_dep_data
*dep_data
= p
;
2829 return string_hash_make(dep_data
->rname
);
2832 static void *route_map_dep_hash_alloc(void *p
)
2834 char *dep_name
= (char *)p
;
2835 struct route_map_dep
*dep_entry
;
2837 dep_entry
= XCALLOC(MTYPE_ROUTE_MAP_DEP
, sizeof(struct route_map_dep
));
2838 dep_entry
->dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
2839 dep_entry
->dep_rmap_hash
=
2840 hash_create_size(8, route_map_dep_data_hash_make_key
,
2841 route_map_rmap_hash_cmp
, "Route Map Dep Hash");
2842 dep_entry
->this_hash
= NULL
;
2847 static void *route_map_name_hash_alloc(void *p
)
2849 struct route_map_dep_data
*dep_data
= NULL
, *tmp_dep_data
= NULL
;
2851 dep_data
= XCALLOC(MTYPE_ROUTE_MAP_DEP_DATA
,
2852 sizeof(struct route_map_dep_data
));
2854 dep_data
->rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, tmp_dep_data
->rname
);
2858 static unsigned int route_map_dep_hash_make_key(const void *p
)
2860 return (string_hash_make((char *)p
));
2863 static void route_map_print_dependency(struct hash_bucket
*bucket
, void *data
)
2865 struct route_map_dep_data
*dep_data
= bucket
->data
;
2866 char *rmap_name
= dep_data
->rname
;
2867 char *dep_name
= data
;
2869 zlog_debug("%s: Dependency for %s: %s", __func__
, dep_name
, rmap_name
);
2872 static int route_map_dep_update(struct hash
*dephash
, const char *dep_name
,
2873 const char *rmap_name
, route_map_event_t type
)
2875 struct route_map_dep
*dep
= NULL
;
2876 char *dname
, *rname
;
2878 struct route_map_dep_data
*dep_data
= NULL
, *ret_dep_data
= NULL
;
2879 struct route_map_dep_data tmp_dep_data
;
2881 dname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
2882 rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
2885 case RMAP_EVENT_PLIST_ADDED
:
2886 case RMAP_EVENT_CLIST_ADDED
:
2887 case RMAP_EVENT_ECLIST_ADDED
:
2888 case RMAP_EVENT_ASLIST_ADDED
:
2889 case RMAP_EVENT_LLIST_ADDED
:
2890 case RMAP_EVENT_CALL_ADDED
:
2891 case RMAP_EVENT_FILTER_ADDED
:
2892 if (unlikely(CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
)))
2893 zlog_debug("Adding dependency for filter %s in route-map %s",
2894 dep_name
, rmap_name
);
2895 dep
= (struct route_map_dep
*)hash_get(
2896 dephash
, dname
, route_map_dep_hash_alloc
);
2902 if (!dep
->this_hash
)
2903 dep
->this_hash
= dephash
;
2905 memset(&tmp_dep_data
, 0, sizeof(tmp_dep_data
));
2906 tmp_dep_data
.rname
= rname
;
2907 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
2909 dep_data
= hash_get(dep
->dep_rmap_hash
, &tmp_dep_data
,
2910 route_map_name_hash_alloc
);
2914 case RMAP_EVENT_PLIST_DELETED
:
2915 case RMAP_EVENT_CLIST_DELETED
:
2916 case RMAP_EVENT_ECLIST_DELETED
:
2917 case RMAP_EVENT_ASLIST_DELETED
:
2918 case RMAP_EVENT_LLIST_DELETED
:
2919 case RMAP_EVENT_CALL_DELETED
:
2920 case RMAP_EVENT_FILTER_DELETED
:
2921 if (unlikely(CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
)))
2922 zlog_debug("Deleting dependency for filter %s in route-map %s",
2923 dep_name
, rmap_name
);
2924 dep
= (struct route_map_dep
*)hash_get(dephash
, dname
, NULL
);
2929 memset(&tmp_dep_data
, 0, sizeof(tmp_dep_data
));
2930 tmp_dep_data
.rname
= rname
;
2931 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
2933 * If dep_data is NULL then something has gone seriously
2934 * wrong in route-map handling. Note it and prevent
2939 "route-map dependency for route-map %s: %s is not correct",
2940 rmap_name
, dep_name
);
2946 if (!dep_data
->refcnt
) {
2947 ret_dep_data
= hash_release(dep
->dep_rmap_hash
,
2950 XFREE(MTYPE_ROUTE_MAP_NAME
,
2951 ret_dep_data
->rname
);
2952 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, ret_dep_data
);
2956 if (!dep
->dep_rmap_hash
->count
) {
2957 dep
= hash_release(dephash
, dname
);
2958 hash_free(dep
->dep_rmap_hash
);
2959 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
2960 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
2963 case RMAP_EVENT_SET_ADDED
:
2964 case RMAP_EVENT_SET_DELETED
:
2965 case RMAP_EVENT_SET_REPLACED
:
2966 case RMAP_EVENT_MATCH_ADDED
:
2967 case RMAP_EVENT_MATCH_DELETED
:
2968 case RMAP_EVENT_MATCH_REPLACED
:
2969 case RMAP_EVENT_INDEX_ADDED
:
2970 case RMAP_EVENT_INDEX_DELETED
:
2975 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
2976 hash_iterate(dep
->dep_rmap_hash
,
2977 route_map_print_dependency
, dname
);
2981 XFREE(MTYPE_ROUTE_MAP_NAME
, rname
);
2982 XFREE(MTYPE_ROUTE_MAP_NAME
, dname
);
2986 static struct hash
*route_map_get_dep_hash(route_map_event_t event
)
2988 struct hash
*upd8_hash
= NULL
;
2991 case RMAP_EVENT_PLIST_ADDED
:
2992 case RMAP_EVENT_PLIST_DELETED
:
2993 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_PLIST
];
2995 case RMAP_EVENT_CLIST_ADDED
:
2996 case RMAP_EVENT_CLIST_DELETED
:
2997 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_CLIST
];
2999 case RMAP_EVENT_ECLIST_ADDED
:
3000 case RMAP_EVENT_ECLIST_DELETED
:
3001 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ECLIST
];
3003 case RMAP_EVENT_ASLIST_ADDED
:
3004 case RMAP_EVENT_ASLIST_DELETED
:
3005 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ASPATH
];
3007 case RMAP_EVENT_LLIST_ADDED
:
3008 case RMAP_EVENT_LLIST_DELETED
:
3009 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_LCLIST
];
3011 case RMAP_EVENT_CALL_ADDED
:
3012 case RMAP_EVENT_CALL_DELETED
:
3013 case RMAP_EVENT_MATCH_ADDED
:
3014 case RMAP_EVENT_MATCH_DELETED
:
3015 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_RMAP
];
3017 case RMAP_EVENT_FILTER_ADDED
:
3018 case RMAP_EVENT_FILTER_DELETED
:
3019 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_FILTER
];
3022 * Should we actually be ignoring these?
3023 * I am not sure but at this point in time, let
3024 * us get them into this switch and we can peel
3025 * them into the appropriate place in the future
3027 case RMAP_EVENT_SET_ADDED
:
3028 case RMAP_EVENT_SET_DELETED
:
3029 case RMAP_EVENT_SET_REPLACED
:
3030 case RMAP_EVENT_MATCH_REPLACED
:
3031 case RMAP_EVENT_INDEX_ADDED
:
3032 case RMAP_EVENT_INDEX_DELETED
:
3039 static void route_map_process_dependency(struct hash_bucket
*bucket
, void *data
)
3041 struct route_map_dep_data
*dep_data
= NULL
;
3042 char *rmap_name
= NULL
;
3044 dep_data
= bucket
->data
;
3045 rmap_name
= dep_data
->rname
;
3047 if (unlikely(CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
)))
3048 zlog_debug("Notifying %s of dependency", rmap_name
);
3049 if (route_map_master
.event_hook
)
3050 (*route_map_master
.event_hook
)(rmap_name
);
3053 void route_map_upd8_dependency(route_map_event_t type
, const char *arg
,
3054 const char *rmap_name
)
3056 struct hash
*upd8_hash
= NULL
;
3058 if ((upd8_hash
= route_map_get_dep_hash(type
))) {
3059 route_map_dep_update(upd8_hash
, arg
, rmap_name
, type
);
3061 if (type
== RMAP_EVENT_CALL_ADDED
) {
3063 if (route_map_master
.add_hook
)
3064 (*route_map_master
.add_hook
)(rmap_name
);
3065 } else if (type
== RMAP_EVENT_CALL_DELETED
) {
3067 if (route_map_master
.delete_hook
)
3068 (*route_map_master
.delete_hook
)(rmap_name
);
3073 void route_map_notify_dependencies(const char *affected_name
,
3074 route_map_event_t event
)
3076 struct route_map_dep
*dep
;
3077 struct hash
*upd8_hash
;
3083 name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, affected_name
);
3085 if ((upd8_hash
= route_map_get_dep_hash(event
)) == NULL
) {
3086 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
3090 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, name
, NULL
);
3092 if (!dep
->this_hash
)
3093 dep
->this_hash
= upd8_hash
;
3095 if (unlikely(CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
)))
3096 zlog_debug("Filter %s updated", dep
->dep_name
);
3097 hash_iterate(dep
->dep_rmap_hash
, route_map_process_dependency
,
3101 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
3104 /* VTY related functions. */
3105 static void clear_route_map_helper(struct route_map
*map
)
3107 struct route_map_index
*index
;
3109 map
->applied_clear
= map
->applied
;
3110 for (index
= map
->head
; index
; index
= index
->next
)
3111 index
->applied_clear
= index
->applied
;
3114 DEFPY (rmap_clear_counters
,
3115 rmap_clear_counters_cmd
,
3116 "clear route-map counters [RMAP_NAME$rmapname]",
3118 "route-map information\n"
3119 "counters associated with the specified route-map\n"
3122 struct route_map
*map
;
3125 map
= route_map_lookup_by_name(rmapname
);
3128 clear_route_map_helper(map
);
3130 vty_out(vty
, "%s: 'route-map %s' not found\n",
3131 frr_protonameinst
, rmapname
);
3135 for (map
= route_map_master
.head
; map
; map
= map
->next
)
3136 clear_route_map_helper(map
);
3143 DEFUN (rmap_show_name
,
3145 "show route-map [WORD] [json]",
3147 "route-map information\n"
3151 bool uj
= use_json(argc
, argv
);
3153 const char *name
= NULL
;
3155 if (argv_find(argv
, argc
, "WORD", &idx
))
3156 name
= argv
[idx
]->arg
;
3158 return vty_show_route_map(vty
, name
, uj
);
3161 DEFUN (rmap_show_unused
,
3162 rmap_show_unused_cmd
,
3163 "show route-map-unused",
3165 "unused route-map information\n")
3167 return vty_show_unused_route_map(vty
);
3172 "debug route-map [detail]$detail",
3174 "Debug option set for route-maps\n"
3175 "Detailed output\n")
3178 SET_FLAG(rmap_debug
, DEBUG_ROUTEMAP
);
3180 SET_FLAG(rmap_debug
, DEBUG_ROUTEMAP
| DEBUG_ROUTEMAP_DETAIL
);
3185 DEFPY (no_debug_rmap
,
3187 "no debug route-map [detail]$detail",
3190 "Debug option set for route-maps\n"
3191 "Detailed output\n")
3194 UNSET_FLAG(rmap_debug
, DEBUG_ROUTEMAP
);
3196 UNSET_FLAG(rmap_debug
, DEBUG_ROUTEMAP
| DEBUG_ROUTEMAP_DETAIL
);
3202 static int rmap_config_write_debug(struct vty
*vty
);
3203 static struct cmd_node rmap_debug_node
= {
3204 .name
= "route-map debug",
3205 .node
= RMAP_DEBUG_NODE
,
3207 .config_write
= rmap_config_write_debug
,
3210 void route_map_show_debug(struct vty
*vty
)
3212 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
3213 vty_out(vty
, "debug route-map\n");
3216 /* Configuration write function. */
3217 static int rmap_config_write_debug(struct vty
*vty
)
3221 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
)) {
3222 vty_out(vty
, "debug route-map\n");
3229 /* Common route map rules */
3231 void *route_map_rule_tag_compile(const char *arg
)
3233 unsigned long int tmp
;
3238 tmp
= strtoul(arg
, &endptr
, 0);
3239 if (arg
[0] == '\0' || *endptr
!= '\0' || errno
|| tmp
> ROUTE_TAG_MAX
)
3242 tag
= XMALLOC(MTYPE_ROUTE_MAP_COMPILED
, sizeof(*tag
));
3248 void route_map_rule_tag_free(void *rule
)
3250 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
3253 void route_map_finish(void)
3256 struct route_map_rule_cmd_proxy
*proxy
;
3258 /* these 2 hash tables have INIT_HASH initializers, so the "default"
3259 * state is "initialized & empty" => fini() followed by init() to
3260 * return to that same state
3262 while ((proxy
= rmap_cmd_name_pop(rmap_match_cmds
)))
3264 rmap_cmd_name_fini(rmap_match_cmds
);
3265 rmap_cmd_name_init(rmap_match_cmds
);
3267 while ((proxy
= rmap_cmd_name_pop(rmap_set_cmds
)))
3269 rmap_cmd_name_fini(rmap_set_cmds
);
3270 rmap_cmd_name_init(rmap_set_cmds
);
3273 * All protocols are setting these to NULL
3274 * by default on shutdown( route_map_finish )
3275 * Why are we making them do this work?
3277 route_map_master
.add_hook
= NULL
;
3278 route_map_master
.delete_hook
= NULL
;
3279 route_map_master
.event_hook
= NULL
;
3281 /* cleanup route_map */
3282 while (route_map_master
.head
) {
3283 struct route_map
*map
= route_map_master
.head
;
3284 map
->to_be_processed
= false;
3285 route_map_delete(map
);
3288 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
3289 hash_free(route_map_dep_hash
[i
]);
3290 route_map_dep_hash
[i
] = NULL
;
3293 hash_free(route_map_master_hash
);
3294 route_map_master_hash
= NULL
;
3297 /* Increment the use_count counter while attaching the route map */
3298 void route_map_counter_increment(struct route_map
*map
)
3304 /* Decrement the use_count counter while detaching the route map. */
3305 void route_map_counter_decrement(struct route_map
*map
)
3308 if (map
->use_count
<= 0)
3314 DEFUN_HIDDEN(show_route_map_pfx_tbl
, show_route_map_pfx_tbl_cmd
,
3315 "show route-map RMAP_NAME prefix-table",
3319 "internal prefix-table\n")
3321 const char *rmap_name
= argv
[2]->arg
;
3322 struct route_map
*rmap
= NULL
;
3323 struct route_table
*rm_pfx_tbl4
= NULL
;
3324 struct route_table
*rm_pfx_tbl6
= NULL
;
3325 struct route_node
*rn
= NULL
, *prn
= NULL
;
3326 struct list
*rmap_index_list
= NULL
;
3327 struct listnode
*ln
= NULL
, *nln
= NULL
;
3328 struct route_map_index
*index
= NULL
;
3331 vty_out(vty
, "%s:\n", frr_protonameinst
);
3332 rmap
= route_map_lookup_by_name(rmap_name
);
3334 rm_pfx_tbl4
= rmap
->ipv4_prefix_table
;
3336 vty_out(vty
, "\n%s%43s%s\n", "IPv4 Prefix", "",
3337 "Route-map Index List");
3338 vty_out(vty
, "%s%39s%s\n", "_______________", "",
3339 "____________________");
3340 for (rn
= route_top(rm_pfx_tbl4
); rn
;
3341 rn
= route_next(rn
)) {
3342 vty_out(vty
, " %pRN (%d)\n", rn
,
3343 route_node_get_lock_count(rn
));
3345 vty_out(vty
, "(P) ");
3348 vty_out(vty
, "%pRN\n", prn
);
3352 rmap_index_list
= (struct list
*)rn
->info
;
3353 if (!rmap_index_list
3354 || !listcount(rmap_index_list
))
3355 vty_out(vty
, "%*s%s\n", len
, "", "-");
3357 for (ALL_LIST_ELEMENTS(rmap_index_list
,
3360 vty_out(vty
, "%*s%s seq %d\n",
3369 rm_pfx_tbl6
= rmap
->ipv6_prefix_table
;
3371 vty_out(vty
, "\n%s%43s%s\n", "IPv6 Prefix", "",
3372 "Route-map Index List");
3373 vty_out(vty
, "%s%39s%s\n", "_______________", "",
3374 "____________________");
3375 for (rn
= route_top(rm_pfx_tbl6
); rn
;
3376 rn
= route_next(rn
)) {
3377 vty_out(vty
, " %pRN (%d)\n", rn
,
3378 route_node_get_lock_count(rn
));
3380 vty_out(vty
, "(P) ");
3383 vty_out(vty
, "%pRN\n", prn
);
3387 rmap_index_list
= (struct list
*)rn
->info
;
3388 if (!rmap_index_list
3389 || !listcount(rmap_index_list
))
3390 vty_out(vty
, "%*s%s\n", len
, "", "-");
3392 for (ALL_LIST_ELEMENTS(rmap_index_list
,
3395 vty_out(vty
, "%*s%s seq %d\n",
3409 /* Initialization of route map vector. */
3410 void route_map_init(void)
3414 route_map_master_hash
=
3415 hash_create_size(8, route_map_hash_key_make
, route_map_hash_cmp
,
3416 "Route Map Master Hash");
3418 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++)
3419 route_map_dep_hash
[i
] = hash_create_size(
3420 8, route_map_dep_hash_make_key
, route_map_dep_hash_cmp
,
3421 "Route Map Dep Hash");
3423 UNSET_FLAG(rmap_debug
, DEBUG_ROUTEMAP
);
3425 route_map_cli_init();
3427 /* Install route map top node. */
3428 install_node(&rmap_debug_node
);
3430 /* Install route map commands. */
3431 install_element(CONFIG_NODE
, &debug_rmap_cmd
);
3432 install_element(CONFIG_NODE
, &no_debug_rmap_cmd
);
3434 /* Install show command */
3435 install_element(ENABLE_NODE
, &rmap_clear_counters_cmd
);
3437 install_element(ENABLE_NODE
, &rmap_show_name_cmd
);
3438 install_element(ENABLE_NODE
, &rmap_show_unused_cmd
);
3440 install_element(ENABLE_NODE
, &debug_rmap_cmd
);
3441 install_element(ENABLE_NODE
, &no_debug_rmap_cmd
);
3443 install_element(ENABLE_NODE
, &show_route_map_pfx_tbl_cmd
);