blob: 55cc33c775fa8bd26d7cd6865df21b63e25e4d1e [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
pauldb29ae52005-11-12 22:36:41 +0000235 /* Call clause */
236 vty_out (vty, " Call clause:%s", VTY_NEWLINE);
paulfee0f4c2004-09-13 05:12:46 +0000237 if (index->nextrm)
238 vty_out (vty, " Call %s%s", index->nextrm, VTY_NEWLINE);
pauldb29ae52005-11-12 22:36:41 +0000239
240 /* Exit Policy */
241 vty_out (vty, " Action:%s", VTY_NEWLINE);
242 if (index->exitpolicy == RMAP_GOTO)
paul5510e832004-07-09 14:00:01 +0000243 vty_out (vty, " Goto %d%s", index->nextpref, VTY_NEWLINE);
paul5510e832004-07-09 14:00:01 +0000244 else if (index->exitpolicy == RMAP_NEXT)
pauldb29ae52005-11-12 22:36:41 +0000245 vty_out (vty, " Continue to next entry%s", VTY_NEWLINE);
paul5510e832004-07-09 14:00:01 +0000246 else if (index->exitpolicy == RMAP_EXIT)
247 vty_out (vty, " Exit routemap%s", VTY_NEWLINE);
248 }
paul718e3742002-12-13 20:15:29 +0000249}
250
paul8cc41982005-05-06 21:25:49 +0000251static int
paul9035efa2004-10-10 11:56:56 +0000252vty_show_route_map (struct vty *vty, const char *name)
paul5510e832004-07-09 14:00:01 +0000253{
254 struct route_map *map;
255
256 if (name)
257 {
258 map = route_map_lookup_by_name (name);
259
260 if (map)
261 {
262 vty_show_route_map_entry (vty, map);
263 return CMD_SUCCESS;
264 }
265 else
266 {
267 vty_out (vty, "%%route-map %s not found%s", name, VTY_NEWLINE);
268 return CMD_WARNING;
269 }
270 }
271 return CMD_SUCCESS;
272}
273
274
paul718e3742002-12-13 20:15:29 +0000275/* New route map allocation. Please note route map's name must be
276 specified. */
paul8cc41982005-05-06 21:25:49 +0000277static struct route_map_index *
278route_map_index_new (void)
paul718e3742002-12-13 20:15:29 +0000279{
280 struct route_map_index *new;
281
282 new = XCALLOC (MTYPE_ROUTE_MAP_INDEX, sizeof (struct route_map_index));
283 new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */
284 return new;
285}
286
287/* Free route map index. */
288static void
289route_map_index_delete (struct route_map_index *index, int notify)
290{
291 struct route_map_rule *rule;
292
293 /* Free route match. */
294 while ((rule = index->match_list.head) != NULL)
295 route_map_rule_delete (&index->match_list, rule);
296
297 /* Free route set. */
298 while ((rule = index->set_list.head) != NULL)
299 route_map_rule_delete (&index->set_list, rule);
300
301 /* Remove index from route map list. */
302 if (index->next)
303 index->next->prev = index->prev;
304 else
305 index->map->tail = index->prev;
306
307 if (index->prev)
308 index->prev->next = index->next;
309 else
310 index->map->head = index->next;
311
paulfee0f4c2004-09-13 05:12:46 +0000312 /* Free 'char *nextrm' if not NULL */
313 if (index->nextrm)
paul02416842005-10-26 05:05:16 +0000314 XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
paulfee0f4c2004-09-13 05:12:46 +0000315
paul718e3742002-12-13 20:15:29 +0000316 /* Execute event hook. */
317 if (route_map_master.event_hook && notify)
318 (*route_map_master.event_hook) (RMAP_EVENT_INDEX_DELETED,
319 index->map->name);
320
321 XFREE (MTYPE_ROUTE_MAP_INDEX, index);
322}
323
324/* Lookup index from route map. */
paul8cc41982005-05-06 21:25:49 +0000325static struct route_map_index *
paul718e3742002-12-13 20:15:29 +0000326route_map_index_lookup (struct route_map *map, enum route_map_type type,
327 int pref)
328{
329 struct route_map_index *index;
330
331 for (index = map->head; index; index = index->next)
332 if ((index->type == type || type == RMAP_ANY)
333 && index->pref == pref)
334 return index;
335 return NULL;
336}
337
338/* Add new index to route map. */
paul8cc41982005-05-06 21:25:49 +0000339static struct route_map_index *
paul718e3742002-12-13 20:15:29 +0000340route_map_index_add (struct route_map *map, enum route_map_type type,
341 int pref)
342{
343 struct route_map_index *index;
344 struct route_map_index *point;
345
346 /* Allocate new route map inex. */
347 index = route_map_index_new ();
348 index->map = map;
349 index->type = type;
350 index->pref = pref;
351
352 /* Compare preference. */
353 for (point = map->head; point; point = point->next)
354 if (point->pref >= pref)
355 break;
356
357 if (map->head == NULL)
358 {
359 map->head = map->tail = index;
360 }
361 else if (point == NULL)
362 {
363 index->prev = map->tail;
364 map->tail->next = index;
365 map->tail = index;
366 }
367 else if (point == map->head)
368 {
369 index->next = map->head;
370 map->head->prev = index;
371 map->head = index;
372 }
373 else
374 {
375 index->next = point;
376 index->prev = point->prev;
377 if (point->prev)
378 point->prev->next = index;
379 point->prev = index;
380 }
381
382 /* Execute event hook. */
383 if (route_map_master.event_hook)
384 (*route_map_master.event_hook) (RMAP_EVENT_INDEX_ADDED,
385 map->name);
386
387 return index;
388}
389
390/* Get route map index. */
paul8cc41982005-05-06 21:25:49 +0000391static struct route_map_index *
paul718e3742002-12-13 20:15:29 +0000392route_map_index_get (struct route_map *map, enum route_map_type type,
393 int pref)
394{
395 struct route_map_index *index;
396
397 index = route_map_index_lookup (map, RMAP_ANY, pref);
398 if (index && index->type != type)
399 {
400 /* Delete index from route map. */
401 route_map_index_delete (index, 1);
402 index = NULL;
403 }
404 if (index == NULL)
405 index = route_map_index_add (map, type, pref);
406 return index;
407}
408
409/* New route map rule */
paul8cc41982005-05-06 21:25:49 +0000410static struct route_map_rule *
411route_map_rule_new (void)
paul718e3742002-12-13 20:15:29 +0000412{
413 struct route_map_rule *new;
414
415 new = XCALLOC (MTYPE_ROUTE_MAP_RULE, sizeof (struct route_map_rule));
416 return new;
417}
418
419/* Install rule command to the match list. */
420void
421route_map_install_match (struct route_map_rule_cmd *cmd)
422{
423 vector_set (route_match_vec, cmd);
424}
425
426/* Install rule command to the set list. */
427void
428route_map_install_set (struct route_map_rule_cmd *cmd)
429{
430 vector_set (route_set_vec, cmd);
431}
432
433/* Lookup rule command from match list. */
paul8cc41982005-05-06 21:25:49 +0000434static struct route_map_rule_cmd *
hasso27a43a82004-10-08 06:29:12 +0000435route_map_lookup_match (const char *name)
paul718e3742002-12-13 20:15:29 +0000436{
hasso8c328f12004-10-05 21:01:23 +0000437 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000438 struct route_map_rule_cmd *rule;
439
paul55468c82005-03-14 20:19:01 +0000440 for (i = 0; i < vector_active (route_match_vec); i++)
paul718e3742002-12-13 20:15:29 +0000441 if ((rule = vector_slot (route_match_vec, i)) != NULL)
442 if (strcmp (rule->str, name) == 0)
443 return rule;
444 return NULL;
445}
446
447/* Lookup rule command from set list. */
paul8cc41982005-05-06 21:25:49 +0000448static struct route_map_rule_cmd *
hasso27a43a82004-10-08 06:29:12 +0000449route_map_lookup_set (const char *name)
paul718e3742002-12-13 20:15:29 +0000450{
hasso8c328f12004-10-05 21:01:23 +0000451 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000452 struct route_map_rule_cmd *rule;
453
paul55468c82005-03-14 20:19:01 +0000454 for (i = 0; i < vector_active (route_set_vec); i++)
paul718e3742002-12-13 20:15:29 +0000455 if ((rule = vector_slot (route_set_vec, i)) != NULL)
456 if (strcmp (rule->str, name) == 0)
457 return rule;
458 return NULL;
459}
460
461/* Add match and set rule to rule list. */
462static void
463route_map_rule_add (struct route_map_rule_list *list,
464 struct route_map_rule *rule)
465{
466 rule->next = NULL;
467 rule->prev = list->tail;
468 if (list->tail)
469 list->tail->next = rule;
470 else
471 list->head = rule;
472 list->tail = rule;
473}
474
475/* Delete rule from rule list. */
476static void
477route_map_rule_delete (struct route_map_rule_list *list,
478 struct route_map_rule *rule)
479{
480 if (rule->cmd->func_free)
481 (*rule->cmd->func_free) (rule->value);
482
483 if (rule->rule_str)
484 XFREE (MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str);
485
486 if (rule->next)
487 rule->next->prev = rule->prev;
488 else
489 list->tail = rule->prev;
490 if (rule->prev)
491 rule->prev->next = rule->next;
492 else
493 list->head = rule->next;
494
495 XFREE (MTYPE_ROUTE_MAP_RULE, rule);
496}
497
498/* strcmp wrapper function which don't crush even argument is NULL. */
paul8cc41982005-05-06 21:25:49 +0000499static int
paulc9eca012004-10-11 11:28:44 +0000500rulecmp (const char *dst, const char *src)
paul718e3742002-12-13 20:15:29 +0000501{
502 if (dst == NULL)
503 {
504 if (src == NULL)
505 return 0;
506 else
507 return 1;
508 }
509 else
510 {
511 if (src == NULL)
512 return 1;
513 else
514 return strcmp (dst, src);
515 }
516 return 1;
517}
518
519/* Add match statement to route map. */
520int
hasso27a43a82004-10-08 06:29:12 +0000521route_map_add_match (struct route_map_index *index, const char *match_name,
paulc9eca012004-10-11 11:28:44 +0000522 const char *match_arg)
paul718e3742002-12-13 20:15:29 +0000523{
524 struct route_map_rule *rule;
525 struct route_map_rule *next;
526 struct route_map_rule_cmd *cmd;
527 void *compile;
528 int replaced = 0;
529
530 /* First lookup rule for add match statement. */
531 cmd = route_map_lookup_match (match_name);
532 if (cmd == NULL)
533 return RMAP_RULE_MISSING;
534
535 /* Next call compile function for this match statement. */
536 if (cmd->func_compile)
537 {
538 compile= (*cmd->func_compile)(match_arg);
539 if (compile == NULL)
540 return RMAP_COMPILE_ERROR;
541 }
542 else
543 compile = NULL;
544
545 /* If argument is completely same ignore it. */
546 for (rule = index->match_list.head; rule; rule = next)
547 {
548 next = rule->next;
549 if (rule->cmd == cmd)
550 {
551 route_map_rule_delete (&index->match_list, rule);
552 replaced = 1;
553 }
554 }
555
556 /* Add new route map match rule. */
557 rule = route_map_rule_new ();
558 rule->cmd = cmd;
559 rule->value = compile;
560 if (match_arg)
561 rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, match_arg);
562 else
563 rule->rule_str = NULL;
564
565 /* Add new route match rule to linked list. */
566 route_map_rule_add (&index->match_list, rule);
567
568 /* Execute event hook. */
569 if (route_map_master.event_hook)
570 (*route_map_master.event_hook) (replaced ?
571 RMAP_EVENT_MATCH_REPLACED:
572 RMAP_EVENT_MATCH_ADDED,
573 index->map->name);
574
575 return 0;
576}
577
578/* Delete specified route match rule. */
579int
hasso27a43a82004-10-08 06:29:12 +0000580route_map_delete_match (struct route_map_index *index, const char *match_name,
paulc9eca012004-10-11 11:28:44 +0000581 const char *match_arg)
paul718e3742002-12-13 20:15:29 +0000582{
583 struct route_map_rule *rule;
584 struct route_map_rule_cmd *cmd;
585
586 cmd = route_map_lookup_match (match_name);
587 if (cmd == NULL)
588 return 1;
589
590 for (rule = index->match_list.head; rule; rule = rule->next)
591 if (rule->cmd == cmd &&
592 (rulecmp (rule->rule_str, match_arg) == 0 || match_arg == NULL))
593 {
594 route_map_rule_delete (&index->match_list, rule);
595 /* Execute event hook. */
596 if (route_map_master.event_hook)
597 (*route_map_master.event_hook) (RMAP_EVENT_MATCH_DELETED,
598 index->map->name);
599 return 0;
600 }
601 /* Can't find matched rule. */
602 return 1;
603}
604
605/* Add route-map set statement to the route map. */
606int
hasso27a43a82004-10-08 06:29:12 +0000607route_map_add_set (struct route_map_index *index, const char *set_name,
paulc9eca012004-10-11 11:28:44 +0000608 const char *set_arg)
paul718e3742002-12-13 20:15:29 +0000609{
610 struct route_map_rule *rule;
611 struct route_map_rule *next;
612 struct route_map_rule_cmd *cmd;
613 void *compile;
614 int replaced = 0;
615
616 cmd = route_map_lookup_set (set_name);
617 if (cmd == NULL)
618 return RMAP_RULE_MISSING;
619
620 /* Next call compile function for this match statement. */
621 if (cmd->func_compile)
622 {
623 compile= (*cmd->func_compile)(set_arg);
624 if (compile == NULL)
625 return RMAP_COMPILE_ERROR;
626 }
627 else
628 compile = NULL;
629
630 /* Add by WJL. if old set command of same kind exist, delete it first
631 to ensure only one set command of same kind exist under a
632 route_map_index. */
633 for (rule = index->set_list.head; rule; rule = next)
634 {
635 next = rule->next;
636 if (rule->cmd == cmd)
637 {
638 route_map_rule_delete (&index->set_list, rule);
639 replaced = 1;
640 }
641 }
642
643 /* Add new route map match rule. */
644 rule = route_map_rule_new ();
645 rule->cmd = cmd;
646 rule->value = compile;
647 if (set_arg)
648 rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, set_arg);
649 else
650 rule->rule_str = NULL;
651
652 /* Add new route match rule to linked list. */
653 route_map_rule_add (&index->set_list, rule);
654
655 /* Execute event hook. */
656 if (route_map_master.event_hook)
657 (*route_map_master.event_hook) (replaced ?
658 RMAP_EVENT_SET_REPLACED:
659 RMAP_EVENT_SET_ADDED,
660 index->map->name);
661 return 0;
662}
663
664/* Delete route map set rule. */
665int
hasso27a43a82004-10-08 06:29:12 +0000666route_map_delete_set (struct route_map_index *index, const char *set_name,
paulc9eca012004-10-11 11:28:44 +0000667 const char *set_arg)
paul718e3742002-12-13 20:15:29 +0000668{
669 struct route_map_rule *rule;
670 struct route_map_rule_cmd *cmd;
671
672 cmd = route_map_lookup_set (set_name);
673 if (cmd == NULL)
674 return 1;
675
676 for (rule = index->set_list.head; rule; rule = rule->next)
677 if ((rule->cmd == cmd) &&
678 (rulecmp (rule->rule_str, set_arg) == 0 || set_arg == NULL))
679 {
680 route_map_rule_delete (&index->set_list, rule);
681 /* Execute event hook. */
682 if (route_map_master.event_hook)
683 (*route_map_master.event_hook) (RMAP_EVENT_SET_DELETED,
684 index->map->name);
685 return 0;
686 }
687 /* Can't find matched rule. */
688 return 1;
689}
690
paul3bf1c912003-10-29 06:30:19 +0000691/* Apply route map's each index to the object.
692
693 The matrix for a route-map looks like this:
694 (note, this includes the description for the "NEXT"
695 and "GOTO" frobs now
paul718e3742002-12-13 20:15:29 +0000696
paul3bf1c912003-10-29 06:30:19 +0000697 Match | No Match
698 |
699 permit action | cont
700 |
701 ------------------+---------------
702 |
703 deny deny | cont
704 |
705
paulfee0f4c2004-09-13 05:12:46 +0000706 action)
707 -Apply Set statements, accept route
708 -If Call statement is present jump to the specified route-map, if it
709 denies the route we finish.
710 -If NEXT is specified, goto NEXT statement
711 -If GOTO is specified, goto the first clause where pref > nextpref
712 -If nothing is specified, do as Cisco and finish
713 deny)
714 -Route is denied by route-map.
715 cont)
716 -Goto Next index
paul3bf1c912003-10-29 06:30:19 +0000717
718 If we get no matches after we've processed all updates, then the route
719 is dropped too.
720
paulfee0f4c2004-09-13 05:12:46 +0000721 Some notes on the new "CALL", "NEXT" and "GOTO"
722 call WORD - If this clause is matched, then the set statements
723 are executed and then we jump to route-map 'WORD'. If
724 this route-map denies the route, we finish, in other case we
725 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
paul3bf1c912003-10-29 06:30:19 +0000726 on-match next - If this clause is matched, then the set statements
727 are executed and then we drop through to the next clause
728 on-match goto n - If this clause is matched, then the set statments
729 are executed and then we goto the nth clause, or the
730 first clause greater than this. In order to ensure
731 route-maps *always* exit, you cannot jump backwards.
732 Sorry ;)
733
734 We need to make sure our route-map processing matches the above
735*/
paul718e3742002-12-13 20:15:29 +0000736
paul8cc41982005-05-06 21:25:49 +0000737static route_map_result_t
paul3bf1c912003-10-29 06:30:19 +0000738route_map_apply_match (struct route_map_rule_list *match_list,
739 struct prefix *prefix, route_map_object_t type,
740 void *object)
741{
742 route_map_result_t ret = RMAP_NOMATCH;
743 struct route_map_rule *match;
paul718e3742002-12-13 20:15:29 +0000744
paul3bf1c912003-10-29 06:30:19 +0000745
746 /* Check all match rule and if there is no match rule, go to the
747 set statement. */
748 if (!match_list->head)
749 ret = RMAP_MATCH;
750 else
paul718e3742002-12-13 20:15:29 +0000751 {
paul3bf1c912003-10-29 06:30:19 +0000752 for (match = match_list->head; match; match = match->next)
753 {
754 /* Try each match statement in turn, If any do not return
755 RMAP_MATCH, return, otherwise continue on to next match
756 statement. All match statements must match for end-result
757 to be a match. */
758 ret = (*match->cmd->func_apply) (match->value, prefix,
759 type, object);
760 if (ret != RMAP_MATCH)
761 return ret;
762 }
paul718e3742002-12-13 20:15:29 +0000763 }
paul3bf1c912003-10-29 06:30:19 +0000764 return ret;
paul718e3742002-12-13 20:15:29 +0000765}
766
767/* Apply route map to the object. */
768route_map_result_t
paul3bf1c912003-10-29 06:30:19 +0000769route_map_apply (struct route_map *map, struct prefix *prefix,
770 route_map_object_t type, void *object)
paul718e3742002-12-13 20:15:29 +0000771{
paulfee0f4c2004-09-13 05:12:46 +0000772 static int recursion = 0;
paul718e3742002-12-13 20:15:29 +0000773 int ret = 0;
774 struct route_map_index *index;
paul3bf1c912003-10-29 06:30:19 +0000775 struct route_map_rule *set;
paul718e3742002-12-13 20:15:29 +0000776
paulfee0f4c2004-09-13 05:12:46 +0000777 if (recursion > RMAP_RECURSION_LIMIT)
778 {
779 zlog (NULL, LOG_WARNING,
780 "route-map recursion limit (%d) reached, discarding route",
781 RMAP_RECURSION_LIMIT);
782 recursion = 0;
783 return RMAP_DENYMATCH;
784 }
785
paul718e3742002-12-13 20:15:29 +0000786 if (map == NULL)
787 return RMAP_DENYMATCH;
788
789 for (index = map->head; index; index = index->next)
790 {
paul3bf1c912003-10-29 06:30:19 +0000791 /* Apply this index. */
792 ret = route_map_apply_match (&index->match_list, prefix, type, object);
paul718e3742002-12-13 20:15:29 +0000793
paul3bf1c912003-10-29 06:30:19 +0000794 /* Now we apply the matrix from above */
795 if (ret == RMAP_NOMATCH)
796 /* 'cont' from matrix - continue to next route-map sequence */
797 continue;
798 else if (ret == RMAP_MATCH)
799 {
800 if (index->type == RMAP_PERMIT)
801 /* 'action' */
802 {
803 /* permit+match must execute sets */
804 for (set = index->set_list.head; set; set = set->next)
805 ret = (*set->cmd->func_apply) (set->value, prefix,
806 type, object);
paulfee0f4c2004-09-13 05:12:46 +0000807
808 /* Call another route-map if available */
809 if (index->nextrm)
810 {
811 struct route_map *nextrm =
812 route_map_lookup_by_name (index->nextrm);
813
814 if (nextrm) /* Target route-map found, jump to it */
815 {
816 recursion++;
817 ret = route_map_apply (nextrm, prefix, type, object);
818 recursion--;
819 }
820
821 /* If nextrm returned 'deny', finish. */
822 if (ret == RMAP_DENYMATCH)
823 return ret;
824 }
825
paul3bf1c912003-10-29 06:30:19 +0000826 switch (index->exitpolicy)
827 {
828 case RMAP_EXIT:
829 return ret;
830 case RMAP_NEXT:
831 continue;
832 case RMAP_GOTO:
833 {
834 /* Find the next clause to jump to */
835 struct route_map_index *next = index->next;
paulfee0f4c2004-09-13 05:12:46 +0000836 int nextpref = index->nextpref;
paul718e3742002-12-13 20:15:29 +0000837
paulfee0f4c2004-09-13 05:12:46 +0000838 while (next && next->pref < nextpref)
paul3bf1c912003-10-29 06:30:19 +0000839 {
840 index = next;
841 next = next->next;
842 }
843 if (next == NULL)
844 {
845 /* No clauses match! */
846 return ret;
847 }
848 }
849 }
850 }
851 else if (index->type == RMAP_DENY)
852 /* 'deny' */
853 {
paul3bf1c912003-10-29 06:30:19 +0000854 return RMAP_DENYMATCH;
855 }
856 }
paul718e3742002-12-13 20:15:29 +0000857 }
858 /* Finally route-map does not match at all. */
859 return RMAP_DENYMATCH;
860}
861
862void
paul9035efa2004-10-10 11:56:56 +0000863route_map_add_hook (void (*func) (const char *))
paul718e3742002-12-13 20:15:29 +0000864{
865 route_map_master.add_hook = func;
866}
867
868void
paul9035efa2004-10-10 11:56:56 +0000869route_map_delete_hook (void (*func) (const char *))
paul718e3742002-12-13 20:15:29 +0000870{
871 route_map_master.delete_hook = func;
872}
873
874void
paul9035efa2004-10-10 11:56:56 +0000875route_map_event_hook (void (*func) (route_map_event_t, const char *))
paul718e3742002-12-13 20:15:29 +0000876{
877 route_map_master.event_hook = func;
878}
879
880void
paul8cc41982005-05-06 21:25:49 +0000881route_map_init (void)
paul718e3742002-12-13 20:15:29 +0000882{
883 /* Make vector for match and set. */
884 route_match_vec = vector_init (1);
885 route_set_vec = vector_init (1);
886}
887
888/* VTY related functions. */
889DEFUN (route_map,
890 route_map_cmd,
891 "route-map WORD (deny|permit) <1-65535>",
892 "Create route-map or enter route-map command mode\n"
893 "Route map tag\n"
894 "Route map denies set operations\n"
895 "Route map permits set operations\n"
896 "Sequence to insert to/delete from existing route-map entry\n")
897{
898 int permit;
899 unsigned long pref;
900 struct route_map *map;
901 struct route_map_index *index;
902 char *endptr = NULL;
903
904 /* Permit check. */
905 if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
906 permit = RMAP_PERMIT;
907 else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
908 permit = RMAP_DENY;
909 else
910 {
911 vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
912 return CMD_WARNING;
913 }
914
915 /* Preference check. */
916 pref = strtoul (argv[2], &endptr, 10);
917 if (pref == ULONG_MAX || *endptr != '\0')
918 {
919 vty_out (vty, "the fourth field must be positive integer%s",
920 VTY_NEWLINE);
921 return CMD_WARNING;
922 }
923 if (pref == 0 || pref > 65535)
924 {
925 vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
926 return CMD_WARNING;
927 }
928
929 /* Get route map. */
930 map = route_map_get (argv[0]);
931 index = route_map_index_get (map, permit, pref);
932
933 vty->index = index;
934 vty->node = RMAP_NODE;
935 return CMD_SUCCESS;
936}
937
938DEFUN (no_route_map_all,
939 no_route_map_all_cmd,
940 "no route-map WORD",
941 NO_STR
942 "Create route-map or enter route-map command mode\n"
943 "Route map tag\n")
944{
945 struct route_map *map;
946
947 map = route_map_lookup_by_name (argv[0]);
948 if (map == NULL)
949 {
950 vty_out (vty, "%% Could not find route-map %s%s",
951 argv[0], VTY_NEWLINE);
952 return CMD_WARNING;
953 }
954
955 route_map_delete (map);
956
957 return CMD_SUCCESS;
958}
959
960DEFUN (no_route_map,
961 no_route_map_cmd,
962 "no route-map WORD (deny|permit) <1-65535>",
963 NO_STR
964 "Create route-map or enter route-map command mode\n"
965 "Route map tag\n"
966 "Route map denies set operations\n"
967 "Route map permits set operations\n"
968 "Sequence to insert to/delete from existing route-map entry\n")
969{
970 int permit;
971 unsigned long pref;
972 struct route_map *map;
973 struct route_map_index *index;
974 char *endptr = NULL;
975
976 /* Permit check. */
977 if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
978 permit = RMAP_PERMIT;
979 else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
980 permit = RMAP_DENY;
981 else
982 {
983 vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
984 return CMD_WARNING;
985 }
986
987 /* Preference. */
988 pref = strtoul (argv[2], &endptr, 10);
989 if (pref == ULONG_MAX || *endptr != '\0')
990 {
991 vty_out (vty, "the fourth field must be positive integer%s",
992 VTY_NEWLINE);
993 return CMD_WARNING;
994 }
995 if (pref == 0 || pref > 65535)
996 {
997 vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
998 return CMD_WARNING;
999 }
1000
1001 /* Existence check. */
1002 map = route_map_lookup_by_name (argv[0]);
1003 if (map == NULL)
1004 {
1005 vty_out (vty, "%% Could not find route-map %s%s",
1006 argv[0], VTY_NEWLINE);
1007 return CMD_WARNING;
1008 }
1009
1010 /* Lookup route map index. */
1011 index = route_map_index_lookup (map, permit, pref);
1012 if (index == NULL)
1013 {
1014 vty_out (vty, "%% Could not find route-map entry %s %s%s",
1015 argv[0], argv[2], VTY_NEWLINE);
1016 return CMD_WARNING;
1017 }
1018
1019 /* Delete index from route map. */
1020 route_map_index_delete (index, 1);
1021
1022 /* If this route rule is the last one, delete route map itself. */
1023 if (route_map_empty (map))
1024 route_map_delete (map);
1025
1026 return CMD_SUCCESS;
1027}
1028
1029DEFUN (rmap_onmatch_next,
1030 rmap_onmatch_next_cmd,
1031 "on-match next",
1032 "Exit policy on matches\n"
1033 "Next clause\n")
1034{
1035 struct route_map_index *index;
1036
1037 index = vty->index;
1038
1039 if (index)
1040 index->exitpolicy = RMAP_NEXT;
1041
1042 return CMD_SUCCESS;
1043}
1044
1045DEFUN (no_rmap_onmatch_next,
1046 no_rmap_onmatch_next_cmd,
1047 "no on-match next",
1048 NO_STR
1049 "Exit policy on matches\n"
1050 "Next clause\n")
1051{
1052 struct route_map_index *index;
1053
1054 index = vty->index;
1055
1056 if (index)
1057 index->exitpolicy = RMAP_EXIT;
1058
1059 return CMD_SUCCESS;
1060}
1061
1062DEFUN (rmap_onmatch_goto,
1063 rmap_onmatch_goto_cmd,
1064 "on-match goto <1-65535>",
1065 "Exit policy on matches\n"
1066 "Goto Clause number\n"
1067 "Number\n")
1068{
pauld4f09602005-05-23 12:43:34 +00001069 struct route_map_index *index = vty->index;
paul718e3742002-12-13 20:15:29 +00001070 int d = 0;
1071
paul718e3742002-12-13 20:15:29 +00001072 if (index)
1073 {
pauld4f09602005-05-23 12:43:34 +00001074 if (argc == 1 && argv[0])
1075 VTY_GET_INTEGER_RANGE("route-map index", d, argv[0], 1, 65536);
1076 else
1077 d = index->pref + 1;
1078
paul718e3742002-12-13 20:15:29 +00001079 if (d <= index->pref)
1080 {
1081 /* Can't allow you to do that, Dave */
1082 vty_out (vty, "can't jump backwards in route-maps%s",
1083 VTY_NEWLINE);
1084 return CMD_WARNING;
1085 }
1086 else
1087 {
1088 index->exitpolicy = RMAP_GOTO;
1089 index->nextpref = d;
1090 }
1091 }
1092 return CMD_SUCCESS;
1093}
1094
1095DEFUN (no_rmap_onmatch_goto,
1096 no_rmap_onmatch_goto_cmd,
1097 "no on-match goto",
1098 NO_STR
1099 "Exit policy on matches\n"
paulfee0f4c2004-09-13 05:12:46 +00001100 "Goto Clause number\n")
paul718e3742002-12-13 20:15:29 +00001101{
1102 struct route_map_index *index;
1103
1104 index = vty->index;
1105
1106 if (index)
1107 index->exitpolicy = RMAP_EXIT;
1108
1109 return CMD_SUCCESS;
1110}
1111
paul5510e832004-07-09 14:00:01 +00001112/* Cisco/GNU Zebra compatible ALIASes for on-match next */
1113ALIAS (rmap_onmatch_goto,
1114 rmap_continue_cmd,
1115 "continue",
1116 "Continue on a different entry within the route-map\n")
1117
1118ALIAS (no_rmap_onmatch_goto,
1119 no_rmap_continue_cmd,
1120 "no continue",
1121 NO_STR
1122 "Continue on a different entry within the route-map\n")
1123
1124/* GNU Zebra compatible */
1125ALIAS (rmap_onmatch_goto,
1126 rmap_continue_seq_cmd,
1127 "continue <1-65535>",
1128 "Continue on a different entry within the route-map\n"
1129 "Route-map entry sequence number\n")
1130
1131ALIAS (no_rmap_onmatch_goto,
1132 no_rmap_continue_seq,
1133 "no continue <1-65535>",
1134 NO_STR
1135 "Continue on a different entry within the route-map\n"
1136 "Route-map entry sequence number\n")
1137
1138DEFUN (rmap_show,
1139 rmap_show_cmd,
1140 "show route-map",
1141 SHOW_STR
1142 "route-map information\n")
1143{
1144 return vty_show_route_map (vty, NULL);
1145}
1146
1147DEFUN (rmap_show_name,
1148 rmap_show_name_cmd,
1149 "show route-map WORD",
1150 SHOW_STR
1151 "route-map information\n"
1152 "route-map name\n")
1153{
1154 return vty_show_route_map (vty, argv[0]);
1155}
1156
paulfee0f4c2004-09-13 05:12:46 +00001157ALIAS (rmap_onmatch_goto,
1158 rmap_continue_index_cmd,
1159 "continue <1-65536>",
1160 "Exit policy on matches\n"
1161 "Goto Clause number\n")
1162
1163DEFUN (rmap_call,
1164 rmap_call_cmd,
1165 "call WORD",
1166 "Jump to another Route-Map after match+set\n"
1167 "Target route-map name\n")
1168{
1169 struct route_map_index *index;
1170
1171 index = vty->index;
1172 if (index)
1173 {
1174 if (index->nextrm)
paul02416842005-10-26 05:05:16 +00001175 XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
1176 index->nextrm = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[0]);
paulfee0f4c2004-09-13 05:12:46 +00001177 }
1178 return CMD_SUCCESS;
1179}
1180
1181DEFUN (no_rmap_call,
1182 no_rmap_call_cmd,
1183 "no call",
1184 NO_STR
1185 "Jump to another Route-Map after match+set\n")
1186{
1187 struct route_map_index *index;
1188
1189 index = vty->index;
1190
1191 if (index->nextrm)
1192 {
paul02416842005-10-26 05:05:16 +00001193 XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
paulfee0f4c2004-09-13 05:12:46 +00001194 index->nextrm = NULL;
1195 }
1196
1197 return CMD_SUCCESS;
1198}
1199
hasso4a8164e2005-04-08 14:20:18 +00001200DEFUN (rmap_description,
1201 rmap_description_cmd,
1202 "description .LINE",
1203 "Route-map comment\n"
1204 "Comment describing this route-map rule\n")
1205{
1206 struct route_map_index *index;
1207
1208 index = vty->index;
1209 if (index)
1210 {
1211 if (index->description)
1212 XFREE (MTYPE_TMP, index->description);
1213 index->description = argv_concat (argv, argc, 0);
1214 }
1215 return CMD_SUCCESS;
1216}
1217
1218DEFUN (no_rmap_description,
1219 no_rmap_description_cmd,
1220 "no description",
1221 NO_STR
1222 "Route-map comment\n")
1223{
1224 struct route_map_index *index;
1225
1226 index = vty->index;
1227 if (index)
1228 {
1229 if (index->description)
1230 XFREE (MTYPE_TMP, index->description);
1231 index->description = NULL;
1232 }
1233 return CMD_SUCCESS;
1234}
1235
paul718e3742002-12-13 20:15:29 +00001236/* Configuration write function. */
paul8cc41982005-05-06 21:25:49 +00001237static int
paul718e3742002-12-13 20:15:29 +00001238route_map_config_write (struct vty *vty)
1239{
1240 struct route_map *map;
1241 struct route_map_index *index;
1242 struct route_map_rule *rule;
1243 int first = 1;
1244 int write = 0;
1245
1246 for (map = route_map_master.head; map; map = map->next)
1247 for (index = map->head; index; index = index->next)
1248 {
1249 if (!first)
1250 vty_out (vty, "!%s", VTY_NEWLINE);
1251 else
1252 first = 0;
1253
1254 vty_out (vty, "route-map %s %s %d%s",
1255 map->name,
1256 route_map_type_str (index->type),
1257 index->pref, VTY_NEWLINE);
1258
hasso4a8164e2005-04-08 14:20:18 +00001259 if (index->description)
1260 vty_out (vty, " description %s%s", index->description, VTY_NEWLINE);
1261
paul718e3742002-12-13 20:15:29 +00001262 for (rule = index->match_list.head; rule; rule = rule->next)
1263 vty_out (vty, " match %s %s%s", rule->cmd->str,
1264 rule->rule_str ? rule->rule_str : "",
1265 VTY_NEWLINE);
1266
1267 for (rule = index->set_list.head; rule; rule = rule->next)
1268 vty_out (vty, " set %s %s%s", rule->cmd->str,
1269 rule->rule_str ? rule->rule_str : "",
1270 VTY_NEWLINE);
paulfee0f4c2004-09-13 05:12:46 +00001271 if (index->nextrm)
1272 vty_out (vty, " call %s%s", index->nextrm, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00001273 if (index->exitpolicy == RMAP_GOTO)
paulfee0f4c2004-09-13 05:12:46 +00001274 vty_out (vty, " on-match goto %d%s", index->nextpref, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00001275 if (index->exitpolicy == RMAP_NEXT)
1276 vty_out (vty," on-match next%s", VTY_NEWLINE);
1277
1278 write++;
1279 }
1280 return write;
1281}
1282
1283/* Route map node structure. */
1284struct cmd_node rmap_node =
1285{
1286 RMAP_NODE,
1287 "%s(config-route-map)# ",
1288 1
1289};
1290
1291/* Initialization of route map vector. */
1292void
paul8cc41982005-05-06 21:25:49 +00001293route_map_init_vty (void)
paul718e3742002-12-13 20:15:29 +00001294{
1295 /* Install route map top node. */
1296 install_node (&rmap_node, route_map_config_write);
1297
1298 /* Install route map commands. */
1299 install_default (RMAP_NODE);
1300 install_element (CONFIG_NODE, &route_map_cmd);
1301 install_element (CONFIG_NODE, &no_route_map_cmd);
1302 install_element (CONFIG_NODE, &no_route_map_all_cmd);
1303
1304 /* Install the on-match stuff */
1305 install_element (RMAP_NODE, &route_map_cmd);
1306 install_element (RMAP_NODE, &rmap_onmatch_next_cmd);
1307 install_element (RMAP_NODE, &no_rmap_onmatch_next_cmd);
1308 install_element (RMAP_NODE, &rmap_onmatch_goto_cmd);
1309 install_element (RMAP_NODE, &no_rmap_onmatch_goto_cmd);
paulfee0f4c2004-09-13 05:12:46 +00001310
1311 /* Install the continue stuff (ALIAS of on-match). */
1312 install_element (RMAP_NODE, &rmap_continue_cmd);
1313 install_element (RMAP_NODE, &no_rmap_continue_cmd);
1314 install_element (RMAP_NODE, &rmap_continue_index_cmd);
1315
1316 /* Install the call stuff. */
1317 install_element (RMAP_NODE, &rmap_call_cmd);
1318 install_element (RMAP_NODE, &no_rmap_call_cmd);
hasso4a8164e2005-04-08 14:20:18 +00001319
1320 /* Install description commands. */
1321 install_element (RMAP_NODE, &rmap_description_cmd);
1322 install_element (RMAP_NODE, &no_rmap_description_cmd);
paulfee0f4c2004-09-13 05:12:46 +00001323
paul5510e832004-07-09 14:00:01 +00001324 /* Install show command */
1325 install_element (ENABLE_NODE, &rmap_show_cmd);
1326 install_element (ENABLE_NODE, &rmap_show_name_cmd);
paul718e3742002-12-13 20:15:29 +00001327}