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