blob: 85491ead783581949bb1491548451f55b4b5d297 [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"
pauld4f09602005-05-23 12:43:34 +000029#include "vty.h"
paulfee0f4c2004-09-13 05:12:46 +000030#include "log.h"
paul718e3742002-12-13 20:15:29 +000031
32/* Vector for route match rules. */
33static vector route_match_vec;
34
35/* Vector for route set rules. */
36static vector route_set_vec;
37
38/* Route map rule. This rule has both `match' rule and `set' rule. */
39struct route_map_rule
40{
41 /* Rule type. */
42 struct route_map_rule_cmd *cmd;
43
44 /* For pretty printing. */
45 char *rule_str;
46
47 /* Pre-compiled match rule. */
48 void *value;
49
50 /* Linked list. */
51 struct route_map_rule *next;
52 struct route_map_rule *prev;
53};
54
55/* Making route map list. */
56struct route_map_list
57{
58 struct route_map *head;
59 struct route_map *tail;
60
paul9035efa2004-10-10 11:56:56 +000061 void (*add_hook) (const char *);
62 void (*delete_hook) (const char *);
63 void (*event_hook) (route_map_event_t, const char *);
paul718e3742002-12-13 20:15:29 +000064};
65
66/* Master list of route map. */
67static struct route_map_list route_map_master = { NULL, NULL, NULL, NULL };
68
69static void
70route_map_rule_delete (struct route_map_rule_list *,
71 struct route_map_rule *);
72
73static void
74route_map_index_delete (struct route_map_index *, int);
75
76/* New route map allocation. Please note route map's name must be
77 specified. */
78static struct route_map *
paul9035efa2004-10-10 11:56:56 +000079route_map_new (const char *name)
paul718e3742002-12-13 20:15:29 +000080{
81 struct route_map *new;
82
83 new = XCALLOC (MTYPE_ROUTE_MAP, sizeof (struct route_map));
84 new->name = XSTRDUP (MTYPE_ROUTE_MAP_NAME, name);
85 return new;
86}
87
88/* Add new name to route_map. */
89static struct route_map *
paul9035efa2004-10-10 11:56:56 +000090route_map_add (const char *name)
paul718e3742002-12-13 20:15:29 +000091{
92 struct route_map *map;
93 struct route_map_list *list;
94
95 map = route_map_new (name);
96 list = &route_map_master;
97
98 map->next = NULL;
99 map->prev = list->tail;
100 if (list->tail)
101 list->tail->next = map;
102 else
103 list->head = map;
104 list->tail = map;
105
106 /* Execute hook. */
107 if (route_map_master.add_hook)
108 (*route_map_master.add_hook) (name);
109
110 return map;
111}
112
113/* Route map delete from list. */
114static void
115route_map_delete (struct route_map *map)
116{
117 struct route_map_list *list;
118 struct route_map_index *index;
119 char *name;
120
121 while ((index = map->head) != NULL)
122 route_map_index_delete (index, 0);
123
124 name = map->name;
125
126 list = &route_map_master;
127
128 if (map->next)
129 map->next->prev = map->prev;
130 else
131 list->tail = map->prev;
132
133 if (map->prev)
134 map->prev->next = map->next;
135 else
136 list->head = map->next;
137
138 XFREE (MTYPE_ROUTE_MAP, map);
139
140 /* Execute deletion hook. */
141 if (route_map_master.delete_hook)
142 (*route_map_master.delete_hook) (name);
143
144 if (name)
145 XFREE (MTYPE_ROUTE_MAP_NAME, name);
146
147}
148
149/* Lookup route map by route map name string. */
150struct route_map *
paul9035efa2004-10-10 11:56:56 +0000151route_map_lookup_by_name (const char *name)
paul718e3742002-12-13 20:15:29 +0000152{
153 struct route_map *map;
154
155 for (map = route_map_master.head; map; map = map->next)
156 if (strcmp (map->name, name) == 0)
157 return map;
158 return NULL;
159}
160
161/* Lookup route map. If there isn't route map create one and return
162 it. */
paul8cc41982005-05-06 21:25:49 +0000163static struct route_map *
paul9035efa2004-10-10 11:56:56 +0000164route_map_get (const char *name)
paul718e3742002-12-13 20:15:29 +0000165{
166 struct route_map *map;
167
168 map = route_map_lookup_by_name (name);
169 if (map == NULL)
170 map = route_map_add (name);
171 return map;
172}
173
174/* Return route map's type string. */
paul8cc41982005-05-06 21:25:49 +0000175static const char *
paul718e3742002-12-13 20:15:29 +0000176route_map_type_str (enum route_map_type type)
177{
178 switch (type)
179 {
180 case RMAP_PERMIT:
181 return "permit";
182 break;
183 case RMAP_DENY:
184 return "deny";
185 break;
186 default:
187 return "";
188 break;
189 }
190}
191
paul8cc41982005-05-06 21:25:49 +0000192static int
paul718e3742002-12-13 20:15:29 +0000193route_map_empty (struct route_map *map)
194{
195 if (map->head == NULL && map->tail == NULL)
196 return 1;
197 else
198 return 0;
199}
200
paul5510e832004-07-09 14:00:01 +0000201/* show route-map */
202static void
203vty_show_route_map_entry (struct vty *vty, struct route_map *map)
paul718e3742002-12-13 20:15:29 +0000204{
paul718e3742002-12-13 20:15:29 +0000205 struct route_map_index *index;
206 struct route_map_rule *rule;
207
vincentfbf5d032005-09-29 11:25:50 +0000208 /* Print the name of the protocol */
209 if (zlog_default)
210 vty_out (vty, "%s:%s", zlog_proto_names[zlog_default->protocol],
211 VTY_NEWLINE);
212
paul5510e832004-07-09 14:00:01 +0000213 for (index = map->head; index; index = index->next)
214 {
215 vty_out (vty, "route-map %s, %s, sequence %d%s",
216 map->name, route_map_type_str (index->type),
217 index->pref, VTY_NEWLINE);
hasso5bb4c192005-04-09 13:27:50 +0000218
219 /* Description */
220 if (index->description)
221 vty_out (vty, " Description:%s %s%s", VTY_NEWLINE,
222 index->description, VTY_NEWLINE);
paul5510e832004-07-09 14:00:01 +0000223
224 /* Match clauses */
225 vty_out (vty, " Match clauses:%s", VTY_NEWLINE);
226 for (rule = index->match_list.head; rule; rule = rule->next)
227 vty_out (vty, " %s %s%s",
228 rule->cmd->str, rule->rule_str, VTY_NEWLINE);
229
230 vty_out (vty, " Set clauses:%s", VTY_NEWLINE);
231 for (rule = index->set_list.head; rule; rule = rule->next)
232 vty_out (vty, " %s %s%s",
233 rule->cmd->str, rule->rule_str, VTY_NEWLINE);
234
235 vty_out (vty, " Action:%s", VTY_NEWLINE);
paulfee0f4c2004-09-13 05:12:46 +0000236
237 if (index->nextrm)
238 vty_out (vty, " Call %s%s", index->nextrm, VTY_NEWLINE);
239 else if (index->exitpolicy == RMAP_GOTO)
paul5510e832004-07-09 14:00:01 +0000240 vty_out (vty, " Goto %d%s", index->nextpref, VTY_NEWLINE);
paul5510e832004-07-09 14:00:01 +0000241 else if (index->exitpolicy == RMAP_NEXT)
242 {
243 vty_out (vty, " Goto next, (entry ");
244 if (index->next)
245 vty_out (vty, " %d)%s", index->next->pref, VTY_NEWLINE);
246 else
247 vty_out (vty, " undefined)%s", VTY_NEWLINE);
248 }
249 else if (index->exitpolicy == RMAP_EXIT)
250 vty_out (vty, " Exit routemap%s", VTY_NEWLINE);
251 }
paul718e3742002-12-13 20:15:29 +0000252}
253
paul8cc41982005-05-06 21:25:49 +0000254static int
paul9035efa2004-10-10 11:56:56 +0000255vty_show_route_map (struct vty *vty, const char *name)
paul5510e832004-07-09 14:00:01 +0000256{
257 struct route_map *map;
258
259 if (name)
260 {
261 map = route_map_lookup_by_name (name);
262
263 if (map)
264 {
265 vty_show_route_map_entry (vty, map);
266 return CMD_SUCCESS;
267 }
268 else
269 {
270 vty_out (vty, "%%route-map %s not found%s", name, VTY_NEWLINE);
271 return CMD_WARNING;
272 }
273 }
274 return CMD_SUCCESS;
275}
276
277
paul718e3742002-12-13 20:15:29 +0000278/* New route map allocation. Please note route map's name must be
279 specified. */
paul8cc41982005-05-06 21:25:49 +0000280static struct route_map_index *
281route_map_index_new (void)
paul718e3742002-12-13 20:15:29 +0000282{
283 struct route_map_index *new;
284
285 new = XCALLOC (MTYPE_ROUTE_MAP_INDEX, sizeof (struct route_map_index));
286 new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */
287 return new;
288}
289
290/* Free route map index. */
291static void
292route_map_index_delete (struct route_map_index *index, int notify)
293{
294 struct route_map_rule *rule;
295
296 /* Free route match. */
297 while ((rule = index->match_list.head) != NULL)
298 route_map_rule_delete (&index->match_list, rule);
299
300 /* Free route set. */
301 while ((rule = index->set_list.head) != NULL)
302 route_map_rule_delete (&index->set_list, rule);
303
304 /* Remove index from route map list. */
305 if (index->next)
306 index->next->prev = index->prev;
307 else
308 index->map->tail = index->prev;
309
310 if (index->prev)
311 index->prev->next = index->next;
312 else
313 index->map->head = index->next;
314
paulfee0f4c2004-09-13 05:12:46 +0000315 /* Free 'char *nextrm' if not NULL */
316 if (index->nextrm)
paul02416842005-10-26 05:05:16 +0000317 XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
paulfee0f4c2004-09-13 05:12:46 +0000318
paul718e3742002-12-13 20:15:29 +0000319 /* Execute event hook. */
320 if (route_map_master.event_hook && notify)
321 (*route_map_master.event_hook) (RMAP_EVENT_INDEX_DELETED,
322 index->map->name);
323
324 XFREE (MTYPE_ROUTE_MAP_INDEX, index);
325}
326
327/* Lookup index from route map. */
paul8cc41982005-05-06 21:25:49 +0000328static struct route_map_index *
paul718e3742002-12-13 20:15:29 +0000329route_map_index_lookup (struct route_map *map, enum route_map_type type,
330 int pref)
331{
332 struct route_map_index *index;
333
334 for (index = map->head; index; index = index->next)
335 if ((index->type == type || type == RMAP_ANY)
336 && index->pref == pref)
337 return index;
338 return NULL;
339}
340
341/* Add new index to route map. */
paul8cc41982005-05-06 21:25:49 +0000342static struct route_map_index *
paul718e3742002-12-13 20:15:29 +0000343route_map_index_add (struct route_map *map, enum route_map_type type,
344 int pref)
345{
346 struct route_map_index *index;
347 struct route_map_index *point;
348
349 /* Allocate new route map inex. */
350 index = route_map_index_new ();
351 index->map = map;
352 index->type = type;
353 index->pref = pref;
354
355 /* Compare preference. */
356 for (point = map->head; point; point = point->next)
357 if (point->pref >= pref)
358 break;
359
360 if (map->head == NULL)
361 {
362 map->head = map->tail = index;
363 }
364 else if (point == NULL)
365 {
366 index->prev = map->tail;
367 map->tail->next = index;
368 map->tail = index;
369 }
370 else if (point == map->head)
371 {
372 index->next = map->head;
373 map->head->prev = index;
374 map->head = index;
375 }
376 else
377 {
378 index->next = point;
379 index->prev = point->prev;
380 if (point->prev)
381 point->prev->next = index;
382 point->prev = index;
383 }
384
385 /* Execute event hook. */
386 if (route_map_master.event_hook)
387 (*route_map_master.event_hook) (RMAP_EVENT_INDEX_ADDED,
388 map->name);
389
390 return index;
391}
392
393/* Get route map index. */
paul8cc41982005-05-06 21:25:49 +0000394static struct route_map_index *
paul718e3742002-12-13 20:15:29 +0000395route_map_index_get (struct route_map *map, enum route_map_type type,
396 int pref)
397{
398 struct route_map_index *index;
399
400 index = route_map_index_lookup (map, RMAP_ANY, pref);
401 if (index && index->type != type)
402 {
403 /* Delete index from route map. */
404 route_map_index_delete (index, 1);
405 index = NULL;
406 }
407 if (index == NULL)
408 index = route_map_index_add (map, type, pref);
409 return index;
410}
411
412/* New route map rule */
paul8cc41982005-05-06 21:25:49 +0000413static struct route_map_rule *
414route_map_rule_new (void)
paul718e3742002-12-13 20:15:29 +0000415{
416 struct route_map_rule *new;
417
418 new = XCALLOC (MTYPE_ROUTE_MAP_RULE, sizeof (struct route_map_rule));
419 return new;
420}
421
422/* Install rule command to the match list. */
423void
424route_map_install_match (struct route_map_rule_cmd *cmd)
425{
426 vector_set (route_match_vec, cmd);
427}
428
429/* Install rule command to the set list. */
430void
431route_map_install_set (struct route_map_rule_cmd *cmd)
432{
433 vector_set (route_set_vec, cmd);
434}
435
436/* Lookup rule command from match list. */
paul8cc41982005-05-06 21:25:49 +0000437static struct route_map_rule_cmd *
hasso27a43a82004-10-08 06:29:12 +0000438route_map_lookup_match (const char *name)
paul718e3742002-12-13 20:15:29 +0000439{
hasso8c328f12004-10-05 21:01:23 +0000440 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000441 struct route_map_rule_cmd *rule;
442
paul55468c82005-03-14 20:19:01 +0000443 for (i = 0; i < vector_active (route_match_vec); i++)
paul718e3742002-12-13 20:15:29 +0000444 if ((rule = vector_slot (route_match_vec, i)) != NULL)
445 if (strcmp (rule->str, name) == 0)
446 return rule;
447 return NULL;
448}
449
450/* Lookup rule command from set list. */
paul8cc41982005-05-06 21:25:49 +0000451static struct route_map_rule_cmd *
hasso27a43a82004-10-08 06:29:12 +0000452route_map_lookup_set (const char *name)
paul718e3742002-12-13 20:15:29 +0000453{
hasso8c328f12004-10-05 21:01:23 +0000454 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000455 struct route_map_rule_cmd *rule;
456
paul55468c82005-03-14 20:19:01 +0000457 for (i = 0; i < vector_active (route_set_vec); i++)
paul718e3742002-12-13 20:15:29 +0000458 if ((rule = vector_slot (route_set_vec, i)) != NULL)
459 if (strcmp (rule->str, name) == 0)
460 return rule;
461 return NULL;
462}
463
464/* Add match and set rule to rule list. */
465static void
466route_map_rule_add (struct route_map_rule_list *list,
467 struct route_map_rule *rule)
468{
469 rule->next = NULL;
470 rule->prev = list->tail;
471 if (list->tail)
472 list->tail->next = rule;
473 else
474 list->head = rule;
475 list->tail = rule;
476}
477
478/* Delete rule from rule list. */
479static void
480route_map_rule_delete (struct route_map_rule_list *list,
481 struct route_map_rule *rule)
482{
483 if (rule->cmd->func_free)
484 (*rule->cmd->func_free) (rule->value);
485
486 if (rule->rule_str)
487 XFREE (MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str);
488
489 if (rule->next)
490 rule->next->prev = rule->prev;
491 else
492 list->tail = rule->prev;
493 if (rule->prev)
494 rule->prev->next = rule->next;
495 else
496 list->head = rule->next;
497
498 XFREE (MTYPE_ROUTE_MAP_RULE, rule);
499}
500
501/* strcmp wrapper function which don't crush even argument is NULL. */
paul8cc41982005-05-06 21:25:49 +0000502static int
paulc9eca012004-10-11 11:28:44 +0000503rulecmp (const char *dst, const char *src)
paul718e3742002-12-13 20:15:29 +0000504{
505 if (dst == NULL)
506 {
507 if (src == NULL)
508 return 0;
509 else
510 return 1;
511 }
512 else
513 {
514 if (src == NULL)
515 return 1;
516 else
517 return strcmp (dst, src);
518 }
519 return 1;
520}
521
522/* Add match statement to route map. */
523int
hasso27a43a82004-10-08 06:29:12 +0000524route_map_add_match (struct route_map_index *index, const char *match_name,
paulc9eca012004-10-11 11:28:44 +0000525 const char *match_arg)
paul718e3742002-12-13 20:15:29 +0000526{
527 struct route_map_rule *rule;
528 struct route_map_rule *next;
529 struct route_map_rule_cmd *cmd;
530 void *compile;
531 int replaced = 0;
532
533 /* First lookup rule for add match statement. */
534 cmd = route_map_lookup_match (match_name);
535 if (cmd == NULL)
536 return RMAP_RULE_MISSING;
537
538 /* Next call compile function for this match statement. */
539 if (cmd->func_compile)
540 {
541 compile= (*cmd->func_compile)(match_arg);
542 if (compile == NULL)
543 return RMAP_COMPILE_ERROR;
544 }
545 else
546 compile = NULL;
547
548 /* If argument is completely same ignore it. */
549 for (rule = index->match_list.head; rule; rule = next)
550 {
551 next = rule->next;
552 if (rule->cmd == cmd)
553 {
554 route_map_rule_delete (&index->match_list, rule);
555 replaced = 1;
556 }
557 }
558
559 /* Add new route map match rule. */
560 rule = route_map_rule_new ();
561 rule->cmd = cmd;
562 rule->value = compile;
563 if (match_arg)
564 rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, match_arg);
565 else
566 rule->rule_str = NULL;
567
568 /* Add new route match rule to linked list. */
569 route_map_rule_add (&index->match_list, rule);
570
571 /* Execute event hook. */
572 if (route_map_master.event_hook)
573 (*route_map_master.event_hook) (replaced ?
574 RMAP_EVENT_MATCH_REPLACED:
575 RMAP_EVENT_MATCH_ADDED,
576 index->map->name);
577
578 return 0;
579}
580
581/* Delete specified route match rule. */
582int
hasso27a43a82004-10-08 06:29:12 +0000583route_map_delete_match (struct route_map_index *index, const char *match_name,
paulc9eca012004-10-11 11:28:44 +0000584 const char *match_arg)
paul718e3742002-12-13 20:15:29 +0000585{
586 struct route_map_rule *rule;
587 struct route_map_rule_cmd *cmd;
588
589 cmd = route_map_lookup_match (match_name);
590 if (cmd == NULL)
591 return 1;
592
593 for (rule = index->match_list.head; rule; rule = rule->next)
594 if (rule->cmd == cmd &&
595 (rulecmp (rule->rule_str, match_arg) == 0 || match_arg == NULL))
596 {
597 route_map_rule_delete (&index->match_list, rule);
598 /* Execute event hook. */
599 if (route_map_master.event_hook)
600 (*route_map_master.event_hook) (RMAP_EVENT_MATCH_DELETED,
601 index->map->name);
602 return 0;
603 }
604 /* Can't find matched rule. */
605 return 1;
606}
607
608/* Add route-map set statement to the route map. */
609int
hasso27a43a82004-10-08 06:29:12 +0000610route_map_add_set (struct route_map_index *index, const char *set_name,
paulc9eca012004-10-11 11:28:44 +0000611 const char *set_arg)
paul718e3742002-12-13 20:15:29 +0000612{
613 struct route_map_rule *rule;
614 struct route_map_rule *next;
615 struct route_map_rule_cmd *cmd;
616 void *compile;
617 int replaced = 0;
618
619 cmd = route_map_lookup_set (set_name);
620 if (cmd == NULL)
621 return RMAP_RULE_MISSING;
622
623 /* Next call compile function for this match statement. */
624 if (cmd->func_compile)
625 {
626 compile= (*cmd->func_compile)(set_arg);
627 if (compile == NULL)
628 return RMAP_COMPILE_ERROR;
629 }
630 else
631 compile = NULL;
632
633 /* Add by WJL. if old set command of same kind exist, delete it first
634 to ensure only one set command of same kind exist under a
635 route_map_index. */
636 for (rule = index->set_list.head; rule; rule = next)
637 {
638 next = rule->next;
639 if (rule->cmd == cmd)
640 {
641 route_map_rule_delete (&index->set_list, rule);
642 replaced = 1;
643 }
644 }
645
646 /* Add new route map match rule. */
647 rule = route_map_rule_new ();
648 rule->cmd = cmd;
649 rule->value = compile;
650 if (set_arg)
651 rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, set_arg);
652 else
653 rule->rule_str = NULL;
654
655 /* Add new route match rule to linked list. */
656 route_map_rule_add (&index->set_list, rule);
657
658 /* Execute event hook. */
659 if (route_map_master.event_hook)
660 (*route_map_master.event_hook) (replaced ?
661 RMAP_EVENT_SET_REPLACED:
662 RMAP_EVENT_SET_ADDED,
663 index->map->name);
664 return 0;
665}
666
667/* Delete route map set rule. */
668int
hasso27a43a82004-10-08 06:29:12 +0000669route_map_delete_set (struct route_map_index *index, const char *set_name,
paulc9eca012004-10-11 11:28:44 +0000670 const char *set_arg)
paul718e3742002-12-13 20:15:29 +0000671{
672 struct route_map_rule *rule;
673 struct route_map_rule_cmd *cmd;
674
675 cmd = route_map_lookup_set (set_name);
676 if (cmd == NULL)
677 return 1;
678
679 for (rule = index->set_list.head; rule; rule = rule->next)
680 if ((rule->cmd == cmd) &&
681 (rulecmp (rule->rule_str, set_arg) == 0 || set_arg == NULL))
682 {
683 route_map_rule_delete (&index->set_list, rule);
684 /* Execute event hook. */
685 if (route_map_master.event_hook)
686 (*route_map_master.event_hook) (RMAP_EVENT_SET_DELETED,
687 index->map->name);
688 return 0;
689 }
690 /* Can't find matched rule. */
691 return 1;
692}
693
paul3bf1c912003-10-29 06:30:19 +0000694/* Apply route map's each index to the object.
695
696 The matrix for a route-map looks like this:
697 (note, this includes the description for the "NEXT"
698 and "GOTO" frobs now
paul718e3742002-12-13 20:15:29 +0000699
paul3bf1c912003-10-29 06:30:19 +0000700 Match | No Match
701 |
702 permit action | cont
703 |
704 ------------------+---------------
705 |
706 deny deny | cont
707 |
708
paulfee0f4c2004-09-13 05:12:46 +0000709 action)
710 -Apply Set statements, accept route
711 -If Call statement is present jump to the specified route-map, if it
712 denies the route we finish.
713 -If NEXT is specified, goto NEXT statement
714 -If GOTO is specified, goto the first clause where pref > nextpref
715 -If nothing is specified, do as Cisco and finish
716 deny)
717 -Route is denied by route-map.
718 cont)
719 -Goto Next index
paul3bf1c912003-10-29 06:30:19 +0000720
721 If we get no matches after we've processed all updates, then the route
722 is dropped too.
723
paulfee0f4c2004-09-13 05:12:46 +0000724 Some notes on the new "CALL", "NEXT" and "GOTO"
725 call WORD - If this clause is matched, then the set statements
726 are executed and then we jump to route-map 'WORD'. If
727 this route-map denies the route, we finish, in other case we
728 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
paul3bf1c912003-10-29 06:30:19 +0000729 on-match next - If this clause is matched, then the set statements
730 are executed and then we drop through to the next clause
731 on-match goto n - If this clause is matched, then the set statments
732 are executed and then we goto the nth clause, or the
733 first clause greater than this. In order to ensure
734 route-maps *always* exit, you cannot jump backwards.
735 Sorry ;)
736
737 We need to make sure our route-map processing matches the above
738*/
paul718e3742002-12-13 20:15:29 +0000739
paul8cc41982005-05-06 21:25:49 +0000740static route_map_result_t
paul3bf1c912003-10-29 06:30:19 +0000741route_map_apply_match (struct route_map_rule_list *match_list,
742 struct prefix *prefix, route_map_object_t type,
743 void *object)
744{
745 route_map_result_t ret = RMAP_NOMATCH;
746 struct route_map_rule *match;
paul718e3742002-12-13 20:15:29 +0000747
paul3bf1c912003-10-29 06:30:19 +0000748
749 /* Check all match rule and if there is no match rule, go to the
750 set statement. */
751 if (!match_list->head)
752 ret = RMAP_MATCH;
753 else
paul718e3742002-12-13 20:15:29 +0000754 {
paul3bf1c912003-10-29 06:30:19 +0000755 for (match = match_list->head; match; match = match->next)
756 {
757 /* Try each match statement in turn, If any do not return
758 RMAP_MATCH, return, otherwise continue on to next match
759 statement. All match statements must match for end-result
760 to be a match. */
761 ret = (*match->cmd->func_apply) (match->value, prefix,
762 type, object);
763 if (ret != RMAP_MATCH)
764 return ret;
765 }
paul718e3742002-12-13 20:15:29 +0000766 }
paul3bf1c912003-10-29 06:30:19 +0000767 return ret;
paul718e3742002-12-13 20:15:29 +0000768}
769
770/* Apply route map to the object. */
771route_map_result_t
paul3bf1c912003-10-29 06:30:19 +0000772route_map_apply (struct route_map *map, struct prefix *prefix,
773 route_map_object_t type, void *object)
paul718e3742002-12-13 20:15:29 +0000774{
paulfee0f4c2004-09-13 05:12:46 +0000775 static int recursion = 0;
paul718e3742002-12-13 20:15:29 +0000776 int ret = 0;
777 struct route_map_index *index;
paul3bf1c912003-10-29 06:30:19 +0000778 struct route_map_rule *set;
paul718e3742002-12-13 20:15:29 +0000779
paulfee0f4c2004-09-13 05:12:46 +0000780 if (recursion > RMAP_RECURSION_LIMIT)
781 {
782 zlog (NULL, LOG_WARNING,
783 "route-map recursion limit (%d) reached, discarding route",
784 RMAP_RECURSION_LIMIT);
785 recursion = 0;
786 return RMAP_DENYMATCH;
787 }
788
paul718e3742002-12-13 20:15:29 +0000789 if (map == NULL)
790 return RMAP_DENYMATCH;
791
792 for (index = map->head; index; index = index->next)
793 {
paul3bf1c912003-10-29 06:30:19 +0000794 /* Apply this index. */
795 ret = route_map_apply_match (&index->match_list, prefix, type, object);
paul718e3742002-12-13 20:15:29 +0000796
paul3bf1c912003-10-29 06:30:19 +0000797 /* Now we apply the matrix from above */
798 if (ret == RMAP_NOMATCH)
799 /* 'cont' from matrix - continue to next route-map sequence */
800 continue;
801 else if (ret == RMAP_MATCH)
802 {
803 if (index->type == RMAP_PERMIT)
804 /* 'action' */
805 {
806 /* permit+match must execute sets */
807 for (set = index->set_list.head; set; set = set->next)
808 ret = (*set->cmd->func_apply) (set->value, prefix,
809 type, object);
paulfee0f4c2004-09-13 05:12:46 +0000810
811 /* Call another route-map if available */
812 if (index->nextrm)
813 {
814 struct route_map *nextrm =
815 route_map_lookup_by_name (index->nextrm);
816
817 if (nextrm) /* Target route-map found, jump to it */
818 {
819 recursion++;
820 ret = route_map_apply (nextrm, prefix, type, object);
821 recursion--;
822 }
823
824 /* If nextrm returned 'deny', finish. */
825 if (ret == RMAP_DENYMATCH)
826 return ret;
827 }
828
paul3bf1c912003-10-29 06:30:19 +0000829 switch (index->exitpolicy)
830 {
831 case RMAP_EXIT:
832 return ret;
833 case RMAP_NEXT:
834 continue;
835 case RMAP_GOTO:
836 {
837 /* Find the next clause to jump to */
838 struct route_map_index *next = index->next;
paulfee0f4c2004-09-13 05:12:46 +0000839 int nextpref = index->nextpref;
paul718e3742002-12-13 20:15:29 +0000840
paulfee0f4c2004-09-13 05:12:46 +0000841 while (next && next->pref < nextpref)
paul3bf1c912003-10-29 06:30:19 +0000842 {
843 index = next;
844 next = next->next;
845 }
846 if (next == NULL)
847 {
848 /* No clauses match! */
849 return ret;
850 }
851 }
852 }
853 }
854 else if (index->type == RMAP_DENY)
855 /* 'deny' */
856 {
paul3bf1c912003-10-29 06:30:19 +0000857 return RMAP_DENYMATCH;
858 }
859 }
paul718e3742002-12-13 20:15:29 +0000860 }
861 /* Finally route-map does not match at all. */
862 return RMAP_DENYMATCH;
863}
864
865void
paul9035efa2004-10-10 11:56:56 +0000866route_map_add_hook (void (*func) (const char *))
paul718e3742002-12-13 20:15:29 +0000867{
868 route_map_master.add_hook = func;
869}
870
871void
paul9035efa2004-10-10 11:56:56 +0000872route_map_delete_hook (void (*func) (const char *))
paul718e3742002-12-13 20:15:29 +0000873{
874 route_map_master.delete_hook = func;
875}
876
877void
paul9035efa2004-10-10 11:56:56 +0000878route_map_event_hook (void (*func) (route_map_event_t, const char *))
paul718e3742002-12-13 20:15:29 +0000879{
880 route_map_master.event_hook = func;
881}
882
883void
paul8cc41982005-05-06 21:25:49 +0000884route_map_init (void)
paul718e3742002-12-13 20:15:29 +0000885{
886 /* Make vector for match and set. */
887 route_match_vec = vector_init (1);
888 route_set_vec = vector_init (1);
889}
890
891/* VTY related functions. */
892DEFUN (route_map,
893 route_map_cmd,
894 "route-map WORD (deny|permit) <1-65535>",
895 "Create route-map or enter route-map command mode\n"
896 "Route map tag\n"
897 "Route map denies set operations\n"
898 "Route map permits set operations\n"
899 "Sequence to insert to/delete from existing route-map entry\n")
900{
901 int permit;
902 unsigned long pref;
903 struct route_map *map;
904 struct route_map_index *index;
905 char *endptr = NULL;
906
907 /* Permit check. */
908 if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
909 permit = RMAP_PERMIT;
910 else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
911 permit = RMAP_DENY;
912 else
913 {
914 vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
915 return CMD_WARNING;
916 }
917
918 /* Preference check. */
919 pref = strtoul (argv[2], &endptr, 10);
920 if (pref == ULONG_MAX || *endptr != '\0')
921 {
922 vty_out (vty, "the fourth field must be positive integer%s",
923 VTY_NEWLINE);
924 return CMD_WARNING;
925 }
926 if (pref == 0 || pref > 65535)
927 {
928 vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
929 return CMD_WARNING;
930 }
931
932 /* Get route map. */
933 map = route_map_get (argv[0]);
934 index = route_map_index_get (map, permit, pref);
935
936 vty->index = index;
937 vty->node = RMAP_NODE;
938 return CMD_SUCCESS;
939}
940
941DEFUN (no_route_map_all,
942 no_route_map_all_cmd,
943 "no route-map WORD",
944 NO_STR
945 "Create route-map or enter route-map command mode\n"
946 "Route map tag\n")
947{
948 struct route_map *map;
949
950 map = route_map_lookup_by_name (argv[0]);
951 if (map == NULL)
952 {
953 vty_out (vty, "%% Could not find route-map %s%s",
954 argv[0], VTY_NEWLINE);
955 return CMD_WARNING;
956 }
957
958 route_map_delete (map);
959
960 return CMD_SUCCESS;
961}
962
963DEFUN (no_route_map,
964 no_route_map_cmd,
965 "no route-map WORD (deny|permit) <1-65535>",
966 NO_STR
967 "Create route-map or enter route-map command mode\n"
968 "Route map tag\n"
969 "Route map denies set operations\n"
970 "Route map permits set operations\n"
971 "Sequence to insert to/delete from existing route-map entry\n")
972{
973 int permit;
974 unsigned long pref;
975 struct route_map *map;
976 struct route_map_index *index;
977 char *endptr = NULL;
978
979 /* Permit check. */
980 if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
981 permit = RMAP_PERMIT;
982 else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
983 permit = RMAP_DENY;
984 else
985 {
986 vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
987 return CMD_WARNING;
988 }
989
990 /* Preference. */
991 pref = strtoul (argv[2], &endptr, 10);
992 if (pref == ULONG_MAX || *endptr != '\0')
993 {
994 vty_out (vty, "the fourth field must be positive integer%s",
995 VTY_NEWLINE);
996 return CMD_WARNING;
997 }
998 if (pref == 0 || pref > 65535)
999 {
1000 vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
1001 return CMD_WARNING;
1002 }
1003
1004 /* Existence check. */
1005 map = route_map_lookup_by_name (argv[0]);
1006 if (map == NULL)
1007 {
1008 vty_out (vty, "%% Could not find route-map %s%s",
1009 argv[0], VTY_NEWLINE);
1010 return CMD_WARNING;
1011 }
1012
1013 /* Lookup route map index. */
1014 index = route_map_index_lookup (map, permit, pref);
1015 if (index == NULL)
1016 {
1017 vty_out (vty, "%% Could not find route-map entry %s %s%s",
1018 argv[0], argv[2], VTY_NEWLINE);
1019 return CMD_WARNING;
1020 }
1021
1022 /* Delete index from route map. */
1023 route_map_index_delete (index, 1);
1024
1025 /* If this route rule is the last one, delete route map itself. */
1026 if (route_map_empty (map))
1027 route_map_delete (map);
1028
1029 return CMD_SUCCESS;
1030}
1031
1032DEFUN (rmap_onmatch_next,
1033 rmap_onmatch_next_cmd,
1034 "on-match next",
1035 "Exit policy on matches\n"
1036 "Next clause\n")
1037{
1038 struct route_map_index *index;
1039
1040 index = vty->index;
1041
1042 if (index)
1043 index->exitpolicy = RMAP_NEXT;
1044
1045 return CMD_SUCCESS;
1046}
1047
1048DEFUN (no_rmap_onmatch_next,
1049 no_rmap_onmatch_next_cmd,
1050 "no on-match next",
1051 NO_STR
1052 "Exit policy on matches\n"
1053 "Next clause\n")
1054{
1055 struct route_map_index *index;
1056
1057 index = vty->index;
1058
1059 if (index)
1060 index->exitpolicy = RMAP_EXIT;
1061
1062 return CMD_SUCCESS;
1063}
1064
1065DEFUN (rmap_onmatch_goto,
1066 rmap_onmatch_goto_cmd,
1067 "on-match goto <1-65535>",
1068 "Exit policy on matches\n"
1069 "Goto Clause number\n"
1070 "Number\n")
1071{
pauld4f09602005-05-23 12:43:34 +00001072 struct route_map_index *index = vty->index;
paul718e3742002-12-13 20:15:29 +00001073 int d = 0;
1074
paul718e3742002-12-13 20:15:29 +00001075 if (index)
1076 {
pauld4f09602005-05-23 12:43:34 +00001077 if (argc == 1 && argv[0])
1078 VTY_GET_INTEGER_RANGE("route-map index", d, argv[0], 1, 65536);
1079 else
1080 d = index->pref + 1;
1081
paul718e3742002-12-13 20:15:29 +00001082 if (d <= index->pref)
1083 {
1084 /* Can't allow you to do that, Dave */
1085 vty_out (vty, "can't jump backwards in route-maps%s",
1086 VTY_NEWLINE);
1087 return CMD_WARNING;
1088 }
1089 else
1090 {
1091 index->exitpolicy = RMAP_GOTO;
1092 index->nextpref = d;
1093 }
1094 }
1095 return CMD_SUCCESS;
1096}
1097
1098DEFUN (no_rmap_onmatch_goto,
1099 no_rmap_onmatch_goto_cmd,
1100 "no on-match goto",
1101 NO_STR
1102 "Exit policy on matches\n"
paulfee0f4c2004-09-13 05:12:46 +00001103 "Goto Clause number\n")
paul718e3742002-12-13 20:15:29 +00001104{
1105 struct route_map_index *index;
1106
1107 index = vty->index;
1108
1109 if (index)
1110 index->exitpolicy = RMAP_EXIT;
1111
1112 return CMD_SUCCESS;
1113}
1114
paul5510e832004-07-09 14:00:01 +00001115/* Cisco/GNU Zebra compatible ALIASes for on-match next */
1116ALIAS (rmap_onmatch_goto,
1117 rmap_continue_cmd,
1118 "continue",
1119 "Continue on a different entry within the route-map\n")
1120
1121ALIAS (no_rmap_onmatch_goto,
1122 no_rmap_continue_cmd,
1123 "no continue",
1124 NO_STR
1125 "Continue on a different entry within the route-map\n")
1126
1127/* GNU Zebra compatible */
1128ALIAS (rmap_onmatch_goto,
1129 rmap_continue_seq_cmd,
1130 "continue <1-65535>",
1131 "Continue on a different entry within the route-map\n"
1132 "Route-map entry sequence number\n")
1133
1134ALIAS (no_rmap_onmatch_goto,
1135 no_rmap_continue_seq,
1136 "no continue <1-65535>",
1137 NO_STR
1138 "Continue on a different entry within the route-map\n"
1139 "Route-map entry sequence number\n")
1140
1141DEFUN (rmap_show,
1142 rmap_show_cmd,
1143 "show route-map",
1144 SHOW_STR
1145 "route-map information\n")
1146{
1147 return vty_show_route_map (vty, NULL);
1148}
1149
1150DEFUN (rmap_show_name,
1151 rmap_show_name_cmd,
1152 "show route-map WORD",
1153 SHOW_STR
1154 "route-map information\n"
1155 "route-map name\n")
1156{
1157 return vty_show_route_map (vty, argv[0]);
1158}
1159
paulfee0f4c2004-09-13 05:12:46 +00001160ALIAS (rmap_onmatch_goto,
1161 rmap_continue_index_cmd,
1162 "continue <1-65536>",
1163 "Exit policy on matches\n"
1164 "Goto Clause number\n")
1165
1166DEFUN (rmap_call,
1167 rmap_call_cmd,
1168 "call WORD",
1169 "Jump to another Route-Map after match+set\n"
1170 "Target route-map name\n")
1171{
1172 struct route_map_index *index;
1173
1174 index = vty->index;
1175 if (index)
1176 {
1177 if (index->nextrm)
paul02416842005-10-26 05:05:16 +00001178 XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
1179 index->nextrm = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[0]);
paulfee0f4c2004-09-13 05:12:46 +00001180 }
1181 return CMD_SUCCESS;
1182}
1183
1184DEFUN (no_rmap_call,
1185 no_rmap_call_cmd,
1186 "no call",
1187 NO_STR
1188 "Jump to another Route-Map after match+set\n")
1189{
1190 struct route_map_index *index;
1191
1192 index = vty->index;
1193
1194 if (index->nextrm)
1195 {
paul02416842005-10-26 05:05:16 +00001196 XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
paulfee0f4c2004-09-13 05:12:46 +00001197 index->nextrm = NULL;
1198 }
1199
1200 return CMD_SUCCESS;
1201}
1202
hasso4a8164e2005-04-08 14:20:18 +00001203DEFUN (rmap_description,
1204 rmap_description_cmd,
1205 "description .LINE",
1206 "Route-map comment\n"
1207 "Comment describing this route-map rule\n")
1208{
1209 struct route_map_index *index;
1210
1211 index = vty->index;
1212 if (index)
1213 {
1214 if (index->description)
1215 XFREE (MTYPE_TMP, index->description);
1216 index->description = argv_concat (argv, argc, 0);
1217 }
1218 return CMD_SUCCESS;
1219}
1220
1221DEFUN (no_rmap_description,
1222 no_rmap_description_cmd,
1223 "no description",
1224 NO_STR
1225 "Route-map comment\n")
1226{
1227 struct route_map_index *index;
1228
1229 index = vty->index;
1230 if (index)
1231 {
1232 if (index->description)
1233 XFREE (MTYPE_TMP, index->description);
1234 index->description = NULL;
1235 }
1236 return CMD_SUCCESS;
1237}
1238
paul718e3742002-12-13 20:15:29 +00001239/* Configuration write function. */
paul8cc41982005-05-06 21:25:49 +00001240static int
paul718e3742002-12-13 20:15:29 +00001241route_map_config_write (struct vty *vty)
1242{
1243 struct route_map *map;
1244 struct route_map_index *index;
1245 struct route_map_rule *rule;
1246 int first = 1;
1247 int write = 0;
1248
1249 for (map = route_map_master.head; map; map = map->next)
1250 for (index = map->head; index; index = index->next)
1251 {
1252 if (!first)
1253 vty_out (vty, "!%s", VTY_NEWLINE);
1254 else
1255 first = 0;
1256
1257 vty_out (vty, "route-map %s %s %d%s",
1258 map->name,
1259 route_map_type_str (index->type),
1260 index->pref, VTY_NEWLINE);
1261
hasso4a8164e2005-04-08 14:20:18 +00001262 if (index->description)
1263 vty_out (vty, " description %s%s", index->description, VTY_NEWLINE);
1264
paul718e3742002-12-13 20:15:29 +00001265 for (rule = index->match_list.head; rule; rule = rule->next)
1266 vty_out (vty, " match %s %s%s", rule->cmd->str,
1267 rule->rule_str ? rule->rule_str : "",
1268 VTY_NEWLINE);
1269
1270 for (rule = index->set_list.head; rule; rule = rule->next)
1271 vty_out (vty, " set %s %s%s", rule->cmd->str,
1272 rule->rule_str ? rule->rule_str : "",
1273 VTY_NEWLINE);
paulfee0f4c2004-09-13 05:12:46 +00001274 if (index->nextrm)
1275 vty_out (vty, " call %s%s", index->nextrm, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00001276 if (index->exitpolicy == RMAP_GOTO)
paulfee0f4c2004-09-13 05:12:46 +00001277 vty_out (vty, " on-match goto %d%s", index->nextpref, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00001278 if (index->exitpolicy == RMAP_NEXT)
1279 vty_out (vty," on-match next%s", VTY_NEWLINE);
1280
1281 write++;
1282 }
1283 return write;
1284}
1285
1286/* Route map node structure. */
1287struct cmd_node rmap_node =
1288{
1289 RMAP_NODE,
1290 "%s(config-route-map)# ",
1291 1
1292};
1293
1294/* Initialization of route map vector. */
1295void
paul8cc41982005-05-06 21:25:49 +00001296route_map_init_vty (void)
paul718e3742002-12-13 20:15:29 +00001297{
1298 /* Install route map top node. */
1299 install_node (&rmap_node, route_map_config_write);
1300
1301 /* Install route map commands. */
1302 install_default (RMAP_NODE);
1303 install_element (CONFIG_NODE, &route_map_cmd);
1304 install_element (CONFIG_NODE, &no_route_map_cmd);
1305 install_element (CONFIG_NODE, &no_route_map_all_cmd);
1306
1307 /* Install the on-match stuff */
1308 install_element (RMAP_NODE, &route_map_cmd);
1309 install_element (RMAP_NODE, &rmap_onmatch_next_cmd);
1310 install_element (RMAP_NODE, &no_rmap_onmatch_next_cmd);
1311 install_element (RMAP_NODE, &rmap_onmatch_goto_cmd);
1312 install_element (RMAP_NODE, &no_rmap_onmatch_goto_cmd);
paulfee0f4c2004-09-13 05:12:46 +00001313
1314 /* Install the continue stuff (ALIAS of on-match). */
1315 install_element (RMAP_NODE, &rmap_continue_cmd);
1316 install_element (RMAP_NODE, &no_rmap_continue_cmd);
1317 install_element (RMAP_NODE, &rmap_continue_index_cmd);
1318
1319 /* Install the call stuff. */
1320 install_element (RMAP_NODE, &rmap_call_cmd);
1321 install_element (RMAP_NODE, &no_rmap_call_cmd);
hasso4a8164e2005-04-08 14:20:18 +00001322
1323 /* Install description commands. */
1324 install_element (RMAP_NODE, &rmap_description_cmd);
1325 install_element (RMAP_NODE, &no_rmap_description_cmd);
paulfee0f4c2004-09-13 05:12:46 +00001326
paul5510e832004-07-09 14:00:01 +00001327 /* Install show command */
1328 install_element (ENABLE_NODE, &rmap_show_cmd);
1329 install_element (ENABLE_NODE, &rmap_show_name_cmd);
paul718e3742002-12-13 20:15:29 +00001330}