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