1 | /***************************************
2 | $Revision: 1.11 $
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, skpglue=0;
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 | } else { /* nodeglue = 1 && walkmode&skpglue = 1 */
85 | skpglue = 1;
86 | }
87 |
88 | // check the limits and maybe quit here: prefix length for RX_WALK_PRFLEN,
89 | // level otherwise
90 |
91 | if(walk_mode & RX_WALK_PRFLEN) {
92 | if(node->prefix.bits > maxlevel) {
93 | return nodecounter;
94 | }
95 | }
96 | else if( level > maxlevel ) {
97 | return nodecounter;
98 | }
99 |
100 | // didn't quit ?? OK, count it too...
101 | if( skpglue == 0 ) {
102 | nodecounter++;
103 | }
104 |
105 | if( func != NULL && skpglue == 0 ) {
106 | *err = func(node, level, nodecounter, userptr);
107 |
108 | // abort the walk on error
109 | if( *err != RX_OK ) {
110 | ER_dbg_va(FAC_RX, ASP_RX_TREE_WALK,
111 | "walk_tree: func returned error %d, aborting", *err);
112 | return nodecounter;
113 | }
114 | }
115 |
116 |
117 | for(i=0; i<=1; i++) {
118 |
119 | // reverse the sense of the walk
120 | link = ( walk_mode & RX_WALK_REVERS ) ? ! i : i;
121 |
122 | if( node->child_ptr[link] != NULL ) {
123 | nodecounter += rx_walk_tree(node->child_ptr[link], func, walk_mode,
124 | maxlevel, level, 0, userptr, err);
125 | // abort the walk on error
126 | if( func != NULL && *err != RX_OK ) {
127 | break;
128 | }
129 | }
130 | }
131 |
132 | return nodecounter;
133 | }
134 |
135 |
136 |
137 |
138 | /***************************************************************************/
139 | /*++++++++++++++
140 | finds a tree matching the specified criteria(registry+space+family).
141 |
142 | MT-note: locks/unlocks forest (still to be done)
143 |
144 | Returns: RX_OK or RX_NOTREE if no such tree can be found.
145 | +++++++++++*/
146 |
147 | er_ret_t
148 | RX_get_tree ( rx_tree_t **treeptr, /*+ answer goes here, please +*/
149 | rx_regid_t reg_id, /*+ id of the registry +*/
150 | ip_space_t spc_id, /*+ type of space (ipv4/ipv6) +*/
151 | rx_fam_t fam_id /*+ family of objects (route/inetnum) +*/
152 | )
153 |
154 | {
155 | GList *elem = g_list_first(rx_forest);
156 | rx_tree_t *trp;
157 |
158 | while( elem != NULL ) {
159 | trp = (rx_tree_t *) elem->data;
160 |
161 | if( trp->reg_id == reg_id
162 | && trp->space == spc_id && trp->family == fam_id) {
163 | /* copy the value to user's data */
164 | *treeptr = trp;
165 | ER_dbg_va(FAC_RX, ASP_RX_TREE_BOT, "tree found at %08x",trp);
166 |
167 | return RX_OK;
168 | }
169 | elem = g_list_next(elem);
170 | }
171 |
172 | *treeptr = NULL; // set no NOT FOUND
173 | return RX_NOTREE;
174 | }
175 |
176 |
177 | /***************************************************************************/
178 | /*++++++
179 | creates a (top) tree for the space, fills out sql table of trees
180 | generates a tablename for a tree (if NONE)
181 | updates LL of trees
182 |
183 | MT-note: locks/unlocks the forest (still to be done)
184 |
185 | ++++++++*/
186 | er_ret_t
187 | RX_tree_cre (
188 | rx_regid_t reg_id, /*+ id of the registry +*/
189 | ip_space_t spc_id, /*+ space id, one of IPv4 IPv6. +*/
190 | rx_fam_t fam_id, /*+ family of objects (route/inetnum) +*/
191 | char *prefixstr, /*+ prefix the tree will cover (string) +*/
192 | rx_mem_mt mem_mode, /* memory only, memory+sql, sql only +*/
193 | rx_subtree_mt subtrees, /*+ one of NONE, AUTO, HAND +*/
194 | rx_tree_t **treestore /* store the tree pointer here */
195 | )
196 |
197 | {
198 | er_ret_t err;
199 | rx_tree_t *newtree;
200 | ip_prefix_t newpref;
201 |
202 | if( IP_pref_e2b(&newpref, prefixstr) != IP_OK ) {
203 | die;
204 | }
205 |
206 | RX_get_tree ( &newtree, reg_id, spc_id, fam_id);
207 |
208 | if ( newtree != NULL ) {
209 | // die; /* error RX_TRALEX == tree already exists */
210 | return RX_TRALEX;
211 | }
212 |
213 |
214 | if ( (err=wr_malloc( (void **) & newtree, sizeof(rx_tree_t))) != UT_OK ) {
215 | return err; // die
216 | }
217 |
218 | ER_dbg_va(FAC_RX, ASP_RX_TREE_BOT, "creating a tree at %08x", newtree);
219 |
220 | /* copy tree settings */
221 |
222 | newtree -> reg_id = reg_id;
223 | newtree -> space = spc_id;
224 | newtree -> family = fam_id;
225 | newtree -> subtrees = subtrees;
226 | newtree -> mem_mode = mem_mode;
227 |
228 | /* set other tree values */
229 |
230 | /* parent set to NULL because it's not a subtree */
231 | newtree -> parent_tree = NULL;
232 | // PR_zeroprefix(& newtree -> prefix);
233 | newtree -> maxbits = IP_sizebits(spc_id);
234 |
235 | strcpy(newtree->data_table.val,"");
236 | strcpy(newtree->radix_table.val,"");
237 | strcpy(newtree->leaves_table.val,"");
238 |
239 | newtree->num_nodes = 0;
240 |
241 | newtree->top_ptr = NULL;
242 | newtree->top_key = SQ_NOKEY;
243 |
244 | newtree->prefix = newpref;
245 |
246 | TH_init_read_write_lock( &(newtree->rwlock));
247 |
248 | *treestore = newtree;
249 |
250 | return RX_OK;
251 | }
252 |
253 | void RX_attach2forest(rx_tree_t *newtree) {
254 | /* put into LL of trees; handle alloc err ??? */
255 | /* if threads are supposed to be reading already,
256 | set forest mutex; */
257 |
258 | rx_forest = g_list_append (rx_forest, newtree);
259 |
260 | /* release forest mutex; */
261 |
262 | }