File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / bgpd / bgp_ecommunity.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:09:10 2016 UTC (7 years, 8 months ago) by misho
Branches: quagga, MAIN
CVS tags: v1_0_20160315, HEAD
quagga 1.0.20160315

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

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