1 | /***************************************
2 | $Revision: 1.10 $
3 |
4 | Radix tree (rx). rx_tree.c - functions to operate on trees
5 | (creation/deletion/finding).
6 |
7 | Status: NOT REVUED, TESTED, INCOMPLETE
8 |
9 | Design and implementation by: Marek Bukowy
10 |
11 | ******************/ /******************
12 | Copyright (c) 1999 RIPE NCC
13 |
14 | All Rights Reserved
15 |
16 | Permission to use, copy, modify, and distribute this software and its
17 | documentation for any purpose and without fee is hereby granted,
18 | provided that the above copyright notice appear in all copies and that
19 | both that copyright notice and this permission notice appear in
20 | supporting documentation, and that the name of the author not be
21 | used in advertising or publicity pertaining to distribution of the
22 | software without specific, written prior permission.
23 |
24 | THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
25 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
26 | AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
27 | DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
28 | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
29 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
30 | ***************************************/
31 |
32 | #include <erroutines.h>
33 | #include <iproutines.h>
34 | #include <memwrap.h>
35 | #include <stubs.h>
36 |
37 | /***************************************************************************/
38 |
39 | #define RX_IMPL
40 |
41 | #include <rxroutines.h>
42 | /***************************************************************************/
43 |
44 |
45 | /*+++++++++
46 | go down the tree calling func on every node.
47 | (func takes the node pointer and the current level)
48 |
49 | the function is called recursively with level increased
50 | it stops recursing when no child nodes are found or maxlevel is reached.
51 |
52 | therefore the initial call must set level to 0.
53 |
54 | the nodecounter increments at every node, and is the return value
55 | of the function. So start with 0 to get the number of nodes traversed.
56 |
57 | ERROR HANDLING IS DIFFERENT HERE!
58 | Unlike other functions it is not the return value:
59 | The error code from the func function IF DEFINED (== not NULL ) goes
60 | to the variable pointed to by the last parameter.
61 | ++++++++++++*/
62 | int
63 | rx_walk_tree(rx_node_t *node,
64 | er_ret_t (*func)(rx_node_t *node, int level, int nodecounter,
65 | void *userptr),
66 | rx_walk_mt walk_mode,
67 | // controls if glue nodes are counted
68 | // and if levels or prefix lenghts are checked
69 | int maxlevel,
70 | int level,
71 | int nodecounter,
72 | void *userptr,
73 | er_ret_t *err)
74 | {
75 | int i, link;
76 |
77 | if( node == NULL ) die; // program error. we expect a valid, checked, node.
78 |
79 | // count the node appropriately:
80 | // if (not glue) or (it doesn't matter)
81 |
82 | if( node->glue == 0 || (walk_mode & RX_WALK_SKPGLU) == 0 ) {
83 | level++;
84 | }
85 |
86 | // check the limits and maybe quit here: prefix length for RX_WALK_PRFLEN,
87 | // level otherwise
88 |
89 | if(walk_mode & RX_WALK_PRFLEN) {
90 | if(node->prefix.bits > maxlevel) {
91 | return nodecounter;
92 | }
93 | }
94 | else if( level > maxlevel ) {
95 | return nodecounter;
96 | }
97 |
98 | // didn't quit ?? OK, count it too...
99 | nodecounter++;
100 |
101 | if( func != NULL ) {
102 | *err = func(node, level, nodecounter, userptr);
103 |
104 | // abort the walk on error
105 | if( *err != RX_OK ) {
106 | ER_dbg_va(FAC_RX, ASP_RX_TREE_WALK,
107 | "walk_tree: func returned error %d, aborting", *err);
108 | return nodecounter;
109 | }
110 | }
111 |
112 |
113 | for(i=0; i<=1; i++) {
114 |
115 | // reverse the sense of the walk
116 | link = ( walk_mode & RX_WALK_REVERS ) ? ! i : i;
117 |
118 | if( node->child_ptr[link] != NULL ) {
119 | nodecounter += rx_walk_tree(node->child_ptr[link], func, walk_mode,
120 | maxlevel, level, 0, userptr, err);
121 | // abort the walk on error
122 | if( func != NULL && *err != RX_OK ) {
123 | break;
124 | }
125 | }
126 | }
127 |
128 | return nodecounter;
129 | }
130 |
131 |
132 |
133 |
134 | /***************************************************************************/
135 | /*++++++++++++++
136 | finds a tree matching the specified criteria(registry+space+family).
137 |
138 | MT-note: locks/unlocks forest (still to be done)
139 |
140 | Returns: RX_OK or RX_NOTREE if no such tree can be found.
141 | +++++++++++*/
142 |
143 | er_ret_t
144 | RX_get_tree ( rx_tree_t **treeptr, /*+ answer goes here, please +*/
145 | rx_regid_t reg_id, /*+ id of the registry +*/
146 | ip_space_t spc_id, /*+ type of space (ipv4/ipv6) +*/
147 | rx_fam_t fam_id /*+ family of objects (route/inetnum) +*/
148 | )
149 |
150 | {
151 | GList *elem = g_list_first(rx_forest);
152 | rx_tree_t *trp;
153 |
154 | while( elem != NULL ) {
155 | trp = (rx_tree_t *) elem->data;
156 |
157 | if( trp->reg_id == reg_id
158 | && trp->space == spc_id && trp->family == fam_id) {
159 | /* copy the value to user's data */
160 | *treeptr = trp;
161 | ER_dbg_va(FAC_RX, ASP_RX_TREE_BOT, "tree found at %08x",trp);
162 |
163 | return RX_OK;
164 | }
165 | elem = g_list_next(elem);
166 | }
167 |
168 | *treeptr = NULL; // set no NOT FOUND
169 | return RX_NOTREE;
170 | }
171 |
172 |
173 | /***************************************************************************/
174 | /*++++++
175 | creates a (top) tree for the space, fills out sql table of trees
176 | generates a tablename for a tree (if NONE)
177 | updates LL of trees
178 |
179 | MT-note: locks/unlocks the forest (still to be done)
180 |
181 | ++++++++*/
182 | er_ret_t
183 | RX_space_cre (
184 | rx_regid_t reg_id, /*+ id of the registry +*/
185 | ip_space_t spc_id, /*+ space id, one of IPv4 IPv6. +*/
186 | rx_fam_t fam_id, /*+ family of objects (route/inetnum) +*/
187 | char *prefixstr, /*+ prefix the tree will cover (string) +*/
188 | rx_mem_mt mem_mode, /* memory only, memory+sql, sql only +*/
189 | rx_subtree_mt subtrees /*+ one of NONE, AUTO, HAND +*/
190 | )
191 |
192 | {
193 | er_ret_t err;
194 | rx_tree_t *newtree;
195 | ip_prefix_t newpref;
196 |
197 | if( IP_pref_e2b(&newpref, prefixstr) != IP_OK ) {
198 | die;
199 | }
200 |
201 | RX_get_tree ( &newtree, reg_id, spc_id, fam_id);
202 |
203 | if ( newtree != NULL ) {
204 | // die; /* error RX_TRALEX == tree already exists */
205 | return RX_TRALEX;
206 | }
207 |
208 | /* set forest mutex; */
209 |
210 | if ( (err=wr_malloc( (void **) & newtree, sizeof(rx_tree_t))) != UT_OK ) {
211 | return err; // die
212 | }
213 |
214 | ER_dbg_va(FAC_RX, ASP_RX_TREE_BOT, "creating a tree at %08x", newtree);
215 |
216 | /* copy tree settings */
217 |
218 | newtree -> reg_id = reg_id;
219 | newtree -> space = spc_id;
220 | newtree -> family = fam_id;
221 | newtree -> subtrees = subtrees;
222 | newtree -> mem_mode = mem_mode;
223 |
224 | /* set other tree values */
225 |
226 | /* parent set to NULL because it's not a subtree */
227 | newtree -> parent_tree = NULL;
228 | // PR_zeroprefix(& newtree -> prefix);
229 | newtree -> maxbits = IP_sizebits(spc_id);
230 |
231 | strcpy(newtree->data_table.val,"");
232 | strcpy(newtree->radix_table.val,"");
233 | strcpy(newtree->leaves_table.val,"");
234 |
235 | newtree->num_nodes = 0;
236 |
237 | newtree->top_ptr = NULL;
238 | newtree->top_key = SQ_NOKEY;
239 |
240 | newtree->prefix = newpref;
241 |
242 | /* put into LL of trees; handle alloc err ??? */
243 |
244 | rx_forest = g_list_append (rx_forest, newtree);
245 |
246 | /* release forest mutex; */
247 | return RX_OK;
248 | }
249 |