The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
xlat_redundant.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: efc200b7a8b88541760d2370d0ec7d3a3b790ca1 $
19  *
20  * @file xlat_redundant.c
21  * @brief Register xlat functions for calling redundant xlats
22  *
23  * @copyright 2023 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
24  */
25 
26 RCSID("$Id: efc200b7a8b88541760d2370d0ec7d3a3b790ca1 $")
27 
28 #include <freeradius-devel/unlang/interpret.h>
29 #include <freeradius-devel/unlang/xlat_redundant.h>
30 #include <freeradius-devel/unlang/xlat_func.h>
31 #include <freeradius-devel/unlang/xlat_priv.h>
32 #include <freeradius-devel/util/rand.h>
33 
34 /*
35  * Internal redundant handler for xlats
36  */
37 typedef enum {
38  XLAT_REDUNDANT_INVALID = 0, //!< Not a valid redundant type.
39  XLAT_REDUNDANT, //!< Use the first xlat function first, then
40  ///< go through in sequence, using the next
41  ///< function after each failure.
42 
43  XLAT_LOAD_BALANCE, //!< Pick a random xlat, and if that fails
44  ///< then the call as a whole fails.
45 
46  XLAT_REDUNDANT_LOAD_BALANCE, //!< Pick a random xlat to start, then fail
47  ///< between the other xlats in the redundant
48  ///< group.
50 
51 typedef struct {
52  fr_dlist_t entry; //!< Entry in the redundant function list.
53  xlat_t *func; //!< Resolved xlat function.
55 
56 typedef struct {
57  xlat_redundant_type_t type; //!< Type of redundant xlat expression.
58  fr_dlist_head_t funcs; //!< List of redundant xlat functions.
59  CONF_SECTION *cs; //!< That this redundant xlat list was created from.
61 
62 typedef struct {
63  xlat_redundant_t *xr; //!< Information about the redundant xlat.
64  xlat_exp_head_t **ex; //!< Array of xlat expressions created by
65  ///< tokenizing the arguments to the redundant
66  ///< xlat, then duplicating them multiple times,
67  ///< one for each xlat function that may be called.
69 
70 typedef struct {
71  bool last_success; //!< Did the last call succeed?
72 
73  xlat_exp_head_t **first; //!< First function called.
74  ///< Used for redundant-load-balance.
75  xlat_exp_head_t **current; //!< Last function called, used for redundant xlats.
77 
78 /** Pass back the result from a single redundant child call
79  *
80  */
82  xlat_ctx_t const *xctx,
83  request_t *request, UNUSED fr_value_box_list_t *in)
84 {
86  xlat_redundant_rctx_t *rctx = talloc_get_type_abort(xctx->rctx, xlat_redundant_rctx_t);
88 
89  if (rctx->last_success) {
90  done:
91  talloc_free(rctx);
92  return xa;
93  }
94 
95  /*
96  * We're at the end, loop back to the start
97  */
98  if (++rctx->current >= (xri->ex + talloc_array_length(xri->ex))) rctx->current = xri->ex;
99 
100  /*
101  * We're back to the first one we tried, fail...
102  */
103  if (rctx->current == rctx->first) {
104  error:
105  xa = XLAT_ACTION_FAIL;
106  goto done;
107  }
108 
109  if (unlang_xlat_yield(request, xlat_redundant_resume, NULL, 0, rctx) != XLAT_ACTION_YIELD) goto error;
110 
111  /*
112  * Push the next child...
113  */
114  if (unlang_xlat_push(ctx, &rctx->last_success, (fr_value_box_list_t *)out->dlist,
115  request, *rctx->current, UNLANG_SUB_FRAME) < 0) goto error;
116 
118 }
119 
120 /** Pass back the result from a single redundant child call
121  *
122  */
124  xlat_ctx_t const *xctx,
125  UNUSED request_t *request, UNUSED fr_value_box_list_t *in)
126 {
127  xlat_redundant_rctx_t *rctx = talloc_get_type_abort(xctx->rctx, xlat_redundant_rctx_t);
129 
130  talloc_free(rctx);
131 
132  return xa;
133 }
134 
135 /** xlat "redundant", "load-balance" and "redundant-load-balance" processing
136  *
137  * @ingroup xlat_functions
138  */
139 static xlat_action_t xlat_redundant(TALLOC_CTX *ctx, fr_dcursor_t *out,
140  xlat_ctx_t const *xctx,
141  request_t *request, UNUSED fr_value_box_list_t *in)
142 {
144  xlat_redundant_rctx_t *rctx;
145 
146  MEM(rctx = talloc_zero(unlang_interpret_frame_talloc_ctx(request), xlat_redundant_rctx_t));
147 
148  switch (xri->xr->type) {
149  /*
150  * Run through each of the redundant functions sequentially
151  * starting at the first.
152  */
153  case XLAT_REDUNDANT:
154  rctx->current = rctx->first = xri->ex; /* First element first */
155  if (unlang_xlat_yield(request, xlat_redundant_resume, NULL, 0, rctx) != XLAT_ACTION_YIELD) {
156  error:
157  talloc_free(rctx);
158  return XLAT_ACTION_FAIL;
159  }
160  break;
161 
162  /*
163  * Run a single random redundant function.
164  */
165  case XLAT_LOAD_BALANCE:
166  rctx->first = &xri->ex[(size_t)fr_rand() & (talloc_array_length(xri->ex) - 1)]; /* Random start */
167  if (unlang_xlat_yield(request, xlat_load_balance_resume, NULL, 0, rctx) != XLAT_ACTION_YIELD) goto error;
168  break;
169 
170  /*
171  * Run through each of the redundant functions sequentially
172  * starting at a random element.
173  */
175  rctx->first = &xri->ex[(size_t)fr_rand() & (talloc_array_length(xri->ex) - 1)]; /* Random start */
176  if (unlang_xlat_yield(request, xlat_redundant_resume, NULL, 0, rctx) != XLAT_ACTION_YIELD) goto error;
177  break;
178 
179  default:
180  fr_assert(0);
181  }
182 
183  if (unlang_xlat_push(ctx, &rctx->last_success, (fr_value_box_list_t *)out->dlist,
184  request, *rctx->current, UNLANG_SUB_FRAME) < 0) return XLAT_ACTION_FAIL;
185 
187 }
188 
189 /** Allocate an xlat node to call an xlat function
190  *
191  * @param[in] ctx to allocate the new node in.
192  * @param[in] func to call.
193  * @param[in] args Arguments to the function. Will be copied,
194  * and freed when the new xlat node is freed.
195  */
196 static xlat_exp_t *xlat_exp_func_alloc(TALLOC_CTX *ctx, xlat_t *func, xlat_exp_head_t const *args)
197 {
198  xlat_exp_t *node;
199 
200  MEM(node = xlat_exp_alloc(ctx, XLAT_FUNC, func->name, strlen(func->name)));
201  node->call.func = func;
202  if (unlikely(xlat_copy(node, node->call.args, args) < 0)) {
203  talloc_free(node);
204  return NULL;
205  }
206  node->flags = func->flags;
207  xlat_flags_merge(&node->flags, &args->flags);
208 
209  /*
210  * If the function is pure, AND it's arguments are pure,
211  * then remember that we need to call a pure function.
212  */
213  node->flags.can_purify = (func->flags.pure && args->flags.pure) | args->flags.can_purify;
214 
215  return node;
216 }
217 
218 
219 /** Allocate additional nodes for evaluation
220  *
221  */
223 {
224  xlat_redundant_t *xr = talloc_get_type_abort(xctx->uctx, xlat_redundant_t);
225  xlat_redundant_inst_t *xri = talloc_get_type_abort(xctx->inst, xlat_redundant_inst_t);
226  unsigned int num = 0;
227  xlat_redundant_func_t const *first;
228 
229  MEM(xri->ex = talloc_array(xri, xlat_exp_head_t *, fr_dlist_num_elements(&xr->funcs)));
230  xri->xr = xr;
231 
232  first = talloc_get_type_abort(fr_dlist_head(&xr->funcs), xlat_redundant_func_t);
233 
234  /*
235  * Check the calling style matches the first
236  * function.
237  *
238  * We do this here as the redundant xlat
239  * itself can't have an input type or
240  * defined arguments;
241  */
242  switch (xctx->ex->call.input_type) {
244  break;
245 
246  case XLAT_INPUT_MONO:
247  if (first->func->input_type == XLAT_INPUT_ARGS) {
248  PERROR("Expansion function \"%s\" takes defined arguments and should "
249  "be called using %%(func:args) syntax",
250  xctx->ex->call.func->name);
251  return -1;
252 
253  }
254  break;
255 
256  case XLAT_INPUT_ARGS:
257  if (first->func->input_type == XLAT_INPUT_MONO) {
258  PERROR("Expansion function \"%s\" should be called using %%{func:arg} syntax",
259  xctx->ex->call.func->name);
260  return -1;
261  }
262  break;
263  }
264 
265  /*
266  * For each function, create the appropriate xlat
267  * node, and duplicate the child arguments.
268  */
270  xlat_exp_t *node;
272 
273  /*
274  * We have to do this here as it only
275  * becomes an error when the user tries
276  * to use the redundant xlat.
277  */
278  if (first->func->input_type != xrf->func->input_type) {
279  cf_log_err(xr->cs, "Expansion functions \"%s\" and \"%s\" use different argument styles "
280  "cannot be used in the same redundant section", first->func->name, xrf->func->name);
281  error:
282  talloc_free(xri->ex);
283  return -1;
284  }
285 
286  /*
287  * We pass the current arguments in
288  * so that the instantiation functions
289  * for the new node can operate
290  * correctly.
291  */
292  MEM(head = xlat_exp_head_alloc(xri->ex));
293  MEM(node = xlat_exp_func_alloc(head, xrf->func, xctx->ex->call.args));
294  xlat_exp_insert_tail(head, node);
295 
296  switch (xrf->func->input_type) {
298  break;
299 
300  case XLAT_INPUT_MONO:
301  if (xlat_validate_function_mono(node) < 0) {
302  PERROR("Invalid arguments for redundant expansion function \"%s\"",
303  xrf->func->name);
304  goto error;
305  }
306  break;
307 
308  case XLAT_INPUT_ARGS:
309  if (xlat_validate_function_args(node) < 0) {
310  PERROR("Invalid arguments for redundant expansion function \"%s\"",
311  xrf->func->name);
312  goto error;
313  }
314  break;
315  }
316 
317  /*
318  * Add the xlat function (and any children)
319  * to the end of the instantiation list so
320  * they'll get called at some point after
321  * we return.
322  */
323  head->flags = node->flags;
324  if (xlat_finalize(head, NULL) < 0) {
325  PERROR("Failed bootstrapping function \"%s\"",
326  xrf->func->name);
327  goto error;
328  }
329  xri->ex[num++] = head;
330  }
331 
332  /*
333  * Free the original argument nodes so they're
334  * not evaluated when the redundant xlat is called.
335  *
336  * We need to re-evaluate the arguments for each
337  * redundant function call we perform.
338  *
339  * The xlat_exp_func_alloc call above associates
340  * a copy of the original arguments with each
341  * function that's called.
342  */
343  fr_dlist_talloc_free(&xctx->ex->call.args->dlist);
344 
345  return 0;
346 }
347 
349  { .type = FR_TYPE_VOID },
351 };
352 
353 /** Registers a redundant xlat
354  *
355  * These xlats wrap the xlat methods of the modules in a redundant section,
356  * emulating the behaviour of a redundant section, but over xlats.
357  *
358  * @return
359  * - 0 on success.
360  * - -1 on error.
361  * - 1 if the modules in the section do not have an xlat method.
362  */
364 {
365  static fr_table_num_sorted_t const xlat_redundant_type_table[] = {
366  { L("load-balance"), XLAT_LOAD_BALANCE },
367  { L("redundant"), XLAT_REDUNDANT },
368  { L("redundant-load-balance"), XLAT_REDUNDANT_LOAD_BALANCE },
369  };
370  static size_t xlat_redundant_type_table_len = NUM_ELEMENTS(xlat_redundant_type_table);
371 
372  char const *name1, *name2;
373  xlat_redundant_type_t xr_type;
374  xlat_redundant_t *xr;
376  bool can_be_pure = false;
377  xlat_arg_parser_t const *args = NULL;
378 
379  fr_type_t return_type = FR_TYPE_NULL;
380  bool first = true;
381 
382  xlat_t *xlat;
383  CONF_ITEM *ci = NULL;
384 
385  name1 = cf_section_name1(cs);
386  xr_type = fr_table_value_by_str(xlat_redundant_type_table, name1, XLAT_REDUNDANT_INVALID);
387  switch (xr_type) {
389  cf_log_err(cs, "Invalid redundant section verb \"%s\"", name1);
390  return -1;
391 
392  case XLAT_REDUNDANT:
393  can_be_pure = true; /* Can be pure */
394  break;
395 
396  case XLAT_LOAD_BALANCE:
397  can_be_pure = false; /* Can never be pure because of random selection */
398  break;
399 
401  can_be_pure = false; /* Can never be pure because of random selection */
402  break;
403  }
404 
405  name2 = cf_section_name2(cs);
406  if (xlat_func_find(name2, talloc_array_length(name2) - 1)) {
407  cf_log_err(cs, "An expansion is already registered for this name");
408  return -1;
409  }
410 
411  MEM(xr = talloc_zero(cs, xlat_redundant_t));
412  xr->type = xr_type;
413  xr->cs = cs;
415 
416  /*
417  * Count the number of children for load-balance, and
418  * also find out a little bit more about the old xlats.
419  *
420  * These are just preemptive checks, the majority of
421  * the work is done when a redundant xlat is
422  * instantiated. There we create an xlat node for
423  * each of the children of the section.
424  */
425  while ((ci = cf_item_next(cs, ci))) {
427  char const *mod_func_name;
428  xlat_t *mod_func;
429 
430  if (!cf_item_is_pair(ci)) continue;
431 
432  mod_func_name = cf_pair_attr(cf_item_to_pair(ci));
433 
434  /*
435  * This is ok, it just means the module
436  * doesn't have an xlat method.
437  *
438  * If there are ordering issues we could
439  * move this check to the instantiation
440  * function.
441  */
442  mod_func = xlat_func_find(mod_func_name, talloc_array_length(mod_func_name) - 1);
443  if (!mod_func) {
444  talloc_free(xr);
445  return 1;
446  }
447 
448  if (!args) {
449  args = mod_func->args;
450  } else {
451  fr_assert(args == mod_func->args);
452  }
453 
454  /*
455  * Degrade to a void return type if
456  * we have mixed types in a redundant
457  * section.
458  */
459  if (!first) {
460  if (mod_func->return_type != return_type) return_type = FR_TYPE_VOID;
461  } else {
462  return_type = mod_func->return_type;
463  first = false;
464  }
465 
466  MEM(xrf = talloc_zero(xr, xlat_redundant_func_t));
467  xrf->func = mod_func;
468  fr_dlist_insert_tail(&xr->funcs, xrf);
469 
470  /*
471  * Figure out pure status. If any of
472  * the children are un-pure then the
473  * whole redundant xlat is un-pure,
474  * same with async.
475  */
476  if (can_be_pure && mod_func->flags.pure) flags |= XLAT_FUNC_FLAG_PURE;
477  }
478 
479  /*
480  * At least one module xlat has to exist.
481  */
482  if (!fr_dlist_num_elements(&xr->funcs)) {
483  talloc_free(xr);
484  return 1;
485  }
486 
487  xlat = xlat_func_register(NULL, name2, xlat_redundant, return_type);
488  if (unlikely(xlat == NULL)) {
489  ERROR("Registering xlat for %s section failed",
490  fr_table_str_by_value(xlat_redundant_type_table, xr->type, "<INVALID>"));
491  talloc_free(xr);
492  return -1;
493  }
494  xlat_func_flags_set(xlat, flags);
497 
498  return 0;
499 }
va_list args
Definition: acutest.h:770
#define RCSID(id)
Definition: build.h:444
#define L(_str)
Helper for initialising arrays of string literals.
Definition: build.h:207
#define unlikely(_x)
Definition: build.h:378
#define UNUSED
Definition: build.h:313
#define NUM_ELEMENTS(_t)
Definition: build.h:335
Common header for all CONF_* types.
Definition: cf_priv.h:49
A section grouping multiple CONF_PAIR.
Definition: cf_priv.h:89
bool cf_item_is_pair(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_PAIR.
Definition: cf_util.c:597
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition: cf_util.c:629
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
Definition: cf_util.c:1495
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition: cf_util.c:1126
char const * cf_section_name1(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition: cf_util.c:1112
#define cf_log_err(_cf, _fmt,...)
Definition: cf_util.h:265
#define cf_item_next(_ci, _prev)
Definition: cf_util.h:92
#define ERROR(fmt,...)
Definition: dhcpclient.c:41
static fr_slen_t in
Definition: dict.h:645
#define fr_dlist_foreach(_list_head, _type, _iter)
Iterate over the contents of a list.
Definition: dlist.h:94
static void fr_dlist_talloc_free(fr_dlist_head_t *head)
Free all items in a doubly linked list (with talloc)
Definition: dlist.h:908
static unsigned int fr_dlist_num_elements(fr_dlist_head_t const *head)
Return the number of elements in the dlist.
Definition: dlist.h:939
static void * fr_dlist_head(fr_dlist_head_t const *list_head)
Return the HEAD item of a list or NULL if the list is empty.
Definition: dlist.h:486
static int fr_dlist_insert_tail(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the tail of a list.
Definition: dlist.h:378
#define fr_dlist_talloc_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
Definition: dlist.h:275
Head of a doubly linked list.
Definition: dlist.h:51
Entry in a doubly linked list.
Definition: dlist.h:41
static xlat_action_t xlat_redundant(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, UNUSED fr_value_box_list_t *in)
xlat "redundant", "load-balance" and "redundant-load-balance" processing
TALLOC_CTX * unlang_interpret_frame_talloc_ctx(request_t *request)
Get a talloc_ctx which is valid only for this frame.
Definition: interpret.c:1384
#define UNLANG_SUB_FRAME
Definition: interpret.h:36
#define PERROR(_fmt,...)
Definition: log.h:228
talloc_free(reap)
fr_type_t
Definition: merged_model.c:80
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
Definition: merged_model.c:81
@ FR_TYPE_VOID
User data.
Definition: merged_model.c:127
unsigned long int size_t
Definition: merged_model.c:25
static bool done
Definition: radclient.c:80
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition: rand.c:106
fr_assert(0)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
Definition: table.h:134
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition: table.h:253
An element in a lexicographically sorted array of name to num mappings.
Definition: table.h:45
#define talloc_get_type_abort_const
Definition: talloc.h:270
xlat_action_t unlang_xlat_yield(request_t *request, xlat_func_t resume, xlat_func_signal_t signal, fr_signal_t sigmask, void *rctx)
Yield a request back to the interpreter from within a module.
Definition: xlat.c:561
int unlang_xlat_push(TALLOC_CTX *ctx, bool *p_success, fr_value_box_list_t *out, request_t *request, xlat_exp_head_t const *xlat, bool top_frame)
Push a pre-compiled xlat onto the stack for evaluation.
Definition: xlat.c:274
fr_type_t type
Type to cast argument to.
Definition: xlat.h:153
int xlat_validate_function_args(xlat_exp_t *node)
static fr_slen_t head
Definition: xlat.h:408
#define xlat_copy(_ctx, _out, _in)
Definition: xlat.h:445
bool can_purify
if the xlat has a pure function with pure arguments.
Definition: xlat.h:114
@ XLAT_INPUT_MONO
Ingests a single argument.
Definition: xlat.h:47
@ XLAT_INPUT_ARGS
Ingests a number of arguments.
Definition: xlat.h:48
@ XLAT_INPUT_UNPROCESSED
No input argument processing.
Definition: xlat.h:46
int xlat_validate_function_mono(xlat_exp_t *node)
bool pure
has no external side effects, true for BOX, LITERAL, and some functions
Definition: xlat.h:113
#define XLAT_ARG_PARSER_TERMINATOR
Definition: xlat.h:166
int xlat_finalize(xlat_exp_head_t *head, fr_event_list_t *runtime_el)
Bootstrap static xlats, or instantiate ephemeral ones.
Definition: xlat_inst.c:690
xlat_action_t
Definition: xlat.h:35
@ XLAT_ACTION_FAIL
An xlat function failed.
Definition: xlat.h:42
@ XLAT_ACTION_YIELD
An xlat function pushed a resume frame onto the stack.
Definition: xlat.h:40
@ XLAT_ACTION_PUSH_UNLANG
An xlat function pushed an unlang frame onto the unlang stack.
Definition: xlat.h:37
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
Definition: xlat.h:41
Definition for a single argument consumend by an xlat function.
Definition: xlat.h:145
static size_t char ** out
Definition: value.h:984
void * rctx
Resume context.
Definition: xlat_ctx.h:47
void * inst
xlat instance data to populate.
Definition: xlat_ctx.h:55
void const * inst
xlat instance data.
Definition: xlat_ctx.h:43
xlat_exp_t * ex
Tokenized expression to use in expansion.
Definition: xlat_ctx.h:56
void * uctx
Passed to the registration function.
Definition: xlat_ctx.h:58
An xlat calling ctx.
Definition: xlat_ctx.h:42
An xlat instantiation ctx.
Definition: xlat_ctx.h:54
void xlat_func_flags_set(xlat_t *x, xlat_func_flags_t flags)
Specify flags that alter the xlat's behaviour.
Definition: xlat_func.c:415
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.
Definition: xlat_func.c:360
xlat_t * xlat_func_register(TALLOC_CTX *ctx, char const *name, xlat_func_t func, fr_type_t return_type)
Register an xlat function.
Definition: xlat_func.c:195
xlat_t * xlat_func_find(char const *in, ssize_t inlen)
Definition: xlat_func.c:56
#define xlat_func_instantiate_set(_xlat, _instantiate, _inst_struct, _detach, _uctx)
Set a callback for global instantiation of xlat functions.
Definition: xlat_func.h:91
xlat_func_flags_t
Definition: xlat_func.h:36
@ XLAT_FUNC_FLAG_NONE
Definition: xlat_func.h:37
@ XLAT_FUNC_FLAG_PURE
Definition: xlat_func.h:38
char const * name
Name of xlat function.
Definition: xlat_priv.h:60
#define xlat_exp_head_alloc(_ctx)
Definition: xlat_priv.h:266
xlat_flags_t flags
Flags that control resolution and evaluation.
Definition: xlat_priv.h:153
fr_type_t return_type
Function is guaranteed to return one or more boxes of this type.
Definition: xlat_priv.h:96
@ XLAT_FUNC
xlat module
Definition: xlat_priv.h:105
xlat_arg_parser_t const * args
Definition of args consumed.
Definition: xlat_priv.h:89
static void xlat_flags_merge(xlat_flags_t *parent, xlat_flags_t const *child)
Merge flags from child to parent.
Definition: xlat_priv.h:223
xlat_input_type_t input_type
Type of input used.
Definition: xlat_priv.h:88
#define xlat_exp_alloc(_ctx, _type, _in, _inlen)
Definition: xlat_priv.h:275
xlat_flags_t flags
various flags
Definition: xlat_priv.h:86
static int xlat_exp_insert_tail(xlat_exp_head_t *head, xlat_exp_t *node)
Definition: xlat_priv.h:231
An xlat expansion node.
Definition: xlat_priv.h:147
static xlat_action_t xlat_load_balance_resume(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, xlat_ctx_t const *xctx, UNUSED request_t *request, UNUSED fr_value_box_list_t *in)
Pass back the result from a single redundant child call.
xlat_redundant_t * xr
Information about the redundant xlat.
static xlat_arg_parser_t const xlat_redundant_args[]
bool last_success
Did the last call succeed?
fr_dlist_head_t funcs
List of redundant xlat functions.
fr_dlist_t entry
Entry in the redundant function list.
xlat_exp_head_t ** first
First function called.
static xlat_exp_t * xlat_exp_func_alloc(TALLOC_CTX *ctx, xlat_t *func, xlat_exp_head_t const *args)
Allocate an xlat node to call an xlat function.
xlat_redundant_type_t type
Type of redundant xlat expression.
xlat_exp_head_t ** current
Last function called, used for redundant xlats.
xlat_exp_head_t ** ex
Array of xlat expressions created by tokenizing the arguments to the redundant xlat,...
static int xlat_redundant_instantiate(xlat_inst_ctx_t const *xctx)
Allocate additional nodes for evaluation.
int xlat_register_redundant(CONF_SECTION *cs)
Registers a redundant xlat.
xlat_t * func
Resolved xlat function.
CONF_SECTION * cs
That this redundant xlat list was created from.
xlat_redundant_type_t
@ XLAT_REDUNDANT_INVALID
Not a valid redundant type.
@ XLAT_REDUNDANT
Use the first xlat function first, then go through in sequence, using the next function after each fa...
@ XLAT_LOAD_BALANCE
Pick a random xlat, and if that fails then the call as a whole fails.
@ XLAT_REDUNDANT_LOAD_BALANCE
Pick a random xlat to start, then fail between the other xlats in the redundant group.
static xlat_action_t xlat_redundant_resume(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, UNUSED fr_value_box_list_t *in)
Pass back the result from a single redundant child call.