Annotation of embedaddon/quagga/lib/routemap.c, revision 1.1.1.1
1.1 misho 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: route_map_new (const char *name)
80: {
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. */
89: static struct route_map *
90: route_map_add (const char *name)
91: {
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. */
114: static void
115: 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: 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. */
150: struct route_map *
151: route_map_lookup_by_name (const char *name)
152: {
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. */
163: static struct route_map *
164: route_map_get (const char *name)
165: {
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. */
175: static const char *
176: route_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:
192: static int
193: route_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:
201: /* show route-map */
202: static void
203: 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: if (zlog_default)
210: vty_out (vty, "%s:%s", zlog_proto_names[zlog_default->protocol],
211: VTY_NEWLINE);
212:
213: 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);
218:
219: /* Description */
220: if (index->description)
221: vty_out (vty, " Description:%s %s%s", VTY_NEWLINE,
222: index->description, VTY_NEWLINE);
223:
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: /* Call clause */
236: vty_out (vty, " Call clause:%s", VTY_NEWLINE);
237: if (index->nextrm)
238: vty_out (vty, " Call %s%s", index->nextrm, VTY_NEWLINE);
239:
240: /* Exit Policy */
241: vty_out (vty, " Action:%s", VTY_NEWLINE);
242: if (index->exitpolicy == RMAP_GOTO)
243: vty_out (vty, " Goto %d%s", index->nextpref, VTY_NEWLINE);
244: else if (index->exitpolicy == RMAP_NEXT)
245: vty_out (vty, " Continue to next entry%s", VTY_NEWLINE);
246: else if (index->exitpolicy == RMAP_EXIT)
247: vty_out (vty, " Exit routemap%s", VTY_NEWLINE);
248: }
249: }
250:
251: static int
252: vty_show_route_map (struct vty *vty, const char *name)
253: {
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: else
272: {
273: for (map = route_map_master.head; map; map = map->next)
274: vty_show_route_map_entry (vty, map);
275: }
276: 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: route_map_index_new (void)
284: {
285: struct route_map_index *new;
286:
287: new = XCALLOC (MTYPE_ROUTE_MAP_INDEX, sizeof (struct route_map_index));
288: new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */
289: return new;
290: }
291:
292: /* Free route map index. */
293: static void
294: route_map_index_delete (struct route_map_index *index, int notify)
295: {
296: struct route_map_rule *rule;
297:
298: /* Free route match. */
299: while ((rule = index->match_list.head) != NULL)
300: route_map_rule_delete (&index->match_list, rule);
301:
302: /* Free route set. */
303: while ((rule = index->set_list.head) != NULL)
304: route_map_rule_delete (&index->set_list, rule);
305:
306: /* Remove index from route map list. */
307: if (index->next)
308: index->next->prev = index->prev;
309: else
310: index->map->tail = index->prev;
311:
312: if (index->prev)
313: index->prev->next = index->next;
314: else
315: index->map->head = index->next;
316:
317: /* Free 'char *nextrm' if not NULL */
318: if (index->nextrm)
319: XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
320:
321: /* Execute event hook. */
322: if (route_map_master.event_hook && notify)
323: (*route_map_master.event_hook) (RMAP_EVENT_INDEX_DELETED,
324: index->map->name);
325:
326: XFREE (MTYPE_ROUTE_MAP_INDEX, index);
327: }
328:
329: /* Lookup index from route map. */
330: static struct route_map_index *
331: 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: for (index = map->head; index; index = index->next)
337: if ((index->type == type || type == RMAP_ANY)
338: && index->pref == pref)
339: return index;
340: return NULL;
341: }
342:
343: /* Add new index to route map. */
344: static struct route_map_index *
345: 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: index = route_map_index_new ();
353: index->map = map;
354: index->type = type;
355: index->pref = pref;
356:
357: /* Compare preference. */
358: for (point = map->head; point; point = point->next)
359: if (point->pref >= pref)
360: break;
361:
362: if (map->head == NULL)
363: {
364: map->head = map->tail = index;
365: }
366: else if (point == NULL)
367: {
368: index->prev = map->tail;
369: map->tail->next = index;
370: map->tail = index;
371: }
372: else if (point == map->head)
373: {
374: index->next = map->head;
375: map->head->prev = index;
376: map->head = index;
377: }
378: else
379: {
380: index->next = point;
381: index->prev = point->prev;
382: if (point->prev)
383: point->prev->next = index;
384: point->prev = index;
385: }
386:
387: /* Execute event hook. */
388: if (route_map_master.event_hook)
389: (*route_map_master.event_hook) (RMAP_EVENT_INDEX_ADDED,
390: map->name);
391:
392: return index;
393: }
394:
395: /* Get route map index. */
396: static struct route_map_index *
397: 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: index = route_map_index_lookup (map, RMAP_ANY, pref);
403: if (index && index->type != type)
404: {
405: /* Delete index from route map. */
406: route_map_index_delete (index, 1);
407: index = NULL;
408: }
409: if (index == NULL)
410: index = route_map_index_add (map, type, pref);
411: return index;
412: }
413:
414: /* New route map rule */
415: static struct route_map_rule *
416: route_map_rule_new (void)
417: {
418: struct route_map_rule *new;
419:
420: new = XCALLOC (MTYPE_ROUTE_MAP_RULE, sizeof (struct route_map_rule));
421: return new;
422: }
423:
424: /* Install rule command to the match list. */
425: void
426: route_map_install_match (struct route_map_rule_cmd *cmd)
427: {
428: vector_set (route_match_vec, cmd);
429: }
430:
431: /* Install rule command to the set list. */
432: void
433: route_map_install_set (struct route_map_rule_cmd *cmd)
434: {
435: vector_set (route_set_vec, cmd);
436: }
437:
438: /* Lookup rule command from match list. */
439: static struct route_map_rule_cmd *
440: route_map_lookup_match (const char *name)
441: {
442: unsigned int i;
443: struct route_map_rule_cmd *rule;
444:
445: for (i = 0; i < vector_active (route_match_vec); i++)
446: if ((rule = vector_slot (route_match_vec, i)) != NULL)
447: if (strcmp (rule->str, name) == 0)
448: return rule;
449: return NULL;
450: }
451:
452: /* Lookup rule command from set list. */
453: static struct route_map_rule_cmd *
454: route_map_lookup_set (const char *name)
455: {
456: unsigned int i;
457: struct route_map_rule_cmd *rule;
458:
459: for (i = 0; i < vector_active (route_set_vec); i++)
460: if ((rule = vector_slot (route_set_vec, i)) != NULL)
461: if (strcmp (rule->str, name) == 0)
462: return rule;
463: return NULL;
464: }
465:
466: /* Add match and set rule to rule list. */
467: static void
468: route_map_rule_add (struct route_map_rule_list *list,
469: struct route_map_rule *rule)
470: {
471: rule->next = NULL;
472: rule->prev = list->tail;
473: if (list->tail)
474: list->tail->next = rule;
475: else
476: list->head = rule;
477: list->tail = rule;
478: }
479:
480: /* Delete rule from rule list. */
481: static void
482: route_map_rule_delete (struct route_map_rule_list *list,
483: struct route_map_rule *rule)
484: {
485: if (rule->cmd->func_free)
486: (*rule->cmd->func_free) (rule->value);
487:
488: if (rule->rule_str)
489: XFREE (MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str);
490:
491: if (rule->next)
492: rule->next->prev = rule->prev;
493: else
494: list->tail = rule->prev;
495: if (rule->prev)
496: rule->prev->next = rule->next;
497: else
498: list->head = rule->next;
499:
500: XFREE (MTYPE_ROUTE_MAP_RULE, rule);
501: }
502:
503: /* strcmp wrapper function which don't crush even argument is NULL. */
504: static int
505: rulecmp (const char *dst, const char *src)
506: {
507: if (dst == NULL)
508: {
509: if (src == NULL)
510: return 0;
511: else
512: return 1;
513: }
514: else
515: {
516: if (src == NULL)
517: return 1;
518: else
519: return strcmp (dst, src);
520: }
521: return 1;
522: }
523:
524: /* Add match statement to route map. */
525: int
526: 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: int replaced = 0;
534:
535: /* First lookup rule for add match statement. */
536: cmd = route_map_lookup_match (match_name);
537: if (cmd == NULL)
538: return RMAP_RULE_MISSING;
539:
540: /* Next call compile function for this match statement. */
541: if (cmd->func_compile)
542: {
543: compile= (*cmd->func_compile)(match_arg);
544: if (compile == NULL)
545: return RMAP_COMPILE_ERROR;
546: }
547: else
548: compile = NULL;
549:
550: /* If argument is completely same ignore it. */
551: for (rule = index->match_list.head; rule; rule = next)
552: {
553: next = rule->next;
554: if (rule->cmd == cmd)
555: {
556: route_map_rule_delete (&index->match_list, rule);
557: replaced = 1;
558: }
559: }
560:
561: /* Add new route map match rule. */
562: rule = route_map_rule_new ();
563: rule->cmd = cmd;
564: rule->value = compile;
565: if (match_arg)
566: rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, match_arg);
567: else
568: rule->rule_str = NULL;
569:
570: /* Add new route match rule to linked list. */
571: route_map_rule_add (&index->match_list, rule);
572:
573: /* Execute event hook. */
574: if (route_map_master.event_hook)
575: (*route_map_master.event_hook) (replaced ?
576: RMAP_EVENT_MATCH_REPLACED:
577: RMAP_EVENT_MATCH_ADDED,
578: index->map->name);
579:
580: return 0;
581: }
582:
583: /* Delete specified route match rule. */
584: int
585: 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: cmd = route_map_lookup_match (match_name);
592: if (cmd == NULL)
593: return 1;
594:
595: for (rule = index->match_list.head; rule; rule = rule->next)
596: if (rule->cmd == cmd &&
597: (rulecmp (rule->rule_str, match_arg) == 0 || match_arg == NULL))
598: {
599: route_map_rule_delete (&index->match_list, rule);
600: /* Execute event hook. */
601: if (route_map_master.event_hook)
602: (*route_map_master.event_hook) (RMAP_EVENT_MATCH_DELETED,
603: index->map->name);
604: return 0;
605: }
606: /* Can't find matched rule. */
607: return 1;
608: }
609:
610: /* Add route-map set statement to the route map. */
611: int
612: 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: int replaced = 0;
620:
621: cmd = route_map_lookup_set (set_name);
622: if (cmd == NULL)
623: return RMAP_RULE_MISSING;
624:
625: /* Next call compile function for this match statement. */
626: if (cmd->func_compile)
627: {
628: compile= (*cmd->func_compile)(set_arg);
629: if (compile == NULL)
630: return RMAP_COMPILE_ERROR;
631: }
632: else
633: 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: for (rule = index->set_list.head; rule; rule = next)
639: {
640: next = rule->next;
641: if (rule->cmd == cmd)
642: {
643: route_map_rule_delete (&index->set_list, rule);
644: replaced = 1;
645: }
646: }
647:
648: /* Add new route map match rule. */
649: rule = route_map_rule_new ();
650: rule->cmd = cmd;
651: rule->value = compile;
652: if (set_arg)
653: rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, set_arg);
654: else
655: rule->rule_str = NULL;
656:
657: /* Add new route match rule to linked list. */
658: route_map_rule_add (&index->set_list, rule);
659:
660: /* Execute event hook. */
661: if (route_map_master.event_hook)
662: (*route_map_master.event_hook) (replaced ?
663: RMAP_EVENT_SET_REPLACED:
664: RMAP_EVENT_SET_ADDED,
665: index->map->name);
666: return 0;
667: }
668:
669: /* Delete route map set rule. */
670: int
671: 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: cmd = route_map_lookup_set (set_name);
678: if (cmd == NULL)
679: return 1;
680:
681: for (rule = index->set_list.head; rule; rule = rule->next)
682: if ((rule->cmd == cmd) &&
683: (rulecmp (rule->rule_str, set_arg) == 0 || set_arg == NULL))
684: {
685: route_map_rule_delete (&index->set_list, rule);
686: /* Execute event hook. */
687: if (route_map_master.event_hook)
688: (*route_map_master.event_hook) (RMAP_EVENT_SET_DELETED,
689: index->map->name);
690: return 0;
691: }
692: /* Can't find matched rule. */
693: 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: 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: 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: if (!match_list->head)
754: ret = RMAP_MATCH;
755: else
756: {
757: 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: ret = (*match->cmd->func_apply) (match->value, prefix,
764: type, object);
765: if (ret != RMAP_MATCH)
766: return ret;
767: }
768: }
769: return ret;
770: }
771:
772: /* Apply route map to the object. */
773: route_map_result_t
774: 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: int ret = 0;
779: struct route_map_index *index;
780: struct route_map_rule *set;
781:
782: if (recursion > RMAP_RECURSION_LIMIT)
783: {
784: zlog (NULL, LOG_WARNING,
785: "route-map recursion limit (%d) reached, discarding route",
786: RMAP_RECURSION_LIMIT);
787: recursion = 0;
788: return RMAP_DENYMATCH;
789: }
790:
791: if (map == NULL)
792: return RMAP_DENYMATCH;
793:
794: for (index = map->head; index; index = index->next)
795: {
796: /* Apply this index. */
797: ret = route_map_apply_match (&index->match_list, prefix, type, object);
798:
799: /* Now we apply the matrix from above */
800: if (ret == RMAP_NOMATCH)
801: /* 'cont' from matrix - continue to next route-map sequence */
802: continue;
803: else if (ret == RMAP_MATCH)
804: {
805: if (index->type == RMAP_PERMIT)
806: /* 'action' */
807: {
808: /* permit+match must execute sets */
809: for (set = index->set_list.head; set; set = set->next)
810: ret = (*set->cmd->func_apply) (set->value, prefix,
811: type, object);
812:
813: /* Call another route-map if available */
814: if (index->nextrm)
815: {
816: struct route_map *nextrm =
817: route_map_lookup_by_name (index->nextrm);
818:
819: if (nextrm) /* Target route-map found, jump to it */
820: {
821: recursion++;
822: ret = route_map_apply (nextrm, prefix, type, object);
823: recursion--;
824: }
825:
826: /* If nextrm returned 'deny', finish. */
827: if (ret == RMAP_DENYMATCH)
828: return ret;
829: }
830:
831: switch (index->exitpolicy)
832: {
833: case RMAP_EXIT:
834: return ret;
835: case RMAP_NEXT:
836: continue;
837: case RMAP_GOTO:
838: {
839: /* Find the next clause to jump to */
840: struct route_map_index *next = index->next;
841: int nextpref = index->nextpref;
842:
843: while (next && next->pref < nextpref)
844: {
845: index = next;
846: next = next->next;
847: }
848: if (next == NULL)
849: {
850: /* No clauses match! */
851: return ret;
852: }
853: }
854: }
855: }
856: else if (index->type == RMAP_DENY)
857: /* 'deny' */
858: {
859: return RMAP_DENYMATCH;
860: }
861: }
862: }
863: /* Finally route-map does not match at all. */
864: return RMAP_DENYMATCH;
865: }
866:
867: void
868: route_map_add_hook (void (*func) (const char *))
869: {
870: route_map_master.add_hook = func;
871: }
872:
873: void
874: route_map_delete_hook (void (*func) (const char *))
875: {
876: route_map_master.delete_hook = func;
877: }
878:
879: void
880: route_map_event_hook (void (*func) (route_map_event_t, const char *))
881: {
882: route_map_master.event_hook = func;
883: }
884:
885: void
886: route_map_init (void)
887: {
888: /* Make vector for match and set. */
889: route_match_vec = vector_init (1);
890: route_set_vec = vector_init (1);
891: }
892:
893: void
894: route_map_finish (void)
895: {
896: vector_free (route_match_vec);
897: route_match_vec = NULL;
898: vector_free (route_set_vec);
899: route_set_vec = NULL;
900: }
901:
902: /* VTY related functions. */
903: 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: char *endptr = NULL;
917:
918: /* Permit check. */
919: if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
920: permit = RMAP_PERMIT;
921: else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
922: permit = RMAP_DENY;
923: else
924: {
925: vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
926: return CMD_WARNING;
927: }
928:
929: /* Preference check. */
930: pref = strtoul (argv[2], &endptr, 10);
931: if (pref == ULONG_MAX || *endptr != '\0')
932: {
933: vty_out (vty, "the fourth field must be positive integer%s",
934: VTY_NEWLINE);
935: return CMD_WARNING;
936: }
937: if (pref == 0 || pref > 65535)
938: {
939: vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
940: return CMD_WARNING;
941: }
942:
943: /* Get route map. */
944: map = route_map_get (argv[0]);
945: index = route_map_index_get (map, permit, pref);
946:
947: vty->index = index;
948: vty->node = RMAP_NODE;
949: return CMD_SUCCESS;
950: }
951:
952: 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: map = route_map_lookup_by_name (argv[0]);
962: if (map == NULL)
963: {
964: vty_out (vty, "%% Could not find route-map %s%s",
965: argv[0], VTY_NEWLINE);
966: return CMD_WARNING;
967: }
968:
969: route_map_delete (map);
970:
971: return CMD_SUCCESS;
972: }
973:
974: 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: char *endptr = NULL;
989:
990: /* Permit check. */
991: if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
992: permit = RMAP_PERMIT;
993: else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
994: permit = RMAP_DENY;
995: else
996: {
997: vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
998: return CMD_WARNING;
999: }
1000:
1001: /* Preference. */
1002: pref = strtoul (argv[2], &endptr, 10);
1003: if (pref == ULONG_MAX || *endptr != '\0')
1004: {
1005: vty_out (vty, "the fourth field must be positive integer%s",
1006: VTY_NEWLINE);
1007: return CMD_WARNING;
1008: }
1009: if (pref == 0 || pref > 65535)
1010: {
1011: vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
1012: return CMD_WARNING;
1013: }
1014:
1015: /* Existence check. */
1016: map = route_map_lookup_by_name (argv[0]);
1017: if (map == NULL)
1018: {
1019: vty_out (vty, "%% Could not find route-map %s%s",
1020: argv[0], VTY_NEWLINE);
1021: return CMD_WARNING;
1022: }
1023:
1024: /* Lookup route map index. */
1025: index = route_map_index_lookup (map, permit, pref);
1026: if (index == NULL)
1027: {
1028: vty_out (vty, "%% Could not find route-map entry %s %s%s",
1029: argv[0], argv[2], VTY_NEWLINE);
1030: return CMD_WARNING;
1031: }
1032:
1033: /* Delete index from route map. */
1034: route_map_index_delete (index, 1);
1035:
1036: /* If this route rule is the last one, delete route map itself. */
1037: if (route_map_empty (map))
1038: route_map_delete (map);
1039:
1040: return CMD_SUCCESS;
1041: }
1042:
1043: 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: index = vty->index;
1052:
1053: if (index)
1054: index->exitpolicy = RMAP_NEXT;
1055:
1056: return CMD_SUCCESS;
1057: }
1058:
1059: 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: index = vty->index;
1069:
1070: if (index)
1071: index->exitpolicy = RMAP_EXIT;
1072:
1073: return CMD_SUCCESS;
1074: }
1075:
1076: 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: struct route_map_index *index = vty->index;
1084: int d = 0;
1085:
1086: if (index)
1087: {
1088: if (argc == 1 && argv[0])
1089: VTY_GET_INTEGER_RANGE("route-map index", d, argv[0], 1, 65536);
1090: else
1091: d = index->pref + 1;
1092:
1093: if (d <= index->pref)
1094: {
1095: /* Can't allow you to do that, Dave */
1096: vty_out (vty, "can't jump backwards in route-maps%s",
1097: VTY_NEWLINE);
1098: return CMD_WARNING;
1099: }
1100: else
1101: {
1102: index->exitpolicy = RMAP_GOTO;
1103: index->nextpref = d;
1104: }
1105: }
1106: return CMD_SUCCESS;
1107: }
1108:
1109: 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: index = vty->index;
1119:
1120: if (index)
1121: index->exitpolicy = RMAP_EXIT;
1122:
1123: 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: 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: const char *name = NULL;
1160: if (argc)
1161: name = argv[0];
1162: 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: 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: index = vty->index;
1180: if (index)
1181: {
1182: if (index->nextrm)
1183: XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
1184: index->nextrm = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[0]);
1185: }
1186: return CMD_SUCCESS;
1187: }
1188:
1189: 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: index = vty->index;
1198:
1199: if (index->nextrm)
1200: {
1201: XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
1202: index->nextrm = NULL;
1203: }
1204:
1205: return CMD_SUCCESS;
1206: }
1207:
1208: 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: index = vty->index;
1217: if (index)
1218: {
1219: if (index->description)
1220: XFREE (MTYPE_TMP, index->description);
1221: index->description = argv_concat (argv, argc, 0);
1222: }
1223: return CMD_SUCCESS;
1224: }
1225:
1226: 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: index = vty->index;
1235: if (index)
1236: {
1237: if (index->description)
1238: XFREE (MTYPE_TMP, index->description);
1239: index->description = NULL;
1240: }
1241: return CMD_SUCCESS;
1242: }
1243:
1244: /* Configuration write function. */
1245: static int
1246: 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: int first = 1;
1252: int write = 0;
1253:
1254: for (map = route_map_master.head; map; map = map->next)
1255: for (index = map->head; index; index = index->next)
1256: {
1257: if (!first)
1258: vty_out (vty, "!%s", VTY_NEWLINE);
1259: else
1260: first = 0;
1261:
1262: vty_out (vty, "route-map %s %s %d%s",
1263: map->name,
1264: route_map_type_str (index->type),
1265: index->pref, VTY_NEWLINE);
1266:
1267: if (index->description)
1268: vty_out (vty, " description %s%s", index->description, VTY_NEWLINE);
1269:
1270: for (rule = index->match_list.head; rule; rule = rule->next)
1271: vty_out (vty, " match %s %s%s", rule->cmd->str,
1272: rule->rule_str ? rule->rule_str : "",
1273: VTY_NEWLINE);
1274:
1275: for (rule = index->set_list.head; rule; rule = rule->next)
1276: vty_out (vty, " set %s %s%s", rule->cmd->str,
1277: rule->rule_str ? rule->rule_str : "",
1278: VTY_NEWLINE);
1279: if (index->nextrm)
1280: vty_out (vty, " call %s%s", index->nextrm, VTY_NEWLINE);
1281: if (index->exitpolicy == RMAP_GOTO)
1282: vty_out (vty, " on-match goto %d%s", index->nextpref, VTY_NEWLINE);
1283: if (index->exitpolicy == RMAP_NEXT)
1284: vty_out (vty," on-match next%s", VTY_NEWLINE);
1285:
1286: write++;
1287: }
1288: 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: route_map_init_vty (void)
1302: {
1303: /* Install route map top node. */
1304: install_node (&rmap_node, route_map_config_write);
1305:
1306: /* Install route map commands. */
1307: install_default (RMAP_NODE);
1308: install_element (CONFIG_NODE, &route_map_cmd);
1309: install_element (CONFIG_NODE, &no_route_map_cmd);
1310: install_element (CONFIG_NODE, &no_route_map_all_cmd);
1311:
1312: /* Install the on-match stuff */
1313: install_element (RMAP_NODE, &route_map_cmd);
1314: install_element (RMAP_NODE, &rmap_onmatch_next_cmd);
1315: install_element (RMAP_NODE, &no_rmap_onmatch_next_cmd);
1316: install_element (RMAP_NODE, &rmap_onmatch_goto_cmd);
1317: install_element (RMAP_NODE, &no_rmap_onmatch_goto_cmd);
1318:
1319: /* Install the continue stuff (ALIAS of on-match). */
1320: install_element (RMAP_NODE, &rmap_continue_cmd);
1321: install_element (RMAP_NODE, &no_rmap_continue_cmd);
1322: install_element (RMAP_NODE, &rmap_continue_index_cmd);
1323:
1324: /* Install the call stuff. */
1325: install_element (RMAP_NODE, &rmap_call_cmd);
1326: install_element (RMAP_NODE, &no_rmap_call_cmd);
1327:
1328: /* Install description commands. */
1329: install_element (RMAP_NODE, &rmap_description_cmd);
1330: install_element (RMAP_NODE, &no_rmap_description_cmd);
1331:
1332: /* Install show command */
1333: install_element (ENABLE_NODE, &rmap_show_name_cmd);
1334: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>