2 * Copyright (C) 1998, 1999 Kunihiro Ishiguro
4 * This file is part of GNU Zebra.
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
34 #include "lib_errors.h"
39 #include "lib/routemap_clippy.c"
41 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP
, "Route map");
42 DEFINE_MTYPE(LIB
, ROUTE_MAP_NAME
, "Route map name");
43 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_INDEX
, "Route map index");
44 DEFINE_MTYPE(LIB
, ROUTE_MAP_RULE
, "Route map rule");
45 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_RULE_STR
, "Route map rule str");
46 DEFINE_MTYPE(LIB
, ROUTE_MAP_COMPILED
, "Route map compiled");
47 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_DEP
, "Route map dependency");
48 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_DEP_DATA
, "Route map dependency data");
50 DEFINE_QOBJ_TYPE(route_map_index
);
51 DEFINE_QOBJ_TYPE(route_map
);
53 static int rmap_cmd_name_cmp(const struct route_map_rule_cmd_proxy
*a
,
54 const struct route_map_rule_cmd_proxy
*b
)
56 return strcmp(a
->cmd
->str
, b
->cmd
->str
);
59 static uint32_t rmap_cmd_name_hash(const struct route_map_rule_cmd_proxy
*item
)
61 return jhash(item
->cmd
->str
, strlen(item
->cmd
->str
), 0xbfd69320);
64 DECLARE_HASH(rmap_cmd_name
, struct route_map_rule_cmd_proxy
, itm
,
65 rmap_cmd_name_cmp
, rmap_cmd_name_hash
);
67 static struct rmap_cmd_name_head rmap_match_cmds
[1] = {
68 INIT_HASH(rmap_match_cmds
[0]),
70 static struct rmap_cmd_name_head rmap_set_cmds
[1] = {
71 INIT_HASH(rmap_set_cmds
[0]),
74 #define IPv4_PREFIX_LIST "ip address prefix-list"
75 #define IPv6_PREFIX_LIST "ipv6 address prefix-list"
77 #define IS_RULE_IPv4_PREFIX_LIST(S) \
78 (strncmp(S, IPv4_PREFIX_LIST, strlen(IPv4_PREFIX_LIST)) == 0)
79 #define IS_RULE_IPv6_PREFIX_LIST(S) \
80 (strncmp(S, IPv6_PREFIX_LIST, strlen(IPv6_PREFIX_LIST)) == 0)
82 struct route_map_pentry_dep
{
83 struct prefix_list_entry
*pentry
;
84 const char *plist_name
;
85 route_map_event_t event
;
88 static void route_map_pfx_tbl_update(route_map_event_t event
,
89 struct route_map_index
*index
, afi_t afi
,
90 const char *plist_name
);
91 static void route_map_pfx_table_add_default(afi_t afi
,
92 struct route_map_index
*index
);
93 static void route_map_pfx_table_del_default(afi_t afi
,
94 struct route_map_index
*index
);
95 static void route_map_add_plist_entries(afi_t afi
,
96 struct route_map_index
*index
,
97 const char *plist_name
,
98 struct prefix_list_entry
*entry
);
99 static void route_map_del_plist_entries(afi_t afi
,
100 struct route_map_index
*index
,
101 const char *plist_name
,
102 struct prefix_list_entry
*entry
);
104 static struct hash
*route_map_get_dep_hash(route_map_event_t event
);
105 static void route_map_free_map(struct route_map
*map
);
107 struct route_map_match_set_hooks rmap_match_set_hook
;
109 /* match interface */
110 void route_map_match_interface_hook(int (*func
)(
111 struct route_map_index
*index
, const char *command
,
112 const char *arg
, route_map_event_t type
,
113 char *errmsg
, size_t errmsg_len
))
115 rmap_match_set_hook
.match_interface
= func
;
118 /* no match interface */
119 void route_map_no_match_interface_hook(int (*func
)(
120 struct route_map_index
*index
, const char *command
,
121 const char *arg
, route_map_event_t type
,
122 char *errmsg
, size_t errmsg_len
))
124 rmap_match_set_hook
.no_match_interface
= func
;
127 /* match ip address */
128 void route_map_match_ip_address_hook(int (*func
)(
129 struct route_map_index
*index
, const char *command
,
130 const char *arg
, route_map_event_t type
,
131 char *errmsg
, size_t errmsg_len
))
133 rmap_match_set_hook
.match_ip_address
= func
;
136 /* no match ip address */
137 void route_map_no_match_ip_address_hook(int (*func
)(
138 struct route_map_index
*index
, const char *command
,
139 const char *arg
, route_map_event_t type
,
140 char *errmsg
, size_t errmsg_len
))
142 rmap_match_set_hook
.no_match_ip_address
= func
;
145 /* match ip address prefix list */
146 void route_map_match_ip_address_prefix_list_hook(int (*func
)(
147 struct route_map_index
*index
, const char *command
,
148 const char *arg
, route_map_event_t type
,
149 char *errmsg
, size_t errmsg_len
))
151 rmap_match_set_hook
.match_ip_address_prefix_list
= func
;
154 /* no match ip address prefix list */
155 void route_map_no_match_ip_address_prefix_list_hook(int (*func
)(
156 struct route_map_index
*index
, const char *command
,
157 const char *arg
, route_map_event_t type
,
158 char *errmsg
, size_t errmsg_len
))
160 rmap_match_set_hook
.no_match_ip_address_prefix_list
= func
;
163 /* match ip next hop */
164 void route_map_match_ip_next_hop_hook(int (*func
)(
165 struct route_map_index
*index
, const char *command
,
166 const char *arg
, route_map_event_t type
,
167 char *errmsg
, size_t errmsg_len
))
169 rmap_match_set_hook
.match_ip_next_hop
= func
;
172 /* no match ip next hop */
173 void route_map_no_match_ip_next_hop_hook(int (*func
)(
174 struct route_map_index
*index
, const char *command
,
175 const char *arg
, route_map_event_t type
,
176 char *errmsg
, size_t errmsg_len
))
178 rmap_match_set_hook
.no_match_ip_next_hop
= func
;
181 /* match ipv6 next-hop */
182 void route_map_match_ipv6_next_hop_hook(int (*func
)(
183 struct route_map_index
*index
, const char *command
, const char *arg
,
184 route_map_event_t type
, char *errmsg
, size_t errmsg_len
))
186 rmap_match_set_hook
.match_ipv6_next_hop
= func
;
189 /* no match ipv6 next-hop */
190 void route_map_no_match_ipv6_next_hop_hook(int (*func
)(
191 struct route_map_index
*index
, const char *command
, const char *arg
,
192 route_map_event_t type
, char *errmsg
, size_t errmsg_len
))
194 rmap_match_set_hook
.no_match_ipv6_next_hop
= func
;
197 /* match ip next hop prefix list */
198 void route_map_match_ip_next_hop_prefix_list_hook(int (*func
)(
199 struct route_map_index
*index
, const char *command
,
200 const char *arg
, route_map_event_t type
,
201 char *errmsg
, size_t errmsg_len
))
203 rmap_match_set_hook
.match_ip_next_hop_prefix_list
= func
;
206 /* no match ip next hop prefix list */
207 void route_map_no_match_ip_next_hop_prefix_list_hook(int (*func
)(
208 struct route_map_index
*index
, const char *command
,
209 const char *arg
, route_map_event_t type
,
210 char *errmsg
, size_t errmsg_len
))
212 rmap_match_set_hook
.no_match_ip_next_hop_prefix_list
= func
;
215 /* match ip next-hop type */
216 void route_map_match_ip_next_hop_type_hook(int (*func
)(
217 struct route_map_index
*index
, const char *command
,
218 const char *arg
, route_map_event_t type
,
219 char *errmsg
, size_t errmsg_len
))
221 rmap_match_set_hook
.match_ip_next_hop_type
= func
;
224 /* no match ip next-hop type */
225 void route_map_no_match_ip_next_hop_type_hook(int (*func
)(
226 struct route_map_index
*index
, const char *command
,
227 const char *arg
, route_map_event_t type
,
228 char *errmsg
, size_t errmsg_len
))
230 rmap_match_set_hook
.no_match_ip_next_hop_type
= func
;
233 /* match ipv6 address */
234 void route_map_match_ipv6_address_hook(int (*func
)(
235 struct route_map_index
*index
, const char *command
,
236 const char *arg
, route_map_event_t type
,
237 char *errmsg
, size_t errmsg_len
))
239 rmap_match_set_hook
.match_ipv6_address
= func
;
242 /* no match ipv6 address */
243 void route_map_no_match_ipv6_address_hook(int (*func
)(
244 struct route_map_index
*index
, const char *command
,
245 const char *arg
, route_map_event_t type
,
246 char *errmsg
, size_t errmsg_len
))
248 rmap_match_set_hook
.no_match_ipv6_address
= func
;
252 /* match ipv6 address prefix list */
253 void route_map_match_ipv6_address_prefix_list_hook(int (*func
)(
254 struct route_map_index
*index
, const char *command
,
255 const char *arg
, route_map_event_t type
,
256 char *errmsg
, size_t errmsg_len
))
258 rmap_match_set_hook
.match_ipv6_address_prefix_list
= func
;
261 /* no match ipv6 address prefix list */
262 void route_map_no_match_ipv6_address_prefix_list_hook(int (*func
)(
263 struct route_map_index
*index
, const char *command
,
264 const char *arg
, route_map_event_t type
,
265 char *errmsg
, size_t errmsg_len
))
267 rmap_match_set_hook
.no_match_ipv6_address_prefix_list
= func
;
270 /* match ipv6 next-hop type */
271 void route_map_match_ipv6_next_hop_type_hook(int (*func
)(
272 struct route_map_index
*index
, const char *command
,
273 const char *arg
, route_map_event_t type
,
274 char *errmsg
, size_t errmsg_len
))
276 rmap_match_set_hook
.match_ipv6_next_hop_type
= func
;
279 /* no match ipv6 next-hop type */
280 void route_map_no_match_ipv6_next_hop_type_hook(int (*func
)(
281 struct route_map_index
*index
, const char *command
,
282 const char *arg
, route_map_event_t type
,
283 char *errmsg
, size_t errmsg_len
))
285 rmap_match_set_hook
.no_match_ipv6_next_hop_type
= func
;
288 /* match ipv6 next-hop prefix-list */
289 void route_map_match_ipv6_next_hop_prefix_list_hook(int (*func
)(
290 struct route_map_index
*index
, const char *command
, const char *arg
,
291 route_map_event_t type
, char *errmsg
, size_t errmsg_len
))
293 rmap_match_set_hook
.match_ipv6_next_hop_prefix_list
= func
;
296 /* no match ipv6 next-hop prefix-list */
297 void route_map_no_match_ipv6_next_hop_prefix_list_hook(int (*func
)(
298 struct route_map_index
*index
, const char *command
, const char *arg
,
299 route_map_event_t type
, char *errmsg
, size_t errmsg_len
))
301 rmap_match_set_hook
.no_match_ipv6_next_hop_prefix_list
= func
;
305 void route_map_match_metric_hook(int (*func
)(
306 struct route_map_index
*index
, const char *command
,
307 const char *arg
, route_map_event_t type
,
308 char *errmsg
, size_t errmsg_len
))
310 rmap_match_set_hook
.match_metric
= func
;
313 /* no match metric */
314 void route_map_no_match_metric_hook(int (*func
)(
315 struct route_map_index
*index
, const char *command
,
316 const char *arg
, route_map_event_t type
,
317 char *errmsg
, size_t errmsg_len
))
319 rmap_match_set_hook
.no_match_metric
= func
;
323 void route_map_match_tag_hook(int (*func
)(struct route_map_index
*index
,
324 const char *command
, const char *arg
,
325 route_map_event_t type
,
326 char *errmsg
, size_t errmsg_len
))
328 rmap_match_set_hook
.match_tag
= func
;
332 void route_map_no_match_tag_hook(int (*func
)(
333 struct route_map_index
*index
, const char *command
,
334 const char *arg
, route_map_event_t type
,
335 char *errmsg
, size_t errmsg_len
))
337 rmap_match_set_hook
.no_match_tag
= func
;
340 /* set sr-te color */
341 void route_map_set_srte_color_hook(int (*func
)(struct route_map_index
*index
,
344 char *errmsg
, size_t errmsg_len
))
346 rmap_match_set_hook
.set_srte_color
= func
;
349 /* no set sr-te color */
350 void route_map_no_set_srte_color_hook(int (*func
)(struct route_map_index
*index
,
353 char *errmsg
, size_t errmsg_len
))
355 rmap_match_set_hook
.no_set_srte_color
= func
;
359 void route_map_set_ip_nexthop_hook(int (*func
)(struct route_map_index
*index
,
362 char *errmsg
, size_t errmsg_len
))
364 rmap_match_set_hook
.set_ip_nexthop
= func
;
367 /* no set ip nexthop */
368 void route_map_no_set_ip_nexthop_hook(int (*func
)(struct route_map_index
*index
,
374 rmap_match_set_hook
.no_set_ip_nexthop
= func
;
377 /* set ipv6 nexthop local */
378 void route_map_set_ipv6_nexthop_local_hook(
379 int (*func
)(struct route_map_index
*index
,
380 const char *command
, const char *arg
,
381 char *errmsg
, size_t errmsg_len
))
383 rmap_match_set_hook
.set_ipv6_nexthop_local
= func
;
386 /* no set ipv6 nexthop local */
387 void route_map_no_set_ipv6_nexthop_local_hook(
388 int (*func
)(struct route_map_index
*index
,
389 const char *command
, const char *arg
,
390 char *errmsg
, size_t errmsg_len
))
392 rmap_match_set_hook
.no_set_ipv6_nexthop_local
= func
;
396 void route_map_set_metric_hook(int (*func
)(struct route_map_index
*index
,
399 char *errmsg
, size_t errmsg_len
))
401 rmap_match_set_hook
.set_metric
= func
;
405 void route_map_no_set_metric_hook(int (*func
)(struct route_map_index
*index
,
408 char *errmsg
, size_t errmsg_len
))
410 rmap_match_set_hook
.no_set_metric
= func
;
414 void route_map_set_tag_hook(int (*func
)(struct route_map_index
*index
,
415 const char *command
, const char *arg
,
416 char *errmsg
, size_t errmsg_len
))
418 rmap_match_set_hook
.set_tag
= func
;
422 void route_map_no_set_tag_hook(int (*func
)(struct route_map_index
*index
,
425 char *errmsg
, size_t errmsg_len
))
427 rmap_match_set_hook
.no_set_tag
= func
;
430 int generic_match_add(struct route_map_index
*index
,
431 const char *command
, const char *arg
,
432 route_map_event_t type
,
433 char *errmsg
, size_t errmsg_len
)
435 enum rmap_compile_rets ret
;
437 ret
= route_map_add_match(index
, command
, arg
, type
);
439 case RMAP_RULE_MISSING
:
440 snprintf(errmsg
, errmsg_len
, "%% [%s] Can't find rule.",
442 return CMD_WARNING_CONFIG_FAILED
;
443 case RMAP_COMPILE_ERROR
:
444 snprintf(errmsg
, errmsg_len
,
445 "%% [%s] Argument form is unsupported or malformed.",
447 return CMD_WARNING_CONFIG_FAILED
;
448 case RMAP_COMPILE_SUCCESS
:
450 * Nothing to do here move along
458 int generic_match_delete(struct route_map_index
*index
,
459 const char *command
, const char *arg
,
460 route_map_event_t type
,
461 char *errmsg
, size_t errmsg_len
)
463 enum rmap_compile_rets ret
;
464 int retval
= CMD_SUCCESS
;
465 char *dep_name
= NULL
;
467 char *rmap_name
= NULL
;
469 if (type
!= RMAP_EVENT_MATCH_DELETED
) {
470 /* ignore the mundane, the types without any dependency */
472 if ((tmpstr
= route_map_get_match_arg(index
, command
))
475 XSTRDUP(MTYPE_ROUTE_MAP_RULE
, tmpstr
);
477 dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_RULE
, arg
);
479 rmap_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, index
->map
->name
);
482 ret
= route_map_delete_match(index
, command
, dep_name
, type
);
484 case RMAP_RULE_MISSING
:
485 snprintf(errmsg
, errmsg_len
, "%% [%s] Can't find rule.",
487 retval
= CMD_WARNING_CONFIG_FAILED
;
489 case RMAP_COMPILE_ERROR
:
490 snprintf(errmsg
, errmsg_len
,
491 "%% [%s] Argument form is unsupported or malformed.",
493 retval
= CMD_WARNING_CONFIG_FAILED
;
495 case RMAP_COMPILE_SUCCESS
:
502 XFREE(MTYPE_ROUTE_MAP_RULE
, dep_name
);
503 XFREE(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
508 int generic_set_add(struct route_map_index
*index
,
509 const char *command
, const char *arg
,
510 char *errmsg
, size_t errmsg_len
)
512 enum rmap_compile_rets ret
;
514 ret
= route_map_add_set(index
, command
, arg
);
516 case RMAP_RULE_MISSING
:
517 snprintf(errmsg
, errmsg_len
,
518 "%% [%s] Can't find rule.", frr_protonameinst
);
519 return CMD_WARNING_CONFIG_FAILED
;
520 case RMAP_COMPILE_ERROR
:
521 snprintf(errmsg
, errmsg_len
,
522 "%% [%s] Argument form is unsupported or malformed.",
524 return CMD_WARNING_CONFIG_FAILED
;
525 case RMAP_COMPILE_SUCCESS
:
532 int generic_set_delete(struct route_map_index
*index
,
533 const char *command
, const char *arg
,
534 char *errmsg
, size_t errmsg_len
)
536 enum rmap_compile_rets ret
;
538 ret
= route_map_delete_set(index
, command
, arg
);
540 case RMAP_RULE_MISSING
:
541 snprintf(errmsg
, errmsg_len
, "%% [%s] Can't find rule.",
543 return CMD_WARNING_CONFIG_FAILED
;
544 case RMAP_COMPILE_ERROR
:
545 snprintf(errmsg
, errmsg_len
,
546 "%% [%s] Argument form is unsupported or malformed.",
548 return CMD_WARNING_CONFIG_FAILED
;
549 case RMAP_COMPILE_SUCCESS
:
557 /* Master list of route map. */
558 struct route_map_list route_map_master
= {NULL
, NULL
, NULL
, NULL
, NULL
};
559 struct hash
*route_map_master_hash
= NULL
;
561 static unsigned int route_map_hash_key_make(const void *p
)
563 const struct route_map
*map
= p
;
564 return string_hash_make(map
->name
);
567 static bool route_map_hash_cmp(const void *p1
, const void *p2
)
569 const struct route_map
*map1
= p1
;
570 const struct route_map
*map2
= p2
;
572 if (!strcmp(map1
->name
, map2
->name
))
578 enum route_map_upd8_type
{
583 /* all possible route-map dependency types */
584 enum route_map_dep_type
{
585 ROUTE_MAP_DEP_RMAP
= 1,
587 ROUTE_MAP_DEP_ECLIST
,
588 ROUTE_MAP_DEP_LCLIST
,
590 ROUTE_MAP_DEP_ASPATH
,
591 ROUTE_MAP_DEP_FILTER
,
595 struct route_map_dep
{
597 struct hash
*dep_rmap_hash
;
598 struct hash
*this_hash
; /* ptr to the hash structure this is part of */
601 struct route_map_dep_data
{
605 /* Count of number of sequences of this
606 * route-map that depend on the same entity.
611 /* Hashes maintaining dependency between various sublists used by route maps */
612 static struct hash
*route_map_dep_hash
[ROUTE_MAP_DEP_MAX
];
614 static unsigned int route_map_dep_hash_make_key(const void *p
);
615 static void route_map_clear_all_references(char *rmap_name
);
616 static void route_map_rule_delete(struct route_map_rule_list
*,
617 struct route_map_rule
*);
621 /* New route map allocation. Please note route map's name must be
623 static struct route_map
*route_map_new(const char *name
)
625 struct route_map
*new;
627 new = XCALLOC(MTYPE_ROUTE_MAP
, sizeof(struct route_map
));
628 new->name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
629 QOBJ_REG(new, route_map
);
633 /* Add new name to route_map. */
634 static struct route_map
*route_map_add(const char *name
)
636 struct route_map
*map
, *exist
;
637 struct route_map_list
*list
;
639 map
= route_map_new(name
);
640 list
= &route_map_master
;
643 * Add map to the hash
645 * If the map already exists in the hash, then we know that
646 * FRR is now in a sequence of delete/create.
647 * All FRR needs to do here is set the to_be_processed
648 * bit (to inherit from the old one
650 exist
= hash_release(route_map_master_hash
, map
);
652 map
->to_be_processed
= exist
->to_be_processed
;
653 route_map_free_map(exist
);
655 hash_get(route_map_master_hash
, map
, hash_alloc_intern
);
657 /* Add new entry to the head of the list to match how it is added in the
658 * hash table. This is to ensure that if the same route-map has been
659 * created more than once and then marked for deletion (which can happen
660 * if prior deletions haven't completed as BGP hasn't yet done the
661 * route-map processing), the order of the entities is the same in both
662 * the list and the hash table. Otherwise, since there is nothing to
663 * distinguish between the two entries, the wrong entry could get freed.
664 * TODO: This needs to be re-examined to handle it better - e.g., revive
665 * a deleted entry if the route-map is created again.
668 map
->next
= list
->head
;
670 list
->head
->prev
= map
;
676 if (route_map_master
.add_hook
) {
677 (*route_map_master
.add_hook
)(name
);
678 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_ADDED
);
681 if (!map
->ipv4_prefix_table
)
682 map
->ipv4_prefix_table
= route_table_init();
684 if (!map
->ipv6_prefix_table
)
685 map
->ipv6_prefix_table
= route_table_init();
687 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
688 zlog_debug("Add route-map %s", name
);
692 /* this is supposed to be called post processing by
693 * the delete hook function. Don't invoke delete_hook
694 * again in this routine.
696 static void route_map_free_map(struct route_map
*map
)
698 struct route_map_list
*list
;
699 struct route_map_index
*index
;
704 while ((index
= map
->head
) != NULL
)
705 route_map_index_delete(index
, 0);
707 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
708 zlog_debug("Deleting route-map %s", map
->name
);
710 list
= &route_map_master
;
715 map
->next
->prev
= map
->prev
;
717 list
->tail
= map
->prev
;
720 map
->prev
->next
= map
->next
;
722 list
->head
= map
->next
;
724 hash_release(route_map_master_hash
, map
);
725 XFREE(MTYPE_ROUTE_MAP_NAME
, map
->name
);
726 XFREE(MTYPE_ROUTE_MAP
, map
);
729 /* Route map delete from list. */
730 void route_map_delete(struct route_map
*map
)
732 struct route_map_index
*index
;
735 while ((index
= map
->head
) != NULL
)
736 route_map_index_delete(index
, 0);
741 /* Clear all dependencies */
742 route_map_clear_all_references(name
);
744 /* Execute deletion hook. */
745 if (route_map_master
.delete_hook
) {
746 (*route_map_master
.delete_hook
)(name
);
747 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_DELETED
);
750 if (!map
->to_be_processed
) {
751 route_map_free_map(map
);
755 /* Lookup route map by route map name string. */
756 struct route_map
*route_map_lookup_by_name(const char *name
)
758 struct route_map
*map
;
759 struct route_map tmp_map
;
764 // map.deleted is false via memset
765 memset(&tmp_map
, 0, sizeof(tmp_map
));
766 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
767 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
768 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
770 if (map
&& map
->deleted
)
776 /* Simple helper to warn if route-map does not exist. */
777 struct route_map
*route_map_lookup_warn_noexist(struct vty
*vty
, const char *name
)
779 struct route_map
*route_map
= route_map_lookup_by_name(name
);
782 if (vty_shell_serv(vty
))
783 vty_out(vty
, "The route-map '%s' does not exist.\n", name
);
788 int route_map_mark_updated(const char *name
)
790 struct route_map
*map
;
792 struct route_map tmp_map
;
797 map
= route_map_lookup_by_name(name
);
799 /* If we did not find the routemap with deleted=false try again
803 memset(&tmp_map
, 0, sizeof(tmp_map
));
804 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
805 tmp_map
.deleted
= true;
806 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
807 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
811 map
->to_be_processed
= true;
818 static void route_map_clear_updated(struct route_map
*map
)
821 map
->to_be_processed
= false;
823 route_map_free_map(map
);
827 /* Lookup route map. If there isn't route map create one and return
829 struct route_map
*route_map_get(const char *name
)
831 struct route_map
*map
;
833 map
= route_map_lookup_by_name(name
);
835 map
= route_map_add(name
);
840 void route_map_walk_update_list(void (*route_map_update_fn
)(char *name
))
842 struct route_map
*node
;
843 struct route_map
*nnode
= NULL
;
845 for (node
= route_map_master
.head
; node
; node
= nnode
) {
846 if (node
->to_be_processed
) {
847 /* DD: Should we add any thread yield code here */
848 route_map_update_fn(node
->name
);
850 route_map_clear_updated(node
);
856 /* Return route map's type string. */
857 static const char *route_map_type_str(enum route_map_type type
)
871 static const char *route_map_cmd_result_str(enum route_map_cmd_result_t res
)
889 static const char *route_map_result_str(route_map_result_t res
)
894 case RMAP_PERMITMATCH
:
902 static void vty_show_route_map_entry(struct vty
*vty
, struct route_map
*map
,
905 struct route_map_index
*index
;
906 struct route_map_rule
*rule
;
907 json_object
*json_rmap
= NULL
;
908 json_object
*json_rules
= NULL
;
911 json_rmap
= json_object_new_object();
912 json_object_object_add(json
, map
->name
, json_rmap
);
914 json_rules
= json_object_new_array();
915 json_object_int_add(json_rmap
, "invoked",
916 map
->applied
- map
->applied_clear
);
917 json_object_boolean_add(json_rmap
, "disabledOptimization",
918 map
->optimization_disabled
);
919 json_object_boolean_add(json_rmap
, "processedChange",
920 map
->to_be_processed
);
921 json_object_object_add(json_rmap
, "rules", json_rules
);
924 "route-map: %s Invoked: %" PRIu64
925 " Optimization: %s Processed Change: %s\n",
926 map
->name
, map
->applied
- map
->applied_clear
,
927 map
->optimization_disabled
? "disabled" : "enabled",
928 map
->to_be_processed
? "true" : "false");
931 for (index
= map
->head
; index
; index
= index
->next
) {
933 json_object
*json_rule
;
934 json_object
*json_matches
;
935 json_object
*json_sets
;
936 char action
[BUFSIZ
] = {};
938 json_rule
= json_object_new_object();
939 json_object_array_add(json_rules
, json_rule
);
941 json_object_int_add(json_rule
, "sequenceNumber",
943 json_object_string_add(json_rule
, "type",
944 route_map_type_str(index
->type
));
945 json_object_int_add(json_rule
, "invoked",
947 - index
->applied_clear
);
950 if (index
->description
)
951 json_object_string_add(json_rule
, "description",
955 json_matches
= json_object_new_array();
956 json_object_object_add(json_rule
, "matchClauses",
958 for (rule
= index
->match_list
.head
; rule
;
962 snprintf(buf
, sizeof(buf
), "%s %s",
963 rule
->cmd
->str
, rule
->rule_str
);
964 json_array_string_add(json_matches
, buf
);
968 json_sets
= json_object_new_array();
969 json_object_object_add(json_rule
, "setClauses",
971 for (rule
= index
->set_list
.head
; rule
;
975 snprintf(buf
, sizeof(buf
), "%s %s",
976 rule
->cmd
->str
, rule
->rule_str
);
977 json_array_string_add(json_sets
, buf
);
982 json_object_string_add(json_rule
, "callClause",
986 if (index
->exitpolicy
== RMAP_GOTO
)
987 snprintf(action
, sizeof(action
), "Goto %d",
989 else if (index
->exitpolicy
== RMAP_NEXT
)
990 snprintf(action
, sizeof(action
),
991 "Continue to next entry");
992 else if (index
->exitpolicy
== RMAP_EXIT
)
993 snprintf(action
, sizeof(action
),
995 if (action
[0] != '\0')
996 json_object_string_add(json_rule
, "action",
999 vty_out(vty
, " %s, sequence %d Invoked %" PRIu64
"\n",
1000 route_map_type_str(index
->type
), index
->pref
,
1001 index
->applied
- index
->applied_clear
);
1004 if (index
->description
)
1005 vty_out(vty
, " Description:\n %s\n",
1006 index
->description
);
1009 vty_out(vty
, " Match clauses:\n");
1010 for (rule
= index
->match_list
.head
; rule
;
1012 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
1016 vty_out(vty
, " Set clauses:\n");
1017 for (rule
= index
->set_list
.head
; rule
;
1019 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
1023 vty_out(vty
, " Call clause:\n");
1025 vty_out(vty
, " Call %s\n", index
->nextrm
);
1028 vty_out(vty
, " Action:\n");
1029 if (index
->exitpolicy
== RMAP_GOTO
)
1030 vty_out(vty
, " Goto %d\n", index
->nextpref
);
1031 else if (index
->exitpolicy
== RMAP_NEXT
)
1032 vty_out(vty
, " Continue to next entry\n");
1033 else if (index
->exitpolicy
== RMAP_EXIT
)
1034 vty_out(vty
, " Exit routemap\n");
1039 static int sort_route_map(const void **map1
, const void **map2
)
1041 const struct route_map
*m1
= *map1
;
1042 const struct route_map
*m2
= *map2
;
1044 return strcmp(m1
->name
, m2
->name
);
1047 static int vty_show_route_map(struct vty
*vty
, const char *name
, bool use_json
)
1049 struct route_map
*map
;
1050 json_object
*json
= NULL
;
1051 json_object
*json_proto
= NULL
;
1054 json
= json_object_new_object();
1055 json_proto
= json_object_new_object();
1056 json_object_object_add(json
, frr_protonameinst
, json_proto
);
1058 vty_out(vty
, "%s:\n", frr_protonameinst
);
1061 map
= route_map_lookup_by_name(name
);
1064 vty_show_route_map_entry(vty
, map
, json_proto
);
1065 } else if (!use_json
) {
1066 vty_out(vty
, "%s: 'route-map %s' not found\n",
1067 frr_protonameinst
, name
);
1071 struct list
*maplist
= list_new();
1072 struct listnode
*ln
;
1074 for (map
= route_map_master
.head
; map
; map
= map
->next
)
1075 listnode_add(maplist
, map
);
1077 list_sort(maplist
, sort_route_map
);
1079 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
1080 vty_show_route_map_entry(vty
, map
, json_proto
);
1082 list_delete(&maplist
);
1085 return vty_json(vty
, json
);
1088 /* Unused route map details */
1089 static int vty_show_unused_route_map(struct vty
*vty
)
1091 struct list
*maplist
= list_new();
1092 struct listnode
*ln
;
1093 struct route_map
*map
;
1095 for (map
= route_map_master
.head
; map
; map
= map
->next
) {
1096 /* If use_count is zero, No protocol is using this routemap.
1097 * so adding to the list.
1099 if (!map
->use_count
)
1100 listnode_add(maplist
, map
);
1103 if (maplist
->count
> 0) {
1104 vty_out(vty
, "\n%s:\n", frr_protonameinst
);
1105 list_sort(maplist
, sort_route_map
);
1107 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
1108 vty_show_route_map_entry(vty
, map
, NULL
);
1110 vty_out(vty
, "\n%s: None\n", frr_protonameinst
);
1113 list_delete(&maplist
);
1117 /* New route map allocation. Please note route map's name must be
1119 static struct route_map_index
*route_map_index_new(void)
1121 struct route_map_index
*new;
1123 new = XCALLOC(MTYPE_ROUTE_MAP_INDEX
, sizeof(struct route_map_index
));
1124 new->exitpolicy
= RMAP_EXIT
; /* Default to Cisco-style */
1125 TAILQ_INIT(&new->rhclist
);
1126 QOBJ_REG(new, route_map_index
);
1130 /* Free route map index. */
1131 void route_map_index_delete(struct route_map_index
*index
, int notify
)
1133 struct routemap_hook_context
*rhc
;
1134 struct route_map_rule
*rule
;
1138 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
1139 zlog_debug("Deleting route-map %s sequence %d",
1140 index
->map
->name
, index
->pref
);
1142 /* Free route map entry description. */
1143 XFREE(MTYPE_TMP
, index
->description
);
1145 /* Free route map northbound hook contexts. */
1146 while ((rhc
= TAILQ_FIRST(&index
->rhclist
)) != NULL
)
1147 routemap_hook_context_free(rhc
);
1149 /* Free route match. */
1150 while ((rule
= index
->match_list
.head
) != NULL
) {
1151 if (IS_RULE_IPv4_PREFIX_LIST(rule
->cmd
->str
))
1152 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_DELETED
,
1153 index
, AFI_IP
, rule
->rule_str
);
1154 else if (IS_RULE_IPv6_PREFIX_LIST(rule
->cmd
->str
))
1155 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_DELETED
,
1159 route_map_rule_delete(&index
->match_list
, rule
);
1162 /* Free route set. */
1163 while ((rule
= index
->set_list
.head
) != NULL
)
1164 route_map_rule_delete(&index
->set_list
, rule
);
1166 /* Remove index from route map list. */
1168 index
->next
->prev
= index
->prev
;
1170 index
->map
->tail
= index
->prev
;
1173 index
->prev
->next
= index
->next
;
1175 index
->map
->head
= index
->next
;
1177 /* Free 'char *nextrm' if not NULL */
1178 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
1180 route_map_pfx_tbl_update(RMAP_EVENT_INDEX_DELETED
, index
, 0, NULL
);
1182 /* Execute event hook. */
1183 if (route_map_master
.event_hook
&& notify
) {
1184 (*route_map_master
.event_hook
)(index
->map
->name
);
1185 route_map_notify_dependencies(index
->map
->name
,
1186 RMAP_EVENT_CALL_ADDED
);
1188 XFREE(MTYPE_ROUTE_MAP_INDEX
, index
);
1191 /* Lookup index from route map. */
1192 static struct route_map_index
*route_map_index_lookup(struct route_map
*map
,
1193 enum route_map_type type
,
1196 struct route_map_index
*index
;
1198 for (index
= map
->head
; index
; index
= index
->next
)
1199 if ((index
->type
== type
|| type
== RMAP_ANY
)
1200 && index
->pref
== pref
)
1205 /* Add new index to route map. */
1206 static struct route_map_index
*
1207 route_map_index_add(struct route_map
*map
, enum route_map_type type
, int pref
)
1209 struct route_map_index
*index
;
1210 struct route_map_index
*point
;
1212 /* Allocate new route map inex. */
1213 index
= route_map_index_new();
1218 /* Compare preference. */
1219 for (point
= map
->head
; point
; point
= point
->next
)
1220 if (point
->pref
>= pref
)
1223 if (map
->head
== NULL
) {
1224 map
->head
= map
->tail
= index
;
1225 } else if (point
== NULL
) {
1226 index
->prev
= map
->tail
;
1227 map
->tail
->next
= index
;
1229 } else if (point
== map
->head
) {
1230 index
->next
= map
->head
;
1231 map
->head
->prev
= index
;
1234 index
->next
= point
;
1235 index
->prev
= point
->prev
;
1237 point
->prev
->next
= index
;
1238 point
->prev
= index
;
1241 route_map_pfx_tbl_update(RMAP_EVENT_INDEX_ADDED
, index
, 0, NULL
);
1243 /* Execute event hook. */
1244 if (route_map_master
.event_hook
) {
1245 (*route_map_master
.event_hook
)(map
->name
);
1246 route_map_notify_dependencies(map
->name
, RMAP_EVENT_CALL_ADDED
);
1249 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
1250 zlog_debug("Route-map %s add sequence %d, type: %s",
1251 map
->name
, pref
, route_map_type_str(type
));
1256 /* Get route map index. */
1257 struct route_map_index
*
1258 route_map_index_get(struct route_map
*map
, enum route_map_type type
, int pref
)
1260 struct route_map_index
*index
;
1262 index
= route_map_index_lookup(map
, RMAP_ANY
, pref
);
1263 if (index
&& index
->type
!= type
) {
1264 /* Delete index from route map. */
1265 route_map_index_delete(index
, 1);
1269 index
= route_map_index_add(map
, type
, pref
);
1273 /* New route map rule */
1274 static struct route_map_rule
*route_map_rule_new(void)
1276 struct route_map_rule
*new;
1278 new = XCALLOC(MTYPE_ROUTE_MAP_RULE
, sizeof(struct route_map_rule
));
1282 /* Install rule command to the match list. */
1283 void _route_map_install_match(struct route_map_rule_cmd_proxy
*proxy
)
1285 rmap_cmd_name_add(rmap_match_cmds
, proxy
);
1288 /* Install rule command to the set list. */
1289 void _route_map_install_set(struct route_map_rule_cmd_proxy
*proxy
)
1291 rmap_cmd_name_add(rmap_set_cmds
, proxy
);
1294 /* Lookup rule command from match list. */
1295 static const struct route_map_rule_cmd
*route_map_lookup_match(const char *name
)
1297 struct route_map_rule_cmd refcmd
= {.str
= name
};
1298 struct route_map_rule_cmd_proxy ref
= {.cmd
= &refcmd
};
1299 struct route_map_rule_cmd_proxy
*res
;
1301 res
= rmap_cmd_name_find(rmap_match_cmds
, &ref
);
1307 /* Lookup rule command from set list. */
1308 static const struct route_map_rule_cmd
*route_map_lookup_set(const char *name
)
1310 struct route_map_rule_cmd refcmd
= {.str
= name
};
1311 struct route_map_rule_cmd_proxy ref
= {.cmd
= &refcmd
};
1312 struct route_map_rule_cmd_proxy
*res
;
1314 res
= rmap_cmd_name_find(rmap_set_cmds
, &ref
);
1320 /* Add match and set rule to rule list. */
1321 static void route_map_rule_add(struct route_map_rule_list
*list
,
1322 struct route_map_rule
*rule
)
1325 rule
->prev
= list
->tail
;
1327 list
->tail
->next
= rule
;
1333 /* Delete rule from rule list. */
1334 static void route_map_rule_delete(struct route_map_rule_list
*list
,
1335 struct route_map_rule
*rule
)
1337 if (rule
->cmd
->func_free
)
1338 (*rule
->cmd
->func_free
)(rule
->value
);
1340 XFREE(MTYPE_ROUTE_MAP_RULE_STR
, rule
->rule_str
);
1343 rule
->next
->prev
= rule
->prev
;
1345 list
->tail
= rule
->prev
;
1347 rule
->prev
->next
= rule
->next
;
1349 list
->head
= rule
->next
;
1351 XFREE(MTYPE_ROUTE_MAP_RULE
, rule
);
1354 /* strcmp wrapper function which don't crush even argument is NULL. */
1355 static int rulecmp(const char *dst
, const char *src
)
1366 return strcmp(dst
, src
);
1371 /* Use this to return the already specified argument for this match. This is
1372 * useful to get the specified argument with a route map match rule when the
1373 * rule is being deleted and the argument is not provided.
1375 const char *route_map_get_match_arg(struct route_map_index
*index
,
1376 const char *match_name
)
1378 struct route_map_rule
*rule
;
1379 const struct route_map_rule_cmd
*cmd
;
1381 /* First lookup rule for add match statement. */
1382 cmd
= route_map_lookup_match(match_name
);
1386 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1387 if (rule
->cmd
== cmd
&& rule
->rule_str
!= NULL
)
1388 return (rule
->rule_str
);
1393 static route_map_event_t
get_route_map_delete_event(route_map_event_t type
)
1396 case RMAP_EVENT_CALL_ADDED
:
1397 return RMAP_EVENT_CALL_DELETED
;
1398 case RMAP_EVENT_PLIST_ADDED
:
1399 return RMAP_EVENT_PLIST_DELETED
;
1400 case RMAP_EVENT_CLIST_ADDED
:
1401 return RMAP_EVENT_CLIST_DELETED
;
1402 case RMAP_EVENT_ECLIST_ADDED
:
1403 return RMAP_EVENT_ECLIST_DELETED
;
1404 case RMAP_EVENT_LLIST_ADDED
:
1405 return RMAP_EVENT_LLIST_DELETED
;
1406 case RMAP_EVENT_ASLIST_ADDED
:
1407 return RMAP_EVENT_ASLIST_DELETED
;
1408 case RMAP_EVENT_FILTER_ADDED
:
1409 return RMAP_EVENT_FILTER_DELETED
;
1410 case RMAP_EVENT_SET_ADDED
:
1411 case RMAP_EVENT_SET_DELETED
:
1412 case RMAP_EVENT_SET_REPLACED
:
1413 case RMAP_EVENT_MATCH_ADDED
:
1414 case RMAP_EVENT_MATCH_DELETED
:
1415 case RMAP_EVENT_MATCH_REPLACED
:
1416 case RMAP_EVENT_INDEX_ADDED
:
1417 case RMAP_EVENT_INDEX_DELETED
:
1418 case RMAP_EVENT_CALL_DELETED
:
1419 case RMAP_EVENT_PLIST_DELETED
:
1420 case RMAP_EVENT_CLIST_DELETED
:
1421 case RMAP_EVENT_ECLIST_DELETED
:
1422 case RMAP_EVENT_LLIST_DELETED
:
1423 case RMAP_EVENT_ASLIST_DELETED
:
1424 case RMAP_EVENT_FILTER_DELETED
:
1425 /* This function returns the appropriate 'deleted' event type
1426 * for every 'added' event type passed to this function.
1427 * This is done only for named entities used in the
1428 * route-map match commands.
1429 * This function is not to be invoked for any of the other event
1437 * Return to make c happy but if we get here something has gone
1438 * terribly terribly wrong, so yes this return makes no sense.
1440 return RMAP_EVENT_CALL_ADDED
;
1443 /* Add match statement to route map. */
1444 enum rmap_compile_rets
route_map_add_match(struct route_map_index
*index
,
1445 const char *match_name
,
1446 const char *match_arg
,
1447 route_map_event_t type
)
1449 struct route_map_rule
*rule
;
1450 struct route_map_rule
*next
;
1451 const struct route_map_rule_cmd
*cmd
;
1453 int8_t delete_rmap_event_type
= 0;
1454 const char *rule_key
;
1456 /* First lookup rule for add match statement. */
1457 cmd
= route_map_lookup_match(match_name
);
1459 return RMAP_RULE_MISSING
;
1461 /* Next call compile function for this match statement. */
1462 if (cmd
->func_compile
) {
1463 compile
= (*cmd
->func_compile
)(match_arg
);
1464 if (compile
== NULL
)
1465 return RMAP_COMPILE_ERROR
;
1468 /* use the compiled results if applicable */
1469 if (compile
&& cmd
->func_get_rmap_rule_key
)
1470 rule_key
= (*cmd
->func_get_rmap_rule_key
)
1473 rule_key
= match_arg
;
1475 /* If argument is completely same ignore it. */
1476 for (rule
= index
->match_list
.head
; rule
; rule
= next
) {
1478 if (rule
->cmd
== cmd
) {
1479 /* If the configured route-map match rule is exactly
1480 * the same as the existing configuration then,
1481 * ignore the duplicate configuration.
1483 if (rulecmp(match_arg
, rule
->rule_str
) == 0) {
1485 (*cmd
->func_free
)(compile
);
1487 return RMAP_COMPILE_SUCCESS
;
1490 /* If IPv4 or IPv6 prefix-list match criteria
1491 * has been delete to the route-map index, update
1492 * the route-map's prefix table.
1494 if (IS_RULE_IPv4_PREFIX_LIST(match_name
))
1495 route_map_pfx_tbl_update(
1496 RMAP_EVENT_PLIST_DELETED
, index
, AFI_IP
,
1498 else if (IS_RULE_IPv6_PREFIX_LIST(match_name
))
1499 route_map_pfx_tbl_update(
1500 RMAP_EVENT_PLIST_DELETED
, index
,
1501 AFI_IP6
, rule
->rule_str
);
1503 /* Remove the dependency of the route-map on the rule
1504 * that is being replaced.
1506 if (type
>= RMAP_EVENT_CALL_ADDED
) {
1507 delete_rmap_event_type
=
1508 get_route_map_delete_event(type
);
1509 route_map_upd8_dependency(
1510 delete_rmap_event_type
,
1515 route_map_rule_delete(&index
->match_list
, rule
);
1519 /* Add new route map match rule. */
1520 rule
= route_map_rule_new();
1522 rule
->value
= compile
;
1524 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, match_arg
);
1526 rule
->rule_str
= NULL
;
1528 /* Add new route match rule to linked list. */
1529 route_map_rule_add(&index
->match_list
, rule
);
1531 /* If IPv4 or IPv6 prefix-list match criteria
1532 * has been added to the route-map index, update
1533 * the route-map's prefix table.
1535 if (IS_RULE_IPv4_PREFIX_LIST(match_name
)) {
1536 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_ADDED
, index
, AFI_IP
,
1538 } else if (IS_RULE_IPv6_PREFIX_LIST(match_name
)) {
1539 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_ADDED
, index
, AFI_IP6
,
1543 /* Execute event hook. */
1544 if (route_map_master
.event_hook
) {
1545 (*route_map_master
.event_hook
)(index
->map
->name
);
1546 route_map_notify_dependencies(index
->map
->name
,
1547 RMAP_EVENT_CALL_ADDED
);
1549 if (type
!= RMAP_EVENT_MATCH_ADDED
)
1550 route_map_upd8_dependency(type
, rule_key
, index
->map
->name
);
1552 return RMAP_COMPILE_SUCCESS
;
1555 /* Delete specified route match rule. */
1556 enum rmap_compile_rets
route_map_delete_match(struct route_map_index
*index
,
1557 const char *match_name
,
1558 const char *match_arg
,
1559 route_map_event_t type
)
1561 struct route_map_rule
*rule
;
1562 const struct route_map_rule_cmd
*cmd
;
1563 const char *rule_key
;
1565 cmd
= route_map_lookup_match(match_name
);
1567 return RMAP_RULE_MISSING
;
1569 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1570 if (rule
->cmd
== cmd
&& (rulecmp(rule
->rule_str
, match_arg
) == 0
1571 || match_arg
== NULL
)) {
1572 /* Execute event hook. */
1573 if (route_map_master
.event_hook
) {
1574 (*route_map_master
.event_hook
)(index
->map
->name
);
1575 route_map_notify_dependencies(
1577 RMAP_EVENT_CALL_ADDED
);
1579 if (cmd
->func_get_rmap_rule_key
)
1580 rule_key
= (*cmd
->func_get_rmap_rule_key
)
1583 rule_key
= match_arg
;
1585 if (type
!= RMAP_EVENT_MATCH_DELETED
&& rule_key
)
1586 route_map_upd8_dependency(type
, rule_key
,
1589 route_map_rule_delete(&index
->match_list
, rule
);
1591 /* If IPv4 or IPv6 prefix-list match criteria
1592 * has been delete from the route-map index, update
1593 * the route-map's prefix table.
1595 if (IS_RULE_IPv4_PREFIX_LIST(match_name
)) {
1596 route_map_pfx_tbl_update(
1597 RMAP_EVENT_PLIST_DELETED
, index
, AFI_IP
,
1599 } else if (IS_RULE_IPv6_PREFIX_LIST(match_name
)) {
1600 route_map_pfx_tbl_update(
1601 RMAP_EVENT_PLIST_DELETED
, index
,
1602 AFI_IP6
, match_arg
);
1605 return RMAP_COMPILE_SUCCESS
;
1607 /* Can't find matched rule. */
1608 return RMAP_RULE_MISSING
;
1611 /* Add route-map set statement to the route map. */
1612 enum rmap_compile_rets
route_map_add_set(struct route_map_index
*index
,
1613 const char *set_name
,
1614 const char *set_arg
)
1616 struct route_map_rule
*rule
;
1617 struct route_map_rule
*next
;
1618 const struct route_map_rule_cmd
*cmd
;
1621 cmd
= route_map_lookup_set(set_name
);
1623 return RMAP_RULE_MISSING
;
1625 /* Next call compile function for this match statement. */
1626 if (cmd
->func_compile
) {
1627 compile
= (*cmd
->func_compile
)(set_arg
);
1628 if (compile
== NULL
)
1629 return RMAP_COMPILE_ERROR
;
1633 /* Add by WJL. if old set command of same kind exist, delete it first
1634 to ensure only one set command of same kind exist under a
1636 for (rule
= index
->set_list
.head
; rule
; rule
= next
) {
1638 if (rule
->cmd
== cmd
)
1639 route_map_rule_delete(&index
->set_list
, rule
);
1642 /* Add new route map match rule. */
1643 rule
= route_map_rule_new();
1645 rule
->value
= compile
;
1647 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, set_arg
);
1649 rule
->rule_str
= NULL
;
1651 /* Add new route match rule to linked list. */
1652 route_map_rule_add(&index
->set_list
, rule
);
1654 /* Execute event hook. */
1655 if (route_map_master
.event_hook
) {
1656 (*route_map_master
.event_hook
)(index
->map
->name
);
1657 route_map_notify_dependencies(index
->map
->name
,
1658 RMAP_EVENT_CALL_ADDED
);
1660 return RMAP_COMPILE_SUCCESS
;
1663 /* Delete route map set rule. */
1664 enum rmap_compile_rets
route_map_delete_set(struct route_map_index
*index
,
1665 const char *set_name
,
1666 const char *set_arg
)
1668 struct route_map_rule
*rule
;
1669 const struct route_map_rule_cmd
*cmd
;
1671 cmd
= route_map_lookup_set(set_name
);
1673 return RMAP_RULE_MISSING
;
1675 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
1676 if ((rule
->cmd
== cmd
) && (rulecmp(rule
->rule_str
, set_arg
) == 0
1677 || set_arg
== NULL
)) {
1678 route_map_rule_delete(&index
->set_list
, rule
);
1679 /* Execute event hook. */
1680 if (route_map_master
.event_hook
) {
1681 (*route_map_master
.event_hook
)(index
->map
->name
);
1682 route_map_notify_dependencies(
1684 RMAP_EVENT_CALL_ADDED
);
1686 return RMAP_COMPILE_SUCCESS
;
1688 /* Can't find matched rule. */
1689 return RMAP_RULE_MISSING
;
1692 static enum route_map_cmd_result_t
1693 route_map_apply_match(struct route_map_rule_list
*match_list
,
1694 const struct prefix
*prefix
, void *object
)
1696 enum route_map_cmd_result_t ret
= RMAP_NOMATCH
;
1697 struct route_map_rule
*match
;
1698 bool is_matched
= false;
1701 /* Check all match rule and if there is no match rule, go to the
1703 if (!match_list
->head
)
1706 for (match
= match_list
->head
; match
; match
= match
->next
) {
1708 * Try each match statement. If any match does not
1709 * return RMAP_MATCH or RMAP_NOOP, return.
1710 * Otherwise continue on to next match statement.
1711 * All match statements must MATCH for
1712 * end-result to be a match.
1713 * (Exception:If match stmts result in a mix of
1714 * MATCH/NOOP, then also end-result is a match)
1715 * If all result in NOOP, end-result is NOOP.
1717 ret
= (*match
->cmd
->func_apply
)(match
->value
, prefix
,
1721 * If the consolidated result of func_apply is:
1722 * -----------------------------------------------
1723 * | MATCH | NOMATCH | NOOP | Final Result |
1724 * ------------------------------------------------
1725 * | yes | yes | yes | NOMATCH |
1726 * | no | no | yes | NOOP |
1727 * | yes | no | yes | MATCH |
1728 * | no | yes | yes | NOMATCH |
1729 * |-----------------------------------------------
1731 * Traditionally, all rules within route-map
1732 * should match for it to MATCH.
1733 * If there are noops within the route-map rules,
1734 * it follows the above matrix.
1736 * Eg: route-map rm1 permit 10
1741 * route-map rm1 permit 20
1770 static struct list
*route_map_get_index_list(struct route_node
**rn
,
1771 const struct prefix
*prefix
,
1772 struct route_table
*table
)
1774 struct route_node
*tmp_rn
= NULL
;
1777 *rn
= route_node_match(table
, prefix
);
1783 return (struct list
*)((*rn
)->info
);
1785 /* If rn->info is NULL, get the parent.
1786 * Store the rn in tmp_rn and unlock it later.
1792 *rn
= (*rn
)->parent
;
1794 route_unlock_node(tmp_rn
);
1800 route_lock_node(*rn
);
1801 return (struct list
*)((*rn
)->info
);
1803 } while (!(*rn
)->info
);
1809 * This function returns the route-map index that best matches the prefix.
1811 static struct route_map_index
*
1812 route_map_get_index(struct route_map
*map
, const struct prefix
*prefix
,
1813 void *object
, enum route_map_cmd_result_t
*match_ret
)
1815 enum route_map_cmd_result_t ret
= RMAP_NOMATCH
;
1816 struct list
*candidate_rmap_list
= NULL
;
1817 struct route_node
*rn
= NULL
;
1818 struct listnode
*ln
= NULL
, *nn
= NULL
;
1819 struct route_map_index
*index
= NULL
, *best_index
= NULL
;
1820 struct route_map_index
*head_index
= NULL
;
1821 struct route_table
*table
= NULL
;
1823 unsigned char family
;
1826 * Handling for matching evpn_routes in the prefix table.
1828 * We convert type2/5 prefix to ipv4/6 prefix to do longest
1829 * prefix matching on.
1831 if (prefix
->family
== AF_EVPN
) {
1832 if (evpn_prefix2prefix(prefix
, &conv
) != 0)
1839 family
= prefix
->family
;
1841 if (family
== AF_INET
)
1842 table
= map
->ipv4_prefix_table
;
1844 table
= map
->ipv6_prefix_table
;
1850 candidate_rmap_list
=
1851 route_map_get_index_list(&rn
, prefix
, table
);
1855 /* If the index at the head of the list is of seq higher
1856 * than that in best_index, ignore the list and get the
1857 * parent node's list.
1859 head_index
= (struct route_map_index
*)(listgetdata(
1860 listhead(candidate_rmap_list
)));
1861 if (best_index
&& head_index
1862 && (best_index
->pref
< head_index
->pref
)) {
1863 route_unlock_node(rn
);
1867 for (ALL_LIST_ELEMENTS(candidate_rmap_list
, ln
, nn
, index
)) {
1868 /* If the index is of seq higher than that in
1869 * best_index, ignore the list and get the parent
1872 if (best_index
&& (best_index
->pref
< index
->pref
))
1875 ret
= route_map_apply_match(&index
->match_list
, prefix
,
1878 if (ret
== RMAP_MATCH
) {
1882 } else if (ret
== RMAP_NOOP
) {
1884 * If match_ret is denymatch, even if we see
1885 * more noops, we retain this return value and
1886 * return this eventually if there are no
1888 * If a best match route-map index already
1889 * exists, do not reset the match_ret.
1891 if (!best_index
&& (*match_ret
!= RMAP_NOMATCH
))
1895 * ret is RMAP_NOMATCH.
1896 * If a best match route-map index already
1897 * exists, do not reset the match_ret.
1904 route_unlock_node(rn
);
1911 static int route_map_candidate_list_cmp(struct route_map_index
*idx1
,
1912 struct route_map_index
*idx2
)
1914 return idx1
->pref
- idx2
->pref
;
1918 * This function adds the route-map index into the default route's
1919 * route-node in the route-map's IPv4/IPv6 prefix-table.
1921 static void route_map_pfx_table_add_default(afi_t afi
,
1922 struct route_map_index
*index
)
1924 struct route_node
*rn
= NULL
;
1925 struct list
*rmap_candidate_list
= NULL
;
1927 bool updated_rn
= false;
1928 struct route_table
*table
= NULL
;
1930 memset(&p
, 0, sizeof(p
));
1931 p
.family
= afi2family(afi
);
1934 if (p
.family
== AF_INET
) {
1935 table
= index
->map
->ipv4_prefix_table
;
1937 index
->map
->ipv4_prefix_table
= route_table_init();
1939 table
= index
->map
->ipv4_prefix_table
;
1941 table
= index
->map
->ipv6_prefix_table
;
1943 index
->map
->ipv6_prefix_table
= route_table_init();
1945 table
= index
->map
->ipv6_prefix_table
;
1948 /* Add default route to table */
1949 rn
= route_node_get(table
, &p
);
1955 rmap_candidate_list
= list_new();
1956 rmap_candidate_list
->cmp
=
1957 (int (*)(void *, void *))route_map_candidate_list_cmp
;
1958 rn
->info
= rmap_candidate_list
;
1960 rmap_candidate_list
= (struct list
*)rn
->info
;
1964 listnode_add_sort_nodup(rmap_candidate_list
, index
);
1966 route_unlock_node(rn
);
1970 * This function removes the route-map index from the default route's
1971 * route-node in the route-map's IPv4/IPv6 prefix-table.
1973 static void route_map_pfx_table_del_default(afi_t afi
,
1974 struct route_map_index
*index
)
1976 struct route_node
*rn
= NULL
;
1977 struct list
*rmap_candidate_list
= NULL
;
1979 struct route_table
*table
= NULL
;
1981 memset(&p
, 0, sizeof(p
));
1982 p
.family
= afi2family(afi
);
1985 if (p
.family
== AF_INET
)
1986 table
= index
->map
->ipv4_prefix_table
;
1988 table
= index
->map
->ipv6_prefix_table
;
1990 /* Remove RMAP index from default route in table */
1991 rn
= route_node_lookup(table
, &p
);
1992 if (!rn
|| !rn
->info
)
1995 rmap_candidate_list
= (struct list
*)rn
->info
;
1997 listnode_delete(rmap_candidate_list
, index
);
1999 if (listcount(rmap_candidate_list
) == 0) {
2000 list_delete(&rmap_candidate_list
);
2002 route_unlock_node(rn
);
2004 route_unlock_node(rn
);
2008 * This function adds the route-map index to the route-node for
2009 * the prefix-entry in the route-map's IPv4/IPv6 prefix-table.
2011 static void route_map_pfx_table_add(struct route_table
*table
,
2012 struct route_map_index
*index
,
2013 struct prefix_list_entry
*pentry
)
2015 struct route_node
*rn
= NULL
;
2016 struct list
*rmap_candidate_list
= NULL
;
2017 bool updated_rn
= false;
2019 rn
= route_node_get(table
, &pentry
->prefix
);
2024 rmap_candidate_list
= list_new();
2025 rmap_candidate_list
->cmp
=
2026 (int (*)(void *, void *))route_map_candidate_list_cmp
;
2027 rn
->info
= rmap_candidate_list
;
2029 rmap_candidate_list
= (struct list
*)rn
->info
;
2033 listnode_add_sort_nodup(rmap_candidate_list
, index
);
2035 route_unlock_node(rn
);
2039 * This function removes the route-map index from the route-node for
2040 * the prefix-entry in the route-map's IPv4/IPv6 prefix-table.
2042 static void route_map_pfx_table_del(struct route_table
*table
,
2043 struct route_map_index
*index
,
2044 struct prefix_list_entry
*pentry
)
2046 struct route_node
*rn
= NULL
;
2047 struct list
*rmap_candidate_list
= NULL
;
2049 rn
= route_node_lookup(table
, &pentry
->prefix
);
2050 if (!rn
|| !rn
->info
)
2053 rmap_candidate_list
= (struct list
*)rn
->info
;
2055 listnode_delete(rmap_candidate_list
, index
);
2057 if (listcount(rmap_candidate_list
) == 0) {
2058 list_delete(&rmap_candidate_list
);
2060 route_unlock_node(rn
);
2062 route_unlock_node(rn
);
2065 /* This function checks for the presence of an IPv4 prefix-list
2066 * match rule in the given route-map index.
2068 static bool route_map_is_ip_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_IPv4_PREFIX_LIST(rule
->cmd
->str
))
2081 /* This function checks for the presence of an IPv6 prefix-list
2082 * match rule in the given route-map index.
2085 route_map_is_ipv6_pfx_list_rule_present(struct route_map_index
*index
)
2087 struct route_map_rule_list
*match_list
= NULL
;
2088 struct route_map_rule
*rule
= NULL
;
2090 match_list
= &index
->match_list
;
2091 for (rule
= match_list
->head
; rule
; rule
= rule
->next
)
2092 if (IS_RULE_IPv6_PREFIX_LIST(rule
->cmd
->str
))
2098 /* This function does the following:
2099 * 1) If plist_name is not present, search for a IPv4 or IPv6 prefix-list
2100 * match clause (based on the afi passed to this foo) and get the
2102 * 2) Look up the prefix-list using the name.
2103 * 3) If the prefix-list is not found then, add the index to the IPv4/IPv6
2104 * default-route's node in the trie (based on the afi passed to this foo).
2105 * 4) If the prefix-list is found then, remove the index from the IPv4/IPv6
2106 * default-route's node in the trie (based on the afi passed to this foo).
2107 * 5) If a prefix-entry is passed then, create a route-node for this entry and
2108 * add this index to the route-node.
2109 * 6) If prefix-entry is not passed then, for every prefix-entry in the
2110 * prefix-list, create a route-node for this entry and
2111 * add this index to the route-node.
2113 static void route_map_add_plist_entries(afi_t afi
,
2114 struct route_map_index
*index
,
2115 const char *plist_name
,
2116 struct prefix_list_entry
*entry
)
2118 struct route_map_rule_list
*match_list
= NULL
;
2119 struct route_map_rule
*match
= NULL
;
2120 struct prefix_list
*plist
= NULL
;
2121 struct prefix_list_entry
*pentry
= NULL
;
2122 bool plist_rule_is_present
= false;
2125 match_list
= &index
->match_list
;
2127 for (match
= match_list
->head
; match
; match
= match
->next
) {
2128 if (afi
== AFI_IP
) {
2129 if (IS_RULE_IPv4_PREFIX_LIST(match
->cmd
->str
)) {
2130 plist_rule_is_present
= true;
2134 if (IS_RULE_IPv6_PREFIX_LIST(match
->cmd
->str
)) {
2135 plist_rule_is_present
= true;
2141 if (plist_rule_is_present
)
2142 plist
= prefix_list_lookup(afi
, match
->rule_str
);
2144 plist
= prefix_list_lookup(afi
, plist_name
);
2148 route_map_pfx_table_add_default(afi
, index
);
2152 /* Default entry should be deleted only if the first entry of the
2153 * prefix-list is created.
2156 if (plist
->count
== 1)
2157 route_map_pfx_table_del_default(afi
, index
);
2159 route_map_pfx_table_del_default(afi
, index
);
2163 if (afi
== AFI_IP
) {
2164 route_map_pfx_table_add(index
->map
->ipv4_prefix_table
,
2167 route_map_pfx_table_add(index
->map
->ipv6_prefix_table
,
2171 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
2172 if (afi
== AFI_IP
) {
2173 route_map_pfx_table_add(
2174 index
->map
->ipv4_prefix_table
, index
,
2177 route_map_pfx_table_add(
2178 index
->map
->ipv6_prefix_table
, index
,
2185 /* This function does the following:
2186 * 1) If plist_name is not present, search for a IPv4 or IPv6 prefix-list
2187 * match clause (based on the afi passed to this foo) and get the
2189 * 2) Look up the prefix-list using the name.
2190 * 3) If the prefix-list is not found then, delete the index from the IPv4/IPv6
2191 * default-route's node in the trie (based on the afi passed to this foo).
2192 * 4) If a prefix-entry is passed then, remove this index from the route-node
2193 * for the prefix in this prefix-entry.
2194 * 5) If prefix-entry is not passed then, for every prefix-entry in the
2195 * prefix-list, remove this index from the route-node
2196 * for the prefix in this prefix-entry.
2198 static void route_map_del_plist_entries(afi_t afi
,
2199 struct route_map_index
*index
,
2200 const char *plist_name
,
2201 struct prefix_list_entry
*entry
)
2203 struct route_map_rule_list
*match_list
= NULL
;
2204 struct route_map_rule
*match
= NULL
;
2205 struct prefix_list
*plist
= NULL
;
2206 struct prefix_list_entry
*pentry
= NULL
;
2207 bool plist_rule_is_present
= false;
2210 match_list
= &index
->match_list
;
2212 for (match
= match_list
->head
; match
; match
= match
->next
) {
2213 if (afi
== AFI_IP
) {
2214 if (IS_RULE_IPv4_PREFIX_LIST(match
->cmd
->str
)) {
2215 plist_rule_is_present
= true;
2219 if (IS_RULE_IPv6_PREFIX_LIST(match
->cmd
->str
)) {
2220 plist_rule_is_present
= true;
2226 if (plist_rule_is_present
)
2227 plist
= prefix_list_lookup(afi
, match
->rule_str
);
2229 plist
= prefix_list_lookup(afi
, plist_name
);
2233 route_map_pfx_table_del_default(afi
, index
);
2238 if (afi
== AFI_IP
) {
2239 route_map_pfx_table_del(index
->map
->ipv4_prefix_table
,
2242 route_map_pfx_table_del(index
->map
->ipv6_prefix_table
,
2246 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
2247 if (afi
== AFI_IP
) {
2248 route_map_pfx_table_del(
2249 index
->map
->ipv4_prefix_table
, index
,
2252 route_map_pfx_table_del(
2253 index
->map
->ipv6_prefix_table
, index
,
2261 * This function handles the cases where a prefix-list is added/removed
2262 * as a match command from a particular route-map index.
2263 * It updates the prefix-table of the route-map accordingly.
2265 static void route_map_trie_update(afi_t afi
, route_map_event_t event
,
2266 struct route_map_index
*index
,
2267 const char *plist_name
)
2269 if (event
== RMAP_EVENT_PLIST_ADDED
) {
2270 if (afi
== AFI_IP
) {
2271 if (!route_map_is_ipv6_pfx_list_rule_present(index
)) {
2272 route_map_pfx_table_del_default(AFI_IP6
, index
);
2273 route_map_add_plist_entries(afi
, index
,
2276 route_map_del_plist_entries(AFI_IP6
, index
,
2280 if (!route_map_is_ip_pfx_list_rule_present(index
)) {
2281 route_map_pfx_table_del_default(AFI_IP
, index
);
2282 route_map_add_plist_entries(afi
, index
,
2285 route_map_del_plist_entries(AFI_IP
, index
, NULL
,
2289 } else if (event
== RMAP_EVENT_PLIST_DELETED
) {
2290 if (afi
== AFI_IP
) {
2291 route_map_del_plist_entries(afi
, index
, plist_name
,
2294 /* If IPv6 prefix-list match rule is not present,
2295 * add this index to the IPv4 default route's trie
2297 * Also, add this index to the trie nodes created
2298 * for each of the prefix-entries within the IPv6
2299 * prefix-list, if the IPv6 prefix-list match rule
2300 * is present. Else, add this index to the IPv6
2301 * default route's trie node.
2303 if (!route_map_is_ipv6_pfx_list_rule_present(index
))
2304 route_map_pfx_table_add_default(afi
, index
);
2306 route_map_add_plist_entries(AFI_IP6
, index
, NULL
, NULL
);
2308 route_map_del_plist_entries(afi
, index
, plist_name
,
2311 /* If IPv4 prefix-list match rule is not present,
2312 * add this index to the IPv6 default route's trie
2314 * Also, add this index to the trie nodes created
2315 * for each of the prefix-entries within the IPv4
2316 * prefix-list, if the IPv4 prefix-list match rule
2317 * is present. Else, add this index to the IPv4
2318 * default route's trie node.
2320 if (!route_map_is_ip_pfx_list_rule_present(index
))
2321 route_map_pfx_table_add_default(afi
, index
);
2323 route_map_add_plist_entries(AFI_IP
, index
, NULL
, NULL
);
2329 * This function handles the cases where a route-map index and
2330 * prefix-list is added/removed.
2331 * It updates the prefix-table of the route-map accordingly.
2333 static void route_map_pfx_tbl_update(route_map_event_t event
,
2334 struct route_map_index
*index
, afi_t afi
,
2335 const char *plist_name
)
2337 struct route_map
*rmap
= NULL
;
2342 if (event
== RMAP_EVENT_INDEX_ADDED
) {
2343 route_map_pfx_table_add_default(AFI_IP
, index
);
2344 route_map_pfx_table_add_default(AFI_IP6
, index
);
2348 if (event
== RMAP_EVENT_INDEX_DELETED
) {
2349 route_map_pfx_table_del_default(AFI_IP
, index
);
2350 route_map_pfx_table_del_default(AFI_IP6
, index
);
2352 if ((index
->map
->head
== NULL
) && (index
->map
->tail
== NULL
)) {
2355 if (rmap
->ipv4_prefix_table
) {
2356 route_table_finish(rmap
->ipv4_prefix_table
);
2357 rmap
->ipv4_prefix_table
= NULL
;
2360 if (rmap
->ipv6_prefix_table
) {
2361 route_table_finish(rmap
->ipv6_prefix_table
);
2362 rmap
->ipv6_prefix_table
= NULL
;
2368 /* Handle prefix-list match rule addition/deletion.
2370 route_map_trie_update(afi
, event
, index
, plist_name
);
2374 * This function handles the cases where a new prefix-entry is added to
2375 * a prefix-list or, an existing prefix-entry is removed from the prefix-list.
2376 * It updates the prefix-table of the route-map accordingly.
2378 static void route_map_pentry_update(route_map_event_t event
,
2379 const char *plist_name
,
2380 struct route_map_index
*index
,
2381 struct prefix_list_entry
*pentry
)
2383 struct prefix_list
*plist
= NULL
;
2385 unsigned char family
= pentry
->prefix
.family
;
2387 if (family
== AF_INET
) {
2389 plist
= prefix_list_lookup(AFI_IP
, plist_name
);
2392 plist
= prefix_list_lookup(AFI_IP6
, plist_name
);
2395 if (event
== RMAP_EVENT_PLIST_ADDED
) {
2396 if (afi
== AFI_IP
) {
2397 if (!route_map_is_ipv6_pfx_list_rule_present(index
))
2398 route_map_add_plist_entries(afi
, index
,
2399 plist_name
, pentry
);
2401 if (!route_map_is_ip_pfx_list_rule_present(index
))
2402 route_map_add_plist_entries(afi
, index
,
2403 plist_name
, pentry
);
2405 } else if (event
== RMAP_EVENT_PLIST_DELETED
) {
2406 route_map_del_plist_entries(afi
, index
, plist_name
, pentry
);
2408 if (plist
->count
== 1) {
2409 if (afi
== AFI_IP
) {
2410 if (!route_map_is_ipv6_pfx_list_rule_present(
2412 route_map_pfx_table_add_default(afi
,
2415 if (!route_map_is_ip_pfx_list_rule_present(
2417 route_map_pfx_table_add_default(afi
,
2424 static void route_map_pentry_process_dependency(struct hash_bucket
*bucket
,
2427 char *rmap_name
= NULL
;
2428 struct route_map
*rmap
= NULL
;
2429 struct route_map_index
*index
= NULL
;
2430 struct route_map_rule_list
*match_list
= NULL
;
2431 struct route_map_rule
*match
= NULL
;
2432 struct route_map_dep_data
*dep_data
= NULL
;
2433 struct route_map_pentry_dep
*pentry_dep
=
2434 (struct route_map_pentry_dep
*)data
;
2435 unsigned char family
= pentry_dep
->pentry
->prefix
.family
;
2437 dep_data
= (struct route_map_dep_data
*)bucket
->data
;
2441 rmap_name
= dep_data
->rname
;
2442 rmap
= route_map_lookup_by_name(rmap_name
);
2443 if (!rmap
|| !rmap
->head
)
2446 for (index
= rmap
->head
; index
; index
= index
->next
) {
2447 match_list
= &index
->match_list
;
2452 for (match
= match_list
->head
; match
; match
= match
->next
) {
2453 if (strcmp(match
->rule_str
, pentry_dep
->plist_name
)
2455 if (IS_RULE_IPv4_PREFIX_LIST(match
->cmd
->str
)
2456 && family
== AF_INET
) {
2457 route_map_pentry_update(
2459 pentry_dep
->plist_name
, index
,
2460 pentry_dep
->pentry
);
2461 } else if (IS_RULE_IPv6_PREFIX_LIST(
2463 && family
== AF_INET6
) {
2464 route_map_pentry_update(
2466 pentry_dep
->plist_name
, index
,
2467 pentry_dep
->pentry
);
2474 void route_map_notify_pentry_dependencies(const char *affected_name
,
2475 struct prefix_list_entry
*pentry
,
2476 route_map_event_t event
)
2478 struct route_map_dep
*dep
= NULL
;
2479 struct hash
*upd8_hash
= NULL
;
2480 struct route_map_pentry_dep pentry_dep
;
2482 if (!affected_name
|| !pentry
)
2485 upd8_hash
= route_map_get_dep_hash(event
);
2489 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, (void *)affected_name
,
2492 if (!dep
->this_hash
)
2493 dep
->this_hash
= upd8_hash
;
2495 memset(&pentry_dep
, 0, sizeof(pentry_dep
));
2496 pentry_dep
.pentry
= pentry
;
2497 pentry_dep
.plist_name
= affected_name
;
2498 pentry_dep
.event
= event
;
2500 hash_iterate(dep
->dep_rmap_hash
,
2501 route_map_pentry_process_dependency
,
2502 (void *)&pentry_dep
);
2506 /* Apply route map's each index to the object.
2508 The matrix for a route-map looks like this:
2509 (note, this includes the description for the "NEXT"
2510 and "GOTO" frobs now
2512 | Match | No Match | No op
2513 |-----------|--------------|-------
2514 permit | action | cont | cont.
2515 | | default:deny | default:permit
2516 -------------------+-----------------------
2517 | deny | cont | cont.
2518 deny | | default:deny | default:permit
2519 |-----------|--------------|--------
2522 -Apply Set statements, accept route
2523 -If Call statement is present jump to the specified route-map, if it
2524 denies the route we finish.
2525 -If NEXT is specified, goto NEXT statement
2526 -If GOTO is specified, goto the first clause where pref > nextpref
2527 -If nothing is specified, do as Cisco and finish
2529 -Route is denied by route-map.
2533 If we get no matches after we've processed all updates, then the route
2536 Some notes on the new "CALL", "NEXT" and "GOTO"
2537 call WORD - If this clause is matched, then the set statements
2538 are executed and then we jump to route-map 'WORD'. If
2539 this route-map denies the route, we finish, in other
2541 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
2542 on-match next - If this clause is matched, then the set statements
2543 are executed and then we drop through to the next clause
2544 on-match goto n - If this clause is matched, then the set statements
2545 are executed and then we goto the nth clause, or the
2546 first clause greater than this. In order to ensure
2547 route-maps *always* exit, you cannot jump backwards.
2550 We need to make sure our route-map processing matches the above
2552 route_map_result_t
route_map_apply_ext(struct route_map
*map
,
2553 const struct prefix
*prefix
,
2554 void *match_object
, void *set_object
,
2557 static int recursion
= 0;
2558 enum route_map_cmd_result_t match_ret
= RMAP_NOMATCH
;
2559 route_map_result_t ret
= RMAP_PERMITMATCH
;
2560 struct route_map_index
*index
= NULL
;
2561 struct route_map_rule
*set
= NULL
;
2562 bool skip_match_clause
= false;
2564 if (recursion
> RMAP_RECURSION_LIMIT
) {
2566 EC_LIB_RMAP_RECURSION_LIMIT
,
2567 "route-map recursion limit (%d) reached, discarding route",
2568 RMAP_RECURSION_LIMIT
);
2570 return RMAP_DENYMATCH
;
2573 if (map
== NULL
|| map
->head
== NULL
) {
2574 ret
= RMAP_DENYMATCH
;
2575 goto route_map_apply_end
;
2580 if ((!map
->optimization_disabled
)
2581 && (map
->ipv4_prefix_table
|| map
->ipv6_prefix_table
)) {
2582 index
= route_map_get_index(map
, prefix
, match_object
,
2586 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
2588 "Best match route-map: %s, sequence: %d for pfx: %pFX, result: %s",
2589 map
->name
, index
->pref
, prefix
,
2590 route_map_cmd_result_str(match_ret
));
2592 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
2594 "No best match sequence for pfx: %pFX in route-map: %s, result: %s",
2596 route_map_cmd_result_str(match_ret
));
2598 * No index matches this prefix. Return deny unless,
2599 * match_ret = RMAP_NOOP.
2601 if (match_ret
== RMAP_NOOP
)
2602 ret
= RMAP_PERMITMATCH
;
2604 ret
= RMAP_DENYMATCH
;
2605 goto route_map_apply_end
;
2607 skip_match_clause
= true;
2612 for (; index
; index
= index
->next
) {
2613 if (!skip_match_clause
) {
2615 /* Apply this index. */
2616 match_ret
= route_map_apply_match(&index
->match_list
,
2617 prefix
, match_object
);
2618 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
)) {
2620 "Route-map: %s, sequence: %d, prefix: %pFX, result: %s",
2621 map
->name
, index
->pref
, prefix
,
2622 route_map_cmd_result_str(match_ret
));
2625 skip_match_clause
= false;
2628 /* Now we apply the matrix from above */
2629 if (match_ret
== RMAP_NOOP
)
2631 * Do not change the return value. Retain the previous
2632 * return value. Previous values can be:
2633 * 1)permitmatch (if a nomatch was never
2634 * seen before in this route-map.)
2635 * 2)denymatch (if a nomatch was seen earlier in one
2636 * of the previous sequences)
2640 * 'cont' from matrix - continue to next route-map
2644 else if (match_ret
== RMAP_NOMATCH
) {
2647 * The return value is now changed to denymatch.
2648 * So from here on out, even if we see more noops,
2649 * we retain this return value and return this
2650 * eventually if there are no matches.
2652 ret
= RMAP_DENYMATCH
;
2655 * 'cont' from matrix - continue to next route-map
2659 } else if (match_ret
== RMAP_MATCH
) {
2660 if (index
->type
== RMAP_PERMIT
)
2663 /* Match succeeded, rmap is of type permit */
2664 ret
= RMAP_PERMITMATCH
;
2666 /* permit+match must execute sets */
2667 for (set
= index
->set_list
.head
; set
;
2670 * set cmds return RMAP_OKAY or
2671 * RMAP_ERROR. We do not care if
2672 * set succeeded or not. So, ignore
2675 (void)(*set
->cmd
->func_apply
)(
2676 set
->value
, prefix
, set_object
);
2678 /* Call another route-map if available */
2679 if (index
->nextrm
) {
2680 struct route_map
*nextrm
=
2681 route_map_lookup_by_name(
2684 if (nextrm
) /* Target route-map found,
2688 ret
= route_map_apply_ext(
2695 /* If nextrm returned 'deny', finish. */
2696 if (ret
== RMAP_DENYMATCH
)
2697 goto route_map_apply_end
;
2700 switch (index
->exitpolicy
) {
2702 goto route_map_apply_end
;
2706 /* Find the next clause to jump to */
2707 struct route_map_index
*next
=
2709 int nextpref
= index
->nextpref
;
2711 while (next
&& next
->pref
< nextpref
) {
2716 /* No clauses match! */
2717 goto route_map_apply_end
;
2721 } else if (index
->type
== RMAP_DENY
)
2724 ret
= RMAP_DENYMATCH
;
2725 goto route_map_apply_end
;
2730 route_map_apply_end
:
2731 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
2732 zlog_debug("Route-map: %s, prefix: %pFX, result: %s",
2733 (map
? map
->name
: "null"), prefix
,
2734 route_map_result_str(ret
));
2737 if (index
!= NULL
&& ret
== RMAP_PERMITMATCH
)
2738 *pref
= index
->pref
;
2746 void route_map_add_hook(void (*func
)(const char *))
2748 route_map_master
.add_hook
= func
;
2751 void route_map_delete_hook(void (*func
)(const char *))
2753 route_map_master
.delete_hook
= func
;
2756 void route_map_event_hook(void (*func
)(const char *name
))
2758 route_map_master
.event_hook
= func
;
2761 /* Routines for route map dependency lists and dependency processing */
2762 static bool route_map_rmap_hash_cmp(const void *p1
, const void *p2
)
2764 return strcmp(((const struct route_map_dep_data
*)p1
)->rname
,
2765 ((const struct route_map_dep_data
*)p2
)->rname
)
2769 static bool route_map_dep_hash_cmp(const void *p1
, const void *p2
)
2772 return (strcmp(((const struct route_map_dep
*)p1
)->dep_name
,
2777 static void route_map_clear_reference(struct hash_bucket
*bucket
, void *arg
)
2779 struct route_map_dep
*dep
= bucket
->data
;
2780 struct route_map_dep_data
*dep_data
= NULL
, tmp_dep_data
;
2782 memset(&tmp_dep_data
, 0, sizeof(tmp_dep_data
));
2783 tmp_dep_data
.rname
= arg
;
2784 dep_data
= hash_release(dep
->dep_rmap_hash
, &tmp_dep_data
);
2786 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
2787 zlog_debug("Clearing reference for %s to %s count: %d",
2788 dep
->dep_name
, tmp_dep_data
.rname
,
2791 XFREE(MTYPE_ROUTE_MAP_NAME
, dep_data
->rname
);
2792 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, dep_data
);
2794 if (!dep
->dep_rmap_hash
->count
) {
2795 dep
= hash_release(dep
->this_hash
, (void *)dep
->dep_name
);
2796 hash_free(dep
->dep_rmap_hash
);
2797 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
2798 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
2802 static void route_map_clear_all_references(char *rmap_name
)
2806 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
2807 zlog_debug("Clearing references for %s", rmap_name
);
2809 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
2810 hash_iterate(route_map_dep_hash
[i
], route_map_clear_reference
,
2815 static unsigned int route_map_dep_data_hash_make_key(const void *p
)
2817 const struct route_map_dep_data
*dep_data
= p
;
2819 return string_hash_make(dep_data
->rname
);
2822 static void *route_map_dep_hash_alloc(void *p
)
2824 char *dep_name
= (char *)p
;
2825 struct route_map_dep
*dep_entry
;
2827 dep_entry
= XCALLOC(MTYPE_ROUTE_MAP_DEP
, sizeof(struct route_map_dep
));
2828 dep_entry
->dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
2829 dep_entry
->dep_rmap_hash
=
2830 hash_create_size(8, route_map_dep_data_hash_make_key
,
2831 route_map_rmap_hash_cmp
, "Route Map Dep Hash");
2832 dep_entry
->this_hash
= NULL
;
2837 static void *route_map_name_hash_alloc(void *p
)
2839 struct route_map_dep_data
*dep_data
= NULL
, *tmp_dep_data
= NULL
;
2841 dep_data
= XCALLOC(MTYPE_ROUTE_MAP_DEP_DATA
,
2842 sizeof(struct route_map_dep_data
));
2844 dep_data
->rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, tmp_dep_data
->rname
);
2848 static unsigned int route_map_dep_hash_make_key(const void *p
)
2850 return (string_hash_make((char *)p
));
2853 static void route_map_print_dependency(struct hash_bucket
*bucket
, void *data
)
2855 struct route_map_dep_data
*dep_data
= bucket
->data
;
2856 char *rmap_name
= dep_data
->rname
;
2857 char *dep_name
= data
;
2859 zlog_debug("%s: Dependency for %s: %s", __func__
, dep_name
, rmap_name
);
2862 static int route_map_dep_update(struct hash
*dephash
, const char *dep_name
,
2863 const char *rmap_name
, route_map_event_t type
)
2865 struct route_map_dep
*dep
= NULL
;
2866 char *dname
, *rname
;
2868 struct route_map_dep_data
*dep_data
= NULL
, *ret_dep_data
= NULL
;
2869 struct route_map_dep_data tmp_dep_data
;
2871 dname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
2872 rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
2875 case RMAP_EVENT_PLIST_ADDED
:
2876 case RMAP_EVENT_CLIST_ADDED
:
2877 case RMAP_EVENT_ECLIST_ADDED
:
2878 case RMAP_EVENT_ASLIST_ADDED
:
2879 case RMAP_EVENT_LLIST_ADDED
:
2880 case RMAP_EVENT_CALL_ADDED
:
2881 case RMAP_EVENT_FILTER_ADDED
:
2882 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
2883 zlog_debug("Adding dependency for filter %s in route-map %s",
2884 dep_name
, rmap_name
);
2885 dep
= (struct route_map_dep
*)hash_get(
2886 dephash
, dname
, route_map_dep_hash_alloc
);
2892 if (!dep
->this_hash
)
2893 dep
->this_hash
= dephash
;
2895 memset(&tmp_dep_data
, 0, sizeof(tmp_dep_data
));
2896 tmp_dep_data
.rname
= rname
;
2897 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
2899 dep_data
= hash_get(dep
->dep_rmap_hash
, &tmp_dep_data
,
2900 route_map_name_hash_alloc
);
2904 case RMAP_EVENT_PLIST_DELETED
:
2905 case RMAP_EVENT_CLIST_DELETED
:
2906 case RMAP_EVENT_ECLIST_DELETED
:
2907 case RMAP_EVENT_ASLIST_DELETED
:
2908 case RMAP_EVENT_LLIST_DELETED
:
2909 case RMAP_EVENT_CALL_DELETED
:
2910 case RMAP_EVENT_FILTER_DELETED
:
2911 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
2912 zlog_debug("Deleting dependency for filter %s in route-map %s",
2913 dep_name
, rmap_name
);
2914 dep
= (struct route_map_dep
*)hash_get(dephash
, dname
, NULL
);
2919 memset(&tmp_dep_data
, 0, sizeof(tmp_dep_data
));
2920 tmp_dep_data
.rname
= rname
;
2921 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
2923 * If dep_data is NULL then something has gone seriously
2924 * wrong in route-map handling. Note it and prevent
2929 "route-map dependency for route-map %s: %s is not correct",
2930 rmap_name
, dep_name
);
2936 if (!dep_data
->refcnt
) {
2937 ret_dep_data
= hash_release(dep
->dep_rmap_hash
,
2940 XFREE(MTYPE_ROUTE_MAP_NAME
,
2941 ret_dep_data
->rname
);
2942 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, ret_dep_data
);
2946 if (!dep
->dep_rmap_hash
->count
) {
2947 dep
= hash_release(dephash
, dname
);
2948 hash_free(dep
->dep_rmap_hash
);
2949 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
2950 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
2953 case RMAP_EVENT_SET_ADDED
:
2954 case RMAP_EVENT_SET_DELETED
:
2955 case RMAP_EVENT_SET_REPLACED
:
2956 case RMAP_EVENT_MATCH_ADDED
:
2957 case RMAP_EVENT_MATCH_DELETED
:
2958 case RMAP_EVENT_MATCH_REPLACED
:
2959 case RMAP_EVENT_INDEX_ADDED
:
2960 case RMAP_EVENT_INDEX_DELETED
:
2965 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
2966 hash_iterate(dep
->dep_rmap_hash
,
2967 route_map_print_dependency
, dname
);
2971 XFREE(MTYPE_ROUTE_MAP_NAME
, rname
);
2972 XFREE(MTYPE_ROUTE_MAP_NAME
, dname
);
2976 static struct hash
*route_map_get_dep_hash(route_map_event_t event
)
2978 struct hash
*upd8_hash
= NULL
;
2981 case RMAP_EVENT_PLIST_ADDED
:
2982 case RMAP_EVENT_PLIST_DELETED
:
2983 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_PLIST
];
2985 case RMAP_EVENT_CLIST_ADDED
:
2986 case RMAP_EVENT_CLIST_DELETED
:
2987 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_CLIST
];
2989 case RMAP_EVENT_ECLIST_ADDED
:
2990 case RMAP_EVENT_ECLIST_DELETED
:
2991 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ECLIST
];
2993 case RMAP_EVENT_ASLIST_ADDED
:
2994 case RMAP_EVENT_ASLIST_DELETED
:
2995 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ASPATH
];
2997 case RMAP_EVENT_LLIST_ADDED
:
2998 case RMAP_EVENT_LLIST_DELETED
:
2999 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_LCLIST
];
3001 case RMAP_EVENT_CALL_ADDED
:
3002 case RMAP_EVENT_CALL_DELETED
:
3003 case RMAP_EVENT_MATCH_ADDED
:
3004 case RMAP_EVENT_MATCH_DELETED
:
3005 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_RMAP
];
3007 case RMAP_EVENT_FILTER_ADDED
:
3008 case RMAP_EVENT_FILTER_DELETED
:
3009 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_FILTER
];
3012 * Should we actually be ignoring these?
3013 * I am not sure but at this point in time, let
3014 * us get them into this switch and we can peel
3015 * them into the appropriate place in the future
3017 case RMAP_EVENT_SET_ADDED
:
3018 case RMAP_EVENT_SET_DELETED
:
3019 case RMAP_EVENT_SET_REPLACED
:
3020 case RMAP_EVENT_MATCH_REPLACED
:
3021 case RMAP_EVENT_INDEX_ADDED
:
3022 case RMAP_EVENT_INDEX_DELETED
:
3029 static void route_map_process_dependency(struct hash_bucket
*bucket
, void *data
)
3031 struct route_map_dep_data
*dep_data
= NULL
;
3032 char *rmap_name
= NULL
;
3034 dep_data
= bucket
->data
;
3035 rmap_name
= dep_data
->rname
;
3037 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
3038 zlog_debug("Notifying %s of dependency", rmap_name
);
3039 if (route_map_master
.event_hook
)
3040 (*route_map_master
.event_hook
)(rmap_name
);
3043 void route_map_upd8_dependency(route_map_event_t type
, const char *arg
,
3044 const char *rmap_name
)
3046 struct hash
*upd8_hash
= NULL
;
3048 if ((upd8_hash
= route_map_get_dep_hash(type
))) {
3049 route_map_dep_update(upd8_hash
, arg
, rmap_name
, type
);
3051 if (type
== RMAP_EVENT_CALL_ADDED
) {
3053 if (route_map_master
.add_hook
)
3054 (*route_map_master
.add_hook
)(rmap_name
);
3055 } else if (type
== RMAP_EVENT_CALL_DELETED
) {
3057 if (route_map_master
.delete_hook
)
3058 (*route_map_master
.delete_hook
)(rmap_name
);
3063 void route_map_notify_dependencies(const char *affected_name
,
3064 route_map_event_t event
)
3066 struct route_map_dep
*dep
;
3067 struct hash
*upd8_hash
;
3073 name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, affected_name
);
3075 if ((upd8_hash
= route_map_get_dep_hash(event
)) == NULL
) {
3076 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
3080 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, name
, NULL
);
3082 if (!dep
->this_hash
)
3083 dep
->this_hash
= upd8_hash
;
3085 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
3086 zlog_debug("Filter %s updated", dep
->dep_name
);
3087 hash_iterate(dep
->dep_rmap_hash
, route_map_process_dependency
,
3091 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
3094 /* VTY related functions. */
3095 static void clear_route_map_helper(struct route_map
*map
)
3097 struct route_map_index
*index
;
3099 map
->applied_clear
= map
->applied
;
3100 for (index
= map
->head
; index
; index
= index
->next
)
3101 index
->applied_clear
= index
->applied
;
3104 DEFUN (rmap_clear_counters
,
3105 rmap_clear_counters_cmd
,
3106 "clear route-map counters [WORD]",
3108 "route-map information\n"
3109 "counters associated with the specified route-map\n"
3113 struct route_map
*map
;
3115 const char *name
= (argc
== 3 ) ? argv
[idx_word
]->arg
: NULL
;
3118 map
= route_map_lookup_by_name(name
);
3121 clear_route_map_helper(map
);
3123 vty_out(vty
, "%s: 'route-map %s' not found\n",
3124 frr_protonameinst
, name
);
3128 for (map
= route_map_master
.head
; map
; map
= map
->next
)
3129 clear_route_map_helper(map
);
3136 DEFUN (rmap_show_name
,
3138 "show route-map [WORD] [json]",
3140 "route-map information\n"
3144 bool uj
= use_json(argc
, argv
);
3146 const char *name
= NULL
;
3148 if (argv_find(argv
, argc
, "WORD", &idx
))
3149 name
= argv
[idx
]->arg
;
3151 return vty_show_route_map(vty
, name
, uj
);
3154 DEFUN (rmap_show_unused
,
3155 rmap_show_unused_cmd
,
3156 "show route-map-unused",
3158 "unused route-map information\n")
3160 return vty_show_unused_route_map(vty
);
3165 "debug route-map [detail]$detail",
3167 "Debug option set for route-maps\n"
3168 "Detailed output\n")
3171 SET_FLAG(rmap_debug
, DEBUG_ROUTEMAP
);
3173 SET_FLAG(rmap_debug
, DEBUG_ROUTEMAP
| DEBUG_ROUTEMAP_DETAIL
);
3178 DEFPY (no_debug_rmap
,
3180 "no debug route-map [detail]$detail",
3183 "Debug option set for route-maps\n"
3184 "Detailed output\n")
3187 UNSET_FLAG(rmap_debug
, DEBUG_ROUTEMAP
);
3189 UNSET_FLAG(rmap_debug
, DEBUG_ROUTEMAP
| DEBUG_ROUTEMAP_DETAIL
);
3195 static int rmap_config_write_debug(struct vty
*vty
);
3196 static struct cmd_node rmap_debug_node
= {
3197 .name
= "route-map debug",
3198 .node
= RMAP_DEBUG_NODE
,
3200 .config_write
= rmap_config_write_debug
,
3203 void route_map_show_debug(struct vty
*vty
)
3205 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
))
3206 vty_out(vty
, "debug route-map\n");
3209 /* Configuration write function. */
3210 static int rmap_config_write_debug(struct vty
*vty
)
3214 if (CHECK_FLAG(rmap_debug
, DEBUG_ROUTEMAP
)) {
3215 vty_out(vty
, "debug route-map\n");
3222 /* Common route map rules */
3224 void *route_map_rule_tag_compile(const char *arg
)
3226 unsigned long int tmp
;
3231 tmp
= strtoul(arg
, &endptr
, 0);
3232 if (arg
[0] == '\0' || *endptr
!= '\0' || errno
|| tmp
> ROUTE_TAG_MAX
)
3235 tag
= XMALLOC(MTYPE_ROUTE_MAP_COMPILED
, sizeof(*tag
));
3241 void route_map_rule_tag_free(void *rule
)
3243 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
3246 void route_map_finish(void)
3249 struct route_map_rule_cmd_proxy
*proxy
;
3251 /* these 2 hash tables have INIT_HASH initializers, so the "default"
3252 * state is "initialized & empty" => fini() followed by init() to
3253 * return to that same state
3255 while ((proxy
= rmap_cmd_name_pop(rmap_match_cmds
)))
3257 rmap_cmd_name_fini(rmap_match_cmds
);
3258 rmap_cmd_name_init(rmap_match_cmds
);
3260 while ((proxy
= rmap_cmd_name_pop(rmap_set_cmds
)))
3262 rmap_cmd_name_fini(rmap_set_cmds
);
3263 rmap_cmd_name_init(rmap_set_cmds
);
3266 * All protocols are setting these to NULL
3267 * by default on shutdown( route_map_finish )
3268 * Why are we making them do this work?
3270 route_map_master
.add_hook
= NULL
;
3271 route_map_master
.delete_hook
= NULL
;
3272 route_map_master
.event_hook
= NULL
;
3274 /* cleanup route_map */
3275 while (route_map_master
.head
) {
3276 struct route_map
*map
= route_map_master
.head
;
3277 map
->to_be_processed
= false;
3278 route_map_delete(map
);
3281 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
3282 hash_free(route_map_dep_hash
[i
]);
3283 route_map_dep_hash
[i
] = NULL
;
3286 hash_free(route_map_master_hash
);
3287 route_map_master_hash
= NULL
;
3290 /* Increment the use_count counter while attaching the route map */
3291 void route_map_counter_increment(struct route_map
*map
)
3297 /* Decrement the use_count counter while detaching the route map. */
3298 void route_map_counter_decrement(struct route_map
*map
)
3301 if (map
->use_count
<= 0)
3307 DEFUN_HIDDEN(show_route_map_pfx_tbl
, show_route_map_pfx_tbl_cmd
,
3308 "show route-map RMAP_NAME prefix-table",
3312 "internal prefix-table\n")
3314 const char *rmap_name
= argv
[2]->arg
;
3315 struct route_map
*rmap
= NULL
;
3316 struct route_table
*rm_pfx_tbl4
= NULL
;
3317 struct route_table
*rm_pfx_tbl6
= NULL
;
3318 struct route_node
*rn
= NULL
, *prn
= NULL
;
3319 struct list
*rmap_index_list
= NULL
;
3320 struct listnode
*ln
= NULL
, *nln
= NULL
;
3321 struct route_map_index
*index
= NULL
;
3324 vty_out(vty
, "%s:\n", frr_protonameinst
);
3325 rmap
= route_map_lookup_by_name(rmap_name
);
3327 rm_pfx_tbl4
= rmap
->ipv4_prefix_table
;
3329 vty_out(vty
, "\n%s%43s%s\n", "IPv4 Prefix", "",
3330 "Route-map Index List");
3331 vty_out(vty
, "%s%39s%s\n", "_______________", "",
3332 "____________________");
3333 for (rn
= route_top(rm_pfx_tbl4
); rn
;
3334 rn
= route_next(rn
)) {
3335 vty_out(vty
, " %pRN (%d)\n", rn
,
3336 route_node_get_lock_count(rn
));
3338 vty_out(vty
, "(P) ");
3341 vty_out(vty
, "%pRN\n", prn
);
3345 rmap_index_list
= (struct list
*)rn
->info
;
3346 if (!rmap_index_list
3347 || !listcount(rmap_index_list
))
3348 vty_out(vty
, "%*s%s\n", len
, "", "-");
3350 for (ALL_LIST_ELEMENTS(rmap_index_list
,
3353 vty_out(vty
, "%*s%s seq %d\n",
3362 rm_pfx_tbl6
= rmap
->ipv6_prefix_table
;
3364 vty_out(vty
, "\n%s%43s%s\n", "IPv6 Prefix", "",
3365 "Route-map Index List");
3366 vty_out(vty
, "%s%39s%s\n", "_______________", "",
3367 "____________________");
3368 for (rn
= route_top(rm_pfx_tbl6
); rn
;
3369 rn
= route_next(rn
)) {
3370 vty_out(vty
, " %pRN (%d)\n", rn
,
3371 route_node_get_lock_count(rn
));
3373 vty_out(vty
, "(P) ");
3376 vty_out(vty
, "%pRN\n", prn
);
3380 rmap_index_list
= (struct list
*)rn
->info
;
3381 if (!rmap_index_list
3382 || !listcount(rmap_index_list
))
3383 vty_out(vty
, "%*s%s\n", len
, "", "-");
3385 for (ALL_LIST_ELEMENTS(rmap_index_list
,
3388 vty_out(vty
, "%*s%s seq %d\n",
3402 /* Initialization of route map vector. */
3403 void route_map_init(void)
3407 route_map_master_hash
=
3408 hash_create_size(8, route_map_hash_key_make
, route_map_hash_cmp
,
3409 "Route Map Master Hash");
3411 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++)
3412 route_map_dep_hash
[i
] = hash_create_size(
3413 8, route_map_dep_hash_make_key
, route_map_dep_hash_cmp
,
3414 "Route Map Dep Hash");
3416 UNSET_FLAG(rmap_debug
, DEBUG_ROUTEMAP
);
3418 route_map_cli_init();
3420 /* Install route map top node. */
3421 install_node(&rmap_debug_node
);
3423 /* Install route map commands. */
3424 install_element(CONFIG_NODE
, &debug_rmap_cmd
);
3425 install_element(CONFIG_NODE
, &no_debug_rmap_cmd
);
3427 /* Install show command */
3428 install_element(ENABLE_NODE
, &rmap_clear_counters_cmd
);
3430 install_element(ENABLE_NODE
, &rmap_show_name_cmd
);
3431 install_element(ENABLE_NODE
, &rmap_show_unused_cmd
);
3433 install_element(ENABLE_NODE
, &debug_rmap_cmd
);
3434 install_element(ENABLE_NODE
, &no_debug_rmap_cmd
);
3436 install_element(ENABLE_NODE
, &show_route_map_pfx_tbl_cmd
);