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