]> git.proxmox.com Git - mirror_frr.git/blame - lib/routemap.c
Merge pull request #4417 from sworleys/Move-Multicast-Mode
[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 }
1336}
1337
718e3744 1338/* Add match statement to route map. */
d62a17ae 1339int route_map_add_match(struct route_map_index *index, const char *match_name,
e2c8d6ce 1340 const char *match_arg, route_map_event_t type)
d62a17ae 1341{
1342 struct route_map_rule *rule;
1343 struct route_map_rule *next;
1344 struct route_map_rule_cmd *cmd;
1345 void *compile;
e2c8d6ce 1346 int8_t delete_rmap_event_type = 0;
d62a17ae 1347
1348 /* First lookup rule for add match statement. */
1349 cmd = route_map_lookup_match(match_name);
1350 if (cmd == NULL)
1351 return RMAP_RULE_MISSING;
1352
1353 /* Next call compile function for this match statement. */
1354 if (cmd->func_compile) {
1355 compile = (*cmd->func_compile)(match_arg);
1356 if (compile == NULL)
1357 return RMAP_COMPILE_ERROR;
1358 } else
1359 compile = NULL;
1360
1361 /* If argument is completely same ignore it. */
1362 for (rule = index->match_list.head; rule; rule = next) {
1363 next = rule->next;
1364 if (rule->cmd == cmd) {
6c3247bd
NT
1365 /* If the configured route-map match rule is exactly
1366 * the same as the existing configuration then,
1367 * ignore the duplicate configuration.
1368 */
1369 if (strcmp(match_arg, rule->rule_str) == 0) {
1370 if (cmd->func_free)
1371 (*cmd->func_free)(compile);
e2c8d6ce
NT
1372
1373 return RMAP_DUPLICATE_RULE;
1374 }
1375
1376 /* Remove the dependency of the route-map on the rule
1377 * that is being replaced.
1378 */
1379 if (type >= RMAP_EVENT_CALL_ADDED) {
1380 delete_rmap_event_type =
1381 get_route_map_delete_event(type);
1382 route_map_upd8_dependency(
1383 delete_rmap_event_type,
1384 rule->rule_str,
1385 index->map->name);
6c3247bd
NT
1386 }
1387
d62a17ae 1388 route_map_rule_delete(&index->match_list, rule);
d62a17ae 1389 }
718e3744 1390 }
718e3744 1391
d62a17ae 1392 /* Add new route map match rule. */
1393 rule = route_map_rule_new();
1394 rule->cmd = cmd;
1395 rule->value = compile;
1396 if (match_arg)
1397 rule->rule_str = XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR, match_arg);
1398 else
1399 rule->rule_str = NULL;
718e3744 1400
d62a17ae 1401 /* Add new route match rule to linked list. */
1402 route_map_rule_add(&index->match_list, rule);
718e3744 1403
d62a17ae 1404 /* Execute event hook. */
1405 if (route_map_master.event_hook) {
097b5973 1406 (*route_map_master.event_hook)(index->map->name);
d62a17ae 1407 route_map_notify_dependencies(index->map->name,
1408 RMAP_EVENT_CALL_ADDED);
1409 }
718e3744 1410
9ca25fed 1411 return RMAP_COMPILE_SUCCESS;
718e3744 1412}
1413
1414/* Delete specified route match rule. */
d62a17ae 1415int route_map_delete_match(struct route_map_index *index,
1416 const char *match_name, const char *match_arg)
1417{
1418 struct route_map_rule *rule;
1419 struct route_map_rule_cmd *cmd;
1420
1421 cmd = route_map_lookup_match(match_name);
1422 if (cmd == NULL)
1423 return 1;
1424
1425 for (rule = index->match_list.head; rule; rule = rule->next)
9d303b37
DL
1426 if (rule->cmd == cmd && (rulecmp(rule->rule_str, match_arg) == 0
1427 || match_arg == NULL)) {
d62a17ae 1428 route_map_rule_delete(&index->match_list, rule);
1429 /* Execute event hook. */
1430 if (route_map_master.event_hook) {
097b5973 1431 (*route_map_master.event_hook)(index->map->name);
d62a17ae 1432 route_map_notify_dependencies(
1433 index->map->name,
1434 RMAP_EVENT_CALL_ADDED);
1435 }
1436 return 0;
1437 }
1438 /* Can't find matched rule. */
1439 return 1;
718e3744 1440}
1441
1442/* Add route-map set statement to the route map. */
d62a17ae 1443int route_map_add_set(struct route_map_index *index, const char *set_name,
1444 const char *set_arg)
1445{
1446 struct route_map_rule *rule;
1447 struct route_map_rule *next;
1448 struct route_map_rule_cmd *cmd;
1449 void *compile;
d62a17ae 1450
1451 cmd = route_map_lookup_set(set_name);
1452 if (cmd == NULL)
1453 return RMAP_RULE_MISSING;
1454
1455 /* Next call compile function for this match statement. */
1456 if (cmd->func_compile) {
1457 compile = (*cmd->func_compile)(set_arg);
1458 if (compile == NULL)
1459 return RMAP_COMPILE_ERROR;
1460 } else
1461 compile = NULL;
1462
1463 /* Add by WJL. if old set command of same kind exist, delete it first
1464 to ensure only one set command of same kind exist under a
1465 route_map_index. */
1466 for (rule = index->set_list.head; rule; rule = next) {
1467 next = rule->next;
4255dbe9 1468 if (rule->cmd == cmd)
d62a17ae 1469 route_map_rule_delete(&index->set_list, rule);
d62a17ae 1470 }
1471
1472 /* Add new route map match rule. */
1473 rule = route_map_rule_new();
1474 rule->cmd = cmd;
1475 rule->value = compile;
1476 if (set_arg)
1477 rule->rule_str = XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR, set_arg);
1478 else
1479 rule->rule_str = NULL;
1480
1481 /* Add new route match rule to linked list. */
1482 route_map_rule_add(&index->set_list, rule);
1483
1484 /* Execute event hook. */
1485 if (route_map_master.event_hook) {
097b5973 1486 (*route_map_master.event_hook)(index->map->name);
d62a17ae 1487 route_map_notify_dependencies(index->map->name,
1488 RMAP_EVENT_CALL_ADDED);
718e3744 1489 }
9ca25fed 1490 return RMAP_COMPILE_SUCCESS;
718e3744 1491}
1492
1493/* Delete route map set rule. */
d62a17ae 1494int route_map_delete_set(struct route_map_index *index, const char *set_name,
1495 const char *set_arg)
1496{
1497 struct route_map_rule *rule;
1498 struct route_map_rule_cmd *cmd;
1499
1500 cmd = route_map_lookup_set(set_name);
1501 if (cmd == NULL)
1502 return 1;
1503
1504 for (rule = index->set_list.head; rule; rule = rule->next)
9d303b37
DL
1505 if ((rule->cmd == cmd) && (rulecmp(rule->rule_str, set_arg) == 0
1506 || set_arg == NULL)) {
d62a17ae 1507 route_map_rule_delete(&index->set_list, rule);
1508 /* Execute event hook. */
1509 if (route_map_master.event_hook) {
097b5973 1510 (*route_map_master.event_hook)(index->map->name);
d62a17ae 1511 route_map_notify_dependencies(
1512 index->map->name,
1513 RMAP_EVENT_CALL_ADDED);
1514 }
1515 return 0;
1516 }
1517 /* Can't find matched rule. */
1518 return 1;
718e3744 1519}
1520
3bf1c917 1521/* Apply route map's each index to the object.
1522
1523 The matrix for a route-map looks like this:
1524 (note, this includes the description for the "NEXT"
1525 and "GOTO" frobs now
d62a17ae 1526
eadd1687
LK
1527 | Match | No Match | No op
1528 |-----------|--------------|-------
1529 permit | action | cont | cont.
1530 | | default:deny | default:permit
1531 -------------------+-----------------------
1532 | deny | cont | cont.
1533 deny | | default:deny | default:permit
1534 |-----------|--------------|--------
d62a17ae 1535
fee0f4c6 1536 action)
1537 -Apply Set statements, accept route
1538 -If Call statement is present jump to the specified route-map, if it
d62a17ae 1539 denies the route we finish.
fee0f4c6 1540 -If NEXT is specified, goto NEXT statement
1541 -If GOTO is specified, goto the first clause where pref > nextpref
1542 -If nothing is specified, do as Cisco and finish
1543 deny)
1544 -Route is denied by route-map.
1545 cont)
1546 -Goto Next index
d62a17ae 1547
3bf1c917 1548 If we get no matches after we've processed all updates, then the route
1549 is dropped too.
d62a17ae 1550
fee0f4c6 1551 Some notes on the new "CALL", "NEXT" and "GOTO"
1552 call WORD - If this clause is matched, then the set statements
d62a17ae 1553 are executed and then we jump to route-map 'WORD'. If
1554 this route-map denies the route, we finish, in other
1555 case we
1556 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
3bf1c917 1557 on-match next - If this clause is matched, then the set statements
d62a17ae 1558 are executed and then we drop through to the next clause
3bf1c917 1559 on-match goto n - If this clause is matched, then the set statments
d62a17ae 1560 are executed and then we goto the nth clause, or the
1561 first clause greater than this. In order to ensure
1562 route-maps *always* exit, you cannot jump backwards.
1563 Sorry ;)
1564
3bf1c917 1565 We need to make sure our route-map processing matches the above
718e3744 1566*/
3bf1c917 1567
eadd1687 1568static enum route_map_match_result_t
d62a17ae 1569route_map_apply_match(struct route_map_rule_list *match_list,
123214ef 1570 const struct prefix *prefix, route_map_object_t type,
d62a17ae 1571 void *object)
1572{
eadd1687 1573 enum route_map_match_result_t ret = RMAP_NOMATCH;
d62a17ae 1574 struct route_map_rule *match;
1575
1576
1577 /* Check all match rule and if there is no match rule, go to the
1578 set statement. */
1579 if (!match_list->head)
1580 ret = RMAP_MATCH;
1581 else {
1582 for (match = match_list->head; match; match = match->next) {
1583 /* Try each match statement in turn, If any do not
1584 return
1585 RMAP_MATCH, return, otherwise continue on to next
1586 match
1587 statement. All match statements must match for
1588 end-result
1589 to be a match. */
1590 ret = (*match->cmd->func_apply)(match->value, prefix,
1591 type, object);
1592 if (ret != RMAP_MATCH)
1593 return ret;
1594 }
1595 }
1596 return ret;
718e3744 1597}
1598
1599/* Apply route map to the object. */
123214ef
MS
1600route_map_result_t route_map_apply(struct route_map *map,
1601 const struct prefix *prefix,
d62a17ae 1602 route_map_object_t type, void *object)
1603{
1604 static int recursion = 0;
eadd1687
LK
1605 enum route_map_match_result_t match_ret = RMAP_NOMATCH;
1606 route_map_result_t ret = 0;
d62a17ae 1607 struct route_map_index *index;
1608 struct route_map_rule *set;
1609
1610 if (recursion > RMAP_RECURSION_LIMIT) {
040c7c3a 1611 flog_warn(
450971aa 1612 EC_LIB_RMAP_RECURSION_LIMIT,
d62a17ae 1613 "route-map recursion limit (%d) reached, discarding route",
1614 RMAP_RECURSION_LIMIT);
1615 recursion = 0;
1616 return RMAP_DENYMATCH;
1617 }
1618
1619 if (map == NULL)
1620 return RMAP_DENYMATCH;
1621
279b0607 1622 map->applied++;
d62a17ae 1623 for (index = map->head; index; index = index->next) {
1624 /* Apply this index. */
279b0607 1625 index->applied++;
eadd1687
LK
1626 match_ret = route_map_apply_match(&index->match_list, prefix,
1627 type, object);
d62a17ae 1628
1629 /* Now we apply the matrix from above */
eadd1687 1630 if (match_ret == RMAP_NOMATCH || match_ret == RMAP_NOOP)
d62a17ae 1631 /* 'cont' from matrix - continue to next route-map
1632 * sequence */
1633 continue;
eadd1687 1634 else if (match_ret == RMAP_MATCH) {
d62a17ae 1635 if (index->type == RMAP_PERMIT)
1636 /* 'action' */
1637 {
eadd1687
LK
1638 /* Match succeeded, rmap is of type permit */
1639 ret = RMAP_PERMITMATCH;
1640
d62a17ae 1641 /* permit+match must execute sets */
1642 for (set = index->set_list.head; set;
1643 set = set->next)
eadd1687
LK
1644 /*
1645 * We dont care abt the return value
1646 * for set cmd. Almost always,
1647 * RMAP_OKAY is returned. Rarely
1648 * do we see RMAP_ERROR
1649 */
1650 match_ret = (*set->cmd->func_apply)(
1651 set->value, prefix, type,
1652 object);
d62a17ae 1653
1654 /* Call another route-map if available */
1655 if (index->nextrm) {
1656 struct route_map *nextrm =
1657 route_map_lookup_by_name(
1658 index->nextrm);
1659
1660 if (nextrm) /* Target route-map found,
1661 jump to it */
1662 {
1663 recursion++;
1664 ret = route_map_apply(
1665 nextrm, prefix, type,
1666 object);
1667 recursion--;
1668 }
1669
1670 /* If nextrm returned 'deny', finish. */
1671 if (ret == RMAP_DENYMATCH)
1672 return ret;
1673 }
1674
1675 switch (index->exitpolicy) {
1676 case RMAP_EXIT:
1677 return ret;
1678 case RMAP_NEXT:
1679 continue;
1680 case RMAP_GOTO: {
1681 /* Find the next clause to jump to */
1682 struct route_map_index *next =
1683 index->next;
1684 int nextpref = index->nextpref;
1685
1686 while (next && next->pref < nextpref) {
1687 index = next;
1688 next = next->next;
1689 }
1690 if (next == NULL) {
1691 /* No clauses match! */
1692 return ret;
1693 }
1694 }
1695 }
1696 } else if (index->type == RMAP_DENY)
1697 /* 'deny' */
1698 {
1699 return RMAP_DENYMATCH;
1700 }
1701 }
1702 }
eadd1687
LK
1703
1704 if (match_ret == RMAP_NOOP)
1705 return RMAP_PERMITMATCH;
1706
d62a17ae 1707 /* Finally route-map does not match at all. */
1708 return RMAP_DENYMATCH;
1709}
1710
1711void route_map_add_hook(void (*func)(const char *))
1712{
1713 route_map_master.add_hook = func;
1714}
1715
1716void route_map_delete_hook(void (*func)(const char *))
1717{
1718 route_map_master.delete_hook = func;
1719}
1720
097b5973 1721void route_map_event_hook(void (*func)(const char *name))
d62a17ae 1722{
1723 route_map_master.event_hook = func;
718e3744 1724}
1725
518f0eb1 1726/* Routines for route map dependency lists and dependency processing */
74df8d6d 1727static bool route_map_rmap_hash_cmp(const void *p1, const void *p2)
518f0eb1 1728{
e2c8d6ce
NT
1729 return strcmp(((const struct route_map_dep_data *)p1)->rname,
1730 ((const struct route_map_dep_data *)p2)->rname)
1731 == 0;
518f0eb1
DS
1732}
1733
74df8d6d 1734static bool route_map_dep_hash_cmp(const void *p1, const void *p2)
518f0eb1
DS
1735{
1736
d62a17ae 1737 return (strcmp(((const struct route_map_dep *)p1)->dep_name,
1738 (const char *)p2)
1739 == 0);
518f0eb1
DS
1740}
1741
e3b78da8 1742static void route_map_clear_reference(struct hash_bucket *bucket, void *arg)
518f0eb1 1743{
e2c8d6ce
NT
1744 struct route_map_dep *dep = bucket->data;
1745 struct route_map_dep_data *dep_data = NULL, tmp_dep_data;
518f0eb1 1746
1fae5ff2 1747 if (arg) {
e2c8d6ce
NT
1748 memset(&tmp_dep_data, 0, sizeof(struct route_map_dep_data));
1749 tmp_dep_data.rname = arg;
1750 dep_data = hash_release(dep->dep_rmap_hash,
1751 &tmp_dep_data);
1752 if (dep_data) {
1753 XFREE(MTYPE_ROUTE_MAP_NAME, dep_data->rname);
1754 XFREE(MTYPE_ROUTE_MAP_DEP_DATA, dep_data);
d62a17ae 1755 }
1756 if (!dep->dep_rmap_hash->count) {
1757 dep = hash_release(dep->this_hash,
1758 (void *)dep->dep_name);
1759 hash_free(dep->dep_rmap_hash);
1760 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
1761 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
1762 }
518f0eb1 1763 }
d62a17ae 1764}
1765
1766static void route_map_clear_all_references(char *rmap_name)
1767{
1768 int i;
1769
1770 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
1771 hash_iterate(route_map_dep_hash[i], route_map_clear_reference,
1772 (void *)rmap_name);
518f0eb1 1773 }
518f0eb1
DS
1774}
1775
e2c8d6ce
NT
1776static unsigned int route_map_dep_data_hash_make_key(const void *p)
1777{
1778 const struct route_map_dep_data *dep_data = p;
1779
1780 return string_hash_make(dep_data->rname);
1781}
1782
d62a17ae 1783static void *route_map_dep_hash_alloc(void *p)
518f0eb1 1784{
d62a17ae 1785 char *dep_name = (char *)p;
1786 struct route_map_dep *dep_entry;
1787
1788 dep_entry = XCALLOC(MTYPE_ROUTE_MAP_DEP, sizeof(struct route_map_dep));
1789 dep_entry->dep_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
996c9314 1790 dep_entry->dep_rmap_hash =
e2c8d6ce 1791 hash_create_size(8, route_map_dep_data_hash_make_key,
996c9314 1792 route_map_rmap_hash_cmp, "Route Map Dep Hash");
d62a17ae 1793 dep_entry->this_hash = NULL;
1794
e2c8d6ce 1795 return dep_entry;
d62a17ae 1796}
518f0eb1 1797
d62a17ae 1798static void *route_map_name_hash_alloc(void *p)
1799{
e2c8d6ce
NT
1800 struct route_map_dep_data *dep_data = NULL, *tmp_dep_data = NULL;
1801
1802 dep_data = XCALLOC(MTYPE_ROUTE_MAP_DEP_DATA,
1803 sizeof(struct route_map_dep_data));
1804 tmp_dep_data = p;
1805 dep_data->rname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, tmp_dep_data->rname);
1806 return dep_data;
518f0eb1
DS
1807}
1808
d8b87afe 1809static unsigned int route_map_dep_hash_make_key(const void *p)
518f0eb1 1810{
d62a17ae 1811 return (string_hash_make((char *)p));
1812}
518f0eb1 1813
e3b78da8 1814static void route_map_print_dependency(struct hash_bucket *bucket, void *data)
d62a17ae 1815{
e2c8d6ce
NT
1816 struct route_map_dep_data *dep_data = bucket->data;
1817 char *rmap_name = dep_data->rname;
1818 char *dep_name = data;
518f0eb1 1819
1fae5ff2
DS
1820 zlog_debug("%s: Dependency for %s: %s", __FUNCTION__, dep_name,
1821 rmap_name);
518f0eb1
DS
1822}
1823
d62a17ae 1824static int route_map_dep_update(struct hash *dephash, const char *dep_name,
1825 const char *rmap_name, route_map_event_t type)
518f0eb1 1826{
d62a17ae 1827 struct route_map_dep *dep = NULL;
d62a17ae 1828 char *dname, *rname;
1829 int ret = 0;
e2c8d6ce
NT
1830 struct route_map_dep_data *dep_data = NULL, *ret_dep_data = NULL;
1831 struct route_map_dep_data tmp_dep_data;
d62a17ae 1832
1833 dname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
1834 rname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_name);
1835
1836 switch (type) {
1837 case RMAP_EVENT_PLIST_ADDED:
1838 case RMAP_EVENT_CLIST_ADDED:
1839 case RMAP_EVENT_ECLIST_ADDED:
1840 case RMAP_EVENT_ASLIST_ADDED:
1841 case RMAP_EVENT_LLIST_ADDED:
1842 case RMAP_EVENT_CALL_ADDED:
1843 case RMAP_EVENT_FILTER_ADDED:
1844 if (rmap_debug)
1845 zlog_debug("%s: Adding dependency for %s in %s",
1846 __FUNCTION__, dep_name, rmap_name);
1847 dep = (struct route_map_dep *)hash_get(
1848 dephash, dname, route_map_dep_hash_alloc);
1849 if (!dep) {
1850 ret = -1;
1851 goto out;
1852 }
1853
1854 if (!dep->this_hash)
1855 dep->this_hash = dephash;
1856
e2c8d6ce
NT
1857 memset(&tmp_dep_data, 0, sizeof(struct route_map_dep_data));
1858 tmp_dep_data.rname = rname;
1859 dep_data = hash_lookup(dep->dep_rmap_hash, &tmp_dep_data);
1860 if (!dep_data)
1861 dep_data = hash_get(dep->dep_rmap_hash, &tmp_dep_data,
1862 route_map_name_hash_alloc);
1863
1864 dep_data->refcnt++;
d62a17ae 1865 break;
1866 case RMAP_EVENT_PLIST_DELETED:
1867 case RMAP_EVENT_CLIST_DELETED:
1868 case RMAP_EVENT_ECLIST_DELETED:
1869 case RMAP_EVENT_ASLIST_DELETED:
1870 case RMAP_EVENT_LLIST_DELETED:
1871 case RMAP_EVENT_CALL_DELETED:
1872 case RMAP_EVENT_FILTER_DELETED:
1873 if (rmap_debug)
1874 zlog_debug("%s: Deleting dependency for %s in %s",
1875 __FUNCTION__, dep_name, rmap_name);
1876 dep = (struct route_map_dep *)hash_get(dephash, dname, NULL);
1877 if (!dep) {
1878 goto out;
1879 }
1880
e2c8d6ce
NT
1881 memset(&tmp_dep_data, 0, sizeof(struct route_map_dep_data));
1882 tmp_dep_data.rname = rname;
1883 dep_data = hash_lookup(dep->dep_rmap_hash, &tmp_dep_data);
1884 dep_data->refcnt--;
1885
1886 if (!dep_data->refcnt) {
1887 ret_dep_data = hash_release(dep->dep_rmap_hash,
1888 &tmp_dep_data);
1889 if (ret_dep_data) {
1890 XFREE(MTYPE_ROUTE_MAP_NAME,
1891 ret_dep_data->rname);
1892 XFREE(MTYPE_ROUTE_MAP_DEP_DATA, ret_dep_data);
1893 }
1894 }
d62a17ae 1895
1896 if (!dep->dep_rmap_hash->count) {
1897 dep = hash_release(dephash, dname);
1898 hash_free(dep->dep_rmap_hash);
1899 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
1900 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
1901 dep = NULL;
1902 }
1903 break;
ba1707ca
DS
1904 case RMAP_EVENT_SET_ADDED:
1905 case RMAP_EVENT_SET_DELETED:
1906 case RMAP_EVENT_SET_REPLACED:
1907 case RMAP_EVENT_MATCH_ADDED:
1908 case RMAP_EVENT_MATCH_DELETED:
1909 case RMAP_EVENT_MATCH_REPLACED:
1910 case RMAP_EVENT_INDEX_ADDED:
1911 case RMAP_EVENT_INDEX_DELETED:
d62a17ae 1912 break;
1913 }
1914
1915 if (dep) {
1916 if (rmap_debug)
1917 hash_iterate(dep->dep_rmap_hash,
1918 route_map_print_dependency, dname);
1919 }
1920
1921out:
1922 XFREE(MTYPE_ROUTE_MAP_NAME, rname);
1923 XFREE(MTYPE_ROUTE_MAP_NAME, dname);
1924 return ret;
1925}
1926
1927static struct hash *route_map_get_dep_hash(route_map_event_t event)
1928{
1929 struct hash *upd8_hash = NULL;
1930
1931 switch (event) {
1932 case RMAP_EVENT_PLIST_ADDED:
1933 case RMAP_EVENT_PLIST_DELETED:
1934 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_PLIST];
1935 break;
1936 case RMAP_EVENT_CLIST_ADDED:
1937 case RMAP_EVENT_CLIST_DELETED:
1938 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_CLIST];
1939 break;
1940 case RMAP_EVENT_ECLIST_ADDED:
1941 case RMAP_EVENT_ECLIST_DELETED:
1942 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ECLIST];
1943 break;
1944 case RMAP_EVENT_ASLIST_ADDED:
1945 case RMAP_EVENT_ASLIST_DELETED:
1946 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ASPATH];
1947 break;
1948 case RMAP_EVENT_LLIST_ADDED:
1949 case RMAP_EVENT_LLIST_DELETED:
1950 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_LCLIST];
1951 break;
1952 case RMAP_EVENT_CALL_ADDED:
1953 case RMAP_EVENT_CALL_DELETED:
5ed2e47b 1954 case RMAP_EVENT_MATCH_ADDED:
1955 case RMAP_EVENT_MATCH_DELETED:
d62a17ae 1956 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_RMAP];
1957 break;
1958 case RMAP_EVENT_FILTER_ADDED:
1959 case RMAP_EVENT_FILTER_DELETED:
1960 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_FILTER];
1961 break;
ba1707ca
DS
1962 /*
1963 * Should we actually be ignoring these?
1964 * I am not sure but at this point in time, let
1965 * us get them into this switch and we can peel
1966 * them into the appropriate place in the future
1967 */
1968 case RMAP_EVENT_SET_ADDED:
1969 case RMAP_EVENT_SET_DELETED:
1970 case RMAP_EVENT_SET_REPLACED:
1971 case RMAP_EVENT_MATCH_REPLACED:
1972 case RMAP_EVENT_INDEX_ADDED:
1973 case RMAP_EVENT_INDEX_DELETED:
d62a17ae 1974 upd8_hash = NULL;
1975 break;
1976 }
1977 return (upd8_hash);
518f0eb1
DS
1978}
1979
e3b78da8 1980static void route_map_process_dependency(struct hash_bucket *bucket, void *data)
518f0eb1 1981{
e2c8d6ce
NT
1982 struct route_map_dep_data *dep_data = NULL;
1983 char *rmap_name = NULL;
1984
1985 dep_data = bucket->data;
1986 rmap_name = dep_data->rname;
d62a17ae 1987
1fae5ff2
DS
1988 if (rmap_debug)
1989 zlog_debug("%s: Notifying %s of dependency",
1990 __FUNCTION__, rmap_name);
1991 if (route_map_master.event_hook)
097b5973 1992 (*route_map_master.event_hook)(rmap_name);
518f0eb1
DS
1993}
1994
d62a17ae 1995void route_map_upd8_dependency(route_map_event_t type, const char *arg,
1996 const char *rmap_name)
518f0eb1 1997{
d62a17ae 1998 struct hash *upd8_hash = NULL;
518f0eb1 1999
fdf823db 2000 if ((upd8_hash = route_map_get_dep_hash(type))) {
d62a17ae 2001 route_map_dep_update(upd8_hash, arg, rmap_name, type);
fdf823db
NT
2002
2003 if (type == RMAP_EVENT_CALL_ADDED) {
2004 /* Execute hook. */
2005 if (route_map_master.add_hook)
2006 (*route_map_master.add_hook)(rmap_name);
2007 } else if (type == RMAP_EVENT_CALL_DELETED) {
2008 /* Execute hook. */
2009 if (route_map_master.delete_hook)
2010 (*route_map_master.delete_hook)(rmap_name);
2011 }
2012 }
518f0eb1
DS
2013}
2014
d62a17ae 2015void route_map_notify_dependencies(const char *affected_name,
2016 route_map_event_t event)
518f0eb1 2017{
d62a17ae 2018 struct route_map_dep *dep;
2019 struct hash *upd8_hash;
2020 char *name;
2021
2022 if (!affected_name)
2023 return;
2024
2025 name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, affected_name);
2026
2027 if ((upd8_hash = route_map_get_dep_hash(event)) == NULL) {
2028 XFREE(MTYPE_ROUTE_MAP_NAME, name);
2029 return;
518f0eb1 2030 }
d62a17ae 2031
2032 dep = (struct route_map_dep *)hash_get(upd8_hash, name, NULL);
2033 if (dep) {
2034 if (!dep->this_hash)
2035 dep->this_hash = upd8_hash;
2036
2037 hash_iterate(dep->dep_rmap_hash, route_map_process_dependency,
2038 (void *)event);
2039 }
2040
2041 XFREE(MTYPE_ROUTE_MAP_NAME, name);
518f0eb1
DS
2042}
2043
82f97584 2044
718e3744 2045/* VTY related functions. */
82f97584
DW
2046DEFUN (match_interface,
2047 match_interface_cmd,
2048 "match interface WORD",
2049 MATCH_STR
2050 "match first hop interface of route\n"
2051 "Interface name\n")
2052{
d62a17ae 2053 int idx_word = 2;
2054 VTY_DECLVAR_CONTEXT(route_map_index, index);
82f97584 2055
d62a17ae 2056 if (rmap_match_set_hook.match_interface)
2057 return rmap_match_set_hook.match_interface(
2058 vty, index, "interface", argv[idx_word]->arg,
2059 RMAP_EVENT_MATCH_ADDED);
2060 return CMD_SUCCESS;
82f97584
DW
2061}
2062
2063DEFUN (no_match_interface,
2064 no_match_interface_cmd,
70d44c5c 2065 "no match interface [WORD]",
82f97584
DW
2066 NO_STR
2067 MATCH_STR
2068 "Match first hop interface of route\n"
2069 "Interface name\n")
2070{
d62a17ae 2071 char *iface = (argc == 4) ? argv[3]->arg : NULL;
2072 VTY_DECLVAR_CONTEXT(route_map_index, index);
82f97584 2073
d62a17ae 2074 if (rmap_match_set_hook.no_match_interface)
2075 return rmap_match_set_hook.no_match_interface(
2076 vty, index, "interface", iface,
2077 RMAP_EVENT_MATCH_DELETED);
2078 return CMD_SUCCESS;
82f97584
DW
2079}
2080
2081
2082DEFUN (match_ip_address,
2083 match_ip_address_cmd,
2084 "match ip address <(1-199)|(1300-2699)|WORD>",
2085 MATCH_STR
2086 IP_STR
2087 "Match address of route\n"
2088 "IP access-list number\n"
2089 "IP access-list number (expanded range)\n"
2090 "IP Access-list name\n")
2091{
d62a17ae 2092 int idx_acl = 3;
2093 VTY_DECLVAR_CONTEXT(route_map_index, index);
82f97584 2094
d62a17ae 2095 if (rmap_match_set_hook.match_ip_address)
2096 return rmap_match_set_hook.match_ip_address(
2097 vty, index, "ip address", argv[idx_acl]->arg,
2098 RMAP_EVENT_FILTER_ADDED);
2099 return CMD_SUCCESS;
82f97584
DW
2100}
2101
2102
2103DEFUN (no_match_ip_address,
2104 no_match_ip_address_cmd,
2105 "no match ip address [<(1-199)|(1300-2699)|WORD>]",
2106 NO_STR
2107 MATCH_STR
2108 IP_STR
2109 "Match address of route\n"
2110 "IP access-list number\n"
2111 "IP access-list number (expanded range)\n"
2112 "IP Access-list name\n")
2113{
d62a17ae 2114 int idx_word = 4;
2115 VTY_DECLVAR_CONTEXT(route_map_index, index);
2116
2117 if (rmap_match_set_hook.no_match_ip_address) {
2118 if (argc <= idx_word)
2119 return rmap_match_set_hook.no_match_ip_address(
2120 vty, index, "ip address", NULL,
2121 RMAP_EVENT_FILTER_DELETED);
2122 return rmap_match_set_hook.no_match_ip_address(
2123 vty, index, "ip address", argv[idx_word]->arg,
2124 RMAP_EVENT_FILTER_DELETED);
2125 }
2126 return CMD_SUCCESS;
82f97584
DW
2127}
2128
2129
2130DEFUN (match_ip_address_prefix_list,
2131 match_ip_address_prefix_list_cmd,
2132 "match ip address prefix-list WORD",
2133 MATCH_STR
2134 IP_STR
2135 "Match address of route\n"
2136 "Match entries of prefix-lists\n"
2137 "IP prefix-list name\n")
2138{
d62a17ae 2139 int idx_word = 4;
2140 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2141
d62a17ae 2142 if (rmap_match_set_hook.match_ip_address_prefix_list)
2143 return rmap_match_set_hook.match_ip_address_prefix_list(
2144 vty, index, "ip address prefix-list",
2145 argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
2146 return CMD_SUCCESS;
82f97584
DW
2147}
2148
2149
2150DEFUN (no_match_ip_address_prefix_list,
2151 no_match_ip_address_prefix_list_cmd,
2152 "no match ip address prefix-list [WORD]",
2153 NO_STR
2154 MATCH_STR
2155 IP_STR
2156 "Match address of route\n"
2157 "Match entries of prefix-lists\n"
2158 "IP prefix-list name\n")
2159{
d62a17ae 2160 int idx_word = 5;
2161 VTY_DECLVAR_CONTEXT(route_map_index, index);
2162
2163 if (rmap_match_set_hook.no_match_ip_address_prefix_list) {
2164 if (argc <= idx_word)
2165 return rmap_match_set_hook
2166 .no_match_ip_address_prefix_list(
2167 vty, index, "ip address prefix-list",
2168 NULL, RMAP_EVENT_PLIST_DELETED);
2169 return rmap_match_set_hook.no_match_ip_address_prefix_list(
2170 vty, index, "ip address prefix-list",
2171 argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
2172 }
2173 return CMD_SUCCESS;
82f97584
DW
2174}
2175
2176
2177DEFUN (match_ip_next_hop,
2178 match_ip_next_hop_cmd,
2179 "match ip next-hop <(1-199)|(1300-2699)|WORD>",
2180 MATCH_STR
2181 IP_STR
2182 "Match next-hop address of route\n"
2183 "IP access-list number\n"
2184 "IP access-list number (expanded range)\n"
2185 "IP Access-list name\n")
2186{
d62a17ae 2187 int idx_acl = 3;
2188 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2189
d62a17ae 2190 if (rmap_match_set_hook.match_ip_next_hop)
2191 return rmap_match_set_hook.match_ip_next_hop(
2192 vty, index, "ip next-hop", argv[idx_acl]->arg,
2193 RMAP_EVENT_FILTER_ADDED);
2194 return CMD_SUCCESS;
82f97584
DW
2195}
2196
2197
2198DEFUN (no_match_ip_next_hop,
2199 no_match_ip_next_hop_cmd,
2200 "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
2201 NO_STR
2202 MATCH_STR
2203 IP_STR
2204 "Match next-hop address of route\n"
2205 "IP access-list number\n"
2206 "IP access-list number (expanded range)\n"
2207 "IP Access-list name\n")
2208{
d62a17ae 2209 int idx_word = 4;
2210 VTY_DECLVAR_CONTEXT(route_map_index, index);
2211
2212 if (rmap_match_set_hook.no_match_ip_next_hop) {
2213 if (argc <= idx_word)
2214 return rmap_match_set_hook.no_match_ip_next_hop(
2215 vty, index, "ip next-hop", NULL,
2216 RMAP_EVENT_FILTER_DELETED);
2217 return rmap_match_set_hook.no_match_ip_next_hop(
2218 vty, index, "ip next-hop", argv[idx_word]->arg,
2219 RMAP_EVENT_FILTER_DELETED);
2220 }
2221 return CMD_SUCCESS;
82f97584
DW
2222}
2223
2224
2225DEFUN (match_ip_next_hop_prefix_list,
2226 match_ip_next_hop_prefix_list_cmd,
2227 "match ip next-hop prefix-list WORD",
2228 MATCH_STR
2229 IP_STR
2230 "Match next-hop address of route\n"
2231 "Match entries of prefix-lists\n"
2232 "IP prefix-list name\n")
2233{
d62a17ae 2234 int idx_word = 4;
2235 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2236
d62a17ae 2237 if (rmap_match_set_hook.match_ip_next_hop_prefix_list)
2238 return rmap_match_set_hook.match_ip_next_hop_prefix_list(
2239 vty, index, "ip next-hop prefix-list",
2240 argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
2241 return CMD_SUCCESS;
82f97584
DW
2242}
2243
2244DEFUN (no_match_ip_next_hop_prefix_list,
2245 no_match_ip_next_hop_prefix_list_cmd,
2246 "no match ip next-hop prefix-list [WORD]",
2247 NO_STR
2248 MATCH_STR
2249 IP_STR
2250 "Match next-hop address of route\n"
2251 "Match entries of prefix-lists\n"
2252 "IP prefix-list name\n")
2253{
d62a17ae 2254 int idx_word = 5;
2255 VTY_DECLVAR_CONTEXT(route_map_index, index);
2256
2257 if (rmap_match_set_hook.no_match_ip_next_hop) {
2258 if (argc <= idx_word)
2259 return rmap_match_set_hook.no_match_ip_next_hop(
2260 vty, index, "ip next-hop prefix-list", NULL,
2261 RMAP_EVENT_PLIST_DELETED);
2262 return rmap_match_set_hook.no_match_ip_next_hop(
2263 vty, index, "ip next-hop prefix-list",
2264 argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
2265 }
2266 return CMD_SUCCESS;
82f97584
DW
2267}
2268
61ad901e
DA
2269DEFUN(match_ip_next_hop_type, match_ip_next_hop_type_cmd,
2270 "match ip next-hop type <blackhole>",
2271 MATCH_STR IP_STR
2272 "Match next-hop address of route\n"
2273 "Match entries by type\n"
2274 "Blackhole\n")
2275{
2276 int idx_word = 4;
2277 VTY_DECLVAR_CONTEXT(route_map_index, index);
2278
2279 if (rmap_match_set_hook.match_ip_next_hop_type)
2280 return rmap_match_set_hook.match_ip_next_hop_type(
2281 vty, index, "ip next-hop type", argv[idx_word]->arg,
2282 RMAP_EVENT_MATCH_ADDED);
2283 return CMD_SUCCESS;
2284}
2285
2286DEFUN(no_match_ip_next_hop_type, no_match_ip_next_hop_type_cmd,
2287 "no match ip next-hop type [<blackhole>]",
2288 NO_STR MATCH_STR IP_STR
2289 "Match next-hop address of route\n"
2290 "Match entries by type\n"
2291 "Blackhole\n")
2292{
2293 int idx_word = 5;
2294 VTY_DECLVAR_CONTEXT(route_map_index, index);
2295
2296 if (rmap_match_set_hook.no_match_ip_next_hop) {
2297 if (argc <= idx_word)
2298 return rmap_match_set_hook.no_match_ip_next_hop(
2299 vty, index, "ip next-hop type", NULL,
2300 RMAP_EVENT_MATCH_DELETED);
2301 return rmap_match_set_hook.no_match_ip_next_hop(
2302 vty, index, "ip next-hop type", argv[idx_word]->arg,
2303 RMAP_EVENT_MATCH_DELETED);
2304 }
2305 return CMD_SUCCESS;
2306}
2307
82f97584
DW
2308
2309DEFUN (match_ipv6_address,
2310 match_ipv6_address_cmd,
2311 "match ipv6 address WORD",
2312 MATCH_STR
2313 IPV6_STR
2314 "Match IPv6 address of route\n"
2315 "IPv6 access-list name\n")
2316{
d62a17ae 2317 int idx_word = 3;
2318 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2319
d62a17ae 2320 if (rmap_match_set_hook.match_ipv6_address)
2321 return rmap_match_set_hook.match_ipv6_address(
2322 vty, index, "ipv6 address", argv[idx_word]->arg,
2323 RMAP_EVENT_FILTER_ADDED);
2324 return CMD_SUCCESS;
82f97584
DW
2325}
2326
2327DEFUN (no_match_ipv6_address,
2328 no_match_ipv6_address_cmd,
2329 "no match ipv6 address WORD",
2330 NO_STR
2331 MATCH_STR
2332 IPV6_STR
2333 "Match IPv6 address of route\n"
2334 "IPv6 access-list name\n")
2335{
d62a17ae 2336 int idx_word = 4;
2337 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2338
d62a17ae 2339 if (rmap_match_set_hook.no_match_ipv6_address)
2340 return rmap_match_set_hook.no_match_ipv6_address(
2341 vty, index, "ipv6 address", argv[idx_word]->arg,
2342 RMAP_EVENT_FILTER_DELETED);
2343 return CMD_SUCCESS;
82f97584
DW
2344}
2345
2346
2347DEFUN (match_ipv6_address_prefix_list,
2348 match_ipv6_address_prefix_list_cmd,
2349 "match ipv6 address prefix-list WORD",
2350 MATCH_STR
2351 IPV6_STR
2352 "Match address of route\n"
2353 "Match entries of prefix-lists\n"
2354 "IP prefix-list name\n")
2355{
d62a17ae 2356 int idx_word = 4;
2357 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2358
d62a17ae 2359 if (rmap_match_set_hook.match_ipv6_address_prefix_list)
2360 return rmap_match_set_hook.match_ipv6_address_prefix_list(
2361 vty, index, "ipv6 address prefix-list",
2362 argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
2363 return CMD_SUCCESS;
82f97584
DW
2364}
2365
2366DEFUN (no_match_ipv6_address_prefix_list,
2367 no_match_ipv6_address_prefix_list_cmd,
2368 "no match ipv6 address prefix-list WORD",
2369 NO_STR
2370 MATCH_STR
2371 IPV6_STR
2372 "Match address of route\n"
2373 "Match entries of prefix-lists\n"
2374 "IP prefix-list name\n")
2375{
d62a17ae 2376 int idx_word = 5;
2377 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2378
d62a17ae 2379 if (rmap_match_set_hook.no_match_ipv6_address_prefix_list)
2380 return rmap_match_set_hook.no_match_ipv6_address_prefix_list(
2381 vty, index, "ipv6 address prefix-list",
2382 argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
2383 return CMD_SUCCESS;
82f97584
DW
2384}
2385
61ad901e
DA
2386DEFUN(match_ipv6_next_hop_type, match_ipv6_next_hop_type_cmd,
2387 "match ipv6 next-hop type <blackhole>",
2388 MATCH_STR IPV6_STR
2389 "Match address of route\n"
2390 "Match entries by type\n"
2391 "Blackhole\n")
2392{
2393 int idx_word = 4;
2394 VTY_DECLVAR_CONTEXT(route_map_index, index);
2395
2396 if (rmap_match_set_hook.match_ipv6_next_hop_type)
2397 return rmap_match_set_hook.match_ipv6_next_hop_type(
2398 vty, index, "ipv6 next-hop type", argv[idx_word]->arg,
2399 RMAP_EVENT_MATCH_ADDED);
2400 return CMD_SUCCESS;
2401}
2402
2403DEFUN(no_match_ipv6_next_hop_type, no_match_ipv6_next_hop_type_cmd,
2404 "no match ipv6 next-hop type [<blackhole>]",
2405 NO_STR MATCH_STR IPV6_STR
2406 "Match address of route\n"
2407 "Match entries by type\n"
2408 "Blackhole\n")
2409{
2410 int idx_word = 5;
2411 VTY_DECLVAR_CONTEXT(route_map_index, index);
2412
2413 if (rmap_match_set_hook.no_match_ipv6_next_hop_type)
2414 return rmap_match_set_hook.no_match_ipv6_next_hop_type(
4cfecc3e
RW
2415 vty, index, "ipv6 next-hop type",
2416 (argc <= idx_word) ? NULL : argv[idx_word]->arg,
61ad901e
DA
2417 RMAP_EVENT_MATCH_DELETED);
2418 return CMD_SUCCESS;
2419}
82f97584
DW
2420
2421DEFUN (match_metric,
2422 match_metric_cmd,
2423 "match metric (0-4294967295)",
2424 MATCH_STR
2425 "Match metric of route\n"
2426 "Metric value\n")
2427{
d62a17ae 2428 int idx_number = 2;
2429 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2430
d62a17ae 2431 if (rmap_match_set_hook.match_metric)
2432 return rmap_match_set_hook.match_metric(vty, index, "metric",
2433 argv[idx_number]->arg,
2434 RMAP_EVENT_MATCH_ADDED);
2435 return CMD_SUCCESS;
82f97584
DW
2436}
2437
2438
2439DEFUN (no_match_metric,
2440 no_match_metric_cmd,
2441 "no match metric [(0-4294967295)]",
2442 NO_STR
2443 MATCH_STR
2444 "Match metric of route\n"
2445 "Metric value\n")
2446{
d62a17ae 2447 int idx_number = 3;
2448 VTY_DECLVAR_CONTEXT(route_map_index, index);
2449
2450 if (rmap_match_set_hook.no_match_metric) {
2451 if (argc <= idx_number)
2452 return rmap_match_set_hook.no_match_metric(
2453 vty, index, "metric", NULL,
2454 RMAP_EVENT_MATCH_DELETED);
2455 return rmap_match_set_hook.no_match_metric(
2456 vty, index, "metric", argv[idx_number]->arg,
2457 RMAP_EVENT_MATCH_DELETED);
2458 }
2459 return CMD_SUCCESS;
82f97584
DW
2460}
2461
2462
2463DEFUN (match_tag,
2464 match_tag_cmd,
e52702f2 2465 "match tag (1-4294967295)",
82f97584
DW
2466 MATCH_STR
2467 "Match tag of route\n"
2468 "Tag value\n")
2469{
d62a17ae 2470 int idx_number = 2;
2471 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2472
d62a17ae 2473 if (rmap_match_set_hook.match_tag)
2474 return rmap_match_set_hook.match_tag(vty, index, "tag",
2475 argv[idx_number]->arg,
2476 RMAP_EVENT_MATCH_ADDED);
2477 return CMD_SUCCESS;
82f97584
DW
2478}
2479
2480
2481DEFUN (no_match_tag,
2482 no_match_tag_cmd,
e52702f2 2483 "no match tag [(1-4294967295)]",
82f97584
DW
2484 NO_STR
2485 MATCH_STR
2486 "Match tag of route\n"
2487 "Tag value\n")
2488{
d62a17ae 2489 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2490
d62a17ae 2491 int idx = 0;
2492 char *arg = argv_find(argv, argc, "(1-4294967295)", &idx)
2493 ? argv[idx]->arg
2494 : NULL;
0d702986 2495
d62a17ae 2496 if (rmap_match_set_hook.no_match_tag)
2497 return rmap_match_set_hook.no_match_tag(
2498 vty, index, "tag", arg, RMAP_EVENT_MATCH_DELETED);
2499 return CMD_SUCCESS;
82f97584
DW
2500}
2501
2502
2503DEFUN (set_ip_nexthop,
2504 set_ip_nexthop_cmd,
2505 "set ip next-hop A.B.C.D",
2506 SET_STR
2507 IP_STR
2508 "Next hop address\n"
2509 "IP address of next hop\n")
2510{
d62a17ae 2511 int idx_ipv4 = 3;
2512 union sockunion su;
2513 int ret;
2514 VTY_DECLVAR_CONTEXT(route_map_index, index);
82f97584 2515
d62a17ae 2516 ret = str2sockunion(argv[idx_ipv4]->arg, &su);
2517 if (ret < 0) {
2518 vty_out(vty, "%% Malformed nexthop address\n");
2519 return CMD_WARNING_CONFIG_FAILED;
2520 }
2521 if (su.sin.sin_addr.s_addr == 0
ae2158fe 2522 || IPV4_CLASS_DE(ntohl(su.sin.sin_addr.s_addr))) {
d62a17ae 2523 vty_out(vty,
2524 "%% nexthop address cannot be 0.0.0.0, multicast or reserved\n");
2525 return CMD_WARNING_CONFIG_FAILED;
2526 }
82f97584 2527
d62a17ae 2528 if (rmap_match_set_hook.set_ip_nexthop)
2529 return rmap_match_set_hook.set_ip_nexthop(
2530 vty, index, "ip next-hop", argv[idx_ipv4]->arg);
2531 return CMD_SUCCESS;
82f97584
DW
2532}
2533
2534
2535DEFUN (no_set_ip_nexthop,
2536 no_set_ip_nexthop_cmd,
89602edb 2537 "no set ip next-hop [A.B.C.D]",
82f97584
DW
2538 NO_STR
2539 SET_STR
3a2d747c 2540 IP_STR
82f97584 2541 "Next hop address\n"
82f97584
DW
2542 "IP address of next hop\n")
2543{
0af35d90 2544 int idx = 0;
d62a17ae 2545 VTY_DECLVAR_CONTEXT(route_map_index, index);
89602edb 2546 const char *arg = NULL;
82f97584 2547
89602edb
QY
2548 if (argv_find(argv, argc, "A.B.C.D", &idx))
2549 arg = argv[idx]->arg;
2550
2551 if (rmap_match_set_hook.no_set_ip_nexthop)
d62a17ae 2552 return rmap_match_set_hook.no_set_ip_nexthop(
89602edb
QY
2553 vty, index, "ip next-hop", arg);
2554
d62a17ae 2555 return CMD_SUCCESS;
82f97584
DW
2556}
2557
2558
2559DEFUN (set_ipv6_nexthop_local,
2560 set_ipv6_nexthop_local_cmd,
2561 "set ipv6 next-hop local X:X::X:X",
2562 SET_STR
2563 IPV6_STR
2564 "IPv6 next-hop address\n"
2565 "IPv6 local address\n"
2566 "IPv6 address of next hop\n")
2567{
d62a17ae 2568 int idx_ipv6 = 4;
2569 struct in6_addr addr;
2570 int ret;
2571 VTY_DECLVAR_CONTEXT(route_map_index, index);
82f97584 2572
d62a17ae 2573 ret = inet_pton(AF_INET6, argv[idx_ipv6]->arg, &addr);
2574 if (!ret) {
2575 vty_out(vty, "%% Malformed nexthop address\n");
2576 return CMD_WARNING_CONFIG_FAILED;
2577 }
2578 if (!IN6_IS_ADDR_LINKLOCAL(&addr)) {
2579 vty_out(vty, "%% Invalid link-local nexthop address\n");
2580 return CMD_WARNING_CONFIG_FAILED;
2581 }
82f97584 2582
d62a17ae 2583 if (rmap_match_set_hook.set_ipv6_nexthop_local)
2584 return rmap_match_set_hook.set_ipv6_nexthop_local(
2585 vty, index, "ipv6 next-hop local", argv[idx_ipv6]->arg);
2586 return CMD_SUCCESS;
82f97584
DW
2587}
2588
2589
2590DEFUN (no_set_ipv6_nexthop_local,
2591 no_set_ipv6_nexthop_local_cmd,
2592 "no set ipv6 next-hop local [X:X::X:X]",
2593 NO_STR
2594 SET_STR
2595 IPV6_STR
2596 "IPv6 next-hop address\n"
2597 "IPv6 local address\n"
2598 "IPv6 address of next hop\n")
2599{
d62a17ae 2600 int idx_ipv6 = 5;
2601 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2602
d62a17ae 2603 if (rmap_match_set_hook.no_set_ipv6_nexthop_local) {
2604 if (argc <= idx_ipv6)
2605 return rmap_match_set_hook.no_set_ipv6_nexthop_local(
2606 vty, index, "ipv6 next-hop local", NULL);
2607 return rmap_match_set_hook.no_set_ipv6_nexthop_local(
2608 vty, index, "ipv6 next-hop local", argv[5]->arg);
2609 }
2610 return CMD_SUCCESS;
82f97584
DW
2611}
2612
2613DEFUN (set_metric,
2614 set_metric_cmd,
2615 "set metric <(0-4294967295)|rtt|+rtt|-rtt|+metric|-metric>",
2616 SET_STR
2617 "Metric value for destination routing protocol\n"
2618 "Metric value\n"
2619 "Assign round trip time\n"
2620 "Add round trip time\n"
2621 "Subtract round trip time\n"
2622 "Add metric\n"
2623 "Subtract metric\n")
2624{
d62a17ae 2625 int idx_number = 2;
2626 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2627
d62a17ae 2628 const char *pass = (argv[idx_number]->type == RANGE_TKN)
2629 ? argv[idx_number]->arg
2630 : argv[idx_number]->text;
af3346ec 2631
d62a17ae 2632 if (rmap_match_set_hook.set_metric)
2633 return rmap_match_set_hook.set_metric(vty, index, "metric",
2634 pass);
2635 return CMD_SUCCESS;
82f97584
DW
2636}
2637
2638
2639DEFUN (no_set_metric,
2640 no_set_metric_cmd,
2641 "no set metric [(0-4294967295)]",
2642 NO_STR
2643 SET_STR
2644 "Metric value for destination routing protocol\n"
2645 "Metric value\n")
2646{
d62a17ae 2647 int idx_number = 3;
2648 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2649
d62a17ae 2650 if (rmap_match_set_hook.no_set_metric) {
2651 if (argc <= idx_number)
2652 return rmap_match_set_hook.no_set_metric(
2653 vty, index, "metric", NULL);
2654 return rmap_match_set_hook.no_set_metric(vty, index, "metric",
2655 argv[idx_number]->arg);
2656 }
2657 return CMD_SUCCESS;
82f97584
DW
2658}
2659
2660
2661DEFUN (set_tag,
2662 set_tag_cmd,
e52702f2 2663 "set tag (1-4294967295)",
82f97584
DW
2664 SET_STR
2665 "Tag value for routing protocol\n"
2666 "Tag value\n")
2667{
d62a17ae 2668 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2669
d62a17ae 2670 int idx_number = 2;
2671 if (rmap_match_set_hook.set_tag)
2672 return rmap_match_set_hook.set_tag(vty, index, "tag",
2673 argv[idx_number]->arg);
2674 return CMD_SUCCESS;
82f97584
DW
2675}
2676
2677
2678DEFUN (no_set_tag,
2679 no_set_tag_cmd,
e52702f2 2680 "no set tag [(1-4294967295)]",
82f97584
DW
2681 NO_STR
2682 SET_STR
2683 "Tag value for routing protocol\n"
2684 "Tag value\n")
2685{
d62a17ae 2686 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2687
d62a17ae 2688 int idx_number = 3;
2689 if (rmap_match_set_hook.no_set_tag) {
2690 if (argc <= idx_number)
2691 return rmap_match_set_hook.no_set_tag(vty, index, "tag",
2692 NULL);
2693 return rmap_match_set_hook.no_set_tag(vty, index, "tag",
2694 argv[idx_number]->arg);
2695 }
2696 return CMD_SUCCESS;
82f97584
DW
2697}
2698
2699
505e5056 2700DEFUN_NOSH (route_map,
718e3744 2701 route_map_cmd,
7fcbbdae 2702 "route-map WORD <deny|permit> (1-65535)",
718e3744 2703 "Create route-map or enter route-map command mode\n"
2704 "Route map tag\n"
2705 "Route map denies set operations\n"
2706 "Route map permits set operations\n"
2707 "Sequence to insert to/delete from existing route-map entry\n")
2708{
d62a17ae 2709 int idx_word = 1;
2710 int idx_permit_deny = 2;
2711 int idx_number = 3;
2712 struct route_map *map;
2713 struct route_map_index *index;
2714 char *endptr = NULL;
2715 int permit =
2716 argv[idx_permit_deny]->arg[0] == 'p' ? RMAP_PERMIT : RMAP_DENY;
2717 unsigned long pref = strtoul(argv[idx_number]->arg, &endptr, 10);
2718 const char *mapname = argv[idx_word]->arg;
718e3744 2719
d62a17ae 2720 /* Get route map. */
2721 map = route_map_get(mapname);
2722 index = route_map_index_get(map, permit, pref);
718e3744 2723
d62a17ae 2724 VTY_PUSH_CONTEXT(RMAP_NODE, index);
2725 return CMD_SUCCESS;
718e3744 2726}
2727
2728DEFUN (no_route_map_all,
2729 no_route_map_all_cmd,
2730 "no route-map WORD",
2731 NO_STR
2732 "Create route-map or enter route-map command mode\n"
2733 "Route map tag\n")
2734{
d62a17ae 2735 int idx_word = 2;
2736 const char *mapname = argv[idx_word]->arg;
2737 struct route_map *map;
718e3744 2738
d62a17ae 2739 map = route_map_lookup_by_name(mapname);
2740 if (map == NULL) {
2741 vty_out(vty, "%% Could not find route-map %s\n", mapname);
2742 return CMD_WARNING_CONFIG_FAILED;
2743 }
718e3744 2744
d62a17ae 2745 route_map_delete(map);
718e3744 2746
d62a17ae 2747 return CMD_SUCCESS;
718e3744 2748}
2749
2750DEFUN (no_route_map,
2751 no_route_map_cmd,
7fcbbdae 2752 "no route-map WORD <deny|permit> (1-65535)",
718e3744 2753 NO_STR
2754 "Create route-map or enter route-map command mode\n"
2755 "Route map tag\n"
2756 "Route map denies set operations\n"
2757 "Route map permits set operations\n"
2758 "Sequence to insert to/delete from existing route-map entry\n")
2759{
d62a17ae 2760 int idx_word = 2;
2761 int idx_permit_deny = 3;
2762 int idx_number = 4;
2763 struct route_map *map;
2764 struct route_map_index *index;
2765 char *endptr = NULL;
2766 int permit = strmatch(argv[idx_permit_deny]->text, "permit")
2767 ? RMAP_PERMIT
2768 : RMAP_DENY;
2769 const char *prefstr = argv[idx_number]->arg;
2770 const char *mapname = argv[idx_word]->arg;
2771 unsigned long pref = strtoul(prefstr, &endptr, 10);
2772
2773 /* Existence check. */
2774 map = route_map_lookup_by_name(mapname);
2775 if (map == NULL) {
2776 vty_out(vty, "%% Could not find route-map %s\n", mapname);
2777 return CMD_WARNING_CONFIG_FAILED;
2778 }
2779
2780 /* Lookup route map index. */
2781 index = route_map_index_lookup(map, permit, pref);
2782 if (index == NULL) {
2783 vty_out(vty, "%% Could not find route-map entry %s %s\n",
2784 mapname, prefstr);
2785 return CMD_WARNING_CONFIG_FAILED;
2786 }
2787
2788 /* Delete index from route map. */
2789 route_map_index_delete(index, 1);
2790
2791 /* If this route rule is the last one, delete route map itself. */
2792 if (route_map_empty(map))
2793 route_map_delete(map);
2794
2795 return CMD_SUCCESS;
718e3744 2796}
2797
2798DEFUN (rmap_onmatch_next,
2799 rmap_onmatch_next_cmd,
2800 "on-match next",
2801 "Exit policy on matches\n"
2802 "Next clause\n")
2803{
d62a17ae 2804 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2805
2806 if (index) {
2807 if (index->type == RMAP_DENY) {
2808 /* Under a deny clause, match means it's finished. No
2809 * need to set next */
2810 vty_out(vty,
2811 "on-match next not supported under route-map deny\n");
2812 return CMD_WARNING_CONFIG_FAILED;
2813 }
2814 index->exitpolicy = RMAP_NEXT;
2815 }
2816 return CMD_SUCCESS;
718e3744 2817}
2818
2819DEFUN (no_rmap_onmatch_next,
2820 no_rmap_onmatch_next_cmd,
2821 "no on-match next",
2822 NO_STR
2823 "Exit policy on matches\n"
2824 "Next clause\n")
2825{
d62a17ae 2826 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2827
2828 if (index)
2829 index->exitpolicy = RMAP_EXIT;
718e3744 2830
d62a17ae 2831 return CMD_SUCCESS;
718e3744 2832}
2833
2834DEFUN (rmap_onmatch_goto,
2835 rmap_onmatch_goto_cmd,
7fcbbdae 2836 "on-match goto (1-65535)",
718e3744 2837 "Exit policy on matches\n"
2838 "Goto Clause number\n"
2839 "Number\n")
2840{
d62a17ae 2841 int idx = 0;
2842 char *num = argv_find(argv, argc, "(1-65535)", &idx) ? argv[idx]->arg
2843 : NULL;
2844
2845 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2846 int d = 0;
2847
2848 if (index) {
2849 if (index->type == RMAP_DENY) {
2850 /* Under a deny clause, match means it's finished. No
2851 * need to go anywhere */
2852 vty_out(vty,
2853 "on-match goto not supported under route-map deny\n");
2854 return CMD_WARNING_CONFIG_FAILED;
2855 }
2856
2857 if (num)
2858 d = strtoul(num, NULL, 10);
2859 else
2860 d = index->pref + 1;
2861
2862 if (d <= index->pref) {
2863 /* Can't allow you to do that, Dave */
2864 vty_out(vty, "can't jump backwards in route-maps\n");
2865 return CMD_WARNING_CONFIG_FAILED;
2866 } else {
2867 index->exitpolicy = RMAP_GOTO;
2868 index->nextpref = d;
2869 }
718e3744 2870 }
d62a17ae 2871 return CMD_SUCCESS;
718e3744 2872}
2873
2874DEFUN (no_rmap_onmatch_goto,
2875 no_rmap_onmatch_goto_cmd,
2876 "no on-match goto",
2877 NO_STR
2878 "Exit policy on matches\n"
fee0f4c6 2879 "Goto Clause number\n")
718e3744 2880{
d62a17ae 2881 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
718e3744 2882
d62a17ae 2883 if (index)
2884 index->exitpolicy = RMAP_EXIT;
2885
2886 return CMD_SUCCESS;
718e3744 2887}
2888
f667a580
QY
2889/* Cisco/GNU Zebra compatibility aliases */
2890/* ALIAS_FIXME */
2891DEFUN (rmap_continue,
2892 rmap_continue_cmd,
2893 "continue (1-65535)",
2894 "Continue on a different entry within the route-map\n"
2895 "Route-map entry sequence number\n")
2896{
d62a17ae 2897 return rmap_onmatch_goto(self, vty, argc, argv);
f667a580 2898}
5510e83b 2899
f667a580
QY
2900/* ALIAS_FIXME */
2901DEFUN (no_rmap_continue,
2902 no_rmap_continue_cmd,
2903 "no continue [(1-65535)]",
2904 NO_STR
2905 "Continue on a different entry within the route-map\n"
2906 "Route-map entry sequence number\n")
2907{
d62a17ae 2908 return no_rmap_onmatch_goto(self, vty, argc, argv);
f667a580 2909}
f412b39a 2910
5510e83b 2911
6d2729e3 2912DEFUN (rmap_show_name,
5510e83b 2913 rmap_show_name_cmd,
7514fb77 2914 "show route-map [WORD]",
5510e83b 2915 SHOW_STR
2916 "route-map information\n"
2917 "route-map name\n")
2918{
d62a17ae 2919 int idx_word = 2;
2920 const char *name = (argc == 3) ? argv[idx_word]->arg : NULL;
2921 return vty_show_route_map(vty, name);
5510e83b 2922}
2923
4a2a09d0 2924DEFUN (rmap_show_unused,
2925 rmap_show_unused_cmd,
2926 "show route-map-unused",
2927 SHOW_STR
2928 "unused route-map information\n")
2929{
2930 return vty_show_unused_route_map(vty);
2931}
2932
fee0f4c6 2933DEFUN (rmap_call,
2934 rmap_call_cmd,
2935 "call WORD",
2936 "Jump to another Route-Map after match+set\n"
2937 "Target route-map name\n")
2938{
d62a17ae 2939 int idx_word = 1;
2940 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2941 const char *rmap = argv[idx_word]->arg;
fee0f4c6 2942
d62a17ae 2943 assert(index);
c01d03a6 2944
6c3247bd
NT
2945 /* If "call" is invoked with the same route-map name as
2946 * the one previously configured then, ignore the duplicate
2947 * configuration.
2948 */
2949 if (index->nextrm && (strcmp(index->nextrm, rmap) == 0))
2950 return CMD_SUCCESS;
2951
d62a17ae 2952 if (index->nextrm) {
2953 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED,
2954 index->nextrm, index->map->name);
2955 XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
2956 }
2957 index->nextrm = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
518f0eb1 2958
d62a17ae 2959 /* Execute event hook. */
2960 route_map_upd8_dependency(RMAP_EVENT_CALL_ADDED, index->nextrm,
2961 index->map->name);
2962 return CMD_SUCCESS;
fee0f4c6 2963}
2964
2965DEFUN (no_rmap_call,
2966 no_rmap_call_cmd,
2967 "no call",
2968 NO_STR
2969 "Jump to another Route-Map after match+set\n")
2970{
d62a17ae 2971 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
fee0f4c6 2972
d62a17ae 2973 if (index->nextrm) {
2974 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED,
2975 index->nextrm, index->map->name);
2976 XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
2977 index->nextrm = NULL;
2978 }
fee0f4c6 2979
d62a17ae 2980 return CMD_SUCCESS;
fee0f4c6 2981}
2982
4a8164e5 2983DEFUN (rmap_description,
2984 rmap_description_cmd,
7fcbbdae 2985 "description LINE...",
4a8164e5 2986 "Route-map comment\n"
2987 "Comment describing this route-map rule\n")
2988{
d62a17ae 2989 int idx_line = 1;
2990 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
4a8164e5 2991
d62a17ae 2992 if (index) {
2993 if (index->description)
2994 XFREE(MTYPE_TMP, index->description);
2995 index->description = argv_concat(argv, argc, idx_line);
2996 }
2997 return CMD_SUCCESS;
4a8164e5 2998}
2999
3000DEFUN (no_rmap_description,
3001 no_rmap_description_cmd,
3002 "no description",
3003 NO_STR
3004 "Route-map comment\n")
3005{
d62a17ae 3006 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
4a8164e5 3007
d62a17ae 3008 if (index) {
3009 if (index->description)
3010 XFREE(MTYPE_TMP, index->description);
3011 index->description = NULL;
3012 }
3013 return CMD_SUCCESS;
4a8164e5 3014}
3015
718e3744 3016/* Configuration write function. */
d62a17ae 3017static int route_map_config_write(struct vty *vty)
3018{
3019 struct route_map *map;
3020 struct route_map_index *index;
3021 struct route_map_rule *rule;
3022 int first = 1;
3023 int write = 0;
3024
3025 for (map = route_map_master.head; map; map = map->next)
3026 for (index = map->head; index; index = index->next) {
3027 if (!first)
3028 vty_out(vty, "!\n");
3029 else
3030 first = 0;
3031
3032 vty_out(vty, "route-map %s %s %d\n", map->name,
3033 route_map_type_str(index->type), index->pref);
3034
3035 if (index->description)
3036 vty_out(vty, " description %s\n",
3037 index->description);
3038
3039 for (rule = index->match_list.head; rule;
3040 rule = rule->next)
3041 vty_out(vty, " match %s %s\n", rule->cmd->str,
3042 rule->rule_str ? rule->rule_str : "");
3043
3044 for (rule = index->set_list.head; rule;
3045 rule = rule->next)
3046 vty_out(vty, " set %s %s\n", rule->cmd->str,
3047 rule->rule_str ? rule->rule_str : "");
3048 if (index->nextrm)
3049 vty_out(vty, " call %s\n", index->nextrm);
3050 if (index->exitpolicy == RMAP_GOTO)
3051 vty_out(vty, " on-match goto %d\n",
3052 index->nextpref);
3053 if (index->exitpolicy == RMAP_NEXT)
3054 vty_out(vty, " on-match next\n");
3055
3056 write++;
3057 }
3058 return write;
718e3744 3059}
3060
3061/* Route map node structure. */
d62a17ae 3062static struct cmd_node rmap_node = {RMAP_NODE, "%s(config-route-map)# ", 1};
718e3744 3063
dc9ffce8
CF
3064/* Common route map rules */
3065
d62a17ae 3066void *route_map_rule_tag_compile(const char *arg)
dc9ffce8 3067{
d62a17ae 3068 unsigned long int tmp;
3069 char *endptr;
3070 route_tag_t *tag;
dc9ffce8 3071
d62a17ae 3072 errno = 0;
3073 tmp = strtoul(arg, &endptr, 0);
3074 if (arg[0] == '\0' || *endptr != '\0' || errno || tmp > ROUTE_TAG_MAX)
3075 return NULL;
dc9ffce8 3076
d62a17ae 3077 tag = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*tag));
3078 *tag = tmp;
dc9ffce8 3079
d62a17ae 3080 return tag;
dc9ffce8
CF
3081}
3082
d62a17ae 3083void route_map_rule_tag_free(void *rule)
dc9ffce8 3084{
d62a17ae 3085 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
dc9ffce8
CF
3086}
3087
d62a17ae 3088void route_map_finish(void)
9df78e7c 3089{
d62a17ae 3090 int i;
9df78e7c 3091
d62a17ae 3092 vector_free(route_match_vec);
3093 route_match_vec = NULL;
3094 vector_free(route_set_vec);
3095 route_set_vec = NULL;
9df78e7c 3096
8619629a
DS
3097 /*
3098 * All protocols are setting these to NULL
3099 * by default on shutdown( route_map_finish )
3100 * Why are we making them do this work?
3101 */
3102 route_map_master.add_hook = NULL;
3103 route_map_master.delete_hook = NULL;
3104 route_map_master.event_hook = NULL;
3105
d62a17ae 3106 /* cleanup route_map */
3107 while (route_map_master.head) {
3108 struct route_map *map = route_map_master.head;
e4694d0d 3109 map->to_be_processed = false;
d62a17ae 3110 route_map_delete(map);
3111 }
9df78e7c 3112
d62a17ae 3113 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
3114 hash_free(route_map_dep_hash[i]);
3115 route_map_dep_hash[i] = NULL;
3116 }
9df78e7c 3117
d62a17ae 3118 hash_free(route_map_master_hash);
3119 route_map_master_hash = NULL;
9df78e7c
DS
3120}
3121
70d44c5c
DL
3122static void rmap_autocomplete(vector comps, struct cmd_token *token)
3123{
d62a17ae 3124 struct route_map *map;
70d44c5c 3125
d62a17ae 3126 for (map = route_map_master.head; map; map = map->next)
3127 vector_set(comps, XSTRDUP(MTYPE_COMPLETION, map->name));
70d44c5c
DL
3128}
3129
4a2a09d0 3130/* Increment the use_count counter while attaching the route map */
3131void route_map_counter_increment(struct route_map *map)
3132{
3133 if (map)
3134 map->use_count++;
3135}
3136
3137/* Decrement the use_count counter while detaching the route map. */
3138void route_map_counter_decrement(struct route_map *map)
3139{
3140 if (map) {
3141 if (map->use_count <= 0)
3142 return;
3143 map->use_count--;
3144 }
3145}
3146
70d44c5c 3147static const struct cmd_variable_handler rmap_var_handlers[] = {
d62a17ae 3148 {/* "route-map WORD" */
3149 .varname = "route_map",
3150 .completions = rmap_autocomplete},
3151 {.tokenname = "ROUTEMAP_NAME", .completions = rmap_autocomplete},
3152 {.tokenname = "RMAP_NAME", .completions = rmap_autocomplete},
3153 {.completions = NULL}};
70d44c5c 3154
718e3744 3155/* Initialization of route map vector. */
d62a17ae 3156void route_map_init(void)
718e3744 3157{
d62a17ae 3158 int i;
3159
3160 /* Make vector for match and set. */
3161 route_match_vec = vector_init(1);
3162 route_set_vec = vector_init(1);
3163 route_map_master_hash =
996c9314 3164 hash_create_size(8, route_map_hash_key_make, route_map_hash_cmp,
bd74dc61 3165 "Route Map Master Hash");
d62a17ae 3166
3167 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
996c9314
LB
3168 route_map_dep_hash[i] = hash_create_size(
3169 8, route_map_dep_hash_make_key, route_map_dep_hash_cmp,
3170 "Route Map Dep Hash");
b2575bc0 3171
d62a17ae 3172 cmd_variable_handler_register(rmap_var_handlers);
b2575bc0 3173
d62a17ae 3174 /* Install route map top node. */
3175 install_node(&rmap_node, route_map_config_write);
518f0eb1 3176
d62a17ae 3177 /* Install route map commands. */
3178 install_default(RMAP_NODE);
3179 install_element(CONFIG_NODE, &route_map_cmd);
3180 install_element(CONFIG_NODE, &no_route_map_cmd);
3181 install_element(CONFIG_NODE, &no_route_map_all_cmd);
70d44c5c 3182
d62a17ae 3183 /* Install the on-match stuff */
3184 install_element(RMAP_NODE, &route_map_cmd);
3185 install_element(RMAP_NODE, &rmap_onmatch_next_cmd);
3186 install_element(RMAP_NODE, &no_rmap_onmatch_next_cmd);
3187 install_element(RMAP_NODE, &rmap_onmatch_goto_cmd);
3188 install_element(RMAP_NODE, &no_rmap_onmatch_goto_cmd);
3189 install_element(RMAP_NODE, &rmap_continue_cmd);
3190 install_element(RMAP_NODE, &no_rmap_continue_cmd);
718e3744 3191
d62a17ae 3192 /* Install the continue stuff (ALIAS of on-match). */
718e3744 3193
d62a17ae 3194 /* Install the call stuff. */
3195 install_element(RMAP_NODE, &rmap_call_cmd);
3196 install_element(RMAP_NODE, &no_rmap_call_cmd);
4a8164e5 3197
d62a17ae 3198 /* Install description commands. */
3199 install_element(RMAP_NODE, &rmap_description_cmd);
3200 install_element(RMAP_NODE, &no_rmap_description_cmd);
82f97584 3201
d62a17ae 3202 /* Install show command */
3203 install_element(ENABLE_NODE, &rmap_show_name_cmd);
4a2a09d0 3204 install_element(ENABLE_NODE, &rmap_show_unused_cmd);
82f97584 3205
d62a17ae 3206 install_element(RMAP_NODE, &match_interface_cmd);
3207 install_element(RMAP_NODE, &no_match_interface_cmd);
82f97584 3208
d62a17ae 3209 install_element(RMAP_NODE, &match_ip_address_cmd);
3210 install_element(RMAP_NODE, &no_match_ip_address_cmd);
82f97584 3211
d62a17ae 3212 install_element(RMAP_NODE, &match_ip_address_prefix_list_cmd);
3213 install_element(RMAP_NODE, &no_match_ip_address_prefix_list_cmd);
82f97584 3214
d62a17ae 3215 install_element(RMAP_NODE, &match_ip_next_hop_cmd);
3216 install_element(RMAP_NODE, &no_match_ip_next_hop_cmd);
82f97584 3217
d62a17ae 3218 install_element(RMAP_NODE, &match_ip_next_hop_prefix_list_cmd);
3219 install_element(RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd);
82f97584 3220
61ad901e
DA
3221 install_element(RMAP_NODE, &match_ip_next_hop_type_cmd);
3222 install_element(RMAP_NODE, &no_match_ip_next_hop_type_cmd);
3223
d62a17ae 3224 install_element(RMAP_NODE, &match_ipv6_address_cmd);
3225 install_element(RMAP_NODE, &no_match_ipv6_address_cmd);
82f97584 3226
d62a17ae 3227 install_element(RMAP_NODE, &match_ipv6_address_prefix_list_cmd);
3228 install_element(RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd);
82f97584 3229
61ad901e
DA
3230 install_element(RMAP_NODE, &match_ipv6_next_hop_type_cmd);
3231 install_element(RMAP_NODE, &no_match_ipv6_next_hop_type_cmd);
3232
d62a17ae 3233 install_element(RMAP_NODE, &match_metric_cmd);
3234 install_element(RMAP_NODE, &no_match_metric_cmd);
82f97584 3235
d62a17ae 3236 install_element(RMAP_NODE, &match_tag_cmd);
3237 install_element(RMAP_NODE, &no_match_tag_cmd);
82f97584 3238
d62a17ae 3239 install_element(RMAP_NODE, &set_ip_nexthop_cmd);
3240 install_element(RMAP_NODE, &no_set_ip_nexthop_cmd);
82f97584 3241
d62a17ae 3242 install_element(RMAP_NODE, &set_ipv6_nexthop_local_cmd);
3243 install_element(RMAP_NODE, &no_set_ipv6_nexthop_local_cmd);
82f97584 3244
d62a17ae 3245 install_element(RMAP_NODE, &set_metric_cmd);
3246 install_element(RMAP_NODE, &no_set_metric_cmd);
82f97584 3247
d62a17ae 3248 install_element(RMAP_NODE, &set_tag_cmd);
3249 install_element(RMAP_NODE, &no_set_tag_cmd);
718e3744 3250}