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