blob: 3ad5c04bb33b750ac24b54a803eb043e3936820a [file] [log] [blame]
jjakoa7cd2492003-04-11 09:40:12 +00001/*
2 * IP address pool functions.
3 * Copyright (C) 2003 Mondru AB.
4 *
5 * The contents of this file may be used under the terms of the GNU
6 * General Public License Version 2, provided that the above copyright
7 * notice and this permission notice is included in all copies or
8 * substantial portions of the software.
9 *
10 * The initial developer of the original code is
11 * Jens Jakobsen <jj@openggsn.org>
12 *
13 * Contributor(s):
14 *
15 */
16
17#include <netinet/in.h> /* in_addr */
18#include <stdlib.h> /* calloc */
19#include <stdio.h> /* sscanf */
20
21#include "ippool.h"
22
23
24/*
25--------------------------------------------------------------------
26Public domain by From Bob Jenkins, December 1996.
27mix -- mix 3 32-bit values reversibly.
28For every delta with one or two bit set, and the deltas of all three
29 high bits or all three low bits, whether the original value of a,b,c
30 is almost all zero or is uniformly distributed,
31* If mix() is run forward or backward, at least 32 bits in a,b,c
32 have at least 1/4 probability of changing.
33* If mix() is run forward, every bit of c will change between 1/3 and
34 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.)
35mix() was built out of 36 single-cycle latency instructions in a
36 structure that could supported 2x parallelism, like so:
37 a -= b;
38 a -= c; x = (c>>13);
39 b -= c; a ^= x;
40 b -= a; x = (a<<8);
41 c -= a; b ^= x;
42 c -= b; x = (b>>13);
43 ...
44 Unfortunately, superscalar Pentiums and Sparcs can't take advantage
45 of that parallelism. They've also turned some of those single-cycle
46 latency instructions into multi-cycle latency instructions. Still,
47 this is the fastest good hash I could find. There were about 2^^68
48 to choose from. I only looked at a billion or so.
49--------------------------------------------------------------------
50*/
51#define mix(a,b,c) \
52{ \
53 a -= b; a -= c; a ^= (c>>13); \
54 b -= c; b -= a; b ^= (a<<8); \
55 c -= a; c -= b; c ^= (b>>13); \
56 a -= b; a -= c; a ^= (c>>12); \
57 b -= c; b -= a; b ^= (a<<16); \
58 c -= a; c -= b; c ^= (b>>5); \
59 a -= b; a -= c; a ^= (c>>3); \
60 b -= c; b -= a; b ^= (a<<10); \
61 c -= a; c -= b; c ^= (b>>15); \
62}
63/*
64--------------------------------------------------------------------
65lookup() -- hash a variable-length key into a 32-bit value
66 k : the key (the unaligned variable-length array of bytes)
67 len : the length of the key, counting by bytes
68 level : can be any 4-byte value
69Returns a 32-bit value. Every bit of the key affects every bit of
70the return value. Every 1-bit and 2-bit delta achieves avalanche.
71About 6len+35 instructions.
72
73The best hash table sizes are powers of 2. There is no need to do
74mod a prime (mod is sooo slow!). If you need less than 32 bits,
75use a bitmask. For example, if you need only 10 bits, do
76 h = (h & hashmask(10));
77In which case, the hash table should have hashsize(10) elements.
78
79If you are hashing n strings (ub1 **)k, do it like this:
80 for (i=0, h=0; i<n; ++i) h = lookup( k[i], len[i], h);
81
82By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use this
83code any way you wish, private, educational, or commercial.
84
85See http://burtleburtle.net/bob/hash/evahash.html
86Use for hash table lookup, or anything where one collision in 2^32 is
87acceptable. Do NOT use for cryptographic purposes.
88--------------------------------------------------------------------
89*/
90
91unsigned long int lookup( k, length, level)
92register unsigned char *k; /* the key */
93register unsigned long int length; /* the length of the key */
94register unsigned long int level; /* the previous hash, or an arbitrary value */
95{
96 register unsigned long int a,b,c,len;
97
98 /* Set up the internal state */
99 len = length;
100 a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
101 c = level; /* the previous hash value */
102
103 /*---------------------------------------- handle most of the key */
104 while (len >= 12)
105 {
106 a += (k[0] +((ub4)k[1]<<8) +((ub4)k[2]<<16) +((ub4)k[3]<<24));
107 b += (k[4] +((ub4)k[5]<<8) +((ub4)k[6]<<16) +((ub4)k[7]<<24));
108 c += (k[8] +((ub4)k[9]<<8) +((ub4)k[10]<<16)+((ub4)k[11]<<24));
109 mix(a,b,c);
110 k += 12; len -= 12;
111 }
112
113 /*------------------------------------- handle the last 11 bytes */
114 c += length;
115 switch(len) /* all the case statements fall through */
116 {
117 case 11: c+=((ub4)k[10]<<24);
118 case 10: c+=((ub4)k[9]<<16);
119 case 9 : c+=((ub4)k[8]<<8);
120 /* the first byte of c is reserved for the length */
121 case 8 : b+=((ub4)k[7]<<24);
122 case 7 : b+=((ub4)k[6]<<16);
123 case 6 : b+=((ub4)k[5]<<8);
124 case 5 : b+=k[4];
125 case 4 : a+=((ub4)k[3]<<24);
126 case 3 : a+=((ub4)k[2]<<16);
127 case 2 : a+=((ub4)k[1]<<8);
128 case 1 : a+=k[0];
129 /* case 0: nothing left to add */
130 }
131 mix(a,b,c);
132 /*-------------------------------------------- report the result */
133 return c;
134}
135
136/*
137End of public domain code by From Bob Jenkins, December 1996.
138--------------------------------------------------------------------
139*/
140
141int ippool_printaddr(struct ippool_t *this) {
142 int n;
143 printf("ippool_printaddr\n");
144 printf("First %d\n", this->first - this->member);
145 printf("Last %d\n", this->last - this->member);
146 printf("Listsize %d\n", this->listsize);
147
148 for (n=0; n<this->listsize; n++) {
149 printf("Unit %d inuse %d prev %d next %d addr %x\n",
150 n,
151 this->member[n].inuse,
152 this->member[n].prev - this->member,
153 this->member[n].next - this->member,
154 this->member[n].addr.s_addr
155 );
156 }
157 return 0;
158}
159
160
161unsigned long int ippool_hash4(struct in_addr *addr) {
162 return lookup(&addr->s_addr, sizeof(addr->s_addr), 0);
163}
164
165#ifndef IPPOOL_NOIP6
166unsigned long int ippool_hash6(struct in6_addr *addr) {
167 return lookup(addr->u6_addr8, sizeof(addr->u6_addr8), 0);
168}
169#endif
170
171
172/* Get IP address and mask */
173int ippool_aton(struct in_addr *addr, struct in_addr *mask,
174 char *pool, int number) {
175
176 /* Parse only first instance of network for now */
177 /* Eventually "number" will indicate the token which we want to parse */
178
179 unsigned int a1, a2, a3, a4;
180 unsigned int m1, m2, m3, m4;
181 int c;
182 unsigned int m;
183 int masklog;
184
185 c = sscanf(pool, "%u.%u.%u.%u/%u.%u.%u.%u",
186 &a1, &a2, &a3, &a4,
187 &m1, &m2, &m3, &m4);
188 switch (c) {
189 case 4:
190 if (a1 == 0 && a2 == 0 && a3 == 0 && a4 == 0) /* Full Internet */
191 mask->s_addr = 0x00000000;
192 else if (a2 == 0 && a3 == 0 && a4 == 0) /* class A */
193 mask->s_addr = htonl(0xff000000);
194 else if (a3 == 0 && a4 == 0) /* class B */
195 mask->s_addr = htonl(0xffff0000);
196 else if (a4 == 0) /* class C */
197 mask->s_addr = htonl(0xffffff00);
198 else
199 mask->s_addr = 0xffffffff;
200 break;
201 case 5:
202 if (m1 < 0 || m1 > 32) {
203 return -1; /* Invalid mask */
204 }
205 mask->s_addr = htonl(0xffffffff << (32 - m1));
206 break;
207 case 8:
208 if (m1 >= 256 || m2 >= 256 || m3 >= 256 || m4 >= 256)
209 return -1; /* Wrong mask format */
210 m = m1 * 0x1000000 + m2 * 0x10000 + m3 * 0x100 + m4;
211 for (masklog = 0; ((1 << masklog) < ((~m)+1)); masklog++);
212 if (((~m)+1) != (1 << masklog))
213 return -1; /* Wrong mask format (not all ones followed by all zeros)*/
214 mask->s_addr = htonl(m);
215 break;
216 default:
217 return -1; /* Invalid mask */
218 }
219
220 if (a1 >= 256 || a2 >= 256 || a3 >= 256 || a4 >= 256)
221 return -1; /* Wrong IP address format */
222 else
223 addr->s_addr = htonl(a1 * 0x1000000 + a2 * 0x10000 + a3 * 0x100 + a4);
224
225 return 0;
226}
227
228/* Create new address pool */
229int ippool_new(struct ippool_t **this, char *pool, int flags) {
230
231 /* Parse only first instance of network for now */
232
233 int i;
234 struct ippoolm_t *p;
235 struct ippoolm_t *p_prev = NULL;
236 uint32_t hash;
237 struct in_addr addr;
238 struct in_addr mask;
239 unsigned int m;
240 unsigned int listsize;
241
242 if (ippool_aton(&addr, &mask, pool, 0))
243 return 0; /* Failed to parse pool */
244
245 m = ntohl(mask.s_addr);
246 listsize = ((~m)+1);
247 if (flags & IPPOOL_NONETWORK) /* Exclude network address from pool */
248 listsize--;
249 if (flags & IPPOOL_NOBROADCAST) /* Exclude broadcast address from pool */
250 listsize--;
251
252 if (!(*this = calloc(sizeof(struct ippool_t), 1))) {
253 /* Failed to allocate memory for ippool */
254 return -1;
255 }
256
257 (*this)->listsize += listsize;
258 if (!((*this)->member = calloc(sizeof(struct ippoolm_t), (*this)->listsize))){
259 /* Failed to allocate memory for members in ippool */
260 return -1;
261 }
262
263 for ((*this)->hashlog = 0;
264 ((1 << (*this)->hashlog) < listsize);
265 (*this)->hashlog++);
266
267 /* printf ("Hashlog %d %d %d\n", (*this)->hashlog, listsize, (1 << (*this)->hashlog)); */
268
269 /* Determine hashsize */
270 (*this)->hashsize = 1 << (*this)->hashlog; /* Fails if mask=0: All Internet*/
271 (*this)->hashmask = (*this)->hashsize -1;
272
273 /* Allocate hash table */
274 if (!((*this)->hash = calloc(sizeof(struct ippoolm_t), (*this)->hashsize))){
275 /* Failed to allocate memory for hash members in ippool */
276 return -1;
277 }
278
279 (*this)->first = NULL;
280 (*this)->last = NULL;
281 for (i = 0; i<(*this)->listsize; i++) {
282
283 if (flags & IPPOOL_NONETWORK)
284 (*this)->member[i].addr.s_addr = htonl(ntohl(addr.s_addr) + i + 1);
285 else
286 (*this)->member[i].addr.s_addr = htonl(ntohl(addr.s_addr) + i);
287
288 (*this)->member[i].inuse = 0;
289 (*this)->member[i].parent = *this;
290
291 /* Insert into list of unused */
292 (*this)->member[i].prev = (*this)->last;
293 if ((*this)->last) {
294 (*this)->last->next = &((*this)->member[i]);
295 }
296 else {
297 (*this)->first = &((*this)->member[i]);
298 }
299 (*this)->last = &((*this)->member[i]);
300 (*this)->member[i].next = NULL; /* Redundant */
301
302 /* Insert into hash table */
303 hash = ippool_hash4(&(*this)->member[i].addr) & (*this)->hashmask;
304 for (p = (*this)->hash[hash]; p; p = p->nexthash)
305 p_prev = p;
306 if (!p_prev)
307 (*this)->hash[hash] = &((*this)->member[i]);
308 else
309 p_prev->nexthash = &((*this)->member[i]);
310 }
311 /*ippool_printaddr(*this);*/
312 return 0;
313}
314
315/* Delete existing address pool */
316int ippool_free(struct ippool_t *this) {
317 free(this->hash);
318 free(this->member);
319 free(this);
320 return 0; /* Always OK */
321}
322
323/* Find an IP address in the pool */
324int ippool_getip(struct ippool_t *this, struct ippoolm_t **member,
325 struct in_addr *addr) {
326 struct ippoolm_t *p;
327 uint32_t hash;
328
329 /* Find in hash table */
330 hash = ippool_hash4(addr) & this->hashmask;
331 for (p = this->hash[hash]; p; p = p->nexthash) {
332 if ((p->addr.s_addr == addr->s_addr) && (p->inuse)) {
333 *member = p;
334 return 0;
335 }
336 }
337 *member = NULL;
338 return -1; /* Address could not be found */
339}
340
341
342/* Get an IP address. If addr = 0.0.0.0 get a dynamic IP address. Otherwise
343 check to see if the given address is available */
344int ippool_newip(struct ippool_t *this, struct ippoolm_t **member,
345 struct in_addr *addr) {
346 struct ippoolm_t *p;
347 struct ippoolm_t *p2 = NULL;
348 uint32_t hash;
349
350 /*ippool_printaddr(this);*/
351
352 if ((addr) && (addr->s_addr)) { /* IP address given */
353 /* Find in hash table */
354 hash = ippool_hash4(addr) & this->hashmask;
355 for (p = this->hash[hash]; p; p = p->nexthash) {
356 if ((p->addr.s_addr == addr->s_addr)) {
357 p2 = p;
358 break;
359 }
360 }
361 }
362 else { /* No ip address given */
363 p2 = this -> first;
364 }
365
366 if (!p2) return -1; /* Not found */
367 if (p2->inuse) return -1; /* Allready in use / Should not happen */
368
369 /* Found new address. Remove from queue */
370 if (p2->prev)
371 p2->prev->next = p2->next;
372 else
373 this->first = p2->next;
374 if (p2->next)
375 p2->next->prev = p2->prev;
376 else
377 this->last = p2->prev;
378 p2->next = NULL;
379 p2->prev = NULL;
380 p2->inuse = 1;
381
382 *member = p2;
383 /*ippool_printaddr(this);*/
384 return 0; /* Success */
385}
386
387
388int ippool_freeip(struct ippoolm_t *member) {
389 struct ippool_t *this = member->parent;
390
391 /*ippool_printaddr(this);*/
392
393 if (!member->inuse) return -1; /* Not in use: Should not happen */
394
395 /* Insert into list of unused */
396 member->prev = this->last;
397 if (this->last) {
398 this->last->next = member;
399 }
400 else {
401 this->first = member;
402 }
403 this->last = member;
404
405 member->inuse = 0;
406 /*ippool_printaddr(this);*/
407
408 return 0; /* Success */
409}
410
411
412#ifndef IPPOOL_NOIP6
413extern unsigned long int ippool_hash6(struct in6_addr *addr);
414extern int ippool_getip6(struct ippool_t *this, struct in6_addr *addr);
415extern int ippool_returnip6(struct ippool_t *this, struct in6_addr *addr);
416#endif