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