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