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