/src/suricata8/src/util-radix-tree-common.h
Line | Count | Source |
1 | | /* Copyright (C) 2007-2022 Open Information Security Foundation |
2 | | * |
3 | | * You can copy, redistribute or modify this Program under the terms of |
4 | | * the GNU General Public License version 2 as published by the Free |
5 | | * Software Foundation. |
6 | | * |
7 | | * This program is distributed in the hope that it will be useful, |
8 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | | * GNU General Public License for more details. |
11 | | * |
12 | | * You should have received a copy of the GNU General Public License |
13 | | * version 2 along with this program; if not, write to the Free Software |
14 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
15 | | * 02110-1301, USA. |
16 | | */ |
17 | | |
18 | | /** |
19 | | * \file |
20 | | * |
21 | | * \author Victor Julien <victor@inliniac.net> |
22 | | * \author Anoop Saldanha <anoopsaldanha@gmail.com> |
23 | | * |
24 | | * Implementation of radix trees |
25 | | */ |
26 | | |
27 | | #include "util-validate.h" |
28 | | |
29 | | #ifndef ADDRESS_BYTES |
30 | | #error "define ADDRESS_BYTES" |
31 | | #endif |
32 | | #ifndef NETMASK_MAX |
33 | | #error "define NETMASK_MAX" |
34 | | #endif |
35 | | |
36 | 908k | #define RADIX_BITTEST(x, y) ((x) & (y)) |
37 | | |
38 | | /** |
39 | | * \brief Structure that hold the user data and the netmask associated with it. |
40 | | */ |
41 | | typedef struct RadixUserData { |
42 | | /* holds a pointer to the user data associated with the particular netmask */ |
43 | | void *user; |
44 | | /* pointer to the next user data in the list */ |
45 | | struct RadixUserData *next; |
46 | | /* holds the netmask value that corresponds to this user data pointer */ |
47 | | uint8_t netmask; |
48 | | } RadixUserData; |
49 | | |
50 | | /** |
51 | | * \brief Allocates and returns a new instance of RadixUserData. |
52 | | * |
53 | | * \param netmask The netmask entry (cidr) that has to be made in the new |
54 | | * RadixUserData instance |
55 | | * \param user The user data that has to be set for the above |
56 | | * netmask in the newly created RadixUserData instance. |
57 | | * |
58 | | * \retval user_data Pointer to a new instance of RadixUserData. |
59 | | */ |
60 | | static RadixUserData *AllocUserData(uint8_t netmask, void *user) |
61 | 57.2k | { |
62 | 57.2k | RadixUserData *user_data = SCCalloc(1, sizeof(RadixUserData)); |
63 | 57.2k | if (unlikely(user_data == NULL)) { |
64 | 0 | sc_errno = SC_ENOMEM; |
65 | 0 | return NULL; |
66 | 0 | } |
67 | 57.2k | user_data->netmask = netmask; |
68 | 57.2k | user_data->user = user; |
69 | 57.2k | return user_data; |
70 | 57.2k | } util-radix4-tree.c:AllocUserData Line | Count | Source | 61 | 33.8k | { | 62 | 33.8k | RadixUserData *user_data = SCCalloc(1, sizeof(RadixUserData)); | 63 | 33.8k | if (unlikely(user_data == NULL)) { | 64 | 0 | sc_errno = SC_ENOMEM; | 65 | 0 | return NULL; | 66 | 0 | } | 67 | 33.8k | user_data->netmask = netmask; | 68 | 33.8k | user_data->user = user; | 69 | 33.8k | return user_data; | 70 | 33.8k | } |
util-radix6-tree.c:AllocUserData Line | Count | Source | 61 | 23.3k | { | 62 | 23.3k | RadixUserData *user_data = SCCalloc(1, sizeof(RadixUserData)); | 63 | 23.3k | if (unlikely(user_data == NULL)) { | 64 | 0 | sc_errno = SC_ENOMEM; | 65 | 0 | return NULL; | 66 | 0 | } | 67 | 23.3k | user_data->netmask = netmask; | 68 | 23.3k | user_data->user = user; | 69 | 23.3k | return user_data; | 70 | 23.3k | } |
|
71 | | |
72 | | /** |
73 | | * \brief Deallocates an instance of RadixUserData. |
74 | | * |
75 | | * \param user_data Pointer to the instance of RadixUserData that has to be |
76 | | * freed. |
77 | | */ |
78 | | static void FreeUserData(RadixUserData *user_data) |
79 | 57.2k | { |
80 | 57.2k | SCFree(user_data); |
81 | 57.2k | } util-radix4-tree.c:FreeUserData Line | Count | Source | 79 | 33.8k | { | 80 | 33.8k | SCFree(user_data); | 81 | 33.8k | } |
util-radix6-tree.c:FreeUserData Line | Count | Source | 79 | 23.3k | { | 80 | 23.3k | SCFree(user_data); | 81 | 23.3k | } |
|
82 | | |
83 | | /** |
84 | | * \brief Appends a user_data instance(RadixUserData) to a |
85 | | * user_data(RadixUserData) list. We add the new entry in descending |
86 | | * order with respect to the netmask contained in the RadixUserData. |
87 | | * |
88 | | * \param new Pointer to the RadixUserData to be added to the list. |
89 | | * \param list Pointer to the RadixUserData list head, to which "new" has to |
90 | | * be appended. |
91 | | */ |
92 | | static void AppendToUserDataList(RadixUserData *add, RadixUserData **list) |
93 | 3.99k | { |
94 | 3.99k | RadixUserData *temp = NULL; |
95 | | |
96 | 3.99k | BUG_ON(add == NULL || list == NULL); |
97 | | |
98 | | /* add to the list in descending order. The reason we do this is for |
99 | | * optimizing key retrieval for a ip key under a netblock */ |
100 | 3.99k | RadixUserData *prev = temp = *list; |
101 | 6.23k | while (temp != NULL) { |
102 | 5.77k | if (add->netmask > temp->netmask) |
103 | 3.52k | break; |
104 | 2.24k | prev = temp; |
105 | 2.24k | temp = temp->next; |
106 | 2.24k | } |
107 | | |
108 | 3.99k | if (temp == *list) { |
109 | 3.11k | add->next = *list; |
110 | 3.11k | *list = add; |
111 | 3.11k | } else { |
112 | 873 | add->next = prev->next; |
113 | 873 | prev->next = add; |
114 | 873 | } |
115 | 3.99k | } util-radix4-tree.c:AppendToUserDataList Line | Count | Source | 93 | 1.12k | { | 94 | 1.12k | RadixUserData *temp = NULL; | 95 | | | 96 | 1.12k | BUG_ON(add == NULL || list == NULL); | 97 | | | 98 | | /* add to the list in descending order. The reason we do this is for | 99 | | * optimizing key retrieval for a ip key under a netblock */ | 100 | 1.12k | RadixUserData *prev = temp = *list; | 101 | 2.02k | while (temp != NULL) { | 102 | 1.84k | if (add->netmask > temp->netmask) | 103 | 953 | break; | 104 | 895 | prev = temp; | 105 | 895 | temp = temp->next; | 106 | 895 | } | 107 | | | 108 | 1.12k | if (temp == *list) { | 109 | 790 | add->next = *list; | 110 | 790 | *list = add; | 111 | 790 | } else { | 112 | 339 | add->next = prev->next; | 113 | 339 | prev->next = add; | 114 | 339 | } | 115 | 1.12k | } |
util-radix6-tree.c:AppendToUserDataList Line | Count | Source | 93 | 2.86k | { | 94 | 2.86k | RadixUserData *temp = NULL; | 95 | | | 96 | 2.86k | BUG_ON(add == NULL || list == NULL); | 97 | | | 98 | | /* add to the list in descending order. The reason we do this is for | 99 | | * optimizing key retrieval for a ip key under a netblock */ | 100 | 2.86k | RadixUserData *prev = temp = *list; | 101 | 4.21k | while (temp != NULL) { | 102 | 3.92k | if (add->netmask > temp->netmask) | 103 | 2.57k | break; | 104 | 1.34k | prev = temp; | 105 | 1.34k | temp = temp->next; | 106 | 1.34k | } | 107 | | | 108 | 2.86k | if (temp == *list) { | 109 | 2.32k | add->next = *list; | 110 | 2.32k | *list = add; | 111 | 2.32k | } else { | 112 | 534 | add->next = prev->next; | 113 | 534 | prev->next = add; | 114 | 534 | } | 115 | 2.86k | } |
|
116 | | |
117 | | /** |
118 | | * \brief Adds a netmask and its user_data for a particular prefix stream. |
119 | | * |
120 | | * \param prefix The prefix stream to which the netmask and its corresponding |
121 | | * user data has to be added. |
122 | | * \param netmask The netmask value (cidr) that has to be added to the prefix. |
123 | | * \param user The pointer to the user data corresponding to the above |
124 | | * netmask. |
125 | | */ |
126 | | static void AddNetmaskUserDataToNode(RADIX_NODE_TYPE *node, uint8_t netmask, void *user) |
127 | 3.99k | { |
128 | 3.99k | BUG_ON(!node); |
129 | 3.99k | AppendToUserDataList(AllocUserData(netmask, user), &node->user_data); |
130 | 3.99k | } util-radix4-tree.c:AddNetmaskUserDataToNode Line | Count | Source | 127 | 1.12k | { | 128 | 1.12k | BUG_ON(!node); | 129 | 1.12k | AppendToUserDataList(AllocUserData(netmask, user), &node->user_data); | 130 | 1.12k | } |
util-radix6-tree.c:AddNetmaskUserDataToNode Line | Count | Source | 127 | 2.86k | { | 128 | 2.86k | BUG_ON(!node); | 129 | 2.86k | AppendToUserDataList(AllocUserData(netmask, user), &node->user_data); | 130 | 2.86k | } |
|
131 | | |
132 | | /** |
133 | | * \brief Removes a particular user_data corresponding to a particular netmask |
134 | | * entry, from a prefix. |
135 | | * |
136 | | * \param prefix Pointer to the prefix from which the user_data/netmask entry |
137 | | * has to be removed. |
138 | | * \param netmask The netmask value (cidr) whose user_data has to be deleted. |
139 | | */ |
140 | | static void RemoveNetmaskUserDataFromNode(RADIX_NODE_TYPE *node, uint8_t netmask) |
141 | 0 | { |
142 | 0 | BUG_ON(!node); |
143 | | |
144 | 0 | RadixUserData *temp = NULL, *prev = NULL; |
145 | 0 | prev = temp = node->user_data; |
146 | 0 | while (temp != NULL) { |
147 | 0 | if (temp->netmask == netmask) { |
148 | 0 | if (temp == node->user_data) |
149 | 0 | node->user_data = temp->next; |
150 | 0 | else |
151 | 0 | prev->next = temp->next; |
152 | |
|
153 | 0 | FreeUserData(temp); |
154 | 0 | break; |
155 | 0 | } |
156 | 0 | prev = temp; |
157 | 0 | temp = temp->next; |
158 | 0 | } |
159 | 0 | } Unexecuted instantiation: util-radix4-tree.c:RemoveNetmaskUserDataFromNode Unexecuted instantiation: util-radix6-tree.c:RemoveNetmaskUserDataFromNode |
160 | | |
161 | | /** |
162 | | * \brief Indicates if prefix contains an entry for an ip with a specific netmask. |
163 | | * |
164 | | * \param prefix Pointer to the ip prefix that is being checked. |
165 | | * \param netmask The netmask value (cidr) that has to be checked for |
166 | | * presence in the prefix. |
167 | | * |
168 | | * \retval 1 On match. |
169 | | * \retval 0 On no match. |
170 | | */ |
171 | | static int ContainNetmask(RADIX_NODE_TYPE *node, uint8_t netmask) |
172 | 8.42k | { |
173 | 8.42k | BUG_ON(!node); |
174 | 8.42k | RadixUserData *user_data = node->user_data; |
175 | 18.9k | while (user_data != NULL) { |
176 | 14.9k | if (user_data->netmask == netmask) |
177 | 4.43k | return 1; |
178 | 10.5k | user_data = user_data->next; |
179 | 10.5k | } |
180 | 3.99k | return 0; |
181 | 8.42k | } util-radix4-tree.c:ContainNetmask Line | Count | Source | 172 | 2.28k | { | 173 | 2.28k | BUG_ON(!node); | 174 | 2.28k | RadixUserData *user_data = node->user_data; | 175 | 4.98k | while (user_data != NULL) { | 176 | 3.85k | if (user_data->netmask == netmask) | 177 | 1.15k | return 1; | 178 | 2.69k | user_data = user_data->next; | 179 | 2.69k | } | 180 | 1.12k | return 0; | 181 | 2.28k | } |
util-radix6-tree.c:ContainNetmask Line | Count | Source | 172 | 6.14k | { | 173 | 6.14k | BUG_ON(!node); | 174 | 6.14k | RadixUserData *user_data = node->user_data; | 175 | 13.9k | while (user_data != NULL) { | 176 | 11.1k | if (user_data->netmask == netmask) | 177 | 3.27k | return 1; | 178 | 7.83k | user_data = user_data->next; | 179 | 7.83k | } | 180 | 2.86k | return 0; | 181 | 6.14k | } |
|
182 | | |
183 | | /** |
184 | | * \brief Returns the total netmask count for this prefix. |
185 | | * |
186 | | * \param prefix Pointer to the prefix |
187 | | * |
188 | | * \retval count The total netmask count for this prefix. |
189 | | */ |
190 | | static int NetmaskCount(RADIX_NODE_TYPE *node) |
191 | 0 | { |
192 | 0 | BUG_ON(!node); |
193 | 0 | uint32_t count = 0; |
194 | 0 | RadixUserData *user_data = node->user_data; |
195 | 0 | while (user_data != NULL) { |
196 | 0 | count++; |
197 | 0 | user_data = user_data->next; |
198 | 0 | } |
199 | 0 | return count; |
200 | 0 | } Unexecuted instantiation: util-radix4-tree.c:NetmaskCount Unexecuted instantiation: util-radix6-tree.c:NetmaskCount |
201 | | |
202 | | /** |
203 | | * \brief Indicates if prefix contains an entry for an ip with a specific netmask |
204 | | * and if it does, it sets `user_data_result` to the netmask user_data entry. |
205 | | * |
206 | | * \param prefix Pointer to the ip prefix that is being checked. |
207 | | * \param netmask The netmask value for which we will have to return the user_data |
208 | | * \param exact_match Bool flag which indicates if we should check if the prefix |
209 | | * holds proper netblock or not. |
210 | | * \param[out] user_data_result user data pointer |
211 | | * |
212 | | * \retval 1 On match. |
213 | | * \retval 0 On no match. |
214 | | */ |
215 | | static int ContainNetmaskAndSetUserData( |
216 | | RADIX_NODE_TYPE *node, uint8_t netmask, bool exact_match, void **user_data_result) |
217 | 269k | { |
218 | 269k | DEBUG_VALIDATE_BUG_ON(!node); |
219 | | |
220 | 269k | RadixUserData *user_data = node->user_data; |
221 | | /* Check if we have a match for an exact ip. An exact ip as in not a proper |
222 | | * netblock, i.e. an ip with a netmask of 32. */ |
223 | 269k | if (exact_match) { |
224 | 56.1k | if (user_data->netmask == netmask) { |
225 | 40.4k | if (user_data_result) |
226 | 40.4k | *user_data_result = user_data->user; |
227 | 40.4k | return 1; |
228 | 40.4k | } else { |
229 | 15.7k | goto no_match; |
230 | 15.7k | } |
231 | 56.1k | } |
232 | | |
233 | | /* Check for the user_data entry for this netmask_value */ |
234 | 221k | while (user_data != NULL) { |
235 | 221k | if (user_data->netmask == netmask) { |
236 | 213k | if (user_data_result) |
237 | 213k | *user_data_result = user_data->user; |
238 | 213k | return 1; |
239 | 213k | } |
240 | 7.39k | user_data = user_data->next; |
241 | 7.39k | } |
242 | | |
243 | 15.7k | no_match: |
244 | 15.7k | if (user_data_result != NULL) |
245 | 15.7k | *user_data_result = NULL; |
246 | 15.7k | return 0; |
247 | 213k | } util-radix4-tree.c:ContainNetmaskAndSetUserData Line | Count | Source | 217 | 193k | { | 218 | 193k | DEBUG_VALIDATE_BUG_ON(!node); | 219 | | | 220 | 193k | RadixUserData *user_data = node->user_data; | 221 | | /* Check if we have a match for an exact ip. An exact ip as in not a proper | 222 | | * netblock, i.e. an ip with a netmask of 32. */ | 223 | 193k | if (exact_match) { | 224 | 32.1k | if (user_data->netmask == netmask) { | 225 | 21.8k | if (user_data_result) | 226 | 21.8k | *user_data_result = user_data->user; | 227 | 21.8k | return 1; | 228 | 21.8k | } else { | 229 | 10.3k | goto no_match; | 230 | 10.3k | } | 231 | 32.1k | } | 232 | | | 233 | | /* Check for the user_data entry for this netmask_value */ | 234 | 163k | while (user_data != NULL) { | 235 | 163k | if (user_data->netmask == netmask) { | 236 | 160k | if (user_data_result) | 237 | 160k | *user_data_result = user_data->user; | 238 | 160k | return 1; | 239 | 160k | } | 240 | 2.34k | user_data = user_data->next; | 241 | 2.34k | } | 242 | | | 243 | 10.3k | no_match: | 244 | 10.3k | if (user_data_result != NULL) | 245 | 10.3k | *user_data_result = NULL; | 246 | 10.3k | return 0; | 247 | 160k | } |
util-radix6-tree.c:ContainNetmaskAndSetUserData Line | Count | Source | 217 | 76.9k | { | 218 | 76.9k | DEBUG_VALIDATE_BUG_ON(!node); | 219 | | | 220 | 76.9k | RadixUserData *user_data = node->user_data; | 221 | | /* Check if we have a match for an exact ip. An exact ip as in not a proper | 222 | | * netblock, i.e. an ip with a netmask of 32. */ | 223 | 76.9k | if (exact_match) { | 224 | 23.9k | if (user_data->netmask == netmask) { | 225 | 18.5k | if (user_data_result) | 226 | 18.5k | *user_data_result = user_data->user; | 227 | 18.5k | return 1; | 228 | 18.5k | } else { | 229 | 5.38k | goto no_match; | 230 | 5.38k | } | 231 | 23.9k | } | 232 | | | 233 | | /* Check for the user_data entry for this netmask_value */ | 234 | 58.0k | while (user_data != NULL) { | 235 | 58.0k | if (user_data->netmask == netmask) { | 236 | 52.9k | if (user_data_result) | 237 | 52.9k | *user_data_result = user_data->user; | 238 | 52.9k | return 1; | 239 | 52.9k | } | 240 | 5.05k | user_data = user_data->next; | 241 | 5.05k | } | 242 | | | 243 | 5.38k | no_match: | 244 | 5.38k | if (user_data_result != NULL) | 245 | 5.38k | *user_data_result = NULL; | 246 | 5.38k | return 0; | 247 | 52.9k | } |
|
248 | | |
249 | | /** |
250 | | * \brief Creates a new node for the Radix tree |
251 | | * |
252 | | * \retval node The newly created node for the radix tree |
253 | | */ |
254 | | static inline RADIX_NODE_TYPE *RadixCreateNode(void) |
255 | 83.3k | { |
256 | 83.3k | RADIX_NODE_TYPE *node = NULL; |
257 | | |
258 | 83.3k | if ((node = SCCalloc(1, sizeof(RADIX_NODE_TYPE))) == NULL) { |
259 | 0 | sc_errno = SC_ENOMEM; |
260 | 0 | return NULL; |
261 | 0 | } |
262 | 83.3k | node->bit = NETMASK_MAX; |
263 | 83.3k | return node; |
264 | 83.3k | } util-radix4-tree.c:RadixCreateNode Line | Count | Source | 255 | 54.5k | { | 256 | 54.5k | RADIX_NODE_TYPE *node = NULL; | 257 | | | 258 | 54.5k | if ((node = SCCalloc(1, sizeof(RADIX_NODE_TYPE))) == NULL) { | 259 | 0 | sc_errno = SC_ENOMEM; | 260 | 0 | return NULL; | 261 | 0 | } | 262 | 54.5k | node->bit = NETMASK_MAX; | 263 | 54.5k | return node; | 264 | 54.5k | } |
util-radix6-tree.c:RadixCreateNode Line | Count | Source | 255 | 28.8k | { | 256 | 28.8k | RADIX_NODE_TYPE *node = NULL; | 257 | | | 258 | 28.8k | if ((node = SCCalloc(1, sizeof(RADIX_NODE_TYPE))) == NULL) { | 259 | 0 | sc_errno = SC_ENOMEM; | 260 | 0 | return NULL; | 261 | 0 | } | 262 | 28.8k | node->bit = NETMASK_MAX; | 263 | 28.8k | return node; | 264 | 28.8k | } |
|
265 | | |
266 | | /** |
267 | | * \brief Frees a Radix tree node |
268 | | * |
269 | | * \param node Pointer to a Radix tree node |
270 | | * \param tree Pointer to the Radix tree to which this node belongs |
271 | | */ |
272 | | static void ReleaseNode( |
273 | | RADIX_NODE_TYPE *node, RADIX_TREE_TYPE *tree, const RADIX_CONFIG_TYPE *config) |
274 | 83.3k | { |
275 | 83.3k | DEBUG_VALIDATE_BUG_ON(config == NULL); |
276 | 83.3k | if (node != NULL) { |
277 | 83.3k | RadixUserData *ud = node->user_data; |
278 | 140k | while (ud != NULL) { |
279 | 57.2k | RadixUserData *next = ud->next; |
280 | 57.2k | if (config->Free != NULL && ud->user) { |
281 | 57.2k | config->Free(ud->user); |
282 | 57.2k | } |
283 | 57.2k | FreeUserData(ud); |
284 | 57.2k | ud = next; |
285 | 57.2k | } |
286 | 83.3k | SCFree(node); |
287 | 83.3k | } |
288 | 83.3k | } util-radix4-tree.c:ReleaseNode Line | Count | Source | 274 | 54.5k | { | 275 | 54.5k | DEBUG_VALIDATE_BUG_ON(config == NULL); | 276 | 54.5k | if (node != NULL) { | 277 | 54.5k | RadixUserData *ud = node->user_data; | 278 | 88.4k | while (ud != NULL) { | 279 | 33.8k | RadixUserData *next = ud->next; | 280 | 33.8k | if (config->Free != NULL && ud->user) { | 281 | 33.8k | config->Free(ud->user); | 282 | 33.8k | } | 283 | 33.8k | FreeUserData(ud); | 284 | 33.8k | ud = next; | 285 | 33.8k | } | 286 | 54.5k | SCFree(node); | 287 | 54.5k | } | 288 | 54.5k | } |
util-radix6-tree.c:ReleaseNode Line | Count | Source | 274 | 28.8k | { | 275 | 28.8k | DEBUG_VALIDATE_BUG_ON(config == NULL); | 276 | 28.8k | if (node != NULL) { | 277 | 28.8k | RadixUserData *ud = node->user_data; | 278 | 52.2k | while (ud != NULL) { | 279 | 23.3k | RadixUserData *next = ud->next; | 280 | 23.3k | if (config->Free != NULL && ud->user) { | 281 | 23.3k | config->Free(ud->user); | 282 | 23.3k | } | 283 | 23.3k | FreeUserData(ud); | 284 | 23.3k | ud = next; | 285 | 23.3k | } | 286 | 28.8k | SCFree(node); | 287 | 28.8k | } | 288 | 28.8k | } |
|
289 | | |
290 | | /** |
291 | | * \brief Internal helper function used by TreeRelease to free a subtree |
292 | | * |
293 | | * \param node Pointer to the root of the subtree that has to be freed |
294 | | * \param tree Pointer to the Radix tree to which this subtree belongs |
295 | | */ |
296 | | static void ReleaseSubtree( |
297 | | RADIX_NODE_TYPE *node, RADIX_TREE_TYPE *tree, const RADIX_CONFIG_TYPE *config) |
298 | 16.5M | { |
299 | 16.5M | DEBUG_VALIDATE_BUG_ON(config == NULL); |
300 | 16.5M | if (node != NULL) { |
301 | 83.3k | ReleaseSubtree(node->left, tree, config); |
302 | 83.3k | ReleaseSubtree(node->right, tree, config); |
303 | 83.3k | ReleaseNode(node, tree, config); |
304 | 83.3k | } |
305 | 16.5M | } util-radix4-tree.c:ReleaseSubtree Line | Count | Source | 298 | 8.32M | { | 299 | 8.32M | DEBUG_VALIDATE_BUG_ON(config == NULL); | 300 | 8.32M | if (node != NULL) { | 301 | 54.5k | ReleaseSubtree(node->left, tree, config); | 302 | 54.5k | ReleaseSubtree(node->right, tree, config); | 303 | 54.5k | ReleaseNode(node, tree, config); | 304 | 54.5k | } | 305 | 8.32M | } |
util-radix6-tree.c:ReleaseSubtree Line | Count | Source | 298 | 8.26M | { | 299 | 8.26M | DEBUG_VALIDATE_BUG_ON(config == NULL); | 300 | 8.26M | if (node != NULL) { | 301 | 28.8k | ReleaseSubtree(node->left, tree, config); | 302 | 28.8k | ReleaseSubtree(node->right, tree, config); | 303 | 28.8k | ReleaseNode(node, tree, config); | 304 | 28.8k | } | 305 | 8.26M | } |
|
306 | | |
307 | | /** |
308 | | * \brief frees a Radix tree and all its nodes |
309 | | * |
310 | | * \param tree Pointer to the Radix tree that has to be freed |
311 | | */ |
312 | | static void TreeRelease(RADIX_TREE_TYPE *tree, const RADIX_CONFIG_TYPE *config) |
313 | 16.4M | { |
314 | 16.4M | DEBUG_VALIDATE_BUG_ON(config == NULL); |
315 | 16.4M | if (tree == NULL) |
316 | 0 | return; |
317 | | |
318 | 16.4M | ReleaseSubtree(tree->head, tree, config); |
319 | 16.4M | tree->head = NULL; |
320 | 16.4M | return; |
321 | 16.4M | } util-radix4-tree.c:TreeRelease Line | Count | Source | 313 | 8.21M | { | 314 | 8.21M | DEBUG_VALIDATE_BUG_ON(config == NULL); | 315 | 8.21M | if (tree == NULL) | 316 | 0 | return; | 317 | | | 318 | 8.21M | ReleaseSubtree(tree->head, tree, config); | 319 | | tree->head = NULL; | 320 | 8.21M | return; | 321 | 8.21M | } |
util-radix6-tree.c:TreeRelease Line | Count | Source | 313 | 8.21M | { | 314 | 8.21M | DEBUG_VALIDATE_BUG_ON(config == NULL); | 315 | 8.21M | if (tree == NULL) | 316 | 0 | return; | 317 | | | 318 | 8.21M | ReleaseSubtree(tree->head, tree, config); | 319 | | tree->head = NULL; | 320 | 8.21M | return; | 321 | 8.21M | } |
|
322 | | |
323 | | /** |
324 | | * \brief Adds a key to the Radix tree. Used internally by the API. |
325 | | * |
326 | | * \param tree Pointer to the Radix tree |
327 | | * \param key_stream Data that has to added to the Radix tree |
328 | | * \param netmask The netmask (cidr) |
329 | | * \param user Pointer to the user data that has to be associated with |
330 | | * this key |
331 | | * \param exclusive True if the node should be added iff it doesn't exist. |
332 | | * |
333 | | * \retval node Pointer to the newly created node |
334 | | */ |
335 | | static RADIX_NODE_TYPE *AddKey(RADIX_TREE_TYPE *tree, const RADIX_CONFIG_TYPE *config, |
336 | | const uint8_t *key_stream, uint8_t netmask, void *user, const bool exclusive) |
337 | 61.7k | { |
338 | 61.7k | DEBUG_VALIDATE_BUG_ON(config == NULL); |
339 | 61.7k | RADIX_NODE_TYPE *node = NULL; |
340 | 61.7k | RADIX_NODE_TYPE *parent = NULL; |
341 | 61.7k | RADIX_NODE_TYPE *bottom_node = NULL; |
342 | | |
343 | 61.7k | uint8_t tmp_stream[ADDRESS_BYTES]; |
344 | 61.7k | memcpy(tmp_stream, key_stream, sizeof(tmp_stream)); |
345 | | |
346 | 61.7k | if (tree == NULL) { |
347 | 0 | SCLogError("Argument \"tree\" NULL"); |
348 | 0 | sc_errno = SC_EINVAL; |
349 | 0 | return NULL; |
350 | 0 | } |
351 | | |
352 | | /* chop the ip address against a netmask */ |
353 | 61.7k | MaskIPNetblock(tmp_stream, netmask, NETMASK_MAX); |
354 | | |
355 | | /* the very first element in the radix tree */ |
356 | 61.7k | if (tree->head == NULL) { |
357 | 23.1k | node = RadixCreateNode(); |
358 | 23.1k | if (node == NULL) |
359 | 0 | return NULL; |
360 | 23.1k | memcpy(node->prefix_stream, tmp_stream, sizeof(tmp_stream)); |
361 | 23.1k | node->has_prefix = true; |
362 | 23.1k | node->user_data = AllocUserData(netmask, user); |
363 | 23.1k | if (node->user_data == NULL) { |
364 | 0 | ReleaseNode(node, tree, config); |
365 | 0 | return NULL; |
366 | 0 | } |
367 | 23.1k | tree->head = node; |
368 | 23.1k | if (netmask == NETMASK_MAX) |
369 | 2.05k | return node; |
370 | | |
371 | 21.1k | AddNetmaskToMasks(node, netmask); |
372 | 21.1k | return node; |
373 | 23.1k | } |
374 | 38.5k | node = tree->head; |
375 | | |
376 | | /* we walk down the tree only when we satisfy 2 conditions. The first one |
377 | | * being the incoming prefix is shorter than the differ bit of the current |
378 | | * node. In case we fail in this aspect, we walk down to the tree, till we |
379 | | * arrive at a node that ends in a prefix */ |
380 | 290k | while (node->bit < NETMASK_MAX || !node->has_prefix) { |
381 | | /* if the bitlen isn't long enough to handle the bit test, we just walk |
382 | | * down along one of the paths, since either paths should end up with a |
383 | | * node that has a common prefix whose differ bit is greater than the |
384 | | * bitlen of the incoming prefix */ |
385 | 251k | if (NETMASK_MAX <= node->bit) { |
386 | 0 | if (node->right == NULL) |
387 | 0 | break; |
388 | 0 | node = node->right; |
389 | 251k | } else { |
390 | 251k | if (RADIX_BITTEST(tmp_stream[node->bit >> 3], (0x80 >> (node->bit % 8)))) { |
391 | 53.5k | if (node->right == NULL) |
392 | 0 | break; |
393 | 53.5k | node = node->right; |
394 | 198k | } else { |
395 | 198k | if (node->left == NULL) |
396 | 0 | break; |
397 | 198k | node = node->left; |
398 | 198k | } |
399 | 251k | } |
400 | 251k | } |
401 | | |
402 | | /* we need to keep a reference to the bottom-most node, that actually holds |
403 | | * the prefix */ |
404 | 38.5k | bottom_node = node; |
405 | | |
406 | | /* get the first bit position where the ips differ */ |
407 | 38.5k | uint8_t check_bit = MIN(node->bit, NETMASK_MAX); |
408 | 38.5k | uint8_t differ_bit = 0; |
409 | 38.5k | uint8_t j = 0; |
410 | 223k | for (uint8_t i = 0; (i * 8) < check_bit; i++) { |
411 | 214k | int temp = 0; |
412 | 214k | if ((temp = (tmp_stream[i] ^ bottom_node->prefix_stream[i])) == 0) { |
413 | 184k | differ_bit = (i + 1) * 8; |
414 | 184k | continue; |
415 | 184k | } |
416 | | |
417 | | /* find out the position where the first bit differs. This method is |
418 | | * faster, but at the cost of being larger. But with larger caches |
419 | | * these days we don't have to worry about cache misses */ |
420 | 30.1k | temp = temp * 2; |
421 | 30.1k | if (temp >= 256) |
422 | 3.26k | j = 0; |
423 | 26.8k | else if (temp >= 128) |
424 | 4.40k | j = 1; |
425 | 22.4k | else if (temp >= 64) |
426 | 3.85k | j = 2; |
427 | 18.5k | else if (temp >= 32) |
428 | 3.05k | j = 3; |
429 | 15.5k | else if (temp >= 16) |
430 | 4.38k | j = 4; |
431 | 11.1k | else if (temp >= 8) |
432 | 4.00k | j = 5; |
433 | 7.15k | else if (temp >= 4) |
434 | 3.61k | j = 6; |
435 | 3.54k | else if (temp >= 2) |
436 | 3.54k | j = 7; |
437 | | |
438 | 30.1k | differ_bit = i * 8 + j; |
439 | 30.1k | break; |
440 | 214k | } |
441 | 38.5k | if (check_bit < differ_bit) |
442 | 0 | differ_bit = check_bit; |
443 | | |
444 | | /* walk up the tree till we find the position, to fit our new node in */ |
445 | 38.5k | parent = node->parent; |
446 | 50.6k | while (parent && differ_bit <= parent->bit) { |
447 | 12.1k | node = parent; |
448 | 12.1k | parent = node->parent; |
449 | 12.1k | } |
450 | 38.5k | BUG_ON(differ_bit == NETMASK_MAX && node->bit != NETMASK_MAX); |
451 | | |
452 | | /* We already have the node in the tree with the same differing bit position */ |
453 | 38.5k | if (differ_bit == NETMASK_MAX && node->bit == NETMASK_MAX) { |
454 | 8.42k | if (node->has_prefix) { |
455 | | /* Check if we already have this netmask entry covered by this prefix */ |
456 | 8.42k | if (ContainNetmask(node, netmask)) { |
457 | | /* Basically we already have this stream prefix, as well as the |
458 | | * netblock entry for this. A perfect duplicate. */ |
459 | 4.43k | if (exclusive) { |
460 | 4.43k | SCLogDebug("not inserting since it already exists"); |
461 | 4.43k | sc_errno = SC_EEXIST; |
462 | 4.43k | return NULL; |
463 | 4.43k | } |
464 | 0 | SCLogDebug("Duplicate entry for this ip address/netblock"); |
465 | 3.99k | } else { |
466 | | /* Basically we already have this stream prefix, but we don't |
467 | | * have an entry for this particular netmask value for this |
468 | | * prefix. For example, we have an entry for 192.168.0.0 and |
469 | | * 192.168.0.0/16 and now we are trying to enter 192.168.0.0/20 */ |
470 | 3.99k | AddNetmaskUserDataToNode(node, netmask, user); |
471 | | |
472 | | /* if we are adding a netmask of 32 it indicates we are adding |
473 | | * an exact host ip into the radix tree, in which case we don't |
474 | | * need to add the netmask value into the tree */ |
475 | 3.99k | if (netmask == NETMASK_MAX) |
476 | 1.03k | return node; |
477 | | |
478 | | /* looks like we have a netmask which is != 32, in which |
479 | | * case we walk up the tree to insert this netmask value in the |
480 | | * correct node */ |
481 | 2.96k | parent = node->parent; |
482 | 4.99k | while (parent != NULL && netmask < (parent->bit + 1)) { |
483 | 2.03k | node = parent; |
484 | 2.03k | parent = parent->parent; |
485 | 2.03k | } |
486 | | |
487 | 2.96k | AddNetmaskToMasks(node, netmask); |
488 | 2.96k | if (NetmaskEqualsMask(node, netmask)) { |
489 | 181 | return node; |
490 | 181 | } |
491 | 2.96k | } |
492 | 8.42k | } |
493 | 2.77k | return node; |
494 | 8.42k | } |
495 | | |
496 | | /* create the leaf node for the new key */ |
497 | 30.1k | RADIX_NODE_TYPE *new_node = RadixCreateNode(); |
498 | 30.1k | if (new_node == NULL) |
499 | 0 | return NULL; |
500 | 30.1k | memcpy(new_node->prefix_stream, tmp_stream, sizeof(tmp_stream)); |
501 | 30.1k | new_node->has_prefix = true; |
502 | 30.1k | new_node->user_data = AllocUserData(netmask, user); |
503 | 30.1k | if (new_node->user_data == NULL) { |
504 | 0 | ReleaseNode(new_node, tree, config); |
505 | 0 | return NULL; |
506 | 0 | } |
507 | | |
508 | | /* stick our new_node into the tree. Create a node that holds the |
509 | | * differing bit position and break the branch. Also handle the |
510 | | * tranfer of netmasks between node and inter_node(explained in more |
511 | | * detail below) */ |
512 | 30.1k | RADIX_NODE_TYPE *inter_node = RadixCreateNode(); |
513 | 30.1k | if (inter_node == NULL) { |
514 | 0 | ReleaseNode(new_node, tree, config); |
515 | 0 | return NULL; |
516 | 0 | } |
517 | 30.1k | inter_node->has_prefix = false; |
518 | 30.1k | inter_node->bit = differ_bit; |
519 | 30.1k | inter_node->parent = node->parent; |
520 | 30.1k | SCLogDebug("inter_node: differ_bit %u", differ_bit); |
521 | | |
522 | | /* update netmasks for node and set them for inter_node */ |
523 | 30.1k | ProcessInternode(node, inter_node); |
524 | | |
525 | 30.1k | if (RADIX_BITTEST(tmp_stream[differ_bit >> 3], (0x80 >> (differ_bit % 8)))) { |
526 | 18.3k | inter_node->left = node; |
527 | 18.3k | inter_node->right = new_node; |
528 | 18.3k | } else { |
529 | 11.7k | inter_node->left = new_node; |
530 | 11.7k | inter_node->right = node; |
531 | 11.7k | } |
532 | 30.1k | new_node->parent = inter_node; |
533 | | |
534 | 30.1k | if (node->parent == NULL) |
535 | 6.25k | tree->head = inter_node; |
536 | 23.8k | else if (node->parent->right == node) |
537 | 8.69k | node->parent->right = inter_node; |
538 | 15.1k | else |
539 | 15.1k | node->parent->left = inter_node; |
540 | | |
541 | 30.1k | node->parent = inter_node; |
542 | | |
543 | | /* insert the netmask into the tree */ |
544 | 30.1k | if (netmask != NETMASK_MAX) { |
545 | 21.1k | node = new_node; |
546 | 21.1k | parent = new_node->parent; |
547 | 22.3k | while (parent != NULL && netmask < (parent->bit + 1)) { |
548 | 1.25k | node = parent; |
549 | 1.25k | parent = parent->parent; |
550 | 1.25k | } |
551 | 21.1k | AddNetmaskToMasks(node, netmask); |
552 | 21.1k | } |
553 | 30.1k | return new_node; |
554 | 30.1k | } util-radix4-tree.c:AddKey Line | Count | Source | 337 | 35.0k | { | 338 | 35.0k | DEBUG_VALIDATE_BUG_ON(config == NULL); | 339 | 35.0k | RADIX_NODE_TYPE *node = NULL; | 340 | 35.0k | RADIX_NODE_TYPE *parent = NULL; | 341 | 35.0k | RADIX_NODE_TYPE *bottom_node = NULL; | 342 | | | 343 | 35.0k | uint8_t tmp_stream[ADDRESS_BYTES]; | 344 | 35.0k | memcpy(tmp_stream, key_stream, sizeof(tmp_stream)); | 345 | | | 346 | 35.0k | if (tree == NULL) { | 347 | 0 | SCLogError("Argument \"tree\" NULL"); | 348 | 0 | sc_errno = SC_EINVAL; | 349 | 0 | return NULL; | 350 | 0 | } | 351 | | | 352 | | /* chop the ip address against a netmask */ | 353 | 35.0k | MaskIPNetblock(tmp_stream, netmask, NETMASK_MAX); | 354 | | | 355 | | /* the very first element in the radix tree */ | 356 | 35.0k | if (tree->head == NULL) { | 357 | 10.9k | node = RadixCreateNode(); | 358 | 10.9k | if (node == NULL) | 359 | 0 | return NULL; | 360 | 10.9k | memcpy(node->prefix_stream, tmp_stream, sizeof(tmp_stream)); | 361 | 10.9k | node->has_prefix = true; | 362 | 10.9k | node->user_data = AllocUserData(netmask, user); | 363 | 10.9k | if (node->user_data == NULL) { | 364 | 0 | ReleaseNode(node, tree, config); | 365 | 0 | return NULL; | 366 | 0 | } | 367 | 10.9k | tree->head = node; | 368 | 10.9k | if (netmask == NETMASK_MAX) | 369 | 441 | return node; | 370 | | | 371 | 10.5k | AddNetmaskToMasks(node, netmask); | 372 | 10.5k | return node; | 373 | 10.9k | } | 374 | 24.0k | node = tree->head; | 375 | | | 376 | | /* we walk down the tree only when we satisfy 2 conditions. The first one | 377 | | * being the incoming prefix is shorter than the differ bit of the current | 378 | | * node. In case we fail in this aspect, we walk down to the tree, till we | 379 | | * arrive at a node that ends in a prefix */ | 380 | 235k | while (node->bit < NETMASK_MAX || !node->has_prefix) { | 381 | | /* if the bitlen isn't long enough to handle the bit test, we just walk | 382 | | * down along one of the paths, since either paths should end up with a | 383 | | * node that has a common prefix whose differ bit is greater than the | 384 | | * bitlen of the incoming prefix */ | 385 | 211k | if (NETMASK_MAX <= node->bit) { | 386 | 0 | if (node->right == NULL) | 387 | 0 | break; | 388 | 0 | node = node->right; | 389 | 211k | } else { | 390 | 211k | if (RADIX_BITTEST(tmp_stream[node->bit >> 3], (0x80 >> (node->bit % 8)))) { | 391 | 46.8k | if (node->right == NULL) | 392 | 0 | break; | 393 | 46.8k | node = node->right; | 394 | 164k | } else { | 395 | 164k | if (node->left == NULL) | 396 | 0 | break; | 397 | 164k | node = node->left; | 398 | 164k | } | 399 | 211k | } | 400 | 211k | } | 401 | | | 402 | | /* we need to keep a reference to the bottom-most node, that actually holds | 403 | | * the prefix */ | 404 | 24.0k | bottom_node = node; | 405 | | | 406 | | /* get the first bit position where the ips differ */ | 407 | 24.0k | uint8_t check_bit = MIN(node->bit, NETMASK_MAX); | 408 | 24.0k | uint8_t differ_bit = 0; | 409 | 24.0k | uint8_t j = 0; | 410 | 68.9k | for (uint8_t i = 0; (i * 8) < check_bit; i++) { | 411 | 66.6k | int temp = 0; | 412 | 66.6k | if ((temp = (tmp_stream[i] ^ bottom_node->prefix_stream[i])) == 0) { | 413 | 44.8k | differ_bit = (i + 1) * 8; | 414 | 44.8k | continue; | 415 | 44.8k | } | 416 | | | 417 | | /* find out the position where the first bit differs. This method is | 418 | | * faster, but at the cost of being larger. But with larger caches | 419 | | * these days we don't have to worry about cache misses */ | 420 | 21.8k | temp = temp * 2; | 421 | 21.8k | if (temp >= 256) | 422 | 2.79k | j = 0; | 423 | 19.0k | else if (temp >= 128) | 424 | 2.78k | j = 1; | 425 | 16.2k | else if (temp >= 64) | 426 | 3.02k | j = 2; | 427 | 13.2k | else if (temp >= 32) | 428 | 2.52k | j = 3; | 429 | 10.6k | else if (temp >= 16) | 430 | 2.97k | j = 4; | 431 | 7.70k | else if (temp >= 8) | 432 | 2.66k | j = 5; | 433 | 5.03k | else if (temp >= 4) | 434 | 2.66k | j = 6; | 435 | 2.37k | else if (temp >= 2) | 436 | 2.37k | j = 7; | 437 | | | 438 | 21.8k | differ_bit = i * 8 + j; | 439 | 21.8k | break; | 440 | 66.6k | } | 441 | 24.0k | if (check_bit < differ_bit) | 442 | 0 | differ_bit = check_bit; | 443 | | | 444 | | /* walk up the tree till we find the position, to fit our new node in */ | 445 | 24.0k | parent = node->parent; | 446 | 28.0k | while (parent && differ_bit <= parent->bit) { | 447 | 3.98k | node = parent; | 448 | 3.98k | parent = node->parent; | 449 | 3.98k | } | 450 | 24.0k | BUG_ON(differ_bit == NETMASK_MAX && node->bit != NETMASK_MAX); | 451 | | | 452 | | /* We already have the node in the tree with the same differing bit position */ | 453 | 24.0k | if (differ_bit == NETMASK_MAX && node->bit == NETMASK_MAX) { | 454 | 2.28k | if (node->has_prefix) { | 455 | | /* Check if we already have this netmask entry covered by this prefix */ | 456 | 2.28k | if (ContainNetmask(node, netmask)) { | 457 | | /* Basically we already have this stream prefix, as well as the | 458 | | * netblock entry for this. A perfect duplicate. */ | 459 | 1.15k | if (exclusive) { | 460 | 1.15k | SCLogDebug("not inserting since it already exists"); | 461 | 1.15k | sc_errno = SC_EEXIST; | 462 | 1.15k | return NULL; | 463 | 1.15k | } | 464 | 0 | SCLogDebug("Duplicate entry for this ip address/netblock"); | 465 | 1.12k | } else { | 466 | | /* Basically we already have this stream prefix, but we don't | 467 | | * have an entry for this particular netmask value for this | 468 | | * prefix. For example, we have an entry for 192.168.0.0 and | 469 | | * 192.168.0.0/16 and now we are trying to enter 192.168.0.0/20 */ | 470 | 1.12k | AddNetmaskUserDataToNode(node, netmask, user); | 471 | | | 472 | | /* if we are adding a netmask of 32 it indicates we are adding | 473 | | * an exact host ip into the radix tree, in which case we don't | 474 | | * need to add the netmask value into the tree */ | 475 | 1.12k | if (netmask == NETMASK_MAX) | 476 | 63 | return node; | 477 | | | 478 | | /* looks like we have a netmask which is != 32, in which | 479 | | * case we walk up the tree to insert this netmask value in the | 480 | | * correct node */ | 481 | 1.06k | parent = node->parent; | 482 | 1.91k | while (parent != NULL && netmask < (parent->bit + 1)) { | 483 | 849 | node = parent; | 484 | 849 | parent = parent->parent; | 485 | 849 | } | 486 | | | 487 | 1.06k | AddNetmaskToMasks(node, netmask); | 488 | 1.06k | if (NetmaskEqualsMask(node, netmask)) { | 489 | 181 | return node; | 490 | 181 | } | 491 | 1.06k | } | 492 | 2.28k | } | 493 | 885 | return node; | 494 | 2.28k | } | 495 | | | 496 | | /* create the leaf node for the new key */ | 497 | 21.8k | RADIX_NODE_TYPE *new_node = RadixCreateNode(); | 498 | 21.8k | if (new_node == NULL) | 499 | 0 | return NULL; | 500 | 21.8k | memcpy(new_node->prefix_stream, tmp_stream, sizeof(tmp_stream)); | 501 | 21.8k | new_node->has_prefix = true; | 502 | 21.8k | new_node->user_data = AllocUserData(netmask, user); | 503 | 21.8k | if (new_node->user_data == NULL) { | 504 | 0 | ReleaseNode(new_node, tree, config); | 505 | 0 | return NULL; | 506 | 0 | } | 507 | | | 508 | | /* stick our new_node into the tree. Create a node that holds the | 509 | | * differing bit position and break the branch. Also handle the | 510 | | * tranfer of netmasks between node and inter_node(explained in more | 511 | | * detail below) */ | 512 | 21.8k | RADIX_NODE_TYPE *inter_node = RadixCreateNode(); | 513 | 21.8k | if (inter_node == NULL) { | 514 | 0 | ReleaseNode(new_node, tree, config); | 515 | 0 | return NULL; | 516 | 0 | } | 517 | 21.8k | inter_node->has_prefix = false; | 518 | 21.8k | inter_node->bit = differ_bit; | 519 | 21.8k | inter_node->parent = node->parent; | 520 | 21.8k | SCLogDebug("inter_node: differ_bit %u", differ_bit); | 521 | | | 522 | | /* update netmasks for node and set them for inter_node */ | 523 | 21.8k | ProcessInternode(node, inter_node); | 524 | | | 525 | 21.8k | if (RADIX_BITTEST(tmp_stream[differ_bit >> 3], (0x80 >> (differ_bit % 8)))) { | 526 | 11.4k | inter_node->left = node; | 527 | 11.4k | inter_node->right = new_node; | 528 | 11.4k | } else { | 529 | 10.4k | inter_node->left = new_node; | 530 | 10.4k | inter_node->right = node; | 531 | 10.4k | } | 532 | 21.8k | new_node->parent = inter_node; | 533 | | | 534 | 21.8k | if (node->parent == NULL) | 535 | 2.67k | tree->head = inter_node; | 536 | 19.1k | else if (node->parent->right == node) | 537 | 6.88k | node->parent->right = inter_node; | 538 | 12.2k | else | 539 | 12.2k | node->parent->left = inter_node; | 540 | | | 541 | 21.8k | node->parent = inter_node; | 542 | | | 543 | | /* insert the netmask into the tree */ | 544 | 21.8k | if (netmask != NETMASK_MAX) { | 545 | 17.9k | node = new_node; | 546 | 17.9k | parent = new_node->parent; | 547 | 18.4k | while (parent != NULL && netmask < (parent->bit + 1)) { | 548 | 449 | node = parent; | 549 | 449 | parent = parent->parent; | 550 | 449 | } | 551 | 17.9k | AddNetmaskToMasks(node, netmask); | 552 | 17.9k | } | 553 | 21.8k | return new_node; | 554 | 21.8k | } |
util-radix6-tree.c:AddKey Line | Count | Source | 337 | 26.6k | { | 338 | 26.6k | DEBUG_VALIDATE_BUG_ON(config == NULL); | 339 | 26.6k | RADIX_NODE_TYPE *node = NULL; | 340 | 26.6k | RADIX_NODE_TYPE *parent = NULL; | 341 | 26.6k | RADIX_NODE_TYPE *bottom_node = NULL; | 342 | | | 343 | 26.6k | uint8_t tmp_stream[ADDRESS_BYTES]; | 344 | 26.6k | memcpy(tmp_stream, key_stream, sizeof(tmp_stream)); | 345 | | | 346 | 26.6k | if (tree == NULL) { | 347 | 0 | SCLogError("Argument \"tree\" NULL"); | 348 | 0 | sc_errno = SC_EINVAL; | 349 | 0 | return NULL; | 350 | 0 | } | 351 | | | 352 | | /* chop the ip address against a netmask */ | 353 | 26.6k | MaskIPNetblock(tmp_stream, netmask, NETMASK_MAX); | 354 | | | 355 | | /* the very first element in the radix tree */ | 356 | 26.6k | if (tree->head == NULL) { | 357 | 12.2k | node = RadixCreateNode(); | 358 | 12.2k | if (node == NULL) | 359 | 0 | return NULL; | 360 | 12.2k | memcpy(node->prefix_stream, tmp_stream, sizeof(tmp_stream)); | 361 | 12.2k | node->has_prefix = true; | 362 | 12.2k | node->user_data = AllocUserData(netmask, user); | 363 | 12.2k | if (node->user_data == NULL) { | 364 | 0 | ReleaseNode(node, tree, config); | 365 | 0 | return NULL; | 366 | 0 | } | 367 | 12.2k | tree->head = node; | 368 | 12.2k | if (netmask == NETMASK_MAX) | 369 | 1.60k | return node; | 370 | | | 371 | 10.6k | AddNetmaskToMasks(node, netmask); | 372 | 10.6k | return node; | 373 | 12.2k | } | 374 | 14.4k | node = tree->head; | 375 | | | 376 | | /* we walk down the tree only when we satisfy 2 conditions. The first one | 377 | | * being the incoming prefix is shorter than the differ bit of the current | 378 | | * node. In case we fail in this aspect, we walk down to the tree, till we | 379 | | * arrive at a node that ends in a prefix */ | 380 | 54.2k | while (node->bit < NETMASK_MAX || !node->has_prefix) { | 381 | | /* if the bitlen isn't long enough to handle the bit test, we just walk | 382 | | * down along one of the paths, since either paths should end up with a | 383 | | * node that has a common prefix whose differ bit is greater than the | 384 | | * bitlen of the incoming prefix */ | 385 | 39.7k | if (NETMASK_MAX <= node->bit) { | 386 | 0 | if (node->right == NULL) | 387 | 0 | break; | 388 | 0 | node = node->right; | 389 | 39.7k | } else { | 390 | 39.7k | if (RADIX_BITTEST(tmp_stream[node->bit >> 3], (0x80 >> (node->bit % 8)))) { | 391 | 6.65k | if (node->right == NULL) | 392 | 0 | break; | 393 | 6.65k | node = node->right; | 394 | 33.1k | } else { | 395 | 33.1k | if (node->left == NULL) | 396 | 0 | break; | 397 | 33.1k | node = node->left; | 398 | 33.1k | } | 399 | 39.7k | } | 400 | 39.7k | } | 401 | | | 402 | | /* we need to keep a reference to the bottom-most node, that actually holds | 403 | | * the prefix */ | 404 | 14.4k | bottom_node = node; | 405 | | | 406 | | /* get the first bit position where the ips differ */ | 407 | 14.4k | uint8_t check_bit = MIN(node->bit, NETMASK_MAX); | 408 | 14.4k | uint8_t differ_bit = 0; | 409 | 14.4k | uint8_t j = 0; | 410 | 154k | for (uint8_t i = 0; (i * 8) < check_bit; i++) { | 411 | 147k | int temp = 0; | 412 | 147k | if ((temp = (tmp_stream[i] ^ bottom_node->prefix_stream[i])) == 0) { | 413 | 139k | differ_bit = (i + 1) * 8; | 414 | 139k | continue; | 415 | 139k | } | 416 | | | 417 | | /* find out the position where the first bit differs. This method is | 418 | | * faster, but at the cost of being larger. But with larger caches | 419 | | * these days we don't have to worry about cache misses */ | 420 | 8.30k | temp = temp * 2; | 421 | 8.30k | if (temp >= 256) | 422 | 471 | j = 0; | 423 | 7.83k | else if (temp >= 128) | 424 | 1.61k | j = 1; | 425 | 6.22k | else if (temp >= 64) | 426 | 835 | j = 2; | 427 | 5.38k | else if (temp >= 32) | 428 | 524 | j = 3; | 429 | 4.86k | else if (temp >= 16) | 430 | 1.41k | j = 4; | 431 | 3.45k | else if (temp >= 8) | 432 | 1.33k | j = 5; | 433 | 2.11k | else if (temp >= 4) | 434 | 947 | j = 6; | 435 | 1.16k | else if (temp >= 2) | 436 | 1.16k | j = 7; | 437 | | | 438 | 8.30k | differ_bit = i * 8 + j; | 439 | 8.30k | break; | 440 | 147k | } | 441 | 14.4k | if (check_bit < differ_bit) | 442 | 0 | differ_bit = check_bit; | 443 | | | 444 | | /* walk up the tree till we find the position, to fit our new node in */ | 445 | 14.4k | parent = node->parent; | 446 | 22.6k | while (parent && differ_bit <= parent->bit) { | 447 | 8.15k | node = parent; | 448 | 8.15k | parent = node->parent; | 449 | 8.15k | } | 450 | 14.4k | BUG_ON(differ_bit == NETMASK_MAX && node->bit != NETMASK_MAX); | 451 | | | 452 | | /* We already have the node in the tree with the same differing bit position */ | 453 | 14.4k | if (differ_bit == NETMASK_MAX && node->bit == NETMASK_MAX) { | 454 | 6.14k | if (node->has_prefix) { | 455 | | /* Check if we already have this netmask entry covered by this prefix */ | 456 | 6.14k | if (ContainNetmask(node, netmask)) { | 457 | | /* Basically we already have this stream prefix, as well as the | 458 | | * netblock entry for this. A perfect duplicate. */ | 459 | 3.27k | if (exclusive) { | 460 | 3.27k | SCLogDebug("not inserting since it already exists"); | 461 | 3.27k | sc_errno = SC_EEXIST; | 462 | 3.27k | return NULL; | 463 | 3.27k | } | 464 | 0 | SCLogDebug("Duplicate entry for this ip address/netblock"); | 465 | 2.86k | } else { | 466 | | /* Basically we already have this stream prefix, but we don't | 467 | | * have an entry for this particular netmask value for this | 468 | | * prefix. For example, we have an entry for 192.168.0.0 and | 469 | | * 192.168.0.0/16 and now we are trying to enter 192.168.0.0/20 */ | 470 | 2.86k | AddNetmaskUserDataToNode(node, netmask, user); | 471 | | | 472 | | /* if we are adding a netmask of 32 it indicates we are adding | 473 | | * an exact host ip into the radix tree, in which case we don't | 474 | | * need to add the netmask value into the tree */ | 475 | 2.86k | if (netmask == NETMASK_MAX) | 476 | 969 | return node; | 477 | | | 478 | | /* looks like we have a netmask which is != 32, in which | 479 | | * case we walk up the tree to insert this netmask value in the | 480 | | * correct node */ | 481 | 1.89k | parent = node->parent; | 482 | 3.08k | while (parent != NULL && netmask < (parent->bit + 1)) { | 483 | 1.18k | node = parent; | 484 | 1.18k | parent = parent->parent; | 485 | 1.18k | } | 486 | | | 487 | 1.89k | AddNetmaskToMasks(node, netmask); | 488 | 1.89k | if (NetmaskEqualsMask(node, netmask)) { | 489 | 0 | return node; | 490 | 0 | } | 491 | 1.89k | } | 492 | 6.14k | } | 493 | 1.89k | return node; | 494 | 6.14k | } | 495 | | | 496 | | /* create the leaf node for the new key */ | 497 | 8.30k | RADIX_NODE_TYPE *new_node = RadixCreateNode(); | 498 | 8.30k | if (new_node == NULL) | 499 | 0 | return NULL; | 500 | 8.30k | memcpy(new_node->prefix_stream, tmp_stream, sizeof(tmp_stream)); | 501 | 8.30k | new_node->has_prefix = true; | 502 | 8.30k | new_node->user_data = AllocUserData(netmask, user); | 503 | 8.30k | if (new_node->user_data == NULL) { | 504 | 0 | ReleaseNode(new_node, tree, config); | 505 | 0 | return NULL; | 506 | 0 | } | 507 | | | 508 | | /* stick our new_node into the tree. Create a node that holds the | 509 | | * differing bit position and break the branch. Also handle the | 510 | | * tranfer of netmasks between node and inter_node(explained in more | 511 | | * detail below) */ | 512 | 8.30k | RADIX_NODE_TYPE *inter_node = RadixCreateNode(); | 513 | 8.30k | if (inter_node == NULL) { | 514 | 0 | ReleaseNode(new_node, tree, config); | 515 | 0 | return NULL; | 516 | 0 | } | 517 | 8.30k | inter_node->has_prefix = false; | 518 | 8.30k | inter_node->bit = differ_bit; | 519 | 8.30k | inter_node->parent = node->parent; | 520 | 8.30k | SCLogDebug("inter_node: differ_bit %u", differ_bit); | 521 | | | 522 | | /* update netmasks for node and set them for inter_node */ | 523 | 8.30k | ProcessInternode(node, inter_node); | 524 | | | 525 | 8.30k | if (RADIX_BITTEST(tmp_stream[differ_bit >> 3], (0x80 >> (differ_bit % 8)))) { | 526 | 6.97k | inter_node->left = node; | 527 | 6.97k | inter_node->right = new_node; | 528 | 6.97k | } else { | 529 | 1.33k | inter_node->left = new_node; | 530 | 1.33k | inter_node->right = node; | 531 | 1.33k | } | 532 | 8.30k | new_node->parent = inter_node; | 533 | | | 534 | 8.30k | if (node->parent == NULL) | 535 | 3.58k | tree->head = inter_node; | 536 | 4.72k | else if (node->parent->right == node) | 537 | 1.80k | node->parent->right = inter_node; | 538 | 2.92k | else | 539 | 2.92k | node->parent->left = inter_node; | 540 | | | 541 | 8.30k | node->parent = inter_node; | 542 | | | 543 | | /* insert the netmask into the tree */ | 544 | 8.30k | if (netmask != NETMASK_MAX) { | 545 | 3.12k | node = new_node; | 546 | 3.12k | parent = new_node->parent; | 547 | 3.93k | while (parent != NULL && netmask < (parent->bit + 1)) { | 548 | 806 | node = parent; | 549 | 806 | parent = parent->parent; | 550 | 806 | } | 551 | 3.12k | AddNetmaskToMasks(node, netmask); | 552 | 3.12k | } | 553 | 8.30k | return new_node; | 554 | 8.30k | } |
|
555 | | |
556 | | /** |
557 | | * \brief Removes a netblock entry from an ip node. The function first |
558 | | * deletes the netblock/user_data entry for the prefix and then |
559 | | * removes the netmask entry that has been made in the tree, by |
560 | | * walking up the tree and deleting the entry from the specific node. |
561 | | * |
562 | | * \param node The node from which the netblock entry has to be removed. |
563 | | * \param netmask The netmask entry (cidr) that has to be removed. |
564 | | */ |
565 | | static void RemoveNetblockEntry(RADIX_NODE_TYPE *node, uint8_t netmask) |
566 | 0 | { |
567 | 0 | BUG_ON(!node); |
568 | | |
569 | 0 | RemoveNetmaskUserDataFromNode(node, netmask); |
570 | |
|
571 | 0 | if (netmask == NETMASK_MAX) { |
572 | 0 | SCLogDebug("%d == %d", netmask, NETMASK_MAX); |
573 | 0 | return; |
574 | 0 | } |
575 | | |
576 | 0 | RemoveNetmaskFromMasks(node, netmask); |
577 | 0 | if (node->parent != NULL) |
578 | 0 | RemoveNetmaskFromMasks(node->parent, netmask); |
579 | 0 | return; |
580 | 0 | } Unexecuted instantiation: util-radix4-tree.c:RemoveNetblockEntry Unexecuted instantiation: util-radix6-tree.c:RemoveNetblockEntry |
581 | | |
582 | | /** |
583 | | * \brief Removes a key from the Radix tree |
584 | | * |
585 | | * \param key_stream Data that has to be removed from the Radix tree |
586 | | * \param tree Pointer to the Radix tree from which the key has to be |
587 | | * removed |
588 | | */ |
589 | | static void RemoveKey(RADIX_TREE_TYPE *tree, const RADIX_CONFIG_TYPE *config, |
590 | | const uint8_t *key_stream, const uint8_t netmask) |
591 | 0 | { |
592 | 0 | RADIX_NODE_TYPE *node = tree->head; |
593 | 0 | RADIX_NODE_TYPE *parent = NULL; |
594 | 0 | RADIX_NODE_TYPE *temp_dest = NULL; |
595 | |
|
596 | 0 | if (node == NULL) { |
597 | 0 | SCLogDebug("tree is empty"); |
598 | 0 | return; |
599 | 0 | } |
600 | | |
601 | 0 | uint8_t tmp_stream[ADDRESS_BYTES]; |
602 | 0 | memcpy(tmp_stream, key_stream, sizeof(tmp_stream)); |
603 | |
|
604 | 0 | while (node->bit < NETMASK_MAX) { |
605 | 0 | if (RADIX_BITTEST(tmp_stream[node->bit >> 3], (0x80 >> (node->bit % 8)))) { |
606 | 0 | node = node->right; |
607 | 0 | } else { |
608 | 0 | node = node->left; |
609 | 0 | } |
610 | |
|
611 | 0 | if (node == NULL) { |
612 | 0 | SCLogDebug("no matching node found"); |
613 | 0 | return; |
614 | 0 | } |
615 | 0 | } |
616 | | |
617 | 0 | if (node->bit != NETMASK_MAX || !node->has_prefix) { |
618 | 0 | SCLogDebug("node %p bit %d != %d, or not has_prefix %s", node, node->bit, NETMASK_MAX, |
619 | 0 | node->has_prefix ? "true" : "false"); |
620 | 0 | return; |
621 | 0 | } |
622 | | |
623 | 0 | if (SCMemcmp(node->prefix_stream, tmp_stream, sizeof(tmp_stream)) == 0) { |
624 | 0 | if (!ContainNetmask(node, netmask)) { |
625 | 0 | SCLogDebug("key exists in the tree, but this (%d) " |
626 | 0 | "netblock entry doesn't exist", |
627 | 0 | netmask); |
628 | 0 | return; |
629 | 0 | } |
630 | 0 | } else { |
631 | 0 | SCLogDebug("You are trying to remove a key that doesn't exist in the " |
632 | 0 | "Radix Tree"); |
633 | 0 | return; |
634 | 0 | } |
635 | | |
636 | | /* The ip node does exist, and the netblock entry does exist in this node, if |
637 | | * we have reached this point. If we have more than one netblock entry, it |
638 | | * indicates we have multiple entries for this key. So we delete that |
639 | | * particular netblock entry, and make our way out of this function */ |
640 | 0 | if (NetmaskCount(node) > 1) { // || !NoneNegated(node)) { |
641 | 0 | RemoveNetblockEntry(node, netmask); |
642 | 0 | SCLogDebug("NetmaskCount"); |
643 | 0 | return; |
644 | 0 | } |
645 | 0 | SCLogDebug("not netmask cnt"); |
646 | | |
647 | | /* we are deleting the root of the tree. This would be the only node left |
648 | | * in the tree */ |
649 | 0 | if (tree->head == node) { |
650 | 0 | ReleaseNode(node, tree, config); |
651 | 0 | tree->head = NULL; |
652 | 0 | SCLogDebug("tree->head == node"); |
653 | 0 | return; |
654 | 0 | } |
655 | | |
656 | 0 | parent = node->parent; |
657 | | /* parent->parent is not the root of the tree */ |
658 | 0 | if (parent->parent != NULL) { |
659 | 0 | if (parent->parent->left == parent) { |
660 | 0 | if (node->parent->left == node) { |
661 | 0 | temp_dest = parent->right; |
662 | 0 | parent->parent->left = parent->right; |
663 | 0 | parent->right->parent = parent->parent; |
664 | 0 | } else { |
665 | 0 | temp_dest = parent->left; |
666 | 0 | parent->parent->left = parent->left; |
667 | 0 | parent->left->parent = parent->parent; |
668 | 0 | } |
669 | 0 | } else { |
670 | 0 | if (node->parent->left == node) { |
671 | 0 | temp_dest = parent->right; |
672 | 0 | parent->parent->right = parent->right; |
673 | 0 | parent->right->parent = parent->parent; |
674 | 0 | } else { |
675 | 0 | temp_dest = parent->left; |
676 | 0 | parent->parent->right = parent->left; |
677 | 0 | parent->left->parent = parent->parent; |
678 | 0 | } |
679 | 0 | } |
680 | | /* parent is the root of the tree */ |
681 | 0 | } else { |
682 | 0 | if (parent->left == node) { |
683 | 0 | temp_dest = tree->head->right; |
684 | 0 | tree->head->right->parent = NULL; |
685 | 0 | tree->head = tree->head->right; |
686 | 0 | } else { |
687 | 0 | temp_dest = tree->head->left; |
688 | 0 | tree->head->left->parent = NULL; |
689 | 0 | tree->head = tree->head->left; |
690 | 0 | } |
691 | 0 | } |
692 | | /* We need to shift the netmask entries from the node that would be |
693 | | * deleted to its immediate descendant */ |
694 | 0 | AddNetmasksFromNode(temp_dest, parent); |
695 | 0 | RemoveNetmaskFromMasks(temp_dest, netmask); |
696 | | /* release the nodes */ |
697 | 0 | ReleaseNode(parent, tree, config); |
698 | 0 | ReleaseNode(node, tree, config); |
699 | |
|
700 | 0 | SCLogDebug("end (netmask %d)", netmask); |
701 | 0 | return; |
702 | 0 | } Unexecuted instantiation: util-radix4-tree.c:RemoveKey Unexecuted instantiation: util-radix6-tree.c:RemoveKey |
703 | | |
704 | | /** |
705 | | * \brief Checks if an IP prefix falls under a netblock, in the path to the root |
706 | | * of the tree, from the node. Used internally by FindKey() |
707 | | * |
708 | | * \param prefix Pointer to the prefix that contains the ip address |
709 | | * \param node Pointer to the node from where we have to climb the tree |
710 | | */ |
711 | | static inline RADIX_NODE_TYPE *FindKeyIPNetblock(const uint8_t *key_stream, RADIX_NODE_TYPE *node, |
712 | | void **user_data_result, uint8_t *out_netmask) |
713 | 240k | { |
714 | 371k | while (node != NULL && NetmasksEmpty(node)) |
715 | 131k | node = node->parent; |
716 | 240k | if (node == NULL) |
717 | 9.42k | return NULL; |
718 | | |
719 | 231k | uint8_t tmp_stream[ADDRESS_BYTES]; |
720 | 231k | memcpy(tmp_stream, key_stream, sizeof(tmp_stream)); |
721 | | |
722 | | /* hold the node found containing a netmask. We will need it when we call |
723 | | * this function recursively */ |
724 | 231k | RADIX_NODE_TYPE *netmask_node = node; |
725 | | |
726 | 12.6M | for (uint8_t j = 0; j <= NETMASK_MAX; j++) { |
727 | 12.5M | uint8_t m = NETMASK_MAX - j; |
728 | | |
729 | 12.5M | if (!(NetmaskIssetInMasks(netmask_node, m))) |
730 | 12.3M | continue; |
731 | | |
732 | 1.82M | for (uint8_t i = 0; i < ADDRESS_BYTES; i++) { |
733 | 1.59M | uint32_t mask = UINT_MAX; |
734 | 1.59M | if (((i + 1) * 8) > m) { |
735 | 1.52M | if (((i + 1) * 8 - m) < 8) |
736 | 27.5k | mask = UINT_MAX << ((i + 1) * 8 - m); |
737 | 1.49M | else |
738 | 1.49M | mask = 0; |
739 | 1.52M | } |
740 | 1.59M | tmp_stream[i] &= mask; |
741 | 1.59M | } |
742 | | |
743 | 285k | while (node->bit < NETMASK_MAX) { |
744 | 52.4k | if (RADIX_BITTEST(tmp_stream[node->bit >> 3], (0x80 >> (node->bit % 8)))) { |
745 | 0 | node = node->right; |
746 | 52.4k | } else { |
747 | 52.4k | node = node->left; |
748 | 52.4k | } |
749 | | |
750 | 52.4k | if (node == NULL) |
751 | 0 | return NULL; |
752 | 52.4k | } |
753 | | |
754 | 233k | if (node->bit != NETMASK_MAX || !node->has_prefix) |
755 | 0 | return NULL; |
756 | | |
757 | 233k | if (SCMemcmp(node->prefix_stream, tmp_stream, sizeof(tmp_stream)) == 0) { |
758 | 213k | if (ContainNetmaskAndSetUserData(node, m, false, user_data_result)) { |
759 | 213k | *out_netmask = m; |
760 | 213k | return node; |
761 | 213k | } |
762 | 213k | } |
763 | 233k | } |
764 | | |
765 | 17.3k | return FindKeyIPNetblock(tmp_stream, netmask_node->parent, user_data_result, out_netmask); |
766 | 231k | } util-radix4-tree.c:FindKeyIPNetblock Line | Count | Source | 713 | 186k | { | 714 | 308k | while (node != NULL && NetmasksEmpty(node)) | 715 | 122k | node = node->parent; | 716 | 186k | if (node == NULL) | 717 | 8.90k | return NULL; | 718 | | | 719 | 177k | uint8_t tmp_stream[ADDRESS_BYTES]; | 720 | 177k | memcpy(tmp_stream, key_stream, sizeof(tmp_stream)); | 721 | | | 722 | | /* hold the node found containing a netmask. We will need it when we call | 723 | | * this function recursively */ | 724 | 177k | RADIX_NODE_TYPE *netmask_node = node; | 725 | | | 726 | 5.76M | for (uint8_t j = 0; j <= NETMASK_MAX; j++) { | 727 | 5.74M | uint8_t m = NETMASK_MAX - j; | 728 | | | 729 | 5.74M | if (!(NetmaskIssetInMasks(netmask_node, m))) | 730 | 5.56M | continue; | 731 | | | 732 | 890k | for (uint8_t i = 0; i < ADDRESS_BYTES; i++) { | 733 | 712k | uint32_t mask = UINT_MAX; | 734 | 712k | if (((i + 1) * 8) > m) { | 735 | 665k | if (((i + 1) * 8 - m) < 8) | 736 | 23.2k | mask = UINT_MAX << ((i + 1) * 8 - m); | 737 | 642k | else | 738 | 642k | mask = 0; | 739 | 665k | } | 740 | 712k | tmp_stream[i] &= mask; | 741 | 712k | } | 742 | | | 743 | 217k | while (node->bit < NETMASK_MAX) { | 744 | 39.3k | if (RADIX_BITTEST(tmp_stream[node->bit >> 3], (0x80 >> (node->bit % 8)))) { | 745 | 0 | node = node->right; | 746 | 39.3k | } else { | 747 | 39.3k | node = node->left; | 748 | 39.3k | } | 749 | | | 750 | 39.3k | if (node == NULL) | 751 | 0 | return NULL; | 752 | 39.3k | } | 753 | | | 754 | 178k | if (node->bit != NETMASK_MAX || !node->has_prefix) | 755 | 0 | return NULL; | 756 | | | 757 | 178k | if (SCMemcmp(node->prefix_stream, tmp_stream, sizeof(tmp_stream)) == 0) { | 758 | 160k | if (ContainNetmaskAndSetUserData(node, m, false, user_data_result)) { | 759 | 160k | *out_netmask = m; | 760 | 160k | return node; | 761 | 160k | } | 762 | 160k | } | 763 | 178k | } | 764 | | | 765 | 16.5k | return FindKeyIPNetblock(tmp_stream, netmask_node->parent, user_data_result, out_netmask); | 766 | 177k | } |
util-radix6-tree.c:FindKeyIPNetblock Line | Count | Source | 713 | 54.3k | { | 714 | 63.3k | while (node != NULL && NetmasksEmpty(node)) | 715 | 9.02k | node = node->parent; | 716 | 54.3k | if (node == NULL) | 717 | 516 | return NULL; | 718 | | | 719 | 53.7k | uint8_t tmp_stream[ADDRESS_BYTES]; | 720 | 53.7k | memcpy(tmp_stream, key_stream, sizeof(tmp_stream)); | 721 | | | 722 | | /* hold the node found containing a netmask. We will need it when we call | 723 | | * this function recursively */ | 724 | 53.7k | RADIX_NODE_TYPE *netmask_node = node; | 725 | | | 726 | 6.85M | for (uint8_t j = 0; j <= NETMASK_MAX; j++) { | 727 | 6.84M | uint8_t m = NETMASK_MAX - j; | 728 | | | 729 | 6.84M | if (!(NetmaskIssetInMasks(netmask_node, m))) | 730 | 6.79M | continue; | 731 | | | 732 | 936k | for (uint8_t i = 0; i < ADDRESS_BYTES; i++) { | 733 | 881k | uint32_t mask = UINT_MAX; | 734 | 881k | if (((i + 1) * 8) > m) { | 735 | 856k | if (((i + 1) * 8 - m) < 8) | 736 | 4.27k | mask = UINT_MAX << ((i + 1) * 8 - m); | 737 | 851k | else | 738 | 851k | mask = 0; | 739 | 856k | } | 740 | 881k | tmp_stream[i] &= mask; | 741 | 881k | } | 742 | | | 743 | 68.1k | while (node->bit < NETMASK_MAX) { | 744 | 13.0k | if (RADIX_BITTEST(tmp_stream[node->bit >> 3], (0x80 >> (node->bit % 8)))) { | 745 | 0 | node = node->right; | 746 | 13.0k | } else { | 747 | 13.0k | node = node->left; | 748 | 13.0k | } | 749 | | | 750 | 13.0k | if (node == NULL) | 751 | 0 | return NULL; | 752 | 13.0k | } | 753 | | | 754 | 55.0k | if (node->bit != NETMASK_MAX || !node->has_prefix) | 755 | 0 | return NULL; | 756 | | | 757 | 55.0k | if (SCMemcmp(node->prefix_stream, tmp_stream, sizeof(tmp_stream)) == 0) { | 758 | 52.9k | if (ContainNetmaskAndSetUserData(node, m, false, user_data_result)) { | 759 | 52.9k | *out_netmask = m; | 760 | 52.9k | return node; | 761 | 52.9k | } | 762 | 52.9k | } | 763 | 55.0k | } | 764 | | | 765 | 838 | return FindKeyIPNetblock(tmp_stream, netmask_node->parent, user_data_result, out_netmask); | 766 | 53.7k | } |
|
767 | | |
768 | | /** |
769 | | * \brief Checks if an IP address key is present in the tree. The function |
770 | | * apart from handling any normal data, also handles ipv4/ipv6 netblocks |
771 | | * |
772 | | * \param key_stream Data that has to be found in the Radix tree |
773 | | * \param tree Pointer to the Radix tree |
774 | | * \param exact_match The key to be searched is an ip address |
775 | | */ |
776 | | static RADIX_NODE_TYPE *FindKey(const RADIX_TREE_TYPE *tree, const uint8_t *key_stream, |
777 | | const uint8_t netmask, bool exact_match, void **user_data_result, uint8_t *out_netmask) |
778 | 4.00M | { |
779 | 4.00M | if (tree == NULL || tree->head == NULL) |
780 | 3.71M | return NULL; |
781 | | |
782 | 290k | RADIX_NODE_TYPE *node = tree->head; |
783 | 290k | uint8_t tmp_stream[ADDRESS_BYTES]; |
784 | 290k | memcpy(tmp_stream, key_stream, sizeof(tmp_stream)); |
785 | | |
786 | 864k | while (node->bit < NETMASK_MAX) { |
787 | 574k | if (RADIX_BITTEST(tmp_stream[node->bit >> 3], (0x80 >> (node->bit % 8)))) { |
788 | 137k | node = node->right; |
789 | 436k | } else { |
790 | 436k | node = node->left; |
791 | 436k | } |
792 | | |
793 | 574k | if (node == NULL) { |
794 | 0 | return NULL; |
795 | 0 | } |
796 | 574k | } |
797 | | |
798 | 290k | if (node->bit != NETMASK_MAX || !node->has_prefix) { |
799 | 0 | return NULL; |
800 | 0 | } |
801 | | |
802 | 290k | if (SCMemcmp(node->prefix_stream, tmp_stream, sizeof(tmp_stream)) == 0) { |
803 | 56.1k | SCLogDebug("stream match"); |
804 | 56.1k | if (ContainNetmaskAndSetUserData(node, netmask, true, user_data_result)) { |
805 | 40.4k | SCLogDebug("contains netmask etc"); |
806 | 40.4k | *out_netmask = netmask; |
807 | 40.4k | return node; |
808 | 40.4k | } |
809 | 56.1k | } |
810 | | |
811 | | /* if you are not an ip key, get out of here */ |
812 | 250k | if (exact_match) { |
813 | 26.8k | SCLogDebug("no node found and need exact match, so failed"); |
814 | 26.8k | return NULL; |
815 | 26.8k | } |
816 | | |
817 | 223k | RADIX_NODE_TYPE *ret = FindKeyIPNetblock(tmp_stream, node, user_data_result, out_netmask); |
818 | 223k | return ret; |
819 | 250k | } util-radix4-tree.c:FindKey Line | Count | Source | 778 | 2.71M | { | 779 | 2.71M | if (tree == NULL || tree->head == NULL) | 780 | 2.49M | return NULL; | 781 | | | 782 | 211k | RADIX_NODE_TYPE *node = tree->head; | 783 | 211k | uint8_t tmp_stream[ADDRESS_BYTES]; | 784 | 211k | memcpy(tmp_stream, key_stream, sizeof(tmp_stream)); | 785 | | | 786 | 755k | while (node->bit < NETMASK_MAX) { | 787 | 544k | if (RADIX_BITTEST(tmp_stream[node->bit >> 3], (0x80 >> (node->bit % 8)))) { | 788 | 125k | node = node->right; | 789 | 418k | } else { | 790 | 418k | node = node->left; | 791 | 418k | } | 792 | | | 793 | 544k | if (node == NULL) { | 794 | 0 | return NULL; | 795 | 0 | } | 796 | 544k | } | 797 | | | 798 | 211k | if (node->bit != NETMASK_MAX || !node->has_prefix) { | 799 | 0 | return NULL; | 800 | 0 | } | 801 | | | 802 | 211k | if (SCMemcmp(node->prefix_stream, tmp_stream, sizeof(tmp_stream)) == 0) { | 803 | 32.1k | SCLogDebug("stream match"); | 804 | 32.1k | if (ContainNetmaskAndSetUserData(node, netmask, true, user_data_result)) { | 805 | 21.8k | SCLogDebug("contains netmask etc"); | 806 | 21.8k | *out_netmask = netmask; | 807 | 21.8k | return node; | 808 | 21.8k | } | 809 | 32.1k | } | 810 | | | 811 | | /* if you are not an ip key, get out of here */ | 812 | 189k | if (exact_match) { | 813 | 19.8k | SCLogDebug("no node found and need exact match, so failed"); | 814 | 19.8k | return NULL; | 815 | 19.8k | } | 816 | | | 817 | 169k | RADIX_NODE_TYPE *ret = FindKeyIPNetblock(tmp_stream, node, user_data_result, out_netmask); | 818 | 169k | return ret; | 819 | 189k | } |
util-radix6-tree.c:FindKey Line | Count | Source | 778 | 1.29M | { | 779 | 1.29M | if (tree == NULL || tree->head == NULL) | 780 | 1.21M | return NULL; | 781 | | | 782 | 79.1k | RADIX_NODE_TYPE *node = tree->head; | 783 | 79.1k | uint8_t tmp_stream[ADDRESS_BYTES]; | 784 | 79.1k | memcpy(tmp_stream, key_stream, sizeof(tmp_stream)); | 785 | | | 786 | 109k | while (node->bit < NETMASK_MAX) { | 787 | 30.2k | if (RADIX_BITTEST(tmp_stream[node->bit >> 3], (0x80 >> (node->bit % 8)))) { | 788 | 11.5k | node = node->right; | 789 | 18.6k | } else { | 790 | 18.6k | node = node->left; | 791 | 18.6k | } | 792 | | | 793 | 30.2k | if (node == NULL) { | 794 | 0 | return NULL; | 795 | 0 | } | 796 | 30.2k | } | 797 | | | 798 | 79.1k | if (node->bit != NETMASK_MAX || !node->has_prefix) { | 799 | 0 | return NULL; | 800 | 0 | } | 801 | | | 802 | 79.1k | if (SCMemcmp(node->prefix_stream, tmp_stream, sizeof(tmp_stream)) == 0) { | 803 | 23.9k | SCLogDebug("stream match"); | 804 | 23.9k | if (ContainNetmaskAndSetUserData(node, netmask, true, user_data_result)) { | 805 | 18.5k | SCLogDebug("contains netmask etc"); | 806 | 18.5k | *out_netmask = netmask; | 807 | 18.5k | return node; | 808 | 18.5k | } | 809 | 23.9k | } | 810 | | | 811 | | /* if you are not an ip key, get out of here */ | 812 | 60.5k | if (exact_match) { | 813 | 7.05k | SCLogDebug("no node found and need exact match, so failed"); | 814 | 7.05k | return NULL; | 815 | 7.05k | } | 816 | | | 817 | 53.4k | RADIX_NODE_TYPE *ret = FindKeyIPNetblock(tmp_stream, node, user_data_result, out_netmask); | 818 | 53.4k | return ret; | 819 | 60.5k | } |
|
820 | | |
821 | | /** |
822 | | * \brief Checks if an IPV4 address is present in the tree |
823 | | * |
824 | | * \param key_stream Data that has to be found in the Radix tree. In this case |
825 | | * an IPV4 address |
826 | | * \param tree Pointer to the Radix tree instance |
827 | | */ |
828 | | static RADIX_NODE_TYPE *FindExactMatch( |
829 | | const RADIX_TREE_TYPE *tree, const uint8_t *key_stream, void **user_data_result) |
830 | 20.8k | { |
831 | 20.8k | uint8_t unused = 0; |
832 | 20.8k | return FindKey(tree, key_stream, NETMASK_MAX, true, user_data_result, &unused); |
833 | 20.8k | } util-radix4-tree.c:FindExactMatch Line | Count | Source | 830 | 5.19k | { | 831 | 5.19k | uint8_t unused = 0; | 832 | 5.19k | return FindKey(tree, key_stream, NETMASK_MAX, true, user_data_result, &unused); | 833 | 5.19k | } |
util-radix6-tree.c:FindExactMatch Line | Count | Source | 830 | 15.6k | { | 831 | 15.6k | uint8_t unused = 0; | 832 | 15.6k | return FindKey(tree, key_stream, NETMASK_MAX, true, user_data_result, &unused); | 833 | 15.6k | } |
|
834 | | |
835 | | /** |
836 | | * \brief Checks if an IPV4 address is present in the tree under a netblock |
837 | | * |
838 | | * \param key_stream Data that has to be found in the Radix tree. In this case |
839 | | * an IPV4 address |
840 | | * \param tree Pointer to the Radix tree instance |
841 | | */ |
842 | | static RADIX_NODE_TYPE *FindBestMatch( |
843 | | const RADIX_TREE_TYPE *tree, const uint8_t *key_stream, void **user_data_result) |
844 | 3.91M | { |
845 | 3.91M | uint8_t unused = 0; |
846 | 3.91M | return FindKey(tree, key_stream, NETMASK_MAX, false, user_data_result, &unused); |
847 | 3.91M | } util-radix4-tree.c:FindBestMatch Line | Count | Source | 844 | 2.65M | { | 845 | 2.65M | uint8_t unused = 0; | 846 | 2.65M | return FindKey(tree, key_stream, NETMASK_MAX, false, user_data_result, &unused); | 847 | 2.65M | } |
util-radix6-tree.c:FindBestMatch Line | Count | Source | 844 | 1.25M | { | 845 | 1.25M | uint8_t unused = 0; | 846 | 1.25M | return FindKey(tree, key_stream, NETMASK_MAX, false, user_data_result, &unused); | 847 | 1.25M | } |
|
848 | | |
849 | | static RADIX_NODE_TYPE *FindBestMatch2(const RADIX_TREE_TYPE *tree, const uint8_t *key_stream, |
850 | | void **user_data_result, uint8_t *out_netmask) |
851 | 0 | { |
852 | 0 | return FindKey(tree, key_stream, NETMASK_MAX, false, user_data_result, out_netmask); |
853 | 0 | } Unexecuted instantiation: util-radix4-tree.c:FindBestMatch2 Unexecuted instantiation: util-radix6-tree.c:FindBestMatch2 |
854 | | |
855 | | /** |
856 | | * \brief Checks if an IPV4 Netblock address is present in the tree |
857 | | * |
858 | | * \param key_stream Data that has to be found in the Radix tree. In this case |
859 | | * an IPV4 netblock address |
860 | | * \param tree Pointer to the Radix tree instance |
861 | | */ |
862 | | static RADIX_NODE_TYPE *FindNetblock(const RADIX_TREE_TYPE *tree, const uint8_t *key_stream, |
863 | | const uint8_t netmask, void **user_data_result) |
864 | 68.2k | { |
865 | 68.2k | uint8_t unused = 0; |
866 | 68.2k | RADIX_NODE_TYPE *node = FindKey(tree, key_stream, netmask, true, user_data_result, &unused); |
867 | 68.2k | return node; |
868 | 68.2k | } util-radix4-tree.c:FindNetblock Line | Count | Source | 864 | 46.9k | { | 865 | 46.9k | uint8_t unused = 0; | 866 | 46.9k | RADIX_NODE_TYPE *node = FindKey(tree, key_stream, netmask, true, user_data_result, &unused); | 867 | 46.9k | return node; | 868 | 46.9k | } |
util-radix6-tree.c:FindNetblock Line | Count | Source | 864 | 21.3k | { | 865 | 21.3k | uint8_t unused = 0; | 866 | 21.3k | RADIX_NODE_TYPE *node = FindKey(tree, key_stream, netmask, true, user_data_result, &unused); | 867 | 21.3k | return node; | 868 | 21.3k | } |
|
869 | | |
870 | | /** |
871 | | * \brief Helper function used by PrintTree. Prints the subtree with |
872 | | * node as the root of the subtree |
873 | | * |
874 | | * \param node Pointer to the node that is the root of the subtree to be printed |
875 | | * \param level Used for indentation purposes |
876 | | */ |
877 | | static void PrintSubtree(RADIX_NODE_TYPE *node, int level, void (*PrintData)(void *)) |
878 | 0 | { |
879 | 0 | if (node != NULL) { |
880 | 0 | PrintNodeInfo(node, level, PrintData); |
881 | 0 | PrintSubtree(node->left, level + 1, PrintData); |
882 | 0 | PrintSubtree(node->right, level + 1, PrintData); |
883 | 0 | } |
884 | |
|
885 | 0 | return; |
886 | 0 | } Unexecuted instantiation: util-radix4-tree.c:PrintSubtree Unexecuted instantiation: util-radix6-tree.c:PrintSubtree |
887 | | |
888 | | /** |
889 | | * \brief Prints the Radix Tree. While printing the radix tree we use the |
890 | | * following format |
891 | | * |
892 | | * Parent_0 |
893 | | * Left_Child_1 |
894 | | * Left_Child_2 |
895 | | * Right_Child_2 |
896 | | * Right_Child_1 |
897 | | * Left_Child_2 |
898 | | * Right_Child_2 and so on |
899 | | * |
900 | | * Each node printed out holds details on the next bit that differs |
901 | | * amongst its children, and if the node holds a prefix, the perfix is |
902 | | * printed as well. |
903 | | * |
904 | | * \param tree Pointer to the Radix tree that has to be printed |
905 | | */ |
906 | | static void PrintTree(RADIX_TREE_TYPE *tree, const RADIX_CONFIG_TYPE *config) |
907 | 0 | { |
908 | 0 | printf("Printing the Radix Tree: \n"); |
909 | 0 | PrintSubtree(tree->head, 0, config->PrintData); |
910 | 0 | } Unexecuted instantiation: util-radix4-tree.c:PrintTree Unexecuted instantiation: util-radix6-tree.c:PrintTree |
911 | | |
912 | | static bool CompareTreesSub( |
913 | | RADIX_NODE_TYPE *n1, RADIX_NODE_TYPE *n2, RADIX_TREE_COMPARE_CALLBACK Callback) |
914 | 0 | { |
915 | | // compare nodes |
916 | 0 | bool n1_has_left = n1->left != NULL; |
917 | 0 | bool n2_has_left = n2->left != NULL; |
918 | 0 | if (n1_has_left != n2_has_left) |
919 | 0 | return false; |
920 | | |
921 | 0 | bool n1_has_right = n1->right != NULL; |
922 | 0 | bool n2_has_right = n2->right != NULL; |
923 | 0 | if (n1_has_right != n2_has_right) |
924 | 0 | return false; |
925 | | |
926 | 0 | if (SCMemcmp(n1->prefix_stream, n2->prefix_stream, ADDRESS_BYTES) != 0) |
927 | 0 | return false; |
928 | | |
929 | 0 | RadixUserData *u1 = n1->user_data; |
930 | 0 | RadixUserData *u2 = n2->user_data; |
931 | 0 | while (1) { |
932 | 0 | if (u1 == NULL && u2 == NULL) |
933 | 0 | break; |
934 | 0 | if ((u1 != NULL && u2 == NULL) || (u1 == NULL && u2 != NULL)) |
935 | 0 | return false; |
936 | 0 | if (u1->netmask != u2->netmask) |
937 | 0 | return false; |
938 | | |
939 | 0 | if (Callback != NULL) { |
940 | 0 | if (!Callback(u1->user, u2->user)) |
941 | 0 | return false; |
942 | 0 | } |
943 | | |
944 | 0 | u1 = u1->next; |
945 | 0 | u2 = u2->next; |
946 | 0 | } |
947 | | |
948 | 0 | if (n1->left && n2->left) |
949 | 0 | if (!CompareTreesSub(n1->left, n2->left, Callback)) |
950 | 0 | return false; |
951 | 0 | if (n1->right && n2->right) |
952 | 0 | if (!CompareTreesSub(n1->right, n2->right, Callback)) |
953 | 0 | return false; |
954 | | |
955 | 0 | return true; |
956 | 0 | } Unexecuted instantiation: util-radix4-tree.c:CompareTreesSub Unexecuted instantiation: util-radix6-tree.c:CompareTreesSub |
957 | | |
958 | | static bool CompareTrees( |
959 | | const RADIX_TREE_TYPE *t1, const RADIX_TREE_TYPE *t2, RADIX_TREE_COMPARE_CALLBACK Callback) |
960 | 0 | { |
961 | 0 | if (t1->head == NULL && t2->head == NULL) |
962 | 0 | return true; |
963 | 0 | if ((t1->head == NULL && t2->head != NULL) || (t1->head != NULL && t2->head == NULL)) |
964 | 0 | return false; |
965 | 0 | return CompareTreesSub(t1->head, t2->head, Callback); |
966 | 0 | } Unexecuted instantiation: util-radix4-tree.c:CompareTrees Unexecuted instantiation: util-radix6-tree.c:CompareTrees |