]> git.proxmox.com Git - mirror_frr.git/blob - lib/routemap.c
Merge pull request #1087 from qlyoung/fix-weirdness
[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(route_map_dep_hash_make_key,
1585 route_map_rmap_hash_cmp, NULL);
1586 dep_entry->this_hash = NULL;
1587
1588 return ((void *)dep_entry);
1589 }
1590
1591 static void *route_map_name_hash_alloc(void *p)
1592 {
1593 return ((void *)XSTRDUP(MTYPE_ROUTE_MAP_NAME, (const char *)p));
1594 }
1595
1596 static unsigned int route_map_dep_hash_make_key(void *p)
1597 {
1598 return (string_hash_make((char *)p));
1599 }
1600
1601 static void route_map_print_dependency(struct hash_backet *backet, void *data)
1602 {
1603 char *rmap_name = (char *)backet->data;
1604 char *dep_name = (char *)data;
1605
1606 if (rmap_name)
1607 zlog_debug("%s: Dependency for %s: %s", __FUNCTION__, dep_name,
1608 rmap_name);
1609 }
1610
1611 static int route_map_dep_update(struct hash *dephash, const char *dep_name,
1612 const char *rmap_name, route_map_event_t type)
1613 {
1614 struct route_map_dep *dep = NULL;
1615 char *ret_map_name;
1616 char *dname, *rname;
1617 int ret = 0;
1618
1619 dname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
1620 rname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_name);
1621
1622 switch (type) {
1623 case RMAP_EVENT_PLIST_ADDED:
1624 case RMAP_EVENT_CLIST_ADDED:
1625 case RMAP_EVENT_ECLIST_ADDED:
1626 case RMAP_EVENT_ASLIST_ADDED:
1627 case RMAP_EVENT_LLIST_ADDED:
1628 case RMAP_EVENT_CALL_ADDED:
1629 case RMAP_EVENT_FILTER_ADDED:
1630 if (rmap_debug)
1631 zlog_debug("%s: Adding dependency for %s in %s",
1632 __FUNCTION__, dep_name, rmap_name);
1633 dep = (struct route_map_dep *)hash_get(
1634 dephash, dname, route_map_dep_hash_alloc);
1635 if (!dep) {
1636 ret = -1;
1637 goto out;
1638 }
1639
1640 if (!dep->this_hash)
1641 dep->this_hash = dephash;
1642
1643 hash_get(dep->dep_rmap_hash, rname, route_map_name_hash_alloc);
1644 break;
1645 case RMAP_EVENT_PLIST_DELETED:
1646 case RMAP_EVENT_CLIST_DELETED:
1647 case RMAP_EVENT_ECLIST_DELETED:
1648 case RMAP_EVENT_ASLIST_DELETED:
1649 case RMAP_EVENT_LLIST_DELETED:
1650 case RMAP_EVENT_CALL_DELETED:
1651 case RMAP_EVENT_FILTER_DELETED:
1652 if (rmap_debug)
1653 zlog_debug("%s: Deleting dependency for %s in %s",
1654 __FUNCTION__, dep_name, rmap_name);
1655 dep = (struct route_map_dep *)hash_get(dephash, dname, NULL);
1656 if (!dep) {
1657 goto out;
1658 }
1659
1660 ret_map_name = (char *)hash_release(dep->dep_rmap_hash, rname);
1661 if (ret_map_name)
1662 XFREE(MTYPE_ROUTE_MAP_NAME, ret_map_name);
1663
1664 if (!dep->dep_rmap_hash->count) {
1665 dep = hash_release(dephash, dname);
1666 hash_free(dep->dep_rmap_hash);
1667 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
1668 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
1669 dep = NULL;
1670 }
1671 break;
1672 default:
1673 break;
1674 }
1675
1676 if (dep) {
1677 if (rmap_debug)
1678 hash_iterate(dep->dep_rmap_hash,
1679 route_map_print_dependency, dname);
1680 }
1681
1682 out:
1683 XFREE(MTYPE_ROUTE_MAP_NAME, rname);
1684 XFREE(MTYPE_ROUTE_MAP_NAME, dname);
1685 return ret;
1686 }
1687
1688 static struct hash *route_map_get_dep_hash(route_map_event_t event)
1689 {
1690 struct hash *upd8_hash = NULL;
1691
1692 switch (event) {
1693 case RMAP_EVENT_PLIST_ADDED:
1694 case RMAP_EVENT_PLIST_DELETED:
1695 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_PLIST];
1696 break;
1697 case RMAP_EVENT_CLIST_ADDED:
1698 case RMAP_EVENT_CLIST_DELETED:
1699 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_CLIST];
1700 break;
1701 case RMAP_EVENT_ECLIST_ADDED:
1702 case RMAP_EVENT_ECLIST_DELETED:
1703 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ECLIST];
1704 break;
1705 case RMAP_EVENT_ASLIST_ADDED:
1706 case RMAP_EVENT_ASLIST_DELETED:
1707 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ASPATH];
1708 break;
1709 case RMAP_EVENT_LLIST_ADDED:
1710 case RMAP_EVENT_LLIST_DELETED:
1711 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_LCLIST];
1712 break;
1713 case RMAP_EVENT_CALL_ADDED:
1714 case RMAP_EVENT_CALL_DELETED:
1715 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_RMAP];
1716 break;
1717 case RMAP_EVENT_FILTER_ADDED:
1718 case RMAP_EVENT_FILTER_DELETED:
1719 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_FILTER];
1720 break;
1721 default:
1722 upd8_hash = NULL;
1723 break;
1724 }
1725 return (upd8_hash);
1726 }
1727
1728 static void route_map_process_dependency(struct hash_backet *backet, void *data)
1729 {
1730 char *rmap_name;
1731 route_map_event_t type = (route_map_event_t)(ptrdiff_t)data;
1732
1733 rmap_name = (char *)backet->data;
1734
1735 if (rmap_name) {
1736 if (rmap_debug)
1737 zlog_debug("%s: Notifying %s of dependency",
1738 __FUNCTION__, rmap_name);
1739 if (route_map_master.event_hook)
1740 (*route_map_master.event_hook)(type, rmap_name);
1741 }
1742 }
1743
1744 void route_map_upd8_dependency(route_map_event_t type, const char *arg,
1745 const char *rmap_name)
1746 {
1747 struct hash *upd8_hash = NULL;
1748
1749 if ((upd8_hash = route_map_get_dep_hash(type)))
1750 route_map_dep_update(upd8_hash, arg, rmap_name, type);
1751 }
1752
1753 void route_map_notify_dependencies(const char *affected_name,
1754 route_map_event_t event)
1755 {
1756 struct route_map_dep *dep;
1757 struct hash *upd8_hash;
1758 char *name;
1759
1760 if (!affected_name)
1761 return;
1762
1763 name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, affected_name);
1764
1765 if ((upd8_hash = route_map_get_dep_hash(event)) == NULL) {
1766 XFREE(MTYPE_ROUTE_MAP_NAME, name);
1767 return;
1768 }
1769
1770 dep = (struct route_map_dep *)hash_get(upd8_hash, name, NULL);
1771 if (dep) {
1772 if (!dep->this_hash)
1773 dep->this_hash = upd8_hash;
1774
1775 hash_iterate(dep->dep_rmap_hash, route_map_process_dependency,
1776 (void *)event);
1777 }
1778
1779 XFREE(MTYPE_ROUTE_MAP_NAME, name);
1780 }
1781
1782
1783 /* VTY related functions. */
1784 DEFUN (match_interface,
1785 match_interface_cmd,
1786 "match interface WORD",
1787 MATCH_STR
1788 "match first hop interface of route\n"
1789 "Interface name\n")
1790 {
1791 int idx_word = 2;
1792 VTY_DECLVAR_CONTEXT(route_map_index, index);
1793
1794 if (rmap_match_set_hook.match_interface)
1795 return rmap_match_set_hook.match_interface(
1796 vty, index, "interface", argv[idx_word]->arg,
1797 RMAP_EVENT_MATCH_ADDED);
1798 return CMD_SUCCESS;
1799 }
1800
1801 DEFUN (no_match_interface,
1802 no_match_interface_cmd,
1803 "no match interface [WORD]",
1804 NO_STR
1805 MATCH_STR
1806 "Match first hop interface of route\n"
1807 "Interface name\n")
1808 {
1809 char *iface = (argc == 4) ? argv[3]->arg : NULL;
1810 VTY_DECLVAR_CONTEXT(route_map_index, index);
1811
1812 if (rmap_match_set_hook.no_match_interface)
1813 return rmap_match_set_hook.no_match_interface(
1814 vty, index, "interface", iface,
1815 RMAP_EVENT_MATCH_DELETED);
1816 return CMD_SUCCESS;
1817 }
1818
1819
1820 DEFUN (match_ip_address,
1821 match_ip_address_cmd,
1822 "match ip address <(1-199)|(1300-2699)|WORD>",
1823 MATCH_STR
1824 IP_STR
1825 "Match address of route\n"
1826 "IP access-list number\n"
1827 "IP access-list number (expanded range)\n"
1828 "IP Access-list name\n")
1829 {
1830 int idx_acl = 3;
1831 VTY_DECLVAR_CONTEXT(route_map_index, index);
1832
1833 if (rmap_match_set_hook.match_ip_address)
1834 return rmap_match_set_hook.match_ip_address(
1835 vty, index, "ip address", argv[idx_acl]->arg,
1836 RMAP_EVENT_FILTER_ADDED);
1837 return CMD_SUCCESS;
1838 }
1839
1840
1841 DEFUN (no_match_ip_address,
1842 no_match_ip_address_cmd,
1843 "no match ip address [<(1-199)|(1300-2699)|WORD>]",
1844 NO_STR
1845 MATCH_STR
1846 IP_STR
1847 "Match address of route\n"
1848 "IP access-list number\n"
1849 "IP access-list number (expanded range)\n"
1850 "IP Access-list name\n")
1851 {
1852 int idx_word = 4;
1853 VTY_DECLVAR_CONTEXT(route_map_index, index);
1854
1855 if (rmap_match_set_hook.no_match_ip_address) {
1856 if (argc <= idx_word)
1857 return rmap_match_set_hook.no_match_ip_address(
1858 vty, index, "ip address", NULL,
1859 RMAP_EVENT_FILTER_DELETED);
1860 return rmap_match_set_hook.no_match_ip_address(
1861 vty, index, "ip address", argv[idx_word]->arg,
1862 RMAP_EVENT_FILTER_DELETED);
1863 }
1864 return CMD_SUCCESS;
1865 }
1866
1867
1868 DEFUN (match_ip_address_prefix_list,
1869 match_ip_address_prefix_list_cmd,
1870 "match ip address prefix-list WORD",
1871 MATCH_STR
1872 IP_STR
1873 "Match address of route\n"
1874 "Match entries of prefix-lists\n"
1875 "IP prefix-list name\n")
1876 {
1877 int idx_word = 4;
1878 VTY_DECLVAR_CONTEXT(route_map_index, index);
1879
1880 if (rmap_match_set_hook.match_ip_address_prefix_list)
1881 return rmap_match_set_hook.match_ip_address_prefix_list(
1882 vty, index, "ip address prefix-list",
1883 argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
1884 return CMD_SUCCESS;
1885 }
1886
1887
1888 DEFUN (no_match_ip_address_prefix_list,
1889 no_match_ip_address_prefix_list_cmd,
1890 "no match ip address prefix-list [WORD]",
1891 NO_STR
1892 MATCH_STR
1893 IP_STR
1894 "Match address of route\n"
1895 "Match entries of prefix-lists\n"
1896 "IP prefix-list name\n")
1897 {
1898 int idx_word = 5;
1899 VTY_DECLVAR_CONTEXT(route_map_index, index);
1900
1901 if (rmap_match_set_hook.no_match_ip_address_prefix_list) {
1902 if (argc <= idx_word)
1903 return rmap_match_set_hook
1904 .no_match_ip_address_prefix_list(
1905 vty, index, "ip address prefix-list",
1906 NULL, RMAP_EVENT_PLIST_DELETED);
1907 return rmap_match_set_hook.no_match_ip_address_prefix_list(
1908 vty, index, "ip address prefix-list",
1909 argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
1910 }
1911 return CMD_SUCCESS;
1912 }
1913
1914
1915 DEFUN (match_ip_next_hop,
1916 match_ip_next_hop_cmd,
1917 "match ip next-hop <(1-199)|(1300-2699)|WORD>",
1918 MATCH_STR
1919 IP_STR
1920 "Match next-hop address of route\n"
1921 "IP access-list number\n"
1922 "IP access-list number (expanded range)\n"
1923 "IP Access-list name\n")
1924 {
1925 int idx_acl = 3;
1926 VTY_DECLVAR_CONTEXT(route_map_index, index);
1927
1928 if (rmap_match_set_hook.match_ip_next_hop)
1929 return rmap_match_set_hook.match_ip_next_hop(
1930 vty, index, "ip next-hop", argv[idx_acl]->arg,
1931 RMAP_EVENT_FILTER_ADDED);
1932 return CMD_SUCCESS;
1933 }
1934
1935
1936 DEFUN (no_match_ip_next_hop,
1937 no_match_ip_next_hop_cmd,
1938 "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
1939 NO_STR
1940 MATCH_STR
1941 IP_STR
1942 "Match next-hop address of route\n"
1943 "IP access-list number\n"
1944 "IP access-list number (expanded range)\n"
1945 "IP Access-list name\n")
1946 {
1947 int idx_word = 4;
1948 VTY_DECLVAR_CONTEXT(route_map_index, index);
1949
1950 if (rmap_match_set_hook.no_match_ip_next_hop) {
1951 if (argc <= idx_word)
1952 return rmap_match_set_hook.no_match_ip_next_hop(
1953 vty, index, "ip next-hop", NULL,
1954 RMAP_EVENT_FILTER_DELETED);
1955 return rmap_match_set_hook.no_match_ip_next_hop(
1956 vty, index, "ip next-hop", argv[idx_word]->arg,
1957 RMAP_EVENT_FILTER_DELETED);
1958 }
1959 return CMD_SUCCESS;
1960 }
1961
1962
1963 DEFUN (match_ip_next_hop_prefix_list,
1964 match_ip_next_hop_prefix_list_cmd,
1965 "match ip next-hop prefix-list WORD",
1966 MATCH_STR
1967 IP_STR
1968 "Match next-hop address of route\n"
1969 "Match entries of prefix-lists\n"
1970 "IP prefix-list name\n")
1971 {
1972 int idx_word = 4;
1973 VTY_DECLVAR_CONTEXT(route_map_index, index);
1974
1975 if (rmap_match_set_hook.match_ip_next_hop_prefix_list)
1976 return rmap_match_set_hook.match_ip_next_hop_prefix_list(
1977 vty, index, "ip next-hop prefix-list",
1978 argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
1979 return CMD_SUCCESS;
1980 }
1981
1982 DEFUN (no_match_ip_next_hop_prefix_list,
1983 no_match_ip_next_hop_prefix_list_cmd,
1984 "no match ip next-hop prefix-list [WORD]",
1985 NO_STR
1986 MATCH_STR
1987 IP_STR
1988 "Match next-hop address of route\n"
1989 "Match entries of prefix-lists\n"
1990 "IP prefix-list name\n")
1991 {
1992 int idx_word = 5;
1993 VTY_DECLVAR_CONTEXT(route_map_index, index);
1994
1995 if (rmap_match_set_hook.no_match_ip_next_hop) {
1996 if (argc <= idx_word)
1997 return rmap_match_set_hook.no_match_ip_next_hop(
1998 vty, index, "ip next-hop prefix-list", NULL,
1999 RMAP_EVENT_PLIST_DELETED);
2000 return rmap_match_set_hook.no_match_ip_next_hop(
2001 vty, index, "ip next-hop prefix-list",
2002 argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
2003 }
2004 return CMD_SUCCESS;
2005 }
2006
2007
2008 DEFUN (match_ipv6_address,
2009 match_ipv6_address_cmd,
2010 "match ipv6 address WORD",
2011 MATCH_STR
2012 IPV6_STR
2013 "Match IPv6 address of route\n"
2014 "IPv6 access-list name\n")
2015 {
2016 int idx_word = 3;
2017 VTY_DECLVAR_CONTEXT(route_map_index, index);
2018
2019 if (rmap_match_set_hook.match_ipv6_address)
2020 return rmap_match_set_hook.match_ipv6_address(
2021 vty, index, "ipv6 address", argv[idx_word]->arg,
2022 RMAP_EVENT_FILTER_ADDED);
2023 return CMD_SUCCESS;
2024 }
2025
2026 DEFUN (no_match_ipv6_address,
2027 no_match_ipv6_address_cmd,
2028 "no match ipv6 address WORD",
2029 NO_STR
2030 MATCH_STR
2031 IPV6_STR
2032 "Match IPv6 address of route\n"
2033 "IPv6 access-list name\n")
2034 {
2035 int idx_word = 4;
2036 VTY_DECLVAR_CONTEXT(route_map_index, index);
2037
2038 if (rmap_match_set_hook.no_match_ipv6_address)
2039 return rmap_match_set_hook.no_match_ipv6_address(
2040 vty, index, "ipv6 address", argv[idx_word]->arg,
2041 RMAP_EVENT_FILTER_DELETED);
2042 return CMD_SUCCESS;
2043 }
2044
2045
2046 DEFUN (match_ipv6_address_prefix_list,
2047 match_ipv6_address_prefix_list_cmd,
2048 "match ipv6 address prefix-list WORD",
2049 MATCH_STR
2050 IPV6_STR
2051 "Match address of route\n"
2052 "Match entries of prefix-lists\n"
2053 "IP prefix-list name\n")
2054 {
2055 int idx_word = 4;
2056 VTY_DECLVAR_CONTEXT(route_map_index, index);
2057
2058 if (rmap_match_set_hook.match_ipv6_address_prefix_list)
2059 return rmap_match_set_hook.match_ipv6_address_prefix_list(
2060 vty, index, "ipv6 address prefix-list",
2061 argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
2062 return CMD_SUCCESS;
2063 }
2064
2065 DEFUN (no_match_ipv6_address_prefix_list,
2066 no_match_ipv6_address_prefix_list_cmd,
2067 "no match ipv6 address prefix-list WORD",
2068 NO_STR
2069 MATCH_STR
2070 IPV6_STR
2071 "Match address of route\n"
2072 "Match entries of prefix-lists\n"
2073 "IP prefix-list name\n")
2074 {
2075 int idx_word = 5;
2076 VTY_DECLVAR_CONTEXT(route_map_index, index);
2077
2078 if (rmap_match_set_hook.no_match_ipv6_address_prefix_list)
2079 return rmap_match_set_hook.no_match_ipv6_address_prefix_list(
2080 vty, index, "ipv6 address prefix-list",
2081 argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
2082 return CMD_SUCCESS;
2083 }
2084
2085
2086 DEFUN (match_metric,
2087 match_metric_cmd,
2088 "match metric (0-4294967295)",
2089 MATCH_STR
2090 "Match metric of route\n"
2091 "Metric value\n")
2092 {
2093 int idx_number = 2;
2094 VTY_DECLVAR_CONTEXT(route_map_index, index);
2095
2096 if (rmap_match_set_hook.match_metric)
2097 return rmap_match_set_hook.match_metric(vty, index, "metric",
2098 argv[idx_number]->arg,
2099 RMAP_EVENT_MATCH_ADDED);
2100 return CMD_SUCCESS;
2101 }
2102
2103
2104 DEFUN (no_match_metric,
2105 no_match_metric_cmd,
2106 "no match metric [(0-4294967295)]",
2107 NO_STR
2108 MATCH_STR
2109 "Match metric of route\n"
2110 "Metric value\n")
2111 {
2112 int idx_number = 3;
2113 VTY_DECLVAR_CONTEXT(route_map_index, index);
2114
2115 if (rmap_match_set_hook.no_match_metric) {
2116 if (argc <= idx_number)
2117 return rmap_match_set_hook.no_match_metric(
2118 vty, index, "metric", NULL,
2119 RMAP_EVENT_MATCH_DELETED);
2120 return rmap_match_set_hook.no_match_metric(
2121 vty, index, "metric", argv[idx_number]->arg,
2122 RMAP_EVENT_MATCH_DELETED);
2123 }
2124 return CMD_SUCCESS;
2125 }
2126
2127
2128 DEFUN (match_tag,
2129 match_tag_cmd,
2130 "match tag (1-4294967295)",
2131 MATCH_STR
2132 "Match tag of route\n"
2133 "Tag value\n")
2134 {
2135 int idx_number = 2;
2136 VTY_DECLVAR_CONTEXT(route_map_index, index);
2137
2138 if (rmap_match_set_hook.match_tag)
2139 return rmap_match_set_hook.match_tag(vty, index, "tag",
2140 argv[idx_number]->arg,
2141 RMAP_EVENT_MATCH_ADDED);
2142 return CMD_SUCCESS;
2143 }
2144
2145
2146 DEFUN (no_match_tag,
2147 no_match_tag_cmd,
2148 "no match tag [(1-4294967295)]",
2149 NO_STR
2150 MATCH_STR
2151 "Match tag of route\n"
2152 "Tag value\n")
2153 {
2154 VTY_DECLVAR_CONTEXT(route_map_index, index);
2155
2156 int idx = 0;
2157 char *arg = argv_find(argv, argc, "(1-4294967295)", &idx)
2158 ? argv[idx]->arg
2159 : NULL;
2160
2161 if (rmap_match_set_hook.no_match_tag)
2162 return rmap_match_set_hook.no_match_tag(
2163 vty, index, "tag", arg, RMAP_EVENT_MATCH_DELETED);
2164 return CMD_SUCCESS;
2165 }
2166
2167
2168 DEFUN (set_ip_nexthop,
2169 set_ip_nexthop_cmd,
2170 "set ip next-hop A.B.C.D",
2171 SET_STR
2172 IP_STR
2173 "Next hop address\n"
2174 "IP address of next hop\n")
2175 {
2176 int idx_ipv4 = 3;
2177 union sockunion su;
2178 int ret;
2179 VTY_DECLVAR_CONTEXT(route_map_index, index);
2180
2181 ret = str2sockunion(argv[idx_ipv4]->arg, &su);
2182 if (ret < 0) {
2183 vty_out(vty, "%% Malformed nexthop address\n");
2184 return CMD_WARNING_CONFIG_FAILED;
2185 }
2186 if (su.sin.sin_addr.s_addr == 0
2187 || IPV4_CLASS_DE(su.sin.sin_addr.s_addr)) {
2188 vty_out(vty,
2189 "%% nexthop address cannot be 0.0.0.0, multicast or reserved\n");
2190 return CMD_WARNING_CONFIG_FAILED;
2191 }
2192
2193 if (rmap_match_set_hook.set_ip_nexthop)
2194 return rmap_match_set_hook.set_ip_nexthop(
2195 vty, index, "ip next-hop", argv[idx_ipv4]->arg);
2196 return CMD_SUCCESS;
2197 }
2198
2199
2200 DEFUN (no_set_ip_nexthop,
2201 no_set_ip_nexthop_cmd,
2202 "no set ip next-hop [A.B.C.D]",
2203 NO_STR
2204 SET_STR
2205 IP_STR
2206 "Next hop address\n"
2207 "IP address of next hop\n")
2208 {
2209 int idx = 0;
2210 VTY_DECLVAR_CONTEXT(route_map_index, index);
2211 const char *arg = NULL;
2212
2213 if (argv_find(argv, argc, "A.B.C.D", &idx))
2214 arg = argv[idx]->arg;
2215
2216 if (rmap_match_set_hook.no_set_ip_nexthop)
2217 return rmap_match_set_hook.no_set_ip_nexthop(
2218 vty, index, "ip next-hop", arg);
2219
2220 return CMD_SUCCESS;
2221 }
2222
2223
2224 DEFUN (set_ipv6_nexthop_local,
2225 set_ipv6_nexthop_local_cmd,
2226 "set ipv6 next-hop local X:X::X:X",
2227 SET_STR
2228 IPV6_STR
2229 "IPv6 next-hop address\n"
2230 "IPv6 local address\n"
2231 "IPv6 address of next hop\n")
2232 {
2233 int idx_ipv6 = 4;
2234 struct in6_addr addr;
2235 int ret;
2236 VTY_DECLVAR_CONTEXT(route_map_index, index);
2237
2238 ret = inet_pton(AF_INET6, argv[idx_ipv6]->arg, &addr);
2239 if (!ret) {
2240 vty_out(vty, "%% Malformed nexthop address\n");
2241 return CMD_WARNING_CONFIG_FAILED;
2242 }
2243 if (!IN6_IS_ADDR_LINKLOCAL(&addr)) {
2244 vty_out(vty, "%% Invalid link-local nexthop address\n");
2245 return CMD_WARNING_CONFIG_FAILED;
2246 }
2247
2248 if (rmap_match_set_hook.set_ipv6_nexthop_local)
2249 return rmap_match_set_hook.set_ipv6_nexthop_local(
2250 vty, index, "ipv6 next-hop local", argv[idx_ipv6]->arg);
2251 return CMD_SUCCESS;
2252 }
2253
2254
2255 DEFUN (no_set_ipv6_nexthop_local,
2256 no_set_ipv6_nexthop_local_cmd,
2257 "no set ipv6 next-hop local [X:X::X:X]",
2258 NO_STR
2259 SET_STR
2260 IPV6_STR
2261 "IPv6 next-hop address\n"
2262 "IPv6 local address\n"
2263 "IPv6 address of next hop\n")
2264 {
2265 int idx_ipv6 = 5;
2266 VTY_DECLVAR_CONTEXT(route_map_index, index);
2267
2268 if (rmap_match_set_hook.no_set_ipv6_nexthop_local) {
2269 if (argc <= idx_ipv6)
2270 return rmap_match_set_hook.no_set_ipv6_nexthop_local(
2271 vty, index, "ipv6 next-hop local", NULL);
2272 return rmap_match_set_hook.no_set_ipv6_nexthop_local(
2273 vty, index, "ipv6 next-hop local", argv[5]->arg);
2274 }
2275 return CMD_SUCCESS;
2276 }
2277
2278 DEFUN (set_metric,
2279 set_metric_cmd,
2280 "set metric <(0-4294967295)|rtt|+rtt|-rtt|+metric|-metric>",
2281 SET_STR
2282 "Metric value for destination routing protocol\n"
2283 "Metric value\n"
2284 "Assign round trip time\n"
2285 "Add round trip time\n"
2286 "Subtract round trip time\n"
2287 "Add metric\n"
2288 "Subtract metric\n")
2289 {
2290 int idx_number = 2;
2291 VTY_DECLVAR_CONTEXT(route_map_index, index);
2292
2293 const char *pass = (argv[idx_number]->type == RANGE_TKN)
2294 ? argv[idx_number]->arg
2295 : argv[idx_number]->text;
2296
2297 if (rmap_match_set_hook.set_metric)
2298 return rmap_match_set_hook.set_metric(vty, index, "metric",
2299 pass);
2300 return CMD_SUCCESS;
2301 }
2302
2303
2304 DEFUN (no_set_metric,
2305 no_set_metric_cmd,
2306 "no set metric [(0-4294967295)]",
2307 NO_STR
2308 SET_STR
2309 "Metric value for destination routing protocol\n"
2310 "Metric value\n")
2311 {
2312 int idx_number = 3;
2313 VTY_DECLVAR_CONTEXT(route_map_index, index);
2314
2315 if (rmap_match_set_hook.no_set_metric) {
2316 if (argc <= idx_number)
2317 return rmap_match_set_hook.no_set_metric(
2318 vty, index, "metric", NULL);
2319 return rmap_match_set_hook.no_set_metric(vty, index, "metric",
2320 argv[idx_number]->arg);
2321 }
2322 return CMD_SUCCESS;
2323 }
2324
2325
2326 DEFUN (set_tag,
2327 set_tag_cmd,
2328 "set tag (1-4294967295)",
2329 SET_STR
2330 "Tag value for routing protocol\n"
2331 "Tag value\n")
2332 {
2333 VTY_DECLVAR_CONTEXT(route_map_index, index);
2334
2335 int idx_number = 2;
2336 if (rmap_match_set_hook.set_tag)
2337 return rmap_match_set_hook.set_tag(vty, index, "tag",
2338 argv[idx_number]->arg);
2339 return CMD_SUCCESS;
2340 }
2341
2342
2343 DEFUN (no_set_tag,
2344 no_set_tag_cmd,
2345 "no set tag [(1-4294967295)]",
2346 NO_STR
2347 SET_STR
2348 "Tag value for routing protocol\n"
2349 "Tag value\n")
2350 {
2351 VTY_DECLVAR_CONTEXT(route_map_index, index);
2352
2353 int idx_number = 3;
2354 if (rmap_match_set_hook.no_set_tag) {
2355 if (argc <= idx_number)
2356 return rmap_match_set_hook.no_set_tag(vty, index, "tag",
2357 NULL);
2358 return rmap_match_set_hook.no_set_tag(vty, index, "tag",
2359 argv[idx_number]->arg);
2360 }
2361 return CMD_SUCCESS;
2362 }
2363
2364
2365 DEFUN_NOSH (route_map,
2366 route_map_cmd,
2367 "route-map WORD <deny|permit> (1-65535)",
2368 "Create route-map or enter route-map command mode\n"
2369 "Route map tag\n"
2370 "Route map denies set operations\n"
2371 "Route map permits set operations\n"
2372 "Sequence to insert to/delete from existing route-map entry\n")
2373 {
2374 int idx_word = 1;
2375 int idx_permit_deny = 2;
2376 int idx_number = 3;
2377 struct route_map *map;
2378 struct route_map_index *index;
2379 char *endptr = NULL;
2380 int permit =
2381 argv[idx_permit_deny]->arg[0] == 'p' ? RMAP_PERMIT : RMAP_DENY;
2382 unsigned long pref = strtoul(argv[idx_number]->arg, &endptr, 10);
2383 const char *mapname = argv[idx_word]->arg;
2384
2385 /* Get route map. */
2386 map = route_map_get(mapname);
2387 index = route_map_index_get(map, permit, pref);
2388
2389 VTY_PUSH_CONTEXT(RMAP_NODE, index);
2390 return CMD_SUCCESS;
2391 }
2392
2393 DEFUN (no_route_map_all,
2394 no_route_map_all_cmd,
2395 "no route-map WORD",
2396 NO_STR
2397 "Create route-map or enter route-map command mode\n"
2398 "Route map tag\n")
2399 {
2400 int idx_word = 2;
2401 const char *mapname = argv[idx_word]->arg;
2402 struct route_map *map;
2403
2404 map = route_map_lookup_by_name(mapname);
2405 if (map == NULL) {
2406 vty_out(vty, "%% Could not find route-map %s\n", mapname);
2407 return CMD_WARNING_CONFIG_FAILED;
2408 }
2409
2410 route_map_delete(map);
2411
2412 return CMD_SUCCESS;
2413 }
2414
2415 DEFUN (no_route_map,
2416 no_route_map_cmd,
2417 "no route-map WORD <deny|permit> (1-65535)",
2418 NO_STR
2419 "Create route-map or enter route-map command mode\n"
2420 "Route map tag\n"
2421 "Route map denies set operations\n"
2422 "Route map permits set operations\n"
2423 "Sequence to insert to/delete from existing route-map entry\n")
2424 {
2425 int idx_word = 2;
2426 int idx_permit_deny = 3;
2427 int idx_number = 4;
2428 struct route_map *map;
2429 struct route_map_index *index;
2430 char *endptr = NULL;
2431 int permit = strmatch(argv[idx_permit_deny]->text, "permit")
2432 ? RMAP_PERMIT
2433 : RMAP_DENY;
2434 const char *prefstr = argv[idx_number]->arg;
2435 const char *mapname = argv[idx_word]->arg;
2436 unsigned long pref = strtoul(prefstr, &endptr, 10);
2437
2438 /* Existence check. */
2439 map = route_map_lookup_by_name(mapname);
2440 if (map == NULL) {
2441 vty_out(vty, "%% Could not find route-map %s\n", mapname);
2442 return CMD_WARNING_CONFIG_FAILED;
2443 }
2444
2445 /* Lookup route map index. */
2446 index = route_map_index_lookup(map, permit, pref);
2447 if (index == NULL) {
2448 vty_out(vty, "%% Could not find route-map entry %s %s\n",
2449 mapname, prefstr);
2450 return CMD_WARNING_CONFIG_FAILED;
2451 }
2452
2453 /* Delete index from route map. */
2454 route_map_index_delete(index, 1);
2455
2456 /* If this route rule is the last one, delete route map itself. */
2457 if (route_map_empty(map))
2458 route_map_delete(map);
2459
2460 return CMD_SUCCESS;
2461 }
2462
2463 DEFUN (rmap_onmatch_next,
2464 rmap_onmatch_next_cmd,
2465 "on-match next",
2466 "Exit policy on matches\n"
2467 "Next clause\n")
2468 {
2469 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2470
2471 if (index) {
2472 if (index->type == RMAP_DENY) {
2473 /* Under a deny clause, match means it's finished. No
2474 * need to set next */
2475 vty_out(vty,
2476 "on-match next not supported under route-map deny\n");
2477 return CMD_WARNING_CONFIG_FAILED;
2478 }
2479 index->exitpolicy = RMAP_NEXT;
2480 }
2481 return CMD_SUCCESS;
2482 }
2483
2484 DEFUN (no_rmap_onmatch_next,
2485 no_rmap_onmatch_next_cmd,
2486 "no on-match next",
2487 NO_STR
2488 "Exit policy on matches\n"
2489 "Next clause\n")
2490 {
2491 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2492
2493 if (index)
2494 index->exitpolicy = RMAP_EXIT;
2495
2496 return CMD_SUCCESS;
2497 }
2498
2499 DEFUN (rmap_onmatch_goto,
2500 rmap_onmatch_goto_cmd,
2501 "on-match goto (1-65535)",
2502 "Exit policy on matches\n"
2503 "Goto Clause number\n"
2504 "Number\n")
2505 {
2506 int idx = 0;
2507 char *num = argv_find(argv, argc, "(1-65535)", &idx) ? argv[idx]->arg
2508 : NULL;
2509
2510 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2511 int d = 0;
2512
2513 if (index) {
2514 if (index->type == RMAP_DENY) {
2515 /* Under a deny clause, match means it's finished. No
2516 * need to go anywhere */
2517 vty_out(vty,
2518 "on-match goto not supported under route-map deny\n");
2519 return CMD_WARNING_CONFIG_FAILED;
2520 }
2521
2522 if (num)
2523 d = strtoul(num, NULL, 10);
2524 else
2525 d = index->pref + 1;
2526
2527 if (d <= index->pref) {
2528 /* Can't allow you to do that, Dave */
2529 vty_out(vty, "can't jump backwards in route-maps\n");
2530 return CMD_WARNING_CONFIG_FAILED;
2531 } else {
2532 index->exitpolicy = RMAP_GOTO;
2533 index->nextpref = d;
2534 }
2535 }
2536 return CMD_SUCCESS;
2537 }
2538
2539 DEFUN (no_rmap_onmatch_goto,
2540 no_rmap_onmatch_goto_cmd,
2541 "no on-match goto",
2542 NO_STR
2543 "Exit policy on matches\n"
2544 "Goto Clause number\n")
2545 {
2546 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2547
2548 if (index)
2549 index->exitpolicy = RMAP_EXIT;
2550
2551 return CMD_SUCCESS;
2552 }
2553
2554 /* Cisco/GNU Zebra compatibility aliases */
2555 /* ALIAS_FIXME */
2556 DEFUN (rmap_continue,
2557 rmap_continue_cmd,
2558 "continue (1-65535)",
2559 "Continue on a different entry within the route-map\n"
2560 "Route-map entry sequence number\n")
2561 {
2562 return rmap_onmatch_goto(self, vty, argc, argv);
2563 }
2564
2565 /* ALIAS_FIXME */
2566 DEFUN (no_rmap_continue,
2567 no_rmap_continue_cmd,
2568 "no continue [(1-65535)]",
2569 NO_STR
2570 "Continue on a different entry within the route-map\n"
2571 "Route-map entry sequence number\n")
2572 {
2573 return no_rmap_onmatch_goto(self, vty, argc, argv);
2574 }
2575
2576
2577 DEFUN (rmap_show_name,
2578 rmap_show_name_cmd,
2579 "show route-map [WORD]",
2580 SHOW_STR
2581 "route-map information\n"
2582 "route-map name\n")
2583 {
2584 int idx_word = 2;
2585 const char *name = (argc == 3) ? argv[idx_word]->arg : NULL;
2586 return vty_show_route_map(vty, name);
2587 }
2588
2589 DEFUN (rmap_call,
2590 rmap_call_cmd,
2591 "call WORD",
2592 "Jump to another Route-Map after match+set\n"
2593 "Target route-map name\n")
2594 {
2595 int idx_word = 1;
2596 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2597 const char *rmap = argv[idx_word]->arg;
2598
2599 assert(index);
2600
2601 if (index->nextrm) {
2602 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED,
2603 index->nextrm, index->map->name);
2604 XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
2605 }
2606 index->nextrm = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
2607
2608 /* Execute event hook. */
2609 route_map_upd8_dependency(RMAP_EVENT_CALL_ADDED, index->nextrm,
2610 index->map->name);
2611 return CMD_SUCCESS;
2612 }
2613
2614 DEFUN (no_rmap_call,
2615 no_rmap_call_cmd,
2616 "no call",
2617 NO_STR
2618 "Jump to another Route-Map after match+set\n")
2619 {
2620 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2621
2622 if (index->nextrm) {
2623 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED,
2624 index->nextrm, index->map->name);
2625 XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
2626 index->nextrm = NULL;
2627 }
2628
2629 return CMD_SUCCESS;
2630 }
2631
2632 DEFUN (rmap_description,
2633 rmap_description_cmd,
2634 "description LINE...",
2635 "Route-map comment\n"
2636 "Comment describing this route-map rule\n")
2637 {
2638 int idx_line = 1;
2639 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2640
2641 if (index) {
2642 if (index->description)
2643 XFREE(MTYPE_TMP, index->description);
2644 index->description = argv_concat(argv, argc, idx_line);
2645 }
2646 return CMD_SUCCESS;
2647 }
2648
2649 DEFUN (no_rmap_description,
2650 no_rmap_description_cmd,
2651 "no description",
2652 NO_STR
2653 "Route-map comment\n")
2654 {
2655 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2656
2657 if (index) {
2658 if (index->description)
2659 XFREE(MTYPE_TMP, index->description);
2660 index->description = NULL;
2661 }
2662 return CMD_SUCCESS;
2663 }
2664
2665 /* Configuration write function. */
2666 static int route_map_config_write(struct vty *vty)
2667 {
2668 struct route_map *map;
2669 struct route_map_index *index;
2670 struct route_map_rule *rule;
2671 int first = 1;
2672 int write = 0;
2673
2674 for (map = route_map_master.head; map; map = map->next)
2675 for (index = map->head; index; index = index->next) {
2676 if (!first)
2677 vty_out(vty, "!\n");
2678 else
2679 first = 0;
2680
2681 vty_out(vty, "route-map %s %s %d\n", map->name,
2682 route_map_type_str(index->type), index->pref);
2683
2684 if (index->description)
2685 vty_out(vty, " description %s\n",
2686 index->description);
2687
2688 for (rule = index->match_list.head; rule;
2689 rule = rule->next)
2690 vty_out(vty, " match %s %s\n", rule->cmd->str,
2691 rule->rule_str ? rule->rule_str : "");
2692
2693 for (rule = index->set_list.head; rule;
2694 rule = rule->next)
2695 vty_out(vty, " set %s %s\n", rule->cmd->str,
2696 rule->rule_str ? rule->rule_str : "");
2697 if (index->nextrm)
2698 vty_out(vty, " call %s\n", index->nextrm);
2699 if (index->exitpolicy == RMAP_GOTO)
2700 vty_out(vty, " on-match goto %d\n",
2701 index->nextpref);
2702 if (index->exitpolicy == RMAP_NEXT)
2703 vty_out(vty, " on-match next\n");
2704
2705 write++;
2706 }
2707 return write;
2708 }
2709
2710 /* Route map node structure. */
2711 static struct cmd_node rmap_node = {RMAP_NODE, "%s(config-route-map)# ", 1};
2712
2713 /* Common route map rules */
2714
2715 void *route_map_rule_tag_compile(const char *arg)
2716 {
2717 unsigned long int tmp;
2718 char *endptr;
2719 route_tag_t *tag;
2720
2721 errno = 0;
2722 tmp = strtoul(arg, &endptr, 0);
2723 if (arg[0] == '\0' || *endptr != '\0' || errno || tmp > ROUTE_TAG_MAX)
2724 return NULL;
2725
2726 tag = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*tag));
2727 *tag = tmp;
2728
2729 return tag;
2730 }
2731
2732 void route_map_rule_tag_free(void *rule)
2733 {
2734 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
2735 }
2736
2737 void route_map_finish(void)
2738 {
2739 int i;
2740
2741 vector_free(route_match_vec);
2742 route_match_vec = NULL;
2743 vector_free(route_set_vec);
2744 route_set_vec = NULL;
2745
2746 /* cleanup route_map */
2747 while (route_map_master.head) {
2748 struct route_map *map = route_map_master.head;
2749 map->to_be_processed = 0;
2750 route_map_delete(map);
2751 }
2752
2753 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
2754 hash_free(route_map_dep_hash[i]);
2755 route_map_dep_hash[i] = NULL;
2756 }
2757
2758 hash_free(route_map_master_hash);
2759 route_map_master_hash = NULL;
2760 }
2761
2762 static void rmap_autocomplete(vector comps, struct cmd_token *token)
2763 {
2764 struct route_map *map;
2765
2766 for (map = route_map_master.head; map; map = map->next)
2767 vector_set(comps, XSTRDUP(MTYPE_COMPLETION, map->name));
2768 }
2769
2770 static const struct cmd_variable_handler rmap_var_handlers[] = {
2771 {/* "route-map WORD" */
2772 .varname = "route_map",
2773 .completions = rmap_autocomplete},
2774 {.tokenname = "ROUTEMAP_NAME", .completions = rmap_autocomplete},
2775 {.tokenname = "RMAP_NAME", .completions = rmap_autocomplete},
2776 {.completions = NULL}};
2777
2778 /* Initialization of route map vector. */
2779 void route_map_init(void)
2780 {
2781 int i;
2782
2783 /* Make vector for match and set. */
2784 route_match_vec = vector_init(1);
2785 route_set_vec = vector_init(1);
2786 route_map_master_hash =
2787 hash_create(route_map_hash_key_make, route_map_hash_cmp, NULL);
2788
2789 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
2790 route_map_dep_hash[i] =
2791 hash_create(route_map_dep_hash_make_key,
2792 route_map_dep_hash_cmp, NULL);
2793
2794 cmd_variable_handler_register(rmap_var_handlers);
2795
2796 /* Install route map top node. */
2797 install_node(&rmap_node, route_map_config_write);
2798
2799 /* Install route map commands. */
2800 install_default(RMAP_NODE);
2801 install_element(CONFIG_NODE, &route_map_cmd);
2802 install_element(CONFIG_NODE, &no_route_map_cmd);
2803 install_element(CONFIG_NODE, &no_route_map_all_cmd);
2804
2805 /* Install the on-match stuff */
2806 install_element(RMAP_NODE, &route_map_cmd);
2807 install_element(RMAP_NODE, &rmap_onmatch_next_cmd);
2808 install_element(RMAP_NODE, &no_rmap_onmatch_next_cmd);
2809 install_element(RMAP_NODE, &rmap_onmatch_goto_cmd);
2810 install_element(RMAP_NODE, &no_rmap_onmatch_goto_cmd);
2811 install_element(RMAP_NODE, &rmap_continue_cmd);
2812 install_element(RMAP_NODE, &no_rmap_continue_cmd);
2813
2814 /* Install the continue stuff (ALIAS of on-match). */
2815
2816 /* Install the call stuff. */
2817 install_element(RMAP_NODE, &rmap_call_cmd);
2818 install_element(RMAP_NODE, &no_rmap_call_cmd);
2819
2820 /* Install description commands. */
2821 install_element(RMAP_NODE, &rmap_description_cmd);
2822 install_element(RMAP_NODE, &no_rmap_description_cmd);
2823
2824 /* Install show command */
2825 install_element(ENABLE_NODE, &rmap_show_name_cmd);
2826
2827 install_element(RMAP_NODE, &match_interface_cmd);
2828 install_element(RMAP_NODE, &no_match_interface_cmd);
2829
2830 install_element(RMAP_NODE, &match_ip_address_cmd);
2831 install_element(RMAP_NODE, &no_match_ip_address_cmd);
2832
2833 install_element(RMAP_NODE, &match_ip_address_prefix_list_cmd);
2834 install_element(RMAP_NODE, &no_match_ip_address_prefix_list_cmd);
2835
2836 install_element(RMAP_NODE, &match_ip_next_hop_cmd);
2837 install_element(RMAP_NODE, &no_match_ip_next_hop_cmd);
2838
2839 install_element(RMAP_NODE, &match_ip_next_hop_prefix_list_cmd);
2840 install_element(RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd);
2841
2842 install_element(RMAP_NODE, &match_ipv6_address_cmd);
2843 install_element(RMAP_NODE, &no_match_ipv6_address_cmd);
2844
2845 install_element(RMAP_NODE, &match_ipv6_address_prefix_list_cmd);
2846 install_element(RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd);
2847
2848 install_element(RMAP_NODE, &match_metric_cmd);
2849 install_element(RMAP_NODE, &no_match_metric_cmd);
2850
2851 install_element(RMAP_NODE, &match_tag_cmd);
2852 install_element(RMAP_NODE, &no_match_tag_cmd);
2853
2854 install_element(RMAP_NODE, &set_ip_nexthop_cmd);
2855 install_element(RMAP_NODE, &no_set_ip_nexthop_cmd);
2856
2857 install_element(RMAP_NODE, &set_ipv6_nexthop_local_cmd);
2858 install_element(RMAP_NODE, &no_set_ipv6_nexthop_local_cmd);
2859
2860 install_element(RMAP_NODE, &set_metric_cmd);
2861 install_element(RMAP_NODE, &no_set_metric_cmd);
2862
2863 install_element(RMAP_NODE, &set_tag_cmd);
2864 install_element(RMAP_NODE, &no_set_tag_cmd);
2865 }