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