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