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