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