Line data Source code
1 : /* Route map function.
2 : Copyright (C) 1998, 1999 Kunihiro Ishiguro
3 :
4 : This file is part of GNU Zebra.
5 :
6 : GNU Zebra is free software; you can redistribute it and/or modify it
7 : under the terms of the GNU General Public License as published by the
8 : Free Software Foundation; either version 2, or (at your option) any
9 : later version.
10 :
11 : GNU Zebra is distributed in the hope that it will be useful, but
12 : WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with GNU Zebra; see the file COPYING. If not, write to the Free
18 : Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 : 02111-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 : #include "vty.h"
30 : #include "log.h"
31 :
32 : /* Vector for route match rules. */
33 : static vector route_match_vec;
34 :
35 : /* Vector for route set rules. */
36 : static vector route_set_vec;
37 :
38 : /* Route map rule. This rule has both `match' rule and `set' rule. */
39 : struct 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. */
56 : struct route_map_list
57 : {
58 : struct route_map *head;
59 : struct route_map *tail;
60 :
61 : void (*add_hook) (const char *);
62 : void (*delete_hook) (const char *);
63 : void (*event_hook) (route_map_event_t, const char *);
64 : };
65 :
66 : /* Master list of route map. */
67 : static struct route_map_list route_map_master = { NULL, NULL, NULL, NULL };
68 :
69 : static void
70 : route_map_rule_delete (struct route_map_rule_list *,
71 : struct route_map_rule *);
72 :
73 : static void
74 : route_map_index_delete (struct route_map_index *, int);
75 :
76 : /* New route map allocation. Please note route map's name must be
77 : specified. */
78 : static struct route_map *
79 13 : route_map_new (const char *name)
80 : {
81 : struct route_map *new;
82 :
83 13 : new = XCALLOC (MTYPE_ROUTE_MAP, sizeof (struct route_map));
84 13 : new->name = XSTRDUP (MTYPE_ROUTE_MAP_NAME, name);
85 13 : return new;
86 : }
87 :
88 : /* Add new name to route_map. */
89 : static struct route_map *
90 13 : route_map_add (const char *name)
91 : {
92 : struct route_map *map;
93 : struct route_map_list *list;
94 :
95 13 : map = route_map_new (name);
96 13 : list = &route_map_master;
97 :
98 13 : map->next = NULL;
99 13 : map->prev = list->tail;
100 13 : if (list->tail)
101 0 : list->tail->next = map;
102 : else
103 13 : list->head = map;
104 13 : list->tail = map;
105 :
106 : /* Execute hook. */
107 13 : if (route_map_master.add_hook)
108 0 : (*route_map_master.add_hook) (name);
109 :
110 13 : return map;
111 : }
112 :
113 : /* Route map delete from list. */
114 : static void
115 0 : route_map_delete (struct route_map *map)
116 : {
117 : struct route_map_list *list;
118 : struct route_map_index *index;
119 : char *name;
120 :
121 0 : while ((index = map->head) != NULL)
122 0 : route_map_index_delete (index, 0);
123 :
124 0 : name = map->name;
125 :
126 0 : list = &route_map_master;
127 :
128 0 : if (map->next)
129 0 : map->next->prev = map->prev;
130 : else
131 0 : list->tail = map->prev;
132 :
133 0 : if (map->prev)
134 0 : map->prev->next = map->next;
135 : else
136 0 : list->head = map->next;
137 :
138 0 : XFREE (MTYPE_ROUTE_MAP, map);
139 :
140 : /* Execute deletion hook. */
141 0 : if (route_map_master.delete_hook)
142 0 : (*route_map_master.delete_hook) (name);
143 :
144 0 : if (name)
145 0 : XFREE (MTYPE_ROUTE_MAP_NAME, name);
146 :
147 0 : }
148 :
149 : /* Lookup route map by route map name string. */
150 : struct route_map *
151 81 : route_map_lookup_by_name (const char *name)
152 : {
153 : struct route_map *map;
154 :
155 81 : for (map = route_map_master.head; map; map = map->next)
156 68 : if (strcmp (map->name, name) == 0)
157 68 : return map;
158 13 : return NULL;
159 : }
160 :
161 : /* Lookup route map. If there isn't route map create one and return
162 : it. */
163 : static struct route_map *
164 20 : route_map_get (const char *name)
165 : {
166 : struct route_map *map;
167 :
168 20 : map = route_map_lookup_by_name (name);
169 20 : if (map == NULL)
170 13 : map = route_map_add (name);
171 20 : return map;
172 : }
173 :
174 : /* Return route map's type string. */
175 : static const char *
176 0 : route_map_type_str (enum route_map_type type)
177 : {
178 0 : switch (type)
179 : {
180 : case RMAP_PERMIT:
181 0 : return "permit";
182 : break;
183 : case RMAP_DENY:
184 0 : return "deny";
185 : break;
186 : default:
187 0 : return "";
188 : break;
189 : }
190 : }
191 :
192 : static int
193 0 : route_map_empty (struct route_map *map)
194 : {
195 0 : if (map->head == NULL && map->tail == NULL)
196 0 : return 1;
197 : else
198 0 : return 0;
199 : }
200 :
201 : /* show route-map */
202 : static void
203 0 : vty_show_route_map_entry (struct vty *vty, struct route_map *map)
204 : {
205 : struct route_map_index *index;
206 : struct route_map_rule *rule;
207 :
208 : /* Print the name of the protocol */
209 0 : if (zlog_default)
210 0 : vty_out (vty, "%s:%s", zlog_proto_names[zlog_default->protocol],
211 0 : VTY_NEWLINE);
212 :
213 0 : for (index = map->head; index; index = index->next)
214 : {
215 0 : vty_out (vty, "route-map %s, %s, sequence %d%s",
216 : map->name, route_map_type_str (index->type),
217 0 : index->pref, VTY_NEWLINE);
218 :
219 : /* Description */
220 0 : if (index->description)
221 0 : vty_out (vty, " Description:%s %s%s", VTY_NEWLINE,
222 0 : index->description, VTY_NEWLINE);
223 :
224 : /* Match clauses */
225 0 : vty_out (vty, " Match clauses:%s", VTY_NEWLINE);
226 0 : for (rule = index->match_list.head; rule; rule = rule->next)
227 0 : vty_out (vty, " %s %s%s",
228 0 : rule->cmd->str, rule->rule_str, VTY_NEWLINE);
229 :
230 0 : vty_out (vty, " Set clauses:%s", VTY_NEWLINE);
231 0 : for (rule = index->set_list.head; rule; rule = rule->next)
232 0 : vty_out (vty, " %s %s%s",
233 0 : rule->cmd->str, rule->rule_str, VTY_NEWLINE);
234 :
235 : /* Call clause */
236 0 : vty_out (vty, " Call clause:%s", VTY_NEWLINE);
237 0 : if (index->nextrm)
238 0 : vty_out (vty, " Call %s%s", index->nextrm, VTY_NEWLINE);
239 :
240 : /* Exit Policy */
241 0 : vty_out (vty, " Action:%s", VTY_NEWLINE);
242 0 : if (index->exitpolicy == RMAP_GOTO)
243 0 : vty_out (vty, " Goto %d%s", index->nextpref, VTY_NEWLINE);
244 0 : else if (index->exitpolicy == RMAP_NEXT)
245 0 : vty_out (vty, " Continue to next entry%s", VTY_NEWLINE);
246 0 : else if (index->exitpolicy == RMAP_EXIT)
247 0 : vty_out (vty, " Exit routemap%s", VTY_NEWLINE);
248 : }
249 0 : }
250 :
251 : static int
252 0 : vty_show_route_map (struct vty *vty, const char *name)
253 : {
254 : struct route_map *map;
255 :
256 0 : if (name)
257 : {
258 0 : map = route_map_lookup_by_name (name);
259 :
260 0 : if (map)
261 : {
262 0 : vty_show_route_map_entry (vty, map);
263 0 : return CMD_SUCCESS;
264 : }
265 : else
266 : {
267 0 : vty_out (vty, "%%route-map %s not found%s", name, VTY_NEWLINE);
268 0 : return CMD_WARNING;
269 : }
270 : }
271 : else
272 : {
273 0 : for (map = route_map_master.head; map; map = map->next)
274 0 : vty_show_route_map_entry (vty, map);
275 : }
276 0 : return CMD_SUCCESS;
277 : }
278 :
279 :
280 : /* New route map allocation. Please note route map's name must be
281 : specified. */
282 : static struct route_map_index *
283 20 : route_map_index_new (void)
284 : {
285 : struct route_map_index *new;
286 :
287 20 : new = XCALLOC (MTYPE_ROUTE_MAP_INDEX, sizeof (struct route_map_index));
288 20 : new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */
289 20 : return new;
290 : }
291 :
292 : /* Free route map index. */
293 : static void
294 0 : route_map_index_delete (struct route_map_index *index, int notify)
295 : {
296 : struct route_map_rule *rule;
297 :
298 : /* Free route match. */
299 0 : while ((rule = index->match_list.head) != NULL)
300 0 : route_map_rule_delete (&index->match_list, rule);
301 :
302 : /* Free route set. */
303 0 : while ((rule = index->set_list.head) != NULL)
304 0 : route_map_rule_delete (&index->set_list, rule);
305 :
306 : /* Remove index from route map list. */
307 0 : if (index->next)
308 0 : index->next->prev = index->prev;
309 : else
310 0 : index->map->tail = index->prev;
311 :
312 0 : if (index->prev)
313 0 : index->prev->next = index->next;
314 : else
315 0 : index->map->head = index->next;
316 :
317 : /* Free 'char *nextrm' if not NULL */
318 0 : if (index->nextrm)
319 0 : XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
320 :
321 : /* Execute event hook. */
322 0 : if (route_map_master.event_hook && notify)
323 0 : (*route_map_master.event_hook) (RMAP_EVENT_INDEX_DELETED,
324 0 : index->map->name);
325 :
326 0 : XFREE (MTYPE_ROUTE_MAP_INDEX, index);
327 0 : }
328 :
329 : /* Lookup index from route map. */
330 : static struct route_map_index *
331 20 : route_map_index_lookup (struct route_map *map, enum route_map_type type,
332 : int pref)
333 : {
334 : struct route_map_index *index;
335 :
336 27 : for (index = map->head; index; index = index->next)
337 7 : if ((index->type == type || type == RMAP_ANY)
338 7 : && index->pref == pref)
339 0 : return index;
340 20 : return NULL;
341 : }
342 :
343 : /* Add new index to route map. */
344 : static struct route_map_index *
345 20 : route_map_index_add (struct route_map *map, enum route_map_type type,
346 : int pref)
347 : {
348 : struct route_map_index *index;
349 : struct route_map_index *point;
350 :
351 : /* Allocate new route map inex. */
352 20 : index = route_map_index_new ();
353 20 : index->map = map;
354 20 : index->type = type;
355 20 : index->pref = pref;
356 :
357 : /* Compare preference. */
358 27 : for (point = map->head; point; point = point->next)
359 7 : if (point->pref >= pref)
360 0 : break;
361 :
362 20 : if (map->head == NULL)
363 : {
364 13 : map->head = map->tail = index;
365 : }
366 7 : else if (point == NULL)
367 : {
368 7 : index->prev = map->tail;
369 7 : map->tail->next = index;
370 7 : map->tail = index;
371 : }
372 0 : else if (point == map->head)
373 : {
374 0 : index->next = map->head;
375 0 : map->head->prev = index;
376 0 : map->head = index;
377 : }
378 : else
379 : {
380 0 : index->next = point;
381 0 : index->prev = point->prev;
382 0 : if (point->prev)
383 0 : point->prev->next = index;
384 0 : point->prev = index;
385 : }
386 :
387 : /* Execute event hook. */
388 20 : if (route_map_master.event_hook)
389 0 : (*route_map_master.event_hook) (RMAP_EVENT_INDEX_ADDED,
390 0 : map->name);
391 :
392 20 : return index;
393 : }
394 :
395 : /* Get route map index. */
396 : static struct route_map_index *
397 20 : route_map_index_get (struct route_map *map, enum route_map_type type,
398 : int pref)
399 : {
400 : struct route_map_index *index;
401 :
402 20 : index = route_map_index_lookup (map, RMAP_ANY, pref);
403 20 : if (index && index->type != type)
404 : {
405 : /* Delete index from route map. */
406 0 : route_map_index_delete (index, 1);
407 0 : index = NULL;
408 : }
409 20 : if (index == NULL)
410 20 : index = route_map_index_add (map, type, pref);
411 20 : return index;
412 : }
413 :
414 : /* New route map rule */
415 : static struct route_map_rule *
416 13 : route_map_rule_new (void)
417 : {
418 : struct route_map_rule *new;
419 :
420 13 : new = XCALLOC (MTYPE_ROUTE_MAP_RULE, sizeof (struct route_map_rule));
421 13 : return new;
422 : }
423 :
424 : /* Install rule command to the match list. */
425 : void
426 225 : route_map_install_match (struct route_map_rule_cmd *cmd)
427 : {
428 225 : vector_set (route_match_vec, cmd);
429 225 : }
430 :
431 : /* Install rule command to the set list. */
432 : void
433 45 : route_map_install_set (struct route_map_rule_cmd *cmd)
434 : {
435 45 : vector_set (route_set_vec, cmd);
436 45 : }
437 :
438 : /* Lookup rule command from match list. */
439 : static struct route_map_rule_cmd *
440 7 : route_map_lookup_match (const char *name)
441 : {
442 : unsigned int i;
443 : struct route_map_rule_cmd *rule;
444 :
445 15 : for (i = 0; i < vector_active (route_match_vec); i++)
446 15 : if ((rule = vector_slot (route_match_vec, i)) != NULL)
447 15 : if (strcmp (rule->str, name) == 0)
448 7 : return rule;
449 0 : return NULL;
450 : }
451 :
452 : /* Lookup rule command from set list. */
453 : static struct route_map_rule_cmd *
454 6 : route_map_lookup_set (const char *name)
455 : {
456 : unsigned int i;
457 : struct route_map_rule_cmd *rule;
458 :
459 6 : for (i = 0; i < vector_active (route_set_vec); i++)
460 6 : if ((rule = vector_slot (route_set_vec, i)) != NULL)
461 6 : if (strcmp (rule->str, name) == 0)
462 6 : return rule;
463 0 : return NULL;
464 : }
465 :
466 : /* Add match and set rule to rule list. */
467 : static void
468 13 : route_map_rule_add (struct route_map_rule_list *list,
469 : struct route_map_rule *rule)
470 : {
471 13 : rule->next = NULL;
472 13 : rule->prev = list->tail;
473 13 : if (list->tail)
474 0 : list->tail->next = rule;
475 : else
476 13 : list->head = rule;
477 13 : list->tail = rule;
478 13 : }
479 :
480 : /* Delete rule from rule list. */
481 : static void
482 0 : route_map_rule_delete (struct route_map_rule_list *list,
483 : struct route_map_rule *rule)
484 : {
485 0 : if (rule->cmd->func_free)
486 0 : (*rule->cmd->func_free) (rule->value);
487 :
488 0 : if (rule->rule_str)
489 0 : XFREE (MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str);
490 :
491 0 : if (rule->next)
492 0 : rule->next->prev = rule->prev;
493 : else
494 0 : list->tail = rule->prev;
495 0 : if (rule->prev)
496 0 : rule->prev->next = rule->next;
497 : else
498 0 : list->head = rule->next;
499 :
500 0 : XFREE (MTYPE_ROUTE_MAP_RULE, rule);
501 0 : }
502 :
503 : /* strcmp wrapper function which don't crush even argument is NULL. */
504 : static int
505 0 : rulecmp (const char *dst, const char *src)
506 : {
507 0 : if (dst == NULL)
508 : {
509 0 : if (src == NULL)
510 0 : return 0;
511 : else
512 0 : return 1;
513 : }
514 : else
515 : {
516 0 : if (src == NULL)
517 0 : return 1;
518 : else
519 0 : return strcmp (dst, src);
520 : }
521 : return 1;
522 : }
523 :
524 : /* Add match statement to route map. */
525 : int
526 7 : route_map_add_match (struct route_map_index *index, const char *match_name,
527 : const char *match_arg)
528 : {
529 : struct route_map_rule *rule;
530 : struct route_map_rule *next;
531 : struct route_map_rule_cmd *cmd;
532 : void *compile;
533 7 : int replaced = 0;
534 :
535 : /* First lookup rule for add match statement. */
536 7 : cmd = route_map_lookup_match (match_name);
537 7 : if (cmd == NULL)
538 0 : return RMAP_RULE_MISSING;
539 :
540 : /* Next call compile function for this match statement. */
541 7 : if (cmd->func_compile)
542 : {
543 7 : compile= (*cmd->func_compile)(match_arg);
544 7 : if (compile == NULL)
545 0 : return RMAP_COMPILE_ERROR;
546 : }
547 : else
548 0 : compile = NULL;
549 :
550 : /* If argument is completely same ignore it. */
551 7 : for (rule = index->match_list.head; rule; rule = next)
552 : {
553 0 : next = rule->next;
554 0 : if (rule->cmd == cmd)
555 : {
556 0 : route_map_rule_delete (&index->match_list, rule);
557 0 : replaced = 1;
558 : }
559 : }
560 :
561 : /* Add new route map match rule. */
562 7 : rule = route_map_rule_new ();
563 7 : rule->cmd = cmd;
564 7 : rule->value = compile;
565 7 : if (match_arg)
566 7 : rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, match_arg);
567 : else
568 0 : rule->rule_str = NULL;
569 :
570 : /* Add new route match rule to linked list. */
571 7 : route_map_rule_add (&index->match_list, rule);
572 :
573 : /* Execute event hook. */
574 7 : if (route_map_master.event_hook)
575 0 : (*route_map_master.event_hook) (replaced ?
576 : RMAP_EVENT_MATCH_REPLACED:
577 : RMAP_EVENT_MATCH_ADDED,
578 0 : index->map->name);
579 :
580 7 : return 0;
581 : }
582 :
583 : /* Delete specified route match rule. */
584 : int
585 0 : route_map_delete_match (struct route_map_index *index, const char *match_name,
586 : const char *match_arg)
587 : {
588 : struct route_map_rule *rule;
589 : struct route_map_rule_cmd *cmd;
590 :
591 0 : cmd = route_map_lookup_match (match_name);
592 0 : if (cmd == NULL)
593 0 : return 1;
594 :
595 0 : for (rule = index->match_list.head; rule; rule = rule->next)
596 0 : if (rule->cmd == cmd &&
597 0 : (rulecmp (rule->rule_str, match_arg) == 0 || match_arg == NULL))
598 : {
599 0 : route_map_rule_delete (&index->match_list, rule);
600 : /* Execute event hook. */
601 0 : if (route_map_master.event_hook)
602 0 : (*route_map_master.event_hook) (RMAP_EVENT_MATCH_DELETED,
603 0 : index->map->name);
604 0 : return 0;
605 : }
606 : /* Can't find matched rule. */
607 0 : return 1;
608 : }
609 :
610 : /* Add route-map set statement to the route map. */
611 : int
612 6 : route_map_add_set (struct route_map_index *index, const char *set_name,
613 : const char *set_arg)
614 : {
615 : struct route_map_rule *rule;
616 : struct route_map_rule *next;
617 : struct route_map_rule_cmd *cmd;
618 : void *compile;
619 6 : int replaced = 0;
620 :
621 6 : cmd = route_map_lookup_set (set_name);
622 6 : if (cmd == NULL)
623 0 : return RMAP_RULE_MISSING;
624 :
625 : /* Next call compile function for this match statement. */
626 6 : if (cmd->func_compile)
627 : {
628 6 : compile= (*cmd->func_compile)(set_arg);
629 6 : if (compile == NULL)
630 0 : return RMAP_COMPILE_ERROR;
631 : }
632 : else
633 0 : compile = NULL;
634 :
635 : /* Add by WJL. if old set command of same kind exist, delete it first
636 : to ensure only one set command of same kind exist under a
637 : route_map_index. */
638 6 : for (rule = index->set_list.head; rule; rule = next)
639 : {
640 0 : next = rule->next;
641 0 : if (rule->cmd == cmd)
642 : {
643 0 : route_map_rule_delete (&index->set_list, rule);
644 0 : replaced = 1;
645 : }
646 : }
647 :
648 : /* Add new route map match rule. */
649 6 : rule = route_map_rule_new ();
650 6 : rule->cmd = cmd;
651 6 : rule->value = compile;
652 6 : if (set_arg)
653 6 : rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, set_arg);
654 : else
655 0 : rule->rule_str = NULL;
656 :
657 : /* Add new route match rule to linked list. */
658 6 : route_map_rule_add (&index->set_list, rule);
659 :
660 : /* Execute event hook. */
661 6 : if (route_map_master.event_hook)
662 0 : (*route_map_master.event_hook) (replaced ?
663 : RMAP_EVENT_SET_REPLACED:
664 : RMAP_EVENT_SET_ADDED,
665 0 : index->map->name);
666 6 : return 0;
667 : }
668 :
669 : /* Delete route map set rule. */
670 : int
671 0 : route_map_delete_set (struct route_map_index *index, const char *set_name,
672 : const char *set_arg)
673 : {
674 : struct route_map_rule *rule;
675 : struct route_map_rule_cmd *cmd;
676 :
677 0 : cmd = route_map_lookup_set (set_name);
678 0 : if (cmd == NULL)
679 0 : return 1;
680 :
681 0 : for (rule = index->set_list.head; rule; rule = rule->next)
682 0 : if ((rule->cmd == cmd) &&
683 0 : (rulecmp (rule->rule_str, set_arg) == 0 || set_arg == NULL))
684 : {
685 0 : route_map_rule_delete (&index->set_list, rule);
686 : /* Execute event hook. */
687 0 : if (route_map_master.event_hook)
688 0 : (*route_map_master.event_hook) (RMAP_EVENT_SET_DELETED,
689 0 : index->map->name);
690 0 : return 0;
691 : }
692 : /* Can't find matched rule. */
693 0 : return 1;
694 : }
695 :
696 : /* Apply route map's each index to the object.
697 :
698 : The matrix for a route-map looks like this:
699 : (note, this includes the description for the "NEXT"
700 : and "GOTO" frobs now
701 :
702 : Match | No Match
703 : |
704 : permit action | cont
705 : |
706 : ------------------+---------------
707 : |
708 : deny deny | cont
709 : |
710 :
711 : action)
712 : -Apply Set statements, accept route
713 : -If Call statement is present jump to the specified route-map, if it
714 : denies the route we finish.
715 : -If NEXT is specified, goto NEXT statement
716 : -If GOTO is specified, goto the first clause where pref > nextpref
717 : -If nothing is specified, do as Cisco and finish
718 : deny)
719 : -Route is denied by route-map.
720 : cont)
721 : -Goto Next index
722 :
723 : If we get no matches after we've processed all updates, then the route
724 : is dropped too.
725 :
726 : Some notes on the new "CALL", "NEXT" and "GOTO"
727 : call WORD - If this clause is matched, then the set statements
728 : are executed and then we jump to route-map 'WORD'. If
729 : this route-map denies the route, we finish, in other case we
730 : do whatever the exit policy (EXIT, NEXT or GOTO) tells.
731 : on-match next - If this clause is matched, then the set statements
732 : are executed and then we drop through to the next clause
733 : on-match goto n - If this clause is matched, then the set statments
734 : are executed and then we goto the nth clause, or the
735 : first clause greater than this. In order to ensure
736 : route-maps *always* exit, you cannot jump backwards.
737 : Sorry ;)
738 :
739 : We need to make sure our route-map processing matches the above
740 : */
741 :
742 : static route_map_result_t
743 74 : route_map_apply_match (struct route_map_rule_list *match_list,
744 : struct prefix *prefix, route_map_object_t type,
745 : void *object)
746 : {
747 74 : route_map_result_t ret = RMAP_NOMATCH;
748 : struct route_map_rule *match;
749 :
750 :
751 : /* Check all match rule and if there is no match rule, go to the
752 : set statement. */
753 74 : if (!match_list->head)
754 40 : ret = RMAP_MATCH;
755 : else
756 : {
757 55 : for (match = match_list->head; match; match = match->next)
758 : {
759 : /* Try each match statement in turn, If any do not return
760 : RMAP_MATCH, return, otherwise continue on to next match
761 : statement. All match statements must match for end-result
762 : to be a match. */
763 34 : ret = (*match->cmd->func_apply) (match->value, prefix,
764 : type, object);
765 34 : if (ret != RMAP_MATCH)
766 13 : return ret;
767 : }
768 : }
769 61 : return ret;
770 : }
771 :
772 : /* Apply route map to the object. */
773 : route_map_result_t
774 61 : route_map_apply (struct route_map *map, struct prefix *prefix,
775 : route_map_object_t type, void *object)
776 : {
777 : static int recursion = 0;
778 61 : int ret = 0;
779 : struct route_map_index *index;
780 : struct route_map_rule *set;
781 :
782 61 : if (recursion > RMAP_RECURSION_LIMIT)
783 : {
784 0 : zlog (NULL, LOG_WARNING,
785 : "route-map recursion limit (%d) reached, discarding route",
786 : RMAP_RECURSION_LIMIT);
787 0 : recursion = 0;
788 0 : return RMAP_DENYMATCH;
789 : }
790 :
791 61 : if (map == NULL)
792 0 : return RMAP_DENYMATCH;
793 :
794 74 : for (index = map->head; index; index = index->next)
795 : {
796 : /* Apply this index. */
797 74 : ret = route_map_apply_match (&index->match_list, prefix, type, object);
798 :
799 : /* Now we apply the matrix from above */
800 74 : if (ret == RMAP_NOMATCH)
801 : /* 'cont' from matrix - continue to next route-map sequence */
802 13 : continue;
803 61 : else if (ret == RMAP_MATCH)
804 : {
805 61 : if (index->type == RMAP_PERMIT)
806 : /* 'action' */
807 : {
808 : /* permit+match must execute sets */
809 75 : for (set = index->set_list.head; set; set = set->next)
810 27 : ret = (*set->cmd->func_apply) (set->value, prefix,
811 : type, object);
812 :
813 : /* Call another route-map if available */
814 48 : if (index->nextrm)
815 : {
816 0 : struct route_map *nextrm =
817 0 : route_map_lookup_by_name (index->nextrm);
818 :
819 0 : if (nextrm) /* Target route-map found, jump to it */
820 : {
821 0 : recursion++;
822 0 : ret = route_map_apply (nextrm, prefix, type, object);
823 0 : recursion--;
824 : }
825 :
826 : /* If nextrm returned 'deny', finish. */
827 0 : if (ret == RMAP_DENYMATCH)
828 0 : return ret;
829 : }
830 :
831 48 : switch (index->exitpolicy)
832 : {
833 : case RMAP_EXIT:
834 48 : return ret;
835 : case RMAP_NEXT:
836 0 : continue;
837 : case RMAP_GOTO:
838 : {
839 : /* Find the next clause to jump to */
840 0 : struct route_map_index *next = index->next;
841 0 : int nextpref = index->nextpref;
842 :
843 0 : while (next && next->pref < nextpref)
844 : {
845 0 : index = next;
846 0 : next = next->next;
847 : }
848 0 : if (next == NULL)
849 : {
850 : /* No clauses match! */
851 0 : return ret;
852 : }
853 : }
854 : }
855 : }
856 13 : else if (index->type == RMAP_DENY)
857 : /* 'deny' */
858 : {
859 13 : return RMAP_DENYMATCH;
860 : }
861 : }
862 : }
863 : /* Finally route-map does not match at all. */
864 0 : return RMAP_DENYMATCH;
865 : }
866 :
867 : void
868 0 : route_map_add_hook (void (*func) (const char *))
869 : {
870 0 : route_map_master.add_hook = func;
871 0 : }
872 :
873 : void
874 0 : route_map_delete_hook (void (*func) (const char *))
875 : {
876 0 : route_map_master.delete_hook = func;
877 0 : }
878 :
879 : void
880 0 : route_map_event_hook (void (*func) (route_map_event_t, const char *))
881 : {
882 0 : route_map_master.event_hook = func;
883 0 : }
884 :
885 : void
886 45 : route_map_init (void)
887 : {
888 : /* Make vector for match and set. */
889 45 : route_match_vec = vector_init (1);
890 45 : route_set_vec = vector_init (1);
891 45 : }
892 :
893 : void
894 0 : route_map_finish (void)
895 : {
896 0 : vector_free (route_match_vec);
897 0 : route_match_vec = NULL;
898 0 : vector_free (route_set_vec);
899 0 : route_set_vec = NULL;
900 0 : }
901 :
902 : /* VTY related functions. */
903 20 : DEFUN (route_map,
904 : route_map_cmd,
905 : "route-map WORD (deny|permit) <1-65535>",
906 : "Create route-map or enter route-map command mode\n"
907 : "Route map tag\n"
908 : "Route map denies set operations\n"
909 : "Route map permits set operations\n"
910 : "Sequence to insert to/delete from existing route-map entry\n")
911 : {
912 : int permit;
913 : unsigned long pref;
914 : struct route_map *map;
915 : struct route_map_index *index;
916 20 : char *endptr = NULL;
917 :
918 : /* Permit check. */
919 20 : if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
920 13 : permit = RMAP_PERMIT;
921 7 : else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
922 7 : permit = RMAP_DENY;
923 : else
924 : {
925 0 : vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
926 0 : return CMD_WARNING;
927 : }
928 :
929 : /* Preference check. */
930 20 : pref = strtoul (argv[2], &endptr, 10);
931 20 : if (pref == ULONG_MAX || *endptr != '\0')
932 : {
933 0 : vty_out (vty, "the fourth field must be positive integer%s",
934 0 : VTY_NEWLINE);
935 0 : return CMD_WARNING;
936 : }
937 20 : if (pref == 0 || pref > 65535)
938 : {
939 0 : vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
940 0 : return CMD_WARNING;
941 : }
942 :
943 : /* Get route map. */
944 20 : map = route_map_get (argv[0]);
945 20 : index = route_map_index_get (map, permit, pref);
946 :
947 20 : vty->index = index;
948 20 : vty->node = RMAP_NODE;
949 20 : return CMD_SUCCESS;
950 : }
951 :
952 0 : DEFUN (no_route_map_all,
953 : no_route_map_all_cmd,
954 : "no route-map WORD",
955 : NO_STR
956 : "Create route-map or enter route-map command mode\n"
957 : "Route map tag\n")
958 : {
959 : struct route_map *map;
960 :
961 0 : map = route_map_lookup_by_name (argv[0]);
962 0 : if (map == NULL)
963 : {
964 0 : vty_out (vty, "%% Could not find route-map %s%s",
965 0 : argv[0], VTY_NEWLINE);
966 0 : return CMD_WARNING;
967 : }
968 :
969 0 : route_map_delete (map);
970 :
971 0 : return CMD_SUCCESS;
972 : }
973 :
974 0 : DEFUN (no_route_map,
975 : no_route_map_cmd,
976 : "no route-map WORD (deny|permit) <1-65535>",
977 : NO_STR
978 : "Create route-map or enter route-map command mode\n"
979 : "Route map tag\n"
980 : "Route map denies set operations\n"
981 : "Route map permits set operations\n"
982 : "Sequence to insert to/delete from existing route-map entry\n")
983 : {
984 : int permit;
985 : unsigned long pref;
986 : struct route_map *map;
987 : struct route_map_index *index;
988 0 : char *endptr = NULL;
989 :
990 : /* Permit check. */
991 0 : if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
992 0 : permit = RMAP_PERMIT;
993 0 : else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
994 0 : permit = RMAP_DENY;
995 : else
996 : {
997 0 : vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
998 0 : return CMD_WARNING;
999 : }
1000 :
1001 : /* Preference. */
1002 0 : pref = strtoul (argv[2], &endptr, 10);
1003 0 : if (pref == ULONG_MAX || *endptr != '\0')
1004 : {
1005 0 : vty_out (vty, "the fourth field must be positive integer%s",
1006 0 : VTY_NEWLINE);
1007 0 : return CMD_WARNING;
1008 : }
1009 0 : if (pref == 0 || pref > 65535)
1010 : {
1011 0 : vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
1012 0 : return CMD_WARNING;
1013 : }
1014 :
1015 : /* Existence check. */
1016 0 : map = route_map_lookup_by_name (argv[0]);
1017 0 : if (map == NULL)
1018 : {
1019 0 : vty_out (vty, "%% Could not find route-map %s%s",
1020 0 : argv[0], VTY_NEWLINE);
1021 0 : return CMD_WARNING;
1022 : }
1023 :
1024 : /* Lookup route map index. */
1025 0 : index = route_map_index_lookup (map, permit, pref);
1026 0 : if (index == NULL)
1027 : {
1028 0 : vty_out (vty, "%% Could not find route-map entry %s %s%s",
1029 0 : argv[0], argv[2], VTY_NEWLINE);
1030 0 : return CMD_WARNING;
1031 : }
1032 :
1033 : /* Delete index from route map. */
1034 0 : route_map_index_delete (index, 1);
1035 :
1036 : /* If this route rule is the last one, delete route map itself. */
1037 0 : if (route_map_empty (map))
1038 0 : route_map_delete (map);
1039 :
1040 0 : return CMD_SUCCESS;
1041 : }
1042 :
1043 0 : DEFUN (rmap_onmatch_next,
1044 : rmap_onmatch_next_cmd,
1045 : "on-match next",
1046 : "Exit policy on matches\n"
1047 : "Next clause\n")
1048 : {
1049 : struct route_map_index *index;
1050 :
1051 0 : index = vty->index;
1052 :
1053 0 : if (index)
1054 0 : index->exitpolicy = RMAP_NEXT;
1055 :
1056 0 : return CMD_SUCCESS;
1057 : }
1058 :
1059 0 : DEFUN (no_rmap_onmatch_next,
1060 : no_rmap_onmatch_next_cmd,
1061 : "no on-match next",
1062 : NO_STR
1063 : "Exit policy on matches\n"
1064 : "Next clause\n")
1065 : {
1066 : struct route_map_index *index;
1067 :
1068 0 : index = vty->index;
1069 :
1070 0 : if (index)
1071 0 : index->exitpolicy = RMAP_EXIT;
1072 :
1073 0 : return CMD_SUCCESS;
1074 : }
1075 :
1076 0 : DEFUN (rmap_onmatch_goto,
1077 : rmap_onmatch_goto_cmd,
1078 : "on-match goto <1-65535>",
1079 : "Exit policy on matches\n"
1080 : "Goto Clause number\n"
1081 : "Number\n")
1082 : {
1083 0 : struct route_map_index *index = vty->index;
1084 0 : int d = 0;
1085 :
1086 0 : if (index)
1087 : {
1088 0 : if (argc == 1 && argv[0])
1089 0 : VTY_GET_INTEGER_RANGE("route-map index", d, argv[0], 1, 65536);
1090 : else
1091 0 : d = index->pref + 1;
1092 :
1093 0 : if (d <= index->pref)
1094 : {
1095 : /* Can't allow you to do that, Dave */
1096 0 : vty_out (vty, "can't jump backwards in route-maps%s",
1097 0 : VTY_NEWLINE);
1098 0 : return CMD_WARNING;
1099 : }
1100 : else
1101 : {
1102 0 : index->exitpolicy = RMAP_GOTO;
1103 0 : index->nextpref = d;
1104 : }
1105 : }
1106 0 : return CMD_SUCCESS;
1107 : }
1108 :
1109 0 : DEFUN (no_rmap_onmatch_goto,
1110 : no_rmap_onmatch_goto_cmd,
1111 : "no on-match goto",
1112 : NO_STR
1113 : "Exit policy on matches\n"
1114 : "Goto Clause number\n")
1115 : {
1116 : struct route_map_index *index;
1117 :
1118 0 : index = vty->index;
1119 :
1120 0 : if (index)
1121 0 : index->exitpolicy = RMAP_EXIT;
1122 :
1123 0 : return CMD_SUCCESS;
1124 : }
1125 :
1126 : /* Cisco/GNU Zebra compatible ALIASes for on-match next */
1127 : ALIAS (rmap_onmatch_goto,
1128 : rmap_continue_cmd,
1129 : "continue",
1130 : "Continue on a different entry within the route-map\n")
1131 :
1132 : ALIAS (no_rmap_onmatch_goto,
1133 : no_rmap_continue_cmd,
1134 : "no continue",
1135 : NO_STR
1136 : "Continue on a different entry within the route-map\n")
1137 :
1138 : /* GNU Zebra compatible */
1139 : ALIAS (rmap_onmatch_goto,
1140 : rmap_continue_seq_cmd,
1141 : "continue <1-65535>",
1142 : "Continue on a different entry within the route-map\n"
1143 : "Route-map entry sequence number\n")
1144 :
1145 : ALIAS (no_rmap_onmatch_goto,
1146 : no_rmap_continue_seq,
1147 : "no continue <1-65535>",
1148 : NO_STR
1149 : "Continue on a different entry within the route-map\n"
1150 : "Route-map entry sequence number\n")
1151 :
1152 0 : DEFUN (rmap_show_name,
1153 : rmap_show_name_cmd,
1154 : "show route-map [WORD]",
1155 : SHOW_STR
1156 : "route-map information\n"
1157 : "route-map name\n")
1158 : {
1159 0 : const char *name = NULL;
1160 0 : if (argc)
1161 0 : name = argv[0];
1162 0 : return vty_show_route_map (vty, name);
1163 : }
1164 :
1165 : ALIAS (rmap_onmatch_goto,
1166 : rmap_continue_index_cmd,
1167 : "continue <1-65536>",
1168 : "Exit policy on matches\n"
1169 : "Goto Clause number\n")
1170 :
1171 0 : DEFUN (rmap_call,
1172 : rmap_call_cmd,
1173 : "call WORD",
1174 : "Jump to another Route-Map after match+set\n"
1175 : "Target route-map name\n")
1176 : {
1177 : struct route_map_index *index;
1178 :
1179 0 : index = vty->index;
1180 0 : if (index)
1181 : {
1182 0 : if (index->nextrm)
1183 0 : XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
1184 0 : index->nextrm = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[0]);
1185 : }
1186 0 : return CMD_SUCCESS;
1187 : }
1188 :
1189 0 : DEFUN (no_rmap_call,
1190 : no_rmap_call_cmd,
1191 : "no call",
1192 : NO_STR
1193 : "Jump to another Route-Map after match+set\n")
1194 : {
1195 : struct route_map_index *index;
1196 :
1197 0 : index = vty->index;
1198 :
1199 0 : if (index->nextrm)
1200 : {
1201 0 : XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
1202 0 : index->nextrm = NULL;
1203 : }
1204 :
1205 0 : return CMD_SUCCESS;
1206 : }
1207 :
1208 0 : DEFUN (rmap_description,
1209 : rmap_description_cmd,
1210 : "description .LINE",
1211 : "Route-map comment\n"
1212 : "Comment describing this route-map rule\n")
1213 : {
1214 : struct route_map_index *index;
1215 :
1216 0 : index = vty->index;
1217 0 : if (index)
1218 : {
1219 0 : if (index->description)
1220 0 : XFREE (MTYPE_TMP, index->description);
1221 0 : index->description = argv_concat (argv, argc, 0);
1222 : }
1223 0 : return CMD_SUCCESS;
1224 : }
1225 :
1226 0 : DEFUN (no_rmap_description,
1227 : no_rmap_description_cmd,
1228 : "no description",
1229 : NO_STR
1230 : "Route-map comment\n")
1231 : {
1232 : struct route_map_index *index;
1233 :
1234 0 : index = vty->index;
1235 0 : if (index)
1236 : {
1237 0 : if (index->description)
1238 0 : XFREE (MTYPE_TMP, index->description);
1239 0 : index->description = NULL;
1240 : }
1241 0 : return CMD_SUCCESS;
1242 : }
1243 :
1244 : /* Configuration write function. */
1245 : static int
1246 0 : route_map_config_write (struct vty *vty)
1247 : {
1248 : struct route_map *map;
1249 : struct route_map_index *index;
1250 : struct route_map_rule *rule;
1251 0 : int first = 1;
1252 0 : int write = 0;
1253 :
1254 0 : for (map = route_map_master.head; map; map = map->next)
1255 0 : for (index = map->head; index; index = index->next)
1256 : {
1257 0 : if (!first)
1258 0 : vty_out (vty, "!%s", VTY_NEWLINE);
1259 : else
1260 0 : first = 0;
1261 :
1262 0 : vty_out (vty, "route-map %s %s %d%s",
1263 : map->name,
1264 : route_map_type_str (index->type),
1265 0 : index->pref, VTY_NEWLINE);
1266 :
1267 0 : if (index->description)
1268 0 : vty_out (vty, " description %s%s", index->description, VTY_NEWLINE);
1269 :
1270 0 : for (rule = index->match_list.head; rule; rule = rule->next)
1271 0 : vty_out (vty, " match %s %s%s", rule->cmd->str,
1272 0 : rule->rule_str ? rule->rule_str : "",
1273 0 : VTY_NEWLINE);
1274 :
1275 0 : for (rule = index->set_list.head; rule; rule = rule->next)
1276 0 : vty_out (vty, " set %s %s%s", rule->cmd->str,
1277 0 : rule->rule_str ? rule->rule_str : "",
1278 0 : VTY_NEWLINE);
1279 0 : if (index->nextrm)
1280 0 : vty_out (vty, " call %s%s", index->nextrm, VTY_NEWLINE);
1281 0 : if (index->exitpolicy == RMAP_GOTO)
1282 0 : vty_out (vty, " on-match goto %d%s", index->nextpref, VTY_NEWLINE);
1283 0 : if (index->exitpolicy == RMAP_NEXT)
1284 0 : vty_out (vty," on-match next%s", VTY_NEWLINE);
1285 :
1286 0 : write++;
1287 : }
1288 0 : return write;
1289 : }
1290 :
1291 : /* Route map node structure. */
1292 : static struct cmd_node rmap_node =
1293 : {
1294 : RMAP_NODE,
1295 : "%s(config-route-map)# ",
1296 : 1
1297 : };
1298 :
1299 : /* Initialization of route map vector. */
1300 : void
1301 45 : route_map_init_vty (void)
1302 : {
1303 : /* Install route map top node. */
1304 45 : install_node (&rmap_node, route_map_config_write);
1305 :
1306 : /* Install route map commands. */
1307 45 : install_default (RMAP_NODE);
1308 45 : install_element (CONFIG_NODE, &route_map_cmd);
1309 45 : install_element (CONFIG_NODE, &no_route_map_cmd);
1310 45 : install_element (CONFIG_NODE, &no_route_map_all_cmd);
1311 :
1312 : /* Install the on-match stuff */
1313 45 : install_element (RMAP_NODE, &route_map_cmd);
1314 45 : install_element (RMAP_NODE, &rmap_onmatch_next_cmd);
1315 45 : install_element (RMAP_NODE, &no_rmap_onmatch_next_cmd);
1316 45 : install_element (RMAP_NODE, &rmap_onmatch_goto_cmd);
1317 45 : install_element (RMAP_NODE, &no_rmap_onmatch_goto_cmd);
1318 :
1319 : /* Install the continue stuff (ALIAS of on-match). */
1320 45 : install_element (RMAP_NODE, &rmap_continue_cmd);
1321 45 : install_element (RMAP_NODE, &no_rmap_continue_cmd);
1322 45 : install_element (RMAP_NODE, &rmap_continue_index_cmd);
1323 :
1324 : /* Install the call stuff. */
1325 45 : install_element (RMAP_NODE, &rmap_call_cmd);
1326 45 : install_element (RMAP_NODE, &no_rmap_call_cmd);
1327 :
1328 : /* Install description commands. */
1329 45 : install_element (RMAP_NODE, &rmap_description_cmd);
1330 45 : install_element (RMAP_NODE, &no_rmap_description_cmd);
1331 :
1332 : /* Install show command */
1333 45 : install_element (ENABLE_NODE, &rmap_show_name_cmd);
1334 45 : }
|