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: b2da275c7c40f314ccdf1fb9eb0c5f53363b04e4 $
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: b2da275c7c40f314ccdf1fb9eb0c5f53363b04e4 $")
27
28#include <freeradius-devel/server/base.h>
29#include <freeradius-devel/server/module_rlm.h>
30#include <freeradius-devel/unlang/xlat_func.h>
31#include <freeradius-devel/util/slab.h>
32#include <freeradius-devel/util/timer.h>
33#include <freeradius-devel/util/debug.h>
34#include <freeradius-devel/util/strerror.h>
35
36#include <pthread.h>
37
42
44 { L("global"), INTERVAL_SCOPE_GLOBAL },
45 { L("thread"), INTERVAL_SCOPE_THREAD }
46};
48
49/** RBTree entry for keyed lookups
50 */
51typedef struct {
52 fr_rb_node_t node; //!< RBTree node.
53 fr_value_box_t key; //!< Key stored in value box.
54 fr_timer_t *ev; //!< Expiry timer.
55 void *owner; //!< Back-pointer to mutable_t or thread_t.
57
60
61/** Mutable data for global scope (allocated outside mprotected instance data)
62 */
63typedef struct {
64 fr_rb_tree_t *tree; //!< RBTree for keyed lookups.
65 pthread_mutex_t mutex; //!< Mutex for thread safety.
67
68/** Module instance data
69 */
70typedef struct {
71 rlm_interval_scope_t scope; //!< Global or thread-local scope.
72 fr_slab_config_t reuse; //!< Slab allocator configuration.
73 rlm_interval_mutable_t *mutable; //!< Mutable data for global scope.
75
76/** Module thread instance data
77 */
78typedef struct {
79 fr_rb_tree_t *tree; //!< RBTree for keyed lookups (thread scope only).
80 fr_timer_list_t *tl; //!< Timer list for entry expiry.
81 interval_slab_list_t *slab; //!< Slab allocator for entries.
83
84/** Xlat instance data - stores the xlat expression pointer for keyless lookups
85 */
86typedef struct {
87 xlat_exp_t const *ex; //!< Cached for keyless lookups.
89
90/** Xlat thread instance data - stores last_used for keyless thread-scope lookups
91 */
92typedef struct {
93 fr_time_t last_used; //!< Last used time for this call site.
95
100
101static const conf_parser_t module_config[] = {
102 { FR_CONF_OFFSET("scope", rlm_interval_t, scope),
105 .dflt = "global" },
108};
109
111 { .required = true, .single = true, .type = FR_TYPE_TIME_DELTA },
112 { .single = true, .type = FR_TYPE_STRING },
114};
115
116static int8_t interval_entry_cmp(void const *one, void const *two)
117{
118 rlm_interval_entry_t const *a = one;
119 rlm_interval_entry_t const *b = two;
120 int8_t ret;
121
122 ret = CMP(a->key.type, b->key.type);
123 if (ret != 0) return ret;
124
125 return fr_value_box_cmp(&a->key, &b->key);
126}
127
128/** Timer callback to expire entries (thread scope)
129 */
131{
132 rlm_interval_entry_t *entry = uctx;
133 rlm_interval_thread_t *thread = talloc_get_type_abort(entry->owner, rlm_interval_thread_t);
134
135 (void)fr_rb_delete_by_inline_node(thread->tree, &entry->node);
136 interval_slab_release(entry);
137}
138
139/** Timer callback to expire entries (global scope)
140 */
142{
143 rlm_interval_entry_t *entry = uctx;
144 rlm_interval_mutable_t *mutable = talloc_get_type_abort(entry->owner, rlm_interval_mutable_t);
145
146 pthread_mutex_lock(&mutable->mutex);
147 (void)fr_rb_delete_by_inline_node(mutable->tree, &entry->node);
148 pthread_mutex_unlock(&mutable->mutex);
149
150 interval_slab_release(entry);
151}
152
153/** Check interval limit
154 *
155 * @note Don't be tempted to move mutex handling in here. Yes you could probably reduce
156 * the size of the critical region, but you're going to break something and miss
157 * interaction effects. Just don't do it.
158 *
159 * @param[in] tree RBTree for lookups.
160 * @param[in] thread Thread instance (for timer list and slab).
161 * @param[in] owner Back-pointer to store in new entries (for expiry callback).
162 * @param[in] expire Expiry callback function.
163 * @param[in] find Entry with key to search for.
164 * @param[in] interval Interval limit interval.
165 * @return
166 * - 1 if allowed.
167 * - 0 if interval limited.
168 * - -1 on error.
169 */
171 void *owner, fr_timer_cb_t expire,
173{
175
176 entry = fr_rb_find(tree, find);
177 if (!entry) {
178 entry = interval_slab_reserve(thread->slab);
179 if (!entry) return -1;
180
181 fr_value_box_copy_shallow(entry, &entry->key, &find->key);
182
183 entry->owner = owner;
184
185 if (unlikely(fr_rb_insert(tree, entry) == false)) {
186 fr_strerror_const("Insertion failed - duplicate key?");
187 error:
188 interval_slab_release(entry);
189 return -1;
190 }
191
192 if (unlikely(fr_timer_in(entry, thread->tl, &entry->ev, interval, true, expire, entry) < 0)) goto error;
193 return 1;
194 }
195
196 /*
197 * Entry exists - check if interval limited.
198 * Timer loop doesn't run immediately, so check the scheduled
199 * fire time rather than just whether it's armed.
200 */
201 if (fr_timer_armed(entry->ev) && fr_time_gt(fr_timer_when(entry->ev), fr_time())) return 0;
202
203 /*
204 * Timer expired (or wasn't set), reset it
205 */
206 if (unlikely(fr_timer_in(entry, thread->tl, &entry->ev, interval, true, expire, entry) < 0)) {
207 fr_rb_delete(tree, entry);
208 return -1;
209 }
210
211 return 1;
212}
213
214/** Global scope xlat - always uses mutex-protected tree
215 */
217 xlat_ctx_t const *xctx,
218 request_t *request, fr_value_box_list_t *in)
219{
221 rlm_interval_thread_t *thread = talloc_get_type_abort(xctx->mctx->thread, rlm_interval_thread_t);
222 rlm_interval_xlat_inst_t const *xlat_inst = xctx->inst;
223
224 fr_value_box_t *interval, *key, *result;
225 rlm_interval_entry_t find = {};
226 int ret;
227
228 XLAT_ARGS(in, &interval, &key);
229
230 /*
231 * Set up the find key - either string key or xlat expression pointer
232 */
233 if (!key) {
234 fr_value_box_set_void_shallow(&find.key, xlat_inst->ex);
235 } else {
236 fr_value_box_copy_shallow(NULL, &find.key, key);
237 }
238
239 pthread_mutex_lock(&inst->mutable->mutex);
240 ret = interval_check(inst->mutable->tree, thread, inst->mutable, interval_expire_global,
241 &find, interval->vb_time_delta);
242 pthread_mutex_unlock(&inst->mutable->mutex);
243
244 MEM(result = fr_value_box_alloc(ctx, FR_TYPE_BOOL, NULL));
245 switch (ret) {
246 case 1:
247 RDEBUG3("Interval passed");
248 result->vb_bool = true;
249 break;
250
251 case 0:
252 RDEBUG3("Within interval");
253 result->vb_bool = false;
254 break;
255
256 default:
257 fr_assert_msg(false, "interval_check failed in global scope xlat: %s", fr_strerror());
258 result->vb_bool = true; /* Allow on error */
259 break;
260 }
261
262 fr_dcursor_append(out, result);
263 return XLAT_ACTION_DONE;
264}
265
266/** Thread scope xlat - uses thread-local tree or module thread instance
267 */
269 xlat_ctx_t const *xctx,
270 request_t *request, fr_value_box_list_t *in)
271{
272 rlm_interval_thread_t *thread = talloc_get_type_abort(xctx->mctx->thread, rlm_interval_thread_t);
273 rlm_interval_xlat_thread_inst_t *xlat_thread = xctx->thread;
274
275 fr_value_box_t *interval, *key, *result;
276 int ret;
277
278 XLAT_ARGS(in, &interval, &key);
279
280 if (!key) {
281 /*
282 * Keyless: use xlat thread instance directly - no tree lookup needed
283 */
284 fr_time_t now = fr_time();
285
286 if (fr_time_gt(fr_time_add(xlat_thread->last_used, interval->vb_time_delta), now)) {
287 ret = 0;
288 } else {
289 xlat_thread->last_used = now;
290 ret = 1;
291 }
292 } else {
293 /*
294 * Keyed: use thread-local tree
295 */
296 rlm_interval_entry_t find = {};
297
298 fr_value_box_copy_shallow(NULL, &find.key, key);
299
300 ret = interval_check(thread->tree, thread, thread, interval_expire_thread,
301 &find, interval->vb_time_delta);
302 }
303
304 MEM(result = fr_value_box_alloc(ctx, FR_TYPE_BOOL, NULL));
305
306 switch (ret) {
307 case 1:
308 RDEBUG3("Interval passed");
309 result->vb_bool = true;
310 break;
311
312 case 0:
313 RDEBUG3("Within interval");
314 result->vb_bool = false;
315 break;
316
317 default:
318 fr_assert_msg(false, "interval_check failed in thread scope xlat: %s", fr_strerror());
319 result->vb_bool = true; /* Allow on error */
320 break;
321 }
322
323 fr_dcursor_append(out, result);
324 return XLAT_ACTION_DONE;
325}
326
328{
329 rlm_interval_xlat_inst_t *xlat_inst = xctx->inst;
330
331 xlat_inst->ex = xctx->ex;
332 return 0;
333}
334
336{
337 rlm_interval_xlat_thread_inst_t *xlat_thread = xctx->thread;
338
339 /*
340 * Initialize to "never used" so first check always allows.
341 * fr_time() is relative to server start, not Unix epoch.
342 */
343 xlat_thread->last_used = fr_time_min();
344 return 0;
345}
346
348{
349 rlm_interval_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_interval_t);
350 rlm_interval_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_interval_thread_t);
351
352 /*
353 * Always need a thread-local timer list and slab, even for global scope,
354 * because timer lists and talloc aren't thread-safe.
355 *
356 * Use lst (heap) not ordered (dlist) because timers aren't
357 * inserted in chronological order.
358 */
359 t->tl = fr_timer_list_lst_alloc(t, mctx->el->tl);
360 if (!t->tl) {
361 ERROR("Failed to create thread-local timer list");
362 return -1;
363 }
364
365 t->slab = interval_slab_list_alloc(t, mctx->el, &inst->reuse,
366 NULL, NULL, NULL,
367 true, false);
368 if (!t->slab) {
369 ERROR("Failed to create thread-local slab allocator");
370 return -1;
371 }
372
373 if (inst->scope == INTERVAL_SCOPE_THREAD) {
375 interval_entry_cmp, NULL);
376 if (!t->tree) {
377 ERROR("Failed to create thread-local rbtree");
378 return -1;
379 }
380 }
381
382 return 0;
383}
384
385static int mod_detach(module_detach_ctx_t const *mctx)
386{
387 rlm_interval_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_interval_t);
388
389 if (inst->mutable) {
390 pthread_mutex_destroy(&inst->mutable->mutex);
391 talloc_free(inst->mutable);
392 }
393
394 return 0;
395}
396
397static int mod_instantiate(module_inst_ctx_t const *mctx)
398{
399 rlm_interval_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_interval_t);
400
401 if (inst->scope == INTERVAL_SCOPE_GLOBAL) {
402 MEM(inst->mutable = talloc_zero(NULL, rlm_interval_mutable_t));
403
404 inst->mutable->tree = fr_rb_inline_talloc_alloc(inst->mutable, rlm_interval_entry_t, node,
405 interval_entry_cmp, NULL);
406 if (!inst->mutable->tree) {
407 ERROR("Failed to create rbtree");
408 talloc_free(inst->mutable);
409 return -1;
410 }
411
412 MEM(pthread_mutex_init(&inst->mutable->mutex, NULL) == 0);
413 }
414
415 return 0;
416}
417
418static int mod_bootstrap(module_inst_ctx_t const *mctx)
419{
420 rlm_interval_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_interval_t);
421 xlat_t *xlat;
422
423 /*
424 * Register scope-specific xlat function
425 */
426 switch (inst->scope) {
429 if (!xlat) {
430 registration_error:
431 ERROR("Failed to register xlat function");
432 return -1;
433 }
434 break;
435
438 if (!xlat) goto registration_error;
439 if (xlat) {
442 }
443 break;
444 }
445
448
449 return 0;
450}
451
454 .common = {
455 .magic = MODULE_MAGIC_INIT,
456 .name = "interval",
457 .inst_size = sizeof(rlm_interval_t),
458 .thread_inst_size = sizeof(rlm_interval_thread_t),
459 .config = module_config,
460 .bootstrap = mod_bootstrap,
461 .instantiate = mod_instantiate,
462 .detach = mod_detach,
463 .thread_instantiate = mod_thread_instantiate,
464 }
465};
#define RCSID(id)
Definition build.h:506
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:228
#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:113
#define unlikely(_x)
Definition build.h:402
#define UNUSED
Definition build.h:336
#define NUM_ELEMENTS(_t)
Definition build.h:358
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:1635
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:657
cf_parse_t func
Override default parsing behaviour for the specified type with a custom parsing function.
Definition cf_parse.h:611
#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:280
#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:309
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:594
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
Definition dcursor.h:406
#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:212
#define MEM(x)
Definition debug.h:46
#define ERROR(fmt,...)
Definition dhcpclient.c:40
static fr_slen_t in
Definition dict.h:882
#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:355
#define fr_time()
Definition event.c:60
@ 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:244
The main red black tree structure.
Definition rb.h:71
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:293
void * boot
Data allocated during the boostrap phase.
Definition module.h:296
#define FR_SLAB_FUNCS(_name, _type)
Define type specific wrapper functions for slabs and slab elements.
Definition slab.h:124
#define FR_SLAB_TYPES(_name, _type)
Define type specific wrapper structs for slabs and slab elements.
Definition slab.h:75
#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
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:110
#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:719
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:1262
An event timer list.
Definition timer.c:49
A timer event.
Definition timer.c:83
#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 consumed 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:5194
int8_t fr_value_box_cmp(fr_value_box_t const *a, fr_value_box_t const *b)
Compare two values.
Definition value.c:748
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:4503
#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:1030
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