back to topotato report
topotato coverage report
Current view: top level - lib - routemap.c (source / functions) Hit Total Coverage
Test: test_bgp_ecmp_enhe.py::BGP_Unnumbered_ECMP Lines: 175 1467 11.9 %
Date: 2023-11-16 17:19:14 Functions: 64 279 22.9 %

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

Generated by: LCOV version v1.16-topotato