]> git.proxmox.com Git - mirror_frr.git/blame - lib/routemap.c
initd: initd-mi.patch
[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"
27#include "routemap.h"
28#include "command.h"
d4f0960c 29#include "vty.h"
fee0f4c6 30#include "log.h"
518f0eb1 31#include "hash.h"
6b0655a2 32
718e3744 33/* Vector for route match rules. */
34static vector route_match_vec;
35
36/* Vector for route set rules. */
37static vector route_set_vec;
38
39/* Route map rule. This rule has both `match' rule and `set' rule. */
40struct route_map_rule
41{
42 /* Rule type. */
43 struct route_map_rule_cmd *cmd;
44
45 /* For pretty printing. */
46 char *rule_str;
47
48 /* Pre-compiled match rule. */
49 void *value;
50
51 /* Linked list. */
52 struct route_map_rule *next;
53 struct route_map_rule *prev;
54};
55
56/* Making route map list. */
57struct route_map_list
58{
59 struct route_map *head;
60 struct route_map *tail;
61
9035efaa 62 void (*add_hook) (const char *);
63 void (*delete_hook) (const char *);
518f0eb1 64 void (*event_hook) (route_map_event_t, const char *);
718e3744 65};
66
67/* Master list of route map. */
518f0eb1
DS
68static struct route_map_list route_map_master = { NULL, NULL, NULL, NULL, NULL };
69
70enum route_map_upd8_type
71 {
72 ROUTE_MAP_ADD = 1,
73 ROUTE_MAP_DEL,
74 };
75
76/* all possible route-map dependency types */
77enum route_map_dep_type
78 {
79 ROUTE_MAP_DEP_RMAP = 1,
80 ROUTE_MAP_DEP_CLIST,
81 ROUTE_MAP_DEP_ECLIST,
82 ROUTE_MAP_DEP_PLIST,
83 ROUTE_MAP_DEP_ASPATH,
84 ROUTE_MAP_DEP_FILTER,
85 ROUTE_MAP_DEP_MAX,
86 };
87
88struct route_map_dep
89{
90 char *dep_name;
91 struct hash *dep_rmap_hash;
92 struct hash *this_hash; /* ptr to the hash structure this is part of */
93};
718e3744 94
518f0eb1
DS
95/* Hashes maintaining dependency between various sublists used by route maps */
96struct hash *route_map_dep_hash[ROUTE_MAP_DEP_MAX];
97
98static unsigned int route_map_dep_hash_make_key (void *p);
99static int route_map_dep_hash_cmp (const void *p1, const void *p2);
100static void route_map_init_dep_hashes (void);
101static void route_map_clear_all_references (char *rmap_name);
102static void route_map_rule_delete (struct route_map_rule_list *,
103 struct route_map_rule *);
104static int rmap_debug = 0;
718e3744 105
106static void
107route_map_index_delete (struct route_map_index *, int);
6b0655a2 108
718e3744 109/* New route map allocation. Please note route map's name must be
110 specified. */
111static struct route_map *
9035efaa 112route_map_new (const char *name)
718e3744 113{
114 struct route_map *new;
115
116 new = XCALLOC (MTYPE_ROUTE_MAP, sizeof (struct route_map));
117 new->name = XSTRDUP (MTYPE_ROUTE_MAP_NAME, name);
118 return new;
119}
120
121/* Add new name to route_map. */
122static struct route_map *
9035efaa 123route_map_add (const char *name)
718e3744 124{
125 struct route_map *map;
126 struct route_map_list *list;
127
128 map = route_map_new (name);
129 list = &route_map_master;
130
131 map->next = NULL;
132 map->prev = list->tail;
133 if (list->tail)
134 list->tail->next = map;
135 else
136 list->head = map;
137 list->tail = map;
138
139 /* Execute hook. */
140 if (route_map_master.add_hook)
518f0eb1
DS
141 {
142 (*route_map_master.add_hook) (name);
143 route_map_notify_dependencies(name, RMAP_EVENT_CALL_ADDED);
144 }
718e3744 145 return map;
146}
147
518f0eb1
DS
148/* this is supposed to be called post processing by
149 * the delete hook function. Don't invoke delete_hook
150 * again in this routine.
151 */
152void
153route_map_free_map (struct route_map *map)
718e3744 154{
155 struct route_map_list *list;
156 struct route_map_index *index;
518f0eb1 157
718e3744 158 while ((index = map->head) != NULL)
159 route_map_index_delete (index, 0);
160
718e3744 161 list = &route_map_master;
162
518f0eb1
DS
163 if (map != NULL)
164 {
165 if (map->next)
166 map->next->prev = map->prev;
167 else
168 list->tail = map->prev;
718e3744 169
518f0eb1
DS
170 if (map->prev)
171 map->prev->next = map->next;
172 else
173 list->head = map->next;
718e3744 174
518f0eb1
DS
175 XFREE (MTYPE_ROUTE_MAP_NAME, map->name);
176 XFREE (MTYPE_ROUTE_MAP, map);
177 }
178}
718e3744 179
518f0eb1
DS
180/* Route map delete from list. */
181static void
182route_map_delete (struct route_map *map)
183{
184 struct route_map_index *index;
185 char *name;
186
187 while ((index = map->head) != NULL)
188 route_map_index_delete (index, 0);
189
190 name = map->name;
191 map->head = NULL;
192
193 /* Clear all dependencies */
194 route_map_clear_all_references(name);
195 map->deleted = 1;
718e3744 196 /* Execute deletion hook. */
197 if (route_map_master.delete_hook)
518f0eb1
DS
198 {
199 (*route_map_master.delete_hook) (name);
200 route_map_notify_dependencies(name, RMAP_EVENT_CALL_DELETED);
201 }
718e3744 202
518f0eb1
DS
203 if (!map->to_be_processed)
204 {
205 route_map_free_map (map);
206 }
718e3744 207}
208
209/* Lookup route map by route map name string. */
210struct route_map *
9035efaa 211route_map_lookup_by_name (const char *name)
718e3744 212{
213 struct route_map *map;
214
518f0eb1
DS
215 if (!name)
216 return NULL;
217
718e3744 218 for (map = route_map_master.head; map; map = map->next)
518f0eb1 219 if ((strcmp (map->name, name) == 0) && (!map->deleted))
718e3744 220 return map;
221 return NULL;
222}
223
518f0eb1
DS
224int
225route_map_mark_updated (const char *name, int del_later)
226{
227 struct route_map *map;
228 int ret = -1;
229
230 /* We need to do this walk manually instead of calling lookup_by_name()
231 * because the lookup function doesn't return route maps marked as
232 * deleted.
233 */
234 for (map = route_map_master.head; map; map = map->next)
235 if (strcmp (map->name, name) == 0)
236 {
237 map->to_be_processed = 1;
238 ret = 0;
239 }
240
241 return(ret);
242}
243
244int
245route_map_clear_updated (struct route_map *map)
246{
247 int ret = -1;
248
249 if (map)
250 {
251 map->to_be_processed = 0;
252 if (map->deleted)
253 route_map_free_map(map);
254 }
255
256 return (ret);
257}
258
718e3744 259/* Lookup route map. If there isn't route map create one and return
260 it. */
8cc4198f 261static struct route_map *
9035efaa 262route_map_get (const char *name)
718e3744 263{
264 struct route_map *map;
265
266 map = route_map_lookup_by_name (name);
267 if (map == NULL)
268 map = route_map_add (name);
518f0eb1 269
718e3744 270 return map;
271}
272
518f0eb1
DS
273void
274route_map_walk_update_list (void *arg,
275 int (*route_map_update_fn) (void *arg, char *name))
276{
277 struct route_map *node;
278 struct route_map *nnode = NULL;
279
280 for (node = route_map_master.head; node; node = nnode)
281 {
282 if (node->to_be_processed)
283 {
284 /* DD: Should we add any thread yield code here */
285 route_map_update_fn(arg, node->name);
286 nnode = node->next;
287 route_map_clear_updated(node);
288 }
289 else
290 nnode = node->next;
291 }
292}
293
718e3744 294/* Return route map's type string. */
8cc4198f 295static const char *
718e3744 296route_map_type_str (enum route_map_type type)
297{
298 switch (type)
299 {
300 case RMAP_PERMIT:
301 return "permit";
302 break;
303 case RMAP_DENY:
304 return "deny";
305 break;
306 default:
307 return "";
308 break;
309 }
310}
311
8cc4198f 312static int
718e3744 313route_map_empty (struct route_map *map)
314{
315 if (map->head == NULL && map->tail == NULL)
316 return 1;
317 else
318 return 0;
319}
320
5510e83b 321/* show route-map */
322static void
323vty_show_route_map_entry (struct vty *vty, struct route_map *map)
718e3744 324{
718e3744 325 struct route_map_index *index;
326 struct route_map_rule *rule;
327
fbf5d033 328 /* Print the name of the protocol */
329 if (zlog_default)
330 vty_out (vty, "%s:%s", zlog_proto_names[zlog_default->protocol],
331 VTY_NEWLINE);
332
5510e83b 333 for (index = map->head; index; index = index->next)
334 {
335 vty_out (vty, "route-map %s, %s, sequence %d%s",
336 map->name, route_map_type_str (index->type),
337 index->pref, VTY_NEWLINE);
5bb4c198 338
339 /* Description */
340 if (index->description)
341 vty_out (vty, " Description:%s %s%s", VTY_NEWLINE,
342 index->description, VTY_NEWLINE);
5510e83b 343
344 /* Match clauses */
345 vty_out (vty, " Match clauses:%s", VTY_NEWLINE);
346 for (rule = index->match_list.head; rule; rule = rule->next)
347 vty_out (vty, " %s %s%s",
348 rule->cmd->str, rule->rule_str, VTY_NEWLINE);
349
350 vty_out (vty, " Set clauses:%s", VTY_NEWLINE);
351 for (rule = index->set_list.head; rule; rule = rule->next)
352 vty_out (vty, " %s %s%s",
353 rule->cmd->str, rule->rule_str, VTY_NEWLINE);
354
db29ae5f 355 /* Call clause */
356 vty_out (vty, " Call clause:%s", VTY_NEWLINE);
fee0f4c6 357 if (index->nextrm)
358 vty_out (vty, " Call %s%s", index->nextrm, VTY_NEWLINE);
db29ae5f 359
360 /* Exit Policy */
361 vty_out (vty, " Action:%s", VTY_NEWLINE);
362 if (index->exitpolicy == RMAP_GOTO)
5510e83b 363 vty_out (vty, " Goto %d%s", index->nextpref, VTY_NEWLINE);
5510e83b 364 else if (index->exitpolicy == RMAP_NEXT)
db29ae5f 365 vty_out (vty, " Continue to next entry%s", VTY_NEWLINE);
5510e83b 366 else if (index->exitpolicy == RMAP_EXIT)
367 vty_out (vty, " Exit routemap%s", VTY_NEWLINE);
368 }
718e3744 369}
370
8cc4198f 371static int
9035efaa 372vty_show_route_map (struct vty *vty, const char *name)
5510e83b 373{
374 struct route_map *map;
375
376 if (name)
377 {
378 map = route_map_lookup_by_name (name);
379
380 if (map)
381 {
382 vty_show_route_map_entry (vty, map);
383 return CMD_SUCCESS;
384 }
385 else
386 {
387 vty_out (vty, "%%route-map %s not found%s", name, VTY_NEWLINE);
388 return CMD_WARNING;
389 }
390 }
7514fb77
PJ
391 else
392 {
393 for (map = route_map_master.head; map; map = map->next)
518f0eb1
DS
394 if (!map->deleted)
395 vty_show_route_map_entry (vty, map);
7514fb77 396 }
5510e83b 397 return CMD_SUCCESS;
398}
399
400
718e3744 401/* New route map allocation. Please note route map's name must be
402 specified. */
8cc4198f 403static struct route_map_index *
404route_map_index_new (void)
718e3744 405{
406 struct route_map_index *new;
407
408 new = XCALLOC (MTYPE_ROUTE_MAP_INDEX, sizeof (struct route_map_index));
409 new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */
410 return new;
411}
412
413/* Free route map index. */
414static void
415route_map_index_delete (struct route_map_index *index, int notify)
416{
417 struct route_map_rule *rule;
418
419 /* Free route match. */
420 while ((rule = index->match_list.head) != NULL)
421 route_map_rule_delete (&index->match_list, rule);
422
423 /* Free route set. */
424 while ((rule = index->set_list.head) != NULL)
425 route_map_rule_delete (&index->set_list, rule);
426
427 /* Remove index from route map list. */
428 if (index->next)
429 index->next->prev = index->prev;
430 else
431 index->map->tail = index->prev;
432
433 if (index->prev)
434 index->prev->next = index->next;
435 else
436 index->map->head = index->next;
437
fee0f4c6 438 /* Free 'char *nextrm' if not NULL */
439 if (index->nextrm)
0241684e 440 XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
fee0f4c6 441
718e3744 442 /* Execute event hook. */
443 if (route_map_master.event_hook && notify)
518f0eb1
DS
444 {
445 (*route_map_master.event_hook) (RMAP_EVENT_INDEX_DELETED,
446 index->map->name);
447 route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
448 }
718e3744 449 XFREE (MTYPE_ROUTE_MAP_INDEX, index);
450}
451
452/* Lookup index from route map. */
8cc4198f 453static struct route_map_index *
718e3744 454route_map_index_lookup (struct route_map *map, enum route_map_type type,
455 int pref)
456{
457 struct route_map_index *index;
458
459 for (index = map->head; index; index = index->next)
460 if ((index->type == type || type == RMAP_ANY)
461 && index->pref == pref)
462 return index;
463 return NULL;
464}
465
466/* Add new index to route map. */
8cc4198f 467static struct route_map_index *
718e3744 468route_map_index_add (struct route_map *map, enum route_map_type type,
469 int pref)
470{
471 struct route_map_index *index;
472 struct route_map_index *point;
473
474 /* Allocate new route map inex. */
475 index = route_map_index_new ();
476 index->map = map;
477 index->type = type;
478 index->pref = pref;
479
480 /* Compare preference. */
481 for (point = map->head; point; point = point->next)
482 if (point->pref >= pref)
483 break;
484
485 if (map->head == NULL)
486 {
487 map->head = map->tail = index;
488 }
489 else if (point == NULL)
490 {
491 index->prev = map->tail;
492 map->tail->next = index;
493 map->tail = index;
494 }
495 else if (point == map->head)
496 {
497 index->next = map->head;
498 map->head->prev = index;
499 map->head = index;
500 }
501 else
502 {
503 index->next = point;
504 index->prev = point->prev;
505 if (point->prev)
506 point->prev->next = index;
507 point->prev = index;
508 }
509
510 /* Execute event hook. */
511 if (route_map_master.event_hook)
518f0eb1
DS
512 {
513 (*route_map_master.event_hook) (RMAP_EVENT_INDEX_ADDED,
514 map->name);
515 route_map_notify_dependencies (map->name, RMAP_EVENT_CALL_ADDED);
516 }
718e3744 517 return index;
518}
519
520/* Get route map index. */
8cc4198f 521static struct route_map_index *
718e3744 522route_map_index_get (struct route_map *map, enum route_map_type type,
523 int pref)
524{
525 struct route_map_index *index;
526
527 index = route_map_index_lookup (map, RMAP_ANY, pref);
528 if (index && index->type != type)
529 {
530 /* Delete index from route map. */
531 route_map_index_delete (index, 1);
532 index = NULL;
533 }
534 if (index == NULL)
535 index = route_map_index_add (map, type, pref);
536 return index;
537}
538
539/* New route map rule */
8cc4198f 540static struct route_map_rule *
541route_map_rule_new (void)
718e3744 542{
543 struct route_map_rule *new;
544
545 new = XCALLOC (MTYPE_ROUTE_MAP_RULE, sizeof (struct route_map_rule));
546 return new;
547}
6b0655a2 548
718e3744 549/* Install rule command to the match list. */
550void
551route_map_install_match (struct route_map_rule_cmd *cmd)
552{
553 vector_set (route_match_vec, cmd);
554}
555
556/* Install rule command to the set list. */
557void
558route_map_install_set (struct route_map_rule_cmd *cmd)
559{
560 vector_set (route_set_vec, cmd);
561}
562
563/* Lookup rule command from match list. */
8cc4198f 564static struct route_map_rule_cmd *
27a43a81 565route_map_lookup_match (const char *name)
718e3744 566{
8c328f11 567 unsigned int i;
718e3744 568 struct route_map_rule_cmd *rule;
569
55468c86 570 for (i = 0; i < vector_active (route_match_vec); i++)
718e3744 571 if ((rule = vector_slot (route_match_vec, i)) != NULL)
572 if (strcmp (rule->str, name) == 0)
573 return rule;
574 return NULL;
575}
576
577/* Lookup rule command from set list. */
8cc4198f 578static struct route_map_rule_cmd *
27a43a81 579route_map_lookup_set (const char *name)
718e3744 580{
8c328f11 581 unsigned int i;
718e3744 582 struct route_map_rule_cmd *rule;
583
55468c86 584 for (i = 0; i < vector_active (route_set_vec); i++)
718e3744 585 if ((rule = vector_slot (route_set_vec, i)) != NULL)
586 if (strcmp (rule->str, name) == 0)
587 return rule;
588 return NULL;
589}
590
591/* Add match and set rule to rule list. */
592static void
593route_map_rule_add (struct route_map_rule_list *list,
594 struct route_map_rule *rule)
595{
596 rule->next = NULL;
597 rule->prev = list->tail;
598 if (list->tail)
599 list->tail->next = rule;
600 else
601 list->head = rule;
602 list->tail = rule;
603}
604
605/* Delete rule from rule list. */
606static void
607route_map_rule_delete (struct route_map_rule_list *list,
608 struct route_map_rule *rule)
609{
610 if (rule->cmd->func_free)
611 (*rule->cmd->func_free) (rule->value);
612
613 if (rule->rule_str)
614 XFREE (MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str);
615
616 if (rule->next)
617 rule->next->prev = rule->prev;
618 else
619 list->tail = rule->prev;
620 if (rule->prev)
621 rule->prev->next = rule->next;
622 else
623 list->head = rule->next;
624
625 XFREE (MTYPE_ROUTE_MAP_RULE, rule);
626}
627
628/* strcmp wrapper function which don't crush even argument is NULL. */
8cc4198f 629static int
c9eca01b 630rulecmp (const char *dst, const char *src)
718e3744 631{
632 if (dst == NULL)
633 {
634 if (src == NULL)
635 return 0;
636 else
637 return 1;
638 }
639 else
640 {
641 if (src == NULL)
642 return 1;
643 else
644 return strcmp (dst, src);
645 }
646 return 1;
647}
648
518f0eb1
DS
649/* Use this to return the already specified argument for this match. This is
650 * useful to get the specified argument with a route map match rule when the
651 * rule is being deleted and the argument is not provided.
652 */
653const char *
654route_map_get_match_arg(struct route_map_index *index, const char *match_name)
655{
656 struct route_map_rule *rule;
657 struct route_map_rule_cmd *cmd;
658
659 /* First lookup rule for add match statement. */
660 cmd = route_map_lookup_match (match_name);
661 if (cmd == NULL)
662 return NULL;
663
664 for (rule = index->match_list.head; rule; rule = rule->next)
665 if (rule->cmd == cmd && rule->rule_str != NULL)
666 return (rule->rule_str);
667
668 return (NULL);
669}
670
718e3744 671/* Add match statement to route map. */
672int
27a43a81 673route_map_add_match (struct route_map_index *index, const char *match_name,
c9eca01b 674 const char *match_arg)
718e3744 675{
676 struct route_map_rule *rule;
677 struct route_map_rule *next;
678 struct route_map_rule_cmd *cmd;
679 void *compile;
680 int replaced = 0;
681
682 /* First lookup rule for add match statement. */
683 cmd = route_map_lookup_match (match_name);
684 if (cmd == NULL)
685 return RMAP_RULE_MISSING;
686
687 /* Next call compile function for this match statement. */
688 if (cmd->func_compile)
689 {
690 compile= (*cmd->func_compile)(match_arg);
691 if (compile == NULL)
692 return RMAP_COMPILE_ERROR;
693 }
694 else
695 compile = NULL;
696
697 /* If argument is completely same ignore it. */
698 for (rule = index->match_list.head; rule; rule = next)
699 {
700 next = rule->next;
701 if (rule->cmd == cmd)
702 {
703 route_map_rule_delete (&index->match_list, rule);
704 replaced = 1;
705 }
706 }
707
708 /* Add new route map match rule. */
709 rule = route_map_rule_new ();
710 rule->cmd = cmd;
711 rule->value = compile;
712 if (match_arg)
713 rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, match_arg);
714 else
715 rule->rule_str = NULL;
716
717 /* Add new route match rule to linked list. */
718 route_map_rule_add (&index->match_list, rule);
719
720 /* Execute event hook. */
721 if (route_map_master.event_hook)
518f0eb1
DS
722 {
723 (*route_map_master.event_hook) (replaced ?
724 RMAP_EVENT_MATCH_REPLACED:
725 RMAP_EVENT_MATCH_ADDED,
726 index->map->name);
727 route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
728 }
718e3744 729
730 return 0;
731}
732
733/* Delete specified route match rule. */
734int
27a43a81 735route_map_delete_match (struct route_map_index *index, const char *match_name,
c9eca01b 736 const char *match_arg)
718e3744 737{
738 struct route_map_rule *rule;
739 struct route_map_rule_cmd *cmd;
740
741 cmd = route_map_lookup_match (match_name);
742 if (cmd == NULL)
743 return 1;
744
745 for (rule = index->match_list.head; rule; rule = rule->next)
746 if (rule->cmd == cmd &&
747 (rulecmp (rule->rule_str, match_arg) == 0 || match_arg == NULL))
748 {
749 route_map_rule_delete (&index->match_list, rule);
750 /* Execute event hook. */
751 if (route_map_master.event_hook)
518f0eb1
DS
752 {
753 (*route_map_master.event_hook) (RMAP_EVENT_MATCH_DELETED,
754 index->map->name);
755 route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
756 }
718e3744 757 return 0;
758 }
759 /* Can't find matched rule. */
760 return 1;
761}
762
763/* Add route-map set statement to the route map. */
764int
27a43a81 765route_map_add_set (struct route_map_index *index, const char *set_name,
c9eca01b 766 const char *set_arg)
718e3744 767{
768 struct route_map_rule *rule;
769 struct route_map_rule *next;
770 struct route_map_rule_cmd *cmd;
771 void *compile;
772 int replaced = 0;
773
774 cmd = route_map_lookup_set (set_name);
775 if (cmd == NULL)
776 return RMAP_RULE_MISSING;
777
778 /* Next call compile function for this match statement. */
779 if (cmd->func_compile)
780 {
781 compile= (*cmd->func_compile)(set_arg);
782 if (compile == NULL)
783 return RMAP_COMPILE_ERROR;
784 }
785 else
786 compile = NULL;
787
788 /* Add by WJL. if old set command of same kind exist, delete it first
789 to ensure only one set command of same kind exist under a
790 route_map_index. */
791 for (rule = index->set_list.head; rule; rule = next)
792 {
793 next = rule->next;
794 if (rule->cmd == cmd)
795 {
796 route_map_rule_delete (&index->set_list, rule);
797 replaced = 1;
798 }
799 }
800
801 /* Add new route map match rule. */
802 rule = route_map_rule_new ();
803 rule->cmd = cmd;
804 rule->value = compile;
805 if (set_arg)
806 rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, set_arg);
807 else
808 rule->rule_str = NULL;
809
810 /* Add new route match rule to linked list. */
811 route_map_rule_add (&index->set_list, rule);
812
813 /* Execute event hook. */
814 if (route_map_master.event_hook)
518f0eb1
DS
815 {
816 (*route_map_master.event_hook) (replaced ?
817 RMAP_EVENT_SET_REPLACED:
818 RMAP_EVENT_SET_ADDED,
819 index->map->name);
820 route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
821 }
718e3744 822 return 0;
823}
824
825/* Delete route map set rule. */
826int
27a43a81 827route_map_delete_set (struct route_map_index *index, const char *set_name,
c9eca01b 828 const char *set_arg)
718e3744 829{
830 struct route_map_rule *rule;
831 struct route_map_rule_cmd *cmd;
832
833 cmd = route_map_lookup_set (set_name);
834 if (cmd == NULL)
835 return 1;
836
837 for (rule = index->set_list.head; rule; rule = rule->next)
838 if ((rule->cmd == cmd) &&
839 (rulecmp (rule->rule_str, set_arg) == 0 || set_arg == NULL))
840 {
841 route_map_rule_delete (&index->set_list, rule);
842 /* Execute event hook. */
843 if (route_map_master.event_hook)
518f0eb1
DS
844 {
845 (*route_map_master.event_hook) (RMAP_EVENT_SET_DELETED,
846 index->map->name);
847 route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
848 }
718e3744 849 return 0;
850 }
851 /* Can't find matched rule. */
852 return 1;
853}
854
3bf1c917 855/* Apply route map's each index to the object.
856
857 The matrix for a route-map looks like this:
858 (note, this includes the description for the "NEXT"
859 and "GOTO" frobs now
860
861 Match | No Match
862 |
863 permit action | cont
864 |
865 ------------------+---------------
866 |
867 deny deny | cont
868 |
869
fee0f4c6 870 action)
871 -Apply Set statements, accept route
872 -If Call statement is present jump to the specified route-map, if it
873 denies the route we finish.
874 -If NEXT is specified, goto NEXT statement
875 -If GOTO is specified, goto the first clause where pref > nextpref
876 -If nothing is specified, do as Cisco and finish
877 deny)
878 -Route is denied by route-map.
879 cont)
880 -Goto Next index
3bf1c917 881
882 If we get no matches after we've processed all updates, then the route
883 is dropped too.
884
fee0f4c6 885 Some notes on the new "CALL", "NEXT" and "GOTO"
886 call WORD - If this clause is matched, then the set statements
887 are executed and then we jump to route-map 'WORD'. If
888 this route-map denies the route, we finish, in other case we
889 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
3bf1c917 890 on-match next - If this clause is matched, then the set statements
891 are executed and then we drop through to the next clause
892 on-match goto n - If this clause is matched, then the set statments
893 are executed and then we goto the nth clause, or the
894 first clause greater than this. In order to ensure
895 route-maps *always* exit, you cannot jump backwards.
896 Sorry ;)
897
898 We need to make sure our route-map processing matches the above
718e3744 899*/
3bf1c917 900
8cc4198f 901static route_map_result_t
3bf1c917 902route_map_apply_match (struct route_map_rule_list *match_list,
903 struct prefix *prefix, route_map_object_t type,
904 void *object)
718e3744 905{
3bf1c917 906 route_map_result_t ret = RMAP_NOMATCH;
718e3744 907 struct route_map_rule *match;
718e3744 908
718e3744 909
3bf1c917 910 /* Check all match rule and if there is no match rule, go to the
911 set statement. */
912 if (!match_list->head)
913 ret = RMAP_MATCH;
914 else
718e3744 915 {
3bf1c917 916 for (match = match_list->head; match; match = match->next)
917 {
918 /* Try each match statement in turn, If any do not return
919 RMAP_MATCH, return, otherwise continue on to next match
920 statement. All match statements must match for end-result
921 to be a match. */
922 ret = (*match->cmd->func_apply) (match->value, prefix,
923 type, object);
924 if (ret != RMAP_MATCH)
925 return ret;
926 }
718e3744 927 }
3bf1c917 928 return ret;
718e3744 929}
930
931/* Apply route map to the object. */
932route_map_result_t
3bf1c917 933route_map_apply (struct route_map *map, struct prefix *prefix,
934 route_map_object_t type, void *object)
718e3744 935{
fee0f4c6 936 static int recursion = 0;
718e3744 937 int ret = 0;
938 struct route_map_index *index;
3bf1c917 939 struct route_map_rule *set;
718e3744 940
fee0f4c6 941 if (recursion > RMAP_RECURSION_LIMIT)
942 {
943 zlog (NULL, LOG_WARNING,
944 "route-map recursion limit (%d) reached, discarding route",
945 RMAP_RECURSION_LIMIT);
946 recursion = 0;
947 return RMAP_DENYMATCH;
948 }
949
718e3744 950 if (map == NULL)
951 return RMAP_DENYMATCH;
952
953 for (index = map->head; index; index = index->next)
954 {
3bf1c917 955 /* Apply this index. */
956 ret = route_map_apply_match (&index->match_list, prefix, type, object);
957
958 /* Now we apply the matrix from above */
959 if (ret == RMAP_NOMATCH)
960 /* 'cont' from matrix - continue to next route-map sequence */
961 continue;
962 else if (ret == RMAP_MATCH)
963 {
964 if (index->type == RMAP_PERMIT)
965 /* 'action' */
966 {
967 /* permit+match must execute sets */
968 for (set = index->set_list.head; set; set = set->next)
969 ret = (*set->cmd->func_apply) (set->value, prefix,
970 type, object);
fee0f4c6 971
972 /* Call another route-map if available */
973 if (index->nextrm)
974 {
975 struct route_map *nextrm =
976 route_map_lookup_by_name (index->nextrm);
977
978 if (nextrm) /* Target route-map found, jump to it */
979 {
980 recursion++;
981 ret = route_map_apply (nextrm, prefix, type, object);
982 recursion--;
983 }
984
985 /* If nextrm returned 'deny', finish. */
986 if (ret == RMAP_DENYMATCH)
987 return ret;
988 }
989
3bf1c917 990 switch (index->exitpolicy)
991 {
992 case RMAP_EXIT:
993 return ret;
994 case RMAP_NEXT:
995 continue;
996 case RMAP_GOTO:
997 {
998 /* Find the next clause to jump to */
999 struct route_map_index *next = index->next;
fee0f4c6 1000 int nextpref = index->nextpref;
3bf1c917 1001
fee0f4c6 1002 while (next && next->pref < nextpref)
3bf1c917 1003 {
1004 index = next;
1005 next = next->next;
1006 }
1007 if (next == NULL)
1008 {
1009 /* No clauses match! */
1010 return ret;
1011 }
1012 }
1013 }
1014 }
1015 else if (index->type == RMAP_DENY)
1016 /* 'deny' */
1017 {
3bf1c917 1018 return RMAP_DENYMATCH;
1019 }
1020 }
718e3744 1021 }
1022 /* Finally route-map does not match at all. */
1023 return RMAP_DENYMATCH;
1024}
1025
1026void
9035efaa 1027route_map_add_hook (void (*func) (const char *))
718e3744 1028{
1029 route_map_master.add_hook = func;
1030}
1031
1032void
9035efaa 1033route_map_delete_hook (void (*func) (const char *))
718e3744 1034{
1035 route_map_master.delete_hook = func;
1036}
1037
1038void
9035efaa 1039route_map_event_hook (void (*func) (route_map_event_t, const char *))
718e3744 1040{
1041 route_map_master.event_hook = func;
1042}
1043
1044void
8cc4198f 1045route_map_init (void)
718e3744 1046{
1047 /* Make vector for match and set. */
1048 route_match_vec = vector_init (1);
1049 route_set_vec = vector_init (1);
1050}
228da428
CC
1051
1052void
1053route_map_finish (void)
1054{
1055 vector_free (route_match_vec);
1056 route_match_vec = NULL;
1057 vector_free (route_set_vec);
1058 route_set_vec = NULL;
1059}
6b0655a2 1060
518f0eb1
DS
1061/* Routines for route map dependency lists and dependency processing */
1062static int
1063route_map_rmap_hash_cmp (const void *p1, const void *p2)
1064{
1065 return (strcmp((char *)p1, (char *)p2) == 0);
1066}
1067
1068static int
1069route_map_dep_hash_cmp (const void *p1, const void *p2)
1070{
1071
1072 return (strcmp (((struct route_map_dep *)p1)->dep_name, (char *)p2) == 0);
1073}
1074
1075static void
1076route_map_rmap_free(struct hash_backet *backet, void *arg)
1077{
1078 char *rmap_name = (char *)backet->data;
1079
1080 if (rmap_name)
1081 XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
1082}
1083
1084static void
1085route_map_dep_hash_free (struct hash_backet *backet, void *arg)
1086{
1087 struct route_map_dep *dep = (struct route_map_dep *)backet->data;
1088
1089 if (!dep)
1090 return;
1091
1092 if (dep->dep_rmap_hash)
1093 hash_iterate (dep->dep_rmap_hash, route_map_rmap_free, (void *)NULL);
1094
1095 hash_free(dep->dep_rmap_hash);
1096 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
1097 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
1098}
1099
1100static void
1101route_map_clear_reference(struct hash_backet *backet, void *arg)
1102{
1103 struct route_map_dep *dep = (struct route_map_dep *)backet->data;
1104 char *rmap_name;
1105
1106 if (dep && arg)
1107 {
1108 rmap_name = (char *)hash_release(dep->dep_rmap_hash, (void *)arg);
1109 if (rmap_name)
1110 {
1111 XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
1112 }
1113 if (!dep->dep_rmap_hash->count)
1114 {
1115 dep = hash_release(dep->this_hash, (void *)dep->dep_name);
1116 hash_free(dep->dep_rmap_hash);
1117 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
1118 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
1119 }
1120 }
1121}
1122
1123static void
1124route_map_clear_all_references (char *rmap_name)
1125{
1126 int i;
1127
1128 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
1129 {
1130 hash_iterate(route_map_dep_hash[i], route_map_clear_reference,
1131 (void *)rmap_name);
1132 }
1133}
1134
1135static void *
1136route_map_dep_hash_alloc(void *p)
1137{
1138 char *dep_name = (char *)p;
1139 struct route_map_dep *dep_entry;
1140
1141 dep_entry = XCALLOC(MTYPE_ROUTE_MAP_DEP, sizeof(struct route_map_dep));
1142 dep_entry->dep_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
1143 dep_entry->dep_rmap_hash = hash_create(route_map_dep_hash_make_key,
1144 route_map_rmap_hash_cmp);
1145 dep_entry->this_hash = NULL;
1146
1147 return((void *)dep_entry);
1148}
1149
1150static void *
1151route_map_name_hash_alloc(void *p)
1152{
1153 return((void *)XSTRDUP(MTYPE_ROUTE_MAP_NAME, (char *)p));
1154}
1155
1156static unsigned int
1157route_map_dep_hash_make_key (void *p)
1158{
1159 return (string_hash_make((char *)p));
1160}
1161
1162static void
1163route_map_print_dependency (struct hash_backet *backet, void *data)
1164{
1165 char *rmap_name = (char *)backet->data;
1166 char *dep_name = (char *)data;
1167
1168 if (rmap_name)
1169 zlog_debug("%s: Dependency for %s: %s", __FUNCTION__, dep_name, rmap_name);
1170}
1171
1172static int
1173route_map_dep_update (struct hash *dephash, const char *dep_name,
1174 const char *rmap_name,
1175 route_map_event_t type)
1176{
1177 struct route_map_dep *dep;
1178 char *ret_map_name;
1179
1180 switch (type)
1181 {
1182 case RMAP_EVENT_PLIST_ADDED:
1183 case RMAP_EVENT_CLIST_ADDED:
1184 case RMAP_EVENT_ECLIST_ADDED:
1185 case RMAP_EVENT_ASLIST_ADDED:
1186 case RMAP_EVENT_CALL_ADDED:
1187 case RMAP_EVENT_FILTER_ADDED:
1188 if (rmap_debug)
1189 zlog_debug("%s: Adding dependency for %s in %s", __FUNCTION__,
1190 dep_name, rmap_name);
1191 dep = (struct route_map_dep *) hash_get (dephash, (void *)dep_name,
1192 route_map_dep_hash_alloc);
1193 if (!dep)
1194 return -1;
1195
1196 if (!dep->this_hash)
1197 dep->this_hash = dephash;
1198
1199 hash_get(dep->dep_rmap_hash, rmap_name, route_map_name_hash_alloc);
1200 break;
1201 case RMAP_EVENT_PLIST_DELETED:
1202 case RMAP_EVENT_CLIST_DELETED:
1203 case RMAP_EVENT_ECLIST_DELETED:
1204 case RMAP_EVENT_ASLIST_DELETED:
1205 case RMAP_EVENT_CALL_DELETED:
1206 case RMAP_EVENT_FILTER_DELETED:
1207 if (rmap_debug)
1208 zlog_debug("%s: Deleting dependency for %s in %s", __FUNCTION__,
1209 dep_name, rmap_name);
1210 dep = (struct route_map_dep *) hash_get (dephash, (void *)dep_name,
1211 NULL);
1212 if (!dep)
1213 return 0;
1214 ret_map_name = (char *)hash_release(dep->dep_rmap_hash, (void *)rmap_name);
1215 if (ret_map_name)
1216 XFREE(MTYPE_ROUTE_MAP_NAME, ret_map_name);
1217
1218 if (!dep->dep_rmap_hash->count)
1219 {
1220 dep = hash_release(dephash, (void *)dep_name);
1221 hash_free(dep->dep_rmap_hash);
1222 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
1223 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
1224 dep = NULL;
1225 }
1226 break;
1227 default:
1228 break;
1229 }
1230
1231 if (dep)
1232 {
1233 if (rmap_debug)
1234 hash_iterate (dep->dep_rmap_hash, route_map_print_dependency, (void *)dep_name);
1235 }
1236 return 0;
1237}
1238
1239static struct hash *
1240route_map_get_dep_hash (route_map_event_t event)
1241{
1242 struct hash *upd8_hash = NULL;
1243
1244 switch (event)
1245 {
1246 case RMAP_EVENT_PLIST_ADDED:
1247 case RMAP_EVENT_PLIST_DELETED:
1248 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_PLIST];
1249 break;
1250 case RMAP_EVENT_CLIST_ADDED:
1251 case RMAP_EVENT_CLIST_DELETED:
1252 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_CLIST];
1253 break;
1254 case RMAP_EVENT_ECLIST_ADDED:
1255 case RMAP_EVENT_ECLIST_DELETED:
1256 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ECLIST];
1257 break;
1258 case RMAP_EVENT_ASLIST_ADDED:
1259 case RMAP_EVENT_ASLIST_DELETED:
1260 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ASPATH];
1261 break;
1262 case RMAP_EVENT_CALL_ADDED:
1263 case RMAP_EVENT_CALL_DELETED:
1264 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_RMAP];
1265 break;
1266 case RMAP_EVENT_FILTER_ADDED:
1267 case RMAP_EVENT_FILTER_DELETED:
1268 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_FILTER];
1269 break;
1270 default:
1271 upd8_hash = NULL;
1272 break;
1273 }
1274 return (upd8_hash);
1275}
1276
1277static void
1278route_map_process_dependency (struct hash_backet *backet, void *data)
1279{
1280 char *rmap_name;
1281 route_map_event_t type = (route_map_event_t )data;
1282
1283 rmap_name = (char *)backet->data;
1284
1285 if (rmap_name)
1286 {
1287 if (rmap_debug)
1288 zlog_debug("%s: Notifying %s of dependency", __FUNCTION__,
1289 rmap_name);
1290 if (route_map_master.event_hook)
1291 (*route_map_master.event_hook) (type, rmap_name);
1292 }
1293}
1294
1295void
1296route_map_upd8_dependency (route_map_event_t type, const char *arg,
1297 const char *rmap_name)
1298{
1299 struct hash *upd8_hash = NULL;
1300
1301 if ((upd8_hash = route_map_get_dep_hash(type)))
1302 route_map_dep_update (upd8_hash, arg, rmap_name, type);
1303}
1304
1305void
1306route_map_notify_dependencies (const char *affected_name, route_map_event_t event)
1307{
1308 struct route_map_dep *dep;
1309 struct hash *upd8_hash;
1310
1311 if (!affected_name)
1312 return;
1313
1314 if ((upd8_hash = route_map_get_dep_hash(event)) == NULL)
1315 return;
1316
1317 dep = (struct route_map_dep *)hash_get (upd8_hash, (void *)affected_name,
1318 NULL);
1319 if (dep)
1320 {
1321 if (!dep->this_hash)
1322 dep->this_hash = upd8_hash;
1323
1324 hash_iterate (dep->dep_rmap_hash, route_map_process_dependency, (void *)event);
1325 }
1326}
1327
718e3744 1328/* VTY related functions. */
1329DEFUN (route_map,
1330 route_map_cmd,
1331 "route-map WORD (deny|permit) <1-65535>",
1332 "Create route-map or enter route-map command mode\n"
1333 "Route map tag\n"
1334 "Route map denies set operations\n"
1335 "Route map permits set operations\n"
1336 "Sequence to insert to/delete from existing route-map entry\n")
1337{
1338 int permit;
1339 unsigned long pref;
1340 struct route_map *map;
1341 struct route_map_index *index;
1342 char *endptr = NULL;
1343
1344 /* Permit check. */
1345 if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
1346 permit = RMAP_PERMIT;
1347 else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
1348 permit = RMAP_DENY;
1349 else
1350 {
1351 vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
1352 return CMD_WARNING;
1353 }
1354
1355 /* Preference check. */
1356 pref = strtoul (argv[2], &endptr, 10);
1357 if (pref == ULONG_MAX || *endptr != '\0')
1358 {
1359 vty_out (vty, "the fourth field must be positive integer%s",
1360 VTY_NEWLINE);
1361 return CMD_WARNING;
1362 }
1363 if (pref == 0 || pref > 65535)
1364 {
1365 vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
1366 return CMD_WARNING;
1367 }
1368
1369 /* Get route map. */
1370 map = route_map_get (argv[0]);
1371 index = route_map_index_get (map, permit, pref);
1372
1373 vty->index = index;
1374 vty->node = RMAP_NODE;
1375 return CMD_SUCCESS;
1376}
1377
1378DEFUN (no_route_map_all,
1379 no_route_map_all_cmd,
1380 "no route-map WORD",
1381 NO_STR
1382 "Create route-map or enter route-map command mode\n"
1383 "Route map tag\n")
1384{
1385 struct route_map *map;
1386
1387 map = route_map_lookup_by_name (argv[0]);
1388 if (map == NULL)
1389 {
1390 vty_out (vty, "%% Could not find route-map %s%s",
1391 argv[0], VTY_NEWLINE);
1392 return CMD_WARNING;
1393 }
1394
1395 route_map_delete (map);
1396
1397 return CMD_SUCCESS;
1398}
1399
1400DEFUN (no_route_map,
1401 no_route_map_cmd,
1402 "no route-map WORD (deny|permit) <1-65535>",
1403 NO_STR
1404 "Create route-map or enter route-map command mode\n"
1405 "Route map tag\n"
1406 "Route map denies set operations\n"
1407 "Route map permits set operations\n"
1408 "Sequence to insert to/delete from existing route-map entry\n")
1409{
1410 int permit;
1411 unsigned long pref;
1412 struct route_map *map;
1413 struct route_map_index *index;
1414 char *endptr = NULL;
1415
1416 /* Permit check. */
1417 if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
1418 permit = RMAP_PERMIT;
1419 else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
1420 permit = RMAP_DENY;
1421 else
1422 {
1423 vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
1424 return CMD_WARNING;
1425 }
1426
1427 /* Preference. */
1428 pref = strtoul (argv[2], &endptr, 10);
1429 if (pref == ULONG_MAX || *endptr != '\0')
1430 {
1431 vty_out (vty, "the fourth field must be positive integer%s",
1432 VTY_NEWLINE);
1433 return CMD_WARNING;
1434 }
1435 if (pref == 0 || pref > 65535)
1436 {
1437 vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
1438 return CMD_WARNING;
1439 }
1440
1441 /* Existence check. */
1442 map = route_map_lookup_by_name (argv[0]);
1443 if (map == NULL)
1444 {
1445 vty_out (vty, "%% Could not find route-map %s%s",
1446 argv[0], VTY_NEWLINE);
1447 return CMD_WARNING;
1448 }
1449
1450 /* Lookup route map index. */
1451 index = route_map_index_lookup (map, permit, pref);
1452 if (index == NULL)
1453 {
1454 vty_out (vty, "%% Could not find route-map entry %s %s%s",
1455 argv[0], argv[2], VTY_NEWLINE);
1456 return CMD_WARNING;
1457 }
1458
1459 /* Delete index from route map. */
1460 route_map_index_delete (index, 1);
1461
1462 /* If this route rule is the last one, delete route map itself. */
1463 if (route_map_empty (map))
1464 route_map_delete (map);
1465
1466 return CMD_SUCCESS;
1467}
1468
1469DEFUN (rmap_onmatch_next,
1470 rmap_onmatch_next_cmd,
1471 "on-match next",
1472 "Exit policy on matches\n"
1473 "Next clause\n")
1474{
1475 struct route_map_index *index;
1476
1477 index = vty->index;
1478
1479 if (index)
1480 index->exitpolicy = RMAP_NEXT;
1481
1482 return CMD_SUCCESS;
1483}
1484
1485DEFUN (no_rmap_onmatch_next,
1486 no_rmap_onmatch_next_cmd,
1487 "no on-match next",
1488 NO_STR
1489 "Exit policy on matches\n"
1490 "Next clause\n")
1491{
1492 struct route_map_index *index;
1493
1494 index = vty->index;
1495
1496 if (index)
1497 index->exitpolicy = RMAP_EXIT;
1498
1499 return CMD_SUCCESS;
1500}
1501
1502DEFUN (rmap_onmatch_goto,
1503 rmap_onmatch_goto_cmd,
1504 "on-match goto <1-65535>",
1505 "Exit policy on matches\n"
1506 "Goto Clause number\n"
1507 "Number\n")
1508{
d4f0960c 1509 struct route_map_index *index = vty->index;
718e3744 1510 int d = 0;
1511
718e3744 1512 if (index)
1513 {
d4f0960c 1514 if (argc == 1 && argv[0])
1515 VTY_GET_INTEGER_RANGE("route-map index", d, argv[0], 1, 65536);
1516 else
1517 d = index->pref + 1;
1518
718e3744 1519 if (d <= index->pref)
1520 {
1521 /* Can't allow you to do that, Dave */
1522 vty_out (vty, "can't jump backwards in route-maps%s",
1523 VTY_NEWLINE);
1524 return CMD_WARNING;
1525 }
1526 else
1527 {
1528 index->exitpolicy = RMAP_GOTO;
1529 index->nextpref = d;
1530 }
1531 }
1532 return CMD_SUCCESS;
1533}
1534
1535DEFUN (no_rmap_onmatch_goto,
1536 no_rmap_onmatch_goto_cmd,
1537 "no on-match goto",
1538 NO_STR
1539 "Exit policy on matches\n"
fee0f4c6 1540 "Goto Clause number\n")
718e3744 1541{
1542 struct route_map_index *index;
1543
1544 index = vty->index;
1545
1546 if (index)
1547 index->exitpolicy = RMAP_EXIT;
1548
1549 return CMD_SUCCESS;
1550}
1551
5510e83b 1552/* Cisco/GNU Zebra compatible ALIASes for on-match next */
1553ALIAS (rmap_onmatch_goto,
1554 rmap_continue_cmd,
1555 "continue",
1556 "Continue on a different entry within the route-map\n")
1557
1558ALIAS (no_rmap_onmatch_goto,
1559 no_rmap_continue_cmd,
1560 "no continue",
1561 NO_STR
1562 "Continue on a different entry within the route-map\n")
1563
1564/* GNU Zebra compatible */
1565ALIAS (rmap_onmatch_goto,
1566 rmap_continue_seq_cmd,
1567 "continue <1-65535>",
1568 "Continue on a different entry within the route-map\n"
1569 "Route-map entry sequence number\n")
1570
1571ALIAS (no_rmap_onmatch_goto,
1572 no_rmap_continue_seq,
1573 "no continue <1-65535>",
1574 NO_STR
1575 "Continue on a different entry within the route-map\n"
1576 "Route-map entry sequence number\n")
1577
5510e83b 1578DEFUN (rmap_show_name,
1579 rmap_show_name_cmd,
7514fb77 1580 "show route-map [WORD]",
5510e83b 1581 SHOW_STR
1582 "route-map information\n"
1583 "route-map name\n")
1584{
7514fb77
PJ
1585 const char *name = NULL;
1586 if (argc)
1587 name = argv[0];
1588 return vty_show_route_map (vty, name);
5510e83b 1589}
1590
fee0f4c6 1591ALIAS (rmap_onmatch_goto,
1592 rmap_continue_index_cmd,
1593 "continue <1-65536>",
1594 "Exit policy on matches\n"
1595 "Goto Clause number\n")
1596
1597DEFUN (rmap_call,
1598 rmap_call_cmd,
1599 "call WORD",
1600 "Jump to another Route-Map after match+set\n"
1601 "Target route-map name\n")
1602{
1603 struct route_map_index *index;
1604
1605 index = vty->index;
1606 if (index)
1607 {
1608 if (index->nextrm)
518f0eb1
DS
1609 {
1610 route_map_upd8_dependency (RMAP_EVENT_CALL_DELETED,
1611 index->nextrm,
1612 index->map->name);
1613 XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
1614 }
0241684e 1615 index->nextrm = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[0]);
fee0f4c6 1616 }
518f0eb1
DS
1617
1618 /* Execute event hook. */
1619 route_map_upd8_dependency (RMAP_EVENT_CALL_ADDED,
1620 index->nextrm,
1621 index->map->name);
fee0f4c6 1622 return CMD_SUCCESS;
1623}
1624
1625DEFUN (no_rmap_call,
1626 no_rmap_call_cmd,
1627 "no call",
1628 NO_STR
1629 "Jump to another Route-Map after match+set\n")
1630{
1631 struct route_map_index *index;
1632
1633 index = vty->index;
1634
1635 if (index->nextrm)
1636 {
518f0eb1
DS
1637 route_map_upd8_dependency (RMAP_EVENT_CALL_DELETED,
1638 index->nextrm,
1639 index->map->name);
0241684e 1640 XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
fee0f4c6 1641 index->nextrm = NULL;
1642 }
1643
1644 return CMD_SUCCESS;
1645}
1646
4a8164e5 1647DEFUN (rmap_description,
1648 rmap_description_cmd,
1649 "description .LINE",
1650 "Route-map comment\n"
1651 "Comment describing this route-map rule\n")
1652{
1653 struct route_map_index *index;
1654
1655 index = vty->index;
1656 if (index)
1657 {
1658 if (index->description)
1659 XFREE (MTYPE_TMP, index->description);
1660 index->description = argv_concat (argv, argc, 0);
1661 }
1662 return CMD_SUCCESS;
1663}
1664
1665DEFUN (no_rmap_description,
1666 no_rmap_description_cmd,
1667 "no description",
1668 NO_STR
1669 "Route-map comment\n")
1670{
1671 struct route_map_index *index;
1672
1673 index = vty->index;
1674 if (index)
1675 {
1676 if (index->description)
1677 XFREE (MTYPE_TMP, index->description);
1678 index->description = NULL;
1679 }
1680 return CMD_SUCCESS;
1681}
1682
718e3744 1683/* Configuration write function. */
8cc4198f 1684static int
718e3744 1685route_map_config_write (struct vty *vty)
1686{
1687 struct route_map *map;
1688 struct route_map_index *index;
1689 struct route_map_rule *rule;
1690 int first = 1;
1691 int write = 0;
1692
1693 for (map = route_map_master.head; map; map = map->next)
1694 for (index = map->head; index; index = index->next)
1695 {
1696 if (!first)
1697 vty_out (vty, "!%s", VTY_NEWLINE);
1698 else
1699 first = 0;
1700
1701 vty_out (vty, "route-map %s %s %d%s",
1702 map->name,
1703 route_map_type_str (index->type),
1704 index->pref, VTY_NEWLINE);
1705
4a8164e5 1706 if (index->description)
1707 vty_out (vty, " description %s%s", index->description, VTY_NEWLINE);
1708
718e3744 1709 for (rule = index->match_list.head; rule; rule = rule->next)
1710 vty_out (vty, " match %s %s%s", rule->cmd->str,
1711 rule->rule_str ? rule->rule_str : "",
1712 VTY_NEWLINE);
1713
1714 for (rule = index->set_list.head; rule; rule = rule->next)
1715 vty_out (vty, " set %s %s%s", rule->cmd->str,
1716 rule->rule_str ? rule->rule_str : "",
1717 VTY_NEWLINE);
fee0f4c6 1718 if (index->nextrm)
1719 vty_out (vty, " call %s%s", index->nextrm, VTY_NEWLINE);
718e3744 1720 if (index->exitpolicy == RMAP_GOTO)
fee0f4c6 1721 vty_out (vty, " on-match goto %d%s", index->nextpref, VTY_NEWLINE);
718e3744 1722 if (index->exitpolicy == RMAP_NEXT)
1723 vty_out (vty," on-match next%s", VTY_NEWLINE);
1724
1725 write++;
1726 }
1727 return write;
1728}
1729
1730/* Route map node structure. */
7fc626de 1731static struct cmd_node rmap_node =
718e3744 1732{
1733 RMAP_NODE,
1734 "%s(config-route-map)# ",
1735 1
1736};
1737
518f0eb1
DS
1738static void
1739route_map_init_dep_hashes (void)
1740{
1741 int i;
1742
1743 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
1744 route_map_dep_hash[i] = hash_create(route_map_dep_hash_make_key,
1745 route_map_dep_hash_cmp);
1746}
1747
718e3744 1748/* Initialization of route map vector. */
1749void
8cc4198f 1750route_map_init_vty (void)
718e3744 1751{
518f0eb1
DS
1752 route_map_init_dep_hashes();
1753
718e3744 1754 /* Install route map top node. */
1755 install_node (&rmap_node, route_map_config_write);
1756
1757 /* Install route map commands. */
1758 install_default (RMAP_NODE);
1759 install_element (CONFIG_NODE, &route_map_cmd);
1760 install_element (CONFIG_NODE, &no_route_map_cmd);
1761 install_element (CONFIG_NODE, &no_route_map_all_cmd);
1762
1763 /* Install the on-match stuff */
1764 install_element (RMAP_NODE, &route_map_cmd);
1765 install_element (RMAP_NODE, &rmap_onmatch_next_cmd);
1766 install_element (RMAP_NODE, &no_rmap_onmatch_next_cmd);
1767 install_element (RMAP_NODE, &rmap_onmatch_goto_cmd);
1768 install_element (RMAP_NODE, &no_rmap_onmatch_goto_cmd);
fee0f4c6 1769
1770 /* Install the continue stuff (ALIAS of on-match). */
1771 install_element (RMAP_NODE, &rmap_continue_cmd);
1772 install_element (RMAP_NODE, &no_rmap_continue_cmd);
1773 install_element (RMAP_NODE, &rmap_continue_index_cmd);
1774
1775 /* Install the call stuff. */
1776 install_element (RMAP_NODE, &rmap_call_cmd);
1777 install_element (RMAP_NODE, &no_rmap_call_cmd);
4a8164e5 1778
1779 /* Install description commands. */
1780 install_element (RMAP_NODE, &rmap_description_cmd);
1781 install_element (RMAP_NODE, &no_rmap_description_cmd);
fee0f4c6 1782
5510e83b 1783 /* Install show command */
5510e83b 1784 install_element (ENABLE_NODE, &rmap_show_name_cmd);
718e3744 1785}