]> git.proxmox.com Git - mirror_frr.git/blob - lib/routemap.c
*: reindent
[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 && (rulecmp(rule->rule_str, match_arg) == 0
1236 || match_arg == NULL)) {
1237 route_map_rule_delete(&index->match_list, rule);
1238 /* Execute event hook. */
1239 if (route_map_master.event_hook) {
1240 (*route_map_master.event_hook)(
1241 RMAP_EVENT_MATCH_DELETED,
1242 index->map->name);
1243 route_map_notify_dependencies(
1244 index->map->name,
1245 RMAP_EVENT_CALL_ADDED);
1246 }
1247 return 0;
1248 }
1249 /* Can't find matched rule. */
1250 return 1;
1251 }
1252
1253 /* Add route-map set statement to the route map. */
1254 int route_map_add_set(struct route_map_index *index, const char *set_name,
1255 const char *set_arg)
1256 {
1257 struct route_map_rule *rule;
1258 struct route_map_rule *next;
1259 struct route_map_rule_cmd *cmd;
1260 void *compile;
1261 int replaced = 0;
1262
1263 cmd = route_map_lookup_set(set_name);
1264 if (cmd == NULL)
1265 return RMAP_RULE_MISSING;
1266
1267 /* Next call compile function for this match statement. */
1268 if (cmd->func_compile) {
1269 compile = (*cmd->func_compile)(set_arg);
1270 if (compile == NULL)
1271 return RMAP_COMPILE_ERROR;
1272 } else
1273 compile = NULL;
1274
1275 /* Add by WJL. if old set command of same kind exist, delete it first
1276 to ensure only one set command of same kind exist under a
1277 route_map_index. */
1278 for (rule = index->set_list.head; rule; rule = next) {
1279 next = rule->next;
1280 if (rule->cmd == cmd) {
1281 route_map_rule_delete(&index->set_list, rule);
1282 replaced = 1;
1283 }
1284 }
1285
1286 /* Add new route map match rule. */
1287 rule = route_map_rule_new();
1288 rule->cmd = cmd;
1289 rule->value = compile;
1290 if (set_arg)
1291 rule->rule_str = XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR, set_arg);
1292 else
1293 rule->rule_str = NULL;
1294
1295 /* Add new route match rule to linked list. */
1296 route_map_rule_add(&index->set_list, rule);
1297
1298 /* Execute event hook. */
1299 if (route_map_master.event_hook) {
1300 (*route_map_master.event_hook)(replaced
1301 ? RMAP_EVENT_SET_REPLACED
1302 : RMAP_EVENT_SET_ADDED,
1303 index->map->name);
1304 route_map_notify_dependencies(index->map->name,
1305 RMAP_EVENT_CALL_ADDED);
1306 }
1307 return 0;
1308 }
1309
1310 /* Delete route map set rule. */
1311 int route_map_delete_set(struct route_map_index *index, const char *set_name,
1312 const char *set_arg)
1313 {
1314 struct route_map_rule *rule;
1315 struct route_map_rule_cmd *cmd;
1316
1317 cmd = route_map_lookup_set(set_name);
1318 if (cmd == NULL)
1319 return 1;
1320
1321 for (rule = index->set_list.head; rule; rule = rule->next)
1322 if ((rule->cmd == cmd) && (rulecmp(rule->rule_str, set_arg) == 0
1323 || set_arg == NULL)) {
1324 route_map_rule_delete(&index->set_list, rule);
1325 /* Execute event hook. */
1326 if (route_map_master.event_hook) {
1327 (*route_map_master.event_hook)(
1328 RMAP_EVENT_SET_DELETED,
1329 index->map->name);
1330 route_map_notify_dependencies(
1331 index->map->name,
1332 RMAP_EVENT_CALL_ADDED);
1333 }
1334 return 0;
1335 }
1336 /* Can't find matched rule. */
1337 return 1;
1338 }
1339
1340 /* Apply route map's each index to the object.
1341
1342 The matrix for a route-map looks like this:
1343 (note, this includes the description for the "NEXT"
1344 and "GOTO" frobs now
1345
1346 Match | No Match
1347 |
1348 permit action | cont
1349 |
1350 ------------------+---------------
1351 |
1352 deny deny | cont
1353 |
1354
1355 action)
1356 -Apply Set statements, accept route
1357 -If Call statement is present jump to the specified route-map, if it
1358 denies the route we finish.
1359 -If NEXT is specified, goto NEXT statement
1360 -If GOTO is specified, goto the first clause where pref > nextpref
1361 -If nothing is specified, do as Cisco and finish
1362 deny)
1363 -Route is denied by route-map.
1364 cont)
1365 -Goto Next index
1366
1367 If we get no matches after we've processed all updates, then the route
1368 is dropped too.
1369
1370 Some notes on the new "CALL", "NEXT" and "GOTO"
1371 call WORD - If this clause is matched, then the set statements
1372 are executed and then we jump to route-map 'WORD'. If
1373 this route-map denies the route, we finish, in other
1374 case we
1375 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
1376 on-match next - If this clause is matched, then the set statements
1377 are executed and then we drop through to the next clause
1378 on-match goto n - If this clause is matched, then the set statments
1379 are executed and then we goto the nth clause, or the
1380 first clause greater than this. In order to ensure
1381 route-maps *always* exit, you cannot jump backwards.
1382 Sorry ;)
1383
1384 We need to make sure our route-map processing matches the above
1385 */
1386
1387 static route_map_result_t
1388 route_map_apply_match(struct route_map_rule_list *match_list,
1389 struct prefix *prefix, route_map_object_t type,
1390 void *object)
1391 {
1392 route_map_result_t ret = RMAP_NOMATCH;
1393 struct route_map_rule *match;
1394
1395
1396 /* Check all match rule and if there is no match rule, go to the
1397 set statement. */
1398 if (!match_list->head)
1399 ret = RMAP_MATCH;
1400 else {
1401 for (match = match_list->head; match; match = match->next) {
1402 /* Try each match statement in turn, If any do not
1403 return
1404 RMAP_MATCH, return, otherwise continue on to next
1405 match
1406 statement. All match statements must match for
1407 end-result
1408 to be a match. */
1409 ret = (*match->cmd->func_apply)(match->value, prefix,
1410 type, object);
1411 if (ret != RMAP_MATCH)
1412 return ret;
1413 }
1414 }
1415 return ret;
1416 }
1417
1418 /* Apply route map to the object. */
1419 route_map_result_t route_map_apply(struct route_map *map, struct prefix *prefix,
1420 route_map_object_t type, void *object)
1421 {
1422 static int recursion = 0;
1423 int ret = 0;
1424 struct route_map_index *index;
1425 struct route_map_rule *set;
1426
1427 if (recursion > RMAP_RECURSION_LIMIT) {
1428 zlog_warn(
1429 "route-map recursion limit (%d) reached, discarding route",
1430 RMAP_RECURSION_LIMIT);
1431 recursion = 0;
1432 return RMAP_DENYMATCH;
1433 }
1434
1435 if (map == NULL)
1436 return RMAP_DENYMATCH;
1437
1438 for (index = map->head; index; index = index->next) {
1439 /* Apply this index. */
1440 ret = route_map_apply_match(&index->match_list, prefix, type,
1441 object);
1442
1443 /* Now we apply the matrix from above */
1444 if (ret == RMAP_NOMATCH)
1445 /* 'cont' from matrix - continue to next route-map
1446 * sequence */
1447 continue;
1448 else if (ret == RMAP_MATCH) {
1449 if (index->type == RMAP_PERMIT)
1450 /* 'action' */
1451 {
1452 /* permit+match must execute sets */
1453 for (set = index->set_list.head; set;
1454 set = set->next)
1455 ret = (*set->cmd->func_apply)(
1456 set->value, prefix, type,
1457 object);
1458
1459 /* Call another route-map if available */
1460 if (index->nextrm) {
1461 struct route_map *nextrm =
1462 route_map_lookup_by_name(
1463 index->nextrm);
1464
1465 if (nextrm) /* Target route-map found,
1466 jump to it */
1467 {
1468 recursion++;
1469 ret = route_map_apply(
1470 nextrm, prefix, type,
1471 object);
1472 recursion--;
1473 }
1474
1475 /* If nextrm returned 'deny', finish. */
1476 if (ret == RMAP_DENYMATCH)
1477 return ret;
1478 }
1479
1480 switch (index->exitpolicy) {
1481 case RMAP_EXIT:
1482 return ret;
1483 case RMAP_NEXT:
1484 continue;
1485 case RMAP_GOTO: {
1486 /* Find the next clause to jump to */
1487 struct route_map_index *next =
1488 index->next;
1489 int nextpref = index->nextpref;
1490
1491 while (next && next->pref < nextpref) {
1492 index = next;
1493 next = next->next;
1494 }
1495 if (next == NULL) {
1496 /* No clauses match! */
1497 return ret;
1498 }
1499 }
1500 }
1501 } else if (index->type == RMAP_DENY)
1502 /* 'deny' */
1503 {
1504 return RMAP_DENYMATCH;
1505 }
1506 }
1507 }
1508 /* Finally route-map does not match at all. */
1509 return RMAP_DENYMATCH;
1510 }
1511
1512 void route_map_add_hook(void (*func)(const char *))
1513 {
1514 route_map_master.add_hook = func;
1515 }
1516
1517 void route_map_delete_hook(void (*func)(const char *))
1518 {
1519 route_map_master.delete_hook = func;
1520 }
1521
1522 void route_map_event_hook(void (*func)(route_map_event_t, const char *))
1523 {
1524 route_map_master.event_hook = func;
1525 }
1526
1527 /* Routines for route map dependency lists and dependency processing */
1528 static int route_map_rmap_hash_cmp(const void *p1, const void *p2)
1529 {
1530 return (strcmp((const char *)p1, (const char *)p2) == 0);
1531 }
1532
1533 static int route_map_dep_hash_cmp(const void *p1, const void *p2)
1534 {
1535
1536 return (strcmp(((const struct route_map_dep *)p1)->dep_name,
1537 (const char *)p2)
1538 == 0);
1539 }
1540
1541 static void route_map_clear_reference(struct hash_backet *backet, void *arg)
1542 {
1543 struct route_map_dep *dep = (struct route_map_dep *)backet->data;
1544 char *rmap_name;
1545
1546 if (dep && arg) {
1547 rmap_name =
1548 (char *)hash_release(dep->dep_rmap_hash, (void *)arg);
1549 if (rmap_name) {
1550 XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
1551 }
1552 if (!dep->dep_rmap_hash->count) {
1553 dep = hash_release(dep->this_hash,
1554 (void *)dep->dep_name);
1555 hash_free(dep->dep_rmap_hash);
1556 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
1557 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
1558 }
1559 }
1560 }
1561
1562 static void route_map_clear_all_references(char *rmap_name)
1563 {
1564 int i;
1565
1566 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
1567 hash_iterate(route_map_dep_hash[i], route_map_clear_reference,
1568 (void *)rmap_name);
1569 }
1570 }
1571
1572 static void *route_map_dep_hash_alloc(void *p)
1573 {
1574 char *dep_name = (char *)p;
1575 struct route_map_dep *dep_entry;
1576
1577 dep_entry = XCALLOC(MTYPE_ROUTE_MAP_DEP, sizeof(struct route_map_dep));
1578 dep_entry->dep_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
1579 dep_entry->dep_rmap_hash = hash_create(route_map_dep_hash_make_key,
1580 route_map_rmap_hash_cmp, NULL);
1581 dep_entry->this_hash = NULL;
1582
1583 return ((void *)dep_entry);
1584 }
1585
1586 static void *route_map_name_hash_alloc(void *p)
1587 {
1588 return ((void *)XSTRDUP(MTYPE_ROUTE_MAP_NAME, (const char *)p));
1589 }
1590
1591 static unsigned int route_map_dep_hash_make_key(void *p)
1592 {
1593 return (string_hash_make((char *)p));
1594 }
1595
1596 static void route_map_print_dependency(struct hash_backet *backet, void *data)
1597 {
1598 char *rmap_name = (char *)backet->data;
1599 char *dep_name = (char *)data;
1600
1601 if (rmap_name)
1602 zlog_debug("%s: Dependency for %s: %s", __FUNCTION__, dep_name,
1603 rmap_name);
1604 }
1605
1606 static int route_map_dep_update(struct hash *dephash, const char *dep_name,
1607 const char *rmap_name, route_map_event_t type)
1608 {
1609 struct route_map_dep *dep = NULL;
1610 char *ret_map_name;
1611 char *dname, *rname;
1612 int ret = 0;
1613
1614 dname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
1615 rname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_name);
1616
1617 switch (type) {
1618 case RMAP_EVENT_PLIST_ADDED:
1619 case RMAP_EVENT_CLIST_ADDED:
1620 case RMAP_EVENT_ECLIST_ADDED:
1621 case RMAP_EVENT_ASLIST_ADDED:
1622 case RMAP_EVENT_LLIST_ADDED:
1623 case RMAP_EVENT_CALL_ADDED:
1624 case RMAP_EVENT_FILTER_ADDED:
1625 if (rmap_debug)
1626 zlog_debug("%s: Adding dependency for %s in %s",
1627 __FUNCTION__, dep_name, rmap_name);
1628 dep = (struct route_map_dep *)hash_get(
1629 dephash, dname, route_map_dep_hash_alloc);
1630 if (!dep) {
1631 ret = -1;
1632 goto out;
1633 }
1634
1635 if (!dep->this_hash)
1636 dep->this_hash = dephash;
1637
1638 hash_get(dep->dep_rmap_hash, rname, route_map_name_hash_alloc);
1639 break;
1640 case RMAP_EVENT_PLIST_DELETED:
1641 case RMAP_EVENT_CLIST_DELETED:
1642 case RMAP_EVENT_ECLIST_DELETED:
1643 case RMAP_EVENT_ASLIST_DELETED:
1644 case RMAP_EVENT_LLIST_DELETED:
1645 case RMAP_EVENT_CALL_DELETED:
1646 case RMAP_EVENT_FILTER_DELETED:
1647 if (rmap_debug)
1648 zlog_debug("%s: Deleting dependency for %s in %s",
1649 __FUNCTION__, dep_name, rmap_name);
1650 dep = (struct route_map_dep *)hash_get(dephash, dname, NULL);
1651 if (!dep) {
1652 goto out;
1653 }
1654
1655 ret_map_name = (char *)hash_release(dep->dep_rmap_hash, rname);
1656 if (ret_map_name)
1657 XFREE(MTYPE_ROUTE_MAP_NAME, ret_map_name);
1658
1659 if (!dep->dep_rmap_hash->count) {
1660 dep = hash_release(dephash, dname);
1661 hash_free(dep->dep_rmap_hash);
1662 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
1663 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
1664 dep = NULL;
1665 }
1666 break;
1667 default:
1668 break;
1669 }
1670
1671 if (dep) {
1672 if (rmap_debug)
1673 hash_iterate(dep->dep_rmap_hash,
1674 route_map_print_dependency, dname);
1675 }
1676
1677 out:
1678 XFREE(MTYPE_ROUTE_MAP_NAME, rname);
1679 XFREE(MTYPE_ROUTE_MAP_NAME, dname);
1680 return ret;
1681 }
1682
1683 static struct hash *route_map_get_dep_hash(route_map_event_t event)
1684 {
1685 struct hash *upd8_hash = NULL;
1686
1687 switch (event) {
1688 case RMAP_EVENT_PLIST_ADDED:
1689 case RMAP_EVENT_PLIST_DELETED:
1690 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_PLIST];
1691 break;
1692 case RMAP_EVENT_CLIST_ADDED:
1693 case RMAP_EVENT_CLIST_DELETED:
1694 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_CLIST];
1695 break;
1696 case RMAP_EVENT_ECLIST_ADDED:
1697 case RMAP_EVENT_ECLIST_DELETED:
1698 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ECLIST];
1699 break;
1700 case RMAP_EVENT_ASLIST_ADDED:
1701 case RMAP_EVENT_ASLIST_DELETED:
1702 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ASPATH];
1703 break;
1704 case RMAP_EVENT_LLIST_ADDED:
1705 case RMAP_EVENT_LLIST_DELETED:
1706 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_LCLIST];
1707 break;
1708 case RMAP_EVENT_CALL_ADDED:
1709 case RMAP_EVENT_CALL_DELETED:
1710 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_RMAP];
1711 break;
1712 case RMAP_EVENT_FILTER_ADDED:
1713 case RMAP_EVENT_FILTER_DELETED:
1714 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_FILTER];
1715 break;
1716 default:
1717 upd8_hash = NULL;
1718 break;
1719 }
1720 return (upd8_hash);
1721 }
1722
1723 static void route_map_process_dependency(struct hash_backet *backet, void *data)
1724 {
1725 char *rmap_name;
1726 route_map_event_t type = (route_map_event_t)(ptrdiff_t)data;
1727
1728 rmap_name = (char *)backet->data;
1729
1730 if (rmap_name) {
1731 if (rmap_debug)
1732 zlog_debug("%s: Notifying %s of dependency",
1733 __FUNCTION__, rmap_name);
1734 if (route_map_master.event_hook)
1735 (*route_map_master.event_hook)(type, rmap_name);
1736 }
1737 }
1738
1739 void route_map_upd8_dependency(route_map_event_t type, const char *arg,
1740 const char *rmap_name)
1741 {
1742 struct hash *upd8_hash = NULL;
1743
1744 if ((upd8_hash = route_map_get_dep_hash(type)))
1745 route_map_dep_update(upd8_hash, arg, rmap_name, type);
1746 }
1747
1748 void route_map_notify_dependencies(const char *affected_name,
1749 route_map_event_t event)
1750 {
1751 struct route_map_dep *dep;
1752 struct hash *upd8_hash;
1753 char *name;
1754
1755 if (!affected_name)
1756 return;
1757
1758 name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, affected_name);
1759
1760 if ((upd8_hash = route_map_get_dep_hash(event)) == NULL) {
1761 XFREE(MTYPE_ROUTE_MAP_NAME, name);
1762 return;
1763 }
1764
1765 dep = (struct route_map_dep *)hash_get(upd8_hash, name, NULL);
1766 if (dep) {
1767 if (!dep->this_hash)
1768 dep->this_hash = upd8_hash;
1769
1770 hash_iterate(dep->dep_rmap_hash, route_map_process_dependency,
1771 (void *)event);
1772 }
1773
1774 XFREE(MTYPE_ROUTE_MAP_NAME, name);
1775 }
1776
1777
1778 /* VTY related functions. */
1779 DEFUN (match_interface,
1780 match_interface_cmd,
1781 "match interface WORD",
1782 MATCH_STR
1783 "match first hop interface of route\n"
1784 "Interface name\n")
1785 {
1786 int idx_word = 2;
1787 VTY_DECLVAR_CONTEXT(route_map_index, index);
1788
1789 if (rmap_match_set_hook.match_interface)
1790 return rmap_match_set_hook.match_interface(
1791 vty, index, "interface", argv[idx_word]->arg,
1792 RMAP_EVENT_MATCH_ADDED);
1793 return CMD_SUCCESS;
1794 }
1795
1796 DEFUN (no_match_interface,
1797 no_match_interface_cmd,
1798 "no match interface [WORD]",
1799 NO_STR
1800 MATCH_STR
1801 "Match first hop interface of route\n"
1802 "Interface name\n")
1803 {
1804 char *iface = (argc == 4) ? argv[3]->arg : NULL;
1805 VTY_DECLVAR_CONTEXT(route_map_index, index);
1806
1807 if (rmap_match_set_hook.no_match_interface)
1808 return rmap_match_set_hook.no_match_interface(
1809 vty, index, "interface", iface,
1810 RMAP_EVENT_MATCH_DELETED);
1811 return CMD_SUCCESS;
1812 }
1813
1814
1815 DEFUN (match_ip_address,
1816 match_ip_address_cmd,
1817 "match ip address <(1-199)|(1300-2699)|WORD>",
1818 MATCH_STR
1819 IP_STR
1820 "Match address of route\n"
1821 "IP access-list number\n"
1822 "IP access-list number (expanded range)\n"
1823 "IP Access-list name\n")
1824 {
1825 int idx_acl = 3;
1826 VTY_DECLVAR_CONTEXT(route_map_index, index);
1827
1828 if (rmap_match_set_hook.match_ip_address)
1829 return rmap_match_set_hook.match_ip_address(
1830 vty, index, "ip address", argv[idx_acl]->arg,
1831 RMAP_EVENT_FILTER_ADDED);
1832 return CMD_SUCCESS;
1833 }
1834
1835
1836 DEFUN (no_match_ip_address,
1837 no_match_ip_address_cmd,
1838 "no match ip address [<(1-199)|(1300-2699)|WORD>]",
1839 NO_STR
1840 MATCH_STR
1841 IP_STR
1842 "Match address of route\n"
1843 "IP access-list number\n"
1844 "IP access-list number (expanded range)\n"
1845 "IP Access-list name\n")
1846 {
1847 int idx_word = 4;
1848 VTY_DECLVAR_CONTEXT(route_map_index, index);
1849
1850 if (rmap_match_set_hook.no_match_ip_address) {
1851 if (argc <= idx_word)
1852 return rmap_match_set_hook.no_match_ip_address(
1853 vty, index, "ip address", NULL,
1854 RMAP_EVENT_FILTER_DELETED);
1855 return rmap_match_set_hook.no_match_ip_address(
1856 vty, index, "ip address", argv[idx_word]->arg,
1857 RMAP_EVENT_FILTER_DELETED);
1858 }
1859 return CMD_SUCCESS;
1860 }
1861
1862
1863 DEFUN (match_ip_address_prefix_list,
1864 match_ip_address_prefix_list_cmd,
1865 "match ip address prefix-list WORD",
1866 MATCH_STR
1867 IP_STR
1868 "Match address of route\n"
1869 "Match entries of prefix-lists\n"
1870 "IP prefix-list name\n")
1871 {
1872 int idx_word = 4;
1873 VTY_DECLVAR_CONTEXT(route_map_index, index);
1874
1875 if (rmap_match_set_hook.match_ip_address_prefix_list)
1876 return rmap_match_set_hook.match_ip_address_prefix_list(
1877 vty, index, "ip address prefix-list",
1878 argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
1879 return CMD_SUCCESS;
1880 }
1881
1882
1883 DEFUN (no_match_ip_address_prefix_list,
1884 no_match_ip_address_prefix_list_cmd,
1885 "no match ip address prefix-list [WORD]",
1886 NO_STR
1887 MATCH_STR
1888 IP_STR
1889 "Match address of route\n"
1890 "Match entries of prefix-lists\n"
1891 "IP prefix-list name\n")
1892 {
1893 int idx_word = 5;
1894 VTY_DECLVAR_CONTEXT(route_map_index, index);
1895
1896 if (rmap_match_set_hook.no_match_ip_address_prefix_list) {
1897 if (argc <= idx_word)
1898 return rmap_match_set_hook
1899 .no_match_ip_address_prefix_list(
1900 vty, index, "ip address prefix-list",
1901 NULL, RMAP_EVENT_PLIST_DELETED);
1902 return rmap_match_set_hook.no_match_ip_address_prefix_list(
1903 vty, index, "ip address prefix-list",
1904 argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
1905 }
1906 return CMD_SUCCESS;
1907 }
1908
1909
1910 DEFUN (match_ip_next_hop,
1911 match_ip_next_hop_cmd,
1912 "match ip next-hop <(1-199)|(1300-2699)|WORD>",
1913 MATCH_STR
1914 IP_STR
1915 "Match next-hop address of route\n"
1916 "IP access-list number\n"
1917 "IP access-list number (expanded range)\n"
1918 "IP Access-list name\n")
1919 {
1920 int idx_acl = 3;
1921 VTY_DECLVAR_CONTEXT(route_map_index, index);
1922
1923 if (rmap_match_set_hook.match_ip_next_hop)
1924 return rmap_match_set_hook.match_ip_next_hop(
1925 vty, index, "ip next-hop", argv[idx_acl]->arg,
1926 RMAP_EVENT_FILTER_ADDED);
1927 return CMD_SUCCESS;
1928 }
1929
1930
1931 DEFUN (no_match_ip_next_hop,
1932 no_match_ip_next_hop_cmd,
1933 "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
1934 NO_STR
1935 MATCH_STR
1936 IP_STR
1937 "Match next-hop address of route\n"
1938 "IP access-list number\n"
1939 "IP access-list number (expanded range)\n"
1940 "IP Access-list name\n")
1941 {
1942 int idx_word = 4;
1943 VTY_DECLVAR_CONTEXT(route_map_index, index);
1944
1945 if (rmap_match_set_hook.no_match_ip_next_hop) {
1946 if (argc <= idx_word)
1947 return rmap_match_set_hook.no_match_ip_next_hop(
1948 vty, index, "ip next-hop", NULL,
1949 RMAP_EVENT_FILTER_DELETED);
1950 return rmap_match_set_hook.no_match_ip_next_hop(
1951 vty, index, "ip next-hop", argv[idx_word]->arg,
1952 RMAP_EVENT_FILTER_DELETED);
1953 }
1954 return CMD_SUCCESS;
1955 }
1956
1957
1958 DEFUN (match_ip_next_hop_prefix_list,
1959 match_ip_next_hop_prefix_list_cmd,
1960 "match ip next-hop prefix-list WORD",
1961 MATCH_STR
1962 IP_STR
1963 "Match next-hop address of route\n"
1964 "Match entries of prefix-lists\n"
1965 "IP prefix-list name\n")
1966 {
1967 int idx_word = 4;
1968 VTY_DECLVAR_CONTEXT(route_map_index, index);
1969
1970 if (rmap_match_set_hook.match_ip_next_hop_prefix_list)
1971 return rmap_match_set_hook.match_ip_next_hop_prefix_list(
1972 vty, index, "ip next-hop prefix-list",
1973 argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
1974 return CMD_SUCCESS;
1975 }
1976
1977 DEFUN (no_match_ip_next_hop_prefix_list,
1978 no_match_ip_next_hop_prefix_list_cmd,
1979 "no match ip next-hop prefix-list [WORD]",
1980 NO_STR
1981 MATCH_STR
1982 IP_STR
1983 "Match next-hop address of route\n"
1984 "Match entries of prefix-lists\n"
1985 "IP prefix-list name\n")
1986 {
1987 int idx_word = 5;
1988 VTY_DECLVAR_CONTEXT(route_map_index, index);
1989
1990 if (rmap_match_set_hook.no_match_ip_next_hop) {
1991 if (argc <= idx_word)
1992 return rmap_match_set_hook.no_match_ip_next_hop(
1993 vty, index, "ip next-hop prefix-list", NULL,
1994 RMAP_EVENT_PLIST_DELETED);
1995 return rmap_match_set_hook.no_match_ip_next_hop(
1996 vty, index, "ip next-hop prefix-list",
1997 argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
1998 }
1999 return CMD_SUCCESS;
2000 }
2001
2002
2003 DEFUN (match_ipv6_address,
2004 match_ipv6_address_cmd,
2005 "match ipv6 address WORD",
2006 MATCH_STR
2007 IPV6_STR
2008 "Match IPv6 address of route\n"
2009 "IPv6 access-list name\n")
2010 {
2011 int idx_word = 3;
2012 VTY_DECLVAR_CONTEXT(route_map_index, index);
2013
2014 if (rmap_match_set_hook.match_ipv6_address)
2015 return rmap_match_set_hook.match_ipv6_address(
2016 vty, index, "ipv6 address", argv[idx_word]->arg,
2017 RMAP_EVENT_FILTER_ADDED);
2018 return CMD_SUCCESS;
2019 }
2020
2021 DEFUN (no_match_ipv6_address,
2022 no_match_ipv6_address_cmd,
2023 "no match ipv6 address WORD",
2024 NO_STR
2025 MATCH_STR
2026 IPV6_STR
2027 "Match IPv6 address of route\n"
2028 "IPv6 access-list name\n")
2029 {
2030 int idx_word = 4;
2031 VTY_DECLVAR_CONTEXT(route_map_index, index);
2032
2033 if (rmap_match_set_hook.no_match_ipv6_address)
2034 return rmap_match_set_hook.no_match_ipv6_address(
2035 vty, index, "ipv6 address", argv[idx_word]->arg,
2036 RMAP_EVENT_FILTER_DELETED);
2037 return CMD_SUCCESS;
2038 }
2039
2040
2041 DEFUN (match_ipv6_address_prefix_list,
2042 match_ipv6_address_prefix_list_cmd,
2043 "match ipv6 address prefix-list WORD",
2044 MATCH_STR
2045 IPV6_STR
2046 "Match address of route\n"
2047 "Match entries of prefix-lists\n"
2048 "IP prefix-list name\n")
2049 {
2050 int idx_word = 4;
2051 VTY_DECLVAR_CONTEXT(route_map_index, index);
2052
2053 if (rmap_match_set_hook.match_ipv6_address_prefix_list)
2054 return rmap_match_set_hook.match_ipv6_address_prefix_list(
2055 vty, index, "ipv6 address prefix-list",
2056 argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
2057 return CMD_SUCCESS;
2058 }
2059
2060 DEFUN (no_match_ipv6_address_prefix_list,
2061 no_match_ipv6_address_prefix_list_cmd,
2062 "no match ipv6 address prefix-list WORD",
2063 NO_STR
2064 MATCH_STR
2065 IPV6_STR
2066 "Match address of route\n"
2067 "Match entries of prefix-lists\n"
2068 "IP prefix-list name\n")
2069 {
2070 int idx_word = 5;
2071 VTY_DECLVAR_CONTEXT(route_map_index, index);
2072
2073 if (rmap_match_set_hook.no_match_ipv6_address_prefix_list)
2074 return rmap_match_set_hook.no_match_ipv6_address_prefix_list(
2075 vty, index, "ipv6 address prefix-list",
2076 argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
2077 return CMD_SUCCESS;
2078 }
2079
2080
2081 DEFUN (match_metric,
2082 match_metric_cmd,
2083 "match metric (0-4294967295)",
2084 MATCH_STR
2085 "Match metric of route\n"
2086 "Metric value\n")
2087 {
2088 int idx_number = 2;
2089 VTY_DECLVAR_CONTEXT(route_map_index, index);
2090
2091 if (rmap_match_set_hook.match_metric)
2092 return rmap_match_set_hook.match_metric(vty, index, "metric",
2093 argv[idx_number]->arg,
2094 RMAP_EVENT_MATCH_ADDED);
2095 return CMD_SUCCESS;
2096 }
2097
2098
2099 DEFUN (no_match_metric,
2100 no_match_metric_cmd,
2101 "no match metric [(0-4294967295)]",
2102 NO_STR
2103 MATCH_STR
2104 "Match metric of route\n"
2105 "Metric value\n")
2106 {
2107 int idx_number = 3;
2108 VTY_DECLVAR_CONTEXT(route_map_index, index);
2109
2110 if (rmap_match_set_hook.no_match_metric) {
2111 if (argc <= idx_number)
2112 return rmap_match_set_hook.no_match_metric(
2113 vty, index, "metric", NULL,
2114 RMAP_EVENT_MATCH_DELETED);
2115 return rmap_match_set_hook.no_match_metric(
2116 vty, index, "metric", argv[idx_number]->arg,
2117 RMAP_EVENT_MATCH_DELETED);
2118 }
2119 return CMD_SUCCESS;
2120 }
2121
2122
2123 DEFUN (match_tag,
2124 match_tag_cmd,
2125 "match tag (1-4294967295)",
2126 MATCH_STR
2127 "Match tag of route\n"
2128 "Tag value\n")
2129 {
2130 int idx_number = 2;
2131 VTY_DECLVAR_CONTEXT(route_map_index, index);
2132
2133 if (rmap_match_set_hook.match_tag)
2134 return rmap_match_set_hook.match_tag(vty, index, "tag",
2135 argv[idx_number]->arg,
2136 RMAP_EVENT_MATCH_ADDED);
2137 return CMD_SUCCESS;
2138 }
2139
2140
2141 DEFUN (no_match_tag,
2142 no_match_tag_cmd,
2143 "no match tag [(1-4294967295)]",
2144 NO_STR
2145 MATCH_STR
2146 "Match tag of route\n"
2147 "Tag value\n")
2148 {
2149 VTY_DECLVAR_CONTEXT(route_map_index, index);
2150
2151 int idx = 0;
2152 char *arg = argv_find(argv, argc, "(1-4294967295)", &idx)
2153 ? argv[idx]->arg
2154 : NULL;
2155
2156 if (rmap_match_set_hook.no_match_tag)
2157 return rmap_match_set_hook.no_match_tag(
2158 vty, index, "tag", arg, RMAP_EVENT_MATCH_DELETED);
2159 return CMD_SUCCESS;
2160 }
2161
2162
2163 DEFUN (set_ip_nexthop,
2164 set_ip_nexthop_cmd,
2165 "set ip next-hop A.B.C.D",
2166 SET_STR
2167 IP_STR
2168 "Next hop address\n"
2169 "IP address of next hop\n")
2170 {
2171 int idx_ipv4 = 3;
2172 union sockunion su;
2173 int ret;
2174 VTY_DECLVAR_CONTEXT(route_map_index, index);
2175
2176 ret = str2sockunion(argv[idx_ipv4]->arg, &su);
2177 if (ret < 0) {
2178 vty_out(vty, "%% Malformed nexthop address\n");
2179 return CMD_WARNING_CONFIG_FAILED;
2180 }
2181 if (su.sin.sin_addr.s_addr == 0
2182 || IPV4_CLASS_DE(su.sin.sin_addr.s_addr)) {
2183 vty_out(vty,
2184 "%% nexthop address cannot be 0.0.0.0, multicast or reserved\n");
2185 return CMD_WARNING_CONFIG_FAILED;
2186 }
2187
2188 if (rmap_match_set_hook.set_ip_nexthop)
2189 return rmap_match_set_hook.set_ip_nexthop(
2190 vty, index, "ip next-hop", argv[idx_ipv4]->arg);
2191 return CMD_SUCCESS;
2192 }
2193
2194
2195 DEFUN (no_set_ip_nexthop,
2196 no_set_ip_nexthop_cmd,
2197 "no set ip next-hop [<peer-address|A.B.C.D>]",
2198 NO_STR
2199 SET_STR
2200 IP_STR
2201 "Next hop address\n"
2202 "Use peer address (for BGP only)\n"
2203 "IP address of next hop\n")
2204 {
2205 int idx_peer = 4;
2206 VTY_DECLVAR_CONTEXT(route_map_index, index);
2207
2208 if (rmap_match_set_hook.no_set_ip_nexthop) {
2209 if (argc <= idx_peer)
2210 return rmap_match_set_hook.no_set_ip_nexthop(
2211 vty, index, "ip next-hop", NULL);
2212 return rmap_match_set_hook.no_set_ip_nexthop(
2213 vty, index, "ip next-hop", argv[idx_peer]->arg);
2214 }
2215 return CMD_SUCCESS;
2216 }
2217
2218
2219 DEFUN (set_ipv6_nexthop_local,
2220 set_ipv6_nexthop_local_cmd,
2221 "set ipv6 next-hop local X:X::X:X",
2222 SET_STR
2223 IPV6_STR
2224 "IPv6 next-hop address\n"
2225 "IPv6 local address\n"
2226 "IPv6 address of next hop\n")
2227 {
2228 int idx_ipv6 = 4;
2229 struct in6_addr addr;
2230 int ret;
2231 VTY_DECLVAR_CONTEXT(route_map_index, index);
2232
2233 ret = inet_pton(AF_INET6, argv[idx_ipv6]->arg, &addr);
2234 if (!ret) {
2235 vty_out(vty, "%% Malformed nexthop address\n");
2236 return CMD_WARNING_CONFIG_FAILED;
2237 }
2238 if (!IN6_IS_ADDR_LINKLOCAL(&addr)) {
2239 vty_out(vty, "%% Invalid link-local nexthop address\n");
2240 return CMD_WARNING_CONFIG_FAILED;
2241 }
2242
2243 if (rmap_match_set_hook.set_ipv6_nexthop_local)
2244 return rmap_match_set_hook.set_ipv6_nexthop_local(
2245 vty, index, "ipv6 next-hop local", argv[idx_ipv6]->arg);
2246 return CMD_SUCCESS;
2247 }
2248
2249
2250 DEFUN (no_set_ipv6_nexthop_local,
2251 no_set_ipv6_nexthop_local_cmd,
2252 "no set ipv6 next-hop local [X:X::X:X]",
2253 NO_STR
2254 SET_STR
2255 IPV6_STR
2256 "IPv6 next-hop address\n"
2257 "IPv6 local address\n"
2258 "IPv6 address of next hop\n")
2259 {
2260 int idx_ipv6 = 5;
2261 VTY_DECLVAR_CONTEXT(route_map_index, index);
2262
2263 if (rmap_match_set_hook.no_set_ipv6_nexthop_local) {
2264 if (argc <= idx_ipv6)
2265 return rmap_match_set_hook.no_set_ipv6_nexthop_local(
2266 vty, index, "ipv6 next-hop local", NULL);
2267 return rmap_match_set_hook.no_set_ipv6_nexthop_local(
2268 vty, index, "ipv6 next-hop local", argv[5]->arg);
2269 }
2270 return CMD_SUCCESS;
2271 }
2272
2273 DEFUN (set_metric,
2274 set_metric_cmd,
2275 "set metric <(0-4294967295)|rtt|+rtt|-rtt|+metric|-metric>",
2276 SET_STR
2277 "Metric value for destination routing protocol\n"
2278 "Metric value\n"
2279 "Assign round trip time\n"
2280 "Add round trip time\n"
2281 "Subtract round trip time\n"
2282 "Add metric\n"
2283 "Subtract metric\n")
2284 {
2285 int idx_number = 2;
2286 VTY_DECLVAR_CONTEXT(route_map_index, index);
2287
2288 const char *pass = (argv[idx_number]->type == RANGE_TKN)
2289 ? argv[idx_number]->arg
2290 : argv[idx_number]->text;
2291
2292 if (rmap_match_set_hook.set_metric)
2293 return rmap_match_set_hook.set_metric(vty, index, "metric",
2294 pass);
2295 return CMD_SUCCESS;
2296 }
2297
2298
2299 DEFUN (no_set_metric,
2300 no_set_metric_cmd,
2301 "no set metric [(0-4294967295)]",
2302 NO_STR
2303 SET_STR
2304 "Metric value for destination routing protocol\n"
2305 "Metric value\n")
2306 {
2307 int idx_number = 3;
2308 VTY_DECLVAR_CONTEXT(route_map_index, index);
2309
2310 if (rmap_match_set_hook.no_set_metric) {
2311 if (argc <= idx_number)
2312 return rmap_match_set_hook.no_set_metric(
2313 vty, index, "metric", NULL);
2314 return rmap_match_set_hook.no_set_metric(vty, index, "metric",
2315 argv[idx_number]->arg);
2316 }
2317 return CMD_SUCCESS;
2318 }
2319
2320
2321 DEFUN (set_tag,
2322 set_tag_cmd,
2323 "set tag (1-4294967295)",
2324 SET_STR
2325 "Tag value for routing protocol\n"
2326 "Tag value\n")
2327 {
2328 VTY_DECLVAR_CONTEXT(route_map_index, index);
2329
2330 int idx_number = 2;
2331 if (rmap_match_set_hook.set_tag)
2332 return rmap_match_set_hook.set_tag(vty, index, "tag",
2333 argv[idx_number]->arg);
2334 return CMD_SUCCESS;
2335 }
2336
2337
2338 DEFUN (no_set_tag,
2339 no_set_tag_cmd,
2340 "no set tag [(1-4294967295)]",
2341 NO_STR
2342 SET_STR
2343 "Tag value for routing protocol\n"
2344 "Tag value\n")
2345 {
2346 VTY_DECLVAR_CONTEXT(route_map_index, index);
2347
2348 int idx_number = 3;
2349 if (rmap_match_set_hook.no_set_tag) {
2350 if (argc <= idx_number)
2351 return rmap_match_set_hook.no_set_tag(vty, index, "tag",
2352 NULL);
2353 return rmap_match_set_hook.no_set_tag(vty, index, "tag",
2354 argv[idx_number]->arg);
2355 }
2356 return CMD_SUCCESS;
2357 }
2358
2359
2360 DEFUN_NOSH (route_map,
2361 route_map_cmd,
2362 "route-map WORD <deny|permit> (1-65535)",
2363 "Create route-map or enter route-map command mode\n"
2364 "Route map tag\n"
2365 "Route map denies set operations\n"
2366 "Route map permits set operations\n"
2367 "Sequence to insert to/delete from existing route-map entry\n")
2368 {
2369 int idx_word = 1;
2370 int idx_permit_deny = 2;
2371 int idx_number = 3;
2372 struct route_map *map;
2373 struct route_map_index *index;
2374 char *endptr = NULL;
2375 int permit =
2376 argv[idx_permit_deny]->arg[0] == 'p' ? RMAP_PERMIT : RMAP_DENY;
2377 unsigned long pref = strtoul(argv[idx_number]->arg, &endptr, 10);
2378 const char *mapname = argv[idx_word]->arg;
2379
2380 /* Get route map. */
2381 map = route_map_get(mapname);
2382 index = route_map_index_get(map, permit, pref);
2383
2384 VTY_PUSH_CONTEXT(RMAP_NODE, index);
2385 return CMD_SUCCESS;
2386 }
2387
2388 DEFUN (no_route_map_all,
2389 no_route_map_all_cmd,
2390 "no route-map WORD",
2391 NO_STR
2392 "Create route-map or enter route-map command mode\n"
2393 "Route map tag\n")
2394 {
2395 int idx_word = 2;
2396 const char *mapname = argv[idx_word]->arg;
2397 struct route_map *map;
2398
2399 map = route_map_lookup_by_name(mapname);
2400 if (map == NULL) {
2401 vty_out(vty, "%% Could not find route-map %s\n", mapname);
2402 return CMD_WARNING_CONFIG_FAILED;
2403 }
2404
2405 route_map_delete(map);
2406
2407 return CMD_SUCCESS;
2408 }
2409
2410 DEFUN (no_route_map,
2411 no_route_map_cmd,
2412 "no route-map WORD <deny|permit> (1-65535)",
2413 NO_STR
2414 "Create route-map or enter route-map command mode\n"
2415 "Route map tag\n"
2416 "Route map denies set operations\n"
2417 "Route map permits set operations\n"
2418 "Sequence to insert to/delete from existing route-map entry\n")
2419 {
2420 int idx_word = 2;
2421 int idx_permit_deny = 3;
2422 int idx_number = 4;
2423 struct route_map *map;
2424 struct route_map_index *index;
2425 char *endptr = NULL;
2426 int permit = strmatch(argv[idx_permit_deny]->text, "permit")
2427 ? RMAP_PERMIT
2428 : RMAP_DENY;
2429 const char *prefstr = argv[idx_number]->arg;
2430 const char *mapname = argv[idx_word]->arg;
2431 unsigned long pref = strtoul(prefstr, &endptr, 10);
2432
2433 /* Existence check. */
2434 map = route_map_lookup_by_name(mapname);
2435 if (map == NULL) {
2436 vty_out(vty, "%% Could not find route-map %s\n", mapname);
2437 return CMD_WARNING_CONFIG_FAILED;
2438 }
2439
2440 /* Lookup route map index. */
2441 index = route_map_index_lookup(map, permit, pref);
2442 if (index == NULL) {
2443 vty_out(vty, "%% Could not find route-map entry %s %s\n",
2444 mapname, prefstr);
2445 return CMD_WARNING_CONFIG_FAILED;
2446 }
2447
2448 /* Delete index from route map. */
2449 route_map_index_delete(index, 1);
2450
2451 /* If this route rule is the last one, delete route map itself. */
2452 if (route_map_empty(map))
2453 route_map_delete(map);
2454
2455 return CMD_SUCCESS;
2456 }
2457
2458 DEFUN (rmap_onmatch_next,
2459 rmap_onmatch_next_cmd,
2460 "on-match next",
2461 "Exit policy on matches\n"
2462 "Next clause\n")
2463 {
2464 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2465
2466 if (index) {
2467 if (index->type == RMAP_DENY) {
2468 /* Under a deny clause, match means it's finished. No
2469 * need to set next */
2470 vty_out(vty,
2471 "on-match next not supported under route-map deny\n");
2472 return CMD_WARNING_CONFIG_FAILED;
2473 }
2474 index->exitpolicy = RMAP_NEXT;
2475 }
2476 return CMD_SUCCESS;
2477 }
2478
2479 DEFUN (no_rmap_onmatch_next,
2480 no_rmap_onmatch_next_cmd,
2481 "no on-match next",
2482 NO_STR
2483 "Exit policy on matches\n"
2484 "Next clause\n")
2485 {
2486 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2487
2488 if (index)
2489 index->exitpolicy = RMAP_EXIT;
2490
2491 return CMD_SUCCESS;
2492 }
2493
2494 DEFUN (rmap_onmatch_goto,
2495 rmap_onmatch_goto_cmd,
2496 "on-match goto (1-65535)",
2497 "Exit policy on matches\n"
2498 "Goto Clause number\n"
2499 "Number\n")
2500 {
2501 int idx = 0;
2502 char *num = argv_find(argv, argc, "(1-65535)", &idx) ? argv[idx]->arg
2503 : NULL;
2504
2505 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2506 int d = 0;
2507
2508 if (index) {
2509 if (index->type == RMAP_DENY) {
2510 /* Under a deny clause, match means it's finished. No
2511 * need to go anywhere */
2512 vty_out(vty,
2513 "on-match goto not supported under route-map deny\n");
2514 return CMD_WARNING_CONFIG_FAILED;
2515 }
2516
2517 if (num)
2518 d = strtoul(num, NULL, 10);
2519 else
2520 d = index->pref + 1;
2521
2522 if (d <= index->pref) {
2523 /* Can't allow you to do that, Dave */
2524 vty_out(vty, "can't jump backwards in route-maps\n");
2525 return CMD_WARNING_CONFIG_FAILED;
2526 } else {
2527 index->exitpolicy = RMAP_GOTO;
2528 index->nextpref = d;
2529 }
2530 }
2531 return CMD_SUCCESS;
2532 }
2533
2534 DEFUN (no_rmap_onmatch_goto,
2535 no_rmap_onmatch_goto_cmd,
2536 "no on-match goto",
2537 NO_STR
2538 "Exit policy on matches\n"
2539 "Goto Clause number\n")
2540 {
2541 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2542
2543 if (index)
2544 index->exitpolicy = RMAP_EXIT;
2545
2546 return CMD_SUCCESS;
2547 }
2548
2549 /* Cisco/GNU Zebra compatibility aliases */
2550 /* ALIAS_FIXME */
2551 DEFUN (rmap_continue,
2552 rmap_continue_cmd,
2553 "continue (1-65535)",
2554 "Continue on a different entry within the route-map\n"
2555 "Route-map entry sequence number\n")
2556 {
2557 return rmap_onmatch_goto(self, vty, argc, argv);
2558 }
2559
2560 /* ALIAS_FIXME */
2561 DEFUN (no_rmap_continue,
2562 no_rmap_continue_cmd,
2563 "no continue [(1-65535)]",
2564 NO_STR
2565 "Continue on a different entry within the route-map\n"
2566 "Route-map entry sequence number\n")
2567 {
2568 return no_rmap_onmatch_goto(self, vty, argc, argv);
2569 }
2570
2571
2572 DEFUN (rmap_show_name,
2573 rmap_show_name_cmd,
2574 "show route-map [WORD]",
2575 SHOW_STR
2576 "route-map information\n"
2577 "route-map name\n")
2578 {
2579 int idx_word = 2;
2580 const char *name = (argc == 3) ? argv[idx_word]->arg : NULL;
2581 return vty_show_route_map(vty, name);
2582 }
2583
2584 DEFUN (rmap_call,
2585 rmap_call_cmd,
2586 "call WORD",
2587 "Jump to another Route-Map after match+set\n"
2588 "Target route-map name\n")
2589 {
2590 int idx_word = 1;
2591 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2592 const char *rmap = argv[idx_word]->arg;
2593
2594 assert(index);
2595
2596 if (index->nextrm) {
2597 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED,
2598 index->nextrm, index->map->name);
2599 XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
2600 }
2601 index->nextrm = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
2602
2603 /* Execute event hook. */
2604 route_map_upd8_dependency(RMAP_EVENT_CALL_ADDED, index->nextrm,
2605 index->map->name);
2606 return CMD_SUCCESS;
2607 }
2608
2609 DEFUN (no_rmap_call,
2610 no_rmap_call_cmd,
2611 "no call",
2612 NO_STR
2613 "Jump to another Route-Map after match+set\n")
2614 {
2615 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2616
2617 if (index->nextrm) {
2618 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED,
2619 index->nextrm, index->map->name);
2620 XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
2621 index->nextrm = NULL;
2622 }
2623
2624 return CMD_SUCCESS;
2625 }
2626
2627 DEFUN (rmap_description,
2628 rmap_description_cmd,
2629 "description LINE...",
2630 "Route-map comment\n"
2631 "Comment describing this route-map rule\n")
2632 {
2633 int idx_line = 1;
2634 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2635
2636 if (index) {
2637 if (index->description)
2638 XFREE(MTYPE_TMP, index->description);
2639 index->description = argv_concat(argv, argc, idx_line);
2640 }
2641 return CMD_SUCCESS;
2642 }
2643
2644 DEFUN (no_rmap_description,
2645 no_rmap_description_cmd,
2646 "no description",
2647 NO_STR
2648 "Route-map comment\n")
2649 {
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 = NULL;
2656 }
2657 return CMD_SUCCESS;
2658 }
2659
2660 /* Configuration write function. */
2661 static int route_map_config_write(struct vty *vty)
2662 {
2663 struct route_map *map;
2664 struct route_map_index *index;
2665 struct route_map_rule *rule;
2666 int first = 1;
2667 int write = 0;
2668
2669 for (map = route_map_master.head; map; map = map->next)
2670 for (index = map->head; index; index = index->next) {
2671 if (!first)
2672 vty_out(vty, "!\n");
2673 else
2674 first = 0;
2675
2676 vty_out(vty, "route-map %s %s %d\n", map->name,
2677 route_map_type_str(index->type), index->pref);
2678
2679 if (index->description)
2680 vty_out(vty, " description %s\n",
2681 index->description);
2682
2683 for (rule = index->match_list.head; rule;
2684 rule = rule->next)
2685 vty_out(vty, " match %s %s\n", rule->cmd->str,
2686 rule->rule_str ? rule->rule_str : "");
2687
2688 for (rule = index->set_list.head; rule;
2689 rule = rule->next)
2690 vty_out(vty, " set %s %s\n", rule->cmd->str,
2691 rule->rule_str ? rule->rule_str : "");
2692 if (index->nextrm)
2693 vty_out(vty, " call %s\n", index->nextrm);
2694 if (index->exitpolicy == RMAP_GOTO)
2695 vty_out(vty, " on-match goto %d\n",
2696 index->nextpref);
2697 if (index->exitpolicy == RMAP_NEXT)
2698 vty_out(vty, " on-match next\n");
2699
2700 write++;
2701 }
2702 return write;
2703 }
2704
2705 /* Route map node structure. */
2706 static struct cmd_node rmap_node = {RMAP_NODE, "%s(config-route-map)# ", 1};
2707
2708 /* Common route map rules */
2709
2710 void *route_map_rule_tag_compile(const char *arg)
2711 {
2712 unsigned long int tmp;
2713 char *endptr;
2714 route_tag_t *tag;
2715
2716 errno = 0;
2717 tmp = strtoul(arg, &endptr, 0);
2718 if (arg[0] == '\0' || *endptr != '\0' || errno || tmp > ROUTE_TAG_MAX)
2719 return NULL;
2720
2721 tag = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*tag));
2722 *tag = tmp;
2723
2724 return tag;
2725 }
2726
2727 void route_map_rule_tag_free(void *rule)
2728 {
2729 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
2730 }
2731
2732 void route_map_finish(void)
2733 {
2734 int i;
2735
2736 vector_free(route_match_vec);
2737 route_match_vec = NULL;
2738 vector_free(route_set_vec);
2739 route_set_vec = NULL;
2740
2741 /* cleanup route_map */
2742 while (route_map_master.head) {
2743 struct route_map *map = route_map_master.head;
2744 map->to_be_processed = 0;
2745 route_map_delete(map);
2746 }
2747
2748 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
2749 hash_free(route_map_dep_hash[i]);
2750 route_map_dep_hash[i] = NULL;
2751 }
2752
2753 hash_free(route_map_master_hash);
2754 route_map_master_hash = NULL;
2755 }
2756
2757 static void rmap_autocomplete(vector comps, struct cmd_token *token)
2758 {
2759 struct route_map *map;
2760
2761 for (map = route_map_master.head; map; map = map->next)
2762 vector_set(comps, XSTRDUP(MTYPE_COMPLETION, map->name));
2763 }
2764
2765 static const struct cmd_variable_handler rmap_var_handlers[] = {
2766 {/* "route-map WORD" */
2767 .varname = "route_map",
2768 .completions = rmap_autocomplete},
2769 {.tokenname = "ROUTEMAP_NAME", .completions = rmap_autocomplete},
2770 {.tokenname = "RMAP_NAME", .completions = rmap_autocomplete},
2771 {.completions = NULL}};
2772
2773 /* Initialization of route map vector. */
2774 void route_map_init(void)
2775 {
2776 int i;
2777
2778 /* Make vector for match and set. */
2779 route_match_vec = vector_init(1);
2780 route_set_vec = vector_init(1);
2781 route_map_master_hash =
2782 hash_create(route_map_hash_key_make, route_map_hash_cmp, NULL);
2783
2784 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
2785 route_map_dep_hash[i] =
2786 hash_create(route_map_dep_hash_make_key,
2787 route_map_dep_hash_cmp, NULL);
2788
2789 cmd_variable_handler_register(rmap_var_handlers);
2790
2791 /* Install route map top node. */
2792 install_node(&rmap_node, route_map_config_write);
2793
2794 /* Install route map commands. */
2795 install_default(RMAP_NODE);
2796 install_element(CONFIG_NODE, &route_map_cmd);
2797 install_element(CONFIG_NODE, &no_route_map_cmd);
2798 install_element(CONFIG_NODE, &no_route_map_all_cmd);
2799
2800 /* Install the on-match stuff */
2801 install_element(RMAP_NODE, &route_map_cmd);
2802 install_element(RMAP_NODE, &rmap_onmatch_next_cmd);
2803 install_element(RMAP_NODE, &no_rmap_onmatch_next_cmd);
2804 install_element(RMAP_NODE, &rmap_onmatch_goto_cmd);
2805 install_element(RMAP_NODE, &no_rmap_onmatch_goto_cmd);
2806 install_element(RMAP_NODE, &rmap_continue_cmd);
2807 install_element(RMAP_NODE, &no_rmap_continue_cmd);
2808
2809 /* Install the continue stuff (ALIAS of on-match). */
2810
2811 /* Install the call stuff. */
2812 install_element(RMAP_NODE, &rmap_call_cmd);
2813 install_element(RMAP_NODE, &no_rmap_call_cmd);
2814
2815 /* Install description commands. */
2816 install_element(RMAP_NODE, &rmap_description_cmd);
2817 install_element(RMAP_NODE, &no_rmap_description_cmd);
2818
2819 /* Install show command */
2820 install_element(ENABLE_NODE, &rmap_show_name_cmd);
2821
2822 install_element(RMAP_NODE, &match_interface_cmd);
2823 install_element(RMAP_NODE, &no_match_interface_cmd);
2824
2825 install_element(RMAP_NODE, &match_ip_address_cmd);
2826 install_element(RMAP_NODE, &no_match_ip_address_cmd);
2827
2828 install_element(RMAP_NODE, &match_ip_address_prefix_list_cmd);
2829 install_element(RMAP_NODE, &no_match_ip_address_prefix_list_cmd);
2830
2831 install_element(RMAP_NODE, &match_ip_next_hop_cmd);
2832 install_element(RMAP_NODE, &no_match_ip_next_hop_cmd);
2833
2834 install_element(RMAP_NODE, &match_ip_next_hop_prefix_list_cmd);
2835 install_element(RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd);
2836
2837 install_element(RMAP_NODE, &match_ipv6_address_cmd);
2838 install_element(RMAP_NODE, &no_match_ipv6_address_cmd);
2839
2840 install_element(RMAP_NODE, &match_ipv6_address_prefix_list_cmd);
2841 install_element(RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd);
2842
2843 install_element(RMAP_NODE, &match_metric_cmd);
2844 install_element(RMAP_NODE, &no_match_metric_cmd);
2845
2846 install_element(RMAP_NODE, &match_tag_cmd);
2847 install_element(RMAP_NODE, &no_match_tag_cmd);
2848
2849 install_element(RMAP_NODE, &set_ip_nexthop_cmd);
2850 install_element(RMAP_NODE, &no_set_ip_nexthop_cmd);
2851
2852 install_element(RMAP_NODE, &set_ipv6_nexthop_local_cmd);
2853 install_element(RMAP_NODE, &no_set_ipv6_nexthop_local_cmd);
2854
2855 install_element(RMAP_NODE, &set_metric_cmd);
2856 install_element(RMAP_NODE, &no_set_metric_cmd);
2857
2858 install_element(RMAP_NODE, &set_tag_cmd);
2859 install_element(RMAP_NODE, &no_set_tag_cmd);
2860 }