]> git.proxmox.com Git - mirror_frr.git/blame - lib/routemap.c
Merge pull request #5104 from opensourcerouting/route-map-nbv2
[mirror_frr.git] / lib / routemap.c
CommitLineData
718e3744 1/* Route map function.
896014f4
DL
2 * Copyright (C) 1998, 1999 Kunihiro Ishiguro
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
718e3744 20
21#include <zebra.h>
22
23#include "linklist.h"
24#include "memory.h"
25#include "vector.h"
26#include "prefix.h"
82f97584 27#include "vty.h"
718e3744 28#include "routemap.h"
29#include "command.h"
fee0f4c6 30#include "log.h"
518f0eb1 31#include "hash.h"
b85120bc 32#include "libfrr.h"
040c7c3a 33#include "lib_errors.h"
6b0655a2 34
d62a17ae 35DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP, "Route map")
36DEFINE_MTYPE(LIB, ROUTE_MAP_NAME, "Route map name")
37DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_INDEX, "Route map index")
38DEFINE_MTYPE(LIB, ROUTE_MAP_RULE, "Route map rule")
4a1ab8e4 39DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_RULE_STR, "Route map rule str")
d62a17ae 40DEFINE_MTYPE(LIB, ROUTE_MAP_COMPILED, "Route map compiled")
41DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_DEP, "Route map dependency")
e2c8d6ce 42DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_DEP_DATA, "Route map dependency data")
4a1ab8e4 43
e80e7cce
DL
44DEFINE_QOBJ_TYPE(route_map_index)
45DEFINE_QOBJ_TYPE(route_map)
46
718e3744 47/* Vector for route match rules. */
48static vector route_match_vec;
49
50/* Vector for route set rules. */
51static vector route_set_vec;
52
a7282663 53struct route_map_match_set_hooks rmap_match_set_hook;
82f97584
DW
54
55/* match interface */
d62a17ae 56void route_map_match_interface_hook(int (*func)(
57 struct vty *vty, struct route_map_index *index, const char *command,
58 const char *arg, route_map_event_t type))
82f97584 59{
d62a17ae 60 rmap_match_set_hook.match_interface = func;
82f97584
DW
61}
62
63/* no match interface */
d62a17ae 64void route_map_no_match_interface_hook(int (*func)(
65 struct vty *vty, struct route_map_index *index, const char *command,
66 const char *arg, route_map_event_t type))
82f97584 67{
d62a17ae 68 rmap_match_set_hook.no_match_interface = func;
82f97584
DW
69}
70
71/* match ip address */
d62a17ae 72void route_map_match_ip_address_hook(int (*func)(
73 struct vty *vty, struct route_map_index *index, const char *command,
74 const char *arg, route_map_event_t type))
82f97584 75{
d62a17ae 76 rmap_match_set_hook.match_ip_address = func;
82f97584
DW
77}
78
79/* no match ip address */
d62a17ae 80void route_map_no_match_ip_address_hook(int (*func)(
81 struct vty *vty, struct route_map_index *index, const char *command,
82 const char *arg, route_map_event_t type))
82f97584 83{
d62a17ae 84 rmap_match_set_hook.no_match_ip_address = func;
82f97584
DW
85}
86
87/* match ip address prefix list */
d62a17ae 88void route_map_match_ip_address_prefix_list_hook(int (*func)(
89 struct vty *vty, struct route_map_index *index, const char *command,
90 const char *arg, route_map_event_t type))
82f97584 91{
d62a17ae 92 rmap_match_set_hook.match_ip_address_prefix_list = func;
82f97584
DW
93}
94
95/* no match ip address prefix list */
d62a17ae 96void route_map_no_match_ip_address_prefix_list_hook(int (*func)(
97 struct vty *vty, struct route_map_index *index, const char *command,
98 const char *arg, route_map_event_t type))
82f97584 99{
d62a17ae 100 rmap_match_set_hook.no_match_ip_address_prefix_list = func;
82f97584
DW
101}
102
103/* match ip next hop */
d62a17ae 104void route_map_match_ip_next_hop_hook(int (*func)(
105 struct vty *vty, struct route_map_index *index, const char *command,
106 const char *arg, route_map_event_t type))
82f97584 107{
d62a17ae 108 rmap_match_set_hook.match_ip_next_hop = func;
82f97584
DW
109}
110
111/* no match ip next hop */
d62a17ae 112void route_map_no_match_ip_next_hop_hook(int (*func)(
113 struct vty *vty, struct route_map_index *index, const char *command,
114 const char *arg, route_map_event_t type))
82f97584 115{
d62a17ae 116 rmap_match_set_hook.no_match_ip_next_hop = func;
82f97584
DW
117}
118
119/* match ip next hop prefix list */
d62a17ae 120void route_map_match_ip_next_hop_prefix_list_hook(int (*func)(
121 struct vty *vty, struct route_map_index *index, const char *command,
122 const char *arg, route_map_event_t type))
82f97584 123{
d62a17ae 124 rmap_match_set_hook.match_ip_next_hop_prefix_list = func;
82f97584
DW
125}
126
127/* no match ip next hop prefix list */
d62a17ae 128void route_map_no_match_ip_next_hop_prefix_list_hook(int (*func)(
129 struct vty *vty, struct route_map_index *index, const char *command,
130 const char *arg, route_map_event_t type))
82f97584 131{
d62a17ae 132 rmap_match_set_hook.no_match_ip_next_hop_prefix_list = func;
82f97584
DW
133}
134
f554fda7 135/* match ip next-hop type */
61ad901e
DA
136void route_map_match_ip_next_hop_type_hook(int (*func)(
137 struct vty *vty, struct route_map_index *index, const char *command,
138 const char *arg, route_map_event_t type))
139{
140 rmap_match_set_hook.match_ip_next_hop_type = func;
141}
142
f554fda7 143/* no match ip next-hop type */
61ad901e
DA
144void route_map_no_match_ip_next_hop_type_hook(int (*func)(
145 struct vty *vty, struct route_map_index *index, const char *command,
146 const char *arg, route_map_event_t type))
147{
148 rmap_match_set_hook.no_match_ip_next_hop_type = func;
149}
150
82f97584 151/* match ipv6 address */
d62a17ae 152void route_map_match_ipv6_address_hook(int (*func)(
153 struct vty *vty, struct route_map_index *index, const char *command,
154 const char *arg, route_map_event_t type))
82f97584 155{
d62a17ae 156 rmap_match_set_hook.match_ipv6_address = func;
82f97584
DW
157}
158
159/* no match ipv6 address */
d62a17ae 160void route_map_no_match_ipv6_address_hook(int (*func)(
161 struct vty *vty, struct route_map_index *index, const char *command,
162 const char *arg, route_map_event_t type))
82f97584 163{
d62a17ae 164 rmap_match_set_hook.no_match_ipv6_address = func;
82f97584
DW
165}
166
167
168/* match ipv6 address prefix list */
d62a17ae 169void route_map_match_ipv6_address_prefix_list_hook(int (*func)(
170 struct vty *vty, struct route_map_index *index, const char *command,
171 const char *arg, route_map_event_t type))
82f97584 172{
d62a17ae 173 rmap_match_set_hook.match_ipv6_address_prefix_list = func;
82f97584
DW
174}
175
176/* no match ipv6 address prefix list */
d62a17ae 177void route_map_no_match_ipv6_address_prefix_list_hook(int (*func)(
178 struct vty *vty, struct route_map_index *index, const char *command,
179 const char *arg, route_map_event_t type))
82f97584 180{
d62a17ae 181 rmap_match_set_hook.no_match_ipv6_address_prefix_list = func;
82f97584
DW
182}
183
61ad901e
DA
184/* match ipv6 next-hop type */
185void route_map_match_ipv6_next_hop_type_hook(int (*func)(
186 struct vty *vty, struct route_map_index *index, const char *command,
187 const char *arg, route_map_event_t type))
188{
189 rmap_match_set_hook.match_ipv6_next_hop_type = func;
190}
191
192/* no match ipv6 next-hop type */
193void route_map_no_match_ipv6_next_hop_type_hook(int (*func)(
194 struct vty *vty, struct route_map_index *index, const char *command,
195 const char *arg, route_map_event_t type))
196{
197 rmap_match_set_hook.no_match_ipv6_next_hop_type = func;
198}
199
82f97584 200/* match metric */
d62a17ae 201void route_map_match_metric_hook(int (*func)(
202 struct vty *vty, struct route_map_index *index, const char *command,
203 const char *arg, route_map_event_t type))
82f97584 204{
d62a17ae 205 rmap_match_set_hook.match_metric = func;
82f97584
DW
206}
207
208/* no match metric */
d62a17ae 209void route_map_no_match_metric_hook(int (*func)(
210 struct vty *vty, struct route_map_index *index, const char *command,
211 const char *arg, route_map_event_t type))
82f97584 212{
d62a17ae 213 rmap_match_set_hook.no_match_metric = func;
82f97584
DW
214}
215
216/* match tag */
d62a17ae 217void route_map_match_tag_hook(int (*func)(struct vty *vty,
218 struct route_map_index *index,
219 const char *command, const char *arg,
220 route_map_event_t type))
82f97584 221{
d62a17ae 222 rmap_match_set_hook.match_tag = func;
82f97584
DW
223}
224
225/* no match tag */
d62a17ae 226void route_map_no_match_tag_hook(int (*func)(
227 struct vty *vty, struct route_map_index *index, const char *command,
228 const char *arg, route_map_event_t type))
82f97584 229{
d62a17ae 230 rmap_match_set_hook.no_match_tag = func;
82f97584
DW
231}
232
233/* set ip nexthop */
d62a17ae 234void route_map_set_ip_nexthop_hook(int (*func)(struct vty *vty,
235 struct route_map_index *index,
236 const char *command,
237 const char *arg))
82f97584 238{
d62a17ae 239 rmap_match_set_hook.set_ip_nexthop = func;
82f97584
DW
240}
241
242/* no set ip nexthop */
d62a17ae 243void route_map_no_set_ip_nexthop_hook(int (*func)(struct vty *vty,
244 struct route_map_index *index,
245 const char *command,
246 const char *arg))
82f97584 247{
d62a17ae 248 rmap_match_set_hook.no_set_ip_nexthop = func;
82f97584
DW
249}
250
251/* set ipv6 nexthop local */
d62a17ae 252void route_map_set_ipv6_nexthop_local_hook(
253 int (*func)(struct vty *vty, struct route_map_index *index,
254 const char *command, const char *arg))
82f97584 255{
d62a17ae 256 rmap_match_set_hook.set_ipv6_nexthop_local = func;
82f97584
DW
257}
258
259/* no set ipv6 nexthop local */
d62a17ae 260void route_map_no_set_ipv6_nexthop_local_hook(
261 int (*func)(struct vty *vty, struct route_map_index *index,
262 const char *command, const char *arg))
82f97584 263{
d62a17ae 264 rmap_match_set_hook.no_set_ipv6_nexthop_local = func;
82f97584
DW
265}
266
267/* set metric */
d62a17ae 268void route_map_set_metric_hook(int (*func)(struct vty *vty,
269 struct route_map_index *index,
270 const char *command,
271 const char *arg))
82f97584 272{
d62a17ae 273 rmap_match_set_hook.set_metric = func;
82f97584
DW
274}
275
276/* no set metric */
d62a17ae 277void route_map_no_set_metric_hook(int (*func)(struct vty *vty,
278 struct route_map_index *index,
279 const char *command,
280 const char *arg))
82f97584 281{
d62a17ae 282 rmap_match_set_hook.no_set_metric = func;
82f97584
DW
283}
284
285/* set tag */
d62a17ae 286void route_map_set_tag_hook(int (*func)(struct vty *vty,
287 struct route_map_index *index,
288 const char *command, const char *arg))
82f97584 289{
d62a17ae 290 rmap_match_set_hook.set_tag = func;
82f97584
DW
291}
292
293/* no set tag */
d62a17ae 294void route_map_no_set_tag_hook(int (*func)(struct vty *vty,
295 struct route_map_index *index,
296 const char *command,
297 const char *arg))
298{
299 rmap_match_set_hook.no_set_tag = func;
82f97584
DW
300}
301
d62a17ae 302int generic_match_add(struct vty *vty, struct route_map_index *index,
303 const char *command, const char *arg,
304 route_map_event_t type)
305{
cda7187d 306 enum rmap_compile_rets ret;
d62a17ae 307
e2c8d6ce 308 ret = route_map_add_match(index, command, arg, type);
9ca25fed 309 switch (ret) {
9ca25fed 310 case RMAP_RULE_MISSING:
a162869e
RZ
311 if (vty)
312 vty_out(vty, "%% [%s] Can't find rule.\n",
313 frr_protonameinst);
314 else
315 zlog_warn("Can't find rule: %s", command);
9ca25fed 316 return CMD_WARNING_CONFIG_FAILED;
9ca25fed 317 case RMAP_COMPILE_ERROR:
a162869e
RZ
318 if (vty)
319 vty_out(vty,
320 "%% [%s] Argument form is unsupported or malformed.\n",
321 frr_protonameinst);
322 else
323 zlog_warn("Argument form is unsupported or malformed: "
324 "%s %s", command, arg);
9ca25fed 325 return CMD_WARNING_CONFIG_FAILED;
909f3d56 326 case RMAP_COMPILE_SUCCESS:
cda7187d
DS
327 /*
328 * Nothing to do here move along
329 */
330 break;
d62a17ae 331 }
82f97584 332
d62a17ae 333 return CMD_SUCCESS;
334}
335
336int generic_match_delete(struct vty *vty, struct route_map_index *index,
337 const char *command, const char *arg,
338 route_map_event_t type)
339{
cda7187d 340 enum rmap_compile_rets ret;
9ca25fed 341 int retval = CMD_SUCCESS;
d62a17ae 342 char *dep_name = NULL;
343 const char *tmpstr;
344 char *rmap_name = NULL;
345
346 if (type != RMAP_EVENT_MATCH_DELETED) {
347 /* ignore the mundane, the types without any dependency */
348 if (arg == NULL) {
349 if ((tmpstr = route_map_get_match_arg(index, command))
350 != NULL)
351 dep_name =
352 XSTRDUP(MTYPE_ROUTE_MAP_RULE, tmpstr);
353 } else {
354 dep_name = XSTRDUP(MTYPE_ROUTE_MAP_RULE, arg);
355 }
356 rmap_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, index->map->name);
357 }
358
909f3d56 359 ret = route_map_delete_match(index, command, dep_name, type);
9ca25fed
DS
360 switch (ret) {
361 case RMAP_RULE_MISSING:
a162869e
RZ
362 if (vty)
363 vty_out(vty, "%% [%s] Can't find rule.\n",
364 frr_protonameinst);
365 else
366 zlog_warn("Can't find rule: %s", command);
9ca25fed
DS
367 retval = CMD_WARNING_CONFIG_FAILED;
368 break;
369 case RMAP_COMPILE_ERROR:
a162869e
RZ
370 if (vty)
371 vty_out(vty,
372 "%% [%s] Argument form is unsupported or malformed.\n",
373 frr_protonameinst);
374 else
375 zlog_warn("Argument form is unsupported or malformed: "
376 "%s %s", command, arg);
9ca25fed
DS
377 retval = CMD_WARNING_CONFIG_FAILED;
378 break;
379 case RMAP_COMPILE_SUCCESS:
cda7187d
DS
380 /*
381 * Nothing to do here
382 */
383 break;
d62a17ae 384 }
385
0a22ddfb
QY
386 XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
387 XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
d62a17ae 388
9ca25fed 389 return retval;
d62a17ae 390}
391
392int generic_set_add(struct vty *vty, struct route_map_index *index,
393 const char *command, const char *arg)
718e3744 394{
cda7187d 395 enum rmap_compile_rets ret;
d62a17ae 396
397 ret = route_map_add_set(index, command, arg);
9ca25fed
DS
398 switch (ret) {
399 case RMAP_RULE_MISSING:
a162869e
RZ
400 if (vty)
401 vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst);
402 else
403 zlog_warn("Can't find rule: %s", command);
9ca25fed 404 return CMD_WARNING_CONFIG_FAILED;
9ca25fed 405 case RMAP_COMPILE_ERROR:
a162869e
RZ
406 if (vty)
407 vty_out(vty,
408 "%% [%s] Argument form is unsupported or malformed.\n",
409 frr_protonameinst);
410 else
411 zlog_warn("Argument form is unsupported or malformed: "
412 "%s %s", command, arg);
9ca25fed 413 return CMD_WARNING_CONFIG_FAILED;
9ca25fed
DS
414 case RMAP_COMPILE_SUCCESS:
415 break;
d62a17ae 416 }
9ca25fed 417
d62a17ae 418 return CMD_SUCCESS;
419}
420
421int generic_set_delete(struct vty *vty, struct route_map_index *index,
422 const char *command, const char *arg)
423{
cda7187d 424 enum rmap_compile_rets ret;
d62a17ae 425
426 ret = route_map_delete_set(index, command, arg);
9ca25fed
DS
427 switch (ret) {
428 case RMAP_RULE_MISSING:
a162869e
RZ
429 if (vty)
430 vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst);
431 else
432 zlog_warn("Can't find rule: %s", command);
9ca25fed 433 return CMD_WARNING_CONFIG_FAILED;
9ca25fed 434 case RMAP_COMPILE_ERROR:
a162869e
RZ
435 if (vty)
436 vty_out(vty,
437 "%% [%s] Argument form is unsupported or malformed.\n",
438 frr_protonameinst);
439 else
440 zlog_warn("Argument form is unsupported or malformed: "
441 "%s %s", command, arg);
9ca25fed 442 return CMD_WARNING_CONFIG_FAILED;
9ca25fed
DS
443 case RMAP_COMPILE_SUCCESS:
444 break;
d62a17ae 445 }
9ca25fed 446
d62a17ae 447 return CMD_SUCCESS;
448}
449
450
718e3744 451/* Master list of route map. */
a7282663
RZ
452struct route_map_list route_map_master = {NULL, NULL, NULL, NULL, NULL};
453struct hash *route_map_master_hash = NULL;
a6e0d253 454
d8b87afe 455static unsigned int route_map_hash_key_make(const void *p)
a6e0d253 456{
d62a17ae 457 const struct route_map *map = p;
458 return string_hash_make(map->name);
a6e0d253
DW
459}
460
74df8d6d 461static bool route_map_hash_cmp(const void *p1, const void *p2)
a6e0d253 462{
d62a17ae 463 const struct route_map *map1 = p1;
464 const struct route_map *map2 = p2;
a6e0d253 465
d62a17ae 466 if (map1->deleted == map2->deleted) {
467 if (map1->name && map2->name) {
468 if (!strcmp(map1->name, map2->name)) {
74df8d6d 469 return true;
d62a17ae 470 }
471 } else if (!map1->name && !map2->name) {
74df8d6d 472 return true;
d62a17ae 473 }
474 }
a6e0d253 475
74df8d6d 476 return false;
a6e0d253 477}
518f0eb1 478
d62a17ae 479enum route_map_upd8_type {
480 ROUTE_MAP_ADD = 1,
481 ROUTE_MAP_DEL,
482};
518f0eb1
DS
483
484/* all possible route-map dependency types */
d62a17ae 485enum route_map_dep_type {
486 ROUTE_MAP_DEP_RMAP = 1,
487 ROUTE_MAP_DEP_CLIST,
488 ROUTE_MAP_DEP_ECLIST,
489 ROUTE_MAP_DEP_LCLIST,
490 ROUTE_MAP_DEP_PLIST,
491 ROUTE_MAP_DEP_ASPATH,
492 ROUTE_MAP_DEP_FILTER,
493 ROUTE_MAP_DEP_MAX,
494};
495
496struct route_map_dep {
497 char *dep_name;
498 struct hash *dep_rmap_hash;
499 struct hash *this_hash; /* ptr to the hash structure this is part of */
518f0eb1 500};
718e3744 501
e2c8d6ce
NT
502struct route_map_dep_data {
503 /* Route-map name.
504 */
505 char *rname;
506 /* Count of number of sequences of this
507 * route-map that depend on the same entity.
508 */
509 uint16_t refcnt;
510};
511
518f0eb1 512/* Hashes maintaining dependency between various sublists used by route maps */
1b3e9a21 513static struct hash *route_map_dep_hash[ROUTE_MAP_DEP_MAX];
518f0eb1 514
d8b87afe 515static unsigned int route_map_dep_hash_make_key(const void *p);
d62a17ae 516static void route_map_clear_all_references(char *rmap_name);
517static void route_map_rule_delete(struct route_map_rule_list *,
518 struct route_map_rule *);
e3ab8170 519static bool rmap_debug;
718e3744 520
718e3744 521/* New route map allocation. Please note route map's name must be
522 specified. */
d62a17ae 523static struct route_map *route_map_new(const char *name)
718e3744 524{
d62a17ae 525 struct route_map *new;
718e3744 526
d62a17ae 527 new = XCALLOC(MTYPE_ROUTE_MAP, sizeof(struct route_map));
528 new->name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, name);
529 QOBJ_REG(new, route_map);
530 return new;
718e3744 531}
532
533/* Add new name to route_map. */
d62a17ae 534static struct route_map *route_map_add(const char *name)
535{
536 struct route_map *map;
537 struct route_map_list *list;
538
539 map = route_map_new(name);
540 list = &route_map_master;
541
542 /* Add map to the hash */
543 hash_get(route_map_master_hash, map, hash_alloc_intern);
544
545 /* Add new entry to the head of the list to match how it is added in the
546 * hash table. This is to ensure that if the same route-map has been
547 * created more than once and then marked for deletion (which can happen
548 * if prior deletions haven't completed as BGP hasn't yet done the
549 * route-map processing), the order of the entities is the same in both
550 * the list and the hash table. Otherwise, since there is nothing to
551 * distinguish between the two entries, the wrong entry could get freed.
552 * TODO: This needs to be re-examined to handle it better - e.g., revive
553 * a deleted entry if the route-map is created again.
554 */
555 map->prev = NULL;
556 map->next = list->head;
557 if (list->head)
558 list->head->prev = map;
559 list->head = map;
560 if (!list->tail)
561 list->tail = map;
562
563 /* Execute hook. */
564 if (route_map_master.add_hook) {
565 (*route_map_master.add_hook)(name);
566 route_map_notify_dependencies(name, RMAP_EVENT_CALL_ADDED);
567 }
e3ab8170
AD
568
569 if (rmap_debug)
570 zlog_debug("Add route-map %s", name);
d62a17ae 571 return map;
718e3744 572}
573
518f0eb1
DS
574/* this is supposed to be called post processing by
575 * the delete hook function. Don't invoke delete_hook
576 * again in this routine.
577 */
d62a17ae 578static void route_map_free_map(struct route_map *map)
718e3744 579{
d62a17ae 580 struct route_map_list *list;
581 struct route_map_index *index;
518f0eb1 582
d62a17ae 583 if (map == NULL)
584 return;
a31ff449 585
d62a17ae 586 while ((index = map->head) != NULL)
587 route_map_index_delete(index, 0);
718e3744 588
e3ab8170
AD
589 if (rmap_debug)
590 zlog_debug("Deleting route-map %s", map->name);
591
d62a17ae 592 list = &route_map_master;
718e3744 593
d62a17ae 594 QOBJ_UNREG(map);
e80e7cce 595
d62a17ae 596 if (map->next)
597 map->next->prev = map->prev;
598 else
599 list->tail = map->prev;
718e3744 600
d62a17ae 601 if (map->prev)
602 map->prev->next = map->next;
603 else
604 list->head = map->next;
718e3744 605
d62a17ae 606 hash_release(route_map_master_hash, map);
607 XFREE(MTYPE_ROUTE_MAP_NAME, map->name);
608 XFREE(MTYPE_ROUTE_MAP, map);
518f0eb1 609}
718e3744 610
518f0eb1 611/* Route map delete from list. */
a7282663 612void route_map_delete(struct route_map *map)
518f0eb1 613{
d62a17ae 614 struct route_map_index *index;
615 char *name;
518f0eb1 616
d62a17ae 617 while ((index = map->head) != NULL)
618 route_map_index_delete(index, 0);
518f0eb1 619
d62a17ae 620 name = map->name;
621 map->head = NULL;
518f0eb1 622
d62a17ae 623 /* Clear all dependencies */
624 route_map_clear_all_references(name);
e4694d0d 625 map->deleted = true;
d62a17ae 626 /* Execute deletion hook. */
627 if (route_map_master.delete_hook) {
628 (*route_map_master.delete_hook)(name);
629 route_map_notify_dependencies(name, RMAP_EVENT_CALL_DELETED);
630 }
718e3744 631
d62a17ae 632 if (!map->to_be_processed) {
633 route_map_free_map(map);
634 }
718e3744 635}
636
637/* Lookup route map by route map name string. */
d62a17ae 638struct route_map *route_map_lookup_by_name(const char *name)
718e3744 639{
d62a17ae 640 struct route_map *map;
641 struct route_map tmp_map;
718e3744 642
d62a17ae 643 if (!name)
644 return NULL;
518f0eb1 645
d62a17ae 646 // map.deleted is 0 via memset
647 memset(&tmp_map, 0, sizeof(struct route_map));
648 tmp_map.name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, name);
649 map = hash_lookup(route_map_master_hash, &tmp_map);
650 XFREE(MTYPE_ROUTE_MAP_NAME, tmp_map.name);
651 return map;
718e3744 652}
653
1de27621
DA
654/* Simple helper to warn if route-map does not exist. */
655struct route_map *route_map_lookup_warn_noexist(struct vty *vty, const char *name)
656{
657 struct route_map *route_map = route_map_lookup_by_name(name);
658
659 if (!route_map)
660 if (vty_shell_serv(vty))
661 vty_out(vty, "The route-map '%s' does not exist.\n", name);
662
663 return route_map;
664}
665
7096e938 666int route_map_mark_updated(const char *name)
518f0eb1 667{
d62a17ae 668 struct route_map *map;
669 int ret = -1;
670 struct route_map tmp_map;
518f0eb1 671
d62a17ae 672 if (!name)
673 return (ret);
a6e0d253 674
d62a17ae 675 map = route_map_lookup_by_name(name);
a6e0d253 676
e4694d0d
DS
677 /* If we did not find the routemap with deleted=false try again
678 * with deleted=true
d62a17ae 679 */
680 if (!map) {
681 memset(&tmp_map, 0, sizeof(struct route_map));
682 tmp_map.name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, name);
e4694d0d 683 tmp_map.deleted = true;
d62a17ae 684 map = hash_lookup(route_map_master_hash, &tmp_map);
685 XFREE(MTYPE_ROUTE_MAP_NAME, tmp_map.name);
686 }
a6e0d253 687
d62a17ae 688 if (map) {
e4694d0d 689 map->to_be_processed = true;
d62a17ae 690 ret = 0;
691 }
518f0eb1 692
d62a17ae 693 return (ret);
518f0eb1
DS
694}
695
69f02720 696static int route_map_clear_updated(struct route_map *map)
518f0eb1 697{
d62a17ae 698 int ret = -1;
518f0eb1 699
d62a17ae 700 if (map) {
e4694d0d 701 map->to_be_processed = false;
d62a17ae 702 if (map->deleted)
703 route_map_free_map(map);
704 }
518f0eb1 705
d62a17ae 706 return (ret);
518f0eb1
DS
707}
708
718e3744 709/* Lookup route map. If there isn't route map create one and return
710 it. */
a7282663 711struct route_map *route_map_get(const char *name)
718e3744 712{
d62a17ae 713 struct route_map *map;
718e3744 714
d62a17ae 715 map = route_map_lookup_by_name(name);
716 if (map == NULL)
717 map = route_map_add(name);
518f0eb1 718
d62a17ae 719 return map;
718e3744 720}
721
46a69f10 722void route_map_walk_update_list(void (*route_map_update_fn)(char *name))
518f0eb1 723{
d62a17ae 724 struct route_map *node;
725 struct route_map *nnode = NULL;
518f0eb1 726
d62a17ae 727 for (node = route_map_master.head; node; node = nnode) {
728 if (node->to_be_processed) {
729 /* DD: Should we add any thread yield code here */
730 route_map_update_fn(node->name);
731 nnode = node->next;
732 route_map_clear_updated(node);
733 } else
734 nnode = node->next;
518f0eb1 735 }
518f0eb1
DS
736}
737
718e3744 738/* Return route map's type string. */
d62a17ae 739static const char *route_map_type_str(enum route_map_type type)
740{
741 switch (type) {
742 case RMAP_PERMIT:
743 return "permit";
744 break;
745 case RMAP_DENY:
746 return "deny";
747 break;
ba1707ca 748 case RMAP_ANY:
d62a17ae 749 return "";
750 break;
751 }
4255dbe9
DS
752
753 return "";
718e3744 754}
755
b68885f9 756static const char *route_map_cmd_result_str(enum route_map_cmd_result_t res)
e3ab8170
AD
757{
758 switch (res) {
759 case RMAP_MATCH:
760 return "match";
e3ab8170
AD
761 case RMAP_NOMATCH:
762 return "no match";
b68885f9
LK
763 case RMAP_NOOP:
764 return "noop";
e3ab8170
AD
765 case RMAP_ERROR:
766 return "error";
767 case RMAP_OKAY:
768 return "okay";
769 }
770
771 return "invalid";
772}
773
b68885f9
LK
774static const char *route_map_result_str(route_map_result_t res)
775{
776 switch (res) {
777 case RMAP_DENYMATCH:
778 return "deny";
779 case RMAP_PERMITMATCH:
780 return "permit";
781 }
782
783 return "invalid";
784}
785
5510e83b 786/* show route-map */
d62a17ae 787static void vty_show_route_map_entry(struct vty *vty, struct route_map *map)
788{
789 struct route_map_index *index;
790 struct route_map_rule *rule;
791
279b0607 792 vty_out(vty, "route-map: %s Invoked: %" PRIu64 "\n",
1fa30509 793 map->name, map->applied - map->applied_clear);
d62a17ae 794
795 for (index = map->head; index; index = index->next) {
279b0607
DS
796 vty_out(vty, " %s, sequence %d Invoked %" PRIu64 "\n",
797 route_map_type_str(index->type), index->pref,
1fa30509 798 index->applied - index->applied_clear);
d62a17ae 799
800 /* Description */
801 if (index->description)
802 vty_out(vty, " Description:\n %s\n",
803 index->description);
804
805 /* Match clauses */
806 vty_out(vty, " Match clauses:\n");
807 for (rule = index->match_list.head; rule; rule = rule->next)
808 vty_out(vty, " %s %s\n", rule->cmd->str,
809 rule->rule_str);
810
811 vty_out(vty, " Set clauses:\n");
812 for (rule = index->set_list.head; rule; rule = rule->next)
813 vty_out(vty, " %s %s\n", rule->cmd->str,
814 rule->rule_str);
815
816 /* Call clause */
817 vty_out(vty, " Call clause:\n");
818 if (index->nextrm)
819 vty_out(vty, " Call %s\n", index->nextrm);
820
821 /* Exit Policy */
822 vty_out(vty, " Action:\n");
823 if (index->exitpolicy == RMAP_GOTO)
824 vty_out(vty, " Goto %d\n", index->nextpref);
825 else if (index->exitpolicy == RMAP_NEXT)
826 vty_out(vty, " Continue to next entry\n");
827 else if (index->exitpolicy == RMAP_EXIT)
828 vty_out(vty, " Exit routemap\n");
829 }
830}
831
78b1bb5f
QY
832static int sort_route_map(const void **map1, const void **map2)
833{
834 const struct route_map *m1 = *map1;
835 const struct route_map *m2 = *map2;
836
837 return strcmp(m1->name, m2->name);
838}
839
d62a17ae 840static int vty_show_route_map(struct vty *vty, const char *name)
841{
842 struct route_map *map;
843
279b0607
DS
844 vty_out(vty, "%s:\n", frr_protonameinst);
845
d62a17ae 846 if (name) {
847 map = route_map_lookup_by_name(name);
848
849 if (map) {
850 vty_show_route_map_entry(vty, map);
851 return CMD_SUCCESS;
852 } else {
853 vty_out(vty, "%s: 'route-map %s' not found\n",
854 frr_protonameinst, name);
855 return CMD_SUCCESS;
856 }
857 } else {
78b1bb5f
QY
858
859 struct list *maplist = list_new();
860 struct listnode *ln;
861
d62a17ae 862 for (map = route_map_master.head; map; map = map->next)
78b1bb5f
QY
863 listnode_add(maplist, map);
864
865 list_sort(maplist, sort_route_map);
866
867 for (ALL_LIST_ELEMENTS_RO(maplist, ln, map))
868 vty_show_route_map_entry(vty, map);
869
6a154c88 870 list_delete(&maplist);
d62a17ae 871 }
872 return CMD_SUCCESS;
5510e83b 873}
874
4a2a09d0 875/* Unused route map details */
876static int vty_show_unused_route_map(struct vty *vty)
877{
878 struct list *maplist = list_new();
879 struct listnode *ln;
880 struct route_map *map;
881
882 for (map = route_map_master.head; map; map = map->next) {
883 /* If use_count is zero, No protocol is using this routemap.
884 * so adding to the list.
885 */
886 if (!map->use_count)
887 listnode_add(maplist, map);
888 }
889
890 if (maplist->count > 0) {
891 vty_out(vty, "\n%s:\n", frr_protonameinst);
892 list_sort(maplist, sort_route_map);
893
894 for (ALL_LIST_ELEMENTS_RO(maplist, ln, map))
895 vty_show_route_map_entry(vty, map);
896 } else {
897 vty_out(vty, "\n%s: None\n", frr_protonameinst);
898 }
899
900 list_delete(&maplist);
901 return CMD_SUCCESS;
902}
5510e83b 903
718e3744 904/* New route map allocation. Please note route map's name must be
905 specified. */
d62a17ae 906static struct route_map_index *route_map_index_new(void)
718e3744 907{
d62a17ae 908 struct route_map_index *new;
718e3744 909
d62a17ae 910 new = XCALLOC(MTYPE_ROUTE_MAP_INDEX, sizeof(struct route_map_index));
911 new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */
54a35ff4 912 TAILQ_INIT(&new->rhclist);
d62a17ae 913 QOBJ_REG(new, route_map_index);
914 return new;
718e3744 915}
916
917/* Free route map index. */
a7282663 918void route_map_index_delete(struct route_map_index *index, int notify)
718e3744 919{
d62a17ae 920 struct route_map_rule *rule;
718e3744 921
d62a17ae 922 QOBJ_UNREG(index);
e80e7cce 923
e3ab8170
AD
924 if (rmap_debug)
925 zlog_debug("Deleting route-map %s sequence %d",
926 index->map->name, index->pref);
927
54a35ff4
RZ
928 /* Free route map northbound hook contexts. */
929 while (!TAILQ_EMPTY(&index->rhclist))
930 routemap_hook_context_free(TAILQ_FIRST(&index->rhclist));
931
d62a17ae 932 /* Free route match. */
933 while ((rule = index->match_list.head) != NULL)
934 route_map_rule_delete(&index->match_list, rule);
718e3744 935
d62a17ae 936 /* Free route set. */
937 while ((rule = index->set_list.head) != NULL)
938 route_map_rule_delete(&index->set_list, rule);
718e3744 939
d62a17ae 940 /* Remove index from route map list. */
941 if (index->next)
942 index->next->prev = index->prev;
943 else
944 index->map->tail = index->prev;
718e3744 945
d62a17ae 946 if (index->prev)
947 index->prev->next = index->next;
948 else
949 index->map->head = index->next;
718e3744 950
d62a17ae 951 /* Free 'char *nextrm' if not NULL */
0a22ddfb 952 XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
fee0f4c6 953
d62a17ae 954 /* Execute event hook. */
955 if (route_map_master.event_hook && notify) {
097b5973 956 (*route_map_master.event_hook)(index->map->name);
d62a17ae 957 route_map_notify_dependencies(index->map->name,
958 RMAP_EVENT_CALL_ADDED);
959 }
960 XFREE(MTYPE_ROUTE_MAP_INDEX, index);
718e3744 961}
962
963/* Lookup index from route map. */
d62a17ae 964static struct route_map_index *route_map_index_lookup(struct route_map *map,
965 enum route_map_type type,
966 int pref)
718e3744 967{
d62a17ae 968 struct route_map_index *index;
718e3744 969
d62a17ae 970 for (index = map->head; index; index = index->next)
971 if ((index->type == type || type == RMAP_ANY)
972 && index->pref == pref)
973 return index;
974 return NULL;
718e3744 975}
976
977/* Add new index to route map. */
8cc4198f 978static struct route_map_index *
d62a17ae 979route_map_index_add(struct route_map *map, enum route_map_type type, int pref)
980{
981 struct route_map_index *index;
982 struct route_map_index *point;
983
984 /* Allocate new route map inex. */
985 index = route_map_index_new();
986 index->map = map;
987 index->type = type;
988 index->pref = pref;
989
990 /* Compare preference. */
991 for (point = map->head; point; point = point->next)
992 if (point->pref >= pref)
993 break;
994
995 if (map->head == NULL) {
996 map->head = map->tail = index;
997 } else if (point == NULL) {
998 index->prev = map->tail;
999 map->tail->next = index;
1000 map->tail = index;
1001 } else if (point == map->head) {
1002 index->next = map->head;
1003 map->head->prev = index;
1004 map->head = index;
1005 } else {
1006 index->next = point;
1007 index->prev = point->prev;
1008 if (point->prev)
1009 point->prev->next = index;
1010 point->prev = index;
1011 }
1012
1013 /* Execute event hook. */
1014 if (route_map_master.event_hook) {
097b5973 1015 (*route_map_master.event_hook)(map->name);
d62a17ae 1016 route_map_notify_dependencies(map->name, RMAP_EVENT_CALL_ADDED);
1017 }
e3ab8170
AD
1018
1019 if (rmap_debug)
1020 zlog_debug("Route-map %s add sequence %d, type: %s",
1021 map->name, pref, route_map_type_str(type));
1022
d62a17ae 1023 return index;
718e3744 1024}
1025
1026/* Get route map index. */
a7282663 1027struct route_map_index *
d62a17ae 1028route_map_index_get(struct route_map *map, enum route_map_type type, int pref)
718e3744 1029{
d62a17ae 1030 struct route_map_index *index;
718e3744 1031
d62a17ae 1032 index = route_map_index_lookup(map, RMAP_ANY, pref);
1033 if (index && index->type != type) {
1034 /* Delete index from route map. */
1035 route_map_index_delete(index, 1);
1036 index = NULL;
1037 }
1038 if (index == NULL)
1039 index = route_map_index_add(map, type, pref);
1040 return index;
718e3744 1041}
1042
1043/* New route map rule */
d62a17ae 1044static struct route_map_rule *route_map_rule_new(void)
718e3744 1045{
d62a17ae 1046 struct route_map_rule *new;
718e3744 1047
d62a17ae 1048 new = XCALLOC(MTYPE_ROUTE_MAP_RULE, sizeof(struct route_map_rule));
1049 return new;
718e3744 1050}
6b0655a2 1051
718e3744 1052/* Install rule command to the match list. */
364deb04 1053void route_map_install_match(const struct route_map_rule_cmd *cmd)
718e3744 1054{
364deb04 1055 vector_set(route_match_vec, (void *)cmd);
718e3744 1056}
1057
1058/* Install rule command to the set list. */
364deb04 1059void route_map_install_set(const struct route_map_rule_cmd *cmd)
718e3744 1060{
364deb04 1061 vector_set(route_set_vec, (void *)cmd);
718e3744 1062}
1063
1064/* Lookup rule command from match list. */
364deb04 1065static const struct route_map_rule_cmd *route_map_lookup_match(const char *name)
718e3744 1066{
d62a17ae 1067 unsigned int i;
364deb04 1068 const struct route_map_rule_cmd *rule;
718e3744 1069
d62a17ae 1070 for (i = 0; i < vector_active(route_match_vec); i++)
1071 if ((rule = vector_slot(route_match_vec, i)) != NULL)
1072 if (strcmp(rule->str, name) == 0)
1073 return rule;
1074 return NULL;
718e3744 1075}
1076
1077/* Lookup rule command from set list. */
364deb04 1078static const struct route_map_rule_cmd *route_map_lookup_set(const char *name)
718e3744 1079{
d62a17ae 1080 unsigned int i;
364deb04 1081 const struct route_map_rule_cmd *rule;
718e3744 1082
d62a17ae 1083 for (i = 0; i < vector_active(route_set_vec); i++)
1084 if ((rule = vector_slot(route_set_vec, i)) != NULL)
1085 if (strcmp(rule->str, name) == 0)
1086 return rule;
1087 return NULL;
718e3744 1088}
1089
1090/* Add match and set rule to rule list. */
d62a17ae 1091static void route_map_rule_add(struct route_map_rule_list *list,
1092 struct route_map_rule *rule)
718e3744 1093{
d62a17ae 1094 rule->next = NULL;
1095 rule->prev = list->tail;
1096 if (list->tail)
1097 list->tail->next = rule;
1098 else
1099 list->head = rule;
1100 list->tail = rule;
718e3744 1101}
1102
1103/* Delete rule from rule list. */
d62a17ae 1104static void route_map_rule_delete(struct route_map_rule_list *list,
1105 struct route_map_rule *rule)
718e3744 1106{
d62a17ae 1107 if (rule->cmd->func_free)
1108 (*rule->cmd->func_free)(rule->value);
718e3744 1109
0a22ddfb 1110 XFREE(MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str);
718e3744 1111
d62a17ae 1112 if (rule->next)
1113 rule->next->prev = rule->prev;
1114 else
1115 list->tail = rule->prev;
1116 if (rule->prev)
1117 rule->prev->next = rule->next;
1118 else
1119 list->head = rule->next;
718e3744 1120
d62a17ae 1121 XFREE(MTYPE_ROUTE_MAP_RULE, rule);
718e3744 1122}
1123
1124/* strcmp wrapper function which don't crush even argument is NULL. */
d62a17ae 1125static int rulecmp(const char *dst, const char *src)
1126{
1127 if (dst == NULL) {
1128 if (src == NULL)
1129 return 0;
1130 else
1131 return 1;
1132 } else {
1133 if (src == NULL)
1134 return 1;
1135 else
1136 return strcmp(dst, src);
1137 }
718e3744 1138 return 1;
718e3744 1139}
1140
518f0eb1
DS
1141/* Use this to return the already specified argument for this match. This is
1142 * useful to get the specified argument with a route map match rule when the
1143 * rule is being deleted and the argument is not provided.
1144 */
d62a17ae 1145const char *route_map_get_match_arg(struct route_map_index *index,
1146 const char *match_name)
518f0eb1 1147{
d62a17ae 1148 struct route_map_rule *rule;
364deb04 1149 const struct route_map_rule_cmd *cmd;
518f0eb1 1150
d62a17ae 1151 /* First lookup rule for add match statement. */
1152 cmd = route_map_lookup_match(match_name);
1153 if (cmd == NULL)
1154 return NULL;
518f0eb1 1155
d62a17ae 1156 for (rule = index->match_list.head; rule; rule = rule->next)
1157 if (rule->cmd == cmd && rule->rule_str != NULL)
1158 return (rule->rule_str);
518f0eb1 1159
d62a17ae 1160 return (NULL);
518f0eb1
DS
1161}
1162
e2c8d6ce
NT
1163static route_map_event_t get_route_map_delete_event(route_map_event_t type)
1164{
1165 switch (type) {
1166 case RMAP_EVENT_CALL_ADDED:
1167 return RMAP_EVENT_CALL_DELETED;
1168 case RMAP_EVENT_PLIST_ADDED:
1169 return RMAP_EVENT_PLIST_DELETED;
1170 case RMAP_EVENT_CLIST_ADDED:
1171 return RMAP_EVENT_CLIST_DELETED;
1172 case RMAP_EVENT_ECLIST_ADDED:
1173 return RMAP_EVENT_ECLIST_DELETED;
1174 case RMAP_EVENT_LLIST_ADDED:
1175 return RMAP_EVENT_LLIST_DELETED;
1176 case RMAP_EVENT_ASLIST_ADDED:
1177 return RMAP_EVENT_ASLIST_DELETED;
1178 case RMAP_EVENT_FILTER_ADDED:
1179 return RMAP_EVENT_FILTER_DELETED;
1180 case RMAP_EVENT_SET_ADDED:
1181 case RMAP_EVENT_SET_DELETED:
1182 case RMAP_EVENT_SET_REPLACED:
1183 case RMAP_EVENT_MATCH_ADDED:
1184 case RMAP_EVENT_MATCH_DELETED:
1185 case RMAP_EVENT_MATCH_REPLACED:
1186 case RMAP_EVENT_INDEX_ADDED:
1187 case RMAP_EVENT_INDEX_DELETED:
1188 case RMAP_EVENT_CALL_DELETED:
1189 case RMAP_EVENT_PLIST_DELETED:
1190 case RMAP_EVENT_CLIST_DELETED:
1191 case RMAP_EVENT_ECLIST_DELETED:
1192 case RMAP_EVENT_LLIST_DELETED:
1193 case RMAP_EVENT_ASLIST_DELETED:
1194 case RMAP_EVENT_FILTER_DELETED:
1195 /* This function returns the appropriate 'deleted' event type
1196 * for every 'added' event type passed to this function.
1197 * This is done only for named entities used in the
1198 * route-map match commands.
1199 * This function is not to be invoked for any of the other event
1200 * types.
1201 */
1202 assert(0);
1203 }
f232dd29
DS
1204
1205 assert(0);
1206 /*
1207 * Return to make c happy but if we get here something has gone
1208 * terribly terribly wrong, so yes this return makes no sense.
1209 */
1210 return RMAP_EVENT_CALL_ADDED;
e2c8d6ce
NT
1211}
1212
718e3744 1213/* Add match statement to route map. */
cda7187d
DS
1214enum rmap_compile_rets route_map_add_match(struct route_map_index *index,
1215 const char *match_name,
1216 const char *match_arg,
1217 route_map_event_t type)
d62a17ae 1218{
1219 struct route_map_rule *rule;
1220 struct route_map_rule *next;
364deb04 1221 const struct route_map_rule_cmd *cmd;
d62a17ae 1222 void *compile;
e2c8d6ce 1223 int8_t delete_rmap_event_type = 0;
909f3d56 1224 const char *rule_key;
d62a17ae 1225
1226 /* First lookup rule for add match statement. */
1227 cmd = route_map_lookup_match(match_name);
1228 if (cmd == NULL)
1229 return RMAP_RULE_MISSING;
1230
1231 /* Next call compile function for this match statement. */
1232 if (cmd->func_compile) {
1233 compile = (*cmd->func_compile)(match_arg);
1234 if (compile == NULL)
1235 return RMAP_COMPILE_ERROR;
1236 } else
1237 compile = NULL;
909f3d56 1238 /* use the compiled results if applicable */
1239 if (compile && cmd->func_get_rmap_rule_key)
1240 rule_key = (*cmd->func_get_rmap_rule_key)
1241 (compile);
1242 else
1243 rule_key = match_arg;
d62a17ae 1244
1245 /* If argument is completely same ignore it. */
1246 for (rule = index->match_list.head; rule; rule = next) {
1247 next = rule->next;
1248 if (rule->cmd == cmd) {
6c3247bd
NT
1249 /* If the configured route-map match rule is exactly
1250 * the same as the existing configuration then,
1251 * ignore the duplicate configuration.
1252 */
1253 if (strcmp(match_arg, rule->rule_str) == 0) {
1254 if (cmd->func_free)
1255 (*cmd->func_free)(compile);
e2c8d6ce 1256
909f3d56 1257 return RMAP_COMPILE_SUCCESS;
e2c8d6ce
NT
1258 }
1259
1260 /* Remove the dependency of the route-map on the rule
1261 * that is being replaced.
1262 */
1263 if (type >= RMAP_EVENT_CALL_ADDED) {
1264 delete_rmap_event_type =
1265 get_route_map_delete_event(type);
1266 route_map_upd8_dependency(
1267 delete_rmap_event_type,
909f3d56 1268 rule_key,
e2c8d6ce 1269 index->map->name);
6c3247bd
NT
1270 }
1271
d62a17ae 1272 route_map_rule_delete(&index->match_list, rule);
d62a17ae 1273 }
718e3744 1274 }
718e3744 1275
d62a17ae 1276 /* Add new route map match rule. */
1277 rule = route_map_rule_new();
1278 rule->cmd = cmd;
1279 rule->value = compile;
1280 if (match_arg)
1281 rule->rule_str = XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR, match_arg);
1282 else
1283 rule->rule_str = NULL;
718e3744 1284
d62a17ae 1285 /* Add new route match rule to linked list. */
1286 route_map_rule_add(&index->match_list, rule);
718e3744 1287
d62a17ae 1288 /* Execute event hook. */
1289 if (route_map_master.event_hook) {
097b5973 1290 (*route_map_master.event_hook)(index->map->name);
d62a17ae 1291 route_map_notify_dependencies(index->map->name,
1292 RMAP_EVENT_CALL_ADDED);
1293 }
909f3d56 1294 if (type != RMAP_EVENT_MATCH_ADDED)
1295 route_map_upd8_dependency(type, rule_key, index->map->name);
718e3744 1296
9ca25fed 1297 return RMAP_COMPILE_SUCCESS;
718e3744 1298}
1299
1300/* Delete specified route match rule. */
cda7187d
DS
1301enum rmap_compile_rets route_map_delete_match(struct route_map_index *index,
1302 const char *match_name,
909f3d56 1303 const char *match_arg,
1304 route_map_event_t type)
d62a17ae 1305{
1306 struct route_map_rule *rule;
364deb04 1307 const struct route_map_rule_cmd *cmd;
909f3d56 1308 const char *rule_key;
d62a17ae 1309
1310 cmd = route_map_lookup_match(match_name);
1311 if (cmd == NULL)
e5b4b49e 1312 return RMAP_RULE_MISSING;
d62a17ae 1313
1314 for (rule = index->match_list.head; rule; rule = rule->next)
9d303b37
DL
1315 if (rule->cmd == cmd && (rulecmp(rule->rule_str, match_arg) == 0
1316 || match_arg == NULL)) {
d62a17ae 1317 /* Execute event hook. */
1318 if (route_map_master.event_hook) {
097b5973 1319 (*route_map_master.event_hook)(index->map->name);
d62a17ae 1320 route_map_notify_dependencies(
1321 index->map->name,
1322 RMAP_EVENT_CALL_ADDED);
1323 }
909f3d56 1324 if (cmd->func_get_rmap_rule_key)
1325 rule_key = (*cmd->func_get_rmap_rule_key)
1326 (rule->value);
1327 else
1328 rule_key = match_arg;
1329
1330 if (type != RMAP_EVENT_MATCH_DELETED && rule_key)
1331 route_map_upd8_dependency(type, rule_key,
1332 index->map->name);
1333
1334 route_map_rule_delete(&index->match_list, rule);
e5b4b49e 1335 return RMAP_COMPILE_SUCCESS;
d62a17ae 1336 }
1337 /* Can't find matched rule. */
e5b4b49e 1338 return RMAP_RULE_MISSING;
718e3744 1339}
1340
1341/* Add route-map set statement to the route map. */
cda7187d
DS
1342enum rmap_compile_rets route_map_add_set(struct route_map_index *index,
1343 const char *set_name,
1344 const char *set_arg)
d62a17ae 1345{
1346 struct route_map_rule *rule;
1347 struct route_map_rule *next;
364deb04 1348 const struct route_map_rule_cmd *cmd;
d62a17ae 1349 void *compile;
d62a17ae 1350
1351 cmd = route_map_lookup_set(set_name);
1352 if (cmd == NULL)
1353 return RMAP_RULE_MISSING;
1354
1355 /* Next call compile function for this match statement. */
1356 if (cmd->func_compile) {
1357 compile = (*cmd->func_compile)(set_arg);
1358 if (compile == NULL)
1359 return RMAP_COMPILE_ERROR;
1360 } else
1361 compile = NULL;
1362
1363 /* Add by WJL. if old set command of same kind exist, delete it first
1364 to ensure only one set command of same kind exist under a
1365 route_map_index. */
1366 for (rule = index->set_list.head; rule; rule = next) {
1367 next = rule->next;
4255dbe9 1368 if (rule->cmd == cmd)
d62a17ae 1369 route_map_rule_delete(&index->set_list, rule);
d62a17ae 1370 }
1371
1372 /* Add new route map match rule. */
1373 rule = route_map_rule_new();
1374 rule->cmd = cmd;
1375 rule->value = compile;
1376 if (set_arg)
1377 rule->rule_str = XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR, set_arg);
1378 else
1379 rule->rule_str = NULL;
1380
1381 /* Add new route match rule to linked list. */
1382 route_map_rule_add(&index->set_list, rule);
1383
1384 /* Execute event hook. */
1385 if (route_map_master.event_hook) {
097b5973 1386 (*route_map_master.event_hook)(index->map->name);
d62a17ae 1387 route_map_notify_dependencies(index->map->name,
1388 RMAP_EVENT_CALL_ADDED);
718e3744 1389 }
9ca25fed 1390 return RMAP_COMPILE_SUCCESS;
718e3744 1391}
1392
1393/* Delete route map set rule. */
cda7187d
DS
1394enum rmap_compile_rets route_map_delete_set(struct route_map_index *index,
1395 const char *set_name,
1396 const char *set_arg)
d62a17ae 1397{
1398 struct route_map_rule *rule;
364deb04 1399 const struct route_map_rule_cmd *cmd;
d62a17ae 1400
1401 cmd = route_map_lookup_set(set_name);
1402 if (cmd == NULL)
e5b4b49e 1403 return RMAP_RULE_MISSING;
d62a17ae 1404
1405 for (rule = index->set_list.head; rule; rule = rule->next)
9d303b37
DL
1406 if ((rule->cmd == cmd) && (rulecmp(rule->rule_str, set_arg) == 0
1407 || set_arg == NULL)) {
d62a17ae 1408 route_map_rule_delete(&index->set_list, rule);
1409 /* Execute event hook. */
1410 if (route_map_master.event_hook) {
097b5973 1411 (*route_map_master.event_hook)(index->map->name);
d62a17ae 1412 route_map_notify_dependencies(
1413 index->map->name,
1414 RMAP_EVENT_CALL_ADDED);
1415 }
e5b4b49e 1416 return RMAP_COMPILE_SUCCESS;
d62a17ae 1417 }
1418 /* Can't find matched rule. */
e5b4b49e 1419 return RMAP_RULE_MISSING;
718e3744 1420}
1421
b68885f9
LK
1422static enum route_map_cmd_result_t
1423route_map_apply_match(struct route_map_rule_list *match_list,
1424 const struct prefix *prefix, route_map_object_t type,
1425 void *object)
1426{
1427 enum route_map_cmd_result_t ret = RMAP_NOMATCH;
1428 struct route_map_rule *match;
1429 bool is_matched = false;
1430
1431
1432 /* Check all match rule and if there is no match rule, go to the
1433 set statement. */
1434 if (!match_list->head)
1435 ret = RMAP_MATCH;
1436 else {
1437 for (match = match_list->head; match; match = match->next) {
1438 /*
1439 * Try each match statement. If any match does not
1440 * return RMAP_MATCH or RMAP_NOOP, return.
1441 * Otherwise continue on to next match statement.
1442 * All match statements must MATCH for
1443 * end-result to be a match.
1444 * (Exception:If match stmts result in a mix of
1445 * MATCH/NOOP, then also end-result is a match)
1446 * If all result in NOOP, end-result is NOOP.
1447 */
1448 ret = (*match->cmd->func_apply)(match->value, prefix,
1449 type, object);
1450
1451 /*
1452 * If the consolidated result of func_apply is:
1453 * -----------------------------------------------
1454 * | MATCH | NOMATCH | NOOP | Final Result |
1455 * ------------------------------------------------
1456 * | yes | yes | yes | NOMATCH |
1457 * | no | no | yes | NOOP |
1458 * | yes | no | yes | MATCH |
1459 * | no | yes | yes | NOMATCH |
1460 * |-----------------------------------------------
1461 *
1462 * Traditionally, all rules within route-map
1463 * should match for it to MATCH.
1464 * If there are noops within the route-map rules,
1465 * it follows the above matrix.
1466 *
1467 * Eg: route-map rm1 permit 10
1468 * match rule1
1469 * match rule2
1470 * match rule3
1471 * ....
1472 * route-map rm1 permit 20
1473 * match ruleX
1474 * match ruleY
1475 * ...
1476 */
1477
1478 switch (ret) {
1479 case RMAP_MATCH:
1480 is_matched = true;
1481 break;
1482
1483 case RMAP_NOMATCH:
1484 return ret;
1485
1486 case RMAP_NOOP:
1487 if (is_matched)
1488 ret = RMAP_MATCH;
1489 break;
1490
1491 default:
1492 break;
1493 }
1494
1495 }
1496 }
1497 return ret;
1498}
1499
3bf1c917 1500/* Apply route map's each index to the object.
1501
1502 The matrix for a route-map looks like this:
1503 (note, this includes the description for the "NEXT"
1504 and "GOTO" frobs now
d62a17ae 1505
b68885f9
LK
1506 | Match | No Match | No op
1507 |-----------|--------------|-------
1508 permit | action | cont | cont.
1509 | | default:deny | default:permit
1510 -------------------+-----------------------
1511 | deny | cont | cont.
1512 deny | | default:deny | default:permit
1513 |-----------|--------------|--------
d62a17ae 1514
fee0f4c6 1515 action)
1516 -Apply Set statements, accept route
1517 -If Call statement is present jump to the specified route-map, if it
d62a17ae 1518 denies the route we finish.
fee0f4c6 1519 -If NEXT is specified, goto NEXT statement
1520 -If GOTO is specified, goto the first clause where pref > nextpref
1521 -If nothing is specified, do as Cisco and finish
1522 deny)
1523 -Route is denied by route-map.
1524 cont)
1525 -Goto Next index
d62a17ae 1526
3bf1c917 1527 If we get no matches after we've processed all updates, then the route
1528 is dropped too.
d62a17ae 1529
fee0f4c6 1530 Some notes on the new "CALL", "NEXT" and "GOTO"
1531 call WORD - If this clause is matched, then the set statements
d62a17ae 1532 are executed and then we jump to route-map 'WORD'. If
1533 this route-map denies the route, we finish, in other
1534 case we
1535 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
3bf1c917 1536 on-match next - If this clause is matched, then the set statements
d62a17ae 1537 are executed and then we drop through to the next clause
3bf1c917 1538 on-match goto n - If this clause is matched, then the set statments
d62a17ae 1539 are executed and then we goto the nth clause, or the
1540 first clause greater than this. In order to ensure
1541 route-maps *always* exit, you cannot jump backwards.
1542 Sorry ;)
1543
3bf1c917 1544 We need to make sure our route-map processing matches the above
718e3744 1545*/
123214ef
MS
1546route_map_result_t route_map_apply(struct route_map *map,
1547 const struct prefix *prefix,
d62a17ae 1548 route_map_object_t type, void *object)
1549{
1550 static int recursion = 0;
b68885f9
LK
1551 enum route_map_cmd_result_t match_ret = RMAP_NOMATCH;
1552 route_map_result_t ret = RMAP_PERMITMATCH;
d62a17ae 1553 struct route_map_index *index;
1554 struct route_map_rule *set;
e3ab8170 1555 char buf[PREFIX_STRLEN];
d62a17ae 1556
1557 if (recursion > RMAP_RECURSION_LIMIT) {
040c7c3a 1558 flog_warn(
450971aa 1559 EC_LIB_RMAP_RECURSION_LIMIT,
d62a17ae 1560 "route-map recursion limit (%d) reached, discarding route",
1561 RMAP_RECURSION_LIMIT);
1562 recursion = 0;
1563 return RMAP_DENYMATCH;
1564 }
1565
b68885f9 1566 if (map == NULL || map->head == NULL) {
e3ab8170
AD
1567 ret = RMAP_DENYMATCH;
1568 goto route_map_apply_end;
1569 }
d62a17ae 1570
279b0607 1571 map->applied++;
d62a17ae 1572 for (index = map->head; index; index = index->next) {
1573 /* Apply this index. */
279b0607 1574 index->applied++;
b68885f9
LK
1575 match_ret = route_map_apply_match(&index->match_list, prefix,
1576 type, object);
d62a17ae 1577
e3ab8170
AD
1578 if (rmap_debug) {
1579 zlog_debug("Route-map: %s, sequence: %d, prefix: %s, result: %s",
1580 map->name, index->pref,
1581 prefix2str(prefix, buf, sizeof(buf)),
b68885f9 1582 route_map_cmd_result_str(match_ret));
e3ab8170
AD
1583 }
1584
d62a17ae 1585 /* Now we apply the matrix from above */
b68885f9
LK
1586 if (match_ret == RMAP_NOOP)
1587 /*
1588 * Do not change the return value. Retain the previous
1589 * return value. Previous values can be:
1590 * 1)permitmatch (if a nomatch was never
1591 * seen before in this route-map.)
1592 * 2)denymatch (if a nomatch was seen earlier in one
1593 * of the previous sequences)
1594 */
1595
1596 /*
1597 * 'cont' from matrix - continue to next route-map
1598 * sequence
1599 */
d62a17ae 1600 continue;
b68885f9
LK
1601 else if (match_ret == RMAP_NOMATCH) {
1602
1603 /*
1604 * The return value is now changed to denymatch.
1605 * So from here on out, even if we see more noops,
1606 * we retain this return value and return this
1607 * eventually if there are no matches.
1608 */
1609 ret = RMAP_DENYMATCH;
1610
1611 /*
1612 * 'cont' from matrix - continue to next route-map
1613 * sequence
1614 */
1615 continue;
1616 } else if (match_ret == RMAP_MATCH) {
d62a17ae 1617 if (index->type == RMAP_PERMIT)
1618 /* 'action' */
1619 {
b68885f9
LK
1620 /* Match succeeded, rmap is of type permit */
1621 ret = RMAP_PERMITMATCH;
1622
d62a17ae 1623 /* permit+match must execute sets */
1624 for (set = index->set_list.head; set;
1625 set = set->next)
b68885f9
LK
1626 /*
1627 * set cmds return RMAP_OKAY or
1628 * RMAP_ERROR. We do not care if
1629 * set succeeded or not. So, ignore
1630 * return code.
1631 */
1632 (void) (*set->cmd->func_apply)(
2789041a
LK
1633 set->value, prefix, type,
1634 object);
d62a17ae 1635
1636 /* Call another route-map if available */
1637 if (index->nextrm) {
1638 struct route_map *nextrm =
1639 route_map_lookup_by_name(
1640 index->nextrm);
1641
1642 if (nextrm) /* Target route-map found,
1643 jump to it */
1644 {
1645 recursion++;
1646 ret = route_map_apply(
1647 nextrm, prefix, type,
1648 object);
1649 recursion--;
1650 }
1651
1652 /* If nextrm returned 'deny', finish. */
1653 if (ret == RMAP_DENYMATCH)
e3ab8170 1654 goto route_map_apply_end;
d62a17ae 1655 }
1656
1657 switch (index->exitpolicy) {
1658 case RMAP_EXIT:
e3ab8170 1659 goto route_map_apply_end;
d62a17ae 1660 case RMAP_NEXT:
1661 continue;
1662 case RMAP_GOTO: {
1663 /* Find the next clause to jump to */
1664 struct route_map_index *next =
1665 index->next;
1666 int nextpref = index->nextpref;
1667
1668 while (next && next->pref < nextpref) {
1669 index = next;
1670 next = next->next;
1671 }
1672 if (next == NULL) {
1673 /* No clauses match! */
e3ab8170 1674 goto route_map_apply_end;
d62a17ae 1675 }
1676 }
1677 }
1678 } else if (index->type == RMAP_DENY)
1679 /* 'deny' */
1680 {
e3ab8170
AD
1681 ret = RMAP_DENYMATCH;
1682 goto route_map_apply_end;
d62a17ae 1683 }
1684 }
1685 }
e3ab8170
AD
1686
1687route_map_apply_end:
1688 if (rmap_debug) {
1689 zlog_debug("Route-map: %s, prefix: %s, result: %s",
1690 (map ? map->name : "null"),
1691 prefix2str(prefix, buf, sizeof(buf)),
1692 route_map_result_str(ret));
1693 }
1694
1695 return (ret);
d62a17ae 1696}
1697
1698void route_map_add_hook(void (*func)(const char *))
1699{
1700 route_map_master.add_hook = func;
1701}
1702
1703void route_map_delete_hook(void (*func)(const char *))
1704{
1705 route_map_master.delete_hook = func;
1706}
1707
097b5973 1708void route_map_event_hook(void (*func)(const char *name))
d62a17ae 1709{
1710 route_map_master.event_hook = func;
718e3744 1711}
1712
518f0eb1 1713/* Routines for route map dependency lists and dependency processing */
74df8d6d 1714static bool route_map_rmap_hash_cmp(const void *p1, const void *p2)
518f0eb1 1715{
e2c8d6ce
NT
1716 return strcmp(((const struct route_map_dep_data *)p1)->rname,
1717 ((const struct route_map_dep_data *)p2)->rname)
1718 == 0;
518f0eb1
DS
1719}
1720
74df8d6d 1721static bool route_map_dep_hash_cmp(const void *p1, const void *p2)
518f0eb1
DS
1722{
1723
d62a17ae 1724 return (strcmp(((const struct route_map_dep *)p1)->dep_name,
1725 (const char *)p2)
1726 == 0);
518f0eb1
DS
1727}
1728
e3b78da8 1729static void route_map_clear_reference(struct hash_bucket *bucket, void *arg)
518f0eb1 1730{
e2c8d6ce
NT
1731 struct route_map_dep *dep = bucket->data;
1732 struct route_map_dep_data *dep_data = NULL, tmp_dep_data;
518f0eb1 1733
1fae5ff2 1734 if (arg) {
e2c8d6ce
NT
1735 memset(&tmp_dep_data, 0, sizeof(struct route_map_dep_data));
1736 tmp_dep_data.rname = arg;
1737 dep_data = hash_release(dep->dep_rmap_hash,
1738 &tmp_dep_data);
1739 if (dep_data) {
1740 XFREE(MTYPE_ROUTE_MAP_NAME, dep_data->rname);
1741 XFREE(MTYPE_ROUTE_MAP_DEP_DATA, dep_data);
d62a17ae 1742 }
1743 if (!dep->dep_rmap_hash->count) {
1744 dep = hash_release(dep->this_hash,
1745 (void *)dep->dep_name);
1746 hash_free(dep->dep_rmap_hash);
1747 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
1748 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
1749 }
518f0eb1 1750 }
d62a17ae 1751}
1752
1753static void route_map_clear_all_references(char *rmap_name)
1754{
1755 int i;
1756
1757 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
1758 hash_iterate(route_map_dep_hash[i], route_map_clear_reference,
1759 (void *)rmap_name);
518f0eb1 1760 }
518f0eb1
DS
1761}
1762
e2c8d6ce
NT
1763static unsigned int route_map_dep_data_hash_make_key(const void *p)
1764{
1765 const struct route_map_dep_data *dep_data = p;
1766
1767 return string_hash_make(dep_data->rname);
1768}
1769
d62a17ae 1770static void *route_map_dep_hash_alloc(void *p)
518f0eb1 1771{
d62a17ae 1772 char *dep_name = (char *)p;
1773 struct route_map_dep *dep_entry;
1774
1775 dep_entry = XCALLOC(MTYPE_ROUTE_MAP_DEP, sizeof(struct route_map_dep));
1776 dep_entry->dep_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
996c9314 1777 dep_entry->dep_rmap_hash =
e2c8d6ce 1778 hash_create_size(8, route_map_dep_data_hash_make_key,
996c9314 1779 route_map_rmap_hash_cmp, "Route Map Dep Hash");
d62a17ae 1780 dep_entry->this_hash = NULL;
1781
e2c8d6ce 1782 return dep_entry;
d62a17ae 1783}
518f0eb1 1784
d62a17ae 1785static void *route_map_name_hash_alloc(void *p)
1786{
e2c8d6ce
NT
1787 struct route_map_dep_data *dep_data = NULL, *tmp_dep_data = NULL;
1788
1789 dep_data = XCALLOC(MTYPE_ROUTE_MAP_DEP_DATA,
1790 sizeof(struct route_map_dep_data));
1791 tmp_dep_data = p;
1792 dep_data->rname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, tmp_dep_data->rname);
1793 return dep_data;
518f0eb1
DS
1794}
1795
d8b87afe 1796static unsigned int route_map_dep_hash_make_key(const void *p)
518f0eb1 1797{
d62a17ae 1798 return (string_hash_make((char *)p));
1799}
518f0eb1 1800
e3b78da8 1801static void route_map_print_dependency(struct hash_bucket *bucket, void *data)
d62a17ae 1802{
e2c8d6ce
NT
1803 struct route_map_dep_data *dep_data = bucket->data;
1804 char *rmap_name = dep_data->rname;
1805 char *dep_name = data;
518f0eb1 1806
1fae5ff2
DS
1807 zlog_debug("%s: Dependency for %s: %s", __FUNCTION__, dep_name,
1808 rmap_name);
518f0eb1
DS
1809}
1810
d62a17ae 1811static int route_map_dep_update(struct hash *dephash, const char *dep_name,
1812 const char *rmap_name, route_map_event_t type)
518f0eb1 1813{
d62a17ae 1814 struct route_map_dep *dep = NULL;
d62a17ae 1815 char *dname, *rname;
1816 int ret = 0;
e2c8d6ce
NT
1817 struct route_map_dep_data *dep_data = NULL, *ret_dep_data = NULL;
1818 struct route_map_dep_data tmp_dep_data;
d62a17ae 1819
1820 dname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
1821 rname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_name);
1822
1823 switch (type) {
1824 case RMAP_EVENT_PLIST_ADDED:
1825 case RMAP_EVENT_CLIST_ADDED:
1826 case RMAP_EVENT_ECLIST_ADDED:
1827 case RMAP_EVENT_ASLIST_ADDED:
1828 case RMAP_EVENT_LLIST_ADDED:
1829 case RMAP_EVENT_CALL_ADDED:
1830 case RMAP_EVENT_FILTER_ADDED:
1831 if (rmap_debug)
e3ab8170
AD
1832 zlog_debug("Adding dependency for filter %s in route-map %s",
1833 dep_name, rmap_name);
d62a17ae 1834 dep = (struct route_map_dep *)hash_get(
1835 dephash, dname, route_map_dep_hash_alloc);
1836 if (!dep) {
1837 ret = -1;
1838 goto out;
1839 }
1840
1841 if (!dep->this_hash)
1842 dep->this_hash = dephash;
1843
e2c8d6ce
NT
1844 memset(&tmp_dep_data, 0, sizeof(struct route_map_dep_data));
1845 tmp_dep_data.rname = rname;
1846 dep_data = hash_lookup(dep->dep_rmap_hash, &tmp_dep_data);
1847 if (!dep_data)
1848 dep_data = hash_get(dep->dep_rmap_hash, &tmp_dep_data,
1849 route_map_name_hash_alloc);
1850
1851 dep_data->refcnt++;
d62a17ae 1852 break;
1853 case RMAP_EVENT_PLIST_DELETED:
1854 case RMAP_EVENT_CLIST_DELETED:
1855 case RMAP_EVENT_ECLIST_DELETED:
1856 case RMAP_EVENT_ASLIST_DELETED:
1857 case RMAP_EVENT_LLIST_DELETED:
1858 case RMAP_EVENT_CALL_DELETED:
1859 case RMAP_EVENT_FILTER_DELETED:
1860 if (rmap_debug)
e3ab8170
AD
1861 zlog_debug("Deleting dependency for filter %s in route-map %s",
1862 dep_name, rmap_name);
d62a17ae 1863 dep = (struct route_map_dep *)hash_get(dephash, dname, NULL);
1864 if (!dep) {
1865 goto out;
1866 }
1867
e2c8d6ce
NT
1868 memset(&tmp_dep_data, 0, sizeof(struct route_map_dep_data));
1869 tmp_dep_data.rname = rname;
1870 dep_data = hash_lookup(dep->dep_rmap_hash, &tmp_dep_data);
1871 dep_data->refcnt--;
1872
1873 if (!dep_data->refcnt) {
1874 ret_dep_data = hash_release(dep->dep_rmap_hash,
1875 &tmp_dep_data);
1876 if (ret_dep_data) {
1877 XFREE(MTYPE_ROUTE_MAP_NAME,
1878 ret_dep_data->rname);
1879 XFREE(MTYPE_ROUTE_MAP_DEP_DATA, ret_dep_data);
1880 }
1881 }
d62a17ae 1882
1883 if (!dep->dep_rmap_hash->count) {
1884 dep = hash_release(dephash, dname);
1885 hash_free(dep->dep_rmap_hash);
1886 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
1887 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
d62a17ae 1888 }
1889 break;
ba1707ca
DS
1890 case RMAP_EVENT_SET_ADDED:
1891 case RMAP_EVENT_SET_DELETED:
1892 case RMAP_EVENT_SET_REPLACED:
1893 case RMAP_EVENT_MATCH_ADDED:
1894 case RMAP_EVENT_MATCH_DELETED:
1895 case RMAP_EVENT_MATCH_REPLACED:
1896 case RMAP_EVENT_INDEX_ADDED:
1897 case RMAP_EVENT_INDEX_DELETED:
d62a17ae 1898 break;
1899 }
1900
1901 if (dep) {
1902 if (rmap_debug)
1903 hash_iterate(dep->dep_rmap_hash,
1904 route_map_print_dependency, dname);
1905 }
1906
1907out:
1908 XFREE(MTYPE_ROUTE_MAP_NAME, rname);
1909 XFREE(MTYPE_ROUTE_MAP_NAME, dname);
1910 return ret;
1911}
1912
1913static struct hash *route_map_get_dep_hash(route_map_event_t event)
1914{
1915 struct hash *upd8_hash = NULL;
1916
1917 switch (event) {
1918 case RMAP_EVENT_PLIST_ADDED:
1919 case RMAP_EVENT_PLIST_DELETED:
1920 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_PLIST];
1921 break;
1922 case RMAP_EVENT_CLIST_ADDED:
1923 case RMAP_EVENT_CLIST_DELETED:
1924 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_CLIST];
1925 break;
1926 case RMAP_EVENT_ECLIST_ADDED:
1927 case RMAP_EVENT_ECLIST_DELETED:
1928 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ECLIST];
1929 break;
1930 case RMAP_EVENT_ASLIST_ADDED:
1931 case RMAP_EVENT_ASLIST_DELETED:
1932 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ASPATH];
1933 break;
1934 case RMAP_EVENT_LLIST_ADDED:
1935 case RMAP_EVENT_LLIST_DELETED:
1936 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_LCLIST];
1937 break;
1938 case RMAP_EVENT_CALL_ADDED:
1939 case RMAP_EVENT_CALL_DELETED:
5ed2e47b 1940 case RMAP_EVENT_MATCH_ADDED:
1941 case RMAP_EVENT_MATCH_DELETED:
d62a17ae 1942 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_RMAP];
1943 break;
1944 case RMAP_EVENT_FILTER_ADDED:
1945 case RMAP_EVENT_FILTER_DELETED:
1946 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_FILTER];
1947 break;
ba1707ca
DS
1948 /*
1949 * Should we actually be ignoring these?
1950 * I am not sure but at this point in time, let
1951 * us get them into this switch and we can peel
1952 * them into the appropriate place in the future
1953 */
1954 case RMAP_EVENT_SET_ADDED:
1955 case RMAP_EVENT_SET_DELETED:
1956 case RMAP_EVENT_SET_REPLACED:
1957 case RMAP_EVENT_MATCH_REPLACED:
1958 case RMAP_EVENT_INDEX_ADDED:
1959 case RMAP_EVENT_INDEX_DELETED:
d62a17ae 1960 upd8_hash = NULL;
1961 break;
1962 }
1963 return (upd8_hash);
518f0eb1
DS
1964}
1965
e3b78da8 1966static void route_map_process_dependency(struct hash_bucket *bucket, void *data)
518f0eb1 1967{
e2c8d6ce
NT
1968 struct route_map_dep_data *dep_data = NULL;
1969 char *rmap_name = NULL;
1970
1971 dep_data = bucket->data;
1972 rmap_name = dep_data->rname;
d62a17ae 1973
1fae5ff2 1974 if (rmap_debug)
e3ab8170 1975 zlog_debug("Notifying %s of dependency", rmap_name);
1fae5ff2 1976 if (route_map_master.event_hook)
097b5973 1977 (*route_map_master.event_hook)(rmap_name);
518f0eb1
DS
1978}
1979
d62a17ae 1980void route_map_upd8_dependency(route_map_event_t type, const char *arg,
1981 const char *rmap_name)
518f0eb1 1982{
d62a17ae 1983 struct hash *upd8_hash = NULL;
518f0eb1 1984
fdf823db 1985 if ((upd8_hash = route_map_get_dep_hash(type))) {
d62a17ae 1986 route_map_dep_update(upd8_hash, arg, rmap_name, type);
fdf823db
NT
1987
1988 if (type == RMAP_EVENT_CALL_ADDED) {
1989 /* Execute hook. */
1990 if (route_map_master.add_hook)
1991 (*route_map_master.add_hook)(rmap_name);
1992 } else if (type == RMAP_EVENT_CALL_DELETED) {
1993 /* Execute hook. */
1994 if (route_map_master.delete_hook)
1995 (*route_map_master.delete_hook)(rmap_name);
1996 }
1997 }
518f0eb1
DS
1998}
1999
d62a17ae 2000void route_map_notify_dependencies(const char *affected_name,
2001 route_map_event_t event)
518f0eb1 2002{
d62a17ae 2003 struct route_map_dep *dep;
2004 struct hash *upd8_hash;
2005 char *name;
2006
2007 if (!affected_name)
2008 return;
2009
2010 name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, affected_name);
2011
2012 if ((upd8_hash = route_map_get_dep_hash(event)) == NULL) {
2013 XFREE(MTYPE_ROUTE_MAP_NAME, name);
2014 return;
518f0eb1 2015 }
d62a17ae 2016
2017 dep = (struct route_map_dep *)hash_get(upd8_hash, name, NULL);
2018 if (dep) {
2019 if (!dep->this_hash)
2020 dep->this_hash = upd8_hash;
2021
e3ab8170
AD
2022 if (rmap_debug)
2023 zlog_debug("Filter %s updated", dep->dep_name);
d62a17ae 2024 hash_iterate(dep->dep_rmap_hash, route_map_process_dependency,
2025 (void *)event);
2026 }
2027
2028 XFREE(MTYPE_ROUTE_MAP_NAME, name);
518f0eb1
DS
2029}
2030
82f97584 2031
718e3744 2032/* VTY related functions. */
1fa30509
DS
2033static void clear_route_map_helper(struct route_map *map)
2034{
2035 struct route_map_index *index;
2036
2037 map->applied_clear = map->applied;
2038 for (index = map->head; index; index = index->next)
2039 index->applied_clear = index->applied;
2040}
2041
2042DEFUN (rmap_clear_counters,
2043 rmap_clear_counters_cmd,
2044 "clear route-map counters [WORD]",
2045 CLEAR_STR
2046 "route-map information\n"
2047 "counters associated with the specified route-map\n"
2048 "route-map name\n")
2049{
2050 int idx_word = 2;
2051 struct route_map *map;
2052
2053 const char *name = (argc == 3 ) ? argv[idx_word]->arg : NULL;
2054
2055 if (name) {
2056 map = route_map_lookup_by_name(name);
2057
2058 if (map)
2059 clear_route_map_helper(map);
2060 else {
2061 vty_out(vty, "%s: 'route-map %s' not found\n",
2062 frr_protonameinst, name);
2063 return CMD_SUCCESS;
2064 }
2065 } else {
2066 for (map = route_map_master.head; map; map = map->next)
2067 clear_route_map_helper(map);
2068 }
2069
2070 return CMD_SUCCESS;
2071
2072}
5510e83b 2073
6d2729e3 2074DEFUN (rmap_show_name,
5510e83b 2075 rmap_show_name_cmd,
7514fb77 2076 "show route-map [WORD]",
5510e83b 2077 SHOW_STR
2078 "route-map information\n"
2079 "route-map name\n")
2080{
d62a17ae 2081 int idx_word = 2;
2082 const char *name = (argc == 3) ? argv[idx_word]->arg : NULL;
2083 return vty_show_route_map(vty, name);
5510e83b 2084}
2085
4a2a09d0 2086DEFUN (rmap_show_unused,
2087 rmap_show_unused_cmd,
2088 "show route-map-unused",
2089 SHOW_STR
2090 "unused route-map information\n")
2091{
2092 return vty_show_unused_route_map(vty);
2093}
2094
e3ab8170
AD
2095DEFUN (debug_rmap,
2096 debug_rmap_cmd,
2097 "debug route-map",
2098 DEBUG_STR
2099 "Debug option set for route-maps\n")
2100{
2101 rmap_debug = true;
2102 return CMD_SUCCESS;
2103}
2104
2105DEFUN (no_debug_rmap,
2106 no_debug_rmap_cmd,
2107 "no debug route-map",
2108 NO_STR
2109 DEBUG_STR
2110 "Debug option set for route-maps\n")
2111{
2112 rmap_debug = false;
2113 return CMD_SUCCESS;
2114}
2115
2116/* Debug node. */
2117static struct cmd_node rmap_debug_node = {RMAP_DEBUG_NODE, "", 1};
2118
718e3744 2119/* Configuration write function. */
e3ab8170
AD
2120static int rmap_config_write_debug(struct vty *vty)
2121{
2122 int write = 0;
2123
2124 if (rmap_debug) {
2125 vty_out(vty, "debug route-map\n");
2126 write++;
2127 }
2128
2129 return write;
2130}
2131
dc9ffce8
CF
2132/* Common route map rules */
2133
d62a17ae 2134void *route_map_rule_tag_compile(const char *arg)
dc9ffce8 2135{
d62a17ae 2136 unsigned long int tmp;
2137 char *endptr;
2138 route_tag_t *tag;
dc9ffce8 2139
d62a17ae 2140 errno = 0;
2141 tmp = strtoul(arg, &endptr, 0);
2142 if (arg[0] == '\0' || *endptr != '\0' || errno || tmp > ROUTE_TAG_MAX)
2143 return NULL;
dc9ffce8 2144
d62a17ae 2145 tag = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*tag));
2146 *tag = tmp;
dc9ffce8 2147
d62a17ae 2148 return tag;
dc9ffce8
CF
2149}
2150
d62a17ae 2151void route_map_rule_tag_free(void *rule)
dc9ffce8 2152{
d62a17ae 2153 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
dc9ffce8
CF
2154}
2155
d62a17ae 2156void route_map_finish(void)
9df78e7c 2157{
d62a17ae 2158 int i;
9df78e7c 2159
d62a17ae 2160 vector_free(route_match_vec);
2161 route_match_vec = NULL;
2162 vector_free(route_set_vec);
2163 route_set_vec = NULL;
9df78e7c 2164
8619629a
DS
2165 /*
2166 * All protocols are setting these to NULL
2167 * by default on shutdown( route_map_finish )
2168 * Why are we making them do this work?
2169 */
2170 route_map_master.add_hook = NULL;
2171 route_map_master.delete_hook = NULL;
2172 route_map_master.event_hook = NULL;
2173
d62a17ae 2174 /* cleanup route_map */
2175 while (route_map_master.head) {
2176 struct route_map *map = route_map_master.head;
e4694d0d 2177 map->to_be_processed = false;
d62a17ae 2178 route_map_delete(map);
2179 }
9df78e7c 2180
d62a17ae 2181 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
2182 hash_free(route_map_dep_hash[i]);
2183 route_map_dep_hash[i] = NULL;
2184 }
9df78e7c 2185
d62a17ae 2186 hash_free(route_map_master_hash);
2187 route_map_master_hash = NULL;
9df78e7c
DS
2188}
2189
4a2a09d0 2190/* Increment the use_count counter while attaching the route map */
2191void route_map_counter_increment(struct route_map *map)
2192{
2193 if (map)
2194 map->use_count++;
2195}
2196
2197/* Decrement the use_count counter while detaching the route map. */
2198void route_map_counter_decrement(struct route_map *map)
2199{
2200 if (map) {
2201 if (map->use_count <= 0)
2202 return;
2203 map->use_count--;
2204 }
2205}
2206
718e3744 2207/* Initialization of route map vector. */
d62a17ae 2208void route_map_init(void)
718e3744 2209{
d62a17ae 2210 int i;
2211
2212 /* Make vector for match and set. */
2213 route_match_vec = vector_init(1);
2214 route_set_vec = vector_init(1);
2215 route_map_master_hash =
996c9314 2216 hash_create_size(8, route_map_hash_key_make, route_map_hash_cmp,
bd74dc61 2217 "Route Map Master Hash");
d62a17ae 2218
2219 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
996c9314
LB
2220 route_map_dep_hash[i] = hash_create_size(
2221 8, route_map_dep_hash_make_key, route_map_dep_hash_cmp,
2222 "Route Map Dep Hash");
b2575bc0 2223
e3ab8170
AD
2224 rmap_debug = false;
2225
2b3e4807 2226 route_map_cli_init();
518f0eb1 2227
2b3e4807 2228 /* Install route map top node. */
e3ab8170
AD
2229 install_node(&rmap_debug_node, rmap_config_write_debug);
2230
d62a17ae 2231 /* Install route map commands. */
e3ab8170
AD
2232 install_element(CONFIG_NODE, &debug_rmap_cmd);
2233 install_element(CONFIG_NODE, &no_debug_rmap_cmd);
2234
d62a17ae 2235 /* Install show command */
1fa30509
DS
2236 install_element(ENABLE_NODE, &rmap_clear_counters_cmd);
2237
d62a17ae 2238 install_element(ENABLE_NODE, &rmap_show_name_cmd);
4a2a09d0 2239 install_element(ENABLE_NODE, &rmap_show_unused_cmd);
82f97584 2240
e3ab8170
AD
2241 install_element(ENABLE_NODE, &debug_rmap_cmd);
2242 install_element(ENABLE_NODE, &no_debug_rmap_cmd);
718e3744 2243}