⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bgp_community.c

📁 大名鼎鼎的路由器源码。程序分ZEBRA、OSPFRIP等3个包。程序框架采用一个路由协议一个进程的方式
💻 C
字号:
/* Community attribute related functions.   Copyright (C) 1998, 2001 Kunihiro IshiguroThis file is part of GNU Zebra.GNU Zebra is free software; you can redistribute it and/or modify itunder the terms of the GNU General Public License as published by theFree Software Foundation; either version 2, or (at your option) anylater version.GNU Zebra is distributed in the hope that it will be useful, butWITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNUGeneral Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU Zebra; see the file COPYING.  If not, write to the FreeSoftware Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA02111-1307, USA.  */#include <zebra.h>#include "hash.h"#include "memory.h"#include "bgpd/bgp_community.h"/* Hash of community attribute. */struct hash *comhash;/* Allocate a new communities value.  */struct community *community_new (){  return (struct community *) XCALLOC (MTYPE_COMMUNITY,				       sizeof (struct community));}/* Free communities value.  */voidcommunity_free (struct community *com){  if (com->val)    XFREE (MTYPE_COMMUNITY_VAL, com->val);  if (com->str)    XFREE (MTYPE_COMMUNITY_STR, com->str);  XFREE (MTYPE_COMMUNITY, com);}/* Add one community value to the community. */voidcommunity_add_val (struct community *com, u_int32_t val){  com->size++;  if (com->val)    com->val = XREALLOC (MTYPE_COMMUNITY_VAL, com->val, com_length (com));  else    com->val = XMALLOC (MTYPE_COMMUNITY_VAL, com_length (com));  val = htonl (val);  memcpy (com_lastval (com), &val, sizeof (u_int32_t));}/* Delete one community. */voidcommunity_del_val (struct community *com, u_int32_t *val){  int i = 0;  int c = 0;  if (! com->val)    return;  while (i < com->size)    {      if (memcmp (com->val + i, val, sizeof (u_int32_t)) == 0)	{	  c = com->size -i -1;	  if (c > 0)	    memcpy (com->val + i, com->val + (i + 1), c * sizeof (val));	  com->size--;	  if (com->size > 0)	    com->val = XREALLOC (MTYPE_COMMUNITY_VAL, com->val,				 com_length (com));	  else	    {	      XFREE (MTYPE_COMMUNITY_VAL, com->val);	      com->val = NULL;	    }	  return;	}      i++;    }}/* Delete all communities listed in com2 from com1 */struct community *community_delete (struct community *com1, struct community *com2){  int i = 0;  while(i < com2->size)    {      community_del_val (com1, com2->val + i);      i++;    }  return com1;}/* Callback function from qsort(). */intcommunity_compare (const void *a1, const void *a2){  u_int32_t v1;  u_int32_t v2;  memcpy (&v1, a1, sizeof (u_int32_t));  memcpy (&v2, a2, sizeof (u_int32_t));  v1 = ntohl (v1);  v2 = ntohl (v2);  if (v1 < v2)    return -1;  if (v1 > v2)    return 1;  return 0;}intcommunity_include (struct community *com, u_int32_t val){  int i;  val = htonl (val);  for (i = 0; i < com->size; i++)    if (memcmp (&val, com_nthval (com, i), sizeof (u_int32_t)) == 0)      return 1;  return 0;}u_int32_tcommunity_val_get (struct community *com, int i){  u_char *p;  u_int32_t val;  p = (u_char *) com->val;  p += (i * 4);  memcpy (&val, p, sizeof (u_int32_t));  return ntohl (val);}/* Sort and uniq given community. */struct community *community_uniq_sort (struct community *com){  int i;  struct community *new;  u_int32_t val;  if (! com)    return NULL;    new = community_new ();;    for (i = 0; i < com->size; i++)    {      val = community_val_get (com, i);      if (! community_include (new, val))	community_add_val (new, val);    }  qsort (new->val, new->size, sizeof (u_int32_t), community_compare);  return new;}/* Convert communities attribute to string.   For Well-known communities value, below keyword is used.   0x0             "internet"       0xFFFFFF01      "no-export"   0xFFFFFF02      "no-advertise"   0xFFFFFF03      "local-AS"   For other values, "AS:VAL" format is used.  */static char *community_com2str  (struct community *com){  int i;  char *str;  char *pnt;  int len;  int first;  u_int32_t comval;  u_int16_t as;  u_int16_t val;  /* When communities attribute is empty.  */  if (com->size == 0)    {      str = XMALLOC (MTYPE_COMMUNITY_STR, 1);      str[0] = '\0';      return str;    }  /* Memory allocation is time consuming work.  So we calculate     required string length first.  */  len = 0;  for (i = 0; i < com->size; i++)    {      memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t));      comval = ntohl (comval);      switch (comval) 	{	case COMMUNITY_INTERNET:	  len += strlen (" internet");	  break;	case COMMUNITY_NO_EXPORT:	  len += strlen (" no-export");	  break;	case COMMUNITY_NO_ADVERTISE:	  len += strlen (" no-advertise");	  break;	case COMMUNITY_LOCAL_AS:	  len += strlen (" local-AS");	  break;	default:	  len += strlen (" 65536:65535");	  break;	}    }  /* Allocate memory.  */  str = pnt = XMALLOC (MTYPE_COMMUNITY_STR, len);  first = 1;  /* Fill in string.  */  for (i = 0; i < com->size; i++)    {      memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t));      comval = ntohl (comval);      if (first)	first = 0;      else	*pnt++ = ' ';      switch (comval) 	{	case COMMUNITY_INTERNET:	  strcpy (pnt, "internet");	  pnt += strlen ("internet");	  break;	case COMMUNITY_NO_EXPORT:	  strcpy (pnt, "no-export");	  pnt += strlen ("no-export");	  break;	case COMMUNITY_NO_ADVERTISE:	  strcpy (pnt, "no-advertise");	  pnt += strlen ("no-advertise");	  break;	case COMMUNITY_LOCAL_AS:	  strcpy (pnt, "local-AS");	  pnt += strlen ("local-AS");	  break;	default:	  as = (comval >> 16) & 0xFFFF;	  val = comval & 0xFFFF;	  sprintf (pnt, "%d:%d", as, val);	  pnt += strlen (pnt);	  break;	}    }  *pnt = '\0';  return str;}/* Intern communities attribute.  */struct community *community_intern (struct community *com){  struct community *find;  /* Assert this community structure is not interned. */  assert (com->refcnt == 0);  /* Lookup community hash. */  find = (struct community *) hash_get (comhash, com, hash_alloc_intern);  /* Arguemnt com is allocated temporary.  So when it is not used in     hash, it should be freed.  */  if (find != com)    community_free (com);  /* Increment refrence counter.  */  find->refcnt++;  /* Make string.  */  if (! find->str)    find->str = community_com2str (find);  return find;}/* Free community attribute. */voidcommunity_unintern (struct community *com){  struct community *ret;  if (com->refcnt)    com->refcnt--;  /* Pull off from hash.  */  if (com->refcnt == 0)    {      /* Community value com must exist in hash. */      ret = (struct community *) hash_release (comhash, com);      assert (ret != NULL);      community_free (com);    }}/* Create new community attribute. */struct community *community_parse (char *pnt, u_short length){  struct community tmp;  struct community *new;  /* If length is malformed return NULL. */  if (length % 4)    return NULL;  /* Make temporary community for hash look up. */  tmp.size = length / 4;  tmp.val = (u_int32_t *) pnt;  new = community_uniq_sort (&tmp);  return community_intern (new);}struct community *community_dup (struct community *com){  struct community *new;  new = XCALLOC (MTYPE_COMMUNITY, sizeof (struct community));  new->size = com->size;  if (new->size)    {      new->val = XMALLOC (MTYPE_COMMUNITY_VAL, com->size * 4);      memcpy (new->val, com->val, com->size * 4);    }  else    new->val = NULL;  return new;}/* Retrun string representation of communities attribute. */char *community_str (struct community *com){  if (! com->str)    com->str = community_com2str (com);  return com->str;}/* Make hash value of community attribute. This function is used by   hash package.*/unsigned intcommunity_hash_make (struct community *com){  int c;  unsigned int key;  unsigned char *pnt;  key = 0;  pnt = (unsigned char *)com->val;    for(c = 0; c < com->size * 4; c++)    key += pnt[c];        return key;}intcommunity_match (struct community *com1, struct community *com2){  int i = 0;  int j = 0;  if (com1 == NULL && com2 == NULL)    return 1;  if (com1 == NULL || com2 == NULL)    return 0;  if (com1->size < com2->size)    return 0;  /* Every community on com2 needs to be on com1 for this to match */  while (i < com1->size && j < com2->size)    {      if (memcmp (com1->val + i, com2->val + j, sizeof (u_int32_t)) == 0)	j++;      i++;    }  if (j == com2->size)    return 1;  else    return 0;}/* If two aspath have same value then return 1 else return 0. This   function is used by hash package. */intcommunity_cmp (struct community *com1, struct community *com2){  if (com1 == NULL && com2 == NULL)    return 1;  if (com1 == NULL || com2 == NULL)    return 0;  if (com1->size == com2->size)    if (memcmp (com1->val, com2->val, com1->size * 4) == 0)      return 1;  return 0;}/* Add com2 to the end of com1. */struct community *community_merge (struct community *com1, struct community *com2){  if (com1->val)    com1->val = XREALLOC (MTYPE_COMMUNITY_VAL, com1->val, 			  (com1->size + com2->size) * 4);  else    com1->val = XMALLOC (MTYPE_COMMUNITY_VAL, (com1->size + com2->size) * 4);  memcpy (com1->val + com1->size, com2->val, com2->size * 4);  com1->size += com2->size;  return com1;}/* Community token enum. */enum community_token{  community_token_val,  community_token_no_export,  community_token_no_advertise,  community_token_local_as,  community_token_unknown};/* Get next community token from string. */char *community_gettoken (char *buf, enum community_token *token, u_int32_t *val){  char *p = buf;  /* Skip white space. */  while (isspace ((int) *p))    p++;  /* Check the end of the line. */  if (*p == '\0')    return NULL;  /* Well known community string check. */  if (isalpha ((int) *p))     {      if (strncmp (p, "internet", strlen ("internet")) == 0)	{	  *val = COMMUNITY_INTERNET;	  *token = community_token_no_export;	  p += strlen ("internet");	  return p;	}      if (strncmp (p, "no-export", strlen ("no-export")) == 0)	{	  *val = COMMUNITY_NO_EXPORT;	  *token = community_token_no_export;	  p += strlen ("no-export");	  return p;	}      if (strncmp (p, "no-advertise", strlen ("no-advertise")) == 0)	{	  *val = COMMUNITY_NO_ADVERTISE;	  *token = community_token_no_advertise;	  p += strlen ("no-advertise");	  return p;	}      if (strncmp (p, "local-AS", strlen ("local-AS")) == 0)	{	  *val = COMMUNITY_LOCAL_AS;	  *token = community_token_local_as;	  p += strlen ("local-AS");	  return p;	}      /* Unknown string. */      *token = community_token_unknown;      return p;    }  /* Community value. */  if (isdigit ((int) *p))     {      int separator = 0;      int digit = 0;      u_int32_t community_low = 0;      u_int32_t community_high = 0;      while (isdigit ((int) *p) || *p == ':') 	{	  if (*p == ':') 	    {	      if (separator)		{		  *token = community_token_unknown;		  return p;		}	      else		{		  separator = 1;		  digit = 0;		  community_high = community_low << 16;		  community_low = 0;		}	    }	  else 	    {	      digit = 1;	      community_low *= 10;	      community_low += (*p - '0');	    }	  p++;	}      if (! digit)	{	  *token = community_token_unknown;	  return p;	}      *val = community_high + community_low;      *token = community_token_val;      return p;    }  *token = community_token_unknown;  return p;}/* convert string to community structure */struct community *community_str2com (char *str){  struct community *com = NULL;  struct community *com_sort = NULL;  u_int32_t val;  enum community_token token;  while ((str = community_gettoken (str, &token, &val)))     {      switch (token)	{	case community_token_val:	case community_token_no_export:	case community_token_no_advertise:	case community_token_local_as:	  if (com == NULL)	    com = community_new();	  community_add_val (com, val);	  break;	case community_token_unknown:	default:	  if (com)	    community_free (com);	  return NULL;	  break;	}    }    if (! com)    return NULL;  com_sort = community_uniq_sort (com);  community_free (com);  return com_sort;}/* Return communities hash entry count.  */unsigned longcommunity_count (){  return comhash->count;}/* Return communities hash.  */struct hash *community_hash (){  return comhash;}/* Initialize comminity related hash. */voidcommunity_init (){  comhash = hash_create (community_hash_make, community_cmp);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -