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
);
1010 /* Unused route map details */
1011 static int vty_show_unused_route_map(struct vty
*vty
)
1013 struct list
*maplist
= list_new();
1014 struct listnode
*ln
;
1015 struct route_map
*map
;
1017 for (map
= route_map_master
.head
; map
; map
= map
->next
) {
1018 /* If use_count is zero, No protocol is using this routemap.
1019 * so adding to the list.
1021 if (!map
->use_count
)
1022 listnode_add(maplist
, map
);
1025 if (maplist
->count
> 0) {
1026 vty_out(vty
, "\n%s:\n", frr_protonameinst
);
1027 list_sort(maplist
, sort_route_map
);
1029 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
1030 vty_show_route_map_entry(vty
, map
);
1032 vty_out(vty
, "\n%s: None\n", frr_protonameinst
);
1035 list_delete(&maplist
);
1039 /* New route map allocation. Please note route map's name must be
1041 static struct route_map_index
*route_map_index_new(void)
1043 struct route_map_index
*new;
1045 new = XCALLOC(MTYPE_ROUTE_MAP_INDEX
, sizeof(struct route_map_index
));
1046 new->exitpolicy
= RMAP_EXIT
; /* Default to Cisco-style */
1047 QOBJ_REG(new, route_map_index
);
1051 /* Free route map index. */
1052 static void route_map_index_delete(struct route_map_index
*index
, int notify
)
1054 struct route_map_rule
*rule
;
1058 /* Free route match. */
1059 while ((rule
= index
->match_list
.head
) != NULL
)
1060 route_map_rule_delete(&index
->match_list
, rule
);
1062 /* Free route set. */
1063 while ((rule
= index
->set_list
.head
) != NULL
)
1064 route_map_rule_delete(&index
->set_list
, rule
);
1066 /* Remove index from route map list. */
1068 index
->next
->prev
= index
->prev
;
1070 index
->map
->tail
= index
->prev
;
1073 index
->prev
->next
= index
->next
;
1075 index
->map
->head
= index
->next
;
1077 /* Free 'char *nextrm' if not NULL */
1079 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
1081 /* Execute event hook. */
1082 if (route_map_master
.event_hook
&& notify
) {
1083 (*route_map_master
.event_hook
)(RMAP_EVENT_INDEX_DELETED
,
1085 route_map_notify_dependencies(index
->map
->name
,
1086 RMAP_EVENT_CALL_ADDED
);
1088 XFREE(MTYPE_ROUTE_MAP_INDEX
, index
);
1091 /* Lookup index from route map. */
1092 static struct route_map_index
*route_map_index_lookup(struct route_map
*map
,
1093 enum route_map_type type
,
1096 struct route_map_index
*index
;
1098 for (index
= map
->head
; index
; index
= index
->next
)
1099 if ((index
->type
== type
|| type
== RMAP_ANY
)
1100 && index
->pref
== pref
)
1105 /* Add new index to route map. */
1106 static struct route_map_index
*
1107 route_map_index_add(struct route_map
*map
, enum route_map_type type
, int pref
)
1109 struct route_map_index
*index
;
1110 struct route_map_index
*point
;
1112 /* Allocate new route map inex. */
1113 index
= route_map_index_new();
1118 /* Compare preference. */
1119 for (point
= map
->head
; point
; point
= point
->next
)
1120 if (point
->pref
>= pref
)
1123 if (map
->head
== NULL
) {
1124 map
->head
= map
->tail
= index
;
1125 } else if (point
== NULL
) {
1126 index
->prev
= map
->tail
;
1127 map
->tail
->next
= index
;
1129 } else if (point
== map
->head
) {
1130 index
->next
= map
->head
;
1131 map
->head
->prev
= index
;
1134 index
->next
= point
;
1135 index
->prev
= point
->prev
;
1137 point
->prev
->next
= index
;
1138 point
->prev
= index
;
1141 /* Execute event hook. */
1142 if (route_map_master
.event_hook
) {
1143 (*route_map_master
.event_hook
)(RMAP_EVENT_INDEX_ADDED
,
1145 route_map_notify_dependencies(map
->name
, RMAP_EVENT_CALL_ADDED
);
1150 /* Get route map index. */
1151 static struct route_map_index
*
1152 route_map_index_get(struct route_map
*map
, enum route_map_type type
, int pref
)
1154 struct route_map_index
*index
;
1156 index
= route_map_index_lookup(map
, RMAP_ANY
, pref
);
1157 if (index
&& index
->type
!= type
) {
1158 /* Delete index from route map. */
1159 route_map_index_delete(index
, 1);
1163 index
= route_map_index_add(map
, type
, pref
);
1167 /* New route map rule */
1168 static struct route_map_rule
*route_map_rule_new(void)
1170 struct route_map_rule
*new;
1172 new = XCALLOC(MTYPE_ROUTE_MAP_RULE
, sizeof(struct route_map_rule
));
1176 /* Install rule command to the match list. */
1177 void route_map_install_match(struct route_map_rule_cmd
*cmd
)
1179 vector_set(route_match_vec
, cmd
);
1182 /* Install rule command to the set list. */
1183 void route_map_install_set(struct route_map_rule_cmd
*cmd
)
1185 vector_set(route_set_vec
, cmd
);
1188 /* Lookup rule command from match list. */
1189 static struct route_map_rule_cmd
*route_map_lookup_match(const char *name
)
1192 struct route_map_rule_cmd
*rule
;
1194 for (i
= 0; i
< vector_active(route_match_vec
); i
++)
1195 if ((rule
= vector_slot(route_match_vec
, i
)) != NULL
)
1196 if (strcmp(rule
->str
, name
) == 0)
1201 /* Lookup rule command from set list. */
1202 static struct route_map_rule_cmd
*route_map_lookup_set(const char *name
)
1205 struct route_map_rule_cmd
*rule
;
1207 for (i
= 0; i
< vector_active(route_set_vec
); i
++)
1208 if ((rule
= vector_slot(route_set_vec
, i
)) != NULL
)
1209 if (strcmp(rule
->str
, name
) == 0)
1214 /* Add match and set rule to rule list. */
1215 static void route_map_rule_add(struct route_map_rule_list
*list
,
1216 struct route_map_rule
*rule
)
1219 rule
->prev
= list
->tail
;
1221 list
->tail
->next
= rule
;
1227 /* Delete rule from rule list. */
1228 static void route_map_rule_delete(struct route_map_rule_list
*list
,
1229 struct route_map_rule
*rule
)
1231 if (rule
->cmd
->func_free
)
1232 (*rule
->cmd
->func_free
)(rule
->value
);
1235 XFREE(MTYPE_ROUTE_MAP_RULE_STR
, rule
->rule_str
);
1238 rule
->next
->prev
= rule
->prev
;
1240 list
->tail
= rule
->prev
;
1242 rule
->prev
->next
= rule
->next
;
1244 list
->head
= rule
->next
;
1246 XFREE(MTYPE_ROUTE_MAP_RULE
, rule
);
1249 /* strcmp wrapper function which don't crush even argument is NULL. */
1250 static int rulecmp(const char *dst
, const char *src
)
1261 return strcmp(dst
, src
);
1266 /* Use this to return the already specified argument for this match. This is
1267 * useful to get the specified argument with a route map match rule when the
1268 * rule is being deleted and the argument is not provided.
1270 const char *route_map_get_match_arg(struct route_map_index
*index
,
1271 const char *match_name
)
1273 struct route_map_rule
*rule
;
1274 struct route_map_rule_cmd
*cmd
;
1276 /* First lookup rule for add match statement. */
1277 cmd
= route_map_lookup_match(match_name
);
1281 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1282 if (rule
->cmd
== cmd
&& rule
->rule_str
!= NULL
)
1283 return (rule
->rule_str
);
1288 /* Add match statement to route map. */
1289 int route_map_add_match(struct route_map_index
*index
, const char *match_name
,
1290 const char *match_arg
)
1292 struct route_map_rule
*rule
;
1293 struct route_map_rule
*next
;
1294 struct route_map_rule_cmd
*cmd
;
1298 /* First lookup rule for add match statement. */
1299 cmd
= route_map_lookup_match(match_name
);
1301 return RMAP_RULE_MISSING
;
1303 /* Next call compile function for this match statement. */
1304 if (cmd
->func_compile
) {
1305 compile
= (*cmd
->func_compile
)(match_arg
);
1306 if (compile
== NULL
)
1307 return RMAP_COMPILE_ERROR
;
1311 /* If argument is completely same ignore it. */
1312 for (rule
= index
->match_list
.head
; rule
; rule
= next
) {
1314 if (rule
->cmd
== cmd
) {
1315 route_map_rule_delete(&index
->match_list
, rule
);
1320 /* Add new route map match rule. */
1321 rule
= route_map_rule_new();
1323 rule
->value
= compile
;
1325 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, match_arg
);
1327 rule
->rule_str
= NULL
;
1329 /* Add new route match rule to linked list. */
1330 route_map_rule_add(&index
->match_list
, rule
);
1332 /* Execute event hook. */
1333 if (route_map_master
.event_hook
) {
1334 (*route_map_master
.event_hook
)(
1335 replaced
? RMAP_EVENT_MATCH_REPLACED
1336 : RMAP_EVENT_MATCH_ADDED
,
1338 route_map_notify_dependencies(index
->map
->name
,
1339 RMAP_EVENT_CALL_ADDED
);
1342 return RMAP_COMPILE_SUCCESS
;
1345 /* Delete specified route match rule. */
1346 int route_map_delete_match(struct route_map_index
*index
,
1347 const char *match_name
, const char *match_arg
)
1349 struct route_map_rule
*rule
;
1350 struct route_map_rule_cmd
*cmd
;
1352 cmd
= route_map_lookup_match(match_name
);
1356 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1357 if (rule
->cmd
== cmd
&& (rulecmp(rule
->rule_str
, match_arg
) == 0
1358 || match_arg
== NULL
)) {
1359 route_map_rule_delete(&index
->match_list
, rule
);
1360 /* Execute event hook. */
1361 if (route_map_master
.event_hook
) {
1362 (*route_map_master
.event_hook
)(
1363 RMAP_EVENT_MATCH_DELETED
,
1365 route_map_notify_dependencies(
1367 RMAP_EVENT_CALL_ADDED
);
1371 /* Can't find matched rule. */
1375 /* Add route-map set statement to the route map. */
1376 int route_map_add_set(struct route_map_index
*index
, const char *set_name
,
1377 const char *set_arg
)
1379 struct route_map_rule
*rule
;
1380 struct route_map_rule
*next
;
1381 struct route_map_rule_cmd
*cmd
;
1385 cmd
= route_map_lookup_set(set_name
);
1387 return RMAP_RULE_MISSING
;
1389 /* Next call compile function for this match statement. */
1390 if (cmd
->func_compile
) {
1391 compile
= (*cmd
->func_compile
)(set_arg
);
1392 if (compile
== NULL
)
1393 return RMAP_COMPILE_ERROR
;
1397 /* Add by WJL. if old set command of same kind exist, delete it first
1398 to ensure only one set command of same kind exist under a
1400 for (rule
= index
->set_list
.head
; rule
; rule
= next
) {
1402 if (rule
->cmd
== cmd
) {
1403 route_map_rule_delete(&index
->set_list
, rule
);
1408 /* Add new route map match rule. */
1409 rule
= route_map_rule_new();
1411 rule
->value
= compile
;
1413 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, set_arg
);
1415 rule
->rule_str
= NULL
;
1417 /* Add new route match rule to linked list. */
1418 route_map_rule_add(&index
->set_list
, rule
);
1420 /* Execute event hook. */
1421 if (route_map_master
.event_hook
) {
1422 (*route_map_master
.event_hook
)(replaced
1423 ? RMAP_EVENT_SET_REPLACED
1424 : RMAP_EVENT_SET_ADDED
,
1426 route_map_notify_dependencies(index
->map
->name
,
1427 RMAP_EVENT_CALL_ADDED
);
1429 return RMAP_COMPILE_SUCCESS
;
1432 /* Delete route map set rule. */
1433 int route_map_delete_set(struct route_map_index
*index
, const char *set_name
,
1434 const char *set_arg
)
1436 struct route_map_rule
*rule
;
1437 struct route_map_rule_cmd
*cmd
;
1439 cmd
= route_map_lookup_set(set_name
);
1443 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
1444 if ((rule
->cmd
== cmd
) && (rulecmp(rule
->rule_str
, set_arg
) == 0
1445 || set_arg
== NULL
)) {
1446 route_map_rule_delete(&index
->set_list
, rule
);
1447 /* Execute event hook. */
1448 if (route_map_master
.event_hook
) {
1449 (*route_map_master
.event_hook
)(
1450 RMAP_EVENT_SET_DELETED
,
1452 route_map_notify_dependencies(
1454 RMAP_EVENT_CALL_ADDED
);
1458 /* Can't find matched rule. */
1462 /* Apply route map's each index to the object.
1464 The matrix for a route-map looks like this:
1465 (note, this includes the description for the "NEXT"
1466 and "GOTO" frobs now
1470 permit action | cont
1472 ------------------+---------------
1478 -Apply Set statements, accept route
1479 -If Call statement is present jump to the specified route-map, if it
1480 denies the route we finish.
1481 -If NEXT is specified, goto NEXT statement
1482 -If GOTO is specified, goto the first clause where pref > nextpref
1483 -If nothing is specified, do as Cisco and finish
1485 -Route is denied by route-map.
1489 If we get no matches after we've processed all updates, then the route
1492 Some notes on the new "CALL", "NEXT" and "GOTO"
1493 call WORD - If this clause is matched, then the set statements
1494 are executed and then we jump to route-map 'WORD'. If
1495 this route-map denies the route, we finish, in other
1497 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
1498 on-match next - If this clause is matched, then the set statements
1499 are executed and then we drop through to the next clause
1500 on-match goto n - If this clause is matched, then the set statments
1501 are executed and then we goto the nth clause, or the
1502 first clause greater than this. In order to ensure
1503 route-maps *always* exit, you cannot jump backwards.
1506 We need to make sure our route-map processing matches the above
1509 static route_map_result_t
1510 route_map_apply_match(struct route_map_rule_list
*match_list
,
1511 const struct prefix
*prefix
, route_map_object_t type
,
1514 route_map_result_t ret
= RMAP_NOMATCH
;
1515 struct route_map_rule
*match
;
1518 /* Check all match rule and if there is no match rule, go to the
1520 if (!match_list
->head
)
1523 for (match
= match_list
->head
; match
; match
= match
->next
) {
1524 /* Try each match statement in turn, If any do not
1526 RMAP_MATCH, return, otherwise continue on to next
1528 statement. All match statements must match for
1531 ret
= (*match
->cmd
->func_apply
)(match
->value
, prefix
,
1533 if (ret
!= RMAP_MATCH
)
1540 /* Apply route map to the object. */
1541 route_map_result_t
route_map_apply(struct route_map
*map
,
1542 const struct prefix
*prefix
,
1543 route_map_object_t type
, void *object
)
1545 static int recursion
= 0;
1547 struct route_map_index
*index
;
1548 struct route_map_rule
*set
;
1550 if (recursion
> RMAP_RECURSION_LIMIT
) {
1552 EC_LIB_RMAP_RECURSION_LIMIT
,
1553 "route-map recursion limit (%d) reached, discarding route",
1554 RMAP_RECURSION_LIMIT
);
1556 return RMAP_DENYMATCH
;
1560 return RMAP_DENYMATCH
;
1563 for (index
= map
->head
; index
; index
= index
->next
) {
1564 /* Apply this index. */
1566 ret
= route_map_apply_match(&index
->match_list
, prefix
, type
,
1569 /* Now we apply the matrix from above */
1570 if (ret
== RMAP_NOMATCH
)
1571 /* 'cont' from matrix - continue to next route-map
1574 else if (ret
== RMAP_MATCH
) {
1575 if (index
->type
== RMAP_PERMIT
)
1578 /* permit+match must execute sets */
1579 for (set
= index
->set_list
.head
; set
;
1581 ret
= (*set
->cmd
->func_apply
)(
1582 set
->value
, prefix
, type
,
1585 /* Call another route-map if available */
1586 if (index
->nextrm
) {
1587 struct route_map
*nextrm
=
1588 route_map_lookup_by_name(
1591 if (nextrm
) /* Target route-map found,
1595 ret
= route_map_apply(
1596 nextrm
, prefix
, type
,
1601 /* If nextrm returned 'deny', finish. */
1602 if (ret
== RMAP_DENYMATCH
)
1606 switch (index
->exitpolicy
) {
1612 /* Find the next clause to jump to */
1613 struct route_map_index
*next
=
1615 int nextpref
= index
->nextpref
;
1617 while (next
&& next
->pref
< nextpref
) {
1622 /* No clauses match! */
1627 } else if (index
->type
== RMAP_DENY
)
1630 return RMAP_DENYMATCH
;
1634 /* Finally route-map does not match at all. */
1635 return RMAP_DENYMATCH
;
1638 void route_map_add_hook(void (*func
)(const char *))
1640 route_map_master
.add_hook
= func
;
1643 void route_map_delete_hook(void (*func
)(const char *))
1645 route_map_master
.delete_hook
= func
;
1648 void route_map_event_hook(void (*func
)(route_map_event_t
, const char *))
1650 route_map_master
.event_hook
= func
;
1653 /* Routines for route map dependency lists and dependency processing */
1654 static bool route_map_rmap_hash_cmp(const void *p1
, const void *p2
)
1656 return (strcmp((const char *)p1
, (const char *)p2
) == 0);
1659 static bool route_map_dep_hash_cmp(const void *p1
, const void *p2
)
1662 return (strcmp(((const struct route_map_dep
*)p1
)->dep_name
,
1667 static void route_map_clear_reference(struct hash_bucket
*bucket
, void *arg
)
1669 struct route_map_dep
*dep
= (struct route_map_dep
*)bucket
->data
;
1674 (char *)hash_release(dep
->dep_rmap_hash
, (void *)arg
);
1676 XFREE(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
1678 if (!dep
->dep_rmap_hash
->count
) {
1679 dep
= hash_release(dep
->this_hash
,
1680 (void *)dep
->dep_name
);
1681 hash_free(dep
->dep_rmap_hash
);
1682 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
1683 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
1688 static void route_map_clear_all_references(char *rmap_name
)
1692 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
1693 hash_iterate(route_map_dep_hash
[i
], route_map_clear_reference
,
1698 static void *route_map_dep_hash_alloc(void *p
)
1700 char *dep_name
= (char *)p
;
1701 struct route_map_dep
*dep_entry
;
1703 dep_entry
= XCALLOC(MTYPE_ROUTE_MAP_DEP
, sizeof(struct route_map_dep
));
1704 dep_entry
->dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1705 dep_entry
->dep_rmap_hash
=
1706 hash_create_size(8, route_map_dep_hash_make_key
,
1707 route_map_rmap_hash_cmp
, "Route Map Dep Hash");
1708 dep_entry
->this_hash
= NULL
;
1710 return ((void *)dep_entry
);
1713 static void *route_map_name_hash_alloc(void *p
)
1715 return ((void *)XSTRDUP(MTYPE_ROUTE_MAP_NAME
, (const char *)p
));
1718 static unsigned int route_map_dep_hash_make_key(void *p
)
1720 return (string_hash_make((char *)p
));
1723 static void route_map_print_dependency(struct hash_bucket
*bucket
, void *data
)
1725 char *rmap_name
= (char *)bucket
->data
;
1726 char *dep_name
= (char *)data
;
1728 zlog_debug("%s: Dependency for %s: %s", __FUNCTION__
, dep_name
,
1732 static int route_map_dep_update(struct hash
*dephash
, const char *dep_name
,
1733 const char *rmap_name
, route_map_event_t type
)
1735 struct route_map_dep
*dep
= NULL
;
1737 char *dname
, *rname
;
1740 dname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1741 rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
1744 case RMAP_EVENT_PLIST_ADDED
:
1745 case RMAP_EVENT_CLIST_ADDED
:
1746 case RMAP_EVENT_ECLIST_ADDED
:
1747 case RMAP_EVENT_ASLIST_ADDED
:
1748 case RMAP_EVENT_LLIST_ADDED
:
1749 case RMAP_EVENT_CALL_ADDED
:
1750 case RMAP_EVENT_FILTER_ADDED
:
1752 zlog_debug("%s: Adding dependency for %s in %s",
1753 __FUNCTION__
, dep_name
, rmap_name
);
1754 dep
= (struct route_map_dep
*)hash_get(
1755 dephash
, dname
, route_map_dep_hash_alloc
);
1761 if (!dep
->this_hash
)
1762 dep
->this_hash
= dephash
;
1764 hash_get(dep
->dep_rmap_hash
, rname
, route_map_name_hash_alloc
);
1766 case RMAP_EVENT_PLIST_DELETED
:
1767 case RMAP_EVENT_CLIST_DELETED
:
1768 case RMAP_EVENT_ECLIST_DELETED
:
1769 case RMAP_EVENT_ASLIST_DELETED
:
1770 case RMAP_EVENT_LLIST_DELETED
:
1771 case RMAP_EVENT_CALL_DELETED
:
1772 case RMAP_EVENT_FILTER_DELETED
:
1774 zlog_debug("%s: Deleting dependency for %s in %s",
1775 __FUNCTION__
, dep_name
, rmap_name
);
1776 dep
= (struct route_map_dep
*)hash_get(dephash
, dname
, NULL
);
1781 ret_map_name
= (char *)hash_release(dep
->dep_rmap_hash
, rname
);
1783 XFREE(MTYPE_ROUTE_MAP_NAME
, ret_map_name
);
1785 if (!dep
->dep_rmap_hash
->count
) {
1786 dep
= hash_release(dephash
, dname
);
1787 hash_free(dep
->dep_rmap_hash
);
1788 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
1789 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
1799 hash_iterate(dep
->dep_rmap_hash
,
1800 route_map_print_dependency
, dname
);
1804 XFREE(MTYPE_ROUTE_MAP_NAME
, rname
);
1805 XFREE(MTYPE_ROUTE_MAP_NAME
, dname
);
1809 static struct hash
*route_map_get_dep_hash(route_map_event_t event
)
1811 struct hash
*upd8_hash
= NULL
;
1814 case RMAP_EVENT_PLIST_ADDED
:
1815 case RMAP_EVENT_PLIST_DELETED
:
1816 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_PLIST
];
1818 case RMAP_EVENT_CLIST_ADDED
:
1819 case RMAP_EVENT_CLIST_DELETED
:
1820 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_CLIST
];
1822 case RMAP_EVENT_ECLIST_ADDED
:
1823 case RMAP_EVENT_ECLIST_DELETED
:
1824 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ECLIST
];
1826 case RMAP_EVENT_ASLIST_ADDED
:
1827 case RMAP_EVENT_ASLIST_DELETED
:
1828 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ASPATH
];
1830 case RMAP_EVENT_LLIST_ADDED
:
1831 case RMAP_EVENT_LLIST_DELETED
:
1832 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_LCLIST
];
1834 case RMAP_EVENT_CALL_ADDED
:
1835 case RMAP_EVENT_CALL_DELETED
:
1836 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_RMAP
];
1838 case RMAP_EVENT_FILTER_ADDED
:
1839 case RMAP_EVENT_FILTER_DELETED
:
1840 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_FILTER
];
1849 static void route_map_process_dependency(struct hash_bucket
*bucket
, void *data
)
1851 char *rmap_name
= (char *)bucket
->data
;
1852 route_map_event_t type
= (route_map_event_t
)(ptrdiff_t)data
;
1855 zlog_debug("%s: Notifying %s of dependency",
1856 __FUNCTION__
, rmap_name
);
1857 if (route_map_master
.event_hook
)
1858 (*route_map_master
.event_hook
)(type
, rmap_name
);
1861 void route_map_upd8_dependency(route_map_event_t type
, const char *arg
,
1862 const char *rmap_name
)
1864 struct hash
*upd8_hash
= NULL
;
1866 if ((upd8_hash
= route_map_get_dep_hash(type
))) {
1867 route_map_dep_update(upd8_hash
, arg
, rmap_name
, type
);
1869 if (type
== RMAP_EVENT_CALL_ADDED
) {
1871 if (route_map_master
.add_hook
)
1872 (*route_map_master
.add_hook
)(rmap_name
);
1873 } else if (type
== RMAP_EVENT_CALL_DELETED
) {
1875 if (route_map_master
.delete_hook
)
1876 (*route_map_master
.delete_hook
)(rmap_name
);
1881 void route_map_notify_dependencies(const char *affected_name
,
1882 route_map_event_t event
)
1884 struct route_map_dep
*dep
;
1885 struct hash
*upd8_hash
;
1891 name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, affected_name
);
1893 if ((upd8_hash
= route_map_get_dep_hash(event
)) == NULL
) {
1894 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
1898 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, name
, NULL
);
1900 if (!dep
->this_hash
)
1901 dep
->this_hash
= upd8_hash
;
1903 hash_iterate(dep
->dep_rmap_hash
, route_map_process_dependency
,
1907 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
1911 /* VTY related functions. */
1912 DEFUN (match_interface
,
1913 match_interface_cmd
,
1914 "match interface WORD",
1916 "match first hop interface of route\n"
1920 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1922 if (rmap_match_set_hook
.match_interface
)
1923 return rmap_match_set_hook
.match_interface(
1924 vty
, index
, "interface", argv
[idx_word
]->arg
,
1925 RMAP_EVENT_MATCH_ADDED
);
1929 DEFUN (no_match_interface
,
1930 no_match_interface_cmd
,
1931 "no match interface [WORD]",
1934 "Match first hop interface of route\n"
1937 char *iface
= (argc
== 4) ? argv
[3]->arg
: NULL
;
1938 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1940 if (rmap_match_set_hook
.no_match_interface
)
1941 return rmap_match_set_hook
.no_match_interface(
1942 vty
, index
, "interface", iface
,
1943 RMAP_EVENT_MATCH_DELETED
);
1948 DEFUN (match_ip_address
,
1949 match_ip_address_cmd
,
1950 "match ip address <(1-199)|(1300-2699)|WORD>",
1953 "Match address of route\n"
1954 "IP access-list number\n"
1955 "IP access-list number (expanded range)\n"
1956 "IP Access-list name\n")
1959 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1961 if (rmap_match_set_hook
.match_ip_address
)
1962 return rmap_match_set_hook
.match_ip_address(
1963 vty
, index
, "ip address", argv
[idx_acl
]->arg
,
1964 RMAP_EVENT_FILTER_ADDED
);
1969 DEFUN (no_match_ip_address
,
1970 no_match_ip_address_cmd
,
1971 "no match ip address [<(1-199)|(1300-2699)|WORD>]",
1975 "Match address of route\n"
1976 "IP access-list number\n"
1977 "IP access-list number (expanded range)\n"
1978 "IP Access-list name\n")
1981 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1983 if (rmap_match_set_hook
.no_match_ip_address
) {
1984 if (argc
<= idx_word
)
1985 return rmap_match_set_hook
.no_match_ip_address(
1986 vty
, index
, "ip address", NULL
,
1987 RMAP_EVENT_FILTER_DELETED
);
1988 return rmap_match_set_hook
.no_match_ip_address(
1989 vty
, index
, "ip address", argv
[idx_word
]->arg
,
1990 RMAP_EVENT_FILTER_DELETED
);
1996 DEFUN (match_ip_address_prefix_list
,
1997 match_ip_address_prefix_list_cmd
,
1998 "match ip address prefix-list WORD",
2001 "Match 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
.match_ip_address_prefix_list
)
2009 return rmap_match_set_hook
.match_ip_address_prefix_list(
2010 vty
, index
, "ip address prefix-list",
2011 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
2016 DEFUN (no_match_ip_address_prefix_list
,
2017 no_match_ip_address_prefix_list_cmd
,
2018 "no match ip address prefix-list [WORD]",
2022 "Match address of route\n"
2023 "Match entries of prefix-lists\n"
2024 "IP prefix-list name\n")
2027 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2029 if (rmap_match_set_hook
.no_match_ip_address_prefix_list
) {
2030 if (argc
<= idx_word
)
2031 return rmap_match_set_hook
2032 .no_match_ip_address_prefix_list(
2033 vty
, index
, "ip address prefix-list",
2034 NULL
, RMAP_EVENT_PLIST_DELETED
);
2035 return rmap_match_set_hook
.no_match_ip_address_prefix_list(
2036 vty
, index
, "ip address prefix-list",
2037 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2043 DEFUN (match_ip_next_hop
,
2044 match_ip_next_hop_cmd
,
2045 "match ip next-hop <(1-199)|(1300-2699)|WORD>",
2048 "Match next-hop address of route\n"
2049 "IP access-list number\n"
2050 "IP access-list number (expanded range)\n"
2051 "IP Access-list name\n")
2054 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2056 if (rmap_match_set_hook
.match_ip_next_hop
)
2057 return rmap_match_set_hook
.match_ip_next_hop(
2058 vty
, index
, "ip next-hop", argv
[idx_acl
]->arg
,
2059 RMAP_EVENT_FILTER_ADDED
);
2064 DEFUN (no_match_ip_next_hop
,
2065 no_match_ip_next_hop_cmd
,
2066 "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
2070 "Match next-hop address of route\n"
2071 "IP access-list number\n"
2072 "IP access-list number (expanded range)\n"
2073 "IP Access-list name\n")
2076 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2078 if (rmap_match_set_hook
.no_match_ip_next_hop
) {
2079 if (argc
<= idx_word
)
2080 return rmap_match_set_hook
.no_match_ip_next_hop(
2081 vty
, index
, "ip next-hop", NULL
,
2082 RMAP_EVENT_FILTER_DELETED
);
2083 return rmap_match_set_hook
.no_match_ip_next_hop(
2084 vty
, index
, "ip next-hop", argv
[idx_word
]->arg
,
2085 RMAP_EVENT_FILTER_DELETED
);
2091 DEFUN (match_ip_next_hop_prefix_list
,
2092 match_ip_next_hop_prefix_list_cmd
,
2093 "match ip next-hop prefix-list WORD",
2096 "Match next-hop address of route\n"
2097 "Match entries of prefix-lists\n"
2098 "IP prefix-list name\n")
2101 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2103 if (rmap_match_set_hook
.match_ip_next_hop_prefix_list
)
2104 return rmap_match_set_hook
.match_ip_next_hop_prefix_list(
2105 vty
, index
, "ip next-hop prefix-list",
2106 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
2110 DEFUN (no_match_ip_next_hop_prefix_list
,
2111 no_match_ip_next_hop_prefix_list_cmd
,
2112 "no match ip next-hop prefix-list [WORD]",
2116 "Match next-hop address of route\n"
2117 "Match entries of prefix-lists\n"
2118 "IP prefix-list name\n")
2121 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2123 if (rmap_match_set_hook
.no_match_ip_next_hop
) {
2124 if (argc
<= idx_word
)
2125 return rmap_match_set_hook
.no_match_ip_next_hop(
2126 vty
, index
, "ip next-hop prefix-list", NULL
,
2127 RMAP_EVENT_PLIST_DELETED
);
2128 return rmap_match_set_hook
.no_match_ip_next_hop(
2129 vty
, index
, "ip next-hop prefix-list",
2130 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2135 DEFUN(match_ip_next_hop_type
, match_ip_next_hop_type_cmd
,
2136 "match ip next-hop type <blackhole>",
2138 "Match next-hop address of route\n"
2139 "Match entries by type\n"
2143 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2145 if (rmap_match_set_hook
.match_ip_next_hop_type
)
2146 return rmap_match_set_hook
.match_ip_next_hop_type(
2147 vty
, index
, "ip next-hop type", argv
[idx_word
]->arg
,
2148 RMAP_EVENT_MATCH_ADDED
);
2152 DEFUN(no_match_ip_next_hop_type
, no_match_ip_next_hop_type_cmd
,
2153 "no match ip next-hop type [<blackhole>]",
2154 NO_STR MATCH_STR IP_STR
2155 "Match next-hop address of route\n"
2156 "Match entries by type\n"
2160 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2162 if (rmap_match_set_hook
.no_match_ip_next_hop
) {
2163 if (argc
<= idx_word
)
2164 return rmap_match_set_hook
.no_match_ip_next_hop(
2165 vty
, index
, "ip next-hop type", NULL
,
2166 RMAP_EVENT_MATCH_DELETED
);
2167 return rmap_match_set_hook
.no_match_ip_next_hop(
2168 vty
, index
, "ip next-hop type", argv
[idx_word
]->arg
,
2169 RMAP_EVENT_MATCH_DELETED
);
2175 DEFUN (match_ipv6_address
,
2176 match_ipv6_address_cmd
,
2177 "match ipv6 address WORD",
2180 "Match IPv6 address of route\n"
2181 "IPv6 access-list name\n")
2184 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2186 if (rmap_match_set_hook
.match_ipv6_address
)
2187 return rmap_match_set_hook
.match_ipv6_address(
2188 vty
, index
, "ipv6 address", argv
[idx_word
]->arg
,
2189 RMAP_EVENT_FILTER_ADDED
);
2193 DEFUN (no_match_ipv6_address
,
2194 no_match_ipv6_address_cmd
,
2195 "no match ipv6 address WORD",
2199 "Match IPv6 address of route\n"
2200 "IPv6 access-list name\n")
2203 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2205 if (rmap_match_set_hook
.no_match_ipv6_address
)
2206 return rmap_match_set_hook
.no_match_ipv6_address(
2207 vty
, index
, "ipv6 address", argv
[idx_word
]->arg
,
2208 RMAP_EVENT_FILTER_DELETED
);
2213 DEFUN (match_ipv6_address_prefix_list
,
2214 match_ipv6_address_prefix_list_cmd
,
2215 "match ipv6 address prefix-list WORD",
2218 "Match address of route\n"
2219 "Match entries of prefix-lists\n"
2220 "IP prefix-list name\n")
2223 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2225 if (rmap_match_set_hook
.match_ipv6_address_prefix_list
)
2226 return rmap_match_set_hook
.match_ipv6_address_prefix_list(
2227 vty
, index
, "ipv6 address prefix-list",
2228 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
2232 DEFUN (no_match_ipv6_address_prefix_list
,
2233 no_match_ipv6_address_prefix_list_cmd
,
2234 "no match ipv6 address prefix-list WORD",
2238 "Match address of route\n"
2239 "Match entries of prefix-lists\n"
2240 "IP prefix-list name\n")
2243 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2245 if (rmap_match_set_hook
.no_match_ipv6_address_prefix_list
)
2246 return rmap_match_set_hook
.no_match_ipv6_address_prefix_list(
2247 vty
, index
, "ipv6 address prefix-list",
2248 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2252 DEFUN(match_ipv6_next_hop_type
, match_ipv6_next_hop_type_cmd
,
2253 "match ipv6 next-hop type <blackhole>",
2255 "Match address of route\n"
2256 "Match entries by type\n"
2260 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2262 if (rmap_match_set_hook
.match_ipv6_next_hop_type
)
2263 return rmap_match_set_hook
.match_ipv6_next_hop_type(
2264 vty
, index
, "ipv6 next-hop type", argv
[idx_word
]->arg
,
2265 RMAP_EVENT_MATCH_ADDED
);
2269 DEFUN(no_match_ipv6_next_hop_type
, no_match_ipv6_next_hop_type_cmd
,
2270 "no match ipv6 next-hop type [<blackhole>]",
2271 NO_STR MATCH_STR IPV6_STR
2272 "Match address of route\n"
2273 "Match entries by type\n"
2277 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2279 if (rmap_match_set_hook
.no_match_ipv6_next_hop_type
)
2280 return rmap_match_set_hook
.no_match_ipv6_next_hop_type(
2281 vty
, index
, "ipv6 next-hop type",
2282 (argc
<= idx_word
) ? NULL
: argv
[idx_word
]->arg
,
2283 RMAP_EVENT_MATCH_DELETED
);
2287 DEFUN (match_metric
,
2289 "match metric (0-4294967295)",
2291 "Match metric of route\n"
2295 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2297 if (rmap_match_set_hook
.match_metric
)
2298 return rmap_match_set_hook
.match_metric(vty
, index
, "metric",
2299 argv
[idx_number
]->arg
,
2300 RMAP_EVENT_MATCH_ADDED
);
2305 DEFUN (no_match_metric
,
2306 no_match_metric_cmd
,
2307 "no match metric [(0-4294967295)]",
2310 "Match metric of route\n"
2314 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2316 if (rmap_match_set_hook
.no_match_metric
) {
2317 if (argc
<= idx_number
)
2318 return rmap_match_set_hook
.no_match_metric(
2319 vty
, index
, "metric", NULL
,
2320 RMAP_EVENT_MATCH_DELETED
);
2321 return rmap_match_set_hook
.no_match_metric(
2322 vty
, index
, "metric", argv
[idx_number
]->arg
,
2323 RMAP_EVENT_MATCH_DELETED
);
2331 "match tag (1-4294967295)",
2333 "Match tag of route\n"
2337 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2339 if (rmap_match_set_hook
.match_tag
)
2340 return rmap_match_set_hook
.match_tag(vty
, index
, "tag",
2341 argv
[idx_number
]->arg
,
2342 RMAP_EVENT_MATCH_ADDED
);
2347 DEFUN (no_match_tag
,
2349 "no match tag [(1-4294967295)]",
2352 "Match tag of route\n"
2355 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2358 char *arg
= argv_find(argv
, argc
, "(1-4294967295)", &idx
)
2362 if (rmap_match_set_hook
.no_match_tag
)
2363 return rmap_match_set_hook
.no_match_tag(
2364 vty
, index
, "tag", arg
, RMAP_EVENT_MATCH_DELETED
);
2369 DEFUN (set_ip_nexthop
,
2371 "set ip next-hop A.B.C.D",
2374 "Next hop address\n"
2375 "IP address of next hop\n")
2380 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2382 ret
= str2sockunion(argv
[idx_ipv4
]->arg
, &su
);
2384 vty_out(vty
, "%% Malformed nexthop address\n");
2385 return CMD_WARNING_CONFIG_FAILED
;
2387 if (su
.sin
.sin_addr
.s_addr
== 0
2388 || IPV4_CLASS_DE(ntohl(su
.sin
.sin_addr
.s_addr
))) {
2390 "%% nexthop address cannot be 0.0.0.0, multicast or reserved\n");
2391 return CMD_WARNING_CONFIG_FAILED
;
2394 if (rmap_match_set_hook
.set_ip_nexthop
)
2395 return rmap_match_set_hook
.set_ip_nexthop(
2396 vty
, index
, "ip next-hop", argv
[idx_ipv4
]->arg
);
2401 DEFUN (no_set_ip_nexthop
,
2402 no_set_ip_nexthop_cmd
,
2403 "no set ip next-hop [A.B.C.D]",
2407 "Next hop address\n"
2408 "IP address of next hop\n")
2411 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2412 const char *arg
= NULL
;
2414 if (argv_find(argv
, argc
, "A.B.C.D", &idx
))
2415 arg
= argv
[idx
]->arg
;
2417 if (rmap_match_set_hook
.no_set_ip_nexthop
)
2418 return rmap_match_set_hook
.no_set_ip_nexthop(
2419 vty
, index
, "ip next-hop", arg
);
2425 DEFUN (set_ipv6_nexthop_local
,
2426 set_ipv6_nexthop_local_cmd
,
2427 "set ipv6 next-hop local X:X::X:X",
2430 "IPv6 next-hop address\n"
2431 "IPv6 local address\n"
2432 "IPv6 address of next hop\n")
2435 struct in6_addr addr
;
2437 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2439 ret
= inet_pton(AF_INET6
, argv
[idx_ipv6
]->arg
, &addr
);
2441 vty_out(vty
, "%% Malformed nexthop address\n");
2442 return CMD_WARNING_CONFIG_FAILED
;
2444 if (!IN6_IS_ADDR_LINKLOCAL(&addr
)) {
2445 vty_out(vty
, "%% Invalid link-local nexthop address\n");
2446 return CMD_WARNING_CONFIG_FAILED
;
2449 if (rmap_match_set_hook
.set_ipv6_nexthop_local
)
2450 return rmap_match_set_hook
.set_ipv6_nexthop_local(
2451 vty
, index
, "ipv6 next-hop local", argv
[idx_ipv6
]->arg
);
2456 DEFUN (no_set_ipv6_nexthop_local
,
2457 no_set_ipv6_nexthop_local_cmd
,
2458 "no set ipv6 next-hop local [X:X::X:X]",
2462 "IPv6 next-hop address\n"
2463 "IPv6 local address\n"
2464 "IPv6 address of next hop\n")
2467 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2469 if (rmap_match_set_hook
.no_set_ipv6_nexthop_local
) {
2470 if (argc
<= idx_ipv6
)
2471 return rmap_match_set_hook
.no_set_ipv6_nexthop_local(
2472 vty
, index
, "ipv6 next-hop local", NULL
);
2473 return rmap_match_set_hook
.no_set_ipv6_nexthop_local(
2474 vty
, index
, "ipv6 next-hop local", argv
[5]->arg
);
2481 "set metric <(0-4294967295)|rtt|+rtt|-rtt|+metric|-metric>",
2483 "Metric value for destination routing protocol\n"
2485 "Assign round trip time\n"
2486 "Add round trip time\n"
2487 "Subtract round trip time\n"
2489 "Subtract metric\n")
2492 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2494 const char *pass
= (argv
[idx_number
]->type
== RANGE_TKN
)
2495 ? argv
[idx_number
]->arg
2496 : argv
[idx_number
]->text
;
2498 if (rmap_match_set_hook
.set_metric
)
2499 return rmap_match_set_hook
.set_metric(vty
, index
, "metric",
2505 DEFUN (no_set_metric
,
2507 "no set metric [(0-4294967295)]",
2510 "Metric value for destination routing protocol\n"
2514 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2516 if (rmap_match_set_hook
.no_set_metric
) {
2517 if (argc
<= idx_number
)
2518 return rmap_match_set_hook
.no_set_metric(
2519 vty
, index
, "metric", NULL
);
2520 return rmap_match_set_hook
.no_set_metric(vty
, index
, "metric",
2521 argv
[idx_number
]->arg
);
2529 "set tag (1-4294967295)",
2531 "Tag value for routing protocol\n"
2534 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2537 if (rmap_match_set_hook
.set_tag
)
2538 return rmap_match_set_hook
.set_tag(vty
, index
, "tag",
2539 argv
[idx_number
]->arg
);
2546 "no set tag [(1-4294967295)]",
2549 "Tag value for routing protocol\n"
2552 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2555 if (rmap_match_set_hook
.no_set_tag
) {
2556 if (argc
<= idx_number
)
2557 return rmap_match_set_hook
.no_set_tag(vty
, index
, "tag",
2559 return rmap_match_set_hook
.no_set_tag(vty
, index
, "tag",
2560 argv
[idx_number
]->arg
);
2566 DEFUN_NOSH (route_map
,
2568 "route-map WORD <deny|permit> (1-65535)",
2569 "Create route-map or enter route-map command mode\n"
2571 "Route map denies set operations\n"
2572 "Route map permits set operations\n"
2573 "Sequence to insert to/delete from existing route-map entry\n")
2576 int idx_permit_deny
= 2;
2578 struct route_map
*map
;
2579 struct route_map_index
*index
;
2580 char *endptr
= NULL
;
2582 argv
[idx_permit_deny
]->arg
[0] == 'p' ? RMAP_PERMIT
: RMAP_DENY
;
2583 unsigned long pref
= strtoul(argv
[idx_number
]->arg
, &endptr
, 10);
2584 const char *mapname
= argv
[idx_word
]->arg
;
2586 /* Get route map. */
2587 map
= route_map_get(mapname
);
2588 index
= route_map_index_get(map
, permit
, pref
);
2590 VTY_PUSH_CONTEXT(RMAP_NODE
, index
);
2594 DEFUN (no_route_map_all
,
2595 no_route_map_all_cmd
,
2596 "no route-map WORD",
2598 "Create route-map or enter route-map command mode\n"
2602 const char *mapname
= argv
[idx_word
]->arg
;
2603 struct route_map
*map
;
2605 map
= route_map_lookup_by_name(mapname
);
2607 vty_out(vty
, "%% Could not find route-map %s\n", mapname
);
2608 return CMD_WARNING_CONFIG_FAILED
;
2611 route_map_delete(map
);
2616 DEFUN (no_route_map
,
2618 "no route-map WORD <deny|permit> (1-65535)",
2620 "Create route-map or enter route-map command mode\n"
2622 "Route map denies set operations\n"
2623 "Route map permits set operations\n"
2624 "Sequence to insert to/delete from existing route-map entry\n")
2627 int idx_permit_deny
= 3;
2629 struct route_map
*map
;
2630 struct route_map_index
*index
;
2631 char *endptr
= NULL
;
2632 int permit
= strmatch(argv
[idx_permit_deny
]->text
, "permit")
2635 const char *prefstr
= argv
[idx_number
]->arg
;
2636 const char *mapname
= argv
[idx_word
]->arg
;
2637 unsigned long pref
= strtoul(prefstr
, &endptr
, 10);
2639 /* Existence check. */
2640 map
= route_map_lookup_by_name(mapname
);
2642 vty_out(vty
, "%% Could not find route-map %s\n", mapname
);
2643 return CMD_WARNING_CONFIG_FAILED
;
2646 /* Lookup route map index. */
2647 index
= route_map_index_lookup(map
, permit
, pref
);
2648 if (index
== NULL
) {
2649 vty_out(vty
, "%% Could not find route-map entry %s %s\n",
2651 return CMD_WARNING_CONFIG_FAILED
;
2654 /* Delete index from route map. */
2655 route_map_index_delete(index
, 1);
2657 /* If this route rule is the last one, delete route map itself. */
2658 if (route_map_empty(map
))
2659 route_map_delete(map
);
2664 DEFUN (rmap_onmatch_next
,
2665 rmap_onmatch_next_cmd
,
2667 "Exit policy on matches\n"
2670 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2673 if (index
->type
== RMAP_DENY
) {
2674 /* Under a deny clause, match means it's finished. No
2675 * need to set next */
2677 "on-match next not supported under route-map deny\n");
2678 return CMD_WARNING_CONFIG_FAILED
;
2680 index
->exitpolicy
= RMAP_NEXT
;
2685 DEFUN (no_rmap_onmatch_next
,
2686 no_rmap_onmatch_next_cmd
,
2689 "Exit policy on matches\n"
2692 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2695 index
->exitpolicy
= RMAP_EXIT
;
2700 DEFUN (rmap_onmatch_goto
,
2701 rmap_onmatch_goto_cmd
,
2702 "on-match goto (1-65535)",
2703 "Exit policy on matches\n"
2704 "Goto Clause number\n"
2708 char *num
= argv_find(argv
, argc
, "(1-65535)", &idx
) ? argv
[idx
]->arg
2711 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2715 if (index
->type
== RMAP_DENY
) {
2716 /* Under a deny clause, match means it's finished. No
2717 * need to go anywhere */
2719 "on-match goto not supported under route-map deny\n");
2720 return CMD_WARNING_CONFIG_FAILED
;
2724 d
= strtoul(num
, NULL
, 10);
2726 d
= index
->pref
+ 1;
2728 if (d
<= index
->pref
) {
2729 /* Can't allow you to do that, Dave */
2730 vty_out(vty
, "can't jump backwards in route-maps\n");
2731 return CMD_WARNING_CONFIG_FAILED
;
2733 index
->exitpolicy
= RMAP_GOTO
;
2734 index
->nextpref
= d
;
2740 DEFUN (no_rmap_onmatch_goto
,
2741 no_rmap_onmatch_goto_cmd
,
2744 "Exit policy on matches\n"
2745 "Goto Clause number\n")
2747 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2750 index
->exitpolicy
= RMAP_EXIT
;
2755 /* Cisco/GNU Zebra compatibility aliases */
2757 DEFUN (rmap_continue
,
2759 "continue (1-65535)",
2760 "Continue on a different entry within the route-map\n"
2761 "Route-map entry sequence number\n")
2763 return rmap_onmatch_goto(self
, vty
, argc
, argv
);
2767 DEFUN (no_rmap_continue
,
2768 no_rmap_continue_cmd
,
2769 "no continue [(1-65535)]",
2771 "Continue on a different entry within the route-map\n"
2772 "Route-map entry sequence number\n")
2774 return no_rmap_onmatch_goto(self
, vty
, argc
, argv
);
2778 DEFUN (rmap_show_name
,
2780 "show route-map [WORD]",
2782 "route-map information\n"
2786 const char *name
= (argc
== 3) ? argv
[idx_word
]->arg
: NULL
;
2787 return vty_show_route_map(vty
, name
);
2790 DEFUN (rmap_show_unused
,
2791 rmap_show_unused_cmd
,
2792 "show route-map-unused",
2794 "unused route-map information\n")
2796 return vty_show_unused_route_map(vty
);
2802 "Jump to another Route-Map after match+set\n"
2803 "Target route-map name\n")
2806 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2807 const char *rmap
= argv
[idx_word
]->arg
;
2811 if (index
->nextrm
) {
2812 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED
,
2813 index
->nextrm
, index
->map
->name
);
2814 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
2816 index
->nextrm
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap
);
2818 /* Execute event hook. */
2819 route_map_upd8_dependency(RMAP_EVENT_CALL_ADDED
, index
->nextrm
,
2824 DEFUN (no_rmap_call
,
2828 "Jump to another Route-Map after match+set\n")
2830 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2832 if (index
->nextrm
) {
2833 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED
,
2834 index
->nextrm
, index
->map
->name
);
2835 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
2836 index
->nextrm
= NULL
;
2842 DEFUN (rmap_description
,
2843 rmap_description_cmd
,
2844 "description LINE...",
2845 "Route-map comment\n"
2846 "Comment describing this route-map rule\n")
2849 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2852 if (index
->description
)
2853 XFREE(MTYPE_TMP
, index
->description
);
2854 index
->description
= argv_concat(argv
, argc
, idx_line
);
2859 DEFUN (no_rmap_description
,
2860 no_rmap_description_cmd
,
2863 "Route-map comment\n")
2865 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2868 if (index
->description
)
2869 XFREE(MTYPE_TMP
, index
->description
);
2870 index
->description
= NULL
;
2875 /* Configuration write function. */
2876 static int route_map_config_write(struct vty
*vty
)
2878 struct route_map
*map
;
2879 struct route_map_index
*index
;
2880 struct route_map_rule
*rule
;
2884 for (map
= route_map_master
.head
; map
; map
= map
->next
)
2885 for (index
= map
->head
; index
; index
= index
->next
) {
2887 vty_out(vty
, "!\n");
2891 vty_out(vty
, "route-map %s %s %d\n", map
->name
,
2892 route_map_type_str(index
->type
), index
->pref
);
2894 if (index
->description
)
2895 vty_out(vty
, " description %s\n",
2896 index
->description
);
2898 for (rule
= index
->match_list
.head
; rule
;
2900 vty_out(vty
, " match %s %s\n", rule
->cmd
->str
,
2901 rule
->rule_str
? rule
->rule_str
: "");
2903 for (rule
= index
->set_list
.head
; rule
;
2905 vty_out(vty
, " set %s %s\n", rule
->cmd
->str
,
2906 rule
->rule_str
? rule
->rule_str
: "");
2908 vty_out(vty
, " call %s\n", index
->nextrm
);
2909 if (index
->exitpolicy
== RMAP_GOTO
)
2910 vty_out(vty
, " on-match goto %d\n",
2912 if (index
->exitpolicy
== RMAP_NEXT
)
2913 vty_out(vty
, " on-match next\n");
2920 /* Route map node structure. */
2921 static struct cmd_node rmap_node
= {RMAP_NODE
, "%s(config-route-map)# ", 1};
2923 /* Common route map rules */
2925 void *route_map_rule_tag_compile(const char *arg
)
2927 unsigned long int tmp
;
2932 tmp
= strtoul(arg
, &endptr
, 0);
2933 if (arg
[0] == '\0' || *endptr
!= '\0' || errno
|| tmp
> ROUTE_TAG_MAX
)
2936 tag
= XMALLOC(MTYPE_ROUTE_MAP_COMPILED
, sizeof(*tag
));
2942 void route_map_rule_tag_free(void *rule
)
2944 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
2947 void route_map_finish(void)
2951 vector_free(route_match_vec
);
2952 route_match_vec
= NULL
;
2953 vector_free(route_set_vec
);
2954 route_set_vec
= NULL
;
2957 * All protocols are setting these to NULL
2958 * by default on shutdown( route_map_finish )
2959 * Why are we making them do this work?
2961 route_map_master
.add_hook
= NULL
;
2962 route_map_master
.delete_hook
= NULL
;
2963 route_map_master
.event_hook
= NULL
;
2965 /* cleanup route_map */
2966 while (route_map_master
.head
) {
2967 struct route_map
*map
= route_map_master
.head
;
2968 map
->to_be_processed
= false;
2969 route_map_delete(map
);
2972 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
2973 hash_free(route_map_dep_hash
[i
]);
2974 route_map_dep_hash
[i
] = NULL
;
2977 hash_free(route_map_master_hash
);
2978 route_map_master_hash
= NULL
;
2981 static void rmap_autocomplete(vector comps
, struct cmd_token
*token
)
2983 struct route_map
*map
;
2985 for (map
= route_map_master
.head
; map
; map
= map
->next
)
2986 vector_set(comps
, XSTRDUP(MTYPE_COMPLETION
, map
->name
));
2989 /* Increment the use_count counter while attaching the route map */
2990 void route_map_counter_increment(struct route_map
*map
)
2996 /* Decrement the use_count counter while detaching the route map. */
2997 void route_map_counter_decrement(struct route_map
*map
)
3000 if (map
->use_count
<= 0)
3006 static const struct cmd_variable_handler rmap_var_handlers
[] = {
3007 {/* "route-map WORD" */
3008 .varname
= "route_map",
3009 .completions
= rmap_autocomplete
},
3010 {.tokenname
= "ROUTEMAP_NAME", .completions
= rmap_autocomplete
},
3011 {.tokenname
= "RMAP_NAME", .completions
= rmap_autocomplete
},
3012 {.completions
= NULL
}};
3014 /* Initialization of route map vector. */
3015 void route_map_init(void)
3019 /* Make vector for match and set. */
3020 route_match_vec
= vector_init(1);
3021 route_set_vec
= vector_init(1);
3022 route_map_master_hash
=
3023 hash_create_size(8, route_map_hash_key_make
, route_map_hash_cmp
,
3024 "Route Map Master Hash");
3026 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++)
3027 route_map_dep_hash
[i
] = hash_create_size(
3028 8, route_map_dep_hash_make_key
, route_map_dep_hash_cmp
,
3029 "Route Map Dep Hash");
3031 cmd_variable_handler_register(rmap_var_handlers
);
3033 /* Install route map top node. */
3034 install_node(&rmap_node
, route_map_config_write
);
3036 /* Install route map commands. */
3037 install_default(RMAP_NODE
);
3038 install_element(CONFIG_NODE
, &route_map_cmd
);
3039 install_element(CONFIG_NODE
, &no_route_map_cmd
);
3040 install_element(CONFIG_NODE
, &no_route_map_all_cmd
);
3042 /* Install the on-match stuff */
3043 install_element(RMAP_NODE
, &route_map_cmd
);
3044 install_element(RMAP_NODE
, &rmap_onmatch_next_cmd
);
3045 install_element(RMAP_NODE
, &no_rmap_onmatch_next_cmd
);
3046 install_element(RMAP_NODE
, &rmap_onmatch_goto_cmd
);
3047 install_element(RMAP_NODE
, &no_rmap_onmatch_goto_cmd
);
3048 install_element(RMAP_NODE
, &rmap_continue_cmd
);
3049 install_element(RMAP_NODE
, &no_rmap_continue_cmd
);
3051 /* Install the continue stuff (ALIAS of on-match). */
3053 /* Install the call stuff. */
3054 install_element(RMAP_NODE
, &rmap_call_cmd
);
3055 install_element(RMAP_NODE
, &no_rmap_call_cmd
);
3057 /* Install description commands. */
3058 install_element(RMAP_NODE
, &rmap_description_cmd
);
3059 install_element(RMAP_NODE
, &no_rmap_description_cmd
);
3061 /* Install show command */
3062 install_element(ENABLE_NODE
, &rmap_show_name_cmd
);
3063 install_element(ENABLE_NODE
, &rmap_show_unused_cmd
);
3065 install_element(RMAP_NODE
, &match_interface_cmd
);
3066 install_element(RMAP_NODE
, &no_match_interface_cmd
);
3068 install_element(RMAP_NODE
, &match_ip_address_cmd
);
3069 install_element(RMAP_NODE
, &no_match_ip_address_cmd
);
3071 install_element(RMAP_NODE
, &match_ip_address_prefix_list_cmd
);
3072 install_element(RMAP_NODE
, &no_match_ip_address_prefix_list_cmd
);
3074 install_element(RMAP_NODE
, &match_ip_next_hop_cmd
);
3075 install_element(RMAP_NODE
, &no_match_ip_next_hop_cmd
);
3077 install_element(RMAP_NODE
, &match_ip_next_hop_prefix_list_cmd
);
3078 install_element(RMAP_NODE
, &no_match_ip_next_hop_prefix_list_cmd
);
3080 install_element(RMAP_NODE
, &match_ip_next_hop_type_cmd
);
3081 install_element(RMAP_NODE
, &no_match_ip_next_hop_type_cmd
);
3083 install_element(RMAP_NODE
, &match_ipv6_address_cmd
);
3084 install_element(RMAP_NODE
, &no_match_ipv6_address_cmd
);
3086 install_element(RMAP_NODE
, &match_ipv6_address_prefix_list_cmd
);
3087 install_element(RMAP_NODE
, &no_match_ipv6_address_prefix_list_cmd
);
3089 install_element(RMAP_NODE
, &match_ipv6_next_hop_type_cmd
);
3090 install_element(RMAP_NODE
, &no_match_ipv6_next_hop_type_cmd
);
3092 install_element(RMAP_NODE
, &match_metric_cmd
);
3093 install_element(RMAP_NODE
, &no_match_metric_cmd
);
3095 install_element(RMAP_NODE
, &match_tag_cmd
);
3096 install_element(RMAP_NODE
, &no_match_tag_cmd
);
3098 install_element(RMAP_NODE
, &set_ip_nexthop_cmd
);
3099 install_element(RMAP_NODE
, &no_set_ip_nexthop_cmd
);
3101 install_element(RMAP_NODE
, &set_ipv6_nexthop_local_cmd
);
3102 install_element(RMAP_NODE
, &no_set_ipv6_nexthop_local_cmd
);
3104 install_element(RMAP_NODE
, &set_metric_cmd
);
3105 install_element(RMAP_NODE
, &no_set_metric_cmd
);
3107 install_element(RMAP_NODE
, &set_tag_cmd
);
3108 install_element(RMAP_NODE
, &no_set_tag_cmd
);