bgp_community.c
上传用户:xiaozhuqw
上传日期:2009-11-15
资源大小:1338k
文件大小:13k
源码类别:

网络

开发平台:

Unix_Linux

  1. /* Community attribute related functions.
  2.    Copyright (C) 1998, 2001 Kunihiro Ishiguro
  3. This file is part of GNU Zebra.
  4. GNU Zebra is free software; you can redistribute it and/or modify it
  5. under the terms of the GNU General Public License as published by the
  6. Free Software Foundation; either version 2, or (at your option) any
  7. later version.
  8. GNU Zebra is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNU Zebra; see the file COPYING.  If not, write to the Free
  14. Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  15. 02111-1307, USA.  */
  16. #include <zebra.h>
  17. #include "hash.h"
  18. #include "memory.h"
  19. #include "bgpd/bgp_community.h"
  20. /* Hash of community attribute. */
  21. struct hash *comhash;
  22. /* Allocate a new communities value.  */
  23. struct community *
  24. community_new ()
  25. {
  26.   return (struct community *) XCALLOC (MTYPE_COMMUNITY,
  27.        sizeof (struct community));
  28. }
  29. /* Free communities value.  */
  30. void
  31. community_free (struct community *com)
  32. {
  33.   if (com->val)
  34.     XFREE (MTYPE_COMMUNITY_VAL, com->val);
  35.   if (com->str)
  36.     XFREE (MTYPE_COMMUNITY_STR, com->str);
  37.   XFREE (MTYPE_COMMUNITY, com);
  38. }
  39. /* Add one community value to the community. */
  40. void
  41. community_add_val (struct community *com, u_int32_t val)
  42. {
  43.   com->size++;
  44.   if (com->val)
  45.     com->val = XREALLOC (MTYPE_COMMUNITY_VAL, com->val, com_length (com));
  46.   else
  47.     com->val = XMALLOC (MTYPE_COMMUNITY_VAL, com_length (com));
  48.   val = htonl (val);
  49.   memcpy (com_lastval (com), &val, sizeof (u_int32_t));
  50. }
  51. /* Delete one community. */
  52. void
  53. community_del_val (struct community *com, u_int32_t *val)
  54. {
  55.   int i = 0;
  56.   int c = 0;
  57.   if (! com->val)
  58.     return;
  59.   while (i < com->size)
  60.     {
  61.       if (memcmp (com->val + i, val, sizeof (u_int32_t)) == 0)
  62. {
  63.   c = com->size -i -1;
  64.   if (c > 0)
  65.     memcpy (com->val + i, com->val + (i + 1), c * sizeof (val));
  66.   com->size--;
  67.   if (com->size > 0)
  68.     com->val = XREALLOC (MTYPE_COMMUNITY_VAL, com->val,
  69.  com_length (com));
  70.   else
  71.     {
  72.       XFREE (MTYPE_COMMUNITY_VAL, com->val);
  73.       com->val = NULL;
  74.     }
  75.   return;
  76. }
  77.       i++;
  78.     }
  79. }
  80. /* Delete all communities listed in com2 from com1 */
  81. struct community *
  82. community_delete (struct community *com1, struct community *com2)
  83. {
  84.   int i = 0;
  85.   while(i < com2->size)
  86.     {
  87.       community_del_val (com1, com2->val + i);
  88.       i++;
  89.     }
  90.   return com1;
  91. }
  92. /* Callback function from qsort(). */
  93. int
  94. community_compare (const void *a1, const void *a2)
  95. {
  96.   u_int32_t v1;
  97.   u_int32_t v2;
  98.   memcpy (&v1, a1, sizeof (u_int32_t));
  99.   memcpy (&v2, a2, sizeof (u_int32_t));
  100.   v1 = ntohl (v1);
  101.   v2 = ntohl (v2);
  102.   if (v1 < v2)
  103.     return -1;
  104.   if (v1 > v2)
  105.     return 1;
  106.   return 0;
  107. }
  108. int
  109. community_include (struct community *com, u_int32_t val)
  110. {
  111.   int i;
  112.   val = htonl (val);
  113.   for (i = 0; i < com->size; i++)
  114.     if (memcmp (&val, com_nthval (com, i), sizeof (u_int32_t)) == 0)
  115.       return 1;
  116.   return 0;
  117. }
  118. u_int32_t
  119. community_val_get (struct community *com, int i)
  120. {
  121.   u_char *p;
  122.   u_int32_t val;
  123.   p = (u_char *) com->val;
  124.   p += (i * 4);
  125.   memcpy (&val, p, sizeof (u_int32_t));
  126.   return ntohl (val);
  127. }
  128. /* Sort and uniq given community. */
  129. struct community *
  130. community_uniq_sort (struct community *com)
  131. {
  132.   int i;
  133.   struct community *new;
  134.   u_int32_t val;
  135.   if (! com)
  136.     return NULL;
  137.   
  138.   new = community_new ();;
  139.   
  140.   for (i = 0; i < com->size; i++)
  141.     {
  142.       val = community_val_get (com, i);
  143.       if (! community_include (new, val))
  144. community_add_val (new, val);
  145.     }
  146.   qsort (new->val, new->size, sizeof (u_int32_t), community_compare);
  147.   return new;
  148. }
  149. /* Convert communities attribute to string.
  150.    For Well-known communities value, below keyword is used.
  151.    0x0             "internet"    
  152.    0xFFFFFF01      "no-export"
  153.    0xFFFFFF02      "no-advertise"
  154.    0xFFFFFF03      "local-AS"
  155.    For other values, "AS:VAL" format is used.  */
  156. static char *
  157. community_com2str  (struct community *com)
  158. {
  159.   int i;
  160.   char *str;
  161.   char *pnt;
  162.   int len;
  163.   int first;
  164.   u_int32_t comval;
  165.   u_int16_t as;
  166.   u_int16_t val;
  167.   /* When communities attribute is empty.  */
  168.   if (com->size == 0)
  169.     {
  170.       str = XMALLOC (MTYPE_COMMUNITY_STR, 1);
  171.       str[0] = '';
  172.       return str;
  173.     }
  174.   /* Memory allocation is time consuming work.  So we calculate
  175.      required string length first.  */
  176.   len = 0;
  177.   for (i = 0; i < com->size; i++)
  178.     {
  179.       memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t));
  180.       comval = ntohl (comval);
  181.       switch (comval) 
  182. {
  183. case COMMUNITY_INTERNET:
  184.   len += strlen (" internet");
  185.   break;
  186. case COMMUNITY_NO_EXPORT:
  187.   len += strlen (" no-export");
  188.   break;
  189. case COMMUNITY_NO_ADVERTISE:
  190.   len += strlen (" no-advertise");
  191.   break;
  192. case COMMUNITY_LOCAL_AS:
  193.   len += strlen (" local-AS");
  194.   break;
  195. default:
  196.   len += strlen (" 65536:65535");
  197.   break;
  198. }
  199.     }
  200.   /* Allocate memory.  */
  201.   str = pnt = XMALLOC (MTYPE_COMMUNITY_STR, len);
  202.   first = 1;
  203.   /* Fill in string.  */
  204.   for (i = 0; i < com->size; i++)
  205.     {
  206.       memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t));
  207.       comval = ntohl (comval);
  208.       if (first)
  209. first = 0;
  210.       else
  211. *pnt++ = ' ';
  212.       switch (comval) 
  213. {
  214. case COMMUNITY_INTERNET:
  215.   strcpy (pnt, "internet");
  216.   pnt += strlen ("internet");
  217.   break;
  218. case COMMUNITY_NO_EXPORT:
  219.   strcpy (pnt, "no-export");
  220.   pnt += strlen ("no-export");
  221.   break;
  222. case COMMUNITY_NO_ADVERTISE:
  223.   strcpy (pnt, "no-advertise");
  224.   pnt += strlen ("no-advertise");
  225.   break;
  226. case COMMUNITY_LOCAL_AS:
  227.   strcpy (pnt, "local-AS");
  228.   pnt += strlen ("local-AS");
  229.   break;
  230. default:
  231.   as = (comval >> 16) & 0xFFFF;
  232.   val = comval & 0xFFFF;
  233.   sprintf (pnt, "%d:%d", as, val);
  234.   pnt += strlen (pnt);
  235.   break;
  236. }
  237.     }
  238.   *pnt = '';
  239.   return str;
  240. }
  241. /* Intern communities attribute.  */
  242. struct community *
  243. community_intern (struct community *com)
  244. {
  245.   struct community *find;
  246.   /* Assert this community structure is not interned. */
  247.   assert (com->refcnt == 0);
  248.   /* Lookup community hash. */
  249.   find = (struct community *) hash_get (comhash, com, hash_alloc_intern);
  250.   /* Arguemnt com is allocated temporary.  So when it is not used in
  251.      hash, it should be freed.  */
  252.   if (find != com)
  253.     community_free (com);
  254.   /* Increment refrence counter.  */
  255.   find->refcnt++;
  256.   /* Make string.  */
  257.   if (! find->str)
  258.     find->str = community_com2str (find);
  259.   return find;
  260. }
  261. /* Free community attribute. */
  262. void
  263. community_unintern (struct community *com)
  264. {
  265.   struct community *ret;
  266.   if (com->refcnt)
  267.     com->refcnt--;
  268.   /* Pull off from hash.  */
  269.   if (com->refcnt == 0)
  270.     {
  271.       /* Community value com must exist in hash. */
  272.       ret = (struct community *) hash_release (comhash, com);
  273.       assert (ret != NULL);
  274.       community_free (com);
  275.     }
  276. }
  277. /* Create new community attribute. */
  278. struct community *
  279. community_parse (char *pnt, u_short length)
  280. {
  281.   struct community tmp;
  282.   struct community *new;
  283.   /* If length is malformed return NULL. */
  284.   if (length % 4)
  285.     return NULL;
  286.   /* Make temporary community for hash look up. */
  287.   tmp.size = length / 4;
  288.   tmp.val = (u_int32_t *) pnt;
  289.   new = community_uniq_sort (&tmp);
  290.   return community_intern (new);
  291. }
  292. struct community *
  293. community_dup (struct community *com)
  294. {
  295.   struct community *new;
  296.   new = XCALLOC (MTYPE_COMMUNITY, sizeof (struct community));
  297.   new->size = com->size;
  298.   if (new->size)
  299.     {
  300.       new->val = XMALLOC (MTYPE_COMMUNITY_VAL, com->size * 4);
  301.       memcpy (new->val, com->val, com->size * 4);
  302.     }
  303.   else
  304.     new->val = NULL;
  305.   return new;
  306. }
  307. /* Retrun string representation of communities attribute. */
  308. char *
  309. community_str (struct community *com)
  310. {
  311.   if (! com->str)
  312.     com->str = community_com2str (com);
  313.   return com->str;
  314. }
  315. /* Make hash value of community attribute. This function is used by
  316.    hash package.*/
  317. unsigned int
  318. community_hash_make (struct community *com)
  319. {
  320.   int c;
  321.   unsigned int key;
  322.   unsigned char *pnt;
  323.   key = 0;
  324.   pnt = (unsigned char *)com->val;
  325.   
  326.   for(c = 0; c < com->size * 4; c++)
  327.     key += pnt[c];
  328.       
  329.   return key;
  330. }
  331. int
  332. community_match (struct community *com1, struct community *com2)
  333. {
  334.   int i = 0;
  335.   int j = 0;
  336.   if (com1 == NULL && com2 == NULL)
  337.     return 1;
  338.   if (com1 == NULL || com2 == NULL)
  339.     return 0;
  340.   if (com1->size < com2->size)
  341.     return 0;
  342.   /* Every community on com2 needs to be on com1 for this to match */
  343.   while (i < com1->size && j < com2->size)
  344.     {
  345.       if (memcmp (com1->val + i, com2->val + j, sizeof (u_int32_t)) == 0)
  346. j++;
  347.       i++;
  348.     }
  349.   if (j == com2->size)
  350.     return 1;
  351.   else
  352.     return 0;
  353. }
  354. /* If two aspath have same value then return 1 else return 0. This
  355.    function is used by hash package. */
  356. int
  357. community_cmp (struct community *com1, struct community *com2)
  358. {
  359.   if (com1 == NULL && com2 == NULL)
  360.     return 1;
  361.   if (com1 == NULL || com2 == NULL)
  362.     return 0;
  363.   if (com1->size == com2->size)
  364.     if (memcmp (com1->val, com2->val, com1->size * 4) == 0)
  365.       return 1;
  366.   return 0;
  367. }
  368. /* Add com2 to the end of com1. */
  369. struct community *
  370. community_merge (struct community *com1, struct community *com2)
  371. {
  372.   if (com1->val)
  373.     com1->val = XREALLOC (MTYPE_COMMUNITY_VAL, com1->val, 
  374.   (com1->size + com2->size) * 4);
  375.   else
  376.     com1->val = XMALLOC (MTYPE_COMMUNITY_VAL, (com1->size + com2->size) * 4);
  377.   memcpy (com1->val + com1->size, com2->val, com2->size * 4);
  378.   com1->size += com2->size;
  379.   return com1;
  380. }
  381. /* Community token enum. */
  382. enum community_token
  383. {
  384.   community_token_val,
  385.   community_token_no_export,
  386.   community_token_no_advertise,
  387.   community_token_local_as,
  388.   community_token_unknown
  389. };
  390. /* Get next community token from string. */
  391. char *
  392. community_gettoken (char *buf, enum community_token *token, u_int32_t *val)
  393. {
  394.   char *p = buf;
  395.   /* Skip white space. */
  396.   while (isspace ((int) *p))
  397.     p++;
  398.   /* Check the end of the line. */
  399.   if (*p == '')
  400.     return NULL;
  401.   /* Well known community string check. */
  402.   if (isalpha ((int) *p)) 
  403.     {
  404.       if (strncmp (p, "internet", strlen ("internet")) == 0)
  405. {
  406.   *val = COMMUNITY_INTERNET;
  407.   *token = community_token_no_export;
  408.   p += strlen ("internet");
  409.   return p;
  410. }
  411.       if (strncmp (p, "no-export", strlen ("no-export")) == 0)
  412. {
  413.   *val = COMMUNITY_NO_EXPORT;
  414.   *token = community_token_no_export;
  415.   p += strlen ("no-export");
  416.   return p;
  417. }
  418.       if (strncmp (p, "no-advertise", strlen ("no-advertise")) == 0)
  419. {
  420.   *val = COMMUNITY_NO_ADVERTISE;
  421.   *token = community_token_no_advertise;
  422.   p += strlen ("no-advertise");
  423.   return p;
  424. }
  425.       if (strncmp (p, "local-AS", strlen ("local-AS")) == 0)
  426. {
  427.   *val = COMMUNITY_LOCAL_AS;
  428.   *token = community_token_local_as;
  429.   p += strlen ("local-AS");
  430.   return p;
  431. }
  432.       /* Unknown string. */
  433.       *token = community_token_unknown;
  434.       return p;
  435.     }
  436.   /* Community value. */
  437.   if (isdigit ((int) *p)) 
  438.     {
  439.       int separator = 0;
  440.       int digit = 0;
  441.       u_int32_t community_low = 0;
  442.       u_int32_t community_high = 0;
  443.       while (isdigit ((int) *p) || *p == ':') 
  444. {
  445.   if (*p == ':') 
  446.     {
  447.       if (separator)
  448. {
  449.   *token = community_token_unknown;
  450.   return p;
  451. }
  452.       else
  453. {
  454.   separator = 1;
  455.   digit = 0;
  456.   community_high = community_low << 16;
  457.   community_low = 0;
  458. }
  459.     }
  460.   else 
  461.     {
  462.       digit = 1;
  463.       community_low *= 10;
  464.       community_low += (*p - '0');
  465.     }
  466.   p++;
  467. }
  468.       if (! digit)
  469. {
  470.   *token = community_token_unknown;
  471.   return p;
  472. }
  473.       *val = community_high + community_low;
  474.       *token = community_token_val;
  475.       return p;
  476.     }
  477.   *token = community_token_unknown;
  478.   return p;
  479. }
  480. /* convert string to community structure */
  481. struct community *
  482. community_str2com (char *str)
  483. {
  484.   struct community *com = NULL;
  485.   struct community *com_sort = NULL;
  486.   u_int32_t val;
  487.   enum community_token token;
  488.   while ((str = community_gettoken (str, &token, &val))) 
  489.     {
  490.       switch (token)
  491. {
  492. case community_token_val:
  493. case community_token_no_export:
  494. case community_token_no_advertise:
  495. case community_token_local_as:
  496.   if (com == NULL)
  497.     com = community_new();
  498.   community_add_val (com, val);
  499.   break;
  500. case community_token_unknown:
  501. default:
  502.   if (com)
  503.     community_free (com);
  504.   return NULL;
  505.   break;
  506. }
  507.     }
  508.   
  509.   if (! com)
  510.     return NULL;
  511.   com_sort = community_uniq_sort (com);
  512.   community_free (com);
  513.   return com_sort;
  514. }
  515. /* Return communities hash entry count.  */
  516. unsigned long
  517. community_count ()
  518. {
  519.   return comhash->count;
  520. }
  521. /* Return communities hash.  */
  522. struct hash *
  523. community_hash ()
  524. {
  525.   return comhash;
  526. }
  527. /* Initialize comminity related hash. */
  528. void
  529. community_init ()
  530. {
  531.   comhash = hash_create (community_hash_make, community_cmp);
  532. }