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