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