1 /*
2     pmacct (Promiscuous mode IP Accounting package)
3     pmacct is Copyright (C) 2003-2019 by Paolo Lucente
4 */
5 
6 /*
7  * Originally based on Quagga hash routine which is:
8  *
9  * Copyright (C) 1998 Kunihiro Ishiguro
10  *
11  * GNU Zebra is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published
13  * by the Free Software Foundation; either version 2, or (at your
14  * option) any later version.
15  *
16  * GNU Zebra is distributed in the hope that it will be useful, but
17  * WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with GNU Zebra; see the file COPYING.  If not, write to the
23  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24  * Boston, MA 02111-1307, USA.
25  */
26 
27 #include "pmacct.h"
28 #include "bgp.h"
29 
30 /* Allocate a new hash.  */
31 struct hash *
hash_create_size(unsigned int size,unsigned int (* hash_key)(void *),int (* hash_cmp)(const void *,const void *))32 hash_create_size (unsigned int size, unsigned int (*hash_key) (void *),
33                                      int (*hash_cmp) (const void *, const void *))
34 {
35   struct hash *hash;
36 
37   hash = malloc(sizeof (struct hash));
38   if (!hash) {
39     Log(LOG_ERR, "ERROR ( %s/core/BGP ): malloc() failed (hash_create_size). Exiting ..\n", config.name); // XXX
40     exit_gracefully(1);
41   }
42   memset (hash, 0, sizeof (struct hash));
43   hash->index = malloc(sizeof (struct hash_backet *) * size);
44   if (!hash->index) {
45     Log(LOG_ERR, "ERROR ( %s/core/BGP ): malloc() failed (hash_create_size). Exiting ..\n", config.name); // XXX
46     exit_gracefully(1);
47   }
48   memset (hash->index, 0, sizeof (struct hash_backet *) * size);
49   hash->size = size;
50   hash->hash_key = hash_key;
51   hash->hash_cmp = hash_cmp;
52   hash->count = 0;
53 
54   return hash;
55 }
56 
57 /* Allocate a new hash with default hash size.  */
58 struct hash *
hash_create(int buckets,unsigned int (* hash_key)(void *),int (* hash_cmp)(const void *,const void *))59 hash_create (int buckets, unsigned int (*hash_key) (void *),
60              int (*hash_cmp) (const void *, const void *))
61 {
62   return hash_create_size (buckets, hash_key, hash_cmp);
63 }
64 
65 /* Utility function for hash_get().  When this function is specified
66    as alloc_func, return arugment as it is.  This function is used for
67    intern already allocated value.  */
68 void *
hash_alloc_intern(void * arg)69 hash_alloc_intern (void *arg)
70 {
71   return arg;
72 }
73 
74 /* Lookup and return hash backet in hash.  If there is no
75    corresponding hash backet and alloc_func is specified, create new
76    hash backet.  */
77 void *
hash_get(struct bgp_peer * peer,struct hash * hash,void * data,void * (* alloc_func)(void *))78 hash_get (struct bgp_peer *peer, struct hash *hash, void *data, void * (*alloc_func) (void *))
79 {
80   struct bgp_misc_structs *bms;
81   unsigned int key;
82   unsigned int index;
83   void *newdata;
84   struct hash_backet *backet;
85 
86   if (!peer) return NULL;
87 
88   bms = bgp_select_misc_db(peer->type);
89 
90   if (!bms) return NULL;
91 
92   key = (*hash->hash_key) (data);
93   index = key % hash->size;
94 
95   for (backet = hash->index[index]; backet != NULL; backet = backet->next)
96     if (backet->key == key && (*hash->hash_cmp) (backet->data, data))
97       return backet->data;
98 
99   if (alloc_func)
100     {
101       newdata = (*alloc_func) (data);
102       if (!newdata) {
103         Log(LOG_ERR, "ERROR ( %s/%s ): alloc_func failed (hash_get). Exiting ..\n", config.name, bms->log_str);
104         exit_gracefully(1);
105       }
106 
107       backet = malloc(sizeof (struct hash_backet));
108       if (!backet) {
109         Log(LOG_ERR, "ERROR ( %s/%s ): malloc() failed (hash_get). Exiting ..\n", config.name, bms->log_str);
110         exit_gracefully(1);
111       }
112       memset(backet, 0, sizeof (struct hash_backet));
113       backet->data = newdata;
114       backet->key = key;
115       backet->next = hash->index[index];
116       hash->index[index] = backet;
117       hash->count++;
118       return backet->data;
119     }
120 
121   return NULL;
122 }
123 
124 /* This function release registered value from specified hash.  When
125    release is successfully finished, return the data pointer in the
126    hash backet.  */
127 void *
hash_release(struct hash * hash,void * data)128 hash_release (struct hash *hash, void *data)
129 {
130   void *ret;
131   unsigned int key;
132   unsigned int index;
133   struct hash_backet *backet;
134   struct hash_backet *pp;
135 
136   key = (*hash->hash_key) (data);
137   index = key % hash->size;
138 
139   for (backet = pp = hash->index[index]; backet; backet = backet->next)
140     {
141       if (backet->key == key && (*hash->hash_cmp) (backet->data, data))
142 	{
143 	  if (backet == pp)
144 	    hash->index[index] = backet->next;
145 	  else
146 	    pp->next = backet->next;
147 
148 	  ret = backet->data;
149 	  free(backet);
150 	  hash->count--;
151 	  return ret;
152 	}
153       pp = backet;
154     }
155   return NULL;
156 }
157 
158 /* Iterator function for hash.  */
159 void
hash_iterate(struct hash * hash,void (* func)(struct hash_backet *,void *),void * arg)160 hash_iterate (struct hash *hash,
161 	      void (*func) (struct hash_backet *, void *), void *arg)
162 {
163   unsigned int i;
164   struct hash_backet *hb;
165   struct hash_backet *hbnext;
166 
167   for (i = 0; i < hash->size; i++)
168     for (hb = hash->index[i]; hb; hb = hbnext)
169       {
170 	/* get pointer to next hash backet here, in case (*func)
171 	 * decides to delete hb by calling hash_release
172 	 */
173 	hbnext = hb->next;
174 	(*func) (hb, arg);
175       }
176 }
177 
178 /* Clean up hash.  */
179 void
hash_clean(struct hash * hash,void (* free_func)(void *))180 hash_clean (struct hash *hash, void (*free_func) (void *))
181 {
182   unsigned int i;
183   struct hash_backet *hb;
184   struct hash_backet *next;
185 
186   for (i = 0; i < hash->size; i++)
187     {
188       for (hb = hash->index[i]; hb; hb = next)
189 	{
190 	  next = hb->next;
191 
192 	  if (free_func)
193 	    (*free_func) (hb->data);
194 
195 	  free(hb);
196 	  hash->count--;
197 	}
198       hash->index[i] = NULL;
199     }
200 }
201 
202 /* Free hash memory.  You may call hash_clean before call this
203    function.  */
204 void
hash_free(struct hash * hash)205 hash_free (struct hash *hash)
206 {
207   free(hash->index);
208   free(hash);
209 }
210