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