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