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 ip next hop type */
115 int (*match_ip_next_hop_type
)(struct vty
*vty
,
116 struct route_map_index
*index
,
119 route_map_event_t type
);
121 /* no match ip next hop type */
122 int (*no_match_ip_next_hop_type
)(struct vty
*vty
,
123 struct route_map_index
*index
,
126 route_map_event_t type
);
128 /* match ipv6 address */
129 int (*match_ipv6_address
)(struct vty
*vty
,
130 struct route_map_index
*index
,
131 const char *command
, const char *arg
,
132 route_map_event_t type
);
134 /* no match ipv6 address */
135 int (*no_match_ipv6_address
)(struct vty
*vty
,
136 struct route_map_index
*index
,
137 const char *command
, const char *arg
,
138 route_map_event_t type
);
141 /* match ipv6 address prefix list */
142 int (*match_ipv6_address_prefix_list
)(struct vty
*vty
,
143 struct route_map_index
*index
,
146 route_map_event_t type
);
148 /* no match ipv6 address prefix list */
149 int (*no_match_ipv6_address_prefix_list
)(struct vty
*vty
,
150 struct route_map_index
*index
,
153 route_map_event_t type
);
155 /* match ipv6 next-hop type */
156 int (*match_ipv6_next_hop_type
)(struct vty
*vty
,
157 struct route_map_index
*index
,
160 route_map_event_t type
);
162 /* no match ipv6next-hop type */
163 int (*no_match_ipv6_next_hop_type
)(struct vty
*vty
,
164 struct route_map_index
*index
,
165 const char *command
, const char *arg
,
166 route_map_event_t type
);
169 int (*match_metric
)(struct vty
*vty
, struct route_map_index
*index
,
170 const char *command
, const char *arg
,
171 route_map_event_t type
);
173 /* no match metric */
174 int (*no_match_metric
)(struct vty
*vty
, struct route_map_index
*index
,
175 const char *command
, const char *arg
,
176 route_map_event_t type
);
179 int (*match_tag
)(struct vty
*vty
, struct route_map_index
*index
,
180 const char *command
, const char *arg
,
181 route_map_event_t type
);
184 int (*no_match_tag
)(struct vty
*vty
, struct route_map_index
*index
,
185 const char *command
, const char *arg
,
186 route_map_event_t type
);
189 int (*set_ip_nexthop
)(struct vty
*vty
, struct route_map_index
*index
,
190 const char *command
, const char *arg
);
192 /* no set ip nexthop */
193 int (*no_set_ip_nexthop
)(struct vty
*vty
, struct route_map_index
*index
,
194 const char *command
, const char *arg
);
196 /* set ipv6 nexthop local */
197 int (*set_ipv6_nexthop_local
)(struct vty
*vty
,
198 struct route_map_index
*index
,
199 const char *command
, const char *arg
);
201 /* no set ipv6 nexthop local */
202 int (*no_set_ipv6_nexthop_local
)(struct vty
*vty
,
203 struct route_map_index
*index
,
204 const char *command
, const char *arg
);
207 int (*set_metric
)(struct vty
*vty
, struct route_map_index
*index
,
208 const char *command
, const char *arg
);
211 int (*no_set_metric
)(struct vty
*vty
, struct route_map_index
*index
,
212 const char *command
, const char *arg
);
215 int (*set_tag
)(struct vty
*vty
, struct route_map_index
*index
,
216 const char *command
, const char *arg
);
219 int (*no_set_tag
)(struct vty
*vty
, struct route_map_index
*index
,
220 const char *command
, const char *arg
);
223 struct route_map_match_set_hooks rmap_match_set_hook
;
225 /* match interface */
226 void route_map_match_interface_hook(int (*func
)(
227 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
228 const char *arg
, route_map_event_t type
))
230 rmap_match_set_hook
.match_interface
= func
;
233 /* no match interface */
234 void route_map_no_match_interface_hook(int (*func
)(
235 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
236 const char *arg
, route_map_event_t type
))
238 rmap_match_set_hook
.no_match_interface
= func
;
241 /* match ip address */
242 void route_map_match_ip_address_hook(int (*func
)(
243 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
244 const char *arg
, route_map_event_t type
))
246 rmap_match_set_hook
.match_ip_address
= func
;
249 /* no match ip address */
250 void route_map_no_match_ip_address_hook(int (*func
)(
251 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
252 const char *arg
, route_map_event_t type
))
254 rmap_match_set_hook
.no_match_ip_address
= func
;
257 /* match ip address prefix list */
258 void route_map_match_ip_address_prefix_list_hook(int (*func
)(
259 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
260 const char *arg
, route_map_event_t type
))
262 rmap_match_set_hook
.match_ip_address_prefix_list
= func
;
265 /* no match ip address prefix list */
266 void route_map_no_match_ip_address_prefix_list_hook(int (*func
)(
267 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
268 const char *arg
, route_map_event_t type
))
270 rmap_match_set_hook
.no_match_ip_address_prefix_list
= func
;
273 /* match ip next hop */
274 void route_map_match_ip_next_hop_hook(int (*func
)(
275 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
276 const char *arg
, route_map_event_t type
))
278 rmap_match_set_hook
.match_ip_next_hop
= func
;
281 /* no match ip next hop */
282 void route_map_no_match_ip_next_hop_hook(int (*func
)(
283 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
284 const char *arg
, route_map_event_t type
))
286 rmap_match_set_hook
.no_match_ip_next_hop
= func
;
289 /* match ip next hop prefix list */
290 void route_map_match_ip_next_hop_prefix_list_hook(int (*func
)(
291 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
292 const char *arg
, route_map_event_t type
))
294 rmap_match_set_hook
.match_ip_next_hop_prefix_list
= func
;
297 /* no match ip next hop prefix list */
298 void route_map_no_match_ip_next_hop_prefix_list_hook(int (*func
)(
299 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
300 const char *arg
, route_map_event_t type
))
302 rmap_match_set_hook
.no_match_ip_next_hop_prefix_list
= func
;
305 /* match ip next hop type */
306 void route_map_match_ip_next_hop_type_hook(int (*func
)(
307 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
308 const char *arg
, route_map_event_t type
))
310 rmap_match_set_hook
.match_ip_next_hop_type
= func
;
313 /* no match ip next hop type */
314 void route_map_no_match_ip_next_hop_type_hook(int (*func
)(
315 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
316 const char *arg
, route_map_event_t type
))
318 rmap_match_set_hook
.no_match_ip_next_hop_type
= func
;
321 /* match ipv6 address */
322 void route_map_match_ipv6_address_hook(int (*func
)(
323 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
324 const char *arg
, route_map_event_t type
))
326 rmap_match_set_hook
.match_ipv6_address
= func
;
329 /* no match ipv6 address */
330 void route_map_no_match_ipv6_address_hook(int (*func
)(
331 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
332 const char *arg
, route_map_event_t type
))
334 rmap_match_set_hook
.no_match_ipv6_address
= func
;
338 /* match ipv6 address prefix list */
339 void route_map_match_ipv6_address_prefix_list_hook(int (*func
)(
340 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
341 const char *arg
, route_map_event_t type
))
343 rmap_match_set_hook
.match_ipv6_address_prefix_list
= func
;
346 /* no match ipv6 address prefix list */
347 void route_map_no_match_ipv6_address_prefix_list_hook(int (*func
)(
348 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
349 const char *arg
, route_map_event_t type
))
351 rmap_match_set_hook
.no_match_ipv6_address_prefix_list
= func
;
354 /* match ipv6 next-hop type */
355 void route_map_match_ipv6_next_hop_type_hook(int (*func
)(
356 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
357 const char *arg
, route_map_event_t type
))
359 rmap_match_set_hook
.match_ipv6_next_hop_type
= func
;
362 /* no match ipv6 next-hop type */
363 void route_map_no_match_ipv6_next_hop_type_hook(int (*func
)(
364 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
365 const char *arg
, route_map_event_t type
))
367 rmap_match_set_hook
.no_match_ipv6_next_hop_type
= func
;
371 void route_map_match_metric_hook(int (*func
)(
372 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
373 const char *arg
, route_map_event_t type
))
375 rmap_match_set_hook
.match_metric
= func
;
378 /* no match metric */
379 void route_map_no_match_metric_hook(int (*func
)(
380 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
381 const char *arg
, route_map_event_t type
))
383 rmap_match_set_hook
.no_match_metric
= func
;
387 void route_map_match_tag_hook(int (*func
)(struct vty
*vty
,
388 struct route_map_index
*index
,
389 const char *command
, const char *arg
,
390 route_map_event_t type
))
392 rmap_match_set_hook
.match_tag
= func
;
396 void route_map_no_match_tag_hook(int (*func
)(
397 struct vty
*vty
, struct route_map_index
*index
, const char *command
,
398 const char *arg
, route_map_event_t type
))
400 rmap_match_set_hook
.no_match_tag
= func
;
404 void route_map_set_ip_nexthop_hook(int (*func
)(struct vty
*vty
,
405 struct route_map_index
*index
,
409 rmap_match_set_hook
.set_ip_nexthop
= func
;
412 /* no set ip nexthop */
413 void route_map_no_set_ip_nexthop_hook(int (*func
)(struct vty
*vty
,
414 struct route_map_index
*index
,
418 rmap_match_set_hook
.no_set_ip_nexthop
= func
;
421 /* set ipv6 nexthop local */
422 void route_map_set_ipv6_nexthop_local_hook(
423 int (*func
)(struct vty
*vty
, struct route_map_index
*index
,
424 const char *command
, const char *arg
))
426 rmap_match_set_hook
.set_ipv6_nexthop_local
= func
;
429 /* no set ipv6 nexthop local */
430 void route_map_no_set_ipv6_nexthop_local_hook(
431 int (*func
)(struct vty
*vty
, struct route_map_index
*index
,
432 const char *command
, const char *arg
))
434 rmap_match_set_hook
.no_set_ipv6_nexthop_local
= func
;
438 void route_map_set_metric_hook(int (*func
)(struct vty
*vty
,
439 struct route_map_index
*index
,
443 rmap_match_set_hook
.set_metric
= func
;
447 void route_map_no_set_metric_hook(int (*func
)(struct vty
*vty
,
448 struct route_map_index
*index
,
452 rmap_match_set_hook
.no_set_metric
= func
;
456 void route_map_set_tag_hook(int (*func
)(struct vty
*vty
,
457 struct route_map_index
*index
,
458 const char *command
, const char *arg
))
460 rmap_match_set_hook
.set_tag
= func
;
464 void route_map_no_set_tag_hook(int (*func
)(struct vty
*vty
,
465 struct route_map_index
*index
,
469 rmap_match_set_hook
.no_set_tag
= func
;
472 int generic_match_add(struct vty
*vty
, struct route_map_index
*index
,
473 const char *command
, const char *arg
,
474 route_map_event_t type
)
478 ret
= route_map_add_match(index
, command
, arg
);
480 case RMAP_COMPILE_SUCCESS
:
481 if (type
!= RMAP_EVENT_MATCH_ADDED
) {
482 route_map_upd8_dependency(type
, arg
, index
->map
->name
);
485 case RMAP_RULE_MISSING
:
486 vty_out(vty
, "%% [%s] Can't find rule.\n", frr_protonameinst
);
487 return CMD_WARNING_CONFIG_FAILED
;
489 case RMAP_COMPILE_ERROR
:
491 "%% [%s] Argument form is unsupported or malformed.\n",
493 return CMD_WARNING_CONFIG_FAILED
;
500 int generic_match_delete(struct vty
*vty
, struct route_map_index
*index
,
501 const char *command
, const char *arg
,
502 route_map_event_t type
)
505 int retval
= CMD_SUCCESS
;
506 char *dep_name
= NULL
;
508 char *rmap_name
= NULL
;
510 if (type
!= RMAP_EVENT_MATCH_DELETED
) {
511 /* ignore the mundane, the types without any dependency */
513 if ((tmpstr
= route_map_get_match_arg(index
, command
))
516 XSTRDUP(MTYPE_ROUTE_MAP_RULE
, tmpstr
);
518 dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_RULE
, arg
);
520 rmap_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, index
->map
->name
);
523 ret
= route_map_delete_match(index
, command
, dep_name
);
525 case RMAP_RULE_MISSING
:
526 vty_out(vty
, "%% [%s] Can't find rule.\n", frr_protonameinst
);
527 retval
= CMD_WARNING_CONFIG_FAILED
;
529 case RMAP_COMPILE_ERROR
:
531 "%% [%s] Argument form is unsupported or malformed.\n",
533 retval
= CMD_WARNING_CONFIG_FAILED
;
535 case RMAP_COMPILE_SUCCESS
:
536 if (type
!= RMAP_EVENT_MATCH_DELETED
&& dep_name
)
537 route_map_upd8_dependency(type
, dep_name
, rmap_name
);
542 XFREE(MTYPE_ROUTE_MAP_RULE
, dep_name
);
544 XFREE(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
549 int generic_set_add(struct vty
*vty
, struct route_map_index
*index
,
550 const char *command
, const char *arg
)
554 ret
= route_map_add_set(index
, command
, arg
);
556 case RMAP_RULE_MISSING
:
557 vty_out(vty
, "%% [%s] Can't find rule.\n", frr_protonameinst
);
558 return CMD_WARNING_CONFIG_FAILED
;
560 case RMAP_COMPILE_ERROR
:
562 "%% [%s] Argument form is unsupported or malformed.\n",
564 return CMD_WARNING_CONFIG_FAILED
;
566 case RMAP_COMPILE_SUCCESS
:
573 int generic_set_delete(struct vty
*vty
, struct route_map_index
*index
,
574 const char *command
, const char *arg
)
578 ret
= route_map_delete_set(index
, command
, arg
);
580 case RMAP_RULE_MISSING
:
581 vty_out(vty
, "%% [%s] Can't find rule.\n", frr_protonameinst
);
582 return CMD_WARNING_CONFIG_FAILED
;
584 case RMAP_COMPILE_ERROR
:
586 "%% [%s] Argument form is unsupported or malformed.\n",
588 return CMD_WARNING_CONFIG_FAILED
;
590 case RMAP_COMPILE_SUCCESS
:
598 /* Route map rule. This rule has both `match' rule and `set' rule. */
599 struct route_map_rule
{
601 struct route_map_rule_cmd
*cmd
;
603 /* For pretty printing. */
606 /* Pre-compiled match rule. */
610 struct route_map_rule
*next
;
611 struct route_map_rule
*prev
;
614 /* Making route map list. */
615 struct route_map_list
{
616 struct route_map
*head
;
617 struct route_map
*tail
;
619 void (*add_hook
)(const char *);
620 void (*delete_hook
)(const char *);
621 void (*event_hook
)(route_map_event_t
, const char *);
624 /* Master list of route map. */
625 static struct route_map_list route_map_master
= {NULL
, NULL
, NULL
, NULL
, NULL
};
626 struct hash
*route_map_master_hash
= NULL
;
628 static unsigned int route_map_hash_key_make(void *p
)
630 const struct route_map
*map
= p
;
631 return string_hash_make(map
->name
);
634 static bool route_map_hash_cmp(const void *p1
, const void *p2
)
636 const struct route_map
*map1
= p1
;
637 const struct route_map
*map2
= p2
;
639 if (map1
->deleted
== map2
->deleted
) {
640 if (map1
->name
&& map2
->name
) {
641 if (!strcmp(map1
->name
, map2
->name
)) {
644 } else if (!map1
->name
&& !map2
->name
) {
652 enum route_map_upd8_type
{
657 /* all possible route-map dependency types */
658 enum route_map_dep_type
{
659 ROUTE_MAP_DEP_RMAP
= 1,
661 ROUTE_MAP_DEP_ECLIST
,
662 ROUTE_MAP_DEP_LCLIST
,
664 ROUTE_MAP_DEP_ASPATH
,
665 ROUTE_MAP_DEP_FILTER
,
669 struct route_map_dep
{
671 struct hash
*dep_rmap_hash
;
672 struct hash
*this_hash
; /* ptr to the hash structure this is part of */
675 /* Hashes maintaining dependency between various sublists used by route maps */
676 struct hash
*route_map_dep_hash
[ROUTE_MAP_DEP_MAX
];
678 static unsigned int route_map_dep_hash_make_key(void *p
);
679 static void route_map_clear_all_references(char *rmap_name
);
680 static void route_map_rule_delete(struct route_map_rule_list
*,
681 struct route_map_rule
*);
682 static int rmap_debug
= 0;
684 static void route_map_index_delete(struct route_map_index
*, int);
686 /* New route map allocation. Please note route map's name must be
688 static struct route_map
*route_map_new(const char *name
)
690 struct route_map
*new;
692 new = XCALLOC(MTYPE_ROUTE_MAP
, sizeof(struct route_map
));
693 new->name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
694 QOBJ_REG(new, route_map
);
698 /* Add new name to route_map. */
699 static struct route_map
*route_map_add(const char *name
)
701 struct route_map
*map
;
702 struct route_map_list
*list
;
704 map
= route_map_new(name
);
705 list
= &route_map_master
;
707 /* Add map to the hash */
708 hash_get(route_map_master_hash
, map
, hash_alloc_intern
);
710 /* Add new entry to the head of the list to match how it is added in the
711 * hash table. This is to ensure that if the same route-map has been
712 * created more than once and then marked for deletion (which can happen
713 * if prior deletions haven't completed as BGP hasn't yet done the
714 * route-map processing), the order of the entities is the same in both
715 * the list and the hash table. Otherwise, since there is nothing to
716 * distinguish between the two entries, the wrong entry could get freed.
717 * TODO: This needs to be re-examined to handle it better - e.g., revive
718 * a deleted entry if the route-map is created again.
721 map
->next
= list
->head
;
723 list
->head
->prev
= map
;
729 if (route_map_master
.add_hook
) {
730 (*route_map_master
.add_hook
)(name
);
731 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_ADDED
);
736 /* this is supposed to be called post processing by
737 * the delete hook function. Don't invoke delete_hook
738 * again in this routine.
740 static void route_map_free_map(struct route_map
*map
)
742 struct route_map_list
*list
;
743 struct route_map_index
*index
;
748 while ((index
= map
->head
) != NULL
)
749 route_map_index_delete(index
, 0);
751 list
= &route_map_master
;
756 map
->next
->prev
= map
->prev
;
758 list
->tail
= map
->prev
;
761 map
->prev
->next
= map
->next
;
763 list
->head
= map
->next
;
765 hash_release(route_map_master_hash
, map
);
766 XFREE(MTYPE_ROUTE_MAP_NAME
, map
->name
);
767 XFREE(MTYPE_ROUTE_MAP
, map
);
770 /* Route map delete from list. */
771 static void route_map_delete(struct route_map
*map
)
773 struct route_map_index
*index
;
776 while ((index
= map
->head
) != NULL
)
777 route_map_index_delete(index
, 0);
782 /* Clear all dependencies */
783 route_map_clear_all_references(name
);
785 /* Execute deletion hook. */
786 if (route_map_master
.delete_hook
) {
787 (*route_map_master
.delete_hook
)(name
);
788 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_DELETED
);
791 if (!map
->to_be_processed
) {
792 route_map_free_map(map
);
796 /* Lookup route map by route map name string. */
797 struct route_map
*route_map_lookup_by_name(const char *name
)
799 struct route_map
*map
;
800 struct route_map tmp_map
;
805 // map.deleted is 0 via memset
806 memset(&tmp_map
, 0, sizeof(struct route_map
));
807 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
808 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
809 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
813 /* Simple helper to warn if route-map does not exist. */
814 struct route_map
*route_map_lookup_warn_noexist(struct vty
*vty
, const char *name
)
816 struct route_map
*route_map
= route_map_lookup_by_name(name
);
819 if (vty_shell_serv(vty
))
820 vty_out(vty
, "The route-map '%s' does not exist.\n", name
);
825 int route_map_mark_updated(const char *name
)
827 struct route_map
*map
;
829 struct route_map tmp_map
;
834 map
= route_map_lookup_by_name(name
);
836 /* If we did not find the routemap with deleted=false try again
840 memset(&tmp_map
, 0, sizeof(struct route_map
));
841 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
842 tmp_map
.deleted
= true;
843 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
844 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
848 map
->to_be_processed
= true;
855 static int route_map_clear_updated(struct route_map
*map
)
860 map
->to_be_processed
= false;
862 route_map_free_map(map
);
868 /* Lookup route map. If there isn't route map create one and return
870 static struct route_map
*route_map_get(const char *name
)
872 struct route_map
*map
;
874 map
= route_map_lookup_by_name(name
);
876 map
= route_map_add(name
);
881 void route_map_walk_update_list(void (*route_map_update_fn
)(char *name
))
883 struct route_map
*node
;
884 struct route_map
*nnode
= NULL
;
886 for (node
= route_map_master
.head
; node
; node
= nnode
) {
887 if (node
->to_be_processed
) {
888 /* DD: Should we add any thread yield code here */
889 route_map_update_fn(node
->name
);
891 route_map_clear_updated(node
);
897 /* Return route map's type string. */
898 static const char *route_map_type_str(enum route_map_type type
)
913 static int route_map_empty(struct route_map
*map
)
915 if (map
->head
== NULL
&& map
->tail
== NULL
)
922 static void vty_show_route_map_entry(struct vty
*vty
, struct route_map
*map
)
924 struct route_map_index
*index
;
925 struct route_map_rule
*rule
;
927 vty_out(vty
, "route-map: %s Invoked: %" PRIu64
"\n",
928 map
->name
, map
->applied
);
930 for (index
= map
->head
; index
; index
= index
->next
) {
931 vty_out(vty
, " %s, sequence %d Invoked %" PRIu64
"\n",
932 route_map_type_str(index
->type
), index
->pref
,
936 if (index
->description
)
937 vty_out(vty
, " Description:\n %s\n",
941 vty_out(vty
, " Match clauses:\n");
942 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
943 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
946 vty_out(vty
, " Set clauses:\n");
947 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
948 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
952 vty_out(vty
, " Call clause:\n");
954 vty_out(vty
, " Call %s\n", index
->nextrm
);
957 vty_out(vty
, " Action:\n");
958 if (index
->exitpolicy
== RMAP_GOTO
)
959 vty_out(vty
, " Goto %d\n", index
->nextpref
);
960 else if (index
->exitpolicy
== RMAP_NEXT
)
961 vty_out(vty
, " Continue to next entry\n");
962 else if (index
->exitpolicy
== RMAP_EXIT
)
963 vty_out(vty
, " Exit routemap\n");
967 static int sort_route_map(const void **map1
, const void **map2
)
969 const struct route_map
*m1
= *map1
;
970 const struct route_map
*m2
= *map2
;
972 return strcmp(m1
->name
, m2
->name
);
975 static int vty_show_route_map(struct vty
*vty
, const char *name
)
977 struct route_map
*map
;
979 vty_out(vty
, "%s:\n", frr_protonameinst
);
982 map
= route_map_lookup_by_name(name
);
985 vty_show_route_map_entry(vty
, map
);
988 vty_out(vty
, "%s: 'route-map %s' not found\n",
989 frr_protonameinst
, name
);
994 struct list
*maplist
= list_new();
997 for (map
= route_map_master
.head
; map
; map
= map
->next
)
998 listnode_add(maplist
, map
);
1000 list_sort(maplist
, sort_route_map
);
1002 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
1003 vty_show_route_map_entry(vty
, map
);
1005 list_delete(&maplist
);
1011 /* New route map allocation. Please note route map's name must be
1013 static struct route_map_index
*route_map_index_new(void)
1015 struct route_map_index
*new;
1017 new = XCALLOC(MTYPE_ROUTE_MAP_INDEX
, sizeof(struct route_map_index
));
1018 new->exitpolicy
= RMAP_EXIT
; /* Default to Cisco-style */
1019 QOBJ_REG(new, route_map_index
);
1023 /* Free route map index. */
1024 static void route_map_index_delete(struct route_map_index
*index
, int notify
)
1026 struct route_map_rule
*rule
;
1030 /* Free route match. */
1031 while ((rule
= index
->match_list
.head
) != NULL
)
1032 route_map_rule_delete(&index
->match_list
, rule
);
1034 /* Free route set. */
1035 while ((rule
= index
->set_list
.head
) != NULL
)
1036 route_map_rule_delete(&index
->set_list
, rule
);
1038 /* Remove index from route map list. */
1040 index
->next
->prev
= index
->prev
;
1042 index
->map
->tail
= index
->prev
;
1045 index
->prev
->next
= index
->next
;
1047 index
->map
->head
= index
->next
;
1049 /* Free 'char *nextrm' if not NULL */
1051 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
1053 /* Execute event hook. */
1054 if (route_map_master
.event_hook
&& notify
) {
1055 (*route_map_master
.event_hook
)(RMAP_EVENT_INDEX_DELETED
,
1057 route_map_notify_dependencies(index
->map
->name
,
1058 RMAP_EVENT_CALL_ADDED
);
1060 XFREE(MTYPE_ROUTE_MAP_INDEX
, index
);
1063 /* Lookup index from route map. */
1064 static struct route_map_index
*route_map_index_lookup(struct route_map
*map
,
1065 enum route_map_type type
,
1068 struct route_map_index
*index
;
1070 for (index
= map
->head
; index
; index
= index
->next
)
1071 if ((index
->type
== type
|| type
== RMAP_ANY
)
1072 && index
->pref
== pref
)
1077 /* Add new index to route map. */
1078 static struct route_map_index
*
1079 route_map_index_add(struct route_map
*map
, enum route_map_type type
, int pref
)
1081 struct route_map_index
*index
;
1082 struct route_map_index
*point
;
1084 /* Allocate new route map inex. */
1085 index
= route_map_index_new();
1090 /* Compare preference. */
1091 for (point
= map
->head
; point
; point
= point
->next
)
1092 if (point
->pref
>= pref
)
1095 if (map
->head
== NULL
) {
1096 map
->head
= map
->tail
= index
;
1097 } else if (point
== NULL
) {
1098 index
->prev
= map
->tail
;
1099 map
->tail
->next
= index
;
1101 } else if (point
== map
->head
) {
1102 index
->next
= map
->head
;
1103 map
->head
->prev
= index
;
1106 index
->next
= point
;
1107 index
->prev
= point
->prev
;
1109 point
->prev
->next
= index
;
1110 point
->prev
= index
;
1113 /* Execute event hook. */
1114 if (route_map_master
.event_hook
) {
1115 (*route_map_master
.event_hook
)(RMAP_EVENT_INDEX_ADDED
,
1117 route_map_notify_dependencies(map
->name
, RMAP_EVENT_CALL_ADDED
);
1122 /* Get route map index. */
1123 static struct route_map_index
*
1124 route_map_index_get(struct route_map
*map
, enum route_map_type type
, int pref
)
1126 struct route_map_index
*index
;
1128 index
= route_map_index_lookup(map
, RMAP_ANY
, pref
);
1129 if (index
&& index
->type
!= type
) {
1130 /* Delete index from route map. */
1131 route_map_index_delete(index
, 1);
1135 index
= route_map_index_add(map
, type
, pref
);
1139 /* New route map rule */
1140 static struct route_map_rule
*route_map_rule_new(void)
1142 struct route_map_rule
*new;
1144 new = XCALLOC(MTYPE_ROUTE_MAP_RULE
, sizeof(struct route_map_rule
));
1148 /* Install rule command to the match list. */
1149 void route_map_install_match(struct route_map_rule_cmd
*cmd
)
1151 vector_set(route_match_vec
, cmd
);
1154 /* Install rule command to the set list. */
1155 void route_map_install_set(struct route_map_rule_cmd
*cmd
)
1157 vector_set(route_set_vec
, cmd
);
1160 /* Lookup rule command from match list. */
1161 static struct route_map_rule_cmd
*route_map_lookup_match(const char *name
)
1164 struct route_map_rule_cmd
*rule
;
1166 for (i
= 0; i
< vector_active(route_match_vec
); i
++)
1167 if ((rule
= vector_slot(route_match_vec
, i
)) != NULL
)
1168 if (strcmp(rule
->str
, name
) == 0)
1173 /* Lookup rule command from set list. */
1174 static struct route_map_rule_cmd
*route_map_lookup_set(const char *name
)
1177 struct route_map_rule_cmd
*rule
;
1179 for (i
= 0; i
< vector_active(route_set_vec
); i
++)
1180 if ((rule
= vector_slot(route_set_vec
, i
)) != NULL
)
1181 if (strcmp(rule
->str
, name
) == 0)
1186 /* Add match and set rule to rule list. */
1187 static void route_map_rule_add(struct route_map_rule_list
*list
,
1188 struct route_map_rule
*rule
)
1191 rule
->prev
= list
->tail
;
1193 list
->tail
->next
= rule
;
1199 /* Delete rule from rule list. */
1200 static void route_map_rule_delete(struct route_map_rule_list
*list
,
1201 struct route_map_rule
*rule
)
1203 if (rule
->cmd
->func_free
)
1204 (*rule
->cmd
->func_free
)(rule
->value
);
1207 XFREE(MTYPE_ROUTE_MAP_RULE_STR
, rule
->rule_str
);
1210 rule
->next
->prev
= rule
->prev
;
1212 list
->tail
= rule
->prev
;
1214 rule
->prev
->next
= rule
->next
;
1216 list
->head
= rule
->next
;
1218 XFREE(MTYPE_ROUTE_MAP_RULE
, rule
);
1221 /* strcmp wrapper function which don't crush even argument is NULL. */
1222 static int rulecmp(const char *dst
, const char *src
)
1233 return strcmp(dst
, src
);
1238 /* Use this to return the already specified argument for this match. This is
1239 * useful to get the specified argument with a route map match rule when the
1240 * rule is being deleted and the argument is not provided.
1242 const char *route_map_get_match_arg(struct route_map_index
*index
,
1243 const char *match_name
)
1245 struct route_map_rule
*rule
;
1246 struct route_map_rule_cmd
*cmd
;
1248 /* First lookup rule for add match statement. */
1249 cmd
= route_map_lookup_match(match_name
);
1253 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1254 if (rule
->cmd
== cmd
&& rule
->rule_str
!= NULL
)
1255 return (rule
->rule_str
);
1260 /* Add match statement to route map. */
1261 int route_map_add_match(struct route_map_index
*index
, const char *match_name
,
1262 const char *match_arg
)
1264 struct route_map_rule
*rule
;
1265 struct route_map_rule
*next
;
1266 struct route_map_rule_cmd
*cmd
;
1270 /* First lookup rule for add match statement. */
1271 cmd
= route_map_lookup_match(match_name
);
1273 return RMAP_RULE_MISSING
;
1275 /* Next call compile function for this match statement. */
1276 if (cmd
->func_compile
) {
1277 compile
= (*cmd
->func_compile
)(match_arg
);
1278 if (compile
== NULL
)
1279 return RMAP_COMPILE_ERROR
;
1283 /* If argument is completely same ignore it. */
1284 for (rule
= index
->match_list
.head
; rule
; rule
= next
) {
1286 if (rule
->cmd
== cmd
) {
1287 route_map_rule_delete(&index
->match_list
, rule
);
1292 /* Add new route map match rule. */
1293 rule
= route_map_rule_new();
1295 rule
->value
= compile
;
1297 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, match_arg
);
1299 rule
->rule_str
= NULL
;
1301 /* Add new route match rule to linked list. */
1302 route_map_rule_add(&index
->match_list
, rule
);
1304 /* Execute event hook. */
1305 if (route_map_master
.event_hook
) {
1306 (*route_map_master
.event_hook
)(
1307 replaced
? RMAP_EVENT_MATCH_REPLACED
1308 : RMAP_EVENT_MATCH_ADDED
,
1310 route_map_notify_dependencies(index
->map
->name
,
1311 RMAP_EVENT_CALL_ADDED
);
1314 return RMAP_COMPILE_SUCCESS
;
1317 /* Delete specified route match rule. */
1318 int route_map_delete_match(struct route_map_index
*index
,
1319 const char *match_name
, const char *match_arg
)
1321 struct route_map_rule
*rule
;
1322 struct route_map_rule_cmd
*cmd
;
1324 cmd
= route_map_lookup_match(match_name
);
1328 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1329 if (rule
->cmd
== cmd
&& (rulecmp(rule
->rule_str
, match_arg
) == 0
1330 || match_arg
== NULL
)) {
1331 route_map_rule_delete(&index
->match_list
, rule
);
1332 /* Execute event hook. */
1333 if (route_map_master
.event_hook
) {
1334 (*route_map_master
.event_hook
)(
1335 RMAP_EVENT_MATCH_DELETED
,
1337 route_map_notify_dependencies(
1339 RMAP_EVENT_CALL_ADDED
);
1343 /* Can't find matched rule. */
1347 /* Add route-map set statement to the route map. */
1348 int route_map_add_set(struct route_map_index
*index
, const char *set_name
,
1349 const char *set_arg
)
1351 struct route_map_rule
*rule
;
1352 struct route_map_rule
*next
;
1353 struct route_map_rule_cmd
*cmd
;
1357 cmd
= route_map_lookup_set(set_name
);
1359 return RMAP_RULE_MISSING
;
1361 /* Next call compile function for this match statement. */
1362 if (cmd
->func_compile
) {
1363 compile
= (*cmd
->func_compile
)(set_arg
);
1364 if (compile
== NULL
)
1365 return RMAP_COMPILE_ERROR
;
1369 /* Add by WJL. if old set command of same kind exist, delete it first
1370 to ensure only one set command of same kind exist under a
1372 for (rule
= index
->set_list
.head
; rule
; rule
= next
) {
1374 if (rule
->cmd
== cmd
) {
1375 route_map_rule_delete(&index
->set_list
, rule
);
1380 /* Add new route map match rule. */
1381 rule
= route_map_rule_new();
1383 rule
->value
= compile
;
1385 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, set_arg
);
1387 rule
->rule_str
= NULL
;
1389 /* Add new route match rule to linked list. */
1390 route_map_rule_add(&index
->set_list
, rule
);
1392 /* Execute event hook. */
1393 if (route_map_master
.event_hook
) {
1394 (*route_map_master
.event_hook
)(replaced
1395 ? RMAP_EVENT_SET_REPLACED
1396 : RMAP_EVENT_SET_ADDED
,
1398 route_map_notify_dependencies(index
->map
->name
,
1399 RMAP_EVENT_CALL_ADDED
);
1401 return RMAP_COMPILE_SUCCESS
;
1404 /* Delete route map set rule. */
1405 int route_map_delete_set(struct route_map_index
*index
, const char *set_name
,
1406 const char *set_arg
)
1408 struct route_map_rule
*rule
;
1409 struct route_map_rule_cmd
*cmd
;
1411 cmd
= route_map_lookup_set(set_name
);
1415 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
1416 if ((rule
->cmd
== cmd
) && (rulecmp(rule
->rule_str
, set_arg
) == 0
1417 || set_arg
== NULL
)) {
1418 route_map_rule_delete(&index
->set_list
, rule
);
1419 /* Execute event hook. */
1420 if (route_map_master
.event_hook
) {
1421 (*route_map_master
.event_hook
)(
1422 RMAP_EVENT_SET_DELETED
,
1424 route_map_notify_dependencies(
1426 RMAP_EVENT_CALL_ADDED
);
1430 /* Can't find matched rule. */
1434 /* Apply route map's each index to the object.
1436 The matrix for a route-map looks like this:
1437 (note, this includes the description for the "NEXT"
1438 and "GOTO" frobs now
1442 permit action | cont
1444 ------------------+---------------
1450 -Apply Set statements, accept route
1451 -If Call statement is present jump to the specified route-map, if it
1452 denies the route we finish.
1453 -If NEXT is specified, goto NEXT statement
1454 -If GOTO is specified, goto the first clause where pref > nextpref
1455 -If nothing is specified, do as Cisco and finish
1457 -Route is denied by route-map.
1461 If we get no matches after we've processed all updates, then the route
1464 Some notes on the new "CALL", "NEXT" and "GOTO"
1465 call WORD - If this clause is matched, then the set statements
1466 are executed and then we jump to route-map 'WORD'. If
1467 this route-map denies the route, we finish, in other
1469 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
1470 on-match next - If this clause is matched, then the set statements
1471 are executed and then we drop through to the next clause
1472 on-match goto n - If this clause is matched, then the set statments
1473 are executed and then we goto the nth clause, or the
1474 first clause greater than this. In order to ensure
1475 route-maps *always* exit, you cannot jump backwards.
1478 We need to make sure our route-map processing matches the above
1481 static route_map_result_t
1482 route_map_apply_match(struct route_map_rule_list
*match_list
,
1483 const struct prefix
*prefix
, route_map_object_t type
,
1486 route_map_result_t ret
= RMAP_NOMATCH
;
1487 struct route_map_rule
*match
;
1490 /* Check all match rule and if there is no match rule, go to the
1492 if (!match_list
->head
)
1495 for (match
= match_list
->head
; match
; match
= match
->next
) {
1496 /* Try each match statement in turn, If any do not
1498 RMAP_MATCH, return, otherwise continue on to next
1500 statement. All match statements must match for
1503 ret
= (*match
->cmd
->func_apply
)(match
->value
, prefix
,
1505 if (ret
!= RMAP_MATCH
)
1512 /* Apply route map to the object. */
1513 route_map_result_t
route_map_apply(struct route_map
*map
,
1514 const struct prefix
*prefix
,
1515 route_map_object_t type
, void *object
)
1517 static int recursion
= 0;
1519 struct route_map_index
*index
;
1520 struct route_map_rule
*set
;
1522 if (recursion
> RMAP_RECURSION_LIMIT
) {
1524 EC_LIB_RMAP_RECURSION_LIMIT
,
1525 "route-map recursion limit (%d) reached, discarding route",
1526 RMAP_RECURSION_LIMIT
);
1528 return RMAP_DENYMATCH
;
1532 return RMAP_DENYMATCH
;
1535 for (index
= map
->head
; index
; index
= index
->next
) {
1536 /* Apply this index. */
1538 ret
= route_map_apply_match(&index
->match_list
, prefix
, type
,
1541 /* Now we apply the matrix from above */
1542 if (ret
== RMAP_NOMATCH
)
1543 /* 'cont' from matrix - continue to next route-map
1546 else if (ret
== RMAP_MATCH
) {
1547 if (index
->type
== RMAP_PERMIT
)
1550 /* permit+match must execute sets */
1551 for (set
= index
->set_list
.head
; set
;
1553 ret
= (*set
->cmd
->func_apply
)(
1554 set
->value
, prefix
, type
,
1557 /* Call another route-map if available */
1558 if (index
->nextrm
) {
1559 struct route_map
*nextrm
=
1560 route_map_lookup_by_name(
1563 if (nextrm
) /* Target route-map found,
1567 ret
= route_map_apply(
1568 nextrm
, prefix
, type
,
1573 /* If nextrm returned 'deny', finish. */
1574 if (ret
== RMAP_DENYMATCH
)
1578 switch (index
->exitpolicy
) {
1584 /* Find the next clause to jump to */
1585 struct route_map_index
*next
=
1587 int nextpref
= index
->nextpref
;
1589 while (next
&& next
->pref
< nextpref
) {
1594 /* No clauses match! */
1599 } else if (index
->type
== RMAP_DENY
)
1602 return RMAP_DENYMATCH
;
1606 /* Finally route-map does not match at all. */
1607 return RMAP_DENYMATCH
;
1610 void route_map_add_hook(void (*func
)(const char *))
1612 route_map_master
.add_hook
= func
;
1615 void route_map_delete_hook(void (*func
)(const char *))
1617 route_map_master
.delete_hook
= func
;
1620 void route_map_event_hook(void (*func
)(route_map_event_t
, const char *))
1622 route_map_master
.event_hook
= func
;
1625 /* Routines for route map dependency lists and dependency processing */
1626 static bool route_map_rmap_hash_cmp(const void *p1
, const void *p2
)
1628 return (strcmp((const char *)p1
, (const char *)p2
) == 0);
1631 static bool route_map_dep_hash_cmp(const void *p1
, const void *p2
)
1634 return (strcmp(((const struct route_map_dep
*)p1
)->dep_name
,
1639 static void route_map_clear_reference(struct hash_backet
*backet
, void *arg
)
1641 struct route_map_dep
*dep
= (struct route_map_dep
*)backet
->data
;
1646 (char *)hash_release(dep
->dep_rmap_hash
, (void *)arg
);
1648 XFREE(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
1650 if (!dep
->dep_rmap_hash
->count
) {
1651 dep
= hash_release(dep
->this_hash
,
1652 (void *)dep
->dep_name
);
1653 hash_free(dep
->dep_rmap_hash
);
1654 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
1655 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
1660 static void route_map_clear_all_references(char *rmap_name
)
1664 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
1665 hash_iterate(route_map_dep_hash
[i
], route_map_clear_reference
,
1670 static void *route_map_dep_hash_alloc(void *p
)
1672 char *dep_name
= (char *)p
;
1673 struct route_map_dep
*dep_entry
;
1675 dep_entry
= XCALLOC(MTYPE_ROUTE_MAP_DEP
, sizeof(struct route_map_dep
));
1676 dep_entry
->dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1677 dep_entry
->dep_rmap_hash
=
1678 hash_create_size(8, route_map_dep_hash_make_key
,
1679 route_map_rmap_hash_cmp
, "Route Map Dep Hash");
1680 dep_entry
->this_hash
= NULL
;
1682 return ((void *)dep_entry
);
1685 static void *route_map_name_hash_alloc(void *p
)
1687 return ((void *)XSTRDUP(MTYPE_ROUTE_MAP_NAME
, (const char *)p
));
1690 static unsigned int route_map_dep_hash_make_key(void *p
)
1692 return (string_hash_make((char *)p
));
1695 static void route_map_print_dependency(struct hash_backet
*backet
, void *data
)
1697 char *rmap_name
= (char *)backet
->data
;
1698 char *dep_name
= (char *)data
;
1700 zlog_debug("%s: Dependency for %s: %s", __FUNCTION__
, dep_name
,
1704 static int route_map_dep_update(struct hash
*dephash
, const char *dep_name
,
1705 const char *rmap_name
, route_map_event_t type
)
1707 struct route_map_dep
*dep
= NULL
;
1709 char *dname
, *rname
;
1712 dname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1713 rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
1716 case RMAP_EVENT_PLIST_ADDED
:
1717 case RMAP_EVENT_CLIST_ADDED
:
1718 case RMAP_EVENT_ECLIST_ADDED
:
1719 case RMAP_EVENT_ASLIST_ADDED
:
1720 case RMAP_EVENT_LLIST_ADDED
:
1721 case RMAP_EVENT_CALL_ADDED
:
1722 case RMAP_EVENT_FILTER_ADDED
:
1724 zlog_debug("%s: Adding dependency for %s in %s",
1725 __FUNCTION__
, dep_name
, rmap_name
);
1726 dep
= (struct route_map_dep
*)hash_get(
1727 dephash
, dname
, route_map_dep_hash_alloc
);
1733 if (!dep
->this_hash
)
1734 dep
->this_hash
= dephash
;
1736 hash_get(dep
->dep_rmap_hash
, rname
, route_map_name_hash_alloc
);
1738 case RMAP_EVENT_PLIST_DELETED
:
1739 case RMAP_EVENT_CLIST_DELETED
:
1740 case RMAP_EVENT_ECLIST_DELETED
:
1741 case RMAP_EVENT_ASLIST_DELETED
:
1742 case RMAP_EVENT_LLIST_DELETED
:
1743 case RMAP_EVENT_CALL_DELETED
:
1744 case RMAP_EVENT_FILTER_DELETED
:
1746 zlog_debug("%s: Deleting dependency for %s in %s",
1747 __FUNCTION__
, dep_name
, rmap_name
);
1748 dep
= (struct route_map_dep
*)hash_get(dephash
, dname
, NULL
);
1753 ret_map_name
= (char *)hash_release(dep
->dep_rmap_hash
, rname
);
1755 XFREE(MTYPE_ROUTE_MAP_NAME
, ret_map_name
);
1757 if (!dep
->dep_rmap_hash
->count
) {
1758 dep
= hash_release(dephash
, dname
);
1759 hash_free(dep
->dep_rmap_hash
);
1760 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
1761 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
1771 hash_iterate(dep
->dep_rmap_hash
,
1772 route_map_print_dependency
, dname
);
1776 XFREE(MTYPE_ROUTE_MAP_NAME
, rname
);
1777 XFREE(MTYPE_ROUTE_MAP_NAME
, dname
);
1781 static struct hash
*route_map_get_dep_hash(route_map_event_t event
)
1783 struct hash
*upd8_hash
= NULL
;
1786 case RMAP_EVENT_PLIST_ADDED
:
1787 case RMAP_EVENT_PLIST_DELETED
:
1788 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_PLIST
];
1790 case RMAP_EVENT_CLIST_ADDED
:
1791 case RMAP_EVENT_CLIST_DELETED
:
1792 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_CLIST
];
1794 case RMAP_EVENT_ECLIST_ADDED
:
1795 case RMAP_EVENT_ECLIST_DELETED
:
1796 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ECLIST
];
1798 case RMAP_EVENT_ASLIST_ADDED
:
1799 case RMAP_EVENT_ASLIST_DELETED
:
1800 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ASPATH
];
1802 case RMAP_EVENT_LLIST_ADDED
:
1803 case RMAP_EVENT_LLIST_DELETED
:
1804 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_LCLIST
];
1806 case RMAP_EVENT_CALL_ADDED
:
1807 case RMAP_EVENT_CALL_DELETED
:
1808 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_RMAP
];
1810 case RMAP_EVENT_FILTER_ADDED
:
1811 case RMAP_EVENT_FILTER_DELETED
:
1812 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_FILTER
];
1821 static void route_map_process_dependency(struct hash_backet
*backet
, void *data
)
1823 char *rmap_name
= (char *)backet
->data
;
1824 route_map_event_t type
= (route_map_event_t
)(ptrdiff_t)data
;
1827 zlog_debug("%s: Notifying %s of dependency",
1828 __FUNCTION__
, rmap_name
);
1829 if (route_map_master
.event_hook
)
1830 (*route_map_master
.event_hook
)(type
, rmap_name
);
1833 void route_map_upd8_dependency(route_map_event_t type
, const char *arg
,
1834 const char *rmap_name
)
1836 struct hash
*upd8_hash
= NULL
;
1838 if ((upd8_hash
= route_map_get_dep_hash(type
))) {
1839 route_map_dep_update(upd8_hash
, arg
, rmap_name
, type
);
1841 if (type
== RMAP_EVENT_CALL_ADDED
) {
1843 if (route_map_master
.add_hook
)
1844 (*route_map_master
.add_hook
)(rmap_name
);
1845 } else if (type
== RMAP_EVENT_CALL_DELETED
) {
1847 if (route_map_master
.delete_hook
)
1848 (*route_map_master
.delete_hook
)(rmap_name
);
1853 void route_map_notify_dependencies(const char *affected_name
,
1854 route_map_event_t event
)
1856 struct route_map_dep
*dep
;
1857 struct hash
*upd8_hash
;
1863 name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, affected_name
);
1865 if ((upd8_hash
= route_map_get_dep_hash(event
)) == NULL
) {
1866 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
1870 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, name
, NULL
);
1872 if (!dep
->this_hash
)
1873 dep
->this_hash
= upd8_hash
;
1875 hash_iterate(dep
->dep_rmap_hash
, route_map_process_dependency
,
1879 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
1883 /* VTY related functions. */
1884 DEFUN (match_interface
,
1885 match_interface_cmd
,
1886 "match interface WORD",
1888 "match first hop interface of route\n"
1892 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1894 if (rmap_match_set_hook
.match_interface
)
1895 return rmap_match_set_hook
.match_interface(
1896 vty
, index
, "interface", argv
[idx_word
]->arg
,
1897 RMAP_EVENT_MATCH_ADDED
);
1901 DEFUN (no_match_interface
,
1902 no_match_interface_cmd
,
1903 "no match interface [WORD]",
1906 "Match first hop interface of route\n"
1909 char *iface
= (argc
== 4) ? argv
[3]->arg
: NULL
;
1910 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1912 if (rmap_match_set_hook
.no_match_interface
)
1913 return rmap_match_set_hook
.no_match_interface(
1914 vty
, index
, "interface", iface
,
1915 RMAP_EVENT_MATCH_DELETED
);
1920 DEFUN (match_ip_address
,
1921 match_ip_address_cmd
,
1922 "match ip address <(1-199)|(1300-2699)|WORD>",
1925 "Match address of route\n"
1926 "IP access-list number\n"
1927 "IP access-list number (expanded range)\n"
1928 "IP Access-list name\n")
1931 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1933 if (rmap_match_set_hook
.match_ip_address
)
1934 return rmap_match_set_hook
.match_ip_address(
1935 vty
, index
, "ip address", argv
[idx_acl
]->arg
,
1936 RMAP_EVENT_FILTER_ADDED
);
1941 DEFUN (no_match_ip_address
,
1942 no_match_ip_address_cmd
,
1943 "no match ip address [<(1-199)|(1300-2699)|WORD>]",
1947 "Match address of route\n"
1948 "IP access-list number\n"
1949 "IP access-list number (expanded range)\n"
1950 "IP Access-list name\n")
1953 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1955 if (rmap_match_set_hook
.no_match_ip_address
) {
1956 if (argc
<= idx_word
)
1957 return rmap_match_set_hook
.no_match_ip_address(
1958 vty
, index
, "ip address", NULL
,
1959 RMAP_EVENT_FILTER_DELETED
);
1960 return rmap_match_set_hook
.no_match_ip_address(
1961 vty
, index
, "ip address", argv
[idx_word
]->arg
,
1962 RMAP_EVENT_FILTER_DELETED
);
1968 DEFUN (match_ip_address_prefix_list
,
1969 match_ip_address_prefix_list_cmd
,
1970 "match ip address prefix-list WORD",
1973 "Match address of route\n"
1974 "Match entries of prefix-lists\n"
1975 "IP prefix-list name\n")
1978 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1980 if (rmap_match_set_hook
.match_ip_address_prefix_list
)
1981 return rmap_match_set_hook
.match_ip_address_prefix_list(
1982 vty
, index
, "ip address prefix-list",
1983 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
1988 DEFUN (no_match_ip_address_prefix_list
,
1989 no_match_ip_address_prefix_list_cmd
,
1990 "no match ip address prefix-list [WORD]",
1994 "Match address of route\n"
1995 "Match entries of prefix-lists\n"
1996 "IP prefix-list name\n")
1999 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2001 if (rmap_match_set_hook
.no_match_ip_address_prefix_list
) {
2002 if (argc
<= idx_word
)
2003 return rmap_match_set_hook
2004 .no_match_ip_address_prefix_list(
2005 vty
, index
, "ip address prefix-list",
2006 NULL
, RMAP_EVENT_PLIST_DELETED
);
2007 return rmap_match_set_hook
.no_match_ip_address_prefix_list(
2008 vty
, index
, "ip address prefix-list",
2009 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2015 DEFUN (match_ip_next_hop
,
2016 match_ip_next_hop_cmd
,
2017 "match ip next-hop <(1-199)|(1300-2699)|WORD>",
2020 "Match next-hop address of route\n"
2021 "IP access-list number\n"
2022 "IP access-list number (expanded range)\n"
2023 "IP Access-list name\n")
2026 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2028 if (rmap_match_set_hook
.match_ip_next_hop
)
2029 return rmap_match_set_hook
.match_ip_next_hop(
2030 vty
, index
, "ip next-hop", argv
[idx_acl
]->arg
,
2031 RMAP_EVENT_FILTER_ADDED
);
2036 DEFUN (no_match_ip_next_hop
,
2037 no_match_ip_next_hop_cmd
,
2038 "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
2042 "Match next-hop address of route\n"
2043 "IP access-list number\n"
2044 "IP access-list number (expanded range)\n"
2045 "IP Access-list name\n")
2048 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2050 if (rmap_match_set_hook
.no_match_ip_next_hop
) {
2051 if (argc
<= idx_word
)
2052 return rmap_match_set_hook
.no_match_ip_next_hop(
2053 vty
, index
, "ip next-hop", NULL
,
2054 RMAP_EVENT_FILTER_DELETED
);
2055 return rmap_match_set_hook
.no_match_ip_next_hop(
2056 vty
, index
, "ip next-hop", argv
[idx_word
]->arg
,
2057 RMAP_EVENT_FILTER_DELETED
);
2063 DEFUN (match_ip_next_hop_prefix_list
,
2064 match_ip_next_hop_prefix_list_cmd
,
2065 "match ip next-hop prefix-list WORD",
2068 "Match next-hop address of route\n"
2069 "Match entries of prefix-lists\n"
2070 "IP prefix-list name\n")
2073 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2075 if (rmap_match_set_hook
.match_ip_next_hop_prefix_list
)
2076 return rmap_match_set_hook
.match_ip_next_hop_prefix_list(
2077 vty
, index
, "ip next-hop prefix-list",
2078 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
2082 DEFUN (no_match_ip_next_hop_prefix_list
,
2083 no_match_ip_next_hop_prefix_list_cmd
,
2084 "no match ip next-hop prefix-list [WORD]",
2088 "Match next-hop address of route\n"
2089 "Match entries of prefix-lists\n"
2090 "IP prefix-list name\n")
2093 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2095 if (rmap_match_set_hook
.no_match_ip_next_hop
) {
2096 if (argc
<= idx_word
)
2097 return rmap_match_set_hook
.no_match_ip_next_hop(
2098 vty
, index
, "ip next-hop prefix-list", NULL
,
2099 RMAP_EVENT_PLIST_DELETED
);
2100 return rmap_match_set_hook
.no_match_ip_next_hop(
2101 vty
, index
, "ip next-hop prefix-list",
2102 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2107 DEFUN(match_ip_next_hop_type
, match_ip_next_hop_type_cmd
,
2108 "match ip next-hop type <blackhole>",
2110 "Match next-hop address of route\n"
2111 "Match entries by type\n"
2115 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2117 if (rmap_match_set_hook
.match_ip_next_hop_type
)
2118 return rmap_match_set_hook
.match_ip_next_hop_type(
2119 vty
, index
, "ip next-hop type", argv
[idx_word
]->arg
,
2120 RMAP_EVENT_MATCH_ADDED
);
2124 DEFUN(no_match_ip_next_hop_type
, no_match_ip_next_hop_type_cmd
,
2125 "no match ip next-hop type [<blackhole>]",
2126 NO_STR MATCH_STR IP_STR
2127 "Match next-hop address of route\n"
2128 "Match entries by type\n"
2132 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2134 if (rmap_match_set_hook
.no_match_ip_next_hop
) {
2135 if (argc
<= idx_word
)
2136 return rmap_match_set_hook
.no_match_ip_next_hop(
2137 vty
, index
, "ip next-hop type", NULL
,
2138 RMAP_EVENT_MATCH_DELETED
);
2139 return rmap_match_set_hook
.no_match_ip_next_hop(
2140 vty
, index
, "ip next-hop type", argv
[idx_word
]->arg
,
2141 RMAP_EVENT_MATCH_DELETED
);
2147 DEFUN (match_ipv6_address
,
2148 match_ipv6_address_cmd
,
2149 "match ipv6 address WORD",
2152 "Match IPv6 address of route\n"
2153 "IPv6 access-list name\n")
2156 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2158 if (rmap_match_set_hook
.match_ipv6_address
)
2159 return rmap_match_set_hook
.match_ipv6_address(
2160 vty
, index
, "ipv6 address", argv
[idx_word
]->arg
,
2161 RMAP_EVENT_FILTER_ADDED
);
2165 DEFUN (no_match_ipv6_address
,
2166 no_match_ipv6_address_cmd
,
2167 "no match ipv6 address WORD",
2171 "Match IPv6 address of route\n"
2172 "IPv6 access-list name\n")
2175 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2177 if (rmap_match_set_hook
.no_match_ipv6_address
)
2178 return rmap_match_set_hook
.no_match_ipv6_address(
2179 vty
, index
, "ipv6 address", argv
[idx_word
]->arg
,
2180 RMAP_EVENT_FILTER_DELETED
);
2185 DEFUN (match_ipv6_address_prefix_list
,
2186 match_ipv6_address_prefix_list_cmd
,
2187 "match ipv6 address prefix-list WORD",
2190 "Match address of route\n"
2191 "Match entries of prefix-lists\n"
2192 "IP prefix-list name\n")
2195 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2197 if (rmap_match_set_hook
.match_ipv6_address_prefix_list
)
2198 return rmap_match_set_hook
.match_ipv6_address_prefix_list(
2199 vty
, index
, "ipv6 address prefix-list",
2200 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
2204 DEFUN (no_match_ipv6_address_prefix_list
,
2205 no_match_ipv6_address_prefix_list_cmd
,
2206 "no match ipv6 address prefix-list WORD",
2210 "Match address of route\n"
2211 "Match entries of prefix-lists\n"
2212 "IP prefix-list name\n")
2215 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2217 if (rmap_match_set_hook
.no_match_ipv6_address_prefix_list
)
2218 return rmap_match_set_hook
.no_match_ipv6_address_prefix_list(
2219 vty
, index
, "ipv6 address prefix-list",
2220 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2224 DEFUN(match_ipv6_next_hop_type
, match_ipv6_next_hop_type_cmd
,
2225 "match ipv6 next-hop type <blackhole>",
2227 "Match address of route\n"
2228 "Match entries by type\n"
2232 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2234 if (rmap_match_set_hook
.match_ipv6_next_hop_type
)
2235 return rmap_match_set_hook
.match_ipv6_next_hop_type(
2236 vty
, index
, "ipv6 next-hop type", argv
[idx_word
]->arg
,
2237 RMAP_EVENT_MATCH_ADDED
);
2241 DEFUN(no_match_ipv6_next_hop_type
, no_match_ipv6_next_hop_type_cmd
,
2242 "no match ipv6 next-hop type [<blackhole>]",
2243 NO_STR MATCH_STR IPV6_STR
2244 "Match address of route\n"
2245 "Match entries by type\n"
2249 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2251 if (rmap_match_set_hook
.no_match_ipv6_next_hop_type
)
2252 return rmap_match_set_hook
.no_match_ipv6_next_hop_type(
2253 vty
, index
, "ipv6 next-hop type",
2254 (argc
<= idx_word
) ? NULL
: argv
[idx_word
]->arg
,
2255 RMAP_EVENT_MATCH_DELETED
);
2259 DEFUN (match_metric
,
2261 "match metric (0-4294967295)",
2263 "Match metric of route\n"
2267 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2269 if (rmap_match_set_hook
.match_metric
)
2270 return rmap_match_set_hook
.match_metric(vty
, index
, "metric",
2271 argv
[idx_number
]->arg
,
2272 RMAP_EVENT_MATCH_ADDED
);
2277 DEFUN (no_match_metric
,
2278 no_match_metric_cmd
,
2279 "no match metric [(0-4294967295)]",
2282 "Match metric of route\n"
2286 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2288 if (rmap_match_set_hook
.no_match_metric
) {
2289 if (argc
<= idx_number
)
2290 return rmap_match_set_hook
.no_match_metric(
2291 vty
, index
, "metric", NULL
,
2292 RMAP_EVENT_MATCH_DELETED
);
2293 return rmap_match_set_hook
.no_match_metric(
2294 vty
, index
, "metric", argv
[idx_number
]->arg
,
2295 RMAP_EVENT_MATCH_DELETED
);
2303 "match tag (1-4294967295)",
2305 "Match tag of route\n"
2309 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2311 if (rmap_match_set_hook
.match_tag
)
2312 return rmap_match_set_hook
.match_tag(vty
, index
, "tag",
2313 argv
[idx_number
]->arg
,
2314 RMAP_EVENT_MATCH_ADDED
);
2319 DEFUN (no_match_tag
,
2321 "no match tag [(1-4294967295)]",
2324 "Match tag of route\n"
2327 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2330 char *arg
= argv_find(argv
, argc
, "(1-4294967295)", &idx
)
2334 if (rmap_match_set_hook
.no_match_tag
)
2335 return rmap_match_set_hook
.no_match_tag(
2336 vty
, index
, "tag", arg
, RMAP_EVENT_MATCH_DELETED
);
2341 DEFUN (set_ip_nexthop
,
2343 "set ip next-hop A.B.C.D",
2346 "Next hop address\n"
2347 "IP address of next hop\n")
2352 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2354 ret
= str2sockunion(argv
[idx_ipv4
]->arg
, &su
);
2356 vty_out(vty
, "%% Malformed nexthop address\n");
2357 return CMD_WARNING_CONFIG_FAILED
;
2359 if (su
.sin
.sin_addr
.s_addr
== 0
2360 || IPV4_CLASS_DE(ntohl(su
.sin
.sin_addr
.s_addr
))) {
2362 "%% nexthop address cannot be 0.0.0.0, multicast or reserved\n");
2363 return CMD_WARNING_CONFIG_FAILED
;
2366 if (rmap_match_set_hook
.set_ip_nexthop
)
2367 return rmap_match_set_hook
.set_ip_nexthop(
2368 vty
, index
, "ip next-hop", argv
[idx_ipv4
]->arg
);
2373 DEFUN (no_set_ip_nexthop
,
2374 no_set_ip_nexthop_cmd
,
2375 "no set ip next-hop [A.B.C.D]",
2379 "Next hop address\n"
2380 "IP address of next hop\n")
2383 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2384 const char *arg
= NULL
;
2386 if (argv_find(argv
, argc
, "A.B.C.D", &idx
))
2387 arg
= argv
[idx
]->arg
;
2389 if (rmap_match_set_hook
.no_set_ip_nexthop
)
2390 return rmap_match_set_hook
.no_set_ip_nexthop(
2391 vty
, index
, "ip next-hop", arg
);
2397 DEFUN (set_ipv6_nexthop_local
,
2398 set_ipv6_nexthop_local_cmd
,
2399 "set ipv6 next-hop local X:X::X:X",
2402 "IPv6 next-hop address\n"
2403 "IPv6 local address\n"
2404 "IPv6 address of next hop\n")
2407 struct in6_addr addr
;
2409 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2411 ret
= inet_pton(AF_INET6
, argv
[idx_ipv6
]->arg
, &addr
);
2413 vty_out(vty
, "%% Malformed nexthop address\n");
2414 return CMD_WARNING_CONFIG_FAILED
;
2416 if (!IN6_IS_ADDR_LINKLOCAL(&addr
)) {
2417 vty_out(vty
, "%% Invalid link-local nexthop address\n");
2418 return CMD_WARNING_CONFIG_FAILED
;
2421 if (rmap_match_set_hook
.set_ipv6_nexthop_local
)
2422 return rmap_match_set_hook
.set_ipv6_nexthop_local(
2423 vty
, index
, "ipv6 next-hop local", argv
[idx_ipv6
]->arg
);
2428 DEFUN (no_set_ipv6_nexthop_local
,
2429 no_set_ipv6_nexthop_local_cmd
,
2430 "no set ipv6 next-hop local [X:X::X:X]",
2434 "IPv6 next-hop address\n"
2435 "IPv6 local address\n"
2436 "IPv6 address of next hop\n")
2439 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2441 if (rmap_match_set_hook
.no_set_ipv6_nexthop_local
) {
2442 if (argc
<= idx_ipv6
)
2443 return rmap_match_set_hook
.no_set_ipv6_nexthop_local(
2444 vty
, index
, "ipv6 next-hop local", NULL
);
2445 return rmap_match_set_hook
.no_set_ipv6_nexthop_local(
2446 vty
, index
, "ipv6 next-hop local", argv
[5]->arg
);
2453 "set metric <(0-4294967295)|rtt|+rtt|-rtt|+metric|-metric>",
2455 "Metric value for destination routing protocol\n"
2457 "Assign round trip time\n"
2458 "Add round trip time\n"
2459 "Subtract round trip time\n"
2461 "Subtract metric\n")
2464 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2466 const char *pass
= (argv
[idx_number
]->type
== RANGE_TKN
)
2467 ? argv
[idx_number
]->arg
2468 : argv
[idx_number
]->text
;
2470 if (rmap_match_set_hook
.set_metric
)
2471 return rmap_match_set_hook
.set_metric(vty
, index
, "metric",
2477 DEFUN (no_set_metric
,
2479 "no set metric [(0-4294967295)]",
2482 "Metric value for destination routing protocol\n"
2486 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2488 if (rmap_match_set_hook
.no_set_metric
) {
2489 if (argc
<= idx_number
)
2490 return rmap_match_set_hook
.no_set_metric(
2491 vty
, index
, "metric", NULL
);
2492 return rmap_match_set_hook
.no_set_metric(vty
, index
, "metric",
2493 argv
[idx_number
]->arg
);
2501 "set tag (1-4294967295)",
2503 "Tag value for routing protocol\n"
2506 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2509 if (rmap_match_set_hook
.set_tag
)
2510 return rmap_match_set_hook
.set_tag(vty
, index
, "tag",
2511 argv
[idx_number
]->arg
);
2518 "no set tag [(1-4294967295)]",
2521 "Tag value for routing protocol\n"
2524 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2527 if (rmap_match_set_hook
.no_set_tag
) {
2528 if (argc
<= idx_number
)
2529 return rmap_match_set_hook
.no_set_tag(vty
, index
, "tag",
2531 return rmap_match_set_hook
.no_set_tag(vty
, index
, "tag",
2532 argv
[idx_number
]->arg
);
2538 DEFUN_NOSH (route_map
,
2540 "route-map WORD <deny|permit> (1-65535)",
2541 "Create route-map or enter route-map command mode\n"
2543 "Route map denies set operations\n"
2544 "Route map permits set operations\n"
2545 "Sequence to insert to/delete from existing route-map entry\n")
2548 int idx_permit_deny
= 2;
2550 struct route_map
*map
;
2551 struct route_map_index
*index
;
2552 char *endptr
= NULL
;
2554 argv
[idx_permit_deny
]->arg
[0] == 'p' ? RMAP_PERMIT
: RMAP_DENY
;
2555 unsigned long pref
= strtoul(argv
[idx_number
]->arg
, &endptr
, 10);
2556 const char *mapname
= argv
[idx_word
]->arg
;
2558 /* Get route map. */
2559 map
= route_map_get(mapname
);
2560 index
= route_map_index_get(map
, permit
, pref
);
2562 VTY_PUSH_CONTEXT(RMAP_NODE
, index
);
2566 DEFUN (no_route_map_all
,
2567 no_route_map_all_cmd
,
2568 "no route-map WORD",
2570 "Create route-map or enter route-map command mode\n"
2574 const char *mapname
= argv
[idx_word
]->arg
;
2575 struct route_map
*map
;
2577 map
= route_map_lookup_by_name(mapname
);
2579 vty_out(vty
, "%% Could not find route-map %s\n", mapname
);
2580 return CMD_WARNING_CONFIG_FAILED
;
2583 route_map_delete(map
);
2588 DEFUN (no_route_map
,
2590 "no route-map WORD <deny|permit> (1-65535)",
2592 "Create route-map or enter route-map command mode\n"
2594 "Route map denies set operations\n"
2595 "Route map permits set operations\n"
2596 "Sequence to insert to/delete from existing route-map entry\n")
2599 int idx_permit_deny
= 3;
2601 struct route_map
*map
;
2602 struct route_map_index
*index
;
2603 char *endptr
= NULL
;
2604 int permit
= strmatch(argv
[idx_permit_deny
]->text
, "permit")
2607 const char *prefstr
= argv
[idx_number
]->arg
;
2608 const char *mapname
= argv
[idx_word
]->arg
;
2609 unsigned long pref
= strtoul(prefstr
, &endptr
, 10);
2611 /* Existence check. */
2612 map
= route_map_lookup_by_name(mapname
);
2614 vty_out(vty
, "%% Could not find route-map %s\n", mapname
);
2615 return CMD_WARNING_CONFIG_FAILED
;
2618 /* Lookup route map index. */
2619 index
= route_map_index_lookup(map
, permit
, pref
);
2620 if (index
== NULL
) {
2621 vty_out(vty
, "%% Could not find route-map entry %s %s\n",
2623 return CMD_WARNING_CONFIG_FAILED
;
2626 /* Delete index from route map. */
2627 route_map_index_delete(index
, 1);
2629 /* If this route rule is the last one, delete route map itself. */
2630 if (route_map_empty(map
))
2631 route_map_delete(map
);
2636 DEFUN (rmap_onmatch_next
,
2637 rmap_onmatch_next_cmd
,
2639 "Exit policy on matches\n"
2642 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2645 if (index
->type
== RMAP_DENY
) {
2646 /* Under a deny clause, match means it's finished. No
2647 * need to set next */
2649 "on-match next not supported under route-map deny\n");
2650 return CMD_WARNING_CONFIG_FAILED
;
2652 index
->exitpolicy
= RMAP_NEXT
;
2657 DEFUN (no_rmap_onmatch_next
,
2658 no_rmap_onmatch_next_cmd
,
2661 "Exit policy on matches\n"
2664 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2667 index
->exitpolicy
= RMAP_EXIT
;
2672 DEFUN (rmap_onmatch_goto
,
2673 rmap_onmatch_goto_cmd
,
2674 "on-match goto (1-65535)",
2675 "Exit policy on matches\n"
2676 "Goto Clause number\n"
2680 char *num
= argv_find(argv
, argc
, "(1-65535)", &idx
) ? argv
[idx
]->arg
2683 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2687 if (index
->type
== RMAP_DENY
) {
2688 /* Under a deny clause, match means it's finished. No
2689 * need to go anywhere */
2691 "on-match goto not supported under route-map deny\n");
2692 return CMD_WARNING_CONFIG_FAILED
;
2696 d
= strtoul(num
, NULL
, 10);
2698 d
= index
->pref
+ 1;
2700 if (d
<= index
->pref
) {
2701 /* Can't allow you to do that, Dave */
2702 vty_out(vty
, "can't jump backwards in route-maps\n");
2703 return CMD_WARNING_CONFIG_FAILED
;
2705 index
->exitpolicy
= RMAP_GOTO
;
2706 index
->nextpref
= d
;
2712 DEFUN (no_rmap_onmatch_goto
,
2713 no_rmap_onmatch_goto_cmd
,
2716 "Exit policy on matches\n"
2717 "Goto Clause number\n")
2719 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2722 index
->exitpolicy
= RMAP_EXIT
;
2727 /* Cisco/GNU Zebra compatibility aliases */
2729 DEFUN (rmap_continue
,
2731 "continue (1-65535)",
2732 "Continue on a different entry within the route-map\n"
2733 "Route-map entry sequence number\n")
2735 return rmap_onmatch_goto(self
, vty
, argc
, argv
);
2739 DEFUN (no_rmap_continue
,
2740 no_rmap_continue_cmd
,
2741 "no continue [(1-65535)]",
2743 "Continue on a different entry within the route-map\n"
2744 "Route-map entry sequence number\n")
2746 return no_rmap_onmatch_goto(self
, vty
, argc
, argv
);
2750 DEFUN (rmap_show_name
,
2752 "show route-map [WORD]",
2754 "route-map information\n"
2758 const char *name
= (argc
== 3) ? argv
[idx_word
]->arg
: NULL
;
2759 return vty_show_route_map(vty
, name
);
2765 "Jump to another Route-Map after match+set\n"
2766 "Target route-map name\n")
2769 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2770 const char *rmap
= argv
[idx_word
]->arg
;
2774 if (index
->nextrm
) {
2775 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED
,
2776 index
->nextrm
, index
->map
->name
);
2777 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
2779 index
->nextrm
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap
);
2781 /* Execute event hook. */
2782 route_map_upd8_dependency(RMAP_EVENT_CALL_ADDED
, index
->nextrm
,
2787 DEFUN (no_rmap_call
,
2791 "Jump to another Route-Map after match+set\n")
2793 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2795 if (index
->nextrm
) {
2796 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED
,
2797 index
->nextrm
, index
->map
->name
);
2798 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
2799 index
->nextrm
= NULL
;
2805 DEFUN (rmap_description
,
2806 rmap_description_cmd
,
2807 "description LINE...",
2808 "Route-map comment\n"
2809 "Comment describing this route-map rule\n")
2812 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2815 if (index
->description
)
2816 XFREE(MTYPE_TMP
, index
->description
);
2817 index
->description
= argv_concat(argv
, argc
, idx_line
);
2822 DEFUN (no_rmap_description
,
2823 no_rmap_description_cmd
,
2826 "Route-map comment\n")
2828 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2831 if (index
->description
)
2832 XFREE(MTYPE_TMP
, index
->description
);
2833 index
->description
= NULL
;
2838 /* Configuration write function. */
2839 static int route_map_config_write(struct vty
*vty
)
2841 struct route_map
*map
;
2842 struct route_map_index
*index
;
2843 struct route_map_rule
*rule
;
2847 for (map
= route_map_master
.head
; map
; map
= map
->next
)
2848 for (index
= map
->head
; index
; index
= index
->next
) {
2850 vty_out(vty
, "!\n");
2854 vty_out(vty
, "route-map %s %s %d\n", map
->name
,
2855 route_map_type_str(index
->type
), index
->pref
);
2857 if (index
->description
)
2858 vty_out(vty
, " description %s\n",
2859 index
->description
);
2861 for (rule
= index
->match_list
.head
; rule
;
2863 vty_out(vty
, " match %s %s\n", rule
->cmd
->str
,
2864 rule
->rule_str
? rule
->rule_str
: "");
2866 for (rule
= index
->set_list
.head
; rule
;
2868 vty_out(vty
, " set %s %s\n", rule
->cmd
->str
,
2869 rule
->rule_str
? rule
->rule_str
: "");
2871 vty_out(vty
, " call %s\n", index
->nextrm
);
2872 if (index
->exitpolicy
== RMAP_GOTO
)
2873 vty_out(vty
, " on-match goto %d\n",
2875 if (index
->exitpolicy
== RMAP_NEXT
)
2876 vty_out(vty
, " on-match next\n");
2883 /* Route map node structure. */
2884 static struct cmd_node rmap_node
= {RMAP_NODE
, "%s(config-route-map)# ", 1};
2886 /* Common route map rules */
2888 void *route_map_rule_tag_compile(const char *arg
)
2890 unsigned long int tmp
;
2895 tmp
= strtoul(arg
, &endptr
, 0);
2896 if (arg
[0] == '\0' || *endptr
!= '\0' || errno
|| tmp
> ROUTE_TAG_MAX
)
2899 tag
= XMALLOC(MTYPE_ROUTE_MAP_COMPILED
, sizeof(*tag
));
2905 void route_map_rule_tag_free(void *rule
)
2907 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
2910 void route_map_finish(void)
2914 vector_free(route_match_vec
);
2915 route_match_vec
= NULL
;
2916 vector_free(route_set_vec
);
2917 route_set_vec
= NULL
;
2920 * All protocols are setting these to NULL
2921 * by default on shutdown( route_map_finish )
2922 * Why are we making them do this work?
2924 route_map_master
.add_hook
= NULL
;
2925 route_map_master
.delete_hook
= NULL
;
2926 route_map_master
.event_hook
= NULL
;
2928 /* cleanup route_map */
2929 while (route_map_master
.head
) {
2930 struct route_map
*map
= route_map_master
.head
;
2931 map
->to_be_processed
= false;
2932 route_map_delete(map
);
2935 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
2936 hash_free(route_map_dep_hash
[i
]);
2937 route_map_dep_hash
[i
] = NULL
;
2940 hash_free(route_map_master_hash
);
2941 route_map_master_hash
= NULL
;
2944 static void rmap_autocomplete(vector comps
, struct cmd_token
*token
)
2946 struct route_map
*map
;
2948 for (map
= route_map_master
.head
; map
; map
= map
->next
)
2949 vector_set(comps
, XSTRDUP(MTYPE_COMPLETION
, map
->name
));
2952 static const struct cmd_variable_handler rmap_var_handlers
[] = {
2953 {/* "route-map WORD" */
2954 .varname
= "route_map",
2955 .completions
= rmap_autocomplete
},
2956 {.tokenname
= "ROUTEMAP_NAME", .completions
= rmap_autocomplete
},
2957 {.tokenname
= "RMAP_NAME", .completions
= rmap_autocomplete
},
2958 {.completions
= NULL
}};
2960 /* Initialization of route map vector. */
2961 void route_map_init(void)
2965 /* Make vector for match and set. */
2966 route_match_vec
= vector_init(1);
2967 route_set_vec
= vector_init(1);
2968 route_map_master_hash
=
2969 hash_create_size(8, route_map_hash_key_make
, route_map_hash_cmp
,
2970 "Route Map Master Hash");
2972 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++)
2973 route_map_dep_hash
[i
] = hash_create_size(
2974 8, route_map_dep_hash_make_key
, route_map_dep_hash_cmp
,
2975 "Route Map Dep Hash");
2977 cmd_variable_handler_register(rmap_var_handlers
);
2979 /* Install route map top node. */
2980 install_node(&rmap_node
, route_map_config_write
);
2982 /* Install route map commands. */
2983 install_default(RMAP_NODE
);
2984 install_element(CONFIG_NODE
, &route_map_cmd
);
2985 install_element(CONFIG_NODE
, &no_route_map_cmd
);
2986 install_element(CONFIG_NODE
, &no_route_map_all_cmd
);
2988 /* Install the on-match stuff */
2989 install_element(RMAP_NODE
, &route_map_cmd
);
2990 install_element(RMAP_NODE
, &rmap_onmatch_next_cmd
);
2991 install_element(RMAP_NODE
, &no_rmap_onmatch_next_cmd
);
2992 install_element(RMAP_NODE
, &rmap_onmatch_goto_cmd
);
2993 install_element(RMAP_NODE
, &no_rmap_onmatch_goto_cmd
);
2994 install_element(RMAP_NODE
, &rmap_continue_cmd
);
2995 install_element(RMAP_NODE
, &no_rmap_continue_cmd
);
2997 /* Install the continue stuff (ALIAS of on-match). */
2999 /* Install the call stuff. */
3000 install_element(RMAP_NODE
, &rmap_call_cmd
);
3001 install_element(RMAP_NODE
, &no_rmap_call_cmd
);
3003 /* Install description commands. */
3004 install_element(RMAP_NODE
, &rmap_description_cmd
);
3005 install_element(RMAP_NODE
, &no_rmap_description_cmd
);
3007 /* Install show command */
3008 install_element(ENABLE_NODE
, &rmap_show_name_cmd
);
3010 install_element(RMAP_NODE
, &match_interface_cmd
);
3011 install_element(RMAP_NODE
, &no_match_interface_cmd
);
3013 install_element(RMAP_NODE
, &match_ip_address_cmd
);
3014 install_element(RMAP_NODE
, &no_match_ip_address_cmd
);
3016 install_element(RMAP_NODE
, &match_ip_address_prefix_list_cmd
);
3017 install_element(RMAP_NODE
, &no_match_ip_address_prefix_list_cmd
);
3019 install_element(RMAP_NODE
, &match_ip_next_hop_cmd
);
3020 install_element(RMAP_NODE
, &no_match_ip_next_hop_cmd
);
3022 install_element(RMAP_NODE
, &match_ip_next_hop_prefix_list_cmd
);
3023 install_element(RMAP_NODE
, &no_match_ip_next_hop_prefix_list_cmd
);
3025 install_element(RMAP_NODE
, &match_ip_next_hop_type_cmd
);
3026 install_element(RMAP_NODE
, &no_match_ip_next_hop_type_cmd
);
3028 install_element(RMAP_NODE
, &match_ipv6_address_cmd
);
3029 install_element(RMAP_NODE
, &no_match_ipv6_address_cmd
);
3031 install_element(RMAP_NODE
, &match_ipv6_address_prefix_list_cmd
);
3032 install_element(RMAP_NODE
, &no_match_ipv6_address_prefix_list_cmd
);
3034 install_element(RMAP_NODE
, &match_ipv6_next_hop_type_cmd
);
3035 install_element(RMAP_NODE
, &no_match_ipv6_next_hop_type_cmd
);
3037 install_element(RMAP_NODE
, &match_metric_cmd
);
3038 install_element(RMAP_NODE
, &no_match_metric_cmd
);
3040 install_element(RMAP_NODE
, &match_tag_cmd
);
3041 install_element(RMAP_NODE
, &no_match_tag_cmd
);
3043 install_element(RMAP_NODE
, &set_ip_nexthop_cmd
);
3044 install_element(RMAP_NODE
, &no_set_ip_nexthop_cmd
);
3046 install_element(RMAP_NODE
, &set_ipv6_nexthop_local_cmd
);
3047 install_element(RMAP_NODE
, &no_set_ipv6_nexthop_local_cmd
);
3049 install_element(RMAP_NODE
, &set_metric_cmd
);
3050 install_element(RMAP_NODE
, &no_set_metric_cmd
);
3052 install_element(RMAP_NODE
, &set_tag_cmd
);
3053 install_element(RMAP_NODE
, &no_set_tag_cmd
);