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