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