]> git.proxmox.com Git - mirror_frr.git/blob - lib/routemap.c
Merge pull request #8373 from mjstapp/fix_ospf_timeval_dump
[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 #include "table.h"
35
36 DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP, "Route map");
37 DEFINE_MTYPE(LIB, ROUTE_MAP_NAME, "Route map name");
38 DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_INDEX, "Route map index");
39 DEFINE_MTYPE(LIB, ROUTE_MAP_RULE, "Route map rule");
40 DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_RULE_STR, "Route map rule str");
41 DEFINE_MTYPE(LIB, ROUTE_MAP_COMPILED, "Route map compiled");
42 DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_DEP, "Route map dependency");
43 DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_DEP_DATA, "Route map dependency data");
44
45 DEFINE_QOBJ_TYPE(route_map_index);
46 DEFINE_QOBJ_TYPE(route_map);
47
48 #define IPv4_PREFIX_LIST "ip address prefix-list"
49 #define IPv6_PREFIX_LIST "ipv6 address prefix-list"
50
51 #define IS_RULE_IPv4_PREFIX_LIST(S) \
52 (strncmp(S, IPv4_PREFIX_LIST, strlen(IPv4_PREFIX_LIST)) == 0)
53 #define IS_RULE_IPv6_PREFIX_LIST(S) \
54 (strncmp(S, IPv6_PREFIX_LIST, strlen(IPv6_PREFIX_LIST)) == 0)
55
56 struct route_map_pentry_dep {
57 struct prefix_list_entry *pentry;
58 const char *plist_name;
59 route_map_event_t event;
60 };
61
62 /* Vector for route match rules. */
63 static vector route_match_vec;
64
65 /* Vector for route set rules. */
66 static vector route_set_vec;
67
68 static void route_map_pfx_tbl_update(route_map_event_t event,
69 struct route_map_index *index, afi_t afi,
70 const char *plist_name);
71 static void route_map_pfx_table_add_default(afi_t afi,
72 struct route_map_index *index);
73 static void route_map_pfx_table_del_default(afi_t afi,
74 struct route_map_index *index);
75 static void route_map_add_plist_entries(afi_t afi,
76 struct route_map_index *index,
77 const char *plist_name,
78 struct prefix_list_entry *entry);
79 static void route_map_del_plist_entries(afi_t afi,
80 struct route_map_index *index,
81 const char *plist_name,
82 struct prefix_list_entry *entry);
83
84 static struct hash *route_map_get_dep_hash(route_map_event_t event);
85
86 struct route_map_match_set_hooks rmap_match_set_hook;
87
88 /* match interface */
89 void route_map_match_interface_hook(int (*func)(
90 struct route_map_index *index, const char *command,
91 const char *arg, route_map_event_t type,
92 char *errmsg, size_t errmsg_len))
93 {
94 rmap_match_set_hook.match_interface = func;
95 }
96
97 /* no match interface */
98 void route_map_no_match_interface_hook(int (*func)(
99 struct route_map_index *index, const char *command,
100 const char *arg, route_map_event_t type,
101 char *errmsg, size_t errmsg_len))
102 {
103 rmap_match_set_hook.no_match_interface = func;
104 }
105
106 /* match ip address */
107 void route_map_match_ip_address_hook(int (*func)(
108 struct route_map_index *index, const char *command,
109 const char *arg, route_map_event_t type,
110 char *errmsg, size_t errmsg_len))
111 {
112 rmap_match_set_hook.match_ip_address = func;
113 }
114
115 /* no match ip address */
116 void route_map_no_match_ip_address_hook(int (*func)(
117 struct route_map_index *index, const char *command,
118 const char *arg, route_map_event_t type,
119 char *errmsg, size_t errmsg_len))
120 {
121 rmap_match_set_hook.no_match_ip_address = func;
122 }
123
124 /* match ip address prefix list */
125 void route_map_match_ip_address_prefix_list_hook(int (*func)(
126 struct route_map_index *index, const char *command,
127 const char *arg, route_map_event_t type,
128 char *errmsg, size_t errmsg_len))
129 {
130 rmap_match_set_hook.match_ip_address_prefix_list = func;
131 }
132
133 /* no match ip address prefix list */
134 void route_map_no_match_ip_address_prefix_list_hook(int (*func)(
135 struct route_map_index *index, const char *command,
136 const char *arg, route_map_event_t type,
137 char *errmsg, size_t errmsg_len))
138 {
139 rmap_match_set_hook.no_match_ip_address_prefix_list = func;
140 }
141
142 /* match ip next hop */
143 void route_map_match_ip_next_hop_hook(int (*func)(
144 struct route_map_index *index, const char *command,
145 const char *arg, route_map_event_t type,
146 char *errmsg, size_t errmsg_len))
147 {
148 rmap_match_set_hook.match_ip_next_hop = func;
149 }
150
151 /* no match ip next hop */
152 void route_map_no_match_ip_next_hop_hook(int (*func)(
153 struct route_map_index *index, const char *command,
154 const char *arg, route_map_event_t type,
155 char *errmsg, size_t errmsg_len))
156 {
157 rmap_match_set_hook.no_match_ip_next_hop = func;
158 }
159
160 /* match ip next hop prefix list */
161 void route_map_match_ip_next_hop_prefix_list_hook(int (*func)(
162 struct route_map_index *index, const char *command,
163 const char *arg, route_map_event_t type,
164 char *errmsg, size_t errmsg_len))
165 {
166 rmap_match_set_hook.match_ip_next_hop_prefix_list = func;
167 }
168
169 /* no match ip next hop prefix list */
170 void route_map_no_match_ip_next_hop_prefix_list_hook(int (*func)(
171 struct route_map_index *index, const char *command,
172 const char *arg, route_map_event_t type,
173 char *errmsg, size_t errmsg_len))
174 {
175 rmap_match_set_hook.no_match_ip_next_hop_prefix_list = func;
176 }
177
178 /* match ip next-hop type */
179 void route_map_match_ip_next_hop_type_hook(int (*func)(
180 struct route_map_index *index, const char *command,
181 const char *arg, route_map_event_t type,
182 char *errmsg, size_t errmsg_len))
183 {
184 rmap_match_set_hook.match_ip_next_hop_type = func;
185 }
186
187 /* no match ip next-hop type */
188 void route_map_no_match_ip_next_hop_type_hook(int (*func)(
189 struct route_map_index *index, const char *command,
190 const char *arg, route_map_event_t type,
191 char *errmsg, size_t errmsg_len))
192 {
193 rmap_match_set_hook.no_match_ip_next_hop_type = func;
194 }
195
196 /* match ipv6 address */
197 void route_map_match_ipv6_address_hook(int (*func)(
198 struct route_map_index *index, const char *command,
199 const char *arg, route_map_event_t type,
200 char *errmsg, size_t errmsg_len))
201 {
202 rmap_match_set_hook.match_ipv6_address = func;
203 }
204
205 /* no match ipv6 address */
206 void route_map_no_match_ipv6_address_hook(int (*func)(
207 struct route_map_index *index, const char *command,
208 const char *arg, route_map_event_t type,
209 char *errmsg, size_t errmsg_len))
210 {
211 rmap_match_set_hook.no_match_ipv6_address = func;
212 }
213
214
215 /* match ipv6 address prefix list */
216 void route_map_match_ipv6_address_prefix_list_hook(int (*func)(
217 struct route_map_index *index, const char *command,
218 const char *arg, route_map_event_t type,
219 char *errmsg, size_t errmsg_len))
220 {
221 rmap_match_set_hook.match_ipv6_address_prefix_list = func;
222 }
223
224 /* no match ipv6 address prefix list */
225 void route_map_no_match_ipv6_address_prefix_list_hook(int (*func)(
226 struct route_map_index *index, const char *command,
227 const char *arg, route_map_event_t type,
228 char *errmsg, size_t errmsg_len))
229 {
230 rmap_match_set_hook.no_match_ipv6_address_prefix_list = func;
231 }
232
233 /* match ipv6 next-hop type */
234 void route_map_match_ipv6_next_hop_type_hook(int (*func)(
235 struct route_map_index *index, const char *command,
236 const char *arg, route_map_event_t type,
237 char *errmsg, size_t errmsg_len))
238 {
239 rmap_match_set_hook.match_ipv6_next_hop_type = func;
240 }
241
242 /* no match ipv6 next-hop type */
243 void route_map_no_match_ipv6_next_hop_type_hook(int (*func)(
244 struct route_map_index *index, const char *command,
245 const char *arg, route_map_event_t type,
246 char *errmsg, size_t errmsg_len))
247 {
248 rmap_match_set_hook.no_match_ipv6_next_hop_type = func;
249 }
250
251 /* match metric */
252 void route_map_match_metric_hook(int (*func)(
253 struct route_map_index *index, const char *command,
254 const char *arg, route_map_event_t type,
255 char *errmsg, size_t errmsg_len))
256 {
257 rmap_match_set_hook.match_metric = func;
258 }
259
260 /* no match metric */
261 void route_map_no_match_metric_hook(int (*func)(
262 struct route_map_index *index, const char *command,
263 const char *arg, route_map_event_t type,
264 char *errmsg, size_t errmsg_len))
265 {
266 rmap_match_set_hook.no_match_metric = func;
267 }
268
269 /* match tag */
270 void route_map_match_tag_hook(int (*func)(struct route_map_index *index,
271 const char *command, const char *arg,
272 route_map_event_t type,
273 char *errmsg, size_t errmsg_len))
274 {
275 rmap_match_set_hook.match_tag = func;
276 }
277
278 /* no match tag */
279 void route_map_no_match_tag_hook(int (*func)(
280 struct route_map_index *index, const char *command,
281 const char *arg, route_map_event_t type,
282 char *errmsg, size_t errmsg_len))
283 {
284 rmap_match_set_hook.no_match_tag = func;
285 }
286
287 /* set sr-te color */
288 void route_map_set_srte_color_hook(int (*func)(struct route_map_index *index,
289 const char *command,
290 const char *arg,
291 char *errmsg, size_t errmsg_len))
292 {
293 rmap_match_set_hook.set_srte_color = func;
294 }
295
296 /* no set sr-te color */
297 void route_map_no_set_srte_color_hook(int (*func)(struct route_map_index *index,
298 const char *command,
299 const char *arg,
300 char *errmsg, size_t errmsg_len))
301 {
302 rmap_match_set_hook.no_set_srte_color = func;
303 }
304
305 /* set ip nexthop */
306 void route_map_set_ip_nexthop_hook(int (*func)(struct route_map_index *index,
307 const char *command,
308 const char *arg,
309 char *errmsg, size_t errmsg_len))
310 {
311 rmap_match_set_hook.set_ip_nexthop = func;
312 }
313
314 /* no set ip nexthop */
315 void route_map_no_set_ip_nexthop_hook(int (*func)(struct route_map_index *index,
316 const char *command,
317 const char *arg,
318 char *errmsg,
319 size_t errmsg_len))
320 {
321 rmap_match_set_hook.no_set_ip_nexthop = func;
322 }
323
324 /* set ipv6 nexthop local */
325 void route_map_set_ipv6_nexthop_local_hook(
326 int (*func)(struct route_map_index *index,
327 const char *command, const char *arg,
328 char *errmsg, size_t errmsg_len))
329 {
330 rmap_match_set_hook.set_ipv6_nexthop_local = func;
331 }
332
333 /* no set ipv6 nexthop local */
334 void route_map_no_set_ipv6_nexthop_local_hook(
335 int (*func)(struct route_map_index *index,
336 const char *command, const char *arg,
337 char *errmsg, size_t errmsg_len))
338 {
339 rmap_match_set_hook.no_set_ipv6_nexthop_local = func;
340 }
341
342 /* set metric */
343 void route_map_set_metric_hook(int (*func)(struct route_map_index *index,
344 const char *command,
345 const char *arg,
346 char *errmsg, size_t errmsg_len))
347 {
348 rmap_match_set_hook.set_metric = func;
349 }
350
351 /* no set metric */
352 void route_map_no_set_metric_hook(int (*func)(struct route_map_index *index,
353 const char *command,
354 const char *arg,
355 char *errmsg, size_t errmsg_len))
356 {
357 rmap_match_set_hook.no_set_metric = func;
358 }
359
360 /* set tag */
361 void route_map_set_tag_hook(int (*func)(struct route_map_index *index,
362 const char *command, const char *arg,
363 char *errmsg, size_t errmsg_len))
364 {
365 rmap_match_set_hook.set_tag = func;
366 }
367
368 /* no set tag */
369 void route_map_no_set_tag_hook(int (*func)(struct route_map_index *index,
370 const char *command,
371 const char *arg,
372 char *errmsg, size_t errmsg_len))
373 {
374 rmap_match_set_hook.no_set_tag = func;
375 }
376
377 int generic_match_add(struct route_map_index *index,
378 const char *command, const char *arg,
379 route_map_event_t type,
380 char *errmsg, size_t errmsg_len)
381 {
382 enum rmap_compile_rets ret;
383
384 ret = route_map_add_match(index, command, arg, type);
385 switch (ret) {
386 case RMAP_RULE_MISSING:
387 snprintf(errmsg, errmsg_len, "%% [%s] Can't find rule.",
388 frr_protonameinst);
389 return CMD_WARNING_CONFIG_FAILED;
390 case RMAP_COMPILE_ERROR:
391 snprintf(errmsg, errmsg_len,
392 "%% [%s] Argument form is unsupported or malformed.",
393 frr_protonameinst);
394 return CMD_WARNING_CONFIG_FAILED;
395 case RMAP_COMPILE_SUCCESS:
396 /*
397 * Nothing to do here move along
398 */
399 break;
400 }
401
402 return CMD_SUCCESS;
403 }
404
405 int generic_match_delete(struct route_map_index *index,
406 const char *command, const char *arg,
407 route_map_event_t type,
408 char *errmsg, size_t errmsg_len)
409 {
410 enum rmap_compile_rets ret;
411 int retval = CMD_SUCCESS;
412 char *dep_name = NULL;
413 const char *tmpstr;
414 char *rmap_name = NULL;
415
416 if (type != RMAP_EVENT_MATCH_DELETED) {
417 /* ignore the mundane, the types without any dependency */
418 if (arg == NULL) {
419 if ((tmpstr = route_map_get_match_arg(index, command))
420 != NULL)
421 dep_name =
422 XSTRDUP(MTYPE_ROUTE_MAP_RULE, tmpstr);
423 } else {
424 dep_name = XSTRDUP(MTYPE_ROUTE_MAP_RULE, arg);
425 }
426 rmap_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, index->map->name);
427 }
428
429 ret = route_map_delete_match(index, command, dep_name, type);
430 switch (ret) {
431 case RMAP_RULE_MISSING:
432 snprintf(errmsg, errmsg_len, "%% [%s] Can't find rule.",
433 frr_protonameinst);
434 retval = CMD_WARNING_CONFIG_FAILED;
435 break;
436 case RMAP_COMPILE_ERROR:
437 snprintf(errmsg, errmsg_len,
438 "%% [%s] Argument form is unsupported or malformed.",
439 frr_protonameinst);
440 retval = CMD_WARNING_CONFIG_FAILED;
441 break;
442 case RMAP_COMPILE_SUCCESS:
443 /*
444 * Nothing to do here
445 */
446 break;
447 }
448
449 XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
450 XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
451
452 return retval;
453 }
454
455 int generic_set_add(struct route_map_index *index,
456 const char *command, const char *arg,
457 char *errmsg, size_t errmsg_len)
458 {
459 enum rmap_compile_rets ret;
460
461 ret = route_map_add_set(index, command, arg);
462 switch (ret) {
463 case RMAP_RULE_MISSING:
464 snprintf(errmsg, errmsg_len,
465 "%% [%s] Can't find rule.", frr_protonameinst);
466 return CMD_WARNING_CONFIG_FAILED;
467 case RMAP_COMPILE_ERROR:
468 snprintf(errmsg, errmsg_len,
469 "%% [%s] Argument form is unsupported or malformed.",
470 frr_protonameinst);
471 return CMD_WARNING_CONFIG_FAILED;
472 case RMAP_COMPILE_SUCCESS:
473 break;
474 }
475
476 return CMD_SUCCESS;
477 }
478
479 int generic_set_delete(struct route_map_index *index,
480 const char *command, const char *arg,
481 char *errmsg, size_t errmsg_len)
482 {
483 enum rmap_compile_rets ret;
484
485 ret = route_map_delete_set(index, command, arg);
486 switch (ret) {
487 case RMAP_RULE_MISSING:
488 snprintf(errmsg, errmsg_len, "%% [%s] Can't find rule.",
489 frr_protonameinst);
490 return CMD_WARNING_CONFIG_FAILED;
491 case RMAP_COMPILE_ERROR:
492 snprintf(errmsg, errmsg_len,
493 "%% [%s] Argument form is unsupported or malformed.",
494 frr_protonameinst);
495 return CMD_WARNING_CONFIG_FAILED;
496 case RMAP_COMPILE_SUCCESS:
497 break;
498 }
499
500 return CMD_SUCCESS;
501 }
502
503
504 /* Master list of route map. */
505 struct route_map_list route_map_master = {NULL, NULL, NULL, NULL, NULL};
506 struct hash *route_map_master_hash = NULL;
507
508 static unsigned int route_map_hash_key_make(const void *p)
509 {
510 const struct route_map *map = p;
511 return string_hash_make(map->name);
512 }
513
514 static bool route_map_hash_cmp(const void *p1, const void *p2)
515 {
516 const struct route_map *map1 = p1;
517 const struct route_map *map2 = p2;
518
519 if (map1->deleted == map2->deleted) {
520 if (map1->name && map2->name) {
521 if (!strcmp(map1->name, map2->name)) {
522 return true;
523 }
524 } else if (!map1->name && !map2->name) {
525 return true;
526 }
527 }
528
529 return false;
530 }
531
532 enum route_map_upd8_type {
533 ROUTE_MAP_ADD = 1,
534 ROUTE_MAP_DEL,
535 };
536
537 /* all possible route-map dependency types */
538 enum route_map_dep_type {
539 ROUTE_MAP_DEP_RMAP = 1,
540 ROUTE_MAP_DEP_CLIST,
541 ROUTE_MAP_DEP_ECLIST,
542 ROUTE_MAP_DEP_LCLIST,
543 ROUTE_MAP_DEP_PLIST,
544 ROUTE_MAP_DEP_ASPATH,
545 ROUTE_MAP_DEP_FILTER,
546 ROUTE_MAP_DEP_MAX,
547 };
548
549 struct route_map_dep {
550 char *dep_name;
551 struct hash *dep_rmap_hash;
552 struct hash *this_hash; /* ptr to the hash structure this is part of */
553 };
554
555 struct route_map_dep_data {
556 /* Route-map name.
557 */
558 char *rname;
559 /* Count of number of sequences of this
560 * route-map that depend on the same entity.
561 */
562 uint16_t refcnt;
563 };
564
565 /* Hashes maintaining dependency between various sublists used by route maps */
566 static struct hash *route_map_dep_hash[ROUTE_MAP_DEP_MAX];
567
568 static unsigned int route_map_dep_hash_make_key(const void *p);
569 static void route_map_clear_all_references(char *rmap_name);
570 static void route_map_rule_delete(struct route_map_rule_list *,
571 struct route_map_rule *);
572 static bool rmap_debug;
573
574 /* New route map allocation. Please note route map's name must be
575 specified. */
576 static struct route_map *route_map_new(const char *name)
577 {
578 struct route_map *new;
579
580 new = XCALLOC(MTYPE_ROUTE_MAP, sizeof(struct route_map));
581 new->name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, name);
582 QOBJ_REG(new, route_map);
583 return new;
584 }
585
586 /* Add new name to route_map. */
587 static struct route_map *route_map_add(const char *name)
588 {
589 struct route_map *map;
590 struct route_map_list *list;
591
592 map = route_map_new(name);
593 list = &route_map_master;
594
595 /* Add map to the hash */
596 hash_get(route_map_master_hash, map, hash_alloc_intern);
597
598 /* Add new entry to the head of the list to match how it is added in the
599 * hash table. This is to ensure that if the same route-map has been
600 * created more than once and then marked for deletion (which can happen
601 * if prior deletions haven't completed as BGP hasn't yet done the
602 * route-map processing), the order of the entities is the same in both
603 * the list and the hash table. Otherwise, since there is nothing to
604 * distinguish between the two entries, the wrong entry could get freed.
605 * TODO: This needs to be re-examined to handle it better - e.g., revive
606 * a deleted entry if the route-map is created again.
607 */
608 map->prev = NULL;
609 map->next = list->head;
610 if (list->head)
611 list->head->prev = map;
612 list->head = map;
613 if (!list->tail)
614 list->tail = map;
615
616 /* Execute hook. */
617 if (route_map_master.add_hook) {
618 (*route_map_master.add_hook)(name);
619 route_map_notify_dependencies(name, RMAP_EVENT_CALL_ADDED);
620 }
621
622 if (!map->ipv4_prefix_table)
623 map->ipv4_prefix_table = route_table_init();
624
625 if (!map->ipv6_prefix_table)
626 map->ipv6_prefix_table = route_table_init();
627
628 if (rmap_debug)
629 zlog_debug("Add route-map %s", name);
630 return map;
631 }
632
633 /* this is supposed to be called post processing by
634 * the delete hook function. Don't invoke delete_hook
635 * again in this routine.
636 */
637 static void route_map_free_map(struct route_map *map)
638 {
639 struct route_map_list *list;
640 struct route_map_index *index;
641
642 if (map == NULL)
643 return;
644
645 while ((index = map->head) != NULL)
646 route_map_index_delete(index, 0);
647
648 if (rmap_debug)
649 zlog_debug("Deleting route-map %s", map->name);
650
651 list = &route_map_master;
652
653 QOBJ_UNREG(map);
654
655 if (map->next)
656 map->next->prev = map->prev;
657 else
658 list->tail = map->prev;
659
660 if (map->prev)
661 map->prev->next = map->next;
662 else
663 list->head = map->next;
664
665 hash_release(route_map_master_hash, map);
666 XFREE(MTYPE_ROUTE_MAP_NAME, map->name);
667 XFREE(MTYPE_ROUTE_MAP, map);
668 }
669
670 /* Route map delete from list. */
671 void route_map_delete(struct route_map *map)
672 {
673 struct route_map_index *index;
674 char *name;
675
676 while ((index = map->head) != NULL)
677 route_map_index_delete(index, 0);
678
679 name = map->name;
680 map->head = NULL;
681
682 /* Clear all dependencies */
683 route_map_clear_all_references(name);
684 map->deleted = true;
685 /* Execute deletion hook. */
686 if (route_map_master.delete_hook) {
687 (*route_map_master.delete_hook)(name);
688 route_map_notify_dependencies(name, RMAP_EVENT_CALL_DELETED);
689 }
690
691 if (!map->to_be_processed) {
692 route_map_free_map(map);
693 }
694 }
695
696 /* Lookup route map by route map name string. */
697 struct route_map *route_map_lookup_by_name(const char *name)
698 {
699 struct route_map *map;
700 struct route_map tmp_map;
701
702 if (!name)
703 return NULL;
704
705 // map.deleted is 0 via memset
706 memset(&tmp_map, 0, sizeof(struct route_map));
707 tmp_map.name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, name);
708 map = hash_lookup(route_map_master_hash, &tmp_map);
709 XFREE(MTYPE_ROUTE_MAP_NAME, tmp_map.name);
710 return map;
711 }
712
713 /* Simple helper to warn if route-map does not exist. */
714 struct route_map *route_map_lookup_warn_noexist(struct vty *vty, const char *name)
715 {
716 struct route_map *route_map = route_map_lookup_by_name(name);
717
718 if (!route_map)
719 if (vty_shell_serv(vty))
720 vty_out(vty, "The route-map '%s' does not exist.\n", name);
721
722 return route_map;
723 }
724
725 int route_map_mark_updated(const char *name)
726 {
727 struct route_map *map;
728 int ret = -1;
729 struct route_map tmp_map;
730
731 if (!name)
732 return (ret);
733
734 map = route_map_lookup_by_name(name);
735
736 /* If we did not find the routemap with deleted=false try again
737 * with deleted=true
738 */
739 if (!map) {
740 memset(&tmp_map, 0, sizeof(struct route_map));
741 tmp_map.name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, name);
742 tmp_map.deleted = true;
743 map = hash_lookup(route_map_master_hash, &tmp_map);
744 XFREE(MTYPE_ROUTE_MAP_NAME, tmp_map.name);
745 }
746
747 if (map) {
748 map->to_be_processed = true;
749 ret = 0;
750 }
751
752 return (ret);
753 }
754
755 static int route_map_clear_updated(struct route_map *map)
756 {
757 int ret = -1;
758
759 if (map) {
760 map->to_be_processed = false;
761 if (map->deleted)
762 route_map_free_map(map);
763 }
764
765 return (ret);
766 }
767
768 /* Lookup route map. If there isn't route map create one and return
769 it. */
770 struct route_map *route_map_get(const char *name)
771 {
772 struct route_map *map;
773
774 map = route_map_lookup_by_name(name);
775 if (map == NULL)
776 map = route_map_add(name);
777
778 return map;
779 }
780
781 void route_map_walk_update_list(void (*route_map_update_fn)(char *name))
782 {
783 struct route_map *node;
784 struct route_map *nnode = NULL;
785
786 for (node = route_map_master.head; node; node = nnode) {
787 if (node->to_be_processed) {
788 /* DD: Should we add any thread yield code here */
789 route_map_update_fn(node->name);
790 nnode = node->next;
791 route_map_clear_updated(node);
792 } else
793 nnode = node->next;
794 }
795 }
796
797 /* Return route map's type string. */
798 static const char *route_map_type_str(enum route_map_type type)
799 {
800 switch (type) {
801 case RMAP_PERMIT:
802 return "permit";
803 case RMAP_DENY:
804 return "deny";
805 case RMAP_ANY:
806 return "";
807 }
808
809 return "";
810 }
811
812 static const char *route_map_cmd_result_str(enum route_map_cmd_result_t res)
813 {
814 switch (res) {
815 case RMAP_MATCH:
816 return "match";
817 case RMAP_NOMATCH:
818 return "no match";
819 case RMAP_NOOP:
820 return "noop";
821 case RMAP_ERROR:
822 return "error";
823 case RMAP_OKAY:
824 return "okay";
825 }
826
827 return "invalid";
828 }
829
830 static const char *route_map_result_str(route_map_result_t res)
831 {
832 switch (res) {
833 case RMAP_DENYMATCH:
834 return "deny";
835 case RMAP_PERMITMATCH:
836 return "permit";
837 }
838
839 return "invalid";
840 }
841
842 /* show route-map */
843 static void vty_show_route_map_entry(struct vty *vty, struct route_map *map)
844 {
845 struct route_map_index *index;
846 struct route_map_rule *rule;
847
848 vty_out(vty, "route-map: %s Invoked: %" PRIu64 " Optimization: %s Processed Change: %s\n",
849 map->name, map->applied - map->applied_clear,
850 map->optimization_disabled ? "disabled" : "enabled",
851 map->to_be_processed ? "true" : "false");
852
853 for (index = map->head; index; index = index->next) {
854 vty_out(vty, " %s, sequence %d Invoked %" PRIu64 "\n",
855 route_map_type_str(index->type), index->pref,
856 index->applied - index->applied_clear);
857
858 /* Description */
859 if (index->description)
860 vty_out(vty, " Description:\n %s\n",
861 index->description);
862
863 /* Match clauses */
864 vty_out(vty, " Match clauses:\n");
865 for (rule = index->match_list.head; rule; rule = rule->next)
866 vty_out(vty, " %s %s\n", rule->cmd->str,
867 rule->rule_str);
868
869 vty_out(vty, " Set clauses:\n");
870 for (rule = index->set_list.head; rule; rule = rule->next)
871 vty_out(vty, " %s %s\n", rule->cmd->str,
872 rule->rule_str);
873
874 /* Call clause */
875 vty_out(vty, " Call clause:\n");
876 if (index->nextrm)
877 vty_out(vty, " Call %s\n", index->nextrm);
878
879 /* Exit Policy */
880 vty_out(vty, " Action:\n");
881 if (index->exitpolicy == RMAP_GOTO)
882 vty_out(vty, " Goto %d\n", index->nextpref);
883 else if (index->exitpolicy == RMAP_NEXT)
884 vty_out(vty, " Continue to next entry\n");
885 else if (index->exitpolicy == RMAP_EXIT)
886 vty_out(vty, " Exit routemap\n");
887 }
888 }
889
890 static int sort_route_map(const void **map1, const void **map2)
891 {
892 const struct route_map *m1 = *map1;
893 const struct route_map *m2 = *map2;
894
895 return strcmp(m1->name, m2->name);
896 }
897
898 static int vty_show_route_map(struct vty *vty, const char *name)
899 {
900 struct route_map *map;
901
902 vty_out(vty, "%s:\n", frr_protonameinst);
903
904 if (name) {
905 map = route_map_lookup_by_name(name);
906
907 if (map) {
908 vty_show_route_map_entry(vty, map);
909 return CMD_SUCCESS;
910 } else {
911 vty_out(vty, "%s: 'route-map %s' not found\n",
912 frr_protonameinst, name);
913 return CMD_SUCCESS;
914 }
915 } else {
916
917 struct list *maplist = list_new();
918 struct listnode *ln;
919
920 for (map = route_map_master.head; map; map = map->next)
921 listnode_add(maplist, map);
922
923 list_sort(maplist, sort_route_map);
924
925 for (ALL_LIST_ELEMENTS_RO(maplist, ln, map))
926 vty_show_route_map_entry(vty, map);
927
928 list_delete(&maplist);
929 }
930 return CMD_SUCCESS;
931 }
932
933 /* Unused route map details */
934 static int vty_show_unused_route_map(struct vty *vty)
935 {
936 struct list *maplist = list_new();
937 struct listnode *ln;
938 struct route_map *map;
939
940 for (map = route_map_master.head; map; map = map->next) {
941 /* If use_count is zero, No protocol is using this routemap.
942 * so adding to the list.
943 */
944 if (!map->use_count)
945 listnode_add(maplist, map);
946 }
947
948 if (maplist->count > 0) {
949 vty_out(vty, "\n%s:\n", frr_protonameinst);
950 list_sort(maplist, sort_route_map);
951
952 for (ALL_LIST_ELEMENTS_RO(maplist, ln, map))
953 vty_show_route_map_entry(vty, map);
954 } else {
955 vty_out(vty, "\n%s: None\n", frr_protonameinst);
956 }
957
958 list_delete(&maplist);
959 return CMD_SUCCESS;
960 }
961
962 /* New route map allocation. Please note route map's name must be
963 specified. */
964 static struct route_map_index *route_map_index_new(void)
965 {
966 struct route_map_index *new;
967
968 new = XCALLOC(MTYPE_ROUTE_MAP_INDEX, sizeof(struct route_map_index));
969 new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */
970 TAILQ_INIT(&new->rhclist);
971 QOBJ_REG(new, route_map_index);
972 return new;
973 }
974
975 /* Free route map index. */
976 void route_map_index_delete(struct route_map_index *index, int notify)
977 {
978 struct routemap_hook_context *rhc;
979 struct route_map_rule *rule;
980
981 QOBJ_UNREG(index);
982
983 if (rmap_debug)
984 zlog_debug("Deleting route-map %s sequence %d",
985 index->map->name, index->pref);
986
987 /* Free route map entry description. */
988 XFREE(MTYPE_TMP, index->description);
989
990 /* Free route map northbound hook contexts. */
991 while ((rhc = TAILQ_FIRST(&index->rhclist)) != NULL)
992 routemap_hook_context_free(rhc);
993
994 /* Free route match. */
995 while ((rule = index->match_list.head) != NULL) {
996 if (IS_RULE_IPv4_PREFIX_LIST(rule->cmd->str))
997 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_DELETED,
998 index, AFI_IP, rule->rule_str);
999 else if (IS_RULE_IPv6_PREFIX_LIST(rule->cmd->str))
1000 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_DELETED,
1001 index, AFI_IP6,
1002 rule->rule_str);
1003
1004 route_map_rule_delete(&index->match_list, rule);
1005 }
1006
1007 /* Free route set. */
1008 while ((rule = index->set_list.head) != NULL)
1009 route_map_rule_delete(&index->set_list, rule);
1010
1011 /* Remove index from route map list. */
1012 if (index->next)
1013 index->next->prev = index->prev;
1014 else
1015 index->map->tail = index->prev;
1016
1017 if (index->prev)
1018 index->prev->next = index->next;
1019 else
1020 index->map->head = index->next;
1021
1022 /* Free 'char *nextrm' if not NULL */
1023 XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
1024
1025 route_map_pfx_tbl_update(RMAP_EVENT_INDEX_DELETED, index, 0, NULL);
1026
1027 /* Execute event hook. */
1028 if (route_map_master.event_hook && notify) {
1029 (*route_map_master.event_hook)(index->map->name);
1030 route_map_notify_dependencies(index->map->name,
1031 RMAP_EVENT_CALL_ADDED);
1032 }
1033 XFREE(MTYPE_ROUTE_MAP_INDEX, index);
1034 }
1035
1036 /* Lookup index from route map. */
1037 static struct route_map_index *route_map_index_lookup(struct route_map *map,
1038 enum route_map_type type,
1039 int pref)
1040 {
1041 struct route_map_index *index;
1042
1043 for (index = map->head; index; index = index->next)
1044 if ((index->type == type || type == RMAP_ANY)
1045 && index->pref == pref)
1046 return index;
1047 return NULL;
1048 }
1049
1050 /* Add new index to route map. */
1051 static struct route_map_index *
1052 route_map_index_add(struct route_map *map, enum route_map_type type, int pref)
1053 {
1054 struct route_map_index *index;
1055 struct route_map_index *point;
1056
1057 /* Allocate new route map inex. */
1058 index = route_map_index_new();
1059 index->map = map;
1060 index->type = type;
1061 index->pref = pref;
1062
1063 /* Compare preference. */
1064 for (point = map->head; point; point = point->next)
1065 if (point->pref >= pref)
1066 break;
1067
1068 if (map->head == NULL) {
1069 map->head = map->tail = index;
1070 } else if (point == NULL) {
1071 index->prev = map->tail;
1072 map->tail->next = index;
1073 map->tail = index;
1074 } else if (point == map->head) {
1075 index->next = map->head;
1076 map->head->prev = index;
1077 map->head = index;
1078 } else {
1079 index->next = point;
1080 index->prev = point->prev;
1081 if (point->prev)
1082 point->prev->next = index;
1083 point->prev = index;
1084 }
1085
1086 route_map_pfx_tbl_update(RMAP_EVENT_INDEX_ADDED, index, 0, NULL);
1087
1088 /* Execute event hook. */
1089 if (route_map_master.event_hook) {
1090 (*route_map_master.event_hook)(map->name);
1091 route_map_notify_dependencies(map->name, RMAP_EVENT_CALL_ADDED);
1092 }
1093
1094 if (rmap_debug)
1095 zlog_debug("Route-map %s add sequence %d, type: %s",
1096 map->name, pref, route_map_type_str(type));
1097
1098 return index;
1099 }
1100
1101 /* Get route map index. */
1102 struct route_map_index *
1103 route_map_index_get(struct route_map *map, enum route_map_type type, int pref)
1104 {
1105 struct route_map_index *index;
1106
1107 index = route_map_index_lookup(map, RMAP_ANY, pref);
1108 if (index && index->type != type) {
1109 /* Delete index from route map. */
1110 route_map_index_delete(index, 1);
1111 index = NULL;
1112 }
1113 if (index == NULL)
1114 index = route_map_index_add(map, type, pref);
1115 return index;
1116 }
1117
1118 /* New route map rule */
1119 static struct route_map_rule *route_map_rule_new(void)
1120 {
1121 struct route_map_rule *new;
1122
1123 new = XCALLOC(MTYPE_ROUTE_MAP_RULE, sizeof(struct route_map_rule));
1124 return new;
1125 }
1126
1127 /* Install rule command to the match list. */
1128 void route_map_install_match(const struct route_map_rule_cmd *cmd)
1129 {
1130 vector_set(route_match_vec, (void *)cmd);
1131 }
1132
1133 /* Install rule command to the set list. */
1134 void route_map_install_set(const struct route_map_rule_cmd *cmd)
1135 {
1136 vector_set(route_set_vec, (void *)cmd);
1137 }
1138
1139 /* Lookup rule command from match list. */
1140 static const struct route_map_rule_cmd *route_map_lookup_match(const char *name)
1141 {
1142 unsigned int i;
1143 const struct route_map_rule_cmd *rule;
1144
1145 for (i = 0; i < vector_active(route_match_vec); i++)
1146 if ((rule = vector_slot(route_match_vec, i)) != NULL)
1147 if (strcmp(rule->str, name) == 0)
1148 return rule;
1149 return NULL;
1150 }
1151
1152 /* Lookup rule command from set list. */
1153 static const struct route_map_rule_cmd *route_map_lookup_set(const char *name)
1154 {
1155 unsigned int i;
1156 const struct route_map_rule_cmd *rule;
1157
1158 for (i = 0; i < vector_active(route_set_vec); i++)
1159 if ((rule = vector_slot(route_set_vec, i)) != NULL)
1160 if (strcmp(rule->str, name) == 0)
1161 return rule;
1162 return NULL;
1163 }
1164
1165 /* Add match and set rule to rule list. */
1166 static void route_map_rule_add(struct route_map_rule_list *list,
1167 struct route_map_rule *rule)
1168 {
1169 rule->next = NULL;
1170 rule->prev = list->tail;
1171 if (list->tail)
1172 list->tail->next = rule;
1173 else
1174 list->head = rule;
1175 list->tail = rule;
1176 }
1177
1178 /* Delete rule from rule list. */
1179 static void route_map_rule_delete(struct route_map_rule_list *list,
1180 struct route_map_rule *rule)
1181 {
1182 if (rule->cmd->func_free)
1183 (*rule->cmd->func_free)(rule->value);
1184
1185 XFREE(MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str);
1186
1187 if (rule->next)
1188 rule->next->prev = rule->prev;
1189 else
1190 list->tail = rule->prev;
1191 if (rule->prev)
1192 rule->prev->next = rule->next;
1193 else
1194 list->head = rule->next;
1195
1196 XFREE(MTYPE_ROUTE_MAP_RULE, rule);
1197 }
1198
1199 /* strcmp wrapper function which don't crush even argument is NULL. */
1200 static int rulecmp(const char *dst, const char *src)
1201 {
1202 if (dst == NULL) {
1203 if (src == NULL)
1204 return 0;
1205 else
1206 return 1;
1207 } else {
1208 if (src == NULL)
1209 return 1;
1210 else
1211 return strcmp(dst, src);
1212 }
1213 return 1;
1214 }
1215
1216 /* Use this to return the already specified argument for this match. This is
1217 * useful to get the specified argument with a route map match rule when the
1218 * rule is being deleted and the argument is not provided.
1219 */
1220 const char *route_map_get_match_arg(struct route_map_index *index,
1221 const char *match_name)
1222 {
1223 struct route_map_rule *rule;
1224 const struct route_map_rule_cmd *cmd;
1225
1226 /* First lookup rule for add match statement. */
1227 cmd = route_map_lookup_match(match_name);
1228 if (cmd == NULL)
1229 return NULL;
1230
1231 for (rule = index->match_list.head; rule; rule = rule->next)
1232 if (rule->cmd == cmd && rule->rule_str != NULL)
1233 return (rule->rule_str);
1234
1235 return NULL;
1236 }
1237
1238 static route_map_event_t get_route_map_delete_event(route_map_event_t type)
1239 {
1240 switch (type) {
1241 case RMAP_EVENT_CALL_ADDED:
1242 return RMAP_EVENT_CALL_DELETED;
1243 case RMAP_EVENT_PLIST_ADDED:
1244 return RMAP_EVENT_PLIST_DELETED;
1245 case RMAP_EVENT_CLIST_ADDED:
1246 return RMAP_EVENT_CLIST_DELETED;
1247 case RMAP_EVENT_ECLIST_ADDED:
1248 return RMAP_EVENT_ECLIST_DELETED;
1249 case RMAP_EVENT_LLIST_ADDED:
1250 return RMAP_EVENT_LLIST_DELETED;
1251 case RMAP_EVENT_ASLIST_ADDED:
1252 return RMAP_EVENT_ASLIST_DELETED;
1253 case RMAP_EVENT_FILTER_ADDED:
1254 return RMAP_EVENT_FILTER_DELETED;
1255 case RMAP_EVENT_SET_ADDED:
1256 case RMAP_EVENT_SET_DELETED:
1257 case RMAP_EVENT_SET_REPLACED:
1258 case RMAP_EVENT_MATCH_ADDED:
1259 case RMAP_EVENT_MATCH_DELETED:
1260 case RMAP_EVENT_MATCH_REPLACED:
1261 case RMAP_EVENT_INDEX_ADDED:
1262 case RMAP_EVENT_INDEX_DELETED:
1263 case RMAP_EVENT_CALL_DELETED:
1264 case RMAP_EVENT_PLIST_DELETED:
1265 case RMAP_EVENT_CLIST_DELETED:
1266 case RMAP_EVENT_ECLIST_DELETED:
1267 case RMAP_EVENT_LLIST_DELETED:
1268 case RMAP_EVENT_ASLIST_DELETED:
1269 case RMAP_EVENT_FILTER_DELETED:
1270 /* This function returns the appropriate 'deleted' event type
1271 * for every 'added' event type passed to this function.
1272 * This is done only for named entities used in the
1273 * route-map match commands.
1274 * This function is not to be invoked for any of the other event
1275 * types.
1276 */
1277 assert(0);
1278 }
1279
1280 assert(0);
1281 /*
1282 * Return to make c happy but if we get here something has gone
1283 * terribly terribly wrong, so yes this return makes no sense.
1284 */
1285 return RMAP_EVENT_CALL_ADDED;
1286 }
1287
1288 /* Add match statement to route map. */
1289 enum rmap_compile_rets route_map_add_match(struct route_map_index *index,
1290 const char *match_name,
1291 const char *match_arg,
1292 route_map_event_t type)
1293 {
1294 struct route_map_rule *rule;
1295 struct route_map_rule *next;
1296 const struct route_map_rule_cmd *cmd;
1297 void *compile;
1298 int8_t delete_rmap_event_type = 0;
1299 const char *rule_key;
1300
1301 /* First lookup rule for add match statement. */
1302 cmd = route_map_lookup_match(match_name);
1303 if (cmd == NULL)
1304 return RMAP_RULE_MISSING;
1305
1306 /* Next call compile function for this match statement. */
1307 if (cmd->func_compile) {
1308 compile = (*cmd->func_compile)(match_arg);
1309 if (compile == NULL)
1310 return RMAP_COMPILE_ERROR;
1311 } else
1312 compile = NULL;
1313 /* use the compiled results if applicable */
1314 if (compile && cmd->func_get_rmap_rule_key)
1315 rule_key = (*cmd->func_get_rmap_rule_key)
1316 (compile);
1317 else
1318 rule_key = match_arg;
1319
1320 /* If argument is completely same ignore it. */
1321 for (rule = index->match_list.head; rule; rule = next) {
1322 next = rule->next;
1323 if (rule->cmd == cmd) {
1324 /* If the configured route-map match rule is exactly
1325 * the same as the existing configuration then,
1326 * ignore the duplicate configuration.
1327 */
1328 if (strcmp(match_arg, rule->rule_str) == 0) {
1329 if (cmd->func_free)
1330 (*cmd->func_free)(compile);
1331
1332 return RMAP_COMPILE_SUCCESS;
1333 }
1334
1335 /* If IPv4 or IPv6 prefix-list match criteria
1336 * has been delete to the route-map index, update
1337 * the route-map's prefix table.
1338 */
1339 if (IS_RULE_IPv4_PREFIX_LIST(match_name))
1340 route_map_pfx_tbl_update(
1341 RMAP_EVENT_PLIST_DELETED, index, AFI_IP,
1342 rule->rule_str);
1343 else if (IS_RULE_IPv6_PREFIX_LIST(match_name))
1344 route_map_pfx_tbl_update(
1345 RMAP_EVENT_PLIST_DELETED, index,
1346 AFI_IP6, rule->rule_str);
1347
1348 /* Remove the dependency of the route-map on the rule
1349 * that is being replaced.
1350 */
1351 if (type >= RMAP_EVENT_CALL_ADDED) {
1352 delete_rmap_event_type =
1353 get_route_map_delete_event(type);
1354 route_map_upd8_dependency(
1355 delete_rmap_event_type,
1356 rule->rule_str,
1357 index->map->name);
1358 }
1359
1360 route_map_rule_delete(&index->match_list, rule);
1361 }
1362 }
1363
1364 /* Add new route map match rule. */
1365 rule = route_map_rule_new();
1366 rule->cmd = cmd;
1367 rule->value = compile;
1368 if (match_arg)
1369 rule->rule_str = XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR, match_arg);
1370 else
1371 rule->rule_str = NULL;
1372
1373 /* Add new route match rule to linked list. */
1374 route_map_rule_add(&index->match_list, rule);
1375
1376 /* If IPv4 or IPv6 prefix-list match criteria
1377 * has been added to the route-map index, update
1378 * the route-map's prefix table.
1379 */
1380 if (IS_RULE_IPv4_PREFIX_LIST(match_name)) {
1381 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_ADDED, index, AFI_IP,
1382 match_arg);
1383 } else if (IS_RULE_IPv6_PREFIX_LIST(match_name)) {
1384 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_ADDED, index, AFI_IP6,
1385 match_arg);
1386 }
1387
1388 /* Execute event hook. */
1389 if (route_map_master.event_hook) {
1390 (*route_map_master.event_hook)(index->map->name);
1391 route_map_notify_dependencies(index->map->name,
1392 RMAP_EVENT_CALL_ADDED);
1393 }
1394 if (type != RMAP_EVENT_MATCH_ADDED)
1395 route_map_upd8_dependency(type, rule_key, index->map->name);
1396
1397 return RMAP_COMPILE_SUCCESS;
1398 }
1399
1400 /* Delete specified route match rule. */
1401 enum rmap_compile_rets route_map_delete_match(struct route_map_index *index,
1402 const char *match_name,
1403 const char *match_arg,
1404 route_map_event_t type)
1405 {
1406 struct route_map_rule *rule;
1407 const struct route_map_rule_cmd *cmd;
1408 const char *rule_key;
1409
1410 cmd = route_map_lookup_match(match_name);
1411 if (cmd == NULL)
1412 return RMAP_RULE_MISSING;
1413
1414 for (rule = index->match_list.head; rule; rule = rule->next)
1415 if (rule->cmd == cmd && (rulecmp(rule->rule_str, match_arg) == 0
1416 || match_arg == NULL)) {
1417 /* Execute event hook. */
1418 if (route_map_master.event_hook) {
1419 (*route_map_master.event_hook)(index->map->name);
1420 route_map_notify_dependencies(
1421 index->map->name,
1422 RMAP_EVENT_CALL_ADDED);
1423 }
1424 if (cmd->func_get_rmap_rule_key)
1425 rule_key = (*cmd->func_get_rmap_rule_key)
1426 (rule->value);
1427 else
1428 rule_key = match_arg;
1429
1430 if (type != RMAP_EVENT_MATCH_DELETED && rule_key)
1431 route_map_upd8_dependency(type, rule_key,
1432 index->map->name);
1433
1434 route_map_rule_delete(&index->match_list, rule);
1435
1436 /* If IPv4 or IPv6 prefix-list match criteria
1437 * has been delete from the route-map index, update
1438 * the route-map's prefix table.
1439 */
1440 if (IS_RULE_IPv4_PREFIX_LIST(match_name)) {
1441 route_map_pfx_tbl_update(
1442 RMAP_EVENT_PLIST_DELETED, index, AFI_IP,
1443 match_arg);
1444 } else if (IS_RULE_IPv6_PREFIX_LIST(match_name)) {
1445 route_map_pfx_tbl_update(
1446 RMAP_EVENT_PLIST_DELETED, index,
1447 AFI_IP6, match_arg);
1448 }
1449
1450 return RMAP_COMPILE_SUCCESS;
1451 }
1452 /* Can't find matched rule. */
1453 return RMAP_RULE_MISSING;
1454 }
1455
1456 /* Add route-map set statement to the route map. */
1457 enum rmap_compile_rets route_map_add_set(struct route_map_index *index,
1458 const char *set_name,
1459 const char *set_arg)
1460 {
1461 struct route_map_rule *rule;
1462 struct route_map_rule *next;
1463 const struct route_map_rule_cmd *cmd;
1464 void *compile;
1465
1466 cmd = route_map_lookup_set(set_name);
1467 if (cmd == NULL)
1468 return RMAP_RULE_MISSING;
1469
1470 /* Next call compile function for this match statement. */
1471 if (cmd->func_compile) {
1472 compile = (*cmd->func_compile)(set_arg);
1473 if (compile == NULL)
1474 return RMAP_COMPILE_ERROR;
1475 } else
1476 compile = NULL;
1477
1478 /* Add by WJL. if old set command of same kind exist, delete it first
1479 to ensure only one set command of same kind exist under a
1480 route_map_index. */
1481 for (rule = index->set_list.head; rule; rule = next) {
1482 next = rule->next;
1483 if (rule->cmd == cmd)
1484 route_map_rule_delete(&index->set_list, rule);
1485 }
1486
1487 /* Add new route map match rule. */
1488 rule = route_map_rule_new();
1489 rule->cmd = cmd;
1490 rule->value = compile;
1491 if (set_arg)
1492 rule->rule_str = XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR, set_arg);
1493 else
1494 rule->rule_str = NULL;
1495
1496 /* Add new route match rule to linked list. */
1497 route_map_rule_add(&index->set_list, rule);
1498
1499 /* Execute event hook. */
1500 if (route_map_master.event_hook) {
1501 (*route_map_master.event_hook)(index->map->name);
1502 route_map_notify_dependencies(index->map->name,
1503 RMAP_EVENT_CALL_ADDED);
1504 }
1505 return RMAP_COMPILE_SUCCESS;
1506 }
1507
1508 /* Delete route map set rule. */
1509 enum rmap_compile_rets route_map_delete_set(struct route_map_index *index,
1510 const char *set_name,
1511 const char *set_arg)
1512 {
1513 struct route_map_rule *rule;
1514 const struct route_map_rule_cmd *cmd;
1515
1516 cmd = route_map_lookup_set(set_name);
1517 if (cmd == NULL)
1518 return RMAP_RULE_MISSING;
1519
1520 for (rule = index->set_list.head; rule; rule = rule->next)
1521 if ((rule->cmd == cmd) && (rulecmp(rule->rule_str, set_arg) == 0
1522 || set_arg == NULL)) {
1523 route_map_rule_delete(&index->set_list, rule);
1524 /* Execute event hook. */
1525 if (route_map_master.event_hook) {
1526 (*route_map_master.event_hook)(index->map->name);
1527 route_map_notify_dependencies(
1528 index->map->name,
1529 RMAP_EVENT_CALL_ADDED);
1530 }
1531 return RMAP_COMPILE_SUCCESS;
1532 }
1533 /* Can't find matched rule. */
1534 return RMAP_RULE_MISSING;
1535 }
1536
1537 static enum route_map_cmd_result_t
1538 route_map_apply_match(struct route_map_rule_list *match_list,
1539 const struct prefix *prefix, void *object)
1540 {
1541 enum route_map_cmd_result_t ret = RMAP_NOMATCH;
1542 struct route_map_rule *match;
1543 bool is_matched = false;
1544
1545
1546 /* Check all match rule and if there is no match rule, go to the
1547 set statement. */
1548 if (!match_list->head)
1549 ret = RMAP_MATCH;
1550 else {
1551 for (match = match_list->head; match; match = match->next) {
1552 /*
1553 * Try each match statement. If any match does not
1554 * return RMAP_MATCH or RMAP_NOOP, return.
1555 * Otherwise continue on to next match statement.
1556 * All match statements must MATCH for
1557 * end-result to be a match.
1558 * (Exception:If match stmts result in a mix of
1559 * MATCH/NOOP, then also end-result is a match)
1560 * If all result in NOOP, end-result is NOOP.
1561 */
1562 ret = (*match->cmd->func_apply)(match->value, prefix,
1563 object);
1564
1565 /*
1566 * If the consolidated result of func_apply is:
1567 * -----------------------------------------------
1568 * | MATCH | NOMATCH | NOOP | Final Result |
1569 * ------------------------------------------------
1570 * | yes | yes | yes | NOMATCH |
1571 * | no | no | yes | NOOP |
1572 * | yes | no | yes | MATCH |
1573 * | no | yes | yes | NOMATCH |
1574 * |-----------------------------------------------
1575 *
1576 * Traditionally, all rules within route-map
1577 * should match for it to MATCH.
1578 * If there are noops within the route-map rules,
1579 * it follows the above matrix.
1580 *
1581 * Eg: route-map rm1 permit 10
1582 * match rule1
1583 * match rule2
1584 * match rule3
1585 * ....
1586 * route-map rm1 permit 20
1587 * match ruleX
1588 * match ruleY
1589 * ...
1590 */
1591
1592 switch (ret) {
1593 case RMAP_MATCH:
1594 is_matched = true;
1595 break;
1596
1597 case RMAP_NOMATCH:
1598 return ret;
1599
1600 case RMAP_NOOP:
1601 if (is_matched)
1602 ret = RMAP_MATCH;
1603 break;
1604
1605 default:
1606 break;
1607 }
1608
1609 }
1610 }
1611 return ret;
1612 }
1613
1614 static struct list *route_map_get_index_list(struct route_node **rn,
1615 const struct prefix *prefix,
1616 struct route_table *table)
1617 {
1618 struct route_node *tmp_rn = NULL;
1619
1620 if (!(*rn)) {
1621 *rn = route_node_match(table, prefix);
1622
1623 if (!(*rn))
1624 return NULL;
1625
1626 if ((*rn)->info)
1627 return (struct list *)((*rn)->info);
1628
1629 /* If rn->info is NULL, get the parent.
1630 * Store the rn in tmp_rn and unlock it later.
1631 */
1632 tmp_rn = *rn;
1633 }
1634
1635 do {
1636 *rn = (*rn)->parent;
1637 if (tmp_rn)
1638 route_unlock_node(tmp_rn);
1639
1640 if (!(*rn))
1641 break;
1642
1643 if ((*rn)->info) {
1644 route_lock_node(*rn);
1645 return (struct list *)((*rn)->info);
1646 }
1647 } while (!(*rn)->info);
1648
1649 return NULL;
1650 }
1651
1652 /*
1653 * This function returns the route-map index that best matches the prefix.
1654 */
1655 static struct route_map_index *route_map_get_index(struct route_map *map,
1656 const struct prefix *prefix,
1657 void *object,
1658 uint8_t *match_ret)
1659 {
1660 int ret = 0;
1661 struct list *candidate_rmap_list = NULL;
1662 struct route_node *rn = NULL;
1663 struct listnode *ln = NULL, *nn = NULL;
1664 struct route_map_index *index = NULL, *best_index = NULL;
1665 struct route_map_index *head_index = NULL;
1666 struct route_table *table = NULL;
1667 unsigned char family = prefix->family;
1668
1669 if (family == AF_INET)
1670 table = map->ipv4_prefix_table;
1671 else
1672 table = map->ipv6_prefix_table;
1673
1674 if (!table)
1675 return NULL;
1676
1677 do {
1678 candidate_rmap_list =
1679 route_map_get_index_list(&rn, prefix, table);
1680 if (!rn)
1681 break;
1682
1683 /* If the index at the head of the list is of seq higher
1684 * than that in best_index, ignore the list and get the
1685 * parent node's list.
1686 */
1687 head_index = (struct route_map_index *)(listgetdata(
1688 listhead(candidate_rmap_list)));
1689 if (best_index && head_index
1690 && (best_index->pref < head_index->pref)) {
1691 route_unlock_node(rn);
1692 continue;
1693 }
1694
1695 for (ALL_LIST_ELEMENTS(candidate_rmap_list, ln, nn, index)) {
1696 /* If the index is of seq higher than that in
1697 * best_index, ignore the list and get the parent
1698 * node's list.
1699 */
1700 if (best_index && (best_index->pref < index->pref))
1701 break;
1702
1703 ret = route_map_apply_match(&index->match_list, prefix,
1704 object);
1705
1706 if (ret == RMAP_MATCH) {
1707 *match_ret = ret;
1708 best_index = index;
1709 break;
1710 } else if (ret == RMAP_NOOP) {
1711 /*
1712 * If match_ret is denymatch, even if we see
1713 * more noops, we retain this return value and
1714 * return this eventually if there are no
1715 * matches.
1716 * If a best match route-map index already
1717 * exists, do not reset the match_ret.
1718 */
1719 if (!best_index && (*match_ret != RMAP_NOMATCH))
1720 *match_ret = ret;
1721 } else {
1722 /*
1723 * ret is RMAP_NOMATCH.
1724 * If a best match route-map index already
1725 * exists, do not reset the match_ret.
1726 */
1727 if (!best_index)
1728 *match_ret = ret;
1729 }
1730 }
1731
1732 route_unlock_node(rn);
1733
1734 } while (rn);
1735
1736 return best_index;
1737 }
1738
1739 static int route_map_candidate_list_cmp(struct route_map_index *idx1,
1740 struct route_map_index *idx2)
1741 {
1742 if (!idx1)
1743 return -1;
1744 if (!idx2)
1745 return 1;
1746
1747 return (idx1->pref - idx2->pref);
1748 }
1749
1750 /*
1751 * This function adds the route-map index into the default route's
1752 * route-node in the route-map's IPv4/IPv6 prefix-table.
1753 */
1754 static void route_map_pfx_table_add_default(afi_t afi,
1755 struct route_map_index *index)
1756 {
1757 struct route_node *rn = NULL;
1758 struct list *rmap_candidate_list = NULL;
1759 struct prefix p;
1760 bool updated_rn = false;
1761 struct route_table *table = NULL;
1762
1763 memset(&p, 0, sizeof(p));
1764 p.family = afi2family(afi);
1765 p.prefixlen = 0;
1766
1767 if (p.family == AF_INET) {
1768 table = index->map->ipv4_prefix_table;
1769 if (!table)
1770 index->map->ipv4_prefix_table = route_table_init();
1771
1772 table = index->map->ipv4_prefix_table;
1773 } else {
1774 table = index->map->ipv6_prefix_table;
1775 if (!table)
1776 index->map->ipv6_prefix_table = route_table_init();
1777
1778 table = index->map->ipv6_prefix_table;
1779 }
1780
1781 /* Add default route to table */
1782 rn = route_node_get(table, &p);
1783
1784 if (!rn)
1785 return;
1786
1787 if (!rn->info) {
1788 rmap_candidate_list = list_new();
1789 rmap_candidate_list->cmp =
1790 (int (*)(void *, void *))route_map_candidate_list_cmp;
1791 rn->info = rmap_candidate_list;
1792 } else {
1793 rmap_candidate_list = (struct list *)rn->info;
1794 updated_rn = true;
1795 }
1796
1797 listnode_add_sort_nodup(rmap_candidate_list, index);
1798 if (updated_rn)
1799 route_unlock_node(rn);
1800 }
1801
1802 /*
1803 * This function removes the route-map index from the default route's
1804 * route-node in the route-map's IPv4/IPv6 prefix-table.
1805 */
1806 static void route_map_pfx_table_del_default(afi_t afi,
1807 struct route_map_index *index)
1808 {
1809 struct route_node *rn = NULL;
1810 struct list *rmap_candidate_list = NULL;
1811 struct prefix p;
1812 struct route_table *table = NULL;
1813
1814 memset(&p, 0, sizeof(p));
1815 p.family = afi2family(afi);
1816 p.prefixlen = 0;
1817
1818 if (p.family == AF_INET)
1819 table = index->map->ipv4_prefix_table;
1820 else
1821 table = index->map->ipv6_prefix_table;
1822
1823 /* Remove RMAP index from default route in table */
1824 rn = route_node_lookup(table, &p);
1825 if (!rn || !rn->info)
1826 return;
1827
1828 rmap_candidate_list = (struct list *)rn->info;
1829
1830 listnode_delete(rmap_candidate_list, index);
1831
1832 if (listcount(rmap_candidate_list) == 0) {
1833 list_delete(&rmap_candidate_list);
1834 rn->info = NULL;
1835 route_unlock_node(rn);
1836 }
1837 route_unlock_node(rn);
1838 }
1839
1840 /*
1841 * This function adds the route-map index to the route-node for
1842 * the prefix-entry in the route-map's IPv4/IPv6 prefix-table.
1843 */
1844 static void route_map_pfx_table_add(struct route_table *table,
1845 struct route_map_index *index,
1846 struct prefix_list_entry *pentry)
1847 {
1848 struct route_node *rn = NULL;
1849 struct list *rmap_candidate_list = NULL;
1850 bool updated_rn = false;
1851
1852 rn = route_node_get(table, &pentry->prefix);
1853 if (!rn)
1854 return;
1855
1856 if (!rn->info) {
1857 rmap_candidate_list = list_new();
1858 rmap_candidate_list->cmp =
1859 (int (*)(void *, void *))route_map_candidate_list_cmp;
1860 rn->info = rmap_candidate_list;
1861 } else {
1862 rmap_candidate_list = (struct list *)rn->info;
1863 updated_rn = true;
1864 }
1865
1866 listnode_add_sort_nodup(rmap_candidate_list, index);
1867 if (updated_rn)
1868 route_unlock_node(rn);
1869 }
1870
1871 /*
1872 * This function removes the route-map index from the route-node for
1873 * the prefix-entry in the route-map's IPv4/IPv6 prefix-table.
1874 */
1875 static void route_map_pfx_table_del(struct route_table *table,
1876 struct route_map_index *index,
1877 struct prefix_list_entry *pentry)
1878 {
1879 struct route_node *rn = NULL;
1880 struct list *rmap_candidate_list = NULL;
1881
1882 rn = route_node_lookup(table, &pentry->prefix);
1883 if (!rn || !rn->info)
1884 return;
1885
1886 rmap_candidate_list = (struct list *)rn->info;
1887
1888 listnode_delete(rmap_candidate_list, index);
1889
1890 if (listcount(rmap_candidate_list) == 0) {
1891 list_delete(&rmap_candidate_list);
1892 rn->info = NULL;
1893 route_unlock_node(rn);
1894 }
1895 route_unlock_node(rn);
1896 }
1897
1898 /* This function checks for the presence of an IPv4 prefix-list
1899 * match rule in the given route-map index.
1900 */
1901 static bool route_map_is_ip_pfx_list_rule_present(struct route_map_index *index)
1902 {
1903 struct route_map_rule_list *match_list = NULL;
1904 struct route_map_rule *rule = NULL;
1905
1906 match_list = &index->match_list;
1907 for (rule = match_list->head; rule; rule = rule->next)
1908 if (IS_RULE_IPv4_PREFIX_LIST(rule->cmd->str))
1909 return true;
1910
1911 return false;
1912 }
1913
1914 /* This function checks for the presence of an IPv6 prefix-list
1915 * match rule in the given route-map index.
1916 */
1917 static bool
1918 route_map_is_ipv6_pfx_list_rule_present(struct route_map_index *index)
1919 {
1920 struct route_map_rule_list *match_list = NULL;
1921 struct route_map_rule *rule = NULL;
1922
1923 match_list = &index->match_list;
1924 for (rule = match_list->head; rule; rule = rule->next)
1925 if (IS_RULE_IPv6_PREFIX_LIST(rule->cmd->str))
1926 return true;
1927
1928 return false;
1929 }
1930
1931 /* This function does the following:
1932 * 1) If plist_name is not present, search for a IPv4 or IPv6 prefix-list
1933 * match clause (based on the afi passed to this foo) and get the
1934 * prefix-list name.
1935 * 2) Look up the prefix-list using the name.
1936 * 3) If the prefix-list is not found then, add the index to the IPv4/IPv6
1937 * default-route's node in the trie (based on the afi passed to this foo).
1938 * 4) If the prefix-list is found then, remove the index from the IPv4/IPv6
1939 * default-route's node in the trie (based on the afi passed to this foo).
1940 * 5) If a prefix-entry is passed then, create a route-node for this entry and
1941 * add this index to the route-node.
1942 * 6) If prefix-entry is not passed then, for every prefix-entry in the
1943 * prefix-list, create a route-node for this entry and
1944 * add this index to the route-node.
1945 */
1946 static void route_map_add_plist_entries(afi_t afi,
1947 struct route_map_index *index,
1948 const char *plist_name,
1949 struct prefix_list_entry *entry)
1950 {
1951 struct route_map_rule_list *match_list = NULL;
1952 struct route_map_rule *match = NULL;
1953 struct prefix_list *plist = NULL;
1954 struct prefix_list_entry *pentry = NULL;
1955 bool plist_rule_is_present = false;
1956
1957 if (!plist_name) {
1958 match_list = &index->match_list;
1959
1960 for (match = match_list->head; match; match = match->next) {
1961 if (afi == AFI_IP) {
1962 if (IS_RULE_IPv4_PREFIX_LIST(match->cmd->str)) {
1963 plist_rule_is_present = true;
1964 break;
1965 }
1966 } else {
1967 if (IS_RULE_IPv6_PREFIX_LIST(match->cmd->str)) {
1968 plist_rule_is_present = true;
1969 break;
1970 }
1971 }
1972 }
1973
1974 if (plist_rule_is_present)
1975 plist = prefix_list_lookup(afi, match->rule_str);
1976 } else {
1977 plist = prefix_list_lookup(afi, plist_name);
1978 }
1979
1980 if (!plist) {
1981 route_map_pfx_table_add_default(afi, index);
1982 return;
1983 }
1984
1985 route_map_pfx_table_del_default(afi, index);
1986
1987 if (entry) {
1988 if (afi == AFI_IP) {
1989 route_map_pfx_table_add(index->map->ipv4_prefix_table,
1990 index, entry);
1991 } else {
1992 route_map_pfx_table_add(index->map->ipv6_prefix_table,
1993 index, entry);
1994 }
1995 } else {
1996 for (pentry = plist->head; pentry; pentry = pentry->next) {
1997 if (afi == AFI_IP) {
1998 route_map_pfx_table_add(
1999 index->map->ipv4_prefix_table, index,
2000 pentry);
2001 } else {
2002 route_map_pfx_table_add(
2003 index->map->ipv6_prefix_table, index,
2004 pentry);
2005 }
2006 }
2007 }
2008 }
2009
2010 /* This function does the following:
2011 * 1) If plist_name is not present, search for a IPv4 or IPv6 prefix-list
2012 * match clause (based on the afi passed to this foo) and get the
2013 * prefix-list name.
2014 * 2) Look up the prefix-list using the name.
2015 * 3) If the prefix-list is not found then, delete the index from the IPv4/IPv6
2016 * default-route's node in the trie (based on the afi passed to this foo).
2017 * 4) If a prefix-entry is passed then, remove this index from the route-node
2018 * for the prefix in this prefix-entry.
2019 * 5) If prefix-entry is not passed then, for every prefix-entry in the
2020 * prefix-list, remove this index from the route-node
2021 * for the prefix in this prefix-entry.
2022 */
2023 static void route_map_del_plist_entries(afi_t afi,
2024 struct route_map_index *index,
2025 const char *plist_name,
2026 struct prefix_list_entry *entry)
2027 {
2028 struct route_map_rule_list *match_list = NULL;
2029 struct route_map_rule *match = NULL;
2030 struct prefix_list *plist = NULL;
2031 struct prefix_list_entry *pentry = NULL;
2032 bool plist_rule_is_present = false;
2033
2034 if (!plist_name) {
2035 match_list = &index->match_list;
2036
2037 for (match = match_list->head; match; match = match->next) {
2038 if (afi == AFI_IP) {
2039 if (IS_RULE_IPv4_PREFIX_LIST(match->cmd->str)) {
2040 plist_rule_is_present = true;
2041 break;
2042 }
2043 } else {
2044 if (IS_RULE_IPv6_PREFIX_LIST(match->cmd->str)) {
2045 plist_rule_is_present = true;
2046 break;
2047 }
2048 }
2049 }
2050
2051 if (plist_rule_is_present)
2052 plist = prefix_list_lookup(afi, match->rule_str);
2053 } else {
2054 plist = prefix_list_lookup(afi, plist_name);
2055 }
2056
2057 if (!plist) {
2058 route_map_pfx_table_del_default(afi, index);
2059 return;
2060 }
2061
2062 if (entry) {
2063 if (afi == AFI_IP) {
2064 route_map_pfx_table_del(index->map->ipv4_prefix_table,
2065 index, entry);
2066 } else {
2067 route_map_pfx_table_del(index->map->ipv6_prefix_table,
2068 index, entry);
2069 }
2070 } else {
2071 for (pentry = plist->head; pentry; pentry = pentry->next) {
2072 if (afi == AFI_IP) {
2073 route_map_pfx_table_del(
2074 index->map->ipv4_prefix_table, index,
2075 pentry);
2076 } else {
2077 route_map_pfx_table_del(
2078 index->map->ipv6_prefix_table, index,
2079 pentry);
2080 }
2081 }
2082 }
2083 }
2084
2085 /*
2086 * This function handles the cases where a prefix-list is added/removed
2087 * as a match command from a particular route-map index.
2088 * It updates the prefix-table of the route-map accordingly.
2089 */
2090 static void route_map_trie_update(afi_t afi, route_map_event_t event,
2091 struct route_map_index *index,
2092 const char *plist_name)
2093 {
2094 if (event == RMAP_EVENT_PLIST_ADDED) {
2095 if (afi == AFI_IP) {
2096 if (!route_map_is_ipv6_pfx_list_rule_present(index)) {
2097 route_map_pfx_table_del_default(AFI_IP6, index);
2098 route_map_add_plist_entries(afi, index,
2099 plist_name, NULL);
2100 } else {
2101 route_map_del_plist_entries(AFI_IP6, index,
2102 NULL, NULL);
2103 }
2104 } else {
2105 if (!route_map_is_ip_pfx_list_rule_present(index)) {
2106 route_map_pfx_table_del_default(AFI_IP, index);
2107 route_map_add_plist_entries(afi, index,
2108 plist_name, NULL);
2109 } else {
2110 route_map_del_plist_entries(AFI_IP, index, NULL,
2111 NULL);
2112 }
2113 }
2114 } else if (event == RMAP_EVENT_PLIST_DELETED) {
2115 if (afi == AFI_IP) {
2116 route_map_del_plist_entries(afi, index, plist_name,
2117 NULL);
2118
2119 /* If IPv6 prefix-list match rule is not present,
2120 * add this index to the IPv4 default route's trie
2121 * node.
2122 * Also, add this index to the trie nodes created
2123 * for each of the prefix-entries within the IPv6
2124 * prefix-list, if the IPv6 prefix-list match rule
2125 * is present. Else, add this index to the IPv6
2126 * default route's trie node.
2127 */
2128 if (!route_map_is_ipv6_pfx_list_rule_present(index))
2129 route_map_pfx_table_add_default(afi, index);
2130
2131 route_map_add_plist_entries(AFI_IP6, index, NULL, NULL);
2132 } else {
2133 route_map_del_plist_entries(afi, index, plist_name,
2134 NULL);
2135
2136 /* If IPv4 prefix-list match rule is not present,
2137 * add this index to the IPv6 default route's trie
2138 * node.
2139 * Also, add this index to the trie nodes created
2140 * for each of the prefix-entries within the IPv4
2141 * prefix-list, if the IPv4 prefix-list match rule
2142 * is present. Else, add this index to the IPv4
2143 * default route's trie node.
2144 */
2145 if (!route_map_is_ip_pfx_list_rule_present(index))
2146 route_map_pfx_table_add_default(afi, index);
2147
2148 route_map_add_plist_entries(AFI_IP, index, NULL, NULL);
2149 }
2150 }
2151 }
2152
2153 /*
2154 * This function handles the cases where a route-map index and
2155 * prefix-list is added/removed.
2156 * It updates the prefix-table of the route-map accordingly.
2157 */
2158 static void route_map_pfx_tbl_update(route_map_event_t event,
2159 struct route_map_index *index, afi_t afi,
2160 const char *plist_name)
2161 {
2162 struct route_map *rmap = NULL;
2163
2164 if (!index)
2165 return;
2166
2167 if (event == RMAP_EVENT_INDEX_ADDED) {
2168 route_map_pfx_table_add_default(AFI_IP, index);
2169 route_map_pfx_table_add_default(AFI_IP6, index);
2170 return;
2171 }
2172
2173 if (event == RMAP_EVENT_INDEX_DELETED) {
2174 route_map_pfx_table_del_default(AFI_IP, index);
2175 route_map_pfx_table_del_default(AFI_IP6, index);
2176
2177 if ((index->map->head == NULL) && (index->map->tail == NULL)) {
2178 rmap = index->map;
2179
2180 if (rmap->ipv4_prefix_table) {
2181 route_table_finish(rmap->ipv4_prefix_table);
2182 rmap->ipv4_prefix_table = NULL;
2183 }
2184
2185 if (rmap->ipv6_prefix_table) {
2186 route_table_finish(rmap->ipv6_prefix_table);
2187 rmap->ipv6_prefix_table = NULL;
2188 }
2189 }
2190 return;
2191 }
2192
2193 /* Handle prefix-list match rule addition/deletion.
2194 */
2195 route_map_trie_update(afi, event, index, plist_name);
2196 }
2197
2198 /*
2199 * This function handles the cases where a new prefix-entry is added to
2200 * a prefix-list or, an existing prefix-entry is removed from the prefix-list.
2201 * It updates the prefix-table of the route-map accordingly.
2202 */
2203 static void route_map_pentry_update(route_map_event_t event,
2204 const char *plist_name,
2205 struct route_map_index *index,
2206 struct prefix_list_entry *pentry)
2207 {
2208 struct prefix_list *plist = NULL;
2209 afi_t afi;
2210 unsigned char family = pentry->prefix.family;
2211
2212 if (family == AF_INET) {
2213 afi = AFI_IP;
2214 plist = prefix_list_lookup(AFI_IP, plist_name);
2215 } else {
2216 afi = AFI_IP6;
2217 plist = prefix_list_lookup(AFI_IP6, plist_name);
2218 }
2219
2220 if (event == RMAP_EVENT_PLIST_ADDED) {
2221 if (afi == AFI_IP) {
2222 if (!route_map_is_ipv6_pfx_list_rule_present(index))
2223 route_map_add_plist_entries(afi, index,
2224 plist_name, pentry);
2225 } else {
2226 if (!route_map_is_ip_pfx_list_rule_present(index))
2227 route_map_add_plist_entries(afi, index,
2228 plist_name, pentry);
2229 }
2230 } else if (event == RMAP_EVENT_PLIST_DELETED) {
2231 route_map_del_plist_entries(afi, index, plist_name, pentry);
2232
2233 if (plist->count == 1) {
2234 if (afi == AFI_IP) {
2235 if (!route_map_is_ipv6_pfx_list_rule_present(
2236 index))
2237 route_map_pfx_table_add_default(afi,
2238 index);
2239 } else {
2240 if (!route_map_is_ip_pfx_list_rule_present(
2241 index))
2242 route_map_pfx_table_add_default(afi,
2243 index);
2244 }
2245 }
2246 }
2247 }
2248
2249 static void route_map_pentry_process_dependency(struct hash_bucket *bucket,
2250 void *data)
2251 {
2252 char *rmap_name = NULL;
2253 struct route_map *rmap = NULL;
2254 struct route_map_index *index = NULL;
2255 struct route_map_rule_list *match_list = NULL;
2256 struct route_map_rule *match = NULL;
2257 struct route_map_dep_data *dep_data = NULL;
2258 struct route_map_pentry_dep *pentry_dep =
2259 (struct route_map_pentry_dep *)data;
2260 unsigned char family = pentry_dep->pentry->prefix.family;
2261
2262 dep_data = (struct route_map_dep_data *)bucket->data;
2263 if (!dep_data)
2264 return;
2265
2266 rmap_name = dep_data->rname;
2267 rmap = route_map_lookup_by_name(rmap_name);
2268 if (!rmap || !rmap->head)
2269 return;
2270
2271 for (index = rmap->head; index; index = index->next) {
2272 match_list = &index->match_list;
2273
2274 if (!match_list)
2275 continue;
2276
2277 for (match = match_list->head; match; match = match->next) {
2278 if (strcmp(match->rule_str, pentry_dep->plist_name)
2279 == 0) {
2280 if (IS_RULE_IPv4_PREFIX_LIST(match->cmd->str)
2281 && family == AF_INET) {
2282 route_map_pentry_update(
2283 pentry_dep->event,
2284 pentry_dep->plist_name, index,
2285 pentry_dep->pentry);
2286 } else if (IS_RULE_IPv6_PREFIX_LIST(
2287 match->cmd->str)
2288 && family == AF_INET6) {
2289 route_map_pentry_update(
2290 pentry_dep->event,
2291 pentry_dep->plist_name, index,
2292 pentry_dep->pentry);
2293 }
2294 }
2295 }
2296 }
2297 }
2298
2299 void route_map_notify_pentry_dependencies(const char *affected_name,
2300 struct prefix_list_entry *pentry,
2301 route_map_event_t event)
2302 {
2303 struct route_map_dep *dep = NULL;
2304 struct hash *upd8_hash = NULL;
2305 struct route_map_pentry_dep pentry_dep;
2306
2307 if (!affected_name || !pentry)
2308 return;
2309
2310 upd8_hash = route_map_get_dep_hash(event);
2311 if (!upd8_hash)
2312 return;
2313
2314 dep = (struct route_map_dep *)hash_get(upd8_hash, (void *)affected_name,
2315 NULL);
2316 if (dep) {
2317 if (!dep->this_hash)
2318 dep->this_hash = upd8_hash;
2319
2320 memset(&pentry_dep, 0, sizeof(struct route_map_pentry_dep));
2321 pentry_dep.pentry = pentry;
2322 pentry_dep.plist_name = affected_name;
2323 pentry_dep.event = event;
2324
2325 hash_iterate(dep->dep_rmap_hash,
2326 route_map_pentry_process_dependency,
2327 (void *)&pentry_dep);
2328 }
2329 }
2330
2331 /* Apply route map's each index to the object.
2332
2333 The matrix for a route-map looks like this:
2334 (note, this includes the description for the "NEXT"
2335 and "GOTO" frobs now
2336
2337 | Match | No Match | No op
2338 |-----------|--------------|-------
2339 permit | action | cont | cont.
2340 | | default:deny | default:permit
2341 -------------------+-----------------------
2342 | deny | cont | cont.
2343 deny | | default:deny | default:permit
2344 |-----------|--------------|--------
2345
2346 action)
2347 -Apply Set statements, accept route
2348 -If Call statement is present jump to the specified route-map, if it
2349 denies the route we finish.
2350 -If NEXT is specified, goto NEXT statement
2351 -If GOTO is specified, goto the first clause where pref > nextpref
2352 -If nothing is specified, do as Cisco and finish
2353 deny)
2354 -Route is denied by route-map.
2355 cont)
2356 -Goto Next index
2357
2358 If we get no matches after we've processed all updates, then the route
2359 is dropped too.
2360
2361 Some notes on the new "CALL", "NEXT" and "GOTO"
2362 call WORD - If this clause is matched, then the set statements
2363 are executed and then we jump to route-map 'WORD'. If
2364 this route-map denies the route, we finish, in other
2365 case we
2366 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
2367 on-match next - If this clause is matched, then the set statements
2368 are executed and then we drop through to the next clause
2369 on-match goto n - If this clause is matched, then the set statments
2370 are executed and then we goto the nth clause, or the
2371 first clause greater than this. In order to ensure
2372 route-maps *always* exit, you cannot jump backwards.
2373 Sorry ;)
2374
2375 We need to make sure our route-map processing matches the above
2376 */
2377 route_map_result_t route_map_apply(struct route_map *map,
2378 const struct prefix *prefix, void *object)
2379 {
2380 static int recursion = 0;
2381 enum route_map_cmd_result_t match_ret = RMAP_NOMATCH;
2382 route_map_result_t ret = RMAP_PERMITMATCH;
2383 struct route_map_index *index = NULL;
2384 struct route_map_rule *set = NULL;
2385 bool skip_match_clause = false;
2386
2387 if (recursion > RMAP_RECURSION_LIMIT) {
2388 flog_warn(
2389 EC_LIB_RMAP_RECURSION_LIMIT,
2390 "route-map recursion limit (%d) reached, discarding route",
2391 RMAP_RECURSION_LIMIT);
2392 recursion = 0;
2393 return RMAP_DENYMATCH;
2394 }
2395
2396 if (map == NULL || map->head == NULL) {
2397 ret = RMAP_DENYMATCH;
2398 goto route_map_apply_end;
2399 }
2400
2401 map->applied++;
2402
2403 if ((!map->optimization_disabled)
2404 && (map->ipv4_prefix_table || map->ipv6_prefix_table)) {
2405 index = route_map_get_index(map, prefix, object,
2406 (uint8_t *)&match_ret);
2407 if (index) {
2408 index->applied++;
2409 if (rmap_debug)
2410 zlog_debug(
2411 "Best match route-map: %s, sequence: %d for pfx: %pFX, result: %s",
2412 map->name, index->pref, prefix,
2413 route_map_cmd_result_str(match_ret));
2414 } else {
2415 if (rmap_debug)
2416 zlog_debug(
2417 "No best match sequence for pfx: %pFX in route-map: %s, result: %s",
2418 prefix, map->name,
2419 route_map_cmd_result_str(match_ret));
2420 /*
2421 * No index matches this prefix. Return deny unless,
2422 * match_ret = RMAP_NOOP.
2423 */
2424 if (match_ret == RMAP_NOOP)
2425 ret = RMAP_PERMITMATCH;
2426 else
2427 ret = RMAP_DENYMATCH;
2428 goto route_map_apply_end;
2429 }
2430 skip_match_clause = true;
2431 } else {
2432 index = map->head;
2433 }
2434
2435 for (; index; index = index->next) {
2436 if (!skip_match_clause) {
2437 index->applied++;
2438 /* Apply this index. */
2439 match_ret = route_map_apply_match(&index->match_list,
2440 prefix, object);
2441 if (rmap_debug) {
2442 zlog_debug(
2443 "Route-map: %s, sequence: %d, prefix: %pFX, result: %s",
2444 map->name, index->pref, prefix,
2445 route_map_cmd_result_str(match_ret));
2446 }
2447 } else
2448 skip_match_clause = false;
2449
2450
2451 /* Now we apply the matrix from above */
2452 if (match_ret == RMAP_NOOP)
2453 /*
2454 * Do not change the return value. Retain the previous
2455 * return value. Previous values can be:
2456 * 1)permitmatch (if a nomatch was never
2457 * seen before in this route-map.)
2458 * 2)denymatch (if a nomatch was seen earlier in one
2459 * of the previous sequences)
2460 */
2461
2462 /*
2463 * 'cont' from matrix - continue to next route-map
2464 * sequence
2465 */
2466 continue;
2467 else if (match_ret == RMAP_NOMATCH) {
2468
2469 /*
2470 * The return value is now changed to denymatch.
2471 * So from here on out, even if we see more noops,
2472 * we retain this return value and return this
2473 * eventually if there are no matches.
2474 */
2475 ret = RMAP_DENYMATCH;
2476
2477 /*
2478 * 'cont' from matrix - continue to next route-map
2479 * sequence
2480 */
2481 continue;
2482 } else if (match_ret == RMAP_MATCH) {
2483 if (index->type == RMAP_PERMIT)
2484 /* 'action' */
2485 {
2486 /* Match succeeded, rmap is of type permit */
2487 ret = RMAP_PERMITMATCH;
2488
2489 /* permit+match must execute sets */
2490 for (set = index->set_list.head; set;
2491 set = set->next)
2492 /*
2493 * set cmds return RMAP_OKAY or
2494 * RMAP_ERROR. We do not care if
2495 * set succeeded or not. So, ignore
2496 * return code.
2497 */
2498 (void)(*set->cmd->func_apply)(
2499 set->value, prefix, object);
2500
2501 /* Call another route-map if available */
2502 if (index->nextrm) {
2503 struct route_map *nextrm =
2504 route_map_lookup_by_name(
2505 index->nextrm);
2506
2507 if (nextrm) /* Target route-map found,
2508 jump to it */
2509 {
2510 recursion++;
2511 ret = route_map_apply(
2512 nextrm, prefix, object);
2513 recursion--;
2514 }
2515
2516 /* If nextrm returned 'deny', finish. */
2517 if (ret == RMAP_DENYMATCH)
2518 goto route_map_apply_end;
2519 }
2520
2521 switch (index->exitpolicy) {
2522 case RMAP_EXIT:
2523 goto route_map_apply_end;
2524 case RMAP_NEXT:
2525 continue;
2526 case RMAP_GOTO: {
2527 /* Find the next clause to jump to */
2528 struct route_map_index *next =
2529 index->next;
2530 int nextpref = index->nextpref;
2531
2532 while (next && next->pref < nextpref) {
2533 index = next;
2534 next = next->next;
2535 }
2536 if (next == NULL) {
2537 /* No clauses match! */
2538 goto route_map_apply_end;
2539 }
2540 }
2541 }
2542 } else if (index->type == RMAP_DENY)
2543 /* 'deny' */
2544 {
2545 ret = RMAP_DENYMATCH;
2546 goto route_map_apply_end;
2547 }
2548 }
2549 }
2550
2551 route_map_apply_end:
2552 if (rmap_debug)
2553 zlog_debug("Route-map: %s, prefix: %pFX, result: %s",
2554 (map ? map->name : "null"), prefix,
2555 route_map_result_str(ret));
2556
2557 return (ret);
2558 }
2559
2560 void route_map_add_hook(void (*func)(const char *))
2561 {
2562 route_map_master.add_hook = func;
2563 }
2564
2565 void route_map_delete_hook(void (*func)(const char *))
2566 {
2567 route_map_master.delete_hook = func;
2568 }
2569
2570 void route_map_event_hook(void (*func)(const char *name))
2571 {
2572 route_map_master.event_hook = func;
2573 }
2574
2575 /* Routines for route map dependency lists and dependency processing */
2576 static bool route_map_rmap_hash_cmp(const void *p1, const void *p2)
2577 {
2578 return strcmp(((const struct route_map_dep_data *)p1)->rname,
2579 ((const struct route_map_dep_data *)p2)->rname)
2580 == 0;
2581 }
2582
2583 static bool route_map_dep_hash_cmp(const void *p1, const void *p2)
2584 {
2585
2586 return (strcmp(((const struct route_map_dep *)p1)->dep_name,
2587 (const char *)p2)
2588 == 0);
2589 }
2590
2591 static void route_map_clear_reference(struct hash_bucket *bucket, void *arg)
2592 {
2593 struct route_map_dep *dep = bucket->data;
2594 struct route_map_dep_data *dep_data = NULL, tmp_dep_data;
2595
2596 memset(&tmp_dep_data, 0, sizeof(struct route_map_dep_data));
2597 tmp_dep_data.rname = arg;
2598 dep_data = hash_release(dep->dep_rmap_hash, &tmp_dep_data);
2599 if (dep_data) {
2600 if (rmap_debug)
2601 zlog_debug("Clearing reference for %s to %s count: %d",
2602 dep->dep_name, tmp_dep_data.rname,
2603 dep_data->refcnt);
2604
2605 XFREE(MTYPE_ROUTE_MAP_NAME, dep_data->rname);
2606 XFREE(MTYPE_ROUTE_MAP_DEP_DATA, dep_data);
2607 }
2608 if (!dep->dep_rmap_hash->count) {
2609 dep = hash_release(dep->this_hash, (void *)dep->dep_name);
2610 hash_free(dep->dep_rmap_hash);
2611 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
2612 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
2613 }
2614 }
2615
2616 static void route_map_clear_all_references(char *rmap_name)
2617 {
2618 int i;
2619
2620 if (rmap_debug)
2621 zlog_debug("Clearing references for %s", rmap_name);
2622
2623 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
2624 hash_iterate(route_map_dep_hash[i], route_map_clear_reference,
2625 (void *)rmap_name);
2626 }
2627 }
2628
2629 static unsigned int route_map_dep_data_hash_make_key(const void *p)
2630 {
2631 const struct route_map_dep_data *dep_data = p;
2632
2633 return string_hash_make(dep_data->rname);
2634 }
2635
2636 static void *route_map_dep_hash_alloc(void *p)
2637 {
2638 char *dep_name = (char *)p;
2639 struct route_map_dep *dep_entry;
2640
2641 dep_entry = XCALLOC(MTYPE_ROUTE_MAP_DEP, sizeof(struct route_map_dep));
2642 dep_entry->dep_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
2643 dep_entry->dep_rmap_hash =
2644 hash_create_size(8, route_map_dep_data_hash_make_key,
2645 route_map_rmap_hash_cmp, "Route Map Dep Hash");
2646 dep_entry->this_hash = NULL;
2647
2648 return dep_entry;
2649 }
2650
2651 static void *route_map_name_hash_alloc(void *p)
2652 {
2653 struct route_map_dep_data *dep_data = NULL, *tmp_dep_data = NULL;
2654
2655 dep_data = XCALLOC(MTYPE_ROUTE_MAP_DEP_DATA,
2656 sizeof(struct route_map_dep_data));
2657 tmp_dep_data = p;
2658 dep_data->rname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, tmp_dep_data->rname);
2659 return dep_data;
2660 }
2661
2662 static unsigned int route_map_dep_hash_make_key(const void *p)
2663 {
2664 return (string_hash_make((char *)p));
2665 }
2666
2667 static void route_map_print_dependency(struct hash_bucket *bucket, void *data)
2668 {
2669 struct route_map_dep_data *dep_data = bucket->data;
2670 char *rmap_name = dep_data->rname;
2671 char *dep_name = data;
2672
2673 zlog_debug("%s: Dependency for %s: %s", __func__, dep_name, rmap_name);
2674 }
2675
2676 static int route_map_dep_update(struct hash *dephash, const char *dep_name,
2677 const char *rmap_name, route_map_event_t type)
2678 {
2679 struct route_map_dep *dep = NULL;
2680 char *dname, *rname;
2681 int ret = 0;
2682 struct route_map_dep_data *dep_data = NULL, *ret_dep_data = NULL;
2683 struct route_map_dep_data tmp_dep_data;
2684
2685 dname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
2686 rname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_name);
2687
2688 switch (type) {
2689 case RMAP_EVENT_PLIST_ADDED:
2690 case RMAP_EVENT_CLIST_ADDED:
2691 case RMAP_EVENT_ECLIST_ADDED:
2692 case RMAP_EVENT_ASLIST_ADDED:
2693 case RMAP_EVENT_LLIST_ADDED:
2694 case RMAP_EVENT_CALL_ADDED:
2695 case RMAP_EVENT_FILTER_ADDED:
2696 if (rmap_debug)
2697 zlog_debug("Adding dependency for filter %s in route-map %s",
2698 dep_name, rmap_name);
2699 dep = (struct route_map_dep *)hash_get(
2700 dephash, dname, route_map_dep_hash_alloc);
2701 if (!dep) {
2702 ret = -1;
2703 goto out;
2704 }
2705
2706 if (!dep->this_hash)
2707 dep->this_hash = dephash;
2708
2709 memset(&tmp_dep_data, 0, sizeof(struct route_map_dep_data));
2710 tmp_dep_data.rname = rname;
2711 dep_data = hash_lookup(dep->dep_rmap_hash, &tmp_dep_data);
2712 if (!dep_data)
2713 dep_data = hash_get(dep->dep_rmap_hash, &tmp_dep_data,
2714 route_map_name_hash_alloc);
2715
2716 dep_data->refcnt++;
2717 break;
2718 case RMAP_EVENT_PLIST_DELETED:
2719 case RMAP_EVENT_CLIST_DELETED:
2720 case RMAP_EVENT_ECLIST_DELETED:
2721 case RMAP_EVENT_ASLIST_DELETED:
2722 case RMAP_EVENT_LLIST_DELETED:
2723 case RMAP_EVENT_CALL_DELETED:
2724 case RMAP_EVENT_FILTER_DELETED:
2725 if (rmap_debug)
2726 zlog_debug("Deleting dependency for filter %s in route-map %s",
2727 dep_name, rmap_name);
2728 dep = (struct route_map_dep *)hash_get(dephash, dname, NULL);
2729 if (!dep) {
2730 goto out;
2731 }
2732
2733 memset(&tmp_dep_data, 0, sizeof(struct route_map_dep_data));
2734 tmp_dep_data.rname = rname;
2735 dep_data = hash_lookup(dep->dep_rmap_hash, &tmp_dep_data);
2736 /*
2737 * If dep_data is NULL then something has gone seriously
2738 * wrong in route-map handling. Note it and prevent
2739 * the crash.
2740 */
2741 if (!dep_data) {
2742 zlog_warn(
2743 "route-map dependency for route-map %s: %s is not correct",
2744 rmap_name, dep_name);
2745 goto out;
2746 }
2747
2748 dep_data->refcnt--;
2749
2750 if (!dep_data->refcnt) {
2751 ret_dep_data = hash_release(dep->dep_rmap_hash,
2752 &tmp_dep_data);
2753 if (ret_dep_data) {
2754 XFREE(MTYPE_ROUTE_MAP_NAME,
2755 ret_dep_data->rname);
2756 XFREE(MTYPE_ROUTE_MAP_DEP_DATA, ret_dep_data);
2757 }
2758 }
2759
2760 if (!dep->dep_rmap_hash->count) {
2761 dep = hash_release(dephash, dname);
2762 hash_free(dep->dep_rmap_hash);
2763 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
2764 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
2765 }
2766 break;
2767 case RMAP_EVENT_SET_ADDED:
2768 case RMAP_EVENT_SET_DELETED:
2769 case RMAP_EVENT_SET_REPLACED:
2770 case RMAP_EVENT_MATCH_ADDED:
2771 case RMAP_EVENT_MATCH_DELETED:
2772 case RMAP_EVENT_MATCH_REPLACED:
2773 case RMAP_EVENT_INDEX_ADDED:
2774 case RMAP_EVENT_INDEX_DELETED:
2775 break;
2776 }
2777
2778 if (dep) {
2779 if (rmap_debug)
2780 hash_iterate(dep->dep_rmap_hash,
2781 route_map_print_dependency, dname);
2782 }
2783
2784 out:
2785 XFREE(MTYPE_ROUTE_MAP_NAME, rname);
2786 XFREE(MTYPE_ROUTE_MAP_NAME, dname);
2787 return ret;
2788 }
2789
2790 static struct hash *route_map_get_dep_hash(route_map_event_t event)
2791 {
2792 struct hash *upd8_hash = NULL;
2793
2794 switch (event) {
2795 case RMAP_EVENT_PLIST_ADDED:
2796 case RMAP_EVENT_PLIST_DELETED:
2797 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_PLIST];
2798 break;
2799 case RMAP_EVENT_CLIST_ADDED:
2800 case RMAP_EVENT_CLIST_DELETED:
2801 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_CLIST];
2802 break;
2803 case RMAP_EVENT_ECLIST_ADDED:
2804 case RMAP_EVENT_ECLIST_DELETED:
2805 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ECLIST];
2806 break;
2807 case RMAP_EVENT_ASLIST_ADDED:
2808 case RMAP_EVENT_ASLIST_DELETED:
2809 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ASPATH];
2810 break;
2811 case RMAP_EVENT_LLIST_ADDED:
2812 case RMAP_EVENT_LLIST_DELETED:
2813 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_LCLIST];
2814 break;
2815 case RMAP_EVENT_CALL_ADDED:
2816 case RMAP_EVENT_CALL_DELETED:
2817 case RMAP_EVENT_MATCH_ADDED:
2818 case RMAP_EVENT_MATCH_DELETED:
2819 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_RMAP];
2820 break;
2821 case RMAP_EVENT_FILTER_ADDED:
2822 case RMAP_EVENT_FILTER_DELETED:
2823 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_FILTER];
2824 break;
2825 /*
2826 * Should we actually be ignoring these?
2827 * I am not sure but at this point in time, let
2828 * us get them into this switch and we can peel
2829 * them into the appropriate place in the future
2830 */
2831 case RMAP_EVENT_SET_ADDED:
2832 case RMAP_EVENT_SET_DELETED:
2833 case RMAP_EVENT_SET_REPLACED:
2834 case RMAP_EVENT_MATCH_REPLACED:
2835 case RMAP_EVENT_INDEX_ADDED:
2836 case RMAP_EVENT_INDEX_DELETED:
2837 upd8_hash = NULL;
2838 break;
2839 }
2840 return (upd8_hash);
2841 }
2842
2843 static void route_map_process_dependency(struct hash_bucket *bucket, void *data)
2844 {
2845 struct route_map_dep_data *dep_data = NULL;
2846 char *rmap_name = NULL;
2847
2848 dep_data = bucket->data;
2849 rmap_name = dep_data->rname;
2850
2851 if (rmap_debug)
2852 zlog_debug("Notifying %s of dependency", rmap_name);
2853 if (route_map_master.event_hook)
2854 (*route_map_master.event_hook)(rmap_name);
2855 }
2856
2857 void route_map_upd8_dependency(route_map_event_t type, const char *arg,
2858 const char *rmap_name)
2859 {
2860 struct hash *upd8_hash = NULL;
2861
2862 if ((upd8_hash = route_map_get_dep_hash(type))) {
2863 route_map_dep_update(upd8_hash, arg, rmap_name, type);
2864
2865 if (type == RMAP_EVENT_CALL_ADDED) {
2866 /* Execute hook. */
2867 if (route_map_master.add_hook)
2868 (*route_map_master.add_hook)(rmap_name);
2869 } else if (type == RMAP_EVENT_CALL_DELETED) {
2870 /* Execute hook. */
2871 if (route_map_master.delete_hook)
2872 (*route_map_master.delete_hook)(rmap_name);
2873 }
2874 }
2875 }
2876
2877 void route_map_notify_dependencies(const char *affected_name,
2878 route_map_event_t event)
2879 {
2880 struct route_map_dep *dep;
2881 struct hash *upd8_hash;
2882 char *name;
2883
2884 if (!affected_name)
2885 return;
2886
2887 name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, affected_name);
2888
2889 if ((upd8_hash = route_map_get_dep_hash(event)) == NULL) {
2890 XFREE(MTYPE_ROUTE_MAP_NAME, name);
2891 return;
2892 }
2893
2894 dep = (struct route_map_dep *)hash_get(upd8_hash, name, NULL);
2895 if (dep) {
2896 if (!dep->this_hash)
2897 dep->this_hash = upd8_hash;
2898
2899 if (rmap_debug)
2900 zlog_debug("Filter %s updated", dep->dep_name);
2901 hash_iterate(dep->dep_rmap_hash, route_map_process_dependency,
2902 (void *)event);
2903 }
2904
2905 XFREE(MTYPE_ROUTE_MAP_NAME, name);
2906 }
2907
2908 /* VTY related functions. */
2909 static void clear_route_map_helper(struct route_map *map)
2910 {
2911 struct route_map_index *index;
2912
2913 map->applied_clear = map->applied;
2914 for (index = map->head; index; index = index->next)
2915 index->applied_clear = index->applied;
2916 }
2917
2918 DEFUN (rmap_clear_counters,
2919 rmap_clear_counters_cmd,
2920 "clear route-map counters [WORD]",
2921 CLEAR_STR
2922 "route-map information\n"
2923 "counters associated with the specified route-map\n"
2924 "route-map name\n")
2925 {
2926 int idx_word = 2;
2927 struct route_map *map;
2928
2929 const char *name = (argc == 3 ) ? argv[idx_word]->arg : NULL;
2930
2931 if (name) {
2932 map = route_map_lookup_by_name(name);
2933
2934 if (map)
2935 clear_route_map_helper(map);
2936 else {
2937 vty_out(vty, "%s: 'route-map %s' not found\n",
2938 frr_protonameinst, name);
2939 return CMD_SUCCESS;
2940 }
2941 } else {
2942 for (map = route_map_master.head; map; map = map->next)
2943 clear_route_map_helper(map);
2944 }
2945
2946 return CMD_SUCCESS;
2947
2948 }
2949
2950 DEFUN (rmap_show_name,
2951 rmap_show_name_cmd,
2952 "show route-map [WORD]",
2953 SHOW_STR
2954 "route-map information\n"
2955 "route-map name\n")
2956 {
2957 int idx_word = 2;
2958 const char *name = (argc == 3) ? argv[idx_word]->arg : NULL;
2959 return vty_show_route_map(vty, name);
2960 }
2961
2962 DEFUN (rmap_show_unused,
2963 rmap_show_unused_cmd,
2964 "show route-map-unused",
2965 SHOW_STR
2966 "unused route-map information\n")
2967 {
2968 return vty_show_unused_route_map(vty);
2969 }
2970
2971 DEFUN (debug_rmap,
2972 debug_rmap_cmd,
2973 "debug route-map",
2974 DEBUG_STR
2975 "Debug option set for route-maps\n")
2976 {
2977 rmap_debug = true;
2978 return CMD_SUCCESS;
2979 }
2980
2981 DEFUN (no_debug_rmap,
2982 no_debug_rmap_cmd,
2983 "no debug route-map",
2984 NO_STR
2985 DEBUG_STR
2986 "Debug option set for route-maps\n")
2987 {
2988 rmap_debug = false;
2989 return CMD_SUCCESS;
2990 }
2991
2992 /* Debug node. */
2993 static int rmap_config_write_debug(struct vty *vty);
2994 static struct cmd_node rmap_debug_node = {
2995 .name = "route-map debug",
2996 .node = RMAP_DEBUG_NODE,
2997 .prompt = "",
2998 .config_write = rmap_config_write_debug,
2999 };
3000
3001 /* Configuration write function. */
3002 static int rmap_config_write_debug(struct vty *vty)
3003 {
3004 int write = 0;
3005
3006 if (rmap_debug) {
3007 vty_out(vty, "debug route-map\n");
3008 write++;
3009 }
3010
3011 return write;
3012 }
3013
3014 /* Common route map rules */
3015
3016 void *route_map_rule_tag_compile(const char *arg)
3017 {
3018 unsigned long int tmp;
3019 char *endptr;
3020 route_tag_t *tag;
3021
3022 errno = 0;
3023 tmp = strtoul(arg, &endptr, 0);
3024 if (arg[0] == '\0' || *endptr != '\0' || errno || tmp > ROUTE_TAG_MAX)
3025 return NULL;
3026
3027 tag = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*tag));
3028 *tag = tmp;
3029
3030 return tag;
3031 }
3032
3033 void route_map_rule_tag_free(void *rule)
3034 {
3035 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
3036 }
3037
3038 void route_map_finish(void)
3039 {
3040 int i;
3041
3042 vector_free(route_match_vec);
3043 route_match_vec = NULL;
3044 vector_free(route_set_vec);
3045 route_set_vec = NULL;
3046
3047 /*
3048 * All protocols are setting these to NULL
3049 * by default on shutdown( route_map_finish )
3050 * Why are we making them do this work?
3051 */
3052 route_map_master.add_hook = NULL;
3053 route_map_master.delete_hook = NULL;
3054 route_map_master.event_hook = NULL;
3055
3056 /* cleanup route_map */
3057 while (route_map_master.head) {
3058 struct route_map *map = route_map_master.head;
3059 map->to_be_processed = false;
3060 route_map_delete(map);
3061 }
3062
3063 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
3064 hash_free(route_map_dep_hash[i]);
3065 route_map_dep_hash[i] = NULL;
3066 }
3067
3068 hash_free(route_map_master_hash);
3069 route_map_master_hash = NULL;
3070 }
3071
3072 /* Increment the use_count counter while attaching the route map */
3073 void route_map_counter_increment(struct route_map *map)
3074 {
3075 if (map)
3076 map->use_count++;
3077 }
3078
3079 /* Decrement the use_count counter while detaching the route map. */
3080 void route_map_counter_decrement(struct route_map *map)
3081 {
3082 if (map) {
3083 if (map->use_count <= 0)
3084 return;
3085 map->use_count--;
3086 }
3087 }
3088
3089 DEFUN_HIDDEN(show_route_map_pfx_tbl, show_route_map_pfx_tbl_cmd,
3090 "show route-map WORD prefix-table",
3091 SHOW_STR
3092 "route-map\n"
3093 "route-map name\n"
3094 "internal prefix-table\n")
3095 {
3096 const char *rmap_name = argv[2]->arg;
3097 struct route_map *rmap = NULL;
3098 struct route_table *rm_pfx_tbl4 = NULL;
3099 struct route_table *rm_pfx_tbl6 = NULL;
3100 struct route_node *rn = NULL, *prn = NULL;
3101 struct list *rmap_index_list = NULL;
3102 struct listnode *ln = NULL, *nln = NULL;
3103 struct route_map_index *index = NULL;
3104 uint8_t len = 54;
3105
3106 vty_out(vty, "%s:\n", frr_protonameinst);
3107 rmap = route_map_lookup_by_name(rmap_name);
3108 if (rmap) {
3109 rm_pfx_tbl4 = rmap->ipv4_prefix_table;
3110 if (rm_pfx_tbl4) {
3111 vty_out(vty, "\n%s%43s%s\n", "IPv4 Prefix", "",
3112 "Route-map Index List");
3113 vty_out(vty, "%s%39s%s\n", "_______________", "",
3114 "____________________");
3115 for (rn = route_top(rm_pfx_tbl4); rn;
3116 rn = route_next(rn)) {
3117 vty_out(vty, " %pRN (%d)\n", rn,
3118 route_node_get_lock_count(rn));
3119
3120 vty_out(vty, "(P) ");
3121 prn = rn->parent;
3122 if (prn) {
3123 vty_out(vty, "%pRN\n", prn);
3124 }
3125
3126 vty_out(vty, "\n");
3127 rmap_index_list = (struct list *)rn->info;
3128 if (!rmap_index_list
3129 || !listcount(rmap_index_list))
3130 vty_out(vty, "%*s%s\n", len, "", "-");
3131 else
3132 for (ALL_LIST_ELEMENTS(rmap_index_list,
3133 ln, nln,
3134 index)) {
3135 vty_out(vty, "%*s%s seq %d\n",
3136 len, "",
3137 index->map->name,
3138 index->pref);
3139 }
3140 vty_out(vty, "\n");
3141 }
3142 }
3143
3144 rm_pfx_tbl6 = rmap->ipv6_prefix_table;
3145 if (rm_pfx_tbl6) {
3146 vty_out(vty, "\n%s%43s%s\n", "IPv6 Prefix", "",
3147 "Route-map Index List");
3148 vty_out(vty, "%s%39s%s\n", "_______________", "",
3149 "____________________");
3150 for (rn = route_top(rm_pfx_tbl6); rn;
3151 rn = route_next(rn)) {
3152 vty_out(vty, " %pRN (%d)\n", rn,
3153 route_node_get_lock_count(rn));
3154
3155 vty_out(vty, "(P) ");
3156 prn = rn->parent;
3157 if (prn) {
3158 vty_out(vty, "%pRN\n", prn);
3159 }
3160
3161 vty_out(vty, "\n");
3162 rmap_index_list = (struct list *)rn->info;
3163 if (!rmap_index_list
3164 || !listcount(rmap_index_list))
3165 vty_out(vty, "%*s%s\n", len, "", "-");
3166 else
3167 for (ALL_LIST_ELEMENTS(rmap_index_list,
3168 ln, nln,
3169 index)) {
3170 vty_out(vty, "%*s%s seq %d\n",
3171 len, "",
3172 index->map->name,
3173 index->pref);
3174 }
3175 vty_out(vty, "\n");
3176 }
3177 }
3178 }
3179
3180 vty_out(vty, "\n");
3181 return CMD_SUCCESS;
3182 }
3183
3184 /* Initialization of route map vector. */
3185 void route_map_init(void)
3186 {
3187 int i;
3188
3189 /* Make vector for match and set. */
3190 route_match_vec = vector_init(1);
3191 route_set_vec = vector_init(1);
3192 route_map_master_hash =
3193 hash_create_size(8, route_map_hash_key_make, route_map_hash_cmp,
3194 "Route Map Master Hash");
3195
3196 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
3197 route_map_dep_hash[i] = hash_create_size(
3198 8, route_map_dep_hash_make_key, route_map_dep_hash_cmp,
3199 "Route Map Dep Hash");
3200
3201 rmap_debug = false;
3202
3203 route_map_cli_init();
3204
3205 /* Install route map top node. */
3206 install_node(&rmap_debug_node);
3207
3208 /* Install route map commands. */
3209 install_element(CONFIG_NODE, &debug_rmap_cmd);
3210 install_element(CONFIG_NODE, &no_debug_rmap_cmd);
3211
3212 /* Install show command */
3213 install_element(ENABLE_NODE, &rmap_clear_counters_cmd);
3214
3215 install_element(ENABLE_NODE, &rmap_show_name_cmd);
3216 install_element(ENABLE_NODE, &rmap_show_unused_cmd);
3217
3218 install_element(ENABLE_NODE, &debug_rmap_cmd);
3219 install_element(ENABLE_NODE, &no_debug_rmap_cmd);
3220
3221 install_element(ENABLE_NODE, &show_route_map_pfx_tbl_cmd);
3222 }