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 int 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 int route_map_dep_hash_cmp(const void *p1
, const void *p2
);
680 static void route_map_clear_all_references(char *rmap_name
);
681 static void route_map_rule_delete(struct route_map_rule_list
*,
682 struct route_map_rule
*);
683 static int rmap_debug
= 0;
685 static void route_map_index_delete(struct route_map_index
*, int);
687 /* New route map allocation. Please note route map's name must be
689 static struct route_map
*route_map_new(const char *name
)
691 struct route_map
*new;
693 new = XCALLOC(MTYPE_ROUTE_MAP
, sizeof(struct route_map
));
694 new->name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
695 QOBJ_REG(new, route_map
);
699 /* Add new name to route_map. */
700 static struct route_map
*route_map_add(const char *name
)
702 struct route_map
*map
;
703 struct route_map_list
*list
;
705 map
= route_map_new(name
);
706 list
= &route_map_master
;
708 /* Add map to the hash */
709 hash_get(route_map_master_hash
, map
, hash_alloc_intern
);
711 /* Add new entry to the head of the list to match how it is added in the
712 * hash table. This is to ensure that if the same route-map has been
713 * created more than once and then marked for deletion (which can happen
714 * if prior deletions haven't completed as BGP hasn't yet done the
715 * route-map processing), the order of the entities is the same in both
716 * the list and the hash table. Otherwise, since there is nothing to
717 * distinguish between the two entries, the wrong entry could get freed.
718 * TODO: This needs to be re-examined to handle it better - e.g., revive
719 * a deleted entry if the route-map is created again.
722 map
->next
= list
->head
;
724 list
->head
->prev
= map
;
730 if (route_map_master
.add_hook
) {
731 (*route_map_master
.add_hook
)(name
);
732 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_ADDED
);
737 /* this is supposed to be called post processing by
738 * the delete hook function. Don't invoke delete_hook
739 * again in this routine.
741 static void route_map_free_map(struct route_map
*map
)
743 struct route_map_list
*list
;
744 struct route_map_index
*index
;
749 while ((index
= map
->head
) != NULL
)
750 route_map_index_delete(index
, 0);
752 list
= &route_map_master
;
757 map
->next
->prev
= map
->prev
;
759 list
->tail
= map
->prev
;
762 map
->prev
->next
= map
->next
;
764 list
->head
= map
->next
;
766 hash_release(route_map_master_hash
, map
);
767 XFREE(MTYPE_ROUTE_MAP_NAME
, map
->name
);
768 XFREE(MTYPE_ROUTE_MAP
, map
);
771 /* Route map delete from list. */
772 static void route_map_delete(struct route_map
*map
)
774 struct route_map_index
*index
;
777 while ((index
= map
->head
) != NULL
)
778 route_map_index_delete(index
, 0);
783 /* Clear all dependencies */
784 route_map_clear_all_references(name
);
786 /* Execute deletion hook. */
787 if (route_map_master
.delete_hook
) {
788 (*route_map_master
.delete_hook
)(name
);
789 route_map_notify_dependencies(name
, RMAP_EVENT_CALL_DELETED
);
792 if (!map
->to_be_processed
) {
793 route_map_free_map(map
);
797 /* Lookup route map by route map name string. */
798 struct route_map
*route_map_lookup_by_name(const char *name
)
800 struct route_map
*map
;
801 struct route_map tmp_map
;
806 // map.deleted is 0 via memset
807 memset(&tmp_map
, 0, sizeof(struct route_map
));
808 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
809 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
810 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
814 int route_map_mark_updated(const char *name
)
816 struct route_map
*map
;
818 struct route_map tmp_map
;
823 map
= route_map_lookup_by_name(name
);
825 /* If we did not find the routemap with deleted=false try again
829 memset(&tmp_map
, 0, sizeof(struct route_map
));
830 tmp_map
.name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, name
);
831 tmp_map
.deleted
= true;
832 map
= hash_lookup(route_map_master_hash
, &tmp_map
);
833 XFREE(MTYPE_ROUTE_MAP_NAME
, tmp_map
.name
);
837 map
->to_be_processed
= true;
844 static int route_map_clear_updated(struct route_map
*map
)
849 map
->to_be_processed
= false;
851 route_map_free_map(map
);
857 /* Lookup route map. If there isn't route map create one and return
859 static struct route_map
*route_map_get(const char *name
)
861 struct route_map
*map
;
863 map
= route_map_lookup_by_name(name
);
865 map
= route_map_add(name
);
870 void route_map_walk_update_list(void (*route_map_update_fn
)(char *name
))
872 struct route_map
*node
;
873 struct route_map
*nnode
= NULL
;
875 for (node
= route_map_master
.head
; node
; node
= nnode
) {
876 if (node
->to_be_processed
) {
877 /* DD: Should we add any thread yield code here */
878 route_map_update_fn(node
->name
);
880 route_map_clear_updated(node
);
886 /* Return route map's type string. */
887 static const char *route_map_type_str(enum route_map_type type
)
902 static int route_map_empty(struct route_map
*map
)
904 if (map
->head
== NULL
&& map
->tail
== NULL
)
911 static void vty_show_route_map_entry(struct vty
*vty
, struct route_map
*map
)
913 struct route_map_index
*index
;
914 struct route_map_rule
*rule
;
916 vty_out(vty
, "route-map: %s Invoked: %" PRIu64
"\n",
917 map
->name
, map
->applied
);
919 for (index
= map
->head
; index
; index
= index
->next
) {
920 vty_out(vty
, " %s, sequence %d Invoked %" PRIu64
"\n",
921 route_map_type_str(index
->type
), index
->pref
,
925 if (index
->description
)
926 vty_out(vty
, " Description:\n %s\n",
930 vty_out(vty
, " Match clauses:\n");
931 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
932 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
935 vty_out(vty
, " Set clauses:\n");
936 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
937 vty_out(vty
, " %s %s\n", rule
->cmd
->str
,
941 vty_out(vty
, " Call clause:\n");
943 vty_out(vty
, " Call %s\n", index
->nextrm
);
946 vty_out(vty
, " Action:\n");
947 if (index
->exitpolicy
== RMAP_GOTO
)
948 vty_out(vty
, " Goto %d\n", index
->nextpref
);
949 else if (index
->exitpolicy
== RMAP_NEXT
)
950 vty_out(vty
, " Continue to next entry\n");
951 else if (index
->exitpolicy
== RMAP_EXIT
)
952 vty_out(vty
, " Exit routemap\n");
956 static int sort_route_map(const void **map1
, const void **map2
)
958 const struct route_map
*m1
= *map1
;
959 const struct route_map
*m2
= *map2
;
961 return strcmp(m1
->name
, m2
->name
);
964 static int vty_show_route_map(struct vty
*vty
, const char *name
)
966 struct route_map
*map
;
968 vty_out(vty
, "%s:\n", frr_protonameinst
);
971 map
= route_map_lookup_by_name(name
);
974 vty_show_route_map_entry(vty
, map
);
977 vty_out(vty
, "%s: 'route-map %s' not found\n",
978 frr_protonameinst
, name
);
983 struct list
*maplist
= list_new();
986 for (map
= route_map_master
.head
; map
; map
= map
->next
)
987 listnode_add(maplist
, map
);
989 list_sort(maplist
, sort_route_map
);
991 for (ALL_LIST_ELEMENTS_RO(maplist
, ln
, map
))
992 vty_show_route_map_entry(vty
, map
);
994 list_delete(&maplist
);
1000 /* New route map allocation. Please note route map's name must be
1002 static struct route_map_index
*route_map_index_new(void)
1004 struct route_map_index
*new;
1006 new = XCALLOC(MTYPE_ROUTE_MAP_INDEX
, sizeof(struct route_map_index
));
1007 new->exitpolicy
= RMAP_EXIT
; /* Default to Cisco-style */
1008 QOBJ_REG(new, route_map_index
);
1012 /* Free route map index. */
1013 static void route_map_index_delete(struct route_map_index
*index
, int notify
)
1015 struct route_map_rule
*rule
;
1019 /* Free route match. */
1020 while ((rule
= index
->match_list
.head
) != NULL
)
1021 route_map_rule_delete(&index
->match_list
, rule
);
1023 /* Free route set. */
1024 while ((rule
= index
->set_list
.head
) != NULL
)
1025 route_map_rule_delete(&index
->set_list
, rule
);
1027 /* Remove index from route map list. */
1029 index
->next
->prev
= index
->prev
;
1031 index
->map
->tail
= index
->prev
;
1034 index
->prev
->next
= index
->next
;
1036 index
->map
->head
= index
->next
;
1038 /* Free 'char *nextrm' if not NULL */
1040 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
1042 /* Execute event hook. */
1043 if (route_map_master
.event_hook
&& notify
) {
1044 (*route_map_master
.event_hook
)(RMAP_EVENT_INDEX_DELETED
,
1046 route_map_notify_dependencies(index
->map
->name
,
1047 RMAP_EVENT_CALL_ADDED
);
1049 XFREE(MTYPE_ROUTE_MAP_INDEX
, index
);
1052 /* Lookup index from route map. */
1053 static struct route_map_index
*route_map_index_lookup(struct route_map
*map
,
1054 enum route_map_type type
,
1057 struct route_map_index
*index
;
1059 for (index
= map
->head
; index
; index
= index
->next
)
1060 if ((index
->type
== type
|| type
== RMAP_ANY
)
1061 && index
->pref
== pref
)
1066 /* Add new index to route map. */
1067 static struct route_map_index
*
1068 route_map_index_add(struct route_map
*map
, enum route_map_type type
, int pref
)
1070 struct route_map_index
*index
;
1071 struct route_map_index
*point
;
1073 /* Allocate new route map inex. */
1074 index
= route_map_index_new();
1079 /* Compare preference. */
1080 for (point
= map
->head
; point
; point
= point
->next
)
1081 if (point
->pref
>= pref
)
1084 if (map
->head
== NULL
) {
1085 map
->head
= map
->tail
= index
;
1086 } else if (point
== NULL
) {
1087 index
->prev
= map
->tail
;
1088 map
->tail
->next
= index
;
1090 } else if (point
== map
->head
) {
1091 index
->next
= map
->head
;
1092 map
->head
->prev
= index
;
1095 index
->next
= point
;
1096 index
->prev
= point
->prev
;
1098 point
->prev
->next
= index
;
1099 point
->prev
= index
;
1102 /* Execute event hook. */
1103 if (route_map_master
.event_hook
) {
1104 (*route_map_master
.event_hook
)(RMAP_EVENT_INDEX_ADDED
,
1106 route_map_notify_dependencies(map
->name
, RMAP_EVENT_CALL_ADDED
);
1111 /* Get route map index. */
1112 static struct route_map_index
*
1113 route_map_index_get(struct route_map
*map
, enum route_map_type type
, int pref
)
1115 struct route_map_index
*index
;
1117 index
= route_map_index_lookup(map
, RMAP_ANY
, pref
);
1118 if (index
&& index
->type
!= type
) {
1119 /* Delete index from route map. */
1120 route_map_index_delete(index
, 1);
1124 index
= route_map_index_add(map
, type
, pref
);
1128 /* New route map rule */
1129 static struct route_map_rule
*route_map_rule_new(void)
1131 struct route_map_rule
*new;
1133 new = XCALLOC(MTYPE_ROUTE_MAP_RULE
, sizeof(struct route_map_rule
));
1137 /* Install rule command to the match list. */
1138 void route_map_install_match(struct route_map_rule_cmd
*cmd
)
1140 vector_set(route_match_vec
, cmd
);
1143 /* Install rule command to the set list. */
1144 void route_map_install_set(struct route_map_rule_cmd
*cmd
)
1146 vector_set(route_set_vec
, cmd
);
1149 /* Lookup rule command from match list. */
1150 static struct route_map_rule_cmd
*route_map_lookup_match(const char *name
)
1153 struct route_map_rule_cmd
*rule
;
1155 for (i
= 0; i
< vector_active(route_match_vec
); i
++)
1156 if ((rule
= vector_slot(route_match_vec
, i
)) != NULL
)
1157 if (strcmp(rule
->str
, name
) == 0)
1162 /* Lookup rule command from set list. */
1163 static struct route_map_rule_cmd
*route_map_lookup_set(const char *name
)
1166 struct route_map_rule_cmd
*rule
;
1168 for (i
= 0; i
< vector_active(route_set_vec
); i
++)
1169 if ((rule
= vector_slot(route_set_vec
, i
)) != NULL
)
1170 if (strcmp(rule
->str
, name
) == 0)
1175 /* Add match and set rule to rule list. */
1176 static void route_map_rule_add(struct route_map_rule_list
*list
,
1177 struct route_map_rule
*rule
)
1180 rule
->prev
= list
->tail
;
1182 list
->tail
->next
= rule
;
1188 /* Delete rule from rule list. */
1189 static void route_map_rule_delete(struct route_map_rule_list
*list
,
1190 struct route_map_rule
*rule
)
1192 if (rule
->cmd
->func_free
)
1193 (*rule
->cmd
->func_free
)(rule
->value
);
1196 XFREE(MTYPE_ROUTE_MAP_RULE_STR
, rule
->rule_str
);
1199 rule
->next
->prev
= rule
->prev
;
1201 list
->tail
= rule
->prev
;
1203 rule
->prev
->next
= rule
->next
;
1205 list
->head
= rule
->next
;
1207 XFREE(MTYPE_ROUTE_MAP_RULE
, rule
);
1210 /* strcmp wrapper function which don't crush even argument is NULL. */
1211 static int rulecmp(const char *dst
, const char *src
)
1222 return strcmp(dst
, src
);
1227 /* Use this to return the already specified argument for this match. This is
1228 * useful to get the specified argument with a route map match rule when the
1229 * rule is being deleted and the argument is not provided.
1231 const char *route_map_get_match_arg(struct route_map_index
*index
,
1232 const char *match_name
)
1234 struct route_map_rule
*rule
;
1235 struct route_map_rule_cmd
*cmd
;
1237 /* First lookup rule for add match statement. */
1238 cmd
= route_map_lookup_match(match_name
);
1242 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1243 if (rule
->cmd
== cmd
&& rule
->rule_str
!= NULL
)
1244 return (rule
->rule_str
);
1249 /* Add match statement to route map. */
1250 int route_map_add_match(struct route_map_index
*index
, const char *match_name
,
1251 const char *match_arg
)
1253 struct route_map_rule
*rule
;
1254 struct route_map_rule
*next
;
1255 struct route_map_rule_cmd
*cmd
;
1259 /* First lookup rule for add match statement. */
1260 cmd
= route_map_lookup_match(match_name
);
1262 return RMAP_RULE_MISSING
;
1264 /* Next call compile function for this match statement. */
1265 if (cmd
->func_compile
) {
1266 compile
= (*cmd
->func_compile
)(match_arg
);
1267 if (compile
== NULL
)
1268 return RMAP_COMPILE_ERROR
;
1272 /* If argument is completely same ignore it. */
1273 for (rule
= index
->match_list
.head
; rule
; rule
= next
) {
1275 if (rule
->cmd
== cmd
) {
1276 route_map_rule_delete(&index
->match_list
, rule
);
1281 /* Add new route map match rule. */
1282 rule
= route_map_rule_new();
1284 rule
->value
= compile
;
1286 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, match_arg
);
1288 rule
->rule_str
= NULL
;
1290 /* Add new route match rule to linked list. */
1291 route_map_rule_add(&index
->match_list
, rule
);
1293 /* Execute event hook. */
1294 if (route_map_master
.event_hook
) {
1295 (*route_map_master
.event_hook
)(
1296 replaced
? RMAP_EVENT_MATCH_REPLACED
1297 : RMAP_EVENT_MATCH_ADDED
,
1299 route_map_notify_dependencies(index
->map
->name
,
1300 RMAP_EVENT_CALL_ADDED
);
1303 return RMAP_COMPILE_SUCCESS
;
1306 /* Delete specified route match rule. */
1307 int route_map_delete_match(struct route_map_index
*index
,
1308 const char *match_name
, const char *match_arg
)
1310 struct route_map_rule
*rule
;
1311 struct route_map_rule_cmd
*cmd
;
1313 cmd
= route_map_lookup_match(match_name
);
1317 for (rule
= index
->match_list
.head
; rule
; rule
= rule
->next
)
1318 if (rule
->cmd
== cmd
&& (rulecmp(rule
->rule_str
, match_arg
) == 0
1319 || match_arg
== NULL
)) {
1320 route_map_rule_delete(&index
->match_list
, rule
);
1321 /* Execute event hook. */
1322 if (route_map_master
.event_hook
) {
1323 (*route_map_master
.event_hook
)(
1324 RMAP_EVENT_MATCH_DELETED
,
1326 route_map_notify_dependencies(
1328 RMAP_EVENT_CALL_ADDED
);
1332 /* Can't find matched rule. */
1336 /* Add route-map set statement to the route map. */
1337 int route_map_add_set(struct route_map_index
*index
, const char *set_name
,
1338 const char *set_arg
)
1340 struct route_map_rule
*rule
;
1341 struct route_map_rule
*next
;
1342 struct route_map_rule_cmd
*cmd
;
1346 cmd
= route_map_lookup_set(set_name
);
1348 return RMAP_RULE_MISSING
;
1350 /* Next call compile function for this match statement. */
1351 if (cmd
->func_compile
) {
1352 compile
= (*cmd
->func_compile
)(set_arg
);
1353 if (compile
== NULL
)
1354 return RMAP_COMPILE_ERROR
;
1358 /* Add by WJL. if old set command of same kind exist, delete it first
1359 to ensure only one set command of same kind exist under a
1361 for (rule
= index
->set_list
.head
; rule
; rule
= next
) {
1363 if (rule
->cmd
== cmd
) {
1364 route_map_rule_delete(&index
->set_list
, rule
);
1369 /* Add new route map match rule. */
1370 rule
= route_map_rule_new();
1372 rule
->value
= compile
;
1374 rule
->rule_str
= XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR
, set_arg
);
1376 rule
->rule_str
= NULL
;
1378 /* Add new route match rule to linked list. */
1379 route_map_rule_add(&index
->set_list
, rule
);
1381 /* Execute event hook. */
1382 if (route_map_master
.event_hook
) {
1383 (*route_map_master
.event_hook
)(replaced
1384 ? RMAP_EVENT_SET_REPLACED
1385 : RMAP_EVENT_SET_ADDED
,
1387 route_map_notify_dependencies(index
->map
->name
,
1388 RMAP_EVENT_CALL_ADDED
);
1390 return RMAP_COMPILE_SUCCESS
;
1393 /* Delete route map set rule. */
1394 int route_map_delete_set(struct route_map_index
*index
, const char *set_name
,
1395 const char *set_arg
)
1397 struct route_map_rule
*rule
;
1398 struct route_map_rule_cmd
*cmd
;
1400 cmd
= route_map_lookup_set(set_name
);
1404 for (rule
= index
->set_list
.head
; rule
; rule
= rule
->next
)
1405 if ((rule
->cmd
== cmd
) && (rulecmp(rule
->rule_str
, set_arg
) == 0
1406 || set_arg
== NULL
)) {
1407 route_map_rule_delete(&index
->set_list
, rule
);
1408 /* Execute event hook. */
1409 if (route_map_master
.event_hook
) {
1410 (*route_map_master
.event_hook
)(
1411 RMAP_EVENT_SET_DELETED
,
1413 route_map_notify_dependencies(
1415 RMAP_EVENT_CALL_ADDED
);
1419 /* Can't find matched rule. */
1423 /* Apply route map's each index to the object.
1425 The matrix for a route-map looks like this:
1426 (note, this includes the description for the "NEXT"
1427 and "GOTO" frobs now
1431 permit action | cont
1433 ------------------+---------------
1439 -Apply Set statements, accept route
1440 -If Call statement is present jump to the specified route-map, if it
1441 denies the route we finish.
1442 -If NEXT is specified, goto NEXT statement
1443 -If GOTO is specified, goto the first clause where pref > nextpref
1444 -If nothing is specified, do as Cisco and finish
1446 -Route is denied by route-map.
1450 If we get no matches after we've processed all updates, then the route
1453 Some notes on the new "CALL", "NEXT" and "GOTO"
1454 call WORD - If this clause is matched, then the set statements
1455 are executed and then we jump to route-map 'WORD'. If
1456 this route-map denies the route, we finish, in other
1458 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
1459 on-match next - If this clause is matched, then the set statements
1460 are executed and then we drop through to the next clause
1461 on-match goto n - If this clause is matched, then the set statments
1462 are executed and then we goto the nth clause, or the
1463 first clause greater than this. In order to ensure
1464 route-maps *always* exit, you cannot jump backwards.
1467 We need to make sure our route-map processing matches the above
1470 static route_map_result_t
1471 route_map_apply_match(struct route_map_rule_list
*match_list
,
1472 const struct prefix
*prefix
, route_map_object_t type
,
1475 route_map_result_t ret
= RMAP_NOMATCH
;
1476 struct route_map_rule
*match
;
1479 /* Check all match rule and if there is no match rule, go to the
1481 if (!match_list
->head
)
1484 for (match
= match_list
->head
; match
; match
= match
->next
) {
1485 /* Try each match statement in turn, If any do not
1487 RMAP_MATCH, return, otherwise continue on to next
1489 statement. All match statements must match for
1492 ret
= (*match
->cmd
->func_apply
)(match
->value
, prefix
,
1494 if (ret
!= RMAP_MATCH
)
1501 /* Apply route map to the object. */
1502 route_map_result_t
route_map_apply(struct route_map
*map
,
1503 const struct prefix
*prefix
,
1504 route_map_object_t type
, void *object
)
1506 static int recursion
= 0;
1508 struct route_map_index
*index
;
1509 struct route_map_rule
*set
;
1511 if (recursion
> RMAP_RECURSION_LIMIT
) {
1513 EC_LIB_RMAP_RECURSION_LIMIT
,
1514 "route-map recursion limit (%d) reached, discarding route",
1515 RMAP_RECURSION_LIMIT
);
1517 return RMAP_DENYMATCH
;
1521 return RMAP_DENYMATCH
;
1524 for (index
= map
->head
; index
; index
= index
->next
) {
1525 /* Apply this index. */
1527 ret
= route_map_apply_match(&index
->match_list
, prefix
, type
,
1530 /* Now we apply the matrix from above */
1531 if (ret
== RMAP_NOMATCH
)
1532 /* 'cont' from matrix - continue to next route-map
1535 else if (ret
== RMAP_MATCH
) {
1536 if (index
->type
== RMAP_PERMIT
)
1539 /* permit+match must execute sets */
1540 for (set
= index
->set_list
.head
; set
;
1542 ret
= (*set
->cmd
->func_apply
)(
1543 set
->value
, prefix
, type
,
1546 /* Call another route-map if available */
1547 if (index
->nextrm
) {
1548 struct route_map
*nextrm
=
1549 route_map_lookup_by_name(
1552 if (nextrm
) /* Target route-map found,
1556 ret
= route_map_apply(
1557 nextrm
, prefix
, type
,
1562 /* If nextrm returned 'deny', finish. */
1563 if (ret
== RMAP_DENYMATCH
)
1567 switch (index
->exitpolicy
) {
1573 /* Find the next clause to jump to */
1574 struct route_map_index
*next
=
1576 int nextpref
= index
->nextpref
;
1578 while (next
&& next
->pref
< nextpref
) {
1583 /* No clauses match! */
1588 } else if (index
->type
== RMAP_DENY
)
1591 return RMAP_DENYMATCH
;
1595 /* Finally route-map does not match at all. */
1596 return RMAP_DENYMATCH
;
1599 void route_map_add_hook(void (*func
)(const char *))
1601 route_map_master
.add_hook
= func
;
1604 void route_map_delete_hook(void (*func
)(const char *))
1606 route_map_master
.delete_hook
= func
;
1609 void route_map_event_hook(void (*func
)(route_map_event_t
, const char *))
1611 route_map_master
.event_hook
= func
;
1614 /* Routines for route map dependency lists and dependency processing */
1615 static int route_map_rmap_hash_cmp(const void *p1
, const void *p2
)
1617 return (strcmp((const char *)p1
, (const char *)p2
) == 0);
1620 static int route_map_dep_hash_cmp(const void *p1
, const void *p2
)
1623 return (strcmp(((const struct route_map_dep
*)p1
)->dep_name
,
1628 static void route_map_clear_reference(struct hash_backet
*backet
, void *arg
)
1630 struct route_map_dep
*dep
= (struct route_map_dep
*)backet
->data
;
1635 (char *)hash_release(dep
->dep_rmap_hash
, (void *)arg
);
1637 XFREE(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
1639 if (!dep
->dep_rmap_hash
->count
) {
1640 dep
= hash_release(dep
->this_hash
,
1641 (void *)dep
->dep_name
);
1642 hash_free(dep
->dep_rmap_hash
);
1643 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
1644 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
1649 static void route_map_clear_all_references(char *rmap_name
)
1653 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
1654 hash_iterate(route_map_dep_hash
[i
], route_map_clear_reference
,
1659 static void *route_map_dep_hash_alloc(void *p
)
1661 char *dep_name
= (char *)p
;
1662 struct route_map_dep
*dep_entry
;
1664 dep_entry
= XCALLOC(MTYPE_ROUTE_MAP_DEP
, sizeof(struct route_map_dep
));
1665 dep_entry
->dep_name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1666 dep_entry
->dep_rmap_hash
=
1667 hash_create_size(8, route_map_dep_hash_make_key
,
1668 route_map_rmap_hash_cmp
, "Route Map Dep Hash");
1669 dep_entry
->this_hash
= NULL
;
1671 return ((void *)dep_entry
);
1674 static void *route_map_name_hash_alloc(void *p
)
1676 return ((void *)XSTRDUP(MTYPE_ROUTE_MAP_NAME
, (const char *)p
));
1679 static unsigned int route_map_dep_hash_make_key(void *p
)
1681 return (string_hash_make((char *)p
));
1684 static void route_map_print_dependency(struct hash_backet
*backet
, void *data
)
1686 char *rmap_name
= (char *)backet
->data
;
1687 char *dep_name
= (char *)data
;
1689 zlog_debug("%s: Dependency for %s: %s", __FUNCTION__
, dep_name
,
1693 static int route_map_dep_update(struct hash
*dephash
, const char *dep_name
,
1694 const char *rmap_name
, route_map_event_t type
)
1696 struct route_map_dep
*dep
= NULL
;
1698 char *dname
, *rname
;
1701 dname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, dep_name
);
1702 rname
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap_name
);
1705 case RMAP_EVENT_PLIST_ADDED
:
1706 case RMAP_EVENT_CLIST_ADDED
:
1707 case RMAP_EVENT_ECLIST_ADDED
:
1708 case RMAP_EVENT_ASLIST_ADDED
:
1709 case RMAP_EVENT_LLIST_ADDED
:
1710 case RMAP_EVENT_CALL_ADDED
:
1711 case RMAP_EVENT_FILTER_ADDED
:
1713 zlog_debug("%s: Adding dependency for %s in %s",
1714 __FUNCTION__
, dep_name
, rmap_name
);
1715 dep
= (struct route_map_dep
*)hash_get(
1716 dephash
, dname
, route_map_dep_hash_alloc
);
1722 if (!dep
->this_hash
)
1723 dep
->this_hash
= dephash
;
1725 hash_get(dep
->dep_rmap_hash
, rname
, route_map_name_hash_alloc
);
1727 case RMAP_EVENT_PLIST_DELETED
:
1728 case RMAP_EVENT_CLIST_DELETED
:
1729 case RMAP_EVENT_ECLIST_DELETED
:
1730 case RMAP_EVENT_ASLIST_DELETED
:
1731 case RMAP_EVENT_LLIST_DELETED
:
1732 case RMAP_EVENT_CALL_DELETED
:
1733 case RMAP_EVENT_FILTER_DELETED
:
1735 zlog_debug("%s: Deleting dependency for %s in %s",
1736 __FUNCTION__
, dep_name
, rmap_name
);
1737 dep
= (struct route_map_dep
*)hash_get(dephash
, dname
, NULL
);
1742 ret_map_name
= (char *)hash_release(dep
->dep_rmap_hash
, rname
);
1744 XFREE(MTYPE_ROUTE_MAP_NAME
, ret_map_name
);
1746 if (!dep
->dep_rmap_hash
->count
) {
1747 dep
= hash_release(dephash
, dname
);
1748 hash_free(dep
->dep_rmap_hash
);
1749 XFREE(MTYPE_ROUTE_MAP_NAME
, dep
->dep_name
);
1750 XFREE(MTYPE_ROUTE_MAP_DEP
, dep
);
1760 hash_iterate(dep
->dep_rmap_hash
,
1761 route_map_print_dependency
, dname
);
1765 XFREE(MTYPE_ROUTE_MAP_NAME
, rname
);
1766 XFREE(MTYPE_ROUTE_MAP_NAME
, dname
);
1770 static struct hash
*route_map_get_dep_hash(route_map_event_t event
)
1772 struct hash
*upd8_hash
= NULL
;
1775 case RMAP_EVENT_PLIST_ADDED
:
1776 case RMAP_EVENT_PLIST_DELETED
:
1777 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_PLIST
];
1779 case RMAP_EVENT_CLIST_ADDED
:
1780 case RMAP_EVENT_CLIST_DELETED
:
1781 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_CLIST
];
1783 case RMAP_EVENT_ECLIST_ADDED
:
1784 case RMAP_EVENT_ECLIST_DELETED
:
1785 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ECLIST
];
1787 case RMAP_EVENT_ASLIST_ADDED
:
1788 case RMAP_EVENT_ASLIST_DELETED
:
1789 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_ASPATH
];
1791 case RMAP_EVENT_LLIST_ADDED
:
1792 case RMAP_EVENT_LLIST_DELETED
:
1793 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_LCLIST
];
1795 case RMAP_EVENT_CALL_ADDED
:
1796 case RMAP_EVENT_CALL_DELETED
:
1797 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_RMAP
];
1799 case RMAP_EVENT_FILTER_ADDED
:
1800 case RMAP_EVENT_FILTER_DELETED
:
1801 upd8_hash
= route_map_dep_hash
[ROUTE_MAP_DEP_FILTER
];
1810 static void route_map_process_dependency(struct hash_backet
*backet
, void *data
)
1812 char *rmap_name
= (char *)backet
->data
;
1813 route_map_event_t type
= (route_map_event_t
)(ptrdiff_t)data
;
1816 zlog_debug("%s: Notifying %s of dependency",
1817 __FUNCTION__
, rmap_name
);
1818 if (route_map_master
.event_hook
)
1819 (*route_map_master
.event_hook
)(type
, rmap_name
);
1822 void route_map_upd8_dependency(route_map_event_t type
, const char *arg
,
1823 const char *rmap_name
)
1825 struct hash
*upd8_hash
= NULL
;
1827 if ((upd8_hash
= route_map_get_dep_hash(type
))) {
1828 route_map_dep_update(upd8_hash
, arg
, rmap_name
, type
);
1830 if (type
== RMAP_EVENT_CALL_ADDED
) {
1832 if (route_map_master
.add_hook
)
1833 (*route_map_master
.add_hook
)(rmap_name
);
1834 } else if (type
== RMAP_EVENT_CALL_DELETED
) {
1836 if (route_map_master
.delete_hook
)
1837 (*route_map_master
.delete_hook
)(rmap_name
);
1842 void route_map_notify_dependencies(const char *affected_name
,
1843 route_map_event_t event
)
1845 struct route_map_dep
*dep
;
1846 struct hash
*upd8_hash
;
1852 name
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, affected_name
);
1854 if ((upd8_hash
= route_map_get_dep_hash(event
)) == NULL
) {
1855 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
1859 dep
= (struct route_map_dep
*)hash_get(upd8_hash
, name
, NULL
);
1861 if (!dep
->this_hash
)
1862 dep
->this_hash
= upd8_hash
;
1864 hash_iterate(dep
->dep_rmap_hash
, route_map_process_dependency
,
1868 XFREE(MTYPE_ROUTE_MAP_NAME
, name
);
1872 /* VTY related functions. */
1873 DEFUN (match_interface
,
1874 match_interface_cmd
,
1875 "match interface WORD",
1877 "match first hop interface of route\n"
1881 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1883 if (rmap_match_set_hook
.match_interface
)
1884 return rmap_match_set_hook
.match_interface(
1885 vty
, index
, "interface", argv
[idx_word
]->arg
,
1886 RMAP_EVENT_MATCH_ADDED
);
1890 DEFUN (no_match_interface
,
1891 no_match_interface_cmd
,
1892 "no match interface [WORD]",
1895 "Match first hop interface of route\n"
1898 char *iface
= (argc
== 4) ? argv
[3]->arg
: NULL
;
1899 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1901 if (rmap_match_set_hook
.no_match_interface
)
1902 return rmap_match_set_hook
.no_match_interface(
1903 vty
, index
, "interface", iface
,
1904 RMAP_EVENT_MATCH_DELETED
);
1909 DEFUN (match_ip_address
,
1910 match_ip_address_cmd
,
1911 "match ip address <(1-199)|(1300-2699)|WORD>",
1914 "Match address of route\n"
1915 "IP access-list number\n"
1916 "IP access-list number (expanded range)\n"
1917 "IP Access-list name\n")
1920 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1922 if (rmap_match_set_hook
.match_ip_address
)
1923 return rmap_match_set_hook
.match_ip_address(
1924 vty
, index
, "ip address", argv
[idx_acl
]->arg
,
1925 RMAP_EVENT_FILTER_ADDED
);
1930 DEFUN (no_match_ip_address
,
1931 no_match_ip_address_cmd
,
1932 "no match ip address [<(1-199)|(1300-2699)|WORD>]",
1936 "Match address of route\n"
1937 "IP access-list number\n"
1938 "IP access-list number (expanded range)\n"
1939 "IP Access-list name\n")
1942 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1944 if (rmap_match_set_hook
.no_match_ip_address
) {
1945 if (argc
<= idx_word
)
1946 return rmap_match_set_hook
.no_match_ip_address(
1947 vty
, index
, "ip address", NULL
,
1948 RMAP_EVENT_FILTER_DELETED
);
1949 return rmap_match_set_hook
.no_match_ip_address(
1950 vty
, index
, "ip address", argv
[idx_word
]->arg
,
1951 RMAP_EVENT_FILTER_DELETED
);
1957 DEFUN (match_ip_address_prefix_list
,
1958 match_ip_address_prefix_list_cmd
,
1959 "match ip address prefix-list WORD",
1962 "Match address of route\n"
1963 "Match entries of prefix-lists\n"
1964 "IP prefix-list name\n")
1967 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1969 if (rmap_match_set_hook
.match_ip_address_prefix_list
)
1970 return rmap_match_set_hook
.match_ip_address_prefix_list(
1971 vty
, index
, "ip address prefix-list",
1972 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
1977 DEFUN (no_match_ip_address_prefix_list
,
1978 no_match_ip_address_prefix_list_cmd
,
1979 "no match ip address prefix-list [WORD]",
1983 "Match address of route\n"
1984 "Match entries of prefix-lists\n"
1985 "IP prefix-list name\n")
1988 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
1990 if (rmap_match_set_hook
.no_match_ip_address_prefix_list
) {
1991 if (argc
<= idx_word
)
1992 return rmap_match_set_hook
1993 .no_match_ip_address_prefix_list(
1994 vty
, index
, "ip address prefix-list",
1995 NULL
, RMAP_EVENT_PLIST_DELETED
);
1996 return rmap_match_set_hook
.no_match_ip_address_prefix_list(
1997 vty
, index
, "ip address prefix-list",
1998 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2004 DEFUN (match_ip_next_hop
,
2005 match_ip_next_hop_cmd
,
2006 "match ip next-hop <(1-199)|(1300-2699)|WORD>",
2009 "Match next-hop address of route\n"
2010 "IP access-list number\n"
2011 "IP access-list number (expanded range)\n"
2012 "IP Access-list name\n")
2015 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2017 if (rmap_match_set_hook
.match_ip_next_hop
)
2018 return rmap_match_set_hook
.match_ip_next_hop(
2019 vty
, index
, "ip next-hop", argv
[idx_acl
]->arg
,
2020 RMAP_EVENT_FILTER_ADDED
);
2025 DEFUN (no_match_ip_next_hop
,
2026 no_match_ip_next_hop_cmd
,
2027 "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
2031 "Match next-hop address of route\n"
2032 "IP access-list number\n"
2033 "IP access-list number (expanded range)\n"
2034 "IP Access-list name\n")
2037 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2039 if (rmap_match_set_hook
.no_match_ip_next_hop
) {
2040 if (argc
<= idx_word
)
2041 return rmap_match_set_hook
.no_match_ip_next_hop(
2042 vty
, index
, "ip next-hop", NULL
,
2043 RMAP_EVENT_FILTER_DELETED
);
2044 return rmap_match_set_hook
.no_match_ip_next_hop(
2045 vty
, index
, "ip next-hop", argv
[idx_word
]->arg
,
2046 RMAP_EVENT_FILTER_DELETED
);
2052 DEFUN (match_ip_next_hop_prefix_list
,
2053 match_ip_next_hop_prefix_list_cmd
,
2054 "match ip next-hop prefix-list WORD",
2057 "Match next-hop address of route\n"
2058 "Match entries of prefix-lists\n"
2059 "IP prefix-list name\n")
2062 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2064 if (rmap_match_set_hook
.match_ip_next_hop_prefix_list
)
2065 return rmap_match_set_hook
.match_ip_next_hop_prefix_list(
2066 vty
, index
, "ip next-hop prefix-list",
2067 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
2071 DEFUN (no_match_ip_next_hop_prefix_list
,
2072 no_match_ip_next_hop_prefix_list_cmd
,
2073 "no match ip next-hop prefix-list [WORD]",
2077 "Match next-hop address of route\n"
2078 "Match entries of prefix-lists\n"
2079 "IP prefix-list name\n")
2082 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2084 if (rmap_match_set_hook
.no_match_ip_next_hop
) {
2085 if (argc
<= idx_word
)
2086 return rmap_match_set_hook
.no_match_ip_next_hop(
2087 vty
, index
, "ip next-hop prefix-list", NULL
,
2088 RMAP_EVENT_PLIST_DELETED
);
2089 return rmap_match_set_hook
.no_match_ip_next_hop(
2090 vty
, index
, "ip next-hop prefix-list",
2091 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2096 DEFUN(match_ip_next_hop_type
, match_ip_next_hop_type_cmd
,
2097 "match ip next-hop type <blackhole>",
2099 "Match next-hop address of route\n"
2100 "Match entries by type\n"
2104 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2106 if (rmap_match_set_hook
.match_ip_next_hop_type
)
2107 return rmap_match_set_hook
.match_ip_next_hop_type(
2108 vty
, index
, "ip next-hop type", argv
[idx_word
]->arg
,
2109 RMAP_EVENT_MATCH_ADDED
);
2113 DEFUN(no_match_ip_next_hop_type
, no_match_ip_next_hop_type_cmd
,
2114 "no match ip next-hop type [<blackhole>]",
2115 NO_STR MATCH_STR IP_STR
2116 "Match next-hop address of route\n"
2117 "Match entries by type\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 type", NULL
,
2127 RMAP_EVENT_MATCH_DELETED
);
2128 return rmap_match_set_hook
.no_match_ip_next_hop(
2129 vty
, index
, "ip next-hop type", argv
[idx_word
]->arg
,
2130 RMAP_EVENT_MATCH_DELETED
);
2136 DEFUN (match_ipv6_address
,
2137 match_ipv6_address_cmd
,
2138 "match ipv6 address WORD",
2141 "Match IPv6 address of route\n"
2142 "IPv6 access-list name\n")
2145 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2147 if (rmap_match_set_hook
.match_ipv6_address
)
2148 return rmap_match_set_hook
.match_ipv6_address(
2149 vty
, index
, "ipv6 address", argv
[idx_word
]->arg
,
2150 RMAP_EVENT_FILTER_ADDED
);
2154 DEFUN (no_match_ipv6_address
,
2155 no_match_ipv6_address_cmd
,
2156 "no match ipv6 address WORD",
2160 "Match IPv6 address of route\n"
2161 "IPv6 access-list name\n")
2164 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2166 if (rmap_match_set_hook
.no_match_ipv6_address
)
2167 return rmap_match_set_hook
.no_match_ipv6_address(
2168 vty
, index
, "ipv6 address", argv
[idx_word
]->arg
,
2169 RMAP_EVENT_FILTER_DELETED
);
2174 DEFUN (match_ipv6_address_prefix_list
,
2175 match_ipv6_address_prefix_list_cmd
,
2176 "match ipv6 address prefix-list WORD",
2179 "Match address of route\n"
2180 "Match entries of prefix-lists\n"
2181 "IP prefix-list name\n")
2184 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2186 if (rmap_match_set_hook
.match_ipv6_address_prefix_list
)
2187 return rmap_match_set_hook
.match_ipv6_address_prefix_list(
2188 vty
, index
, "ipv6 address prefix-list",
2189 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_ADDED
);
2193 DEFUN (no_match_ipv6_address_prefix_list
,
2194 no_match_ipv6_address_prefix_list_cmd
,
2195 "no match ipv6 address prefix-list WORD",
2199 "Match address of route\n"
2200 "Match entries of prefix-lists\n"
2201 "IP prefix-list name\n")
2204 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2206 if (rmap_match_set_hook
.no_match_ipv6_address_prefix_list
)
2207 return rmap_match_set_hook
.no_match_ipv6_address_prefix_list(
2208 vty
, index
, "ipv6 address prefix-list",
2209 argv
[idx_word
]->arg
, RMAP_EVENT_PLIST_DELETED
);
2213 DEFUN(match_ipv6_next_hop_type
, match_ipv6_next_hop_type_cmd
,
2214 "match ipv6 next-hop type <blackhole>",
2216 "Match address of route\n"
2217 "Match entries by type\n"
2221 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2223 if (rmap_match_set_hook
.match_ipv6_next_hop_type
)
2224 return rmap_match_set_hook
.match_ipv6_next_hop_type(
2225 vty
, index
, "ipv6 next-hop type", argv
[idx_word
]->arg
,
2226 RMAP_EVENT_MATCH_ADDED
);
2230 DEFUN(no_match_ipv6_next_hop_type
, no_match_ipv6_next_hop_type_cmd
,
2231 "no match ipv6 next-hop type [<blackhole>]",
2232 NO_STR MATCH_STR IPV6_STR
2233 "Match address of route\n"
2234 "Match entries by type\n"
2238 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2240 if (rmap_match_set_hook
.no_match_ipv6_next_hop_type
)
2241 return rmap_match_set_hook
.no_match_ipv6_next_hop_type(
2242 vty
, index
, "ipv6 next-hop type", argv
[idx_word
]->arg
,
2243 RMAP_EVENT_MATCH_DELETED
);
2247 DEFUN (match_metric
,
2249 "match metric (0-4294967295)",
2251 "Match metric of route\n"
2255 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2257 if (rmap_match_set_hook
.match_metric
)
2258 return rmap_match_set_hook
.match_metric(vty
, index
, "metric",
2259 argv
[idx_number
]->arg
,
2260 RMAP_EVENT_MATCH_ADDED
);
2265 DEFUN (no_match_metric
,
2266 no_match_metric_cmd
,
2267 "no match metric [(0-4294967295)]",
2270 "Match metric of route\n"
2274 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2276 if (rmap_match_set_hook
.no_match_metric
) {
2277 if (argc
<= idx_number
)
2278 return rmap_match_set_hook
.no_match_metric(
2279 vty
, index
, "metric", NULL
,
2280 RMAP_EVENT_MATCH_DELETED
);
2281 return rmap_match_set_hook
.no_match_metric(
2282 vty
, index
, "metric", argv
[idx_number
]->arg
,
2283 RMAP_EVENT_MATCH_DELETED
);
2291 "match tag (1-4294967295)",
2293 "Match tag of route\n"
2297 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2299 if (rmap_match_set_hook
.match_tag
)
2300 return rmap_match_set_hook
.match_tag(vty
, index
, "tag",
2301 argv
[idx_number
]->arg
,
2302 RMAP_EVENT_MATCH_ADDED
);
2307 DEFUN (no_match_tag
,
2309 "no match tag [(1-4294967295)]",
2312 "Match tag of route\n"
2315 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2318 char *arg
= argv_find(argv
, argc
, "(1-4294967295)", &idx
)
2322 if (rmap_match_set_hook
.no_match_tag
)
2323 return rmap_match_set_hook
.no_match_tag(
2324 vty
, index
, "tag", arg
, RMAP_EVENT_MATCH_DELETED
);
2329 DEFUN (set_ip_nexthop
,
2331 "set ip next-hop A.B.C.D",
2334 "Next hop address\n"
2335 "IP address of next hop\n")
2340 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2342 ret
= str2sockunion(argv
[idx_ipv4
]->arg
, &su
);
2344 vty_out(vty
, "%% Malformed nexthop address\n");
2345 return CMD_WARNING_CONFIG_FAILED
;
2347 if (su
.sin
.sin_addr
.s_addr
== 0
2348 || IPV4_CLASS_DE(ntohl(su
.sin
.sin_addr
.s_addr
))) {
2350 "%% nexthop address cannot be 0.0.0.0, multicast or reserved\n");
2351 return CMD_WARNING_CONFIG_FAILED
;
2354 if (rmap_match_set_hook
.set_ip_nexthop
)
2355 return rmap_match_set_hook
.set_ip_nexthop(
2356 vty
, index
, "ip next-hop", argv
[idx_ipv4
]->arg
);
2361 DEFUN (no_set_ip_nexthop
,
2362 no_set_ip_nexthop_cmd
,
2363 "no set ip next-hop [A.B.C.D]",
2367 "Next hop address\n"
2368 "IP address of next hop\n")
2371 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2372 const char *arg
= NULL
;
2374 if (argv_find(argv
, argc
, "A.B.C.D", &idx
))
2375 arg
= argv
[idx
]->arg
;
2377 if (rmap_match_set_hook
.no_set_ip_nexthop
)
2378 return rmap_match_set_hook
.no_set_ip_nexthop(
2379 vty
, index
, "ip next-hop", arg
);
2385 DEFUN (set_ipv6_nexthop_local
,
2386 set_ipv6_nexthop_local_cmd
,
2387 "set ipv6 next-hop local X:X::X:X",
2390 "IPv6 next-hop address\n"
2391 "IPv6 local address\n"
2392 "IPv6 address of next hop\n")
2395 struct in6_addr addr
;
2397 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2399 ret
= inet_pton(AF_INET6
, argv
[idx_ipv6
]->arg
, &addr
);
2401 vty_out(vty
, "%% Malformed nexthop address\n");
2402 return CMD_WARNING_CONFIG_FAILED
;
2404 if (!IN6_IS_ADDR_LINKLOCAL(&addr
)) {
2405 vty_out(vty
, "%% Invalid link-local nexthop address\n");
2406 return CMD_WARNING_CONFIG_FAILED
;
2409 if (rmap_match_set_hook
.set_ipv6_nexthop_local
)
2410 return rmap_match_set_hook
.set_ipv6_nexthop_local(
2411 vty
, index
, "ipv6 next-hop local", argv
[idx_ipv6
]->arg
);
2416 DEFUN (no_set_ipv6_nexthop_local
,
2417 no_set_ipv6_nexthop_local_cmd
,
2418 "no set ipv6 next-hop local [X:X::X:X]",
2422 "IPv6 next-hop address\n"
2423 "IPv6 local address\n"
2424 "IPv6 address of next hop\n")
2427 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2429 if (rmap_match_set_hook
.no_set_ipv6_nexthop_local
) {
2430 if (argc
<= idx_ipv6
)
2431 return rmap_match_set_hook
.no_set_ipv6_nexthop_local(
2432 vty
, index
, "ipv6 next-hop local", NULL
);
2433 return rmap_match_set_hook
.no_set_ipv6_nexthop_local(
2434 vty
, index
, "ipv6 next-hop local", argv
[5]->arg
);
2441 "set metric <(0-4294967295)|rtt|+rtt|-rtt|+metric|-metric>",
2443 "Metric value for destination routing protocol\n"
2445 "Assign round trip time\n"
2446 "Add round trip time\n"
2447 "Subtract round trip time\n"
2449 "Subtract metric\n")
2452 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2454 const char *pass
= (argv
[idx_number
]->type
== RANGE_TKN
)
2455 ? argv
[idx_number
]->arg
2456 : argv
[idx_number
]->text
;
2458 if (rmap_match_set_hook
.set_metric
)
2459 return rmap_match_set_hook
.set_metric(vty
, index
, "metric",
2465 DEFUN (no_set_metric
,
2467 "no set metric [(0-4294967295)]",
2470 "Metric value for destination routing protocol\n"
2474 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2476 if (rmap_match_set_hook
.no_set_metric
) {
2477 if (argc
<= idx_number
)
2478 return rmap_match_set_hook
.no_set_metric(
2479 vty
, index
, "metric", NULL
);
2480 return rmap_match_set_hook
.no_set_metric(vty
, index
, "metric",
2481 argv
[idx_number
]->arg
);
2489 "set tag (1-4294967295)",
2491 "Tag value for routing protocol\n"
2494 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2497 if (rmap_match_set_hook
.set_tag
)
2498 return rmap_match_set_hook
.set_tag(vty
, index
, "tag",
2499 argv
[idx_number
]->arg
);
2506 "no set tag [(1-4294967295)]",
2509 "Tag value for routing protocol\n"
2512 VTY_DECLVAR_CONTEXT(route_map_index
, index
);
2515 if (rmap_match_set_hook
.no_set_tag
) {
2516 if (argc
<= idx_number
)
2517 return rmap_match_set_hook
.no_set_tag(vty
, index
, "tag",
2519 return rmap_match_set_hook
.no_set_tag(vty
, index
, "tag",
2520 argv
[idx_number
]->arg
);
2526 DEFUN_NOSH (route_map
,
2528 "route-map WORD <deny|permit> (1-65535)",
2529 "Create route-map or enter route-map command mode\n"
2531 "Route map denies set operations\n"
2532 "Route map permits set operations\n"
2533 "Sequence to insert to/delete from existing route-map entry\n")
2536 int idx_permit_deny
= 2;
2538 struct route_map
*map
;
2539 struct route_map_index
*index
;
2540 char *endptr
= NULL
;
2542 argv
[idx_permit_deny
]->arg
[0] == 'p' ? RMAP_PERMIT
: RMAP_DENY
;
2543 unsigned long pref
= strtoul(argv
[idx_number
]->arg
, &endptr
, 10);
2544 const char *mapname
= argv
[idx_word
]->arg
;
2546 /* Get route map. */
2547 map
= route_map_get(mapname
);
2548 index
= route_map_index_get(map
, permit
, pref
);
2550 VTY_PUSH_CONTEXT(RMAP_NODE
, index
);
2554 DEFUN (no_route_map_all
,
2555 no_route_map_all_cmd
,
2556 "no route-map WORD",
2558 "Create route-map or enter route-map command mode\n"
2562 const char *mapname
= argv
[idx_word
]->arg
;
2563 struct route_map
*map
;
2565 map
= route_map_lookup_by_name(mapname
);
2567 vty_out(vty
, "%% Could not find route-map %s\n", mapname
);
2568 return CMD_WARNING_CONFIG_FAILED
;
2571 route_map_delete(map
);
2576 DEFUN (no_route_map
,
2578 "no route-map WORD <deny|permit> (1-65535)",
2580 "Create route-map or enter route-map command mode\n"
2582 "Route map denies set operations\n"
2583 "Route map permits set operations\n"
2584 "Sequence to insert to/delete from existing route-map entry\n")
2587 int idx_permit_deny
= 3;
2589 struct route_map
*map
;
2590 struct route_map_index
*index
;
2591 char *endptr
= NULL
;
2592 int permit
= strmatch(argv
[idx_permit_deny
]->text
, "permit")
2595 const char *prefstr
= argv
[idx_number
]->arg
;
2596 const char *mapname
= argv
[idx_word
]->arg
;
2597 unsigned long pref
= strtoul(prefstr
, &endptr
, 10);
2599 /* Existence check. */
2600 map
= route_map_lookup_by_name(mapname
);
2602 vty_out(vty
, "%% Could not find route-map %s\n", mapname
);
2603 return CMD_WARNING_CONFIG_FAILED
;
2606 /* Lookup route map index. */
2607 index
= route_map_index_lookup(map
, permit
, pref
);
2608 if (index
== NULL
) {
2609 vty_out(vty
, "%% Could not find route-map entry %s %s\n",
2611 return CMD_WARNING_CONFIG_FAILED
;
2614 /* Delete index from route map. */
2615 route_map_index_delete(index
, 1);
2617 /* If this route rule is the last one, delete route map itself. */
2618 if (route_map_empty(map
))
2619 route_map_delete(map
);
2624 DEFUN (rmap_onmatch_next
,
2625 rmap_onmatch_next_cmd
,
2627 "Exit policy on matches\n"
2630 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2633 if (index
->type
== RMAP_DENY
) {
2634 /* Under a deny clause, match means it's finished. No
2635 * need to set next */
2637 "on-match next not supported under route-map deny\n");
2638 return CMD_WARNING_CONFIG_FAILED
;
2640 index
->exitpolicy
= RMAP_NEXT
;
2645 DEFUN (no_rmap_onmatch_next
,
2646 no_rmap_onmatch_next_cmd
,
2649 "Exit policy on matches\n"
2652 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2655 index
->exitpolicy
= RMAP_EXIT
;
2660 DEFUN (rmap_onmatch_goto
,
2661 rmap_onmatch_goto_cmd
,
2662 "on-match goto (1-65535)",
2663 "Exit policy on matches\n"
2664 "Goto Clause number\n"
2668 char *num
= argv_find(argv
, argc
, "(1-65535)", &idx
) ? argv
[idx
]->arg
2671 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2675 if (index
->type
== RMAP_DENY
) {
2676 /* Under a deny clause, match means it's finished. No
2677 * need to go anywhere */
2679 "on-match goto not supported under route-map deny\n");
2680 return CMD_WARNING_CONFIG_FAILED
;
2684 d
= strtoul(num
, NULL
, 10);
2686 d
= index
->pref
+ 1;
2688 if (d
<= index
->pref
) {
2689 /* Can't allow you to do that, Dave */
2690 vty_out(vty
, "can't jump backwards in route-maps\n");
2691 return CMD_WARNING_CONFIG_FAILED
;
2693 index
->exitpolicy
= RMAP_GOTO
;
2694 index
->nextpref
= d
;
2700 DEFUN (no_rmap_onmatch_goto
,
2701 no_rmap_onmatch_goto_cmd
,
2704 "Exit policy on matches\n"
2705 "Goto Clause number\n")
2707 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2710 index
->exitpolicy
= RMAP_EXIT
;
2715 /* Cisco/GNU Zebra compatibility aliases */
2717 DEFUN (rmap_continue
,
2719 "continue (1-65535)",
2720 "Continue on a different entry within the route-map\n"
2721 "Route-map entry sequence number\n")
2723 return rmap_onmatch_goto(self
, vty
, argc
, argv
);
2727 DEFUN (no_rmap_continue
,
2728 no_rmap_continue_cmd
,
2729 "no continue [(1-65535)]",
2731 "Continue on a different entry within the route-map\n"
2732 "Route-map entry sequence number\n")
2734 return no_rmap_onmatch_goto(self
, vty
, argc
, argv
);
2738 DEFUN (rmap_show_name
,
2740 "show route-map [WORD]",
2742 "route-map information\n"
2746 const char *name
= (argc
== 3) ? argv
[idx_word
]->arg
: NULL
;
2747 return vty_show_route_map(vty
, name
);
2753 "Jump to another Route-Map after match+set\n"
2754 "Target route-map name\n")
2757 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2758 const char *rmap
= argv
[idx_word
]->arg
;
2762 if (index
->nextrm
) {
2763 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED
,
2764 index
->nextrm
, index
->map
->name
);
2765 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
2767 index
->nextrm
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmap
);
2769 /* Execute event hook. */
2770 route_map_upd8_dependency(RMAP_EVENT_CALL_ADDED
, index
->nextrm
,
2775 DEFUN (no_rmap_call
,
2779 "Jump to another Route-Map after match+set\n")
2781 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2783 if (index
->nextrm
) {
2784 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED
,
2785 index
->nextrm
, index
->map
->name
);
2786 XFREE(MTYPE_ROUTE_MAP_NAME
, index
->nextrm
);
2787 index
->nextrm
= NULL
;
2793 DEFUN (rmap_description
,
2794 rmap_description_cmd
,
2795 "description LINE...",
2796 "Route-map comment\n"
2797 "Comment describing this route-map rule\n")
2800 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2803 if (index
->description
)
2804 XFREE(MTYPE_TMP
, index
->description
);
2805 index
->description
= argv_concat(argv
, argc
, idx_line
);
2810 DEFUN (no_rmap_description
,
2811 no_rmap_description_cmd
,
2814 "Route-map comment\n")
2816 struct route_map_index
*index
= VTY_GET_CONTEXT(route_map_index
);
2819 if (index
->description
)
2820 XFREE(MTYPE_TMP
, index
->description
);
2821 index
->description
= NULL
;
2826 /* Configuration write function. */
2827 static int route_map_config_write(struct vty
*vty
)
2829 struct route_map
*map
;
2830 struct route_map_index
*index
;
2831 struct route_map_rule
*rule
;
2835 for (map
= route_map_master
.head
; map
; map
= map
->next
)
2836 for (index
= map
->head
; index
; index
= index
->next
) {
2838 vty_out(vty
, "!\n");
2842 vty_out(vty
, "route-map %s %s %d\n", map
->name
,
2843 route_map_type_str(index
->type
), index
->pref
);
2845 if (index
->description
)
2846 vty_out(vty
, " description %s\n",
2847 index
->description
);
2849 for (rule
= index
->match_list
.head
; rule
;
2851 vty_out(vty
, " match %s %s\n", rule
->cmd
->str
,
2852 rule
->rule_str
? rule
->rule_str
: "");
2854 for (rule
= index
->set_list
.head
; rule
;
2856 vty_out(vty
, " set %s %s\n", rule
->cmd
->str
,
2857 rule
->rule_str
? rule
->rule_str
: "");
2859 vty_out(vty
, " call %s\n", index
->nextrm
);
2860 if (index
->exitpolicy
== RMAP_GOTO
)
2861 vty_out(vty
, " on-match goto %d\n",
2863 if (index
->exitpolicy
== RMAP_NEXT
)
2864 vty_out(vty
, " on-match next\n");
2871 /* Route map node structure. */
2872 static struct cmd_node rmap_node
= {RMAP_NODE
, "%s(config-route-map)# ", 1};
2874 /* Common route map rules */
2876 void *route_map_rule_tag_compile(const char *arg
)
2878 unsigned long int tmp
;
2883 tmp
= strtoul(arg
, &endptr
, 0);
2884 if (arg
[0] == '\0' || *endptr
!= '\0' || errno
|| tmp
> ROUTE_TAG_MAX
)
2887 tag
= XMALLOC(MTYPE_ROUTE_MAP_COMPILED
, sizeof(*tag
));
2893 void route_map_rule_tag_free(void *rule
)
2895 XFREE(MTYPE_ROUTE_MAP_COMPILED
, rule
);
2898 void route_map_finish(void)
2902 vector_free(route_match_vec
);
2903 route_match_vec
= NULL
;
2904 vector_free(route_set_vec
);
2905 route_set_vec
= NULL
;
2908 * All protocols are setting these to NULL
2909 * by default on shutdown( route_map_finish )
2910 * Why are we making them do this work?
2912 route_map_master
.add_hook
= NULL
;
2913 route_map_master
.delete_hook
= NULL
;
2914 route_map_master
.event_hook
= NULL
;
2916 /* cleanup route_map */
2917 while (route_map_master
.head
) {
2918 struct route_map
*map
= route_map_master
.head
;
2919 map
->to_be_processed
= false;
2920 route_map_delete(map
);
2923 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++) {
2924 hash_free(route_map_dep_hash
[i
]);
2925 route_map_dep_hash
[i
] = NULL
;
2928 hash_free(route_map_master_hash
);
2929 route_map_master_hash
= NULL
;
2932 static void rmap_autocomplete(vector comps
, struct cmd_token
*token
)
2934 struct route_map
*map
;
2936 for (map
= route_map_master
.head
; map
; map
= map
->next
)
2937 vector_set(comps
, XSTRDUP(MTYPE_COMPLETION
, map
->name
));
2940 static const struct cmd_variable_handler rmap_var_handlers
[] = {
2941 {/* "route-map WORD" */
2942 .varname
= "route_map",
2943 .completions
= rmap_autocomplete
},
2944 {.tokenname
= "ROUTEMAP_NAME", .completions
= rmap_autocomplete
},
2945 {.tokenname
= "RMAP_NAME", .completions
= rmap_autocomplete
},
2946 {.completions
= NULL
}};
2948 /* Initialization of route map vector. */
2949 void route_map_init(void)
2953 /* Make vector for match and set. */
2954 route_match_vec
= vector_init(1);
2955 route_set_vec
= vector_init(1);
2956 route_map_master_hash
=
2957 hash_create_size(8, route_map_hash_key_make
, route_map_hash_cmp
,
2958 "Route Map Master Hash");
2960 for (i
= 1; i
< ROUTE_MAP_DEP_MAX
; i
++)
2961 route_map_dep_hash
[i
] = hash_create_size(
2962 8, route_map_dep_hash_make_key
, route_map_dep_hash_cmp
,
2963 "Route Map Dep Hash");
2965 cmd_variable_handler_register(rmap_var_handlers
);
2967 /* Install route map top node. */
2968 install_node(&rmap_node
, route_map_config_write
);
2970 /* Install route map commands. */
2971 install_default(RMAP_NODE
);
2972 install_element(CONFIG_NODE
, &route_map_cmd
);
2973 install_element(CONFIG_NODE
, &no_route_map_cmd
);
2974 install_element(CONFIG_NODE
, &no_route_map_all_cmd
);
2976 /* Install the on-match stuff */
2977 install_element(RMAP_NODE
, &route_map_cmd
);
2978 install_element(RMAP_NODE
, &rmap_onmatch_next_cmd
);
2979 install_element(RMAP_NODE
, &no_rmap_onmatch_next_cmd
);
2980 install_element(RMAP_NODE
, &rmap_onmatch_goto_cmd
);
2981 install_element(RMAP_NODE
, &no_rmap_onmatch_goto_cmd
);
2982 install_element(RMAP_NODE
, &rmap_continue_cmd
);
2983 install_element(RMAP_NODE
, &no_rmap_continue_cmd
);
2985 /* Install the continue stuff (ALIAS of on-match). */
2987 /* Install the call stuff. */
2988 install_element(RMAP_NODE
, &rmap_call_cmd
);
2989 install_element(RMAP_NODE
, &no_rmap_call_cmd
);
2991 /* Install description commands. */
2992 install_element(RMAP_NODE
, &rmap_description_cmd
);
2993 install_element(RMAP_NODE
, &no_rmap_description_cmd
);
2995 /* Install show command */
2996 install_element(ENABLE_NODE
, &rmap_show_name_cmd
);
2998 install_element(RMAP_NODE
, &match_interface_cmd
);
2999 install_element(RMAP_NODE
, &no_match_interface_cmd
);
3001 install_element(RMAP_NODE
, &match_ip_address_cmd
);
3002 install_element(RMAP_NODE
, &no_match_ip_address_cmd
);
3004 install_element(RMAP_NODE
, &match_ip_address_prefix_list_cmd
);
3005 install_element(RMAP_NODE
, &no_match_ip_address_prefix_list_cmd
);
3007 install_element(RMAP_NODE
, &match_ip_next_hop_cmd
);
3008 install_element(RMAP_NODE
, &no_match_ip_next_hop_cmd
);
3010 install_element(RMAP_NODE
, &match_ip_next_hop_prefix_list_cmd
);
3011 install_element(RMAP_NODE
, &no_match_ip_next_hop_prefix_list_cmd
);
3013 install_element(RMAP_NODE
, &match_ip_next_hop_type_cmd
);
3014 install_element(RMAP_NODE
, &no_match_ip_next_hop_type_cmd
);
3016 install_element(RMAP_NODE
, &match_ipv6_address_cmd
);
3017 install_element(RMAP_NODE
, &no_match_ipv6_address_cmd
);
3019 install_element(RMAP_NODE
, &match_ipv6_address_prefix_list_cmd
);
3020 install_element(RMAP_NODE
, &no_match_ipv6_address_prefix_list_cmd
);
3022 install_element(RMAP_NODE
, &match_ipv6_next_hop_type_cmd
);
3023 install_element(RMAP_NODE
, &no_match_ipv6_next_hop_type_cmd
);
3025 install_element(RMAP_NODE
, &match_metric_cmd
);
3026 install_element(RMAP_NODE
, &no_match_metric_cmd
);
3028 install_element(RMAP_NODE
, &match_tag_cmd
);
3029 install_element(RMAP_NODE
, &no_match_tag_cmd
);
3031 install_element(RMAP_NODE
, &set_ip_nexthop_cmd
);
3032 install_element(RMAP_NODE
, &no_set_ip_nexthop_cmd
);
3034 install_element(RMAP_NODE
, &set_ipv6_nexthop_local_cmd
);
3035 install_element(RMAP_NODE
, &no_set_ipv6_nexthop_local_cmd
);
3037 install_element(RMAP_NODE
, &set_metric_cmd
);
3038 install_element(RMAP_NODE
, &no_set_metric_cmd
);
3040 install_element(RMAP_NODE
, &set_tag_cmd
);
3041 install_element(RMAP_NODE
, &no_set_tag_cmd
);