]> git.proxmox.com Git - mirror_frr.git/blob - lib/routemap.c
Merge pull request #11469 from donaldsharp/fdev2
[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 int route_map_clear_updated(struct route_map *map)
816 {
817 int ret = -1;
818
819 if (map) {
820 map->to_be_processed = false;
821 if (map->deleted)
822 route_map_free_map(map);
823 }
824
825 return (ret);
826 }
827
828 /* Lookup route map. If there isn't route map create one and return
829 it. */
830 struct route_map *route_map_get(const char *name)
831 {
832 struct route_map *map;
833
834 map = route_map_lookup_by_name(name);
835 if (map == NULL)
836 map = route_map_add(name);
837
838 return map;
839 }
840
841 void route_map_walk_update_list(void (*route_map_update_fn)(char *name))
842 {
843 struct route_map *node;
844 struct route_map *nnode = NULL;
845
846 for (node = route_map_master.head; node; node = nnode) {
847 if (node->to_be_processed) {
848 /* DD: Should we add any thread yield code here */
849 route_map_update_fn(node->name);
850 nnode = node->next;
851 route_map_clear_updated(node);
852 } else
853 nnode = node->next;
854 }
855 }
856
857 /* Return route map's type string. */
858 static const char *route_map_type_str(enum route_map_type type)
859 {
860 switch (type) {
861 case RMAP_PERMIT:
862 return "permit";
863 case RMAP_DENY:
864 return "deny";
865 case RMAP_ANY:
866 return "";
867 }
868
869 return "";
870 }
871
872 static const char *route_map_cmd_result_str(enum route_map_cmd_result_t res)
873 {
874 switch (res) {
875 case RMAP_MATCH:
876 return "match";
877 case RMAP_NOMATCH:
878 return "no match";
879 case RMAP_NOOP:
880 return "noop";
881 case RMAP_ERROR:
882 return "error";
883 case RMAP_OKAY:
884 return "okay";
885 }
886
887 return "invalid";
888 }
889
890 static const char *route_map_result_str(route_map_result_t res)
891 {
892 switch (res) {
893 case RMAP_DENYMATCH:
894 return "deny";
895 case RMAP_PERMITMATCH:
896 return "permit";
897 }
898
899 return "invalid";
900 }
901
902 /* show route-map */
903 static void vty_show_route_map_entry(struct vty *vty, struct route_map *map,
904 json_object *json)
905 {
906 struct route_map_index *index;
907 struct route_map_rule *rule;
908 json_object *json_rmap = NULL;
909 json_object *json_rules = NULL;
910
911 if (json) {
912 json_rmap = json_object_new_object();
913 json_object_object_add(json, map->name, json_rmap);
914
915 json_rules = json_object_new_array();
916 json_object_int_add(json_rmap, "invoked",
917 map->applied - map->applied_clear);
918 json_object_boolean_add(json_rmap, "disabledOptimization",
919 map->optimization_disabled);
920 json_object_boolean_add(json_rmap, "processedChange",
921 map->to_be_processed);
922 json_object_object_add(json_rmap, "rules", json_rules);
923 } else {
924 vty_out(vty,
925 "route-map: %s Invoked: %" PRIu64
926 " Optimization: %s Processed Change: %s\n",
927 map->name, map->applied - map->applied_clear,
928 map->optimization_disabled ? "disabled" : "enabled",
929 map->to_be_processed ? "true" : "false");
930 }
931
932 for (index = map->head; index; index = index->next) {
933 if (json) {
934 json_object *json_rule;
935 json_object *json_matches;
936 json_object *json_sets;
937 char action[BUFSIZ] = {};
938
939 json_rule = json_object_new_object();
940 json_object_array_add(json_rules, json_rule);
941
942 json_object_int_add(json_rule, "sequenceNumber",
943 index->pref);
944 json_object_string_add(json_rule, "type",
945 route_map_type_str(index->type));
946 json_object_int_add(json_rule, "invoked",
947 index->applied
948 - index->applied_clear);
949
950 /* Description */
951 if (index->description)
952 json_object_string_add(json_rule, "description",
953 index->description);
954
955 /* Match clauses */
956 json_matches = json_object_new_array();
957 json_object_object_add(json_rule, "matchClauses",
958 json_matches);
959 for (rule = index->match_list.head; rule;
960 rule = rule->next) {
961 char buf[BUFSIZ];
962
963 snprintf(buf, sizeof(buf), "%s %s",
964 rule->cmd->str, rule->rule_str);
965 json_array_string_add(json_matches, buf);
966 }
967
968 /* Set clauses */
969 json_sets = json_object_new_array();
970 json_object_object_add(json_rule, "setClauses",
971 json_sets);
972 for (rule = index->set_list.head; rule;
973 rule = rule->next) {
974 char buf[BUFSIZ];
975
976 snprintf(buf, sizeof(buf), "%s %s",
977 rule->cmd->str, rule->rule_str);
978 json_array_string_add(json_sets, buf);
979 }
980
981 /* Call clause */
982 if (index->nextrm)
983 json_object_string_add(json_rule, "callClause",
984 index->nextrm);
985
986 /* Exit Policy */
987 if (index->exitpolicy == RMAP_GOTO)
988 snprintf(action, sizeof(action), "Goto %d",
989 index->nextpref);
990 else if (index->exitpolicy == RMAP_NEXT)
991 snprintf(action, sizeof(action),
992 "Continue to next entry");
993 else if (index->exitpolicy == RMAP_EXIT)
994 snprintf(action, sizeof(action),
995 "Exit routemap");
996 if (action[0] != '\0')
997 json_object_string_add(json_rule, "action",
998 action);
999 } else {
1000 vty_out(vty, " %s, sequence %d Invoked %" PRIu64 "\n",
1001 route_map_type_str(index->type), index->pref,
1002 index->applied - index->applied_clear);
1003
1004 /* Description */
1005 if (index->description)
1006 vty_out(vty, " Description:\n %s\n",
1007 index->description);
1008
1009 /* Match clauses */
1010 vty_out(vty, " Match clauses:\n");
1011 for (rule = index->match_list.head; rule;
1012 rule = rule->next)
1013 vty_out(vty, " %s %s\n", rule->cmd->str,
1014 rule->rule_str);
1015
1016 /* Set clauses */
1017 vty_out(vty, " Set clauses:\n");
1018 for (rule = index->set_list.head; rule;
1019 rule = rule->next)
1020 vty_out(vty, " %s %s\n", rule->cmd->str,
1021 rule->rule_str);
1022
1023 /* Call clause */
1024 vty_out(vty, " Call clause:\n");
1025 if (index->nextrm)
1026 vty_out(vty, " Call %s\n", index->nextrm);
1027
1028 /* Exit Policy */
1029 vty_out(vty, " Action:\n");
1030 if (index->exitpolicy == RMAP_GOTO)
1031 vty_out(vty, " Goto %d\n", index->nextpref);
1032 else if (index->exitpolicy == RMAP_NEXT)
1033 vty_out(vty, " Continue to next entry\n");
1034 else if (index->exitpolicy == RMAP_EXIT)
1035 vty_out(vty, " Exit routemap\n");
1036 }
1037 }
1038 }
1039
1040 static int sort_route_map(const void **map1, const void **map2)
1041 {
1042 const struct route_map *m1 = *map1;
1043 const struct route_map *m2 = *map2;
1044
1045 return strcmp(m1->name, m2->name);
1046 }
1047
1048 static int vty_show_route_map(struct vty *vty, const char *name, bool use_json)
1049 {
1050 struct route_map *map;
1051 json_object *json = NULL;
1052 json_object *json_proto = NULL;
1053
1054 if (use_json) {
1055 json = json_object_new_object();
1056 json_proto = json_object_new_object();
1057 json_object_object_add(json, frr_protonameinst, json_proto);
1058 } else
1059 vty_out(vty, "%s:\n", frr_protonameinst);
1060
1061 if (name) {
1062 map = route_map_lookup_by_name(name);
1063
1064 if (map) {
1065 vty_show_route_map_entry(vty, map, json_proto);
1066 return CMD_SUCCESS;
1067 } else if (!use_json) {
1068 vty_out(vty, "%s: 'route-map %s' not found\n",
1069 frr_protonameinst, name);
1070 }
1071 } else {
1072
1073 struct list *maplist = list_new();
1074 struct listnode *ln;
1075
1076 for (map = route_map_master.head; map; map = map->next)
1077 listnode_add(maplist, map);
1078
1079 list_sort(maplist, sort_route_map);
1080
1081 for (ALL_LIST_ELEMENTS_RO(maplist, ln, map))
1082 vty_show_route_map_entry(vty, map, json_proto);
1083
1084 list_delete(&maplist);
1085 }
1086
1087 return vty_json(vty, json);
1088 }
1089
1090 /* Unused route map details */
1091 static int vty_show_unused_route_map(struct vty *vty)
1092 {
1093 struct list *maplist = list_new();
1094 struct listnode *ln;
1095 struct route_map *map;
1096
1097 for (map = route_map_master.head; map; map = map->next) {
1098 /* If use_count is zero, No protocol is using this routemap.
1099 * so adding to the list.
1100 */
1101 if (!map->use_count)
1102 listnode_add(maplist, map);
1103 }
1104
1105 if (maplist->count > 0) {
1106 vty_out(vty, "\n%s:\n", frr_protonameinst);
1107 list_sort(maplist, sort_route_map);
1108
1109 for (ALL_LIST_ELEMENTS_RO(maplist, ln, map))
1110 vty_show_route_map_entry(vty, map, NULL);
1111 } else {
1112 vty_out(vty, "\n%s: None\n", frr_protonameinst);
1113 }
1114
1115 list_delete(&maplist);
1116 return CMD_SUCCESS;
1117 }
1118
1119 /* New route map allocation. Please note route map's name must be
1120 specified. */
1121 static struct route_map_index *route_map_index_new(void)
1122 {
1123 struct route_map_index *new;
1124
1125 new = XCALLOC(MTYPE_ROUTE_MAP_INDEX, sizeof(struct route_map_index));
1126 new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */
1127 TAILQ_INIT(&new->rhclist);
1128 QOBJ_REG(new, route_map_index);
1129 return new;
1130 }
1131
1132 /* Free route map index. */
1133 void route_map_index_delete(struct route_map_index *index, int notify)
1134 {
1135 struct routemap_hook_context *rhc;
1136 struct route_map_rule *rule;
1137
1138 QOBJ_UNREG(index);
1139
1140 if (rmap_debug)
1141 zlog_debug("Deleting route-map %s sequence %d",
1142 index->map->name, index->pref);
1143
1144 /* Free route map entry description. */
1145 XFREE(MTYPE_TMP, index->description);
1146
1147 /* Free route map northbound hook contexts. */
1148 while ((rhc = TAILQ_FIRST(&index->rhclist)) != NULL)
1149 routemap_hook_context_free(rhc);
1150
1151 /* Free route match. */
1152 while ((rule = index->match_list.head) != NULL) {
1153 if (IS_RULE_IPv4_PREFIX_LIST(rule->cmd->str))
1154 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_DELETED,
1155 index, AFI_IP, rule->rule_str);
1156 else if (IS_RULE_IPv6_PREFIX_LIST(rule->cmd->str))
1157 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_DELETED,
1158 index, AFI_IP6,
1159 rule->rule_str);
1160
1161 route_map_rule_delete(&index->match_list, rule);
1162 }
1163
1164 /* Free route set. */
1165 while ((rule = index->set_list.head) != NULL)
1166 route_map_rule_delete(&index->set_list, rule);
1167
1168 /* Remove index from route map list. */
1169 if (index->next)
1170 index->next->prev = index->prev;
1171 else
1172 index->map->tail = index->prev;
1173
1174 if (index->prev)
1175 index->prev->next = index->next;
1176 else
1177 index->map->head = index->next;
1178
1179 /* Free 'char *nextrm' if not NULL */
1180 XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
1181
1182 route_map_pfx_tbl_update(RMAP_EVENT_INDEX_DELETED, index, 0, NULL);
1183
1184 /* Execute event hook. */
1185 if (route_map_master.event_hook && notify) {
1186 (*route_map_master.event_hook)(index->map->name);
1187 route_map_notify_dependencies(index->map->name,
1188 RMAP_EVENT_CALL_ADDED);
1189 }
1190 XFREE(MTYPE_ROUTE_MAP_INDEX, index);
1191 }
1192
1193 /* Lookup index from route map. */
1194 static struct route_map_index *route_map_index_lookup(struct route_map *map,
1195 enum route_map_type type,
1196 int pref)
1197 {
1198 struct route_map_index *index;
1199
1200 for (index = map->head; index; index = index->next)
1201 if ((index->type == type || type == RMAP_ANY)
1202 && index->pref == pref)
1203 return index;
1204 return NULL;
1205 }
1206
1207 /* Add new index to route map. */
1208 static struct route_map_index *
1209 route_map_index_add(struct route_map *map, enum route_map_type type, int pref)
1210 {
1211 struct route_map_index *index;
1212 struct route_map_index *point;
1213
1214 /* Allocate new route map inex. */
1215 index = route_map_index_new();
1216 index->map = map;
1217 index->type = type;
1218 index->pref = pref;
1219
1220 /* Compare preference. */
1221 for (point = map->head; point; point = point->next)
1222 if (point->pref >= pref)
1223 break;
1224
1225 if (map->head == NULL) {
1226 map->head = map->tail = index;
1227 } else if (point == NULL) {
1228 index->prev = map->tail;
1229 map->tail->next = index;
1230 map->tail = index;
1231 } else if (point == map->head) {
1232 index->next = map->head;
1233 map->head->prev = index;
1234 map->head = index;
1235 } else {
1236 index->next = point;
1237 index->prev = point->prev;
1238 if (point->prev)
1239 point->prev->next = index;
1240 point->prev = index;
1241 }
1242
1243 route_map_pfx_tbl_update(RMAP_EVENT_INDEX_ADDED, index, 0, NULL);
1244
1245 /* Execute event hook. */
1246 if (route_map_master.event_hook) {
1247 (*route_map_master.event_hook)(map->name);
1248 route_map_notify_dependencies(map->name, RMAP_EVENT_CALL_ADDED);
1249 }
1250
1251 if (rmap_debug)
1252 zlog_debug("Route-map %s add sequence %d, type: %s",
1253 map->name, pref, route_map_type_str(type));
1254
1255 return index;
1256 }
1257
1258 /* Get route map index. */
1259 struct route_map_index *
1260 route_map_index_get(struct route_map *map, enum route_map_type type, int pref)
1261 {
1262 struct route_map_index *index;
1263
1264 index = route_map_index_lookup(map, RMAP_ANY, pref);
1265 if (index && index->type != type) {
1266 /* Delete index from route map. */
1267 route_map_index_delete(index, 1);
1268 index = NULL;
1269 }
1270 if (index == NULL)
1271 index = route_map_index_add(map, type, pref);
1272 return index;
1273 }
1274
1275 /* New route map rule */
1276 static struct route_map_rule *route_map_rule_new(void)
1277 {
1278 struct route_map_rule *new;
1279
1280 new = XCALLOC(MTYPE_ROUTE_MAP_RULE, sizeof(struct route_map_rule));
1281 return new;
1282 }
1283
1284 /* Install rule command to the match list. */
1285 void _route_map_install_match(struct route_map_rule_cmd_proxy *proxy)
1286 {
1287 rmap_cmd_name_add(rmap_match_cmds, proxy);
1288 }
1289
1290 /* Install rule command to the set list. */
1291 void _route_map_install_set(struct route_map_rule_cmd_proxy *proxy)
1292 {
1293 rmap_cmd_name_add(rmap_set_cmds, proxy);
1294 }
1295
1296 /* Lookup rule command from match list. */
1297 static const struct route_map_rule_cmd *route_map_lookup_match(const char *name)
1298 {
1299 struct route_map_rule_cmd refcmd = {.str = name};
1300 struct route_map_rule_cmd_proxy ref = {.cmd = &refcmd};
1301 struct route_map_rule_cmd_proxy *res;
1302
1303 res = rmap_cmd_name_find(rmap_match_cmds, &ref);
1304 if (res)
1305 return res->cmd;
1306 return NULL;
1307 }
1308
1309 /* Lookup rule command from set list. */
1310 static const struct route_map_rule_cmd *route_map_lookup_set(const char *name)
1311 {
1312 struct route_map_rule_cmd refcmd = {.str = name};
1313 struct route_map_rule_cmd_proxy ref = {.cmd = &refcmd};
1314 struct route_map_rule_cmd_proxy *res;
1315
1316 res = rmap_cmd_name_find(rmap_set_cmds, &ref);
1317 if (res)
1318 return res->cmd;
1319 return NULL;
1320 }
1321
1322 /* Add match and set rule to rule list. */
1323 static void route_map_rule_add(struct route_map_rule_list *list,
1324 struct route_map_rule *rule)
1325 {
1326 rule->next = NULL;
1327 rule->prev = list->tail;
1328 if (list->tail)
1329 list->tail->next = rule;
1330 else
1331 list->head = rule;
1332 list->tail = rule;
1333 }
1334
1335 /* Delete rule from rule list. */
1336 static void route_map_rule_delete(struct route_map_rule_list *list,
1337 struct route_map_rule *rule)
1338 {
1339 if (rule->cmd->func_free)
1340 (*rule->cmd->func_free)(rule->value);
1341
1342 XFREE(MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str);
1343
1344 if (rule->next)
1345 rule->next->prev = rule->prev;
1346 else
1347 list->tail = rule->prev;
1348 if (rule->prev)
1349 rule->prev->next = rule->next;
1350 else
1351 list->head = rule->next;
1352
1353 XFREE(MTYPE_ROUTE_MAP_RULE, rule);
1354 }
1355
1356 /* strcmp wrapper function which don't crush even argument is NULL. */
1357 static int rulecmp(const char *dst, const char *src)
1358 {
1359 if (dst == NULL) {
1360 if (src == NULL)
1361 return 0;
1362 else
1363 return 1;
1364 } else {
1365 if (src == NULL)
1366 return 1;
1367 else
1368 return strcmp(dst, src);
1369 }
1370 return 1;
1371 }
1372
1373 /* Use this to return the already specified argument for this match. This is
1374 * useful to get the specified argument with a route map match rule when the
1375 * rule is being deleted and the argument is not provided.
1376 */
1377 const char *route_map_get_match_arg(struct route_map_index *index,
1378 const char *match_name)
1379 {
1380 struct route_map_rule *rule;
1381 const struct route_map_rule_cmd *cmd;
1382
1383 /* First lookup rule for add match statement. */
1384 cmd = route_map_lookup_match(match_name);
1385 if (cmd == NULL)
1386 return NULL;
1387
1388 for (rule = index->match_list.head; rule; rule = rule->next)
1389 if (rule->cmd == cmd && rule->rule_str != NULL)
1390 return (rule->rule_str);
1391
1392 return NULL;
1393 }
1394
1395 static route_map_event_t get_route_map_delete_event(route_map_event_t type)
1396 {
1397 switch (type) {
1398 case RMAP_EVENT_CALL_ADDED:
1399 return RMAP_EVENT_CALL_DELETED;
1400 case RMAP_EVENT_PLIST_ADDED:
1401 return RMAP_EVENT_PLIST_DELETED;
1402 case RMAP_EVENT_CLIST_ADDED:
1403 return RMAP_EVENT_CLIST_DELETED;
1404 case RMAP_EVENT_ECLIST_ADDED:
1405 return RMAP_EVENT_ECLIST_DELETED;
1406 case RMAP_EVENT_LLIST_ADDED:
1407 return RMAP_EVENT_LLIST_DELETED;
1408 case RMAP_EVENT_ASLIST_ADDED:
1409 return RMAP_EVENT_ASLIST_DELETED;
1410 case RMAP_EVENT_FILTER_ADDED:
1411 return RMAP_EVENT_FILTER_DELETED;
1412 case RMAP_EVENT_SET_ADDED:
1413 case RMAP_EVENT_SET_DELETED:
1414 case RMAP_EVENT_SET_REPLACED:
1415 case RMAP_EVENT_MATCH_ADDED:
1416 case RMAP_EVENT_MATCH_DELETED:
1417 case RMAP_EVENT_MATCH_REPLACED:
1418 case RMAP_EVENT_INDEX_ADDED:
1419 case RMAP_EVENT_INDEX_DELETED:
1420 case RMAP_EVENT_CALL_DELETED:
1421 case RMAP_EVENT_PLIST_DELETED:
1422 case RMAP_EVENT_CLIST_DELETED:
1423 case RMAP_EVENT_ECLIST_DELETED:
1424 case RMAP_EVENT_LLIST_DELETED:
1425 case RMAP_EVENT_ASLIST_DELETED:
1426 case RMAP_EVENT_FILTER_DELETED:
1427 /* This function returns the appropriate 'deleted' event type
1428 * for every 'added' event type passed to this function.
1429 * This is done only for named entities used in the
1430 * route-map match commands.
1431 * This function is not to be invoked for any of the other event
1432 * types.
1433 */
1434 assert(0);
1435 }
1436
1437 assert(0);
1438 /*
1439 * Return to make c happy but if we get here something has gone
1440 * terribly terribly wrong, so yes this return makes no sense.
1441 */
1442 return RMAP_EVENT_CALL_ADDED;
1443 }
1444
1445 /* Add match statement to route map. */
1446 enum rmap_compile_rets route_map_add_match(struct route_map_index *index,
1447 const char *match_name,
1448 const char *match_arg,
1449 route_map_event_t type)
1450 {
1451 struct route_map_rule *rule;
1452 struct route_map_rule *next;
1453 const struct route_map_rule_cmd *cmd;
1454 void *compile;
1455 int8_t delete_rmap_event_type = 0;
1456 const char *rule_key;
1457
1458 /* First lookup rule for add match statement. */
1459 cmd = route_map_lookup_match(match_name);
1460 if (cmd == NULL)
1461 return RMAP_RULE_MISSING;
1462
1463 /* Next call compile function for this match statement. */
1464 if (cmd->func_compile) {
1465 compile = (*cmd->func_compile)(match_arg);
1466 if (compile == NULL)
1467 return RMAP_COMPILE_ERROR;
1468 } else
1469 compile = NULL;
1470 /* use the compiled results if applicable */
1471 if (compile && cmd->func_get_rmap_rule_key)
1472 rule_key = (*cmd->func_get_rmap_rule_key)
1473 (compile);
1474 else
1475 rule_key = match_arg;
1476
1477 /* If argument is completely same ignore it. */
1478 for (rule = index->match_list.head; rule; rule = next) {
1479 next = rule->next;
1480 if (rule->cmd == cmd) {
1481 /* If the configured route-map match rule is exactly
1482 * the same as the existing configuration then,
1483 * ignore the duplicate configuration.
1484 */
1485 if (rulecmp(match_arg, rule->rule_str) == 0) {
1486 if (cmd->func_free)
1487 (*cmd->func_free)(compile);
1488
1489 return RMAP_COMPILE_SUCCESS;
1490 }
1491
1492 /* If IPv4 or IPv6 prefix-list match criteria
1493 * has been delete to the route-map index, update
1494 * the route-map's prefix table.
1495 */
1496 if (IS_RULE_IPv4_PREFIX_LIST(match_name))
1497 route_map_pfx_tbl_update(
1498 RMAP_EVENT_PLIST_DELETED, index, AFI_IP,
1499 rule->rule_str);
1500 else if (IS_RULE_IPv6_PREFIX_LIST(match_name))
1501 route_map_pfx_tbl_update(
1502 RMAP_EVENT_PLIST_DELETED, index,
1503 AFI_IP6, rule->rule_str);
1504
1505 /* Remove the dependency of the route-map on the rule
1506 * that is being replaced.
1507 */
1508 if (type >= RMAP_EVENT_CALL_ADDED) {
1509 delete_rmap_event_type =
1510 get_route_map_delete_event(type);
1511 route_map_upd8_dependency(
1512 delete_rmap_event_type,
1513 rule->rule_str,
1514 index->map->name);
1515 }
1516
1517 route_map_rule_delete(&index->match_list, rule);
1518 }
1519 }
1520
1521 /* Add new route map match rule. */
1522 rule = route_map_rule_new();
1523 rule->cmd = cmd;
1524 rule->value = compile;
1525 if (match_arg)
1526 rule->rule_str = XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR, match_arg);
1527 else
1528 rule->rule_str = NULL;
1529
1530 /* Add new route match rule to linked list. */
1531 route_map_rule_add(&index->match_list, rule);
1532
1533 /* If IPv4 or IPv6 prefix-list match criteria
1534 * has been added to the route-map index, update
1535 * the route-map's prefix table.
1536 */
1537 if (IS_RULE_IPv4_PREFIX_LIST(match_name)) {
1538 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_ADDED, index, AFI_IP,
1539 match_arg);
1540 } else if (IS_RULE_IPv6_PREFIX_LIST(match_name)) {
1541 route_map_pfx_tbl_update(RMAP_EVENT_PLIST_ADDED, index, AFI_IP6,
1542 match_arg);
1543 }
1544
1545 /* Execute event hook. */
1546 if (route_map_master.event_hook) {
1547 (*route_map_master.event_hook)(index->map->name);
1548 route_map_notify_dependencies(index->map->name,
1549 RMAP_EVENT_CALL_ADDED);
1550 }
1551 if (type != RMAP_EVENT_MATCH_ADDED)
1552 route_map_upd8_dependency(type, rule_key, index->map->name);
1553
1554 return RMAP_COMPILE_SUCCESS;
1555 }
1556
1557 /* Delete specified route match rule. */
1558 enum rmap_compile_rets route_map_delete_match(struct route_map_index *index,
1559 const char *match_name,
1560 const char *match_arg,
1561 route_map_event_t type)
1562 {
1563 struct route_map_rule *rule;
1564 const struct route_map_rule_cmd *cmd;
1565 const char *rule_key;
1566
1567 cmd = route_map_lookup_match(match_name);
1568 if (cmd == NULL)
1569 return RMAP_RULE_MISSING;
1570
1571 for (rule = index->match_list.head; rule; rule = rule->next)
1572 if (rule->cmd == cmd && (rulecmp(rule->rule_str, match_arg) == 0
1573 || match_arg == NULL)) {
1574 /* Execute event hook. */
1575 if (route_map_master.event_hook) {
1576 (*route_map_master.event_hook)(index->map->name);
1577 route_map_notify_dependencies(
1578 index->map->name,
1579 RMAP_EVENT_CALL_ADDED);
1580 }
1581 if (cmd->func_get_rmap_rule_key)
1582 rule_key = (*cmd->func_get_rmap_rule_key)
1583 (rule->value);
1584 else
1585 rule_key = match_arg;
1586
1587 if (type != RMAP_EVENT_MATCH_DELETED && rule_key)
1588 route_map_upd8_dependency(type, rule_key,
1589 index->map->name);
1590
1591 route_map_rule_delete(&index->match_list, rule);
1592
1593 /* If IPv4 or IPv6 prefix-list match criteria
1594 * has been delete from the route-map index, update
1595 * the route-map's prefix table.
1596 */
1597 if (IS_RULE_IPv4_PREFIX_LIST(match_name)) {
1598 route_map_pfx_tbl_update(
1599 RMAP_EVENT_PLIST_DELETED, index, AFI_IP,
1600 match_arg);
1601 } else if (IS_RULE_IPv6_PREFIX_LIST(match_name)) {
1602 route_map_pfx_tbl_update(
1603 RMAP_EVENT_PLIST_DELETED, index,
1604 AFI_IP6, match_arg);
1605 }
1606
1607 return RMAP_COMPILE_SUCCESS;
1608 }
1609 /* Can't find matched rule. */
1610 return RMAP_RULE_MISSING;
1611 }
1612
1613 /* Add route-map set statement to the route map. */
1614 enum rmap_compile_rets route_map_add_set(struct route_map_index *index,
1615 const char *set_name,
1616 const char *set_arg)
1617 {
1618 struct route_map_rule *rule;
1619 struct route_map_rule *next;
1620 const struct route_map_rule_cmd *cmd;
1621 void *compile;
1622
1623 cmd = route_map_lookup_set(set_name);
1624 if (cmd == NULL)
1625 return RMAP_RULE_MISSING;
1626
1627 /* Next call compile function for this match statement. */
1628 if (cmd->func_compile) {
1629 compile = (*cmd->func_compile)(set_arg);
1630 if (compile == NULL)
1631 return RMAP_COMPILE_ERROR;
1632 } else
1633 compile = NULL;
1634
1635 /* Add by WJL. if old set command of same kind exist, delete it first
1636 to ensure only one set command of same kind exist under a
1637 route_map_index. */
1638 for (rule = index->set_list.head; rule; rule = next) {
1639 next = rule->next;
1640 if (rule->cmd == cmd)
1641 route_map_rule_delete(&index->set_list, rule);
1642 }
1643
1644 /* Add new route map match rule. */
1645 rule = route_map_rule_new();
1646 rule->cmd = cmd;
1647 rule->value = compile;
1648 if (set_arg)
1649 rule->rule_str = XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR, set_arg);
1650 else
1651 rule->rule_str = NULL;
1652
1653 /* Add new route match rule to linked list. */
1654 route_map_rule_add(&index->set_list, rule);
1655
1656 /* Execute event hook. */
1657 if (route_map_master.event_hook) {
1658 (*route_map_master.event_hook)(index->map->name);
1659 route_map_notify_dependencies(index->map->name,
1660 RMAP_EVENT_CALL_ADDED);
1661 }
1662 return RMAP_COMPILE_SUCCESS;
1663 }
1664
1665 /* Delete route map set rule. */
1666 enum rmap_compile_rets route_map_delete_set(struct route_map_index *index,
1667 const char *set_name,
1668 const char *set_arg)
1669 {
1670 struct route_map_rule *rule;
1671 const struct route_map_rule_cmd *cmd;
1672
1673 cmd = route_map_lookup_set(set_name);
1674 if (cmd == NULL)
1675 return RMAP_RULE_MISSING;
1676
1677 for (rule = index->set_list.head; rule; rule = rule->next)
1678 if ((rule->cmd == cmd) && (rulecmp(rule->rule_str, set_arg) == 0
1679 || set_arg == NULL)) {
1680 route_map_rule_delete(&index->set_list, rule);
1681 /* Execute event hook. */
1682 if (route_map_master.event_hook) {
1683 (*route_map_master.event_hook)(index->map->name);
1684 route_map_notify_dependencies(
1685 index->map->name,
1686 RMAP_EVENT_CALL_ADDED);
1687 }
1688 return RMAP_COMPILE_SUCCESS;
1689 }
1690 /* Can't find matched rule. */
1691 return RMAP_RULE_MISSING;
1692 }
1693
1694 static enum route_map_cmd_result_t
1695 route_map_apply_match(struct route_map_rule_list *match_list,
1696 const struct prefix *prefix, void *object)
1697 {
1698 enum route_map_cmd_result_t ret = RMAP_NOMATCH;
1699 struct route_map_rule *match;
1700 bool is_matched = false;
1701
1702
1703 /* Check all match rule and if there is no match rule, go to the
1704 set statement. */
1705 if (!match_list->head)
1706 ret = RMAP_MATCH;
1707 else {
1708 for (match = match_list->head; match; match = match->next) {
1709 /*
1710 * Try each match statement. If any match does not
1711 * return RMAP_MATCH or RMAP_NOOP, return.
1712 * Otherwise continue on to next match statement.
1713 * All match statements must MATCH for
1714 * end-result to be a match.
1715 * (Exception:If match stmts result in a mix of
1716 * MATCH/NOOP, then also end-result is a match)
1717 * If all result in NOOP, end-result is NOOP.
1718 */
1719 ret = (*match->cmd->func_apply)(match->value, prefix,
1720 object);
1721
1722 /*
1723 * If the consolidated result of func_apply is:
1724 * -----------------------------------------------
1725 * | MATCH | NOMATCH | NOOP | Final Result |
1726 * ------------------------------------------------
1727 * | yes | yes | yes | NOMATCH |
1728 * | no | no | yes | NOOP |
1729 * | yes | no | yes | MATCH |
1730 * | no | yes | yes | NOMATCH |
1731 * |-----------------------------------------------
1732 *
1733 * Traditionally, all rules within route-map
1734 * should match for it to MATCH.
1735 * If there are noops within the route-map rules,
1736 * it follows the above matrix.
1737 *
1738 * Eg: route-map rm1 permit 10
1739 * match rule1
1740 * match rule2
1741 * match rule3
1742 * ....
1743 * route-map rm1 permit 20
1744 * match ruleX
1745 * match ruleY
1746 * ...
1747 */
1748
1749 switch (ret) {
1750 case RMAP_MATCH:
1751 is_matched = true;
1752 break;
1753
1754 case RMAP_NOMATCH:
1755 return ret;
1756
1757 case RMAP_NOOP:
1758 if (is_matched)
1759 ret = RMAP_MATCH;
1760 break;
1761
1762 default:
1763 break;
1764 }
1765
1766 }
1767 }
1768 return ret;
1769 }
1770
1771 static struct list *route_map_get_index_list(struct route_node **rn,
1772 const struct prefix *prefix,
1773 struct route_table *table)
1774 {
1775 struct route_node *tmp_rn = NULL;
1776
1777 if (!(*rn)) {
1778 *rn = route_node_match(table, prefix);
1779
1780 if (!(*rn))
1781 return NULL;
1782
1783 if ((*rn)->info)
1784 return (struct list *)((*rn)->info);
1785
1786 /* If rn->info is NULL, get the parent.
1787 * Store the rn in tmp_rn and unlock it later.
1788 */
1789 tmp_rn = *rn;
1790 }
1791
1792 do {
1793 *rn = (*rn)->parent;
1794 if (tmp_rn)
1795 route_unlock_node(tmp_rn);
1796
1797 if (!(*rn))
1798 break;
1799
1800 if ((*rn)->info) {
1801 route_lock_node(*rn);
1802 return (struct list *)((*rn)->info);
1803 }
1804 } while (!(*rn)->info);
1805
1806 return NULL;
1807 }
1808
1809 /*
1810 * This function returns the route-map index that best matches the prefix.
1811 */
1812 static struct route_map_index *
1813 route_map_get_index(struct route_map *map, const struct prefix *prefix,
1814 void *object, enum route_map_cmd_result_t *match_ret)
1815 {
1816 enum route_map_cmd_result_t ret = RMAP_NOMATCH;
1817 struct list *candidate_rmap_list = NULL;
1818 struct route_node *rn = NULL;
1819 struct listnode *ln = NULL, *nn = NULL;
1820 struct route_map_index *index = NULL, *best_index = NULL;
1821 struct route_map_index *head_index = NULL;
1822 struct route_table *table = NULL;
1823 unsigned char family = prefix->family;
1824
1825 if (family == AF_INET)
1826 table = map->ipv4_prefix_table;
1827 else
1828 table = map->ipv6_prefix_table;
1829
1830 if (!table)
1831 return NULL;
1832
1833 do {
1834 candidate_rmap_list =
1835 route_map_get_index_list(&rn, prefix, table);
1836 if (!rn)
1837 break;
1838
1839 /* If the index at the head of the list is of seq higher
1840 * than that in best_index, ignore the list and get the
1841 * parent node's list.
1842 */
1843 head_index = (struct route_map_index *)(listgetdata(
1844 listhead(candidate_rmap_list)));
1845 if (best_index && head_index
1846 && (best_index->pref < head_index->pref)) {
1847 route_unlock_node(rn);
1848 continue;
1849 }
1850
1851 for (ALL_LIST_ELEMENTS(candidate_rmap_list, ln, nn, index)) {
1852 /* If the index is of seq higher than that in
1853 * best_index, ignore the list and get the parent
1854 * node's list.
1855 */
1856 if (best_index && (best_index->pref < index->pref))
1857 break;
1858
1859 ret = route_map_apply_match(&index->match_list, prefix,
1860 object);
1861
1862 if (ret == RMAP_MATCH) {
1863 *match_ret = ret;
1864 best_index = index;
1865 break;
1866 } else if (ret == RMAP_NOOP) {
1867 /*
1868 * If match_ret is denymatch, even if we see
1869 * more noops, we retain this return value and
1870 * return this eventually if there are no
1871 * matches.
1872 * If a best match route-map index already
1873 * exists, do not reset the match_ret.
1874 */
1875 if (!best_index && (*match_ret != RMAP_NOMATCH))
1876 *match_ret = ret;
1877 } else {
1878 /*
1879 * ret is RMAP_NOMATCH.
1880 * If a best match route-map index already
1881 * exists, do not reset the match_ret.
1882 */
1883 if (!best_index)
1884 *match_ret = ret;
1885 }
1886 }
1887
1888 route_unlock_node(rn);
1889
1890 } while (rn);
1891
1892 return best_index;
1893 }
1894
1895 static int route_map_candidate_list_cmp(struct route_map_index *idx1,
1896 struct route_map_index *idx2)
1897 {
1898 if (!idx1)
1899 return -1;
1900 if (!idx2)
1901 return 1;
1902
1903 return (idx1->pref - idx2->pref);
1904 }
1905
1906 /*
1907 * This function adds the route-map index into the default route's
1908 * route-node in the route-map's IPv4/IPv6 prefix-table.
1909 */
1910 static void route_map_pfx_table_add_default(afi_t afi,
1911 struct route_map_index *index)
1912 {
1913 struct route_node *rn = NULL;
1914 struct list *rmap_candidate_list = NULL;
1915 struct prefix p;
1916 bool updated_rn = false;
1917 struct route_table *table = NULL;
1918
1919 memset(&p, 0, sizeof(p));
1920 p.family = afi2family(afi);
1921 p.prefixlen = 0;
1922
1923 if (p.family == AF_INET) {
1924 table = index->map->ipv4_prefix_table;
1925 if (!table)
1926 index->map->ipv4_prefix_table = route_table_init();
1927
1928 table = index->map->ipv4_prefix_table;
1929 } else {
1930 table = index->map->ipv6_prefix_table;
1931 if (!table)
1932 index->map->ipv6_prefix_table = route_table_init();
1933
1934 table = index->map->ipv6_prefix_table;
1935 }
1936
1937 /* Add default route to table */
1938 rn = route_node_get(table, &p);
1939
1940 if (!rn)
1941 return;
1942
1943 if (!rn->info) {
1944 rmap_candidate_list = list_new();
1945 rmap_candidate_list->cmp =
1946 (int (*)(void *, void *))route_map_candidate_list_cmp;
1947 rn->info = rmap_candidate_list;
1948 } else {
1949 rmap_candidate_list = (struct list *)rn->info;
1950 updated_rn = true;
1951 }
1952
1953 listnode_add_sort_nodup(rmap_candidate_list, index);
1954 if (updated_rn)
1955 route_unlock_node(rn);
1956 }
1957
1958 /*
1959 * This function removes the route-map index from the default route's
1960 * route-node in the route-map's IPv4/IPv6 prefix-table.
1961 */
1962 static void route_map_pfx_table_del_default(afi_t afi,
1963 struct route_map_index *index)
1964 {
1965 struct route_node *rn = NULL;
1966 struct list *rmap_candidate_list = NULL;
1967 struct prefix p;
1968 struct route_table *table = NULL;
1969
1970 memset(&p, 0, sizeof(p));
1971 p.family = afi2family(afi);
1972 p.prefixlen = 0;
1973
1974 if (p.family == AF_INET)
1975 table = index->map->ipv4_prefix_table;
1976 else
1977 table = index->map->ipv6_prefix_table;
1978
1979 /* Remove RMAP index from default route in table */
1980 rn = route_node_lookup(table, &p);
1981 if (!rn || !rn->info)
1982 return;
1983
1984 rmap_candidate_list = (struct list *)rn->info;
1985
1986 listnode_delete(rmap_candidate_list, index);
1987
1988 if (listcount(rmap_candidate_list) == 0) {
1989 list_delete(&rmap_candidate_list);
1990 rn->info = NULL;
1991 route_unlock_node(rn);
1992 }
1993 route_unlock_node(rn);
1994 }
1995
1996 /*
1997 * This function adds the route-map index to the route-node for
1998 * the prefix-entry in the route-map's IPv4/IPv6 prefix-table.
1999 */
2000 static void route_map_pfx_table_add(struct route_table *table,
2001 struct route_map_index *index,
2002 struct prefix_list_entry *pentry)
2003 {
2004 struct route_node *rn = NULL;
2005 struct list *rmap_candidate_list = NULL;
2006 bool updated_rn = false;
2007
2008 rn = route_node_get(table, &pentry->prefix);
2009 if (!rn)
2010 return;
2011
2012 if (!rn->info) {
2013 rmap_candidate_list = list_new();
2014 rmap_candidate_list->cmp =
2015 (int (*)(void *, void *))route_map_candidate_list_cmp;
2016 rn->info = rmap_candidate_list;
2017 } else {
2018 rmap_candidate_list = (struct list *)rn->info;
2019 updated_rn = true;
2020 }
2021
2022 listnode_add_sort_nodup(rmap_candidate_list, index);
2023 if (updated_rn)
2024 route_unlock_node(rn);
2025 }
2026
2027 /*
2028 * This function removes the route-map index from the route-node for
2029 * the prefix-entry in the route-map's IPv4/IPv6 prefix-table.
2030 */
2031 static void route_map_pfx_table_del(struct route_table *table,
2032 struct route_map_index *index,
2033 struct prefix_list_entry *pentry)
2034 {
2035 struct route_node *rn = NULL;
2036 struct list *rmap_candidate_list = NULL;
2037
2038 rn = route_node_lookup(table, &pentry->prefix);
2039 if (!rn || !rn->info)
2040 return;
2041
2042 rmap_candidate_list = (struct list *)rn->info;
2043
2044 listnode_delete(rmap_candidate_list, index);
2045
2046 if (listcount(rmap_candidate_list) == 0) {
2047 list_delete(&rmap_candidate_list);
2048 rn->info = NULL;
2049 route_unlock_node(rn);
2050 }
2051 route_unlock_node(rn);
2052 }
2053
2054 /* This function checks for the presence of an IPv4 prefix-list
2055 * match rule in the given route-map index.
2056 */
2057 static bool route_map_is_ip_pfx_list_rule_present(struct route_map_index *index)
2058 {
2059 struct route_map_rule_list *match_list = NULL;
2060 struct route_map_rule *rule = NULL;
2061
2062 match_list = &index->match_list;
2063 for (rule = match_list->head; rule; rule = rule->next)
2064 if (IS_RULE_IPv4_PREFIX_LIST(rule->cmd->str))
2065 return true;
2066
2067 return false;
2068 }
2069
2070 /* This function checks for the presence of an IPv6 prefix-list
2071 * match rule in the given route-map index.
2072 */
2073 static bool
2074 route_map_is_ipv6_pfx_list_rule_present(struct route_map_index *index)
2075 {
2076 struct route_map_rule_list *match_list = NULL;
2077 struct route_map_rule *rule = NULL;
2078
2079 match_list = &index->match_list;
2080 for (rule = match_list->head; rule; rule = rule->next)
2081 if (IS_RULE_IPv6_PREFIX_LIST(rule->cmd->str))
2082 return true;
2083
2084 return false;
2085 }
2086
2087 /* This function does the following:
2088 * 1) If plist_name is not present, search for a IPv4 or IPv6 prefix-list
2089 * match clause (based on the afi passed to this foo) and get the
2090 * prefix-list name.
2091 * 2) Look up the prefix-list using the name.
2092 * 3) If the prefix-list is not found then, add the index to the IPv4/IPv6
2093 * default-route's node in the trie (based on the afi passed to this foo).
2094 * 4) If the prefix-list is found then, remove the index from the IPv4/IPv6
2095 * default-route's node in the trie (based on the afi passed to this foo).
2096 * 5) If a prefix-entry is passed then, create a route-node for this entry and
2097 * add this index to the route-node.
2098 * 6) If prefix-entry is not passed then, for every prefix-entry in the
2099 * prefix-list, create a route-node for this entry and
2100 * add this index to the route-node.
2101 */
2102 static void route_map_add_plist_entries(afi_t afi,
2103 struct route_map_index *index,
2104 const char *plist_name,
2105 struct prefix_list_entry *entry)
2106 {
2107 struct route_map_rule_list *match_list = NULL;
2108 struct route_map_rule *match = NULL;
2109 struct prefix_list *plist = NULL;
2110 struct prefix_list_entry *pentry = NULL;
2111 bool plist_rule_is_present = false;
2112
2113 if (!plist_name) {
2114 match_list = &index->match_list;
2115
2116 for (match = match_list->head; match; match = match->next) {
2117 if (afi == AFI_IP) {
2118 if (IS_RULE_IPv4_PREFIX_LIST(match->cmd->str)) {
2119 plist_rule_is_present = true;
2120 break;
2121 }
2122 } else {
2123 if (IS_RULE_IPv6_PREFIX_LIST(match->cmd->str)) {
2124 plist_rule_is_present = true;
2125 break;
2126 }
2127 }
2128 }
2129
2130 if (plist_rule_is_present)
2131 plist = prefix_list_lookup(afi, match->rule_str);
2132 } else {
2133 plist = prefix_list_lookup(afi, plist_name);
2134 }
2135
2136 if (!plist) {
2137 route_map_pfx_table_add_default(afi, index);
2138 return;
2139 }
2140
2141 /* Default entry should be deleted only if the first entry of the
2142 * prefix-list is created.
2143 */
2144 if (entry) {
2145 if (plist->count == 1)
2146 route_map_pfx_table_del_default(afi, index);
2147 } else {
2148 route_map_pfx_table_del_default(afi, index);
2149 }
2150
2151 if (entry) {
2152 if (afi == AFI_IP) {
2153 route_map_pfx_table_add(index->map->ipv4_prefix_table,
2154 index, entry);
2155 } else {
2156 route_map_pfx_table_add(index->map->ipv6_prefix_table,
2157 index, entry);
2158 }
2159 } else {
2160 for (pentry = plist->head; pentry; pentry = pentry->next) {
2161 if (afi == AFI_IP) {
2162 route_map_pfx_table_add(
2163 index->map->ipv4_prefix_table, index,
2164 pentry);
2165 } else {
2166 route_map_pfx_table_add(
2167 index->map->ipv6_prefix_table, index,
2168 pentry);
2169 }
2170 }
2171 }
2172 }
2173
2174 /* This function does the following:
2175 * 1) If plist_name is not present, search for a IPv4 or IPv6 prefix-list
2176 * match clause (based on the afi passed to this foo) and get the
2177 * prefix-list name.
2178 * 2) Look up the prefix-list using the name.
2179 * 3) If the prefix-list is not found then, delete the index from the IPv4/IPv6
2180 * default-route's node in the trie (based on the afi passed to this foo).
2181 * 4) If a prefix-entry is passed then, remove this index from the route-node
2182 * for the prefix in this prefix-entry.
2183 * 5) If prefix-entry is not passed then, for every prefix-entry in the
2184 * prefix-list, remove this index from the route-node
2185 * for the prefix in this prefix-entry.
2186 */
2187 static void route_map_del_plist_entries(afi_t afi,
2188 struct route_map_index *index,
2189 const char *plist_name,
2190 struct prefix_list_entry *entry)
2191 {
2192 struct route_map_rule_list *match_list = NULL;
2193 struct route_map_rule *match = NULL;
2194 struct prefix_list *plist = NULL;
2195 struct prefix_list_entry *pentry = NULL;
2196 bool plist_rule_is_present = false;
2197
2198 if (!plist_name) {
2199 match_list = &index->match_list;
2200
2201 for (match = match_list->head; match; match = match->next) {
2202 if (afi == AFI_IP) {
2203 if (IS_RULE_IPv4_PREFIX_LIST(match->cmd->str)) {
2204 plist_rule_is_present = true;
2205 break;
2206 }
2207 } else {
2208 if (IS_RULE_IPv6_PREFIX_LIST(match->cmd->str)) {
2209 plist_rule_is_present = true;
2210 break;
2211 }
2212 }
2213 }
2214
2215 if (plist_rule_is_present)
2216 plist = prefix_list_lookup(afi, match->rule_str);
2217 } else {
2218 plist = prefix_list_lookup(afi, plist_name);
2219 }
2220
2221 if (!plist) {
2222 route_map_pfx_table_del_default(afi, index);
2223 return;
2224 }
2225
2226 if (entry) {
2227 if (afi == AFI_IP) {
2228 route_map_pfx_table_del(index->map->ipv4_prefix_table,
2229 index, entry);
2230 } else {
2231 route_map_pfx_table_del(index->map->ipv6_prefix_table,
2232 index, entry);
2233 }
2234 } else {
2235 for (pentry = plist->head; pentry; pentry = pentry->next) {
2236 if (afi == AFI_IP) {
2237 route_map_pfx_table_del(
2238 index->map->ipv4_prefix_table, index,
2239 pentry);
2240 } else {
2241 route_map_pfx_table_del(
2242 index->map->ipv6_prefix_table, index,
2243 pentry);
2244 }
2245 }
2246 }
2247 }
2248
2249 /*
2250 * This function handles the cases where a prefix-list is added/removed
2251 * as a match command from a particular route-map index.
2252 * It updates the prefix-table of the route-map accordingly.
2253 */
2254 static void route_map_trie_update(afi_t afi, route_map_event_t event,
2255 struct route_map_index *index,
2256 const char *plist_name)
2257 {
2258 if (event == RMAP_EVENT_PLIST_ADDED) {
2259 if (afi == AFI_IP) {
2260 if (!route_map_is_ipv6_pfx_list_rule_present(index)) {
2261 route_map_pfx_table_del_default(AFI_IP6, index);
2262 route_map_add_plist_entries(afi, index,
2263 plist_name, NULL);
2264 } else {
2265 route_map_del_plist_entries(AFI_IP6, index,
2266 NULL, NULL);
2267 }
2268 } else {
2269 if (!route_map_is_ip_pfx_list_rule_present(index)) {
2270 route_map_pfx_table_del_default(AFI_IP, index);
2271 route_map_add_plist_entries(afi, index,
2272 plist_name, NULL);
2273 } else {
2274 route_map_del_plist_entries(AFI_IP, index, NULL,
2275 NULL);
2276 }
2277 }
2278 } else if (event == RMAP_EVENT_PLIST_DELETED) {
2279 if (afi == AFI_IP) {
2280 route_map_del_plist_entries(afi, index, plist_name,
2281 NULL);
2282
2283 /* If IPv6 prefix-list match rule is not present,
2284 * add this index to the IPv4 default route's trie
2285 * node.
2286 * Also, add this index to the trie nodes created
2287 * for each of the prefix-entries within the IPv6
2288 * prefix-list, if the IPv6 prefix-list match rule
2289 * is present. Else, add this index to the IPv6
2290 * default route's trie node.
2291 */
2292 if (!route_map_is_ipv6_pfx_list_rule_present(index))
2293 route_map_pfx_table_add_default(afi, index);
2294
2295 route_map_add_plist_entries(AFI_IP6, index, NULL, NULL);
2296 } else {
2297 route_map_del_plist_entries(afi, index, plist_name,
2298 NULL);
2299
2300 /* If IPv4 prefix-list match rule is not present,
2301 * add this index to the IPv6 default route's trie
2302 * node.
2303 * Also, add this index to the trie nodes created
2304 * for each of the prefix-entries within the IPv4
2305 * prefix-list, if the IPv4 prefix-list match rule
2306 * is present. Else, add this index to the IPv4
2307 * default route's trie node.
2308 */
2309 if (!route_map_is_ip_pfx_list_rule_present(index))
2310 route_map_pfx_table_add_default(afi, index);
2311
2312 route_map_add_plist_entries(AFI_IP, index, NULL, NULL);
2313 }
2314 }
2315 }
2316
2317 /*
2318 * This function handles the cases where a route-map index and
2319 * prefix-list is added/removed.
2320 * It updates the prefix-table of the route-map accordingly.
2321 */
2322 static void route_map_pfx_tbl_update(route_map_event_t event,
2323 struct route_map_index *index, afi_t afi,
2324 const char *plist_name)
2325 {
2326 struct route_map *rmap = NULL;
2327
2328 if (!index)
2329 return;
2330
2331 if (event == RMAP_EVENT_INDEX_ADDED) {
2332 route_map_pfx_table_add_default(AFI_IP, index);
2333 route_map_pfx_table_add_default(AFI_IP6, index);
2334 return;
2335 }
2336
2337 if (event == RMAP_EVENT_INDEX_DELETED) {
2338 route_map_pfx_table_del_default(AFI_IP, index);
2339 route_map_pfx_table_del_default(AFI_IP6, index);
2340
2341 if ((index->map->head == NULL) && (index->map->tail == NULL)) {
2342 rmap = index->map;
2343
2344 if (rmap->ipv4_prefix_table) {
2345 route_table_finish(rmap->ipv4_prefix_table);
2346 rmap->ipv4_prefix_table = NULL;
2347 }
2348
2349 if (rmap->ipv6_prefix_table) {
2350 route_table_finish(rmap->ipv6_prefix_table);
2351 rmap->ipv6_prefix_table = NULL;
2352 }
2353 }
2354 return;
2355 }
2356
2357 /* Handle prefix-list match rule addition/deletion.
2358 */
2359 route_map_trie_update(afi, event, index, plist_name);
2360 }
2361
2362 /*
2363 * This function handles the cases where a new prefix-entry is added to
2364 * a prefix-list or, an existing prefix-entry is removed from the prefix-list.
2365 * It updates the prefix-table of the route-map accordingly.
2366 */
2367 static void route_map_pentry_update(route_map_event_t event,
2368 const char *plist_name,
2369 struct route_map_index *index,
2370 struct prefix_list_entry *pentry)
2371 {
2372 struct prefix_list *plist = NULL;
2373 afi_t afi;
2374 unsigned char family = pentry->prefix.family;
2375
2376 if (family == AF_INET) {
2377 afi = AFI_IP;
2378 plist = prefix_list_lookup(AFI_IP, plist_name);
2379 } else {
2380 afi = AFI_IP6;
2381 plist = prefix_list_lookup(AFI_IP6, plist_name);
2382 }
2383
2384 if (event == RMAP_EVENT_PLIST_ADDED) {
2385 if (afi == AFI_IP) {
2386 if (!route_map_is_ipv6_pfx_list_rule_present(index))
2387 route_map_add_plist_entries(afi, index,
2388 plist_name, pentry);
2389 } else {
2390 if (!route_map_is_ip_pfx_list_rule_present(index))
2391 route_map_add_plist_entries(afi, index,
2392 plist_name, pentry);
2393 }
2394 } else if (event == RMAP_EVENT_PLIST_DELETED) {
2395 route_map_del_plist_entries(afi, index, plist_name, pentry);
2396
2397 if (plist->count == 1) {
2398 if (afi == AFI_IP) {
2399 if (!route_map_is_ipv6_pfx_list_rule_present(
2400 index))
2401 route_map_pfx_table_add_default(afi,
2402 index);
2403 } else {
2404 if (!route_map_is_ip_pfx_list_rule_present(
2405 index))
2406 route_map_pfx_table_add_default(afi,
2407 index);
2408 }
2409 }
2410 }
2411 }
2412
2413 static void route_map_pentry_process_dependency(struct hash_bucket *bucket,
2414 void *data)
2415 {
2416 char *rmap_name = NULL;
2417 struct route_map *rmap = NULL;
2418 struct route_map_index *index = NULL;
2419 struct route_map_rule_list *match_list = NULL;
2420 struct route_map_rule *match = NULL;
2421 struct route_map_dep_data *dep_data = NULL;
2422 struct route_map_pentry_dep *pentry_dep =
2423 (struct route_map_pentry_dep *)data;
2424 unsigned char family = pentry_dep->pentry->prefix.family;
2425
2426 dep_data = (struct route_map_dep_data *)bucket->data;
2427 if (!dep_data)
2428 return;
2429
2430 rmap_name = dep_data->rname;
2431 rmap = route_map_lookup_by_name(rmap_name);
2432 if (!rmap || !rmap->head)
2433 return;
2434
2435 for (index = rmap->head; index; index = index->next) {
2436 match_list = &index->match_list;
2437
2438 if (!match_list)
2439 continue;
2440
2441 for (match = match_list->head; match; match = match->next) {
2442 if (strcmp(match->rule_str, pentry_dep->plist_name)
2443 == 0) {
2444 if (IS_RULE_IPv4_PREFIX_LIST(match->cmd->str)
2445 && family == AF_INET) {
2446 route_map_pentry_update(
2447 pentry_dep->event,
2448 pentry_dep->plist_name, index,
2449 pentry_dep->pentry);
2450 } else if (IS_RULE_IPv6_PREFIX_LIST(
2451 match->cmd->str)
2452 && family == AF_INET6) {
2453 route_map_pentry_update(
2454 pentry_dep->event,
2455 pentry_dep->plist_name, index,
2456 pentry_dep->pentry);
2457 }
2458 }
2459 }
2460 }
2461 }
2462
2463 void route_map_notify_pentry_dependencies(const char *affected_name,
2464 struct prefix_list_entry *pentry,
2465 route_map_event_t event)
2466 {
2467 struct route_map_dep *dep = NULL;
2468 struct hash *upd8_hash = NULL;
2469 struct route_map_pentry_dep pentry_dep;
2470
2471 if (!affected_name || !pentry)
2472 return;
2473
2474 upd8_hash = route_map_get_dep_hash(event);
2475 if (!upd8_hash)
2476 return;
2477
2478 dep = (struct route_map_dep *)hash_get(upd8_hash, (void *)affected_name,
2479 NULL);
2480 if (dep) {
2481 if (!dep->this_hash)
2482 dep->this_hash = upd8_hash;
2483
2484 memset(&pentry_dep, 0, sizeof(pentry_dep));
2485 pentry_dep.pentry = pentry;
2486 pentry_dep.plist_name = affected_name;
2487 pentry_dep.event = event;
2488
2489 hash_iterate(dep->dep_rmap_hash,
2490 route_map_pentry_process_dependency,
2491 (void *)&pentry_dep);
2492 }
2493 }
2494
2495 /* Apply route map's each index to the object.
2496
2497 The matrix for a route-map looks like this:
2498 (note, this includes the description for the "NEXT"
2499 and "GOTO" frobs now
2500
2501 | Match | No Match | No op
2502 |-----------|--------------|-------
2503 permit | action | cont | cont.
2504 | | default:deny | default:permit
2505 -------------------+-----------------------
2506 | deny | cont | cont.
2507 deny | | default:deny | default:permit
2508 |-----------|--------------|--------
2509
2510 action)
2511 -Apply Set statements, accept route
2512 -If Call statement is present jump to the specified route-map, if it
2513 denies the route we finish.
2514 -If NEXT is specified, goto NEXT statement
2515 -If GOTO is specified, goto the first clause where pref > nextpref
2516 -If nothing is specified, do as Cisco and finish
2517 deny)
2518 -Route is denied by route-map.
2519 cont)
2520 -Goto Next index
2521
2522 If we get no matches after we've processed all updates, then the route
2523 is dropped too.
2524
2525 Some notes on the new "CALL", "NEXT" and "GOTO"
2526 call WORD - If this clause is matched, then the set statements
2527 are executed and then we jump to route-map 'WORD'. If
2528 this route-map denies the route, we finish, in other
2529 case we
2530 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
2531 on-match next - If this clause is matched, then the set statements
2532 are executed and then we drop through to the next clause
2533 on-match goto n - If this clause is matched, then the set statements
2534 are executed and then we goto the nth clause, or the
2535 first clause greater than this. In order to ensure
2536 route-maps *always* exit, you cannot jump backwards.
2537 Sorry ;)
2538
2539 We need to make sure our route-map processing matches the above
2540 */
2541 route_map_result_t route_map_apply_ext(struct route_map *map,
2542 const struct prefix *prefix,
2543 void *match_object, void *set_object)
2544 {
2545 static int recursion = 0;
2546 enum route_map_cmd_result_t match_ret = RMAP_NOMATCH;
2547 route_map_result_t ret = RMAP_PERMITMATCH;
2548 struct route_map_index *index = NULL;
2549 struct route_map_rule *set = NULL;
2550 bool skip_match_clause = false;
2551
2552 if (recursion > RMAP_RECURSION_LIMIT) {
2553 flog_warn(
2554 EC_LIB_RMAP_RECURSION_LIMIT,
2555 "route-map recursion limit (%d) reached, discarding route",
2556 RMAP_RECURSION_LIMIT);
2557 recursion = 0;
2558 return RMAP_DENYMATCH;
2559 }
2560
2561 if (map == NULL || map->head == NULL) {
2562 ret = RMAP_DENYMATCH;
2563 goto route_map_apply_end;
2564 }
2565
2566 map->applied++;
2567
2568 if ((!map->optimization_disabled)
2569 && (map->ipv4_prefix_table || map->ipv6_prefix_table)) {
2570 index = route_map_get_index(map, prefix, match_object,
2571 &match_ret);
2572 if (index) {
2573 index->applied++;
2574 if (rmap_debug)
2575 zlog_debug(
2576 "Best match route-map: %s, sequence: %d for pfx: %pFX, result: %s",
2577 map->name, index->pref, prefix,
2578 route_map_cmd_result_str(match_ret));
2579 } else {
2580 if (rmap_debug)
2581 zlog_debug(
2582 "No best match sequence for pfx: %pFX in route-map: %s, result: %s",
2583 prefix, map->name,
2584 route_map_cmd_result_str(match_ret));
2585 /*
2586 * No index matches this prefix. Return deny unless,
2587 * match_ret = RMAP_NOOP.
2588 */
2589 if (match_ret == RMAP_NOOP)
2590 ret = RMAP_PERMITMATCH;
2591 else
2592 ret = RMAP_DENYMATCH;
2593 goto route_map_apply_end;
2594 }
2595 skip_match_clause = true;
2596 } else {
2597 index = map->head;
2598 }
2599
2600 for (; index; index = index->next) {
2601 if (!skip_match_clause) {
2602 index->applied++;
2603 /* Apply this index. */
2604 match_ret = route_map_apply_match(&index->match_list,
2605 prefix, match_object);
2606 if (rmap_debug) {
2607 zlog_debug(
2608 "Route-map: %s, sequence: %d, prefix: %pFX, result: %s",
2609 map->name, index->pref, prefix,
2610 route_map_cmd_result_str(match_ret));
2611 }
2612 } else
2613 skip_match_clause = false;
2614
2615
2616 /* Now we apply the matrix from above */
2617 if (match_ret == RMAP_NOOP)
2618 /*
2619 * Do not change the return value. Retain the previous
2620 * return value. Previous values can be:
2621 * 1)permitmatch (if a nomatch was never
2622 * seen before in this route-map.)
2623 * 2)denymatch (if a nomatch was seen earlier in one
2624 * of the previous sequences)
2625 */
2626
2627 /*
2628 * 'cont' from matrix - continue to next route-map
2629 * sequence
2630 */
2631 continue;
2632 else if (match_ret == RMAP_NOMATCH) {
2633
2634 /*
2635 * The return value is now changed to denymatch.
2636 * So from here on out, even if we see more noops,
2637 * we retain this return value and return this
2638 * eventually if there are no matches.
2639 */
2640 ret = RMAP_DENYMATCH;
2641
2642 /*
2643 * 'cont' from matrix - continue to next route-map
2644 * sequence
2645 */
2646 continue;
2647 } else if (match_ret == RMAP_MATCH) {
2648 if (index->type == RMAP_PERMIT)
2649 /* 'action' */
2650 {
2651 /* Match succeeded, rmap is of type permit */
2652 ret = RMAP_PERMITMATCH;
2653
2654 /* permit+match must execute sets */
2655 for (set = index->set_list.head; set;
2656 set = set->next)
2657 /*
2658 * set cmds return RMAP_OKAY or
2659 * RMAP_ERROR. We do not care if
2660 * set succeeded or not. So, ignore
2661 * return code.
2662 */
2663 (void)(*set->cmd->func_apply)(
2664 set->value, prefix, set_object);
2665
2666 /* Call another route-map if available */
2667 if (index->nextrm) {
2668 struct route_map *nextrm =
2669 route_map_lookup_by_name(
2670 index->nextrm);
2671
2672 if (nextrm) /* Target route-map found,
2673 jump to it */
2674 {
2675 recursion++;
2676 ret = route_map_apply_ext(
2677 nextrm, prefix,
2678 match_object,
2679 set_object);
2680 recursion--;
2681 }
2682
2683 /* If nextrm returned 'deny', finish. */
2684 if (ret == RMAP_DENYMATCH)
2685 goto route_map_apply_end;
2686 }
2687
2688 switch (index->exitpolicy) {
2689 case RMAP_EXIT:
2690 goto route_map_apply_end;
2691 case RMAP_NEXT:
2692 continue;
2693 case RMAP_GOTO: {
2694 /* Find the next clause to jump to */
2695 struct route_map_index *next =
2696 index->next;
2697 int nextpref = index->nextpref;
2698
2699 while (next && next->pref < nextpref) {
2700 index = next;
2701 next = next->next;
2702 }
2703 if (next == NULL) {
2704 /* No clauses match! */
2705 goto route_map_apply_end;
2706 }
2707 }
2708 }
2709 } else if (index->type == RMAP_DENY)
2710 /* 'deny' */
2711 {
2712 ret = RMAP_DENYMATCH;
2713 goto route_map_apply_end;
2714 }
2715 }
2716 }
2717
2718 route_map_apply_end:
2719 if (rmap_debug)
2720 zlog_debug("Route-map: %s, prefix: %pFX, result: %s",
2721 (map ? map->name : "null"), prefix,
2722 route_map_result_str(ret));
2723
2724 return (ret);
2725 }
2726
2727 void route_map_add_hook(void (*func)(const char *))
2728 {
2729 route_map_master.add_hook = func;
2730 }
2731
2732 void route_map_delete_hook(void (*func)(const char *))
2733 {
2734 route_map_master.delete_hook = func;
2735 }
2736
2737 void route_map_event_hook(void (*func)(const char *name))
2738 {
2739 route_map_master.event_hook = func;
2740 }
2741
2742 /* Routines for route map dependency lists and dependency processing */
2743 static bool route_map_rmap_hash_cmp(const void *p1, const void *p2)
2744 {
2745 return strcmp(((const struct route_map_dep_data *)p1)->rname,
2746 ((const struct route_map_dep_data *)p2)->rname)
2747 == 0;
2748 }
2749
2750 static bool route_map_dep_hash_cmp(const void *p1, const void *p2)
2751 {
2752
2753 return (strcmp(((const struct route_map_dep *)p1)->dep_name,
2754 (const char *)p2)
2755 == 0);
2756 }
2757
2758 static void route_map_clear_reference(struct hash_bucket *bucket, void *arg)
2759 {
2760 struct route_map_dep *dep = bucket->data;
2761 struct route_map_dep_data *dep_data = NULL, tmp_dep_data;
2762
2763 memset(&tmp_dep_data, 0, sizeof(tmp_dep_data));
2764 tmp_dep_data.rname = arg;
2765 dep_data = hash_release(dep->dep_rmap_hash, &tmp_dep_data);
2766 if (dep_data) {
2767 if (rmap_debug)
2768 zlog_debug("Clearing reference for %s to %s count: %d",
2769 dep->dep_name, tmp_dep_data.rname,
2770 dep_data->refcnt);
2771
2772 XFREE(MTYPE_ROUTE_MAP_NAME, dep_data->rname);
2773 XFREE(MTYPE_ROUTE_MAP_DEP_DATA, dep_data);
2774 }
2775 if (!dep->dep_rmap_hash->count) {
2776 dep = hash_release(dep->this_hash, (void *)dep->dep_name);
2777 hash_free(dep->dep_rmap_hash);
2778 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
2779 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
2780 }
2781 }
2782
2783 static void route_map_clear_all_references(char *rmap_name)
2784 {
2785 int i;
2786
2787 if (rmap_debug)
2788 zlog_debug("Clearing references for %s", rmap_name);
2789
2790 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
2791 hash_iterate(route_map_dep_hash[i], route_map_clear_reference,
2792 (void *)rmap_name);
2793 }
2794 }
2795
2796 static unsigned int route_map_dep_data_hash_make_key(const void *p)
2797 {
2798 const struct route_map_dep_data *dep_data = p;
2799
2800 return string_hash_make(dep_data->rname);
2801 }
2802
2803 static void *route_map_dep_hash_alloc(void *p)
2804 {
2805 char *dep_name = (char *)p;
2806 struct route_map_dep *dep_entry;
2807
2808 dep_entry = XCALLOC(MTYPE_ROUTE_MAP_DEP, sizeof(struct route_map_dep));
2809 dep_entry->dep_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
2810 dep_entry->dep_rmap_hash =
2811 hash_create_size(8, route_map_dep_data_hash_make_key,
2812 route_map_rmap_hash_cmp, "Route Map Dep Hash");
2813 dep_entry->this_hash = NULL;
2814
2815 return dep_entry;
2816 }
2817
2818 static void *route_map_name_hash_alloc(void *p)
2819 {
2820 struct route_map_dep_data *dep_data = NULL, *tmp_dep_data = NULL;
2821
2822 dep_data = XCALLOC(MTYPE_ROUTE_MAP_DEP_DATA,
2823 sizeof(struct route_map_dep_data));
2824 tmp_dep_data = p;
2825 dep_data->rname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, tmp_dep_data->rname);
2826 return dep_data;
2827 }
2828
2829 static unsigned int route_map_dep_hash_make_key(const void *p)
2830 {
2831 return (string_hash_make((char *)p));
2832 }
2833
2834 static void route_map_print_dependency(struct hash_bucket *bucket, void *data)
2835 {
2836 struct route_map_dep_data *dep_data = bucket->data;
2837 char *rmap_name = dep_data->rname;
2838 char *dep_name = data;
2839
2840 zlog_debug("%s: Dependency for %s: %s", __func__, dep_name, rmap_name);
2841 }
2842
2843 static int route_map_dep_update(struct hash *dephash, const char *dep_name,
2844 const char *rmap_name, route_map_event_t type)
2845 {
2846 struct route_map_dep *dep = NULL;
2847 char *dname, *rname;
2848 int ret = 0;
2849 struct route_map_dep_data *dep_data = NULL, *ret_dep_data = NULL;
2850 struct route_map_dep_data tmp_dep_data;
2851
2852 dname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
2853 rname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_name);
2854
2855 switch (type) {
2856 case RMAP_EVENT_PLIST_ADDED:
2857 case RMAP_EVENT_CLIST_ADDED:
2858 case RMAP_EVENT_ECLIST_ADDED:
2859 case RMAP_EVENT_ASLIST_ADDED:
2860 case RMAP_EVENT_LLIST_ADDED:
2861 case RMAP_EVENT_CALL_ADDED:
2862 case RMAP_EVENT_FILTER_ADDED:
2863 if (rmap_debug)
2864 zlog_debug("Adding dependency for filter %s in route-map %s",
2865 dep_name, rmap_name);
2866 dep = (struct route_map_dep *)hash_get(
2867 dephash, dname, route_map_dep_hash_alloc);
2868 if (!dep) {
2869 ret = -1;
2870 goto out;
2871 }
2872
2873 if (!dep->this_hash)
2874 dep->this_hash = dephash;
2875
2876 memset(&tmp_dep_data, 0, sizeof(tmp_dep_data));
2877 tmp_dep_data.rname = rname;
2878 dep_data = hash_lookup(dep->dep_rmap_hash, &tmp_dep_data);
2879 if (!dep_data)
2880 dep_data = hash_get(dep->dep_rmap_hash, &tmp_dep_data,
2881 route_map_name_hash_alloc);
2882
2883 dep_data->refcnt++;
2884 break;
2885 case RMAP_EVENT_PLIST_DELETED:
2886 case RMAP_EVENT_CLIST_DELETED:
2887 case RMAP_EVENT_ECLIST_DELETED:
2888 case RMAP_EVENT_ASLIST_DELETED:
2889 case RMAP_EVENT_LLIST_DELETED:
2890 case RMAP_EVENT_CALL_DELETED:
2891 case RMAP_EVENT_FILTER_DELETED:
2892 if (rmap_debug)
2893 zlog_debug("Deleting dependency for filter %s in route-map %s",
2894 dep_name, rmap_name);
2895 dep = (struct route_map_dep *)hash_get(dephash, dname, NULL);
2896 if (!dep) {
2897 goto out;
2898 }
2899
2900 memset(&tmp_dep_data, 0, sizeof(tmp_dep_data));
2901 tmp_dep_data.rname = rname;
2902 dep_data = hash_lookup(dep->dep_rmap_hash, &tmp_dep_data);
2903 /*
2904 * If dep_data is NULL then something has gone seriously
2905 * wrong in route-map handling. Note it and prevent
2906 * the crash.
2907 */
2908 if (!dep_data) {
2909 zlog_warn(
2910 "route-map dependency for route-map %s: %s is not correct",
2911 rmap_name, dep_name);
2912 goto out;
2913 }
2914
2915 dep_data->refcnt--;
2916
2917 if (!dep_data->refcnt) {
2918 ret_dep_data = hash_release(dep->dep_rmap_hash,
2919 &tmp_dep_data);
2920 if (ret_dep_data) {
2921 XFREE(MTYPE_ROUTE_MAP_NAME,
2922 ret_dep_data->rname);
2923 XFREE(MTYPE_ROUTE_MAP_DEP_DATA, ret_dep_data);
2924 }
2925 }
2926
2927 if (!dep->dep_rmap_hash->count) {
2928 dep = hash_release(dephash, dname);
2929 hash_free(dep->dep_rmap_hash);
2930 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
2931 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
2932 }
2933 break;
2934 case RMAP_EVENT_SET_ADDED:
2935 case RMAP_EVENT_SET_DELETED:
2936 case RMAP_EVENT_SET_REPLACED:
2937 case RMAP_EVENT_MATCH_ADDED:
2938 case RMAP_EVENT_MATCH_DELETED:
2939 case RMAP_EVENT_MATCH_REPLACED:
2940 case RMAP_EVENT_INDEX_ADDED:
2941 case RMAP_EVENT_INDEX_DELETED:
2942 break;
2943 }
2944
2945 if (dep) {
2946 if (rmap_debug)
2947 hash_iterate(dep->dep_rmap_hash,
2948 route_map_print_dependency, dname);
2949 }
2950
2951 out:
2952 XFREE(MTYPE_ROUTE_MAP_NAME, rname);
2953 XFREE(MTYPE_ROUTE_MAP_NAME, dname);
2954 return ret;
2955 }
2956
2957 static struct hash *route_map_get_dep_hash(route_map_event_t event)
2958 {
2959 struct hash *upd8_hash = NULL;
2960
2961 switch (event) {
2962 case RMAP_EVENT_PLIST_ADDED:
2963 case RMAP_EVENT_PLIST_DELETED:
2964 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_PLIST];
2965 break;
2966 case RMAP_EVENT_CLIST_ADDED:
2967 case RMAP_EVENT_CLIST_DELETED:
2968 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_CLIST];
2969 break;
2970 case RMAP_EVENT_ECLIST_ADDED:
2971 case RMAP_EVENT_ECLIST_DELETED:
2972 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ECLIST];
2973 break;
2974 case RMAP_EVENT_ASLIST_ADDED:
2975 case RMAP_EVENT_ASLIST_DELETED:
2976 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ASPATH];
2977 break;
2978 case RMAP_EVENT_LLIST_ADDED:
2979 case RMAP_EVENT_LLIST_DELETED:
2980 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_LCLIST];
2981 break;
2982 case RMAP_EVENT_CALL_ADDED:
2983 case RMAP_EVENT_CALL_DELETED:
2984 case RMAP_EVENT_MATCH_ADDED:
2985 case RMAP_EVENT_MATCH_DELETED:
2986 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_RMAP];
2987 break;
2988 case RMAP_EVENT_FILTER_ADDED:
2989 case RMAP_EVENT_FILTER_DELETED:
2990 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_FILTER];
2991 break;
2992 /*
2993 * Should we actually be ignoring these?
2994 * I am not sure but at this point in time, let
2995 * us get them into this switch and we can peel
2996 * them into the appropriate place in the future
2997 */
2998 case RMAP_EVENT_SET_ADDED:
2999 case RMAP_EVENT_SET_DELETED:
3000 case RMAP_EVENT_SET_REPLACED:
3001 case RMAP_EVENT_MATCH_REPLACED:
3002 case RMAP_EVENT_INDEX_ADDED:
3003 case RMAP_EVENT_INDEX_DELETED:
3004 upd8_hash = NULL;
3005 break;
3006 }
3007 return (upd8_hash);
3008 }
3009
3010 static void route_map_process_dependency(struct hash_bucket *bucket, void *data)
3011 {
3012 struct route_map_dep_data *dep_data = NULL;
3013 char *rmap_name = NULL;
3014
3015 dep_data = bucket->data;
3016 rmap_name = dep_data->rname;
3017
3018 if (rmap_debug)
3019 zlog_debug("Notifying %s of dependency", rmap_name);
3020 if (route_map_master.event_hook)
3021 (*route_map_master.event_hook)(rmap_name);
3022 }
3023
3024 void route_map_upd8_dependency(route_map_event_t type, const char *arg,
3025 const char *rmap_name)
3026 {
3027 struct hash *upd8_hash = NULL;
3028
3029 if ((upd8_hash = route_map_get_dep_hash(type))) {
3030 route_map_dep_update(upd8_hash, arg, rmap_name, type);
3031
3032 if (type == RMAP_EVENT_CALL_ADDED) {
3033 /* Execute hook. */
3034 if (route_map_master.add_hook)
3035 (*route_map_master.add_hook)(rmap_name);
3036 } else if (type == RMAP_EVENT_CALL_DELETED) {
3037 /* Execute hook. */
3038 if (route_map_master.delete_hook)
3039 (*route_map_master.delete_hook)(rmap_name);
3040 }
3041 }
3042 }
3043
3044 void route_map_notify_dependencies(const char *affected_name,
3045 route_map_event_t event)
3046 {
3047 struct route_map_dep *dep;
3048 struct hash *upd8_hash;
3049 char *name;
3050
3051 if (!affected_name)
3052 return;
3053
3054 name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, affected_name);
3055
3056 if ((upd8_hash = route_map_get_dep_hash(event)) == NULL) {
3057 XFREE(MTYPE_ROUTE_MAP_NAME, name);
3058 return;
3059 }
3060
3061 dep = (struct route_map_dep *)hash_get(upd8_hash, name, NULL);
3062 if (dep) {
3063 if (!dep->this_hash)
3064 dep->this_hash = upd8_hash;
3065
3066 if (rmap_debug)
3067 zlog_debug("Filter %s updated", dep->dep_name);
3068 hash_iterate(dep->dep_rmap_hash, route_map_process_dependency,
3069 (void *)event);
3070 }
3071
3072 XFREE(MTYPE_ROUTE_MAP_NAME, name);
3073 }
3074
3075 /* VTY related functions. */
3076 static void clear_route_map_helper(struct route_map *map)
3077 {
3078 struct route_map_index *index;
3079
3080 map->applied_clear = map->applied;
3081 for (index = map->head; index; index = index->next)
3082 index->applied_clear = index->applied;
3083 }
3084
3085 DEFUN (rmap_clear_counters,
3086 rmap_clear_counters_cmd,
3087 "clear route-map counters [WORD]",
3088 CLEAR_STR
3089 "route-map information\n"
3090 "counters associated with the specified route-map\n"
3091 "route-map name\n")
3092 {
3093 int idx_word = 2;
3094 struct route_map *map;
3095
3096 const char *name = (argc == 3 ) ? argv[idx_word]->arg : NULL;
3097
3098 if (name) {
3099 map = route_map_lookup_by_name(name);
3100
3101 if (map)
3102 clear_route_map_helper(map);
3103 else {
3104 vty_out(vty, "%s: 'route-map %s' not found\n",
3105 frr_protonameinst, name);
3106 return CMD_SUCCESS;
3107 }
3108 } else {
3109 for (map = route_map_master.head; map; map = map->next)
3110 clear_route_map_helper(map);
3111 }
3112
3113 return CMD_SUCCESS;
3114
3115 }
3116
3117 DEFUN (rmap_show_name,
3118 rmap_show_name_cmd,
3119 "show route-map [WORD] [json]",
3120 SHOW_STR
3121 "route-map information\n"
3122 "route-map name\n"
3123 JSON_STR)
3124 {
3125 bool uj = use_json(argc, argv);
3126 int idx = 0;
3127 const char *name = NULL;
3128
3129 if (argv_find(argv, argc, "WORD", &idx))
3130 name = argv[idx]->arg;
3131
3132 return vty_show_route_map(vty, name, uj);
3133 }
3134
3135 DEFUN (rmap_show_unused,
3136 rmap_show_unused_cmd,
3137 "show route-map-unused",
3138 SHOW_STR
3139 "unused route-map information\n")
3140 {
3141 return vty_show_unused_route_map(vty);
3142 }
3143
3144 DEFUN (debug_rmap,
3145 debug_rmap_cmd,
3146 "debug route-map",
3147 DEBUG_STR
3148 "Debug option set for route-maps\n")
3149 {
3150 rmap_debug = true;
3151 return CMD_SUCCESS;
3152 }
3153
3154 DEFUN (no_debug_rmap,
3155 no_debug_rmap_cmd,
3156 "no debug route-map",
3157 NO_STR
3158 DEBUG_STR
3159 "Debug option set for route-maps\n")
3160 {
3161 rmap_debug = false;
3162 return CMD_SUCCESS;
3163 }
3164
3165 /* Debug node. */
3166 static int rmap_config_write_debug(struct vty *vty);
3167 static struct cmd_node rmap_debug_node = {
3168 .name = "route-map debug",
3169 .node = RMAP_DEBUG_NODE,
3170 .prompt = "",
3171 .config_write = rmap_config_write_debug,
3172 };
3173
3174 /* Configuration write function. */
3175 static int rmap_config_write_debug(struct vty *vty)
3176 {
3177 int write = 0;
3178
3179 if (rmap_debug) {
3180 vty_out(vty, "debug route-map\n");
3181 write++;
3182 }
3183
3184 return write;
3185 }
3186
3187 /* Common route map rules */
3188
3189 void *route_map_rule_tag_compile(const char *arg)
3190 {
3191 unsigned long int tmp;
3192 char *endptr;
3193 route_tag_t *tag;
3194
3195 errno = 0;
3196 tmp = strtoul(arg, &endptr, 0);
3197 if (arg[0] == '\0' || *endptr != '\0' || errno || tmp > ROUTE_TAG_MAX)
3198 return NULL;
3199
3200 tag = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*tag));
3201 *tag = tmp;
3202
3203 return tag;
3204 }
3205
3206 void route_map_rule_tag_free(void *rule)
3207 {
3208 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
3209 }
3210
3211 void route_map_finish(void)
3212 {
3213 int i;
3214 struct route_map_rule_cmd_proxy *proxy;
3215
3216 /* these 2 hash tables have INIT_HASH initializers, so the "default"
3217 * state is "initialized & empty" => fini() followed by init() to
3218 * return to that same state
3219 */
3220 while ((proxy = rmap_cmd_name_pop(rmap_match_cmds)))
3221 (void)proxy;
3222 rmap_cmd_name_fini(rmap_match_cmds);
3223 rmap_cmd_name_init(rmap_match_cmds);
3224
3225 while ((proxy = rmap_cmd_name_pop(rmap_set_cmds)))
3226 (void)proxy;
3227 rmap_cmd_name_fini(rmap_set_cmds);
3228 rmap_cmd_name_init(rmap_set_cmds);
3229
3230 /*
3231 * All protocols are setting these to NULL
3232 * by default on shutdown( route_map_finish )
3233 * Why are we making them do this work?
3234 */
3235 route_map_master.add_hook = NULL;
3236 route_map_master.delete_hook = NULL;
3237 route_map_master.event_hook = NULL;
3238
3239 /* cleanup route_map */
3240 while (route_map_master.head) {
3241 struct route_map *map = route_map_master.head;
3242 map->to_be_processed = false;
3243 route_map_delete(map);
3244 }
3245
3246 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
3247 hash_free(route_map_dep_hash[i]);
3248 route_map_dep_hash[i] = NULL;
3249 }
3250
3251 hash_free(route_map_master_hash);
3252 route_map_master_hash = NULL;
3253 }
3254
3255 /* Increment the use_count counter while attaching the route map */
3256 void route_map_counter_increment(struct route_map *map)
3257 {
3258 if (map)
3259 map->use_count++;
3260 }
3261
3262 /* Decrement the use_count counter while detaching the route map. */
3263 void route_map_counter_decrement(struct route_map *map)
3264 {
3265 if (map) {
3266 if (map->use_count <= 0)
3267 return;
3268 map->use_count--;
3269 }
3270 }
3271
3272 DEFUN_HIDDEN(show_route_map_pfx_tbl, show_route_map_pfx_tbl_cmd,
3273 "show route-map RMAP_NAME prefix-table",
3274 SHOW_STR
3275 "route-map\n"
3276 "route-map name\n"
3277 "internal prefix-table\n")
3278 {
3279 const char *rmap_name = argv[2]->arg;
3280 struct route_map *rmap = NULL;
3281 struct route_table *rm_pfx_tbl4 = NULL;
3282 struct route_table *rm_pfx_tbl6 = NULL;
3283 struct route_node *rn = NULL, *prn = NULL;
3284 struct list *rmap_index_list = NULL;
3285 struct listnode *ln = NULL, *nln = NULL;
3286 struct route_map_index *index = NULL;
3287 uint8_t len = 54;
3288
3289 vty_out(vty, "%s:\n", frr_protonameinst);
3290 rmap = route_map_lookup_by_name(rmap_name);
3291 if (rmap) {
3292 rm_pfx_tbl4 = rmap->ipv4_prefix_table;
3293 if (rm_pfx_tbl4) {
3294 vty_out(vty, "\n%s%43s%s\n", "IPv4 Prefix", "",
3295 "Route-map Index List");
3296 vty_out(vty, "%s%39s%s\n", "_______________", "",
3297 "____________________");
3298 for (rn = route_top(rm_pfx_tbl4); rn;
3299 rn = route_next(rn)) {
3300 vty_out(vty, " %pRN (%d)\n", rn,
3301 route_node_get_lock_count(rn));
3302
3303 vty_out(vty, "(P) ");
3304 prn = rn->parent;
3305 if (prn) {
3306 vty_out(vty, "%pRN\n", prn);
3307 }
3308
3309 vty_out(vty, "\n");
3310 rmap_index_list = (struct list *)rn->info;
3311 if (!rmap_index_list
3312 || !listcount(rmap_index_list))
3313 vty_out(vty, "%*s%s\n", len, "", "-");
3314 else
3315 for (ALL_LIST_ELEMENTS(rmap_index_list,
3316 ln, nln,
3317 index)) {
3318 vty_out(vty, "%*s%s seq %d\n",
3319 len, "",
3320 index->map->name,
3321 index->pref);
3322 }
3323 vty_out(vty, "\n");
3324 }
3325 }
3326
3327 rm_pfx_tbl6 = rmap->ipv6_prefix_table;
3328 if (rm_pfx_tbl6) {
3329 vty_out(vty, "\n%s%43s%s\n", "IPv6 Prefix", "",
3330 "Route-map Index List");
3331 vty_out(vty, "%s%39s%s\n", "_______________", "",
3332 "____________________");
3333 for (rn = route_top(rm_pfx_tbl6); rn;
3334 rn = route_next(rn)) {
3335 vty_out(vty, " %pRN (%d)\n", rn,
3336 route_node_get_lock_count(rn));
3337
3338 vty_out(vty, "(P) ");
3339 prn = rn->parent;
3340 if (prn) {
3341 vty_out(vty, "%pRN\n", prn);
3342 }
3343
3344 vty_out(vty, "\n");
3345 rmap_index_list = (struct list *)rn->info;
3346 if (!rmap_index_list
3347 || !listcount(rmap_index_list))
3348 vty_out(vty, "%*s%s\n", len, "", "-");
3349 else
3350 for (ALL_LIST_ELEMENTS(rmap_index_list,
3351 ln, nln,
3352 index)) {
3353 vty_out(vty, "%*s%s seq %d\n",
3354 len, "",
3355 index->map->name,
3356 index->pref);
3357 }
3358 vty_out(vty, "\n");
3359 }
3360 }
3361 }
3362
3363 vty_out(vty, "\n");
3364 return CMD_SUCCESS;
3365 }
3366
3367 /* Initialization of route map vector. */
3368 void route_map_init(void)
3369 {
3370 int i;
3371
3372 route_map_master_hash =
3373 hash_create_size(8, route_map_hash_key_make, route_map_hash_cmp,
3374 "Route Map Master Hash");
3375
3376 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
3377 route_map_dep_hash[i] = hash_create_size(
3378 8, route_map_dep_hash_make_key, route_map_dep_hash_cmp,
3379 "Route Map Dep Hash");
3380
3381 rmap_debug = false;
3382
3383 route_map_cli_init();
3384
3385 /* Install route map top node. */
3386 install_node(&rmap_debug_node);
3387
3388 /* Install route map commands. */
3389 install_element(CONFIG_NODE, &debug_rmap_cmd);
3390 install_element(CONFIG_NODE, &no_debug_rmap_cmd);
3391
3392 /* Install show command */
3393 install_element(ENABLE_NODE, &rmap_clear_counters_cmd);
3394
3395 install_element(ENABLE_NODE, &rmap_show_name_cmd);
3396 install_element(ENABLE_NODE, &rmap_show_unused_cmd);
3397
3398 install_element(ENABLE_NODE, &debug_rmap_cmd);
3399 install_element(ENABLE_NODE, &no_debug_rmap_cmd);
3400
3401 install_element(ENABLE_NODE, &show_route_map_pfx_tbl_cmd);
3402 }