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
)
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
;
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
)
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
);
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
:
537 if (type
!= RMAP_EVENT_MATCH_DELETED
&& dep_name
)
538 route_map_upd8_dependency(type
, dep_name
, rmap_name
);
542 XFREE(MTYPE_ROUTE_MAP_RULE
, dep_name
);
543 XFREE(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
548 int generic_set_add(struct vty
*vty
, struct route_map_index
*index
,
549 const char *command
, const char *arg
)
553 ret
= route_map_add_set(index
, command
, arg
);
555 case RMAP_RULE_MISSING
:
556 vty_out(vty
, "%% [%s] Can't find rule.\n", frr_protonameinst
);
557 return CMD_WARNING_CONFIG_FAILED
;
559 case RMAP_COMPILE_ERROR
:
561 "%% [%s] Argument form is unsupported or malformed.\n",
563 return CMD_WARNING_CONFIG_FAILED
;
565 case RMAP_COMPILE_SUCCESS
:
572 int generic_set_delete(struct vty
*vty
, struct route_map_index
*index
,
573 const char *command
, const char *arg
)
577 ret
= route_map_delete_set(index
, command
, arg
);
579 case RMAP_RULE_MISSING
:
580 vty_out(vty
, "%% [%s] Can't find rule.\n", frr_protonameinst
);
581 return CMD_WARNING_CONFIG_FAILED
;
583 case RMAP_COMPILE_ERROR
:
585 "%% [%s] Argument form is unsupported or malformed.\n",
587 return CMD_WARNING_CONFIG_FAILED
;
589 case RMAP_COMPILE_SUCCESS
:
597 /* Route map rule. This rule has both `match' rule and `set' rule. */
598 struct route_map_rule
{
600 struct route_map_rule_cmd
*cmd
;
602 /* For pretty printing. */
605 /* Pre-compiled match rule. */
609 struct route_map_rule
*next
;
610 struct route_map_rule
*prev
;
613 /* Making route map list. */
614 struct route_map_list
{
615 struct route_map
*head
;
616 struct route_map
*tail
;
618 void (*add_hook
)(const char *);
619 void (*delete_hook
)(const char *);
620 void (*event_hook
)(const char *);
623 /* Master list of route map. */
624 static struct route_map_list route_map_master
= {NULL
, NULL
, NULL
, NULL
, NULL
};
625 struct hash
*route_map_master_hash
= NULL
;
627 static unsigned int route_map_hash_key_make(const void *p
)
629 const struct route_map
*map
= p
;
630 return string_hash_make(map
->name
);
633 static bool route_map_hash_cmp(const void *p1
, const void *p2
)
635 const struct route_map
*map1
= p1
;
636 const struct route_map
*map2
= p2
;
638 if (map1
->deleted
== map2
->deleted
) {
639 if (map1
->name
&& map2
->name
) {
640 if (!strcmp(map1
->name
, map2
->name
)) {
643 } else if (!map1
->name
&& !map2
->name
) {
651 enum route_map_upd8_type
{
656 /* all possible route-map dependency types */
657 enum route_map_dep_type
{
658 ROUTE_MAP_DEP_RMAP
= 1,
660 ROUTE_MAP_DEP_ECLIST
,
661 ROUTE_MAP_DEP_LCLIST
,
663 ROUTE_MAP_DEP_ASPATH
,
664 ROUTE_MAP_DEP_FILTER
,
668 struct route_map_dep
{
670 struct hash
*dep_rmap_hash
;
671 struct hash
*this_hash
; /* ptr to the hash structure this is part of */
674 struct route_map_dep_data
{
678 /* Count of number of sequences of this
679 * route-map that depend on the same entity.
684 /* Hashes maintaining dependency between various sublists used by route maps */
685 struct hash
*route_map_dep_hash
[ROUTE_MAP_DEP_MAX
];
687 static unsigned int route_map_dep_hash_make_key(const void *p
);
688 static void route_map_clear_all_references(char *rmap_name
);
689 static void route_map_rule_delete(struct route_map_rule_list
*,
690 struct route_map_rule
*);
691 static bool rmap_debug
;
693 static void route_map_index_delete(struct route_map_index
*, int);
695 /* New route map allocation. Please note route map's name must be
697 static struct route_map
*route_map_new(const char *name
)
699 struct route_map
*new;
701 new = XCALLOC(MTYPE_ROUTE_MAP
, sizeof(struct route_map
));
702 new->name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
703 QOBJ_REG(new, route_map
);
707 /* Add new name to route_map. */
708 static struct route_map
*route_map_add(const char *name
)
710 struct route_map
*map
;
711 struct route_map_list
*list
;
713 map
= route_map_new(name
);
714 list
= &route_map_master
;
716 /* Add map to the hash */
717 hash_get(route_map_master_hash
, map
, hash_alloc_intern
);
719 /* Add new entry to the head of the list to match how it is added in the
720 * hash table. This is to ensure that if the same route-map has been
721 * created more than once and then marked for deletion (which can happen
722 * if prior deletions haven't completed as BGP hasn't yet done the
723 * route-map processing), the order of the entities is the same in both
724 * the list and the hash table. Otherwise, since there is nothing to
725 * distinguish between the two entries, the wrong entry could get freed.
726 * TODO: This needs to be re-examined to handle it better - e.g., revive
727 * a deleted entry if the route-map is created again.
730 map
->next
= list
->head
;
732 list
->head
->prev
= map
;
738 if (route_map_master
.add_hook
) {
739 (*route_map_master
.add_hook
)(name
);
740 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_ADDED
);
744 zlog_debug("Add route-map %s", name
);
748 /* this is supposed to be called post processing by
749 * the delete hook function. Don't invoke delete_hook
750 * again in this routine.
752 static void route_map_free_map(struct route_map
*map
)
754 struct route_map_list
*list
;
755 struct route_map_index
*index
;
760 while ((index
= map
->head
) != NULL
)
761 route_map_index_delete(index
, 0);
764 zlog_debug("Deleting route-map %s", map
->name
);
766 list
= &route_map_master
;
771 map
->next
->prev
= map
->prev
;
773 list
->tail
= map
->prev
;
776 map
->prev
->next
= map
->next
;
778 list
->head
= map
->next
;
780 hash_release(route_map_master_hash
, map
);
781 XFREE(MTYPE_ROUTE_MAP_NAME
, map
->name
);
782 XFREE(MTYPE_ROUTE_MAP
, map
);
785 /* Route map delete from list. */
786 static void route_map_delete(struct route_map
*map
)
788 struct route_map_index
*index
;
791 while ((index
= map
->head
) != NULL
)
792 route_map_index_delete(index
, 0);
797 /* Clear all dependencies */
798 route_map_clear_all_references(name
);
800 /* Execute deletion hook. */
801 if (route_map_master
.delete_hook
) {
802 (*route_map_master
.delete_hook
)(name
);
803 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_DELETED
);
806 if (!map
->to_be_processed
) {
807 route_map_free_map(map
);
811 /* Lookup route map by route map name string. */
812 struct route_map
*route_map_lookup_by_name(const char *name
)
814 struct route_map
*map
;
815 struct route_map tmp_map
;
820 // map.deleted is 0 via memset
821 memset(&tmp_map
, 0, sizeof(struct route_map
));
822 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
823 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
824 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
828 /* Simple helper to warn if route-map does not exist. */
829 struct route_map
*route_map_lookup_warn_noexist(struct vty
*vty
, const char *name
)
831 struct route_map
*route_map
= route_map_lookup_by_name(name
);
834 if (vty_shell_serv(vty
))
835 vty_out(vty
, "The route-map '%s' does not exist.\n", name
);
840 int route_map_mark_updated(const char *name
)
842 struct route_map
*map
;
844 struct route_map tmp_map
;
849 map
= route_map_lookup_by_name(name
);
851 /* If we did not find the routemap with deleted=false try again
855 memset(&tmp_map
, 0, sizeof(struct route_map
));
856 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
857 tmp_map
.deleted
= true;
858 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
859 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
863 map
->to_be_processed
= true;
870 static int route_map_clear_updated(struct route_map
*map
)
875 map
->to_be_processed
= false;
877 route_map_free_map(map
);
883 /* Lookup route map. If there isn't route map create one and return
885 static struct route_map
*route_map_get(const char *name
)
887 struct route_map
*map
;
889 map
= route_map_lookup_by_name(name
);
891 map
= route_map_add(name
);
896 void route_map_walk_update_list(void (*route_map_update_fn
)(char *name
))
898 struct route_map
*node
;
899 struct route_map
*nnode
= NULL
;
901 for (node
= route_map_master
.head
; node
; node
= nnode
) {
902 if (node
->to_be_processed
) {
903 /* DD: Should we add any thread yield code here */
904 route_map_update_fn(node
->name
);
906 route_map_clear_updated(node
);
912 /* Return route map's type string. */
913 static const char *route_map_type_str(enum route_map_type type
)
930 static const char *route_map_cmd_result_str(enum route_map_cmd_result_t res
)
948 static const char *route_map_result_str(route_map_result_t res
)
953 case RMAP_PERMITMATCH
:
960 static int route_map_empty(struct route_map
*map
)
962 if (map
->head
== NULL
&& map
->tail
== NULL
)
969 static void vty_show_route_map_entry(struct vty
*vty
, struct route_map
*map
)
971 struct route_map_index
*index
;
972 struct route_map_rule
*rule
;
974 vty_out(vty
, "route-map: %s Invoked: %" PRIu64
"\n",
975 map
->name
, map
->applied
- map
->applied_clear
);
977 for (index
= map
->head
; index
; index
= index
->next
) {
978 vty_out(vty
, " %s, sequence %d Invoked %" PRIu64
"\n",
979 route_map_type_str(index
->type
), index
->pref
,
980 index
->applied
- index
->applied_clear
);
983 if (index
->description
)
984 vty_out(vty
, " Description:\n %s\n",
988 vty_out(vty
, " Match clauses:\n");
989 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
990 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
993 vty_out(vty
, " Set clauses:\n");
994 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
995 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
999 vty_out(vty
, " Call clause:\n");
1001 vty_out(vty
, " Call %s\n", index
->nextrm
);
1004 vty_out(vty
, " Action:\n");
1005 if (index
->exitpolicy
== RMAP_GOTO
)
1006 vty_out(vty
, " Goto %d\n", index
->nextpref
);
1007 else if (index
->exitpolicy
== RMAP_NEXT
)
1008 vty_out(vty
, " Continue to next entry\n");
1009 else if (index
->exitpolicy
== RMAP_EXIT
)
1010 vty_out(vty
, " Exit routemap\n");
1014 static int sort_route_map(const void **map1
, const void **map2
)
1016 const struct route_map
*m1
= *map1
;
1017 const struct route_map
*m2
= *map2
;
1019 return strcmp(m1
->name
, m2
->name
);
1022 static int vty_show_route_map(struct vty
*vty
, const char *name
)
1024 struct route_map
*map
;
1026 vty_out(vty
, "%s:\n", frr_protonameinst
);
1029 map
= route_map_lookup_by_name(name
);
1032 vty_show_route_map_entry(vty
, map
);
1035 vty_out(vty
, "%s: 'route-map %s' not found\n",
1036 frr_protonameinst
, name
);
1041 struct list
*maplist
= list_new();
1042 struct listnode
*ln
;
1044 for (map
= route_map_master
.head
; map
; map
= map
->next
)
1045 listnode_add(maplist
, map
);
1047 list_sort(maplist
, sort_route_map
);
1049 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
1050 vty_show_route_map_entry(vty
, map
);
1052 list_delete(&maplist
);
1057 /* Unused route map details */
1058 static int vty_show_unused_route_map(struct vty
*vty
)
1060 struct list
*maplist
= list_new();
1061 struct listnode
*ln
;
1062 struct route_map
*map
;
1064 for (map
= route_map_master
.head
; map
; map
= map
->next
) {
1065 /* If use_count is zero, No protocol is using this routemap.
1066 * so adding to the list.
1068 if (!map
->use_count
)
1069 listnode_add(maplist
, map
);
1072 if (maplist
->count
> 0) {
1073 vty_out(vty
, "\n%s:\n", frr_protonameinst
);
1074 list_sort(maplist
, sort_route_map
);
1076 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
1077 vty_show_route_map_entry(vty
, map
);
1079 vty_out(vty
, "\n%s: None\n", frr_protonameinst
);
1082 list_delete(&maplist
);
1086 /* New route map allocation. Please note route map's name must be
1088 static struct route_map_index
*route_map_index_new(void)
1090 struct route_map_index
*new;
1092 new = XCALLOC(MTYPE_ROUTE_MAP_INDEX
, sizeof(struct route_map_index
));
1093 new->exitpolicy
= RMAP_EXIT
; /* Default to Cisco-style */
1094 QOBJ_REG(new, route_map_index
);
1098 /* Free route map index. */
1099 static void route_map_index_delete(struct route_map_index
*index
, int notify
)
1101 struct route_map_rule
*rule
;
1106 zlog_debug("Deleting route-map %s sequence %d",
1107 index
->map
->name
, index
->pref
);
1109 /* Free route match. */
1110 while ((rule
= index
->match_list
.head
) != NULL
)
1111 route_map_rule_delete(&index
->match_list
, rule
);
1113 /* Free route set. */
1114 while ((rule
= index
->set_list
.head
) != NULL
)
1115 route_map_rule_delete(&index
->set_list
, rule
);
1117 /* Remove index from route map list. */
1119 index
->next
->prev
= index
->prev
;
1121 index
->map
->tail
= index
->prev
;
1124 index
->prev
->next
= index
->next
;
1126 index
->map
->head
= index
->next
;
1128 /* Free 'char *nextrm' if not NULL */
1129 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
1131 /* Execute event hook. */
1132 if (route_map_master
.event_hook
&& notify
) {
1133 (*route_map_master
.event_hook
)(index
->map
->name
);
1134 route_map_notify_dependencies(index
->map
->name
,
1135 RMAP_EVENT_CALL_ADDED
);
1137 XFREE(MTYPE_ROUTE_MAP_INDEX
, index
);
1140 /* Lookup index from route map. */
1141 static struct route_map_index
*route_map_index_lookup(struct route_map
*map
,
1142 enum route_map_type type
,
1145 struct route_map_index
*index
;
1147 for (index
= map
->head
; index
; index
= index
->next
)
1148 if ((index
->type
== type
|| type
== RMAP_ANY
)
1149 && index
->pref
== pref
)
1154 /* Add new index to route map. */
1155 static struct route_map_index
*
1156 route_map_index_add(struct route_map
*map
, enum route_map_type type
, int pref
)
1158 struct route_map_index
*index
;
1159 struct route_map_index
*point
;
1161 /* Allocate new route map inex. */
1162 index
= route_map_index_new();
1167 /* Compare preference. */
1168 for (point
= map
->head
; point
; point
= point
->next
)
1169 if (point
->pref
>= pref
)
1172 if (map
->head
== NULL
) {
1173 map
->head
= map
->tail
= index
;
1174 } else if (point
== NULL
) {
1175 index
->prev
= map
->tail
;
1176 map
->tail
->next
= index
;
1178 } else if (point
== map
->head
) {
1179 index
->next
= map
->head
;
1180 map
->head
->prev
= index
;
1183 index
->next
= point
;
1184 index
->prev
= point
->prev
;
1186 point
->prev
->next
= index
;
1187 point
->prev
= index
;
1190 /* Execute event hook. */
1191 if (route_map_master
.event_hook
) {
1192 (*route_map_master
.event_hook
)(map
->name
);
1193 route_map_notify_dependencies(map
->name
, RMAP_EVENT_CALL_ADDED
);
1197 zlog_debug("Route-map %s add sequence %d, type: %s",
1198 map
->name
, pref
, route_map_type_str(type
));
1203 /* Get route map index. */
1204 static struct route_map_index
*
1205 route_map_index_get(struct route_map
*map
, enum route_map_type type
, int pref
)
1207 struct route_map_index
*index
;
1209 index
= route_map_index_lookup(map
, RMAP_ANY
, pref
);
1210 if (index
&& index
->type
!= type
) {
1211 /* Delete index from route map. */
1212 route_map_index_delete(index
, 1);
1216 index
= route_map_index_add(map
, type
, pref
);
1220 /* New route map rule */
1221 static struct route_map_rule
*route_map_rule_new(void)
1223 struct route_map_rule
*new;
1225 new = XCALLOC(MTYPE_ROUTE_MAP_RULE
, sizeof(struct route_map_rule
));
1229 /* Install rule command to the match list. */
1230 void route_map_install_match(struct route_map_rule_cmd
*cmd
)
1232 vector_set(route_match_vec
, cmd
);
1235 /* Install rule command to the set list. */
1236 void route_map_install_set(struct route_map_rule_cmd
*cmd
)
1238 vector_set(route_set_vec
, cmd
);
1241 /* Lookup rule command from match list. */
1242 static struct route_map_rule_cmd
*route_map_lookup_match(const char *name
)
1245 struct route_map_rule_cmd
*rule
;
1247 for (i
= 0; i
< vector_active(route_match_vec
); i
++)
1248 if ((rule
= vector_slot(route_match_vec
, i
)) != NULL
)
1249 if (strcmp(rule
->str
, name
) == 0)
1254 /* Lookup rule command from set list. */
1255 static struct route_map_rule_cmd
*route_map_lookup_set(const char *name
)
1258 struct route_map_rule_cmd
*rule
;
1260 for (i
= 0; i
< vector_active(route_set_vec
); i
++)
1261 if ((rule
= vector_slot(route_set_vec
, i
)) != NULL
)
1262 if (strcmp(rule
->str
, name
) == 0)
1267 /* Add match and set rule to rule list. */
1268 static void route_map_rule_add(struct route_map_rule_list
*list
,
1269 struct route_map_rule
*rule
)
1272 rule
->prev
= list
->tail
;
1274 list
->tail
->next
= rule
;
1280 /* Delete rule from rule list. */
1281 static void route_map_rule_delete(struct route_map_rule_list
*list
,
1282 struct route_map_rule
*rule
)
1284 if (rule
->cmd
->func_free
)
1285 (*rule
->cmd
->func_free
)(rule
->value
);
1287 XFREE(MTYPE_ROUTE_MAP_RULE_STR
, rule
->rule_str
);
1290 rule
->next
->prev
= rule
->prev
;
1292 list
->tail
= rule
->prev
;
1294 rule
->prev
->next
= rule
->next
;
1296 list
->head
= rule
->next
;
1298 XFREE(MTYPE_ROUTE_MAP_RULE
, rule
);
1301 /* strcmp wrapper function which don't crush even argument is NULL. */
1302 static int rulecmp(const char *dst
, const char *src
)
1313 return strcmp(dst
, src
);
1318 /* Use this to return the already specified argument for this match. This is
1319 * useful to get the specified argument with a route map match rule when the
1320 * rule is being deleted and the argument is not provided.
1322 const char *route_map_get_match_arg(struct route_map_index
*index
,
1323 const char *match_name
)
1325 struct route_map_rule
*rule
;
1326 struct route_map_rule_cmd
*cmd
;
1328 /* First lookup rule for add match statement. */
1329 cmd
= route_map_lookup_match(match_name
);
1333 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1334 if (rule
->cmd
== cmd
&& rule
->rule_str
!= NULL
)
1335 return (rule
->rule_str
);
1340 static route_map_event_t
get_route_map_delete_event(route_map_event_t type
)
1343 case RMAP_EVENT_CALL_ADDED
:
1344 return RMAP_EVENT_CALL_DELETED
;
1345 case RMAP_EVENT_PLIST_ADDED
:
1346 return RMAP_EVENT_PLIST_DELETED
;
1347 case RMAP_EVENT_CLIST_ADDED
:
1348 return RMAP_EVENT_CLIST_DELETED
;
1349 case RMAP_EVENT_ECLIST_ADDED
:
1350 return RMAP_EVENT_ECLIST_DELETED
;
1351 case RMAP_EVENT_LLIST_ADDED
:
1352 return RMAP_EVENT_LLIST_DELETED
;
1353 case RMAP_EVENT_ASLIST_ADDED
:
1354 return RMAP_EVENT_ASLIST_DELETED
;
1355 case RMAP_EVENT_FILTER_ADDED
:
1356 return RMAP_EVENT_FILTER_DELETED
;
1357 case RMAP_EVENT_SET_ADDED
:
1358 case RMAP_EVENT_SET_DELETED
:
1359 case RMAP_EVENT_SET_REPLACED
:
1360 case RMAP_EVENT_MATCH_ADDED
:
1361 case RMAP_EVENT_MATCH_DELETED
:
1362 case RMAP_EVENT_MATCH_REPLACED
:
1363 case RMAP_EVENT_INDEX_ADDED
:
1364 case RMAP_EVENT_INDEX_DELETED
:
1365 case RMAP_EVENT_CALL_DELETED
:
1366 case RMAP_EVENT_PLIST_DELETED
:
1367 case RMAP_EVENT_CLIST_DELETED
:
1368 case RMAP_EVENT_ECLIST_DELETED
:
1369 case RMAP_EVENT_LLIST_DELETED
:
1370 case RMAP_EVENT_ASLIST_DELETED
:
1371 case RMAP_EVENT_FILTER_DELETED
:
1372 /* This function returns the appropriate 'deleted' event type
1373 * for every 'added' event type passed to this function.
1374 * This is done only for named entities used in the
1375 * route-map match commands.
1376 * This function is not to be invoked for any of the other event
1384 * Return to make c happy but if we get here something has gone
1385 * terribly terribly wrong, so yes this return makes no sense.
1387 return RMAP_EVENT_CALL_ADDED
;
1390 /* Add match statement to route map. */
1391 int route_map_add_match(struct route_map_index
*index
, const char *match_name
,
1392 const char *match_arg
, route_map_event_t type
)
1394 struct route_map_rule
*rule
;
1395 struct route_map_rule
*next
;
1396 struct route_map_rule_cmd
*cmd
;
1398 int8_t delete_rmap_event_type
= 0;
1400 /* First lookup rule for add match statement. */
1401 cmd
= route_map_lookup_match(match_name
);
1403 return RMAP_RULE_MISSING
;
1405 /* Next call compile function for this match statement. */
1406 if (cmd
->func_compile
) {
1407 compile
= (*cmd
->func_compile
)(match_arg
);
1408 if (compile
== NULL
)
1409 return RMAP_COMPILE_ERROR
;
1413 /* If argument is completely same ignore it. */
1414 for (rule
= index
->match_list
.head
; rule
; rule
= next
) {
1416 if (rule
->cmd
== cmd
) {
1417 /* If the configured route-map match rule is exactly
1418 * the same as the existing configuration then,
1419 * ignore the duplicate configuration.
1421 if (strcmp(match_arg
, rule
->rule_str
) == 0) {
1423 (*cmd
->func_free
)(compile
);
1425 return RMAP_DUPLICATE_RULE
;
1428 /* Remove the dependency of the route-map on the rule
1429 * that is being replaced.
1431 if (type
>= RMAP_EVENT_CALL_ADDED
) {
1432 delete_rmap_event_type
=
1433 get_route_map_delete_event(type
);
1434 route_map_upd8_dependency(
1435 delete_rmap_event_type
,
1440 route_map_rule_delete(&index
->match_list
, rule
);
1444 /* Add new route map match rule. */
1445 rule
= route_map_rule_new();
1447 rule
->value
= compile
;
1449 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, match_arg
);
1451 rule
->rule_str
= NULL
;
1453 /* Add new route match rule to linked list. */
1454 route_map_rule_add(&index
->match_list
, rule
);
1456 /* Execute event hook. */
1457 if (route_map_master
.event_hook
) {
1458 (*route_map_master
.event_hook
)(index
->map
->name
);
1459 route_map_notify_dependencies(index
->map
->name
,
1460 RMAP_EVENT_CALL_ADDED
);
1463 return RMAP_COMPILE_SUCCESS
;
1466 /* Delete specified route match rule. */
1467 int route_map_delete_match(struct route_map_index
*index
,
1468 const char *match_name
, const char *match_arg
)
1470 struct route_map_rule
*rule
;
1471 struct route_map_rule_cmd
*cmd
;
1473 cmd
= route_map_lookup_match(match_name
);
1477 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1478 if (rule
->cmd
== cmd
&& (rulecmp(rule
->rule_str
, match_arg
) == 0
1479 || match_arg
== NULL
)) {
1480 route_map_rule_delete(&index
->match_list
, rule
);
1481 /* Execute event hook. */
1482 if (route_map_master
.event_hook
) {
1483 (*route_map_master
.event_hook
)(index
->map
->name
);
1484 route_map_notify_dependencies(
1486 RMAP_EVENT_CALL_ADDED
);
1490 /* Can't find matched rule. */
1494 /* Add route-map set statement to the route map. */
1495 int route_map_add_set(struct route_map_index
*index
, const char *set_name
,
1496 const char *set_arg
)
1498 struct route_map_rule
*rule
;
1499 struct route_map_rule
*next
;
1500 struct route_map_rule_cmd
*cmd
;
1503 cmd
= route_map_lookup_set(set_name
);
1505 return RMAP_RULE_MISSING
;
1507 /* Next call compile function for this match statement. */
1508 if (cmd
->func_compile
) {
1509 compile
= (*cmd
->func_compile
)(set_arg
);
1510 if (compile
== NULL
)
1511 return RMAP_COMPILE_ERROR
;
1515 /* Add by WJL. if old set command of same kind exist, delete it first
1516 to ensure only one set command of same kind exist under a
1518 for (rule
= index
->set_list
.head
; rule
; rule
= next
) {
1520 if (rule
->cmd
== cmd
)
1521 route_map_rule_delete(&index
->set_list
, rule
);
1524 /* Add new route map match rule. */
1525 rule
= route_map_rule_new();
1527 rule
->value
= compile
;
1529 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, set_arg
);
1531 rule
->rule_str
= NULL
;
1533 /* Add new route match rule to linked list. */
1534 route_map_rule_add(&index
->set_list
, rule
);
1536 /* Execute event hook. */
1537 if (route_map_master
.event_hook
) {
1538 (*route_map_master
.event_hook
)(index
->map
->name
);
1539 route_map_notify_dependencies(index
->map
->name
,
1540 RMAP_EVENT_CALL_ADDED
);
1542 return RMAP_COMPILE_SUCCESS
;
1545 /* Delete route map set rule. */
1546 int route_map_delete_set(struct route_map_index
*index
, const char *set_name
,
1547 const char *set_arg
)
1549 struct route_map_rule
*rule
;
1550 struct route_map_rule_cmd
*cmd
;
1552 cmd
= route_map_lookup_set(set_name
);
1556 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
1557 if ((rule
->cmd
== cmd
) && (rulecmp(rule
->rule_str
, set_arg
) == 0
1558 || set_arg
== NULL
)) {
1559 route_map_rule_delete(&index
->set_list
, rule
);
1560 /* Execute event hook. */
1561 if (route_map_master
.event_hook
) {
1562 (*route_map_master
.event_hook
)(index
->map
->name
);
1563 route_map_notify_dependencies(
1565 RMAP_EVENT_CALL_ADDED
);
1569 /* Can't find matched rule. */
1573 static enum route_map_cmd_result_t
1574 route_map_apply_match(struct route_map_rule_list
*match_list
,
1575 const struct prefix
*prefix
, route_map_object_t type
,
1578 enum route_map_cmd_result_t ret
= RMAP_NOMATCH
;
1579 struct route_map_rule
*match
;
1580 bool is_matched
= false;
1583 /* Check all match rule and if there is no match rule, go to the
1585 if (!match_list
->head
)
1588 for (match
= match_list
->head
; match
; match
= match
->next
) {
1590 * Try each match statement. If any match does not
1591 * return RMAP_MATCH or RMAP_NOOP, return.
1592 * Otherwise continue on to next match statement.
1593 * All match statements must MATCH for
1594 * end-result to be a match.
1595 * (Exception:If match stmts result in a mix of
1596 * MATCH/NOOP, then also end-result is a match)
1597 * If all result in NOOP, end-result is NOOP.
1599 ret
= (*match
->cmd
->func_apply
)(match
->value
, prefix
,
1603 * If the consolidated result of func_apply is:
1604 * -----------------------------------------------
1605 * | MATCH | NOMATCH | NOOP | Final Result |
1606 * ------------------------------------------------
1607 * | yes | yes | yes | NOMATCH |
1608 * | no | no | yes | NOOP |
1609 * | yes | no | yes | MATCH |
1610 * | no | yes | yes | NOMATCH |
1611 * |-----------------------------------------------
1613 * Traditionally, all rules within route-map
1614 * should match for it to MATCH.
1615 * If there are noops within the route-map rules,
1616 * it follows the above matrix.
1618 * Eg: route-map rm1 permit 10
1623 * route-map rm1 permit 20
1651 /* Apply route map's each index to the object.
1653 The matrix for a route-map looks like this:
1654 (note, this includes the description for the "NEXT"
1655 and "GOTO" frobs now
1657 | Match | No Match | No op
1658 |-----------|--------------|-------
1659 permit | action | cont | cont.
1660 | | default:deny | default:permit
1661 -------------------+-----------------------
1662 | deny | cont | cont.
1663 deny | | default:deny | default:permit
1664 |-----------|--------------|--------
1667 -Apply Set statements, accept route
1668 -If Call statement is present jump to the specified route-map, if it
1669 denies the route we finish.
1670 -If NEXT is specified, goto NEXT statement
1671 -If GOTO is specified, goto the first clause where pref > nextpref
1672 -If nothing is specified, do as Cisco and finish
1674 -Route is denied by route-map.
1678 If we get no matches after we've processed all updates, then the route
1681 Some notes on the new "CALL", "NEXT" and "GOTO"
1682 call WORD - If this clause is matched, then the set statements
1683 are executed and then we jump to route-map 'WORD'. If
1684 this route-map denies the route, we finish, in other
1686 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
1687 on-match next - If this clause is matched, then the set statements
1688 are executed and then we drop through to the next clause
1689 on-match goto n - If this clause is matched, then the set statments
1690 are executed and then we goto the nth clause, or the
1691 first clause greater than this. In order to ensure
1692 route-maps *always* exit, you cannot jump backwards.
1695 We need to make sure our route-map processing matches the above
1697 route_map_result_t
route_map_apply(struct route_map
*map
,
1698 const struct prefix
*prefix
,
1699 route_map_object_t type
, void *object
)
1701 static int recursion
= 0;
1702 enum route_map_cmd_result_t match_ret
= RMAP_NOMATCH
;
1703 route_map_result_t ret
= RMAP_PERMITMATCH
;
1704 struct route_map_index
*index
;
1705 struct route_map_rule
*set
;
1706 char buf
[PREFIX_STRLEN
];
1708 if (recursion
> RMAP_RECURSION_LIMIT
) {
1710 EC_LIB_RMAP_RECURSION_LIMIT
,
1711 "route-map recursion limit (%d) reached, discarding route",
1712 RMAP_RECURSION_LIMIT
);
1714 return RMAP_DENYMATCH
;
1717 if (map
== NULL
|| map
->head
== NULL
) {
1718 ret
= RMAP_DENYMATCH
;
1719 goto route_map_apply_end
;
1723 for (index
= map
->head
; index
; index
= index
->next
) {
1724 /* Apply this index. */
1726 match_ret
= route_map_apply_match(&index
->match_list
, prefix
,
1730 zlog_debug("Route-map: %s, sequence: %d, prefix: %s, result: %s",
1731 map
->name
, index
->pref
,
1732 prefix2str(prefix
, buf
, sizeof(buf
)),
1733 route_map_cmd_result_str(match_ret
));
1736 /* Now we apply the matrix from above */
1737 if (match_ret
== RMAP_NOOP
)
1739 * Do not change the return value. Retain the previous
1740 * return value. Previous values can be:
1741 * 1)permitmatch (if a nomatch was never
1742 * seen before in this route-map.)
1743 * 2)denymatch (if a nomatch was seen earlier in one
1744 * of the previous sequences)
1748 * 'cont' from matrix - continue to next route-map
1752 else if (match_ret
== RMAP_NOMATCH
) {
1755 * The return value is now changed to denymatch.
1756 * So from here on out, even if we see more noops,
1757 * we retain this return value and return this
1758 * eventually if there are no matches.
1760 ret
= RMAP_DENYMATCH
;
1763 * 'cont' from matrix - continue to next route-map
1767 } else if (match_ret
== RMAP_MATCH
) {
1768 if (index
->type
== RMAP_PERMIT
)
1771 /* Match succeeded, rmap is of type permit */
1772 ret
= RMAP_PERMITMATCH
;
1774 /* permit+match must execute sets */
1775 for (set
= index
->set_list
.head
; set
;
1778 * set cmds return RMAP_OKAY or
1779 * RMAP_ERROR. We do not care if
1780 * set succeeded or not. So, ignore
1783 (void) (*set
->cmd
->func_apply
)(
1784 set
->value
, prefix
, type
,
1787 /* Call another route-map if available */
1788 if (index
->nextrm
) {
1789 struct route_map
*nextrm
=
1790 route_map_lookup_by_name(
1793 if (nextrm
) /* Target route-map found,
1797 ret
= route_map_apply(
1798 nextrm
, prefix
, type
,
1803 /* If nextrm returned 'deny', finish. */
1804 if (ret
== RMAP_DENYMATCH
)
1805 goto route_map_apply_end
;
1808 switch (index
->exitpolicy
) {
1810 goto route_map_apply_end
;
1814 /* Find the next clause to jump to */
1815 struct route_map_index
*next
=
1817 int nextpref
= index
->nextpref
;
1819 while (next
&& next
->pref
< nextpref
) {
1824 /* No clauses match! */
1825 goto route_map_apply_end
;
1829 } else if (index
->type
== RMAP_DENY
)
1832 ret
= RMAP_DENYMATCH
;
1833 goto route_map_apply_end
;
1838 route_map_apply_end
:
1840 zlog_debug("Route-map: %s, prefix: %s, result: %s",
1841 (map
? map
->name
: "null"),
1842 prefix2str(prefix
, buf
, sizeof(buf
)),
1843 route_map_result_str(ret
));
1849 void route_map_add_hook(void (*func
)(const char *))
1851 route_map_master
.add_hook
= func
;
1854 void route_map_delete_hook(void (*func
)(const char *))
1856 route_map_master
.delete_hook
= func
;
1859 void route_map_event_hook(void (*func
)(const char *name
))
1861 route_map_master
.event_hook
= func
;
1864 /* Routines for route map dependency lists and dependency processing */
1865 static bool route_map_rmap_hash_cmp(const void *p1
, const void *p2
)
1867 return strcmp(((const struct route_map_dep_data
*)p1
)->rname
,
1868 ((const struct route_map_dep_data
*)p2
)->rname
)
1872 static bool route_map_dep_hash_cmp(const void *p1
, const void *p2
)
1875 return (strcmp(((const struct route_map_dep
*)p1
)->dep_name
,
1880 static void route_map_clear_reference(struct hash_bucket
*bucket
, void *arg
)
1882 struct route_map_dep
*dep
= bucket
->data
;
1883 struct route_map_dep_data
*dep_data
= NULL
, tmp_dep_data
;
1886 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
1887 tmp_dep_data
.rname
= arg
;
1888 dep_data
= hash_release(dep
->dep_rmap_hash
,
1891 XFREE(MTYPE_ROUTE_MAP_NAME
, dep_data
->rname
);
1892 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, dep_data
);
1894 if (!dep
->dep_rmap_hash
->count
) {
1895 dep
= hash_release(dep
->this_hash
,
1896 (void *)dep
->dep_name
);
1897 hash_free(dep
->dep_rmap_hash
);
1898 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
1899 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
1904 static void route_map_clear_all_references(char *rmap_name
)
1908 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
1909 hash_iterate(route_map_dep_hash
[i
], route_map_clear_reference
,
1914 static unsigned int route_map_dep_data_hash_make_key(const void *p
)
1916 const struct route_map_dep_data
*dep_data
= p
;
1918 return string_hash_make(dep_data
->rname
);
1921 static void *route_map_dep_hash_alloc(void *p
)
1923 char *dep_name
= (char *)p
;
1924 struct route_map_dep
*dep_entry
;
1926 dep_entry
= XCALLOC(MTYPE_ROUTE_MAP_DEP
, sizeof(struct route_map_dep
));
1927 dep_entry
->dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1928 dep_entry
->dep_rmap_hash
=
1929 hash_create_size(8, route_map_dep_data_hash_make_key
,
1930 route_map_rmap_hash_cmp
, "Route Map Dep Hash");
1931 dep_entry
->this_hash
= NULL
;
1936 static void *route_map_name_hash_alloc(void *p
)
1938 struct route_map_dep_data
*dep_data
= NULL
, *tmp_dep_data
= NULL
;
1940 dep_data
= XCALLOC(MTYPE_ROUTE_MAP_DEP_DATA
,
1941 sizeof(struct route_map_dep_data
));
1943 dep_data
->rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, tmp_dep_data
->rname
);
1947 static unsigned int route_map_dep_hash_make_key(const void *p
)
1949 return (string_hash_make((char *)p
));
1952 static void route_map_print_dependency(struct hash_bucket
*bucket
, void *data
)
1954 struct route_map_dep_data
*dep_data
= bucket
->data
;
1955 char *rmap_name
= dep_data
->rname
;
1956 char *dep_name
= data
;
1958 zlog_debug("%s: Dependency for %s: %s", __FUNCTION__
, dep_name
,
1962 static int route_map_dep_update(struct hash
*dephash
, const char *dep_name
,
1963 const char *rmap_name
, route_map_event_t type
)
1965 struct route_map_dep
*dep
= NULL
;
1966 char *dname
, *rname
;
1968 struct route_map_dep_data
*dep_data
= NULL
, *ret_dep_data
= NULL
;
1969 struct route_map_dep_data tmp_dep_data
;
1971 dname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1972 rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
1975 case RMAP_EVENT_PLIST_ADDED
:
1976 case RMAP_EVENT_CLIST_ADDED
:
1977 case RMAP_EVENT_ECLIST_ADDED
:
1978 case RMAP_EVENT_ASLIST_ADDED
:
1979 case RMAP_EVENT_LLIST_ADDED
:
1980 case RMAP_EVENT_CALL_ADDED
:
1981 case RMAP_EVENT_FILTER_ADDED
:
1983 zlog_debug("Adding dependency for filter %s in route-map %s",
1984 dep_name
, rmap_name
);
1985 dep
= (struct route_map_dep
*)hash_get(
1986 dephash
, dname
, route_map_dep_hash_alloc
);
1992 if (!dep
->this_hash
)
1993 dep
->this_hash
= dephash
;
1995 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
1996 tmp_dep_data
.rname
= rname
;
1997 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
1999 dep_data
= hash_get(dep
->dep_rmap_hash
, &tmp_dep_data
,
2000 route_map_name_hash_alloc
);
2004 case RMAP_EVENT_PLIST_DELETED
:
2005 case RMAP_EVENT_CLIST_DELETED
:
2006 case RMAP_EVENT_ECLIST_DELETED
:
2007 case RMAP_EVENT_ASLIST_DELETED
:
2008 case RMAP_EVENT_LLIST_DELETED
:
2009 case RMAP_EVENT_CALL_DELETED
:
2010 case RMAP_EVENT_FILTER_DELETED
:
2012 zlog_debug("Deleting dependency for filter %s in route-map %s",
2013 dep_name
, rmap_name
);
2014 dep
= (struct route_map_dep
*)hash_get(dephash
, dname
, NULL
);
2019 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
2020 tmp_dep_data
.rname
= rname
;
2021 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
2024 if (!dep_data
->refcnt
) {
2025 ret_dep_data
= hash_release(dep
->dep_rmap_hash
,
2028 XFREE(MTYPE_ROUTE_MAP_NAME
,
2029 ret_dep_data
->rname
);
2030 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, ret_dep_data
);
2034 if (!dep
->dep_rmap_hash
->count
) {
2035 dep
= hash_release(dephash
, dname
);
2036 hash_free(dep
->dep_rmap_hash
);
2037 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
2038 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
2042 case RMAP_EVENT_SET_ADDED
:
2043 case RMAP_EVENT_SET_DELETED
:
2044 case RMAP_EVENT_SET_REPLACED
:
2045 case RMAP_EVENT_MATCH_ADDED
:
2046 case RMAP_EVENT_MATCH_DELETED
:
2047 case RMAP_EVENT_MATCH_REPLACED
:
2048 case RMAP_EVENT_INDEX_ADDED
:
2049 case RMAP_EVENT_INDEX_DELETED
:
2055 hash_iterate(dep
->dep_rmap_hash
,
2056 route_map_print_dependency
, dname
);
2060 XFREE(MTYPE_ROUTE_MAP_NAME
, rname
);
2061 XFREE(MTYPE_ROUTE_MAP_NAME
, dname
);
2065 static struct hash
*route_map_get_dep_hash(route_map_event_t event
)
2067 struct hash
*upd8_hash
= NULL
;
2070 case RMAP_EVENT_PLIST_ADDED
:
2071 case RMAP_EVENT_PLIST_DELETED
:
2072 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_PLIST
];
2074 case RMAP_EVENT_CLIST_ADDED
:
2075 case RMAP_EVENT_CLIST_DELETED
:
2076 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_CLIST
];
2078 case RMAP_EVENT_ECLIST_ADDED
:
2079 case RMAP_EVENT_ECLIST_DELETED
:
2080 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ECLIST
];
2082 case RMAP_EVENT_ASLIST_ADDED
:
2083 case RMAP_EVENT_ASLIST_DELETED
:
2084 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ASPATH
];
2086 case RMAP_EVENT_LLIST_ADDED
:
2087 case RMAP_EVENT_LLIST_DELETED
:
2088 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_LCLIST
];
2090 case RMAP_EVENT_CALL_ADDED
:
2091 case RMAP_EVENT_CALL_DELETED
:
2092 case RMAP_EVENT_MATCH_ADDED
:
2093 case RMAP_EVENT_MATCH_DELETED
:
2094 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_RMAP
];
2096 case RMAP_EVENT_FILTER_ADDED
:
2097 case RMAP_EVENT_FILTER_DELETED
:
2098 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_FILTER
];
2101 * Should we actually be ignoring these?
2102 * I am not sure but at this point in time, let
2103 * us get them into this switch and we can peel
2104 * them into the appropriate place in the future
2106 case RMAP_EVENT_SET_ADDED
:
2107 case RMAP_EVENT_SET_DELETED
:
2108 case RMAP_EVENT_SET_REPLACED
:
2109 case RMAP_EVENT_MATCH_REPLACED
:
2110 case RMAP_EVENT_INDEX_ADDED
:
2111 case RMAP_EVENT_INDEX_DELETED
:
2118 static void route_map_process_dependency(struct hash_bucket
*bucket
, void *data
)
2120 struct route_map_dep_data
*dep_data
= NULL
;
2121 char *rmap_name
= NULL
;
2123 dep_data
= bucket
->data
;
2124 rmap_name
= dep_data
->rname
;
2127 zlog_debug("Notifying %s of dependency", rmap_name
);
2128 if (route_map_master
.event_hook
)
2129 (*route_map_master
.event_hook
)(rmap_name
);
2132 void route_map_upd8_dependency(route_map_event_t type
, const char *arg
,
2133 const char *rmap_name
)
2135 struct hash
*upd8_hash
= NULL
;
2137 if ((upd8_hash
= route_map_get_dep_hash(type
))) {
2138 route_map_dep_update(upd8_hash
, arg
, rmap_name
, type
);
2140 if (type
== RMAP_EVENT_CALL_ADDED
) {
2142 if (route_map_master
.add_hook
)
2143 (*route_map_master
.add_hook
)(rmap_name
);
2144 } else if (type
== RMAP_EVENT_CALL_DELETED
) {
2146 if (route_map_master
.delete_hook
)
2147 (*route_map_master
.delete_hook
)(rmap_name
);
2152 void route_map_notify_dependencies(const char *affected_name
,
2153 route_map_event_t event
)
2155 struct route_map_dep
*dep
;
2156 struct hash
*upd8_hash
;
2162 name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, affected_name
);
2164 if ((upd8_hash
= route_map_get_dep_hash(event
)) == NULL
) {
2165 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
2169 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, name
, NULL
);
2171 if (!dep
->this_hash
)
2172 dep
->this_hash
= upd8_hash
;
2175 zlog_debug("Filter %s updated", dep
->dep_name
);
2176 hash_iterate(dep
->dep_rmap_hash
, route_map_process_dependency
,
2180 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
2184 /* VTY related functions. */
2185 DEFUN (match_interface
,
2186 match_interface_cmd
,
2187 "match interface WORD",
2189 "match first hop interface of route\n"
2193 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2195 if (rmap_match_set_hook
.match_interface
)
2196 return rmap_match_set_hook
.match_interface(
2197 vty
, index
, "interface", argv
[idx_word
]->arg
,
2198 RMAP_EVENT_MATCH_ADDED
);
2202 DEFUN (no_match_interface
,
2203 no_match_interface_cmd
,
2204 "no match interface [WORD]",
2207 "Match first hop interface of route\n"
2210 char *iface
= (argc
== 4) ? argv
[3]->arg
: NULL
;
2211 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2213 if (rmap_match_set_hook
.no_match_interface
)
2214 return rmap_match_set_hook
.no_match_interface(
2215 vty
, index
, "interface", iface
,
2216 RMAP_EVENT_MATCH_DELETED
);
2221 DEFUN (match_ip_address
,
2222 match_ip_address_cmd
,
2223 "match ip address <(1-199)|(1300-2699)|WORD>",
2226 "Match address of route\n"
2227 "IP access-list number\n"
2228 "IP access-list number (expanded range)\n"
2229 "IP Access-list name\n")
2232 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2234 if (rmap_match_set_hook
.match_ip_address
)
2235 return rmap_match_set_hook
.match_ip_address(
2236 vty
, index
, "ip address", argv
[idx_acl
]->arg
,
2237 RMAP_EVENT_FILTER_ADDED
);
2242 DEFUN (no_match_ip_address
,
2243 no_match_ip_address_cmd
,
2244 "no match ip address [<(1-199)|(1300-2699)|WORD>]",
2248 "Match address of route\n"
2249 "IP access-list number\n"
2250 "IP access-list number (expanded range)\n"
2251 "IP Access-list name\n")
2254 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2256 if (rmap_match_set_hook
.no_match_ip_address
) {
2257 if (argc
<= idx_word
)
2258 return rmap_match_set_hook
.no_match_ip_address(
2259 vty
, index
, "ip address", NULL
,
2260 RMAP_EVENT_FILTER_DELETED
);
2261 return rmap_match_set_hook
.no_match_ip_address(
2262 vty
, index
, "ip address", argv
[idx_word
]->arg
,
2263 RMAP_EVENT_FILTER_DELETED
);
2269 DEFUN (match_ip_address_prefix_list
,
2270 match_ip_address_prefix_list_cmd
,
2271 "match ip address prefix-list WORD",
2274 "Match address of route\n"
2275 "Match entries of prefix-lists\n"
2276 "IP prefix-list name\n")
2279 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2281 if (rmap_match_set_hook
.match_ip_address_prefix_list
)
2282 return rmap_match_set_hook
.match_ip_address_prefix_list(
2283 vty
, index
, "ip address prefix-list",
2284 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
2289 DEFUN (no_match_ip_address_prefix_list
,
2290 no_match_ip_address_prefix_list_cmd
,
2291 "no match ip address prefix-list [WORD]",
2295 "Match address of route\n"
2296 "Match entries of prefix-lists\n"
2297 "IP prefix-list name\n")
2300 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2302 if (rmap_match_set_hook
.no_match_ip_address_prefix_list
) {
2303 if (argc
<= idx_word
)
2304 return rmap_match_set_hook
2305 .no_match_ip_address_prefix_list(
2306 vty
, index
, "ip address prefix-list",
2307 NULL
, RMAP_EVENT_PLIST_DELETED
);
2308 return rmap_match_set_hook
.no_match_ip_address_prefix_list(
2309 vty
, index
, "ip address prefix-list",
2310 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2316 DEFUN (match_ip_next_hop
,
2317 match_ip_next_hop_cmd
,
2318 "match ip next-hop <(1-199)|(1300-2699)|WORD>",
2321 "Match next-hop address of route\n"
2322 "IP access-list number\n"
2323 "IP access-list number (expanded range)\n"
2324 "IP Access-list name\n")
2327 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2329 if (rmap_match_set_hook
.match_ip_next_hop
)
2330 return rmap_match_set_hook
.match_ip_next_hop(
2331 vty
, index
, "ip next-hop", argv
[idx_acl
]->arg
,
2332 RMAP_EVENT_FILTER_ADDED
);
2337 DEFUN (no_match_ip_next_hop
,
2338 no_match_ip_next_hop_cmd
,
2339 "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
2343 "Match next-hop address of route\n"
2344 "IP access-list number\n"
2345 "IP access-list number (expanded range)\n"
2346 "IP Access-list name\n")
2349 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2351 if (rmap_match_set_hook
.no_match_ip_next_hop
) {
2352 if (argc
<= idx_word
)
2353 return rmap_match_set_hook
.no_match_ip_next_hop(
2354 vty
, index
, "ip next-hop", NULL
,
2355 RMAP_EVENT_FILTER_DELETED
);
2356 return rmap_match_set_hook
.no_match_ip_next_hop(
2357 vty
, index
, "ip next-hop", argv
[idx_word
]->arg
,
2358 RMAP_EVENT_FILTER_DELETED
);
2364 DEFUN (match_ip_next_hop_prefix_list
,
2365 match_ip_next_hop_prefix_list_cmd
,
2366 "match ip next-hop prefix-list WORD",
2369 "Match next-hop address of route\n"
2370 "Match entries of prefix-lists\n"
2371 "IP prefix-list name\n")
2374 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2376 if (rmap_match_set_hook
.match_ip_next_hop_prefix_list
)
2377 return rmap_match_set_hook
.match_ip_next_hop_prefix_list(
2378 vty
, index
, "ip next-hop prefix-list",
2379 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
2383 DEFUN (no_match_ip_next_hop_prefix_list
,
2384 no_match_ip_next_hop_prefix_list_cmd
,
2385 "no match ip next-hop prefix-list [WORD]",
2389 "Match next-hop address of route\n"
2390 "Match entries of prefix-lists\n"
2391 "IP prefix-list name\n")
2394 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2396 if (rmap_match_set_hook
.no_match_ip_next_hop
) {
2397 if (argc
<= idx_word
)
2398 return rmap_match_set_hook
.no_match_ip_next_hop(
2399 vty
, index
, "ip next-hop prefix-list", NULL
,
2400 RMAP_EVENT_PLIST_DELETED
);
2401 return rmap_match_set_hook
.no_match_ip_next_hop(
2402 vty
, index
, "ip next-hop prefix-list",
2403 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2408 DEFUN(match_ip_next_hop_type
, match_ip_next_hop_type_cmd
,
2409 "match ip next-hop type <blackhole>",
2411 "Match next-hop address of route\n"
2412 "Match entries by type\n"
2416 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2418 if (rmap_match_set_hook
.match_ip_next_hop_type
)
2419 return rmap_match_set_hook
.match_ip_next_hop_type(
2420 vty
, index
, "ip next-hop type", argv
[idx_word
]->arg
,
2421 RMAP_EVENT_MATCH_ADDED
);
2425 DEFUN(no_match_ip_next_hop_type
, no_match_ip_next_hop_type_cmd
,
2426 "no match ip next-hop type [<blackhole>]",
2427 NO_STR MATCH_STR IP_STR
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
.no_match_ip_next_hop
) {
2436 if (argc
<= idx_word
)
2437 return rmap_match_set_hook
.no_match_ip_next_hop(
2438 vty
, index
, "ip next-hop type", NULL
,
2439 RMAP_EVENT_MATCH_DELETED
);
2440 return rmap_match_set_hook
.no_match_ip_next_hop(
2441 vty
, index
, "ip next-hop type", argv
[idx_word
]->arg
,
2442 RMAP_EVENT_MATCH_DELETED
);
2448 DEFUN (match_ipv6_address
,
2449 match_ipv6_address_cmd
,
2450 "match ipv6 address WORD",
2453 "Match IPv6 address of route\n"
2454 "IPv6 access-list name\n")
2457 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2459 if (rmap_match_set_hook
.match_ipv6_address
)
2460 return rmap_match_set_hook
.match_ipv6_address(
2461 vty
, index
, "ipv6 address", argv
[idx_word
]->arg
,
2462 RMAP_EVENT_FILTER_ADDED
);
2466 DEFUN (no_match_ipv6_address
,
2467 no_match_ipv6_address_cmd
,
2468 "no match ipv6 address WORD",
2472 "Match IPv6 address of route\n"
2473 "IPv6 access-list name\n")
2476 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2478 if (rmap_match_set_hook
.no_match_ipv6_address
)
2479 return rmap_match_set_hook
.no_match_ipv6_address(
2480 vty
, index
, "ipv6 address", argv
[idx_word
]->arg
,
2481 RMAP_EVENT_FILTER_DELETED
);
2486 DEFUN (match_ipv6_address_prefix_list
,
2487 match_ipv6_address_prefix_list_cmd
,
2488 "match ipv6 address prefix-list WORD",
2491 "Match address of route\n"
2492 "Match entries of prefix-lists\n"
2493 "IP prefix-list name\n")
2496 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2498 if (rmap_match_set_hook
.match_ipv6_address_prefix_list
)
2499 return rmap_match_set_hook
.match_ipv6_address_prefix_list(
2500 vty
, index
, "ipv6 address prefix-list",
2501 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
2505 DEFUN (no_match_ipv6_address_prefix_list
,
2506 no_match_ipv6_address_prefix_list_cmd
,
2507 "no match ipv6 address prefix-list WORD",
2511 "Match address of route\n"
2512 "Match entries of prefix-lists\n"
2513 "IP prefix-list name\n")
2516 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2518 if (rmap_match_set_hook
.no_match_ipv6_address_prefix_list
)
2519 return rmap_match_set_hook
.no_match_ipv6_address_prefix_list(
2520 vty
, index
, "ipv6 address prefix-list",
2521 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2525 DEFUN(match_ipv6_next_hop_type
, match_ipv6_next_hop_type_cmd
,
2526 "match ipv6 next-hop type <blackhole>",
2528 "Match next-hop address of route\n"
2529 "Match entries by type\n"
2533 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2535 if (rmap_match_set_hook
.match_ipv6_next_hop_type
)
2536 return rmap_match_set_hook
.match_ipv6_next_hop_type(
2537 vty
, index
, "ipv6 next-hop type", argv
[idx_word
]->arg
,
2538 RMAP_EVENT_MATCH_ADDED
);
2542 DEFUN(no_match_ipv6_next_hop_type
, no_match_ipv6_next_hop_type_cmd
,
2543 "no match ipv6 next-hop type [<blackhole>]",
2544 NO_STR MATCH_STR IPV6_STR
2545 "Match address of route\n"
2546 "Match entries by type\n"
2550 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2552 if (rmap_match_set_hook
.no_match_ipv6_next_hop_type
)
2553 return rmap_match_set_hook
.no_match_ipv6_next_hop_type(
2554 vty
, index
, "ipv6 next-hop type",
2555 (argc
<= idx_word
) ? NULL
: argv
[idx_word
]->arg
,
2556 RMAP_EVENT_MATCH_DELETED
);
2560 DEFUN (match_metric
,
2562 "match metric (0-4294967295)",
2564 "Match metric of route\n"
2568 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2570 if (rmap_match_set_hook
.match_metric
)
2571 return rmap_match_set_hook
.match_metric(vty
, index
, "metric",
2572 argv
[idx_number
]->arg
,
2573 RMAP_EVENT_MATCH_ADDED
);
2578 DEFUN (no_match_metric
,
2579 no_match_metric_cmd
,
2580 "no match metric [(0-4294967295)]",
2583 "Match metric of route\n"
2587 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2589 if (rmap_match_set_hook
.no_match_metric
) {
2590 if (argc
<= idx_number
)
2591 return rmap_match_set_hook
.no_match_metric(
2592 vty
, index
, "metric", NULL
,
2593 RMAP_EVENT_MATCH_DELETED
);
2594 return rmap_match_set_hook
.no_match_metric(
2595 vty
, index
, "metric", argv
[idx_number
]->arg
,
2596 RMAP_EVENT_MATCH_DELETED
);
2604 "match tag (1-4294967295)",
2606 "Match tag of route\n"
2610 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2612 if (rmap_match_set_hook
.match_tag
)
2613 return rmap_match_set_hook
.match_tag(vty
, index
, "tag",
2614 argv
[idx_number
]->arg
,
2615 RMAP_EVENT_MATCH_ADDED
);
2620 DEFUN (no_match_tag
,
2622 "no match tag [(1-4294967295)]",
2625 "Match tag of route\n"
2628 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2631 char *arg
= argv_find(argv
, argc
, "(1-4294967295)", &idx
)
2635 if (rmap_match_set_hook
.no_match_tag
)
2636 return rmap_match_set_hook
.no_match_tag(
2637 vty
, index
, "tag", arg
, RMAP_EVENT_MATCH_DELETED
);
2642 DEFUN (set_ip_nexthop
,
2644 "set ip next-hop A.B.C.D",
2647 "Next hop address\n"
2648 "IP address of next hop\n")
2653 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2655 ret
= str2sockunion(argv
[idx_ipv4
]->arg
, &su
);
2657 vty_out(vty
, "%% Malformed nexthop address\n");
2658 return CMD_WARNING_CONFIG_FAILED
;
2660 if (su
.sin
.sin_addr
.s_addr
== 0
2661 || IPV4_CLASS_DE(ntohl(su
.sin
.sin_addr
.s_addr
))) {
2663 "%% nexthop address cannot be 0.0.0.0, multicast or reserved\n");
2664 return CMD_WARNING_CONFIG_FAILED
;
2667 if (rmap_match_set_hook
.set_ip_nexthop
)
2668 return rmap_match_set_hook
.set_ip_nexthop(
2669 vty
, index
, "ip next-hop", argv
[idx_ipv4
]->arg
);
2674 DEFUN (no_set_ip_nexthop
,
2675 no_set_ip_nexthop_cmd
,
2676 "no set ip next-hop [A.B.C.D]",
2680 "Next hop address\n"
2681 "IP address of next hop\n")
2684 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2685 const char *arg
= NULL
;
2687 if (argv_find(argv
, argc
, "A.B.C.D", &idx
))
2688 arg
= argv
[idx
]->arg
;
2690 if (rmap_match_set_hook
.no_set_ip_nexthop
)
2691 return rmap_match_set_hook
.no_set_ip_nexthop(
2692 vty
, index
, "ip next-hop", arg
);
2698 DEFUN (set_ipv6_nexthop_local
,
2699 set_ipv6_nexthop_local_cmd
,
2700 "set ipv6 next-hop local X:X::X:X",
2703 "IPv6 next-hop address\n"
2704 "IPv6 local address\n"
2705 "IPv6 address of next hop\n")
2708 struct in6_addr addr
;
2710 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2712 ret
= inet_pton(AF_INET6
, argv
[idx_ipv6
]->arg
, &addr
);
2714 vty_out(vty
, "%% Malformed nexthop address\n");
2715 return CMD_WARNING_CONFIG_FAILED
;
2717 if (!IN6_IS_ADDR_LINKLOCAL(&addr
)) {
2718 vty_out(vty
, "%% Invalid link-local nexthop address\n");
2719 return CMD_WARNING_CONFIG_FAILED
;
2722 if (rmap_match_set_hook
.set_ipv6_nexthop_local
)
2723 return rmap_match_set_hook
.set_ipv6_nexthop_local(
2724 vty
, index
, "ipv6 next-hop local", argv
[idx_ipv6
]->arg
);
2729 DEFUN (no_set_ipv6_nexthop_local
,
2730 no_set_ipv6_nexthop_local_cmd
,
2731 "no set ipv6 next-hop local [X:X::X:X]",
2735 "IPv6 next-hop address\n"
2736 "IPv6 local address\n"
2737 "IPv6 address of next hop\n")
2740 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2742 if (rmap_match_set_hook
.no_set_ipv6_nexthop_local
) {
2743 if (argc
<= idx_ipv6
)
2744 return rmap_match_set_hook
.no_set_ipv6_nexthop_local(
2745 vty
, index
, "ipv6 next-hop local", NULL
);
2746 return rmap_match_set_hook
.no_set_ipv6_nexthop_local(
2747 vty
, index
, "ipv6 next-hop local", argv
[5]->arg
);
2754 "set metric <(0-4294967295)|rtt|+rtt|-rtt|+metric|-metric>",
2756 "Metric value for destination routing protocol\n"
2758 "Assign round trip time\n"
2759 "Add round trip time\n"
2760 "Subtract round trip time\n"
2762 "Subtract metric\n")
2765 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2767 const char *pass
= (argv
[idx_number
]->type
== RANGE_TKN
)
2768 ? argv
[idx_number
]->arg
2769 : argv
[idx_number
]->text
;
2771 if (rmap_match_set_hook
.set_metric
)
2772 return rmap_match_set_hook
.set_metric(vty
, index
, "metric",
2778 DEFUN (no_set_metric
,
2780 "no set metric [(0-4294967295)]",
2783 "Metric value for destination routing protocol\n"
2787 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2789 if (rmap_match_set_hook
.no_set_metric
) {
2790 if (argc
<= idx_number
)
2791 return rmap_match_set_hook
.no_set_metric(
2792 vty
, index
, "metric", NULL
);
2793 return rmap_match_set_hook
.no_set_metric(vty
, index
, "metric",
2794 argv
[idx_number
]->arg
);
2802 "set tag (1-4294967295)",
2804 "Tag value for routing protocol\n"
2807 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2810 if (rmap_match_set_hook
.set_tag
)
2811 return rmap_match_set_hook
.set_tag(vty
, index
, "tag",
2812 argv
[idx_number
]->arg
);
2819 "no set tag [(1-4294967295)]",
2822 "Tag value for routing protocol\n"
2825 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2828 if (rmap_match_set_hook
.no_set_tag
) {
2829 if (argc
<= idx_number
)
2830 return rmap_match_set_hook
.no_set_tag(vty
, index
, "tag",
2832 return rmap_match_set_hook
.no_set_tag(vty
, index
, "tag",
2833 argv
[idx_number
]->arg
);
2839 DEFUN_NOSH (route_map
,
2841 "route-map WORD <deny|permit> (1-65535)",
2842 "Create route-map or enter route-map command mode\n"
2844 "Route map denies set operations\n"
2845 "Route map permits set operations\n"
2846 "Sequence to insert to/delete from existing route-map entry\n")
2849 int idx_permit_deny
= 2;
2851 struct route_map
*map
;
2852 struct route_map_index
*index
;
2853 char *endptr
= NULL
;
2855 argv
[idx_permit_deny
]->arg
[0] == 'p' ? RMAP_PERMIT
: RMAP_DENY
;
2856 unsigned long pref
= strtoul(argv
[idx_number
]->arg
, &endptr
, 10);
2857 const char *mapname
= argv
[idx_word
]->arg
;
2859 /* Get route map. */
2860 map
= route_map_get(mapname
);
2861 index
= route_map_index_get(map
, permit
, pref
);
2863 VTY_PUSH_CONTEXT(RMAP_NODE
, index
);
2867 DEFUN (no_route_map_all
,
2868 no_route_map_all_cmd
,
2869 "no route-map WORD",
2871 "Create route-map or enter route-map command mode\n"
2875 const char *mapname
= argv
[idx_word
]->arg
;
2876 struct route_map
*map
;
2878 map
= route_map_lookup_by_name(mapname
);
2880 vty_out(vty
, "%% Could not find route-map %s\n", mapname
);
2881 return CMD_WARNING_CONFIG_FAILED
;
2884 route_map_delete(map
);
2889 DEFUN (no_route_map
,
2891 "no route-map WORD <deny|permit> (1-65535)",
2893 "Create route-map or enter route-map command mode\n"
2895 "Route map denies set operations\n"
2896 "Route map permits set operations\n"
2897 "Sequence to insert to/delete from existing route-map entry\n")
2900 int idx_permit_deny
= 3;
2902 struct route_map
*map
;
2903 struct route_map_index
*index
;
2904 char *endptr
= NULL
;
2905 int permit
= strmatch(argv
[idx_permit_deny
]->text
, "permit")
2908 const char *prefstr
= argv
[idx_number
]->arg
;
2909 const char *mapname
= argv
[idx_word
]->arg
;
2910 unsigned long pref
= strtoul(prefstr
, &endptr
, 10);
2912 /* Existence check. */
2913 map
= route_map_lookup_by_name(mapname
);
2915 vty_out(vty
, "%% Could not find route-map %s\n", mapname
);
2916 return CMD_WARNING_CONFIG_FAILED
;
2919 /* Lookup route map index. */
2920 index
= route_map_index_lookup(map
, permit
, pref
);
2921 if (index
== NULL
) {
2922 vty_out(vty
, "%% Could not find route-map entry %s %s\n",
2924 return CMD_WARNING_CONFIG_FAILED
;
2927 /* Delete index from route map. */
2928 route_map_index_delete(index
, 1);
2930 /* If this route rule is the last one, delete route map itself. */
2931 if (route_map_empty(map
))
2932 route_map_delete(map
);
2937 DEFUN (rmap_onmatch_next
,
2938 rmap_onmatch_next_cmd
,
2940 "Exit policy on matches\n"
2943 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2946 if (index
->type
== RMAP_DENY
) {
2947 /* Under a deny clause, match means it's finished. No
2948 * need to set next */
2950 "on-match next not supported under route-map deny\n");
2951 return CMD_WARNING_CONFIG_FAILED
;
2953 index
->exitpolicy
= RMAP_NEXT
;
2958 DEFUN (no_rmap_onmatch_next
,
2959 no_rmap_onmatch_next_cmd
,
2962 "Exit policy on matches\n"
2965 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2968 index
->exitpolicy
= RMAP_EXIT
;
2973 DEFUN (rmap_onmatch_goto
,
2974 rmap_onmatch_goto_cmd
,
2975 "on-match goto (1-65535)",
2976 "Exit policy on matches\n"
2977 "Goto Clause number\n"
2981 char *num
= argv_find(argv
, argc
, "(1-65535)", &idx
) ? argv
[idx
]->arg
2984 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2988 if (index
->type
== RMAP_DENY
) {
2989 /* Under a deny clause, match means it's finished. No
2990 * need to go anywhere */
2992 "on-match goto not supported under route-map deny\n");
2993 return CMD_WARNING_CONFIG_FAILED
;
2997 d
= strtoul(num
, NULL
, 10);
2999 d
= index
->pref
+ 1;
3001 if (d
<= index
->pref
) {
3002 /* Can't allow you to do that, Dave */
3003 vty_out(vty
, "can't jump backwards in route-maps\n");
3004 return CMD_WARNING_CONFIG_FAILED
;
3006 index
->exitpolicy
= RMAP_GOTO
;
3007 index
->nextpref
= d
;
3013 DEFUN (no_rmap_onmatch_goto
,
3014 no_rmap_onmatch_goto_cmd
,
3017 "Exit policy on matches\n"
3018 "Goto Clause number\n")
3020 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
3023 index
->exitpolicy
= RMAP_EXIT
;
3028 /* Cisco/GNU Zebra compatibility aliases */
3030 DEFUN (rmap_continue
,
3032 "continue (1-65535)",
3033 "Continue on a different entry within the route-map\n"
3034 "Route-map entry sequence number\n")
3036 return rmap_onmatch_goto(self
, vty
, argc
, argv
);
3040 DEFUN (no_rmap_continue
,
3041 no_rmap_continue_cmd
,
3042 "no continue [(1-65535)]",
3044 "Continue on a different entry within the route-map\n"
3045 "Route-map entry sequence number\n")
3047 return no_rmap_onmatch_goto(self
, vty
, argc
, argv
);
3050 static void clear_route_map_helper(struct route_map
*map
)
3052 struct route_map_index
*index
;
3054 map
->applied_clear
= map
->applied
;
3055 for (index
= map
->head
; index
; index
= index
->next
)
3056 index
->applied_clear
= index
->applied
;
3059 DEFUN (rmap_clear_counters
,
3060 rmap_clear_counters_cmd
,
3061 "clear route-map counters [WORD]",
3063 "route-map information\n"
3064 "counters associated with the specified route-map\n"
3068 struct route_map
*map
;
3070 const char *name
= (argc
== 3 ) ? argv
[idx_word
]->arg
: NULL
;
3073 map
= route_map_lookup_by_name(name
);
3076 clear_route_map_helper(map
);
3078 vty_out(vty
, "%s: 'route-map %s' not found\n",
3079 frr_protonameinst
, name
);
3083 for (map
= route_map_master
.head
; map
; map
= map
->next
)
3084 clear_route_map_helper(map
);
3091 DEFUN (rmap_show_name
,
3093 "show route-map [WORD]",
3095 "route-map information\n"
3099 const char *name
= (argc
== 3) ? argv
[idx_word
]->arg
: NULL
;
3100 return vty_show_route_map(vty
, name
);
3103 DEFUN (rmap_show_unused
,
3104 rmap_show_unused_cmd
,
3105 "show route-map-unused",
3107 "unused route-map information\n")
3109 return vty_show_unused_route_map(vty
);
3115 "Jump to another Route-Map after match+set\n"
3116 "Target route-map name\n")
3119 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
3120 const char *rmap
= argv
[idx_word
]->arg
;
3124 /* If "call" is invoked with the same route-map name as
3125 * the one previously configured then, ignore the duplicate
3128 if (index
->nextrm
&& (strcmp(index
->nextrm
, rmap
) == 0))
3131 if (index
->nextrm
) {
3132 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED
,
3133 index
->nextrm
, index
->map
->name
);
3134 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
3136 index
->nextrm
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap
);
3138 /* Execute event hook. */
3139 route_map_upd8_dependency(RMAP_EVENT_CALL_ADDED
, index
->nextrm
,
3144 DEFUN (no_rmap_call
,
3148 "Jump to another Route-Map after match+set\n")
3150 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
3152 if (index
->nextrm
) {
3153 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED
,
3154 index
->nextrm
, index
->map
->name
);
3155 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
3156 index
->nextrm
= NULL
;
3162 DEFUN (rmap_description
,
3163 rmap_description_cmd
,
3164 "description LINE...",
3165 "Route-map comment\n"
3166 "Comment describing this route-map rule\n")
3169 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
3172 if (index
->description
)
3173 XFREE(MTYPE_TMP
, index
->description
);
3174 index
->description
= argv_concat(argv
, argc
, idx_line
);
3179 DEFUN (no_rmap_description
,
3180 no_rmap_description_cmd
,
3183 "Route-map comment\n")
3185 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
3188 if (index
->description
)
3189 XFREE(MTYPE_TMP
, index
->description
);
3190 index
->description
= NULL
;
3199 "Debug option set for route-maps\n")
3205 DEFUN (no_debug_rmap
,
3207 "no debug route-map",
3210 "Debug option set for route-maps\n")
3217 static struct cmd_node rmap_debug_node
= {RMAP_DEBUG_NODE
, "", 1};
3219 /* Configuration write function. */
3220 static int route_map_config_write(struct vty
*vty
)
3222 struct route_map
*map
;
3223 struct route_map_index
*index
;
3224 struct route_map_rule
*rule
;
3227 struct listnode
*ln
;
3228 struct list
*maplist
= list_new();
3230 for (map
= route_map_master
.head
; map
; map
= map
->next
)
3231 listnode_add(maplist
, map
);
3233 list_sort(maplist
, sort_route_map
);
3235 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
3236 for (index
= map
->head
; index
; index
= index
->next
) {
3238 vty_out(vty
, "!\n");
3242 vty_out(vty
, "route-map %s %s %d\n", map
->name
,
3243 route_map_type_str(index
->type
), index
->pref
);
3245 if (index
->description
)
3246 vty_out(vty
, " description %s\n",
3247 index
->description
);
3249 for (rule
= index
->match_list
.head
; rule
;
3251 vty_out(vty
, " match %s %s\n", rule
->cmd
->str
,
3252 rule
->rule_str
? rule
->rule_str
: "");
3254 for (rule
= index
->set_list
.head
; rule
;
3256 vty_out(vty
, " set %s %s\n", rule
->cmd
->str
,
3257 rule
->rule_str
? rule
->rule_str
: "");
3259 vty_out(vty
, " call %s\n", index
->nextrm
);
3260 if (index
->exitpolicy
== RMAP_GOTO
)
3261 vty_out(vty
, " on-match goto %d\n",
3263 if (index
->exitpolicy
== RMAP_NEXT
)
3264 vty_out(vty
, " on-match next\n");
3269 list_delete(&maplist
);
3273 static int rmap_config_write_debug(struct vty
*vty
)
3278 vty_out(vty
, "debug route-map\n");
3285 /* Route map node structure. */
3286 static struct cmd_node rmap_node
= {RMAP_NODE
, "%s(config-route-map)# ", 1};
3288 /* Common route map rules */
3290 void *route_map_rule_tag_compile(const char *arg
)
3292 unsigned long int tmp
;
3297 tmp
= strtoul(arg
, &endptr
, 0);
3298 if (arg
[0] == '\0' || *endptr
!= '\0' || errno
|| tmp
> ROUTE_TAG_MAX
)
3301 tag
= XMALLOC(MTYPE_ROUTE_MAP_COMPILED
, sizeof(*tag
));
3307 void route_map_rule_tag_free(void *rule
)
3309 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
3312 void route_map_finish(void)
3316 vector_free(route_match_vec
);
3317 route_match_vec
= NULL
;
3318 vector_free(route_set_vec
);
3319 route_set_vec
= NULL
;
3322 * All protocols are setting these to NULL
3323 * by default on shutdown( route_map_finish )
3324 * Why are we making them do this work?
3326 route_map_master
.add_hook
= NULL
;
3327 route_map_master
.delete_hook
= NULL
;
3328 route_map_master
.event_hook
= NULL
;
3330 /* cleanup route_map */
3331 while (route_map_master
.head
) {
3332 struct route_map
*map
= route_map_master
.head
;
3333 map
->to_be_processed
= false;
3334 route_map_delete(map
);
3337 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
3338 hash_free(route_map_dep_hash
[i
]);
3339 route_map_dep_hash
[i
] = NULL
;
3342 hash_free(route_map_master_hash
);
3343 route_map_master_hash
= NULL
;
3346 static void rmap_autocomplete(vector comps
, struct cmd_token
*token
)
3348 struct route_map
*map
;
3350 for (map
= route_map_master
.head
; map
; map
= map
->next
)
3351 vector_set(comps
, XSTRDUP(MTYPE_COMPLETION
, map
->name
));
3354 /* Increment the use_count counter while attaching the route map */
3355 void route_map_counter_increment(struct route_map
*map
)
3361 /* Decrement the use_count counter while detaching the route map. */
3362 void route_map_counter_decrement(struct route_map
*map
)
3365 if (map
->use_count
<= 0)
3371 static const struct cmd_variable_handler rmap_var_handlers
[] = {
3372 {/* "route-map WORD" */
3373 .varname
= "route_map",
3374 .completions
= rmap_autocomplete
},
3375 {.tokenname
= "ROUTEMAP_NAME", .completions
= rmap_autocomplete
},
3376 {.tokenname
= "RMAP_NAME", .completions
= rmap_autocomplete
},
3377 {.completions
= NULL
}};
3379 /* Initialization of route map vector. */
3380 void route_map_init(void)
3384 /* Make vector for match and set. */
3385 route_match_vec
= vector_init(1);
3386 route_set_vec
= vector_init(1);
3387 route_map_master_hash
=
3388 hash_create_size(8, route_map_hash_key_make
, route_map_hash_cmp
,
3389 "Route Map Master Hash");
3391 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++)
3392 route_map_dep_hash
[i
] = hash_create_size(
3393 8, route_map_dep_hash_make_key
, route_map_dep_hash_cmp
,
3394 "Route Map Dep Hash");
3396 cmd_variable_handler_register(rmap_var_handlers
);
3400 /* Install route map top node. */
3401 install_node(&rmap_node
, route_map_config_write
);
3403 install_node(&rmap_debug_node
, rmap_config_write_debug
);
3405 /* Install route map commands. */
3406 install_default(RMAP_NODE
);
3407 install_element(CONFIG_NODE
, &route_map_cmd
);
3408 install_element(CONFIG_NODE
, &no_route_map_cmd
);
3409 install_element(CONFIG_NODE
, &no_route_map_all_cmd
);
3411 install_element(CONFIG_NODE
, &debug_rmap_cmd
);
3412 install_element(CONFIG_NODE
, &no_debug_rmap_cmd
);
3414 /* Install the on-match stuff */
3415 install_element(RMAP_NODE
, &route_map_cmd
);
3416 install_element(RMAP_NODE
, &rmap_onmatch_next_cmd
);
3417 install_element(RMAP_NODE
, &no_rmap_onmatch_next_cmd
);
3418 install_element(RMAP_NODE
, &rmap_onmatch_goto_cmd
);
3419 install_element(RMAP_NODE
, &no_rmap_onmatch_goto_cmd
);
3420 install_element(RMAP_NODE
, &rmap_continue_cmd
);
3421 install_element(RMAP_NODE
, &no_rmap_continue_cmd
);
3423 /* Install the continue stuff (ALIAS of on-match). */
3425 /* Install the call stuff. */
3426 install_element(RMAP_NODE
, &rmap_call_cmd
);
3427 install_element(RMAP_NODE
, &no_rmap_call_cmd
);
3429 /* Install description commands. */
3430 install_element(RMAP_NODE
, &rmap_description_cmd
);
3431 install_element(RMAP_NODE
, &no_rmap_description_cmd
);
3433 /* Install show command */
3434 install_element(ENABLE_NODE
, &rmap_clear_counters_cmd
);
3436 install_element(ENABLE_NODE
, &rmap_show_name_cmd
);
3437 install_element(ENABLE_NODE
, &rmap_show_unused_cmd
);
3439 install_element(ENABLE_NODE
, &debug_rmap_cmd
);
3440 install_element(ENABLE_NODE
, &no_debug_rmap_cmd
);
3442 install_element(RMAP_NODE
, &match_interface_cmd
);
3443 install_element(RMAP_NODE
, &no_match_interface_cmd
);
3445 install_element(RMAP_NODE
, &match_ip_address_cmd
);
3446 install_element(RMAP_NODE
, &no_match_ip_address_cmd
);
3448 install_element(RMAP_NODE
, &match_ip_address_prefix_list_cmd
);
3449 install_element(RMAP_NODE
, &no_match_ip_address_prefix_list_cmd
);
3451 install_element(RMAP_NODE
, &match_ip_next_hop_cmd
);
3452 install_element(RMAP_NODE
, &no_match_ip_next_hop_cmd
);
3454 install_element(RMAP_NODE
, &match_ip_next_hop_prefix_list_cmd
);
3455 install_element(RMAP_NODE
, &no_match_ip_next_hop_prefix_list_cmd
);
3457 install_element(RMAP_NODE
, &match_ip_next_hop_type_cmd
);
3458 install_element(RMAP_NODE
, &no_match_ip_next_hop_type_cmd
);
3460 install_element(RMAP_NODE
, &match_ipv6_address_cmd
);
3461 install_element(RMAP_NODE
, &no_match_ipv6_address_cmd
);
3463 install_element(RMAP_NODE
, &match_ipv6_address_prefix_list_cmd
);
3464 install_element(RMAP_NODE
, &no_match_ipv6_address_prefix_list_cmd
);
3466 install_element(RMAP_NODE
, &match_ipv6_next_hop_type_cmd
);
3467 install_element(RMAP_NODE
, &no_match_ipv6_next_hop_type_cmd
);
3469 install_element(RMAP_NODE
, &match_metric_cmd
);
3470 install_element(RMAP_NODE
, &no_match_metric_cmd
);
3472 install_element(RMAP_NODE
, &match_tag_cmd
);
3473 install_element(RMAP_NODE
, &no_match_tag_cmd
);
3475 install_element(RMAP_NODE
, &set_ip_nexthop_cmd
);
3476 install_element(RMAP_NODE
, &no_set_ip_nexthop_cmd
);
3478 install_element(RMAP_NODE
, &set_ipv6_nexthop_local_cmd
);
3479 install_element(RMAP_NODE
, &no_set_ipv6_nexthop_local_cmd
);
3481 install_element(RMAP_NODE
, &set_metric_cmd
);
3482 install_element(RMAP_NODE
, &no_set_metric_cmd
);
3484 install_element(RMAP_NODE
, &set_tag_cmd
);
3485 install_element(RMAP_NODE
, &no_set_tag_cmd
);