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
34 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP
, "Route map")
35 DEFINE_MTYPE(LIB
, ROUTE_MAP_NAME
, "Route map name")
36 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_INDEX
, "Route map index")
37 DEFINE_MTYPE(LIB
, ROUTE_MAP_RULE
, "Route map rule")
38 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_RULE_STR
, "Route map rule str")
39 DEFINE_MTYPE(LIB
, ROUTE_MAP_COMPILED
, "Route map compiled")
40 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_DEP
, "Route map dependency")
42 DEFINE_QOBJ_TYPE(route_map_index
)
43 DEFINE_QOBJ_TYPE(route_map
)
45 /* Vector for route match rules. */
46 static vector route_match_vec
;
48 /* Vector for route set rules. */
49 static vector route_set_vec
;
51 struct route_map_match_set_hooks
{
53 int (*match_interface
)(struct vty
*vty
, struct route_map_index
*index
,
54 const char *command
, const char *arg
,
55 route_map_event_t type
);
57 /* no match interface */
58 int (*no_match_interface
)(struct vty
*vty
,
59 struct route_map_index
*index
,
60 const char *command
, const char *arg
,
61 route_map_event_t type
);
63 /* match ip address */
64 int (*match_ip_address
)(struct vty
*vty
, struct route_map_index
*index
,
65 const char *command
, const char *arg
,
66 route_map_event_t type
);
68 /* no match ip address */
69 int (*no_match_ip_address
)(struct vty
*vty
,
70 struct route_map_index
*index
,
71 const char *command
, const char *arg
,
72 route_map_event_t type
);
74 /* match ip address prefix list */
75 int (*match_ip_address_prefix_list
)(struct vty
*vty
,
76 struct route_map_index
*index
,
79 route_map_event_t type
);
81 /* no match ip address prefix list */
82 int (*no_match_ip_address_prefix_list
)(struct vty
*vty
,
83 struct route_map_index
*index
,
86 route_map_event_t type
);
88 /* match ip next hop */
89 int (*match_ip_next_hop
)(struct vty
*vty
, struct route_map_index
*index
,
90 const char *command
, const char *arg
,
91 route_map_event_t type
);
93 /* no match ip next hop */
94 int (*no_match_ip_next_hop
)(struct vty
*vty
,
95 struct route_map_index
*index
,
96 const char *command
, const char *arg
,
97 route_map_event_t type
);
99 /* match ip next hop prefix list */
100 int (*match_ip_next_hop_prefix_list
)(struct vty
*vty
,
101 struct route_map_index
*index
,
104 route_map_event_t type
);
106 /* no match ip next hop prefix list */
107 int (*no_match_ip_next_hop_prefix_list
)(struct vty
*vty
,
108 struct route_map_index
*index
,
111 route_map_event_t type
);
113 /* match ipv6 address */
114 int (*match_ipv6_address
)(struct vty
*vty
,
115 struct route_map_index
*index
,
116 const char *command
, const char *arg
,
117 route_map_event_t type
);
119 /* no match ipv6 address */
120 int (*no_match_ipv6_address
)(struct vty
*vty
,
121 struct route_map_index
*index
,
122 const char *command
, const char *arg
,
123 route_map_event_t type
);
126 /* match ipv6 address prefix list */
127 int (*match_ipv6_address_prefix_list
)(struct vty
*vty
,
128 struct route_map_index
*index
,
131 route_map_event_t type
);
133 /* no match ipv6 address prefix list */
134 int (*no_match_ipv6_address_prefix_list
)(struct vty
*vty
,
135 struct route_map_index
*index
,
138 route_map_event_t type
);
141 int (*match_metric
)(struct vty
*vty
, struct route_map_index
*index
,
142 const char *command
, const char *arg
,
143 route_map_event_t type
);
145 /* no match metric */
146 int (*no_match_metric
)(struct vty
*vty
, struct route_map_index
*index
,
147 const char *command
, const char *arg
,
148 route_map_event_t type
);
151 int (*match_tag
)(struct vty
*vty
, struct route_map_index
*index
,
152 const char *command
, const char *arg
,
153 route_map_event_t type
);
156 int (*no_match_tag
)(struct vty
*vty
, struct route_map_index
*index
,
157 const char *command
, const char *arg
,
158 route_map_event_t type
);
161 int (*set_ip_nexthop
)(struct vty
*vty
, struct route_map_index
*index
,
162 const char *command
, const char *arg
);
164 /* no set ip nexthop */
165 int (*no_set_ip_nexthop
)(struct vty
*vty
, struct route_map_index
*index
,
166 const char *command
, const char *arg
);
168 /* set ipv6 nexthop local */
169 int (*set_ipv6_nexthop_local
)(struct vty
*vty
,
170 struct route_map_index
*index
,
171 const char *command
, const char *arg
);
173 /* no set ipv6 nexthop local */
174 int (*no_set_ipv6_nexthop_local
)(struct vty
*vty
,
175 struct route_map_index
*index
,
176 const char *command
, const char *arg
);
179 int (*set_metric
)(struct vty
*vty
, struct route_map_index
*index
,
180 const char *command
, const char *arg
);
183 int (*no_set_metric
)(struct vty
*vty
, struct route_map_index
*index
,
184 const char *command
, const char *arg
);
187 int (*set_tag
)(struct vty
*vty
, struct route_map_index
*index
,
188 const char *command
, const char *arg
);
191 int (*no_set_tag
)(struct vty
*vty
, struct route_map_index
*index
,
192 const char *command
, const char *arg
);
195 struct route_map_match_set_hooks rmap_match_set_hook
;
197 /* match interface */
198 void route_map_match_interface_hook(int (*func
)(
199 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
200 const char *arg
, route_map_event_t type
))
202 rmap_match_set_hook
.match_interface
= func
;
205 /* no match interface */
206 void route_map_no_match_interface_hook(int (*func
)(
207 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
208 const char *arg
, route_map_event_t type
))
210 rmap_match_set_hook
.no_match_interface
= func
;
213 /* match ip address */
214 void route_map_match_ip_address_hook(int (*func
)(
215 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
216 const char *arg
, route_map_event_t type
))
218 rmap_match_set_hook
.match_ip_address
= func
;
221 /* no match ip address */
222 void route_map_no_match_ip_address_hook(int (*func
)(
223 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
224 const char *arg
, route_map_event_t type
))
226 rmap_match_set_hook
.no_match_ip_address
= func
;
229 /* match ip address prefix list */
230 void route_map_match_ip_address_prefix_list_hook(int (*func
)(
231 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
232 const char *arg
, route_map_event_t type
))
234 rmap_match_set_hook
.match_ip_address_prefix_list
= func
;
237 /* no match ip address prefix list */
238 void route_map_no_match_ip_address_prefix_list_hook(int (*func
)(
239 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
240 const char *arg
, route_map_event_t type
))
242 rmap_match_set_hook
.no_match_ip_address_prefix_list
= func
;
245 /* match ip next hop */
246 void route_map_match_ip_next_hop_hook(int (*func
)(
247 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
248 const char *arg
, route_map_event_t type
))
250 rmap_match_set_hook
.match_ip_next_hop
= func
;
253 /* no match ip next hop */
254 void route_map_no_match_ip_next_hop_hook(int (*func
)(
255 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
256 const char *arg
, route_map_event_t type
))
258 rmap_match_set_hook
.no_match_ip_next_hop
= func
;
261 /* match ip next hop prefix list */
262 void route_map_match_ip_next_hop_prefix_list_hook(int (*func
)(
263 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
264 const char *arg
, route_map_event_t type
))
266 rmap_match_set_hook
.match_ip_next_hop_prefix_list
= func
;
269 /* no match ip next hop prefix list */
270 void route_map_no_match_ip_next_hop_prefix_list_hook(int (*func
)(
271 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
272 const char *arg
, route_map_event_t type
))
274 rmap_match_set_hook
.no_match_ip_next_hop_prefix_list
= func
;
277 /* match ipv6 address */
278 void route_map_match_ipv6_address_hook(int (*func
)(
279 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
280 const char *arg
, route_map_event_t type
))
282 rmap_match_set_hook
.match_ipv6_address
= func
;
285 /* no match ipv6 address */
286 void route_map_no_match_ipv6_address_hook(int (*func
)(
287 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
288 const char *arg
, route_map_event_t type
))
290 rmap_match_set_hook
.no_match_ipv6_address
= func
;
294 /* match ipv6 address prefix list */
295 void route_map_match_ipv6_address_prefix_list_hook(int (*func
)(
296 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
297 const char *arg
, route_map_event_t type
))
299 rmap_match_set_hook
.match_ipv6_address_prefix_list
= func
;
302 /* no match ipv6 address prefix list */
303 void route_map_no_match_ipv6_address_prefix_list_hook(int (*func
)(
304 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
305 const char *arg
, route_map_event_t type
))
307 rmap_match_set_hook
.no_match_ipv6_address_prefix_list
= func
;
311 void route_map_match_metric_hook(int (*func
)(
312 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
313 const char *arg
, route_map_event_t type
))
315 rmap_match_set_hook
.match_metric
= func
;
318 /* no match metric */
319 void route_map_no_match_metric_hook(int (*func
)(
320 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
321 const char *arg
, route_map_event_t type
))
323 rmap_match_set_hook
.no_match_metric
= func
;
327 void route_map_match_tag_hook(int (*func
)(struct vty
*vty
,
328 struct route_map_index
*index
,
329 const char *command
, const char *arg
,
330 route_map_event_t type
))
332 rmap_match_set_hook
.match_tag
= func
;
336 void route_map_no_match_tag_hook(int (*func
)(
337 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
338 const char *arg
, route_map_event_t type
))
340 rmap_match_set_hook
.no_match_tag
= func
;
344 void route_map_set_ip_nexthop_hook(int (*func
)(struct vty
*vty
,
345 struct route_map_index
*index
,
349 rmap_match_set_hook
.set_ip_nexthop
= func
;
352 /* no set ip nexthop */
353 void route_map_no_set_ip_nexthop_hook(int (*func
)(struct vty
*vty
,
354 struct route_map_index
*index
,
358 rmap_match_set_hook
.no_set_ip_nexthop
= func
;
361 /* set ipv6 nexthop local */
362 void route_map_set_ipv6_nexthop_local_hook(
363 int (*func
)(struct vty
*vty
, struct route_map_index
*index
,
364 const char *command
, const char *arg
))
366 rmap_match_set_hook
.set_ipv6_nexthop_local
= func
;
369 /* no set ipv6 nexthop local */
370 void route_map_no_set_ipv6_nexthop_local_hook(
371 int (*func
)(struct vty
*vty
, struct route_map_index
*index
,
372 const char *command
, const char *arg
))
374 rmap_match_set_hook
.no_set_ipv6_nexthop_local
= func
;
378 void route_map_set_metric_hook(int (*func
)(struct vty
*vty
,
379 struct route_map_index
*index
,
383 rmap_match_set_hook
.set_metric
= func
;
387 void route_map_no_set_metric_hook(int (*func
)(struct vty
*vty
,
388 struct route_map_index
*index
,
392 rmap_match_set_hook
.no_set_metric
= func
;
396 void route_map_set_tag_hook(int (*func
)(struct vty
*vty
,
397 struct route_map_index
*index
,
398 const char *command
, const char *arg
))
400 rmap_match_set_hook
.set_tag
= func
;
404 void route_map_no_set_tag_hook(int (*func
)(struct vty
*vty
,
405 struct route_map_index
*index
,
409 rmap_match_set_hook
.no_set_tag
= func
;
412 int generic_match_add(struct vty
*vty
, struct route_map_index
*index
,
413 const char *command
, const char *arg
,
414 route_map_event_t type
)
418 ret
= route_map_add_match(index
, command
, arg
);
420 case RMAP_COMPILE_SUCCESS
:
421 if (type
!= RMAP_EVENT_MATCH_ADDED
) {
422 route_map_upd8_dependency(type
, arg
, index
->map
->name
);
425 case RMAP_RULE_MISSING
:
426 vty_out(vty
, "%% [%s] Can't find rule.\n", frr_protonameinst
);
427 return CMD_WARNING_CONFIG_FAILED
;
429 case RMAP_COMPILE_ERROR
:
431 "%% [%s] Argument form is unsupported or malformed.\n",
433 return CMD_WARNING_CONFIG_FAILED
;
440 int generic_match_delete(struct vty
*vty
, struct route_map_index
*index
,
441 const char *command
, const char *arg
,
442 route_map_event_t type
)
445 int retval
= CMD_SUCCESS
;
446 char *dep_name
= NULL
;
448 char *rmap_name
= NULL
;
450 if (type
!= RMAP_EVENT_MATCH_DELETED
) {
451 /* ignore the mundane, the types without any dependency */
453 if ((tmpstr
= route_map_get_match_arg(index
, command
))
456 XSTRDUP(MTYPE_ROUTE_MAP_RULE
, tmpstr
);
458 dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_RULE
, arg
);
460 rmap_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, index
->map
->name
);
463 ret
= route_map_delete_match(index
, command
, dep_name
);
465 case RMAP_RULE_MISSING
:
466 vty_out(vty
, "%% [%s] Can't find rule.\n", frr_protonameinst
);
467 retval
= CMD_WARNING_CONFIG_FAILED
;
469 case RMAP_COMPILE_ERROR
:
471 "%% [%s] Argument form is unsupported or malformed.\n",
473 retval
= CMD_WARNING_CONFIG_FAILED
;
475 case RMAP_COMPILE_SUCCESS
:
476 if (type
!= RMAP_EVENT_MATCH_DELETED
&& dep_name
)
477 route_map_upd8_dependency(type
, dep_name
, rmap_name
);
482 XFREE(MTYPE_ROUTE_MAP_RULE
, dep_name
);
484 XFREE(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
489 int generic_set_add(struct vty
*vty
, struct route_map_index
*index
,
490 const char *command
, const char *arg
)
494 ret
= route_map_add_set(index
, command
, arg
);
496 case RMAP_RULE_MISSING
:
497 vty_out(vty
, "%% [%s] Can't find rule.\n", frr_protonameinst
);
498 return CMD_WARNING_CONFIG_FAILED
;
500 case RMAP_COMPILE_ERROR
:
502 "%% [%s] Argument form is unsupported or malformed.\n",
504 return CMD_WARNING_CONFIG_FAILED
;
506 case RMAP_COMPILE_SUCCESS
:
513 int generic_set_delete(struct vty
*vty
, struct route_map_index
*index
,
514 const char *command
, const char *arg
)
518 ret
= route_map_delete_set(index
, command
, arg
);
520 case RMAP_RULE_MISSING
:
521 vty_out(vty
, "%% [%s] Can't find rule.\n", frr_protonameinst
);
522 return CMD_WARNING_CONFIG_FAILED
;
524 case RMAP_COMPILE_ERROR
:
526 "%% [%s] Argument form is unsupported or malformed.\n",
528 return CMD_WARNING_CONFIG_FAILED
;
530 case RMAP_COMPILE_SUCCESS
:
538 /* Route map rule. This rule has both `match' rule and `set' rule. */
539 struct route_map_rule
{
541 struct route_map_rule_cmd
*cmd
;
543 /* For pretty printing. */
546 /* Pre-compiled match rule. */
550 struct route_map_rule
*next
;
551 struct route_map_rule
*prev
;
554 /* Making route map list. */
555 struct route_map_list
{
556 struct route_map
*head
;
557 struct route_map
*tail
;
559 void (*add_hook
)(const char *);
560 void (*delete_hook
)(const char *);
561 void (*event_hook
)(route_map_event_t
, const char *);
564 /* Master list of route map. */
565 static struct route_map_list route_map_master
= {NULL
, NULL
, NULL
, NULL
, NULL
};
566 struct hash
*route_map_master_hash
= NULL
;
568 static unsigned int route_map_hash_key_make(void *p
)
570 const struct route_map
*map
= p
;
571 return string_hash_make(map
->name
);
574 static int route_map_hash_cmp(const void *p1
, const void *p2
)
576 const struct route_map
*map1
= p1
;
577 const struct route_map
*map2
= p2
;
579 if (map1
->deleted
== map2
->deleted
) {
580 if (map1
->name
&& map2
->name
) {
581 if (!strcmp(map1
->name
, map2
->name
)) {
584 } else if (!map1
->name
&& !map2
->name
) {
592 enum route_map_upd8_type
{
597 /* all possible route-map dependency types */
598 enum route_map_dep_type
{
599 ROUTE_MAP_DEP_RMAP
= 1,
601 ROUTE_MAP_DEP_ECLIST
,
602 ROUTE_MAP_DEP_LCLIST
,
604 ROUTE_MAP_DEP_ASPATH
,
605 ROUTE_MAP_DEP_FILTER
,
609 struct route_map_dep
{
611 struct hash
*dep_rmap_hash
;
612 struct hash
*this_hash
; /* ptr to the hash structure this is part of */
615 /* Hashes maintaining dependency between various sublists used by route maps */
616 struct hash
*route_map_dep_hash
[ROUTE_MAP_DEP_MAX
];
618 static unsigned int route_map_dep_hash_make_key(void *p
);
619 static int route_map_dep_hash_cmp(const void *p1
, const void *p2
);
620 static void route_map_clear_all_references(char *rmap_name
);
621 static void route_map_rule_delete(struct route_map_rule_list
*,
622 struct route_map_rule
*);
623 static int rmap_debug
= 0;
625 static void route_map_index_delete(struct route_map_index
*, int);
627 /* New route map allocation. Please note route map's name must be
629 static struct route_map
*route_map_new(const char *name
)
631 struct route_map
*new;
633 new = XCALLOC(MTYPE_ROUTE_MAP
, sizeof(struct route_map
));
634 new->name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
635 QOBJ_REG(new, route_map
);
639 /* Add new name to route_map. */
640 static struct route_map
*route_map_add(const char *name
)
642 struct route_map
*map
;
643 struct route_map_list
*list
;
645 map
= route_map_new(name
);
646 list
= &route_map_master
;
648 /* Add map to the hash */
649 hash_get(route_map_master_hash
, map
, hash_alloc_intern
);
651 /* Add new entry to the head of the list to match how it is added in the
652 * hash table. This is to ensure that if the same route-map has been
653 * created more than once and then marked for deletion (which can happen
654 * if prior deletions haven't completed as BGP hasn't yet done the
655 * route-map processing), the order of the entities is the same in both
656 * the list and the hash table. Otherwise, since there is nothing to
657 * distinguish between the two entries, the wrong entry could get freed.
658 * TODO: This needs to be re-examined to handle it better - e.g., revive
659 * a deleted entry if the route-map is created again.
662 map
->next
= list
->head
;
664 list
->head
->prev
= map
;
670 if (route_map_master
.add_hook
) {
671 (*route_map_master
.add_hook
)(name
);
672 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_ADDED
);
677 /* this is supposed to be called post processing by
678 * the delete hook function. Don't invoke delete_hook
679 * again in this routine.
681 static void route_map_free_map(struct route_map
*map
)
683 struct route_map_list
*list
;
684 struct route_map_index
*index
;
689 while ((index
= map
->head
) != NULL
)
690 route_map_index_delete(index
, 0);
692 list
= &route_map_master
;
697 map
->next
->prev
= map
->prev
;
699 list
->tail
= map
->prev
;
702 map
->prev
->next
= map
->next
;
704 list
->head
= map
->next
;
706 hash_release(route_map_master_hash
, map
);
707 XFREE(MTYPE_ROUTE_MAP_NAME
, map
->name
);
708 XFREE(MTYPE_ROUTE_MAP
, map
);
711 /* Route map delete from list. */
712 static void route_map_delete(struct route_map
*map
)
714 struct route_map_index
*index
;
717 while ((index
= map
->head
) != NULL
)
718 route_map_index_delete(index
, 0);
723 /* Clear all dependencies */
724 route_map_clear_all_references(name
);
726 /* Execute deletion hook. */
727 if (route_map_master
.delete_hook
) {
728 (*route_map_master
.delete_hook
)(name
);
729 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_DELETED
);
732 if (!map
->to_be_processed
) {
733 route_map_free_map(map
);
737 /* Lookup route map by route map name string. */
738 struct route_map
*route_map_lookup_by_name(const char *name
)
740 struct route_map
*map
;
741 struct route_map tmp_map
;
746 // map.deleted is 0 via memset
747 memset(&tmp_map
, 0, sizeof(struct route_map
));
748 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
749 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
750 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
754 int route_map_mark_updated(const char *name
)
756 struct route_map
*map
;
758 struct route_map tmp_map
;
763 map
= route_map_lookup_by_name(name
);
765 /* If we did not find the routemap with deleted=false try again
769 memset(&tmp_map
, 0, sizeof(struct route_map
));
770 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
771 tmp_map
.deleted
= true;
772 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
773 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
777 map
->to_be_processed
= true;
784 static int route_map_clear_updated(struct route_map
*map
)
789 map
->to_be_processed
= false;
791 route_map_free_map(map
);
797 /* Lookup route map. If there isn't route map create one and return
799 static struct route_map
*route_map_get(const char *name
)
801 struct route_map
*map
;
803 map
= route_map_lookup_by_name(name
);
805 map
= route_map_add(name
);
810 void route_map_walk_update_list(void (*route_map_update_fn
)(char *name
))
812 struct route_map
*node
;
813 struct route_map
*nnode
= NULL
;
815 for (node
= route_map_master
.head
; node
; node
= nnode
) {
816 if (node
->to_be_processed
) {
817 /* DD: Should we add any thread yield code here */
818 route_map_update_fn(node
->name
);
820 route_map_clear_updated(node
);
826 /* Return route map's type string. */
827 static const char *route_map_type_str(enum route_map_type type
)
842 static int route_map_empty(struct route_map
*map
)
844 if (map
->head
== NULL
&& map
->tail
== NULL
)
851 static void vty_show_route_map_entry(struct vty
*vty
, struct route_map
*map
)
853 struct route_map_index
*index
;
854 struct route_map_rule
*rule
;
856 vty_out(vty
, "%s:\n", frr_protonameinst
);
858 for (index
= map
->head
; index
; index
= index
->next
) {
859 vty_out(vty
, "route-map %s, %s, sequence %d\n", map
->name
,
860 route_map_type_str(index
->type
), index
->pref
);
863 if (index
->description
)
864 vty_out(vty
, " Description:\n %s\n",
868 vty_out(vty
, " Match clauses:\n");
869 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
870 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
873 vty_out(vty
, " Set clauses:\n");
874 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
875 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
879 vty_out(vty
, " Call clause:\n");
881 vty_out(vty
, " Call %s\n", index
->nextrm
);
884 vty_out(vty
, " Action:\n");
885 if (index
->exitpolicy
== RMAP_GOTO
)
886 vty_out(vty
, " Goto %d\n", index
->nextpref
);
887 else if (index
->exitpolicy
== RMAP_NEXT
)
888 vty_out(vty
, " Continue to next entry\n");
889 else if (index
->exitpolicy
== RMAP_EXIT
)
890 vty_out(vty
, " Exit routemap\n");
894 static int vty_show_route_map(struct vty
*vty
, const char *name
)
896 struct route_map
*map
;
899 map
= route_map_lookup_by_name(name
);
902 vty_show_route_map_entry(vty
, map
);
905 vty_out(vty
, "%s: 'route-map %s' not found\n",
906 frr_protonameinst
, name
);
910 for (map
= route_map_master
.head
; map
; map
= map
->next
)
912 vty_show_route_map_entry(vty
, map
);
918 /* New route map allocation. Please note route map's name must be
920 static struct route_map_index
*route_map_index_new(void)
922 struct route_map_index
*new;
924 new = XCALLOC(MTYPE_ROUTE_MAP_INDEX
, sizeof(struct route_map_index
));
925 new->exitpolicy
= RMAP_EXIT
; /* Default to Cisco-style */
926 QOBJ_REG(new, route_map_index
);
930 /* Free route map index. */
931 static void route_map_index_delete(struct route_map_index
*index
, int notify
)
933 struct route_map_rule
*rule
;
937 /* Free route match. */
938 while ((rule
= index
->match_list
.head
) != NULL
)
939 route_map_rule_delete(&index
->match_list
, rule
);
941 /* Free route set. */
942 while ((rule
= index
->set_list
.head
) != NULL
)
943 route_map_rule_delete(&index
->set_list
, rule
);
945 /* Remove index from route map list. */
947 index
->next
->prev
= index
->prev
;
949 index
->map
->tail
= index
->prev
;
952 index
->prev
->next
= index
->next
;
954 index
->map
->head
= index
->next
;
956 /* Free 'char *nextrm' if not NULL */
958 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
960 /* Execute event hook. */
961 if (route_map_master
.event_hook
&& notify
) {
962 (*route_map_master
.event_hook
)(RMAP_EVENT_INDEX_DELETED
,
964 route_map_notify_dependencies(index
->map
->name
,
965 RMAP_EVENT_CALL_ADDED
);
967 XFREE(MTYPE_ROUTE_MAP_INDEX
, index
);
970 /* Lookup index from route map. */
971 static struct route_map_index
*route_map_index_lookup(struct route_map
*map
,
972 enum route_map_type type
,
975 struct route_map_index
*index
;
977 for (index
= map
->head
; index
; index
= index
->next
)
978 if ((index
->type
== type
|| type
== RMAP_ANY
)
979 && index
->pref
== pref
)
984 /* Add new index to route map. */
985 static struct route_map_index
*
986 route_map_index_add(struct route_map
*map
, enum route_map_type type
, int pref
)
988 struct route_map_index
*index
;
989 struct route_map_index
*point
;
991 /* Allocate new route map inex. */
992 index
= route_map_index_new();
997 /* Compare preference. */
998 for (point
= map
->head
; point
; point
= point
->next
)
999 if (point
->pref
>= pref
)
1002 if (map
->head
== NULL
) {
1003 map
->head
= map
->tail
= index
;
1004 } else if (point
== NULL
) {
1005 index
->prev
= map
->tail
;
1006 map
->tail
->next
= index
;
1008 } else if (point
== map
->head
) {
1009 index
->next
= map
->head
;
1010 map
->head
->prev
= index
;
1013 index
->next
= point
;
1014 index
->prev
= point
->prev
;
1016 point
->prev
->next
= index
;
1017 point
->prev
= index
;
1020 /* Execute event hook. */
1021 if (route_map_master
.event_hook
) {
1022 (*route_map_master
.event_hook
)(RMAP_EVENT_INDEX_ADDED
,
1024 route_map_notify_dependencies(map
->name
, RMAP_EVENT_CALL_ADDED
);
1029 /* Get route map index. */
1030 static struct route_map_index
*
1031 route_map_index_get(struct route_map
*map
, enum route_map_type type
, int pref
)
1033 struct route_map_index
*index
;
1035 index
= route_map_index_lookup(map
, RMAP_ANY
, pref
);
1036 if (index
&& index
->type
!= type
) {
1037 /* Delete index from route map. */
1038 route_map_index_delete(index
, 1);
1042 index
= route_map_index_add(map
, type
, pref
);
1046 /* New route map rule */
1047 static struct route_map_rule
*route_map_rule_new(void)
1049 struct route_map_rule
*new;
1051 new = XCALLOC(MTYPE_ROUTE_MAP_RULE
, sizeof(struct route_map_rule
));
1055 /* Install rule command to the match list. */
1056 void route_map_install_match(struct route_map_rule_cmd
*cmd
)
1058 vector_set(route_match_vec
, cmd
);
1061 /* Install rule command to the set list. */
1062 void route_map_install_set(struct route_map_rule_cmd
*cmd
)
1064 vector_set(route_set_vec
, cmd
);
1067 /* Lookup rule command from match list. */
1068 static struct route_map_rule_cmd
*route_map_lookup_match(const char *name
)
1071 struct route_map_rule_cmd
*rule
;
1073 for (i
= 0; i
< vector_active(route_match_vec
); i
++)
1074 if ((rule
= vector_slot(route_match_vec
, i
)) != NULL
)
1075 if (strcmp(rule
->str
, name
) == 0)
1080 /* Lookup rule command from set list. */
1081 static struct route_map_rule_cmd
*route_map_lookup_set(const char *name
)
1084 struct route_map_rule_cmd
*rule
;
1086 for (i
= 0; i
< vector_active(route_set_vec
); i
++)
1087 if ((rule
= vector_slot(route_set_vec
, i
)) != NULL
)
1088 if (strcmp(rule
->str
, name
) == 0)
1093 /* Add match and set rule to rule list. */
1094 static void route_map_rule_add(struct route_map_rule_list
*list
,
1095 struct route_map_rule
*rule
)
1098 rule
->prev
= list
->tail
;
1100 list
->tail
->next
= rule
;
1106 /* Delete rule from rule list. */
1107 static void route_map_rule_delete(struct route_map_rule_list
*list
,
1108 struct route_map_rule
*rule
)
1110 if (rule
->cmd
->func_free
)
1111 (*rule
->cmd
->func_free
)(rule
->value
);
1114 XFREE(MTYPE_ROUTE_MAP_RULE_STR
, rule
->rule_str
);
1117 rule
->next
->prev
= rule
->prev
;
1119 list
->tail
= rule
->prev
;
1121 rule
->prev
->next
= rule
->next
;
1123 list
->head
= rule
->next
;
1125 XFREE(MTYPE_ROUTE_MAP_RULE
, rule
);
1128 /* strcmp wrapper function which don't crush even argument is NULL. */
1129 static int rulecmp(const char *dst
, const char *src
)
1140 return strcmp(dst
, src
);
1145 /* Use this to return the already specified argument for this match. This is
1146 * useful to get the specified argument with a route map match rule when the
1147 * rule is being deleted and the argument is not provided.
1149 const char *route_map_get_match_arg(struct route_map_index
*index
,
1150 const char *match_name
)
1152 struct route_map_rule
*rule
;
1153 struct route_map_rule_cmd
*cmd
;
1155 /* First lookup rule for add match statement. */
1156 cmd
= route_map_lookup_match(match_name
);
1160 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1161 if (rule
->cmd
== cmd
&& rule
->rule_str
!= NULL
)
1162 return (rule
->rule_str
);
1167 /* Add match statement to route map. */
1168 int route_map_add_match(struct route_map_index
*index
, const char *match_name
,
1169 const char *match_arg
)
1171 struct route_map_rule
*rule
;
1172 struct route_map_rule
*next
;
1173 struct route_map_rule_cmd
*cmd
;
1177 /* First lookup rule for add match statement. */
1178 cmd
= route_map_lookup_match(match_name
);
1180 return RMAP_RULE_MISSING
;
1182 /* Next call compile function for this match statement. */
1183 if (cmd
->func_compile
) {
1184 compile
= (*cmd
->func_compile
)(match_arg
);
1185 if (compile
== NULL
)
1186 return RMAP_COMPILE_ERROR
;
1190 /* If argument is completely same ignore it. */
1191 for (rule
= index
->match_list
.head
; rule
; rule
= next
) {
1193 if (rule
->cmd
== cmd
) {
1194 route_map_rule_delete(&index
->match_list
, rule
);
1199 /* Add new route map match rule. */
1200 rule
= route_map_rule_new();
1202 rule
->value
= compile
;
1204 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, match_arg
);
1206 rule
->rule_str
= NULL
;
1208 /* Add new route match rule to linked list. */
1209 route_map_rule_add(&index
->match_list
, rule
);
1211 /* Execute event hook. */
1212 if (route_map_master
.event_hook
) {
1213 (*route_map_master
.event_hook
)(
1214 replaced
? RMAP_EVENT_MATCH_REPLACED
1215 : RMAP_EVENT_MATCH_ADDED
,
1217 route_map_notify_dependencies(index
->map
->name
,
1218 RMAP_EVENT_CALL_ADDED
);
1221 return RMAP_COMPILE_SUCCESS
;
1224 /* Delete specified route match rule. */
1225 int route_map_delete_match(struct route_map_index
*index
,
1226 const char *match_name
, const char *match_arg
)
1228 struct route_map_rule
*rule
;
1229 struct route_map_rule_cmd
*cmd
;
1231 cmd
= route_map_lookup_match(match_name
);
1235 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1236 if (rule
->cmd
== cmd
&& (rulecmp(rule
->rule_str
, match_arg
) == 0
1237 || match_arg
== NULL
)) {
1238 route_map_rule_delete(&index
->match_list
, rule
);
1239 /* Execute event hook. */
1240 if (route_map_master
.event_hook
) {
1241 (*route_map_master
.event_hook
)(
1242 RMAP_EVENT_MATCH_DELETED
,
1244 route_map_notify_dependencies(
1246 RMAP_EVENT_CALL_ADDED
);
1250 /* Can't find matched rule. */
1254 /* Add route-map set statement to the route map. */
1255 int route_map_add_set(struct route_map_index
*index
, const char *set_name
,
1256 const char *set_arg
)
1258 struct route_map_rule
*rule
;
1259 struct route_map_rule
*next
;
1260 struct route_map_rule_cmd
*cmd
;
1264 cmd
= route_map_lookup_set(set_name
);
1266 return RMAP_RULE_MISSING
;
1268 /* Next call compile function for this match statement. */
1269 if (cmd
->func_compile
) {
1270 compile
= (*cmd
->func_compile
)(set_arg
);
1271 if (compile
== NULL
)
1272 return RMAP_COMPILE_ERROR
;
1276 /* Add by WJL. if old set command of same kind exist, delete it first
1277 to ensure only one set command of same kind exist under a
1279 for (rule
= index
->set_list
.head
; rule
; rule
= next
) {
1281 if (rule
->cmd
== cmd
) {
1282 route_map_rule_delete(&index
->set_list
, rule
);
1287 /* Add new route map match rule. */
1288 rule
= route_map_rule_new();
1290 rule
->value
= compile
;
1292 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, set_arg
);
1294 rule
->rule_str
= NULL
;
1296 /* Add new route match rule to linked list. */
1297 route_map_rule_add(&index
->set_list
, rule
);
1299 /* Execute event hook. */
1300 if (route_map_master
.event_hook
) {
1301 (*route_map_master
.event_hook
)(replaced
1302 ? RMAP_EVENT_SET_REPLACED
1303 : RMAP_EVENT_SET_ADDED
,
1305 route_map_notify_dependencies(index
->map
->name
,
1306 RMAP_EVENT_CALL_ADDED
);
1308 return RMAP_COMPILE_SUCCESS
;
1311 /* Delete route map set rule. */
1312 int route_map_delete_set(struct route_map_index
*index
, const char *set_name
,
1313 const char *set_arg
)
1315 struct route_map_rule
*rule
;
1316 struct route_map_rule_cmd
*cmd
;
1318 cmd
= route_map_lookup_set(set_name
);
1322 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
1323 if ((rule
->cmd
== cmd
) && (rulecmp(rule
->rule_str
, set_arg
) == 0
1324 || set_arg
== NULL
)) {
1325 route_map_rule_delete(&index
->set_list
, rule
);
1326 /* Execute event hook. */
1327 if (route_map_master
.event_hook
) {
1328 (*route_map_master
.event_hook
)(
1329 RMAP_EVENT_SET_DELETED
,
1331 route_map_notify_dependencies(
1333 RMAP_EVENT_CALL_ADDED
);
1337 /* Can't find matched rule. */
1341 /* Apply route map's each index to the object.
1343 The matrix for a route-map looks like this:
1344 (note, this includes the description for the "NEXT"
1345 and "GOTO" frobs now
1349 permit action | cont
1351 ------------------+---------------
1357 -Apply Set statements, accept route
1358 -If Call statement is present jump to the specified route-map, if it
1359 denies the route we finish.
1360 -If NEXT is specified, goto NEXT statement
1361 -If GOTO is specified, goto the first clause where pref > nextpref
1362 -If nothing is specified, do as Cisco and finish
1364 -Route is denied by route-map.
1368 If we get no matches after we've processed all updates, then the route
1371 Some notes on the new "CALL", "NEXT" and "GOTO"
1372 call WORD - If this clause is matched, then the set statements
1373 are executed and then we jump to route-map 'WORD'. If
1374 this route-map denies the route, we finish, in other
1376 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
1377 on-match next - If this clause is matched, then the set statements
1378 are executed and then we drop through to the next clause
1379 on-match goto n - If this clause is matched, then the set statments
1380 are executed and then we goto the nth clause, or the
1381 first clause greater than this. In order to ensure
1382 route-maps *always* exit, you cannot jump backwards.
1385 We need to make sure our route-map processing matches the above
1388 static route_map_result_t
1389 route_map_apply_match(struct route_map_rule_list
*match_list
,
1390 const struct prefix
*prefix
, route_map_object_t type
,
1393 route_map_result_t ret
= RMAP_NOMATCH
;
1394 struct route_map_rule
*match
;
1397 /* Check all match rule and if there is no match rule, go to the
1399 if (!match_list
->head
)
1402 for (match
= match_list
->head
; match
; match
= match
->next
) {
1403 /* Try each match statement in turn, If any do not
1405 RMAP_MATCH, return, otherwise continue on to next
1407 statement. All match statements must match for
1410 ret
= (*match
->cmd
->func_apply
)(match
->value
, prefix
,
1412 if (ret
!= RMAP_MATCH
)
1419 /* Apply route map to the object. */
1420 route_map_result_t
route_map_apply(struct route_map
*map
,
1421 const struct prefix
*prefix
,
1422 route_map_object_t type
, void *object
)
1424 static int recursion
= 0;
1426 struct route_map_index
*index
;
1427 struct route_map_rule
*set
;
1429 if (recursion
> RMAP_RECURSION_LIMIT
) {
1431 "route-map recursion limit (%d) reached, discarding route",
1432 RMAP_RECURSION_LIMIT
);
1434 return RMAP_DENYMATCH
;
1438 return RMAP_DENYMATCH
;
1440 for (index
= map
->head
; index
; index
= index
->next
) {
1441 /* Apply this index. */
1442 ret
= route_map_apply_match(&index
->match_list
, prefix
, type
,
1445 /* Now we apply the matrix from above */
1446 if (ret
== RMAP_NOMATCH
)
1447 /* 'cont' from matrix - continue to next route-map
1450 else if (ret
== RMAP_MATCH
) {
1451 if (index
->type
== RMAP_PERMIT
)
1454 /* permit+match must execute sets */
1455 for (set
= index
->set_list
.head
; set
;
1457 ret
= (*set
->cmd
->func_apply
)(
1458 set
->value
, prefix
, type
,
1461 /* Call another route-map if available */
1462 if (index
->nextrm
) {
1463 struct route_map
*nextrm
=
1464 route_map_lookup_by_name(
1467 if (nextrm
) /* Target route-map found,
1471 ret
= route_map_apply(
1472 nextrm
, prefix
, type
,
1477 /* If nextrm returned 'deny', finish. */
1478 if (ret
== RMAP_DENYMATCH
)
1482 switch (index
->exitpolicy
) {
1488 /* Find the next clause to jump to */
1489 struct route_map_index
*next
=
1491 int nextpref
= index
->nextpref
;
1493 while (next
&& next
->pref
< nextpref
) {
1498 /* No clauses match! */
1503 } else if (index
->type
== RMAP_DENY
)
1506 return RMAP_DENYMATCH
;
1510 /* Finally route-map does not match at all. */
1511 return RMAP_DENYMATCH
;
1514 void route_map_add_hook(void (*func
)(const char *))
1516 route_map_master
.add_hook
= func
;
1519 void route_map_delete_hook(void (*func
)(const char *))
1521 route_map_master
.delete_hook
= func
;
1524 void route_map_event_hook(void (*func
)(route_map_event_t
, const char *))
1526 route_map_master
.event_hook
= func
;
1529 /* Routines for route map dependency lists and dependency processing */
1530 static int route_map_rmap_hash_cmp(const void *p1
, const void *p2
)
1532 return (strcmp((const char *)p1
, (const char *)p2
) == 0);
1535 static int route_map_dep_hash_cmp(const void *p1
, const void *p2
)
1538 return (strcmp(((const struct route_map_dep
*)p1
)->dep_name
,
1543 static void route_map_clear_reference(struct hash_backet
*backet
, void *arg
)
1545 struct route_map_dep
*dep
= (struct route_map_dep
*)backet
->data
;
1550 (char *)hash_release(dep
->dep_rmap_hash
, (void *)arg
);
1552 XFREE(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
1554 if (!dep
->dep_rmap_hash
->count
) {
1555 dep
= hash_release(dep
->this_hash
,
1556 (void *)dep
->dep_name
);
1557 hash_free(dep
->dep_rmap_hash
);
1558 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
1559 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
1564 static void route_map_clear_all_references(char *rmap_name
)
1568 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
1569 hash_iterate(route_map_dep_hash
[i
], route_map_clear_reference
,
1574 static void *route_map_dep_hash_alloc(void *p
)
1576 char *dep_name
= (char *)p
;
1577 struct route_map_dep
*dep_entry
;
1579 dep_entry
= XCALLOC(MTYPE_ROUTE_MAP_DEP
, sizeof(struct route_map_dep
));
1580 dep_entry
->dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1581 dep_entry
->dep_rmap_hash
=
1582 hash_create_size(8, route_map_dep_hash_make_key
,
1583 route_map_rmap_hash_cmp
, "Route Map Dep Hash");
1584 dep_entry
->this_hash
= NULL
;
1586 return ((void *)dep_entry
);
1589 static void *route_map_name_hash_alloc(void *p
)
1591 return ((void *)XSTRDUP(MTYPE_ROUTE_MAP_NAME
, (const char *)p
));
1594 static unsigned int route_map_dep_hash_make_key(void *p
)
1596 return (string_hash_make((char *)p
));
1599 static void route_map_print_dependency(struct hash_backet
*backet
, void *data
)
1601 char *rmap_name
= (char *)backet
->data
;
1602 char *dep_name
= (char *)data
;
1605 zlog_debug("%s: Dependency for %s: %s", __FUNCTION__
, dep_name
,
1609 static int route_map_dep_update(struct hash
*dephash
, const char *dep_name
,
1610 const char *rmap_name
, route_map_event_t type
)
1612 struct route_map_dep
*dep
= NULL
;
1614 char *dname
, *rname
;
1617 dname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1618 rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
1621 case RMAP_EVENT_PLIST_ADDED
:
1622 case RMAP_EVENT_CLIST_ADDED
:
1623 case RMAP_EVENT_ECLIST_ADDED
:
1624 case RMAP_EVENT_ASLIST_ADDED
:
1625 case RMAP_EVENT_LLIST_ADDED
:
1626 case RMAP_EVENT_CALL_ADDED
:
1627 case RMAP_EVENT_FILTER_ADDED
:
1629 zlog_debug("%s: Adding dependency for %s in %s",
1630 __FUNCTION__
, dep_name
, rmap_name
);
1631 dep
= (struct route_map_dep
*)hash_get(
1632 dephash
, dname
, route_map_dep_hash_alloc
);
1638 if (!dep
->this_hash
)
1639 dep
->this_hash
= dephash
;
1641 hash_get(dep
->dep_rmap_hash
, rname
, route_map_name_hash_alloc
);
1643 case RMAP_EVENT_PLIST_DELETED
:
1644 case RMAP_EVENT_CLIST_DELETED
:
1645 case RMAP_EVENT_ECLIST_DELETED
:
1646 case RMAP_EVENT_ASLIST_DELETED
:
1647 case RMAP_EVENT_LLIST_DELETED
:
1648 case RMAP_EVENT_CALL_DELETED
:
1649 case RMAP_EVENT_FILTER_DELETED
:
1651 zlog_debug("%s: Deleting dependency for %s in %s",
1652 __FUNCTION__
, dep_name
, rmap_name
);
1653 dep
= (struct route_map_dep
*)hash_get(dephash
, dname
, NULL
);
1658 ret_map_name
= (char *)hash_release(dep
->dep_rmap_hash
, rname
);
1660 XFREE(MTYPE_ROUTE_MAP_NAME
, ret_map_name
);
1662 if (!dep
->dep_rmap_hash
->count
) {
1663 dep
= hash_release(dephash
, dname
);
1664 hash_free(dep
->dep_rmap_hash
);
1665 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
1666 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
1676 hash_iterate(dep
->dep_rmap_hash
,
1677 route_map_print_dependency
, dname
);
1681 XFREE(MTYPE_ROUTE_MAP_NAME
, rname
);
1682 XFREE(MTYPE_ROUTE_MAP_NAME
, dname
);
1686 static struct hash
*route_map_get_dep_hash(route_map_event_t event
)
1688 struct hash
*upd8_hash
= NULL
;
1691 case RMAP_EVENT_PLIST_ADDED
:
1692 case RMAP_EVENT_PLIST_DELETED
:
1693 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_PLIST
];
1695 case RMAP_EVENT_CLIST_ADDED
:
1696 case RMAP_EVENT_CLIST_DELETED
:
1697 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_CLIST
];
1699 case RMAP_EVENT_ECLIST_ADDED
:
1700 case RMAP_EVENT_ECLIST_DELETED
:
1701 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ECLIST
];
1703 case RMAP_EVENT_ASLIST_ADDED
:
1704 case RMAP_EVENT_ASLIST_DELETED
:
1705 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ASPATH
];
1707 case RMAP_EVENT_LLIST_ADDED
:
1708 case RMAP_EVENT_LLIST_DELETED
:
1709 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_LCLIST
];
1711 case RMAP_EVENT_CALL_ADDED
:
1712 case RMAP_EVENT_CALL_DELETED
:
1713 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_RMAP
];
1715 case RMAP_EVENT_FILTER_ADDED
:
1716 case RMAP_EVENT_FILTER_DELETED
:
1717 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_FILTER
];
1726 static void route_map_process_dependency(struct hash_backet
*backet
, void *data
)
1729 route_map_event_t type
= (route_map_event_t
)(ptrdiff_t)data
;
1731 rmap_name
= (char *)backet
->data
;
1735 zlog_debug("%s: Notifying %s of dependency",
1736 __FUNCTION__
, rmap_name
);
1737 if (route_map_master
.event_hook
)
1738 (*route_map_master
.event_hook
)(type
, rmap_name
);
1742 void route_map_upd8_dependency(route_map_event_t type
, const char *arg
,
1743 const char *rmap_name
)
1745 struct hash
*upd8_hash
= NULL
;
1747 if ((upd8_hash
= route_map_get_dep_hash(type
)))
1748 route_map_dep_update(upd8_hash
, arg
, rmap_name
, type
);
1751 void route_map_notify_dependencies(const char *affected_name
,
1752 route_map_event_t event
)
1754 struct route_map_dep
*dep
;
1755 struct hash
*upd8_hash
;
1761 name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, affected_name
);
1763 if ((upd8_hash
= route_map_get_dep_hash(event
)) == NULL
) {
1764 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
1768 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, name
, NULL
);
1770 if (!dep
->this_hash
)
1771 dep
->this_hash
= upd8_hash
;
1773 hash_iterate(dep
->dep_rmap_hash
, route_map_process_dependency
,
1777 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
1781 /* VTY related functions. */
1782 DEFUN (match_interface
,
1783 match_interface_cmd
,
1784 "match interface WORD",
1786 "match first hop interface of route\n"
1790 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1792 if (rmap_match_set_hook
.match_interface
)
1793 return rmap_match_set_hook
.match_interface(
1794 vty
, index
, "interface", argv
[idx_word
]->arg
,
1795 RMAP_EVENT_MATCH_ADDED
);
1799 DEFUN (no_match_interface
,
1800 no_match_interface_cmd
,
1801 "no match interface [WORD]",
1804 "Match first hop interface of route\n"
1807 char *iface
= (argc
== 4) ? argv
[3]->arg
: NULL
;
1808 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1810 if (rmap_match_set_hook
.no_match_interface
)
1811 return rmap_match_set_hook
.no_match_interface(
1812 vty
, index
, "interface", iface
,
1813 RMAP_EVENT_MATCH_DELETED
);
1818 DEFUN (match_ip_address
,
1819 match_ip_address_cmd
,
1820 "match ip address <(1-199)|(1300-2699)|WORD>",
1823 "Match address of route\n"
1824 "IP access-list number\n"
1825 "IP access-list number (expanded range)\n"
1826 "IP Access-list name\n")
1829 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1831 if (rmap_match_set_hook
.match_ip_address
)
1832 return rmap_match_set_hook
.match_ip_address(
1833 vty
, index
, "ip address", argv
[idx_acl
]->arg
,
1834 RMAP_EVENT_FILTER_ADDED
);
1839 DEFUN (no_match_ip_address
,
1840 no_match_ip_address_cmd
,
1841 "no match ip address [<(1-199)|(1300-2699)|WORD>]",
1845 "Match address of route\n"
1846 "IP access-list number\n"
1847 "IP access-list number (expanded range)\n"
1848 "IP Access-list name\n")
1851 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1853 if (rmap_match_set_hook
.no_match_ip_address
) {
1854 if (argc
<= idx_word
)
1855 return rmap_match_set_hook
.no_match_ip_address(
1856 vty
, index
, "ip address", NULL
,
1857 RMAP_EVENT_FILTER_DELETED
);
1858 return rmap_match_set_hook
.no_match_ip_address(
1859 vty
, index
, "ip address", argv
[idx_word
]->arg
,
1860 RMAP_EVENT_FILTER_DELETED
);
1866 DEFUN (match_ip_address_prefix_list
,
1867 match_ip_address_prefix_list_cmd
,
1868 "match ip address prefix-list WORD",
1871 "Match address of route\n"
1872 "Match entries of prefix-lists\n"
1873 "IP prefix-list name\n")
1876 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1878 if (rmap_match_set_hook
.match_ip_address_prefix_list
)
1879 return rmap_match_set_hook
.match_ip_address_prefix_list(
1880 vty
, index
, "ip address prefix-list",
1881 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
1886 DEFUN (no_match_ip_address_prefix_list
,
1887 no_match_ip_address_prefix_list_cmd
,
1888 "no match ip address prefix-list [WORD]",
1892 "Match address of route\n"
1893 "Match entries of prefix-lists\n"
1894 "IP prefix-list name\n")
1897 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1899 if (rmap_match_set_hook
.no_match_ip_address_prefix_list
) {
1900 if (argc
<= idx_word
)
1901 return rmap_match_set_hook
1902 .no_match_ip_address_prefix_list(
1903 vty
, index
, "ip address prefix-list",
1904 NULL
, RMAP_EVENT_PLIST_DELETED
);
1905 return rmap_match_set_hook
.no_match_ip_address_prefix_list(
1906 vty
, index
, "ip address prefix-list",
1907 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
1913 DEFUN (match_ip_next_hop
,
1914 match_ip_next_hop_cmd
,
1915 "match ip next-hop <(1-199)|(1300-2699)|WORD>",
1918 "Match next-hop address of route\n"
1919 "IP access-list number\n"
1920 "IP access-list number (expanded range)\n"
1921 "IP Access-list name\n")
1924 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1926 if (rmap_match_set_hook
.match_ip_next_hop
)
1927 return rmap_match_set_hook
.match_ip_next_hop(
1928 vty
, index
, "ip next-hop", argv
[idx_acl
]->arg
,
1929 RMAP_EVENT_FILTER_ADDED
);
1934 DEFUN (no_match_ip_next_hop
,
1935 no_match_ip_next_hop_cmd
,
1936 "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
1940 "Match next-hop address of route\n"
1941 "IP access-list number\n"
1942 "IP access-list number (expanded range)\n"
1943 "IP Access-list name\n")
1946 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1948 if (rmap_match_set_hook
.no_match_ip_next_hop
) {
1949 if (argc
<= idx_word
)
1950 return rmap_match_set_hook
.no_match_ip_next_hop(
1951 vty
, index
, "ip next-hop", NULL
,
1952 RMAP_EVENT_FILTER_DELETED
);
1953 return rmap_match_set_hook
.no_match_ip_next_hop(
1954 vty
, index
, "ip next-hop", argv
[idx_word
]->arg
,
1955 RMAP_EVENT_FILTER_DELETED
);
1961 DEFUN (match_ip_next_hop_prefix_list
,
1962 match_ip_next_hop_prefix_list_cmd
,
1963 "match ip next-hop prefix-list WORD",
1966 "Match next-hop address of route\n"
1967 "Match entries of prefix-lists\n"
1968 "IP prefix-list name\n")
1971 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1973 if (rmap_match_set_hook
.match_ip_next_hop_prefix_list
)
1974 return rmap_match_set_hook
.match_ip_next_hop_prefix_list(
1975 vty
, index
, "ip next-hop prefix-list",
1976 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
1980 DEFUN (no_match_ip_next_hop_prefix_list
,
1981 no_match_ip_next_hop_prefix_list_cmd
,
1982 "no match ip next-hop prefix-list [WORD]",
1986 "Match next-hop address of route\n"
1987 "Match entries of prefix-lists\n"
1988 "IP prefix-list name\n")
1991 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1993 if (rmap_match_set_hook
.no_match_ip_next_hop
) {
1994 if (argc
<= idx_word
)
1995 return rmap_match_set_hook
.no_match_ip_next_hop(
1996 vty
, index
, "ip next-hop prefix-list", NULL
,
1997 RMAP_EVENT_PLIST_DELETED
);
1998 return rmap_match_set_hook
.no_match_ip_next_hop(
1999 vty
, index
, "ip next-hop prefix-list",
2000 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2006 DEFUN (match_ipv6_address
,
2007 match_ipv6_address_cmd
,
2008 "match ipv6 address WORD",
2011 "Match IPv6 address of route\n"
2012 "IPv6 access-list name\n")
2015 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2017 if (rmap_match_set_hook
.match_ipv6_address
)
2018 return rmap_match_set_hook
.match_ipv6_address(
2019 vty
, index
, "ipv6 address", argv
[idx_word
]->arg
,
2020 RMAP_EVENT_FILTER_ADDED
);
2024 DEFUN (no_match_ipv6_address
,
2025 no_match_ipv6_address_cmd
,
2026 "no match ipv6 address WORD",
2030 "Match IPv6 address of route\n"
2031 "IPv6 access-list name\n")
2034 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2036 if (rmap_match_set_hook
.no_match_ipv6_address
)
2037 return rmap_match_set_hook
.no_match_ipv6_address(
2038 vty
, index
, "ipv6 address", argv
[idx_word
]->arg
,
2039 RMAP_EVENT_FILTER_DELETED
);
2044 DEFUN (match_ipv6_address_prefix_list
,
2045 match_ipv6_address_prefix_list_cmd
,
2046 "match ipv6 address prefix-list WORD",
2049 "Match address of route\n"
2050 "Match entries of prefix-lists\n"
2051 "IP prefix-list name\n")
2054 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2056 if (rmap_match_set_hook
.match_ipv6_address_prefix_list
)
2057 return rmap_match_set_hook
.match_ipv6_address_prefix_list(
2058 vty
, index
, "ipv6 address prefix-list",
2059 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
2063 DEFUN (no_match_ipv6_address_prefix_list
,
2064 no_match_ipv6_address_prefix_list_cmd
,
2065 "no match ipv6 address prefix-list WORD",
2069 "Match address of route\n"
2070 "Match entries of prefix-lists\n"
2071 "IP prefix-list name\n")
2074 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2076 if (rmap_match_set_hook
.no_match_ipv6_address_prefix_list
)
2077 return rmap_match_set_hook
.no_match_ipv6_address_prefix_list(
2078 vty
, index
, "ipv6 address prefix-list",
2079 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2084 DEFUN (match_metric
,
2086 "match metric (0-4294967295)",
2088 "Match metric of route\n"
2092 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2094 if (rmap_match_set_hook
.match_metric
)
2095 return rmap_match_set_hook
.match_metric(vty
, index
, "metric",
2096 argv
[idx_number
]->arg
,
2097 RMAP_EVENT_MATCH_ADDED
);
2102 DEFUN (no_match_metric
,
2103 no_match_metric_cmd
,
2104 "no match metric [(0-4294967295)]",
2107 "Match metric of route\n"
2111 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2113 if (rmap_match_set_hook
.no_match_metric
) {
2114 if (argc
<= idx_number
)
2115 return rmap_match_set_hook
.no_match_metric(
2116 vty
, index
, "metric", NULL
,
2117 RMAP_EVENT_MATCH_DELETED
);
2118 return rmap_match_set_hook
.no_match_metric(
2119 vty
, index
, "metric", argv
[idx_number
]->arg
,
2120 RMAP_EVENT_MATCH_DELETED
);
2128 "match tag (1-4294967295)",
2130 "Match tag of route\n"
2134 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2136 if (rmap_match_set_hook
.match_tag
)
2137 return rmap_match_set_hook
.match_tag(vty
, index
, "tag",
2138 argv
[idx_number
]->arg
,
2139 RMAP_EVENT_MATCH_ADDED
);
2144 DEFUN (no_match_tag
,
2146 "no match tag [(1-4294967295)]",
2149 "Match tag of route\n"
2152 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2155 char *arg
= argv_find(argv
, argc
, "(1-4294967295)", &idx
)
2159 if (rmap_match_set_hook
.no_match_tag
)
2160 return rmap_match_set_hook
.no_match_tag(
2161 vty
, index
, "tag", arg
, RMAP_EVENT_MATCH_DELETED
);
2166 DEFUN (set_ip_nexthop
,
2168 "set ip next-hop A.B.C.D",
2171 "Next hop address\n"
2172 "IP address of next hop\n")
2177 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2179 ret
= str2sockunion(argv
[idx_ipv4
]->arg
, &su
);
2181 vty_out(vty
, "%% Malformed nexthop address\n");
2182 return CMD_WARNING_CONFIG_FAILED
;
2184 if (su
.sin
.sin_addr
.s_addr
== 0
2185 || IPV4_CLASS_DE(ntohl(su
.sin
.sin_addr
.s_addr
))) {
2187 "%% nexthop address cannot be 0.0.0.0, multicast or reserved\n");
2188 return CMD_WARNING_CONFIG_FAILED
;
2191 if (rmap_match_set_hook
.set_ip_nexthop
)
2192 return rmap_match_set_hook
.set_ip_nexthop(
2193 vty
, index
, "ip next-hop", argv
[idx_ipv4
]->arg
);
2198 DEFUN (no_set_ip_nexthop
,
2199 no_set_ip_nexthop_cmd
,
2200 "no set ip next-hop [A.B.C.D]",
2204 "Next hop address\n"
2205 "IP address of next hop\n")
2208 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2209 const char *arg
= NULL
;
2211 if (argv_find(argv
, argc
, "A.B.C.D", &idx
))
2212 arg
= argv
[idx
]->arg
;
2214 if (rmap_match_set_hook
.no_set_ip_nexthop
)
2215 return rmap_match_set_hook
.no_set_ip_nexthop(
2216 vty
, index
, "ip next-hop", arg
);
2222 DEFUN (set_ipv6_nexthop_local
,
2223 set_ipv6_nexthop_local_cmd
,
2224 "set ipv6 next-hop local X:X::X:X",
2227 "IPv6 next-hop address\n"
2228 "IPv6 local address\n"
2229 "IPv6 address of next hop\n")
2232 struct in6_addr addr
;
2234 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2236 ret
= inet_pton(AF_INET6
, argv
[idx_ipv6
]->arg
, &addr
);
2238 vty_out(vty
, "%% Malformed nexthop address\n");
2239 return CMD_WARNING_CONFIG_FAILED
;
2241 if (!IN6_IS_ADDR_LINKLOCAL(&addr
)) {
2242 vty_out(vty
, "%% Invalid link-local nexthop address\n");
2243 return CMD_WARNING_CONFIG_FAILED
;
2246 if (rmap_match_set_hook
.set_ipv6_nexthop_local
)
2247 return rmap_match_set_hook
.set_ipv6_nexthop_local(
2248 vty
, index
, "ipv6 next-hop local", argv
[idx_ipv6
]->arg
);
2253 DEFUN (no_set_ipv6_nexthop_local
,
2254 no_set_ipv6_nexthop_local_cmd
,
2255 "no set ipv6 next-hop local [X:X::X:X]",
2259 "IPv6 next-hop address\n"
2260 "IPv6 local address\n"
2261 "IPv6 address of next hop\n")
2264 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2266 if (rmap_match_set_hook
.no_set_ipv6_nexthop_local
) {
2267 if (argc
<= idx_ipv6
)
2268 return rmap_match_set_hook
.no_set_ipv6_nexthop_local(
2269 vty
, index
, "ipv6 next-hop local", NULL
);
2270 return rmap_match_set_hook
.no_set_ipv6_nexthop_local(
2271 vty
, index
, "ipv6 next-hop local", argv
[5]->arg
);
2278 "set metric <(0-4294967295)|rtt|+rtt|-rtt|+metric|-metric>",
2280 "Metric value for destination routing protocol\n"
2282 "Assign round trip time\n"
2283 "Add round trip time\n"
2284 "Subtract round trip time\n"
2286 "Subtract metric\n")
2289 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2291 const char *pass
= (argv
[idx_number
]->type
== RANGE_TKN
)
2292 ? argv
[idx_number
]->arg
2293 : argv
[idx_number
]->text
;
2295 if (rmap_match_set_hook
.set_metric
)
2296 return rmap_match_set_hook
.set_metric(vty
, index
, "metric",
2302 DEFUN (no_set_metric
,
2304 "no set metric [(0-4294967295)]",
2307 "Metric value for destination routing protocol\n"
2311 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2313 if (rmap_match_set_hook
.no_set_metric
) {
2314 if (argc
<= idx_number
)
2315 return rmap_match_set_hook
.no_set_metric(
2316 vty
, index
, "metric", NULL
);
2317 return rmap_match_set_hook
.no_set_metric(vty
, index
, "metric",
2318 argv
[idx_number
]->arg
);
2326 "set tag (1-4294967295)",
2328 "Tag value for routing protocol\n"
2331 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2334 if (rmap_match_set_hook
.set_tag
)
2335 return rmap_match_set_hook
.set_tag(vty
, index
, "tag",
2336 argv
[idx_number
]->arg
);
2343 "no set tag [(1-4294967295)]",
2346 "Tag value for routing protocol\n"
2349 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2352 if (rmap_match_set_hook
.no_set_tag
) {
2353 if (argc
<= idx_number
)
2354 return rmap_match_set_hook
.no_set_tag(vty
, index
, "tag",
2356 return rmap_match_set_hook
.no_set_tag(vty
, index
, "tag",
2357 argv
[idx_number
]->arg
);
2363 DEFUN_NOSH (route_map
,
2365 "route-map WORD <deny|permit> (1-65535)",
2366 "Create route-map or enter route-map command mode\n"
2368 "Route map denies set operations\n"
2369 "Route map permits set operations\n"
2370 "Sequence to insert to/delete from existing route-map entry\n")
2373 int idx_permit_deny
= 2;
2375 struct route_map
*map
;
2376 struct route_map_index
*index
;
2377 char *endptr
= NULL
;
2379 argv
[idx_permit_deny
]->arg
[0] == 'p' ? RMAP_PERMIT
: RMAP_DENY
;
2380 unsigned long pref
= strtoul(argv
[idx_number
]->arg
, &endptr
, 10);
2381 const char *mapname
= argv
[idx_word
]->arg
;
2383 /* Get route map. */
2384 map
= route_map_get(mapname
);
2385 index
= route_map_index_get(map
, permit
, pref
);
2387 VTY_PUSH_CONTEXT(RMAP_NODE
, index
);
2391 DEFUN (no_route_map_all
,
2392 no_route_map_all_cmd
,
2393 "no route-map WORD",
2395 "Create route-map or enter route-map command mode\n"
2399 const char *mapname
= argv
[idx_word
]->arg
;
2400 struct route_map
*map
;
2402 map
= route_map_lookup_by_name(mapname
);
2404 vty_out(vty
, "%% Could not find route-map %s\n", mapname
);
2405 return CMD_WARNING_CONFIG_FAILED
;
2408 route_map_delete(map
);
2413 DEFUN (no_route_map
,
2415 "no route-map WORD <deny|permit> (1-65535)",
2417 "Create route-map or enter route-map command mode\n"
2419 "Route map denies set operations\n"
2420 "Route map permits set operations\n"
2421 "Sequence to insert to/delete from existing route-map entry\n")
2424 int idx_permit_deny
= 3;
2426 struct route_map
*map
;
2427 struct route_map_index
*index
;
2428 char *endptr
= NULL
;
2429 int permit
= strmatch(argv
[idx_permit_deny
]->text
, "permit")
2432 const char *prefstr
= argv
[idx_number
]->arg
;
2433 const char *mapname
= argv
[idx_word
]->arg
;
2434 unsigned long pref
= strtoul(prefstr
, &endptr
, 10);
2436 /* Existence check. */
2437 map
= route_map_lookup_by_name(mapname
);
2439 vty_out(vty
, "%% Could not find route-map %s\n", mapname
);
2440 return CMD_WARNING_CONFIG_FAILED
;
2443 /* Lookup route map index. */
2444 index
= route_map_index_lookup(map
, permit
, pref
);
2445 if (index
== NULL
) {
2446 vty_out(vty
, "%% Could not find route-map entry %s %s\n",
2448 return CMD_WARNING_CONFIG_FAILED
;
2451 /* Delete index from route map. */
2452 route_map_index_delete(index
, 1);
2454 /* If this route rule is the last one, delete route map itself. */
2455 if (route_map_empty(map
))
2456 route_map_delete(map
);
2461 DEFUN (rmap_onmatch_next
,
2462 rmap_onmatch_next_cmd
,
2464 "Exit policy on matches\n"
2467 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2470 if (index
->type
== RMAP_DENY
) {
2471 /* Under a deny clause, match means it's finished. No
2472 * need to set next */
2474 "on-match next not supported under route-map deny\n");
2475 return CMD_WARNING_CONFIG_FAILED
;
2477 index
->exitpolicy
= RMAP_NEXT
;
2482 DEFUN (no_rmap_onmatch_next
,
2483 no_rmap_onmatch_next_cmd
,
2486 "Exit policy on matches\n"
2489 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2492 index
->exitpolicy
= RMAP_EXIT
;
2497 DEFUN (rmap_onmatch_goto
,
2498 rmap_onmatch_goto_cmd
,
2499 "on-match goto (1-65535)",
2500 "Exit policy on matches\n"
2501 "Goto Clause number\n"
2505 char *num
= argv_find(argv
, argc
, "(1-65535)", &idx
) ? argv
[idx
]->arg
2508 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2512 if (index
->type
== RMAP_DENY
) {
2513 /* Under a deny clause, match means it's finished. No
2514 * need to go anywhere */
2516 "on-match goto not supported under route-map deny\n");
2517 return CMD_WARNING_CONFIG_FAILED
;
2521 d
= strtoul(num
, NULL
, 10);
2523 d
= index
->pref
+ 1;
2525 if (d
<= index
->pref
) {
2526 /* Can't allow you to do that, Dave */
2527 vty_out(vty
, "can't jump backwards in route-maps\n");
2528 return CMD_WARNING_CONFIG_FAILED
;
2530 index
->exitpolicy
= RMAP_GOTO
;
2531 index
->nextpref
= d
;
2537 DEFUN (no_rmap_onmatch_goto
,
2538 no_rmap_onmatch_goto_cmd
,
2541 "Exit policy on matches\n"
2542 "Goto Clause number\n")
2544 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2547 index
->exitpolicy
= RMAP_EXIT
;
2552 /* Cisco/GNU Zebra compatibility aliases */
2554 DEFUN (rmap_continue
,
2556 "continue (1-65535)",
2557 "Continue on a different entry within the route-map\n"
2558 "Route-map entry sequence number\n")
2560 return rmap_onmatch_goto(self
, vty
, argc
, argv
);
2564 DEFUN (no_rmap_continue
,
2565 no_rmap_continue_cmd
,
2566 "no continue [(1-65535)]",
2568 "Continue on a different entry within the route-map\n"
2569 "Route-map entry sequence number\n")
2571 return no_rmap_onmatch_goto(self
, vty
, argc
, argv
);
2575 DEFUN (rmap_show_name
,
2577 "show route-map [WORD]",
2579 "route-map information\n"
2583 const char *name
= (argc
== 3) ? argv
[idx_word
]->arg
: NULL
;
2584 return vty_show_route_map(vty
, name
);
2590 "Jump to another Route-Map after match+set\n"
2591 "Target route-map name\n")
2594 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2595 const char *rmap
= argv
[idx_word
]->arg
;
2599 if (index
->nextrm
) {
2600 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED
,
2601 index
->nextrm
, index
->map
->name
);
2602 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
2604 index
->nextrm
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap
);
2606 /* Execute event hook. */
2607 route_map_upd8_dependency(RMAP_EVENT_CALL_ADDED
, index
->nextrm
,
2612 DEFUN (no_rmap_call
,
2616 "Jump to another Route-Map after match+set\n")
2618 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2620 if (index
->nextrm
) {
2621 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED
,
2622 index
->nextrm
, index
->map
->name
);
2623 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
2624 index
->nextrm
= NULL
;
2630 DEFUN (rmap_description
,
2631 rmap_description_cmd
,
2632 "description LINE...",
2633 "Route-map comment\n"
2634 "Comment describing this route-map rule\n")
2637 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2640 if (index
->description
)
2641 XFREE(MTYPE_TMP
, index
->description
);
2642 index
->description
= argv_concat(argv
, argc
, idx_line
);
2647 DEFUN (no_rmap_description
,
2648 no_rmap_description_cmd
,
2651 "Route-map comment\n")
2653 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2656 if (index
->description
)
2657 XFREE(MTYPE_TMP
, index
->description
);
2658 index
->description
= NULL
;
2663 /* Configuration write function. */
2664 static int route_map_config_write(struct vty
*vty
)
2666 struct route_map
*map
;
2667 struct route_map_index
*index
;
2668 struct route_map_rule
*rule
;
2672 for (map
= route_map_master
.head
; map
; map
= map
->next
)
2673 for (index
= map
->head
; index
; index
= index
->next
) {
2675 vty_out(vty
, "!\n");
2679 vty_out(vty
, "route-map %s %s %d\n", map
->name
,
2680 route_map_type_str(index
->type
), index
->pref
);
2682 if (index
->description
)
2683 vty_out(vty
, " description %s\n",
2684 index
->description
);
2686 for (rule
= index
->match_list
.head
; rule
;
2688 vty_out(vty
, " match %s %s\n", rule
->cmd
->str
,
2689 rule
->rule_str
? rule
->rule_str
: "");
2691 for (rule
= index
->set_list
.head
; rule
;
2693 vty_out(vty
, " set %s %s\n", rule
->cmd
->str
,
2694 rule
->rule_str
? rule
->rule_str
: "");
2696 vty_out(vty
, " call %s\n", index
->nextrm
);
2697 if (index
->exitpolicy
== RMAP_GOTO
)
2698 vty_out(vty
, " on-match goto %d\n",
2700 if (index
->exitpolicy
== RMAP_NEXT
)
2701 vty_out(vty
, " on-match next\n");
2708 /* Route map node structure. */
2709 static struct cmd_node rmap_node
= {RMAP_NODE
, "%s(config-route-map)# ", 1};
2711 /* Common route map rules */
2713 void *route_map_rule_tag_compile(const char *arg
)
2715 unsigned long int tmp
;
2720 tmp
= strtoul(arg
, &endptr
, 0);
2721 if (arg
[0] == '\0' || *endptr
!= '\0' || errno
|| tmp
> ROUTE_TAG_MAX
)
2724 tag
= XMALLOC(MTYPE_ROUTE_MAP_COMPILED
, sizeof(*tag
));
2730 void route_map_rule_tag_free(void *rule
)
2732 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
2735 void route_map_finish(void)
2739 vector_free(route_match_vec
);
2740 route_match_vec
= NULL
;
2741 vector_free(route_set_vec
);
2742 route_set_vec
= NULL
;
2744 /* cleanup route_map */
2745 while (route_map_master
.head
) {
2746 struct route_map
*map
= route_map_master
.head
;
2747 map
->to_be_processed
= false;
2748 route_map_delete(map
);
2751 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
2752 hash_free(route_map_dep_hash
[i
]);
2753 route_map_dep_hash
[i
] = NULL
;
2756 hash_free(route_map_master_hash
);
2757 route_map_master_hash
= NULL
;
2760 static void rmap_autocomplete(vector comps
, struct cmd_token
*token
)
2762 struct route_map
*map
;
2764 for (map
= route_map_master
.head
; map
; map
= map
->next
)
2765 vector_set(comps
, XSTRDUP(MTYPE_COMPLETION
, map
->name
));
2768 static const struct cmd_variable_handler rmap_var_handlers
[] = {
2769 {/* "route-map WORD" */
2770 .varname
= "route_map",
2771 .completions
= rmap_autocomplete
},
2772 {.tokenname
= "ROUTEMAP_NAME", .completions
= rmap_autocomplete
},
2773 {.tokenname
= "RMAP_NAME", .completions
= rmap_autocomplete
},
2774 {.completions
= NULL
}};
2776 /* Initialization of route map vector. */
2777 void route_map_init(void)
2781 /* Make vector for match and set. */
2782 route_match_vec
= vector_init(1);
2783 route_set_vec
= vector_init(1);
2784 route_map_master_hash
=
2785 hash_create_size(8, route_map_hash_key_make
, route_map_hash_cmp
,
2786 "Route Map Master Hash");
2788 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++)
2789 route_map_dep_hash
[i
] = hash_create_size(
2790 8, route_map_dep_hash_make_key
, route_map_dep_hash_cmp
,
2791 "Route Map Dep Hash");
2793 cmd_variable_handler_register(rmap_var_handlers
);
2795 /* Install route map top node. */
2796 install_node(&rmap_node
, route_map_config_write
);
2798 /* Install route map commands. */
2799 install_default(RMAP_NODE
);
2800 install_element(CONFIG_NODE
, &route_map_cmd
);
2801 install_element(CONFIG_NODE
, &no_route_map_cmd
);
2802 install_element(CONFIG_NODE
, &no_route_map_all_cmd
);
2804 /* Install the on-match stuff */
2805 install_element(RMAP_NODE
, &route_map_cmd
);
2806 install_element(RMAP_NODE
, &rmap_onmatch_next_cmd
);
2807 install_element(RMAP_NODE
, &no_rmap_onmatch_next_cmd
);
2808 install_element(RMAP_NODE
, &rmap_onmatch_goto_cmd
);
2809 install_element(RMAP_NODE
, &no_rmap_onmatch_goto_cmd
);
2810 install_element(RMAP_NODE
, &rmap_continue_cmd
);
2811 install_element(RMAP_NODE
, &no_rmap_continue_cmd
);
2813 /* Install the continue stuff (ALIAS of on-match). */
2815 /* Install the call stuff. */
2816 install_element(RMAP_NODE
, &rmap_call_cmd
);
2817 install_element(RMAP_NODE
, &no_rmap_call_cmd
);
2819 /* Install description commands. */
2820 install_element(RMAP_NODE
, &rmap_description_cmd
);
2821 install_element(RMAP_NODE
, &no_rmap_description_cmd
);
2823 /* Install show command */
2824 install_element(ENABLE_NODE
, &rmap_show_name_cmd
);
2826 install_element(RMAP_NODE
, &match_interface_cmd
);
2827 install_element(RMAP_NODE
, &no_match_interface_cmd
);
2829 install_element(RMAP_NODE
, &match_ip_address_cmd
);
2830 install_element(RMAP_NODE
, &no_match_ip_address_cmd
);
2832 install_element(RMAP_NODE
, &match_ip_address_prefix_list_cmd
);
2833 install_element(RMAP_NODE
, &no_match_ip_address_prefix_list_cmd
);
2835 install_element(RMAP_NODE
, &match_ip_next_hop_cmd
);
2836 install_element(RMAP_NODE
, &no_match_ip_next_hop_cmd
);
2838 install_element(RMAP_NODE
, &match_ip_next_hop_prefix_list_cmd
);
2839 install_element(RMAP_NODE
, &no_match_ip_next_hop_prefix_list_cmd
);
2841 install_element(RMAP_NODE
, &match_ipv6_address_cmd
);
2842 install_element(RMAP_NODE
, &no_match_ipv6_address_cmd
);
2844 install_element(RMAP_NODE
, &match_ipv6_address_prefix_list_cmd
);
2845 install_element(RMAP_NODE
, &no_match_ipv6_address_prefix_list_cmd
);
2847 install_element(RMAP_NODE
, &match_metric_cmd
);
2848 install_element(RMAP_NODE
, &no_match_metric_cmd
);
2850 install_element(RMAP_NODE
, &match_tag_cmd
);
2851 install_element(RMAP_NODE
, &no_match_tag_cmd
);
2853 install_element(RMAP_NODE
, &set_ip_nexthop_cmd
);
2854 install_element(RMAP_NODE
, &no_set_ip_nexthop_cmd
);
2856 install_element(RMAP_NODE
, &set_ipv6_nexthop_local_cmd
);
2857 install_element(RMAP_NODE
, &no_set_ipv6_nexthop_local_cmd
);
2859 install_element(RMAP_NODE
, &set_metric_cmd
);
2860 install_element(RMAP_NODE
, &no_set_metric_cmd
);
2862 install_element(RMAP_NODE
, &set_tag_cmd
);
2863 install_element(RMAP_NODE
, &no_set_tag_cmd
);