The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
rlm_cache_htrie.c
Go to the documentation of this file.
1 /*
2  * This program is is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or (at
5  * your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /**
18  * $Id: e45787a9e5f311b7822aaf40e2381572394aa7c8 $
19  * @file rlm_cache_htrie.c
20  * @brief Simple htrie based cache.
21  *
22  * @copyright 2024 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
23  * @copyright 2014 The FreeRADIUS server project
24  */
25 #include <freeradius-devel/server/base.h>
26 #include <freeradius-devel/util/heap.h>
27 #include <freeradius-devel/util/debug.h>
28 #include <freeradius-devel/util/value.h>
29 #include <freeradius-devel/util/htrie.h>
30 #include "../../rlm_cache.h"
31 #include "lib/server/cf_parse.h"
32 #include "lib/server/tmpl.h"
33 #include "lib/util/types.h"
34 
35 static int cf_htrie_type_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule);
36 static int cf_htrie_key_parse(TALLOC_CTX *ctx, void *out, tmpl_rules_t const *t_rules, CONF_ITEM *ci,
37  void const *data, UNUSED call_env_parser_t const *rule);
38 
39 typedef struct {
40  fr_htrie_t *cache; //!< Tree for looking up cache keys.
41  fr_heap_t *heap; //!< For managing entry expiry.
42 
43  fr_type_t ktype; //!< When htrie is "auto", we use this type to decide
44  ///< what type of tree to use.
45 
46  fr_htrie_type_t htype; //!< The htrie type we'll be using
47  bool htrie_auto; //!< Whether the user wanted to automatically configure
48  ///< the htrie.
49 
50  pthread_mutex_t mutex; //!< Protect the tree from multiple readers/writers.
52 
53 typedef struct {
54  rlm_cache_entry_t fields; //!< Entry data.
55  fr_heap_index_t heap_id; //!< Offset used for expiry heap.
57 
59  { FR_CONF_OFFSET("type", rlm_cache_htrie_t, htype), .dflt = "auto",
60  .func = cf_htrie_type_parse,
61  .uctx = &(cf_table_parse_ctx_t){ .table = fr_htrie_type_table, .len = &fr_htrie_type_table_len } },
63 };
64 
65 /** Custom htrie type parsing function
66  *
67  * Sets a bool, so we known if the original type was "auto", so we can constantly re-evaluate
68  * the htrie type based on the key type.
69  */
70 int cf_htrie_type_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
71 {
72  rlm_cache_htrie_t *inst = talloc_get_type_abort(parent, rlm_cache_htrie_t);
73  int ret;
74 
75  ret = cf_table_parse_int(ctx, out, parent, ci, rule);
76  if (unlikely(ret < 0)) return ret;
77 
78  /*
79  * Record this now, so when we overwrite this
80  * value later, we know to keep checking the
81  * htrie type value for consistency.
82  */
83  if (*(int *)out == FR_HTRIE_AUTO) inst->htrie_auto = true;
84 
85  return 0;
86 }
87 
88 /** Custom key parsing function for checking compatibility of key types
89  *
90  * This function does two things:
91  * - It selects a htrie type based on the key type.
92  * - It checks that all keys are compatible with each other.
93  */
94 static int cf_htrie_key_parse(TALLOC_CTX *ctx, void *out, tmpl_rules_t const *t_rules, CONF_ITEM *ci,
95  void const *data, UNUSED call_env_parser_t const *rule)
96 {
98  tmpl_t *key_tmpl;
99  fr_type_t our_ktype, old_ktype;
100 
101  /*
102  * Call the standard pair parsing function
103  */
104  if (unlikely(call_env_parse_pair(ctx, &key_tmpl, t_rules, ci, data, rule) < 0)) return -1;
105  our_ktype = tmpl_expanded_type(key_tmpl);
106 
107  /*
108  * We need the user to tell us what the key type is for ambiguous expansions
109  */
110  if (fr_type_is_void(our_ktype)) {
111  cf_log_err(ci, "Key type is unspecified. Add a cast to set a specific type");
112  return -1;
113  }
114 
115  /*
116  * If we don't have a key type already, then just set it to the first key type we see
117  */
118  if (fr_type_is_void(inst->ktype)) {
119  inst->ktype = our_ktype;
120  /*
121  * Check if we can cast this key type, to the key type we've already seen
122  */
123  } else if (!fr_type_cast(our_ktype, inst->ktype)) {
124  cf_log_err(ci, "Incompatible key types '%s' and '%s', cast to a more broadly compatible "
125  "type such as 'string'", fr_type_to_str(inst->ktype), fr_type_to_str(our_ktype));
126  return -1;
127  }
128 
129  /*
130  * See if we should promote inst->ktype
131  */
132  old_ktype = inst->ktype;
133  inst->ktype = fr_type_promote(inst->ktype, our_ktype);
134  fr_assert(!fr_type_is_void(inst->ktype));
135 
136  /*
137  * If we're not automatically determining the htrie type,
138  * or the ktype hasn't changed, then don't bother figuring
139  * out the htrie type.
140  */
141  if (!inst->htrie_auto || (old_ktype == inst->ktype)) return 0;
142 
143  /*
144  * We need to figure out the htrie type based on the key type
145  */
146  inst->htype = fr_htrie_hint(inst->ktype);
147  if (inst->htype == FR_HTRIE_INVALID) {
148  cf_log_err(ci, "Invalid data type '%s' for htrie key. "
149  "Cast to another type, or manually specify 'type", fr_type_to_str(inst->ktype));
150  return -1;
151  }
152 
153  cf_log_info(ci, "Automatically setting htrie type to '%s' based on key type '%s'",
154  fr_htrie_type_to_str(inst->htype), fr_type_to_str(inst->ktype));
155 
156  *(void **)out = key_tmpl;
157  return 0;
158 }
159 
160 /** Compare two entries by expiry time
161  *
162  * There may be multiple entries with the same expiry time.
163  */
164 static int8_t cache_heap_cmp(void const *one, void const *two)
165 {
166  rlm_cache_entry_t const *a = one, *b = two;
167 
168  return fr_unix_time_cmp(a->expires, b->expires);
169 }
170 
171 /** Custom allocation function for the driver
172  *
173  * Allows allocation of cache entry structures with additional fields.
174  *
175  * @copydetails cache_entry_alloc_t
176  */
178  request_t *request)
179 {
181 
182  c = talloc_zero(NULL, rlm_cache_htrie_entry_t);
183  if (!c) {
184  RERROR("Failed allocating cache entry");
185  return NULL;
186  }
187 
188  return (rlm_cache_entry_t *)c;
189 }
190 
191 /** Locate a cache entry
192  *
193  * @note handle not used except for sanity checks.
194  *
195  * @copydetails cache_entry_find_t
196  */
198  UNUSED rlm_cache_config_t const *config, void *instance,
199  request_t *request, UNUSED void *handle, fr_value_box_t const *key)
200 {
201  rlm_cache_htrie_t *driver = talloc_get_type_abort(instance, rlm_cache_htrie_t);
202  rlm_cache_entry_t find = {};
203 
205 
206  fr_assert(driver->cache);
207 
208  /*
209  * Clear out old entries
210  */
211  c = fr_heap_peek(driver->heap);
212  if (c && (fr_unix_time_lt(c->expires, fr_time_to_unix_time(request->packet->timestamp)))) {
213  fr_heap_extract(&driver->heap, c);
214  fr_htrie_delete(driver->cache, c);
215  talloc_free(c);
216  }
217 
218  fr_value_box_copy_shallow(NULL, &find.key, key);
219 
220  /*
221  * Is there an entry for this key?
222  */
223  c = fr_htrie_find(driver->cache, &find);
224  if (!c) {
225  *out = NULL;
226  return CACHE_MISS;
227  }
228  *out = c;
229 
230  return CACHE_OK;
231 }
232 
233 /** Free an entry and remove it from the data store
234  *
235  * @note handle not used except for sanity checks.
236  *
237  * @copydetails cache_entry_expire_t
238  */
240  request_t *request, UNUSED void *handle,
241  fr_value_box_t const *key)
242 {
243  rlm_cache_htrie_t *driver = talloc_get_type_abort(instance, rlm_cache_htrie_t);
244  rlm_cache_entry_t find = {};
246 
247  if (!request) return CACHE_ERROR;
248 
249  fr_value_box_copy_shallow(NULL, &find.key, key);
250 
251  c = fr_htrie_find(driver->cache, &find);
252  if (!c) return CACHE_MISS;
253 
254  fr_heap_extract(&driver->heap, c);
255  fr_htrie_delete(driver->cache, c);
256  talloc_free(c);
257 
258  return CACHE_OK;
259 }
260 
261 /** Insert a new entry into the data store
262  *
263  * @note handle not used except for sanity checks.
264  *
265  * @copydetails cache_entry_insert_t
266  */
268  request_t *request, void *handle,
269  rlm_cache_entry_t const *c)
270 {
271  cache_status_t status;
272 
273  rlm_cache_htrie_t *driver = talloc_get_type_abort(instance, rlm_cache_htrie_t);
274 
275  fr_assert(handle == request);
276 
277  if (!request) return CACHE_ERROR;
278 
279  /*
280  * Allow overwriting
281  */
282  if (!fr_htrie_insert(driver->cache, c)) {
283  status = cache_entry_expire(config, instance, request, handle, &c->key);
284  if ((status != CACHE_OK) && !fr_cond_assert(0)) return CACHE_ERROR;
285 
286  if (!fr_htrie_insert(driver->cache, c)) {
287  RERROR("Failed adding entry");
288 
289  return CACHE_ERROR;
290  }
291  }
292 
293  if (fr_heap_insert(&driver->heap, UNCONST(rlm_cache_entry_t *, c)) < 0) {
294  fr_htrie_delete(driver->cache, c);
295  RERROR("Failed adding entry to expiry heap");
296 
297  return CACHE_ERROR;
298  }
299 
300  return CACHE_OK;
301 }
302 
303 /** Update the TTL of an entry
304  *
305  * @note handle not used except for sanity checks.
306  *
307  * @copydetails cache_entry_set_ttl_t
308  */
310  request_t *request, UNUSED void *handle,
312 {
313  rlm_cache_htrie_t *driver = talloc_get_type_abort(instance, rlm_cache_htrie_t);
314 
315 #ifdef NDEBUG
316  if (!request) return CACHE_ERROR;
317 #endif
318 
319  if (!fr_cond_assert(fr_heap_extract(&driver->heap, c) == 0)) {
320  RERROR("Entry not in heap");
321  return CACHE_ERROR;
322  }
323 
324  if (fr_heap_insert(&driver->heap, c) < 0) {
325  fr_htrie_delete(driver->cache, c); /* make sure we don't leak entries... */
326  RERROR("Failed updating entry TTL. Entry was forcefully expired");
327  return CACHE_ERROR;
328  }
329  return CACHE_OK;
330 }
331 
332 /** Return the number of entries in the cache
333  *
334  * @note handle not used except for sanity checks.
335  *
336  * @copydetails cache_entry_count_t
337  */
338 static uint64_t cache_entry_count(UNUSED rlm_cache_config_t const *config, void *instance,
339  request_t *request, UNUSED void *handle)
340 {
341  rlm_cache_htrie_t *driver = talloc_get_type_abort(instance, rlm_cache_htrie_t);
342 
343  if (!request) return CACHE_ERROR;
344 
345  return fr_htrie_num_elements(driver->cache);
346 }
347 
348 /** Lock the htrie
349  *
350  * @note handle not used except for sanity checks.
351  *
352  * @copydetails cache_acquire_t
353  */
354 static int cache_acquire(void **handle, UNUSED rlm_cache_config_t const *config, void *instance,
355  request_t *request)
356 {
357  rlm_cache_htrie_t *driver = talloc_get_type_abort(instance, rlm_cache_htrie_t);
358 
359  pthread_mutex_lock(&driver->mutex);
360 
361  *handle = request; /* handle is unused, this is just for sanity checking */
362 
363  RDEBUG3("Mutex acquired");
364 
365  return 0;
366 }
367 
368 /** Release an entry unlocking any mutexes
369  *
370  * @note handle not used except for sanity checks.
371  *
372  * @copydetails cache_release_t
373  */
374 static void cache_release(UNUSED rlm_cache_config_t const *config, void *instance, request_t *request,
375  UNUSED rlm_cache_handle_t *handle)
376 {
377  rlm_cache_htrie_t *driver = talloc_get_type_abort(instance, rlm_cache_htrie_t);
378 
379  pthread_mutex_unlock(&driver->mutex);
380 
381  RDEBUG3("Mutex released");
382 }
383 
384 /** Cleanup a cache_htrie instance
385  *
386  */
387 static int mod_detach(module_detach_ctx_t const *mctx)
388 {
389  rlm_cache_htrie_t *driver = talloc_get_type_abort(mctx->mi->data, rlm_cache_htrie_t);
390 
391  if (driver->cache) {
393  void *data;
394 
395  for (data = fr_rb_iter_init_inorder(&iter, driver->cache);
396  data;
399  talloc_free(data);
400  }
401  }
402 
403  pthread_mutex_destroy(&driver->mutex);
404 
405  return 0;
406 }
407 
408 /** Create a new cache_htrie instance
409  *
410  * @param[in] mctx Data required for instantiation.
411  * @return
412  * - 0 on success.
413  * - -1 on failure.
414  */
415 static int mod_instantiate(module_inst_ctx_t const *mctx)
416 {
417  rlm_cache_htrie_t *driver = talloc_get_type_abort(mctx->mi->data, rlm_cache_htrie_t);
418  int ret;
419 
420  /*
421  * The cache.
422  */
423  driver->cache = fr_htrie_alloc(driver, driver->htype,
427  if (!driver->cache) {
428  PERROR("Failed to create cache");
429  return -1;
430  }
431 
432  /*
433  * The heap of entries to expire.
434  */
435  driver->heap = fr_heap_talloc_alloc(driver, cache_heap_cmp, rlm_cache_htrie_entry_t, heap_id, 0);
436  if (!driver->heap) {
437  ERROR("Failed to create heap for the cache");
438  return -1;
439  }
440 
441  if ((ret = pthread_mutex_init(&driver->mutex, NULL)) < 0) {
442  ERROR("Failed initializing mutex: %s", fr_syserror(ret));
443  return -1;
444  }
445 
446  return 0;
447 }
448 
451  .common = {
452  .magic = MODULE_MAGIC_INIT,
453  .name = "cache_htrie",
454  .config = driver_config,
455  .instantiate = mod_instantiate,
456  .detach = mod_detach,
457  .inst_size = sizeof(rlm_cache_htrie_t),
458  .inst_type = "rlm_cache_htrie_t",
459  },
460  .alloc = cache_entry_alloc,
461 
462  .find = cache_entry_find,
463  .insert = cache_entry_insert,
464  .expire = cache_entry_expire,
465  .set_ttl = cache_entry_set_ttl,
466  .count = cache_entry_count,
467 
468  .acquire = cache_acquire,
469  .release = cache_release,
470 
471  .key_parse = cf_htrie_key_parse
472 };
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition: build.h:165
#define unlikely(_x)
Definition: build.h:379
#define UNUSED
Definition: build.h:313
int call_env_parse_pair(TALLOC_CTX *ctx, void *out, tmpl_rules_t const *t_rules, CONF_ITEM *ci, UNUSED call_env_ctx_t const *cec, UNUSED call_env_parser_t const *rule)
Standard function we use for parsing call env pairs.
Definition: call_env.c:375
Per method call config.
Definition: call_env.h:175
int cf_table_parse_int(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
Generic function for parsing conf pair values as int.
Definition: cf_parse.c:1474
API to parse internal format configuration items into native C types.
#define CONF_PARSER_TERMINATOR
Definition: cf_parse.h:627
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition: cf_parse.h:268
Defines a CONF_PAIR to C data type mapping.
Definition: cf_parse.h:564
Common header for all CONF_* types.
Definition: cf_priv.h:49
#define cf_log_err(_cf, _fmt,...)
Definition: cf_util.h:289
#define cf_log_info(_cf, _fmt,...)
Definition: cf_util.h:291
fr_dcursor_iter_t iter
Definition: dcursor.h:147
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition: debug.h:139
#define ERROR(fmt,...)
Definition: dhcpclient.c:41
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition: dl_module.h:63
uint32_t(* fr_hash_t)(void const *)
Definition: hash.h:36
int fr_heap_insert(fr_heap_t **hp, void *data)
Insert a new element into the heap.
Definition: heap.c:146
int fr_heap_extract(fr_heap_t **hp, void *data)
Remove a node from the heap.
Definition: heap.c:239
unsigned int fr_heap_index_t
Definition: heap.h:80
static void * fr_heap_peek(fr_heap_t *h)
Return the item from the top of the heap but don't pop it.
Definition: heap.h:136
#define fr_heap_talloc_alloc(_ctx, _cmp, _talloc_type, _field, _init)
Creates a heap that verifies elements are of a specific talloc type.
Definition: heap.h:115
The main heap structure.
Definition: heap.h:66
size_t fr_htrie_type_table_len
Definition: htrie.c:37
fr_htrie_t * fr_htrie_alloc(TALLOC_CTX *ctx, fr_htrie_type_t type, fr_hash_t hash_data, fr_cmp_t cmp_data, fr_trie_key_t get_key, fr_free_t free_data)
An abstraction over our internal hashes, rb trees, and prefix tries.
Definition: htrie.c:92
fr_table_num_sorted_t const fr_htrie_type_table[]
Definition: htrie.c:31
fr_htrie_type_t
Definition: htrie.h:49
@ FR_HTRIE_AUTO
Automatically choose the best type.
Definition: htrie.h:54
@ FR_HTRIE_INVALID
Definition: htrie.h:50
static fr_htrie_type_t fr_htrie_hint(fr_type_t type)
Definition: htrie.h:149
static bool fr_htrie_insert(fr_htrie_t *ht, void const *data)
Insert data into a htrie.
Definition: htrie.h:112
static int fr_htrie_num_elements(fr_htrie_t *ht)
Return the number of elements in the htrie.
Definition: htrie.h:144
static bool fr_htrie_delete(fr_htrie_t *ht, void const *data)
Delete data from a htrie, freeing it if free_data cb was passed to fr_htrie_alloc.
Definition: htrie.h:136
static void * fr_htrie_find(fr_htrie_t *ht, void const *data)
Find data in a htrie.
Definition: htrie.h:104
static char const * fr_htrie_type_to_str(fr_htrie_type_t type)
Return a static string containing the type name.
Definition: htrie.h:185
A hash/rb/prefix trie abstraction.
Definition: htrie.h:80
#define PERROR(_fmt,...)
Definition: log.h:228
#define RDEBUG3(fmt,...)
Definition: log.h:343
#define RERROR(fmt,...)
Definition: log.h:298
talloc_free(reap)
fr_type_t
Definition: merged_model.c:80
int8_t(* fr_cmp_t)(void const *a, void const *b)
Definition: misc.h:38
module_instance_t * mi
Module instance to detach.
Definition: module_ctx.h:57
module_instance_t * mi
Instance of the module being instantiated.
Definition: module_ctx.h:51
Temporary structure to hold arguments for detach calls.
Definition: module_ctx.h:56
Temporary structure to hold arguments for instantiation calls.
Definition: module_ctx.h:50
static const conf_parser_t config[]
Definition: base.c:183
void fr_rb_iter_delete_inorder(fr_rb_iter_inorder_t *iter)
Remove the current node from the tree.
Definition: rb.c:898
void * fr_rb_iter_next_inorder(fr_rb_iter_inorder_t *iter)
Return the next node.
Definition: rb.c:850
void * fr_rb_iter_init_inorder(fr_rb_iter_inorder_t *iter, fr_rb_tree_t *tree)
Initialise an in-order iterator.
Definition: rb.c:824
Iterator structure for in-order traversal of an rbtree.
Definition: rb.h:321
fr_value_box_t key
Key used to identify entry.
Definition: rlm_cache.h:73
module_t common
Common fields for all loadable modules.
Definition: rlm_cache.h:258
cache_status_t
Definition: rlm_cache.h:39
@ CACHE_ERROR
Fatal error.
Definition: rlm_cache.h:41
@ CACHE_OK
Cache entry found/updated.
Definition: rlm_cache.h:42
@ CACHE_MISS
Cache entry notfound.
Definition: rlm_cache.h:43
void rlm_cache_handle_t
Definition: rlm_cache.h:35
fr_unix_time_t expires
When the entry expires.
Definition: rlm_cache.h:76
Configuration for the rlm_cache module.
Definition: rlm_cache.h:51
Definition: rlm_cache.h:72
static int mod_detach(module_detach_ctx_t const *mctx)
Cleanup a cache_htrie instance.
bool htrie_auto
Whether the user wanted to automatically configure the htrie.
static int cf_htrie_type_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
Custom htrie type parsing function.
static int cf_htrie_key_parse(TALLOC_CTX *ctx, void *out, tmpl_rules_t const *t_rules, CONF_ITEM *ci, void const *data, UNUSED call_env_parser_t const *rule)
Custom key parsing function for checking compatibility of key types.
rlm_cache_entry_t fields
Entry data.
static conf_parser_t driver_config[]
static uint64_t cache_entry_count(UNUSED rlm_cache_config_t const *config, void *instance, request_t *request, UNUSED void *handle)
Return the number of entries in the cache.
static int cache_acquire(void **handle, UNUSED rlm_cache_config_t const *config, void *instance, request_t *request)
Lock the htrie.
fr_htrie_t * cache
Tree for looking up cache keys.
static void cache_release(UNUSED rlm_cache_config_t const *config, void *instance, request_t *request, UNUSED rlm_cache_handle_t *handle)
Release an entry unlocking any mutexes.
rlm_cache_driver_t rlm_cache_htrie
static int8_t cache_heap_cmp(void const *one, void const *two)
Compare two entries by expiry time.
static cache_status_t cache_entry_expire(UNUSED rlm_cache_config_t const *config, void *instance, request_t *request, UNUSED void *handle, fr_value_box_t const *key)
Free an entry and remove it from the data store.
static cache_status_t cache_entry_find(rlm_cache_entry_t **out, UNUSED rlm_cache_config_t const *config, void *instance, request_t *request, UNUSED void *handle, fr_value_box_t const *key)
Locate a cache entry.
pthread_mutex_t mutex
Protect the tree from multiple readers/writers.
fr_heap_index_t heap_id
Offset used for expiry heap.
static cache_status_t cache_entry_set_ttl(UNUSED rlm_cache_config_t const *config, void *instance, request_t *request, UNUSED void *handle, rlm_cache_entry_t *c)
Update the TTL of an entry.
static int mod_instantiate(module_inst_ctx_t const *mctx)
Create a new cache_htrie instance.
static cache_status_t cache_entry_insert(rlm_cache_config_t const *config, void *instance, request_t *request, void *handle, rlm_cache_entry_t const *c)
Insert a new entry into the data store.
fr_heap_t * heap
For managing entry expiry.
fr_htrie_type_t htype
The htrie type we'll be using.
static rlm_cache_entry_t * cache_entry_alloc(UNUSED rlm_cache_config_t const *config, UNUSED void *instance, request_t *request)
Custom allocation function for the driver.
fr_type_t ktype
When htrie is "auto", we use this type to decide what type of tree to use.
void * data
Module's instance data.
Definition: module.h:271
Structures and prototypes for templates.
fr_type_t tmpl_expanded_type(tmpl_t const *vpt)
Return the native data type of the expression.
Definition: tmpl_eval.c:209
Optional arguments passed to vp_tmpl functions.
Definition: tmpl.h:341
fr_assert(0)
eap_aka_sim_process_conf_t * inst
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition: syserror.c:243
#define talloc_get_type_abort_const
Definition: talloc.h:282
static int8_t fr_unix_time_cmp(fr_unix_time_t a, fr_unix_time_t b)
Compare two fr_unix_time_t values.
Definition: time.h:944
static fr_unix_time_t fr_time_to_unix_time(fr_time_t when)
Convert an fr_time_t (internal time) to our version of unix time (wallclock time)
Definition: time.h:688
#define fr_unix_time_lt(_a, _b)
Definition: time.h:367
int(* fr_trie_key_t)(uint8_t **out, size_t *outlen, void const *data)
Definition: trie.h:56
static fr_slen_t parent
Definition: pair.h:851
bool fr_type_cast(fr_type_t dst, fr_type_t src)
Return if we're allowed to cast the types.
Definition: types.c:283
fr_type_t fr_type_promote(fr_type_t a, fr_type_t b)
Return the promoted type.
Definition: types.c:572
Types of values contained within an fr_value_box_t.
#define fr_type_is_void(_x)
Definition: types.h:357
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition: types.h:433
uint32_t fr_value_box_hash(fr_value_box_t const *vb)
Hash the contents of a value box.
Definition: value.c:6129
int8_t fr_value_box_cmp(fr_value_box_t const *a, fr_value_box_t const *b)
Compare two values.
Definition: value.c:676
void fr_value_box_copy_shallow(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *src)
Perform a shallow copy of a value_box.
Definition: value.c:3834
int fr_value_box_to_key(uint8_t **out, size_t *outlen, fr_value_box_t const *value)
Get a key from a value box.
Definition: value.c:2084
static fr_slen_t data
Definition: value.h:1265
static size_t char ** out
Definition: value.h:997