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