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