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