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