LCOV - code coverage report
Current view: top level - bgpd - bgp_ecommunity.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 222 325 68.3 %
Date: 2015-11-19 Functions: 14 18 77.8 %

          Line data    Source code
       1             : /* BGP Extended Communities Attribute
       2             :    Copyright (C) 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
       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
      17             : along with GNU Zebra; see the file COPYING.  If not, write to the Free
      18             : Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
      19             : 02111-1307, USA.  */
      20             : 
      21             : #include <zebra.h>
      22             : 
      23             : #include "hash.h"
      24             : #include "memory.h"
      25             : #include "prefix.h"
      26             : #include "command.h"
      27             : 
      28             : #include "bgpd/bgpd.h"
      29             : #include "bgpd/bgp_ecommunity.h"
      30             : #include "bgpd/bgp_aspath.h"
      31             : 
      32             : /* Hash of community attribute. */
      33             : static struct hash *ecomhash;
      34             : 
      35             : /* Allocate a new ecommunities.  */
      36             : static struct ecommunity *
      37           8 : ecommunity_new (void)
      38             : {
      39           8 :   return (struct ecommunity *) XCALLOC (MTYPE_ECOMMUNITY,
      40             :                                         sizeof (struct ecommunity));
      41             : }
      42             : 
      43             : /* Allocate ecommunities.  */
      44             : void
      45           8 : ecommunity_free (struct ecommunity **ecom)
      46             : {
      47           8 :   if ((*ecom)->val)
      48           8 :     XFREE (MTYPE_ECOMMUNITY_VAL, (*ecom)->val);
      49           8 :   if ((*ecom)->str)
      50           4 :     XFREE (MTYPE_ECOMMUNITY_STR, (*ecom)->str);
      51           8 :   XFREE (MTYPE_ECOMMUNITY, *ecom);
      52           8 :   ecom = NULL;
      53           8 : }
      54             : 
      55             : /* Add a new Extended Communities value to Extended Communities
      56             :    Attribute structure.  When the value is already exists in the
      57             :    structure, we don't add the value.  Newly added value is sorted by
      58             :    numerical order.  When the value is added to the structure return 1
      59             :    else return 0.  */
      60             : static int
      61           8 : ecommunity_add_val (struct ecommunity *ecom, struct ecommunity_val *eval)
      62             : {
      63             :   u_int8_t *p;
      64             :   int ret;
      65             :   int c;
      66             : 
      67             :   /* When this is fist value, just add it.  */
      68           8 :   if (ecom->val == NULL)
      69             :     {
      70           8 :       ecom->size++;
      71           8 :       ecom->val = XMALLOC (MTYPE_ECOMMUNITY_VAL, ecom_length (ecom));
      72           8 :       memcpy (ecom->val, eval->val, ECOMMUNITY_SIZE);
      73           8 :       return 1;
      74             :     }
      75             : 
      76             :   /* If the value already exists in the structure return 0.  */
      77           0 :   c = 0;
      78           0 :   for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++)
      79             :     {
      80           0 :       ret = memcmp (p, eval->val, ECOMMUNITY_SIZE);
      81           0 :       if (ret == 0)
      82           0 :         return 0;
      83           0 :       if (ret > 0)
      84           0 :         break;
      85             :     }
      86             : 
      87             :   /* Add the value to the structure with numerical sorting.  */
      88           0 :   ecom->size++;
      89           0 :   ecom->val = XREALLOC (MTYPE_ECOMMUNITY_VAL, ecom->val, ecom_length (ecom));
      90             : 
      91           0 :   memmove (ecom->val + (c + 1) * ECOMMUNITY_SIZE,
      92           0 :            ecom->val + c * ECOMMUNITY_SIZE,
      93           0 :            (ecom->size - 1 - c) * ECOMMUNITY_SIZE);
      94           0 :   memcpy (ecom->val + c * ECOMMUNITY_SIZE, eval->val, ECOMMUNITY_SIZE);
      95             : 
      96           0 :   return 1;
      97             : }
      98             : 
      99             : /* This function takes pointer to Extended Communites strucutre then
     100             :    create a new Extended Communities structure by uniq and sort each
     101             :    Extended Communities value.  */
     102             : struct ecommunity *
     103           4 : ecommunity_uniq_sort (struct ecommunity *ecom)
     104             : {
     105             :   int i;
     106             :   struct ecommunity *new;
     107             :   struct ecommunity_val *eval;
     108             :   
     109           4 :   if (! ecom)
     110           0 :     return NULL;
     111             :   
     112           4 :   new = ecommunity_new ();
     113             :   
     114           8 :   for (i = 0; i < ecom->size; i++)
     115             :     {
     116           4 :       eval = (struct ecommunity_val *) (ecom->val + (i * ECOMMUNITY_SIZE));
     117           4 :       ecommunity_add_val (new, eval);
     118             :     }
     119           4 :   return new;
     120             : }
     121             : 
     122             : /* Parse Extended Communites Attribute in BGP packet.  */
     123             : struct ecommunity *
     124           4 : ecommunity_parse (u_int8_t *pnt, u_short length)
     125             : {
     126             :   struct ecommunity tmp;
     127             :   struct ecommunity *new;
     128             : 
     129             :   /* Length check.  */
     130           4 :   if (length % ECOMMUNITY_SIZE)
     131           0 :     return NULL;
     132             : 
     133             :   /* Prepare tmporary structure for making a new Extended Communities
     134             :      Attribute.  */
     135           4 :   tmp.size = length / ECOMMUNITY_SIZE;
     136           4 :   tmp.val = pnt;
     137             : 
     138             :   /* Create a new Extended Communities Attribute by uniq and sort each
     139             :      Extended Communities value  */
     140           4 :   new = ecommunity_uniq_sort (&tmp);
     141             : 
     142           4 :   return ecommunity_intern (new);
     143             : }
     144             : 
     145             : /* Duplicate the Extended Communities Attribute structure.  */
     146             : struct ecommunity *
     147           0 : ecommunity_dup (struct ecommunity *ecom)
     148             : {
     149             :   struct ecommunity *new;
     150             : 
     151           0 :   new = XCALLOC (MTYPE_ECOMMUNITY, sizeof (struct ecommunity));
     152           0 :   new->size = ecom->size;
     153           0 :   if (new->size)
     154             :     {
     155           0 :       new->val = XMALLOC (MTYPE_ECOMMUNITY_VAL, ecom->size * ECOMMUNITY_SIZE);
     156           0 :       memcpy (new->val, ecom->val, ecom->size * ECOMMUNITY_SIZE);
     157             :     }
     158             :   else
     159           0 :     new->val = NULL;
     160           0 :   return new;
     161             : }
     162             : 
     163             : /* Retrun string representation of communities attribute. */
     164             : char *
     165           8 : ecommunity_str (struct ecommunity *ecom)
     166             : {
     167           8 :   if (! ecom->str)
     168           0 :     ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY);
     169           8 :   return ecom->str;
     170             : }
     171             : 
     172             : /* Merge two Extended Communities Attribute structure.  */
     173             : struct ecommunity *
     174           0 : ecommunity_merge (struct ecommunity *ecom1, struct ecommunity *ecom2)
     175             : {
     176           0 :   if (ecom1->val)
     177           0 :     ecom1->val = XREALLOC (MTYPE_ECOMMUNITY_VAL, ecom1->val, 
     178             :                            (ecom1->size + ecom2->size) * ECOMMUNITY_SIZE);
     179             :   else
     180           0 :     ecom1->val = XMALLOC (MTYPE_ECOMMUNITY_VAL,
     181             :                           (ecom1->size + ecom2->size) * ECOMMUNITY_SIZE);
     182             : 
     183           0 :   memcpy (ecom1->val + (ecom1->size * ECOMMUNITY_SIZE),
     184           0 :           ecom2->val, ecom2->size * ECOMMUNITY_SIZE);
     185           0 :   ecom1->size += ecom2->size;
     186             : 
     187           0 :   return ecom1;
     188             : }
     189             : 
     190             : /* Intern Extended Communities Attribute.  */
     191             : struct ecommunity *
     192           4 : ecommunity_intern (struct ecommunity *ecom)
     193             : {
     194             :   struct ecommunity *find;
     195             : 
     196           4 :   assert (ecom->refcnt == 0);
     197             : 
     198           4 :   find = (struct ecommunity *) hash_get (ecomhash, ecom, hash_alloc_intern);
     199             : 
     200           4 :   if (find != ecom)
     201           0 :     ecommunity_free (&ecom);
     202             : 
     203           4 :   find->refcnt++;
     204             : 
     205           4 :   if (! find->str)
     206           4 :     find->str = ecommunity_ecom2str (find, ECOMMUNITY_FORMAT_DISPLAY);
     207             : 
     208           4 :   return find;
     209             : }
     210             : 
     211             : /* Unintern Extended Communities Attribute.  */
     212             : void
     213           4 : ecommunity_unintern (struct ecommunity **ecom)
     214             : {
     215             :   struct ecommunity *ret;
     216             : 
     217           4 :   if ((*ecom)->refcnt)
     218           4 :     (*ecom)->refcnt--;
     219             :     
     220             :   /* Pull off from hash.  */
     221           4 :   if ((*ecom)->refcnt == 0)
     222             :     {
     223             :       /* Extended community must be in the hash.  */
     224           4 :       ret = (struct ecommunity *) hash_release (ecomhash, *ecom);
     225           4 :       assert (ret != NULL);
     226             : 
     227           4 :       ecommunity_free (ecom);
     228             :     }
     229           4 : }
     230             : 
     231             : /* Utinity function to make hash key.  */
     232             : unsigned int
     233           8 : ecommunity_hash_make (void *arg)
     234             : {
     235           8 :   const struct ecommunity *ecom = arg;
     236           8 :   int size = ecom->size * ECOMMUNITY_SIZE;
     237           8 :   u_int8_t *pnt = ecom->val;
     238           8 :   unsigned int key = 0;
     239             :   int c;
     240             : 
     241          16 :   for (c = 0; c < size; c += ECOMMUNITY_SIZE)
     242             :     {
     243           8 :       key += pnt[c];
     244           8 :       key += pnt[c + 1];
     245           8 :       key += pnt[c + 2];
     246           8 :       key += pnt[c + 3];
     247           8 :       key += pnt[c + 4];
     248           8 :       key += pnt[c + 5];
     249           8 :       key += pnt[c + 6];
     250           8 :       key += pnt[c + 7];
     251             :     }
     252             : 
     253           8 :   return key;
     254             : }
     255             : 
     256             : /* Compare two Extended Communities Attribute structure.  */
     257             : int
     258           4 : ecommunity_cmp (const void *arg1, const void *arg2)
     259             : {
     260           4 :   const struct ecommunity *ecom1 = arg1;
     261           4 :   const struct ecommunity *ecom2 = arg2;
     262             :   
     263           8 :   return (ecom1->size == ecom2->size
     264           4 :           && memcmp (ecom1->val, ecom2->val, ecom1->size * ECOMMUNITY_SIZE) == 0);
     265             : }
     266             : 
     267             : /* Initialize Extended Comminities related hash. */
     268             : void
     269           2 : ecommunity_init (void)
     270             : {
     271           2 :   ecomhash = hash_create (ecommunity_hash_make, ecommunity_cmp);
     272           2 : }
     273             : 
     274             : void
     275           0 : ecommunity_finish (void)
     276             : {
     277           0 :   hash_free (ecomhash);
     278           0 :   ecomhash = NULL;
     279           0 : }
     280             : 
     281             : /* Extended Communities token enum. */
     282             : enum ecommunity_token
     283             : {
     284             :   ecommunity_token_rt,
     285             :   ecommunity_token_soo,
     286             :   ecommunity_token_val,
     287             :   ecommunity_token_unknown
     288             : };
     289             : 
     290             : /* Get next Extended Communities token from the string. */
     291             : static const char *
     292          12 : ecommunity_gettoken (const char *str, struct ecommunity_val *eval,
     293             :                      enum ecommunity_token *token)
     294             : {
     295             :   int ret;
     296          12 :   int dot = 0;
     297          12 :   int digit = 0;
     298          12 :   int separator = 0;
     299          12 :   const char *p = str;
     300             :   char *endptr;
     301             :   struct in_addr ip;
     302          12 :   as_t as = 0;
     303          12 :   u_int32_t val = 0;
     304             :   char buf[INET_ADDRSTRLEN + 1];
     305             : 
     306             :   /* Skip white space. */
     307          28 :   while (isspace ((int) *p))
     308             :     {
     309           4 :       p++;
     310           4 :       str++;
     311             :     }
     312             : 
     313             :   /* Check the end of the line. */
     314          12 :   if (*p == '\0')
     315           4 :     return NULL;
     316             : 
     317             :   /* "rt" and "soo" keyword parse. */
     318           8 :   if (! isdigit ((int) *p)) 
     319             :     {
     320             :       /* "rt" match check.  */
     321           4 :       if (tolower ((int) *p) == 'r')
     322             :         {
     323           1 :           p++;
     324           1 :           if (tolower ((int) *p) == 't')
     325             :             {
     326           1 :               p++;
     327           1 :               *token = ecommunity_token_rt;
     328           1 :               return p;
     329             :             }
     330           0 :           if (isspace ((int) *p) || *p == '\0')
     331             :             {
     332           0 :               *token = ecommunity_token_rt;
     333           0 :               return p;
     334             :             }
     335           0 :           goto error;
     336             :         }
     337             :       /* "soo" match check.  */
     338           3 :       else if (tolower ((int) *p) == 's')
     339             :         {
     340           3 :           p++;
     341           3 :           if (tolower ((int) *p) == 'o')
     342             :             {
     343           3 :               p++;
     344           3 :               if (tolower ((int) *p) == 'o')
     345             :                 {
     346           3 :                   p++;
     347           3 :                   *token = ecommunity_token_soo;
     348           3 :                   return p;
     349             :                 }
     350           0 :               if (isspace ((int) *p) || *p == '\0')
     351             :                 {
     352           0 :                   *token = ecommunity_token_soo;
     353           0 :                   return p;
     354             :                 }
     355           0 :               goto error;
     356             :             }
     357           0 :           if (isspace ((int) *p) || *p == '\0')
     358             :             {
     359           0 :               *token = ecommunity_token_soo;
     360           0 :               return p;
     361             :             }
     362           0 :           goto error;
     363             :         }
     364           0 :       goto error;
     365             :     }
     366             :   
     367             :   /* What a mess, there are several possibilities:
     368             :    *
     369             :    * a) A.B.C.D:MN
     370             :    * b) EF:OPQR
     371             :    * c) GHJK:MN
     372             :    *
     373             :    * A.B.C.D: Four Byte IP
     374             :    * EF:      Two byte ASN
     375             :    * GHJK:    Four-byte ASN
     376             :    * MN:      Two byte value
     377             :    * OPQR:    Four byte value
     378             :    *
     379             :    */
     380          59 :   while (isdigit ((int) *p) || *p == ':' || *p == '.') 
     381             :     {
     382          51 :       if (*p == ':')
     383             :         {
     384           4 :           if (separator)
     385           0 :             goto error;
     386             : 
     387           4 :           separator = 1;
     388           4 :           digit = 0;
     389             :           
     390           4 :           if ((p - str) > INET_ADDRSTRLEN)
     391           0 :             goto error;
     392           4 :           memset (buf, 0, INET_ADDRSTRLEN + 1);
     393           4 :           memcpy (buf, str, p - str);
     394             :           
     395           4 :           if (dot)
     396             :             {
     397             :               /* Parsing A.B.C.D in:
     398             :                * A.B.C.D:MN
     399             :                */
     400           2 :               ret = inet_aton (buf, &ip);
     401           2 :               if (ret == 0)
     402           0 :                 goto error;
     403             :             }
     404             :           else
     405             :             {
     406             :               /* ASN */
     407           2 :               as = strtoul (buf, &endptr, 10);
     408           2 :               if (*endptr != '\0' || as == BGP_AS4_MAX)
     409             :                 goto error;
     410             :             }
     411             :         }
     412          47 :       else if (*p == '.')
     413             :         {
     414           6 :           if (separator)
     415           0 :             goto error;
     416           6 :           dot++;
     417           6 :           if (dot > 4)
     418           0 :             goto error;
     419             :         }
     420             :       else
     421             :         {
     422          41 :           digit = 1;
     423             :           
     424             :           /* We're past the IP/ASN part */
     425          41 :           if (separator)
     426             :             {
     427          19 :               val *= 10;
     428          19 :               val += (*p - '0');
     429             :             }
     430             :         }
     431          51 :       p++;
     432             :     }
     433             : 
     434             :   /* Low digit part must be there. */
     435           4 :   if (!digit || !separator)
     436             :     goto error;
     437             : 
     438             :   /* Encode result into routing distinguisher.  */
     439           4 :   if (dot)
     440             :     {
     441           2 :       if (val > UINT16_MAX)
     442           0 :         goto error;
     443             :       
     444           2 :       eval->val[0] = ECOMMUNITY_ENCODE_IP;
     445           2 :       eval->val[1] = 0;
     446           2 :       memcpy (&eval->val[2], &ip, sizeof (struct in_addr));
     447           2 :       eval->val[6] = (val >> 8) & 0xff;
     448           2 :       eval->val[7] = val & 0xff;
     449             :     }
     450           2 :   else if (as > BGP_AS_MAX)
     451             :     {
     452           1 :       if (val > UINT16_MAX)
     453           0 :         goto error;
     454             :       
     455           1 :       eval->val[0] = ECOMMUNITY_ENCODE_AS4;
     456           1 :       eval->val[1] = 0;
     457           1 :       eval->val[2] = (as >>24) & 0xff;
     458           1 :       eval->val[3] = (as >>16) & 0xff;
     459           1 :       eval->val[4] = (as >>8) & 0xff;
     460           1 :       eval->val[5] =  as & 0xff;
     461           1 :       eval->val[6] = (val >> 8) & 0xff;
     462           1 :       eval->val[7] = val & 0xff;
     463             :     }
     464             :   else
     465             :     {
     466           1 :       eval->val[0] = ECOMMUNITY_ENCODE_AS;
     467           1 :       eval->val[1] = 0;
     468             :       
     469           1 :       eval->val[2] = (as >>8) & 0xff;
     470           1 :       eval->val[3] = as & 0xff;
     471           1 :       eval->val[4] = (val >>24) & 0xff;
     472           1 :       eval->val[5] = (val >>16) & 0xff;
     473           1 :       eval->val[6] = (val >>8) & 0xff;
     474           1 :       eval->val[7] = val & 0xff;
     475             :     }
     476           4 :   *token = ecommunity_token_val;
     477           4 :   return p;
     478             : 
     479             :  error:
     480           0 :   *token = ecommunity_token_unknown;
     481           0 :   return p;
     482             : }
     483             : 
     484             : /* Convert string to extended community attribute. 
     485             : 
     486             :    When type is already known, please specify both str and type.  str
     487             :    should not include keyword such as "rt" and "soo".  Type is
     488             :    ECOMMUNITY_ROUTE_TARGET or ECOMMUNITY_SITE_ORIGIN.
     489             :    keyword_included should be zero.
     490             : 
     491             :    For example route-map's "set extcommunity" command case:
     492             : 
     493             :    "rt 100:1 100:2 100:3"        -> str = "100:1 100:2 100:3"
     494             :                                     type = ECOMMUNITY_ROUTE_TARGET
     495             :                                     keyword_included = 0
     496             : 
     497             :    "soo 100:1"                   -> str = "100:1"
     498             :                                     type = ECOMMUNITY_SITE_ORIGIN
     499             :                                     keyword_included = 0
     500             : 
     501             :    When string includes keyword for each extended community value.
     502             :    Please specify keyword_included as non-zero value.
     503             : 
     504             :    For example standard extcommunity-list case:
     505             : 
     506             :    "rt 100:1 rt 100:2 soo 100:1" -> str = "rt 100:1 rt 100:2 soo 100:1"
     507             :                                     type = 0
     508             :                                     keyword_include = 1
     509             : */
     510             : struct ecommunity *
     511           4 : ecommunity_str2com (const char *str, int type, int keyword_included)
     512             : {
     513           4 :   struct ecommunity *ecom = NULL;
     514             :   enum ecommunity_token token;
     515             :   struct ecommunity_val eval;
     516           4 :   int keyword = 0;
     517             : 
     518          16 :   while ((str = ecommunity_gettoken (str, &eval, &token)))
     519             :     {
     520           8 :       switch (token)
     521             :         {
     522             :         case ecommunity_token_rt:
     523             :         case ecommunity_token_soo:
     524           4 :           if (! keyword_included || keyword)
     525             :             {
     526           0 :               if (ecom)
     527           0 :                 ecommunity_free (&ecom);
     528           0 :               return NULL;
     529             :             }
     530           4 :           keyword = 1;
     531             : 
     532           4 :           if (token == ecommunity_token_rt)
     533             :             {
     534           1 :               type = ECOMMUNITY_ROUTE_TARGET;
     535             :             }
     536           4 :           if (token == ecommunity_token_soo)
     537             :             {
     538           3 :               type = ECOMMUNITY_SITE_ORIGIN;
     539             :             }
     540           4 :           break;
     541             :         case ecommunity_token_val:
     542           4 :           if (keyword_included)
     543             :             {
     544           4 :               if (! keyword)
     545             :                 {
     546           0 :                   if (ecom)
     547           0 :                     ecommunity_free (&ecom);
     548           0 :                   return NULL;
     549             :                 }
     550           4 :               keyword = 0;
     551             :             }
     552           4 :           if (ecom == NULL)
     553           4 :             ecom = ecommunity_new ();
     554           4 :           eval.val[1] = type;
     555           4 :           ecommunity_add_val (ecom, &eval);
     556           4 :           break;
     557             :         case ecommunity_token_unknown:
     558             :         default:
     559           0 :           if (ecom)
     560           0 :             ecommunity_free (&ecom);
     561           0 :           return NULL;
     562             :         }
     563             :     }
     564           4 :   return ecom;
     565             : }
     566             : 
     567             : /* Convert extended community attribute to string.  
     568             : 
     569             :    Due to historical reason of industry standard implementation, there
     570             :    are three types of format.
     571             : 
     572             :    route-map set extcommunity format
     573             :         "rt 100:1 100:2"
     574             :         "soo 100:3"
     575             : 
     576             :    extcommunity-list
     577             :         "rt 100:1 rt 100:2 soo 100:3"
     578             : 
     579             :    "show ip bgp" and extcommunity-list regular expression matching
     580             :         "RT:100:1 RT:100:2 SoO:100:3"
     581             : 
     582             :    For each formath please use below definition for format:
     583             : 
     584             :    ECOMMUNITY_FORMAT_ROUTE_MAP
     585             :    ECOMMUNITY_FORMAT_COMMUNITY_LIST
     586             :    ECOMMUNITY_FORMAT_DISPLAY
     587             : */
     588             : char *
     589          12 : ecommunity_ecom2str (struct ecommunity *ecom, int format)
     590             : {
     591             :   int i;
     592             :   u_int8_t *pnt;
     593          12 :   int encode = 0;
     594          12 :   int type = 0;
     595             : #define ECOMMUNITY_STR_DEFAULT_LEN  27
     596             :   int str_size;
     597             :   int str_pnt;
     598             :   char *str_buf;
     599             :   const char *prefix;
     600          12 :   int len = 0;
     601          12 :   int first = 1;
     602             : 
     603             :   /* For parse Extended Community attribute tupple. */
     604             :   struct ecommunity_as
     605             :   {
     606             :     as_t as;
     607             :     u_int32_t val;
     608             :   } eas;
     609             : 
     610             :   struct ecommunity_ip
     611             :   {
     612             :     struct in_addr ip;
     613             :     u_int16_t val;
     614             :   } eip;
     615             : 
     616          12 :   if (ecom->size == 0)
     617             :     {
     618           0 :       str_buf = XMALLOC (MTYPE_ECOMMUNITY_STR, 1);
     619           0 :       str_buf[0] = '\0';
     620           0 :       return str_buf;
     621             :     }
     622             : 
     623             :   /* Prepare buffer.  */
     624          12 :   str_buf = XMALLOC (MTYPE_ECOMMUNITY_STR, ECOMMUNITY_STR_DEFAULT_LEN + 1);
     625          12 :   str_size = ECOMMUNITY_STR_DEFAULT_LEN + 1;
     626          12 :   str_pnt = 0;
     627             : 
     628          24 :   for (i = 0; i < ecom->size; i++)
     629             :     {
     630             :       /* Make it sure size is enough.  */
     631          24 :       while (str_pnt + ECOMMUNITY_STR_DEFAULT_LEN >= str_size)
     632             :         {
     633           0 :           str_size *= 2;
     634           0 :           str_buf = XREALLOC (MTYPE_ECOMMUNITY_STR, str_buf, str_size);
     635             :         }
     636             : 
     637             :       /* Space between each value.  */
     638          12 :       if (! first)
     639           0 :         str_buf[str_pnt++] = ' ';
     640             : 
     641          12 :       pnt = ecom->val + (i * 8);
     642             : 
     643             :       /* High-order octet of type. */
     644          12 :       encode = *pnt++;
     645          12 :       if (encode != ECOMMUNITY_ENCODE_AS && encode != ECOMMUNITY_ENCODE_IP
     646           3 :                       && encode != ECOMMUNITY_ENCODE_AS4)
     647             :         {
     648           0 :           len = sprintf (str_buf + str_pnt, "?");
     649           0 :           str_pnt += len;
     650           0 :           first = 0;
     651           0 :           continue;
     652             :         }
     653             :       
     654             :       /* Low-order octet of type. */
     655          12 :       type = *pnt++;
     656          12 :       if (type !=  ECOMMUNITY_ROUTE_TARGET && type != ECOMMUNITY_SITE_ORIGIN)
     657             :         {
     658           0 :           len = sprintf (str_buf + str_pnt, "?");
     659           0 :           str_pnt += len;
     660           0 :           first = 0;
     661           0 :           continue;
     662             :         }
     663             : 
     664          12 :       switch (format)
     665             :         {
     666             :         case ECOMMUNITY_FORMAT_COMMUNITY_LIST:
     667           8 :           prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "rt " : "soo ");
     668           8 :           break;
     669             :         case ECOMMUNITY_FORMAT_DISPLAY:
     670           4 :           prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "RT:" : "SoO:");
     671           4 :           break;
     672             :         case ECOMMUNITY_FORMAT_ROUTE_MAP:
     673           0 :           prefix = "";
     674           0 :           break;
     675             :         default:
     676           0 :           prefix = "";
     677           0 :           break;
     678             :         }
     679             : 
     680             :       /* Put string into buffer.  */
     681          12 :       if (encode == ECOMMUNITY_ENCODE_AS4)
     682             :         {
     683           3 :           eas.as = (*pnt++ << 24);
     684           3 :           eas.as |= (*pnt++ << 16);
     685           3 :           eas.as |= (*pnt++ << 8);
     686           3 :           eas.as |= (*pnt++);
     687             : 
     688           3 :           eas.val = (*pnt++ << 8);
     689           3 :           eas.val |= (*pnt++);
     690             : 
     691           3 :           len = sprintf( str_buf + str_pnt, "%s%u:%d", prefix,
     692             :                         eas.as, eas.val );
     693           3 :           str_pnt += len;
     694           3 :           first = 0;
     695             :         }
     696          12 :       if (encode == ECOMMUNITY_ENCODE_AS)
     697             :         {
     698           3 :           eas.as = (*pnt++ << 8);
     699           3 :           eas.as |= (*pnt++);
     700             : 
     701           3 :           eas.val = (*pnt++ << 24);
     702           3 :           eas.val |= (*pnt++ << 16);
     703           3 :           eas.val |= (*pnt++ << 8);
     704           3 :           eas.val |= (*pnt++);
     705             : 
     706           3 :           len = sprintf (str_buf + str_pnt, "%s%u:%d", prefix,
     707             :                          eas.as, eas.val);
     708           3 :           str_pnt += len;
     709           3 :           first = 0;
     710             :         }
     711           9 :       else if (encode == ECOMMUNITY_ENCODE_IP)
     712             :         {
     713           6 :           memcpy (&eip.ip, pnt, 4);
     714           6 :           pnt += 4;
     715           6 :           eip.val = (*pnt++ << 8);
     716           6 :           eip.val |= (*pnt++);
     717             : 
     718           6 :           len = sprintf (str_buf + str_pnt, "%s%s:%d", prefix,
     719           6 :                          inet_ntoa (eip.ip), eip.val);
     720           6 :           str_pnt += len;
     721           6 :           first = 0;
     722             :         }
     723             :     }
     724          12 :   return str_buf;
     725             : }
     726             : 
     727             : int
     728           0 : ecommunity_match (const struct ecommunity *ecom1, 
     729             :                   const struct ecommunity *ecom2)
     730             : {
     731           0 :   int i = 0;
     732           0 :   int j = 0;
     733             : 
     734           0 :   if (ecom1 == NULL && ecom2 == NULL)
     735           0 :     return 1;
     736             : 
     737           0 :   if (ecom1 == NULL || ecom2 == NULL)
     738           0 :     return 0;
     739             : 
     740           0 :   if (ecom1->size < ecom2->size)
     741           0 :     return 0;
     742             : 
     743             :   /* Every community on com2 needs to be on com1 for this to match */
     744           0 :   while (i < ecom1->size && j < ecom2->size)
     745             :     {
     746           0 :       if (memcmp (ecom1->val + i, ecom2->val + j, ECOMMUNITY_SIZE) == 0)
     747           0 :         j++;
     748           0 :       i++;
     749             :     }
     750             : 
     751           0 :   if (j == ecom2->size)
     752           0 :     return 1;
     753             :   else
     754           0 :     return 0;
     755             : }
     756             : 

Generated by: LCOV version 1.10