2 * Copyright (C) 1998, 1999 Kunihiro Ishiguro
4 * This file is part of GNU Zebra.
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
33 #include "lib_errors.h"
35 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP
, "Route map")
36 DEFINE_MTYPE(LIB
, ROUTE_MAP_NAME
, "Route map name")
37 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_INDEX
, "Route map index")
38 DEFINE_MTYPE(LIB
, ROUTE_MAP_RULE
, "Route map rule")
39 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_RULE_STR
, "Route map rule str")
40 DEFINE_MTYPE(LIB
, ROUTE_MAP_COMPILED
, "Route map compiled")
41 DEFINE_MTYPE_STATIC(LIB
, ROUTE_MAP_DEP
, "Route map dependency")
43 DEFINE_QOBJ_TYPE(route_map_index
)
44 DEFINE_QOBJ_TYPE(route_map
)
46 /* Vector for route match rules. */
47 static vector route_match_vec
;
49 /* Vector for route set rules. */
50 static vector route_set_vec
;
52 struct route_map_match_set_hooks
{
54 int (*match_interface
)(struct vty
*vty
, struct route_map_index
*index
,
55 const char *command
, const char *arg
,
56 route_map_event_t type
);
58 /* no match interface */
59 int (*no_match_interface
)(struct vty
*vty
,
60 struct route_map_index
*index
,
61 const char *command
, const char *arg
,
62 route_map_event_t type
);
64 /* match ip address */
65 int (*match_ip_address
)(struct vty
*vty
, struct route_map_index
*index
,
66 const char *command
, const char *arg
,
67 route_map_event_t type
);
69 /* no match ip address */
70 int (*no_match_ip_address
)(struct vty
*vty
,
71 struct route_map_index
*index
,
72 const char *command
, const char *arg
,
73 route_map_event_t type
);
75 /* match ip address prefix list */
76 int (*match_ip_address_prefix_list
)(struct vty
*vty
,
77 struct route_map_index
*index
,
80 route_map_event_t type
);
82 /* no match ip address prefix list */
83 int (*no_match_ip_address_prefix_list
)(struct vty
*vty
,
84 struct route_map_index
*index
,
87 route_map_event_t type
);
89 /* match ip next hop */
90 int (*match_ip_next_hop
)(struct vty
*vty
, struct route_map_index
*index
,
91 const char *command
, const char *arg
,
92 route_map_event_t type
);
94 /* no match ip next hop */
95 int (*no_match_ip_next_hop
)(struct vty
*vty
,
96 struct route_map_index
*index
,
97 const char *command
, const char *arg
,
98 route_map_event_t type
);
100 /* match ip next hop prefix list */
101 int (*match_ip_next_hop_prefix_list
)(struct vty
*vty
,
102 struct route_map_index
*index
,
105 route_map_event_t type
);
107 /* no match ip next hop prefix list */
108 int (*no_match_ip_next_hop_prefix_list
)(struct vty
*vty
,
109 struct route_map_index
*index
,
112 route_map_event_t type
);
114 /* match ipv6 address */
115 int (*match_ipv6_address
)(struct vty
*vty
,
116 struct route_map_index
*index
,
117 const char *command
, const char *arg
,
118 route_map_event_t type
);
120 /* no match ipv6 address */
121 int (*no_match_ipv6_address
)(struct vty
*vty
,
122 struct route_map_index
*index
,
123 const char *command
, const char *arg
,
124 route_map_event_t type
);
127 /* match ipv6 address prefix list */
128 int (*match_ipv6_address_prefix_list
)(struct vty
*vty
,
129 struct route_map_index
*index
,
132 route_map_event_t type
);
134 /* no match ipv6 address prefix list */
135 int (*no_match_ipv6_address_prefix_list
)(struct vty
*vty
,
136 struct route_map_index
*index
,
139 route_map_event_t type
);
142 int (*match_metric
)(struct vty
*vty
, struct route_map_index
*index
,
143 const char *command
, const char *arg
,
144 route_map_event_t type
);
146 /* no match metric */
147 int (*no_match_metric
)(struct vty
*vty
, struct route_map_index
*index
,
148 const char *command
, const char *arg
,
149 route_map_event_t type
);
152 int (*match_tag
)(struct vty
*vty
, struct route_map_index
*index
,
153 const char *command
, const char *arg
,
154 route_map_event_t type
);
157 int (*no_match_tag
)(struct vty
*vty
, struct route_map_index
*index
,
158 const char *command
, const char *arg
,
159 route_map_event_t type
);
162 int (*set_ip_nexthop
)(struct vty
*vty
, struct route_map_index
*index
,
163 const char *command
, const char *arg
);
165 /* no set ip nexthop */
166 int (*no_set_ip_nexthop
)(struct vty
*vty
, struct route_map_index
*index
,
167 const char *command
, const char *arg
);
169 /* set ipv6 nexthop local */
170 int (*set_ipv6_nexthop_local
)(struct vty
*vty
,
171 struct route_map_index
*index
,
172 const char *command
, const char *arg
);
174 /* no set ipv6 nexthop local */
175 int (*no_set_ipv6_nexthop_local
)(struct vty
*vty
,
176 struct route_map_index
*index
,
177 const char *command
, const char *arg
);
180 int (*set_metric
)(struct vty
*vty
, struct route_map_index
*index
,
181 const char *command
, const char *arg
);
184 int (*no_set_metric
)(struct vty
*vty
, struct route_map_index
*index
,
185 const char *command
, const char *arg
);
188 int (*set_tag
)(struct vty
*vty
, struct route_map_index
*index
,
189 const char *command
, const char *arg
);
192 int (*no_set_tag
)(struct vty
*vty
, struct route_map_index
*index
,
193 const char *command
, const char *arg
);
196 struct route_map_match_set_hooks rmap_match_set_hook
;
198 /* match interface */
199 void route_map_match_interface_hook(int (*func
)(
200 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
201 const char *arg
, route_map_event_t type
))
203 rmap_match_set_hook
.match_interface
= func
;
206 /* no match interface */
207 void route_map_no_match_interface_hook(int (*func
)(
208 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
209 const char *arg
, route_map_event_t type
))
211 rmap_match_set_hook
.no_match_interface
= func
;
214 /* match ip address */
215 void route_map_match_ip_address_hook(int (*func
)(
216 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
217 const char *arg
, route_map_event_t type
))
219 rmap_match_set_hook
.match_ip_address
= func
;
222 /* no match ip address */
223 void route_map_no_match_ip_address_hook(int (*func
)(
224 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
225 const char *arg
, route_map_event_t type
))
227 rmap_match_set_hook
.no_match_ip_address
= func
;
230 /* match ip address prefix list */
231 void route_map_match_ip_address_prefix_list_hook(int (*func
)(
232 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
233 const char *arg
, route_map_event_t type
))
235 rmap_match_set_hook
.match_ip_address_prefix_list
= func
;
238 /* no match ip address prefix list */
239 void route_map_no_match_ip_address_prefix_list_hook(int (*func
)(
240 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
241 const char *arg
, route_map_event_t type
))
243 rmap_match_set_hook
.no_match_ip_address_prefix_list
= func
;
246 /* match ip next hop */
247 void route_map_match_ip_next_hop_hook(int (*func
)(
248 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
249 const char *arg
, route_map_event_t type
))
251 rmap_match_set_hook
.match_ip_next_hop
= func
;
254 /* no match ip next hop */
255 void route_map_no_match_ip_next_hop_hook(int (*func
)(
256 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
257 const char *arg
, route_map_event_t type
))
259 rmap_match_set_hook
.no_match_ip_next_hop
= func
;
262 /* match ip next hop prefix list */
263 void route_map_match_ip_next_hop_prefix_list_hook(int (*func
)(
264 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
265 const char *arg
, route_map_event_t type
))
267 rmap_match_set_hook
.match_ip_next_hop_prefix_list
= func
;
270 /* no match ip next hop prefix list */
271 void route_map_no_match_ip_next_hop_prefix_list_hook(int (*func
)(
272 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
273 const char *arg
, route_map_event_t type
))
275 rmap_match_set_hook
.no_match_ip_next_hop_prefix_list
= func
;
278 /* match ipv6 address */
279 void route_map_match_ipv6_address_hook(int (*func
)(
280 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
281 const char *arg
, route_map_event_t type
))
283 rmap_match_set_hook
.match_ipv6_address
= func
;
286 /* no match ipv6 address */
287 void route_map_no_match_ipv6_address_hook(int (*func
)(
288 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
289 const char *arg
, route_map_event_t type
))
291 rmap_match_set_hook
.no_match_ipv6_address
= func
;
295 /* match ipv6 address prefix list */
296 void route_map_match_ipv6_address_prefix_list_hook(int (*func
)(
297 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
298 const char *arg
, route_map_event_t type
))
300 rmap_match_set_hook
.match_ipv6_address_prefix_list
= func
;
303 /* no match ipv6 address prefix list */
304 void route_map_no_match_ipv6_address_prefix_list_hook(int (*func
)(
305 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
306 const char *arg
, route_map_event_t type
))
308 rmap_match_set_hook
.no_match_ipv6_address_prefix_list
= func
;
312 void route_map_match_metric_hook(int (*func
)(
313 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
314 const char *arg
, route_map_event_t type
))
316 rmap_match_set_hook
.match_metric
= func
;
319 /* no match metric */
320 void route_map_no_match_metric_hook(int (*func
)(
321 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
322 const char *arg
, route_map_event_t type
))
324 rmap_match_set_hook
.no_match_metric
= func
;
328 void route_map_match_tag_hook(int (*func
)(struct vty
*vty
,
329 struct route_map_index
*index
,
330 const char *command
, const char *arg
,
331 route_map_event_t type
))
333 rmap_match_set_hook
.match_tag
= func
;
337 void route_map_no_match_tag_hook(int (*func
)(
338 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
339 const char *arg
, route_map_event_t type
))
341 rmap_match_set_hook
.no_match_tag
= func
;
345 void route_map_set_ip_nexthop_hook(int (*func
)(struct vty
*vty
,
346 struct route_map_index
*index
,
350 rmap_match_set_hook
.set_ip_nexthop
= func
;
353 /* no set ip nexthop */
354 void route_map_no_set_ip_nexthop_hook(int (*func
)(struct vty
*vty
,
355 struct route_map_index
*index
,
359 rmap_match_set_hook
.no_set_ip_nexthop
= func
;
362 /* set ipv6 nexthop local */
363 void route_map_set_ipv6_nexthop_local_hook(
364 int (*func
)(struct vty
*vty
, struct route_map_index
*index
,
365 const char *command
, const char *arg
))
367 rmap_match_set_hook
.set_ipv6_nexthop_local
= func
;
370 /* no set ipv6 nexthop local */
371 void route_map_no_set_ipv6_nexthop_local_hook(
372 int (*func
)(struct vty
*vty
, struct route_map_index
*index
,
373 const char *command
, const char *arg
))
375 rmap_match_set_hook
.no_set_ipv6_nexthop_local
= func
;
379 void route_map_set_metric_hook(int (*func
)(struct vty
*vty
,
380 struct route_map_index
*index
,
384 rmap_match_set_hook
.set_metric
= func
;
388 void route_map_no_set_metric_hook(int (*func
)(struct vty
*vty
,
389 struct route_map_index
*index
,
393 rmap_match_set_hook
.no_set_metric
= func
;
397 void route_map_set_tag_hook(int (*func
)(struct vty
*vty
,
398 struct route_map_index
*index
,
399 const char *command
, const char *arg
))
401 rmap_match_set_hook
.set_tag
= func
;
405 void route_map_no_set_tag_hook(int (*func
)(struct vty
*vty
,
406 struct route_map_index
*index
,
410 rmap_match_set_hook
.no_set_tag
= func
;
413 int generic_match_add(struct vty
*vty
, struct route_map_index
*index
,
414 const char *command
, const char *arg
,
415 route_map_event_t type
)
419 ret
= route_map_add_match(index
, command
, arg
);
421 case RMAP_COMPILE_SUCCESS
:
422 if (type
!= RMAP_EVENT_MATCH_ADDED
) {
423 route_map_upd8_dependency(type
, arg
, index
->map
->name
);
426 case RMAP_RULE_MISSING
:
427 vty_out(vty
, "%% [%s] Can't find rule.\n", frr_protonameinst
);
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", frr_protonameinst
);
468 retval
= CMD_WARNING_CONFIG_FAILED
;
470 case RMAP_COMPILE_ERROR
:
472 "%% [%s] Argument form is unsupported or malformed.\n",
474 retval
= CMD_WARNING_CONFIG_FAILED
;
476 case RMAP_COMPILE_SUCCESS
:
477 if (type
!= RMAP_EVENT_MATCH_DELETED
&& dep_name
)
478 route_map_upd8_dependency(type
, dep_name
, rmap_name
);
483 XFREE(MTYPE_ROUTE_MAP_RULE
, dep_name
);
485 XFREE(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
490 int generic_set_add(struct vty
*vty
, struct route_map_index
*index
,
491 const char *command
, const char *arg
)
495 ret
= route_map_add_set(index
, command
, arg
);
497 case RMAP_RULE_MISSING
:
498 vty_out(vty
, "%% [%s] Can't find rule.\n", frr_protonameinst
);
499 return CMD_WARNING_CONFIG_FAILED
;
501 case RMAP_COMPILE_ERROR
:
503 "%% [%s] Argument form is unsupported or malformed.\n",
505 return CMD_WARNING_CONFIG_FAILED
;
507 case RMAP_COMPILE_SUCCESS
:
514 int generic_set_delete(struct vty
*vty
, struct route_map_index
*index
,
515 const char *command
, const char *arg
)
519 ret
= route_map_delete_set(index
, command
, arg
);
521 case RMAP_RULE_MISSING
:
522 vty_out(vty
, "%% [%s] Can't find rule.\n", frr_protonameinst
);
523 return CMD_WARNING_CONFIG_FAILED
;
525 case RMAP_COMPILE_ERROR
:
527 "%% [%s] Argument form is unsupported or malformed.\n",
529 return CMD_WARNING_CONFIG_FAILED
;
531 case RMAP_COMPILE_SUCCESS
:
539 /* Route map rule. This rule has both `match' rule and `set' rule. */
540 struct route_map_rule
{
542 struct route_map_rule_cmd
*cmd
;
544 /* For pretty printing. */
547 /* Pre-compiled match rule. */
551 struct route_map_rule
*next
;
552 struct route_map_rule
*prev
;
555 /* Making route map list. */
556 struct route_map_list
{
557 struct route_map
*head
;
558 struct route_map
*tail
;
560 void (*add_hook
)(const char *);
561 void (*delete_hook
)(const char *);
562 void (*event_hook
)(route_map_event_t
, const char *);
565 /* Master list of route map. */
566 static struct route_map_list route_map_master
= {NULL
, NULL
, NULL
, NULL
, NULL
};
567 struct hash
*route_map_master_hash
= NULL
;
569 static unsigned int route_map_hash_key_make(void *p
)
571 const struct route_map
*map
= p
;
572 return string_hash_make(map
->name
);
575 static int route_map_hash_cmp(const void *p1
, const void *p2
)
577 const struct route_map
*map1
= p1
;
578 const struct route_map
*map2
= p2
;
580 if (map1
->deleted
== map2
->deleted
) {
581 if (map1
->name
&& map2
->name
) {
582 if (!strcmp(map1
->name
, map2
->name
)) {
585 } else if (!map1
->name
&& !map2
->name
) {
593 enum route_map_upd8_type
{
598 /* all possible route-map dependency types */
599 enum route_map_dep_type
{
600 ROUTE_MAP_DEP_RMAP
= 1,
602 ROUTE_MAP_DEP_ECLIST
,
603 ROUTE_MAP_DEP_LCLIST
,
605 ROUTE_MAP_DEP_ASPATH
,
606 ROUTE_MAP_DEP_FILTER
,
610 struct route_map_dep
{
612 struct hash
*dep_rmap_hash
;
613 struct hash
*this_hash
; /* ptr to the hash structure this is part of */
616 /* Hashes maintaining dependency between various sublists used by route maps */
617 struct hash
*route_map_dep_hash
[ROUTE_MAP_DEP_MAX
];
619 static unsigned int route_map_dep_hash_make_key(void *p
);
620 static int route_map_dep_hash_cmp(const void *p1
, const void *p2
);
621 static void route_map_clear_all_references(char *rmap_name
);
622 static void route_map_rule_delete(struct route_map_rule_list
*,
623 struct route_map_rule
*);
624 static int rmap_debug
= 0;
626 static void route_map_index_delete(struct route_map_index
*, int);
628 /* New route map allocation. Please note route map's name must be
630 static struct route_map
*route_map_new(const char *name
)
632 struct route_map
*new;
634 new = XCALLOC(MTYPE_ROUTE_MAP
, sizeof(struct route_map
));
635 new->name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
636 QOBJ_REG(new, route_map
);
640 /* Add new name to route_map. */
641 static struct route_map
*route_map_add(const char *name
)
643 struct route_map
*map
;
644 struct route_map_list
*list
;
646 map
= route_map_new(name
);
647 list
= &route_map_master
;
649 /* Add map to the hash */
650 hash_get(route_map_master_hash
, map
, hash_alloc_intern
);
652 /* Add new entry to the head of the list to match how it is added in the
653 * hash table. This is to ensure that if the same route-map has been
654 * created more than once and then marked for deletion (which can happen
655 * if prior deletions haven't completed as BGP hasn't yet done the
656 * route-map processing), the order of the entities is the same in both
657 * the list and the hash table. Otherwise, since there is nothing to
658 * distinguish between the two entries, the wrong entry could get freed.
659 * TODO: This needs to be re-examined to handle it better - e.g., revive
660 * a deleted entry if the route-map is created again.
663 map
->next
= list
->head
;
665 list
->head
->prev
= map
;
671 if (route_map_master
.add_hook
) {
672 (*route_map_master
.add_hook
)(name
);
673 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_ADDED
);
678 /* this is supposed to be called post processing by
679 * the delete hook function. Don't invoke delete_hook
680 * again in this routine.
682 static void route_map_free_map(struct route_map
*map
)
684 struct route_map_list
*list
;
685 struct route_map_index
*index
;
690 while ((index
= map
->head
) != NULL
)
691 route_map_index_delete(index
, 0);
693 list
= &route_map_master
;
698 map
->next
->prev
= map
->prev
;
700 list
->tail
= map
->prev
;
703 map
->prev
->next
= map
->next
;
705 list
->head
= map
->next
;
707 hash_release(route_map_master_hash
, map
);
708 XFREE(MTYPE_ROUTE_MAP_NAME
, map
->name
);
709 XFREE(MTYPE_ROUTE_MAP
, map
);
712 /* Route map delete from list. */
713 static void route_map_delete(struct route_map
*map
)
715 struct route_map_index
*index
;
718 while ((index
= map
->head
) != NULL
)
719 route_map_index_delete(index
, 0);
724 /* Clear all dependencies */
725 route_map_clear_all_references(name
);
727 /* Execute deletion hook. */
728 if (route_map_master
.delete_hook
) {
729 (*route_map_master
.delete_hook
)(name
);
730 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_DELETED
);
733 if (!map
->to_be_processed
) {
734 route_map_free_map(map
);
738 /* Lookup route map by route map name string. */
739 struct route_map
*route_map_lookup_by_name(const char *name
)
741 struct route_map
*map
;
742 struct route_map tmp_map
;
747 // map.deleted is 0 via memset
748 memset(&tmp_map
, 0, sizeof(struct route_map
));
749 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
750 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
751 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
755 int route_map_mark_updated(const char *name
)
757 struct route_map
*map
;
759 struct route_map tmp_map
;
764 map
= route_map_lookup_by_name(name
);
766 /* If we did not find the routemap with deleted=false try again
770 memset(&tmp_map
, 0, sizeof(struct route_map
));
771 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
772 tmp_map
.deleted
= true;
773 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
774 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
778 map
->to_be_processed
= true;
785 static int route_map_clear_updated(struct route_map
*map
)
790 map
->to_be_processed
= false;
792 route_map_free_map(map
);
798 /* Lookup route map. If there isn't route map create one and return
800 static struct route_map
*route_map_get(const char *name
)
802 struct route_map
*map
;
804 map
= route_map_lookup_by_name(name
);
806 map
= route_map_add(name
);
811 void route_map_walk_update_list(void (*route_map_update_fn
)(char *name
))
813 struct route_map
*node
;
814 struct route_map
*nnode
= NULL
;
816 for (node
= route_map_master
.head
; node
; node
= nnode
) {
817 if (node
->to_be_processed
) {
818 /* DD: Should we add any thread yield code here */
819 route_map_update_fn(node
->name
);
821 route_map_clear_updated(node
);
827 /* Return route map's type string. */
828 static const char *route_map_type_str(enum route_map_type type
)
843 static int route_map_empty(struct route_map
*map
)
845 if (map
->head
== NULL
&& map
->tail
== NULL
)
852 static void vty_show_route_map_entry(struct vty
*vty
, struct route_map
*map
)
854 struct route_map_index
*index
;
855 struct route_map_rule
*rule
;
857 vty_out(vty
, "%s:\n", frr_protonameinst
);
859 for (index
= map
->head
; index
; index
= index
->next
) {
860 vty_out(vty
, "route-map %s, %s, sequence %d\n", map
->name
,
861 route_map_type_str(index
->type
), index
->pref
);
864 if (index
->description
)
865 vty_out(vty
, " Description:\n %s\n",
869 vty_out(vty
, " Match clauses:\n");
870 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
871 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
874 vty_out(vty
, " Set clauses:\n");
875 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
876 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
880 vty_out(vty
, " Call clause:\n");
882 vty_out(vty
, " Call %s\n", index
->nextrm
);
885 vty_out(vty
, " Action:\n");
886 if (index
->exitpolicy
== RMAP_GOTO
)
887 vty_out(vty
, " Goto %d\n", index
->nextpref
);
888 else if (index
->exitpolicy
== RMAP_NEXT
)
889 vty_out(vty
, " Continue to next entry\n");
890 else if (index
->exitpolicy
== RMAP_EXIT
)
891 vty_out(vty
, " Exit routemap\n");
895 static int sort_route_map(const void **map1
, const void **map2
)
897 const struct route_map
*m1
= *map1
;
898 const struct route_map
*m2
= *map2
;
900 return strcmp(m1
->name
, m2
->name
);
903 static int vty_show_route_map(struct vty
*vty
, const char *name
)
905 struct route_map
*map
;
908 map
= route_map_lookup_by_name(name
);
911 vty_show_route_map_entry(vty
, map
);
914 vty_out(vty
, "%s: 'route-map %s' not found\n",
915 frr_protonameinst
, name
);
920 struct list
*maplist
= list_new();
923 for (map
= route_map_master
.head
; map
; map
= map
->next
)
924 listnode_add(maplist
, map
);
926 list_sort(maplist
, sort_route_map
);
928 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
929 vty_show_route_map_entry(vty
, map
);
931 list_delete_and_null(&maplist
);
937 /* New route map allocation. Please note route map's name must be
939 static struct route_map_index
*route_map_index_new(void)
941 struct route_map_index
*new;
943 new = XCALLOC(MTYPE_ROUTE_MAP_INDEX
, sizeof(struct route_map_index
));
944 new->exitpolicy
= RMAP_EXIT
; /* Default to Cisco-style */
945 QOBJ_REG(new, route_map_index
);
949 /* Free route map index. */
950 static void route_map_index_delete(struct route_map_index
*index
, int notify
)
952 struct route_map_rule
*rule
;
956 /* Free route match. */
957 while ((rule
= index
->match_list
.head
) != NULL
)
958 route_map_rule_delete(&index
->match_list
, rule
);
960 /* Free route set. */
961 while ((rule
= index
->set_list
.head
) != NULL
)
962 route_map_rule_delete(&index
->set_list
, rule
);
964 /* Remove index from route map list. */
966 index
->next
->prev
= index
->prev
;
968 index
->map
->tail
= index
->prev
;
971 index
->prev
->next
= index
->next
;
973 index
->map
->head
= index
->next
;
975 /* Free 'char *nextrm' if not NULL */
977 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
979 /* Execute event hook. */
980 if (route_map_master
.event_hook
&& notify
) {
981 (*route_map_master
.event_hook
)(RMAP_EVENT_INDEX_DELETED
,
983 route_map_notify_dependencies(index
->map
->name
,
984 RMAP_EVENT_CALL_ADDED
);
986 XFREE(MTYPE_ROUTE_MAP_INDEX
, index
);
989 /* Lookup index from route map. */
990 static struct route_map_index
*route_map_index_lookup(struct route_map
*map
,
991 enum route_map_type type
,
994 struct route_map_index
*index
;
996 for (index
= map
->head
; index
; index
= index
->next
)
997 if ((index
->type
== type
|| type
== RMAP_ANY
)
998 && index
->pref
== pref
)
1003 /* Add new index to route map. */
1004 static struct route_map_index
*
1005 route_map_index_add(struct route_map
*map
, enum route_map_type type
, int pref
)
1007 struct route_map_index
*index
;
1008 struct route_map_index
*point
;
1010 /* Allocate new route map inex. */
1011 index
= route_map_index_new();
1016 /* Compare preference. */
1017 for (point
= map
->head
; point
; point
= point
->next
)
1018 if (point
->pref
>= pref
)
1021 if (map
->head
== NULL
) {
1022 map
->head
= map
->tail
= index
;
1023 } else if (point
== NULL
) {
1024 index
->prev
= map
->tail
;
1025 map
->tail
->next
= index
;
1027 } else if (point
== map
->head
) {
1028 index
->next
= map
->head
;
1029 map
->head
->prev
= index
;
1032 index
->next
= point
;
1033 index
->prev
= point
->prev
;
1035 point
->prev
->next
= index
;
1036 point
->prev
= index
;
1039 /* Execute event hook. */
1040 if (route_map_master
.event_hook
) {
1041 (*route_map_master
.event_hook
)(RMAP_EVENT_INDEX_ADDED
,
1043 route_map_notify_dependencies(map
->name
, RMAP_EVENT_CALL_ADDED
);
1048 /* Get route map index. */
1049 static struct route_map_index
*
1050 route_map_index_get(struct route_map
*map
, enum route_map_type type
, int pref
)
1052 struct route_map_index
*index
;
1054 index
= route_map_index_lookup(map
, RMAP_ANY
, pref
);
1055 if (index
&& index
->type
!= type
) {
1056 /* Delete index from route map. */
1057 route_map_index_delete(index
, 1);
1061 index
= route_map_index_add(map
, type
, pref
);
1065 /* New route map rule */
1066 static struct route_map_rule
*route_map_rule_new(void)
1068 struct route_map_rule
*new;
1070 new = XCALLOC(MTYPE_ROUTE_MAP_RULE
, sizeof(struct route_map_rule
));
1074 /* Install rule command to the match list. */
1075 void route_map_install_match(struct route_map_rule_cmd
*cmd
)
1077 vector_set(route_match_vec
, cmd
);
1080 /* Install rule command to the set list. */
1081 void route_map_install_set(struct route_map_rule_cmd
*cmd
)
1083 vector_set(route_set_vec
, cmd
);
1086 /* Lookup rule command from match list. */
1087 static struct route_map_rule_cmd
*route_map_lookup_match(const char *name
)
1090 struct route_map_rule_cmd
*rule
;
1092 for (i
= 0; i
< vector_active(route_match_vec
); i
++)
1093 if ((rule
= vector_slot(route_match_vec
, i
)) != NULL
)
1094 if (strcmp(rule
->str
, name
) == 0)
1099 /* Lookup rule command from set list. */
1100 static struct route_map_rule_cmd
*route_map_lookup_set(const char *name
)
1103 struct route_map_rule_cmd
*rule
;
1105 for (i
= 0; i
< vector_active(route_set_vec
); i
++)
1106 if ((rule
= vector_slot(route_set_vec
, i
)) != NULL
)
1107 if (strcmp(rule
->str
, name
) == 0)
1112 /* Add match and set rule to rule list. */
1113 static void route_map_rule_add(struct route_map_rule_list
*list
,
1114 struct route_map_rule
*rule
)
1117 rule
->prev
= list
->tail
;
1119 list
->tail
->next
= rule
;
1125 /* Delete rule from rule list. */
1126 static void route_map_rule_delete(struct route_map_rule_list
*list
,
1127 struct route_map_rule
*rule
)
1129 if (rule
->cmd
->func_free
)
1130 (*rule
->cmd
->func_free
)(rule
->value
);
1133 XFREE(MTYPE_ROUTE_MAP_RULE_STR
, rule
->rule_str
);
1136 rule
->next
->prev
= rule
->prev
;
1138 list
->tail
= rule
->prev
;
1140 rule
->prev
->next
= rule
->next
;
1142 list
->head
= rule
->next
;
1144 XFREE(MTYPE_ROUTE_MAP_RULE
, rule
);
1147 /* strcmp wrapper function which don't crush even argument is NULL. */
1148 static int rulecmp(const char *dst
, const char *src
)
1159 return strcmp(dst
, src
);
1164 /* Use this to return the already specified argument for this match. This is
1165 * useful to get the specified argument with a route map match rule when the
1166 * rule is being deleted and the argument is not provided.
1168 const char *route_map_get_match_arg(struct route_map_index
*index
,
1169 const char *match_name
)
1171 struct route_map_rule
*rule
;
1172 struct route_map_rule_cmd
*cmd
;
1174 /* First lookup rule for add match statement. */
1175 cmd
= route_map_lookup_match(match_name
);
1179 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1180 if (rule
->cmd
== cmd
&& rule
->rule_str
!= NULL
)
1181 return (rule
->rule_str
);
1186 /* Add match statement to route map. */
1187 int route_map_add_match(struct route_map_index
*index
, const char *match_name
,
1188 const char *match_arg
)
1190 struct route_map_rule
*rule
;
1191 struct route_map_rule
*next
;
1192 struct route_map_rule_cmd
*cmd
;
1196 /* First lookup rule for add match statement. */
1197 cmd
= route_map_lookup_match(match_name
);
1199 return RMAP_RULE_MISSING
;
1201 /* Next call compile function for this match statement. */
1202 if (cmd
->func_compile
) {
1203 compile
= (*cmd
->func_compile
)(match_arg
);
1204 if (compile
== NULL
)
1205 return RMAP_COMPILE_ERROR
;
1209 /* If argument is completely same ignore it. */
1210 for (rule
= index
->match_list
.head
; rule
; rule
= next
) {
1212 if (rule
->cmd
== cmd
) {
1213 route_map_rule_delete(&index
->match_list
, rule
);
1218 /* Add new route map match rule. */
1219 rule
= route_map_rule_new();
1221 rule
->value
= compile
;
1223 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, match_arg
);
1225 rule
->rule_str
= NULL
;
1227 /* Add new route match rule to linked list. */
1228 route_map_rule_add(&index
->match_list
, rule
);
1230 /* Execute event hook. */
1231 if (route_map_master
.event_hook
) {
1232 (*route_map_master
.event_hook
)(
1233 replaced
? RMAP_EVENT_MATCH_REPLACED
1234 : RMAP_EVENT_MATCH_ADDED
,
1236 route_map_notify_dependencies(index
->map
->name
,
1237 RMAP_EVENT_CALL_ADDED
);
1240 return RMAP_COMPILE_SUCCESS
;
1243 /* Delete specified route match rule. */
1244 int route_map_delete_match(struct route_map_index
*index
,
1245 const char *match_name
, const char *match_arg
)
1247 struct route_map_rule
*rule
;
1248 struct route_map_rule_cmd
*cmd
;
1250 cmd
= route_map_lookup_match(match_name
);
1254 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1255 if (rule
->cmd
== cmd
&& (rulecmp(rule
->rule_str
, match_arg
) == 0
1256 || match_arg
== NULL
)) {
1257 route_map_rule_delete(&index
->match_list
, rule
);
1258 /* Execute event hook. */
1259 if (route_map_master
.event_hook
) {
1260 (*route_map_master
.event_hook
)(
1261 RMAP_EVENT_MATCH_DELETED
,
1263 route_map_notify_dependencies(
1265 RMAP_EVENT_CALL_ADDED
);
1269 /* Can't find matched rule. */
1273 /* Add route-map set statement to the route map. */
1274 int route_map_add_set(struct route_map_index
*index
, const char *set_name
,
1275 const char *set_arg
)
1277 struct route_map_rule
*rule
;
1278 struct route_map_rule
*next
;
1279 struct route_map_rule_cmd
*cmd
;
1283 cmd
= route_map_lookup_set(set_name
);
1285 return RMAP_RULE_MISSING
;
1287 /* Next call compile function for this match statement. */
1288 if (cmd
->func_compile
) {
1289 compile
= (*cmd
->func_compile
)(set_arg
);
1290 if (compile
== NULL
)
1291 return RMAP_COMPILE_ERROR
;
1295 /* Add by WJL. if old set command of same kind exist, delete it first
1296 to ensure only one set command of same kind exist under a
1298 for (rule
= index
->set_list
.head
; rule
; rule
= next
) {
1300 if (rule
->cmd
== cmd
) {
1301 route_map_rule_delete(&index
->set_list
, rule
);
1306 /* Add new route map match rule. */
1307 rule
= route_map_rule_new();
1309 rule
->value
= compile
;
1311 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, set_arg
);
1313 rule
->rule_str
= NULL
;
1315 /* Add new route match rule to linked list. */
1316 route_map_rule_add(&index
->set_list
, rule
);
1318 /* Execute event hook. */
1319 if (route_map_master
.event_hook
) {
1320 (*route_map_master
.event_hook
)(replaced
1321 ? RMAP_EVENT_SET_REPLACED
1322 : RMAP_EVENT_SET_ADDED
,
1324 route_map_notify_dependencies(index
->map
->name
,
1325 RMAP_EVENT_CALL_ADDED
);
1327 return RMAP_COMPILE_SUCCESS
;
1330 /* Delete route map set rule. */
1331 int route_map_delete_set(struct route_map_index
*index
, const char *set_name
,
1332 const char *set_arg
)
1334 struct route_map_rule
*rule
;
1335 struct route_map_rule_cmd
*cmd
;
1337 cmd
= route_map_lookup_set(set_name
);
1341 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
1342 if ((rule
->cmd
== cmd
) && (rulecmp(rule
->rule_str
, set_arg
) == 0
1343 || set_arg
== NULL
)) {
1344 route_map_rule_delete(&index
->set_list
, rule
);
1345 /* Execute event hook. */
1346 if (route_map_master
.event_hook
) {
1347 (*route_map_master
.event_hook
)(
1348 RMAP_EVENT_SET_DELETED
,
1350 route_map_notify_dependencies(
1352 RMAP_EVENT_CALL_ADDED
);
1356 /* Can't find matched rule. */
1360 /* Apply route map's each index to the object.
1362 The matrix for a route-map looks like this:
1363 (note, this includes the description for the "NEXT"
1364 and "GOTO" frobs now
1368 permit action | cont
1370 ------------------+---------------
1376 -Apply Set statements, accept route
1377 -If Call statement is present jump to the specified route-map, if it
1378 denies the route we finish.
1379 -If NEXT is specified, goto NEXT statement
1380 -If GOTO is specified, goto the first clause where pref > nextpref
1381 -If nothing is specified, do as Cisco and finish
1383 -Route is denied by route-map.
1387 If we get no matches after we've processed all updates, then the route
1390 Some notes on the new "CALL", "NEXT" and "GOTO"
1391 call WORD - If this clause is matched, then the set statements
1392 are executed and then we jump to route-map 'WORD'. If
1393 this route-map denies the route, we finish, in other
1395 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
1396 on-match next - If this clause is matched, then the set statements
1397 are executed and then we drop through to the next clause
1398 on-match goto n - If this clause is matched, then the set statments
1399 are executed and then we goto the nth clause, or the
1400 first clause greater than this. In order to ensure
1401 route-maps *always* exit, you cannot jump backwards.
1404 We need to make sure our route-map processing matches the above
1407 static route_map_result_t
1408 route_map_apply_match(struct route_map_rule_list
*match_list
,
1409 const struct prefix
*prefix
, route_map_object_t type
,
1412 route_map_result_t ret
= RMAP_NOMATCH
;
1413 struct route_map_rule
*match
;
1416 /* Check all match rule and if there is no match rule, go to the
1418 if (!match_list
->head
)
1421 for (match
= match_list
->head
; match
; match
= match
->next
) {
1422 /* Try each match statement in turn, If any do not
1424 RMAP_MATCH, return, otherwise continue on to next
1426 statement. All match statements must match for
1429 ret
= (*match
->cmd
->func_apply
)(match
->value
, prefix
,
1431 if (ret
!= RMAP_MATCH
)
1438 /* Apply route map to the object. */
1439 route_map_result_t
route_map_apply(struct route_map
*map
,
1440 const struct prefix
*prefix
,
1441 route_map_object_t type
, void *object
)
1443 static int recursion
= 0;
1445 struct route_map_index
*index
;
1446 struct route_map_rule
*set
;
1448 if (recursion
> RMAP_RECURSION_LIMIT
) {
1450 EC_LIB_RMAP_RECURSION_LIMIT
,
1451 "route-map recursion limit (%d) reached, discarding route",
1452 RMAP_RECURSION_LIMIT
);
1454 return RMAP_DENYMATCH
;
1458 return RMAP_DENYMATCH
;
1460 for (index
= map
->head
; index
; index
= index
->next
) {
1461 /* Apply this index. */
1462 ret
= route_map_apply_match(&index
->match_list
, prefix
, type
,
1465 /* Now we apply the matrix from above */
1466 if (ret
== RMAP_NOMATCH
)
1467 /* 'cont' from matrix - continue to next route-map
1470 else if (ret
== RMAP_MATCH
) {
1471 if (index
->type
== RMAP_PERMIT
)
1474 /* permit+match must execute sets */
1475 for (set
= index
->set_list
.head
; set
;
1477 ret
= (*set
->cmd
->func_apply
)(
1478 set
->value
, prefix
, type
,
1481 /* Call another route-map if available */
1482 if (index
->nextrm
) {
1483 struct route_map
*nextrm
=
1484 route_map_lookup_by_name(
1487 if (nextrm
) /* Target route-map found,
1491 ret
= route_map_apply(
1492 nextrm
, prefix
, type
,
1497 /* If nextrm returned 'deny', finish. */
1498 if (ret
== RMAP_DENYMATCH
)
1502 switch (index
->exitpolicy
) {
1508 /* Find the next clause to jump to */
1509 struct route_map_index
*next
=
1511 int nextpref
= index
->nextpref
;
1513 while (next
&& next
->pref
< nextpref
) {
1518 /* No clauses match! */
1523 } else if (index
->type
== RMAP_DENY
)
1526 return RMAP_DENYMATCH
;
1530 /* Finally route-map does not match at all. */
1531 return RMAP_DENYMATCH
;
1534 void route_map_add_hook(void (*func
)(const char *))
1536 route_map_master
.add_hook
= func
;
1539 void route_map_delete_hook(void (*func
)(const char *))
1541 route_map_master
.delete_hook
= func
;
1544 void route_map_event_hook(void (*func
)(route_map_event_t
, const char *))
1546 route_map_master
.event_hook
= func
;
1549 /* Routines for route map dependency lists and dependency processing */
1550 static int route_map_rmap_hash_cmp(const void *p1
, const void *p2
)
1552 return (strcmp((const char *)p1
, (const char *)p2
) == 0);
1555 static int route_map_dep_hash_cmp(const void *p1
, const void *p2
)
1558 return (strcmp(((const struct route_map_dep
*)p1
)->dep_name
,
1563 static void route_map_clear_reference(struct hash_backet
*backet
, void *arg
)
1565 struct route_map_dep
*dep
= (struct route_map_dep
*)backet
->data
;
1570 (char *)hash_release(dep
->dep_rmap_hash
, (void *)arg
);
1572 XFREE(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
1574 if (!dep
->dep_rmap_hash
->count
) {
1575 dep
= hash_release(dep
->this_hash
,
1576 (void *)dep
->dep_name
);
1577 hash_free(dep
->dep_rmap_hash
);
1578 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
1579 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
1584 static void route_map_clear_all_references(char *rmap_name
)
1588 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
1589 hash_iterate(route_map_dep_hash
[i
], route_map_clear_reference
,
1594 static void *route_map_dep_hash_alloc(void *p
)
1596 char *dep_name
= (char *)p
;
1597 struct route_map_dep
*dep_entry
;
1599 dep_entry
= XCALLOC(MTYPE_ROUTE_MAP_DEP
, sizeof(struct route_map_dep
));
1600 dep_entry
->dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1601 dep_entry
->dep_rmap_hash
=
1602 hash_create_size(8, route_map_dep_hash_make_key
,
1603 route_map_rmap_hash_cmp
, "Route Map Dep Hash");
1604 dep_entry
->this_hash
= NULL
;
1606 return ((void *)dep_entry
);
1609 static void *route_map_name_hash_alloc(void *p
)
1611 return ((void *)XSTRDUP(MTYPE_ROUTE_MAP_NAME
, (const char *)p
));
1614 static unsigned int route_map_dep_hash_make_key(void *p
)
1616 return (string_hash_make((char *)p
));
1619 static void route_map_print_dependency(struct hash_backet
*backet
, void *data
)
1621 char *rmap_name
= (char *)backet
->data
;
1622 char *dep_name
= (char *)data
;
1624 zlog_debug("%s: Dependency for %s: %s", __FUNCTION__
, dep_name
,
1628 static int route_map_dep_update(struct hash
*dephash
, const char *dep_name
,
1629 const char *rmap_name
, route_map_event_t type
)
1631 struct route_map_dep
*dep
= NULL
;
1633 char *dname
, *rname
;
1636 dname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1637 rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
1640 case RMAP_EVENT_PLIST_ADDED
:
1641 case RMAP_EVENT_CLIST_ADDED
:
1642 case RMAP_EVENT_ECLIST_ADDED
:
1643 case RMAP_EVENT_ASLIST_ADDED
:
1644 case RMAP_EVENT_LLIST_ADDED
:
1645 case RMAP_EVENT_CALL_ADDED
:
1646 case RMAP_EVENT_FILTER_ADDED
:
1648 zlog_debug("%s: Adding dependency for %s in %s",
1649 __FUNCTION__
, dep_name
, rmap_name
);
1650 dep
= (struct route_map_dep
*)hash_get(
1651 dephash
, dname
, route_map_dep_hash_alloc
);
1657 if (!dep
->this_hash
)
1658 dep
->this_hash
= dephash
;
1660 hash_get(dep
->dep_rmap_hash
, rname
, route_map_name_hash_alloc
);
1662 case RMAP_EVENT_PLIST_DELETED
:
1663 case RMAP_EVENT_CLIST_DELETED
:
1664 case RMAP_EVENT_ECLIST_DELETED
:
1665 case RMAP_EVENT_ASLIST_DELETED
:
1666 case RMAP_EVENT_LLIST_DELETED
:
1667 case RMAP_EVENT_CALL_DELETED
:
1668 case RMAP_EVENT_FILTER_DELETED
:
1670 zlog_debug("%s: Deleting dependency for %s in %s",
1671 __FUNCTION__
, dep_name
, rmap_name
);
1672 dep
= (struct route_map_dep
*)hash_get(dephash
, dname
, NULL
);
1677 ret_map_name
= (char *)hash_release(dep
->dep_rmap_hash
, rname
);
1679 XFREE(MTYPE_ROUTE_MAP_NAME
, ret_map_name
);
1681 if (!dep
->dep_rmap_hash
->count
) {
1682 dep
= hash_release(dephash
, dname
);
1683 hash_free(dep
->dep_rmap_hash
);
1684 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
1685 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
1695 hash_iterate(dep
->dep_rmap_hash
,
1696 route_map_print_dependency
, dname
);
1700 XFREE(MTYPE_ROUTE_MAP_NAME
, rname
);
1701 XFREE(MTYPE_ROUTE_MAP_NAME
, dname
);
1705 static struct hash
*route_map_get_dep_hash(route_map_event_t event
)
1707 struct hash
*upd8_hash
= NULL
;
1710 case RMAP_EVENT_PLIST_ADDED
:
1711 case RMAP_EVENT_PLIST_DELETED
:
1712 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_PLIST
];
1714 case RMAP_EVENT_CLIST_ADDED
:
1715 case RMAP_EVENT_CLIST_DELETED
:
1716 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_CLIST
];
1718 case RMAP_EVENT_ECLIST_ADDED
:
1719 case RMAP_EVENT_ECLIST_DELETED
:
1720 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ECLIST
];
1722 case RMAP_EVENT_ASLIST_ADDED
:
1723 case RMAP_EVENT_ASLIST_DELETED
:
1724 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ASPATH
];
1726 case RMAP_EVENT_LLIST_ADDED
:
1727 case RMAP_EVENT_LLIST_DELETED
:
1728 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_LCLIST
];
1730 case RMAP_EVENT_CALL_ADDED
:
1731 case RMAP_EVENT_CALL_DELETED
:
1732 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_RMAP
];
1734 case RMAP_EVENT_FILTER_ADDED
:
1735 case RMAP_EVENT_FILTER_DELETED
:
1736 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_FILTER
];
1745 static void route_map_process_dependency(struct hash_backet
*backet
, void *data
)
1747 char *rmap_name
= (char *)backet
->data
;
1748 route_map_event_t type
= (route_map_event_t
)(ptrdiff_t)data
;
1751 zlog_debug("%s: Notifying %s of dependency",
1752 __FUNCTION__
, rmap_name
);
1753 if (route_map_master
.event_hook
)
1754 (*route_map_master
.event_hook
)(type
, rmap_name
);
1757 void route_map_upd8_dependency(route_map_event_t type
, const char *arg
,
1758 const char *rmap_name
)
1760 struct hash
*upd8_hash
= NULL
;
1762 if ((upd8_hash
= route_map_get_dep_hash(type
)))
1763 route_map_dep_update(upd8_hash
, arg
, rmap_name
, type
);
1766 void route_map_notify_dependencies(const char *affected_name
,
1767 route_map_event_t event
)
1769 struct route_map_dep
*dep
;
1770 struct hash
*upd8_hash
;
1776 name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, affected_name
);
1778 if ((upd8_hash
= route_map_get_dep_hash(event
)) == NULL
) {
1779 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
1783 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, name
, NULL
);
1785 if (!dep
->this_hash
)
1786 dep
->this_hash
= upd8_hash
;
1788 hash_iterate(dep
->dep_rmap_hash
, route_map_process_dependency
,
1792 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
1796 /* VTY related functions. */
1797 DEFUN (match_interface
,
1798 match_interface_cmd
,
1799 "match interface WORD",
1801 "match first hop interface of route\n"
1805 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1807 if (rmap_match_set_hook
.match_interface
)
1808 return rmap_match_set_hook
.match_interface(
1809 vty
, index
, "interface", argv
[idx_word
]->arg
,
1810 RMAP_EVENT_MATCH_ADDED
);
1814 DEFUN (no_match_interface
,
1815 no_match_interface_cmd
,
1816 "no match interface [WORD]",
1819 "Match first hop interface of route\n"
1822 char *iface
= (argc
== 4) ? argv
[3]->arg
: NULL
;
1823 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1825 if (rmap_match_set_hook
.no_match_interface
)
1826 return rmap_match_set_hook
.no_match_interface(
1827 vty
, index
, "interface", iface
,
1828 RMAP_EVENT_MATCH_DELETED
);
1833 DEFUN (match_ip_address
,
1834 match_ip_address_cmd
,
1835 "match ip address <(1-199)|(1300-2699)|WORD>",
1838 "Match address of route\n"
1839 "IP access-list number\n"
1840 "IP access-list number (expanded range)\n"
1841 "IP Access-list name\n")
1844 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1846 if (rmap_match_set_hook
.match_ip_address
)
1847 return rmap_match_set_hook
.match_ip_address(
1848 vty
, index
, "ip address", argv
[idx_acl
]->arg
,
1849 RMAP_EVENT_FILTER_ADDED
);
1854 DEFUN (no_match_ip_address
,
1855 no_match_ip_address_cmd
,
1856 "no match ip address [<(1-199)|(1300-2699)|WORD>]",
1860 "Match address of route\n"
1861 "IP access-list number\n"
1862 "IP access-list number (expanded range)\n"
1863 "IP Access-list name\n")
1866 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1868 if (rmap_match_set_hook
.no_match_ip_address
) {
1869 if (argc
<= idx_word
)
1870 return rmap_match_set_hook
.no_match_ip_address(
1871 vty
, index
, "ip address", NULL
,
1872 RMAP_EVENT_FILTER_DELETED
);
1873 return rmap_match_set_hook
.no_match_ip_address(
1874 vty
, index
, "ip address", argv
[idx_word
]->arg
,
1875 RMAP_EVENT_FILTER_DELETED
);
1881 DEFUN (match_ip_address_prefix_list
,
1882 match_ip_address_prefix_list_cmd
,
1883 "match ip address prefix-list WORD",
1886 "Match address of route\n"
1887 "Match entries of prefix-lists\n"
1888 "IP prefix-list name\n")
1891 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1893 if (rmap_match_set_hook
.match_ip_address_prefix_list
)
1894 return rmap_match_set_hook
.match_ip_address_prefix_list(
1895 vty
, index
, "ip address prefix-list",
1896 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
1901 DEFUN (no_match_ip_address_prefix_list
,
1902 no_match_ip_address_prefix_list_cmd
,
1903 "no match ip address prefix-list [WORD]",
1907 "Match address of route\n"
1908 "Match entries of prefix-lists\n"
1909 "IP prefix-list name\n")
1912 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1914 if (rmap_match_set_hook
.no_match_ip_address_prefix_list
) {
1915 if (argc
<= idx_word
)
1916 return rmap_match_set_hook
1917 .no_match_ip_address_prefix_list(
1918 vty
, index
, "ip address prefix-list",
1919 NULL
, RMAP_EVENT_PLIST_DELETED
);
1920 return rmap_match_set_hook
.no_match_ip_address_prefix_list(
1921 vty
, index
, "ip address prefix-list",
1922 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
1928 DEFUN (match_ip_next_hop
,
1929 match_ip_next_hop_cmd
,
1930 "match ip next-hop <(1-199)|(1300-2699)|WORD>",
1933 "Match next-hop address of route\n"
1934 "IP access-list number\n"
1935 "IP access-list number (expanded range)\n"
1936 "IP Access-list name\n")
1939 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1941 if (rmap_match_set_hook
.match_ip_next_hop
)
1942 return rmap_match_set_hook
.match_ip_next_hop(
1943 vty
, index
, "ip next-hop", argv
[idx_acl
]->arg
,
1944 RMAP_EVENT_FILTER_ADDED
);
1949 DEFUN (no_match_ip_next_hop
,
1950 no_match_ip_next_hop_cmd
,
1951 "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
1955 "Match next-hop address of route\n"
1956 "IP access-list number\n"
1957 "IP access-list number (expanded range)\n"
1958 "IP Access-list name\n")
1961 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1963 if (rmap_match_set_hook
.no_match_ip_next_hop
) {
1964 if (argc
<= idx_word
)
1965 return rmap_match_set_hook
.no_match_ip_next_hop(
1966 vty
, index
, "ip next-hop", NULL
,
1967 RMAP_EVENT_FILTER_DELETED
);
1968 return rmap_match_set_hook
.no_match_ip_next_hop(
1969 vty
, index
, "ip next-hop", argv
[idx_word
]->arg
,
1970 RMAP_EVENT_FILTER_DELETED
);
1976 DEFUN (match_ip_next_hop_prefix_list
,
1977 match_ip_next_hop_prefix_list_cmd
,
1978 "match ip next-hop prefix-list WORD",
1981 "Match next-hop address of route\n"
1982 "Match entries of prefix-lists\n"
1983 "IP prefix-list name\n")
1986 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1988 if (rmap_match_set_hook
.match_ip_next_hop_prefix_list
)
1989 return rmap_match_set_hook
.match_ip_next_hop_prefix_list(
1990 vty
, index
, "ip next-hop prefix-list",
1991 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
1995 DEFUN (no_match_ip_next_hop_prefix_list
,
1996 no_match_ip_next_hop_prefix_list_cmd
,
1997 "no match ip next-hop prefix-list [WORD]",
2001 "Match next-hop address of route\n"
2002 "Match entries of prefix-lists\n"
2003 "IP prefix-list name\n")
2006 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2008 if (rmap_match_set_hook
.no_match_ip_next_hop
) {
2009 if (argc
<= idx_word
)
2010 return rmap_match_set_hook
.no_match_ip_next_hop(
2011 vty
, index
, "ip next-hop prefix-list", NULL
,
2012 RMAP_EVENT_PLIST_DELETED
);
2013 return rmap_match_set_hook
.no_match_ip_next_hop(
2014 vty
, index
, "ip next-hop prefix-list",
2015 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2021 DEFUN (match_ipv6_address
,
2022 match_ipv6_address_cmd
,
2023 "match ipv6 address WORD",
2026 "Match IPv6 address of route\n"
2027 "IPv6 access-list name\n")
2030 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2032 if (rmap_match_set_hook
.match_ipv6_address
)
2033 return rmap_match_set_hook
.match_ipv6_address(
2034 vty
, index
, "ipv6 address", argv
[idx_word
]->arg
,
2035 RMAP_EVENT_FILTER_ADDED
);
2039 DEFUN (no_match_ipv6_address
,
2040 no_match_ipv6_address_cmd
,
2041 "no match ipv6 address WORD",
2045 "Match IPv6 address of route\n"
2046 "IPv6 access-list name\n")
2049 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2051 if (rmap_match_set_hook
.no_match_ipv6_address
)
2052 return rmap_match_set_hook
.no_match_ipv6_address(
2053 vty
, index
, "ipv6 address", argv
[idx_word
]->arg
,
2054 RMAP_EVENT_FILTER_DELETED
);
2059 DEFUN (match_ipv6_address_prefix_list
,
2060 match_ipv6_address_prefix_list_cmd
,
2061 "match ipv6 address prefix-list WORD",
2064 "Match address of route\n"
2065 "Match entries of prefix-lists\n"
2066 "IP prefix-list name\n")
2069 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2071 if (rmap_match_set_hook
.match_ipv6_address_prefix_list
)
2072 return rmap_match_set_hook
.match_ipv6_address_prefix_list(
2073 vty
, index
, "ipv6 address prefix-list",
2074 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
2078 DEFUN (no_match_ipv6_address_prefix_list
,
2079 no_match_ipv6_address_prefix_list_cmd
,
2080 "no match ipv6 address prefix-list WORD",
2084 "Match address of route\n"
2085 "Match entries of prefix-lists\n"
2086 "IP prefix-list name\n")
2089 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2091 if (rmap_match_set_hook
.no_match_ipv6_address_prefix_list
)
2092 return rmap_match_set_hook
.no_match_ipv6_address_prefix_list(
2093 vty
, index
, "ipv6 address prefix-list",
2094 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2099 DEFUN (match_metric
,
2101 "match metric (0-4294967295)",
2103 "Match metric of route\n"
2107 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2109 if (rmap_match_set_hook
.match_metric
)
2110 return rmap_match_set_hook
.match_metric(vty
, index
, "metric",
2111 argv
[idx_number
]->arg
,
2112 RMAP_EVENT_MATCH_ADDED
);
2117 DEFUN (no_match_metric
,
2118 no_match_metric_cmd
,
2119 "no match metric [(0-4294967295)]",
2122 "Match metric of route\n"
2126 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2128 if (rmap_match_set_hook
.no_match_metric
) {
2129 if (argc
<= idx_number
)
2130 return rmap_match_set_hook
.no_match_metric(
2131 vty
, index
, "metric", NULL
,
2132 RMAP_EVENT_MATCH_DELETED
);
2133 return rmap_match_set_hook
.no_match_metric(
2134 vty
, index
, "metric", argv
[idx_number
]->arg
,
2135 RMAP_EVENT_MATCH_DELETED
);
2143 "match tag (1-4294967295)",
2145 "Match tag of route\n"
2149 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2151 if (rmap_match_set_hook
.match_tag
)
2152 return rmap_match_set_hook
.match_tag(vty
, index
, "tag",
2153 argv
[idx_number
]->arg
,
2154 RMAP_EVENT_MATCH_ADDED
);
2159 DEFUN (no_match_tag
,
2161 "no match tag [(1-4294967295)]",
2164 "Match tag of route\n"
2167 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2170 char *arg
= argv_find(argv
, argc
, "(1-4294967295)", &idx
)
2174 if (rmap_match_set_hook
.no_match_tag
)
2175 return rmap_match_set_hook
.no_match_tag(
2176 vty
, index
, "tag", arg
, RMAP_EVENT_MATCH_DELETED
);
2181 DEFUN (set_ip_nexthop
,
2183 "set ip next-hop A.B.C.D",
2186 "Next hop address\n"
2187 "IP address of next hop\n")
2192 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2194 ret
= str2sockunion(argv
[idx_ipv4
]->arg
, &su
);
2196 vty_out(vty
, "%% Malformed nexthop address\n");
2197 return CMD_WARNING_CONFIG_FAILED
;
2199 if (su
.sin
.sin_addr
.s_addr
== 0
2200 || IPV4_CLASS_DE(ntohl(su
.sin
.sin_addr
.s_addr
))) {
2202 "%% nexthop address cannot be 0.0.0.0, multicast or reserved\n");
2203 return CMD_WARNING_CONFIG_FAILED
;
2206 if (rmap_match_set_hook
.set_ip_nexthop
)
2207 return rmap_match_set_hook
.set_ip_nexthop(
2208 vty
, index
, "ip next-hop", argv
[idx_ipv4
]->arg
);
2213 DEFUN (no_set_ip_nexthop
,
2214 no_set_ip_nexthop_cmd
,
2215 "no set ip next-hop [A.B.C.D]",
2219 "Next hop address\n"
2220 "IP address of next hop\n")
2223 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2224 const char *arg
= NULL
;
2226 if (argv_find(argv
, argc
, "A.B.C.D", &idx
))
2227 arg
= argv
[idx
]->arg
;
2229 if (rmap_match_set_hook
.no_set_ip_nexthop
)
2230 return rmap_match_set_hook
.no_set_ip_nexthop(
2231 vty
, index
, "ip next-hop", arg
);
2237 DEFUN (set_ipv6_nexthop_local
,
2238 set_ipv6_nexthop_local_cmd
,
2239 "set ipv6 next-hop local X:X::X:X",
2242 "IPv6 next-hop address\n"
2243 "IPv6 local address\n"
2244 "IPv6 address of next hop\n")
2247 struct in6_addr addr
;
2249 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2251 ret
= inet_pton(AF_INET6
, argv
[idx_ipv6
]->arg
, &addr
);
2253 vty_out(vty
, "%% Malformed nexthop address\n");
2254 return CMD_WARNING_CONFIG_FAILED
;
2256 if (!IN6_IS_ADDR_LINKLOCAL(&addr
)) {
2257 vty_out(vty
, "%% Invalid link-local nexthop address\n");
2258 return CMD_WARNING_CONFIG_FAILED
;
2261 if (rmap_match_set_hook
.set_ipv6_nexthop_local
)
2262 return rmap_match_set_hook
.set_ipv6_nexthop_local(
2263 vty
, index
, "ipv6 next-hop local", argv
[idx_ipv6
]->arg
);
2268 DEFUN (no_set_ipv6_nexthop_local
,
2269 no_set_ipv6_nexthop_local_cmd
,
2270 "no set ipv6 next-hop local [X:X::X:X]",
2274 "IPv6 next-hop address\n"
2275 "IPv6 local address\n"
2276 "IPv6 address of next hop\n")
2279 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2281 if (rmap_match_set_hook
.no_set_ipv6_nexthop_local
) {
2282 if (argc
<= idx_ipv6
)
2283 return rmap_match_set_hook
.no_set_ipv6_nexthop_local(
2284 vty
, index
, "ipv6 next-hop local", NULL
);
2285 return rmap_match_set_hook
.no_set_ipv6_nexthop_local(
2286 vty
, index
, "ipv6 next-hop local", argv
[5]->arg
);
2293 "set metric <(0-4294967295)|rtt|+rtt|-rtt|+metric|-metric>",
2295 "Metric value for destination routing protocol\n"
2297 "Assign round trip time\n"
2298 "Add round trip time\n"
2299 "Subtract round trip time\n"
2301 "Subtract metric\n")
2304 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2306 const char *pass
= (argv
[idx_number
]->type
== RANGE_TKN
)
2307 ? argv
[idx_number
]->arg
2308 : argv
[idx_number
]->text
;
2310 if (rmap_match_set_hook
.set_metric
)
2311 return rmap_match_set_hook
.set_metric(vty
, index
, "metric",
2317 DEFUN (no_set_metric
,
2319 "no set metric [(0-4294967295)]",
2322 "Metric value for destination routing protocol\n"
2326 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2328 if (rmap_match_set_hook
.no_set_metric
) {
2329 if (argc
<= idx_number
)
2330 return rmap_match_set_hook
.no_set_metric(
2331 vty
, index
, "metric", NULL
);
2332 return rmap_match_set_hook
.no_set_metric(vty
, index
, "metric",
2333 argv
[idx_number
]->arg
);
2341 "set tag (1-4294967295)",
2343 "Tag value for routing protocol\n"
2346 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2349 if (rmap_match_set_hook
.set_tag
)
2350 return rmap_match_set_hook
.set_tag(vty
, index
, "tag",
2351 argv
[idx_number
]->arg
);
2358 "no set tag [(1-4294967295)]",
2361 "Tag value for routing protocol\n"
2364 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2367 if (rmap_match_set_hook
.no_set_tag
) {
2368 if (argc
<= idx_number
)
2369 return rmap_match_set_hook
.no_set_tag(vty
, index
, "tag",
2371 return rmap_match_set_hook
.no_set_tag(vty
, index
, "tag",
2372 argv
[idx_number
]->arg
);
2378 DEFUN_NOSH (route_map
,
2380 "route-map WORD <deny|permit> (1-65535)",
2381 "Create route-map or enter route-map command mode\n"
2383 "Route map denies set operations\n"
2384 "Route map permits set operations\n"
2385 "Sequence to insert to/delete from existing route-map entry\n")
2388 int idx_permit_deny
= 2;
2390 struct route_map
*map
;
2391 struct route_map_index
*index
;
2392 char *endptr
= NULL
;
2394 argv
[idx_permit_deny
]->arg
[0] == 'p' ? RMAP_PERMIT
: RMAP_DENY
;
2395 unsigned long pref
= strtoul(argv
[idx_number
]->arg
, &endptr
, 10);
2396 const char *mapname
= argv
[idx_word
]->arg
;
2398 /* Get route map. */
2399 map
= route_map_get(mapname
);
2400 index
= route_map_index_get(map
, permit
, pref
);
2402 VTY_PUSH_CONTEXT(RMAP_NODE
, index
);
2406 DEFUN (no_route_map_all
,
2407 no_route_map_all_cmd
,
2408 "no route-map WORD",
2410 "Create route-map or enter route-map command mode\n"
2414 const char *mapname
= argv
[idx_word
]->arg
;
2415 struct route_map
*map
;
2417 map
= route_map_lookup_by_name(mapname
);
2419 vty_out(vty
, "%% Could not find route-map %s\n", mapname
);
2420 return CMD_WARNING_CONFIG_FAILED
;
2423 route_map_delete(map
);
2428 DEFUN (no_route_map
,
2430 "no route-map WORD <deny|permit> (1-65535)",
2432 "Create route-map or enter route-map command mode\n"
2434 "Route map denies set operations\n"
2435 "Route map permits set operations\n"
2436 "Sequence to insert to/delete from existing route-map entry\n")
2439 int idx_permit_deny
= 3;
2441 struct route_map
*map
;
2442 struct route_map_index
*index
;
2443 char *endptr
= NULL
;
2444 int permit
= strmatch(argv
[idx_permit_deny
]->text
, "permit")
2447 const char *prefstr
= argv
[idx_number
]->arg
;
2448 const char *mapname
= argv
[idx_word
]->arg
;
2449 unsigned long pref
= strtoul(prefstr
, &endptr
, 10);
2451 /* Existence check. */
2452 map
= route_map_lookup_by_name(mapname
);
2454 vty_out(vty
, "%% Could not find route-map %s\n", mapname
);
2455 return CMD_WARNING_CONFIG_FAILED
;
2458 /* Lookup route map index. */
2459 index
= route_map_index_lookup(map
, permit
, pref
);
2460 if (index
== NULL
) {
2461 vty_out(vty
, "%% Could not find route-map entry %s %s\n",
2463 return CMD_WARNING_CONFIG_FAILED
;
2466 /* Delete index from route map. */
2467 route_map_index_delete(index
, 1);
2469 /* If this route rule is the last one, delete route map itself. */
2470 if (route_map_empty(map
))
2471 route_map_delete(map
);
2476 DEFUN (rmap_onmatch_next
,
2477 rmap_onmatch_next_cmd
,
2479 "Exit policy on matches\n"
2482 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2485 if (index
->type
== RMAP_DENY
) {
2486 /* Under a deny clause, match means it's finished. No
2487 * need to set next */
2489 "on-match next not supported under route-map deny\n");
2490 return CMD_WARNING_CONFIG_FAILED
;
2492 index
->exitpolicy
= RMAP_NEXT
;
2497 DEFUN (no_rmap_onmatch_next
,
2498 no_rmap_onmatch_next_cmd
,
2501 "Exit policy on matches\n"
2504 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2507 index
->exitpolicy
= RMAP_EXIT
;
2512 DEFUN (rmap_onmatch_goto
,
2513 rmap_onmatch_goto_cmd
,
2514 "on-match goto (1-65535)",
2515 "Exit policy on matches\n"
2516 "Goto Clause number\n"
2520 char *num
= argv_find(argv
, argc
, "(1-65535)", &idx
) ? argv
[idx
]->arg
2523 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2527 if (index
->type
== RMAP_DENY
) {
2528 /* Under a deny clause, match means it's finished. No
2529 * need to go anywhere */
2531 "on-match goto not supported under route-map deny\n");
2532 return CMD_WARNING_CONFIG_FAILED
;
2536 d
= strtoul(num
, NULL
, 10);
2538 d
= index
->pref
+ 1;
2540 if (d
<= index
->pref
) {
2541 /* Can't allow you to do that, Dave */
2542 vty_out(vty
, "can't jump backwards in route-maps\n");
2543 return CMD_WARNING_CONFIG_FAILED
;
2545 index
->exitpolicy
= RMAP_GOTO
;
2546 index
->nextpref
= d
;
2552 DEFUN (no_rmap_onmatch_goto
,
2553 no_rmap_onmatch_goto_cmd
,
2556 "Exit policy on matches\n"
2557 "Goto Clause number\n")
2559 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2562 index
->exitpolicy
= RMAP_EXIT
;
2567 /* Cisco/GNU Zebra compatibility aliases */
2569 DEFUN (rmap_continue
,
2571 "continue (1-65535)",
2572 "Continue on a different entry within the route-map\n"
2573 "Route-map entry sequence number\n")
2575 return rmap_onmatch_goto(self
, vty
, argc
, argv
);
2579 DEFUN (no_rmap_continue
,
2580 no_rmap_continue_cmd
,
2581 "no continue [(1-65535)]",
2583 "Continue on a different entry within the route-map\n"
2584 "Route-map entry sequence number\n")
2586 return no_rmap_onmatch_goto(self
, vty
, argc
, argv
);
2590 DEFUN (rmap_show_name
,
2592 "show route-map [WORD]",
2594 "route-map information\n"
2598 const char *name
= (argc
== 3) ? argv
[idx_word
]->arg
: NULL
;
2599 return vty_show_route_map(vty
, name
);
2605 "Jump to another Route-Map after match+set\n"
2606 "Target route-map name\n")
2609 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2610 const char *rmap
= argv
[idx_word
]->arg
;
2614 if (index
->nextrm
) {
2615 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED
,
2616 index
->nextrm
, index
->map
->name
);
2617 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
2619 index
->nextrm
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap
);
2621 /* Execute event hook. */
2622 route_map_upd8_dependency(RMAP_EVENT_CALL_ADDED
, index
->nextrm
,
2627 DEFUN (no_rmap_call
,
2631 "Jump to another Route-Map after match+set\n")
2633 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2635 if (index
->nextrm
) {
2636 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED
,
2637 index
->nextrm
, index
->map
->name
);
2638 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
2639 index
->nextrm
= NULL
;
2645 DEFUN (rmap_description
,
2646 rmap_description_cmd
,
2647 "description LINE...",
2648 "Route-map comment\n"
2649 "Comment describing this route-map rule\n")
2652 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2655 if (index
->description
)
2656 XFREE(MTYPE_TMP
, index
->description
);
2657 index
->description
= argv_concat(argv
, argc
, idx_line
);
2662 DEFUN (no_rmap_description
,
2663 no_rmap_description_cmd
,
2666 "Route-map comment\n")
2668 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2671 if (index
->description
)
2672 XFREE(MTYPE_TMP
, index
->description
);
2673 index
->description
= NULL
;
2678 /* Configuration write function. */
2679 static int route_map_config_write(struct vty
*vty
)
2681 struct route_map
*map
;
2682 struct route_map_index
*index
;
2683 struct route_map_rule
*rule
;
2687 for (map
= route_map_master
.head
; map
; map
= map
->next
)
2688 for (index
= map
->head
; index
; index
= index
->next
) {
2690 vty_out(vty
, "!\n");
2694 vty_out(vty
, "route-map %s %s %d\n", map
->name
,
2695 route_map_type_str(index
->type
), index
->pref
);
2697 if (index
->description
)
2698 vty_out(vty
, " description %s\n",
2699 index
->description
);
2701 for (rule
= index
->match_list
.head
; rule
;
2703 vty_out(vty
, " match %s %s\n", rule
->cmd
->str
,
2704 rule
->rule_str
? rule
->rule_str
: "");
2706 for (rule
= index
->set_list
.head
; rule
;
2708 vty_out(vty
, " set %s %s\n", rule
->cmd
->str
,
2709 rule
->rule_str
? rule
->rule_str
: "");
2711 vty_out(vty
, " call %s\n", index
->nextrm
);
2712 if (index
->exitpolicy
== RMAP_GOTO
)
2713 vty_out(vty
, " on-match goto %d\n",
2715 if (index
->exitpolicy
== RMAP_NEXT
)
2716 vty_out(vty
, " on-match next\n");
2723 /* Route map node structure. */
2724 static struct cmd_node rmap_node
= {RMAP_NODE
, "%s(config-route-map)# ", 1};
2726 /* Common route map rules */
2728 void *route_map_rule_tag_compile(const char *arg
)
2730 unsigned long int tmp
;
2735 tmp
= strtoul(arg
, &endptr
, 0);
2736 if (arg
[0] == '\0' || *endptr
!= '\0' || errno
|| tmp
> ROUTE_TAG_MAX
)
2739 tag
= XMALLOC(MTYPE_ROUTE_MAP_COMPILED
, sizeof(*tag
));
2745 void route_map_rule_tag_free(void *rule
)
2747 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
2750 void route_map_finish(void)
2754 vector_free(route_match_vec
);
2755 route_match_vec
= NULL
;
2756 vector_free(route_set_vec
);
2757 route_set_vec
= NULL
;
2760 * All protocols are setting these to NULL
2761 * by default on shutdown( route_map_finish )
2762 * Why are we making them do this work?
2764 route_map_master
.add_hook
= NULL
;
2765 route_map_master
.delete_hook
= NULL
;
2766 route_map_master
.event_hook
= NULL
;
2768 /* cleanup route_map */
2769 while (route_map_master
.head
) {
2770 struct route_map
*map
= route_map_master
.head
;
2771 map
->to_be_processed
= false;
2772 route_map_delete(map
);
2775 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
2776 hash_free(route_map_dep_hash
[i
]);
2777 route_map_dep_hash
[i
] = NULL
;
2780 hash_free(route_map_master_hash
);
2781 route_map_master_hash
= NULL
;
2784 static void rmap_autocomplete(vector comps
, struct cmd_token
*token
)
2786 struct route_map
*map
;
2788 for (map
= route_map_master
.head
; map
; map
= map
->next
)
2789 vector_set(comps
, XSTRDUP(MTYPE_COMPLETION
, map
->name
));
2792 static const struct cmd_variable_handler rmap_var_handlers
[] = {
2793 {/* "route-map WORD" */
2794 .varname
= "route_map",
2795 .completions
= rmap_autocomplete
},
2796 {.tokenname
= "ROUTEMAP_NAME", .completions
= rmap_autocomplete
},
2797 {.tokenname
= "RMAP_NAME", .completions
= rmap_autocomplete
},
2798 {.completions
= NULL
}};
2800 /* Initialization of route map vector. */
2801 void route_map_init(void)
2805 /* Make vector for match and set. */
2806 route_match_vec
= vector_init(1);
2807 route_set_vec
= vector_init(1);
2808 route_map_master_hash
=
2809 hash_create_size(8, route_map_hash_key_make
, route_map_hash_cmp
,
2810 "Route Map Master Hash");
2812 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++)
2813 route_map_dep_hash
[i
] = hash_create_size(
2814 8, route_map_dep_hash_make_key
, route_map_dep_hash_cmp
,
2815 "Route Map Dep Hash");
2817 cmd_variable_handler_register(rmap_var_handlers
);
2819 /* Install route map top node. */
2820 install_node(&rmap_node
, route_map_config_write
);
2822 /* Install route map commands. */
2823 install_default(RMAP_NODE
);
2824 install_element(CONFIG_NODE
, &route_map_cmd
);
2825 install_element(CONFIG_NODE
, &no_route_map_cmd
);
2826 install_element(CONFIG_NODE
, &no_route_map_all_cmd
);
2828 /* Install the on-match stuff */
2829 install_element(RMAP_NODE
, &route_map_cmd
);
2830 install_element(RMAP_NODE
, &rmap_onmatch_next_cmd
);
2831 install_element(RMAP_NODE
, &no_rmap_onmatch_next_cmd
);
2832 install_element(RMAP_NODE
, &rmap_onmatch_goto_cmd
);
2833 install_element(RMAP_NODE
, &no_rmap_onmatch_goto_cmd
);
2834 install_element(RMAP_NODE
, &rmap_continue_cmd
);
2835 install_element(RMAP_NODE
, &no_rmap_continue_cmd
);
2837 /* Install the continue stuff (ALIAS of on-match). */
2839 /* Install the call stuff. */
2840 install_element(RMAP_NODE
, &rmap_call_cmd
);
2841 install_element(RMAP_NODE
, &no_rmap_call_cmd
);
2843 /* Install description commands. */
2844 install_element(RMAP_NODE
, &rmap_description_cmd
);
2845 install_element(RMAP_NODE
, &no_rmap_description_cmd
);
2847 /* Install show command */
2848 install_element(ENABLE_NODE
, &rmap_show_name_cmd
);
2850 install_element(RMAP_NODE
, &match_interface_cmd
);
2851 install_element(RMAP_NODE
, &no_match_interface_cmd
);
2853 install_element(RMAP_NODE
, &match_ip_address_cmd
);
2854 install_element(RMAP_NODE
, &no_match_ip_address_cmd
);
2856 install_element(RMAP_NODE
, &match_ip_address_prefix_list_cmd
);
2857 install_element(RMAP_NODE
, &no_match_ip_address_prefix_list_cmd
);
2859 install_element(RMAP_NODE
, &match_ip_next_hop_cmd
);
2860 install_element(RMAP_NODE
, &no_match_ip_next_hop_cmd
);
2862 install_element(RMAP_NODE
, &match_ip_next_hop_prefix_list_cmd
);
2863 install_element(RMAP_NODE
, &no_match_ip_next_hop_prefix_list_cmd
);
2865 install_element(RMAP_NODE
, &match_ipv6_address_cmd
);
2866 install_element(RMAP_NODE
, &no_match_ipv6_address_cmd
);
2868 install_element(RMAP_NODE
, &match_ipv6_address_prefix_list_cmd
);
2869 install_element(RMAP_NODE
, &no_match_ipv6_address_prefix_list_cmd
);
2871 install_element(RMAP_NODE
, &match_metric_cmd
);
2872 install_element(RMAP_NODE
, &no_match_metric_cmd
);
2874 install_element(RMAP_NODE
, &match_tag_cmd
);
2875 install_element(RMAP_NODE
, &no_match_tag_cmd
);
2877 install_element(RMAP_NODE
, &set_ip_nexthop_cmd
);
2878 install_element(RMAP_NODE
, &no_set_ip_nexthop_cmd
);
2880 install_element(RMAP_NODE
, &set_ipv6_nexthop_local_cmd
);
2881 install_element(RMAP_NODE
, &no_set_ipv6_nexthop_local_cmd
);
2883 install_element(RMAP_NODE
, &set_metric_cmd
);
2884 install_element(RMAP_NODE
, &no_set_metric_cmd
);
2886 install_element(RMAP_NODE
, &set_tag_cmd
);
2887 install_element(RMAP_NODE
, &no_set_tag_cmd
);