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