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