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: /* cleanup route_map */
901: while (route_map_master.head)
902: route_map_delete (route_map_master.head);
903: }
904:
905: /* VTY related functions. */
906: DEFUN (route_map,
907: route_map_cmd,
908: "route-map WORD (deny|permit) <1-65535>",
909: "Create route-map or enter route-map command mode\n"
910: "Route map tag\n"
911: "Route map denies set operations\n"
912: "Route map permits set operations\n"
913: "Sequence to insert to/delete from existing route-map entry\n")
914: {
915: int permit;
916: unsigned long pref;
917: struct route_map *map;
918: struct route_map_index *index;
919: char *endptr = NULL;
920:
921: /* Permit check. */
922: if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
923: permit = RMAP_PERMIT;
924: else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
925: permit = RMAP_DENY;
926: else
927: {
928: vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
929: return CMD_WARNING;
930: }
931:
932: /* Preference check. */
933: pref = strtoul (argv[2], &endptr, 10);
934: if (pref == ULONG_MAX || *endptr != '\0')
935: {
936: vty_out (vty, "the fourth field must be positive integer%s",
937: VTY_NEWLINE);
938: return CMD_WARNING;
939: }
940: if (pref == 0 || pref > 65535)
941: {
942: vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
943: return CMD_WARNING;
944: }
945:
946: /* Get route map. */
947: map = route_map_get (argv[0]);
948: index = route_map_index_get (map, permit, pref);
949:
950: vty->index = index;
951: vty->node = RMAP_NODE;
952: return CMD_SUCCESS;
953: }
954:
955: DEFUN (no_route_map_all,
956: no_route_map_all_cmd,
957: "no route-map WORD",
958: NO_STR
959: "Create route-map or enter route-map command mode\n"
960: "Route map tag\n")
961: {
962: struct route_map *map;
963:
964: map = route_map_lookup_by_name (argv[0]);
965: if (map == NULL)
966: {
967: vty_out (vty, "%% Could not find route-map %s%s",
968: argv[0], VTY_NEWLINE);
969: return CMD_WARNING;
970: }
971:
972: route_map_delete (map);
973:
974: return CMD_SUCCESS;
975: }
976:
977: DEFUN (no_route_map,
978: no_route_map_cmd,
979: "no route-map WORD (deny|permit) <1-65535>",
980: NO_STR
981: "Create route-map or enter route-map command mode\n"
982: "Route map tag\n"
983: "Route map denies set operations\n"
984: "Route map permits set operations\n"
985: "Sequence to insert to/delete from existing route-map entry\n")
986: {
987: int permit;
988: unsigned long pref;
989: struct route_map *map;
990: struct route_map_index *index;
991: char *endptr = NULL;
992:
993: /* Permit check. */
994: if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
995: permit = RMAP_PERMIT;
996: else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
997: permit = RMAP_DENY;
998: else
999: {
1000: vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
1001: return CMD_WARNING;
1002: }
1003:
1004: /* Preference. */
1005: pref = strtoul (argv[2], &endptr, 10);
1006: if (pref == ULONG_MAX || *endptr != '\0')
1007: {
1008: vty_out (vty, "the fourth field must be positive integer%s",
1009: VTY_NEWLINE);
1010: return CMD_WARNING;
1011: }
1012: if (pref == 0 || pref > 65535)
1013: {
1014: vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
1015: return CMD_WARNING;
1016: }
1017:
1018: /* Existence check. */
1019: map = route_map_lookup_by_name (argv[0]);
1020: if (map == NULL)
1021: {
1022: vty_out (vty, "%% Could not find route-map %s%s",
1023: argv[0], VTY_NEWLINE);
1024: return CMD_WARNING;
1025: }
1026:
1027: /* Lookup route map index. */
1028: index = route_map_index_lookup (map, permit, pref);
1029: if (index == NULL)
1030: {
1031: vty_out (vty, "%% Could not find route-map entry %s %s%s",
1032: argv[0], argv[2], VTY_NEWLINE);
1033: return CMD_WARNING;
1034: }
1035:
1036: /* Delete index from route map. */
1037: route_map_index_delete (index, 1);
1038:
1039: /* If this route rule is the last one, delete route map itself. */
1040: if (route_map_empty (map))
1041: route_map_delete (map);
1042:
1043: return CMD_SUCCESS;
1044: }
1045:
1046: DEFUN (rmap_onmatch_next,
1047: rmap_onmatch_next_cmd,
1048: "on-match next",
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_NEXT;
1058:
1059: return CMD_SUCCESS;
1060: }
1061:
1062: DEFUN (no_rmap_onmatch_next,
1063: no_rmap_onmatch_next_cmd,
1064: "no on-match next",
1065: NO_STR
1066: "Exit policy on matches\n"
1067: "Next clause\n")
1068: {
1069: struct route_map_index *index;
1070:
1071: index = vty->index;
1072:
1073: if (index)
1074: index->exitpolicy = RMAP_EXIT;
1075:
1076: return CMD_SUCCESS;
1077: }
1078:
1079: DEFUN (rmap_onmatch_goto,
1080: rmap_onmatch_goto_cmd,
1081: "on-match goto <1-65535>",
1082: "Exit policy on matches\n"
1083: "Goto Clause number\n"
1084: "Number\n")
1085: {
1086: struct route_map_index *index = vty->index;
1087: int d = 0;
1088:
1089: if (index)
1090: {
1091: if (argc == 1 && argv[0])
1092: VTY_GET_INTEGER_RANGE("route-map index", d, argv[0], 1, 65536);
1093: else
1094: d = index->pref + 1;
1095:
1096: if (d <= index->pref)
1097: {
1098: /* Can't allow you to do that, Dave */
1099: vty_out (vty, "can't jump backwards in route-maps%s",
1100: VTY_NEWLINE);
1101: return CMD_WARNING;
1102: }
1103: else
1104: {
1105: index->exitpolicy = RMAP_GOTO;
1106: index->nextpref = d;
1107: }
1108: }
1109: return CMD_SUCCESS;
1110: }
1111:
1112: DEFUN (no_rmap_onmatch_goto,
1113: no_rmap_onmatch_goto_cmd,
1114: "no on-match goto",
1115: NO_STR
1116: "Exit policy on matches\n"
1117: "Goto Clause number\n")
1118: {
1119: struct route_map_index *index;
1120:
1121: index = vty->index;
1122:
1123: if (index)
1124: index->exitpolicy = RMAP_EXIT;
1125:
1126: return CMD_SUCCESS;
1127: }
1128:
1129: /* Cisco/GNU Zebra compatible ALIASes for on-match next */
1130: ALIAS (rmap_onmatch_goto,
1131: rmap_continue_cmd,
1132: "continue",
1133: "Continue on a different entry within the route-map\n")
1134:
1135: ALIAS (no_rmap_onmatch_goto,
1136: no_rmap_continue_cmd,
1137: "no continue",
1138: NO_STR
1139: "Continue on a different entry within the route-map\n")
1140:
1141: /* GNU Zebra compatible */
1142: ALIAS (rmap_onmatch_goto,
1143: rmap_continue_seq_cmd,
1144: "continue <1-65535>",
1145: "Continue on a different entry within the route-map\n"
1146: "Route-map entry sequence number\n")
1147:
1148: ALIAS (no_rmap_onmatch_goto,
1149: no_rmap_continue_seq,
1150: "no continue <1-65535>",
1151: NO_STR
1152: "Continue on a different entry within the route-map\n"
1153: "Route-map entry sequence number\n")
1154:
1155: DEFUN (rmap_show_name,
1156: rmap_show_name_cmd,
1157: "show route-map [WORD]",
1158: SHOW_STR
1159: "route-map information\n"
1160: "route-map name\n")
1161: {
1162: const char *name = NULL;
1163: if (argc)
1164: name = argv[0];
1165: return vty_show_route_map (vty, name);
1166: }
1167:
1168: ALIAS (rmap_onmatch_goto,
1169: rmap_continue_index_cmd,
1170: "continue <1-65536>",
1171: "Exit policy on matches\n"
1172: "Goto Clause number\n")
1173:
1174: DEFUN (rmap_call,
1175: rmap_call_cmd,
1176: "call WORD",
1177: "Jump to another Route-Map after match+set\n"
1178: "Target route-map name\n")
1179: {
1180: struct route_map_index *index;
1181:
1182: index = vty->index;
1183: if (index)
1184: {
1185: if (index->nextrm)
1186: XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
1187: index->nextrm = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[0]);
1188: }
1189: return CMD_SUCCESS;
1190: }
1191:
1192: DEFUN (no_rmap_call,
1193: no_rmap_call_cmd,
1194: "no call",
1195: NO_STR
1196: "Jump to another Route-Map after match+set\n")
1197: {
1198: struct route_map_index *index;
1199:
1200: index = vty->index;
1201:
1202: if (index->nextrm)
1203: {
1204: XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
1205: index->nextrm = NULL;
1206: }
1207:
1208: return CMD_SUCCESS;
1209: }
1210:
1211: DEFUN (rmap_description,
1212: rmap_description_cmd,
1213: "description .LINE",
1214: "Route-map comment\n"
1215: "Comment describing this route-map rule\n")
1216: {
1217: struct route_map_index *index;
1218:
1219: index = vty->index;
1220: if (index)
1221: {
1222: if (index->description)
1223: XFREE (MTYPE_TMP, index->description);
1224: index->description = argv_concat (argv, argc, 0);
1225: }
1226: return CMD_SUCCESS;
1227: }
1228:
1229: DEFUN (no_rmap_description,
1230: no_rmap_description_cmd,
1231: "no description",
1232: NO_STR
1233: "Route-map comment\n")
1234: {
1235: struct route_map_index *index;
1236:
1237: index = vty->index;
1238: if (index)
1239: {
1240: if (index->description)
1241: XFREE (MTYPE_TMP, index->description);
1242: index->description = NULL;
1243: }
1244: return CMD_SUCCESS;
1245: }
1246:
1247: /* Configuration write function. */
1248: static int
1249: route_map_config_write (struct vty *vty)
1250: {
1251: struct route_map *map;
1252: struct route_map_index *index;
1253: struct route_map_rule *rule;
1254: int first = 1;
1255: int write = 0;
1256:
1257: for (map = route_map_master.head; map; map = map->next)
1258: for (index = map->head; index; index = index->next)
1259: {
1260: if (!first)
1261: vty_out (vty, "!%s", VTY_NEWLINE);
1262: else
1263: first = 0;
1264:
1265: vty_out (vty, "route-map %s %s %d%s",
1266: map->name,
1267: route_map_type_str (index->type),
1268: index->pref, VTY_NEWLINE);
1269:
1270: if (index->description)
1271: vty_out (vty, " description %s%s", index->description, VTY_NEWLINE);
1272:
1273: for (rule = index->match_list.head; rule; rule = rule->next)
1274: vty_out (vty, " match %s %s%s", rule->cmd->str,
1275: rule->rule_str ? rule->rule_str : "",
1276: VTY_NEWLINE);
1277:
1278: for (rule = index->set_list.head; rule; rule = rule->next)
1279: vty_out (vty, " set %s %s%s", rule->cmd->str,
1280: rule->rule_str ? rule->rule_str : "",
1281: VTY_NEWLINE);
1282: if (index->nextrm)
1283: vty_out (vty, " call %s%s", index->nextrm, VTY_NEWLINE);
1284: if (index->exitpolicy == RMAP_GOTO)
1285: vty_out (vty, " on-match goto %d%s", index->nextpref, VTY_NEWLINE);
1286: if (index->exitpolicy == RMAP_NEXT)
1287: vty_out (vty," on-match next%s", VTY_NEWLINE);
1288:
1289: write++;
1290: }
1291: return write;
1292: }
1293:
1294: /* Route map node structure. */
1295: static struct cmd_node rmap_node =
1296: {
1297: RMAP_NODE,
1298: "%s(config-route-map)# ",
1299: 1
1300: };
1301:
1302: /* Initialization of route map vector. */
1303: void
1304: route_map_init_vty (void)
1305: {
1306: /* Install route map top node. */
1307: install_node (&rmap_node, route_map_config_write);
1308:
1309: /* Install route map commands. */
1310: install_default (RMAP_NODE);
1311: install_element (CONFIG_NODE, &route_map_cmd);
1312: install_element (CONFIG_NODE, &no_route_map_cmd);
1313: install_element (CONFIG_NODE, &no_route_map_all_cmd);
1314:
1315: /* Install the on-match stuff */
1316: install_element (RMAP_NODE, &route_map_cmd);
1317: install_element (RMAP_NODE, &rmap_onmatch_next_cmd);
1318: install_element (RMAP_NODE, &no_rmap_onmatch_next_cmd);
1319: install_element (RMAP_NODE, &rmap_onmatch_goto_cmd);
1320: install_element (RMAP_NODE, &no_rmap_onmatch_goto_cmd);
1321:
1322: /* Install the continue stuff (ALIAS of on-match). */
1323: install_element (RMAP_NODE, &rmap_continue_cmd);
1324: install_element (RMAP_NODE, &no_rmap_continue_cmd);
1325: install_element (RMAP_NODE, &rmap_continue_index_cmd);
1326:
1327: /* Install the call stuff. */
1328: install_element (RMAP_NODE, &rmap_call_cmd);
1329: install_element (RMAP_NODE, &no_rmap_call_cmd);
1330:
1331: /* Install description commands. */
1332: install_element (RMAP_NODE, &rmap_description_cmd);
1333: install_element (RMAP_NODE, &no_rmap_description_cmd);
1334:
1335: /* Install show command */
1336: install_element (ENABLE_NODE, &rmap_show_name_cmd);
1337: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>