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