The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
trie.c
Go to the documentation of this file.
1 /*
2  * This library is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU Lesser General Public
4  * License as published by the Free Software Foundation; either
5  * version 2.1 of the License, or (at your option) any later version.
6  *
7  * This library 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 GNU
10  * Lesser General Public License for more details.
11  *
12  * You should have received a copy of the GNU Lesser General Public
13  * License along with this library; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /** Path-compressed prefix tries
18  *
19  * @file src/lib/util/trie.c
20  *
21  * @copyright 2017 Alan DeKok (aland@freeradius.org)
22  */
23 RCSID("$Id: 237c42ab6edc7280b38a8a0214250d17802925d5 $")
24 
25 #include <freeradius-devel/util/dict.h>
26 #include <freeradius-devel/util/misc.h>
27 #include <freeradius-devel/util/syserror.h>
28 #include <freeradius-devel/util/trie.h>
29 
30 
31 /*
32  * This file implements path-compressed, level-compressed
33  * patricia tries. The original research paper is:
34  *
35  * https://www.nada.kth.se/~snilsson/publications/Dynamic-trie-compression-implementation/
36  *
37  * The functionality has been extended to include intermediate
38  * nodes which consume 0 bits, but which hold user context data.
39  * These intermediate nodes allow for "longest prefix" matching.
40  * For example, in networking, you can have a routing table entry
41  * with 0/0 leading to one destination, and 10/8 leading to a
42  * different one. Looking up an address in the 10/8 network will
43  * return the 10/8 destination. Looking up any other address
44  * will return the default destination.
45  *
46  * In addition, we desire the ability to add and delete nodes
47  * dynamically. In the example given above, this means that
48  * after deleting 10/8, the trie should contain only the 0/0
49  * network and associated destination.
50  *
51  * As of yet, it does not do level compression. This can be
52  * added without (hopefully) too much work. That would require
53  * an additional step to "normalize" the trie.
54  *
55  * This code could be extended to do packet matching, through the
56  * inclusion of "don't care" paths. e.g. parsing an IP header,
57  * where the src/dst IP addresses are 32-bit "don't care" fields.
58  *
59  * It could also be extended via "count" paths, where the path
60  * holds a count that is used in another part of the trie. For
61  * example, in RADIUS. The attribute encoding is one byte
62  * attribute, one byte length, followed by "length - 2" bytes of
63  * data. At that point though, you might as well just use Ragel.
64  */
65 
66 /** Enable path compression (or not)
67  *
68  * With path compression, long sequences of bits are stored as a
69  * path, e.g. "abcdef". Without path compression, we would have to
70  * create a large number of intermediate 2^N-way nodes, all of which
71  * would have only one edge.
72  */
73 #if !defined(NO_PATH_COMPRESSION) && !defined(WITH_PATH_COMPRESSION)
74 #define WITH_PATH_COMPRESSION
75 #endif
76 
77 //#define WITH_NODE_COMPRESSION
78 
79 #ifdef WITH_NODE_COMPRESSION
80 #ifndef WITH_PATH_COMPRESSION
81 #define WITH_PATH_COMPRESSION
82 #endif
83 
84 #ifndef MAX_COMP_BITS
85 #define MAX_COMP_BITS (8)
86 #endif
87 
88 #ifndef MAX_COMP_EDGES
89 #define MAX_COMP_EDGES (4)
90 #endif
91 
92 #endif /* WITH_NODE_COMPRESSION */
93 
94 #define MAX_KEY_BYTES (256)
95 #define MAX_KEY_BITS (MAX_KEY_BYTES * 8)
96 
97 #ifndef MAX_NODE_BITS
98 #define MAX_NODE_BITS (4)
99 #endif
100 
101 /** Internal sanity checks for debugging.
102  *
103  * Tries are complex. So we have verification routines for every
104  * type of node. These routines are called from within the trie
105  * manipulation functions. If the trie manipulation has a bug, the
106  * verification routines are likely to catch some of the more
107  * egregious issues.
108  */
109 DIAG_OFF(unused-macros)
110 #ifdef TESTING
111 #define WITH_TRIE_VERIFY (1)
112 # define MPRINT(...) fprintf(stderr, ## __VA_ARGS__)
113 
114  /* define this to be MPRINT for additional debugging */
115 # define MPRINT2(...)
116 # define MPRINT3(...)
117 static void trie_sprint(fr_trie_t *trie, uint8_t const *key, int start_bit, int lineno);
118 #else
119 # define MPRINT(...)
120 # define MPRINT2(...)
121 # define MPRINT3(...)
122 #define trie_sprint(_trie, _key, _start_bit, _lineno)
123 #endif
124 
125 #ifdef WITH_TRIE_VERIFY
126 static int trie_verify(fr_trie_t *trie);
127 //#define VERIFY(_x) fr_cond_assert(trie_verify((fr_trie_t *) _x) == 0)
128 #define VERIFY(_x) if (trie_verify((fr_trie_t *) _x) < 0) do { fprintf(stderr, "FAIL VERIFY at %d - %s\n", __LINE__, fr_strerror()); fr_cond_assert(0); } while (0)
129 #else
130 #define VERIFY(_x)
131 #endif
132 
133 /*
134  * Macros to swap one for the other.
135  */
136 #define BITSOF(_x) ((_x) * 8)
137 #define BYTEOF(_x) ((_x) >> 3)
138 #define BYTES(_x) (((_x) + 0x07) >> 3)
139 DIAG_ON(unused-macros)
140 
141 
142 // @todo - do level compression
143 // stop merging nodes if a key ends at the top of the level
144 // otherwise merge so we have at least 2^4 way fan-out, but no more than 2^8
145 // that should be a decent trade-off between memory and speed
146 
147 // @todo - generalized function to normalize the trie.
148 
149 
150 static uint8_t start_bit_mask[8] = {
151  0xff, 0x7f, 0x3f, 0x1f,
152  0x0f, 0x07, 0x03, 0x01
153 };
154 
155 static uint8_t used_bit_mask[8] = {
156  0x80, 0xc0, 0xe0, 0xf0,
157  0xf8, 0xfc, 0xfe, 0xff,
158 };
159 
160 #if 0
161 /*
162  * For testing and debugging.
163  */
164 static char const *spaces = " ";
165 #endif
166 
167 
168 #if defined(WITH_PATH_COMPRESSION) || defined(TESTING)
169 /*
170  * Table of how many leading bits there are in KEY1^KEY2.
171  */
172 static uint8_t xor2lcp[256] = {
173  8, 7, 6, 6,
174  5, 5, 5, 5, /* 4x 5 */
175  4, 4, 4, 4, /* 8x 4 */
176  4, 4, 4, 4,
177  3, 3, 3, 3, /* 16x 3 */
178  3, 3, 3, 3,
179  3, 3, 3, 3,
180  3, 3, 3, 3,
181  2, 2, 2, 2, /* 32x 2 */
182  2, 2, 2, 2,
183  2, 2, 2, 2,
184  2, 2, 2, 2,
185  2, 2, 2, 2,
186  2, 2, 2, 2,
187  2, 2, 2, 2,
188  2, 2, 2, 2,
189  1, 1, 1, 1, /* 64x 1 */
190  1, 1, 1, 1,
191  1, 1, 1, 1,
192  1, 1, 1, 1,
193  1, 1, 1, 1,
194  1, 1, 1, 1,
195  1, 1, 1, 1,
196  1, 1, 1, 1,
197  1, 1, 1, 1,
198  1, 1, 1, 1,
199  1, 1, 1, 1,
200  1, 1, 1, 1,
201  1, 1, 1, 1,
202  1, 1, 1, 1,
203  1, 1, 1, 1,
204  1, 1, 1, 1,
205  0, 0, 0, 0, /* 128x 0 */
206  0, 0, 0, 0,
207  0, 0, 0, 0,
208  0, 0, 0, 0,
209  0, 0, 0, 0,
210  0, 0, 0, 0,
211  0, 0, 0, 0,
212  0, 0, 0, 0,
213  0, 0, 0, 0,
214  0, 0, 0, 0,
215  0, 0, 0, 0,
216  0, 0, 0, 0,
217  0, 0, 0, 0,
218  0, 0, 0, 0,
219  0, 0, 0, 0,
220  0, 0, 0, 0,
221 };
222 
223 
224 /** Get the longest prefix of the two keys.
225  *
226  */
227 static int fr_trie_key_lcp(uint8_t const *key1, int keylen1, uint8_t const *key2, int keylen2, int start_bit)
228 {
229  int lcp, end_bit;
230 
231  if (!keylen1 || !keylen2) return 0;
232  fr_cond_assert((start_bit & 0x07) == start_bit);
233 
234  end_bit = keylen1;
235  if (end_bit > keylen2) end_bit = keylen2;
236  end_bit += start_bit;
237 
238  MPRINT2("%.*sLCP %02x%02x %02x%02x start %d length %d, %d\n",
239  start_bit, spaces, key1[0], key1[1], key2[0], key2[1], start_bit, keylen1, keylen2);
240 
241  lcp = 0;
242 
243  while (end_bit > 0) {
244  int num_bits;
245  uint8_t cmp1, cmp2, xor;
246 
247  MPRINT2("END %d\n", end_bit);
248 
249  /*
250  * Default to grabbing the whole byte.
251  */
252  cmp1 = key1[0];
253  cmp2 = key2[0];
254  num_bits = 8;
255 
256  /*
257  * The LCP ends in this byte. Mask off the
258  * trailing bits so that they don't affect the
259  * result.
260  */
261  if (end_bit < 8) {
262  cmp1 &= used_bit_mask[end_bit - 1];
263  cmp2 &= used_bit_mask[end_bit - 1];
264  num_bits = end_bit;
265  }
266 
267  /*
268  * The key doesn't start on the leading bit.
269  * Shift the data left until it does start there.
270  */
271  if ((start_bit & 0x07) != 0) {
272  cmp1 <<= start_bit;
273  cmp2 <<= start_bit;
274  num_bits -= start_bit;
275  end_bit -= start_bit;
276 
277  /*
278  * For subsequent bytes we start on a
279  * byte boundary.
280  */
281  start_bit = 0;
282  }
283 
284  xor = cmp1 ^ cmp2;
285 
286  /*
287  * A table lookup is faster than looping through
288  * the bits. If the LCP is smaller than the
289  * number of bits we're looking up, we can stop.
290  *
291  * On the other hand, if it returns the same or
292  * too many bits, just do another round through
293  * the loop, so that we can update the pointers
294  * and check the exit conditions.
295  */
296  if (xor2lcp[xor] < num_bits) {
297  MPRINT2("RETURN %d + %d\n", lcp, xor2lcp[xor]);
298  return lcp + xor2lcp[xor];
299  }
300 
301  /*
302  * The LCP may be longer than num_bits if we're
303  * checking the first byte, which has only
304  * "start_bit" things we care about. Ignore that
305  * case, and just keep going.
306  */
307 
308  lcp += num_bits;
309  end_bit -= num_bits;
310  key1++;
311  key2++;
312  }
313 
314  return lcp;
315 }
316 #endif
317 
318 //#define HEX_DUMP
319 
320 #ifdef HEX_DUMP
321 static void hex_dump(FILE *fp, char const *msg, uint8_t const *key, int start_bit, int end_bit)
322 {
323  int i;
324 
325  fprintf(fp, "%s\ts=%zd e=%zd\t\t", msg, start_bit, end_bit);
326 
327  for (i = 0; i < BYTES(end_bit); i++) {
328  fprintf(fp, "%02x ", key[i]);
329  }
330  fprintf(fp, "\n");
331 }
332 #endif
333 
334 static uint16_t get_chunk(uint8_t const *key, int start_bit, int num_bits) CC_HINT(nonnull);
335 
336 /** Return a chunk of a key (in the low bits) for use in 2^N node de-indexing
337  *
338  */
339 static uint16_t get_chunk(uint8_t const *key, int start_bit, int num_bits)
340 {
341  uint16_t chunk;
342  int end_bit;
343 
344  fr_cond_assert(num_bits > 0);
345  fr_cond_assert(num_bits <= 16);
346 
347  /*
348  * Normalize it so that the caller doesn't have to.
349  */
350  if (start_bit > 7) {
351  key += BYTEOF(start_bit);
352  start_bit &= 0x07;
353  }
354 
355  /*
356  * Special-case 1-bit lookups.
357  */
358  if (num_bits == 1) {
359  chunk = key[0] >> (7 - start_bit);
360  chunk &= 0x01;
361  return chunk;
362  }
363 
364  /*
365  * Catch some simple use-cases.
366  */
367  if (start_bit == 0) {
368  if (num_bits < 7) return key[0] >> (8 - num_bits);
369  if (num_bits == 8) return key[0];
370 
371  chunk = (key[0] << 8) | key[1];
372  if (num_bits < 16) chunk >>= (16 - num_bits);
373  fr_cond_assert(chunk < (1 << num_bits));
374  return chunk;
375  }
376 
377  /*
378  * Load the first byte and mask off the bits we don't
379  * want.
380  */
381  chunk = key[0] & start_bit_mask[start_bit & 0x07];
382 
383  fr_cond_assert(BYTEOF(start_bit + num_bits - 1) <= 1);
384 
385  if (BYTEOF(start_bit + num_bits - 1) != 0) {
386  chunk <<= 8;
387  chunk |= key[1];
388  }
389 
390  /*
391  * The bits we want are now all in the higher bits
392  * of "chunk". But we only want some of them.
393  *
394  * Shift the chunk so that the bits we want are now in
395  * the low bits.
396  */
397  end_bit = (start_bit + num_bits) & 0x07;
398  if (end_bit != 0) chunk >>= 8 - end_bit;
399 
400  fr_cond_assert(chunk < (1 << num_bits));
401 
402  return chunk;
403 }
404 
405 
406 static void write_chunk(uint8_t *out, int start_bit, int num_bits, uint16_t chunk) CC_HINT(nonnull);
407 
408 /** Write a chunk to an output buffer
409  *
410  */
411 static void write_chunk(uint8_t *out, int start_bit, int num_bits, uint16_t chunk)
412 {
413  fr_cond_assert(chunk < (1 << num_bits));
414 
415  /*
416  * Normalize it so that the caller doesn't have to.
417  */
418  if (start_bit > 7) {
419  out += BYTEOF(start_bit);
420  start_bit &= 0x07;
421  }
422 
423  /*
424  * Special-case 1-bit writes.
425  */
426  if (num_bits == 1) {
427  out[0] &= ~((1 << (7 - start_bit)) - 1);
428  out[0] |= chunk << (7 - start_bit);
429  return;
430  }
431 
432  /*
433  * Ensure that we don't write to more than 2 octets at
434  * the same time.
435  */
436  fr_cond_assert((start_bit + num_bits) <= 16);
437 
438  /*
439  * Shift the chunk to the high bits, but leave room for
440  * start_bit
441  */
442  if ((start_bit + num_bits) < 16) chunk <<= (16 - (start_bit + num_bits));
443 
444  /*
445  * Mask off the first bits that are already in the
446  * output. Then OR in the relevant bits of "chunk".
447  */
448  out[0] &= (used_bit_mask[start_bit] << 1);
449  out[0] |= chunk >> 8;
450 
451  if ((start_bit + num_bits) > 8) {
452  out[1] = chunk & 0xff;
453  }
454 }
455 
456 typedef enum fr_trie_type_t {
459 #ifdef WITH_PATH_COMPRESSION
461 #endif
462 #ifdef WITH_NODE_COMPRESSION
463  FR_TRIE_COMP, /* 4-way, N bits deep */
464 #endif
467 
468 #define FR_TRIE_MAX (FR_TRIE_NODE + 1)
469 
470 #ifdef TESTING
471 static int trie_number = 0;
472 
473 #define TRIE_HEADER uint8_t type; uint8_t bits; int number
474 #define TRIE_TYPE_CHECK(_x, _r) do { if ((trie->type == FR_TRIE_INVALID) || \
475  (trie->type >= FR_TRIE_MAX) || \
476  !trie_ ## _x ##_table [trie->type]) { \
477  fr_strerror_printf("unknown trie type %d", trie->type); \
478  return _r; \
479  } } while (0)
480 
481 #else
482 #define TRIE_HEADER uint8_t type; uint8_t bits
483 #define TRIE_TYPE_CHECK(_x, _r)
484 #endif
485 
486 struct fr_trie_s {
488 
489  fr_trie_t *trie; /* for USER and PATH nodes*/
490 };
491 
492 typedef struct {
494 
495  int used;
496  fr_trie_t *trie[];
498 
499 typedef struct {
501 
503  void *data;
505 
506 #ifdef WITH_PATH_COMPRESSION
507 typedef struct {
509 
511 
513  uint8_t key[2];
515 #endif
516 
517 #ifdef WITH_NODE_COMPRESSION
518 typedef struct {
519  TRIE_HEADER;
520 
521  int used; //!< number of used entries
522  uint8_t index[MAX_COMP_EDGES];
523  fr_trie_t *trie[MAX_COMP_EDGES];
524 } fr_trie_comp_t;
525 #endif
526 
527 
528 /* ALLOC FUNCTIONS */
529 
530 static fr_trie_node_t *trie_node_alloc(TALLOC_CTX *ctx, int bits)
531 {
532  fr_trie_node_t *node;
533  int size;
534 
535  if ((bits <= 0) || (bits > 8)) {
536  fr_strerror_printf("Invalid bit size %d passed to node alloc", bits);
537  return NULL;
538  }
539 
540  size = 1 << bits;
541 
542  node = (fr_trie_node_t *) talloc_zero_array(ctx, uint8_t, sizeof(fr_trie_node_t) + sizeof(node->trie[0]) * size);
543  if (!node) {
544  fr_strerror_const("failed allocating node trie");
545  return NULL;
546  }
547 
548  talloc_set_name_const(node, "fr_trie_node_t");
549  node->type = FR_TRIE_NODE;
550  node->bits = bits;
551 
552 #ifdef TESTING
553  node->number = trie_number++;
554 #endif
555  return node;
556 }
557 
558 /** Free a fr_trie_t
559  *
560  * We can't use talloc_free(), because we can't talloc_parent the
561  * nodes from each other, as talloc_steal() is O(N). So, we just
562  * recurse manually.
563  */
564 static void trie_free(fr_trie_t *trie)
565 {
566  if (!trie) return;
567 
568  if (trie->type == FR_TRIE_USER) {
569  fr_trie_user_t *user = (fr_trie_user_t *) trie;
570 
571  trie_free(user->trie);
572  talloc_free(user);
573  return;
574  }
575 
576  if (trie->type == FR_TRIE_NODE) {
577  fr_trie_node_t *node = (fr_trie_node_t *) trie;
578  int i;
579 
580  for (i = 0; i < (1 << node->bits); i++) {
581  if (!node->trie[i]) continue; /* save a function call in the common case */
582 
583  trie_free(node->trie[i]);
584  }
585 
586  talloc_free(node);
587  return;
588  }
589 
590 #ifdef WITH_PATH_COMPRESSION
591  if (trie->type == FR_TRIE_PATH) {
592  fr_trie_path_t *path = (fr_trie_path_t *) trie;
593 
594  trie_free(path->trie);
595  talloc_free(path);
596  return;
597  }
598 #endif
599 
600 #ifdef WITH_NODE_COMPRESSION
601  if (trie->type == FR_TRIE_COMP) {
602  fr_trie_comp_t *comp = (fr_trie_comp_t *) trie;
603  int i;
604 
605  for (i = 0; i < comp->used; i++) {
606  trie_free(comp->trie[i]);
607  }
608 
609  talloc_free(comp);
610  return;
611  }
612 #endif
613 }
614 
615 static CC_HINT(nonnull(2)) fr_trie_user_t *fr_trie_user_alloc(TALLOC_CTX *ctx, void const *data)
616 {
617  fr_trie_user_t *user;
618 
619  user = talloc_zero(ctx, fr_trie_user_t);
620  if (!user) {
621  fr_strerror_const("failed allocating user trie");
622  return NULL;
623  }
624 
625  user->type = FR_TRIE_USER;
626  user->data = UNCONST(void *, data);
627 
628 #ifdef TESTING
629  user->number = trie_number++;
630 #endif
631 
632  return user;
633 }
634 
635 #ifdef WITH_PATH_COMPRESSION
636 static CC_HINT(nonnull(2)) fr_trie_path_t *fr_trie_path_alloc(TALLOC_CTX *ctx, uint8_t const *key, int start_bit, int end_bit)
637 {
638  fr_trie_path_t *path;
639 
640  if (end_bit <= start_bit) {
641  fr_strerror_printf("path asked for start >= end, %d >= %d", start_bit, end_bit);
642  return NULL;
643  }
644 
645  /*
646  * Normalize it so that the caller doesn't have to.
647  */
648  if (start_bit > 7) {
649  key += (start_bit >> 3);
650  end_bit -= 8 * (start_bit >> 3);
651  start_bit -= 8 * (start_bit >> 3);
652  }
653 
654  if ((end_bit - start_bit) > 16) {
655  fr_strerror_printf("path asked for too many bits (%d)", end_bit - start_bit);
656  return NULL;
657  }
658 
659  /*
660  * The "end_bit" is the bit we're not using, so it's
661  * allowed to point past the end of path->key.
662  */
663  if ((BYTEOF(start_bit) - BYTEOF(end_bit - 1)) > 1) {
664  fr_strerror_printf("path asked for too many bits / bytes (%d)", end_bit - start_bit);
665  return NULL;
666  }
667 
668  path = talloc_zero(ctx, fr_trie_path_t);
669  if (!path) {
670  fr_strerror_const("failed allocating path trie");
671  return NULL;
672  }
673 
674  path->type = FR_TRIE_PATH;
675  path->bits = end_bit - start_bit;
676  path->chunk = get_chunk(key, start_bit, path->bits);
677 
678  /*
679  * Write the chunk back to the key.
680  */
681  write_chunk(&path->key[0], start_bit, path->bits, path->chunk);
682 
683 #if 0
684  fprintf(stderr, "PATH ALLOC key %02x%02x start %d end %d bits %d == chunk %04x key %02x%02x\n",
685  key[0], key[1],
686  start_bit, end_bit, path->bits,
687  path->chunk, path->key[0], path->key[1]);
688 #endif
689 
690 #ifdef TESTING
691  path->number = trie_number++;
692 #endif
693 
694  return path;
695 }
696 #endif /* WITH_PATH_COMPRESSION */
697 
698 #ifdef WITH_NODE_COMPRESSION
699 static fr_trie_comp_t *fr_trie_comp_alloc(TALLOC_CTX *ctx, int bits)
700 {
701  fr_trie_comp_t *comp;
702 
703  /*
704  * For 1 && 2 bits, just allocate fr_trie_node_t.
705  */
706  if ((bits <= 2) || (bits > MAX_COMP_BITS)) {
707  fr_strerror_printf("Invalid bit size %d passed to comp alloc", bits);
708  return NULL;
709  }
710 
711  comp = talloc_zero(ctx, fr_trie_comp_t);
712  if (!comp) {
713  fr_strerror_const("failed allocating comp trie");
714  return NULL;
715  }
716 
717  comp->type = FR_TRIE_COMP;
718  comp->bits = bits;
719  comp->used = 0;
720 
721 #ifdef TESTING
722  comp->number = trie_number++;
723 #endif
724  return comp;
725 }
726 #endif /* WITH_NODE_COMPRESSION */
727 
728 typedef struct {
729  uint8_t buffer[16]; /* for get_key callbacks */
732 } fr_trie_ctx_t;
733 
734 /** Allocate a trie
735  *
736  * @param ctx The talloc ctx.
737  * @param get_key The "get key from object" function.
738  * @param free_data Callback to free data.
739  * @return
740  * - NULL on error
741  * - fr_trie_node_t on success
742  */
743 fr_trie_t *fr_trie_alloc(TALLOC_CTX *ctx, fr_trie_key_t get_key, fr_free_t free_data)
744 {
745  fr_trie_user_t *user;
746  fr_trie_ctx_t *uctx;
747 
748  /*
749  * The trie itself is just a user node with user data
750  * that is the get_key function.
751  */
752  user = (fr_trie_user_t *) fr_trie_user_alloc(ctx, "");
753  if (!user) return NULL;
754 
755  /*
756  * Only the top-level node here can have 'user->data == NULL'
757  */
758  user->data = uctx = talloc_zero(user, fr_trie_ctx_t);
759  if (!user->data) {
760  talloc_free(user);
761  return NULL;
762  }
763 
764  uctx->get_key = get_key;
765  uctx->free_data = free_data;
766 
767  return (fr_trie_t *) user;
768 }
769 
770 /* SPLIT FUNCTIONS */
771 
772 /** Split a node at bits
773  *
774  */
775 static CC_HINT(nonnull(2)) fr_trie_node_t *trie_node_split(TALLOC_CTX *ctx, fr_trie_node_t *node, int bits)
776 {
778  int i, remaining_bits;
779 
780  /*
781  * Can't split zero bits, more bits than the node has, or
782  * a node which has 1 bit.
783  */
784  if ((bits == 0) || (bits >= node->bits) || (node->bits == 1)) {
785  fr_strerror_printf("invalid value for node split (%d / %d)", bits, node->bits);
786  return NULL;
787  }
788 
789  split = trie_node_alloc(ctx, bits);
790  if (!split) return NULL;
791 
792  remaining_bits = node->bits - bits;
793 
794  /*
795  * Allocate the children. For now, just brute-force all
796  * of the children. We take a later pass at optimizing this.
797  */
798  for (i = 0; i < (1 << bits); i++) {
799  int j;
800  fr_trie_node_t *child;
801 
802  child = trie_node_alloc(ctx, remaining_bits);
803  if (!child) {
805  return NULL;
806  }
807 
808  for (j = 0; j < (1 << remaining_bits); j++) {
809  if (!node->trie[(i << remaining_bits) + j]) continue;
810 
811  child->trie[j] = node->trie[(i << remaining_bits) + j];
812  node->trie[(i << remaining_bits) + j] = NULL; /* so we don't free it when freeing 'node' */
813  child->used++;
814  }
815 
816  if (!child->used) {
817  talloc_free(child); /* no children, so no need to recurse */
818  continue;
819  }
820 
821  split->trie[i] = (fr_trie_t *) child;
822  split->used++;
823  }
824 
825  /*
826  * Note that we do NOT free "node". The caller still
827  * needs it for some activities.
828  */
829  return split;
830 }
831 
832 #ifdef WITH_PATH_COMPRESSION
833 static CC_HINT(nonnull(2)) fr_trie_path_t *trie_path_split(TALLOC_CTX *ctx, fr_trie_path_t *path, int start_bit, int lcp)
834 {
835  fr_trie_path_t *split, *child;
836 #ifdef TESTING
837  uint8_t key[2] = { 0, 0 };
838 #endif
839 
840  if ((lcp <= 0) || (lcp > path->bits) || (start_bit < 0)) {
841  fr_strerror_printf("invalid parameter %d %d to path split", lcp, start_bit);
842  return NULL;
843  }
844 
845  MPRINT3("%.*sSPLIT start %d\n", start_bit, spaces, start_bit);
846  start_bit &= 0x07;
847 
848  split = fr_trie_path_alloc(ctx, &path->key[0], start_bit, start_bit + lcp);
849  if (!split) return NULL;
850 
851  child = fr_trie_path_alloc(ctx, &path->key[0], start_bit + lcp, start_bit + path->bits);
852  if (!child) return NULL;
853 
854  split->trie = (fr_trie_t *) child;
855  child->trie = (fr_trie_t *) path->trie;
856 
857  /*
858  * Don't free "path" until we've successfully inserted
859  * the new key.
860  */
861 
862 #ifdef TESTING
863  /*
864  * Check that the two chunks add up to the parent chunk.
865  */
866  fr_cond_assert(path->chunk == ((split->chunk << (path->bits - lcp)) | child->chunk));
867 
868  /*
869  * Check that the two keys match the parent key.
870  */
871 
872  write_chunk(&key[0], start_bit, split->bits, split->chunk);
873  write_chunk(&key[0], start_bit + split->bits, child->bits, child->chunk);
874 
875  fr_cond_assert(key[0] == path->key[0]);
876  fr_cond_assert(key[1] == path->key[1]);
877 
878  MPRINT3("%.*ssplit %02x%02x start %d split %d -> %02x%02x %02x%02x\n",
879  start_bit, spaces,
880  path->key[0], path->key[1],
881  start_bit, split->bits,
882  split->key[0], split->key[1],
883  child->key[0], child->key[1]);
884 #endif
885 
886  return split;
887 }
888 
889 static CC_HINT(nonnull(2)) fr_trie_t *trie_key_alloc(TALLOC_CTX *ctx, uint8_t const *key, int start_bit, int end_bit, void *data)
890 {
891  fr_trie_path_t *path;
892  int next_bit;
893 
894  if (start_bit == end_bit) return (fr_trie_t *) fr_trie_user_alloc(ctx, data);
895 
896  if (start_bit > end_bit) {
897  fr_strerror_printf("key_alloc asked for start >= end, %d >= %d", start_bit, end_bit);
898  return NULL;
899  }
900 
901  /*
902  * Grab some more bits. Try to grab 16 bits at a time.
903  */
904  next_bit = start_bit + 16 - (start_bit & 0x07);
905 
906  if (next_bit >= end_bit) {
907  path = fr_trie_path_alloc(ctx, key, start_bit, end_bit);
908  if (!path) return NULL;
909 
910  path->trie = (fr_trie_t *) fr_trie_user_alloc(ctx, data);
911  return (fr_trie_t *) path;
912  }
913 
914 
915  path = fr_trie_path_alloc(ctx, key, start_bit, next_bit);
916  if (!path) return NULL;
917 
918  path->trie = (fr_trie_t *) trie_key_alloc(ctx, key, next_bit, end_bit, data);
919  if (!path->trie) {
920  talloc_free(path); /* no children */
921  return NULL;
922  }
923 
924  return (fr_trie_t *) path;
925 }
926 #else /* WITH_PATH_COMPRESSION */
927 static CC_HINT(nonnull(2)) fr_trie_t *trie_key_alloc(TALLOC_CTX *ctx, uint8_t const *key, int start_bit, int end_bit, void *data)
928 {
929  fr_trie_node_t *node;
930  uint16_t chunk;
931  int bits = MAX_NODE_BITS;
932 
933  if (start_bit == end_bit) {
934  return (fr_trie_t *) fr_trie_user_alloc(ctx, data);
935  }
936 
937  bits = end_bit - start_bit;
938  if (bits > MAX_NODE_BITS) bits = MAX_NODE_BITS;
939 
940  /*
941  * We only want one edge here.
942  */
943  node = trie_node_alloc(ctx, bits);
944  if (!node) return NULL;
945 
946  chunk = get_chunk(key, start_bit, node->bits);
947  node->trie[chunk] = trie_key_alloc(ctx, key, start_bit + node->bits, end_bit, data);
948  if (!node->trie[chunk]) {
949  talloc_free(node); /* no children */
950  return NULL;
951  }
952  node->used++;
953 
954  return (fr_trie_t *) node;
955 }
956 #endif
957 
958 
959 #if 0
960 /** Split a compressed at bits
961  *
962  */
963 #ifdef WITH_NODE_COMPRESSION
964 static fr_trie_t *trie_comp_split(TALLOC_CTX *ctx, fr_trie_comp_t *comp, int start_bit, int bits)
965 {
966  int i;
967  fr_trie_comp_t *split;
968 
969  /*
970  * Can't split zero bits, more bits than the node has, or
971  * a node which has 1 bit.
972  */
973  if ((bits == 0) || (bits >= comp->bits)) {
974  fr_strerror_printf("invalid value for comp split (%d / %d)", bits, comp->bits);
975  return NULL;
976  }
977 
978  split = fr_trie_comp_alloc(ctx, bits);
979  if (!split) return NULL;
980 
981  if (start_bit > 7) start_bit &= 0x07;
982 
983  // walk over the edges, seeing how many edges have the same before bits
984  //
985  // if all have the same bits, then split by creating a path
986  // node, and then a child split node.
987 
988  /*
989  * Walk over each edge, inserting the first chunk into
990  * the new node, and the split node...
991  */
992  for (i = 0; i < comp->used; i++) {
993  int j, where;
994  uint16_t before, after;
995  uint8_t key[2];
996  fr_trie_path_t *path;
997 
998  before = i >> (comp->bits - bits);
999  after = i & ((1 << bits) - 1);
1000 
1001  write_chunk(&key[0], start_bit, comp->bits, i);
1002 
1003  // see if "before" was already used in the newly created node.
1004 
1005  where = 0;
1006 
1007  for (j = 0; j < split->used; j++) {
1008  if (before == split->index[j]) {
1009  where = j;
1010  break;
1011  }
1012  }
1013 
1014  if (split->index[where]) {
1015  // the children MUST be different
1016  // create another compressed node as a child, and go from there.
1017 
1018  } else {
1019  split->index[split->used] = before;
1020  path = fr_trie_path_alloc(ctx, &key[0], start_bit, start_bit + bits);
1021  if (!path) goto fail;
1022 
1023  split->trie[split->used++] = (fr_trie_t *) path;
1024  path->trie = comp->trie[i];
1025  }
1026  }
1027 
1028  return (fr_trie_t *) split;
1029 
1030 fail:
1031  for (i = 0; i < split->used; i++) {
1032  talloc_free(split->trie[i]);
1033  }
1034  talloc_free(split);
1035  return NULL;
1036 }
1037 #endif /* WITH_NODE_COMPRESSION */
1038 #endif
1039 
1040 /* ADD EDGES */
1041 
1042 #ifdef WITH_PATH_COMPRESSION
1043 /** Add an edge to a node.
1044  *
1045  * This function is so that we can abstract 2^N-way nodes, or
1046  * compressed edge nodes.
1047  */
1048 static int trie_add_edge(fr_trie_t *trie, uint16_t chunk, fr_trie_t *child)
1049 {
1050  fr_trie_node_t *node;
1051 
1052 #ifdef WITH_NODE_COMPRESSION
1053  if (trie->type == FR_TRIE_COMP) {
1054  fr_trie_comp_t *comp = (fr_trie_comp_t *) trie;
1055  int i, edge;
1056 
1057  if (chunk >= (1 << comp->bits)) return -1;
1058 
1059  if (comp->used >= MAX_COMP_EDGES) return -1;
1060 
1061  edge = comp->used;
1062  for (i = 0; i < comp->used; i++) {
1063  if (comp->index[i] < chunk) continue;
1064 
1065  if (comp->index[edge] == chunk) return -1;
1066 
1067  edge = i;
1068  break;
1069  }
1070 
1071  if (edge == MAX_COMP_EDGES) return -1;
1072 
1073  /*
1074  * Move the nodes up so that we have room for the
1075  * new edge.
1076  */
1077  for (i = edge; i < comp->used; i++) {
1078  comp->index[i + 1] = comp->index[i];
1079  comp->trie[i + 1] = comp->trie[i];
1080  }
1081 
1082  comp->index[edge] = chunk;
1083  comp->trie[edge] = child;
1084 
1085  comp->used++;
1086  VERIFY(comp);
1087  return 0;
1088  }
1089 #endif
1090 
1091  if (trie->type != FR_TRIE_NODE) return -1;
1092 
1093  node = (fr_trie_node_t *) trie;
1094 
1095  if (chunk >= (1 << node->bits)) return -1;
1096 
1097  if (node->trie[chunk] != NULL) return -1;
1098 
1099  node->used++;
1100  node->trie[chunk] = child;
1101 
1102  return 0;
1103 }
1104 #endif
1105 
1106 /* MATCH FUNCTIONS */
1107 
1108 typedef void *(*trie_key_match_t)(fr_trie_t *trie, uint8_t const *key, int start_bit, int end_bit, bool exact);
1109 
1110 static void *trie_key_match(fr_trie_t *trie, uint8_t const *key, int start_bit, int end_bit, bool exact);
1111 
1112 static void *trie_user_match(fr_trie_t *trie, uint8_t const *key, int start_bit, int end_bit, bool exact)
1113 {
1114  fr_trie_user_t *user = (fr_trie_user_t *) trie;
1115  void *data;
1116 
1117  /*
1118  * We've matched the input exactly. Return the
1119  * user data.
1120  */
1121  if (start_bit == end_bit) return user->data;
1122 
1123  /*
1124  * We're not at the end of the input. Go find a
1125  * deeper match. If a match is found, return
1126  * that.
1127  */
1128  data = trie_key_match(user->trie, key, start_bit, end_bit, exact);
1129  if (data) return data;
1130 
1131  /*
1132  * We didn't find anything deeper in the trie,
1133  * AND we require an exact match. That's a
1134  * failure.
1135  */
1136  if (exact) {
1137  MPRINT2("no exact match at %d\n", __LINE__);
1138  return NULL;
1139  }
1140 
1141  /*
1142  * Return the closest (i.e. inexact) match.
1143  */
1144  return user->data;
1145 }
1146 
1147 static void *trie_node_match(fr_trie_t *trie, uint8_t const *key, int start_bit, int end_bit, bool exact)
1148 {
1149  uint16_t chunk;
1150  fr_trie_node_t *node = (fr_trie_node_t *) trie;
1151 
1152  chunk = get_chunk(key, start_bit, node->bits);
1153  if (!node->trie[chunk]) {
1154  MPRINT2("no match for node chunk %02x at %d\n", chunk, __LINE__);
1155  return NULL;
1156  }
1157 
1158  return trie_key_match(node->trie[chunk], key, start_bit + node->bits, end_bit, exact);
1159 }
1160 
1161 #ifdef WITH_PATH_COMPRESSION
1162 static void *trie_path_match(fr_trie_t *trie, uint8_t const *key, int start_bit, int end_bit, bool exact)
1163 {
1164  uint16_t chunk;
1165  fr_trie_path_t *path = (fr_trie_path_t *) trie;
1166 
1167  chunk = get_chunk(key, start_bit, path->bits);
1168  if (chunk != path->chunk) return NULL;
1169 
1170  return trie_key_match(path->trie, key, start_bit + path->bits, end_bit, exact);
1171 }
1172 #endif
1173 
1174 #ifdef WITH_NODE_COMPRESSION
1175 static void *trie_comp_match(fr_trie_t *trie, uint8_t const *key, int start_bit, int end_bit, bool exact)
1176 {
1177  int i;
1178  uint16_t chunk;
1179  fr_trie_comp_t *comp = (fr_trie_comp_t *) trie;
1180 
1181  chunk = get_chunk(key, start_bit, comp->bits);
1182 
1183  for (i = 0; i < comp->used; i++) {
1184  if (comp->index[i] < chunk) continue;
1185 
1186  if (comp->index[i] == chunk) {
1187  return trie_key_match(comp->trie[i], key, start_bit + comp->bits, end_bit, exact);
1188  }
1189 
1190  /*
1191  * The edges are ordered smallest to largest. So
1192  * if the edge is larger than the chunk, NO edge
1193  * will match the chunk.
1194  */
1195  return NULL;
1196  }
1197 
1198  return NULL;
1199 }
1200 #endif
1201 
1205 #ifdef WITH_PATH_COMPRESSION
1207 #endif
1208 #ifdef WITH_NODE_COMPRESSION
1209  [ FR_TRIE_COMP ] = trie_comp_match,
1210 #endif
1211 };
1212 
1213 
1214 /** Match a key in a trie and return user ctx, if any
1215  *
1216  * The key may be LONGER than entries in the trie. In which case the
1217  * closest match is returned.
1218  *
1219  * @param trie the trie
1220  * @param key the key
1221  * @param start_bit the start bit
1222  * @param end_bit the end bit
1223  * @param exact do we return an exact match, or the shortest one.
1224  * @return
1225  * - NULL on not found
1226  * - void* user ctx on found
1227  */
1228 static void *trie_key_match(fr_trie_t *trie, uint8_t const *key, int start_bit, int end_bit, bool exact)
1229 {
1230  if (!trie) return NULL;
1231 
1232  /*
1233  * We've run out of trie, so it's not a match.
1234  */
1235  if ((start_bit + trie->bits) > end_bit) {
1236  MPRINT2("%d + %d = %d > %d\n",
1237  start_bit, trie->bits, start_bit + trie->bits, end_bit);
1238 #ifdef TESTING
1239  MPRINT2("no match for key too short for trie NODE-%d at %d\n", trie->number, __LINE__);
1240 #endif
1241  return NULL;
1242  }
1243 
1244  TRIE_TYPE_CHECK(match, NULL);
1245 
1246  /*
1247  * Recursively match each type.
1248  */
1249  return trie_match_table[trie->type](trie, key, start_bit, end_bit, exact);
1250 }
1251 
1252 /** Lookup a key in a trie and return user ctx, if any
1253  *
1254  * The key may be LONGER than entries in the trie. In which case the
1255  * closest match is returned.
1256  *
1257  * @param ft the trie
1258  * @param key the key bytes
1259  * @param keylen length in bits of the key
1260  * @return
1261  * - NULL on not found
1262  * - void* user ctx on found
1263  */
1264 void *fr_trie_lookup_by_key(fr_trie_t const *ft, void const *key, size_t keylen)
1265 {
1266  fr_trie_user_t *user;
1267 
1268  if (keylen > MAX_KEY_BITS) return NULL;
1269 
1270  if (!ft->trie) return NULL;
1271 
1272  user = UNCONST(fr_trie_user_t *, ft);
1273 
1274  return trie_key_match(user->trie, key, 0, keylen, false);
1275 }
1276 
1277 /** Match a key and length in a trie and return user ctx, if any
1278  *
1279  * Only the exact match is returned.
1280  *
1281  * @param ft the trie
1282  * @param key the key bytes
1283  * @param keylen length in bits of the key
1284  * @return
1285  * - NULL on not found
1286  * - void* user ctx on found
1287  */
1288 void *fr_trie_match_by_key(fr_trie_t const *ft, void const *key, size_t keylen)
1289 {
1290  fr_trie_user_t *user;
1291 
1292  if (keylen > MAX_KEY_BITS) return NULL;
1293 
1294  if (!ft->trie) return NULL;
1295 
1296  user = UNCONST(fr_trie_user_t *, ft);
1297 
1298  return trie_key_match(user->trie, key, 0, keylen, true);
1299 }
1300 
1301 /* INSERT FUNCTIONS */
1302 
1303 #ifdef TESTING
1304 static void trie_check(fr_trie_t *trie, uint8_t const *key, int start_bit, int end_bit, void *data, int lineno)
1305 {
1306  void *answer;
1307 
1308  trie_sprint(trie, key, start_bit, lineno);
1309 
1310  answer = trie_key_match(trie, key, start_bit, end_bit, true);
1311  if (!answer) {
1312  fr_strerror_printf("Failed trie check answer at %d", lineno);
1313 
1314  // print out the current trie!
1315  MPRINT3("%.*sFailed to find user data %s from start %d end %d at %d\n", start_bit, spaces, data,
1316  start_bit, end_bit, lineno);
1317  fr_cond_assert(0);
1318  }
1319 
1320  if (answer != data) {
1321  fr_strerror_printf("Failed trie check answer == data at %d", lineno);
1322 
1323  MPRINT3("%.*sFound wrong user data %s != %s, from start %d end %d at %d\n", start_bit, spaces,
1324  answer, data, start_bit, end_bit, lineno);
1325  fr_cond_assert(0);
1326  }
1327 }
1328 #else
1329 #define trie_check(_trie, _key, _start_bit, _end_bit, _data, _lineno)
1330 #endif
1331 
1332 static int trie_key_insert(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit, void *data) CC_HINT(nonnull(2,3,6));
1333 
1334 typedef int (*trie_key_insert_t)(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit, void *data);
1335 
1336 static int trie_user_insert(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit, void *data)
1337 {
1338  fr_trie_t *trie = *trie_p;
1339  fr_trie_user_t *user = (fr_trie_user_t *) trie;
1340 
1341  MPRINT3("user insert to start %d end %d with data %s\n", start_bit, end_bit, (char *) data);
1342 
1343  /*
1344  * Just insert the key into user->trie.
1345  */
1346  MPRINT3("%.*srecurse at %d\n", start_bit, spaces, __LINE__);
1347  return trie_key_insert(ctx, &user->trie, key, start_bit, end_bit, data);
1348 }
1349 
1350 static int trie_node_insert(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit, void *data)
1351 {
1352  fr_trie_t *trie = *trie_p;
1353  fr_trie_node_t *node = (fr_trie_node_t *) trie;
1354  fr_trie_t *trie_to_free = NULL;
1355  uint32_t chunk;
1356 
1357  MPRINT3("%.*snode insert end %d with data %s\n",
1358  start_bit, spaces, end_bit, (char *) data);
1359 
1360  /*
1361  * The current node is longer than the input bits
1362  * for the key. Split the node into a smaller
1363  * N-way node, and insert the key into the (now
1364  * fitting) node.
1365  */
1366  if ((start_bit + node->bits) > end_bit) {
1368 
1369  MPRINT3("%.*snode insert splitting %d at %d start %d end %d with data %s\n",
1370  start_bit, spaces,
1371  node->bits, start_bit - end_bit,
1372  start_bit, end_bit, (char *) data);
1373 
1374  split = trie_node_split(ctx, node, end_bit - start_bit);
1375  if (!split) {
1376  fr_strerror_printf("Failed splitting node at %d\n", __LINE__);
1377  return -1;
1378  }
1379 
1380  trie_to_free = (fr_trie_t *) node;
1381  node = split;
1382  }
1383 
1384  chunk = get_chunk(key, start_bit, node->bits);
1385 
1386  /*
1387  * No existing trie, create a brand new trie from
1388  * the key.
1389  */
1390  if (!node->trie[chunk]) {
1391  node->trie[chunk] = trie_key_alloc(ctx, key, start_bit + node->bits, end_bit, data);
1392  if (!node->trie[chunk]) {
1393  fr_strerror_printf("Failed key_alloc at %d\n", __LINE__);
1394  if (trie_to_free) trie_free(trie_to_free);
1395  return -1;
1396  }
1397  node->used++;
1398 
1399  } else {
1400  /*
1401  * Recurse in order to insert the key
1402  * into the current node.
1403  */
1404  MPRINT3("%.*srecurse at %d\n", start_bit, spaces, __LINE__);
1405  if (trie_key_insert(ctx, &node->trie[chunk], key, start_bit + node->bits, end_bit, data) < 0) {
1406  MPRINT("Failed recursing at %d\n", __LINE__);
1407  if (trie_to_free) trie_free(trie_to_free);
1408  return -1;
1409  }
1410  }
1411 
1412  trie_check((fr_trie_t *) node, key, start_bit, end_bit, data, __LINE__);
1413 
1414  MPRINT3("%.*snode insert returning at %d\n",
1415  start_bit, spaces, __LINE__);
1416 
1417  if (trie_to_free) trie_free(trie_to_free);
1418  *trie_p = (fr_trie_t *) node;
1419  VERIFY(node);
1420  return 0;
1421 }
1422 
1423 #ifdef WITH_PATH_COMPRESSION
1424 static CC_HINT(nonnull(2,3,6)) int trie_path_insert(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit, void *data)
1425 {
1426  fr_trie_t *trie = *trie_p;
1427  fr_trie_path_t *path = (fr_trie_path_t *) trie;
1428  uint32_t chunk;
1429  int lcp, bits;
1430  uint8_t const *key2;
1431  int start_bit2;
1432  fr_trie_t *node;
1433  fr_trie_t *child;
1434 
1435  MPRINT3("%.*spath insert start %d end %d with key %02x%02x data %s\n",
1436  start_bit, spaces, start_bit, end_bit, key[0], key[1], (char *) data);
1437 
1438  VERIFY(path);
1439  trie_sprint((fr_trie_t *) path, key, start_bit, __LINE__);
1440 
1441  /*
1442  * The key exactly matches the path. Recurse.
1443  */
1444  if (start_bit + path->bits <= end_bit) {
1445  chunk = get_chunk(key, start_bit, path->bits);
1446 
1447  /*
1448  * The chunk matches exactly. Recurse to
1449  * insert the key into the child trie.
1450  */
1451  if (chunk == path->chunk) {
1452  MPRINT3("%.*spath chunk matches %04x bits of %d\n",
1453  start_bit, spaces, chunk, path->bits);
1454  MPRINT3("%.*srecurse at %d\n", start_bit, spaces, __LINE__);
1455  if (trie_key_insert(ctx, &path->trie, key, start_bit + path->bits, end_bit, data) < 0) {
1456  return -1;
1457  }
1458 
1459  trie_check((fr_trie_t *) path, key, start_bit, end_bit, data, __LINE__);
1460 
1461  MPRINT3("%.*spath returning at %d\n", start_bit, spaces, __LINE__);
1462  VERIFY(path);
1463  return 0;
1464  }
1465 
1466  bits = path->bits;
1467  MPRINT3("%.*spath using %d\n", start_bit, spaces, path->bits);
1468 
1469  } else {
1470  /*
1471  * Limit the number of bits we check to
1472  * the number of bits left in the key.
1473  */
1474  bits = end_bit - start_bit;
1475  MPRINT3("%.*spath limiting %d to %d\n", start_bit, spaces, path->bits, bits);
1476  }
1477 
1478  /*
1479  * Figure out what part of the key we need to
1480  * look at for LCP.
1481  */
1482  key2 = key;
1483  start_bit2 = start_bit;
1484  if (start_bit2 > 7) {
1485  key2 += (start_bit2 >> 3);
1486  start_bit2 -= 8 * (start_bit2 >> 3);
1487  }
1488 
1489  /*
1490  * Get the LCP. If we have one, split the path
1491  * node at the LCP. Replace the parent with the
1492  * first half of the path, and build an N-way
1493  * node for the second half.
1494  */
1495  lcp = fr_trie_key_lcp(&path->key[0], bits, key2, bits, start_bit2);
1496  MPRINT3("%.*spath lcp %d\n", start_bit, spaces, lcp);
1497 
1498  /*
1499  * This should have been caught above.
1500  */
1501  if (lcp == path->bits) {
1502  fr_strerror_const("found lcp which should have been previously found");
1503  return -1;
1504  }
1505 
1506  if (lcp > 0) {
1508 
1509  /*
1510  * Note that "path" is still valid after this
1511  * call. We will rewrite things on the way back
1512  * up the stack.
1513  */
1514  MPRINT3("%.*spath split depth %d bits %d at lcp %d with data %s\n",
1515  start_bit, spaces, start_bit, path->bits, lcp, (char *) data);
1516 
1517  MPRINT3("%.*spath key %02x%02x input key %02x%02x, offset %d\n",
1518  start_bit, spaces,
1519  path->key[0],path->key[1],
1520  key[0], key[1],
1521  start_bit2);
1522 
1523  split = trie_path_split(ctx, path, start_bit2, lcp);
1524  if (!split) {
1525  fr_strerror_printf("failed path split at %d\n", __LINE__);
1526  return -1;
1527  }
1528 
1529  trie_sprint((fr_trie_t *) path, key, start_bit, __LINE__);
1530  trie_sprint((fr_trie_t *) split, key, start_bit, __LINE__);
1531  trie_sprint((fr_trie_t *) split->trie, key, start_bit + split->bits, __LINE__);
1532 
1533  /*
1534  * Recurse to insert the key into the child node.
1535  * Note that if "bits > MAX_NODE_BITS", we will
1536  * have to split "path" again.
1537  */
1538  MPRINT3("%.*srecurse at %d\n", start_bit, spaces, __LINE__);
1539  if (trie_key_insert(ctx, &split->trie, key, start_bit + split->bits, end_bit, data) < 0) {
1540  talloc_free(split->trie);
1541  talloc_free(split);
1542  return -1;
1543  }
1544 
1545  /*
1546  * We can't have two LCPs in a row here, as we
1547  * SHOULD have found the LCP above!
1548  */
1549  fr_cond_assert(split->type == FR_TRIE_PATH);
1550  fr_cond_assert(split->trie->type != FR_TRIE_PATH);
1551 
1552  trie_check((fr_trie_t *) split, key, start_bit, end_bit, data, __LINE__);
1553 
1554  MPRINT3("%.*spath returning at %d\n", start_bit, spaces, __LINE__);
1555  talloc_free(path);
1556  *trie_p = (fr_trie_t *) split;
1557  VERIFY(split);
1558  return 0;
1559  }
1560 
1561  /*
1562  * Else there's no common prefix. Just create an
1563  * fanout node.
1564  */
1565  /*
1566  * We only want two edges here. Try to create a
1567  * compressed N-way node if possible.
1568  */
1569 #ifdef WITH_NODE_COMPRESSION
1570  if (bits > 2) {
1571  if (bits > MAX_COMP_BITS) bits = MAX_COMP_BITS;
1572 
1573  MPRINT3("%.*sFanout to comp %d at depth %d data %s\n", start_bit, spaces, bits, start_bit, (char *) data);
1574  node = (fr_trie_t *) fr_trie_comp_alloc(ctx, bits);
1575  } else
1576 #endif
1577  {
1578  /*
1579  * Without path compression create no more than a
1580  * 16-way node.
1581  */
1582  if (bits > MAX_NODE_BITS) bits = MAX_NODE_BITS;
1583 
1584  MPRINT3("%.*sFanout to node %d at depth %d data %s\n", start_bit, spaces, bits, start_bit, (char *) data);
1585  node = (fr_trie_t *) trie_node_alloc(ctx, bits);
1586  }
1587  if (!node) return -1;
1588 
1589  /*
1590  * Get the chunk from the path, and insert the child trie
1591  * into the node at that chunk.
1592  */
1593  chunk = get_chunk(&path->key[0], start_bit2, node->bits);
1594 
1595  if (node->bits == path->bits) {
1596  child = path->trie;
1597 
1598  } else {
1599  /*
1600  * Skip the common prefix.
1601  */
1602  child = (fr_trie_t *) fr_trie_path_alloc(ctx, &path->key[0], start_bit2 + node->bits, start_bit2 + path->bits);
1603  if (!child) {
1604  fr_strerror_printf("failed allocating path child at %d", __LINE__);
1605  return -1;
1606  }
1607 
1608  /*
1609  * Patch in the child trie.
1610  */
1611  ((fr_trie_path_t *)child)->trie = path->trie;
1612 
1613  VERIFY(child);
1614  }
1615 
1616  trie = NULL;
1617 
1618  /*
1619  * Recurse to insert the key into the second edge. If
1620  * this fails, then we haven't changed anything. So just
1621  * free memory and return.
1622  *
1623  * Note that if "bits > DEFAULT_BITS", we will have to
1624  * split "path" again.
1625  */
1626  MPRINT3("%.*srecurse at %d\n", start_bit, spaces, __LINE__);
1627  if (trie_key_insert(ctx, &trie, key, start_bit + node->bits, end_bit, data) < 0) {
1628  talloc_free(node);
1629  if (child != path->trie) talloc_free(child);
1630  return -1;
1631  }
1632 
1633  /*
1634  * Copy the first edge over to the first chunk.
1635  */
1636  if (trie_add_edge(node, chunk, child) < 0) {
1637  fr_strerror_printf("chunk failure in insert node %d at %d", node->bits, __LINE__);
1638  talloc_free(node);
1639  if (child != path->trie) talloc_free(child);
1640  return -1;
1641  }
1642 
1643  /*
1644  * Copy the second edge from the new chunk.
1645  */
1646  chunk = get_chunk(key, start_bit, node->bits);
1647  if (trie_add_edge(node, chunk, trie) < 0) {
1648  fr_strerror_printf("chunk failure in insert node %d at %d", node->bits, __LINE__);
1649  talloc_free(node);
1650  trie_free(trie);
1651  return -1;
1652  }
1653 
1654  trie_check((fr_trie_t *) node, key, start_bit, end_bit, data, __LINE__);
1655 
1656  MPRINT3("%.*spath returning at %d\n", start_bit, spaces, __LINE__);
1657 
1658  /*
1659  * Only update the answer if the insert succeeded.
1660  */
1661  *trie_p = node;
1662  talloc_free(path);
1663  VERIFY(node);
1664  return 0;
1665 }
1666 #endif
1667 
1668 #ifdef WITH_NODE_COMPRESSION
1669 static CC_HINT(nonnull(2,3,6)) int trie_comp_insert(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit, void *data)
1670 {
1671  int i, bits;
1672  fr_trie_t *trie = *trie_p;
1673  fr_trie_comp_t *comp = (fr_trie_comp_t *) trie;
1674  fr_trie_node_t *node;
1675  uint16_t chunk;
1676 
1677  MPRINT3("%.*scomp insert start %d end %d with key %02x%02x data %s\n",
1678  start_bit, spaces, start_bit, end_bit, key[0], key[1], (char *) data);
1679 
1680  if ((end_bit - start_bit) < comp->bits) {
1681  fr_strerror_printf("Not implemented at %d", __LINE__);
1682  return -1;
1683  }
1684 
1685  chunk = get_chunk(key, start_bit, comp->bits);
1686 
1687  /*
1688  * Search for a matching edge. If found, recurse and
1689  * insert the key there.
1690  */
1691  for (i = 0; i < comp->used; i++) {
1692  if (comp->index[i] < chunk) continue;
1693 
1694  /*
1695  * We've found a matching chunk, recurse.
1696  */
1697  if (comp->index[i] == chunk) {
1698  MPRINT3("%.*srecurse at %d\n", start_bit, spaces, __LINE__);
1699  if (trie_key_insert(ctx, &comp->trie[i], key, start_bit + comp->bits, end_bit, data) < 0) {
1700  MPRINT3("%.*scomp failed recursing at %d", start_bit, spaces, __LINE__);
1701  return -1;
1702  }
1703 
1704  trie_check((fr_trie_t *) comp, key, start_bit, end_bit, data, __LINE__);
1705 
1706  MPRINT3("%.*scomp returning at %d", start_bit, spaces, __LINE__);
1707  VERIFY(comp);
1708  return 0;
1709  }
1710 
1711  /*
1712  * The chunk is larger than the current edge,
1713  * stop.
1714  */
1715  break;
1716  }
1717 
1718  /*
1719  * No edge matches the chunk from the key. Insert the
1720  * child trie into a place-holder entry, so that we don't
1721  * modify the current node on failure.
1722  */
1723  if (comp->used < MAX_COMP_EDGES) {
1724  MPRINT3("%.*srecurse at %d\n", start_bit, spaces, __LINE__);
1725  trie = NULL;
1726  if (trie_key_insert(ctx, &trie, key, start_bit + comp->bits, end_bit, data) < 0) {
1727  MPRINT3("%.*scomp failed recursing at %d", start_bit, spaces, __LINE__);
1728  return -1;
1729  }
1730  fr_cond_assert(trie != NULL);
1731 
1732  if (trie_add_edge((fr_trie_t *) comp, chunk, trie) < 0) {
1733  talloc_free(trie); // @todo - there may be multiple nodes here?
1734  return -1;
1735  }
1736 
1737  trie_check((fr_trie_t *) comp, key, start_bit, end_bit, data, __LINE__);
1738 
1739  VERIFY(comp);
1740  return 0;
1741  }
1742 
1743  /*
1744  * All edges are used. Create an N-way node.
1745  */
1746 
1747  /*
1748  * @todo - limit bits by calling
1749  * trie_comp_split()?
1750  */
1751  bits = comp->bits;
1752 
1753  MPRINT3("%.*scomp swapping to node bits %d at %d\n", start_bit, spaces, bits, __LINE__);
1754 
1755  node = trie_node_alloc(ctx, bits);
1756  if (!node) return -1;
1757 
1758  for (i = 0; i < comp->used; i++) {
1759  fr_cond_assert(node->trie[comp->index[i]] == NULL);
1760  node->trie[comp->index[i]] = comp->trie[i];
1761  }
1762  node->used = comp->used;
1763  node->used += (node->trie[chunk] == NULL); /* will get set if the recursive insert succeeds */
1764 
1765  /*
1766  * Insert the new chunk, which may or may not overlap
1767  * with an existing one.
1768  */
1769  MPRINT3("%.*srecurse at %d\n", start_bit, spaces, __LINE__);
1770  if (trie_key_insert(ctx, &node->trie[chunk], key, start_bit + node->bits, end_bit, data) < 0) {
1771  MPRINT3("%.*scomp failed recursing at %d", start_bit, spaces, __LINE__);
1772  talloc_free(node);
1773  return -1;
1774  }
1775 
1776  trie_check((fr_trie_t *) node, key, start_bit, end_bit, data, __LINE__);
1777 
1778  MPRINT3("%.*scomp returning at %d", start_bit, spaces, __LINE__);
1779 
1780  talloc_free(comp);
1781  *trie_p = (fr_trie_t *) node;
1782  VERIFY(node);
1783  return 0;
1784 }
1785 #endif
1786 
1790 #ifdef WITH_PATH_COMPRESSION
1792 #endif
1793 #ifdef WITH_NODE_COMPRESSION
1794  [ FR_TRIE_COMP ] = trie_comp_insert,
1795 #endif
1796 };
1797 
1798 /** Insert a binary key into the trie
1799  *
1800  * The key must have at least ((start_bit + keylen) >> 3) bytes
1801  *
1802  * @param ctx the talloc ctx
1803  * @param[in,out] trie_p the trie where things are inserted
1804  * @param key the binary key
1805  * @param start_bit the start bit
1806  * @param end_bit the end bit
1807  * @param data user data to insert
1808  * @return
1809  * - <0 on error
1810  * - 0 on success
1811  */
1812 static int trie_key_insert(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit, void *data)
1813 {
1814  fr_trie_t *trie = *trie_p;
1815 
1816  /*
1817  * We've reached the end of the trie, but may still have
1818  * key bits to insert.
1819  */
1820  if (!trie) {
1821  *trie_p = trie_key_alloc(ctx, key, start_bit, end_bit, data);
1822  if (!*trie_p) return -1;
1823  return 0;
1824  }
1825 
1826  MPRINT3("%.*sIN recurse at %d\n", start_bit, spaces, __LINE__);
1827  trie_sprint(trie, key, start_bit, __LINE__);
1828 
1829  /*
1830  * We've reached the end of the key. Insert a user node
1831  * here, and push the remaining bits of the trie to after
1832  * the user node.
1833  */
1834  if (start_bit == end_bit) {
1835  fr_trie_user_t *user;
1836 
1837  if (trie->type == FR_TRIE_USER) {
1838  fr_strerror_printf("already has a user node at %d\n", __LINE__);
1839  return -1;
1840  }
1841 
1842  user = fr_trie_user_alloc(ctx, data);
1843  if (!user) return -1;
1844 
1845  user->trie = trie;
1846  *trie_p = (fr_trie_t *) user;
1847  return 0;
1848  }
1849 
1850  TRIE_TYPE_CHECK(insert, -1);
1851 
1852 #ifndef TESTING
1853  return trie_insert_table[trie->type](ctx, trie_p, key, start_bit, end_bit, data);
1854 #else
1855  MPRINT3("%.*srecurse at start %d end %d with data %s\n", start_bit, spaces, start_bit, end_bit, (char *) data);
1856 
1857  if (trie_insert_table[trie->type](ctx, trie_p, key, start_bit, end_bit, data) < 0) {
1858  return -1;
1859  }
1860 
1861  trie_check(*trie_p, key, start_bit, end_bit, data, __LINE__);
1862 
1863  return 0;
1864 #endif
1865 }
1866 
1867 /** Insert a key and user ctx into a trie
1868  *
1869  * @param ft the trie
1870  * @param key the key
1871  * @param keylen key length in bits
1872  * @param data user ctx information to associated with the key
1873  * @return
1874  * - <0 on error
1875  * - 0 on success
1876  */
1877 int fr_trie_insert_by_key(fr_trie_t *ft, void const *key, size_t keylen, void const *data)
1878 {
1879  void *my_data;
1880  fr_trie_user_t *user;
1881 
1882  if (keylen > MAX_KEY_BITS) {
1883  fr_strerror_printf("keylen too long (%u > %d)", (unsigned int) keylen, MAX_KEY_BITS);
1884  return -1;
1885  }
1886 
1887  user = (fr_trie_user_t *) ft;
1888 
1889  /*
1890  * Do a lookup before insertion. If we tried to insert
1891  * the key with new nodes and then discovered a conflict,
1892  * we would not be able to undo the process. This check
1893  * ensures that the insertion can modify the trie in
1894  * place without worry.
1895  */
1896  if (trie_key_match(user->trie, key, 0, keylen, true) != NULL) {
1897  fr_strerror_const("Cannot insert due to pre-existing key");
1898  return -1;
1899  }
1900 
1901  my_data = UNCONST(void *, data);
1902  MPRINT2("No match for data, inserting...\n");
1903 
1904  MPRINT3("%.*srecurse STARTS at %d with %.*s=%s\n", 0, spaces, __LINE__,
1905  (int) keylen, key, my_data);
1906  return trie_key_insert(user->data, &user->trie, key, 0, keylen, my_data);
1907 }
1908 
1909 /* REMOVE FUNCTIONS */
1910 static void *trie_key_remove(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit);
1911 
1912 typedef void *(*trie_key_remove_t)(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit);
1913 
1914 static void *trie_user_remove(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit)
1915 {
1916  fr_trie_t *trie = *trie_p;
1917  fr_trie_user_t *user = (fr_trie_user_t *) trie;
1918 
1919  /*
1920  * We're at the end of the key, return the data
1921  * given here, and free the node that we're
1922  * removing.
1923  */
1924  if (start_bit == end_bit) {
1925  void *data = user->data;
1926 
1927  *trie_p = user->trie;
1928  talloc_free(user);
1929 
1930  return data;
1931  }
1932 
1933  return trie_key_remove(ctx, &user->trie, key, start_bit, end_bit);
1934 }
1935 
1936 static void *trie_node_remove(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit)
1937 {
1938  fr_trie_t *trie = *trie_p;
1939  fr_trie_node_t *node = (fr_trie_node_t *) trie;
1940  uint32_t chunk;
1941  void *data;
1942 
1943  chunk = get_chunk(key, start_bit, node->bits);
1944  if (!node->trie[chunk]) return NULL;
1945 
1946  data = trie_key_remove(ctx, &node->trie[chunk], key, start_bit + node->bits, end_bit);
1947  if (!data) return NULL;
1948 
1949  /*
1950  * The trie still has a subtrie. Just return the data.
1951  */
1952  if (node->trie[chunk]) return data;
1953 
1954  /*
1955  * One less used edge.
1956  */
1957  node->used--;
1958  if (node->used > 0) return data;
1959 
1960  /*
1961  * @todo - if we have path compression, and
1962  * node->used==1, then create a fr_trie_path_t from the
1963  * chunk, and concatenate it (if necessary) to any
1964  * trailing path compression node.
1965  */
1966 
1967  /*
1968  * Our entire node is empty. Delete it as we walk back up the trie.
1969  */
1970  *trie_p = NULL;
1971  talloc_free(node); /* no children */
1972  return data;
1973 }
1974 
1975 #ifdef WITH_PATH_COMPRESSION
1976 static void *trie_path_remove(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit)
1977 {
1978  fr_trie_t *trie = *trie_p;
1979  fr_trie_path_t *path = (fr_trie_path_t *) trie;
1980  uint32_t chunk;
1981  void *data;
1982 
1983  chunk = get_chunk(key, start_bit, path->bits);
1984 
1985  /*
1986  * No match, can't remove it.
1987  */
1988  if (path->chunk != chunk) return NULL;
1989 
1990  data = trie_key_remove(ctx, &path->trie, key, start_bit + path->bits, end_bit);
1991  if (!data) return NULL;
1992 
1993  /*
1994  * The trie still has a subtrie. Just return the data.
1995  */
1996  if (path->trie) return data;
1997 
1998  /*
1999  * Our entire path is empty. Delete it as we walk back up the trie.
2000  */
2001  *trie_p = NULL;
2002  talloc_free(path); /* no children */
2003  return data;
2004 }
2005 #endif
2006 
2007 #ifdef WITH_NODE_COMPRESSION
2008 static void *trie_comp_remove(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit)
2009 {
2010  int i, j;
2011  uint16_t chunk;
2012  void *data;
2013  fr_trie_comp_t *comp = *(fr_trie_comp_t **) trie_p;
2014  fr_trie_path_t *path;
2015 
2016  chunk = get_chunk(key, start_bit, comp->bits);
2017 
2018  MPRINT3("%.*sremove at %d\n", start_bit, spaces, __LINE__);
2019  trie_sprint(*trie_p, key, start_bit, __LINE__);
2020 
2021  for (i = 0; i < comp->used; i++) {
2022  if (comp->index[i] < chunk) continue;
2023 
2024  if (comp->index[i] == chunk) {
2025  break;
2026  }
2027 
2028  /*
2029  * The edges are ordered smallest to largest. So
2030  * if the edge is larger than the chunk, NO edge
2031  * will match the chunk.
2032  */
2033  if (comp->index[i] > chunk) return NULL;
2034  }
2035 
2036  /*
2037  * Didn't find it, fail.
2038  */
2039  if (i >= comp->used) return NULL;
2040 
2041  fr_cond_assert(chunk == comp->index[i]);
2042 
2043  data = trie_key_remove(ctx, &comp->trie[i], key, start_bit + comp->bits, end_bit);
2044  if (!data) return NULL;
2045 
2046  /*
2047  * The trie still has a subtrie. Just return the data.
2048  */
2049  if (comp->trie[i]) {
2050  MPRINT3("%.*sremove at %d\n", start_bit, spaces, __LINE__);
2051  trie_sprint((fr_trie_t *) comp, key, start_bit, __LINE__);
2052  VERIFY(comp);
2053  return data;
2054  }
2055 
2056  /*
2057  * Shrinking at the end is easy, we don't need to do
2058  * anything. For shrinking in the middle, we just copy
2059  * the entries down.
2060  */
2061  for (j = i; j < comp->used - 1; j++) {
2062  comp->index[j] = comp->index[j + 1];
2063  comp->trie[j] = comp->trie[j + 1];
2064  }
2065  comp->used--;
2066 
2067  if (comp->used >= 2) {
2068  VERIFY(comp);
2069  return data;
2070  }
2071 
2072  /*
2073  * Our entire path is empty. Delete it as we walk back
2074  * up the trie. We hope that this doesn't happen.
2075  */
2076  if (!comp->used) {
2077  *trie_p = NULL;
2078  talloc_free(comp); /* no children */
2079  MPRINT3("%.*sremove at %d\n", start_bit, spaces, __LINE__);
2080  return data;
2081  }
2082 
2083  /*
2084  * Only one edge. Turn it back into a path node. Note
2085  * that we pass "key" here, which is wrong... that's the
2086  * key we're removing, not the key left in the node. But
2087  * we fix that later.
2088  *
2089  * @todo - check the child. If it's also a path node, try
2090  * to concatenate the nodes together.
2091  */
2092  path = fr_trie_path_alloc(ctx, key, start_bit, start_bit + comp->bits);
2093  if (!path) return data;
2094 
2095  /*
2096  * Tie the new node in.
2097  */
2098  path->trie = comp->trie[0];
2099 
2100  /*
2101  * Fix up the chunk and key to be the one left in the
2102  * trie, not the one which was removed.
2103  */
2104  path->chunk = comp->index[0];
2105  write_chunk(&path->key[0], start_bit & 0x07, path->bits, path->chunk);
2106 
2107  *trie_p = (fr_trie_t *) path;
2108  talloc_free(comp);
2109  VERIFY(path);
2110  return data;
2111 }
2112 #endif
2113 
2117 #ifdef WITH_PATH_COMPRESSION
2119 #endif
2120 #ifdef WITH_NODE_COMPRESSION
2121  [ FR_TRIE_COMP ] = trie_comp_remove,
2122 #endif
2123 };
2124 
2125 /** Remove a key from a trie, and return the user data.
2126  *
2127  */
2128 static void *trie_key_remove(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit)
2129 {
2130  fr_trie_t *trie = *trie_p;
2131 
2132  if (!trie) return NULL;
2133 
2134  /*
2135  * We can't remove a key which is shorter than the
2136  * current trie.
2137  */
2138  if ((start_bit + trie->bits) > end_bit) return NULL;
2139 
2140  TRIE_TYPE_CHECK(remove, NULL);
2141 
2142  return trie_remove_table[trie->type](ctx, trie_p, key, start_bit, end_bit);
2143 }
2144 
2145 /** Remove a key and return the associated user ctx
2146  *
2147  * The key must match EXACTLY. This is not a prefix match.
2148  *
2149  * @param ft the trie
2150  * @param key the key
2151  * @param keylen key length in bits
2152  * @return
2153  * - NULL on not found
2154  * - user ctx data on success
2155  */
2156 void *fr_trie_remove_by_key(fr_trie_t *ft, void const *key, size_t keylen)
2157 {
2158  fr_trie_user_t *user;
2159 
2160  if (keylen > MAX_KEY_BITS) return NULL;
2161 
2162  if (!ft->trie) return NULL;
2163 
2164  user = (fr_trie_user_t *) ft;
2165 
2166  /*
2167  * Remove the user trie, not ft->trie.
2168  */
2169  return trie_key_remove(user->data, &user->trie, key, 0, (int) keylen);
2170 }
2171 
2172 /* WALK FUNCTIONS */
2173 
2174 typedef struct fr_trie_callback_s fr_trie_callback_t;
2175 
2176 typedef int (*fr_trie_key_walk_t)(fr_trie_t *trie, fr_trie_callback_t *cb, int depth, bool more);
2177 
2178 static int trie_key_walk(fr_trie_t *trie, fr_trie_callback_t *cb, int depth, bool more);
2179 
2182  uint8_t const *end;
2183 
2184  void *ctx;
2185 
2188 };
2189 
2190 static int trie_user_walk(fr_trie_t *trie, fr_trie_callback_t *cb, int depth, bool more)
2191 {
2192  fr_trie_user_t *user = (fr_trie_user_t *) trie;
2193 
2194  if (!user->trie) return 0;
2195 
2196  return trie_key_walk(user->trie, cb, depth, more);
2197 }
2198 
2199 static int trie_node_walk(fr_trie_t *trie, fr_trie_callback_t *cb, int depth, bool more)
2200 {
2201  int i, used;
2202  fr_trie_node_t *node = (fr_trie_node_t *) trie;
2203 
2204  used = 0;
2205  for (i = 0; i < (1 << node->bits); i++) {
2206  if (!node->trie[i]) continue;
2207 
2208  write_chunk(cb->start, depth, node->bits, (uint16_t) i);
2209  used++;
2210 
2211  if (trie_key_walk(node->trie[i], cb, depth + node->bits,
2212  more || (used < node->used)) < 0) {
2213  return -1;
2214  }
2215  }
2216 
2217  return 0;
2218 }
2219 
2220 #ifdef WITH_PATH_COMPRESSION
2221 static int trie_path_walk(fr_trie_t *trie, fr_trie_callback_t *cb, int depth, bool more)
2222 {
2223  fr_trie_path_t *path = (fr_trie_path_t *) trie;
2224 
2225  write_chunk(cb->start, depth, path->bits, path->chunk);
2226 
2227  fr_cond_assert(path->trie != NULL);
2228  return trie_key_walk(path->trie, cb, depth + path->bits, more);
2229 }
2230 #endif
2231 
2232 #ifdef WITH_NODE_COMPRESSION
2233 static int trie_comp_walk(fr_trie_t *trie, fr_trie_callback_t *cb, int depth, bool more)
2234 {
2235  int i, used;
2236  fr_trie_comp_t *comp = (fr_trie_comp_t *) trie;
2237 
2238  used = 0;
2239  for (i = 0; i < comp->used; i++) {
2240  write_chunk(cb->start, depth, comp->bits, comp->index[i]);
2241 
2242  fr_cond_assert(comp->trie[i] != NULL);
2243 
2244  used++;
2245  if (trie_key_walk(comp->trie[i], cb, depth + comp->bits,
2246  more || (used < comp->used)) < 0) {
2247  return -1;
2248  }
2249  }
2250 
2251  return 0;
2252 }
2253 #endif
2254 
2258 #ifdef WITH_PATH_COMPRESSION
2260 #endif
2261 #ifdef WITH_NODE_COMPRESSION
2262  [ FR_TRIE_COMP ] = trie_comp_walk,
2263 #endif
2264 };
2265 
2266 static int trie_key_walk(fr_trie_t *trie, fr_trie_callback_t *cb, int depth, bool more)
2267 {
2268  /*
2269  * Do the callback before anything else.
2270  */
2271  if (cb->callback(trie, cb, depth, more) < 0) return -1;
2272 
2273  if (!trie) {
2274  fr_cond_assert(depth == 0);
2275  return 0;
2276  }
2277 
2278  TRIE_TYPE_CHECK(walk, -1);
2279 
2280  /*
2281  * No more buffer space, stop.
2282  */
2283  if ((cb->start + BYTEOF(depth + trie->bits + 8)) >= cb->end) return 0;
2284 
2285  return trie_walk_table[trie->type](trie, cb, depth, more);
2286 }
2287 
2288 #ifdef WITH_TRIE_VERIFY
2289 /* VERIFY FUNCTIONS */
2290 
2291 typedef int (*trie_verify_t)(fr_trie_t *trie);
2292 
2293 static int trie_user_verify(fr_trie_t *trie)
2294 {
2295  fr_trie_user_t *user = (fr_trie_user_t *) trie;
2296 
2297  if (!user->data) {
2298  fr_strerror_const("user node has no user data");
2299  return -1;
2300  }
2301 
2302  if (!user->trie) return 0;
2303 
2304  return trie_verify(user->trie);
2305 }
2306 
2307 static int trie_node_verify(fr_trie_t *trie)
2308 {
2309  fr_trie_node_t *node = (fr_trie_node_t *) trie;
2310  int i, used;
2311 
2312  if ((node->bits == 0) || (node->bits > MAX_NODE_BITS)) {
2313  fr_strerror_printf("N-way node has invalid bits %d",
2314  node->bits);
2315  return -1;
2316  }
2317 
2318  if ((node->used == 0) || (node->used > (1 << node->bits))) {
2319  fr_strerror_printf("N-way node has invalid used %d for bits %d",
2320  node->used, node->bits);
2321  return -1;
2322  }
2323 
2324  used = 0;
2325  for (i = 0; i < (1 << node->bits); i++) {
2326  if (!node->trie[i]) continue;
2327 
2328  if (trie_verify(node->trie[i]) < 0) return -1;
2329 
2330  used++;
2331  }
2332 
2333  if (used != node->used) {
2334  fr_strerror_printf("N-way node has incorrect used %d when actually used %d",
2335  node->used, used);
2336  return -1;
2337  }
2338 
2339  return 0;
2340 }
2341 
2342 #ifdef WITH_PATH_COMPRESSION
2343 static int trie_path_verify(fr_trie_t *trie)
2344 {
2345  fr_trie_path_t *path = (fr_trie_path_t *) trie;
2346 
2347  if ((path->bits == 0) || (path->bits > 16)) {
2348  fr_strerror_printf("path node has invalid bits %d",
2349  path->bits);
2350  return -1;
2351  }
2352 
2353  if (!path->trie) {
2354  fr_strerror_const("path node has no child trie");
2355  return -1;
2356  }
2357 
2358  return trie_verify(path->trie);
2359 }
2360 #endif
2361 
2362 #ifdef WITH_NODE_COMPRESSION
2363 static int trie_comp_verify(fr_trie_t *trie)
2364 {
2365  int i, used;
2366  fr_trie_comp_t *comp = (fr_trie_comp_t *) trie;
2367 
2368  if ((comp->bits == 0) || (comp->bits > MAX_COMP_BITS)) {
2369  fr_strerror_printf("comp node has invalid bits %d",
2370  comp->bits);
2371  return -1;
2372  }
2373 
2374  used = 0;
2375  for (i = 0; i < comp->used; i++) {
2376  if (!comp->trie[i]) {
2377  fr_strerror_printf("comp node has no child trie at %d", i);
2378  return -1;
2379  }
2380 
2381  if ((i + 1) < comp->used) {
2382  if (comp->index[i] >= comp->index[i + 1]) {
2383  fr_strerror_printf("comp node has inverted edges at %d (%04x >= %04x)",
2384  i, comp->index[i], comp->index[i + 1]);
2385  return -1;
2386  }
2387  }
2388 
2389  if (trie_verify(comp->trie[i]) < 0) return -1;
2390  used++;
2391  }
2392 
2393  if (used != comp->used) {
2394  fr_strerror_printf("Compressed node has incorrect used %d when actually used %d",
2395  comp->used, used);
2396  return -1;
2397  }
2398 
2399  return 0;
2400 }
2401 #endif
2402 
2403 static trie_verify_t trie_verify_table[FR_TRIE_MAX] = {
2404  [ FR_TRIE_USER ] = trie_user_verify,
2405  [ FR_TRIE_NODE ] = trie_node_verify,
2406 #ifdef WITH_PATH_COMPRESSION
2407  [ FR_TRIE_PATH ] = trie_path_verify,
2408 #endif
2409 #ifdef WITH_NODE_COMPRESSION
2410  [ FR_TRIE_COMP ] = trie_comp_verify,
2411 #endif
2412 };
2413 
2414 
2415 /** Verify the trie nodes
2416  *
2417  */
2418 static int trie_verify(fr_trie_t *trie)
2419 {
2420  if (!trie) return 0;
2421 
2422  TRIE_TYPE_CHECK(verify, -1);
2423 
2424  return trie_verify_table[trie->type](trie);
2425 }
2426 #endif /* WITH_TRIE_VERIFY */
2427 
2428 /* MISCELLANEOUS FUNCTIONS */
2429 
2430 #ifdef TESTING
2431 /** Dump a trie edge in canonical form.
2432  *
2433  */
2434 static void trie_dump_edge(FILE *fp, fr_trie_t *trie)
2435 {
2436  fr_cond_assert(trie != NULL);
2437 
2438  fprintf(fp, "NODE-%d\n", trie->number);
2439  return;
2440 }
2441 
2442 
2443 typedef void (*fr_trie_dump_t)(FILE *fp, fr_trie_t *trie, char const *key, int keylen);
2444 
2445 static void trie_user_dump(FILE *fp, fr_trie_t *trie, char const *key, int keylen)
2446 {
2447  fr_trie_user_t *user = (fr_trie_user_t *) trie;
2448  int bytes = BYTES(keylen);
2449 
2450  fprintf(fp, "{ NODE-%d\n", user->number);
2451  fprintf(fp, "\ttype\tUSER\n");
2452  fprintf(fp, "\tinput\t{%d}%.*s\n", keylen, bytes, key);
2453 
2454  fprintf(fp, "\tdata\t\"%s\"\n", (char const *) user->data);
2455  if (!user->trie) {
2456  fprintf(fp, "}\n\n");
2457  return;
2458  }
2459 
2460  fprintf(fp, "\tnext\t");
2461  trie_dump_edge(fp, user->trie);
2462  fprintf(fp, "}\n\n");
2463 }
2464 
2465 static void trie_node_dump(FILE *fp, fr_trie_t *trie, char const *key, int keylen)
2466 {
2467  fr_trie_node_t *node = (fr_trie_node_t *) trie;
2468  int i;
2469  int bytes = BYTES(keylen);
2470 
2471  fprintf(fp, "{ NODE-%d\n", node->number);
2472  fprintf(fp, "\ttype\tNODE\n");
2473  fprintf(fp, "\tinput\t{%d}%.*s\n", keylen, bytes, key);
2474 
2475  fprintf(fp, "\tbits\t%d\n", node->bits);
2476  fprintf(fp, "\tused\t%d\n", node->used);
2477 
2478  for (i = 0; i < (1 << node->bits); i++) {
2479  if (!node->trie[i]) continue;
2480 
2481  fprintf(fp, "\t%02x\t", (int) i);
2482  trie_dump_edge(fp, node->trie[i]);
2483  }
2484  fprintf(fp, "}\n\n");
2485 }
2486 
2487 #ifdef WITH_PATH_COMPRESSION
2488 static void trie_path_dump(FILE *fp, fr_trie_t *trie, char const *key, int keylen)
2489 {
2490  fr_trie_path_t *path = (fr_trie_path_t *) trie;
2491  int bytes = BYTES(keylen);
2492 
2493  fprintf(fp, "{ NODE-%d\n", path->number);
2494  fprintf(fp, "\ttype\tPATH\n");
2495  fprintf(fp, "\tinput\t{%d}%.*s\n", keylen, bytes, key);
2496 
2497  fprintf(fp, "\tbits\t%d\n", (int) path->bits);
2498  fprintf(fp, "\tpath\t");
2499 
2500  fprintf(fp, "%02x %02x", path->key[0], path->key[1]);
2501 
2502  fprintf(fp, "\n");
2503 
2504  fprintf(fp, "\tnext\t");
2505  trie_dump_edge(fp, path->trie);
2506 
2507  fprintf(fp, "}\n\n");
2508 }
2509 #endif
2510 
2511 #ifdef WITH_NODE_COMPRESSION
2512 static void trie_comp_dump(FILE *fp, fr_trie_t *trie, char const *key, int keylen)
2513 {
2514  fr_trie_comp_t *comp = (fr_trie_comp_t *) trie;
2515  int i;
2516  int bytes = BYTES(keylen);
2517 
2518  fprintf(fp, "{ NODE-%d\n", comp->number);
2519  fprintf(fp, "\ttype\tCOMP\n");
2520  fprintf(fp, "\tinput\t{%d}%.*s\n", keylen, bytes, key);
2521 
2522  fprintf(fp, "\tbits\t%d\n", comp->bits);
2523  fprintf(fp, "\tused\t%d\n", comp->used);
2524 
2525  for (i = 0; i < comp->used; i++) {
2526  fprintf(fp, "\t%d = %02x\t", i, comp->index[i]);
2527  trie_dump_edge(fp, comp->trie[i]);
2528  }
2529  fprintf(fp, "}\n\n");
2530 }
2531 
2532 #endif
2533 
2534 static fr_trie_dump_t trie_dump_table[FR_TRIE_MAX] = {
2535  [ FR_TRIE_USER ] = trie_user_dump,
2536  [ FR_TRIE_NODE ] = trie_node_dump,
2537 #ifdef WITH_PATH_COMPRESSION
2538  [ FR_TRIE_PATH ] = trie_path_dump,
2539 #endif
2540 #ifdef WITH_NODE_COMPRESSION
2541  [ FR_TRIE_COMP ] = trie_comp_dump,
2542 #endif
2543 };
2544 
2545 
2546 /** Dump the trie nodes
2547  *
2548  */
2549 static int _trie_dump_cb(fr_trie_t *trie, fr_trie_callback_t *cb, int keylen, UNUSED bool more)
2550 {
2551  FILE *fp = cb->ctx;
2552 
2553  if (!trie) return 0;
2554 
2555  TRIE_TYPE_CHECK(dump, -1);
2556 
2557  trie_dump_table[trie->type](fp, trie, (char const *) cb->start, keylen);
2558  return 0;
2559 }
2560 
2561 /** Print the strings accepted by a trie to a file
2562  *
2563  */
2564 static int _trie_print_cb(fr_trie_t *trie, fr_trie_callback_t *cb, int keylen, UNUSED bool more)
2565 {
2566  int bytes;
2567  FILE *fp = cb->ctx;
2568  fr_trie_user_t *user;
2569 
2570  if (!trie || (trie->type != FR_TRIE_USER)) {
2571  return 0;
2572  }
2573 
2574  bytes = BYTES(keylen);
2575  user = (fr_trie_user_t *) trie;
2576 
2577  if ((keylen & 0x07) != 0) {
2578  fprintf(fp, "{%d}%.*s\t%s\n", keylen, bytes, cb->start, (char const *) user->data);
2579  } else {
2580  fprintf(fp, "%.*s\t%s\n", bytes, cb->start, (char const *) user->data);
2581  }
2582 
2583  return 0;
2584 }
2585 #endif /* TESTING */
2586 
2587 
2588 /** Implement the user-visible side of the walk callback.
2589  *
2590  */
2591 static int _trie_user_cb(fr_trie_t *trie, fr_trie_callback_t *cb, int keylen, UNUSED bool more)
2592 {
2593  fr_trie_user_t *user;
2594 
2595  if (!trie || (trie->type != FR_TRIE_USER)) return 0;
2596 
2597  user = (fr_trie_user_t *) trie;
2598 
2599  /*
2600  * Call the user function with the key, key length, and data.
2601  */
2602  if (cb->user_callback(cb->start, keylen, UNCONST(void *, user->data), cb->ctx) < 0) {
2603  return -1;
2604  }
2605 
2606  return 0;
2607 }
2608 
2609 int fr_trie_walk(fr_trie_t *ft, void *ctx, fr_trie_walk_t callback)
2610 {
2612  fr_trie_callback_t my_cb = {
2613  .start = buffer,
2614  .end = buffer + sizeof(buffer),
2615  .callback = _trie_user_cb,
2616  .user_callback = callback,
2617  .ctx = ctx
2618  };
2619 
2620  memset(buffer, 0, sizeof(buffer));
2621 
2622  /*
2623  * Call the internal walk function to do the work.
2624  */
2625  return trie_key_walk(ft->trie, &my_cb, 0, false);
2626 }
2627 
2628 
2629 /**********************************************************************/
2630 
2631 /*
2632  * Object API.
2633  */
2634 
2635 /** Find an element in the trie, returning the data.
2636  *
2637  * @param[in] ft to search in.
2638  * @param[in] data to find.
2639  * @return
2640  * - User data matching the data passed in.
2641  * - NULL if nothing matched passed data.
2642  */
2643 void *fr_trie_find(fr_trie_t *ft, void const *data)
2644 {
2645  fr_trie_user_t *user = (fr_trie_user_t *) ft;
2646  fr_trie_ctx_t *uctx = talloc_get_type_abort(user->data, fr_trie_ctx_t);
2647  uint8_t *key;
2648  size_t keylen;
2649 
2650  key = &uctx->buffer[0];
2651  keylen = sizeof(uctx->buffer) * 8;
2652 
2653  if (!uctx->get_key) return false;
2654 
2655  if (uctx->get_key(&key, &keylen, data) < 0) return false;
2656 
2657  return fr_trie_lookup_by_key(ft, key, keylen);
2658 }
2659 
2660 /** Match an element exactly in the trie, returning the data.
2661  *
2662  * @param[in] ft to search in.
2663  * @param[in] data to find.
2664  * @return
2665  * - User data matching the data passed in.
2666  * - NULL if nothing matched passed data.
2667  */
2668 void *fr_trie_match(fr_trie_t *ft, void const *data)
2669 {
2670  fr_trie_user_t *user = (fr_trie_user_t *) ft;
2671  fr_trie_ctx_t *uctx = talloc_get_type_abort(user->data, fr_trie_ctx_t);
2672  uint8_t *key;
2673  size_t keylen;
2674 
2675  key = &uctx->buffer[0];
2676  keylen = sizeof(uctx->buffer) * 8;
2677 
2678  if (!uctx->get_key) return false;
2679 
2680  if (uctx->get_key(&key, &keylen, data) < 0) return false;
2681 
2682  return fr_trie_match_by_key(ft, key, keylen);
2683 }
2684 
2685 /** Insert data into a trie
2686  *
2687  * @param[in] ft to insert data into.
2688  * @param[in] data to insert.
2689  * @return
2690  * - true if data was inserted.
2691  * - false if data already existed and was not inserted.
2692  */
2693 bool fr_trie_insert(fr_trie_t *ft, void const *data)
2694 {
2695  fr_trie_user_t *user = (fr_trie_user_t *) ft;
2696  fr_trie_ctx_t *uctx = talloc_get_type_abort(user->data, fr_trie_ctx_t);
2697  uint8_t *key;
2698  size_t keylen;
2699 
2700  key = &uctx->buffer[0];
2701  keylen = sizeof(uctx->buffer) * 8;
2702 
2703  if (!uctx->get_key) return false;
2704 
2705  if (uctx->get_key(&key, &keylen, data) < 0) return false;
2706 
2707  if (fr_trie_insert_by_key(ft, key, keylen, data) < 0) return false;
2708 
2709  return true;
2710 }
2711 
2712 /** Replace old data with new data, OR insert if there is no old
2713  *
2714  * @param[out] old data that was replaced. If this argument
2715  * is not NULL, then the old data will not
2716  * be freed, even if a free function is
2717  * configured.
2718  * @param[in] ft to insert data into.
2719  * @param[in] data to replace.
2720  * @return
2721  * - 1 if data was replaced.
2722  * - 0 if data was inserted.
2723  * - -1 if we failed to replace data
2724  */
2725 int fr_trie_replace(void **old, fr_trie_t *ft, void const *data)
2726 {
2727  fr_trie_user_t *user = (fr_trie_user_t *) ft;
2728  fr_trie_ctx_t *uctx = talloc_get_type_abort(user->data, fr_trie_ctx_t);
2729  uint8_t *key;
2730  size_t keylen;
2731  void *found;
2732 
2733  key = &uctx->buffer[0];
2734  keylen = sizeof(uctx->buffer) * 8;
2735 
2736  if (!uctx->get_key) return -1;
2737 
2738  if (uctx->get_key(&key, &keylen, data) < 0) return -1;
2739 
2740  found = trie_key_match(ft, key, 0, keylen, true); /* do exact match */
2741  if (found) {
2742  if (old) *old = found;
2743  if (fr_trie_remove_by_key(ft, key, keylen) != found) return -1;
2744  } else {
2745  if (old) *old = NULL;
2746  }
2747 
2748  /*
2749  * Insert the new key.
2750  */
2751  if (fr_trie_insert_by_key(ft, key, keylen, data) < 0) return -1;
2752 
2753  return found ? 1 : 0;
2754 }
2755 
2756 /** Remove an entry, without freeing the data
2757  *
2758  * @param[in] ft to remove data from.
2759  * @param[in] data to remove.
2760  * @return
2761  * - The user data we removed.
2762  * - NULL if we couldn't find any matching data.
2763  */
2764 void *fr_trie_remove(fr_trie_t *ft, void const *data)
2765 {
2766  fr_trie_user_t *user = (fr_trie_user_t *) ft;
2767  fr_trie_ctx_t *uctx = talloc_get_type_abort(user->data, fr_trie_ctx_t);
2768  uint8_t *key;
2769  size_t keylen;
2770 
2771  key = &uctx->buffer[0];
2772  keylen = sizeof(uctx->buffer) * 8;
2773 
2774  if (!uctx->get_key) return NULL;
2775 
2776  if (uctx->get_key(&key, &keylen, data) < 0) return NULL;
2777 
2778  return fr_trie_remove_by_key(ft, key, keylen);
2779 }
2780 
2781 /** Remove node and free data (if a free function was specified)
2782  *
2783  * @param[in] ft to remove data from.
2784  * @param[in] data to remove/free.
2785  * @return
2786  * - true if we removed data.
2787  * - false if we couldn't find any matching data.
2788  */
2789 bool fr_trie_delete(fr_trie_t *ft, void const *data)
2790 {
2791  fr_trie_user_t *user = (fr_trie_user_t *) ft;
2792  fr_trie_ctx_t *uctx = talloc_get_type_abort(user->data, fr_trie_ctx_t);
2793  uint8_t *key;
2794  size_t keylen;
2795  void *found;
2796 
2797  key = &uctx->buffer[0];
2798  keylen = sizeof(uctx->buffer) * 8;
2799 
2800  if (!uctx->get_key) return false;
2801 
2802  if (uctx->get_key(&key, &keylen, data) < 0) return false;
2803 
2804  found = fr_trie_remove_by_key(ft, key, keylen);
2805  if (!found) return false;
2806 
2807  if (!uctx->free_data) return true;
2808 
2809  uctx->free_data(found);
2810  return true;
2811 }
2812 
2813 /** Return how many nodes there are in a trie
2814  *
2815  * @param[in] ft to return node count for.
2816  */
2818 {
2819  return 0;
2820 }
2821 
2822 #ifdef TESTING
2823 static bool print_lineno = false;
2824 
2825 typedef struct {
2826  char *start;
2827  char *buffer;
2828  size_t buflen;
2829 } trie_sprint_ctx_t;
2830 
2831 
2832 /** Print the strings accepted by a trie to one line
2833  */
2834 static int _trie_sprint_cb(fr_trie_t *trie, fr_trie_callback_t *cb, int keylen, bool more)
2835 {
2836  int bytes, len;
2837  trie_sprint_ctx_t *ctx;
2838  fr_trie_user_t *user;
2839 
2840  ctx = cb->ctx;
2841 
2842  if (!trie) {
2843  len = snprintf(ctx->buffer, ctx->buflen, "{}");
2844  goto done;
2845  }
2846 
2847  if (trie->type != FR_TRIE_USER) return 0;
2848 
2849  bytes = BYTES(keylen);
2850  user = (fr_trie_user_t *) trie;
2851 
2852  if (!user->trie && !more) {
2853  len = snprintf(ctx->buffer, ctx->buflen, "%.*s=%s",
2854  bytes, cb->start, (char const *) user->data);
2855  } else {
2856  len = snprintf(ctx->buffer, ctx->buflen, "%.*s=%s,",
2857  bytes, cb->start, (char const *) user->data);
2858  }
2859 
2860 done:
2861  ctx->buffer += len;
2862  ctx->buflen -= len;
2863 
2864  return 0;
2865 }
2866 
2867 
2868 static void trie_sprint(fr_trie_t *trie, uint8_t const *key, int start_bit, UNUSED int lineno)
2869 {
2870  fr_trie_callback_t my_cb;
2871  trie_sprint_ctx_t my_sprint;
2873  char out[8192];
2874 
2875  /*
2876  * Initialize the buffer
2877  */
2878  memset(buffer, 0, sizeof(buffer));
2879  memset(out, 0, sizeof(out));
2880  if (key) {
2881  memcpy(buffer, key, BYTES(start_bit) + 1);
2882  }
2883 
2884  /*
2885  * Where the output data goes.
2886  */
2887  my_sprint.start = out;
2888  my_sprint.buffer = out;
2889  my_sprint.buflen = sizeof(out);
2890 
2891  /*
2892  * Where the keys are built.
2893  */
2894  my_cb.start = buffer;
2895  my_cb.end = buffer + sizeof(buffer);
2896  my_cb.callback = _trie_sprint_cb;
2897  my_cb.user_callback = NULL;
2898  my_cb.ctx = &my_sprint;
2899 
2900  /*
2901  * Call the internal walk function to do the work.
2902  */
2903  (void) trie_key_walk(trie, &my_cb, start_bit, false);
2904 
2905  MPRINT3("%.*s%s at %d\n", start_bit, spaces, out, lineno);
2906 }
2907 
2908 
2909 /** Parse a string into bits + key
2910  *
2911  * The format is one of:
2912  *
2913  * - string such as "abcdef"
2914  * - string prefixed with a bit length, {4}a
2915  */
2916 static int arg2key(char *arg, char **key, int *length)
2917 {
2918  char *p;
2919  int bits, size;
2920 
2921  if (*arg != '{') {
2922  *key = arg;
2923  *length = BITSOF(strlen(arg));
2924  return 0;
2925  }
2926 
2927  p = strchr(arg, '}');
2928  if (!p) {
2929  MPRINT("Failed to find end '}' for {bits}\n");
2930  return -1;
2931  }
2932 
2933  bits = BITSOF(strlen(p + 1));
2934  if (!bits) {
2935  MPRINT("No key found in in '%s'\n", arg);
2936  return -1;
2937  }
2938 
2939  size = atoi(arg + 1); /* ignore end character... */
2940  if (size > bits) {
2941  MPRINT("Length '%d' is longer than bits in key %s",
2942  size, p + 1);
2943  }
2944 
2945  *key = p + 1;
2946  *length = size;
2947 
2948  return 0;
2949 }
2950 
2951 /** Our TALLOC_CTX for the data we put into the trie.
2952  *
2953  * Most people don't need to do this, they can just insert their own
2954  * data.
2955  */
2956 static void *data_ctx = NULL;
2957 
2958 /** Insert a key + data into a trie.
2959  *
2960  */
2961 static int command_insert(fr_trie_t *ft, UNUSED int argc, char **argv, UNUSED char *out, UNUSED size_t outlen)
2962 {
2963  int bits;
2964  void *data;
2965  char *key;
2966 
2967  if (arg2key(argv[0], &key, &bits) < 0) {
2968  return -1;
2969  }
2970 
2971  /*
2972  * This has to stick around in between command
2973  * invocations.
2974  */
2975  data = talloc_strdup(data_ctx, argv[1]);
2976  if (!data) {
2977  MPRINT("OOM\n");
2978  return -1;
2979  }
2980 
2981  if (fr_trie_insert_by_key(ft, key, bits, data) < 0) {
2982  MPRINT("Failed inserting key %s=%s - %s\n", key, argv[1], fr_strerror());
2983  return -1;
2984  }
2985 
2986  return 0;
2987 }
2988 
2989 /** Verify a trie recursively
2990  *
2991  * For sanity reasons, this command runs but doesn't do anything if
2992  * the code is built with no trie verification.
2993  */
2994 static int command_verify(fr_trie_t *ft, UNUSED int argc, UNUSED char **argv, UNUSED char *out, UNUSED size_t outlen)
2995 {
2996  fr_cond_assert(ft != NULL);
2997 
2998  /*
2999  * The top-level node may have a NULL talloc ctx, which
3000  * is OK. So we skip that.
3001  */
3002  if (ft->type != FR_TRIE_USER) {
3003  fprintf(stderr, "Verify failed: trie is malformed\n");
3004  return -1;
3005  }
3006 
3007  if (trie_verify(ft->trie) < 0) {
3008  fprintf(stderr, "Verify failed: %s\n", fr_strerror());
3009  return -1;
3010  }
3011 
3012  return 0;
3013 }
3014 
3015 /** Print the keys accepted by a trie
3016  *
3017  * The strings are printed to stdout.
3018  *
3019  * @todo - allow printing to a file.
3020  */
3021 static int command_keys(fr_trie_t *ft, UNUSED int argc, UNUSED char **argv, char *out, size_t outlen)
3022 {
3023  fr_trie_callback_t my_cb;
3024 
3025  my_cb.start = (uint8_t *) out;
3026  my_cb.end = (uint8_t *) (out + outlen);
3027  my_cb.callback = _trie_print_cb;
3028  my_cb.user_callback = NULL;
3029  my_cb.ctx = stdout;
3030 
3031  /*
3032  * Call the internal walk function to do the work.
3033  */
3034  return trie_key_walk(ft->trie, &my_cb, 0, false);
3035 }
3036 
3037 
3038 /** Dump the trie in internal format
3039  *
3040  * The information is printed to stdout.
3041  *
3042  * For sanity reasons, this command runs but doesn't do anything if
3043  * the code is built with no trie dumping.
3044  *
3045  * @todo - allow printing to a file.
3046  */
3047 static int command_dump(fr_trie_t *ft, UNUSED int argc, UNUSED char **argv, char *out, size_t outlen)
3048 {
3049  fr_trie_callback_t my_cb;
3050 
3051  my_cb.start = (uint8_t *) out;
3052  my_cb.end = (uint8_t *) (out + outlen);
3053  my_cb.callback = _trie_dump_cb;
3054  my_cb.user_callback = NULL;
3055  my_cb.ctx = stdout;
3056 
3057  /*
3058  * Call the internal walk function to do the work.
3059  */
3060  return trie_key_walk(ft->trie, &my_cb, 0, false);
3061 }
3062 
3063 
3064 /** Clear the entire trie without caring what's in it.
3065  *
3066  */
3067 static int command_clear(fr_trie_t *ft, UNUSED int argc, UNUSED char **argv, UNUSED char *out, UNUSED size_t outlen)
3068 {
3069  if (!ft->trie) return 0;
3070 
3071  trie_free(ft->trie);
3072  ft->trie = NULL;
3073 
3074  /*
3075  * Clean up our internal data ctx, too.
3076  */
3077  talloc_free(data_ctx);
3078  data_ctx = talloc_init_const("data_ctx");
3079 
3080  return 0;
3081 }
3082 
3083 
3084 /** Turn on line number debugging.
3085  *
3086  * @todo - add general "debug" functionality.
3087  */
3088 static int command_lineno(UNUSED fr_trie_t *ft, UNUSED int argc, char **argv, UNUSED char *out, UNUSED size_t outlen)
3089 {
3090  if (strcmp(argv[0], "true") == 0) {
3091  print_lineno = true;
3092  } else {
3093  print_lineno = false;
3094  }
3095 
3096  return 0;
3097 }
3098 
3099 
3100 /** Match an exact key + length
3101  *
3102  * Normally, the "lookup" returns the longest prefix match, so that
3103  * *long* key lookups can return *short* matches.
3104  *
3105  * In some cases, we want to know if an exact key is in the trie.
3106  * For those cases, we use this function.
3107  */
3108 static int command_match(fr_trie_t *ft, UNUSED int argc, char **argv, char *out, size_t outlen)
3109 {
3110  int bits;
3111  void *answer;
3112  char *key;
3113 
3114  if (arg2key(argv[0], &key, &bits) < 0) {
3115  return -1;
3116  }
3117 
3118  answer = trie_key_match(ft->trie, (uint8_t *) key, 0, bits, true);
3119  if (!answer) {
3120  strlcpy(out, "{}", outlen);
3121  return 0;
3122  }
3123 
3124  strlcpy(out, answer, outlen);
3125 
3126  return 0;
3127 }
3128 
3129 
3130 /** Look up a key and return user ctx data.
3131  *
3132  * This is done by longest prefix match, not exact match.
3133  */
3134 static int command_lookup(fr_trie_t *ft, UNUSED int argc, char **argv, char *out, size_t outlen)
3135 {
3136  int bits;
3137  void *answer;
3138  char *key;
3139 
3140  if (arg2key(argv[0], &key, &bits) < 0) {
3141  return -1;
3142  }
3143 
3144  answer = fr_trie_lookup_by_key(ft, key, bits);
3145  if (!answer) {
3146  strlcpy(out, "{}", outlen);
3147  return 0;
3148  }
3149 
3150  strlcpy(out, answer, outlen);
3151 
3152  return 0;
3153 }
3154 
3155 
3156 /** Remove a key from the trie.
3157  *
3158  * The key has to match exactly.
3159  */
3160 static int command_remove(fr_trie_t *ft, UNUSED int argc, char **argv, char *out, size_t outlen)
3161 {
3162  int bits;
3163  void *answer;
3164  char *key;
3165 
3166  if (arg2key(argv[0], &key, &bits) < 0) {
3167  return -1;
3168  }
3169 
3170  answer = fr_trie_remove_by_key(ft, key, bits);
3171  if (!answer) {
3172  MPRINT("Could not remove key %s\n", key);
3173  return -1;
3174  }
3175 
3176  strlcpy(out, answer, outlen);
3177 
3178  talloc_free(answer);
3179 
3180  /*
3181  * We now try to find an exact match. i.e. we don't want
3182  * to find a shorter prefix.
3183  */
3184  answer = trie_key_match(ft->trie, (uint8_t *) key, 0, bits, true);
3185  if (answer) {
3186  MPRINT("Still in trie after 'remove' for key %s, found data %s\n", key, (char const *) answer);
3187  return -1;
3188  }
3189 
3190  return 0;
3191 }
3192 
3193 
3194 /** Remove a key from the trie.
3195  *
3196  * Try to remove a key, but don't error if we can't.
3197  */
3198 static int command_try_to_remove(fr_trie_t *ft, UNUSED int argc, char **argv, char *out, size_t outlen)
3199 {
3200  int bits;
3201  void *answer;
3202  char *key;
3203 
3204  if (arg2key(argv[0], &key, &bits) < 0) {
3205  return -1;
3206  }
3207 
3208  answer = fr_trie_remove_by_key(ft, key, bits);
3209  if (!answer) {
3210  strlcpy(out, ".", outlen);
3211  return 0;
3212  }
3213 
3214  strlcpy(out, answer, outlen);
3215 
3216  talloc_free(answer);
3217 
3218  /*
3219  * We now try to find an exact match. i.e. we don't want
3220  * to find a shorter prefix.
3221  */
3222  answer = trie_key_match(ft->trie, (uint8_t *) key, 0, bits, true);
3223  if (answer) {
3224  MPRINT("Still in trie after 'remove' for key %s, found data %s\n", key, (char const *) answer);
3225  return -1;
3226  }
3227 
3228  return 0;
3229 }
3230 
3231 
3232 /** Print a trie to a string
3233  *
3234  * The trie is printed one one line. If the trie contains keys which
3235  * are not on a byte boundary, well... too bad. It gets printed
3236  * terribly.
3237  */
3238 static int command_print(fr_trie_t *ft, UNUSED int argc, UNUSED char **argv, char *out, size_t outlen)
3239 {
3240  fr_trie_callback_t my_cb;
3241  trie_sprint_ctx_t my_sprint;
3243 
3244  /*
3245  * Where the output data goes.
3246  */
3247  my_sprint.start = out;
3248  my_sprint.buffer = out;
3249  my_sprint.buflen = outlen;
3250 
3251  /*
3252  * Where the keys are built.
3253  */
3254  my_cb.start = buffer;
3255  my_cb.end = buffer + sizeof(buffer);
3256  my_cb.callback = _trie_sprint_cb;
3257  my_cb.user_callback = NULL;
3258  my_cb.ctx = &my_sprint;
3259 
3260  memset(buffer, 0, sizeof(buffer));
3261 
3262  /*
3263  * Call the internal walk function to do the work.
3264  */
3265  return trie_key_walk(ft->trie, &my_cb, 0, false);
3266 }
3267 
3268 
3269 /** Do insert / lookup / remove all at once.
3270  *
3271  * Sometimes it's more useful to do insert / lookup / remove for
3272  * simple keys.
3273  */
3274 static int command_path(fr_trie_t *ft, int argc, char **argv, char *out, size_t outlen)
3275 {
3276  void *data;
3277  void *answer;
3278 
3279  data = talloc_strdup(ft, argv[1]); /* has to be malloc'd data, sorry */
3280  if (!data) {
3281  MPRINT("OOM\n");
3282  return -1;
3283  }
3284 
3285  if (fr_trie_insert_by_key(ft, argv[0], BITSOF(strlen(argv[0])), data) < 0) {
3286  MPRINT("Could not insert key %s=%s - %s\n", argv[0], argv[1], fr_strerror());
3287  return -1;
3288  }
3289 
3290  answer = fr_trie_lookup_by_key(ft, argv[0], BITSOF(strlen(argv[0])));
3291  if (!answer) {
3292  MPRINT("Could not look up key %s\n", argv[0]);
3293  return -1;
3294  }
3295 
3296  if (answer != data) {
3297  MPRINT("Expected to find %s, got %s\n", argv[1], (char const *) answer);
3298  return -1;
3299  }
3300 
3301  /*
3302  * Call the command 'print' to print out the key.
3303  */
3304  (void) command_print(ft, argc, argv, out, outlen);
3305 
3306  answer = fr_trie_remove_by_key(ft, (uint8_t const *) argv[0], BITSOF(strlen(argv[0])));
3307  if (!answer) {
3308  MPRINT("Could not remove key %s\n", argv[0]);
3309  return -1;
3310  }
3311 
3312  if (answer != data) {
3313  MPRINT("Expected to remove %s, got %s\n", argv[1], (char const *) answer);
3314  return -1;
3315  }
3316 
3317  talloc_free(answer);
3318 
3319  return 0;
3320 }
3321 
3322 
3323 /** Return the longest common prefix of two bit strings.
3324  *
3325  */
3326 static int command_lcp(UNUSED fr_trie_t *ft, int argc, char **argv, char *out, size_t outlen)
3327 {
3328  int lcp;
3329  int keylen1, keylen2;
3330  int start_bit;
3331  uint8_t const *key1, *key2;
3332 
3333  if (argc == 2) {
3334  key1 = (uint8_t const *) argv[0];
3335  keylen1 = BITSOF(strlen(argv[0]));
3336 
3337  key2 = (uint8_t const *) argv[1];
3338  keylen2 = BITSOF(strlen(argv[1]));
3339  start_bit = 0;
3340 
3341  } else if (argc == 5) {
3342  key1 = (uint8_t const *) argv[0];
3343  keylen1 = atoi(argv[1]);
3344  if ((keylen1 < 0) || (keylen1 > (int) BITSOF(strlen(argv[0])))) {
3345  MPRINT("length of key1 %s is larger than string length %ld\n",
3346  argv[1], BITSOF(strlen(argv[0])));
3347  return -1;
3348  }
3349 
3350  key2 = (uint8_t const *) argv[2];
3351  keylen2 = atoi(argv[3]);
3352  if ((keylen2 < 0) || (keylen2 > (int) BITSOF(strlen(argv[2])))) {
3353  MPRINT("length of key2 %s is larger than string length %ld\n",
3354  argv[3], BITSOF(strlen(argv[2])));
3355  return -1;
3356  }
3357 
3358  start_bit = atoi(argv[4]);
3359  if ((start_bit < 0) || (start_bit > 7)) {
3360  MPRINT("start_bit has invalid value %s\n", argv[4]);
3361  return -1;
3362  }
3363 
3364  } else {
3365  MPRINT("Invalid number of arguments\n");
3366  return -1;
3367  }
3368 
3369  lcp = fr_trie_key_lcp(key1, keylen1, key2, keylen2, start_bit);
3370 
3371  snprintf(out, outlen, "%d", lcp);
3372  return 0;
3373 }
3374 
3375 /** Get chunks from raw data
3376  *
3377  */
3378 static int command_chunk(UNUSED fr_trie_t *ft, UNUSED int argc, char **argv, char *out, size_t outlen)
3379 {
3380  int start_bit, num_bits;
3381  uint16_t chunk;
3382 
3383  start_bit = atoi(argv[1]);
3384  num_bits = atoi(argv[2]);
3385 
3386  chunk = get_chunk((uint8_t const *) argv[0], start_bit, num_bits);
3387 
3388  snprintf(out, outlen, "%04x", chunk);
3389  return 0;
3390 }
3391 
3392 /** A function to parse a trie command line.
3393  *
3394  */
3395 typedef int (*fr_trie_function_t)(fr_trie_t *ft, int argc, char **argv, char *out, size_t outlen);
3396 
3397 /** Data structure which holds the trie command name, function, etc.
3398  *
3399  */
3400 typedef struct {
3401  char const *name;
3402  fr_trie_function_t function;
3403  int min_argc;
3404  int max_argc;
3405  bool output;
3406 } fr_trie_command_t;
3407 
3408 
3409 /** The trie commands for debugging.
3410  *
3411  */
3412 static fr_trie_command_t commands[] = {
3413  { "lcp", command_lcp, 2, 5, true },
3414  { "chunk", command_chunk, 3, 3, true },
3415  { "path", command_path, 2, 2, true },
3416  { "insert", command_insert, 2, 2, false },
3417  { "match", command_match, 1, 1, true },
3418  { "lookup", command_lookup, 1, 1, true },
3419  { "remove", command_remove, 1, 1, true },
3420  { "-remove", command_try_to_remove, 1, 1, true },
3421  { "print", command_print, 0, 0, true },
3422  { "dump", command_dump, 0, 0, false },
3423  { "keys", command_keys, 0, 0, false },
3424  { "verify", command_verify, 0, 0, false },
3425  { "lineno", command_lineno, 1, 1, false },
3426  { "clear", command_clear, 0, 0, false },
3427  { NULL, NULL, 0, 0}
3428 };
3429 
3430 #define MAX_ARGC (16)
3431 int main(int argc, char **argv)
3432 {
3433  int lineno = 0;
3434  int ret = 0;
3435  fr_trie_t *ft;
3436  FILE *fp;
3437  int my_argc;
3438  char *my_argv[MAX_ARGC];
3439  char buffer[8192];
3440  char output[8192];
3441 
3442  if (argc < 2) {
3443  fprintf(stderr, "Please specify filename\n");
3444  fr_exit_now(EXIT_SUCCESS);
3445  }
3446 
3447  fp = fopen(argv[1], "r");
3448  if (!fp) {
3449  fprintf(stderr, "Failed opening %s: %s\n", argv[1], fr_syserror(errno));
3450  fr_exit_now(1);
3451  }
3452 
3453  /*
3454  * Tell us if we leaked memory.
3455  */
3456  talloc_enable_null_tracking();
3457 
3458  data_ctx = talloc_init_const("data_ctx");
3459 
3460  ft = fr_trie_alloc(NULL, NULL, NULL);
3461  if (!ft) {
3462  fprintf(stderr, "Failed creating trie\n");
3463  fr_exit_now(1);
3464  }
3465 
3466  while (fgets(buffer, sizeof(buffer), fp) != NULL) {
3467  int i, cmd;
3468  char *p;
3469 
3470  lineno++;
3471 
3472  /*
3473  * Remove comments.
3474  */
3475  for (p = buffer; *p != '\0'; p++) {
3476  if (*p == '#') {
3477  *p = '\0';
3478  break;
3479  }
3480  }
3481 
3482  /*
3483  * Skip leading whitespace.
3484  */
3485  p = buffer;
3486  fr_skip_whitespace(p);
3487 
3488  /*
3489  * Skip (now) blank lines.
3490  */
3491  if (!*p) continue;
3492 
3493  my_argc = fr_dict_str_to_argv(p, my_argv, MAX_ARGC);
3494 
3495  cmd = -1;
3496  for (i = 0; commands[i].name != NULL; i++) {
3497  if (strcmp(my_argv[0], commands[i].name) != 0) continue;
3498 
3499  cmd = i;
3500  break;
3501  }
3502 
3503  if (cmd < 0) {
3504  fprintf(stderr, "Unknown command '%s' at line %d\n",
3505  my_argv[0], lineno);
3506  ret = 1;
3507  break;
3508  }
3509 
3510  /*
3511  * argv[0] is the command.
3512  * argv[argc-1] is the output.
3513  */
3514  if (((commands[cmd].min_argc + 1 + commands[cmd].output) > my_argc) ||
3515  ((commands[cmd].max_argc + 1 + commands[cmd].output) < my_argc)) {
3516  fprintf(stderr, "Invalid number of arguments to %s at line %d. Expected %d, got %d\n",
3517  my_argv[0], lineno, commands[cmd].min_argc + 1, my_argc - 1);
3518  fr_exit_now(1);
3519  }
3520 
3521  if (print_lineno) {
3522  printf("%d ", lineno);
3523  fflush(stdout);
3524  }
3525 
3526  MPRINT3("[%d] %s\n", lineno, my_argv[0]);
3527  if (commands[cmd].function(ft, my_argc - 1 - commands[cmd].output, &my_argv[1], output, sizeof(output)) < 0) {
3528  fprintf(stderr, "Failed running %s at line %d\n",
3529  my_argv[0], lineno);
3530  fr_exit_now(1);
3531  }
3532 
3533  if (!commands[cmd].output) continue;
3534 
3535  if (strcmp(output, my_argv[my_argc - 1]) != 0) {
3536  fprintf(stderr, "Failed running %s at line %d: Expected '%s' got '%s'\n",
3537  my_argv[0], lineno, my_argv[my_argc - 1], output);
3538  fr_exit_now(1);
3539  }
3540  }
3541 
3542  fclose(fp);
3543 
3544  trie_free(ft);
3545  talloc_free(data_ctx);
3546 
3547  talloc_report_full(NULL, stdout); /* Print details of any leaked memory */
3548  talloc_disable_null_tracking(); /* Cleanup talloc null tracking context */
3549 
3550  return ret;
3551 }
3552 #endif
static int const char char buffer[256]
Definition: acutest.h:574
log_entry msg
Definition: acutest.h:794
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition: build.h:165
#define RCSID(id)
Definition: build.h:444
#define DIAG_ON(_x)
Definition: build.h:419
#define UNUSED
Definition: build.h:313
#define DIAG_OFF(_x)
Definition: build.h:418
static int split(char **input, char **output, bool syntax_string)
Definition: command.c:385
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition: debug.h:137
#define fr_exit_now(_x)
Exit without calling atexit() handlers, producing a log message in debug builds.
Definition: debug.h:232
static char const * spaces
Definition: dependency.c:364
int main(int argc, char **argv)
Definition: dhcpclient.c:521
int fr_dict_str_to_argv(char *str, char **argv, int max_argc)
Definition: dict_tokenize.c:80
talloc_free(reap)
unsigned short uint16_t
Definition: merged_model.c:31
unsigned int uint32_t
Definition: merged_model.c:33
unsigned char uint8_t
Definition: merged_model.c:30
static size_t used
static uint8_t depth(fr_minmax_heap_index_t i)
Definition: minmax_heap.c:83
#define fr_skip_whitespace(_p)
Skip whitespace ('\t', '\n', '\v', '\f', '\r', ' ')
Definition: misc.h:59
void(* fr_free_t)(void *)
Definition: misc.h:39
static bool done
Definition: radclient.c:80
static int8_t comp(void const *a, void const *b)
Definition: rbmonkey.c:13
static char const * name
static void xor(char *out, char *in1, char *in2, int n)
Definition: smbdes.c:183
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition: snprintf.c:689
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition: strlcpy.c:34
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition: syserror.c:243
fr_table_elem_t name
Definition: table.h:62
static TALLOC_CTX * talloc_init_const(char const *name)
Allocate a top level chunk with a constant name.
Definition: talloc.h:112
int(* fr_trie_key_walk_t)(fr_trie_t *trie, fr_trie_callback_t *cb, int depth, bool more)
Definition: trie.c:2176
fr_trie_t * fr_trie_alloc(TALLOC_CTX *ctx, fr_trie_key_t get_key, fr_free_t free_data)
Allocate a trie.
Definition: trie.c:743
#define MPRINT(...)
Internal sanity checks for debugging.
Definition: trie.c:119
static trie_key_match_t trie_match_table[FR_TRIE_MAX]
Definition: trie.c:1202
static void * trie_user_remove(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit)
Definition: trie.c:1914
bool fr_trie_delete(fr_trie_t *ft, void const *data)
Remove node and free data (if a free function was specified)
Definition: trie.c:2789
#define trie_check(_trie, _key, _start_bit, _end_bit, _data, _lineno)
Definition: trie.c:1329
static trie_key_remove_t trie_remove_table[FR_TRIE_MAX]
Definition: trie.c:2114
bool fr_trie_insert(fr_trie_t *ft, void const *data)
Insert data into a trie.
Definition: trie.c:2693
#define MAX_KEY_BITS
Definition: trie.c:95
static void * trie_key_match(fr_trie_t *trie, uint8_t const *key, int start_bit, int end_bit, bool exact)
Match a key in a trie and return user ctx, if any.
Definition: trie.c:1228
unsigned int fr_trie_num_elements(UNUSED fr_trie_t *ft)
Return how many nodes there are in a trie.
Definition: trie.c:2817
static fr_trie_key_walk_t trie_walk_table[FR_TRIE_MAX]
Definition: trie.c:2255
int used
Definition: trie.c:495
void * fr_trie_find(fr_trie_t *ft, void const *data)
Find an element in the trie, returning the data.
Definition: trie.c:2643
#define TRIE_HEADER
Definition: trie.c:482
static fr_trie_node_t * trie_node_alloc(TALLOC_CTX *ctx, int bits)
Definition: trie.c:530
static fr_trie_path_t * fr_trie_path_alloc(TALLOC_CTX *ctx, uint8_t const *key, int start_bit, int end_bit)
Definition: trie.c:636
void *(* trie_key_match_t)(fr_trie_t *trie, uint8_t const *key, int start_bit, int end_bit, bool exact)
Definition: trie.c:1108
static void * trie_node_remove(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit)
Definition: trie.c:1936
uint16_t chunk
Definition: trie.c:512
int fr_trie_replace(void **old, fr_trie_t *ft, void const *data)
Replace old data with new data, OR insert if there is no old.
Definition: trie.c:2725
static int trie_key_walk(fr_trie_t *trie, fr_trie_callback_t *cb, int depth, bool more)
Definition: trie.c:2266
#define BYTEOF(_x)
Definition: trie.c:137
static fr_trie_t * trie_key_alloc(TALLOC_CTX *ctx, uint8_t const *key, int start_bit, int end_bit, void *data)
Definition: trie.c:889
#define MAX_KEY_BYTES
Definition: trie.c:94
fr_free_t free_data
Definition: trie.c:731
void * fr_trie_remove(fr_trie_t *ft, void const *data)
Remove an entry, without freeing the data.
Definition: trie.c:2764
fr_trie_t * trie[]
Definition: trie.c:496
static void * trie_key_remove(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit)
Remove a key from a trie, and return the user data.
Definition: trie.c:2128
void * fr_trie_remove_by_key(fr_trie_t *ft, void const *key, size_t keylen)
Remove a key and return the associated user ctx.
Definition: trie.c:2156
static fr_trie_user_t * fr_trie_user_alloc(TALLOC_CTX *ctx, void const *data)
Definition: trie.c:615
fr_trie_t * trie
Definition: trie.c:510
int fr_trie_walk(fr_trie_t *ft, void *ctx, fr_trie_walk_t callback)
Definition: trie.c:2609
#define BYTES(_x)
Definition: trie.c:138
#define MPRINT3(...)
Definition: trie.c:121
void * fr_trie_match_by_key(fr_trie_t const *ft, void const *key, size_t keylen)
Match a key and length in a trie and return user ctx, if any.
Definition: trie.c:1288
fr_trie_walk_t user_callback
Definition: trie.c:2187
static int _trie_user_cb(fr_trie_t *trie, fr_trie_callback_t *cb, int keylen, UNUSED bool more)
Implement the user-visible side of the walk callback.
Definition: trie.c:2591
uint8_t * start
Definition: trie.c:2181
static uint8_t xor2lcp[256]
Definition: trie.c:172
void *(* trie_key_remove_t)(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit)
Definition: trie.c:1912
static void * trie_path_remove(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit)
Definition: trie.c:1976
void * data
Definition: trie.c:503
static int trie_path_insert(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit, void *data)
Definition: trie.c:1424
void * fr_trie_match(fr_trie_t *ft, void const *data)
Match an element exactly in the trie, returning the data.
Definition: trie.c:2668
static int trie_node_insert(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit, void *data)
Definition: trie.c:1350
fr_trie_key_walk_t callback
Definition: trie.c:2186
#define trie_sprint(_trie, _key, _start_bit, _lineno)
Definition: trie.c:122
#define VERIFY(_x)
Definition: trie.c:130
#define BITSOF(_x)
Definition: trie.c:136
static trie_key_insert_t trie_insert_table[FR_TRIE_MAX]
Definition: trie.c:1787
static int trie_node_walk(fr_trie_t *trie, fr_trie_callback_t *cb, int depth, bool more)
Definition: trie.c:2199
static uint16_t get_chunk(uint8_t const *key, int start_bit, int num_bits)
Return a chunk of a key (in the low bits) for use in 2^N node de-indexing.
Definition: trie.c:339
uint8_t buffer[16]
Definition: trie.c:729
fr_trie_type_t
Definition: trie.c:456
@ FR_TRIE_PATH
Definition: trie.c:460
@ FR_TRIE_NODE
Definition: trie.c:465
@ FR_TRIE_INVALID
Definition: trie.c:457
@ FR_TRIE_USER
Definition: trie.c:458
#define FR_TRIE_MAX
Definition: trie.c:468
#define TRIE_TYPE_CHECK(_x, _r)
Definition: trie.c:483
#define MPRINT2(...)
Definition: trie.c:120
static void write_chunk(uint8_t *out, int start_bit, int num_bits, uint16_t chunk)
Write a chunk to an output buffer.
Definition: trie.c:411
static int fr_trie_key_lcp(uint8_t const *key1, int keylen1, uint8_t const *key2, int keylen2, int start_bit)
Get the longest prefix of the two keys.
Definition: trie.c:227
fr_trie_t * trie
Definition: trie.c:502
static int trie_user_walk(fr_trie_t *trie, fr_trie_callback_t *cb, int depth, bool more)
Definition: trie.c:2190
static fr_trie_node_t * trie_node_split(TALLOC_CTX *ctx, fr_trie_node_t *node, int bits)
Split a node at bits.
Definition: trie.c:775
static int trie_add_edge(fr_trie_t *trie, uint16_t chunk, fr_trie_t *child)
Add an edge to a node.
Definition: trie.c:1048
static int trie_key_insert(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit, void *data))
Insert a binary key into the trie.
Definition: trie.c:1812
TRIE_HEADER
Definition: trie.c:487
static fr_trie_path_t * trie_path_split(TALLOC_CTX *ctx, fr_trie_path_t *path, int start_bit, int lcp)
Definition: trie.c:833
uint8_t key[2]
Definition: trie.c:513
fr_trie_t * trie
Definition: trie.c:489
static void * trie_path_match(fr_trie_t *trie, uint8_t const *key, int start_bit, int end_bit, bool exact)
Definition: trie.c:1162
#define MAX_NODE_BITS
Definition: trie.c:98
uint8_t const * end
Definition: trie.c:2182
static void * trie_user_match(fr_trie_t *trie, uint8_t const *key, int start_bit, int end_bit, bool exact)
Definition: trie.c:1112
int fr_trie_insert_by_key(fr_trie_t *ft, void const *key, size_t keylen, void const *data)
Insert a key and user ctx into a trie.
Definition: trie.c:1877
fr_trie_key_t get_key
Definition: trie.c:730
void * fr_trie_lookup_by_key(fr_trie_t const *ft, void const *key, size_t keylen)
Lookup a key in a trie and return user ctx, if any.
Definition: trie.c:1264
static int trie_path_walk(fr_trie_t *trie, fr_trie_callback_t *cb, int depth, bool more)
Definition: trie.c:2221
static uint8_t start_bit_mask[8]
Definition: trie.c:150
static int trie_user_insert(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit, void *data)
Definition: trie.c:1336
static uint8_t used_bit_mask[8]
Definition: trie.c:155
int(* trie_key_insert_t)(TALLOC_CTX *ctx, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit, void *data)
Definition: trie.c:1334
static void * trie_node_match(fr_trie_t *trie, uint8_t const *key, int start_bit, int end_bit, bool exact)
Definition: trie.c:1147
static void trie_free(fr_trie_t *trie)
Free a fr_trie_t.
Definition: trie.c:564
int(* fr_trie_key_t)(uint8_t **out, size_t *outlen, void const *data)
Definition: trie.h:56
int(* fr_trie_walk_t)(uint8_t const *key, size_t keylen, void *data, void *uctx)
Walk over a trie.
Definition: trie.h:43
static fr_table_ptr_sorted_t commands[]
static void command_print(void)
static size_t command_match(command_result_t *result, command_file_ctx_t *cc, char *data, size_t data_used, char *in, size_t inlen)
Compare the data buffer to an expected value.
static size_t command_clear(command_result_t *result, UNUSED command_file_ctx_t *cc, char *data, size_t UNUSED data_used, UNUSED char *in, UNUSED size_t inlen)
char const * fr_strerror(void)
Get the last library error.
Definition: strerror.c:554
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition: strerror.h:64
#define fr_strerror_const(_msg)
Definition: strerror.h:223
static fr_slen_t data
Definition: value.h:1259
int nonnull(2, 5))
static size_t char ** out
Definition: value.h:984