]> git.ipfire.org Git - thirdparty/bird.git/blob - filter/trie.c
Filter: Remove mixed address tests and fix formatting
[thirdparty/bird.git] / filter / trie.c
1 /*
2 * Filters: Trie for prefix sets
3 *
4 * Copyright 2009 Ondrej Zajicek <santiago@crfreenet.org>
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
9 /**
10 * DOC: Trie for prefix sets
11 *
12 * We use a (compressed) trie to represent prefix sets. Every node
13 * in the trie represents one prefix (&addr/&plen) and &plen also
14 * indicates the index of the bit in the address that is used to
15 * branch at the node. If we need to represent just a set of
16 * prefixes, it would be simple, but we have to represent a
17 * set of prefix patterns. Each prefix pattern consists of
18 * &ppaddr/&pplen and two integers: &low and &high, and a prefix
19 * &paddr/&plen matches that pattern if the first MIN(&plen, &pplen)
20 * bits of &paddr and &ppaddr are the same and &low <= &plen <= &high.
21 *
22 * We use a bitmask (&accept) to represent accepted prefix lengths
23 * at a node. As there are 33 prefix lengths (0..32 for IPv4), but
24 * there is just one prefix of zero length in the whole trie so we
25 * have &zero flag in &f_trie (indicating whether the trie accepts
26 * prefix 0.0.0.0/0) as a special case, and &accept bitmask
27 * represents accepted prefix lengths from 1 to 32.
28 *
29 * There are two cases in prefix matching - a match when the length
30 * of the prefix is smaller that the length of the prefix pattern,
31 * (&plen < &pplen) and otherwise. The second case is simple - we
32 * just walk through the trie and look at every visited node
33 * whether that prefix accepts our prefix length (&plen). The
34 * first case is tricky - we don't want to examine every descendant
35 * of a final node, so (when we create the trie) we have to propagate
36 * that information from nodes to their ascendants.
37 *
38 * Suppose that we have two masks (M1 and M2) for a node. Mask M1
39 * represents accepted prefix lengths by just the node and mask M2
40 * represents accepted prefix lengths by the node or any of its
41 * descendants. Therefore M2 is a bitwise or of M1 and children's
42 * M2 and this is a maintained invariant during trie building.
43 * Basically, when we want to match a prefix, we walk through the trie,
44 * check mask M1 for our prefix length and when we came to
45 * final node, we check mask M2.
46 *
47 * There are two differences in the real implementation. First,
48 * we use a compressed trie so there is a case that we skip our
49 * final node (if it is not in the trie) and we came to node that
50 * is either extension of our prefix, or completely out of path
51 * In the first case, we also have to check M2.
52 *
53 * Second, we really need not to maintain two separate bitmasks.
54 * Checks for mask M1 are always larger than &applen and we need
55 * just the first &pplen bits of mask M2 (if trie compression
56 * hadn't been used it would suffice to know just $applen-th bit),
57 * so we have to store them together in &accept mask - the first
58 * &pplen bits of mask M2 and then mask M1.
59 *
60 * There are four cases when we walk through a trie:
61 *
62 * - we are in NULL
63 * - we are out of path (prefixes are inconsistent)
64 * - we are in the wanted (final) node (node length == &plen)
65 * - we are beyond the end of path (node length > &plen)
66 * - we are still on path and keep walking (node length < &plen)
67 *
68 * The walking code in trie_match_prefix() is structured according to
69 * these cases.
70 */
71
72 #include "nest/bird.h"
73 #include "lib/string.h"
74 #include "conf/conf.h"
75 #include "filter/filter.h"
76 #include "filter/data.h"
77
78
79 /*
80 * In the trie_add_prefix(), we use ip_addr (assuming that it is the same as
81 * ip6_addr) to handle both IPv4 and IPv6 prefixes. In contrast to rest of the
82 * BIRD, IPv4 addresses are just zero-padded from right. That is why we have
83 * ipt_from_ip4() and ipt_to_ip4() macros below.
84 */
85
86 #define ipa_mkmask(x) ip6_mkmask(x)
87 #define ipa_masklen(x) ip6_masklen(&x)
88 #define ipa_pxlen(x,y) ip6_pxlen(x,y)
89 #define ipa_getbit(x,n) ip6_getbit(x,n)
90
91 #define ipt_from_ip4(x) _MI6(_I(x), 0, 0, 0)
92 #define ipt_to_ip4(x) _MI4(_I0(x))
93
94
95 /**
96 * f_new_trie - allocates and returns a new empty trie
97 * @lp: linear pool to allocate items from
98 * @data_size: user data attached to node
99 */
100 struct f_trie *
101 f_new_trie(linpool *lp, uint data_size)
102 {
103 struct f_trie * ret;
104 ret = lp_allocz(lp, sizeof(struct f_trie) + data_size);
105 ret->lp = lp;
106 ret->ipv4 = -1;
107 ret->data_size = data_size;
108 return ret;
109 }
110
111 static inline struct f_trie_node4 *
112 new_node4(struct f_trie *t, int plen, ip4_addr paddr, ip4_addr pmask, ip4_addr amask)
113 {
114 struct f_trie_node4 *n = lp_allocz(t->lp, sizeof(struct f_trie_node4) + t->data_size);
115 n->plen = plen;
116 n->addr = paddr;
117 n->mask = pmask;
118 n->accept = amask;
119 return n;
120 }
121
122 static inline struct f_trie_node6 *
123 new_node6(struct f_trie *t, int plen, ip6_addr paddr, ip6_addr pmask, ip6_addr amask)
124 {
125 struct f_trie_node6 *n = lp_allocz(t->lp, sizeof(struct f_trie_node6) + t->data_size);
126 n->plen = plen;
127 n->addr = paddr;
128 n->mask = pmask;
129 n->accept = amask;
130 return n;
131 }
132
133 static inline struct f_trie_node *
134 new_node(struct f_trie *t, int plen, ip_addr paddr, ip_addr pmask, ip_addr amask)
135 {
136 if (t->ipv4)
137 return (struct f_trie_node *) new_node4(t, plen, ipt_to_ip4(paddr), ipt_to_ip4(pmask), ipt_to_ip4(amask));
138 else
139 return (struct f_trie_node *) new_node6(t, plen, ipa_to_ip6(paddr), ipa_to_ip6(pmask), ipa_to_ip6(amask));
140 }
141
142 static inline void
143 attach_node4(struct f_trie_node4 *parent, struct f_trie_node4 *child)
144 {
145 parent->c[ip4_getbit(child->addr, parent->plen) ? 1 : 0] = child;
146 }
147
148 static inline void
149 attach_node6(struct f_trie_node6 *parent, struct f_trie_node6 *child)
150 {
151 parent->c[ip6_getbit(child->addr, parent->plen) ? 1 : 0] = child;
152 }
153
154 static inline void
155 attach_node(struct f_trie_node *parent, struct f_trie_node *child, int v4)
156 {
157 if (v4)
158 attach_node4(&parent->v4, &child->v4);
159 else
160 attach_node6(&parent->v6, &child->v6);
161 }
162
163 #define GET_ADDR(N,F,X) ((X) ? ipt_from_ip4((N)->v4.F) : ipa_from_ip6((N)->v6.F))
164 #define SET_ADDR(N,F,X,V) ({ if (X) (N)->v4.F =ipt_to_ip4(V); else (N)->v6.F =ipa_to_ip6(V); })
165
166 #define GET_CHILD(N,F,X,I) ((X) ? (struct f_trie_node *) (N)->v4.c[I] : (struct f_trie_node *) (N)->v6.c[I])
167 /**
168 * trie_add_prefix
169 * @t: trie to add to
170 * @net: IP network prefix
171 * @l: prefix lower bound
172 * @h: prefix upper bound
173 *
174 * Adds prefix (prefix pattern) @n to trie @t. @l and @h are lower
175 * and upper bounds on accepted prefix lengths, both inclusive.
176 * 0 <= l, h <= 32 (128 for IPv6).
177 *
178 * Returns a pointer to the allocated node. The function can return a pointer to
179 * an existing node if @px and @plen are the same. If px/plen == 0/0 (or ::/0),
180 * a pointer to the root node is returned. Returns NULL when called with
181 * mismatched IPv4/IPv6 net type.
182 */
183
184 void *
185 trie_add_prefix(struct f_trie *t, const net_addr *net, uint l, uint h)
186 {
187 uint plen = net_pxlen(net);
188 ip_addr px;
189 int v4;
190
191 switch (net->type)
192 {
193 case NET_IP4: px = ipt_from_ip4(net4_prefix(net)); v4 = 1; break;
194 case NET_IP6: px = ipa_from_ip6(net6_prefix(net)); v4 = 0; break;
195 default: bug("invalid type");
196 }
197
198 if (t->ipv4 != v4)
199 {
200 if (t->ipv4 < 0)
201 t->ipv4 = v4;
202 else
203 return NULL;
204 }
205
206 if (l == 0)
207 t->zero = 1;
208 else
209 l--;
210
211 if (h < plen)
212 plen = h;
213
214 ip_addr amask = ipa_xor(ipa_mkmask(l), ipa_mkmask(h));
215 ip_addr pmask = ipa_mkmask(plen);
216 ip_addr paddr = ipa_and(px, pmask);
217 struct f_trie_node *o = NULL;
218 struct f_trie_node *n = &t->root;
219
220 while (n)
221 {
222 ip_addr naddr = GET_ADDR(n, addr, v4);
223 ip_addr nmask = GET_ADDR(n, mask, v4);
224 ip_addr accept = GET_ADDR(n, accept, v4);
225 ip_addr cmask = ipa_and(nmask, pmask);
226 uint nlen = v4 ? n->v4.plen : n->v6.plen;
227
228 if (ipa_compare(ipa_and(paddr, cmask), ipa_and(naddr, cmask)))
229 {
230 /* We are out of path - we have to add branching node 'b'
231 between node 'o' and node 'n', and attach new node 'a'
232 as the other child of 'b'. */
233 int blen = ipa_pxlen(paddr, naddr);
234 ip_addr bmask = ipa_mkmask(blen);
235 ip_addr baddr = ipa_and(px, bmask);
236
237 /* Merge accept masks from children to get accept mask for node 'b' */
238 ip_addr baccm = ipa_and(ipa_or(amask, accept), bmask);
239
240 struct f_trie_node *a = new_node(t, plen, paddr, pmask, amask);
241 struct f_trie_node *b = new_node(t, blen, baddr, bmask, baccm);
242 attach_node(o, b, v4);
243 attach_node(b, n, v4);
244 attach_node(b, a, v4);
245 return a;
246 }
247
248 if (plen < nlen)
249 {
250 /* We add new node 'a' between node 'o' and node 'n' */
251 amask = ipa_or(amask, ipa_and(accept, pmask));
252 struct f_trie_node *a = new_node(t, plen, paddr, pmask, amask);
253 attach_node(o, a, v4);
254 attach_node(a, n, v4);
255 return a;
256 }
257
258 if (plen == nlen)
259 {
260 /* We already found added node in trie. Just update accept mask */
261 accept = ipa_or(accept, amask);
262 SET_ADDR(n, accept, v4, accept);
263 return n;
264 }
265
266 /* Update accept mask part M2 and go deeper */
267 accept = ipa_or(accept, ipa_and(amask, nmask));
268 SET_ADDR(n, accept, v4, accept);
269
270 /* n->plen < plen and plen <= 32 (128) */
271 o = n;
272 n = GET_CHILD(n, c, v4, ipa_getbit(paddr, nlen) ? 1 : 0);
273 }
274
275 /* We add new tail node 'a' after node 'o' */
276 struct f_trie_node *a = new_node(t, plen, paddr, pmask, amask);
277 attach_node(o, a, v4);
278
279 return a;
280 }
281
282 static int
283 trie_match_net4(const struct f_trie *t, ip4_addr px, uint plen)
284 {
285 ip4_addr pmask = ip4_mkmask(plen);
286 ip4_addr paddr = ip4_and(px, pmask);
287
288 if (plen == 0)
289 return t->zero;
290
291 int plentest = plen - 1;
292 const struct f_trie_node4 *n = &t->root.v4;
293
294 while (n)
295 {
296 ip4_addr cmask = ip4_and(n->mask, pmask);
297
298 /* We are out of path */
299 if (ip4_compare(ip4_and(paddr, cmask), ip4_and(n->addr, cmask)))
300 return 0;
301
302 /* Check accept mask */
303 if (ip4_getbit(n->accept, plentest))
304 return 1;
305
306 /* We finished trie walk and still no match */
307 if (plen <= n->plen)
308 return 0;
309
310 /* Choose children */
311 n = n->c[(ip4_getbit(paddr, n->plen)) ? 1 : 0];
312 }
313
314 return 0;
315 }
316
317 static int
318 trie_match_net6(const struct f_trie *t, ip6_addr px, uint plen)
319 {
320 ip6_addr pmask = ip6_mkmask(plen);
321 ip6_addr paddr = ip6_and(px, pmask);
322
323 if (plen == 0)
324 return t->zero;
325
326 int plentest = plen - 1;
327 const struct f_trie_node6 *n = &t->root.v6;
328
329 while (n)
330 {
331 ip6_addr cmask = ip6_and(n->mask, pmask);
332
333 /* We are out of path */
334 if (ip6_compare(ip6_and(paddr, cmask), ip6_and(n->addr, cmask)))
335 return 0;
336
337 /* Check accept mask */
338 if (ip6_getbit(n->accept, plentest))
339 return 1;
340
341 /* We finished trie walk and still no match */
342 if (plen <= n->plen)
343 return 0;
344
345 /* Choose children */
346 n = n->c[(ip6_getbit(paddr, n->plen)) ? 1 : 0];
347 }
348
349 return 0;
350 }
351
352 /**
353 * trie_match_net
354 * @t: trie
355 * @n: net address
356 *
357 * Tries to find a matching net in the trie such that
358 * prefix @n matches that prefix pattern. Returns 1 if there
359 * is such prefix pattern in the trie.
360 */
361 int
362 trie_match_net(const struct f_trie *t, const net_addr *n)
363 {
364 switch (n->type)
365 {
366 case NET_IP4:
367 case NET_VPN4:
368 case NET_ROA4:
369 return t->ipv4 ? trie_match_net4(t, net4_prefix(n), net_pxlen(n)) : 0;
370
371 case NET_IP6:
372 case NET_VPN6:
373 case NET_ROA6:
374 return !t->ipv4 ? trie_match_net6(t, net6_prefix(n), net_pxlen(n)) : 0;
375
376 default:
377 return 0;
378 }
379 }
380
381 static int
382 trie_node_same4(const struct f_trie_node4 *t1, const struct f_trie_node4 *t2)
383 {
384 if ((t1 == NULL) && (t2 == NULL))
385 return 1;
386
387 if ((t1 == NULL) || (t2 == NULL))
388 return 0;
389
390 if ((t1->plen != t2->plen) ||
391 (! ip4_equal(t1->addr, t2->addr)) ||
392 (! ip4_equal(t1->accept, t2->accept)))
393 return 0;
394
395 return trie_node_same4(t1->c[0], t2->c[0]) && trie_node_same4(t1->c[1], t2->c[1]);
396 }
397
398 static int
399 trie_node_same6(const struct f_trie_node6 *t1, const struct f_trie_node6 *t2)
400 {
401 if ((t1 == NULL) && (t2 == NULL))
402 return 1;
403
404 if ((t1 == NULL) || (t2 == NULL))
405 return 0;
406
407 if ((t1->plen != t2->plen) ||
408 (! ip6_equal(t1->addr, t2->addr)) ||
409 (! ip6_equal(t1->accept, t2->accept)))
410 return 0;
411
412 return trie_node_same6(t1->c[0], t2->c[0]) && trie_node_same6(t1->c[1], t2->c[1]);
413 }
414
415 /**
416 * trie_same
417 * @t1: first trie to be compared
418 * @t2: second one
419 *
420 * Compares two tries and returns 1 if they are same
421 */
422 int
423 trie_same(const struct f_trie *t1, const struct f_trie *t2)
424 {
425 if ((t1->zero != t2->zero) || (t1->ipv4 != t2->ipv4))
426 return 0;
427
428 if (t1->ipv4)
429 return trie_node_same4(&t1->root.v4, &t2->root.v4);
430 else
431 return trie_node_same6(&t1->root.v6, &t2->root.v6);
432 }
433
434 static void
435 trie_node_format4(const struct f_trie_node4 *t, buffer *buf)
436 {
437 if (t == NULL)
438 return;
439
440 if (ip4_nonzero(t->accept))
441 buffer_print(buf, "%I4/%d{%I4}, ", t->addr, t->plen, t->accept);
442
443 trie_node_format4(t->c[0], buf);
444 trie_node_format4(t->c[1], buf);
445 }
446
447 static void
448 trie_node_format6(const struct f_trie_node6 *t, buffer *buf)
449 {
450 if (t == NULL)
451 return;
452
453 if (ip6_nonzero(t->accept))
454 buffer_print(buf, "%I6/%d{%I6}, ", t->addr, t->plen, t->accept);
455
456 trie_node_format6(t->c[0], buf);
457 trie_node_format6(t->c[1], buf);
458 }
459
460 /**
461 * trie_format
462 * @t: trie to be formatted
463 * @buf: destination buffer
464 *
465 * Prints the trie to the supplied buffer.
466 */
467 void
468 trie_format(const struct f_trie *t, buffer *buf)
469 {
470 buffer_puts(buf, "[");
471
472 if (t->zero)
473 buffer_print(buf, "%I/%d, ", t->ipv4 ? IPA_NONE4 : IPA_NONE6, 0);
474
475 if (t->ipv4)
476 trie_node_format4(&t->root.v4, buf);
477 else
478 trie_node_format6(&t->root.v6, buf);
479
480 if (buf->pos == buf->end)
481 return;
482
483 /* Undo last separator */
484 if (buf->pos[-1] != '[')
485 buf->pos -= 2;
486
487 buffer_puts(buf, "]");
488 }