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