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