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 ipv6next-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_result_str(route_map_result_t res
)
948 static int route_map_empty(struct route_map
*map
)
950 if (map
->head
== NULL
&& map
->tail
== NULL
)
957 static void vty_show_route_map_entry(struct vty
*vty
, struct route_map
*map
)
959 struct route_map_index
*index
;
960 struct route_map_rule
*rule
;
962 vty_out(vty
, "route-map: %s Invoked: %" PRIu64
"\n",
963 map
->name
, map
->applied
);
965 for (index
= map
->head
; index
; index
= index
->next
) {
966 vty_out(vty
, " %s, sequence %d Invoked %" PRIu64
"\n",
967 route_map_type_str(index
->type
), index
->pref
,
971 if (index
->description
)
972 vty_out(vty
, " Description:\n %s\n",
976 vty_out(vty
, " Match clauses:\n");
977 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
978 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
981 vty_out(vty
, " Set clauses:\n");
982 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
983 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
987 vty_out(vty
, " Call clause:\n");
989 vty_out(vty
, " Call %s\n", index
->nextrm
);
992 vty_out(vty
, " Action:\n");
993 if (index
->exitpolicy
== RMAP_GOTO
)
994 vty_out(vty
, " Goto %d\n", index
->nextpref
);
995 else if (index
->exitpolicy
== RMAP_NEXT
)
996 vty_out(vty
, " Continue to next entry\n");
997 else if (index
->exitpolicy
== RMAP_EXIT
)
998 vty_out(vty
, " Exit routemap\n");
1002 static int sort_route_map(const void **map1
, const void **map2
)
1004 const struct route_map
*m1
= *map1
;
1005 const struct route_map
*m2
= *map2
;
1007 return strcmp(m1
->name
, m2
->name
);
1010 static int vty_show_route_map(struct vty
*vty
, const char *name
)
1012 struct route_map
*map
;
1014 vty_out(vty
, "%s:\n", frr_protonameinst
);
1017 map
= route_map_lookup_by_name(name
);
1020 vty_show_route_map_entry(vty
, map
);
1023 vty_out(vty
, "%s: 'route-map %s' not found\n",
1024 frr_protonameinst
, name
);
1029 struct list
*maplist
= list_new();
1030 struct listnode
*ln
;
1032 for (map
= route_map_master
.head
; map
; map
= map
->next
)
1033 listnode_add(maplist
, map
);
1035 list_sort(maplist
, sort_route_map
);
1037 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
1038 vty_show_route_map_entry(vty
, map
);
1040 list_delete(&maplist
);
1045 /* Unused route map details */
1046 static int vty_show_unused_route_map(struct vty
*vty
)
1048 struct list
*maplist
= list_new();
1049 struct listnode
*ln
;
1050 struct route_map
*map
;
1052 for (map
= route_map_master
.head
; map
; map
= map
->next
) {
1053 /* If use_count is zero, No protocol is using this routemap.
1054 * so adding to the list.
1056 if (!map
->use_count
)
1057 listnode_add(maplist
, map
);
1060 if (maplist
->count
> 0) {
1061 vty_out(vty
, "\n%s:\n", frr_protonameinst
);
1062 list_sort(maplist
, sort_route_map
);
1064 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
1065 vty_show_route_map_entry(vty
, map
);
1067 vty_out(vty
, "\n%s: None\n", frr_protonameinst
);
1070 list_delete(&maplist
);
1074 /* New route map allocation. Please note route map's name must be
1076 static struct route_map_index
*route_map_index_new(void)
1078 struct route_map_index
*new;
1080 new = XCALLOC(MTYPE_ROUTE_MAP_INDEX
, sizeof(struct route_map_index
));
1081 new->exitpolicy
= RMAP_EXIT
; /* Default to Cisco-style */
1082 QOBJ_REG(new, route_map_index
);
1086 /* Free route map index. */
1087 static void route_map_index_delete(struct route_map_index
*index
, int notify
)
1089 struct route_map_rule
*rule
;
1094 zlog_debug("Deleting route-map %s sequence %d",
1095 index
->map
->name
, index
->pref
);
1097 /* Free route match. */
1098 while ((rule
= index
->match_list
.head
) != NULL
)
1099 route_map_rule_delete(&index
->match_list
, rule
);
1101 /* Free route set. */
1102 while ((rule
= index
->set_list
.head
) != NULL
)
1103 route_map_rule_delete(&index
->set_list
, rule
);
1105 /* Remove index from route map list. */
1107 index
->next
->prev
= index
->prev
;
1109 index
->map
->tail
= index
->prev
;
1112 index
->prev
->next
= index
->next
;
1114 index
->map
->head
= index
->next
;
1116 /* Free 'char *nextrm' if not NULL */
1117 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
1119 /* Execute event hook. */
1120 if (route_map_master
.event_hook
&& notify
) {
1121 (*route_map_master
.event_hook
)(index
->map
->name
);
1122 route_map_notify_dependencies(index
->map
->name
,
1123 RMAP_EVENT_CALL_ADDED
);
1125 XFREE(MTYPE_ROUTE_MAP_INDEX
, index
);
1128 /* Lookup index from route map. */
1129 static struct route_map_index
*route_map_index_lookup(struct route_map
*map
,
1130 enum route_map_type type
,
1133 struct route_map_index
*index
;
1135 for (index
= map
->head
; index
; index
= index
->next
)
1136 if ((index
->type
== type
|| type
== RMAP_ANY
)
1137 && index
->pref
== pref
)
1142 /* Add new index to route map. */
1143 static struct route_map_index
*
1144 route_map_index_add(struct route_map
*map
, enum route_map_type type
, int pref
)
1146 struct route_map_index
*index
;
1147 struct route_map_index
*point
;
1149 /* Allocate new route map inex. */
1150 index
= route_map_index_new();
1155 /* Compare preference. */
1156 for (point
= map
->head
; point
; point
= point
->next
)
1157 if (point
->pref
>= pref
)
1160 if (map
->head
== NULL
) {
1161 map
->head
= map
->tail
= index
;
1162 } else if (point
== NULL
) {
1163 index
->prev
= map
->tail
;
1164 map
->tail
->next
= index
;
1166 } else if (point
== map
->head
) {
1167 index
->next
= map
->head
;
1168 map
->head
->prev
= index
;
1171 index
->next
= point
;
1172 index
->prev
= point
->prev
;
1174 point
->prev
->next
= index
;
1175 point
->prev
= index
;
1178 /* Execute event hook. */
1179 if (route_map_master
.event_hook
) {
1180 (*route_map_master
.event_hook
)(map
->name
);
1181 route_map_notify_dependencies(map
->name
, RMAP_EVENT_CALL_ADDED
);
1185 zlog_debug("Route-map %s add sequence %d, type: %s",
1186 map
->name
, pref
, route_map_type_str(type
));
1191 /* Get route map index. */
1192 static struct route_map_index
*
1193 route_map_index_get(struct route_map
*map
, enum route_map_type type
, int pref
)
1195 struct route_map_index
*index
;
1197 index
= route_map_index_lookup(map
, RMAP_ANY
, pref
);
1198 if (index
&& index
->type
!= type
) {
1199 /* Delete index from route map. */
1200 route_map_index_delete(index
, 1);
1204 index
= route_map_index_add(map
, type
, pref
);
1208 /* New route map rule */
1209 static struct route_map_rule
*route_map_rule_new(void)
1211 struct route_map_rule
*new;
1213 new = XCALLOC(MTYPE_ROUTE_MAP_RULE
, sizeof(struct route_map_rule
));
1217 /* Install rule command to the match list. */
1218 void route_map_install_match(struct route_map_rule_cmd
*cmd
)
1220 vector_set(route_match_vec
, cmd
);
1223 /* Install rule command to the set list. */
1224 void route_map_install_set(struct route_map_rule_cmd
*cmd
)
1226 vector_set(route_set_vec
, cmd
);
1229 /* Lookup rule command from match list. */
1230 static struct route_map_rule_cmd
*route_map_lookup_match(const char *name
)
1233 struct route_map_rule_cmd
*rule
;
1235 for (i
= 0; i
< vector_active(route_match_vec
); i
++)
1236 if ((rule
= vector_slot(route_match_vec
, i
)) != NULL
)
1237 if (strcmp(rule
->str
, name
) == 0)
1242 /* Lookup rule command from set list. */
1243 static struct route_map_rule_cmd
*route_map_lookup_set(const char *name
)
1246 struct route_map_rule_cmd
*rule
;
1248 for (i
= 0; i
< vector_active(route_set_vec
); i
++)
1249 if ((rule
= vector_slot(route_set_vec
, i
)) != NULL
)
1250 if (strcmp(rule
->str
, name
) == 0)
1255 /* Add match and set rule to rule list. */
1256 static void route_map_rule_add(struct route_map_rule_list
*list
,
1257 struct route_map_rule
*rule
)
1260 rule
->prev
= list
->tail
;
1262 list
->tail
->next
= rule
;
1268 /* Delete rule from rule list. */
1269 static void route_map_rule_delete(struct route_map_rule_list
*list
,
1270 struct route_map_rule
*rule
)
1272 if (rule
->cmd
->func_free
)
1273 (*rule
->cmd
->func_free
)(rule
->value
);
1275 XFREE(MTYPE_ROUTE_MAP_RULE_STR
, rule
->rule_str
);
1278 rule
->next
->prev
= rule
->prev
;
1280 list
->tail
= rule
->prev
;
1282 rule
->prev
->next
= rule
->next
;
1284 list
->head
= rule
->next
;
1286 XFREE(MTYPE_ROUTE_MAP_RULE
, rule
);
1289 /* strcmp wrapper function which don't crush even argument is NULL. */
1290 static int rulecmp(const char *dst
, const char *src
)
1301 return strcmp(dst
, src
);
1306 /* Use this to return the already specified argument for this match. This is
1307 * useful to get the specified argument with a route map match rule when the
1308 * rule is being deleted and the argument is not provided.
1310 const char *route_map_get_match_arg(struct route_map_index
*index
,
1311 const char *match_name
)
1313 struct route_map_rule
*rule
;
1314 struct route_map_rule_cmd
*cmd
;
1316 /* First lookup rule for add match statement. */
1317 cmd
= route_map_lookup_match(match_name
);
1321 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1322 if (rule
->cmd
== cmd
&& rule
->rule_str
!= NULL
)
1323 return (rule
->rule_str
);
1328 static route_map_event_t
get_route_map_delete_event(route_map_event_t type
)
1331 case RMAP_EVENT_CALL_ADDED
:
1332 return RMAP_EVENT_CALL_DELETED
;
1333 case RMAP_EVENT_PLIST_ADDED
:
1334 return RMAP_EVENT_PLIST_DELETED
;
1335 case RMAP_EVENT_CLIST_ADDED
:
1336 return RMAP_EVENT_CLIST_DELETED
;
1337 case RMAP_EVENT_ECLIST_ADDED
:
1338 return RMAP_EVENT_ECLIST_DELETED
;
1339 case RMAP_EVENT_LLIST_ADDED
:
1340 return RMAP_EVENT_LLIST_DELETED
;
1341 case RMAP_EVENT_ASLIST_ADDED
:
1342 return RMAP_EVENT_ASLIST_DELETED
;
1343 case RMAP_EVENT_FILTER_ADDED
:
1344 return RMAP_EVENT_FILTER_DELETED
;
1345 case RMAP_EVENT_SET_ADDED
:
1346 case RMAP_EVENT_SET_DELETED
:
1347 case RMAP_EVENT_SET_REPLACED
:
1348 case RMAP_EVENT_MATCH_ADDED
:
1349 case RMAP_EVENT_MATCH_DELETED
:
1350 case RMAP_EVENT_MATCH_REPLACED
:
1351 case RMAP_EVENT_INDEX_ADDED
:
1352 case RMAP_EVENT_INDEX_DELETED
:
1353 case RMAP_EVENT_CALL_DELETED
:
1354 case RMAP_EVENT_PLIST_DELETED
:
1355 case RMAP_EVENT_CLIST_DELETED
:
1356 case RMAP_EVENT_ECLIST_DELETED
:
1357 case RMAP_EVENT_LLIST_DELETED
:
1358 case RMAP_EVENT_ASLIST_DELETED
:
1359 case RMAP_EVENT_FILTER_DELETED
:
1360 /* This function returns the appropriate 'deleted' event type
1361 * for every 'added' event type passed to this function.
1362 * This is done only for named entities used in the
1363 * route-map match commands.
1364 * This function is not to be invoked for any of the other event
1372 * Return to make c happy but if we get here something has gone
1373 * terribly terribly wrong, so yes this return makes no sense.
1375 return RMAP_EVENT_CALL_ADDED
;
1378 /* Add match statement to route map. */
1379 int route_map_add_match(struct route_map_index
*index
, const char *match_name
,
1380 const char *match_arg
, route_map_event_t type
)
1382 struct route_map_rule
*rule
;
1383 struct route_map_rule
*next
;
1384 struct route_map_rule_cmd
*cmd
;
1386 int8_t delete_rmap_event_type
= 0;
1388 /* First lookup rule for add match statement. */
1389 cmd
= route_map_lookup_match(match_name
);
1391 return RMAP_RULE_MISSING
;
1393 /* Next call compile function for this match statement. */
1394 if (cmd
->func_compile
) {
1395 compile
= (*cmd
->func_compile
)(match_arg
);
1396 if (compile
== NULL
)
1397 return RMAP_COMPILE_ERROR
;
1401 /* If argument is completely same ignore it. */
1402 for (rule
= index
->match_list
.head
; rule
; rule
= next
) {
1404 if (rule
->cmd
== cmd
) {
1405 /* If the configured route-map match rule is exactly
1406 * the same as the existing configuration then,
1407 * ignore the duplicate configuration.
1409 if (strcmp(match_arg
, rule
->rule_str
) == 0) {
1411 (*cmd
->func_free
)(compile
);
1413 return RMAP_DUPLICATE_RULE
;
1416 /* Remove the dependency of the route-map on the rule
1417 * that is being replaced.
1419 if (type
>= RMAP_EVENT_CALL_ADDED
) {
1420 delete_rmap_event_type
=
1421 get_route_map_delete_event(type
);
1422 route_map_upd8_dependency(
1423 delete_rmap_event_type
,
1428 route_map_rule_delete(&index
->match_list
, rule
);
1432 /* Add new route map match rule. */
1433 rule
= route_map_rule_new();
1435 rule
->value
= compile
;
1437 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, match_arg
);
1439 rule
->rule_str
= NULL
;
1441 /* Add new route match rule to linked list. */
1442 route_map_rule_add(&index
->match_list
, rule
);
1444 /* Execute event hook. */
1445 if (route_map_master
.event_hook
) {
1446 (*route_map_master
.event_hook
)(index
->map
->name
);
1447 route_map_notify_dependencies(index
->map
->name
,
1448 RMAP_EVENT_CALL_ADDED
);
1451 return RMAP_COMPILE_SUCCESS
;
1454 /* Delete specified route match rule. */
1455 int route_map_delete_match(struct route_map_index
*index
,
1456 const char *match_name
, const char *match_arg
)
1458 struct route_map_rule
*rule
;
1459 struct route_map_rule_cmd
*cmd
;
1461 cmd
= route_map_lookup_match(match_name
);
1465 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1466 if (rule
->cmd
== cmd
&& (rulecmp(rule
->rule_str
, match_arg
) == 0
1467 || match_arg
== NULL
)) {
1468 route_map_rule_delete(&index
->match_list
, rule
);
1469 /* Execute event hook. */
1470 if (route_map_master
.event_hook
) {
1471 (*route_map_master
.event_hook
)(index
->map
->name
);
1472 route_map_notify_dependencies(
1474 RMAP_EVENT_CALL_ADDED
);
1478 /* Can't find matched rule. */
1482 /* Add route-map set statement to the route map. */
1483 int route_map_add_set(struct route_map_index
*index
, const char *set_name
,
1484 const char *set_arg
)
1486 struct route_map_rule
*rule
;
1487 struct route_map_rule
*next
;
1488 struct route_map_rule_cmd
*cmd
;
1491 cmd
= route_map_lookup_set(set_name
);
1493 return RMAP_RULE_MISSING
;
1495 /* Next call compile function for this match statement. */
1496 if (cmd
->func_compile
) {
1497 compile
= (*cmd
->func_compile
)(set_arg
);
1498 if (compile
== NULL
)
1499 return RMAP_COMPILE_ERROR
;
1503 /* Add by WJL. if old set command of same kind exist, delete it first
1504 to ensure only one set command of same kind exist under a
1506 for (rule
= index
->set_list
.head
; rule
; rule
= next
) {
1508 if (rule
->cmd
== cmd
)
1509 route_map_rule_delete(&index
->set_list
, rule
);
1512 /* Add new route map match rule. */
1513 rule
= route_map_rule_new();
1515 rule
->value
= compile
;
1517 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, set_arg
);
1519 rule
->rule_str
= NULL
;
1521 /* Add new route match rule to linked list. */
1522 route_map_rule_add(&index
->set_list
, rule
);
1524 /* Execute event hook. */
1525 if (route_map_master
.event_hook
) {
1526 (*route_map_master
.event_hook
)(index
->map
->name
);
1527 route_map_notify_dependencies(index
->map
->name
,
1528 RMAP_EVENT_CALL_ADDED
);
1530 return RMAP_COMPILE_SUCCESS
;
1533 /* Delete route map set rule. */
1534 int route_map_delete_set(struct route_map_index
*index
, const char *set_name
,
1535 const char *set_arg
)
1537 struct route_map_rule
*rule
;
1538 struct route_map_rule_cmd
*cmd
;
1540 cmd
= route_map_lookup_set(set_name
);
1544 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
1545 if ((rule
->cmd
== cmd
) && (rulecmp(rule
->rule_str
, set_arg
) == 0
1546 || set_arg
== NULL
)) {
1547 route_map_rule_delete(&index
->set_list
, rule
);
1548 /* Execute event hook. */
1549 if (route_map_master
.event_hook
) {
1550 (*route_map_master
.event_hook
)(index
->map
->name
);
1551 route_map_notify_dependencies(
1553 RMAP_EVENT_CALL_ADDED
);
1557 /* Can't find matched rule. */
1561 /* Apply route map's each index to the object.
1563 The matrix for a route-map looks like this:
1564 (note, this includes the description for the "NEXT"
1565 and "GOTO" frobs now
1569 permit action | cont
1571 ------------------+---------------
1577 -Apply Set statements, accept route
1578 -If Call statement is present jump to the specified route-map, if it
1579 denies the route we finish.
1580 -If NEXT is specified, goto NEXT statement
1581 -If GOTO is specified, goto the first clause where pref > nextpref
1582 -If nothing is specified, do as Cisco and finish
1584 -Route is denied by route-map.
1588 If we get no matches after we've processed all updates, then the route
1591 Some notes on the new "CALL", "NEXT" and "GOTO"
1592 call WORD - If this clause is matched, then the set statements
1593 are executed and then we jump to route-map 'WORD'. If
1594 this route-map denies the route, we finish, in other
1596 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
1597 on-match next - If this clause is matched, then the set statements
1598 are executed and then we drop through to the next clause
1599 on-match goto n - If this clause is matched, then the set statments
1600 are executed and then we goto the nth clause, or the
1601 first clause greater than this. In order to ensure
1602 route-maps *always* exit, you cannot jump backwards.
1605 We need to make sure our route-map processing matches the above
1608 static route_map_result_t
1609 route_map_apply_match(struct route_map_rule_list
*match_list
,
1610 const struct prefix
*prefix
, route_map_object_t type
,
1613 route_map_result_t ret
= RMAP_NOMATCH
;
1614 struct route_map_rule
*match
;
1617 /* Check all match rule and if there is no match rule, go to the
1619 if (!match_list
->head
)
1622 for (match
= match_list
->head
; match
; match
= match
->next
) {
1623 /* Try each match statement in turn, If any do not
1625 RMAP_MATCH, return, otherwise continue on to next
1627 statement. All match statements must match for
1630 ret
= (*match
->cmd
->func_apply
)(match
->value
, prefix
,
1632 if (ret
!= RMAP_MATCH
)
1639 /* Apply route map to the object. */
1640 route_map_result_t
route_map_apply(struct route_map
*map
,
1641 const struct prefix
*prefix
,
1642 route_map_object_t type
, void *object
)
1644 static int recursion
= 0;
1646 struct route_map_index
*index
;
1647 struct route_map_rule
*set
;
1648 char buf
[PREFIX_STRLEN
];
1650 if (recursion
> RMAP_RECURSION_LIMIT
) {
1652 EC_LIB_RMAP_RECURSION_LIMIT
,
1653 "route-map recursion limit (%d) reached, discarding route",
1654 RMAP_RECURSION_LIMIT
);
1656 return RMAP_DENYMATCH
;
1660 ret
= RMAP_DENYMATCH
;
1661 goto route_map_apply_end
;
1665 for (index
= map
->head
; index
; index
= index
->next
) {
1666 /* Apply this index. */
1668 ret
= route_map_apply_match(&index
->match_list
, prefix
, type
,
1672 zlog_debug("Route-map: %s, sequence: %d, prefix: %s, result: %s",
1673 map
->name
, index
->pref
,
1674 prefix2str(prefix
, buf
, sizeof(buf
)),
1675 route_map_result_str(ret
));
1678 /* Now we apply the matrix from above */
1679 if (ret
== RMAP_NOMATCH
)
1680 /* 'cont' from matrix - continue to next route-map
1683 else if (ret
== RMAP_MATCH
) {
1684 if (index
->type
== RMAP_PERMIT
)
1687 /* permit+match must execute sets */
1688 for (set
= index
->set_list
.head
; set
;
1690 ret
= (*set
->cmd
->func_apply
)(
1691 set
->value
, prefix
, type
,
1694 /* Call another route-map if available */
1695 if (index
->nextrm
) {
1696 struct route_map
*nextrm
=
1697 route_map_lookup_by_name(
1700 if (nextrm
) /* Target route-map found,
1704 ret
= route_map_apply(
1705 nextrm
, prefix
, type
,
1710 /* If nextrm returned 'deny', finish. */
1711 if (ret
== RMAP_DENYMATCH
)
1712 goto route_map_apply_end
;
1715 switch (index
->exitpolicy
) {
1717 goto route_map_apply_end
;
1721 /* Find the next clause to jump to */
1722 struct route_map_index
*next
=
1724 int nextpref
= index
->nextpref
;
1726 while (next
&& next
->pref
< nextpref
) {
1731 /* No clauses match! */
1732 goto route_map_apply_end
;
1736 } else if (index
->type
== RMAP_DENY
)
1739 ret
= RMAP_DENYMATCH
;
1740 goto route_map_apply_end
;
1744 /* Finally route-map does not match at all. */
1745 ret
= RMAP_DENYMATCH
;
1747 route_map_apply_end
:
1749 zlog_debug("Route-map: %s, prefix: %s, result: %s",
1750 (map
? map
->name
: "null"),
1751 prefix2str(prefix
, buf
, sizeof(buf
)),
1752 route_map_result_str(ret
));
1758 void route_map_add_hook(void (*func
)(const char *))
1760 route_map_master
.add_hook
= func
;
1763 void route_map_delete_hook(void (*func
)(const char *))
1765 route_map_master
.delete_hook
= func
;
1768 void route_map_event_hook(void (*func
)(const char *name
))
1770 route_map_master
.event_hook
= func
;
1773 /* Routines for route map dependency lists and dependency processing */
1774 static bool route_map_rmap_hash_cmp(const void *p1
, const void *p2
)
1776 return strcmp(((const struct route_map_dep_data
*)p1
)->rname
,
1777 ((const struct route_map_dep_data
*)p2
)->rname
)
1781 static bool route_map_dep_hash_cmp(const void *p1
, const void *p2
)
1784 return (strcmp(((const struct route_map_dep
*)p1
)->dep_name
,
1789 static void route_map_clear_reference(struct hash_bucket
*bucket
, void *arg
)
1791 struct route_map_dep
*dep
= bucket
->data
;
1792 struct route_map_dep_data
*dep_data
= NULL
, tmp_dep_data
;
1795 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
1796 tmp_dep_data
.rname
= arg
;
1797 dep_data
= hash_release(dep
->dep_rmap_hash
,
1800 XFREE(MTYPE_ROUTE_MAP_NAME
, dep_data
->rname
);
1801 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, dep_data
);
1803 if (!dep
->dep_rmap_hash
->count
) {
1804 dep
= hash_release(dep
->this_hash
,
1805 (void *)dep
->dep_name
);
1806 hash_free(dep
->dep_rmap_hash
);
1807 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
1808 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
1813 static void route_map_clear_all_references(char *rmap_name
)
1817 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
1818 hash_iterate(route_map_dep_hash
[i
], route_map_clear_reference
,
1823 static unsigned int route_map_dep_data_hash_make_key(const void *p
)
1825 const struct route_map_dep_data
*dep_data
= p
;
1827 return string_hash_make(dep_data
->rname
);
1830 static void *route_map_dep_hash_alloc(void *p
)
1832 char *dep_name
= (char *)p
;
1833 struct route_map_dep
*dep_entry
;
1835 dep_entry
= XCALLOC(MTYPE_ROUTE_MAP_DEP
, sizeof(struct route_map_dep
));
1836 dep_entry
->dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1837 dep_entry
->dep_rmap_hash
=
1838 hash_create_size(8, route_map_dep_data_hash_make_key
,
1839 route_map_rmap_hash_cmp
, "Route Map Dep Hash");
1840 dep_entry
->this_hash
= NULL
;
1845 static void *route_map_name_hash_alloc(void *p
)
1847 struct route_map_dep_data
*dep_data
= NULL
, *tmp_dep_data
= NULL
;
1849 dep_data
= XCALLOC(MTYPE_ROUTE_MAP_DEP_DATA
,
1850 sizeof(struct route_map_dep_data
));
1852 dep_data
->rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, tmp_dep_data
->rname
);
1856 static unsigned int route_map_dep_hash_make_key(const void *p
)
1858 return (string_hash_make((char *)p
));
1861 static void route_map_print_dependency(struct hash_bucket
*bucket
, void *data
)
1863 struct route_map_dep_data
*dep_data
= bucket
->data
;
1864 char *rmap_name
= dep_data
->rname
;
1865 char *dep_name
= data
;
1867 zlog_debug("%s: Dependency for %s: %s", __FUNCTION__
, dep_name
,
1871 static int route_map_dep_update(struct hash
*dephash
, const char *dep_name
,
1872 const char *rmap_name
, route_map_event_t type
)
1874 struct route_map_dep
*dep
= NULL
;
1875 char *dname
, *rname
;
1877 struct route_map_dep_data
*dep_data
= NULL
, *ret_dep_data
= NULL
;
1878 struct route_map_dep_data tmp_dep_data
;
1880 dname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1881 rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
1884 case RMAP_EVENT_PLIST_ADDED
:
1885 case RMAP_EVENT_CLIST_ADDED
:
1886 case RMAP_EVENT_ECLIST_ADDED
:
1887 case RMAP_EVENT_ASLIST_ADDED
:
1888 case RMAP_EVENT_LLIST_ADDED
:
1889 case RMAP_EVENT_CALL_ADDED
:
1890 case RMAP_EVENT_FILTER_ADDED
:
1892 zlog_debug("Adding dependency for filter %s in route-map %s",
1893 dep_name
, rmap_name
);
1894 dep
= (struct route_map_dep
*)hash_get(
1895 dephash
, dname
, route_map_dep_hash_alloc
);
1901 if (!dep
->this_hash
)
1902 dep
->this_hash
= dephash
;
1904 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
1905 tmp_dep_data
.rname
= rname
;
1906 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
1908 dep_data
= hash_get(dep
->dep_rmap_hash
, &tmp_dep_data
,
1909 route_map_name_hash_alloc
);
1913 case RMAP_EVENT_PLIST_DELETED
:
1914 case RMAP_EVENT_CLIST_DELETED
:
1915 case RMAP_EVENT_ECLIST_DELETED
:
1916 case RMAP_EVENT_ASLIST_DELETED
:
1917 case RMAP_EVENT_LLIST_DELETED
:
1918 case RMAP_EVENT_CALL_DELETED
:
1919 case RMAP_EVENT_FILTER_DELETED
:
1921 zlog_debug("Deleting dependency for filter %s in route-map %s",
1922 dep_name
, rmap_name
);
1923 dep
= (struct route_map_dep
*)hash_get(dephash
, dname
, NULL
);
1928 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
1929 tmp_dep_data
.rname
= rname
;
1930 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
1933 if (!dep_data
->refcnt
) {
1934 ret_dep_data
= hash_release(dep
->dep_rmap_hash
,
1937 XFREE(MTYPE_ROUTE_MAP_NAME
,
1938 ret_dep_data
->rname
);
1939 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, ret_dep_data
);
1943 if (!dep
->dep_rmap_hash
->count
) {
1944 dep
= hash_release(dephash
, dname
);
1945 hash_free(dep
->dep_rmap_hash
);
1946 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
1947 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
1951 case RMAP_EVENT_SET_ADDED
:
1952 case RMAP_EVENT_SET_DELETED
:
1953 case RMAP_EVENT_SET_REPLACED
:
1954 case RMAP_EVENT_MATCH_ADDED
:
1955 case RMAP_EVENT_MATCH_DELETED
:
1956 case RMAP_EVENT_MATCH_REPLACED
:
1957 case RMAP_EVENT_INDEX_ADDED
:
1958 case RMAP_EVENT_INDEX_DELETED
:
1964 hash_iterate(dep
->dep_rmap_hash
,
1965 route_map_print_dependency
, dname
);
1969 XFREE(MTYPE_ROUTE_MAP_NAME
, rname
);
1970 XFREE(MTYPE_ROUTE_MAP_NAME
, dname
);
1974 static struct hash
*route_map_get_dep_hash(route_map_event_t event
)
1976 struct hash
*upd8_hash
= NULL
;
1979 case RMAP_EVENT_PLIST_ADDED
:
1980 case RMAP_EVENT_PLIST_DELETED
:
1981 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_PLIST
];
1983 case RMAP_EVENT_CLIST_ADDED
:
1984 case RMAP_EVENT_CLIST_DELETED
:
1985 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_CLIST
];
1987 case RMAP_EVENT_ECLIST_ADDED
:
1988 case RMAP_EVENT_ECLIST_DELETED
:
1989 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ECLIST
];
1991 case RMAP_EVENT_ASLIST_ADDED
:
1992 case RMAP_EVENT_ASLIST_DELETED
:
1993 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ASPATH
];
1995 case RMAP_EVENT_LLIST_ADDED
:
1996 case RMAP_EVENT_LLIST_DELETED
:
1997 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_LCLIST
];
1999 case RMAP_EVENT_CALL_ADDED
:
2000 case RMAP_EVENT_CALL_DELETED
:
2001 case RMAP_EVENT_MATCH_ADDED
:
2002 case RMAP_EVENT_MATCH_DELETED
:
2003 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_RMAP
];
2005 case RMAP_EVENT_FILTER_ADDED
:
2006 case RMAP_EVENT_FILTER_DELETED
:
2007 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_FILTER
];
2010 * Should we actually be ignoring these?
2011 * I am not sure but at this point in time, let
2012 * us get them into this switch and we can peel
2013 * them into the appropriate place in the future
2015 case RMAP_EVENT_SET_ADDED
:
2016 case RMAP_EVENT_SET_DELETED
:
2017 case RMAP_EVENT_SET_REPLACED
:
2018 case RMAP_EVENT_MATCH_REPLACED
:
2019 case RMAP_EVENT_INDEX_ADDED
:
2020 case RMAP_EVENT_INDEX_DELETED
:
2027 static void route_map_process_dependency(struct hash_bucket
*bucket
, void *data
)
2029 struct route_map_dep_data
*dep_data
= NULL
;
2030 char *rmap_name
= NULL
;
2032 dep_data
= bucket
->data
;
2033 rmap_name
= dep_data
->rname
;
2036 zlog_debug("Notifying %s of dependency", rmap_name
);
2037 if (route_map_master
.event_hook
)
2038 (*route_map_master
.event_hook
)(rmap_name
);
2041 void route_map_upd8_dependency(route_map_event_t type
, const char *arg
,
2042 const char *rmap_name
)
2044 struct hash
*upd8_hash
= NULL
;
2046 if ((upd8_hash
= route_map_get_dep_hash(type
))) {
2047 route_map_dep_update(upd8_hash
, arg
, rmap_name
, type
);
2049 if (type
== RMAP_EVENT_CALL_ADDED
) {
2051 if (route_map_master
.add_hook
)
2052 (*route_map_master
.add_hook
)(rmap_name
);
2053 } else if (type
== RMAP_EVENT_CALL_DELETED
) {
2055 if (route_map_master
.delete_hook
)
2056 (*route_map_master
.delete_hook
)(rmap_name
);
2061 void route_map_notify_dependencies(const char *affected_name
,
2062 route_map_event_t event
)
2064 struct route_map_dep
*dep
;
2065 struct hash
*upd8_hash
;
2071 name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, affected_name
);
2073 if ((upd8_hash
= route_map_get_dep_hash(event
)) == NULL
) {
2074 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
2078 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, name
, NULL
);
2080 if (!dep
->this_hash
)
2081 dep
->this_hash
= upd8_hash
;
2084 zlog_debug("Filter %s updated", dep
->dep_name
);
2085 hash_iterate(dep
->dep_rmap_hash
, route_map_process_dependency
,
2089 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
2093 /* VTY related functions. */
2094 DEFUN (match_interface
,
2095 match_interface_cmd
,
2096 "match interface WORD",
2098 "match first hop interface of route\n"
2102 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2104 if (rmap_match_set_hook
.match_interface
)
2105 return rmap_match_set_hook
.match_interface(
2106 vty
, index
, "interface", argv
[idx_word
]->arg
,
2107 RMAP_EVENT_MATCH_ADDED
);
2111 DEFUN (no_match_interface
,
2112 no_match_interface_cmd
,
2113 "no match interface [WORD]",
2116 "Match first hop interface of route\n"
2119 char *iface
= (argc
== 4) ? argv
[3]->arg
: NULL
;
2120 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2122 if (rmap_match_set_hook
.no_match_interface
)
2123 return rmap_match_set_hook
.no_match_interface(
2124 vty
, index
, "interface", iface
,
2125 RMAP_EVENT_MATCH_DELETED
);
2130 DEFUN (match_ip_address
,
2131 match_ip_address_cmd
,
2132 "match ip address <(1-199)|(1300-2699)|WORD>",
2135 "Match address of route\n"
2136 "IP access-list number\n"
2137 "IP access-list number (expanded range)\n"
2138 "IP Access-list name\n")
2141 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2143 if (rmap_match_set_hook
.match_ip_address
)
2144 return rmap_match_set_hook
.match_ip_address(
2145 vty
, index
, "ip address", argv
[idx_acl
]->arg
,
2146 RMAP_EVENT_FILTER_ADDED
);
2151 DEFUN (no_match_ip_address
,
2152 no_match_ip_address_cmd
,
2153 "no match ip address [<(1-199)|(1300-2699)|WORD>]",
2157 "Match address of route\n"
2158 "IP access-list number\n"
2159 "IP access-list number (expanded range)\n"
2160 "IP Access-list name\n")
2163 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2165 if (rmap_match_set_hook
.no_match_ip_address
) {
2166 if (argc
<= idx_word
)
2167 return rmap_match_set_hook
.no_match_ip_address(
2168 vty
, index
, "ip address", NULL
,
2169 RMAP_EVENT_FILTER_DELETED
);
2170 return rmap_match_set_hook
.no_match_ip_address(
2171 vty
, index
, "ip address", argv
[idx_word
]->arg
,
2172 RMAP_EVENT_FILTER_DELETED
);
2178 DEFUN (match_ip_address_prefix_list
,
2179 match_ip_address_prefix_list_cmd
,
2180 "match ip address prefix-list WORD",
2183 "Match address of route\n"
2184 "Match entries of prefix-lists\n"
2185 "IP prefix-list name\n")
2188 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2190 if (rmap_match_set_hook
.match_ip_address_prefix_list
)
2191 return rmap_match_set_hook
.match_ip_address_prefix_list(
2192 vty
, index
, "ip address prefix-list",
2193 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
2198 DEFUN (no_match_ip_address_prefix_list
,
2199 no_match_ip_address_prefix_list_cmd
,
2200 "no match ip address prefix-list [WORD]",
2204 "Match address of route\n"
2205 "Match entries of prefix-lists\n"
2206 "IP prefix-list name\n")
2209 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2211 if (rmap_match_set_hook
.no_match_ip_address_prefix_list
) {
2212 if (argc
<= idx_word
)
2213 return rmap_match_set_hook
2214 .no_match_ip_address_prefix_list(
2215 vty
, index
, "ip address prefix-list",
2216 NULL
, RMAP_EVENT_PLIST_DELETED
);
2217 return rmap_match_set_hook
.no_match_ip_address_prefix_list(
2218 vty
, index
, "ip address prefix-list",
2219 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2225 DEFUN (match_ip_next_hop
,
2226 match_ip_next_hop_cmd
,
2227 "match ip next-hop <(1-199)|(1300-2699)|WORD>",
2230 "Match next-hop address of route\n"
2231 "IP access-list number\n"
2232 "IP access-list number (expanded range)\n"
2233 "IP Access-list name\n")
2236 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2238 if (rmap_match_set_hook
.match_ip_next_hop
)
2239 return rmap_match_set_hook
.match_ip_next_hop(
2240 vty
, index
, "ip next-hop", argv
[idx_acl
]->arg
,
2241 RMAP_EVENT_FILTER_ADDED
);
2246 DEFUN (no_match_ip_next_hop
,
2247 no_match_ip_next_hop_cmd
,
2248 "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
2252 "Match next-hop address of route\n"
2253 "IP access-list number\n"
2254 "IP access-list number (expanded range)\n"
2255 "IP Access-list name\n")
2258 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2260 if (rmap_match_set_hook
.no_match_ip_next_hop
) {
2261 if (argc
<= idx_word
)
2262 return rmap_match_set_hook
.no_match_ip_next_hop(
2263 vty
, index
, "ip next-hop", NULL
,
2264 RMAP_EVENT_FILTER_DELETED
);
2265 return rmap_match_set_hook
.no_match_ip_next_hop(
2266 vty
, index
, "ip next-hop", argv
[idx_word
]->arg
,
2267 RMAP_EVENT_FILTER_DELETED
);
2273 DEFUN (match_ip_next_hop_prefix_list
,
2274 match_ip_next_hop_prefix_list_cmd
,
2275 "match ip next-hop prefix-list WORD",
2278 "Match next-hop address of route\n"
2279 "Match entries of prefix-lists\n"
2280 "IP prefix-list name\n")
2283 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2285 if (rmap_match_set_hook
.match_ip_next_hop_prefix_list
)
2286 return rmap_match_set_hook
.match_ip_next_hop_prefix_list(
2287 vty
, index
, "ip next-hop prefix-list",
2288 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
2292 DEFUN (no_match_ip_next_hop_prefix_list
,
2293 no_match_ip_next_hop_prefix_list_cmd
,
2294 "no match ip next-hop prefix-list [WORD]",
2298 "Match next-hop address of route\n"
2299 "Match entries of prefix-lists\n"
2300 "IP prefix-list name\n")
2303 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2305 if (rmap_match_set_hook
.no_match_ip_next_hop
) {
2306 if (argc
<= idx_word
)
2307 return rmap_match_set_hook
.no_match_ip_next_hop(
2308 vty
, index
, "ip next-hop prefix-list", NULL
,
2309 RMAP_EVENT_PLIST_DELETED
);
2310 return rmap_match_set_hook
.no_match_ip_next_hop(
2311 vty
, index
, "ip next-hop prefix-list",
2312 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2317 DEFUN(match_ip_next_hop_type
, match_ip_next_hop_type_cmd
,
2318 "match ip next-hop type <blackhole>",
2320 "Match next-hop address of route\n"
2321 "Match entries by type\n"
2325 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2327 if (rmap_match_set_hook
.match_ip_next_hop_type
)
2328 return rmap_match_set_hook
.match_ip_next_hop_type(
2329 vty
, index
, "ip next-hop type", argv
[idx_word
]->arg
,
2330 RMAP_EVENT_MATCH_ADDED
);
2334 DEFUN(no_match_ip_next_hop_type
, no_match_ip_next_hop_type_cmd
,
2335 "no match ip next-hop type [<blackhole>]",
2336 NO_STR MATCH_STR IP_STR
2337 "Match next-hop address of route\n"
2338 "Match entries by type\n"
2342 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2344 if (rmap_match_set_hook
.no_match_ip_next_hop
) {
2345 if (argc
<= idx_word
)
2346 return rmap_match_set_hook
.no_match_ip_next_hop(
2347 vty
, index
, "ip next-hop type", NULL
,
2348 RMAP_EVENT_MATCH_DELETED
);
2349 return rmap_match_set_hook
.no_match_ip_next_hop(
2350 vty
, index
, "ip next-hop type", argv
[idx_word
]->arg
,
2351 RMAP_EVENT_MATCH_DELETED
);
2357 DEFUN (match_ipv6_address
,
2358 match_ipv6_address_cmd
,
2359 "match ipv6 address WORD",
2362 "Match IPv6 address of route\n"
2363 "IPv6 access-list name\n")
2366 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2368 if (rmap_match_set_hook
.match_ipv6_address
)
2369 return rmap_match_set_hook
.match_ipv6_address(
2370 vty
, index
, "ipv6 address", argv
[idx_word
]->arg
,
2371 RMAP_EVENT_FILTER_ADDED
);
2375 DEFUN (no_match_ipv6_address
,
2376 no_match_ipv6_address_cmd
,
2377 "no match ipv6 address WORD",
2381 "Match IPv6 address of route\n"
2382 "IPv6 access-list name\n")
2385 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2387 if (rmap_match_set_hook
.no_match_ipv6_address
)
2388 return rmap_match_set_hook
.no_match_ipv6_address(
2389 vty
, index
, "ipv6 address", argv
[idx_word
]->arg
,
2390 RMAP_EVENT_FILTER_DELETED
);
2395 DEFUN (match_ipv6_address_prefix_list
,
2396 match_ipv6_address_prefix_list_cmd
,
2397 "match ipv6 address prefix-list WORD",
2400 "Match address of route\n"
2401 "Match entries of prefix-lists\n"
2402 "IP prefix-list name\n")
2405 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2407 if (rmap_match_set_hook
.match_ipv6_address_prefix_list
)
2408 return rmap_match_set_hook
.match_ipv6_address_prefix_list(
2409 vty
, index
, "ipv6 address prefix-list",
2410 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
2414 DEFUN (no_match_ipv6_address_prefix_list
,
2415 no_match_ipv6_address_prefix_list_cmd
,
2416 "no match ipv6 address prefix-list WORD",
2420 "Match address of route\n"
2421 "Match entries of prefix-lists\n"
2422 "IP prefix-list name\n")
2425 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2427 if (rmap_match_set_hook
.no_match_ipv6_address_prefix_list
)
2428 return rmap_match_set_hook
.no_match_ipv6_address_prefix_list(
2429 vty
, index
, "ipv6 address prefix-list",
2430 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2434 DEFUN(match_ipv6_next_hop_type
, match_ipv6_next_hop_type_cmd
,
2435 "match ipv6 next-hop type <blackhole>",
2437 "Match address of route\n"
2438 "Match entries by type\n"
2442 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2444 if (rmap_match_set_hook
.match_ipv6_next_hop_type
)
2445 return rmap_match_set_hook
.match_ipv6_next_hop_type(
2446 vty
, index
, "ipv6 next-hop type", argv
[idx_word
]->arg
,
2447 RMAP_EVENT_MATCH_ADDED
);
2451 DEFUN(no_match_ipv6_next_hop_type
, no_match_ipv6_next_hop_type_cmd
,
2452 "no match ipv6 next-hop type [<blackhole>]",
2453 NO_STR MATCH_STR IPV6_STR
2454 "Match address of route\n"
2455 "Match entries by type\n"
2459 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2461 if (rmap_match_set_hook
.no_match_ipv6_next_hop_type
)
2462 return rmap_match_set_hook
.no_match_ipv6_next_hop_type(
2463 vty
, index
, "ipv6 next-hop type",
2464 (argc
<= idx_word
) ? NULL
: argv
[idx_word
]->arg
,
2465 RMAP_EVENT_MATCH_DELETED
);
2469 DEFUN (match_metric
,
2471 "match metric (0-4294967295)",
2473 "Match metric of route\n"
2477 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2479 if (rmap_match_set_hook
.match_metric
)
2480 return rmap_match_set_hook
.match_metric(vty
, index
, "metric",
2481 argv
[idx_number
]->arg
,
2482 RMAP_EVENT_MATCH_ADDED
);
2487 DEFUN (no_match_metric
,
2488 no_match_metric_cmd
,
2489 "no match metric [(0-4294967295)]",
2492 "Match metric of route\n"
2496 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2498 if (rmap_match_set_hook
.no_match_metric
) {
2499 if (argc
<= idx_number
)
2500 return rmap_match_set_hook
.no_match_metric(
2501 vty
, index
, "metric", NULL
,
2502 RMAP_EVENT_MATCH_DELETED
);
2503 return rmap_match_set_hook
.no_match_metric(
2504 vty
, index
, "metric", argv
[idx_number
]->arg
,
2505 RMAP_EVENT_MATCH_DELETED
);
2513 "match tag (1-4294967295)",
2515 "Match tag of route\n"
2519 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2521 if (rmap_match_set_hook
.match_tag
)
2522 return rmap_match_set_hook
.match_tag(vty
, index
, "tag",
2523 argv
[idx_number
]->arg
,
2524 RMAP_EVENT_MATCH_ADDED
);
2529 DEFUN (no_match_tag
,
2531 "no match tag [(1-4294967295)]",
2534 "Match tag of route\n"
2537 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2540 char *arg
= argv_find(argv
, argc
, "(1-4294967295)", &idx
)
2544 if (rmap_match_set_hook
.no_match_tag
)
2545 return rmap_match_set_hook
.no_match_tag(
2546 vty
, index
, "tag", arg
, RMAP_EVENT_MATCH_DELETED
);
2551 DEFUN (set_ip_nexthop
,
2553 "set ip next-hop A.B.C.D",
2556 "Next hop address\n"
2557 "IP address of next hop\n")
2562 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2564 ret
= str2sockunion(argv
[idx_ipv4
]->arg
, &su
);
2566 vty_out(vty
, "%% Malformed nexthop address\n");
2567 return CMD_WARNING_CONFIG_FAILED
;
2569 if (su
.sin
.sin_addr
.s_addr
== 0
2570 || IPV4_CLASS_DE(ntohl(su
.sin
.sin_addr
.s_addr
))) {
2572 "%% nexthop address cannot be 0.0.0.0, multicast or reserved\n");
2573 return CMD_WARNING_CONFIG_FAILED
;
2576 if (rmap_match_set_hook
.set_ip_nexthop
)
2577 return rmap_match_set_hook
.set_ip_nexthop(
2578 vty
, index
, "ip next-hop", argv
[idx_ipv4
]->arg
);
2583 DEFUN (no_set_ip_nexthop
,
2584 no_set_ip_nexthop_cmd
,
2585 "no set ip next-hop [A.B.C.D]",
2589 "Next hop address\n"
2590 "IP address of next hop\n")
2593 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2594 const char *arg
= NULL
;
2596 if (argv_find(argv
, argc
, "A.B.C.D", &idx
))
2597 arg
= argv
[idx
]->arg
;
2599 if (rmap_match_set_hook
.no_set_ip_nexthop
)
2600 return rmap_match_set_hook
.no_set_ip_nexthop(
2601 vty
, index
, "ip next-hop", arg
);
2607 DEFUN (set_ipv6_nexthop_local
,
2608 set_ipv6_nexthop_local_cmd
,
2609 "set ipv6 next-hop local X:X::X:X",
2612 "IPv6 next-hop address\n"
2613 "IPv6 local address\n"
2614 "IPv6 address of next hop\n")
2617 struct in6_addr addr
;
2619 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2621 ret
= inet_pton(AF_INET6
, argv
[idx_ipv6
]->arg
, &addr
);
2623 vty_out(vty
, "%% Malformed nexthop address\n");
2624 return CMD_WARNING_CONFIG_FAILED
;
2626 if (!IN6_IS_ADDR_LINKLOCAL(&addr
)) {
2627 vty_out(vty
, "%% Invalid link-local nexthop address\n");
2628 return CMD_WARNING_CONFIG_FAILED
;
2631 if (rmap_match_set_hook
.set_ipv6_nexthop_local
)
2632 return rmap_match_set_hook
.set_ipv6_nexthop_local(
2633 vty
, index
, "ipv6 next-hop local", argv
[idx_ipv6
]->arg
);
2638 DEFUN (no_set_ipv6_nexthop_local
,
2639 no_set_ipv6_nexthop_local_cmd
,
2640 "no set ipv6 next-hop local [X:X::X:X]",
2644 "IPv6 next-hop address\n"
2645 "IPv6 local address\n"
2646 "IPv6 address of next hop\n")
2649 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2651 if (rmap_match_set_hook
.no_set_ipv6_nexthop_local
) {
2652 if (argc
<= idx_ipv6
)
2653 return rmap_match_set_hook
.no_set_ipv6_nexthop_local(
2654 vty
, index
, "ipv6 next-hop local", NULL
);
2655 return rmap_match_set_hook
.no_set_ipv6_nexthop_local(
2656 vty
, index
, "ipv6 next-hop local", argv
[5]->arg
);
2663 "set metric <(0-4294967295)|rtt|+rtt|-rtt|+metric|-metric>",
2665 "Metric value for destination routing protocol\n"
2667 "Assign round trip time\n"
2668 "Add round trip time\n"
2669 "Subtract round trip time\n"
2671 "Subtract metric\n")
2674 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2676 const char *pass
= (argv
[idx_number
]->type
== RANGE_TKN
)
2677 ? argv
[idx_number
]->arg
2678 : argv
[idx_number
]->text
;
2680 if (rmap_match_set_hook
.set_metric
)
2681 return rmap_match_set_hook
.set_metric(vty
, index
, "metric",
2687 DEFUN (no_set_metric
,
2689 "no set metric [(0-4294967295)]",
2692 "Metric value for destination routing protocol\n"
2696 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2698 if (rmap_match_set_hook
.no_set_metric
) {
2699 if (argc
<= idx_number
)
2700 return rmap_match_set_hook
.no_set_metric(
2701 vty
, index
, "metric", NULL
);
2702 return rmap_match_set_hook
.no_set_metric(vty
, index
, "metric",
2703 argv
[idx_number
]->arg
);
2711 "set tag (1-4294967295)",
2713 "Tag value for routing protocol\n"
2716 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2719 if (rmap_match_set_hook
.set_tag
)
2720 return rmap_match_set_hook
.set_tag(vty
, index
, "tag",
2721 argv
[idx_number
]->arg
);
2728 "no set tag [(1-4294967295)]",
2731 "Tag value for routing protocol\n"
2734 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2737 if (rmap_match_set_hook
.no_set_tag
) {
2738 if (argc
<= idx_number
)
2739 return rmap_match_set_hook
.no_set_tag(vty
, index
, "tag",
2741 return rmap_match_set_hook
.no_set_tag(vty
, index
, "tag",
2742 argv
[idx_number
]->arg
);
2748 DEFUN_NOSH (route_map
,
2750 "route-map WORD <deny|permit> (1-65535)",
2751 "Create route-map or enter route-map command mode\n"
2753 "Route map denies set operations\n"
2754 "Route map permits set operations\n"
2755 "Sequence to insert to/delete from existing route-map entry\n")
2758 int idx_permit_deny
= 2;
2760 struct route_map
*map
;
2761 struct route_map_index
*index
;
2762 char *endptr
= NULL
;
2764 argv
[idx_permit_deny
]->arg
[0] == 'p' ? RMAP_PERMIT
: RMAP_DENY
;
2765 unsigned long pref
= strtoul(argv
[idx_number
]->arg
, &endptr
, 10);
2766 const char *mapname
= argv
[idx_word
]->arg
;
2768 /* Get route map. */
2769 map
= route_map_get(mapname
);
2770 index
= route_map_index_get(map
, permit
, pref
);
2772 VTY_PUSH_CONTEXT(RMAP_NODE
, index
);
2776 DEFUN (no_route_map_all
,
2777 no_route_map_all_cmd
,
2778 "no route-map WORD",
2780 "Create route-map or enter route-map command mode\n"
2784 const char *mapname
= argv
[idx_word
]->arg
;
2785 struct route_map
*map
;
2787 map
= route_map_lookup_by_name(mapname
);
2789 vty_out(vty
, "%% Could not find route-map %s\n", mapname
);
2790 return CMD_WARNING_CONFIG_FAILED
;
2793 route_map_delete(map
);
2798 DEFUN (no_route_map
,
2800 "no route-map WORD <deny|permit> (1-65535)",
2802 "Create route-map or enter route-map command mode\n"
2804 "Route map denies set operations\n"
2805 "Route map permits set operations\n"
2806 "Sequence to insert to/delete from existing route-map entry\n")
2809 int idx_permit_deny
= 3;
2811 struct route_map
*map
;
2812 struct route_map_index
*index
;
2813 char *endptr
= NULL
;
2814 int permit
= strmatch(argv
[idx_permit_deny
]->text
, "permit")
2817 const char *prefstr
= argv
[idx_number
]->arg
;
2818 const char *mapname
= argv
[idx_word
]->arg
;
2819 unsigned long pref
= strtoul(prefstr
, &endptr
, 10);
2821 /* Existence check. */
2822 map
= route_map_lookup_by_name(mapname
);
2824 vty_out(vty
, "%% Could not find route-map %s\n", mapname
);
2825 return CMD_WARNING_CONFIG_FAILED
;
2828 /* Lookup route map index. */
2829 index
= route_map_index_lookup(map
, permit
, pref
);
2830 if (index
== NULL
) {
2831 vty_out(vty
, "%% Could not find route-map entry %s %s\n",
2833 return CMD_WARNING_CONFIG_FAILED
;
2836 /* Delete index from route map. */
2837 route_map_index_delete(index
, 1);
2839 /* If this route rule is the last one, delete route map itself. */
2840 if (route_map_empty(map
))
2841 route_map_delete(map
);
2846 DEFUN (rmap_onmatch_next
,
2847 rmap_onmatch_next_cmd
,
2849 "Exit policy on matches\n"
2852 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2855 if (index
->type
== RMAP_DENY
) {
2856 /* Under a deny clause, match means it's finished. No
2857 * need to set next */
2859 "on-match next not supported under route-map deny\n");
2860 return CMD_WARNING_CONFIG_FAILED
;
2862 index
->exitpolicy
= RMAP_NEXT
;
2867 DEFUN (no_rmap_onmatch_next
,
2868 no_rmap_onmatch_next_cmd
,
2871 "Exit policy on matches\n"
2874 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2877 index
->exitpolicy
= RMAP_EXIT
;
2882 DEFUN (rmap_onmatch_goto
,
2883 rmap_onmatch_goto_cmd
,
2884 "on-match goto (1-65535)",
2885 "Exit policy on matches\n"
2886 "Goto Clause number\n"
2890 char *num
= argv_find(argv
, argc
, "(1-65535)", &idx
) ? argv
[idx
]->arg
2893 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2897 if (index
->type
== RMAP_DENY
) {
2898 /* Under a deny clause, match means it's finished. No
2899 * need to go anywhere */
2901 "on-match goto not supported under route-map deny\n");
2902 return CMD_WARNING_CONFIG_FAILED
;
2906 d
= strtoul(num
, NULL
, 10);
2908 d
= index
->pref
+ 1;
2910 if (d
<= index
->pref
) {
2911 /* Can't allow you to do that, Dave */
2912 vty_out(vty
, "can't jump backwards in route-maps\n");
2913 return CMD_WARNING_CONFIG_FAILED
;
2915 index
->exitpolicy
= RMAP_GOTO
;
2916 index
->nextpref
= d
;
2922 DEFUN (no_rmap_onmatch_goto
,
2923 no_rmap_onmatch_goto_cmd
,
2926 "Exit policy on matches\n"
2927 "Goto Clause number\n")
2929 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2932 index
->exitpolicy
= RMAP_EXIT
;
2937 /* Cisco/GNU Zebra compatibility aliases */
2939 DEFUN (rmap_continue
,
2941 "continue (1-65535)",
2942 "Continue on a different entry within the route-map\n"
2943 "Route-map entry sequence number\n")
2945 return rmap_onmatch_goto(self
, vty
, argc
, argv
);
2949 DEFUN (no_rmap_continue
,
2950 no_rmap_continue_cmd
,
2951 "no continue [(1-65535)]",
2953 "Continue on a different entry within the route-map\n"
2954 "Route-map entry sequence number\n")
2956 return no_rmap_onmatch_goto(self
, vty
, argc
, argv
);
2960 DEFUN (rmap_show_name
,
2962 "show route-map [WORD]",
2964 "route-map information\n"
2968 const char *name
= (argc
== 3) ? argv
[idx_word
]->arg
: NULL
;
2969 return vty_show_route_map(vty
, name
);
2972 DEFUN (rmap_show_unused
,
2973 rmap_show_unused_cmd
,
2974 "show route-map-unused",
2976 "unused route-map information\n")
2978 return vty_show_unused_route_map(vty
);
2984 "Jump to another Route-Map after match+set\n"
2985 "Target route-map name\n")
2988 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2989 const char *rmap
= argv
[idx_word
]->arg
;
2993 /* If "call" is invoked with the same route-map name as
2994 * the one previously configured then, ignore the duplicate
2997 if (index
->nextrm
&& (strcmp(index
->nextrm
, rmap
) == 0))
3000 if (index
->nextrm
) {
3001 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED
,
3002 index
->nextrm
, index
->map
->name
);
3003 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
3005 index
->nextrm
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap
);
3007 /* Execute event hook. */
3008 route_map_upd8_dependency(RMAP_EVENT_CALL_ADDED
, index
->nextrm
,
3013 DEFUN (no_rmap_call
,
3017 "Jump to another Route-Map after match+set\n")
3019 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
3021 if (index
->nextrm
) {
3022 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED
,
3023 index
->nextrm
, index
->map
->name
);
3024 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
3025 index
->nextrm
= NULL
;
3031 DEFUN (rmap_description
,
3032 rmap_description_cmd
,
3033 "description LINE...",
3034 "Route-map comment\n"
3035 "Comment describing this route-map rule\n")
3038 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
3041 if (index
->description
)
3042 XFREE(MTYPE_TMP
, index
->description
);
3043 index
->description
= argv_concat(argv
, argc
, idx_line
);
3048 DEFUN (no_rmap_description
,
3049 no_rmap_description_cmd
,
3052 "Route-map comment\n")
3054 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
3057 if (index
->description
)
3058 XFREE(MTYPE_TMP
, index
->description
);
3059 index
->description
= NULL
;
3068 "Debug option set for route-maps\n")
3074 DEFUN (no_debug_rmap
,
3076 "no debug route-map",
3079 "Debug option set for route-maps\n")
3086 static struct cmd_node rmap_debug_node
= {RMAP_DEBUG_NODE
, "", 1};
3088 /* Configuration write function. */
3089 static int route_map_config_write(struct vty
*vty
)
3091 struct route_map
*map
;
3092 struct route_map_index
*index
;
3093 struct route_map_rule
*rule
;
3097 for (map
= route_map_master
.head
; map
; map
= map
->next
)
3098 for (index
= map
->head
; index
; index
= index
->next
) {
3100 vty_out(vty
, "!\n");
3104 vty_out(vty
, "route-map %s %s %d\n", map
->name
,
3105 route_map_type_str(index
->type
), index
->pref
);
3107 if (index
->description
)
3108 vty_out(vty
, " description %s\n",
3109 index
->description
);
3111 for (rule
= index
->match_list
.head
; rule
;
3113 vty_out(vty
, " match %s %s\n", rule
->cmd
->str
,
3114 rule
->rule_str
? rule
->rule_str
: "");
3116 for (rule
= index
->set_list
.head
; rule
;
3118 vty_out(vty
, " set %s %s\n", rule
->cmd
->str
,
3119 rule
->rule_str
? rule
->rule_str
: "");
3121 vty_out(vty
, " call %s\n", index
->nextrm
);
3122 if (index
->exitpolicy
== RMAP_GOTO
)
3123 vty_out(vty
, " on-match goto %d\n",
3125 if (index
->exitpolicy
== RMAP_NEXT
)
3126 vty_out(vty
, " on-match next\n");
3133 static int rmap_config_write_debug(struct vty
*vty
)
3138 vty_out(vty
, "debug route-map\n");
3145 /* Route map node structure. */
3146 static struct cmd_node rmap_node
= {RMAP_NODE
, "%s(config-route-map)# ", 1};
3148 /* Common route map rules */
3150 void *route_map_rule_tag_compile(const char *arg
)
3152 unsigned long int tmp
;
3157 tmp
= strtoul(arg
, &endptr
, 0);
3158 if (arg
[0] == '\0' || *endptr
!= '\0' || errno
|| tmp
> ROUTE_TAG_MAX
)
3161 tag
= XMALLOC(MTYPE_ROUTE_MAP_COMPILED
, sizeof(*tag
));
3167 void route_map_rule_tag_free(void *rule
)
3169 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
3172 void route_map_finish(void)
3176 vector_free(route_match_vec
);
3177 route_match_vec
= NULL
;
3178 vector_free(route_set_vec
);
3179 route_set_vec
= NULL
;
3182 * All protocols are setting these to NULL
3183 * by default on shutdown( route_map_finish )
3184 * Why are we making them do this work?
3186 route_map_master
.add_hook
= NULL
;
3187 route_map_master
.delete_hook
= NULL
;
3188 route_map_master
.event_hook
= NULL
;
3190 /* cleanup route_map */
3191 while (route_map_master
.head
) {
3192 struct route_map
*map
= route_map_master
.head
;
3193 map
->to_be_processed
= false;
3194 route_map_delete(map
);
3197 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
3198 hash_free(route_map_dep_hash
[i
]);
3199 route_map_dep_hash
[i
] = NULL
;
3202 hash_free(route_map_master_hash
);
3203 route_map_master_hash
= NULL
;
3206 static void rmap_autocomplete(vector comps
, struct cmd_token
*token
)
3208 struct route_map
*map
;
3210 for (map
= route_map_master
.head
; map
; map
= map
->next
)
3211 vector_set(comps
, XSTRDUP(MTYPE_COMPLETION
, map
->name
));
3214 /* Increment the use_count counter while attaching the route map */
3215 void route_map_counter_increment(struct route_map
*map
)
3221 /* Decrement the use_count counter while detaching the route map. */
3222 void route_map_counter_decrement(struct route_map
*map
)
3225 if (map
->use_count
<= 0)
3231 static const struct cmd_variable_handler rmap_var_handlers
[] = {
3232 {/* "route-map WORD" */
3233 .varname
= "route_map",
3234 .completions
= rmap_autocomplete
},
3235 {.tokenname
= "ROUTEMAP_NAME", .completions
= rmap_autocomplete
},
3236 {.tokenname
= "RMAP_NAME", .completions
= rmap_autocomplete
},
3237 {.completions
= NULL
}};
3239 /* Initialization of route map vector. */
3240 void route_map_init(void)
3244 /* Make vector for match and set. */
3245 route_match_vec
= vector_init(1);
3246 route_set_vec
= vector_init(1);
3247 route_map_master_hash
=
3248 hash_create_size(8, route_map_hash_key_make
, route_map_hash_cmp
,
3249 "Route Map Master Hash");
3251 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++)
3252 route_map_dep_hash
[i
] = hash_create_size(
3253 8, route_map_dep_hash_make_key
, route_map_dep_hash_cmp
,
3254 "Route Map Dep Hash");
3256 cmd_variable_handler_register(rmap_var_handlers
);
3260 /* Install route map top node. */
3261 install_node(&rmap_node
, route_map_config_write
);
3263 install_node(&rmap_debug_node
, rmap_config_write_debug
);
3265 /* Install route map commands. */
3266 install_default(RMAP_NODE
);
3267 install_element(CONFIG_NODE
, &route_map_cmd
);
3268 install_element(CONFIG_NODE
, &no_route_map_cmd
);
3269 install_element(CONFIG_NODE
, &no_route_map_all_cmd
);
3271 install_element(CONFIG_NODE
, &debug_rmap_cmd
);
3272 install_element(CONFIG_NODE
, &no_debug_rmap_cmd
);
3274 /* Install the on-match stuff */
3275 install_element(RMAP_NODE
, &route_map_cmd
);
3276 install_element(RMAP_NODE
, &rmap_onmatch_next_cmd
);
3277 install_element(RMAP_NODE
, &no_rmap_onmatch_next_cmd
);
3278 install_element(RMAP_NODE
, &rmap_onmatch_goto_cmd
);
3279 install_element(RMAP_NODE
, &no_rmap_onmatch_goto_cmd
);
3280 install_element(RMAP_NODE
, &rmap_continue_cmd
);
3281 install_element(RMAP_NODE
, &no_rmap_continue_cmd
);
3283 /* Install the continue stuff (ALIAS of on-match). */
3285 /* Install the call stuff. */
3286 install_element(RMAP_NODE
, &rmap_call_cmd
);
3287 install_element(RMAP_NODE
, &no_rmap_call_cmd
);
3289 /* Install description commands. */
3290 install_element(RMAP_NODE
, &rmap_description_cmd
);
3291 install_element(RMAP_NODE
, &no_rmap_description_cmd
);
3293 /* Install show command */
3294 install_element(ENABLE_NODE
, &rmap_show_name_cmd
);
3295 install_element(ENABLE_NODE
, &rmap_show_unused_cmd
);
3297 install_element(ENABLE_NODE
, &debug_rmap_cmd
);
3298 install_element(ENABLE_NODE
, &no_debug_rmap_cmd
);
3300 install_element(RMAP_NODE
, &match_interface_cmd
);
3301 install_element(RMAP_NODE
, &no_match_interface_cmd
);
3303 install_element(RMAP_NODE
, &match_ip_address_cmd
);
3304 install_element(RMAP_NODE
, &no_match_ip_address_cmd
);
3306 install_element(RMAP_NODE
, &match_ip_address_prefix_list_cmd
);
3307 install_element(RMAP_NODE
, &no_match_ip_address_prefix_list_cmd
);
3309 install_element(RMAP_NODE
, &match_ip_next_hop_cmd
);
3310 install_element(RMAP_NODE
, &no_match_ip_next_hop_cmd
);
3312 install_element(RMAP_NODE
, &match_ip_next_hop_prefix_list_cmd
);
3313 install_element(RMAP_NODE
, &no_match_ip_next_hop_prefix_list_cmd
);
3315 install_element(RMAP_NODE
, &match_ip_next_hop_type_cmd
);
3316 install_element(RMAP_NODE
, &no_match_ip_next_hop_type_cmd
);
3318 install_element(RMAP_NODE
, &match_ipv6_address_cmd
);
3319 install_element(RMAP_NODE
, &no_match_ipv6_address_cmd
);
3321 install_element(RMAP_NODE
, &match_ipv6_address_prefix_list_cmd
);
3322 install_element(RMAP_NODE
, &no_match_ipv6_address_prefix_list_cmd
);
3324 install_element(RMAP_NODE
, &match_ipv6_next_hop_type_cmd
);
3325 install_element(RMAP_NODE
, &no_match_ipv6_next_hop_type_cmd
);
3327 install_element(RMAP_NODE
, &match_metric_cmd
);
3328 install_element(RMAP_NODE
, &no_match_metric_cmd
);
3330 install_element(RMAP_NODE
, &match_tag_cmd
);
3331 install_element(RMAP_NODE
, &no_match_tag_cmd
);
3333 install_element(RMAP_NODE
, &set_ip_nexthop_cmd
);
3334 install_element(RMAP_NODE
, &no_set_ip_nexthop_cmd
);
3336 install_element(RMAP_NODE
, &set_ipv6_nexthop_local_cmd
);
3337 install_element(RMAP_NODE
, &no_set_ipv6_nexthop_local_cmd
);
3339 install_element(RMAP_NODE
, &set_metric_cmd
);
3340 install_element(RMAP_NODE
, &no_set_metric_cmd
);
3342 install_element(RMAP_NODE
, &set_tag_cmd
);
3343 install_element(RMAP_NODE
, &no_set_tag_cmd
);