summaryrefslogtreecommitdiffstats
path: root/src/knot/zone/zone-tree.h
blob: 384e87efdfc7cd8a463d15c7a3684d7d8dbaf6d2 (plain)
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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
/*  Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

#pragma once

#include "contrib/qp-trie/trie.h"
#include "contrib/ucw/lists.h"
#include "knot/zone/node.h"

enum {
	/*! Indication of a zone tree with bi-nodes (two zone_node_t structures allocated for one node). */
	ZONE_TREE_USE_BINODES = (1 << 0),
	/*! If set, from each bi-node in the zone tree, the second zone_node_t is valid. */
	ZONE_TREE_BINO_SECOND = (1 << 1),
};

typedef struct {
	trie_t *trie;
	trie_cow_t *cow; // non-NULL only during zone update
	uint16_t flags;
} zone_tree_t;

/*!
 * \brief Signature of callback for zone apply functions.
 */
typedef int (*zone_tree_apply_cb_t)(zone_node_t *node, void *data);

typedef zone_node_t *(*zone_tree_new_node_cb_t)(const knot_dname_t *dname, void *ctx);

/*!
 * \brief Zone tree iteration context.
 */
typedef struct {
	zone_tree_t *tree;
	trie_it_t *it;
	int binode_second;

	zone_tree_t *next_tree;
	knot_dname_t *sub_root;
} zone_tree_it_t;

typedef struct {
	zone_node_t **nodes;
	size_t total;
	size_t current;
	bool incl_del;
} zone_tree_delsafe_it_t;

/*!
 * \brief Creates the zone tree.
 *
 * \return created zone tree structure.
 */
zone_tree_t *zone_tree_create(bool use_binodes);

zone_tree_t *zone_tree_cow(zone_tree_t *from);

/*!
 * \brief Create a clone of existing zone_tree.
 *
 * \note Copies only the trie, not individual nodes.
 *
 * \warning Don't use COW in the duplicate.
 */
zone_tree_t *zone_tree_shallow_copy(zone_tree_t *from);

/*!
 * \brief Return number of nodes in the zone tree.
 *
 * \param tree Zone tree.
 *
 * \return number of nodes in tree.
 */
inline static size_t zone_tree_count(const zone_tree_t *tree)
{
	if (tree == NULL || tree->trie == NULL) {
		return 0;
	}

	return trie_weight(tree->trie);
}

/*!
 * \brief Checks if the zone tree is empty.
 *
 * \param tree Zone tree to check.
 *
 * \return Nonzero if the zone tree is empty.
 */
inline static bool zone_tree_is_empty(const zone_tree_t *tree)
{
	return zone_tree_count(tree) == 0;
}

inline static zone_node_t *zone_tree_fix_get(zone_node_t *node, const zone_tree_t *tree)
{
	assert(((node->flags & NODE_FLAGS_BINODE) ? 1 : 0) == ((tree->flags & ZONE_TREE_USE_BINODES) ? 1 : 0));
	assert((tree->flags & ZONE_TREE_USE_BINODES) || !(tree->flags & ZONE_TREE_BINO_SECOND));
	return binode_node(node, (tree->flags & ZONE_TREE_BINO_SECOND));
}

inline static zone_node_t *node_new_for_tree(const knot_dname_t *owner, const zone_tree_t *tree, knot_mm_t *mm)
{
	assert((tree->flags & ZONE_TREE_USE_BINODES) || !(tree->flags & ZONE_TREE_BINO_SECOND));
	return node_new(owner, (tree->flags & ZONE_TREE_USE_BINODES), (tree->flags & ZONE_TREE_BINO_SECOND), mm);
}

/*!
 * \brief Inserts the given node into the zone tree.
 *
 * \param tree Zone tree to insert the node into.
 * \param node Node to insert. If it's binode, the pointer will be adjusted to correct node.
 *
 * \retval KNOT_EOK
 * \retval KNOT_EINVAL
 * \retval KNOT_ENOMEM
 */
int zone_tree_insert(zone_tree_t *tree, zone_node_t **node);

/*!
 * \brief Insert a node together with its parents (iteratively node->parent).
 *
 * \param tree   Zone tree to insert into.
 * \param node   Node to be inserted with parents.
 * \param without_parents   Actually, insert it without parents.
 *
 * \return KNOT_E*
 */
int zone_tree_insert_with_parents(zone_tree_t *tree, zone_node_t *node, bool without_parents);

/*!
 * \brief Finds node with the given owner in the zone tree.
 *
 * \param tree Zone tree to search in.
 * \param owner Owner of the node to find.
 *
 * \retval Found node or NULL.
 */
zone_node_t *zone_tree_get(zone_tree_t *tree, const knot_dname_t *owner);

/*!
 * \brief Tries to find the given domain name in the zone tree and returns the
 *        associated node and previous node in canonical order.
 *
 * \param tree Zone to search in.
 * \param owner Owner of the node to find.
 * \param found Found node.
 * \param previous Previous node in canonical order (i.e. the one directly
 *                 preceding \a owner in canonical order, regardless if the name
 *                 is in the zone or not).
 *
 * \retval > 0 if the domain name was found. In such case \a found holds the
 *             zone node with \a owner as its owner.
 *             \a previous is set properly.
 * \retval 0 if the domain name was not found. \a found may hold any (or none)
 *           node. \a previous is set properly.
 * \retval KNOT_EINVAL
 * \retval KNOT_ENOMEM
 */
int zone_tree_get_less_or_equal(zone_tree_t *tree,
                                const knot_dname_t *owner,
                                zone_node_t **found,
                                zone_node_t **previous);

