blob: b000f2fc0d317cab9b4e4602401acd10299ca1b2 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* 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"
29
30/* Vector for route match rules. */
31static vector route_match_vec;
32
33/* Vector for route set rules. */
34static vector route_set_vec;
35
36/* Route map rule. This rule has both `match' rule and `set' rule. */
37struct route_map_rule
38{
39 /* Rule type. */
40 struct route_map_rule_cmd *cmd;
41
42 /* For pretty printing. */
43 char *rule_str;
44
45 /* Pre-compiled match rule. */
46 void *value;
47
48 /* Linked list. */
49 struct route_map_rule *next;
50 struct route_map_rule *prev;
51};
52
53/* Making route map list. */
54struct route_map_list
55{
56 struct route_map *head;
57 struct route_map *tail;
58
59 void (*add_hook) (char *);
60 void (*delete_hook) (char *);
61 void (*event_hook) (route_map_event_t, char *);
62};
63
64/* Master list of route map. */
65static struct route_map_list route_map_master = { NULL, NULL, NULL, NULL };
66
67static void
68route_map_rule_delete (struct route_map_rule_list *,
69 struct route_map_rule *);
70
71static void
72route_map_index_delete (struct route_map_index *, int);
73
74/* New route map allocation. Please note route map's name must be
75 specified. */
76static struct route_map *
77route_map_new (char *name)
78{
79 struct route_map *new;
80
81 new = XCALLOC (MTYPE_ROUTE_MAP, sizeof (struct route_map));
82 new->name = XSTRDUP (MTYPE_ROUTE_MAP_NAME, name);
83 return new;
84}
85
86/* Add new name to route_map. */
87static struct route_map *
88route_map_add (char *name)
89{
90 struct route_map *map;
91 struct route_map_list *list;
92
93 map = route_map_new (name);
94 list = &route_map_master;
95
96 map->next = NULL;
97 map->prev = list->tail;
98 if (list->tail)
99 list->tail->next = map;
100 else
101 list->head = map;
102 list->tail = map;
103
104 /* Execute hook. */
105 if (route_map_master.add_hook)
106 (*route_map_master.add_hook) (name);
107
108 return map;
109}
110
111/* Route map delete from list. */
112static void
113route_map_delete (struct route_map *map)
114{
115 struct route_map_list *list;
116 struct route_map_index *index;
117 char *name;
118
119 while ((index = map->head) != NULL)
120 route_map_index_delete (index, 0);
121
122 name = map->name;
123
124 list = &route_map_master;
125
126 if (map->next)
127 map->next->prev = map->prev;
128 else
129 list->tail = map->prev;
130
131 if (map->prev)
132 map->prev->next = map->next;
133 else
134 list->head = map->next;
135
136 XFREE (MTYPE_ROUTE_MAP, map);
137
138 /* Execute deletion hook. */
139 if (route_map_master.delete_hook)
140 (*route_map_master.delete_hook) (name);
141
142 if (name)
143 XFREE (MTYPE_ROUTE_MAP_NAME, name);
144
145}
146
147/* Lookup route map by route map name string. */
148struct route_map *
149route_map_lookup_by_name (char *name)
150{
151 struct route_map *map;
152
153 for (map = route_map_master.head; map; map = map->next)
154 if (strcmp (map->name, name) == 0)
155 return map;
156 return NULL;
157}
158
159/* Lookup route map. If there isn't route map create one and return
160 it. */
161struct route_map *
162route_map_get (char *name)
163{
164 struct route_map *map;
165
166 map = route_map_lookup_by_name (name);
167 if (map == NULL)
168 map = route_map_add (name);
169 return map;
170}
171
172/* Return route map's type string. */
173static char *
174route_map_type_str (enum route_map_type type)
175{
176 switch (type)
177 {
178 case RMAP_PERMIT:
179 return "permit";
180 break;
181 case RMAP_DENY:
182 return "deny";
183 break;
184 default:
185 return "";
186 break;
187 }
188}
189
190int
191route_map_empty (struct route_map *map)
192{
193 if (map->head == NULL && map->tail == NULL)
194 return 1;
195 else
196 return 0;
197}
198
199/* For debug. */
200void
201route_map_print ()
202{
203 struct route_map *map;
204 struct route_map_index *index;
205 struct route_map_rule *rule;
206
207 for (map = route_map_master.head; map; map = map->next)
208 for (index = map->head; index; index = index->next)
209 {
210 printf ("route-map %s %s %d\n",
211 map->name,
212 route_map_type_str (index->type),
213 index->pref);
214 for (rule = index->match_list.head; rule; rule = rule->next)
215 printf (" match %s %s\n", rule->cmd->str, rule->rule_str);
216 for (rule = index->set_list.head; rule; rule = rule->next)
217 printf (" set %s %s\n", rule->cmd->str, rule->rule_str);
218 if (index->exitpolicy == RMAP_GOTO)
219 printf (" on-match goto %d\n", index->nextpref);
220 if (index->exitpolicy == RMAP_NEXT)
221 printf (" on-match next\n");
222 }
223}
224
225/* New route map allocation. Please note route map's name must be
226 specified. */
227struct route_map_index *
228route_map_index_new ()
229{
230 struct route_map_index *new;
231
232 new = XCALLOC (MTYPE_ROUTE_MAP_INDEX, sizeof (struct route_map_index));
233 new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */
234 return new;
235}
236
237/* Free route map index. */
238static void
239route_map_index_delete (struct route_map_index *index, int notify)
240{
241 struct route_map_rule *rule;
242
243 /* Free route match. */
244 while ((rule = index->match_list.head) != NULL)
245 route_map_rule_delete (&index->match_list, rule);
246
247 /* Free route set. */
248 while ((rule = index->set_list.head) != NULL)
249 route_map_rule_delete (&index->set_list, rule);
250
251 /* Remove index from route map list. */
252 if (index->next)
253 index->next->prev = index->prev;
254 else
255 index->map->tail = index->prev;
256
257 if (index->prev)
258 index->prev->next = index->next;
259 else
260 index->map->head = index->next;
261
262 /* Execute event hook. */
263 if (route_map_master.event_hook && notify)
264 (*route_map_master.event_hook) (RMAP_EVENT_INDEX_DELETED,
265 index->map->name);
266
267 XFREE (MTYPE_ROUTE_MAP_INDEX, index);
268}
269
270/* Lookup index from route map. */
271struct route_map_index *
272route_map_index_lookup (struct route_map *map, enum route_map_type type,
273 int pref)
274{
275 struct route_map_index *index;
276
277 for (index = map->head; index; index = index->next)
278 if ((index->type == type || type == RMAP_ANY)
279 && index->pref == pref)
280 return index;
281 return NULL;
282}
283
284/* Add new index to route map. */
285struct route_map_index *
286route_map_index_add (struct route_map *map, enum route_map_type type,
287 int pref)
288{
289 struct route_map_index *index;
290 struct route_map_index *point;
291
292 /* Allocate new route map inex. */
293 index = route_map_index_new ();
294 index->map = map;
295 index->type = type;
296 index->pref = pref;
297
298 /* Compare preference. */
299 for (point = map->head; point; point = point->next)
300 if (point->pref >= pref)
301 break;
302
303 if (map->head == NULL)
304 {
305 map->head = map->tail = index;
306 }
307 else if (point == NULL)
308 {
309 index->prev = map->tail;
310 map->tail->next = index;
311 map->tail = index;
312 }
313 else if (point == map->head)
314 {
315 index->next = map->head;
316 map->head->prev = index;
317 map->head = index;
318 }
319 else
320 {
321 index->next = point;
322 index->prev = point->prev;
323 if (point->prev)
324 point->prev->next = index;
325 point->prev = index;
326 }
327
328 /* Execute event hook. */
329 if (route_map_master.event_hook)
330 (*route_map_master.event_hook) (RMAP_EVENT_INDEX_ADDED,
331 map->name);
332
333 return index;
334}
335
336/* Get route map index. */
337struct route_map_index *
338route_map_index_get (struct route_map *map, enum route_map_type type,
339 int pref)
340{
341 struct route_map_index *index;
342
343 index = route_map_index_lookup (map, RMAP_ANY, pref);
344 if (index && index->type != type)
345 {
346 /* Delete index from route map. */
347 route_map_index_delete (index, 1);
348 index = NULL;
349 }
350 if (index == NULL)
351 index = route_map_index_add (map, type, pref);
352 return index;
353}
354
355/* New route map rule */
356struct route_map_rule *
357route_map_rule_new ()
358{
359 struct route_map_rule *new;
360
361 new = XCALLOC (MTYPE_ROUTE_MAP_RULE, sizeof (struct route_map_rule));
362 return new;
363}
364
365/* Install rule command to the match list. */
366void
367route_map_install_match (struct route_map_rule_cmd *cmd)
368{
369 vector_set (route_match_vec, cmd);
370}
371
372/* Install rule command to the set list. */
373void
374route_map_install_set (struct route_map_rule_cmd *cmd)
375{
376 vector_set (route_set_vec, cmd);
377}
378
379/* Lookup rule command from match list. */
380struct route_map_rule_cmd *
381route_map_lookup_match (char *name)
382{
383 int i;
384 struct route_map_rule_cmd *rule;
385
386 for (i = 0; i < vector_max (route_match_vec); i++)
387 if ((rule = vector_slot (route_match_vec, i)) != NULL)
388 if (strcmp (rule->str, name) == 0)
389 return rule;
390 return NULL;
391}
392
393/* Lookup rule command from set list. */
394struct route_map_rule_cmd *
395route_map_lookup_set (char *name)
396{
397 int i;
398 struct route_map_rule_cmd *rule;
399
400 for (i = 0; i < vector_max (route_set_vec); i++)
401 if ((rule = vector_slot (route_set_vec, i)) != NULL)
402 if (strcmp (rule->str, name) == 0)
403 return rule;
404 return NULL;
405}
406
407/* Add match and set rule to rule list. */
408static void
409route_map_rule_add (struct route_map_rule_list *list,
410 struct route_map_rule *rule)
411{
412 rule->next = NULL;
413 rule->prev = list->tail;
414 if (list->tail)
415 list->tail->next = rule;
416 else
417 list->head = rule;
418 list->tail = rule;
419}
420
421/* Delete rule from rule list. */
422static void
423route_map_rule_delete (struct route_map_rule_list *list,
424 struct route_map_rule *rule)
425{
426 if (rule->cmd->func_free)
427 (*rule->cmd->func_free) (rule->value);
428
429 if (rule->rule_str)
430 XFREE (MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str);
431
432 if (rule->next)
433 rule->next->prev = rule->prev;
434 else
435 list->tail = rule->prev;
436 if (rule->prev)
437 rule->prev->next = rule->next;
438 else
439 list->head = rule->next;
440
441 XFREE (MTYPE_ROUTE_MAP_RULE, rule);
442}
443
444/* strcmp wrapper function which don't crush even argument is NULL. */
445int
446rulecmp (char *dst, char *src)
447{
448 if (dst == NULL)
449 {
450 if (src == NULL)
451 return 0;
452 else
453 return 1;
454 }
455 else
456 {
457 if (src == NULL)
458 return 1;
459 else
460 return strcmp (dst, src);
461 }
462 return 1;
463}
464
465/* Add match statement to route map. */
466int
467route_map_add_match (struct route_map_index *index, char *match_name,
468 char *match_arg)
469{
470 struct route_map_rule *rule;
471 struct route_map_rule *next;
472 struct route_map_rule_cmd *cmd;
473 void *compile;
474 int replaced = 0;
475
476 /* First lookup rule for add match statement. */
477 cmd = route_map_lookup_match (match_name);
478 if (cmd == NULL)
479 return RMAP_RULE_MISSING;
480
481 /* Next call compile function for this match statement. */
482 if (cmd->func_compile)
483 {
484 compile= (*cmd->func_compile)(match_arg);
485 if (compile == NULL)
486 return RMAP_COMPILE_ERROR;
487 }
488 else
489 compile = NULL;
490
491 /* If argument is completely same ignore it. */
492 for (rule = index->match_list.head; rule; rule = next)
493 {
494 next = rule->next;
495 if (rule->cmd == cmd)
496 {
497 route_map_rule_delete (&index->match_list, rule);
498 replaced = 1;
499 }
500 }
501
502 /* Add new route map match rule. */
503 rule = route_map_rule_new ();
504 rule->cmd = cmd;
505 rule->value = compile;
506 if (match_arg)
507 rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, match_arg);
508 else
509 rule->rule_str = NULL;
510
511 /* Add new route match rule to linked list. */
512 route_map_rule_add (&index->match_list, rule);
513
514 /* Execute event hook. */
515 if (route_map_master.event_hook)
516 (*route_map_master.event_hook) (replaced ?
517 RMAP_EVENT_MATCH_REPLACED:
518 RMAP_EVENT_MATCH_ADDED,
519 index->map->name);
520
521 return 0;
522}
523
524/* Delete specified route match rule. */
525int
526route_map_delete_match (struct route_map_index *index, char *match_name,
527 char *match_arg)
528{
529 struct route_map_rule *rule;
530 struct route_map_rule_cmd *cmd;
531
532 cmd = route_map_lookup_match (match_name);
533 if (cmd == NULL)
534 return 1;
535
536 for (rule = index->match_list.head; rule; rule = rule->next)
537 if (rule->cmd == cmd &&
538 (rulecmp (rule->rule_str, match_arg) == 0 || match_arg == NULL))
539 {
540 route_map_rule_delete (&index->match_list, rule);
541 /* Execute event hook. */
542 if (route_map_master.event_hook)
543 (*route_map_master.event_hook) (RMAP_EVENT_MATCH_DELETED,
544 index->map->name);
545 return 0;
546 }
547 /* Can't find matched rule. */
548 return 1;
549}
550
551/* Add route-map set statement to the route map. */
552int
553route_map_add_set (struct route_map_index *index, char *set_name,
554 char *set_arg)
555{
556 struct route_map_rule *rule;
557 struct route_map_rule *next;
558 struct route_map_rule_cmd *cmd;
559 void *compile;
560 int replaced = 0;
561
562 cmd = route_map_lookup_set (set_name);
563 if (cmd == NULL)
564 return RMAP_RULE_MISSING;
565
566 /* Next call compile function for this match statement. */
567 if (cmd->func_compile)
568 {
569 compile= (*cmd->func_compile)(set_arg);
570 if (compile == NULL)
571 return RMAP_COMPILE_ERROR;
572 }
573 else
574 compile = NULL;
575
576 /* Add by WJL. if old set command of same kind exist, delete it first
577 to ensure only one set command of same kind exist under a
578 route_map_index. */
579 for (rule = index->set_list.head; rule; rule = next)
580 {
581 next = rule->next;
582 if (rule->cmd == cmd)
583 {
584 route_map_rule_delete (&index->set_list, rule);
585 replaced = 1;
586 }
587 }
588
589 /* Add new route map match rule. */
590 rule = route_map_rule_new ();
591 rule->cmd = cmd;
592 rule->value = compile;
593 if (set_arg)
594 rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, set_arg);
595 else
596 rule->rule_str = NULL;
597
598 /* Add new route match rule to linked list. */
599 route_map_rule_add (&index->set_list, rule);
600
601 /* Execute event hook. */
602 if (route_map_master.event_hook)
603 (*route_map_master.event_hook) (replaced ?
604 RMAP_EVENT_SET_REPLACED:
605 RMAP_EVENT_SET_ADDED,
606 index->map->name);
607 return 0;
608}
609
610/* Delete route map set rule. */
611int
612route_map_delete_set (struct route_map_index *index, char *set_name,
613 char *set_arg)
614{
615 struct route_map_rule *rule;
616 struct route_map_rule_cmd *cmd;
617
618 cmd = route_map_lookup_set (set_name);
619 if (cmd == NULL)
620 return 1;
621
622 for (rule = index->set_list.head; rule; rule = rule->next)
623 if ((rule->cmd == cmd) &&
624 (rulecmp (rule->rule_str, set_arg) == 0 || set_arg == NULL))
625 {
626 route_map_rule_delete (&index->set_list, rule);
627 /* Execute event hook. */
628 if (route_map_master.event_hook)
629 (*route_map_master.event_hook) (RMAP_EVENT_SET_DELETED,
630 index->map->name);
631 return 0;
632 }
633 /* Can't find matched rule. */
634 return 1;
635}
636
637/* Apply route map's each index to the object. */
638/*
639** The matrix for a route-map looks like this:
640** (note, this includes the description for the "NEXT"
641** and "GOTO" frobs now
642**
643** Match | No Match
644** |
645** permit a | c
646** |
647** ------------------+---------------
648** |
649** deny b | d
650** |
651**
652** a) Apply Set statements, accept route
653** If NEXT is specified, goto NEXT statement
654** If GOTO is specified, goto the first clause where pref > nextpref
655** If nothing is specified, do as Cisco and finish
656** b) Finish route-map processing, and deny route
657** c) & d) Goto Next index
658**
659** If we get no matches after we've processed all updates, then the route
660** is dropped too.
661**
662** Some notes on the new "NEXT" and "GOTO"
663** on-match next - If this clause is matched, then the set statements
664** are executed and then we drop through to the next clause
665** on-match goto n - If this clause is matched, then the set statments
666** are executed and then we goto the nth clause, or the
667** first clause greater than this. In order to ensure
668** route-maps *always* exit, you cannot jump backwards.
669** Sorry ;)
670**
671** We need to make sure our route-map processing matches the above
672*/
673route_map_result_t
674route_map_apply_index (struct route_map_index *index, struct prefix *prefix,
675 route_map_object_t type, void *object)
676{
677 int ret;
678 struct route_map_rule *match;
679 struct route_map_rule *set;
680
681 /* Check all match rule and if there is no match rule return 0. */
682 for (match = index->match_list.head; match; match = match->next)
683 {
684 /* Try each match statement in turn. If any return something
685 other than RM_MATCH then we don't need to check anymore and can
686 return */
687 ret = (*match->cmd->func_apply)(match->value, prefix, type, object);
688 if (ret != RMAP_MATCH)
689 return ret;
690 }
691
692 /* We get here if all match statements matched From the matrix
693 above, if this is PERMIT we go on and apply the SET functions. If
694 we're deny, we return indicating we matched a deny */
695
696 /* Apply set statement to the object. */
697 if (index->type == RMAP_PERMIT)
698 {
699 for (set = index->set_list.head; set; set = set->next)
700 {
701 ret = (*set->cmd->func_apply)(set->value, prefix, type, object);
702 }
703 return RMAP_MATCH;
704 }
705 else
706 {
707 return RMAP_DENYMATCH;
708 }
709 /* Should not get here! */
710 return RMAP_MATCH;
711}
712
713/* Apply route map to the object. */
714route_map_result_t
715route_map_apply (struct route_map *map, struct prefix *prefix,
716 route_map_object_t type, void *object)
717{
718 int ret = 0;
719 struct route_map_index *index;
720
721 if (map == NULL)
722 return RMAP_DENYMATCH;
723
724 for (index = map->head; index; index = index->next)
725 {
726 /* Apply this index. End here if we get a RM_NOMATCH */
727 ret = route_map_apply_index (index, prefix, type, object);
728
729 if (ret != RMAP_NOMATCH)
730 {
731 /* We now have to handle the NEXT and GOTO clauses */
732 if(index->exitpolicy == RMAP_EXIT)
733 return ret;
734 if(index->exitpolicy == RMAP_GOTO)
735 {
736 /* Find the next clause to jump to */
737 struct route_map_index *next;
738
739 next = index->next;
740 while (next && next->pref < index->nextpref)
741 {
742 index = next;
743 next = next->next;
744 }
745 if (next == NULL)
746 {
747 /* No clauses match! */
748 return ret;
749 }
750 }
751 /* Otherwise, we fall through as it was a NEXT */
752 }
753 }
754 /* Finally route-map does not match at all. */
755 return RMAP_DENYMATCH;
756}
757
758void
759route_map_add_hook (void (*func) (char *))
760{
761 route_map_master.add_hook = func;
762}
763
764void
765route_map_delete_hook (void (*func) (char *))
766{
767 route_map_master.delete_hook = func;
768}
769
770void
771route_map_event_hook (void (*func) (route_map_event_t, char *))
772{
773 route_map_master.event_hook = func;
774}
775
776void
777route_map_init ()
778{
779 /* Make vector for match and set. */
780 route_match_vec = vector_init (1);
781 route_set_vec = vector_init (1);
782}
783
784/* VTY related functions. */
785DEFUN (route_map,
786 route_map_cmd,
787 "route-map WORD (deny|permit) <1-65535>",
788 "Create route-map or enter route-map command mode\n"
789 "Route map tag\n"
790 "Route map denies set operations\n"
791 "Route map permits set operations\n"
792 "Sequence to insert to/delete from existing route-map entry\n")
793{
794 int permit;
795 unsigned long pref;
796 struct route_map *map;
797 struct route_map_index *index;
798 char *endptr = NULL;
799
800 /* Permit check. */
801 if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
802 permit = RMAP_PERMIT;
803 else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
804 permit = RMAP_DENY;
805 else
806 {
807 vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
808 return CMD_WARNING;
809 }
810
811 /* Preference check. */
812 pref = strtoul (argv[2], &endptr, 10);
813 if (pref == ULONG_MAX || *endptr != '\0')
814 {
815 vty_out (vty, "the fourth field must be positive integer%s",
816 VTY_NEWLINE);
817 return CMD_WARNING;
818 }
819 if (pref == 0 || pref > 65535)
820 {
821 vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
822 return CMD_WARNING;
823 }
824
825 /* Get route map. */
826 map = route_map_get (argv[0]);
827 index = route_map_index_get (map, permit, pref);
828
829 vty->index = index;
830 vty->node = RMAP_NODE;
831 return CMD_SUCCESS;
832}
833
834DEFUN (no_route_map_all,
835 no_route_map_all_cmd,
836 "no route-map WORD",
837 NO_STR
838 "Create route-map or enter route-map command mode\n"
839 "Route map tag\n")
840{
841 struct route_map *map;
842
843 map = route_map_lookup_by_name (argv[0]);
844 if (map == NULL)
845 {
846 vty_out (vty, "%% Could not find route-map %s%s",
847 argv[0], VTY_NEWLINE);
848 return CMD_WARNING;
849 }
850
851 route_map_delete (map);
852
853 return CMD_SUCCESS;
854}
855
856DEFUN (no_route_map,
857 no_route_map_cmd,
858 "no route-map WORD (deny|permit) <1-65535>",
859 NO_STR
860 "Create route-map or enter route-map command mode\n"
861 "Route map tag\n"
862 "Route map denies set operations\n"
863 "Route map permits set operations\n"
864 "Sequence to insert to/delete from existing route-map entry\n")
865{
866 int permit;
867 unsigned long pref;
868 struct route_map *map;
869 struct route_map_index *index;
870 char *endptr = NULL;
871
872 /* Permit check. */
873 if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
874 permit = RMAP_PERMIT;
875 else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
876 permit = RMAP_DENY;
877 else
878 {
879 vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
880 return CMD_WARNING;
881 }
882
883 /* Preference. */
884 pref = strtoul (argv[2], &endptr, 10);
885 if (pref == ULONG_MAX || *endptr != '\0')
886 {
887 vty_out (vty, "the fourth field must be positive integer%s",
888 VTY_NEWLINE);
889 return CMD_WARNING;
890 }
891 if (pref == 0 || pref > 65535)
892 {
893 vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
894 return CMD_WARNING;
895 }
896
897 /* Existence check. */
898 map = route_map_lookup_by_name (argv[0]);
899 if (map == NULL)
900 {
901 vty_out (vty, "%% Could not find route-map %s%s",
902 argv[0], VTY_NEWLINE);
903 return CMD_WARNING;
904 }
905
906 /* Lookup route map index. */
907 index = route_map_index_lookup (map, permit, pref);
908 if (index == NULL)
909 {
910 vty_out (vty, "%% Could not find route-map entry %s %s%s",
911 argv[0], argv[2], VTY_NEWLINE);
912 return CMD_WARNING;
913 }
914
915 /* Delete index from route map. */
916 route_map_index_delete (index, 1);
917
918 /* If this route rule is the last one, delete route map itself. */
919 if (route_map_empty (map))
920 route_map_delete (map);
921
922 return CMD_SUCCESS;
923}
924
925DEFUN (rmap_onmatch_next,
926 rmap_onmatch_next_cmd,
927 "on-match next",
928 "Exit policy on matches\n"
929 "Next clause\n")
930{
931 struct route_map_index *index;
932
933 index = vty->index;
934
935 if (index)
936 index->exitpolicy = RMAP_NEXT;
937
938 return CMD_SUCCESS;
939}
940
941DEFUN (no_rmap_onmatch_next,
942 no_rmap_onmatch_next_cmd,
943 "no on-match next",
944 NO_STR
945 "Exit policy on matches\n"
946 "Next clause\n")
947{
948 struct route_map_index *index;
949
950 index = vty->index;
951
952 if (index)
953 index->exitpolicy = RMAP_EXIT;
954
955 return CMD_SUCCESS;
956}
957
958DEFUN (rmap_onmatch_goto,
959 rmap_onmatch_goto_cmd,
960 "on-match goto <1-65535>",
961 "Exit policy on matches\n"
962 "Goto Clause number\n"
963 "Number\n")
964{
965 struct route_map_index *index;
966 int d = 0;
967
968 if (argv[0])
969 d = atoi(argv[0]);
970
971 index = vty->index;
972 if (index)
973 {
974 if (d <= index->pref)
975 {
976 /* Can't allow you to do that, Dave */
977 vty_out (vty, "can't jump backwards in route-maps%s",
978 VTY_NEWLINE);
979 return CMD_WARNING;
980 }
981 else
982 {
983 index->exitpolicy = RMAP_GOTO;
984 index->nextpref = d;
985 }
986 }
987 return CMD_SUCCESS;
988}
989
990DEFUN (no_rmap_onmatch_goto,
991 no_rmap_onmatch_goto_cmd,
992 "no on-match goto",
993 NO_STR
994 "Exit policy on matches\n"
995 "Next clause\n")
996{
997 struct route_map_index *index;
998
999 index = vty->index;
1000
1001 if (index)
1002 index->exitpolicy = RMAP_EXIT;
1003
1004 return CMD_SUCCESS;
1005}
1006
1007/* Configuration write function. */
1008int
1009route_map_config_write (struct vty *vty)
1010{
1011 struct route_map *map;
1012 struct route_map_index *index;
1013 struct route_map_rule *rule;
1014 int first = 1;
1015 int write = 0;
1016
1017 for (map = route_map_master.head; map; map = map->next)
1018 for (index = map->head; index; index = index->next)
1019 {
1020 if (!first)
1021 vty_out (vty, "!%s", VTY_NEWLINE);
1022 else
1023 first = 0;
1024
1025 vty_out (vty, "route-map %s %s %d%s",
1026 map->name,
1027 route_map_type_str (index->type),
1028 index->pref, VTY_NEWLINE);
1029
1030 for (rule = index->match_list.head; rule; rule = rule->next)
1031 vty_out (vty, " match %s %s%s", rule->cmd->str,
1032 rule->rule_str ? rule->rule_str : "",
1033 VTY_NEWLINE);
1034
1035 for (rule = index->set_list.head; rule; rule = rule->next)
1036 vty_out (vty, " set %s %s%s", rule->cmd->str,
1037 rule->rule_str ? rule->rule_str : "",
1038 VTY_NEWLINE);
1039 if (index->exitpolicy == RMAP_GOTO)
1040 vty_out (vty, " on-match goto %d%s", index->nextpref,
1041 VTY_NEWLINE);
1042 if (index->exitpolicy == RMAP_NEXT)
1043 vty_out (vty," on-match next%s", VTY_NEWLINE);
1044
1045 write++;
1046 }
1047 return write;
1048}
1049
1050/* Route map node structure. */
1051struct cmd_node rmap_node =
1052{
1053 RMAP_NODE,
1054 "%s(config-route-map)# ",
1055 1
1056};
1057
1058/* Initialization of route map vector. */
1059void
1060route_map_init_vty ()
1061{
1062 /* Install route map top node. */
1063 install_node (&rmap_node, route_map_config_write);
1064
1065 /* Install route map commands. */
1066 install_default (RMAP_NODE);
1067 install_element (CONFIG_NODE, &route_map_cmd);
1068 install_element (CONFIG_NODE, &no_route_map_cmd);
1069 install_element (CONFIG_NODE, &no_route_map_all_cmd);
1070
1071 /* Install the on-match stuff */
1072 install_element (RMAP_NODE, &route_map_cmd);
1073 install_element (RMAP_NODE, &rmap_onmatch_next_cmd);
1074 install_element (RMAP_NODE, &no_rmap_onmatch_next_cmd);
1075 install_element (RMAP_NODE, &rmap_onmatch_goto_cmd);
1076 install_element (RMAP_NODE, &no_rmap_onmatch_goto_cmd);
1077}