back to topotato report
topotato coverage report
Current view: top level - lib - distribute.c (source / functions) Hit Total Coverage
Test: test_bgp_aggregate_address_origin.py::BGPAggregateAddressOrigin Lines: 4 223 1.8 %
Date: 2023-02-24 18:36:37 Functions: 8 29 27.6 %

          Line data    Source code
       1             : /* Distribute list functions
       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
       7             :  * it under the terms of the GNU General Public License as published
       8             :  * by the Free Software Foundation; either version 2, or (at your
       9             :  * option) any 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 "hash.h"
      24             : #include "if.h"
      25             : #include "filter.h"
      26             : #include "command.h"
      27             : #include "distribute.h"
      28             : #include "memory.h"
      29             : 
      30          12 : DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_CTX, "Distribute ctx");
      31          12 : DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE, "Distribute list");
      32          12 : DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_IFNAME, "Dist-list ifname");
      33          12 : DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_NAME, "Dist-list name");
      34             : 
      35             : static struct list *dist_ctx_list;
      36             : 
      37           0 : static struct distribute *distribute_new(void)
      38             : {
      39           0 :         return XCALLOC(MTYPE_DISTRIBUTE, sizeof(struct distribute));
      40             : }
      41             : 
      42             : /* Free distribute object. */
      43           0 : static void distribute_free(struct distribute *dist)
      44             : {
      45           0 :         int i = 0;
      46             : 
      47           0 :         XFREE(MTYPE_DISTRIBUTE_IFNAME, dist->ifname);
      48             : 
      49           0 :         for (i = 0; i < DISTRIBUTE_MAX; i++) {
      50           0 :                 XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[i]);
      51             :         }
      52             : 
      53           0 :         for (i = 0; i < DISTRIBUTE_MAX; i++) {
      54           0 :                 XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[i]);
      55             :         }
      56             : 
      57           0 :         XFREE(MTYPE_DISTRIBUTE, dist);
      58           0 : }
      59             : 
      60           0 : static void distribute_free_if_empty(struct distribute_ctx *ctx,
      61             :                                      struct distribute *dist)
      62             : {
      63           0 :         int i;
      64             : 
      65           0 :         for (i = 0; i < DISTRIBUTE_MAX; i++)
      66           0 :                 if (dist->list[i] != NULL || dist->prefix[i] != NULL)
      67             :                         return;
      68             : 
      69           0 :         hash_release(ctx->disthash, dist);
      70           0 :         distribute_free(dist);
      71             : }
      72             : 
      73             : /* Lookup interface's distribute list. */
      74           0 : struct distribute *distribute_lookup(struct distribute_ctx *ctx,
      75             :                                      const char *ifname)
      76             : {
      77           0 :         struct distribute key;
      78           0 :         struct distribute *dist;
      79             : 
      80             :         /* temporary reference */
      81           0 :         key.ifname = (ifname) ? XSTRDUP(MTYPE_DISTRIBUTE_IFNAME, ifname) : NULL;
      82             : 
      83           0 :         dist = hash_lookup(ctx->disthash, &key);
      84             : 
      85           0 :         XFREE(MTYPE_DISTRIBUTE_IFNAME, key.ifname);
      86             : 
      87           0 :         return dist;
      88             : }
      89             : 
      90           0 : void distribute_list_add_hook(struct distribute_ctx *ctx,
      91             :                               void (*func)(struct distribute_ctx *ctx,
      92             :                                            struct distribute *))
      93             : {
      94           0 :         ctx->distribute_add_hook = func;
      95           0 : }
      96             : 
      97           0 : void distribute_list_delete_hook(struct distribute_ctx *ctx,
      98             :                                  void (*func)(struct distribute_ctx *ctx,
      99             :                                               struct distribute *))
     100             : {
     101           0 :         ctx->distribute_delete_hook = func;
     102           0 : }
     103             : 
     104           0 : static void *distribute_hash_alloc(struct distribute *arg)
     105             : {
     106           0 :         struct distribute *dist;
     107             : 
     108           0 :         dist = distribute_new();
     109           0 :         if (arg->ifname)
     110           0 :                 dist->ifname = XSTRDUP(MTYPE_DISTRIBUTE_IFNAME, arg->ifname);
     111             :         else
     112           0 :                 dist->ifname = NULL;
     113           0 :         return dist;
     114             : }
     115             : 
     116             : /* Make new distribute list and push into hash. */
     117           0 : static struct distribute *distribute_get(struct distribute_ctx *ctx,
     118             :                                          const char *ifname)
     119             : {
     120           0 :         struct distribute key;
     121           0 :         struct distribute *ret;
     122             : 
     123             :         /* temporary reference */
     124           0 :         key.ifname = (ifname) ? XSTRDUP(MTYPE_DISTRIBUTE_IFNAME, ifname) : NULL;
     125             : 
     126           0 :         ret = hash_get(ctx->disthash, &key,
     127             :                        (void *(*)(void *))distribute_hash_alloc);
     128             : 
     129           0 :         XFREE(MTYPE_DISTRIBUTE_IFNAME, key.ifname);
     130             : 
     131           0 :         return ret;
     132             : }
     133             : 
     134           0 : static unsigned int distribute_hash_make(const void *arg)
     135             : {
     136           0 :         const struct distribute *dist = arg;
     137             : 
     138           0 :         return dist->ifname ? string_hash_make(dist->ifname) : 0;
     139             : }
     140             : 
     141             : /* If two distribute-list have same value then return 1 else return
     142             :    0. This function is used by hash package. */
     143           0 : static bool distribute_cmp(const struct distribute *dist1,
     144             :                           const struct distribute *dist2)
     145             : {
     146           0 :         if (dist1->ifname && dist2->ifname)
     147           0 :                 if (strcmp(dist1->ifname, dist2->ifname) == 0)
     148             :                         return true;
     149           0 :         if (!dist1->ifname && !dist2->ifname)
     150           0 :                 return true;
     151             :         return false;
     152             : }
     153             : 
     154             : /* Set access-list name to the distribute list. */
     155           0 : static void distribute_list_set(struct distribute_ctx *ctx,
     156             :                                 const char *ifname, enum distribute_type type,
     157             :                                 const char *alist_name)
     158             : {
     159           0 :         struct distribute *dist;
     160             : 
     161           0 :         dist = distribute_get(ctx, ifname);
     162             : 
     163           0 :         XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[type]);
     164           0 :         dist->list[type] = XSTRDUP(MTYPE_DISTRIBUTE_NAME, alist_name);
     165             : 
     166             :         /* Apply this distribute-list to the interface. */
     167           0 :         (ctx->distribute_add_hook)(ctx, dist);
     168           0 : }
     169             : 
     170             : /* Unset distribute-list.  If matched distribute-list exist then
     171             :    return 1. */
     172           0 : static int distribute_list_unset(struct distribute_ctx *ctx,
     173             :                                  const char *ifname,
     174             :                                  enum distribute_type type,
     175             :                                  const char *alist_name)
     176             : {
     177           0 :         struct distribute *dist;
     178             : 
     179           0 :         dist = distribute_lookup(ctx, ifname);
     180           0 :         if (!dist)
     181             :                 return 0;
     182             : 
     183           0 :         if (!dist->list[type])
     184             :                 return 0;
     185           0 :         if (strcmp(dist->list[type], alist_name) != 0)
     186             :                 return 0;
     187             : 
     188           0 :         XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[type]);
     189             : 
     190             :         /* Apply this distribute-list to the interface. */
     191           0 :         (ctx->distribute_delete_hook)(ctx, dist);
     192             : 
     193             :         /* If all dist are NULL, then free distribute list. */
     194           0 :         distribute_free_if_empty(ctx, dist);
     195           0 :         return 1;
     196             : }
     197             : 
     198             : /* Set access-list name to the distribute list. */
     199           0 : static void distribute_list_prefix_set(struct distribute_ctx *ctx,
     200             :                                        const char *ifname,
     201             :                                        enum distribute_type type,
     202             :                                        const char *plist_name)
     203             : {
     204           0 :         struct distribute *dist;
     205             : 
     206           0 :         dist = distribute_get(ctx, ifname);
     207             : 
     208           0 :         XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[type]);
     209           0 :         dist->prefix[type] = XSTRDUP(MTYPE_DISTRIBUTE_NAME, plist_name);
     210             : 
     211             :         /* Apply this distribute-list to the interface. */
     212           0 :         (ctx->distribute_add_hook)(ctx, dist);
     213           0 : }
     214             : 
     215             : /* Unset distribute-list.  If matched distribute-list exist then
     216             :    return 1. */
     217           0 : static int distribute_list_prefix_unset(struct distribute_ctx *ctx,
     218             :                                         const char *ifname,
     219             :                                         enum distribute_type type,
     220             :                                         const char *plist_name)
     221             : {
     222           0 :         struct distribute *dist;
     223             : 
     224           0 :         dist = distribute_lookup(ctx, ifname);
     225           0 :         if (!dist)
     226             :                 return 0;
     227             : 
     228           0 :         if (!dist->prefix[type])
     229             :                 return 0;
     230           0 :         if (strcmp(dist->prefix[type], plist_name) != 0)
     231             :                 return 0;
     232             : 
     233           0 :         XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[type]);
     234             : 
     235             :         /* Apply this distribute-list to the interface. */
     236           0 :         (ctx->distribute_delete_hook)(ctx, dist);
     237             : 
     238             :         /* If all dist are NULL, then free distribute list. */
     239           0 :         distribute_free_if_empty(ctx, dist);
     240           0 :         return 1;
     241             : }
     242             : 
     243           0 : static enum distribute_type distribute_direction(const char *dir, bool v4)
     244             : {
     245           0 :         if (dir[0] == 'i') {
     246           0 :                 if (v4)
     247             :                         return DISTRIBUTE_V4_IN;
     248             :                 else
     249           0 :                         return DISTRIBUTE_V6_IN;
     250           0 :         } else if (dir[0] == 'o') {
     251           0 :                 if (v4)
     252             :                         return DISTRIBUTE_V4_OUT;
     253             :                 else
     254           0 :                         return DISTRIBUTE_V6_OUT;
     255             :         }
     256             : 
     257           0 :         assert(!"Expecting in or out only, fix your code");
     258             : 
     259             :         __builtin_unreachable();
     260             : }
     261             : 
     262           0 : int distribute_list_parser(bool prefix, bool v4, const char *dir,
     263             :                            const char *list, const char *ifname)
     264             : {
     265           0 :         enum distribute_type type = distribute_direction(dir, v4);
     266           0 :         struct distribute_ctx *ctx = listnode_head(dist_ctx_list);
     267             : 
     268           0 :         void (*distfn)(struct distribute_ctx *, const char *,
     269             :                        enum distribute_type, const char *) =
     270           0 :                 prefix ? &distribute_list_prefix_set : &distribute_list_set;
     271             : 
     272           0 :         distfn(ctx, ifname, type, list);
     273             : 
     274           0 :         return CMD_SUCCESS;
     275             : }
     276             : 
     277           0 : int distribute_list_no_parser(struct vty *vty, bool prefix, bool v4,
     278             :                               const char *dir, const char *list,
     279             :                               const char *ifname)
     280             : {
     281           0 :         enum distribute_type type = distribute_direction(dir, v4);
     282           0 :         struct distribute_ctx *ctx = listnode_head(dist_ctx_list);
     283           0 :         int ret;
     284             : 
     285           0 :         int (*distfn)(struct distribute_ctx *, const char *,
     286             :                       enum distribute_type, const char *) =
     287           0 :                 prefix ? &distribute_list_prefix_unset : &distribute_list_unset;
     288             : 
     289             : 
     290           0 :         ret = distfn(ctx, ifname, type, list);
     291           0 :         if (!ret) {
     292           0 :                 vty_out(vty, "distribute list doesn't exist\n");
     293           0 :                 return CMD_WARNING_CONFIG_FAILED;
     294             :         }
     295             : 
     296             :         return CMD_SUCCESS;
     297             : }
     298             : 
     299           0 : static int distribute_print(struct vty *vty, char *tab[], int is_prefix,
     300             :                             enum distribute_type type, int has_print)
     301             : {
     302           0 :         if (tab[type]) {
     303           0 :                 vty_out(vty, "%s %s%s", has_print ? "," : "",
     304             :                         is_prefix ? "(prefix-list) " : "", tab[type]);
     305           0 :                 return 1;
     306             :         }
     307             :         return has_print;
     308             : }
     309             : 
     310           0 : int config_show_distribute(struct vty *vty, struct distribute_ctx *dist_ctxt)
     311             : {
     312           0 :         unsigned int i;
     313           0 :         int has_print = 0;
     314           0 :         struct hash_bucket *mp;
     315           0 :         struct distribute *dist;
     316             : 
     317             :         /* Output filter configuration. */
     318           0 :         dist = distribute_lookup(dist_ctxt, NULL);
     319           0 :         vty_out(vty, "  Outgoing update filter list for all interface is");
     320           0 :         has_print = 0;
     321           0 :         if (dist) {
     322           0 :                 has_print = distribute_print(vty, dist->list, 0,
     323             :                                              DISTRIBUTE_V4_OUT, has_print);
     324           0 :                 has_print = distribute_print(vty, dist->prefix, 1,
     325             :                                              DISTRIBUTE_V4_OUT, has_print);
     326           0 :                 has_print = distribute_print(vty, dist->list, 0,
     327             :                                              DISTRIBUTE_V6_OUT, has_print);
     328           0 :                 has_print = distribute_print(vty, dist->prefix, 1,
     329             :                                              DISTRIBUTE_V6_OUT, has_print);
     330             :         }
     331           0 :         if (has_print)
     332           0 :                 vty_out(vty, "\n");
     333             :         else
     334           0 :                 vty_out(vty, " not set\n");
     335             : 
     336           0 :         for (i = 0; i < dist_ctxt->disthash->size; i++)
     337           0 :                 for (mp = dist_ctxt->disthash->index[i]; mp; mp = mp->next) {
     338           0 :                         dist = mp->data;
     339           0 :                         if (dist->ifname) {
     340           0 :                                 vty_out(vty, "    %s filtered by",
     341             :                                         dist->ifname);
     342           0 :                                 has_print = 0;
     343           0 :                                 has_print = distribute_print(vty, dist->list, 0,
     344             :                                                              DISTRIBUTE_V4_OUT,
     345             :                                                              has_print);
     346           0 :                                 has_print = distribute_print(
     347           0 :                                         vty, dist->prefix, 1, DISTRIBUTE_V4_OUT,
     348             :                                         has_print);
     349           0 :                                 has_print = distribute_print(vty, dist->list, 0,
     350             :                                                              DISTRIBUTE_V6_OUT,
     351             :                                                              has_print);
     352           0 :                                 has_print = distribute_print(
     353             :                                         vty, dist->prefix, 1, DISTRIBUTE_V6_OUT,
     354             :                                         has_print);
     355           0 :                                 if (has_print)
     356           0 :                                         vty_out(vty, "\n");
     357             :                                 else
     358           0 :                                         vty_out(vty, " nothing\n");
     359             :                         }
     360             :                 }
     361             : 
     362             : 
     363             :         /* Input filter configuration. */
     364           0 :         dist = distribute_lookup(dist_ctxt, NULL);
     365           0 :         vty_out(vty, "  Incoming update filter list for all interface is");
     366           0 :         has_print = 0;
     367           0 :         if (dist) {
     368           0 :                 has_print = distribute_print(vty, dist->list, 0,
     369             :                                              DISTRIBUTE_V4_IN, has_print);
     370           0 :                 has_print = distribute_print(vty, dist->prefix, 1,
     371             :                                              DISTRIBUTE_V4_IN, has_print);
     372           0 :                 has_print = distribute_print(vty, dist->list, 0,
     373             :                                              DISTRIBUTE_V6_IN, has_print);
     374           0 :                 has_print = distribute_print(vty, dist->prefix, 1,
     375             :                                              DISTRIBUTE_V6_IN, has_print);
     376             :         }
     377           0 :         if (has_print)
     378           0 :                 vty_out(vty, "\n");
     379             :         else
     380           0 :                 vty_out(vty, " not set\n");
     381             : 
     382           0 :         for (i = 0; i < dist_ctxt->disthash->size; i++)
     383           0 :                 for (mp = dist_ctxt->disthash->index[i]; mp; mp = mp->next) {
     384           0 :                         dist = mp->data;
     385           0 :                         if (dist->ifname) {
     386           0 :                                 vty_out(vty, "    %s filtered by",
     387             :                                         dist->ifname);
     388           0 :                                 has_print = 0;
     389           0 :                                 has_print = distribute_print(vty, dist->list, 0,
     390             :                                                              DISTRIBUTE_V4_IN,
     391             :                                                              has_print);
     392           0 :                                 has_print = distribute_print(
     393           0 :                                         vty, dist->prefix, 1, DISTRIBUTE_V4_IN,
     394             :                                         has_print);
     395           0 :                                 has_print = distribute_print(vty, dist->list, 0,
     396             :                                                              DISTRIBUTE_V6_IN,
     397             :                                                              has_print);
     398           0 :                                 has_print = distribute_print(
     399             :                                         vty, dist->prefix, 1, DISTRIBUTE_V6_IN,
     400             :                                         has_print);
     401           0 :                                 if (has_print)
     402           0 :                                         vty_out(vty, "\n");
     403             :                                 else
     404           0 :                                         vty_out(vty, " nothing\n");
     405             :                         }
     406             :                 }
     407           0 :         return 0;
     408             : }
     409             : 
     410             : /* Configuration write function. */
     411           0 : int config_write_distribute(struct vty *vty,
     412             :                             struct distribute_ctx *dist_ctxt)
     413             : {
     414           0 :         unsigned int i;
     415           0 :         int j;
     416           0 :         int output, v6;
     417           0 :         struct hash_bucket *mp;
     418           0 :         int write = 0;
     419             : 
     420           0 :         for (i = 0; i < dist_ctxt->disthash->size; i++)
     421           0 :                 for (mp = dist_ctxt->disthash->index[i]; mp; mp = mp->next) {
     422           0 :                         struct distribute *dist;
     423             : 
     424           0 :                         dist = mp->data;
     425             : 
     426           0 :                         for (j = 0; j < DISTRIBUTE_MAX; j++)
     427           0 :                                 if (dist->list[j]) {
     428           0 :                                         output = j == DISTRIBUTE_V4_OUT
     429           0 :                                                  || j == DISTRIBUTE_V6_OUT;
     430           0 :                                         v6 = j == DISTRIBUTE_V6_IN
     431           0 :                                              || j == DISTRIBUTE_V6_OUT;
     432           0 :                                         vty_out(vty,
     433             :                                                 " %sdistribute-list %s %s %s\n",
     434             :                                                 v6 ? "ipv6 " : "",
     435             :                                                 dist->list[j],
     436             :                                                 output ? "out" : "in",
     437           0 :                                                 dist->ifname ? dist->ifname
     438             :                                                              : "");
     439           0 :                                         write++;
     440             :                                 }
     441             : 
     442           0 :                         for (j = 0; j < DISTRIBUTE_MAX; j++)
     443           0 :                                 if (dist->prefix[j]) {
     444           0 :                                         output = j == DISTRIBUTE_V4_OUT
     445           0 :                                                  || j == DISTRIBUTE_V6_OUT;
     446           0 :                                         v6 = j == DISTRIBUTE_V6_IN
     447           0 :                                              || j == DISTRIBUTE_V6_OUT;
     448           0 :                                         vty_out(vty,
     449             :                                                 " %sdistribute-list prefix %s %s %s\n",
     450             :                                                 v6 ? "ipv6 " : "",
     451             :                                                 dist->prefix[j],
     452             :                                                 output ? "out" : "in",
     453           0 :                                                 dist->ifname ? dist->ifname
     454             :                                                              : "");
     455           0 :                                         write++;
     456             :                                 }
     457             :                 }
     458           0 :         return write;
     459             : }
     460             : 
     461           0 : void distribute_list_delete(struct distribute_ctx **ctx)
     462             : {
     463           0 :         if ((*ctx)->disthash) {
     464           0 :                 hash_clean((*ctx)->disthash, (void (*)(void *))distribute_free);
     465             :         }
     466           0 :         if (!dist_ctx_list)
     467           0 :                 dist_ctx_list = list_new();
     468           0 :         listnode_delete(dist_ctx_list, *ctx);
     469           0 :         if (list_isempty(dist_ctx_list))
     470           0 :                 list_delete(&dist_ctx_list);
     471           0 :         XFREE(MTYPE_DISTRIBUTE_CTX, (*ctx));
     472           0 : }
     473             : 
     474             : /* Initialize distribute list container */
     475           0 : struct distribute_ctx *distribute_list_ctx_create(struct vrf *vrf)
     476             : {
     477           0 :         struct distribute_ctx *ctx;
     478             : 
     479           0 :         ctx = XCALLOC(MTYPE_DISTRIBUTE_CTX, sizeof(struct distribute_ctx));
     480           0 :         ctx->vrf = vrf;
     481           0 :         ctx->disthash = hash_create(
     482             :                 distribute_hash_make,
     483             :                 (bool (*)(const void *, const void *))distribute_cmp, NULL);
     484           0 :         if (!dist_ctx_list)
     485           0 :                 dist_ctx_list = list_new();
     486           0 :         listnode_add(dist_ctx_list, ctx);
     487           0 :         return ctx;
     488             : }

Generated by: LCOV version v1.16-topotato