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