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