The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
rlm_interval.c
Go to the documentation of this file.
1/*
2 * This program 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
5 * (at 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: 1a042ab5071847a64ce19818a0748b60dcb2dfad $
19 * @file rlm_interval.c
20 * @brief Interval limiting module providing an xlat function.
21 *
22 * @copyright 2026 The FreeRADIUS server project
23 * @copyright 2026 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
24 */
25
26RCSID("$Id: 1a042ab5071847a64ce19818a0748b60dcb2dfad $")
27
28#include <freeradius-devel/server/base.h>
29#include <freeradius-devel/server/main_loop.h>
30#include <freeradius-devel/server/module_rlm.h>
31#include <freeradius-devel/unlang/xlat_func.h>
32#include <freeradius-devel/util/rb.h>
33#include <freeradius-devel/util/slab.h>
34#include <freeradius-devel/util/timer.h>
35#include <freeradius-devel/util/debug.h>
36#include <freeradius-devel/util/strerror.h>
37
38#include <pthread.h>
39
44
46 { L("global"), INTERVAL_SCOPE_GLOBAL },
47 { L("thread"), INTERVAL_SCOPE_THREAD }
48};
50
51/** RBTree entry for keyed lookups
52 */
53typedef struct {
54 fr_rb_node_t node; //!< RBTree node.
55 fr_value_box_t key; //!< Key stored in value box.
56 fr_timer_t *ev; //!< Expiry timer.
57 void *owner; //!< Back-pointer to mutable_t or thread_t.
59
62
63/** Mutable data for global scope (allocated outside mprotected instance data)
64 */
65typedef struct {
66 fr_rb_tree_t *tree; //!< RBTree for keyed lookups.
67 pthread_mutex_t mutex; //!< Mutex for thread safety.
69
70/** Module instance data
71 */
72typedef struct {
73 rlm_interval_scope_t scope; //!< Global or thread-local scope.
74 fr_slab_config_t reuse; //!< Slab allocator configuration.
75 rlm_interval_mutable_t *mutable; //!< Mutable data for global scope.
77
78/** Module thread instance data
79 */
80typedef struct {
81 fr_rb_tree_t *tree; //!< RBTree for keyed lookups (thread scope only).
82 fr_timer_list_t *tl; //!< Timer list for entry expiry.
83 interval_slab_list_t *slab; //!< Slab allocator for entries.
85
86/** Xlat instance data - stores the xlat expression pointer for keyless lookups
87 */
88typedef struct {
89 xlat_exp_t const *ex; //!< Cached for keyless lookups.
91
92/** Xlat thread instance data - stores last_used for keyless thread-scope lookups
93 */
94typedef struct {
95 fr_time_t last_used; //!< Last used time for this call site.
97
102
103static const conf_parser_t module_config[] = {
104 { FR_CONF_OFFSET("scope", rlm_interval_t, scope),
107 .dflt = "global" },
110};
111
113 { .required = true, .single = true, .type = FR_TYPE_TIME_DELTA },
114 { .single = true, .type = FR_TYPE_STRING },
116};
117
118static int8_t interval_entry_cmp(void const *one, void const *two)
119{
120 rlm_interval_entry_t const *a = one;
121 rlm_interval_entry_t const *b = two;
122 int8_t ret;
123
124 ret = CMP(a->key.type, b->key.type);
125 if (ret != 0) return ret;
126
127 return fr_value_box_cmp(&a->key, &b->key);
128}
129
130/** Timer callback to expire entries (thread scope)
131 */
133{
134 rlm_interval_entry_t *entry = uctx;
135 rlm_interval_thread_t *thread = talloc_get_type_abort(entry->owner, rlm_interval_thread_t);
136
137 (void)fr_rb_delete_by_inline_node(thread->tree, &entry->node);
138 interval_slab_release(entry);
139}
140
141/** Timer callback to expire entries (global scope)
142 */
144{
145 rlm_interval_entry_t *entry = uctx;
146 rlm_interval_mutable_t *mutable = talloc_get_type_abort(entry->owner, rlm_interval_mutable_t);
147
148 pthread_mutex_lock(&mutable->mutex);
149 (void)fr_rb_delete_by_inline_node(mutable->tree, &entry->node);
150 pthread_mutex_unlock(&mutable->mutex);
151
152 interval_slab_release(entry);
153}
154
155/** Check interval limit
156 *
157 * @note Don't be tempted to move mutex handling in here. Yes you could probably reduce
158 * the size of the critical region, but you're going to break something and miss
159 * interaction effects. Just don't do it.
160 *
161 * @param[in] tree RBTree for lookups.
162 * @param[in] thread Thread instance (for timer list and slab).
163 * @param[in] owner Back-pointer to store in new entries (for expiry callback).
164 * @param[in] expire Expiry callback function.
165 * @param[in] find Entry with key to search for.
166 * @param[in] interval Interval limit interval.
167 * @return
168 * - 1 if allowed.
169 * - 0 if interval limited.
170 * - -1 on error.
171 */
173 void *owner, fr_timer_cb_t expire,
175{
177
178 entry = fr_rb_find(tree, find);
179 if (!entry) {
180 entry = interval_slab_reserve(thread->slab);
181 if (!entry) return -1;
182
183 fr_value_box_copy_shallow(entry, &entry->key, &find->key);
184
185 entry->owner = owner;
186
187 if (unlikely(fr_rb_insert(tree, entry) == false)) {
188 fr_strerror_const("Insertion failed - duplicate key?");
189 error:
190 interval_slab_release(entry);
191 return -1;
192 }
193
194 if (unlikely(fr_timer_in(entry, thread->tl, &entry->ev, interval, true, expire, entry) < 0)) goto error;
195 return 1;
196 }
197
198 /*
199 * Entry exists - check if interval limited.
200 * Timer loop doesn't run immediately, so check the scheduled
201 * fire time rather than just whether it's armed.
202 */
203 if (fr_timer_armed(entry->ev) && fr_time_gt(fr_timer_when(entry->ev), fr_time())) return 0;
204
205 /*
206 * Timer expired (or wasn't set), reset it
207 */
208 if (unlikely(fr_timer_in(entry, thread->tl, &entry->ev, interval, true, expire, entry) < 0)) {
209 fr_rb_delete(tree, entry);
210 return -1;
211 }
212
213 return 1;
214}
215
216/** Global scope xlat - always uses mutex-protected tree
217 */
219 xlat_ctx_t const *xctx,
220 request_t *request, fr_value_box_list_t *in)
221{
223 rlm_interval_thread_t *thread = talloc_get_type_abort(xctx->mctx->thread, rlm_interval_thread_t);
224 rlm_interval_xlat_inst_t const *xlat_inst = xctx->inst;
225
226 fr_value_box_t *interval, *key, *result;
227 rlm_interval_entry_t find = {};
228 int ret;
229
230 XLAT_ARGS(in, &interval, &key);
231
232 /*
233 * Set up the find key - either string key or xlat expression pointer
234 */
235 if (!key) {
236 fr_value_box_set_void_shallow(&find.key, xlat_inst->ex);
237 } else {
238 fr_value_box_copy_shallow(NULL, &find.key, key);
239 }
240
241 pthread_mutex_lock(&inst->mutable->mutex);
242 ret = interval_check(inst->mutable->tree, thread, inst->mutable, interval_expire_global,
243 &find, interval->vb_time_delta);
244 pthread_mutex_unlock(&inst->mutable->mutex);
245
246 MEM(result = fr_value_box_alloc(ctx, FR_TYPE_BOOL, NULL));
247 switch (ret) {
248 case 1:
249 RDEBUG3("Interval passed");
250 result->vb_bool = true;
251 break;
252
253 case 0:
254 RDEBUG3("Within interval");
255 result->vb_bool = false;
256 break;
257
258 default:
259 fr_assert_msg(false, "interval_check failed in global scope xlat: %s", fr_strerror());
260 result->vb_bool = true; /* Allow on error */
261 break;
262 }
263
264 fr_dcursor_append(out, result);
265 return XLAT_ACTION_DONE;
266}
267
268/** Thread scope xlat - uses thread-local tree or module thread instance
269 */
271 xlat_ctx_t const *xctx,
272 request_t *request, fr_value_box_list_t *in)
273{
274 rlm_interval_thread_t *thread = talloc_get_type_abort(xctx->mctx->thread, rlm_interval_thread_t);
275 rlm_interval_xlat_thread_inst_t *xlat_thread = xctx->thread;
276
277 fr_value_box_t *interval, *key, *result;
278 int ret;
279
280 XLAT_ARGS(in, &interval, &key);
281
282 if (!key) {
283 /*
284 * Keyless: use xlat thread instance directly - no tree lookup needed
285 */
286 fr_time_t now = fr_time();
287
288 if (fr_time_gt(fr_time_add(xlat_thread->last_used, interval->vb_time_delta), now)) {
289 ret = 0;
290 } else {
291 xlat_thread->last_used = now;
292 ret = 1;
293 }
294 } else {
295 /*
296 * Keyed: use thread-local tree
297 */
298 rlm_interval_entry_t find = {};
299
300 fr_value_box_copy_shallow(NULL, &find.key, key);
301
302 ret = interval_check(thread->tree, thread, thread, interval_expire_thread,
303 &find, interval->vb_time_delta);
304 }
305
306 MEM(result = fr_value_box_alloc(ctx, FR_TYPE_BOOL, NULL));
307
308 switch (ret) {
309 case 1:
310 RDEBUG3("Interval passed");
311 result->vb_bool = true;
312 break;
313
314 case 0:
315 RDEBUG3("Within interval");
316 result->vb_bool = false;
317 break;
318
319 default:
320 fr_assert_msg(false, "interval_check failed in thread scope xlat: %s", fr_strerror());
321 result->vb_bool = true; /* Allow on error */
322 break;
323 }
324
325 fr_dcursor_append(out, result);
326 return XLAT_ACTION_DONE;
327}
328
330{
331 rlm_interval_xlat_inst_t *xlat_inst = xctx->inst;
332
333 xlat_inst->ex = xctx->ex;
334 return 0;
335}
336
338{
339 rlm_interval_xlat_thread_inst_t *xlat_thread = xctx->thread;
340
341 /*
342 * Initialize to "never used" so first check always allows.
343 * fr_time() is relative to server start, not Unix epoch.
344 */
345 xlat_thread->last_used = fr_time_min();
346 return 0;
347}
348
350{
351 rlm_interval_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_interval_t);
352 rlm_interval_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_interval_thread_t);
353
354 /*
355 * Always need a thread-local timer list and slab, even for global scope,
356 * because timer lists and talloc aren't thread-safe.
357 *
358 * Use lst (heap) not ordered (dlist) because timers aren't
359 * inserted in chronological order.
360 */
361 t->tl = fr_timer_list_lst_alloc(t, mctx->el->tl);
362 if (!t->tl) {
363 ERROR("Failed to create thread-local timer list");
364 return -1;
365 }
366
367 t->slab = interval_slab_list_alloc(t, mctx->el, &inst->reuse,
368 NULL, NULL, NULL,
369 true, false);
370 if (!t->slab) {
371 ERROR("Failed to create thread-local slab allocator");
372 return -1;
373 }
374
375 if (inst->scope == INTERVAL_SCOPE_THREAD) {
377 interval_entry_cmp, NULL);
378 if (!t->tree) {
379 ERROR("Failed to create thread-local rbtree");
380 return -1;
381 }
382 }
383
384 return 0;
385}
386
387static int mod_detach(module_detach_ctx_t const *mctx)
388{
389 rlm_interval_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_interval_t);
390
391 if (inst->mutable) {
392 pthread_mutex_destroy(&inst->mutable->mutex);
393 talloc_free(inst->mutable);
394 }
395
396 return 0;
397}
398
399static int mod_instantiate(module_inst_ctx_t const *mctx)
400{
401 rlm_interval_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_interval_t);
402
403 if (inst->scope == INTERVAL_SCOPE_GLOBAL) {
404 MEM(inst->mutable = talloc_zero(NULL, rlm_interval_mutable_t));
405
406 inst->mutable->tree = fr_rb_inline_talloc_alloc(inst->mutable, rlm_interval_entry_t, node,
407 interval_entry_cmp, NULL);
408 if (!inst->mutable->tree) {
409 ERROR("Failed to create rbtree");
410 talloc_free(inst->mutable);
411 return -1;
412 }
413
414 MEM(pthread_mutex_init(&inst->mutable->mutex, NULL) == 0);
415 }
416
417 return 0;
418}
419
420static int mod_bootstrap(module_inst_ctx_t const *mctx)
421{
422 rlm_interval_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_interval_t);
423 xlat_t *xlat;
424
425 /*
426 * Register scope-specific xlat function
427 */
428 switch (inst->scope) {
431 if (!xlat) {
432 registration_error:
433 ERROR("Failed to register xlat function");
434 return -1;
435 }
436 break;
437
440 if (!xlat) goto registration_error;
441 if (xlat) {
444 }
445 break;
446 }
447
450
451 return 0;
452}
453
456 .common = {
457 .magic = MODULE_MAGIC_INIT,
458 .name = "interval",
459 .inst_size = sizeof(rlm_interval_t),
460 .thread_inst_size = sizeof(rlm_interval_thread_t),
461 .config = module_config,
462 .bootstrap = mod_bootstrap,
463 .instantiate = mod_instantiate,
464 .detach = mod_detach,
465 .thread_instantiate = mod_thread_instantiate,
466 }
467};
#define RCSID(id)
Definition build.h:487
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:209
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
Definition build.h:112
#define unlikely(_x)
Definition build.h:383
#define UNUSED
Definition build.h:317
#define NUM_ELEMENTS(_t)
Definition build.h:339
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:1624
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:660
cf_parse_t func
Override default parsing behaviour for the specified type with a custom parsing function.
Definition cf_parse.h:614
#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:283
#define FR_CONF_OFFSET_SUBSECTION(_name, _flags, _struct, _field, _subcs)
conf_parser_t which populates a sub-struct using a CONF_SECTION
Definition cf_parse.h:312
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:597
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
Definition dcursor.h:408
#define fr_assert_msg(_x, _msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition debug.h:202
#define MEM(x)
Definition debug.h:36
#define ERROR(fmt,...)
Definition dhcpclient.c:41
static fr_slen_t in
Definition dict.h:884
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
talloc_free(hp)
#define RDEBUG3(fmt,...)
Definition log.h:343
@ FR_TYPE_TIME_DELTA
A period of time measured in nanoseconds.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_BOOL
A truth value.
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:42
void * thread
Thread specific instance data.
Definition module_ctx.h:43
fr_event_list_t * el
Event list to register any IO handlers and timers against.
Definition module_ctx.h:68
module_instance_t * mi
Module instance to detach.
Definition module_ctx.h:57
void * thread
Thread instance data.
Definition module_ctx.h:67
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:64
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
Temporary structure to hold arguments for thread_instantiation calls.
Definition module_ctx.h:63
xlat_t * module_rlm_xlat_register(TALLOC_CTX *ctx, module_inst_ctx_t const *mctx, char const *name, xlat_func_t func, fr_type_t return_type)
Definition module_rlm.c:247
module_t common
Common fields presented by all modules.
Definition module_rlm.h:39
bool fr_rb_delete_by_inline_node(fr_rb_tree_t *tree, fr_rb_node_t *node)
Remove node and free data (if a free function was specified)
Definition rb.c:767
void * fr_rb_find(fr_rb_tree_t const *tree, void const *data)
Find an element in the tree, returning the data, not the node.
Definition rb.c:577
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
Definition rb.c:626
bool fr_rb_delete(fr_rb_tree_t *tree, void const *data)
Remove node and free data (if a free function was specified)
Definition rb.c:741
#define fr_rb_inline_talloc_alloc(_ctx, _type, _field, _data_cmp, _data_free)
Allocs a red black that verifies elements are of a specific talloc type.
Definition rb.h:246
The main red black tree structure.
Definition rb.h:73
static void interval_expire_thread(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *uctx)
Timer callback to expire entries (thread scope)
rlm_interval_scope_t
@ INTERVAL_SCOPE_GLOBAL
@ INTERVAL_SCOPE_THREAD
static int mod_detach(module_detach_ctx_t const *mctx)
static xlat_arg_parser_t const interval_xlat_args[]
fr_rb_tree_t * tree
RBTree for keyed lookups (thread scope only).
interval_slab_list_t * slab
Slab allocator for entries.
xlat_exp_t const * ex
Cached for keyless lookups.
static int interval_xlat_instantiate(xlat_inst_ctx_t const *xctx)
fr_value_box_t key
Key stored in value box.
module_rlm_t rlm_interval
fr_time_t last_used
Last used time for this call site.
rlm_interval_scope_t scope
Global or thread-local scope.
static xlat_action_t interval_xlat_global(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Global scope xlat - always uses mutex-protected tree.
static int mod_bootstrap(module_inst_ctx_t const *mctx)
fr_timer_t * ev
Expiry timer.
fr_timer_list_t * tl
Timer list for entry expiry.
static conf_parser_t reuse_config[]
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
static fr_table_num_sorted_t const interval_scope_table[]
static void interval_expire_global(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *uctx)
Timer callback to expire entries (global scope)
fr_rb_tree_t * tree
RBTree for keyed lookups.
pthread_mutex_t mutex
Mutex for thread safety.
static int8_t interval_entry_cmp(void const *one, void const *two)
static const conf_parser_t module_config[]
static size_t interval_scope_table_len
static xlat_action_t interval_xlat_thread(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Thread scope xlat - uses thread-local tree or module thread instance.
fr_slab_config_t reuse
Slab allocator configuration.
fr_rb_node_t node
RBTree node.
static int mod_instantiate(module_inst_ctx_t const *mctx)
static int interval_xlat_thread_instantiate(xlat_thread_inst_ctx_t const *xctx)
void * owner
Back-pointer to mutable_t or thread_t.
static int interval_check(fr_rb_tree_t *tree, rlm_interval_thread_t *thread, void *owner, fr_timer_cb_t expire, rlm_interval_entry_t *find, fr_time_delta_t interval)
Check interval limit.
RBTree entry for keyed lookups.
Mutable data for global scope (allocated outside mprotected instance data)
Module instance data.
Module thread instance data.
Xlat instance data - stores the xlat expression pointer for keyless lookups.
Xlat thread instance data - stores last_used for keyless thread-scope lookups.
size_t inst_size
Size of the module's instance data.
Definition module.h:212
void * data
Module's instance data.
Definition module.h:291
void * boot
Data allocated during the boostrap phase.
Definition module.h:294
#define FR_SLAB_FUNCS(_name, _type)
Define type specific wrapper functions for slabs and slab elements.
Definition slab.h:120
#define FR_SLAB_TYPES(_name, _type)
Define type specific wrapper structs for slabs and slab elements.
Definition slab.h:72
#define FR_SLAB_CONFIG_CONF_PARSER
conf_parser_t entries to populate user configurable slab values
Definition slab.h:35
Tuneable parameters for slabs.
Definition slab.h:42
eap_aka_sim_process_conf_t * inst
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition state_test.c:8
An element in a lexicographically sorted array of name to num mappings.
Definition table.h:49
#define talloc_get_type_abort_const
Definition talloc.h:245
#define fr_time_min()
Definition time.h:144
#define fr_time_add(_a, _b)
Add a time/time delta together.
Definition time.h:196
#define fr_time_gt(_a, _b)
Definition time.h:237
A time delta, a difference in time measured in nanoseconds.
Definition time.h:80
"server local" time.
Definition time.h:69
fr_time_t fr_timer_when(fr_timer_t *ev)
Internal timestamp representing when the timer should fire.
Definition timer.c:720
fr_timer_list_t * fr_timer_list_lst_alloc(TALLOC_CTX *ctx, fr_timer_list_t *parent)
Allocate a new lst based timer list.
Definition timer.c:1263
An event timer list.
Definition timer.c:50
A timer event.
Definition timer.c:84
#define fr_timer_in(...)
Definition timer.h:87
void(* fr_timer_cb_t)(fr_timer_list_t *tl, fr_time_t now, void *uctx)
Called when a timer event fires.
Definition timer.h:75
static bool fr_timer_armed(fr_timer_t *ev)
Definition timer.h:120
#define XLAT_ARGS(_list,...)
Populate local variables with value boxes from the input list.
Definition xlat.h:383
unsigned int required
Argument must be present, and non-empty.
Definition xlat.h:146
#define XLAT_ARG_PARSER_TERMINATOR
Definition xlat.h:170
xlat_action_t
Definition xlat.h:37
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
Definition xlat.h:43
Definition for a single argument consumend by an xlat function.
Definition xlat.h:145
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:553
#define fr_strerror_const(_msg)
Definition strerror.h:223
void fr_value_box_set_void_shallow(fr_value_box_t *dst, void const *ptr)
Assign a void pointer to a box.
Definition value.c:5224
int8_t fr_value_box_cmp(fr_value_box_t const *a, fr_value_box_t const *b)
Compare two values.
Definition value.c:749
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:4535
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition value.h:644
static size_t char ** out
Definition value.h:1024
void * thread
xlat threadinstance data.
Definition xlat_ctx.h:51
xlat_exp_t * ex
Tokenized expression to use in expansion.
Definition xlat_ctx.h:64
void const * inst
xlat instance data.
Definition xlat_ctx.h:50
void * thread
xlat thread instance data to populate.
Definition xlat_ctx.h:75
module_ctx_t const * mctx
Synthesised module calling ctx.
Definition xlat_ctx.h:52
void * inst
xlat instance data to populate.
Definition xlat_ctx.h:63
An xlat calling ctx.
Definition xlat_ctx.h:49
An xlat instantiation ctx.
Definition xlat_ctx.h:62
An xlat thread instantiation ctx.
Definition xlat_ctx.h:73
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.
Definition xlat_func.c:363
#define xlat_func_instantiate_set(_xlat, _instantiate, _inst_struct, _detach, _uctx)
Set a callback for global instantiation of xlat functions.
Definition xlat_func.h:93
#define xlat_func_thread_instantiate_set(_xlat, _instantiate, _inst_struct, _detach, _uctx)
Set a callback for thread-specific instantiation of xlat functions.
Definition xlat_func.h:108
An xlat expansion node.
Definition xlat_priv.h:148