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