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