blob: 9995334e8c08a406370c1cf16bb3065a0bb6acb8 [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
paul5510e832004-07-09 14:00:01 +0000199/* show route-map */
200static void
201vty_show_route_map_entry (struct vty *vty, struct route_map *map)
paul718e3742002-12-13 20:15:29 +0000202{
paul718e3742002-12-13 20:15:29 +0000203 struct route_map_index *index;
204 struct route_map_rule *rule;
205
paul5510e832004-07-09 14:00:01 +0000206 for (index = map->head; index; index = index->next)
207 {
208 vty_out (vty, "route-map %s, %s, sequence %d%s",
209 map->name, route_map_type_str (index->type),
210 index->pref, VTY_NEWLINE);
211
212 /* Match clauses */
213 vty_out (vty, " Match clauses:%s", VTY_NEWLINE);
214 for (rule = index->match_list.head; rule; rule = rule->next)
215 vty_out (vty, " %s %s%s",
216 rule->cmd->str, rule->rule_str, VTY_NEWLINE);
217
218 vty_out (vty, " Set clauses:%s", VTY_NEWLINE);
219 for (rule = index->set_list.head; rule; rule = rule->next)
220 vty_out (vty, " %s %s%s",
221 rule->cmd->str, rule->rule_str, VTY_NEWLINE);
222
223 vty_out (vty, " Action:%s", VTY_NEWLINE);
224 if (index->exitpolicy == RMAP_GOTO)
225 vty_out (vty, " Goto %d%s", index->nextpref, VTY_NEWLINE);
226
227 else if (index->exitpolicy == RMAP_NEXT)
228 {
229 vty_out (vty, " Goto next, (entry ");
230 if (index->next)
231 vty_out (vty, " %d)%s", index->next->pref, VTY_NEWLINE);
232 else
233 vty_out (vty, " undefined)%s", VTY_NEWLINE);
234 }
235 else if (index->exitpolicy == RMAP_EXIT)
236 vty_out (vty, " Exit routemap%s", VTY_NEWLINE);
237 }
paul718e3742002-12-13 20:15:29 +0000238}
239
paul5510e832004-07-09 14:00:01 +0000240int
241vty_show_route_map (struct vty *vty, char *name)
242{
243 struct route_map *map;
244
245 if (name)
246 {
247 map = route_map_lookup_by_name (name);
248
249 if (map)
250 {
251 vty_show_route_map_entry (vty, map);
252 return CMD_SUCCESS;
253 }
254 else
255 {
256 vty_out (vty, "%%route-map %s not found%s", name, VTY_NEWLINE);
257 return CMD_WARNING;
258 }
259 }
260 return CMD_SUCCESS;
261}
262
263
paul718e3742002-12-13 20:15:29 +0000264/* New route map allocation. Please note route map's name must be
265 specified. */
266struct route_map_index *
267route_map_index_new ()
268{
269 struct route_map_index *new;
270
271 new = XCALLOC (MTYPE_ROUTE_MAP_INDEX, sizeof (struct route_map_index));
272 new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */
273 return new;
274}
275
276/* Free route map index. */
277static void
278route_map_index_delete (struct route_map_index *index, int notify)
279{
280 struct route_map_rule *rule;
281
282 /* Free route match. */
283 while ((rule = index->match_list.head) != NULL)
284 route_map_rule_delete (&index->match_list, rule);
285
286 /* Free route set. */
287 while ((rule = index->set_list.head) != NULL)
288 route_map_rule_delete (&index->set_list, rule);
289
290 /* Remove index from route map list. */
291 if (index->next)
292 index->next->prev = index->prev;
293 else
294 index->map->tail = index->prev;
295
296 if (index->prev)
297 index->prev->next = index->next;
298 else
299 index->map->head = index->next;
300
301 /* Execute event hook. */
302 if (route_map_master.event_hook && notify)
303 (*route_map_master.event_hook) (RMAP_EVENT_INDEX_DELETED,
304 index->map->name);
305
306 XFREE (MTYPE_ROUTE_MAP_INDEX, index);
307}
308
309/* Lookup index from route map. */
310struct route_map_index *
311route_map_index_lookup (struct route_map *map, enum route_map_type type,
312 int pref)
313{
314 struct route_map_index *index;
315
316 for (index = map->head; index; index = index->next)
317 if ((index->type == type || type == RMAP_ANY)
318 && index->pref == pref)
319 return index;
320 return NULL;
321}
322
323/* Add new index to route map. */
324struct route_map_index *
325route_map_index_add (struct route_map *map, enum route_map_type type,
326 int pref)
327{
328 struct route_map_index *index;
329 struct route_map_index *point;
330
331 /* Allocate new route map inex. */
332 index = route_map_index_new ();
333 index->map = map;
334 index->type = type;
335 index->pref = pref;
336
337 /* Compare preference. */
338 for (point = map->head; point; point = point->next)
339 if (point->pref >= pref)
340 break;
341
342 if (map->head == NULL)
343 {
344 map->head = map->tail = index;
345 }
346 else if (point == NULL)
347 {
348 index->prev = map->tail;
349 map->tail->next = index;
350 map->tail = index;
351 }
352 else if (point == map->head)
353 {
354 index->next = map->head;
355 map->head->prev = index;
356 map->head = index;
357 }
358 else
359 {
360 index->next = point;
361 index->prev = point->prev;
362 if (point->prev)
363 point->prev->next = index;
364 point->prev = index;
365 }
366
367 /* Execute event hook. */
368 if (route_map_master.event_hook)
369 (*route_map_master.event_hook) (RMAP_EVENT_INDEX_ADDED,
370 map->name);
371
372 return index;
373}
374
375/* Get route map index. */
376struct route_map_index *
377route_map_index_get (struct route_map *map, enum route_map_type type,
378 int pref)
379{
380 struct route_map_index *index;
381
382 index = route_map_index_lookup (map, RMAP_ANY, pref);
383 if (index && index->type != type)
384 {
385 /* Delete index from route map. */
386 route_map_index_delete (index, 1);
387 index = NULL;
388 }
389 if (index == NULL)
390 index = route_map_index_add (map, type, pref);
391 return index;
392}
393
394/* New route map rule */
395struct route_map_rule *
396route_map_rule_new ()
397{
398 struct route_map_rule *new;
399
400 new = XCALLOC (MTYPE_ROUTE_MAP_RULE, sizeof (struct route_map_rule));
401 return new;
402}
403
404/* Install rule command to the match list. */
405void
406route_map_install_match (struct route_map_rule_cmd *cmd)
407{
408 vector_set (route_match_vec, cmd);
409}
410
411/* Install rule command to the set list. */
412void
413route_map_install_set (struct route_map_rule_cmd *cmd)
414{
415 vector_set (route_set_vec, cmd);
416}
417
418/* Lookup rule command from match list. */
419struct route_map_rule_cmd *
420route_map_lookup_match (char *name)
421{
422 int i;
423 struct route_map_rule_cmd *rule;
424
425 for (i = 0; i < vector_max (route_match_vec); i++)
426 if ((rule = vector_slot (route_match_vec, i)) != NULL)
427 if (strcmp (rule->str, name) == 0)
428 return rule;
429 return NULL;
430}
431
432/* Lookup rule command from set list. */
433struct route_map_rule_cmd *
434route_map_lookup_set (char *name)
435{
436 int i;
437 struct route_map_rule_cmd *rule;
438
439 for (i = 0; i < vector_max (route_set_vec); i++)
440 if ((rule = vector_slot (route_set_vec, i)) != NULL)
441 if (strcmp (rule->str, name) == 0)
442 return rule;
443 return NULL;
444}
445
446/* Add match and set rule to rule list. */
447static void
448route_map_rule_add (struct route_map_rule_list *list,
449 struct route_map_rule *rule)
450{
451 rule->next = NULL;
452 rule->prev = list->tail;
453 if (list->tail)
454 list->tail->next = rule;
455 else
456 list->head = rule;
457 list->tail = rule;
458}
459
460/* Delete rule from rule list. */
461static void
462route_map_rule_delete (struct route_map_rule_list *list,
463 struct route_map_rule *rule)
464{
465 if (rule->cmd->func_free)
466 (*rule->cmd->func_free) (rule->value);
467
468 if (rule->rule_str)
469 XFREE (MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str);
470
471 if (rule->next)
472 rule->next->prev = rule->prev;
473 else
474 list->tail = rule->prev;
475 if (rule->prev)
476 rule->prev->next = rule->next;
477 else
478 list->head = rule->next;
479
480 XFREE (MTYPE_ROUTE_MAP_RULE, rule);
481}
482
483/* strcmp wrapper function which don't crush even argument is NULL. */
484int
485rulecmp (char *dst, char *src)
486{
487 if (dst == NULL)
488 {
489 if (src == NULL)
490 return 0;
491 else
492 return 1;
493 }
494 else
495 {
496 if (src == NULL)
497 return 1;
498 else
499 return strcmp (dst, src);
500 }
501 return 1;
502}
503
504/* Add match statement to route map. */
505int
506route_map_add_match (struct route_map_index *index, char *match_name,
507 char *match_arg)
508{
509 struct route_map_rule *rule;
510 struct route_map_rule *next;
511 struct route_map_rule_cmd *cmd;
512 void *compile;
513 int replaced = 0;
514
515 /* First lookup rule for add match statement. */
516 cmd = route_map_lookup_match (match_name);
517 if (cmd == NULL)
518 return RMAP_RULE_MISSING;
519
520 /* Next call compile function for this match statement. */
521 if (cmd->func_compile)
522 {
523 compile= (*cmd->func_compile)(match_arg);
524 if (compile == NULL)
525 return RMAP_COMPILE_ERROR;
526 }
527 else
528 compile = NULL;
529
530 /* If argument is completely same ignore it. */
531 for (rule = index->match_list.head; rule; rule = next)
532 {
533 next = rule->next;
534 if (rule->cmd == cmd)
535 {
536 route_map_rule_delete (&index->match_list, rule);
537 replaced = 1;
538 }
539 }
540
541 /* Add new route map match rule. */
542 rule = route_map_rule_new ();
543 rule->cmd = cmd;
544 rule->value = compile;
545 if (match_arg)
546 rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, match_arg);
547 else
548 rule->rule_str = NULL;
549
550 /* Add new route match rule to linked list. */
551 route_map_rule_add (&index->match_list, rule);
552
553 /* Execute event hook. */
554 if (route_map_master.event_hook)
555 (*route_map_master.event_hook) (replaced ?
556 RMAP_EVENT_MATCH_REPLACED:
557 RMAP_EVENT_MATCH_ADDED,
558 index->map->name);
559
560 return 0;
561}
562
563/* Delete specified route match rule. */
564int
565route_map_delete_match (struct route_map_index *index, char *match_name,
566 char *match_arg)
567{
568 struct route_map_rule *rule;
569 struct route_map_rule_cmd *cmd;
570
571 cmd = route_map_lookup_match (match_name);
572 if (cmd == NULL)
573 return 1;
574
575 for (rule = index->match_list.head; rule; rule = rule->next)
576 if (rule->cmd == cmd &&
577 (rulecmp (rule->rule_str, match_arg) == 0 || match_arg == NULL))
578 {
579 route_map_rule_delete (&index->match_list, rule);
580 /* Execute event hook. */
581 if (route_map_master.event_hook)
582 (*route_map_master.event_hook) (RMAP_EVENT_MATCH_DELETED,
583 index->map->name);
584 return 0;
585 }
586 /* Can't find matched rule. */
587 return 1;
588}
589
590/* Add route-map set statement to the route map. */
591int
592route_map_add_set (struct route_map_index *index, char *set_name,
593 char *set_arg)
594{
595 struct route_map_rule *rule;
596 struct route_map_rule *next;
597 struct route_map_rule_cmd *cmd;
598 void *compile;
599 int replaced = 0;
600
601 cmd = route_map_lookup_set (set_name);
602 if (cmd == NULL)
603 return RMAP_RULE_MISSING;
604
605 /* Next call compile function for this match statement. */
606 if (cmd->func_compile)
607 {
608 compile= (*cmd->func_compile)(set_arg);
609 if (compile == NULL)
610 return RMAP_COMPILE_ERROR;
611 }
612 else
613 compile = NULL;
614
615 /* Add by WJL. if old set command of same kind exist, delete it first
616 to ensure only one set command of same kind exist under a
617 route_map_index. */
618 for (rule = index->set_list.head; rule; rule = next)
619 {
620 next = rule->next;
621 if (rule->cmd == cmd)
622 {
623 route_map_rule_delete (&index->set_list, rule);
624 replaced = 1;
625 }
626 }
627
628 /* Add new route map match rule. */
629 rule = route_map_rule_new ();
630 rule->cmd = cmd;
631 rule->value = compile;
632 if (set_arg)
633 rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, set_arg);
634 else
635 rule->rule_str = NULL;
636
637 /* Add new route match rule to linked list. */
638 route_map_rule_add (&index->set_list, rule);
639
640 /* Execute event hook. */
641 if (route_map_master.event_hook)
642 (*route_map_master.event_hook) (replaced ?
643 RMAP_EVENT_SET_REPLACED:
644 RMAP_EVENT_SET_ADDED,
645 index->map->name);
646 return 0;
647}
648
649/* Delete route map set rule. */
650int
651route_map_delete_set (struct route_map_index *index, char *set_name,
652 char *set_arg)
653{
654 struct route_map_rule *rule;
655 struct route_map_rule_cmd *cmd;
656
657 cmd = route_map_lookup_set (set_name);
658 if (cmd == NULL)
659 return 1;
660
661 for (rule = index->set_list.head; rule; rule = rule->next)
662 if ((rule->cmd == cmd) &&
663 (rulecmp (rule->rule_str, set_arg) == 0 || set_arg == NULL))
664 {
665 route_map_rule_delete (&index->set_list, rule);
666 /* Execute event hook. */
667 if (route_map_master.event_hook)
668 (*route_map_master.event_hook) (RMAP_EVENT_SET_DELETED,
669 index->map->name);
670 return 0;
671 }
672 /* Can't find matched rule. */
673 return 1;
674}
675
paul3bf1c912003-10-29 06:30:19 +0000676/* Apply route map's each index to the object.
677
678 The matrix for a route-map looks like this:
679 (note, this includes the description for the "NEXT"
680 and "GOTO" frobs now
paul718e3742002-12-13 20:15:29 +0000681
paul3bf1c912003-10-29 06:30:19 +0000682 Match | No Match
683 |
684 permit action | cont
685 |
686 ------------------+---------------
687 |
688 deny deny | cont
689 |
690
691 action) Apply Set statements, accept route
692 If NEXT is specified, goto NEXT statement
693 If GOTO is specified, goto the first clause where pref > nextpref
694 If nothing is specified, do as Cisco and finish
695 deny) If NEXT is specified, goto NEXT statement
696 If nothing is specified, finally will be denied by route-map.
697 cont) Goto Next index
698
699 If we get no matches after we've processed all updates, then the route
700 is dropped too.
701
702 Some notes on the new "NEXT" and "GOTO"
703 on-match next - If this clause is matched, then the set statements
704 are executed and then we drop through to the next clause
705 on-match goto n - If this clause is matched, then the set statments
706 are executed and then we goto the nth clause, or the
707 first clause greater than this. In order to ensure
708 route-maps *always* exit, you cannot jump backwards.
709 Sorry ;)
710
711 We need to make sure our route-map processing matches the above
712*/
paul718e3742002-12-13 20:15:29 +0000713
paul3bf1c912003-10-29 06:30:19 +0000714route_map_result_t
715route_map_apply_match (struct route_map_rule_list *match_list,
716 struct prefix *prefix, route_map_object_t type,
717 void *object)
718{
719 route_map_result_t ret = RMAP_NOMATCH;
720 struct route_map_rule *match;
paul718e3742002-12-13 20:15:29 +0000721
paul3bf1c912003-10-29 06:30:19 +0000722
723 /* Check all match rule and if there is no match rule, go to the
724 set statement. */
725 if (!match_list->head)
726 ret = RMAP_MATCH;
727 else
paul718e3742002-12-13 20:15:29 +0000728 {
paul3bf1c912003-10-29 06:30:19 +0000729 for (match = match_list->head; match; match = match->next)
730 {
731 /* Try each match statement in turn, If any do not return
732 RMAP_MATCH, return, otherwise continue on to next match
733 statement. All match statements must match for end-result
734 to be a match. */
735 ret = (*match->cmd->func_apply) (match->value, prefix,
736 type, object);
737 if (ret != RMAP_MATCH)
738 return ret;
739 }
paul718e3742002-12-13 20:15:29 +0000740 }
paul3bf1c912003-10-29 06:30:19 +0000741 return ret;
paul718e3742002-12-13 20:15:29 +0000742}
743
744/* Apply route map to the object. */
745route_map_result_t
paul3bf1c912003-10-29 06:30:19 +0000746route_map_apply (struct route_map *map, struct prefix *prefix,
747 route_map_object_t type, void *object)
paul718e3742002-12-13 20:15:29 +0000748{
749 int ret = 0;
750 struct route_map_index *index;
paul3bf1c912003-10-29 06:30:19 +0000751 struct route_map_rule *set;
paul718e3742002-12-13 20:15:29 +0000752
753 if (map == NULL)
754 return RMAP_DENYMATCH;
755
756 for (index = map->head; index; index = index->next)
757 {
paul3bf1c912003-10-29 06:30:19 +0000758 /* Apply this index. */
759 ret = route_map_apply_match (&index->match_list, prefix, type, object);
paul718e3742002-12-13 20:15:29 +0000760
paul3bf1c912003-10-29 06:30:19 +0000761 /* Now we apply the matrix from above */
762 if (ret == RMAP_NOMATCH)
763 /* 'cont' from matrix - continue to next route-map sequence */
764 continue;
765 else if (ret == RMAP_MATCH)
766 {
767 if (index->type == RMAP_PERMIT)
768 /* 'action' */
769 {
770 /* permit+match must execute sets */
771 for (set = index->set_list.head; set; set = set->next)
772 ret = (*set->cmd->func_apply) (set->value, prefix,
773 type, object);
774 switch (index->exitpolicy)
775 {
776 case RMAP_EXIT:
777 return ret;
778 case RMAP_NEXT:
779 continue;
780 case RMAP_GOTO:
781 {
782 /* Find the next clause to jump to */
783 struct route_map_index *next = index->next;
paul718e3742002-12-13 20:15:29 +0000784
paul3bf1c912003-10-29 06:30:19 +0000785 while (next && next->pref < index->nextpref)
786 {
787 index = next;
788 next = next->next;
789 }
790 if (next == NULL)
791 {
792 /* No clauses match! */
793 return ret;
794 }
795 }
796 }
797 }
798 else if (index->type == RMAP_DENY)
799 /* 'deny' */
800 {
801 if (index->exitpolicy == RMAP_NEXT)
802 continue;
803 else
804 return RMAP_DENYMATCH;
805 }
806 }
paul718e3742002-12-13 20:15:29 +0000807 }
808 /* Finally route-map does not match at all. */
809 return RMAP_DENYMATCH;
810}
811
812void
813route_map_add_hook (void (*func) (char *))
814{
815 route_map_master.add_hook = func;
816}
817
818void
819route_map_delete_hook (void (*func) (char *))
820{
821 route_map_master.delete_hook = func;
822}
823
824void
825route_map_event_hook (void (*func) (route_map_event_t, char *))
826{
827 route_map_master.event_hook = func;
828}
829
830void
831route_map_init ()
832{
833 /* Make vector for match and set. */
834 route_match_vec = vector_init (1);
835 route_set_vec = vector_init (1);
836}
837
838/* VTY related functions. */
839DEFUN (route_map,
840 route_map_cmd,
841 "route-map WORD (deny|permit) <1-65535>",
842 "Create route-map or enter route-map command mode\n"
843 "Route map tag\n"
844 "Route map denies set operations\n"
845 "Route map permits set operations\n"
846 "Sequence to insert to/delete from existing route-map entry\n")
847{
848 int permit;
849 unsigned long pref;
850 struct route_map *map;
851 struct route_map_index *index;
852 char *endptr = NULL;
853
854 /* Permit check. */
855 if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
856 permit = RMAP_PERMIT;
857 else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
858 permit = RMAP_DENY;
859 else
860 {
861 vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
862 return CMD_WARNING;
863 }
864
865 /* Preference check. */
866 pref = strtoul (argv[2], &endptr, 10);
867 if (pref == ULONG_MAX || *endptr != '\0')
868 {
869 vty_out (vty, "the fourth field must be positive integer%s",
870 VTY_NEWLINE);
871 return CMD_WARNING;
872 }
873 if (pref == 0 || pref > 65535)
874 {
875 vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
876 return CMD_WARNING;
877 }
878
879 /* Get route map. */
880 map = route_map_get (argv[0]);
881 index = route_map_index_get (map, permit, pref);
882
883 vty->index = index;
884 vty->node = RMAP_NODE;
885 return CMD_SUCCESS;
886}
887
888DEFUN (no_route_map_all,
889 no_route_map_all_cmd,
890 "no route-map WORD",
891 NO_STR
892 "Create route-map or enter route-map command mode\n"
893 "Route map tag\n")
894{
895 struct route_map *map;
896
897 map = route_map_lookup_by_name (argv[0]);
898 if (map == NULL)
899 {
900 vty_out (vty, "%% Could not find route-map %s%s",
901 argv[0], VTY_NEWLINE);
902 return CMD_WARNING;
903 }
904
905 route_map_delete (map);
906
907 return CMD_SUCCESS;
908}
909
910DEFUN (no_route_map,
911 no_route_map_cmd,
912 "no route-map WORD (deny|permit) <1-65535>",
913 NO_STR
914 "Create route-map or enter route-map command mode\n"
915 "Route map tag\n"
916 "Route map denies set operations\n"
917 "Route map permits set operations\n"
918 "Sequence to insert to/delete from existing route-map entry\n")
919{
920 int permit;
921 unsigned long pref;
922 struct route_map *map;
923 struct route_map_index *index;
924 char *endptr = NULL;
925
926 /* Permit check. */
927 if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
928 permit = RMAP_PERMIT;
929 else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
930 permit = RMAP_DENY;
931 else
932 {
933 vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
934 return CMD_WARNING;
935 }
936
937 /* Preference. */
938 pref = strtoul (argv[2], &endptr, 10);
939 if (pref == ULONG_MAX || *endptr != '\0')
940 {
941 vty_out (vty, "the fourth field must be positive integer%s",
942 VTY_NEWLINE);
943 return CMD_WARNING;
944 }
945 if (pref == 0 || pref > 65535)
946 {
947 vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
948 return CMD_WARNING;
949 }
950
951 /* Existence check. */
952 map = route_map_lookup_by_name (argv[0]);
953 if (map == NULL)
954 {
955 vty_out (vty, "%% Could not find route-map %s%s",
956 argv[0], VTY_NEWLINE);
957 return CMD_WARNING;
958 }
959
960 /* Lookup route map index. */
961 index = route_map_index_lookup (map, permit, pref);
962 if (index == NULL)
963 {
964 vty_out (vty, "%% Could not find route-map entry %s %s%s",
965 argv[0], argv[2], VTY_NEWLINE);
966 return CMD_WARNING;
967 }
968
969 /* Delete index from route map. */
970 route_map_index_delete (index, 1);
971
972 /* If this route rule is the last one, delete route map itself. */
973 if (route_map_empty (map))
974 route_map_delete (map);
975
976 return CMD_SUCCESS;
977}
978
979DEFUN (rmap_onmatch_next,
980 rmap_onmatch_next_cmd,
981 "on-match next",
982 "Exit policy on matches\n"
983 "Next clause\n")
984{
985 struct route_map_index *index;
986
987 index = vty->index;
988
989 if (index)
990 index->exitpolicy = RMAP_NEXT;
991
992 return CMD_SUCCESS;
993}
994
995DEFUN (no_rmap_onmatch_next,
996 no_rmap_onmatch_next_cmd,
997 "no on-match next",
998 NO_STR
999 "Exit policy on matches\n"
1000 "Next clause\n")
1001{
1002 struct route_map_index *index;
1003
1004 index = vty->index;
1005
1006 if (index)
1007 index->exitpolicy = RMAP_EXIT;
1008
1009 return CMD_SUCCESS;
1010}
1011
1012DEFUN (rmap_onmatch_goto,
1013 rmap_onmatch_goto_cmd,
1014 "on-match goto <1-65535>",
1015 "Exit policy on matches\n"
1016 "Goto Clause number\n"
1017 "Number\n")
1018{
1019 struct route_map_index *index;
1020 int d = 0;
1021
1022 if (argv[0])
1023 d = atoi(argv[0]);
1024
1025 index = vty->index;
1026 if (index)
1027 {
1028 if (d <= index->pref)
1029 {
1030 /* Can't allow you to do that, Dave */
1031 vty_out (vty, "can't jump backwards in route-maps%s",
1032 VTY_NEWLINE);
1033 return CMD_WARNING;
1034 }
1035 else
1036 {
1037 index->exitpolicy = RMAP_GOTO;
1038 index->nextpref = d;
1039 }
1040 }
1041 return CMD_SUCCESS;
1042}
1043
1044DEFUN (no_rmap_onmatch_goto,
1045 no_rmap_onmatch_goto_cmd,
1046 "no on-match goto",
1047 NO_STR
1048 "Exit policy on matches\n"
1049 "Next clause\n")
1050{
1051 struct route_map_index *index;
1052
1053 index = vty->index;
1054
1055 if (index)
1056 index->exitpolicy = RMAP_EXIT;
1057
1058 return CMD_SUCCESS;
1059}
1060
paul5510e832004-07-09 14:00:01 +00001061/* Cisco/GNU Zebra compatible ALIASes for on-match next */
1062ALIAS (rmap_onmatch_goto,
1063 rmap_continue_cmd,
1064 "continue",
1065 "Continue on a different entry within the route-map\n")
1066
1067ALIAS (no_rmap_onmatch_goto,
1068 no_rmap_continue_cmd,
1069 "no continue",
1070 NO_STR
1071 "Continue on a different entry within the route-map\n")
1072
1073/* GNU Zebra compatible */
1074ALIAS (rmap_onmatch_goto,
1075 rmap_continue_seq_cmd,
1076 "continue <1-65535>",
1077 "Continue on a different entry within the route-map\n"
1078 "Route-map entry sequence number\n")
1079
1080ALIAS (no_rmap_onmatch_goto,
1081 no_rmap_continue_seq,
1082 "no continue <1-65535>",
1083 NO_STR
1084 "Continue on a different entry within the route-map\n"
1085 "Route-map entry sequence number\n")
1086
1087DEFUN (rmap_show,
1088 rmap_show_cmd,
1089 "show route-map",
1090 SHOW_STR
1091 "route-map information\n")
1092{
1093 return vty_show_route_map (vty, NULL);
1094}
1095
1096DEFUN (rmap_show_name,
1097 rmap_show_name_cmd,
1098 "show route-map WORD",
1099 SHOW_STR
1100 "route-map information\n"
1101 "route-map name\n")
1102{
1103 return vty_show_route_map (vty, argv[0]);
1104}
1105
paul718e3742002-12-13 20:15:29 +00001106/* Configuration write function. */
1107int
1108route_map_config_write (struct vty *vty)
1109{
1110 struct route_map *map;
1111 struct route_map_index *index;
1112 struct route_map_rule *rule;
1113 int first = 1;
1114 int write = 0;
1115
1116 for (map = route_map_master.head; map; map = map->next)
1117 for (index = map->head; index; index = index->next)
1118 {
1119 if (!first)
1120 vty_out (vty, "!%s", VTY_NEWLINE);
1121 else
1122 first = 0;
1123
1124 vty_out (vty, "route-map %s %s %d%s",
1125 map->name,
1126 route_map_type_str (index->type),
1127 index->pref, VTY_NEWLINE);
1128
1129 for (rule = index->match_list.head; rule; rule = rule->next)
1130 vty_out (vty, " match %s %s%s", rule->cmd->str,
1131 rule->rule_str ? rule->rule_str : "",
1132 VTY_NEWLINE);
1133
1134 for (rule = index->set_list.head; rule; rule = rule->next)
1135 vty_out (vty, " set %s %s%s", rule->cmd->str,
1136 rule->rule_str ? rule->rule_str : "",
1137 VTY_NEWLINE);
1138 if (index->exitpolicy == RMAP_GOTO)
1139 vty_out (vty, " on-match goto %d%s", index->nextpref,
1140 VTY_NEWLINE);
1141 if (index->exitpolicy == RMAP_NEXT)
1142 vty_out (vty," on-match next%s", VTY_NEWLINE);
1143
1144 write++;
1145 }
1146 return write;
1147}
1148
1149/* Route map node structure. */
1150struct cmd_node rmap_node =
1151{
1152 RMAP_NODE,
1153 "%s(config-route-map)# ",
1154 1
1155};
1156
1157/* Initialization of route map vector. */
1158void
1159route_map_init_vty ()
1160{
1161 /* Install route map top node. */
1162 install_node (&rmap_node, route_map_config_write);
1163
1164 /* Install route map commands. */
1165 install_default (RMAP_NODE);
1166 install_element (CONFIG_NODE, &route_map_cmd);
1167 install_element (CONFIG_NODE, &no_route_map_cmd);
1168 install_element (CONFIG_NODE, &no_route_map_all_cmd);
1169
1170 /* Install the on-match stuff */
1171 install_element (RMAP_NODE, &route_map_cmd);
1172 install_element (RMAP_NODE, &rmap_onmatch_next_cmd);
1173 install_element (RMAP_NODE, &no_rmap_onmatch_next_cmd);
1174 install_element (RMAP_NODE, &rmap_onmatch_goto_cmd);
1175 install_element (RMAP_NODE, &no_rmap_onmatch_goto_cmd);
paul5510e832004-07-09 14:00:01 +00001176
1177 /* Install show command */
1178 install_element (ENABLE_NODE, &rmap_show_cmd);
1179 install_element (ENABLE_NODE, &rmap_show_name_cmd);
paul718e3742002-12-13 20:15:29 +00001180}