back to topotato report
topotato coverage report
Current view: top level - lib - routemap.c (source / functions) Hit Total Coverage
Test: test_bgp_disable_addpath_rx.py::BGPDisableAddpathRx Lines: 175 1459 12.0 %
Date: 2023-02-24 18:37:08 Functions: 64 143 44.8 %

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

Generated by: LCOV version v1.16-topotato