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