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