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