]> git.proxmox.com Git - mirror_frr.git/blame - lib/routemap.c
*: remove VTY_GET_*
[mirror_frr.git] / lib / routemap.c
CommitLineData
718e3744 1/* Route map function.
896014f4
DL
2 * Copyright (C) 1998, 1999 Kunihiro Ishiguro
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
718e3744 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"
b85120bc 32#include "libfrr.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
b85120bc 992 vty_out (vty, "%s:%s", frr_protonameinst, VTY_NEWLINE);
fbf5d033 993
5510e83b 994 for (index = map->head; index; index = index->next)
995 {
996 vty_out (vty, "route-map %s, %s, sequence %d%s",
997 map->name, route_map_type_str (index->type),
998 index->pref, VTY_NEWLINE);
5bb4c198 999
1000 /* Description */
1001 if (index->description)
1002 vty_out (vty, " Description:%s %s%s", VTY_NEWLINE,
1003 index->description, VTY_NEWLINE);
5510e83b 1004
1005 /* Match clauses */
1006 vty_out (vty, " Match clauses:%s", VTY_NEWLINE);
1007 for (rule = index->match_list.head; rule; rule = rule->next)
1008 vty_out (vty, " %s %s%s",
1009 rule->cmd->str, rule->rule_str, VTY_NEWLINE);
1010
1011 vty_out (vty, " Set clauses:%s", VTY_NEWLINE);
1012 for (rule = index->set_list.head; rule; rule = rule->next)
1013 vty_out (vty, " %s %s%s",
1014 rule->cmd->str, rule->rule_str, VTY_NEWLINE);
1015
db29ae5f 1016 /* Call clause */
1017 vty_out (vty, " Call clause:%s", VTY_NEWLINE);
fee0f4c6 1018 if (index->nextrm)
1019 vty_out (vty, " Call %s%s", index->nextrm, VTY_NEWLINE);
db29ae5f 1020
1021 /* Exit Policy */
1022 vty_out (vty, " Action:%s", VTY_NEWLINE);
1023 if (index->exitpolicy == RMAP_GOTO)
5510e83b 1024 vty_out (vty, " Goto %d%s", index->nextpref, VTY_NEWLINE);
5510e83b 1025 else if (index->exitpolicy == RMAP_NEXT)
db29ae5f 1026 vty_out (vty, " Continue to next entry%s", VTY_NEWLINE);
5510e83b 1027 else if (index->exitpolicy == RMAP_EXIT)
1028 vty_out (vty, " Exit routemap%s", VTY_NEWLINE);
1029 }
718e3744 1030}
1031
8cc4198f 1032static int
9035efaa 1033vty_show_route_map (struct vty *vty, const char *name)
5510e83b 1034{
1035 struct route_map *map;
1036
1037 if (name)
1038 {
1039 map = route_map_lookup_by_name (name);
1040
1041 if (map)
1042 {
1043 vty_show_route_map_entry (vty, map);
1044 return CMD_SUCCESS;
1045 }
1046 else
1047 {
b85120bc
DL
1048 vty_out (vty, "%s: 'route-map %s' not found%s", frr_protonameinst,
1049 name, VTY_NEWLINE);
a6e0d253 1050 return CMD_SUCCESS;
5510e83b 1051 }
1052 }
7514fb77
PJ
1053 else
1054 {
1055 for (map = route_map_master.head; map; map = map->next)
518f0eb1
DS
1056 if (!map->deleted)
1057 vty_show_route_map_entry (vty, map);
7514fb77 1058 }
5510e83b 1059 return CMD_SUCCESS;
1060}
1061
1062
718e3744 1063/* New route map allocation. Please note route map's name must be
1064 specified. */
8cc4198f 1065static struct route_map_index *
1066route_map_index_new (void)
718e3744 1067{
1068 struct route_map_index *new;
1069
1070 new = XCALLOC (MTYPE_ROUTE_MAP_INDEX, sizeof (struct route_map_index));
1071 new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */
e80e7cce 1072 QOBJ_REG (new, route_map_index);
718e3744 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
e80e7cce
DL
1082 QOBJ_UNREG (index);
1083
718e3744 1084 /* Free route match. */
1085 while ((rule = index->match_list.head) != NULL)
1086 route_map_rule_delete (&index->match_list, rule);
1087
1088 /* Free route set. */
1089 while ((rule = index->set_list.head) != NULL)
1090 route_map_rule_delete (&index->set_list, rule);
1091
1092 /* Remove index from route map list. */
1093 if (index->next)
1094 index->next->prev = index->prev;
1095 else
1096 index->map->tail = index->prev;
1097
1098 if (index->prev)
1099 index->prev->next = index->next;
1100 else
1101 index->map->head = index->next;
1102
fee0f4c6 1103 /* Free 'char *nextrm' if not NULL */
1104 if (index->nextrm)
0241684e 1105 XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
fee0f4c6 1106
718e3744 1107 /* Execute event hook. */
1108 if (route_map_master.event_hook && notify)
518f0eb1
DS
1109 {
1110 (*route_map_master.event_hook) (RMAP_EVENT_INDEX_DELETED,
1111 index->map->name);
1112 route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
1113 }
718e3744 1114 XFREE (MTYPE_ROUTE_MAP_INDEX, index);
1115}
1116
1117/* Lookup index from route map. */
8cc4198f 1118static struct route_map_index *
718e3744 1119route_map_index_lookup (struct route_map *map, enum route_map_type type,
1120 int pref)
1121{
1122 struct route_map_index *index;
1123
1124 for (index = map->head; index; index = index->next)
1125 if ((index->type == type || type == RMAP_ANY)
1126 && index->pref == pref)
1127 return index;
1128 return NULL;
1129}
1130
1131/* Add new index to route map. */
8cc4198f 1132static struct route_map_index *
718e3744 1133route_map_index_add (struct route_map *map, enum route_map_type type,
1134 int pref)
1135{
1136 struct route_map_index *index;
1137 struct route_map_index *point;
1138
1139 /* Allocate new route map inex. */
1140 index = route_map_index_new ();
1141 index->map = map;
1142 index->type = type;
1143 index->pref = pref;
1144
1145 /* Compare preference. */
1146 for (point = map->head; point; point = point->next)
1147 if (point->pref >= pref)
1148 break;
1149
1150 if (map->head == NULL)
1151 {
1152 map->head = map->tail = index;
1153 }
1154 else if (point == NULL)
1155 {
1156 index->prev = map->tail;
1157 map->tail->next = index;
1158 map->tail = index;
1159 }
1160 else if (point == map->head)
1161 {
1162 index->next = map->head;
1163 map->head->prev = index;
1164 map->head = index;
1165 }
1166 else
1167 {
1168 index->next = point;
1169 index->prev = point->prev;
1170 if (point->prev)
1171 point->prev->next = index;
1172 point->prev = index;
1173 }
1174
1175 /* Execute event hook. */
1176 if (route_map_master.event_hook)
518f0eb1
DS
1177 {
1178 (*route_map_master.event_hook) (RMAP_EVENT_INDEX_ADDED,
1179 map->name);
1180 route_map_notify_dependencies (map->name, RMAP_EVENT_CALL_ADDED);
1181 }
718e3744 1182 return index;
1183}
1184
1185/* Get route map index. */
8cc4198f 1186static struct route_map_index *
718e3744 1187route_map_index_get (struct route_map *map, enum route_map_type type,
1188 int pref)
1189{
1190 struct route_map_index *index;
1191
1192 index = route_map_index_lookup (map, RMAP_ANY, pref);
1193 if (index && index->type != type)
1194 {
1195 /* Delete index from route map. */
1196 route_map_index_delete (index, 1);
1197 index = NULL;
1198 }
1199 if (index == NULL)
1200 index = route_map_index_add (map, type, pref);
1201 return index;
1202}
1203
1204/* New route map rule */
8cc4198f 1205static struct route_map_rule *
1206route_map_rule_new (void)
718e3744 1207{
1208 struct route_map_rule *new;
1209
1210 new = XCALLOC (MTYPE_ROUTE_MAP_RULE, sizeof (struct route_map_rule));
1211 return new;
1212}
6b0655a2 1213
718e3744 1214/* Install rule command to the match list. */
1215void
1216route_map_install_match (struct route_map_rule_cmd *cmd)
1217{
1218 vector_set (route_match_vec, cmd);
1219}
1220
1221/* Install rule command to the set list. */
1222void
1223route_map_install_set (struct route_map_rule_cmd *cmd)
1224{
1225 vector_set (route_set_vec, cmd);
1226}
1227
1228/* Lookup rule command from match list. */
8cc4198f 1229static struct route_map_rule_cmd *
27a43a81 1230route_map_lookup_match (const char *name)
718e3744 1231{
8c328f11 1232 unsigned int i;
718e3744 1233 struct route_map_rule_cmd *rule;
1234
55468c86 1235 for (i = 0; i < vector_active (route_match_vec); i++)
718e3744 1236 if ((rule = vector_slot (route_match_vec, i)) != NULL)
1237 if (strcmp (rule->str, name) == 0)
1238 return rule;
1239 return NULL;
1240}
1241
1242/* Lookup rule command from set list. */
8cc4198f 1243static struct route_map_rule_cmd *
27a43a81 1244route_map_lookup_set (const char *name)
718e3744 1245{
8c328f11 1246 unsigned int i;
718e3744 1247 struct route_map_rule_cmd *rule;
1248
55468c86 1249 for (i = 0; i < vector_active (route_set_vec); i++)
718e3744 1250 if ((rule = vector_slot (route_set_vec, i)) != NULL)
1251 if (strcmp (rule->str, name) == 0)
1252 return rule;
1253 return NULL;
1254}
1255
1256/* Add match and set rule to rule list. */
1257static void
1258route_map_rule_add (struct route_map_rule_list *list,
1259 struct route_map_rule *rule)
1260{
1261 rule->next = NULL;
1262 rule->prev = list->tail;
1263 if (list->tail)
1264 list->tail->next = rule;
1265 else
1266 list->head = rule;
1267 list->tail = rule;
1268}
1269
1270/* Delete rule from rule list. */
1271static void
1272route_map_rule_delete (struct route_map_rule_list *list,
1273 struct route_map_rule *rule)
1274{
1275 if (rule->cmd->func_free)
1276 (*rule->cmd->func_free) (rule->value);
1277
1278 if (rule->rule_str)
1279 XFREE (MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str);
1280
1281 if (rule->next)
1282 rule->next->prev = rule->prev;
1283 else
1284 list->tail = rule->prev;
1285 if (rule->prev)
1286 rule->prev->next = rule->next;
1287 else
1288 list->head = rule->next;
1289
1290 XFREE (MTYPE_ROUTE_MAP_RULE, rule);
1291}
1292
1293/* strcmp wrapper function which don't crush even argument is NULL. */
8cc4198f 1294static int
c9eca01b 1295rulecmp (const char *dst, const char *src)
718e3744 1296{
1297 if (dst == NULL)
1298 {
1299 if (src == NULL)
1300 return 0;
1301 else
1302 return 1;
1303 }
1304 else
1305 {
1306 if (src == NULL)
1307 return 1;
1308 else
1309 return strcmp (dst, src);
1310 }
1311 return 1;
1312}
1313
518f0eb1
DS
1314/* Use this to return the already specified argument for this match. This is
1315 * useful to get the specified argument with a route map match rule when the
1316 * rule is being deleted and the argument is not provided.
1317 */
1318const char *
1319route_map_get_match_arg(struct route_map_index *index, const char *match_name)
1320{
1321 struct route_map_rule *rule;
1322 struct route_map_rule_cmd *cmd;
1323
1324 /* First lookup rule for add match statement. */
1325 cmd = route_map_lookup_match (match_name);
1326 if (cmd == NULL)
1327 return NULL;
1328
1329 for (rule = index->match_list.head; rule; rule = rule->next)
1330 if (rule->cmd == cmd && rule->rule_str != NULL)
1331 return (rule->rule_str);
1332
1333 return (NULL);
1334}
1335
718e3744 1336/* Add match statement to route map. */
1337int
27a43a81 1338route_map_add_match (struct route_map_index *index, const char *match_name,
c9eca01b 1339 const char *match_arg)
718e3744 1340{
1341 struct route_map_rule *rule;
1342 struct route_map_rule *next;
1343 struct route_map_rule_cmd *cmd;
1344 void *compile;
1345 int replaced = 0;
1346
1347 /* First lookup rule for add match statement. */
1348 cmd = route_map_lookup_match (match_name);
1349 if (cmd == NULL)
1350 return RMAP_RULE_MISSING;
1351
1352 /* Next call compile function for this match statement. */
1353 if (cmd->func_compile)
1354 {
1355 compile= (*cmd->func_compile)(match_arg);
1356 if (compile == NULL)
1357 return RMAP_COMPILE_ERROR;
1358 }
1359 else
1360 compile = NULL;
1361
1362 /* If argument is completely same ignore it. */
1363 for (rule = index->match_list.head; rule; rule = next)
1364 {
1365 next = rule->next;
1366 if (rule->cmd == cmd)
1367 {
1368 route_map_rule_delete (&index->match_list, rule);
1369 replaced = 1;
1370 }
1371 }
1372
1373 /* Add new route map match rule. */
1374 rule = route_map_rule_new ();
1375 rule->cmd = cmd;
1376 rule->value = compile;
1377 if (match_arg)
1378 rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, match_arg);
1379 else
1380 rule->rule_str = NULL;
1381
1382 /* Add new route match rule to linked list. */
1383 route_map_rule_add (&index->match_list, rule);
1384
1385 /* Execute event hook. */
1386 if (route_map_master.event_hook)
518f0eb1
DS
1387 {
1388 (*route_map_master.event_hook) (replaced ?
1389 RMAP_EVENT_MATCH_REPLACED:
1390 RMAP_EVENT_MATCH_ADDED,
1391 index->map->name);
1392 route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
1393 }
718e3744 1394
1395 return 0;
1396}
1397
1398/* Delete specified route match rule. */
1399int
27a43a81 1400route_map_delete_match (struct route_map_index *index, const char *match_name,
c9eca01b 1401 const char *match_arg)
718e3744 1402{
1403 struct route_map_rule *rule;
1404 struct route_map_rule_cmd *cmd;
1405
1406 cmd = route_map_lookup_match (match_name);
1407 if (cmd == NULL)
1408 return 1;
1409
1410 for (rule = index->match_list.head; rule; rule = rule->next)
1411 if (rule->cmd == cmd &&
1412 (rulecmp (rule->rule_str, match_arg) == 0 || match_arg == NULL))
1413 {
1414 route_map_rule_delete (&index->match_list, rule);
1415 /* Execute event hook. */
1416 if (route_map_master.event_hook)
518f0eb1
DS
1417 {
1418 (*route_map_master.event_hook) (RMAP_EVENT_MATCH_DELETED,
1419 index->map->name);
1420 route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
1421 }
718e3744 1422 return 0;
1423 }
1424 /* Can't find matched rule. */
1425 return 1;
1426}
1427
1428/* Add route-map set statement to the route map. */
1429int
27a43a81 1430route_map_add_set (struct route_map_index *index, const char *set_name,
c9eca01b 1431 const char *set_arg)
718e3744 1432{
1433 struct route_map_rule *rule;
1434 struct route_map_rule *next;
1435 struct route_map_rule_cmd *cmd;
1436 void *compile;
1437 int replaced = 0;
1438
1439 cmd = route_map_lookup_set (set_name);
1440 if (cmd == NULL)
1441 return RMAP_RULE_MISSING;
1442
1443 /* Next call compile function for this match statement. */
1444 if (cmd->func_compile)
1445 {
1446 compile= (*cmd->func_compile)(set_arg);
1447 if (compile == NULL)
1448 return RMAP_COMPILE_ERROR;
1449 }
1450 else
1451 compile = NULL;
1452
1453 /* Add by WJL. if old set command of same kind exist, delete it first
1454 to ensure only one set command of same kind exist under a
1455 route_map_index. */
1456 for (rule = index->set_list.head; rule; rule = next)
1457 {
1458 next = rule->next;
1459 if (rule->cmd == cmd)
1460 {
1461 route_map_rule_delete (&index->set_list, rule);
1462 replaced = 1;
1463 }
1464 }
1465
1466 /* Add new route map match rule. */
1467 rule = route_map_rule_new ();
1468 rule->cmd = cmd;
1469 rule->value = compile;
1470 if (set_arg)
1471 rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, set_arg);
1472 else
1473 rule->rule_str = NULL;
1474
1475 /* Add new route match rule to linked list. */
1476 route_map_rule_add (&index->set_list, rule);
1477
1478 /* Execute event hook. */
1479 if (route_map_master.event_hook)
518f0eb1
DS
1480 {
1481 (*route_map_master.event_hook) (replaced ?
1482 RMAP_EVENT_SET_REPLACED:
1483 RMAP_EVENT_SET_ADDED,
1484 index->map->name);
1485 route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
1486 }
718e3744 1487 return 0;
1488}
1489
1490/* Delete route map set rule. */
1491int
27a43a81 1492route_map_delete_set (struct route_map_index *index, const char *set_name,
c9eca01b 1493 const char *set_arg)
718e3744 1494{
1495 struct route_map_rule *rule;
1496 struct route_map_rule_cmd *cmd;
1497
1498 cmd = route_map_lookup_set (set_name);
1499 if (cmd == NULL)
1500 return 1;
1501
1502 for (rule = index->set_list.head; rule; rule = rule->next)
1503 if ((rule->cmd == cmd) &&
1504 (rulecmp (rule->rule_str, set_arg) == 0 || set_arg == NULL))
1505 {
1506 route_map_rule_delete (&index->set_list, rule);
1507 /* Execute event hook. */
1508 if (route_map_master.event_hook)
518f0eb1
DS
1509 {
1510 (*route_map_master.event_hook) (RMAP_EVENT_SET_DELETED,
1511 index->map->name);
1512 route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
1513 }
718e3744 1514 return 0;
1515 }
1516 /* Can't find matched rule. */
1517 return 1;
1518}
1519
3bf1c917 1520/* Apply route map's each index to the object.
1521
1522 The matrix for a route-map looks like this:
1523 (note, this includes the description for the "NEXT"
1524 and "GOTO" frobs now
1525
1526 Match | No Match
1527 |
1528 permit action | cont
1529 |
1530 ------------------+---------------
1531 |
1532 deny deny | cont
1533 |
1534
fee0f4c6 1535 action)
1536 -Apply Set statements, accept route
1537 -If Call statement is present jump to the specified route-map, if it
1538 denies the route we finish.
1539 -If NEXT is specified, goto NEXT statement
1540 -If GOTO is specified, goto the first clause where pref > nextpref
1541 -If nothing is specified, do as Cisco and finish
1542 deny)
1543 -Route is denied by route-map.
1544 cont)
1545 -Goto Next index
3bf1c917 1546
1547 If we get no matches after we've processed all updates, then the route
1548 is dropped too.
1549
fee0f4c6 1550 Some notes on the new "CALL", "NEXT" and "GOTO"
1551 call WORD - If this clause is matched, then the set statements
1552 are executed and then we jump to route-map 'WORD'. If
1553 this route-map denies the route, we finish, in other case we
1554 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
3bf1c917 1555 on-match next - If this clause is matched, then the set statements
1556 are executed and then we drop through to the next clause
1557 on-match goto n - If this clause is matched, then the set statments
1558 are executed and then we goto the nth clause, or the
1559 first clause greater than this. In order to ensure
1560 route-maps *always* exit, you cannot jump backwards.
1561 Sorry ;)
1562
1563 We need to make sure our route-map processing matches the above
718e3744 1564*/
3bf1c917 1565
8cc4198f 1566static route_map_result_t
3bf1c917 1567route_map_apply_match (struct route_map_rule_list *match_list,
1568 struct prefix *prefix, route_map_object_t type,
1569 void *object)
718e3744 1570{
3bf1c917 1571 route_map_result_t ret = RMAP_NOMATCH;
718e3744 1572 struct route_map_rule *match;
718e3744 1573
718e3744 1574
3bf1c917 1575 /* Check all match rule and if there is no match rule, go to the
1576 set statement. */
1577 if (!match_list->head)
1578 ret = RMAP_MATCH;
1579 else
718e3744 1580 {
3bf1c917 1581 for (match = match_list->head; match; match = match->next)
1582 {
1583 /* Try each match statement in turn, If any do not return
1584 RMAP_MATCH, return, otherwise continue on to next match
1585 statement. All match statements must match for end-result
1586 to be a match. */
1587 ret = (*match->cmd->func_apply) (match->value, prefix,
1588 type, object);
1589 if (ret != RMAP_MATCH)
1590 return ret;
1591 }
718e3744 1592 }
3bf1c917 1593 return ret;
718e3744 1594}
1595
1596/* Apply route map to the object. */
1597route_map_result_t
3bf1c917 1598route_map_apply (struct route_map *map, struct prefix *prefix,
1599 route_map_object_t type, void *object)
718e3744 1600{
fee0f4c6 1601 static int recursion = 0;
718e3744 1602 int ret = 0;
1603 struct route_map_index *index;
3bf1c917 1604 struct route_map_rule *set;
718e3744 1605
fee0f4c6 1606 if (recursion > RMAP_RECURSION_LIMIT)
1607 {
4525281a
DL
1608 zlog_warn("route-map recursion limit (%d) reached, discarding route",
1609 RMAP_RECURSION_LIMIT);
fee0f4c6 1610 recursion = 0;
1611 return RMAP_DENYMATCH;
1612 }
1613
718e3744 1614 if (map == NULL)
1615 return RMAP_DENYMATCH;
1616
1617 for (index = map->head; index; index = index->next)
1618 {
3bf1c917 1619 /* Apply this index. */
1620 ret = route_map_apply_match (&index->match_list, prefix, type, object);
1621
1622 /* Now we apply the matrix from above */
1623 if (ret == RMAP_NOMATCH)
1624 /* 'cont' from matrix - continue to next route-map sequence */
1625 continue;
1626 else if (ret == RMAP_MATCH)
1627 {
1628 if (index->type == RMAP_PERMIT)
1629 /* 'action' */
1630 {
1631 /* permit+match must execute sets */
1632 for (set = index->set_list.head; set; set = set->next)
1633 ret = (*set->cmd->func_apply) (set->value, prefix,
1634 type, object);
fee0f4c6 1635
1636 /* Call another route-map if available */
1637 if (index->nextrm)
1638 {
1639 struct route_map *nextrm =
1640 route_map_lookup_by_name (index->nextrm);
1641
1642 if (nextrm) /* Target route-map found, jump to it */
1643 {
1644 recursion++;
1645 ret = route_map_apply (nextrm, prefix, type, object);
1646 recursion--;
1647 }
1648
1649 /* If nextrm returned 'deny', finish. */
1650 if (ret == RMAP_DENYMATCH)
1651 return ret;
1652 }
1653
3bf1c917 1654 switch (index->exitpolicy)
1655 {
1656 case RMAP_EXIT:
1657 return ret;
1658 case RMAP_NEXT:
1659 continue;
1660 case RMAP_GOTO:
1661 {
1662 /* Find the next clause to jump to */
1663 struct route_map_index *next = index->next;
fee0f4c6 1664 int nextpref = index->nextpref;
3bf1c917 1665
fee0f4c6 1666 while (next && next->pref < nextpref)
3bf1c917 1667 {
1668 index = next;
1669 next = next->next;
1670 }
1671 if (next == NULL)
1672 {
1673 /* No clauses match! */
1674 return ret;
1675 }
1676 }
1677 }
1678 }
1679 else if (index->type == RMAP_DENY)
1680 /* 'deny' */
1681 {
3bf1c917 1682 return RMAP_DENYMATCH;
1683 }
1684 }
718e3744 1685 }
1686 /* Finally route-map does not match at all. */
1687 return RMAP_DENYMATCH;
1688}
1689
1690void
9035efaa 1691route_map_add_hook (void (*func) (const char *))
718e3744 1692{
1693 route_map_master.add_hook = func;
1694}
1695
1696void
9035efaa 1697route_map_delete_hook (void (*func) (const char *))
718e3744 1698{
1699 route_map_master.delete_hook = func;
1700}
1701
1702void
9035efaa 1703route_map_event_hook (void (*func) (route_map_event_t, const char *))
718e3744 1704{
1705 route_map_master.event_hook = func;
1706}
1707
518f0eb1
DS
1708/* Routines for route map dependency lists and dependency processing */
1709static int
1710route_map_rmap_hash_cmp (const void *p1, const void *p2)
1711{
24873f0c 1712 return (strcmp((const char *)p1, (const char *)p2) == 0);
518f0eb1
DS
1713}
1714
1715static int
1716route_map_dep_hash_cmp (const void *p1, const void *p2)
1717{
1718
24873f0c 1719 return (strcmp (((const struct route_map_dep *)p1)->dep_name, (const char *)p2) == 0);
518f0eb1
DS
1720}
1721
1722static void
1723route_map_clear_reference(struct hash_backet *backet, void *arg)
1724{
1725 struct route_map_dep *dep = (struct route_map_dep *)backet->data;
1726 char *rmap_name;
1727
1728 if (dep && arg)
1729 {
1730 rmap_name = (char *)hash_release(dep->dep_rmap_hash, (void *)arg);
1731 if (rmap_name)
1732 {
1733 XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
1734 }
1735 if (!dep->dep_rmap_hash->count)
1736 {
1737 dep = hash_release(dep->this_hash, (void *)dep->dep_name);
1738 hash_free(dep->dep_rmap_hash);
1739 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
1740 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
1741 }
1742 }
1743}
1744
1745static void
1746route_map_clear_all_references (char *rmap_name)
1747{
1748 int i;
1749
1750 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
1751 {
1752 hash_iterate(route_map_dep_hash[i], route_map_clear_reference,
1753 (void *)rmap_name);
1754 }
1755}
1756
1757static void *
1758route_map_dep_hash_alloc(void *p)
1759{
1760 char *dep_name = (char *)p;
1761 struct route_map_dep *dep_entry;
1762
1763 dep_entry = XCALLOC(MTYPE_ROUTE_MAP_DEP, sizeof(struct route_map_dep));
1764 dep_entry->dep_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
1765 dep_entry->dep_rmap_hash = hash_create(route_map_dep_hash_make_key,
1766 route_map_rmap_hash_cmp);
1767 dep_entry->this_hash = NULL;
1768
1769 return((void *)dep_entry);
1770}
1771
1772static void *
1773route_map_name_hash_alloc(void *p)
1774{
24873f0c 1775 return((void *)XSTRDUP(MTYPE_ROUTE_MAP_NAME, (const char *)p));
518f0eb1
DS
1776}
1777
1778static unsigned int
1779route_map_dep_hash_make_key (void *p)
1780{
1781 return (string_hash_make((char *)p));
1782}
1783
1784static void
1785route_map_print_dependency (struct hash_backet *backet, void *data)
1786{
1787 char *rmap_name = (char *)backet->data;
1788 char *dep_name = (char *)data;
1789
1790 if (rmap_name)
1791 zlog_debug("%s: Dependency for %s: %s", __FUNCTION__, dep_name, rmap_name);
1792}
1793
1794static int
1795route_map_dep_update (struct hash *dephash, const char *dep_name,
1796 const char *rmap_name,
1797 route_map_event_t type)
1798{
cd657e23 1799 struct route_map_dep *dep = NULL;
518f0eb1 1800 char *ret_map_name;
24873f0c
DS
1801 char *dname, *rname;
1802 int ret = 0;
1803
1804 dname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
1805 rname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_name);
518f0eb1
DS
1806
1807 switch (type)
1808 {
1809 case RMAP_EVENT_PLIST_ADDED:
1810 case RMAP_EVENT_CLIST_ADDED:
1811 case RMAP_EVENT_ECLIST_ADDED:
1812 case RMAP_EVENT_ASLIST_ADDED:
57d187bc 1813 case RMAP_EVENT_LLIST_ADDED:
518f0eb1
DS
1814 case RMAP_EVENT_CALL_ADDED:
1815 case RMAP_EVENT_FILTER_ADDED:
1816 if (rmap_debug)
1817 zlog_debug("%s: Adding dependency for %s in %s", __FUNCTION__,
1818 dep_name, rmap_name);
24873f0c 1819 dep = (struct route_map_dep *) hash_get (dephash, dname,
518f0eb1 1820 route_map_dep_hash_alloc);
24873f0c
DS
1821 if (!dep) {
1822 ret = -1;
1823 goto out;
1824 }
518f0eb1
DS
1825
1826 if (!dep->this_hash)
1827 dep->this_hash = dephash;
1828
24873f0c 1829 hash_get(dep->dep_rmap_hash, rname, route_map_name_hash_alloc);
518f0eb1
DS
1830 break;
1831 case RMAP_EVENT_PLIST_DELETED:
1832 case RMAP_EVENT_CLIST_DELETED:
1833 case RMAP_EVENT_ECLIST_DELETED:
1834 case RMAP_EVENT_ASLIST_DELETED:
57d187bc 1835 case RMAP_EVENT_LLIST_DELETED:
518f0eb1
DS
1836 case RMAP_EVENT_CALL_DELETED:
1837 case RMAP_EVENT_FILTER_DELETED:
1838 if (rmap_debug)
1839 zlog_debug("%s: Deleting dependency for %s in %s", __FUNCTION__,
1840 dep_name, rmap_name);
24873f0c
DS
1841 dep = (struct route_map_dep *) hash_get (dephash, dname, NULL);
1842 if (!dep) {
1843 goto out;
1844 }
1845
1846 ret_map_name = (char *)hash_release(dep->dep_rmap_hash, rname);
518f0eb1
DS
1847 if (ret_map_name)
1848 XFREE(MTYPE_ROUTE_MAP_NAME, ret_map_name);
1849
1850 if (!dep->dep_rmap_hash->count)
1851 {
24873f0c 1852 dep = hash_release(dephash, dname);
518f0eb1
DS
1853 hash_free(dep->dep_rmap_hash);
1854 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
1855 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
1856 dep = NULL;
1857 }
1858 break;
1859 default:
1860 break;
1861 }
1862
1863 if (dep)
1864 {
1865 if (rmap_debug)
24873f0c 1866 hash_iterate (dep->dep_rmap_hash, route_map_print_dependency, dname);
518f0eb1 1867 }
24873f0c
DS
1868
1869 out:
1870 XFREE(MTYPE_ROUTE_MAP_NAME, rname);
1871 XFREE(MTYPE_ROUTE_MAP_NAME, dname);
1872 return ret;
518f0eb1
DS
1873}
1874
1875static struct hash *
1876route_map_get_dep_hash (route_map_event_t event)
1877{
1878 struct hash *upd8_hash = NULL;
1879
1880 switch (event)
1881 {
1882 case RMAP_EVENT_PLIST_ADDED:
1883 case RMAP_EVENT_PLIST_DELETED:
1884 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_PLIST];
1885 break;
1886 case RMAP_EVENT_CLIST_ADDED:
1887 case RMAP_EVENT_CLIST_DELETED:
1888 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_CLIST];
1889 break;
1890 case RMAP_EVENT_ECLIST_ADDED:
1891 case RMAP_EVENT_ECLIST_DELETED:
1892 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ECLIST];
1893 break;
1894 case RMAP_EVENT_ASLIST_ADDED:
1895 case RMAP_EVENT_ASLIST_DELETED:
1896 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ASPATH];
1897 break;
57d187bc
JS
1898 case RMAP_EVENT_LLIST_ADDED:
1899 case RMAP_EVENT_LLIST_DELETED:
1900 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_LCLIST];
1901 break;
518f0eb1
DS
1902 case RMAP_EVENT_CALL_ADDED:
1903 case RMAP_EVENT_CALL_DELETED:
1904 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_RMAP];
1905 break;
1906 case RMAP_EVENT_FILTER_ADDED:
1907 case RMAP_EVENT_FILTER_DELETED:
1908 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_FILTER];
1909 break;
1910 default:
1911 upd8_hash = NULL;
1912 break;
1913 }
1914 return (upd8_hash);
1915}
1916
1917static void
1918route_map_process_dependency (struct hash_backet *backet, void *data)
1919{
1920 char *rmap_name;
01673c68 1921 route_map_event_t type = (route_map_event_t)(ptrdiff_t)data;
518f0eb1
DS
1922
1923 rmap_name = (char *)backet->data;
1924
1925 if (rmap_name)
1926 {
1927 if (rmap_debug)
1928 zlog_debug("%s: Notifying %s of dependency", __FUNCTION__,
1929 rmap_name);
1930 if (route_map_master.event_hook)
1931 (*route_map_master.event_hook) (type, rmap_name);
1932 }
1933}
1934
1935void
1936route_map_upd8_dependency (route_map_event_t type, const char *arg,
1937 const char *rmap_name)
1938{
1939 struct hash *upd8_hash = NULL;
1940
1941 if ((upd8_hash = route_map_get_dep_hash(type)))
1942 route_map_dep_update (upd8_hash, arg, rmap_name, type);
1943}
1944
1945void
1946route_map_notify_dependencies (const char *affected_name, route_map_event_t event)
1947{
1948 struct route_map_dep *dep;
1949 struct hash *upd8_hash;
24873f0c 1950 char *name;
518f0eb1
DS
1951
1952 if (!affected_name)
1953 return;
1954
24873f0c
DS
1955 name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, affected_name);
1956
518f0eb1 1957 if ((upd8_hash = route_map_get_dep_hash(event)) == NULL)
262e75b1
DV
1958 {
1959 XFREE (MTYPE_ROUTE_MAP_NAME, name);
1960 return;
1961 }
518f0eb1 1962
24873f0c 1963 dep = (struct route_map_dep *)hash_get (upd8_hash, name,
518f0eb1
DS
1964 NULL);
1965 if (dep)
1966 {
1967 if (!dep->this_hash)
1968 dep->this_hash = upd8_hash;
1969
1970 hash_iterate (dep->dep_rmap_hash, route_map_process_dependency, (void *)event);
1971 }
24873f0c
DS
1972
1973 XFREE (MTYPE_ROUTE_MAP_NAME, name);
518f0eb1
DS
1974}
1975
82f97584 1976
718e3744 1977/* VTY related functions. */
82f97584
DW
1978DEFUN (match_interface,
1979 match_interface_cmd,
1980 "match interface WORD",
1981 MATCH_STR
1982 "match first hop interface of route\n"
1983 "Interface name\n")
1984{
1985 int idx_word = 2;
e52702f2 1986 VTY_DECLVAR_CONTEXT (route_map_index, index);
82f97584
DW
1987
1988 if (rmap_match_set_hook.match_interface)
e52702f2 1989 return rmap_match_set_hook.match_interface (vty, index, "interface", argv[idx_word]->arg, RMAP_EVENT_MATCH_ADDED);
82f97584
DW
1990 return CMD_SUCCESS;
1991}
1992
1993DEFUN (no_match_interface,
1994 no_match_interface_cmd,
70d44c5c 1995 "no match interface [WORD]",
82f97584
DW
1996 NO_STR
1997 MATCH_STR
1998 "Match first hop interface of route\n"
1999 "Interface name\n")
2000{
2001 char *iface = (argc == 4) ? argv[3]->arg : NULL;
e52702f2 2002 VTY_DECLVAR_CONTEXT (route_map_index, index);
82f97584
DW
2003
2004 if (rmap_match_set_hook.no_match_interface)
e52702f2 2005 return rmap_match_set_hook.no_match_interface (vty, index, "interface", iface, RMAP_EVENT_MATCH_DELETED);
82f97584
DW
2006 return CMD_SUCCESS;
2007}
2008
2009
2010DEFUN (match_ip_address,
2011 match_ip_address_cmd,
2012 "match ip address <(1-199)|(1300-2699)|WORD>",
2013 MATCH_STR
2014 IP_STR
2015 "Match address of route\n"
2016 "IP access-list number\n"
2017 "IP access-list number (expanded range)\n"
2018 "IP Access-list name\n")
2019{
2020 int idx_acl = 3;
e52702f2 2021 VTY_DECLVAR_CONTEXT (route_map_index, index);
82f97584
DW
2022
2023 if (rmap_match_set_hook.match_ip_address)
e52702f2 2024 return rmap_match_set_hook.match_ip_address (vty, index, "ip address", argv[idx_acl]->arg,
82f97584
DW
2025 RMAP_EVENT_FILTER_ADDED);
2026 return CMD_SUCCESS;
2027}
2028
2029
2030DEFUN (no_match_ip_address,
2031 no_match_ip_address_cmd,
2032 "no match ip address [<(1-199)|(1300-2699)|WORD>]",
2033 NO_STR
2034 MATCH_STR
2035 IP_STR
2036 "Match address of route\n"
2037 "IP access-list number\n"
2038 "IP access-list number (expanded range)\n"
2039 "IP Access-list name\n")
2040{
2041 int idx_word = 4;
e52702f2 2042 VTY_DECLVAR_CONTEXT (route_map_index, index);
82f97584
DW
2043
2044 if (rmap_match_set_hook.no_match_ip_address)
2045 {
2046 if (argc <= idx_word)
e52702f2 2047 return rmap_match_set_hook.no_match_ip_address (vty, index, "ip address", NULL,
82f97584 2048 RMAP_EVENT_FILTER_DELETED);
e52702f2 2049 return rmap_match_set_hook.no_match_ip_address (vty, index, "ip address", argv[idx_word]->arg,
82f97584
DW
2050 RMAP_EVENT_FILTER_DELETED);
2051 }
2052 return CMD_SUCCESS;
2053}
2054
2055
2056DEFUN (match_ip_address_prefix_list,
2057 match_ip_address_prefix_list_cmd,
2058 "match ip address prefix-list WORD",
2059 MATCH_STR
2060 IP_STR
2061 "Match address of route\n"
2062 "Match entries of prefix-lists\n"
2063 "IP prefix-list name\n")
2064{
2065 int idx_word = 4;
e52702f2
QY
2066 VTY_DECLVAR_CONTEXT (route_map_index, index);
2067
82f97584 2068 if (rmap_match_set_hook.match_ip_address_prefix_list)
e52702f2 2069 return rmap_match_set_hook.match_ip_address_prefix_list (vty, index, "ip address prefix-list",
82f97584
DW
2070 argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
2071 return CMD_SUCCESS;
2072}
2073
2074
2075DEFUN (no_match_ip_address_prefix_list,
2076 no_match_ip_address_prefix_list_cmd,
2077 "no match ip address prefix-list [WORD]",
2078 NO_STR
2079 MATCH_STR
2080 IP_STR
2081 "Match address of route\n"
2082 "Match entries of prefix-lists\n"
2083 "IP prefix-list name\n")
2084{
2085 int idx_word = 5;
e52702f2 2086 VTY_DECLVAR_CONTEXT (route_map_index, index);
82f97584
DW
2087
2088 if (rmap_match_set_hook.no_match_ip_address_prefix_list)
2089 {
2090 if (argc <= idx_word)
e52702f2 2091 return rmap_match_set_hook.no_match_ip_address_prefix_list (vty, index, "ip address prefix-list",
82f97584 2092 NULL, RMAP_EVENT_PLIST_DELETED);
e52702f2 2093 return rmap_match_set_hook.no_match_ip_address_prefix_list(vty, index, "ip address prefix-list",
82f97584
DW
2094 argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
2095 }
2096 return CMD_SUCCESS;
2097}
2098
2099
2100DEFUN (match_ip_next_hop,
2101 match_ip_next_hop_cmd,
2102 "match ip next-hop <(1-199)|(1300-2699)|WORD>",
2103 MATCH_STR
2104 IP_STR
2105 "Match next-hop address of route\n"
2106 "IP access-list number\n"
2107 "IP access-list number (expanded range)\n"
2108 "IP Access-list name\n")
2109{
2110 int idx_acl = 3;
e52702f2
QY
2111 VTY_DECLVAR_CONTEXT (route_map_index, index);
2112
82f97584 2113 if (rmap_match_set_hook.match_ip_next_hop)
e52702f2 2114 return rmap_match_set_hook.match_ip_next_hop (vty, index, "ip next-hop", argv[idx_acl]->arg,
82f97584
DW
2115 RMAP_EVENT_FILTER_ADDED);
2116 return CMD_SUCCESS;
2117}
2118
2119
2120DEFUN (no_match_ip_next_hop,
2121 no_match_ip_next_hop_cmd,
2122 "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
2123 NO_STR
2124 MATCH_STR
2125 IP_STR
2126 "Match next-hop address of route\n"
2127 "IP access-list number\n"
2128 "IP access-list number (expanded range)\n"
2129 "IP Access-list name\n")
2130{
e52702f2
QY
2131 int idx_word = 4;
2132 VTY_DECLVAR_CONTEXT (route_map_index, index);
82f97584
DW
2133
2134 if (rmap_match_set_hook.no_match_ip_next_hop)
2135 {
2136 if (argc <= idx_word)
e52702f2 2137 return rmap_match_set_hook.no_match_ip_next_hop (vty, index, "ip next-hop", NULL,
82f97584 2138 RMAP_EVENT_FILTER_DELETED);
e52702f2 2139 return rmap_match_set_hook.no_match_ip_next_hop (vty, index, "ip next-hop", argv[idx_word]->arg,
82f97584
DW
2140 RMAP_EVENT_FILTER_DELETED);
2141 }
2142 return CMD_SUCCESS;
2143}
2144
2145
2146DEFUN (match_ip_next_hop_prefix_list,
2147 match_ip_next_hop_prefix_list_cmd,
2148 "match ip next-hop prefix-list WORD",
2149 MATCH_STR
2150 IP_STR
2151 "Match next-hop address of route\n"
2152 "Match entries of prefix-lists\n"
2153 "IP prefix-list name\n")
2154{
2155 int idx_word = 4;
e52702f2
QY
2156 VTY_DECLVAR_CONTEXT (route_map_index, index);
2157
82f97584 2158 if (rmap_match_set_hook.match_ip_next_hop_prefix_list)
e52702f2 2159 return rmap_match_set_hook.match_ip_next_hop_prefix_list (vty, index, "ip next-hop prefix-list",
82f97584
DW
2160 argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
2161 return CMD_SUCCESS;
2162}
2163
2164DEFUN (no_match_ip_next_hop_prefix_list,
2165 no_match_ip_next_hop_prefix_list_cmd,
2166 "no match ip next-hop prefix-list [WORD]",
2167 NO_STR
2168 MATCH_STR
2169 IP_STR
2170 "Match next-hop address of route\n"
2171 "Match entries of prefix-lists\n"
2172 "IP prefix-list name\n")
2173{
2174 int idx_word = 5;
e52702f2 2175 VTY_DECLVAR_CONTEXT (route_map_index, index);
82f97584
DW
2176
2177 if (rmap_match_set_hook.no_match_ip_next_hop)
2178 {
2179 if (argc <= idx_word)
e52702f2 2180 return rmap_match_set_hook.no_match_ip_next_hop (vty, index, "ip next-hop prefix-list",
82f97584 2181 NULL, RMAP_EVENT_PLIST_DELETED);
e52702f2 2182 return rmap_match_set_hook.no_match_ip_next_hop (vty, index, "ip next-hop prefix-list",
82f97584
DW
2183 argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
2184 }
2185 return CMD_SUCCESS;
2186}
2187
2188
2189DEFUN (match_ipv6_address,
2190 match_ipv6_address_cmd,
2191 "match ipv6 address WORD",
2192 MATCH_STR
2193 IPV6_STR
2194 "Match IPv6 address of route\n"
2195 "IPv6 access-list name\n")
2196{
2197 int idx_word = 3;
e52702f2
QY
2198 VTY_DECLVAR_CONTEXT (route_map_index, index);
2199
82f97584 2200 if (rmap_match_set_hook.match_ipv6_address)
e52702f2 2201 return rmap_match_set_hook.match_ipv6_address (vty, index, "ipv6 address", argv[idx_word]->arg,
82f97584
DW
2202 RMAP_EVENT_FILTER_ADDED);
2203 return CMD_SUCCESS;
2204}
2205
2206DEFUN (no_match_ipv6_address,
2207 no_match_ipv6_address_cmd,
2208 "no match ipv6 address WORD",
2209 NO_STR
2210 MATCH_STR
2211 IPV6_STR
2212 "Match IPv6 address of route\n"
2213 "IPv6 access-list name\n")
2214{
2215 int idx_word = 4;
e52702f2
QY
2216 VTY_DECLVAR_CONTEXT (route_map_index, index);
2217
82f97584 2218 if (rmap_match_set_hook.no_match_ipv6_address)
e52702f2 2219 return rmap_match_set_hook.no_match_ipv6_address (vty, index, "ipv6 address", argv[idx_word]->arg,
82f97584
DW
2220 RMAP_EVENT_FILTER_DELETED);
2221 return CMD_SUCCESS;
2222}
2223
2224
2225DEFUN (match_ipv6_address_prefix_list,
2226 match_ipv6_address_prefix_list_cmd,
2227 "match ipv6 address prefix-list WORD",
2228 MATCH_STR
2229 IPV6_STR
2230 "Match address of route\n"
2231 "Match entries of prefix-lists\n"
2232 "IP prefix-list name\n")
2233{
2234 int idx_word = 4;
e52702f2
QY
2235 VTY_DECLVAR_CONTEXT (route_map_index, index);
2236
82f97584 2237 if (rmap_match_set_hook.match_ipv6_address_prefix_list)
e52702f2 2238 return rmap_match_set_hook.match_ipv6_address_prefix_list (vty, index, "ipv6 address prefix-list",
82f97584
DW
2239 argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
2240 return CMD_SUCCESS;
2241}
2242
2243DEFUN (no_match_ipv6_address_prefix_list,
2244 no_match_ipv6_address_prefix_list_cmd,
2245 "no match ipv6 address prefix-list WORD",
2246 NO_STR
2247 MATCH_STR
2248 IPV6_STR
2249 "Match address of route\n"
2250 "Match entries of prefix-lists\n"
2251 "IP prefix-list name\n")
2252{
2253 int idx_word = 5;
e52702f2
QY
2254 VTY_DECLVAR_CONTEXT (route_map_index, index);
2255
82f97584 2256 if (rmap_match_set_hook.no_match_ipv6_address_prefix_list)
e52702f2 2257 return rmap_match_set_hook.no_match_ipv6_address_prefix_list(vty, index, "ipv6 address prefix-list",
82f97584
DW
2258 argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
2259 return CMD_SUCCESS;
2260}
2261
2262
2263DEFUN (match_metric,
2264 match_metric_cmd,
2265 "match metric (0-4294967295)",
2266 MATCH_STR
2267 "Match metric of route\n"
2268 "Metric value\n")
2269{
2270 int idx_number = 2;
e52702f2
QY
2271 VTY_DECLVAR_CONTEXT (route_map_index, index);
2272
82f97584 2273 if (rmap_match_set_hook.match_metric)
e52702f2 2274 return rmap_match_set_hook.match_metric(vty, index, "metric", argv[idx_number]->arg,
82f97584
DW
2275 RMAP_EVENT_MATCH_ADDED);
2276 return CMD_SUCCESS;
2277}
2278
2279
2280DEFUN (no_match_metric,
2281 no_match_metric_cmd,
2282 "no match metric [(0-4294967295)]",
2283 NO_STR
2284 MATCH_STR
2285 "Match metric of route\n"
2286 "Metric value\n")
2287{
2288 int idx_number = 3;
e52702f2
QY
2289 VTY_DECLVAR_CONTEXT (route_map_index, index);
2290
82f97584
DW
2291 if (rmap_match_set_hook.no_match_metric)
2292 {
2293 if (argc <= idx_number)
e52702f2 2294 return rmap_match_set_hook.no_match_metric (vty, index, "metric",
82f97584 2295 NULL, RMAP_EVENT_MATCH_DELETED);
fa6d4efe
DS
2296 return rmap_match_set_hook.no_match_metric(vty, index, "metric",
2297 argv[idx_number]->arg,
2298 RMAP_EVENT_MATCH_DELETED);
82f97584
DW
2299 }
2300 return CMD_SUCCESS;
2301}
2302
2303
2304DEFUN (match_tag,
2305 match_tag_cmd,
e52702f2 2306 "match tag (1-4294967295)",
82f97584
DW
2307 MATCH_STR
2308 "Match tag of route\n"
2309 "Tag value\n")
2310{
2311 int idx_number = 2;
e52702f2
QY
2312 VTY_DECLVAR_CONTEXT (route_map_index, index);
2313
82f97584 2314 if (rmap_match_set_hook.match_tag)
e52702f2 2315 return rmap_match_set_hook.match_tag(vty, index, "tag", argv[idx_number]->arg,
82f97584
DW
2316 RMAP_EVENT_MATCH_ADDED);
2317 return CMD_SUCCESS;
2318}
2319
2320
2321DEFUN (no_match_tag,
2322 no_match_tag_cmd,
e52702f2 2323 "no match tag [(1-4294967295)]",
82f97584
DW
2324 NO_STR
2325 MATCH_STR
2326 "Match tag of route\n"
2327 "Tag value\n")
2328{
e52702f2
QY
2329 VTY_DECLVAR_CONTEXT (route_map_index, index);
2330
0d702986
QY
2331 int idx = 0;
2332 char *arg = argv_find (argv, argc, "(1-4294967295)", &idx) ?
2333 argv[idx]->arg : NULL;
2334
82f97584 2335 if (rmap_match_set_hook.no_match_tag)
0d702986 2336 return rmap_match_set_hook.no_match_tag (vty, index, "tag", arg,
82f97584
DW
2337 RMAP_EVENT_MATCH_DELETED);
2338 return CMD_SUCCESS;
2339}
2340
2341
2342DEFUN (set_ip_nexthop,
2343 set_ip_nexthop_cmd,
2344 "set ip next-hop A.B.C.D",
2345 SET_STR
2346 IP_STR
2347 "Next hop address\n"
2348 "IP address of next hop\n")
2349{
2350 int idx_ipv4 = 3;
2351 union sockunion su;
2352 int ret;
e52702f2 2353 VTY_DECLVAR_CONTEXT (route_map_index, index);
82f97584
DW
2354
2355 ret = str2sockunion (argv[idx_ipv4]->arg, &su);
2356 if (ret < 0)
2357 {
2358 vty_out (vty, "%% Malformed nexthop address%s", VTY_NEWLINE);
2359 return CMD_WARNING;
2360 }
2361 if (su.sin.sin_addr.s_addr == 0 ||
2362 IPV4_CLASS_DE(su.sin.sin_addr.s_addr))
2363 {
2364 vty_out (vty, "%% nexthop address cannot be 0.0.0.0, multicast "
2365 "or reserved%s", VTY_NEWLINE);
2366 return CMD_WARNING;
2367 }
2368
2369 if (rmap_match_set_hook.set_ip_nexthop)
e52702f2 2370 return rmap_match_set_hook.set_ip_nexthop(vty, index, "ip next-hop", argv[idx_ipv4]->arg);
82f97584
DW
2371 return CMD_SUCCESS;
2372}
2373
2374
2375DEFUN (no_set_ip_nexthop,
2376 no_set_ip_nexthop_cmd,
2377 "no set ip next-hop [<peer-address|A.B.C.D>]",
2378 NO_STR
2379 SET_STR
3a2d747c 2380 IP_STR
82f97584
DW
2381 "Next hop address\n"
2382 "Use peer address (for BGP only)\n"
2383 "IP address of next hop\n")
2384{
2385 int idx_peer = 4;
e52702f2 2386 VTY_DECLVAR_CONTEXT (route_map_index, index);
82f97584
DW
2387
2388 if (rmap_match_set_hook.no_set_ip_nexthop)
2389 {
2390 if (argc <= idx_peer)
e52702f2
QY
2391 return rmap_match_set_hook.no_set_ip_nexthop (vty, index, "ip next-hop", NULL);
2392 return rmap_match_set_hook.no_set_ip_nexthop (vty, index, "ip next-hop", argv[idx_peer]->arg);
82f97584
DW
2393 }
2394 return CMD_SUCCESS;
2395}
2396
2397
2398DEFUN (set_ipv6_nexthop_local,
2399 set_ipv6_nexthop_local_cmd,
2400 "set ipv6 next-hop local X:X::X:X",
2401 SET_STR
2402 IPV6_STR
2403 "IPv6 next-hop address\n"
2404 "IPv6 local address\n"
2405 "IPv6 address of next hop\n")
2406{
2407 int idx_ipv6 = 4;
2408 struct in6_addr addr;
2409 int ret;
e52702f2 2410 VTY_DECLVAR_CONTEXT (route_map_index, index);
82f97584
DW
2411
2412 ret = inet_pton (AF_INET6, argv[idx_ipv6]->arg, &addr);
2413 if (!ret)
2414 {
2415 vty_out (vty, "%% Malformed nexthop address%s", VTY_NEWLINE);
2416 return CMD_WARNING;
2417 }
2418 if (!IN6_IS_ADDR_LINKLOCAL(&addr))
2419 {
2420 vty_out (vty, "%% Invalid link-local nexthop address%s", VTY_NEWLINE);
2421 return CMD_WARNING;
2422 }
2423
2424 if (rmap_match_set_hook.set_ipv6_nexthop_local)
e52702f2 2425 return rmap_match_set_hook.set_ipv6_nexthop_local (vty, index, "ipv6 next-hop local", argv[idx_ipv6]->arg);
82f97584
DW
2426 return CMD_SUCCESS;
2427}
2428
2429
2430DEFUN (no_set_ipv6_nexthop_local,
2431 no_set_ipv6_nexthop_local_cmd,
2432 "no set ipv6 next-hop local [X:X::X:X]",
2433 NO_STR
2434 SET_STR
2435 IPV6_STR
2436 "IPv6 next-hop address\n"
2437 "IPv6 local address\n"
2438 "IPv6 address of next hop\n")
2439{
2440 int idx_ipv6 = 5;
e52702f2
QY
2441 VTY_DECLVAR_CONTEXT (route_map_index, index);
2442
82f97584
DW
2443 if (rmap_match_set_hook.no_set_ipv6_nexthop_local)
2444 {
2445 if (argc <= idx_ipv6)
e52702f2
QY
2446 return rmap_match_set_hook.no_set_ipv6_nexthop_local (vty, index, "ipv6 next-hop local", NULL);
2447 return rmap_match_set_hook.no_set_ipv6_nexthop_local (vty, index, "ipv6 next-hop local", argv[5]->arg);
82f97584
DW
2448 }
2449 return CMD_SUCCESS;
2450}
2451
2452DEFUN (set_metric,
2453 set_metric_cmd,
2454 "set metric <(0-4294967295)|rtt|+rtt|-rtt|+metric|-metric>",
2455 SET_STR
2456 "Metric value for destination routing protocol\n"
2457 "Metric value\n"
2458 "Assign round trip time\n"
2459 "Add round trip time\n"
2460 "Subtract round trip time\n"
2461 "Add metric\n"
2462 "Subtract metric\n")
2463{
2464 int idx_number = 2;
e52702f2
QY
2465 VTY_DECLVAR_CONTEXT (route_map_index, index);
2466
82f97584 2467 if (rmap_match_set_hook.set_metric)
e52702f2 2468 return rmap_match_set_hook.set_metric (vty, index, "metric", argv[idx_number]->arg);
82f97584
DW
2469 return CMD_SUCCESS;
2470}
2471
2472
2473DEFUN (no_set_metric,
2474 no_set_metric_cmd,
2475 "no set metric [(0-4294967295)]",
2476 NO_STR
2477 SET_STR
2478 "Metric value for destination routing protocol\n"
2479 "Metric value\n")
2480{
2481 int idx_number = 3;
e52702f2
QY
2482 VTY_DECLVAR_CONTEXT (route_map_index, index);
2483
82f97584
DW
2484 if (rmap_match_set_hook.no_set_metric)
2485 {
2486 if (argc <= idx_number)
e52702f2
QY
2487 return rmap_match_set_hook.no_set_metric (vty, index, "metric", NULL);
2488 return rmap_match_set_hook.no_set_metric (vty, index, "metric", argv[idx_number]->arg);
82f97584
DW
2489 }
2490 return CMD_SUCCESS;
2491}
2492
2493
2494DEFUN (set_tag,
2495 set_tag_cmd,
e52702f2 2496 "set tag (1-4294967295)",
82f97584
DW
2497 SET_STR
2498 "Tag value for routing protocol\n"
2499 "Tag value\n")
2500{
e52702f2
QY
2501 VTY_DECLVAR_CONTEXT (route_map_index, index);
2502
82f97584
DW
2503 int idx_number = 2;
2504 if (rmap_match_set_hook.set_tag)
e52702f2 2505 return rmap_match_set_hook.set_tag (vty, index, "tag", argv[idx_number]->arg);
82f97584
DW
2506 return CMD_SUCCESS;
2507}
2508
2509
2510DEFUN (no_set_tag,
2511 no_set_tag_cmd,
e52702f2 2512 "no set tag [(1-4294967295)]",
82f97584
DW
2513 NO_STR
2514 SET_STR
2515 "Tag value for routing protocol\n"
2516 "Tag value\n")
2517{
e52702f2
QY
2518 VTY_DECLVAR_CONTEXT (route_map_index, index);
2519
82f97584
DW
2520 int idx_number = 3;
2521 if (rmap_match_set_hook.no_set_tag)
2522 {
2523 if (argc <= idx_number)
e52702f2
QY
2524 return rmap_match_set_hook.no_set_tag (vty, index, "tag", NULL);
2525 return rmap_match_set_hook.no_set_tag (vty, index, "tag", argv[idx_number]->arg);
82f97584
DW
2526 }
2527 return CMD_SUCCESS;
2528}
2529
2530
2531
505e5056 2532DEFUN_NOSH (route_map,
718e3744 2533 route_map_cmd,
7fcbbdae 2534 "route-map WORD <deny|permit> (1-65535)",
718e3744 2535 "Create route-map or enter route-map command mode\n"
2536 "Route map tag\n"
2537 "Route map denies set operations\n"
2538 "Route map permits set operations\n"
2539 "Sequence to insert to/delete from existing route-map entry\n")
2540{
c349116d
DW
2541 int idx_word = 1;
2542 int idx_permit_deny = 2;
2543 int idx_number = 3;
718e3744 2544 struct route_map *map;
2545 struct route_map_index *index;
2546 char *endptr = NULL;
c349116d
DW
2547 int permit = argv[idx_permit_deny]->arg[0] == 'p' ? RMAP_PERMIT : RMAP_DENY;
2548 unsigned long pref = strtoul (argv[idx_number]->arg, &endptr, 10);
2549 const char *mapname = argv[idx_word]->arg;
718e3744 2550
2551 /* Get route map. */
7fcbbdae 2552 map = route_map_get (mapname);
718e3744 2553 index = route_map_index_get (map, permit, pref);
2554
a50b7ceb 2555 VTY_PUSH_CONTEXT (RMAP_NODE, index);
718e3744 2556 return CMD_SUCCESS;
2557}
2558
2559DEFUN (no_route_map_all,
2560 no_route_map_all_cmd,
2561 "no route-map WORD",
2562 NO_STR
2563 "Create route-map or enter route-map command mode\n"
2564 "Route map tag\n")
2565{
c349116d
DW
2566 int idx_word = 2;
2567 const char *mapname = argv[idx_word]->arg;
718e3744 2568 struct route_map *map;
2569
7fcbbdae 2570 map = route_map_lookup_by_name (mapname);
718e3744 2571 if (map == NULL)
2572 {
7fcbbdae 2573 vty_out (vty, "%% Could not find route-map %s%s", mapname, VTY_NEWLINE);
718e3744 2574 return CMD_WARNING;
2575 }
2576
2577 route_map_delete (map);
2578
2579 return CMD_SUCCESS;
2580}
2581
2582DEFUN (no_route_map,
2583 no_route_map_cmd,
7fcbbdae 2584 "no route-map WORD <deny|permit> (1-65535)",
718e3744 2585 NO_STR
2586 "Create route-map or enter route-map command mode\n"
2587 "Route map tag\n"
2588 "Route map denies set operations\n"
2589 "Route map permits set operations\n"
2590 "Sequence to insert to/delete from existing route-map entry\n")
2591{
c349116d
DW
2592 int idx_word = 2;
2593 int idx_permit_deny = 3;
2594 int idx_number = 4;
718e3744 2595 struct route_map *map;
2596 struct route_map_index *index;
2597 char *endptr = NULL;
c349116d
DW
2598 int permit = argv[idx_permit_deny]->arg[0] == 'p' ? RMAP_PERMIT : RMAP_DENY;
2599 const char *prefstr = argv[idx_number]->arg;
2600 const char *mapname = argv[idx_word]->arg;
7fcbbdae 2601 unsigned long pref = strtoul (prefstr, &endptr, 10);
718e3744 2602
2603 /* Existence check. */
7fcbbdae 2604 map = route_map_lookup_by_name (mapname);
718e3744 2605 if (map == NULL)
2606 {
7fcbbdae 2607 vty_out (vty, "%% Could not find route-map %s%s", mapname, VTY_NEWLINE);
718e3744 2608 return CMD_WARNING;
2609 }
2610
2611 /* Lookup route map index. */
2612 index = route_map_index_lookup (map, permit, pref);
2613 if (index == NULL)
2614 {
2615 vty_out (vty, "%% Could not find route-map entry %s %s%s",
7fcbbdae 2616 mapname, prefstr, VTY_NEWLINE);
718e3744 2617 return CMD_WARNING;
2618 }
2619
2620 /* Delete index from route map. */
2621 route_map_index_delete (index, 1);
2622
2623 /* If this route rule is the last one, delete route map itself. */
2624 if (route_map_empty (map))
2625 route_map_delete (map);
2626
2627 return CMD_SUCCESS;
2628}
2629
2630DEFUN (rmap_onmatch_next,
2631 rmap_onmatch_next_cmd,
2632 "on-match next",
2633 "Exit policy on matches\n"
2634 "Next clause\n")
2635{
be301cc2 2636 struct route_map_index *index = VTY_GET_CONTEXT (route_map_index);
718e3744 2637
2638 if (index)
7ebab1fb
DS
2639 {
2640 if (index->type == RMAP_DENY)
2641 {
2642 /* Under a deny clause, match means it's finished. No need to set next */
2643 vty_out (vty, "on-match next not supported under route-map deny%s",
2644 VTY_NEWLINE);
2645 return CMD_WARNING;
2646 }
2647 index->exitpolicy = RMAP_NEXT;
2648 }
718e3744 2649 return CMD_SUCCESS;
2650}
2651
2652DEFUN (no_rmap_onmatch_next,
2653 no_rmap_onmatch_next_cmd,
2654 "no on-match next",
2655 NO_STR
2656 "Exit policy on matches\n"
2657 "Next clause\n")
2658{
be301cc2 2659 struct route_map_index *index = VTY_GET_CONTEXT (route_map_index);
718e3744 2660
2661 if (index)
2662 index->exitpolicy = RMAP_EXIT;
2663
2664 return CMD_SUCCESS;
2665}
2666
2667DEFUN (rmap_onmatch_goto,
2668 rmap_onmatch_goto_cmd,
7fcbbdae 2669 "on-match goto (1-65535)",
718e3744 2670 "Exit policy on matches\n"
2671 "Goto Clause number\n"
2672 "Number\n")
2673{
0d702986
QY
2674 int idx = 0;
2675 char *num = argv_find (argv, argc, "(1-65535)", &idx) ? argv[idx]->arg : NULL;
e52702f2 2676
be301cc2 2677 struct route_map_index *index = VTY_GET_CONTEXT (route_map_index);
718e3744 2678 int d = 0;
2679
718e3744 2680 if (index)
2681 {
7ebab1fb
DS
2682 if (index->type == RMAP_DENY)
2683 {
2684 /* Under a deny clause, match means it's finished. No need to go anywhere */
2685 vty_out (vty, "on-match goto not supported under route-map deny%s",
2686 VTY_NEWLINE);
2687 return CMD_WARNING;
2688 }
2689
abddf075 2690 if (num)
facfee22 2691 d = strtoul(num, NULL, 10);
d4f0960c 2692 else
2693 d = index->pref + 1;
2694
718e3744 2695 if (d <= index->pref)
2696 {
2697 /* Can't allow you to do that, Dave */
f667a580 2698 vty_out (vty, "can't jump backwards in route-maps%s", VTY_NEWLINE);
718e3744 2699 return CMD_WARNING;
2700 }
2701 else
2702 {
2703 index->exitpolicy = RMAP_GOTO;
2704 index->nextpref = d;
2705 }
2706 }
2707 return CMD_SUCCESS;
2708}
2709
2710DEFUN (no_rmap_onmatch_goto,
2711 no_rmap_onmatch_goto_cmd,
2712 "no on-match goto",
2713 NO_STR
2714 "Exit policy on matches\n"
fee0f4c6 2715 "Goto Clause number\n")
718e3744 2716{
be301cc2 2717 struct route_map_index *index = VTY_GET_CONTEXT (route_map_index);
718e3744 2718
2719 if (index)
2720 index->exitpolicy = RMAP_EXIT;
2721
2722 return CMD_SUCCESS;
2723}
2724
f667a580
QY
2725/* Cisco/GNU Zebra compatibility aliases */
2726/* ALIAS_FIXME */
2727DEFUN (rmap_continue,
2728 rmap_continue_cmd,
2729 "continue (1-65535)",
2730 "Continue on a different entry within the route-map\n"
2731 "Route-map entry sequence number\n")
2732{
2733 return rmap_onmatch_goto (self, vty, argc, argv);
2734}
5510e83b 2735
f667a580
QY
2736/* ALIAS_FIXME */
2737DEFUN (no_rmap_continue,
2738 no_rmap_continue_cmd,
2739 "no continue [(1-65535)]",
2740 NO_STR
2741 "Continue on a different entry within the route-map\n"
2742 "Route-map entry sequence number\n")
2743{
2744 return no_rmap_onmatch_goto (self, vty, argc, argv);
2745}
f412b39a 2746
5510e83b 2747
6d2729e3 2748DEFUN (rmap_show_name,
5510e83b 2749 rmap_show_name_cmd,
7514fb77 2750 "show route-map [WORD]",
5510e83b 2751 SHOW_STR
2752 "route-map information\n"
2753 "route-map name\n")
2754{
c349116d 2755 int idx_word = 2;
abddf075
DW
2756 const char *name = (argc == 3) ? argv[idx_word]->arg : NULL;
2757 return vty_show_route_map (vty, name);
5510e83b 2758}
2759
fee0f4c6 2760DEFUN (rmap_call,
2761 rmap_call_cmd,
2762 "call WORD",
2763 "Jump to another Route-Map after match+set\n"
2764 "Target route-map name\n")
2765{
c349116d 2766 int idx_word = 1;
be301cc2 2767 struct route_map_index *index = VTY_GET_CONTEXT (route_map_index);
c349116d 2768 const char *rmap = argv[idx_word]->arg;
fee0f4c6 2769
c01d03a6
QY
2770 assert(index);
2771
2772 if (index->nextrm)
fee0f4c6 2773 {
c01d03a6
QY
2774 route_map_upd8_dependency (RMAP_EVENT_CALL_DELETED,
2775 index->nextrm,
2776 index->map->name);
2777 XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
fee0f4c6 2778 }
c01d03a6 2779 index->nextrm = XSTRDUP (MTYPE_ROUTE_MAP_NAME, rmap);
518f0eb1
DS
2780
2781 /* Execute event hook. */
2782 route_map_upd8_dependency (RMAP_EVENT_CALL_ADDED,
2783 index->nextrm,
2784 index->map->name);
fee0f4c6 2785 return CMD_SUCCESS;
2786}
2787
2788DEFUN (no_rmap_call,
2789 no_rmap_call_cmd,
2790 "no call",
2791 NO_STR
2792 "Jump to another Route-Map after match+set\n")
2793{
be301cc2 2794 struct route_map_index *index = VTY_GET_CONTEXT (route_map_index);
fee0f4c6 2795
2796 if (index->nextrm)
2797 {
518f0eb1
DS
2798 route_map_upd8_dependency (RMAP_EVENT_CALL_DELETED,
2799 index->nextrm,
2800 index->map->name);
0241684e 2801 XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
fee0f4c6 2802 index->nextrm = NULL;
2803 }
2804
2805 return CMD_SUCCESS;
2806}
2807
4a8164e5 2808DEFUN (rmap_description,
2809 rmap_description_cmd,
7fcbbdae 2810 "description LINE...",
4a8164e5 2811 "Route-map comment\n"
2812 "Comment describing this route-map rule\n")
2813{
58749582 2814 int idx_line = 1;
be301cc2 2815 struct route_map_index *index = VTY_GET_CONTEXT (route_map_index);
4a8164e5 2816
4a8164e5 2817 if (index)
2818 {
2819 if (index->description)
2820 XFREE (MTYPE_TMP, index->description);
58749582 2821 index->description = argv_concat (argv, argc, idx_line);
4a8164e5 2822 }
2823 return CMD_SUCCESS;
2824}
2825
2826DEFUN (no_rmap_description,
2827 no_rmap_description_cmd,
2828 "no description",
2829 NO_STR
2830 "Route-map comment\n")
2831{
be301cc2 2832 struct route_map_index *index = VTY_GET_CONTEXT (route_map_index);
4a8164e5 2833
4a8164e5 2834 if (index)
2835 {
2836 if (index->description)
2837 XFREE (MTYPE_TMP, index->description);
2838 index->description = NULL;
2839 }
2840 return CMD_SUCCESS;
2841}
2842
718e3744 2843/* Configuration write function. */
8cc4198f 2844static int
718e3744 2845route_map_config_write (struct vty *vty)
2846{
2847 struct route_map *map;
2848 struct route_map_index *index;
2849 struct route_map_rule *rule;
2850 int first = 1;
2851 int write = 0;
2852
2853 for (map = route_map_master.head; map; map = map->next)
2854 for (index = map->head; index; index = index->next)
2855 {
2856 if (!first)
2857 vty_out (vty, "!%s", VTY_NEWLINE);
2858 else
2859 first = 0;
2860
2861 vty_out (vty, "route-map %s %s %d%s",
2862 map->name,
2863 route_map_type_str (index->type),
2864 index->pref, VTY_NEWLINE);
2865
4a8164e5 2866 if (index->description)
2867 vty_out (vty, " description %s%s", index->description, VTY_NEWLINE);
2868
718e3744 2869 for (rule = index->match_list.head; rule; rule = rule->next)
2870 vty_out (vty, " match %s %s%s", rule->cmd->str,
2871 rule->rule_str ? rule->rule_str : "",
2872 VTY_NEWLINE);
2873
2874 for (rule = index->set_list.head; rule; rule = rule->next)
2875 vty_out (vty, " set %s %s%s", rule->cmd->str,
2876 rule->rule_str ? rule->rule_str : "",
2877 VTY_NEWLINE);
fee0f4c6 2878 if (index->nextrm)
2879 vty_out (vty, " call %s%s", index->nextrm, VTY_NEWLINE);
718e3744 2880 if (index->exitpolicy == RMAP_GOTO)
fee0f4c6 2881 vty_out (vty, " on-match goto %d%s", index->nextpref, VTY_NEWLINE);
718e3744 2882 if (index->exitpolicy == RMAP_NEXT)
2883 vty_out (vty," on-match next%s", VTY_NEWLINE);
2884
2885 write++;
2886 }
2887 return write;
2888}
2889
2890/* Route map node structure. */
7fc626de 2891static struct cmd_node rmap_node =
718e3744 2892{
2893 RMAP_NODE,
2894 "%s(config-route-map)# ",
2895 1
2896};
2897
dc9ffce8
CF
2898/* Common route map rules */
2899
2900void *
2901route_map_rule_tag_compile (const char *arg)
2902{
2903 unsigned long int tmp;
2904 char *endptr;
2905 route_tag_t *tag;
2906
2907 errno = 0;
2908 tmp = strtoul(arg, &endptr, 0);
2909 if (arg[0] == '\0' || *endptr != '\0' || errno || tmp > ROUTE_TAG_MAX)
2910 return NULL;
2911
2912 tag = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*tag));
2913 *tag = tmp;
2914
2915 return tag;
2916}
2917
2918void
2919route_map_rule_tag_free (void *rule)
2920{
2921 XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
2922}
2923
9df78e7c
DS
2924void
2925route_map_finish (void)
2926{
2927 int i;
2928
2929 vector_free (route_match_vec);
2930 route_match_vec = NULL;
2931 vector_free (route_set_vec);
2932 route_set_vec = NULL;
2933
2934 /* cleanup route_map */
2935 while (route_map_master.head)
b09bceec
DS
2936 {
2937 struct route_map *map = route_map_master.head;
2938 map->to_be_processed = 0;
2939 route_map_delete (map);
2940 }
9df78e7c
DS
2941
2942 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
8eefe200
DS
2943 {
2944 hash_free(route_map_dep_hash[i]);
2945 route_map_dep_hash[i] = NULL;
2946 }
9df78e7c
DS
2947
2948 hash_free (route_map_master_hash);
8eefe200 2949 route_map_master_hash = NULL;
9df78e7c
DS
2950}
2951
70d44c5c
DL
2952static void rmap_autocomplete(vector comps, struct cmd_token *token)
2953{
2954 struct route_map *map;
2955
2956 for (map = route_map_master.head; map; map = map->next)
2957 vector_set (comps, XSTRDUP (MTYPE_COMPLETION, map->name));
2958}
2959
2960static const struct cmd_variable_handler rmap_var_handlers[] = {
2961 {
2962 /* "route-map WORD" */
2963 .varname = "route_map",
2964 .completions = rmap_autocomplete
2965 }, {
2966 .tokenname = "ROUTEMAP_NAME",
2967 .completions = rmap_autocomplete
2968 }, {
2969 .tokenname = "RMAP_NAME",
2970 .completions = rmap_autocomplete
2971 }, {
2972 .completions = NULL
2973 }
2974};
2975
718e3744 2976/* Initialization of route map vector. */
2977void
b2575bc0 2978route_map_init (void)
718e3744 2979{
b2575bc0
DS
2980 int i;
2981
2982 /* Make vector for match and set. */
2983 route_match_vec = vector_init (1);
2984 route_set_vec = vector_init (1);
2985 route_map_master_hash = hash_create(route_map_hash_key_make, route_map_hash_cmp);
2986
2987 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
2988 route_map_dep_hash[i] = hash_create(route_map_dep_hash_make_key,
2989 route_map_dep_hash_cmp);
518f0eb1 2990
70d44c5c
DL
2991 cmd_variable_handler_register(rmap_var_handlers);
2992
718e3744 2993 /* Install route map top node. */
2994 install_node (&rmap_node, route_map_config_write);
2995
2996 /* Install route map commands. */
2997 install_default (RMAP_NODE);
2998 install_element (CONFIG_NODE, &route_map_cmd);
2999 install_element (CONFIG_NODE, &no_route_map_cmd);
3000 install_element (CONFIG_NODE, &no_route_map_all_cmd);
3001
3002 /* Install the on-match stuff */
3003 install_element (RMAP_NODE, &route_map_cmd);
3004 install_element (RMAP_NODE, &rmap_onmatch_next_cmd);
3005 install_element (RMAP_NODE, &no_rmap_onmatch_next_cmd);
3006 install_element (RMAP_NODE, &rmap_onmatch_goto_cmd);
3007 install_element (RMAP_NODE, &no_rmap_onmatch_goto_cmd);
f667a580
QY
3008 install_element (RMAP_NODE, &rmap_continue_cmd);
3009 install_element (RMAP_NODE, &no_rmap_continue_cmd);
fee0f4c6 3010
3011 /* Install the continue stuff (ALIAS of on-match). */
fee0f4c6 3012
3013 /* Install the call stuff. */
3014 install_element (RMAP_NODE, &rmap_call_cmd);
3015 install_element (RMAP_NODE, &no_rmap_call_cmd);
4a8164e5 3016
3017 /* Install description commands. */
3018 install_element (RMAP_NODE, &rmap_description_cmd);
3019 install_element (RMAP_NODE, &no_rmap_description_cmd);
fee0f4c6 3020
5510e83b 3021 /* Install show command */
5510e83b 3022 install_element (ENABLE_NODE, &rmap_show_name_cmd);
82f97584
DW
3023
3024 install_element (RMAP_NODE, &match_interface_cmd);
3025 install_element (RMAP_NODE, &no_match_interface_cmd);
3026
3027 install_element (RMAP_NODE, &match_ip_address_cmd);
3028 install_element (RMAP_NODE, &no_match_ip_address_cmd);
3029
3030 install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd);
3031 install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd);
3032
3033 install_element (RMAP_NODE, &match_ip_next_hop_cmd);
3034 install_element (RMAP_NODE, &no_match_ip_next_hop_cmd);
3035
3036 install_element (RMAP_NODE, &match_ip_next_hop_prefix_list_cmd);
3037 install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd);
3038
3039 install_element (RMAP_NODE, &match_ipv6_address_cmd);
3040 install_element (RMAP_NODE, &no_match_ipv6_address_cmd);
3041
3042 install_element (RMAP_NODE, &match_ipv6_address_prefix_list_cmd);
3043 install_element (RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd);
3044
3045 install_element (RMAP_NODE, &match_metric_cmd);
3046 install_element (RMAP_NODE, &no_match_metric_cmd);
3047
3048 install_element (RMAP_NODE, &match_tag_cmd);
3049 install_element (RMAP_NODE, &no_match_tag_cmd);
3050
3051 install_element (RMAP_NODE, &set_ip_nexthop_cmd);
3052 install_element (RMAP_NODE, &no_set_ip_nexthop_cmd);
3053
3054 install_element (RMAP_NODE, &set_ipv6_nexthop_local_cmd);
3055 install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_cmd);
3056
3057 install_element (RMAP_NODE, &set_metric_cmd);
3058 install_element (RMAP_NODE, &no_set_metric_cmd);
3059
3060 install_element (RMAP_NODE, &set_tag_cmd);
3061 install_element (RMAP_NODE, &no_set_tag_cmd);
3062
718e3744 3063}