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"
35 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP
, "Route map")
36 DEFINE_MTYPE(LIB
, ROUTE_MAP_NAME
, "Route map name")
37 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_INDEX
, "Route map index")
38 DEFINE_MTYPE(LIB
, ROUTE_MAP_RULE
, "Route map rule")
39 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_RULE_STR
, "Route map rule str")
40 DEFINE_MTYPE(LIB
, ROUTE_MAP_COMPILED
, "Route map compiled")
41 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_DEP
, "Route map dependency")
42 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_DEP_DATA
, "Route map dependency data")
44 DEFINE_QOBJ_TYPE(route_map_index
)
45 DEFINE_QOBJ_TYPE(route_map
)
47 /* Vector for route match rules. */
48 static vector route_match_vec
;
50 /* Vector for route set rules. */
51 static vector route_set_vec
;
53 struct route_map_match_set_hooks
{
55 int (*match_interface
)(struct vty
*vty
, struct route_map_index
*index
,
56 const char *command
, const char *arg
,
57 route_map_event_t type
);
59 /* no match interface */
60 int (*no_match_interface
)(struct vty
*vty
,
61 struct route_map_index
*index
,
62 const char *command
, const char *arg
,
63 route_map_event_t type
);
65 /* match ip address */
66 int (*match_ip_address
)(struct vty
*vty
, struct route_map_index
*index
,
67 const char *command
, const char *arg
,
68 route_map_event_t type
);
70 /* no match ip address */
71 int (*no_match_ip_address
)(struct vty
*vty
,
72 struct route_map_index
*index
,
73 const char *command
, const char *arg
,
74 route_map_event_t type
);
76 /* match ip address prefix list */
77 int (*match_ip_address_prefix_list
)(struct vty
*vty
,
78 struct route_map_index
*index
,
81 route_map_event_t type
);
83 /* no match ip address prefix list */
84 int (*no_match_ip_address_prefix_list
)(struct vty
*vty
,
85 struct route_map_index
*index
,
88 route_map_event_t type
);
90 /* match ip next hop */
91 int (*match_ip_next_hop
)(struct vty
*vty
, struct route_map_index
*index
,
92 const char *command
, const char *arg
,
93 route_map_event_t type
);
95 /* no match ip next hop */
96 int (*no_match_ip_next_hop
)(struct vty
*vty
,
97 struct route_map_index
*index
,
98 const char *command
, const char *arg
,
99 route_map_event_t type
);
101 /* match ip next hop prefix list */
102 int (*match_ip_next_hop_prefix_list
)(struct vty
*vty
,
103 struct route_map_index
*index
,
106 route_map_event_t type
);
108 /* no match ip next hop prefix list */
109 int (*no_match_ip_next_hop_prefix_list
)(struct vty
*vty
,
110 struct route_map_index
*index
,
113 route_map_event_t type
);
115 /* match ip next-hop type */
116 int (*match_ip_next_hop_type
)(struct vty
*vty
,
117 struct route_map_index
*index
,
120 route_map_event_t type
);
122 /* no match ip next-hop type */
123 int (*no_match_ip_next_hop_type
)(struct vty
*vty
,
124 struct route_map_index
*index
,
127 route_map_event_t type
);
129 /* match ipv6 address */
130 int (*match_ipv6_address
)(struct vty
*vty
,
131 struct route_map_index
*index
,
132 const char *command
, const char *arg
,
133 route_map_event_t type
);
135 /* no match ipv6 address */
136 int (*no_match_ipv6_address
)(struct vty
*vty
,
137 struct route_map_index
*index
,
138 const char *command
, const char *arg
,
139 route_map_event_t type
);
142 /* match ipv6 address prefix list */
143 int (*match_ipv6_address_prefix_list
)(struct vty
*vty
,
144 struct route_map_index
*index
,
147 route_map_event_t type
);
149 /* no match ipv6 address prefix list */
150 int (*no_match_ipv6_address_prefix_list
)(struct vty
*vty
,
151 struct route_map_index
*index
,
154 route_map_event_t type
);
156 /* match ipv6 next-hop type */
157 int (*match_ipv6_next_hop_type
)(struct vty
*vty
,
158 struct route_map_index
*index
,
161 route_map_event_t type
);
163 /* no match ipv6 next-hop type */
164 int (*no_match_ipv6_next_hop_type
)(struct vty
*vty
,
165 struct route_map_index
*index
,
166 const char *command
, const char *arg
,
167 route_map_event_t type
);
170 int (*match_metric
)(struct vty
*vty
, struct route_map_index
*index
,
171 const char *command
, const char *arg
,
172 route_map_event_t type
);
174 /* no match metric */
175 int (*no_match_metric
)(struct vty
*vty
, struct route_map_index
*index
,
176 const char *command
, const char *arg
,
177 route_map_event_t type
);
180 int (*match_tag
)(struct vty
*vty
, struct route_map_index
*index
,
181 const char *command
, const char *arg
,
182 route_map_event_t type
);
185 int (*no_match_tag
)(struct vty
*vty
, struct route_map_index
*index
,
186 const char *command
, const char *arg
,
187 route_map_event_t type
);
190 int (*set_ip_nexthop
)(struct vty
*vty
, struct route_map_index
*index
,
191 const char *command
, const char *arg
);
193 /* no set ip nexthop */
194 int (*no_set_ip_nexthop
)(struct vty
*vty
, struct route_map_index
*index
,
195 const char *command
, const char *arg
);
197 /* set ipv6 nexthop local */
198 int (*set_ipv6_nexthop_local
)(struct vty
*vty
,
199 struct route_map_index
*index
,
200 const char *command
, const char *arg
);
202 /* no set ipv6 nexthop local */
203 int (*no_set_ipv6_nexthop_local
)(struct vty
*vty
,
204 struct route_map_index
*index
,
205 const char *command
, const char *arg
);
208 int (*set_metric
)(struct vty
*vty
, struct route_map_index
*index
,
209 const char *command
, const char *arg
);
212 int (*no_set_metric
)(struct vty
*vty
, struct route_map_index
*index
,
213 const char *command
, const char *arg
);
216 int (*set_tag
)(struct vty
*vty
, struct route_map_index
*index
,
217 const char *command
, const char *arg
);
220 int (*no_set_tag
)(struct vty
*vty
, struct route_map_index
*index
,
221 const char *command
, const char *arg
);
224 struct route_map_match_set_hooks rmap_match_set_hook
;
226 /* match interface */
227 void route_map_match_interface_hook(int (*func
)(
228 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
229 const char *arg
, route_map_event_t type
))
231 rmap_match_set_hook
.match_interface
= func
;
234 /* no match interface */
235 void route_map_no_match_interface_hook(int (*func
)(
236 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
237 const char *arg
, route_map_event_t type
))
239 rmap_match_set_hook
.no_match_interface
= func
;
242 /* match ip address */
243 void route_map_match_ip_address_hook(int (*func
)(
244 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
245 const char *arg
, route_map_event_t type
))
247 rmap_match_set_hook
.match_ip_address
= func
;
250 /* no match ip address */
251 void route_map_no_match_ip_address_hook(int (*func
)(
252 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
253 const char *arg
, route_map_event_t type
))
255 rmap_match_set_hook
.no_match_ip_address
= func
;
258 /* match ip address prefix list */
259 void route_map_match_ip_address_prefix_list_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
.match_ip_address_prefix_list
= func
;
266 /* no match ip address prefix list */
267 void route_map_no_match_ip_address_prefix_list_hook(int (*func
)(
268 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
269 const char *arg
, route_map_event_t type
))
271 rmap_match_set_hook
.no_match_ip_address_prefix_list
= func
;
274 /* match ip next hop */
275 void route_map_match_ip_next_hop_hook(int (*func
)(
276 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
277 const char *arg
, route_map_event_t type
))
279 rmap_match_set_hook
.match_ip_next_hop
= func
;
282 /* no match ip next hop */
283 void route_map_no_match_ip_next_hop_hook(int (*func
)(
284 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
285 const char *arg
, route_map_event_t type
))
287 rmap_match_set_hook
.no_match_ip_next_hop
= func
;
290 /* match ip next hop prefix list */
291 void route_map_match_ip_next_hop_prefix_list_hook(int (*func
)(
292 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
293 const char *arg
, route_map_event_t type
))
295 rmap_match_set_hook
.match_ip_next_hop_prefix_list
= func
;
298 /* no match ip next hop prefix list */
299 void route_map_no_match_ip_next_hop_prefix_list_hook(int (*func
)(
300 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
301 const char *arg
, route_map_event_t type
))
303 rmap_match_set_hook
.no_match_ip_next_hop_prefix_list
= func
;
306 /* match ip next-hop type */
307 void route_map_match_ip_next_hop_type_hook(int (*func
)(
308 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
309 const char *arg
, route_map_event_t type
))
311 rmap_match_set_hook
.match_ip_next_hop_type
= func
;
314 /* no match ip next-hop type */
315 void route_map_no_match_ip_next_hop_type_hook(int (*func
)(
316 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
317 const char *arg
, route_map_event_t type
))
319 rmap_match_set_hook
.no_match_ip_next_hop_type
= func
;
322 /* match ipv6 address */
323 void route_map_match_ipv6_address_hook(int (*func
)(
324 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
325 const char *arg
, route_map_event_t type
))
327 rmap_match_set_hook
.match_ipv6_address
= func
;
330 /* no match ipv6 address */
331 void route_map_no_match_ipv6_address_hook(int (*func
)(
332 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
333 const char *arg
, route_map_event_t type
))
335 rmap_match_set_hook
.no_match_ipv6_address
= func
;
339 /* match ipv6 address prefix list */
340 void route_map_match_ipv6_address_prefix_list_hook(int (*func
)(
341 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
342 const char *arg
, route_map_event_t type
))
344 rmap_match_set_hook
.match_ipv6_address_prefix_list
= func
;
347 /* no match ipv6 address prefix list */
348 void route_map_no_match_ipv6_address_prefix_list_hook(int (*func
)(
349 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
350 const char *arg
, route_map_event_t type
))
352 rmap_match_set_hook
.no_match_ipv6_address_prefix_list
= func
;
355 /* match ipv6 next-hop type */
356 void route_map_match_ipv6_next_hop_type_hook(int (*func
)(
357 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
358 const char *arg
, route_map_event_t type
))
360 rmap_match_set_hook
.match_ipv6_next_hop_type
= func
;
363 /* no match ipv6 next-hop type */
364 void route_map_no_match_ipv6_next_hop_type_hook(int (*func
)(
365 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
366 const char *arg
, route_map_event_t type
))
368 rmap_match_set_hook
.no_match_ipv6_next_hop_type
= func
;
372 void route_map_match_metric_hook(int (*func
)(
373 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
374 const char *arg
, route_map_event_t type
))
376 rmap_match_set_hook
.match_metric
= func
;
379 /* no match metric */
380 void route_map_no_match_metric_hook(int (*func
)(
381 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
382 const char *arg
, route_map_event_t type
))
384 rmap_match_set_hook
.no_match_metric
= func
;
388 void route_map_match_tag_hook(int (*func
)(struct vty
*vty
,
389 struct route_map_index
*index
,
390 const char *command
, const char *arg
,
391 route_map_event_t type
))
393 rmap_match_set_hook
.match_tag
= func
;
397 void route_map_no_match_tag_hook(int (*func
)(
398 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
399 const char *arg
, route_map_event_t type
))
401 rmap_match_set_hook
.no_match_tag
= func
;
405 void route_map_set_ip_nexthop_hook(int (*func
)(struct vty
*vty
,
406 struct route_map_index
*index
,
410 rmap_match_set_hook
.set_ip_nexthop
= func
;
413 /* no set ip nexthop */
414 void route_map_no_set_ip_nexthop_hook(int (*func
)(struct vty
*vty
,
415 struct route_map_index
*index
,
419 rmap_match_set_hook
.no_set_ip_nexthop
= func
;
422 /* set ipv6 nexthop local */
423 void route_map_set_ipv6_nexthop_local_hook(
424 int (*func
)(struct vty
*vty
, struct route_map_index
*index
,
425 const char *command
, const char *arg
))
427 rmap_match_set_hook
.set_ipv6_nexthop_local
= func
;
430 /* no set ipv6 nexthop local */
431 void route_map_no_set_ipv6_nexthop_local_hook(
432 int (*func
)(struct vty
*vty
, struct route_map_index
*index
,
433 const char *command
, const char *arg
))
435 rmap_match_set_hook
.no_set_ipv6_nexthop_local
= func
;
439 void route_map_set_metric_hook(int (*func
)(struct vty
*vty
,
440 struct route_map_index
*index
,
444 rmap_match_set_hook
.set_metric
= func
;
448 void route_map_no_set_metric_hook(int (*func
)(struct vty
*vty
,
449 struct route_map_index
*index
,
453 rmap_match_set_hook
.no_set_metric
= func
;
457 void route_map_set_tag_hook(int (*func
)(struct vty
*vty
,
458 struct route_map_index
*index
,
459 const char *command
, const char *arg
))
461 rmap_match_set_hook
.set_tag
= func
;
465 void route_map_no_set_tag_hook(int (*func
)(struct vty
*vty
,
466 struct route_map_index
*index
,
470 rmap_match_set_hook
.no_set_tag
= func
;
473 int generic_match_add(struct vty
*vty
, struct route_map_index
*index
,
474 const char *command
, const char *arg
,
475 route_map_event_t type
)
477 enum rmap_compile_rets ret
;
479 ret
= route_map_add_match(index
, command
, arg
, type
);
481 case RMAP_COMPILE_SUCCESS
:
482 if (type
!= RMAP_EVENT_MATCH_ADDED
) {
483 route_map_upd8_dependency(type
, arg
, index
->map
->name
);
486 case RMAP_RULE_MISSING
:
487 vty_out(vty
, "%% [%s] Can't find rule.\n", frr_protonameinst
);
488 return CMD_WARNING_CONFIG_FAILED
;
490 case RMAP_COMPILE_ERROR
:
492 "%% [%s] Argument form is unsupported or malformed.\n",
494 return CMD_WARNING_CONFIG_FAILED
;
496 case RMAP_DUPLICATE_RULE
:
498 * Nothing to do here move along
506 int generic_match_delete(struct vty
*vty
, struct route_map_index
*index
,
507 const char *command
, const char *arg
,
508 route_map_event_t type
)
510 enum rmap_compile_rets ret
;
511 int retval
= CMD_SUCCESS
;
512 char *dep_name
= NULL
;
514 char *rmap_name
= NULL
;
516 if (type
!= RMAP_EVENT_MATCH_DELETED
) {
517 /* ignore the mundane, the types without any dependency */
519 if ((tmpstr
= route_map_get_match_arg(index
, command
))
522 XSTRDUP(MTYPE_ROUTE_MAP_RULE
, tmpstr
);
524 dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_RULE
, arg
);
526 rmap_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, index
->map
->name
);
529 ret
= route_map_delete_match(index
, command
, dep_name
);
531 case RMAP_RULE_MISSING
:
532 vty_out(vty
, "%% [%s] Can't find rule.\n", frr_protonameinst
);
533 retval
= CMD_WARNING_CONFIG_FAILED
;
535 case RMAP_COMPILE_ERROR
:
537 "%% [%s] Argument form is unsupported or malformed.\n",
539 retval
= CMD_WARNING_CONFIG_FAILED
;
541 case RMAP_COMPILE_SUCCESS
:
542 if (type
!= RMAP_EVENT_MATCH_DELETED
&& dep_name
)
543 route_map_upd8_dependency(type
, dep_name
, rmap_name
);
545 case RMAP_DUPLICATE_RULE
:
552 XFREE(MTYPE_ROUTE_MAP_RULE
, dep_name
);
553 XFREE(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
558 int generic_set_add(struct vty
*vty
, struct route_map_index
*index
,
559 const char *command
, const char *arg
)
561 enum rmap_compile_rets ret
;
563 ret
= route_map_add_set(index
, command
, arg
);
565 case RMAP_RULE_MISSING
:
566 vty_out(vty
, "%% [%s] Can't find rule.\n", frr_protonameinst
);
567 return CMD_WARNING_CONFIG_FAILED
;
569 case RMAP_COMPILE_ERROR
:
571 "%% [%s] Argument form is unsupported or malformed.\n",
573 return CMD_WARNING_CONFIG_FAILED
;
575 case RMAP_COMPILE_SUCCESS
:
576 case RMAP_DUPLICATE_RULE
:
583 int generic_set_delete(struct vty
*vty
, struct route_map_index
*index
,
584 const char *command
, const char *arg
)
586 enum rmap_compile_rets ret
;
588 ret
= route_map_delete_set(index
, command
, arg
);
590 case RMAP_RULE_MISSING
:
591 vty_out(vty
, "%% [%s] Can't find rule.\n", frr_protonameinst
);
592 return CMD_WARNING_CONFIG_FAILED
;
594 case RMAP_COMPILE_ERROR
:
596 "%% [%s] Argument form is unsupported or malformed.\n",
598 return CMD_WARNING_CONFIG_FAILED
;
600 case RMAP_COMPILE_SUCCESS
:
601 case RMAP_DUPLICATE_RULE
:
609 /* Route map rule. This rule has both `match' rule and `set' rule. */
610 struct route_map_rule
{
612 struct route_map_rule_cmd
*cmd
;
614 /* For pretty printing. */
617 /* Pre-compiled match rule. */
621 struct route_map_rule
*next
;
622 struct route_map_rule
*prev
;
625 /* Making route map list. */
626 struct route_map_list
{
627 struct route_map
*head
;
628 struct route_map
*tail
;
630 void (*add_hook
)(const char *);
631 void (*delete_hook
)(const char *);
632 void (*event_hook
)(const char *);
635 /* Master list of route map. */
636 static struct route_map_list route_map_master
= {NULL
, NULL
, NULL
, NULL
, NULL
};
637 struct hash
*route_map_master_hash
= NULL
;
639 static unsigned int route_map_hash_key_make(const void *p
)
641 const struct route_map
*map
= p
;
642 return string_hash_make(map
->name
);
645 static bool route_map_hash_cmp(const void *p1
, const void *p2
)
647 const struct route_map
*map1
= p1
;
648 const struct route_map
*map2
= p2
;
650 if (map1
->deleted
== map2
->deleted
) {
651 if (map1
->name
&& map2
->name
) {
652 if (!strcmp(map1
->name
, map2
->name
)) {
655 } else if (!map1
->name
&& !map2
->name
) {
663 enum route_map_upd8_type
{
668 /* all possible route-map dependency types */
669 enum route_map_dep_type
{
670 ROUTE_MAP_DEP_RMAP
= 1,
672 ROUTE_MAP_DEP_ECLIST
,
673 ROUTE_MAP_DEP_LCLIST
,
675 ROUTE_MAP_DEP_ASPATH
,
676 ROUTE_MAP_DEP_FILTER
,
680 struct route_map_dep
{
682 struct hash
*dep_rmap_hash
;
683 struct hash
*this_hash
; /* ptr to the hash structure this is part of */
686 struct route_map_dep_data
{
690 /* Count of number of sequences of this
691 * route-map that depend on the same entity.
696 /* Hashes maintaining dependency between various sublists used by route maps */
697 struct hash
*route_map_dep_hash
[ROUTE_MAP_DEP_MAX
];
699 static unsigned int route_map_dep_hash_make_key(const void *p
);
700 static void route_map_clear_all_references(char *rmap_name
);
701 static void route_map_rule_delete(struct route_map_rule_list
*,
702 struct route_map_rule
*);
703 static bool rmap_debug
;
705 static void route_map_index_delete(struct route_map_index
*, int);
707 /* New route map allocation. Please note route map's name must be
709 static struct route_map
*route_map_new(const char *name
)
711 struct route_map
*new;
713 new = XCALLOC(MTYPE_ROUTE_MAP
, sizeof(struct route_map
));
714 new->name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
715 QOBJ_REG(new, route_map
);
719 /* Add new name to route_map. */
720 static struct route_map
*route_map_add(const char *name
)
722 struct route_map
*map
;
723 struct route_map_list
*list
;
725 map
= route_map_new(name
);
726 list
= &route_map_master
;
728 /* Add map to the hash */
729 hash_get(route_map_master_hash
, map
, hash_alloc_intern
);
731 /* Add new entry to the head of the list to match how it is added in the
732 * hash table. This is to ensure that if the same route-map has been
733 * created more than once and then marked for deletion (which can happen
734 * if prior deletions haven't completed as BGP hasn't yet done the
735 * route-map processing), the order of the entities is the same in both
736 * the list and the hash table. Otherwise, since there is nothing to
737 * distinguish between the two entries, the wrong entry could get freed.
738 * TODO: This needs to be re-examined to handle it better - e.g., revive
739 * a deleted entry if the route-map is created again.
742 map
->next
= list
->head
;
744 list
->head
->prev
= map
;
750 if (route_map_master
.add_hook
) {
751 (*route_map_master
.add_hook
)(name
);
752 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_ADDED
);
756 zlog_debug("Add route-map %s", name
);
760 /* this is supposed to be called post processing by
761 * the delete hook function. Don't invoke delete_hook
762 * again in this routine.
764 static void route_map_free_map(struct route_map
*map
)
766 struct route_map_list
*list
;
767 struct route_map_index
*index
;
772 while ((index
= map
->head
) != NULL
)
773 route_map_index_delete(index
, 0);
776 zlog_debug("Deleting route-map %s", map
->name
);
778 list
= &route_map_master
;
783 map
->next
->prev
= map
->prev
;
785 list
->tail
= map
->prev
;
788 map
->prev
->next
= map
->next
;
790 list
->head
= map
->next
;
792 hash_release(route_map_master_hash
, map
);
793 XFREE(MTYPE_ROUTE_MAP_NAME
, map
->name
);
794 XFREE(MTYPE_ROUTE_MAP
, map
);
797 /* Route map delete from list. */
798 static void route_map_delete(struct route_map
*map
)
800 struct route_map_index
*index
;
803 while ((index
= map
->head
) != NULL
)
804 route_map_index_delete(index
, 0);
809 /* Clear all dependencies */
810 route_map_clear_all_references(name
);
812 /* Execute deletion hook. */
813 if (route_map_master
.delete_hook
) {
814 (*route_map_master
.delete_hook
)(name
);
815 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_DELETED
);
818 if (!map
->to_be_processed
) {
819 route_map_free_map(map
);
823 /* Lookup route map by route map name string. */
824 struct route_map
*route_map_lookup_by_name(const char *name
)
826 struct route_map
*map
;
827 struct route_map tmp_map
;
832 // map.deleted is 0 via memset
833 memset(&tmp_map
, 0, sizeof(struct route_map
));
834 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
835 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
836 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
840 /* Simple helper to warn if route-map does not exist. */
841 struct route_map
*route_map_lookup_warn_noexist(struct vty
*vty
, const char *name
)
843 struct route_map
*route_map
= route_map_lookup_by_name(name
);
846 if (vty_shell_serv(vty
))
847 vty_out(vty
, "The route-map '%s' does not exist.\n", name
);
852 int route_map_mark_updated(const char *name
)
854 struct route_map
*map
;
856 struct route_map tmp_map
;
861 map
= route_map_lookup_by_name(name
);
863 /* If we did not find the routemap with deleted=false try again
867 memset(&tmp_map
, 0, sizeof(struct route_map
));
868 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
869 tmp_map
.deleted
= true;
870 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
871 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
875 map
->to_be_processed
= true;
882 static int route_map_clear_updated(struct route_map
*map
)
887 map
->to_be_processed
= false;
889 route_map_free_map(map
);
895 /* Lookup route map. If there isn't route map create one and return
897 static struct route_map
*route_map_get(const char *name
)
899 struct route_map
*map
;
901 map
= route_map_lookup_by_name(name
);
903 map
= route_map_add(name
);
908 void route_map_walk_update_list(void (*route_map_update_fn
)(char *name
))
910 struct route_map
*node
;
911 struct route_map
*nnode
= NULL
;
913 for (node
= route_map_master
.head
; node
; node
= nnode
) {
914 if (node
->to_be_processed
) {
915 /* DD: Should we add any thread yield code here */
916 route_map_update_fn(node
->name
);
918 route_map_clear_updated(node
);
924 /* Return route map's type string. */
925 static const char *route_map_type_str(enum route_map_type type
)
942 static const char *route_map_cmd_result_str(enum route_map_cmd_result_t res
)
960 static const char *route_map_result_str(route_map_result_t res
)
965 case RMAP_PERMITMATCH
:
972 static int route_map_empty(struct route_map
*map
)
974 if (map
->head
== NULL
&& map
->tail
== NULL
)
981 static void vty_show_route_map_entry(struct vty
*vty
, struct route_map
*map
)
983 struct route_map_index
*index
;
984 struct route_map_rule
*rule
;
986 vty_out(vty
, "route-map: %s Invoked: %" PRIu64
"\n",
987 map
->name
, map
->applied
- map
->applied_clear
);
989 for (index
= map
->head
; index
; index
= index
->next
) {
990 vty_out(vty
, " %s, sequence %d Invoked %" PRIu64
"\n",
991 route_map_type_str(index
->type
), index
->pref
,
992 index
->applied
- index
->applied_clear
);
995 if (index
->description
)
996 vty_out(vty
, " Description:\n %s\n",
1000 vty_out(vty
, " Match clauses:\n");
1001 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1002 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
1005 vty_out(vty
, " Set clauses:\n");
1006 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
1007 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
1011 vty_out(vty
, " Call clause:\n");
1013 vty_out(vty
, " Call %s\n", index
->nextrm
);
1016 vty_out(vty
, " Action:\n");
1017 if (index
->exitpolicy
== RMAP_GOTO
)
1018 vty_out(vty
, " Goto %d\n", index
->nextpref
);
1019 else if (index
->exitpolicy
== RMAP_NEXT
)
1020 vty_out(vty
, " Continue to next entry\n");
1021 else if (index
->exitpolicy
== RMAP_EXIT
)
1022 vty_out(vty
, " Exit routemap\n");
1026 static int sort_route_map(const void **map1
, const void **map2
)
1028 const struct route_map
*m1
= *map1
;
1029 const struct route_map
*m2
= *map2
;
1031 return strcmp(m1
->name
, m2
->name
);
1034 static int vty_show_route_map(struct vty
*vty
, const char *name
)
1036 struct route_map
*map
;
1038 vty_out(vty
, "%s:\n", frr_protonameinst
);
1041 map
= route_map_lookup_by_name(name
);
1044 vty_show_route_map_entry(vty
, map
);
1047 vty_out(vty
, "%s: 'route-map %s' not found\n",
1048 frr_protonameinst
, name
);
1053 struct list
*maplist
= list_new();
1054 struct listnode
*ln
;
1056 for (map
= route_map_master
.head
; map
; map
= map
->next
)
1057 listnode_add(maplist
, map
);
1059 list_sort(maplist
, sort_route_map
);
1061 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
1062 vty_show_route_map_entry(vty
, map
);
1064 list_delete(&maplist
);
1069 /* Unused route map details */
1070 static int vty_show_unused_route_map(struct vty
*vty
)
1072 struct list
*maplist
= list_new();
1073 struct listnode
*ln
;
1074 struct route_map
*map
;
1076 for (map
= route_map_master
.head
; map
; map
= map
->next
) {
1077 /* If use_count is zero, No protocol is using this routemap.
1078 * so adding to the list.
1080 if (!map
->use_count
)
1081 listnode_add(maplist
, map
);
1084 if (maplist
->count
> 0) {
1085 vty_out(vty
, "\n%s:\n", frr_protonameinst
);
1086 list_sort(maplist
, sort_route_map
);
1088 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
1089 vty_show_route_map_entry(vty
, map
);
1091 vty_out(vty
, "\n%s: None\n", frr_protonameinst
);
1094 list_delete(&maplist
);
1098 /* New route map allocation. Please note route map's name must be
1100 static struct route_map_index
*route_map_index_new(void)
1102 struct route_map_index
*new;
1104 new = XCALLOC(MTYPE_ROUTE_MAP_INDEX
, sizeof(struct route_map_index
));
1105 new->exitpolicy
= RMAP_EXIT
; /* Default to Cisco-style */
1106 QOBJ_REG(new, route_map_index
);
1110 /* Free route map index. */
1111 static void route_map_index_delete(struct route_map_index
*index
, int notify
)
1113 struct route_map_rule
*rule
;
1118 zlog_debug("Deleting route-map %s sequence %d",
1119 index
->map
->name
, index
->pref
);
1121 /* Free route match. */
1122 while ((rule
= index
->match_list
.head
) != NULL
)
1123 route_map_rule_delete(&index
->match_list
, rule
);
1125 /* Free route set. */
1126 while ((rule
= index
->set_list
.head
) != NULL
)
1127 route_map_rule_delete(&index
->set_list
, rule
);
1129 /* Remove index from route map list. */
1131 index
->next
->prev
= index
->prev
;
1133 index
->map
->tail
= index
->prev
;
1136 index
->prev
->next
= index
->next
;
1138 index
->map
->head
= index
->next
;
1140 /* Free 'char *nextrm' if not NULL */
1141 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
1143 /* Execute event hook. */
1144 if (route_map_master
.event_hook
&& notify
) {
1145 (*route_map_master
.event_hook
)(index
->map
->name
);
1146 route_map_notify_dependencies(index
->map
->name
,
1147 RMAP_EVENT_CALL_ADDED
);
1149 XFREE(MTYPE_ROUTE_MAP_INDEX
, index
);
1152 /* Lookup index from route map. */
1153 static struct route_map_index
*route_map_index_lookup(struct route_map
*map
,
1154 enum route_map_type type
,
1157 struct route_map_index
*index
;
1159 for (index
= map
->head
; index
; index
= index
->next
)
1160 if ((index
->type
== type
|| type
== RMAP_ANY
)
1161 && index
->pref
== pref
)
1166 /* Add new index to route map. */
1167 static struct route_map_index
*
1168 route_map_index_add(struct route_map
*map
, enum route_map_type type
, int pref
)
1170 struct route_map_index
*index
;
1171 struct route_map_index
*point
;
1173 /* Allocate new route map inex. */
1174 index
= route_map_index_new();
1179 /* Compare preference. */
1180 for (point
= map
->head
; point
; point
= point
->next
)
1181 if (point
->pref
>= pref
)
1184 if (map
->head
== NULL
) {
1185 map
->head
= map
->tail
= index
;
1186 } else if (point
== NULL
) {
1187 index
->prev
= map
->tail
;
1188 map
->tail
->next
= index
;
1190 } else if (point
== map
->head
) {
1191 index
->next
= map
->head
;
1192 map
->head
->prev
= index
;
1195 index
->next
= point
;
1196 index
->prev
= point
->prev
;
1198 point
->prev
->next
= index
;
1199 point
->prev
= index
;
1202 /* Execute event hook. */
1203 if (route_map_master
.event_hook
) {
1204 (*route_map_master
.event_hook
)(map
->name
);
1205 route_map_notify_dependencies(map
->name
, RMAP_EVENT_CALL_ADDED
);
1209 zlog_debug("Route-map %s add sequence %d, type: %s",
1210 map
->name
, pref
, route_map_type_str(type
));
1215 /* Get route map index. */
1216 static struct route_map_index
*
1217 route_map_index_get(struct route_map
*map
, enum route_map_type type
, int pref
)
1219 struct route_map_index
*index
;
1221 index
= route_map_index_lookup(map
, RMAP_ANY
, pref
);
1222 if (index
&& index
->type
!= type
) {
1223 /* Delete index from route map. */
1224 route_map_index_delete(index
, 1);
1228 index
= route_map_index_add(map
, type
, pref
);
1232 /* New route map rule */
1233 static struct route_map_rule
*route_map_rule_new(void)
1235 struct route_map_rule
*new;
1237 new = XCALLOC(MTYPE_ROUTE_MAP_RULE
, sizeof(struct route_map_rule
));
1241 /* Install rule command to the match list. */
1242 void route_map_install_match(struct route_map_rule_cmd
*cmd
)
1244 vector_set(route_match_vec
, cmd
);
1247 /* Install rule command to the set list. */
1248 void route_map_install_set(struct route_map_rule_cmd
*cmd
)
1250 vector_set(route_set_vec
, cmd
);
1253 /* Lookup rule command from match list. */
1254 static struct route_map_rule_cmd
*route_map_lookup_match(const char *name
)
1257 struct route_map_rule_cmd
*rule
;
1259 for (i
= 0; i
< vector_active(route_match_vec
); i
++)
1260 if ((rule
= vector_slot(route_match_vec
, i
)) != NULL
)
1261 if (strcmp(rule
->str
, name
) == 0)
1266 /* Lookup rule command from set list. */
1267 static struct route_map_rule_cmd
*route_map_lookup_set(const char *name
)
1270 struct route_map_rule_cmd
*rule
;
1272 for (i
= 0; i
< vector_active(route_set_vec
); i
++)
1273 if ((rule
= vector_slot(route_set_vec
, i
)) != NULL
)
1274 if (strcmp(rule
->str
, name
) == 0)
1279 /* Add match and set rule to rule list. */
1280 static void route_map_rule_add(struct route_map_rule_list
*list
,
1281 struct route_map_rule
*rule
)
1284 rule
->prev
= list
->tail
;
1286 list
->tail
->next
= rule
;
1292 /* Delete rule from rule list. */
1293 static void route_map_rule_delete(struct route_map_rule_list
*list
,
1294 struct route_map_rule
*rule
)
1296 if (rule
->cmd
->func_free
)
1297 (*rule
->cmd
->func_free
)(rule
->value
);
1299 XFREE(MTYPE_ROUTE_MAP_RULE_STR
, rule
->rule_str
);
1302 rule
->next
->prev
= rule
->prev
;
1304 list
->tail
= rule
->prev
;
1306 rule
->prev
->next
= rule
->next
;
1308 list
->head
= rule
->next
;
1310 XFREE(MTYPE_ROUTE_MAP_RULE
, rule
);
1313 /* strcmp wrapper function which don't crush even argument is NULL. */
1314 static int rulecmp(const char *dst
, const char *src
)
1325 return strcmp(dst
, src
);
1330 /* Use this to return the already specified argument for this match. This is
1331 * useful to get the specified argument with a route map match rule when the
1332 * rule is being deleted and the argument is not provided.
1334 const char *route_map_get_match_arg(struct route_map_index
*index
,
1335 const char *match_name
)
1337 struct route_map_rule
*rule
;
1338 struct route_map_rule_cmd
*cmd
;
1340 /* First lookup rule for add match statement. */
1341 cmd
= route_map_lookup_match(match_name
);
1345 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1346 if (rule
->cmd
== cmd
&& rule
->rule_str
!= NULL
)
1347 return (rule
->rule_str
);
1352 static route_map_event_t
get_route_map_delete_event(route_map_event_t type
)
1355 case RMAP_EVENT_CALL_ADDED
:
1356 return RMAP_EVENT_CALL_DELETED
;
1357 case RMAP_EVENT_PLIST_ADDED
:
1358 return RMAP_EVENT_PLIST_DELETED
;
1359 case RMAP_EVENT_CLIST_ADDED
:
1360 return RMAP_EVENT_CLIST_DELETED
;
1361 case RMAP_EVENT_ECLIST_ADDED
:
1362 return RMAP_EVENT_ECLIST_DELETED
;
1363 case RMAP_EVENT_LLIST_ADDED
:
1364 return RMAP_EVENT_LLIST_DELETED
;
1365 case RMAP_EVENT_ASLIST_ADDED
:
1366 return RMAP_EVENT_ASLIST_DELETED
;
1367 case RMAP_EVENT_FILTER_ADDED
:
1368 return RMAP_EVENT_FILTER_DELETED
;
1369 case RMAP_EVENT_SET_ADDED
:
1370 case RMAP_EVENT_SET_DELETED
:
1371 case RMAP_EVENT_SET_REPLACED
:
1372 case RMAP_EVENT_MATCH_ADDED
:
1373 case RMAP_EVENT_MATCH_DELETED
:
1374 case RMAP_EVENT_MATCH_REPLACED
:
1375 case RMAP_EVENT_INDEX_ADDED
:
1376 case RMAP_EVENT_INDEX_DELETED
:
1377 case RMAP_EVENT_CALL_DELETED
:
1378 case RMAP_EVENT_PLIST_DELETED
:
1379 case RMAP_EVENT_CLIST_DELETED
:
1380 case RMAP_EVENT_ECLIST_DELETED
:
1381 case RMAP_EVENT_LLIST_DELETED
:
1382 case RMAP_EVENT_ASLIST_DELETED
:
1383 case RMAP_EVENT_FILTER_DELETED
:
1384 /* This function returns the appropriate 'deleted' event type
1385 * for every 'added' event type passed to this function.
1386 * This is done only for named entities used in the
1387 * route-map match commands.
1388 * This function is not to be invoked for any of the other event
1396 * Return to make c happy but if we get here something has gone
1397 * terribly terribly wrong, so yes this return makes no sense.
1399 return RMAP_EVENT_CALL_ADDED
;
1402 /* Add match statement to route map. */
1403 enum rmap_compile_rets
route_map_add_match(struct route_map_index
*index
,
1404 const char *match_name
,
1405 const char *match_arg
,
1406 route_map_event_t type
)
1408 struct route_map_rule
*rule
;
1409 struct route_map_rule
*next
;
1410 struct route_map_rule_cmd
*cmd
;
1412 int8_t delete_rmap_event_type
= 0;
1414 /* First lookup rule for add match statement. */
1415 cmd
= route_map_lookup_match(match_name
);
1417 return RMAP_RULE_MISSING
;
1419 /* Next call compile function for this match statement. */
1420 if (cmd
->func_compile
) {
1421 compile
= (*cmd
->func_compile
)(match_arg
);
1422 if (compile
== NULL
)
1423 return RMAP_COMPILE_ERROR
;
1427 /* If argument is completely same ignore it. */
1428 for (rule
= index
->match_list
.head
; rule
; rule
= next
) {
1430 if (rule
->cmd
== cmd
) {
1431 /* If the configured route-map match rule is exactly
1432 * the same as the existing configuration then,
1433 * ignore the duplicate configuration.
1435 if (strcmp(match_arg
, rule
->rule_str
) == 0) {
1437 (*cmd
->func_free
)(compile
);
1439 return RMAP_DUPLICATE_RULE
;
1442 /* Remove the dependency of the route-map on the rule
1443 * that is being replaced.
1445 if (type
>= RMAP_EVENT_CALL_ADDED
) {
1446 delete_rmap_event_type
=
1447 get_route_map_delete_event(type
);
1448 route_map_upd8_dependency(
1449 delete_rmap_event_type
,
1454 route_map_rule_delete(&index
->match_list
, rule
);
1458 /* Add new route map match rule. */
1459 rule
= route_map_rule_new();
1461 rule
->value
= compile
;
1463 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, match_arg
);
1465 rule
->rule_str
= NULL
;
1467 /* Add new route match rule to linked list. */
1468 route_map_rule_add(&index
->match_list
, rule
);
1470 /* Execute event hook. */
1471 if (route_map_master
.event_hook
) {
1472 (*route_map_master
.event_hook
)(index
->map
->name
);
1473 route_map_notify_dependencies(index
->map
->name
,
1474 RMAP_EVENT_CALL_ADDED
);
1477 return RMAP_COMPILE_SUCCESS
;
1480 /* Delete specified route match rule. */
1481 enum rmap_compile_rets
route_map_delete_match(struct route_map_index
*index
,
1482 const char *match_name
,
1483 const char *match_arg
)
1485 struct route_map_rule
*rule
;
1486 struct route_map_rule_cmd
*cmd
;
1488 cmd
= route_map_lookup_match(match_name
);
1490 return RMAP_RULE_MISSING
;
1492 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1493 if (rule
->cmd
== cmd
&& (rulecmp(rule
->rule_str
, match_arg
) == 0
1494 || match_arg
== NULL
)) {
1495 route_map_rule_delete(&index
->match_list
, rule
);
1496 /* Execute event hook. */
1497 if (route_map_master
.event_hook
) {
1498 (*route_map_master
.event_hook
)(index
->map
->name
);
1499 route_map_notify_dependencies(
1501 RMAP_EVENT_CALL_ADDED
);
1503 return RMAP_COMPILE_SUCCESS
;
1505 /* Can't find matched rule. */
1506 return RMAP_RULE_MISSING
;
1509 /* Add route-map set statement to the route map. */
1510 enum rmap_compile_rets
route_map_add_set(struct route_map_index
*index
,
1511 const char *set_name
,
1512 const char *set_arg
)
1514 struct route_map_rule
*rule
;
1515 struct route_map_rule
*next
;
1516 struct route_map_rule_cmd
*cmd
;
1519 cmd
= route_map_lookup_set(set_name
);
1521 return RMAP_RULE_MISSING
;
1523 /* Next call compile function for this match statement. */
1524 if (cmd
->func_compile
) {
1525 compile
= (*cmd
->func_compile
)(set_arg
);
1526 if (compile
== NULL
)
1527 return RMAP_COMPILE_ERROR
;
1531 /* Add by WJL. if old set command of same kind exist, delete it first
1532 to ensure only one set command of same kind exist under a
1534 for (rule
= index
->set_list
.head
; rule
; rule
= next
) {
1536 if (rule
->cmd
== cmd
)
1537 route_map_rule_delete(&index
->set_list
, rule
);
1540 /* Add new route map match rule. */
1541 rule
= route_map_rule_new();
1543 rule
->value
= compile
;
1545 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, set_arg
);
1547 rule
->rule_str
= NULL
;
1549 /* Add new route match rule to linked list. */
1550 route_map_rule_add(&index
->set_list
, rule
);
1552 /* Execute event hook. */
1553 if (route_map_master
.event_hook
) {
1554 (*route_map_master
.event_hook
)(index
->map
->name
);
1555 route_map_notify_dependencies(index
->map
->name
,
1556 RMAP_EVENT_CALL_ADDED
);
1558 return RMAP_COMPILE_SUCCESS
;
1561 /* Delete route map set rule. */
1562 enum rmap_compile_rets
route_map_delete_set(struct route_map_index
*index
,
1563 const char *set_name
,
1564 const char *set_arg
)
1566 struct route_map_rule
*rule
;
1567 struct route_map_rule_cmd
*cmd
;
1569 cmd
= route_map_lookup_set(set_name
);
1571 return RMAP_RULE_MISSING
;
1573 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
1574 if ((rule
->cmd
== cmd
) && (rulecmp(rule
->rule_str
, set_arg
) == 0
1575 || set_arg
== NULL
)) {
1576 route_map_rule_delete(&index
->set_list
, rule
);
1577 /* Execute event hook. */
1578 if (route_map_master
.event_hook
) {
1579 (*route_map_master
.event_hook
)(index
->map
->name
);
1580 route_map_notify_dependencies(
1582 RMAP_EVENT_CALL_ADDED
);
1584 return RMAP_COMPILE_SUCCESS
;
1586 /* Can't find matched rule. */
1587 return RMAP_RULE_MISSING
;
1590 static enum route_map_cmd_result_t
1591 route_map_apply_match(struct route_map_rule_list
*match_list
,
1592 const struct prefix
*prefix
, route_map_object_t type
,
1595 enum route_map_cmd_result_t ret
= RMAP_NOMATCH
;
1596 struct route_map_rule
*match
;
1597 bool is_matched
= false;
1600 /* Check all match rule and if there is no match rule, go to the
1602 if (!match_list
->head
)
1605 for (match
= match_list
->head
; match
; match
= match
->next
) {
1607 * Try each match statement. If any match does not
1608 * return RMAP_MATCH or RMAP_NOOP, return.
1609 * Otherwise continue on to next match statement.
1610 * All match statements must MATCH for
1611 * end-result to be a match.
1612 * (Exception:If match stmts result in a mix of
1613 * MATCH/NOOP, then also end-result is a match)
1614 * If all result in NOOP, end-result is NOOP.
1616 ret
= (*match
->cmd
->func_apply
)(match
->value
, prefix
,
1620 * If the consolidated result of func_apply is:
1621 * -----------------------------------------------
1622 * | MATCH | NOMATCH | NOOP | Final Result |
1623 * ------------------------------------------------
1624 * | yes | yes | yes | NOMATCH |
1625 * | no | no | yes | NOOP |
1626 * | yes | no | yes | MATCH |
1627 * | no | yes | yes | NOMATCH |
1628 * |-----------------------------------------------
1630 * Traditionally, all rules within route-map
1631 * should match for it to MATCH.
1632 * If there are noops within the route-map rules,
1633 * it follows the above matrix.
1635 * Eg: route-map rm1 permit 10
1640 * route-map rm1 permit 20
1668 /* Apply route map's each index to the object.
1670 The matrix for a route-map looks like this:
1671 (note, this includes the description for the "NEXT"
1672 and "GOTO" frobs now
1674 | Match | No Match | No op
1675 |-----------|--------------|-------
1676 permit | action | cont | cont.
1677 | | default:deny | default:permit
1678 -------------------+-----------------------
1679 | deny | cont | cont.
1680 deny | | default:deny | default:permit
1681 |-----------|--------------|--------
1684 -Apply Set statements, accept route
1685 -If Call statement is present jump to the specified route-map, if it
1686 denies the route we finish.
1687 -If NEXT is specified, goto NEXT statement
1688 -If GOTO is specified, goto the first clause where pref > nextpref
1689 -If nothing is specified, do as Cisco and finish
1691 -Route is denied by route-map.
1695 If we get no matches after we've processed all updates, then the route
1698 Some notes on the new "CALL", "NEXT" and "GOTO"
1699 call WORD - If this clause is matched, then the set statements
1700 are executed and then we jump to route-map 'WORD'. If
1701 this route-map denies the route, we finish, in other
1703 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
1704 on-match next - If this clause is matched, then the set statements
1705 are executed and then we drop through to the next clause
1706 on-match goto n - If this clause is matched, then the set statments
1707 are executed and then we goto the nth clause, or the
1708 first clause greater than this. In order to ensure
1709 route-maps *always* exit, you cannot jump backwards.
1712 We need to make sure our route-map processing matches the above
1714 route_map_result_t
route_map_apply(struct route_map
*map
,
1715 const struct prefix
*prefix
,
1716 route_map_object_t type
, void *object
)
1718 static int recursion
= 0;
1719 enum route_map_cmd_result_t match_ret
= RMAP_NOMATCH
;
1720 route_map_result_t ret
= RMAP_PERMITMATCH
;
1721 struct route_map_index
*index
;
1722 struct route_map_rule
*set
;
1723 char buf
[PREFIX_STRLEN
];
1725 if (recursion
> RMAP_RECURSION_LIMIT
) {
1727 EC_LIB_RMAP_RECURSION_LIMIT
,
1728 "route-map recursion limit (%d) reached, discarding route",
1729 RMAP_RECURSION_LIMIT
);
1731 return RMAP_DENYMATCH
;
1734 if (map
== NULL
|| map
->head
== NULL
) {
1735 ret
= RMAP_DENYMATCH
;
1736 goto route_map_apply_end
;
1740 for (index
= map
->head
; index
; index
= index
->next
) {
1741 /* Apply this index. */
1743 match_ret
= route_map_apply_match(&index
->match_list
, prefix
,
1747 zlog_debug("Route-map: %s, sequence: %d, prefix: %s, result: %s",
1748 map
->name
, index
->pref
,
1749 prefix2str(prefix
, buf
, sizeof(buf
)),
1750 route_map_cmd_result_str(match_ret
));
1753 /* Now we apply the matrix from above */
1754 if (match_ret
== RMAP_NOOP
)
1756 * Do not change the return value. Retain the previous
1757 * return value. Previous values can be:
1758 * 1)permitmatch (if a nomatch was never
1759 * seen before in this route-map.)
1760 * 2)denymatch (if a nomatch was seen earlier in one
1761 * of the previous sequences)
1765 * 'cont' from matrix - continue to next route-map
1769 else if (match_ret
== RMAP_NOMATCH
) {
1772 * The return value is now changed to denymatch.
1773 * So from here on out, even if we see more noops,
1774 * we retain this return value and return this
1775 * eventually if there are no matches.
1777 ret
= RMAP_DENYMATCH
;
1780 * 'cont' from matrix - continue to next route-map
1784 } else if (match_ret
== RMAP_MATCH
) {
1785 if (index
->type
== RMAP_PERMIT
)
1788 /* Match succeeded, rmap is of type permit */
1789 ret
= RMAP_PERMITMATCH
;
1791 /* permit+match must execute sets */
1792 for (set
= index
->set_list
.head
; set
;
1795 * set cmds return RMAP_OKAY or
1796 * RMAP_ERROR. We do not care if
1797 * set succeeded or not. So, ignore
1800 (void) (*set
->cmd
->func_apply
)(
1801 set
->value
, prefix
, type
,
1804 /* Call another route-map if available */
1805 if (index
->nextrm
) {
1806 struct route_map
*nextrm
=
1807 route_map_lookup_by_name(
1810 if (nextrm
) /* Target route-map found,
1814 ret
= route_map_apply(
1815 nextrm
, prefix
, type
,
1820 /* If nextrm returned 'deny', finish. */
1821 if (ret
== RMAP_DENYMATCH
)
1822 goto route_map_apply_end
;
1825 switch (index
->exitpolicy
) {
1827 goto route_map_apply_end
;
1831 /* Find the next clause to jump to */
1832 struct route_map_index
*next
=
1834 int nextpref
= index
->nextpref
;
1836 while (next
&& next
->pref
< nextpref
) {
1841 /* No clauses match! */
1842 goto route_map_apply_end
;
1846 } else if (index
->type
== RMAP_DENY
)
1849 ret
= RMAP_DENYMATCH
;
1850 goto route_map_apply_end
;
1855 route_map_apply_end
:
1857 zlog_debug("Route-map: %s, prefix: %s, result: %s",
1858 (map
? map
->name
: "null"),
1859 prefix2str(prefix
, buf
, sizeof(buf
)),
1860 route_map_result_str(ret
));
1866 void route_map_add_hook(void (*func
)(const char *))
1868 route_map_master
.add_hook
= func
;
1871 void route_map_delete_hook(void (*func
)(const char *))
1873 route_map_master
.delete_hook
= func
;
1876 void route_map_event_hook(void (*func
)(const char *name
))
1878 route_map_master
.event_hook
= func
;
1881 /* Routines for route map dependency lists and dependency processing */
1882 static bool route_map_rmap_hash_cmp(const void *p1
, const void *p2
)
1884 return strcmp(((const struct route_map_dep_data
*)p1
)->rname
,
1885 ((const struct route_map_dep_data
*)p2
)->rname
)
1889 static bool route_map_dep_hash_cmp(const void *p1
, const void *p2
)
1892 return (strcmp(((const struct route_map_dep
*)p1
)->dep_name
,
1897 static void route_map_clear_reference(struct hash_bucket
*bucket
, void *arg
)
1899 struct route_map_dep
*dep
= bucket
->data
;
1900 struct route_map_dep_data
*dep_data
= NULL
, tmp_dep_data
;
1903 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
1904 tmp_dep_data
.rname
= arg
;
1905 dep_data
= hash_release(dep
->dep_rmap_hash
,
1908 XFREE(MTYPE_ROUTE_MAP_NAME
, dep_data
->rname
);
1909 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, dep_data
);
1911 if (!dep
->dep_rmap_hash
->count
) {
1912 dep
= hash_release(dep
->this_hash
,
1913 (void *)dep
->dep_name
);
1914 hash_free(dep
->dep_rmap_hash
);
1915 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
1916 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
1921 static void route_map_clear_all_references(char *rmap_name
)
1925 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
1926 hash_iterate(route_map_dep_hash
[i
], route_map_clear_reference
,
1931 static unsigned int route_map_dep_data_hash_make_key(const void *p
)
1933 const struct route_map_dep_data
*dep_data
= p
;
1935 return string_hash_make(dep_data
->rname
);
1938 static void *route_map_dep_hash_alloc(void *p
)
1940 char *dep_name
= (char *)p
;
1941 struct route_map_dep
*dep_entry
;
1943 dep_entry
= XCALLOC(MTYPE_ROUTE_MAP_DEP
, sizeof(struct route_map_dep
));
1944 dep_entry
->dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1945 dep_entry
->dep_rmap_hash
=
1946 hash_create_size(8, route_map_dep_data_hash_make_key
,
1947 route_map_rmap_hash_cmp
, "Route Map Dep Hash");
1948 dep_entry
->this_hash
= NULL
;
1953 static void *route_map_name_hash_alloc(void *p
)
1955 struct route_map_dep_data
*dep_data
= NULL
, *tmp_dep_data
= NULL
;
1957 dep_data
= XCALLOC(MTYPE_ROUTE_MAP_DEP_DATA
,
1958 sizeof(struct route_map_dep_data
));
1960 dep_data
->rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, tmp_dep_data
->rname
);
1964 static unsigned int route_map_dep_hash_make_key(const void *p
)
1966 return (string_hash_make((char *)p
));
1969 static void route_map_print_dependency(struct hash_bucket
*bucket
, void *data
)
1971 struct route_map_dep_data
*dep_data
= bucket
->data
;
1972 char *rmap_name
= dep_data
->rname
;
1973 char *dep_name
= data
;
1975 zlog_debug("%s: Dependency for %s: %s", __FUNCTION__
, dep_name
,
1979 static int route_map_dep_update(struct hash
*dephash
, const char *dep_name
,
1980 const char *rmap_name
, route_map_event_t type
)
1982 struct route_map_dep
*dep
= NULL
;
1983 char *dname
, *rname
;
1985 struct route_map_dep_data
*dep_data
= NULL
, *ret_dep_data
= NULL
;
1986 struct route_map_dep_data tmp_dep_data
;
1988 dname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1989 rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
1992 case RMAP_EVENT_PLIST_ADDED
:
1993 case RMAP_EVENT_CLIST_ADDED
:
1994 case RMAP_EVENT_ECLIST_ADDED
:
1995 case RMAP_EVENT_ASLIST_ADDED
:
1996 case RMAP_EVENT_LLIST_ADDED
:
1997 case RMAP_EVENT_CALL_ADDED
:
1998 case RMAP_EVENT_FILTER_ADDED
:
2000 zlog_debug("Adding dependency for filter %s in route-map %s",
2001 dep_name
, rmap_name
);
2002 dep
= (struct route_map_dep
*)hash_get(
2003 dephash
, dname
, route_map_dep_hash_alloc
);
2009 if (!dep
->this_hash
)
2010 dep
->this_hash
= dephash
;
2012 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
2013 tmp_dep_data
.rname
= rname
;
2014 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
2016 dep_data
= hash_get(dep
->dep_rmap_hash
, &tmp_dep_data
,
2017 route_map_name_hash_alloc
);
2021 case RMAP_EVENT_PLIST_DELETED
:
2022 case RMAP_EVENT_CLIST_DELETED
:
2023 case RMAP_EVENT_ECLIST_DELETED
:
2024 case RMAP_EVENT_ASLIST_DELETED
:
2025 case RMAP_EVENT_LLIST_DELETED
:
2026 case RMAP_EVENT_CALL_DELETED
:
2027 case RMAP_EVENT_FILTER_DELETED
:
2029 zlog_debug("Deleting dependency for filter %s in route-map %s",
2030 dep_name
, rmap_name
);
2031 dep
= (struct route_map_dep
*)hash_get(dephash
, dname
, NULL
);
2036 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
2037 tmp_dep_data
.rname
= rname
;
2038 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
2041 if (!dep_data
->refcnt
) {
2042 ret_dep_data
= hash_release(dep
->dep_rmap_hash
,
2045 XFREE(MTYPE_ROUTE_MAP_NAME
,
2046 ret_dep_data
->rname
);
2047 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, ret_dep_data
);
2051 if (!dep
->dep_rmap_hash
->count
) {
2052 dep
= hash_release(dephash
, dname
);
2053 hash_free(dep
->dep_rmap_hash
);
2054 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
2055 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
2059 case RMAP_EVENT_SET_ADDED
:
2060 case RMAP_EVENT_SET_DELETED
:
2061 case RMAP_EVENT_SET_REPLACED
:
2062 case RMAP_EVENT_MATCH_ADDED
:
2063 case RMAP_EVENT_MATCH_DELETED
:
2064 case RMAP_EVENT_MATCH_REPLACED
:
2065 case RMAP_EVENT_INDEX_ADDED
:
2066 case RMAP_EVENT_INDEX_DELETED
:
2072 hash_iterate(dep
->dep_rmap_hash
,
2073 route_map_print_dependency
, dname
);
2077 XFREE(MTYPE_ROUTE_MAP_NAME
, rname
);
2078 XFREE(MTYPE_ROUTE_MAP_NAME
, dname
);
2082 static struct hash
*route_map_get_dep_hash(route_map_event_t event
)
2084 struct hash
*upd8_hash
= NULL
;
2087 case RMAP_EVENT_PLIST_ADDED
:
2088 case RMAP_EVENT_PLIST_DELETED
:
2089 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_PLIST
];
2091 case RMAP_EVENT_CLIST_ADDED
:
2092 case RMAP_EVENT_CLIST_DELETED
:
2093 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_CLIST
];
2095 case RMAP_EVENT_ECLIST_ADDED
:
2096 case RMAP_EVENT_ECLIST_DELETED
:
2097 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ECLIST
];
2099 case RMAP_EVENT_ASLIST_ADDED
:
2100 case RMAP_EVENT_ASLIST_DELETED
:
2101 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ASPATH
];
2103 case RMAP_EVENT_LLIST_ADDED
:
2104 case RMAP_EVENT_LLIST_DELETED
:
2105 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_LCLIST
];
2107 case RMAP_EVENT_CALL_ADDED
:
2108 case RMAP_EVENT_CALL_DELETED
:
2109 case RMAP_EVENT_MATCH_ADDED
:
2110 case RMAP_EVENT_MATCH_DELETED
:
2111 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_RMAP
];
2113 case RMAP_EVENT_FILTER_ADDED
:
2114 case RMAP_EVENT_FILTER_DELETED
:
2115 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_FILTER
];
2118 * Should we actually be ignoring these?
2119 * I am not sure but at this point in time, let
2120 * us get them into this switch and we can peel
2121 * them into the appropriate place in the future
2123 case RMAP_EVENT_SET_ADDED
:
2124 case RMAP_EVENT_SET_DELETED
:
2125 case RMAP_EVENT_SET_REPLACED
:
2126 case RMAP_EVENT_MATCH_REPLACED
:
2127 case RMAP_EVENT_INDEX_ADDED
:
2128 case RMAP_EVENT_INDEX_DELETED
:
2135 static void route_map_process_dependency(struct hash_bucket
*bucket
, void *data
)
2137 struct route_map_dep_data
*dep_data
= NULL
;
2138 char *rmap_name
= NULL
;
2140 dep_data
= bucket
->data
;
2141 rmap_name
= dep_data
->rname
;
2144 zlog_debug("Notifying %s of dependency", rmap_name
);
2145 if (route_map_master
.event_hook
)
2146 (*route_map_master
.event_hook
)(rmap_name
);
2149 void route_map_upd8_dependency(route_map_event_t type
, const char *arg
,
2150 const char *rmap_name
)
2152 struct hash
*upd8_hash
= NULL
;
2154 if ((upd8_hash
= route_map_get_dep_hash(type
))) {
2155 route_map_dep_update(upd8_hash
, arg
, rmap_name
, type
);
2157 if (type
== RMAP_EVENT_CALL_ADDED
) {
2159 if (route_map_master
.add_hook
)
2160 (*route_map_master
.add_hook
)(rmap_name
);
2161 } else if (type
== RMAP_EVENT_CALL_DELETED
) {
2163 if (route_map_master
.delete_hook
)
2164 (*route_map_master
.delete_hook
)(rmap_name
);
2169 void route_map_notify_dependencies(const char *affected_name
,
2170 route_map_event_t event
)
2172 struct route_map_dep
*dep
;
2173 struct hash
*upd8_hash
;
2179 name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, affected_name
);
2181 if ((upd8_hash
= route_map_get_dep_hash(event
)) == NULL
) {
2182 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
2186 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, name
, NULL
);
2188 if (!dep
->this_hash
)
2189 dep
->this_hash
= upd8_hash
;
2192 zlog_debug("Filter %s updated", dep
->dep_name
);
2193 hash_iterate(dep
->dep_rmap_hash
, route_map_process_dependency
,
2197 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
2201 /* VTY related functions. */
2202 DEFUN (match_interface
,
2203 match_interface_cmd
,
2204 "match interface WORD",
2206 "match first hop interface of route\n"
2210 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2212 if (rmap_match_set_hook
.match_interface
)
2213 return rmap_match_set_hook
.match_interface(
2214 vty
, index
, "interface", argv
[idx_word
]->arg
,
2215 RMAP_EVENT_MATCH_ADDED
);
2219 DEFUN (no_match_interface
,
2220 no_match_interface_cmd
,
2221 "no match interface [WORD]",
2224 "Match first hop interface of route\n"
2227 char *iface
= (argc
== 4) ? argv
[3]->arg
: NULL
;
2228 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2230 if (rmap_match_set_hook
.no_match_interface
)
2231 return rmap_match_set_hook
.no_match_interface(
2232 vty
, index
, "interface", iface
,
2233 RMAP_EVENT_MATCH_DELETED
);
2238 DEFUN (match_ip_address
,
2239 match_ip_address_cmd
,
2240 "match ip address <(1-199)|(1300-2699)|WORD>",
2243 "Match address of route\n"
2244 "IP access-list number\n"
2245 "IP access-list number (expanded range)\n"
2246 "IP Access-list name\n")
2249 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2251 if (rmap_match_set_hook
.match_ip_address
)
2252 return rmap_match_set_hook
.match_ip_address(
2253 vty
, index
, "ip address", argv
[idx_acl
]->arg
,
2254 RMAP_EVENT_FILTER_ADDED
);
2259 DEFUN (no_match_ip_address
,
2260 no_match_ip_address_cmd
,
2261 "no match ip address [<(1-199)|(1300-2699)|WORD>]",
2265 "Match address of route\n"
2266 "IP access-list number\n"
2267 "IP access-list number (expanded range)\n"
2268 "IP Access-list name\n")
2271 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2273 if (rmap_match_set_hook
.no_match_ip_address
) {
2274 if (argc
<= idx_word
)
2275 return rmap_match_set_hook
.no_match_ip_address(
2276 vty
, index
, "ip address", NULL
,
2277 RMAP_EVENT_FILTER_DELETED
);
2278 return rmap_match_set_hook
.no_match_ip_address(
2279 vty
, index
, "ip address", argv
[idx_word
]->arg
,
2280 RMAP_EVENT_FILTER_DELETED
);
2286 DEFUN (match_ip_address_prefix_list
,
2287 match_ip_address_prefix_list_cmd
,
2288 "match ip address prefix-list WORD",
2291 "Match address of route\n"
2292 "Match entries of prefix-lists\n"
2293 "IP prefix-list name\n")
2296 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2298 if (rmap_match_set_hook
.match_ip_address_prefix_list
)
2299 return rmap_match_set_hook
.match_ip_address_prefix_list(
2300 vty
, index
, "ip address prefix-list",
2301 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
2306 DEFUN (no_match_ip_address_prefix_list
,
2307 no_match_ip_address_prefix_list_cmd
,
2308 "no match ip address prefix-list [WORD]",
2312 "Match address of route\n"
2313 "Match entries of prefix-lists\n"
2314 "IP prefix-list name\n")
2317 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2319 if (rmap_match_set_hook
.no_match_ip_address_prefix_list
) {
2320 if (argc
<= idx_word
)
2321 return rmap_match_set_hook
2322 .no_match_ip_address_prefix_list(
2323 vty
, index
, "ip address prefix-list",
2324 NULL
, RMAP_EVENT_PLIST_DELETED
);
2325 return rmap_match_set_hook
.no_match_ip_address_prefix_list(
2326 vty
, index
, "ip address prefix-list",
2327 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2333 DEFUN (match_ip_next_hop
,
2334 match_ip_next_hop_cmd
,
2335 "match ip next-hop <(1-199)|(1300-2699)|WORD>",
2338 "Match next-hop address of route\n"
2339 "IP access-list number\n"
2340 "IP access-list number (expanded range)\n"
2341 "IP Access-list name\n")
2344 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2346 if (rmap_match_set_hook
.match_ip_next_hop
)
2347 return rmap_match_set_hook
.match_ip_next_hop(
2348 vty
, index
, "ip next-hop", argv
[idx_acl
]->arg
,
2349 RMAP_EVENT_FILTER_ADDED
);
2354 DEFUN (no_match_ip_next_hop
,
2355 no_match_ip_next_hop_cmd
,
2356 "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
2360 "Match next-hop address of route\n"
2361 "IP access-list number\n"
2362 "IP access-list number (expanded range)\n"
2363 "IP Access-list name\n")
2366 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2368 if (rmap_match_set_hook
.no_match_ip_next_hop
) {
2369 if (argc
<= idx_word
)
2370 return rmap_match_set_hook
.no_match_ip_next_hop(
2371 vty
, index
, "ip next-hop", NULL
,
2372 RMAP_EVENT_FILTER_DELETED
);
2373 return rmap_match_set_hook
.no_match_ip_next_hop(
2374 vty
, index
, "ip next-hop", argv
[idx_word
]->arg
,
2375 RMAP_EVENT_FILTER_DELETED
);
2381 DEFUN (match_ip_next_hop_prefix_list
,
2382 match_ip_next_hop_prefix_list_cmd
,
2383 "match ip next-hop prefix-list WORD",
2386 "Match next-hop address of route\n"
2387 "Match entries of prefix-lists\n"
2388 "IP prefix-list name\n")
2391 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2393 if (rmap_match_set_hook
.match_ip_next_hop_prefix_list
)
2394 return rmap_match_set_hook
.match_ip_next_hop_prefix_list(
2395 vty
, index
, "ip next-hop prefix-list",
2396 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
2400 DEFUN (no_match_ip_next_hop_prefix_list
,
2401 no_match_ip_next_hop_prefix_list_cmd
,
2402 "no match ip next-hop prefix-list [WORD]",
2406 "Match next-hop address of route\n"
2407 "Match entries of prefix-lists\n"
2408 "IP prefix-list name\n")
2411 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2413 if (rmap_match_set_hook
.no_match_ip_next_hop
) {
2414 if (argc
<= idx_word
)
2415 return rmap_match_set_hook
.no_match_ip_next_hop(
2416 vty
, index
, "ip next-hop prefix-list", NULL
,
2417 RMAP_EVENT_PLIST_DELETED
);
2418 return rmap_match_set_hook
.no_match_ip_next_hop(
2419 vty
, index
, "ip next-hop prefix-list",
2420 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2425 DEFUN(match_ip_next_hop_type
, match_ip_next_hop_type_cmd
,
2426 "match ip next-hop type <blackhole>",
2428 "Match next-hop address of route\n"
2429 "Match entries by type\n"
2433 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2435 if (rmap_match_set_hook
.match_ip_next_hop_type
)
2436 return rmap_match_set_hook
.match_ip_next_hop_type(
2437 vty
, index
, "ip next-hop type", argv
[idx_word
]->arg
,
2438 RMAP_EVENT_MATCH_ADDED
);
2442 DEFUN(no_match_ip_next_hop_type
, no_match_ip_next_hop_type_cmd
,
2443 "no match ip next-hop type [<blackhole>]",
2444 NO_STR MATCH_STR IP_STR
2445 "Match next-hop address of route\n"
2446 "Match entries by type\n"
2450 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2452 if (rmap_match_set_hook
.no_match_ip_next_hop
) {
2453 if (argc
<= idx_word
)
2454 return rmap_match_set_hook
.no_match_ip_next_hop(
2455 vty
, index
, "ip next-hop type", NULL
,
2456 RMAP_EVENT_MATCH_DELETED
);
2457 return rmap_match_set_hook
.no_match_ip_next_hop(
2458 vty
, index
, "ip next-hop type", argv
[idx_word
]->arg
,
2459 RMAP_EVENT_MATCH_DELETED
);
2465 DEFUN (match_ipv6_address
,
2466 match_ipv6_address_cmd
,
2467 "match ipv6 address WORD",
2470 "Match IPv6 address of route\n"
2471 "IPv6 access-list name\n")
2474 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2476 if (rmap_match_set_hook
.match_ipv6_address
)
2477 return rmap_match_set_hook
.match_ipv6_address(
2478 vty
, index
, "ipv6 address", argv
[idx_word
]->arg
,
2479 RMAP_EVENT_FILTER_ADDED
);
2483 DEFUN (no_match_ipv6_address
,
2484 no_match_ipv6_address_cmd
,
2485 "no match ipv6 address WORD",
2489 "Match IPv6 address of route\n"
2490 "IPv6 access-list name\n")
2493 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2495 if (rmap_match_set_hook
.no_match_ipv6_address
)
2496 return rmap_match_set_hook
.no_match_ipv6_address(
2497 vty
, index
, "ipv6 address", argv
[idx_word
]->arg
,
2498 RMAP_EVENT_FILTER_DELETED
);
2503 DEFUN (match_ipv6_address_prefix_list
,
2504 match_ipv6_address_prefix_list_cmd
,
2505 "match ipv6 address prefix-list WORD",
2508 "Match address of route\n"
2509 "Match entries of prefix-lists\n"
2510 "IP prefix-list name\n")
2513 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2515 if (rmap_match_set_hook
.match_ipv6_address_prefix_list
)
2516 return rmap_match_set_hook
.match_ipv6_address_prefix_list(
2517 vty
, index
, "ipv6 address prefix-list",
2518 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
2522 DEFUN (no_match_ipv6_address_prefix_list
,
2523 no_match_ipv6_address_prefix_list_cmd
,
2524 "no match ipv6 address prefix-list WORD",
2528 "Match address of route\n"
2529 "Match entries of prefix-lists\n"
2530 "IP prefix-list name\n")
2533 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2535 if (rmap_match_set_hook
.no_match_ipv6_address_prefix_list
)
2536 return rmap_match_set_hook
.no_match_ipv6_address_prefix_list(
2537 vty
, index
, "ipv6 address prefix-list",
2538 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2542 DEFUN(match_ipv6_next_hop_type
, match_ipv6_next_hop_type_cmd
,
2543 "match ipv6 next-hop type <blackhole>",
2545 "Match next-hop address of route\n"
2546 "Match entries by type\n"
2550 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2552 if (rmap_match_set_hook
.match_ipv6_next_hop_type
)
2553 return rmap_match_set_hook
.match_ipv6_next_hop_type(
2554 vty
, index
, "ipv6 next-hop type", argv
[idx_word
]->arg
,
2555 RMAP_EVENT_MATCH_ADDED
);
2559 DEFUN(no_match_ipv6_next_hop_type
, no_match_ipv6_next_hop_type_cmd
,
2560 "no match ipv6 next-hop type [<blackhole>]",
2561 NO_STR MATCH_STR IPV6_STR
2562 "Match address of route\n"
2563 "Match entries by type\n"
2567 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2569 if (rmap_match_set_hook
.no_match_ipv6_next_hop_type
)
2570 return rmap_match_set_hook
.no_match_ipv6_next_hop_type(
2571 vty
, index
, "ipv6 next-hop type",
2572 (argc
<= idx_word
) ? NULL
: argv
[idx_word
]->arg
,
2573 RMAP_EVENT_MATCH_DELETED
);
2577 DEFUN (match_metric
,
2579 "match metric (0-4294967295)",
2581 "Match metric of route\n"
2585 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2587 if (rmap_match_set_hook
.match_metric
)
2588 return rmap_match_set_hook
.match_metric(vty
, index
, "metric",
2589 argv
[idx_number
]->arg
,
2590 RMAP_EVENT_MATCH_ADDED
);
2595 DEFUN (no_match_metric
,
2596 no_match_metric_cmd
,
2597 "no match metric [(0-4294967295)]",
2600 "Match metric of route\n"
2604 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2606 if (rmap_match_set_hook
.no_match_metric
) {
2607 if (argc
<= idx_number
)
2608 return rmap_match_set_hook
.no_match_metric(
2609 vty
, index
, "metric", NULL
,
2610 RMAP_EVENT_MATCH_DELETED
);
2611 return rmap_match_set_hook
.no_match_metric(
2612 vty
, index
, "metric", argv
[idx_number
]->arg
,
2613 RMAP_EVENT_MATCH_DELETED
);
2621 "match tag (1-4294967295)",
2623 "Match tag of route\n"
2627 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2629 if (rmap_match_set_hook
.match_tag
)
2630 return rmap_match_set_hook
.match_tag(vty
, index
, "tag",
2631 argv
[idx_number
]->arg
,
2632 RMAP_EVENT_MATCH_ADDED
);
2637 DEFUN (no_match_tag
,
2639 "no match tag [(1-4294967295)]",
2642 "Match tag of route\n"
2645 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2648 char *arg
= argv_find(argv
, argc
, "(1-4294967295)", &idx
)
2652 if (rmap_match_set_hook
.no_match_tag
)
2653 return rmap_match_set_hook
.no_match_tag(
2654 vty
, index
, "tag", arg
, RMAP_EVENT_MATCH_DELETED
);
2659 DEFUN (set_ip_nexthop
,
2661 "set ip next-hop A.B.C.D",
2664 "Next hop address\n"
2665 "IP address of next hop\n")
2670 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2672 ret
= str2sockunion(argv
[idx_ipv4
]->arg
, &su
);
2674 vty_out(vty
, "%% Malformed nexthop address\n");
2675 return CMD_WARNING_CONFIG_FAILED
;
2677 if (su
.sin
.sin_addr
.s_addr
== 0
2678 || IPV4_CLASS_DE(ntohl(su
.sin
.sin_addr
.s_addr
))) {
2680 "%% nexthop address cannot be 0.0.0.0, multicast or reserved\n");
2681 return CMD_WARNING_CONFIG_FAILED
;
2684 if (rmap_match_set_hook
.set_ip_nexthop
)
2685 return rmap_match_set_hook
.set_ip_nexthop(
2686 vty
, index
, "ip next-hop", argv
[idx_ipv4
]->arg
);
2691 DEFUN (no_set_ip_nexthop
,
2692 no_set_ip_nexthop_cmd
,
2693 "no set ip next-hop [A.B.C.D]",
2697 "Next hop address\n"
2698 "IP address of next hop\n")
2701 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2702 const char *arg
= NULL
;
2704 if (argv_find(argv
, argc
, "A.B.C.D", &idx
))
2705 arg
= argv
[idx
]->arg
;
2707 if (rmap_match_set_hook
.no_set_ip_nexthop
)
2708 return rmap_match_set_hook
.no_set_ip_nexthop(
2709 vty
, index
, "ip next-hop", arg
);
2715 DEFUN (set_ipv6_nexthop_local
,
2716 set_ipv6_nexthop_local_cmd
,
2717 "set ipv6 next-hop local X:X::X:X",
2720 "IPv6 next-hop address\n"
2721 "IPv6 local address\n"
2722 "IPv6 address of next hop\n")
2725 struct in6_addr addr
;
2727 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2729 ret
= inet_pton(AF_INET6
, argv
[idx_ipv6
]->arg
, &addr
);
2731 vty_out(vty
, "%% Malformed nexthop address\n");
2732 return CMD_WARNING_CONFIG_FAILED
;
2734 if (!IN6_IS_ADDR_LINKLOCAL(&addr
)) {
2735 vty_out(vty
, "%% Invalid link-local nexthop address\n");
2736 return CMD_WARNING_CONFIG_FAILED
;
2739 if (rmap_match_set_hook
.set_ipv6_nexthop_local
)
2740 return rmap_match_set_hook
.set_ipv6_nexthop_local(
2741 vty
, index
, "ipv6 next-hop local", argv
[idx_ipv6
]->arg
);
2746 DEFUN (no_set_ipv6_nexthop_local
,
2747 no_set_ipv6_nexthop_local_cmd
,
2748 "no set ipv6 next-hop local [X:X::X:X]",
2752 "IPv6 next-hop address\n"
2753 "IPv6 local address\n"
2754 "IPv6 address of next hop\n")
2757 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2759 if (rmap_match_set_hook
.no_set_ipv6_nexthop_local
) {
2760 if (argc
<= idx_ipv6
)
2761 return rmap_match_set_hook
.no_set_ipv6_nexthop_local(
2762 vty
, index
, "ipv6 next-hop local", NULL
);
2763 return rmap_match_set_hook
.no_set_ipv6_nexthop_local(
2764 vty
, index
, "ipv6 next-hop local", argv
[5]->arg
);
2771 "set metric <(0-4294967295)|rtt|+rtt|-rtt|+metric|-metric>",
2773 "Metric value for destination routing protocol\n"
2775 "Assign round trip time\n"
2776 "Add round trip time\n"
2777 "Subtract round trip time\n"
2779 "Subtract metric\n")
2782 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2784 const char *pass
= (argv
[idx_number
]->type
== RANGE_TKN
)
2785 ? argv
[idx_number
]->arg
2786 : argv
[idx_number
]->text
;
2788 if (rmap_match_set_hook
.set_metric
)
2789 return rmap_match_set_hook
.set_metric(vty
, index
, "metric",
2795 DEFUN (no_set_metric
,
2797 "no set metric [(0-4294967295)]",
2800 "Metric value for destination routing protocol\n"
2804 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2806 if (rmap_match_set_hook
.no_set_metric
) {
2807 if (argc
<= idx_number
)
2808 return rmap_match_set_hook
.no_set_metric(
2809 vty
, index
, "metric", NULL
);
2810 return rmap_match_set_hook
.no_set_metric(vty
, index
, "metric",
2811 argv
[idx_number
]->arg
);
2819 "set tag (1-4294967295)",
2821 "Tag value for routing protocol\n"
2824 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2827 if (rmap_match_set_hook
.set_tag
)
2828 return rmap_match_set_hook
.set_tag(vty
, index
, "tag",
2829 argv
[idx_number
]->arg
);
2836 "no set tag [(1-4294967295)]",
2839 "Tag value for routing protocol\n"
2842 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2845 if (rmap_match_set_hook
.no_set_tag
) {
2846 if (argc
<= idx_number
)
2847 return rmap_match_set_hook
.no_set_tag(vty
, index
, "tag",
2849 return rmap_match_set_hook
.no_set_tag(vty
, index
, "tag",
2850 argv
[idx_number
]->arg
);
2856 DEFUN_NOSH (route_map
,
2858 "route-map WORD <deny|permit> (1-65535)",
2859 "Create route-map or enter route-map command mode\n"
2861 "Route map denies set operations\n"
2862 "Route map permits set operations\n"
2863 "Sequence to insert to/delete from existing route-map entry\n")
2866 int idx_permit_deny
= 2;
2868 struct route_map
*map
;
2869 struct route_map_index
*index
;
2870 char *endptr
= NULL
;
2872 argv
[idx_permit_deny
]->arg
[0] == 'p' ? RMAP_PERMIT
: RMAP_DENY
;
2873 unsigned long pref
= strtoul(argv
[idx_number
]->arg
, &endptr
, 10);
2874 const char *mapname
= argv
[idx_word
]->arg
;
2876 /* Get route map. */
2877 map
= route_map_get(mapname
);
2878 index
= route_map_index_get(map
, permit
, pref
);
2880 VTY_PUSH_CONTEXT(RMAP_NODE
, index
);
2884 DEFUN (no_route_map_all
,
2885 no_route_map_all_cmd
,
2886 "no route-map WORD",
2888 "Create route-map or enter route-map command mode\n"
2892 const char *mapname
= argv
[idx_word
]->arg
;
2893 struct route_map
*map
;
2895 map
= route_map_lookup_by_name(mapname
);
2897 vty_out(vty
, "%% Could not find route-map %s\n", mapname
);
2898 return CMD_WARNING_CONFIG_FAILED
;
2901 route_map_delete(map
);
2906 DEFUN (no_route_map
,
2908 "no route-map WORD <deny|permit> (1-65535)",
2910 "Create route-map or enter route-map command mode\n"
2912 "Route map denies set operations\n"
2913 "Route map permits set operations\n"
2914 "Sequence to insert to/delete from existing route-map entry\n")
2917 int idx_permit_deny
= 3;
2919 struct route_map
*map
;
2920 struct route_map_index
*index
;
2921 char *endptr
= NULL
;
2922 int permit
= strmatch(argv
[idx_permit_deny
]->text
, "permit")
2925 const char *prefstr
= argv
[idx_number
]->arg
;
2926 const char *mapname
= argv
[idx_word
]->arg
;
2927 unsigned long pref
= strtoul(prefstr
, &endptr
, 10);
2929 /* Existence check. */
2930 map
= route_map_lookup_by_name(mapname
);
2932 vty_out(vty
, "%% Could not find route-map %s\n", mapname
);
2933 return CMD_WARNING_CONFIG_FAILED
;
2936 /* Lookup route map index. */
2937 index
= route_map_index_lookup(map
, permit
, pref
);
2938 if (index
== NULL
) {
2939 vty_out(vty
, "%% Could not find route-map entry %s %s\n",
2941 return CMD_WARNING_CONFIG_FAILED
;
2944 /* Delete index from route map. */
2945 route_map_index_delete(index
, 1);
2947 /* If this route rule is the last one, delete route map itself. */
2948 if (route_map_empty(map
))
2949 route_map_delete(map
);
2954 DEFUN (rmap_onmatch_next
,
2955 rmap_onmatch_next_cmd
,
2957 "Exit policy on matches\n"
2960 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2963 if (index
->type
== RMAP_DENY
) {
2964 /* Under a deny clause, match means it's finished. No
2965 * need to set next */
2967 "on-match next not supported under route-map deny\n");
2968 return CMD_WARNING_CONFIG_FAILED
;
2970 index
->exitpolicy
= RMAP_NEXT
;
2975 DEFUN (no_rmap_onmatch_next
,
2976 no_rmap_onmatch_next_cmd
,
2979 "Exit policy on matches\n"
2982 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2985 index
->exitpolicy
= RMAP_EXIT
;
2990 DEFUN (rmap_onmatch_goto
,
2991 rmap_onmatch_goto_cmd
,
2992 "on-match goto (1-65535)",
2993 "Exit policy on matches\n"
2994 "Goto Clause number\n"
2998 char *num
= argv_find(argv
, argc
, "(1-65535)", &idx
) ? argv
[idx
]->arg
3001 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
3005 if (index
->type
== RMAP_DENY
) {
3006 /* Under a deny clause, match means it's finished. No
3007 * need to go anywhere */
3009 "on-match goto not supported under route-map deny\n");
3010 return CMD_WARNING_CONFIG_FAILED
;
3014 d
= strtoul(num
, NULL
, 10);
3016 d
= index
->pref
+ 1;
3018 if (d
<= index
->pref
) {
3019 /* Can't allow you to do that, Dave */
3020 vty_out(vty
, "can't jump backwards in route-maps\n");
3021 return CMD_WARNING_CONFIG_FAILED
;
3023 index
->exitpolicy
= RMAP_GOTO
;
3024 index
->nextpref
= d
;
3030 DEFUN (no_rmap_onmatch_goto
,
3031 no_rmap_onmatch_goto_cmd
,
3034 "Exit policy on matches\n"
3035 "Goto Clause number\n")
3037 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
3040 index
->exitpolicy
= RMAP_EXIT
;
3045 /* Cisco/GNU Zebra compatibility aliases */
3047 DEFUN (rmap_continue
,
3049 "continue (1-65535)",
3050 "Continue on a different entry within the route-map\n"
3051 "Route-map entry sequence number\n")
3053 return rmap_onmatch_goto(self
, vty
, argc
, argv
);
3057 DEFUN (no_rmap_continue
,
3058 no_rmap_continue_cmd
,
3059 "no continue [(1-65535)]",
3061 "Continue on a different entry within the route-map\n"
3062 "Route-map entry sequence number\n")
3064 return no_rmap_onmatch_goto(self
, vty
, argc
, argv
);
3067 static void clear_route_map_helper(struct route_map
*map
)
3069 struct route_map_index
*index
;
3071 map
->applied_clear
= map
->applied
;
3072 for (index
= map
->head
; index
; index
= index
->next
)
3073 index
->applied_clear
= index
->applied
;
3076 DEFUN (rmap_clear_counters
,
3077 rmap_clear_counters_cmd
,
3078 "clear route-map counters [WORD]",
3080 "route-map information\n"
3081 "counters associated with the specified route-map\n"
3085 struct route_map
*map
;
3087 const char *name
= (argc
== 3 ) ? argv
[idx_word
]->arg
: NULL
;
3090 map
= route_map_lookup_by_name(name
);
3093 clear_route_map_helper(map
);
3095 vty_out(vty
, "%s: 'route-map %s' not found\n",
3096 frr_protonameinst
, name
);
3100 for (map
= route_map_master
.head
; map
; map
= map
->next
)
3101 clear_route_map_helper(map
);
3108 DEFUN (rmap_show_name
,
3110 "show route-map [WORD]",
3112 "route-map information\n"
3116 const char *name
= (argc
== 3) ? argv
[idx_word
]->arg
: NULL
;
3117 return vty_show_route_map(vty
, name
);
3120 DEFUN (rmap_show_unused
,
3121 rmap_show_unused_cmd
,
3122 "show route-map-unused",
3124 "unused route-map information\n")
3126 return vty_show_unused_route_map(vty
);
3132 "Jump to another Route-Map after match+set\n"
3133 "Target route-map name\n")
3136 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
3137 const char *rmap
= argv
[idx_word
]->arg
;
3141 /* If "call" is invoked with the same route-map name as
3142 * the one previously configured then, ignore the duplicate
3145 if (index
->nextrm
&& (strcmp(index
->nextrm
, rmap
) == 0))
3148 if (index
->nextrm
) {
3149 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED
,
3150 index
->nextrm
, index
->map
->name
);
3151 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
3153 index
->nextrm
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap
);
3155 /* Execute event hook. */
3156 route_map_upd8_dependency(RMAP_EVENT_CALL_ADDED
, index
->nextrm
,
3161 DEFUN (no_rmap_call
,
3165 "Jump to another Route-Map after match+set\n")
3167 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
3169 if (index
->nextrm
) {
3170 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED
,
3171 index
->nextrm
, index
->map
->name
);
3172 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
3173 index
->nextrm
= NULL
;
3179 DEFUN (rmap_description
,
3180 rmap_description_cmd
,
3181 "description LINE...",
3182 "Route-map comment\n"
3183 "Comment describing this route-map rule\n")
3186 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
3189 if (index
->description
)
3190 XFREE(MTYPE_TMP
, index
->description
);
3191 index
->description
= argv_concat(argv
, argc
, idx_line
);
3196 DEFUN (no_rmap_description
,
3197 no_rmap_description_cmd
,
3200 "Route-map comment\n")
3202 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
3205 if (index
->description
)
3206 XFREE(MTYPE_TMP
, index
->description
);
3207 index
->description
= NULL
;
3216 "Debug option set for route-maps\n")
3222 DEFUN (no_debug_rmap
,
3224 "no debug route-map",
3227 "Debug option set for route-maps\n")
3234 static struct cmd_node rmap_debug_node
= {RMAP_DEBUG_NODE
, "", 1};
3236 /* Configuration write function. */
3237 static int route_map_config_write(struct vty
*vty
)
3239 struct route_map
*map
;
3240 struct route_map_index
*index
;
3241 struct route_map_rule
*rule
;
3244 struct listnode
*ln
;
3245 struct list
*maplist
= list_new();
3247 for (map
= route_map_master
.head
; map
; map
= map
->next
)
3248 listnode_add(maplist
, map
);
3250 list_sort(maplist
, sort_route_map
);
3252 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
3253 for (index
= map
->head
; index
; index
= index
->next
) {
3255 vty_out(vty
, "!\n");
3259 vty_out(vty
, "route-map %s %s %d\n", map
->name
,
3260 route_map_type_str(index
->type
), index
->pref
);
3262 if (index
->description
)
3263 vty_out(vty
, " description %s\n",
3264 index
->description
);
3266 for (rule
= index
->match_list
.head
; rule
;
3268 vty_out(vty
, " match %s %s\n", rule
->cmd
->str
,
3269 rule
->rule_str
? rule
->rule_str
: "");
3271 for (rule
= index
->set_list
.head
; rule
;
3273 vty_out(vty
, " set %s %s\n", rule
->cmd
->str
,
3274 rule
->rule_str
? rule
->rule_str
: "");
3276 vty_out(vty
, " call %s\n", index
->nextrm
);
3277 if (index
->exitpolicy
== RMAP_GOTO
)
3278 vty_out(vty
, " on-match goto %d\n",
3280 if (index
->exitpolicy
== RMAP_NEXT
)
3281 vty_out(vty
, " on-match next\n");
3286 list_delete(&maplist
);
3290 static int rmap_config_write_debug(struct vty
*vty
)
3295 vty_out(vty
, "debug route-map\n");
3302 /* Route map node structure. */
3303 static struct cmd_node rmap_node
= {RMAP_NODE
, "%s(config-route-map)# ", 1};
3305 /* Common route map rules */
3307 void *route_map_rule_tag_compile(const char *arg
)
3309 unsigned long int tmp
;
3314 tmp
= strtoul(arg
, &endptr
, 0);
3315 if (arg
[0] == '\0' || *endptr
!= '\0' || errno
|| tmp
> ROUTE_TAG_MAX
)
3318 tag
= XMALLOC(MTYPE_ROUTE_MAP_COMPILED
, sizeof(*tag
));
3324 void route_map_rule_tag_free(void *rule
)
3326 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
3329 void route_map_finish(void)
3333 vector_free(route_match_vec
);
3334 route_match_vec
= NULL
;
3335 vector_free(route_set_vec
);
3336 route_set_vec
= NULL
;
3339 * All protocols are setting these to NULL
3340 * by default on shutdown( route_map_finish )
3341 * Why are we making them do this work?
3343 route_map_master
.add_hook
= NULL
;
3344 route_map_master
.delete_hook
= NULL
;
3345 route_map_master
.event_hook
= NULL
;
3347 /* cleanup route_map */
3348 while (route_map_master
.head
) {
3349 struct route_map
*map
= route_map_master
.head
;
3350 map
->to_be_processed
= false;
3351 route_map_delete(map
);
3354 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
3355 hash_free(route_map_dep_hash
[i
]);
3356 route_map_dep_hash
[i
] = NULL
;
3359 hash_free(route_map_master_hash
);
3360 route_map_master_hash
= NULL
;
3363 static void rmap_autocomplete(vector comps
, struct cmd_token
*token
)
3365 struct route_map
*map
;
3367 for (map
= route_map_master
.head
; map
; map
= map
->next
)
3368 vector_set(comps
, XSTRDUP(MTYPE_COMPLETION
, map
->name
));
3371 /* Increment the use_count counter while attaching the route map */
3372 void route_map_counter_increment(struct route_map
*map
)
3378 /* Decrement the use_count counter while detaching the route map. */
3379 void route_map_counter_decrement(struct route_map
*map
)
3382 if (map
->use_count
<= 0)
3388 static const struct cmd_variable_handler rmap_var_handlers
[] = {
3389 {/* "route-map WORD" */
3390 .varname
= "route_map",
3391 .completions
= rmap_autocomplete
},
3392 {.tokenname
= "ROUTEMAP_NAME", .completions
= rmap_autocomplete
},
3393 {.tokenname
= "RMAP_NAME", .completions
= rmap_autocomplete
},
3394 {.completions
= NULL
}};
3396 /* Initialization of route map vector. */
3397 void route_map_init(void)
3401 /* Make vector for match and set. */
3402 route_match_vec
= vector_init(1);
3403 route_set_vec
= vector_init(1);
3404 route_map_master_hash
=
3405 hash_create_size(8, route_map_hash_key_make
, route_map_hash_cmp
,
3406 "Route Map Master Hash");
3408 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++)
3409 route_map_dep_hash
[i
] = hash_create_size(
3410 8, route_map_dep_hash_make_key
, route_map_dep_hash_cmp
,
3411 "Route Map Dep Hash");
3413 cmd_variable_handler_register(rmap_var_handlers
);
3417 /* Install route map top node. */
3418 install_node(&rmap_node
, route_map_config_write
);
3420 install_node(&rmap_debug_node
, rmap_config_write_debug
);
3422 /* Install route map commands. */
3423 install_default(RMAP_NODE
);
3424 install_element(CONFIG_NODE
, &route_map_cmd
);
3425 install_element(CONFIG_NODE
, &no_route_map_cmd
);
3426 install_element(CONFIG_NODE
, &no_route_map_all_cmd
);
3428 install_element(CONFIG_NODE
, &debug_rmap_cmd
);
3429 install_element(CONFIG_NODE
, &no_debug_rmap_cmd
);
3431 /* Install the on-match stuff */
3432 install_element(RMAP_NODE
, &route_map_cmd
);
3433 install_element(RMAP_NODE
, &rmap_onmatch_next_cmd
);
3434 install_element(RMAP_NODE
, &no_rmap_onmatch_next_cmd
);
3435 install_element(RMAP_NODE
, &rmap_onmatch_goto_cmd
);
3436 install_element(RMAP_NODE
, &no_rmap_onmatch_goto_cmd
);
3437 install_element(RMAP_NODE
, &rmap_continue_cmd
);
3438 install_element(RMAP_NODE
, &no_rmap_continue_cmd
);
3440 /* Install the continue stuff (ALIAS of on-match). */
3442 /* Install the call stuff. */
3443 install_element(RMAP_NODE
, &rmap_call_cmd
);
3444 install_element(RMAP_NODE
, &no_rmap_call_cmd
);
3446 /* Install description commands. */
3447 install_element(RMAP_NODE
, &rmap_description_cmd
);
3448 install_element(RMAP_NODE
, &no_rmap_description_cmd
);
3450 /* Install show command */
3451 install_element(ENABLE_NODE
, &rmap_clear_counters_cmd
);
3453 install_element(ENABLE_NODE
, &rmap_show_name_cmd
);
3454 install_element(ENABLE_NODE
, &rmap_show_unused_cmd
);
3456 install_element(ENABLE_NODE
, &debug_rmap_cmd
);
3457 install_element(ENABLE_NODE
, &no_debug_rmap_cmd
);
3459 install_element(RMAP_NODE
, &match_interface_cmd
);
3460 install_element(RMAP_NODE
, &no_match_interface_cmd
);
3462 install_element(RMAP_NODE
, &match_ip_address_cmd
);
3463 install_element(RMAP_NODE
, &no_match_ip_address_cmd
);
3465 install_element(RMAP_NODE
, &match_ip_address_prefix_list_cmd
);
3466 install_element(RMAP_NODE
, &no_match_ip_address_prefix_list_cmd
);
3468 install_element(RMAP_NODE
, &match_ip_next_hop_cmd
);
3469 install_element(RMAP_NODE
, &no_match_ip_next_hop_cmd
);
3471 install_element(RMAP_NODE
, &match_ip_next_hop_prefix_list_cmd
);
3472 install_element(RMAP_NODE
, &no_match_ip_next_hop_prefix_list_cmd
);
3474 install_element(RMAP_NODE
, &match_ip_next_hop_type_cmd
);
3475 install_element(RMAP_NODE
, &no_match_ip_next_hop_type_cmd
);
3477 install_element(RMAP_NODE
, &match_ipv6_address_cmd
);
3478 install_element(RMAP_NODE
, &no_match_ipv6_address_cmd
);
3480 install_element(RMAP_NODE
, &match_ipv6_address_prefix_list_cmd
);
3481 install_element(RMAP_NODE
, &no_match_ipv6_address_prefix_list_cmd
);
3483 install_element(RMAP_NODE
, &match_ipv6_next_hop_type_cmd
);
3484 install_element(RMAP_NODE
, &no_match_ipv6_next_hop_type_cmd
);
3486 install_element(RMAP_NODE
, &match_metric_cmd
);
3487 install_element(RMAP_NODE
, &no_match_metric_cmd
);
3489 install_element(RMAP_NODE
, &match_tag_cmd
);
3490 install_element(RMAP_NODE
, &no_match_tag_cmd
);
3492 install_element(RMAP_NODE
, &set_ip_nexthop_cmd
);
3493 install_element(RMAP_NODE
, &no_set_ip_nexthop_cmd
);
3495 install_element(RMAP_NODE
, &set_ipv6_nexthop_local_cmd
);
3496 install_element(RMAP_NODE
, &no_set_ipv6_nexthop_local_cmd
);
3498 install_element(RMAP_NODE
, &set_metric_cmd
);
3499 install_element(RMAP_NODE
, &no_set_metric_cmd
);
3501 install_element(RMAP_NODE
, &set_tag_cmd
);
3502 install_element(RMAP_NODE
, &no_set_tag_cmd
);