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
33 #include "lib_errors.h"
36 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP
, "Route map");
37 DEFINE_MTYPE(LIB
, ROUTE_MAP_NAME
, "Route map name");
38 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_INDEX
, "Route map index");
39 DEFINE_MTYPE(LIB
, ROUTE_MAP_RULE
, "Route map rule");
40 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_RULE_STR
, "Route map rule str");
41 DEFINE_MTYPE(LIB
, ROUTE_MAP_COMPILED
, "Route map compiled");
42 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_DEP
, "Route map dependency");
43 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_DEP_DATA
, "Route map dependency data");
45 DEFINE_QOBJ_TYPE(route_map_index
);
46 DEFINE_QOBJ_TYPE(route_map
);
48 #define IPv4_PREFIX_LIST "ip address prefix-list"
49 #define IPv6_PREFIX_LIST "ipv6 address prefix-list"
51 #define IS_RULE_IPv4_PREFIX_LIST(S) \
52 (strncmp(S, IPv4_PREFIX_LIST, strlen(IPv4_PREFIX_LIST)) == 0)
53 #define IS_RULE_IPv6_PREFIX_LIST(S) \
54 (strncmp(S, IPv6_PREFIX_LIST, strlen(IPv6_PREFIX_LIST)) == 0)
56 struct route_map_pentry_dep
{
57 struct prefix_list_entry
*pentry
;
58 const char *plist_name
;
59 route_map_event_t event
;
62 /* Vector for route match rules. */
63 static vector route_match_vec
;
65 /* Vector for route set rules. */
66 static vector route_set_vec
;
68 static void route_map_pfx_tbl_update(route_map_event_t event
,
69 struct route_map_index
*index
, afi_t afi
,
70 const char *plist_name
);
71 static void route_map_pfx_table_add_default(afi_t afi
,
72 struct route_map_index
*index
);
73 static void route_map_pfx_table_del_default(afi_t afi
,
74 struct route_map_index
*index
);
75 static void route_map_add_plist_entries(afi_t afi
,
76 struct route_map_index
*index
,
77 const char *plist_name
,
78 struct prefix_list_entry
*entry
);
79 static void route_map_del_plist_entries(afi_t afi
,
80 struct route_map_index
*index
,
81 const char *plist_name
,
82 struct prefix_list_entry
*entry
);
84 static struct hash
*route_map_get_dep_hash(route_map_event_t event
);
86 struct route_map_match_set_hooks rmap_match_set_hook
;
89 void route_map_match_interface_hook(int (*func
)(
90 struct route_map_index
*index
, const char *command
,
91 const char *arg
, route_map_event_t type
,
92 char *errmsg
, size_t errmsg_len
))
94 rmap_match_set_hook
.match_interface
= func
;
97 /* no match interface */
98 void route_map_no_match_interface_hook(int (*func
)(
99 struct route_map_index
*index
, const char *command
,
100 const char *arg
, route_map_event_t type
,
101 char *errmsg
, size_t errmsg_len
))
103 rmap_match_set_hook
.no_match_interface
= func
;
106 /* match ip address */
107 void route_map_match_ip_address_hook(int (*func
)(
108 struct route_map_index
*index
, const char *command
,
109 const char *arg
, route_map_event_t type
,
110 char *errmsg
, size_t errmsg_len
))
112 rmap_match_set_hook
.match_ip_address
= func
;
115 /* no match ip address */
116 void route_map_no_match_ip_address_hook(int (*func
)(
117 struct route_map_index
*index
, const char *command
,
118 const char *arg
, route_map_event_t type
,
119 char *errmsg
, size_t errmsg_len
))
121 rmap_match_set_hook
.no_match_ip_address
= func
;
124 /* match ip address prefix list */
125 void route_map_match_ip_address_prefix_list_hook(int (*func
)(
126 struct route_map_index
*index
, const char *command
,
127 const char *arg
, route_map_event_t type
,
128 char *errmsg
, size_t errmsg_len
))
130 rmap_match_set_hook
.match_ip_address_prefix_list
= func
;
133 /* no match ip address prefix list */
134 void route_map_no_match_ip_address_prefix_list_hook(int (*func
)(
135 struct route_map_index
*index
, const char *command
,
136 const char *arg
, route_map_event_t type
,
137 char *errmsg
, size_t errmsg_len
))
139 rmap_match_set_hook
.no_match_ip_address_prefix_list
= func
;
142 /* match ip next hop */
143 void route_map_match_ip_next_hop_hook(int (*func
)(
144 struct route_map_index
*index
, const char *command
,
145 const char *arg
, route_map_event_t type
,
146 char *errmsg
, size_t errmsg_len
))
148 rmap_match_set_hook
.match_ip_next_hop
= func
;
151 /* no match ip next hop */
152 void route_map_no_match_ip_next_hop_hook(int (*func
)(
153 struct route_map_index
*index
, const char *command
,
154 const char *arg
, route_map_event_t type
,
155 char *errmsg
, size_t errmsg_len
))
157 rmap_match_set_hook
.no_match_ip_next_hop
= func
;
160 /* match ip next hop prefix list */
161 void route_map_match_ip_next_hop_prefix_list_hook(int (*func
)(
162 struct route_map_index
*index
, const char *command
,
163 const char *arg
, route_map_event_t type
,
164 char *errmsg
, size_t errmsg_len
))
166 rmap_match_set_hook
.match_ip_next_hop_prefix_list
= func
;
169 /* no match ip next hop prefix list */
170 void route_map_no_match_ip_next_hop_prefix_list_hook(int (*func
)(
171 struct route_map_index
*index
, const char *command
,
172 const char *arg
, route_map_event_t type
,
173 char *errmsg
, size_t errmsg_len
))
175 rmap_match_set_hook
.no_match_ip_next_hop_prefix_list
= func
;
178 /* match ip next-hop type */
179 void route_map_match_ip_next_hop_type_hook(int (*func
)(
180 struct route_map_index
*index
, const char *command
,
181 const char *arg
, route_map_event_t type
,
182 char *errmsg
, size_t errmsg_len
))
184 rmap_match_set_hook
.match_ip_next_hop_type
= func
;
187 /* no match ip next-hop type */
188 void route_map_no_match_ip_next_hop_type_hook(int (*func
)(
189 struct route_map_index
*index
, const char *command
,
190 const char *arg
, route_map_event_t type
,
191 char *errmsg
, size_t errmsg_len
))
193 rmap_match_set_hook
.no_match_ip_next_hop_type
= func
;
196 /* match ipv6 address */
197 void route_map_match_ipv6_address_hook(int (*func
)(
198 struct route_map_index
*index
, const char *command
,
199 const char *arg
, route_map_event_t type
,
200 char *errmsg
, size_t errmsg_len
))
202 rmap_match_set_hook
.match_ipv6_address
= func
;
205 /* no match ipv6 address */
206 void route_map_no_match_ipv6_address_hook(int (*func
)(
207 struct route_map_index
*index
, const char *command
,
208 const char *arg
, route_map_event_t type
,
209 char *errmsg
, size_t errmsg_len
))
211 rmap_match_set_hook
.no_match_ipv6_address
= func
;
215 /* match ipv6 address prefix list */
216 void route_map_match_ipv6_address_prefix_list_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_ipv6_address_prefix_list
= func
;
224 /* no match ipv6 address prefix list */
225 void route_map_no_match_ipv6_address_prefix_list_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_ipv6_address_prefix_list
= func
;
233 /* match ipv6 next-hop type */
234 void route_map_match_ipv6_next_hop_type_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_next_hop_type
= func
;
242 /* no match ipv6 next-hop type */
243 void route_map_no_match_ipv6_next_hop_type_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_next_hop_type
= func
;
252 void route_map_match_metric_hook(int (*func
)(
253 struct route_map_index
*index
, const char *command
,
254 const char *arg
, route_map_event_t type
,
255 char *errmsg
, size_t errmsg_len
))
257 rmap_match_set_hook
.match_metric
= func
;
260 /* no match metric */
261 void route_map_no_match_metric_hook(int (*func
)(
262 struct route_map_index
*index
, const char *command
,
263 const char *arg
, route_map_event_t type
,
264 char *errmsg
, size_t errmsg_len
))
266 rmap_match_set_hook
.no_match_metric
= func
;
270 void route_map_match_tag_hook(int (*func
)(struct route_map_index
*index
,
271 const char *command
, const char *arg
,
272 route_map_event_t type
,
273 char *errmsg
, size_t errmsg_len
))
275 rmap_match_set_hook
.match_tag
= func
;
279 void route_map_no_match_tag_hook(int (*func
)(
280 struct route_map_index
*index
, const char *command
,
281 const char *arg
, route_map_event_t type
,
282 char *errmsg
, size_t errmsg_len
))
284 rmap_match_set_hook
.no_match_tag
= func
;
287 /* set sr-te color */
288 void route_map_set_srte_color_hook(int (*func
)(struct route_map_index
*index
,
291 char *errmsg
, size_t errmsg_len
))
293 rmap_match_set_hook
.set_srte_color
= func
;
296 /* no set sr-te color */
297 void route_map_no_set_srte_color_hook(int (*func
)(struct route_map_index
*index
,
300 char *errmsg
, size_t errmsg_len
))
302 rmap_match_set_hook
.no_set_srte_color
= func
;
306 void route_map_set_ip_nexthop_hook(int (*func
)(struct route_map_index
*index
,
309 char *errmsg
, size_t errmsg_len
))
311 rmap_match_set_hook
.set_ip_nexthop
= func
;
314 /* no set ip nexthop */
315 void route_map_no_set_ip_nexthop_hook(int (*func
)(struct route_map_index
*index
,
321 rmap_match_set_hook
.no_set_ip_nexthop
= func
;
324 /* set ipv6 nexthop local */
325 void route_map_set_ipv6_nexthop_local_hook(
326 int (*func
)(struct route_map_index
*index
,
327 const char *command
, const char *arg
,
328 char *errmsg
, size_t errmsg_len
))
330 rmap_match_set_hook
.set_ipv6_nexthop_local
= func
;
333 /* no set ipv6 nexthop local */
334 void route_map_no_set_ipv6_nexthop_local_hook(
335 int (*func
)(struct route_map_index
*index
,
336 const char *command
, const char *arg
,
337 char *errmsg
, size_t errmsg_len
))
339 rmap_match_set_hook
.no_set_ipv6_nexthop_local
= func
;
343 void route_map_set_metric_hook(int (*func
)(struct route_map_index
*index
,
346 char *errmsg
, size_t errmsg_len
))
348 rmap_match_set_hook
.set_metric
= func
;
352 void route_map_no_set_metric_hook(int (*func
)(struct route_map_index
*index
,
355 char *errmsg
, size_t errmsg_len
))
357 rmap_match_set_hook
.no_set_metric
= func
;
361 void route_map_set_tag_hook(int (*func
)(struct route_map_index
*index
,
362 const char *command
, const char *arg
,
363 char *errmsg
, size_t errmsg_len
))
365 rmap_match_set_hook
.set_tag
= func
;
369 void route_map_no_set_tag_hook(int (*func
)(struct route_map_index
*index
,
372 char *errmsg
, size_t errmsg_len
))
374 rmap_match_set_hook
.no_set_tag
= func
;
377 int generic_match_add(struct route_map_index
*index
,
378 const char *command
, const char *arg
,
379 route_map_event_t type
,
380 char *errmsg
, size_t errmsg_len
)
382 enum rmap_compile_rets ret
;
384 ret
= route_map_add_match(index
, command
, arg
, type
);
386 case RMAP_RULE_MISSING
:
387 snprintf(errmsg
, errmsg_len
, "%% [%s] Can't find rule.",
389 return CMD_WARNING_CONFIG_FAILED
;
390 case RMAP_COMPILE_ERROR
:
391 snprintf(errmsg
, errmsg_len
,
392 "%% [%s] Argument form is unsupported or malformed.",
394 return CMD_WARNING_CONFIG_FAILED
;
395 case RMAP_COMPILE_SUCCESS
:
397 * Nothing to do here move along
405 int generic_match_delete(struct route_map_index
*index
,
406 const char *command
, const char *arg
,
407 route_map_event_t type
,
408 char *errmsg
, size_t errmsg_len
)
410 enum rmap_compile_rets ret
;
411 int retval
= CMD_SUCCESS
;
412 char *dep_name
= NULL
;
414 char *rmap_name
= NULL
;
416 if (type
!= RMAP_EVENT_MATCH_DELETED
) {
417 /* ignore the mundane, the types without any dependency */
419 if ((tmpstr
= route_map_get_match_arg(index
, command
))
422 XSTRDUP(MTYPE_ROUTE_MAP_RULE
, tmpstr
);
424 dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_RULE
, arg
);
426 rmap_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, index
->map
->name
);
429 ret
= route_map_delete_match(index
, command
, dep_name
, type
);
431 case RMAP_RULE_MISSING
:
432 snprintf(errmsg
, errmsg_len
, "%% [%s] Can't find rule.",
434 retval
= CMD_WARNING_CONFIG_FAILED
;
436 case RMAP_COMPILE_ERROR
:
437 snprintf(errmsg
, errmsg_len
,
438 "%% [%s] Argument form is unsupported or malformed.",
440 retval
= CMD_WARNING_CONFIG_FAILED
;
442 case RMAP_COMPILE_SUCCESS
:
449 XFREE(MTYPE_ROUTE_MAP_RULE
, dep_name
);
450 XFREE(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
455 int generic_set_add(struct route_map_index
*index
,
456 const char *command
, const char *arg
,
457 char *errmsg
, size_t errmsg_len
)
459 enum rmap_compile_rets ret
;
461 ret
= route_map_add_set(index
, command
, arg
);
463 case RMAP_RULE_MISSING
:
464 snprintf(errmsg
, errmsg_len
,
465 "%% [%s] Can't find rule.", frr_protonameinst
);
466 return CMD_WARNING_CONFIG_FAILED
;
467 case RMAP_COMPILE_ERROR
:
468 snprintf(errmsg
, errmsg_len
,
469 "%% [%s] Argument form is unsupported or malformed.",
471 return CMD_WARNING_CONFIG_FAILED
;
472 case RMAP_COMPILE_SUCCESS
:
479 int generic_set_delete(struct route_map_index
*index
,
480 const char *command
, const char *arg
,
481 char *errmsg
, size_t errmsg_len
)
483 enum rmap_compile_rets ret
;
485 ret
= route_map_delete_set(index
, command
, arg
);
487 case RMAP_RULE_MISSING
:
488 snprintf(errmsg
, errmsg_len
, "%% [%s] Can't find rule.",
490 return CMD_WARNING_CONFIG_FAILED
;
491 case RMAP_COMPILE_ERROR
:
492 snprintf(errmsg
, errmsg_len
,
493 "%% [%s] Argument form is unsupported or malformed.",
495 return CMD_WARNING_CONFIG_FAILED
;
496 case RMAP_COMPILE_SUCCESS
:
504 /* Master list of route map. */
505 struct route_map_list route_map_master
= {NULL
, NULL
, NULL
, NULL
, NULL
};
506 struct hash
*route_map_master_hash
= NULL
;
508 static unsigned int route_map_hash_key_make(const void *p
)
510 const struct route_map
*map
= p
;
511 return string_hash_make(map
->name
);
514 static bool route_map_hash_cmp(const void *p1
, const void *p2
)
516 const struct route_map
*map1
= p1
;
517 const struct route_map
*map2
= p2
;
519 if (map1
->deleted
== map2
->deleted
) {
520 if (map1
->name
&& map2
->name
) {
521 if (!strcmp(map1
->name
, map2
->name
)) {
524 } else if (!map1
->name
&& !map2
->name
) {
532 enum route_map_upd8_type
{
537 /* all possible route-map dependency types */
538 enum route_map_dep_type
{
539 ROUTE_MAP_DEP_RMAP
= 1,
541 ROUTE_MAP_DEP_ECLIST
,
542 ROUTE_MAP_DEP_LCLIST
,
544 ROUTE_MAP_DEP_ASPATH
,
545 ROUTE_MAP_DEP_FILTER
,
549 struct route_map_dep
{
551 struct hash
*dep_rmap_hash
;
552 struct hash
*this_hash
; /* ptr to the hash structure this is part of */
555 struct route_map_dep_data
{
559 /* Count of number of sequences of this
560 * route-map that depend on the same entity.
565 /* Hashes maintaining dependency between various sublists used by route maps */
566 static struct hash
*route_map_dep_hash
[ROUTE_MAP_DEP_MAX
];
568 static unsigned int route_map_dep_hash_make_key(const void *p
);
569 static void route_map_clear_all_references(char *rmap_name
);
570 static void route_map_rule_delete(struct route_map_rule_list
*,
571 struct route_map_rule
*);
572 static bool rmap_debug
;
574 /* New route map allocation. Please note route map's name must be
576 static struct route_map
*route_map_new(const char *name
)
578 struct route_map
*new;
580 new = XCALLOC(MTYPE_ROUTE_MAP
, sizeof(struct route_map
));
581 new->name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
582 QOBJ_REG(new, route_map
);
586 /* Add new name to route_map. */
587 static struct route_map
*route_map_add(const char *name
)
589 struct route_map
*map
;
590 struct route_map_list
*list
;
592 map
= route_map_new(name
);
593 list
= &route_map_master
;
595 /* Add map to the hash */
596 hash_get(route_map_master_hash
, map
, hash_alloc_intern
);
598 /* Add new entry to the head of the list to match how it is added in the
599 * hash table. This is to ensure that if the same route-map has been
600 * created more than once and then marked for deletion (which can happen
601 * if prior deletions haven't completed as BGP hasn't yet done the
602 * route-map processing), the order of the entities is the same in both
603 * the list and the hash table. Otherwise, since there is nothing to
604 * distinguish between the two entries, the wrong entry could get freed.
605 * TODO: This needs to be re-examined to handle it better - e.g., revive
606 * a deleted entry if the route-map is created again.
609 map
->next
= list
->head
;
611 list
->head
->prev
= map
;
617 if (route_map_master
.add_hook
) {
618 (*route_map_master
.add_hook
)(name
);
619 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_ADDED
);
622 if (!map
->ipv4_prefix_table
)
623 map
->ipv4_prefix_table
= route_table_init();
625 if (!map
->ipv6_prefix_table
)
626 map
->ipv6_prefix_table
= route_table_init();
629 zlog_debug("Add route-map %s", name
);
633 /* this is supposed to be called post processing by
634 * the delete hook function. Don't invoke delete_hook
635 * again in this routine.
637 static void route_map_free_map(struct route_map
*map
)
639 struct route_map_list
*list
;
640 struct route_map_index
*index
;
645 while ((index
= map
->head
) != NULL
)
646 route_map_index_delete(index
, 0);
649 zlog_debug("Deleting route-map %s", map
->name
);
651 list
= &route_map_master
;
656 map
->next
->prev
= map
->prev
;
658 list
->tail
= map
->prev
;
661 map
->prev
->next
= map
->next
;
663 list
->head
= map
->next
;
665 hash_release(route_map_master_hash
, map
);
666 XFREE(MTYPE_ROUTE_MAP_NAME
, map
->name
);
667 XFREE(MTYPE_ROUTE_MAP
, map
);
670 /* Route map delete from list. */
671 void route_map_delete(struct route_map
*map
)
673 struct route_map_index
*index
;
676 while ((index
= map
->head
) != NULL
)
677 route_map_index_delete(index
, 0);
682 /* Clear all dependencies */
683 route_map_clear_all_references(name
);
685 /* Execute deletion hook. */
686 if (route_map_master
.delete_hook
) {
687 (*route_map_master
.delete_hook
)(name
);
688 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_DELETED
);
691 if (!map
->to_be_processed
) {
692 route_map_free_map(map
);
696 /* Lookup route map by route map name string. */
697 struct route_map
*route_map_lookup_by_name(const char *name
)
699 struct route_map
*map
;
700 struct route_map tmp_map
;
705 // map.deleted is 0 via memset
706 memset(&tmp_map
, 0, sizeof(struct route_map
));
707 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
708 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
709 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
713 /* Simple helper to warn if route-map does not exist. */
714 struct route_map
*route_map_lookup_warn_noexist(struct vty
*vty
, const char *name
)
716 struct route_map
*route_map
= route_map_lookup_by_name(name
);
719 if (vty_shell_serv(vty
))
720 vty_out(vty
, "The route-map '%s' does not exist.\n", name
);
725 int route_map_mark_updated(const char *name
)
727 struct route_map
*map
;
729 struct route_map tmp_map
;
734 map
= route_map_lookup_by_name(name
);
736 /* If we did not find the routemap with deleted=false try again
740 memset(&tmp_map
, 0, sizeof(struct route_map
));
741 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
742 tmp_map
.deleted
= true;
743 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
744 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
748 map
->to_be_processed
= true;
755 static int route_map_clear_updated(struct route_map
*map
)
760 map
->to_be_processed
= false;
762 route_map_free_map(map
);
768 /* Lookup route map. If there isn't route map create one and return
770 struct route_map
*route_map_get(const char *name
)
772 struct route_map
*map
;
774 map
= route_map_lookup_by_name(name
);
776 map
= route_map_add(name
);
781 void route_map_walk_update_list(void (*route_map_update_fn
)(char *name
))
783 struct route_map
*node
;
784 struct route_map
*nnode
= NULL
;
786 for (node
= route_map_master
.head
; node
; node
= nnode
) {
787 if (node
->to_be_processed
) {
788 /* DD: Should we add any thread yield code here */
789 route_map_update_fn(node
->name
);
791 route_map_clear_updated(node
);
797 /* Return route map's type string. */
798 static const char *route_map_type_str(enum route_map_type type
)
812 static const char *route_map_cmd_result_str(enum route_map_cmd_result_t res
)
830 static const char *route_map_result_str(route_map_result_t res
)
835 case RMAP_PERMITMATCH
:
843 static void vty_show_route_map_entry(struct vty
*vty
, struct route_map
*map
)
845 struct route_map_index
*index
;
846 struct route_map_rule
*rule
;
848 vty_out(vty
, "route-map: %s Invoked: %" PRIu64
" Optimization: %s Processed Change: %s\n",
849 map
->name
, map
->applied
- map
->applied_clear
,
850 map
->optimization_disabled
? "disabled" : "enabled",
851 map
->to_be_processed
? "true" : "false");
853 for (index
= map
->head
; index
; index
= index
->next
) {
854 vty_out(vty
, " %s, sequence %d Invoked %" PRIu64
"\n",
855 route_map_type_str(index
->type
), index
->pref
,
856 index
->applied
- index
->applied_clear
);
859 if (index
->description
)
860 vty_out(vty
, " Description:\n %s\n",
864 vty_out(vty
, " Match clauses:\n");
865 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
866 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
869 vty_out(vty
, " Set clauses:\n");
870 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
871 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
875 vty_out(vty
, " Call clause:\n");
877 vty_out(vty
, " Call %s\n", index
->nextrm
);
880 vty_out(vty
, " Action:\n");
881 if (index
->exitpolicy
== RMAP_GOTO
)
882 vty_out(vty
, " Goto %d\n", index
->nextpref
);
883 else if (index
->exitpolicy
== RMAP_NEXT
)
884 vty_out(vty
, " Continue to next entry\n");
885 else if (index
->exitpolicy
== RMAP_EXIT
)
886 vty_out(vty
, " Exit routemap\n");
890 static int sort_route_map(const void **map1
, const void **map2
)
892 const struct route_map
*m1
= *map1
;
893 const struct route_map
*m2
= *map2
;
895 return strcmp(m1
->name
, m2
->name
);
898 static int vty_show_route_map(struct vty
*vty
, const char *name
)
900 struct route_map
*map
;
902 vty_out(vty
, "%s:\n", frr_protonameinst
);
905 map
= route_map_lookup_by_name(name
);
908 vty_show_route_map_entry(vty
, map
);
911 vty_out(vty
, "%s: 'route-map %s' not found\n",
912 frr_protonameinst
, name
);
917 struct list
*maplist
= list_new();
920 for (map
= route_map_master
.head
; map
; map
= map
->next
)
921 listnode_add(maplist
, map
);
923 list_sort(maplist
, sort_route_map
);
925 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
926 vty_show_route_map_entry(vty
, map
);
928 list_delete(&maplist
);
933 /* Unused route map details */
934 static int vty_show_unused_route_map(struct vty
*vty
)
936 struct list
*maplist
= list_new();
938 struct route_map
*map
;
940 for (map
= route_map_master
.head
; map
; map
= map
->next
) {
941 /* If use_count is zero, No protocol is using this routemap.
942 * so adding to the list.
945 listnode_add(maplist
, map
);
948 if (maplist
->count
> 0) {
949 vty_out(vty
, "\n%s:\n", frr_protonameinst
);
950 list_sort(maplist
, sort_route_map
);
952 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
953 vty_show_route_map_entry(vty
, map
);
955 vty_out(vty
, "\n%s: None\n", frr_protonameinst
);
958 list_delete(&maplist
);
962 /* New route map allocation. Please note route map's name must be
964 static struct route_map_index
*route_map_index_new(void)
966 struct route_map_index
*new;
968 new = XCALLOC(MTYPE_ROUTE_MAP_INDEX
, sizeof(struct route_map_index
));
969 new->exitpolicy
= RMAP_EXIT
; /* Default to Cisco-style */
970 TAILQ_INIT(&new->rhclist
);
971 QOBJ_REG(new, route_map_index
);
975 /* Free route map index. */
976 void route_map_index_delete(struct route_map_index
*index
, int notify
)
978 struct routemap_hook_context
*rhc
;
979 struct route_map_rule
*rule
;
984 zlog_debug("Deleting route-map %s sequence %d",
985 index
->map
->name
, index
->pref
);
987 /* Free route map entry description. */
988 XFREE(MTYPE_TMP
, index
->description
);
990 /* Free route map northbound hook contexts. */
991 while ((rhc
= TAILQ_FIRST(&index
->rhclist
)) != NULL
)
992 routemap_hook_context_free(rhc
);
994 /* Free route match. */
995 while ((rule
= index
->match_list
.head
) != NULL
) {
996 if (IS_RULE_IPv4_PREFIX_LIST(rule
->cmd
->str
))
997 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_DELETED
,
998 index
, AFI_IP
, rule
->rule_str
);
999 else if (IS_RULE_IPv6_PREFIX_LIST(rule
->cmd
->str
))
1000 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_DELETED
,
1004 route_map_rule_delete(&index
->match_list
, rule
);
1007 /* Free route set. */
1008 while ((rule
= index
->set_list
.head
) != NULL
)
1009 route_map_rule_delete(&index
->set_list
, rule
);
1011 /* Remove index from route map list. */
1013 index
->next
->prev
= index
->prev
;
1015 index
->map
->tail
= index
->prev
;
1018 index
->prev
->next
= index
->next
;
1020 index
->map
->head
= index
->next
;
1022 /* Free 'char *nextrm' if not NULL */
1023 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
1025 route_map_pfx_tbl_update(RMAP_EVENT_INDEX_DELETED
, index
, 0, NULL
);
1027 /* Execute event hook. */
1028 if (route_map_master
.event_hook
&& notify
) {
1029 (*route_map_master
.event_hook
)(index
->map
->name
);
1030 route_map_notify_dependencies(index
->map
->name
,
1031 RMAP_EVENT_CALL_ADDED
);
1033 XFREE(MTYPE_ROUTE_MAP_INDEX
, index
);
1036 /* Lookup index from route map. */
1037 static struct route_map_index
*route_map_index_lookup(struct route_map
*map
,
1038 enum route_map_type type
,
1041 struct route_map_index
*index
;
1043 for (index
= map
->head
; index
; index
= index
->next
)
1044 if ((index
->type
== type
|| type
== RMAP_ANY
)
1045 && index
->pref
== pref
)
1050 /* Add new index to route map. */
1051 static struct route_map_index
*
1052 route_map_index_add(struct route_map
*map
, enum route_map_type type
, int pref
)
1054 struct route_map_index
*index
;
1055 struct route_map_index
*point
;
1057 /* Allocate new route map inex. */
1058 index
= route_map_index_new();
1063 /* Compare preference. */
1064 for (point
= map
->head
; point
; point
= point
->next
)
1065 if (point
->pref
>= pref
)
1068 if (map
->head
== NULL
) {
1069 map
->head
= map
->tail
= index
;
1070 } else if (point
== NULL
) {
1071 index
->prev
= map
->tail
;
1072 map
->tail
->next
= index
;
1074 } else if (point
== map
->head
) {
1075 index
->next
= map
->head
;
1076 map
->head
->prev
= index
;
1079 index
->next
= point
;
1080 index
->prev
= point
->prev
;
1082 point
->prev
->next
= index
;
1083 point
->prev
= index
;
1086 route_map_pfx_tbl_update(RMAP_EVENT_INDEX_ADDED
, index
, 0, NULL
);
1088 /* Execute event hook. */
1089 if (route_map_master
.event_hook
) {
1090 (*route_map_master
.event_hook
)(map
->name
);
1091 route_map_notify_dependencies(map
->name
, RMAP_EVENT_CALL_ADDED
);
1095 zlog_debug("Route-map %s add sequence %d, type: %s",
1096 map
->name
, pref
, route_map_type_str(type
));
1101 /* Get route map index. */
1102 struct route_map_index
*
1103 route_map_index_get(struct route_map
*map
, enum route_map_type type
, int pref
)
1105 struct route_map_index
*index
;
1107 index
= route_map_index_lookup(map
, RMAP_ANY
, pref
);
1108 if (index
&& index
->type
!= type
) {
1109 /* Delete index from route map. */
1110 route_map_index_delete(index
, 1);
1114 index
= route_map_index_add(map
, type
, pref
);
1118 /* New route map rule */
1119 static struct route_map_rule
*route_map_rule_new(void)
1121 struct route_map_rule
*new;
1123 new = XCALLOC(MTYPE_ROUTE_MAP_RULE
, sizeof(struct route_map_rule
));
1127 /* Install rule command to the match list. */
1128 void route_map_install_match(const struct route_map_rule_cmd
*cmd
)
1130 vector_set(route_match_vec
, (void *)cmd
);
1133 /* Install rule command to the set list. */
1134 void route_map_install_set(const struct route_map_rule_cmd
*cmd
)
1136 vector_set(route_set_vec
, (void *)cmd
);
1139 /* Lookup rule command from match list. */
1140 static const struct route_map_rule_cmd
*route_map_lookup_match(const char *name
)
1143 const struct route_map_rule_cmd
*rule
;
1145 for (i
= 0; i
< vector_active(route_match_vec
); i
++)
1146 if ((rule
= vector_slot(route_match_vec
, i
)) != NULL
)
1147 if (strcmp(rule
->str
, name
) == 0)
1152 /* Lookup rule command from set list. */
1153 static const struct route_map_rule_cmd
*route_map_lookup_set(const char *name
)
1156 const struct route_map_rule_cmd
*rule
;
1158 for (i
= 0; i
< vector_active(route_set_vec
); i
++)
1159 if ((rule
= vector_slot(route_set_vec
, i
)) != NULL
)
1160 if (strcmp(rule
->str
, name
) == 0)
1165 /* Add match and set rule to rule list. */
1166 static void route_map_rule_add(struct route_map_rule_list
*list
,
1167 struct route_map_rule
*rule
)
1170 rule
->prev
= list
->tail
;
1172 list
->tail
->next
= rule
;
1178 /* Delete rule from rule list. */
1179 static void route_map_rule_delete(struct route_map_rule_list
*list
,
1180 struct route_map_rule
*rule
)
1182 if (rule
->cmd
->func_free
)
1183 (*rule
->cmd
->func_free
)(rule
->value
);
1185 XFREE(MTYPE_ROUTE_MAP_RULE_STR
, rule
->rule_str
);
1188 rule
->next
->prev
= rule
->prev
;
1190 list
->tail
= rule
->prev
;
1192 rule
->prev
->next
= rule
->next
;
1194 list
->head
= rule
->next
;
1196 XFREE(MTYPE_ROUTE_MAP_RULE
, rule
);
1199 /* strcmp wrapper function which don't crush even argument is NULL. */
1200 static int rulecmp(const char *dst
, const char *src
)
1211 return strcmp(dst
, src
);
1216 /* Use this to return the already specified argument for this match. This is
1217 * useful to get the specified argument with a route map match rule when the
1218 * rule is being deleted and the argument is not provided.
1220 const char *route_map_get_match_arg(struct route_map_index
*index
,
1221 const char *match_name
)
1223 struct route_map_rule
*rule
;
1224 const struct route_map_rule_cmd
*cmd
;
1226 /* First lookup rule for add match statement. */
1227 cmd
= route_map_lookup_match(match_name
);
1231 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1232 if (rule
->cmd
== cmd
&& rule
->rule_str
!= NULL
)
1233 return (rule
->rule_str
);
1238 static route_map_event_t
get_route_map_delete_event(route_map_event_t type
)
1241 case RMAP_EVENT_CALL_ADDED
:
1242 return RMAP_EVENT_CALL_DELETED
;
1243 case RMAP_EVENT_PLIST_ADDED
:
1244 return RMAP_EVENT_PLIST_DELETED
;
1245 case RMAP_EVENT_CLIST_ADDED
:
1246 return RMAP_EVENT_CLIST_DELETED
;
1247 case RMAP_EVENT_ECLIST_ADDED
:
1248 return RMAP_EVENT_ECLIST_DELETED
;
1249 case RMAP_EVENT_LLIST_ADDED
:
1250 return RMAP_EVENT_LLIST_DELETED
;
1251 case RMAP_EVENT_ASLIST_ADDED
:
1252 return RMAP_EVENT_ASLIST_DELETED
;
1253 case RMAP_EVENT_FILTER_ADDED
:
1254 return RMAP_EVENT_FILTER_DELETED
;
1255 case RMAP_EVENT_SET_ADDED
:
1256 case RMAP_EVENT_SET_DELETED
:
1257 case RMAP_EVENT_SET_REPLACED
:
1258 case RMAP_EVENT_MATCH_ADDED
:
1259 case RMAP_EVENT_MATCH_DELETED
:
1260 case RMAP_EVENT_MATCH_REPLACED
:
1261 case RMAP_EVENT_INDEX_ADDED
:
1262 case RMAP_EVENT_INDEX_DELETED
:
1263 case RMAP_EVENT_CALL_DELETED
:
1264 case RMAP_EVENT_PLIST_DELETED
:
1265 case RMAP_EVENT_CLIST_DELETED
:
1266 case RMAP_EVENT_ECLIST_DELETED
:
1267 case RMAP_EVENT_LLIST_DELETED
:
1268 case RMAP_EVENT_ASLIST_DELETED
:
1269 case RMAP_EVENT_FILTER_DELETED
:
1270 /* This function returns the appropriate 'deleted' event type
1271 * for every 'added' event type passed to this function.
1272 * This is done only for named entities used in the
1273 * route-map match commands.
1274 * This function is not to be invoked for any of the other event
1282 * Return to make c happy but if we get here something has gone
1283 * terribly terribly wrong, so yes this return makes no sense.
1285 return RMAP_EVENT_CALL_ADDED
;
1288 /* Add match statement to route map. */
1289 enum rmap_compile_rets
route_map_add_match(struct route_map_index
*index
,
1290 const char *match_name
,
1291 const char *match_arg
,
1292 route_map_event_t type
)
1294 struct route_map_rule
*rule
;
1295 struct route_map_rule
*next
;
1296 const struct route_map_rule_cmd
*cmd
;
1298 int8_t delete_rmap_event_type
= 0;
1299 const char *rule_key
;
1301 /* First lookup rule for add match statement. */
1302 cmd
= route_map_lookup_match(match_name
);
1304 return RMAP_RULE_MISSING
;
1306 /* Next call compile function for this match statement. */
1307 if (cmd
->func_compile
) {
1308 compile
= (*cmd
->func_compile
)(match_arg
);
1309 if (compile
== NULL
)
1310 return RMAP_COMPILE_ERROR
;
1313 /* use the compiled results if applicable */
1314 if (compile
&& cmd
->func_get_rmap_rule_key
)
1315 rule_key
= (*cmd
->func_get_rmap_rule_key
)
1318 rule_key
= match_arg
;
1320 /* If argument is completely same ignore it. */
1321 for (rule
= index
->match_list
.head
; rule
; rule
= next
) {
1323 if (rule
->cmd
== cmd
) {
1324 /* If the configured route-map match rule is exactly
1325 * the same as the existing configuration then,
1326 * ignore the duplicate configuration.
1328 if (strcmp(match_arg
, rule
->rule_str
) == 0) {
1330 (*cmd
->func_free
)(compile
);
1332 return RMAP_COMPILE_SUCCESS
;
1335 /* If IPv4 or IPv6 prefix-list match criteria
1336 * has been delete to the route-map index, update
1337 * the route-map's prefix table.
1339 if (IS_RULE_IPv4_PREFIX_LIST(match_name
))
1340 route_map_pfx_tbl_update(
1341 RMAP_EVENT_PLIST_DELETED
, index
, AFI_IP
,
1343 else if (IS_RULE_IPv6_PREFIX_LIST(match_name
))
1344 route_map_pfx_tbl_update(
1345 RMAP_EVENT_PLIST_DELETED
, index
,
1346 AFI_IP6
, rule
->rule_str
);
1348 /* Remove the dependency of the route-map on the rule
1349 * that is being replaced.
1351 if (type
>= RMAP_EVENT_CALL_ADDED
) {
1352 delete_rmap_event_type
=
1353 get_route_map_delete_event(type
);
1354 route_map_upd8_dependency(
1355 delete_rmap_event_type
,
1360 route_map_rule_delete(&index
->match_list
, rule
);
1364 /* Add new route map match rule. */
1365 rule
= route_map_rule_new();
1367 rule
->value
= compile
;
1369 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, match_arg
);
1371 rule
->rule_str
= NULL
;
1373 /* Add new route match rule to linked list. */
1374 route_map_rule_add(&index
->match_list
, rule
);
1376 /* If IPv4 or IPv6 prefix-list match criteria
1377 * has been added to the route-map index, update
1378 * the route-map's prefix table.
1380 if (IS_RULE_IPv4_PREFIX_LIST(match_name
)) {
1381 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_ADDED
, index
, AFI_IP
,
1383 } else if (IS_RULE_IPv6_PREFIX_LIST(match_name
)) {
1384 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_ADDED
, index
, AFI_IP6
,
1388 /* Execute event hook. */
1389 if (route_map_master
.event_hook
) {
1390 (*route_map_master
.event_hook
)(index
->map
->name
);
1391 route_map_notify_dependencies(index
->map
->name
,
1392 RMAP_EVENT_CALL_ADDED
);
1394 if (type
!= RMAP_EVENT_MATCH_ADDED
)
1395 route_map_upd8_dependency(type
, rule_key
, index
->map
->name
);
1397 return RMAP_COMPILE_SUCCESS
;
1400 /* Delete specified route match rule. */
1401 enum rmap_compile_rets
route_map_delete_match(struct route_map_index
*index
,
1402 const char *match_name
,
1403 const char *match_arg
,
1404 route_map_event_t type
)
1406 struct route_map_rule
*rule
;
1407 const struct route_map_rule_cmd
*cmd
;
1408 const char *rule_key
;
1410 cmd
= route_map_lookup_match(match_name
);
1412 return RMAP_RULE_MISSING
;
1414 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1415 if (rule
->cmd
== cmd
&& (rulecmp(rule
->rule_str
, match_arg
) == 0
1416 || match_arg
== NULL
)) {
1417 /* Execute event hook. */
1418 if (route_map_master
.event_hook
) {
1419 (*route_map_master
.event_hook
)(index
->map
->name
);
1420 route_map_notify_dependencies(
1422 RMAP_EVENT_CALL_ADDED
);
1424 if (cmd
->func_get_rmap_rule_key
)
1425 rule_key
= (*cmd
->func_get_rmap_rule_key
)
1428 rule_key
= match_arg
;
1430 if (type
!= RMAP_EVENT_MATCH_DELETED
&& rule_key
)
1431 route_map_upd8_dependency(type
, rule_key
,
1434 route_map_rule_delete(&index
->match_list
, rule
);
1436 /* If IPv4 or IPv6 prefix-list match criteria
1437 * has been delete from the route-map index, update
1438 * the route-map's prefix table.
1440 if (IS_RULE_IPv4_PREFIX_LIST(match_name
)) {
1441 route_map_pfx_tbl_update(
1442 RMAP_EVENT_PLIST_DELETED
, index
, AFI_IP
,
1444 } else if (IS_RULE_IPv6_PREFIX_LIST(match_name
)) {
1445 route_map_pfx_tbl_update(
1446 RMAP_EVENT_PLIST_DELETED
, index
,
1447 AFI_IP6
, match_arg
);
1450 return RMAP_COMPILE_SUCCESS
;
1452 /* Can't find matched rule. */
1453 return RMAP_RULE_MISSING
;
1456 /* Add route-map set statement to the route map. */
1457 enum rmap_compile_rets
route_map_add_set(struct route_map_index
*index
,
1458 const char *set_name
,
1459 const char *set_arg
)
1461 struct route_map_rule
*rule
;
1462 struct route_map_rule
*next
;
1463 const struct route_map_rule_cmd
*cmd
;
1466 cmd
= route_map_lookup_set(set_name
);
1468 return RMAP_RULE_MISSING
;
1470 /* Next call compile function for this match statement. */
1471 if (cmd
->func_compile
) {
1472 compile
= (*cmd
->func_compile
)(set_arg
);
1473 if (compile
== NULL
)
1474 return RMAP_COMPILE_ERROR
;
1478 /* Add by WJL. if old set command of same kind exist, delete it first
1479 to ensure only one set command of same kind exist under a
1481 for (rule
= index
->set_list
.head
; rule
; rule
= next
) {
1483 if (rule
->cmd
== cmd
)
1484 route_map_rule_delete(&index
->set_list
, rule
);
1487 /* Add new route map match rule. */
1488 rule
= route_map_rule_new();
1490 rule
->value
= compile
;
1492 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, set_arg
);
1494 rule
->rule_str
= NULL
;
1496 /* Add new route match rule to linked list. */
1497 route_map_rule_add(&index
->set_list
, rule
);
1499 /* Execute event hook. */
1500 if (route_map_master
.event_hook
) {
1501 (*route_map_master
.event_hook
)(index
->map
->name
);
1502 route_map_notify_dependencies(index
->map
->name
,
1503 RMAP_EVENT_CALL_ADDED
);
1505 return RMAP_COMPILE_SUCCESS
;
1508 /* Delete route map set rule. */
1509 enum rmap_compile_rets
route_map_delete_set(struct route_map_index
*index
,
1510 const char *set_name
,
1511 const char *set_arg
)
1513 struct route_map_rule
*rule
;
1514 const struct route_map_rule_cmd
*cmd
;
1516 cmd
= route_map_lookup_set(set_name
);
1518 return RMAP_RULE_MISSING
;
1520 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
1521 if ((rule
->cmd
== cmd
) && (rulecmp(rule
->rule_str
, set_arg
) == 0
1522 || set_arg
== NULL
)) {
1523 route_map_rule_delete(&index
->set_list
, rule
);
1524 /* Execute event hook. */
1525 if (route_map_master
.event_hook
) {
1526 (*route_map_master
.event_hook
)(index
->map
->name
);
1527 route_map_notify_dependencies(
1529 RMAP_EVENT_CALL_ADDED
);
1531 return RMAP_COMPILE_SUCCESS
;
1533 /* Can't find matched rule. */
1534 return RMAP_RULE_MISSING
;
1537 static enum route_map_cmd_result_t
1538 route_map_apply_match(struct route_map_rule_list
*match_list
,
1539 const struct prefix
*prefix
, void *object
)
1541 enum route_map_cmd_result_t ret
= RMAP_NOMATCH
;
1542 struct route_map_rule
*match
;
1543 bool is_matched
= false;
1546 /* Check all match rule and if there is no match rule, go to the
1548 if (!match_list
->head
)
1551 for (match
= match_list
->head
; match
; match
= match
->next
) {
1553 * Try each match statement. If any match does not
1554 * return RMAP_MATCH or RMAP_NOOP, return.
1555 * Otherwise continue on to next match statement.
1556 * All match statements must MATCH for
1557 * end-result to be a match.
1558 * (Exception:If match stmts result in a mix of
1559 * MATCH/NOOP, then also end-result is a match)
1560 * If all result in NOOP, end-result is NOOP.
1562 ret
= (*match
->cmd
->func_apply
)(match
->value
, prefix
,
1566 * If the consolidated result of func_apply is:
1567 * -----------------------------------------------
1568 * | MATCH | NOMATCH | NOOP | Final Result |
1569 * ------------------------------------------------
1570 * | yes | yes | yes | NOMATCH |
1571 * | no | no | yes | NOOP |
1572 * | yes | no | yes | MATCH |
1573 * | no | yes | yes | NOMATCH |
1574 * |-----------------------------------------------
1576 * Traditionally, all rules within route-map
1577 * should match for it to MATCH.
1578 * If there are noops within the route-map rules,
1579 * it follows the above matrix.
1581 * Eg: route-map rm1 permit 10
1586 * route-map rm1 permit 20
1614 static struct list
*route_map_get_index_list(struct route_node
**rn
,
1615 const struct prefix
*prefix
,
1616 struct route_table
*table
)
1618 struct route_node
*tmp_rn
= NULL
;
1621 *rn
= route_node_match(table
, prefix
);
1627 return (struct list
*)((*rn
)->info
);
1629 /* If rn->info is NULL, get the parent.
1630 * Store the rn in tmp_rn and unlock it later.
1636 *rn
= (*rn
)->parent
;
1638 route_unlock_node(tmp_rn
);
1644 route_lock_node(*rn
);
1645 return (struct list
*)((*rn
)->info
);
1647 } while (!(*rn
)->info
);
1653 * This function returns the route-map index that best matches the prefix.
1655 static struct route_map_index
*route_map_get_index(struct route_map
*map
,
1656 const struct prefix
*prefix
,
1661 struct list
*candidate_rmap_list
= NULL
;
1662 struct route_node
*rn
= NULL
;
1663 struct listnode
*ln
= NULL
, *nn
= NULL
;
1664 struct route_map_index
*index
= NULL
, *best_index
= NULL
;
1665 struct route_map_index
*head_index
= NULL
;
1666 struct route_table
*table
= NULL
;
1667 unsigned char family
= prefix
->family
;
1669 if (family
== AF_INET
)
1670 table
= map
->ipv4_prefix_table
;
1672 table
= map
->ipv6_prefix_table
;
1678 candidate_rmap_list
=
1679 route_map_get_index_list(&rn
, prefix
, table
);
1683 /* If the index at the head of the list is of seq higher
1684 * than that in best_index, ignore the list and get the
1685 * parent node's list.
1687 head_index
= (struct route_map_index
*)(listgetdata(
1688 listhead(candidate_rmap_list
)));
1689 if (best_index
&& head_index
1690 && (best_index
->pref
< head_index
->pref
)) {
1691 route_unlock_node(rn
);
1695 for (ALL_LIST_ELEMENTS(candidate_rmap_list
, ln
, nn
, index
)) {
1696 /* If the index is of seq higher than that in
1697 * best_index, ignore the list and get the parent
1700 if (best_index
&& (best_index
->pref
< index
->pref
))
1703 ret
= route_map_apply_match(&index
->match_list
, prefix
,
1706 if (ret
== RMAP_MATCH
) {
1710 } else if (ret
== RMAP_NOOP
) {
1712 * If match_ret is denymatch, even if we see
1713 * more noops, we retain this return value and
1714 * return this eventually if there are no
1716 * If a best match route-map index already
1717 * exists, do not reset the match_ret.
1719 if (!best_index
&& (*match_ret
!= RMAP_NOMATCH
))
1723 * ret is RMAP_NOMATCH.
1724 * If a best match route-map index already
1725 * exists, do not reset the match_ret.
1732 route_unlock_node(rn
);
1739 static int route_map_candidate_list_cmp(struct route_map_index
*idx1
,
1740 struct route_map_index
*idx2
)
1747 return (idx1
->pref
- idx2
->pref
);
1751 * This function adds the route-map index into the default route's
1752 * route-node in the route-map's IPv4/IPv6 prefix-table.
1754 static void route_map_pfx_table_add_default(afi_t afi
,
1755 struct route_map_index
*index
)
1757 struct route_node
*rn
= NULL
;
1758 struct list
*rmap_candidate_list
= NULL
;
1760 bool updated_rn
= false;
1761 struct route_table
*table
= NULL
;
1763 memset(&p
, 0, sizeof(p
));
1764 p
.family
= afi2family(afi
);
1767 if (p
.family
== AF_INET
) {
1768 table
= index
->map
->ipv4_prefix_table
;
1770 index
->map
->ipv4_prefix_table
= route_table_init();
1772 table
= index
->map
->ipv4_prefix_table
;
1774 table
= index
->map
->ipv6_prefix_table
;
1776 index
->map
->ipv6_prefix_table
= route_table_init();
1778 table
= index
->map
->ipv6_prefix_table
;
1781 /* Add default route to table */
1782 rn
= route_node_get(table
, &p
);
1788 rmap_candidate_list
= list_new();
1789 rmap_candidate_list
->cmp
=
1790 (int (*)(void *, void *))route_map_candidate_list_cmp
;
1791 rn
->info
= rmap_candidate_list
;
1793 rmap_candidate_list
= (struct list
*)rn
->info
;
1797 listnode_add_sort_nodup(rmap_candidate_list
, index
);
1799 route_unlock_node(rn
);
1803 * This function removes the route-map index from the default route's
1804 * route-node in the route-map's IPv4/IPv6 prefix-table.
1806 static void route_map_pfx_table_del_default(afi_t afi
,
1807 struct route_map_index
*index
)
1809 struct route_node
*rn
= NULL
;
1810 struct list
*rmap_candidate_list
= NULL
;
1812 struct route_table
*table
= NULL
;
1814 memset(&p
, 0, sizeof(p
));
1815 p
.family
= afi2family(afi
);
1818 if (p
.family
== AF_INET
)
1819 table
= index
->map
->ipv4_prefix_table
;
1821 table
= index
->map
->ipv6_prefix_table
;
1823 /* Remove RMAP index from default route in table */
1824 rn
= route_node_lookup(table
, &p
);
1825 if (!rn
|| !rn
->info
)
1828 rmap_candidate_list
= (struct list
*)rn
->info
;
1830 listnode_delete(rmap_candidate_list
, index
);
1832 if (listcount(rmap_candidate_list
) == 0) {
1833 list_delete(&rmap_candidate_list
);
1835 route_unlock_node(rn
);
1837 route_unlock_node(rn
);
1841 * This function adds the route-map index to the route-node for
1842 * the prefix-entry in the route-map's IPv4/IPv6 prefix-table.
1844 static void route_map_pfx_table_add(struct route_table
*table
,
1845 struct route_map_index
*index
,
1846 struct prefix_list_entry
*pentry
)
1848 struct route_node
*rn
= NULL
;
1849 struct list
*rmap_candidate_list
= NULL
;
1850 bool updated_rn
= false;
1852 rn
= route_node_get(table
, &pentry
->prefix
);
1857 rmap_candidate_list
= list_new();
1858 rmap_candidate_list
->cmp
=
1859 (int (*)(void *, void *))route_map_candidate_list_cmp
;
1860 rn
->info
= rmap_candidate_list
;
1862 rmap_candidate_list
= (struct list
*)rn
->info
;
1866 listnode_add_sort_nodup(rmap_candidate_list
, index
);
1868 route_unlock_node(rn
);
1872 * This function removes the route-map index from the route-node for
1873 * the prefix-entry in the route-map's IPv4/IPv6 prefix-table.
1875 static void route_map_pfx_table_del(struct route_table
*table
,
1876 struct route_map_index
*index
,
1877 struct prefix_list_entry
*pentry
)
1879 struct route_node
*rn
= NULL
;
1880 struct list
*rmap_candidate_list
= NULL
;
1882 rn
= route_node_lookup(table
, &pentry
->prefix
);
1883 if (!rn
|| !rn
->info
)
1886 rmap_candidate_list
= (struct list
*)rn
->info
;
1888 listnode_delete(rmap_candidate_list
, index
);
1890 if (listcount(rmap_candidate_list
) == 0) {
1891 list_delete(&rmap_candidate_list
);
1893 route_unlock_node(rn
);
1895 route_unlock_node(rn
);
1898 /* This function checks for the presence of an IPv4 prefix-list
1899 * match rule in the given route-map index.
1901 static bool route_map_is_ip_pfx_list_rule_present(struct route_map_index
*index
)
1903 struct route_map_rule_list
*match_list
= NULL
;
1904 struct route_map_rule
*rule
= NULL
;
1906 match_list
= &index
->match_list
;
1907 for (rule
= match_list
->head
; rule
; rule
= rule
->next
)
1908 if (IS_RULE_IPv4_PREFIX_LIST(rule
->cmd
->str
))
1914 /* This function checks for the presence of an IPv6 prefix-list
1915 * match rule in the given route-map index.
1918 route_map_is_ipv6_pfx_list_rule_present(struct route_map_index
*index
)
1920 struct route_map_rule_list
*match_list
= NULL
;
1921 struct route_map_rule
*rule
= NULL
;
1923 match_list
= &index
->match_list
;
1924 for (rule
= match_list
->head
; rule
; rule
= rule
->next
)
1925 if (IS_RULE_IPv6_PREFIX_LIST(rule
->cmd
->str
))
1931 /* This function does the following:
1932 * 1) If plist_name is not present, search for a IPv4 or IPv6 prefix-list
1933 * match clause (based on the afi passed to this foo) and get the
1935 * 2) Look up the prefix-list using the name.
1936 * 3) If the prefix-list is not found then, add the index to the IPv4/IPv6
1937 * default-route's node in the trie (based on the afi passed to this foo).
1938 * 4) If the prefix-list is found then, remove the index from the IPv4/IPv6
1939 * default-route's node in the trie (based on the afi passed to this foo).
1940 * 5) If a prefix-entry is passed then, create a route-node for this entry and
1941 * add this index to the route-node.
1942 * 6) If prefix-entry is not passed then, for every prefix-entry in the
1943 * prefix-list, create a route-node for this entry and
1944 * add this index to the route-node.
1946 static void route_map_add_plist_entries(afi_t afi
,
1947 struct route_map_index
*index
,
1948 const char *plist_name
,
1949 struct prefix_list_entry
*entry
)
1951 struct route_map_rule_list
*match_list
= NULL
;
1952 struct route_map_rule
*match
= NULL
;
1953 struct prefix_list
*plist
= NULL
;
1954 struct prefix_list_entry
*pentry
= NULL
;
1955 bool plist_rule_is_present
= false;
1958 match_list
= &index
->match_list
;
1960 for (match
= match_list
->head
; match
; match
= match
->next
) {
1961 if (afi
== AFI_IP
) {
1962 if (IS_RULE_IPv4_PREFIX_LIST(match
->cmd
->str
)) {
1963 plist_rule_is_present
= true;
1967 if (IS_RULE_IPv6_PREFIX_LIST(match
->cmd
->str
)) {
1968 plist_rule_is_present
= true;
1974 if (plist_rule_is_present
)
1975 plist
= prefix_list_lookup(afi
, match
->rule_str
);
1977 plist
= prefix_list_lookup(afi
, plist_name
);
1981 route_map_pfx_table_add_default(afi
, index
);
1985 route_map_pfx_table_del_default(afi
, index
);
1988 if (afi
== AFI_IP
) {
1989 route_map_pfx_table_add(index
->map
->ipv4_prefix_table
,
1992 route_map_pfx_table_add(index
->map
->ipv6_prefix_table
,
1996 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
1997 if (afi
== AFI_IP
) {
1998 route_map_pfx_table_add(
1999 index
->map
->ipv4_prefix_table
, index
,
2002 route_map_pfx_table_add(
2003 index
->map
->ipv6_prefix_table
, index
,
2010 /* This function does the following:
2011 * 1) If plist_name is not present, search for a IPv4 or IPv6 prefix-list
2012 * match clause (based on the afi passed to this foo) and get the
2014 * 2) Look up the prefix-list using the name.
2015 * 3) If the prefix-list is not found then, delete the index from the IPv4/IPv6
2016 * default-route's node in the trie (based on the afi passed to this foo).
2017 * 4) If a prefix-entry is passed then, remove this index from the route-node
2018 * for the prefix in this prefix-entry.
2019 * 5) If prefix-entry is not passed then, for every prefix-entry in the
2020 * prefix-list, remove this index from the route-node
2021 * for the prefix in this prefix-entry.
2023 static void route_map_del_plist_entries(afi_t afi
,
2024 struct route_map_index
*index
,
2025 const char *plist_name
,
2026 struct prefix_list_entry
*entry
)
2028 struct route_map_rule_list
*match_list
= NULL
;
2029 struct route_map_rule
*match
= NULL
;
2030 struct prefix_list
*plist
= NULL
;
2031 struct prefix_list_entry
*pentry
= NULL
;
2032 bool plist_rule_is_present
= false;
2035 match_list
= &index
->match_list
;
2037 for (match
= match_list
->head
; match
; match
= match
->next
) {
2038 if (afi
== AFI_IP
) {
2039 if (IS_RULE_IPv4_PREFIX_LIST(match
->cmd
->str
)) {
2040 plist_rule_is_present
= true;
2044 if (IS_RULE_IPv6_PREFIX_LIST(match
->cmd
->str
)) {
2045 plist_rule_is_present
= true;
2051 if (plist_rule_is_present
)
2052 plist
= prefix_list_lookup(afi
, match
->rule_str
);
2054 plist
= prefix_list_lookup(afi
, plist_name
);
2058 route_map_pfx_table_del_default(afi
, index
);
2063 if (afi
== AFI_IP
) {
2064 route_map_pfx_table_del(index
->map
->ipv4_prefix_table
,
2067 route_map_pfx_table_del(index
->map
->ipv6_prefix_table
,
2071 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
2072 if (afi
== AFI_IP
) {
2073 route_map_pfx_table_del(
2074 index
->map
->ipv4_prefix_table
, index
,
2077 route_map_pfx_table_del(
2078 index
->map
->ipv6_prefix_table
, index
,
2086 * This function handles the cases where a prefix-list is added/removed
2087 * as a match command from a particular route-map index.
2088 * It updates the prefix-table of the route-map accordingly.
2090 static void route_map_trie_update(afi_t afi
, route_map_event_t event
,
2091 struct route_map_index
*index
,
2092 const char *plist_name
)
2094 if (event
== RMAP_EVENT_PLIST_ADDED
) {
2095 if (afi
== AFI_IP
) {
2096 if (!route_map_is_ipv6_pfx_list_rule_present(index
)) {
2097 route_map_pfx_table_del_default(AFI_IP6
, index
);
2098 route_map_add_plist_entries(afi
, index
,
2101 route_map_del_plist_entries(AFI_IP6
, index
,
2105 if (!route_map_is_ip_pfx_list_rule_present(index
)) {
2106 route_map_pfx_table_del_default(AFI_IP
, index
);
2107 route_map_add_plist_entries(afi
, index
,
2110 route_map_del_plist_entries(AFI_IP
, index
, NULL
,
2114 } else if (event
== RMAP_EVENT_PLIST_DELETED
) {
2115 if (afi
== AFI_IP
) {
2116 route_map_del_plist_entries(afi
, index
, plist_name
,
2119 /* If IPv6 prefix-list match rule is not present,
2120 * add this index to the IPv4 default route's trie
2122 * Also, add this index to the trie nodes created
2123 * for each of the prefix-entries within the IPv6
2124 * prefix-list, if the IPv6 prefix-list match rule
2125 * is present. Else, add this index to the IPv6
2126 * default route's trie node.
2128 if (!route_map_is_ipv6_pfx_list_rule_present(index
))
2129 route_map_pfx_table_add_default(afi
, index
);
2131 route_map_add_plist_entries(AFI_IP6
, index
, NULL
, NULL
);
2133 route_map_del_plist_entries(afi
, index
, plist_name
,
2136 /* If IPv4 prefix-list match rule is not present,
2137 * add this index to the IPv6 default route's trie
2139 * Also, add this index to the trie nodes created
2140 * for each of the prefix-entries within the IPv4
2141 * prefix-list, if the IPv4 prefix-list match rule
2142 * is present. Else, add this index to the IPv4
2143 * default route's trie node.
2145 if (!route_map_is_ip_pfx_list_rule_present(index
))
2146 route_map_pfx_table_add_default(afi
, index
);
2148 route_map_add_plist_entries(AFI_IP
, index
, NULL
, NULL
);
2154 * This function handles the cases where a route-map index and
2155 * prefix-list is added/removed.
2156 * It updates the prefix-table of the route-map accordingly.
2158 static void route_map_pfx_tbl_update(route_map_event_t event
,
2159 struct route_map_index
*index
, afi_t afi
,
2160 const char *plist_name
)
2162 struct route_map
*rmap
= NULL
;
2167 if (event
== RMAP_EVENT_INDEX_ADDED
) {
2168 route_map_pfx_table_add_default(AFI_IP
, index
);
2169 route_map_pfx_table_add_default(AFI_IP6
, index
);
2173 if (event
== RMAP_EVENT_INDEX_DELETED
) {
2174 route_map_pfx_table_del_default(AFI_IP
, index
);
2175 route_map_pfx_table_del_default(AFI_IP6
, index
);
2177 if ((index
->map
->head
== NULL
) && (index
->map
->tail
== NULL
)) {
2180 if (rmap
->ipv4_prefix_table
) {
2181 route_table_finish(rmap
->ipv4_prefix_table
);
2182 rmap
->ipv4_prefix_table
= NULL
;
2185 if (rmap
->ipv6_prefix_table
) {
2186 route_table_finish(rmap
->ipv6_prefix_table
);
2187 rmap
->ipv6_prefix_table
= NULL
;
2193 /* Handle prefix-list match rule addition/deletion.
2195 route_map_trie_update(afi
, event
, index
, plist_name
);
2199 * This function handles the cases where a new prefix-entry is added to
2200 * a prefix-list or, an existing prefix-entry is removed from the prefix-list.
2201 * It updates the prefix-table of the route-map accordingly.
2203 static void route_map_pentry_update(route_map_event_t event
,
2204 const char *plist_name
,
2205 struct route_map_index
*index
,
2206 struct prefix_list_entry
*pentry
)
2208 struct prefix_list
*plist
= NULL
;
2210 unsigned char family
= pentry
->prefix
.family
;
2212 if (family
== AF_INET
) {
2214 plist
= prefix_list_lookup(AFI_IP
, plist_name
);
2217 plist
= prefix_list_lookup(AFI_IP6
, plist_name
);
2220 if (event
== RMAP_EVENT_PLIST_ADDED
) {
2221 if (afi
== AFI_IP
) {
2222 if (!route_map_is_ipv6_pfx_list_rule_present(index
))
2223 route_map_add_plist_entries(afi
, index
,
2224 plist_name
, pentry
);
2226 if (!route_map_is_ip_pfx_list_rule_present(index
))
2227 route_map_add_plist_entries(afi
, index
,
2228 plist_name
, pentry
);
2230 } else if (event
== RMAP_EVENT_PLIST_DELETED
) {
2231 route_map_del_plist_entries(afi
, index
, plist_name
, pentry
);
2233 if (plist
->count
== 1) {
2234 if (afi
== AFI_IP
) {
2235 if (!route_map_is_ipv6_pfx_list_rule_present(
2237 route_map_pfx_table_add_default(afi
,
2240 if (!route_map_is_ip_pfx_list_rule_present(
2242 route_map_pfx_table_add_default(afi
,
2249 static void route_map_pentry_process_dependency(struct hash_bucket
*bucket
,
2252 char *rmap_name
= NULL
;
2253 struct route_map
*rmap
= NULL
;
2254 struct route_map_index
*index
= NULL
;
2255 struct route_map_rule_list
*match_list
= NULL
;
2256 struct route_map_rule
*match
= NULL
;
2257 struct route_map_dep_data
*dep_data
= NULL
;
2258 struct route_map_pentry_dep
*pentry_dep
=
2259 (struct route_map_pentry_dep
*)data
;
2260 unsigned char family
= pentry_dep
->pentry
->prefix
.family
;
2262 dep_data
= (struct route_map_dep_data
*)bucket
->data
;
2266 rmap_name
= dep_data
->rname
;
2267 rmap
= route_map_lookup_by_name(rmap_name
);
2268 if (!rmap
|| !rmap
->head
)
2271 for (index
= rmap
->head
; index
; index
= index
->next
) {
2272 match_list
= &index
->match_list
;
2277 for (match
= match_list
->head
; match
; match
= match
->next
) {
2278 if (strcmp(match
->rule_str
, pentry_dep
->plist_name
)
2280 if (IS_RULE_IPv4_PREFIX_LIST(match
->cmd
->str
)
2281 && family
== AF_INET
) {
2282 route_map_pentry_update(
2284 pentry_dep
->plist_name
, index
,
2285 pentry_dep
->pentry
);
2286 } else if (IS_RULE_IPv6_PREFIX_LIST(
2288 && family
== AF_INET6
) {
2289 route_map_pentry_update(
2291 pentry_dep
->plist_name
, index
,
2292 pentry_dep
->pentry
);
2299 void route_map_notify_pentry_dependencies(const char *affected_name
,
2300 struct prefix_list_entry
*pentry
,
2301 route_map_event_t event
)
2303 struct route_map_dep
*dep
= NULL
;
2304 struct hash
*upd8_hash
= NULL
;
2305 struct route_map_pentry_dep pentry_dep
;
2307 if (!affected_name
|| !pentry
)
2310 upd8_hash
= route_map_get_dep_hash(event
);
2314 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, (void *)affected_name
,
2317 if (!dep
->this_hash
)
2318 dep
->this_hash
= upd8_hash
;
2320 memset(&pentry_dep
, 0, sizeof(struct route_map_pentry_dep
));
2321 pentry_dep
.pentry
= pentry
;
2322 pentry_dep
.plist_name
= affected_name
;
2323 pentry_dep
.event
= event
;
2325 hash_iterate(dep
->dep_rmap_hash
,
2326 route_map_pentry_process_dependency
,
2327 (void *)&pentry_dep
);
2331 /* Apply route map's each index to the object.
2333 The matrix for a route-map looks like this:
2334 (note, this includes the description for the "NEXT"
2335 and "GOTO" frobs now
2337 | Match | No Match | No op
2338 |-----------|--------------|-------
2339 permit | action | cont | cont.
2340 | | default:deny | default:permit
2341 -------------------+-----------------------
2342 | deny | cont | cont.
2343 deny | | default:deny | default:permit
2344 |-----------|--------------|--------
2347 -Apply Set statements, accept route
2348 -If Call statement is present jump to the specified route-map, if it
2349 denies the route we finish.
2350 -If NEXT is specified, goto NEXT statement
2351 -If GOTO is specified, goto the first clause where pref > nextpref
2352 -If nothing is specified, do as Cisco and finish
2354 -Route is denied by route-map.
2358 If we get no matches after we've processed all updates, then the route
2361 Some notes on the new "CALL", "NEXT" and "GOTO"
2362 call WORD - If this clause is matched, then the set statements
2363 are executed and then we jump to route-map 'WORD'. If
2364 this route-map denies the route, we finish, in other
2366 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
2367 on-match next - If this clause is matched, then the set statements
2368 are executed and then we drop through to the next clause
2369 on-match goto n - If this clause is matched, then the set statments
2370 are executed and then we goto the nth clause, or the
2371 first clause greater than this. In order to ensure
2372 route-maps *always* exit, you cannot jump backwards.
2375 We need to make sure our route-map processing matches the above
2377 route_map_result_t
route_map_apply(struct route_map
*map
,
2378 const struct prefix
*prefix
, void *object
)
2380 static int recursion
= 0;
2381 enum route_map_cmd_result_t match_ret
= RMAP_NOMATCH
;
2382 route_map_result_t ret
= RMAP_PERMITMATCH
;
2383 struct route_map_index
*index
= NULL
;
2384 struct route_map_rule
*set
= NULL
;
2385 bool skip_match_clause
= false;
2387 if (recursion
> RMAP_RECURSION_LIMIT
) {
2389 EC_LIB_RMAP_RECURSION_LIMIT
,
2390 "route-map recursion limit (%d) reached, discarding route",
2391 RMAP_RECURSION_LIMIT
);
2393 return RMAP_DENYMATCH
;
2396 if (map
== NULL
|| map
->head
== NULL
) {
2397 ret
= RMAP_DENYMATCH
;
2398 goto route_map_apply_end
;
2403 if ((!map
->optimization_disabled
)
2404 && (map
->ipv4_prefix_table
|| map
->ipv6_prefix_table
)) {
2405 index
= route_map_get_index(map
, prefix
, object
,
2406 (uint8_t *)&match_ret
);
2411 "Best match route-map: %s, sequence: %d for pfx: %pFX, result: %s",
2412 map
->name
, index
->pref
, prefix
,
2413 route_map_cmd_result_str(match_ret
));
2417 "No best match sequence for pfx: %pFX in route-map: %s, result: %s",
2419 route_map_cmd_result_str(match_ret
));
2421 * No index matches this prefix. Return deny unless,
2422 * match_ret = RMAP_NOOP.
2424 if (match_ret
== RMAP_NOOP
)
2425 ret
= RMAP_PERMITMATCH
;
2427 ret
= RMAP_DENYMATCH
;
2428 goto route_map_apply_end
;
2430 skip_match_clause
= true;
2435 for (; index
; index
= index
->next
) {
2436 if (!skip_match_clause
) {
2438 /* Apply this index. */
2439 match_ret
= route_map_apply_match(&index
->match_list
,
2443 "Route-map: %s, sequence: %d, prefix: %pFX, result: %s",
2444 map
->name
, index
->pref
, prefix
,
2445 route_map_cmd_result_str(match_ret
));
2448 skip_match_clause
= false;
2451 /* Now we apply the matrix from above */
2452 if (match_ret
== RMAP_NOOP
)
2454 * Do not change the return value. Retain the previous
2455 * return value. Previous values can be:
2456 * 1)permitmatch (if a nomatch was never
2457 * seen before in this route-map.)
2458 * 2)denymatch (if a nomatch was seen earlier in one
2459 * of the previous sequences)
2463 * 'cont' from matrix - continue to next route-map
2467 else if (match_ret
== RMAP_NOMATCH
) {
2470 * The return value is now changed to denymatch.
2471 * So from here on out, even if we see more noops,
2472 * we retain this return value and return this
2473 * eventually if there are no matches.
2475 ret
= RMAP_DENYMATCH
;
2478 * 'cont' from matrix - continue to next route-map
2482 } else if (match_ret
== RMAP_MATCH
) {
2483 if (index
->type
== RMAP_PERMIT
)
2486 /* Match succeeded, rmap is of type permit */
2487 ret
= RMAP_PERMITMATCH
;
2489 /* permit+match must execute sets */
2490 for (set
= index
->set_list
.head
; set
;
2493 * set cmds return RMAP_OKAY or
2494 * RMAP_ERROR. We do not care if
2495 * set succeeded or not. So, ignore
2498 (void)(*set
->cmd
->func_apply
)(
2499 set
->value
, prefix
, object
);
2501 /* Call another route-map if available */
2502 if (index
->nextrm
) {
2503 struct route_map
*nextrm
=
2504 route_map_lookup_by_name(
2507 if (nextrm
) /* Target route-map found,
2511 ret
= route_map_apply(
2512 nextrm
, prefix
, object
);
2516 /* If nextrm returned 'deny', finish. */
2517 if (ret
== RMAP_DENYMATCH
)
2518 goto route_map_apply_end
;
2521 switch (index
->exitpolicy
) {
2523 goto route_map_apply_end
;
2527 /* Find the next clause to jump to */
2528 struct route_map_index
*next
=
2530 int nextpref
= index
->nextpref
;
2532 while (next
&& next
->pref
< nextpref
) {
2537 /* No clauses match! */
2538 goto route_map_apply_end
;
2542 } else if (index
->type
== RMAP_DENY
)
2545 ret
= RMAP_DENYMATCH
;
2546 goto route_map_apply_end
;
2551 route_map_apply_end
:
2553 zlog_debug("Route-map: %s, prefix: %pFX, result: %s",
2554 (map
? map
->name
: "null"), prefix
,
2555 route_map_result_str(ret
));
2560 void route_map_add_hook(void (*func
)(const char *))
2562 route_map_master
.add_hook
= func
;
2565 void route_map_delete_hook(void (*func
)(const char *))
2567 route_map_master
.delete_hook
= func
;
2570 void route_map_event_hook(void (*func
)(const char *name
))
2572 route_map_master
.event_hook
= func
;
2575 /* Routines for route map dependency lists and dependency processing */
2576 static bool route_map_rmap_hash_cmp(const void *p1
, const void *p2
)
2578 return strcmp(((const struct route_map_dep_data
*)p1
)->rname
,
2579 ((const struct route_map_dep_data
*)p2
)->rname
)
2583 static bool route_map_dep_hash_cmp(const void *p1
, const void *p2
)
2586 return (strcmp(((const struct route_map_dep
*)p1
)->dep_name
,
2591 static void route_map_clear_reference(struct hash_bucket
*bucket
, void *arg
)
2593 struct route_map_dep
*dep
= bucket
->data
;
2594 struct route_map_dep_data
*dep_data
= NULL
, tmp_dep_data
;
2596 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
2597 tmp_dep_data
.rname
= arg
;
2598 dep_data
= hash_release(dep
->dep_rmap_hash
, &tmp_dep_data
);
2601 zlog_debug("Clearing reference for %s to %s count: %d",
2602 dep
->dep_name
, tmp_dep_data
.rname
,
2605 XFREE(MTYPE_ROUTE_MAP_NAME
, dep_data
->rname
);
2606 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, dep_data
);
2608 if (!dep
->dep_rmap_hash
->count
) {
2609 dep
= hash_release(dep
->this_hash
, (void *)dep
->dep_name
);
2610 hash_free(dep
->dep_rmap_hash
);
2611 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
2612 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
2616 static void route_map_clear_all_references(char *rmap_name
)
2621 zlog_debug("Clearing references for %s", rmap_name
);
2623 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
2624 hash_iterate(route_map_dep_hash
[i
], route_map_clear_reference
,
2629 static unsigned int route_map_dep_data_hash_make_key(const void *p
)
2631 const struct route_map_dep_data
*dep_data
= p
;
2633 return string_hash_make(dep_data
->rname
);
2636 static void *route_map_dep_hash_alloc(void *p
)
2638 char *dep_name
= (char *)p
;
2639 struct route_map_dep
*dep_entry
;
2641 dep_entry
= XCALLOC(MTYPE_ROUTE_MAP_DEP
, sizeof(struct route_map_dep
));
2642 dep_entry
->dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
2643 dep_entry
->dep_rmap_hash
=
2644 hash_create_size(8, route_map_dep_data_hash_make_key
,
2645 route_map_rmap_hash_cmp
, "Route Map Dep Hash");
2646 dep_entry
->this_hash
= NULL
;
2651 static void *route_map_name_hash_alloc(void *p
)
2653 struct route_map_dep_data
*dep_data
= NULL
, *tmp_dep_data
= NULL
;
2655 dep_data
= XCALLOC(MTYPE_ROUTE_MAP_DEP_DATA
,
2656 sizeof(struct route_map_dep_data
));
2658 dep_data
->rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, tmp_dep_data
->rname
);
2662 static unsigned int route_map_dep_hash_make_key(const void *p
)
2664 return (string_hash_make((char *)p
));
2667 static void route_map_print_dependency(struct hash_bucket
*bucket
, void *data
)
2669 struct route_map_dep_data
*dep_data
= bucket
->data
;
2670 char *rmap_name
= dep_data
->rname
;
2671 char *dep_name
= data
;
2673 zlog_debug("%s: Dependency for %s: %s", __func__
, dep_name
, rmap_name
);
2676 static int route_map_dep_update(struct hash
*dephash
, const char *dep_name
,
2677 const char *rmap_name
, route_map_event_t type
)
2679 struct route_map_dep
*dep
= NULL
;
2680 char *dname
, *rname
;
2682 struct route_map_dep_data
*dep_data
= NULL
, *ret_dep_data
= NULL
;
2683 struct route_map_dep_data tmp_dep_data
;
2685 dname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
2686 rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
2689 case RMAP_EVENT_PLIST_ADDED
:
2690 case RMAP_EVENT_CLIST_ADDED
:
2691 case RMAP_EVENT_ECLIST_ADDED
:
2692 case RMAP_EVENT_ASLIST_ADDED
:
2693 case RMAP_EVENT_LLIST_ADDED
:
2694 case RMAP_EVENT_CALL_ADDED
:
2695 case RMAP_EVENT_FILTER_ADDED
:
2697 zlog_debug("Adding dependency for filter %s in route-map %s",
2698 dep_name
, rmap_name
);
2699 dep
= (struct route_map_dep
*)hash_get(
2700 dephash
, dname
, route_map_dep_hash_alloc
);
2706 if (!dep
->this_hash
)
2707 dep
->this_hash
= dephash
;
2709 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
2710 tmp_dep_data
.rname
= rname
;
2711 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
2713 dep_data
= hash_get(dep
->dep_rmap_hash
, &tmp_dep_data
,
2714 route_map_name_hash_alloc
);
2718 case RMAP_EVENT_PLIST_DELETED
:
2719 case RMAP_EVENT_CLIST_DELETED
:
2720 case RMAP_EVENT_ECLIST_DELETED
:
2721 case RMAP_EVENT_ASLIST_DELETED
:
2722 case RMAP_EVENT_LLIST_DELETED
:
2723 case RMAP_EVENT_CALL_DELETED
:
2724 case RMAP_EVENT_FILTER_DELETED
:
2726 zlog_debug("Deleting dependency for filter %s in route-map %s",
2727 dep_name
, rmap_name
);
2728 dep
= (struct route_map_dep
*)hash_get(dephash
, dname
, NULL
);
2733 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
2734 tmp_dep_data
.rname
= rname
;
2735 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
2737 * If dep_data is NULL then something has gone seriously
2738 * wrong in route-map handling. Note it and prevent
2743 "route-map dependency for route-map %s: %s is not correct",
2744 rmap_name
, dep_name
);
2750 if (!dep_data
->refcnt
) {
2751 ret_dep_data
= hash_release(dep
->dep_rmap_hash
,
2754 XFREE(MTYPE_ROUTE_MAP_NAME
,
2755 ret_dep_data
->rname
);
2756 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, ret_dep_data
);
2760 if (!dep
->dep_rmap_hash
->count
) {
2761 dep
= hash_release(dephash
, dname
);
2762 hash_free(dep
->dep_rmap_hash
);
2763 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
2764 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
2767 case RMAP_EVENT_SET_ADDED
:
2768 case RMAP_EVENT_SET_DELETED
:
2769 case RMAP_EVENT_SET_REPLACED
:
2770 case RMAP_EVENT_MATCH_ADDED
:
2771 case RMAP_EVENT_MATCH_DELETED
:
2772 case RMAP_EVENT_MATCH_REPLACED
:
2773 case RMAP_EVENT_INDEX_ADDED
:
2774 case RMAP_EVENT_INDEX_DELETED
:
2780 hash_iterate(dep
->dep_rmap_hash
,
2781 route_map_print_dependency
, dname
);
2785 XFREE(MTYPE_ROUTE_MAP_NAME
, rname
);
2786 XFREE(MTYPE_ROUTE_MAP_NAME
, dname
);
2790 static struct hash
*route_map_get_dep_hash(route_map_event_t event
)
2792 struct hash
*upd8_hash
= NULL
;
2795 case RMAP_EVENT_PLIST_ADDED
:
2796 case RMAP_EVENT_PLIST_DELETED
:
2797 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_PLIST
];
2799 case RMAP_EVENT_CLIST_ADDED
:
2800 case RMAP_EVENT_CLIST_DELETED
:
2801 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_CLIST
];
2803 case RMAP_EVENT_ECLIST_ADDED
:
2804 case RMAP_EVENT_ECLIST_DELETED
:
2805 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ECLIST
];
2807 case RMAP_EVENT_ASLIST_ADDED
:
2808 case RMAP_EVENT_ASLIST_DELETED
:
2809 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ASPATH
];
2811 case RMAP_EVENT_LLIST_ADDED
:
2812 case RMAP_EVENT_LLIST_DELETED
:
2813 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_LCLIST
];
2815 case RMAP_EVENT_CALL_ADDED
:
2816 case RMAP_EVENT_CALL_DELETED
:
2817 case RMAP_EVENT_MATCH_ADDED
:
2818 case RMAP_EVENT_MATCH_DELETED
:
2819 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_RMAP
];
2821 case RMAP_EVENT_FILTER_ADDED
:
2822 case RMAP_EVENT_FILTER_DELETED
:
2823 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_FILTER
];
2826 * Should we actually be ignoring these?
2827 * I am not sure but at this point in time, let
2828 * us get them into this switch and we can peel
2829 * them into the appropriate place in the future
2831 case RMAP_EVENT_SET_ADDED
:
2832 case RMAP_EVENT_SET_DELETED
:
2833 case RMAP_EVENT_SET_REPLACED
:
2834 case RMAP_EVENT_MATCH_REPLACED
:
2835 case RMAP_EVENT_INDEX_ADDED
:
2836 case RMAP_EVENT_INDEX_DELETED
:
2843 static void route_map_process_dependency(struct hash_bucket
*bucket
, void *data
)
2845 struct route_map_dep_data
*dep_data
= NULL
;
2846 char *rmap_name
= NULL
;
2848 dep_data
= bucket
->data
;
2849 rmap_name
= dep_data
->rname
;
2852 zlog_debug("Notifying %s of dependency", rmap_name
);
2853 if (route_map_master
.event_hook
)
2854 (*route_map_master
.event_hook
)(rmap_name
);
2857 void route_map_upd8_dependency(route_map_event_t type
, const char *arg
,
2858 const char *rmap_name
)
2860 struct hash
*upd8_hash
= NULL
;
2862 if ((upd8_hash
= route_map_get_dep_hash(type
))) {
2863 route_map_dep_update(upd8_hash
, arg
, rmap_name
, type
);
2865 if (type
== RMAP_EVENT_CALL_ADDED
) {
2867 if (route_map_master
.add_hook
)
2868 (*route_map_master
.add_hook
)(rmap_name
);
2869 } else if (type
== RMAP_EVENT_CALL_DELETED
) {
2871 if (route_map_master
.delete_hook
)
2872 (*route_map_master
.delete_hook
)(rmap_name
);
2877 void route_map_notify_dependencies(const char *affected_name
,
2878 route_map_event_t event
)
2880 struct route_map_dep
*dep
;
2881 struct hash
*upd8_hash
;
2887 name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, affected_name
);
2889 if ((upd8_hash
= route_map_get_dep_hash(event
)) == NULL
) {
2890 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
2894 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, name
, NULL
);
2896 if (!dep
->this_hash
)
2897 dep
->this_hash
= upd8_hash
;
2900 zlog_debug("Filter %s updated", dep
->dep_name
);
2901 hash_iterate(dep
->dep_rmap_hash
, route_map_process_dependency
,
2905 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
2908 /* VTY related functions. */
2909 static void clear_route_map_helper(struct route_map
*map
)
2911 struct route_map_index
*index
;
2913 map
->applied_clear
= map
->applied
;
2914 for (index
= map
->head
; index
; index
= index
->next
)
2915 index
->applied_clear
= index
->applied
;
2918 DEFUN (rmap_clear_counters
,
2919 rmap_clear_counters_cmd
,
2920 "clear route-map counters [WORD]",
2922 "route-map information\n"
2923 "counters associated with the specified route-map\n"
2927 struct route_map
*map
;
2929 const char *name
= (argc
== 3 ) ? argv
[idx_word
]->arg
: NULL
;
2932 map
= route_map_lookup_by_name(name
);
2935 clear_route_map_helper(map
);
2937 vty_out(vty
, "%s: 'route-map %s' not found\n",
2938 frr_protonameinst
, name
);
2942 for (map
= route_map_master
.head
; map
; map
= map
->next
)
2943 clear_route_map_helper(map
);
2950 DEFUN (rmap_show_name
,
2952 "show route-map [WORD]",
2954 "route-map information\n"
2958 const char *name
= (argc
== 3) ? argv
[idx_word
]->arg
: NULL
;
2959 return vty_show_route_map(vty
, name
);
2962 DEFUN (rmap_show_unused
,
2963 rmap_show_unused_cmd
,
2964 "show route-map-unused",
2966 "unused route-map information\n")
2968 return vty_show_unused_route_map(vty
);
2975 "Debug option set for route-maps\n")
2981 DEFUN (no_debug_rmap
,
2983 "no debug route-map",
2986 "Debug option set for route-maps\n")
2993 static int rmap_config_write_debug(struct vty
*vty
);
2994 static struct cmd_node rmap_debug_node
= {
2995 .name
= "route-map debug",
2996 .node
= RMAP_DEBUG_NODE
,
2998 .config_write
= rmap_config_write_debug
,
3001 /* Configuration write function. */
3002 static int rmap_config_write_debug(struct vty
*vty
)
3007 vty_out(vty
, "debug route-map\n");
3014 /* Common route map rules */
3016 void *route_map_rule_tag_compile(const char *arg
)
3018 unsigned long int tmp
;
3023 tmp
= strtoul(arg
, &endptr
, 0);
3024 if (arg
[0] == '\0' || *endptr
!= '\0' || errno
|| tmp
> ROUTE_TAG_MAX
)
3027 tag
= XMALLOC(MTYPE_ROUTE_MAP_COMPILED
, sizeof(*tag
));
3033 void route_map_rule_tag_free(void *rule
)
3035 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
3038 void route_map_finish(void)
3042 vector_free(route_match_vec
);
3043 route_match_vec
= NULL
;
3044 vector_free(route_set_vec
);
3045 route_set_vec
= NULL
;
3048 * All protocols are setting these to NULL
3049 * by default on shutdown( route_map_finish )
3050 * Why are we making them do this work?
3052 route_map_master
.add_hook
= NULL
;
3053 route_map_master
.delete_hook
= NULL
;
3054 route_map_master
.event_hook
= NULL
;
3056 /* cleanup route_map */
3057 while (route_map_master
.head
) {
3058 struct route_map
*map
= route_map_master
.head
;
3059 map
->to_be_processed
= false;
3060 route_map_delete(map
);
3063 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
3064 hash_free(route_map_dep_hash
[i
]);
3065 route_map_dep_hash
[i
] = NULL
;
3068 hash_free(route_map_master_hash
);
3069 route_map_master_hash
= NULL
;
3072 /* Increment the use_count counter while attaching the route map */
3073 void route_map_counter_increment(struct route_map
*map
)
3079 /* Decrement the use_count counter while detaching the route map. */
3080 void route_map_counter_decrement(struct route_map
*map
)
3083 if (map
->use_count
<= 0)
3089 DEFUN_HIDDEN(show_route_map_pfx_tbl
, show_route_map_pfx_tbl_cmd
,
3090 "show route-map WORD prefix-table",
3094 "internal prefix-table\n")
3096 const char *rmap_name
= argv
[2]->arg
;
3097 struct route_map
*rmap
= NULL
;
3098 struct route_table
*rm_pfx_tbl4
= NULL
;
3099 struct route_table
*rm_pfx_tbl6
= NULL
;
3100 struct route_node
*rn
= NULL
, *prn
= NULL
;
3101 struct list
*rmap_index_list
= NULL
;
3102 struct listnode
*ln
= NULL
, *nln
= NULL
;
3103 struct route_map_index
*index
= NULL
;
3106 vty_out(vty
, "%s:\n", frr_protonameinst
);
3107 rmap
= route_map_lookup_by_name(rmap_name
);
3109 rm_pfx_tbl4
= rmap
->ipv4_prefix_table
;
3111 vty_out(vty
, "\n%s%43s%s\n", "IPv4 Prefix", "",
3112 "Route-map Index List");
3113 vty_out(vty
, "%s%39s%s\n", "_______________", "",
3114 "____________________");
3115 for (rn
= route_top(rm_pfx_tbl4
); rn
;
3116 rn
= route_next(rn
)) {
3117 vty_out(vty
, " %pRN (%d)\n", rn
,
3118 route_node_get_lock_count(rn
));
3120 vty_out(vty
, "(P) ");
3123 vty_out(vty
, "%pRN\n", prn
);
3127 rmap_index_list
= (struct list
*)rn
->info
;
3128 if (!rmap_index_list
3129 || !listcount(rmap_index_list
))
3130 vty_out(vty
, "%*s%s\n", len
, "", "-");
3132 for (ALL_LIST_ELEMENTS(rmap_index_list
,
3135 vty_out(vty
, "%*s%s seq %d\n",
3144 rm_pfx_tbl6
= rmap
->ipv6_prefix_table
;
3146 vty_out(vty
, "\n%s%43s%s\n", "IPv6 Prefix", "",
3147 "Route-map Index List");
3148 vty_out(vty
, "%s%39s%s\n", "_______________", "",
3149 "____________________");
3150 for (rn
= route_top(rm_pfx_tbl6
); rn
;
3151 rn
= route_next(rn
)) {
3152 vty_out(vty
, " %pRN (%d)\n", rn
,
3153 route_node_get_lock_count(rn
));
3155 vty_out(vty
, "(P) ");
3158 vty_out(vty
, "%pRN\n", prn
);
3162 rmap_index_list
= (struct list
*)rn
->info
;
3163 if (!rmap_index_list
3164 || !listcount(rmap_index_list
))
3165 vty_out(vty
, "%*s%s\n", len
, "", "-");
3167 for (ALL_LIST_ELEMENTS(rmap_index_list
,
3170 vty_out(vty
, "%*s%s seq %d\n",
3184 /* Initialization of route map vector. */
3185 void route_map_init(void)
3189 /* Make vector for match and set. */
3190 route_match_vec
= vector_init(1);
3191 route_set_vec
= vector_init(1);
3192 route_map_master_hash
=
3193 hash_create_size(8, route_map_hash_key_make
, route_map_hash_cmp
,
3194 "Route Map Master Hash");
3196 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++)
3197 route_map_dep_hash
[i
] = hash_create_size(
3198 8, route_map_dep_hash_make_key
, route_map_dep_hash_cmp
,
3199 "Route Map Dep Hash");
3203 route_map_cli_init();
3205 /* Install route map top node. */
3206 install_node(&rmap_debug_node
);
3208 /* Install route map commands. */
3209 install_element(CONFIG_NODE
, &debug_rmap_cmd
);
3210 install_element(CONFIG_NODE
, &no_debug_rmap_cmd
);
3212 /* Install show command */
3213 install_element(ENABLE_NODE
, &rmap_clear_counters_cmd
);
3215 install_element(ENABLE_NODE
, &rmap_show_name_cmd
);
3216 install_element(ENABLE_NODE
, &rmap_show_unused_cmd
);
3218 install_element(ENABLE_NODE
, &debug_rmap_cmd
);
3219 install_element(ENABLE_NODE
, &no_debug_rmap_cmd
);
3221 install_element(ENABLE_NODE
, &show_route_map_pfx_tbl_cmd
);