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