-
Notifications
You must be signed in to change notification settings - Fork 36
/
poptrie.c
175 lines (157 loc) · 4.33 KB
/
poptrie.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/*_
* Copyright (c) 2014-2017 Hirochika Asai <[email protected]>
* All rights reserved.
*/
#include "buddy.h"
#include "poptrie.h"
#include <stdlib.h>
#include <string.h>
#define INDEX(a, s, n) \
(((u64)(a) << 32 >> (64 - ((s) + (n)))) & ((1 << (n)) - 1))
#define KEYLENGTH 32
/* Prototype declaration */
static void _release_radix(struct radix_node *);
/*
* Initialize the poptrie data structure
*/
struct poptrie *
poptrie_init(struct poptrie *poptrie, int sz1, int sz0)
{
int ret;
int i;
if ( NULL == poptrie ) {
/* Allocate new one */
poptrie = malloc(sizeof(struct poptrie));
if ( NULL == poptrie ) {
return NULL;
}
(void)memset(poptrie, 0, sizeof(struct poptrie));
/* Set the flag indicating that this data structure needs free() when
released. */
poptrie->_allocated = 1;
} else {
/* Write zero's */
(void)memset(poptrie, 0, sizeof(struct poptrie));
}
/* Allocate the nodes and leaves */
poptrie->nodes = malloc(sizeof(poptrie_node_t) * (1 << sz1));
if ( NULL == poptrie->nodes ) {
poptrie_release(poptrie);
return NULL;
}
poptrie->leaves = malloc(sizeof(poptrie_leaf_t) * (1 << sz0));
if ( NULL == poptrie->leaves ) {
poptrie_release(poptrie);
return NULL;
}
/* Prepare the buddy system for the internal node array */
poptrie->cnodes = malloc(sizeof(struct buddy));
if ( NULL == poptrie->cnodes ) {
poptrie_release(poptrie);
return NULL;
}
ret = buddy_init(poptrie->cnodes, sz1, sz1, sizeof(u32));
if ( ret < 0 ) {
free(poptrie->cnodes);
poptrie->cnodes = NULL;
poptrie_release(poptrie);
return NULL;
}
/* Prepare the buddy system for the leaf node array */
poptrie->cleaves = malloc(sizeof(struct buddy));
if ( NULL == poptrie->cleaves ) {
poptrie_release(poptrie);
return NULL;
}
ret = buddy_init(poptrie->cleaves, sz0, sz0, sizeof(u32));
if ( ret < 0 ) {
free(poptrie->cnodes);
poptrie->cnodes = NULL;
poptrie_release(poptrie);
return NULL;
}
/* Prepare the direct pointing array */
poptrie->dir = malloc(sizeof(u32) << POPTRIE_S);
if ( NULL == poptrie->dir ) {
poptrie_release(poptrie);
return NULL;
}
for ( i = 0; i < (1 << POPTRIE_S); i++ ) {
poptrie->dir[i] = (u32)1 << 31;
}
/* Prepare the alternative direct pointing array for the update procedure */
poptrie->altdir = malloc(sizeof(u32) << POPTRIE_S);
if ( NULL == poptrie->altdir ) {
poptrie_release(poptrie);
return NULL;
}
/* Prepare the FIB mapping table */
poptrie->fib.entries = malloc(sizeof(struct poptrie_fib_entry)
* POPTRIE_INIT_FIB_SIZE);
if ( NULL == poptrie->fib.entries ) {
poptrie_release(poptrie);
return NULL;
}
memset(poptrie->fib.entries, 0, sizeof(struct poptrie_fib_entry)
* POPTRIE_INIT_FIB_SIZE);
poptrie->fib.sz = POPTRIE_INIT_FIB_SIZE;
/* Insert a NULL entry as the default route */
poptrie->fib.entries[0].entry = NULL;
poptrie->fib.entries[0].refs = 1;
return poptrie;
}
/*
* Release the poptrie data structure
*/
void
poptrie_release(struct poptrie *poptrie)
{
/* Release the radix tree */
_release_radix(poptrie->radix);
if ( poptrie->nodes ) {
free(poptrie->nodes);
}
if ( poptrie->leaves ) {
free(poptrie->leaves);
}
if ( poptrie->cnodes ) {
buddy_release(poptrie->cnodes);
free(poptrie->cnodes);
}
if ( poptrie->cleaves ) {
buddy_release(poptrie->cleaves);
free(poptrie->cleaves);
}
if ( poptrie->dir ) {
free(poptrie->dir);
}
if ( poptrie->altdir ) {
free(poptrie->altdir);
}
if ( poptrie->fib.entries ) {
free(poptrie->fib.entries);
}
if ( poptrie->_allocated ) {
free(poptrie);
}
}
/*
* Free the allocated memory by the radix tree
*/
static void
_release_radix(struct radix_node *node)
{
if ( NULL != node ) {
_release_radix(node->left);
_release_radix(node->right);
free(node);
}
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: sw=4 ts=4 fdm=marker
* vim<600: sw=4 ts=4
*/