]> git.proxmox.com Git - mirror_frr.git/blobdiff - bgpd/bgp_community.c
*: update hash_create(), hash_create_size()
[mirror_frr.git] / bgpd / bgp_community.c
index d40d69a2ffa1090d00e4f96b4b4579ca090990f9..be4cdac0acbaf7b6fbb431980f92ecfaa530e557 100644 (file)
@@ -1,28 +1,30 @@
 /* Community attribute related functions.
  Copyright (C) 1998, 2001 Kunihiro Ishiguro
-
-This file is part of GNU Zebra.
-
-GNU Zebra is free software; you can redistribute it and/or modify it
-under the terms of the GNU General Public License as published by the
-Free Software Foundation; either version 2, or (at your option) any
-later version.
-
-GNU Zebra is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Zebra; see the file COPYING.  If not, write to the Free
-Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
* Copyright (C) 1998, 2001 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
 
 #include <zebra.h>
 
+#include "command.h"
 #include "hash.h"
 #include "memory.h"
 
+#include "bgpd/bgp_memory.h"
 #include "bgpd/bgp_community.h"
 
 /* Hash of community attribute. */
@@ -44,6 +46,13 @@ community_free (struct community *com)
     XFREE (MTYPE_COMMUNITY_VAL, com->val);
   if (com->str)
     XFREE (MTYPE_COMMUNITY_STR, com->str);
+
+  if (com->json)
+    {
+      json_object_free(com->json);
+      com->json = NULL;
+    }
+
   XFREE (MTYPE_COMMUNITY, com);
 }
 
@@ -78,7 +87,7 @@ community_del_val (struct community *com, u_int32_t *val)
          c = com->size -i -1;
 
          if (c > 0)
-           memcpy (com->val + i, com->val + (i + 1), c * sizeof (*val));
+           memmove (com->val + i, com->val + (i + 1), c * sizeof (*val));
 
          com->size--;
 
@@ -144,7 +153,7 @@ community_include (struct community *com, u_int32_t val)
   return 0;
 }
 
