]> git.proxmox.com Git - mirror_frr.git/blob - lib/routemap.c
*: rebase vty_outln() -> master
[mirror_frr.git] / lib / routemap.c
1 /* Route map function.
2 * Copyright (C) 1998, 1999 Kunihiro Ishiguro
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include <zebra.h>
22
23 #include "linklist.h"
24 #include "memory.h"
25 #include "vector.h"
26 #include "prefix.h"
27 #include "vty.h"
28 #include "routemap.h"
29 #include "command.h"
30 #include "log.h"
31 #include "hash.h"
32 #include "libfrr.h"
33
34 DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP, "Route map")
35 DEFINE_MTYPE( LIB, ROUTE_MAP_NAME, "Route map name")
36 DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_INDEX, "Route map index")
37 DEFINE_MTYPE( LIB, ROUTE_MAP_RULE, "Route map rule")
38 DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_RULE_STR, "Route map rule str")
39 DEFINE_MTYPE( LIB, ROUTE_MAP_COMPILED, "Route map compiled")
40 DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_DEP, "Route map dependency")
41
42 DEFINE_QOBJ_TYPE(route_map_index)
43 DEFINE_QOBJ_TYPE(route_map)
44
45 /* Vector for route match rules. */
46 static vector route_match_vec;
47
48 /* Vector for route set rules. */
49 static vector route_set_vec;
50
51 struct route_map_match_set_hooks
52 {
53 /* match interface */
54 int (*match_interface) (struct vty *vty,
55 struct route_map_index *index,
56 const char *command,
57 const char *arg,
58 route_map_event_t type);
59
60 /* no match interface */
61 int (*no_match_interface) (struct vty *vty,
62 struct route_map_index *index,
63 const char *command,
64 const char *arg,
65 route_map_event_t type);
66
67 /* match ip address */
68 int (*match_ip_address) (struct vty *vty,
69 struct route_map_index *index,
70 const char *command,
71 const char *arg,
72 route_map_event_t type);
73
74 /* no match ip address */
75 int (*no_match_ip_address) (struct vty *vty,
76 struct route_map_index *index,
77 const char *command,
78 const char *arg,
79 route_map_event_t type);
80
81 /* match ip address prefix list */
82 int (*match_ip_address_prefix_list) (struct vty *vty,
83 struct route_map_index *index,
84 const char *command,
85 const char *arg,
86 route_map_event_t type);
87
88 /* no match ip address prefix list */
89 int (*no_match_ip_address_prefix_list) (struct vty *vty,
90 struct route_map_index *index,
91 const char *command,
92 const char *arg,
93 route_map_event_t type);
94
95 /* match ip next hop */
96 int (*match_ip_next_hop) (struct vty *vty,
97 struct route_map_index *index,
98 const char *command,
99 const char *arg,
100 route_map_event_t type);
101
102 /* no match ip next hop */
103 int (*no_match_ip_next_hop) (struct vty *vty,
104 struct route_map_index *index,
105 const char *command,
106 const char *arg,
107 route_map_event_t type);
108
109 /* match ip next hop prefix list */
110 int (*match_ip_next_hop_prefix_list) (struct vty *vty,
111 struct route_map_index *index,
112 const char *command,
113 const char *arg,
114 route_map_event_t type);
115
116 /* no match ip next hop prefix list */
117 int (*no_match_ip_next_hop_prefix_list) (struct vty *vty,
118 struct route_map_index *index,
119 const char *command,
120 const char *arg,
121 route_map_event_t type);
122
123 /* match ipv6 address */
124 int (*match_ipv6_address) (struct vty *vty,
125 struct route_map_index *index,
126 const char *command,
127 const char *arg,
128 route_map_event_t type);
129
130 /* no match ipv6 address */
131 int (*no_match_ipv6_address) (struct vty *vty,
132 struct route_map_index *index,
133 const char *command,
134 const char *arg,
135 route_map_event_t type);
136
137
138 /* match ipv6 address prefix list */
139 int (*match_ipv6_address_prefix_list) (struct vty *vty,
140 struct route_map_index *index,
141 const char *command,
142 const char *arg,
143 route_map_event_t type);
144
145 /* no match ipv6 address prefix list */
146 int (*no_match_ipv6_address_prefix_list) (struct vty *vty,
147 struct route_map_index *index,
148 const char *command,
149 const char *arg,
150 route_map_event_t type);
151
152 /* match metric */
153 int (*match_metric) (struct vty *vty,
154 struct route_map_index *index,
155 const char *command,
156 const char *arg,
157 route_map_event_t type);
158
159 /* no match metric */
160 int (*no_match_metric) (struct vty *vty,
161 struct route_map_index *index,
162 const char *command,
163 const char *arg,
164 route_map_event_t type);
165
166 /* match tag */
167 int (*match_tag) (struct vty *vty,
168 struct route_map_index *index,
169 const char *command,
170 const char *arg,
171 route_map_event_t type);
172
173 /* no match tag */
174 int (*no_match_tag) (struct vty *vty,
175 struct route_map_index *index,
176 const char *command,
177 const char *arg,
178 route_map_event_t type);
179
180 /* set ip nexthop */
181 int (*set_ip_nexthop) (struct vty *vty,
182 struct route_map_index *index,
183 const char *command,
184 const char *arg);
185
186 /* no set ip nexthop */
187 int (*no_set_ip_nexthop) (struct vty *vty,
188 struct route_map_index *index,
189 const char *command,
190 const char *arg);
191
192 /* set ipv6 nexthop local */
193 int (*set_ipv6_nexthop_local) (struct vty *vty,
194 struct route_map_index *index,
195 const char *command,
196 const char *arg);
197
198 /* no set ipv6 nexthop local */
199 int (*no_set_ipv6_nexthop_local) (struct vty *vty,
200 struct route_map_index *index,
201 const char *command,
202 const char *arg);
203
204 /* set metric */
205 int (*set_metric) (struct vty *vty,
206 struct route_map_index *index,
207 const char *command,
208 const char *arg);
209
210 /* no set metric */
211 int (*no_set_metric) (struct vty *vty,
212 struct route_map_index *index,
213 const char *command,
214 const char *arg);
215
216 /* set tag */
217 int (*set_tag) (struct vty *vty,
218 struct route_map_index *index,
219 const char *command,
220 const char *arg);
221
222 /* no set tag */
223 int (*no_set_tag) (struct vty *vty,
224 struct route_map_index *index,
225 const char *command,
226 const char *arg);
227
228 };
229
230 struct route_map_match_set_hooks rmap_match_set_hook;
231
232 /* match interface */
233 void
234 route_map_match_interface_hook (int (*func) (struct vty *vty,
235 struct route_map_index *index,
236 const char *command,
237 const char *arg,
238 route_map_event_t type))
239 {
240 rmap_match_set_hook.match_interface = func;
241 }
242
243 /* no match interface */
244 void
245 route_map_no_match_interface_hook (int (*func) (struct vty *vty,
246 struct route_map_index *index,
247 const char *command,
248 const char *arg,
249 route_map_event_t type))
250 {
251 rmap_match_set_hook.no_match_interface = func;
252 }
253
254 /* match ip address */
255 void
256 route_map_match_ip_address_hook (int (*func) (struct vty *vty,
257 struct route_map_index *index,
258 const char *command,
259 const char *arg,
260 route_map_event_t type))
261 {
262 rmap_match_set_hook.match_ip_address = func;
263 }
264
265 /* no match ip address */
266 void
267 route_map_no_match_ip_address_hook (int (*func) (struct vty *vty,
268 struct route_map_index *index,
269 const char *command,
270 const char *arg,
271 route_map_event_t type))
272 {
273 rmap_match_set_hook.no_match_ip_address = func;
274 }
275
276 /* match ip address prefix list */
277 void
278 route_map_match_ip_address_prefix_list_hook (int (*func) (struct vty *vty,
279 struct route_map_index *index,
280 const char *command,
281 const char *arg,
282 route_map_event_t type))
283 {
284 rmap_match_set_hook.match_ip_address_prefix_list = func;
285 }
286
287 /* no match ip address prefix list */
288 void
289 route_map_no_match_ip_address_prefix_list_hook (int (*func) (struct vty *vty,
290 struct route_map_index *index,
291 const char *command,
292 const char *arg,
293 route_map_event_t type))
294 {
295 rmap_match_set_hook.no_match_ip_address_prefix_list = func;
296 }
297
298 /* match ip next hop */
299 void
300 route_map_match_ip_next_hop_hook (int (*func) (struct vty *vty,
301 struct route_map_index *index,
302 const char *command,
303 const char *arg,
304 route_map_event_t type))
305 {
306 rmap_match_set_hook.match_ip_next_hop = func;
307 }
308
309 /* no match ip next hop */
310 void
311 route_map_no_match_ip_next_hop_hook (int (*func) (struct vty *vty,
312 struct route_map_index *index,
313 const char *command,
314 const char *arg,
315 route_map_event_t type))
316 {
317 rmap_match_set_hook.no_match_ip_next_hop = func;
318 }
319
320 /* match ip next hop prefix list */
321 void
322 route_map_match_ip_next_hop_prefix_list_hook (int (*func) (struct vty *vty,
323 struct route_map_index *index,
324 const char *command,
325 const char *arg,
326 route_map_event_t type))
327 {
328 rmap_match_set_hook.match_ip_next_hop_prefix_list = func;
329 }
330
331 /* no match ip next hop prefix list */
332 void
333 route_map_no_match_ip_next_hop_prefix_list_hook (int (*func) (struct vty *vty,
334 struct route_map_index *index,
335 const char *command,
336 const char *arg,
337 route_map_event_t type))
338 {
339 rmap_match_set_hook.no_match_ip_next_hop_prefix_list = func;
340 }
341
342 /* match ipv6 address */
343 void
344 route_map_match_ipv6_address_hook (int (*func) (struct vty *vty,
345 struct route_map_index *index,
346 const char *command,
347 const char *arg,
348 route_map_event_t type))
349 {
350 rmap_match_set_hook.match_ipv6_address = func;
351 }
352
353 /* no match ipv6 address */
354 void
355 route_map_no_match_ipv6_address_hook (int (*func) (struct vty *vty,
356 struct route_map_index *index,
357 const char *command,
358 const char *arg,
359 route_map_event_t type))
360 {
361 rmap_match_set_hook.no_match_ipv6_address = func;
362 }
363
364
365 /* match ipv6 address prefix list */
366 void
367 route_map_match_ipv6_address_prefix_list_hook (int (*func) (struct vty *vty,
368 struct route_map_index *index,
369 const char *command,
370 const char *arg,
371 route_map_event_t type))
372 {
373 rmap_match_set_hook.match_ipv6_address_prefix_list = func;
374 }
375
376 /* no match ipv6 address prefix list */
377 void
378 route_map_no_match_ipv6_address_prefix_list_hook (int (*func) (struct vty *vty,
379 struct route_map_index *index,
380 const char *command,
381 const char *arg,
382 route_map_event_t type))
383 {
384 rmap_match_set_hook.no_match_ipv6_address_prefix_list = func;
385 }
386
387 /* match metric */
388 void
389 route_map_match_metric_hook (int (*func) (struct vty *vty,
390 struct route_map_index *index,
391 const char *command,
392 const char *arg,
393 route_map_event_t type))
394 {
395 rmap_match_set_hook.match_metric = func;
396 }
397
398 /* no match metric */
399 void
400 route_map_no_match_metric_hook (int (*func) (struct vty *vty,
401 struct route_map_index *index,
402 const char *command,
403 const char *arg,
404 route_map_event_t type))
405 {
406 rmap_match_set_hook.no_match_metric = func;
407 }
408
409 /* match tag */
410 void
411 route_map_match_tag_hook (int (*func) (struct vty *vty,
412 struct route_map_index *index,
413 const char *command,
414 const char *arg,
415 route_map_event_t type))
416 {
417 rmap_match_set_hook.match_tag = func;
418 }
419
420 /* no match tag */
421 void
422 route_map_no_match_tag_hook (int (*func) (struct vty *vty,
423 struct route_map_index *index,
424 const char *command,
425 const char *arg,
426 route_map_event_t type))
427 {
428 rmap_match_set_hook.no_match_tag = func;
429 }
430
431 /* set ip nexthop */
432 void
433 route_map_set_ip_nexthop_hook (int (*func) (struct vty *vty,
434 struct route_map_index *index,
435 const char *command,
436 const char *arg))
437 {
438 rmap_match_set_hook.set_ip_nexthop = func;
439 }
440
441 /* no set ip nexthop */
442 void
443 route_map_no_set_ip_nexthop_hook (int (*func) (struct vty *vty,
444 struct route_map_index *index,
445 const char *command,
446 const char *arg))
447 {
448 rmap_match_set_hook.no_set_ip_nexthop = func;
449 }
450
451 /* set ipv6 nexthop local */
452 void
453 route_map_set_ipv6_nexthop_local_hook (int (*func) (struct vty *vty,
454 struct route_map_index *index,
455 const char *command,
456 const char *arg))
457 {
458 rmap_match_set_hook.set_ipv6_nexthop_local = func;
459 }
460
461 /* no set ipv6 nexthop local */
462 void
463 route_map_no_set_ipv6_nexthop_local_hook (int (*func) (struct vty *vty,
464 struct route_map_index *index,
465 const char *command,
466 const char *arg))
467 {
468 rmap_match_set_hook.no_set_ipv6_nexthop_local = func;
469 }
470
471 /* set metric */
472 void
473 route_map_set_metric_hook (int (*func) (struct vty *vty,
474 struct route_map_index *index,
475 const char *command,
476 const char *arg))
477 {
478 rmap_match_set_hook.set_metric = func;
479 }
480
481 /* no set metric */
482 void
483 route_map_no_set_metric_hook (int (*func) (struct vty *vty,
484 struct route_map_index *index,
485 const char *command,
486 const char *arg))
487 {
488 rmap_match_set_hook.no_set_metric = func;
489 }
490
491 /* set tag */
492 void
493 route_map_set_tag_hook (int (*func) (struct vty *vty,
494 struct route_map_index *index,
495 const char *command,
496 const char *arg))
497 {
498 rmap_match_set_hook.set_tag = func;
499 }
500
501 /* no set tag */
502 void
503 route_map_no_set_tag_hook (int (*func) (struct vty *vty,
504 struct route_map_index *index,
505 const char *command,
506 const char *arg))
507 {
508 rmap_match_set_hook.no_set_tag = func;
509 }
510
511 int
512 generic_match_add (struct vty *vty, struct route_map_index *index,
513 const char *command, const char *arg,
514 route_map_event_t type)
515 {
516 int ret;
517
518 ret = route_map_add_match (index, command, arg);
519 if (ret)
520 {
521 switch (ret)
522 {
523 case RMAP_RULE_MISSING:
524 vty_outln (vty, "%% [%s] Can't find rule.", frr_protonameinst);
525 return CMD_WARNING;
526 case RMAP_COMPILE_ERROR:
527 vty_outln (vty, "%% [%s] Argument form is unsupported or malformed.",
528 frr_protonameinst);
529 return CMD_WARNING;
530 }
531 }
532
533 if (type != RMAP_EVENT_MATCH_ADDED)
534 {
535 route_map_upd8_dependency (type, arg, index->map->name);
536 }
537 return CMD_SUCCESS;
538 }
539
540 int
541 generic_match_delete (struct vty *vty, struct route_map_index *index,
542 const char *command, const char *arg,
543 route_map_event_t type)
544 {
545 int ret;
546 char *dep_name = NULL;
547 const char *tmpstr;
548 char *rmap_name = NULL;
549
550 if (type != RMAP_EVENT_MATCH_DELETED)
551 {
552 /* ignore the mundane, the types without any dependency */
553 if (arg == NULL)
554 {
555 if ((tmpstr = route_map_get_match_arg(index, command)) != NULL)
556 dep_name = XSTRDUP(MTYPE_ROUTE_MAP_RULE, tmpstr);
557 }
558 else
559 {
560 dep_name = XSTRDUP(MTYPE_ROUTE_MAP_RULE, arg);
561 }
562 rmap_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, index->map->name);
563 }
564
565 ret = route_map_delete_match (index, command, dep_name);
566 if (ret)
567 {
568 switch (ret)
569 {
570 case RMAP_RULE_MISSING:
571 vty_outln (vty, "%% [%s] Can't find rule.", frr_protonameinst);
572 break;
573 case RMAP_COMPILE_ERROR:
574 vty_outln (vty, "%% [%s] Argument form is unsupported or malformed.",
575 frr_protonameinst);
576 break;
577 }
578 if (dep_name)
579 XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
580 if (rmap_name)
581 XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
582 return CMD_WARNING;
583 }
584
585 if (type != RMAP_EVENT_MATCH_DELETED && dep_name)
586 route_map_upd8_dependency(type, dep_name, rmap_name);
587
588 if (dep_name)
589 XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
590 if (rmap_name)
591 XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
592
593 return CMD_SUCCESS;
594 }
595
596 int
597 generic_set_add (struct vty *vty, struct route_map_index *index,
598 const char *command, const char *arg)
599 {
600 int ret;
601
602 ret = route_map_add_set (index, command, arg);
603 if (ret)
604 {
605 switch (ret)
606 {
607 case RMAP_RULE_MISSING:
608 vty_outln (vty, "%% [%s] Can't find rule.", frr_protonameinst);
609 return CMD_WARNING;
610 case RMAP_COMPILE_ERROR:
611 vty_outln (vty, "%% [%s] Argument form is unsupported or malformed.",
612 frr_protonameinst);
613 return CMD_WARNING;
614 }
615 }
616 return CMD_SUCCESS;
617 }
618
619 int
620 generic_set_delete (struct vty *vty, struct route_map_index *index,
621 const char *command, const char *arg)
622 {
623 int ret;
624
625 ret = route_map_delete_set (index, command, arg);
626 if (ret)
627 {
628 switch (ret)
629 {
630 case RMAP_RULE_MISSING:
631 vty_outln (vty, "%% [%s] Can't find rule.", frr_protonameinst);
632 return CMD_WARNING;
633 case RMAP_COMPILE_ERROR:
634 vty_outln (vty, "%% [%s] Argument form is unsupported or malformed.",
635 frr_protonameinst);
636 return CMD_WARNING;
637 }
638 }
639 return CMD_SUCCESS;
640 }
641
642
643 /* Route map rule. This rule has both `match' rule and `set' rule. */
644 struct route_map_rule
645 {
646 /* Rule type. */
647 struct route_map_rule_cmd *cmd;
648
649 /* For pretty printing. */
650 char *rule_str;
651
652 /* Pre-compiled match rule. */
653 void *value;
654
655 /* Linked list. */
656 struct route_map_rule *next;
657 struct route_map_rule *prev;
658 };
659
660 /* Making route map list. */
661 struct route_map_list
662 {
663 struct route_map *head;
664 struct route_map *tail;
665
666 void (*add_hook) (const char *);
667 void (*delete_hook) (const char *);
668 void (*event_hook) (route_map_event_t, const char *);
669 };
670
671 /* Master list of route map. */
672 static struct route_map_list route_map_master = { NULL, NULL, NULL, NULL, NULL };
673 struct hash *route_map_master_hash = NULL;
674
675 static unsigned int
676 route_map_hash_key_make (void *p)
677 {
678 const struct route_map *map = p;
679 return string_hash_make (map->name);
680 }
681
682 static int
683 route_map_hash_cmp(const void *p1, const void *p2)
684 {
685 const struct route_map *map1 = p1;
686 const struct route_map *map2 = p2;
687
688 if (map1->deleted == map2->deleted)
689 {
690 if (map1->name && map2->name)
691 {
692 if (!strcmp (map1->name, map2->name))
693 {
694 return 1;
695 }
696 }
697 else if (!map1->name && !map2->name)
698 {
699 return 1;
700 }
701 }
702
703 return 0;
704 }
705
706 enum route_map_upd8_type
707 {
708 ROUTE_MAP_ADD = 1,
709 ROUTE_MAP_DEL,
710 };
711
712 /* all possible route-map dependency types */
713 enum route_map_dep_type
714 {
715 ROUTE_MAP_DEP_RMAP = 1,
716 ROUTE_MAP_DEP_CLIST,
717 ROUTE_MAP_DEP_ECLIST,
718 ROUTE_MAP_DEP_LCLIST,
719 ROUTE_MAP_DEP_PLIST,
720 ROUTE_MAP_DEP_ASPATH,
721 ROUTE_MAP_DEP_FILTER,
722 ROUTE_MAP_DEP_MAX,
723 };
724
725 struct route_map_dep
726 {
727 char *dep_name;
728 struct hash *dep_rmap_hash;
729 struct hash *this_hash; /* ptr to the hash structure this is part of */
730 };
731
732 /* Hashes maintaining dependency between various sublists used by route maps */
733 struct hash *route_map_dep_hash[ROUTE_MAP_DEP_MAX];
734
735 static unsigned int route_map_dep_hash_make_key (void *p);
736 static int route_map_dep_hash_cmp (const void *p1, const void *p2);
737 static void route_map_clear_all_references (char *rmap_name);
738 static void route_map_rule_delete (struct route_map_rule_list *,
739 struct route_map_rule *);
740 static int rmap_debug = 0;
741
742 static void
743 route_map_index_delete (struct route_map_index *, int);
744
745 /* New route map allocation. Please note route map's name must be
746 specified. */
747 static struct route_map *
748 route_map_new (const char *name)
749 {
750 struct route_map *new;
751
752 new = XCALLOC (MTYPE_ROUTE_MAP, sizeof (struct route_map));
753 new->name = XSTRDUP (MTYPE_ROUTE_MAP_NAME, name);
754 QOBJ_REG (new, route_map);
755 return new;
756 }
757
758 /* Add new name to route_map. */
759 static struct route_map *
760 route_map_add (const char *name)
761 {
762 struct route_map *map;
763 struct route_map_list *list;
764
765 map = route_map_new (name);
766 list = &route_map_master;
767
768 /* Add map to the hash */
769 hash_get(route_map_master_hash, map, hash_alloc_intern);
770
771 /* Add new entry to the head of the list to match how it is added in the
772 * hash table. This is to ensure that if the same route-map has been
773 * created more than once and then marked for deletion (which can happen
774 * if prior deletions haven't completed as BGP hasn't yet done the
775 * route-map processing), the order of the entities is the same in both
776 * the list and the hash table. Otherwise, since there is nothing to
777 * distinguish between the two entries, the wrong entry could get freed.
778 * TODO: This needs to be re-examined to handle it better - e.g., revive
779 * a deleted entry if the route-map is created again.
780 */
781 map->prev = NULL;
782 map->next = list->head;
783 if (list->head)
784 list->head->prev = map;
785 list->head = map;
786 if (!list->tail)
787 list->tail = map;
788
789 /* Execute hook. */
790 if (route_map_master.add_hook)
791 {
792 (*route_map_master.add_hook) (name);
793 route_map_notify_dependencies(name, RMAP_EVENT_CALL_ADDED);
794 }
795 return map;
796 }
797
798 /* this is supposed to be called post processing by
799 * the delete hook function. Don't invoke delete_hook
800 * again in this routine.
801 */
802 static void
803 route_map_free_map (struct route_map *map)
804 {
805 struct route_map_list *list;
806 struct route_map_index *index;
807
808 if (map == NULL)
809 return;
810
811 while ((index = map->head) != NULL)
812 route_map_index_delete (index, 0);
813
814 list = &route_map_master;
815
816 QOBJ_UNREG (map);
817
818 if (map->next)
819 map->next->prev = map->prev;
820 else
821 list->tail = map->prev;
822
823 if (map->prev)
824 map->prev->next = map->next;
825 else
826 list->head = map->next;
827
828 hash_release(route_map_master_hash, map);
829 XFREE (MTYPE_ROUTE_MAP_NAME, map->name);
830 XFREE (MTYPE_ROUTE_MAP, map);
831 }
832
833 /* Route map delete from list. */
834 static void
835 route_map_delete (struct route_map *map)
836 {
837 struct route_map_index *index;
838 char *name;
839
840 while ((index = map->head) != NULL)
841 route_map_index_delete (index, 0);
842
843 name = map->name;
844 map->head = NULL;
845
846 /* Clear all dependencies */
847 route_map_clear_all_references(name);
848 map->deleted = 1;
849 /* Execute deletion hook. */
850 if (route_map_master.delete_hook)
851 {
852 (*route_map_master.delete_hook) (name);
853 route_map_notify_dependencies(name, RMAP_EVENT_CALL_DELETED);
854 }
855
856 if (!map->to_be_processed)
857 {
858 route_map_free_map (map);
859 }
860 }
861
862 /* Lookup route map by route map name string. */
863 struct route_map *
864 route_map_lookup_by_name (const char *name)
865 {
866 struct route_map *map;
867 struct route_map tmp_map;
868
869 if (!name)
870 return NULL;
871
872 // map.deleted is 0 via memset
873 memset(&tmp_map, 0, sizeof(struct route_map));
874 tmp_map.name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, name);
875 map = hash_lookup(route_map_master_hash, &tmp_map);
876 XFREE(MTYPE_ROUTE_MAP_NAME, tmp_map.name);
877 return map;
878 }
879
880 int
881 route_map_mark_updated (const char *name, int del_later)
882 {
883 struct route_map *map;
884 int ret = -1;
885 struct route_map tmp_map;
886
887 if (!name)
888 return (ret);
889
890 map = route_map_lookup_by_name(name);
891
892 /* If we did not find the routemap with deleted=0 try again
893 * with deleted=1
894 */
895 if (!map)
896 {
897 memset(&tmp_map, 0, sizeof(struct route_map));
898 tmp_map.name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, name);
899 tmp_map.deleted = 1;
900 map = hash_lookup(route_map_master_hash, &tmp_map);
901 XFREE(MTYPE_ROUTE_MAP_NAME, tmp_map.name);
902 }
903
904 if (map)
905 {
906 map->to_be_processed = 1;
907 ret = 0;
908 }
909
910 return(ret);
911 }
912
913 int
914 route_map_clear_updated (struct route_map *map)
915 {
916 int ret = -1;
917
918 if (map)
919 {
920 map->to_be_processed = 0;
921 if (map->deleted)
922 route_map_free_map(map);
923 }
924
925 return (ret);
926 }
927
928 /* Lookup route map. If there isn't route map create one and return
929 it. */
930 static struct route_map *
931 route_map_get (const char *name)
932 {
933 struct route_map *map;
934
935 map = route_map_lookup_by_name (name);
936 if (map == NULL)
937 map = route_map_add (name);
938
939 return map;
940 }
941
942 void
943 route_map_walk_update_list (int (*route_map_update_fn) (char *name))
944 {
945 struct route_map *node;
946 struct route_map *nnode = NULL;
947
948 for (node = route_map_master.head; node; node = nnode)
949 {
950 if (node->to_be_processed)
951 {
952 /* DD: Should we add any thread yield code here */
953 route_map_update_fn(node->name);
954 nnode = node->next;
955 route_map_clear_updated(node);
956 }
957 else
958 nnode = node->next;
959 }
960 }
961
962 /* Return route map's type string. */
963 static const char *
964 route_map_type_str (enum route_map_type type)
965 {
966 switch (type)
967 {
968 case RMAP_PERMIT:
969 return "permit";
970 break;
971 case RMAP_DENY:
972 return "deny";
973 break;
974 default:
975 return "";
976 break;
977 }
978 }
979
980 static int
981 route_map_empty (struct route_map *map)
982 {
983 if (map->head == NULL && map->tail == NULL)
984 return 1;
985 else
986 return 0;
987 }
988
989 /* show route-map */
990 static void
991 vty_show_route_map_entry (struct vty *vty, struct route_map *map)
992 {
993 struct route_map_index *index;
994 struct route_map_rule *rule;
995
996 vty_outln (vty, "%s:", frr_protonameinst);
997
998 for (index = map->head; index; index = index->next)
999 {
1000 vty_outln (vty, "route-map %s, %s, sequence %d",
1001 map->name, route_map_type_str (index->type),
1002 index->pref);
1003
1004 /* Description */
1005 if (index->description)
1006 vty_outln (vty, " Description:%s %s", VTYNL,
1007 index->description);
1008
1009 /* Match clauses */
1010 vty_outln (vty, " Match clauses:");
1011 for (rule = index->match_list.head; rule; rule = rule->next)
1012 vty_outln (vty, " %s %s",
1013 rule->cmd->str, rule->rule_str);
1014
1015 vty_outln (vty, " Set clauses:");
1016 for (rule = index->set_list.head; rule; rule = rule->next)
1017 vty_outln (vty, " %s %s",
1018 rule->cmd->str, rule->rule_str);
1019
1020 /* Call clause */
1021 vty_outln (vty, " Call clause:");
1022 if (index->nextrm)
1023 vty_outln (vty, " Call %s", index->nextrm);
1024
1025 /* Exit Policy */
1026 vty_outln (vty, " Action:");
1027 if (index->exitpolicy == RMAP_GOTO)
1028 vty_outln (vty, " Goto %d", index->nextpref);
1029 else if (index->exitpolicy == RMAP_NEXT)
1030 vty_outln (vty, " Continue to next entry");
1031 else if (index->exitpolicy == RMAP_EXIT)
1032 vty_outln (vty, " Exit routemap");
1033 }
1034 }
1035
1036 static int
1037 vty_show_route_map (struct vty *vty, const char *name)
1038 {
1039 struct route_map *map;
1040
1041 if (name)
1042 {
1043 map = route_map_lookup_by_name (name);
1044
1045 if (map)
1046 {
1047 vty_show_route_map_entry (vty, map);
1048 return CMD_SUCCESS;
1049 }
1050 else
1051 {
1052 vty_outln (vty, "%s: 'route-map %s' not found", frr_protonameinst,
1053 name);
1054 return CMD_SUCCESS;
1055 }
1056 }
1057 else
1058 {
1059 for (map = route_map_master.head; map; map = map->next)
1060 if (!map->deleted)
1061 vty_show_route_map_entry (vty, map);
1062 }
1063 return CMD_SUCCESS;
1064 }
1065
1066
1067 /* New route map allocation. Please note route map's name must be
1068 specified. */
1069 static struct route_map_index *
1070 route_map_index_new (void)
1071 {
1072 struct route_map_index *new;
1073
1074 new = XCALLOC (MTYPE_ROUTE_MAP_INDEX, sizeof (struct route_map_index));
1075 new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */
1076 QOBJ_REG (new, route_map_index);
1077 return new;
1078 }
1079
1080 /* Free route map index. */
1081 static void
1082 route_map_index_delete (struct route_map_index *index, int notify)
1083 {
1084 struct route_map_rule *rule;
1085
1086 QOBJ_UNREG (index);
1087
1088 /* Free route match. */
1089 while ((rule = index->match_list.head) != NULL)
1090 route_map_rule_delete (&index->match_list, rule);
1091
1092 /* Free route set. */
1093 while ((rule = index->set_list.head) != NULL)
1094 route_map_rule_delete (&index->set_list, rule);
1095
1096 /* Remove index from route map list. */
1097 if (index->next)
1098 index->next->prev = index->prev;
1099 else
1100 index->map->tail = index->prev;
1101
1102 if (index->prev)
1103 index->prev->next = index->next;
1104 else
1105 index->map->head = index->next;
1106
1107 /* Free 'char *nextrm' if not NULL */
1108 if (index->nextrm)
1109 XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
1110
1111 /* Execute event hook. */
1112 if (route_map_master.event_hook && notify)
1113 {
1114 (*route_map_master.event_hook) (RMAP_EVENT_INDEX_DELETED,
1115 index->map->name);
1116 route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
1117 }
1118 XFREE (MTYPE_ROUTE_MAP_INDEX, index);
1119 }
1120
1121 /* Lookup index from route map. */
1122 static struct route_map_index *
1123 route_map_index_lookup (struct route_map *map, enum route_map_type type,
1124 int pref)
1125 {
1126 struct route_map_index *index;
1127
1128 for (index = map->head; index; index = index->next)
1129 if ((index->type == type || type == RMAP_ANY)
1130 && index->pref == pref)
1131 return index;
1132 return NULL;
1133 }
1134
1135 /* Add new index to route map. */
1136 static struct route_map_index *
1137 route_map_index_add (struct route_map *map, enum route_map_type type,
1138 int pref)
1139 {
1140 struct route_map_index *index;
1141 struct route_map_index *point;
1142
1143 /* Allocate new route map inex. */
1144 index = route_map_index_new ();
1145 index->map = map;
1146 index->type = type;
1147 index->pref = pref;
1148
1149 /* Compare preference. */
1150 for (point = map->head; point; point = point->next)
1151 if (point->pref >= pref)
1152 break;
1153
1154 if (map->head == NULL)
1155 {
1156 map->head = map->tail = index;
1157 }
1158 else if (point == NULL)
1159 {
1160 index->prev = map->tail;
1161 map->tail->next = index;
1162 map->tail = index;
1163 }
1164 else if (point == map->head)
1165 {
1166 index->next = map->head;
1167 map->head->prev = index;
1168 map->head = index;
1169 }
1170 else
1171 {
1172 index->next = point;
1173 index->prev = point->prev;
1174 if (point->prev)
1175 point->prev->next = index;
1176 point->prev = index;
1177 }
1178
1179 /* Execute event hook. */
1180 if (route_map_master.event_hook)
1181 {
1182 (*route_map_master.event_hook) (RMAP_EVENT_INDEX_ADDED,
1183 map->name);
1184 route_map_notify_dependencies (map->name, RMAP_EVENT_CALL_ADDED);
1185 }
1186 return index;
1187 }
1188
1189 /* Get route map index. */
1190 static struct route_map_index *
1191 route_map_index_get (struct route_map *map, enum route_map_type type,
1192 int pref)
1193 {
1194 struct route_map_index *index;
1195
1196 index = route_map_index_lookup (map, RMAP_ANY, pref);
1197 if (index && index->type != type)
1198 {
1199 /* Delete index from route map. */
1200 route_map_index_delete (index, 1);
1201 index = NULL;
1202 }
1203 if (index == NULL)
1204 index = route_map_index_add (map, type, pref);
1205 return index;
1206 }
1207
1208 /* New route map rule */
1209 static struct route_map_rule *
1210 route_map_rule_new (void)
1211 {
1212 struct route_map_rule *new;
1213
1214 new = XCALLOC (MTYPE_ROUTE_MAP_RULE, sizeof (struct route_map_rule));
1215 return new;
1216 }
1217
1218 /* Install rule command to the match list. */
1219 void
1220 route_map_install_match (struct route_map_rule_cmd *cmd)
1221 {
1222 vector_set (route_match_vec, cmd);
1223 }
1224
1225 /* Install rule command to the set list. */
1226 void
1227 route_map_install_set (struct route_map_rule_cmd *cmd)
1228 {
1229 vector_set (route_set_vec, cmd);
1230 }
1231
1232 /* Lookup rule command from match list. */
1233 static struct route_map_rule_cmd *
1234 route_map_lookup_match (const char *name)
1235 {
1236 unsigned int i;
1237 struct route_map_rule_cmd *rule;
1238
1239 for (i = 0; i < vector_active (route_match_vec); i++)
1240 if ((rule = vector_slot (route_match_vec, i)) != NULL)
1241 if (strcmp (rule->str, name) == 0)
1242 return rule;
1243 return NULL;
1244 }
1245
1246 /* Lookup rule command from set list. */
1247 static struct route_map_rule_cmd *
1248 route_map_lookup_set (const char *name)
1249 {
1250 unsigned int i;
1251 struct route_map_rule_cmd *rule;
1252
1253 for (i = 0; i < vector_active (route_set_vec); i++)
1254 if ((rule = vector_slot (route_set_vec, i)) != NULL)
1255 if (strcmp (rule->str, name) == 0)
1256 return rule;
1257 return NULL;
1258 }
1259
1260 /* Add match and set rule to rule list. */
1261 static void
1262 route_map_rule_add (struct route_map_rule_list *list,
1263 struct route_map_rule *rule)
1264 {
1265 rule->next = NULL;
1266 rule->prev = list->tail;
1267 if (list->tail)
1268 list->tail->next = rule;
1269 else
1270 list->head = rule;
1271 list->tail = rule;
1272 }
1273
1274 /* Delete rule from rule list. */
1275 static void
1276 route_map_rule_delete (struct route_map_rule_list *list,
1277 struct route_map_rule *rule)
1278 {
1279 if (rule->cmd->func_free)
1280 (*rule->cmd->func_free) (rule->value);
1281
1282 if (rule->rule_str)
1283 XFREE (MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str);
1284
1285 if (rule->next)
1286 rule->next->prev = rule->prev;
1287 else
1288 list->tail = rule->prev;
1289 if (rule->prev)
1290 rule->prev->next = rule->next;
1291 else
1292 list->head = rule->next;
1293
1294 XFREE (MTYPE_ROUTE_MAP_RULE, rule);
1295 }
1296
1297 /* strcmp wrapper function which don't crush even argument is NULL. */
1298 static int
1299 rulecmp (const char *dst, const char *src)
1300 {
1301 if (dst == NULL)
1302 {
1303 if (src == NULL)
1304 return 0;
1305 else
1306 return 1;
1307 }
1308 else
1309 {
1310 if (src == NULL)
1311 return 1;
1312 else
1313 return strcmp (dst, src);
1314 }
1315 return 1;
1316 }
1317
1318 /* Use this to return the already specified argument for this match. This is
1319 * useful to get the specified argument with a route map match rule when the
1320 * rule is being deleted and the argument is not provided.
1321 */
1322 const char *
1323 route_map_get_match_arg(struct route_map_index *index, const char *match_name)
1324 {
1325 struct route_map_rule *rule;
1326 struct route_map_rule_cmd *cmd;
1327
1328 /* First lookup rule for add match statement. */
1329 cmd = route_map_lookup_match (match_name);
1330 if (cmd == NULL)
1331 return NULL;
1332
1333 for (rule = index->match_list.head; rule; rule = rule->next)
1334 if (rule->cmd == cmd && rule->rule_str != NULL)
1335 return (rule->rule_str);
1336
1337 return (NULL);
1338 }
1339
1340 /* Add match statement to route map. */
1341 int
1342 route_map_add_match (struct route_map_index *index, const char *match_name,
1343 const char *match_arg)
1344 {
1345 struct route_map_rule *rule;
1346 struct route_map_rule *next;
1347 struct route_map_rule_cmd *cmd;
1348 void *compile;
1349 int replaced = 0;
1350
1351 /* First lookup rule for add match statement. */
1352 cmd = route_map_lookup_match (match_name);
1353 if (cmd == NULL)
1354 return RMAP_RULE_MISSING;
1355
1356 /* Next call compile function for this match statement. */
1357 if (cmd->func_compile)
1358 {
1359 compile= (*cmd->func_compile)(match_arg);
1360 if (compile == NULL)
1361 return RMAP_COMPILE_ERROR;
1362 }
1363 else
1364 compile = NULL;
1365
1366 /* If argument is completely same ignore it. */
1367 for (rule = index->match_list.head; rule; rule = next)
1368 {
1369 next = rule->next;
1370 if (rule->cmd == cmd)
1371 {
1372 route_map_rule_delete (&index->match_list, rule);
1373 replaced = 1;
1374 }
1375 }
1376
1377 /* Add new route map match rule. */
1378 rule = route_map_rule_new ();
1379 rule->cmd = cmd;
1380 rule->value = compile;
1381 if (match_arg)
1382 rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, match_arg);
1383 else
1384 rule->rule_str = NULL;
1385
1386 /* Add new route match rule to linked list. */
1387 route_map_rule_add (&index->match_list, rule);
1388
1389 /* Execute event hook. */
1390 if (route_map_master.event_hook)
1391 {
1392 (*route_map_master.event_hook) (replaced ?
1393 RMAP_EVENT_MATCH_REPLACED:
1394 RMAP_EVENT_MATCH_ADDED,
1395 index->map->name);
1396 route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
1397 }
1398
1399 return 0;
1400 }
1401
1402 /* Delete specified route match rule. */
1403 int
1404 route_map_delete_match (struct route_map_index *index, const char *match_name,
1405 const char *match_arg)
1406 {
1407 struct route_map_rule *rule;
1408 struct route_map_rule_cmd *cmd;
1409
1410 cmd = route_map_lookup_match (match_name);
1411 if (cmd == NULL)
1412 return 1;
1413
1414 for (rule = index->match_list.head; rule; rule = rule->next)
1415 if (rule->cmd == cmd &&
1416 (rulecmp (rule->rule_str, match_arg) == 0 || match_arg == NULL))
1417 {
1418 route_map_rule_delete (&index->match_list, rule);
1419 /* Execute event hook. */
1420 if (route_map_master.event_hook)
1421 {
1422 (*route_map_master.event_hook) (RMAP_EVENT_MATCH_DELETED,
1423 index->map->name);
1424 route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
1425 }
1426 return 0;
1427 }
1428 /* Can't find matched rule. */
1429 return 1;
1430 }
1431
1432 /* Add route-map set statement to the route map. */
1433 int
1434 route_map_add_set (struct route_map_index *index, const char *set_name,
1435 const char *set_arg)
1436 {
1437 struct route_map_rule *rule;
1438 struct route_map_rule *next;
1439 struct route_map_rule_cmd *cmd;
1440 void *compile;
1441 int replaced = 0;
1442
1443 cmd = route_map_lookup_set (set_name);
1444 if (cmd == NULL)
1445 return RMAP_RULE_MISSING;
1446
1447 /* Next call compile function for this match statement. */
1448 if (cmd->func_compile)
1449 {
1450 compile= (*cmd->func_compile)(set_arg);
1451 if (compile == NULL)
1452 return RMAP_COMPILE_ERROR;
1453 }
1454 else
1455 compile = NULL;
1456
1457 /* Add by WJL. if old set command of same kind exist, delete it first
1458 to ensure only one set command of same kind exist under a
1459 route_map_index. */
1460 for (rule = index->set_list.head; rule; rule = next)
1461 {
1462 next = rule->next;
1463 if (rule->cmd == cmd)
1464 {
1465 route_map_rule_delete (&index->set_list, rule);
1466 replaced = 1;
1467 }
1468 }
1469
1470 /* Add new route map match rule. */
1471 rule = route_map_rule_new ();
1472 rule->cmd = cmd;
1473 rule->value = compile;
1474 if (set_arg)
1475 rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, set_arg);
1476 else
1477 rule->rule_str = NULL;
1478
1479 /* Add new route match rule to linked list. */
1480 route_map_rule_add (&index->set_list, rule);
1481
1482 /* Execute event hook. */
1483 if (route_map_master.event_hook)
1484 {
1485 (*route_map_master.event_hook) (replaced ?
1486 RMAP_EVENT_SET_REPLACED:
1487 RMAP_EVENT_SET_ADDED,
1488 index->map->name);
1489 route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
1490 }
1491 return 0;
1492 }
1493
1494 /* Delete route map set rule. */
1495 int
1496 route_map_delete_set (struct route_map_index *index, const char *set_name,
1497 const char *set_arg)
1498 {
1499 struct route_map_rule *rule;
1500 struct route_map_rule_cmd *cmd;
1501
1502 cmd = route_map_lookup_set (set_name);
1503 if (cmd == NULL)
1504 return 1;
1505
1506 for (rule = index->set_list.head; rule; rule = rule->next)
1507 if ((rule->cmd == cmd) &&
1508 (rulecmp (rule->rule_str, set_arg) == 0 || set_arg == NULL))
1509 {
1510 route_map_rule_delete (&index->set_list, rule);
1511 /* Execute event hook. */
1512 if (route_map_master.event_hook)
1513 {
1514 (*route_map_master.event_hook) (RMAP_EVENT_SET_DELETED,
1515 index->map->name);
1516 route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
1517 }
1518 return 0;
1519 }
1520 /* Can't find matched rule. */
1521 return 1;
1522 }
1523
1524 /* Apply route map's each index to the object.
1525
1526 The matrix for a route-map looks like this:
1527 (note, this includes the description for the "NEXT"
1528 and "GOTO" frobs now
1529
1530 Match | No Match
1531 |
1532 permit action | cont
1533 |
1534 ------------------+---------------
1535 |
1536 deny deny | cont
1537 |
1538
1539 action)
1540 -Apply Set statements, accept route
1541 -If Call statement is present jump to the specified route-map, if it
1542 denies the route we finish.
1543 -If NEXT is specified, goto NEXT statement
1544 -If GOTO is specified, goto the first clause where pref > nextpref
1545 -If nothing is specified, do as Cisco and finish
1546 deny)
1547 -Route is denied by route-map.
1548 cont)
1549 -Goto Next index
1550
1551 If we get no matches after we've processed all updates, then the route
1552 is dropped too.
1553
1554 Some notes on the new "CALL", "NEXT" and "GOTO"
1555 call WORD - If this clause is matched, then the set statements
1556 are executed and then we jump to route-map 'WORD'. If
1557 this route-map denies the route, we finish, in other case we
1558 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
1559 on-match next - If this clause is matched, then the set statements
1560 are executed and then we drop through to the next clause
1561 on-match goto n - If this clause is matched, then the set statments
1562 are executed and then we goto the nth clause, or the
1563 first clause greater than this. In order to ensure
1564 route-maps *always* exit, you cannot jump backwards.
1565 Sorry ;)
1566
1567 We need to make sure our route-map processing matches the above
1568 */
1569
1570 static route_map_result_t
1571 route_map_apply_match (struct route_map_rule_list *match_list,
1572 struct prefix *prefix, route_map_object_t type,
1573 void *object)
1574 {
1575 route_map_result_t ret = RMAP_NOMATCH;
1576 struct route_map_rule *match;
1577
1578
1579 /* Check all match rule and if there is no match rule, go to the
1580 set statement. */
1581 if (!match_list->head)
1582 ret = RMAP_MATCH;
1583 else
1584 {
1585 for (match = match_list->head; match; match = match->next)
1586 {
1587 /* Try each match statement in turn, If any do not return
1588 RMAP_MATCH, return, otherwise continue on to next match
1589 statement. All match statements must match for end-result
1590 to be a match. */
1591 ret = (*match->cmd->func_apply) (match->value, prefix,
1592 type, object);
1593 if (ret != RMAP_MATCH)
1594 return ret;
1595 }
1596 }
1597 return ret;
1598 }
1599
1600 /* Apply route map to the object. */
1601 route_map_result_t
1602 route_map_apply (struct route_map *map, struct prefix *prefix,
1603 route_map_object_t type, void *object)
1604 {
1605 static int recursion = 0;
1606 int ret = 0;
1607 struct route_map_index *index;
1608 struct route_map_rule *set;
1609
1610 if (recursion > RMAP_RECURSION_LIMIT)
1611 {
1612 zlog_warn("route-map recursion limit (%d) reached, discarding route",
1613 RMAP_RECURSION_LIMIT);
1614 recursion = 0;
1615 return RMAP_DENYMATCH;
1616 }
1617
1618 if (map == NULL)
1619 return RMAP_DENYMATCH;
1620
1621 for (index = map->head; index; index = index->next)
1622 {
1623 /* Apply this index. */
1624 ret = route_map_apply_match (&index->match_list, prefix, type, object);
1625
1626 /* Now we apply the matrix from above */
1627 if (ret == RMAP_NOMATCH)
1628 /* 'cont' from matrix - continue to next route-map sequence */
1629 continue;
1630 else if (ret == RMAP_MATCH)
1631 {
1632 if (index->type == RMAP_PERMIT)
1633 /* 'action' */
1634 {
1635 /* permit+match must execute sets */
1636 for (set = index->set_list.head; set; set = set->next)
1637 ret = (*set->cmd->func_apply) (set->value, prefix,
1638 type, object);
1639
1640 /* Call another route-map if available */
1641 if (index->nextrm)
1642 {
1643 struct route_map *nextrm =
1644 route_map_lookup_by_name (index->nextrm);
1645
1646 if (nextrm) /* Target route-map found, jump to it */
1647 {
1648 recursion++;
1649 ret = route_map_apply (nextrm, prefix, type, object);
1650 recursion--;
1651 }
1652
1653 /* If nextrm returned 'deny', finish. */
1654 if (ret == RMAP_DENYMATCH)
1655 return ret;
1656 }
1657
1658 switch (index->exitpolicy)
1659 {
1660 case RMAP_EXIT:
1661 return ret;
1662 case RMAP_NEXT:
1663 continue;
1664 case RMAP_GOTO:
1665 {
1666 /* Find the next clause to jump to */
1667 struct route_map_index *next = index->next;
1668 int nextpref = index->nextpref;
1669
1670 while (next && next->pref < nextpref)
1671 {
1672 index = next;
1673 next = next->next;
1674 }
1675 if (next == NULL)
1676 {
1677 /* No clauses match! */
1678 return ret;
1679 }
1680 }
1681 }
1682 }
1683 else if (index->type == RMAP_DENY)
1684 /* 'deny' */
1685 {
1686 return RMAP_DENYMATCH;
1687 }
1688 }
1689 }
1690 /* Finally route-map does not match at all. */
1691 return RMAP_DENYMATCH;
1692 }
1693
1694 void
1695 route_map_add_hook (void (*func) (const char *))
1696 {
1697 route_map_master.add_hook = func;
1698 }
1699
1700 void
1701 route_map_delete_hook (void (*func) (const char *))
1702 {
1703 route_map_master.delete_hook = func;
1704 }
1705
1706 void
1707 route_map_event_hook (void (*func) (route_map_event_t, const char *))
1708 {
1709 route_map_master.event_hook = func;
1710 }
1711
1712 /* Routines for route map dependency lists and dependency processing */
1713 static int
1714 route_map_rmap_hash_cmp (const void *p1, const void *p2)
1715 {
1716 return (strcmp((const char *)p1, (const char *)p2) == 0);
1717 }
1718
1719 static int
1720 route_map_dep_hash_cmp (const void *p1, const void *p2)
1721 {
1722
1723 return (strcmp (((const struct route_map_dep *)p1)->dep_name, (const char *)p2) == 0);
1724 }
1725
1726 static void
1727 route_map_clear_reference(struct hash_backet *backet, void *arg)
1728 {
1729 struct route_map_dep *dep = (struct route_map_dep *)backet->data;
1730 char *rmap_name;
1731
1732 if (dep && arg)
1733 {
1734 rmap_name = (char *)hash_release(dep->dep_rmap_hash, (void *)arg);
1735 if (rmap_name)
1736 {
1737 XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
1738 }
1739 if (!dep->dep_rmap_hash->count)
1740 {
1741 dep = hash_release(dep->this_hash, (void *)dep->dep_name);
1742 hash_free(dep->dep_rmap_hash);
1743 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
1744 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
1745 }
1746 }
1747 }
1748
1749 static void
1750 route_map_clear_all_references (char *rmap_name)
1751 {
1752 int i;
1753
1754 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
1755 {
1756 hash_iterate(route_map_dep_hash[i], route_map_clear_reference,
1757 (void *)rmap_name);
1758 }
1759 }
1760
1761 static void *
1762 route_map_dep_hash_alloc(void *p)
1763 {
1764 char *dep_name = (char *)p;
1765 struct route_map_dep *dep_entry;
1766
1767 dep_entry = XCALLOC(MTYPE_ROUTE_MAP_DEP, sizeof(struct route_map_dep));
1768 dep_entry->dep_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
1769 dep_entry->dep_rmap_hash = hash_create(route_map_dep_hash_make_key,
1770 route_map_rmap_hash_cmp);
1771 dep_entry->this_hash = NULL;
1772
1773 return((void *)dep_entry);
1774 }
1775
1776 static void *
1777 route_map_name_hash_alloc(void *p)
1778 {
1779 return((void *)XSTRDUP(MTYPE_ROUTE_MAP_NAME, (const char *)p));
1780 }
1781
1782 static unsigned int
1783 route_map_dep_hash_make_key (void *p)
1784 {
1785 return (string_hash_make((char *)p));
1786 }
1787
1788 static void
1789 route_map_print_dependency (struct hash_backet *backet, void *data)
1790 {
1791 char *rmap_name = (char *)backet->data;
1792 char *dep_name = (char *)data;
1793
1794 if (rmap_name)
1795 zlog_debug("%s: Dependency for %s: %s", __FUNCTION__, dep_name, rmap_name);
1796 }
1797
1798 static int
1799 route_map_dep_update (struct hash *dephash, const char *dep_name,
1800 const char *rmap_name,
1801 route_map_event_t type)
1802 {
1803 struct route_map_dep *dep = NULL;
1804 char *ret_map_name;
1805 char *dname, *rname;
1806 int ret = 0;
1807
1808 dname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
1809 rname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_name);
1810
1811 switch (type)
1812 {
1813 case RMAP_EVENT_PLIST_ADDED:
1814 case RMAP_EVENT_CLIST_ADDED:
1815 case RMAP_EVENT_ECLIST_ADDED:
1816 case RMAP_EVENT_ASLIST_ADDED:
1817 case RMAP_EVENT_LLIST_ADDED:
1818 case RMAP_EVENT_CALL_ADDED:
1819 case RMAP_EVENT_FILTER_ADDED:
1820 if (rmap_debug)
1821 zlog_debug("%s: Adding dependency for %s in %s", __FUNCTION__,
1822 dep_name, rmap_name);
1823 dep = (struct route_map_dep *) hash_get (dephash, dname,
1824 route_map_dep_hash_alloc);
1825 if (!dep) {
1826 ret = -1;
1827 goto out;
1828 }
1829
1830 if (!dep->this_hash)
1831 dep->this_hash = dephash;
1832
1833 hash_get(dep->dep_rmap_hash, rname, route_map_name_hash_alloc);
1834 break;
1835 case RMAP_EVENT_PLIST_DELETED:
1836 case RMAP_EVENT_CLIST_DELETED:
1837 case RMAP_EVENT_ECLIST_DELETED:
1838 case RMAP_EVENT_ASLIST_DELETED:
1839 case RMAP_EVENT_LLIST_DELETED:
1840 case RMAP_EVENT_CALL_DELETED:
1841 case RMAP_EVENT_FILTER_DELETED:
1842 if (rmap_debug)
1843 zlog_debug("%s: Deleting dependency for %s in %s", __FUNCTION__,
1844 dep_name, rmap_name);
1845 dep = (struct route_map_dep *) hash_get (dephash, dname, NULL);
1846 if (!dep) {
1847 goto out;
1848 }
1849
1850 ret_map_name = (char *)hash_release(dep->dep_rmap_hash, rname);
1851 if (ret_map_name)
1852 XFREE(MTYPE_ROUTE_MAP_NAME, ret_map_name);
1853
1854 if (!dep->dep_rmap_hash->count)
1855 {
1856 dep = hash_release(dephash, dname);
1857 hash_free(dep->dep_rmap_hash);
1858 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
1859 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
1860 dep = NULL;
1861 }
1862 break;
1863 default:
1864 break;
1865 }
1866
1867 if (dep)
1868 {
1869 if (rmap_debug)
1870 hash_iterate (dep->dep_rmap_hash, route_map_print_dependency, dname);
1871 }
1872
1873 out:
1874 XFREE(MTYPE_ROUTE_MAP_NAME, rname);
1875 XFREE(MTYPE_ROUTE_MAP_NAME, dname);
1876 return ret;
1877 }
1878
1879 static struct hash *
1880 route_map_get_dep_hash (route_map_event_t event)
1881 {
1882 struct hash *upd8_hash = NULL;
1883
1884 switch (event)
1885 {
1886 case RMAP_EVENT_PLIST_ADDED:
1887 case RMAP_EVENT_PLIST_DELETED:
1888 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_PLIST];
1889 break;
1890 case RMAP_EVENT_CLIST_ADDED:
1891 case RMAP_EVENT_CLIST_DELETED:
1892 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_CLIST];
1893 break;
1894 case RMAP_EVENT_ECLIST_ADDED:
1895 case RMAP_EVENT_ECLIST_DELETED:
1896 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ECLIST];
1897 break;
1898 case RMAP_EVENT_ASLIST_ADDED:
1899 case RMAP_EVENT_ASLIST_DELETED:
1900 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ASPATH];
1901 break;
1902 case RMAP_EVENT_LLIST_ADDED:
1903 case RMAP_EVENT_LLIST_DELETED:
1904 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_LCLIST];
1905 break;
1906 case RMAP_EVENT_CALL_ADDED:
1907 case RMAP_EVENT_CALL_DELETED:
1908 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_RMAP];
1909 break;
1910 case RMAP_EVENT_FILTER_ADDED:
1911 case RMAP_EVENT_FILTER_DELETED:
1912 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_FILTER];
1913 break;
1914 default:
1915 upd8_hash = NULL;
1916 break;
1917 }
1918 return (upd8_hash);
1919 }
1920
1921 static void
1922 route_map_process_dependency (struct hash_backet *backet, void *data)
1923 {
1924 char *rmap_name;
1925 route_map_event_t type = (route_map_event_t)(ptrdiff_t)data;
1926
1927 rmap_name = (char *)backet->data;
1928
1929 if (rmap_name)
1930 {
1931 if (rmap_debug)
1932 zlog_debug("%s: Notifying %s of dependency", __FUNCTION__,
1933 rmap_name);
1934 if (route_map_master.event_hook)
1935 (*route_map_master.event_hook) (type, rmap_name);
1936 }
1937 }
1938
1939 void
1940 route_map_upd8_dependency (route_map_event_t type, const char *arg,
1941 const char *rmap_name)
1942 {
1943 struct hash *upd8_hash = NULL;
1944
1945 if ((upd8_hash = route_map_get_dep_hash(type)))
1946 route_map_dep_update (upd8_hash, arg, rmap_name, type);
1947 }
1948
1949 void
1950 route_map_notify_dependencies (const char *affected_name, route_map_event_t event)
1951 {
1952 struct route_map_dep *dep;
1953 struct hash *upd8_hash;
1954 char *name;
1955
1956 if (!affected_name)
1957 return;
1958
1959 name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, affected_name);
1960
1961 if ((upd8_hash = route_map_get_dep_hash(event)) == NULL)
1962 {
1963 XFREE (MTYPE_ROUTE_MAP_NAME, name);
1964 return;
1965 }
1966
1967 dep = (struct route_map_dep *)hash_get (upd8_hash, name,
1968 NULL);
1969 if (dep)
1970 {
1971 if (!dep->this_hash)
1972 dep->this_hash = upd8_hash;
1973
1974 hash_iterate (dep->dep_rmap_hash, route_map_process_dependency, (void *)event);
1975 }
1976
1977 XFREE (MTYPE_ROUTE_MAP_NAME, name);
1978 }
1979
1980
1981 /* VTY related functions. */
1982 DEFUN (match_interface,
1983 match_interface_cmd,
1984 "match interface WORD",
1985 MATCH_STR
1986 "match first hop interface of route\n"
1987 "Interface name\n")
1988 {
1989 int idx_word = 2;
1990 VTY_DECLVAR_CONTEXT (route_map_index, index);
1991
1992 if (rmap_match_set_hook.match_interface)
1993 return rmap_match_set_hook.match_interface (vty, index, "interface", argv[idx_word]->arg, RMAP_EVENT_MATCH_ADDED);
1994 return CMD_SUCCESS;
1995 }
1996
1997 DEFUN (no_match_interface,
1998 no_match_interface_cmd,
1999 "no match interface [WORD]",
2000 NO_STR
2001 MATCH_STR
2002 "Match first hop interface of route\n"
2003 "Interface name\n")
2004 {
2005 char *iface = (argc == 4) ? argv[3]->arg : NULL;
2006 VTY_DECLVAR_CONTEXT (route_map_index, index);
2007
2008 if (rmap_match_set_hook.no_match_interface)
2009 return rmap_match_set_hook.no_match_interface (vty, index, "interface", iface, RMAP_EVENT_MATCH_DELETED);
2010 return CMD_SUCCESS;
2011 }
2012
2013
2014 DEFUN (match_ip_address,
2015 match_ip_address_cmd,
2016 "match ip address <(1-199)|(1300-2699)|WORD>",
2017 MATCH_STR
2018 IP_STR
2019 "Match address of route\n"
2020 "IP access-list number\n"
2021 "IP access-list number (expanded range)\n"
2022 "IP Access-list name\n")
2023 {
2024 int idx_acl = 3;
2025 VTY_DECLVAR_CONTEXT (route_map_index, index);
2026
2027 if (rmap_match_set_hook.match_ip_address)
2028 return rmap_match_set_hook.match_ip_address (vty, index, "ip address", argv[idx_acl]->arg,
2029 RMAP_EVENT_FILTER_ADDED);
2030 return CMD_SUCCESS;
2031 }
2032
2033
2034 DEFUN (no_match_ip_address,
2035 no_match_ip_address_cmd,
2036 "no match ip address [<(1-199)|(1300-2699)|WORD>]",
2037 NO_STR
2038 MATCH_STR
2039 IP_STR
2040 "Match address of route\n"
2041 "IP access-list number\n"
2042 "IP access-list number (expanded range)\n"
2043 "IP Access-list name\n")
2044 {
2045 int idx_word = 4;
2046 VTY_DECLVAR_CONTEXT (route_map_index, index);
2047
2048 if (rmap_match_set_hook.no_match_ip_address)
2049 {
2050 if (argc <= idx_word)
2051 return rmap_match_set_hook.no_match_ip_address (vty, index, "ip address", NULL,
2052 RMAP_EVENT_FILTER_DELETED);
2053 return rmap_match_set_hook.no_match_ip_address (vty, index, "ip address", argv[idx_word]->arg,
2054 RMAP_EVENT_FILTER_DELETED);
2055 }
2056 return CMD_SUCCESS;
2057 }
2058
2059
2060 DEFUN (match_ip_address_prefix_list,
2061 match_ip_address_prefix_list_cmd,
2062 "match ip address prefix-list WORD",
2063 MATCH_STR
2064 IP_STR
2065 "Match address of route\n"
2066 "Match entries of prefix-lists\n"
2067 "IP prefix-list name\n")
2068 {
2069 int idx_word = 4;
2070 VTY_DECLVAR_CONTEXT (route_map_index, index);
2071
2072 if (rmap_match_set_hook.match_ip_address_prefix_list)
2073 return rmap_match_set_hook.match_ip_address_prefix_list (vty, index, "ip address prefix-list",
2074 argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
2075 return CMD_SUCCESS;
2076 }
2077
2078
2079 DEFUN (no_match_ip_address_prefix_list,
2080 no_match_ip_address_prefix_list_cmd,
2081 "no match ip address prefix-list [WORD]",
2082 NO_STR
2083 MATCH_STR
2084 IP_STR
2085 "Match address of route\n"
2086 "Match entries of prefix-lists\n"
2087 "IP prefix-list name\n")
2088 {
2089 int idx_word = 5;
2090 VTY_DECLVAR_CONTEXT (route_map_index, index);
2091
2092 if (rmap_match_set_hook.no_match_ip_address_prefix_list)
2093 {
2094 if (argc <= idx_word)
2095 return rmap_match_set_hook.no_match_ip_address_prefix_list (vty, index, "ip address prefix-list",
2096 NULL, RMAP_EVENT_PLIST_DELETED);
2097 return rmap_match_set_hook.no_match_ip_address_prefix_list(vty, index, "ip address prefix-list",
2098 argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
2099 }
2100 return CMD_SUCCESS;
2101 }
2102
2103
2104 DEFUN (match_ip_next_hop,
2105 match_ip_next_hop_cmd,
2106 "match ip next-hop <(1-199)|(1300-2699)|WORD>",
2107 MATCH_STR
2108 IP_STR
2109 "Match next-hop address of route\n"
2110 "IP access-list number\n"
2111 "IP access-list number (expanded range)\n"
2112 "IP Access-list name\n")
2113 {
2114 int idx_acl = 3;
2115 VTY_DECLVAR_CONTEXT (route_map_index, index);
2116
2117 if (rmap_match_set_hook.match_ip_next_hop)
2118 return rmap_match_set_hook.match_ip_next_hop (vty, index, "ip next-hop", argv[idx_acl]->arg,
2119 RMAP_EVENT_FILTER_ADDED);
2120 return CMD_SUCCESS;
2121 }
2122
2123
2124 DEFUN (no_match_ip_next_hop,
2125 no_match_ip_next_hop_cmd,
2126 "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
2127 NO_STR
2128 MATCH_STR
2129 IP_STR
2130 "Match next-hop address of route\n"
2131 "IP access-list number\n"
2132 "IP access-list number (expanded range)\n"
2133 "IP Access-list name\n")
2134 {
2135 int idx_word = 4;
2136 VTY_DECLVAR_CONTEXT (route_map_index, index);
2137
2138 if (rmap_match_set_hook.no_match_ip_next_hop)
2139 {
2140 if (argc <= idx_word)
2141 return rmap_match_set_hook.no_match_ip_next_hop (vty, index, "ip next-hop", NULL,
2142 RMAP_EVENT_FILTER_DELETED);
2143 return rmap_match_set_hook.no_match_ip_next_hop (vty, index, "ip next-hop", argv[idx_word]->arg,
2144 RMAP_EVENT_FILTER_DELETED);
2145 }
2146 return CMD_SUCCESS;
2147 }
2148
2149
2150 DEFUN (match_ip_next_hop_prefix_list,
2151 match_ip_next_hop_prefix_list_cmd,
2152 "match ip next-hop prefix-list WORD",
2153 MATCH_STR
2154 IP_STR
2155 "Match next-hop address of route\n"
2156 "Match entries of prefix-lists\n"
2157 "IP prefix-list name\n")
2158 {
2159 int idx_word = 4;
2160 VTY_DECLVAR_CONTEXT (route_map_index, index);
2161
2162 if (rmap_match_set_hook.match_ip_next_hop_prefix_list)
2163 return rmap_match_set_hook.match_ip_next_hop_prefix_list (vty, index, "ip next-hop prefix-list",
2164 argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
2165 return CMD_SUCCESS;
2166 }
2167
2168 DEFUN (no_match_ip_next_hop_prefix_list,
2169 no_match_ip_next_hop_prefix_list_cmd,
2170 "no match ip next-hop prefix-list [WORD]",
2171 NO_STR
2172 MATCH_STR
2173 IP_STR
2174 "Match next-hop address of route\n"
2175 "Match entries of prefix-lists\n"
2176 "IP prefix-list name\n")
2177 {
2178 int idx_word = 5;
2179 VTY_DECLVAR_CONTEXT (route_map_index, index);
2180
2181 if (rmap_match_set_hook.no_match_ip_next_hop)
2182 {
2183 if (argc <= idx_word)
2184 return rmap_match_set_hook.no_match_ip_next_hop (vty, index, "ip next-hop prefix-list",
2185 NULL, RMAP_EVENT_PLIST_DELETED);
2186 return rmap_match_set_hook.no_match_ip_next_hop (vty, index, "ip next-hop prefix-list",
2187 argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
2188 }
2189 return CMD_SUCCESS;
2190 }
2191
2192
2193 DEFUN (match_ipv6_address,
2194 match_ipv6_address_cmd,
2195 "match ipv6 address WORD",
2196 MATCH_STR
2197 IPV6_STR
2198 "Match IPv6 address of route\n"
2199 "IPv6 access-list name\n")
2200 {
2201 int idx_word = 3;
2202 VTY_DECLVAR_CONTEXT (route_map_index, index);
2203
2204 if (rmap_match_set_hook.match_ipv6_address)
2205 return rmap_match_set_hook.match_ipv6_address (vty, index, "ipv6 address", argv[idx_word]->arg,
2206 RMAP_EVENT_FILTER_ADDED);
2207 return CMD_SUCCESS;
2208 }
2209
2210 DEFUN (no_match_ipv6_address,
2211 no_match_ipv6_address_cmd,
2212 "no match ipv6 address WORD",
2213 NO_STR
2214 MATCH_STR
2215 IPV6_STR
2216 "Match IPv6 address of route\n"
2217 "IPv6 access-list name\n")
2218 {
2219 int idx_word = 4;
2220 VTY_DECLVAR_CONTEXT (route_map_index, index);
2221
2222 if (rmap_match_set_hook.no_match_ipv6_address)
2223 return rmap_match_set_hook.no_match_ipv6_address (vty, index, "ipv6 address", argv[idx_word]->arg,
2224 RMAP_EVENT_FILTER_DELETED);
2225 return CMD_SUCCESS;
2226 }
2227
2228
2229 DEFUN (match_ipv6_address_prefix_list,
2230 match_ipv6_address_prefix_list_cmd,
2231 "match ipv6 address prefix-list WORD",
2232 MATCH_STR
2233 IPV6_STR
2234 "Match address of route\n"
2235 "Match entries of prefix-lists\n"
2236 "IP prefix-list name\n")
2237 {
2238 int idx_word = 4;
2239 VTY_DECLVAR_CONTEXT (route_map_index, index);
2240
2241 if (rmap_match_set_hook.match_ipv6_address_prefix_list)
2242 return rmap_match_set_hook.match_ipv6_address_prefix_list (vty, index, "ipv6 address prefix-list",
2243 argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
2244 return CMD_SUCCESS;
2245 }
2246
2247 DEFUN (no_match_ipv6_address_prefix_list,
2248 no_match_ipv6_address_prefix_list_cmd,
2249 "no match ipv6 address prefix-list WORD",
2250 NO_STR
2251 MATCH_STR
2252 IPV6_STR
2253 "Match address of route\n"
2254 "Match entries of prefix-lists\n"
2255 "IP prefix-list name\n")
2256 {
2257 int idx_word = 5;
2258 VTY_DECLVAR_CONTEXT (route_map_index, index);
2259
2260 if (rmap_match_set_hook.no_match_ipv6_address_prefix_list)
2261 return rmap_match_set_hook.no_match_ipv6_address_prefix_list(vty, index, "ipv6 address prefix-list",
2262 argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
2263 return CMD_SUCCESS;
2264 }
2265
2266
2267 DEFUN (match_metric,
2268 match_metric_cmd,
2269 "match metric (0-4294967295)",
2270 MATCH_STR
2271 "Match metric of route\n"
2272 "Metric value\n")
2273 {
2274 int idx_number = 2;
2275 VTY_DECLVAR_CONTEXT (route_map_index, index);
2276
2277 if (rmap_match_set_hook.match_metric)
2278 return rmap_match_set_hook.match_metric(vty, index, "metric", argv[idx_number]->arg,
2279 RMAP_EVENT_MATCH_ADDED);
2280 return CMD_SUCCESS;
2281 }
2282
2283
2284 DEFUN (no_match_metric,
2285 no_match_metric_cmd,
2286 "no match metric [(0-4294967295)]",
2287 NO_STR
2288 MATCH_STR
2289 "Match metric of route\n"
2290 "Metric value\n")
2291 {
2292 int idx_number = 3;
2293 VTY_DECLVAR_CONTEXT (route_map_index, index);
2294
2295 if (rmap_match_set_hook.no_match_metric)
2296 {
2297 if (argc <= idx_number)
2298 return rmap_match_set_hook.no_match_metric (vty, index, "metric",
2299 NULL, RMAP_EVENT_MATCH_DELETED);
2300 return rmap_match_set_hook.no_match_metric(vty, index, "metric",
2301 argv[idx_number]->arg,
2302 RMAP_EVENT_MATCH_DELETED);
2303 }
2304 return CMD_SUCCESS;
2305 }
2306
2307
2308 DEFUN (match_tag,
2309 match_tag_cmd,
2310 "match tag (1-4294967295)",
2311 MATCH_STR
2312 "Match tag of route\n"
2313 "Tag value\n")
2314 {
2315 int idx_number = 2;
2316 VTY_DECLVAR_CONTEXT (route_map_index, index);
2317
2318 if (rmap_match_set_hook.match_tag)
2319 return rmap_match_set_hook.match_tag(vty, index, "tag", argv[idx_number]->arg,
2320 RMAP_EVENT_MATCH_ADDED);
2321 return CMD_SUCCESS;
2322 }
2323
2324
2325 DEFUN (no_match_tag,
2326 no_match_tag_cmd,
2327 "no match tag [(1-4294967295)]",
2328 NO_STR
2329 MATCH_STR
2330 "Match tag of route\n"
2331 "Tag value\n")
2332 {
2333 VTY_DECLVAR_CONTEXT (route_map_index, index);
2334
2335 int idx = 0;
2336 char *arg = argv_find (argv, argc, "(1-4294967295)", &idx) ?
2337 argv[idx]->arg : NULL;
2338
2339 if (rmap_match_set_hook.no_match_tag)
2340 return rmap_match_set_hook.no_match_tag (vty, index, "tag", arg,
2341 RMAP_EVENT_MATCH_DELETED);
2342 return CMD_SUCCESS;
2343 }
2344
2345
2346 DEFUN (set_ip_nexthop,
2347 set_ip_nexthop_cmd,
2348 "set ip next-hop A.B.C.D",
2349 SET_STR
2350 IP_STR
2351 "Next hop address\n"
2352 "IP address of next hop\n")
2353 {
2354 int idx_ipv4 = 3;
2355 union sockunion su;
2356 int ret;
2357 VTY_DECLVAR_CONTEXT (route_map_index, index);
2358
2359 ret = str2sockunion (argv[idx_ipv4]->arg, &su);
2360 if (ret < 0)
2361 {
2362 vty_outln (vty, "%% Malformed nexthop address");
2363 return CMD_WARNING;
2364 }
2365 if (su.sin.sin_addr.s_addr == 0 ||
2366 IPV4_CLASS_DE(su.sin.sin_addr.s_addr))
2367 {
2368 vty_outln (vty,
2369 "%% nexthop address cannot be 0.0.0.0, multicast " "or reserved");
2370 return CMD_WARNING;
2371 }
2372
2373 if (rmap_match_set_hook.set_ip_nexthop)
2374 return rmap_match_set_hook.set_ip_nexthop(vty, index, "ip next-hop", argv[idx_ipv4]->arg);
2375 return CMD_SUCCESS;
2376 }
2377
2378
2379 DEFUN (no_set_ip_nexthop,
2380 no_set_ip_nexthop_cmd,
2381 "no set ip next-hop [<peer-address|A.B.C.D>]",
2382 NO_STR
2383 SET_STR
2384 IP_STR
2385 "Next hop address\n"
2386 "Use peer address (for BGP only)\n"
2387 "IP address of next hop\n")
2388 {
2389 int idx_peer = 4;
2390 VTY_DECLVAR_CONTEXT (route_map_index, index);
2391
2392 if (rmap_match_set_hook.no_set_ip_nexthop)
2393 {
2394 if (argc <= idx_peer)
2395 return rmap_match_set_hook.no_set_ip_nexthop (vty, index, "ip next-hop", NULL);
2396 return rmap_match_set_hook.no_set_ip_nexthop (vty, index, "ip next-hop", argv[idx_peer]->arg);
2397 }
2398 return CMD_SUCCESS;
2399 }
2400
2401
2402 DEFUN (set_ipv6_nexthop_local,
2403 set_ipv6_nexthop_local_cmd,
2404 "set ipv6 next-hop local X:X::X:X",
2405 SET_STR
2406 IPV6_STR
2407 "IPv6 next-hop address\n"
2408 "IPv6 local address\n"
2409 "IPv6 address of next hop\n")
2410 {
2411 int idx_ipv6 = 4;
2412 struct in6_addr addr;
2413 int ret;
2414 VTY_DECLVAR_CONTEXT (route_map_index, index);
2415
2416 ret = inet_pton (AF_INET6, argv[idx_ipv6]->arg, &addr);
2417 if (!ret)
2418 {
2419 vty_outln (vty, "%% Malformed nexthop address");
2420 return CMD_WARNING;
2421 }
2422 if (!IN6_IS_ADDR_LINKLOCAL(&addr))
2423 {
2424 vty_outln (vty, "%% Invalid link-local nexthop address");
2425 return CMD_WARNING;
2426 }
2427
2428 if (rmap_match_set_hook.set_ipv6_nexthop_local)
2429 return rmap_match_set_hook.set_ipv6_nexthop_local (vty, index, "ipv6 next-hop local", argv[idx_ipv6]->arg);
2430 return CMD_SUCCESS;
2431 }
2432
2433
2434 DEFUN (no_set_ipv6_nexthop_local,
2435 no_set_ipv6_nexthop_local_cmd,
2436 "no set ipv6 next-hop local [X:X::X:X]",
2437 NO_STR
2438 SET_STR
2439 IPV6_STR
2440 "IPv6 next-hop address\n"
2441 "IPv6 local address\n"
2442 "IPv6 address of next hop\n")
2443 {
2444 int idx_ipv6 = 5;
2445 VTY_DECLVAR_CONTEXT (route_map_index, index);
2446
2447 if (rmap_match_set_hook.no_set_ipv6_nexthop_local)
2448 {
2449 if (argc <= idx_ipv6)
2450 return rmap_match_set_hook.no_set_ipv6_nexthop_local (vty, index, "ipv6 next-hop local", NULL);
2451 return rmap_match_set_hook.no_set_ipv6_nexthop_local (vty, index, "ipv6 next-hop local", argv[5]->arg);
2452 }
2453 return CMD_SUCCESS;
2454 }
2455
2456 DEFUN (set_metric,
2457 set_metric_cmd,
2458 "set metric <(0-4294967295)|rtt|+rtt|-rtt|+metric|-metric>",
2459 SET_STR
2460 "Metric value for destination routing protocol\n"
2461 "Metric value\n"
2462 "Assign round trip time\n"
2463 "Add round trip time\n"
2464 "Subtract round trip time\n"
2465 "Add metric\n"
2466 "Subtract metric\n")
2467 {
2468 int idx_number = 2;
2469 VTY_DECLVAR_CONTEXT (route_map_index, index);
2470
2471 const char *pass = (argv[idx_number]->type == RANGE_TKN) ?
2472 argv[idx_number]->arg : argv[idx_number]->text;
2473
2474 if (rmap_match_set_hook.set_metric)
2475 return rmap_match_set_hook.set_metric (vty, index, "metric", pass);
2476 return CMD_SUCCESS;
2477 }
2478
2479
2480 DEFUN (no_set_metric,
2481 no_set_metric_cmd,
2482 "no set metric [(0-4294967295)]",
2483 NO_STR
2484 SET_STR
2485 "Metric value for destination routing protocol\n"
2486 "Metric value\n")
2487 {
2488 int idx_number = 3;
2489 VTY_DECLVAR_CONTEXT (route_map_index, index);
2490
2491 if (rmap_match_set_hook.no_set_metric)
2492 {
2493 if (argc <= idx_number)
2494 return rmap_match_set_hook.no_set_metric (vty, index, "metric", NULL);
2495 return rmap_match_set_hook.no_set_metric (vty, index, "metric", argv[idx_number]->arg);
2496 }
2497 return CMD_SUCCESS;
2498 }
2499
2500
2501 DEFUN (set_tag,
2502 set_tag_cmd,
2503 "set tag (1-4294967295)",
2504 SET_STR
2505 "Tag value for routing protocol\n"
2506 "Tag value\n")
2507 {
2508 VTY_DECLVAR_CONTEXT (route_map_index, index);
2509
2510 int idx_number = 2;
2511 if (rmap_match_set_hook.set_tag)
2512 return rmap_match_set_hook.set_tag (vty, index, "tag", argv[idx_number]->arg);
2513 return CMD_SUCCESS;
2514 }
2515
2516
2517 DEFUN (no_set_tag,
2518 no_set_tag_cmd,
2519 "no set tag [(1-4294967295)]",
2520 NO_STR
2521 SET_STR
2522 "Tag value for routing protocol\n"
2523 "Tag value\n")
2524 {
2525 VTY_DECLVAR_CONTEXT (route_map_index, index);
2526
2527 int idx_number = 3;
2528 if (rmap_match_set_hook.no_set_tag)
2529 {
2530 if (argc <= idx_number)
2531 return rmap_match_set_hook.no_set_tag (vty, index, "tag", NULL);
2532 return rmap_match_set_hook.no_set_tag (vty, index, "tag", argv[idx_number]->arg);
2533 }
2534 return CMD_SUCCESS;
2535 }
2536
2537
2538
2539 DEFUN_NOSH (route_map,
2540 route_map_cmd,
2541 "route-map WORD <deny|permit> (1-65535)",
2542 "Create route-map or enter route-map command mode\n"
2543 "Route map tag\n"
2544 "Route map denies set operations\n"
2545 "Route map permits set operations\n"
2546 "Sequence to insert to/delete from existing route-map entry\n")
2547 {
2548 int idx_word = 1;
2549 int idx_permit_deny = 2;
2550 int idx_number = 3;
2551 struct route_map *map;
2552 struct route_map_index *index;
2553 char *endptr = NULL;
2554 int permit = argv[idx_permit_deny]->arg[0] == 'p' ? RMAP_PERMIT : RMAP_DENY;
2555 unsigned long pref = strtoul (argv[idx_number]->arg, &endptr, 10);
2556 const char *mapname = argv[idx_word]->arg;
2557
2558 /* Get route map. */
2559 map = route_map_get (mapname);
2560 index = route_map_index_get (map, permit, pref);
2561
2562 VTY_PUSH_CONTEXT (RMAP_NODE, index);
2563 return CMD_SUCCESS;
2564 }
2565
2566 DEFUN (no_route_map_all,
2567 no_route_map_all_cmd,
2568 "no route-map WORD",
2569 NO_STR
2570 "Create route-map or enter route-map command mode\n"
2571 "Route map tag\n")
2572 {
2573 int idx_word = 2;
2574 const char *mapname = argv[idx_word]->arg;
2575 struct route_map *map;
2576
2577 map = route_map_lookup_by_name (mapname);
2578 if (map == NULL)
2579 {
2580 vty_outln (vty, "%% Could not find route-map %s", mapname);
2581 return CMD_WARNING;
2582 }
2583
2584 route_map_delete (map);
2585
2586 return CMD_SUCCESS;
2587 }
2588
2589 DEFUN (no_route_map,
2590 no_route_map_cmd,
2591 "no route-map WORD <deny|permit> (1-65535)",
2592 NO_STR
2593 "Create route-map or enter route-map command mode\n"
2594 "Route map tag\n"
2595 "Route map denies set operations\n"
2596 "Route map permits set operations\n"
2597 "Sequence to insert to/delete from existing route-map entry\n")
2598 {
2599 int idx_word = 2;
2600 int idx_permit_deny = 3;
2601 int idx_number = 4;
2602 struct route_map *map;
2603 struct route_map_index *index;
2604 char *endptr = NULL;
2605 int permit = strmatch (argv[idx_permit_deny]->text, "permit") ?
2606 RMAP_PERMIT : RMAP_DENY;
2607 const char *prefstr = argv[idx_number]->arg;
2608 const char *mapname = argv[idx_word]->arg;
2609 unsigned long pref = strtoul (prefstr, &endptr, 10);
2610
2611 /* Existence check. */
2612 map = route_map_lookup_by_name (mapname);
2613 if (map == NULL)
2614 {
2615 vty_outln (vty, "%% Could not find route-map %s", mapname);
2616 return CMD_WARNING;
2617 }
2618
2619 /* Lookup route map index. */
2620 index = route_map_index_lookup (map, permit, pref);
2621 if (index == NULL)
2622 {
2623 vty_outln (vty, "%% Could not find route-map entry %s %s",
2624 mapname, prefstr);
2625 return CMD_WARNING;
2626 }
2627
2628 /* Delete index from route map. */
2629 route_map_index_delete (index, 1);
2630
2631 /* If this route rule is the last one, delete route map itself. */
2632 if (route_map_empty (map))
2633 route_map_delete (map);
2634
2635 return CMD_SUCCESS;
2636 }
2637
2638 DEFUN (rmap_onmatch_next,
2639 rmap_onmatch_next_cmd,
2640 "on-match next",
2641 "Exit policy on matches\n"
2642 "Next clause\n")
2643 {
2644 struct route_map_index *index = VTY_GET_CONTEXT (route_map_index);
2645
2646 if (index)
2647 {
2648 if (index->type == RMAP_DENY)
2649 {
2650 /* Under a deny clause, match means it's finished. No need to set next */
2651 vty_outln (vty,"on-match next not supported under route-map deny");
2652 return CMD_WARNING;
2653 }
2654 index->exitpolicy = RMAP_NEXT;
2655 }
2656 return CMD_SUCCESS;
2657 }
2658
2659 DEFUN (no_rmap_onmatch_next,
2660 no_rmap_onmatch_next_cmd,
2661 "no on-match next",
2662 NO_STR
2663 "Exit policy on matches\n"
2664 "Next clause\n")
2665 {
2666 struct route_map_index *index = VTY_GET_CONTEXT (route_map_index);
2667
2668 if (index)
2669 index->exitpolicy = RMAP_EXIT;
2670
2671 return CMD_SUCCESS;
2672 }
2673
2674 DEFUN (rmap_onmatch_goto,
2675 rmap_onmatch_goto_cmd,
2676 "on-match goto (1-65535)",
2677 "Exit policy on matches\n"
2678 "Goto Clause number\n"
2679 "Number\n")
2680 {
2681 int idx = 0;
2682 char *num = argv_find (argv, argc, "(1-65535)", &idx) ? argv[idx]->arg : NULL;
2683
2684 struct route_map_index *index = VTY_GET_CONTEXT (route_map_index);
2685 int d = 0;
2686
2687 if (index)
2688 {
2689 if (index->type == RMAP_DENY)
2690 {
2691 /* Under a deny clause, match means it's finished. No need to go anywhere */
2692 vty_outln (vty,"on-match goto not supported under route-map deny");
2693 return CMD_WARNING;
2694 }
2695
2696 if (num)
2697 d = strtoul(num, NULL, 10);
2698 else
2699 d = index->pref + 1;
2700
2701 if (d <= index->pref)
2702 {
2703 /* Can't allow you to do that, Dave */
2704 vty_outln (vty, "can't jump backwards in route-maps");
2705 return CMD_WARNING;
2706 }
2707 else
2708 {
2709 index->exitpolicy = RMAP_GOTO;
2710 index->nextpref = d;
2711 }
2712 }
2713 return CMD_SUCCESS;
2714 }
2715
2716 DEFUN (no_rmap_onmatch_goto,
2717 no_rmap_onmatch_goto_cmd,
2718 "no on-match goto",
2719 NO_STR
2720 "Exit policy on matches\n"
2721 "Goto Clause number\n")
2722 {
2723 struct route_map_index *index = VTY_GET_CONTEXT (route_map_index);
2724
2725 if (index)
2726 index->exitpolicy = RMAP_EXIT;
2727
2728 return CMD_SUCCESS;
2729 }
2730
2731 /* Cisco/GNU Zebra compatibility aliases */
2732 /* ALIAS_FIXME */
2733 DEFUN (rmap_continue,
2734 rmap_continue_cmd,
2735 "continue (1-65535)",
2736 "Continue on a different entry within the route-map\n"
2737 "Route-map entry sequence number\n")
2738 {
2739 return rmap_onmatch_goto (self, vty, argc, argv);
2740 }
2741
2742 /* ALIAS_FIXME */
2743 DEFUN (no_rmap_continue,
2744 no_rmap_continue_cmd,
2745 "no continue [(1-65535)]",
2746 NO_STR
2747 "Continue on a different entry within the route-map\n"
2748 "Route-map entry sequence number\n")
2749 {
2750 return no_rmap_onmatch_goto (self, vty, argc, argv);
2751 }
2752
2753
2754 DEFUN (rmap_show_name,
2755 rmap_show_name_cmd,
2756 "show route-map [WORD]",
2757 SHOW_STR
2758 "route-map information\n"
2759 "route-map name\n")
2760 {
2761 int idx_word = 2;
2762 const char *name = (argc == 3) ? argv[idx_word]->arg : NULL;
2763 return vty_show_route_map (vty, name);
2764 }
2765
2766 DEFUN (rmap_call,
2767 rmap_call_cmd,
2768 "call WORD",
2769 "Jump to another Route-Map after match+set\n"
2770 "Target route-map name\n")
2771 {
2772 int idx_word = 1;
2773 struct route_map_index *index = VTY_GET_CONTEXT (route_map_index);
2774 const char *rmap = argv[idx_word]->arg;
2775
2776 assert(index);
2777
2778 if (index->nextrm)
2779 {
2780 route_map_upd8_dependency (RMAP_EVENT_CALL_DELETED,
2781 index->nextrm,
2782 index->map->name);
2783 XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
2784 }
2785 index->nextrm = XSTRDUP (MTYPE_ROUTE_MAP_NAME, rmap);
2786
2787 /* Execute event hook. */
2788 route_map_upd8_dependency (RMAP_EVENT_CALL_ADDED,
2789 index->nextrm,
2790 index->map->name);
2791 return CMD_SUCCESS;
2792 }
2793
2794 DEFUN (no_rmap_call,
2795 no_rmap_call_cmd,
2796 "no call",
2797 NO_STR
2798 "Jump to another Route-Map after match+set\n")
2799 {
2800 struct route_map_index *index = VTY_GET_CONTEXT (route_map_index);
2801
2802 if (index->nextrm)
2803 {
2804 route_map_upd8_dependency (RMAP_EVENT_CALL_DELETED,
2805 index->nextrm,
2806 index->map->name);
2807 XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
2808 index->nextrm = NULL;
2809 }
2810
2811 return CMD_SUCCESS;
2812 }
2813
2814 DEFUN (rmap_description,
2815 rmap_description_cmd,
2816 "description LINE...",
2817 "Route-map comment\n"
2818 "Comment describing this route-map rule\n")
2819 {
2820 int idx_line = 1;
2821 struct route_map_index *index = VTY_GET_CONTEXT (route_map_index);
2822
2823 if (index)
2824 {
2825 if (index->description)
2826 XFREE (MTYPE_TMP, index->description);
2827 index->description = argv_concat (argv, argc, idx_line);
2828 }
2829 return CMD_SUCCESS;
2830 }
2831
2832 DEFUN (no_rmap_description,
2833 no_rmap_description_cmd,
2834 "no description",
2835 NO_STR
2836 "Route-map comment\n")
2837 {
2838 struct route_map_index *index = VTY_GET_CONTEXT (route_map_index);
2839
2840 if (index)
2841 {
2842 if (index->description)
2843 XFREE (MTYPE_TMP, index->description);
2844 index->description = NULL;
2845 }
2846 return CMD_SUCCESS;
2847 }
2848
2849 /* Configuration write function. */
2850 static int
2851 route_map_config_write (struct vty *vty)
2852 {
2853 struct route_map *map;
2854 struct route_map_index *index;
2855 struct route_map_rule *rule;
2856 int first = 1;
2857 int write = 0;
2858
2859 for (map = route_map_master.head; map; map = map->next)
2860 for (index = map->head; index; index = index->next)
2861 {
2862 if (!first)
2863 vty_outln (vty, "!");
2864 else
2865 first = 0;
2866
2867 vty_outln (vty, "route-map %s %s %d",
2868 map->name,
2869 route_map_type_str (index->type),
2870 index->pref);
2871
2872 if (index->description)
2873 vty_outln (vty, " description %s", index->description);
2874
2875 for (rule = index->match_list.head; rule; rule = rule->next)
2876 vty_outln (vty, " match %s %s", rule->cmd->str,
2877 rule->rule_str ? rule->rule_str : "");
2878
2879 for (rule = index->set_list.head; rule; rule = rule->next)
2880 vty_outln (vty, " set %s %s", rule->cmd->str,
2881 rule->rule_str ? rule->rule_str : "");
2882 if (index->nextrm)
2883 vty_outln (vty, " call %s", index->nextrm);
2884 if (index->exitpolicy == RMAP_GOTO)
2885 vty_outln (vty, " on-match goto %d", index->nextpref);
2886 if (index->exitpolicy == RMAP_NEXT)
2887 vty_outln (vty," on-match next");
2888
2889 write++;
2890 }
2891 return write;
2892 }
2893
2894 /* Route map node structure. */
2895 static struct cmd_node rmap_node =
2896 {
2897 RMAP_NODE,
2898 "%s(config-route-map)# ",
2899 1
2900 };
2901
2902 /* Common route map rules */
2903
2904 void *
2905 route_map_rule_tag_compile (const char *arg)
2906 {
2907 unsigned long int tmp;
2908 char *endptr;
2909 route_tag_t *tag;
2910
2911 errno = 0;
2912 tmp = strtoul(arg, &endptr, 0);
2913 if (arg[0] == '\0' || *endptr != '\0' || errno || tmp > ROUTE_TAG_MAX)
2914 return NULL;
2915
2916 tag = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*tag));
2917 *tag = tmp;
2918
2919 return tag;
2920 }
2921
2922 void
2923 route_map_rule_tag_free (void *rule)
2924 {
2925 XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
2926 }
2927
2928 void
2929 route_map_finish (void)
2930 {
2931 int i;
2932
2933 vector_free (route_match_vec);
2934 route_match_vec = NULL;
2935 vector_free (route_set_vec);
2936 route_set_vec = NULL;
2937
2938 /* cleanup route_map */
2939 while (route_map_master.head)
2940 {
2941 struct route_map *map = route_map_master.head;
2942 map->to_be_processed = 0;
2943 route_map_delete (map);
2944 }
2945
2946 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
2947 {
2948 hash_free(route_map_dep_hash[i]);
2949 route_map_dep_hash[i] = NULL;
2950 }
2951
2952 hash_free (route_map_master_hash);
2953 route_map_master_hash = NULL;
2954 }
2955
2956 static void rmap_autocomplete(vector comps, struct cmd_token *token)
2957 {
2958 struct route_map *map;
2959
2960 for (map = route_map_master.head; map; map = map->next)
2961 vector_set (comps, XSTRDUP (MTYPE_COMPLETION, map->name));
2962 }
2963
2964 static const struct cmd_variable_handler rmap_var_handlers[] = {
2965 {
2966 /* "route-map WORD" */
2967 .varname = "route_map",
2968 .completions = rmap_autocomplete
2969 }, {
2970 .tokenname = "ROUTEMAP_NAME",
2971 .completions = rmap_autocomplete
2972 }, {
2973 .tokenname = "RMAP_NAME",
2974 .completions = rmap_autocomplete
2975 }, {
2976 .completions = NULL
2977 }
2978 };
2979
2980 /* Initialization of route map vector. */
2981 void
2982 route_map_init (void)
2983 {
2984 int i;
2985
2986 /* Make vector for match and set. */
2987 route_match_vec = vector_init (1);
2988 route_set_vec = vector_init (1);
2989 route_map_master_hash = hash_create(route_map_hash_key_make, route_map_hash_cmp);
2990
2991 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
2992 route_map_dep_hash[i] = hash_create(route_map_dep_hash_make_key,
2993 route_map_dep_hash_cmp);
2994
2995 cmd_variable_handler_register(rmap_var_handlers);
2996
2997 /* Install route map top node. */
2998 install_node (&rmap_node, route_map_config_write);
2999
3000 /* Install route map commands. */
3001 install_default (RMAP_NODE);
3002 install_element (CONFIG_NODE, &route_map_cmd);
3003 install_element (CONFIG_NODE, &no_route_map_cmd);
3004 install_element (CONFIG_NODE, &no_route_map_all_cmd);
3005
3006 /* Install the on-match stuff */
3007 install_element (RMAP_NODE, &route_map_cmd);
3008 install_element (RMAP_NODE, &rmap_onmatch_next_cmd);
3009 install_element (RMAP_NODE, &no_rmap_onmatch_next_cmd);
3010 install_element (RMAP_NODE, &rmap_onmatch_goto_cmd);
3011 install_element (RMAP_NODE, &no_rmap_onmatch_goto_cmd);
3012 install_element (RMAP_NODE, &rmap_continue_cmd);
3013 install_element (RMAP_NODE, &no_rmap_continue_cmd);
3014
3015 /* Install the continue stuff (ALIAS of on-match). */
3016
3017 /* Install the call stuff. */
3018 install_element (RMAP_NODE, &rmap_call_cmd);
3019 install_element (RMAP_NODE, &no_rmap_call_cmd);
3020
3021 /* Install description commands. */
3022 install_element (RMAP_NODE, &rmap_description_cmd);
3023 install_element (RMAP_NODE, &no_rmap_description_cmd);
3024
3025 /* Install show command */
3026 install_element (ENABLE_NODE, &rmap_show_name_cmd);
3027
3028 install_element (RMAP_NODE, &match_interface_cmd);
3029 install_element (RMAP_NODE, &no_match_interface_cmd);
3030
3031 install_element (RMAP_NODE, &match_ip_address_cmd);
3032 install_element (RMAP_NODE, &no_match_ip_address_cmd);
3033
3034 install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd);
3035 install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd);
3036
3037 install_element (RMAP_NODE, &match_ip_next_hop_cmd);
3038 install_element (RMAP_NODE, &no_match_ip_next_hop_cmd);
3039
3040 install_element (RMAP_NODE, &match_ip_next_hop_prefix_list_cmd);
3041 install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd);
3042
3043 install_element (RMAP_NODE, &match_ipv6_address_cmd);
3044 install_element (RMAP_NODE, &no_match_ipv6_address_cmd);
3045
3046 install_element (RMAP_NODE, &match_ipv6_address_prefix_list_cmd);
3047 install_element (RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd);
3048
3049 install_element (RMAP_NODE, &match_metric_cmd);
3050 install_element (RMAP_NODE, &no_match_metric_cmd);
3051
3052 install_element (RMAP_NODE, &match_tag_cmd);
3053 install_element (RMAP_NODE, &no_match_tag_cmd);
3054
3055 install_element (RMAP_NODE, &set_ip_nexthop_cmd);
3056 install_element (RMAP_NODE, &no_set_ip_nexthop_cmd);
3057
3058 install_element (RMAP_NODE, &set_ipv6_nexthop_local_cmd);
3059 install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_cmd);
3060
3061 install_element (RMAP_NODE, &set_metric_cmd);
3062 install_element (RMAP_NODE, &no_set_metric_cmd);
3063
3064 install_element (RMAP_NODE, &set_tag_cmd);
3065 install_element (RMAP_NODE, &no_set_tag_cmd);
3066
3067 }