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