-static u_int32_t
+u_int32_t
 community_val_get (struct community *com, int i)
 {
   u_char *p;
@@ -170,6 +179,7 @@ community_uniq_sort (struct community *com)
     return NULL;
   
   new = community_new ();;
+  new->json = NULL;
   
   for (i = 0; i < com->size; i++)
     {
@@ -194,8 +204,8 @@ community_uniq_sort (struct community *com)
    0xFFFFFF03      "local-AS"
 
    For other values, "AS:VAL" format is used.  */
-static char *
-community_com2str  (struct community *com)
+static void
+set_community_string  (struct community *com)
 {
   int i;
   char *str;
@@ -205,16 +215,25 @@ community_com2str  (struct community *com)
   u_int32_t comval;
   u_int16_t as;
   u_int16_t val;
+  json_object *json_community_list = NULL;
+  json_object *json_string = NULL;
 
   if (!com)
-    return NULL;
+    return;
   
+  com->json = json_object_new_object();
+  json_community_list = json_object_new_array();
+
   /* When communities attribute is empty.  */
   if (com->size == 0)
     {
       str = XMALLOC (MTYPE_COMMUNITY_STR, 1);
       str[0] = '\0';
-      return str;
+
+      json_object_string_add(com->json, "string", "");
+      json_object_object_add(com->json, "list", json_community_list);
+      com->str = str;
+      return;
     }
 
   /* Memory allocation is time consuming work.  So we calculate
@@ -266,30 +285,42 @@ community_com2str  (struct community *com)
        case COMMUNITY_INTERNET:
          strcpy (pnt, "internet");
          pnt += strlen ("internet");
+          json_string = json_object_new_string("internet");
+          json_object_array_add(json_community_list, json_string);
          break;
        case COMMUNITY_NO_EXPORT:
          strcpy (pnt, "no-export");
          pnt += strlen ("no-export");
+          json_string = json_object_new_string("noExport");
+          json_object_array_add(json_community_list, json_string);
          break;
        case COMMUNITY_NO_ADVERTISE:
          strcpy (pnt, "no-advertise");
          pnt += strlen ("no-advertise");
+          json_string = json_object_new_string("noAdvertise");
+          json_object_array_add(json_community_list, json_string);
          break;
        case COMMUNITY_LOCAL_AS:
          strcpy (pnt, "local-AS");
          pnt += strlen ("local-AS");
+          json_string = json_object_new_string("localAs");
+          json_object_array_add(json_community_list, json_string);
          break;
        default:
          as = (comval >> 16) & 0xFFFF;
          val = comval & 0xFFFF;
          sprintf (pnt, "%u:%d", as, val);
+          json_string = json_object_new_string(pnt);
+          json_object_array_add(json_community_list, json_string);
          pnt += strlen (pnt);
          break;
        }
     }
   *pnt = '\0';
 
-  return str;
+  json_object_string_add(com->json, "string", str);
+  json_object_object_add(com->json, "list", json_community_list);
+  com->str = str;
 }
 
 /* Intern communities attribute.  */
@@ -314,28 +345,29 @@ community_intern (struct community *com)
 
   /* Make string.  */
   if (! find->str)
-    find->str = community_com2str (find);
+    set_community_string (find);
 
   return find;
 }
 
 /* Free community attribute. */
 void
-community_unintern (struct community *com)
+community_unintern (struct community **com)
 {
   struct community *ret;
 
-  if (com->refcnt)
-    com->refcnt--;
+  if ((*com)->refcnt)
+    (*com)->refcnt--;
 
   /* Pull off from hash.  */
-  if (com->refcnt == 0)
+  if ((*com)->refcnt == 0)
     {
       /* Community value com must exist in hash. */
-      ret = (struct community *) hash_release (comhash, com);
+      ret = (struct community *) hash_release (comhash, *com);
       assert (ret != NULL);
 
-      community_free (com);
+      community_free (*com);
+      *com = NULL;
     }
 }
 
@@ -382,9 +414,9 @@ community_str (struct community *com)
 {
   if (!com)
     return NULL;
-  
+
   if (! com->str)
-    com->str = community_com2str (com);
+    set_community_string (com);
   return com->str;
 }
 
@@ -393,16 +425,19 @@ community_str (struct community *com)
 unsigned int
 community_hash_make (struct community *com)
 {
+  unsigned char *pnt = (unsigned char *)com->val;
+  int size = com->size * 4;
+  unsigned int key = 0;
   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];
-      
+  for (c = 0; c < size; c += 4)
+    {
+      key += pnt[c];
+      key += pnt[c + 1];
+      key += pnt[c + 2];
+      key += pnt[c + 3];
+    }
+
   return key;
 }
 
@@ -550,6 +585,13 @@ community_gettoken (const char *buf, enum community_token *token,
                {
                  separator = 1;
                  digit = 0;
+
+                  if (community_low > UINT16_MAX)
+                    {
+                      *token = community_token_unknown;
+                      return NULL;
+                    }
+
                  community_high = community_low << 16;
                  community_low = 0;
                }
@@ -567,6 +609,13 @@ community_gettoken (const char *buf, enum community_token *token,
          *token = community_token_unknown;
          return NULL;
        }
+
+      if (community_low > UINT16_MAX)
+        {
+          *token = community_token_unknown;
+          return NULL;
+        }
+
       *val = community_high + community_low;
       *token = community_token_val;
       return p;
@@ -595,7 +644,10 @@ community_str2com (const char *str)
        case community_token_no_advertise:
        case community_token_local_as:
          if (com == NULL)
-           com = community_new();
+            {
+              com = community_new();
+              com->json = NULL;
+            }
          community_add_val (com, val);
          break;
        case community_token_unknown:
@@ -634,5 +686,12 @@ void
 community_init (void)
 {
   comhash = hash_create ((unsigned int (*) (void *))community_hash_make,
-                        (int (*) (const void *, const void *))community_cmp);
+                        (int (*) (const void *, const void *))community_cmp, NULL);
+}
+
+void
+community_finish (void)
+{
+  hash_free (comhash);
+  comhash = NULL;
 }