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