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