]> git.proxmox.com Git - mirror_frr.git/blob - lib/routemap.c
pimd: Add missing yang callbacks for route-maps
[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 case RMAP_DENY:
745 return "deny";
746 case RMAP_ANY:
747 return "";
748 }
749
750 return "";
751 }
752
753 static const char *route_map_cmd_result_str(enum route_map_cmd_result_t res)
754 {
755 switch (res) {
756 case RMAP_MATCH:
757 return "match";
758 case RMAP_NOMATCH:
759 return "no match";
760 case RMAP_NOOP:
761 return "noop";
762 case RMAP_ERROR:
763 return "error";
764 case RMAP_OKAY:
765 return "okay";
766 }
767
768 return "invalid";
769 }
770
771 static const char *route_map_result_str(route_map_result_t res)
772 {
773 switch (res) {
774 case RMAP_DENYMATCH:
775 return "deny";
776 case RMAP_PERMITMATCH:
777 return "permit";
778 }
779
780 return "invalid";
781 }
782
783 /* show route-map */
784 static void vty_show_route_map_entry(struct vty *vty, struct route_map *map)
785 {
786 struct route_map_index *index;
787 struct route_map_rule *rule;
788
789 vty_out(vty, "route-map: %s Invoked: %" PRIu64 "\n",
790 map->name, map->applied - map->applied_clear);
791
792 for (index = map->head; index; index = index->next) {
793 vty_out(vty, " %s, sequence %d Invoked %" PRIu64 "\n",
794 route_map_type_str(index->type), index->pref,
795 index->applied - index->applied_clear);
796
797 /* Description */
798 if (index->description)
799 vty_out(vty, " Description:\n %s\n",
800 index->description);
801
802 /* Match clauses */
803 vty_out(vty, " Match clauses:\n");
804 for (rule = index->match_list.head; rule; rule = rule->next)
805 vty_out(vty, " %s %s\n", rule->cmd->str,
806 rule->rule_str);
807
808 vty_out(vty, " Set clauses:\n");
809 for (rule = index->set_list.head; rule; rule = rule->next)
810 vty_out(vty, " %s %s\n", rule->cmd->str,
811 rule->rule_str);
812
813 /* Call clause */
814 vty_out(vty, " Call clause:\n");
815 if (index->nextrm)
816 vty_out(vty, " Call %s\n", index->nextrm);
817
818 /* Exit Policy */
819 vty_out(vty, " Action:\n");
820 if (index->exitpolicy == RMAP_GOTO)
821 vty_out(vty, " Goto %d\n", index->nextpref);
822 else if (index->exitpolicy == RMAP_NEXT)
823 vty_out(vty, " Continue to next entry\n");
824 else if (index->exitpolicy == RMAP_EXIT)
825 vty_out(vty, " Exit routemap\n");
826 }
827 }
828
829 static int sort_route_map(const void **map1, const void **map2)
830 {
831 const struct route_map *m1 = *map1;
832 const struct route_map *m2 = *map2;
833
834 return strcmp(m1->name, m2->name);
835 }
836
837 static int vty_show_route_map(struct vty *vty, const char *name)
838 {
839 struct route_map *map;
840
841 vty_out(vty, "%s:\n", frr_protonameinst);
842
843 if (name) {
844 map = route_map_lookup_by_name(name);
845
846 if (map) {
847 vty_show_route_map_entry(vty, map);
848 return CMD_SUCCESS;
849 } else {
850 vty_out(vty, "%s: 'route-map %s' not found\n",
851 frr_protonameinst, name);
852 return CMD_SUCCESS;
853 }
854 } else {
855
856 struct list *maplist = list_new();
857 struct listnode *ln;
858
859 for (map = route_map_master.head; map; map = map->next)
860 listnode_add(maplist, map);
861
862 list_sort(maplist, sort_route_map);
863
864 for (ALL_LIST_ELEMENTS_RO(maplist, ln, map))
865 vty_show_route_map_entry(vty, map);
866
867 list_delete(&maplist);
868 }
869 return CMD_SUCCESS;
870 }
871
872 /* Unused route map details */
873 static int vty_show_unused_route_map(struct vty *vty)
874 {
875 struct list *maplist = list_new();
876 struct listnode *ln;
877 struct route_map *map;
878
879 for (map = route_map_master.head; map; map = map->next) {
880 /* If use_count is zero, No protocol is using this routemap.
881 * so adding to the list.
882 */
883 if (!map->use_count)
884 listnode_add(maplist, map);
885 }
886
887 if (maplist->count > 0) {
888 vty_out(vty, "\n%s:\n", frr_protonameinst);
889 list_sort(maplist, sort_route_map);
890
891 for (ALL_LIST_ELEMENTS_RO(maplist, ln, map))
892 vty_show_route_map_entry(vty, map);
893 } else {
894 vty_out(vty, "\n%s: None\n", frr_protonameinst);
895 }
896
897 list_delete(&maplist);
898 return CMD_SUCCESS;
899 }
900
901 /* New route map allocation. Please note route map's name must be
902 specified. */
903 static struct route_map_index *route_map_index_new(void)
904 {
905 struct route_map_index *new;
906
907 new = XCALLOC(MTYPE_ROUTE_MAP_INDEX, sizeof(struct route_map_index));
908 new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */
909 TAILQ_INIT(&new->rhclist);
910 QOBJ_REG(new, route_map_index);
911 return new;
912 }
913
914 /* Free route map index. */
915 void route_map_index_delete(struct route_map_index *index, int notify)
916 {
917 struct route_map_rule *rule;
918
919 QOBJ_UNREG(index);
920
921 if (rmap_debug)
922 zlog_debug("Deleting route-map %s sequence %d",
923 index->map->name, index->pref);
924
925 /* Free route map northbound hook contexts. */
926 while (!TAILQ_EMPTY(&index->rhclist))
927 routemap_hook_context_free(TAILQ_FIRST(&index->rhclist));
928
929 /* Free route match. */
930 while ((rule = index->match_list.head) != NULL)
931 route_map_rule_delete(&index->match_list, rule);
932
933 /* Free route set. */
934 while ((rule = index->set_list.head) != NULL)
935 route_map_rule_delete(&index->set_list, rule);
936
937 /* Remove index from route map list. */
938 if (index->next)
939 index->next->prev = index->prev;
940 else
941 index->map->tail = index->prev;
942
943 if (index->prev)
944 index->prev->next = index->next;
945 else
946 index->map->head = index->next;
947
948 /* Free 'char *nextrm' if not NULL */
949 XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
950
951 /* Execute event hook. */
952 if (route_map_master.event_hook && notify) {
953 (*route_map_master.event_hook)(index->map->name);
954 route_map_notify_dependencies(index->map->name,
955 RMAP_EVENT_CALL_ADDED);
956 }
957 XFREE(MTYPE_ROUTE_MAP_INDEX, index);
958 }
959
960 /* Lookup index from route map. */
961 static struct route_map_index *route_map_index_lookup(struct route_map *map,
962 enum route_map_type type,
963 int pref)
964 {
965 struct route_map_index *index;
966
967 for (index = map->head; index; index = index->next)
968 if ((index->type == type || type == RMAP_ANY)
969 && index->pref == pref)
970 return index;
971 return NULL;
972 }
973
974 /* Add new index to route map. */
975 static struct route_map_index *
976 route_map_index_add(struct route_map *map, enum route_map_type type, int pref)
977 {
978 struct route_map_index *index;
979 struct route_map_index *point;
980
981 /* Allocate new route map inex. */
982 index = route_map_index_new();
983 index->map = map;
984 index->type = type;
985 index->pref = pref;
986
987 /* Compare preference. */
988 for (point = map->head; point; point = point->next)
989 if (point->pref >= pref)
990 break;
991
992 if (map->head == NULL) {
993 map->head = map->tail = index;
994 } else if (point == NULL) {
995 index->prev = map->tail;
996 map->tail->next = index;
997 map->tail = index;
998 } else if (point == map->head) {
999 index->next = map->head;
1000 map->head->prev = index;
1001 map->head = index;
1002 } else {
1003 index->next = point;
1004 index->prev = point->prev;
1005 if (point->prev)
1006 point->prev->next = index;
1007 point->prev = index;
1008 }
1009
1010 /* Execute event hook. */
1011 if (route_map_master.event_hook) {
1012 (*route_map_master.event_hook)(map->name);
1013 route_map_notify_dependencies(map->name, RMAP_EVENT_CALL_ADDED);
1014 }
1015
1016 if (rmap_debug)
1017 zlog_debug("Route-map %s add sequence %d, type: %s",
1018 map->name, pref, route_map_type_str(type));
1019
1020 return index;
1021 }
1022
1023 /* Get route map index. */
1024 struct route_map_index *
1025 route_map_index_get(struct route_map *map, enum route_map_type type, int pref)
1026 {
1027 struct route_map_index *index;
1028
1029 index = route_map_index_lookup(map, RMAP_ANY, pref);
1030 if (index && index->type != type) {
1031 /* Delete index from route map. */
1032 route_map_index_delete(index, 1);
1033 index = NULL;
1034 }
1035 if (index == NULL)
1036 index = route_map_index_add(map, type, pref);
1037 return index;
1038 }
1039
1040 /* New route map rule */
1041 static struct route_map_rule *route_map_rule_new(void)
1042 {
1043 struct route_map_rule *new;
1044
1045 new = XCALLOC(MTYPE_ROUTE_MAP_RULE, sizeof(struct route_map_rule));
1046 return new;
1047 }
1048
1049 /* Install rule command to the match list. */
1050 void route_map_install_match(const struct route_map_rule_cmd *cmd)
1051 {
1052 vector_set(route_match_vec, (void *)cmd);
1053 }
1054
1055 /* Install rule command to the set list. */
1056 void route_map_install_set(const struct route_map_rule_cmd *cmd)
1057 {
1058 vector_set(route_set_vec, (void *)cmd);
1059 }
1060
1061 /* Lookup rule command from match list. */
1062 static const struct route_map_rule_cmd *route_map_lookup_match(const char *name)
1063 {
1064 unsigned int i;
1065 const struct route_map_rule_cmd *rule;
1066
1067 for (i = 0; i < vector_active(route_match_vec); i++)
1068 if ((rule = vector_slot(route_match_vec, i)) != NULL)
1069 if (strcmp(rule->str, name) == 0)
1070 return rule;
1071 return NULL;
1072 }
1073
1074 /* Lookup rule command from set list. */
1075 static const struct route_map_rule_cmd *route_map_lookup_set(const char *name)
1076 {
1077 unsigned int i;
1078 const struct route_map_rule_cmd *rule;
1079
1080 for (i = 0; i < vector_active(route_set_vec); i++)
1081 if ((rule = vector_slot(route_set_vec, i)) != NULL)
1082 if (strcmp(rule->str, name) == 0)
1083 return rule;
1084 return NULL;
1085 }
1086
1087 /* Add match and set rule to rule list. */
1088 static void route_map_rule_add(struct route_map_rule_list *list,
1089 struct route_map_rule *rule)
1090 {
1091 rule->next = NULL;
1092 rule->prev = list->tail;
1093 if (list->tail)
1094 list->tail->next = rule;
1095 else
1096 list->head = rule;
1097 list->tail = rule;
1098 }
1099
1100 /* Delete rule from rule list. */
1101 static void route_map_rule_delete(struct route_map_rule_list *list,
1102 struct route_map_rule *rule)
1103 {
1104 if (rule->cmd->func_free)
1105 (*rule->cmd->func_free)(rule->value);
1106
1107 XFREE(MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str);
1108
1109 if (rule->next)
1110 rule->next->prev = rule->prev;
1111 else
1112 list->tail = rule->prev;
1113 if (rule->prev)
1114 rule->prev->next = rule->next;
1115 else
1116 list->head = rule->next;
1117
1118 XFREE(MTYPE_ROUTE_MAP_RULE, rule);
1119 }
1120
1121 /* strcmp wrapper function which don't crush even argument is NULL. */
1122 static int rulecmp(const char *dst, const char *src)
1123 {
1124 if (dst == NULL) {
1125 if (src == NULL)
1126 return 0;
1127 else
1128 return 1;
1129 } else {
1130 if (src == NULL)
1131 return 1;
1132 else
1133 return strcmp(dst, src);
1134 }
1135 return 1;
1136 }
1137
1138 /* Use this to return the already specified argument for this match. This is
1139 * useful to get the specified argument with a route map match rule when the
1140 * rule is being deleted and the argument is not provided.
1141 */
1142 const char *route_map_get_match_arg(struct route_map_index *index,
1143 const char *match_name)
1144 {
1145 struct route_map_rule *rule;
1146 const struct route_map_rule_cmd *cmd;
1147
1148 /* First lookup rule for add match statement. */
1149 cmd = route_map_lookup_match(match_name);
1150 if (cmd == NULL)
1151 return NULL;
1152
1153 for (rule = index->match_list.head; rule; rule = rule->next)
1154 if (rule->cmd == cmd && rule->rule_str != NULL)
1155 return (rule->rule_str);
1156
1157 return NULL;
1158 }
1159
1160 static route_map_event_t get_route_map_delete_event(route_map_event_t type)
1161 {
1162 switch (type) {
1163 case RMAP_EVENT_CALL_ADDED:
1164 return RMAP_EVENT_CALL_DELETED;
1165 case RMAP_EVENT_PLIST_ADDED:
1166 return RMAP_EVENT_PLIST_DELETED;
1167 case RMAP_EVENT_CLIST_ADDED:
1168 return RMAP_EVENT_CLIST_DELETED;
1169 case RMAP_EVENT_ECLIST_ADDED:
1170 return RMAP_EVENT_ECLIST_DELETED;
1171 case RMAP_EVENT_LLIST_ADDED:
1172 return RMAP_EVENT_LLIST_DELETED;
1173 case RMAP_EVENT_ASLIST_ADDED:
1174 return RMAP_EVENT_ASLIST_DELETED;
1175 case RMAP_EVENT_FILTER_ADDED:
1176 return RMAP_EVENT_FILTER_DELETED;
1177 case RMAP_EVENT_SET_ADDED:
1178 case RMAP_EVENT_SET_DELETED:
1179 case RMAP_EVENT_SET_REPLACED:
1180 case RMAP_EVENT_MATCH_ADDED:
1181 case RMAP_EVENT_MATCH_DELETED:
1182 case RMAP_EVENT_MATCH_REPLACED:
1183 case RMAP_EVENT_INDEX_ADDED:
1184 case RMAP_EVENT_INDEX_DELETED:
1185 case RMAP_EVENT_CALL_DELETED:
1186 case RMAP_EVENT_PLIST_DELETED:
1187 case RMAP_EVENT_CLIST_DELETED:
1188 case RMAP_EVENT_ECLIST_DELETED:
1189 case RMAP_EVENT_LLIST_DELETED:
1190 case RMAP_EVENT_ASLIST_DELETED:
1191 case RMAP_EVENT_FILTER_DELETED:
1192 /* This function returns the appropriate 'deleted' event type
1193 * for every 'added' event type passed to this function.
1194 * This is done only for named entities used in the
1195 * route-map match commands.
1196 * This function is not to be invoked for any of the other event
1197 * types.
1198 */
1199 assert(0);
1200 }
1201
1202 assert(0);
1203 /*
1204 * Return to make c happy but if we get here something has gone
1205 * terribly terribly wrong, so yes this return makes no sense.
1206 */
1207 return RMAP_EVENT_CALL_ADDED;
1208 }
1209
1210 /* Add match statement to route map. */
1211 enum rmap_compile_rets route_map_add_match(struct route_map_index *index,
1212 const char *match_name,
1213 const char *match_arg,
1214 route_map_event_t type)
1215 {
1216 struct route_map_rule *rule;
1217 struct route_map_rule *next;
1218 const struct route_map_rule_cmd *cmd;
1219 void *compile;
1220 int8_t delete_rmap_event_type = 0;
1221 const char *rule_key;
1222
1223 /* First lookup rule for add match statement. */
1224 cmd = route_map_lookup_match(match_name);
1225 if (cmd == NULL)
1226 return RMAP_RULE_MISSING;
1227
1228 /* Next call compile function for this match statement. */
1229 if (cmd->func_compile) {
1230 compile = (*cmd->func_compile)(match_arg);
1231 if (compile == NULL)
1232 return RMAP_COMPILE_ERROR;
1233 } else
1234 compile = NULL;
1235 /* use the compiled results if applicable */
1236 if (compile && cmd->func_get_rmap_rule_key)
1237 rule_key = (*cmd->func_get_rmap_rule_key)
1238 (compile);
1239 else
1240 rule_key = match_arg;
1241
1242 /* If argument is completely same ignore it. */
1243 for (rule = index->match_list.head; rule; rule = next) {
1244 next = rule->next;
1245 if (rule->cmd == cmd) {
1246 /* If the configured route-map match rule is exactly
1247 * the same as the existing configuration then,
1248 * ignore the duplicate configuration.
1249 */
1250 if (strcmp(match_arg, rule->rule_str) == 0) {
1251 if (cmd->func_free)
1252 (*cmd->func_free)(compile);
1253
1254 return RMAP_COMPILE_SUCCESS;
1255 }
1256
1257 /* Remove the dependency of the route-map on the rule
1258 * that is being replaced.
1259 */
1260 if (type >= RMAP_EVENT_CALL_ADDED) {
1261 delete_rmap_event_type =
1262 get_route_map_delete_event(type);
1263 route_map_upd8_dependency(
1264 delete_rmap_event_type,
1265 rule_key,
1266 index->map->name);
1267 }
1268
1269 route_map_rule_delete(&index->match_list, rule);
1270 }
1271 }
1272
1273 /* Add new route map match rule. */
1274 rule = route_map_rule_new();
1275 rule->cmd = cmd;
1276 rule->value = compile;
1277 if (match_arg)
1278 rule->rule_str = XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR, match_arg);
1279 else
1280 rule->rule_str = NULL;
1281
1282 /* Add new route match rule to linked list. */
1283 route_map_rule_add(&index->match_list, rule);
1284
1285 /* Execute event hook. */
1286 if (route_map_master.event_hook) {
1287 (*route_map_master.event_hook)(index->map->name);
1288 route_map_notify_dependencies(index->map->name,
1289 RMAP_EVENT_CALL_ADDED);
1290 }
1291 if (type != RMAP_EVENT_MATCH_ADDED)
1292 route_map_upd8_dependency(type, rule_key, index->map->name);
1293
1294 return RMAP_COMPILE_SUCCESS;
1295 }
1296
1297 /* Delete specified route match rule. */
1298 enum rmap_compile_rets route_map_delete_match(struct route_map_index *index,
1299 const char *match_name,
1300 const char *match_arg,
1301 route_map_event_t type)
1302 {
1303 struct route_map_rule *rule;
1304 const struct route_map_rule_cmd *cmd;
1305 const char *rule_key;
1306
1307 cmd = route_map_lookup_match(match_name);
1308 if (cmd == NULL)
1309 return RMAP_RULE_MISSING;
1310
1311 for (rule = index->match_list.head; rule; rule = rule->next)
1312 if (rule->cmd == cmd && (rulecmp(rule->rule_str, match_arg) == 0
1313 || match_arg == NULL)) {
1314 /* Execute event hook. */
1315 if (route_map_master.event_hook) {
1316 (*route_map_master.event_hook)(index->map->name);
1317 route_map_notify_dependencies(
1318 index->map->name,
1319 RMAP_EVENT_CALL_ADDED);
1320 }
1321 if (cmd->func_get_rmap_rule_key)
1322 rule_key = (*cmd->func_get_rmap_rule_key)
1323 (rule->value);
1324 else
1325 rule_key = match_arg;
1326
1327 if (type != RMAP_EVENT_MATCH_DELETED && rule_key)
1328 route_map_upd8_dependency(type, rule_key,
1329 index->map->name);
1330
1331 route_map_rule_delete(&index->match_list, rule);
1332 return RMAP_COMPILE_SUCCESS;
1333 }
1334 /* Can't find matched rule. */
1335 return RMAP_RULE_MISSING;
1336 }
1337
1338 /* Add route-map set statement to the route map. */
1339 enum rmap_compile_rets route_map_add_set(struct route_map_index *index,
1340 const char *set_name,
1341 const char *set_arg)
1342 {
1343 struct route_map_rule *rule;
1344 struct route_map_rule *next;
1345 const struct route_map_rule_cmd *cmd;
1346 void *compile;
1347
1348 cmd = route_map_lookup_set(set_name);
1349 if (cmd == NULL)
1350 return RMAP_RULE_MISSING;
1351
1352 /* Next call compile function for this match statement. */
1353 if (cmd->func_compile) {
1354 compile = (*cmd->func_compile)(set_arg);
1355 if (compile == NULL)
1356 return RMAP_COMPILE_ERROR;
1357 } else
1358 compile = NULL;
1359
1360 /* Add by WJL. if old set command of same kind exist, delete it first
1361 to ensure only one set command of same kind exist under a
1362 route_map_index. */
1363 for (rule = index->set_list.head; rule; rule = next) {
1364 next = rule->next;
1365 if (rule->cmd == cmd)
1366 route_map_rule_delete(&index->set_list, rule);
1367 }
1368
1369 /* Add new route map match rule. */
1370 rule = route_map_rule_new();
1371 rule->cmd = cmd;
1372 rule->value = compile;
1373 if (set_arg)
1374 rule->rule_str = XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR, set_arg);
1375 else
1376 rule->rule_str = NULL;
1377
1378 /* Add new route match rule to linked list. */
1379 route_map_rule_add(&index->set_list, rule);
1380
1381 /* Execute event hook. */
1382 if (route_map_master.event_hook) {
1383 (*route_map_master.event_hook)(index->map->name);
1384 route_map_notify_dependencies(index->map->name,
1385 RMAP_EVENT_CALL_ADDED);
1386 }
1387 return RMAP_COMPILE_SUCCESS;
1388 }
1389
1390 /* Delete route map set rule. */
1391 enum rmap_compile_rets route_map_delete_set(struct route_map_index *index,
1392 const char *set_name,
1393 const char *set_arg)
1394 {
1395 struct route_map_rule *rule;
1396 const struct route_map_rule_cmd *cmd;
1397
1398 cmd = route_map_lookup_set(set_name);
1399 if (cmd == NULL)
1400 return RMAP_RULE_MISSING;
1401
1402 for (rule = index->set_list.head; rule; rule = rule->next)
1403 if ((rule->cmd == cmd) && (rulecmp(rule->rule_str, set_arg) == 0
1404 || set_arg == NULL)) {
1405 route_map_rule_delete(&index->set_list, rule);
1406 /* Execute event hook. */
1407 if (route_map_master.event_hook) {
1408 (*route_map_master.event_hook)(index->map->name);
1409 route_map_notify_dependencies(
1410 index->map->name,
1411 RMAP_EVENT_CALL_ADDED);
1412 }
1413 return RMAP_COMPILE_SUCCESS;
1414 }
1415 /* Can't find matched rule. */
1416 return RMAP_RULE_MISSING;
1417 }
1418
1419 static enum route_map_cmd_result_t
1420 route_map_apply_match(struct route_map_rule_list *match_list,
1421 const struct prefix *prefix, route_map_object_t type,
1422 void *object)
1423 {
1424 enum route_map_cmd_result_t ret = RMAP_NOMATCH;
1425 struct route_map_rule *match;
1426 bool is_matched = false;
1427
1428
1429 /* Check all match rule and if there is no match rule, go to the
1430 set statement. */
1431 if (!match_list->head)
1432 ret = RMAP_MATCH;
1433 else {
1434 for (match = match_list->head; match; match = match->next) {
1435 /*
1436 * Try each match statement. If any match does not
1437 * return RMAP_MATCH or RMAP_NOOP, return.
1438 * Otherwise continue on to next match statement.
1439 * All match statements must MATCH for
1440 * end-result to be a match.
1441 * (Exception:If match stmts result in a mix of
1442 * MATCH/NOOP, then also end-result is a match)
1443 * If all result in NOOP, end-result is NOOP.
1444 */
1445 ret = (*match->cmd->func_apply)(match->value, prefix,
1446 type, object);
1447
1448 /*
1449 * If the consolidated result of func_apply is:
1450 * -----------------------------------------------
1451 * | MATCH | NOMATCH | NOOP | Final Result |
1452 * ------------------------------------------------
1453 * | yes | yes | yes | NOMATCH |
1454 * | no | no | yes | NOOP |
1455 * | yes | no | yes | MATCH |
1456 * | no | yes | yes | NOMATCH |
1457 * |-----------------------------------------------
1458 *
1459 * Traditionally, all rules within route-map
1460 * should match for it to MATCH.
1461 * If there are noops within the route-map rules,
1462 * it follows the above matrix.
1463 *
1464 * Eg: route-map rm1 permit 10
1465 * match rule1
1466 * match rule2
1467 * match rule3
1468 * ....
1469 * route-map rm1 permit 20
1470 * match ruleX
1471 * match ruleY
1472 * ...
1473 */
1474
1475 switch (ret) {
1476 case RMAP_MATCH:
1477 is_matched = true;
1478 break;
1479
1480 case RMAP_NOMATCH:
1481 return ret;
1482
1483 case RMAP_NOOP:
1484 if (is_matched)
1485 ret = RMAP_MATCH;
1486 break;
1487
1488 default:
1489 break;
1490 }
1491
1492 }
1493 }
1494 return ret;
1495 }
1496
1497 /* Apply route map's each index to the object.
1498
1499 The matrix for a route-map looks like this:
1500 (note, this includes the description for the "NEXT"
1501 and "GOTO" frobs now
1502
1503 | Match | No Match | No op
1504 |-----------|--------------|-------
1505 permit | action | cont | cont.
1506 | | default:deny | default:permit
1507 -------------------+-----------------------
1508 | deny | cont | cont.
1509 deny | | default:deny | default:permit
1510 |-----------|--------------|--------
1511
1512 action)
1513 -Apply Set statements, accept route
1514 -If Call statement is present jump to the specified route-map, if it
1515 denies the route we finish.
1516 -If NEXT is specified, goto NEXT statement
1517 -If GOTO is specified, goto the first clause where pref > nextpref
1518 -If nothing is specified, do as Cisco and finish
1519 deny)
1520 -Route is denied by route-map.
1521 cont)
1522 -Goto Next index
1523
1524 If we get no matches after we've processed all updates, then the route
1525 is dropped too.
1526
1527 Some notes on the new "CALL", "NEXT" and "GOTO"
1528 call WORD - If this clause is matched, then the set statements
1529 are executed and then we jump to route-map 'WORD'. If
1530 this route-map denies the route, we finish, in other
1531 case we
1532 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
1533 on-match next - If this clause is matched, then the set statements
1534 are executed and then we drop through to the next clause
1535 on-match goto n - If this clause is matched, then the set statments
1536 are executed and then we goto the nth clause, or the
1537 first clause greater than this. In order to ensure
1538 route-maps *always* exit, you cannot jump backwards.
1539 Sorry ;)
1540
1541 We need to make sure our route-map processing matches the above
1542 */
1543 route_map_result_t route_map_apply(struct route_map *map,
1544 const struct prefix *prefix,
1545 route_map_object_t type, void *object)
1546 {
1547 static int recursion = 0;
1548 enum route_map_cmd_result_t match_ret = RMAP_NOMATCH;
1549 route_map_result_t ret = RMAP_PERMITMATCH;
1550 struct route_map_index *index;
1551 struct route_map_rule *set;
1552 char buf[PREFIX_STRLEN];
1553
1554 if (recursion > RMAP_RECURSION_LIMIT) {
1555 flog_warn(
1556 EC_LIB_RMAP_RECURSION_LIMIT,
1557 "route-map recursion limit (%d) reached, discarding route",
1558 RMAP_RECURSION_LIMIT);
1559 recursion = 0;
1560 return RMAP_DENYMATCH;
1561 }
1562
1563 if (map == NULL || map->head == NULL) {
1564 ret = RMAP_DENYMATCH;
1565 goto route_map_apply_end;
1566 }
1567
1568 map->applied++;
1569 for (index = map->head; index; index = index->next) {
1570 /* Apply this index. */
1571 index->applied++;
1572 match_ret = route_map_apply_match(&index->match_list, prefix,
1573 type, object);
1574
1575 if (rmap_debug) {
1576 zlog_debug("Route-map: %s, sequence: %d, prefix: %s, result: %s",
1577 map->name, index->pref,
1578 prefix2str(prefix, buf, sizeof(buf)),
1579 route_map_cmd_result_str(match_ret));
1580 }
1581
1582 /* Now we apply the matrix from above */
1583 if (match_ret == RMAP_NOOP)
1584 /*
1585 * Do not change the return value. Retain the previous
1586 * return value. Previous values can be:
1587 * 1)permitmatch (if a nomatch was never
1588 * seen before in this route-map.)
1589 * 2)denymatch (if a nomatch was seen earlier in one
1590 * of the previous sequences)
1591 */
1592
1593 /*
1594 * 'cont' from matrix - continue to next route-map
1595 * sequence
1596 */
1597 continue;
1598 else if (match_ret == RMAP_NOMATCH) {
1599
1600 /*
1601 * The return value is now changed to denymatch.
1602 * So from here on out, even if we see more noops,
1603 * we retain this return value and return this
1604 * eventually if there are no matches.
1605 */
1606 ret = RMAP_DENYMATCH;
1607
1608 /*
1609 * 'cont' from matrix - continue to next route-map
1610 * sequence
1611 */
1612 continue;
1613 } else if (match_ret == RMAP_MATCH) {
1614 if (index->type == RMAP_PERMIT)
1615 /* 'action' */
1616 {
1617 /* Match succeeded, rmap is of type permit */
1618 ret = RMAP_PERMITMATCH;
1619
1620 /* permit+match must execute sets */
1621 for (set = index->set_list.head; set;
1622 set = set->next)
1623 /*
1624 * set cmds return RMAP_OKAY or
1625 * RMAP_ERROR. We do not care if
1626 * set succeeded or not. So, ignore
1627 * return code.
1628 */
1629 (void) (*set->cmd->func_apply)(
1630 set->value, prefix, type,
1631 object);
1632
1633 /* Call another route-map if available */
1634 if (index->nextrm) {
1635 struct route_map *nextrm =
1636 route_map_lookup_by_name(
1637 index->nextrm);
1638
1639 if (nextrm) /* Target route-map found,
1640 jump to it */
1641 {
1642 recursion++;
1643 ret = route_map_apply(
1644 nextrm, prefix, type,
1645 object);
1646 recursion--;
1647 }
1648
1649 /* If nextrm returned 'deny', finish. */
1650 if (ret == RMAP_DENYMATCH)
1651 goto route_map_apply_end;
1652 }
1653
1654 switch (index->exitpolicy) {
1655 case RMAP_EXIT:
1656 goto route_map_apply_end;
1657 case RMAP_NEXT:
1658 continue;
1659 case RMAP_GOTO: {
1660 /* Find the next clause to jump to */
1661 struct route_map_index *next =
1662 index->next;
1663 int nextpref = index->nextpref;
1664
1665 while (next && next->pref < nextpref) {
1666 index = next;
1667 next = next->next;
1668 }
1669 if (next == NULL) {
1670 /* No clauses match! */
1671 goto route_map_apply_end;
1672 }
1673 }
1674 }
1675 } else if (index->type == RMAP_DENY)
1676 /* 'deny' */
1677 {
1678 ret = RMAP_DENYMATCH;
1679 goto route_map_apply_end;
1680 }
1681 }
1682 }
1683
1684 route_map_apply_end:
1685 if (rmap_debug) {
1686 zlog_debug("Route-map: %s, prefix: %s, result: %s",
1687 (map ? map->name : "null"),
1688 prefix2str(prefix, buf, sizeof(buf)),
1689 route_map_result_str(ret));
1690 }
1691
1692 return (ret);
1693 }
1694
1695 void route_map_add_hook(void (*func)(const char *))
1696 {
1697 route_map_master.add_hook = func;
1698 }
1699
1700 void route_map_delete_hook(void (*func)(const char *))
1701 {
1702 route_map_master.delete_hook = func;
1703 }
1704
1705 void route_map_event_hook(void (*func)(const char *name))
1706 {
1707 route_map_master.event_hook = func;
1708 }
1709
1710 /* Routines for route map dependency lists and dependency processing */
1711 static bool route_map_rmap_hash_cmp(const void *p1, const void *p2)
1712 {
1713 return strcmp(((const struct route_map_dep_data *)p1)->rname,
1714 ((const struct route_map_dep_data *)p2)->rname)
1715 == 0;
1716 }
1717
1718 static bool route_map_dep_hash_cmp(const void *p1, const void *p2)
1719 {
1720
1721 return (strcmp(((const struct route_map_dep *)p1)->dep_name,
1722 (const char *)p2)
1723 == 0);
1724 }
1725
1726 static void route_map_clear_reference(struct hash_bucket *bucket, void *arg)
1727 {
1728 struct route_map_dep *dep = bucket->data;
1729 struct route_map_dep_data *dep_data = NULL, tmp_dep_data;
1730
1731 if (arg) {
1732 memset(&tmp_dep_data, 0, sizeof(struct route_map_dep_data));
1733 tmp_dep_data.rname = arg;
1734 dep_data = hash_release(dep->dep_rmap_hash,
1735 &tmp_dep_data);
1736 if (dep_data) {
1737 XFREE(MTYPE_ROUTE_MAP_NAME, dep_data->rname);
1738 XFREE(MTYPE_ROUTE_MAP_DEP_DATA, dep_data);
1739 }
1740 if (!dep->dep_rmap_hash->count) {
1741 dep = hash_release(dep->this_hash,
1742 (void *)dep->dep_name);
1743 hash_free(dep->dep_rmap_hash);
1744 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
1745 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
1746 }
1747 }
1748 }
1749
1750 static void route_map_clear_all_references(char *rmap_name)
1751 {
1752 int i;
1753
1754 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
1755 hash_iterate(route_map_dep_hash[i], route_map_clear_reference,
1756 (void *)rmap_name);
1757 }
1758 }
1759
1760 static unsigned int route_map_dep_data_hash_make_key(const void *p)
1761 {
1762 const struct route_map_dep_data *dep_data = p;
1763
1764 return string_hash_make(dep_data->rname);
1765 }
1766
1767 static void *route_map_dep_hash_alloc(void *p)
1768 {
1769 char *dep_name = (char *)p;
1770 struct route_map_dep *dep_entry;
1771
1772 dep_entry = XCALLOC(MTYPE_ROUTE_MAP_DEP, sizeof(struct route_map_dep));
1773 dep_entry->dep_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
1774 dep_entry->dep_rmap_hash =
1775 hash_create_size(8, route_map_dep_data_hash_make_key,
1776 route_map_rmap_hash_cmp, "Route Map Dep Hash");
1777 dep_entry->this_hash = NULL;
1778
1779 return dep_entry;
1780 }
1781
1782 static void *route_map_name_hash_alloc(void *p)
1783 {
1784 struct route_map_dep_data *dep_data = NULL, *tmp_dep_data = NULL;
1785
1786 dep_data = XCALLOC(MTYPE_ROUTE_MAP_DEP_DATA,
1787 sizeof(struct route_map_dep_data));
1788 tmp_dep_data = p;
1789 dep_data->rname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, tmp_dep_data->rname);
1790 return dep_data;
1791 }
1792
1793 static unsigned int route_map_dep_hash_make_key(const void *p)
1794 {
1795 return (string_hash_make((char *)p));
1796 }
1797
1798 static void route_map_print_dependency(struct hash_bucket *bucket, void *data)
1799 {
1800 struct route_map_dep_data *dep_data = bucket->data;
1801 char *rmap_name = dep_data->rname;
1802 char *dep_name = data;
1803
1804 zlog_debug("%s: Dependency for %s: %s", __FUNCTION__, dep_name,
1805 rmap_name);
1806 }
1807
1808 static int route_map_dep_update(struct hash *dephash, const char *dep_name,
1809 const char *rmap_name, route_map_event_t type)
1810 {
1811 struct route_map_dep *dep = NULL;
1812 char *dname, *rname;
1813 int ret = 0;
1814 struct route_map_dep_data *dep_data = NULL, *ret_dep_data = NULL;
1815 struct route_map_dep_data tmp_dep_data;
1816
1817 dname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
1818 rname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_name);
1819
1820 switch (type) {
1821 case RMAP_EVENT_PLIST_ADDED:
1822 case RMAP_EVENT_CLIST_ADDED:
1823 case RMAP_EVENT_ECLIST_ADDED:
1824 case RMAP_EVENT_ASLIST_ADDED:
1825 case RMAP_EVENT_LLIST_ADDED:
1826 case RMAP_EVENT_CALL_ADDED:
1827 case RMAP_EVENT_FILTER_ADDED:
1828 if (rmap_debug)
1829 zlog_debug("Adding dependency for filter %s in route-map %s",
1830 dep_name, rmap_name);
1831 dep = (struct route_map_dep *)hash_get(
1832 dephash, dname, route_map_dep_hash_alloc);
1833 if (!dep) {
1834 ret = -1;
1835 goto out;
1836 }
1837
1838 if (!dep->this_hash)
1839 dep->this_hash = dephash;
1840
1841 memset(&tmp_dep_data, 0, sizeof(struct route_map_dep_data));
1842 tmp_dep_data.rname = rname;
1843 dep_data = hash_lookup(dep->dep_rmap_hash, &tmp_dep_data);
1844 if (!dep_data)
1845 dep_data = hash_get(dep->dep_rmap_hash, &tmp_dep_data,
1846 route_map_name_hash_alloc);
1847
1848 dep_data->refcnt++;
1849 break;
1850 case RMAP_EVENT_PLIST_DELETED:
1851 case RMAP_EVENT_CLIST_DELETED:
1852 case RMAP_EVENT_ECLIST_DELETED:
1853 case RMAP_EVENT_ASLIST_DELETED:
1854 case RMAP_EVENT_LLIST_DELETED:
1855 case RMAP_EVENT_CALL_DELETED:
1856 case RMAP_EVENT_FILTER_DELETED:
1857 if (rmap_debug)
1858 zlog_debug("Deleting dependency for filter %s in route-map %s",
1859 dep_name, rmap_name);
1860 dep = (struct route_map_dep *)hash_get(dephash, dname, NULL);
1861 if (!dep) {
1862 goto out;
1863 }
1864
1865 memset(&tmp_dep_data, 0, sizeof(struct route_map_dep_data));
1866 tmp_dep_data.rname = rname;
1867 dep_data = hash_lookup(dep->dep_rmap_hash, &tmp_dep_data);
1868 dep_data->refcnt--;
1869
1870 if (!dep_data->refcnt) {
1871 ret_dep_data = hash_release(dep->dep_rmap_hash,
1872 &tmp_dep_data);
1873 if (ret_dep_data) {
1874 XFREE(MTYPE_ROUTE_MAP_NAME,
1875 ret_dep_data->rname);
1876 XFREE(MTYPE_ROUTE_MAP_DEP_DATA, ret_dep_data);
1877 }
1878 }
1879
1880 if (!dep->dep_rmap_hash->count) {
1881 dep = hash_release(dephash, dname);
1882 hash_free(dep->dep_rmap_hash);
1883 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
1884 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
1885 }
1886 break;
1887 case RMAP_EVENT_SET_ADDED:
1888 case RMAP_EVENT_SET_DELETED:
1889 case RMAP_EVENT_SET_REPLACED:
1890 case RMAP_EVENT_MATCH_ADDED:
1891 case RMAP_EVENT_MATCH_DELETED:
1892 case RMAP_EVENT_MATCH_REPLACED:
1893 case RMAP_EVENT_INDEX_ADDED:
1894 case RMAP_EVENT_INDEX_DELETED:
1895 break;
1896 }
1897
1898 if (dep) {
1899 if (rmap_debug)
1900 hash_iterate(dep->dep_rmap_hash,
1901 route_map_print_dependency, dname);
1902 }
1903
1904 out:
1905 XFREE(MTYPE_ROUTE_MAP_NAME, rname);
1906 XFREE(MTYPE_ROUTE_MAP_NAME, dname);
1907 return ret;
1908 }
1909
1910 static struct hash *route_map_get_dep_hash(route_map_event_t event)
1911 {
1912 struct hash *upd8_hash = NULL;
1913
1914 switch (event) {
1915 case RMAP_EVENT_PLIST_ADDED:
1916 case RMAP_EVENT_PLIST_DELETED:
1917 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_PLIST];
1918 break;
1919 case RMAP_EVENT_CLIST_ADDED:
1920 case RMAP_EVENT_CLIST_DELETED:
1921 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_CLIST];
1922 break;
1923 case RMAP_EVENT_ECLIST_ADDED:
1924 case RMAP_EVENT_ECLIST_DELETED:
1925 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ECLIST];
1926 break;
1927 case RMAP_EVENT_ASLIST_ADDED:
1928 case RMAP_EVENT_ASLIST_DELETED:
1929 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ASPATH];
1930 break;
1931 case RMAP_EVENT_LLIST_ADDED:
1932 case RMAP_EVENT_LLIST_DELETED:
1933 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_LCLIST];
1934 break;
1935 case RMAP_EVENT_CALL_ADDED:
1936 case RMAP_EVENT_CALL_DELETED:
1937 case RMAP_EVENT_MATCH_ADDED:
1938 case RMAP_EVENT_MATCH_DELETED:
1939 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_RMAP];
1940 break;
1941 case RMAP_EVENT_FILTER_ADDED:
1942 case RMAP_EVENT_FILTER_DELETED:
1943 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_FILTER];
1944 break;
1945 /*
1946 * Should we actually be ignoring these?
1947 * I am not sure but at this point in time, let
1948 * us get them into this switch and we can peel
1949 * them into the appropriate place in the future
1950 */
1951 case RMAP_EVENT_SET_ADDED:
1952 case RMAP_EVENT_SET_DELETED:
1953 case RMAP_EVENT_SET_REPLACED:
1954 case RMAP_EVENT_MATCH_REPLACED:
1955 case RMAP_EVENT_INDEX_ADDED:
1956 case RMAP_EVENT_INDEX_DELETED:
1957 upd8_hash = NULL;
1958 break;
1959 }
1960 return (upd8_hash);
1961 }
1962
1963 static void route_map_process_dependency(struct hash_bucket *bucket, void *data)
1964 {
1965 struct route_map_dep_data *dep_data = NULL;
1966 char *rmap_name = NULL;
1967
1968 dep_data = bucket->data;
1969 rmap_name = dep_data->rname;
1970
1971 if (rmap_debug)
1972 zlog_debug("Notifying %s of dependency", rmap_name);
1973 if (route_map_master.event_hook)
1974 (*route_map_master.event_hook)(rmap_name);
1975 }
1976
1977 void route_map_upd8_dependency(route_map_event_t type, const char *arg,
1978 const char *rmap_name)
1979 {
1980 struct hash *upd8_hash = NULL;
1981
1982 if ((upd8_hash = route_map_get_dep_hash(type))) {
1983 route_map_dep_update(upd8_hash, arg, rmap_name, type);
1984
1985 if (type == RMAP_EVENT_CALL_ADDED) {
1986 /* Execute hook. */
1987 if (route_map_master.add_hook)
1988 (*route_map_master.add_hook)(rmap_name);
1989 } else if (type == RMAP_EVENT_CALL_DELETED) {
1990 /* Execute hook. */
1991 if (route_map_master.delete_hook)
1992 (*route_map_master.delete_hook)(rmap_name);
1993 }
1994 }
1995 }
1996
1997 void route_map_notify_dependencies(const char *affected_name,
1998 route_map_event_t event)
1999 {
2000 struct route_map_dep *dep;
2001 struct hash *upd8_hash;
2002 char *name;
2003
2004 if (!affected_name)
2005 return;
2006
2007 name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, affected_name);
2008
2009 if ((upd8_hash = route_map_get_dep_hash(event)) == NULL) {
2010 XFREE(MTYPE_ROUTE_MAP_NAME, name);
2011 return;
2012 }
2013
2014 dep = (struct route_map_dep *)hash_get(upd8_hash, name, NULL);
2015 if (dep) {
2016 if (!dep->this_hash)
2017 dep->this_hash = upd8_hash;
2018
2019 if (rmap_debug)
2020 zlog_debug("Filter %s updated", dep->dep_name);
2021 hash_iterate(dep->dep_rmap_hash, route_map_process_dependency,
2022 (void *)event);
2023 }
2024
2025 XFREE(MTYPE_ROUTE_MAP_NAME, name);
2026 }
2027
2028
2029 /* VTY related functions. */
2030 static void clear_route_map_helper(struct route_map *map)
2031 {
2032 struct route_map_index *index;
2033
2034 map->applied_clear = map->applied;
2035 for (index = map->head; index; index = index->next)
2036 index->applied_clear = index->applied;
2037 }
2038
2039 DEFUN (rmap_clear_counters,
2040 rmap_clear_counters_cmd,
2041 "clear route-map counters [WORD]",
2042 CLEAR_STR
2043 "route-map information\n"
2044 "counters associated with the specified route-map\n"
2045 "route-map name\n")
2046 {
2047 int idx_word = 2;
2048 struct route_map *map;
2049
2050 const char *name = (argc == 3 ) ? argv[idx_word]->arg : NULL;
2051
2052 if (name) {
2053 map = route_map_lookup_by_name(name);
2054
2055 if (map)
2056 clear_route_map_helper(map);
2057 else {
2058 vty_out(vty, "%s: 'route-map %s' not found\n",
2059 frr_protonameinst, name);
2060 return CMD_SUCCESS;
2061 }
2062 } else {
2063 for (map = route_map_master.head; map; map = map->next)
2064 clear_route_map_helper(map);
2065 }
2066
2067 return CMD_SUCCESS;
2068
2069 }
2070
2071 DEFUN (rmap_show_name,
2072 rmap_show_name_cmd,
2073 "show route-map [WORD]",
2074 SHOW_STR
2075 "route-map information\n"
2076 "route-map name\n")
2077 {
2078 int idx_word = 2;
2079 const char *name = (argc == 3) ? argv[idx_word]->arg : NULL;
2080 return vty_show_route_map(vty, name);
2081 }
2082
2083 DEFUN (rmap_show_unused,
2084 rmap_show_unused_cmd,
2085 "show route-map-unused",
2086 SHOW_STR
2087 "unused route-map information\n")
2088 {
2089 return vty_show_unused_route_map(vty);
2090 }
2091
2092 DEFUN (debug_rmap,
2093 debug_rmap_cmd,
2094 "debug route-map",
2095 DEBUG_STR
2096 "Debug option set for route-maps\n")
2097 {
2098 rmap_debug = true;
2099 return CMD_SUCCESS;
2100 }
2101
2102 DEFUN (no_debug_rmap,
2103 no_debug_rmap_cmd,
2104 "no debug route-map",
2105 NO_STR
2106 DEBUG_STR
2107 "Debug option set for route-maps\n")
2108 {
2109 rmap_debug = false;
2110 return CMD_SUCCESS;
2111 }
2112
2113 /* Debug node. */
2114 static struct cmd_node rmap_debug_node = {RMAP_DEBUG_NODE, "", 1};
2115
2116 /* Configuration write function. */
2117 static int rmap_config_write_debug(struct vty *vty)
2118 {
2119 int write = 0;
2120
2121 if (rmap_debug) {
2122 vty_out(vty, "debug route-map\n");
2123 write++;
2124 }
2125
2126 return write;
2127 }
2128
2129 /* Common route map rules */
2130
2131 void *route_map_rule_tag_compile(const char *arg)
2132 {
2133 unsigned long int tmp;
2134 char *endptr;
2135 route_tag_t *tag;
2136
2137 errno = 0;
2138 tmp = strtoul(arg, &endptr, 0);
2139 if (arg[0] == '\0' || *endptr != '\0' || errno || tmp > ROUTE_TAG_MAX)
2140 return NULL;
2141
2142 tag = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*tag));
2143 *tag = tmp;
2144
2145 return tag;
2146 }
2147
2148 void route_map_rule_tag_free(void *rule)
2149 {
2150 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
2151 }
2152
2153 void route_map_finish(void)
2154 {
2155 int i;
2156
2157 vector_free(route_match_vec);
2158 route_match_vec = NULL;
2159 vector_free(route_set_vec);
2160 route_set_vec = NULL;
2161
2162 /*
2163 * All protocols are setting these to NULL
2164 * by default on shutdown( route_map_finish )
2165 * Why are we making them do this work?
2166 */
2167 route_map_master.add_hook = NULL;
2168 route_map_master.delete_hook = NULL;
2169 route_map_master.event_hook = NULL;
2170
2171 /* cleanup route_map */
2172 while (route_map_master.head) {
2173 struct route_map *map = route_map_master.head;
2174 map->to_be_processed = false;
2175 route_map_delete(map);
2176 }
2177
2178 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
2179 hash_free(route_map_dep_hash[i]);
2180 route_map_dep_hash[i] = NULL;
2181 }
2182
2183 hash_free(route_map_master_hash);
2184 route_map_master_hash = NULL;
2185 }
2186
2187 /* Increment the use_count counter while attaching the route map */
2188 void route_map_counter_increment(struct route_map *map)
2189 {
2190 if (map)
2191 map->use_count++;
2192 }
2193
2194 /* Decrement the use_count counter while detaching the route map. */
2195 void route_map_counter_decrement(struct route_map *map)
2196 {
2197 if (map) {
2198 if (map->use_count <= 0)
2199 return;
2200 map->use_count--;
2201 }
2202 }
2203
2204 /* Initialization of route map vector. */
2205 void route_map_init(void)
2206 {
2207 int i;
2208
2209 /* Make vector for match and set. */
2210 route_match_vec = vector_init(1);
2211 route_set_vec = vector_init(1);
2212 route_map_master_hash =
2213 hash_create_size(8, route_map_hash_key_make, route_map_hash_cmp,
2214 "Route Map Master Hash");
2215
2216 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
2217 route_map_dep_hash[i] = hash_create_size(
2218 8, route_map_dep_hash_make_key, route_map_dep_hash_cmp,
2219 "Route Map Dep Hash");
2220
2221 rmap_debug = false;
2222
2223 route_map_cli_init();
2224
2225 /* Install route map top node. */
2226 install_node(&rmap_debug_node, rmap_config_write_debug);
2227
2228 /* Install route map commands. */
2229 install_element(CONFIG_NODE, &debug_rmap_cmd);
2230 install_element(CONFIG_NODE, &no_debug_rmap_cmd);
2231
2232 /* Install show command */
2233 install_element(ENABLE_NODE, &rmap_clear_counters_cmd);
2234
2235 install_element(ENABLE_NODE, &rmap_show_name_cmd);
2236 install_element(ENABLE_NODE, &rmap_show_unused_cmd);
2237
2238 install_element(ENABLE_NODE, &debug_rmap_cmd);
2239 install_element(ENABLE_NODE, &no_debug_rmap_cmd);
2240 }