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