]> git.proxmox.com Git - mirror_frr.git/blame - lib/routemap.c
Merge pull request #10447 from ton31337/fix/json_with_whitespaces
[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
d62a17ae 762 memset(&tmp_map, 0, sizeof(struct route_map));
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) {
800 memset(&tmp_map, 0, sizeof(struct route_map));
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
2484 memset(&pentry_dep, 0, sizeof(struct route_map_pentry_dep));
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,
2543 void *match_object, void *set_object)
d62a17ae 2544{
2545 static int recursion = 0;
b68885f9
LK
2546 enum route_map_cmd_result_t match_ret = RMAP_NOMATCH;
2547 route_map_result_t ret = RMAP_PERMITMATCH;
819a23f9
NT
2548 struct route_map_index *index = NULL;
2549 struct route_map_rule *set = NULL;
819a23f9 2550 bool skip_match_clause = false;
d62a17ae 2551
2552 if (recursion > RMAP_RECURSION_LIMIT) {
040c7c3a 2553 flog_warn(
450971aa 2554 EC_LIB_RMAP_RECURSION_LIMIT,
d62a17ae 2555 "route-map recursion limit (%d) reached, discarding route",
2556 RMAP_RECURSION_LIMIT);
2557 recursion = 0;
2558 return RMAP_DENYMATCH;
2559 }
2560
b68885f9 2561 if (map == NULL || map->head == NULL) {
e3ab8170
AD
2562 ret = RMAP_DENYMATCH;
2563 goto route_map_apply_end;
2564 }
d62a17ae 2565
279b0607 2566 map->applied++;
819a23f9 2567
2d26f094
NT
2568 if ((!map->optimization_disabled)
2569 && (map->ipv4_prefix_table || map->ipv6_prefix_table)) {
c2125847 2570 index = route_map_get_index(map, prefix, match_object,
a34ce5c5 2571 &match_ret);
819a23f9 2572 if (index) {
284a6f5f 2573 index->applied++;
819a23f9
NT
2574 if (rmap_debug)
2575 zlog_debug(
2dbe669b
DA
2576 "Best match route-map: %s, sequence: %d for pfx: %pFX, result: %s",
2577 map->name, index->pref, prefix,
819a23f9
NT
2578 route_map_cmd_result_str(match_ret));
2579 } else {
2580 if (rmap_debug)
2d26f094 2581 zlog_debug(
2dbe669b
DA
2582 "No best match sequence for pfx: %pFX in route-map: %s, result: %s",
2583 prefix, map->name,
2d26f094 2584 route_map_cmd_result_str(match_ret));
819a23f9
NT
2585 /*
2586 * No index matches this prefix. Return deny unless,
2587 * match_ret = RMAP_NOOP.
2588 */
2589 if (match_ret == RMAP_NOOP)
2590 ret = RMAP_PERMITMATCH;
2591 else
2592 ret = RMAP_DENYMATCH;
2593 goto route_map_apply_end;
e3ab8170 2594 }
819a23f9
NT
2595 skip_match_clause = true;
2596 } else {
2597 index = map->head;
2598 }
2599
2600 for (; index; index = index->next) {
a8f58eb6 2601 if (!skip_match_clause) {
00aef028 2602 index->applied++;
819a23f9
NT
2603 /* Apply this index. */
2604 match_ret = route_map_apply_match(&index->match_list,
c2125847 2605 prefix, match_object);
819a23f9
NT
2606 if (rmap_debug) {
2607 zlog_debug(
2dbe669b
DA
2608 "Route-map: %s, sequence: %d, prefix: %pFX, result: %s",
2609 map->name, index->pref, prefix,
819a23f9
NT
2610 route_map_cmd_result_str(match_ret));
2611 }
2612 } else
2613 skip_match_clause = false;
2614
e3ab8170 2615
d62a17ae 2616 /* Now we apply the matrix from above */
b68885f9
LK
2617 if (match_ret == RMAP_NOOP)
2618 /*
2619 * Do not change the return value. Retain the previous
2620 * return value. Previous values can be:
2621 * 1)permitmatch (if a nomatch was never
2622 * seen before in this route-map.)
2623 * 2)denymatch (if a nomatch was seen earlier in one
2624 * of the previous sequences)
2625 */
2626
2627 /*
2628 * 'cont' from matrix - continue to next route-map
2629 * sequence
2630 */
d62a17ae 2631 continue;
b68885f9
LK
2632 else if (match_ret == RMAP_NOMATCH) {
2633
2634 /*
2635 * The return value is now changed to denymatch.
2636 * So from here on out, even if we see more noops,
2637 * we retain this return value and return this
2638 * eventually if there are no matches.
2639 */
2640 ret = RMAP_DENYMATCH;
2641
2642 /*
2643 * 'cont' from matrix - continue to next route-map
2644 * sequence
2645 */
2646 continue;
2647 } else if (match_ret == RMAP_MATCH) {
d62a17ae 2648 if (index->type == RMAP_PERMIT)
2649 /* 'action' */
2650 {
b68885f9
LK
2651 /* Match succeeded, rmap is of type permit */
2652 ret = RMAP_PERMITMATCH;
2653
d62a17ae 2654 /* permit+match must execute sets */
2655 for (set = index->set_list.head; set;
2656 set = set->next)
b68885f9
LK
2657 /*
2658 * set cmds return RMAP_OKAY or
2659 * RMAP_ERROR. We do not care if
2660 * set succeeded or not. So, ignore
2661 * return code.
2662 */
1782514f 2663 (void)(*set->cmd->func_apply)(
c2125847 2664 set->value, prefix, set_object);
d62a17ae 2665
2666 /* Call another route-map if available */
2667 if (index->nextrm) {
2668 struct route_map *nextrm =
2669 route_map_lookup_by_name(
2670 index->nextrm);
2671
2672 if (nextrm) /* Target route-map found,
2673 jump to it */
2674 {
2675 recursion++;
c2125847
IR
2676 ret = route_map_apply_ext(
2677 nextrm, prefix,
2678 match_object,
2679 set_object);
d62a17ae 2680 recursion--;
2681 }
2682
2683 /* If nextrm returned 'deny', finish. */
2684 if (ret == RMAP_DENYMATCH)
e3ab8170 2685 goto route_map_apply_end;
d62a17ae 2686 }
2687
2688 switch (index->exitpolicy) {
2689 case RMAP_EXIT:
e3ab8170 2690 goto route_map_apply_end;
d62a17ae 2691 case RMAP_NEXT:
2692 continue;
2693 case RMAP_GOTO: {
2694 /* Find the next clause to jump to */
2695 struct route_map_index *next =
2696 index->next;
2697 int nextpref = index->nextpref;
2698
2699 while (next && next->pref < nextpref) {
2700 index = next;
2701 next = next->next;
2702 }
2703 if (next == NULL) {
2704 /* No clauses match! */
e3ab8170 2705 goto route_map_apply_end;
d62a17ae 2706 }
2707 }
2708 }
2709 } else if (index->type == RMAP_DENY)
2710 /* 'deny' */
2711 {
e3ab8170
AD
2712 ret = RMAP_DENYMATCH;
2713 goto route_map_apply_end;
d62a17ae 2714 }
2715 }
2716 }
e3ab8170
AD
2717
2718route_map_apply_end:
2dbe669b
DA
2719 if (rmap_debug)
2720 zlog_debug("Route-map: %s, prefix: %pFX, result: %s",
2721 (map ? map->name : "null"), prefix,
e3ab8170 2722 route_map_result_str(ret));
e3ab8170
AD
2723
2724 return (ret);
d62a17ae 2725}
2726
2727void route_map_add_hook(void (*func)(const char *))
2728{
2729 route_map_master.add_hook = func;
2730}
2731
2732void route_map_delete_hook(void (*func)(const char *))
2733{
2734 route_map_master.delete_hook = func;
2735}
2736
097b5973 2737void route_map_event_hook(void (*func)(const char *name))
d62a17ae 2738{
2739 route_map_master.event_hook = func;
718e3744 2740}
2741
518f0eb1 2742/* Routines for route map dependency lists and dependency processing */
74df8d6d 2743static bool route_map_rmap_hash_cmp(const void *p1, const void *p2)
518f0eb1 2744{
e2c8d6ce
NT
2745 return strcmp(((const struct route_map_dep_data *)p1)->rname,
2746 ((const struct route_map_dep_data *)p2)->rname)
2747 == 0;
518f0eb1
DS
2748}
2749
74df8d6d 2750static bool route_map_dep_hash_cmp(const void *p1, const void *p2)
518f0eb1
DS
2751{
2752
d62a17ae 2753 return (strcmp(((const struct route_map_dep *)p1)->dep_name,
2754 (const char *)p2)
2755 == 0);
518f0eb1
DS
2756}
2757
e3b78da8 2758static void route_map_clear_reference(struct hash_bucket *bucket, void *arg)
518f0eb1 2759{
e2c8d6ce
NT
2760 struct route_map_dep *dep = bucket->data;
2761 struct route_map_dep_data *dep_data = NULL, tmp_dep_data;
518f0eb1 2762
db8db580
DS
2763 memset(&tmp_dep_data, 0, sizeof(struct route_map_dep_data));
2764 tmp_dep_data.rname = arg;
2765 dep_data = hash_release(dep->dep_rmap_hash, &tmp_dep_data);
2766 if (dep_data) {
af87aff6
DS
2767 if (rmap_debug)
2768 zlog_debug("Clearing reference for %s to %s count: %d",
2769 dep->dep_name, tmp_dep_data.rname,
2770 dep_data->refcnt);
2771
db8db580
DS
2772 XFREE(MTYPE_ROUTE_MAP_NAME, dep_data->rname);
2773 XFREE(MTYPE_ROUTE_MAP_DEP_DATA, dep_data);
2774 }
2775 if (!dep->dep_rmap_hash->count) {
2776 dep = hash_release(dep->this_hash, (void *)dep->dep_name);
2777 hash_free(dep->dep_rmap_hash);
2778 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
2779 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
518f0eb1 2780 }
d62a17ae 2781}
2782
2783static void route_map_clear_all_references(char *rmap_name)
2784{
2785 int i;
2786
af87aff6
DS
2787 if (rmap_debug)
2788 zlog_debug("Clearing references for %s", rmap_name);
2789
d62a17ae 2790 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
2791 hash_iterate(route_map_dep_hash[i], route_map_clear_reference,
2792 (void *)rmap_name);
518f0eb1 2793 }
518f0eb1
DS
2794}
2795
e2c8d6ce
NT
2796static unsigned int route_map_dep_data_hash_make_key(const void *p)
2797{
2798 const struct route_map_dep_data *dep_data = p;
2799
2800 return string_hash_make(dep_data->rname);
2801}
2802
d62a17ae 2803static void *route_map_dep_hash_alloc(void *p)
518f0eb1 2804{
d62a17ae 2805 char *dep_name = (char *)p;
2806 struct route_map_dep *dep_entry;
2807
2808 dep_entry = XCALLOC(MTYPE_ROUTE_MAP_DEP, sizeof(struct route_map_dep));
2809 dep_entry->dep_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
996c9314 2810 dep_entry->dep_rmap_hash =
e2c8d6ce 2811 hash_create_size(8, route_map_dep_data_hash_make_key,
996c9314 2812 route_map_rmap_hash_cmp, "Route Map Dep Hash");
d62a17ae 2813 dep_entry->this_hash = NULL;
2814
e2c8d6ce 2815 return dep_entry;
d62a17ae 2816}
518f0eb1 2817
d62a17ae 2818static void *route_map_name_hash_alloc(void *p)
2819{
e2c8d6ce
NT
2820 struct route_map_dep_data *dep_data = NULL, *tmp_dep_data = NULL;
2821
2822 dep_data = XCALLOC(MTYPE_ROUTE_MAP_DEP_DATA,
2823 sizeof(struct route_map_dep_data));
2824 tmp_dep_data = p;
2825 dep_data->rname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, tmp_dep_data->rname);
2826 return dep_data;
518f0eb1
DS
2827}
2828
d8b87afe 2829static unsigned int route_map_dep_hash_make_key(const void *p)
518f0eb1 2830{
d62a17ae 2831 return (string_hash_make((char *)p));
2832}
518f0eb1 2833
e3b78da8 2834static void route_map_print_dependency(struct hash_bucket *bucket, void *data)
d62a17ae 2835{
e2c8d6ce
NT
2836 struct route_map_dep_data *dep_data = bucket->data;
2837 char *rmap_name = dep_data->rname;
2838 char *dep_name = data;
518f0eb1 2839
15569c58 2840 zlog_debug("%s: Dependency for %s: %s", __func__, dep_name, rmap_name);
518f0eb1
DS
2841}
2842
d62a17ae 2843static int route_map_dep_update(struct hash *dephash, const char *dep_name,
2844 const char *rmap_name, route_map_event_t type)
518f0eb1 2845{
d62a17ae 2846 struct route_map_dep *dep = NULL;
d62a17ae 2847 char *dname, *rname;
2848 int ret = 0;
e2c8d6ce
NT
2849 struct route_map_dep_data *dep_data = NULL, *ret_dep_data = NULL;
2850 struct route_map_dep_data tmp_dep_data;
d62a17ae 2851
2852 dname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
2853 rname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_name);
2854
2855 switch (type) {
2856 case RMAP_EVENT_PLIST_ADDED:
2857 case RMAP_EVENT_CLIST_ADDED:
2858 case RMAP_EVENT_ECLIST_ADDED:
2859 case RMAP_EVENT_ASLIST_ADDED:
2860 case RMAP_EVENT_LLIST_ADDED:
2861 case RMAP_EVENT_CALL_ADDED:
2862 case RMAP_EVENT_FILTER_ADDED:
2863 if (rmap_debug)
e3ab8170
AD
2864 zlog_debug("Adding dependency for filter %s in route-map %s",
2865 dep_name, rmap_name);
d62a17ae 2866 dep = (struct route_map_dep *)hash_get(
2867 dephash, dname, route_map_dep_hash_alloc);
2868 if (!dep) {
2869 ret = -1;
2870 goto out;
2871 }
2872
2873 if (!dep->this_hash)
2874 dep->this_hash = dephash;
2875
e2c8d6ce
NT
2876 memset(&tmp_dep_data, 0, sizeof(struct route_map_dep_data));
2877 tmp_dep_data.rname = rname;
2878 dep_data = hash_lookup(dep->dep_rmap_hash, &tmp_dep_data);
2879 if (!dep_data)
2880 dep_data = hash_get(dep->dep_rmap_hash, &tmp_dep_data,
2881 route_map_name_hash_alloc);
2882
2883 dep_data->refcnt++;
d62a17ae 2884 break;
2885 case RMAP_EVENT_PLIST_DELETED:
2886 case RMAP_EVENT_CLIST_DELETED:
2887 case RMAP_EVENT_ECLIST_DELETED:
2888 case RMAP_EVENT_ASLIST_DELETED:
2889 case RMAP_EVENT_LLIST_DELETED:
2890 case RMAP_EVENT_CALL_DELETED:
2891 case RMAP_EVENT_FILTER_DELETED:
2892 if (rmap_debug)
e3ab8170
AD
2893 zlog_debug("Deleting dependency for filter %s in route-map %s",
2894 dep_name, rmap_name);
d62a17ae 2895 dep = (struct route_map_dep *)hash_get(dephash, dname, NULL);
2896 if (!dep) {
2897 goto out;
2898 }
2899
e2c8d6ce
NT
2900 memset(&tmp_dep_data, 0, sizeof(struct route_map_dep_data));
2901 tmp_dep_data.rname = rname;
2902 dep_data = hash_lookup(dep->dep_rmap_hash, &tmp_dep_data);
9149c635
DS
2903 /*
2904 * If dep_data is NULL then something has gone seriously
2905 * wrong in route-map handling. Note it and prevent
2906 * the crash.
2907 */
2908 if (!dep_data) {
2909 zlog_warn(
2910 "route-map dependency for route-map %s: %s is not correct",
2911 rmap_name, dep_name);
c415a4dc 2912 goto out;
9149c635 2913 }
c415a4dc 2914
9149c635 2915 dep_data->refcnt--;
e2c8d6ce
NT
2916
2917 if (!dep_data->refcnt) {
2918 ret_dep_data = hash_release(dep->dep_rmap_hash,
2919 &tmp_dep_data);
2920 if (ret_dep_data) {
2921 XFREE(MTYPE_ROUTE_MAP_NAME,
2922 ret_dep_data->rname);
2923 XFREE(MTYPE_ROUTE_MAP_DEP_DATA, ret_dep_data);
2924 }
2925 }
d62a17ae 2926
2927 if (!dep->dep_rmap_hash->count) {
2928 dep = hash_release(dephash, dname);
2929 hash_free(dep->dep_rmap_hash);
2930 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
2931 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
d62a17ae 2932 }
2933 break;
ba1707ca
DS
2934 case RMAP_EVENT_SET_ADDED:
2935 case RMAP_EVENT_SET_DELETED:
2936 case RMAP_EVENT_SET_REPLACED:
2937 case RMAP_EVENT_MATCH_ADDED:
2938 case RMAP_EVENT_MATCH_DELETED:
2939 case RMAP_EVENT_MATCH_REPLACED:
2940 case RMAP_EVENT_INDEX_ADDED:
2941 case RMAP_EVENT_INDEX_DELETED:
d62a17ae 2942 break;
2943 }
2944
2945 if (dep) {
2946 if (rmap_debug)
2947 hash_iterate(dep->dep_rmap_hash,
2948 route_map_print_dependency, dname);
2949 }
2950
2951out:
2952 XFREE(MTYPE_ROUTE_MAP_NAME, rname);
2953 XFREE(MTYPE_ROUTE_MAP_NAME, dname);
2954 return ret;
2955}
2956
2957static struct hash *route_map_get_dep_hash(route_map_event_t event)
2958{
2959 struct hash *upd8_hash = NULL;
2960
2961 switch (event) {
2962 case RMAP_EVENT_PLIST_ADDED:
2963 case RMAP_EVENT_PLIST_DELETED:
2964 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_PLIST];
2965 break;
2966 case RMAP_EVENT_CLIST_ADDED:
2967 case RMAP_EVENT_CLIST_DELETED:
2968 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_CLIST];
2969 break;
2970 case RMAP_EVENT_ECLIST_ADDED:
2971 case RMAP_EVENT_ECLIST_DELETED:
2972 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ECLIST];
2973 break;
2974 case RMAP_EVENT_ASLIST_ADDED:
2975 case RMAP_EVENT_ASLIST_DELETED:
2976 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ASPATH];
2977 break;
2978 case RMAP_EVENT_LLIST_ADDED:
2979 case RMAP_EVENT_LLIST_DELETED:
2980 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_LCLIST];
2981 break;
2982 case RMAP_EVENT_CALL_ADDED:
2983 case RMAP_EVENT_CALL_DELETED:
5ed2e47b 2984 case RMAP_EVENT_MATCH_ADDED:
2985 case RMAP_EVENT_MATCH_DELETED:
d62a17ae 2986 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_RMAP];
2987 break;
2988 case RMAP_EVENT_FILTER_ADDED:
2989 case RMAP_EVENT_FILTER_DELETED:
2990 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_FILTER];
2991 break;
ba1707ca
DS
2992 /*
2993 * Should we actually be ignoring these?
2994 * I am not sure but at this point in time, let
2995 * us get them into this switch and we can peel
2996 * them into the appropriate place in the future
2997 */
2998 case RMAP_EVENT_SET_ADDED:
2999 case RMAP_EVENT_SET_DELETED:
3000 case RMAP_EVENT_SET_REPLACED:
3001 case RMAP_EVENT_MATCH_REPLACED:
3002 case RMAP_EVENT_INDEX_ADDED:
3003 case RMAP_EVENT_INDEX_DELETED:
d62a17ae 3004 upd8_hash = NULL;
3005 break;
3006 }
3007 return (upd8_hash);
518f0eb1
DS
3008}
3009
e3b78da8 3010static void route_map_process_dependency(struct hash_bucket *bucket, void *data)
518f0eb1 3011{
e2c8d6ce
NT
3012 struct route_map_dep_data *dep_data = NULL;
3013 char *rmap_name = NULL;
3014
3015 dep_data = bucket->data;
3016 rmap_name = dep_data->rname;
d62a17ae 3017
1fae5ff2 3018 if (rmap_debug)
e3ab8170 3019 zlog_debug("Notifying %s of dependency", rmap_name);
1fae5ff2 3020 if (route_map_master.event_hook)
097b5973 3021 (*route_map_master.event_hook)(rmap_name);
518f0eb1
DS
3022}
3023
d62a17ae 3024void route_map_upd8_dependency(route_map_event_t type, const char *arg,
3025 const char *rmap_name)
518f0eb1 3026{
d62a17ae 3027 struct hash *upd8_hash = NULL;
518f0eb1 3028
fdf823db 3029 if ((upd8_hash = route_map_get_dep_hash(type))) {
d62a17ae 3030 route_map_dep_update(upd8_hash, arg, rmap_name, type);
fdf823db
NT
3031
3032 if (type == RMAP_EVENT_CALL_ADDED) {
3033 /* Execute hook. */
3034 if (route_map_master.add_hook)
3035 (*route_map_master.add_hook)(rmap_name);
3036 } else if (type == RMAP_EVENT_CALL_DELETED) {
3037 /* Execute hook. */
3038 if (route_map_master.delete_hook)
3039 (*route_map_master.delete_hook)(rmap_name);
3040 }
3041 }
518f0eb1
DS
3042}
3043
d62a17ae 3044void route_map_notify_dependencies(const char *affected_name,
3045 route_map_event_t event)
518f0eb1 3046{
d62a17ae 3047 struct route_map_dep *dep;
3048 struct hash *upd8_hash;
3049 char *name;
3050
3051 if (!affected_name)
3052 return;
3053
3054 name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, affected_name);
3055
3056 if ((upd8_hash = route_map_get_dep_hash(event)) == NULL) {
3057 XFREE(MTYPE_ROUTE_MAP_NAME, name);
3058 return;
518f0eb1 3059 }
d62a17ae 3060
3061 dep = (struct route_map_dep *)hash_get(upd8_hash, name, NULL);
3062 if (dep) {
3063 if (!dep->this_hash)
3064 dep->this_hash = upd8_hash;
3065
e3ab8170
AD
3066 if (rmap_debug)
3067 zlog_debug("Filter %s updated", dep->dep_name);
d62a17ae 3068 hash_iterate(dep->dep_rmap_hash, route_map_process_dependency,
3069 (void *)event);
3070 }
3071
3072 XFREE(MTYPE_ROUTE_MAP_NAME, name);
518f0eb1
DS
3073}
3074
718e3744 3075/* VTY related functions. */
1fa30509
DS
3076static void clear_route_map_helper(struct route_map *map)
3077{
3078 struct route_map_index *index;
3079
3080 map->applied_clear = map->applied;
3081 for (index = map->head; index; index = index->next)
3082 index->applied_clear = index->applied;
3083}
3084
3085DEFUN (rmap_clear_counters,
3086 rmap_clear_counters_cmd,
3087 "clear route-map counters [WORD]",
3088 CLEAR_STR
3089 "route-map information\n"
3090 "counters associated with the specified route-map\n"
3091 "route-map name\n")
3092{
3093 int idx_word = 2;
3094 struct route_map *map;
3095
3096 const char *name = (argc == 3 ) ? argv[idx_word]->arg : NULL;
3097
3098 if (name) {
3099 map = route_map_lookup_by_name(name);
3100
3101 if (map)
3102 clear_route_map_helper(map);
3103 else {
3104 vty_out(vty, "%s: 'route-map %s' not found\n",
3105 frr_protonameinst, name);
3106 return CMD_SUCCESS;
3107 }
3108 } else {
3109 for (map = route_map_master.head; map; map = map->next)
3110 clear_route_map_helper(map);
3111 }
3112
3113 return CMD_SUCCESS;
3114
3115}
5510e83b 3116
6d2729e3 3117DEFUN (rmap_show_name,
5510e83b 3118 rmap_show_name_cmd,
856ed18a 3119 "show route-map [WORD] [json]",
5510e83b 3120 SHOW_STR
3121 "route-map information\n"
856ed18a
RW
3122 "route-map name\n"
3123 JSON_STR)
5510e83b 3124{
856ed18a
RW
3125 bool uj = use_json(argc, argv);
3126 int idx = 0;
3127 const char *name = NULL;
3128
3129 if (argv_find(argv, argc, "WORD", &idx))
3130 name = argv[idx]->arg;
3131
3132 return vty_show_route_map(vty, name, uj);
5510e83b 3133}
3134
4a2a09d0 3135DEFUN (rmap_show_unused,
3136 rmap_show_unused_cmd,
3137 "show route-map-unused",
3138 SHOW_STR
3139 "unused route-map information\n")
3140{
3141 return vty_show_unused_route_map(vty);
3142}
3143
e3ab8170
AD
3144DEFUN (debug_rmap,
3145 debug_rmap_cmd,
3146 "debug route-map",
3147 DEBUG_STR
3148 "Debug option set for route-maps\n")
3149{
3150 rmap_debug = true;
3151 return CMD_SUCCESS;
3152}
3153
3154DEFUN (no_debug_rmap,
3155 no_debug_rmap_cmd,
3156 "no debug route-map",
3157 NO_STR
3158 DEBUG_STR
3159 "Debug option set for route-maps\n")
3160{
3161 rmap_debug = false;
3162 return CMD_SUCCESS;
3163}
3164
3165/* Debug node. */
612c2c15 3166static int rmap_config_write_debug(struct vty *vty);
62b346ee 3167static struct cmd_node rmap_debug_node = {
f4b8291f 3168 .name = "route-map debug",
62b346ee
DL
3169 .node = RMAP_DEBUG_NODE,
3170 .prompt = "",
612c2c15 3171 .config_write = rmap_config_write_debug,
62b346ee 3172};
e3ab8170 3173
718e3744 3174/* Configuration write function. */
e3ab8170
AD
3175static int rmap_config_write_debug(struct vty *vty)
3176{
3177 int write = 0;
3178
3179 if (rmap_debug) {
3180 vty_out(vty, "debug route-map\n");
3181 write++;
3182 }
3183
3184 return write;
3185}
3186
dc9ffce8
CF
3187/* Common route map rules */
3188
d62a17ae 3189void *route_map_rule_tag_compile(const char *arg)
dc9ffce8 3190{
d62a17ae 3191 unsigned long int tmp;
3192 char *endptr;
3193 route_tag_t *tag;
dc9ffce8 3194
d62a17ae 3195 errno = 0;
3196 tmp = strtoul(arg, &endptr, 0);
3197 if (arg[0] == '\0' || *endptr != '\0' || errno || tmp > ROUTE_TAG_MAX)
3198 return NULL;
dc9ffce8 3199
d62a17ae 3200 tag = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*tag));
3201 *tag = tmp;
dc9ffce8 3202
d62a17ae 3203 return tag;
dc9ffce8
CF
3204}
3205
d62a17ae 3206void route_map_rule_tag_free(void *rule)
dc9ffce8 3207{
d62a17ae 3208 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
dc9ffce8
CF
3209}
3210
d62a17ae 3211void route_map_finish(void)
9df78e7c 3212{
d62a17ae 3213 int i;
88711d8a
DL
3214 struct route_map_rule_cmd_proxy *proxy;
3215
3216 /* these 2 hash tables have INIT_HASH initializers, so the "default"
3217 * state is "initialized & empty" => fini() followed by init() to
3218 * return to that same state
3219 */
3220 while ((proxy = rmap_cmd_name_pop(rmap_match_cmds)))
3221 (void)proxy;
3222 rmap_cmd_name_fini(rmap_match_cmds);
3223 rmap_cmd_name_init(rmap_match_cmds);
9df78e7c 3224
88711d8a
DL
3225 while ((proxy = rmap_cmd_name_pop(rmap_set_cmds)))
3226 (void)proxy;
3227 rmap_cmd_name_fini(rmap_set_cmds);
3228 rmap_cmd_name_init(rmap_set_cmds);
9df78e7c 3229
8619629a
DS
3230 /*
3231 * All protocols are setting these to NULL
3232 * by default on shutdown( route_map_finish )
3233 * Why are we making them do this work?
3234 */
3235 route_map_master.add_hook = NULL;
3236 route_map_master.delete_hook = NULL;
3237 route_map_master.event_hook = NULL;
3238
d62a17ae 3239 /* cleanup route_map */
3240 while (route_map_master.head) {
3241 struct route_map *map = route_map_master.head;
e4694d0d 3242 map->to_be_processed = false;
d62a17ae 3243 route_map_delete(map);
3244 }
9df78e7c 3245
d62a17ae 3246 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
3247 hash_free(route_map_dep_hash[i]);
3248 route_map_dep_hash[i] = NULL;
3249 }
9df78e7c 3250
d62a17ae 3251 hash_free(route_map_master_hash);
3252 route_map_master_hash = NULL;
9df78e7c
DS
3253}
3254
4a2a09d0 3255/* Increment the use_count counter while attaching the route map */
3256void route_map_counter_increment(struct route_map *map)
3257{
3258 if (map)
3259 map->use_count++;
3260}
3261
3262/* Decrement the use_count counter while detaching the route map. */
3263void route_map_counter_decrement(struct route_map *map)
3264{
3265 if (map) {
3266 if (map->use_count <= 0)
3267 return;
3268 map->use_count--;
3269 }
3270}
3271
2d26f094
NT
3272DEFUN_HIDDEN(show_route_map_pfx_tbl, show_route_map_pfx_tbl_cmd,
3273 "show route-map WORD prefix-table",
3274 SHOW_STR
3275 "route-map\n"
3276 "route-map name\n"
3277 "internal prefix-table\n")
3278{
3279 const char *rmap_name = argv[2]->arg;
3280 struct route_map *rmap = NULL;
3281 struct route_table *rm_pfx_tbl4 = NULL;
3282 struct route_table *rm_pfx_tbl6 = NULL;
3283 struct route_node *rn = NULL, *prn = NULL;
3284 struct list *rmap_index_list = NULL;
3285 struct listnode *ln = NULL, *nln = NULL;
3286 struct route_map_index *index = NULL;
2d26f094
NT
3287 uint8_t len = 54;
3288
3289 vty_out(vty, "%s:\n", frr_protonameinst);
3290 rmap = route_map_lookup_by_name(rmap_name);
3291 if (rmap) {
3292 rm_pfx_tbl4 = rmap->ipv4_prefix_table;
3293 if (rm_pfx_tbl4) {
3294 vty_out(vty, "\n%s%43s%s\n", "IPv4 Prefix", "",
3295 "Route-map Index List");
3296 vty_out(vty, "%s%39s%s\n", "_______________", "",
3297 "____________________");
3298 for (rn = route_top(rm_pfx_tbl4); rn;
3299 rn = route_next(rn)) {
b219dda1 3300 vty_out(vty, " %pRN (%d)\n", rn,
c10e14e9 3301 route_node_get_lock_count(rn));
2d26f094
NT
3302
3303 vty_out(vty, "(P) ");
3304 prn = rn->parent;
3305 if (prn) {
b219dda1 3306 vty_out(vty, "%pRN\n", prn);
2d26f094
NT
3307 }
3308
3309 vty_out(vty, "\n");
3310 rmap_index_list = (struct list *)rn->info;
3311 if (!rmap_index_list
3312 || !listcount(rmap_index_list))
3313 vty_out(vty, "%*s%s\n", len, "", "-");
3314 else
3315 for (ALL_LIST_ELEMENTS(rmap_index_list,
3316 ln, nln,
3317 index)) {
3318 vty_out(vty, "%*s%s seq %d\n",
3319 len, "",
3320 index->map->name,
3321 index->pref);
3322 }
3323 vty_out(vty, "\n");
3324 }
3325 }
3326
3327 rm_pfx_tbl6 = rmap->ipv6_prefix_table;
3328 if (rm_pfx_tbl6) {
3329 vty_out(vty, "\n%s%43s%s\n", "IPv6 Prefix", "",
3330 "Route-map Index List");
3331 vty_out(vty, "%s%39s%s\n", "_______________", "",
3332 "____________________");
3333 for (rn = route_top(rm_pfx_tbl6); rn;
3334 rn = route_next(rn)) {
b219dda1 3335 vty_out(vty, " %pRN (%d)\n", rn,
c10e14e9 3336 route_node_get_lock_count(rn));
2d26f094
NT
3337
3338 vty_out(vty, "(P) ");
3339 prn = rn->parent;
3340 if (prn) {
b219dda1 3341 vty_out(vty, "%pRN\n", prn);
2d26f094
NT
3342 }
3343
3344 vty_out(vty, "\n");
3345 rmap_index_list = (struct list *)rn->info;
3346 if (!rmap_index_list
3347 || !listcount(rmap_index_list))
3348 vty_out(vty, "%*s%s\n", len, "", "-");
3349 else
3350 for (ALL_LIST_ELEMENTS(rmap_index_list,
3351 ln, nln,
3352 index)) {
3353 vty_out(vty, "%*s%s seq %d\n",
3354 len, "",
3355 index->map->name,
3356 index->pref);
3357 }
3358 vty_out(vty, "\n");
3359 }
3360 }
3361 }
3362
3363 vty_out(vty, "\n");
3364 return CMD_SUCCESS;
3365}
3366
718e3744 3367/* Initialization of route map vector. */
d62a17ae 3368void route_map_init(void)
718e3744 3369{
d62a17ae 3370 int i;
3371
d62a17ae 3372 route_map_master_hash =
996c9314 3373 hash_create_size(8, route_map_hash_key_make, route_map_hash_cmp,
bd74dc61 3374 "Route Map Master Hash");
d62a17ae 3375
3376 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
996c9314
LB
3377 route_map_dep_hash[i] = hash_create_size(
3378 8, route_map_dep_hash_make_key, route_map_dep_hash_cmp,
3379 "Route Map Dep Hash");
b2575bc0 3380
e3ab8170
AD
3381 rmap_debug = false;
3382
2b3e4807 3383 route_map_cli_init();
518f0eb1 3384
2b3e4807 3385 /* Install route map top node. */
612c2c15 3386 install_node(&rmap_debug_node);
e3ab8170 3387
d62a17ae 3388 /* Install route map commands. */
e3ab8170
AD
3389 install_element(CONFIG_NODE, &debug_rmap_cmd);
3390 install_element(CONFIG_NODE, &no_debug_rmap_cmd);
3391
d62a17ae 3392 /* Install show command */
1fa30509
DS
3393 install_element(ENABLE_NODE, &rmap_clear_counters_cmd);
3394
d62a17ae 3395 install_element(ENABLE_NODE, &rmap_show_name_cmd);
4a2a09d0 3396 install_element(ENABLE_NODE, &rmap_show_unused_cmd);
82f97584 3397
e3ab8170
AD
3398 install_element(ENABLE_NODE, &debug_rmap_cmd);
3399 install_element(ENABLE_NODE, &no_debug_rmap_cmd);
49a08bb0 3400
2d26f094 3401 install_element(ENABLE_NODE, &show_route_map_pfx_tbl_cmd);
718e3744 3402}