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