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