back to topotato report
topotato coverage report
Current view: top level - bgpd - bgp_lcommunity.c (source / functions) Hit Total Coverage
Test: test_bgp_rmap_extcommunity_none.py::TestBGPExtCommunity Lines: 11 305 3.6 %
Date: 2023-02-24 18:37:31 Functions: 3 29 10.3 %

          Line data    Source code
       1             : /* BGP Large Communities Attribute
       2             :  *
       3             :  * Copyright (C) 2016 Keyur Patel <keyur@arrcus.com>
       4             :  *
       5             :  * This file is part of FRRouting (FRR).
       6             :  *
       7             :  * FRR is free software; you can redistribute it and/or modify it under the
       8             :  * terms of the GNU General Public License as published by the Free Software
       9             :  * Foundation; either version 2, or (at your option) any later version.
      10             :  *
      11             :  * FRR is distributed in the hope that it will be useful, but WITHOUT ANY
      12             :  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
      13             :  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
      14             :  * 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 "memory.h"
      25             : #include "prefix.h"
      26             : #include "command.h"
      27             : #include "filter.h"
      28             : #include "jhash.h"
      29             : #include "stream.h"
      30             : 
      31             : #include "bgpd/bgpd.h"
      32             : #include "bgpd/bgp_lcommunity.h"
      33             : #include "bgpd/bgp_community_alias.h"
      34             : #include "bgpd/bgp_aspath.h"
      35             : 
      36             : /* Hash of community attribute. */
      37             : static struct hash *lcomhash;
      38             : 
      39             : /* Allocate a new lcommunities.  */
      40           0 : static struct lcommunity *lcommunity_new(void)
      41             : {
      42           0 :         return XCALLOC(MTYPE_LCOMMUNITY, sizeof(struct lcommunity));
      43             : }
      44             : 
      45             : /* Allocate lcommunities.  */
      46           0 : void lcommunity_free(struct lcommunity **lcom)
      47             : {
      48           0 :         if (!(*lcom))
      49             :                 return;
      50             : 
      51           0 :         XFREE(MTYPE_LCOMMUNITY_VAL, (*lcom)->val);
      52           0 :         XFREE(MTYPE_LCOMMUNITY_STR, (*lcom)->str);
      53           0 :         if ((*lcom)->json)
      54           0 :                 json_object_free((*lcom)->json);
      55           0 :         XFREE(MTYPE_LCOMMUNITY, *lcom);
      56             : }
      57             : 
      58           0 : static void lcommunity_hash_free(struct lcommunity *lcom)
      59             : {
      60           0 :         lcommunity_free(&lcom);
      61           0 : }
      62             : 
      63             : /* Add a new Large Communities value to Large Communities
      64             :    Attribute structure.  When the value is already exists in the
      65             :    structure, we don't add the value.  Newly added value is sorted by
      66             :    numerical order.  When the value is added to the structure return 1
      67             :    else return 0.  */
      68           0 : static bool lcommunity_add_val(struct lcommunity *lcom,
      69             :                                struct lcommunity_val *lval)
      70             : {
      71           0 :         uint8_t *p;
      72           0 :         int ret;
      73           0 :         int c;
      74             : 
      75             :         /* When this is fist value, just add it.  */
      76           0 :         if (lcom->val == NULL) {
      77           0 :                 lcom->size++;
      78           0 :                 lcom->val = XMALLOC(MTYPE_LCOMMUNITY_VAL, lcom_length(lcom));
      79           0 :                 memcpy(lcom->val, lval->val, LCOMMUNITY_SIZE);
      80           0 :                 return true;
      81             :         }
      82             : 
      83             :         /* If the value already exists in the structure return 0.  */
      84             :         c = 0;
      85           0 :         for (p = lcom->val; c < lcom->size; p += LCOMMUNITY_SIZE, c++) {
      86           0 :                 ret = memcmp(p, lval->val, LCOMMUNITY_SIZE);
      87           0 :                 if (ret == 0)
      88             :                         return false;
      89           0 :                 if (ret > 0)
      90             :                         break;
      91             :         }
      92             : 
      93             :         /* Add the value to the structure with numerical sorting.  */
      94           0 :         lcom->size++;
      95           0 :         lcom->val =
      96           0 :                 XREALLOC(MTYPE_LCOMMUNITY_VAL, lcom->val, lcom_length(lcom));
      97             : 
      98           0 :         memmove(lcom->val + (c + 1) * LCOMMUNITY_SIZE,
      99           0 :                 lcom->val + c * LCOMMUNITY_SIZE,
     100           0 :                 (lcom->size - 1 - c) * LCOMMUNITY_SIZE);
     101           0 :         memcpy(lcom->val + c * LCOMMUNITY_SIZE, lval->val, LCOMMUNITY_SIZE);
     102             : 
     103           0 :         return true;
     104             : }
     105             : 
     106             : /* This function takes pointer to Large Communites structure then
     107             :    create a new Large Communities structure by uniq and sort each
     108             :    Large Communities value.  */
     109           0 : struct lcommunity *lcommunity_uniq_sort(struct lcommunity *lcom)
     110             : {
     111           0 :         int i;
     112           0 :         struct lcommunity *new;
     113           0 :         struct lcommunity_val *lval;
     114             : 
     115           0 :         if (!lcom)
     116             :                 return NULL;
     117             : 
     118           0 :         new = lcommunity_new();
     119             : 
     120           0 :         for (i = 0; i < lcom->size; i++) {
     121           0 :                 lval = (struct lcommunity_val *)(lcom->val
     122           0 :                                                  + (i * LCOMMUNITY_SIZE));
     123           0 :                 lcommunity_add_val(new, lval);
     124             :         }
     125             :         return new;
     126             : }
     127             : 
     128             : /* Parse Large Communites Attribute in BGP packet.  */
     129           0 : struct lcommunity *lcommunity_parse(uint8_t *pnt, unsigned short length)
     130             : {
     131           0 :         struct lcommunity tmp;
     132           0 :         struct lcommunity *new;
     133             : 
     134             :         /* Length check.  */
     135           0 :         if (length % LCOMMUNITY_SIZE)
     136             :                 return NULL;
     137             : 
     138             :         /* Prepare tmporary structure for making a new Large Communities
     139             :            Attribute.  */
     140           0 :         tmp.size = length / LCOMMUNITY_SIZE;
     141           0 :         tmp.val = pnt;
     142             : 
     143             :         /* Create a new Large Communities Attribute by uniq and sort each
     144             :            Large Communities value  */
     145           0 :         new = lcommunity_uniq_sort(&tmp);
     146             : 
     147           0 :         return lcommunity_intern(new);
     148             : }
     149             : 
     150             : /* Duplicate the Large Communities Attribute structure.  */
     151           0 : struct lcommunity *lcommunity_dup(struct lcommunity *lcom)
     152             : {
     153           0 :         struct lcommunity *new;
     154             : 
     155           0 :         new = lcommunity_new();
     156           0 :         new->size = lcom->size;
     157           0 :         if (new->size) {
     158           0 :                 new->val = XMALLOC(MTYPE_LCOMMUNITY_VAL, lcom_length(lcom));
     159           0 :                 memcpy(new->val, lcom->val, lcom_length(lcom));
     160             :         } else
     161           0 :                 new->val = NULL;
     162           0 :         return new;
     163             : }
     164             : 
     165             : /* Merge two Large Communities Attribute structure.  */
     166           0 : struct lcommunity *lcommunity_merge(struct lcommunity *lcom1,
     167             :                                     struct lcommunity *lcom2)
     168             : {
     169           0 :         lcom1->val = XREALLOC(MTYPE_LCOMMUNITY_VAL, lcom1->val,
     170             :                               lcom_length(lcom1) + lcom_length(lcom2));
     171             : 
     172           0 :         memcpy(lcom1->val + lcom_length(lcom1), lcom2->val, lcom_length(lcom2));
     173           0 :         lcom1->size += lcom2->size;
     174             : 
     175           0 :         return lcom1;
     176             : }
     177             : 
     178           0 : static void set_lcommunity_string(struct lcommunity *lcom, bool make_json,
     179             :                                   bool translate_alias)
     180             : {
     181           0 :         int i;
     182           0 :         int len;
     183           0 :         char *str_buf;
     184           0 :         const uint8_t *pnt;
     185           0 :         uint32_t global, local1, local2;
     186           0 :         json_object *json_lcommunity_list = NULL;
     187           0 :         json_object *json_string = NULL;
     188             : 
     189             :         /* 3 32-bit integers, 2 colons, and a space */
     190             : #define LCOMMUNITY_STRLEN (10 * 3 + 2 + 1)
     191             : 
     192           0 :         if (!lcom)
     193           0 :                 return;
     194             : 
     195           0 :         if (make_json) {
     196           0 :                 lcom->json = json_object_new_object();
     197           0 :                 json_lcommunity_list = json_object_new_array();
     198             :         }
     199             : 
     200           0 :         if (lcom->size == 0) {
     201           0 :                 str_buf = XCALLOC(MTYPE_LCOMMUNITY_STR, 1);
     202             : 
     203           0 :                 if (make_json) {
     204           0 :                         json_object_string_add(lcom->json, "string", "");
     205           0 :                         json_object_object_add(lcom->json, "list",
     206             :                                                json_lcommunity_list);
     207             :                 }
     208             : 
     209           0 :                 lcom->str = str_buf;
     210           0 :                 return;
     211             :         }
     212             : 
     213             :         /* 1 space + lcom->size lcom strings + null terminator */
     214           0 :         size_t str_buf_sz = BUFSIZ;
     215           0 :         str_buf = XCALLOC(MTYPE_LCOMMUNITY_STR, str_buf_sz);
     216             : 
     217           0 :         for (i = 0; i < lcom->size; i++) {
     218           0 :                 if (i > 0)
     219           0 :                         strlcat(str_buf, " ", str_buf_sz);
     220             : 
     221           0 :                 pnt = lcom->val + (i * LCOMMUNITY_SIZE);
     222           0 :                 pnt = ptr_get_be32(pnt, &global);
     223           0 :                 pnt = ptr_get_be32(pnt, &local1);
     224           0 :                 pnt = ptr_get_be32(pnt, &local2);
     225           0 :                 (void)pnt;
     226             : 
     227           0 :                 char lcsb[LCOMMUNITY_STRLEN + 1];
     228             : 
     229           0 :                 snprintf(lcsb, sizeof(lcsb), "%u:%u:%u", global, local1,
     230             :                          local2);
     231             : 
     232           0 :                 const char *com2alias =
     233           0 :                         translate_alias ? bgp_community2alias(lcsb) : lcsb;
     234             : 
     235           0 :                 len = strlcat(str_buf, com2alias, str_buf_sz);
     236           0 :                 assert((unsigned int)len < str_buf_sz);
     237             : 
     238           0 :                 if (make_json) {
     239           0 :                         json_string = json_object_new_string(com2alias);
     240           0 :                         json_object_array_add(json_lcommunity_list,
     241             :                                               json_string);
     242             :                 }
     243             :         }
     244             : 
     245           0 :         if (make_json) {
     246           0 :                 json_object_string_add(lcom->json, "string", str_buf);
     247           0 :                 json_object_object_add(lcom->json, "list",
     248             :                                        json_lcommunity_list);
     249             :         }
     250             : 
     251           0 :         lcom->str = str_buf;
     252             : }
     253             : 
     254             : /* Intern Large Communities Attribute.  */
     255           0 : struct lcommunity *lcommunity_intern(struct lcommunity *lcom)
     256             : {
     257           0 :         struct lcommunity *find;
     258             : 
     259           0 :         assert(lcom->refcnt == 0);
     260             : 
     261           0 :         find = (struct lcommunity *)hash_get(lcomhash, lcom, hash_alloc_intern);
     262             : 
     263           0 :         if (find != lcom)
     264           0 :                 lcommunity_free(&lcom);
     265             : 
     266           0 :         find->refcnt++;
     267             : 
     268           0 :         if (!find->str)
     269           0 :                 set_lcommunity_string(find, false, true);
     270             : 
     271           0 :         return find;
     272             : }
     273             : 
     274             : /* Unintern Large Communities Attribute.  */
     275          41 : void lcommunity_unintern(struct lcommunity **lcom)
     276             : {
     277          41 :         struct lcommunity *ret;
     278             : 
     279          41 :         if (!*lcom)
     280             :                 return;
     281             : 
     282           0 :         if ((*lcom)->refcnt)
     283           0 :                 (*lcom)->refcnt--;
     284             : 
     285             :         /* Pull off from hash.  */
     286           0 :         if ((*lcom)->refcnt == 0) {
     287             :                 /* Large community must be in the hash.  */
     288           0 :                 ret = (struct lcommunity *)hash_release(lcomhash, *lcom);
     289           0 :                 assert(ret != NULL);
     290             : 
     291           0 :                 lcommunity_free(lcom);
     292             :         }
     293             : }
     294             : 
     295             : /* Return string representation of lcommunities attribute. */
     296           0 : char *lcommunity_str(struct lcommunity *lcom, bool make_json,
     297             :                      bool translate_alias)
     298             : {
     299           0 :         if (!lcom)
     300             :                 return NULL;
     301             : 
     302           0 :         if (make_json && !lcom->json && lcom->str)
     303           0 :                 XFREE(MTYPE_LCOMMUNITY_STR, lcom->str);
     304             : 
     305           0 :         if (!lcom->str)
     306           0 :                 set_lcommunity_string(lcom, make_json, translate_alias);
     307             : 
     308           0 :         return lcom->str;
     309             : }
     310             : 
     311             : /* Utility function to make hash key.  */
     312           0 : unsigned int lcommunity_hash_make(const void *arg)
     313             : {
     314           0 :         const struct lcommunity *lcom = arg;
     315           0 :         int size = lcom_length(lcom);
     316             : 
     317           0 :         return jhash(lcom->val, size, 0xab125423);
     318             : }
     319             : 
     320             : /* Compare two Large Communities Attribute structure.  */
     321           0 : bool lcommunity_cmp(const void *arg1, const void *arg2)
     322             : {
     323           0 :         const struct lcommunity *lcom1 = arg1;
     324           0 :         const struct lcommunity *lcom2 = arg2;
     325             : 
     326           0 :         if (lcom1 == NULL && lcom2 == NULL)
     327             :                 return true;
     328             : 
     329           0 :         if (lcom1 == NULL || lcom2 == NULL)
     330             :                 return false;
     331             : 
     332           0 :         return (lcom1->size == lcom2->size
     333           0 :                 && memcmp(lcom1->val, lcom2->val, lcom_length(lcom1)) == 0);
     334             : }
     335             : 
     336             : /* Return communities hash.  */
     337           0 : struct hash *lcommunity_hash(void)
     338             : {
     339           0 :         return lcomhash;
     340             : }
     341             : 
     342             : /* Initialize Large Comminities related hash. */
     343           2 : void lcommunity_init(void)
     344             : {
     345           2 :         lcomhash = hash_create(lcommunity_hash_make, lcommunity_cmp,
     346             :                                "BGP lcommunity hash");
     347           2 : }
     348             : 
     349           2 : void lcommunity_finish(void)
     350             : {
     351           2 :         hash_clean(lcomhash, (void (*)(void *))lcommunity_hash_free);
     352           2 :         hash_free(lcomhash);
     353           2 :         lcomhash = NULL;
     354           2 : }
     355             : 
     356             : /* Get next Large Communities token from the string.
     357             :  * Assumes str is space-delimeted and describes 0 or more
     358             :  * valid large communities
     359             :  */
     360           0 : static const char *lcommunity_gettoken(const char *str,
     361             :                                        struct lcommunity_val *lval)
     362             : {
     363           0 :         const char *p = str;
     364             : 
     365             :         /* Skip white space. */
     366           0 :         while (isspace((unsigned char)*p)) {
     367           0 :                 p++;
     368           0 :                 str++;
     369             :         }
     370             : 
     371             :         /* Check the end of the line. */
     372           0 :         if (*p == '\0')
     373             :                 return NULL;
     374             : 
     375             :         /* Community value. */
     376             :         int separator = 0;
     377             :         int digit = 0;
     378             :         uint32_t globaladmin = 0;
     379             :         uint32_t localdata1 = 0;
     380             :         uint32_t localdata2 = 0;
     381             : 
     382           0 :         while (*p && *p != ' ') {
     383             :                 /* large community valid chars */
     384           0 :                 assert(isdigit((unsigned char)*p) || *p == ':');
     385             : 
     386           0 :                 if (*p == ':') {
     387           0 :                         separator++;
     388           0 :                         digit = 0;
     389           0 :                         if (separator == 1) {
     390           0 :                                 globaladmin = localdata2;
     391             :                         } else {
     392             :                                 localdata1 = localdata2;
     393             :                         }
     394             :                         localdata2 = 0;
     395             :                 } else {
     396           0 :                         digit = 1;
     397             :                         /* left shift the accumulated value and add current
     398             :                          * digit
     399             :                          */
     400           0 :                         localdata2 *= 10;
     401           0 :                         localdata2 += (*p - '0');
     402             :                 }
     403           0 :                 p++;
     404             :         }
     405             : 
     406             :         /* Assert str was a valid large community */
     407           0 :         assert(separator == 2 && digit == 1);
     408             : 
     409             :         /*
     410             :          * Copy the large comm.
     411             :          */
     412           0 :         lval->val[0] = (globaladmin >> 24) & 0xff;
     413           0 :         lval->val[1] = (globaladmin >> 16) & 0xff;
     414           0 :         lval->val[2] = (globaladmin >> 8) & 0xff;
     415           0 :         lval->val[3] = globaladmin & 0xff;
     416           0 :         lval->val[4] = (localdata1 >> 24) & 0xff;
     417           0 :         lval->val[5] = (localdata1 >> 16) & 0xff;
     418           0 :         lval->val[6] = (localdata1 >> 8) & 0xff;
     419           0 :         lval->val[7] = localdata1 & 0xff;
     420           0 :         lval->val[8] = (localdata2 >> 24) & 0xff;
     421           0 :         lval->val[9] = (localdata2 >> 16) & 0xff;
     422           0 :         lval->val[10] = (localdata2 >> 8) & 0xff;
     423           0 :         lval->val[11] = localdata2 & 0xff;
     424             : 
     425           0 :         return p;
     426             : }
     427             : 
     428             : /*
     429             :   Convert string to large community attribute.
     430             :   When type is already known, please specify both str and type.
     431             : 
     432             :   When string includes keyword for each large community value.
     433             :   Please specify keyword_included as non-zero value.
     434             : */
     435           0 : struct lcommunity *lcommunity_str2com(const char *str)
     436             : {
     437           0 :         struct lcommunity *lcom = NULL;
     438           0 :         struct lcommunity_val lval;
     439             : 
     440           0 :         if (!lcommunity_list_valid(str, LARGE_COMMUNITY_LIST_STANDARD))
     441             :                 return NULL;
     442             : 
     443           0 :         do {
     444           0 :                 str = lcommunity_gettoken(str, &lval);
     445           0 :                 if (lcom == NULL)
     446           0 :                         lcom = lcommunity_new();
     447           0 :                 lcommunity_add_val(lcom, &lval);
     448           0 :         } while (str);
     449             : 
     450             :         return lcom;
     451             : }
     452             : 
     453           0 : bool lcommunity_include(struct lcommunity *lcom, uint8_t *ptr)
     454             : {
     455           0 :         int i;
     456           0 :         uint8_t *lcom_ptr;
     457             : 
     458           0 :         for (i = 0; i < lcom->size; i++) {
     459           0 :                 lcom_ptr = lcom->val + (i * LCOMMUNITY_SIZE);
     460           0 :                 if (memcmp(ptr, lcom_ptr, LCOMMUNITY_SIZE) == 0)
     461             :                         return true;
     462             :         }
     463             :         return false;
     464             : }
     465             : 
     466           0 : bool lcommunity_match(const struct lcommunity *lcom1,
     467             :                       const struct lcommunity *lcom2)
     468             : {
     469           0 :         int i = 0;
     470           0 :         int j = 0;
     471             : 
     472           0 :         if (lcom1 == NULL && lcom2 == NULL)
     473             :                 return true;
     474             : 
     475           0 :         if (lcom1 == NULL || lcom2 == NULL)
     476             :                 return false;
     477             : 
     478           0 :         if (lcom1->size < lcom2->size)
     479             :                 return false;
     480             : 
     481             :         /* Every community on com2 needs to be on com1 for this to match */
     482           0 :         while (i < lcom1->size && j < lcom2->size) {
     483           0 :                 if (memcmp(lcom1->val + (i * LCOMMUNITY_SIZE),
     484           0 :                            lcom2->val + (j * LCOMMUNITY_SIZE), LCOMMUNITY_SIZE)
     485             :                     == 0)
     486           0 :                         j++;
     487           0 :                 i++;
     488             :         }
     489             : 
     490           0 :         if (j == lcom2->size)
     491             :                 return true;
     492             :         else
     493           0 :                 return false;
     494             : }
     495             : 
     496             : /* Delete one lcommunity. */
     497           0 : void lcommunity_del_val(struct lcommunity *lcom, uint8_t *ptr)
     498             : {
     499           0 :         int i = 0;
     500           0 :         int c = 0;
     501             : 
     502           0 :         if (!lcom->val)
     503             :                 return;
     504             : 
     505           0 :         while (i < lcom->size) {
     506           0 :                 if (memcmp(lcom->val + i * LCOMMUNITY_SIZE, ptr,
     507             :                            LCOMMUNITY_SIZE)
     508             :                     == 0) {
     509           0 :                         c = lcom->size - i - 1;
     510             : 
     511           0 :                         if (c > 0)
     512           0 :                                 memmove(lcom->val + i * LCOMMUNITY_SIZE,
     513           0 :                                         lcom->val + (i + 1) * LCOMMUNITY_SIZE,
     514           0 :                                         c * LCOMMUNITY_SIZE);
     515             : 
     516           0 :                         lcom->size--;
     517             : 
     518           0 :                         if (lcom->size > 0)
     519           0 :                                 lcom->val =
     520           0 :                                         XREALLOC(MTYPE_LCOMMUNITY_VAL,
     521             :                                                  lcom->val, lcom_length(lcom));
     522             :                         else {
     523           0 :                                 XFREE(MTYPE_LCOMMUNITY_VAL, lcom->val);
     524             :                         }
     525           0 :                         return;
     526             :                 }
     527           0 :                 i++;
     528             :         }
     529             : }
     530             : 
     531           0 : static struct lcommunity *bgp_aggr_lcommunity_lookup(
     532             :                                                 struct bgp_aggregate *aggregate,
     533             :                                                 struct lcommunity *lcommunity)
     534             : {
     535           0 :         return hash_lookup(aggregate->lcommunity_hash, lcommunity);
     536             : }
     537             : 
     538           0 : static void *bgp_aggr_lcommunty_hash_alloc(void *p)
     539             : {
     540           0 :         struct lcommunity *ref = (struct lcommunity *)p;
     541           0 :         struct lcommunity *lcommunity = NULL;
     542             : 
     543           0 :         lcommunity = lcommunity_dup(ref);
     544           0 :         return lcommunity;
     545             : }
     546             : 
     547           0 : static void bgp_aggr_lcommunity_prepare(struct hash_bucket *hb, void *arg)
     548             : {
     549           0 :         struct lcommunity *hb_lcommunity = hb->data;
     550           0 :         struct lcommunity **aggr_lcommunity = arg;
     551             : 
     552           0 :         if (*aggr_lcommunity)
     553           0 :                 *aggr_lcommunity = lcommunity_merge(*aggr_lcommunity,
     554             :                                                     hb_lcommunity);
     555             :         else
     556           0 :                 *aggr_lcommunity = lcommunity_dup(hb_lcommunity);
     557           0 : }
     558             : 
     559           0 : void bgp_aggr_lcommunity_remove(void *arg)
     560             : {
     561           0 :         struct lcommunity *lcommunity = arg;
     562             : 
     563           0 :         lcommunity_free(&lcommunity);
     564           0 : }
     565             : 
     566           0 : void bgp_compute_aggregate_lcommunity(struct bgp_aggregate *aggregate,
     567             :                                       struct lcommunity *lcommunity)
     568             : {
     569             : 
     570           0 :         bgp_compute_aggregate_lcommunity_hash(aggregate, lcommunity);
     571           0 :         bgp_compute_aggregate_lcommunity_val(aggregate);
     572           0 : }
     573             : 
     574           0 : void bgp_compute_aggregate_lcommunity_hash(struct bgp_aggregate *aggregate,
     575             :                                            struct lcommunity *lcommunity)
     576             : {
     577             : 
     578           0 :         struct lcommunity *aggr_lcommunity = NULL;
     579             : 
     580           0 :         if ((aggregate == NULL) || (lcommunity == NULL))
     581             :                 return;
     582             : 
     583             :         /* Create hash if not already created.
     584             :          */
     585           0 :         if (aggregate->lcommunity_hash == NULL)
     586           0 :                 aggregate->lcommunity_hash = hash_create(
     587             :                                         lcommunity_hash_make, lcommunity_cmp,
     588             :                                         "BGP Aggregator lcommunity hash");
     589             : 
     590           0 :         aggr_lcommunity = bgp_aggr_lcommunity_lookup(aggregate, lcommunity);
     591           0 :         if (aggr_lcommunity == NULL) {
     592             :                 /* Insert lcommunity into hash.
     593             :                  */
     594           0 :                 aggr_lcommunity = hash_get(aggregate->lcommunity_hash,
     595             :                                            lcommunity,
     596             :                                            bgp_aggr_lcommunty_hash_alloc);
     597             :         }
     598             : 
     599             :         /* Increment reference counter.
     600             :          */
     601           0 :         aggr_lcommunity->refcnt++;
     602             : }
     603             : 
     604           0 : void bgp_compute_aggregate_lcommunity_val(struct bgp_aggregate *aggregate)
     605             : {
     606           0 :         struct lcommunity *lcommerge = NULL;
     607             : 
     608           0 :         if (aggregate == NULL)
     609           0 :                 return;
     610             : 
     611             :         /* Re-compute aggregate's lcommunity.
     612             :          */
     613           0 :         if (aggregate->lcommunity)
     614           0 :                 lcommunity_free(&aggregate->lcommunity);
     615           0 :         if (aggregate->lcommunity_hash &&
     616           0 :             aggregate->lcommunity_hash->count) {
     617           0 :                 hash_iterate(aggregate->lcommunity_hash,
     618             :                              bgp_aggr_lcommunity_prepare,
     619           0 :                              &aggregate->lcommunity);
     620           0 :                 lcommerge = aggregate->lcommunity;
     621           0 :                 aggregate->lcommunity = lcommunity_uniq_sort(lcommerge);
     622           0 :                 if (lcommerge)
     623           0 :                         lcommunity_free(&lcommerge);
     624             :         }
     625             : }
     626             : 
     627           0 : void bgp_remove_lcommunity_from_aggregate(struct bgp_aggregate *aggregate,
     628             :                                           struct lcommunity *lcommunity)
     629             : {
     630           0 :         struct lcommunity *aggr_lcommunity = NULL;
     631           0 :         struct lcommunity *ret_lcomm = NULL;
     632             : 
     633           0 :         if ((!aggregate)
     634           0 :             || (!aggregate->lcommunity_hash)
     635           0 :             || (!lcommunity))
     636           0 :                 return;
     637             : 
     638             :         /* Look-up the lcommunity in the hash.
     639             :          */
     640           0 :         aggr_lcommunity = bgp_aggr_lcommunity_lookup(aggregate, lcommunity);
     641           0 :         if (aggr_lcommunity) {
     642           0 :                 aggr_lcommunity->refcnt--;
     643             : 
     644           0 :                 if (aggr_lcommunity->refcnt == 0) {
     645           0 :                         ret_lcomm = hash_release(aggregate->lcommunity_hash,
     646             :                                                  aggr_lcommunity);
     647           0 :                         lcommunity_free(&ret_lcomm);
     648             : 
     649           0 :                         bgp_compute_aggregate_lcommunity_val(aggregate);
     650             : 
     651             :                 }
     652             :         }
     653             : }
     654             : 
     655           0 : void bgp_remove_lcomm_from_aggregate_hash(struct bgp_aggregate *aggregate,
     656             :                                           struct lcommunity *lcommunity)
     657             : {
     658           0 :         struct lcommunity *aggr_lcommunity = NULL;
     659           0 :         struct lcommunity *ret_lcomm = NULL;
     660             : 
     661           0 :         if ((!aggregate)
     662           0 :             || (!aggregate->lcommunity_hash)
     663           0 :             || (!lcommunity))
     664           0 :                 return;
     665             : 
     666             :         /* Look-up the lcommunity in the hash.
     667             :          */
     668           0 :         aggr_lcommunity = bgp_aggr_lcommunity_lookup(aggregate, lcommunity);
     669           0 :         if (aggr_lcommunity) {
     670           0 :                 aggr_lcommunity->refcnt--;
     671             : 
     672           0 :                 if (aggr_lcommunity->refcnt == 0) {
     673           0 :                         ret_lcomm = hash_release(aggregate->lcommunity_hash,
     674             :                                                  aggr_lcommunity);
     675           0 :                         lcommunity_free(&ret_lcomm);
     676             :                 }
     677             :         }
     678             : }

Generated by: LCOV version v1.16-topotato