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
);
541 XFREE(MTYPE_ROUTE_MAP_RULE
, dep_name
);
542 XFREE(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
547 int generic_set_add(struct vty
*vty
, struct route_map_index
*index
,
548 const char *command
, const char *arg
)
552 ret
= route_map_add_set(index
, command
, arg
);
554 case RMAP_RULE_MISSING
:
555 vty_out(vty
, "%% [%s] Can't find rule.\n", frr_protonameinst
);
556 return CMD_WARNING_CONFIG_FAILED
;
558 case RMAP_COMPILE_ERROR
:
560 "%% [%s] Argument form is unsupported or malformed.\n",
562 return CMD_WARNING_CONFIG_FAILED
;
564 case RMAP_COMPILE_SUCCESS
:
571 int generic_set_delete(struct vty
*vty
, struct route_map_index
*index
,
572 const char *command
, const char *arg
)
576 ret
= route_map_delete_set(index
, command
, arg
);
578 case RMAP_RULE_MISSING
:
579 vty_out(vty
, "%% [%s] Can't find rule.\n", frr_protonameinst
);
580 return CMD_WARNING_CONFIG_FAILED
;
582 case RMAP_COMPILE_ERROR
:
584 "%% [%s] Argument form is unsupported or malformed.\n",
586 return CMD_WARNING_CONFIG_FAILED
;
588 case RMAP_COMPILE_SUCCESS
:
596 /* Route map rule. This rule has both `match' rule and `set' rule. */
597 struct route_map_rule
{
599 struct route_map_rule_cmd
*cmd
;
601 /* For pretty printing. */
604 /* Pre-compiled match rule. */
608 struct route_map_rule
*next
;
609 struct route_map_rule
*prev
;
612 /* Making route map list. */
613 struct route_map_list
{
614 struct route_map
*head
;
615 struct route_map
*tail
;
617 void (*add_hook
)(const char *);
618 void (*delete_hook
)(const char *);
619 void (*event_hook
)(route_map_event_t
, const char *);
622 /* Master list of route map. */
623 static struct route_map_list route_map_master
= {NULL
, NULL
, NULL
, NULL
, NULL
};
624 struct hash
*route_map_master_hash
= NULL
;
626 static unsigned int route_map_hash_key_make(void *p
)
628 const struct route_map
*map
= p
;
629 return string_hash_make(map
->name
);
632 static bool route_map_hash_cmp(const void *p1
, const void *p2
)
634 const struct route_map
*map1
= p1
;
635 const struct route_map
*map2
= p2
;
637 if (map1
->deleted
== map2
->deleted
) {
638 if (map1
->name
&& map2
->name
) {
639 if (!strcmp(map1
->name
, map2
->name
)) {
642 } else if (!map1
->name
&& !map2
->name
) {
650 enum route_map_upd8_type
{
655 /* all possible route-map dependency types */
656 enum route_map_dep_type
{
657 ROUTE_MAP_DEP_RMAP
= 1,
659 ROUTE_MAP_DEP_ECLIST
,
660 ROUTE_MAP_DEP_LCLIST
,
662 ROUTE_MAP_DEP_ASPATH
,
663 ROUTE_MAP_DEP_FILTER
,
667 struct route_map_dep
{
669 struct hash
*dep_rmap_hash
;
670 struct hash
*this_hash
; /* ptr to the hash structure this is part of */
673 /* Hashes maintaining dependency between various sublists used by route maps */
674 struct hash
*route_map_dep_hash
[ROUTE_MAP_DEP_MAX
];
676 static unsigned int route_map_dep_hash_make_key(void *p
);
677 static void route_map_clear_all_references(char *rmap_name
);
678 static void route_map_rule_delete(struct route_map_rule_list
*,
679 struct route_map_rule
*);
680 static int rmap_debug
= 0;
682 static void route_map_index_delete(struct route_map_index
*, int);
684 /* New route map allocation. Please note route map's name must be
686 static struct route_map
*route_map_new(const char *name
)
688 struct route_map
*new;
690 new = XCALLOC(MTYPE_ROUTE_MAP
, sizeof(struct route_map
));
691 new->name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
692 QOBJ_REG(new, route_map
);
696 /* Add new name to route_map. */
697 static struct route_map
*route_map_add(const char *name
)
699 struct route_map
*map
;
700 struct route_map_list
*list
;
702 map
= route_map_new(name
);
703 list
= &route_map_master
;
705 /* Add map to the hash */
706 hash_get(route_map_master_hash
, map
, hash_alloc_intern
);
708 /* Add new entry to the head of the list to match how it is added in the
709 * hash table. This is to ensure that if the same route-map has been
710 * created more than once and then marked for deletion (which can happen
711 * if prior deletions haven't completed as BGP hasn't yet done the
712 * route-map processing), the order of the entities is the same in both
713 * the list and the hash table. Otherwise, since there is nothing to
714 * distinguish between the two entries, the wrong entry could get freed.
715 * TODO: This needs to be re-examined to handle it better - e.g., revive
716 * a deleted entry if the route-map is created again.
719 map
->next
= list
->head
;
721 list
->head
->prev
= map
;
727 if (route_map_master
.add_hook
) {
728 (*route_map_master
.add_hook
)(name
);
729 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_ADDED
);
734 /* this is supposed to be called post processing by
735 * the delete hook function. Don't invoke delete_hook
736 * again in this routine.
738 static void route_map_free_map(struct route_map
*map
)
740 struct route_map_list
*list
;
741 struct route_map_index
*index
;
746 while ((index
= map
->head
) != NULL
)
747 route_map_index_delete(index
, 0);
749 list
= &route_map_master
;
754 map
->next
->prev
= map
->prev
;
756 list
->tail
= map
->prev
;
759 map
->prev
->next
= map
->next
;
761 list
->head
= map
->next
;
763 hash_release(route_map_master_hash
, map
);
764 XFREE(MTYPE_ROUTE_MAP_NAME
, map
->name
);
765 XFREE(MTYPE_ROUTE_MAP
, map
);
768 /* Route map delete from list. */
769 static void route_map_delete(struct route_map
*map
)
771 struct route_map_index
*index
;
774 while ((index
= map
->head
) != NULL
)
775 route_map_index_delete(index
, 0);
780 /* Clear all dependencies */
781 route_map_clear_all_references(name
);
783 /* Execute deletion hook. */
784 if (route_map_master
.delete_hook
) {
785 (*route_map_master
.delete_hook
)(name
);
786 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_DELETED
);
789 if (!map
->to_be_processed
) {
790 route_map_free_map(map
);
794 /* Lookup route map by route map name string. */
795 struct route_map
*route_map_lookup_by_name(const char *name
)
797 struct route_map
*map
;
798 struct route_map tmp_map
;
803 // map.deleted is 0 via memset
804 memset(&tmp_map
, 0, sizeof(struct route_map
));
805 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
806 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
807 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
811 /* Simple helper to warn if route-map does not exist. */
812 struct route_map
*route_map_lookup_warn_noexist(struct vty
*vty
, const char *name
)
814 struct route_map
*route_map
= route_map_lookup_by_name(name
);
817 if (vty_shell_serv(vty
))
818 vty_out(vty
, "The route-map '%s' does not exist.\n", name
);
823 int route_map_mark_updated(const char *name
)
825 struct route_map
*map
;
827 struct route_map tmp_map
;
832 map
= route_map_lookup_by_name(name
);
834 /* If we did not find the routemap with deleted=false try again
838 memset(&tmp_map
, 0, sizeof(struct route_map
));
839 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
840 tmp_map
.deleted
= true;
841 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
842 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
846 map
->to_be_processed
= true;
853 static int route_map_clear_updated(struct route_map
*map
)
858 map
->to_be_processed
= false;
860 route_map_free_map(map
);
866 /* Lookup route map. If there isn't route map create one and return
868 static struct route_map
*route_map_get(const char *name
)
870 struct route_map
*map
;
872 map
= route_map_lookup_by_name(name
);
874 map
= route_map_add(name
);
879 void route_map_walk_update_list(void (*route_map_update_fn
)(char *name
))
881 struct route_map
*node
;
882 struct route_map
*nnode
= NULL
;
884 for (node
= route_map_master
.head
; node
; node
= nnode
) {
885 if (node
->to_be_processed
) {
886 /* DD: Should we add any thread yield code here */
887 route_map_update_fn(node
->name
);
889 route_map_clear_updated(node
);
895 /* Return route map's type string. */
896 static const char *route_map_type_str(enum route_map_type type
)
911 static int route_map_empty(struct route_map
*map
)
913 if (map
->head
== NULL
&& map
->tail
== NULL
)
920 static void vty_show_route_map_entry(struct vty
*vty
, struct route_map
*map
)
922 struct route_map_index
*index
;
923 struct route_map_rule
*rule
;
925 vty_out(vty
, "route-map: %s Invoked: %" PRIu64
"\n",
926 map
->name
, map
->applied
);
928 for (index
= map
->head
; index
; index
= index
->next
) {
929 vty_out(vty
, " %s, sequence %d Invoked %" PRIu64
"\n",
930 route_map_type_str(index
->type
), index
->pref
,
934 if (index
->description
)
935 vty_out(vty
, " Description:\n %s\n",
939 vty_out(vty
, " Match clauses:\n");
940 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
941 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
944 vty_out(vty
, " Set clauses:\n");
945 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
946 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
950 vty_out(vty
, " Call clause:\n");
952 vty_out(vty
, " Call %s\n", index
->nextrm
);
955 vty_out(vty
, " Action:\n");
956 if (index
->exitpolicy
== RMAP_GOTO
)
957 vty_out(vty
, " Goto %d\n", index
->nextpref
);
958 else if (index
->exitpolicy
== RMAP_NEXT
)
959 vty_out(vty
, " Continue to next entry\n");
960 else if (index
->exitpolicy
== RMAP_EXIT
)
961 vty_out(vty
, " Exit routemap\n");
965 static int sort_route_map(const void **map1
, const void **map2
)
967 const struct route_map
*m1
= *map1
;
968 const struct route_map
*m2
= *map2
;
970 return strcmp(m1
->name
, m2
->name
);
973 static int vty_show_route_map(struct vty
*vty
, const char *name
)
975 struct route_map
*map
;
977 vty_out(vty
, "%s:\n", frr_protonameinst
);
980 map
= route_map_lookup_by_name(name
);
983 vty_show_route_map_entry(vty
, map
);
986 vty_out(vty
, "%s: 'route-map %s' not found\n",
987 frr_protonameinst
, name
);
992 struct list
*maplist
= list_new();
995 for (map
= route_map_master
.head
; map
; map
= map
->next
)
996 listnode_add(maplist
, map
);
998 list_sort(maplist
, sort_route_map
);
1000 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
1001 vty_show_route_map_entry(vty
, map
);
1003 list_delete(&maplist
);
1008 /* Unused route map details */
1009 static int vty_show_unused_route_map(struct vty
*vty
)
1011 struct list
*maplist
= list_new();
1012 struct listnode
*ln
;
1013 struct route_map
*map
;
1015 for (map
= route_map_master
.head
; map
; map
= map
->next
) {
1016 /* If use_count is zero, No protocol is using this routemap.
1017 * so adding to the list.
1019 if (!map
->use_count
)
1020 listnode_add(maplist
, map
);
1023 if (maplist
->count
> 0) {
1024 vty_out(vty
, "\n%s:\n", frr_protonameinst
);
1025 list_sort(maplist
, sort_route_map
);
1027 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
1028 vty_show_route_map_entry(vty
, map
);
1030 vty_out(vty
, "\n%s: None\n", frr_protonameinst
);
1033 list_delete(&maplist
);
1037 /* New route map allocation. Please note route map's name must be
1039 static struct route_map_index
*route_map_index_new(void)
1041 struct route_map_index
*new;
1043 new = XCALLOC(MTYPE_ROUTE_MAP_INDEX
, sizeof(struct route_map_index
));
1044 new->exitpolicy
= RMAP_EXIT
; /* Default to Cisco-style */
1045 QOBJ_REG(new, route_map_index
);
1049 /* Free route map index. */
1050 static void route_map_index_delete(struct route_map_index
*index
, int notify
)
1052 struct route_map_rule
*rule
;
1056 /* Free route match. */
1057 while ((rule
= index
->match_list
.head
) != NULL
)
1058 route_map_rule_delete(&index
->match_list
, rule
);
1060 /* Free route set. */
1061 while ((rule
= index
->set_list
.head
) != NULL
)
1062 route_map_rule_delete(&index
->set_list
, rule
);
1064 /* Remove index from route map list. */
1066 index
->next
->prev
= index
->prev
;
1068 index
->map
->tail
= index
->prev
;
1071 index
->prev
->next
= index
->next
;
1073 index
->map
->head
= index
->next
;
1075 /* Free 'char *nextrm' if not NULL */
1076 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
1078 /* Execute event hook. */
1079 if (route_map_master
.event_hook
&& notify
) {
1080 (*route_map_master
.event_hook
)(RMAP_EVENT_INDEX_DELETED
,
1082 route_map_notify_dependencies(index
->map
->name
,
1083 RMAP_EVENT_CALL_ADDED
);
1085 XFREE(MTYPE_ROUTE_MAP_INDEX
, index
);
1088 /* Lookup index from route map. */
1089 static struct route_map_index
*route_map_index_lookup(struct route_map
*map
,
1090 enum route_map_type type
,
1093 struct route_map_index
*index
;
1095 for (index
= map
->head
; index
; index
= index
->next
)
1096 if ((index
->type
== type
|| type
== RMAP_ANY
)
1097 && index
->pref
== pref
)
1102 /* Add new index to route map. */
1103 static struct route_map_index
*
1104 route_map_index_add(struct route_map
*map
, enum route_map_type type
, int pref
)
1106 struct route_map_index
*index
;
1107 struct route_map_index
*point
;
1109 /* Allocate new route map inex. */
1110 index
= route_map_index_new();
1115 /* Compare preference. */
1116 for (point
= map
->head
; point
; point
= point
->next
)
1117 if (point
->pref
>= pref
)
1120 if (map
->head
== NULL
) {
1121 map
->head
= map
->tail
= index
;
1122 } else if (point
== NULL
) {
1123 index
->prev
= map
->tail
;
1124 map
->tail
->next
= index
;
1126 } else if (point
== map
->head
) {
1127 index
->next
= map
->head
;
1128 map
->head
->prev
= index
;
1131 index
->next
= point
;
1132 index
->prev
= point
->prev
;
1134 point
->prev
->next
= index
;
1135 point
->prev
= index
;
1138 /* Execute event hook. */
1139 if (route_map_master
.event_hook
) {
1140 (*route_map_master
.event_hook
)(RMAP_EVENT_INDEX_ADDED
,
1142 route_map_notify_dependencies(map
->name
, RMAP_EVENT_CALL_ADDED
);
1147 /* Get route map index. */
1148 static struct route_map_index
*
1149 route_map_index_get(struct route_map
*map
, enum route_map_type type
, int pref
)
1151 struct route_map_index
*index
;
1153 index
= route_map_index_lookup(map
, RMAP_ANY
, pref
);
1154 if (index
&& index
->type
!= type
) {
1155 /* Delete index from route map. */
1156 route_map_index_delete(index
, 1);
1160 index
= route_map_index_add(map
, type
, pref
);
1164 /* New route map rule */
1165 static struct route_map_rule
*route_map_rule_new(void)
1167 struct route_map_rule
*new;
1169 new = XCALLOC(MTYPE_ROUTE_MAP_RULE
, sizeof(struct route_map_rule
));
1173 /* Install rule command to the match list. */
1174 void route_map_install_match(struct route_map_rule_cmd
*cmd
)
1176 vector_set(route_match_vec
, cmd
);
1179 /* Install rule command to the set list. */
1180 void route_map_install_set(struct route_map_rule_cmd
*cmd
)
1182 vector_set(route_set_vec
, cmd
);
1185 /* Lookup rule command from match list. */
1186 static struct route_map_rule_cmd
*route_map_lookup_match(const char *name
)
1189 struct route_map_rule_cmd
*rule
;
1191 for (i
= 0; i
< vector_active(route_match_vec
); i
++)
1192 if ((rule
= vector_slot(route_match_vec
, i
)) != NULL
)
1193 if (strcmp(rule
->str
, name
) == 0)
1198 /* Lookup rule command from set list. */
1199 static struct route_map_rule_cmd
*route_map_lookup_set(const char *name
)
1202 struct route_map_rule_cmd
*rule
;
1204 for (i
= 0; i
< vector_active(route_set_vec
); i
++)
1205 if ((rule
= vector_slot(route_set_vec
, i
)) != NULL
)
1206 if (strcmp(rule
->str
, name
) == 0)
1211 /* Add match and set rule to rule list. */
1212 static void route_map_rule_add(struct route_map_rule_list
*list
,
1213 struct route_map_rule
*rule
)
1216 rule
->prev
= list
->tail
;
1218 list
->tail
->next
= rule
;
1224 /* Delete rule from rule list. */
1225 static void route_map_rule_delete(struct route_map_rule_list
*list
,
1226 struct route_map_rule
*rule
)
1228 if (rule
->cmd
->func_free
)
1229 (*rule
->cmd
->func_free
)(rule
->value
);
1231 XFREE(MTYPE_ROUTE_MAP_RULE_STR
, rule
->rule_str
);
1234 rule
->next
->prev
= rule
->prev
;
1236 list
->tail
= rule
->prev
;
1238 rule
->prev
->next
= rule
->next
;
1240 list
->head
= rule
->next
;
1242 XFREE(MTYPE_ROUTE_MAP_RULE
, rule
);
1245 /* strcmp wrapper function which don't crush even argument is NULL. */
1246 static int rulecmp(const char *dst
, const char *src
)
1257 return strcmp(dst
, src
);
1262 /* Use this to return the already specified argument for this match. This is
1263 * useful to get the specified argument with a route map match rule when the
1264 * rule is being deleted and the argument is not provided.
1266 const char *route_map_get_match_arg(struct route_map_index
*index
,
1267 const char *match_name
)
1269 struct route_map_rule
*rule
;
1270 struct route_map_rule_cmd
*cmd
;
1272 /* First lookup rule for add match statement. */
1273 cmd
= route_map_lookup_match(match_name
);
1277 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1278 if (rule
->cmd
== cmd
&& rule
->rule_str
!= NULL
)
1279 return (rule
->rule_str
);
1284 /* Add match statement to route map. */
1285 int route_map_add_match(struct route_map_index
*index
, const char *match_name
,
1286 const char *match_arg
)
1288 struct route_map_rule
*rule
;
1289 struct route_map_rule
*next
;
1290 struct route_map_rule_cmd
*cmd
;
1294 /* First lookup rule for add match statement. */
1295 cmd
= route_map_lookup_match(match_name
);
1297 return RMAP_RULE_MISSING
;
1299 /* Next call compile function for this match statement. */
1300 if (cmd
->func_compile
) {
1301 compile
= (*cmd
->func_compile
)(match_arg
);
1302 if (compile
== NULL
)
1303 return RMAP_COMPILE_ERROR
;
1307 /* If argument is completely same ignore it. */
1308 for (rule
= index
->match_list
.head
; rule
; rule
= next
) {
1310 if (rule
->cmd
== cmd
) {
1311 /* If the configured route-map match rule is exactly
1312 * the same as the existing configuration then,
1313 * ignore the duplicate configuration.
1315 if (strcmp(match_arg
, rule
->rule_str
) == 0) {
1317 (*cmd
->func_free
)(compile
);
1318 return RMAP_COMPILE_SUCCESS
;
1321 route_map_rule_delete(&index
->match_list
, rule
);
1326 /* Add new route map match rule. */
1327 rule
= route_map_rule_new();
1329 rule
->value
= compile
;
1331 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, match_arg
);
1333 rule
->rule_str
= NULL
;
1335 /* Add new route match rule to linked list. */
1336 route_map_rule_add(&index
->match_list
, rule
);
1338 /* Execute event hook. */
1339 if (route_map_master
.event_hook
) {
1340 (*route_map_master
.event_hook
)(
1341 replaced
? RMAP_EVENT_MATCH_REPLACED
1342 : RMAP_EVENT_MATCH_ADDED
,
1344 route_map_notify_dependencies(index
->map
->name
,
1345 RMAP_EVENT_CALL_ADDED
);
1348 return RMAP_COMPILE_SUCCESS
;
1351 /* Delete specified route match rule. */
1352 int route_map_delete_match(struct route_map_index
*index
,
1353 const char *match_name
, const char *match_arg
)
1355 struct route_map_rule
*rule
;
1356 struct route_map_rule_cmd
*cmd
;
1358 cmd
= route_map_lookup_match(match_name
);
1362 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1363 if (rule
->cmd
== cmd
&& (rulecmp(rule
->rule_str
, match_arg
) == 0
1364 || match_arg
== NULL
)) {
1365 route_map_rule_delete(&index
->match_list
, rule
);
1366 /* Execute event hook. */
1367 if (route_map_master
.event_hook
) {
1368 (*route_map_master
.event_hook
)(
1369 RMAP_EVENT_MATCH_DELETED
,
1371 route_map_notify_dependencies(
1373 RMAP_EVENT_CALL_ADDED
);
1377 /* Can't find matched rule. */
1381 /* Add route-map set statement to the route map. */
1382 int route_map_add_set(struct route_map_index
*index
, const char *set_name
,
1383 const char *set_arg
)
1385 struct route_map_rule
*rule
;
1386 struct route_map_rule
*next
;
1387 struct route_map_rule_cmd
*cmd
;
1391 cmd
= route_map_lookup_set(set_name
);
1393 return RMAP_RULE_MISSING
;
1395 /* Next call compile function for this match statement. */
1396 if (cmd
->func_compile
) {
1397 compile
= (*cmd
->func_compile
)(set_arg
);
1398 if (compile
== NULL
)
1399 return RMAP_COMPILE_ERROR
;
1403 /* Add by WJL. if old set command of same kind exist, delete it first
1404 to ensure only one set command of same kind exist under a
1406 for (rule
= index
->set_list
.head
; rule
; rule
= next
) {
1408 if (rule
->cmd
== cmd
) {
1409 route_map_rule_delete(&index
->set_list
, rule
);
1414 /* Add new route map match rule. */
1415 rule
= route_map_rule_new();
1417 rule
->value
= compile
;
1419 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, set_arg
);
1421 rule
->rule_str
= NULL
;
1423 /* Add new route match rule to linked list. */
1424 route_map_rule_add(&index
->set_list
, rule
);
1426 /* Execute event hook. */
1427 if (route_map_master
.event_hook
) {
1428 (*route_map_master
.event_hook
)(replaced
1429 ? RMAP_EVENT_SET_REPLACED
1430 : RMAP_EVENT_SET_ADDED
,
1432 route_map_notify_dependencies(index
->map
->name
,
1433 RMAP_EVENT_CALL_ADDED
);
1435 return RMAP_COMPILE_SUCCESS
;
1438 /* Delete route map set rule. */
1439 int route_map_delete_set(struct route_map_index
*index
, const char *set_name
,
1440 const char *set_arg
)
1442 struct route_map_rule
*rule
;
1443 struct route_map_rule_cmd
*cmd
;
1445 cmd
= route_map_lookup_set(set_name
);
1449 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
1450 if ((rule
->cmd
== cmd
) && (rulecmp(rule
->rule_str
, set_arg
) == 0
1451 || set_arg
== NULL
)) {
1452 route_map_rule_delete(&index
->set_list
, rule
);
1453 /* Execute event hook. */
1454 if (route_map_master
.event_hook
) {
1455 (*route_map_master
.event_hook
)(
1456 RMAP_EVENT_SET_DELETED
,
1458 route_map_notify_dependencies(
1460 RMAP_EVENT_CALL_ADDED
);
1464 /* Can't find matched rule. */
1468 /* Apply route map's each index to the object.
1470 The matrix for a route-map looks like this:
1471 (note, this includes the description for the "NEXT"
1472 and "GOTO" frobs now
1476 permit action | cont
1478 ------------------+---------------
1484 -Apply Set statements, accept route
1485 -If Call statement is present jump to the specified route-map, if it
1486 denies the route we finish.
1487 -If NEXT is specified, goto NEXT statement
1488 -If GOTO is specified, goto the first clause where pref > nextpref
1489 -If nothing is specified, do as Cisco and finish
1491 -Route is denied by route-map.
1495 If we get no matches after we've processed all updates, then the route
1498 Some notes on the new "CALL", "NEXT" and "GOTO"
1499 call WORD - If this clause is matched, then the set statements
1500 are executed and then we jump to route-map 'WORD'. If
1501 this route-map denies the route, we finish, in other
1503 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
1504 on-match next - If this clause is matched, then the set statements
1505 are executed and then we drop through to the next clause
1506 on-match goto n - If this clause is matched, then the set statments
1507 are executed and then we goto the nth clause, or the
1508 first clause greater than this. In order to ensure
1509 route-maps *always* exit, you cannot jump backwards.
1512 We need to make sure our route-map processing matches the above
1515 static route_map_result_t
1516 route_map_apply_match(struct route_map_rule_list
*match_list
,
1517 const struct prefix
*prefix
, route_map_object_t type
,
1520 route_map_result_t ret
= RMAP_NOMATCH
;
1521 struct route_map_rule
*match
;
1524 /* Check all match rule and if there is no match rule, go to the
1526 if (!match_list
->head
)
1529 for (match
= match_list
->head
; match
; match
= match
->next
) {
1530 /* Try each match statement in turn, If any do not
1532 RMAP_MATCH, return, otherwise continue on to next
1534 statement. All match statements must match for
1537 ret
= (*match
->cmd
->func_apply
)(match
->value
, prefix
,
1539 if (ret
!= RMAP_MATCH
)
1546 /* Apply route map to the object. */
1547 route_map_result_t
route_map_apply(struct route_map
*map
,
1548 const struct prefix
*prefix
,
1549 route_map_object_t type
, void *object
)
1551 static int recursion
= 0;
1553 struct route_map_index
*index
;
1554 struct route_map_rule
*set
;
1556 if (recursion
> RMAP_RECURSION_LIMIT
) {
1558 EC_LIB_RMAP_RECURSION_LIMIT
,
1559 "route-map recursion limit (%d) reached, discarding route",
1560 RMAP_RECURSION_LIMIT
);
1562 return RMAP_DENYMATCH
;
1566 return RMAP_DENYMATCH
;
1569 for (index
= map
->head
; index
; index
= index
->next
) {
1570 /* Apply this index. */
1572 ret
= route_map_apply_match(&index
->match_list
, prefix
, type
,
1575 /* Now we apply the matrix from above */
1576 if (ret
== RMAP_NOMATCH
)
1577 /* 'cont' from matrix - continue to next route-map
1580 else if (ret
== RMAP_MATCH
) {
1581 if (index
->type
== RMAP_PERMIT
)
1584 /* permit+match must execute sets */
1585 for (set
= index
->set_list
.head
; set
;
1587 ret
= (*set
->cmd
->func_apply
)(
1588 set
->value
, prefix
, type
,
1591 /* Call another route-map if available */
1592 if (index
->nextrm
) {
1593 struct route_map
*nextrm
=
1594 route_map_lookup_by_name(
1597 if (nextrm
) /* Target route-map found,
1601 ret
= route_map_apply(
1602 nextrm
, prefix
, type
,
1607 /* If nextrm returned 'deny', finish. */
1608 if (ret
== RMAP_DENYMATCH
)
1612 switch (index
->exitpolicy
) {
1618 /* Find the next clause to jump to */
1619 struct route_map_index
*next
=
1621 int nextpref
= index
->nextpref
;
1623 while (next
&& next
->pref
< nextpref
) {
1628 /* No clauses match! */
1633 } else if (index
->type
== RMAP_DENY
)
1636 return RMAP_DENYMATCH
;
1640 /* Finally route-map does not match at all. */
1641 return RMAP_DENYMATCH
;
1644 void route_map_add_hook(void (*func
)(const char *))
1646 route_map_master
.add_hook
= func
;
1649 void route_map_delete_hook(void (*func
)(const char *))
1651 route_map_master
.delete_hook
= func
;
1654 void route_map_event_hook(void (*func
)(route_map_event_t
, const char *))
1656 route_map_master
.event_hook
= func
;
1659 /* Routines for route map dependency lists and dependency processing */
1660 static bool route_map_rmap_hash_cmp(const void *p1
, const void *p2
)
1662 return (strcmp((const char *)p1
, (const char *)p2
) == 0);
1665 static bool route_map_dep_hash_cmp(const void *p1
, const void *p2
)
1668 return (strcmp(((const struct route_map_dep
*)p1
)->dep_name
,
1673 static void route_map_clear_reference(struct hash_bucket
*bucket
, void *arg
)
1675 struct route_map_dep
*dep
= (struct route_map_dep
*)bucket
->data
;
1680 (char *)hash_release(dep
->dep_rmap_hash
, (void *)arg
);
1682 XFREE(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
1684 if (!dep
->dep_rmap_hash
->count
) {
1685 dep
= hash_release(dep
->this_hash
,
1686 (void *)dep
->dep_name
);
1687 hash_free(dep
->dep_rmap_hash
);
1688 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
1689 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
1694 static void route_map_clear_all_references(char *rmap_name
)
1698 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
1699 hash_iterate(route_map_dep_hash
[i
], route_map_clear_reference
,
1704 static void *route_map_dep_hash_alloc(void *p
)
1706 char *dep_name
= (char *)p
;
1707 struct route_map_dep
*dep_entry
;
1709 dep_entry
= XCALLOC(MTYPE_ROUTE_MAP_DEP
, sizeof(struct route_map_dep
));
1710 dep_entry
->dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1711 dep_entry
->dep_rmap_hash
=
1712 hash_create_size(8, route_map_dep_hash_make_key
,
1713 route_map_rmap_hash_cmp
, "Route Map Dep Hash");
1714 dep_entry
->this_hash
= NULL
;
1716 return ((void *)dep_entry
);
1719 static void *route_map_name_hash_alloc(void *p
)
1721 return ((void *)XSTRDUP(MTYPE_ROUTE_MAP_NAME
, (const char *)p
));
1724 static unsigned int route_map_dep_hash_make_key(void *p
)
1726 return (string_hash_make((char *)p
));
1729 static void route_map_print_dependency(struct hash_bucket
*bucket
, void *data
)
1731 char *rmap_name
= (char *)bucket
->data
;
1732 char *dep_name
= (char *)data
;
1734 zlog_debug("%s: Dependency for %s: %s", __FUNCTION__
, dep_name
,
1738 static int route_map_dep_update(struct hash
*dephash
, const char *dep_name
,
1739 const char *rmap_name
, route_map_event_t type
)
1741 struct route_map_dep
*dep
= NULL
;
1743 char *dname
, *rname
;
1746 dname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1747 rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
1750 case RMAP_EVENT_PLIST_ADDED
:
1751 case RMAP_EVENT_CLIST_ADDED
:
1752 case RMAP_EVENT_ECLIST_ADDED
:
1753 case RMAP_EVENT_ASLIST_ADDED
:
1754 case RMAP_EVENT_LLIST_ADDED
:
1755 case RMAP_EVENT_CALL_ADDED
:
1756 case RMAP_EVENT_FILTER_ADDED
:
1758 zlog_debug("%s: Adding dependency for %s in %s",
1759 __FUNCTION__
, dep_name
, rmap_name
);
1760 dep
= (struct route_map_dep
*)hash_get(
1761 dephash
, dname
, route_map_dep_hash_alloc
);
1767 if (!dep
->this_hash
)
1768 dep
->this_hash
= dephash
;
1770 hash_get(dep
->dep_rmap_hash
, rname
, route_map_name_hash_alloc
);
1772 case RMAP_EVENT_PLIST_DELETED
:
1773 case RMAP_EVENT_CLIST_DELETED
:
1774 case RMAP_EVENT_ECLIST_DELETED
:
1775 case RMAP_EVENT_ASLIST_DELETED
:
1776 case RMAP_EVENT_LLIST_DELETED
:
1777 case RMAP_EVENT_CALL_DELETED
:
1778 case RMAP_EVENT_FILTER_DELETED
:
1780 zlog_debug("%s: Deleting dependency for %s in %s",
1781 __FUNCTION__
, dep_name
, rmap_name
);
1782 dep
= (struct route_map_dep
*)hash_get(dephash
, dname
, NULL
);
1787 ret_map_name
= (char *)hash_release(dep
->dep_rmap_hash
, rname
);
1788 XFREE(MTYPE_ROUTE_MAP_NAME
, ret_map_name
);
1790 if (!dep
->dep_rmap_hash
->count
) {
1791 dep
= hash_release(dephash
, dname
);
1792 hash_free(dep
->dep_rmap_hash
);
1793 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
1794 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
1804 hash_iterate(dep
->dep_rmap_hash
,
1805 route_map_print_dependency
, dname
);
1809 XFREE(MTYPE_ROUTE_MAP_NAME
, rname
);
1810 XFREE(MTYPE_ROUTE_MAP_NAME
, dname
);
1814 static struct hash
*route_map_get_dep_hash(route_map_event_t event
)
1816 struct hash
*upd8_hash
= NULL
;
1819 case RMAP_EVENT_PLIST_ADDED
:
1820 case RMAP_EVENT_PLIST_DELETED
:
1821 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_PLIST
];
1823 case RMAP_EVENT_CLIST_ADDED
:
1824 case RMAP_EVENT_CLIST_DELETED
:
1825 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_CLIST
];
1827 case RMAP_EVENT_ECLIST_ADDED
:
1828 case RMAP_EVENT_ECLIST_DELETED
:
1829 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ECLIST
];
1831 case RMAP_EVENT_ASLIST_ADDED
:
1832 case RMAP_EVENT_ASLIST_DELETED
:
1833 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ASPATH
];
1835 case RMAP_EVENT_LLIST_ADDED
:
1836 case RMAP_EVENT_LLIST_DELETED
:
1837 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_LCLIST
];
1839 case RMAP_EVENT_CALL_ADDED
:
1840 case RMAP_EVENT_CALL_DELETED
:
1841 case RMAP_EVENT_MATCH_ADDED
:
1842 case RMAP_EVENT_MATCH_DELETED
:
1843 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_RMAP
];
1845 case RMAP_EVENT_FILTER_ADDED
:
1846 case RMAP_EVENT_FILTER_DELETED
:
1847 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_FILTER
];
1856 static void route_map_process_dependency(struct hash_bucket
*bucket
, void *data
)
1858 char *rmap_name
= (char *)bucket
->data
;
1859 route_map_event_t type
= (route_map_event_t
)(ptrdiff_t)data
;
1862 zlog_debug("%s: Notifying %s of dependency",
1863 __FUNCTION__
, rmap_name
);
1864 if (route_map_master
.event_hook
)
1865 (*route_map_master
.event_hook
)(type
, rmap_name
);
1868 void route_map_upd8_dependency(route_map_event_t type
, const char *arg
,
1869 const char *rmap_name
)
1871 struct hash
*upd8_hash
= NULL
;
1873 if ((upd8_hash
= route_map_get_dep_hash(type
))) {
1874 route_map_dep_update(upd8_hash
, arg
, rmap_name
, type
);
1876 if (type
== RMAP_EVENT_CALL_ADDED
) {
1878 if (route_map_master
.add_hook
)
1879 (*route_map_master
.add_hook
)(rmap_name
);
1880 } else if (type
== RMAP_EVENT_CALL_DELETED
) {
1882 if (route_map_master
.delete_hook
)
1883 (*route_map_master
.delete_hook
)(rmap_name
);
1888 void route_map_notify_dependencies(const char *affected_name
,
1889 route_map_event_t event
)
1891 struct route_map_dep
*dep
;
1892 struct hash
*upd8_hash
;
1898 name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, affected_name
);
1900 if ((upd8_hash
= route_map_get_dep_hash(event
)) == NULL
) {
1901 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
1905 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, name
, NULL
);
1907 if (!dep
->this_hash
)
1908 dep
->this_hash
= upd8_hash
;
1910 hash_iterate(dep
->dep_rmap_hash
, route_map_process_dependency
,
1914 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
1918 /* VTY related functions. */
1919 DEFUN (match_interface
,
1920 match_interface_cmd
,
1921 "match interface WORD",
1923 "match first hop interface of route\n"
1927 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1929 if (rmap_match_set_hook
.match_interface
)
1930 return rmap_match_set_hook
.match_interface(
1931 vty
, index
, "interface", argv
[idx_word
]->arg
,
1932 RMAP_EVENT_MATCH_ADDED
);
1936 DEFUN (no_match_interface
,
1937 no_match_interface_cmd
,
1938 "no match interface [WORD]",
1941 "Match first hop interface of route\n"
1944 char *iface
= (argc
== 4) ? argv
[3]->arg
: NULL
;
1945 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1947 if (rmap_match_set_hook
.no_match_interface
)
1948 return rmap_match_set_hook
.no_match_interface(
1949 vty
, index
, "interface", iface
,
1950 RMAP_EVENT_MATCH_DELETED
);
1955 DEFUN (match_ip_address
,
1956 match_ip_address_cmd
,
1957 "match ip address <(1-199)|(1300-2699)|WORD>",
1960 "Match address of route\n"
1961 "IP access-list number\n"
1962 "IP access-list number (expanded range)\n"
1963 "IP Access-list name\n")
1966 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1968 if (rmap_match_set_hook
.match_ip_address
)
1969 return rmap_match_set_hook
.match_ip_address(
1970 vty
, index
, "ip address", argv
[idx_acl
]->arg
,
1971 RMAP_EVENT_FILTER_ADDED
);
1976 DEFUN (no_match_ip_address
,
1977 no_match_ip_address_cmd
,
1978 "no match ip address [<(1-199)|(1300-2699)|WORD>]",
1982 "Match address of route\n"
1983 "IP access-list number\n"
1984 "IP access-list number (expanded range)\n"
1985 "IP Access-list name\n")
1988 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1990 if (rmap_match_set_hook
.no_match_ip_address
) {
1991 if (argc
<= idx_word
)
1992 return rmap_match_set_hook
.no_match_ip_address(
1993 vty
, index
, "ip address", NULL
,
1994 RMAP_EVENT_FILTER_DELETED
);
1995 return rmap_match_set_hook
.no_match_ip_address(
1996 vty
, index
, "ip address", argv
[idx_word
]->arg
,
1997 RMAP_EVENT_FILTER_DELETED
);
2003 DEFUN (match_ip_address_prefix_list
,
2004 match_ip_address_prefix_list_cmd
,
2005 "match ip address prefix-list WORD",
2008 "Match address of route\n"
2009 "Match entries of prefix-lists\n"
2010 "IP prefix-list name\n")
2013 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2015 if (rmap_match_set_hook
.match_ip_address_prefix_list
)
2016 return rmap_match_set_hook
.match_ip_address_prefix_list(
2017 vty
, index
, "ip address prefix-list",
2018 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
2023 DEFUN (no_match_ip_address_prefix_list
,
2024 no_match_ip_address_prefix_list_cmd
,
2025 "no match ip address prefix-list [WORD]",
2029 "Match address of route\n"
2030 "Match entries of prefix-lists\n"
2031 "IP prefix-list name\n")
2034 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2036 if (rmap_match_set_hook
.no_match_ip_address_prefix_list
) {
2037 if (argc
<= idx_word
)
2038 return rmap_match_set_hook
2039 .no_match_ip_address_prefix_list(
2040 vty
, index
, "ip address prefix-list",
2041 NULL
, RMAP_EVENT_PLIST_DELETED
);
2042 return rmap_match_set_hook
.no_match_ip_address_prefix_list(
2043 vty
, index
, "ip address prefix-list",
2044 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2050 DEFUN (match_ip_next_hop
,
2051 match_ip_next_hop_cmd
,
2052 "match ip next-hop <(1-199)|(1300-2699)|WORD>",
2055 "Match next-hop address of route\n"
2056 "IP access-list number\n"
2057 "IP access-list number (expanded range)\n"
2058 "IP Access-list name\n")
2061 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2063 if (rmap_match_set_hook
.match_ip_next_hop
)
2064 return rmap_match_set_hook
.match_ip_next_hop(
2065 vty
, index
, "ip next-hop", argv
[idx_acl
]->arg
,
2066 RMAP_EVENT_FILTER_ADDED
);
2071 DEFUN (no_match_ip_next_hop
,
2072 no_match_ip_next_hop_cmd
,
2073 "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
2077 "Match next-hop address of route\n"
2078 "IP access-list number\n"
2079 "IP access-list number (expanded range)\n"
2080 "IP Access-list name\n")
2083 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2085 if (rmap_match_set_hook
.no_match_ip_next_hop
) {
2086 if (argc
<= idx_word
)
2087 return rmap_match_set_hook
.no_match_ip_next_hop(
2088 vty
, index
, "ip next-hop", NULL
,
2089 RMAP_EVENT_FILTER_DELETED
);
2090 return rmap_match_set_hook
.no_match_ip_next_hop(
2091 vty
, index
, "ip next-hop", argv
[idx_word
]->arg
,
2092 RMAP_EVENT_FILTER_DELETED
);
2098 DEFUN (match_ip_next_hop_prefix_list
,
2099 match_ip_next_hop_prefix_list_cmd
,
2100 "match ip next-hop prefix-list WORD",
2103 "Match next-hop address of route\n"
2104 "Match entries of prefix-lists\n"
2105 "IP prefix-list name\n")
2108 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2110 if (rmap_match_set_hook
.match_ip_next_hop_prefix_list
)
2111 return rmap_match_set_hook
.match_ip_next_hop_prefix_list(
2112 vty
, index
, "ip next-hop prefix-list",
2113 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
2117 DEFUN (no_match_ip_next_hop_prefix_list
,
2118 no_match_ip_next_hop_prefix_list_cmd
,
2119 "no match ip next-hop prefix-list [WORD]",
2123 "Match next-hop address of route\n"
2124 "Match entries of prefix-lists\n"
2125 "IP prefix-list name\n")
2128 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2130 if (rmap_match_set_hook
.no_match_ip_next_hop
) {
2131 if (argc
<= idx_word
)
2132 return rmap_match_set_hook
.no_match_ip_next_hop(
2133 vty
, index
, "ip next-hop prefix-list", NULL
,
2134 RMAP_EVENT_PLIST_DELETED
);
2135 return rmap_match_set_hook
.no_match_ip_next_hop(
2136 vty
, index
, "ip next-hop prefix-list",
2137 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2142 DEFUN(match_ip_next_hop_type
, match_ip_next_hop_type_cmd
,
2143 "match ip next-hop type <blackhole>",
2145 "Match next-hop address of route\n"
2146 "Match entries by type\n"
2150 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2152 if (rmap_match_set_hook
.match_ip_next_hop_type
)
2153 return rmap_match_set_hook
.match_ip_next_hop_type(
2154 vty
, index
, "ip next-hop type", argv
[idx_word
]->arg
,
2155 RMAP_EVENT_MATCH_ADDED
);
2159 DEFUN(no_match_ip_next_hop_type
, no_match_ip_next_hop_type_cmd
,
2160 "no match ip next-hop type [<blackhole>]",
2161 NO_STR MATCH_STR IP_STR
2162 "Match next-hop address of route\n"
2163 "Match entries by type\n"
2167 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2169 if (rmap_match_set_hook
.no_match_ip_next_hop
) {
2170 if (argc
<= idx_word
)
2171 return rmap_match_set_hook
.no_match_ip_next_hop(
2172 vty
, index
, "ip next-hop type", NULL
,
2173 RMAP_EVENT_MATCH_DELETED
);
2174 return rmap_match_set_hook
.no_match_ip_next_hop(
2175 vty
, index
, "ip next-hop type", argv
[idx_word
]->arg
,
2176 RMAP_EVENT_MATCH_DELETED
);
2182 DEFUN (match_ipv6_address
,
2183 match_ipv6_address_cmd
,
2184 "match ipv6 address WORD",
2187 "Match IPv6 address of route\n"
2188 "IPv6 access-list name\n")
2191 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2193 if (rmap_match_set_hook
.match_ipv6_address
)
2194 return rmap_match_set_hook
.match_ipv6_address(
2195 vty
, index
, "ipv6 address", argv
[idx_word
]->arg
,
2196 RMAP_EVENT_FILTER_ADDED
);
2200 DEFUN (no_match_ipv6_address
,
2201 no_match_ipv6_address_cmd
,
2202 "no match ipv6 address WORD",
2206 "Match IPv6 address of route\n"
2207 "IPv6 access-list name\n")
2210 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2212 if (rmap_match_set_hook
.no_match_ipv6_address
)
2213 return rmap_match_set_hook
.no_match_ipv6_address(
2214 vty
, index
, "ipv6 address", argv
[idx_word
]->arg
,
2215 RMAP_EVENT_FILTER_DELETED
);
2220 DEFUN (match_ipv6_address_prefix_list
,
2221 match_ipv6_address_prefix_list_cmd
,
2222 "match ipv6 address prefix-list WORD",
2225 "Match address of route\n"
2226 "Match entries of prefix-lists\n"
2227 "IP prefix-list name\n")
2230 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2232 if (rmap_match_set_hook
.match_ipv6_address_prefix_list
)
2233 return rmap_match_set_hook
.match_ipv6_address_prefix_list(
2234 vty
, index
, "ipv6 address prefix-list",
2235 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
2239 DEFUN (no_match_ipv6_address_prefix_list
,
2240 no_match_ipv6_address_prefix_list_cmd
,
2241 "no match ipv6 address prefix-list WORD",
2245 "Match address of route\n"
2246 "Match entries of prefix-lists\n"
2247 "IP prefix-list name\n")
2250 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2252 if (rmap_match_set_hook
.no_match_ipv6_address_prefix_list
)
2253 return rmap_match_set_hook
.no_match_ipv6_address_prefix_list(
2254 vty
, index
, "ipv6 address prefix-list",
2255 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2259 DEFUN(match_ipv6_next_hop_type
, match_ipv6_next_hop_type_cmd
,
2260 "match ipv6 next-hop type <blackhole>",
2262 "Match next-hop address of route\n"
2263 "Match entries by type\n"
2267 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2269 if (rmap_match_set_hook
.match_ipv6_next_hop_type
)
2270 return rmap_match_set_hook
.match_ipv6_next_hop_type(
2271 vty
, index
, "ipv6 next-hop type", argv
[idx_word
]->arg
,
2272 RMAP_EVENT_MATCH_ADDED
);
2276 DEFUN(no_match_ipv6_next_hop_type
, no_match_ipv6_next_hop_type_cmd
,
2277 "no match ipv6 next-hop type [<blackhole>]",
2278 NO_STR MATCH_STR IPV6_STR
2279 "Match address of route\n"
2280 "Match entries by type\n"
2284 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2286 if (rmap_match_set_hook
.no_match_ipv6_next_hop_type
)
2287 return rmap_match_set_hook
.no_match_ipv6_next_hop_type(
2288 vty
, index
, "ipv6 next-hop type",
2289 (argc
<= idx_word
) ? NULL
: argv
[idx_word
]->arg
,
2290 RMAP_EVENT_MATCH_DELETED
);
2294 DEFUN (match_metric
,
2296 "match metric (0-4294967295)",
2298 "Match metric of route\n"
2302 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2304 if (rmap_match_set_hook
.match_metric
)
2305 return rmap_match_set_hook
.match_metric(vty
, index
, "metric",
2306 argv
[idx_number
]->arg
,
2307 RMAP_EVENT_MATCH_ADDED
);
2312 DEFUN (no_match_metric
,
2313 no_match_metric_cmd
,
2314 "no match metric [(0-4294967295)]",
2317 "Match metric of route\n"
2321 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2323 if (rmap_match_set_hook
.no_match_metric
) {
2324 if (argc
<= idx_number
)
2325 return rmap_match_set_hook
.no_match_metric(
2326 vty
, index
, "metric", NULL
,
2327 RMAP_EVENT_MATCH_DELETED
);
2328 return rmap_match_set_hook
.no_match_metric(
2329 vty
, index
, "metric", argv
[idx_number
]->arg
,
2330 RMAP_EVENT_MATCH_DELETED
);
2338 "match tag (1-4294967295)",
2340 "Match tag of route\n"
2344 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2346 if (rmap_match_set_hook
.match_tag
)
2347 return rmap_match_set_hook
.match_tag(vty
, index
, "tag",
2348 argv
[idx_number
]->arg
,
2349 RMAP_EVENT_MATCH_ADDED
);
2354 DEFUN (no_match_tag
,
2356 "no match tag [(1-4294967295)]",
2359 "Match tag of route\n"
2362 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2365 char *arg
= argv_find(argv
, argc
, "(1-4294967295)", &idx
)
2369 if (rmap_match_set_hook
.no_match_tag
)
2370 return rmap_match_set_hook
.no_match_tag(
2371 vty
, index
, "tag", arg
, RMAP_EVENT_MATCH_DELETED
);
2376 DEFUN (set_ip_nexthop
,
2378 "set ip next-hop A.B.C.D",
2381 "Next hop address\n"
2382 "IP address of next hop\n")
2387 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2389 ret
= str2sockunion(argv
[idx_ipv4
]->arg
, &su
);
2391 vty_out(vty
, "%% Malformed nexthop address\n");
2392 return CMD_WARNING_CONFIG_FAILED
;
2394 if (su
.sin
.sin_addr
.s_addr
== 0
2395 || IPV4_CLASS_DE(ntohl(su
.sin
.sin_addr
.s_addr
))) {
2397 "%% nexthop address cannot be 0.0.0.0, multicast or reserved\n");
2398 return CMD_WARNING_CONFIG_FAILED
;
2401 if (rmap_match_set_hook
.set_ip_nexthop
)
2402 return rmap_match_set_hook
.set_ip_nexthop(
2403 vty
, index
, "ip next-hop", argv
[idx_ipv4
]->arg
);
2408 DEFUN (no_set_ip_nexthop
,
2409 no_set_ip_nexthop_cmd
,
2410 "no set ip next-hop [A.B.C.D]",
2414 "Next hop address\n"
2415 "IP address of next hop\n")
2418 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2419 const char *arg
= NULL
;
2421 if (argv_find(argv
, argc
, "A.B.C.D", &idx
))
2422 arg
= argv
[idx
]->arg
;
2424 if (rmap_match_set_hook
.no_set_ip_nexthop
)
2425 return rmap_match_set_hook
.no_set_ip_nexthop(
2426 vty
, index
, "ip next-hop", arg
);
2432 DEFUN (set_ipv6_nexthop_local
,
2433 set_ipv6_nexthop_local_cmd
,
2434 "set ipv6 next-hop local X:X::X:X",
2437 "IPv6 next-hop address\n"
2438 "IPv6 local address\n"
2439 "IPv6 address of next hop\n")
2442 struct in6_addr addr
;
2444 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2446 ret
= inet_pton(AF_INET6
, argv
[idx_ipv6
]->arg
, &addr
);
2448 vty_out(vty
, "%% Malformed nexthop address\n");
2449 return CMD_WARNING_CONFIG_FAILED
;
2451 if (!IN6_IS_ADDR_LINKLOCAL(&addr
)) {
2452 vty_out(vty
, "%% Invalid link-local nexthop address\n");
2453 return CMD_WARNING_CONFIG_FAILED
;
2456 if (rmap_match_set_hook
.set_ipv6_nexthop_local
)
2457 return rmap_match_set_hook
.set_ipv6_nexthop_local(
2458 vty
, index
, "ipv6 next-hop local", argv
[idx_ipv6
]->arg
);
2463 DEFUN (no_set_ipv6_nexthop_local
,
2464 no_set_ipv6_nexthop_local_cmd
,
2465 "no set ipv6 next-hop local [X:X::X:X]",
2469 "IPv6 next-hop address\n"
2470 "IPv6 local address\n"
2471 "IPv6 address of next hop\n")
2474 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2476 if (rmap_match_set_hook
.no_set_ipv6_nexthop_local
) {
2477 if (argc
<= idx_ipv6
)
2478 return rmap_match_set_hook
.no_set_ipv6_nexthop_local(
2479 vty
, index
, "ipv6 next-hop local", NULL
);
2480 return rmap_match_set_hook
.no_set_ipv6_nexthop_local(
2481 vty
, index
, "ipv6 next-hop local", argv
[5]->arg
);
2488 "set metric <(0-4294967295)|rtt|+rtt|-rtt|+metric|-metric>",
2490 "Metric value for destination routing protocol\n"
2492 "Assign round trip time\n"
2493 "Add round trip time\n"
2494 "Subtract round trip time\n"
2496 "Subtract metric\n")
2499 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2501 const char *pass
= (argv
[idx_number
]->type
== RANGE_TKN
)
2502 ? argv
[idx_number
]->arg
2503 : argv
[idx_number
]->text
;
2505 if (rmap_match_set_hook
.set_metric
)
2506 return rmap_match_set_hook
.set_metric(vty
, index
, "metric",
2512 DEFUN (no_set_metric
,
2514 "no set metric [(0-4294967295)]",
2517 "Metric value for destination routing protocol\n"
2521 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2523 if (rmap_match_set_hook
.no_set_metric
) {
2524 if (argc
<= idx_number
)
2525 return rmap_match_set_hook
.no_set_metric(
2526 vty
, index
, "metric", NULL
);
2527 return rmap_match_set_hook
.no_set_metric(vty
, index
, "metric",
2528 argv
[idx_number
]->arg
);
2536 "set tag (1-4294967295)",
2538 "Tag value for routing protocol\n"
2541 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2544 if (rmap_match_set_hook
.set_tag
)
2545 return rmap_match_set_hook
.set_tag(vty
, index
, "tag",
2546 argv
[idx_number
]->arg
);
2553 "no set tag [(1-4294967295)]",
2556 "Tag value for routing protocol\n"
2559 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2562 if (rmap_match_set_hook
.no_set_tag
) {
2563 if (argc
<= idx_number
)
2564 return rmap_match_set_hook
.no_set_tag(vty
, index
, "tag",
2566 return rmap_match_set_hook
.no_set_tag(vty
, index
, "tag",
2567 argv
[idx_number
]->arg
);
2573 DEFUN_NOSH (route_map
,
2575 "route-map WORD <deny|permit> (1-65535)",
2576 "Create route-map or enter route-map command mode\n"
2578 "Route map denies set operations\n"
2579 "Route map permits set operations\n"
2580 "Sequence to insert to/delete from existing route-map entry\n")
2583 int idx_permit_deny
= 2;
2585 struct route_map
*map
;
2586 struct route_map_index
*index
;
2587 char *endptr
= NULL
;
2589 argv
[idx_permit_deny
]->arg
[0] == 'p' ? RMAP_PERMIT
: RMAP_DENY
;
2590 unsigned long pref
= strtoul(argv
[idx_number
]->arg
, &endptr
, 10);
2591 const char *mapname
= argv
[idx_word
]->arg
;
2593 /* Get route map. */
2594 map
= route_map_get(mapname
);
2595 index
= route_map_index_get(map
, permit
, pref
);
2597 VTY_PUSH_CONTEXT(RMAP_NODE
, index
);
2601 DEFUN (no_route_map_all
,
2602 no_route_map_all_cmd
,
2603 "no route-map WORD",
2605 "Create route-map or enter route-map command mode\n"
2609 const char *mapname
= argv
[idx_word
]->arg
;
2610 struct route_map
*map
;
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 route_map_delete(map
);
2623 DEFUN (no_route_map
,
2625 "no route-map WORD <deny|permit> (1-65535)",
2627 "Create route-map or enter route-map command mode\n"
2629 "Route map denies set operations\n"
2630 "Route map permits set operations\n"
2631 "Sequence to insert to/delete from existing route-map entry\n")
2634 int idx_permit_deny
= 3;
2636 struct route_map
*map
;
2637 struct route_map_index
*index
;
2638 char *endptr
= NULL
;
2639 int permit
= strmatch(argv
[idx_permit_deny
]->text
, "permit")
2642 const char *prefstr
= argv
[idx_number
]->arg
;
2643 const char *mapname
= argv
[idx_word
]->arg
;
2644 unsigned long pref
= strtoul(prefstr
, &endptr
, 10);
2646 /* Existence check. */
2647 map
= route_map_lookup_by_name(mapname
);
2649 vty_out(vty
, "%% Could not find route-map %s\n", mapname
);
2650 return CMD_WARNING_CONFIG_FAILED
;
2653 /* Lookup route map index. */
2654 index
= route_map_index_lookup(map
, permit
, pref
);
2655 if (index
== NULL
) {
2656 vty_out(vty
, "%% Could not find route-map entry %s %s\n",
2658 return CMD_WARNING_CONFIG_FAILED
;
2661 /* Delete index from route map. */
2662 route_map_index_delete(index
, 1);
2664 /* If this route rule is the last one, delete route map itself. */
2665 if (route_map_empty(map
))
2666 route_map_delete(map
);
2671 DEFUN (rmap_onmatch_next
,
2672 rmap_onmatch_next_cmd
,
2674 "Exit policy on matches\n"
2677 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2680 if (index
->type
== RMAP_DENY
) {
2681 /* Under a deny clause, match means it's finished. No
2682 * need to set next */
2684 "on-match next not supported under route-map deny\n");
2685 return CMD_WARNING_CONFIG_FAILED
;
2687 index
->exitpolicy
= RMAP_NEXT
;
2692 DEFUN (no_rmap_onmatch_next
,
2693 no_rmap_onmatch_next_cmd
,
2696 "Exit policy on matches\n"
2699 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2702 index
->exitpolicy
= RMAP_EXIT
;
2707 DEFUN (rmap_onmatch_goto
,
2708 rmap_onmatch_goto_cmd
,
2709 "on-match goto (1-65535)",
2710 "Exit policy on matches\n"
2711 "Goto Clause number\n"
2715 char *num
= argv_find(argv
, argc
, "(1-65535)", &idx
) ? argv
[idx
]->arg
2718 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2722 if (index
->type
== RMAP_DENY
) {
2723 /* Under a deny clause, match means it's finished. No
2724 * need to go anywhere */
2726 "on-match goto not supported under route-map deny\n");
2727 return CMD_WARNING_CONFIG_FAILED
;
2731 d
= strtoul(num
, NULL
, 10);
2733 d
= index
->pref
+ 1;
2735 if (d
<= index
->pref
) {
2736 /* Can't allow you to do that, Dave */
2737 vty_out(vty
, "can't jump backwards in route-maps\n");
2738 return CMD_WARNING_CONFIG_FAILED
;
2740 index
->exitpolicy
= RMAP_GOTO
;
2741 index
->nextpref
= d
;
2747 DEFUN (no_rmap_onmatch_goto
,
2748 no_rmap_onmatch_goto_cmd
,
2751 "Exit policy on matches\n"
2752 "Goto Clause number\n")
2754 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2757 index
->exitpolicy
= RMAP_EXIT
;
2762 /* Cisco/GNU Zebra compatibility aliases */
2764 DEFUN (rmap_continue
,
2766 "continue (1-65535)",
2767 "Continue on a different entry within the route-map\n"
2768 "Route-map entry sequence number\n")
2770 return rmap_onmatch_goto(self
, vty
, argc
, argv
);
2774 DEFUN (no_rmap_continue
,
2775 no_rmap_continue_cmd
,
2776 "no continue [(1-65535)]",
2778 "Continue on a different entry within the route-map\n"
2779 "Route-map entry sequence number\n")
2781 return no_rmap_onmatch_goto(self
, vty
, argc
, argv
);
2785 DEFUN (rmap_show_name
,
2787 "show route-map [WORD]",
2789 "route-map information\n"
2793 const char *name
= (argc
== 3) ? argv
[idx_word
]->arg
: NULL
;
2794 return vty_show_route_map(vty
, name
);
2797 DEFUN (rmap_show_unused
,
2798 rmap_show_unused_cmd
,
2799 "show route-map-unused",
2801 "unused route-map information\n")
2803 return vty_show_unused_route_map(vty
);
2809 "Jump to another Route-Map after match+set\n"
2810 "Target route-map name\n")
2813 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2814 const char *rmap
= argv
[idx_word
]->arg
;
2818 /* If "call" is invoked with the same route-map name as
2819 * the one previously configured then, ignore the duplicate
2822 if (index
->nextrm
&& (strcmp(index
->nextrm
, rmap
) == 0))
2825 if (index
->nextrm
) {
2826 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED
,
2827 index
->nextrm
, index
->map
->name
);
2828 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
2830 index
->nextrm
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap
);
2832 /* Execute event hook. */
2833 route_map_upd8_dependency(RMAP_EVENT_CALL_ADDED
, index
->nextrm
,
2838 DEFUN (no_rmap_call
,
2842 "Jump to another Route-Map after match+set\n")
2844 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2846 if (index
->nextrm
) {
2847 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED
,
2848 index
->nextrm
, index
->map
->name
);
2849 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
2850 index
->nextrm
= NULL
;
2856 DEFUN (rmap_description
,
2857 rmap_description_cmd
,
2858 "description LINE...",
2859 "Route-map comment\n"
2860 "Comment describing this route-map rule\n")
2863 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2866 if (index
->description
)
2867 XFREE(MTYPE_TMP
, index
->description
);
2868 index
->description
= argv_concat(argv
, argc
, idx_line
);
2873 DEFUN (no_rmap_description
,
2874 no_rmap_description_cmd
,
2877 "Route-map comment\n")
2879 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2882 if (index
->description
)
2883 XFREE(MTYPE_TMP
, index
->description
);
2884 index
->description
= NULL
;
2889 /* Configuration write function. */
2890 static int route_map_config_write(struct vty
*vty
)
2892 struct route_map
*map
;
2893 struct route_map_index
*index
;
2894 struct route_map_rule
*rule
;
2898 for (map
= route_map_master
.head
; map
; map
= map
->next
)
2899 for (index
= map
->head
; index
; index
= index
->next
) {
2901 vty_out(vty
, "!\n");
2905 vty_out(vty
, "route-map %s %s %d\n", map
->name
,
2906 route_map_type_str(index
->type
), index
->pref
);
2908 if (index
->description
)
2909 vty_out(vty
, " description %s\n",
2910 index
->description
);
2912 for (rule
= index
->match_list
.head
; rule
;
2914 vty_out(vty
, " match %s %s\n", rule
->cmd
->str
,
2915 rule
->rule_str
? rule
->rule_str
: "");
2917 for (rule
= index
->set_list
.head
; rule
;
2919 vty_out(vty
, " set %s %s\n", rule
->cmd
->str
,
2920 rule
->rule_str
? rule
->rule_str
: "");
2922 vty_out(vty
, " call %s\n", index
->nextrm
);
2923 if (index
->exitpolicy
== RMAP_GOTO
)
2924 vty_out(vty
, " on-match goto %d\n",
2926 if (index
->exitpolicy
== RMAP_NEXT
)
2927 vty_out(vty
, " on-match next\n");
2934 /* Route map node structure. */
2935 static struct cmd_node rmap_node
= {RMAP_NODE
, "%s(config-route-map)# ", 1};
2937 /* Common route map rules */
2939 void *route_map_rule_tag_compile(const char *arg
)
2941 unsigned long int tmp
;
2946 tmp
= strtoul(arg
, &endptr
, 0);
2947 if (arg
[0] == '\0' || *endptr
!= '\0' || errno
|| tmp
> ROUTE_TAG_MAX
)
2950 tag
= XMALLOC(MTYPE_ROUTE_MAP_COMPILED
, sizeof(*tag
));
2956 void route_map_rule_tag_free(void *rule
)
2958 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
2961 void route_map_finish(void)
2965 vector_free(route_match_vec
);
2966 route_match_vec
= NULL
;
2967 vector_free(route_set_vec
);
2968 route_set_vec
= NULL
;
2971 * All protocols are setting these to NULL
2972 * by default on shutdown( route_map_finish )
2973 * Why are we making them do this work?
2975 route_map_master
.add_hook
= NULL
;
2976 route_map_master
.delete_hook
= NULL
;
2977 route_map_master
.event_hook
= NULL
;
2979 /* cleanup route_map */
2980 while (route_map_master
.head
) {
2981 struct route_map
*map
= route_map_master
.head
;
2982 map
->to_be_processed
= false;
2983 route_map_delete(map
);
2986 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
2987 hash_free(route_map_dep_hash
[i
]);
2988 route_map_dep_hash
[i
] = NULL
;
2991 hash_free(route_map_master_hash
);
2992 route_map_master_hash
= NULL
;
2995 static void rmap_autocomplete(vector comps
, struct cmd_token
*token
)
2997 struct route_map
*map
;
2999 for (map
= route_map_master
.head
; map
; map
= map
->next
)
3000 vector_set(comps
, XSTRDUP(MTYPE_COMPLETION
, map
->name
));
3003 /* Increment the use_count counter while attaching the route map */
3004 void route_map_counter_increment(struct route_map
*map
)
3010 /* Decrement the use_count counter while detaching the route map. */
3011 void route_map_counter_decrement(struct route_map
*map
)
3014 if (map
->use_count
<= 0)
3020 static const struct cmd_variable_handler rmap_var_handlers
[] = {
3021 {/* "route-map WORD" */
3022 .varname
= "route_map",
3023 .completions
= rmap_autocomplete
},
3024 {.tokenname
= "ROUTEMAP_NAME", .completions
= rmap_autocomplete
},
3025 {.tokenname
= "RMAP_NAME", .completions
= rmap_autocomplete
},
3026 {.completions
= NULL
}};
3028 /* Initialization of route map vector. */
3029 void route_map_init(void)
3033 /* Make vector for match and set. */
3034 route_match_vec
= vector_init(1);
3035 route_set_vec
= vector_init(1);
3036 route_map_master_hash
=
3037 hash_create_size(8, route_map_hash_key_make
, route_map_hash_cmp
,
3038 "Route Map Master Hash");
3040 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++)
3041 route_map_dep_hash
[i
] = hash_create_size(
3042 8, route_map_dep_hash_make_key
, route_map_dep_hash_cmp
,
3043 "Route Map Dep Hash");
3045 cmd_variable_handler_register(rmap_var_handlers
);
3047 /* Install route map top node. */
3048 install_node(&rmap_node
, route_map_config_write
);
3050 /* Install route map commands. */
3051 install_default(RMAP_NODE
);
3052 install_element(CONFIG_NODE
, &route_map_cmd
);
3053 install_element(CONFIG_NODE
, &no_route_map_cmd
);
3054 install_element(CONFIG_NODE
, &no_route_map_all_cmd
);
3056 /* Install the on-match stuff */
3057 install_element(RMAP_NODE
, &route_map_cmd
);
3058 install_element(RMAP_NODE
, &rmap_onmatch_next_cmd
);
3059 install_element(RMAP_NODE
, &no_rmap_onmatch_next_cmd
);
3060 install_element(RMAP_NODE
, &rmap_onmatch_goto_cmd
);
3061 install_element(RMAP_NODE
, &no_rmap_onmatch_goto_cmd
);
3062 install_element(RMAP_NODE
, &rmap_continue_cmd
);
3063 install_element(RMAP_NODE
, &no_rmap_continue_cmd
);
3065 /* Install the continue stuff (ALIAS of on-match). */
3067 /* Install the call stuff. */
3068 install_element(RMAP_NODE
, &rmap_call_cmd
);
3069 install_element(RMAP_NODE
, &no_rmap_call_cmd
);
3071 /* Install description commands. */
3072 install_element(RMAP_NODE
, &rmap_description_cmd
);
3073 install_element(RMAP_NODE
, &no_rmap_description_cmd
);
3075 /* Install show command */
3076 install_element(ENABLE_NODE
, &rmap_show_name_cmd
);
3077 install_element(ENABLE_NODE
, &rmap_show_unused_cmd
);
3079 install_element(RMAP_NODE
, &match_interface_cmd
);
3080 install_element(RMAP_NODE
, &no_match_interface_cmd
);
3082 install_element(RMAP_NODE
, &match_ip_address_cmd
);
3083 install_element(RMAP_NODE
, &no_match_ip_address_cmd
);
3085 install_element(RMAP_NODE
, &match_ip_address_prefix_list_cmd
);
3086 install_element(RMAP_NODE
, &no_match_ip_address_prefix_list_cmd
);
3088 install_element(RMAP_NODE
, &match_ip_next_hop_cmd
);
3089 install_element(RMAP_NODE
, &no_match_ip_next_hop_cmd
);
3091 install_element(RMAP_NODE
, &match_ip_next_hop_prefix_list_cmd
);
3092 install_element(RMAP_NODE
, &no_match_ip_next_hop_prefix_list_cmd
);
3094 install_element(RMAP_NODE
, &match_ip_next_hop_type_cmd
);
3095 install_element(RMAP_NODE
, &no_match_ip_next_hop_type_cmd
);
3097 install_element(RMAP_NODE
, &match_ipv6_address_cmd
);
3098 install_element(RMAP_NODE
, &no_match_ipv6_address_cmd
);
3100 install_element(RMAP_NODE
, &match_ipv6_address_prefix_list_cmd
);
3101 install_element(RMAP_NODE
, &no_match_ipv6_address_prefix_list_cmd
);
3103 install_element(RMAP_NODE
, &match_ipv6_next_hop_type_cmd
);
3104 install_element(RMAP_NODE
, &no_match_ipv6_next_hop_type_cmd
);
3106 install_element(RMAP_NODE
, &match_metric_cmd
);
3107 install_element(RMAP_NODE
, &no_match_metric_cmd
);
3109 install_element(RMAP_NODE
, &match_tag_cmd
);
3110 install_element(RMAP_NODE
, &no_match_tag_cmd
);
3112 install_element(RMAP_NODE
, &set_ip_nexthop_cmd
);
3113 install_element(RMAP_NODE
, &no_set_ip_nexthop_cmd
);
3115 install_element(RMAP_NODE
, &set_ipv6_nexthop_local_cmd
);
3116 install_element(RMAP_NODE
, &no_set_ipv6_nexthop_local_cmd
);
3118 install_element(RMAP_NODE
, &set_metric_cmd
);
3119 install_element(RMAP_NODE
, &no_set_metric_cmd
);
3121 install_element(RMAP_NODE
, &set_tag_cmd
);
3122 install_element(RMAP_NODE
, &no_set_tag_cmd
);