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 static 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_RULE_MISSING
:
482 vty_out(vty
, "%% [%s] Can't find rule.\n", frr_protonameinst
);
483 return CMD_WARNING_CONFIG_FAILED
;
485 case RMAP_COMPILE_ERROR
:
487 "%% [%s] Argument form is unsupported or malformed.\n",
489 return CMD_WARNING_CONFIG_FAILED
;
491 case RMAP_COMPILE_SUCCESS
:
493 * Nothing to do here move along
501 int generic_match_delete(struct vty
*vty
, struct route_map_index
*index
,
502 const char *command
, const char *arg
,
503 route_map_event_t type
)
505 enum rmap_compile_rets ret
;
506 int retval
= CMD_SUCCESS
;
507 char *dep_name
= NULL
;
509 char *rmap_name
= NULL
;
511 if (type
!= RMAP_EVENT_MATCH_DELETED
) {
512 /* ignore the mundane, the types without any dependency */
514 if ((tmpstr
= route_map_get_match_arg(index
, command
))
517 XSTRDUP(MTYPE_ROUTE_MAP_RULE
, tmpstr
);
519 dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_RULE
, arg
);
521 rmap_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, index
->map
->name
);
524 ret
= route_map_delete_match(index
, command
, dep_name
, type
);
526 case RMAP_RULE_MISSING
:
527 vty_out(vty
, "%% [%s] Can't find rule.\n", frr_protonameinst
);
528 retval
= CMD_WARNING_CONFIG_FAILED
;
530 case RMAP_COMPILE_ERROR
:
532 "%% [%s] Argument form is unsupported or malformed.\n",
534 retval
= CMD_WARNING_CONFIG_FAILED
;
536 case RMAP_COMPILE_SUCCESS
:
543 XFREE(MTYPE_ROUTE_MAP_RULE
, dep_name
);
544 XFREE(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
549 int generic_set_add(struct vty
*vty
, struct route_map_index
*index
,
550 const char *command
, const char *arg
)
552 enum rmap_compile_rets ret
;
554 ret
= route_map_add_set(index
, command
, arg
);
556 case RMAP_RULE_MISSING
:
557 vty_out(vty
, "%% [%s] Can't find rule.\n", frr_protonameinst
);
558 return CMD_WARNING_CONFIG_FAILED
;
560 case RMAP_COMPILE_ERROR
:
562 "%% [%s] Argument form is unsupported or malformed.\n",
564 return CMD_WARNING_CONFIG_FAILED
;
566 case RMAP_COMPILE_SUCCESS
:
573 int generic_set_delete(struct vty
*vty
, struct route_map_index
*index
,
574 const char *command
, const char *arg
)
576 enum rmap_compile_rets ret
;
578 ret
= route_map_delete_set(index
, command
, arg
);
580 case RMAP_RULE_MISSING
:
581 vty_out(vty
, "%% [%s] Can't find rule.\n", frr_protonameinst
);
582 return CMD_WARNING_CONFIG_FAILED
;
584 case RMAP_COMPILE_ERROR
:
586 "%% [%s] Argument form is unsupported or malformed.\n",
588 return CMD_WARNING_CONFIG_FAILED
;
590 case RMAP_COMPILE_SUCCESS
:
598 /* Route map rule. This rule has both `match' rule and `set' rule. */
599 struct route_map_rule
{
601 const struct route_map_rule_cmd
*cmd
;
603 /* For pretty printing. */
606 /* Pre-compiled match rule. */
610 struct route_map_rule
*next
;
611 struct route_map_rule
*prev
;
614 /* Making route map list. */
615 struct route_map_list
{
616 struct route_map
*head
;
617 struct route_map
*tail
;
619 void (*add_hook
)(const char *);
620 void (*delete_hook
)(const char *);
621 void (*event_hook
)(const char *);
624 /* Master list of route map. */
625 static struct route_map_list route_map_master
= {NULL
, NULL
, NULL
, NULL
, NULL
};
626 static struct hash
*route_map_master_hash
= NULL
;
628 static unsigned int route_map_hash_key_make(const void *p
)
630 const struct route_map
*map
= p
;
631 return string_hash_make(map
->name
);
634 static bool route_map_hash_cmp(const void *p1
, const void *p2
)
636 const struct route_map
*map1
= p1
;
637 const struct route_map
*map2
= p2
;
639 if (map1
->deleted
== map2
->deleted
) {
640 if (map1
->name
&& map2
->name
) {
641 if (!strcmp(map1
->name
, map2
->name
)) {
644 } else if (!map1
->name
&& !map2
->name
) {
652 enum route_map_upd8_type
{
657 /* all possible route-map dependency types */
658 enum route_map_dep_type
{
659 ROUTE_MAP_DEP_RMAP
= 1,
661 ROUTE_MAP_DEP_ECLIST
,
662 ROUTE_MAP_DEP_LCLIST
,
664 ROUTE_MAP_DEP_ASPATH
,
665 ROUTE_MAP_DEP_FILTER
,
669 struct route_map_dep
{
671 struct hash
*dep_rmap_hash
;
672 struct hash
*this_hash
; /* ptr to the hash structure this is part of */
675 struct route_map_dep_data
{
679 /* Count of number of sequences of this
680 * route-map that depend on the same entity.
685 /* Hashes maintaining dependency between various sublists used by route maps */
686 static struct hash
*route_map_dep_hash
[ROUTE_MAP_DEP_MAX
];
688 static unsigned int route_map_dep_hash_make_key(const void *p
);
689 static void route_map_clear_all_references(char *rmap_name
);
690 static void route_map_rule_delete(struct route_map_rule_list
*,
691 struct route_map_rule
*);
692 static bool rmap_debug
;
694 static void route_map_index_delete(struct route_map_index
*, int);
696 /* New route map allocation. Please note route map's name must be
698 static struct route_map
*route_map_new(const char *name
)
700 struct route_map
*new;
702 new = XCALLOC(MTYPE_ROUTE_MAP
, sizeof(struct route_map
));
703 new->name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
704 QOBJ_REG(new, route_map
);
708 /* Add new name to route_map. */
709 static struct route_map
*route_map_add(const char *name
)
711 struct route_map
*map
;
712 struct route_map_list
*list
;
714 map
= route_map_new(name
);
715 list
= &route_map_master
;
717 /* Add map to the hash */
718 hash_get(route_map_master_hash
, map
, hash_alloc_intern
);
720 /* Add new entry to the head of the list to match how it is added in the
721 * hash table. This is to ensure that if the same route-map has been
722 * created more than once and then marked for deletion (which can happen
723 * if prior deletions haven't completed as BGP hasn't yet done the
724 * route-map processing), the order of the entities is the same in both
725 * the list and the hash table. Otherwise, since there is nothing to
726 * distinguish between the two entries, the wrong entry could get freed.
727 * TODO: This needs to be re-examined to handle it better - e.g., revive
728 * a deleted entry if the route-map is created again.
731 map
->next
= list
->head
;
733 list
->head
->prev
= map
;
739 if (route_map_master
.add_hook
) {
740 (*route_map_master
.add_hook
)(name
);
741 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_ADDED
);
745 zlog_debug("Add route-map %s", name
);
749 /* this is supposed to be called post processing by
750 * the delete hook function. Don't invoke delete_hook
751 * again in this routine.
753 static void route_map_free_map(struct route_map
*map
)
755 struct route_map_list
*list
;
756 struct route_map_index
*index
;
761 while ((index
= map
->head
) != NULL
)
762 route_map_index_delete(index
, 0);
765 zlog_debug("Deleting route-map %s", map
->name
);
767 list
= &route_map_master
;
772 map
->next
->prev
= map
->prev
;
774 list
->tail
= map
->prev
;
777 map
->prev
->next
= map
->next
;
779 list
->head
= map
->next
;
781 hash_release(route_map_master_hash
, map
);
782 XFREE(MTYPE_ROUTE_MAP_NAME
, map
->name
);
783 XFREE(MTYPE_ROUTE_MAP
, map
);
786 /* Route map delete from list. */
787 static void route_map_delete(struct route_map
*map
)
789 struct route_map_index
*index
;
792 while ((index
= map
->head
) != NULL
)
793 route_map_index_delete(index
, 0);
798 /* Clear all dependencies */
799 route_map_clear_all_references(name
);
801 /* Execute deletion hook. */
802 if (route_map_master
.delete_hook
) {
803 (*route_map_master
.delete_hook
)(name
);
804 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_DELETED
);
807 if (!map
->to_be_processed
) {
808 route_map_free_map(map
);
812 /* Lookup route map by route map name string. */
813 struct route_map
*route_map_lookup_by_name(const char *name
)
815 struct route_map
*map
;
816 struct route_map tmp_map
;
821 // map.deleted is 0 via memset
822 memset(&tmp_map
, 0, sizeof(struct route_map
));
823 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
824 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
825 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
829 /* Simple helper to warn if route-map does not exist. */
830 struct route_map
*route_map_lookup_warn_noexist(struct vty
*vty
, const char *name
)
832 struct route_map
*route_map
= route_map_lookup_by_name(name
);
835 if (vty_shell_serv(vty
))
836 vty_out(vty
, "The route-map '%s' does not exist.\n", name
);
841 int route_map_mark_updated(const char *name
)
843 struct route_map
*map
;
845 struct route_map tmp_map
;
850 map
= route_map_lookup_by_name(name
);
852 /* If we did not find the routemap with deleted=false try again
856 memset(&tmp_map
, 0, sizeof(struct route_map
));
857 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
858 tmp_map
.deleted
= true;
859 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
860 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
864 map
->to_be_processed
= true;
871 static int route_map_clear_updated(struct route_map
*map
)
876 map
->to_be_processed
= false;
878 route_map_free_map(map
);
884 /* Lookup route map. If there isn't route map create one and return
886 static struct route_map
*route_map_get(const char *name
)
888 struct route_map
*map
;
890 map
= route_map_lookup_by_name(name
);
892 map
= route_map_add(name
);
897 void route_map_walk_update_list(void (*route_map_update_fn
)(char *name
))
899 struct route_map
*node
;
900 struct route_map
*nnode
= NULL
;
902 for (node
= route_map_master
.head
; node
; node
= nnode
) {
903 if (node
->to_be_processed
) {
904 /* DD: Should we add any thread yield code here */
905 route_map_update_fn(node
->name
);
907 route_map_clear_updated(node
);
913 /* Return route map's type string. */
914 static const char *route_map_type_str(enum route_map_type type
)
931 static const char *route_map_cmd_result_str(enum route_map_cmd_result_t res
)
949 static const char *route_map_result_str(route_map_result_t res
)
954 case RMAP_PERMITMATCH
:
961 static int route_map_empty(struct route_map
*map
)
963 if (map
->head
== NULL
&& map
->tail
== NULL
)
970 static void vty_show_route_map_entry(struct vty
*vty
, struct route_map
*map
)
972 struct route_map_index
*index
;
973 struct route_map_rule
*rule
;
975 vty_out(vty
, "route-map: %s Invoked: %" PRIu64
"\n",
976 map
->name
, map
->applied
- map
->applied_clear
);
978 for (index
= map
->head
; index
; index
= index
->next
) {
979 vty_out(vty
, " %s, sequence %d Invoked %" PRIu64
"\n",
980 route_map_type_str(index
->type
), index
->pref
,
981 index
->applied
- index
->applied_clear
);
984 if (index
->description
)
985 vty_out(vty
, " Description:\n %s\n",
989 vty_out(vty
, " Match clauses:\n");
990 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
991 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
994 vty_out(vty
, " Set clauses:\n");
995 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
996 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
1000 vty_out(vty
, " Call clause:\n");
1002 vty_out(vty
, " Call %s\n", index
->nextrm
);
1005 vty_out(vty
, " Action:\n");
1006 if (index
->exitpolicy
== RMAP_GOTO
)
1007 vty_out(vty
, " Goto %d\n", index
->nextpref
);
1008 else if (index
->exitpolicy
== RMAP_NEXT
)
1009 vty_out(vty
, " Continue to next entry\n");
1010 else if (index
->exitpolicy
== RMAP_EXIT
)
1011 vty_out(vty
, " Exit routemap\n");
1015 static int sort_route_map(const void **map1
, const void **map2
)
1017 const struct route_map
*m1
= *map1
;
1018 const struct route_map
*m2
= *map2
;
1020 return strcmp(m1
->name
, m2
->name
);
1023 static int vty_show_route_map(struct vty
*vty
, const char *name
)
1025 struct route_map
*map
;
1027 vty_out(vty
, "%s:\n", frr_protonameinst
);
1030 map
= route_map_lookup_by_name(name
);
1033 vty_show_route_map_entry(vty
, map
);
1036 vty_out(vty
, "%s: 'route-map %s' not found\n",
1037 frr_protonameinst
, name
);
1042 struct list
*maplist
= list_new();
1043 struct listnode
*ln
;
1045 for (map
= route_map_master
.head
; map
; map
= map
->next
)
1046 listnode_add(maplist
, map
);
1048 list_sort(maplist
, sort_route_map
);
1050 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
1051 vty_show_route_map_entry(vty
, map
);
1053 list_delete(&maplist
);
1058 /* Unused route map details */
1059 static int vty_show_unused_route_map(struct vty
*vty
)
1061 struct list
*maplist
= list_new();
1062 struct listnode
*ln
;
1063 struct route_map
*map
;
1065 for (map
= route_map_master
.head
; map
; map
= map
->next
) {
1066 /* If use_count is zero, No protocol is using this routemap.
1067 * so adding to the list.
1069 if (!map
->use_count
)
1070 listnode_add(maplist
, map
);
1073 if (maplist
->count
> 0) {
1074 vty_out(vty
, "\n%s:\n", frr_protonameinst
);
1075 list_sort(maplist
, sort_route_map
);
1077 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
1078 vty_show_route_map_entry(vty
, map
);
1080 vty_out(vty
, "\n%s: None\n", frr_protonameinst
);
1083 list_delete(&maplist
);
1087 /* New route map allocation. Please note route map's name must be
1089 static struct route_map_index
*route_map_index_new(void)
1091 struct route_map_index
*new;
1093 new = XCALLOC(MTYPE_ROUTE_MAP_INDEX
, sizeof(struct route_map_index
));
1094 new->exitpolicy
= RMAP_EXIT
; /* Default to Cisco-style */
1095 QOBJ_REG(new, route_map_index
);
1099 /* Free route map index. */
1100 static void route_map_index_delete(struct route_map_index
*index
, int notify
)
1102 struct route_map_rule
*rule
;
1107 zlog_debug("Deleting route-map %s sequence %d",
1108 index
->map
->name
, index
->pref
);
1110 /* Free route match. */
1111 while ((rule
= index
->match_list
.head
) != NULL
)
1112 route_map_rule_delete(&index
->match_list
, rule
);
1114 /* Free route set. */
1115 while ((rule
= index
->set_list
.head
) != NULL
)
1116 route_map_rule_delete(&index
->set_list
, rule
);
1118 /* Remove index from route map list. */
1120 index
->next
->prev
= index
->prev
;
1122 index
->map
->tail
= index
->prev
;
1125 index
->prev
->next
= index
->next
;
1127 index
->map
->head
= index
->next
;
1129 /* Free 'char *nextrm' if not NULL */
1130 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
1132 /* Execute event hook. */
1133 if (route_map_master
.event_hook
&& notify
) {
1134 (*route_map_master
.event_hook
)(index
->map
->name
);
1135 route_map_notify_dependencies(index
->map
->name
,
1136 RMAP_EVENT_CALL_ADDED
);
1138 XFREE(MTYPE_ROUTE_MAP_INDEX
, index
);
1141 /* Lookup index from route map. */
1142 static struct route_map_index
*route_map_index_lookup(struct route_map
*map
,
1143 enum route_map_type type
,
1146 struct route_map_index
*index
;
1148 for (index
= map
->head
; index
; index
= index
->next
)
1149 if ((index
->type
== type
|| type
== RMAP_ANY
)
1150 && index
->pref
== pref
)
1155 /* Add new index to route map. */
1156 static struct route_map_index
*
1157 route_map_index_add(struct route_map
*map
, enum route_map_type type
, int pref
)
1159 struct route_map_index
*index
;
1160 struct route_map_index
*point
;
1162 /* Allocate new route map inex. */
1163 index
= route_map_index_new();
1168 /* Compare preference. */
1169 for (point
= map
->head
; point
; point
= point
->next
)
1170 if (point
->pref
>= pref
)
1173 if (map
->head
== NULL
) {
1174 map
->head
= map
->tail
= index
;
1175 } else if (point
== NULL
) {
1176 index
->prev
= map
->tail
;
1177 map
->tail
->next
= index
;
1179 } else if (point
== map
->head
) {
1180 index
->next
= map
->head
;
1181 map
->head
->prev
= index
;
1184 index
->next
= point
;
1185 index
->prev
= point
->prev
;
1187 point
->prev
->next
= index
;
1188 point
->prev
= index
;
1191 /* Execute event hook. */
1192 if (route_map_master
.event_hook
) {
1193 (*route_map_master
.event_hook
)(map
->name
);
1194 route_map_notify_dependencies(map
->name
, RMAP_EVENT_CALL_ADDED
);
1198 zlog_debug("Route-map %s add sequence %d, type: %s",
1199 map
->name
, pref
, route_map_type_str(type
));
1204 /* Get route map index. */
1205 static struct route_map_index
*
1206 route_map_index_get(struct route_map
*map
, enum route_map_type type
, int pref
)
1208 struct route_map_index
*index
;
1210 index
= route_map_index_lookup(map
, RMAP_ANY
, pref
);
1211 if (index
&& index
->type
!= type
) {
1212 /* Delete index from route map. */
1213 route_map_index_delete(index
, 1);
1217 index
= route_map_index_add(map
, type
, pref
);
1221 /* New route map rule */
1222 static struct route_map_rule
*route_map_rule_new(void)
1224 struct route_map_rule
*new;
1226 new = XCALLOC(MTYPE_ROUTE_MAP_RULE
, sizeof(struct route_map_rule
));
1230 /* Install rule command to the match list. */
1231 void route_map_install_match(const struct route_map_rule_cmd
*cmd
)
1233 vector_set(route_match_vec
, (void *)cmd
);
1236 /* Install rule command to the set list. */
1237 void route_map_install_set(const struct route_map_rule_cmd
*cmd
)
1239 vector_set(route_set_vec
, (void *)cmd
);
1242 /* Lookup rule command from match list. */
1243 static const struct route_map_rule_cmd
*route_map_lookup_match(const char *name
)
1246 const struct route_map_rule_cmd
*rule
;
1248 for (i
= 0; i
< vector_active(route_match_vec
); i
++)
1249 if ((rule
= vector_slot(route_match_vec
, i
)) != NULL
)
1250 if (strcmp(rule
->str
, name
) == 0)
1255 /* Lookup rule command from set list. */
1256 static const struct route_map_rule_cmd
*route_map_lookup_set(const char *name
)
1259 const struct route_map_rule_cmd
*rule
;
1261 for (i
= 0; i
< vector_active(route_set_vec
); i
++)
1262 if ((rule
= vector_slot(route_set_vec
, i
)) != NULL
)
1263 if (strcmp(rule
->str
, name
) == 0)
1268 /* Add match and set rule to rule list. */
1269 static void route_map_rule_add(struct route_map_rule_list
*list
,
1270 struct route_map_rule
*rule
)
1273 rule
->prev
= list
->tail
;
1275 list
->tail
->next
= rule
;
1281 /* Delete rule from rule list. */
1282 static void route_map_rule_delete(struct route_map_rule_list
*list
,
1283 struct route_map_rule
*rule
)
1285 if (rule
->cmd
->func_free
)
1286 (*rule
->cmd
->func_free
)(rule
->value
);
1288 XFREE(MTYPE_ROUTE_MAP_RULE_STR
, rule
->rule_str
);
1291 rule
->next
->prev
= rule
->prev
;
1293 list
->tail
= rule
->prev
;
1295 rule
->prev
->next
= rule
->next
;
1297 list
->head
= rule
->next
;
1299 XFREE(MTYPE_ROUTE_MAP_RULE
, rule
);
1302 /* strcmp wrapper function which don't crush even argument is NULL. */
1303 static int rulecmp(const char *dst
, const char *src
)
1314 return strcmp(dst
, src
);
1319 /* Use this to return the already specified argument for this match. This is
1320 * useful to get the specified argument with a route map match rule when the
1321 * rule is being deleted and the argument is not provided.
1323 const char *route_map_get_match_arg(struct route_map_index
*index
,
1324 const char *match_name
)
1326 struct route_map_rule
*rule
;
1327 const struct route_map_rule_cmd
*cmd
;
1329 /* First lookup rule for add match statement. */
1330 cmd
= route_map_lookup_match(match_name
);
1334 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1335 if (rule
->cmd
== cmd
&& rule
->rule_str
!= NULL
)
1336 return (rule
->rule_str
);
1341 static route_map_event_t
get_route_map_delete_event(route_map_event_t type
)
1344 case RMAP_EVENT_CALL_ADDED
:
1345 return RMAP_EVENT_CALL_DELETED
;
1346 case RMAP_EVENT_PLIST_ADDED
:
1347 return RMAP_EVENT_PLIST_DELETED
;
1348 case RMAP_EVENT_CLIST_ADDED
:
1349 return RMAP_EVENT_CLIST_DELETED
;
1350 case RMAP_EVENT_ECLIST_ADDED
:
1351 return RMAP_EVENT_ECLIST_DELETED
;
1352 case RMAP_EVENT_LLIST_ADDED
:
1353 return RMAP_EVENT_LLIST_DELETED
;
1354 case RMAP_EVENT_ASLIST_ADDED
:
1355 return RMAP_EVENT_ASLIST_DELETED
;
1356 case RMAP_EVENT_FILTER_ADDED
:
1357 return RMAP_EVENT_FILTER_DELETED
;
1358 case RMAP_EVENT_SET_ADDED
:
1359 case RMAP_EVENT_SET_DELETED
:
1360 case RMAP_EVENT_SET_REPLACED
:
1361 case RMAP_EVENT_MATCH_ADDED
:
1362 case RMAP_EVENT_MATCH_DELETED
:
1363 case RMAP_EVENT_MATCH_REPLACED
:
1364 case RMAP_EVENT_INDEX_ADDED
:
1365 case RMAP_EVENT_INDEX_DELETED
:
1366 case RMAP_EVENT_CALL_DELETED
:
1367 case RMAP_EVENT_PLIST_DELETED
:
1368 case RMAP_EVENT_CLIST_DELETED
:
1369 case RMAP_EVENT_ECLIST_DELETED
:
1370 case RMAP_EVENT_LLIST_DELETED
:
1371 case RMAP_EVENT_ASLIST_DELETED
:
1372 case RMAP_EVENT_FILTER_DELETED
:
1373 /* This function returns the appropriate 'deleted' event type
1374 * for every 'added' event type passed to this function.
1375 * This is done only for named entities used in the
1376 * route-map match commands.
1377 * This function is not to be invoked for any of the other event
1385 * Return to make c happy but if we get here something has gone
1386 * terribly terribly wrong, so yes this return makes no sense.
1388 return RMAP_EVENT_CALL_ADDED
;
1391 /* Add match statement to route map. */
1392 enum rmap_compile_rets
route_map_add_match(struct route_map_index
*index
,
1393 const char *match_name
,
1394 const char *match_arg
,
1395 route_map_event_t type
)
1397 struct route_map_rule
*rule
;
1398 struct route_map_rule
*next
;
1399 const struct route_map_rule_cmd
*cmd
;
1401 int8_t delete_rmap_event_type
= 0;
1402 const char *rule_key
;
1404 /* First lookup rule for add match statement. */
1405 cmd
= route_map_lookup_match(match_name
);
1407 return RMAP_RULE_MISSING
;
1409 /* Next call compile function for this match statement. */
1410 if (cmd
->func_compile
) {
1411 compile
= (*cmd
->func_compile
)(match_arg
);
1412 if (compile
== NULL
)
1413 return RMAP_COMPILE_ERROR
;
1416 /* use the compiled results if applicable */
1417 if (compile
&& cmd
->func_get_rmap_rule_key
)
1418 rule_key
= (*cmd
->func_get_rmap_rule_key
)
1421 rule_key
= match_arg
;
1423 /* If argument is completely same ignore it. */
1424 for (rule
= index
->match_list
.head
; rule
; rule
= next
) {
1426 if (rule
->cmd
== cmd
) {
1427 /* If the configured route-map match rule is exactly
1428 * the same as the existing configuration then,
1429 * ignore the duplicate configuration.
1431 if (strcmp(match_arg
, rule
->rule_str
) == 0) {
1433 (*cmd
->func_free
)(compile
);
1435 return RMAP_COMPILE_SUCCESS
;
1438 /* Remove the dependency of the route-map on the rule
1439 * that is being replaced.
1441 if (type
>= RMAP_EVENT_CALL_ADDED
) {
1442 delete_rmap_event_type
=
1443 get_route_map_delete_event(type
);
1444 route_map_upd8_dependency(
1445 delete_rmap_event_type
,
1450 route_map_rule_delete(&index
->match_list
, rule
);
1454 /* Add new route map match rule. */
1455 rule
= route_map_rule_new();
1457 rule
->value
= compile
;
1459 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, match_arg
);
1461 rule
->rule_str
= NULL
;
1463 /* Add new route match rule to linked list. */
1464 route_map_rule_add(&index
->match_list
, rule
);
1466 /* Execute event hook. */
1467 if (route_map_master
.event_hook
) {
1468 (*route_map_master
.event_hook
)(index
->map
->name
);
1469 route_map_notify_dependencies(index
->map
->name
,
1470 RMAP_EVENT_CALL_ADDED
);
1472 if (type
!= RMAP_EVENT_MATCH_ADDED
)
1473 route_map_upd8_dependency(type
, rule_key
, index
->map
->name
);
1475 return RMAP_COMPILE_SUCCESS
;
1478 /* Delete specified route match rule. */
1479 enum rmap_compile_rets
route_map_delete_match(struct route_map_index
*index
,
1480 const char *match_name
,
1481 const char *match_arg
,
1482 route_map_event_t type
)
1484 struct route_map_rule
*rule
;
1485 const struct route_map_rule_cmd
*cmd
;
1486 const char *rule_key
;
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 /* Execute event hook. */
1496 if (route_map_master
.event_hook
) {
1497 (*route_map_master
.event_hook
)(index
->map
->name
);
1498 route_map_notify_dependencies(
1500 RMAP_EVENT_CALL_ADDED
);
1502 if (cmd
->func_get_rmap_rule_key
)
1503 rule_key
= (*cmd
->func_get_rmap_rule_key
)
1506 rule_key
= match_arg
;
1508 if (type
!= RMAP_EVENT_MATCH_DELETED
&& rule_key
)
1509 route_map_upd8_dependency(type
, rule_key
,
1512 route_map_rule_delete(&index
->match_list
, rule
);
1513 return RMAP_COMPILE_SUCCESS
;
1515 /* Can't find matched rule. */
1516 return RMAP_RULE_MISSING
;
1519 /* Add route-map set statement to the route map. */
1520 enum rmap_compile_rets
route_map_add_set(struct route_map_index
*index
,
1521 const char *set_name
,
1522 const char *set_arg
)
1524 struct route_map_rule
*rule
;
1525 struct route_map_rule
*next
;
1526 const struct route_map_rule_cmd
*cmd
;
1529 cmd
= route_map_lookup_set(set_name
);
1531 return RMAP_RULE_MISSING
;
1533 /* Next call compile function for this match statement. */
1534 if (cmd
->func_compile
) {
1535 compile
= (*cmd
->func_compile
)(set_arg
);
1536 if (compile
== NULL
)
1537 return RMAP_COMPILE_ERROR
;
1541 /* Add by WJL. if old set command of same kind exist, delete it first
1542 to ensure only one set command of same kind exist under a
1544 for (rule
= index
->set_list
.head
; rule
; rule
= next
) {
1546 if (rule
->cmd
== cmd
)
1547 route_map_rule_delete(&index
->set_list
, rule
);
1550 /* Add new route map match rule. */
1551 rule
= route_map_rule_new();
1553 rule
->value
= compile
;
1555 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, set_arg
);
1557 rule
->rule_str
= NULL
;
1559 /* Add new route match rule to linked list. */
1560 route_map_rule_add(&index
->set_list
, rule
);
1562 /* Execute event hook. */
1563 if (route_map_master
.event_hook
) {
1564 (*route_map_master
.event_hook
)(index
->map
->name
);
1565 route_map_notify_dependencies(index
->map
->name
,
1566 RMAP_EVENT_CALL_ADDED
);
1568 return RMAP_COMPILE_SUCCESS
;
1571 /* Delete route map set rule. */
1572 enum rmap_compile_rets
route_map_delete_set(struct route_map_index
*index
,
1573 const char *set_name
,
1574 const char *set_arg
)
1576 struct route_map_rule
*rule
;
1577 const struct route_map_rule_cmd
*cmd
;
1579 cmd
= route_map_lookup_set(set_name
);
1581 return RMAP_RULE_MISSING
;
1583 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
1584 if ((rule
->cmd
== cmd
) && (rulecmp(rule
->rule_str
, set_arg
) == 0
1585 || set_arg
== NULL
)) {
1586 route_map_rule_delete(&index
->set_list
, rule
);
1587 /* Execute event hook. */
1588 if (route_map_master
.event_hook
) {
1589 (*route_map_master
.event_hook
)(index
->map
->name
);
1590 route_map_notify_dependencies(
1592 RMAP_EVENT_CALL_ADDED
);
1594 return RMAP_COMPILE_SUCCESS
;
1596 /* Can't find matched rule. */
1597 return RMAP_RULE_MISSING
;
1600 static enum route_map_cmd_result_t
1601 route_map_apply_match(struct route_map_rule_list
*match_list
,
1602 const struct prefix
*prefix
, route_map_object_t type
,
1605 enum route_map_cmd_result_t ret
= RMAP_NOMATCH
;
1606 struct route_map_rule
*match
;
1607 bool is_matched
= false;
1610 /* Check all match rule and if there is no match rule, go to the
1612 if (!match_list
->head
)
1615 for (match
= match_list
->head
; match
; match
= match
->next
) {
1617 * Try each match statement. If any match does not
1618 * return RMAP_MATCH or RMAP_NOOP, return.
1619 * Otherwise continue on to next match statement.
1620 * All match statements must MATCH for
1621 * end-result to be a match.
1622 * (Exception:If match stmts result in a mix of
1623 * MATCH/NOOP, then also end-result is a match)
1624 * If all result in NOOP, end-result is NOOP.
1626 ret
= (*match
->cmd
->func_apply
)(match
->value
, prefix
,
1630 * If the consolidated result of func_apply is:
1631 * -----------------------------------------------
1632 * | MATCH | NOMATCH | NOOP | Final Result |
1633 * ------------------------------------------------
1634 * | yes | yes | yes | NOMATCH |
1635 * | no | no | yes | NOOP |
1636 * | yes | no | yes | MATCH |
1637 * | no | yes | yes | NOMATCH |
1638 * |-----------------------------------------------
1640 * Traditionally, all rules within route-map
1641 * should match for it to MATCH.
1642 * If there are noops within the route-map rules,
1643 * it follows the above matrix.
1645 * Eg: route-map rm1 permit 10
1650 * route-map rm1 permit 20
1678 /* Apply route map's each index to the object.
1680 The matrix for a route-map looks like this:
1681 (note, this includes the description for the "NEXT"
1682 and "GOTO" frobs now
1684 | Match | No Match | No op
1685 |-----------|--------------|-------
1686 permit | action | cont | cont.
1687 | | default:deny | default:permit
1688 -------------------+-----------------------
1689 | deny | cont | cont.
1690 deny | | default:deny | default:permit
1691 |-----------|--------------|--------
1694 -Apply Set statements, accept route
1695 -If Call statement is present jump to the specified route-map, if it
1696 denies the route we finish.
1697 -If NEXT is specified, goto NEXT statement
1698 -If GOTO is specified, goto the first clause where pref > nextpref
1699 -If nothing is specified, do as Cisco and finish
1701 -Route is denied by route-map.
1705 If we get no matches after we've processed all updates, then the route
1708 Some notes on the new "CALL", "NEXT" and "GOTO"
1709 call WORD - If this clause is matched, then the set statements
1710 are executed and then we jump to route-map 'WORD'. If
1711 this route-map denies the route, we finish, in other
1713 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
1714 on-match next - If this clause is matched, then the set statements
1715 are executed and then we drop through to the next clause
1716 on-match goto n - If this clause is matched, then the set statments
1717 are executed and then we goto the nth clause, or the
1718 first clause greater than this. In order to ensure
1719 route-maps *always* exit, you cannot jump backwards.
1722 We need to make sure our route-map processing matches the above
1724 route_map_result_t
route_map_apply(struct route_map
*map
,
1725 const struct prefix
*prefix
,
1726 route_map_object_t type
, void *object
)
1728 static int recursion
= 0;
1729 enum route_map_cmd_result_t match_ret
= RMAP_NOMATCH
;
1730 route_map_result_t ret
= RMAP_PERMITMATCH
;
1731 struct route_map_index
*index
;
1732 struct route_map_rule
*set
;
1733 char buf
[PREFIX_STRLEN
];
1735 if (recursion
> RMAP_RECURSION_LIMIT
) {
1737 EC_LIB_RMAP_RECURSION_LIMIT
,
1738 "route-map recursion limit (%d) reached, discarding route",
1739 RMAP_RECURSION_LIMIT
);
1741 return RMAP_DENYMATCH
;
1744 if (map
== NULL
|| map
->head
== NULL
) {
1745 ret
= RMAP_DENYMATCH
;
1746 goto route_map_apply_end
;
1750 for (index
= map
->head
; index
; index
= index
->next
) {
1751 /* Apply this index. */
1753 match_ret
= route_map_apply_match(&index
->match_list
, prefix
,
1757 zlog_debug("Route-map: %s, sequence: %d, prefix: %s, result: %s",
1758 map
->name
, index
->pref
,
1759 prefix2str(prefix
, buf
, sizeof(buf
)),
1760 route_map_cmd_result_str(match_ret
));
1763 /* Now we apply the matrix from above */
1764 if (match_ret
== RMAP_NOOP
)
1766 * Do not change the return value. Retain the previous
1767 * return value. Previous values can be:
1768 * 1)permitmatch (if a nomatch was never
1769 * seen before in this route-map.)
1770 * 2)denymatch (if a nomatch was seen earlier in one
1771 * of the previous sequences)
1775 * 'cont' from matrix - continue to next route-map
1779 else if (match_ret
== RMAP_NOMATCH
) {
1782 * The return value is now changed to denymatch.
1783 * So from here on out, even if we see more noops,
1784 * we retain this return value and return this
1785 * eventually if there are no matches.
1787 ret
= RMAP_DENYMATCH
;
1790 * 'cont' from matrix - continue to next route-map
1794 } else if (match_ret
== RMAP_MATCH
) {
1795 if (index
->type
== RMAP_PERMIT
)
1798 /* Match succeeded, rmap is of type permit */
1799 ret
= RMAP_PERMITMATCH
;
1801 /* permit+match must execute sets */
1802 for (set
= index
->set_list
.head
; set
;
1805 * set cmds return RMAP_OKAY or
1806 * RMAP_ERROR. We do not care if
1807 * set succeeded or not. So, ignore
1810 (void) (*set
->cmd
->func_apply
)(
1811 set
->value
, prefix
, type
,
1814 /* Call another route-map if available */
1815 if (index
->nextrm
) {
1816 struct route_map
*nextrm
=
1817 route_map_lookup_by_name(
1820 if (nextrm
) /* Target route-map found,
1824 ret
= route_map_apply(
1825 nextrm
, prefix
, type
,
1830 /* If nextrm returned 'deny', finish. */
1831 if (ret
== RMAP_DENYMATCH
)
1832 goto route_map_apply_end
;
1835 switch (index
->exitpolicy
) {
1837 goto route_map_apply_end
;
1841 /* Find the next clause to jump to */
1842 struct route_map_index
*next
=
1844 int nextpref
= index
->nextpref
;
1846 while (next
&& next
->pref
< nextpref
) {
1851 /* No clauses match! */
1852 goto route_map_apply_end
;
1856 } else if (index
->type
== RMAP_DENY
)
1859 ret
= RMAP_DENYMATCH
;
1860 goto route_map_apply_end
;
1865 route_map_apply_end
:
1867 zlog_debug("Route-map: %s, prefix: %s, result: %s",
1868 (map
? map
->name
: "null"),
1869 prefix2str(prefix
, buf
, sizeof(buf
)),
1870 route_map_result_str(ret
));
1876 void route_map_add_hook(void (*func
)(const char *))
1878 route_map_master
.add_hook
= func
;
1881 void route_map_delete_hook(void (*func
)(const char *))
1883 route_map_master
.delete_hook
= func
;
1886 void route_map_event_hook(void (*func
)(const char *name
))
1888 route_map_master
.event_hook
= func
;
1891 /* Routines for route map dependency lists and dependency processing */
1892 static bool route_map_rmap_hash_cmp(const void *p1
, const void *p2
)
1894 return strcmp(((const struct route_map_dep_data
*)p1
)->rname
,
1895 ((const struct route_map_dep_data
*)p2
)->rname
)
1899 static bool route_map_dep_hash_cmp(const void *p1
, const void *p2
)
1902 return (strcmp(((const struct route_map_dep
*)p1
)->dep_name
,
1907 static void route_map_clear_reference(struct hash_bucket
*bucket
, void *arg
)
1909 struct route_map_dep
*dep
= bucket
->data
;
1910 struct route_map_dep_data
*dep_data
= NULL
, tmp_dep_data
;
1913 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
1914 tmp_dep_data
.rname
= arg
;
1915 dep_data
= hash_release(dep
->dep_rmap_hash
,
1918 XFREE(MTYPE_ROUTE_MAP_NAME
, dep_data
->rname
);
1919 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, dep_data
);
1921 if (!dep
->dep_rmap_hash
->count
) {
1922 dep
= hash_release(dep
->this_hash
,
1923 (void *)dep
->dep_name
);
1924 hash_free(dep
->dep_rmap_hash
);
1925 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
1926 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
1931 static void route_map_clear_all_references(char *rmap_name
)
1935 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
1936 hash_iterate(route_map_dep_hash
[i
], route_map_clear_reference
,
1941 static unsigned int route_map_dep_data_hash_make_key(const void *p
)
1943 const struct route_map_dep_data
*dep_data
= p
;
1945 return string_hash_make(dep_data
->rname
);
1948 static void *route_map_dep_hash_alloc(void *p
)
1950 char *dep_name
= (char *)p
;
1951 struct route_map_dep
*dep_entry
;
1953 dep_entry
= XCALLOC(MTYPE_ROUTE_MAP_DEP
, sizeof(struct route_map_dep
));
1954 dep_entry
->dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1955 dep_entry
->dep_rmap_hash
=
1956 hash_create_size(8, route_map_dep_data_hash_make_key
,
1957 route_map_rmap_hash_cmp
, "Route Map Dep Hash");
1958 dep_entry
->this_hash
= NULL
;
1963 static void *route_map_name_hash_alloc(void *p
)
1965 struct route_map_dep_data
*dep_data
= NULL
, *tmp_dep_data
= NULL
;
1967 dep_data
= XCALLOC(MTYPE_ROUTE_MAP_DEP_DATA
,
1968 sizeof(struct route_map_dep_data
));
1970 dep_data
->rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, tmp_dep_data
->rname
);
1974 static unsigned int route_map_dep_hash_make_key(const void *p
)
1976 return (string_hash_make((char *)p
));
1979 static void route_map_print_dependency(struct hash_bucket
*bucket
, void *data
)
1981 struct route_map_dep_data
*dep_data
= bucket
->data
;
1982 char *rmap_name
= dep_data
->rname
;
1983 char *dep_name
= data
;
1985 zlog_debug("%s: Dependency for %s: %s", __FUNCTION__
, dep_name
,
1989 static int route_map_dep_update(struct hash
*dephash
, const char *dep_name
,
1990 const char *rmap_name
, route_map_event_t type
)
1992 struct route_map_dep
*dep
= NULL
;
1993 char *dname
, *rname
;
1995 struct route_map_dep_data
*dep_data
= NULL
, *ret_dep_data
= NULL
;
1996 struct route_map_dep_data tmp_dep_data
;
1998 dname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1999 rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
2002 case RMAP_EVENT_PLIST_ADDED
:
2003 case RMAP_EVENT_CLIST_ADDED
:
2004 case RMAP_EVENT_ECLIST_ADDED
:
2005 case RMAP_EVENT_ASLIST_ADDED
:
2006 case RMAP_EVENT_LLIST_ADDED
:
2007 case RMAP_EVENT_CALL_ADDED
:
2008 case RMAP_EVENT_FILTER_ADDED
:
2010 zlog_debug("Adding dependency for filter %s in route-map %s",
2011 dep_name
, rmap_name
);
2012 dep
= (struct route_map_dep
*)hash_get(
2013 dephash
, dname
, route_map_dep_hash_alloc
);
2019 if (!dep
->this_hash
)
2020 dep
->this_hash
= dephash
;
2022 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
2023 tmp_dep_data
.rname
= rname
;
2024 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
2026 dep_data
= hash_get(dep
->dep_rmap_hash
, &tmp_dep_data
,
2027 route_map_name_hash_alloc
);
2031 case RMAP_EVENT_PLIST_DELETED
:
2032 case RMAP_EVENT_CLIST_DELETED
:
2033 case RMAP_EVENT_ECLIST_DELETED
:
2034 case RMAP_EVENT_ASLIST_DELETED
:
2035 case RMAP_EVENT_LLIST_DELETED
:
2036 case RMAP_EVENT_CALL_DELETED
:
2037 case RMAP_EVENT_FILTER_DELETED
:
2039 zlog_debug("Deleting dependency for filter %s in route-map %s",
2040 dep_name
, rmap_name
);
2041 dep
= (struct route_map_dep
*)hash_get(dephash
, dname
, NULL
);
2046 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
2047 tmp_dep_data
.rname
= rname
;
2048 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
2051 if (!dep_data
->refcnt
) {
2052 ret_dep_data
= hash_release(dep
->dep_rmap_hash
,
2055 XFREE(MTYPE_ROUTE_MAP_NAME
,
2056 ret_dep_data
->rname
);
2057 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, ret_dep_data
);
2061 if (!dep
->dep_rmap_hash
->count
) {
2062 dep
= hash_release(dephash
, dname
);
2063 hash_free(dep
->dep_rmap_hash
);
2064 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
2065 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
2069 case RMAP_EVENT_SET_ADDED
:
2070 case RMAP_EVENT_SET_DELETED
:
2071 case RMAP_EVENT_SET_REPLACED
:
2072 case RMAP_EVENT_MATCH_ADDED
:
2073 case RMAP_EVENT_MATCH_DELETED
:
2074 case RMAP_EVENT_MATCH_REPLACED
:
2075 case RMAP_EVENT_INDEX_ADDED
:
2076 case RMAP_EVENT_INDEX_DELETED
:
2082 hash_iterate(dep
->dep_rmap_hash
,
2083 route_map_print_dependency
, dname
);
2087 XFREE(MTYPE_ROUTE_MAP_NAME
, rname
);
2088 XFREE(MTYPE_ROUTE_MAP_NAME
, dname
);
2092 static struct hash
*route_map_get_dep_hash(route_map_event_t event
)
2094 struct hash
*upd8_hash
= NULL
;
2097 case RMAP_EVENT_PLIST_ADDED
:
2098 case RMAP_EVENT_PLIST_DELETED
:
2099 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_PLIST
];
2101 case RMAP_EVENT_CLIST_ADDED
:
2102 case RMAP_EVENT_CLIST_DELETED
:
2103 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_CLIST
];
2105 case RMAP_EVENT_ECLIST_ADDED
:
2106 case RMAP_EVENT_ECLIST_DELETED
:
2107 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ECLIST
];
2109 case RMAP_EVENT_ASLIST_ADDED
:
2110 case RMAP_EVENT_ASLIST_DELETED
:
2111 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ASPATH
];
2113 case RMAP_EVENT_LLIST_ADDED
:
2114 case RMAP_EVENT_LLIST_DELETED
:
2115 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_LCLIST
];
2117 case RMAP_EVENT_CALL_ADDED
:
2118 case RMAP_EVENT_CALL_DELETED
:
2119 case RMAP_EVENT_MATCH_ADDED
:
2120 case RMAP_EVENT_MATCH_DELETED
:
2121 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_RMAP
];
2123 case RMAP_EVENT_FILTER_ADDED
:
2124 case RMAP_EVENT_FILTER_DELETED
:
2125 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_FILTER
];
2128 * Should we actually be ignoring these?
2129 * I am not sure but at this point in time, let
2130 * us get them into this switch and we can peel
2131 * them into the appropriate place in the future
2133 case RMAP_EVENT_SET_ADDED
:
2134 case RMAP_EVENT_SET_DELETED
:
2135 case RMAP_EVENT_SET_REPLACED
:
2136 case RMAP_EVENT_MATCH_REPLACED
:
2137 case RMAP_EVENT_INDEX_ADDED
:
2138 case RMAP_EVENT_INDEX_DELETED
:
2145 static void route_map_process_dependency(struct hash_bucket
*bucket
, void *data
)
2147 struct route_map_dep_data
*dep_data
= NULL
;
2148 char *rmap_name
= NULL
;
2150 dep_data
= bucket
->data
;
2151 rmap_name
= dep_data
->rname
;
2154 zlog_debug("Notifying %s of dependency", rmap_name
);
2155 if (route_map_master
.event_hook
)
2156 (*route_map_master
.event_hook
)(rmap_name
);
2159 void route_map_upd8_dependency(route_map_event_t type
, const char *arg
,
2160 const char *rmap_name
)
2162 struct hash
*upd8_hash
= NULL
;
2164 if ((upd8_hash
= route_map_get_dep_hash(type
))) {
2165 route_map_dep_update(upd8_hash
, arg
, rmap_name
, type
);
2167 if (type
== RMAP_EVENT_CALL_ADDED
) {
2169 if (route_map_master
.add_hook
)
2170 (*route_map_master
.add_hook
)(rmap_name
);
2171 } else if (type
== RMAP_EVENT_CALL_DELETED
) {
2173 if (route_map_master
.delete_hook
)
2174 (*route_map_master
.delete_hook
)(rmap_name
);
2179 void route_map_notify_dependencies(const char *affected_name
,
2180 route_map_event_t event
)
2182 struct route_map_dep
*dep
;
2183 struct hash
*upd8_hash
;
2189 name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, affected_name
);
2191 if ((upd8_hash
= route_map_get_dep_hash(event
)) == NULL
) {
2192 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
2196 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, name
, NULL
);
2198 if (!dep
->this_hash
)
2199 dep
->this_hash
= upd8_hash
;
2202 zlog_debug("Filter %s updated", dep
->dep_name
);
2203 hash_iterate(dep
->dep_rmap_hash
, route_map_process_dependency
,
2207 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
2211 /* VTY related functions. */
2212 DEFUN (match_interface
,
2213 match_interface_cmd
,
2214 "match interface WORD",
2216 "match first hop interface of route\n"
2220 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2222 if (rmap_match_set_hook
.match_interface
)
2223 return rmap_match_set_hook
.match_interface(
2224 vty
, index
, "interface", argv
[idx_word
]->arg
,
2225 RMAP_EVENT_MATCH_ADDED
);
2229 DEFUN (no_match_interface
,
2230 no_match_interface_cmd
,
2231 "no match interface [WORD]",
2234 "Match first hop interface of route\n"
2237 char *iface
= (argc
== 4) ? argv
[3]->arg
: NULL
;
2238 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2240 if (rmap_match_set_hook
.no_match_interface
)
2241 return rmap_match_set_hook
.no_match_interface(
2242 vty
, index
, "interface", iface
,
2243 RMAP_EVENT_MATCH_DELETED
);
2248 DEFUN (match_ip_address
,
2249 match_ip_address_cmd
,
2250 "match ip address <(1-199)|(1300-2699)|WORD>",
2253 "Match address of route\n"
2254 "IP access-list number\n"
2255 "IP access-list number (expanded range)\n"
2256 "IP Access-list name\n")
2259 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2261 if (rmap_match_set_hook
.match_ip_address
)
2262 return rmap_match_set_hook
.match_ip_address(
2263 vty
, index
, "ip address", argv
[idx_acl
]->arg
,
2264 RMAP_EVENT_FILTER_ADDED
);
2269 DEFUN (no_match_ip_address
,
2270 no_match_ip_address_cmd
,
2271 "no match ip address [<(1-199)|(1300-2699)|WORD>]",
2275 "Match address of route\n"
2276 "IP access-list number\n"
2277 "IP access-list number (expanded range)\n"
2278 "IP Access-list name\n")
2281 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2283 if (rmap_match_set_hook
.no_match_ip_address
) {
2284 if (argc
<= idx_word
)
2285 return rmap_match_set_hook
.no_match_ip_address(
2286 vty
, index
, "ip address", NULL
,
2287 RMAP_EVENT_FILTER_DELETED
);
2288 return rmap_match_set_hook
.no_match_ip_address(
2289 vty
, index
, "ip address", argv
[idx_word
]->arg
,
2290 RMAP_EVENT_FILTER_DELETED
);
2296 DEFUN (match_ip_address_prefix_list
,
2297 match_ip_address_prefix_list_cmd
,
2298 "match ip address prefix-list WORD",
2301 "Match address of route\n"
2302 "Match entries of prefix-lists\n"
2303 "IP prefix-list name\n")
2306 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2308 if (rmap_match_set_hook
.match_ip_address_prefix_list
)
2309 return rmap_match_set_hook
.match_ip_address_prefix_list(
2310 vty
, index
, "ip address prefix-list",
2311 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
2316 DEFUN (no_match_ip_address_prefix_list
,
2317 no_match_ip_address_prefix_list_cmd
,
2318 "no match ip address prefix-list [WORD]",
2322 "Match address of route\n"
2323 "Match entries of prefix-lists\n"
2324 "IP prefix-list name\n")
2327 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2329 if (rmap_match_set_hook
.no_match_ip_address_prefix_list
) {
2330 if (argc
<= idx_word
)
2331 return rmap_match_set_hook
2332 .no_match_ip_address_prefix_list(
2333 vty
, index
, "ip address prefix-list",
2334 NULL
, RMAP_EVENT_PLIST_DELETED
);
2335 return rmap_match_set_hook
.no_match_ip_address_prefix_list(
2336 vty
, index
, "ip address prefix-list",
2337 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2343 DEFUN (match_ip_next_hop
,
2344 match_ip_next_hop_cmd
,
2345 "match ip next-hop <(1-199)|(1300-2699)|WORD>",
2348 "Match next-hop address of route\n"
2349 "IP access-list number\n"
2350 "IP access-list number (expanded range)\n"
2351 "IP Access-list name\n")
2354 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2356 if (rmap_match_set_hook
.match_ip_next_hop
)
2357 return rmap_match_set_hook
.match_ip_next_hop(
2358 vty
, index
, "ip next-hop", argv
[idx_acl
]->arg
,
2359 RMAP_EVENT_FILTER_ADDED
);
2364 DEFUN (no_match_ip_next_hop
,
2365 no_match_ip_next_hop_cmd
,
2366 "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
2370 "Match next-hop address of route\n"
2371 "IP access-list number\n"
2372 "IP access-list number (expanded range)\n"
2373 "IP Access-list name\n")
2376 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2378 if (rmap_match_set_hook
.no_match_ip_next_hop
) {
2379 if (argc
<= idx_word
)
2380 return rmap_match_set_hook
.no_match_ip_next_hop(
2381 vty
, index
, "ip next-hop", NULL
,
2382 RMAP_EVENT_FILTER_DELETED
);
2383 return rmap_match_set_hook
.no_match_ip_next_hop(
2384 vty
, index
, "ip next-hop", argv
[idx_word
]->arg
,
2385 RMAP_EVENT_FILTER_DELETED
);
2391 DEFUN (match_ip_next_hop_prefix_list
,
2392 match_ip_next_hop_prefix_list_cmd
,
2393 "match ip next-hop prefix-list WORD",
2396 "Match next-hop address of route\n"
2397 "Match entries of prefix-lists\n"
2398 "IP prefix-list name\n")
2401 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2403 if (rmap_match_set_hook
.match_ip_next_hop_prefix_list
)
2404 return rmap_match_set_hook
.match_ip_next_hop_prefix_list(
2405 vty
, index
, "ip next-hop prefix-list",
2406 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
2410 DEFUN (no_match_ip_next_hop_prefix_list
,
2411 no_match_ip_next_hop_prefix_list_cmd
,
2412 "no match ip next-hop prefix-list [WORD]",
2416 "Match next-hop address of route\n"
2417 "Match entries of prefix-lists\n"
2418 "IP prefix-list name\n")
2421 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2423 if (rmap_match_set_hook
.no_match_ip_next_hop
) {
2424 if (argc
<= idx_word
)
2425 return rmap_match_set_hook
.no_match_ip_next_hop(
2426 vty
, index
, "ip next-hop prefix-list", NULL
,
2427 RMAP_EVENT_PLIST_DELETED
);
2428 return rmap_match_set_hook
.no_match_ip_next_hop(
2429 vty
, index
, "ip next-hop prefix-list",
2430 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2435 DEFUN(match_ip_next_hop_type
, match_ip_next_hop_type_cmd
,
2436 "match ip next-hop type <blackhole>",
2438 "Match next-hop address of route\n"
2439 "Match entries by type\n"
2443 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2445 if (rmap_match_set_hook
.match_ip_next_hop_type
)
2446 return rmap_match_set_hook
.match_ip_next_hop_type(
2447 vty
, index
, "ip next-hop type", argv
[idx_word
]->arg
,
2448 RMAP_EVENT_MATCH_ADDED
);
2452 DEFUN(no_match_ip_next_hop_type
, no_match_ip_next_hop_type_cmd
,
2453 "no match ip next-hop type [<blackhole>]",
2454 NO_STR MATCH_STR IP_STR
2455 "Match next-hop address of route\n"
2456 "Match entries by type\n"
2460 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2462 if (rmap_match_set_hook
.no_match_ip_next_hop
) {
2463 if (argc
<= idx_word
)
2464 return rmap_match_set_hook
.no_match_ip_next_hop(
2465 vty
, index
, "ip next-hop type", NULL
,
2466 RMAP_EVENT_MATCH_DELETED
);
2467 return rmap_match_set_hook
.no_match_ip_next_hop(
2468 vty
, index
, "ip next-hop type", argv
[idx_word
]->arg
,
2469 RMAP_EVENT_MATCH_DELETED
);
2475 DEFUN (match_ipv6_address
,
2476 match_ipv6_address_cmd
,
2477 "match ipv6 address WORD",
2480 "Match IPv6 address of route\n"
2481 "IPv6 access-list name\n")
2484 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2486 if (rmap_match_set_hook
.match_ipv6_address
)
2487 return rmap_match_set_hook
.match_ipv6_address(
2488 vty
, index
, "ipv6 address", argv
[idx_word
]->arg
,
2489 RMAP_EVENT_FILTER_ADDED
);
2493 DEFUN (no_match_ipv6_address
,
2494 no_match_ipv6_address_cmd
,
2495 "no match ipv6 address WORD",
2499 "Match IPv6 address of route\n"
2500 "IPv6 access-list name\n")
2503 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2505 if (rmap_match_set_hook
.no_match_ipv6_address
)
2506 return rmap_match_set_hook
.no_match_ipv6_address(
2507 vty
, index
, "ipv6 address", argv
[idx_word
]->arg
,
2508 RMAP_EVENT_FILTER_DELETED
);
2513 DEFUN (match_ipv6_address_prefix_list
,
2514 match_ipv6_address_prefix_list_cmd
,
2515 "match ipv6 address prefix-list WORD",
2518 "Match address of route\n"
2519 "Match entries of prefix-lists\n"
2520 "IP prefix-list name\n")
2523 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2525 if (rmap_match_set_hook
.match_ipv6_address_prefix_list
)
2526 return rmap_match_set_hook
.match_ipv6_address_prefix_list(
2527 vty
, index
, "ipv6 address prefix-list",
2528 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
2532 DEFUN (no_match_ipv6_address_prefix_list
,
2533 no_match_ipv6_address_prefix_list_cmd
,
2534 "no match ipv6 address prefix-list WORD",
2538 "Match address of route\n"
2539 "Match entries of prefix-lists\n"
2540 "IP prefix-list name\n")
2543 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2545 if (rmap_match_set_hook
.no_match_ipv6_address_prefix_list
)
2546 return rmap_match_set_hook
.no_match_ipv6_address_prefix_list(
2547 vty
, index
, "ipv6 address prefix-list",
2548 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2552 DEFUN(match_ipv6_next_hop_type
, match_ipv6_next_hop_type_cmd
,
2553 "match ipv6 next-hop type <blackhole>",
2555 "Match next-hop address of route\n"
2556 "Match entries by type\n"
2560 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2562 if (rmap_match_set_hook
.match_ipv6_next_hop_type
)
2563 return rmap_match_set_hook
.match_ipv6_next_hop_type(
2564 vty
, index
, "ipv6 next-hop type", argv
[idx_word
]->arg
,
2565 RMAP_EVENT_MATCH_ADDED
);
2569 DEFUN(no_match_ipv6_next_hop_type
, no_match_ipv6_next_hop_type_cmd
,
2570 "no match ipv6 next-hop type [<blackhole>]",
2571 NO_STR MATCH_STR IPV6_STR
2572 "Match address of route\n"
2573 "Match entries by type\n"
2577 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2579 if (rmap_match_set_hook
.no_match_ipv6_next_hop_type
)
2580 return rmap_match_set_hook
.no_match_ipv6_next_hop_type(
2581 vty
, index
, "ipv6 next-hop type",
2582 (argc
<= idx_word
) ? NULL
: argv
[idx_word
]->arg
,
2583 RMAP_EVENT_MATCH_DELETED
);
2587 DEFUN (match_metric
,
2589 "match metric (0-4294967295)",
2591 "Match metric of route\n"
2595 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2597 if (rmap_match_set_hook
.match_metric
)
2598 return rmap_match_set_hook
.match_metric(vty
, index
, "metric",
2599 argv
[idx_number
]->arg
,
2600 RMAP_EVENT_MATCH_ADDED
);
2605 DEFUN (no_match_metric
,
2606 no_match_metric_cmd
,
2607 "no match metric [(0-4294967295)]",
2610 "Match metric of route\n"
2614 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2616 if (rmap_match_set_hook
.no_match_metric
) {
2617 if (argc
<= idx_number
)
2618 return rmap_match_set_hook
.no_match_metric(
2619 vty
, index
, "metric", NULL
,
2620 RMAP_EVENT_MATCH_DELETED
);
2621 return rmap_match_set_hook
.no_match_metric(
2622 vty
, index
, "metric", argv
[idx_number
]->arg
,
2623 RMAP_EVENT_MATCH_DELETED
);
2631 "match tag (1-4294967295)",
2633 "Match tag of route\n"
2637 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2639 if (rmap_match_set_hook
.match_tag
)
2640 return rmap_match_set_hook
.match_tag(vty
, index
, "tag",
2641 argv
[idx_number
]->arg
,
2642 RMAP_EVENT_MATCH_ADDED
);
2647 DEFUN (no_match_tag
,
2649 "no match tag [(1-4294967295)]",
2652 "Match tag of route\n"
2655 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2658 char *arg
= argv_find(argv
, argc
, "(1-4294967295)", &idx
)
2662 if (rmap_match_set_hook
.no_match_tag
)
2663 return rmap_match_set_hook
.no_match_tag(
2664 vty
, index
, "tag", arg
, RMAP_EVENT_MATCH_DELETED
);
2669 DEFUN (set_ip_nexthop
,
2671 "set ip next-hop A.B.C.D",
2674 "Next hop address\n"
2675 "IP address of next hop\n")
2680 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2682 ret
= str2sockunion(argv
[idx_ipv4
]->arg
, &su
);
2684 vty_out(vty
, "%% Malformed nexthop address\n");
2685 return CMD_WARNING_CONFIG_FAILED
;
2687 if (su
.sin
.sin_addr
.s_addr
== 0
2688 || IPV4_CLASS_DE(ntohl(su
.sin
.sin_addr
.s_addr
))) {
2690 "%% nexthop address cannot be 0.0.0.0, multicast or reserved\n");
2691 return CMD_WARNING_CONFIG_FAILED
;
2694 if (rmap_match_set_hook
.set_ip_nexthop
)
2695 return rmap_match_set_hook
.set_ip_nexthop(
2696 vty
, index
, "ip next-hop", argv
[idx_ipv4
]->arg
);
2701 DEFUN (no_set_ip_nexthop
,
2702 no_set_ip_nexthop_cmd
,
2703 "no set ip next-hop [A.B.C.D]",
2707 "Next hop address\n"
2708 "IP address of next hop\n")
2711 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2712 const char *arg
= NULL
;
2714 if (argv_find(argv
, argc
, "A.B.C.D", &idx
))
2715 arg
= argv
[idx
]->arg
;
2717 if (rmap_match_set_hook
.no_set_ip_nexthop
)
2718 return rmap_match_set_hook
.no_set_ip_nexthop(
2719 vty
, index
, "ip next-hop", arg
);
2725 DEFUN (set_ipv6_nexthop_local
,
2726 set_ipv6_nexthop_local_cmd
,
2727 "set ipv6 next-hop local X:X::X:X",
2730 "IPv6 next-hop address\n"
2731 "IPv6 local address\n"
2732 "IPv6 address of next hop\n")
2735 struct in6_addr addr
;
2737 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2739 ret
= inet_pton(AF_INET6
, argv
[idx_ipv6
]->arg
, &addr
);
2741 vty_out(vty
, "%% Malformed nexthop address\n");
2742 return CMD_WARNING_CONFIG_FAILED
;
2744 if (!IN6_IS_ADDR_LINKLOCAL(&addr
)) {
2745 vty_out(vty
, "%% Invalid link-local nexthop address\n");
2746 return CMD_WARNING_CONFIG_FAILED
;
2749 if (rmap_match_set_hook
.set_ipv6_nexthop_local
)
2750 return rmap_match_set_hook
.set_ipv6_nexthop_local(
2751 vty
, index
, "ipv6 next-hop local", argv
[idx_ipv6
]->arg
);
2756 DEFUN (no_set_ipv6_nexthop_local
,
2757 no_set_ipv6_nexthop_local_cmd
,
2758 "no set ipv6 next-hop local [X:X::X:X]",
2762 "IPv6 next-hop address\n"
2763 "IPv6 local address\n"
2764 "IPv6 address of next hop\n")
2767 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2769 if (rmap_match_set_hook
.no_set_ipv6_nexthop_local
) {
2770 if (argc
<= idx_ipv6
)
2771 return rmap_match_set_hook
.no_set_ipv6_nexthop_local(
2772 vty
, index
, "ipv6 next-hop local", NULL
);
2773 return rmap_match_set_hook
.no_set_ipv6_nexthop_local(
2774 vty
, index
, "ipv6 next-hop local", argv
[5]->arg
);
2781 "set metric <(0-4294967295)|rtt|+rtt|-rtt|+metric|-metric>",
2783 "Metric value for destination routing protocol\n"
2785 "Assign round trip time\n"
2786 "Add round trip time\n"
2787 "Subtract round trip time\n"
2789 "Subtract metric\n")
2792 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2794 const char *pass
= (argv
[idx_number
]->type
== RANGE_TKN
)
2795 ? argv
[idx_number
]->arg
2796 : argv
[idx_number
]->text
;
2798 if (rmap_match_set_hook
.set_metric
)
2799 return rmap_match_set_hook
.set_metric(vty
, index
, "metric",
2805 DEFUN (no_set_metric
,
2807 "no set metric [(0-4294967295)]",
2810 "Metric value for destination routing protocol\n"
2814 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2816 if (rmap_match_set_hook
.no_set_metric
) {
2817 if (argc
<= idx_number
)
2818 return rmap_match_set_hook
.no_set_metric(
2819 vty
, index
, "metric", NULL
);
2820 return rmap_match_set_hook
.no_set_metric(vty
, index
, "metric",
2821 argv
[idx_number
]->arg
);
2829 "set tag (1-4294967295)",
2831 "Tag value for routing protocol\n"
2834 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2837 if (rmap_match_set_hook
.set_tag
)
2838 return rmap_match_set_hook
.set_tag(vty
, index
, "tag",
2839 argv
[idx_number
]->arg
);
2846 "no set tag [(1-4294967295)]",
2849 "Tag value for routing protocol\n"
2852 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2855 if (rmap_match_set_hook
.no_set_tag
) {
2856 if (argc
<= idx_number
)
2857 return rmap_match_set_hook
.no_set_tag(vty
, index
, "tag",
2859 return rmap_match_set_hook
.no_set_tag(vty
, index
, "tag",
2860 argv
[idx_number
]->arg
);
2866 DEFUN_NOSH (route_map
,
2868 "route-map WORD <deny|permit> (1-65535)",
2869 "Create route-map or enter route-map command mode\n"
2871 "Route map denies set operations\n"
2872 "Route map permits set operations\n"
2873 "Sequence to insert to/delete from existing route-map entry\n")
2876 int idx_permit_deny
= 2;
2878 struct route_map
*map
;
2879 struct route_map_index
*index
;
2880 char *endptr
= NULL
;
2882 argv
[idx_permit_deny
]->arg
[0] == 'p' ? RMAP_PERMIT
: RMAP_DENY
;
2883 unsigned long pref
= strtoul(argv
[idx_number
]->arg
, &endptr
, 10);
2884 const char *mapname
= argv
[idx_word
]->arg
;
2886 /* Get route map. */
2887 map
= route_map_get(mapname
);
2888 index
= route_map_index_get(map
, permit
, pref
);
2890 VTY_PUSH_CONTEXT(RMAP_NODE
, index
);
2894 DEFUN (no_route_map_all
,
2895 no_route_map_all_cmd
,
2896 "no route-map WORD",
2898 "Create route-map or enter route-map command mode\n"
2902 const char *mapname
= argv
[idx_word
]->arg
;
2903 struct route_map
*map
;
2905 map
= route_map_lookup_by_name(mapname
);
2907 vty_out(vty
, "%% Could not find route-map %s\n", mapname
);
2908 return CMD_WARNING_CONFIG_FAILED
;
2911 route_map_delete(map
);
2916 DEFUN (no_route_map
,
2918 "no route-map WORD <deny|permit> (1-65535)",
2920 "Create route-map or enter route-map command mode\n"
2922 "Route map denies set operations\n"
2923 "Route map permits set operations\n"
2924 "Sequence to insert to/delete from existing route-map entry\n")
2927 int idx_permit_deny
= 3;
2929 struct route_map
*map
;
2930 struct route_map_index
*index
;
2931 char *endptr
= NULL
;
2932 int permit
= strmatch(argv
[idx_permit_deny
]->text
, "permit")
2935 const char *prefstr
= argv
[idx_number
]->arg
;
2936 const char *mapname
= argv
[idx_word
]->arg
;
2937 unsigned long pref
= strtoul(prefstr
, &endptr
, 10);
2939 /* Existence check. */
2940 map
= route_map_lookup_by_name(mapname
);
2942 vty_out(vty
, "%% Could not find route-map %s\n", mapname
);
2943 return CMD_WARNING_CONFIG_FAILED
;
2946 /* Lookup route map index. */
2947 index
= route_map_index_lookup(map
, permit
, pref
);
2948 if (index
== NULL
) {
2949 vty_out(vty
, "%% Could not find route-map entry %s %s\n",
2951 return CMD_WARNING_CONFIG_FAILED
;
2954 /* Delete index from route map. */
2955 route_map_index_delete(index
, 1);
2957 /* If this route rule is the last one, delete route map itself. */
2958 if (route_map_empty(map
))
2959 route_map_delete(map
);
2964 DEFUN (rmap_onmatch_next
,
2965 rmap_onmatch_next_cmd
,
2967 "Exit policy on matches\n"
2970 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2973 if (index
->type
== RMAP_DENY
) {
2974 /* Under a deny clause, match means it's finished. No
2975 * need to set next */
2977 "on-match next not supported under route-map deny\n");
2978 return CMD_WARNING_CONFIG_FAILED
;
2980 index
->exitpolicy
= RMAP_NEXT
;
2985 DEFUN (no_rmap_onmatch_next
,
2986 no_rmap_onmatch_next_cmd
,
2989 "Exit policy on matches\n"
2992 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2995 index
->exitpolicy
= RMAP_EXIT
;
3000 DEFUN (rmap_onmatch_goto
,
3001 rmap_onmatch_goto_cmd
,
3002 "on-match goto (1-65535)",
3003 "Exit policy on matches\n"
3004 "Goto Clause number\n"
3008 char *num
= argv_find(argv
, argc
, "(1-65535)", &idx
) ? argv
[idx
]->arg
3011 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
3015 if (index
->type
== RMAP_DENY
) {
3016 /* Under a deny clause, match means it's finished. No
3017 * need to go anywhere */
3019 "on-match goto not supported under route-map deny\n");
3020 return CMD_WARNING_CONFIG_FAILED
;
3024 d
= strtoul(num
, NULL
, 10);
3026 d
= index
->pref
+ 1;
3028 if (d
<= index
->pref
) {
3029 /* Can't allow you to do that, Dave */
3030 vty_out(vty
, "can't jump backwards in route-maps\n");
3031 return CMD_WARNING_CONFIG_FAILED
;
3033 index
->exitpolicy
= RMAP_GOTO
;
3034 index
->nextpref
= d
;
3040 DEFUN (no_rmap_onmatch_goto
,
3041 no_rmap_onmatch_goto_cmd
,
3044 "Exit policy on matches\n"
3045 "Goto Clause number\n")
3047 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
3050 index
->exitpolicy
= RMAP_EXIT
;
3055 /* Cisco/GNU Zebra compatibility aliases */
3057 DEFUN (rmap_continue
,
3059 "continue (1-65535)",
3060 "Continue on a different entry within the route-map\n"
3061 "Route-map entry sequence number\n")
3063 return rmap_onmatch_goto(self
, vty
, argc
, argv
);
3067 DEFUN (no_rmap_continue
,
3068 no_rmap_continue_cmd
,
3069 "no continue [(1-65535)]",
3071 "Continue on a different entry within the route-map\n"
3072 "Route-map entry sequence number\n")
3074 return no_rmap_onmatch_goto(self
, vty
, argc
, argv
);
3077 static void clear_route_map_helper(struct route_map
*map
)
3079 struct route_map_index
*index
;
3081 map
->applied_clear
= map
->applied
;
3082 for (index
= map
->head
; index
; index
= index
->next
)
3083 index
->applied_clear
= index
->applied
;
3086 DEFUN (rmap_clear_counters
,
3087 rmap_clear_counters_cmd
,
3088 "clear route-map counters [WORD]",
3090 "route-map information\n"
3091 "counters associated with the specified route-map\n"
3095 struct route_map
*map
;
3097 const char *name
= (argc
== 3 ) ? argv
[idx_word
]->arg
: NULL
;
3100 map
= route_map_lookup_by_name(name
);
3103 clear_route_map_helper(map
);
3105 vty_out(vty
, "%s: 'route-map %s' not found\n",
3106 frr_protonameinst
, name
);
3110 for (map
= route_map_master
.head
; map
; map
= map
->next
)
3111 clear_route_map_helper(map
);
3118 DEFUN (rmap_show_name
,
3120 "show route-map [WORD]",
3122 "route-map information\n"
3126 const char *name
= (argc
== 3) ? argv
[idx_word
]->arg
: NULL
;
3127 return vty_show_route_map(vty
, name
);
3130 DEFUN (rmap_show_unused
,
3131 rmap_show_unused_cmd
,
3132 "show route-map-unused",
3134 "unused route-map information\n")
3136 return vty_show_unused_route_map(vty
);
3142 "Jump to another Route-Map after match+set\n"
3143 "Target route-map name\n")
3146 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
3147 const char *rmap
= argv
[idx_word
]->arg
;
3151 /* If "call" is invoked with the same route-map name as
3152 * the one previously configured then, ignore the duplicate
3155 if (index
->nextrm
&& (strcmp(index
->nextrm
, rmap
) == 0))
3158 if (index
->nextrm
) {
3159 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED
,
3160 index
->nextrm
, index
->map
->name
);
3161 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
3163 index
->nextrm
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap
);
3165 /* Execute event hook. */
3166 route_map_upd8_dependency(RMAP_EVENT_CALL_ADDED
, index
->nextrm
,
3171 DEFUN (no_rmap_call
,
3175 "Jump to another Route-Map after match+set\n")
3177 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
3179 if (index
->nextrm
) {
3180 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED
,
3181 index
->nextrm
, index
->map
->name
);
3182 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
3183 index
->nextrm
= NULL
;
3189 DEFUN (rmap_description
,
3190 rmap_description_cmd
,
3191 "description LINE...",
3192 "Route-map comment\n"
3193 "Comment describing this route-map rule\n")
3196 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
3199 if (index
->description
)
3200 XFREE(MTYPE_TMP
, index
->description
);
3201 index
->description
= argv_concat(argv
, argc
, idx_line
);
3206 DEFUN (no_rmap_description
,
3207 no_rmap_description_cmd
,
3210 "Route-map comment\n")
3212 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
3215 if (index
->description
)
3216 XFREE(MTYPE_TMP
, index
->description
);
3217 index
->description
= NULL
;
3226 "Debug option set for route-maps\n")
3232 DEFUN (no_debug_rmap
,
3234 "no debug route-map",
3237 "Debug option set for route-maps\n")
3244 static struct cmd_node rmap_debug_node
= {RMAP_DEBUG_NODE
, "", 1};
3246 /* Configuration write function. */
3247 static int route_map_config_write(struct vty
*vty
)
3249 struct route_map
*map
;
3250 struct route_map_index
*index
;
3251 struct route_map_rule
*rule
;
3254 struct listnode
*ln
;
3255 struct list
*maplist
= list_new();
3257 for (map
= route_map_master
.head
; map
; map
= map
->next
)
3258 listnode_add(maplist
, map
);
3260 list_sort(maplist
, sort_route_map
);
3262 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
3263 for (index
= map
->head
; index
; index
= index
->next
) {
3265 vty_out(vty
, "!\n");
3269 vty_out(vty
, "route-map %s %s %d\n", map
->name
,
3270 route_map_type_str(index
->type
), index
->pref
);
3272 if (index
->description
)
3273 vty_out(vty
, " description %s\n",
3274 index
->description
);
3276 for (rule
= index
->match_list
.head
; rule
;
3278 vty_out(vty
, " match %s %s\n", rule
->cmd
->str
,
3279 rule
->rule_str
? rule
->rule_str
: "");
3281 for (rule
= index
->set_list
.head
; rule
;
3283 vty_out(vty
, " set %s %s\n", rule
->cmd
->str
,
3284 rule
->rule_str
? rule
->rule_str
: "");
3286 vty_out(vty
, " call %s\n", index
->nextrm
);
3287 if (index
->exitpolicy
== RMAP_GOTO
)
3288 vty_out(vty
, " on-match goto %d\n",
3290 if (index
->exitpolicy
== RMAP_NEXT
)
3291 vty_out(vty
, " on-match next\n");
3296 list_delete(&maplist
);
3300 static int rmap_config_write_debug(struct vty
*vty
)
3305 vty_out(vty
, "debug route-map\n");
3312 /* Route map node structure. */
3313 static struct cmd_node rmap_node
= {RMAP_NODE
, "%s(config-route-map)# ", 1};
3315 /* Common route map rules */
3317 void *route_map_rule_tag_compile(const char *arg
)
3319 unsigned long int tmp
;
3324 tmp
= strtoul(arg
, &endptr
, 0);
3325 if (arg
[0] == '\0' || *endptr
!= '\0' || errno
|| tmp
> ROUTE_TAG_MAX
)
3328 tag
= XMALLOC(MTYPE_ROUTE_MAP_COMPILED
, sizeof(*tag
));
3334 void route_map_rule_tag_free(void *rule
)
3336 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
3339 void route_map_finish(void)
3343 vector_free(route_match_vec
);
3344 route_match_vec
= NULL
;
3345 vector_free(route_set_vec
);
3346 route_set_vec
= NULL
;
3349 * All protocols are setting these to NULL
3350 * by default on shutdown( route_map_finish )
3351 * Why are we making them do this work?
3353 route_map_master
.add_hook
= NULL
;
3354 route_map_master
.delete_hook
= NULL
;
3355 route_map_master
.event_hook
= NULL
;
3357 /* cleanup route_map */
3358 while (route_map_master
.head
) {
3359 struct route_map
*map
= route_map_master
.head
;
3360 map
->to_be_processed
= false;
3361 route_map_delete(map
);
3364 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
3365 hash_free(route_map_dep_hash
[i
]);
3366 route_map_dep_hash
[i
] = NULL
;
3369 hash_free(route_map_master_hash
);
3370 route_map_master_hash
= NULL
;
3373 static void rmap_autocomplete(vector comps
, struct cmd_token
*token
)
3375 struct route_map
*map
;
3377 for (map
= route_map_master
.head
; map
; map
= map
->next
)
3378 vector_set(comps
, XSTRDUP(MTYPE_COMPLETION
, map
->name
));
3381 /* Increment the use_count counter while attaching the route map */
3382 void route_map_counter_increment(struct route_map
*map
)
3388 /* Decrement the use_count counter while detaching the route map. */
3389 void route_map_counter_decrement(struct route_map
*map
)
3392 if (map
->use_count
<= 0)
3398 static const struct cmd_variable_handler rmap_var_handlers
[] = {
3399 {/* "route-map WORD" */
3400 .varname
= "route_map",
3401 .completions
= rmap_autocomplete
},
3402 {.tokenname
= "ROUTEMAP_NAME", .completions
= rmap_autocomplete
},
3403 {.tokenname
= "RMAP_NAME", .completions
= rmap_autocomplete
},
3404 {.completions
= NULL
}};
3406 /* Initialization of route map vector. */
3407 void route_map_init(void)
3411 /* Make vector for match and set. */
3412 route_match_vec
= vector_init(1);
3413 route_set_vec
= vector_init(1);
3414 route_map_master_hash
=
3415 hash_create_size(8, route_map_hash_key_make
, route_map_hash_cmp
,
3416 "Route Map Master Hash");
3418 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++)
3419 route_map_dep_hash
[i
] = hash_create_size(
3420 8, route_map_dep_hash_make_key
, route_map_dep_hash_cmp
,
3421 "Route Map Dep Hash");
3423 cmd_variable_handler_register(rmap_var_handlers
);
3427 /* Install route map top node. */
3428 install_node(&rmap_node
, route_map_config_write
);
3430 install_node(&rmap_debug_node
, rmap_config_write_debug
);
3432 /* Install route map commands. */
3433 install_default(RMAP_NODE
);
3434 install_element(CONFIG_NODE
, &route_map_cmd
);
3435 install_element(CONFIG_NODE
, &no_route_map_cmd
);
3436 install_element(CONFIG_NODE
, &no_route_map_all_cmd
);
3438 install_element(CONFIG_NODE
, &debug_rmap_cmd
);
3439 install_element(CONFIG_NODE
, &no_debug_rmap_cmd
);
3441 /* Install the on-match stuff */
3442 install_element(RMAP_NODE
, &route_map_cmd
);
3443 install_element(RMAP_NODE
, &rmap_onmatch_next_cmd
);
3444 install_element(RMAP_NODE
, &no_rmap_onmatch_next_cmd
);
3445 install_element(RMAP_NODE
, &rmap_onmatch_goto_cmd
);
3446 install_element(RMAP_NODE
, &no_rmap_onmatch_goto_cmd
);
3447 install_element(RMAP_NODE
, &rmap_continue_cmd
);
3448 install_element(RMAP_NODE
, &no_rmap_continue_cmd
);
3450 /* Install the continue stuff (ALIAS of on-match). */
3452 /* Install the call stuff. */
3453 install_element(RMAP_NODE
, &rmap_call_cmd
);
3454 install_element(RMAP_NODE
, &no_rmap_call_cmd
);
3456 /* Install description commands. */
3457 install_element(RMAP_NODE
, &rmap_description_cmd
);
3458 install_element(RMAP_NODE
, &no_rmap_description_cmd
);
3460 /* Install show command */
3461 install_element(ENABLE_NODE
, &rmap_clear_counters_cmd
);
3463 install_element(ENABLE_NODE
, &rmap_show_name_cmd
);
3464 install_element(ENABLE_NODE
, &rmap_show_unused_cmd
);
3466 install_element(ENABLE_NODE
, &debug_rmap_cmd
);
3467 install_element(ENABLE_NODE
, &no_debug_rmap_cmd
);
3469 install_element(RMAP_NODE
, &match_interface_cmd
);
3470 install_element(RMAP_NODE
, &no_match_interface_cmd
);
3472 install_element(RMAP_NODE
, &match_ip_address_cmd
);
3473 install_element(RMAP_NODE
, &no_match_ip_address_cmd
);
3475 install_element(RMAP_NODE
, &match_ip_address_prefix_list_cmd
);
3476 install_element(RMAP_NODE
, &no_match_ip_address_prefix_list_cmd
);
3478 install_element(RMAP_NODE
, &match_ip_next_hop_cmd
);
3479 install_element(RMAP_NODE
, &no_match_ip_next_hop_cmd
);
3481 install_element(RMAP_NODE
, &match_ip_next_hop_prefix_list_cmd
);
3482 install_element(RMAP_NODE
, &no_match_ip_next_hop_prefix_list_cmd
);
3484 install_element(RMAP_NODE
, &match_ip_next_hop_type_cmd
);
3485 install_element(RMAP_NODE
, &no_match_ip_next_hop_type_cmd
);
3487 install_element(RMAP_NODE
, &match_ipv6_address_cmd
);
3488 install_element(RMAP_NODE
, &no_match_ipv6_address_cmd
);
3490 install_element(RMAP_NODE
, &match_ipv6_address_prefix_list_cmd
);
3491 install_element(RMAP_NODE
, &no_match_ipv6_address_prefix_list_cmd
);
3493 install_element(RMAP_NODE
, &match_ipv6_next_hop_type_cmd
);
3494 install_element(RMAP_NODE
, &no_match_ipv6_next_hop_type_cmd
);
3496 install_element(RMAP_NODE
, &match_metric_cmd
);
3497 install_element(RMAP_NODE
, &no_match_metric_cmd
);
3499 install_element(RMAP_NODE
, &match_tag_cmd
);
3500 install_element(RMAP_NODE
, &no_match_tag_cmd
);
3502 install_element(RMAP_NODE
, &set_ip_nexthop_cmd
);
3503 install_element(RMAP_NODE
, &no_set_ip_nexthop_cmd
);
3505 install_element(RMAP_NODE
, &set_ipv6_nexthop_local_cmd
);
3506 install_element(RMAP_NODE
, &no_set_ipv6_nexthop_local_cmd
);
3508 install_element(RMAP_NODE
, &set_metric_cmd
);
3509 install_element(RMAP_NODE
, &no_set_metric_cmd
);
3511 install_element(RMAP_NODE
, &set_tag_cmd
);
3512 install_element(RMAP_NODE
, &no_set_tag_cmd
);