]> git.proxmox.com Git - mirror_frr.git/blame - lib/routemap.c
Merge pull request #5628 from donaldsharp/rtm_getneigh
[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);
2066 dep = NULL;
2067 }
2068 break;
ba1707ca
DS
2069 case RMAP_EVENT_SET_ADDED:
2070 case RMAP_EVENT_SET_DELETED:
2071 case RMAP_EVENT_SET_REPLACED:
2072 case RMAP_EVENT_MATCH_ADDED:
2073 case RMAP_EVENT_MATCH_DELETED:
2074 case RMAP_EVENT_MATCH_REPLACED:
2075 case RMAP_EVENT_INDEX_ADDED:
2076 case RMAP_EVENT_INDEX_DELETED:
d62a17ae 2077 break;
2078 }
2079
2080 if (dep) {
2081 if (rmap_debug)
2082 hash_iterate(dep->dep_rmap_hash,
2083 route_map_print_dependency, dname);
2084 }
2085
2086out:
2087 XFREE(MTYPE_ROUTE_MAP_NAME, rname);
2088 XFREE(MTYPE_ROUTE_MAP_NAME, dname);
2089 return ret;
2090}
2091
2092static struct hash *route_map_get_dep_hash(route_map_event_t event)
2093{
2094 struct hash *upd8_hash = NULL;
2095
2096 switch (event) {
2097 case RMAP_EVENT_PLIST_ADDED:
2098 case RMAP_EVENT_PLIST_DELETED:
2099 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_PLIST];
2100 break;
2101 case RMAP_EVENT_CLIST_ADDED:
2102 case RMAP_EVENT_CLIST_DELETED:
2103 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_CLIST];
2104 break;
2105 case RMAP_EVENT_ECLIST_ADDED:
2106 case RMAP_EVENT_ECLIST_DELETED:
2107 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ECLIST];
2108 break;
2109 case RMAP_EVENT_ASLIST_ADDED:
2110 case RMAP_EVENT_ASLIST_DELETED:
2111 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ASPATH];
2112 break;
2113 case RMAP_EVENT_LLIST_ADDED:
2114 case RMAP_EVENT_LLIST_DELETED:
2115 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_LCLIST];
2116 break;
2117 case RMAP_EVENT_CALL_ADDED:
2118 case RMAP_EVENT_CALL_DELETED:
5ed2e47b 2119 case RMAP_EVENT_MATCH_ADDED:
2120 case RMAP_EVENT_MATCH_DELETED:
d62a17ae 2121 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_RMAP];
2122 break;
2123 case RMAP_EVENT_FILTER_ADDED:
2124 case RMAP_EVENT_FILTER_DELETED:
2125 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_FILTER];
2126 break;
ba1707ca
DS
2127 /*
2128 * Should we actually be ignoring these?
2129 * I am not sure but at this point in time, let
2130 * us get them into this switch and we can peel
2131 * them into the appropriate place in the future
2132 */
2133 case RMAP_EVENT_SET_ADDED:
2134 case RMAP_EVENT_SET_DELETED:
2135 case RMAP_EVENT_SET_REPLACED:
2136 case RMAP_EVENT_MATCH_REPLACED:
2137 case RMAP_EVENT_INDEX_ADDED:
2138 case RMAP_EVENT_INDEX_DELETED:
d62a17ae 2139 upd8_hash = NULL;
2140 break;
2141 }
2142 return (upd8_hash);
518f0eb1
DS
2143}
2144
e3b78da8 2145static void route_map_process_dependency(struct hash_bucket *bucket, void *data)
518f0eb1 2146{
e2c8d6ce
NT
2147 struct route_map_dep_data *dep_data = NULL;
2148 char *rmap_name = NULL;
2149
2150 dep_data = bucket->data;
2151 rmap_name = dep_data->rname;
d62a17ae 2152
1fae5ff2 2153 if (rmap_debug)
e3ab8170 2154 zlog_debug("Notifying %s of dependency", rmap_name);
1fae5ff2 2155 if (route_map_master.event_hook)
097b5973 2156 (*route_map_master.event_hook)(rmap_name);
518f0eb1
DS
2157}
2158
d62a17ae 2159void route_map_upd8_dependency(route_map_event_t type, const char *arg,
2160 const char *rmap_name)
518f0eb1 2161{
d62a17ae 2162 struct hash *upd8_hash = NULL;
518f0eb1 2163
fdf823db 2164 if ((upd8_hash = route_map_get_dep_hash(type))) {
d62a17ae 2165 route_map_dep_update(upd8_hash, arg, rmap_name, type);
fdf823db
NT
2166
2167 if (type == RMAP_EVENT_CALL_ADDED) {
2168 /* Execute hook. */
2169 if (route_map_master.add_hook)
2170 (*route_map_master.add_hook)(rmap_name);
2171 } else if (type == RMAP_EVENT_CALL_DELETED) {
2172 /* Execute hook. */
2173 if (route_map_master.delete_hook)
2174 (*route_map_master.delete_hook)(rmap_name);
2175 }
2176 }
518f0eb1
DS
2177}
2178
d62a17ae 2179void route_map_notify_dependencies(const char *affected_name,
2180 route_map_event_t event)
518f0eb1 2181{
d62a17ae 2182 struct route_map_dep *dep;
2183 struct hash *upd8_hash;
2184 char *name;
2185
2186 if (!affected_name)
2187 return;
2188
2189 name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, affected_name);
2190
2191 if ((upd8_hash = route_map_get_dep_hash(event)) == NULL) {
2192 XFREE(MTYPE_ROUTE_MAP_NAME, name);
2193 return;
518f0eb1 2194 }
d62a17ae 2195
2196 dep = (struct route_map_dep *)hash_get(upd8_hash, name, NULL);
2197 if (dep) {
2198 if (!dep->this_hash)
2199 dep->this_hash = upd8_hash;
2200
e3ab8170
AD
2201 if (rmap_debug)
2202 zlog_debug("Filter %s updated", dep->dep_name);
d62a17ae 2203 hash_iterate(dep->dep_rmap_hash, route_map_process_dependency,
2204 (void *)event);
2205 }
2206
2207 XFREE(MTYPE_ROUTE_MAP_NAME, name);
518f0eb1
DS
2208}
2209
82f97584 2210
718e3744 2211/* VTY related functions. */
82f97584
DW
2212DEFUN (match_interface,
2213 match_interface_cmd,
2214 "match interface WORD",
2215 MATCH_STR
2216 "match first hop interface of route\n"
2217 "Interface name\n")
2218{
d62a17ae 2219 int idx_word = 2;
2220 VTY_DECLVAR_CONTEXT(route_map_index, index);
82f97584 2221
d62a17ae 2222 if (rmap_match_set_hook.match_interface)
2223 return rmap_match_set_hook.match_interface(
2224 vty, index, "interface", argv[idx_word]->arg,
2225 RMAP_EVENT_MATCH_ADDED);
2226 return CMD_SUCCESS;
82f97584
DW
2227}
2228
2229DEFUN (no_match_interface,
2230 no_match_interface_cmd,
70d44c5c 2231 "no match interface [WORD]",
82f97584
DW
2232 NO_STR
2233 MATCH_STR
2234 "Match first hop interface of route\n"
2235 "Interface name\n")
2236{
d62a17ae 2237 char *iface = (argc == 4) ? argv[3]->arg : NULL;
2238 VTY_DECLVAR_CONTEXT(route_map_index, index);
82f97584 2239
d62a17ae 2240 if (rmap_match_set_hook.no_match_interface)
2241 return rmap_match_set_hook.no_match_interface(
2242 vty, index, "interface", iface,
2243 RMAP_EVENT_MATCH_DELETED);
2244 return CMD_SUCCESS;
82f97584
DW
2245}
2246
2247
2248DEFUN (match_ip_address,
2249 match_ip_address_cmd,
2250 "match ip address <(1-199)|(1300-2699)|WORD>",
2251 MATCH_STR
2252 IP_STR
2253 "Match address of route\n"
2254 "IP access-list number\n"
2255 "IP access-list number (expanded range)\n"
2256 "IP Access-list name\n")
2257{
d62a17ae 2258 int idx_acl = 3;
2259 VTY_DECLVAR_CONTEXT(route_map_index, index);
82f97584 2260
d62a17ae 2261 if (rmap_match_set_hook.match_ip_address)
2262 return rmap_match_set_hook.match_ip_address(
2263 vty, index, "ip address", argv[idx_acl]->arg,
2264 RMAP_EVENT_FILTER_ADDED);
2265 return CMD_SUCCESS;
82f97584
DW
2266}
2267
2268
2269DEFUN (no_match_ip_address,
2270 no_match_ip_address_cmd,
2271 "no match ip address [<(1-199)|(1300-2699)|WORD>]",
2272 NO_STR
2273 MATCH_STR
2274 IP_STR
2275 "Match address of route\n"
2276 "IP access-list number\n"
2277 "IP access-list number (expanded range)\n"
2278 "IP Access-list name\n")
2279{
d62a17ae 2280 int idx_word = 4;
2281 VTY_DECLVAR_CONTEXT(route_map_index, index);
2282
2283 if (rmap_match_set_hook.no_match_ip_address) {
2284 if (argc <= idx_word)
2285 return rmap_match_set_hook.no_match_ip_address(
2286 vty, index, "ip address", NULL,
2287 RMAP_EVENT_FILTER_DELETED);
2288 return rmap_match_set_hook.no_match_ip_address(
2289 vty, index, "ip address", argv[idx_word]->arg,
2290 RMAP_EVENT_FILTER_DELETED);
2291 }
2292 return CMD_SUCCESS;
82f97584
DW
2293}
2294
2295
2296DEFUN (match_ip_address_prefix_list,
2297 match_ip_address_prefix_list_cmd,
2298 "match ip address prefix-list WORD",
2299 MATCH_STR
2300 IP_STR
2301 "Match address of route\n"
2302 "Match entries of prefix-lists\n"
2303 "IP prefix-list name\n")
2304{
d62a17ae 2305 int idx_word = 4;
2306 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2307
d62a17ae 2308 if (rmap_match_set_hook.match_ip_address_prefix_list)
2309 return rmap_match_set_hook.match_ip_address_prefix_list(
2310 vty, index, "ip address prefix-list",
2311 argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
2312 return CMD_SUCCESS;
82f97584
DW
2313}
2314
2315
2316DEFUN (no_match_ip_address_prefix_list,
2317 no_match_ip_address_prefix_list_cmd,
2318 "no match ip address prefix-list [WORD]",
2319 NO_STR
2320 MATCH_STR
2321 IP_STR
2322 "Match address of route\n"
2323 "Match entries of prefix-lists\n"
2324 "IP prefix-list name\n")
2325{
d62a17ae 2326 int idx_word = 5;
2327 VTY_DECLVAR_CONTEXT(route_map_index, index);
2328
2329 if (rmap_match_set_hook.no_match_ip_address_prefix_list) {
2330 if (argc <= idx_word)
2331 return rmap_match_set_hook
2332 .no_match_ip_address_prefix_list(
2333 vty, index, "ip address prefix-list",
2334 NULL, RMAP_EVENT_PLIST_DELETED);
2335 return rmap_match_set_hook.no_match_ip_address_prefix_list(
2336 vty, index, "ip address prefix-list",
2337 argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
2338 }
2339 return CMD_SUCCESS;
82f97584
DW
2340}
2341
2342
2343DEFUN (match_ip_next_hop,
2344 match_ip_next_hop_cmd,
2345 "match ip next-hop <(1-199)|(1300-2699)|WORD>",
2346 MATCH_STR
2347 IP_STR
2348 "Match next-hop address of route\n"
2349 "IP access-list number\n"
2350 "IP access-list number (expanded range)\n"
2351 "IP Access-list name\n")
2352{
d62a17ae 2353 int idx_acl = 3;
2354 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2355
d62a17ae 2356 if (rmap_match_set_hook.match_ip_next_hop)
2357 return rmap_match_set_hook.match_ip_next_hop(
2358 vty, index, "ip next-hop", argv[idx_acl]->arg,
2359 RMAP_EVENT_FILTER_ADDED);
2360 return CMD_SUCCESS;
82f97584
DW
2361}
2362
2363
2364DEFUN (no_match_ip_next_hop,
2365 no_match_ip_next_hop_cmd,
2366 "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
2367 NO_STR
2368 MATCH_STR
2369 IP_STR
2370 "Match next-hop address of route\n"
2371 "IP access-list number\n"
2372 "IP access-list number (expanded range)\n"
2373 "IP Access-list name\n")
2374{
d62a17ae 2375 int idx_word = 4;
2376 VTY_DECLVAR_CONTEXT(route_map_index, index);
2377
2378 if (rmap_match_set_hook.no_match_ip_next_hop) {
2379 if (argc <= idx_word)
2380 return rmap_match_set_hook.no_match_ip_next_hop(
2381 vty, index, "ip next-hop", NULL,
2382 RMAP_EVENT_FILTER_DELETED);
2383 return rmap_match_set_hook.no_match_ip_next_hop(
2384 vty, index, "ip next-hop", argv[idx_word]->arg,
2385 RMAP_EVENT_FILTER_DELETED);
2386 }
2387 return CMD_SUCCESS;
82f97584
DW
2388}
2389
2390
2391DEFUN (match_ip_next_hop_prefix_list,
2392 match_ip_next_hop_prefix_list_cmd,
2393 "match ip next-hop prefix-list WORD",
2394 MATCH_STR
2395 IP_STR
2396 "Match next-hop address of route\n"
2397 "Match entries of prefix-lists\n"
2398 "IP prefix-list name\n")
2399{
d62a17ae 2400 int idx_word = 4;
2401 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2402
d62a17ae 2403 if (rmap_match_set_hook.match_ip_next_hop_prefix_list)
2404 return rmap_match_set_hook.match_ip_next_hop_prefix_list(
2405 vty, index, "ip next-hop prefix-list",
2406 argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
2407 return CMD_SUCCESS;
82f97584
DW
2408}
2409
2410DEFUN (no_match_ip_next_hop_prefix_list,
2411 no_match_ip_next_hop_prefix_list_cmd,
2412 "no match ip next-hop prefix-list [WORD]",
2413 NO_STR
2414 MATCH_STR
2415 IP_STR
2416 "Match next-hop address of route\n"
2417 "Match entries of prefix-lists\n"
2418 "IP prefix-list name\n")
2419{
d62a17ae 2420 int idx_word = 5;
2421 VTY_DECLVAR_CONTEXT(route_map_index, index);
2422
2423 if (rmap_match_set_hook.no_match_ip_next_hop) {
2424 if (argc <= idx_word)
2425 return rmap_match_set_hook.no_match_ip_next_hop(
2426 vty, index, "ip next-hop prefix-list", NULL,
2427 RMAP_EVENT_PLIST_DELETED);
2428 return rmap_match_set_hook.no_match_ip_next_hop(
2429 vty, index, "ip next-hop prefix-list",
2430 argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
2431 }
2432 return CMD_SUCCESS;
82f97584
DW
2433}
2434
61ad901e
DA
2435DEFUN(match_ip_next_hop_type, match_ip_next_hop_type_cmd,
2436 "match ip next-hop type <blackhole>",
2437 MATCH_STR IP_STR
2438 "Match next-hop address of route\n"
2439 "Match entries by type\n"
2440 "Blackhole\n")
2441{
2442 int idx_word = 4;
2443 VTY_DECLVAR_CONTEXT(route_map_index, index);
2444
2445 if (rmap_match_set_hook.match_ip_next_hop_type)
2446 return rmap_match_set_hook.match_ip_next_hop_type(
2447 vty, index, "ip next-hop type", argv[idx_word]->arg,
2448 RMAP_EVENT_MATCH_ADDED);
2449 return CMD_SUCCESS;
2450}
2451
2452DEFUN(no_match_ip_next_hop_type, no_match_ip_next_hop_type_cmd,
2453 "no match ip next-hop type [<blackhole>]",
2454 NO_STR MATCH_STR IP_STR
2455 "Match next-hop address of route\n"
2456 "Match entries by type\n"
2457 "Blackhole\n")
2458{
2459 int idx_word = 5;
2460 VTY_DECLVAR_CONTEXT(route_map_index, index);
2461
2462 if (rmap_match_set_hook.no_match_ip_next_hop) {
2463 if (argc <= idx_word)
2464 return rmap_match_set_hook.no_match_ip_next_hop(
2465 vty, index, "ip next-hop type", NULL,
2466 RMAP_EVENT_MATCH_DELETED);
2467 return rmap_match_set_hook.no_match_ip_next_hop(
2468 vty, index, "ip next-hop type", argv[idx_word]->arg,
2469 RMAP_EVENT_MATCH_DELETED);
2470 }
2471 return CMD_SUCCESS;
2472}
2473
82f97584
DW
2474
2475DEFUN (match_ipv6_address,
2476 match_ipv6_address_cmd,
2477 "match ipv6 address WORD",
2478 MATCH_STR
2479 IPV6_STR
2480 "Match IPv6 address of route\n"
2481 "IPv6 access-list name\n")
2482{
d62a17ae 2483 int idx_word = 3;
2484 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2485
d62a17ae 2486 if (rmap_match_set_hook.match_ipv6_address)
2487 return rmap_match_set_hook.match_ipv6_address(
2488 vty, index, "ipv6 address", argv[idx_word]->arg,
2489 RMAP_EVENT_FILTER_ADDED);
2490 return CMD_SUCCESS;
82f97584
DW
2491}
2492
2493DEFUN (no_match_ipv6_address,
2494 no_match_ipv6_address_cmd,
2495 "no match ipv6 address WORD",
2496 NO_STR
2497 MATCH_STR
2498 IPV6_STR
2499 "Match IPv6 address of route\n"
2500 "IPv6 access-list name\n")
2501{
d62a17ae 2502 int idx_word = 4;
2503 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2504
d62a17ae 2505 if (rmap_match_set_hook.no_match_ipv6_address)
2506 return rmap_match_set_hook.no_match_ipv6_address(
2507 vty, index, "ipv6 address", argv[idx_word]->arg,
2508 RMAP_EVENT_FILTER_DELETED);
2509 return CMD_SUCCESS;
82f97584
DW
2510}
2511
2512
2513DEFUN (match_ipv6_address_prefix_list,
2514 match_ipv6_address_prefix_list_cmd,
2515 "match ipv6 address prefix-list WORD",
2516 MATCH_STR
2517 IPV6_STR
2518 "Match address of route\n"
2519 "Match entries of prefix-lists\n"
2520 "IP prefix-list name\n")
2521{
d62a17ae 2522 int idx_word = 4;
2523 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2524
d62a17ae 2525 if (rmap_match_set_hook.match_ipv6_address_prefix_list)
2526 return rmap_match_set_hook.match_ipv6_address_prefix_list(
2527 vty, index, "ipv6 address prefix-list",
2528 argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
2529 return CMD_SUCCESS;
82f97584
DW
2530}
2531
2532DEFUN (no_match_ipv6_address_prefix_list,
2533 no_match_ipv6_address_prefix_list_cmd,
2534 "no match ipv6 address prefix-list WORD",
2535 NO_STR
2536 MATCH_STR
2537 IPV6_STR
2538 "Match address of route\n"
2539 "Match entries of prefix-lists\n"
2540 "IP prefix-list name\n")
2541{
d62a17ae 2542 int idx_word = 5;
2543 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2544
d62a17ae 2545 if (rmap_match_set_hook.no_match_ipv6_address_prefix_list)
2546 return rmap_match_set_hook.no_match_ipv6_address_prefix_list(
2547 vty, index, "ipv6 address prefix-list",
2548 argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
2549 return CMD_SUCCESS;
82f97584
DW
2550}
2551
61ad901e
DA
2552DEFUN(match_ipv6_next_hop_type, match_ipv6_next_hop_type_cmd,
2553 "match ipv6 next-hop type <blackhole>",
2554 MATCH_STR IPV6_STR
d8524fbe 2555 "Match next-hop address of route\n"
61ad901e
DA
2556 "Match entries by type\n"
2557 "Blackhole\n")
2558{
2559 int idx_word = 4;
2560 VTY_DECLVAR_CONTEXT(route_map_index, index);
2561
2562 if (rmap_match_set_hook.match_ipv6_next_hop_type)
2563 return rmap_match_set_hook.match_ipv6_next_hop_type(
2564 vty, index, "ipv6 next-hop type", argv[idx_word]->arg,
2565 RMAP_EVENT_MATCH_ADDED);
2566 return CMD_SUCCESS;
2567}
2568
2569DEFUN(no_match_ipv6_next_hop_type, no_match_ipv6_next_hop_type_cmd,
2570 "no match ipv6 next-hop type [<blackhole>]",
2571 NO_STR MATCH_STR IPV6_STR
2572 "Match address of route\n"
2573 "Match entries by type\n"
2574 "Blackhole\n")
2575{
2576 int idx_word = 5;
2577 VTY_DECLVAR_CONTEXT(route_map_index, index);
2578
2579 if (rmap_match_set_hook.no_match_ipv6_next_hop_type)
2580 return rmap_match_set_hook.no_match_ipv6_next_hop_type(
4cfecc3e
RW
2581 vty, index, "ipv6 next-hop type",
2582 (argc <= idx_word) ? NULL : argv[idx_word]->arg,
61ad901e
DA
2583 RMAP_EVENT_MATCH_DELETED);
2584 return CMD_SUCCESS;
2585}
82f97584
DW
2586
2587DEFUN (match_metric,
2588 match_metric_cmd,
2589 "match metric (0-4294967295)",
2590 MATCH_STR
2591 "Match metric of route\n"
2592 "Metric value\n")
2593{
d62a17ae 2594 int idx_number = 2;
2595 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2596
d62a17ae 2597 if (rmap_match_set_hook.match_metric)
2598 return rmap_match_set_hook.match_metric(vty, index, "metric",
2599 argv[idx_number]->arg,
2600 RMAP_EVENT_MATCH_ADDED);
2601 return CMD_SUCCESS;
82f97584
DW
2602}
2603
2604
2605DEFUN (no_match_metric,
2606 no_match_metric_cmd,
2607 "no match metric [(0-4294967295)]",
2608 NO_STR
2609 MATCH_STR
2610 "Match metric of route\n"
2611 "Metric value\n")
2612{
d62a17ae 2613 int idx_number = 3;
2614 VTY_DECLVAR_CONTEXT(route_map_index, index);
2615
2616 if (rmap_match_set_hook.no_match_metric) {
2617 if (argc <= idx_number)
2618 return rmap_match_set_hook.no_match_metric(
2619 vty, index, "metric", NULL,
2620 RMAP_EVENT_MATCH_DELETED);
2621 return rmap_match_set_hook.no_match_metric(
2622 vty, index, "metric", argv[idx_number]->arg,
2623 RMAP_EVENT_MATCH_DELETED);
2624 }
2625 return CMD_SUCCESS;
82f97584
DW
2626}
2627
2628
2629DEFUN (match_tag,
2630 match_tag_cmd,
e52702f2 2631 "match tag (1-4294967295)",
82f97584
DW
2632 MATCH_STR
2633 "Match tag of route\n"
2634 "Tag value\n")
2635{
d62a17ae 2636 int idx_number = 2;
2637 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2638
d62a17ae 2639 if (rmap_match_set_hook.match_tag)
2640 return rmap_match_set_hook.match_tag(vty, index, "tag",
2641 argv[idx_number]->arg,
2642 RMAP_EVENT_MATCH_ADDED);
2643 return CMD_SUCCESS;
82f97584
DW
2644}
2645
2646
2647DEFUN (no_match_tag,
2648 no_match_tag_cmd,
e52702f2 2649 "no match tag [(1-4294967295)]",
82f97584
DW
2650 NO_STR
2651 MATCH_STR
2652 "Match tag of route\n"
2653 "Tag value\n")
2654{
d62a17ae 2655 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2656
d62a17ae 2657 int idx = 0;
2658 char *arg = argv_find(argv, argc, "(1-4294967295)", &idx)
2659 ? argv[idx]->arg
2660 : NULL;
0d702986 2661
d62a17ae 2662 if (rmap_match_set_hook.no_match_tag)
2663 return rmap_match_set_hook.no_match_tag(
2664 vty, index, "tag", arg, RMAP_EVENT_MATCH_DELETED);
2665 return CMD_SUCCESS;
82f97584
DW
2666}
2667
2668
2669DEFUN (set_ip_nexthop,
2670 set_ip_nexthop_cmd,
2671 "set ip next-hop A.B.C.D",
2672 SET_STR
2673 IP_STR
2674 "Next hop address\n"
2675 "IP address of next hop\n")
2676{
d62a17ae 2677 int idx_ipv4 = 3;
2678 union sockunion su;
2679 int ret;
2680 VTY_DECLVAR_CONTEXT(route_map_index, index);
82f97584 2681
d62a17ae 2682 ret = str2sockunion(argv[idx_ipv4]->arg, &su);
2683 if (ret < 0) {
2684 vty_out(vty, "%% Malformed nexthop address\n");
2685 return CMD_WARNING_CONFIG_FAILED;
2686 }
2687 if (su.sin.sin_addr.s_addr == 0
ae2158fe 2688 || IPV4_CLASS_DE(ntohl(su.sin.sin_addr.s_addr))) {
d62a17ae 2689 vty_out(vty,
2690 "%% nexthop address cannot be 0.0.0.0, multicast or reserved\n");
2691 return CMD_WARNING_CONFIG_FAILED;
2692 }
82f97584 2693
d62a17ae 2694 if (rmap_match_set_hook.set_ip_nexthop)
2695 return rmap_match_set_hook.set_ip_nexthop(
2696 vty, index, "ip next-hop", argv[idx_ipv4]->arg);
2697 return CMD_SUCCESS;
82f97584
DW
2698}
2699
2700
2701DEFUN (no_set_ip_nexthop,
2702 no_set_ip_nexthop_cmd,
89602edb 2703 "no set ip next-hop [A.B.C.D]",
82f97584
DW
2704 NO_STR
2705 SET_STR
3a2d747c 2706 IP_STR
82f97584 2707 "Next hop address\n"
82f97584
DW
2708 "IP address of next hop\n")
2709{
0af35d90 2710 int idx = 0;
d62a17ae 2711 VTY_DECLVAR_CONTEXT(route_map_index, index);
89602edb 2712 const char *arg = NULL;
82f97584 2713
89602edb
QY
2714 if (argv_find(argv, argc, "A.B.C.D", &idx))
2715 arg = argv[idx]->arg;
2716
2717 if (rmap_match_set_hook.no_set_ip_nexthop)
d62a17ae 2718 return rmap_match_set_hook.no_set_ip_nexthop(
89602edb
QY
2719 vty, index, "ip next-hop", arg);
2720
d62a17ae 2721 return CMD_SUCCESS;
82f97584
DW
2722}
2723
2724
2725DEFUN (set_ipv6_nexthop_local,
2726 set_ipv6_nexthop_local_cmd,
2727 "set ipv6 next-hop local X:X::X:X",
2728 SET_STR
2729 IPV6_STR
2730 "IPv6 next-hop address\n"
2731 "IPv6 local address\n"
2732 "IPv6 address of next hop\n")
2733{
d62a17ae 2734 int idx_ipv6 = 4;
2735 struct in6_addr addr;
2736 int ret;
2737 VTY_DECLVAR_CONTEXT(route_map_index, index);
82f97584 2738
d62a17ae 2739 ret = inet_pton(AF_INET6, argv[idx_ipv6]->arg, &addr);
2740 if (!ret) {
2741 vty_out(vty, "%% Malformed nexthop address\n");
2742 return CMD_WARNING_CONFIG_FAILED;
2743 }
2744 if (!IN6_IS_ADDR_LINKLOCAL(&addr)) {
2745 vty_out(vty, "%% Invalid link-local nexthop address\n");
2746 return CMD_WARNING_CONFIG_FAILED;
2747 }
82f97584 2748
d62a17ae 2749 if (rmap_match_set_hook.set_ipv6_nexthop_local)
2750 return rmap_match_set_hook.set_ipv6_nexthop_local(
2751 vty, index, "ipv6 next-hop local", argv[idx_ipv6]->arg);
2752 return CMD_SUCCESS;
82f97584
DW
2753}
2754
2755
2756DEFUN (no_set_ipv6_nexthop_local,
2757 no_set_ipv6_nexthop_local_cmd,
2758 "no set ipv6 next-hop local [X:X::X:X]",
2759 NO_STR
2760 SET_STR
2761 IPV6_STR
2762 "IPv6 next-hop address\n"
2763 "IPv6 local address\n"
2764 "IPv6 address of next hop\n")
2765{
d62a17ae 2766 int idx_ipv6 = 5;
2767 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2768
d62a17ae 2769 if (rmap_match_set_hook.no_set_ipv6_nexthop_local) {
2770 if (argc <= idx_ipv6)
2771 return rmap_match_set_hook.no_set_ipv6_nexthop_local(
2772 vty, index, "ipv6 next-hop local", NULL);
2773 return rmap_match_set_hook.no_set_ipv6_nexthop_local(
2774 vty, index, "ipv6 next-hop local", argv[5]->arg);
2775 }
2776 return CMD_SUCCESS;
82f97584
DW
2777}
2778
2779DEFUN (set_metric,
2780 set_metric_cmd,
2781 "set metric <(0-4294967295)|rtt|+rtt|-rtt|+metric|-metric>",
2782 SET_STR
2783 "Metric value for destination routing protocol\n"
2784 "Metric value\n"
2785 "Assign round trip time\n"
2786 "Add round trip time\n"
2787 "Subtract round trip time\n"
2788 "Add metric\n"
2789 "Subtract metric\n")
2790{
d62a17ae 2791 int idx_number = 2;
2792 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2793
d62a17ae 2794 const char *pass = (argv[idx_number]->type == RANGE_TKN)
2795 ? argv[idx_number]->arg
2796 : argv[idx_number]->text;
af3346ec 2797
d62a17ae 2798 if (rmap_match_set_hook.set_metric)
2799 return rmap_match_set_hook.set_metric(vty, index, "metric",
2800 pass);
2801 return CMD_SUCCESS;
82f97584
DW
2802}
2803
2804
2805DEFUN (no_set_metric,
2806 no_set_metric_cmd,
2807 "no set metric [(0-4294967295)]",
2808 NO_STR
2809 SET_STR
2810 "Metric value for destination routing protocol\n"
2811 "Metric value\n")
2812{
d62a17ae 2813 int idx_number = 3;
2814 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2815
d62a17ae 2816 if (rmap_match_set_hook.no_set_metric) {
2817 if (argc <= idx_number)
2818 return rmap_match_set_hook.no_set_metric(
2819 vty, index, "metric", NULL);
2820 return rmap_match_set_hook.no_set_metric(vty, index, "metric",
2821 argv[idx_number]->arg);
2822 }
2823 return CMD_SUCCESS;
82f97584
DW
2824}
2825
2826
2827DEFUN (set_tag,
2828 set_tag_cmd,
e52702f2 2829 "set tag (1-4294967295)",
82f97584
DW
2830 SET_STR
2831 "Tag value for routing protocol\n"
2832 "Tag value\n")
2833{
d62a17ae 2834 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2835
d62a17ae 2836 int idx_number = 2;
2837 if (rmap_match_set_hook.set_tag)
2838 return rmap_match_set_hook.set_tag(vty, index, "tag",
2839 argv[idx_number]->arg);
2840 return CMD_SUCCESS;
82f97584
DW
2841}
2842
2843
2844DEFUN (no_set_tag,
2845 no_set_tag_cmd,
e52702f2 2846 "no set tag [(1-4294967295)]",
82f97584
DW
2847 NO_STR
2848 SET_STR
2849 "Tag value for routing protocol\n"
2850 "Tag value\n")
2851{
d62a17ae 2852 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2853
d62a17ae 2854 int idx_number = 3;
2855 if (rmap_match_set_hook.no_set_tag) {
2856 if (argc <= idx_number)
2857 return rmap_match_set_hook.no_set_tag(vty, index, "tag",
2858 NULL);
2859 return rmap_match_set_hook.no_set_tag(vty, index, "tag",
2860 argv[idx_number]->arg);
2861 }
2862 return CMD_SUCCESS;
82f97584
DW
2863}
2864
2865
505e5056 2866DEFUN_NOSH (route_map,
718e3744 2867 route_map_cmd,
7fcbbdae 2868 "route-map WORD <deny|permit> (1-65535)",
718e3744 2869 "Create route-map or enter route-map command mode\n"
2870 "Route map tag\n"
2871 "Route map denies set operations\n"
2872 "Route map permits set operations\n"
2873 "Sequence to insert to/delete from existing route-map entry\n")
2874{
d62a17ae 2875 int idx_word = 1;
2876 int idx_permit_deny = 2;
2877 int idx_number = 3;
2878 struct route_map *map;
2879 struct route_map_index *index;
2880 char *endptr = NULL;
2881 int permit =
2882 argv[idx_permit_deny]->arg[0] == 'p' ? RMAP_PERMIT : RMAP_DENY;
2883 unsigned long pref = strtoul(argv[idx_number]->arg, &endptr, 10);
2884 const char *mapname = argv[idx_word]->arg;
718e3744 2885
d62a17ae 2886 /* Get route map. */
2887 map = route_map_get(mapname);
2888 index = route_map_index_get(map, permit, pref);
718e3744 2889
d62a17ae 2890 VTY_PUSH_CONTEXT(RMAP_NODE, index);
2891 return CMD_SUCCESS;
718e3744 2892}
2893
2894DEFUN (no_route_map_all,
2895 no_route_map_all_cmd,
2896 "no route-map WORD",
2897 NO_STR
2898 "Create route-map or enter route-map command mode\n"
2899 "Route map tag\n")
2900{
d62a17ae 2901 int idx_word = 2;
2902 const char *mapname = argv[idx_word]->arg;
2903 struct route_map *map;
718e3744 2904
d62a17ae 2905 map = route_map_lookup_by_name(mapname);
2906 if (map == NULL) {
2907 vty_out(vty, "%% Could not find route-map %s\n", mapname);
2908 return CMD_WARNING_CONFIG_FAILED;
2909 }
718e3744 2910
d62a17ae 2911 route_map_delete(map);
718e3744 2912
d62a17ae 2913 return CMD_SUCCESS;
718e3744 2914}
2915
2916DEFUN (no_route_map,
2917 no_route_map_cmd,
7fcbbdae 2918 "no route-map WORD <deny|permit> (1-65535)",
718e3744 2919 NO_STR
2920 "Create route-map or enter route-map command mode\n"
2921 "Route map tag\n"
2922 "Route map denies set operations\n"
2923 "Route map permits set operations\n"
2924 "Sequence to insert to/delete from existing route-map entry\n")
2925{
d62a17ae 2926 int idx_word = 2;
2927 int idx_permit_deny = 3;
2928 int idx_number = 4;
2929 struct route_map *map;
2930 struct route_map_index *index;
2931 char *endptr = NULL;
2932 int permit = strmatch(argv[idx_permit_deny]->text, "permit")
2933 ? RMAP_PERMIT
2934 : RMAP_DENY;
2935 const char *prefstr = argv[idx_number]->arg;
2936 const char *mapname = argv[idx_word]->arg;
2937 unsigned long pref = strtoul(prefstr, &endptr, 10);
2938
2939 /* Existence check. */
2940 map = route_map_lookup_by_name(mapname);
2941 if (map == NULL) {
2942 vty_out(vty, "%% Could not find route-map %s\n", mapname);
2943 return CMD_WARNING_CONFIG_FAILED;
2944 }
2945
2946 /* Lookup route map index. */
2947 index = route_map_index_lookup(map, permit, pref);
2948 if (index == NULL) {
2949 vty_out(vty, "%% Could not find route-map entry %s %s\n",
2950 mapname, prefstr);
2951 return CMD_WARNING_CONFIG_FAILED;
2952 }
2953
2954 /* Delete index from route map. */
2955 route_map_index_delete(index, 1);
2956
2957 /* If this route rule is the last one, delete route map itself. */
2958 if (route_map_empty(map))
2959 route_map_delete(map);
2960
2961 return CMD_SUCCESS;
718e3744 2962}
2963
2964DEFUN (rmap_onmatch_next,
2965 rmap_onmatch_next_cmd,
2966 "on-match next",
2967 "Exit policy on matches\n"
2968 "Next clause\n")
2969{
d62a17ae 2970 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2971
2972 if (index) {
2973 if (index->type == RMAP_DENY) {
2974 /* Under a deny clause, match means it's finished. No
2975 * need to set next */
2976 vty_out(vty,
2977 "on-match next not supported under route-map deny\n");
2978 return CMD_WARNING_CONFIG_FAILED;
2979 }
2980 index->exitpolicy = RMAP_NEXT;
2981 }
2982 return CMD_SUCCESS;
718e3744 2983}
2984
2985DEFUN (no_rmap_onmatch_next,
2986 no_rmap_onmatch_next_cmd,
2987 "no on-match next",
2988 NO_STR
2989 "Exit policy on matches\n"
2990 "Next clause\n")
2991{
d62a17ae 2992 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2993
2994 if (index)
2995 index->exitpolicy = RMAP_EXIT;
718e3744 2996
d62a17ae 2997 return CMD_SUCCESS;
718e3744 2998}
2999
3000DEFUN (rmap_onmatch_goto,
3001 rmap_onmatch_goto_cmd,
7fcbbdae 3002 "on-match goto (1-65535)",
718e3744 3003 "Exit policy on matches\n"
3004 "Goto Clause number\n"
3005 "Number\n")
3006{
d62a17ae 3007 int idx = 0;
3008 char *num = argv_find(argv, argc, "(1-65535)", &idx) ? argv[idx]->arg
3009 : NULL;
3010
3011 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
3012 int d = 0;
3013
3014 if (index) {
3015 if (index->type == RMAP_DENY) {
3016 /* Under a deny clause, match means it's finished. No
3017 * need to go anywhere */
3018 vty_out(vty,
3019 "on-match goto not supported under route-map deny\n");
3020 return CMD_WARNING_CONFIG_FAILED;
3021 }
3022
3023 if (num)
3024 d = strtoul(num, NULL, 10);
3025 else
3026 d = index->pref + 1;
3027
3028 if (d <= index->pref) {
3029 /* Can't allow you to do that, Dave */
3030 vty_out(vty, "can't jump backwards in route-maps\n");
3031 return CMD_WARNING_CONFIG_FAILED;
3032 } else {
3033 index->exitpolicy = RMAP_GOTO;
3034 index->nextpref = d;
3035 }
718e3744 3036 }
d62a17ae 3037 return CMD_SUCCESS;
718e3744 3038}
3039
3040DEFUN (no_rmap_onmatch_goto,
3041 no_rmap_onmatch_goto_cmd,
3042 "no on-match goto",
3043 NO_STR
3044 "Exit policy on matches\n"
fee0f4c6 3045 "Goto Clause number\n")
718e3744 3046{
d62a17ae 3047 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
718e3744 3048
d62a17ae 3049 if (index)
3050 index->exitpolicy = RMAP_EXIT;
3051
3052 return CMD_SUCCESS;
718e3744 3053}
3054
f667a580
QY
3055/* Cisco/GNU Zebra compatibility aliases */
3056/* ALIAS_FIXME */
3057DEFUN (rmap_continue,
3058 rmap_continue_cmd,
3059 "continue (1-65535)",
3060 "Continue on a different entry within the route-map\n"
3061 "Route-map entry sequence number\n")
3062{
d62a17ae 3063 return rmap_onmatch_goto(self, vty, argc, argv);
f667a580 3064}
5510e83b 3065
f667a580
QY
3066/* ALIAS_FIXME */
3067DEFUN (no_rmap_continue,
3068 no_rmap_continue_cmd,
3069 "no continue [(1-65535)]",
3070 NO_STR
3071 "Continue on a different entry within the route-map\n"
3072 "Route-map entry sequence number\n")
3073{
d62a17ae 3074 return no_rmap_onmatch_goto(self, vty, argc, argv);
f667a580 3075}
f412b39a 3076
1fa30509
DS
3077static void clear_route_map_helper(struct route_map *map)
3078{
3079 struct route_map_index *index;
3080
3081 map->applied_clear = map->applied;
3082 for (index = map->head; index; index = index->next)
3083 index->applied_clear = index->applied;
3084}
3085
3086DEFUN (rmap_clear_counters,
3087 rmap_clear_counters_cmd,
3088 "clear route-map counters [WORD]",
3089 CLEAR_STR
3090 "route-map information\n"
3091 "counters associated with the specified route-map\n"
3092 "route-map name\n")
3093{
3094 int idx_word = 2;
3095 struct route_map *map;
3096
3097 const char *name = (argc == 3 ) ? argv[idx_word]->arg : NULL;
3098
3099 if (name) {
3100 map = route_map_lookup_by_name(name);
3101
3102 if (map)
3103 clear_route_map_helper(map);
3104 else {
3105 vty_out(vty, "%s: 'route-map %s' not found\n",
3106 frr_protonameinst, name);
3107 return CMD_SUCCESS;
3108 }
3109 } else {
3110 for (map = route_map_master.head; map; map = map->next)
3111 clear_route_map_helper(map);
3112 }
3113
3114 return CMD_SUCCESS;
3115
3116}
5510e83b 3117
6d2729e3 3118DEFUN (rmap_show_name,
5510e83b 3119 rmap_show_name_cmd,
7514fb77 3120 "show route-map [WORD]",
5510e83b 3121 SHOW_STR
3122 "route-map information\n"
3123 "route-map name\n")
3124{
d62a17ae 3125 int idx_word = 2;
3126 const char *name = (argc == 3) ? argv[idx_word]->arg : NULL;
3127 return vty_show_route_map(vty, name);
5510e83b 3128}
3129
4a2a09d0 3130DEFUN (rmap_show_unused,
3131 rmap_show_unused_cmd,
3132 "show route-map-unused",
3133 SHOW_STR
3134 "unused route-map information\n")
3135{
3136 return vty_show_unused_route_map(vty);
3137}
3138
fee0f4c6 3139DEFUN (rmap_call,
3140 rmap_call_cmd,
3141 "call WORD",
3142 "Jump to another Route-Map after match+set\n"
3143 "Target route-map name\n")
3144{
d62a17ae 3145 int idx_word = 1;
3146 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
3147 const char *rmap = argv[idx_word]->arg;
fee0f4c6 3148
d62a17ae 3149 assert(index);
c01d03a6 3150
6c3247bd
NT
3151 /* If "call" is invoked with the same route-map name as
3152 * the one previously configured then, ignore the duplicate
3153 * configuration.
3154 */
3155 if (index->nextrm && (strcmp(index->nextrm, rmap) == 0))
3156 return CMD_SUCCESS;
3157
d62a17ae 3158 if (index->nextrm) {
3159 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED,
3160 index->nextrm, index->map->name);
3161 XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
3162 }
3163 index->nextrm = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
518f0eb1 3164
d62a17ae 3165 /* Execute event hook. */
3166 route_map_upd8_dependency(RMAP_EVENT_CALL_ADDED, index->nextrm,
3167 index->map->name);
3168 return CMD_SUCCESS;
fee0f4c6 3169}
3170
3171DEFUN (no_rmap_call,
3172 no_rmap_call_cmd,
3173 "no call",
3174 NO_STR
3175 "Jump to another Route-Map after match+set\n")
3176{
d62a17ae 3177 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
fee0f4c6 3178
d62a17ae 3179 if (index->nextrm) {
3180 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED,
3181 index->nextrm, index->map->name);
3182 XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
3183 index->nextrm = NULL;
3184 }
fee0f4c6 3185
d62a17ae 3186 return CMD_SUCCESS;
fee0f4c6 3187}
3188
4a8164e5 3189DEFUN (rmap_description,
3190 rmap_description_cmd,
7fcbbdae 3191 "description LINE...",
4a8164e5 3192 "Route-map comment\n"
3193 "Comment describing this route-map rule\n")
3194{
d62a17ae 3195 int idx_line = 1;
3196 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
4a8164e5 3197
d62a17ae 3198 if (index) {
3199 if (index->description)
3200 XFREE(MTYPE_TMP, index->description);
3201 index->description = argv_concat(argv, argc, idx_line);
3202 }
3203 return CMD_SUCCESS;
4a8164e5 3204}
3205
3206DEFUN (no_rmap_description,
3207 no_rmap_description_cmd,
3208 "no description",
3209 NO_STR
3210 "Route-map comment\n")
3211{
d62a17ae 3212 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
4a8164e5 3213
d62a17ae 3214 if (index) {
3215 if (index->description)
3216 XFREE(MTYPE_TMP, index->description);
3217 index->description = NULL;
3218 }
3219 return CMD_SUCCESS;
4a8164e5 3220}
3221
e3ab8170
AD
3222DEFUN (debug_rmap,
3223 debug_rmap_cmd,
3224 "debug route-map",
3225 DEBUG_STR
3226 "Debug option set for route-maps\n")
3227{
3228 rmap_debug = true;
3229 return CMD_SUCCESS;
3230}
3231
3232DEFUN (no_debug_rmap,
3233 no_debug_rmap_cmd,
3234 "no debug route-map",
3235 NO_STR
3236 DEBUG_STR
3237 "Debug option set for route-maps\n")
3238{
3239 rmap_debug = false;
3240 return CMD_SUCCESS;
3241}
3242
3243/* Debug node. */
3244static struct cmd_node rmap_debug_node = {RMAP_DEBUG_NODE, "", 1};
3245
718e3744 3246/* Configuration write function. */
d62a17ae 3247static int route_map_config_write(struct vty *vty)
3248{
3249 struct route_map *map;
3250 struct route_map_index *index;
3251 struct route_map_rule *rule;
3252 int first = 1;
3253 int write = 0;
55858394
DS
3254 struct listnode *ln;
3255 struct list *maplist = list_new();
d62a17ae 3256
3257 for (map = route_map_master.head; map; map = map->next)
55858394
DS
3258 listnode_add(maplist, map);
3259
3260 list_sort(maplist, sort_route_map);
3261
3262 for (ALL_LIST_ELEMENTS_RO(maplist, ln, map))
d62a17ae 3263 for (index = map->head; index; index = index->next) {
3264 if (!first)
3265 vty_out(vty, "!\n");
3266 else
3267 first = 0;
3268
3269 vty_out(vty, "route-map %s %s %d\n", map->name,
3270 route_map_type_str(index->type), index->pref);
3271
3272 if (index->description)
3273 vty_out(vty, " description %s\n",
3274 index->description);
3275
3276 for (rule = index->match_list.head; rule;
3277 rule = rule->next)
3278 vty_out(vty, " match %s %s\n", rule->cmd->str,
3279 rule->rule_str ? rule->rule_str : "");
3280
3281 for (rule = index->set_list.head; rule;
3282 rule = rule->next)
3283 vty_out(vty, " set %s %s\n", rule->cmd->str,
3284 rule->rule_str ? rule->rule_str : "");
3285 if (index->nextrm)
3286 vty_out(vty, " call %s\n", index->nextrm);
3287 if (index->exitpolicy == RMAP_GOTO)
3288 vty_out(vty, " on-match goto %d\n",
3289 index->nextpref);
3290 if (index->exitpolicy == RMAP_NEXT)
3291 vty_out(vty, " on-match next\n");
3292
3293 write++;
3294 }
55858394
DS
3295
3296 list_delete(&maplist);
d62a17ae 3297 return write;
718e3744 3298}
3299
e3ab8170
AD
3300static int rmap_config_write_debug(struct vty *vty)
3301{
3302 int write = 0;
3303
3304 if (rmap_debug) {
3305 vty_out(vty, "debug route-map\n");
3306 write++;
3307 }
3308
3309 return write;
3310}
3311
718e3744 3312/* Route map node structure. */
d62a17ae 3313static struct cmd_node rmap_node = {RMAP_NODE, "%s(config-route-map)# ", 1};
718e3744 3314
dc9ffce8
CF
3315/* Common route map rules */
3316
d62a17ae 3317void *route_map_rule_tag_compile(const char *arg)
dc9ffce8 3318{
d62a17ae 3319 unsigned long int tmp;
3320 char *endptr;
3321 route_tag_t *tag;
dc9ffce8 3322
d62a17ae 3323 errno = 0;
3324 tmp = strtoul(arg, &endptr, 0);
3325 if (arg[0] == '\0' || *endptr != '\0' || errno || tmp > ROUTE_TAG_MAX)
3326 return NULL;
dc9ffce8 3327
d62a17ae 3328 tag = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*tag));
3329 *tag = tmp;
dc9ffce8 3330
d62a17ae 3331 return tag;
dc9ffce8
CF
3332}
3333
d62a17ae 3334void route_map_rule_tag_free(void *rule)
dc9ffce8 3335{
d62a17ae 3336 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
dc9ffce8
CF
3337}
3338
d62a17ae 3339void route_map_finish(void)
9df78e7c 3340{
d62a17ae 3341 int i;
9df78e7c 3342
d62a17ae 3343 vector_free(route_match_vec);
3344 route_match_vec = NULL;
3345 vector_free(route_set_vec);
3346 route_set_vec = NULL;
9df78e7c 3347
8619629a
DS
3348 /*
3349 * All protocols are setting these to NULL
3350 * by default on shutdown( route_map_finish )
3351 * Why are we making them do this work?
3352 */
3353 route_map_master.add_hook = NULL;
3354 route_map_master.delete_hook = NULL;
3355 route_map_master.event_hook = NULL;
3356
d62a17ae 3357 /* cleanup route_map */
3358 while (route_map_master.head) {
3359 struct route_map *map = route_map_master.head;
e4694d0d 3360 map->to_be_processed = false;
d62a17ae 3361 route_map_delete(map);
3362 }
9df78e7c 3363
d62a17ae 3364 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
3365 hash_free(route_map_dep_hash[i]);
3366 route_map_dep_hash[i] = NULL;
3367 }
9df78e7c 3368
d62a17ae 3369 hash_free(route_map_master_hash);
3370 route_map_master_hash = NULL;
9df78e7c
DS
3371}
3372
70d44c5c
DL
3373static void rmap_autocomplete(vector comps, struct cmd_token *token)
3374{
d62a17ae 3375 struct route_map *map;
70d44c5c 3376
d62a17ae 3377 for (map = route_map_master.head; map; map = map->next)
3378 vector_set(comps, XSTRDUP(MTYPE_COMPLETION, map->name));
70d44c5c
DL
3379}
3380
4a2a09d0 3381/* Increment the use_count counter while attaching the route map */
3382void route_map_counter_increment(struct route_map *map)
3383{
3384 if (map)
3385 map->use_count++;
3386}
3387
3388/* Decrement the use_count counter while detaching the route map. */
3389void route_map_counter_decrement(struct route_map *map)
3390{
3391 if (map) {
3392 if (map->use_count <= 0)
3393 return;
3394 map->use_count--;
3395 }
3396}
3397
70d44c5c 3398static const struct cmd_variable_handler rmap_var_handlers[] = {
d62a17ae 3399 {/* "route-map WORD" */
3400 .varname = "route_map",
3401 .completions = rmap_autocomplete},
3402 {.tokenname = "ROUTEMAP_NAME", .completions = rmap_autocomplete},
3403 {.tokenname = "RMAP_NAME", .completions = rmap_autocomplete},
3404 {.completions = NULL}};
70d44c5c 3405
718e3744 3406/* Initialization of route map vector. */
d62a17ae 3407void route_map_init(void)
718e3744 3408{
d62a17ae 3409 int i;
3410
3411 /* Make vector for match and set. */
3412 route_match_vec = vector_init(1);
3413 route_set_vec = vector_init(1);
3414 route_map_master_hash =
996c9314 3415 hash_create_size(8, route_map_hash_key_make, route_map_hash_cmp,
bd74dc61 3416 "Route Map Master Hash");
d62a17ae 3417
3418 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
996c9314
LB
3419 route_map_dep_hash[i] = hash_create_size(
3420 8, route_map_dep_hash_make_key, route_map_dep_hash_cmp,
3421 "Route Map Dep Hash");
b2575bc0 3422
d62a17ae 3423 cmd_variable_handler_register(rmap_var_handlers);
b2575bc0 3424
e3ab8170
AD
3425 rmap_debug = false;
3426
d62a17ae 3427 /* Install route map top node. */
3428 install_node(&rmap_node, route_map_config_write);
518f0eb1 3429
e3ab8170
AD
3430 install_node(&rmap_debug_node, rmap_config_write_debug);
3431
d62a17ae 3432 /* Install route map commands. */
3433 install_default(RMAP_NODE);
3434 install_element(CONFIG_NODE, &route_map_cmd);
3435 install_element(CONFIG_NODE, &no_route_map_cmd);
3436 install_element(CONFIG_NODE, &no_route_map_all_cmd);
70d44c5c 3437
e3ab8170
AD
3438 install_element(CONFIG_NODE, &debug_rmap_cmd);
3439 install_element(CONFIG_NODE, &no_debug_rmap_cmd);
3440
d62a17ae 3441 /* Install the on-match stuff */
3442 install_element(RMAP_NODE, &route_map_cmd);
3443 install_element(RMAP_NODE, &rmap_onmatch_next_cmd);
3444 install_element(RMAP_NODE, &no_rmap_onmatch_next_cmd);
3445 install_element(RMAP_NODE, &rmap_onmatch_goto_cmd);
3446 install_element(RMAP_NODE, &no_rmap_onmatch_goto_cmd);
3447 install_element(RMAP_NODE, &rmap_continue_cmd);
3448 install_element(RMAP_NODE, &no_rmap_continue_cmd);
718e3744 3449
d62a17ae 3450 /* Install the continue stuff (ALIAS of on-match). */
718e3744 3451
d62a17ae 3452 /* Install the call stuff. */
3453 install_element(RMAP_NODE, &rmap_call_cmd);
3454 install_element(RMAP_NODE, &no_rmap_call_cmd);
4a8164e5 3455
d62a17ae 3456 /* Install description commands. */
3457 install_element(RMAP_NODE, &rmap_description_cmd);
3458 install_element(RMAP_NODE, &no_rmap_description_cmd);
82f97584 3459
d62a17ae 3460 /* Install show command */
1fa30509
DS
3461 install_element(ENABLE_NODE, &rmap_clear_counters_cmd);
3462
d62a17ae 3463 install_element(ENABLE_NODE, &rmap_show_name_cmd);
4a2a09d0 3464 install_element(ENABLE_NODE, &rmap_show_unused_cmd);
82f97584 3465
e3ab8170
AD
3466 install_element(ENABLE_NODE, &debug_rmap_cmd);
3467 install_element(ENABLE_NODE, &no_debug_rmap_cmd);
3468
d62a17ae 3469 install_element(RMAP_NODE, &match_interface_cmd);
3470 install_element(RMAP_NODE, &no_match_interface_cmd);
82f97584 3471
d62a17ae 3472 install_element(RMAP_NODE, &match_ip_address_cmd);
3473 install_element(RMAP_NODE, &no_match_ip_address_cmd);
82f97584 3474
d62a17ae 3475 install_element(RMAP_NODE, &match_ip_address_prefix_list_cmd);
3476 install_element(RMAP_NODE, &no_match_ip_address_prefix_list_cmd);
82f97584 3477
d62a17ae 3478 install_element(RMAP_NODE, &match_ip_next_hop_cmd);
3479 install_element(RMAP_NODE, &no_match_ip_next_hop_cmd);
82f97584 3480
d62a17ae 3481 install_element(RMAP_NODE, &match_ip_next_hop_prefix_list_cmd);
3482 install_element(RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd);
82f97584 3483
61ad901e
DA
3484 install_element(RMAP_NODE, &match_ip_next_hop_type_cmd);
3485 install_element(RMAP_NODE, &no_match_ip_next_hop_type_cmd);
3486
d62a17ae 3487 install_element(RMAP_NODE, &match_ipv6_address_cmd);
3488 install_element(RMAP_NODE, &no_match_ipv6_address_cmd);
82f97584 3489
d62a17ae 3490 install_element(RMAP_NODE, &match_ipv6_address_prefix_list_cmd);
3491 install_element(RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd);
82f97584 3492
61ad901e
DA
3493 install_element(RMAP_NODE, &match_ipv6_next_hop_type_cmd);
3494 install_element(RMAP_NODE, &no_match_ipv6_next_hop_type_cmd);
3495
d62a17ae 3496 install_element(RMAP_NODE, &match_metric_cmd);
3497 install_element(RMAP_NODE, &no_match_metric_cmd);
82f97584 3498
d62a17ae 3499 install_element(RMAP_NODE, &match_tag_cmd);
3500 install_element(RMAP_NODE, &no_match_tag_cmd);
82f97584 3501
d62a17ae 3502 install_element(RMAP_NODE, &set_ip_nexthop_cmd);
3503 install_element(RMAP_NODE, &no_set_ip_nexthop_cmd);
82f97584 3504
d62a17ae 3505 install_element(RMAP_NODE, &set_ipv6_nexthop_local_cmd);
3506 install_element(RMAP_NODE, &no_set_ipv6_nexthop_local_cmd);
82f97584 3507
d62a17ae 3508 install_element(RMAP_NODE, &set_metric_cmd);
3509 install_element(RMAP_NODE, &no_set_metric_cmd);
82f97584 3510
d62a17ae 3511 install_element(RMAP_NODE, &set_tag_cmd);
3512 install_element(RMAP_NODE, &no_set_tag_cmd);
718e3744 3513}