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
*bucket
,
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
*)bucket
->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
);
2405 "Best match route-map: %s, sequence: %d for pfx: %pFX, result: %s",
2406 map
->name
, index
->pref
, prefix
,
2407 route_map_cmd_result_str(match_ret
));
2411 "No best match sequence for pfx: %pFX in route-map: %s, result: %s",
2413 route_map_cmd_result_str(match_ret
));
2415 * No index matches this prefix. Return deny unless,
2416 * match_ret = RMAP_NOOP.
2418 if (match_ret
== RMAP_NOOP
)
2419 ret
= RMAP_PERMITMATCH
;
2421 ret
= RMAP_DENYMATCH
;
2422 goto route_map_apply_end
;
2424 skip_match_clause
= true;
2429 for (; index
; index
= index
->next
) {
2430 if (!skip_match_clause
) {
2432 /* Apply this index. */
2433 match_ret
= route_map_apply_match(&index
->match_list
,
2437 "Route-map: %s, sequence: %d, prefix: %pFX, result: %s",
2438 map
->name
, index
->pref
, prefix
,
2439 route_map_cmd_result_str(match_ret
));
2442 skip_match_clause
= false;
2445 /* Now we apply the matrix from above */
2446 if (match_ret
== RMAP_NOOP
)
2448 * Do not change the return value. Retain the previous
2449 * return value. Previous values can be:
2450 * 1)permitmatch (if a nomatch was never
2451 * seen before in this route-map.)
2452 * 2)denymatch (if a nomatch was seen earlier in one
2453 * of the previous sequences)
2457 * 'cont' from matrix - continue to next route-map
2461 else if (match_ret
== RMAP_NOMATCH
) {
2464 * The return value is now changed to denymatch.
2465 * So from here on out, even if we see more noops,
2466 * we retain this return value and return this
2467 * eventually if there are no matches.
2469 ret
= RMAP_DENYMATCH
;
2472 * 'cont' from matrix - continue to next route-map
2476 } else if (match_ret
== RMAP_MATCH
) {
2477 if (index
->type
== RMAP_PERMIT
)
2480 /* Match succeeded, rmap is of type permit */
2481 ret
= RMAP_PERMITMATCH
;
2483 /* permit+match must execute sets */
2484 for (set
= index
->set_list
.head
; set
;
2487 * set cmds return RMAP_OKAY or
2488 * RMAP_ERROR. We do not care if
2489 * set succeeded or not. So, ignore
2492 (void)(*set
->cmd
->func_apply
)(
2493 set
->value
, prefix
, object
);
2495 /* Call another route-map if available */
2496 if (index
->nextrm
) {
2497 struct route_map
*nextrm
=
2498 route_map_lookup_by_name(
2501 if (nextrm
) /* Target route-map found,
2505 ret
= route_map_apply(
2506 nextrm
, prefix
, object
);
2510 /* If nextrm returned 'deny', finish. */
2511 if (ret
== RMAP_DENYMATCH
)
2512 goto route_map_apply_end
;
2515 switch (index
->exitpolicy
) {
2517 goto route_map_apply_end
;
2521 /* Find the next clause to jump to */
2522 struct route_map_index
*next
=
2524 int nextpref
= index
->nextpref
;
2526 while (next
&& next
->pref
< nextpref
) {
2531 /* No clauses match! */
2532 goto route_map_apply_end
;
2536 } else if (index
->type
== RMAP_DENY
)
2539 ret
= RMAP_DENYMATCH
;
2540 goto route_map_apply_end
;
2545 route_map_apply_end
:
2547 zlog_debug("Route-map: %s, prefix: %pFX, result: %s",
2548 (map
? map
->name
: "null"), prefix
,
2549 route_map_result_str(ret
));
2554 void route_map_add_hook(void (*func
)(const char *))
2556 route_map_master
.add_hook
= func
;
2559 void route_map_delete_hook(void (*func
)(const char *))
2561 route_map_master
.delete_hook
= func
;
2564 void route_map_event_hook(void (*func
)(const char *name
))
2566 route_map_master
.event_hook
= func
;
2569 /* Routines for route map dependency lists and dependency processing */
2570 static bool route_map_rmap_hash_cmp(const void *p1
, const void *p2
)
2572 return strcmp(((const struct route_map_dep_data
*)p1
)->rname
,
2573 ((const struct route_map_dep_data
*)p2
)->rname
)
2577 static bool route_map_dep_hash_cmp(const void *p1
, const void *p2
)
2580 return (strcmp(((const struct route_map_dep
*)p1
)->dep_name
,
2585 static void route_map_clear_reference(struct hash_bucket
*bucket
, void *arg
)
2587 struct route_map_dep
*dep
= bucket
->data
;
2588 struct route_map_dep_data
*dep_data
= NULL
, tmp_dep_data
;
2590 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
2591 tmp_dep_data
.rname
= arg
;
2592 dep_data
= hash_release(dep
->dep_rmap_hash
, &tmp_dep_data
);
2595 zlog_debug("Clearing reference for %s to %s count: %d",
2596 dep
->dep_name
, tmp_dep_data
.rname
,
2599 XFREE(MTYPE_ROUTE_MAP_NAME
, dep_data
->rname
);
2600 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, dep_data
);
2602 if (!dep
->dep_rmap_hash
->count
) {
2603 dep
= hash_release(dep
->this_hash
, (void *)dep
->dep_name
);
2604 hash_free(dep
->dep_rmap_hash
);
2605 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
2606 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
2610 static void route_map_clear_all_references(char *rmap_name
)
2615 zlog_debug("Clearing references for %s", rmap_name
);
2617 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
2618 hash_iterate(route_map_dep_hash
[i
], route_map_clear_reference
,
2623 static unsigned int route_map_dep_data_hash_make_key(const void *p
)
2625 const struct route_map_dep_data
*dep_data
= p
;
2627 return string_hash_make(dep_data
->rname
);
2630 DEFUN (set_srte_color
,
2632 "set sr-te color [(1-4294967295)]",
2636 "Color of the SR-TE Policies to match with\n")
2638 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2640 char *arg
= argv_find(argv
, argc
, "(1-4294967295)", &idx
)
2644 if (rmap_match_set_hook
.set_srte_color
)
2645 return rmap_match_set_hook
.set_srte_color(vty
, index
,
2646 "sr-te color", arg
);
2650 DEFUN (no_set_srte_color
,
2651 no_set_srte_color_cmd
,
2652 "no set sr-te color [(1-4294967295)]",
2657 "Color of the SR-TE Policies to match with\n")
2659 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2661 char *arg
= argv_find(argv
, argc
, "(1-4294967295)", &idx
)
2665 if (rmap_match_set_hook
.no_set_srte_color
)
2666 return rmap_match_set_hook
.no_set_srte_color(
2667 vty
, index
, "sr-te color", arg
);
2671 static void *route_map_dep_hash_alloc(void *p
)
2673 char *dep_name
= (char *)p
;
2674 struct route_map_dep
*dep_entry
;
2676 dep_entry
= XCALLOC(MTYPE_ROUTE_MAP_DEP
, sizeof(struct route_map_dep
));
2677 dep_entry
->dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
2678 dep_entry
->dep_rmap_hash
=
2679 hash_create_size(8, route_map_dep_data_hash_make_key
,
2680 route_map_rmap_hash_cmp
, "Route Map Dep Hash");
2681 dep_entry
->this_hash
= NULL
;
2686 static void *route_map_name_hash_alloc(void *p
)
2688 struct route_map_dep_data
*dep_data
= NULL
, *tmp_dep_data
= NULL
;
2690 dep_data
= XCALLOC(MTYPE_ROUTE_MAP_DEP_DATA
,
2691 sizeof(struct route_map_dep_data
));
2693 dep_data
->rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, tmp_dep_data
->rname
);
2697 static unsigned int route_map_dep_hash_make_key(const void *p
)
2699 return (string_hash_make((char *)p
));
2702 static void route_map_print_dependency(struct hash_bucket
*bucket
, void *data
)
2704 struct route_map_dep_data
*dep_data
= bucket
->data
;
2705 char *rmap_name
= dep_data
->rname
;
2706 char *dep_name
= data
;
2708 zlog_debug("%s: Dependency for %s: %s", __func__
, dep_name
, rmap_name
);
2711 static int route_map_dep_update(struct hash
*dephash
, const char *dep_name
,
2712 const char *rmap_name
, route_map_event_t type
)
2714 struct route_map_dep
*dep
= NULL
;
2715 char *dname
, *rname
;
2717 struct route_map_dep_data
*dep_data
= NULL
, *ret_dep_data
= NULL
;
2718 struct route_map_dep_data tmp_dep_data
;
2720 dname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
2721 rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
2724 case RMAP_EVENT_PLIST_ADDED
:
2725 case RMAP_EVENT_CLIST_ADDED
:
2726 case RMAP_EVENT_ECLIST_ADDED
:
2727 case RMAP_EVENT_ASLIST_ADDED
:
2728 case RMAP_EVENT_LLIST_ADDED
:
2729 case RMAP_EVENT_CALL_ADDED
:
2730 case RMAP_EVENT_FILTER_ADDED
:
2732 zlog_debug("Adding dependency for filter %s in route-map %s",
2733 dep_name
, rmap_name
);
2734 dep
= (struct route_map_dep
*)hash_get(
2735 dephash
, dname
, route_map_dep_hash_alloc
);
2741 if (!dep
->this_hash
)
2742 dep
->this_hash
= dephash
;
2744 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
2745 tmp_dep_data
.rname
= rname
;
2746 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
2748 dep_data
= hash_get(dep
->dep_rmap_hash
, &tmp_dep_data
,
2749 route_map_name_hash_alloc
);
2753 case RMAP_EVENT_PLIST_DELETED
:
2754 case RMAP_EVENT_CLIST_DELETED
:
2755 case RMAP_EVENT_ECLIST_DELETED
:
2756 case RMAP_EVENT_ASLIST_DELETED
:
2757 case RMAP_EVENT_LLIST_DELETED
:
2758 case RMAP_EVENT_CALL_DELETED
:
2759 case RMAP_EVENT_FILTER_DELETED
:
2761 zlog_debug("Deleting dependency for filter %s in route-map %s",
2762 dep_name
, rmap_name
);
2763 dep
= (struct route_map_dep
*)hash_get(dephash
, dname
, NULL
);
2768 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
2769 tmp_dep_data
.rname
= rname
;
2770 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
2772 * If dep_data is NULL then something has gone seriously
2773 * wrong in route-map handling. Note it and prevent
2778 "route-map dependency for route-map %s: %s is not correct",
2779 rmap_name
, dep_name
);
2785 if (!dep_data
->refcnt
) {
2786 ret_dep_data
= hash_release(dep
->dep_rmap_hash
,
2789 XFREE(MTYPE_ROUTE_MAP_NAME
,
2790 ret_dep_data
->rname
);
2791 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, ret_dep_data
);
2795 if (!dep
->dep_rmap_hash
->count
) {
2796 dep
= hash_release(dephash
, dname
);
2797 hash_free(dep
->dep_rmap_hash
);
2798 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
2799 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
2802 case RMAP_EVENT_SET_ADDED
:
2803 case RMAP_EVENT_SET_DELETED
:
2804 case RMAP_EVENT_SET_REPLACED
:
2805 case RMAP_EVENT_MATCH_ADDED
:
2806 case RMAP_EVENT_MATCH_DELETED
:
2807 case RMAP_EVENT_MATCH_REPLACED
:
2808 case RMAP_EVENT_INDEX_ADDED
:
2809 case RMAP_EVENT_INDEX_DELETED
:
2815 hash_iterate(dep
->dep_rmap_hash
,
2816 route_map_print_dependency
, dname
);
2820 XFREE(MTYPE_ROUTE_MAP_NAME
, rname
);
2821 XFREE(MTYPE_ROUTE_MAP_NAME
, dname
);
2825 static struct hash
*route_map_get_dep_hash(route_map_event_t event
)
2827 struct hash
*upd8_hash
= NULL
;
2830 case RMAP_EVENT_PLIST_ADDED
:
2831 case RMAP_EVENT_PLIST_DELETED
:
2832 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_PLIST
];
2834 case RMAP_EVENT_CLIST_ADDED
:
2835 case RMAP_EVENT_CLIST_DELETED
:
2836 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_CLIST
];
2838 case RMAP_EVENT_ECLIST_ADDED
:
2839 case RMAP_EVENT_ECLIST_DELETED
:
2840 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ECLIST
];
2842 case RMAP_EVENT_ASLIST_ADDED
:
2843 case RMAP_EVENT_ASLIST_DELETED
:
2844 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ASPATH
];
2846 case RMAP_EVENT_LLIST_ADDED
:
2847 case RMAP_EVENT_LLIST_DELETED
:
2848 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_LCLIST
];
2850 case RMAP_EVENT_CALL_ADDED
:
2851 case RMAP_EVENT_CALL_DELETED
:
2852 case RMAP_EVENT_MATCH_ADDED
:
2853 case RMAP_EVENT_MATCH_DELETED
:
2854 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_RMAP
];
2856 case RMAP_EVENT_FILTER_ADDED
:
2857 case RMAP_EVENT_FILTER_DELETED
:
2858 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_FILTER
];
2861 * Should we actually be ignoring these?
2862 * I am not sure but at this point in time, let
2863 * us get them into this switch and we can peel
2864 * them into the appropriate place in the future
2866 case RMAP_EVENT_SET_ADDED
:
2867 case RMAP_EVENT_SET_DELETED
:
2868 case RMAP_EVENT_SET_REPLACED
:
2869 case RMAP_EVENT_MATCH_REPLACED
:
2870 case RMAP_EVENT_INDEX_ADDED
:
2871 case RMAP_EVENT_INDEX_DELETED
:
2878 static void route_map_process_dependency(struct hash_bucket
*bucket
, void *data
)
2880 struct route_map_dep_data
*dep_data
= NULL
;
2881 char *rmap_name
= NULL
;
2883 dep_data
= bucket
->data
;
2884 rmap_name
= dep_data
->rname
;
2887 zlog_debug("Notifying %s of dependency", rmap_name
);
2888 if (route_map_master
.event_hook
)
2889 (*route_map_master
.event_hook
)(rmap_name
);
2892 void route_map_upd8_dependency(route_map_event_t type
, const char *arg
,
2893 const char *rmap_name
)
2895 struct hash
*upd8_hash
= NULL
;
2897 if ((upd8_hash
= route_map_get_dep_hash(type
))) {
2898 route_map_dep_update(upd8_hash
, arg
, rmap_name
, type
);
2900 if (type
== RMAP_EVENT_CALL_ADDED
) {
2902 if (route_map_master
.add_hook
)
2903 (*route_map_master
.add_hook
)(rmap_name
);
2904 } else if (type
== RMAP_EVENT_CALL_DELETED
) {
2906 if (route_map_master
.delete_hook
)
2907 (*route_map_master
.delete_hook
)(rmap_name
);
2912 void route_map_notify_dependencies(const char *affected_name
,
2913 route_map_event_t event
)
2915 struct route_map_dep
*dep
;
2916 struct hash
*upd8_hash
;
2922 name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, affected_name
);
2924 if ((upd8_hash
= route_map_get_dep_hash(event
)) == NULL
) {
2925 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
2929 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, name
, NULL
);
2931 if (!dep
->this_hash
)
2932 dep
->this_hash
= upd8_hash
;
2935 zlog_debug("Filter %s updated", dep
->dep_name
);
2936 hash_iterate(dep
->dep_rmap_hash
, route_map_process_dependency
,
2940 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
2943 /* VTY related functions. */
2944 DEFUN(no_routemap_optimization
, no_routemap_optimization_cmd
,
2945 "no route-map optimization",
2950 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2952 index
->map
->optimization_disabled
= true;
2956 DEFUN(routemap_optimization
, routemap_optimization_cmd
,
2957 "route-map optimization",
2961 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2963 index
->map
->optimization_disabled
= false;
2967 static void clear_route_map_helper(struct route_map
*map
)
2969 struct route_map_index
*index
;
2971 map
->applied_clear
= map
->applied
;
2972 for (index
= map
->head
; index
; index
= index
->next
)
2973 index
->applied_clear
= index
->applied
;
2976 DEFUN (rmap_clear_counters
,
2977 rmap_clear_counters_cmd
,
2978 "clear route-map counters [WORD]",
2980 "route-map information\n"
2981 "counters associated with the specified route-map\n"
2985 struct route_map
*map
;
2987 const char *name
= (argc
== 3 ) ? argv
[idx_word
]->arg
: NULL
;
2990 map
= route_map_lookup_by_name(name
);
2993 clear_route_map_helper(map
);
2995 vty_out(vty
, "%s: 'route-map %s' not found\n",
2996 frr_protonameinst
, name
);
3000 for (map
= route_map_master
.head
; map
; map
= map
->next
)
3001 clear_route_map_helper(map
);
3008 DEFUN (rmap_show_name
,
3010 "show route-map [WORD]",
3012 "route-map information\n"
3016 const char *name
= (argc
== 3) ? argv
[idx_word
]->arg
: NULL
;
3017 return vty_show_route_map(vty
, name
);
3020 DEFUN (rmap_show_unused
,
3021 rmap_show_unused_cmd
,
3022 "show route-map-unused",
3024 "unused route-map information\n")
3026 return vty_show_unused_route_map(vty
);
3033 "Debug option set for route-maps\n")
3039 DEFUN (no_debug_rmap
,
3041 "no debug route-map",
3044 "Debug option set for route-maps\n")
3051 static int rmap_config_write_debug(struct vty
*vty
);
3052 static struct cmd_node rmap_debug_node
= {
3053 .name
= "route-map debug",
3054 .node
= RMAP_DEBUG_NODE
,
3056 .config_write
= rmap_config_write_debug
,
3059 /* Configuration write function. */
3060 static int rmap_config_write_debug(struct vty
*vty
)
3065 vty_out(vty
, "debug route-map\n");
3072 /* Common route map rules */
3074 void *route_map_rule_tag_compile(const char *arg
)
3076 unsigned long int tmp
;
3081 tmp
= strtoul(arg
, &endptr
, 0);
3082 if (arg
[0] == '\0' || *endptr
!= '\0' || errno
|| tmp
> ROUTE_TAG_MAX
)
3085 tag
= XMALLOC(MTYPE_ROUTE_MAP_COMPILED
, sizeof(*tag
));
3091 void route_map_rule_tag_free(void *rule
)
3093 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
3096 void route_map_finish(void)
3100 vector_free(route_match_vec
);
3101 route_match_vec
= NULL
;
3102 vector_free(route_set_vec
);
3103 route_set_vec
= NULL
;
3106 * All protocols are setting these to NULL
3107 * by default on shutdown( route_map_finish )
3108 * Why are we making them do this work?
3110 route_map_master
.add_hook
= NULL
;
3111 route_map_master
.delete_hook
= NULL
;
3112 route_map_master
.event_hook
= NULL
;
3114 /* cleanup route_map */
3115 while (route_map_master
.head
) {
3116 struct route_map
*map
= route_map_master
.head
;
3117 map
->to_be_processed
= false;
3118 route_map_delete(map
);
3121 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
3122 hash_free(route_map_dep_hash
[i
]);
3123 route_map_dep_hash
[i
] = NULL
;
3126 hash_free(route_map_master_hash
);
3127 route_map_master_hash
= NULL
;
3130 /* Increment the use_count counter while attaching the route map */
3131 void route_map_counter_increment(struct route_map
*map
)
3137 /* Decrement the use_count counter while detaching the route map. */
3138 void route_map_counter_decrement(struct route_map
*map
)
3141 if (map
->use_count
<= 0)
3147 DEFUN_HIDDEN(show_route_map_pfx_tbl
, show_route_map_pfx_tbl_cmd
,
3148 "show route-map WORD prefix-table",
3152 "internal prefix-table\n")
3154 const char *rmap_name
= argv
[2]->arg
;
3155 struct route_map
*rmap
= NULL
;
3156 struct route_table
*rm_pfx_tbl4
= NULL
;
3157 struct route_table
*rm_pfx_tbl6
= NULL
;
3158 struct route_node
*rn
= NULL
, *prn
= NULL
;
3159 struct list
*rmap_index_list
= NULL
;
3160 struct listnode
*ln
= NULL
, *nln
= NULL
;
3161 struct route_map_index
*index
= NULL
;
3164 vty_out(vty
, "%s:\n", frr_protonameinst
);
3165 rmap
= route_map_lookup_by_name(rmap_name
);
3167 rm_pfx_tbl4
= rmap
->ipv4_prefix_table
;
3169 vty_out(vty
, "\n%s%43s%s\n", "IPv4 Prefix", "",
3170 "Route-map Index List");
3171 vty_out(vty
, "%s%39s%s\n", "_______________", "",
3172 "____________________");
3173 for (rn
= route_top(rm_pfx_tbl4
); rn
;
3174 rn
= route_next(rn
)) {
3175 vty_out(vty
, " %pRN (%d)\n", rn
,
3176 route_node_get_lock_count(rn
));
3178 vty_out(vty
, "(P) ");
3181 vty_out(vty
, "%pRN\n", prn
);
3185 rmap_index_list
= (struct list
*)rn
->info
;
3186 if (!rmap_index_list
3187 || !listcount(rmap_index_list
))
3188 vty_out(vty
, "%*s%s\n", len
, "", "-");
3190 for (ALL_LIST_ELEMENTS(rmap_index_list
,
3193 vty_out(vty
, "%*s%s seq %d\n",
3202 rm_pfx_tbl6
= rmap
->ipv6_prefix_table
;
3204 vty_out(vty
, "\n%s%43s%s\n", "IPv6 Prefix", "",
3205 "Route-map Index List");
3206 vty_out(vty
, "%s%39s%s\n", "_______________", "",
3207 "____________________");
3208 for (rn
= route_top(rm_pfx_tbl6
); rn
;
3209 rn
= route_next(rn
)) {
3210 vty_out(vty
, " %pRN (%d)\n", rn
,
3211 route_node_get_lock_count(rn
));
3213 vty_out(vty
, "(P) ");
3216 vty_out(vty
, "%pRN\n", prn
);
3220 rmap_index_list
= (struct list
*)rn
->info
;
3221 if (!rmap_index_list
3222 || !listcount(rmap_index_list
))
3223 vty_out(vty
, "%*s%s\n", len
, "", "-");
3225 for (ALL_LIST_ELEMENTS(rmap_index_list
,
3228 vty_out(vty
, "%*s%s seq %d\n",
3242 /* Initialization of route map vector. */
3243 void route_map_init(void)
3247 /* Make vector for match and set. */
3248 route_match_vec
= vector_init(1);
3249 route_set_vec
= vector_init(1);
3250 route_map_master_hash
=
3251 hash_create_size(8, route_map_hash_key_make
, route_map_hash_cmp
,
3252 "Route Map Master Hash");
3254 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++)
3255 route_map_dep_hash
[i
] = hash_create_size(
3256 8, route_map_dep_hash_make_key
, route_map_dep_hash_cmp
,
3257 "Route Map Dep Hash");
3261 route_map_cli_init();
3263 /* Install route map top node. */
3264 install_node(&rmap_debug_node
);
3266 /* Install route map commands. */
3267 install_element(CONFIG_NODE
, &debug_rmap_cmd
);
3268 install_element(CONFIG_NODE
, &no_debug_rmap_cmd
);
3270 /* Install show command */
3271 install_element(ENABLE_NODE
, &rmap_clear_counters_cmd
);
3273 install_element(ENABLE_NODE
, &rmap_show_name_cmd
);
3274 install_element(ENABLE_NODE
, &rmap_show_unused_cmd
);
3276 install_element(ENABLE_NODE
, &debug_rmap_cmd
);
3277 install_element(ENABLE_NODE
, &no_debug_rmap_cmd
);
3279 install_element(RMAP_NODE
, &routemap_optimization_cmd
);
3280 install_element(RMAP_NODE
, &no_routemap_optimization_cmd
);
3282 install_element(RMAP_NODE
, &set_srte_color_cmd
);
3283 install_element(RMAP_NODE
, &no_set_srte_color_cmd
);
3285 install_element(ENABLE_NODE
, &show_route_map_pfx_tbl_cmd
);