]> git.proxmox.com Git - mirror_frr.git/blob - lib/routemap.c
Merge pull request #3009 from pacovn/static_analysis__shadow_variables3
[mirror_frr.git] / lib / routemap.c
1 /* Route map function.
2 * Copyright (C) 1998, 1999 Kunihiro Ishiguro
3 *
4 * This file is part of GNU Zebra.
5 *
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
9 * later version.
10 *
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.
15 *
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
19 */
20
21 #include <zebra.h>
22
23 #include "linklist.h"
24 #include "memory.h"
25 #include "vector.h"
26 #include "prefix.h"
27 #include "vty.h"
28 #include "routemap.h"
29 #include "command.h"
30 #include "log.h"
31 #include "hash.h"
32 #include "libfrr.h"
33 #include "lib_errors.h"
34
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")
42
43 DEFINE_QOBJ_TYPE(route_map_index)
44 DEFINE_QOBJ_TYPE(route_map)
45
46 /* Vector for route match rules. */
47 static vector route_match_vec;
48
49 /* Vector for route set rules. */
50 static vector route_set_vec;
51
52 struct route_map_match_set_hooks {
53 /* match interface */
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);
57
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);
63
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);
68
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);
74
75 /* match ip address prefix list */
76 int (*match_ip_address_prefix_list)(struct vty *vty,
77 struct route_map_index *index,
78 const char *command,
79 const char *arg,
80 route_map_event_t type);
81
82 /* no match ip address prefix list */
83 int (*no_match_ip_address_prefix_list)(struct vty *vty,
84 struct route_map_index *index,
85 const char *command,
86 const char *arg,
87 route_map_event_t type);
88
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);
93
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);
99
100 /* match ip next hop prefix list */
101 int (*match_ip_next_hop_prefix_list)(struct vty *vty,
102 struct route_map_index *index,
103 const char *command,
104 const char *arg,
105 route_map_event_t type);
106
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,
110 const char *command,
111 const char *arg,
112 route_map_event_t type);
113
114 /* match ipv6 address */
115 int (*match_ipv6_address)(struct vty *vty,
116 struct route_map_index *index,
117 const char *command, const char *arg,
118 route_map_event_t type);
119
120 /* no match ipv6 address */
121 int (*no_match_ipv6_address)(struct vty *vty,
122 struct route_map_index *index,
123 const char *command, const char *arg,
124 route_map_event_t type);
125
126
127 /* match ipv6 address prefix list */
128 int (*match_ipv6_address_prefix_list)(struct vty *vty,
129 struct route_map_index *index,
130 const char *command,
131 const char *arg,
132 route_map_event_t type);
133
134 /* no match ipv6 address prefix list */
135 int (*no_match_ipv6_address_prefix_list)(struct vty *vty,
136 struct route_map_index *index,
137 const char *command,
138 const char *arg,
139 route_map_event_t type);
140
141 /* match metric */
142 int (*match_metric)(struct vty *vty, struct route_map_index *index,
143 const char *command, const char *arg,
144 route_map_event_t type);
145
146 /* no match metric */
147 int (*no_match_metric)(struct vty *vty, struct route_map_index *index,
148 const char *command, const char *arg,
149 route_map_event_t type);
150
151 /* match tag */
152 int (*match_tag)(struct vty *vty, struct route_map_index *index,
153 const char *command, const char *arg,
154 route_map_event_t type);
155
156 /* no match tag */
157 int (*no_match_tag)(struct vty *vty, struct route_map_index *index,
158 const char *command, const char *arg,
159 route_map_event_t type);
160
161 /* set ip nexthop */
162 int (*set_ip_nexthop)(struct vty *vty, struct route_map_index *index,
163 const char *command, const char *arg);
164
165 /* no set ip nexthop */
166 int (*no_set_ip_nexthop)(struct vty *vty, struct route_map_index *index,
167 const char *command, const char *arg);
168
169 /* set ipv6 nexthop local */
170 int (*set_ipv6_nexthop_local)(struct vty *vty,
171 struct route_map_index *index,
172 const char *command, const char *arg);
173
174 /* no set ipv6 nexthop local */
175 int (*no_set_ipv6_nexthop_local)(struct vty *vty,
176 struct route_map_index *index,
177 const char *command, const char *arg);
178
179 /* set metric */
180 int (*set_metric)(struct vty *vty, struct route_map_index *index,
181 const char *command, const char *arg);
182
183 /* no set metric */
184 int (*no_set_metric)(struct vty *vty, struct route_map_index *index,
185 const char *command, const char *arg);
186
187 /* set tag */
188 int (*set_tag)(struct vty *vty, struct route_map_index *index,
189 const char *command, const char *arg);
190
191 /* no set tag */
192 int (*no_set_tag)(struct vty *vty, struct route_map_index *index,
193 const char *command, const char *arg);
194 };
195
196 struct route_map_match_set_hooks rmap_match_set_hook;
197
198 /* match interface */
199 void route_map_match_interface_hook(int (*func)(
200 struct vty *vty, struct route_map_index *index, const char *command,
201 const char *arg, route_map_event_t type))
202 {
203 rmap_match_set_hook.match_interface = func;
204 }
205
206 /* no match interface */
207 void route_map_no_match_interface_hook(int (*func)(
208 struct vty *vty, struct route_map_index *index, const char *command,
209 const char *arg, route_map_event_t type))
210 {
211 rmap_match_set_hook.no_match_interface = func;
212 }
213
214 /* match ip address */
215 void route_map_match_ip_address_hook(int (*func)(
216 struct vty *vty, struct route_map_index *index, const char *command,
217 const char *arg, route_map_event_t type))
218 {
219 rmap_match_set_hook.match_ip_address = func;
220 }
221
222 /* no match ip address */
223 void route_map_no_match_ip_address_hook(int (*func)(
224 struct vty *vty, struct route_map_index *index, const char *command,
225 const char *arg, route_map_event_t type))
226 {
227 rmap_match_set_hook.no_match_ip_address = func;
228 }
229
230 /* match ip address prefix list */
231 void route_map_match_ip_address_prefix_list_hook(int (*func)(
232 struct vty *vty, struct route_map_index *index, const char *command,
233 const char *arg, route_map_event_t type))
234 {
235 rmap_match_set_hook.match_ip_address_prefix_list = func;
236 }
237
238 /* no match ip address prefix list */
239 void route_map_no_match_ip_address_prefix_list_hook(int (*func)(
240 struct vty *vty, struct route_map_index *index, const char *command,
241 const char *arg, route_map_event_t type))
242 {
243 rmap_match_set_hook.no_match_ip_address_prefix_list = func;
244 }
245
246 /* match ip next hop */
247 void route_map_match_ip_next_hop_hook(int (*func)(
248 struct vty *vty, struct route_map_index *index, const char *command,
249 const char *arg, route_map_event_t type))
250 {
251 rmap_match_set_hook.match_ip_next_hop = func;
252 }
253
254 /* no match ip next hop */
255 void route_map_no_match_ip_next_hop_hook(int (*func)(
256 struct vty *vty, struct route_map_index *index, const char *command,
257 const char *arg, route_map_event_t type))
258 {
259 rmap_match_set_hook.no_match_ip_next_hop = func;
260 }
261
262 /* match ip next hop prefix list */
263 void route_map_match_ip_next_hop_prefix_list_hook(int (*func)(
264 struct vty *vty, struct route_map_index *index, const char *command,
265 const char *arg, route_map_event_t type))
266 {
267 rmap_match_set_hook.match_ip_next_hop_prefix_list = func;
268 }
269
270 /* no match ip next hop prefix list */
271 void route_map_no_match_ip_next_hop_prefix_list_hook(int (*func)(
272 struct vty *vty, struct route_map_index *index, const char *command,
273 const char *arg, route_map_event_t type))
274 {
275 rmap_match_set_hook.no_match_ip_next_hop_prefix_list = func;
276 }
277
278 /* match ipv6 address */
279 void route_map_match_ipv6_address_hook(int (*func)(
280 struct vty *vty, struct route_map_index *index, const char *command,
281 const char *arg, route_map_event_t type))
282 {
283 rmap_match_set_hook.match_ipv6_address = func;
284 }
285
286 /* no match ipv6 address */
287 void route_map_no_match_ipv6_address_hook(int (*func)(
288 struct vty *vty, struct route_map_index *index, const char *command,
289 const char *arg, route_map_event_t type))
290 {
291 rmap_match_set_hook.no_match_ipv6_address = func;
292 }
293
294
295 /* match ipv6 address prefix list */
296 void route_map_match_ipv6_address_prefix_list_hook(int (*func)(
297 struct vty *vty, struct route_map_index *index, const char *command,
298 const char *arg, route_map_event_t type))
299 {
300 rmap_match_set_hook.match_ipv6_address_prefix_list = func;
301 }
302
303 /* no match ipv6 address prefix list */
304 void route_map_no_match_ipv6_address_prefix_list_hook(int (*func)(
305 struct vty *vty, struct route_map_index *index, const char *command,
306 const char *arg, route_map_event_t type))
307 {
308 rmap_match_set_hook.no_match_ipv6_address_prefix_list = func;
309 }
310
311 /* match metric */
312 void route_map_match_metric_hook(int (*func)(
313 struct vty *vty, struct route_map_index *index, const char *command,
314 const char *arg, route_map_event_t type))
315 {
316 rmap_match_set_hook.match_metric = func;
317 }
318
319 /* no match metric */
320 void route_map_no_match_metric_hook(int (*func)(
321 struct vty *vty, struct route_map_index *index, const char *command,
322 const char *arg, route_map_event_t type))
323 {
324 rmap_match_set_hook.no_match_metric = func;
325 }
326
327 /* match tag */
328 void route_map_match_tag_hook(int (*func)(struct vty *vty,
329 struct route_map_index *index,
330 const char *command, const char *arg,
331 route_map_event_t type))
332 {
333 rmap_match_set_hook.match_tag = func;
334 }
335
336 /* no match tag */
337 void route_map_no_match_tag_hook(int (*func)(
338 struct vty *vty, struct route_map_index *index, const char *command,
339 const char *arg, route_map_event_t type))
340 {
341 rmap_match_set_hook.no_match_tag = func;
342 }
343
344 /* set ip nexthop */
345 void route_map_set_ip_nexthop_hook(int (*func)(struct vty *vty,
346 struct route_map_index *index,
347 const char *command,
348 const char *arg))
349 {
350 rmap_match_set_hook.set_ip_nexthop = func;
351 }
352
353 /* no set ip nexthop */
354 void route_map_no_set_ip_nexthop_hook(int (*func)(struct vty *vty,
355 struct route_map_index *index,
356 const char *command,
357 const char *arg))
358 {
359 rmap_match_set_hook.no_set_ip_nexthop = func;
360 }
361
362 /* set ipv6 nexthop local */
363 void route_map_set_ipv6_nexthop_local_hook(
364 int (*func)(struct vty *vty, struct route_map_index *index,
365 const char *command, const char *arg))
366 {
367 rmap_match_set_hook.set_ipv6_nexthop_local = func;
368 }
369
370 /* no set ipv6 nexthop local */
371 void route_map_no_set_ipv6_nexthop_local_hook(
372 int (*func)(struct vty *vty, struct route_map_index *index,
373 const char *command, const char *arg))
374 {
375 rmap_match_set_hook.no_set_ipv6_nexthop_local = func;
376 }
377
378 /* set metric */
379 void route_map_set_metric_hook(int (*func)(struct vty *vty,
380 struct route_map_index *index,
381 const char *command,
382 const char *arg))
383 {
384 rmap_match_set_hook.set_metric = func;
385 }
386
387 /* no set metric */
388 void route_map_no_set_metric_hook(int (*func)(struct vty *vty,
389 struct route_map_index *index,
390 const char *command,
391 const char *arg))
392 {
393 rmap_match_set_hook.no_set_metric = func;
394 }
395
396 /* set tag */
397 void route_map_set_tag_hook(int (*func)(struct vty *vty,
398 struct route_map_index *index,
399 const char *command, const char *arg))
400 {
401 rmap_match_set_hook.set_tag = func;
402 }
403
404 /* no set tag */
405 void route_map_no_set_tag_hook(int (*func)(struct vty *vty,
406 struct route_map_index *index,
407 const char *command,
408 const char *arg))
409 {
410 rmap_match_set_hook.no_set_tag = func;
411 }
412
413 int generic_match_add(struct vty *vty, struct route_map_index *index,
414 const char *command, const char *arg,
415 route_map_event_t type)
416 {
417 int ret;
418
419 ret = route_map_add_match(index, command, arg);
420 switch (ret) {
421 case RMAP_COMPILE_SUCCESS:
422 if (type != RMAP_EVENT_MATCH_ADDED) {
423 route_map_upd8_dependency(type, arg, index->map->name);
424 }
425 break;
426 case RMAP_RULE_MISSING:
427 vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst);
428 return CMD_WARNING_CONFIG_FAILED;
429 break;
430 case RMAP_COMPILE_ERROR:
431 vty_out(vty,
432 "%% [%s] Argument form is unsupported or malformed.\n",
433 frr_protonameinst);
434 return CMD_WARNING_CONFIG_FAILED;
435 break;
436 }
437
438 return CMD_SUCCESS;
439 }
440
441 int generic_match_delete(struct vty *vty, struct route_map_index *index,
442 const char *command, const char *arg,
443 route_map_event_t type)
444 {
445 int ret;
446 int retval = CMD_SUCCESS;
447 char *dep_name = NULL;
448 const char *tmpstr;
449 char *rmap_name = NULL;
450
451 if (type != RMAP_EVENT_MATCH_DELETED) {
452 /* ignore the mundane, the types without any dependency */
453 if (arg == NULL) {
454 if ((tmpstr = route_map_get_match_arg(index, command))
455 != NULL)
456 dep_name =
457 XSTRDUP(MTYPE_ROUTE_MAP_RULE, tmpstr);
458 } else {
459 dep_name = XSTRDUP(MTYPE_ROUTE_MAP_RULE, arg);
460 }
461 rmap_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, index->map->name);
462 }
463
464 ret = route_map_delete_match(index, command, dep_name);
465 switch (ret) {
466 case RMAP_RULE_MISSING:
467 vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst);
468 retval = CMD_WARNING_CONFIG_FAILED;
469 break;
470 case RMAP_COMPILE_ERROR:
471 vty_out(vty,
472 "%% [%s] Argument form is unsupported or malformed.\n",
473 frr_protonameinst);
474 retval = CMD_WARNING_CONFIG_FAILED;
475 break;
476 case RMAP_COMPILE_SUCCESS:
477 if (type != RMAP_EVENT_MATCH_DELETED && dep_name)
478 route_map_upd8_dependency(type, dep_name, rmap_name);
479 break;
480 }
481
482 if (dep_name)
483 XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
484 if (rmap_name)
485 XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
486
487 return retval;
488 }
489
490 int generic_set_add(struct vty *vty, struct route_map_index *index,
491 const char *command, const char *arg)
492 {
493 int ret;
494
495 ret = route_map_add_set(index, command, arg);
496 switch (ret) {
497 case RMAP_RULE_MISSING:
498 vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst);
499 return CMD_WARNING_CONFIG_FAILED;
500 break;
501 case RMAP_COMPILE_ERROR:
502 vty_out(vty,
503 "%% [%s] Argument form is unsupported or malformed.\n",
504 frr_protonameinst);
505 return CMD_WARNING_CONFIG_FAILED;
506 break;
507 case RMAP_COMPILE_SUCCESS:
508 break;
509 }
510
511 return CMD_SUCCESS;
512 }
513
514 int generic_set_delete(struct vty *vty, struct route_map_index *index,
515 const char *command, const char *arg)
516 {
517 int ret;
518
519 ret = route_map_delete_set(index, command, arg);
520 switch (ret) {
521 case RMAP_RULE_MISSING:
522 vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst);
523 return CMD_WARNING_CONFIG_FAILED;
524 break;
525 case RMAP_COMPILE_ERROR:
526 vty_out(vty,
527 "%% [%s] Argument form is unsupported or malformed.\n",
528 frr_protonameinst);
529 return CMD_WARNING_CONFIG_FAILED;
530 break;
531 case RMAP_COMPILE_SUCCESS:
532 break;
533 }
534
535 return CMD_SUCCESS;
536 }
537
538
539 /* Route map rule. This rule has both `match' rule and `set' rule. */
540 struct route_map_rule {
541 /* Rule type. */
542 struct route_map_rule_cmd *cmd;
543
544 /* For pretty printing. */
545 char *rule_str;
546
547 /* Pre-compiled match rule. */
548 void *value;
549
550 /* Linked list. */
551 struct route_map_rule *next;
552 struct route_map_rule *prev;
553 };
554
555 /* Making route map list. */
556 struct route_map_list {
557 struct route_map *head;
558 struct route_map *tail;
559
560 void (*add_hook)(const char *);
561 void (*delete_hook)(const char *);
562 void (*event_hook)(route_map_event_t, const char *);
563 };
564
565 /* Master list of route map. */
566 static struct route_map_list route_map_master = {NULL, NULL, NULL, NULL, NULL};
567 struct hash *route_map_master_hash = NULL;
568
569 static unsigned int route_map_hash_key_make(void *p)
570 {
571 const struct route_map *map = p;
572 return string_hash_make(map->name);
573 }
574
575 static int route_map_hash_cmp(const void *p1, const void *p2)
576 {
577 const struct route_map *map1 = p1;
578 const struct route_map *map2 = p2;
579
580 if (map1->deleted == map2->deleted) {
581 if (map1->name && map2->name) {
582 if (!strcmp(map1->name, map2->name)) {
583 return 1;
584 }
585 } else if (!map1->name && !map2->name) {
586 return 1;
587 }
588 }
589
590 return 0;
591 }
592
593 enum route_map_upd8_type {
594 ROUTE_MAP_ADD = 1,
595 ROUTE_MAP_DEL,
596 };
597
598 /* all possible route-map dependency types */
599 enum route_map_dep_type {
600 ROUTE_MAP_DEP_RMAP = 1,
601 ROUTE_MAP_DEP_CLIST,
602 ROUTE_MAP_DEP_ECLIST,
603 ROUTE_MAP_DEP_LCLIST,
604 ROUTE_MAP_DEP_PLIST,
605 ROUTE_MAP_DEP_ASPATH,
606 ROUTE_MAP_DEP_FILTER,
607 ROUTE_MAP_DEP_MAX,
608 };
609
610 struct route_map_dep {
611 char *dep_name;
612 struct hash *dep_rmap_hash;
613 struct hash *this_hash; /* ptr to the hash structure this is part of */
614 };
615
616 /* Hashes maintaining dependency between various sublists used by route maps */
617 struct hash *route_map_dep_hash[ROUTE_MAP_DEP_MAX];
618
619 static unsigned int route_map_dep_hash_make_key(void *p);
620 static int route_map_dep_hash_cmp(const void *p1, const void *p2);
621 static void route_map_clear_all_references(char *rmap_name);
622 static void route_map_rule_delete(struct route_map_rule_list *,
623 struct route_map_rule *);
624 static int rmap_debug = 0;
625
626 static void route_map_index_delete(struct route_map_index *, int);
627
628 /* New route map allocation. Please note route map's name must be
629 specified. */
630 static struct route_map *route_map_new(const char *name)
631 {
632 struct route_map *new;
633
634 new = XCALLOC(MTYPE_ROUTE_MAP, sizeof(struct route_map));
635 new->name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, name);
636 QOBJ_REG(new, route_map);
637 return new;
638 }
639
640 /* Add new name to route_map. */
641 static struct route_map *route_map_add(const char *name)
642 {
643 struct route_map *map;
644 struct route_map_list *list;
645
646 map = route_map_new(name);
647 list = &route_map_master;
648
649 /* Add map to the hash */
650 hash_get(route_map_master_hash, map, hash_alloc_intern);
651
652 /* Add new entry to the head of the list to match how it is added in the
653 * hash table. This is to ensure that if the same route-map has been
654 * created more than once and then marked for deletion (which can happen
655 * if prior deletions haven't completed as BGP hasn't yet done the
656 * route-map processing), the order of the entities is the same in both
657 * the list and the hash table. Otherwise, since there is nothing to
658 * distinguish between the two entries, the wrong entry could get freed.
659 * TODO: This needs to be re-examined to handle it better - e.g., revive
660 * a deleted entry if the route-map is created again.
661 */
662 map->prev = NULL;
663 map->next = list->head;
664 if (list->head)
665 list->head->prev = map;
666 list->head = map;
667 if (!list->tail)
668 list->tail = map;
669
670 /* Execute hook. */
671 if (route_map_master.add_hook) {
672 (*route_map_master.add_hook)(name);
673 route_map_notify_dependencies(name, RMAP_EVENT_CALL_ADDED);
674 }
675 return map;
676 }
677
678 /* this is supposed to be called post processing by
679 * the delete hook function. Don't invoke delete_hook
680 * again in this routine.
681 */
682 static void route_map_free_map(struct route_map *map)
683 {
684 struct route_map_list *list;
685 struct route_map_index *index;
686
687 if (map == NULL)
688 return;
689
690 while ((index = map->head) != NULL)
691 route_map_index_delete(index, 0);
692
693 list = &route_map_master;
694
695 QOBJ_UNREG(map);
696
697 if (map->next)
698 map->next->prev = map->prev;
699 else
700 list->tail = map->prev;
701
702 if (map->prev)
703 map->prev->next = map->next;
704 else
705 list->head = map->next;
706
707 hash_release(route_map_master_hash, map);
708 XFREE(MTYPE_ROUTE_MAP_NAME, map->name);
709 XFREE(MTYPE_ROUTE_MAP, map);
710 }
711
712 /* Route map delete from list. */
713 static void route_map_delete(struct route_map *map)
714 {
715 struct route_map_index *index;
716 char *name;
717
718 while ((index = map->head) != NULL)
719 route_map_index_delete(index, 0);
720
721 name = map->name;
722 map->head = NULL;
723
724 /* Clear all dependencies */
725 route_map_clear_all_references(name);
726 map->deleted = true;
727 /* Execute deletion hook. */
728 if (route_map_master.delete_hook) {
729 (*route_map_master.delete_hook)(name);
730 route_map_notify_dependencies(name, RMAP_EVENT_CALL_DELETED);
731 }
732
733 if (!map->to_be_processed) {
734 route_map_free_map(map);
735 }
736 }
737
738 /* Lookup route map by route map name string. */
739 struct route_map *route_map_lookup_by_name(const char *name)
740 {
741 struct route_map *map;
742 struct route_map tmp_map;
743
744 if (!name)
745 return NULL;
746
747 // map.deleted is 0 via memset
748 memset(&tmp_map, 0, sizeof(struct route_map));
749 tmp_map.name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, name);
750 map = hash_lookup(route_map_master_hash, &tmp_map);
751 XFREE(MTYPE_ROUTE_MAP_NAME, tmp_map.name);
752 return map;
753 }
754
755 int route_map_mark_updated(const char *name)
756 {
757 struct route_map *map;
758 int ret = -1;
759 struct route_map tmp_map;
760
761 if (!name)
762 return (ret);
763
764 map = route_map_lookup_by_name(name);
765
766 /* If we did not find the routemap with deleted=false try again
767 * with deleted=true
768 */
769 if (!map) {
770 memset(&tmp_map, 0, sizeof(struct route_map));
771 tmp_map.name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, name);
772 tmp_map.deleted = true;
773 map = hash_lookup(route_map_master_hash, &tmp_map);
774 XFREE(MTYPE_ROUTE_MAP_NAME, tmp_map.name);
775 }
776
777 if (map) {
778 map->to_be_processed = true;
779 ret = 0;
780 }
781
782 return (ret);
783 }
784
785 static int route_map_clear_updated(struct route_map *map)
786 {
787 int ret = -1;
788
789 if (map) {
790 map->to_be_processed = false;
791 if (map->deleted)
792 route_map_free_map(map);
793 }
794
795 return (ret);
796 }
797
798 /* Lookup route map. If there isn't route map create one and return
799 it. */
800 static struct route_map *route_map_get(const char *name)
801 {
802 struct route_map *map;
803
804 map = route_map_lookup_by_name(name);
805 if (map == NULL)
806 map = route_map_add(name);
807
808 return map;
809 }
810
811 void route_map_walk_update_list(void (*route_map_update_fn)(char *name))
812 {
813 struct route_map *node;
814 struct route_map *nnode = NULL;
815
816 for (node = route_map_master.head; node; node = nnode) {
817 if (node->to_be_processed) {
818 /* DD: Should we add any thread yield code here */
819 route_map_update_fn(node->name);
820 nnode = node->next;
821 route_map_clear_updated(node);
822 } else
823 nnode = node->next;
824 }
825 }
826
827 /* Return route map's type string. */
828 static const char *route_map_type_str(enum route_map_type type)
829 {
830 switch (type) {
831 case RMAP_PERMIT:
832 return "permit";
833 break;
834 case RMAP_DENY:
835 return "deny";
836 break;
837 default:
838 return "";
839 break;
840 }
841 }
842
843 static int route_map_empty(struct route_map *map)
844 {
845 if (map->head == NULL && map->tail == NULL)
846 return 1;
847 else
848 return 0;
849 }
850
851 /* show route-map */
852 static void vty_show_route_map_entry(struct vty *vty, struct route_map *map)
853 {
854 struct route_map_index *index;
855 struct route_map_rule *rule;
856
857 vty_out(vty, "%s:\n", frr_protonameinst);
858
859 for (index = map->head; index; index = index->next) {
860 vty_out(vty, "route-map %s, %s, sequence %d\n", map->name,
861 route_map_type_str(index->type), index->pref);
862
863 /* Description */
864 if (index->description)
865 vty_out(vty, " Description:\n %s\n",
866 index->description);
867
868 /* Match clauses */
869 vty_out(vty, " Match clauses:\n");
870 for (rule = index->match_list.head; rule; rule = rule->next)
871 vty_out(vty, " %s %s\n", rule->cmd->str,
872 rule->rule_str);
873
874 vty_out(vty, " Set clauses:\n");
875 for (rule = index->set_list.head; rule; rule = rule->next)
876 vty_out(vty, " %s %s\n", rule->cmd->str,
877 rule->rule_str);
878
879 /* Call clause */
880 vty_out(vty, " Call clause:\n");
881 if (index->nextrm)
882 vty_out(vty, " Call %s\n", index->nextrm);
883
884 /* Exit Policy */
885 vty_out(vty, " Action:\n");
886 if (index->exitpolicy == RMAP_GOTO)
887 vty_out(vty, " Goto %d\n", index->nextpref);
888 else if (index->exitpolicy == RMAP_NEXT)
889 vty_out(vty, " Continue to next entry\n");
890 else if (index->exitpolicy == RMAP_EXIT)
891 vty_out(vty, " Exit routemap\n");
892 }
893 }
894
895 static int sort_route_map(const void **map1, const void **map2)
896 {
897 const struct route_map *m1 = *map1;
898 const struct route_map *m2 = *map2;
899
900 return strcmp(m1->name, m2->name);
901 }
902
903 static int vty_show_route_map(struct vty *vty, const char *name)
904 {
905 struct route_map *map;
906
907 if (name) {
908 map = route_map_lookup_by_name(name);
909
910 if (map) {
911 vty_show_route_map_entry(vty, map);
912 return CMD_SUCCESS;
913 } else {
914 vty_out(vty, "%s: 'route-map %s' not found\n",
915 frr_protonameinst, name);
916 return CMD_SUCCESS;
917 }
918 } else {
919
920 struct list *maplist = list_new();
921 struct listnode *ln;
922
923 for (map = route_map_master.head; map; map = map->next)
924 listnode_add(maplist, map);
925
926 list_sort(maplist, sort_route_map);
927
928 for (ALL_LIST_ELEMENTS_RO(maplist, ln, map))
929 vty_show_route_map_entry(vty, map);
930
931 list_delete_and_null(&maplist);
932 }
933 return CMD_SUCCESS;
934 }
935
936
937 /* New route map allocation. Please note route map's name must be
938 specified. */
939 static struct route_map_index *route_map_index_new(void)
940 {
941 struct route_map_index *new;
942
943 new = XCALLOC(MTYPE_ROUTE_MAP_INDEX, sizeof(struct route_map_index));
944 new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */
945 QOBJ_REG(new, route_map_index);
946 return new;
947 }
948
949 /* Free route map index. */
950 static void route_map_index_delete(struct route_map_index *index, int notify)
951 {
952 struct route_map_rule *rule;
953
954 QOBJ_UNREG(index);
955
956 /* Free route match. */
957 while ((rule = index->match_list.head) != NULL)
958 route_map_rule_delete(&index->match_list, rule);
959
960 /* Free route set. */
961 while ((rule = index->set_list.head) != NULL)
962 route_map_rule_delete(&index->set_list, rule);
963
964 /* Remove index from route map list. */
965 if (index->next)
966 index->next->prev = index->prev;
967 else
968 index->map->tail = index->prev;
969
970 if (index->prev)
971 index->prev->next = index->next;
972 else
973 index->map->head = index->next;
974
975 /* Free 'char *nextrm' if not NULL */
976 if (index->nextrm)
977 XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
978
979 /* Execute event hook. */
980 if (route_map_master.event_hook && notify) {
981 (*route_map_master.event_hook)(RMAP_EVENT_INDEX_DELETED,
982 index->map->name);
983 route_map_notify_dependencies(index->map->name,
984 RMAP_EVENT_CALL_ADDED);
985 }
986 XFREE(MTYPE_ROUTE_MAP_INDEX, index);
987 }
988
989 /* Lookup index from route map. */
990 static struct route_map_index *route_map_index_lookup(struct route_map *map,
991 enum route_map_type type,
992 int pref)
993 {
994 struct route_map_index *index;
995
996 for (index = map->head; index; index = index->next)
997 if ((index->type == type || type == RMAP_ANY)
998 && index->pref == pref)
999 return index;
1000 return NULL;
1001 }
1002
1003 /* Add new index to route map. */
1004 static struct route_map_index *
1005 route_map_index_add(struct route_map *map, enum route_map_type type, int pref)
1006 {
1007 struct route_map_index *index;
1008 struct route_map_index *point;
1009
1010 /* Allocate new route map inex. */
1011 index = route_map_index_new();
1012 index->map = map;
1013 index->type = type;
1014 index->pref = pref;
1015
1016 /* Compare preference. */
1017 for (point = map->head; point; point = point->next)
1018 if (point->pref >= pref)
1019 break;
1020
1021 if (map->head == NULL) {
1022 map->head = map->tail = index;
1023 } else if (point == NULL) {
1024 index->prev = map->tail;
1025 map->tail->next = index;
1026 map->tail = index;
1027 } else if (point == map->head) {
1028 index->next = map->head;
1029 map->head->prev = index;
1030 map->head = index;
1031 } else {
1032 index->next = point;
1033 index->prev = point->prev;
1034 if (point->prev)
1035 point->prev->next = index;
1036 point->prev = index;
1037 }
1038
1039 /* Execute event hook. */
1040 if (route_map_master.event_hook) {
1041 (*route_map_master.event_hook)(RMAP_EVENT_INDEX_ADDED,
1042 map->name);
1043 route_map_notify_dependencies(map->name, RMAP_EVENT_CALL_ADDED);
1044 }
1045 return index;
1046 }
1047
1048 /* Get route map index. */
1049 static struct route_map_index *
1050 route_map_index_get(struct route_map *map, enum route_map_type type, int pref)
1051 {
1052 struct route_map_index *index;
1053
1054 index = route_map_index_lookup(map, RMAP_ANY, pref);
1055 if (index && index->type != type) {
1056 /* Delete index from route map. */
1057 route_map_index_delete(index, 1);
1058 index = NULL;
1059 }
1060 if (index == NULL)
1061 index = route_map_index_add(map, type, pref);
1062 return index;
1063 }
1064
1065 /* New route map rule */
1066 static struct route_map_rule *route_map_rule_new(void)
1067 {
1068 struct route_map_rule *new;
1069
1070 new = XCALLOC(MTYPE_ROUTE_MAP_RULE, sizeof(struct route_map_rule));
1071 return new;
1072 }
1073
1074 /* Install rule command to the match list. */
1075 void route_map_install_match(struct route_map_rule_cmd *cmd)
1076 {
1077 vector_set(route_match_vec, cmd);
1078 }
1079
1080 /* Install rule command to the set list. */
1081 void route_map_install_set(struct route_map_rule_cmd *cmd)
1082 {
1083 vector_set(route_set_vec, cmd);
1084 }
1085
1086 /* Lookup rule command from match list. */
1087 static struct route_map_rule_cmd *route_map_lookup_match(const char *name)
1088 {
1089 unsigned int i;
1090 struct route_map_rule_cmd *rule;
1091
1092 for (i = 0; i < vector_active(route_match_vec); i++)
1093 if ((rule = vector_slot(route_match_vec, i)) != NULL)
1094 if (strcmp(rule->str, name) == 0)
1095 return rule;
1096 return NULL;
1097 }
1098
1099 /* Lookup rule command from set list. */
1100 static struct route_map_rule_cmd *route_map_lookup_set(const char *name)
1101 {
1102 unsigned int i;
1103 struct route_map_rule_cmd *rule;
1104
1105 for (i = 0; i < vector_active(route_set_vec); i++)
1106 if ((rule = vector_slot(route_set_vec, i)) != NULL)
1107 if (strcmp(rule->str, name) == 0)
1108 return rule;
1109 return NULL;
1110 }
1111
1112 /* Add match and set rule to rule list. */
1113 static void route_map_rule_add(struct route_map_rule_list *list,
1114 struct route_map_rule *rule)
1115 {
1116 rule->next = NULL;
1117 rule->prev = list->tail;
1118 if (list->tail)
1119 list->tail->next = rule;
1120 else
1121 list->head = rule;
1122 list->tail = rule;
1123 }
1124
1125 /* Delete rule from rule list. */
1126 static void route_map_rule_delete(struct route_map_rule_list *list,
1127 struct route_map_rule *rule)
1128 {
1129 if (rule->cmd->func_free)
1130 (*rule->cmd->func_free)(rule->value);
1131
1132 if (rule->rule_str)
1133 XFREE(MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str);
1134
1135 if (rule->next)
1136 rule->next->prev = rule->prev;
1137 else
1138 list->tail = rule->prev;
1139 if (rule->prev)
1140 rule->prev->next = rule->next;
1141 else
1142 list->head = rule->next;
1143
1144 XFREE(MTYPE_ROUTE_MAP_RULE, rule);
1145 }
1146
1147 /* strcmp wrapper function which don't crush even argument is NULL. */
1148 static int rulecmp(const char *dst, const char *src)
1149 {
1150 if (dst == NULL) {
1151 if (src == NULL)
1152 return 0;
1153 else
1154 return 1;
1155 } else {
1156 if (src == NULL)
1157 return 1;
1158 else
1159 return strcmp(dst, src);
1160 }
1161 return 1;
1162 }
1163
1164 /* Use this to return the already specified argument for this match. This is
1165 * useful to get the specified argument with a route map match rule when the
1166 * rule is being deleted and the argument is not provided.
1167 */
1168 const char *route_map_get_match_arg(struct route_map_index *index,
1169 const char *match_name)
1170 {
1171 struct route_map_rule *rule;
1172 struct route_map_rule_cmd *cmd;
1173
1174 /* First lookup rule for add match statement. */
1175 cmd = route_map_lookup_match(match_name);
1176 if (cmd == NULL)
1177 return NULL;
1178
1179 for (rule = index->match_list.head; rule; rule = rule->next)
1180 if (rule->cmd == cmd && rule->rule_str != NULL)
1181 return (rule->rule_str);
1182
1183 return (NULL);
1184 }
1185
1186 /* Add match statement to route map. */
1187 int route_map_add_match(struct route_map_index *index, const char *match_name,
1188 const char *match_arg)
1189 {
1190 struct route_map_rule *rule;
1191 struct route_map_rule *next;
1192 struct route_map_rule_cmd *cmd;
1193 void *compile;
1194 int replaced = 0;
1195
1196 /* First lookup rule for add match statement. */
1197 cmd = route_map_lookup_match(match_name);
1198 if (cmd == NULL)
1199 return RMAP_RULE_MISSING;
1200
1201 /* Next call compile function for this match statement. */
1202 if (cmd->func_compile) {
1203 compile = (*cmd->func_compile)(match_arg);
1204 if (compile == NULL)
1205 return RMAP_COMPILE_ERROR;
1206 } else
1207 compile = NULL;
1208
1209 /* If argument is completely same ignore it. */
1210 for (rule = index->match_list.head; rule; rule = next) {
1211 next = rule->next;
1212 if (rule->cmd == cmd) {
1213 route_map_rule_delete(&index->match_list, rule);
1214 replaced = 1;
1215 }
1216 }
1217
1218 /* Add new route map match rule. */
1219 rule = route_map_rule_new();
1220 rule->cmd = cmd;
1221 rule->value = compile;
1222 if (match_arg)
1223 rule->rule_str = XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR, match_arg);
1224 else
1225 rule->rule_str = NULL;
1226
1227 /* Add new route match rule to linked list. */
1228 route_map_rule_add(&index->match_list, rule);
1229
1230 /* Execute event hook. */
1231 if (route_map_master.event_hook) {
1232 (*route_map_master.event_hook)(
1233 replaced ? RMAP_EVENT_MATCH_REPLACED
1234 : RMAP_EVENT_MATCH_ADDED,
1235 index->map->name);
1236 route_map_notify_dependencies(index->map->name,
1237 RMAP_EVENT_CALL_ADDED);
1238 }
1239
1240 return RMAP_COMPILE_SUCCESS;
1241 }
1242
1243 /* Delete specified route match rule. */
1244 int route_map_delete_match(struct route_map_index *index,
1245 const char *match_name, const char *match_arg)
1246 {
1247 struct route_map_rule *rule;
1248 struct route_map_rule_cmd *cmd;
1249
1250 cmd = route_map_lookup_match(match_name);
1251 if (cmd == NULL)
1252 return 1;
1253
1254 for (rule = index->match_list.head; rule; rule = rule->next)
1255 if (rule->cmd == cmd && (rulecmp(rule->rule_str, match_arg) == 0
1256 || match_arg == NULL)) {
1257 route_map_rule_delete(&index->match_list, rule);
1258 /* Execute event hook. */
1259 if (route_map_master.event_hook) {
1260 (*route_map_master.event_hook)(
1261 RMAP_EVENT_MATCH_DELETED,
1262 index->map->name);
1263 route_map_notify_dependencies(
1264 index->map->name,
1265 RMAP_EVENT_CALL_ADDED);
1266 }
1267 return 0;
1268 }
1269 /* Can't find matched rule. */
1270 return 1;
1271 }
1272
1273 /* Add route-map set statement to the route map. */
1274 int route_map_add_set(struct route_map_index *index, const char *set_name,
1275 const char *set_arg)
1276 {
1277 struct route_map_rule *rule;
1278 struct route_map_rule *next;
1279 struct route_map_rule_cmd *cmd;
1280 void *compile;
1281 int replaced = 0;
1282
1283 cmd = route_map_lookup_set(set_name);
1284 if (cmd == NULL)
1285 return RMAP_RULE_MISSING;
1286
1287 /* Next call compile function for this match statement. */
1288 if (cmd->func_compile) {
1289 compile = (*cmd->func_compile)(set_arg);
1290 if (compile == NULL)
1291 return RMAP_COMPILE_ERROR;
1292 } else
1293 compile = NULL;
1294
1295 /* Add by WJL. if old set command of same kind exist, delete it first
1296 to ensure only one set command of same kind exist under a
1297 route_map_index. */
1298 for (rule = index->set_list.head; rule; rule = next) {
1299 next = rule->next;
1300 if (rule->cmd == cmd) {
1301 route_map_rule_delete(&index->set_list, rule);
1302 replaced = 1;
1303 }
1304 }
1305
1306 /* Add new route map match rule. */
1307 rule = route_map_rule_new();
1308 rule->cmd = cmd;
1309 rule->value = compile;
1310 if (set_arg)
1311 rule->rule_str = XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR, set_arg);
1312 else
1313 rule->rule_str = NULL;
1314
1315 /* Add new route match rule to linked list. */
1316 route_map_rule_add(&index->set_list, rule);
1317
1318 /* Execute event hook. */
1319 if (route_map_master.event_hook) {
1320 (*route_map_master.event_hook)(replaced
1321 ? RMAP_EVENT_SET_REPLACED
1322 : RMAP_EVENT_SET_ADDED,
1323 index->map->name);
1324 route_map_notify_dependencies(index->map->name,
1325 RMAP_EVENT_CALL_ADDED);
1326 }
1327 return RMAP_COMPILE_SUCCESS;
1328 }
1329
1330 /* Delete route map set rule. */
1331 int route_map_delete_set(struct route_map_index *index, const char *set_name,
1332 const char *set_arg)
1333 {
1334 struct route_map_rule *rule;
1335 struct route_map_rule_cmd *cmd;
1336
1337 cmd = route_map_lookup_set(set_name);
1338 if (cmd == NULL)
1339 return 1;
1340
1341 for (rule = index->set_list.head; rule; rule = rule->next)
1342 if ((rule->cmd == cmd) && (rulecmp(rule->rule_str, set_arg) == 0
1343 || set_arg == NULL)) {
1344 route_map_rule_delete(&index->set_list, rule);
1345 /* Execute event hook. */
1346 if (route_map_master.event_hook) {
1347 (*route_map_master.event_hook)(
1348 RMAP_EVENT_SET_DELETED,
1349 index->map->name);
1350 route_map_notify_dependencies(
1351 index->map->name,
1352 RMAP_EVENT_CALL_ADDED);
1353 }
1354 return 0;
1355 }
1356 /* Can't find matched rule. */
1357 return 1;
1358 }
1359
1360 /* Apply route map's each index to the object.
1361
1362 The matrix for a route-map looks like this:
1363 (note, this includes the description for the "NEXT"
1364 and "GOTO" frobs now
1365
1366 Match | No Match
1367 |
1368 permit action | cont
1369 |
1370 ------------------+---------------
1371 |
1372 deny deny | cont
1373 |
1374
1375 action)
1376 -Apply Set statements, accept route
1377 -If Call statement is present jump to the specified route-map, if it
1378 denies the route we finish.
1379 -If NEXT is specified, goto NEXT statement
1380 -If GOTO is specified, goto the first clause where pref > nextpref
1381 -If nothing is specified, do as Cisco and finish
1382 deny)
1383 -Route is denied by route-map.
1384 cont)
1385 -Goto Next index
1386
1387 If we get no matches after we've processed all updates, then the route
1388 is dropped too.
1389
1390 Some notes on the new "CALL", "NEXT" and "GOTO"
1391 call WORD - If this clause is matched, then the set statements
1392 are executed and then we jump to route-map 'WORD'. If
1393 this route-map denies the route, we finish, in other
1394 case we
1395 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
1396 on-match next - If this clause is matched, then the set statements
1397 are executed and then we drop through to the next clause
1398 on-match goto n - If this clause is matched, then the set statments
1399 are executed and then we goto the nth clause, or the
1400 first clause greater than this. In order to ensure
1401 route-maps *always* exit, you cannot jump backwards.
1402 Sorry ;)
1403
1404 We need to make sure our route-map processing matches the above
1405 */
1406
1407 static route_map_result_t
1408 route_map_apply_match(struct route_map_rule_list *match_list,
1409 const struct prefix *prefix, route_map_object_t type,
1410 void *object)
1411 {
1412 route_map_result_t ret = RMAP_NOMATCH;
1413 struct route_map_rule *match;
1414
1415
1416 /* Check all match rule and if there is no match rule, go to the
1417 set statement. */
1418 if (!match_list->head)
1419 ret = RMAP_MATCH;
1420 else {
1421 for (match = match_list->head; match; match = match->next) {
1422 /* Try each match statement in turn, If any do not
1423 return
1424 RMAP_MATCH, return, otherwise continue on to next
1425 match
1426 statement. All match statements must match for
1427 end-result
1428 to be a match. */
1429 ret = (*match->cmd->func_apply)(match->value, prefix,
1430 type, object);
1431 if (ret != RMAP_MATCH)
1432 return ret;
1433 }
1434 }
1435 return ret;
1436 }
1437
1438 /* Apply route map to the object. */
1439 route_map_result_t route_map_apply(struct route_map *map,
1440 const struct prefix *prefix,
1441 route_map_object_t type, void *object)
1442 {
1443 static int recursion = 0;
1444 int ret = 0;
1445 struct route_map_index *index;
1446 struct route_map_rule *set;
1447
1448 if (recursion > RMAP_RECURSION_LIMIT) {
1449 flog_warn(
1450 LIB_WARN_RMAP_RECURSION_LIMIT,
1451 "route-map recursion limit (%d) reached, discarding route",
1452 RMAP_RECURSION_LIMIT);
1453 recursion = 0;
1454 return RMAP_DENYMATCH;
1455 }
1456
1457 if (map == NULL)
1458 return RMAP_DENYMATCH;
1459
1460 for (index = map->head; index; index = index->next) {
1461 /* Apply this index. */
1462 ret = route_map_apply_match(&index->match_list, prefix, type,
1463 object);
1464
1465 /* Now we apply the matrix from above */
1466 if (ret == RMAP_NOMATCH)
1467 /* 'cont' from matrix - continue to next route-map
1468 * sequence */
1469 continue;
1470 else if (ret == RMAP_MATCH) {
1471 if (index->type == RMAP_PERMIT)
1472 /* 'action' */
1473 {
1474 /* permit+match must execute sets */
1475 for (set = index->set_list.head; set;
1476 set = set->next)
1477 ret = (*set->cmd->func_apply)(
1478 set->value, prefix, type,
1479 object);
1480
1481 /* Call another route-map if available */
1482 if (index->nextrm) {
1483 struct route_map *nextrm =
1484 route_map_lookup_by_name(
1485 index->nextrm);
1486
1487 if (nextrm) /* Target route-map found,
1488 jump to it */
1489 {
1490 recursion++;
1491 ret = route_map_apply(
1492 nextrm, prefix, type,
1493 object);
1494 recursion--;
1495 }
1496
1497 /* If nextrm returned 'deny', finish. */
1498 if (ret == RMAP_DENYMATCH)
1499 return ret;
1500 }
1501
1502 switch (index->exitpolicy) {
1503 case RMAP_EXIT:
1504 return ret;
1505 case RMAP_NEXT:
1506 continue;
1507 case RMAP_GOTO: {
1508 /* Find the next clause to jump to */
1509 struct route_map_index *next =
1510 index->next;
1511 int nextpref = index->nextpref;
1512
1513 while (next && next->pref < nextpref) {
1514 index = next;
1515 next = next->next;
1516 }
1517 if (next == NULL) {
1518 /* No clauses match! */
1519 return ret;
1520 }
1521 }
1522 }
1523 } else if (index->type == RMAP_DENY)
1524 /* 'deny' */
1525 {
1526 return RMAP_DENYMATCH;
1527 }
1528 }
1529 }
1530 /* Finally route-map does not match at all. */
1531 return RMAP_DENYMATCH;
1532 }
1533
1534 void route_map_add_hook(void (*func)(const char *))
1535 {
1536 route_map_master.add_hook = func;
1537 }
1538
1539 void route_map_delete_hook(void (*func)(const char *))
1540 {
1541 route_map_master.delete_hook = func;
1542 }
1543
1544 void route_map_event_hook(void (*func)(route_map_event_t, const char *))
1545 {
1546 route_map_master.event_hook = func;
1547 }
1548
1549 /* Routines for route map dependency lists and dependency processing */
1550 static int route_map_rmap_hash_cmp(const void *p1, const void *p2)
1551 {
1552 return (strcmp((const char *)p1, (const char *)p2) == 0);
1553 }
1554
1555 static int route_map_dep_hash_cmp(const void *p1, const void *p2)
1556 {
1557
1558 return (strcmp(((const struct route_map_dep *)p1)->dep_name,
1559 (const char *)p2)
1560 == 0);
1561 }
1562
1563 static void route_map_clear_reference(struct hash_backet *backet, void *arg)
1564 {
1565 struct route_map_dep *dep = (struct route_map_dep *)backet->data;
1566 char *rmap_name;
1567
1568 if (arg) {
1569 rmap_name =
1570 (char *)hash_release(dep->dep_rmap_hash, (void *)arg);
1571 if (rmap_name) {
1572 XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
1573 }
1574 if (!dep->dep_rmap_hash->count) {
1575 dep = hash_release(dep->this_hash,
1576 (void *)dep->dep_name);
1577 hash_free(dep->dep_rmap_hash);
1578 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
1579 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
1580 }
1581 }
1582 }
1583
1584 static void route_map_clear_all_references(char *rmap_name)
1585 {
1586 int i;
1587
1588 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
1589 hash_iterate(route_map_dep_hash[i], route_map_clear_reference,
1590 (void *)rmap_name);
1591 }
1592 }
1593
1594 static void *route_map_dep_hash_alloc(void *p)
1595 {
1596 char *dep_name = (char *)p;
1597 struct route_map_dep *dep_entry;
1598
1599 dep_entry = XCALLOC(MTYPE_ROUTE_MAP_DEP, sizeof(struct route_map_dep));
1600 dep_entry->dep_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
1601 dep_entry->dep_rmap_hash =
1602 hash_create_size(8, route_map_dep_hash_make_key,
1603 route_map_rmap_hash_cmp, "Route Map Dep Hash");
1604 dep_entry->this_hash = NULL;
1605
1606 return ((void *)dep_entry);
1607 }
1608
1609 static void *route_map_name_hash_alloc(void *p)
1610 {
1611 return ((void *)XSTRDUP(MTYPE_ROUTE_MAP_NAME, (const char *)p));
1612 }
1613
1614 static unsigned int route_map_dep_hash_make_key(void *p)
1615 {
1616 return (string_hash_make((char *)p));
1617 }
1618
1619 static void route_map_print_dependency(struct hash_backet *backet, void *data)
1620 {
1621 char *rmap_name = (char *)backet->data;
1622 char *dep_name = (char *)data;
1623
1624 zlog_debug("%s: Dependency for %s: %s", __FUNCTION__, dep_name,
1625 rmap_name);
1626 }
1627
1628 static int route_map_dep_update(struct hash *dephash, const char *dep_name,
1629 const char *rmap_name, route_map_event_t type)
1630 {
1631 struct route_map_dep *dep = NULL;
1632 char *ret_map_name;
1633 char *dname, *rname;
1634 int ret = 0;
1635
1636 dname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
1637 rname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_name);
1638
1639 switch (type) {
1640 case RMAP_EVENT_PLIST_ADDED:
1641 case RMAP_EVENT_CLIST_ADDED:
1642 case RMAP_EVENT_ECLIST_ADDED:
1643 case RMAP_EVENT_ASLIST_ADDED:
1644 case RMAP_EVENT_LLIST_ADDED:
1645 case RMAP_EVENT_CALL_ADDED:
1646 case RMAP_EVENT_FILTER_ADDED:
1647 if (rmap_debug)
1648 zlog_debug("%s: Adding dependency for %s in %s",
1649 __FUNCTION__, dep_name, rmap_name);
1650 dep = (struct route_map_dep *)hash_get(
1651 dephash, dname, route_map_dep_hash_alloc);
1652 if (!dep) {
1653 ret = -1;
1654 goto out;
1655 }
1656
1657 if (!dep->this_hash)
1658 dep->this_hash = dephash;
1659
1660 hash_get(dep->dep_rmap_hash, rname, route_map_name_hash_alloc);
1661 break;
1662 case RMAP_EVENT_PLIST_DELETED:
1663 case RMAP_EVENT_CLIST_DELETED:
1664 case RMAP_EVENT_ECLIST_DELETED:
1665 case RMAP_EVENT_ASLIST_DELETED:
1666 case RMAP_EVENT_LLIST_DELETED:
1667 case RMAP_EVENT_CALL_DELETED:
1668 case RMAP_EVENT_FILTER_DELETED:
1669 if (rmap_debug)
1670 zlog_debug("%s: Deleting dependency for %s in %s",
1671 __FUNCTION__, dep_name, rmap_name);
1672 dep = (struct route_map_dep *)hash_get(dephash, dname, NULL);
1673 if (!dep) {
1674 goto out;
1675 }
1676
1677 ret_map_name = (char *)hash_release(dep->dep_rmap_hash, rname);
1678 if (ret_map_name)
1679 XFREE(MTYPE_ROUTE_MAP_NAME, ret_map_name);
1680
1681 if (!dep->dep_rmap_hash->count) {
1682 dep = hash_release(dephash, dname);
1683 hash_free(dep->dep_rmap_hash);
1684 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
1685 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
1686 dep = NULL;
1687 }
1688 break;
1689 default:
1690 break;
1691 }
1692
1693 if (dep) {
1694 if (rmap_debug)
1695 hash_iterate(dep->dep_rmap_hash,
1696 route_map_print_dependency, dname);
1697 }
1698
1699 out:
1700 XFREE(MTYPE_ROUTE_MAP_NAME, rname);
1701 XFREE(MTYPE_ROUTE_MAP_NAME, dname);
1702 return ret;
1703 }
1704
1705 static struct hash *route_map_get_dep_hash(route_map_event_t event)
1706 {
1707 struct hash *upd8_hash = NULL;
1708
1709 switch (event) {
1710 case RMAP_EVENT_PLIST_ADDED:
1711 case RMAP_EVENT_PLIST_DELETED:
1712 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_PLIST];
1713 break;
1714 case RMAP_EVENT_CLIST_ADDED:
1715 case RMAP_EVENT_CLIST_DELETED:
1716 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_CLIST];
1717 break;
1718 case RMAP_EVENT_ECLIST_ADDED:
1719 case RMAP_EVENT_ECLIST_DELETED:
1720 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ECLIST];
1721 break;
1722 case RMAP_EVENT_ASLIST_ADDED:
1723 case RMAP_EVENT_ASLIST_DELETED:
1724 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ASPATH];
1725 break;
1726 case RMAP_EVENT_LLIST_ADDED:
1727 case RMAP_EVENT_LLIST_DELETED:
1728 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_LCLIST];
1729 break;
1730 case RMAP_EVENT_CALL_ADDED:
1731 case RMAP_EVENT_CALL_DELETED:
1732 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_RMAP];
1733 break;
1734 case RMAP_EVENT_FILTER_ADDED:
1735 case RMAP_EVENT_FILTER_DELETED:
1736 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_FILTER];
1737 break;
1738 default:
1739 upd8_hash = NULL;
1740 break;
1741 }
1742 return (upd8_hash);
1743 }
1744
1745 static void route_map_process_dependency(struct hash_backet *backet, void *data)
1746 {
1747 char *rmap_name = (char *)backet->data;
1748 route_map_event_t type = (route_map_event_t)(ptrdiff_t)data;
1749
1750 if (rmap_debug)
1751 zlog_debug("%s: Notifying %s of dependency",
1752 __FUNCTION__, rmap_name);
1753 if (route_map_master.event_hook)
1754 (*route_map_master.event_hook)(type, rmap_name);
1755 }
1756
1757 void route_map_upd8_dependency(route_map_event_t type, const char *arg,
1758 const char *rmap_name)
1759 {
1760 struct hash *upd8_hash = NULL;
1761
1762 if ((upd8_hash = route_map_get_dep_hash(type)))
1763 route_map_dep_update(upd8_hash, arg, rmap_name, type);
1764 }
1765
1766 void route_map_notify_dependencies(const char *affected_name,
1767 route_map_event_t event)
1768 {
1769 struct route_map_dep *dep;
1770 struct hash *upd8_hash;
1771 char *name;
1772
1773 if (!affected_name)
1774 return;
1775
1776 name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, affected_name);
1777
1778 if ((upd8_hash = route_map_get_dep_hash(event)) == NULL) {
1779 XFREE(MTYPE_ROUTE_MAP_NAME, name);
1780 return;
1781 }
1782
1783 dep = (struct route_map_dep *)hash_get(upd8_hash, name, NULL);
1784 if (dep) {
1785 if (!dep->this_hash)
1786 dep->this_hash = upd8_hash;
1787
1788 hash_iterate(dep->dep_rmap_hash, route_map_process_dependency,
1789 (void *)event);
1790 }
1791
1792 XFREE(MTYPE_ROUTE_MAP_NAME, name);
1793 }
1794
1795
1796 /* VTY related functions. */
1797 DEFUN (match_interface,
1798 match_interface_cmd,
1799 "match interface WORD",
1800 MATCH_STR
1801 "match first hop interface of route\n"
1802 "Interface name\n")
1803 {
1804 int idx_word = 2;
1805 VTY_DECLVAR_CONTEXT(route_map_index, index);
1806
1807 if (rmap_match_set_hook.match_interface)
1808 return rmap_match_set_hook.match_interface(
1809 vty, index, "interface", argv[idx_word]->arg,
1810 RMAP_EVENT_MATCH_ADDED);
1811 return CMD_SUCCESS;
1812 }
1813
1814 DEFUN (no_match_interface,
1815 no_match_interface_cmd,
1816 "no match interface [WORD]",
1817 NO_STR
1818 MATCH_STR
1819 "Match first hop interface of route\n"
1820 "Interface name\n")
1821 {
1822 char *iface = (argc == 4) ? argv[3]->arg : NULL;
1823 VTY_DECLVAR_CONTEXT(route_map_index, index);
1824
1825 if (rmap_match_set_hook.no_match_interface)
1826 return rmap_match_set_hook.no_match_interface(
1827 vty, index, "interface", iface,
1828 RMAP_EVENT_MATCH_DELETED);
1829 return CMD_SUCCESS;
1830 }
1831
1832
1833 DEFUN (match_ip_address,
1834 match_ip_address_cmd,
1835 "match ip address <(1-199)|(1300-2699)|WORD>",
1836 MATCH_STR
1837 IP_STR
1838 "Match address of route\n"
1839 "IP access-list number\n"
1840 "IP access-list number (expanded range)\n"
1841 "IP Access-list name\n")
1842 {
1843 int idx_acl = 3;
1844 VTY_DECLVAR_CONTEXT(route_map_index, index);
1845
1846 if (rmap_match_set_hook.match_ip_address)
1847 return rmap_match_set_hook.match_ip_address(
1848 vty, index, "ip address", argv[idx_acl]->arg,
1849 RMAP_EVENT_FILTER_ADDED);
1850 return CMD_SUCCESS;
1851 }
1852
1853
1854 DEFUN (no_match_ip_address,
1855 no_match_ip_address_cmd,
1856 "no match ip address [<(1-199)|(1300-2699)|WORD>]",
1857 NO_STR
1858 MATCH_STR
1859 IP_STR
1860 "Match address of route\n"
1861 "IP access-list number\n"
1862 "IP access-list number (expanded range)\n"
1863 "IP Access-list name\n")
1864 {
1865 int idx_word = 4;
1866 VTY_DECLVAR_CONTEXT(route_map_index, index);
1867
1868 if (rmap_match_set_hook.no_match_ip_address) {
1869 if (argc <= idx_word)
1870 return rmap_match_set_hook.no_match_ip_address(
1871 vty, index, "ip address", NULL,
1872 RMAP_EVENT_FILTER_DELETED);
1873 return rmap_match_set_hook.no_match_ip_address(
1874 vty, index, "ip address", argv[idx_word]->arg,
1875 RMAP_EVENT_FILTER_DELETED);
1876 }
1877 return CMD_SUCCESS;
1878 }
1879
1880
1881 DEFUN (match_ip_address_prefix_list,
1882 match_ip_address_prefix_list_cmd,
1883 "match ip address prefix-list WORD",
1884 MATCH_STR
1885 IP_STR
1886 "Match address of route\n"
1887 "Match entries of prefix-lists\n"
1888 "IP prefix-list name\n")
1889 {
1890 int idx_word = 4;
1891 VTY_DECLVAR_CONTEXT(route_map_index, index);
1892
1893 if (rmap_match_set_hook.match_ip_address_prefix_list)
1894 return rmap_match_set_hook.match_ip_address_prefix_list(
1895 vty, index, "ip address prefix-list",
1896 argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
1897 return CMD_SUCCESS;
1898 }
1899
1900
1901 DEFUN (no_match_ip_address_prefix_list,
1902 no_match_ip_address_prefix_list_cmd,
1903 "no match ip address prefix-list [WORD]",
1904 NO_STR
1905 MATCH_STR
1906 IP_STR
1907 "Match address of route\n"
1908 "Match entries of prefix-lists\n"
1909 "IP prefix-list name\n")
1910 {
1911 int idx_word = 5;
1912 VTY_DECLVAR_CONTEXT(route_map_index, index);
1913
1914 if (rmap_match_set_hook.no_match_ip_address_prefix_list) {
1915 if (argc <= idx_word)
1916 return rmap_match_set_hook
1917 .no_match_ip_address_prefix_list(
1918 vty, index, "ip address prefix-list",
1919 NULL, RMAP_EVENT_PLIST_DELETED);
1920 return rmap_match_set_hook.no_match_ip_address_prefix_list(
1921 vty, index, "ip address prefix-list",
1922 argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
1923 }
1924 return CMD_SUCCESS;
1925 }
1926
1927
1928 DEFUN (match_ip_next_hop,
1929 match_ip_next_hop_cmd,
1930 "match ip next-hop <(1-199)|(1300-2699)|WORD>",
1931 MATCH_STR
1932 IP_STR
1933 "Match next-hop address of route\n"
1934 "IP access-list number\n"
1935 "IP access-list number (expanded range)\n"
1936 "IP Access-list name\n")
1937 {
1938 int idx_acl = 3;
1939 VTY_DECLVAR_CONTEXT(route_map_index, index);
1940
1941 if (rmap_match_set_hook.match_ip_next_hop)
1942 return rmap_match_set_hook.match_ip_next_hop(
1943 vty, index, "ip next-hop", argv[idx_acl]->arg,
1944 RMAP_EVENT_FILTER_ADDED);
1945 return CMD_SUCCESS;
1946 }
1947
1948
1949 DEFUN (no_match_ip_next_hop,
1950 no_match_ip_next_hop_cmd,
1951 "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
1952 NO_STR
1953 MATCH_STR
1954 IP_STR
1955 "Match next-hop address of route\n"
1956 "IP access-list number\n"
1957 "IP access-list number (expanded range)\n"
1958 "IP Access-list name\n")
1959 {
1960 int idx_word = 4;
1961 VTY_DECLVAR_CONTEXT(route_map_index, index);
1962
1963 if (rmap_match_set_hook.no_match_ip_next_hop) {
1964 if (argc <= idx_word)
1965 return rmap_match_set_hook.no_match_ip_next_hop(
1966 vty, index, "ip next-hop", NULL,
1967 RMAP_EVENT_FILTER_DELETED);
1968 return rmap_match_set_hook.no_match_ip_next_hop(
1969 vty, index, "ip next-hop", argv[idx_word]->arg,
1970 RMAP_EVENT_FILTER_DELETED);
1971 }
1972 return CMD_SUCCESS;
1973 }
1974
1975
1976 DEFUN (match_ip_next_hop_prefix_list,
1977 match_ip_next_hop_prefix_list_cmd,
1978 "match ip next-hop prefix-list WORD",
1979 MATCH_STR
1980 IP_STR
1981 "Match next-hop address of route\n"
1982 "Match entries of prefix-lists\n"
1983 "IP prefix-list name\n")
1984 {
1985 int idx_word = 4;
1986 VTY_DECLVAR_CONTEXT(route_map_index, index);
1987
1988 if (rmap_match_set_hook.match_ip_next_hop_prefix_list)
1989 return rmap_match_set_hook.match_ip_next_hop_prefix_list(
1990 vty, index, "ip next-hop prefix-list",
1991 argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
1992 return CMD_SUCCESS;
1993 }
1994
1995 DEFUN (no_match_ip_next_hop_prefix_list,
1996 no_match_ip_next_hop_prefix_list_cmd,
1997 "no match ip next-hop prefix-list [WORD]",
1998 NO_STR
1999 MATCH_STR
2000 IP_STR
2001 "Match next-hop address of route\n"
2002 "Match entries of prefix-lists\n"
2003 "IP prefix-list name\n")
2004 {
2005 int idx_word = 5;
2006 VTY_DECLVAR_CONTEXT(route_map_index, index);
2007
2008 if (rmap_match_set_hook.no_match_ip_next_hop) {
2009 if (argc <= idx_word)
2010 return rmap_match_set_hook.no_match_ip_next_hop(
2011 vty, index, "ip next-hop prefix-list", NULL,
2012 RMAP_EVENT_PLIST_DELETED);
2013 return rmap_match_set_hook.no_match_ip_next_hop(
2014 vty, index, "ip next-hop prefix-list",
2015 argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
2016 }
2017 return CMD_SUCCESS;
2018 }
2019
2020
2021 DEFUN (match_ipv6_address,
2022 match_ipv6_address_cmd,
2023 "match ipv6 address WORD",
2024 MATCH_STR
2025 IPV6_STR
2026 "Match IPv6 address of route\n"
2027 "IPv6 access-list name\n")
2028 {
2029 int idx_word = 3;
2030 VTY_DECLVAR_CONTEXT(route_map_index, index);
2031
2032 if (rmap_match_set_hook.match_ipv6_address)
2033 return rmap_match_set_hook.match_ipv6_address(
2034 vty, index, "ipv6 address", argv[idx_word]->arg,
2035 RMAP_EVENT_FILTER_ADDED);
2036 return CMD_SUCCESS;
2037 }
2038
2039 DEFUN (no_match_ipv6_address,
2040 no_match_ipv6_address_cmd,
2041 "no match ipv6 address WORD",
2042 NO_STR
2043 MATCH_STR
2044 IPV6_STR
2045 "Match IPv6 address of route\n"
2046 "IPv6 access-list name\n")
2047 {
2048 int idx_word = 4;
2049 VTY_DECLVAR_CONTEXT(route_map_index, index);
2050
2051 if (rmap_match_set_hook.no_match_ipv6_address)
2052 return rmap_match_set_hook.no_match_ipv6_address(
2053 vty, index, "ipv6 address", argv[idx_word]->arg,
2054 RMAP_EVENT_FILTER_DELETED);
2055 return CMD_SUCCESS;
2056 }
2057
2058
2059 DEFUN (match_ipv6_address_prefix_list,
2060 match_ipv6_address_prefix_list_cmd,
2061 "match ipv6 address prefix-list WORD",
2062 MATCH_STR
2063 IPV6_STR
2064 "Match address of route\n"
2065 "Match entries of prefix-lists\n"
2066 "IP prefix-list name\n")
2067 {
2068 int idx_word = 4;
2069 VTY_DECLVAR_CONTEXT(route_map_index, index);
2070
2071 if (rmap_match_set_hook.match_ipv6_address_prefix_list)
2072 return rmap_match_set_hook.match_ipv6_address_prefix_list(
2073 vty, index, "ipv6 address prefix-list",
2074 argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
2075 return CMD_SUCCESS;
2076 }
2077
2078 DEFUN (no_match_ipv6_address_prefix_list,
2079 no_match_ipv6_address_prefix_list_cmd,
2080 "no match ipv6 address prefix-list WORD",
2081 NO_STR
2082 MATCH_STR
2083 IPV6_STR
2084 "Match address of route\n"
2085 "Match entries of prefix-lists\n"
2086 "IP prefix-list name\n")
2087 {
2088 int idx_word = 5;
2089 VTY_DECLVAR_CONTEXT(route_map_index, index);
2090
2091 if (rmap_match_set_hook.no_match_ipv6_address_prefix_list)
2092 return rmap_match_set_hook.no_match_ipv6_address_prefix_list(
2093 vty, index, "ipv6 address prefix-list",
2094 argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
2095 return CMD_SUCCESS;
2096 }
2097
2098
2099 DEFUN (match_metric,
2100 match_metric_cmd,
2101 "match metric (0-4294967295)",
2102 MATCH_STR
2103 "Match metric of route\n"
2104 "Metric value\n")
2105 {
2106 int idx_number = 2;
2107 VTY_DECLVAR_CONTEXT(route_map_index, index);
2108
2109 if (rmap_match_set_hook.match_metric)
2110 return rmap_match_set_hook.match_metric(vty, index, "metric",
2111 argv[idx_number]->arg,
2112 RMAP_EVENT_MATCH_ADDED);
2113 return CMD_SUCCESS;
2114 }
2115
2116
2117 DEFUN (no_match_metric,
2118 no_match_metric_cmd,
2119 "no match metric [(0-4294967295)]",
2120 NO_STR
2121 MATCH_STR
2122 "Match metric of route\n"
2123 "Metric value\n")
2124 {
2125 int idx_number = 3;
2126 VTY_DECLVAR_CONTEXT(route_map_index, index);
2127
2128 if (rmap_match_set_hook.no_match_metric) {
2129 if (argc <= idx_number)
2130 return rmap_match_set_hook.no_match_metric(
2131 vty, index, "metric", NULL,
2132 RMAP_EVENT_MATCH_DELETED);
2133 return rmap_match_set_hook.no_match_metric(
2134 vty, index, "metric", argv[idx_number]->arg,
2135 RMAP_EVENT_MATCH_DELETED);
2136 }
2137 return CMD_SUCCESS;
2138 }
2139
2140
2141 DEFUN (match_tag,
2142 match_tag_cmd,
2143 "match tag (1-4294967295)",
2144 MATCH_STR
2145 "Match tag of route\n"
2146 "Tag value\n")
2147 {
2148 int idx_number = 2;
2149 VTY_DECLVAR_CONTEXT(route_map_index, index);
2150
2151 if (rmap_match_set_hook.match_tag)
2152 return rmap_match_set_hook.match_tag(vty, index, "tag",
2153 argv[idx_number]->arg,
2154 RMAP_EVENT_MATCH_ADDED);
2155 return CMD_SUCCESS;
2156 }
2157
2158
2159 DEFUN (no_match_tag,
2160 no_match_tag_cmd,
2161 "no match tag [(1-4294967295)]",
2162 NO_STR
2163 MATCH_STR
2164 "Match tag of route\n"
2165 "Tag value\n")
2166 {
2167 VTY_DECLVAR_CONTEXT(route_map_index, index);
2168
2169 int idx = 0;
2170 char *arg = argv_find(argv, argc, "(1-4294967295)", &idx)
2171 ? argv[idx]->arg
2172 : NULL;
2173
2174 if (rmap_match_set_hook.no_match_tag)
2175 return rmap_match_set_hook.no_match_tag(
2176 vty, index, "tag", arg, RMAP_EVENT_MATCH_DELETED);
2177 return CMD_SUCCESS;
2178 }
2179
2180
2181 DEFUN (set_ip_nexthop,
2182 set_ip_nexthop_cmd,
2183 "set ip next-hop A.B.C.D",
2184 SET_STR
2185 IP_STR
2186 "Next hop address\n"
2187 "IP address of next hop\n")
2188 {
2189 int idx_ipv4 = 3;
2190 union sockunion su;
2191 int ret;
2192 VTY_DECLVAR_CONTEXT(route_map_index, index);
2193
2194 ret = str2sockunion(argv[idx_ipv4]->arg, &su);
2195 if (ret < 0) {
2196 vty_out(vty, "%% Malformed nexthop address\n");
2197 return CMD_WARNING_CONFIG_FAILED;
2198 }
2199 if (su.sin.sin_addr.s_addr == 0
2200 || IPV4_CLASS_DE(ntohl(su.sin.sin_addr.s_addr))) {
2201 vty_out(vty,
2202 "%% nexthop address cannot be 0.0.0.0, multicast or reserved\n");
2203 return CMD_WARNING_CONFIG_FAILED;
2204 }
2205
2206 if (rmap_match_set_hook.set_ip_nexthop)
2207 return rmap_match_set_hook.set_ip_nexthop(
2208 vty, index, "ip next-hop", argv[idx_ipv4]->arg);
2209 return CMD_SUCCESS;
2210 }
2211
2212
2213 DEFUN (no_set_ip_nexthop,
2214 no_set_ip_nexthop_cmd,
2215 "no set ip next-hop [A.B.C.D]",
2216 NO_STR
2217 SET_STR
2218 IP_STR
2219 "Next hop address\n"
2220 "IP address of next hop\n")
2221 {
2222 int idx = 0;
2223 VTY_DECLVAR_CONTEXT(route_map_index, index);
2224 const char *arg = NULL;
2225
2226 if (argv_find(argv, argc, "A.B.C.D", &idx))
2227 arg = argv[idx]->arg;
2228
2229 if (rmap_match_set_hook.no_set_ip_nexthop)
2230 return rmap_match_set_hook.no_set_ip_nexthop(
2231 vty, index, "ip next-hop", arg);
2232
2233 return CMD_SUCCESS;
2234 }
2235
2236
2237 DEFUN (set_ipv6_nexthop_local,
2238 set_ipv6_nexthop_local_cmd,
2239 "set ipv6 next-hop local X:X::X:X",
2240 SET_STR
2241 IPV6_STR
2242 "IPv6 next-hop address\n"
2243 "IPv6 local address\n"
2244 "IPv6 address of next hop\n")
2245 {
2246 int idx_ipv6 = 4;
2247 struct in6_addr addr;
2248 int ret;
2249 VTY_DECLVAR_CONTEXT(route_map_index, index);
2250
2251 ret = inet_pton(AF_INET6, argv[idx_ipv6]->arg, &addr);
2252 if (!ret) {
2253 vty_out(vty, "%% Malformed nexthop address\n");
2254 return CMD_WARNING_CONFIG_FAILED;
2255 }
2256 if (!IN6_IS_ADDR_LINKLOCAL(&addr)) {
2257 vty_out(vty, "%% Invalid link-local nexthop address\n");
2258 return CMD_WARNING_CONFIG_FAILED;
2259 }
2260
2261 if (rmap_match_set_hook.set_ipv6_nexthop_local)
2262 return rmap_match_set_hook.set_ipv6_nexthop_local(
2263 vty, index, "ipv6 next-hop local", argv[idx_ipv6]->arg);
2264 return CMD_SUCCESS;
2265 }
2266
2267
2268 DEFUN (no_set_ipv6_nexthop_local,
2269 no_set_ipv6_nexthop_local_cmd,
2270 "no set ipv6 next-hop local [X:X::X:X]",
2271 NO_STR
2272 SET_STR
2273 IPV6_STR
2274 "IPv6 next-hop address\n"
2275 "IPv6 local address\n"
2276 "IPv6 address of next hop\n")
2277 {
2278 int idx_ipv6 = 5;
2279 VTY_DECLVAR_CONTEXT(route_map_index, index);
2280
2281 if (rmap_match_set_hook.no_set_ipv6_nexthop_local) {
2282 if (argc <= idx_ipv6)
2283 return rmap_match_set_hook.no_set_ipv6_nexthop_local(
2284 vty, index, "ipv6 next-hop local", NULL);
2285 return rmap_match_set_hook.no_set_ipv6_nexthop_local(
2286 vty, index, "ipv6 next-hop local", argv[5]->arg);
2287 }
2288 return CMD_SUCCESS;
2289 }
2290
2291 DEFUN (set_metric,
2292 set_metric_cmd,
2293 "set metric <(0-4294967295)|rtt|+rtt|-rtt|+metric|-metric>",
2294 SET_STR
2295 "Metric value for destination routing protocol\n"
2296 "Metric value\n"
2297 "Assign round trip time\n"
2298 "Add round trip time\n"
2299 "Subtract round trip time\n"
2300 "Add metric\n"
2301 "Subtract metric\n")
2302 {
2303 int idx_number = 2;
2304 VTY_DECLVAR_CONTEXT(route_map_index, index);
2305
2306 const char *pass = (argv[idx_number]->type == RANGE_TKN)
2307 ? argv[idx_number]->arg
2308 : argv[idx_number]->text;
2309
2310 if (rmap_match_set_hook.set_metric)
2311 return rmap_match_set_hook.set_metric(vty, index, "metric",
2312 pass);
2313 return CMD_SUCCESS;
2314 }
2315
2316
2317 DEFUN (no_set_metric,
2318 no_set_metric_cmd,
2319 "no set metric [(0-4294967295)]",
2320 NO_STR
2321 SET_STR
2322 "Metric value for destination routing protocol\n"
2323 "Metric value\n")
2324 {
2325 int idx_number = 3;
2326 VTY_DECLVAR_CONTEXT(route_map_index, index);
2327
2328 if (rmap_match_set_hook.no_set_metric) {
2329 if (argc <= idx_number)
2330 return rmap_match_set_hook.no_set_metric(
2331 vty, index, "metric", NULL);
2332 return rmap_match_set_hook.no_set_metric(vty, index, "metric",
2333 argv[idx_number]->arg);
2334 }
2335 return CMD_SUCCESS;
2336 }
2337
2338
2339 DEFUN (set_tag,
2340 set_tag_cmd,
2341 "set tag (1-4294967295)",
2342 SET_STR
2343 "Tag value for routing protocol\n"
2344 "Tag value\n")
2345 {
2346 VTY_DECLVAR_CONTEXT(route_map_index, index);
2347
2348 int idx_number = 2;
2349 if (rmap_match_set_hook.set_tag)
2350 return rmap_match_set_hook.set_tag(vty, index, "tag",
2351 argv[idx_number]->arg);
2352 return CMD_SUCCESS;
2353 }
2354
2355
2356 DEFUN (no_set_tag,
2357 no_set_tag_cmd,
2358 "no set tag [(1-4294967295)]",
2359 NO_STR
2360 SET_STR
2361 "Tag value for routing protocol\n"
2362 "Tag value\n")
2363 {
2364 VTY_DECLVAR_CONTEXT(route_map_index, index);
2365
2366 int idx_number = 3;
2367 if (rmap_match_set_hook.no_set_tag) {
2368 if (argc <= idx_number)
2369 return rmap_match_set_hook.no_set_tag(vty, index, "tag",
2370 NULL);
2371 return rmap_match_set_hook.no_set_tag(vty, index, "tag",
2372 argv[idx_number]->arg);
2373 }
2374 return CMD_SUCCESS;
2375 }
2376
2377
2378 DEFUN_NOSH (route_map,
2379 route_map_cmd,
2380 "route-map WORD <deny|permit> (1-65535)",
2381 "Create route-map or enter route-map command mode\n"
2382 "Route map tag\n"
2383 "Route map denies set operations\n"
2384 "Route map permits set operations\n"
2385 "Sequence to insert to/delete from existing route-map entry\n")
2386 {
2387 int idx_word = 1;
2388 int idx_permit_deny = 2;
2389 int idx_number = 3;
2390 struct route_map *map;
2391 struct route_map_index *index;
2392 char *endptr = NULL;
2393 int permit =
2394 argv[idx_permit_deny]->arg[0] == 'p' ? RMAP_PERMIT : RMAP_DENY;
2395 unsigned long pref = strtoul(argv[idx_number]->arg, &endptr, 10);
2396 const char *mapname = argv[idx_word]->arg;
2397
2398 /* Get route map. */
2399 map = route_map_get(mapname);
2400 index = route_map_index_get(map, permit, pref);
2401
2402 VTY_PUSH_CONTEXT(RMAP_NODE, index);
2403 return CMD_SUCCESS;
2404 }
2405
2406 DEFUN (no_route_map_all,
2407 no_route_map_all_cmd,
2408 "no route-map WORD",
2409 NO_STR
2410 "Create route-map or enter route-map command mode\n"
2411 "Route map tag\n")
2412 {
2413 int idx_word = 2;
2414 const char *mapname = argv[idx_word]->arg;
2415 struct route_map *map;
2416
2417 map = route_map_lookup_by_name(mapname);
2418 if (map == NULL) {
2419 vty_out(vty, "%% Could not find route-map %s\n", mapname);
2420 return CMD_WARNING_CONFIG_FAILED;
2421 }
2422
2423 route_map_delete(map);
2424
2425 return CMD_SUCCESS;
2426 }
2427
2428 DEFUN (no_route_map,
2429 no_route_map_cmd,
2430 "no route-map WORD <deny|permit> (1-65535)",
2431 NO_STR
2432 "Create route-map or enter route-map command mode\n"
2433 "Route map tag\n"
2434 "Route map denies set operations\n"
2435 "Route map permits set operations\n"
2436 "Sequence to insert to/delete from existing route-map entry\n")
2437 {
2438 int idx_word = 2;
2439 int idx_permit_deny = 3;
2440 int idx_number = 4;
2441 struct route_map *map;
2442 struct route_map_index *index;
2443 char *endptr = NULL;
2444 int permit = strmatch(argv[idx_permit_deny]->text, "permit")
2445 ? RMAP_PERMIT
2446 : RMAP_DENY;
2447 const char *prefstr = argv[idx_number]->arg;
2448 const char *mapname = argv[idx_word]->arg;
2449 unsigned long pref = strtoul(prefstr, &endptr, 10);
2450
2451 /* Existence check. */
2452 map = route_map_lookup_by_name(mapname);
2453 if (map == NULL) {
2454 vty_out(vty, "%% Could not find route-map %s\n", mapname);
2455 return CMD_WARNING_CONFIG_FAILED;
2456 }
2457
2458 /* Lookup route map index. */
2459 index = route_map_index_lookup(map, permit, pref);
2460 if (index == NULL) {
2461 vty_out(vty, "%% Could not find route-map entry %s %s\n",
2462 mapname, prefstr);
2463 return CMD_WARNING_CONFIG_FAILED;
2464 }
2465
2466 /* Delete index from route map. */
2467 route_map_index_delete(index, 1);
2468
2469 /* If this route rule is the last one, delete route map itself. */
2470 if (route_map_empty(map))
2471 route_map_delete(map);
2472
2473 return CMD_SUCCESS;
2474 }
2475
2476 DEFUN (rmap_onmatch_next,
2477 rmap_onmatch_next_cmd,
2478 "on-match next",
2479 "Exit policy on matches\n"
2480 "Next clause\n")
2481 {
2482 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2483
2484 if (index) {
2485 if (index->type == RMAP_DENY) {
2486 /* Under a deny clause, match means it's finished. No
2487 * need to set next */
2488 vty_out(vty,
2489 "on-match next not supported under route-map deny\n");
2490 return CMD_WARNING_CONFIG_FAILED;
2491 }
2492 index->exitpolicy = RMAP_NEXT;
2493 }
2494 return CMD_SUCCESS;
2495 }
2496
2497 DEFUN (no_rmap_onmatch_next,
2498 no_rmap_onmatch_next_cmd,
2499 "no on-match next",
2500 NO_STR
2501 "Exit policy on matches\n"
2502 "Next clause\n")
2503 {
2504 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2505
2506 if (index)
2507 index->exitpolicy = RMAP_EXIT;
2508
2509 return CMD_SUCCESS;
2510 }
2511
2512 DEFUN (rmap_onmatch_goto,
2513 rmap_onmatch_goto_cmd,
2514 "on-match goto (1-65535)",
2515 "Exit policy on matches\n"
2516 "Goto Clause number\n"
2517 "Number\n")
2518 {
2519 int idx = 0;
2520 char *num = argv_find(argv, argc, "(1-65535)", &idx) ? argv[idx]->arg
2521 : NULL;
2522
2523 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2524 int d = 0;
2525
2526 if (index) {
2527 if (index->type == RMAP_DENY) {
2528 /* Under a deny clause, match means it's finished. No
2529 * need to go anywhere */
2530 vty_out(vty,
2531 "on-match goto not supported under route-map deny\n");
2532 return CMD_WARNING_CONFIG_FAILED;
2533 }
2534
2535 if (num)
2536 d = strtoul(num, NULL, 10);
2537 else
2538 d = index->pref + 1;
2539
2540 if (d <= index->pref) {
2541 /* Can't allow you to do that, Dave */
2542 vty_out(vty, "can't jump backwards in route-maps\n");
2543 return CMD_WARNING_CONFIG_FAILED;
2544 } else {
2545 index->exitpolicy = RMAP_GOTO;
2546 index->nextpref = d;
2547 }
2548 }
2549 return CMD_SUCCESS;
2550 }
2551
2552 DEFUN (no_rmap_onmatch_goto,
2553 no_rmap_onmatch_goto_cmd,
2554 "no on-match goto",
2555 NO_STR
2556 "Exit policy on matches\n"
2557 "Goto Clause number\n")
2558 {
2559 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2560
2561 if (index)
2562 index->exitpolicy = RMAP_EXIT;
2563
2564 return CMD_SUCCESS;
2565 }
2566
2567 /* Cisco/GNU Zebra compatibility aliases */
2568 /* ALIAS_FIXME */
2569 DEFUN (rmap_continue,
2570 rmap_continue_cmd,
2571 "continue (1-65535)",
2572 "Continue on a different entry within the route-map\n"
2573 "Route-map entry sequence number\n")
2574 {
2575 return rmap_onmatch_goto(self, vty, argc, argv);
2576 }
2577
2578 /* ALIAS_FIXME */
2579 DEFUN (no_rmap_continue,
2580 no_rmap_continue_cmd,
2581 "no continue [(1-65535)]",
2582 NO_STR
2583 "Continue on a different entry within the route-map\n"
2584 "Route-map entry sequence number\n")
2585 {
2586 return no_rmap_onmatch_goto(self, vty, argc, argv);
2587 }
2588
2589
2590 DEFUN (rmap_show_name,
2591 rmap_show_name_cmd,
2592 "show route-map [WORD]",
2593 SHOW_STR
2594 "route-map information\n"
2595 "route-map name\n")
2596 {
2597 int idx_word = 2;
2598 const char *name = (argc == 3) ? argv[idx_word]->arg : NULL;
2599 return vty_show_route_map(vty, name);
2600 }
2601
2602 DEFUN (rmap_call,
2603 rmap_call_cmd,
2604 "call WORD",
2605 "Jump to another Route-Map after match+set\n"
2606 "Target route-map name\n")
2607 {
2608 int idx_word = 1;
2609 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2610 const char *rmap = argv[idx_word]->arg;
2611
2612 assert(index);
2613
2614 if (index->nextrm) {
2615 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED,
2616 index->nextrm, index->map->name);
2617 XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
2618 }
2619 index->nextrm = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
2620
2621 /* Execute event hook. */
2622 route_map_upd8_dependency(RMAP_EVENT_CALL_ADDED, index->nextrm,
2623 index->map->name);
2624 return CMD_SUCCESS;
2625 }
2626
2627 DEFUN (no_rmap_call,
2628 no_rmap_call_cmd,
2629 "no call",
2630 NO_STR
2631 "Jump to another Route-Map after match+set\n")
2632 {
2633 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2634
2635 if (index->nextrm) {
2636 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED,
2637 index->nextrm, index->map->name);
2638 XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
2639 index->nextrm = NULL;
2640 }
2641
2642 return CMD_SUCCESS;
2643 }
2644
2645 DEFUN (rmap_description,
2646 rmap_description_cmd,
2647 "description LINE...",
2648 "Route-map comment\n"
2649 "Comment describing this route-map rule\n")
2650 {
2651 int idx_line = 1;
2652 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2653
2654 if (index) {
2655 if (index->description)
2656 XFREE(MTYPE_TMP, index->description);
2657 index->description = argv_concat(argv, argc, idx_line);
2658 }
2659 return CMD_SUCCESS;
2660 }
2661
2662 DEFUN (no_rmap_description,
2663 no_rmap_description_cmd,
2664 "no description",
2665 NO_STR
2666 "Route-map comment\n")
2667 {
2668 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2669
2670 if (index) {
2671 if (index->description)
2672 XFREE(MTYPE_TMP, index->description);
2673 index->description = NULL;
2674 }
2675 return CMD_SUCCESS;
2676 }
2677
2678 /* Configuration write function. */
2679 static int route_map_config_write(struct vty *vty)
2680 {
2681 struct route_map *map;
2682 struct route_map_index *index;
2683 struct route_map_rule *rule;
2684 int first = 1;
2685 int write = 0;
2686
2687 for (map = route_map_master.head; map; map = map->next)
2688 for (index = map->head; index; index = index->next) {
2689 if (!first)
2690 vty_out(vty, "!\n");
2691 else
2692 first = 0;
2693
2694 vty_out(vty, "route-map %s %s %d\n", map->name,
2695 route_map_type_str(index->type), index->pref);
2696
2697 if (index->description)
2698 vty_out(vty, " description %s\n",
2699 index->description);
2700
2701 for (rule = index->match_list.head; rule;
2702 rule = rule->next)
2703 vty_out(vty, " match %s %s\n", rule->cmd->str,
2704 rule->rule_str ? rule->rule_str : "");
2705
2706 for (rule = index->set_list.head; rule;
2707 rule = rule->next)
2708 vty_out(vty, " set %s %s\n", rule->cmd->str,
2709 rule->rule_str ? rule->rule_str : "");
2710 if (index->nextrm)
2711 vty_out(vty, " call %s\n", index->nextrm);
2712 if (index->exitpolicy == RMAP_GOTO)
2713 vty_out(vty, " on-match goto %d\n",
2714 index->nextpref);
2715 if (index->exitpolicy == RMAP_NEXT)
2716 vty_out(vty, " on-match next\n");
2717
2718 write++;
2719 }
2720 return write;
2721 }
2722
2723 /* Route map node structure. */
2724 static struct cmd_node rmap_node = {RMAP_NODE, "%s(config-route-map)# ", 1};
2725
2726 /* Common route map rules */
2727
2728 void *route_map_rule_tag_compile(const char *arg)
2729 {
2730 unsigned long int tmp;
2731 char *endptr;
2732 route_tag_t *tag;
2733
2734 errno = 0;
2735 tmp = strtoul(arg, &endptr, 0);
2736 if (arg[0] == '\0' || *endptr != '\0' || errno || tmp > ROUTE_TAG_MAX)
2737 return NULL;
2738
2739 tag = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*tag));
2740 *tag = tmp;
2741
2742 return tag;
2743 }
2744
2745 void route_map_rule_tag_free(void *rule)
2746 {
2747 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
2748 }
2749
2750 void route_map_finish(void)
2751 {
2752 int i;
2753
2754 vector_free(route_match_vec);
2755 route_match_vec = NULL;
2756 vector_free(route_set_vec);
2757 route_set_vec = NULL;
2758
2759 /*
2760 * All protocols are setting these to NULL
2761 * by default on shutdown( route_map_finish )
2762 * Why are we making them do this work?
2763 */
2764 route_map_master.add_hook = NULL;
2765 route_map_master.delete_hook = NULL;
2766 route_map_master.event_hook = NULL;
2767
2768 /* cleanup route_map */
2769 while (route_map_master.head) {
2770 struct route_map *map = route_map_master.head;
2771 map->to_be_processed = false;
2772 route_map_delete(map);
2773 }
2774
2775 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
2776 hash_free(route_map_dep_hash[i]);
2777 route_map_dep_hash[i] = NULL;
2778 }
2779
2780 hash_free(route_map_master_hash);
2781 route_map_master_hash = NULL;
2782 }
2783
2784 static void rmap_autocomplete(vector comps, struct cmd_token *token)
2785 {
2786 struct route_map *map;
2787
2788 for (map = route_map_master.head; map; map = map->next)
2789 vector_set(comps, XSTRDUP(MTYPE_COMPLETION, map->name));
2790 }
2791
2792 static const struct cmd_variable_handler rmap_var_handlers[] = {
2793 {/* "route-map WORD" */
2794 .varname = "route_map",
2795 .completions = rmap_autocomplete},
2796 {.tokenname = "ROUTEMAP_NAME", .completions = rmap_autocomplete},
2797 {.tokenname = "RMAP_NAME", .completions = rmap_autocomplete},
2798 {.completions = NULL}};
2799
2800 /* Initialization of route map vector. */
2801 void route_map_init(void)
2802 {
2803 int i;
2804
2805 /* Make vector for match and set. */
2806 route_match_vec = vector_init(1);
2807 route_set_vec = vector_init(1);
2808 route_map_master_hash =
2809 hash_create_size(8, route_map_hash_key_make, route_map_hash_cmp,
2810 "Route Map Master Hash");
2811
2812 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
2813 route_map_dep_hash[i] = hash_create_size(
2814 8, route_map_dep_hash_make_key, route_map_dep_hash_cmp,
2815 "Route Map Dep Hash");
2816
2817 cmd_variable_handler_register(rmap_var_handlers);
2818
2819 /* Install route map top node. */
2820 install_node(&rmap_node, route_map_config_write);
2821
2822 /* Install route map commands. */
2823 install_default(RMAP_NODE);
2824 install_element(CONFIG_NODE, &route_map_cmd);
2825 install_element(CONFIG_NODE, &no_route_map_cmd);
2826 install_element(CONFIG_NODE, &no_route_map_all_cmd);
2827
2828 /* Install the on-match stuff */
2829 install_element(RMAP_NODE, &route_map_cmd);
2830 install_element(RMAP_NODE, &rmap_onmatch_next_cmd);
2831 install_element(RMAP_NODE, &no_rmap_onmatch_next_cmd);
2832 install_element(RMAP_NODE, &rmap_onmatch_goto_cmd);
2833 install_element(RMAP_NODE, &no_rmap_onmatch_goto_cmd);
2834 install_element(RMAP_NODE, &rmap_continue_cmd);
2835 install_element(RMAP_NODE, &no_rmap_continue_cmd);
2836
2837 /* Install the continue stuff (ALIAS of on-match). */
2838
2839 /* Install the call stuff. */
2840 install_element(RMAP_NODE, &rmap_call_cmd);
2841 install_element(RMAP_NODE, &no_rmap_call_cmd);
2842
2843 /* Install description commands. */
2844 install_element(RMAP_NODE, &rmap_description_cmd);
2845 install_element(RMAP_NODE, &no_rmap_description_cmd);
2846
2847 /* Install show command */
2848 install_element(ENABLE_NODE, &rmap_show_name_cmd);
2849
2850 install_element(RMAP_NODE, &match_interface_cmd);
2851 install_element(RMAP_NODE, &no_match_interface_cmd);
2852
2853 install_element(RMAP_NODE, &match_ip_address_cmd);
2854 install_element(RMAP_NODE, &no_match_ip_address_cmd);
2855
2856 install_element(RMAP_NODE, &match_ip_address_prefix_list_cmd);
2857 install_element(RMAP_NODE, &no_match_ip_address_prefix_list_cmd);
2858
2859 install_element(RMAP_NODE, &match_ip_next_hop_cmd);
2860 install_element(RMAP_NODE, &no_match_ip_next_hop_cmd);
2861
2862 install_element(RMAP_NODE, &match_ip_next_hop_prefix_list_cmd);
2863 install_element(RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd);
2864
2865 install_element(RMAP_NODE, &match_ipv6_address_cmd);
2866 install_element(RMAP_NODE, &no_match_ipv6_address_cmd);
2867
2868 install_element(RMAP_NODE, &match_ipv6_address_prefix_list_cmd);
2869 install_element(RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd);
2870
2871 install_element(RMAP_NODE, &match_metric_cmd);
2872 install_element(RMAP_NODE, &no_match_metric_cmd);
2873
2874 install_element(RMAP_NODE, &match_tag_cmd);
2875 install_element(RMAP_NODE, &no_match_tag_cmd);
2876
2877 install_element(RMAP_NODE, &set_ip_nexthop_cmd);
2878 install_element(RMAP_NODE, &no_set_ip_nexthop_cmd);
2879
2880 install_element(RMAP_NODE, &set_ipv6_nexthop_local_cmd);
2881 install_element(RMAP_NODE, &no_set_ipv6_nexthop_local_cmd);
2882
2883 install_element(RMAP_NODE, &set_metric_cmd);
2884 install_element(RMAP_NODE, &no_set_metric_cmd);
2885
2886 install_element(RMAP_NODE, &set_tag_cmd);
2887 install_element(RMAP_NODE, &no_set_tag_cmd);
2888 }