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 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP
, "Route map");
40 DEFINE_MTYPE(LIB
, ROUTE_MAP_NAME
, "Route map name");
41 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_INDEX
, "Route map index");
42 DEFINE_MTYPE(LIB
, ROUTE_MAP_RULE
, "Route map rule");
43 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_RULE_STR
, "Route map rule str");
44 DEFINE_MTYPE(LIB
, ROUTE_MAP_COMPILED
, "Route map compiled");
45 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_DEP
, "Route map dependency");
46 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_DEP_DATA
, "Route map dependency data");
48 DEFINE_QOBJ_TYPE(route_map_index
);
49 DEFINE_QOBJ_TYPE(route_map
);
51 static int rmap_cmd_name_cmp(const struct route_map_rule_cmd_proxy
*a
,
52 const struct route_map_rule_cmd_proxy
*b
)
54 return strcmp(a
->cmd
->str
, b
->cmd
->str
);
57 static uint32_t rmap_cmd_name_hash(const struct route_map_rule_cmd_proxy
*item
)
59 return jhash(item
->cmd
->str
, strlen(item
->cmd
->str
), 0xbfd69320);
62 DECLARE_HASH(rmap_cmd_name
, struct route_map_rule_cmd_proxy
, itm
,
63 rmap_cmd_name_cmp
, rmap_cmd_name_hash
);
65 static struct rmap_cmd_name_head rmap_match_cmds
[1] = {
66 INIT_HASH(rmap_match_cmds
[0]),
68 static struct rmap_cmd_name_head rmap_set_cmds
[1] = {
69 INIT_HASH(rmap_set_cmds
[0]),
72 #define IPv4_PREFIX_LIST "ip address prefix-list"
73 #define IPv6_PREFIX_LIST "ipv6 address prefix-list"
75 #define IS_RULE_IPv4_PREFIX_LIST(S) \
76 (strncmp(S, IPv4_PREFIX_LIST, strlen(IPv4_PREFIX_LIST)) == 0)
77 #define IS_RULE_IPv6_PREFIX_LIST(S) \
78 (strncmp(S, IPv6_PREFIX_LIST, strlen(IPv6_PREFIX_LIST)) == 0)
80 struct route_map_pentry_dep
{
81 struct prefix_list_entry
*pentry
;
82 const char *plist_name
;
83 route_map_event_t event
;
86 static void route_map_pfx_tbl_update(route_map_event_t event
,
87 struct route_map_index
*index
, afi_t afi
,
88 const char *plist_name
);
89 static void route_map_pfx_table_add_default(afi_t afi
,
90 struct route_map_index
*index
);
91 static void route_map_pfx_table_del_default(afi_t afi
,
92 struct route_map_index
*index
);
93 static void route_map_add_plist_entries(afi_t afi
,
94 struct route_map_index
*index
,
95 const char *plist_name
,
96 struct prefix_list_entry
*entry
);
97 static void route_map_del_plist_entries(afi_t afi
,
98 struct route_map_index
*index
,
99 const char *plist_name
,
100 struct prefix_list_entry
*entry
);
102 static struct hash
*route_map_get_dep_hash(route_map_event_t event
);
103 static void route_map_free_map(struct route_map
*map
);
105 struct route_map_match_set_hooks rmap_match_set_hook
;
107 /* match interface */
108 void route_map_match_interface_hook(int (*func
)(
109 struct route_map_index
*index
, const char *command
,
110 const char *arg
, route_map_event_t type
,
111 char *errmsg
, size_t errmsg_len
))
113 rmap_match_set_hook
.match_interface
= func
;
116 /* no match interface */
117 void route_map_no_match_interface_hook(int (*func
)(
118 struct route_map_index
*index
, const char *command
,
119 const char *arg
, route_map_event_t type
,
120 char *errmsg
, size_t errmsg_len
))
122 rmap_match_set_hook
.no_match_interface
= func
;
125 /* match ip address */
126 void route_map_match_ip_address_hook(int (*func
)(
127 struct route_map_index
*index
, const char *command
,
128 const char *arg
, route_map_event_t type
,
129 char *errmsg
, size_t errmsg_len
))
131 rmap_match_set_hook
.match_ip_address
= func
;
134 /* no match ip address */
135 void route_map_no_match_ip_address_hook(int (*func
)(
136 struct route_map_index
*index
, const char *command
,
137 const char *arg
, route_map_event_t type
,
138 char *errmsg
, size_t errmsg_len
))
140 rmap_match_set_hook
.no_match_ip_address
= func
;
143 /* match ip address prefix list */
144 void route_map_match_ip_address_prefix_list_hook(int (*func
)(
145 struct route_map_index
*index
, const char *command
,
146 const char *arg
, route_map_event_t type
,
147 char *errmsg
, size_t errmsg_len
))
149 rmap_match_set_hook
.match_ip_address_prefix_list
= func
;
152 /* no match ip address prefix list */
153 void route_map_no_match_ip_address_prefix_list_hook(int (*func
)(
154 struct route_map_index
*index
, const char *command
,
155 const char *arg
, route_map_event_t type
,
156 char *errmsg
, size_t errmsg_len
))
158 rmap_match_set_hook
.no_match_ip_address_prefix_list
= func
;
161 /* match ip next hop */
162 void route_map_match_ip_next_hop_hook(int (*func
)(
163 struct route_map_index
*index
, const char *command
,
164 const char *arg
, route_map_event_t type
,
165 char *errmsg
, size_t errmsg_len
))
167 rmap_match_set_hook
.match_ip_next_hop
= func
;
170 /* no match ip next hop */
171 void route_map_no_match_ip_next_hop_hook(int (*func
)(
172 struct route_map_index
*index
, const char *command
,
173 const char *arg
, route_map_event_t type
,
174 char *errmsg
, size_t errmsg_len
))
176 rmap_match_set_hook
.no_match_ip_next_hop
= func
;
179 /* match ipv6 next-hop */
180 void route_map_match_ipv6_next_hop_hook(int (*func
)(
181 struct route_map_index
*index
, const char *command
, const char *arg
,
182 route_map_event_t type
, char *errmsg
, size_t errmsg_len
))
184 rmap_match_set_hook
.match_ipv6_next_hop
= func
;
187 /* no match ipv6 next-hop */
188 void route_map_no_match_ipv6_next_hop_hook(int (*func
)(
189 struct route_map_index
*index
, const char *command
, const char *arg
,
190 route_map_event_t type
, char *errmsg
, size_t errmsg_len
))
192 rmap_match_set_hook
.no_match_ipv6_next_hop
= func
;
195 /* match ip next hop prefix list */
196 void route_map_match_ip_next_hop_prefix_list_hook(int (*func
)(
197 struct route_map_index
*index
, const char *command
,
198 const char *arg
, route_map_event_t type
,
199 char *errmsg
, size_t errmsg_len
))
201 rmap_match_set_hook
.match_ip_next_hop_prefix_list
= func
;
204 /* no match ip next hop prefix list */
205 void route_map_no_match_ip_next_hop_prefix_list_hook(int (*func
)(
206 struct route_map_index
*index
, const char *command
,
207 const char *arg
, route_map_event_t type
,
208 char *errmsg
, size_t errmsg_len
))
210 rmap_match_set_hook
.no_match_ip_next_hop_prefix_list
= func
;
213 /* match ip next-hop type */
214 void route_map_match_ip_next_hop_type_hook(int (*func
)(
215 struct route_map_index
*index
, const char *command
,
216 const char *arg
, route_map_event_t type
,
217 char *errmsg
, size_t errmsg_len
))
219 rmap_match_set_hook
.match_ip_next_hop_type
= func
;
222 /* no match ip next-hop type */
223 void route_map_no_match_ip_next_hop_type_hook(int (*func
)(
224 struct route_map_index
*index
, const char *command
,
225 const char *arg
, route_map_event_t type
,
226 char *errmsg
, size_t errmsg_len
))
228 rmap_match_set_hook
.no_match_ip_next_hop_type
= func
;
231 /* match ipv6 address */
232 void route_map_match_ipv6_address_hook(int (*func
)(
233 struct route_map_index
*index
, const char *command
,
234 const char *arg
, route_map_event_t type
,
235 char *errmsg
, size_t errmsg_len
))
237 rmap_match_set_hook
.match_ipv6_address
= func
;
240 /* no match ipv6 address */
241 void route_map_no_match_ipv6_address_hook(int (*func
)(
242 struct route_map_index
*index
, const char *command
,
243 const char *arg
, route_map_event_t type
,
244 char *errmsg
, size_t errmsg_len
))
246 rmap_match_set_hook
.no_match_ipv6_address
= func
;
250 /* match ipv6 address prefix list */
251 void route_map_match_ipv6_address_prefix_list_hook(int (*func
)(
252 struct route_map_index
*index
, const char *command
,
253 const char *arg
, route_map_event_t type
,
254 char *errmsg
, size_t errmsg_len
))
256 rmap_match_set_hook
.match_ipv6_address_prefix_list
= func
;
259 /* no match ipv6 address prefix list */
260 void route_map_no_match_ipv6_address_prefix_list_hook(int (*func
)(
261 struct route_map_index
*index
, const char *command
,
262 const char *arg
, route_map_event_t type
,
263 char *errmsg
, size_t errmsg_len
))
265 rmap_match_set_hook
.no_match_ipv6_address_prefix_list
= func
;
268 /* match ipv6 next-hop type */
269 void route_map_match_ipv6_next_hop_type_hook(int (*func
)(
270 struct route_map_index
*index
, const char *command
,
271 const char *arg
, route_map_event_t type
,
272 char *errmsg
, size_t errmsg_len
))
274 rmap_match_set_hook
.match_ipv6_next_hop_type
= func
;
277 /* no match ipv6 next-hop type */
278 void route_map_no_match_ipv6_next_hop_type_hook(int (*func
)(
279 struct route_map_index
*index
, const char *command
,
280 const char *arg
, route_map_event_t type
,
281 char *errmsg
, size_t errmsg_len
))
283 rmap_match_set_hook
.no_match_ipv6_next_hop_type
= func
;
286 /* match ipv6 next-hop prefix-list */
287 void route_map_match_ipv6_next_hop_prefix_list_hook(int (*func
)(
288 struct route_map_index
*index
, const char *command
, const char *arg
,
289 route_map_event_t type
, char *errmsg
, size_t errmsg_len
))
291 rmap_match_set_hook
.match_ipv6_next_hop_prefix_list
= func
;
294 /* no match ipv6 next-hop prefix-list */
295 void route_map_no_match_ipv6_next_hop_prefix_list_hook(int (*func
)(
296 struct route_map_index
*index
, const char *command
, const char *arg
,
297 route_map_event_t type
, char *errmsg
, size_t errmsg_len
))
299 rmap_match_set_hook
.no_match_ipv6_next_hop_prefix_list
= func
;
303 void route_map_match_metric_hook(int (*func
)(
304 struct route_map_index
*index
, const char *command
,
305 const char *arg
, route_map_event_t type
,
306 char *errmsg
, size_t errmsg_len
))
308 rmap_match_set_hook
.match_metric
= func
;
311 /* no match metric */
312 void route_map_no_match_metric_hook(int (*func
)(
313 struct route_map_index
*index
, const char *command
,
314 const char *arg
, route_map_event_t type
,
315 char *errmsg
, size_t errmsg_len
))
317 rmap_match_set_hook
.no_match_metric
= func
;
321 void route_map_match_tag_hook(int (*func
)(struct route_map_index
*index
,
322 const char *command
, const char *arg
,
323 route_map_event_t type
,
324 char *errmsg
, size_t errmsg_len
))
326 rmap_match_set_hook
.match_tag
= func
;
330 void route_map_no_match_tag_hook(int (*func
)(
331 struct route_map_index
*index
, const char *command
,
332 const char *arg
, route_map_event_t type
,
333 char *errmsg
, size_t errmsg_len
))
335 rmap_match_set_hook
.no_match_tag
= func
;
338 /* set sr-te color */
339 void route_map_set_srte_color_hook(int (*func
)(struct route_map_index
*index
,
342 char *errmsg
, size_t errmsg_len
))
344 rmap_match_set_hook
.set_srte_color
= func
;
347 /* no set sr-te color */
348 void route_map_no_set_srte_color_hook(int (*func
)(struct route_map_index
*index
,
351 char *errmsg
, size_t errmsg_len
))
353 rmap_match_set_hook
.no_set_srte_color
= func
;
357 void route_map_set_ip_nexthop_hook(int (*func
)(struct route_map_index
*index
,
360 char *errmsg
, size_t errmsg_len
))
362 rmap_match_set_hook
.set_ip_nexthop
= func
;
365 /* no set ip nexthop */
366 void route_map_no_set_ip_nexthop_hook(int (*func
)(struct route_map_index
*index
,
372 rmap_match_set_hook
.no_set_ip_nexthop
= func
;
375 /* set ipv6 nexthop local */
376 void route_map_set_ipv6_nexthop_local_hook(
377 int (*func
)(struct route_map_index
*index
,
378 const char *command
, const char *arg
,
379 char *errmsg
, size_t errmsg_len
))
381 rmap_match_set_hook
.set_ipv6_nexthop_local
= func
;
384 /* no set ipv6 nexthop local */
385 void route_map_no_set_ipv6_nexthop_local_hook(
386 int (*func
)(struct route_map_index
*index
,
387 const char *command
, const char *arg
,
388 char *errmsg
, size_t errmsg_len
))
390 rmap_match_set_hook
.no_set_ipv6_nexthop_local
= func
;
394 void route_map_set_metric_hook(int (*func
)(struct route_map_index
*index
,
397 char *errmsg
, size_t errmsg_len
))
399 rmap_match_set_hook
.set_metric
= func
;
403 void route_map_no_set_metric_hook(int (*func
)(struct route_map_index
*index
,
406 char *errmsg
, size_t errmsg_len
))
408 rmap_match_set_hook
.no_set_metric
= func
;
412 void route_map_set_tag_hook(int (*func
)(struct route_map_index
*index
,
413 const char *command
, const char *arg
,
414 char *errmsg
, size_t errmsg_len
))
416 rmap_match_set_hook
.set_tag
= func
;
420 void route_map_no_set_tag_hook(int (*func
)(struct route_map_index
*index
,
423 char *errmsg
, size_t errmsg_len
))
425 rmap_match_set_hook
.no_set_tag
= func
;
428 int generic_match_add(struct route_map_index
*index
,
429 const char *command
, const char *arg
,
430 route_map_event_t type
,
431 char *errmsg
, size_t errmsg_len
)
433 enum rmap_compile_rets ret
;
435 ret
= route_map_add_match(index
, command
, arg
, type
);
437 case RMAP_RULE_MISSING
:
438 snprintf(errmsg
, errmsg_len
, "%% [%s] Can't find rule.",
440 return CMD_WARNING_CONFIG_FAILED
;
441 case RMAP_COMPILE_ERROR
:
442 snprintf(errmsg
, errmsg_len
,
443 "%% [%s] Argument form is unsupported or malformed.",
445 return CMD_WARNING_CONFIG_FAILED
;
446 case RMAP_COMPILE_SUCCESS
:
448 * Nothing to do here move along
456 int generic_match_delete(struct route_map_index
*index
,
457 const char *command
, const char *arg
,
458 route_map_event_t type
,
459 char *errmsg
, size_t errmsg_len
)
461 enum rmap_compile_rets ret
;
462 int retval
= CMD_SUCCESS
;
463 char *dep_name
= NULL
;
465 char *rmap_name
= NULL
;
467 if (type
!= RMAP_EVENT_MATCH_DELETED
) {
468 /* ignore the mundane, the types without any dependency */
470 if ((tmpstr
= route_map_get_match_arg(index
, command
))
473 XSTRDUP(MTYPE_ROUTE_MAP_RULE
, tmpstr
);
475 dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_RULE
, arg
);
477 rmap_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, index
->map
->name
);
480 ret
= route_map_delete_match(index
, command
, dep_name
, type
);
482 case RMAP_RULE_MISSING
:
483 snprintf(errmsg
, errmsg_len
, "%% [%s] Can't find rule.",
485 retval
= CMD_WARNING_CONFIG_FAILED
;
487 case RMAP_COMPILE_ERROR
:
488 snprintf(errmsg
, errmsg_len
,
489 "%% [%s] Argument form is unsupported or malformed.",
491 retval
= CMD_WARNING_CONFIG_FAILED
;
493 case RMAP_COMPILE_SUCCESS
:
500 XFREE(MTYPE_ROUTE_MAP_RULE
, dep_name
);
501 XFREE(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
506 int generic_set_add(struct route_map_index
*index
,
507 const char *command
, const char *arg
,
508 char *errmsg
, size_t errmsg_len
)
510 enum rmap_compile_rets ret
;
512 ret
= route_map_add_set(index
, command
, arg
);
514 case RMAP_RULE_MISSING
:
515 snprintf(errmsg
, errmsg_len
,
516 "%% [%s] Can't find rule.", frr_protonameinst
);
517 return CMD_WARNING_CONFIG_FAILED
;
518 case RMAP_COMPILE_ERROR
:
519 snprintf(errmsg
, errmsg_len
,
520 "%% [%s] Argument form is unsupported or malformed.",
522 return CMD_WARNING_CONFIG_FAILED
;
523 case RMAP_COMPILE_SUCCESS
:
530 int generic_set_delete(struct route_map_index
*index
,
531 const char *command
, const char *arg
,
532 char *errmsg
, size_t errmsg_len
)
534 enum rmap_compile_rets ret
;
536 ret
= route_map_delete_set(index
, command
, arg
);
538 case RMAP_RULE_MISSING
:
539 snprintf(errmsg
, errmsg_len
, "%% [%s] Can't find rule.",
541 return CMD_WARNING_CONFIG_FAILED
;
542 case RMAP_COMPILE_ERROR
:
543 snprintf(errmsg
, errmsg_len
,
544 "%% [%s] Argument form is unsupported or malformed.",
546 return CMD_WARNING_CONFIG_FAILED
;
547 case RMAP_COMPILE_SUCCESS
:
555 /* Master list of route map. */
556 struct route_map_list route_map_master
= {NULL
, NULL
, NULL
, NULL
, NULL
};
557 struct hash
*route_map_master_hash
= NULL
;
559 static unsigned int route_map_hash_key_make(const void *p
)
561 const struct route_map
*map
= p
;
562 return string_hash_make(map
->name
);
565 static bool route_map_hash_cmp(const void *p1
, const void *p2
)
567 const struct route_map
*map1
= p1
;
568 const struct route_map
*map2
= p2
;
570 if (!strcmp(map1
->name
, map2
->name
))
576 enum route_map_upd8_type
{
581 /* all possible route-map dependency types */
582 enum route_map_dep_type
{
583 ROUTE_MAP_DEP_RMAP
= 1,
585 ROUTE_MAP_DEP_ECLIST
,
586 ROUTE_MAP_DEP_LCLIST
,
588 ROUTE_MAP_DEP_ASPATH
,
589 ROUTE_MAP_DEP_FILTER
,
593 struct route_map_dep
{
595 struct hash
*dep_rmap_hash
;
596 struct hash
*this_hash
; /* ptr to the hash structure this is part of */
599 struct route_map_dep_data
{
603 /* Count of number of sequences of this
604 * route-map that depend on the same entity.
609 /* Hashes maintaining dependency between various sublists used by route maps */
610 static struct hash
*route_map_dep_hash
[ROUTE_MAP_DEP_MAX
];
612 static unsigned int route_map_dep_hash_make_key(const void *p
);
613 static void route_map_clear_all_references(char *rmap_name
);
614 static void route_map_rule_delete(struct route_map_rule_list
*,
615 struct route_map_rule
*);
616 static bool rmap_debug
;
618 /* New route map allocation. Please note route map's name must be
620 static struct route_map
*route_map_new(const char *name
)
622 struct route_map
*new;
624 new = XCALLOC(MTYPE_ROUTE_MAP
, sizeof(struct route_map
));
625 new->name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
626 QOBJ_REG(new, route_map
);
630 /* Add new name to route_map. */
631 static struct route_map
*route_map_add(const char *name
)
633 struct route_map
*map
, *exist
;
634 struct route_map_list
*list
;
636 map
= route_map_new(name
);
637 list
= &route_map_master
;
640 * Add map to the hash
642 * If the map already exists in the hash, then we know that
643 * FRR is now in a sequence of delete/create.
644 * All FRR needs to do here is set the to_be_processed
645 * bit (to inherit from the old one
647 exist
= hash_release(route_map_master_hash
, map
);
649 map
->to_be_processed
= exist
->to_be_processed
;
650 route_map_free_map(exist
);
652 hash_get(route_map_master_hash
, map
, hash_alloc_intern
);
654 /* Add new entry to the head of the list to match how it is added in the
655 * hash table. This is to ensure that if the same route-map has been
656 * created more than once and then marked for deletion (which can happen
657 * if prior deletions haven't completed as BGP hasn't yet done the
658 * route-map processing), the order of the entities is the same in both
659 * the list and the hash table. Otherwise, since there is nothing to
660 * distinguish between the two entries, the wrong entry could get freed.
661 * TODO: This needs to be re-examined to handle it better - e.g., revive
662 * a deleted entry if the route-map is created again.
665 map
->next
= list
->head
;
667 list
->head
->prev
= map
;
673 if (route_map_master
.add_hook
) {
674 (*route_map_master
.add_hook
)(name
);
675 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_ADDED
);
678 if (!map
->ipv4_prefix_table
)
679 map
->ipv4_prefix_table
= route_table_init();
681 if (!map
->ipv6_prefix_table
)
682 map
->ipv6_prefix_table
= route_table_init();
685 zlog_debug("Add route-map %s", name
);
689 /* this is supposed to be called post processing by
690 * the delete hook function. Don't invoke delete_hook
691 * again in this routine.
693 static void route_map_free_map(struct route_map
*map
)
695 struct route_map_list
*list
;
696 struct route_map_index
*index
;
701 while ((index
= map
->head
) != NULL
)
702 route_map_index_delete(index
, 0);
705 zlog_debug("Deleting route-map %s", map
->name
);
707 list
= &route_map_master
;
712 map
->next
->prev
= map
->prev
;
714 list
->tail
= map
->prev
;
717 map
->prev
->next
= map
->next
;
719 list
->head
= map
->next
;
721 hash_release(route_map_master_hash
, map
);
722 XFREE(MTYPE_ROUTE_MAP_NAME
, map
->name
);
723 XFREE(MTYPE_ROUTE_MAP
, map
);
726 /* Route map delete from list. */
727 void route_map_delete(struct route_map
*map
)
729 struct route_map_index
*index
;
732 while ((index
= map
->head
) != NULL
)
733 route_map_index_delete(index
, 0);
738 /* Clear all dependencies */
739 route_map_clear_all_references(name
);
741 /* Execute deletion hook. */
742 if (route_map_master
.delete_hook
) {
743 (*route_map_master
.delete_hook
)(name
);
744 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_DELETED
);
747 if (!map
->to_be_processed
) {
748 route_map_free_map(map
);
752 /* Lookup route map by route map name string. */
753 struct route_map
*route_map_lookup_by_name(const char *name
)
755 struct route_map
*map
;
756 struct route_map tmp_map
;
761 // map.deleted is false via memset
762 memset(&tmp_map
, 0, sizeof(tmp_map
));
763 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
764 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
765 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
767 if (map
&& map
->deleted
)
773 /* Simple helper to warn if route-map does not exist. */
774 struct route_map
*route_map_lookup_warn_noexist(struct vty
*vty
, const char *name
)
776 struct route_map
*route_map
= route_map_lookup_by_name(name
);
779 if (vty_shell_serv(vty
))
780 vty_out(vty
, "The route-map '%s' does not exist.\n", name
);
785 int route_map_mark_updated(const char *name
)
787 struct route_map
*map
;
789 struct route_map tmp_map
;
794 map
= route_map_lookup_by_name(name
);
796 /* If we did not find the routemap with deleted=false try again
800 memset(&tmp_map
, 0, sizeof(tmp_map
));
801 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
802 tmp_map
.deleted
= true;
803 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
804 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
808 map
->to_be_processed
= true;
815 static void route_map_clear_updated(struct route_map
*map
)
818 map
->to_be_processed
= false;
820 route_map_free_map(map
);
824 /* Lookup route map. If there isn't route map create one and return
826 struct route_map
*route_map_get(const char *name
)
828 struct route_map
*map
;
830 map
= route_map_lookup_by_name(name
);
832 map
= route_map_add(name
);
837 void route_map_walk_update_list(void (*route_map_update_fn
)(char *name
))
839 struct route_map
*node
;
840 struct route_map
*nnode
= NULL
;
842 for (node
= route_map_master
.head
; node
; node
= nnode
) {
843 if (node
->to_be_processed
) {
844 /* DD: Should we add any thread yield code here */
845 route_map_update_fn(node
->name
);
847 route_map_clear_updated(node
);
853 /* Return route map's type string. */
854 static const char *route_map_type_str(enum route_map_type type
)
868 static const char *route_map_cmd_result_str(enum route_map_cmd_result_t res
)
886 static const char *route_map_result_str(route_map_result_t res
)
891 case RMAP_PERMITMATCH
:
899 static void vty_show_route_map_entry(struct vty
*vty
, struct route_map
*map
,
902 struct route_map_index
*index
;
903 struct route_map_rule
*rule
;
904 json_object
*json_rmap
= NULL
;
905 json_object
*json_rules
= NULL
;
908 json_rmap
= json_object_new_object();
909 json_object_object_add(json
, map
->name
, json_rmap
);
911 json_rules
= json_object_new_array();
912 json_object_int_add(json_rmap
, "invoked",
913 map
->applied
- map
->applied_clear
);
914 json_object_boolean_add(json_rmap
, "disabledOptimization",
915 map
->optimization_disabled
);
916 json_object_boolean_add(json_rmap
, "processedChange",
917 map
->to_be_processed
);
918 json_object_object_add(json_rmap
, "rules", json_rules
);
921 "route-map: %s Invoked: %" PRIu64
922 " Optimization: %s Processed Change: %s\n",
923 map
->name
, map
->applied
- map
->applied_clear
,
924 map
->optimization_disabled
? "disabled" : "enabled",
925 map
->to_be_processed
? "true" : "false");
928 for (index
= map
->head
; index
; index
= index
->next
) {
930 json_object
*json_rule
;
931 json_object
*json_matches
;
932 json_object
*json_sets
;
933 char action
[BUFSIZ
] = {};
935 json_rule
= json_object_new_object();
936 json_object_array_add(json_rules
, json_rule
);
938 json_object_int_add(json_rule
, "sequenceNumber",
940 json_object_string_add(json_rule
, "type",
941 route_map_type_str(index
->type
));
942 json_object_int_add(json_rule
, "invoked",
944 - index
->applied_clear
);
947 if (index
->description
)
948 json_object_string_add(json_rule
, "description",
952 json_matches
= json_object_new_array();
953 json_object_object_add(json_rule
, "matchClauses",
955 for (rule
= index
->match_list
.head
; rule
;
959 snprintf(buf
, sizeof(buf
), "%s %s",
960 rule
->cmd
->str
, rule
->rule_str
);
961 json_array_string_add(json_matches
, buf
);
965 json_sets
= json_object_new_array();
966 json_object_object_add(json_rule
, "setClauses",
968 for (rule
= index
->set_list
.head
; rule
;
972 snprintf(buf
, sizeof(buf
), "%s %s",
973 rule
->cmd
->str
, rule
->rule_str
);
974 json_array_string_add(json_sets
, buf
);
979 json_object_string_add(json_rule
, "callClause",
983 if (index
->exitpolicy
== RMAP_GOTO
)
984 snprintf(action
, sizeof(action
), "Goto %d",
986 else if (index
->exitpolicy
== RMAP_NEXT
)
987 snprintf(action
, sizeof(action
),
988 "Continue to next entry");
989 else if (index
->exitpolicy
== RMAP_EXIT
)
990 snprintf(action
, sizeof(action
),
992 if (action
[0] != '\0')
993 json_object_string_add(json_rule
, "action",
996 vty_out(vty
, " %s, sequence %d Invoked %" PRIu64
"\n",
997 route_map_type_str(index
->type
), index
->pref
,
998 index
->applied
- index
->applied_clear
);
1001 if (index
->description
)
1002 vty_out(vty
, " Description:\n %s\n",
1003 index
->description
);
1006 vty_out(vty
, " Match clauses:\n");
1007 for (rule
= index
->match_list
.head
; rule
;
1009 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
1013 vty_out(vty
, " Set clauses:\n");
1014 for (rule
= index
->set_list
.head
; rule
;
1016 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
1020 vty_out(vty
, " Call clause:\n");
1022 vty_out(vty
, " Call %s\n", index
->nextrm
);
1025 vty_out(vty
, " Action:\n");
1026 if (index
->exitpolicy
== RMAP_GOTO
)
1027 vty_out(vty
, " Goto %d\n", index
->nextpref
);
1028 else if (index
->exitpolicy
== RMAP_NEXT
)
1029 vty_out(vty
, " Continue to next entry\n");
1030 else if (index
->exitpolicy
== RMAP_EXIT
)
1031 vty_out(vty
, " Exit routemap\n");
1036 static int sort_route_map(const void **map1
, const void **map2
)
1038 const struct route_map
*m1
= *map1
;
1039 const struct route_map
*m2
= *map2
;
1041 return strcmp(m1
->name
, m2
->name
);
1044 static int vty_show_route_map(struct vty
*vty
, const char *name
, bool use_json
)
1046 struct route_map
*map
;
1047 json_object
*json
= NULL
;
1048 json_object
*json_proto
= NULL
;
1051 json
= json_object_new_object();
1052 json_proto
= json_object_new_object();
1053 json_object_object_add(json
, frr_protonameinst
, json_proto
);
1055 vty_out(vty
, "%s:\n", frr_protonameinst
);
1058 map
= route_map_lookup_by_name(name
);
1061 vty_show_route_map_entry(vty
, map
, json_proto
);
1062 } else if (!use_json
) {
1063 vty_out(vty
, "%s: 'route-map %s' not found\n",
1064 frr_protonameinst
, name
);
1068 struct list
*maplist
= list_new();
1069 struct listnode
*ln
;
1071 for (map
= route_map_master
.head
; map
; map
= map
->next
)
1072 listnode_add(maplist
, map
);
1074 list_sort(maplist
, sort_route_map
);
1076 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
1077 vty_show_route_map_entry(vty
, map
, json_proto
);
1079 list_delete(&maplist
);
1082 return vty_json(vty
, json
);
1085 /* Unused route map details */
1086 static int vty_show_unused_route_map(struct vty
*vty
)
1088 struct list
*maplist
= list_new();
1089 struct listnode
*ln
;
1090 struct route_map
*map
;
1092 for (map
= route_map_master
.head
; map
; map
= map
->next
) {
1093 /* If use_count is zero, No protocol is using this routemap.
1094 * so adding to the list.
1096 if (!map
->use_count
)
1097 listnode_add(maplist
, map
);
1100 if (maplist
->count
> 0) {
1101 vty_out(vty
, "\n%s:\n", frr_protonameinst
);
1102 list_sort(maplist
, sort_route_map
);
1104 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
1105 vty_show_route_map_entry(vty
, map
, NULL
);
1107 vty_out(vty
, "\n%s: None\n", frr_protonameinst
);
1110 list_delete(&maplist
);
1114 /* New route map allocation. Please note route map's name must be
1116 static struct route_map_index
*route_map_index_new(void)
1118 struct route_map_index
*new;
1120 new = XCALLOC(MTYPE_ROUTE_MAP_INDEX
, sizeof(struct route_map_index
));
1121 new->exitpolicy
= RMAP_EXIT
; /* Default to Cisco-style */
1122 TAILQ_INIT(&new->rhclist
);
1123 QOBJ_REG(new, route_map_index
);
1127 /* Free route map index. */
1128 void route_map_index_delete(struct route_map_index
*index
, int notify
)
1130 struct routemap_hook_context
*rhc
;
1131 struct route_map_rule
*rule
;
1136 zlog_debug("Deleting route-map %s sequence %d",
1137 index
->map
->name
, index
->pref
);
1139 /* Free route map entry description. */
1140 XFREE(MTYPE_TMP
, index
->description
);
1142 /* Free route map northbound hook contexts. */
1143 while ((rhc
= TAILQ_FIRST(&index
->rhclist
)) != NULL
)
1144 routemap_hook_context_free(rhc
);
1146 /* Free route match. */
1147 while ((rule
= index
->match_list
.head
) != NULL
) {
1148 if (IS_RULE_IPv4_PREFIX_LIST(rule
->cmd
->str
))
1149 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_DELETED
,
1150 index
, AFI_IP
, rule
->rule_str
);
1151 else if (IS_RULE_IPv6_PREFIX_LIST(rule
->cmd
->str
))
1152 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_DELETED
,
1156 route_map_rule_delete(&index
->match_list
, rule
);
1159 /* Free route set. */
1160 while ((rule
= index
->set_list
.head
) != NULL
)
1161 route_map_rule_delete(&index
->set_list
, rule
);
1163 /* Remove index from route map list. */
1165 index
->next
->prev
= index
->prev
;
1167 index
->map
->tail
= index
->prev
;
1170 index
->prev
->next
= index
->next
;
1172 index
->map
->head
= index
->next
;
1174 /* Free 'char *nextrm' if not NULL */
1175 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
1177 route_map_pfx_tbl_update(RMAP_EVENT_INDEX_DELETED
, index
, 0, NULL
);
1179 /* Execute event hook. */
1180 if (route_map_master
.event_hook
&& notify
) {
1181 (*route_map_master
.event_hook
)(index
->map
->name
);
1182 route_map_notify_dependencies(index
->map
->name
,
1183 RMAP_EVENT_CALL_ADDED
);
1185 XFREE(MTYPE_ROUTE_MAP_INDEX
, index
);
1188 /* Lookup index from route map. */
1189 static struct route_map_index
*route_map_index_lookup(struct route_map
*map
,
1190 enum route_map_type type
,
1193 struct route_map_index
*index
;
1195 for (index
= map
->head
; index
; index
= index
->next
)
1196 if ((index
->type
== type
|| type
== RMAP_ANY
)
1197 && index
->pref
== pref
)
1202 /* Add new index to route map. */
1203 static struct route_map_index
*
1204 route_map_index_add(struct route_map
*map
, enum route_map_type type
, int pref
)
1206 struct route_map_index
*index
;
1207 struct route_map_index
*point
;
1209 /* Allocate new route map inex. */
1210 index
= route_map_index_new();
1215 /* Compare preference. */
1216 for (point
= map
->head
; point
; point
= point
->next
)
1217 if (point
->pref
>= pref
)
1220 if (map
->head
== NULL
) {
1221 map
->head
= map
->tail
= index
;
1222 } else if (point
== NULL
) {
1223 index
->prev
= map
->tail
;
1224 map
->tail
->next
= index
;
1226 } else if (point
== map
->head
) {
1227 index
->next
= map
->head
;
1228 map
->head
->prev
= index
;
1231 index
->next
= point
;
1232 index
->prev
= point
->prev
;
1234 point
->prev
->next
= index
;
1235 point
->prev
= index
;
1238 route_map_pfx_tbl_update(RMAP_EVENT_INDEX_ADDED
, index
, 0, NULL
);
1240 /* Execute event hook. */
1241 if (route_map_master
.event_hook
) {
1242 (*route_map_master
.event_hook
)(map
->name
);
1243 route_map_notify_dependencies(map
->name
, RMAP_EVENT_CALL_ADDED
);
1247 zlog_debug("Route-map %s add sequence %d, type: %s",
1248 map
->name
, pref
, route_map_type_str(type
));
1253 /* Get route map index. */
1254 struct route_map_index
*
1255 route_map_index_get(struct route_map
*map
, enum route_map_type type
, int pref
)
1257 struct route_map_index
*index
;
1259 index
= route_map_index_lookup(map
, RMAP_ANY
, pref
);
1260 if (index
&& index
->type
!= type
) {
1261 /* Delete index from route map. */
1262 route_map_index_delete(index
, 1);
1266 index
= route_map_index_add(map
, type
, pref
);
1270 /* New route map rule */
1271 static struct route_map_rule
*route_map_rule_new(void)
1273 struct route_map_rule
*new;
1275 new = XCALLOC(MTYPE_ROUTE_MAP_RULE
, sizeof(struct route_map_rule
));
1279 /* Install rule command to the match list. */
1280 void _route_map_install_match(struct route_map_rule_cmd_proxy
*proxy
)
1282 rmap_cmd_name_add(rmap_match_cmds
, proxy
);
1285 /* Install rule command to the set list. */
1286 void _route_map_install_set(struct route_map_rule_cmd_proxy
*proxy
)
1288 rmap_cmd_name_add(rmap_set_cmds
, proxy
);
1291 /* Lookup rule command from match list. */
1292 static const struct route_map_rule_cmd
*route_map_lookup_match(const char *name
)
1294 struct route_map_rule_cmd refcmd
= {.str
= name
};
1295 struct route_map_rule_cmd_proxy ref
= {.cmd
= &refcmd
};
1296 struct route_map_rule_cmd_proxy
*res
;
1298 res
= rmap_cmd_name_find(rmap_match_cmds
, &ref
);
1304 /* Lookup rule command from set list. */
1305 static const struct route_map_rule_cmd
*route_map_lookup_set(const char *name
)
1307 struct route_map_rule_cmd refcmd
= {.str
= name
};
1308 struct route_map_rule_cmd_proxy ref
= {.cmd
= &refcmd
};
1309 struct route_map_rule_cmd_proxy
*res
;
1311 res
= rmap_cmd_name_find(rmap_set_cmds
, &ref
);
1317 /* Add match and set rule to rule list. */
1318 static void route_map_rule_add(struct route_map_rule_list
*list
,
1319 struct route_map_rule
*rule
)
1322 rule
->prev
= list
->tail
;
1324 list
->tail
->next
= rule
;
1330 /* Delete rule from rule list. */
1331 static void route_map_rule_delete(struct route_map_rule_list
*list
,
1332 struct route_map_rule
*rule
)
1334 if (rule
->cmd
->func_free
)
1335 (*rule
->cmd
->func_free
)(rule
->value
);
1337 XFREE(MTYPE_ROUTE_MAP_RULE_STR
, rule
->rule_str
);
1340 rule
->next
->prev
= rule
->prev
;
1342 list
->tail
= rule
->prev
;
1344 rule
->prev
->next
= rule
->next
;
1346 list
->head
= rule
->next
;
1348 XFREE(MTYPE_ROUTE_MAP_RULE
, rule
);
1351 /* strcmp wrapper function which don't crush even argument is NULL. */
1352 static int rulecmp(const char *dst
, const char *src
)
1363 return strcmp(dst
, src
);
1368 /* Use this to return the already specified argument for this match. This is
1369 * useful to get the specified argument with a route map match rule when the
1370 * rule is being deleted and the argument is not provided.
1372 const char *route_map_get_match_arg(struct route_map_index
*index
,
1373 const char *match_name
)
1375 struct route_map_rule
*rule
;
1376 const struct route_map_rule_cmd
*cmd
;
1378 /* First lookup rule for add match statement. */
1379 cmd
= route_map_lookup_match(match_name
);
1383 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1384 if (rule
->cmd
== cmd
&& rule
->rule_str
!= NULL
)
1385 return (rule
->rule_str
);
1390 static route_map_event_t
get_route_map_delete_event(route_map_event_t type
)
1393 case RMAP_EVENT_CALL_ADDED
:
1394 return RMAP_EVENT_CALL_DELETED
;
1395 case RMAP_EVENT_PLIST_ADDED
:
1396 return RMAP_EVENT_PLIST_DELETED
;
1397 case RMAP_EVENT_CLIST_ADDED
:
1398 return RMAP_EVENT_CLIST_DELETED
;
1399 case RMAP_EVENT_ECLIST_ADDED
:
1400 return RMAP_EVENT_ECLIST_DELETED
;
1401 case RMAP_EVENT_LLIST_ADDED
:
1402 return RMAP_EVENT_LLIST_DELETED
;
1403 case RMAP_EVENT_ASLIST_ADDED
:
1404 return RMAP_EVENT_ASLIST_DELETED
;
1405 case RMAP_EVENT_FILTER_ADDED
:
1406 return RMAP_EVENT_FILTER_DELETED
;
1407 case RMAP_EVENT_SET_ADDED
:
1408 case RMAP_EVENT_SET_DELETED
:
1409 case RMAP_EVENT_SET_REPLACED
:
1410 case RMAP_EVENT_MATCH_ADDED
:
1411 case RMAP_EVENT_MATCH_DELETED
:
1412 case RMAP_EVENT_MATCH_REPLACED
:
1413 case RMAP_EVENT_INDEX_ADDED
:
1414 case RMAP_EVENT_INDEX_DELETED
:
1415 case RMAP_EVENT_CALL_DELETED
:
1416 case RMAP_EVENT_PLIST_DELETED
:
1417 case RMAP_EVENT_CLIST_DELETED
:
1418 case RMAP_EVENT_ECLIST_DELETED
:
1419 case RMAP_EVENT_LLIST_DELETED
:
1420 case RMAP_EVENT_ASLIST_DELETED
:
1421 case RMAP_EVENT_FILTER_DELETED
:
1422 /* This function returns the appropriate 'deleted' event type
1423 * for every 'added' event type passed to this function.
1424 * This is done only for named entities used in the
1425 * route-map match commands.
1426 * This function is not to be invoked for any of the other event
1434 * Return to make c happy but if we get here something has gone
1435 * terribly terribly wrong, so yes this return makes no sense.
1437 return RMAP_EVENT_CALL_ADDED
;
1440 /* Add match statement to route map. */
1441 enum rmap_compile_rets
route_map_add_match(struct route_map_index
*index
,
1442 const char *match_name
,
1443 const char *match_arg
,
1444 route_map_event_t type
)
1446 struct route_map_rule
*rule
;
1447 struct route_map_rule
*next
;
1448 const struct route_map_rule_cmd
*cmd
;
1450 int8_t delete_rmap_event_type
= 0;
1451 const char *rule_key
;
1453 /* First lookup rule for add match statement. */
1454 cmd
= route_map_lookup_match(match_name
);
1456 return RMAP_RULE_MISSING
;
1458 /* Next call compile function for this match statement. */
1459 if (cmd
->func_compile
) {
1460 compile
= (*cmd
->func_compile
)(match_arg
);
1461 if (compile
== NULL
)
1462 return RMAP_COMPILE_ERROR
;
1465 /* use the compiled results if applicable */
1466 if (compile
&& cmd
->func_get_rmap_rule_key
)
1467 rule_key
= (*cmd
->func_get_rmap_rule_key
)
1470 rule_key
= match_arg
;
1472 /* If argument is completely same ignore it. */
1473 for (rule
= index
->match_list
.head
; rule
; rule
= next
) {
1475 if (rule
->cmd
== cmd
) {
1476 /* If the configured route-map match rule is exactly
1477 * the same as the existing configuration then,
1478 * ignore the duplicate configuration.
1480 if (rulecmp(match_arg
, rule
->rule_str
) == 0) {
1482 (*cmd
->func_free
)(compile
);
1484 return RMAP_COMPILE_SUCCESS
;
1487 /* If IPv4 or IPv6 prefix-list match criteria
1488 * has been delete to the route-map index, update
1489 * the route-map's prefix table.
1491 if (IS_RULE_IPv4_PREFIX_LIST(match_name
))
1492 route_map_pfx_tbl_update(
1493 RMAP_EVENT_PLIST_DELETED
, index
, AFI_IP
,
1495 else if (IS_RULE_IPv6_PREFIX_LIST(match_name
))
1496 route_map_pfx_tbl_update(
1497 RMAP_EVENT_PLIST_DELETED
, index
,
1498 AFI_IP6
, rule
->rule_str
);
1500 /* Remove the dependency of the route-map on the rule
1501 * that is being replaced.
1503 if (type
>= RMAP_EVENT_CALL_ADDED
) {
1504 delete_rmap_event_type
=
1505 get_route_map_delete_event(type
);
1506 route_map_upd8_dependency(
1507 delete_rmap_event_type
,
1512 route_map_rule_delete(&index
->match_list
, rule
);
1516 /* Add new route map match rule. */
1517 rule
= route_map_rule_new();
1519 rule
->value
= compile
;
1521 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, match_arg
);
1523 rule
->rule_str
= NULL
;
1525 /* Add new route match rule to linked list. */
1526 route_map_rule_add(&index
->match_list
, rule
);
1528 /* If IPv4 or IPv6 prefix-list match criteria
1529 * has been added to the route-map index, update
1530 * the route-map's prefix table.
1532 if (IS_RULE_IPv4_PREFIX_LIST(match_name
)) {
1533 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_ADDED
, index
, AFI_IP
,
1535 } else if (IS_RULE_IPv6_PREFIX_LIST(match_name
)) {
1536 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_ADDED
, index
, AFI_IP6
,
1540 /* Execute event hook. */
1541 if (route_map_master
.event_hook
) {
1542 (*route_map_master
.event_hook
)(index
->map
->name
);
1543 route_map_notify_dependencies(index
->map
->name
,
1544 RMAP_EVENT_CALL_ADDED
);
1546 if (type
!= RMAP_EVENT_MATCH_ADDED
)
1547 route_map_upd8_dependency(type
, rule_key
, index
->map
->name
);
1549 return RMAP_COMPILE_SUCCESS
;
1552 /* Delete specified route match rule. */
1553 enum rmap_compile_rets
route_map_delete_match(struct route_map_index
*index
,
1554 const char *match_name
,
1555 const char *match_arg
,
1556 route_map_event_t type
)
1558 struct route_map_rule
*rule
;
1559 const struct route_map_rule_cmd
*cmd
;
1560 const char *rule_key
;
1562 cmd
= route_map_lookup_match(match_name
);
1564 return RMAP_RULE_MISSING
;
1566 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1567 if (rule
->cmd
== cmd
&& (rulecmp(rule
->rule_str
, match_arg
) == 0
1568 || match_arg
== NULL
)) {
1569 /* Execute event hook. */
1570 if (route_map_master
.event_hook
) {
1571 (*route_map_master
.event_hook
)(index
->map
->name
);
1572 route_map_notify_dependencies(
1574 RMAP_EVENT_CALL_ADDED
);
1576 if (cmd
->func_get_rmap_rule_key
)
1577 rule_key
= (*cmd
->func_get_rmap_rule_key
)
1580 rule_key
= match_arg
;
1582 if (type
!= RMAP_EVENT_MATCH_DELETED
&& rule_key
)
1583 route_map_upd8_dependency(type
, rule_key
,
1586 route_map_rule_delete(&index
->match_list
, rule
);
1588 /* If IPv4 or IPv6 prefix-list match criteria
1589 * has been delete from the route-map index, update
1590 * the route-map's prefix table.
1592 if (IS_RULE_IPv4_PREFIX_LIST(match_name
)) {
1593 route_map_pfx_tbl_update(
1594 RMAP_EVENT_PLIST_DELETED
, index
, AFI_IP
,
1596 } else if (IS_RULE_IPv6_PREFIX_LIST(match_name
)) {
1597 route_map_pfx_tbl_update(
1598 RMAP_EVENT_PLIST_DELETED
, index
,
1599 AFI_IP6
, match_arg
);
1602 return RMAP_COMPILE_SUCCESS
;
1604 /* Can't find matched rule. */
1605 return RMAP_RULE_MISSING
;
1608 /* Add route-map set statement to the route map. */
1609 enum rmap_compile_rets
route_map_add_set(struct route_map_index
*index
,
1610 const char *set_name
,
1611 const char *set_arg
)
1613 struct route_map_rule
*rule
;
1614 struct route_map_rule
*next
;
1615 const struct route_map_rule_cmd
*cmd
;
1618 cmd
= route_map_lookup_set(set_name
);
1620 return RMAP_RULE_MISSING
;
1622 /* Next call compile function for this match statement. */
1623 if (cmd
->func_compile
) {
1624 compile
= (*cmd
->func_compile
)(set_arg
);
1625 if (compile
== NULL
)
1626 return RMAP_COMPILE_ERROR
;
1630 /* Add by WJL. if old set command of same kind exist, delete it first
1631 to ensure only one set command of same kind exist under a
1633 for (rule
= index
->set_list
.head
; rule
; rule
= next
) {
1635 if (rule
->cmd
== cmd
)
1636 route_map_rule_delete(&index
->set_list
, rule
);
1639 /* Add new route map match rule. */
1640 rule
= route_map_rule_new();
1642 rule
->value
= compile
;
1644 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, set_arg
);
1646 rule
->rule_str
= NULL
;
1648 /* Add new route match rule to linked list. */
1649 route_map_rule_add(&index
->set_list
, rule
);
1651 /* Execute event hook. */
1652 if (route_map_master
.event_hook
) {
1653 (*route_map_master
.event_hook
)(index
->map
->name
);
1654 route_map_notify_dependencies(index
->map
->name
,
1655 RMAP_EVENT_CALL_ADDED
);
1657 return RMAP_COMPILE_SUCCESS
;
1660 /* Delete route map set rule. */
1661 enum rmap_compile_rets
route_map_delete_set(struct route_map_index
*index
,
1662 const char *set_name
,
1663 const char *set_arg
)
1665 struct route_map_rule
*rule
;
1666 const struct route_map_rule_cmd
*cmd
;
1668 cmd
= route_map_lookup_set(set_name
);
1670 return RMAP_RULE_MISSING
;
1672 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
1673 if ((rule
->cmd
== cmd
) && (rulecmp(rule
->rule_str
, set_arg
) == 0
1674 || set_arg
== NULL
)) {
1675 route_map_rule_delete(&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(
1681 RMAP_EVENT_CALL_ADDED
);
1683 return RMAP_COMPILE_SUCCESS
;
1685 /* Can't find matched rule. */
1686 return RMAP_RULE_MISSING
;
1689 static enum route_map_cmd_result_t
1690 route_map_apply_match(struct route_map_rule_list
*match_list
,
1691 const struct prefix
*prefix
, void *object
)
1693 enum route_map_cmd_result_t ret
= RMAP_NOMATCH
;
1694 struct route_map_rule
*match
;
1695 bool is_matched
= false;
1698 /* Check all match rule and if there is no match rule, go to the
1700 if (!match_list
->head
)
1703 for (match
= match_list
->head
; match
; match
= match
->next
) {
1705 * Try each match statement. If any match does not
1706 * return RMAP_MATCH or RMAP_NOOP, return.
1707 * Otherwise continue on to next match statement.
1708 * All match statements must MATCH for
1709 * end-result to be a match.
1710 * (Exception:If match stmts result in a mix of
1711 * MATCH/NOOP, then also end-result is a match)
1712 * If all result in NOOP, end-result is NOOP.
1714 ret
= (*match
->cmd
->func_apply
)(match
->value
, prefix
,
1718 * If the consolidated result of func_apply is:
1719 * -----------------------------------------------
1720 * | MATCH | NOMATCH | NOOP | Final Result |
1721 * ------------------------------------------------
1722 * | yes | yes | yes | NOMATCH |
1723 * | no | no | yes | NOOP |
1724 * | yes | no | yes | MATCH |
1725 * | no | yes | yes | NOMATCH |
1726 * |-----------------------------------------------
1728 * Traditionally, all rules within route-map
1729 * should match for it to MATCH.
1730 * If there are noops within the route-map rules,
1731 * it follows the above matrix.
1733 * Eg: route-map rm1 permit 10
1738 * route-map rm1 permit 20
1766 static struct list
*route_map_get_index_list(struct route_node
**rn
,
1767 const struct prefix
*prefix
,
1768 struct route_table
*table
)
1770 struct route_node
*tmp_rn
= NULL
;
1773 *rn
= route_node_match(table
, prefix
);
1779 return (struct list
*)((*rn
)->info
);
1781 /* If rn->info is NULL, get the parent.
1782 * Store the rn in tmp_rn and unlock it later.
1788 *rn
= (*rn
)->parent
;
1790 route_unlock_node(tmp_rn
);
1796 route_lock_node(*rn
);
1797 return (struct list
*)((*rn
)->info
);
1799 } while (!(*rn
)->info
);
1805 * This function returns the route-map index that best matches the prefix.
1807 static struct route_map_index
*
1808 route_map_get_index(struct route_map
*map
, const struct prefix
*prefix
,
1809 void *object
, enum route_map_cmd_result_t
*match_ret
)
1811 enum route_map_cmd_result_t ret
= RMAP_NOMATCH
;
1812 struct list
*candidate_rmap_list
= NULL
;
1813 struct route_node
*rn
= NULL
;
1814 struct listnode
*ln
= NULL
, *nn
= NULL
;
1815 struct route_map_index
*index
= NULL
, *best_index
= NULL
;
1816 struct route_map_index
*head_index
= NULL
;
1817 struct route_table
*table
= NULL
;
1819 unsigned char family
;
1822 * Handling for matching evpn_routes in the prefix table.
1824 * We convert type2/5 prefix to ipv4/6 prefix to do longest
1825 * prefix matching on.
1827 if (prefix
->family
== AF_EVPN
) {
1828 if (evpn_prefix2prefix(prefix
, &conv
) != 0)
1835 family
= prefix
->family
;
1837 if (family
== AF_INET
)
1838 table
= map
->ipv4_prefix_table
;
1840 table
= map
->ipv6_prefix_table
;
1846 candidate_rmap_list
=
1847 route_map_get_index_list(&rn
, prefix
, table
);
1851 /* If the index at the head of the list is of seq higher
1852 * than that in best_index, ignore the list and get the
1853 * parent node's list.
1855 head_index
= (struct route_map_index
*)(listgetdata(
1856 listhead(candidate_rmap_list
)));
1857 if (best_index
&& head_index
1858 && (best_index
->pref
< head_index
->pref
)) {
1859 route_unlock_node(rn
);
1863 for (ALL_LIST_ELEMENTS(candidate_rmap_list
, ln
, nn
, index
)) {
1864 /* If the index is of seq higher than that in
1865 * best_index, ignore the list and get the parent
1868 if (best_index
&& (best_index
->pref
< index
->pref
))
1871 ret
= route_map_apply_match(&index
->match_list
, prefix
,
1874 if (ret
== RMAP_MATCH
) {
1878 } else if (ret
== RMAP_NOOP
) {
1880 * If match_ret is denymatch, even if we see
1881 * more noops, we retain this return value and
1882 * return this eventually if there are no
1884 * If a best match route-map index already
1885 * exists, do not reset the match_ret.
1887 if (!best_index
&& (*match_ret
!= RMAP_NOMATCH
))
1891 * ret is RMAP_NOMATCH.
1892 * If a best match route-map index already
1893 * exists, do not reset the match_ret.
1900 route_unlock_node(rn
);
1907 static int route_map_candidate_list_cmp(struct route_map_index
*idx1
,
1908 struct route_map_index
*idx2
)
1910 return idx1
->pref
- idx2
->pref
;
1914 * This function adds the route-map index into the default route's
1915 * route-node in the route-map's IPv4/IPv6 prefix-table.
1917 static void route_map_pfx_table_add_default(afi_t afi
,
1918 struct route_map_index
*index
)
1920 struct route_node
*rn
= NULL
;
1921 struct list
*rmap_candidate_list
= NULL
;
1923 bool updated_rn
= false;
1924 struct route_table
*table
= NULL
;
1926 memset(&p
, 0, sizeof(p
));
1927 p
.family
= afi2family(afi
);
1930 if (p
.family
== AF_INET
) {
1931 table
= index
->map
->ipv4_prefix_table
;
1933 index
->map
->ipv4_prefix_table
= route_table_init();
1935 table
= index
->map
->ipv4_prefix_table
;
1937 table
= index
->map
->ipv6_prefix_table
;
1939 index
->map
->ipv6_prefix_table
= route_table_init();
1941 table
= index
->map
->ipv6_prefix_table
;
1944 /* Add default route to table */
1945 rn
= route_node_get(table
, &p
);
1951 rmap_candidate_list
= list_new();
1952 rmap_candidate_list
->cmp
=
1953 (int (*)(void *, void *))route_map_candidate_list_cmp
;
1954 rn
->info
= rmap_candidate_list
;
1956 rmap_candidate_list
= (struct list
*)rn
->info
;
1960 listnode_add_sort_nodup(rmap_candidate_list
, index
);
1962 route_unlock_node(rn
);
1966 * This function removes the route-map index from the default route's
1967 * route-node in the route-map's IPv4/IPv6 prefix-table.
1969 static void route_map_pfx_table_del_default(afi_t afi
,
1970 struct route_map_index
*index
)
1972 struct route_node
*rn
= NULL
;
1973 struct list
*rmap_candidate_list
= NULL
;
1975 struct route_table
*table
= NULL
;
1977 memset(&p
, 0, sizeof(p
));
1978 p
.family
= afi2family(afi
);
1981 if (p
.family
== AF_INET
)
1982 table
= index
->map
->ipv4_prefix_table
;
1984 table
= index
->map
->ipv6_prefix_table
;
1986 /* Remove RMAP index from default route in table */
1987 rn
= route_node_lookup(table
, &p
);
1988 if (!rn
|| !rn
->info
)
1991 rmap_candidate_list
= (struct list
*)rn
->info
;
1993 listnode_delete(rmap_candidate_list
, index
);
1995 if (listcount(rmap_candidate_list
) == 0) {
1996 list_delete(&rmap_candidate_list
);
1998 route_unlock_node(rn
);
2000 route_unlock_node(rn
);
2004 * This function adds the route-map index to the route-node for
2005 * the prefix-entry in the route-map's IPv4/IPv6 prefix-table.
2007 static void route_map_pfx_table_add(struct route_table
*table
,
2008 struct route_map_index
*index
,
2009 struct prefix_list_entry
*pentry
)
2011 struct route_node
*rn
= NULL
;
2012 struct list
*rmap_candidate_list
= NULL
;
2013 bool updated_rn
= false;
2015 rn
= route_node_get(table
, &pentry
->prefix
);
2020 rmap_candidate_list
= list_new();
2021 rmap_candidate_list
->cmp
=
2022 (int (*)(void *, void *))route_map_candidate_list_cmp
;
2023 rn
->info
= rmap_candidate_list
;
2025 rmap_candidate_list
= (struct list
*)rn
->info
;
2029 listnode_add_sort_nodup(rmap_candidate_list
, index
);
2031 route_unlock_node(rn
);
2035 * This function removes the route-map index from the route-node for
2036 * the prefix-entry in the route-map's IPv4/IPv6 prefix-table.
2038 static void route_map_pfx_table_del(struct route_table
*table
,
2039 struct route_map_index
*index
,
2040 struct prefix_list_entry
*pentry
)
2042 struct route_node
*rn
= NULL
;
2043 struct list
*rmap_candidate_list
= NULL
;
2045 rn
= route_node_lookup(table
, &pentry
->prefix
);
2046 if (!rn
|| !rn
->info
)
2049 rmap_candidate_list
= (struct list
*)rn
->info
;
2051 listnode_delete(rmap_candidate_list
, index
);
2053 if (listcount(rmap_candidate_list
) == 0) {
2054 list_delete(&rmap_candidate_list
);
2056 route_unlock_node(rn
);
2058 route_unlock_node(rn
);
2061 /* This function checks for the presence of an IPv4 prefix-list
2062 * match rule in the given route-map index.
2064 static bool route_map_is_ip_pfx_list_rule_present(struct route_map_index
*index
)
2066 struct route_map_rule_list
*match_list
= NULL
;
2067 struct route_map_rule
*rule
= NULL
;
2069 match_list
= &index
->match_list
;
2070 for (rule
= match_list
->head
; rule
; rule
= rule
->next
)
2071 if (IS_RULE_IPv4_PREFIX_LIST(rule
->cmd
->str
))
2077 /* This function checks for the presence of an IPv6 prefix-list
2078 * match rule in the given route-map index.
2081 route_map_is_ipv6_pfx_list_rule_present(struct route_map_index
*index
)
2083 struct route_map_rule_list
*match_list
= NULL
;
2084 struct route_map_rule
*rule
= NULL
;
2086 match_list
= &index
->match_list
;
2087 for (rule
= match_list
->head
; rule
; rule
= rule
->next
)
2088 if (IS_RULE_IPv6_PREFIX_LIST(rule
->cmd
->str
))
2094 /* This function does the following:
2095 * 1) If plist_name is not present, search for a IPv4 or IPv6 prefix-list
2096 * match clause (based on the afi passed to this foo) and get the
2098 * 2) Look up the prefix-list using the name.
2099 * 3) If the prefix-list is not found then, add the index to the IPv4/IPv6
2100 * default-route's node in the trie (based on the afi passed to this foo).
2101 * 4) If the prefix-list is found then, remove the index from the IPv4/IPv6
2102 * default-route's node in the trie (based on the afi passed to this foo).
2103 * 5) If a prefix-entry is passed then, create a route-node for this entry and
2104 * add this index to the route-node.
2105 * 6) If prefix-entry is not passed then, for every prefix-entry in the
2106 * prefix-list, create a route-node for this entry and
2107 * add this index to the route-node.
2109 static void route_map_add_plist_entries(afi_t afi
,
2110 struct route_map_index
*index
,
2111 const char *plist_name
,
2112 struct prefix_list_entry
*entry
)
2114 struct route_map_rule_list
*match_list
= NULL
;
2115 struct route_map_rule
*match
= NULL
;
2116 struct prefix_list
*plist
= NULL
;
2117 struct prefix_list_entry
*pentry
= NULL
;
2118 bool plist_rule_is_present
= false;
2121 match_list
= &index
->match_list
;
2123 for (match
= match_list
->head
; match
; match
= match
->next
) {
2124 if (afi
== AFI_IP
) {
2125 if (IS_RULE_IPv4_PREFIX_LIST(match
->cmd
->str
)) {
2126 plist_rule_is_present
= true;
2130 if (IS_RULE_IPv6_PREFIX_LIST(match
->cmd
->str
)) {
2131 plist_rule_is_present
= true;
2137 if (plist_rule_is_present
)
2138 plist
= prefix_list_lookup(afi
, match
->rule_str
);
2140 plist
= prefix_list_lookup(afi
, plist_name
);
2144 route_map_pfx_table_add_default(afi
, index
);
2148 /* Default entry should be deleted only if the first entry of the
2149 * prefix-list is created.
2152 if (plist
->count
== 1)
2153 route_map_pfx_table_del_default(afi
, index
);
2155 route_map_pfx_table_del_default(afi
, index
);
2159 if (afi
== AFI_IP
) {
2160 route_map_pfx_table_add(index
->map
->ipv4_prefix_table
,
2163 route_map_pfx_table_add(index
->map
->ipv6_prefix_table
,
2167 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
2168 if (afi
== AFI_IP
) {
2169 route_map_pfx_table_add(
2170 index
->map
->ipv4_prefix_table
, index
,
2173 route_map_pfx_table_add(
2174 index
->map
->ipv6_prefix_table
, index
,
2181 /* This function does the following:
2182 * 1) If plist_name is not present, search for a IPv4 or IPv6 prefix-list
2183 * match clause (based on the afi passed to this foo) and get the
2185 * 2) Look up the prefix-list using the name.
2186 * 3) If the prefix-list is not found then, delete the index from the IPv4/IPv6
2187 * default-route's node in the trie (based on the afi passed to this foo).
2188 * 4) If a prefix-entry is passed then, remove this index from the route-node
2189 * for the prefix in this prefix-entry.
2190 * 5) If prefix-entry is not passed then, for every prefix-entry in the
2191 * prefix-list, remove this index from the route-node
2192 * for the prefix in this prefix-entry.
2194 static void route_map_del_plist_entries(afi_t afi
,
2195 struct route_map_index
*index
,
2196 const char *plist_name
,
2197 struct prefix_list_entry
*entry
)
2199 struct route_map_rule_list
*match_list
= NULL
;
2200 struct route_map_rule
*match
= NULL
;
2201 struct prefix_list
*plist
= NULL
;
2202 struct prefix_list_entry
*pentry
= NULL
;
2203 bool plist_rule_is_present
= false;
2206 match_list
= &index
->match_list
;
2208 for (match
= match_list
->head
; match
; match
= match
->next
) {
2209 if (afi
== AFI_IP
) {
2210 if (IS_RULE_IPv4_PREFIX_LIST(match
->cmd
->str
)) {
2211 plist_rule_is_present
= true;
2215 if (IS_RULE_IPv6_PREFIX_LIST(match
->cmd
->str
)) {
2216 plist_rule_is_present
= true;
2222 if (plist_rule_is_present
)
2223 plist
= prefix_list_lookup(afi
, match
->rule_str
);
2225 plist
= prefix_list_lookup(afi
, plist_name
);
2229 route_map_pfx_table_del_default(afi
, index
);
2234 if (afi
== AFI_IP
) {
2235 route_map_pfx_table_del(index
->map
->ipv4_prefix_table
,
2238 route_map_pfx_table_del(index
->map
->ipv6_prefix_table
,
2242 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
2243 if (afi
== AFI_IP
) {
2244 route_map_pfx_table_del(
2245 index
->map
->ipv4_prefix_table
, index
,
2248 route_map_pfx_table_del(
2249 index
->map
->ipv6_prefix_table
, index
,
2257 * This function handles the cases where a prefix-list is added/removed
2258 * as a match command from a particular route-map index.
2259 * It updates the prefix-table of the route-map accordingly.
2261 static void route_map_trie_update(afi_t afi
, route_map_event_t event
,
2262 struct route_map_index
*index
,
2263 const char *plist_name
)
2265 if (event
== RMAP_EVENT_PLIST_ADDED
) {
2266 if (afi
== AFI_IP
) {
2267 if (!route_map_is_ipv6_pfx_list_rule_present(index
)) {
2268 route_map_pfx_table_del_default(AFI_IP6
, index
);
2269 route_map_add_plist_entries(afi
, index
,
2272 route_map_del_plist_entries(AFI_IP6
, index
,
2276 if (!route_map_is_ip_pfx_list_rule_present(index
)) {
2277 route_map_pfx_table_del_default(AFI_IP
, index
);
2278 route_map_add_plist_entries(afi
, index
,
2281 route_map_del_plist_entries(AFI_IP
, index
, NULL
,
2285 } else if (event
== RMAP_EVENT_PLIST_DELETED
) {
2286 if (afi
== AFI_IP
) {
2287 route_map_del_plist_entries(afi
, index
, plist_name
,
2290 /* If IPv6 prefix-list match rule is not present,
2291 * add this index to the IPv4 default route's trie
2293 * Also, add this index to the trie nodes created
2294 * for each of the prefix-entries within the IPv6
2295 * prefix-list, if the IPv6 prefix-list match rule
2296 * is present. Else, add this index to the IPv6
2297 * default route's trie node.
2299 if (!route_map_is_ipv6_pfx_list_rule_present(index
))
2300 route_map_pfx_table_add_default(afi
, index
);
2302 route_map_add_plist_entries(AFI_IP6
, index
, NULL
, NULL
);
2304 route_map_del_plist_entries(afi
, index
, plist_name
,
2307 /* If IPv4 prefix-list match rule is not present,
2308 * add this index to the IPv6 default route's trie
2310 * Also, add this index to the trie nodes created
2311 * for each of the prefix-entries within the IPv4
2312 * prefix-list, if the IPv4 prefix-list match rule
2313 * is present. Else, add this index to the IPv4
2314 * default route's trie node.
2316 if (!route_map_is_ip_pfx_list_rule_present(index
))
2317 route_map_pfx_table_add_default(afi
, index
);
2319 route_map_add_plist_entries(AFI_IP
, index
, NULL
, NULL
);
2325 * This function handles the cases where a route-map index and
2326 * prefix-list is added/removed.
2327 * It updates the prefix-table of the route-map accordingly.
2329 static void route_map_pfx_tbl_update(route_map_event_t event
,
2330 struct route_map_index
*index
, afi_t afi
,
2331 const char *plist_name
)
2333 struct route_map
*rmap
= NULL
;
2338 if (event
== RMAP_EVENT_INDEX_ADDED
) {
2339 route_map_pfx_table_add_default(AFI_IP
, index
);
2340 route_map_pfx_table_add_default(AFI_IP6
, index
);
2344 if (event
== RMAP_EVENT_INDEX_DELETED
) {
2345 route_map_pfx_table_del_default(AFI_IP
, index
);
2346 route_map_pfx_table_del_default(AFI_IP6
, index
);
2348 if ((index
->map
->head
== NULL
) && (index
->map
->tail
== NULL
)) {
2351 if (rmap
->ipv4_prefix_table
) {
2352 route_table_finish(rmap
->ipv4_prefix_table
);
2353 rmap
->ipv4_prefix_table
= NULL
;
2356 if (rmap
->ipv6_prefix_table
) {
2357 route_table_finish(rmap
->ipv6_prefix_table
);
2358 rmap
->ipv6_prefix_table
= NULL
;
2364 /* Handle prefix-list match rule addition/deletion.
2366 route_map_trie_update(afi
, event
, index
, plist_name
);
2370 * This function handles the cases where a new prefix-entry is added to
2371 * a prefix-list or, an existing prefix-entry is removed from the prefix-list.
2372 * It updates the prefix-table of the route-map accordingly.
2374 static void route_map_pentry_update(route_map_event_t event
,
2375 const char *plist_name
,
2376 struct route_map_index
*index
,
2377 struct prefix_list_entry
*pentry
)
2379 struct prefix_list
*plist
= NULL
;
2381 unsigned char family
= pentry
->prefix
.family
;
2383 if (family
== AF_INET
) {
2385 plist
= prefix_list_lookup(AFI_IP
, plist_name
);
2388 plist
= prefix_list_lookup(AFI_IP6
, plist_name
);
2391 if (event
== RMAP_EVENT_PLIST_ADDED
) {
2392 if (afi
== AFI_IP
) {
2393 if (!route_map_is_ipv6_pfx_list_rule_present(index
))
2394 route_map_add_plist_entries(afi
, index
,
2395 plist_name
, pentry
);
2397 if (!route_map_is_ip_pfx_list_rule_present(index
))
2398 route_map_add_plist_entries(afi
, index
,
2399 plist_name
, pentry
);
2401 } else if (event
== RMAP_EVENT_PLIST_DELETED
) {
2402 route_map_del_plist_entries(afi
, index
, plist_name
, pentry
);
2404 if (plist
->count
== 1) {
2405 if (afi
== AFI_IP
) {
2406 if (!route_map_is_ipv6_pfx_list_rule_present(
2408 route_map_pfx_table_add_default(afi
,
2411 if (!route_map_is_ip_pfx_list_rule_present(
2413 route_map_pfx_table_add_default(afi
,
2420 static void route_map_pentry_process_dependency(struct hash_bucket
*bucket
,
2423 char *rmap_name
= NULL
;
2424 struct route_map
*rmap
= NULL
;
2425 struct route_map_index
*index
= NULL
;
2426 struct route_map_rule_list
*match_list
= NULL
;
2427 struct route_map_rule
*match
= NULL
;
2428 struct route_map_dep_data
*dep_data
= NULL
;
2429 struct route_map_pentry_dep
*pentry_dep
=
2430 (struct route_map_pentry_dep
*)data
;
2431 unsigned char family
= pentry_dep
->pentry
->prefix
.family
;
2433 dep_data
= (struct route_map_dep_data
*)bucket
->data
;
2437 rmap_name
= dep_data
->rname
;
2438 rmap
= route_map_lookup_by_name(rmap_name
);
2439 if (!rmap
|| !rmap
->head
)
2442 for (index
= rmap
->head
; index
; index
= index
->next
) {
2443 match_list
= &index
->match_list
;
2448 for (match
= match_list
->head
; match
; match
= match
->next
) {
2449 if (strcmp(match
->rule_str
, pentry_dep
->plist_name
)
2451 if (IS_RULE_IPv4_PREFIX_LIST(match
->cmd
->str
)
2452 && family
== AF_INET
) {
2453 route_map_pentry_update(
2455 pentry_dep
->plist_name
, index
,
2456 pentry_dep
->pentry
);
2457 } else if (IS_RULE_IPv6_PREFIX_LIST(
2459 && family
== AF_INET6
) {
2460 route_map_pentry_update(
2462 pentry_dep
->plist_name
, index
,
2463 pentry_dep
->pentry
);
2470 void route_map_notify_pentry_dependencies(const char *affected_name
,
2471 struct prefix_list_entry
*pentry
,
2472 route_map_event_t event
)
2474 struct route_map_dep
*dep
= NULL
;
2475 struct hash
*upd8_hash
= NULL
;
2476 struct route_map_pentry_dep pentry_dep
;
2478 if (!affected_name
|| !pentry
)
2481 upd8_hash
= route_map_get_dep_hash(event
);
2485 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, (void *)affected_name
,
2488 if (!dep
->this_hash
)
2489 dep
->this_hash
= upd8_hash
;
2491 memset(&pentry_dep
, 0, sizeof(pentry_dep
));
2492 pentry_dep
.pentry
= pentry
;
2493 pentry_dep
.plist_name
= affected_name
;
2494 pentry_dep
.event
= event
;
2496 hash_iterate(dep
->dep_rmap_hash
,
2497 route_map_pentry_process_dependency
,
2498 (void *)&pentry_dep
);
2502 /* Apply route map's each index to the object.
2504 The matrix for a route-map looks like this:
2505 (note, this includes the description for the "NEXT"
2506 and "GOTO" frobs now
2508 | Match | No Match | No op
2509 |-----------|--------------|-------
2510 permit | action | cont | cont.
2511 | | default:deny | default:permit
2512 -------------------+-----------------------
2513 | deny | cont | cont.
2514 deny | | default:deny | default:permit
2515 |-----------|--------------|--------
2518 -Apply Set statements, accept route
2519 -If Call statement is present jump to the specified route-map, if it
2520 denies the route we finish.
2521 -If NEXT is specified, goto NEXT statement
2522 -If GOTO is specified, goto the first clause where pref > nextpref
2523 -If nothing is specified, do as Cisco and finish
2525 -Route is denied by route-map.
2529 If we get no matches after we've processed all updates, then the route
2532 Some notes on the new "CALL", "NEXT" and "GOTO"
2533 call WORD - If this clause is matched, then the set statements
2534 are executed and then we jump to route-map 'WORD'. If
2535 this route-map denies the route, we finish, in other
2537 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
2538 on-match next - If this clause is matched, then the set statements
2539 are executed and then we drop through to the next clause
2540 on-match goto n - If this clause is matched, then the set statements
2541 are executed and then we goto the nth clause, or the
2542 first clause greater than this. In order to ensure
2543 route-maps *always* exit, you cannot jump backwards.
2546 We need to make sure our route-map processing matches the above
2548 route_map_result_t
route_map_apply_ext(struct route_map
*map
,
2549 const struct prefix
*prefix
,
2550 void *match_object
, void *set_object
,
2553 static int recursion
= 0;
2554 enum route_map_cmd_result_t match_ret
= RMAP_NOMATCH
;
2555 route_map_result_t ret
= RMAP_PERMITMATCH
;
2556 struct route_map_index
*index
= NULL
;
2557 struct route_map_rule
*set
= NULL
;
2558 bool skip_match_clause
= false;
2560 if (recursion
> RMAP_RECURSION_LIMIT
) {
2562 EC_LIB_RMAP_RECURSION_LIMIT
,
2563 "route-map recursion limit (%d) reached, discarding route",
2564 RMAP_RECURSION_LIMIT
);
2566 return RMAP_DENYMATCH
;
2569 if (map
== NULL
|| map
->head
== NULL
) {
2570 ret
= RMAP_DENYMATCH
;
2571 goto route_map_apply_end
;
2576 if ((!map
->optimization_disabled
)
2577 && (map
->ipv4_prefix_table
|| map
->ipv6_prefix_table
)) {
2578 index
= route_map_get_index(map
, prefix
, match_object
,
2584 "Best match route-map: %s, sequence: %d for pfx: %pFX, result: %s",
2585 map
->name
, index
->pref
, prefix
,
2586 route_map_cmd_result_str(match_ret
));
2590 "No best match sequence for pfx: %pFX in route-map: %s, result: %s",
2592 route_map_cmd_result_str(match_ret
));
2594 * No index matches this prefix. Return deny unless,
2595 * match_ret = RMAP_NOOP.
2597 if (match_ret
== RMAP_NOOP
)
2598 ret
= RMAP_PERMITMATCH
;
2600 ret
= RMAP_DENYMATCH
;
2601 goto route_map_apply_end
;
2603 skip_match_clause
= true;
2608 for (; index
; index
= index
->next
) {
2609 if (!skip_match_clause
) {
2611 /* Apply this index. */
2612 match_ret
= route_map_apply_match(&index
->match_list
,
2613 prefix
, match_object
);
2616 "Route-map: %s, sequence: %d, prefix: %pFX, result: %s",
2617 map
->name
, index
->pref
, prefix
,
2618 route_map_cmd_result_str(match_ret
));
2621 skip_match_clause
= false;
2624 /* Now we apply the matrix from above */
2625 if (match_ret
== RMAP_NOOP
)
2627 * Do not change the return value. Retain the previous
2628 * return value. Previous values can be:
2629 * 1)permitmatch (if a nomatch was never
2630 * seen before in this route-map.)
2631 * 2)denymatch (if a nomatch was seen earlier in one
2632 * of the previous sequences)
2636 * 'cont' from matrix - continue to next route-map
2640 else if (match_ret
== RMAP_NOMATCH
) {
2643 * The return value is now changed to denymatch.
2644 * So from here on out, even if we see more noops,
2645 * we retain this return value and return this
2646 * eventually if there are no matches.
2648 ret
= RMAP_DENYMATCH
;
2651 * 'cont' from matrix - continue to next route-map
2655 } else if (match_ret
== RMAP_MATCH
) {
2656 if (index
->type
== RMAP_PERMIT
)
2659 /* Match succeeded, rmap is of type permit */
2660 ret
= RMAP_PERMITMATCH
;
2662 /* permit+match must execute sets */
2663 for (set
= index
->set_list
.head
; set
;
2666 * set cmds return RMAP_OKAY or
2667 * RMAP_ERROR. We do not care if
2668 * set succeeded or not. So, ignore
2671 (void)(*set
->cmd
->func_apply
)(
2672 set
->value
, prefix
, set_object
);
2674 /* Call another route-map if available */
2675 if (index
->nextrm
) {
2676 struct route_map
*nextrm
=
2677 route_map_lookup_by_name(
2680 if (nextrm
) /* Target route-map found,
2684 ret
= route_map_apply_ext(
2691 /* If nextrm returned 'deny', finish. */
2692 if (ret
== RMAP_DENYMATCH
)
2693 goto route_map_apply_end
;
2696 switch (index
->exitpolicy
) {
2698 goto route_map_apply_end
;
2702 /* Find the next clause to jump to */
2703 struct route_map_index
*next
=
2705 int nextpref
= index
->nextpref
;
2707 while (next
&& next
->pref
< nextpref
) {
2712 /* No clauses match! */
2713 goto route_map_apply_end
;
2717 } else if (index
->type
== RMAP_DENY
)
2720 ret
= RMAP_DENYMATCH
;
2721 goto route_map_apply_end
;
2726 route_map_apply_end
:
2728 zlog_debug("Route-map: %s, prefix: %pFX, result: %s",
2729 (map
? map
->name
: "null"), prefix
,
2730 route_map_result_str(ret
));
2733 if (index
!= NULL
&& ret
== RMAP_PERMITMATCH
)
2734 *pref
= index
->pref
;
2742 void route_map_add_hook(void (*func
)(const char *))
2744 route_map_master
.add_hook
= func
;
2747 void route_map_delete_hook(void (*func
)(const char *))
2749 route_map_master
.delete_hook
= func
;
2752 void route_map_event_hook(void (*func
)(const char *name
))
2754 route_map_master
.event_hook
= func
;
2757 /* Routines for route map dependency lists and dependency processing */
2758 static bool route_map_rmap_hash_cmp(const void *p1
, const void *p2
)
2760 return strcmp(((const struct route_map_dep_data
*)p1
)->rname
,
2761 ((const struct route_map_dep_data
*)p2
)->rname
)
2765 static bool route_map_dep_hash_cmp(const void *p1
, const void *p2
)
2768 return (strcmp(((const struct route_map_dep
*)p1
)->dep_name
,
2773 static void route_map_clear_reference(struct hash_bucket
*bucket
, void *arg
)
2775 struct route_map_dep
*dep
= bucket
->data
;
2776 struct route_map_dep_data
*dep_data
= NULL
, tmp_dep_data
;
2778 memset(&tmp_dep_data
, 0, sizeof(tmp_dep_data
));
2779 tmp_dep_data
.rname
= arg
;
2780 dep_data
= hash_release(dep
->dep_rmap_hash
, &tmp_dep_data
);
2783 zlog_debug("Clearing reference for %s to %s count: %d",
2784 dep
->dep_name
, tmp_dep_data
.rname
,
2787 XFREE(MTYPE_ROUTE_MAP_NAME
, dep_data
->rname
);
2788 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, dep_data
);
2790 if (!dep
->dep_rmap_hash
->count
) {
2791 dep
= hash_release(dep
->this_hash
, (void *)dep
->dep_name
);
2792 hash_free(dep
->dep_rmap_hash
);
2793 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
2794 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
2798 static void route_map_clear_all_references(char *rmap_name
)
2803 zlog_debug("Clearing references for %s", rmap_name
);
2805 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
2806 hash_iterate(route_map_dep_hash
[i
], route_map_clear_reference
,
2811 static unsigned int route_map_dep_data_hash_make_key(const void *p
)
2813 const struct route_map_dep_data
*dep_data
= p
;
2815 return string_hash_make(dep_data
->rname
);
2818 static void *route_map_dep_hash_alloc(void *p
)
2820 char *dep_name
= (char *)p
;
2821 struct route_map_dep
*dep_entry
;
2823 dep_entry
= XCALLOC(MTYPE_ROUTE_MAP_DEP
, sizeof(struct route_map_dep
));
2824 dep_entry
->dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
2825 dep_entry
->dep_rmap_hash
=
2826 hash_create_size(8, route_map_dep_data_hash_make_key
,
2827 route_map_rmap_hash_cmp
, "Route Map Dep Hash");
2828 dep_entry
->this_hash
= NULL
;
2833 static void *route_map_name_hash_alloc(void *p
)
2835 struct route_map_dep_data
*dep_data
= NULL
, *tmp_dep_data
= NULL
;
2837 dep_data
= XCALLOC(MTYPE_ROUTE_MAP_DEP_DATA
,
2838 sizeof(struct route_map_dep_data
));
2840 dep_data
->rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, tmp_dep_data
->rname
);
2844 static unsigned int route_map_dep_hash_make_key(const void *p
)
2846 return (string_hash_make((char *)p
));
2849 static void route_map_print_dependency(struct hash_bucket
*bucket
, void *data
)
2851 struct route_map_dep_data
*dep_data
= bucket
->data
;
2852 char *rmap_name
= dep_data
->rname
;
2853 char *dep_name
= data
;
2855 zlog_debug("%s: Dependency for %s: %s", __func__
, dep_name
, rmap_name
);
2858 static int route_map_dep_update(struct hash
*dephash
, const char *dep_name
,
2859 const char *rmap_name
, route_map_event_t type
)
2861 struct route_map_dep
*dep
= NULL
;
2862 char *dname
, *rname
;
2864 struct route_map_dep_data
*dep_data
= NULL
, *ret_dep_data
= NULL
;
2865 struct route_map_dep_data tmp_dep_data
;
2867 dname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
2868 rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
2871 case RMAP_EVENT_PLIST_ADDED
:
2872 case RMAP_EVENT_CLIST_ADDED
:
2873 case RMAP_EVENT_ECLIST_ADDED
:
2874 case RMAP_EVENT_ASLIST_ADDED
:
2875 case RMAP_EVENT_LLIST_ADDED
:
2876 case RMAP_EVENT_CALL_ADDED
:
2877 case RMAP_EVENT_FILTER_ADDED
:
2879 zlog_debug("Adding dependency for filter %s in route-map %s",
2880 dep_name
, rmap_name
);
2881 dep
= (struct route_map_dep
*)hash_get(
2882 dephash
, dname
, route_map_dep_hash_alloc
);
2888 if (!dep
->this_hash
)
2889 dep
->this_hash
= dephash
;
2891 memset(&tmp_dep_data
, 0, sizeof(tmp_dep_data
));
2892 tmp_dep_data
.rname
= rname
;
2893 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
2895 dep_data
= hash_get(dep
->dep_rmap_hash
, &tmp_dep_data
,
2896 route_map_name_hash_alloc
);
2900 case RMAP_EVENT_PLIST_DELETED
:
2901 case RMAP_EVENT_CLIST_DELETED
:
2902 case RMAP_EVENT_ECLIST_DELETED
:
2903 case RMAP_EVENT_ASLIST_DELETED
:
2904 case RMAP_EVENT_LLIST_DELETED
:
2905 case RMAP_EVENT_CALL_DELETED
:
2906 case RMAP_EVENT_FILTER_DELETED
:
2908 zlog_debug("Deleting dependency for filter %s in route-map %s",
2909 dep_name
, rmap_name
);
2910 dep
= (struct route_map_dep
*)hash_get(dephash
, dname
, NULL
);
2915 memset(&tmp_dep_data
, 0, sizeof(tmp_dep_data
));
2916 tmp_dep_data
.rname
= rname
;
2917 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
2919 * If dep_data is NULL then something has gone seriously
2920 * wrong in route-map handling. Note it and prevent
2925 "route-map dependency for route-map %s: %s is not correct",
2926 rmap_name
, dep_name
);
2932 if (!dep_data
->refcnt
) {
2933 ret_dep_data
= hash_release(dep
->dep_rmap_hash
,
2936 XFREE(MTYPE_ROUTE_MAP_NAME
,
2937 ret_dep_data
->rname
);
2938 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, ret_dep_data
);
2942 if (!dep
->dep_rmap_hash
->count
) {
2943 dep
= hash_release(dephash
, dname
);
2944 hash_free(dep
->dep_rmap_hash
);
2945 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
2946 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
2949 case RMAP_EVENT_SET_ADDED
:
2950 case RMAP_EVENT_SET_DELETED
:
2951 case RMAP_EVENT_SET_REPLACED
:
2952 case RMAP_EVENT_MATCH_ADDED
:
2953 case RMAP_EVENT_MATCH_DELETED
:
2954 case RMAP_EVENT_MATCH_REPLACED
:
2955 case RMAP_EVENT_INDEX_ADDED
:
2956 case RMAP_EVENT_INDEX_DELETED
:
2962 hash_iterate(dep
->dep_rmap_hash
,
2963 route_map_print_dependency
, dname
);
2967 XFREE(MTYPE_ROUTE_MAP_NAME
, rname
);
2968 XFREE(MTYPE_ROUTE_MAP_NAME
, dname
);
2972 static struct hash
*route_map_get_dep_hash(route_map_event_t event
)
2974 struct hash
*upd8_hash
= NULL
;
2977 case RMAP_EVENT_PLIST_ADDED
:
2978 case RMAP_EVENT_PLIST_DELETED
:
2979 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_PLIST
];
2981 case RMAP_EVENT_CLIST_ADDED
:
2982 case RMAP_EVENT_CLIST_DELETED
:
2983 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_CLIST
];
2985 case RMAP_EVENT_ECLIST_ADDED
:
2986 case RMAP_EVENT_ECLIST_DELETED
:
2987 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ECLIST
];
2989 case RMAP_EVENT_ASLIST_ADDED
:
2990 case RMAP_EVENT_ASLIST_DELETED
:
2991 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ASPATH
];
2993 case RMAP_EVENT_LLIST_ADDED
:
2994 case RMAP_EVENT_LLIST_DELETED
:
2995 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_LCLIST
];
2997 case RMAP_EVENT_CALL_ADDED
:
2998 case RMAP_EVENT_CALL_DELETED
:
2999 case RMAP_EVENT_MATCH_ADDED
:
3000 case RMAP_EVENT_MATCH_DELETED
:
3001 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_RMAP
];
3003 case RMAP_EVENT_FILTER_ADDED
:
3004 case RMAP_EVENT_FILTER_DELETED
:
3005 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_FILTER
];
3008 * Should we actually be ignoring these?
3009 * I am not sure but at this point in time, let
3010 * us get them into this switch and we can peel
3011 * them into the appropriate place in the future
3013 case RMAP_EVENT_SET_ADDED
:
3014 case RMAP_EVENT_SET_DELETED
:
3015 case RMAP_EVENT_SET_REPLACED
:
3016 case RMAP_EVENT_MATCH_REPLACED
:
3017 case RMAP_EVENT_INDEX_ADDED
:
3018 case RMAP_EVENT_INDEX_DELETED
:
3025 static void route_map_process_dependency(struct hash_bucket
*bucket
, void *data
)
3027 struct route_map_dep_data
*dep_data
= NULL
;
3028 char *rmap_name
= NULL
;
3030 dep_data
= bucket
->data
;
3031 rmap_name
= dep_data
->rname
;
3034 zlog_debug("Notifying %s of dependency", rmap_name
);
3035 if (route_map_master
.event_hook
)
3036 (*route_map_master
.event_hook
)(rmap_name
);
3039 void route_map_upd8_dependency(route_map_event_t type
, const char *arg
,
3040 const char *rmap_name
)
3042 struct hash
*upd8_hash
= NULL
;
3044 if ((upd8_hash
= route_map_get_dep_hash(type
))) {
3045 route_map_dep_update(upd8_hash
, arg
, rmap_name
, type
);
3047 if (type
== RMAP_EVENT_CALL_ADDED
) {
3049 if (route_map_master
.add_hook
)
3050 (*route_map_master
.add_hook
)(rmap_name
);
3051 } else if (type
== RMAP_EVENT_CALL_DELETED
) {
3053 if (route_map_master
.delete_hook
)
3054 (*route_map_master
.delete_hook
)(rmap_name
);
3059 void route_map_notify_dependencies(const char *affected_name
,
3060 route_map_event_t event
)
3062 struct route_map_dep
*dep
;
3063 struct hash
*upd8_hash
;
3069 name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, affected_name
);
3071 if ((upd8_hash
= route_map_get_dep_hash(event
)) == NULL
) {
3072 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
3076 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, name
, NULL
);
3078 if (!dep
->this_hash
)
3079 dep
->this_hash
= upd8_hash
;
3082 zlog_debug("Filter %s updated", dep
->dep_name
);
3083 hash_iterate(dep
->dep_rmap_hash
, route_map_process_dependency
,
3087 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
3090 /* VTY related functions. */
3091 static void clear_route_map_helper(struct route_map
*map
)
3093 struct route_map_index
*index
;
3095 map
->applied_clear
= map
->applied
;
3096 for (index
= map
->head
; index
; index
= index
->next
)
3097 index
->applied_clear
= index
->applied
;
3100 DEFUN (rmap_clear_counters
,
3101 rmap_clear_counters_cmd
,
3102 "clear route-map counters [WORD]",
3104 "route-map information\n"
3105 "counters associated with the specified route-map\n"
3109 struct route_map
*map
;
3111 const char *name
= (argc
== 3 ) ? argv
[idx_word
]->arg
: NULL
;
3114 map
= route_map_lookup_by_name(name
);
3117 clear_route_map_helper(map
);
3119 vty_out(vty
, "%s: 'route-map %s' not found\n",
3120 frr_protonameinst
, name
);
3124 for (map
= route_map_master
.head
; map
; map
= map
->next
)
3125 clear_route_map_helper(map
);
3132 DEFUN (rmap_show_name
,
3134 "show route-map [WORD] [json]",
3136 "route-map information\n"
3140 bool uj
= use_json(argc
, argv
);
3142 const char *name
= NULL
;
3144 if (argv_find(argv
, argc
, "WORD", &idx
))
3145 name
= argv
[idx
]->arg
;
3147 return vty_show_route_map(vty
, name
, uj
);
3150 DEFUN (rmap_show_unused
,
3151 rmap_show_unused_cmd
,
3152 "show route-map-unused",
3154 "unused route-map information\n")
3156 return vty_show_unused_route_map(vty
);
3163 "Debug option set for route-maps\n")
3169 DEFUN (no_debug_rmap
,
3171 "no debug route-map",
3174 "Debug option set for route-maps\n")
3181 static int rmap_config_write_debug(struct vty
*vty
);
3182 static struct cmd_node rmap_debug_node
= {
3183 .name
= "route-map debug",
3184 .node
= RMAP_DEBUG_NODE
,
3186 .config_write
= rmap_config_write_debug
,
3189 void route_map_show_debug(struct vty
*vty
)
3192 vty_out(vty
, "debug route-map\n");
3195 /* Configuration write function. */
3196 static int rmap_config_write_debug(struct vty
*vty
)
3201 vty_out(vty
, "debug route-map\n");
3208 /* Common route map rules */
3210 void *route_map_rule_tag_compile(const char *arg
)
3212 unsigned long int tmp
;
3217 tmp
= strtoul(arg
, &endptr
, 0);
3218 if (arg
[0] == '\0' || *endptr
!= '\0' || errno
|| tmp
> ROUTE_TAG_MAX
)
3221 tag
= XMALLOC(MTYPE_ROUTE_MAP_COMPILED
, sizeof(*tag
));
3227 void route_map_rule_tag_free(void *rule
)
3229 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
3232 void route_map_finish(void)
3235 struct route_map_rule_cmd_proxy
*proxy
;
3237 /* these 2 hash tables have INIT_HASH initializers, so the "default"
3238 * state is "initialized & empty" => fini() followed by init() to
3239 * return to that same state
3241 while ((proxy
= rmap_cmd_name_pop(rmap_match_cmds
)))
3243 rmap_cmd_name_fini(rmap_match_cmds
);
3244 rmap_cmd_name_init(rmap_match_cmds
);
3246 while ((proxy
= rmap_cmd_name_pop(rmap_set_cmds
)))
3248 rmap_cmd_name_fini(rmap_set_cmds
);
3249 rmap_cmd_name_init(rmap_set_cmds
);
3252 * All protocols are setting these to NULL
3253 * by default on shutdown( route_map_finish )
3254 * Why are we making them do this work?
3256 route_map_master
.add_hook
= NULL
;
3257 route_map_master
.delete_hook
= NULL
;
3258 route_map_master
.event_hook
= NULL
;
3260 /* cleanup route_map */
3261 while (route_map_master
.head
) {
3262 struct route_map
*map
= route_map_master
.head
;
3263 map
->to_be_processed
= false;
3264 route_map_delete(map
);
3267 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
3268 hash_free(route_map_dep_hash
[i
]);
3269 route_map_dep_hash
[i
] = NULL
;
3272 hash_free(route_map_master_hash
);
3273 route_map_master_hash
= NULL
;
3276 /* Increment the use_count counter while attaching the route map */
3277 void route_map_counter_increment(struct route_map
*map
)
3283 /* Decrement the use_count counter while detaching the route map. */
3284 void route_map_counter_decrement(struct route_map
*map
)
3287 if (map
->use_count
<= 0)
3293 DEFUN_HIDDEN(show_route_map_pfx_tbl
, show_route_map_pfx_tbl_cmd
,
3294 "show route-map RMAP_NAME prefix-table",
3298 "internal prefix-table\n")
3300 const char *rmap_name
= argv
[2]->arg
;
3301 struct route_map
*rmap
= NULL
;
3302 struct route_table
*rm_pfx_tbl4
= NULL
;
3303 struct route_table
*rm_pfx_tbl6
= NULL
;
3304 struct route_node
*rn
= NULL
, *prn
= NULL
;
3305 struct list
*rmap_index_list
= NULL
;
3306 struct listnode
*ln
= NULL
, *nln
= NULL
;
3307 struct route_map_index
*index
= NULL
;
3310 vty_out(vty
, "%s:\n", frr_protonameinst
);
3311 rmap
= route_map_lookup_by_name(rmap_name
);
3313 rm_pfx_tbl4
= rmap
->ipv4_prefix_table
;
3315 vty_out(vty
, "\n%s%43s%s\n", "IPv4 Prefix", "",
3316 "Route-map Index List");
3317 vty_out(vty
, "%s%39s%s\n", "_______________", "",
3318 "____________________");
3319 for (rn
= route_top(rm_pfx_tbl4
); rn
;
3320 rn
= route_next(rn
)) {
3321 vty_out(vty
, " %pRN (%d)\n", rn
,
3322 route_node_get_lock_count(rn
));
3324 vty_out(vty
, "(P) ");
3327 vty_out(vty
, "%pRN\n", prn
);
3331 rmap_index_list
= (struct list
*)rn
->info
;
3332 if (!rmap_index_list
3333 || !listcount(rmap_index_list
))
3334 vty_out(vty
, "%*s%s\n", len
, "", "-");
3336 for (ALL_LIST_ELEMENTS(rmap_index_list
,
3339 vty_out(vty
, "%*s%s seq %d\n",
3348 rm_pfx_tbl6
= rmap
->ipv6_prefix_table
;
3350 vty_out(vty
, "\n%s%43s%s\n", "IPv6 Prefix", "",
3351 "Route-map Index List");
3352 vty_out(vty
, "%s%39s%s\n", "_______________", "",
3353 "____________________");
3354 for (rn
= route_top(rm_pfx_tbl6
); rn
;
3355 rn
= route_next(rn
)) {
3356 vty_out(vty
, " %pRN (%d)\n", rn
,
3357 route_node_get_lock_count(rn
));
3359 vty_out(vty
, "(P) ");
3362 vty_out(vty
, "%pRN\n", prn
);
3366 rmap_index_list
= (struct list
*)rn
->info
;
3367 if (!rmap_index_list
3368 || !listcount(rmap_index_list
))
3369 vty_out(vty
, "%*s%s\n", len
, "", "-");
3371 for (ALL_LIST_ELEMENTS(rmap_index_list
,
3374 vty_out(vty
, "%*s%s seq %d\n",
3388 /* Initialization of route map vector. */
3389 void route_map_init(void)
3393 route_map_master_hash
=
3394 hash_create_size(8, route_map_hash_key_make
, route_map_hash_cmp
,
3395 "Route Map Master Hash");
3397 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++)
3398 route_map_dep_hash
[i
] = hash_create_size(
3399 8, route_map_dep_hash_make_key
, route_map_dep_hash_cmp
,
3400 "Route Map Dep Hash");
3404 route_map_cli_init();
3406 /* Install route map top node. */
3407 install_node(&rmap_debug_node
);
3409 /* Install route map commands. */
3410 install_element(CONFIG_NODE
, &debug_rmap_cmd
);
3411 install_element(CONFIG_NODE
, &no_debug_rmap_cmd
);
3413 /* Install show command */
3414 install_element(ENABLE_NODE
, &rmap_clear_counters_cmd
);
3416 install_element(ENABLE_NODE
, &rmap_show_name_cmd
);
3417 install_element(ENABLE_NODE
, &rmap_show_unused_cmd
);
3419 install_element(ENABLE_NODE
, &debug_rmap_cmd
);
3420 install_element(ENABLE_NODE
, &no_debug_rmap_cmd
);
3422 install_element(ENABLE_NODE
, &show_route_map_pfx_tbl_cmd
);