]> git.proxmox.com Git - mirror_frr.git/blob - lib/routemap.c
BGP: route-map scale
[mirror_frr.git] / lib / routemap.c
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 #include "hash.h"
32
33 /* Vector for route match rules. */
34 static vector route_match_vec;
35
36 /* Vector for route set rules. */
37 static vector route_set_vec;
38
39 /* Route map rule. This rule has both `match' rule and `set' rule. */
40 struct route_map_rule
41 {
42 /* Rule type. */
43 struct route_map_rule_cmd *cmd;
44
45 /* For pretty printing. */
46 char *rule_str;
47
48 /* Pre-compiled match rule. */
49 void *value;
50
51 /* Linked list. */
52 struct route_map_rule *next;
53 struct route_map_rule *prev;
54 };
55
56 /* Making route map list. */
57 struct route_map_list
58 {
59 struct route_map *head;
60 struct route_map *tail;
61
62 void (*add_hook) (const char *);
63 void (*delete_hook) (const char *);
64 void (*event_hook) (route_map_event_t, const char *);
65 };
66
67 /* Master list of route map. */
68 static struct route_map_list route_map_master = { NULL, NULL, NULL, NULL, NULL };
69 struct hash *route_map_master_hash = NULL;
70
71 static unsigned int
72 route_map_hash_key_make (void *p)
73 {
74 const struct route_map *map = p;
75 return string_hash_make (map->name);
76 }
77
78 static int
79 route_map_hash_cmp(const void *p1, const void *p2)
80 {
81 const struct route_map *map1 = p1;
82 const struct route_map *map2 = p2;
83
84 if (map1->deleted == map2->deleted)
85 {
86 if (map1->name && map2->name)
87 {
88 if (!strcmp (map1->name, map2->name))
89 {
90 return 1;
91 }
92 }
93 else if (!map1->name && !map2->name)
94 {
95 return 1;
96 }
97 }
98
99 return 0;
100 }
101
102 enum route_map_upd8_type
103 {
104 ROUTE_MAP_ADD = 1,
105 ROUTE_MAP_DEL,
106 };
107
108 /* all possible route-map dependency types */
109 enum route_map_dep_type
110 {
111 ROUTE_MAP_DEP_RMAP = 1,
112 ROUTE_MAP_DEP_CLIST,
113 ROUTE_MAP_DEP_ECLIST,
114 ROUTE_MAP_DEP_PLIST,
115 ROUTE_MAP_DEP_ASPATH,
116 ROUTE_MAP_DEP_FILTER,
117 ROUTE_MAP_DEP_MAX,
118 };
119
120 struct route_map_dep
121 {
122 char *dep_name;
123 struct hash *dep_rmap_hash;
124 struct hash *this_hash; /* ptr to the hash structure this is part of */
125 };
126
127 /* Hashes maintaining dependency between various sublists used by route maps */
128 struct hash *route_map_dep_hash[ROUTE_MAP_DEP_MAX];
129
130 static unsigned int route_map_dep_hash_make_key (void *p);
131 static int route_map_dep_hash_cmp (const void *p1, const void *p2);
132 static void route_map_init_dep_hashes (void);
133 static void route_map_clear_all_references (char *rmap_name);
134 static void route_map_rule_delete (struct route_map_rule_list *,
135 struct route_map_rule *);
136 static int rmap_debug = 0;
137
138 static void
139 route_map_index_delete (struct route_map_index *, int);
140
141 /* New route map allocation. Please note route map's name must be
142 specified. */
143 static struct route_map *
144 route_map_new (const char *name)
145 {
146 struct route_map *new;
147
148 new = XCALLOC (MTYPE_ROUTE_MAP, sizeof (struct route_map));
149 new->name = XSTRDUP (MTYPE_ROUTE_MAP_NAME, name);
150 return new;
151 }
152
153 /* Add new name to route_map. */
154 static struct route_map *
155 route_map_add (const char *name)
156 {
157 struct route_map *map;
158 struct route_map_list *list;
159
160 map = route_map_new (name);
161 list = &route_map_master;
162
163 /* Add map to the hash */
164 hash_get(route_map_master_hash, map, hash_alloc_intern);
165
166 map->next = NULL;
167 map->prev = list->tail;
168 if (list->tail)
169 list->tail->next = map;
170 else
171 list->head = map;
172 list->tail = map;
173
174 /* Execute hook. */
175 if (route_map_master.add_hook)
176 {
177 (*route_map_master.add_hook) (name);
178 route_map_notify_dependencies(name, RMAP_EVENT_CALL_ADDED);
179 }
180 return map;
181 }
182
183 /* this is supposed to be called post processing by
184 * the delete hook function. Don't invoke delete_hook
185 * again in this routine.
186 */
187 static void
188 route_map_free_map (struct route_map *map)
189 {
190 struct route_map_list *list;
191 struct route_map_index *index;
192
193 while ((index = map->head) != NULL)
194 route_map_index_delete (index, 0);
195
196 list = &route_map_master;
197
198 if (map != NULL)
199 {
200 if (map->next)
201 map->next->prev = map->prev;
202 else
203 list->tail = map->prev;
204
205 if (map->prev)
206 map->prev->next = map->next;
207 else
208 list->head = map->next;
209
210 hash_release(route_map_master_hash, map);
211 XFREE (MTYPE_ROUTE_MAP_NAME, map->name);
212 XFREE (MTYPE_ROUTE_MAP, map);
213 }
214 }
215
216 /* Route map delete from list. */
217 static void
218 route_map_delete (struct route_map *map)
219 {
220 struct route_map_index *index;
221 char *name;
222
223 while ((index = map->head) != NULL)
224 route_map_index_delete (index, 0);
225
226 name = map->name;
227 map->head = NULL;
228
229 /* Clear all dependencies */
230 route_map_clear_all_references(name);
231 map->deleted = 1;
232 /* Execute deletion hook. */
233 if (route_map_master.delete_hook)
234 {
235 (*route_map_master.delete_hook) (name);
236 route_map_notify_dependencies(name, RMAP_EVENT_CALL_DELETED);
237 }
238
239 if (!map->to_be_processed)
240 {
241 route_map_free_map (map);
242 }
243 }
244
245 /* Lookup route map by route map name string. */
246 struct route_map *
247 route_map_lookup_by_name (const char *name)
248 {
249 struct route_map *map;
250 struct route_map tmp_map;
251
252 if (!name)
253 return NULL;
254
255 // map.deleted is 0 via memset
256 memset(&tmp_map, 0, sizeof(struct route_map));
257 tmp_map.name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, name);
258 map = hash_lookup(route_map_master_hash, &tmp_map);
259 XFREE(MTYPE_ROUTE_MAP_NAME, tmp_map.name);
260 return map;
261 }
262
263 int
264 route_map_mark_updated (const char *name, int del_later)
265 {
266 struct route_map *map;
267 int ret = -1;
268 struct route_map tmp_map;
269
270 if (!name)
271 return (ret);
272
273 map = route_map_lookup_by_name(name);
274
275 /* If we did not find the routemap with deleted=0 try again
276 * with deleted=1
277 */
278 if (!map)
279 {
280 memset(&tmp_map, 0, sizeof(struct route_map));
281 tmp_map.name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, name);
282 tmp_map.deleted = 1;
283 map = hash_lookup(route_map_master_hash, &tmp_map);
284 XFREE(MTYPE_ROUTE_MAP_NAME, tmp_map.name);
285 }
286
287 if (map)
288 {
289 map->to_be_processed = 1;
290 ret = 0;
291 }
292
293 return(ret);
294 }
295
296 int
297 route_map_clear_updated (struct route_map *map)
298 {
299 int ret = -1;
300
301 if (map)
302 {
303 map->to_be_processed = 0;
304 if (map->deleted)
305 route_map_free_map(map);
306 }
307
308 return (ret);
309 }
310
311 /* Lookup route map. If there isn't route map create one and return
312 it. */
313 static struct route_map *
314 route_map_get (const char *name)
315 {
316 struct route_map *map;
317
318 map = route_map_lookup_by_name (name);
319 if (map == NULL)
320 map = route_map_add (name);
321
322 return map;
323 }
324
325 void
326 route_map_walk_update_list (void *arg,
327 int (*route_map_update_fn) (void *arg, char *name))
328 {
329 struct route_map *node;
330 struct route_map *nnode = NULL;
331
332 for (node = route_map_master.head; node; node = nnode)
333 {
334 if (node->to_be_processed)
335 {
336 /* DD: Should we add any thread yield code here */
337 route_map_update_fn(arg, node->name);
338 nnode = node->next;
339 route_map_clear_updated(node);
340 }
341 else
342 nnode = node->next;
343 }
344 }
345
346 /* Return route map's type string. */
347 static const char *
348 route_map_type_str (enum route_map_type type)
349 {
350 switch (type)
351 {
352 case RMAP_PERMIT:
353 return "permit";
354 break;
355 case RMAP_DENY:
356 return "deny";
357 break;
358 default:
359 return "";
360 break;
361 }
362 }
363
364 static int
365 route_map_empty (struct route_map *map)
366 {
367 if (map->head == NULL && map->tail == NULL)
368 return 1;
369 else
370 return 0;
371 }
372
373 /* show route-map */
374 static void
375 vty_show_route_map_entry (struct vty *vty, struct route_map *map)
376 {
377 struct route_map_index *index;
378 struct route_map_rule *rule;
379
380 /* Print the name of the protocol */
381 if (zlog_default)
382 vty_out (vty, "%s", zlog_proto_names[zlog_default->protocol]);
383 if (zlog_default->instance)
384 vty_out (vty, " %d", zlog_default->instance);
385 vty_out (vty, ":%s", VTY_NEWLINE);
386
387 for (index = map->head; index; index = index->next)
388 {
389 vty_out (vty, "route-map %s, %s, sequence %d%s",
390 map->name, route_map_type_str (index->type),
391 index->pref, VTY_NEWLINE);
392
393 /* Description */
394 if (index->description)
395 vty_out (vty, " Description:%s %s%s", VTY_NEWLINE,
396 index->description, VTY_NEWLINE);
397
398 /* Match clauses */
399 vty_out (vty, " Match clauses:%s", VTY_NEWLINE);
400 for (rule = index->match_list.head; rule; rule = rule->next)
401 vty_out (vty, " %s %s%s",
402 rule->cmd->str, rule->rule_str, VTY_NEWLINE);
403
404 vty_out (vty, " Set clauses:%s", VTY_NEWLINE);
405 for (rule = index->set_list.head; rule; rule = rule->next)
406 vty_out (vty, " %s %s%s",
407 rule->cmd->str, rule->rule_str, VTY_NEWLINE);
408
409 /* Call clause */
410 vty_out (vty, " Call clause:%s", VTY_NEWLINE);
411 if (index->nextrm)
412 vty_out (vty, " Call %s%s", index->nextrm, VTY_NEWLINE);
413
414 /* Exit Policy */
415 vty_out (vty, " Action:%s", VTY_NEWLINE);
416 if (index->exitpolicy == RMAP_GOTO)
417 vty_out (vty, " Goto %d%s", index->nextpref, VTY_NEWLINE);
418 else if (index->exitpolicy == RMAP_NEXT)
419 vty_out (vty, " Continue to next entry%s", VTY_NEWLINE);
420 else if (index->exitpolicy == RMAP_EXIT)
421 vty_out (vty, " Exit routemap%s", VTY_NEWLINE);
422 }
423 }
424
425 static int
426 vty_show_route_map (struct vty *vty, const char *name)
427 {
428 struct route_map *map;
429
430 if (name)
431 {
432 map = route_map_lookup_by_name (name);
433
434 if (map)
435 {
436 vty_show_route_map_entry (vty, map);
437 return CMD_SUCCESS;
438 }
439 else
440 {
441 if (zlog_default)
442 vty_out (vty, "%s", zlog_proto_names[zlog_default->protocol]);
443 if (zlog_default->instance)
444 vty_out (vty, " %d", zlog_default->instance);
445 vty_out (vty, ": 'route-map %s' not found%s", name, VTY_NEWLINE);
446 return CMD_SUCCESS;
447 }
448 }
449 else
450 {
451 for (map = route_map_master.head; map; map = map->next)
452 if (!map->deleted)
453 vty_show_route_map_entry (vty, map);
454 }
455 return CMD_SUCCESS;
456 }
457
458
459 /* New route map allocation. Please note route map's name must be
460 specified. */
461 static struct route_map_index *
462 route_map_index_new (void)
463 {
464 struct route_map_index *new;
465
466 new = XCALLOC (MTYPE_ROUTE_MAP_INDEX, sizeof (struct route_map_index));
467 new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */
468 return new;
469 }
470
471 /* Free route map index. */
472 static void
473 route_map_index_delete (struct route_map_index *index, int notify)
474 {
475 struct route_map_rule *rule;
476
477 /* Free route match. */
478 while ((rule = index->match_list.head) != NULL)
479 route_map_rule_delete (&index->match_list, rule);
480
481 /* Free route set. */
482 while ((rule = index->set_list.head) != NULL)
483 route_map_rule_delete (&index->set_list, rule);
484
485 /* Remove index from route map list. */
486 if (index->next)
487 index->next->prev = index->prev;
488 else
489 index->map->tail = index->prev;
490
491 if (index->prev)
492 index->prev->next = index->next;
493 else
494 index->map->head = index->next;
495
496 /* Free 'char *nextrm' if not NULL */
497 if (index->nextrm)
498 XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
499
500 /* Execute event hook. */
501 if (route_map_master.event_hook && notify)
502 {
503 (*route_map_master.event_hook) (RMAP_EVENT_INDEX_DELETED,
504 index->map->name);
505 route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
506 }
507 XFREE (MTYPE_ROUTE_MAP_INDEX, index);
508 }
509
510 /* Lookup index from route map. */
511 static struct route_map_index *
512 route_map_index_lookup (struct route_map *map, enum route_map_type type,
513 int pref)
514 {
515 struct route_map_index *index;
516
517 for (index = map->head; index; index = index->next)
518 if ((index->type == type || type == RMAP_ANY)
519 && index->pref == pref)
520 return index;
521 return NULL;
522 }
523
524 /* Add new index to route map. */
525 static struct route_map_index *
526 route_map_index_add (struct route_map *map, enum route_map_type type,
527 int pref)
528 {
529 struct route_map_index *index;
530 struct route_map_index *point;
531
532 /* Allocate new route map inex. */
533 index = route_map_index_new ();
534 index->map = map;
535 index->type = type;
536 index->pref = pref;
537
538 /* Compare preference. */
539 for (point = map->head; point; point = point->next)
540 if (point->pref >= pref)
541 break;
542
543 if (map->head == NULL)
544 {
545 map->head = map->tail = index;
546 }
547 else if (point == NULL)
548 {
549 index->prev = map->tail;
550 map->tail->next = index;
551 map->tail = index;
552 }
553 else if (point == map->head)
554 {
555 index->next = map->head;
556 map->head->prev = index;
557 map->head = index;
558 }
559 else
560 {
561 index->next = point;
562 index->prev = point->prev;
563 if (point->prev)
564 point->prev->next = index;
565 point->prev = index;
566 }
567
568 /* Execute event hook. */
569 if (route_map_master.event_hook)
570 {
571 (*route_map_master.event_hook) (RMAP_EVENT_INDEX_ADDED,
572 map->name);
573 route_map_notify_dependencies (map->name, RMAP_EVENT_CALL_ADDED);
574 }
575 return index;
576 }
577
578 /* Get route map index. */
579 static struct route_map_index *
580 route_map_index_get (struct route_map *map, enum route_map_type type,
581 int pref)
582 {
583 struct route_map_index *index;
584
585 index = route_map_index_lookup (map, RMAP_ANY, pref);
586 if (index && index->type != type)
587 {
588 /* Delete index from route map. */
589 route_map_index_delete (index, 1);
590 index = NULL;
591 }
592 if (index == NULL)
593 index = route_map_index_add (map, type, pref);
594 return index;
595 }
596
597 /* New route map rule */
598 static struct route_map_rule *
599 route_map_rule_new (void)
600 {
601 struct route_map_rule *new;
602
603 new = XCALLOC (MTYPE_ROUTE_MAP_RULE, sizeof (struct route_map_rule));
604 return new;
605 }
606
607 /* Install rule command to the match list. */
608 void
609 route_map_install_match (struct route_map_rule_cmd *cmd)
610 {
611 vector_set (route_match_vec, cmd);
612 }
613
614 /* Install rule command to the set list. */
615 void
616 route_map_install_set (struct route_map_rule_cmd *cmd)
617 {
618 vector_set (route_set_vec, cmd);
619 }
620
621 /* Lookup rule command from match list. */
622 static struct route_map_rule_cmd *
623 route_map_lookup_match (const char *name)
624 {
625 unsigned int i;
626 struct route_map_rule_cmd *rule;
627
628 for (i = 0; i < vector_active (route_match_vec); i++)
629 if ((rule = vector_slot (route_match_vec, i)) != NULL)
630 if (strcmp (rule->str, name) == 0)
631 return rule;
632 return NULL;
633 }
634
635 /* Lookup rule command from set list. */
636 static struct route_map_rule_cmd *
637 route_map_lookup_set (const char *name)
638 {
639 unsigned int i;
640 struct route_map_rule_cmd *rule;
641
642 for (i = 0; i < vector_active (route_set_vec); i++)
643 if ((rule = vector_slot (route_set_vec, i)) != NULL)
644 if (strcmp (rule->str, name) == 0)
645 return rule;
646 return NULL;
647 }
648
649 /* Add match and set rule to rule list. */
650 static void
651 route_map_rule_add (struct route_map_rule_list *list,
652 struct route_map_rule *rule)
653 {
654 rule->next = NULL;
655 rule->prev = list->tail;
656 if (list->tail)
657 list->tail->next = rule;
658 else
659 list->head = rule;
660 list->tail = rule;
661 }
662
663 /* Delete rule from rule list. */
664 static void
665 route_map_rule_delete (struct route_map_rule_list *list,
666 struct route_map_rule *rule)
667 {
668 if (rule->cmd->func_free)
669 (*rule->cmd->func_free) (rule->value);
670
671 if (rule->rule_str)
672 XFREE (MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str);
673
674 if (rule->next)
675 rule->next->prev = rule->prev;
676 else
677 list->tail = rule->prev;
678 if (rule->prev)
679 rule->prev->next = rule->next;
680 else
681 list->head = rule->next;
682
683 XFREE (MTYPE_ROUTE_MAP_RULE, rule);
684 }
685
686 /* strcmp wrapper function which don't crush even argument is NULL. */
687 static int
688 rulecmp (const char *dst, const char *src)
689 {
690 if (dst == NULL)
691 {
692 if (src == NULL)
693 return 0;
694 else
695 return 1;
696 }
697 else
698 {
699 if (src == NULL)
700 return 1;
701 else
702 return strcmp (dst, src);
703 }
704 return 1;
705 }
706
707 /* Use this to return the already specified argument for this match. This is
708 * useful to get the specified argument with a route map match rule when the
709 * rule is being deleted and the argument is not provided.
710 */
711 const char *
712 route_map_get_match_arg(struct route_map_index *index, const char *match_name)
713 {
714 struct route_map_rule *rule;
715 struct route_map_rule_cmd *cmd;
716
717 /* First lookup rule for add match statement. */
718 cmd = route_map_lookup_match (match_name);
719 if (cmd == NULL)
720 return NULL;
721
722 for (rule = index->match_list.head; rule; rule = rule->next)
723 if (rule->cmd == cmd && rule->rule_str != NULL)
724 return (rule->rule_str);
725
726 return (NULL);
727 }
728
729 /* Add match statement to route map. */
730 int
731 route_map_add_match (struct route_map_index *index, const char *match_name,
732 const char *match_arg)
733 {
734 struct route_map_rule *rule;
735 struct route_map_rule *next;
736 struct route_map_rule_cmd *cmd;
737 void *compile;
738 int replaced = 0;
739
740 /* First lookup rule for add match statement. */
741 cmd = route_map_lookup_match (match_name);
742 if (cmd == NULL)
743 return RMAP_RULE_MISSING;
744
745 /* Next call compile function for this match statement. */
746 if (cmd->func_compile)
747 {
748 compile= (*cmd->func_compile)(match_arg);
749 if (compile == NULL)
750 return RMAP_COMPILE_ERROR;
751 }
752 else
753 compile = NULL;
754
755 /* If argument is completely same ignore it. */
756 for (rule = index->match_list.head; rule; rule = next)
757 {
758 next = rule->next;
759 if (rule->cmd == cmd)
760 {
761 route_map_rule_delete (&index->match_list, rule);
762 replaced = 1;
763 }
764 }
765
766 /* Add new route map match rule. */
767 rule = route_map_rule_new ();
768 rule->cmd = cmd;
769 rule->value = compile;
770 if (match_arg)
771 rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, match_arg);
772 else
773 rule->rule_str = NULL;
774
775 /* Add new route match rule to linked list. */
776 route_map_rule_add (&index->match_list, rule);
777
778 /* Execute event hook. */
779 if (route_map_master.event_hook)
780 {
781 (*route_map_master.event_hook) (replaced ?
782 RMAP_EVENT_MATCH_REPLACED:
783 RMAP_EVENT_MATCH_ADDED,
784 index->map->name);
785 route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
786 }
787
788 return 0;
789 }
790
791 /* Delete specified route match rule. */
792 int
793 route_map_delete_match (struct route_map_index *index, const char *match_name,
794 const char *match_arg)
795 {
796 struct route_map_rule *rule;
797 struct route_map_rule_cmd *cmd;
798
799 cmd = route_map_lookup_match (match_name);
800 if (cmd == NULL)
801 return 1;
802
803 for (rule = index->match_list.head; rule; rule = rule->next)
804 if (rule->cmd == cmd &&
805 (rulecmp (rule->rule_str, match_arg) == 0 || match_arg == NULL))
806 {
807 route_map_rule_delete (&index->match_list, rule);
808 /* Execute event hook. */
809 if (route_map_master.event_hook)
810 {
811 (*route_map_master.event_hook) (RMAP_EVENT_MATCH_DELETED,
812 index->map->name);
813 route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
814 }
815 return 0;
816 }
817 /* Can't find matched rule. */
818 return 1;
819 }
820
821 /* Add route-map set statement to the route map. */
822 int
823 route_map_add_set (struct route_map_index *index, const char *set_name,
824 const char *set_arg)
825 {
826 struct route_map_rule *rule;
827 struct route_map_rule *next;
828 struct route_map_rule_cmd *cmd;
829 void *compile;
830 int replaced = 0;
831
832 cmd = route_map_lookup_set (set_name);
833 if (cmd == NULL)
834 return RMAP_RULE_MISSING;
835
836 /* Next call compile function for this match statement. */
837 if (cmd->func_compile)
838 {
839 compile= (*cmd->func_compile)(set_arg);
840 if (compile == NULL)
841 return RMAP_COMPILE_ERROR;
842 }
843 else
844 compile = NULL;
845
846 /* Add by WJL. if old set command of same kind exist, delete it first
847 to ensure only one set command of same kind exist under a
848 route_map_index. */
849 for (rule = index->set_list.head; rule; rule = next)
850 {
851 next = rule->next;
852 if (rule->cmd == cmd)
853 {
854 route_map_rule_delete (&index->set_list, rule);
855 replaced = 1;
856 }
857 }
858
859 /* Add new route map match rule. */
860 rule = route_map_rule_new ();
861 rule->cmd = cmd;
862 rule->value = compile;
863 if (set_arg)
864 rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, set_arg);
865 else
866 rule->rule_str = NULL;
867
868 /* Add new route match rule to linked list. */
869 route_map_rule_add (&index->set_list, rule);
870
871 /* Execute event hook. */
872 if (route_map_master.event_hook)
873 {
874 (*route_map_master.event_hook) (replaced ?
875 RMAP_EVENT_SET_REPLACED:
876 RMAP_EVENT_SET_ADDED,
877 index->map->name);
878 route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
879 }
880 return 0;
881 }
882
883 /* Delete route map set rule. */
884 int
885 route_map_delete_set (struct route_map_index *index, const char *set_name,
886 const char *set_arg)
887 {
888 struct route_map_rule *rule;
889 struct route_map_rule_cmd *cmd;
890
891 cmd = route_map_lookup_set (set_name);
892 if (cmd == NULL)
893 return 1;
894
895 for (rule = index->set_list.head; rule; rule = rule->next)
896 if ((rule->cmd == cmd) &&
897 (rulecmp (rule->rule_str, set_arg) == 0 || set_arg == NULL))
898 {
899 route_map_rule_delete (&index->set_list, rule);
900 /* Execute event hook. */
901 if (route_map_master.event_hook)
902 {
903 (*route_map_master.event_hook) (RMAP_EVENT_SET_DELETED,
904 index->map->name);
905 route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
906 }
907 return 0;
908 }
909 /* Can't find matched rule. */
910 return 1;
911 }
912
913 /* Apply route map's each index to the object.
914
915 The matrix for a route-map looks like this:
916 (note, this includes the description for the "NEXT"
917 and "GOTO" frobs now
918
919 Match | No Match
920 |
921 permit action | cont
922 |
923 ------------------+---------------
924 |
925 deny deny | cont
926 |
927
928 action)
929 -Apply Set statements, accept route
930 -If Call statement is present jump to the specified route-map, if it
931 denies the route we finish.
932 -If NEXT is specified, goto NEXT statement
933 -If GOTO is specified, goto the first clause where pref > nextpref
934 -If nothing is specified, do as Cisco and finish
935 deny)
936 -Route is denied by route-map.
937 cont)
938 -Goto Next index
939
940 If we get no matches after we've processed all updates, then the route
941 is dropped too.
942
943 Some notes on the new "CALL", "NEXT" and "GOTO"
944 call WORD - If this clause is matched, then the set statements
945 are executed and then we jump to route-map 'WORD'. If
946 this route-map denies the route, we finish, in other case we
947 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
948 on-match next - If this clause is matched, then the set statements
949 are executed and then we drop through to the next clause
950 on-match goto n - If this clause is matched, then the set statments
951 are executed and then we goto the nth clause, or the
952 first clause greater than this. In order to ensure
953 route-maps *always* exit, you cannot jump backwards.
954 Sorry ;)
955
956 We need to make sure our route-map processing matches the above
957 */
958
959 static route_map_result_t
960 route_map_apply_match (struct route_map_rule_list *match_list,
961 struct prefix *prefix, route_map_object_t type,
962 void *object)
963 {
964 route_map_result_t ret = RMAP_NOMATCH;
965 struct route_map_rule *match;
966
967
968 /* Check all match rule and if there is no match rule, go to the
969 set statement. */
970 if (!match_list->head)
971 ret = RMAP_MATCH;
972 else
973 {
974 for (match = match_list->head; match; match = match->next)
975 {
976 /* Try each match statement in turn, If any do not return
977 RMAP_MATCH, return, otherwise continue on to next match
978 statement. All match statements must match for end-result
979 to be a match. */
980 ret = (*match->cmd->func_apply) (match->value, prefix,
981 type, object);
982 if (ret != RMAP_MATCH)
983 return ret;
984 }
985 }
986 return ret;
987 }
988
989 /* Apply route map to the object. */
990 route_map_result_t
991 route_map_apply (struct route_map *map, struct prefix *prefix,
992 route_map_object_t type, void *object)
993 {
994 static int recursion = 0;
995 int ret = 0;
996 struct route_map_index *index;
997 struct route_map_rule *set;
998
999 if (recursion > RMAP_RECURSION_LIMIT)
1000 {
1001 zlog (NULL, LOG_WARNING,
1002 "route-map recursion limit (%d) reached, discarding route",
1003 RMAP_RECURSION_LIMIT);
1004 recursion = 0;
1005 return RMAP_DENYMATCH;
1006 }
1007
1008 if (map == NULL)
1009 return RMAP_DENYMATCH;
1010
1011 for (index = map->head; index; index = index->next)
1012 {
1013 /* Apply this index. */
1014 ret = route_map_apply_match (&index->match_list, prefix, type, object);
1015
1016 /* Now we apply the matrix from above */
1017 if (ret == RMAP_NOMATCH)
1018 /* 'cont' from matrix - continue to next route-map sequence */
1019 continue;
1020 else if (ret == RMAP_MATCH)
1021 {
1022 if (index->type == RMAP_PERMIT)
1023 /* 'action' */
1024 {
1025 /* permit+match must execute sets */
1026 for (set = index->set_list.head; set; set = set->next)
1027 ret = (*set->cmd->func_apply) (set->value, prefix,
1028 type, object);
1029
1030 /* Call another route-map if available */
1031 if (index->nextrm)
1032 {
1033 struct route_map *nextrm =
1034 route_map_lookup_by_name (index->nextrm);
1035
1036 if (nextrm) /* Target route-map found, jump to it */
1037 {
1038 recursion++;
1039 ret = route_map_apply (nextrm, prefix, type, object);
1040 recursion--;
1041 }
1042
1043 /* If nextrm returned 'deny', finish. */
1044 if (ret == RMAP_DENYMATCH)
1045 return ret;
1046 }
1047
1048 switch (index->exitpolicy)
1049 {
1050 case RMAP_EXIT:
1051 return ret;
1052 case RMAP_NEXT:
1053 continue;
1054 case RMAP_GOTO:
1055 {
1056 /* Find the next clause to jump to */
1057 struct route_map_index *next = index->next;
1058 int nextpref = index->nextpref;
1059
1060 while (next && next->pref < nextpref)
1061 {
1062 index = next;
1063 next = next->next;
1064 }
1065 if (next == NULL)
1066 {
1067 /* No clauses match! */
1068 return ret;
1069 }
1070 }
1071 }
1072 }
1073 else if (index->type == RMAP_DENY)
1074 /* 'deny' */
1075 {
1076 return RMAP_DENYMATCH;
1077 }
1078 }
1079 }
1080 /* Finally route-map does not match at all. */
1081 return RMAP_DENYMATCH;
1082 }
1083
1084 void
1085 route_map_add_hook (void (*func) (const char *))
1086 {
1087 route_map_master.add_hook = func;
1088 }
1089
1090 void
1091 route_map_delete_hook (void (*func) (const char *))
1092 {
1093 route_map_master.delete_hook = func;
1094 }
1095
1096 void
1097 route_map_event_hook (void (*func) (route_map_event_t, const char *))
1098 {
1099 route_map_master.event_hook = func;
1100 }
1101
1102 void
1103 route_map_init (void)
1104 {
1105 /* Make vector for match and set. */
1106 route_match_vec = vector_init (1);
1107 route_set_vec = vector_init (1);
1108 route_map_master_hash = hash_create(route_map_hash_key_make, route_map_hash_cmp);
1109 }
1110
1111 void
1112 route_map_finish (void)
1113 {
1114 vector_free (route_match_vec);
1115 route_match_vec = NULL;
1116 vector_free (route_set_vec);
1117 route_set_vec = NULL;
1118 }
1119
1120 /* Routines for route map dependency lists and dependency processing */
1121 static int
1122 route_map_rmap_hash_cmp (const void *p1, const void *p2)
1123 {
1124 return (strcmp((const char *)p1, (const char *)p2) == 0);
1125 }
1126
1127 static int
1128 route_map_dep_hash_cmp (const void *p1, const void *p2)
1129 {
1130
1131 return (strcmp (((const struct route_map_dep *)p1)->dep_name, (const char *)p2) == 0);
1132 }
1133
1134 static void
1135 route_map_clear_reference(struct hash_backet *backet, void *arg)
1136 {
1137 struct route_map_dep *dep = (struct route_map_dep *)backet->data;
1138 char *rmap_name;
1139
1140 if (dep && arg)
1141 {
1142 rmap_name = (char *)hash_release(dep->dep_rmap_hash, (void *)arg);
1143 if (rmap_name)
1144 {
1145 XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
1146 }
1147 if (!dep->dep_rmap_hash->count)
1148 {
1149 dep = hash_release(dep->this_hash, (void *)dep->dep_name);
1150 hash_free(dep->dep_rmap_hash);
1151 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
1152 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
1153 }
1154 }
1155 }
1156
1157 static void
1158 route_map_clear_all_references (char *rmap_name)
1159 {
1160 int i;
1161
1162 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
1163 {
1164 hash_iterate(route_map_dep_hash[i], route_map_clear_reference,
1165 (void *)rmap_name);
1166 }
1167 }
1168
1169 static void *
1170 route_map_dep_hash_alloc(void *p)
1171 {
1172 char *dep_name = (char *)p;
1173 struct route_map_dep *dep_entry;
1174
1175 dep_entry = XCALLOC(MTYPE_ROUTE_MAP_DEP, sizeof(struct route_map_dep));
1176 dep_entry->dep_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
1177 dep_entry->dep_rmap_hash = hash_create(route_map_dep_hash_make_key,
1178 route_map_rmap_hash_cmp);
1179 dep_entry->this_hash = NULL;
1180
1181 return((void *)dep_entry);
1182 }
1183
1184 static void *
1185 route_map_name_hash_alloc(void *p)
1186 {
1187 return((void *)XSTRDUP(MTYPE_ROUTE_MAP_NAME, (const char *)p));
1188 }
1189
1190 static unsigned int
1191 route_map_dep_hash_make_key (void *p)
1192 {
1193 return (string_hash_make((char *)p));
1194 }
1195
1196 static void
1197 route_map_print_dependency (struct hash_backet *backet, void *data)
1198 {
1199 char *rmap_name = (char *)backet->data;
1200 char *dep_name = (char *)data;
1201
1202 if (rmap_name)
1203 zlog_debug("%s: Dependency for %s: %s", __FUNCTION__, dep_name, rmap_name);
1204 }
1205
1206 static int
1207 route_map_dep_update (struct hash *dephash, const char *dep_name,
1208 const char *rmap_name,
1209 route_map_event_t type)
1210 {
1211 struct route_map_dep *dep;
1212 char *ret_map_name;
1213 char *dname, *rname;
1214 int ret = 0;
1215
1216 dname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
1217 rname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_name);
1218
1219 switch (type)
1220 {
1221 case RMAP_EVENT_PLIST_ADDED:
1222 case RMAP_EVENT_CLIST_ADDED:
1223 case RMAP_EVENT_ECLIST_ADDED:
1224 case RMAP_EVENT_ASLIST_ADDED:
1225 case RMAP_EVENT_CALL_ADDED:
1226 case RMAP_EVENT_FILTER_ADDED:
1227 if (rmap_debug)
1228 zlog_debug("%s: Adding dependency for %s in %s", __FUNCTION__,
1229 dep_name, rmap_name);
1230 dep = (struct route_map_dep *) hash_get (dephash, dname,
1231 route_map_dep_hash_alloc);
1232 if (!dep) {
1233 ret = -1;
1234 goto out;
1235 }
1236
1237 if (!dep->this_hash)
1238 dep->this_hash = dephash;
1239
1240 hash_get(dep->dep_rmap_hash, rname, route_map_name_hash_alloc);
1241 break;
1242 case RMAP_EVENT_PLIST_DELETED:
1243 case RMAP_EVENT_CLIST_DELETED:
1244 case RMAP_EVENT_ECLIST_DELETED:
1245 case RMAP_EVENT_ASLIST_DELETED:
1246 case RMAP_EVENT_CALL_DELETED:
1247 case RMAP_EVENT_FILTER_DELETED:
1248 if (rmap_debug)
1249 zlog_debug("%s: Deleting dependency for %s in %s", __FUNCTION__,
1250 dep_name, rmap_name);
1251 dep = (struct route_map_dep *) hash_get (dephash, dname, NULL);
1252 if (!dep) {
1253 goto out;
1254 }
1255
1256 ret_map_name = (char *)hash_release(dep->dep_rmap_hash, rname);
1257 if (ret_map_name)
1258 XFREE(MTYPE_ROUTE_MAP_NAME, ret_map_name);
1259
1260 if (!dep->dep_rmap_hash->count)
1261 {
1262 dep = hash_release(dephash, dname);
1263 hash_free(dep->dep_rmap_hash);
1264 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
1265 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
1266 dep = NULL;
1267 }
1268 break;
1269 default:
1270 break;
1271 }
1272
1273 if (dep)
1274 {
1275 if (rmap_debug)
1276 hash_iterate (dep->dep_rmap_hash, route_map_print_dependency, dname);
1277 }
1278
1279 out:
1280 XFREE(MTYPE_ROUTE_MAP_NAME, rname);
1281 XFREE(MTYPE_ROUTE_MAP_NAME, dname);
1282 return ret;
1283 }
1284
1285 static struct hash *
1286 route_map_get_dep_hash (route_map_event_t event)
1287 {
1288 struct hash *upd8_hash = NULL;
1289
1290 switch (event)
1291 {
1292 case RMAP_EVENT_PLIST_ADDED:
1293 case RMAP_EVENT_PLIST_DELETED:
1294 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_PLIST];
1295 break;
1296 case RMAP_EVENT_CLIST_ADDED:
1297 case RMAP_EVENT_CLIST_DELETED:
1298 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_CLIST];
1299 break;
1300 case RMAP_EVENT_ECLIST_ADDED:
1301 case RMAP_EVENT_ECLIST_DELETED:
1302 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ECLIST];
1303 break;
1304 case RMAP_EVENT_ASLIST_ADDED:
1305 case RMAP_EVENT_ASLIST_DELETED:
1306 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ASPATH];
1307 break;
1308 case RMAP_EVENT_CALL_ADDED:
1309 case RMAP_EVENT_CALL_DELETED:
1310 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_RMAP];
1311 break;
1312 case RMAP_EVENT_FILTER_ADDED:
1313 case RMAP_EVENT_FILTER_DELETED:
1314 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_FILTER];
1315 break;
1316 default:
1317 upd8_hash = NULL;
1318 break;
1319 }
1320 return (upd8_hash);
1321 }
1322
1323 static void
1324 route_map_process_dependency (struct hash_backet *backet, void *data)
1325 {
1326 char *rmap_name;
1327 route_map_event_t type = (route_map_event_t )data;
1328
1329 rmap_name = (char *)backet->data;
1330
1331 if (rmap_name)
1332 {
1333 if (rmap_debug)
1334 zlog_debug("%s: Notifying %s of dependency", __FUNCTION__,
1335 rmap_name);
1336 if (route_map_master.event_hook)
1337 (*route_map_master.event_hook) (type, rmap_name);
1338 }
1339 }
1340
1341 void
1342 route_map_upd8_dependency (route_map_event_t type, const char *arg,
1343 const char *rmap_name)
1344 {
1345 struct hash *upd8_hash = NULL;
1346
1347 if ((upd8_hash = route_map_get_dep_hash(type)))
1348 route_map_dep_update (upd8_hash, arg, rmap_name, type);
1349 }
1350
1351 void
1352 route_map_notify_dependencies (const char *affected_name, route_map_event_t event)
1353 {
1354 struct route_map_dep *dep;
1355 struct hash *upd8_hash;
1356 char *name;
1357
1358 if (!affected_name)
1359 return;
1360
1361 name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, affected_name);
1362
1363 if ((upd8_hash = route_map_get_dep_hash(event)) == NULL)
1364 {
1365 XFREE (MTYPE_ROUTE_MAP_NAME, name);
1366 return;
1367 }
1368
1369 dep = (struct route_map_dep *)hash_get (upd8_hash, name,
1370 NULL);
1371 if (dep)
1372 {
1373 if (!dep->this_hash)
1374 dep->this_hash = upd8_hash;
1375
1376 hash_iterate (dep->dep_rmap_hash, route_map_process_dependency, (void *)event);
1377 }
1378
1379 XFREE (MTYPE_ROUTE_MAP_NAME, name);
1380 }
1381
1382 /* VTY related functions. */
1383 DEFUN (route_map,
1384 route_map_cmd,
1385 "route-map WORD (deny|permit) <1-65535>",
1386 "Create route-map or enter route-map command mode\n"
1387 "Route map tag\n"
1388 "Route map denies set operations\n"
1389 "Route map permits set operations\n"
1390 "Sequence to insert to/delete from existing route-map entry\n")
1391 {
1392 int permit;
1393 unsigned long pref;
1394 struct route_map *map;
1395 struct route_map_index *index;
1396 char *endptr = NULL;
1397
1398 /* Permit check. */
1399 if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
1400 permit = RMAP_PERMIT;
1401 else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
1402 permit = RMAP_DENY;
1403 else
1404 {
1405 vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
1406 return CMD_WARNING;
1407 }
1408
1409 /* Preference check. */
1410 pref = strtoul (argv[2], &endptr, 10);
1411 if (pref == ULONG_MAX || *endptr != '\0')
1412 {
1413 vty_out (vty, "the fourth field must be positive integer%s",
1414 VTY_NEWLINE);
1415 return CMD_WARNING;
1416 }
1417 if (pref == 0 || pref > 65535)
1418 {
1419 vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
1420 return CMD_WARNING;
1421 }
1422
1423 /* Get route map. */
1424 map = route_map_get (argv[0]);
1425 index = route_map_index_get (map, permit, pref);
1426
1427 vty->index = index;
1428 vty->node = RMAP_NODE;
1429 return CMD_SUCCESS;
1430 }
1431
1432 DEFUN (no_route_map_all,
1433 no_route_map_all_cmd,
1434 "no route-map WORD",
1435 NO_STR
1436 "Create route-map or enter route-map command mode\n"
1437 "Route map tag\n")
1438 {
1439 struct route_map *map;
1440
1441 map = route_map_lookup_by_name (argv[0]);
1442 if (map == NULL)
1443 {
1444 vty_out (vty, "%% Could not find route-map %s%s",
1445 argv[0], VTY_NEWLINE);
1446 return CMD_WARNING;
1447 }
1448
1449 route_map_delete (map);
1450
1451 return CMD_SUCCESS;
1452 }
1453
1454 DEFUN (no_route_map,
1455 no_route_map_cmd,
1456 "no route-map WORD (deny|permit) <1-65535>",
1457 NO_STR
1458 "Create route-map or enter route-map command mode\n"
1459 "Route map tag\n"
1460 "Route map denies set operations\n"
1461 "Route map permits set operations\n"
1462 "Sequence to insert to/delete from existing route-map entry\n")
1463 {
1464 int permit;
1465 unsigned long pref;
1466 struct route_map *map;
1467 struct route_map_index *index;
1468 char *endptr = NULL;
1469
1470 /* Permit check. */
1471 if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
1472 permit = RMAP_PERMIT;
1473 else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
1474 permit = RMAP_DENY;
1475 else
1476 {
1477 vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
1478 return CMD_WARNING;
1479 }
1480
1481 /* Preference. */
1482 pref = strtoul (argv[2], &endptr, 10);
1483 if (pref == ULONG_MAX || *endptr != '\0')
1484 {
1485 vty_out (vty, "the fourth field must be positive integer%s",
1486 VTY_NEWLINE);
1487 return CMD_WARNING;
1488 }
1489 if (pref == 0 || pref > 65535)
1490 {
1491 vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
1492 return CMD_WARNING;
1493 }
1494
1495 /* Existence check. */
1496 map = route_map_lookup_by_name (argv[0]);
1497 if (map == NULL)
1498 {
1499 vty_out (vty, "%% Could not find route-map %s%s",
1500 argv[0], VTY_NEWLINE);
1501 return CMD_WARNING;
1502 }
1503
1504 /* Lookup route map index. */
1505 index = route_map_index_lookup (map, permit, pref);
1506 if (index == NULL)
1507 {
1508 vty_out (vty, "%% Could not find route-map entry %s %s%s",
1509 argv[0], argv[2], VTY_NEWLINE);
1510 return CMD_WARNING;
1511 }
1512
1513 /* Delete index from route map. */
1514 route_map_index_delete (index, 1);
1515
1516 /* If this route rule is the last one, delete route map itself. */
1517 if (route_map_empty (map))
1518 route_map_delete (map);
1519
1520 return CMD_SUCCESS;
1521 }
1522
1523 DEFUN (rmap_onmatch_next,
1524 rmap_onmatch_next_cmd,
1525 "on-match next",
1526 "Exit policy on matches\n"
1527 "Next clause\n")
1528 {
1529 struct route_map_index *index;
1530
1531 index = vty->index;
1532
1533 if (index)
1534 index->exitpolicy = RMAP_NEXT;
1535
1536 return CMD_SUCCESS;
1537 }
1538
1539 DEFUN (no_rmap_onmatch_next,
1540 no_rmap_onmatch_next_cmd,
1541 "no on-match next",
1542 NO_STR
1543 "Exit policy on matches\n"
1544 "Next clause\n")
1545 {
1546 struct route_map_index *index;
1547
1548 index = vty->index;
1549
1550 if (index)
1551 index->exitpolicy = RMAP_EXIT;
1552
1553 return CMD_SUCCESS;
1554 }
1555
1556 DEFUN (rmap_onmatch_goto,
1557 rmap_onmatch_goto_cmd,
1558 "on-match goto <1-65535>",
1559 "Exit policy on matches\n"
1560 "Goto Clause number\n"
1561 "Number\n")
1562 {
1563 struct route_map_index *index = vty->index;
1564 int d = 0;
1565
1566 if (index)
1567 {
1568 if (argc == 1 && argv[0])
1569 VTY_GET_INTEGER_RANGE("route-map index", d, argv[0], 1, 65536);
1570 else
1571 d = index->pref + 1;
1572
1573 if (d <= index->pref)
1574 {
1575 /* Can't allow you to do that, Dave */
1576 vty_out (vty, "can't jump backwards in route-maps%s",
1577 VTY_NEWLINE);
1578 return CMD_WARNING;
1579 }
1580 else
1581 {
1582 index->exitpolicy = RMAP_GOTO;
1583 index->nextpref = d;
1584 }
1585 }
1586 return CMD_SUCCESS;
1587 }
1588
1589 DEFUN (no_rmap_onmatch_goto,
1590 no_rmap_onmatch_goto_cmd,
1591 "no on-match goto",
1592 NO_STR
1593 "Exit policy on matches\n"
1594 "Goto Clause number\n")
1595 {
1596 struct route_map_index *index;
1597
1598 index = vty->index;
1599
1600 if (index)
1601 index->exitpolicy = RMAP_EXIT;
1602
1603 return CMD_SUCCESS;
1604 }
1605
1606 /* Cisco/GNU Zebra compatible ALIASes for on-match next */
1607 ALIAS (rmap_onmatch_goto,
1608 rmap_continue_cmd,
1609 "continue",
1610 "Continue on a different entry within the route-map\n")
1611
1612 ALIAS (no_rmap_onmatch_goto,
1613 no_rmap_continue_cmd,
1614 "no continue",
1615 NO_STR
1616 "Continue on a different entry within the route-map\n")
1617
1618 /* GNU Zebra compatible */
1619 ALIAS (rmap_onmatch_goto,
1620 rmap_continue_seq_cmd,
1621 "continue <1-65535>",
1622 "Continue on a different entry within the route-map\n"
1623 "Route-map entry sequence number\n")
1624
1625 ALIAS (no_rmap_onmatch_goto,
1626 no_rmap_continue_seq,
1627 "no continue <1-65535>",
1628 NO_STR
1629 "Continue on a different entry within the route-map\n"
1630 "Route-map entry sequence number\n")
1631
1632 DEFUN (rmap_show_name,
1633 rmap_show_name_cmd,
1634 "show route-map [WORD]",
1635 SHOW_STR
1636 "route-map information\n"
1637 "route-map name\n")
1638 {
1639 const char *name = NULL;
1640 if (argc)
1641 name = argv[0];
1642 return vty_show_route_map (vty, name);
1643 }
1644
1645 ALIAS (rmap_onmatch_goto,
1646 rmap_continue_index_cmd,
1647 "continue <1-65536>",
1648 "Exit policy on matches\n"
1649 "Goto Clause number\n")
1650
1651 DEFUN (rmap_call,
1652 rmap_call_cmd,
1653 "call WORD",
1654 "Jump to another Route-Map after match+set\n"
1655 "Target route-map name\n")
1656 {
1657 struct route_map_index *index;
1658
1659 index = vty->index;
1660 if (index)
1661 {
1662 if (index->nextrm)
1663 {
1664 route_map_upd8_dependency (RMAP_EVENT_CALL_DELETED,
1665 index->nextrm,
1666 index->map->name);
1667 XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
1668 }
1669 index->nextrm = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[0]);
1670 }
1671
1672 /* Execute event hook. */
1673 route_map_upd8_dependency (RMAP_EVENT_CALL_ADDED,
1674 index->nextrm,
1675 index->map->name);
1676 return CMD_SUCCESS;
1677 }
1678
1679 DEFUN (no_rmap_call,
1680 no_rmap_call_cmd,
1681 "no call",
1682 NO_STR
1683 "Jump to another Route-Map after match+set\n")
1684 {
1685 struct route_map_index *index;
1686
1687 index = vty->index;
1688
1689 if (index->nextrm)
1690 {
1691 route_map_upd8_dependency (RMAP_EVENT_CALL_DELETED,
1692 index->nextrm,
1693 index->map->name);
1694 XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
1695 index->nextrm = NULL;
1696 }
1697
1698 return CMD_SUCCESS;
1699 }
1700
1701 DEFUN (rmap_description,
1702 rmap_description_cmd,
1703 "description .LINE",
1704 "Route-map comment\n"
1705 "Comment describing this route-map rule\n")
1706 {
1707 struct route_map_index *index;
1708
1709 index = vty->index;
1710 if (index)
1711 {
1712 if (index->description)
1713 XFREE (MTYPE_TMP, index->description);
1714 index->description = argv_concat (argv, argc, 0);
1715 }
1716 return CMD_SUCCESS;
1717 }
1718
1719 DEFUN (no_rmap_description,
1720 no_rmap_description_cmd,
1721 "no description",
1722 NO_STR
1723 "Route-map comment\n")
1724 {
1725 struct route_map_index *index;
1726
1727 index = vty->index;
1728 if (index)
1729 {
1730 if (index->description)
1731 XFREE (MTYPE_TMP, index->description);
1732 index->description = NULL;
1733 }
1734 return CMD_SUCCESS;
1735 }
1736
1737 /* Configuration write function. */
1738 static int
1739 route_map_config_write (struct vty *vty)
1740 {
1741 struct route_map *map;
1742 struct route_map_index *index;
1743 struct route_map_rule *rule;
1744 int first = 1;
1745 int write = 0;
1746
1747 for (map = route_map_master.head; map; map = map->next)
1748 for (index = map->head; index; index = index->next)
1749 {
1750 if (!first)
1751 vty_out (vty, "!%s", VTY_NEWLINE);
1752 else
1753 first = 0;
1754
1755 vty_out (vty, "route-map %s %s %d%s",
1756 map->name,
1757 route_map_type_str (index->type),
1758 index->pref, VTY_NEWLINE);
1759
1760 if (index->description)
1761 vty_out (vty, " description %s%s", index->description, VTY_NEWLINE);
1762
1763 for (rule = index->match_list.head; rule; rule = rule->next)
1764 vty_out (vty, " match %s %s%s", rule->cmd->str,
1765 rule->rule_str ? rule->rule_str : "",
1766 VTY_NEWLINE);
1767
1768 for (rule = index->set_list.head; rule; rule = rule->next)
1769 vty_out (vty, " set %s %s%s", rule->cmd->str,
1770 rule->rule_str ? rule->rule_str : "",
1771 VTY_NEWLINE);
1772 if (index->nextrm)
1773 vty_out (vty, " call %s%s", index->nextrm, VTY_NEWLINE);
1774 if (index->exitpolicy == RMAP_GOTO)
1775 vty_out (vty, " on-match goto %d%s", index->nextpref, VTY_NEWLINE);
1776 if (index->exitpolicy == RMAP_NEXT)
1777 vty_out (vty," on-match next%s", VTY_NEWLINE);
1778
1779 write++;
1780 }
1781 return write;
1782 }
1783
1784 /* Route map node structure. */
1785 static struct cmd_node rmap_node =
1786 {
1787 RMAP_NODE,
1788 "%s(config-route-map)# ",
1789 1
1790 };
1791
1792 static void
1793 route_map_init_dep_hashes (void)
1794 {
1795 int i;
1796
1797 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
1798 route_map_dep_hash[i] = hash_create(route_map_dep_hash_make_key,
1799 route_map_dep_hash_cmp);
1800 }
1801
1802 /* Initialization of route map vector. */
1803 void
1804 route_map_init_vty (void)
1805 {
1806 route_map_init_dep_hashes();
1807
1808 /* Install route map top node. */
1809 install_node (&rmap_node, route_map_config_write);
1810
1811 /* Install route map commands. */
1812 install_default (RMAP_NODE);
1813 install_element (CONFIG_NODE, &route_map_cmd);
1814 install_element (CONFIG_NODE, &no_route_map_cmd);
1815 install_element (CONFIG_NODE, &no_route_map_all_cmd);
1816
1817 /* Install the on-match stuff */
1818 install_element (RMAP_NODE, &route_map_cmd);
1819 install_element (RMAP_NODE, &rmap_onmatch_next_cmd);
1820 install_element (RMAP_NODE, &no_rmap_onmatch_next_cmd);
1821 install_element (RMAP_NODE, &rmap_onmatch_goto_cmd);
1822 install_element (RMAP_NODE, &no_rmap_onmatch_goto_cmd);
1823
1824 /* Install the continue stuff (ALIAS of on-match). */
1825 install_element (RMAP_NODE, &rmap_continue_cmd);
1826 install_element (RMAP_NODE, &no_rmap_continue_cmd);
1827 install_element (RMAP_NODE, &rmap_continue_index_cmd);
1828
1829 /* Install the call stuff. */
1830 install_element (RMAP_NODE, &rmap_call_cmd);
1831 install_element (RMAP_NODE, &no_rmap_call_cmd);
1832
1833 /* Install description commands. */
1834 install_element (RMAP_NODE, &rmap_description_cmd);
1835 install_element (RMAP_NODE, &no_rmap_description_cmd);
1836
1837 /* Install show command */
1838 install_element (ENABLE_NODE, &rmap_show_name_cmd);
1839 }