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