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