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