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 vty
*vty
, struct route_map_index
*index
, const char *command
,
91 const char *arg
, route_map_event_t type
))
93 rmap_match_set_hook
.match_interface
= func
;
96 /* no match interface */
97 void route_map_no_match_interface_hook(int (*func
)(
98 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
99 const char *arg
, route_map_event_t type
))
101 rmap_match_set_hook
.no_match_interface
= func
;
104 /* match ip address */
105 void route_map_match_ip_address_hook(int (*func
)(
106 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
107 const char *arg
, route_map_event_t type
))
109 rmap_match_set_hook
.match_ip_address
= func
;
112 /* no match ip address */
113 void route_map_no_match_ip_address_hook(int (*func
)(
114 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
115 const char *arg
, route_map_event_t type
))
117 rmap_match_set_hook
.no_match_ip_address
= func
;
120 /* match ip address prefix list */
121 void route_map_match_ip_address_prefix_list_hook(int (*func
)(
122 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
123 const char *arg
, route_map_event_t type
))
125 rmap_match_set_hook
.match_ip_address_prefix_list
= func
;
128 /* no match ip address prefix list */
129 void route_map_no_match_ip_address_prefix_list_hook(int (*func
)(
130 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
131 const char *arg
, route_map_event_t type
))
133 rmap_match_set_hook
.no_match_ip_address_prefix_list
= func
;
136 /* match ip next hop */
137 void route_map_match_ip_next_hop_hook(int (*func
)(
138 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
139 const char *arg
, route_map_event_t type
))
141 rmap_match_set_hook
.match_ip_next_hop
= func
;
144 /* no match ip next hop */
145 void route_map_no_match_ip_next_hop_hook(int (*func
)(
146 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
147 const char *arg
, route_map_event_t type
))
149 rmap_match_set_hook
.no_match_ip_next_hop
= func
;
152 /* match ip next hop prefix list */
153 void route_map_match_ip_next_hop_prefix_list_hook(int (*func
)(
154 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
155 const char *arg
, route_map_event_t type
))
157 rmap_match_set_hook
.match_ip_next_hop_prefix_list
= func
;
160 /* no match ip next hop prefix list */
161 void route_map_no_match_ip_next_hop_prefix_list_hook(int (*func
)(
162 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
163 const char *arg
, route_map_event_t type
))
165 rmap_match_set_hook
.no_match_ip_next_hop_prefix_list
= func
;
168 /* match ip next-hop type */
169 void route_map_match_ip_next_hop_type_hook(int (*func
)(
170 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
171 const char *arg
, route_map_event_t type
))
173 rmap_match_set_hook
.match_ip_next_hop_type
= func
;
176 /* no match ip next-hop type */
177 void route_map_no_match_ip_next_hop_type_hook(int (*func
)(
178 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
179 const char *arg
, route_map_event_t type
))
181 rmap_match_set_hook
.no_match_ip_next_hop_type
= func
;
184 /* match ipv6 address */
185 void route_map_match_ipv6_address_hook(int (*func
)(
186 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
187 const char *arg
, route_map_event_t type
))
189 rmap_match_set_hook
.match_ipv6_address
= func
;
192 /* no match ipv6 address */
193 void route_map_no_match_ipv6_address_hook(int (*func
)(
194 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
195 const char *arg
, route_map_event_t type
))
197 rmap_match_set_hook
.no_match_ipv6_address
= func
;
201 /* match ipv6 address prefix list */
202 void route_map_match_ipv6_address_prefix_list_hook(int (*func
)(
203 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
204 const char *arg
, route_map_event_t type
))
206 rmap_match_set_hook
.match_ipv6_address_prefix_list
= func
;
209 /* no match ipv6 address prefix list */
210 void route_map_no_match_ipv6_address_prefix_list_hook(int (*func
)(
211 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
212 const char *arg
, route_map_event_t type
))
214 rmap_match_set_hook
.no_match_ipv6_address_prefix_list
= func
;
217 /* match ipv6 next-hop type */
218 void route_map_match_ipv6_next_hop_type_hook(int (*func
)(
219 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
220 const char *arg
, route_map_event_t type
))
222 rmap_match_set_hook
.match_ipv6_next_hop_type
= func
;
225 /* no match ipv6 next-hop type */
226 void route_map_no_match_ipv6_next_hop_type_hook(int (*func
)(
227 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
228 const char *arg
, route_map_event_t type
))
230 rmap_match_set_hook
.no_match_ipv6_next_hop_type
= func
;
234 void route_map_match_metric_hook(int (*func
)(
235 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
236 const char *arg
, route_map_event_t type
))
238 rmap_match_set_hook
.match_metric
= func
;
241 /* no match metric */
242 void route_map_no_match_metric_hook(int (*func
)(
243 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
244 const char *arg
, route_map_event_t type
))
246 rmap_match_set_hook
.no_match_metric
= func
;
250 void route_map_match_tag_hook(int (*func
)(struct vty
*vty
,
251 struct route_map_index
*index
,
252 const char *command
, const char *arg
,
253 route_map_event_t type
))
255 rmap_match_set_hook
.match_tag
= func
;
259 void route_map_no_match_tag_hook(int (*func
)(
260 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
261 const char *arg
, route_map_event_t type
))
263 rmap_match_set_hook
.no_match_tag
= func
;
266 /* set sr-te color */
267 void route_map_set_srte_color_hook(int (*func
)(struct vty
*vty
,
268 struct route_map_index
*index
,
272 rmap_match_set_hook
.set_srte_color
= func
;
275 /* no set sr-te color */
276 void route_map_no_set_srte_color_hook(int (*func
)(struct vty
*vty
,
277 struct route_map_index
*index
,
281 rmap_match_set_hook
.no_set_srte_color
= func
;
285 void route_map_set_ip_nexthop_hook(int (*func
)(struct vty
*vty
,
286 struct route_map_index
*index
,
290 rmap_match_set_hook
.set_ip_nexthop
= func
;
293 /* no set ip nexthop */
294 void route_map_no_set_ip_nexthop_hook(int (*func
)(struct vty
*vty
,
295 struct route_map_index
*index
,
299 rmap_match_set_hook
.no_set_ip_nexthop
= func
;
302 /* set ipv6 nexthop local */
303 void route_map_set_ipv6_nexthop_local_hook(
304 int (*func
)(struct vty
*vty
, struct route_map_index
*index
,
305 const char *command
, const char *arg
))
307 rmap_match_set_hook
.set_ipv6_nexthop_local
= func
;
310 /* no set ipv6 nexthop local */
311 void route_map_no_set_ipv6_nexthop_local_hook(
312 int (*func
)(struct vty
*vty
, struct route_map_index
*index
,
313 const char *command
, const char *arg
))
315 rmap_match_set_hook
.no_set_ipv6_nexthop_local
= func
;
319 void route_map_set_metric_hook(int (*func
)(struct vty
*vty
,
320 struct route_map_index
*index
,
324 rmap_match_set_hook
.set_metric
= func
;
328 void route_map_no_set_metric_hook(int (*func
)(struct vty
*vty
,
329 struct route_map_index
*index
,
333 rmap_match_set_hook
.no_set_metric
= func
;
337 void route_map_set_tag_hook(int (*func
)(struct vty
*vty
,
338 struct route_map_index
*index
,
339 const char *command
, const char *arg
))
341 rmap_match_set_hook
.set_tag
= func
;
345 void route_map_no_set_tag_hook(int (*func
)(struct vty
*vty
,
346 struct route_map_index
*index
,
350 rmap_match_set_hook
.no_set_tag
= func
;
353 int generic_match_add(struct vty
*vty
, struct route_map_index
*index
,
354 const char *command
, const char *arg
,
355 route_map_event_t type
)
357 enum rmap_compile_rets ret
;
359 ret
= route_map_add_match(index
, command
, arg
, type
);
361 case RMAP_RULE_MISSING
:
363 vty_out(vty
, "%% [%s] Can't find rule.\n",
366 zlog_warn("Can't find rule: %s", command
);
367 return CMD_WARNING_CONFIG_FAILED
;
368 case RMAP_COMPILE_ERROR
:
371 "%% [%s] Argument form is unsupported or malformed.\n",
374 zlog_warn("Argument form is unsupported or malformed: %s %s", command
, arg
);
375 return CMD_WARNING_CONFIG_FAILED
;
376 case RMAP_COMPILE_SUCCESS
:
378 * Nothing to do here move along
386 int generic_match_delete(struct vty
*vty
, struct route_map_index
*index
,
387 const char *command
, const char *arg
,
388 route_map_event_t type
)
390 enum rmap_compile_rets ret
;
391 int retval
= CMD_SUCCESS
;
392 char *dep_name
= NULL
;
394 char *rmap_name
= NULL
;
396 if (type
!= RMAP_EVENT_MATCH_DELETED
) {
397 /* ignore the mundane, the types without any dependency */
399 if ((tmpstr
= route_map_get_match_arg(index
, command
))
402 XSTRDUP(MTYPE_ROUTE_MAP_RULE
, tmpstr
);
404 dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_RULE
, arg
);
406 rmap_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, index
->map
->name
);
409 ret
= route_map_delete_match(index
, command
, dep_name
, type
);
411 case RMAP_RULE_MISSING
:
413 vty_out(vty
, "%% [%s] Can't find rule.\n",
416 zlog_warn("Can't find rule: %s", command
);
417 retval
= CMD_WARNING_CONFIG_FAILED
;
419 case RMAP_COMPILE_ERROR
:
422 "%% [%s] Argument form is unsupported or malformed.\n",
425 zlog_warn("Argument form is unsupported or malformed: %s %s", command
, arg
);
426 retval
= CMD_WARNING_CONFIG_FAILED
;
428 case RMAP_COMPILE_SUCCESS
:
435 XFREE(MTYPE_ROUTE_MAP_RULE
, dep_name
);
436 XFREE(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
441 int generic_set_add(struct vty
*vty
, struct route_map_index
*index
,
442 const char *command
, const char *arg
)
444 enum rmap_compile_rets ret
;
446 ret
= route_map_add_set(index
, command
, arg
);
448 case RMAP_RULE_MISSING
:
450 vty_out(vty
, "%% [%s] Can't find rule.\n", frr_protonameinst
);
452 zlog_warn("Can't find rule: %s", command
);
453 return CMD_WARNING_CONFIG_FAILED
;
454 case RMAP_COMPILE_ERROR
:
457 "%% [%s] Argument form is unsupported or malformed.\n",
460 zlog_warn("Argument form is unsupported or malformed: %s %s", command
, arg
);
461 return CMD_WARNING_CONFIG_FAILED
;
462 case RMAP_COMPILE_SUCCESS
:
469 int generic_set_delete(struct vty
*vty
, struct route_map_index
*index
,
470 const char *command
, const char *arg
)
472 enum rmap_compile_rets ret
;
474 ret
= route_map_delete_set(index
, command
, arg
);
476 case RMAP_RULE_MISSING
:
478 vty_out(vty
, "%% [%s] Can't find rule.\n", frr_protonameinst
);
480 zlog_warn("Can't find rule: %s", command
);
481 return CMD_WARNING_CONFIG_FAILED
;
482 case RMAP_COMPILE_ERROR
:
485 "%% [%s] Argument form is unsupported or malformed.\n",
488 zlog_warn("Argument form is unsupported or malformed: %s %s", command
, arg
);
489 return CMD_WARNING_CONFIG_FAILED
;
490 case RMAP_COMPILE_SUCCESS
:
498 /* Master list of route map. */
499 struct route_map_list route_map_master
= {NULL
, NULL
, NULL
, NULL
, NULL
};
500 struct hash
*route_map_master_hash
= NULL
;
502 static unsigned int route_map_hash_key_make(const void *p
)
504 const struct route_map
*map
= p
;
505 return string_hash_make(map
->name
);
508 static bool route_map_hash_cmp(const void *p1
, const void *p2
)
510 const struct route_map
*map1
= p1
;
511 const struct route_map
*map2
= p2
;
513 if (map1
->deleted
== map2
->deleted
) {
514 if (map1
->name
&& map2
->name
) {
515 if (!strcmp(map1
->name
, map2
->name
)) {
518 } else if (!map1
->name
&& !map2
->name
) {
526 enum route_map_upd8_type
{
531 /* all possible route-map dependency types */
532 enum route_map_dep_type
{
533 ROUTE_MAP_DEP_RMAP
= 1,
535 ROUTE_MAP_DEP_ECLIST
,
536 ROUTE_MAP_DEP_LCLIST
,
538 ROUTE_MAP_DEP_ASPATH
,
539 ROUTE_MAP_DEP_FILTER
,
543 struct route_map_dep
{
545 struct hash
*dep_rmap_hash
;
546 struct hash
*this_hash
; /* ptr to the hash structure this is part of */
549 struct route_map_dep_data
{
553 /* Count of number of sequences of this
554 * route-map that depend on the same entity.
559 /* Hashes maintaining dependency between various sublists used by route maps */
560 static struct hash
*route_map_dep_hash
[ROUTE_MAP_DEP_MAX
];
562 static unsigned int route_map_dep_hash_make_key(const void *p
);
563 static void route_map_clear_all_references(char *rmap_name
);
564 static void route_map_rule_delete(struct route_map_rule_list
*,
565 struct route_map_rule
*);
566 static bool rmap_debug
;
568 /* New route map allocation. Please note route map's name must be
570 static struct route_map
*route_map_new(const char *name
)
572 struct route_map
*new;
574 new = XCALLOC(MTYPE_ROUTE_MAP
, sizeof(struct route_map
));
575 new->name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
576 QOBJ_REG(new, route_map
);
580 /* Add new name to route_map. */
581 static struct route_map
*route_map_add(const char *name
)
583 struct route_map
*map
;
584 struct route_map_list
*list
;
586 map
= route_map_new(name
);
587 list
= &route_map_master
;
589 /* Add map to the hash */
590 hash_get(route_map_master_hash
, map
, hash_alloc_intern
);
592 /* Add new entry to the head of the list to match how it is added in the
593 * hash table. This is to ensure that if the same route-map has been
594 * created more than once and then marked for deletion (which can happen
595 * if prior deletions haven't completed as BGP hasn't yet done the
596 * route-map processing), the order of the entities is the same in both
597 * the list and the hash table. Otherwise, since there is nothing to
598 * distinguish between the two entries, the wrong entry could get freed.
599 * TODO: This needs to be re-examined to handle it better - e.g., revive
600 * a deleted entry if the route-map is created again.
603 map
->next
= list
->head
;
605 list
->head
->prev
= map
;
611 if (route_map_master
.add_hook
) {
612 (*route_map_master
.add_hook
)(name
);
613 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_ADDED
);
616 if (!map
->ipv4_prefix_table
)
617 map
->ipv4_prefix_table
= route_table_init();
619 if (!map
->ipv6_prefix_table
)
620 map
->ipv6_prefix_table
= route_table_init();
623 zlog_debug("Add route-map %s", name
);
627 /* this is supposed to be called post processing by
628 * the delete hook function. Don't invoke delete_hook
629 * again in this routine.
631 static void route_map_free_map(struct route_map
*map
)
633 struct route_map_list
*list
;
634 struct route_map_index
*index
;
639 while ((index
= map
->head
) != NULL
)
640 route_map_index_delete(index
, 0);
643 zlog_debug("Deleting route-map %s", map
->name
);
645 list
= &route_map_master
;
650 map
->next
->prev
= map
->prev
;
652 list
->tail
= map
->prev
;
655 map
->prev
->next
= map
->next
;
657 list
->head
= map
->next
;
659 hash_release(route_map_master_hash
, map
);
660 XFREE(MTYPE_ROUTE_MAP_NAME
, map
->name
);
661 XFREE(MTYPE_ROUTE_MAP
, map
);
664 /* Route map delete from list. */
665 void route_map_delete(struct route_map
*map
)
667 struct route_map_index
*index
;
670 while ((index
= map
->head
) != NULL
)
671 route_map_index_delete(index
, 0);
676 /* Clear all dependencies */
677 route_map_clear_all_references(name
);
679 /* Execute deletion hook. */
680 if (route_map_master
.delete_hook
) {
681 (*route_map_master
.delete_hook
)(name
);
682 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_DELETED
);
685 if (!map
->to_be_processed
) {
686 route_map_free_map(map
);
690 /* Lookup route map by route map name string. */
691 struct route_map
*route_map_lookup_by_name(const char *name
)
693 struct route_map
*map
;
694 struct route_map tmp_map
;
699 // map.deleted is 0 via memset
700 memset(&tmp_map
, 0, sizeof(struct route_map
));
701 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
702 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
703 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
707 /* Simple helper to warn if route-map does not exist. */
708 struct route_map
*route_map_lookup_warn_noexist(struct vty
*vty
, const char *name
)
710 struct route_map
*route_map
= route_map_lookup_by_name(name
);
713 if (vty_shell_serv(vty
))
714 vty_out(vty
, "The route-map '%s' does not exist.\n", name
);
719 int route_map_mark_updated(const char *name
)
721 struct route_map
*map
;
723 struct route_map tmp_map
;
728 map
= route_map_lookup_by_name(name
);
730 /* If we did not find the routemap with deleted=false try again
734 memset(&tmp_map
, 0, sizeof(struct route_map
));
735 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
736 tmp_map
.deleted
= true;
737 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
738 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
742 map
->to_be_processed
= true;
749 static int route_map_clear_updated(struct route_map
*map
)
754 map
->to_be_processed
= false;
756 route_map_free_map(map
);
762 /* Lookup route map. If there isn't route map create one and return
764 struct route_map
*route_map_get(const char *name
)
766 struct route_map
*map
;
768 map
= route_map_lookup_by_name(name
);
770 map
= route_map_add(name
);
775 void route_map_walk_update_list(void (*route_map_update_fn
)(char *name
))
777 struct route_map
*node
;
778 struct route_map
*nnode
= NULL
;
780 for (node
= route_map_master
.head
; node
; node
= nnode
) {
781 if (node
->to_be_processed
) {
782 /* DD: Should we add any thread yield code here */
783 route_map_update_fn(node
->name
);
785 route_map_clear_updated(node
);
791 /* Return route map's type string. */
792 static const char *route_map_type_str(enum route_map_type type
)
806 static const char *route_map_cmd_result_str(enum route_map_cmd_result_t res
)
824 static const char *route_map_result_str(route_map_result_t res
)
829 case RMAP_PERMITMATCH
:
837 static void vty_show_route_map_entry(struct vty
*vty
, struct route_map
*map
)
839 struct route_map_index
*index
;
840 struct route_map_rule
*rule
;
842 vty_out(vty
, "route-map: %s Invoked: %" PRIu64
" Optimization: %s Processed Change: %s\n",
843 map
->name
, map
->applied
- map
->applied_clear
,
844 map
->optimization_disabled
? "disabled" : "enabled",
845 map
->to_be_processed
? "true" : "false");
847 for (index
= map
->head
; index
; index
= index
->next
) {
848 vty_out(vty
, " %s, sequence %d Invoked %" PRIu64
"\n",
849 route_map_type_str(index
->type
), index
->pref
,
850 index
->applied
- index
->applied_clear
);
853 if (index
->description
)
854 vty_out(vty
, " Description:\n %s\n",
858 vty_out(vty
, " Match clauses:\n");
859 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
860 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
863 vty_out(vty
, " Set clauses:\n");
864 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
865 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
869 vty_out(vty
, " Call clause:\n");
871 vty_out(vty
, " Call %s\n", index
->nextrm
);
874 vty_out(vty
, " Action:\n");
875 if (index
->exitpolicy
== RMAP_GOTO
)
876 vty_out(vty
, " Goto %d\n", index
->nextpref
);
877 else if (index
->exitpolicy
== RMAP_NEXT
)
878 vty_out(vty
, " Continue to next entry\n");
879 else if (index
->exitpolicy
== RMAP_EXIT
)
880 vty_out(vty
, " Exit routemap\n");
884 static int sort_route_map(const void **map1
, const void **map2
)
886 const struct route_map
*m1
= *map1
;
887 const struct route_map
*m2
= *map2
;
889 return strcmp(m1
->name
, m2
->name
);
892 static int vty_show_route_map(struct vty
*vty
, const char *name
)
894 struct route_map
*map
;
896 vty_out(vty
, "%s:\n", frr_protonameinst
);
899 map
= route_map_lookup_by_name(name
);
902 vty_show_route_map_entry(vty
, map
);
905 vty_out(vty
, "%s: 'route-map %s' not found\n",
906 frr_protonameinst
, name
);
911 struct list
*maplist
= list_new();
914 for (map
= route_map_master
.head
; map
; map
= map
->next
)
915 listnode_add(maplist
, map
);
917 list_sort(maplist
, sort_route_map
);
919 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
920 vty_show_route_map_entry(vty
, map
);
922 list_delete(&maplist
);
927 /* Unused route map details */
928 static int vty_show_unused_route_map(struct vty
*vty
)
930 struct list
*maplist
= list_new();
932 struct route_map
*map
;
934 for (map
= route_map_master
.head
; map
; map
= map
->next
) {
935 /* If use_count is zero, No protocol is using this routemap.
936 * so adding to the list.
939 listnode_add(maplist
, map
);
942 if (maplist
->count
> 0) {
943 vty_out(vty
, "\n%s:\n", frr_protonameinst
);
944 list_sort(maplist
, sort_route_map
);
946 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
947 vty_show_route_map_entry(vty
, map
);
949 vty_out(vty
, "\n%s: None\n", frr_protonameinst
);
952 list_delete(&maplist
);
956 /* New route map allocation. Please note route map's name must be
958 static struct route_map_index
*route_map_index_new(void)
960 struct route_map_index
*new;
962 new = XCALLOC(MTYPE_ROUTE_MAP_INDEX
, sizeof(struct route_map_index
));
963 new->exitpolicy
= RMAP_EXIT
; /* Default to Cisco-style */
964 TAILQ_INIT(&new->rhclist
);
965 QOBJ_REG(new, route_map_index
);
969 /* Free route map index. */
970 void route_map_index_delete(struct route_map_index
*index
, int notify
)
972 struct routemap_hook_context
*rhc
;
973 struct route_map_rule
*rule
;
978 zlog_debug("Deleting route-map %s sequence %d",
979 index
->map
->name
, index
->pref
);
981 /* Free route map entry description. */
982 XFREE(MTYPE_TMP
, index
->description
);
984 /* Free route map northbound hook contexts. */
985 while ((rhc
= TAILQ_FIRST(&index
->rhclist
)) != NULL
)
986 routemap_hook_context_free(rhc
);
988 /* Free route match. */
989 while ((rule
= index
->match_list
.head
) != NULL
) {
990 if (IS_RULE_IPv4_PREFIX_LIST(rule
->cmd
->str
))
991 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_DELETED
,
992 index
, AFI_IP
, rule
->rule_str
);
993 else if (IS_RULE_IPv6_PREFIX_LIST(rule
->cmd
->str
))
994 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_DELETED
,
998 route_map_rule_delete(&index
->match_list
, rule
);
1001 /* Free route set. */
1002 while ((rule
= index
->set_list
.head
) != NULL
)
1003 route_map_rule_delete(&index
->set_list
, rule
);
1005 /* Remove index from route map list. */
1007 index
->next
->prev
= index
->prev
;
1009 index
->map
->tail
= index
->prev
;
1012 index
->prev
->next
= index
->next
;
1014 index
->map
->head
= index
->next
;
1016 /* Free 'char *nextrm' if not NULL */
1017 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
1019 route_map_pfx_tbl_update(RMAP_EVENT_INDEX_DELETED
, index
, 0, NULL
);
1021 /* Execute event hook. */
1022 if (route_map_master
.event_hook
&& notify
) {
1023 (*route_map_master
.event_hook
)(index
->map
->name
);
1024 route_map_notify_dependencies(index
->map
->name
,
1025 RMAP_EVENT_CALL_ADDED
);
1027 XFREE(MTYPE_ROUTE_MAP_INDEX
, index
);
1030 /* Lookup index from route map. */
1031 static struct route_map_index
*route_map_index_lookup(struct route_map
*map
,
1032 enum route_map_type type
,
1035 struct route_map_index
*index
;
1037 for (index
= map
->head
; index
; index
= index
->next
)
1038 if ((index
->type
== type
|| type
== RMAP_ANY
)
1039 && index
->pref
== pref
)
1044 /* Add new index to route map. */
1045 static struct route_map_index
*
1046 route_map_index_add(struct route_map
*map
, enum route_map_type type
, int pref
)
1048 struct route_map_index
*index
;
1049 struct route_map_index
*point
;
1051 /* Allocate new route map inex. */
1052 index
= route_map_index_new();
1057 /* Compare preference. */
1058 for (point
= map
->head
; point
; point
= point
->next
)
1059 if (point
->pref
>= pref
)
1062 if (map
->head
== NULL
) {
1063 map
->head
= map
->tail
= index
;
1064 } else if (point
== NULL
) {
1065 index
->prev
= map
->tail
;
1066 map
->tail
->next
= index
;
1068 } else if (point
== map
->head
) {
1069 index
->next
= map
->head
;
1070 map
->head
->prev
= index
;
1073 index
->next
= point
;
1074 index
->prev
= point
->prev
;
1076 point
->prev
->next
= index
;
1077 point
->prev
= index
;
1080 route_map_pfx_tbl_update(RMAP_EVENT_INDEX_ADDED
, index
, 0, NULL
);
1082 /* Execute event hook. */
1083 if (route_map_master
.event_hook
) {
1084 (*route_map_master
.event_hook
)(map
->name
);
1085 route_map_notify_dependencies(map
->name
, RMAP_EVENT_CALL_ADDED
);
1089 zlog_debug("Route-map %s add sequence %d, type: %s",
1090 map
->name
, pref
, route_map_type_str(type
));
1095 /* Get route map index. */
1096 struct route_map_index
*
1097 route_map_index_get(struct route_map
*map
, enum route_map_type type
, int pref
)
1099 struct route_map_index
*index
;
1101 index
= route_map_index_lookup(map
, RMAP_ANY
, pref
);
1102 if (index
&& index
->type
!= type
) {
1103 /* Delete index from route map. */
1104 route_map_index_delete(index
, 1);
1108 index
= route_map_index_add(map
, type
, pref
);
1112 /* New route map rule */
1113 static struct route_map_rule
*route_map_rule_new(void)
1115 struct route_map_rule
*new;
1117 new = XCALLOC(MTYPE_ROUTE_MAP_RULE
, sizeof(struct route_map_rule
));
1121 /* Install rule command to the match list. */
1122 void route_map_install_match(const struct route_map_rule_cmd
*cmd
)
1124 vector_set(route_match_vec
, (void *)cmd
);
1127 /* Install rule command to the set list. */
1128 void route_map_install_set(const struct route_map_rule_cmd
*cmd
)
1130 vector_set(route_set_vec
, (void *)cmd
);
1133 /* Lookup rule command from match list. */
1134 static const struct route_map_rule_cmd
*route_map_lookup_match(const char *name
)
1137 const struct route_map_rule_cmd
*rule
;
1139 for (i
= 0; i
< vector_active(route_match_vec
); i
++)
1140 if ((rule
= vector_slot(route_match_vec
, i
)) != NULL
)
1141 if (strcmp(rule
->str
, name
) == 0)
1146 /* Lookup rule command from set list. */
1147 static const struct route_map_rule_cmd
*route_map_lookup_set(const char *name
)
1150 const struct route_map_rule_cmd
*rule
;
1152 for (i
= 0; i
< vector_active(route_set_vec
); i
++)
1153 if ((rule
= vector_slot(route_set_vec
, i
)) != NULL
)
1154 if (strcmp(rule
->str
, name
) == 0)
1159 /* Add match and set rule to rule list. */
1160 static void route_map_rule_add(struct route_map_rule_list
*list
,
1161 struct route_map_rule
*rule
)
1164 rule
->prev
= list
->tail
;
1166 list
->tail
->next
= rule
;
1172 /* Delete rule from rule list. */
1173 static void route_map_rule_delete(struct route_map_rule_list
*list
,
1174 struct route_map_rule
*rule
)
1176 if (rule
->cmd
->func_free
)
1177 (*rule
->cmd
->func_free
)(rule
->value
);
1179 XFREE(MTYPE_ROUTE_MAP_RULE_STR
, rule
->rule_str
);
1182 rule
->next
->prev
= rule
->prev
;
1184 list
->tail
= rule
->prev
;
1186 rule
->prev
->next
= rule
->next
;
1188 list
->head
= rule
->next
;
1190 XFREE(MTYPE_ROUTE_MAP_RULE
, rule
);
1193 /* strcmp wrapper function which don't crush even argument is NULL. */
1194 static int rulecmp(const char *dst
, const char *src
)
1205 return strcmp(dst
, src
);
1210 /* Use this to return the already specified argument for this match. This is
1211 * useful to get the specified argument with a route map match rule when the
1212 * rule is being deleted and the argument is not provided.
1214 const char *route_map_get_match_arg(struct route_map_index
*index
,
1215 const char *match_name
)
1217 struct route_map_rule
*rule
;
1218 const struct route_map_rule_cmd
*cmd
;
1220 /* First lookup rule for add match statement. */
1221 cmd
= route_map_lookup_match(match_name
);
1225 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1226 if (rule
->cmd
== cmd
&& rule
->rule_str
!= NULL
)
1227 return (rule
->rule_str
);
1232 static route_map_event_t
get_route_map_delete_event(route_map_event_t type
)
1235 case RMAP_EVENT_CALL_ADDED
:
1236 return RMAP_EVENT_CALL_DELETED
;
1237 case RMAP_EVENT_PLIST_ADDED
:
1238 return RMAP_EVENT_PLIST_DELETED
;
1239 case RMAP_EVENT_CLIST_ADDED
:
1240 return RMAP_EVENT_CLIST_DELETED
;
1241 case RMAP_EVENT_ECLIST_ADDED
:
1242 return RMAP_EVENT_ECLIST_DELETED
;
1243 case RMAP_EVENT_LLIST_ADDED
:
1244 return RMAP_EVENT_LLIST_DELETED
;
1245 case RMAP_EVENT_ASLIST_ADDED
:
1246 return RMAP_EVENT_ASLIST_DELETED
;
1247 case RMAP_EVENT_FILTER_ADDED
:
1248 return RMAP_EVENT_FILTER_DELETED
;
1249 case RMAP_EVENT_SET_ADDED
:
1250 case RMAP_EVENT_SET_DELETED
:
1251 case RMAP_EVENT_SET_REPLACED
:
1252 case RMAP_EVENT_MATCH_ADDED
:
1253 case RMAP_EVENT_MATCH_DELETED
:
1254 case RMAP_EVENT_MATCH_REPLACED
:
1255 case RMAP_EVENT_INDEX_ADDED
:
1256 case RMAP_EVENT_INDEX_DELETED
:
1257 case RMAP_EVENT_CALL_DELETED
:
1258 case RMAP_EVENT_PLIST_DELETED
:
1259 case RMAP_EVENT_CLIST_DELETED
:
1260 case RMAP_EVENT_ECLIST_DELETED
:
1261 case RMAP_EVENT_LLIST_DELETED
:
1262 case RMAP_EVENT_ASLIST_DELETED
:
1263 case RMAP_EVENT_FILTER_DELETED
:
1264 /* This function returns the appropriate 'deleted' event type
1265 * for every 'added' event type passed to this function.
1266 * This is done only for named entities used in the
1267 * route-map match commands.
1268 * This function is not to be invoked for any of the other event
1276 * Return to make c happy but if we get here something has gone
1277 * terribly terribly wrong, so yes this return makes no sense.
1279 return RMAP_EVENT_CALL_ADDED
;
1282 /* Add match statement to route map. */
1283 enum rmap_compile_rets
route_map_add_match(struct route_map_index
*index
,
1284 const char *match_name
,
1285 const char *match_arg
,
1286 route_map_event_t type
)
1288 struct route_map_rule
*rule
;
1289 struct route_map_rule
*next
;
1290 const struct route_map_rule_cmd
*cmd
;
1292 int8_t delete_rmap_event_type
= 0;
1293 const char *rule_key
;
1295 /* First lookup rule for add match statement. */
1296 cmd
= route_map_lookup_match(match_name
);
1298 return RMAP_RULE_MISSING
;
1300 /* Next call compile function for this match statement. */
1301 if (cmd
->func_compile
) {
1302 compile
= (*cmd
->func_compile
)(match_arg
);
1303 if (compile
== NULL
)
1304 return RMAP_COMPILE_ERROR
;
1307 /* use the compiled results if applicable */
1308 if (compile
&& cmd
->func_get_rmap_rule_key
)
1309 rule_key
= (*cmd
->func_get_rmap_rule_key
)
1312 rule_key
= match_arg
;
1314 /* If argument is completely same ignore it. */
1315 for (rule
= index
->match_list
.head
; rule
; rule
= next
) {
1317 if (rule
->cmd
== cmd
) {
1318 /* If the configured route-map match rule is exactly
1319 * the same as the existing configuration then,
1320 * ignore the duplicate configuration.
1322 if (strcmp(match_arg
, rule
->rule_str
) == 0) {
1324 (*cmd
->func_free
)(compile
);
1326 return RMAP_COMPILE_SUCCESS
;
1329 /* If IPv4 or IPv6 prefix-list match criteria
1330 * has been delete to the route-map index, update
1331 * the route-map's prefix table.
1333 if (IS_RULE_IPv4_PREFIX_LIST(match_name
))
1334 route_map_pfx_tbl_update(
1335 RMAP_EVENT_PLIST_DELETED
, index
, AFI_IP
,
1337 else if (IS_RULE_IPv6_PREFIX_LIST(match_name
))
1338 route_map_pfx_tbl_update(
1339 RMAP_EVENT_PLIST_DELETED
, index
,
1340 AFI_IP6
, rule
->rule_str
);
1342 /* Remove the dependency of the route-map on the rule
1343 * that is being replaced.
1345 if (type
>= RMAP_EVENT_CALL_ADDED
) {
1346 delete_rmap_event_type
=
1347 get_route_map_delete_event(type
);
1348 route_map_upd8_dependency(
1349 delete_rmap_event_type
,
1354 route_map_rule_delete(&index
->match_list
, rule
);
1358 /* Add new route map match rule. */
1359 rule
= route_map_rule_new();
1361 rule
->value
= compile
;
1363 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, match_arg
);
1365 rule
->rule_str
= NULL
;
1367 /* Add new route match rule to linked list. */
1368 route_map_rule_add(&index
->match_list
, rule
);
1370 /* If IPv4 or IPv6 prefix-list match criteria
1371 * has been added to the route-map index, update
1372 * the route-map's prefix table.
1374 if (IS_RULE_IPv4_PREFIX_LIST(match_name
)) {
1375 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_ADDED
, index
, AFI_IP
,
1377 } else if (IS_RULE_IPv6_PREFIX_LIST(match_name
)) {
1378 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_ADDED
, index
, AFI_IP6
,
1382 /* Execute event hook. */
1383 if (route_map_master
.event_hook
) {
1384 (*route_map_master
.event_hook
)(index
->map
->name
);
1385 route_map_notify_dependencies(index
->map
->name
,
1386 RMAP_EVENT_CALL_ADDED
);
1388 if (type
!= RMAP_EVENT_MATCH_ADDED
)
1389 route_map_upd8_dependency(type
, rule_key
, index
->map
->name
);
1391 return RMAP_COMPILE_SUCCESS
;
1394 /* Delete specified route match rule. */
1395 enum rmap_compile_rets
route_map_delete_match(struct route_map_index
*index
,
1396 const char *match_name
,
1397 const char *match_arg
,
1398 route_map_event_t type
)
1400 struct route_map_rule
*rule
;
1401 const struct route_map_rule_cmd
*cmd
;
1402 const char *rule_key
;
1404 cmd
= route_map_lookup_match(match_name
);
1406 return RMAP_RULE_MISSING
;
1408 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1409 if (rule
->cmd
== cmd
&& (rulecmp(rule
->rule_str
, match_arg
) == 0
1410 || match_arg
== NULL
)) {
1411 /* Execute event hook. */
1412 if (route_map_master
.event_hook
) {
1413 (*route_map_master
.event_hook
)(index
->map
->name
);
1414 route_map_notify_dependencies(
1416 RMAP_EVENT_CALL_ADDED
);
1418 if (cmd
->func_get_rmap_rule_key
)
1419 rule_key
= (*cmd
->func_get_rmap_rule_key
)
1422 rule_key
= match_arg
;
1424 if (type
!= RMAP_EVENT_MATCH_DELETED
&& rule_key
)
1425 route_map_upd8_dependency(type
, rule_key
,
1428 route_map_rule_delete(&index
->match_list
, rule
);
1430 /* If IPv4 or IPv6 prefix-list match criteria
1431 * has been delete from the route-map index, update
1432 * the route-map's prefix table.
1434 if (IS_RULE_IPv4_PREFIX_LIST(match_name
)) {
1435 route_map_pfx_tbl_update(
1436 RMAP_EVENT_PLIST_DELETED
, index
, AFI_IP
,
1438 } else if (IS_RULE_IPv6_PREFIX_LIST(match_name
)) {
1439 route_map_pfx_tbl_update(
1440 RMAP_EVENT_PLIST_DELETED
, index
,
1441 AFI_IP6
, match_arg
);
1444 return RMAP_COMPILE_SUCCESS
;
1446 /* Can't find matched rule. */
1447 return RMAP_RULE_MISSING
;
1450 /* Add route-map set statement to the route map. */
1451 enum rmap_compile_rets
route_map_add_set(struct route_map_index
*index
,
1452 const char *set_name
,
1453 const char *set_arg
)
1455 struct route_map_rule
*rule
;
1456 struct route_map_rule
*next
;
1457 const struct route_map_rule_cmd
*cmd
;
1460 cmd
= route_map_lookup_set(set_name
);
1462 return RMAP_RULE_MISSING
;
1464 /* Next call compile function for this match statement. */
1465 if (cmd
->func_compile
) {
1466 compile
= (*cmd
->func_compile
)(set_arg
);
1467 if (compile
== NULL
)
1468 return RMAP_COMPILE_ERROR
;
1472 /* Add by WJL. if old set command of same kind exist, delete it first
1473 to ensure only one set command of same kind exist under a
1475 for (rule
= index
->set_list
.head
; rule
; rule
= next
) {
1477 if (rule
->cmd
== cmd
)
1478 route_map_rule_delete(&index
->set_list
, rule
);
1481 /* Add new route map match rule. */
1482 rule
= route_map_rule_new();
1484 rule
->value
= compile
;
1486 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, set_arg
);
1488 rule
->rule_str
= NULL
;
1490 /* Add new route match rule to linked list. */
1491 route_map_rule_add(&index
->set_list
, rule
);
1493 /* Execute event hook. */
1494 if (route_map_master
.event_hook
) {
1495 (*route_map_master
.event_hook
)(index
->map
->name
);
1496 route_map_notify_dependencies(index
->map
->name
,
1497 RMAP_EVENT_CALL_ADDED
);
1499 return RMAP_COMPILE_SUCCESS
;
1502 /* Delete route map set rule. */
1503 enum rmap_compile_rets
route_map_delete_set(struct route_map_index
*index
,
1504 const char *set_name
,
1505 const char *set_arg
)
1507 struct route_map_rule
*rule
;
1508 const struct route_map_rule_cmd
*cmd
;
1510 cmd
= route_map_lookup_set(set_name
);
1512 return RMAP_RULE_MISSING
;
1514 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
1515 if ((rule
->cmd
== cmd
) && (rulecmp(rule
->rule_str
, set_arg
) == 0
1516 || set_arg
== NULL
)) {
1517 route_map_rule_delete(&index
->set_list
, rule
);
1518 /* Execute event hook. */
1519 if (route_map_master
.event_hook
) {
1520 (*route_map_master
.event_hook
)(index
->map
->name
);
1521 route_map_notify_dependencies(
1523 RMAP_EVENT_CALL_ADDED
);
1525 return RMAP_COMPILE_SUCCESS
;
1527 /* Can't find matched rule. */
1528 return RMAP_RULE_MISSING
;
1531 static enum route_map_cmd_result_t
1532 route_map_apply_match(struct route_map_rule_list
*match_list
,
1533 const struct prefix
*prefix
, void *object
)
1535 enum route_map_cmd_result_t ret
= RMAP_NOMATCH
;
1536 struct route_map_rule
*match
;
1537 bool is_matched
= false;
1540 /* Check all match rule and if there is no match rule, go to the
1542 if (!match_list
->head
)
1545 for (match
= match_list
->head
; match
; match
= match
->next
) {
1547 * Try each match statement. If any match does not
1548 * return RMAP_MATCH or RMAP_NOOP, return.
1549 * Otherwise continue on to next match statement.
1550 * All match statements must MATCH for
1551 * end-result to be a match.
1552 * (Exception:If match stmts result in a mix of
1553 * MATCH/NOOP, then also end-result is a match)
1554 * If all result in NOOP, end-result is NOOP.
1556 ret
= (*match
->cmd
->func_apply
)(match
->value
, prefix
,
1560 * If the consolidated result of func_apply is:
1561 * -----------------------------------------------
1562 * | MATCH | NOMATCH | NOOP | Final Result |
1563 * ------------------------------------------------
1564 * | yes | yes | yes | NOMATCH |
1565 * | no | no | yes | NOOP |
1566 * | yes | no | yes | MATCH |
1567 * | no | yes | yes | NOMATCH |
1568 * |-----------------------------------------------
1570 * Traditionally, all rules within route-map
1571 * should match for it to MATCH.
1572 * If there are noops within the route-map rules,
1573 * it follows the above matrix.
1575 * Eg: route-map rm1 permit 10
1580 * route-map rm1 permit 20
1608 static struct list
*route_map_get_index_list(struct route_node
**rn
,
1609 const struct prefix
*prefix
,
1610 struct route_table
*table
)
1612 struct route_node
*tmp_rn
= NULL
;
1615 *rn
= route_node_match(table
, prefix
);
1621 return (struct list
*)((*rn
)->info
);
1623 /* If rn->info is NULL, get the parent.
1624 * Store the rn in tmp_rn and unlock it later.
1630 *rn
= (*rn
)->parent
;
1632 route_unlock_node(tmp_rn
);
1638 route_lock_node(*rn
);
1639 return (struct list
*)((*rn
)->info
);
1641 } while (!(*rn
)->info
);
1647 * This function returns the route-map index that best matches the prefix.
1649 static struct route_map_index
*route_map_get_index(struct route_map
*map
,
1650 const struct prefix
*prefix
,
1655 struct list
*candidate_rmap_list
= NULL
;
1656 struct route_node
*rn
= NULL
;
1657 struct listnode
*ln
= NULL
, *nn
= NULL
;
1658 struct route_map_index
*index
= NULL
, *best_index
= NULL
;
1659 struct route_map_index
*head_index
= NULL
;
1660 struct route_table
*table
= NULL
;
1661 unsigned char family
= prefix
->family
;
1663 if (family
== AF_INET
)
1664 table
= map
->ipv4_prefix_table
;
1666 table
= map
->ipv6_prefix_table
;
1672 candidate_rmap_list
=
1673 route_map_get_index_list(&rn
, prefix
, table
);
1677 /* If the index at the head of the list is of seq higher
1678 * than that in best_index, ignore the list and get the
1679 * parent node's list.
1681 head_index
= (struct route_map_index
*)(listgetdata(
1682 listhead(candidate_rmap_list
)));
1683 if (best_index
&& head_index
1684 && (best_index
->pref
< head_index
->pref
)) {
1685 route_unlock_node(rn
);
1689 for (ALL_LIST_ELEMENTS(candidate_rmap_list
, ln
, nn
, index
)) {
1690 /* If the index is of seq higher than that in
1691 * best_index, ignore the list and get the parent
1694 if (best_index
&& (best_index
->pref
< index
->pref
))
1697 ret
= route_map_apply_match(&index
->match_list
, prefix
,
1700 if (ret
== RMAP_MATCH
) {
1704 } else if (ret
== RMAP_NOOP
) {
1706 * If match_ret is denymatch, even if we see
1707 * more noops, we retain this return value and
1708 * return this eventually if there are no
1710 * If a best match route-map index already
1711 * exists, do not reset the match_ret.
1713 if (!best_index
&& (*match_ret
!= RMAP_NOMATCH
))
1717 * ret is RMAP_NOMATCH.
1718 * If a best match route-map index already
1719 * exists, do not reset the match_ret.
1726 route_unlock_node(rn
);
1733 static int route_map_candidate_list_cmp(struct route_map_index
*idx1
,
1734 struct route_map_index
*idx2
)
1741 return (idx1
->pref
- idx2
->pref
);
1745 * This function adds the route-map index into the default route's
1746 * route-node in the route-map's IPv4/IPv6 prefix-table.
1748 static void route_map_pfx_table_add_default(afi_t afi
,
1749 struct route_map_index
*index
)
1751 struct route_node
*rn
= NULL
;
1752 struct list
*rmap_candidate_list
= NULL
;
1754 bool updated_rn
= false;
1755 struct route_table
*table
= NULL
;
1757 memset(&p
, 0, sizeof(p
));
1758 p
.family
= afi2family(afi
);
1761 if (p
.family
== AF_INET
) {
1762 table
= index
->map
->ipv4_prefix_table
;
1764 index
->map
->ipv4_prefix_table
= route_table_init();
1766 table
= index
->map
->ipv4_prefix_table
;
1768 table
= index
->map
->ipv6_prefix_table
;
1770 index
->map
->ipv6_prefix_table
= route_table_init();
1772 table
= index
->map
->ipv6_prefix_table
;
1775 /* Add default route to table */
1776 rn
= route_node_get(table
, &p
);
1782 rmap_candidate_list
= list_new();
1783 rmap_candidate_list
->cmp
=
1784 (int (*)(void *, void *))route_map_candidate_list_cmp
;
1785 rn
->info
= rmap_candidate_list
;
1787 rmap_candidate_list
= (struct list
*)rn
->info
;
1791 listnode_add_sort_nodup(rmap_candidate_list
, index
);
1793 route_unlock_node(rn
);
1797 * This function removes the route-map index from the default route's
1798 * route-node in the route-map's IPv4/IPv6 prefix-table.
1800 static void route_map_pfx_table_del_default(afi_t afi
,
1801 struct route_map_index
*index
)
1803 struct route_node
*rn
= NULL
;
1804 struct list
*rmap_candidate_list
= NULL
;
1806 struct route_table
*table
= NULL
;
1808 memset(&p
, 0, sizeof(p
));
1809 p
.family
= afi2family(afi
);
1812 if (p
.family
== AF_INET
)
1813 table
= index
->map
->ipv4_prefix_table
;
1815 table
= index
->map
->ipv6_prefix_table
;
1817 /* Remove RMAP index from default route in table */
1818 rn
= route_node_lookup(table
, &p
);
1819 if (!rn
|| !rn
->info
)
1822 rmap_candidate_list
= (struct list
*)rn
->info
;
1824 listnode_delete(rmap_candidate_list
, index
);
1826 if (listcount(rmap_candidate_list
) == 0) {
1827 list_delete(&rmap_candidate_list
);
1829 route_unlock_node(rn
);
1831 route_unlock_node(rn
);
1835 * This function adds the route-map index to the route-node for
1836 * the prefix-entry in the route-map's IPv4/IPv6 prefix-table.
1838 static void route_map_pfx_table_add(struct route_table
*table
,
1839 struct route_map_index
*index
,
1840 struct prefix_list_entry
*pentry
)
1842 struct route_node
*rn
= NULL
;
1843 struct list
*rmap_candidate_list
= NULL
;
1844 bool updated_rn
= false;
1846 rn
= route_node_get(table
, &pentry
->prefix
);
1851 rmap_candidate_list
= list_new();
1852 rmap_candidate_list
->cmp
=
1853 (int (*)(void *, void *))route_map_candidate_list_cmp
;
1854 rn
->info
= rmap_candidate_list
;
1856 rmap_candidate_list
= (struct list
*)rn
->info
;
1860 listnode_add_sort_nodup(rmap_candidate_list
, index
);
1862 route_unlock_node(rn
);
1866 * This function removes the route-map index from the route-node for
1867 * the prefix-entry in the route-map's IPv4/IPv6 prefix-table.
1869 static void route_map_pfx_table_del(struct route_table
*table
,
1870 struct route_map_index
*index
,
1871 struct prefix_list_entry
*pentry
)
1873 struct route_node
*rn
= NULL
;
1874 struct list
*rmap_candidate_list
= NULL
;
1876 rn
= route_node_lookup(table
, &pentry
->prefix
);
1877 if (!rn
|| !rn
->info
)
1880 rmap_candidate_list
= (struct list
*)rn
->info
;
1882 listnode_delete(rmap_candidate_list
, index
);
1884 if (listcount(rmap_candidate_list
) == 0) {
1885 list_delete(&rmap_candidate_list
);
1887 route_unlock_node(rn
);
1889 route_unlock_node(rn
);
1892 /* This function checks for the presence of an IPv4 prefix-list
1893 * match rule in the given route-map index.
1895 static bool route_map_is_ip_pfx_list_rule_present(struct route_map_index
*index
)
1897 struct route_map_rule_list
*match_list
= NULL
;
1898 struct route_map_rule
*rule
= NULL
;
1900 match_list
= &index
->match_list
;
1901 for (rule
= match_list
->head
; rule
; rule
= rule
->next
)
1902 if (IS_RULE_IPv4_PREFIX_LIST(rule
->cmd
->str
))
1908 /* This function checks for the presence of an IPv6 prefix-list
1909 * match rule in the given route-map index.
1912 route_map_is_ipv6_pfx_list_rule_present(struct route_map_index
*index
)
1914 struct route_map_rule_list
*match_list
= NULL
;
1915 struct route_map_rule
*rule
= NULL
;
1917 match_list
= &index
->match_list
;
1918 for (rule
= match_list
->head
; rule
; rule
= rule
->next
)
1919 if (IS_RULE_IPv6_PREFIX_LIST(rule
->cmd
->str
))
1925 /* This function does the following:
1926 * 1) If plist_name is not present, search for a IPv4 or IPv6 prefix-list
1927 * match clause (based on the afi passed to this foo) and get the
1929 * 2) Look up the prefix-list using the name.
1930 * 3) If the prefix-list is not found then, add the index to the IPv4/IPv6
1931 * default-route's node in the trie (based on the afi passed to this foo).
1932 * 4) If the prefix-list is found then, remove the index from the IPv4/IPv6
1933 * default-route's node in the trie (based on the afi passed to this foo).
1934 * 5) If a prefix-entry is passed then, create a route-node for this entry and
1935 * add this index to the route-node.
1936 * 6) If prefix-entry is not passed then, for every prefix-entry in the
1937 * prefix-list, create a route-node for this entry and
1938 * add this index to the route-node.
1940 static void route_map_add_plist_entries(afi_t afi
,
1941 struct route_map_index
*index
,
1942 const char *plist_name
,
1943 struct prefix_list_entry
*entry
)
1945 struct route_map_rule_list
*match_list
= NULL
;
1946 struct route_map_rule
*match
= NULL
;
1947 struct prefix_list
*plist
= NULL
;
1948 struct prefix_list_entry
*pentry
= NULL
;
1949 bool plist_rule_is_present
= false;
1952 match_list
= &index
->match_list
;
1954 for (match
= match_list
->head
; match
; match
= match
->next
) {
1955 if (afi
== AFI_IP
) {
1956 if (IS_RULE_IPv4_PREFIX_LIST(match
->cmd
->str
)) {
1957 plist_rule_is_present
= true;
1961 if (IS_RULE_IPv6_PREFIX_LIST(match
->cmd
->str
)) {
1962 plist_rule_is_present
= true;
1968 if (plist_rule_is_present
)
1969 plist
= prefix_list_lookup(afi
, match
->rule_str
);
1971 plist
= prefix_list_lookup(afi
, plist_name
);
1975 route_map_pfx_table_add_default(afi
, index
);
1979 route_map_pfx_table_del_default(afi
, index
);
1982 if (afi
== AFI_IP
) {
1983 route_map_pfx_table_add(index
->map
->ipv4_prefix_table
,
1986 route_map_pfx_table_add(index
->map
->ipv6_prefix_table
,
1990 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
1991 if (afi
== AFI_IP
) {
1992 route_map_pfx_table_add(
1993 index
->map
->ipv4_prefix_table
, index
,
1996 route_map_pfx_table_add(
1997 index
->map
->ipv6_prefix_table
, index
,
2004 /* This function does the following:
2005 * 1) If plist_name is not present, search for a IPv4 or IPv6 prefix-list
2006 * match clause (based on the afi passed to this foo) and get the
2008 * 2) Look up the prefix-list using the name.
2009 * 3) If the prefix-list is not found then, delete the index from the IPv4/IPv6
2010 * default-route's node in the trie (based on the afi passed to this foo).
2011 * 4) If a prefix-entry is passed then, remove this index from the route-node
2012 * for the prefix in this prefix-entry.
2013 * 5) If prefix-entry is not passed then, for every prefix-entry in the
2014 * prefix-list, remove this index from the route-node
2015 * for the prefix in this prefix-entry.
2017 static void route_map_del_plist_entries(afi_t afi
,
2018 struct route_map_index
*index
,
2019 const char *plist_name
,
2020 struct prefix_list_entry
*entry
)
2022 struct route_map_rule_list
*match_list
= NULL
;
2023 struct route_map_rule
*match
= NULL
;
2024 struct prefix_list
*plist
= NULL
;
2025 struct prefix_list_entry
*pentry
= NULL
;
2026 bool plist_rule_is_present
= false;
2029 match_list
= &index
->match_list
;
2031 for (match
= match_list
->head
; match
; match
= match
->next
) {
2032 if (afi
== AFI_IP
) {
2033 if (IS_RULE_IPv4_PREFIX_LIST(match
->cmd
->str
)) {
2034 plist_rule_is_present
= true;
2038 if (IS_RULE_IPv6_PREFIX_LIST(match
->cmd
->str
)) {
2039 plist_rule_is_present
= true;
2045 if (plist_rule_is_present
)
2046 plist
= prefix_list_lookup(afi
, match
->rule_str
);
2048 plist
= prefix_list_lookup(afi
, plist_name
);
2052 route_map_pfx_table_del_default(afi
, index
);
2057 if (afi
== AFI_IP
) {
2058 route_map_pfx_table_del(index
->map
->ipv4_prefix_table
,
2061 route_map_pfx_table_del(index
->map
->ipv6_prefix_table
,
2065 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
2066 if (afi
== AFI_IP
) {
2067 route_map_pfx_table_del(
2068 index
->map
->ipv4_prefix_table
, index
,
2071 route_map_pfx_table_del(
2072 index
->map
->ipv6_prefix_table
, index
,
2080 * This function handles the cases where a prefix-list is added/removed
2081 * as a match command from a particular route-map index.
2082 * It updates the prefix-table of the route-map accordingly.
2084 static void route_map_trie_update(afi_t afi
, route_map_event_t event
,
2085 struct route_map_index
*index
,
2086 const char *plist_name
)
2088 if (event
== RMAP_EVENT_PLIST_ADDED
) {
2089 if (afi
== AFI_IP
) {
2090 if (!route_map_is_ipv6_pfx_list_rule_present(index
)) {
2091 route_map_pfx_table_del_default(AFI_IP6
, index
);
2092 route_map_add_plist_entries(afi
, index
,
2095 route_map_del_plist_entries(AFI_IP6
, index
,
2099 if (!route_map_is_ip_pfx_list_rule_present(index
)) {
2100 route_map_pfx_table_del_default(AFI_IP
, index
);
2101 route_map_add_plist_entries(afi
, index
,
2104 route_map_del_plist_entries(AFI_IP
, index
, NULL
,
2108 } else if (event
== RMAP_EVENT_PLIST_DELETED
) {
2109 if (afi
== AFI_IP
) {
2110 route_map_del_plist_entries(afi
, index
, plist_name
,
2113 /* If IPv6 prefix-list match rule is not present,
2114 * add this index to the IPv4 default route's trie
2116 * Also, add this index to the trie nodes created
2117 * for each of the prefix-entries within the IPv6
2118 * prefix-list, if the IPv6 prefix-list match rule
2119 * is present. Else, add this index to the IPv6
2120 * default route's trie node.
2122 if (!route_map_is_ipv6_pfx_list_rule_present(index
))
2123 route_map_pfx_table_add_default(afi
, index
);
2125 route_map_add_plist_entries(AFI_IP6
, index
, NULL
, NULL
);
2127 route_map_del_plist_entries(afi
, index
, plist_name
,
2130 /* If IPv4 prefix-list match rule is not present,
2131 * add this index to the IPv6 default route's trie
2133 * Also, add this index to the trie nodes created
2134 * for each of the prefix-entries within the IPv4
2135 * prefix-list, if the IPv4 prefix-list match rule
2136 * is present. Else, add this index to the IPv4
2137 * default route's trie node.
2139 if (!route_map_is_ip_pfx_list_rule_present(index
))
2140 route_map_pfx_table_add_default(afi
, index
);
2142 route_map_add_plist_entries(AFI_IP
, index
, NULL
, NULL
);
2148 * This function handles the cases where a route-map index and
2149 * prefix-list is added/removed.
2150 * It updates the prefix-table of the route-map accordingly.
2152 static void route_map_pfx_tbl_update(route_map_event_t event
,
2153 struct route_map_index
*index
, afi_t afi
,
2154 const char *plist_name
)
2156 struct route_map
*rmap
= NULL
;
2161 if (event
== RMAP_EVENT_INDEX_ADDED
) {
2162 route_map_pfx_table_add_default(AFI_IP
, index
);
2163 route_map_pfx_table_add_default(AFI_IP6
, index
);
2167 if (event
== RMAP_EVENT_INDEX_DELETED
) {
2168 route_map_pfx_table_del_default(AFI_IP
, index
);
2169 route_map_pfx_table_del_default(AFI_IP6
, index
);
2171 if ((index
->map
->head
== NULL
) && (index
->map
->tail
== NULL
)) {
2174 if (rmap
->ipv4_prefix_table
) {
2175 route_table_finish(rmap
->ipv4_prefix_table
);
2176 rmap
->ipv4_prefix_table
= NULL
;
2179 if (rmap
->ipv6_prefix_table
) {
2180 route_table_finish(rmap
->ipv6_prefix_table
);
2181 rmap
->ipv6_prefix_table
= NULL
;
2187 /* Handle prefix-list match rule addition/deletion.
2189 route_map_trie_update(afi
, event
, index
, plist_name
);
2193 * This function handles the cases where a new prefix-entry is added to
2194 * a prefix-list or, an existing prefix-entry is removed from the prefix-list.
2195 * It updates the prefix-table of the route-map accordingly.
2197 static void route_map_pentry_update(route_map_event_t event
,
2198 const char *plist_name
,
2199 struct route_map_index
*index
,
2200 struct prefix_list_entry
*pentry
)
2202 struct prefix_list
*plist
= NULL
;
2204 unsigned char family
= pentry
->prefix
.family
;
2206 if (family
== AF_INET
) {
2208 plist
= prefix_list_lookup(AFI_IP
, plist_name
);
2211 plist
= prefix_list_lookup(AFI_IP6
, plist_name
);
2214 if (event
== RMAP_EVENT_PLIST_ADDED
) {
2215 if (afi
== AFI_IP
) {
2216 if (!route_map_is_ipv6_pfx_list_rule_present(index
))
2217 route_map_add_plist_entries(afi
, index
,
2218 plist_name
, pentry
);
2220 if (!route_map_is_ip_pfx_list_rule_present(index
))
2221 route_map_add_plist_entries(afi
, index
,
2222 plist_name
, pentry
);
2224 } else if (event
== RMAP_EVENT_PLIST_DELETED
) {
2225 route_map_del_plist_entries(afi
, index
, plist_name
, pentry
);
2227 if (plist
->count
== 1) {
2228 if (afi
== AFI_IP
) {
2229 if (!route_map_is_ipv6_pfx_list_rule_present(
2231 route_map_pfx_table_add_default(afi
,
2234 if (!route_map_is_ip_pfx_list_rule_present(
2236 route_map_pfx_table_add_default(afi
,
2243 static void route_map_pentry_process_dependency(struct hash_bucket
*backet
,
2246 char *rmap_name
= NULL
;
2247 struct route_map
*rmap
= NULL
;
2248 struct route_map_index
*index
= NULL
;
2249 struct route_map_rule_list
*match_list
= NULL
;
2250 struct route_map_rule
*match
= NULL
;
2251 struct route_map_dep_data
*dep_data
= NULL
;
2252 struct route_map_pentry_dep
*pentry_dep
=
2253 (struct route_map_pentry_dep
*)data
;
2254 unsigned char family
= pentry_dep
->pentry
->prefix
.family
;
2256 dep_data
= (struct route_map_dep_data
*)backet
->data
;
2260 rmap_name
= dep_data
->rname
;
2261 rmap
= route_map_lookup_by_name(rmap_name
);
2262 if (!rmap
|| !rmap
->head
)
2265 for (index
= rmap
->head
; index
; index
= index
->next
) {
2266 match_list
= &index
->match_list
;
2271 for (match
= match_list
->head
; match
; match
= match
->next
) {
2272 if (strcmp(match
->rule_str
, pentry_dep
->plist_name
)
2274 if (IS_RULE_IPv4_PREFIX_LIST(match
->cmd
->str
)
2275 && family
== AF_INET
) {
2276 route_map_pentry_update(
2278 pentry_dep
->plist_name
, index
,
2279 pentry_dep
->pentry
);
2280 } else if (IS_RULE_IPv6_PREFIX_LIST(
2282 && family
== AF_INET6
) {
2283 route_map_pentry_update(
2285 pentry_dep
->plist_name
, index
,
2286 pentry_dep
->pentry
);
2293 void route_map_notify_pentry_dependencies(const char *affected_name
,
2294 struct prefix_list_entry
*pentry
,
2295 route_map_event_t event
)
2297 struct route_map_dep
*dep
= NULL
;
2298 struct hash
*upd8_hash
= NULL
;
2299 struct route_map_pentry_dep pentry_dep
;
2301 if (!affected_name
|| !pentry
)
2304 upd8_hash
= route_map_get_dep_hash(event
);
2308 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, (void *)affected_name
,
2311 if (!dep
->this_hash
)
2312 dep
->this_hash
= upd8_hash
;
2314 memset(&pentry_dep
, 0, sizeof(struct route_map_pentry_dep
));
2315 pentry_dep
.pentry
= pentry
;
2316 pentry_dep
.plist_name
= affected_name
;
2317 pentry_dep
.event
= event
;
2319 hash_iterate(dep
->dep_rmap_hash
,
2320 route_map_pentry_process_dependency
,
2321 (void *)&pentry_dep
);
2325 /* Apply route map's each index to the object.
2327 The matrix for a route-map looks like this:
2328 (note, this includes the description for the "NEXT"
2329 and "GOTO" frobs now
2331 | Match | No Match | No op
2332 |-----------|--------------|-------
2333 permit | action | cont | cont.
2334 | | default:deny | default:permit
2335 -------------------+-----------------------
2336 | deny | cont | cont.
2337 deny | | default:deny | default:permit
2338 |-----------|--------------|--------
2341 -Apply Set statements, accept route
2342 -If Call statement is present jump to the specified route-map, if it
2343 denies the route we finish.
2344 -If NEXT is specified, goto NEXT statement
2345 -If GOTO is specified, goto the first clause where pref > nextpref
2346 -If nothing is specified, do as Cisco and finish
2348 -Route is denied by route-map.
2352 If we get no matches after we've processed all updates, then the route
2355 Some notes on the new "CALL", "NEXT" and "GOTO"
2356 call WORD - If this clause is matched, then the set statements
2357 are executed and then we jump to route-map 'WORD'. If
2358 this route-map denies the route, we finish, in other
2360 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
2361 on-match next - If this clause is matched, then the set statements
2362 are executed and then we drop through to the next clause
2363 on-match goto n - If this clause is matched, then the set statments
2364 are executed and then we goto the nth clause, or the
2365 first clause greater than this. In order to ensure
2366 route-maps *always* exit, you cannot jump backwards.
2369 We need to make sure our route-map processing matches the above
2371 route_map_result_t
route_map_apply(struct route_map
*map
,
2372 const struct prefix
*prefix
, void *object
)
2374 static int recursion
= 0;
2375 enum route_map_cmd_result_t match_ret
= RMAP_NOMATCH
;
2376 route_map_result_t ret
= RMAP_PERMITMATCH
;
2377 struct route_map_index
*index
= NULL
;
2378 struct route_map_rule
*set
= NULL
;
2379 bool skip_match_clause
= false;
2381 if (recursion
> RMAP_RECURSION_LIMIT
) {
2383 EC_LIB_RMAP_RECURSION_LIMIT
,
2384 "route-map recursion limit (%d) reached, discarding route",
2385 RMAP_RECURSION_LIMIT
);
2387 return RMAP_DENYMATCH
;
2390 if (map
== NULL
|| map
->head
== NULL
) {
2391 ret
= RMAP_DENYMATCH
;
2392 goto route_map_apply_end
;
2397 if ((!map
->optimization_disabled
)
2398 && (map
->ipv4_prefix_table
|| map
->ipv6_prefix_table
)) {
2399 index
= route_map_get_index(map
, prefix
, object
,
2400 (uint8_t *)&match_ret
);
2404 "Best match route-map: %s, sequence: %d for pfx: %pFX, result: %s",
2405 map
->name
, index
->pref
, prefix
,
2406 route_map_cmd_result_str(match_ret
));
2410 "No best match sequence for pfx: %pFX in route-map: %s, result: %s",
2412 route_map_cmd_result_str(match_ret
));
2414 * No index matches this prefix. Return deny unless,
2415 * match_ret = RMAP_NOOP.
2417 if (match_ret
== RMAP_NOOP
)
2418 ret
= RMAP_PERMITMATCH
;
2420 ret
= RMAP_DENYMATCH
;
2421 goto route_map_apply_end
;
2423 skip_match_clause
= true;
2428 for (; index
; index
= index
->next
) {
2429 if (!skip_match_clause
) {
2431 /* Apply this index. */
2432 match_ret
= route_map_apply_match(&index
->match_list
,
2436 "Route-map: %s, sequence: %d, prefix: %pFX, result: %s",
2437 map
->name
, index
->pref
, prefix
,
2438 route_map_cmd_result_str(match_ret
));
2441 skip_match_clause
= false;
2444 /* Now we apply the matrix from above */
2445 if (match_ret
== RMAP_NOOP
)
2447 * Do not change the return value. Retain the previous
2448 * return value. Previous values can be:
2449 * 1)permitmatch (if a nomatch was never
2450 * seen before in this route-map.)
2451 * 2)denymatch (if a nomatch was seen earlier in one
2452 * of the previous sequences)
2456 * 'cont' from matrix - continue to next route-map
2460 else if (match_ret
== RMAP_NOMATCH
) {
2463 * The return value is now changed to denymatch.
2464 * So from here on out, even if we see more noops,
2465 * we retain this return value and return this
2466 * eventually if there are no matches.
2468 ret
= RMAP_DENYMATCH
;
2471 * 'cont' from matrix - continue to next route-map
2475 } else if (match_ret
== RMAP_MATCH
) {
2476 if (index
->type
== RMAP_PERMIT
)
2479 /* Match succeeded, rmap is of type permit */
2480 ret
= RMAP_PERMITMATCH
;
2482 /* permit+match must execute sets */
2483 for (set
= index
->set_list
.head
; set
;
2486 * set cmds return RMAP_OKAY or
2487 * RMAP_ERROR. We do not care if
2488 * set succeeded or not. So, ignore
2491 (void)(*set
->cmd
->func_apply
)(
2492 set
->value
, prefix
, object
);
2494 /* Call another route-map if available */
2495 if (index
->nextrm
) {
2496 struct route_map
*nextrm
=
2497 route_map_lookup_by_name(
2500 if (nextrm
) /* Target route-map found,
2504 ret
= route_map_apply(
2505 nextrm
, prefix
, object
);
2509 /* If nextrm returned 'deny', finish. */
2510 if (ret
== RMAP_DENYMATCH
)
2511 goto route_map_apply_end
;
2514 switch (index
->exitpolicy
) {
2516 goto route_map_apply_end
;
2520 /* Find the next clause to jump to */
2521 struct route_map_index
*next
=
2523 int nextpref
= index
->nextpref
;
2525 while (next
&& next
->pref
< nextpref
) {
2530 /* No clauses match! */
2531 goto route_map_apply_end
;
2535 } else if (index
->type
== RMAP_DENY
)
2538 ret
= RMAP_DENYMATCH
;
2539 goto route_map_apply_end
;
2544 route_map_apply_end
:
2546 zlog_debug("Route-map: %s, prefix: %pFX, result: %s",
2547 (map
? map
->name
: "null"), prefix
,
2548 route_map_result_str(ret
));
2553 void route_map_add_hook(void (*func
)(const char *))
2555 route_map_master
.add_hook
= func
;
2558 void route_map_delete_hook(void (*func
)(const char *))
2560 route_map_master
.delete_hook
= func
;
2563 void route_map_event_hook(void (*func
)(const char *name
))
2565 route_map_master
.event_hook
= func
;
2568 /* Routines for route map dependency lists and dependency processing */
2569 static bool route_map_rmap_hash_cmp(const void *p1
, const void *p2
)
2571 return strcmp(((const struct route_map_dep_data
*)p1
)->rname
,
2572 ((const struct route_map_dep_data
*)p2
)->rname
)
2576 static bool route_map_dep_hash_cmp(const void *p1
, const void *p2
)
2579 return (strcmp(((const struct route_map_dep
*)p1
)->dep_name
,
2584 static void route_map_clear_reference(struct hash_bucket
*bucket
, void *arg
)
2586 struct route_map_dep
*dep
= bucket
->data
;
2587 struct route_map_dep_data
*dep_data
= NULL
, tmp_dep_data
;
2589 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
2590 tmp_dep_data
.rname
= arg
;
2591 dep_data
= hash_release(dep
->dep_rmap_hash
, &tmp_dep_data
);
2594 zlog_debug("Clearing reference for %s to %s count: %d",
2595 dep
->dep_name
, tmp_dep_data
.rname
,
2598 XFREE(MTYPE_ROUTE_MAP_NAME
, dep_data
->rname
);
2599 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, dep_data
);
2601 if (!dep
->dep_rmap_hash
->count
) {
2602 dep
= hash_release(dep
->this_hash
, (void *)dep
->dep_name
);
2603 hash_free(dep
->dep_rmap_hash
);
2604 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
2605 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
2609 static void route_map_clear_all_references(char *rmap_name
)
2614 zlog_debug("Clearing references for %s", rmap_name
);
2616 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
2617 hash_iterate(route_map_dep_hash
[i
], route_map_clear_reference
,
2622 static unsigned int route_map_dep_data_hash_make_key(const void *p
)
2624 const struct route_map_dep_data
*dep_data
= p
;
2626 return string_hash_make(dep_data
->rname
);
2629 DEFUN (set_srte_color
,
2631 "set sr-te color [(1-4294967295)]",
2635 "Color of the SR-TE Policies to match with\n")
2637 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2639 char *arg
= argv_find(argv
, argc
, "(1-4294967295)", &idx
)
2643 if (rmap_match_set_hook
.set_srte_color
)
2644 return rmap_match_set_hook
.set_srte_color(vty
, index
,
2645 "sr-te color", arg
);
2649 DEFUN (no_set_srte_color
,
2650 no_set_srte_color_cmd
,
2651 "no set sr-te color [(1-4294967295)]",
2656 "Color of the SR-TE Policies to match with\n")
2658 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2660 char *arg
= argv_find(argv
, argc
, "(1-4294967295)", &idx
)
2664 if (rmap_match_set_hook
.no_set_srte_color
)
2665 return rmap_match_set_hook
.no_set_srte_color(
2666 vty
, index
, "sr-te color", arg
);
2670 static void *route_map_dep_hash_alloc(void *p
)
2672 char *dep_name
= (char *)p
;
2673 struct route_map_dep
*dep_entry
;
2675 dep_entry
= XCALLOC(MTYPE_ROUTE_MAP_DEP
, sizeof(struct route_map_dep
));
2676 dep_entry
->dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
2677 dep_entry
->dep_rmap_hash
=
2678 hash_create_size(8, route_map_dep_data_hash_make_key
,
2679 route_map_rmap_hash_cmp
, "Route Map Dep Hash");
2680 dep_entry
->this_hash
= NULL
;
2685 static void *route_map_name_hash_alloc(void *p
)
2687 struct route_map_dep_data
*dep_data
= NULL
, *tmp_dep_data
= NULL
;
2689 dep_data
= XCALLOC(MTYPE_ROUTE_MAP_DEP_DATA
,
2690 sizeof(struct route_map_dep_data
));
2692 dep_data
->rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, tmp_dep_data
->rname
);
2696 static unsigned int route_map_dep_hash_make_key(const void *p
)
2698 return (string_hash_make((char *)p
));
2701 static void route_map_print_dependency(struct hash_bucket
*bucket
, void *data
)
2703 struct route_map_dep_data
*dep_data
= bucket
->data
;
2704 char *rmap_name
= dep_data
->rname
;
2705 char *dep_name
= data
;
2707 zlog_debug("%s: Dependency for %s: %s", __func__
, dep_name
, rmap_name
);
2710 static int route_map_dep_update(struct hash
*dephash
, const char *dep_name
,
2711 const char *rmap_name
, route_map_event_t type
)
2713 struct route_map_dep
*dep
= NULL
;
2714 char *dname
, *rname
;
2716 struct route_map_dep_data
*dep_data
= NULL
, *ret_dep_data
= NULL
;
2717 struct route_map_dep_data tmp_dep_data
;
2719 dname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
2720 rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
2723 case RMAP_EVENT_PLIST_ADDED
:
2724 case RMAP_EVENT_CLIST_ADDED
:
2725 case RMAP_EVENT_ECLIST_ADDED
:
2726 case RMAP_EVENT_ASLIST_ADDED
:
2727 case RMAP_EVENT_LLIST_ADDED
:
2728 case RMAP_EVENT_CALL_ADDED
:
2729 case RMAP_EVENT_FILTER_ADDED
:
2731 zlog_debug("Adding dependency for filter %s in route-map %s",
2732 dep_name
, rmap_name
);
2733 dep
= (struct route_map_dep
*)hash_get(
2734 dephash
, dname
, route_map_dep_hash_alloc
);
2740 if (!dep
->this_hash
)
2741 dep
->this_hash
= dephash
;
2743 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
2744 tmp_dep_data
.rname
= rname
;
2745 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
2747 dep_data
= hash_get(dep
->dep_rmap_hash
, &tmp_dep_data
,
2748 route_map_name_hash_alloc
);
2752 case RMAP_EVENT_PLIST_DELETED
:
2753 case RMAP_EVENT_CLIST_DELETED
:
2754 case RMAP_EVENT_ECLIST_DELETED
:
2755 case RMAP_EVENT_ASLIST_DELETED
:
2756 case RMAP_EVENT_LLIST_DELETED
:
2757 case RMAP_EVENT_CALL_DELETED
:
2758 case RMAP_EVENT_FILTER_DELETED
:
2760 zlog_debug("Deleting dependency for filter %s in route-map %s",
2761 dep_name
, rmap_name
);
2762 dep
= (struct route_map_dep
*)hash_get(dephash
, dname
, NULL
);
2767 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
2768 tmp_dep_data
.rname
= rname
;
2769 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
2771 * If dep_data is NULL then something has gone seriously
2772 * wrong in route-map handling. Note it and prevent
2777 "route-map dependency for route-map %s: %s is not correct",
2778 rmap_name
, dep_name
);
2784 if (!dep_data
->refcnt
) {
2785 ret_dep_data
= hash_release(dep
->dep_rmap_hash
,
2788 XFREE(MTYPE_ROUTE_MAP_NAME
,
2789 ret_dep_data
->rname
);
2790 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, ret_dep_data
);
2794 if (!dep
->dep_rmap_hash
->count
) {
2795 dep
= hash_release(dephash
, dname
);
2796 hash_free(dep
->dep_rmap_hash
);
2797 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
2798 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
2801 case RMAP_EVENT_SET_ADDED
:
2802 case RMAP_EVENT_SET_DELETED
:
2803 case RMAP_EVENT_SET_REPLACED
:
2804 case RMAP_EVENT_MATCH_ADDED
:
2805 case RMAP_EVENT_MATCH_DELETED
:
2806 case RMAP_EVENT_MATCH_REPLACED
:
2807 case RMAP_EVENT_INDEX_ADDED
:
2808 case RMAP_EVENT_INDEX_DELETED
:
2814 hash_iterate(dep
->dep_rmap_hash
,
2815 route_map_print_dependency
, dname
);
2819 XFREE(MTYPE_ROUTE_MAP_NAME
, rname
);
2820 XFREE(MTYPE_ROUTE_MAP_NAME
, dname
);
2824 static struct hash
*route_map_get_dep_hash(route_map_event_t event
)
2826 struct hash
*upd8_hash
= NULL
;
2829 case RMAP_EVENT_PLIST_ADDED
:
2830 case RMAP_EVENT_PLIST_DELETED
:
2831 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_PLIST
];
2833 case RMAP_EVENT_CLIST_ADDED
:
2834 case RMAP_EVENT_CLIST_DELETED
:
2835 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_CLIST
];
2837 case RMAP_EVENT_ECLIST_ADDED
:
2838 case RMAP_EVENT_ECLIST_DELETED
:
2839 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ECLIST
];
2841 case RMAP_EVENT_ASLIST_ADDED
:
2842 case RMAP_EVENT_ASLIST_DELETED
:
2843 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ASPATH
];
2845 case RMAP_EVENT_LLIST_ADDED
:
2846 case RMAP_EVENT_LLIST_DELETED
:
2847 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_LCLIST
];
2849 case RMAP_EVENT_CALL_ADDED
:
2850 case RMAP_EVENT_CALL_DELETED
:
2851 case RMAP_EVENT_MATCH_ADDED
:
2852 case RMAP_EVENT_MATCH_DELETED
:
2853 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_RMAP
];
2855 case RMAP_EVENT_FILTER_ADDED
:
2856 case RMAP_EVENT_FILTER_DELETED
:
2857 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_FILTER
];
2860 * Should we actually be ignoring these?
2861 * I am not sure but at this point in time, let
2862 * us get them into this switch and we can peel
2863 * them into the appropriate place in the future
2865 case RMAP_EVENT_SET_ADDED
:
2866 case RMAP_EVENT_SET_DELETED
:
2867 case RMAP_EVENT_SET_REPLACED
:
2868 case RMAP_EVENT_MATCH_REPLACED
:
2869 case RMAP_EVENT_INDEX_ADDED
:
2870 case RMAP_EVENT_INDEX_DELETED
:
2877 static void route_map_process_dependency(struct hash_bucket
*bucket
, void *data
)
2879 struct route_map_dep_data
*dep_data
= NULL
;
2880 char *rmap_name
= NULL
;
2882 dep_data
= bucket
->data
;
2883 rmap_name
= dep_data
->rname
;
2886 zlog_debug("Notifying %s of dependency", rmap_name
);
2887 if (route_map_master
.event_hook
)
2888 (*route_map_master
.event_hook
)(rmap_name
);
2891 void route_map_upd8_dependency(route_map_event_t type
, const char *arg
,
2892 const char *rmap_name
)
2894 struct hash
*upd8_hash
= NULL
;
2896 if ((upd8_hash
= route_map_get_dep_hash(type
))) {
2897 route_map_dep_update(upd8_hash
, arg
, rmap_name
, type
);
2899 if (type
== RMAP_EVENT_CALL_ADDED
) {
2901 if (route_map_master
.add_hook
)
2902 (*route_map_master
.add_hook
)(rmap_name
);
2903 } else if (type
== RMAP_EVENT_CALL_DELETED
) {
2905 if (route_map_master
.delete_hook
)
2906 (*route_map_master
.delete_hook
)(rmap_name
);
2911 void route_map_notify_dependencies(const char *affected_name
,
2912 route_map_event_t event
)
2914 struct route_map_dep
*dep
;
2915 struct hash
*upd8_hash
;
2921 name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, affected_name
);
2923 if ((upd8_hash
= route_map_get_dep_hash(event
)) == NULL
) {
2924 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
2928 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, name
, NULL
);
2930 if (!dep
->this_hash
)
2931 dep
->this_hash
= upd8_hash
;
2934 zlog_debug("Filter %s updated", dep
->dep_name
);
2935 hash_iterate(dep
->dep_rmap_hash
, route_map_process_dependency
,
2939 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
2942 /* VTY related functions. */
2943 DEFUN(no_routemap_optimization
, no_routemap_optimization_cmd
,
2944 "no route-map optimization",
2949 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2951 index
->map
->optimization_disabled
= true;
2955 DEFUN(routemap_optimization
, routemap_optimization_cmd
,
2956 "route-map optimization",
2960 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2962 index
->map
->optimization_disabled
= false;
2966 static void clear_route_map_helper(struct route_map
*map
)
2968 struct route_map_index
*index
;
2970 map
->applied_clear
= map
->applied
;
2971 for (index
= map
->head
; index
; index
= index
->next
)
2972 index
->applied_clear
= index
->applied
;
2975 DEFUN (rmap_clear_counters
,
2976 rmap_clear_counters_cmd
,
2977 "clear route-map counters [WORD]",
2979 "route-map information\n"
2980 "counters associated with the specified route-map\n"
2984 struct route_map
*map
;
2986 const char *name
= (argc
== 3 ) ? argv
[idx_word
]->arg
: NULL
;
2989 map
= route_map_lookup_by_name(name
);
2992 clear_route_map_helper(map
);
2994 vty_out(vty
, "%s: 'route-map %s' not found\n",
2995 frr_protonameinst
, name
);
2999 for (map
= route_map_master
.head
; map
; map
= map
->next
)
3000 clear_route_map_helper(map
);
3007 DEFUN (rmap_show_name
,
3009 "show route-map [WORD]",
3011 "route-map information\n"
3015 const char *name
= (argc
== 3) ? argv
[idx_word
]->arg
: NULL
;
3016 return vty_show_route_map(vty
, name
);
3019 DEFUN (rmap_show_unused
,
3020 rmap_show_unused_cmd
,
3021 "show route-map-unused",
3023 "unused route-map information\n")
3025 return vty_show_unused_route_map(vty
);
3032 "Debug option set for route-maps\n")
3038 DEFUN (no_debug_rmap
,
3040 "no debug route-map",
3043 "Debug option set for route-maps\n")
3050 static int rmap_config_write_debug(struct vty
*vty
);
3051 static struct cmd_node rmap_debug_node
= {
3052 .name
= "route-map debug",
3053 .node
= RMAP_DEBUG_NODE
,
3055 .config_write
= rmap_config_write_debug
,
3058 /* Configuration write function. */
3059 static int rmap_config_write_debug(struct vty
*vty
)
3064 vty_out(vty
, "debug route-map\n");
3071 /* Common route map rules */
3073 void *route_map_rule_tag_compile(const char *arg
)
3075 unsigned long int tmp
;
3080 tmp
= strtoul(arg
, &endptr
, 0);
3081 if (arg
[0] == '\0' || *endptr
!= '\0' || errno
|| tmp
> ROUTE_TAG_MAX
)
3084 tag
= XMALLOC(MTYPE_ROUTE_MAP_COMPILED
, sizeof(*tag
));
3090 void route_map_rule_tag_free(void *rule
)
3092 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
3095 void route_map_finish(void)
3099 vector_free(route_match_vec
);
3100 route_match_vec
= NULL
;
3101 vector_free(route_set_vec
);
3102 route_set_vec
= NULL
;
3105 * All protocols are setting these to NULL
3106 * by default on shutdown( route_map_finish )
3107 * Why are we making them do this work?
3109 route_map_master
.add_hook
= NULL
;
3110 route_map_master
.delete_hook
= NULL
;
3111 route_map_master
.event_hook
= NULL
;
3113 /* cleanup route_map */
3114 while (route_map_master
.head
) {
3115 struct route_map
*map
= route_map_master
.head
;
3116 map
->to_be_processed
= false;
3117 route_map_delete(map
);
3120 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
3121 hash_free(route_map_dep_hash
[i
]);
3122 route_map_dep_hash
[i
] = NULL
;
3125 hash_free(route_map_master_hash
);
3126 route_map_master_hash
= NULL
;
3129 /* Increment the use_count counter while attaching the route map */
3130 void route_map_counter_increment(struct route_map
*map
)
3136 /* Decrement the use_count counter while detaching the route map. */
3137 void route_map_counter_decrement(struct route_map
*map
)
3140 if (map
->use_count
<= 0)
3146 DEFUN_HIDDEN(show_route_map_pfx_tbl
, show_route_map_pfx_tbl_cmd
,
3147 "show route-map WORD prefix-table",
3151 "internal prefix-table\n")
3153 const char *rmap_name
= argv
[2]->arg
;
3154 struct route_map
*rmap
= NULL
;
3155 struct route_table
*rm_pfx_tbl4
= NULL
;
3156 struct route_table
*rm_pfx_tbl6
= NULL
;
3157 struct route_node
*rn
= NULL
, *prn
= NULL
;
3158 struct list
*rmap_index_list
= NULL
;
3159 struct listnode
*ln
= NULL
, *nln
= NULL
;
3160 struct route_map_index
*index
= NULL
;
3163 vty_out(vty
, "%s:\n", frr_protonameinst
);
3164 rmap
= route_map_lookup_by_name(rmap_name
);
3166 rm_pfx_tbl4
= rmap
->ipv4_prefix_table
;
3168 vty_out(vty
, "\n%s%43s%s\n", "IPv4 Prefix", "",
3169 "Route-map Index List");
3170 vty_out(vty
, "%s%39s%s\n", "_______________", "",
3171 "____________________");
3172 for (rn
= route_top(rm_pfx_tbl4
); rn
;
3173 rn
= route_next(rn
)) {
3174 vty_out(vty
, " %pRN (%d)\n", rn
,
3175 route_node_get_lock_count(rn
));
3177 vty_out(vty
, "(P) ");
3180 vty_out(vty
, "%pRN\n", prn
);
3184 rmap_index_list
= (struct list
*)rn
->info
;
3185 if (!rmap_index_list
3186 || !listcount(rmap_index_list
))
3187 vty_out(vty
, "%*s%s\n", len
, "", "-");
3189 for (ALL_LIST_ELEMENTS(rmap_index_list
,
3192 vty_out(vty
, "%*s%s seq %d\n",
3201 rm_pfx_tbl6
= rmap
->ipv6_prefix_table
;
3203 vty_out(vty
, "\n%s%43s%s\n", "IPv6 Prefix", "",
3204 "Route-map Index List");
3205 vty_out(vty
, "%s%39s%s\n", "_______________", "",
3206 "____________________");
3207 for (rn
= route_top(rm_pfx_tbl6
); rn
;
3208 rn
= route_next(rn
)) {
3209 vty_out(vty
, " %pRN (%d)\n", rn
,
3210 route_node_get_lock_count(rn
));
3212 vty_out(vty
, "(P) ");
3215 vty_out(vty
, "%pRN\n", prn
);
3219 rmap_index_list
= (struct list
*)rn
->info
;
3220 if (!rmap_index_list
3221 || !listcount(rmap_index_list
))
3222 vty_out(vty
, "%*s%s\n", len
, "", "-");
3224 for (ALL_LIST_ELEMENTS(rmap_index_list
,
3227 vty_out(vty
, "%*s%s seq %d\n",
3241 /* Initialization of route map vector. */
3242 void route_map_init(void)
3246 /* Make vector for match and set. */
3247 route_match_vec
= vector_init(1);
3248 route_set_vec
= vector_init(1);
3249 route_map_master_hash
=
3250 hash_create_size(8, route_map_hash_key_make
, route_map_hash_cmp
,
3251 "Route Map Master Hash");
3253 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++)
3254 route_map_dep_hash
[i
] = hash_create_size(
3255 8, route_map_dep_hash_make_key
, route_map_dep_hash_cmp
,
3256 "Route Map Dep Hash");
3260 route_map_cli_init();
3262 /* Install route map top node. */
3263 install_node(&rmap_debug_node
);
3265 /* Install route map commands. */
3266 install_element(CONFIG_NODE
, &debug_rmap_cmd
);
3267 install_element(CONFIG_NODE
, &no_debug_rmap_cmd
);
3269 /* Install show command */
3270 install_element(ENABLE_NODE
, &rmap_clear_counters_cmd
);
3272 install_element(ENABLE_NODE
, &rmap_show_name_cmd
);
3273 install_element(ENABLE_NODE
, &rmap_show_unused_cmd
);
3275 install_element(ENABLE_NODE
, &debug_rmap_cmd
);
3276 install_element(ENABLE_NODE
, &no_debug_rmap_cmd
);
3278 install_element(RMAP_NODE
, &routemap_optimization_cmd
);
3279 install_element(RMAP_NODE
, &no_routemap_optimization_cmd
);
3281 install_element(RMAP_NODE
, &set_srte_color_cmd
);
3282 install_element(RMAP_NODE
, &no_set_srte_color_cmd
);
3284 install_element(ENABLE_NODE
, &show_route_map_pfx_tbl_cmd
);