]> git.proxmox.com Git - mirror_frr.git/blame - lib/routemap.c
bgpd: update routemap scripting example
[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,
1782514f 1533 const struct prefix *prefix, void *object)
b68885f9
LK
1534{
1535 enum route_map_cmd_result_t ret = RMAP_NOMATCH;
1536 struct route_map_rule *match;
1537 bool is_matched = false;
1538
1539
1540 /* Check all match rule and if there is no match rule, go to the
1541 set statement. */
1542 if (!match_list->head)
1543 ret = RMAP_MATCH;
1544 else {
1545 for (match = match_list->head; match; match = match->next) {
1546 /*
1547 * Try each match statement. If any match does not
1548 * return RMAP_MATCH or RMAP_NOOP, return.
1549 * Otherwise continue on to next match statement.
1550 * All match statements must MATCH for
1551 * end-result to be a match.
1552 * (Exception:If match stmts result in a mix of
1553 * MATCH/NOOP, then also end-result is a match)
1554 * If all result in NOOP, end-result is NOOP.
1555 */
1556 ret = (*match->cmd->func_apply)(match->value, prefix,
1782514f 1557 object);
b68885f9
LK
1558
1559 /*
1560 * If the consolidated result of func_apply is:
1561 * -----------------------------------------------
1562 * | MATCH | NOMATCH | NOOP | Final Result |
1563 * ------------------------------------------------
1564 * | yes | yes | yes | NOMATCH |
1565 * | no | no | yes | NOOP |
1566 * | yes | no | yes | MATCH |
1567 * | no | yes | yes | NOMATCH |
1568 * |-----------------------------------------------
1569 *
1570 * Traditionally, all rules within route-map
1571 * should match for it to MATCH.
1572 * If there are noops within the route-map rules,
1573 * it follows the above matrix.
1574 *
1575 * Eg: route-map rm1 permit 10
1576 * match rule1
1577 * match rule2
1578 * match rule3
1579 * ....
1580 * route-map rm1 permit 20
1581 * match ruleX
1582 * match ruleY
1583 * ...
1584 */
1585
1586 switch (ret) {
1587 case RMAP_MATCH:
1588 is_matched = true;
1589 break;
1590
1591 case RMAP_NOMATCH:
1592 return ret;
1593
1594 case RMAP_NOOP:
1595 if (is_matched)
1596 ret = RMAP_MATCH;
1597 break;
1598
1599 default:
1600 break;
1601 }
1602
1603 }
1604 }
1605 return ret;
1606}
1607
2d26f094
NT
1608static struct list *route_map_get_index_list(struct route_node **rn,
1609 const struct prefix *prefix,
1610 struct route_table *table)
819a23f9
NT
1611{
1612 struct route_node *tmp_rn = NULL;
1613
1614 if (!(*rn)) {
1615 *rn = route_node_match(table, prefix);
1616
1617 if (!(*rn))
1618 return NULL;
1619
1620 if ((*rn)->info)
1621 return (struct list *)((*rn)->info);
1622
1623 /* If rn->info is NULL, get the parent.
1624 * Store the rn in tmp_rn and unlock it later.
1625 */
1626 tmp_rn = *rn;
1627 }
1628
1629 do {
1630 *rn = (*rn)->parent;
1631 if (tmp_rn)
1632 route_unlock_node(tmp_rn);
1633
1634 if (!(*rn))
1635 break;
1636
1637 if ((*rn)->info) {
1638 route_lock_node(*rn);
1639 return (struct list *)((*rn)->info);
1640 }
1641 } while (!(*rn)->info);
1642
1643 return NULL;
1644}
1645
1646/*
1647 * This function returns the route-map index that best matches the prefix.
1648 */
1782514f
DS
1649static struct route_map_index *route_map_get_index(struct route_map *map,
1650 const struct prefix *prefix,
1651 void *object,
1652 uint8_t *match_ret)
819a23f9
NT
1653{
1654 int ret = 0;
1655 struct list *candidate_rmap_list = NULL;
1656 struct route_node *rn = NULL;
1657 struct listnode *ln = NULL, *nn = NULL;
1658 struct route_map_index *index = NULL, *best_index = NULL;
1659 struct route_map_index *head_index = NULL;
1660 struct route_table *table = NULL;
1661 unsigned char family = prefix->family;
1662
1663 if (family == AF_INET)
1664 table = map->ipv4_prefix_table;
1665 else
1666 table = map->ipv6_prefix_table;
1667
1668 if (!table)
1669 return NULL;
1670
1671 do {
2d26f094
NT
1672 candidate_rmap_list =
1673 route_map_get_index_list(&rn, prefix, table);
819a23f9
NT
1674 if (!rn)
1675 break;
1676
1677 /* If the index at the head of the list is of seq higher
1678 * than that in best_index, ignore the list and get the
1679 * parent node's list.
1680 */
2d26f094
NT
1681 head_index = (struct route_map_index *)(listgetdata(
1682 listhead(candidate_rmap_list)));
1683 if (best_index && head_index
1684 && (best_index->pref < head_index->pref)) {
819a23f9
NT
1685 route_unlock_node(rn);
1686 continue;
1687 }
1688
1689 for (ALL_LIST_ELEMENTS(candidate_rmap_list, ln, nn, index)) {
1690 /* If the index is of seq higher than that in
1691 * best_index, ignore the list and get the parent
1692 * node's list.
1693 */
1694 if (best_index && (best_index->pref < index->pref))
1695 break;
1696
2d26f094 1697 ret = route_map_apply_match(&index->match_list, prefix,
1782514f 1698 object);
819a23f9
NT
1699
1700 if (ret == RMAP_MATCH) {
1701 *match_ret = ret;
1702 best_index = index;
1703 break;
1704 } else if (ret == RMAP_NOOP) {
1705 /*
1706 * If match_ret is denymatch, even if we see
1707 * more noops, we retain this return value and
1708 * return this eventually if there are no
1709 * matches.
1410dd3f
NT
1710 * If a best match route-map index already
1711 * exists, do not reset the match_ret.
819a23f9 1712 */
1410dd3f 1713 if (!best_index && (*match_ret != RMAP_NOMATCH))
819a23f9
NT
1714 *match_ret = ret;
1715 } else {
1716 /*
1717 * ret is RMAP_NOMATCH.
1410dd3f
NT
1718 * If a best match route-map index already
1719 * exists, do not reset the match_ret.
819a23f9 1720 */
1410dd3f
NT
1721 if (!best_index)
1722 *match_ret = ret;
819a23f9
NT
1723 }
1724 }
1725
1726 route_unlock_node(rn);
1727
1728 } while (rn);
1729
1730 return best_index;
1731}
1732
2d26f094
NT
1733static int route_map_candidate_list_cmp(struct route_map_index *idx1,
1734 struct route_map_index *idx2)
49a08bb0
NT
1735{
1736 if (!idx1)
1737 return -1;
1738 if (!idx2)
1739 return 1;
1740
1741 return (idx1->pref - idx2->pref);
1742}
1743
1744/*
1745 * This function adds the route-map index into the default route's
1746 * route-node in the route-map's IPv4/IPv6 prefix-table.
1747 */
2d26f094
NT
1748static void route_map_pfx_table_add_default(afi_t afi,
1749 struct route_map_index *index)
49a08bb0
NT
1750{
1751 struct route_node *rn = NULL;
1752 struct list *rmap_candidate_list = NULL;
1753 struct prefix p;
1754 bool updated_rn = false;
1755 struct route_table *table = NULL;
1756
1757 memset(&p, 0, sizeof(p));
1758 p.family = afi2family(afi);
1759 p.prefixlen = 0;
1760
1761 if (p.family == AF_INET) {
1762 table = index->map->ipv4_prefix_table;
1763 if (!table)
1764 index->map->ipv4_prefix_table = route_table_init();
1765
1766 table = index->map->ipv4_prefix_table;
1767 } else {
1768 table = index->map->ipv6_prefix_table;
1769 if (!table)
1770 index->map->ipv6_prefix_table = route_table_init();
1771
1772 table = index->map->ipv6_prefix_table;
1773 }
1774
1775 /* Add default route to table */
1776 rn = route_node_get(table, &p);
1777
1778 if (!rn)
1779 return;
1780
1781 if (!rn->info) {
1782 rmap_candidate_list = list_new();
1783 rmap_candidate_list->cmp =
1784 (int (*)(void *, void *))route_map_candidate_list_cmp;
1785 rn->info = rmap_candidate_list;
1786 } else {
1787 rmap_candidate_list = (struct list *)rn->info;
1788 updated_rn = true;
1789 }
1790
1791 listnode_add_sort_nodup(rmap_candidate_list, index);
1792 if (updated_rn)
1793 route_unlock_node(rn);
1794}
1795
1796/*
1797 * This function removes the route-map index from the default route's
1798 * route-node in the route-map's IPv4/IPv6 prefix-table.
1799 */
2d26f094
NT
1800static void route_map_pfx_table_del_default(afi_t afi,
1801 struct route_map_index *index)
49a08bb0
NT
1802{
1803 struct route_node *rn = NULL;
1804 struct list *rmap_candidate_list = NULL;
1805 struct prefix p;
1806 struct route_table *table = NULL;
1807
1808 memset(&p, 0, sizeof(p));
1809 p.family = afi2family(afi);
1810 p.prefixlen = 0;
1811
1812 if (p.family == AF_INET)
1813 table = index->map->ipv4_prefix_table;
1814 else
1815 table = index->map->ipv6_prefix_table;
1816
1817 /* Remove RMAP index from default route in table */
1818 rn = route_node_lookup(table, &p);
1819 if (!rn || !rn->info)
1820 return;
1821
1822 rmap_candidate_list = (struct list *)rn->info;
1823
1824 listnode_delete(rmap_candidate_list, index);
1825
1826 if (listcount(rmap_candidate_list) == 0) {
1827 list_delete(&rmap_candidate_list);
1828 rn->info = NULL;
1829 route_unlock_node(rn);
1830 }
1831 route_unlock_node(rn);
1832}
1833
1834/*
1835 * This function adds the route-map index to the route-node for
1836 * the prefix-entry in the route-map's IPv4/IPv6 prefix-table.
1837 */
2d26f094
NT
1838static void route_map_pfx_table_add(struct route_table *table,
1839 struct route_map_index *index,
1840 struct prefix_list_entry *pentry)
49a08bb0
NT
1841{
1842 struct route_node *rn = NULL;
1843 struct list *rmap_candidate_list = NULL;
1844 bool updated_rn = false;
1845
1846 rn = route_node_get(table, &pentry->prefix);
1847 if (!rn)
1848 return;
1849
1850 if (!rn->info) {
1851 rmap_candidate_list = list_new();
1852 rmap_candidate_list->cmp =
1853 (int (*)(void *, void *))route_map_candidate_list_cmp;
1854 rn->info = rmap_candidate_list;
1855 } else {
1856 rmap_candidate_list = (struct list *)rn->info;
1857 updated_rn = true;
1858 }
1859
1860 listnode_add_sort_nodup(rmap_candidate_list, index);
1861 if (updated_rn)
1862 route_unlock_node(rn);
1863}
1864
1865/*
1866 * This function removes the route-map index from the route-node for
1867 * the prefix-entry in the route-map's IPv4/IPv6 prefix-table.
1868 */
2d26f094
NT
1869static void route_map_pfx_table_del(struct route_table *table,
1870 struct route_map_index *index,
1871 struct prefix_list_entry *pentry)
49a08bb0
NT
1872{
1873 struct route_node *rn = NULL;
1874 struct list *rmap_candidate_list = NULL;
1875
1876 rn = route_node_lookup(table, &pentry->prefix);
1877 if (!rn || !rn->info)
1878 return;
1879
1880 rmap_candidate_list = (struct list *)rn->info;
1881
1882 listnode_delete(rmap_candidate_list, index);
1883
1884 if (listcount(rmap_candidate_list) == 0) {
1885 list_delete(&rmap_candidate_list);
1886 rn->info = NULL;
1887 route_unlock_node(rn);
1888 }
1889 route_unlock_node(rn);
1890}
1891
3eca8715
NT
1892/* This function checks for the presence of an IPv4 prefix-list
1893 * match rule in the given route-map index.
49a08bb0 1894 */
3eca8715 1895static bool route_map_is_ip_pfx_list_rule_present(struct route_map_index *index)
49a08bb0
NT
1896{
1897 struct route_map_rule_list *match_list = NULL;
1898 struct route_map_rule *rule = NULL;
1899
1900 match_list = &index->match_list;
1901 for (rule = match_list->head; rule; rule = rule->next)
3eca8715 1902 if (IS_RULE_IPv4_PREFIX_LIST(rule->cmd->str))
49a08bb0
NT
1903 return true;
1904
1905 return false;
1906}
1907
3eca8715
NT
1908/* This function checks for the presence of an IPv6 prefix-list
1909 * match rule in the given route-map index.
49a08bb0 1910 */
3eca8715
NT
1911static bool
1912route_map_is_ipv6_pfx_list_rule_present(struct route_map_index *index)
49a08bb0
NT
1913{
1914 struct route_map_rule_list *match_list = NULL;
1915 struct route_map_rule *rule = NULL;
1916
1917 match_list = &index->match_list;
1918 for (rule = match_list->head; rule; rule = rule->next)
3eca8715 1919 if (IS_RULE_IPv6_PREFIX_LIST(rule->cmd->str))
49a08bb0
NT
1920 return true;
1921
1922 return false;
1923}
1924
1925/* This function does the following:
1926 * 1) If plist_name is not present, search for a IPv4 or IPv6 prefix-list
1927 * match clause (based on the afi passed to this foo) and get the
1928 * prefix-list name.
1929 * 2) Look up the prefix-list using the name.
1930 * 3) If the prefix-list is not found then, add the index to the IPv4/IPv6
1931 * default-route's node in the trie (based on the afi passed to this foo).
1932 * 4) If the prefix-list is found then, remove the index from the IPv4/IPv6
1933 * default-route's node in the trie (based on the afi passed to this foo).
1934 * 5) If a prefix-entry is passed then, create a route-node for this entry and
1935 * add this index to the route-node.
1936 * 6) If prefix-entry is not passed then, for every prefix-entry in the
1937 * prefix-list, create a route-node for this entry and
1938 * add this index to the route-node.
1939 */
2d26f094
NT
1940static void route_map_add_plist_entries(afi_t afi,
1941 struct route_map_index *index,
1942 const char *plist_name,
1943 struct prefix_list_entry *entry)
49a08bb0
NT
1944{
1945 struct route_map_rule_list *match_list = NULL;
1946 struct route_map_rule *match = NULL;
1947 struct prefix_list *plist = NULL;
1948 struct prefix_list_entry *pentry = NULL;
1949 bool plist_rule_is_present = false;
1950
1951 if (!plist_name) {
1952 match_list = &index->match_list;
1953
1954 for (match = match_list->head; match; match = match->next) {
819a23f9 1955 if (afi == AFI_IP) {
2d26f094 1956 if (IS_RULE_IPv4_PREFIX_LIST(match->cmd->str)) {
819a23f9
NT
1957 plist_rule_is_present = true;
1958 break;
2d26f094 1959 }
819a23f9 1960 } else {
2d26f094 1961 if (IS_RULE_IPv6_PREFIX_LIST(match->cmd->str)) {
819a23f9
NT
1962 plist_rule_is_present = true;
1963 break;
2d26f094 1964 }
49a08bb0
NT
1965 }
1966 }
1967
1968 if (plist_rule_is_present)
1969 plist = prefix_list_lookup(afi, match->rule_str);
1970 } else {
1971 plist = prefix_list_lookup(afi, plist_name);
1972 }
1973
1974 if (!plist) {
1975 route_map_pfx_table_add_default(afi, index);
1976 return;
1977 }
1978
1979 route_map_pfx_table_del_default(afi, index);
1980
1981 if (entry) {
1982 if (afi == AFI_IP) {
2d26f094
NT
1983 route_map_pfx_table_add(index->map->ipv4_prefix_table,
1984 index, entry);
49a08bb0 1985 } else {
2d26f094
NT
1986 route_map_pfx_table_add(index->map->ipv6_prefix_table,
1987 index, entry);
49a08bb0
NT
1988 }
1989 } else {
1990 for (pentry = plist->head; pentry; pentry = pentry->next) {
1991 if (afi == AFI_IP) {
1992 route_map_pfx_table_add(
2d26f094
NT
1993 index->map->ipv4_prefix_table, index,
1994 pentry);
49a08bb0
NT
1995 } else {
1996 route_map_pfx_table_add(
2d26f094
NT
1997 index->map->ipv6_prefix_table, index,
1998 pentry);
49a08bb0
NT
1999 }
2000 }
2001 }
2002}
2003
2004/* This function does the following:
2005 * 1) If plist_name is not present, search for a IPv4 or IPv6 prefix-list
2006 * match clause (based on the afi passed to this foo) and get the
2007 * prefix-list name.
2008 * 2) Look up the prefix-list using the name.
2009 * 3) If the prefix-list is not found then, delete the index from the IPv4/IPv6
2010 * default-route's node in the trie (based on the afi passed to this foo).
2011 * 4) If a prefix-entry is passed then, remove this index from the route-node
2012 * for the prefix in this prefix-entry.
2013 * 5) If prefix-entry is not passed then, for every prefix-entry in the
2014 * prefix-list, remove this index from the route-node
2015 * for the prefix in this prefix-entry.
2016 */
2d26f094
NT
2017static void route_map_del_plist_entries(afi_t afi,
2018 struct route_map_index *index,
2019 const char *plist_name,
2020 struct prefix_list_entry *entry)
49a08bb0
NT
2021{
2022 struct route_map_rule_list *match_list = NULL;
2023 struct route_map_rule *match = NULL;
2024 struct prefix_list *plist = NULL;
2025 struct prefix_list_entry *pentry = NULL;
2026 bool plist_rule_is_present = false;
2027
2028 if (!plist_name) {
2029 match_list = &index->match_list;
2030
2031 for (match = match_list->head; match; match = match->next) {
819a23f9 2032 if (afi == AFI_IP) {
2d26f094 2033 if (IS_RULE_IPv4_PREFIX_LIST(match->cmd->str)) {
819a23f9
NT
2034 plist_rule_is_present = true;
2035 break;
2d26f094 2036 }
819a23f9 2037 } else {
2d26f094 2038 if (IS_RULE_IPv6_PREFIX_LIST(match->cmd->str)) {
819a23f9
NT
2039 plist_rule_is_present = true;
2040 break;
2d26f094 2041 }
49a08bb0
NT
2042 }
2043 }
2044
2045 if (plist_rule_is_present)
2046 plist = prefix_list_lookup(afi, match->rule_str);
2047 } else {
2048 plist = prefix_list_lookup(afi, plist_name);
2049 }
2050
2051 if (!plist) {
2052 route_map_pfx_table_del_default(afi, index);
2053 return;
2054 }
2055
2056 if (entry) {
2057 if (afi == AFI_IP) {
2d26f094
NT
2058 route_map_pfx_table_del(index->map->ipv4_prefix_table,
2059 index, entry);
49a08bb0 2060 } else {
2d26f094
NT
2061 route_map_pfx_table_del(index->map->ipv6_prefix_table,
2062 index, entry);
49a08bb0
NT
2063 }
2064 } else {
2065 for (pentry = plist->head; pentry; pentry = pentry->next) {
2066 if (afi == AFI_IP) {
2067 route_map_pfx_table_del(
2d26f094
NT
2068 index->map->ipv4_prefix_table, index,
2069 pentry);
49a08bb0
NT
2070 } else {
2071 route_map_pfx_table_del(
2d26f094
NT
2072 index->map->ipv6_prefix_table, index,
2073 pentry);
49a08bb0
NT
2074 }
2075 }
2076 }
2077}
2078
2079/*
2080 * This function handles the cases where a prefix-list is added/removed
2081 * as a match command from a particular route-map index.
2082 * It updates the prefix-table of the route-map accordingly.
2083 */
2d26f094
NT
2084static void route_map_trie_update(afi_t afi, route_map_event_t event,
2085 struct route_map_index *index,
2086 const char *plist_name)
49a08bb0
NT
2087{
2088 if (event == RMAP_EVENT_PLIST_ADDED) {
2089 if (afi == AFI_IP) {
3eca8715 2090 if (!route_map_is_ipv6_pfx_list_rule_present(index)) {
2d26f094 2091 route_map_pfx_table_del_default(AFI_IP6, index);
49a08bb0
NT
2092 route_map_add_plist_entries(afi, index,
2093 plist_name, NULL);
2094 } else {
2095 route_map_del_plist_entries(AFI_IP6, index,
2096 NULL, NULL);
2097 }
2098 } else {
3eca8715 2099 if (!route_map_is_ip_pfx_list_rule_present(index)) {
2d26f094 2100 route_map_pfx_table_del_default(AFI_IP, index);
49a08bb0
NT
2101 route_map_add_plist_entries(afi, index,
2102 plist_name, NULL);
2103 } else {
2d26f094
NT
2104 route_map_del_plist_entries(AFI_IP, index, NULL,
2105 NULL);
49a08bb0
NT
2106 }
2107 }
2108 } else if (event == RMAP_EVENT_PLIST_DELETED) {
2109 if (afi == AFI_IP) {
2d26f094
NT
2110 route_map_del_plist_entries(afi, index, plist_name,
2111 NULL);
49a08bb0 2112
3eca8715
NT
2113 /* If IPv6 prefix-list match rule is not present,
2114 * add this index to the IPv4 default route's trie
2115 * node.
2116 * Also, add this index to the trie nodes created
2117 * for each of the prefix-entries within the IPv6
2118 * prefix-list, if the IPv6 prefix-list match rule
2119 * is present. Else, add this index to the IPv6
2120 * default route's trie node.
2121 */
2122 if (!route_map_is_ipv6_pfx_list_rule_present(index))
49a08bb0
NT
2123 route_map_pfx_table_add_default(afi, index);
2124
3eca8715 2125 route_map_add_plist_entries(AFI_IP6, index, NULL, NULL);
49a08bb0 2126 } else {
2d26f094
NT
2127 route_map_del_plist_entries(afi, index, plist_name,
2128 NULL);
49a08bb0 2129
3eca8715
NT
2130 /* If IPv4 prefix-list match rule is not present,
2131 * add this index to the IPv6 default route's trie
2132 * node.
2133 * Also, add this index to the trie nodes created
2134 * for each of the prefix-entries within the IPv4
2135 * prefix-list, if the IPv4 prefix-list match rule
2136 * is present. Else, add this index to the IPv4
2137 * default route's trie node.
2138 */
2139 if (!route_map_is_ip_pfx_list_rule_present(index))
49a08bb0
NT
2140 route_map_pfx_table_add_default(afi, index);
2141
3eca8715 2142 route_map_add_plist_entries(AFI_IP, index, NULL, NULL);
49a08bb0
NT
2143 }
2144 }
2145}
2146
2147/*
2148 * This function handles the cases where a route-map index and
2149 * prefix-list is added/removed.
2150 * It updates the prefix-table of the route-map accordingly.
2151 */
2d26f094
NT
2152static void route_map_pfx_tbl_update(route_map_event_t event,
2153 struct route_map_index *index, afi_t afi,
2154 const char *plist_name)
49a08bb0
NT
2155{
2156 struct route_map *rmap = NULL;
2157
2158 if (!index)
2159 return;
2160
2161 if (event == RMAP_EVENT_INDEX_ADDED) {
2162 route_map_pfx_table_add_default(AFI_IP, index);
2163 route_map_pfx_table_add_default(AFI_IP6, index);
2164 return;
2165 }
2166
2167 if (event == RMAP_EVENT_INDEX_DELETED) {
2168 route_map_pfx_table_del_default(AFI_IP, index);
2169 route_map_pfx_table_del_default(AFI_IP6, index);
2170
2d26f094 2171 if ((index->map->head == NULL) && (index->map->tail == NULL)) {
49a08bb0
NT
2172 rmap = index->map;
2173
2174 if (rmap->ipv4_prefix_table) {
2175 route_table_finish(rmap->ipv4_prefix_table);
2176 rmap->ipv4_prefix_table = NULL;
2177 }
2178
2179 if (rmap->ipv6_prefix_table) {
2180 route_table_finish(rmap->ipv6_prefix_table);
2181 rmap->ipv6_prefix_table = NULL;
2182 }
2183 }
2184 return;
2185 }
2186
2187 /* Handle prefix-list match rule addition/deletion.
2188 */
2d26f094 2189 route_map_trie_update(afi, event, index, plist_name);
49a08bb0
NT
2190}
2191
2192/*
2193 * This function handles the cases where a new prefix-entry is added to
2194 * a prefix-list or, an existing prefix-entry is removed from the prefix-list.
2195 * It updates the prefix-table of the route-map accordingly.
2196 */
2d26f094
NT
2197static void route_map_pentry_update(route_map_event_t event,
2198 const char *plist_name,
2199 struct route_map_index *index,
2200 struct prefix_list_entry *pentry)
49a08bb0
NT
2201{
2202 struct prefix_list *plist = NULL;
2203 afi_t afi;
2204 unsigned char family = pentry->prefix.family;
2205
2206 if (family == AF_INET) {
2207 afi = AFI_IP;
2208 plist = prefix_list_lookup(AFI_IP, plist_name);
2209 } else {
2210 afi = AFI_IP6;
2211 plist = prefix_list_lookup(AFI_IP6, plist_name);
2212 }
2213
2214 if (event == RMAP_EVENT_PLIST_ADDED) {
3eca8715
NT
2215 if (afi == AFI_IP) {
2216 if (!route_map_is_ipv6_pfx_list_rule_present(index))
2217 route_map_add_plist_entries(afi, index,
2218 plist_name, pentry);
49a08bb0 2219 } else {
3eca8715
NT
2220 if (!route_map_is_ip_pfx_list_rule_present(index))
2221 route_map_add_plist_entries(afi, index,
2222 plist_name, pentry);
49a08bb0
NT
2223 }
2224 } else if (event == RMAP_EVENT_PLIST_DELETED) {
2225 route_map_del_plist_entries(afi, index, plist_name, pentry);
2226
2227 if (plist->count == 1) {
2228 if (afi == AFI_IP) {
3eca8715
NT
2229 if (!route_map_is_ipv6_pfx_list_rule_present(
2230 index))
49a08bb0
NT
2231 route_map_pfx_table_add_default(afi,
2232 index);
2233 } else {
3eca8715
NT
2234 if (!route_map_is_ip_pfx_list_rule_present(
2235 index))
49a08bb0
NT
2236 route_map_pfx_table_add_default(afi,
2237 index);
2238 }
2239 }
2240 }
2241}
2242
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 2371route_map_result_t route_map_apply(struct route_map *map,
1782514f 2372 const struct prefix *prefix, void *object)
d62a17ae 2373{
2374 static int recursion = 0;
b68885f9
LK
2375 enum route_map_cmd_result_t match_ret = RMAP_NOMATCH;
2376 route_map_result_t ret = RMAP_PERMITMATCH;
819a23f9
NT
2377 struct route_map_index *index = NULL;
2378 struct route_map_rule *set = NULL;
819a23f9 2379 bool skip_match_clause = false;
d62a17ae 2380
2381 if (recursion > RMAP_RECURSION_LIMIT) {
040c7c3a 2382 flog_warn(
450971aa 2383 EC_LIB_RMAP_RECURSION_LIMIT,
d62a17ae 2384 "route-map recursion limit (%d) reached, discarding route",
2385 RMAP_RECURSION_LIMIT);
2386 recursion = 0;
2387 return RMAP_DENYMATCH;
2388 }
2389
b68885f9 2390 if (map == NULL || map->head == NULL) {
e3ab8170
AD
2391 ret = RMAP_DENYMATCH;
2392 goto route_map_apply_end;
2393 }
d62a17ae 2394
279b0607 2395 map->applied++;
819a23f9 2396
2d26f094
NT
2397 if ((!map->optimization_disabled)
2398 && (map->ipv4_prefix_table || map->ipv6_prefix_table)) {
1782514f 2399 index = route_map_get_index(map, prefix, object,
819a23f9
NT
2400 (uint8_t *)&match_ret);
2401 if (index) {
2402 if (rmap_debug)
2403 zlog_debug(
2dbe669b
DA
2404 "Best match route-map: %s, sequence: %d for pfx: %pFX, result: %s",
2405 map->name, index->pref, prefix,
819a23f9
NT
2406 route_map_cmd_result_str(match_ret));
2407 } else {
2408 if (rmap_debug)
2d26f094 2409 zlog_debug(
2dbe669b
DA
2410 "No best match sequence for pfx: %pFX in route-map: %s, result: %s",
2411 prefix, map->name,
2d26f094 2412 route_map_cmd_result_str(match_ret));
819a23f9
NT
2413 /*
2414 * No index matches this prefix. Return deny unless,
2415 * match_ret = RMAP_NOOP.
2416 */
2417 if (match_ret == RMAP_NOOP)
2418 ret = RMAP_PERMITMATCH;
2419 else
2420 ret = RMAP_DENYMATCH;
2421 goto route_map_apply_end;
e3ab8170 2422 }
819a23f9
NT
2423 skip_match_clause = true;
2424 } else {
2425 index = map->head;
2426 }
2427
2428 for (; index; index = index->next) {
a8f58eb6 2429 if (!skip_match_clause) {
00aef028 2430 index->applied++;
819a23f9
NT
2431 /* Apply this index. */
2432 match_ret = route_map_apply_match(&index->match_list,
1782514f 2433 prefix, object);
819a23f9
NT
2434 if (rmap_debug) {
2435 zlog_debug(
2dbe669b
DA
2436 "Route-map: %s, sequence: %d, prefix: %pFX, result: %s",
2437 map->name, index->pref, prefix,
819a23f9
NT
2438 route_map_cmd_result_str(match_ret));
2439 }
2440 } else
2441 skip_match_clause = false;
2442
e3ab8170 2443
d62a17ae 2444 /* Now we apply the matrix from above */
b68885f9
LK
2445 if (match_ret == RMAP_NOOP)
2446 /*
2447 * Do not change the return value. Retain the previous
2448 * return value. Previous values can be:
2449 * 1)permitmatch (if a nomatch was never
2450 * seen before in this route-map.)
2451 * 2)denymatch (if a nomatch was seen earlier in one
2452 * of the previous sequences)
2453 */
2454
2455 /*
2456 * 'cont' from matrix - continue to next route-map
2457 * sequence
2458 */
d62a17ae 2459 continue;
b68885f9
LK
2460 else if (match_ret == RMAP_NOMATCH) {
2461
2462 /*
2463 * The return value is now changed to denymatch.
2464 * So from here on out, even if we see more noops,
2465 * we retain this return value and return this
2466 * eventually if there are no matches.
2467 */
2468 ret = RMAP_DENYMATCH;
2469
2470 /*
2471 * 'cont' from matrix - continue to next route-map
2472 * sequence
2473 */
2474 continue;
2475 } else if (match_ret == RMAP_MATCH) {
d62a17ae 2476 if (index->type == RMAP_PERMIT)
2477 /* 'action' */
2478 {
b68885f9
LK
2479 /* Match succeeded, rmap is of type permit */
2480 ret = RMAP_PERMITMATCH;
2481
d62a17ae 2482 /* permit+match must execute sets */
2483 for (set = index->set_list.head; set;
2484 set = set->next)
b68885f9
LK
2485 /*
2486 * set cmds return RMAP_OKAY or
2487 * RMAP_ERROR. We do not care if
2488 * set succeeded or not. So, ignore
2489 * return code.
2490 */
1782514f
DS
2491 (void)(*set->cmd->func_apply)(
2492 set->value, prefix, object);
d62a17ae 2493
2494 /* Call another route-map if available */
2495 if (index->nextrm) {
2496 struct route_map *nextrm =
2497 route_map_lookup_by_name(
2498 index->nextrm);
2499
2500 if (nextrm) /* Target route-map found,
2501 jump to it */
2502 {
2503 recursion++;
2504 ret = route_map_apply(
1782514f 2505 nextrm, prefix, object);
d62a17ae 2506 recursion--;
2507 }
2508
2509 /* If nextrm returned 'deny', finish. */
2510 if (ret == RMAP_DENYMATCH)
e3ab8170 2511 goto route_map_apply_end;
d62a17ae 2512 }
2513
2514 switch (index->exitpolicy) {
2515 case RMAP_EXIT:
e3ab8170 2516 goto route_map_apply_end;
d62a17ae 2517 case RMAP_NEXT:
2518 continue;
2519 case RMAP_GOTO: {
2520 /* Find the next clause to jump to */
2521 struct route_map_index *next =
2522 index->next;
2523 int nextpref = index->nextpref;
2524
2525 while (next && next->pref < nextpref) {
2526 index = next;
2527 next = next->next;
2528 }
2529 if (next == NULL) {
2530 /* No clauses match! */
e3ab8170 2531 goto route_map_apply_end;
d62a17ae 2532 }
2533 }
2534 }
2535 } else if (index->type == RMAP_DENY)
2536 /* 'deny' */
2537 {
e3ab8170
AD
2538 ret = RMAP_DENYMATCH;
2539 goto route_map_apply_end;
d62a17ae 2540 }
2541 }
2542 }
e3ab8170
AD
2543
2544route_map_apply_end:
2dbe669b
DA
2545 if (rmap_debug)
2546 zlog_debug("Route-map: %s, prefix: %pFX, result: %s",
2547 (map ? map->name : "null"), prefix,
e3ab8170 2548 route_map_result_str(ret));
e3ab8170
AD
2549
2550 return (ret);
d62a17ae 2551}
2552
2553void route_map_add_hook(void (*func)(const char *))
2554{
2555 route_map_master.add_hook = func;
2556}
2557
2558void route_map_delete_hook(void (*func)(const char *))
2559{
2560 route_map_master.delete_hook = func;
2561}
2562
097b5973 2563void route_map_event_hook(void (*func)(const char *name))
d62a17ae 2564{
2565 route_map_master.event_hook = func;
718e3744 2566}
2567
518f0eb1 2568/* Routines for route map dependency lists and dependency processing */
74df8d6d 2569static bool route_map_rmap_hash_cmp(const void *p1, const void *p2)
518f0eb1 2570{
e2c8d6ce
NT
2571 return strcmp(((const struct route_map_dep_data *)p1)->rname,
2572 ((const struct route_map_dep_data *)p2)->rname)
2573 == 0;
518f0eb1
DS
2574}
2575
74df8d6d 2576static bool route_map_dep_hash_cmp(const void *p1, const void *p2)
518f0eb1
DS
2577{
2578
d62a17ae 2579 return (strcmp(((const struct route_map_dep *)p1)->dep_name,
2580 (const char *)p2)
2581 == 0);
518f0eb1
DS
2582}
2583
e3b78da8 2584static void route_map_clear_reference(struct hash_bucket *bucket, void *arg)
518f0eb1 2585{
e2c8d6ce
NT
2586 struct route_map_dep *dep = bucket->data;
2587 struct route_map_dep_data *dep_data = NULL, tmp_dep_data;
518f0eb1 2588
1fae5ff2 2589 if (arg) {
e2c8d6ce
NT
2590 memset(&tmp_dep_data, 0, sizeof(struct route_map_dep_data));
2591 tmp_dep_data.rname = arg;
2592 dep_data = hash_release(dep->dep_rmap_hash,
2593 &tmp_dep_data);
2594 if (dep_data) {
2595 XFREE(MTYPE_ROUTE_MAP_NAME, dep_data->rname);
2596 XFREE(MTYPE_ROUTE_MAP_DEP_DATA, dep_data);
d62a17ae 2597 }
2598 if (!dep->dep_rmap_hash->count) {
2599 dep = hash_release(dep->this_hash,
2600 (void *)dep->dep_name);
2601 hash_free(dep->dep_rmap_hash);
2602 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
2603 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
2604 }
518f0eb1 2605 }
d62a17ae 2606}
2607
2608static void route_map_clear_all_references(char *rmap_name)
2609{
2610 int i;
2611
2612 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
2613 hash_iterate(route_map_dep_hash[i], route_map_clear_reference,
2614 (void *)rmap_name);
518f0eb1 2615 }
518f0eb1
DS
2616}
2617
e2c8d6ce
NT
2618static unsigned int route_map_dep_data_hash_make_key(const void *p)
2619{
2620 const struct route_map_dep_data *dep_data = p;
2621
2622 return string_hash_make(dep_data->rname);
2623}
2624
31f937fb
SM
2625DEFUN (set_srte_color,
2626 set_srte_color_cmd,
2627 "set sr-te color [(1-4294967295)]",
2628 SET_STR
2629 SRTE_STR
2630 SRTE_COLOR_STR
2631 "Color of the SR-TE Policies to match with\n")
2632{
2633 VTY_DECLVAR_CONTEXT(route_map_index, index);
2634 int idx = 0;
2635 char *arg = argv_find(argv, argc, "(1-4294967295)", &idx)
2636 ? argv[idx]->arg
2637 : NULL;
2638
2639 if (rmap_match_set_hook.set_srte_color)
2640 return rmap_match_set_hook.set_srte_color(vty, index,
2641 "sr-te color", arg);
2642 return CMD_SUCCESS;
2643}
2644
2645DEFUN (no_set_srte_color,
2646 no_set_srte_color_cmd,
2647 "no set sr-te color [(1-4294967295)]",
2648 NO_STR
2649 SET_STR
2650 SRTE_STR
2651 SRTE_COLOR_STR
2652 "Color of the SR-TE Policies to match with\n")
2653{
2654 VTY_DECLVAR_CONTEXT(route_map_index, index);
2655 int idx = 0;
2656 char *arg = argv_find(argv, argc, "(1-4294967295)", &idx)
2657 ? argv[idx]->arg
2658 : NULL;
2659
2660 if (rmap_match_set_hook.no_set_srte_color)
2661 return rmap_match_set_hook.no_set_srte_color(
2662 vty, index, "sr-te color", arg);
2663 return CMD_SUCCESS;
2664}
2665
d62a17ae 2666static void *route_map_dep_hash_alloc(void *p)
518f0eb1 2667{
d62a17ae 2668 char *dep_name = (char *)p;
2669 struct route_map_dep *dep_entry;
2670
2671 dep_entry = XCALLOC(MTYPE_ROUTE_MAP_DEP, sizeof(struct route_map_dep));
2672 dep_entry->dep_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
996c9314 2673 dep_entry->dep_rmap_hash =
e2c8d6ce 2674 hash_create_size(8, route_map_dep_data_hash_make_key,
996c9314 2675 route_map_rmap_hash_cmp, "Route Map Dep Hash");
d62a17ae 2676 dep_entry->this_hash = NULL;
2677
e2c8d6ce 2678 return dep_entry;
d62a17ae 2679}
518f0eb1 2680
d62a17ae 2681static void *route_map_name_hash_alloc(void *p)
2682{
e2c8d6ce
NT
2683 struct route_map_dep_data *dep_data = NULL, *tmp_dep_data = NULL;
2684
2685 dep_data = XCALLOC(MTYPE_ROUTE_MAP_DEP_DATA,
2686 sizeof(struct route_map_dep_data));
2687 tmp_dep_data = p;
2688 dep_data->rname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, tmp_dep_data->rname);
2689 return dep_data;
518f0eb1
DS
2690}
2691
d8b87afe 2692static unsigned int route_map_dep_hash_make_key(const void *p)
518f0eb1 2693{
d62a17ae 2694 return (string_hash_make((char *)p));
2695}
518f0eb1 2696
e3b78da8 2697static void route_map_print_dependency(struct hash_bucket *bucket, void *data)
d62a17ae 2698{
e2c8d6ce
NT
2699 struct route_map_dep_data *dep_data = bucket->data;
2700 char *rmap_name = dep_data->rname;
2701 char *dep_name = data;
518f0eb1 2702
15569c58 2703 zlog_debug("%s: Dependency for %s: %s", __func__, dep_name, rmap_name);
518f0eb1
DS
2704}
2705
d62a17ae 2706static int route_map_dep_update(struct hash *dephash, const char *dep_name,
2707 const char *rmap_name, route_map_event_t type)
518f0eb1 2708{
d62a17ae 2709 struct route_map_dep *dep = NULL;
d62a17ae 2710 char *dname, *rname;
2711 int ret = 0;
e2c8d6ce
NT
2712 struct route_map_dep_data *dep_data = NULL, *ret_dep_data = NULL;
2713 struct route_map_dep_data tmp_dep_data;
d62a17ae 2714
2715 dname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
2716 rname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_name);
2717
2718 switch (type) {
2719 case RMAP_EVENT_PLIST_ADDED:
2720 case RMAP_EVENT_CLIST_ADDED:
2721 case RMAP_EVENT_ECLIST_ADDED:
2722 case RMAP_EVENT_ASLIST_ADDED:
2723 case RMAP_EVENT_LLIST_ADDED:
2724 case RMAP_EVENT_CALL_ADDED:
2725 case RMAP_EVENT_FILTER_ADDED:
2726 if (rmap_debug)
e3ab8170
AD
2727 zlog_debug("Adding dependency for filter %s in route-map %s",
2728 dep_name, rmap_name);
d62a17ae 2729 dep = (struct route_map_dep *)hash_get(
2730 dephash, dname, route_map_dep_hash_alloc);
2731 if (!dep) {
2732 ret = -1;
2733 goto out;
2734 }
2735
2736 if (!dep->this_hash)
2737 dep->this_hash = dephash;
2738
e2c8d6ce
NT
2739 memset(&tmp_dep_data, 0, sizeof(struct route_map_dep_data));
2740 tmp_dep_data.rname = rname;
2741 dep_data = hash_lookup(dep->dep_rmap_hash, &tmp_dep_data);
2742 if (!dep_data)
2743 dep_data = hash_get(dep->dep_rmap_hash, &tmp_dep_data,
2744 route_map_name_hash_alloc);
2745
2746 dep_data->refcnt++;
d62a17ae 2747 break;
2748 case RMAP_EVENT_PLIST_DELETED:
2749 case RMAP_EVENT_CLIST_DELETED:
2750 case RMAP_EVENT_ECLIST_DELETED:
2751 case RMAP_EVENT_ASLIST_DELETED:
2752 case RMAP_EVENT_LLIST_DELETED:
2753 case RMAP_EVENT_CALL_DELETED:
2754 case RMAP_EVENT_FILTER_DELETED:
2755 if (rmap_debug)
e3ab8170
AD
2756 zlog_debug("Deleting dependency for filter %s in route-map %s",
2757 dep_name, rmap_name);
d62a17ae 2758 dep = (struct route_map_dep *)hash_get(dephash, dname, NULL);
2759 if (!dep) {
2760 goto out;
2761 }
2762
e2c8d6ce
NT
2763 memset(&tmp_dep_data, 0, sizeof(struct route_map_dep_data));
2764 tmp_dep_data.rname = rname;
2765 dep_data = hash_lookup(dep->dep_rmap_hash, &tmp_dep_data);
c415a4dc
DA
2766
2767 if (!dep_data)
2768 goto out;
2769
2770 if (dep_data->refcnt)
2771 dep_data->refcnt--;
e2c8d6ce
NT
2772
2773 if (!dep_data->refcnt) {
2774 ret_dep_data = hash_release(dep->dep_rmap_hash,
2775 &tmp_dep_data);
2776 if (ret_dep_data) {
2777 XFREE(MTYPE_ROUTE_MAP_NAME,
2778 ret_dep_data->rname);
2779 XFREE(MTYPE_ROUTE_MAP_DEP_DATA, ret_dep_data);
2780 }
2781 }
d62a17ae 2782
2783 if (!dep->dep_rmap_hash->count) {
2784 dep = hash_release(dephash, dname);
2785 hash_free(dep->dep_rmap_hash);
2786 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
2787 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
d62a17ae 2788 }
2789 break;
ba1707ca
DS
2790 case RMAP_EVENT_SET_ADDED:
2791 case RMAP_EVENT_SET_DELETED:
2792 case RMAP_EVENT_SET_REPLACED:
2793 case RMAP_EVENT_MATCH_ADDED:
2794 case RMAP_EVENT_MATCH_DELETED:
2795 case RMAP_EVENT_MATCH_REPLACED:
2796 case RMAP_EVENT_INDEX_ADDED:
2797 case RMAP_EVENT_INDEX_DELETED:
d62a17ae 2798 break;
2799 }
2800
2801 if (dep) {
2802 if (rmap_debug)
2803 hash_iterate(dep->dep_rmap_hash,
2804 route_map_print_dependency, dname);
2805 }
2806
2807out:
2808 XFREE(MTYPE_ROUTE_MAP_NAME, rname);
2809 XFREE(MTYPE_ROUTE_MAP_NAME, dname);
2810 return ret;
2811}
2812
2813static struct hash *route_map_get_dep_hash(route_map_event_t event)
2814{
2815 struct hash *upd8_hash = NULL;
2816
2817 switch (event) {
2818 case RMAP_EVENT_PLIST_ADDED:
2819 case RMAP_EVENT_PLIST_DELETED:
2820 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_PLIST];
2821 break;
2822 case RMAP_EVENT_CLIST_ADDED:
2823 case RMAP_EVENT_CLIST_DELETED:
2824 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_CLIST];
2825 break;
2826 case RMAP_EVENT_ECLIST_ADDED:
2827 case RMAP_EVENT_ECLIST_DELETED:
2828 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ECLIST];
2829 break;
2830 case RMAP_EVENT_ASLIST_ADDED:
2831 case RMAP_EVENT_ASLIST_DELETED:
2832 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ASPATH];
2833 break;
2834 case RMAP_EVENT_LLIST_ADDED:
2835 case RMAP_EVENT_LLIST_DELETED:
2836 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_LCLIST];
2837 break;
2838 case RMAP_EVENT_CALL_ADDED:
2839 case RMAP_EVENT_CALL_DELETED:
5ed2e47b 2840 case RMAP_EVENT_MATCH_ADDED:
2841 case RMAP_EVENT_MATCH_DELETED:
d62a17ae 2842 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_RMAP];
2843 break;
2844 case RMAP_EVENT_FILTER_ADDED:
2845 case RMAP_EVENT_FILTER_DELETED:
2846 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_FILTER];
2847 break;
ba1707ca
DS
2848 /*
2849 * Should we actually be ignoring these?
2850 * I am not sure but at this point in time, let
2851 * us get them into this switch and we can peel
2852 * them into the appropriate place in the future
2853 */
2854 case RMAP_EVENT_SET_ADDED:
2855 case RMAP_EVENT_SET_DELETED:
2856 case RMAP_EVENT_SET_REPLACED:
2857 case RMAP_EVENT_MATCH_REPLACED:
2858 case RMAP_EVENT_INDEX_ADDED:
2859 case RMAP_EVENT_INDEX_DELETED:
d62a17ae 2860 upd8_hash = NULL;
2861 break;
2862 }
2863 return (upd8_hash);
518f0eb1
DS
2864}
2865
e3b78da8 2866static void route_map_process_dependency(struct hash_bucket *bucket, void *data)
518f0eb1 2867{
e2c8d6ce
NT
2868 struct route_map_dep_data *dep_data = NULL;
2869 char *rmap_name = NULL;
2870
2871 dep_data = bucket->data;
2872 rmap_name = dep_data->rname;
d62a17ae 2873
1fae5ff2 2874 if (rmap_debug)
e3ab8170 2875 zlog_debug("Notifying %s of dependency", rmap_name);
1fae5ff2 2876 if (route_map_master.event_hook)
097b5973 2877 (*route_map_master.event_hook)(rmap_name);
518f0eb1
DS
2878}
2879
d62a17ae 2880void route_map_upd8_dependency(route_map_event_t type, const char *arg,
2881 const char *rmap_name)
518f0eb1 2882{
d62a17ae 2883 struct hash *upd8_hash = NULL;
518f0eb1 2884
fdf823db 2885 if ((upd8_hash = route_map_get_dep_hash(type))) {
d62a17ae 2886 route_map_dep_update(upd8_hash, arg, rmap_name, type);
fdf823db
NT
2887
2888 if (type == RMAP_EVENT_CALL_ADDED) {
2889 /* Execute hook. */
2890 if (route_map_master.add_hook)
2891 (*route_map_master.add_hook)(rmap_name);
2892 } else if (type == RMAP_EVENT_CALL_DELETED) {
2893 /* Execute hook. */
2894 if (route_map_master.delete_hook)
2895 (*route_map_master.delete_hook)(rmap_name);
2896 }
2897 }
518f0eb1
DS
2898}
2899
d62a17ae 2900void route_map_notify_dependencies(const char *affected_name,
2901 route_map_event_t event)
518f0eb1 2902{
d62a17ae 2903 struct route_map_dep *dep;
2904 struct hash *upd8_hash;
2905 char *name;
2906
2907 if (!affected_name)
2908 return;
2909
2910 name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, affected_name);
2911
2912 if ((upd8_hash = route_map_get_dep_hash(event)) == NULL) {
2913 XFREE(MTYPE_ROUTE_MAP_NAME, name);
2914 return;
518f0eb1 2915 }
d62a17ae 2916
2917 dep = (struct route_map_dep *)hash_get(upd8_hash, name, NULL);
2918 if (dep) {
2919 if (!dep->this_hash)
2920 dep->this_hash = upd8_hash;
2921
e3ab8170
AD
2922 if (rmap_debug)
2923 zlog_debug("Filter %s updated", dep->dep_name);
d62a17ae 2924 hash_iterate(dep->dep_rmap_hash, route_map_process_dependency,
2925 (void *)event);
2926 }
2927
2928 XFREE(MTYPE_ROUTE_MAP_NAME, name);
518f0eb1
DS
2929}
2930
718e3744 2931/* VTY related functions. */
2d26f094
NT
2932DEFUN(no_routemap_optimization, no_routemap_optimization_cmd,
2933 "no route-map optimization",
2934 NO_STR
2935 "route-map\n"
2936 "optimization\n")
49a08bb0
NT
2937{
2938 VTY_DECLVAR_CONTEXT(route_map_index, index);
2939
2940 index->map->optimization_disabled = true;
2941 return CMD_SUCCESS;
2942}
2943
2d26f094
NT
2944DEFUN(routemap_optimization, routemap_optimization_cmd,
2945 "route-map optimization",
2946 "route-map\n"
2947 "optimization\n")
49a08bb0
NT
2948{
2949 VTY_DECLVAR_CONTEXT(route_map_index, index);
2950
2951 index->map->optimization_disabled = false;
2952 return CMD_SUCCESS;
2953}
82f97584 2954
1fa30509
DS
2955static void clear_route_map_helper(struct route_map *map)
2956{
2957 struct route_map_index *index;
2958
2959 map->applied_clear = map->applied;
2960 for (index = map->head; index; index = index->next)
2961 index->applied_clear = index->applied;
2962}
2963
2964DEFUN (rmap_clear_counters,
2965 rmap_clear_counters_cmd,
2966 "clear route-map counters [WORD]",
2967 CLEAR_STR
2968 "route-map information\n"
2969 "counters associated with the specified route-map\n"
2970 "route-map name\n")
2971{
2972 int idx_word = 2;
2973 struct route_map *map;
2974
2975 const char *name = (argc == 3 ) ? argv[idx_word]->arg : NULL;
2976
2977 if (name) {
2978 map = route_map_lookup_by_name(name);
2979
2980 if (map)
2981 clear_route_map_helper(map);
2982 else {
2983 vty_out(vty, "%s: 'route-map %s' not found\n",
2984 frr_protonameinst, name);
2985 return CMD_SUCCESS;
2986 }
2987 } else {
2988 for (map = route_map_master.head; map; map = map->next)
2989 clear_route_map_helper(map);
2990 }
2991
2992 return CMD_SUCCESS;
2993
2994}
5510e83b 2995
6d2729e3 2996DEFUN (rmap_show_name,
5510e83b 2997 rmap_show_name_cmd,
7514fb77 2998 "show route-map [WORD]",
5510e83b 2999 SHOW_STR
3000 "route-map information\n"
3001 "route-map name\n")
3002{
d62a17ae 3003 int idx_word = 2;
3004 const char *name = (argc == 3) ? argv[idx_word]->arg : NULL;
3005 return vty_show_route_map(vty, name);
5510e83b 3006}
3007
4a2a09d0 3008DEFUN (rmap_show_unused,
3009 rmap_show_unused_cmd,
3010 "show route-map-unused",
3011 SHOW_STR
3012 "unused route-map information\n")
3013{
3014 return vty_show_unused_route_map(vty);
3015}
3016
e3ab8170
AD
3017DEFUN (debug_rmap,
3018 debug_rmap_cmd,
3019 "debug route-map",
3020 DEBUG_STR
3021 "Debug option set for route-maps\n")
3022{
3023 rmap_debug = true;
3024 return CMD_SUCCESS;
3025}
3026
3027DEFUN (no_debug_rmap,
3028 no_debug_rmap_cmd,
3029 "no debug route-map",
3030 NO_STR
3031 DEBUG_STR
3032 "Debug option set for route-maps\n")
3033{
3034 rmap_debug = false;
3035 return CMD_SUCCESS;
3036}
3037
3038/* Debug node. */
612c2c15 3039static int rmap_config_write_debug(struct vty *vty);
62b346ee 3040static struct cmd_node rmap_debug_node = {
f4b8291f 3041 .name = "route-map debug",
62b346ee
DL
3042 .node = RMAP_DEBUG_NODE,
3043 .prompt = "",
612c2c15 3044 .config_write = rmap_config_write_debug,
62b346ee 3045};
e3ab8170 3046
718e3744 3047/* Configuration write function. */
e3ab8170
AD
3048static int rmap_config_write_debug(struct vty *vty)
3049{
3050 int write = 0;
3051
3052 if (rmap_debug) {
3053 vty_out(vty, "debug route-map\n");
3054 write++;
3055 }
3056
3057 return write;
3058}
3059
dc9ffce8
CF
3060/* Common route map rules */
3061
d62a17ae 3062void *route_map_rule_tag_compile(const char *arg)
dc9ffce8 3063{
d62a17ae 3064 unsigned long int tmp;
3065 char *endptr;
3066 route_tag_t *tag;
dc9ffce8 3067
d62a17ae 3068 errno = 0;
3069 tmp = strtoul(arg, &endptr, 0);
3070 if (arg[0] == '\0' || *endptr != '\0' || errno || tmp > ROUTE_TAG_MAX)
3071 return NULL;
dc9ffce8 3072
d62a17ae 3073 tag = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*tag));
3074 *tag = tmp;
dc9ffce8 3075
d62a17ae 3076 return tag;
dc9ffce8
CF
3077}
3078
d62a17ae 3079void route_map_rule_tag_free(void *rule)
dc9ffce8 3080{
d62a17ae 3081 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
dc9ffce8
CF
3082}
3083
d62a17ae 3084void route_map_finish(void)
9df78e7c 3085{
d62a17ae 3086 int i;
9df78e7c 3087
d62a17ae 3088 vector_free(route_match_vec);
3089 route_match_vec = NULL;
3090 vector_free(route_set_vec);
3091 route_set_vec = NULL;
9df78e7c 3092
8619629a
DS
3093 /*
3094 * All protocols are setting these to NULL
3095 * by default on shutdown( route_map_finish )
3096 * Why are we making them do this work?
3097 */
3098 route_map_master.add_hook = NULL;
3099 route_map_master.delete_hook = NULL;
3100 route_map_master.event_hook = NULL;
3101
d62a17ae 3102 /* cleanup route_map */
3103 while (route_map_master.head) {
3104 struct route_map *map = route_map_master.head;
e4694d0d 3105 map->to_be_processed = false;
d62a17ae 3106 route_map_delete(map);
3107 }
9df78e7c 3108
d62a17ae 3109 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
3110 hash_free(route_map_dep_hash[i]);
3111 route_map_dep_hash[i] = NULL;
3112 }
9df78e7c 3113
d62a17ae 3114 hash_free(route_map_master_hash);
3115 route_map_master_hash = NULL;
9df78e7c
DS
3116}
3117
4a2a09d0 3118/* Increment the use_count counter while attaching the route map */
3119void route_map_counter_increment(struct route_map *map)
3120{
3121 if (map)
3122 map->use_count++;
3123}
3124
3125/* Decrement the use_count counter while detaching the route map. */
3126void route_map_counter_decrement(struct route_map *map)
3127{
3128 if (map) {
3129 if (map->use_count <= 0)
3130 return;
3131 map->use_count--;
3132 }
3133}
3134
2d26f094
NT
3135DEFUN_HIDDEN(show_route_map_pfx_tbl, show_route_map_pfx_tbl_cmd,
3136 "show route-map WORD prefix-table",
3137 SHOW_STR
3138 "route-map\n"
3139 "route-map name\n"
3140 "internal prefix-table\n")
3141{
3142 const char *rmap_name = argv[2]->arg;
3143 struct route_map *rmap = NULL;
3144 struct route_table *rm_pfx_tbl4 = NULL;
3145 struct route_table *rm_pfx_tbl6 = NULL;
3146 struct route_node *rn = NULL, *prn = NULL;
3147 struct list *rmap_index_list = NULL;
3148 struct listnode *ln = NULL, *nln = NULL;
3149 struct route_map_index *index = NULL;
2d26f094
NT
3150 uint8_t len = 54;
3151
3152 vty_out(vty, "%s:\n", frr_protonameinst);
3153 rmap = route_map_lookup_by_name(rmap_name);
3154 if (rmap) {
3155 rm_pfx_tbl4 = rmap->ipv4_prefix_table;
3156 if (rm_pfx_tbl4) {
3157 vty_out(vty, "\n%s%43s%s\n", "IPv4 Prefix", "",
3158 "Route-map Index List");
3159 vty_out(vty, "%s%39s%s\n", "_______________", "",
3160 "____________________");
3161 for (rn = route_top(rm_pfx_tbl4); rn;
3162 rn = route_next(rn)) {
b219dda1 3163 vty_out(vty, " %pRN (%d)\n", rn,
c10e14e9 3164 route_node_get_lock_count(rn));
2d26f094
NT
3165
3166 vty_out(vty, "(P) ");
3167 prn = rn->parent;
3168 if (prn) {
b219dda1 3169 vty_out(vty, "%pRN\n", prn);
2d26f094
NT
3170 }
3171
3172 vty_out(vty, "\n");
3173 rmap_index_list = (struct list *)rn->info;
3174 if (!rmap_index_list
3175 || !listcount(rmap_index_list))
3176 vty_out(vty, "%*s%s\n", len, "", "-");
3177 else
3178 for (ALL_LIST_ELEMENTS(rmap_index_list,
3179 ln, nln,
3180 index)) {
3181 vty_out(vty, "%*s%s seq %d\n",
3182 len, "",
3183 index->map->name,
3184 index->pref);
3185 }
3186 vty_out(vty, "\n");
3187 }
3188 }
3189
3190 rm_pfx_tbl6 = rmap->ipv6_prefix_table;
3191 if (rm_pfx_tbl6) {
3192 vty_out(vty, "\n%s%43s%s\n", "IPv6 Prefix", "",
3193 "Route-map Index List");
3194 vty_out(vty, "%s%39s%s\n", "_______________", "",
3195 "____________________");
3196 for (rn = route_top(rm_pfx_tbl6); rn;
3197 rn = route_next(rn)) {
b219dda1 3198 vty_out(vty, " %pRN (%d)\n", rn,
c10e14e9 3199 route_node_get_lock_count(rn));
2d26f094
NT
3200
3201 vty_out(vty, "(P) ");
3202 prn = rn->parent;
3203 if (prn) {
b219dda1 3204 vty_out(vty, "%pRN\n", prn);
2d26f094
NT
3205 }
3206
3207 vty_out(vty, "\n");
3208 rmap_index_list = (struct list *)rn->info;
3209 if (!rmap_index_list
3210 || !listcount(rmap_index_list))
3211 vty_out(vty, "%*s%s\n", len, "", "-");
3212 else
3213 for (ALL_LIST_ELEMENTS(rmap_index_list,
3214 ln, nln,
3215 index)) {
3216 vty_out(vty, "%*s%s seq %d\n",
3217 len, "",
3218 index->map->name,
3219 index->pref);
3220 }
3221 vty_out(vty, "\n");
3222 }
3223 }
3224 }
3225
3226 vty_out(vty, "\n");
3227 return CMD_SUCCESS;
3228}
3229
718e3744 3230/* Initialization of route map vector. */
d62a17ae 3231void route_map_init(void)
718e3744 3232{
d62a17ae 3233 int i;
3234
3235 /* Make vector for match and set. */
3236 route_match_vec = vector_init(1);
3237 route_set_vec = vector_init(1);
3238 route_map_master_hash =
996c9314 3239 hash_create_size(8, route_map_hash_key_make, route_map_hash_cmp,
bd74dc61 3240 "Route Map Master Hash");
d62a17ae 3241
3242 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
996c9314
LB
3243 route_map_dep_hash[i] = hash_create_size(
3244 8, route_map_dep_hash_make_key, route_map_dep_hash_cmp,
3245 "Route Map Dep Hash");
b2575bc0 3246
e3ab8170
AD
3247 rmap_debug = false;
3248
2b3e4807 3249 route_map_cli_init();
518f0eb1 3250
2b3e4807 3251 /* Install route map top node. */
612c2c15 3252 install_node(&rmap_debug_node);
e3ab8170 3253
d62a17ae 3254 /* Install route map commands. */
e3ab8170
AD
3255 install_element(CONFIG_NODE, &debug_rmap_cmd);
3256 install_element(CONFIG_NODE, &no_debug_rmap_cmd);
3257
d62a17ae 3258 /* Install show command */
1fa30509
DS
3259 install_element(ENABLE_NODE, &rmap_clear_counters_cmd);
3260
d62a17ae 3261 install_element(ENABLE_NODE, &rmap_show_name_cmd);
4a2a09d0 3262 install_element(ENABLE_NODE, &rmap_show_unused_cmd);
82f97584 3263
e3ab8170
AD
3264 install_element(ENABLE_NODE, &debug_rmap_cmd);
3265 install_element(ENABLE_NODE, &no_debug_rmap_cmd);
49a08bb0
NT
3266
3267 install_element(RMAP_NODE, &routemap_optimization_cmd);
3268 install_element(RMAP_NODE, &no_routemap_optimization_cmd);
2d26f094 3269
31f937fb
SM
3270 install_element(RMAP_NODE, &set_srte_color_cmd);
3271 install_element(RMAP_NODE, &no_set_srte_color_cmd);
3272
2d26f094 3273 install_element(ENABLE_NODE, &show_route_map_pfx_tbl_cmd);
718e3744 3274}