]> git.proxmox.com Git - mirror_frr.git/blame - lib/routemap.c
rmap: Modify cli helper text for `match_ipv6_next_hop_type_cmd`
[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 *);
619 void (*event_hook)(route_map_event_t, 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;
905 default:
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) {
1080 (*route_map_master.event_hook)(RMAP_EVENT_INDEX_DELETED,
1081 index->map->name);
1082 route_map_notify_dependencies(index->map->name,
1083 RMAP_EVENT_CALL_ADDED);
1084 }
1085 XFREE(MTYPE_ROUTE_MAP_INDEX, index);
718e3744 1086}
1087
1088/* Lookup index from route map. */
d62a17ae 1089static struct route_map_index *route_map_index_lookup(struct route_map *map,
1090 enum route_map_type type,
1091 int pref)
718e3744 1092{
d62a17ae 1093 struct route_map_index *index;
718e3744 1094
d62a17ae 1095 for (index = map->head; index; index = index->next)
1096 if ((index->type == type || type == RMAP_ANY)
1097 && index->pref == pref)
1098 return index;
1099 return NULL;
718e3744 1100}
1101
1102/* Add new index to route map. */
8cc4198f 1103static struct route_map_index *
d62a17ae 1104route_map_index_add(struct route_map *map, enum route_map_type type, int pref)
1105{
1106 struct route_map_index *index;
1107 struct route_map_index *point;
1108
1109 /* Allocate new route map inex. */
1110 index = route_map_index_new();
1111 index->map = map;
1112 index->type = type;
1113 index->pref = pref;
1114
1115 /* Compare preference. */
1116 for (point = map->head; point; point = point->next)
1117 if (point->pref >= pref)
1118 break;
1119
1120 if (map->head == NULL) {
1121 map->head = map->tail = index;
1122 } else if (point == NULL) {
1123 index->prev = map->tail;
1124 map->tail->next = index;
1125 map->tail = index;
1126 } else if (point == map->head) {
1127 index->next = map->head;
1128 map->head->prev = index;
1129 map->head = index;
1130 } else {
1131 index->next = point;
1132 index->prev = point->prev;
1133 if (point->prev)
1134 point->prev->next = index;
1135 point->prev = index;
1136 }
1137
1138 /* Execute event hook. */
1139 if (route_map_master.event_hook) {
1140 (*route_map_master.event_hook)(RMAP_EVENT_INDEX_ADDED,
1141 map->name);
1142 route_map_notify_dependencies(map->name, RMAP_EVENT_CALL_ADDED);
1143 }
1144 return index;
718e3744 1145}
1146
1147/* Get route map index. */
8cc4198f 1148static struct route_map_index *
d62a17ae 1149route_map_index_get(struct route_map *map, enum route_map_type type, int pref)
718e3744 1150{
d62a17ae 1151 struct route_map_index *index;
718e3744 1152
d62a17ae 1153 index = route_map_index_lookup(map, RMAP_ANY, pref);
1154 if (index && index->type != type) {
1155 /* Delete index from route map. */
1156 route_map_index_delete(index, 1);
1157 index = NULL;
1158 }
1159 if (index == NULL)
1160 index = route_map_index_add(map, type, pref);
1161 return index;
718e3744 1162}
1163
1164/* New route map rule */
d62a17ae 1165static struct route_map_rule *route_map_rule_new(void)
718e3744 1166{
d62a17ae 1167 struct route_map_rule *new;
718e3744 1168
d62a17ae 1169 new = XCALLOC(MTYPE_ROUTE_MAP_RULE, sizeof(struct route_map_rule));
1170 return new;
718e3744 1171}
6b0655a2 1172
718e3744 1173/* Install rule command to the match list. */
d62a17ae 1174void route_map_install_match(struct route_map_rule_cmd *cmd)
718e3744 1175{
d62a17ae 1176 vector_set(route_match_vec, cmd);
718e3744 1177}
1178
1179/* Install rule command to the set list. */
d62a17ae 1180void route_map_install_set(struct route_map_rule_cmd *cmd)
718e3744 1181{
d62a17ae 1182 vector_set(route_set_vec, cmd);
718e3744 1183}
1184
1185/* Lookup rule command from match list. */
d62a17ae 1186static struct route_map_rule_cmd *route_map_lookup_match(const char *name)
718e3744 1187{
d62a17ae 1188 unsigned int i;
1189 struct route_map_rule_cmd *rule;
718e3744 1190
d62a17ae 1191 for (i = 0; i < vector_active(route_match_vec); i++)
1192 if ((rule = vector_slot(route_match_vec, i)) != NULL)
1193 if (strcmp(rule->str, name) == 0)
1194 return rule;
1195 return NULL;
718e3744 1196}
1197
1198/* Lookup rule command from set list. */
d62a17ae 1199static struct route_map_rule_cmd *route_map_lookup_set(const char *name)
718e3744 1200{
d62a17ae 1201 unsigned int i;
1202 struct route_map_rule_cmd *rule;
718e3744 1203
d62a17ae 1204 for (i = 0; i < vector_active(route_set_vec); i++)
1205 if ((rule = vector_slot(route_set_vec, i)) != NULL)
1206 if (strcmp(rule->str, name) == 0)
1207 return rule;
1208 return NULL;
718e3744 1209}
1210
1211/* Add match and set rule to rule list. */
d62a17ae 1212static void route_map_rule_add(struct route_map_rule_list *list,
1213 struct route_map_rule *rule)
718e3744 1214{
d62a17ae 1215 rule->next = NULL;
1216 rule->prev = list->tail;
1217 if (list->tail)
1218 list->tail->next = rule;
1219 else
1220 list->head = rule;
1221 list->tail = rule;
718e3744 1222}
1223
1224/* Delete rule from rule list. */
d62a17ae 1225static void route_map_rule_delete(struct route_map_rule_list *list,
1226 struct route_map_rule *rule)
718e3744 1227{
d62a17ae 1228 if (rule->cmd->func_free)
1229 (*rule->cmd->func_free)(rule->value);
718e3744 1230
0a22ddfb 1231 XFREE(MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str);
718e3744 1232
d62a17ae 1233 if (rule->next)
1234 rule->next->prev = rule->prev;
1235 else
1236 list->tail = rule->prev;
1237 if (rule->prev)
1238 rule->prev->next = rule->next;
1239 else
1240 list->head = rule->next;
718e3744 1241
d62a17ae 1242 XFREE(MTYPE_ROUTE_MAP_RULE, rule);
718e3744 1243}
1244
1245/* strcmp wrapper function which don't crush even argument is NULL. */
d62a17ae 1246static int rulecmp(const char *dst, const char *src)
1247{
1248 if (dst == NULL) {
1249 if (src == NULL)
1250 return 0;
1251 else
1252 return 1;
1253 } else {
1254 if (src == NULL)
1255 return 1;
1256 else
1257 return strcmp(dst, src);
1258 }
718e3744 1259 return 1;
718e3744 1260}
1261
518f0eb1
DS
1262/* Use this to return the already specified argument for this match. This is
1263 * useful to get the specified argument with a route map match rule when the
1264 * rule is being deleted and the argument is not provided.
1265 */
d62a17ae 1266const char *route_map_get_match_arg(struct route_map_index *index,
1267 const char *match_name)
518f0eb1 1268{
d62a17ae 1269 struct route_map_rule *rule;
1270 struct route_map_rule_cmd *cmd;
518f0eb1 1271
d62a17ae 1272 /* First lookup rule for add match statement. */
1273 cmd = route_map_lookup_match(match_name);
1274 if (cmd == NULL)
1275 return NULL;
518f0eb1 1276
d62a17ae 1277 for (rule = index->match_list.head; rule; rule = rule->next)
1278 if (rule->cmd == cmd && rule->rule_str != NULL)
1279 return (rule->rule_str);
518f0eb1 1280
d62a17ae 1281 return (NULL);
518f0eb1
DS
1282}
1283
718e3744 1284/* Add match statement to route map. */
d62a17ae 1285int route_map_add_match(struct route_map_index *index, const char *match_name,
1286 const char *match_arg)
1287{
1288 struct route_map_rule *rule;
1289 struct route_map_rule *next;
1290 struct route_map_rule_cmd *cmd;
1291 void *compile;
1292 int replaced = 0;
1293
1294 /* First lookup rule for add match statement. */
1295 cmd = route_map_lookup_match(match_name);
1296 if (cmd == NULL)
1297 return RMAP_RULE_MISSING;
1298
1299 /* Next call compile function for this match statement. */
1300 if (cmd->func_compile) {
1301 compile = (*cmd->func_compile)(match_arg);
1302 if (compile == NULL)
1303 return RMAP_COMPILE_ERROR;
1304 } else
1305 compile = NULL;
1306
1307 /* If argument is completely same ignore it. */
1308 for (rule = index->match_list.head; rule; rule = next) {
1309 next = rule->next;
1310 if (rule->cmd == cmd) {
1dc02a55
NT
1311 /* If the configured route-map match rule is exactly
1312 * the same as the existing configuration then,
1313 * ignore the duplicate configuration.
1314 */
1315 if (strcmp(match_arg, rule->rule_str) == 0) {
1316 if (cmd->func_free)
1317 (*cmd->func_free)(compile);
1318 return RMAP_COMPILE_SUCCESS;
1319 }
1320
d62a17ae 1321 route_map_rule_delete(&index->match_list, rule);
1322 replaced = 1;
1323 }
718e3744 1324 }
718e3744 1325
d62a17ae 1326 /* Add new route map match rule. */
1327 rule = route_map_rule_new();
1328 rule->cmd = cmd;
1329 rule->value = compile;
1330 if (match_arg)
1331 rule->rule_str = XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR, match_arg);
1332 else
1333 rule->rule_str = NULL;
718e3744 1334
d62a17ae 1335 /* Add new route match rule to linked list. */
1336 route_map_rule_add(&index->match_list, rule);
718e3744 1337
d62a17ae 1338 /* Execute event hook. */
1339 if (route_map_master.event_hook) {
1340 (*route_map_master.event_hook)(
1341 replaced ? RMAP_EVENT_MATCH_REPLACED
1342 : RMAP_EVENT_MATCH_ADDED,
1343 index->map->name);
1344 route_map_notify_dependencies(index->map->name,
1345 RMAP_EVENT_CALL_ADDED);
1346 }
718e3744 1347
9ca25fed 1348 return RMAP_COMPILE_SUCCESS;
718e3744 1349}
1350
1351/* Delete specified route match rule. */
d62a17ae 1352int route_map_delete_match(struct route_map_index *index,
1353 const char *match_name, const char *match_arg)
1354{
1355 struct route_map_rule *rule;
1356 struct route_map_rule_cmd *cmd;
1357
1358 cmd = route_map_lookup_match(match_name);
1359 if (cmd == NULL)
1360 return 1;
1361
1362 for (rule = index->match_list.head; rule; rule = rule->next)
9d303b37
DL
1363 if (rule->cmd == cmd && (rulecmp(rule->rule_str, match_arg) == 0
1364 || match_arg == NULL)) {
d62a17ae 1365 route_map_rule_delete(&index->match_list, rule);
1366 /* Execute event hook. */
1367 if (route_map_master.event_hook) {
1368 (*route_map_master.event_hook)(
1369 RMAP_EVENT_MATCH_DELETED,
1370 index->map->name);
1371 route_map_notify_dependencies(
1372 index->map->name,
1373 RMAP_EVENT_CALL_ADDED);
1374 }
1375 return 0;
1376 }
1377 /* Can't find matched rule. */
1378 return 1;
718e3744 1379}
1380
1381/* Add route-map set statement to the route map. */
d62a17ae 1382int route_map_add_set(struct route_map_index *index, const char *set_name,
1383 const char *set_arg)
1384{
1385 struct route_map_rule *rule;
1386 struct route_map_rule *next;
1387 struct route_map_rule_cmd *cmd;
1388 void *compile;
1389 int replaced = 0;
1390
1391 cmd = route_map_lookup_set(set_name);
1392 if (cmd == NULL)
1393 return RMAP_RULE_MISSING;
1394
1395 /* Next call compile function for this match statement. */
1396 if (cmd->func_compile) {
1397 compile = (*cmd->func_compile)(set_arg);
1398 if (compile == NULL)
1399 return RMAP_COMPILE_ERROR;
1400 } else
1401 compile = NULL;
1402
1403 /* Add by WJL. if old set command of same kind exist, delete it first
1404 to ensure only one set command of same kind exist under a
1405 route_map_index. */
1406 for (rule = index->set_list.head; rule; rule = next) {
1407 next = rule->next;
1408 if (rule->cmd == cmd) {
1409 route_map_rule_delete(&index->set_list, rule);
1410 replaced = 1;
1411 }
1412 }
1413
1414 /* Add new route map match rule. */
1415 rule = route_map_rule_new();
1416 rule->cmd = cmd;
1417 rule->value = compile;
1418 if (set_arg)
1419 rule->rule_str = XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR, set_arg);
1420 else
1421 rule->rule_str = NULL;
1422
1423 /* Add new route match rule to linked list. */
1424 route_map_rule_add(&index->set_list, rule);
1425
1426 /* Execute event hook. */
1427 if (route_map_master.event_hook) {
1428 (*route_map_master.event_hook)(replaced
1429 ? RMAP_EVENT_SET_REPLACED
1430 : RMAP_EVENT_SET_ADDED,
1431 index->map->name);
1432 route_map_notify_dependencies(index->map->name,
1433 RMAP_EVENT_CALL_ADDED);
718e3744 1434 }
9ca25fed 1435 return RMAP_COMPILE_SUCCESS;
718e3744 1436}
1437
1438/* Delete route map set rule. */
d62a17ae 1439int route_map_delete_set(struct route_map_index *index, const char *set_name,
1440 const char *set_arg)
1441{
1442 struct route_map_rule *rule;
1443 struct route_map_rule_cmd *cmd;
1444
1445 cmd = route_map_lookup_set(set_name);
1446 if (cmd == NULL)
1447 return 1;
1448
1449 for (rule = index->set_list.head; rule; rule = rule->next)
9d303b37
DL
1450 if ((rule->cmd == cmd) && (rulecmp(rule->rule_str, set_arg) == 0
1451 || set_arg == NULL)) {
d62a17ae 1452 route_map_rule_delete(&index->set_list, rule);
1453 /* Execute event hook. */
1454 if (route_map_master.event_hook) {
1455 (*route_map_master.event_hook)(
1456 RMAP_EVENT_SET_DELETED,
1457 index->map->name);
1458 route_map_notify_dependencies(
1459 index->map->name,
1460 RMAP_EVENT_CALL_ADDED);
1461 }
1462 return 0;
1463 }
1464 /* Can't find matched rule. */
1465 return 1;
718e3744 1466}
1467
3bf1c917 1468/* Apply route map's each index to the object.
1469
1470 The matrix for a route-map looks like this:
1471 (note, this includes the description for the "NEXT"
1472 and "GOTO" frobs now
d62a17ae 1473
1474 Match | No Match
1475 |
3bf1c917 1476 permit action | cont
d62a17ae 1477 |
3bf1c917 1478 ------------------+---------------
d62a17ae 1479 |
3bf1c917 1480 deny deny | cont
d62a17ae 1481 |
1482
fee0f4c6 1483 action)
1484 -Apply Set statements, accept route
1485 -If Call statement is present jump to the specified route-map, if it
d62a17ae 1486 denies the route we finish.
fee0f4c6 1487 -If NEXT is specified, goto NEXT statement
1488 -If GOTO is specified, goto the first clause where pref > nextpref
1489 -If nothing is specified, do as Cisco and finish
1490 deny)
1491 -Route is denied by route-map.
1492 cont)
1493 -Goto Next index
d62a17ae 1494
3bf1c917 1495 If we get no matches after we've processed all updates, then the route
1496 is dropped too.
d62a17ae 1497
fee0f4c6 1498 Some notes on the new "CALL", "NEXT" and "GOTO"
1499 call WORD - If this clause is matched, then the set statements
d62a17ae 1500 are executed and then we jump to route-map 'WORD'. If
1501 this route-map denies the route, we finish, in other
1502 case we
1503 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
3bf1c917 1504 on-match next - If this clause is matched, then the set statements
d62a17ae 1505 are executed and then we drop through to the next clause
3bf1c917 1506 on-match goto n - If this clause is matched, then the set statments
d62a17ae 1507 are executed and then we goto the nth clause, or the
1508 first clause greater than this. In order to ensure
1509 route-maps *always* exit, you cannot jump backwards.
1510 Sorry ;)
1511
3bf1c917 1512 We need to make sure our route-map processing matches the above
718e3744 1513*/
3bf1c917 1514
8cc4198f 1515static route_map_result_t
d62a17ae 1516route_map_apply_match(struct route_map_rule_list *match_list,
123214ef 1517 const struct prefix *prefix, route_map_object_t type,
d62a17ae 1518 void *object)
1519{
1520 route_map_result_t ret = RMAP_NOMATCH;
1521 struct route_map_rule *match;
1522
1523
1524 /* Check all match rule and if there is no match rule, go to the
1525 set statement. */
1526 if (!match_list->head)
1527 ret = RMAP_MATCH;
1528 else {
1529 for (match = match_list->head; match; match = match->next) {
1530 /* Try each match statement in turn, If any do not
1531 return
1532 RMAP_MATCH, return, otherwise continue on to next
1533 match
1534 statement. All match statements must match for
1535 end-result
1536 to be a match. */
1537 ret = (*match->cmd->func_apply)(match->value, prefix,
1538 type, object);
1539 if (ret != RMAP_MATCH)
1540 return ret;
1541 }
1542 }
1543 return ret;
718e3744 1544}
1545
1546/* Apply route map to the object. */
123214ef
MS
1547route_map_result_t route_map_apply(struct route_map *map,
1548 const struct prefix *prefix,
d62a17ae 1549 route_map_object_t type, void *object)
1550{
1551 static int recursion = 0;
1552 int ret = 0;
1553 struct route_map_index *index;
1554 struct route_map_rule *set;
1555
1556 if (recursion > RMAP_RECURSION_LIMIT) {
040c7c3a 1557 flog_warn(
450971aa 1558 EC_LIB_RMAP_RECURSION_LIMIT,
d62a17ae 1559 "route-map recursion limit (%d) reached, discarding route",
1560 RMAP_RECURSION_LIMIT);
1561 recursion = 0;
1562 return RMAP_DENYMATCH;
1563 }
1564
1565 if (map == NULL)
1566 return RMAP_DENYMATCH;
1567
279b0607 1568 map->applied++;
d62a17ae 1569 for (index = map->head; index; index = index->next) {
1570 /* Apply this index. */
279b0607 1571 index->applied++;
d62a17ae 1572 ret = route_map_apply_match(&index->match_list, prefix, type,
1573 object);
1574
1575 /* Now we apply the matrix from above */
1576 if (ret == RMAP_NOMATCH)
1577 /* 'cont' from matrix - continue to next route-map
1578 * sequence */
1579 continue;
1580 else if (ret == RMAP_MATCH) {
1581 if (index->type == RMAP_PERMIT)
1582 /* 'action' */
1583 {
1584 /* permit+match must execute sets */
1585 for (set = index->set_list.head; set;
1586 set = set->next)
1587 ret = (*set->cmd->func_apply)(
1588 set->value, prefix, type,
1589 object);
1590
1591 /* Call another route-map if available */
1592 if (index->nextrm) {
1593 struct route_map *nextrm =
1594 route_map_lookup_by_name(
1595 index->nextrm);
1596
1597 if (nextrm) /* Target route-map found,
1598 jump to it */
1599 {
1600 recursion++;
1601 ret = route_map_apply(
1602 nextrm, prefix, type,
1603 object);
1604 recursion--;
1605 }
1606
1607 /* If nextrm returned 'deny', finish. */
1608 if (ret == RMAP_DENYMATCH)
1609 return ret;
1610 }
1611
1612 switch (index->exitpolicy) {
1613 case RMAP_EXIT:
1614 return ret;
1615 case RMAP_NEXT:
1616 continue;
1617 case RMAP_GOTO: {
1618 /* Find the next clause to jump to */
1619 struct route_map_index *next =
1620 index->next;
1621 int nextpref = index->nextpref;
1622
1623 while (next && next->pref < nextpref) {
1624 index = next;
1625 next = next->next;
1626 }
1627 if (next == NULL) {
1628 /* No clauses match! */
1629 return ret;
1630 }
1631 }
1632 }
1633 } else if (index->type == RMAP_DENY)
1634 /* 'deny' */
1635 {
1636 return RMAP_DENYMATCH;
1637 }
1638 }
1639 }
1640 /* Finally route-map does not match at all. */
1641 return RMAP_DENYMATCH;
1642}
1643
1644void route_map_add_hook(void (*func)(const char *))
1645{
1646 route_map_master.add_hook = func;
1647}
1648
1649void route_map_delete_hook(void (*func)(const char *))
1650{
1651 route_map_master.delete_hook = func;
1652}
1653
1654void route_map_event_hook(void (*func)(route_map_event_t, const char *))
1655{
1656 route_map_master.event_hook = func;
718e3744 1657}
1658
518f0eb1 1659/* Routines for route map dependency lists and dependency processing */
74df8d6d 1660static bool route_map_rmap_hash_cmp(const void *p1, const void *p2)
518f0eb1 1661{
d62a17ae 1662 return (strcmp((const char *)p1, (const char *)p2) == 0);
518f0eb1
DS
1663}
1664
74df8d6d 1665static bool route_map_dep_hash_cmp(const void *p1, const void *p2)
518f0eb1
DS
1666{
1667
d62a17ae 1668 return (strcmp(((const struct route_map_dep *)p1)->dep_name,
1669 (const char *)p2)
1670 == 0);
518f0eb1
DS
1671}
1672
e3b78da8 1673static void route_map_clear_reference(struct hash_bucket *bucket, void *arg)
518f0eb1 1674{
e3b78da8 1675 struct route_map_dep *dep = (struct route_map_dep *)bucket->data;
d62a17ae 1676 char *rmap_name;
518f0eb1 1677
1fae5ff2 1678 if (arg) {
d62a17ae 1679 rmap_name =
1680 (char *)hash_release(dep->dep_rmap_hash, (void *)arg);
1681 if (rmap_name) {
1682 XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
1683 }
1684 if (!dep->dep_rmap_hash->count) {
1685 dep = hash_release(dep->this_hash,
1686 (void *)dep->dep_name);
1687 hash_free(dep->dep_rmap_hash);
1688 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
1689 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
1690 }
518f0eb1 1691 }
d62a17ae 1692}
1693
1694static void route_map_clear_all_references(char *rmap_name)
1695{
1696 int i;
1697
1698 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
1699 hash_iterate(route_map_dep_hash[i], route_map_clear_reference,
1700 (void *)rmap_name);
518f0eb1 1701 }
518f0eb1
DS
1702}
1703
d62a17ae 1704static void *route_map_dep_hash_alloc(void *p)
518f0eb1 1705{
d62a17ae 1706 char *dep_name = (char *)p;
1707 struct route_map_dep *dep_entry;
1708
1709 dep_entry = XCALLOC(MTYPE_ROUTE_MAP_DEP, sizeof(struct route_map_dep));
1710 dep_entry->dep_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
996c9314
LB
1711 dep_entry->dep_rmap_hash =
1712 hash_create_size(8, route_map_dep_hash_make_key,
1713 route_map_rmap_hash_cmp, "Route Map Dep Hash");
d62a17ae 1714 dep_entry->this_hash = NULL;
1715
1716 return ((void *)dep_entry);
1717}
518f0eb1 1718
d62a17ae 1719static void *route_map_name_hash_alloc(void *p)
1720{
1721 return ((void *)XSTRDUP(MTYPE_ROUTE_MAP_NAME, (const char *)p));
518f0eb1
DS
1722}
1723
d62a17ae 1724static unsigned int route_map_dep_hash_make_key(void *p)
518f0eb1 1725{
d62a17ae 1726 return (string_hash_make((char *)p));
1727}
518f0eb1 1728
e3b78da8 1729static void route_map_print_dependency(struct hash_bucket *bucket, void *data)
d62a17ae 1730{
e3b78da8 1731 char *rmap_name = (char *)bucket->data;
d62a17ae 1732 char *dep_name = (char *)data;
518f0eb1 1733
1fae5ff2
DS
1734 zlog_debug("%s: Dependency for %s: %s", __FUNCTION__, dep_name,
1735 rmap_name);
518f0eb1
DS
1736}
1737
d62a17ae 1738static int route_map_dep_update(struct hash *dephash, const char *dep_name,
1739 const char *rmap_name, route_map_event_t type)
518f0eb1 1740{
d62a17ae 1741 struct route_map_dep *dep = NULL;
1742 char *ret_map_name;
1743 char *dname, *rname;
1744 int ret = 0;
1745
1746 dname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
1747 rname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_name);
1748
1749 switch (type) {
1750 case RMAP_EVENT_PLIST_ADDED:
1751 case RMAP_EVENT_CLIST_ADDED:
1752 case RMAP_EVENT_ECLIST_ADDED:
1753 case RMAP_EVENT_ASLIST_ADDED:
1754 case RMAP_EVENT_LLIST_ADDED:
1755 case RMAP_EVENT_CALL_ADDED:
1756 case RMAP_EVENT_FILTER_ADDED:
1757 if (rmap_debug)
1758 zlog_debug("%s: Adding dependency for %s in %s",
1759 __FUNCTION__, dep_name, rmap_name);
1760 dep = (struct route_map_dep *)hash_get(
1761 dephash, dname, route_map_dep_hash_alloc);
1762 if (!dep) {
1763 ret = -1;
1764 goto out;
1765 }
1766
1767 if (!dep->this_hash)
1768 dep->this_hash = dephash;
1769
1770 hash_get(dep->dep_rmap_hash, rname, route_map_name_hash_alloc);
1771 break;
1772 case RMAP_EVENT_PLIST_DELETED:
1773 case RMAP_EVENT_CLIST_DELETED:
1774 case RMAP_EVENT_ECLIST_DELETED:
1775 case RMAP_EVENT_ASLIST_DELETED:
1776 case RMAP_EVENT_LLIST_DELETED:
1777 case RMAP_EVENT_CALL_DELETED:
1778 case RMAP_EVENT_FILTER_DELETED:
1779 if (rmap_debug)
1780 zlog_debug("%s: Deleting dependency for %s in %s",
1781 __FUNCTION__, dep_name, rmap_name);
1782 dep = (struct route_map_dep *)hash_get(dephash, dname, NULL);
1783 if (!dep) {
1784 goto out;
1785 }
1786
1787 ret_map_name = (char *)hash_release(dep->dep_rmap_hash, rname);
0a22ddfb 1788 XFREE(MTYPE_ROUTE_MAP_NAME, ret_map_name);
d62a17ae 1789
1790 if (!dep->dep_rmap_hash->count) {
1791 dep = hash_release(dephash, dname);
1792 hash_free(dep->dep_rmap_hash);
1793 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
1794 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
1795 dep = NULL;
1796 }
1797 break;
1798 default:
1799 break;
1800 }
1801
1802 if (dep) {
1803 if (rmap_debug)
1804 hash_iterate(dep->dep_rmap_hash,
1805 route_map_print_dependency, dname);
1806 }
1807
1808out:
1809 XFREE(MTYPE_ROUTE_MAP_NAME, rname);
1810 XFREE(MTYPE_ROUTE_MAP_NAME, dname);
1811 return ret;
1812}
1813
1814static struct hash *route_map_get_dep_hash(route_map_event_t event)
1815{
1816 struct hash *upd8_hash = NULL;
1817
1818 switch (event) {
1819 case RMAP_EVENT_PLIST_ADDED:
1820 case RMAP_EVENT_PLIST_DELETED:
1821 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_PLIST];
1822 break;
1823 case RMAP_EVENT_CLIST_ADDED:
1824 case RMAP_EVENT_CLIST_DELETED:
1825 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_CLIST];
1826 break;
1827 case RMAP_EVENT_ECLIST_ADDED:
1828 case RMAP_EVENT_ECLIST_DELETED:
1829 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ECLIST];
1830 break;
1831 case RMAP_EVENT_ASLIST_ADDED:
1832 case RMAP_EVENT_ASLIST_DELETED:
1833 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ASPATH];
1834 break;
1835 case RMAP_EVENT_LLIST_ADDED:
1836 case RMAP_EVENT_LLIST_DELETED:
1837 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_LCLIST];
1838 break;
1839 case RMAP_EVENT_CALL_ADDED:
1840 case RMAP_EVENT_CALL_DELETED:
0f8cf61a 1841 case RMAP_EVENT_MATCH_ADDED:
1842 case RMAP_EVENT_MATCH_DELETED:
d62a17ae 1843 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_RMAP];
1844 break;
1845 case RMAP_EVENT_FILTER_ADDED:
1846 case RMAP_EVENT_FILTER_DELETED:
1847 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_FILTER];
1848 break;
1849 default:
1850 upd8_hash = NULL;
1851 break;
1852 }
1853 return (upd8_hash);
518f0eb1
DS
1854}
1855
e3b78da8 1856static void route_map_process_dependency(struct hash_bucket *bucket, void *data)
518f0eb1 1857{
e3b78da8 1858 char *rmap_name = (char *)bucket->data;
d62a17ae 1859 route_map_event_t type = (route_map_event_t)(ptrdiff_t)data;
1860
1fae5ff2
DS
1861 if (rmap_debug)
1862 zlog_debug("%s: Notifying %s of dependency",
1863 __FUNCTION__, rmap_name);
1864 if (route_map_master.event_hook)
1865 (*route_map_master.event_hook)(type, rmap_name);
518f0eb1
DS
1866}
1867
d62a17ae 1868void route_map_upd8_dependency(route_map_event_t type, const char *arg,
1869 const char *rmap_name)
518f0eb1 1870{
d62a17ae 1871 struct hash *upd8_hash = NULL;
518f0eb1 1872
fdf823db 1873 if ((upd8_hash = route_map_get_dep_hash(type))) {
d62a17ae 1874 route_map_dep_update(upd8_hash, arg, rmap_name, type);
fdf823db
NT
1875
1876 if (type == RMAP_EVENT_CALL_ADDED) {
1877 /* Execute hook. */
1878 if (route_map_master.add_hook)
1879 (*route_map_master.add_hook)(rmap_name);
1880 } else if (type == RMAP_EVENT_CALL_DELETED) {
1881 /* Execute hook. */
1882 if (route_map_master.delete_hook)
1883 (*route_map_master.delete_hook)(rmap_name);
1884 }
1885 }
518f0eb1
DS
1886}
1887
d62a17ae 1888void route_map_notify_dependencies(const char *affected_name,
1889 route_map_event_t event)
518f0eb1 1890{
d62a17ae 1891 struct route_map_dep *dep;
1892 struct hash *upd8_hash;
1893 char *name;
1894
1895 if (!affected_name)
1896 return;
1897
1898 name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, affected_name);
1899
1900 if ((upd8_hash = route_map_get_dep_hash(event)) == NULL) {
1901 XFREE(MTYPE_ROUTE_MAP_NAME, name);
1902 return;
518f0eb1 1903 }
d62a17ae 1904
1905 dep = (struct route_map_dep *)hash_get(upd8_hash, name, NULL);
1906 if (dep) {
1907 if (!dep->this_hash)
1908 dep->this_hash = upd8_hash;
1909
1910 hash_iterate(dep->dep_rmap_hash, route_map_process_dependency,
1911 (void *)event);
1912 }
1913
1914 XFREE(MTYPE_ROUTE_MAP_NAME, name);
518f0eb1
DS
1915}
1916
82f97584 1917
718e3744 1918/* VTY related functions. */
82f97584
DW
1919DEFUN (match_interface,
1920 match_interface_cmd,
1921 "match interface WORD",
1922 MATCH_STR
1923 "match first hop interface of route\n"
1924 "Interface name\n")
1925{
d62a17ae 1926 int idx_word = 2;
1927 VTY_DECLVAR_CONTEXT(route_map_index, index);
82f97584 1928
d62a17ae 1929 if (rmap_match_set_hook.match_interface)
1930 return rmap_match_set_hook.match_interface(
1931 vty, index, "interface", argv[idx_word]->arg,
1932 RMAP_EVENT_MATCH_ADDED);
1933 return CMD_SUCCESS;
82f97584
DW
1934}
1935
1936DEFUN (no_match_interface,
1937 no_match_interface_cmd,
70d44c5c 1938 "no match interface [WORD]",
82f97584
DW
1939 NO_STR
1940 MATCH_STR
1941 "Match first hop interface of route\n"
1942 "Interface name\n")
1943{
d62a17ae 1944 char *iface = (argc == 4) ? argv[3]->arg : NULL;
1945 VTY_DECLVAR_CONTEXT(route_map_index, index);
82f97584 1946
d62a17ae 1947 if (rmap_match_set_hook.no_match_interface)
1948 return rmap_match_set_hook.no_match_interface(
1949 vty, index, "interface", iface,
1950 RMAP_EVENT_MATCH_DELETED);
1951 return CMD_SUCCESS;
82f97584
DW
1952}
1953
1954
1955DEFUN (match_ip_address,
1956 match_ip_address_cmd,
1957 "match ip address <(1-199)|(1300-2699)|WORD>",
1958 MATCH_STR
1959 IP_STR
1960 "Match address of route\n"
1961 "IP access-list number\n"
1962 "IP access-list number (expanded range)\n"
1963 "IP Access-list name\n")
1964{
d62a17ae 1965 int idx_acl = 3;
1966 VTY_DECLVAR_CONTEXT(route_map_index, index);
82f97584 1967
d62a17ae 1968 if (rmap_match_set_hook.match_ip_address)
1969 return rmap_match_set_hook.match_ip_address(
1970 vty, index, "ip address", argv[idx_acl]->arg,
1971 RMAP_EVENT_FILTER_ADDED);
1972 return CMD_SUCCESS;
82f97584
DW
1973}
1974
1975
1976DEFUN (no_match_ip_address,
1977 no_match_ip_address_cmd,
1978 "no match ip address [<(1-199)|(1300-2699)|WORD>]",
1979 NO_STR
1980 MATCH_STR
1981 IP_STR
1982 "Match address of route\n"
1983 "IP access-list number\n"
1984 "IP access-list number (expanded range)\n"
1985 "IP Access-list name\n")
1986{
d62a17ae 1987 int idx_word = 4;
1988 VTY_DECLVAR_CONTEXT(route_map_index, index);
1989
1990 if (rmap_match_set_hook.no_match_ip_address) {
1991 if (argc <= idx_word)
1992 return rmap_match_set_hook.no_match_ip_address(
1993 vty, index, "ip address", NULL,
1994 RMAP_EVENT_FILTER_DELETED);
1995 return rmap_match_set_hook.no_match_ip_address(
1996 vty, index, "ip address", argv[idx_word]->arg,
1997 RMAP_EVENT_FILTER_DELETED);
1998 }
1999 return CMD_SUCCESS;
82f97584
DW
2000}
2001
2002
2003DEFUN (match_ip_address_prefix_list,
2004 match_ip_address_prefix_list_cmd,
2005 "match ip address prefix-list WORD",
2006 MATCH_STR
2007 IP_STR
2008 "Match address of route\n"
2009 "Match entries of prefix-lists\n"
2010 "IP prefix-list name\n")
2011{
d62a17ae 2012 int idx_word = 4;
2013 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2014
d62a17ae 2015 if (rmap_match_set_hook.match_ip_address_prefix_list)
2016 return rmap_match_set_hook.match_ip_address_prefix_list(
2017 vty, index, "ip address prefix-list",
2018 argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
2019 return CMD_SUCCESS;
82f97584
DW
2020}
2021
2022
2023DEFUN (no_match_ip_address_prefix_list,
2024 no_match_ip_address_prefix_list_cmd,
2025 "no match ip address prefix-list [WORD]",
2026 NO_STR
2027 MATCH_STR
2028 IP_STR
2029 "Match address of route\n"
2030 "Match entries of prefix-lists\n"
2031 "IP prefix-list name\n")
2032{
d62a17ae 2033 int idx_word = 5;
2034 VTY_DECLVAR_CONTEXT(route_map_index, index);
2035
2036 if (rmap_match_set_hook.no_match_ip_address_prefix_list) {
2037 if (argc <= idx_word)
2038 return rmap_match_set_hook
2039 .no_match_ip_address_prefix_list(
2040 vty, index, "ip address prefix-list",
2041 NULL, RMAP_EVENT_PLIST_DELETED);
2042 return rmap_match_set_hook.no_match_ip_address_prefix_list(
2043 vty, index, "ip address prefix-list",
2044 argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
2045 }
2046 return CMD_SUCCESS;
82f97584
DW
2047}
2048
2049
2050DEFUN (match_ip_next_hop,
2051 match_ip_next_hop_cmd,
2052 "match ip next-hop <(1-199)|(1300-2699)|WORD>",
2053 MATCH_STR
2054 IP_STR
2055 "Match next-hop address of route\n"
2056 "IP access-list number\n"
2057 "IP access-list number (expanded range)\n"
2058 "IP Access-list name\n")
2059{
d62a17ae 2060 int idx_acl = 3;
2061 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2062
d62a17ae 2063 if (rmap_match_set_hook.match_ip_next_hop)
2064 return rmap_match_set_hook.match_ip_next_hop(
2065 vty, index, "ip next-hop", argv[idx_acl]->arg,
2066 RMAP_EVENT_FILTER_ADDED);
2067 return CMD_SUCCESS;
82f97584
DW
2068}
2069
2070
2071DEFUN (no_match_ip_next_hop,
2072 no_match_ip_next_hop_cmd,
2073 "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
2074 NO_STR
2075 MATCH_STR
2076 IP_STR
2077 "Match next-hop address of route\n"
2078 "IP access-list number\n"
2079 "IP access-list number (expanded range)\n"
2080 "IP Access-list name\n")
2081{
d62a17ae 2082 int idx_word = 4;
2083 VTY_DECLVAR_CONTEXT(route_map_index, index);
2084
2085 if (rmap_match_set_hook.no_match_ip_next_hop) {
2086 if (argc <= idx_word)
2087 return rmap_match_set_hook.no_match_ip_next_hop(
2088 vty, index, "ip next-hop", NULL,
2089 RMAP_EVENT_FILTER_DELETED);
2090 return rmap_match_set_hook.no_match_ip_next_hop(
2091 vty, index, "ip next-hop", argv[idx_word]->arg,
2092 RMAP_EVENT_FILTER_DELETED);
2093 }
2094 return CMD_SUCCESS;
82f97584
DW
2095}
2096
2097
2098DEFUN (match_ip_next_hop_prefix_list,
2099 match_ip_next_hop_prefix_list_cmd,
2100 "match ip next-hop prefix-list WORD",
2101 MATCH_STR
2102 IP_STR
2103 "Match next-hop address of route\n"
2104 "Match entries of prefix-lists\n"
2105 "IP prefix-list name\n")
2106{
d62a17ae 2107 int idx_word = 4;
2108 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2109
d62a17ae 2110 if (rmap_match_set_hook.match_ip_next_hop_prefix_list)
2111 return rmap_match_set_hook.match_ip_next_hop_prefix_list(
2112 vty, index, "ip next-hop prefix-list",
2113 argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
2114 return CMD_SUCCESS;
82f97584
DW
2115}
2116
2117DEFUN (no_match_ip_next_hop_prefix_list,
2118 no_match_ip_next_hop_prefix_list_cmd,
2119 "no match ip next-hop prefix-list [WORD]",
2120 NO_STR
2121 MATCH_STR
2122 IP_STR
2123 "Match next-hop address of route\n"
2124 "Match entries of prefix-lists\n"
2125 "IP prefix-list name\n")
2126{
d62a17ae 2127 int idx_word = 5;
2128 VTY_DECLVAR_CONTEXT(route_map_index, index);
2129
2130 if (rmap_match_set_hook.no_match_ip_next_hop) {
2131 if (argc <= idx_word)
2132 return rmap_match_set_hook.no_match_ip_next_hop(
2133 vty, index, "ip next-hop prefix-list", NULL,
2134 RMAP_EVENT_PLIST_DELETED);
2135 return rmap_match_set_hook.no_match_ip_next_hop(
2136 vty, index, "ip next-hop prefix-list",
2137 argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
2138 }
2139 return CMD_SUCCESS;
82f97584
DW
2140}
2141
61ad901e
DA
2142DEFUN(match_ip_next_hop_type, match_ip_next_hop_type_cmd,
2143 "match ip next-hop type <blackhole>",
2144 MATCH_STR IP_STR
2145 "Match next-hop address of route\n"
2146 "Match entries by type\n"
2147 "Blackhole\n")
2148{
2149 int idx_word = 4;
2150 VTY_DECLVAR_CONTEXT(route_map_index, index);
2151
2152 if (rmap_match_set_hook.match_ip_next_hop_type)
2153 return rmap_match_set_hook.match_ip_next_hop_type(
2154 vty, index, "ip next-hop type", argv[idx_word]->arg,
2155 RMAP_EVENT_MATCH_ADDED);
2156 return CMD_SUCCESS;
2157}
2158
2159DEFUN(no_match_ip_next_hop_type, no_match_ip_next_hop_type_cmd,
2160 "no match ip next-hop type [<blackhole>]",
2161 NO_STR MATCH_STR IP_STR
2162 "Match next-hop address of route\n"
2163 "Match entries by type\n"
2164 "Blackhole\n")
2165{
2166 int idx_word = 5;
2167 VTY_DECLVAR_CONTEXT(route_map_index, index);
2168
2169 if (rmap_match_set_hook.no_match_ip_next_hop) {
2170 if (argc <= idx_word)
2171 return rmap_match_set_hook.no_match_ip_next_hop(
2172 vty, index, "ip next-hop type", NULL,
2173 RMAP_EVENT_MATCH_DELETED);
2174 return rmap_match_set_hook.no_match_ip_next_hop(
2175 vty, index, "ip next-hop type", argv[idx_word]->arg,
2176 RMAP_EVENT_MATCH_DELETED);
2177 }
2178 return CMD_SUCCESS;
2179}
2180
82f97584
DW
2181
2182DEFUN (match_ipv6_address,
2183 match_ipv6_address_cmd,
2184 "match ipv6 address WORD",
2185 MATCH_STR
2186 IPV6_STR
2187 "Match IPv6 address of route\n"
2188 "IPv6 access-list name\n")
2189{
d62a17ae 2190 int idx_word = 3;
2191 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2192
d62a17ae 2193 if (rmap_match_set_hook.match_ipv6_address)
2194 return rmap_match_set_hook.match_ipv6_address(
2195 vty, index, "ipv6 address", argv[idx_word]->arg,
2196 RMAP_EVENT_FILTER_ADDED);
2197 return CMD_SUCCESS;
82f97584
DW
2198}
2199
2200DEFUN (no_match_ipv6_address,
2201 no_match_ipv6_address_cmd,
2202 "no match ipv6 address WORD",
2203 NO_STR
2204 MATCH_STR
2205 IPV6_STR
2206 "Match IPv6 address of route\n"
2207 "IPv6 access-list name\n")
2208{
d62a17ae 2209 int idx_word = 4;
2210 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2211
d62a17ae 2212 if (rmap_match_set_hook.no_match_ipv6_address)
2213 return rmap_match_set_hook.no_match_ipv6_address(
2214 vty, index, "ipv6 address", argv[idx_word]->arg,
2215 RMAP_EVENT_FILTER_DELETED);
2216 return CMD_SUCCESS;
82f97584
DW
2217}
2218
2219
2220DEFUN (match_ipv6_address_prefix_list,
2221 match_ipv6_address_prefix_list_cmd,
2222 "match ipv6 address prefix-list WORD",
2223 MATCH_STR
2224 IPV6_STR
2225 "Match address of route\n"
2226 "Match entries of prefix-lists\n"
2227 "IP prefix-list name\n")
2228{
d62a17ae 2229 int idx_word = 4;
2230 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2231
d62a17ae 2232 if (rmap_match_set_hook.match_ipv6_address_prefix_list)
2233 return rmap_match_set_hook.match_ipv6_address_prefix_list(
2234 vty, index, "ipv6 address prefix-list",
2235 argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
2236 return CMD_SUCCESS;
82f97584
DW
2237}
2238
2239DEFUN (no_match_ipv6_address_prefix_list,
2240 no_match_ipv6_address_prefix_list_cmd,
2241 "no match ipv6 address prefix-list WORD",
2242 NO_STR
2243 MATCH_STR
2244 IPV6_STR
2245 "Match address of route\n"
2246 "Match entries of prefix-lists\n"
2247 "IP prefix-list name\n")
2248{
d62a17ae 2249 int idx_word = 5;
2250 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2251
d62a17ae 2252 if (rmap_match_set_hook.no_match_ipv6_address_prefix_list)
2253 return rmap_match_set_hook.no_match_ipv6_address_prefix_list(
2254 vty, index, "ipv6 address prefix-list",
2255 argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
2256 return CMD_SUCCESS;
82f97584
DW
2257}
2258
61ad901e
DA
2259DEFUN(match_ipv6_next_hop_type, match_ipv6_next_hop_type_cmd,
2260 "match ipv6 next-hop type <blackhole>",
2261 MATCH_STR IPV6_STR
35342575 2262 "Match next-hop address of route\n"
61ad901e
DA
2263 "Match entries by type\n"
2264 "Blackhole\n")
2265{
2266 int idx_word = 4;
2267 VTY_DECLVAR_CONTEXT(route_map_index, index);
2268
2269 if (rmap_match_set_hook.match_ipv6_next_hop_type)
2270 return rmap_match_set_hook.match_ipv6_next_hop_type(
2271 vty, index, "ipv6 next-hop type", argv[idx_word]->arg,
2272 RMAP_EVENT_MATCH_ADDED);
2273 return CMD_SUCCESS;
2274}
2275
2276DEFUN(no_match_ipv6_next_hop_type, no_match_ipv6_next_hop_type_cmd,
2277 "no match ipv6 next-hop type [<blackhole>]",
2278 NO_STR MATCH_STR IPV6_STR
2279 "Match address of route\n"
2280 "Match entries by type\n"
2281 "Blackhole\n")
2282{
2283 int idx_word = 5;
2284 VTY_DECLVAR_CONTEXT(route_map_index, index);
2285
2286 if (rmap_match_set_hook.no_match_ipv6_next_hop_type)
2287 return rmap_match_set_hook.no_match_ipv6_next_hop_type(
4cfecc3e
RW
2288 vty, index, "ipv6 next-hop type",
2289 (argc <= idx_word) ? NULL : argv[idx_word]->arg,
61ad901e
DA
2290 RMAP_EVENT_MATCH_DELETED);
2291 return CMD_SUCCESS;
2292}
82f97584
DW
2293
2294DEFUN (match_metric,
2295 match_metric_cmd,
2296 "match metric (0-4294967295)",
2297 MATCH_STR
2298 "Match metric of route\n"
2299 "Metric value\n")
2300{
d62a17ae 2301 int idx_number = 2;
2302 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2303
d62a17ae 2304 if (rmap_match_set_hook.match_metric)
2305 return rmap_match_set_hook.match_metric(vty, index, "metric",
2306 argv[idx_number]->arg,
2307 RMAP_EVENT_MATCH_ADDED);
2308 return CMD_SUCCESS;
82f97584
DW
2309}
2310
2311
2312DEFUN (no_match_metric,
2313 no_match_metric_cmd,
2314 "no match metric [(0-4294967295)]",
2315 NO_STR
2316 MATCH_STR
2317 "Match metric of route\n"
2318 "Metric value\n")
2319{
d62a17ae 2320 int idx_number = 3;
2321 VTY_DECLVAR_CONTEXT(route_map_index, index);
2322
2323 if (rmap_match_set_hook.no_match_metric) {
2324 if (argc <= idx_number)
2325 return rmap_match_set_hook.no_match_metric(
2326 vty, index, "metric", NULL,
2327 RMAP_EVENT_MATCH_DELETED);
2328 return rmap_match_set_hook.no_match_metric(
2329 vty, index, "metric", argv[idx_number]->arg,
2330 RMAP_EVENT_MATCH_DELETED);
2331 }
2332 return CMD_SUCCESS;
82f97584
DW
2333}
2334
2335
2336DEFUN (match_tag,
2337 match_tag_cmd,
e52702f2 2338 "match tag (1-4294967295)",
82f97584
DW
2339 MATCH_STR
2340 "Match tag of route\n"
2341 "Tag value\n")
2342{
d62a17ae 2343 int idx_number = 2;
2344 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2345
d62a17ae 2346 if (rmap_match_set_hook.match_tag)
2347 return rmap_match_set_hook.match_tag(vty, index, "tag",
2348 argv[idx_number]->arg,
2349 RMAP_EVENT_MATCH_ADDED);
2350 return CMD_SUCCESS;
82f97584
DW
2351}
2352
2353
2354DEFUN (no_match_tag,
2355 no_match_tag_cmd,
e52702f2 2356 "no match tag [(1-4294967295)]",
82f97584
DW
2357 NO_STR
2358 MATCH_STR
2359 "Match tag of route\n"
2360 "Tag value\n")
2361{
d62a17ae 2362 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2363
d62a17ae 2364 int idx = 0;
2365 char *arg = argv_find(argv, argc, "(1-4294967295)", &idx)
2366 ? argv[idx]->arg
2367 : NULL;
0d702986 2368
d62a17ae 2369 if (rmap_match_set_hook.no_match_tag)
2370 return rmap_match_set_hook.no_match_tag(
2371 vty, index, "tag", arg, RMAP_EVENT_MATCH_DELETED);
2372 return CMD_SUCCESS;
82f97584
DW
2373}
2374
2375
2376DEFUN (set_ip_nexthop,
2377 set_ip_nexthop_cmd,
2378 "set ip next-hop A.B.C.D",
2379 SET_STR
2380 IP_STR
2381 "Next hop address\n"
2382 "IP address of next hop\n")
2383{
d62a17ae 2384 int idx_ipv4 = 3;
2385 union sockunion su;
2386 int ret;
2387 VTY_DECLVAR_CONTEXT(route_map_index, index);
82f97584 2388
d62a17ae 2389 ret = str2sockunion(argv[idx_ipv4]->arg, &su);
2390 if (ret < 0) {
2391 vty_out(vty, "%% Malformed nexthop address\n");
2392 return CMD_WARNING_CONFIG_FAILED;
2393 }
2394 if (su.sin.sin_addr.s_addr == 0
ae2158fe 2395 || IPV4_CLASS_DE(ntohl(su.sin.sin_addr.s_addr))) {
d62a17ae 2396 vty_out(vty,
2397 "%% nexthop address cannot be 0.0.0.0, multicast or reserved\n");
2398 return CMD_WARNING_CONFIG_FAILED;
2399 }
82f97584 2400
d62a17ae 2401 if (rmap_match_set_hook.set_ip_nexthop)
2402 return rmap_match_set_hook.set_ip_nexthop(
2403 vty, index, "ip next-hop", argv[idx_ipv4]->arg);
2404 return CMD_SUCCESS;
82f97584
DW
2405}
2406
2407
2408DEFUN (no_set_ip_nexthop,
2409 no_set_ip_nexthop_cmd,
89602edb 2410 "no set ip next-hop [A.B.C.D]",
82f97584
DW
2411 NO_STR
2412 SET_STR
3a2d747c 2413 IP_STR
82f97584 2414 "Next hop address\n"
82f97584
DW
2415 "IP address of next hop\n")
2416{
0af35d90 2417 int idx = 0;
d62a17ae 2418 VTY_DECLVAR_CONTEXT(route_map_index, index);
89602edb 2419 const char *arg = NULL;
82f97584 2420
89602edb
QY
2421 if (argv_find(argv, argc, "A.B.C.D", &idx))
2422 arg = argv[idx]->arg;
2423
2424 if (rmap_match_set_hook.no_set_ip_nexthop)
d62a17ae 2425 return rmap_match_set_hook.no_set_ip_nexthop(
89602edb
QY
2426 vty, index, "ip next-hop", arg);
2427
d62a17ae 2428 return CMD_SUCCESS;
82f97584
DW
2429}
2430
2431
2432DEFUN (set_ipv6_nexthop_local,
2433 set_ipv6_nexthop_local_cmd,
2434 "set ipv6 next-hop local X:X::X:X",
2435 SET_STR
2436 IPV6_STR
2437 "IPv6 next-hop address\n"
2438 "IPv6 local address\n"
2439 "IPv6 address of next hop\n")
2440{
d62a17ae 2441 int idx_ipv6 = 4;
2442 struct in6_addr addr;
2443 int ret;
2444 VTY_DECLVAR_CONTEXT(route_map_index, index);
82f97584 2445
d62a17ae 2446 ret = inet_pton(AF_INET6, argv[idx_ipv6]->arg, &addr);
2447 if (!ret) {
2448 vty_out(vty, "%% Malformed nexthop address\n");
2449 return CMD_WARNING_CONFIG_FAILED;
2450 }
2451 if (!IN6_IS_ADDR_LINKLOCAL(&addr)) {
2452 vty_out(vty, "%% Invalid link-local nexthop address\n");
2453 return CMD_WARNING_CONFIG_FAILED;
2454 }
82f97584 2455
d62a17ae 2456 if (rmap_match_set_hook.set_ipv6_nexthop_local)
2457 return rmap_match_set_hook.set_ipv6_nexthop_local(
2458 vty, index, "ipv6 next-hop local", argv[idx_ipv6]->arg);
2459 return CMD_SUCCESS;
82f97584
DW
2460}
2461
2462
2463DEFUN (no_set_ipv6_nexthop_local,
2464 no_set_ipv6_nexthop_local_cmd,
2465 "no set ipv6 next-hop local [X:X::X:X]",
2466 NO_STR
2467 SET_STR
2468 IPV6_STR
2469 "IPv6 next-hop address\n"
2470 "IPv6 local address\n"
2471 "IPv6 address of next hop\n")
2472{
d62a17ae 2473 int idx_ipv6 = 5;
2474 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2475
d62a17ae 2476 if (rmap_match_set_hook.no_set_ipv6_nexthop_local) {
2477 if (argc <= idx_ipv6)
2478 return rmap_match_set_hook.no_set_ipv6_nexthop_local(
2479 vty, index, "ipv6 next-hop local", NULL);
2480 return rmap_match_set_hook.no_set_ipv6_nexthop_local(
2481 vty, index, "ipv6 next-hop local", argv[5]->arg);
2482 }
2483 return CMD_SUCCESS;
82f97584
DW
2484}
2485
2486DEFUN (set_metric,
2487 set_metric_cmd,
2488 "set metric <(0-4294967295)|rtt|+rtt|-rtt|+metric|-metric>",
2489 SET_STR
2490 "Metric value for destination routing protocol\n"
2491 "Metric value\n"
2492 "Assign round trip time\n"
2493 "Add round trip time\n"
2494 "Subtract round trip time\n"
2495 "Add metric\n"
2496 "Subtract metric\n")
2497{
d62a17ae 2498 int idx_number = 2;
2499 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2500
d62a17ae 2501 const char *pass = (argv[idx_number]->type == RANGE_TKN)
2502 ? argv[idx_number]->arg
2503 : argv[idx_number]->text;
af3346ec 2504
d62a17ae 2505 if (rmap_match_set_hook.set_metric)
2506 return rmap_match_set_hook.set_metric(vty, index, "metric",
2507 pass);
2508 return CMD_SUCCESS;
82f97584
DW
2509}
2510
2511
2512DEFUN (no_set_metric,
2513 no_set_metric_cmd,
2514 "no set metric [(0-4294967295)]",
2515 NO_STR
2516 SET_STR
2517 "Metric value for destination routing protocol\n"
2518 "Metric value\n")
2519{
d62a17ae 2520 int idx_number = 3;
2521 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2522
d62a17ae 2523 if (rmap_match_set_hook.no_set_metric) {
2524 if (argc <= idx_number)
2525 return rmap_match_set_hook.no_set_metric(
2526 vty, index, "metric", NULL);
2527 return rmap_match_set_hook.no_set_metric(vty, index, "metric",
2528 argv[idx_number]->arg);
2529 }
2530 return CMD_SUCCESS;
82f97584
DW
2531}
2532
2533
2534DEFUN (set_tag,
2535 set_tag_cmd,
e52702f2 2536 "set tag (1-4294967295)",
82f97584
DW
2537 SET_STR
2538 "Tag value for routing protocol\n"
2539 "Tag value\n")
2540{
d62a17ae 2541 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2542
d62a17ae 2543 int idx_number = 2;
2544 if (rmap_match_set_hook.set_tag)
2545 return rmap_match_set_hook.set_tag(vty, index, "tag",
2546 argv[idx_number]->arg);
2547 return CMD_SUCCESS;
82f97584
DW
2548}
2549
2550
2551DEFUN (no_set_tag,
2552 no_set_tag_cmd,
e52702f2 2553 "no set tag [(1-4294967295)]",
82f97584
DW
2554 NO_STR
2555 SET_STR
2556 "Tag value for routing protocol\n"
2557 "Tag value\n")
2558{
d62a17ae 2559 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2560
d62a17ae 2561 int idx_number = 3;
2562 if (rmap_match_set_hook.no_set_tag) {
2563 if (argc <= idx_number)
2564 return rmap_match_set_hook.no_set_tag(vty, index, "tag",
2565 NULL);
2566 return rmap_match_set_hook.no_set_tag(vty, index, "tag",
2567 argv[idx_number]->arg);
2568 }
2569 return CMD_SUCCESS;
82f97584
DW
2570}
2571
2572
505e5056 2573DEFUN_NOSH (route_map,
718e3744 2574 route_map_cmd,
7fcbbdae 2575 "route-map WORD <deny|permit> (1-65535)",
718e3744 2576 "Create route-map or enter route-map command mode\n"
2577 "Route map tag\n"
2578 "Route map denies set operations\n"
2579 "Route map permits set operations\n"
2580 "Sequence to insert to/delete from existing route-map entry\n")
2581{
d62a17ae 2582 int idx_word = 1;
2583 int idx_permit_deny = 2;
2584 int idx_number = 3;
2585 struct route_map *map;
2586 struct route_map_index *index;
2587 char *endptr = NULL;
2588 int permit =
2589 argv[idx_permit_deny]->arg[0] == 'p' ? RMAP_PERMIT : RMAP_DENY;
2590 unsigned long pref = strtoul(argv[idx_number]->arg, &endptr, 10);
2591 const char *mapname = argv[idx_word]->arg;
718e3744 2592
d62a17ae 2593 /* Get route map. */
2594 map = route_map_get(mapname);
2595 index = route_map_index_get(map, permit, pref);
718e3744 2596
d62a17ae 2597 VTY_PUSH_CONTEXT(RMAP_NODE, index);
2598 return CMD_SUCCESS;
718e3744 2599}
2600
2601DEFUN (no_route_map_all,
2602 no_route_map_all_cmd,
2603 "no route-map WORD",
2604 NO_STR
2605 "Create route-map or enter route-map command mode\n"
2606 "Route map tag\n")
2607{
d62a17ae 2608 int idx_word = 2;
2609 const char *mapname = argv[idx_word]->arg;
2610 struct route_map *map;
718e3744 2611
d62a17ae 2612 map = route_map_lookup_by_name(mapname);
2613 if (map == NULL) {
2614 vty_out(vty, "%% Could not find route-map %s\n", mapname);
2615 return CMD_WARNING_CONFIG_FAILED;
2616 }
718e3744 2617
d62a17ae 2618 route_map_delete(map);
718e3744 2619
d62a17ae 2620 return CMD_SUCCESS;
718e3744 2621}
2622
2623DEFUN (no_route_map,
2624 no_route_map_cmd,
7fcbbdae 2625 "no route-map WORD <deny|permit> (1-65535)",
718e3744 2626 NO_STR
2627 "Create route-map or enter route-map command mode\n"
2628 "Route map tag\n"
2629 "Route map denies set operations\n"
2630 "Route map permits set operations\n"
2631 "Sequence to insert to/delete from existing route-map entry\n")
2632{
d62a17ae 2633 int idx_word = 2;
2634 int idx_permit_deny = 3;
2635 int idx_number = 4;
2636 struct route_map *map;
2637 struct route_map_index *index;
2638 char *endptr = NULL;
2639 int permit = strmatch(argv[idx_permit_deny]->text, "permit")
2640 ? RMAP_PERMIT
2641 : RMAP_DENY;
2642 const char *prefstr = argv[idx_number]->arg;
2643 const char *mapname = argv[idx_word]->arg;
2644 unsigned long pref = strtoul(prefstr, &endptr, 10);
2645
2646 /* Existence check. */
2647 map = route_map_lookup_by_name(mapname);
2648 if (map == NULL) {
2649 vty_out(vty, "%% Could not find route-map %s\n", mapname);
2650 return CMD_WARNING_CONFIG_FAILED;
2651 }
2652
2653 /* Lookup route map index. */
2654 index = route_map_index_lookup(map, permit, pref);
2655 if (index == NULL) {
2656 vty_out(vty, "%% Could not find route-map entry %s %s\n",
2657 mapname, prefstr);
2658 return CMD_WARNING_CONFIG_FAILED;
2659 }
2660
2661 /* Delete index from route map. */
2662 route_map_index_delete(index, 1);
2663
2664 /* If this route rule is the last one, delete route map itself. */
2665 if (route_map_empty(map))
2666 route_map_delete(map);
2667
2668 return CMD_SUCCESS;
718e3744 2669}
2670
2671DEFUN (rmap_onmatch_next,
2672 rmap_onmatch_next_cmd,
2673 "on-match next",
2674 "Exit policy on matches\n"
2675 "Next clause\n")
2676{
d62a17ae 2677 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2678
2679 if (index) {
2680 if (index->type == RMAP_DENY) {
2681 /* Under a deny clause, match means it's finished. No
2682 * need to set next */
2683 vty_out(vty,
2684 "on-match next not supported under route-map deny\n");
2685 return CMD_WARNING_CONFIG_FAILED;
2686 }
2687 index->exitpolicy = RMAP_NEXT;
2688 }
2689 return CMD_SUCCESS;
718e3744 2690}
2691
2692DEFUN (no_rmap_onmatch_next,
2693 no_rmap_onmatch_next_cmd,
2694 "no on-match next",
2695 NO_STR
2696 "Exit policy on matches\n"
2697 "Next clause\n")
2698{
d62a17ae 2699 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2700
2701 if (index)
2702 index->exitpolicy = RMAP_EXIT;
718e3744 2703
d62a17ae 2704 return CMD_SUCCESS;
718e3744 2705}
2706
2707DEFUN (rmap_onmatch_goto,
2708 rmap_onmatch_goto_cmd,
7fcbbdae 2709 "on-match goto (1-65535)",
718e3744 2710 "Exit policy on matches\n"
2711 "Goto Clause number\n"
2712 "Number\n")
2713{
d62a17ae 2714 int idx = 0;
2715 char *num = argv_find(argv, argc, "(1-65535)", &idx) ? argv[idx]->arg
2716 : NULL;
2717
2718 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2719 int d = 0;
2720
2721 if (index) {
2722 if (index->type == RMAP_DENY) {
2723 /* Under a deny clause, match means it's finished. No
2724 * need to go anywhere */
2725 vty_out(vty,
2726 "on-match goto not supported under route-map deny\n");
2727 return CMD_WARNING_CONFIG_FAILED;
2728 }
2729
2730 if (num)
2731 d = strtoul(num, NULL, 10);
2732 else
2733 d = index->pref + 1;
2734
2735 if (d <= index->pref) {
2736 /* Can't allow you to do that, Dave */
2737 vty_out(vty, "can't jump backwards in route-maps\n");
2738 return CMD_WARNING_CONFIG_FAILED;
2739 } else {
2740 index->exitpolicy = RMAP_GOTO;
2741 index->nextpref = d;
2742 }
718e3744 2743 }
d62a17ae 2744 return CMD_SUCCESS;
718e3744 2745}
2746
2747DEFUN (no_rmap_onmatch_goto,
2748 no_rmap_onmatch_goto_cmd,
2749 "no on-match goto",
2750 NO_STR
2751 "Exit policy on matches\n"
fee0f4c6 2752 "Goto Clause number\n")
718e3744 2753{
d62a17ae 2754 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
718e3744 2755
d62a17ae 2756 if (index)
2757 index->exitpolicy = RMAP_EXIT;
2758
2759 return CMD_SUCCESS;
718e3744 2760}
2761
f667a580
QY
2762/* Cisco/GNU Zebra compatibility aliases */
2763/* ALIAS_FIXME */
2764DEFUN (rmap_continue,
2765 rmap_continue_cmd,
2766 "continue (1-65535)",
2767 "Continue on a different entry within the route-map\n"
2768 "Route-map entry sequence number\n")
2769{
d62a17ae 2770 return rmap_onmatch_goto(self, vty, argc, argv);
f667a580 2771}
5510e83b 2772
f667a580
QY
2773/* ALIAS_FIXME */
2774DEFUN (no_rmap_continue,
2775 no_rmap_continue_cmd,
2776 "no continue [(1-65535)]",
2777 NO_STR
2778 "Continue on a different entry within the route-map\n"
2779 "Route-map entry sequence number\n")
2780{
d62a17ae 2781 return no_rmap_onmatch_goto(self, vty, argc, argv);
f667a580 2782}
f412b39a 2783
5510e83b 2784
6d2729e3 2785DEFUN (rmap_show_name,
5510e83b 2786 rmap_show_name_cmd,
7514fb77 2787 "show route-map [WORD]",
5510e83b 2788 SHOW_STR
2789 "route-map information\n"
2790 "route-map name\n")
2791{
d62a17ae 2792 int idx_word = 2;
2793 const char *name = (argc == 3) ? argv[idx_word]->arg : NULL;
2794 return vty_show_route_map(vty, name);
5510e83b 2795}
2796
4a2a09d0 2797DEFUN (rmap_show_unused,
2798 rmap_show_unused_cmd,
2799 "show route-map-unused",
2800 SHOW_STR
2801 "unused route-map information\n")
2802{
2803 return vty_show_unused_route_map(vty);
2804}
2805
fee0f4c6 2806DEFUN (rmap_call,
2807 rmap_call_cmd,
2808 "call WORD",
2809 "Jump to another Route-Map after match+set\n"
2810 "Target route-map name\n")
2811{
d62a17ae 2812 int idx_word = 1;
2813 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2814 const char *rmap = argv[idx_word]->arg;
fee0f4c6 2815
d62a17ae 2816 assert(index);
c01d03a6 2817
1dc02a55
NT
2818 /* If "call" is invoked with the same route-map name as
2819 * the one previously configured then, ignore the duplicate
2820 * configuration.
2821 */
2822 if (index->nextrm && (strcmp(index->nextrm, rmap) == 0))
2823 return CMD_SUCCESS;
2824
d62a17ae 2825 if (index->nextrm) {
2826 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED,
2827 index->nextrm, index->map->name);
2828 XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
2829 }
2830 index->nextrm = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
518f0eb1 2831
d62a17ae 2832 /* Execute event hook. */
2833 route_map_upd8_dependency(RMAP_EVENT_CALL_ADDED, index->nextrm,
2834 index->map->name);
2835 return CMD_SUCCESS;
fee0f4c6 2836}
2837
2838DEFUN (no_rmap_call,
2839 no_rmap_call_cmd,
2840 "no call",
2841 NO_STR
2842 "Jump to another Route-Map after match+set\n")
2843{
d62a17ae 2844 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
fee0f4c6 2845
d62a17ae 2846 if (index->nextrm) {
2847 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED,
2848 index->nextrm, index->map->name);
2849 XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
2850 index->nextrm = NULL;
2851 }
fee0f4c6 2852
d62a17ae 2853 return CMD_SUCCESS;
fee0f4c6 2854}
2855
4a8164e5 2856DEFUN (rmap_description,
2857 rmap_description_cmd,
7fcbbdae 2858 "description LINE...",
4a8164e5 2859 "Route-map comment\n"
2860 "Comment describing this route-map rule\n")
2861{
d62a17ae 2862 int idx_line = 1;
2863 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
4a8164e5 2864
d62a17ae 2865 if (index) {
2866 if (index->description)
2867 XFREE(MTYPE_TMP, index->description);
2868 index->description = argv_concat(argv, argc, idx_line);
2869 }
2870 return CMD_SUCCESS;
4a8164e5 2871}
2872
2873DEFUN (no_rmap_description,
2874 no_rmap_description_cmd,
2875 "no description",
2876 NO_STR
2877 "Route-map comment\n")
2878{
d62a17ae 2879 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
4a8164e5 2880
d62a17ae 2881 if (index) {
2882 if (index->description)
2883 XFREE(MTYPE_TMP, index->description);
2884 index->description = NULL;
2885 }
2886 return CMD_SUCCESS;
4a8164e5 2887}
2888
718e3744 2889/* Configuration write function. */
d62a17ae 2890static int route_map_config_write(struct vty *vty)
2891{
2892 struct route_map *map;
2893 struct route_map_index *index;
2894 struct route_map_rule *rule;
2895 int first = 1;
2896 int write = 0;
2897
2898 for (map = route_map_master.head; map; map = map->next)
2899 for (index = map->head; index; index = index->next) {
2900 if (!first)
2901 vty_out(vty, "!\n");
2902 else
2903 first = 0;
2904
2905 vty_out(vty, "route-map %s %s %d\n", map->name,
2906 route_map_type_str(index->type), index->pref);
2907
2908 if (index->description)
2909 vty_out(vty, " description %s\n",
2910 index->description);
2911
2912 for (rule = index->match_list.head; rule;
2913 rule = rule->next)
2914 vty_out(vty, " match %s %s\n", rule->cmd->str,
2915 rule->rule_str ? rule->rule_str : "");
2916
2917 for (rule = index->set_list.head; rule;
2918 rule = rule->next)
2919 vty_out(vty, " set %s %s\n", rule->cmd->str,
2920 rule->rule_str ? rule->rule_str : "");
2921 if (index->nextrm)
2922 vty_out(vty, " call %s\n", index->nextrm);
2923 if (index->exitpolicy == RMAP_GOTO)
2924 vty_out(vty, " on-match goto %d\n",
2925 index->nextpref);
2926 if (index->exitpolicy == RMAP_NEXT)
2927 vty_out(vty, " on-match next\n");
2928
2929 write++;
2930 }
2931 return write;
718e3744 2932}
2933
2934/* Route map node structure. */
d62a17ae 2935static struct cmd_node rmap_node = {RMAP_NODE, "%s(config-route-map)# ", 1};
718e3744 2936
dc9ffce8
CF
2937/* Common route map rules */
2938
d62a17ae 2939void *route_map_rule_tag_compile(const char *arg)
dc9ffce8 2940{
d62a17ae 2941 unsigned long int tmp;
2942 char *endptr;
2943 route_tag_t *tag;
dc9ffce8 2944
d62a17ae 2945 errno = 0;
2946 tmp = strtoul(arg, &endptr, 0);
2947 if (arg[0] == '\0' || *endptr != '\0' || errno || tmp > ROUTE_TAG_MAX)
2948 return NULL;
dc9ffce8 2949
d62a17ae 2950 tag = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*tag));
2951 *tag = tmp;
dc9ffce8 2952
d62a17ae 2953 return tag;
dc9ffce8
CF
2954}
2955
d62a17ae 2956void route_map_rule_tag_free(void *rule)
dc9ffce8 2957{
d62a17ae 2958 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
dc9ffce8
CF
2959}
2960
d62a17ae 2961void route_map_finish(void)
9df78e7c 2962{
d62a17ae 2963 int i;
9df78e7c 2964
d62a17ae 2965 vector_free(route_match_vec);
2966 route_match_vec = NULL;
2967 vector_free(route_set_vec);
2968 route_set_vec = NULL;
9df78e7c 2969
8619629a
DS
2970 /*
2971 * All protocols are setting these to NULL
2972 * by default on shutdown( route_map_finish )
2973 * Why are we making them do this work?
2974 */
2975 route_map_master.add_hook = NULL;
2976 route_map_master.delete_hook = NULL;
2977 route_map_master.event_hook = NULL;
2978
d62a17ae 2979 /* cleanup route_map */
2980 while (route_map_master.head) {
2981 struct route_map *map = route_map_master.head;
e4694d0d 2982 map->to_be_processed = false;
d62a17ae 2983 route_map_delete(map);
2984 }
9df78e7c 2985
d62a17ae 2986 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
2987 hash_free(route_map_dep_hash[i]);
2988 route_map_dep_hash[i] = NULL;
2989 }
9df78e7c 2990
d62a17ae 2991 hash_free(route_map_master_hash);
2992 route_map_master_hash = NULL;
9df78e7c
DS
2993}
2994
70d44c5c
DL
2995static void rmap_autocomplete(vector comps, struct cmd_token *token)
2996{
d62a17ae 2997 struct route_map *map;
70d44c5c 2998
d62a17ae 2999 for (map = route_map_master.head; map; map = map->next)
3000 vector_set(comps, XSTRDUP(MTYPE_COMPLETION, map->name));
70d44c5c
DL
3001}
3002
4a2a09d0 3003/* Increment the use_count counter while attaching the route map */
3004void route_map_counter_increment(struct route_map *map)
3005{
3006 if (map)
3007 map->use_count++;
3008}
3009
3010/* Decrement the use_count counter while detaching the route map. */
3011void route_map_counter_decrement(struct route_map *map)
3012{
3013 if (map) {
3014 if (map->use_count <= 0)
3015 return;
3016 map->use_count--;
3017 }
3018}
3019
70d44c5c 3020static const struct cmd_variable_handler rmap_var_handlers[] = {
d62a17ae 3021 {/* "route-map WORD" */
3022 .varname = "route_map",
3023 .completions = rmap_autocomplete},
3024 {.tokenname = "ROUTEMAP_NAME", .completions = rmap_autocomplete},
3025 {.tokenname = "RMAP_NAME", .completions = rmap_autocomplete},
3026 {.completions = NULL}};
70d44c5c 3027
718e3744 3028/* Initialization of route map vector. */
d62a17ae 3029void route_map_init(void)
718e3744 3030{
d62a17ae 3031 int i;
3032
3033 /* Make vector for match and set. */
3034 route_match_vec = vector_init(1);
3035 route_set_vec = vector_init(1);
3036 route_map_master_hash =
996c9314 3037 hash_create_size(8, route_map_hash_key_make, route_map_hash_cmp,
bd74dc61 3038 "Route Map Master Hash");
d62a17ae 3039
3040 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
996c9314
LB
3041 route_map_dep_hash[i] = hash_create_size(
3042 8, route_map_dep_hash_make_key, route_map_dep_hash_cmp,
3043 "Route Map Dep Hash");
b2575bc0 3044
d62a17ae 3045 cmd_variable_handler_register(rmap_var_handlers);
b2575bc0 3046
d62a17ae 3047 /* Install route map top node. */
3048 install_node(&rmap_node, route_map_config_write);
518f0eb1 3049
d62a17ae 3050 /* Install route map commands. */
3051 install_default(RMAP_NODE);
3052 install_element(CONFIG_NODE, &route_map_cmd);
3053 install_element(CONFIG_NODE, &no_route_map_cmd);
3054 install_element(CONFIG_NODE, &no_route_map_all_cmd);
70d44c5c 3055
d62a17ae 3056 /* Install the on-match stuff */
3057 install_element(RMAP_NODE, &route_map_cmd);
3058 install_element(RMAP_NODE, &rmap_onmatch_next_cmd);
3059 install_element(RMAP_NODE, &no_rmap_onmatch_next_cmd);
3060 install_element(RMAP_NODE, &rmap_onmatch_goto_cmd);
3061 install_element(RMAP_NODE, &no_rmap_onmatch_goto_cmd);
3062 install_element(RMAP_NODE, &rmap_continue_cmd);
3063 install_element(RMAP_NODE, &no_rmap_continue_cmd);
718e3744 3064
d62a17ae 3065 /* Install the continue stuff (ALIAS of on-match). */
718e3744 3066
d62a17ae 3067 /* Install the call stuff. */
3068 install_element(RMAP_NODE, &rmap_call_cmd);
3069 install_element(RMAP_NODE, &no_rmap_call_cmd);
4a8164e5 3070
d62a17ae 3071 /* Install description commands. */
3072 install_element(RMAP_NODE, &rmap_description_cmd);
3073 install_element(RMAP_NODE, &no_rmap_description_cmd);
82f97584 3074
d62a17ae 3075 /* Install show command */
3076 install_element(ENABLE_NODE, &rmap_show_name_cmd);
4a2a09d0 3077 install_element(ENABLE_NODE, &rmap_show_unused_cmd);
82f97584 3078
d62a17ae 3079 install_element(RMAP_NODE, &match_interface_cmd);
3080 install_element(RMAP_NODE, &no_match_interface_cmd);
82f97584 3081
d62a17ae 3082 install_element(RMAP_NODE, &match_ip_address_cmd);
3083 install_element(RMAP_NODE, &no_match_ip_address_cmd);
82f97584 3084
d62a17ae 3085 install_element(RMAP_NODE, &match_ip_address_prefix_list_cmd);
3086 install_element(RMAP_NODE, &no_match_ip_address_prefix_list_cmd);
82f97584 3087
d62a17ae 3088 install_element(RMAP_NODE, &match_ip_next_hop_cmd);
3089 install_element(RMAP_NODE, &no_match_ip_next_hop_cmd);
82f97584 3090
d62a17ae 3091 install_element(RMAP_NODE, &match_ip_next_hop_prefix_list_cmd);
3092 install_element(RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd);
82f97584 3093
61ad901e
DA
3094 install_element(RMAP_NODE, &match_ip_next_hop_type_cmd);
3095 install_element(RMAP_NODE, &no_match_ip_next_hop_type_cmd);
3096
d62a17ae 3097 install_element(RMAP_NODE, &match_ipv6_address_cmd);
3098 install_element(RMAP_NODE, &no_match_ipv6_address_cmd);
82f97584 3099
d62a17ae 3100 install_element(RMAP_NODE, &match_ipv6_address_prefix_list_cmd);
3101 install_element(RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd);
82f97584 3102
61ad901e
DA
3103 install_element(RMAP_NODE, &match_ipv6_next_hop_type_cmd);
3104 install_element(RMAP_NODE, &no_match_ipv6_next_hop_type_cmd);
3105
d62a17ae 3106 install_element(RMAP_NODE, &match_metric_cmd);
3107 install_element(RMAP_NODE, &no_match_metric_cmd);
82f97584 3108
d62a17ae 3109 install_element(RMAP_NODE, &match_tag_cmd);
3110 install_element(RMAP_NODE, &no_match_tag_cmd);
82f97584 3111
d62a17ae 3112 install_element(RMAP_NODE, &set_ip_nexthop_cmd);
3113 install_element(RMAP_NODE, &no_set_ip_nexthop_cmd);
82f97584 3114
d62a17ae 3115 install_element(RMAP_NODE, &set_ipv6_nexthop_local_cmd);
3116 install_element(RMAP_NODE, &no_set_ipv6_nexthop_local_cmd);
82f97584 3117
d62a17ae 3118 install_element(RMAP_NODE, &set_metric_cmd);
3119 install_element(RMAP_NODE, &no_set_metric_cmd);
82f97584 3120
d62a17ae 3121 install_element(RMAP_NODE, &set_tag_cmd);
3122 install_element(RMAP_NODE, &no_set_tag_cmd);
718e3744 3123}