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