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