Annotation of embedaddon/quagga/bgpd/bgp_ecommunity.c, revision 1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>