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 int rmap_debug
= 0;
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
);
745 /* this is supposed to be called post processing by
746 * the delete hook function. Don't invoke delete_hook
747 * again in this routine.
749 static void route_map_free_map(struct route_map
*map
)
751 struct route_map_list
*list
;
752 struct route_map_index
*index
;
757 while ((index
= map
->head
) != NULL
)
758 route_map_index_delete(index
, 0);
760 list
= &route_map_master
;
765 map
->next
->prev
= map
->prev
;
767 list
->tail
= map
->prev
;
770 map
->prev
->next
= map
->next
;
772 list
->head
= map
->next
;
774 hash_release(route_map_master_hash
, map
);
775 XFREE(MTYPE_ROUTE_MAP_NAME
, map
->name
);
776 XFREE(MTYPE_ROUTE_MAP
, map
);
779 /* Route map delete from list. */
780 static void route_map_delete(struct route_map
*map
)
782 struct route_map_index
*index
;
785 while ((index
= map
->head
) != NULL
)
786 route_map_index_delete(index
, 0);
791 /* Clear all dependencies */
792 route_map_clear_all_references(name
);
794 /* Execute deletion hook. */
795 if (route_map_master
.delete_hook
) {
796 (*route_map_master
.delete_hook
)(name
);
797 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_DELETED
);
800 if (!map
->to_be_processed
) {
801 route_map_free_map(map
);
805 /* Lookup route map by route map name string. */
806 struct route_map
*route_map_lookup_by_name(const char *name
)
808 struct route_map
*map
;
809 struct route_map tmp_map
;
814 // map.deleted is 0 via memset
815 memset(&tmp_map
, 0, sizeof(struct route_map
));
816 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
817 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
818 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
822 /* Simple helper to warn if route-map does not exist. */
823 struct route_map
*route_map_lookup_warn_noexist(struct vty
*vty
, const char *name
)
825 struct route_map
*route_map
= route_map_lookup_by_name(name
);
828 if (vty_shell_serv(vty
))
829 vty_out(vty
, "The route-map '%s' does not exist.\n", name
);
834 int route_map_mark_updated(const char *name
)
836 struct route_map
*map
;
838 struct route_map tmp_map
;
843 map
= route_map_lookup_by_name(name
);
845 /* If we did not find the routemap with deleted=false try again
849 memset(&tmp_map
, 0, sizeof(struct route_map
));
850 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
851 tmp_map
.deleted
= true;
852 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
853 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
857 map
->to_be_processed
= true;
864 static int route_map_clear_updated(struct route_map
*map
)
869 map
->to_be_processed
= false;
871 route_map_free_map(map
);
877 /* Lookup route map. If there isn't route map create one and return
879 static struct route_map
*route_map_get(const char *name
)
881 struct route_map
*map
;
883 map
= route_map_lookup_by_name(name
);
885 map
= route_map_add(name
);
890 void route_map_walk_update_list(void (*route_map_update_fn
)(char *name
))
892 struct route_map
*node
;
893 struct route_map
*nnode
= NULL
;
895 for (node
= route_map_master
.head
; node
; node
= nnode
) {
896 if (node
->to_be_processed
) {
897 /* DD: Should we add any thread yield code here */
898 route_map_update_fn(node
->name
);
900 route_map_clear_updated(node
);
906 /* Return route map's type string. */
907 static const char *route_map_type_str(enum route_map_type type
)
924 static int route_map_empty(struct route_map
*map
)
926 if (map
->head
== NULL
&& map
->tail
== NULL
)
933 static void vty_show_route_map_entry(struct vty
*vty
, struct route_map
*map
)
935 struct route_map_index
*index
;
936 struct route_map_rule
*rule
;
938 vty_out(vty
, "route-map: %s Invoked: %" PRIu64
"\n",
939 map
->name
, map
->applied
);
941 for (index
= map
->head
; index
; index
= index
->next
) {
942 vty_out(vty
, " %s, sequence %d Invoked %" PRIu64
"\n",
943 route_map_type_str(index
->type
), index
->pref
,
947 if (index
->description
)
948 vty_out(vty
, " Description:\n %s\n",
952 vty_out(vty
, " Match clauses:\n");
953 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
954 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
957 vty_out(vty
, " Set clauses:\n");
958 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
959 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
963 vty_out(vty
, " Call clause:\n");
965 vty_out(vty
, " Call %s\n", index
->nextrm
);
968 vty_out(vty
, " Action:\n");
969 if (index
->exitpolicy
== RMAP_GOTO
)
970 vty_out(vty
, " Goto %d\n", index
->nextpref
);
971 else if (index
->exitpolicy
== RMAP_NEXT
)
972 vty_out(vty
, " Continue to next entry\n");
973 else if (index
->exitpolicy
== RMAP_EXIT
)
974 vty_out(vty
, " Exit routemap\n");
978 static int sort_route_map(const void **map1
, const void **map2
)
980 const struct route_map
*m1
= *map1
;
981 const struct route_map
*m2
= *map2
;
983 return strcmp(m1
->name
, m2
->name
);
986 static int vty_show_route_map(struct vty
*vty
, const char *name
)
988 struct route_map
*map
;
990 vty_out(vty
, "%s:\n", frr_protonameinst
);
993 map
= route_map_lookup_by_name(name
);
996 vty_show_route_map_entry(vty
, map
);
999 vty_out(vty
, "%s: 'route-map %s' not found\n",
1000 frr_protonameinst
, name
);
1005 struct list
*maplist
= list_new();
1006 struct listnode
*ln
;
1008 for (map
= route_map_master
.head
; map
; map
= map
->next
)
1009 listnode_add(maplist
, map
);
1011 list_sort(maplist
, sort_route_map
);
1013 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
1014 vty_show_route_map_entry(vty
, map
);
1016 list_delete(&maplist
);
1021 /* Unused route map details */
1022 static int vty_show_unused_route_map(struct vty
*vty
)
1024 struct list
*maplist
= list_new();
1025 struct listnode
*ln
;
1026 struct route_map
*map
;
1028 for (map
= route_map_master
.head
; map
; map
= map
->next
) {
1029 /* If use_count is zero, No protocol is using this routemap.
1030 * so adding to the list.
1032 if (!map
->use_count
)
1033 listnode_add(maplist
, map
);
1036 if (maplist
->count
> 0) {
1037 vty_out(vty
, "\n%s:\n", frr_protonameinst
);
1038 list_sort(maplist
, sort_route_map
);
1040 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
1041 vty_show_route_map_entry(vty
, map
);
1043 vty_out(vty
, "\n%s: None\n", frr_protonameinst
);
1046 list_delete(&maplist
);
1050 /* New route map allocation. Please note route map's name must be
1052 static struct route_map_index
*route_map_index_new(void)
1054 struct route_map_index
*new;
1056 new = XCALLOC(MTYPE_ROUTE_MAP_INDEX
, sizeof(struct route_map_index
));
1057 new->exitpolicy
= RMAP_EXIT
; /* Default to Cisco-style */
1058 QOBJ_REG(new, route_map_index
);
1062 /* Free route map index. */
1063 static void route_map_index_delete(struct route_map_index
*index
, int notify
)
1065 struct route_map_rule
*rule
;
1069 /* Free route match. */
1070 while ((rule
= index
->match_list
.head
) != NULL
)
1071 route_map_rule_delete(&index
->match_list
, rule
);
1073 /* Free route set. */
1074 while ((rule
= index
->set_list
.head
) != NULL
)
1075 route_map_rule_delete(&index
->set_list
, rule
);
1077 /* Remove index from route map list. */
1079 index
->next
->prev
= index
->prev
;
1081 index
->map
->tail
= index
->prev
;
1084 index
->prev
->next
= index
->next
;
1086 index
->map
->head
= index
->next
;
1088 /* Free 'char *nextrm' if not NULL */
1089 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
1091 /* Execute event hook. */
1092 if (route_map_master
.event_hook
&& notify
) {
1093 (*route_map_master
.event_hook
)(index
->map
->name
);
1094 route_map_notify_dependencies(index
->map
->name
,
1095 RMAP_EVENT_CALL_ADDED
);
1097 XFREE(MTYPE_ROUTE_MAP_INDEX
, index
);
1100 /* Lookup index from route map. */
1101 static struct route_map_index
*route_map_index_lookup(struct route_map
*map
,
1102 enum route_map_type type
,
1105 struct route_map_index
*index
;
1107 for (index
= map
->head
; index
; index
= index
->next
)
1108 if ((index
->type
== type
|| type
== RMAP_ANY
)
1109 && index
->pref
== pref
)
1114 /* Add new index to route map. */
1115 static struct route_map_index
*
1116 route_map_index_add(struct route_map
*map
, enum route_map_type type
, int pref
)
1118 struct route_map_index
*index
;
1119 struct route_map_index
*point
;
1121 /* Allocate new route map inex. */
1122 index
= route_map_index_new();
1127 /* Compare preference. */
1128 for (point
= map
->head
; point
; point
= point
->next
)
1129 if (point
->pref
>= pref
)
1132 if (map
->head
== NULL
) {
1133 map
->head
= map
->tail
= index
;
1134 } else if (point
== NULL
) {
1135 index
->prev
= map
->tail
;
1136 map
->tail
->next
= index
;
1138 } else if (point
== map
->head
) {
1139 index
->next
= map
->head
;
1140 map
->head
->prev
= index
;
1143 index
->next
= point
;
1144 index
->prev
= point
->prev
;
1146 point
->prev
->next
= index
;
1147 point
->prev
= index
;
1150 /* Execute event hook. */
1151 if (route_map_master
.event_hook
) {
1152 (*route_map_master
.event_hook
)(map
->name
);
1153 route_map_notify_dependencies(map
->name
, RMAP_EVENT_CALL_ADDED
);
1158 /* Get route map index. */
1159 static struct route_map_index
*
1160 route_map_index_get(struct route_map
*map
, enum route_map_type type
, int pref
)
1162 struct route_map_index
*index
;
1164 index
= route_map_index_lookup(map
, RMAP_ANY
, pref
);
1165 if (index
&& index
->type
!= type
) {
1166 /* Delete index from route map. */
1167 route_map_index_delete(index
, 1);
1171 index
= route_map_index_add(map
, type
, pref
);
1175 /* New route map rule */
1176 static struct route_map_rule
*route_map_rule_new(void)
1178 struct route_map_rule
*new;
1180 new = XCALLOC(MTYPE_ROUTE_MAP_RULE
, sizeof(struct route_map_rule
));
1184 /* Install rule command to the match list. */
1185 void route_map_install_match(struct route_map_rule_cmd
*cmd
)
1187 vector_set(route_match_vec
, cmd
);
1190 /* Install rule command to the set list. */
1191 void route_map_install_set(struct route_map_rule_cmd
*cmd
)
1193 vector_set(route_set_vec
, cmd
);
1196 /* Lookup rule command from match list. */
1197 static struct route_map_rule_cmd
*route_map_lookup_match(const char *name
)
1200 struct route_map_rule_cmd
*rule
;
1202 for (i
= 0; i
< vector_active(route_match_vec
); i
++)
1203 if ((rule
= vector_slot(route_match_vec
, i
)) != NULL
)
1204 if (strcmp(rule
->str
, name
) == 0)
1209 /* Lookup rule command from set list. */
1210 static struct route_map_rule_cmd
*route_map_lookup_set(const char *name
)
1213 struct route_map_rule_cmd
*rule
;
1215 for (i
= 0; i
< vector_active(route_set_vec
); i
++)
1216 if ((rule
= vector_slot(route_set_vec
, i
)) != NULL
)
1217 if (strcmp(rule
->str
, name
) == 0)
1222 /* Add match and set rule to rule list. */
1223 static void route_map_rule_add(struct route_map_rule_list
*list
,
1224 struct route_map_rule
*rule
)
1227 rule
->prev
= list
->tail
;
1229 list
->tail
->next
= rule
;
1235 /* Delete rule from rule list. */
1236 static void route_map_rule_delete(struct route_map_rule_list
*list
,
1237 struct route_map_rule
*rule
)
1239 if (rule
->cmd
->func_free
)
1240 (*rule
->cmd
->func_free
)(rule
->value
);
1242 XFREE(MTYPE_ROUTE_MAP_RULE_STR
, rule
->rule_str
);
1245 rule
->next
->prev
= rule
->prev
;
1247 list
->tail
= rule
->prev
;
1249 rule
->prev
->next
= rule
->next
;
1251 list
->head
= rule
->next
;
1253 XFREE(MTYPE_ROUTE_MAP_RULE
, rule
);
1256 /* strcmp wrapper function which don't crush even argument is NULL. */
1257 static int rulecmp(const char *dst
, const char *src
)
1268 return strcmp(dst
, src
);
1273 /* Use this to return the already specified argument for this match. This is
1274 * useful to get the specified argument with a route map match rule when the
1275 * rule is being deleted and the argument is not provided.
1277 const char *route_map_get_match_arg(struct route_map_index
*index
,
1278 const char *match_name
)
1280 struct route_map_rule
*rule
;
1281 struct route_map_rule_cmd
*cmd
;
1283 /* First lookup rule for add match statement. */
1284 cmd
= route_map_lookup_match(match_name
);
1288 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1289 if (rule
->cmd
== cmd
&& rule
->rule_str
!= NULL
)
1290 return (rule
->rule_str
);
1295 static route_map_event_t
get_route_map_delete_event(route_map_event_t type
)
1298 case RMAP_EVENT_CALL_ADDED
:
1299 return RMAP_EVENT_CALL_DELETED
;
1300 case RMAP_EVENT_PLIST_ADDED
:
1301 return RMAP_EVENT_PLIST_DELETED
;
1302 case RMAP_EVENT_CLIST_ADDED
:
1303 return RMAP_EVENT_CLIST_DELETED
;
1304 case RMAP_EVENT_ECLIST_ADDED
:
1305 return RMAP_EVENT_ECLIST_DELETED
;
1306 case RMAP_EVENT_LLIST_ADDED
:
1307 return RMAP_EVENT_LLIST_DELETED
;
1308 case RMAP_EVENT_ASLIST_ADDED
:
1309 return RMAP_EVENT_ASLIST_DELETED
;
1310 case RMAP_EVENT_FILTER_ADDED
:
1311 return RMAP_EVENT_FILTER_DELETED
;
1312 case RMAP_EVENT_SET_ADDED
:
1313 case RMAP_EVENT_SET_DELETED
:
1314 case RMAP_EVENT_SET_REPLACED
:
1315 case RMAP_EVENT_MATCH_ADDED
:
1316 case RMAP_EVENT_MATCH_DELETED
:
1317 case RMAP_EVENT_MATCH_REPLACED
:
1318 case RMAP_EVENT_INDEX_ADDED
:
1319 case RMAP_EVENT_INDEX_DELETED
:
1320 case RMAP_EVENT_CALL_DELETED
:
1321 case RMAP_EVENT_PLIST_DELETED
:
1322 case RMAP_EVENT_CLIST_DELETED
:
1323 case RMAP_EVENT_ECLIST_DELETED
:
1324 case RMAP_EVENT_LLIST_DELETED
:
1325 case RMAP_EVENT_ASLIST_DELETED
:
1326 case RMAP_EVENT_FILTER_DELETED
:
1327 /* This function returns the appropriate 'deleted' event type
1328 * for every 'added' event type passed to this function.
1329 * This is done only for named entities used in the
1330 * route-map match commands.
1331 * This function is not to be invoked for any of the other event
1338 /* Add match statement to route map. */
1339 int route_map_add_match(struct route_map_index
*index
, const char *match_name
,
1340 const char *match_arg
, route_map_event_t type
)
1342 struct route_map_rule
*rule
;
1343 struct route_map_rule
*next
;
1344 struct route_map_rule_cmd
*cmd
;
1346 int8_t delete_rmap_event_type
= 0;
1348 /* First lookup rule for add match statement. */
1349 cmd
= route_map_lookup_match(match_name
);
1351 return RMAP_RULE_MISSING
;
1353 /* Next call compile function for this match statement. */
1354 if (cmd
->func_compile
) {
1355 compile
= (*cmd
->func_compile
)(match_arg
);
1356 if (compile
== NULL
)
1357 return RMAP_COMPILE_ERROR
;
1361 /* If argument is completely same ignore it. */
1362 for (rule
= index
->match_list
.head
; rule
; rule
= next
) {
1364 if (rule
->cmd
== cmd
) {
1365 /* If the configured route-map match rule is exactly
1366 * the same as the existing configuration then,
1367 * ignore the duplicate configuration.
1369 if (strcmp(match_arg
, rule
->rule_str
) == 0) {
1371 (*cmd
->func_free
)(compile
);
1373 return RMAP_DUPLICATE_RULE
;
1376 /* Remove the dependency of the route-map on the rule
1377 * that is being replaced.
1379 if (type
>= RMAP_EVENT_CALL_ADDED
) {
1380 delete_rmap_event_type
=
1381 get_route_map_delete_event(type
);
1382 route_map_upd8_dependency(
1383 delete_rmap_event_type
,
1388 route_map_rule_delete(&index
->match_list
, rule
);
1392 /* Add new route map match rule. */
1393 rule
= route_map_rule_new();
1395 rule
->value
= compile
;
1397 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, match_arg
);
1399 rule
->rule_str
= NULL
;
1401 /* Add new route match rule to linked list. */
1402 route_map_rule_add(&index
->match_list
, rule
);
1404 /* Execute event hook. */
1405 if (route_map_master
.event_hook
) {
1406 (*route_map_master
.event_hook
)(index
->map
->name
);
1407 route_map_notify_dependencies(index
->map
->name
,
1408 RMAP_EVENT_CALL_ADDED
);
1411 return RMAP_COMPILE_SUCCESS
;
1414 /* Delete specified route match rule. */
1415 int route_map_delete_match(struct route_map_index
*index
,
1416 const char *match_name
, const char *match_arg
)
1418 struct route_map_rule
*rule
;
1419 struct route_map_rule_cmd
*cmd
;
1421 cmd
= route_map_lookup_match(match_name
);
1425 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1426 if (rule
->cmd
== cmd
&& (rulecmp(rule
->rule_str
, match_arg
) == 0
1427 || match_arg
== NULL
)) {
1428 route_map_rule_delete(&index
->match_list
, rule
);
1429 /* Execute event hook. */
1430 if (route_map_master
.event_hook
) {
1431 (*route_map_master
.event_hook
)(index
->map
->name
);
1432 route_map_notify_dependencies(
1434 RMAP_EVENT_CALL_ADDED
);
1438 /* Can't find matched rule. */
1442 /* Add route-map set statement to the route map. */
1443 int route_map_add_set(struct route_map_index
*index
, const char *set_name
,
1444 const char *set_arg
)
1446 struct route_map_rule
*rule
;
1447 struct route_map_rule
*next
;
1448 struct route_map_rule_cmd
*cmd
;
1451 cmd
= route_map_lookup_set(set_name
);
1453 return RMAP_RULE_MISSING
;
1455 /* Next call compile function for this match statement. */
1456 if (cmd
->func_compile
) {
1457 compile
= (*cmd
->func_compile
)(set_arg
);
1458 if (compile
== NULL
)
1459 return RMAP_COMPILE_ERROR
;
1463 /* Add by WJL. if old set command of same kind exist, delete it first
1464 to ensure only one set command of same kind exist under a
1466 for (rule
= index
->set_list
.head
; rule
; rule
= next
) {
1468 if (rule
->cmd
== cmd
)
1469 route_map_rule_delete(&index
->set_list
, rule
);
1472 /* Add new route map match rule. */
1473 rule
= route_map_rule_new();
1475 rule
->value
= compile
;
1477 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, set_arg
);
1479 rule
->rule_str
= NULL
;
1481 /* Add new route match rule to linked list. */
1482 route_map_rule_add(&index
->set_list
, rule
);
1484 /* Execute event hook. */
1485 if (route_map_master
.event_hook
) {
1486 (*route_map_master
.event_hook
)(index
->map
->name
);
1487 route_map_notify_dependencies(index
->map
->name
,
1488 RMAP_EVENT_CALL_ADDED
);
1490 return RMAP_COMPILE_SUCCESS
;
1493 /* Delete route map set rule. */
1494 int route_map_delete_set(struct route_map_index
*index
, const char *set_name
,
1495 const char *set_arg
)
1497 struct route_map_rule
*rule
;
1498 struct route_map_rule_cmd
*cmd
;
1500 cmd
= route_map_lookup_set(set_name
);
1504 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
1505 if ((rule
->cmd
== cmd
) && (rulecmp(rule
->rule_str
, set_arg
) == 0
1506 || set_arg
== NULL
)) {
1507 route_map_rule_delete(&index
->set_list
, rule
);
1508 /* Execute event hook. */
1509 if (route_map_master
.event_hook
) {
1510 (*route_map_master
.event_hook
)(index
->map
->name
);
1511 route_map_notify_dependencies(
1513 RMAP_EVENT_CALL_ADDED
);
1517 /* Can't find matched rule. */
1521 /* Apply route map's each index to the object.
1523 The matrix for a route-map looks like this:
1524 (note, this includes the description for the "NEXT"
1525 and "GOTO" frobs now
1527 | Match | No Match | No op
1528 |-----------|--------------|-------
1529 permit | action | cont | cont.
1530 | | default:deny | default:permit
1531 -------------------+-----------------------
1532 | deny | cont | cont.
1533 deny | | default:deny | default:permit
1534 |-----------|--------------|--------
1537 -Apply Set statements, accept route
1538 -If Call statement is present jump to the specified route-map, if it
1539 denies the route we finish.
1540 -If NEXT is specified, goto NEXT statement
1541 -If GOTO is specified, goto the first clause where pref > nextpref
1542 -If nothing is specified, do as Cisco and finish
1544 -Route is denied by route-map.
1548 If we get no matches after we've processed all updates, then the route
1551 Some notes on the new "CALL", "NEXT" and "GOTO"
1552 call WORD - If this clause is matched, then the set statements
1553 are executed and then we jump to route-map 'WORD'. If
1554 this route-map denies the route, we finish, in other
1556 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
1557 on-match next - If this clause is matched, then the set statements
1558 are executed and then we drop through to the next clause
1559 on-match goto n - If this clause is matched, then the set statments
1560 are executed and then we goto the nth clause, or the
1561 first clause greater than this. In order to ensure
1562 route-maps *always* exit, you cannot jump backwards.
1565 We need to make sure our route-map processing matches the above
1568 static enum route_map_match_result_t
1569 route_map_apply_match(struct route_map_rule_list
*match_list
,
1570 const struct prefix
*prefix
, route_map_object_t type
,
1573 enum route_map_match_result_t ret
= RMAP_NOMATCH
;
1574 struct route_map_rule
*match
;
1577 /* Check all match rule and if there is no match rule, go to the
1579 if (!match_list
->head
)
1582 for (match
= match_list
->head
; match
; match
= match
->next
) {
1583 /* Try each match statement in turn, If any do not
1585 RMAP_MATCH, return, otherwise continue on to next
1587 statement. All match statements must match for
1590 ret
= (*match
->cmd
->func_apply
)(match
->value
, prefix
,
1592 if (ret
!= RMAP_MATCH
)
1599 /* Apply route map to the object. */
1600 route_map_result_t
route_map_apply(struct route_map
*map
,
1601 const struct prefix
*prefix
,
1602 route_map_object_t type
, void *object
)
1604 static int recursion
= 0;
1605 enum route_map_match_result_t match_ret
= RMAP_NOMATCH
;
1606 route_map_result_t ret
= 0;
1607 struct route_map_index
*index
;
1608 struct route_map_rule
*set
;
1610 if (recursion
> RMAP_RECURSION_LIMIT
) {
1612 EC_LIB_RMAP_RECURSION_LIMIT
,
1613 "route-map recursion limit (%d) reached, discarding route",
1614 RMAP_RECURSION_LIMIT
);
1616 return RMAP_DENYMATCH
;
1620 return RMAP_DENYMATCH
;
1623 for (index
= map
->head
; index
; index
= index
->next
) {
1624 /* Apply this index. */
1626 match_ret
= route_map_apply_match(&index
->match_list
, prefix
,
1629 /* Now we apply the matrix from above */
1630 if (match_ret
== RMAP_NOMATCH
|| match_ret
== RMAP_NOOP
)
1631 /* 'cont' from matrix - continue to next route-map
1634 else if (match_ret
== RMAP_MATCH
) {
1635 if (index
->type
== RMAP_PERMIT
)
1638 /* Match succeeded, rmap is of type permit */
1639 ret
= RMAP_PERMITMATCH
;
1641 /* permit+match must execute sets */
1642 for (set
= index
->set_list
.head
; set
;
1645 * We dont care abt the return value
1646 * for set cmd. Almost always,
1647 * RMAP_OKAY is returned. Rarely
1648 * do we see RMAP_ERROR
1650 match_ret
= (*set
->cmd
->func_apply
)(
1651 set
->value
, prefix
, type
,
1654 /* Call another route-map if available */
1655 if (index
->nextrm
) {
1656 struct route_map
*nextrm
=
1657 route_map_lookup_by_name(
1660 if (nextrm
) /* Target route-map found,
1664 ret
= route_map_apply(
1665 nextrm
, prefix
, type
,
1670 /* If nextrm returned 'deny', finish. */
1671 if (ret
== RMAP_DENYMATCH
)
1675 switch (index
->exitpolicy
) {
1681 /* Find the next clause to jump to */
1682 struct route_map_index
*next
=
1684 int nextpref
= index
->nextpref
;
1686 while (next
&& next
->pref
< nextpref
) {
1691 /* No clauses match! */
1696 } else if (index
->type
== RMAP_DENY
)
1699 return RMAP_DENYMATCH
;
1704 if (match_ret
== RMAP_NOOP
)
1705 return RMAP_PERMITMATCH
;
1707 /* Finally route-map does not match at all. */
1708 return RMAP_DENYMATCH
;
1711 void route_map_add_hook(void (*func
)(const char *))
1713 route_map_master
.add_hook
= func
;
1716 void route_map_delete_hook(void (*func
)(const char *))
1718 route_map_master
.delete_hook
= func
;
1721 void route_map_event_hook(void (*func
)(const char *name
))
1723 route_map_master
.event_hook
= func
;
1726 /* Routines for route map dependency lists and dependency processing */
1727 static bool route_map_rmap_hash_cmp(const void *p1
, const void *p2
)
1729 return strcmp(((const struct route_map_dep_data
*)p1
)->rname
,
1730 ((const struct route_map_dep_data
*)p2
)->rname
)
1734 static bool route_map_dep_hash_cmp(const void *p1
, const void *p2
)
1737 return (strcmp(((const struct route_map_dep
*)p1
)->dep_name
,
1742 static void route_map_clear_reference(struct hash_bucket
*bucket
, void *arg
)
1744 struct route_map_dep
*dep
= bucket
->data
;
1745 struct route_map_dep_data
*dep_data
= NULL
, tmp_dep_data
;
1748 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
1749 tmp_dep_data
.rname
= arg
;
1750 dep_data
= hash_release(dep
->dep_rmap_hash
,
1753 XFREE(MTYPE_ROUTE_MAP_NAME
, dep_data
->rname
);
1754 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, dep_data
);
1756 if (!dep
->dep_rmap_hash
->count
) {
1757 dep
= hash_release(dep
->this_hash
,
1758 (void *)dep
->dep_name
);
1759 hash_free(dep
->dep_rmap_hash
);
1760 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
1761 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
1766 static void route_map_clear_all_references(char *rmap_name
)
1770 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
1771 hash_iterate(route_map_dep_hash
[i
], route_map_clear_reference
,
1776 static unsigned int route_map_dep_data_hash_make_key(const void *p
)
1778 const struct route_map_dep_data
*dep_data
= p
;
1780 return string_hash_make(dep_data
->rname
);
1783 static void *route_map_dep_hash_alloc(void *p
)
1785 char *dep_name
= (char *)p
;
1786 struct route_map_dep
*dep_entry
;
1788 dep_entry
= XCALLOC(MTYPE_ROUTE_MAP_DEP
, sizeof(struct route_map_dep
));
1789 dep_entry
->dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1790 dep_entry
->dep_rmap_hash
=
1791 hash_create_size(8, route_map_dep_data_hash_make_key
,
1792 route_map_rmap_hash_cmp
, "Route Map Dep Hash");
1793 dep_entry
->this_hash
= NULL
;
1798 static void *route_map_name_hash_alloc(void *p
)
1800 struct route_map_dep_data
*dep_data
= NULL
, *tmp_dep_data
= NULL
;
1802 dep_data
= XCALLOC(MTYPE_ROUTE_MAP_DEP_DATA
,
1803 sizeof(struct route_map_dep_data
));
1805 dep_data
->rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, tmp_dep_data
->rname
);
1809 static unsigned int route_map_dep_hash_make_key(const void *p
)
1811 return (string_hash_make((char *)p
));
1814 static void route_map_print_dependency(struct hash_bucket
*bucket
, void *data
)
1816 struct route_map_dep_data
*dep_data
= bucket
->data
;
1817 char *rmap_name
= dep_data
->rname
;
1818 char *dep_name
= data
;
1820 zlog_debug("%s: Dependency for %s: %s", __FUNCTION__
, dep_name
,
1824 static int route_map_dep_update(struct hash
*dephash
, const char *dep_name
,
1825 const char *rmap_name
, route_map_event_t type
)
1827 struct route_map_dep
*dep
= NULL
;
1828 char *dname
, *rname
;
1830 struct route_map_dep_data
*dep_data
= NULL
, *ret_dep_data
= NULL
;
1831 struct route_map_dep_data tmp_dep_data
;
1833 dname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1834 rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
1837 case RMAP_EVENT_PLIST_ADDED
:
1838 case RMAP_EVENT_CLIST_ADDED
:
1839 case RMAP_EVENT_ECLIST_ADDED
:
1840 case RMAP_EVENT_ASLIST_ADDED
:
1841 case RMAP_EVENT_LLIST_ADDED
:
1842 case RMAP_EVENT_CALL_ADDED
:
1843 case RMAP_EVENT_FILTER_ADDED
:
1845 zlog_debug("%s: Adding dependency for %s in %s",
1846 __FUNCTION__
, dep_name
, rmap_name
);
1847 dep
= (struct route_map_dep
*)hash_get(
1848 dephash
, dname
, route_map_dep_hash_alloc
);
1854 if (!dep
->this_hash
)
1855 dep
->this_hash
= dephash
;
1857 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
1858 tmp_dep_data
.rname
= rname
;
1859 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
1861 dep_data
= hash_get(dep
->dep_rmap_hash
, &tmp_dep_data
,
1862 route_map_name_hash_alloc
);
1866 case RMAP_EVENT_PLIST_DELETED
:
1867 case RMAP_EVENT_CLIST_DELETED
:
1868 case RMAP_EVENT_ECLIST_DELETED
:
1869 case RMAP_EVENT_ASLIST_DELETED
:
1870 case RMAP_EVENT_LLIST_DELETED
:
1871 case RMAP_EVENT_CALL_DELETED
:
1872 case RMAP_EVENT_FILTER_DELETED
:
1874 zlog_debug("%s: Deleting dependency for %s in %s",
1875 __FUNCTION__
, dep_name
, rmap_name
);
1876 dep
= (struct route_map_dep
*)hash_get(dephash
, dname
, NULL
);
1881 memset(&tmp_dep_data
, 0, sizeof(struct route_map_dep_data
));
1882 tmp_dep_data
.rname
= rname
;
1883 dep_data
= hash_lookup(dep
->dep_rmap_hash
, &tmp_dep_data
);
1886 if (!dep_data
->refcnt
) {
1887 ret_dep_data
= hash_release(dep
->dep_rmap_hash
,
1890 XFREE(MTYPE_ROUTE_MAP_NAME
,
1891 ret_dep_data
->rname
);
1892 XFREE(MTYPE_ROUTE_MAP_DEP_DATA
, ret_dep_data
);
1896 if (!dep
->dep_rmap_hash
->count
) {
1897 dep
= hash_release(dephash
, dname
);
1898 hash_free(dep
->dep_rmap_hash
);
1899 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
1900 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
1904 case RMAP_EVENT_SET_ADDED
:
1905 case RMAP_EVENT_SET_DELETED
:
1906 case RMAP_EVENT_SET_REPLACED
:
1907 case RMAP_EVENT_MATCH_ADDED
:
1908 case RMAP_EVENT_MATCH_DELETED
:
1909 case RMAP_EVENT_MATCH_REPLACED
:
1910 case RMAP_EVENT_INDEX_ADDED
:
1911 case RMAP_EVENT_INDEX_DELETED
:
1917 hash_iterate(dep
->dep_rmap_hash
,
1918 route_map_print_dependency
, dname
);
1922 XFREE(MTYPE_ROUTE_MAP_NAME
, rname
);
1923 XFREE(MTYPE_ROUTE_MAP_NAME
, dname
);
1927 static struct hash
*route_map_get_dep_hash(route_map_event_t event
)
1929 struct hash
*upd8_hash
= NULL
;
1932 case RMAP_EVENT_PLIST_ADDED
:
1933 case RMAP_EVENT_PLIST_DELETED
:
1934 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_PLIST
];
1936 case RMAP_EVENT_CLIST_ADDED
:
1937 case RMAP_EVENT_CLIST_DELETED
:
1938 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_CLIST
];
1940 case RMAP_EVENT_ECLIST_ADDED
:
1941 case RMAP_EVENT_ECLIST_DELETED
:
1942 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ECLIST
];
1944 case RMAP_EVENT_ASLIST_ADDED
:
1945 case RMAP_EVENT_ASLIST_DELETED
:
1946 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ASPATH
];
1948 case RMAP_EVENT_LLIST_ADDED
:
1949 case RMAP_EVENT_LLIST_DELETED
:
1950 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_LCLIST
];
1952 case RMAP_EVENT_CALL_ADDED
:
1953 case RMAP_EVENT_CALL_DELETED
:
1954 case RMAP_EVENT_MATCH_ADDED
:
1955 case RMAP_EVENT_MATCH_DELETED
:
1956 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_RMAP
];
1958 case RMAP_EVENT_FILTER_ADDED
:
1959 case RMAP_EVENT_FILTER_DELETED
:
1960 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_FILTER
];
1963 * Should we actually be ignoring these?
1964 * I am not sure but at this point in time, let
1965 * us get them into this switch and we can peel
1966 * them into the appropriate place in the future
1968 case RMAP_EVENT_SET_ADDED
:
1969 case RMAP_EVENT_SET_DELETED
:
1970 case RMAP_EVENT_SET_REPLACED
:
1971 case RMAP_EVENT_MATCH_REPLACED
:
1972 case RMAP_EVENT_INDEX_ADDED
:
1973 case RMAP_EVENT_INDEX_DELETED
:
1980 static void route_map_process_dependency(struct hash_bucket
*bucket
, void *data
)
1982 struct route_map_dep_data
*dep_data
= NULL
;
1983 char *rmap_name
= NULL
;
1985 dep_data
= bucket
->data
;
1986 rmap_name
= dep_data
->rname
;
1989 zlog_debug("%s: Notifying %s of dependency",
1990 __FUNCTION__
, rmap_name
);
1991 if (route_map_master
.event_hook
)
1992 (*route_map_master
.event_hook
)(rmap_name
);
1995 void route_map_upd8_dependency(route_map_event_t type
, const char *arg
,
1996 const char *rmap_name
)
1998 struct hash
*upd8_hash
= NULL
;
2000 if ((upd8_hash
= route_map_get_dep_hash(type
))) {
2001 route_map_dep_update(upd8_hash
, arg
, rmap_name
, type
);
2003 if (type
== RMAP_EVENT_CALL_ADDED
) {
2005 if (route_map_master
.add_hook
)
2006 (*route_map_master
.add_hook
)(rmap_name
);
2007 } else if (type
== RMAP_EVENT_CALL_DELETED
) {
2009 if (route_map_master
.delete_hook
)
2010 (*route_map_master
.delete_hook
)(rmap_name
);
2015 void route_map_notify_dependencies(const char *affected_name
,
2016 route_map_event_t event
)
2018 struct route_map_dep
*dep
;
2019 struct hash
*upd8_hash
;
2025 name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, affected_name
);
2027 if ((upd8_hash
= route_map_get_dep_hash(event
)) == NULL
) {
2028 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
2032 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, name
, NULL
);
2034 if (!dep
->this_hash
)
2035 dep
->this_hash
= upd8_hash
;
2037 hash_iterate(dep
->dep_rmap_hash
, route_map_process_dependency
,
2041 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
2045 /* VTY related functions. */
2046 DEFUN (match_interface
,
2047 match_interface_cmd
,
2048 "match interface WORD",
2050 "match first hop interface of route\n"
2054 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2056 if (rmap_match_set_hook
.match_interface
)
2057 return rmap_match_set_hook
.match_interface(
2058 vty
, index
, "interface", argv
[idx_word
]->arg
,
2059 RMAP_EVENT_MATCH_ADDED
);
2063 DEFUN (no_match_interface
,
2064 no_match_interface_cmd
,
2065 "no match interface [WORD]",
2068 "Match first hop interface of route\n"
2071 char *iface
= (argc
== 4) ? argv
[3]->arg
: NULL
;
2072 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2074 if (rmap_match_set_hook
.no_match_interface
)
2075 return rmap_match_set_hook
.no_match_interface(
2076 vty
, index
, "interface", iface
,
2077 RMAP_EVENT_MATCH_DELETED
);
2082 DEFUN (match_ip_address
,
2083 match_ip_address_cmd
,
2084 "match ip address <(1-199)|(1300-2699)|WORD>",
2087 "Match address of route\n"
2088 "IP access-list number\n"
2089 "IP access-list number (expanded range)\n"
2090 "IP Access-list name\n")
2093 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2095 if (rmap_match_set_hook
.match_ip_address
)
2096 return rmap_match_set_hook
.match_ip_address(
2097 vty
, index
, "ip address", argv
[idx_acl
]->arg
,
2098 RMAP_EVENT_FILTER_ADDED
);
2103 DEFUN (no_match_ip_address
,
2104 no_match_ip_address_cmd
,
2105 "no match ip address [<(1-199)|(1300-2699)|WORD>]",
2109 "Match address of route\n"
2110 "IP access-list number\n"
2111 "IP access-list number (expanded range)\n"
2112 "IP Access-list name\n")
2115 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2117 if (rmap_match_set_hook
.no_match_ip_address
) {
2118 if (argc
<= idx_word
)
2119 return rmap_match_set_hook
.no_match_ip_address(
2120 vty
, index
, "ip address", NULL
,
2121 RMAP_EVENT_FILTER_DELETED
);
2122 return rmap_match_set_hook
.no_match_ip_address(
2123 vty
, index
, "ip address", argv
[idx_word
]->arg
,
2124 RMAP_EVENT_FILTER_DELETED
);
2130 DEFUN (match_ip_address_prefix_list
,
2131 match_ip_address_prefix_list_cmd
,
2132 "match ip address prefix-list WORD",
2135 "Match address of route\n"
2136 "Match entries of prefix-lists\n"
2137 "IP prefix-list name\n")
2140 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2142 if (rmap_match_set_hook
.match_ip_address_prefix_list
)
2143 return rmap_match_set_hook
.match_ip_address_prefix_list(
2144 vty
, index
, "ip address prefix-list",
2145 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
2150 DEFUN (no_match_ip_address_prefix_list
,
2151 no_match_ip_address_prefix_list_cmd
,
2152 "no match ip address prefix-list [WORD]",
2156 "Match address of route\n"
2157 "Match entries of prefix-lists\n"
2158 "IP prefix-list name\n")
2161 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2163 if (rmap_match_set_hook
.no_match_ip_address_prefix_list
) {
2164 if (argc
<= idx_word
)
2165 return rmap_match_set_hook
2166 .no_match_ip_address_prefix_list(
2167 vty
, index
, "ip address prefix-list",
2168 NULL
, RMAP_EVENT_PLIST_DELETED
);
2169 return rmap_match_set_hook
.no_match_ip_address_prefix_list(
2170 vty
, index
, "ip address prefix-list",
2171 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2177 DEFUN (match_ip_next_hop
,
2178 match_ip_next_hop_cmd
,
2179 "match ip next-hop <(1-199)|(1300-2699)|WORD>",
2182 "Match next-hop address of route\n"
2183 "IP access-list number\n"
2184 "IP access-list number (expanded range)\n"
2185 "IP Access-list name\n")
2188 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2190 if (rmap_match_set_hook
.match_ip_next_hop
)
2191 return rmap_match_set_hook
.match_ip_next_hop(
2192 vty
, index
, "ip next-hop", argv
[idx_acl
]->arg
,
2193 RMAP_EVENT_FILTER_ADDED
);
2198 DEFUN (no_match_ip_next_hop
,
2199 no_match_ip_next_hop_cmd
,
2200 "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
2204 "Match next-hop address of route\n"
2205 "IP access-list number\n"
2206 "IP access-list number (expanded range)\n"
2207 "IP Access-list name\n")
2210 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2212 if (rmap_match_set_hook
.no_match_ip_next_hop
) {
2213 if (argc
<= idx_word
)
2214 return rmap_match_set_hook
.no_match_ip_next_hop(
2215 vty
, index
, "ip next-hop", NULL
,
2216 RMAP_EVENT_FILTER_DELETED
);
2217 return rmap_match_set_hook
.no_match_ip_next_hop(
2218 vty
, index
, "ip next-hop", argv
[idx_word
]->arg
,
2219 RMAP_EVENT_FILTER_DELETED
);
2225 DEFUN (match_ip_next_hop_prefix_list
,
2226 match_ip_next_hop_prefix_list_cmd
,
2227 "match ip next-hop prefix-list WORD",
2230 "Match next-hop address of route\n"
2231 "Match entries of prefix-lists\n"
2232 "IP prefix-list name\n")
2235 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2237 if (rmap_match_set_hook
.match_ip_next_hop_prefix_list
)
2238 return rmap_match_set_hook
.match_ip_next_hop_prefix_list(
2239 vty
, index
, "ip next-hop prefix-list",
2240 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
2244 DEFUN (no_match_ip_next_hop_prefix_list
,
2245 no_match_ip_next_hop_prefix_list_cmd
,
2246 "no match ip next-hop prefix-list [WORD]",
2250 "Match next-hop address of route\n"
2251 "Match entries of prefix-lists\n"
2252 "IP prefix-list name\n")
2255 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2257 if (rmap_match_set_hook
.no_match_ip_next_hop
) {
2258 if (argc
<= idx_word
)
2259 return rmap_match_set_hook
.no_match_ip_next_hop(
2260 vty
, index
, "ip next-hop prefix-list", NULL
,
2261 RMAP_EVENT_PLIST_DELETED
);
2262 return rmap_match_set_hook
.no_match_ip_next_hop(
2263 vty
, index
, "ip next-hop prefix-list",
2264 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2269 DEFUN(match_ip_next_hop_type
, match_ip_next_hop_type_cmd
,
2270 "match ip next-hop type <blackhole>",
2272 "Match next-hop address of route\n"
2273 "Match entries by type\n"
2277 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2279 if (rmap_match_set_hook
.match_ip_next_hop_type
)
2280 return rmap_match_set_hook
.match_ip_next_hop_type(
2281 vty
, index
, "ip next-hop type", argv
[idx_word
]->arg
,
2282 RMAP_EVENT_MATCH_ADDED
);
2286 DEFUN(no_match_ip_next_hop_type
, no_match_ip_next_hop_type_cmd
,
2287 "no match ip next-hop type [<blackhole>]",
2288 NO_STR MATCH_STR IP_STR
2289 "Match next-hop address of route\n"
2290 "Match entries by type\n"
2294 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2296 if (rmap_match_set_hook
.no_match_ip_next_hop
) {
2297 if (argc
<= idx_word
)
2298 return rmap_match_set_hook
.no_match_ip_next_hop(
2299 vty
, index
, "ip next-hop type", NULL
,
2300 RMAP_EVENT_MATCH_DELETED
);
2301 return rmap_match_set_hook
.no_match_ip_next_hop(
2302 vty
, index
, "ip next-hop type", argv
[idx_word
]->arg
,
2303 RMAP_EVENT_MATCH_DELETED
);
2309 DEFUN (match_ipv6_address
,
2310 match_ipv6_address_cmd
,
2311 "match ipv6 address WORD",
2314 "Match IPv6 address of route\n"
2315 "IPv6 access-list name\n")
2318 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2320 if (rmap_match_set_hook
.match_ipv6_address
)
2321 return rmap_match_set_hook
.match_ipv6_address(
2322 vty
, index
, "ipv6 address", argv
[idx_word
]->arg
,
2323 RMAP_EVENT_FILTER_ADDED
);
2327 DEFUN (no_match_ipv6_address
,
2328 no_match_ipv6_address_cmd
,
2329 "no match ipv6 address WORD",
2333 "Match IPv6 address of route\n"
2334 "IPv6 access-list name\n")
2337 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2339 if (rmap_match_set_hook
.no_match_ipv6_address
)
2340 return rmap_match_set_hook
.no_match_ipv6_address(
2341 vty
, index
, "ipv6 address", argv
[idx_word
]->arg
,
2342 RMAP_EVENT_FILTER_DELETED
);
2347 DEFUN (match_ipv6_address_prefix_list
,
2348 match_ipv6_address_prefix_list_cmd
,
2349 "match ipv6 address prefix-list WORD",
2352 "Match address of route\n"
2353 "Match entries of prefix-lists\n"
2354 "IP prefix-list name\n")
2357 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2359 if (rmap_match_set_hook
.match_ipv6_address_prefix_list
)
2360 return rmap_match_set_hook
.match_ipv6_address_prefix_list(
2361 vty
, index
, "ipv6 address prefix-list",
2362 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
2366 DEFUN (no_match_ipv6_address_prefix_list
,
2367 no_match_ipv6_address_prefix_list_cmd
,
2368 "no match ipv6 address prefix-list WORD",
2372 "Match address of route\n"
2373 "Match entries of prefix-lists\n"
2374 "IP prefix-list name\n")
2377 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2379 if (rmap_match_set_hook
.no_match_ipv6_address_prefix_list
)
2380 return rmap_match_set_hook
.no_match_ipv6_address_prefix_list(
2381 vty
, index
, "ipv6 address prefix-list",
2382 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2386 DEFUN(match_ipv6_next_hop_type
, match_ipv6_next_hop_type_cmd
,
2387 "match ipv6 next-hop type <blackhole>",
2389 "Match address of route\n"
2390 "Match entries by type\n"
2394 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2396 if (rmap_match_set_hook
.match_ipv6_next_hop_type
)
2397 return rmap_match_set_hook
.match_ipv6_next_hop_type(
2398 vty
, index
, "ipv6 next-hop type", argv
[idx_word
]->arg
,
2399 RMAP_EVENT_MATCH_ADDED
);
2403 DEFUN(no_match_ipv6_next_hop_type
, no_match_ipv6_next_hop_type_cmd
,
2404 "no match ipv6 next-hop type [<blackhole>]",
2405 NO_STR MATCH_STR IPV6_STR
2406 "Match address of route\n"
2407 "Match entries by type\n"
2411 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2413 if (rmap_match_set_hook
.no_match_ipv6_next_hop_type
)
2414 return rmap_match_set_hook
.no_match_ipv6_next_hop_type(
2415 vty
, index
, "ipv6 next-hop type",
2416 (argc
<= idx_word
) ? NULL
: argv
[idx_word
]->arg
,
2417 RMAP_EVENT_MATCH_DELETED
);
2421 DEFUN (match_metric
,
2423 "match metric (0-4294967295)",
2425 "Match metric of route\n"
2429 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2431 if (rmap_match_set_hook
.match_metric
)
2432 return rmap_match_set_hook
.match_metric(vty
, index
, "metric",
2433 argv
[idx_number
]->arg
,
2434 RMAP_EVENT_MATCH_ADDED
);
2439 DEFUN (no_match_metric
,
2440 no_match_metric_cmd
,
2441 "no match metric [(0-4294967295)]",
2444 "Match metric of route\n"
2448 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2450 if (rmap_match_set_hook
.no_match_metric
) {
2451 if (argc
<= idx_number
)
2452 return rmap_match_set_hook
.no_match_metric(
2453 vty
, index
, "metric", NULL
,
2454 RMAP_EVENT_MATCH_DELETED
);
2455 return rmap_match_set_hook
.no_match_metric(
2456 vty
, index
, "metric", argv
[idx_number
]->arg
,
2457 RMAP_EVENT_MATCH_DELETED
);
2465 "match tag (1-4294967295)",
2467 "Match tag of route\n"
2471 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2473 if (rmap_match_set_hook
.match_tag
)
2474 return rmap_match_set_hook
.match_tag(vty
, index
, "tag",
2475 argv
[idx_number
]->arg
,
2476 RMAP_EVENT_MATCH_ADDED
);
2481 DEFUN (no_match_tag
,
2483 "no match tag [(1-4294967295)]",
2486 "Match tag of route\n"
2489 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2492 char *arg
= argv_find(argv
, argc
, "(1-4294967295)", &idx
)
2496 if (rmap_match_set_hook
.no_match_tag
)
2497 return rmap_match_set_hook
.no_match_tag(
2498 vty
, index
, "tag", arg
, RMAP_EVENT_MATCH_DELETED
);
2503 DEFUN (set_ip_nexthop
,
2505 "set ip next-hop A.B.C.D",
2508 "Next hop address\n"
2509 "IP address of next hop\n")
2514 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2516 ret
= str2sockunion(argv
[idx_ipv4
]->arg
, &su
);
2518 vty_out(vty
, "%% Malformed nexthop address\n");
2519 return CMD_WARNING_CONFIG_FAILED
;
2521 if (su
.sin
.sin_addr
.s_addr
== 0
2522 || IPV4_CLASS_DE(ntohl(su
.sin
.sin_addr
.s_addr
))) {
2524 "%% nexthop address cannot be 0.0.0.0, multicast or reserved\n");
2525 return CMD_WARNING_CONFIG_FAILED
;
2528 if (rmap_match_set_hook
.set_ip_nexthop
)
2529 return rmap_match_set_hook
.set_ip_nexthop(
2530 vty
, index
, "ip next-hop", argv
[idx_ipv4
]->arg
);
2535 DEFUN (no_set_ip_nexthop
,
2536 no_set_ip_nexthop_cmd
,
2537 "no set ip next-hop [A.B.C.D]",
2541 "Next hop address\n"
2542 "IP address of next hop\n")
2545 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2546 const char *arg
= NULL
;
2548 if (argv_find(argv
, argc
, "A.B.C.D", &idx
))
2549 arg
= argv
[idx
]->arg
;
2551 if (rmap_match_set_hook
.no_set_ip_nexthop
)
2552 return rmap_match_set_hook
.no_set_ip_nexthop(
2553 vty
, index
, "ip next-hop", arg
);
2559 DEFUN (set_ipv6_nexthop_local
,
2560 set_ipv6_nexthop_local_cmd
,
2561 "set ipv6 next-hop local X:X::X:X",
2564 "IPv6 next-hop address\n"
2565 "IPv6 local address\n"
2566 "IPv6 address of next hop\n")
2569 struct in6_addr addr
;
2571 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2573 ret
= inet_pton(AF_INET6
, argv
[idx_ipv6
]->arg
, &addr
);
2575 vty_out(vty
, "%% Malformed nexthop address\n");
2576 return CMD_WARNING_CONFIG_FAILED
;
2578 if (!IN6_IS_ADDR_LINKLOCAL(&addr
)) {
2579 vty_out(vty
, "%% Invalid link-local nexthop address\n");
2580 return CMD_WARNING_CONFIG_FAILED
;
2583 if (rmap_match_set_hook
.set_ipv6_nexthop_local
)
2584 return rmap_match_set_hook
.set_ipv6_nexthop_local(
2585 vty
, index
, "ipv6 next-hop local", argv
[idx_ipv6
]->arg
);
2590 DEFUN (no_set_ipv6_nexthop_local
,
2591 no_set_ipv6_nexthop_local_cmd
,
2592 "no set ipv6 next-hop local [X:X::X:X]",
2596 "IPv6 next-hop address\n"
2597 "IPv6 local address\n"
2598 "IPv6 address of next hop\n")
2601 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2603 if (rmap_match_set_hook
.no_set_ipv6_nexthop_local
) {
2604 if (argc
<= idx_ipv6
)
2605 return rmap_match_set_hook
.no_set_ipv6_nexthop_local(
2606 vty
, index
, "ipv6 next-hop local", NULL
);
2607 return rmap_match_set_hook
.no_set_ipv6_nexthop_local(
2608 vty
, index
, "ipv6 next-hop local", argv
[5]->arg
);
2615 "set metric <(0-4294967295)|rtt|+rtt|-rtt|+metric|-metric>",
2617 "Metric value for destination routing protocol\n"
2619 "Assign round trip time\n"
2620 "Add round trip time\n"
2621 "Subtract round trip time\n"
2623 "Subtract metric\n")
2626 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2628 const char *pass
= (argv
[idx_number
]->type
== RANGE_TKN
)
2629 ? argv
[idx_number
]->arg
2630 : argv
[idx_number
]->text
;
2632 if (rmap_match_set_hook
.set_metric
)
2633 return rmap_match_set_hook
.set_metric(vty
, index
, "metric",
2639 DEFUN (no_set_metric
,
2641 "no set metric [(0-4294967295)]",
2644 "Metric value for destination routing protocol\n"
2648 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2650 if (rmap_match_set_hook
.no_set_metric
) {
2651 if (argc
<= idx_number
)
2652 return rmap_match_set_hook
.no_set_metric(
2653 vty
, index
, "metric", NULL
);
2654 return rmap_match_set_hook
.no_set_metric(vty
, index
, "metric",
2655 argv
[idx_number
]->arg
);
2663 "set tag (1-4294967295)",
2665 "Tag value for routing protocol\n"
2668 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2671 if (rmap_match_set_hook
.set_tag
)
2672 return rmap_match_set_hook
.set_tag(vty
, index
, "tag",
2673 argv
[idx_number
]->arg
);
2680 "no set tag [(1-4294967295)]",
2683 "Tag value for routing protocol\n"
2686 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2689 if (rmap_match_set_hook
.no_set_tag
) {
2690 if (argc
<= idx_number
)
2691 return rmap_match_set_hook
.no_set_tag(vty
, index
, "tag",
2693 return rmap_match_set_hook
.no_set_tag(vty
, index
, "tag",
2694 argv
[idx_number
]->arg
);
2700 DEFUN_NOSH (route_map
,
2702 "route-map WORD <deny|permit> (1-65535)",
2703 "Create route-map or enter route-map command mode\n"
2705 "Route map denies set operations\n"
2706 "Route map permits set operations\n"
2707 "Sequence to insert to/delete from existing route-map entry\n")
2710 int idx_permit_deny
= 2;
2712 struct route_map
*map
;
2713 struct route_map_index
*index
;
2714 char *endptr
= NULL
;
2716 argv
[idx_permit_deny
]->arg
[0] == 'p' ? RMAP_PERMIT
: RMAP_DENY
;
2717 unsigned long pref
= strtoul(argv
[idx_number
]->arg
, &endptr
, 10);
2718 const char *mapname
= argv
[idx_word
]->arg
;
2720 /* Get route map. */
2721 map
= route_map_get(mapname
);
2722 index
= route_map_index_get(map
, permit
, pref
);
2724 VTY_PUSH_CONTEXT(RMAP_NODE
, index
);
2728 DEFUN (no_route_map_all
,
2729 no_route_map_all_cmd
,
2730 "no route-map WORD",
2732 "Create route-map or enter route-map command mode\n"
2736 const char *mapname
= argv
[idx_word
]->arg
;
2737 struct route_map
*map
;
2739 map
= route_map_lookup_by_name(mapname
);
2741 vty_out(vty
, "%% Could not find route-map %s\n", mapname
);
2742 return CMD_WARNING_CONFIG_FAILED
;
2745 route_map_delete(map
);
2750 DEFUN (no_route_map
,
2752 "no route-map WORD <deny|permit> (1-65535)",
2754 "Create route-map or enter route-map command mode\n"
2756 "Route map denies set operations\n"
2757 "Route map permits set operations\n"
2758 "Sequence to insert to/delete from existing route-map entry\n")
2761 int idx_permit_deny
= 3;
2763 struct route_map
*map
;
2764 struct route_map_index
*index
;
2765 char *endptr
= NULL
;
2766 int permit
= strmatch(argv
[idx_permit_deny
]->text
, "permit")
2769 const char *prefstr
= argv
[idx_number
]->arg
;
2770 const char *mapname
= argv
[idx_word
]->arg
;
2771 unsigned long pref
= strtoul(prefstr
, &endptr
, 10);
2773 /* Existence check. */
2774 map
= route_map_lookup_by_name(mapname
);
2776 vty_out(vty
, "%% Could not find route-map %s\n", mapname
);
2777 return CMD_WARNING_CONFIG_FAILED
;
2780 /* Lookup route map index. */
2781 index
= route_map_index_lookup(map
, permit
, pref
);
2782 if (index
== NULL
) {
2783 vty_out(vty
, "%% Could not find route-map entry %s %s\n",
2785 return CMD_WARNING_CONFIG_FAILED
;
2788 /* Delete index from route map. */
2789 route_map_index_delete(index
, 1);
2791 /* If this route rule is the last one, delete route map itself. */
2792 if (route_map_empty(map
))
2793 route_map_delete(map
);
2798 DEFUN (rmap_onmatch_next
,
2799 rmap_onmatch_next_cmd
,
2801 "Exit policy on matches\n"
2804 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2807 if (index
->type
== RMAP_DENY
) {
2808 /* Under a deny clause, match means it's finished. No
2809 * need to set next */
2811 "on-match next not supported under route-map deny\n");
2812 return CMD_WARNING_CONFIG_FAILED
;
2814 index
->exitpolicy
= RMAP_NEXT
;
2819 DEFUN (no_rmap_onmatch_next
,
2820 no_rmap_onmatch_next_cmd
,
2823 "Exit policy on matches\n"
2826 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2829 index
->exitpolicy
= RMAP_EXIT
;
2834 DEFUN (rmap_onmatch_goto
,
2835 rmap_onmatch_goto_cmd
,
2836 "on-match goto (1-65535)",
2837 "Exit policy on matches\n"
2838 "Goto Clause number\n"
2842 char *num
= argv_find(argv
, argc
, "(1-65535)", &idx
) ? argv
[idx
]->arg
2845 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2849 if (index
->type
== RMAP_DENY
) {
2850 /* Under a deny clause, match means it's finished. No
2851 * need to go anywhere */
2853 "on-match goto not supported under route-map deny\n");
2854 return CMD_WARNING_CONFIG_FAILED
;
2858 d
= strtoul(num
, NULL
, 10);
2860 d
= index
->pref
+ 1;
2862 if (d
<= index
->pref
) {
2863 /* Can't allow you to do that, Dave */
2864 vty_out(vty
, "can't jump backwards in route-maps\n");
2865 return CMD_WARNING_CONFIG_FAILED
;
2867 index
->exitpolicy
= RMAP_GOTO
;
2868 index
->nextpref
= d
;
2874 DEFUN (no_rmap_onmatch_goto
,
2875 no_rmap_onmatch_goto_cmd
,
2878 "Exit policy on matches\n"
2879 "Goto Clause number\n")
2881 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2884 index
->exitpolicy
= RMAP_EXIT
;
2889 /* Cisco/GNU Zebra compatibility aliases */
2891 DEFUN (rmap_continue
,
2893 "continue (1-65535)",
2894 "Continue on a different entry within the route-map\n"
2895 "Route-map entry sequence number\n")
2897 return rmap_onmatch_goto(self
, vty
, argc
, argv
);
2901 DEFUN (no_rmap_continue
,
2902 no_rmap_continue_cmd
,
2903 "no continue [(1-65535)]",
2905 "Continue on a different entry within the route-map\n"
2906 "Route-map entry sequence number\n")
2908 return no_rmap_onmatch_goto(self
, vty
, argc
, argv
);
2912 DEFUN (rmap_show_name
,
2914 "show route-map [WORD]",
2916 "route-map information\n"
2920 const char *name
= (argc
== 3) ? argv
[idx_word
]->arg
: NULL
;
2921 return vty_show_route_map(vty
, name
);
2924 DEFUN (rmap_show_unused
,
2925 rmap_show_unused_cmd
,
2926 "show route-map-unused",
2928 "unused route-map information\n")
2930 return vty_show_unused_route_map(vty
);
2936 "Jump to another Route-Map after match+set\n"
2937 "Target route-map name\n")
2940 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2941 const char *rmap
= argv
[idx_word
]->arg
;
2945 /* If "call" is invoked with the same route-map name as
2946 * the one previously configured then, ignore the duplicate
2949 if (index
->nextrm
&& (strcmp(index
->nextrm
, rmap
) == 0))
2952 if (index
->nextrm
) {
2953 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED
,
2954 index
->nextrm
, index
->map
->name
);
2955 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
2957 index
->nextrm
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap
);
2959 /* Execute event hook. */
2960 route_map_upd8_dependency(RMAP_EVENT_CALL_ADDED
, index
->nextrm
,
2965 DEFUN (no_rmap_call
,
2969 "Jump to another Route-Map after match+set\n")
2971 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2973 if (index
->nextrm
) {
2974 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED
,
2975 index
->nextrm
, index
->map
->name
);
2976 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
2977 index
->nextrm
= NULL
;
2983 DEFUN (rmap_description
,
2984 rmap_description_cmd
,
2985 "description LINE...",
2986 "Route-map comment\n"
2987 "Comment describing this route-map rule\n")
2990 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2993 if (index
->description
)
2994 XFREE(MTYPE_TMP
, index
->description
);
2995 index
->description
= argv_concat(argv
, argc
, idx_line
);
3000 DEFUN (no_rmap_description
,
3001 no_rmap_description_cmd
,
3004 "Route-map comment\n")
3006 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
3009 if (index
->description
)
3010 XFREE(MTYPE_TMP
, index
->description
);
3011 index
->description
= NULL
;
3016 /* Configuration write function. */
3017 static int route_map_config_write(struct vty
*vty
)
3019 struct route_map
*map
;
3020 struct route_map_index
*index
;
3021 struct route_map_rule
*rule
;
3025 for (map
= route_map_master
.head
; map
; map
= map
->next
)
3026 for (index
= map
->head
; index
; index
= index
->next
) {
3028 vty_out(vty
, "!\n");
3032 vty_out(vty
, "route-map %s %s %d\n", map
->name
,
3033 route_map_type_str(index
->type
), index
->pref
);
3035 if (index
->description
)
3036 vty_out(vty
, " description %s\n",
3037 index
->description
);
3039 for (rule
= index
->match_list
.head
; rule
;
3041 vty_out(vty
, " match %s %s\n", rule
->cmd
->str
,
3042 rule
->rule_str
? rule
->rule_str
: "");
3044 for (rule
= index
->set_list
.head
; rule
;
3046 vty_out(vty
, " set %s %s\n", rule
->cmd
->str
,
3047 rule
->rule_str
? rule
->rule_str
: "");
3049 vty_out(vty
, " call %s\n", index
->nextrm
);
3050 if (index
->exitpolicy
== RMAP_GOTO
)
3051 vty_out(vty
, " on-match goto %d\n",
3053 if (index
->exitpolicy
== RMAP_NEXT
)
3054 vty_out(vty
, " on-match next\n");
3061 /* Route map node structure. */
3062 static struct cmd_node rmap_node
= {RMAP_NODE
, "%s(config-route-map)# ", 1};
3064 /* Common route map rules */
3066 void *route_map_rule_tag_compile(const char *arg
)
3068 unsigned long int tmp
;
3073 tmp
= strtoul(arg
, &endptr
, 0);
3074 if (arg
[0] == '\0' || *endptr
!= '\0' || errno
|| tmp
> ROUTE_TAG_MAX
)
3077 tag
= XMALLOC(MTYPE_ROUTE_MAP_COMPILED
, sizeof(*tag
));
3083 void route_map_rule_tag_free(void *rule
)
3085 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
3088 void route_map_finish(void)
3092 vector_free(route_match_vec
);
3093 route_match_vec
= NULL
;
3094 vector_free(route_set_vec
);
3095 route_set_vec
= NULL
;
3098 * All protocols are setting these to NULL
3099 * by default on shutdown( route_map_finish )
3100 * Why are we making them do this work?
3102 route_map_master
.add_hook
= NULL
;
3103 route_map_master
.delete_hook
= NULL
;
3104 route_map_master
.event_hook
= NULL
;
3106 /* cleanup route_map */
3107 while (route_map_master
.head
) {
3108 struct route_map
*map
= route_map_master
.head
;
3109 map
->to_be_processed
= false;
3110 route_map_delete(map
);
3113 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
3114 hash_free(route_map_dep_hash
[i
]);
3115 route_map_dep_hash
[i
] = NULL
;
3118 hash_free(route_map_master_hash
);
3119 route_map_master_hash
= NULL
;
3122 static void rmap_autocomplete(vector comps
, struct cmd_token
*token
)
3124 struct route_map
*map
;
3126 for (map
= route_map_master
.head
; map
; map
= map
->next
)
3127 vector_set(comps
, XSTRDUP(MTYPE_COMPLETION
, map
->name
));
3130 /* Increment the use_count counter while attaching the route map */
3131 void route_map_counter_increment(struct route_map
*map
)
3137 /* Decrement the use_count counter while detaching the route map. */
3138 void route_map_counter_decrement(struct route_map
*map
)
3141 if (map
->use_count
<= 0)
3147 static const struct cmd_variable_handler rmap_var_handlers
[] = {
3148 {/* "route-map WORD" */
3149 .varname
= "route_map",
3150 .completions
= rmap_autocomplete
},
3151 {.tokenname
= "ROUTEMAP_NAME", .completions
= rmap_autocomplete
},
3152 {.tokenname
= "RMAP_NAME", .completions
= rmap_autocomplete
},
3153 {.completions
= NULL
}};
3155 /* Initialization of route map vector. */
3156 void route_map_init(void)
3160 /* Make vector for match and set. */
3161 route_match_vec
= vector_init(1);
3162 route_set_vec
= vector_init(1);
3163 route_map_master_hash
=
3164 hash_create_size(8, route_map_hash_key_make
, route_map_hash_cmp
,
3165 "Route Map Master Hash");
3167 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++)
3168 route_map_dep_hash
[i
] = hash_create_size(
3169 8, route_map_dep_hash_make_key
, route_map_dep_hash_cmp
,
3170 "Route Map Dep Hash");
3172 cmd_variable_handler_register(rmap_var_handlers
);
3174 /* Install route map top node. */
3175 install_node(&rmap_node
, route_map_config_write
);
3177 /* Install route map commands. */
3178 install_default(RMAP_NODE
);
3179 install_element(CONFIG_NODE
, &route_map_cmd
);
3180 install_element(CONFIG_NODE
, &no_route_map_cmd
);
3181 install_element(CONFIG_NODE
, &no_route_map_all_cmd
);
3183 /* Install the on-match stuff */
3184 install_element(RMAP_NODE
, &route_map_cmd
);
3185 install_element(RMAP_NODE
, &rmap_onmatch_next_cmd
);
3186 install_element(RMAP_NODE
, &no_rmap_onmatch_next_cmd
);
3187 install_element(RMAP_NODE
, &rmap_onmatch_goto_cmd
);
3188 install_element(RMAP_NODE
, &no_rmap_onmatch_goto_cmd
);
3189 install_element(RMAP_NODE
, &rmap_continue_cmd
);
3190 install_element(RMAP_NODE
, &no_rmap_continue_cmd
);
3192 /* Install the continue stuff (ALIAS of on-match). */
3194 /* Install the call stuff. */
3195 install_element(RMAP_NODE
, &rmap_call_cmd
);
3196 install_element(RMAP_NODE
, &no_rmap_call_cmd
);
3198 /* Install description commands. */
3199 install_element(RMAP_NODE
, &rmap_description_cmd
);
3200 install_element(RMAP_NODE
, &no_rmap_description_cmd
);
3202 /* Install show command */
3203 install_element(ENABLE_NODE
, &rmap_show_name_cmd
);
3204 install_element(ENABLE_NODE
, &rmap_show_unused_cmd
);
3206 install_element(RMAP_NODE
, &match_interface_cmd
);
3207 install_element(RMAP_NODE
, &no_match_interface_cmd
);
3209 install_element(RMAP_NODE
, &match_ip_address_cmd
);
3210 install_element(RMAP_NODE
, &no_match_ip_address_cmd
);
3212 install_element(RMAP_NODE
, &match_ip_address_prefix_list_cmd
);
3213 install_element(RMAP_NODE
, &no_match_ip_address_prefix_list_cmd
);
3215 install_element(RMAP_NODE
, &match_ip_next_hop_cmd
);
3216 install_element(RMAP_NODE
, &no_match_ip_next_hop_cmd
);
3218 install_element(RMAP_NODE
, &match_ip_next_hop_prefix_list_cmd
);
3219 install_element(RMAP_NODE
, &no_match_ip_next_hop_prefix_list_cmd
);
3221 install_element(RMAP_NODE
, &match_ip_next_hop_type_cmd
);
3222 install_element(RMAP_NODE
, &no_match_ip_next_hop_type_cmd
);
3224 install_element(RMAP_NODE
, &match_ipv6_address_cmd
);
3225 install_element(RMAP_NODE
, &no_match_ipv6_address_cmd
);
3227 install_element(RMAP_NODE
, &match_ipv6_address_prefix_list_cmd
);
3228 install_element(RMAP_NODE
, &no_match_ipv6_address_prefix_list_cmd
);
3230 install_element(RMAP_NODE
, &match_ipv6_next_hop_type_cmd
);
3231 install_element(RMAP_NODE
, &no_match_ipv6_next_hop_type_cmd
);
3233 install_element(RMAP_NODE
, &match_metric_cmd
);
3234 install_element(RMAP_NODE
, &no_match_metric_cmd
);
3236 install_element(RMAP_NODE
, &match_tag_cmd
);
3237 install_element(RMAP_NODE
, &no_match_tag_cmd
);
3239 install_element(RMAP_NODE
, &set_ip_nexthop_cmd
);
3240 install_element(RMAP_NODE
, &no_set_ip_nexthop_cmd
);
3242 install_element(RMAP_NODE
, &set_ipv6_nexthop_local_cmd
);
3243 install_element(RMAP_NODE
, &no_set_ipv6_nexthop_local_cmd
);
3245 install_element(RMAP_NODE
, &set_metric_cmd
);
3246 install_element(RMAP_NODE
, &no_set_metric_cmd
);
3248 install_element(RMAP_NODE
, &set_tag_cmd
);
3249 install_element(RMAP_NODE
, &no_set_tag_cmd
);