]> git.proxmox.com Git - mirror_frr.git/blame - lib/routemap.c
lib,zebra,bgpd,ospfd,ospf6d: Route-map yang defns
[mirror_frr.git] / lib / routemap.c
CommitLineData
718e3744 1/* Route map function.
896014f4
DL
2 * Copyright (C) 1998, 1999 Kunihiro Ishiguro
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
718e3744 20
21#include <zebra.h>
22
23#include "linklist.h"
24#include "memory.h"
25#include "vector.h"
26#include "prefix.h"
82f97584 27#include "vty.h"
718e3744 28#include "routemap.h"
29#include "command.h"
fee0f4c6 30#include "log.h"
518f0eb1 31#include "hash.h"
b85120bc 32#include "libfrr.h"
040c7c3a 33#include "lib_errors.h"
49a08bb0 34#include "table.h"
6b0655a2 35
bf8d3d6a
DL
36DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP, "Route map");
37DEFINE_MTYPE(LIB, ROUTE_MAP_NAME, "Route map name");
38DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_INDEX, "Route map index");
39DEFINE_MTYPE(LIB, ROUTE_MAP_RULE, "Route map rule");
40DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_RULE_STR, "Route map rule str");
41DEFINE_MTYPE(LIB, ROUTE_MAP_COMPILED, "Route map compiled");
42DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_DEP, "Route map dependency");
43DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_DEP_DATA, "Route map dependency data");
4a1ab8e4 44
96244aca
DL
45DEFINE_QOBJ_TYPE(route_map_index);
46DEFINE_QOBJ_TYPE(route_map);
e80e7cce 47
49a08bb0
NT
48#define IPv4_PREFIX_LIST "ip address prefix-list"
49#define IPv6_PREFIX_LIST "ipv6 address prefix-list"
49a08bb0 50
2d26f094
NT
51#define IS_RULE_IPv4_PREFIX_LIST(S) \
52 (strncmp(S, IPv4_PREFIX_LIST, strlen(IPv4_PREFIX_LIST)) == 0)
53#define IS_RULE_IPv6_PREFIX_LIST(S) \
54 (strncmp(S, IPv6_PREFIX_LIST, strlen(IPv6_PREFIX_LIST)) == 0)
55
49a08bb0
NT
56struct route_map_pentry_dep {
57 struct prefix_list_entry *pentry;
58 const char *plist_name;
59 route_map_event_t event;
60};
61
718e3744 62/* Vector for route match rules. */
63static vector route_match_vec;
64
65/* Vector for route set rules. */
66static vector route_set_vec;
67
2d26f094
NT
68static void route_map_pfx_tbl_update(route_map_event_t event,
69 struct route_map_index *index, afi_t afi,
70 const char *plist_name);
71static void route_map_pfx_table_add_default(afi_t afi,
72 struct route_map_index *index);
73static void route_map_pfx_table_del_default(afi_t afi,
74 struct route_map_index *index);
75static void route_map_add_plist_entries(afi_t afi,
76 struct route_map_index *index,
77 const char *plist_name,
78 struct prefix_list_entry *entry);
79static void route_map_del_plist_entries(afi_t afi,
80 struct route_map_index *index,
81 const char *plist_name,
82 struct prefix_list_entry *entry);
2d26f094
NT
83
84static struct hash *route_map_get_dep_hash(route_map_event_t event);
49a08bb0 85
a7282663 86struct route_map_match_set_hooks rmap_match_set_hook;
82f97584
DW
87
88/* match interface */
d62a17ae 89void route_map_match_interface_hook(int (*func)(
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,
02e7a369 1350 rule->rule_str,
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,
1782514f 1533 const struct prefix *prefix, void *object)
b68885f9
LK
1534{
1535 enum route_map_cmd_result_t ret = RMAP_NOMATCH;
1536 struct route_map_rule *match;
1537 bool is_matched = false;
1538
1539
1540 /* Check all match rule and if there is no match rule, go to the
1541 set statement. */
1542 if (!match_list->head)
1543 ret = RMAP_MATCH;
1544 else {
1545 for (match = match_list->head; match; match = match->next) {
1546 /*
1547 * Try each match statement. If any match does not
1548 * return RMAP_MATCH or RMAP_NOOP, return.
1549 * Otherwise continue on to next match statement.
1550 * All match statements must MATCH for
1551 * end-result to be a match.
1552 * (Exception:If match stmts result in a mix of
1553 * MATCH/NOOP, then also end-result is a match)
1554 * If all result in NOOP, end-result is NOOP.
1555 */
1556 ret = (*match->cmd->func_apply)(match->value, prefix,
1782514f 1557 object);
b68885f9
LK
1558
1559 /*
1560 * If the consolidated result of func_apply is:
1561 * -----------------------------------------------
1562 * | MATCH | NOMATCH | NOOP | Final Result |
1563 * ------------------------------------------------
1564 * | yes | yes | yes | NOMATCH |
1565 * | no | no | yes | NOOP |
1566 * | yes | no | yes | MATCH |
1567 * | no | yes | yes | NOMATCH |
1568 * |-----------------------------------------------
1569 *
1570 * Traditionally, all rules within route-map
1571 * should match for it to MATCH.
1572 * If there are noops within the route-map rules,
1573 * it follows the above matrix.
1574 *
1575 * Eg: route-map rm1 permit 10
1576 * match rule1
1577 * match rule2
1578 * match rule3
1579 * ....
1580 * route-map rm1 permit 20
1581 * match ruleX
1582 * match ruleY
1583 * ...
1584 */
1585
1586 switch (ret) {
1587 case RMAP_MATCH:
1588 is_matched = true;
1589 break;
1590
1591 case RMAP_NOMATCH:
1592 return ret;
1593
1594 case RMAP_NOOP:
1595 if (is_matched)
1596 ret = RMAP_MATCH;
1597 break;
1598
1599 default:
1600 break;
1601 }
1602
1603 }
1604 }
1605 return ret;
1606}
1607
2d26f094
NT
1608static struct list *route_map_get_index_list(struct route_node **rn,
1609 const struct prefix *prefix,
1610 struct route_table *table)
819a23f9
NT
1611{
1612 struct route_node *tmp_rn = NULL;
1613
1614 if (!(*rn)) {
1615 *rn = route_node_match(table, prefix);
1616
1617 if (!(*rn))
1618 return NULL;
1619
1620 if ((*rn)->info)
1621 return (struct list *)((*rn)->info);
1622
1623 /* If rn->info is NULL, get the parent.
1624 * Store the rn in tmp_rn and unlock it later.
1625 */
1626 tmp_rn = *rn;
1627 }
1628
1629 do {
1630 *rn = (*rn)->parent;
1631 if (tmp_rn)
1632 route_unlock_node(tmp_rn);
1633
1634 if (!(*rn))
1635 break;
1636
1637 if ((*rn)->info) {
1638 route_lock_node(*rn);
1639 return (struct list *)((*rn)->info);
1640 }
1641 } while (!(*rn)->info);
1642
1643 return NULL;
1644}
1645
1646/*
1647 * This function returns the route-map index that best matches the prefix.
1648 */
1782514f
DS
1649static struct route_map_index *route_map_get_index(struct route_map *map,
1650 const struct prefix *prefix,
1651 void *object,
1652 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 1697 ret = route_map_apply_match(&index->match_list, prefix,
1782514f 1698 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
1ac88792 2243static void route_map_pentry_process_dependency(struct hash_bucket *bucket,
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
1ac88792 2256 dep_data = (struct route_map_dep_data *)bucket->data;
49a08bb0
NT
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 2371route_map_result_t route_map_apply(struct route_map *map,
1782514f 2372 const struct prefix *prefix, void *object)
d62a17ae 2373{
2374 static int recursion = 0;
b68885f9
LK
2375 enum route_map_cmd_result_t match_ret = RMAP_NOMATCH;
2376 route_map_result_t ret = RMAP_PERMITMATCH;
819a23f9
NT
2377 struct route_map_index *index = NULL;
2378 struct route_map_rule *set = NULL;
819a23f9 2379 bool skip_match_clause = false;
d62a17ae 2380
2381 if (recursion > RMAP_RECURSION_LIMIT) {
040c7c3a 2382 flog_warn(
450971aa 2383 EC_LIB_RMAP_RECURSION_LIMIT,
d62a17ae 2384 "route-map recursion limit (%d) reached, discarding route",
2385 RMAP_RECURSION_LIMIT);
2386 recursion = 0;
2387 return RMAP_DENYMATCH;
2388 }
2389
b68885f9 2390 if (map == NULL || map->head == NULL) {
e3ab8170
AD
2391 ret = RMAP_DENYMATCH;
2392 goto route_map_apply_end;
2393 }
d62a17ae 2394
279b0607 2395 map->applied++;
819a23f9 2396
2d26f094
NT
2397 if ((!map->optimization_disabled)
2398 && (map->ipv4_prefix_table || map->ipv6_prefix_table)) {
1782514f 2399 index = route_map_get_index(map, prefix, object,
819a23f9
NT
2400 (uint8_t *)&match_ret);
2401 if (index) {
284a6f5f 2402 index->applied++;
819a23f9
NT
2403 if (rmap_debug)
2404 zlog_debug(
2dbe669b
DA
2405 "Best match route-map: %s, sequence: %d for pfx: %pFX, result: %s",
2406 map->name, index->pref, prefix,
819a23f9
NT
2407 route_map_cmd_result_str(match_ret));
2408 } else {
2409 if (rmap_debug)
2d26f094 2410 zlog_debug(
2dbe669b
DA
2411 "No best match sequence for pfx: %pFX in route-map: %s, result: %s",
2412 prefix, map->name,
2d26f094 2413 route_map_cmd_result_str(match_ret));
819a23f9
NT
2414 /*
2415 * No index matches this prefix. Return deny unless,
2416 * match_ret = RMAP_NOOP.
2417 */
2418 if (match_ret == RMAP_NOOP)
2419 ret = RMAP_PERMITMATCH;
2420 else
2421 ret = RMAP_DENYMATCH;
2422 goto route_map_apply_end;
e3ab8170 2423 }
819a23f9
NT
2424 skip_match_clause = true;
2425 } else {
2426 index = map->head;
2427 }
2428
2429 for (; index; index = index->next) {
a8f58eb6 2430 if (!skip_match_clause) {
00aef028 2431 index->applied++;
819a23f9
NT
2432 /* Apply this index. */
2433 match_ret = route_map_apply_match(&index->match_list,
1782514f 2434 prefix, object);
819a23f9
NT
2435 if (rmap_debug) {
2436 zlog_debug(
2dbe669b
DA
2437 "Route-map: %s, sequence: %d, prefix: %pFX, result: %s",
2438 map->name, index->pref, prefix,
819a23f9
NT
2439 route_map_cmd_result_str(match_ret));
2440 }
2441 } else
2442 skip_match_clause = false;
2443
e3ab8170 2444
d62a17ae 2445 /* Now we apply the matrix from above */
b68885f9
LK
2446 if (match_ret == RMAP_NOOP)
2447 /*
2448 * Do not change the return value. Retain the previous
2449 * return value. Previous values can be:
2450 * 1)permitmatch (if a nomatch was never
2451 * seen before in this route-map.)
2452 * 2)denymatch (if a nomatch was seen earlier in one
2453 * of the previous sequences)
2454 */
2455
2456 /*
2457 * 'cont' from matrix - continue to next route-map
2458 * sequence
2459 */
d62a17ae 2460 continue;
b68885f9
LK
2461 else if (match_ret == RMAP_NOMATCH) {
2462
2463 /*
2464 * The return value is now changed to denymatch.
2465 * So from here on out, even if we see more noops,
2466 * we retain this return value and return this
2467 * eventually if there are no matches.
2468 */
2469 ret = RMAP_DENYMATCH;
2470
2471 /*
2472 * 'cont' from matrix - continue to next route-map
2473 * sequence
2474 */
2475 continue;
2476 } else if (match_ret == RMAP_MATCH) {
d62a17ae 2477 if (index->type == RMAP_PERMIT)
2478 /* 'action' */
2479 {
b68885f9
LK
2480 /* Match succeeded, rmap is of type permit */
2481 ret = RMAP_PERMITMATCH;
2482
d62a17ae 2483 /* permit+match must execute sets */
2484 for (set = index->set_list.head; set;
2485 set = set->next)
b68885f9
LK
2486 /*
2487 * set cmds return RMAP_OKAY or
2488 * RMAP_ERROR. We do not care if
2489 * set succeeded or not. So, ignore
2490 * return code.
2491 */
1782514f
DS
2492 (void)(*set->cmd->func_apply)(
2493 set->value, prefix, object);
d62a17ae 2494
2495 /* Call another route-map if available */
2496 if (index->nextrm) {
2497 struct route_map *nextrm =
2498 route_map_lookup_by_name(
2499 index->nextrm);
2500
2501 if (nextrm) /* Target route-map found,
2502 jump to it */
2503 {
2504 recursion++;
2505 ret = route_map_apply(
1782514f 2506 nextrm, prefix, object);
d62a17ae 2507 recursion--;
2508 }
2509
2510 /* If nextrm returned 'deny', finish. */
2511 if (ret == RMAP_DENYMATCH)
e3ab8170 2512 goto route_map_apply_end;
d62a17ae 2513 }
2514
2515 switch (index->exitpolicy) {
2516 case RMAP_EXIT:
e3ab8170 2517 goto route_map_apply_end;
d62a17ae 2518 case RMAP_NEXT:
2519 continue;
2520 case RMAP_GOTO: {
2521 /* Find the next clause to jump to */
2522 struct route_map_index *next =
2523 index->next;
2524 int nextpref = index->nextpref;
2525
2526 while (next && next->pref < nextpref) {
2527 index = next;
2528 next = next->next;
2529 }
2530 if (next == NULL) {
2531 /* No clauses match! */
e3ab8170 2532 goto route_map_apply_end;
d62a17ae 2533 }
2534 }
2535 }
2536 } else if (index->type == RMAP_DENY)
2537 /* 'deny' */
2538 {
e3ab8170
AD
2539 ret = RMAP_DENYMATCH;
2540 goto route_map_apply_end;
d62a17ae 2541 }
2542 }
2543 }
e3ab8170
AD
2544
2545route_map_apply_end:
2dbe669b
DA
2546 if (rmap_debug)
2547 zlog_debug("Route-map: %s, prefix: %pFX, result: %s",
2548 (map ? map->name : "null"), prefix,
e3ab8170 2549 route_map_result_str(ret));
e3ab8170
AD
2550
2551 return (ret);
d62a17ae 2552}
2553
2554void route_map_add_hook(void (*func)(const char *))
2555{
2556 route_map_master.add_hook = func;
2557}
2558
2559void route_map_delete_hook(void (*func)(const char *))
2560{
2561 route_map_master.delete_hook = func;
2562}
2563
097b5973 2564void route_map_event_hook(void (*func)(const char *name))
d62a17ae 2565{
2566 route_map_master.event_hook = func;
718e3744 2567}
2568
518f0eb1 2569/* Routines for route map dependency lists and dependency processing */
74df8d6d 2570static bool route_map_rmap_hash_cmp(const void *p1, const void *p2)
518f0eb1 2571{
e2c8d6ce
NT
2572 return strcmp(((const struct route_map_dep_data *)p1)->rname,
2573 ((const struct route_map_dep_data *)p2)->rname)
2574 == 0;
518f0eb1
DS
2575}
2576
74df8d6d 2577static bool route_map_dep_hash_cmp(const void *p1, const void *p2)
518f0eb1
DS
2578{
2579
d62a17ae 2580 return (strcmp(((const struct route_map_dep *)p1)->dep_name,
2581 (const char *)p2)
2582 == 0);
518f0eb1
DS
2583}
2584
e3b78da8 2585static void route_map_clear_reference(struct hash_bucket *bucket, void *arg)
518f0eb1 2586{
e2c8d6ce
NT
2587 struct route_map_dep *dep = bucket->data;
2588 struct route_map_dep_data *dep_data = NULL, tmp_dep_data;
518f0eb1 2589
db8db580
DS
2590 memset(&tmp_dep_data, 0, sizeof(struct route_map_dep_data));
2591 tmp_dep_data.rname = arg;
2592 dep_data = hash_release(dep->dep_rmap_hash, &tmp_dep_data);
2593 if (dep_data) {
af87aff6
DS
2594 if (rmap_debug)
2595 zlog_debug("Clearing reference for %s to %s count: %d",
2596 dep->dep_name, tmp_dep_data.rname,
2597 dep_data->refcnt);
2598
db8db580
DS
2599 XFREE(MTYPE_ROUTE_MAP_NAME, dep_data->rname);
2600 XFREE(MTYPE_ROUTE_MAP_DEP_DATA, dep_data);
2601 }
2602 if (!dep->dep_rmap_hash->count) {
2603 dep = hash_release(dep->this_hash, (void *)dep->dep_name);
2604 hash_free(dep->dep_rmap_hash);
2605 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
2606 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
518f0eb1 2607 }
d62a17ae 2608}
2609
2610static void route_map_clear_all_references(char *rmap_name)
2611{
2612 int i;
2613
af87aff6
DS
2614 if (rmap_debug)
2615 zlog_debug("Clearing references for %s", rmap_name);
2616
d62a17ae 2617 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
2618 hash_iterate(route_map_dep_hash[i], route_map_clear_reference,
2619 (void *)rmap_name);
518f0eb1 2620 }
518f0eb1
DS
2621}
2622
e2c8d6ce
NT
2623static unsigned int route_map_dep_data_hash_make_key(const void *p)
2624{
2625 const struct route_map_dep_data *dep_data = p;
2626
2627 return string_hash_make(dep_data->rname);
2628}
2629
31f937fb
SM
2630DEFUN (set_srte_color,
2631 set_srte_color_cmd,
2632 "set sr-te color [(1-4294967295)]",
2633 SET_STR
2634 SRTE_STR
2635 SRTE_COLOR_STR
2636 "Color of the SR-TE Policies to match with\n")
2637{
2638 VTY_DECLVAR_CONTEXT(route_map_index, index);
2639 int idx = 0;
2640 char *arg = argv_find(argv, argc, "(1-4294967295)", &idx)
2641 ? argv[idx]->arg
2642 : NULL;
2643
2644 if (rmap_match_set_hook.set_srte_color)
2645 return rmap_match_set_hook.set_srte_color(vty, index,
2646 "sr-te color", arg);
2647 return CMD_SUCCESS;
2648}
2649
2650DEFUN (no_set_srte_color,
2651 no_set_srte_color_cmd,
2652 "no set sr-te color [(1-4294967295)]",
2653 NO_STR
2654 SET_STR
2655 SRTE_STR
2656 SRTE_COLOR_STR
2657 "Color of the SR-TE Policies to match with\n")
2658{
2659 VTY_DECLVAR_CONTEXT(route_map_index, index);
2660 int idx = 0;
2661 char *arg = argv_find(argv, argc, "(1-4294967295)", &idx)
2662 ? argv[idx]->arg
2663 : NULL;
2664
2665 if (rmap_match_set_hook.no_set_srte_color)
2666 return rmap_match_set_hook.no_set_srte_color(
2667 vty, index, "sr-te color", arg);
2668 return CMD_SUCCESS;
2669}
2670
d62a17ae 2671static void *route_map_dep_hash_alloc(void *p)
518f0eb1 2672{
d62a17ae 2673 char *dep_name = (char *)p;
2674 struct route_map_dep *dep_entry;
2675
2676 dep_entry = XCALLOC(MTYPE_ROUTE_MAP_DEP, sizeof(struct route_map_dep));
2677 dep_entry->dep_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
996c9314 2678 dep_entry->dep_rmap_hash =
e2c8d6ce 2679 hash_create_size(8, route_map_dep_data_hash_make_key,
996c9314 2680 route_map_rmap_hash_cmp, "Route Map Dep Hash");
d62a17ae 2681 dep_entry->this_hash = NULL;
2682
e2c8d6ce 2683 return dep_entry;
d62a17ae 2684}
518f0eb1 2685
d62a17ae 2686static void *route_map_name_hash_alloc(void *p)
2687{
e2c8d6ce
NT
2688 struct route_map_dep_data *dep_data = NULL, *tmp_dep_data = NULL;
2689
2690 dep_data = XCALLOC(MTYPE_ROUTE_MAP_DEP_DATA,
2691 sizeof(struct route_map_dep_data));
2692 tmp_dep_data = p;
2693 dep_data->rname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, tmp_dep_data->rname);
2694 return dep_data;
518f0eb1
DS
2695}
2696
d8b87afe 2697static unsigned int route_map_dep_hash_make_key(const void *p)
518f0eb1 2698{
d62a17ae 2699 return (string_hash_make((char *)p));
2700}
518f0eb1 2701
e3b78da8 2702static void route_map_print_dependency(struct hash_bucket *bucket, void *data)
d62a17ae 2703{
e2c8d6ce
NT
2704 struct route_map_dep_data *dep_data = bucket->data;
2705 char *rmap_name = dep_data->rname;
2706 char *dep_name = data;
518f0eb1 2707
15569c58 2708 zlog_debug("%s: Dependency for %s: %s", __func__, dep_name, rmap_name);
518f0eb1
DS
2709}
2710
d62a17ae 2711static int route_map_dep_update(struct hash *dephash, const char *dep_name,
2712 const char *rmap_name, route_map_event_t type)
518f0eb1 2713{
d62a17ae 2714 struct route_map_dep *dep = NULL;
d62a17ae 2715 char *dname, *rname;
2716 int ret = 0;
e2c8d6ce
NT
2717 struct route_map_dep_data *dep_data = NULL, *ret_dep_data = NULL;
2718 struct route_map_dep_data tmp_dep_data;
d62a17ae 2719
2720 dname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
2721 rname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_name);
2722
2723 switch (type) {
2724 case RMAP_EVENT_PLIST_ADDED:
2725 case RMAP_EVENT_CLIST_ADDED:
2726 case RMAP_EVENT_ECLIST_ADDED:
2727 case RMAP_EVENT_ASLIST_ADDED:
2728 case RMAP_EVENT_LLIST_ADDED:
2729 case RMAP_EVENT_CALL_ADDED:
2730 case RMAP_EVENT_FILTER_ADDED:
2731 if (rmap_debug)
e3ab8170
AD
2732 zlog_debug("Adding dependency for filter %s in route-map %s",
2733 dep_name, rmap_name);
d62a17ae 2734 dep = (struct route_map_dep *)hash_get(
2735 dephash, dname, route_map_dep_hash_alloc);
2736 if (!dep) {
2737 ret = -1;
2738 goto out;
2739 }
2740
2741 if (!dep->this_hash)
2742 dep->this_hash = dephash;
2743
e2c8d6ce
NT
2744 memset(&tmp_dep_data, 0, sizeof(struct route_map_dep_data));
2745 tmp_dep_data.rname = rname;
2746 dep_data = hash_lookup(dep->dep_rmap_hash, &tmp_dep_data);
2747 if (!dep_data)
2748 dep_data = hash_get(dep->dep_rmap_hash, &tmp_dep_data,
2749 route_map_name_hash_alloc);
2750
2751 dep_data->refcnt++;
d62a17ae 2752 break;
2753 case RMAP_EVENT_PLIST_DELETED:
2754 case RMAP_EVENT_CLIST_DELETED:
2755 case RMAP_EVENT_ECLIST_DELETED:
2756 case RMAP_EVENT_ASLIST_DELETED:
2757 case RMAP_EVENT_LLIST_DELETED:
2758 case RMAP_EVENT_CALL_DELETED:
2759 case RMAP_EVENT_FILTER_DELETED:
2760 if (rmap_debug)
e3ab8170
AD
2761 zlog_debug("Deleting dependency for filter %s in route-map %s",
2762 dep_name, rmap_name);
d62a17ae 2763 dep = (struct route_map_dep *)hash_get(dephash, dname, NULL);
2764 if (!dep) {
2765 goto out;
2766 }
2767
e2c8d6ce
NT
2768 memset(&tmp_dep_data, 0, sizeof(struct route_map_dep_data));
2769 tmp_dep_data.rname = rname;
2770 dep_data = hash_lookup(dep->dep_rmap_hash, &tmp_dep_data);
9149c635
DS
2771 /*
2772 * If dep_data is NULL then something has gone seriously
2773 * wrong in route-map handling. Note it and prevent
2774 * the crash.
2775 */
2776 if (!dep_data) {
2777 zlog_warn(
2778 "route-map dependency for route-map %s: %s is not correct",
2779 rmap_name, dep_name);
c415a4dc 2780 goto out;
9149c635 2781 }
c415a4dc 2782
9149c635 2783 dep_data->refcnt--;
e2c8d6ce
NT
2784
2785 if (!dep_data->refcnt) {
2786 ret_dep_data = hash_release(dep->dep_rmap_hash,
2787 &tmp_dep_data);
2788 if (ret_dep_data) {
2789 XFREE(MTYPE_ROUTE_MAP_NAME,
2790 ret_dep_data->rname);
2791 XFREE(MTYPE_ROUTE_MAP_DEP_DATA, ret_dep_data);
2792 }
2793 }
d62a17ae 2794
2795 if (!dep->dep_rmap_hash->count) {
2796 dep = hash_release(dephash, dname);
2797 hash_free(dep->dep_rmap_hash);
2798 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
2799 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
d62a17ae 2800 }
2801 break;
ba1707ca
DS
2802 case RMAP_EVENT_SET_ADDED:
2803 case RMAP_EVENT_SET_DELETED:
2804 case RMAP_EVENT_SET_REPLACED:
2805 case RMAP_EVENT_MATCH_ADDED:
2806 case RMAP_EVENT_MATCH_DELETED:
2807 case RMAP_EVENT_MATCH_REPLACED:
2808 case RMAP_EVENT_INDEX_ADDED:
2809 case RMAP_EVENT_INDEX_DELETED:
d62a17ae 2810 break;
2811 }
2812
2813 if (dep) {
2814 if (rmap_debug)
2815 hash_iterate(dep->dep_rmap_hash,
2816 route_map_print_dependency, dname);
2817 }
2818
2819out:
2820 XFREE(MTYPE_ROUTE_MAP_NAME, rname);
2821 XFREE(MTYPE_ROUTE_MAP_NAME, dname);
2822 return ret;
2823}
2824
2825static struct hash *route_map_get_dep_hash(route_map_event_t event)
2826{
2827 struct hash *upd8_hash = NULL;
2828
2829 switch (event) {
2830 case RMAP_EVENT_PLIST_ADDED:
2831 case RMAP_EVENT_PLIST_DELETED:
2832 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_PLIST];
2833 break;
2834 case RMAP_EVENT_CLIST_ADDED:
2835 case RMAP_EVENT_CLIST_DELETED:
2836 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_CLIST];
2837 break;
2838 case RMAP_EVENT_ECLIST_ADDED:
2839 case RMAP_EVENT_ECLIST_DELETED:
2840 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ECLIST];
2841 break;
2842 case RMAP_EVENT_ASLIST_ADDED:
2843 case RMAP_EVENT_ASLIST_DELETED:
2844 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ASPATH];
2845 break;
2846 case RMAP_EVENT_LLIST_ADDED:
2847 case RMAP_EVENT_LLIST_DELETED:
2848 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_LCLIST];
2849 break;
2850 case RMAP_EVENT_CALL_ADDED:
2851 case RMAP_EVENT_CALL_DELETED:
5ed2e47b 2852 case RMAP_EVENT_MATCH_ADDED:
2853 case RMAP_EVENT_MATCH_DELETED:
d62a17ae 2854 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_RMAP];
2855 break;
2856 case RMAP_EVENT_FILTER_ADDED:
2857 case RMAP_EVENT_FILTER_DELETED:
2858 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_FILTER];
2859 break;
ba1707ca
DS
2860 /*
2861 * Should we actually be ignoring these?
2862 * I am not sure but at this point in time, let
2863 * us get them into this switch and we can peel
2864 * them into the appropriate place in the future
2865 */
2866 case RMAP_EVENT_SET_ADDED:
2867 case RMAP_EVENT_SET_DELETED:
2868 case RMAP_EVENT_SET_REPLACED:
2869 case RMAP_EVENT_MATCH_REPLACED:
2870 case RMAP_EVENT_INDEX_ADDED:
2871 case RMAP_EVENT_INDEX_DELETED:
d62a17ae 2872 upd8_hash = NULL;
2873 break;
2874 }
2875 return (upd8_hash);
518f0eb1
DS
2876}
2877
e3b78da8 2878static void route_map_process_dependency(struct hash_bucket *bucket, void *data)
518f0eb1 2879{
e2c8d6ce
NT
2880 struct route_map_dep_data *dep_data = NULL;
2881 char *rmap_name = NULL;
2882
2883 dep_data = bucket->data;
2884 rmap_name = dep_data->rname;
d62a17ae 2885
1fae5ff2 2886 if (rmap_debug)
e3ab8170 2887 zlog_debug("Notifying %s of dependency", rmap_name);
1fae5ff2 2888 if (route_map_master.event_hook)
097b5973 2889 (*route_map_master.event_hook)(rmap_name);
518f0eb1
DS
2890}
2891
d62a17ae 2892void route_map_upd8_dependency(route_map_event_t type, const char *arg,
2893 const char *rmap_name)
518f0eb1 2894{
d62a17ae 2895 struct hash *upd8_hash = NULL;
518f0eb1 2896
fdf823db 2897 if ((upd8_hash = route_map_get_dep_hash(type))) {
d62a17ae 2898 route_map_dep_update(upd8_hash, arg, rmap_name, type);
fdf823db
NT
2899
2900 if (type == RMAP_EVENT_CALL_ADDED) {
2901 /* Execute hook. */
2902 if (route_map_master.add_hook)
2903 (*route_map_master.add_hook)(rmap_name);
2904 } else if (type == RMAP_EVENT_CALL_DELETED) {
2905 /* Execute hook. */
2906 if (route_map_master.delete_hook)
2907 (*route_map_master.delete_hook)(rmap_name);
2908 }
2909 }
518f0eb1
DS
2910}
2911
d62a17ae 2912void route_map_notify_dependencies(const char *affected_name,
2913 route_map_event_t event)
518f0eb1 2914{
d62a17ae 2915 struct route_map_dep *dep;
2916 struct hash *upd8_hash;
2917 char *name;
2918
2919 if (!affected_name)
2920 return;
2921
2922 name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, affected_name);
2923
2924 if ((upd8_hash = route_map_get_dep_hash(event)) == NULL) {
2925 XFREE(MTYPE_ROUTE_MAP_NAME, name);
2926 return;
518f0eb1 2927 }
d62a17ae 2928
2929 dep = (struct route_map_dep *)hash_get(upd8_hash, name, NULL);
2930 if (dep) {
2931 if (!dep->this_hash)
2932 dep->this_hash = upd8_hash;
2933
e3ab8170
AD
2934 if (rmap_debug)
2935 zlog_debug("Filter %s updated", dep->dep_name);
d62a17ae 2936 hash_iterate(dep->dep_rmap_hash, route_map_process_dependency,
2937 (void *)event);
2938 }
2939
2940 XFREE(MTYPE_ROUTE_MAP_NAME, name);
518f0eb1
DS
2941}
2942
718e3744 2943/* VTY related functions. */
2d26f094
NT
2944DEFUN(no_routemap_optimization, no_routemap_optimization_cmd,
2945 "no route-map optimization",
2946 NO_STR
2947 "route-map\n"
2948 "optimization\n")
49a08bb0
NT
2949{
2950 VTY_DECLVAR_CONTEXT(route_map_index, index);
2951
2952 index->map->optimization_disabled = true;
2953 return CMD_SUCCESS;
2954}
2955
2d26f094
NT
2956DEFUN(routemap_optimization, routemap_optimization_cmd,
2957 "route-map optimization",
2958 "route-map\n"
2959 "optimization\n")
49a08bb0
NT
2960{
2961 VTY_DECLVAR_CONTEXT(route_map_index, index);
2962
2963 index->map->optimization_disabled = false;
2964 return CMD_SUCCESS;
2965}
82f97584 2966
1fa30509
DS
2967static void clear_route_map_helper(struct route_map *map)
2968{
2969 struct route_map_index *index;
2970
2971 map->applied_clear = map->applied;
2972 for (index = map->head; index; index = index->next)
2973 index->applied_clear = index->applied;
2974}
2975
2976DEFUN (rmap_clear_counters,
2977 rmap_clear_counters_cmd,
2978 "clear route-map counters [WORD]",
2979 CLEAR_STR
2980 "route-map information\n"
2981 "counters associated with the specified route-map\n"
2982 "route-map name\n")
2983{
2984 int idx_word = 2;
2985 struct route_map *map;
2986
2987 const char *name = (argc == 3 ) ? argv[idx_word]->arg : NULL;
2988
2989 if (name) {
2990 map = route_map_lookup_by_name(name);
2991
2992 if (map)
2993 clear_route_map_helper(map);
2994 else {
2995 vty_out(vty, "%s: 'route-map %s' not found\n",
2996 frr_protonameinst, name);
2997 return CMD_SUCCESS;
2998 }
2999 } else {
3000 for (map = route_map_master.head; map; map = map->next)
3001 clear_route_map_helper(map);
3002 }
3003
3004 return CMD_SUCCESS;
3005
3006}
5510e83b 3007
6d2729e3 3008DEFUN (rmap_show_name,
5510e83b 3009 rmap_show_name_cmd,
7514fb77 3010 "show route-map [WORD]",
5510e83b 3011 SHOW_STR
3012 "route-map information\n"
3013 "route-map name\n")
3014{
d62a17ae 3015 int idx_word = 2;
3016 const char *name = (argc == 3) ? argv[idx_word]->arg : NULL;
3017 return vty_show_route_map(vty, name);
5510e83b 3018}
3019
4a2a09d0 3020DEFUN (rmap_show_unused,
3021 rmap_show_unused_cmd,
3022 "show route-map-unused",
3023 SHOW_STR
3024 "unused route-map information\n")
3025{
3026 return vty_show_unused_route_map(vty);
3027}
3028
e3ab8170
AD
3029DEFUN (debug_rmap,
3030 debug_rmap_cmd,
3031 "debug route-map",
3032 DEBUG_STR
3033 "Debug option set for route-maps\n")
3034{
3035 rmap_debug = true;
3036 return CMD_SUCCESS;
3037}
3038
3039DEFUN (no_debug_rmap,
3040 no_debug_rmap_cmd,
3041 "no debug route-map",
3042 NO_STR
3043 DEBUG_STR
3044 "Debug option set for route-maps\n")
3045{
3046 rmap_debug = false;
3047 return CMD_SUCCESS;
3048}
3049
3050/* Debug node. */
612c2c15 3051static int rmap_config_write_debug(struct vty *vty);
62b346ee 3052static struct cmd_node rmap_debug_node = {
f4b8291f 3053 .name = "route-map debug",
62b346ee
DL
3054 .node = RMAP_DEBUG_NODE,
3055 .prompt = "",
612c2c15 3056 .config_write = rmap_config_write_debug,
62b346ee 3057};
e3ab8170 3058
718e3744 3059/* Configuration write function. */
e3ab8170
AD
3060static int rmap_config_write_debug(struct vty *vty)
3061{
3062 int write = 0;
3063
3064 if (rmap_debug) {
3065 vty_out(vty, "debug route-map\n");
3066 write++;
3067 }
3068
3069 return write;
3070}
3071
dc9ffce8
CF
3072/* Common route map rules */
3073
d62a17ae 3074void *route_map_rule_tag_compile(const char *arg)
dc9ffce8 3075{
d62a17ae 3076 unsigned long int tmp;
3077 char *endptr;
3078 route_tag_t *tag;
dc9ffce8 3079
d62a17ae 3080 errno = 0;
3081 tmp = strtoul(arg, &endptr, 0);
3082 if (arg[0] == '\0' || *endptr != '\0' || errno || tmp > ROUTE_TAG_MAX)
3083 return NULL;
dc9ffce8 3084
d62a17ae 3085 tag = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*tag));
3086 *tag = tmp;
dc9ffce8 3087
d62a17ae 3088 return tag;
dc9ffce8
CF
3089}
3090
d62a17ae 3091void route_map_rule_tag_free(void *rule)
dc9ffce8 3092{
d62a17ae 3093 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
dc9ffce8
CF
3094}
3095
d62a17ae 3096void route_map_finish(void)
9df78e7c 3097{
d62a17ae 3098 int i;
9df78e7c 3099
d62a17ae 3100 vector_free(route_match_vec);
3101 route_match_vec = NULL;
3102 vector_free(route_set_vec);
3103 route_set_vec = NULL;
9df78e7c 3104
8619629a
DS
3105 /*
3106 * All protocols are setting these to NULL
3107 * by default on shutdown( route_map_finish )
3108 * Why are we making them do this work?
3109 */
3110 route_map_master.add_hook = NULL;
3111 route_map_master.delete_hook = NULL;
3112 route_map_master.event_hook = NULL;
3113
d62a17ae 3114 /* cleanup route_map */
3115 while (route_map_master.head) {
3116 struct route_map *map = route_map_master.head;
e4694d0d 3117 map->to_be_processed = false;
d62a17ae 3118 route_map_delete(map);
3119 }
9df78e7c 3120
d62a17ae 3121 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
3122 hash_free(route_map_dep_hash[i]);
3123 route_map_dep_hash[i] = NULL;
3124 }
9df78e7c 3125
d62a17ae 3126 hash_free(route_map_master_hash);
3127 route_map_master_hash = NULL;
9df78e7c
DS
3128}
3129
4a2a09d0 3130/* Increment the use_count counter while attaching the route map */
3131void route_map_counter_increment(struct route_map *map)
3132{
3133 if (map)
3134 map->use_count++;
3135}
3136
3137/* Decrement the use_count counter while detaching the route map. */
3138void route_map_counter_decrement(struct route_map *map)
3139{
3140 if (map) {
3141 if (map->use_count <= 0)
3142 return;
3143 map->use_count--;
3144 }
3145}
3146
2d26f094
NT
3147DEFUN_HIDDEN(show_route_map_pfx_tbl, show_route_map_pfx_tbl_cmd,
3148 "show route-map WORD prefix-table",
3149 SHOW_STR
3150 "route-map\n"
3151 "route-map name\n"
3152 "internal prefix-table\n")
3153{
3154 const char *rmap_name = argv[2]->arg;
3155 struct route_map *rmap = NULL;
3156 struct route_table *rm_pfx_tbl4 = NULL;
3157 struct route_table *rm_pfx_tbl6 = NULL;
3158 struct route_node *rn = NULL, *prn = NULL;
3159 struct list *rmap_index_list = NULL;
3160 struct listnode *ln = NULL, *nln = NULL;
3161 struct route_map_index *index = NULL;
2d26f094
NT
3162 uint8_t len = 54;
3163
3164 vty_out(vty, "%s:\n", frr_protonameinst);
3165 rmap = route_map_lookup_by_name(rmap_name);
3166 if (rmap) {
3167 rm_pfx_tbl4 = rmap->ipv4_prefix_table;
3168 if (rm_pfx_tbl4) {
3169 vty_out(vty, "\n%s%43s%s\n", "IPv4 Prefix", "",
3170 "Route-map Index List");
3171 vty_out(vty, "%s%39s%s\n", "_______________", "",
3172 "____________________");
3173 for (rn = route_top(rm_pfx_tbl4); rn;
3174 rn = route_next(rn)) {
b219dda1 3175 vty_out(vty, " %pRN (%d)\n", rn,
c10e14e9 3176 route_node_get_lock_count(rn));
2d26f094
NT
3177
3178 vty_out(vty, "(P) ");
3179 prn = rn->parent;
3180 if (prn) {
b219dda1 3181 vty_out(vty, "%pRN\n", prn);
2d26f094
NT
3182 }
3183
3184 vty_out(vty, "\n");
3185 rmap_index_list = (struct list *)rn->info;
3186 if (!rmap_index_list
3187 || !listcount(rmap_index_list))
3188 vty_out(vty, "%*s%s\n", len, "", "-");
3189 else
3190 for (ALL_LIST_ELEMENTS(rmap_index_list,
3191 ln, nln,
3192 index)) {
3193 vty_out(vty, "%*s%s seq %d\n",
3194 len, "",
3195 index->map->name,
3196 index->pref);
3197 }
3198 vty_out(vty, "\n");
3199 }
3200 }
3201
3202 rm_pfx_tbl6 = rmap->ipv6_prefix_table;
3203 if (rm_pfx_tbl6) {
3204 vty_out(vty, "\n%s%43s%s\n", "IPv6 Prefix", "",
3205 "Route-map Index List");
3206 vty_out(vty, "%s%39s%s\n", "_______________", "",
3207 "____________________");
3208 for (rn = route_top(rm_pfx_tbl6); rn;
3209 rn = route_next(rn)) {
b219dda1 3210 vty_out(vty, " %pRN (%d)\n", rn,
c10e14e9 3211 route_node_get_lock_count(rn));
2d26f094
NT
3212
3213 vty_out(vty, "(P) ");
3214 prn = rn->parent;
3215 if (prn) {
b219dda1 3216 vty_out(vty, "%pRN\n", prn);
2d26f094
NT
3217 }
3218
3219 vty_out(vty, "\n");
3220 rmap_index_list = (struct list *)rn->info;
3221 if (!rmap_index_list
3222 || !listcount(rmap_index_list))
3223 vty_out(vty, "%*s%s\n", len, "", "-");
3224 else
3225 for (ALL_LIST_ELEMENTS(rmap_index_list,
3226 ln, nln,
3227 index)) {
3228 vty_out(vty, "%*s%s seq %d\n",
3229 len, "",
3230 index->map->name,
3231 index->pref);
3232 }
3233 vty_out(vty, "\n");
3234 }
3235 }
3236 }
3237
3238 vty_out(vty, "\n");
3239 return CMD_SUCCESS;
3240}
3241
718e3744 3242/* Initialization of route map vector. */
d62a17ae 3243void route_map_init(void)
718e3744 3244{
d62a17ae 3245 int i;
3246
3247 /* Make vector for match and set. */
3248 route_match_vec = vector_init(1);
3249 route_set_vec = vector_init(1);
3250 route_map_master_hash =
996c9314 3251 hash_create_size(8, route_map_hash_key_make, route_map_hash_cmp,
bd74dc61 3252 "Route Map Master Hash");
d62a17ae 3253
3254 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
996c9314
LB
3255 route_map_dep_hash[i] = hash_create_size(
3256 8, route_map_dep_hash_make_key, route_map_dep_hash_cmp,
3257 "Route Map Dep Hash");
b2575bc0 3258
e3ab8170
AD
3259 rmap_debug = false;
3260
2b3e4807 3261 route_map_cli_init();
518f0eb1 3262
2b3e4807 3263 /* Install route map top node. */
612c2c15 3264 install_node(&rmap_debug_node);
e3ab8170 3265
d62a17ae 3266 /* Install route map commands. */
e3ab8170
AD
3267 install_element(CONFIG_NODE, &debug_rmap_cmd);
3268 install_element(CONFIG_NODE, &no_debug_rmap_cmd);
3269
d62a17ae 3270 /* Install show command */
1fa30509
DS
3271 install_element(ENABLE_NODE, &rmap_clear_counters_cmd);
3272
d62a17ae 3273 install_element(ENABLE_NODE, &rmap_show_name_cmd);
4a2a09d0 3274 install_element(ENABLE_NODE, &rmap_show_unused_cmd);
82f97584 3275
e3ab8170
AD
3276 install_element(ENABLE_NODE, &debug_rmap_cmd);
3277 install_element(ENABLE_NODE, &no_debug_rmap_cmd);
49a08bb0
NT
3278
3279 install_element(RMAP_NODE, &routemap_optimization_cmd);
3280 install_element(RMAP_NODE, &no_routemap_optimization_cmd);
2d26f094 3281
31f937fb
SM
3282 install_element(RMAP_NODE, &set_srte_color_cmd);
3283 install_element(RMAP_NODE, &no_set_srte_color_cmd);
3284
2d26f094 3285 install_element(ENABLE_NODE, &show_route_map_pfx_tbl_cmd);
718e3744 3286}