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

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.  */
1.1.1.2   misho     102: struct ecommunity *
1.1       misho     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;
1.1.1.3 ! misho     236:   int size = ecom->size * ECOMMUNITY_SIZE;
        !           237:   u_int8_t *pnt = ecom->val;
        !           238:   unsigned int key = 0;
1.1       misho     239:   int c;
                    240: 
1.1.1.3 ! misho     241:   for (c = 0; c < size; c += ECOMMUNITY_SIZE)
        !           242:     {
        !           243:       key += pnt[c];
        !           244:       key += pnt[c + 1];
        !           245:       key += pnt[c + 2];
        !           246:       key += pnt[c + 3];
        !           247:       key += pnt[c + 4];
        !           248:       key += pnt[c + 5];
        !           249:       key += pnt[c + 6];
        !           250:       key += pnt[c + 7];
        !           251:     }
1.1       misho     252: 
                    253:   return key;
                    254: }
                    255: 
                    256: /* Compare two Extended Communities Attribute structure.  */
                    257: int
                    258: ecommunity_cmp (const void *arg1, const void *arg2)
                    259: {
                    260:   const struct ecommunity *ecom1 = arg1;
                    261:   const struct ecommunity *ecom2 = arg2;
                    262:   
                    263:   return (ecom1->size == ecom2->size
                    264:          && memcmp (ecom1->val, ecom2->val, ecom1->size * ECOMMUNITY_SIZE) == 0);
                    265: }
                    266: 
                    267: /* Initialize Extended Comminities related hash. */
                    268: void
                    269: ecommunity_init (void)
                    270: {
                    271:   ecomhash = hash_create (ecommunity_hash_make, ecommunity_cmp);
                    272: }
                    273: 
                    274: void
                    275: ecommunity_finish (void)
                    276: {
                    277:   hash_free (ecomhash);
                    278:   ecomhash = NULL;
                    279: }
                    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: ecommunity_gettoken (const char *str, struct ecommunity_val *eval,
                    293:                     enum ecommunity_token *token)
                    294: {
                    295:   int ret;
                    296:   int dot = 0;
                    297:   int digit = 0;
                    298:   int separator = 0;
                    299:   const char *p = str;
                    300:   char *endptr;
                    301:   struct in_addr ip;
                    302:   as_t as = 0;
                    303:   u_int32_t val = 0;
                    304:   char buf[INET_ADDRSTRLEN + 1];
                    305: 
                    306:   /* Skip white space. */
                    307:   while (isspace ((int) *p))
                    308:     {
                    309:       p++;
                    310:       str++;
                    311:     }
                    312: 
                    313:   /* Check the end of the line. */
                    314:   if (*p == '\0')
                    315:     return NULL;
                    316: 
                    317:   /* "rt" and "soo" keyword parse. */
                    318:   if (! isdigit ((int) *p)) 
                    319:     {
                    320:       /* "rt" match check.  */
                    321:       if (tolower ((int) *p) == 'r')
                    322:        {
                    323:          p++;
                    324:          if (tolower ((int) *p) == 't')
                    325:            {
                    326:              p++;
                    327:              *token = ecommunity_token_rt;
                    328:              return p;
                    329:            }
                    330:          if (isspace ((int) *p) || *p == '\0')
                    331:            {
                    332:              *token = ecommunity_token_rt;
                    333:              return p;
                    334:            }
                    335:          goto error;
                    336:        }
                    337:       /* "soo" match check.  */
                    338:       else if (tolower ((int) *p) == 's')
                    339:        {
                    340:          p++;
                    341:          if (tolower ((int) *p) == 'o')
                    342:            {
                    343:              p++;
                    344:              if (tolower ((int) *p) == 'o')
                    345:                {
                    346:                  p++;
                    347:                  *token = ecommunity_token_soo;
                    348:                  return p;
                    349:                }
                    350:              if (isspace ((int) *p) || *p == '\0')
                    351:                {
                    352:                  *token = ecommunity_token_soo;
                    353:                  return p;
                    354:                }
                    355:              goto error;
                    356:            }
                    357:          if (isspace ((int) *p) || *p == '\0')
                    358:            {
                    359:              *token = ecommunity_token_soo;
                    360:              return p;
                    361:            }
                    362:          goto error;
                    363:        }
                    364:       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:   while (isdigit ((int) *p) || *p == ':' || *p == '.') 
                    381:     {
                    382:       if (*p == ':')
                    383:        {
                    384:          if (separator)
                    385:            goto error;
                    386: 
                    387:          separator = 1;
                    388:          digit = 0;
                    389:          
                    390:          if ((p - str) > INET_ADDRSTRLEN)
                    391:            goto error;
                    392:           memset (buf, 0, INET_ADDRSTRLEN + 1);
                    393:           memcpy (buf, str, p - str);
                    394:           
                    395:          if (dot)
                    396:            {
                    397:              /* Parsing A.B.C.D in:
                    398:                * A.B.C.D:MN
                    399:                */
                    400:              ret = inet_aton (buf, &ip);
                    401:              if (ret == 0)
                    402:                goto error;
                    403:            }
                    404:           else
                    405:             {
                    406:               /* ASN */
                    407:               as = strtoul (buf, &endptr, 10);
                    408:               if (*endptr != '\0' || as == BGP_AS4_MAX)
                    409:                 goto error;
                    410:             }
                    411:        }
                    412:       else if (*p == '.')
                    413:        {
                    414:          if (separator)
                    415:            goto error;
                    416:          dot++;
                    417:          if (dot > 4)
                    418:            goto error;
                    419:        }
                    420:       else
                    421:        {
                    422:          digit = 1;
                    423:          
                    424:          /* We're past the IP/ASN part */
                    425:          if (separator)
                    426:            {
                    427:              val *= 10;
                    428:              val += (*p - '0');
                    429:             }
                    430:        }
                    431:       p++;
                    432:     }
                    433: 
                    434:   /* Low digit part must be there. */
                    435:   if (!digit || !separator)
                    436:     goto error;
                    437: 
                    438:   /* Encode result into routing distinguisher.  */
                    439:   if (dot)
                    440:     {
                    441:       if (val > UINT16_MAX)
                    442:         goto error;
                    443:       
                    444:       eval->val[0] = ECOMMUNITY_ENCODE_IP;
                    445:       eval->val[1] = 0;
                    446:       memcpy (&eval->val[2], &ip, sizeof (struct in_addr));
                    447:       eval->val[6] = (val >> 8) & 0xff;
                    448:       eval->val[7] = val & 0xff;
                    449:     }
                    450:   else if (as > BGP_AS_MAX)
                    451:     {
                    452:       if (val > UINT16_MAX)
                    453:         goto error;
                    454:       
                    455:       eval->val[0] = ECOMMUNITY_ENCODE_AS4;
                    456:       eval->val[1] = 0;
                    457:       eval->val[2] = (as >>24) & 0xff;
                    458:       eval->val[3] = (as >>16) & 0xff;
                    459:       eval->val[4] = (as >>8) & 0xff;
                    460:       eval->val[5] =  as & 0xff;
                    461:       eval->val[6] = (val >> 8) & 0xff;
                    462:       eval->val[7] = val & 0xff;
                    463:     }
                    464:   else
                    465:     {
                    466:       eval->val[0] = ECOMMUNITY_ENCODE_AS;
                    467:       eval->val[1] = 0;
                    468:       
                    469:       eval->val[2] = (as >>8) & 0xff;
                    470:       eval->val[3] = as & 0xff;
                    471:       eval->val[4] = (val >>24) & 0xff;
                    472:       eval->val[5] = (val >>16) & 0xff;
                    473:       eval->val[6] = (val >>8) & 0xff;
                    474:       eval->val[7] = val & 0xff;
                    475:     }
                    476:   *token = ecommunity_token_val;
                    477:   return p;
                    478: 
                    479:  error:
                    480:   *token = ecommunity_token_unknown;
                    481:   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: ecommunity_str2com (const char *str, int type, int keyword_included)
                    512: {
                    513:   struct ecommunity *ecom = NULL;
                    514:   enum ecommunity_token token;
                    515:   struct ecommunity_val eval;
                    516:   int keyword = 0;
                    517: 
                    518:   while ((str = ecommunity_gettoken (str, &eval, &token)))
                    519:     {
                    520:       switch (token)
                    521:        {
                    522:        case ecommunity_token_rt:
                    523:        case ecommunity_token_soo:
                    524:          if (! keyword_included || keyword)
                    525:            {
                    526:              if (ecom)
                    527:                ecommunity_free (&ecom);
                    528:              return NULL;
                    529:            }
                    530:          keyword = 1;
                    531: 
                    532:          if (token == ecommunity_token_rt)
                    533:            {
                    534:              type = ECOMMUNITY_ROUTE_TARGET;
                    535:            }
                    536:          if (token == ecommunity_token_soo)
                    537:            {
                    538:              type = ECOMMUNITY_SITE_ORIGIN;
                    539:            }
                    540:          break;
                    541:        case ecommunity_token_val:
                    542:          if (keyword_included)
                    543:            {
                    544:              if (! keyword)
                    545:                {
                    546:                  if (ecom)
                    547:                    ecommunity_free (&ecom);
                    548:                  return NULL;
                    549:                }
                    550:              keyword = 0;
                    551:            }
                    552:          if (ecom == NULL)
                    553:            ecom = ecommunity_new ();
                    554:          eval.val[1] = type;
                    555:          ecommunity_add_val (ecom, &eval);
                    556:          break;
                    557:        case ecommunity_token_unknown:
                    558:        default:
                    559:          if (ecom)
                    560:            ecommunity_free (&ecom);
                    561:          return NULL;
                    562:        }
                    563:     }
                    564:   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: ecommunity_ecom2str (struct ecommunity *ecom, int format)
                    590: {
                    591:   int i;
                    592:   u_int8_t *pnt;
                    593:   int encode = 0;
                    594:   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:   int len = 0;
                    601:   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:   if (ecom->size == 0)
                    617:     {
                    618:       str_buf = XMALLOC (MTYPE_ECOMMUNITY_STR, 1);
                    619:       str_buf[0] = '\0';
                    620:       return str_buf;
                    621:     }
                    622: 
                    623:   /* Prepare buffer.  */
                    624:   str_buf = XMALLOC (MTYPE_ECOMMUNITY_STR, ECOMMUNITY_STR_DEFAULT_LEN + 1);
                    625:   str_size = ECOMMUNITY_STR_DEFAULT_LEN + 1;
                    626:   str_pnt = 0;
                    627: 
                    628:   for (i = 0; i < ecom->size; i++)
                    629:     {
                    630:       /* Make it sure size is enough.  */
                    631:       while (str_pnt + ECOMMUNITY_STR_DEFAULT_LEN >= str_size)
                    632:        {
                    633:          str_size *= 2;
                    634:          str_buf = XREALLOC (MTYPE_ECOMMUNITY_STR, str_buf, str_size);
                    635:        }
                    636: 
                    637:       /* Space between each value.  */
                    638:       if (! first)
                    639:        str_buf[str_pnt++] = ' ';
                    640: 
                    641:       pnt = ecom->val + (i * 8);
                    642: 
                    643:       /* High-order octet of type. */
                    644:       encode = *pnt++;
                    645:       if (encode != ECOMMUNITY_ENCODE_AS && encode != ECOMMUNITY_ENCODE_IP
                    646:                      && encode != ECOMMUNITY_ENCODE_AS4)
                    647:        {
                    648:          len = sprintf (str_buf + str_pnt, "?");
                    649:          str_pnt += len;
                    650:          first = 0;
                    651:          continue;
                    652:        }
                    653:       
                    654:       /* Low-order octet of type. */
                    655:       type = *pnt++;
                    656:       if (type !=  ECOMMUNITY_ROUTE_TARGET && type != ECOMMUNITY_SITE_ORIGIN)
                    657:        {
                    658:          len = sprintf (str_buf + str_pnt, "?");
                    659:          str_pnt += len;
                    660:          first = 0;
                    661:          continue;
                    662:        }
                    663: 
                    664:       switch (format)
                    665:        {
                    666:        case ECOMMUNITY_FORMAT_COMMUNITY_LIST:
                    667:          prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "rt " : "soo ");
                    668:          break;
                    669:        case ECOMMUNITY_FORMAT_DISPLAY:
                    670:          prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "RT:" : "SoO:");
                    671:          break;
                    672:        case ECOMMUNITY_FORMAT_ROUTE_MAP:
                    673:          prefix = "";
                    674:          break;
                    675:        default:
                    676:          prefix = "";
                    677:          break;
                    678:        }
                    679: 
                    680:       /* Put string into buffer.  */
                    681:       if (encode == ECOMMUNITY_ENCODE_AS4)
                    682:        {
                    683:          eas.as = (*pnt++ << 24);
                    684:          eas.as |= (*pnt++ << 16);
                    685:          eas.as |= (*pnt++ << 8);
                    686:          eas.as |= (*pnt++);
                    687: 
                    688:          eas.val = (*pnt++ << 8);
                    689:          eas.val |= (*pnt++);
                    690: 
                    691:          len = sprintf( str_buf + str_pnt, "%s%u:%d", prefix,
                    692:                         eas.as, eas.val );
                    693:          str_pnt += len;
                    694:          first = 0;
                    695:        }
                    696:       if (encode == ECOMMUNITY_ENCODE_AS)
                    697:        {
                    698:          eas.as = (*pnt++ << 8);
                    699:          eas.as |= (*pnt++);
                    700: 
                    701:          eas.val = (*pnt++ << 24);
                    702:          eas.val |= (*pnt++ << 16);
                    703:          eas.val |= (*pnt++ << 8);
                    704:          eas.val |= (*pnt++);
                    705: 
                    706:          len = sprintf (str_buf + str_pnt, "%s%u:%d", prefix,
                    707:                         eas.as, eas.val);
                    708:          str_pnt += len;
                    709:          first = 0;
                    710:        }
                    711:       else if (encode == ECOMMUNITY_ENCODE_IP)
                    712:        {
                    713:          memcpy (&eip.ip, pnt, 4);
                    714:          pnt += 4;
                    715:          eip.val = (*pnt++ << 8);
                    716:          eip.val |= (*pnt++);
                    717: 
                    718:          len = sprintf (str_buf + str_pnt, "%s%s:%d", prefix,
                    719:                         inet_ntoa (eip.ip), eip.val);
                    720:          str_pnt += len;
                    721:          first = 0;
                    722:        }
                    723:     }
                    724:   return str_buf;
                    725: }
                    726: 
                    727: int
                    728: ecommunity_match (const struct ecommunity *ecom1, 
                    729:                   const struct ecommunity *ecom2)
                    730: {
                    731:   int i = 0;
                    732:   int j = 0;
                    733: 
                    734:   if (ecom1 == NULL && ecom2 == NULL)
                    735:     return 1;
                    736: 
                    737:   if (ecom1 == NULL || ecom2 == NULL)
                    738:     return 0;
                    739: 
                    740:   if (ecom1->size < ecom2->size)
                    741:     return 0;
                    742: 
                    743:   /* Every community on com2 needs to be on com1 for this to match */
                    744:   while (i < ecom1->size && j < ecom2->size)
                    745:     {
                    746:       if (memcmp (ecom1->val + i, ecom2->val + j, ECOMMUNITY_SIZE) == 0)
                    747:         j++;
                    748:       i++;
                    749:     }
                    750: 
                    751:   if (j == ecom2->size)
                    752:     return 1;
                    753:   else
                    754:     return 0;
                    755: }
                    756: 

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