/*!
 * \brief Remove a node from a tree with no checks.
 *
 * \param tree  The tree to remove from.
 * \param owner The node to remove.
 */
void zone_tree_remove_node(zone_tree_t *tree, const knot_dname_t *owner);

/*!
 * \brief Create a node in zone tree if not already exists, and also all parent nodes.
 *
 * \param tree         Zone tree to insert into.
 * \param apex         Zone contents apex node.
 * \param dname        Name of the node to be added.
 * \param new_cb       Callback for allocating new node.
 * \param new_cb_ctx   Context to be passed to allocating callback.
 * \param new_node     Output: pointer on added (or existing) node with specified dname.
 *
 * \return KNOT_E*
 */
int zone_tree_add_node(zone_tree_t *tree, zone_node_t *apex, const knot_dname_t *dname,
                       zone_tree_new_node_cb_t new_cb, void *new_cb_ctx, zone_node_t **new_node);

/*!
 * \brief Remove a node in zone tree, removing also empty parents.
 *
 * \param tree          Zone tree to remove from.
 * \param node          Node to be removed.
 * \param free_deleted  Indication to free node.
 *
 * \return KNOT_E*
 */
int zone_tree_del_node(zone_tree_t *tree, zone_node_t *node, bool free_deleted);

/*!
 * \brief Applies the given function to each node in the zone in order.
 *
 * \param tree Zone tree to apply the function to.
 * \param function Function to be applied to each node of the zone.
 * \param data Arbitrary data to be passed to the function.
 *
 * \retval KNOT_EOK
 * \retval KNOT_EINVAL
 */
int zone_tree_apply(zone_tree_t *tree, zone_tree_apply_cb_t function, void *data);

/*!
 * \brief Applies given function to each node in a subtree.
 *
 * \param tree        Zone tree.
 * \param sub_root    Name denoting the subtree.
 * \param excl_root   Exclude the subtree root.
 * \param function    Callback to be applied.
 * \param data        Callback context.
 *
 * \return KNOT_E*
 */
int zone_tree_sub_apply(zone_tree_t *tree, const knot_dname_t *sub_root,
                        bool excl_root, zone_tree_apply_cb_t function, void *data);

/*!
 * \brief Start zone tree iteration.
 *
 * \param tree   Zone tree to iterate over.
 * \param it     Out: iteration context. It shall be zeroed before.
 *
 * \return KNOT_OK, KNOT_ENOMEM
 */
int zone_tree_it_begin(zone_tree_t *tree, zone_tree_it_t *it);

/*!
 * \brief Start iteration over a subtree.
 *
 * \param tree        Zone tree to iterate in.
 * \param sub_root    Iterate over node of this name and all children.
 * \param it          Out: iteration context, shall be zeroed before.
 *
 * \return KNOT_E*
 */
int zone_tree_it_sub_begin(zone_tree_t *tree, const knot_dname_t *sub_root,
                           zone_tree_it_t *it);

/*!
 * \brief Start iteration of two zone trees.
 *
 * This is useful e.g. for iteration over normal and NSEC3 nodes.
 *
 * \param first    First tree to be iterated over.
 * \param second   Second tree to be iterated over.
 * \param it       Out: iteration context. It shall be zeroed before.
 *
 * \return KNOT_OK, KNOT_ENOMEM
 */
int zone_tree_it_double_begin(zone_tree_t *first, zone_tree_t *second, zone_tree_it_t *it);

/*!
 * \brief Return true iff iteration is finished.
 *
 * \note The iteration context needs to be freed afterwards nevertheless.
 */
bool zone_tree_it_finished(zone_tree_it_t *it);

/*!
 * \brief Return the node, zone iteration is currently pointing at.
 *
 * \note Don't call this when zone_tree_it_finished.
 */
zone_node_t *zone_tree_it_val(zone_tree_it_t *it);

/*!
 * \brief Remove from zone tree the node that iteration is pointing at.
 *
 * \note This doesn't free the node.
 */
void zone_tree_it_del(zone_tree_it_t *it);

/*!
 * \brief Move the iteration to next node.
 */
void zone_tree_it_next(zone_tree_it_t *it);

/*!
 * \brief Free zone iteration context.
 */
void zone_tree_it_free(zone_tree_it_t *it);

/*!
 * \brief Zone tree iteration allowing tree changes.
 *
 * The semantics is the same like for normal iteration.
 * The set of iterated nodes is according to zone tree state on the beginning.
 */
int zone_tree_delsafe_it_begin(zone_tree_t *tree, zone_tree_delsafe_it_t *it, bool include_deleted);
bool zone_tree_delsafe_it_finished(zone_tree_delsafe_it_t *it);
void zone_tree_delsafe_it_restart(zone_tree_delsafe_it_t *it);
zone_node_t *zone_tree_delsafe_it_val(zone_tree_delsafe_it_t *it);
void zone_tree_delsafe_it_next(zone_tree_delsafe_it_t *it);
void zone_tree_delsafe_it_free(zone_tree_delsafe_it_t *it);

/*!
 * \brief Merge all nodes from 'what' to 'into'.
 *
 * \param into  Zone tree to be inserted into..
 * \param what  ...all nodes from this one.
 *
 * \return KNOT_E*
 */
int zone_tree_merge(zone_tree_t *into, zone_tree_t *what);

/*!
 * \brief Unify all bi-nodes in specified trees.
 */
void zone_trees_unify_binodes(zone_tree_t *nodes, zone_tree_t *nsec3_nodes, bool free_deleted);

/*!
 * \brief Destroys the zone tree, not touching the saved data.
 *
 * \param tree Zone tree to be destroyed.
 */
void zone_tree_free(zone_tree_t **tree);