]> git.proxmox.com Git - mirror_frr.git/blame - lib/routemap.c
more cvsignores
[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"
29\f
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\f
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\f
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
3bf1c917 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 action | cont
646 |
647 ------------------+---------------
648 |
649 deny deny | cont
650 |
651
652 action) 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 deny) If NEXT is specified, goto NEXT statement
657 If nothing is specified, finally will be denied by route-map.
658 cont) Goto Next index
659
660 If we get no matches after we've processed all updates, then the route
661 is dropped too.
662
663 Some notes on the new "NEXT" and "GOTO"
664 on-match next - If this clause is matched, then the set statements
665 are executed and then we drop through to the next clause
666 on-match goto n - If this clause is matched, then the set statments
667 are executed and then we goto the nth clause, or the
668 first clause greater than this. In order to ensure
669 route-maps *always* exit, you cannot jump backwards.
670 Sorry ;)
671
672 We need to make sure our route-map processing matches the above
718e3744 673*/
3bf1c917 674
718e3744 675route_map_result_t
3bf1c917 676route_map_apply_match (struct route_map_rule_list *match_list,
677 struct prefix *prefix, route_map_object_t type,
678 void *object)
718e3744 679{
3bf1c917 680 route_map_result_t ret = RMAP_NOMATCH;
718e3744 681 struct route_map_rule *match;
718e3744 682
718e3744 683
3bf1c917 684 /* Check all match rule and if there is no match rule, go to the
685 set statement. */
686 if (!match_list->head)
687 ret = RMAP_MATCH;
688 else
718e3744 689 {
3bf1c917 690 for (match = match_list->head; match; match = match->next)
691 {
692 /* Try each match statement in turn, If any do not return
693 RMAP_MATCH, return, otherwise continue on to next match
694 statement. All match statements must match for end-result
695 to be a match. */
696 ret = (*match->cmd->func_apply) (match->value, prefix,
697 type, object);
698 if (ret != RMAP_MATCH)
699 return ret;
700 }
718e3744 701 }
3bf1c917 702 return ret;
718e3744 703}
704
705/* Apply route map to the object. */
706route_map_result_t
3bf1c917 707route_map_apply (struct route_map *map, struct prefix *prefix,
708 route_map_object_t type, void *object)
718e3744 709{
710 int ret = 0;
711 struct route_map_index *index;
3bf1c917 712 struct route_map_rule *set;
718e3744 713
714 if (map == NULL)
715 return RMAP_DENYMATCH;
716
717 for (index = map->head; index; index = index->next)
718 {
3bf1c917 719 /* Apply this index. */
720 ret = route_map_apply_match (&index->match_list, prefix, type, object);
721
722 /* Now we apply the matrix from above */
723 if (ret == RMAP_NOMATCH)
724 /* 'cont' from matrix - continue to next route-map sequence */
725 continue;
726 else if (ret == RMAP_MATCH)
727 {
728 if (index->type == RMAP_PERMIT)
729 /* 'action' */
730 {
731 /* permit+match must execute sets */
732 for (set = index->set_list.head; set; set = set->next)
733 ret = (*set->cmd->func_apply) (set->value, prefix,
734 type, object);
735 switch (index->exitpolicy)
736 {
737 case RMAP_EXIT:
738 return ret;
739 case RMAP_NEXT:
740 continue;
741 case RMAP_GOTO:
742 {
743 /* Find the next clause to jump to */
744 struct route_map_index *next = index->next;
745
746 while (next && next->pref < index->nextpref)
747 {
748 index = next;
749 next = next->next;
750 }
751 if (next == NULL)
752 {
753 /* No clauses match! */
754 return ret;
755 }
756 }
757 }
758 }
759 else if (index->type == RMAP_DENY)
760 /* 'deny' */
761 {
762 if (index->exitpolicy == RMAP_NEXT)
763 continue;
764 else
765 return RMAP_DENYMATCH;
766 }
767 }
718e3744 768 }
769 /* Finally route-map does not match at all. */
770 return RMAP_DENYMATCH;
771}
772
773void
774route_map_add_hook (void (*func) (char *))
775{
776 route_map_master.add_hook = func;
777}
778
779void
780route_map_delete_hook (void (*func) (char *))
781{
782 route_map_master.delete_hook = func;
783}
784
785void
786route_map_event_hook (void (*func) (route_map_event_t, char *))
787{
788 route_map_master.event_hook = func;
789}
790
791void
792route_map_init ()
793{
794 /* Make vector for match and set. */
795 route_match_vec = vector_init (1);
796 route_set_vec = vector_init (1);
797}
798\f
799/* VTY related functions. */
800DEFUN (route_map,
801 route_map_cmd,
802 "route-map WORD (deny|permit) <1-65535>",
803 "Create route-map or enter route-map command mode\n"
804 "Route map tag\n"
805 "Route map denies set operations\n"
806 "Route map permits set operations\n"
807 "Sequence to insert to/delete from existing route-map entry\n")
808{
809 int permit;
810 unsigned long pref;
811 struct route_map *map;
812 struct route_map_index *index;
813 char *endptr = NULL;
814
815 /* Permit check. */
816 if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
817 permit = RMAP_PERMIT;
818 else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
819 permit = RMAP_DENY;
820 else
821 {
822 vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
823 return CMD_WARNING;
824 }
825
826 /* Preference check. */
827 pref = strtoul (argv[2], &endptr, 10);
828 if (pref == ULONG_MAX || *endptr != '\0')
829 {
830 vty_out (vty, "the fourth field must be positive integer%s",
831 VTY_NEWLINE);
832 return CMD_WARNING;
833 }
834 if (pref == 0 || pref > 65535)
835 {
836 vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
837 return CMD_WARNING;
838 }
839
840 /* Get route map. */
841 map = route_map_get (argv[0]);
842 index = route_map_index_get (map, permit, pref);
843
844 vty->index = index;
845 vty->node = RMAP_NODE;
846 return CMD_SUCCESS;
847}
848
849DEFUN (no_route_map_all,
850 no_route_map_all_cmd,
851 "no route-map WORD",
852 NO_STR
853 "Create route-map or enter route-map command mode\n"
854 "Route map tag\n")
855{
856 struct route_map *map;
857
858 map = route_map_lookup_by_name (argv[0]);
859 if (map == NULL)
860 {
861 vty_out (vty, "%% Could not find route-map %s%s",
862 argv[0], VTY_NEWLINE);
863 return CMD_WARNING;
864 }
865
866 route_map_delete (map);
867
868 return CMD_SUCCESS;
869}
870
871DEFUN (no_route_map,
872 no_route_map_cmd,
873 "no route-map WORD (deny|permit) <1-65535>",
874 NO_STR
875 "Create route-map or enter route-map command mode\n"
876 "Route map tag\n"
877 "Route map denies set operations\n"
878 "Route map permits set operations\n"
879 "Sequence to insert to/delete from existing route-map entry\n")
880{
881 int permit;
882 unsigned long pref;
883 struct route_map *map;
884 struct route_map_index *index;
885 char *endptr = NULL;
886
887 /* Permit check. */
888 if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
889 permit = RMAP_PERMIT;
890 else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
891 permit = RMAP_DENY;
892 else
893 {
894 vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
895 return CMD_WARNING;
896 }
897
898 /* Preference. */
899 pref = strtoul (argv[2], &endptr, 10);
900 if (pref == ULONG_MAX || *endptr != '\0')
901 {
902 vty_out (vty, "the fourth field must be positive integer%s",
903 VTY_NEWLINE);
904 return CMD_WARNING;
905 }
906 if (pref == 0 || pref > 65535)
907 {
908 vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
909 return CMD_WARNING;
910 }
911
912 /* Existence check. */
913 map = route_map_lookup_by_name (argv[0]);
914 if (map == NULL)
915 {
916 vty_out (vty, "%% Could not find route-map %s%s",
917 argv[0], VTY_NEWLINE);
918 return CMD_WARNING;
919 }
920
921 /* Lookup route map index. */
922 index = route_map_index_lookup (map, permit, pref);
923 if (index == NULL)
924 {
925 vty_out (vty, "%% Could not find route-map entry %s %s%s",
926 argv[0], argv[2], VTY_NEWLINE);
927 return CMD_WARNING;
928 }
929
930 /* Delete index from route map. */
931 route_map_index_delete (index, 1);
932
933 /* If this route rule is the last one, delete route map itself. */
934 if (route_map_empty (map))
935 route_map_delete (map);
936
937 return CMD_SUCCESS;
938}
939
940DEFUN (rmap_onmatch_next,
941 rmap_onmatch_next_cmd,
942 "on-match next",
943 "Exit policy on matches\n"
944 "Next clause\n")
945{
946 struct route_map_index *index;
947
948 index = vty->index;
949
950 if (index)
951 index->exitpolicy = RMAP_NEXT;
952
953 return CMD_SUCCESS;
954}
955
956DEFUN (no_rmap_onmatch_next,
957 no_rmap_onmatch_next_cmd,
958 "no on-match next",
959 NO_STR
960 "Exit policy on matches\n"
961 "Next clause\n")
962{
963 struct route_map_index *index;
964
965 index = vty->index;
966
967 if (index)
968 index->exitpolicy = RMAP_EXIT;
969
970 return CMD_SUCCESS;
971}
972
973DEFUN (rmap_onmatch_goto,
974 rmap_onmatch_goto_cmd,
975 "on-match goto <1-65535>",
976 "Exit policy on matches\n"
977 "Goto Clause number\n"
978 "Number\n")
979{
980 struct route_map_index *index;
981 int d = 0;
982
983 if (argv[0])
984 d = atoi(argv[0]);
985
986 index = vty->index;
987 if (index)
988 {
989 if (d <= index->pref)
990 {
991 /* Can't allow you to do that, Dave */
992 vty_out (vty, "can't jump backwards in route-maps%s",
993 VTY_NEWLINE);
994 return CMD_WARNING;
995 }
996 else
997 {
998 index->exitpolicy = RMAP_GOTO;
999 index->nextpref = d;
1000 }
1001 }
1002 return CMD_SUCCESS;
1003}
1004
1005DEFUN (no_rmap_onmatch_goto,
1006 no_rmap_onmatch_goto_cmd,
1007 "no on-match goto",
1008 NO_STR
1009 "Exit policy on matches\n"
1010 "Next clause\n")
1011{
1012 struct route_map_index *index;
1013
1014 index = vty->index;
1015
1016 if (index)
1017 index->exitpolicy = RMAP_EXIT;
1018
1019 return CMD_SUCCESS;
1020}
1021
1022/* Configuration write function. */
1023int
1024route_map_config_write (struct vty *vty)
1025{
1026 struct route_map *map;
1027 struct route_map_index *index;
1028 struct route_map_rule *rule;
1029 int first = 1;
1030 int write = 0;
1031
1032 for (map = route_map_master.head; map; map = map->next)
1033 for (index = map->head; index; index = index->next)
1034 {
1035 if (!first)
1036 vty_out (vty, "!%s", VTY_NEWLINE);
1037 else
1038 first = 0;
1039
1040 vty_out (vty, "route-map %s %s %d%s",
1041 map->name,
1042 route_map_type_str (index->type),
1043 index->pref, VTY_NEWLINE);
1044
1045 for (rule = index->match_list.head; rule; rule = rule->next)
1046 vty_out (vty, " match %s %s%s", rule->cmd->str,
1047 rule->rule_str ? rule->rule_str : "",
1048 VTY_NEWLINE);
1049
1050 for (rule = index->set_list.head; rule; rule = rule->next)
1051 vty_out (vty, " set %s %s%s", rule->cmd->str,
1052 rule->rule_str ? rule->rule_str : "",
1053 VTY_NEWLINE);
1054 if (index->exitpolicy == RMAP_GOTO)
1055 vty_out (vty, " on-match goto %d%s", index->nextpref,
1056 VTY_NEWLINE);
1057 if (index->exitpolicy == RMAP_NEXT)
1058 vty_out (vty," on-match next%s", VTY_NEWLINE);
1059
1060 write++;
1061 }
1062 return write;
1063}
1064
1065/* Route map node structure. */
1066struct cmd_node rmap_node =
1067{
1068 RMAP_NODE,
1069 "%s(config-route-map)# ",
1070 1
1071};
1072
1073/* Initialization of route map vector. */
1074void
1075route_map_init_vty ()
1076{
1077 /* Install route map top node. */
1078 install_node (&rmap_node, route_map_config_write);
1079
1080 /* Install route map commands. */
1081 install_default (RMAP_NODE);
1082 install_element (CONFIG_NODE, &route_map_cmd);
1083 install_element (CONFIG_NODE, &no_route_map_cmd);
1084 install_element (CONFIG_NODE, &no_route_map_all_cmd);
1085
1086 /* Install the on-match stuff */
1087 install_element (RMAP_NODE, &route_map_cmd);
1088 install_element (RMAP_NODE, &rmap_onmatch_next_cmd);
1089 install_element (RMAP_NODE, &no_rmap_onmatch_next_cmd);
1090 install_element (RMAP_NODE, &rmap_onmatch_goto_cmd);
1091 install_element (RMAP_NODE, &no_rmap_onmatch_goto_cmd);
1092}