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