1
0
mirror of https://code.semirocket.science/wrapsix synced 2024-09-19 23:11:04 +03:00

Revised radix tree

Dropped chunker duplication and created one universal
Rewritten function for deleting entries from the tree
  (limiting the tree to 32 levels)
This commit is contained in:
Michal Zima 2012-04-27 15:25:29 +02:00
parent d7e506abed
commit 9ac06588a8
3 changed files with 54 additions and 85 deletions

View File

@ -85,7 +85,7 @@ struct s_nat *nat_out(radixtree_t *nat_proto6, radixtree_t *nat_proto4,
radixsearch6.port_dst = port_dst; radixsearch6.port_dst = port_dst;
if ((result = (struct s_nat *) radixtree_lookup(nat_proto6, if ((result = (struct s_nat *) radixtree_lookup(nat_proto6,
radixtree_ipv6_chunker, &radixsearch6)) == NULL) { radixtree_chunker, &radixsearch6, sizeof(radixsearch6))) == NULL) {
/* if no connection is found, let's create one */ /* if no connection is found, let's create one */
if ((connection = if ((connection =
(struct s_nat *) malloc(sizeof(struct s_nat))) == NULL) { (struct s_nat *) malloc(sizeof(struct s_nat))) == NULL) {
@ -109,14 +109,14 @@ struct s_nat *nat_out(radixtree_t *nat_proto6, radixtree_t *nat_proto4,
/* returns port from range 1024 - 65535 */ /* returns port from range 1024 - 65535 */
radixsearch4.port_dst = (rand() % 64511) + 1024; radixsearch4.port_dst = (rand() % 64511) + 1024;
result = radixtree_lookup(nat_proto4, radixtree_ipv4_chunker, &radixsearch4); result = radixtree_lookup(nat_proto4, radixtree_chunker, &radixsearch4, sizeof(radixsearch4));
} while (result != NULL); } while (result != NULL);
connection->ipv4_port_src = radixsearch4.port_dst; connection->ipv4_port_src = radixsearch4.port_dst;
/* save this connection to the NAT table (to *both* of them) */ /* save this connection to the NAT table (to *both* of them) */
radixtree_insert(nat_proto6, radixtree_ipv6_chunker, &radixsearch6, connection); radixtree_insert(nat_proto6, radixtree_chunker, &radixsearch6, sizeof(radixsearch6), connection);
radixtree_insert(nat_proto4, radixtree_ipv4_chunker, &radixsearch4, connection); radixtree_insert(nat_proto4, radixtree_chunker, &radixsearch4, sizeof(radixsearch4), connection);
return connection; return connection;
} else { } else {
@ -138,7 +138,7 @@ struct s_nat *nat_in(radixtree_t *nat_proto4, struct s_ipv4_addr ipv4_src,
radixsearch4.port_dst = port_dst; radixsearch4.port_dst = port_dst;
radixsearch4.zeros = 0x0; radixsearch4.zeros = 0x0;
if ((result = (struct s_nat *) radixtree_lookup(nat_proto4, radixtree_ipv4_chunker, &radixsearch4)) == NULL) { if ((result = (struct s_nat *) radixtree_lookup(nat_proto4, radixtree_chunker, &radixsearch4, sizeof(radixsearch4))) == NULL) {
/* when connection is not found, drop the packet */ /* when connection is not found, drop the packet */
return NULL; return NULL;
} else { } else {

View File

@ -52,14 +52,14 @@ void radixtree_destroy(radixtree_t *t, unsigned char depth)
} }
void radixtree_insert(radixtree_t *root, void radixtree_insert(radixtree_t *root,
unsigned char *(chunker)(void *data, unsigned char *count), unsigned char *(chunker)(void *data, unsigned char size, unsigned char *count),
void *search_data, void *data) void *search_data, unsigned char size, void *data)
{ {
radixtree_t *tmp; radixtree_t *tmp;
unsigned char i, chunk_count; unsigned char i, chunk_count;
unsigned char *chunks; unsigned char *chunks;
chunks = chunker(search_data, &chunk_count); chunks = chunker(search_data, size, &chunk_count);
tmp = root; tmp = root;
tmp->count++; tmp->count++;
@ -86,71 +86,57 @@ void radixtree_insert(radixtree_t *root,
} }
void radixtree_delete(radixtree_t *root, void radixtree_delete(radixtree_t *root,
unsigned char *(chunker)(void *data, unsigned char *count), unsigned char *(chunker)(void *data, unsigned char size, unsigned char *count),
void *data) void *data, unsigned char size)
{ {
radixtree_t *tmp, radixtree_t *tmp,
*next; *next;
unsigned char i, chunk_count; unsigned char i, chunk_count;
unsigned char *chunks; unsigned char *chunks;
unsigned int flags = 0;
chunks = chunker(data, &chunk_count); chunks = chunker(data, size, &chunk_count);
for (i = 0, tmp = root; i < chunk_count && tmp != NULL; i++, tmp = tmp->array[chunks[i]]) {
flags = tmp->count == 1 ? flags | (0x1 << i) : 0;
if (i + 1 == chunk_count) {
break;
}
}
/* if was at leaf, decrement counter */
if (i + 1 == chunk_count) {
tmp->count--;
}
tmp = root; tmp = root;
tmp->count--; flags &= 0xfffffffe; /* unflag root */
for (i = 0; i < chunk_count; i++) { for (i = 0; i < chunk_count; i++) {
unsigned char id; next = tmp->array[chunks[i]];
if (flags & (0x1 << (i + 1))) {
id = chunks[i]; tmp->array[chunks[i]] = NULL;
tmp->count--;
/* already deleted? may cause data inconsistency! */
if (tmp->array[id] == NULL) {
return;
} }
if (flags & (0x1 << i)) {
if (i == chunk_count - 1) {
if (tmp->count == 0) {
free(tmp);
} else {
tmp->array[id] = NULL;
}
/**
* now you *have to* call free on data too
* but probably not here...
**/
return;
}
next = tmp->array[id];
/* if it is the last entry in this tree branch */
if (next->count == 1) {
tmp->array[id] = NULL;
}
if (i != 0 && tmp->count == 0) {
free(tmp); free(tmp);
} }
tmp = next; tmp = next;
tmp->count--;
} }
free(chunks); free(chunks);
} }
void *radixtree_lookup(radixtree_t *root, void *radixtree_lookup(radixtree_t *root,
unsigned char *(chunker)(void *data, unsigned char *count), unsigned char *(chunker)(void *data, unsigned char size, unsigned char *count),
void *data) void *data, unsigned char size)
{ {
radixtree_t *tmp; radixtree_t *tmp;
unsigned char i, chunk_count, id; unsigned char i, chunk_count, id;
unsigned char *chunks; unsigned char *chunks;
chunks = chunker(data, &chunk_count); chunks = chunker(data, size, &chunk_count);
tmp = root; tmp = root;
@ -177,14 +163,24 @@ void *radixtree_lookup(radixtree_t *root,
/* we never get here ;c) */ /* we never get here ;c) */
} }
unsigned char *radixtree_ipv6_chunker(void *data, unsigned char *count) /**
* Universal chunker.
*
* @param data Data to chunk
* @param size Size of the data; must be divisible by 3
* @param count Variable into which is put information about number of
* chunks produced
*
* @return Array of chunks
*/
unsigned char *radixtree_chunker(void *data, unsigned char size, unsigned char *count)
{ {
short i; short i;
unsigned char counter; unsigned char counter;
unsigned char *chunks; unsigned char *chunks;
unsigned char *cdata = (unsigned char *) data; unsigned char *cdata = (unsigned char *) data;
counter = 192 / 6; counter = size * 8 / 6;
memcpy(count, &counter, sizeof(unsigned char)); memcpy(count, &counter, sizeof(unsigned char));
if ((chunks = (unsigned char *) malloc(counter * sizeof(unsigned char))) == NULL) { if ((chunks = (unsigned char *) malloc(counter * sizeof(unsigned char))) == NULL) {
@ -202,33 +198,7 @@ unsigned char *radixtree_ipv6_chunker(void *data, unsigned char *count)
* 240 == 1111 0000 == 0xf0 * 240 == 1111 0000 == 0xf0
* 252 == 1111 1100 == 0xfc * 252 == 1111 1100 == 0xfc
*/ */
for (i = 0, counter = 0; counter < *count; i++) { /* processes 3 bytes at a time */
chunks[counter++] = cdata[i] & 0x3f;
chunks[counter++] = ((cdata[i] & 0xc0) >> 6) | ((cdata[i + 1] & 0x0f) << 2);
i++;
chunks[counter++] = ((cdata[i] & 0xf0) >> 4) | ((cdata[i + 1] & 0x03) << 4);
i++;
chunks[counter++] = ((cdata[i] & 0xfc) >> 2);
}
return chunks;
}
unsigned char *radixtree_ipv4_chunker(void *data, unsigned char *count)
{
short i;
unsigned char counter;
unsigned char *chunks;
unsigned char *cdata = (unsigned char *) data;
counter = 72 / 6;
memcpy(count, &counter, sizeof(unsigned char));
if ((chunks = (unsigned char *) malloc(counter * sizeof(unsigned char))) == NULL) {
fprintf(stderr, "[Error] Lack of free memory\n");
return NULL;
}
for (i = 0, counter = 0; counter < *count; i++) { for (i = 0, counter = 0; counter < *count; i++) {
chunks[counter++] = cdata[i] & 0x3f; chunks[counter++] = cdata[i] & 0x3f;
chunks[counter++] = ((cdata[i] & 0xc0) >> 6) | ((cdata[i + 1] & 0x0f) << 2); chunks[counter++] = ((cdata[i] & 0xc0) >> 6) | ((cdata[i + 1] & 0x0f) << 2);

View File

@ -30,15 +30,14 @@ typedef struct radixtree {
radixtree_t *radixtree_create(void); radixtree_t *radixtree_create(void);
void radixtree_destroy(radixtree_t *t, unsigned char depth); void radixtree_destroy(radixtree_t *t, unsigned char depth);
void radixtree_insert(radixtree_t *root, void radixtree_insert(radixtree_t *root,
unsigned char *(chunker)(void *data, unsigned char *count), unsigned char *(chunker)(void *data, unsigned char size, unsigned char *count),
void *search_data, void *data); void *search_data, unsigned char size, void *data);
void radixtree_delete(radixtree_t *root, void radixtree_delete(radixtree_t *root,
unsigned char *(chunker)(void *data, unsigned char *count), unsigned char *(chunker)(void *data, unsigned char size, unsigned char *count),
void *data); void *data, unsigned char size);
void *radixtree_lookup(radixtree_t *root, void *radixtree_lookup(radixtree_t *root,
unsigned char *(chunker)(void *data, unsigned char *count), unsigned char *(chunker)(void *data, unsigned char size, unsigned char *count),
void *data); void *data, unsigned char size);
unsigned char *radixtree_ipv6_chunker(void *data, unsigned char *count); unsigned char *radixtree_chunker(void *data, unsigned char size, unsigned char *count);
unsigned char *radixtree_ipv4_chunker(void *data, unsigned char *count);
#endif /* RADIXTREE_H */ #endif /* RADIXTREE_H */