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",
428 return CMD_WARNING_CONFIG_FAILED
;
430 case RMAP_COMPILE_ERROR
:
432 "%% [%s] Argument form is unsupported or malformed.\n",
434 return CMD_WARNING_CONFIG_FAILED
;
441 int generic_match_delete(struct vty
*vty
, struct route_map_index
*index
,
442 const char *command
, const char *arg
,
443 route_map_event_t type
)
446 int retval
= CMD_SUCCESS
;
447 char *dep_name
= NULL
;
449 char *rmap_name
= NULL
;
451 if (type
!= RMAP_EVENT_MATCH_DELETED
) {
452 /* ignore the mundane, the types without any dependency */
454 if ((tmpstr
= route_map_get_match_arg(index
, command
))
457 XSTRDUP(MTYPE_ROUTE_MAP_RULE
, tmpstr
);
459 dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_RULE
, arg
);
461 rmap_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, index
->map
->name
);
464 ret
= route_map_delete_match(index
, command
, dep_name
);
466 case RMAP_RULE_MISSING
:
467 vty_out(vty
, "%% [%s] Can't find rule.\n",
469 retval
= CMD_WARNING_CONFIG_FAILED
;
471 case RMAP_COMPILE_ERROR
:
473 "%% [%s] Argument form is unsupported or malformed.\n",
475 retval
= CMD_WARNING_CONFIG_FAILED
;
477 case RMAP_COMPILE_SUCCESS
:
478 if (type
!= RMAP_EVENT_MATCH_DELETED
&& dep_name
)
479 route_map_upd8_dependency(type
, dep_name
, rmap_name
);
484 XFREE(MTYPE_ROUTE_MAP_RULE
, dep_name
);
486 XFREE(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
491 int generic_set_add(struct vty
*vty
, struct route_map_index
*index
,
492 const char *command
, const char *arg
)
496 ret
= route_map_add_set(index
, command
, arg
);
498 case RMAP_RULE_MISSING
:
499 vty_out(vty
, "%% [%s] Can't find rule.\n",
501 return CMD_WARNING_CONFIG_FAILED
;
503 case RMAP_COMPILE_ERROR
:
505 "%% [%s] Argument form is unsupported or malformed.\n",
507 return CMD_WARNING_CONFIG_FAILED
;
509 case RMAP_COMPILE_SUCCESS
:
516 int generic_set_delete(struct vty
*vty
, struct route_map_index
*index
,
517 const char *command
, const char *arg
)
521 ret
= route_map_delete_set(index
, command
, arg
);
523 case RMAP_RULE_MISSING
:
524 vty_out(vty
, "%% [%s] Can't find rule.\n",
526 return CMD_WARNING_CONFIG_FAILED
;
528 case RMAP_COMPILE_ERROR
:
530 "%% [%s] Argument form is unsupported or malformed.\n",
532 return CMD_WARNING_CONFIG_FAILED
;
534 case RMAP_COMPILE_SUCCESS
:
542 /* Route map rule. This rule has both `match' rule and `set' rule. */
543 struct route_map_rule
{
545 struct route_map_rule_cmd
*cmd
;
547 /* For pretty printing. */
550 /* Pre-compiled match rule. */
554 struct route_map_rule
*next
;
555 struct route_map_rule
*prev
;
558 /* Making route map list. */
559 struct route_map_list
{
560 struct route_map
*head
;
561 struct route_map
*tail
;
563 void (*add_hook
)(const char *);
564 void (*delete_hook
)(const char *);
565 void (*event_hook
)(route_map_event_t
, const char *);
568 /* Master list of route map. */
569 static struct route_map_list route_map_master
= {NULL
, NULL
, NULL
, NULL
, NULL
};
570 struct hash
*route_map_master_hash
= NULL
;
572 static unsigned int route_map_hash_key_make(void *p
)
574 const struct route_map
*map
= p
;
575 return string_hash_make(map
->name
);
578 static int route_map_hash_cmp(const void *p1
, const void *p2
)
580 const struct route_map
*map1
= p1
;
581 const struct route_map
*map2
= p2
;
583 if (map1
->deleted
== map2
->deleted
) {
584 if (map1
->name
&& map2
->name
) {
585 if (!strcmp(map1
->name
, map2
->name
)) {
588 } else if (!map1
->name
&& !map2
->name
) {
596 enum route_map_upd8_type
{
601 /* all possible route-map dependency types */
602 enum route_map_dep_type
{
603 ROUTE_MAP_DEP_RMAP
= 1,
605 ROUTE_MAP_DEP_ECLIST
,
606 ROUTE_MAP_DEP_LCLIST
,
608 ROUTE_MAP_DEP_ASPATH
,
609 ROUTE_MAP_DEP_FILTER
,
613 struct route_map_dep
{
615 struct hash
*dep_rmap_hash
;
616 struct hash
*this_hash
; /* ptr to the hash structure this is part of */
619 /* Hashes maintaining dependency between various sublists used by route maps */
620 struct hash
*route_map_dep_hash
[ROUTE_MAP_DEP_MAX
];
622 static unsigned int route_map_dep_hash_make_key(void *p
);
623 static int route_map_dep_hash_cmp(const void *p1
, const void *p2
);
624 static void route_map_clear_all_references(char *rmap_name
);
625 static void route_map_rule_delete(struct route_map_rule_list
*,
626 struct route_map_rule
*);
627 static int rmap_debug
= 0;
629 static void route_map_index_delete(struct route_map_index
*, int);
631 /* New route map allocation. Please note route map's name must be
633 static struct route_map
*route_map_new(const char *name
)
635 struct route_map
*new;
637 new = XCALLOC(MTYPE_ROUTE_MAP
, sizeof(struct route_map
));
638 new->name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
639 QOBJ_REG(new, route_map
);
643 /* Add new name to route_map. */
644 static struct route_map
*route_map_add(const char *name
)
646 struct route_map
*map
;
647 struct route_map_list
*list
;
649 map
= route_map_new(name
);
650 list
= &route_map_master
;
652 /* Add map to the hash */
653 hash_get(route_map_master_hash
, map
, hash_alloc_intern
);
655 /* Add new entry to the head of the list to match how it is added in the
656 * hash table. This is to ensure that if the same route-map has been
657 * created more than once and then marked for deletion (which can happen
658 * if prior deletions haven't completed as BGP hasn't yet done the
659 * route-map processing), the order of the entities is the same in both
660 * the list and the hash table. Otherwise, since there is nothing to
661 * distinguish between the two entries, the wrong entry could get freed.
662 * TODO: This needs to be re-examined to handle it better - e.g., revive
663 * a deleted entry if the route-map is created again.
666 map
->next
= list
->head
;
668 list
->head
->prev
= map
;
674 if (route_map_master
.add_hook
) {
675 (*route_map_master
.add_hook
)(name
);
676 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_ADDED
);
681 /* this is supposed to be called post processing by
682 * the delete hook function. Don't invoke delete_hook
683 * again in this routine.
685 static void route_map_free_map(struct route_map
*map
)
687 struct route_map_list
*list
;
688 struct route_map_index
*index
;
693 while ((index
= map
->head
) != NULL
)
694 route_map_index_delete(index
, 0);
696 list
= &route_map_master
;
701 map
->next
->prev
= map
->prev
;
703 list
->tail
= map
->prev
;
706 map
->prev
->next
= map
->next
;
708 list
->head
= map
->next
;
710 hash_release(route_map_master_hash
, map
);
711 XFREE(MTYPE_ROUTE_MAP_NAME
, map
->name
);
712 XFREE(MTYPE_ROUTE_MAP
, map
);
715 /* Route map delete from list. */
716 static void route_map_delete(struct route_map
*map
)
718 struct route_map_index
*index
;
721 while ((index
= map
->head
) != NULL
)
722 route_map_index_delete(index
, 0);
727 /* Clear all dependencies */
728 route_map_clear_all_references(name
);
730 /* Execute deletion hook. */
731 if (route_map_master
.delete_hook
) {
732 (*route_map_master
.delete_hook
)(name
);
733 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_DELETED
);
736 if (!map
->to_be_processed
) {
737 route_map_free_map(map
);
741 /* Lookup route map by route map name string. */
742 struct route_map
*route_map_lookup_by_name(const char *name
)
744 struct route_map
*map
;
745 struct route_map tmp_map
;
750 // map.deleted is 0 via memset
751 memset(&tmp_map
, 0, sizeof(struct route_map
));
752 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
753 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
754 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
758 int route_map_mark_updated(const char *name
, int del_later
)
760 struct route_map
*map
;
762 struct route_map tmp_map
;
767 map
= route_map_lookup_by_name(name
);
769 /* If we did not find the routemap with deleted=0 try again
773 memset(&tmp_map
, 0, sizeof(struct route_map
));
774 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
776 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
777 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
781 map
->to_be_processed
= 1;
788 int route_map_clear_updated(struct route_map
*map
)
793 map
->to_be_processed
= 0;
795 route_map_free_map(map
);
801 /* Lookup route map. If there isn't route map create one and return
803 static struct route_map
*route_map_get(const char *name
)
805 struct route_map
*map
;
807 map
= route_map_lookup_by_name(name
);
809 map
= route_map_add(name
);
814 void route_map_walk_update_list(int (*route_map_update_fn
)(char *name
))
816 struct route_map
*node
;
817 struct route_map
*nnode
= NULL
;
819 for (node
= route_map_master
.head
; node
; node
= nnode
) {
820 if (node
->to_be_processed
) {
821 /* DD: Should we add any thread yield code here */
822 route_map_update_fn(node
->name
);
824 route_map_clear_updated(node
);
830 /* Return route map's type string. */
831 static const char *route_map_type_str(enum route_map_type type
)
846 static int route_map_empty(struct route_map
*map
)
848 if (map
->head
== NULL
&& map
->tail
== NULL
)
855 static void vty_show_route_map_entry(struct vty
*vty
, struct route_map
*map
)
857 struct route_map_index
*index
;
858 struct route_map_rule
*rule
;
860 vty_out(vty
, "%s:\n", frr_protonameinst
);
862 for (index
= map
->head
; index
; index
= index
->next
) {
863 vty_out(vty
, "route-map %s, %s, sequence %d\n", map
->name
,
864 route_map_type_str(index
->type
), index
->pref
);
867 if (index
->description
)
868 vty_out(vty
, " Description:\n %s\n",
872 vty_out(vty
, " Match clauses:\n");
873 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
874 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
877 vty_out(vty
, " Set clauses:\n");
878 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
879 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
883 vty_out(vty
, " Call clause:\n");
885 vty_out(vty
, " Call %s\n", index
->nextrm
);
888 vty_out(vty
, " Action:\n");
889 if (index
->exitpolicy
== RMAP_GOTO
)
890 vty_out(vty
, " Goto %d\n", index
->nextpref
);
891 else if (index
->exitpolicy
== RMAP_NEXT
)
892 vty_out(vty
, " Continue to next entry\n");
893 else if (index
->exitpolicy
== RMAP_EXIT
)
894 vty_out(vty
, " Exit routemap\n");
898 static int vty_show_route_map(struct vty
*vty
, const char *name
)
900 struct route_map
*map
;
903 map
= route_map_lookup_by_name(name
);
906 vty_show_route_map_entry(vty
, map
);
909 vty_out(vty
, "%s: 'route-map %s' not found\n",
910 frr_protonameinst
, name
);
914 for (map
= route_map_master
.head
; map
; map
= map
->next
)
916 vty_show_route_map_entry(vty
, map
);
922 /* New route map allocation. Please note route map's name must be
924 static struct route_map_index
*route_map_index_new(void)
926 struct route_map_index
*new;
928 new = XCALLOC(MTYPE_ROUTE_MAP_INDEX
, sizeof(struct route_map_index
));
929 new->exitpolicy
= RMAP_EXIT
; /* Default to Cisco-style */
930 QOBJ_REG(new, route_map_index
);
934 /* Free route map index. */
935 static void route_map_index_delete(struct route_map_index
*index
, int notify
)
937 struct route_map_rule
*rule
;
941 /* Free route match. */
942 while ((rule
= index
->match_list
.head
) != NULL
)
943 route_map_rule_delete(&index
->match_list
, rule
);
945 /* Free route set. */
946 while ((rule
= index
->set_list
.head
) != NULL
)
947 route_map_rule_delete(&index
->set_list
, rule
);
949 /* Remove index from route map list. */
951 index
->next
->prev
= index
->prev
;
953 index
->map
->tail
= index
->prev
;
956 index
->prev
->next
= index
->next
;
958 index
->map
->head
= index
->next
;
960 /* Free 'char *nextrm' if not NULL */
962 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
964 /* Execute event hook. */
965 if (route_map_master
.event_hook
&& notify
) {
966 (*route_map_master
.event_hook
)(RMAP_EVENT_INDEX_DELETED
,
968 route_map_notify_dependencies(index
->map
->name
,
969 RMAP_EVENT_CALL_ADDED
);
971 XFREE(MTYPE_ROUTE_MAP_INDEX
, index
);
974 /* Lookup index from route map. */
975 static struct route_map_index
*route_map_index_lookup(struct route_map
*map
,
976 enum route_map_type type
,
979 struct route_map_index
*index
;
981 for (index
= map
->head
; index
; index
= index
->next
)
982 if ((index
->type
== type
|| type
== RMAP_ANY
)
983 && index
->pref
== pref
)
988 /* Add new index to route map. */
989 static struct route_map_index
*
990 route_map_index_add(struct route_map
*map
, enum route_map_type type
, int pref
)
992 struct route_map_index
*index
;
993 struct route_map_index
*point
;
995 /* Allocate new route map inex. */
996 index
= route_map_index_new();
1001 /* Compare preference. */
1002 for (point
= map
->head
; point
; point
= point
->next
)
1003 if (point
->pref
>= pref
)
1006 if (map
->head
== NULL
) {
1007 map
->head
= map
->tail
= index
;
1008 } else if (point
== NULL
) {
1009 index
->prev
= map
->tail
;
1010 map
->tail
->next
= index
;
1012 } else if (point
== map
->head
) {
1013 index
->next
= map
->head
;
1014 map
->head
->prev
= index
;
1017 index
->next
= point
;
1018 index
->prev
= point
->prev
;
1020 point
->prev
->next
= index
;
1021 point
->prev
= index
;
1024 /* Execute event hook. */
1025 if (route_map_master
.event_hook
) {
1026 (*route_map_master
.event_hook
)(RMAP_EVENT_INDEX_ADDED
,
1028 route_map_notify_dependencies(map
->name
, RMAP_EVENT_CALL_ADDED
);
1033 /* Get route map index. */
1034 static struct route_map_index
*
1035 route_map_index_get(struct route_map
*map
, enum route_map_type type
, int pref
)
1037 struct route_map_index
*index
;
1039 index
= route_map_index_lookup(map
, RMAP_ANY
, pref
);
1040 if (index
&& index
->type
!= type
) {
1041 /* Delete index from route map. */
1042 route_map_index_delete(index
, 1);
1046 index
= route_map_index_add(map
, type
, pref
);
1050 /* New route map rule */
1051 static struct route_map_rule
*route_map_rule_new(void)
1053 struct route_map_rule
*new;
1055 new = XCALLOC(MTYPE_ROUTE_MAP_RULE
, sizeof(struct route_map_rule
));
1059 /* Install rule command to the match list. */
1060 void route_map_install_match(struct route_map_rule_cmd
*cmd
)
1062 vector_set(route_match_vec
, cmd
);
1065 /* Install rule command to the set list. */
1066 void route_map_install_set(struct route_map_rule_cmd
*cmd
)
1068 vector_set(route_set_vec
, cmd
);
1071 /* Lookup rule command from match list. */
1072 static struct route_map_rule_cmd
*route_map_lookup_match(const char *name
)
1075 struct route_map_rule_cmd
*rule
;
1077 for (i
= 0; i
< vector_active(route_match_vec
); i
++)
1078 if ((rule
= vector_slot(route_match_vec
, i
)) != NULL
)
1079 if (strcmp(rule
->str
, name
) == 0)
1084 /* Lookup rule command from set list. */
1085 static struct route_map_rule_cmd
*route_map_lookup_set(const char *name
)
1088 struct route_map_rule_cmd
*rule
;
1090 for (i
= 0; i
< vector_active(route_set_vec
); i
++)
1091 if ((rule
= vector_slot(route_set_vec
, i
)) != NULL
)
1092 if (strcmp(rule
->str
, name
) == 0)
1097 /* Add match and set rule to rule list. */
1098 static void route_map_rule_add(struct route_map_rule_list
*list
,
1099 struct route_map_rule
*rule
)
1102 rule
->prev
= list
->tail
;
1104 list
->tail
->next
= rule
;
1110 /* Delete rule from rule list. */
1111 static void route_map_rule_delete(struct route_map_rule_list
*list
,
1112 struct route_map_rule
*rule
)
1114 if (rule
->cmd
->func_free
)
1115 (*rule
->cmd
->func_free
)(rule
->value
);
1118 XFREE(MTYPE_ROUTE_MAP_RULE_STR
, rule
->rule_str
);
1121 rule
->next
->prev
= rule
->prev
;
1123 list
->tail
= rule
->prev
;
1125 rule
->prev
->next
= rule
->next
;
1127 list
->head
= rule
->next
;
1129 XFREE(MTYPE_ROUTE_MAP_RULE
, rule
);
1132 /* strcmp wrapper function which don't crush even argument is NULL. */
1133 static int rulecmp(const char *dst
, const char *src
)
1144 return strcmp(dst
, src
);
1149 /* Use this to return the already specified argument for this match. This is
1150 * useful to get the specified argument with a route map match rule when the
1151 * rule is being deleted and the argument is not provided.
1153 const char *route_map_get_match_arg(struct route_map_index
*index
,
1154 const char *match_name
)
1156 struct route_map_rule
*rule
;
1157 struct route_map_rule_cmd
*cmd
;
1159 /* First lookup rule for add match statement. */
1160 cmd
= route_map_lookup_match(match_name
);
1164 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1165 if (rule
->cmd
== cmd
&& rule
->rule_str
!= NULL
)
1166 return (rule
->rule_str
);
1171 /* Add match statement to route map. */
1172 int route_map_add_match(struct route_map_index
*index
, const char *match_name
,
1173 const char *match_arg
)
1175 struct route_map_rule
*rule
;
1176 struct route_map_rule
*next
;
1177 struct route_map_rule_cmd
*cmd
;
1181 /* First lookup rule for add match statement. */
1182 cmd
= route_map_lookup_match(match_name
);
1184 return RMAP_RULE_MISSING
;
1186 /* Next call compile function for this match statement. */
1187 if (cmd
->func_compile
) {
1188 compile
= (*cmd
->func_compile
)(match_arg
);
1189 if (compile
== NULL
)
1190 return RMAP_COMPILE_ERROR
;
1194 /* If argument is completely same ignore it. */
1195 for (rule
= index
->match_list
.head
; rule
; rule
= next
) {
1197 if (rule
->cmd
== cmd
) {
1198 route_map_rule_delete(&index
->match_list
, rule
);
1203 /* Add new route map match rule. */
1204 rule
= route_map_rule_new();
1206 rule
->value
= compile
;
1208 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, match_arg
);
1210 rule
->rule_str
= NULL
;
1212 /* Add new route match rule to linked list. */
1213 route_map_rule_add(&index
->match_list
, rule
);
1215 /* Execute event hook. */
1216 if (route_map_master
.event_hook
) {
1217 (*route_map_master
.event_hook
)(
1218 replaced
? RMAP_EVENT_MATCH_REPLACED
1219 : RMAP_EVENT_MATCH_ADDED
,
1221 route_map_notify_dependencies(index
->map
->name
,
1222 RMAP_EVENT_CALL_ADDED
);
1225 return RMAP_COMPILE_SUCCESS
;
1228 /* Delete specified route match rule. */
1229 int route_map_delete_match(struct route_map_index
*index
,
1230 const char *match_name
, const char *match_arg
)
1232 struct route_map_rule
*rule
;
1233 struct route_map_rule_cmd
*cmd
;
1235 cmd
= route_map_lookup_match(match_name
);
1239 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1240 if (rule
->cmd
== cmd
&& (rulecmp(rule
->rule_str
, match_arg
) == 0
1241 || match_arg
== NULL
)) {
1242 route_map_rule_delete(&index
->match_list
, rule
);
1243 /* Execute event hook. */
1244 if (route_map_master
.event_hook
) {
1245 (*route_map_master
.event_hook
)(
1246 RMAP_EVENT_MATCH_DELETED
,
1248 route_map_notify_dependencies(
1250 RMAP_EVENT_CALL_ADDED
);
1254 /* Can't find matched rule. */
1258 /* Add route-map set statement to the route map. */
1259 int route_map_add_set(struct route_map_index
*index
, const char *set_name
,
1260 const char *set_arg
)
1262 struct route_map_rule
*rule
;
1263 struct route_map_rule
*next
;
1264 struct route_map_rule_cmd
*cmd
;
1268 cmd
= route_map_lookup_set(set_name
);
1270 return RMAP_RULE_MISSING
;
1272 /* Next call compile function for this match statement. */
1273 if (cmd
->func_compile
) {
1274 compile
= (*cmd
->func_compile
)(set_arg
);
1275 if (compile
== NULL
)
1276 return RMAP_COMPILE_ERROR
;
1280 /* Add by WJL. if old set command of same kind exist, delete it first
1281 to ensure only one set command of same kind exist under a
1283 for (rule
= index
->set_list
.head
; rule
; rule
= next
) {
1285 if (rule
->cmd
== cmd
) {
1286 route_map_rule_delete(&index
->set_list
, rule
);
1291 /* Add new route map match rule. */
1292 rule
= route_map_rule_new();
1294 rule
->value
= compile
;
1296 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, set_arg
);
1298 rule
->rule_str
= NULL
;
1300 /* Add new route match rule to linked list. */
1301 route_map_rule_add(&index
->set_list
, rule
);
1303 /* Execute event hook. */
1304 if (route_map_master
.event_hook
) {
1305 (*route_map_master
.event_hook
)(replaced
1306 ? RMAP_EVENT_SET_REPLACED
1307 : RMAP_EVENT_SET_ADDED
,
1309 route_map_notify_dependencies(index
->map
->name
,
1310 RMAP_EVENT_CALL_ADDED
);
1312 return RMAP_COMPILE_SUCCESS
;
1315 /* Delete route map set rule. */
1316 int route_map_delete_set(struct route_map_index
*index
, const char *set_name
,
1317 const char *set_arg
)
1319 struct route_map_rule
*rule
;
1320 struct route_map_rule_cmd
*cmd
;
1322 cmd
= route_map_lookup_set(set_name
);
1326 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
1327 if ((rule
->cmd
== cmd
) && (rulecmp(rule
->rule_str
, set_arg
) == 0
1328 || set_arg
== NULL
)) {
1329 route_map_rule_delete(&index
->set_list
, rule
);
1330 /* Execute event hook. */
1331 if (route_map_master
.event_hook
) {
1332 (*route_map_master
.event_hook
)(
1333 RMAP_EVENT_SET_DELETED
,
1335 route_map_notify_dependencies(
1337 RMAP_EVENT_CALL_ADDED
);
1341 /* Can't find matched rule. */
1345 /* Apply route map's each index to the object.
1347 The matrix for a route-map looks like this:
1348 (note, this includes the description for the "NEXT"
1349 and "GOTO" frobs now
1353 permit action | cont
1355 ------------------+---------------
1361 -Apply Set statements, accept route
1362 -If Call statement is present jump to the specified route-map, if it
1363 denies the route we finish.
1364 -If NEXT is specified, goto NEXT statement
1365 -If GOTO is specified, goto the first clause where pref > nextpref
1366 -If nothing is specified, do as Cisco and finish
1368 -Route is denied by route-map.
1372 If we get no matches after we've processed all updates, then the route
1375 Some notes on the new "CALL", "NEXT" and "GOTO"
1376 call WORD - If this clause is matched, then the set statements
1377 are executed and then we jump to route-map 'WORD'. If
1378 this route-map denies the route, we finish, in other
1380 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
1381 on-match next - If this clause is matched, then the set statements
1382 are executed and then we drop through to the next clause
1383 on-match goto n - If this clause is matched, then the set statments
1384 are executed and then we goto the nth clause, or the
1385 first clause greater than this. In order to ensure
1386 route-maps *always* exit, you cannot jump backwards.
1389 We need to make sure our route-map processing matches the above
1392 static route_map_result_t
1393 route_map_apply_match(struct route_map_rule_list
*match_list
,
1394 struct prefix
*prefix
, route_map_object_t type
,
1397 route_map_result_t ret
= RMAP_NOMATCH
;
1398 struct route_map_rule
*match
;
1401 /* Check all match rule and if there is no match rule, go to the
1403 if (!match_list
->head
)
1406 for (match
= match_list
->head
; match
; match
= match
->next
) {
1407 /* Try each match statement in turn, If any do not
1409 RMAP_MATCH, return, otherwise continue on to next
1411 statement. All match statements must match for
1414 ret
= (*match
->cmd
->func_apply
)(match
->value
, prefix
,
1416 if (ret
!= RMAP_MATCH
)
1423 /* Apply route map to the object. */
1424 route_map_result_t
route_map_apply(struct route_map
*map
, struct prefix
*prefix
,
1425 route_map_object_t type
, void *object
)
1427 static int recursion
= 0;
1429 struct route_map_index
*index
;
1430 struct route_map_rule
*set
;
1432 if (recursion
> RMAP_RECURSION_LIMIT
) {
1434 "route-map recursion limit (%d) reached, discarding route",
1435 RMAP_RECURSION_LIMIT
);
1437 return RMAP_DENYMATCH
;
1441 return RMAP_DENYMATCH
;
1443 for (index
= map
->head
; index
; index
= index
->next
) {
1444 /* Apply this index. */
1445 ret
= route_map_apply_match(&index
->match_list
, prefix
, type
,
1448 /* Now we apply the matrix from above */
1449 if (ret
== RMAP_NOMATCH
)
1450 /* 'cont' from matrix - continue to next route-map
1453 else if (ret
== RMAP_MATCH
) {
1454 if (index
->type
== RMAP_PERMIT
)
1457 /* permit+match must execute sets */
1458 for (set
= index
->set_list
.head
; set
;
1460 ret
= (*set
->cmd
->func_apply
)(
1461 set
->value
, prefix
, type
,
1464 /* Call another route-map if available */
1465 if (index
->nextrm
) {
1466 struct route_map
*nextrm
=
1467 route_map_lookup_by_name(
1470 if (nextrm
) /* Target route-map found,
1474 ret
= route_map_apply(
1475 nextrm
, prefix
, type
,
1480 /* If nextrm returned 'deny', finish. */
1481 if (ret
== RMAP_DENYMATCH
)
1485 switch (index
->exitpolicy
) {
1491 /* Find the next clause to jump to */
1492 struct route_map_index
*next
=
1494 int nextpref
= index
->nextpref
;
1496 while (next
&& next
->pref
< nextpref
) {
1501 /* No clauses match! */
1506 } else if (index
->type
== RMAP_DENY
)
1509 return RMAP_DENYMATCH
;
1513 /* Finally route-map does not match at all. */
1514 return RMAP_DENYMATCH
;
1517 void route_map_add_hook(void (*func
)(const char *))
1519 route_map_master
.add_hook
= func
;
1522 void route_map_delete_hook(void (*func
)(const char *))
1524 route_map_master
.delete_hook
= func
;
1527 void route_map_event_hook(void (*func
)(route_map_event_t
, const char *))
1529 route_map_master
.event_hook
= func
;
1532 /* Routines for route map dependency lists and dependency processing */
1533 static int route_map_rmap_hash_cmp(const void *p1
, const void *p2
)
1535 return (strcmp((const char *)p1
, (const char *)p2
) == 0);
1538 static int route_map_dep_hash_cmp(const void *p1
, const void *p2
)
1541 return (strcmp(((const struct route_map_dep
*)p1
)->dep_name
,
1546 static void route_map_clear_reference(struct hash_backet
*backet
, void *arg
)
1548 struct route_map_dep
*dep
= (struct route_map_dep
*)backet
->data
;
1553 (char *)hash_release(dep
->dep_rmap_hash
, (void *)arg
);
1555 XFREE(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
1557 if (!dep
->dep_rmap_hash
->count
) {
1558 dep
= hash_release(dep
->this_hash
,
1559 (void *)dep
->dep_name
);
1560 hash_free(dep
->dep_rmap_hash
);
1561 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
1562 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
1567 static void route_map_clear_all_references(char *rmap_name
)
1571 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
1572 hash_iterate(route_map_dep_hash
[i
], route_map_clear_reference
,
1577 static void *route_map_dep_hash_alloc(void *p
)
1579 char *dep_name
= (char *)p
;
1580 struct route_map_dep
*dep_entry
;
1582 dep_entry
= XCALLOC(MTYPE_ROUTE_MAP_DEP
, sizeof(struct route_map_dep
));
1583 dep_entry
->dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1584 dep_entry
->dep_rmap_hash
= hash_create_size(8,
1585 route_map_dep_hash_make_key
,
1586 route_map_rmap_hash_cmp
,
1587 "Route Map Dep Hash");
1588 dep_entry
->this_hash
= NULL
;
1590 return ((void *)dep_entry
);
1593 static void *route_map_name_hash_alloc(void *p
)
1595 return ((void *)XSTRDUP(MTYPE_ROUTE_MAP_NAME
, (const char *)p
));
1598 static unsigned int route_map_dep_hash_make_key(void *p
)
1600 return (string_hash_make((char *)p
));
1603 static void route_map_print_dependency(struct hash_backet
*backet
, void *data
)
1605 char *rmap_name
= (char *)backet
->data
;
1606 char *dep_name
= (char *)data
;
1609 zlog_debug("%s: Dependency for %s: %s", __FUNCTION__
, dep_name
,
1613 static int route_map_dep_update(struct hash
*dephash
, const char *dep_name
,
1614 const char *rmap_name
, route_map_event_t type
)
1616 struct route_map_dep
*dep
= NULL
;
1618 char *dname
, *rname
;
1621 dname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1622 rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
1625 case RMAP_EVENT_PLIST_ADDED
:
1626 case RMAP_EVENT_CLIST_ADDED
:
1627 case RMAP_EVENT_ECLIST_ADDED
:
1628 case RMAP_EVENT_ASLIST_ADDED
:
1629 case RMAP_EVENT_LLIST_ADDED
:
1630 case RMAP_EVENT_CALL_ADDED
:
1631 case RMAP_EVENT_FILTER_ADDED
:
1633 zlog_debug("%s: Adding dependency for %s in %s",
1634 __FUNCTION__
, dep_name
, rmap_name
);
1635 dep
= (struct route_map_dep
*)hash_get(
1636 dephash
, dname
, route_map_dep_hash_alloc
);
1642 if (!dep
->this_hash
)
1643 dep
->this_hash
= dephash
;
1645 hash_get(dep
->dep_rmap_hash
, rname
, route_map_name_hash_alloc
);
1647 case RMAP_EVENT_PLIST_DELETED
:
1648 case RMAP_EVENT_CLIST_DELETED
:
1649 case RMAP_EVENT_ECLIST_DELETED
:
1650 case RMAP_EVENT_ASLIST_DELETED
:
1651 case RMAP_EVENT_LLIST_DELETED
:
1652 case RMAP_EVENT_CALL_DELETED
:
1653 case RMAP_EVENT_FILTER_DELETED
:
1655 zlog_debug("%s: Deleting dependency for %s in %s",
1656 __FUNCTION__
, dep_name
, rmap_name
);
1657 dep
= (struct route_map_dep
*)hash_get(dephash
, dname
, NULL
);
1662 ret_map_name
= (char *)hash_release(dep
->dep_rmap_hash
, rname
);
1664 XFREE(MTYPE_ROUTE_MAP_NAME
, ret_map_name
);
1666 if (!dep
->dep_rmap_hash
->count
) {
1667 dep
= hash_release(dephash
, dname
);
1668 hash_free(dep
->dep_rmap_hash
);
1669 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
1670 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
1680 hash_iterate(dep
->dep_rmap_hash
,
1681 route_map_print_dependency
, dname
);
1685 XFREE(MTYPE_ROUTE_MAP_NAME
, rname
);
1686 XFREE(MTYPE_ROUTE_MAP_NAME
, dname
);
1690 static struct hash
*route_map_get_dep_hash(route_map_event_t event
)
1692 struct hash
*upd8_hash
= NULL
;
1695 case RMAP_EVENT_PLIST_ADDED
:
1696 case RMAP_EVENT_PLIST_DELETED
:
1697 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_PLIST
];
1699 case RMAP_EVENT_CLIST_ADDED
:
1700 case RMAP_EVENT_CLIST_DELETED
:
1701 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_CLIST
];
1703 case RMAP_EVENT_ECLIST_ADDED
:
1704 case RMAP_EVENT_ECLIST_DELETED
:
1705 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ECLIST
];
1707 case RMAP_EVENT_ASLIST_ADDED
:
1708 case RMAP_EVENT_ASLIST_DELETED
:
1709 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ASPATH
];
1711 case RMAP_EVENT_LLIST_ADDED
:
1712 case RMAP_EVENT_LLIST_DELETED
:
1713 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_LCLIST
];
1715 case RMAP_EVENT_CALL_ADDED
:
1716 case RMAP_EVENT_CALL_DELETED
:
1717 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_RMAP
];
1719 case RMAP_EVENT_FILTER_ADDED
:
1720 case RMAP_EVENT_FILTER_DELETED
:
1721 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_FILTER
];
1730 static void route_map_process_dependency(struct hash_backet
*backet
, void *data
)
1733 route_map_event_t type
= (route_map_event_t
)(ptrdiff_t)data
;
1735 rmap_name
= (char *)backet
->data
;
1739 zlog_debug("%s: Notifying %s of dependency",
1740 __FUNCTION__
, rmap_name
);
1741 if (route_map_master
.event_hook
)
1742 (*route_map_master
.event_hook
)(type
, rmap_name
);
1746 void route_map_upd8_dependency(route_map_event_t type
, const char *arg
,
1747 const char *rmap_name
)
1749 struct hash
*upd8_hash
= NULL
;
1751 if ((upd8_hash
= route_map_get_dep_hash(type
)))
1752 route_map_dep_update(upd8_hash
, arg
, rmap_name
, type
);
1755 void route_map_notify_dependencies(const char *affected_name
,
1756 route_map_event_t event
)
1758 struct route_map_dep
*dep
;
1759 struct hash
*upd8_hash
;
1765 name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, affected_name
);
1767 if ((upd8_hash
= route_map_get_dep_hash(event
)) == NULL
) {
1768 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
1772 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, name
, NULL
);
1774 if (!dep
->this_hash
)
1775 dep
->this_hash
= upd8_hash
;
1777 hash_iterate(dep
->dep_rmap_hash
, route_map_process_dependency
,
1781 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
1785 /* VTY related functions. */
1786 DEFUN (match_interface
,
1787 match_interface_cmd
,
1788 "match interface WORD",
1790 "match first hop interface of route\n"
1794 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1796 if (rmap_match_set_hook
.match_interface
)
1797 return rmap_match_set_hook
.match_interface(
1798 vty
, index
, "interface", argv
[idx_word
]->arg
,
1799 RMAP_EVENT_MATCH_ADDED
);
1803 DEFUN (no_match_interface
,
1804 no_match_interface_cmd
,
1805 "no match interface [WORD]",
1808 "Match first hop interface of route\n"
1811 char *iface
= (argc
== 4) ? argv
[3]->arg
: NULL
;
1812 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1814 if (rmap_match_set_hook
.no_match_interface
)
1815 return rmap_match_set_hook
.no_match_interface(
1816 vty
, index
, "interface", iface
,
1817 RMAP_EVENT_MATCH_DELETED
);
1822 DEFUN (match_ip_address
,
1823 match_ip_address_cmd
,
1824 "match ip address <(1-199)|(1300-2699)|WORD>",
1827 "Match address of route\n"
1828 "IP access-list number\n"
1829 "IP access-list number (expanded range)\n"
1830 "IP Access-list name\n")
1833 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1835 if (rmap_match_set_hook
.match_ip_address
)
1836 return rmap_match_set_hook
.match_ip_address(
1837 vty
, index
, "ip address", argv
[idx_acl
]->arg
,
1838 RMAP_EVENT_FILTER_ADDED
);
1843 DEFUN (no_match_ip_address
,
1844 no_match_ip_address_cmd
,
1845 "no match ip address [<(1-199)|(1300-2699)|WORD>]",
1849 "Match address of route\n"
1850 "IP access-list number\n"
1851 "IP access-list number (expanded range)\n"
1852 "IP Access-list name\n")
1855 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1857 if (rmap_match_set_hook
.no_match_ip_address
) {
1858 if (argc
<= idx_word
)
1859 return rmap_match_set_hook
.no_match_ip_address(
1860 vty
, index
, "ip address", NULL
,
1861 RMAP_EVENT_FILTER_DELETED
);
1862 return rmap_match_set_hook
.no_match_ip_address(
1863 vty
, index
, "ip address", argv
[idx_word
]->arg
,
1864 RMAP_EVENT_FILTER_DELETED
);
1870 DEFUN (match_ip_address_prefix_list
,
1871 match_ip_address_prefix_list_cmd
,
1872 "match ip address prefix-list WORD",
1875 "Match address of route\n"
1876 "Match entries of prefix-lists\n"
1877 "IP prefix-list name\n")
1880 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1882 if (rmap_match_set_hook
.match_ip_address_prefix_list
)
1883 return rmap_match_set_hook
.match_ip_address_prefix_list(
1884 vty
, index
, "ip address prefix-list",
1885 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
1890 DEFUN (no_match_ip_address_prefix_list
,
1891 no_match_ip_address_prefix_list_cmd
,
1892 "no match ip address prefix-list [WORD]",
1896 "Match address of route\n"
1897 "Match entries of prefix-lists\n"
1898 "IP prefix-list name\n")
1901 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1903 if (rmap_match_set_hook
.no_match_ip_address_prefix_list
) {
1904 if (argc
<= idx_word
)
1905 return rmap_match_set_hook
1906 .no_match_ip_address_prefix_list(
1907 vty
, index
, "ip address prefix-list",
1908 NULL
, RMAP_EVENT_PLIST_DELETED
);
1909 return rmap_match_set_hook
.no_match_ip_address_prefix_list(
1910 vty
, index
, "ip address prefix-list",
1911 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
1917 DEFUN (match_ip_next_hop
,
1918 match_ip_next_hop_cmd
,
1919 "match ip next-hop <(1-199)|(1300-2699)|WORD>",
1922 "Match next-hop address of route\n"
1923 "IP access-list number\n"
1924 "IP access-list number (expanded range)\n"
1925 "IP Access-list name\n")
1928 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1930 if (rmap_match_set_hook
.match_ip_next_hop
)
1931 return rmap_match_set_hook
.match_ip_next_hop(
1932 vty
, index
, "ip next-hop", argv
[idx_acl
]->arg
,
1933 RMAP_EVENT_FILTER_ADDED
);
1938 DEFUN (no_match_ip_next_hop
,
1939 no_match_ip_next_hop_cmd
,
1940 "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
1944 "Match next-hop address of route\n"
1945 "IP access-list number\n"
1946 "IP access-list number (expanded range)\n"
1947 "IP Access-list name\n")
1950 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1952 if (rmap_match_set_hook
.no_match_ip_next_hop
) {
1953 if (argc
<= idx_word
)
1954 return rmap_match_set_hook
.no_match_ip_next_hop(
1955 vty
, index
, "ip next-hop", NULL
,
1956 RMAP_EVENT_FILTER_DELETED
);
1957 return rmap_match_set_hook
.no_match_ip_next_hop(
1958 vty
, index
, "ip next-hop", argv
[idx_word
]->arg
,
1959 RMAP_EVENT_FILTER_DELETED
);
1965 DEFUN (match_ip_next_hop_prefix_list
,
1966 match_ip_next_hop_prefix_list_cmd
,
1967 "match ip next-hop prefix-list WORD",
1970 "Match next-hop address of route\n"
1971 "Match entries of prefix-lists\n"
1972 "IP prefix-list name\n")
1975 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1977 if (rmap_match_set_hook
.match_ip_next_hop_prefix_list
)
1978 return rmap_match_set_hook
.match_ip_next_hop_prefix_list(
1979 vty
, index
, "ip next-hop prefix-list",
1980 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
1984 DEFUN (no_match_ip_next_hop_prefix_list
,
1985 no_match_ip_next_hop_prefix_list_cmd
,
1986 "no match ip next-hop prefix-list [WORD]",
1990 "Match next-hop address of route\n"
1991 "Match entries of prefix-lists\n"
1992 "IP prefix-list name\n")
1995 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1997 if (rmap_match_set_hook
.no_match_ip_next_hop
) {
1998 if (argc
<= idx_word
)
1999 return rmap_match_set_hook
.no_match_ip_next_hop(
2000 vty
, index
, "ip next-hop prefix-list", NULL
,
2001 RMAP_EVENT_PLIST_DELETED
);
2002 return rmap_match_set_hook
.no_match_ip_next_hop(
2003 vty
, index
, "ip next-hop prefix-list",
2004 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2010 DEFUN (match_ipv6_address
,
2011 match_ipv6_address_cmd
,
2012 "match ipv6 address WORD",
2015 "Match IPv6 address of route\n"
2016 "IPv6 access-list name\n")
2019 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2021 if (rmap_match_set_hook
.match_ipv6_address
)
2022 return rmap_match_set_hook
.match_ipv6_address(
2023 vty
, index
, "ipv6 address", argv
[idx_word
]->arg
,
2024 RMAP_EVENT_FILTER_ADDED
);
2028 DEFUN (no_match_ipv6_address
,
2029 no_match_ipv6_address_cmd
,
2030 "no match ipv6 address WORD",
2034 "Match IPv6 address of route\n"
2035 "IPv6 access-list name\n")
2038 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2040 if (rmap_match_set_hook
.no_match_ipv6_address
)
2041 return rmap_match_set_hook
.no_match_ipv6_address(
2042 vty
, index
, "ipv6 address", argv
[idx_word
]->arg
,
2043 RMAP_EVENT_FILTER_DELETED
);
2048 DEFUN (match_ipv6_address_prefix_list
,
2049 match_ipv6_address_prefix_list_cmd
,
2050 "match ipv6 address prefix-list WORD",
2053 "Match address of route\n"
2054 "Match entries of prefix-lists\n"
2055 "IP prefix-list name\n")
2058 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2060 if (rmap_match_set_hook
.match_ipv6_address_prefix_list
)
2061 return rmap_match_set_hook
.match_ipv6_address_prefix_list(
2062 vty
, index
, "ipv6 address prefix-list",
2063 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
2067 DEFUN (no_match_ipv6_address_prefix_list
,
2068 no_match_ipv6_address_prefix_list_cmd
,
2069 "no match ipv6 address prefix-list WORD",
2073 "Match address of route\n"
2074 "Match entries of prefix-lists\n"
2075 "IP prefix-list name\n")
2078 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2080 if (rmap_match_set_hook
.no_match_ipv6_address_prefix_list
)
2081 return rmap_match_set_hook
.no_match_ipv6_address_prefix_list(
2082 vty
, index
, "ipv6 address prefix-list",
2083 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2088 DEFUN (match_metric
,
2090 "match metric (0-4294967295)",
2092 "Match metric of route\n"
2096 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2098 if (rmap_match_set_hook
.match_metric
)
2099 return rmap_match_set_hook
.match_metric(vty
, index
, "metric",
2100 argv
[idx_number
]->arg
,
2101 RMAP_EVENT_MATCH_ADDED
);
2106 DEFUN (no_match_metric
,
2107 no_match_metric_cmd
,
2108 "no match metric [(0-4294967295)]",
2111 "Match metric of route\n"
2115 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2117 if (rmap_match_set_hook
.no_match_metric
) {
2118 if (argc
<= idx_number
)
2119 return rmap_match_set_hook
.no_match_metric(
2120 vty
, index
, "metric", NULL
,
2121 RMAP_EVENT_MATCH_DELETED
);
2122 return rmap_match_set_hook
.no_match_metric(
2123 vty
, index
, "metric", argv
[idx_number
]->arg
,
2124 RMAP_EVENT_MATCH_DELETED
);
2132 "match tag (1-4294967295)",
2134 "Match tag of route\n"
2138 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2140 if (rmap_match_set_hook
.match_tag
)
2141 return rmap_match_set_hook
.match_tag(vty
, index
, "tag",
2142 argv
[idx_number
]->arg
,
2143 RMAP_EVENT_MATCH_ADDED
);
2148 DEFUN (no_match_tag
,
2150 "no match tag [(1-4294967295)]",
2153 "Match tag of route\n"
2156 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2159 char *arg
= argv_find(argv
, argc
, "(1-4294967295)", &idx
)
2163 if (rmap_match_set_hook
.no_match_tag
)
2164 return rmap_match_set_hook
.no_match_tag(
2165 vty
, index
, "tag", arg
, RMAP_EVENT_MATCH_DELETED
);
2170 DEFUN (set_ip_nexthop
,
2172 "set ip next-hop A.B.C.D",
2175 "Next hop address\n"
2176 "IP address of next hop\n")
2181 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2183 ret
= str2sockunion(argv
[idx_ipv4
]->arg
, &su
);
2185 vty_out(vty
, "%% Malformed nexthop address\n");
2186 return CMD_WARNING_CONFIG_FAILED
;
2188 if (su
.sin
.sin_addr
.s_addr
== 0
2189 || IPV4_CLASS_DE(ntohl(su
.sin
.sin_addr
.s_addr
))) {
2191 "%% nexthop address cannot be 0.0.0.0, multicast or reserved\n");
2192 return CMD_WARNING_CONFIG_FAILED
;
2195 if (rmap_match_set_hook
.set_ip_nexthop
)
2196 return rmap_match_set_hook
.set_ip_nexthop(
2197 vty
, index
, "ip next-hop", argv
[idx_ipv4
]->arg
);
2202 DEFUN (no_set_ip_nexthop
,
2203 no_set_ip_nexthop_cmd
,
2204 "no set ip next-hop [A.B.C.D]",
2208 "Next hop address\n"
2209 "IP address of next hop\n")
2212 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2213 const char *arg
= NULL
;
2215 if (argv_find(argv
, argc
, "A.B.C.D", &idx
))
2216 arg
= argv
[idx
]->arg
;
2218 if (rmap_match_set_hook
.no_set_ip_nexthop
)
2219 return rmap_match_set_hook
.no_set_ip_nexthop(
2220 vty
, index
, "ip next-hop", arg
);
2226 DEFUN (set_ipv6_nexthop_local
,
2227 set_ipv6_nexthop_local_cmd
,
2228 "set ipv6 next-hop local X:X::X:X",
2231 "IPv6 next-hop address\n"
2232 "IPv6 local address\n"
2233 "IPv6 address of next hop\n")
2236 struct in6_addr addr
;
2238 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2240 ret
= inet_pton(AF_INET6
, argv
[idx_ipv6
]->arg
, &addr
);
2242 vty_out(vty
, "%% Malformed nexthop address\n");
2243 return CMD_WARNING_CONFIG_FAILED
;
2245 if (!IN6_IS_ADDR_LINKLOCAL(&addr
)) {
2246 vty_out(vty
, "%% Invalid link-local nexthop address\n");
2247 return CMD_WARNING_CONFIG_FAILED
;
2250 if (rmap_match_set_hook
.set_ipv6_nexthop_local
)
2251 return rmap_match_set_hook
.set_ipv6_nexthop_local(
2252 vty
, index
, "ipv6 next-hop local", argv
[idx_ipv6
]->arg
);
2257 DEFUN (no_set_ipv6_nexthop_local
,
2258 no_set_ipv6_nexthop_local_cmd
,
2259 "no set ipv6 next-hop local [X:X::X:X]",
2263 "IPv6 next-hop address\n"
2264 "IPv6 local address\n"
2265 "IPv6 address of next hop\n")
2268 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2270 if (rmap_match_set_hook
.no_set_ipv6_nexthop_local
) {
2271 if (argc
<= idx_ipv6
)
2272 return rmap_match_set_hook
.no_set_ipv6_nexthop_local(
2273 vty
, index
, "ipv6 next-hop local", NULL
);
2274 return rmap_match_set_hook
.no_set_ipv6_nexthop_local(
2275 vty
, index
, "ipv6 next-hop local", argv
[5]->arg
);
2282 "set metric <(0-4294967295)|rtt|+rtt|-rtt|+metric|-metric>",
2284 "Metric value for destination routing protocol\n"
2286 "Assign round trip time\n"
2287 "Add round trip time\n"
2288 "Subtract round trip time\n"
2290 "Subtract metric\n")
2293 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2295 const char *pass
= (argv
[idx_number
]->type
== RANGE_TKN
)
2296 ? argv
[idx_number
]->arg
2297 : argv
[idx_number
]->text
;
2299 if (rmap_match_set_hook
.set_metric
)
2300 return rmap_match_set_hook
.set_metric(vty
, index
, "metric",
2306 DEFUN (no_set_metric
,
2308 "no set metric [(0-4294967295)]",
2311 "Metric value for destination routing protocol\n"
2315 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2317 if (rmap_match_set_hook
.no_set_metric
) {
2318 if (argc
<= idx_number
)
2319 return rmap_match_set_hook
.no_set_metric(
2320 vty
, index
, "metric", NULL
);
2321 return rmap_match_set_hook
.no_set_metric(vty
, index
, "metric",
2322 argv
[idx_number
]->arg
);
2330 "set tag (1-4294967295)",
2332 "Tag value for routing protocol\n"
2335 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2338 if (rmap_match_set_hook
.set_tag
)
2339 return rmap_match_set_hook
.set_tag(vty
, index
, "tag",
2340 argv
[idx_number
]->arg
);
2347 "no set tag [(1-4294967295)]",
2350 "Tag value for routing protocol\n"
2353 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2356 if (rmap_match_set_hook
.no_set_tag
) {
2357 if (argc
<= idx_number
)
2358 return rmap_match_set_hook
.no_set_tag(vty
, index
, "tag",
2360 return rmap_match_set_hook
.no_set_tag(vty
, index
, "tag",
2361 argv
[idx_number
]->arg
);
2367 DEFUN_NOSH (route_map
,
2369 "route-map WORD <deny|permit> (1-65535)",
2370 "Create route-map or enter route-map command mode\n"
2372 "Route map denies set operations\n"
2373 "Route map permits set operations\n"
2374 "Sequence to insert to/delete from existing route-map entry\n")
2377 int idx_permit_deny
= 2;
2379 struct route_map
*map
;
2380 struct route_map_index
*index
;
2381 char *endptr
= NULL
;
2383 argv
[idx_permit_deny
]->arg
[0] == 'p' ? RMAP_PERMIT
: RMAP_DENY
;
2384 unsigned long pref
= strtoul(argv
[idx_number
]->arg
, &endptr
, 10);
2385 const char *mapname
= argv
[idx_word
]->arg
;
2387 /* Get route map. */
2388 map
= route_map_get(mapname
);
2389 index
= route_map_index_get(map
, permit
, pref
);
2391 VTY_PUSH_CONTEXT(RMAP_NODE
, index
);
2395 DEFUN (no_route_map_all
,
2396 no_route_map_all_cmd
,
2397 "no route-map WORD",
2399 "Create route-map or enter route-map command mode\n"
2403 const char *mapname
= argv
[idx_word
]->arg
;
2404 struct route_map
*map
;
2406 map
= route_map_lookup_by_name(mapname
);
2408 vty_out(vty
, "%% Could not find route-map %s\n", mapname
);
2409 return CMD_WARNING_CONFIG_FAILED
;
2412 route_map_delete(map
);
2417 DEFUN (no_route_map
,
2419 "no route-map WORD <deny|permit> (1-65535)",
2421 "Create route-map or enter route-map command mode\n"
2423 "Route map denies set operations\n"
2424 "Route map permits set operations\n"
2425 "Sequence to insert to/delete from existing route-map entry\n")
2428 int idx_permit_deny
= 3;
2430 struct route_map
*map
;
2431 struct route_map_index
*index
;
2432 char *endptr
= NULL
;
2433 int permit
= strmatch(argv
[idx_permit_deny
]->text
, "permit")
2436 const char *prefstr
= argv
[idx_number
]->arg
;
2437 const char *mapname
= argv
[idx_word
]->arg
;
2438 unsigned long pref
= strtoul(prefstr
, &endptr
, 10);
2440 /* Existence check. */
2441 map
= route_map_lookup_by_name(mapname
);
2443 vty_out(vty
, "%% Could not find route-map %s\n", mapname
);
2444 return CMD_WARNING_CONFIG_FAILED
;
2447 /* Lookup route map index. */
2448 index
= route_map_index_lookup(map
, permit
, pref
);
2449 if (index
== NULL
) {
2450 vty_out(vty
, "%% Could not find route-map entry %s %s\n",
2452 return CMD_WARNING_CONFIG_FAILED
;
2455 /* Delete index from route map. */
2456 route_map_index_delete(index
, 1);
2458 /* If this route rule is the last one, delete route map itself. */
2459 if (route_map_empty(map
))
2460 route_map_delete(map
);
2465 DEFUN (rmap_onmatch_next
,
2466 rmap_onmatch_next_cmd
,
2468 "Exit policy on matches\n"
2471 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2474 if (index
->type
== RMAP_DENY
) {
2475 /* Under a deny clause, match means it's finished. No
2476 * need to set next */
2478 "on-match next not supported under route-map deny\n");
2479 return CMD_WARNING_CONFIG_FAILED
;
2481 index
->exitpolicy
= RMAP_NEXT
;
2486 DEFUN (no_rmap_onmatch_next
,
2487 no_rmap_onmatch_next_cmd
,
2490 "Exit policy on matches\n"
2493 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2496 index
->exitpolicy
= RMAP_EXIT
;
2501 DEFUN (rmap_onmatch_goto
,
2502 rmap_onmatch_goto_cmd
,
2503 "on-match goto (1-65535)",
2504 "Exit policy on matches\n"
2505 "Goto Clause number\n"
2509 char *num
= argv_find(argv
, argc
, "(1-65535)", &idx
) ? argv
[idx
]->arg
2512 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2516 if (index
->type
== RMAP_DENY
) {
2517 /* Under a deny clause, match means it's finished. No
2518 * need to go anywhere */
2520 "on-match goto not supported under route-map deny\n");
2521 return CMD_WARNING_CONFIG_FAILED
;
2525 d
= strtoul(num
, NULL
, 10);
2527 d
= index
->pref
+ 1;
2529 if (d
<= index
->pref
) {
2530 /* Can't allow you to do that, Dave */
2531 vty_out(vty
, "can't jump backwards in route-maps\n");
2532 return CMD_WARNING_CONFIG_FAILED
;
2534 index
->exitpolicy
= RMAP_GOTO
;
2535 index
->nextpref
= d
;
2541 DEFUN (no_rmap_onmatch_goto
,
2542 no_rmap_onmatch_goto_cmd
,
2545 "Exit policy on matches\n"
2546 "Goto Clause number\n")
2548 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2551 index
->exitpolicy
= RMAP_EXIT
;
2556 /* Cisco/GNU Zebra compatibility aliases */
2558 DEFUN (rmap_continue
,
2560 "continue (1-65535)",
2561 "Continue on a different entry within the route-map\n"
2562 "Route-map entry sequence number\n")
2564 return rmap_onmatch_goto(self
, vty
, argc
, argv
);
2568 DEFUN (no_rmap_continue
,
2569 no_rmap_continue_cmd
,
2570 "no continue [(1-65535)]",
2572 "Continue on a different entry within the route-map\n"
2573 "Route-map entry sequence number\n")
2575 return no_rmap_onmatch_goto(self
, vty
, argc
, argv
);
2579 DEFUN (rmap_show_name
,
2581 "show route-map [WORD]",
2583 "route-map information\n"
2587 const char *name
= (argc
== 3) ? argv
[idx_word
]->arg
: NULL
;
2588 return vty_show_route_map(vty
, name
);
2594 "Jump to another Route-Map after match+set\n"
2595 "Target route-map name\n")
2598 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2599 const char *rmap
= argv
[idx_word
]->arg
;
2603 if (index
->nextrm
) {
2604 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED
,
2605 index
->nextrm
, index
->map
->name
);
2606 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
2608 index
->nextrm
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap
);
2610 /* Execute event hook. */
2611 route_map_upd8_dependency(RMAP_EVENT_CALL_ADDED
, index
->nextrm
,
2616 DEFUN (no_rmap_call
,
2620 "Jump to another Route-Map after match+set\n")
2622 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2624 if (index
->nextrm
) {
2625 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED
,
2626 index
->nextrm
, index
->map
->name
);
2627 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
2628 index
->nextrm
= NULL
;
2634 DEFUN (rmap_description
,
2635 rmap_description_cmd
,
2636 "description LINE...",
2637 "Route-map comment\n"
2638 "Comment describing this route-map rule\n")
2641 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2644 if (index
->description
)
2645 XFREE(MTYPE_TMP
, index
->description
);
2646 index
->description
= argv_concat(argv
, argc
, idx_line
);
2651 DEFUN (no_rmap_description
,
2652 no_rmap_description_cmd
,
2655 "Route-map comment\n")
2657 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2660 if (index
->description
)
2661 XFREE(MTYPE_TMP
, index
->description
);
2662 index
->description
= NULL
;
2667 /* Configuration write function. */
2668 static int route_map_config_write(struct vty
*vty
)
2670 struct route_map
*map
;
2671 struct route_map_index
*index
;
2672 struct route_map_rule
*rule
;
2676 for (map
= route_map_master
.head
; map
; map
= map
->next
)
2677 for (index
= map
->head
; index
; index
= index
->next
) {
2679 vty_out(vty
, "!\n");
2683 vty_out(vty
, "route-map %s %s %d\n", map
->name
,
2684 route_map_type_str(index
->type
), index
->pref
);
2686 if (index
->description
)
2687 vty_out(vty
, " description %s\n",
2688 index
->description
);
2690 for (rule
= index
->match_list
.head
; rule
;
2692 vty_out(vty
, " match %s %s\n", rule
->cmd
->str
,
2693 rule
->rule_str
? rule
->rule_str
: "");
2695 for (rule
= index
->set_list
.head
; rule
;
2697 vty_out(vty
, " set %s %s\n", rule
->cmd
->str
,
2698 rule
->rule_str
? rule
->rule_str
: "");
2700 vty_out(vty
, " call %s\n", index
->nextrm
);
2701 if (index
->exitpolicy
== RMAP_GOTO
)
2702 vty_out(vty
, " on-match goto %d\n",
2704 if (index
->exitpolicy
== RMAP_NEXT
)
2705 vty_out(vty
, " on-match next\n");
2712 /* Route map node structure. */
2713 static struct cmd_node rmap_node
= {RMAP_NODE
, "%s(config-route-map)# ", 1};
2715 /* Common route map rules */
2717 void *route_map_rule_tag_compile(const char *arg
)
2719 unsigned long int tmp
;
2724 tmp
= strtoul(arg
, &endptr
, 0);
2725 if (arg
[0] == '\0' || *endptr
!= '\0' || errno
|| tmp
> ROUTE_TAG_MAX
)
2728 tag
= XMALLOC(MTYPE_ROUTE_MAP_COMPILED
, sizeof(*tag
));
2734 void route_map_rule_tag_free(void *rule
)
2736 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
2739 void route_map_finish(void)
2743 vector_free(route_match_vec
);
2744 route_match_vec
= NULL
;
2745 vector_free(route_set_vec
);
2746 route_set_vec
= NULL
;
2748 /* cleanup route_map */
2749 while (route_map_master
.head
) {
2750 struct route_map
*map
= route_map_master
.head
;
2751 map
->to_be_processed
= 0;
2752 route_map_delete(map
);
2755 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
2756 hash_free(route_map_dep_hash
[i
]);
2757 route_map_dep_hash
[i
] = NULL
;
2760 hash_free(route_map_master_hash
);
2761 route_map_master_hash
= NULL
;
2764 static void rmap_autocomplete(vector comps
, struct cmd_token
*token
)
2766 struct route_map
*map
;
2768 for (map
= route_map_master
.head
; map
; map
= map
->next
)
2769 vector_set(comps
, XSTRDUP(MTYPE_COMPLETION
, map
->name
));
2772 static const struct cmd_variable_handler rmap_var_handlers
[] = {
2773 {/* "route-map WORD" */
2774 .varname
= "route_map",
2775 .completions
= rmap_autocomplete
},
2776 {.tokenname
= "ROUTEMAP_NAME", .completions
= rmap_autocomplete
},
2777 {.tokenname
= "RMAP_NAME", .completions
= rmap_autocomplete
},
2778 {.completions
= NULL
}};
2780 /* Initialization of route map vector. */
2781 void route_map_init(void)
2785 /* Make vector for match and set. */
2786 route_match_vec
= vector_init(1);
2787 route_set_vec
= vector_init(1);
2788 route_map_master_hash
=
2789 hash_create_size(8, route_map_hash_key_make
,
2791 "Route Map Master Hash");
2793 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++)
2794 route_map_dep_hash
[i
] =
2795 hash_create_size(8, route_map_dep_hash_make_key
,
2796 route_map_dep_hash_cmp
,
2797 "Route Map Dep Hash");
2799 cmd_variable_handler_register(rmap_var_handlers
);
2801 /* Install route map top node. */
2802 install_node(&rmap_node
, route_map_config_write
);
2804 /* Install route map commands. */
2805 install_default(RMAP_NODE
);
2806 install_element(CONFIG_NODE
, &route_map_cmd
);
2807 install_element(CONFIG_NODE
, &no_route_map_cmd
);
2808 install_element(CONFIG_NODE
, &no_route_map_all_cmd
);
2810 /* Install the on-match stuff */
2811 install_element(RMAP_NODE
, &route_map_cmd
);
2812 install_element(RMAP_NODE
, &rmap_onmatch_next_cmd
);
2813 install_element(RMAP_NODE
, &no_rmap_onmatch_next_cmd
);
2814 install_element(RMAP_NODE
, &rmap_onmatch_goto_cmd
);
2815 install_element(RMAP_NODE
, &no_rmap_onmatch_goto_cmd
);
2816 install_element(RMAP_NODE
, &rmap_continue_cmd
);
2817 install_element(RMAP_NODE
, &no_rmap_continue_cmd
);
2819 /* Install the continue stuff (ALIAS of on-match). */
2821 /* Install the call stuff. */
2822 install_element(RMAP_NODE
, &rmap_call_cmd
);
2823 install_element(RMAP_NODE
, &no_rmap_call_cmd
);
2825 /* Install description commands. */
2826 install_element(RMAP_NODE
, &rmap_description_cmd
);
2827 install_element(RMAP_NODE
, &no_rmap_description_cmd
);
2829 /* Install show command */
2830 install_element(ENABLE_NODE
, &rmap_show_name_cmd
);
2832 install_element(RMAP_NODE
, &match_interface_cmd
);
2833 install_element(RMAP_NODE
, &no_match_interface_cmd
);
2835 install_element(RMAP_NODE
, &match_ip_address_cmd
);
2836 install_element(RMAP_NODE
, &no_match_ip_address_cmd
);
2838 install_element(RMAP_NODE
, &match_ip_address_prefix_list_cmd
);
2839 install_element(RMAP_NODE
, &no_match_ip_address_prefix_list_cmd
);
2841 install_element(RMAP_NODE
, &match_ip_next_hop_cmd
);
2842 install_element(RMAP_NODE
, &no_match_ip_next_hop_cmd
);
2844 install_element(RMAP_NODE
, &match_ip_next_hop_prefix_list_cmd
);
2845 install_element(RMAP_NODE
, &no_match_ip_next_hop_prefix_list_cmd
);
2847 install_element(RMAP_NODE
, &match_ipv6_address_cmd
);
2848 install_element(RMAP_NODE
, &no_match_ipv6_address_cmd
);
2850 install_element(RMAP_NODE
, &match_ipv6_address_prefix_list_cmd
);
2851 install_element(RMAP_NODE
, &no_match_ipv6_address_prefix_list_cmd
);
2853 install_element(RMAP_NODE
, &match_metric_cmd
);
2854 install_element(RMAP_NODE
, &no_match_metric_cmd
);
2856 install_element(RMAP_NODE
, &match_tag_cmd
);
2857 install_element(RMAP_NODE
, &no_match_tag_cmd
);
2859 install_element(RMAP_NODE
, &set_ip_nexthop_cmd
);
2860 install_element(RMAP_NODE
, &no_set_ip_nexthop_cmd
);
2862 install_element(RMAP_NODE
, &set_ipv6_nexthop_local_cmd
);
2863 install_element(RMAP_NODE
, &no_set_ipv6_nexthop_local_cmd
);
2865 install_element(RMAP_NODE
, &set_metric_cmd
);
2866 install_element(RMAP_NODE
, &no_set_metric_cmd
);
2868 install_element(RMAP_NODE
, &set_tag_cmd
);
2869 install_element(RMAP_NODE
, &no_set_tag_cmd
);