mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-07 15:47:01 +02:00
MEDIUM: tcp-act: <expr> support for set-fc-{mark,tos} actions
In this patch we add the possibility to use sample expression as argument for set-fc-{mark,tos} actions. To make it backward compatible with previous behavior, during parsing we first try to parse the value as as integer (decimal or hex notation), and then fallback to expr parsing in case of failure. The documentation was updated accordingly.
This commit is contained in:
parent
03cb782bcb
commit
b4ee7b044e
@ -14744,32 +14744,35 @@ set-dst-port <expr>
|
|||||||
destination address to IPv4 "0.0.0.0" before rewriting the port.
|
destination address to IPv4 "0.0.0.0" before rewriting the port.
|
||||||
|
|
||||||
|
|
||||||
set-fc-mark <mark>
|
set-fc-mark { <mark> | <expr> }
|
||||||
Usable in: TCP RqCon| RqSes| RqCnt| RsCnt| HTTP Req| Res| Aft
|
Usable in: TCP RqCon| RqSes| RqCnt| RsCnt| HTTP Req| Res| Aft
|
||||||
X | X | X | X | X | X | -
|
X | X | X | X | X | X | -
|
||||||
|
|
||||||
This is used to set the Netfilter/IPFW MARK on all packets sent to the client
|
This is used to set the Netfilter/IPFW MARK on all packets sent to the client
|
||||||
to the value passed in <mark> on platforms which support it. This value is an
|
to the value passed in <mark> or <expr> on platforms which support it. This
|
||||||
unsigned 32 bit value which can be matched by netfilter/ipfw and by the
|
value is an unsigned 32 bit value which can be matched by netfilter/ipfw and
|
||||||
routing table or monitoring the packets through DTrace. It can be expressed
|
by the routing table or monitoring the packets through DTrace. <mark> can be
|
||||||
both in decimal or hexadecimal format (prefixed by "0x").
|
expressed both in decimal or hexadecimal format (prefixed by "0x").
|
||||||
This can be useful to force certain packets to take a different route (for
|
Alternatively, <expr> can be used: it is a standard HAProxy expression formed
|
||||||
example a cheaper network path for bulk downloads). This works on Linux
|
by a sample-fetch followed by some converters which must resolve to integer
|
||||||
kernels 2.6.32 and above and requires admin privileges, as well on FreeBSD
|
type. This action can be useful to force certain packets to take a different
|
||||||
and OpenBSD.
|
route (for example a cheaper network path for bulk downloads). This works on
|
||||||
|
Linux kernels 2.6.32 and above and requires admin privileges, as well on
|
||||||
|
FreeBSD and OpenBSD.
|
||||||
|
|
||||||
|
|
||||||
set-fc-tos <tos>
|
set-fc-tos { <tos | <expr> }
|
||||||
Usable in: TCP RqCon| RqSes| RqCnt| RsCnt| HTTP Req| Res| Aft
|
Usable in: TCP RqCon| RqSes| RqCnt| RsCnt| HTTP Req| Res| Aft
|
||||||
X | X | X | X | X | X | -
|
X | X | X | X | X | X | -
|
||||||
|
|
||||||
This is used to set the TOS or DSCP field value of packets sent to the client
|
This is used to set the TOS or DSCP field value of packets sent to the client
|
||||||
to the value passed in <tos> on platforms which support this. This value
|
to the value passed in <tos> or <expr> on platforms which support this. This
|
||||||
represents the whole 8 bits of the IP TOS field, and can be expressed both in
|
value represents the whole 8 bits of the IP TOS field. Note that only the 6
|
||||||
decimal or hexadecimal format (prefixed by "0x"). Note that only the 6 higher
|
higher bits are used in DSCP or TOS, and the two lower bits are always 0.
|
||||||
bits are used in DSCP or TOS, and the two lower bits are always 0. This can
|
Alternatively, <expr> can be used: it is a standard HAProxy expression formed
|
||||||
be used to adjust some routing behavior on border routers based on some
|
by a sample-fetch followed by some converters which must resolve to integer
|
||||||
information from the request.
|
type. This action can be used to adjust some routing behavior on border
|
||||||
|
routers based on some information from the request.
|
||||||
|
|
||||||
See RFC 2474, 2597, 3260 and 4594 for more information.
|
See RFC 2474, 2597, 3260 and 4594 for more information.
|
||||||
|
|
||||||
|
@ -191,6 +191,10 @@ struct act_rule {
|
|||||||
struct server *srv; /* target server to attach the connection */
|
struct server *srv; /* target server to attach the connection */
|
||||||
struct sample_expr *name; /* used to differentiate idle connections */
|
struct sample_expr *name; /* used to differentiate idle connections */
|
||||||
} attach_srv; /* 'attach-srv' rule */
|
} attach_srv; /* 'attach-srv' rule */
|
||||||
|
struct {
|
||||||
|
int value;
|
||||||
|
struct sample_expr *expr;
|
||||||
|
} expr_int; /* expr or int value (when expr is NULL)*/
|
||||||
struct {
|
struct {
|
||||||
void *p[4];
|
void *p[4];
|
||||||
} act; /* generic pointers to be used by custom actions */
|
} act; /* generic pointers to be used by custom actions */
|
||||||
|
133
src/tcp_act.c
133
src/tcp_act.c
@ -71,6 +71,29 @@ static enum act_return tcp_action_attach_srv(struct act_rule *rule, struct proxy
|
|||||||
return ACT_RET_CONT;
|
return ACT_RET_CONT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* tries to extract integer value from rule's argument:
|
||||||
|
* if expr is set, computes expr and sets the result into <value>
|
||||||
|
* else, it's already a numerical value, use it as-is.
|
||||||
|
*
|
||||||
|
* Returns 1 on success and 0 on failure.
|
||||||
|
*/
|
||||||
|
static int extract_int_from_rule(struct act_rule *rule,
|
||||||
|
struct proxy *px, struct session *sess, struct stream *s,
|
||||||
|
int *value)
|
||||||
|
{
|
||||||
|
struct sample *smp;
|
||||||
|
|
||||||
|
if (!rule->arg.expr_int.expr) {
|
||||||
|
*value = rule->arg.expr_int.value;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
smp = sample_fetch_as_type(px, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->arg.expr_int.expr, SMP_T_SINT);
|
||||||
|
if (!smp)
|
||||||
|
return 0;
|
||||||
|
*value = smp->data.u.sint;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Execute the "set-src" action. May be called from {tcp,http}request.
|
* Execute the "set-src" action. May be called from {tcp,http}request.
|
||||||
* It only changes the address and tries to preserve the original port. If the
|
* It only changes the address and tries to preserve the original port. If the
|
||||||
@ -392,7 +415,10 @@ static enum act_return tcp_exec_action_silent_drop(struct act_rule *rule, struct
|
|||||||
static enum act_return tcp_action_set_fc_mark(struct act_rule *rule, struct proxy *px,
|
static enum act_return tcp_action_set_fc_mark(struct act_rule *rule, struct proxy *px,
|
||||||
struct session *sess, struct stream *s, int flags)
|
struct session *sess, struct stream *s, int flags)
|
||||||
{
|
{
|
||||||
conn_set_mark(objt_conn(sess->origin), (uintptr_t)rule->arg.act.p[0]);
|
unsigned int mark;
|
||||||
|
|
||||||
|
if (extract_int_from_rule(rule, px, sess, s, (int *)&mark))
|
||||||
|
conn_set_mark(objt_conn(sess->origin), mark);
|
||||||
return ACT_RET_CONT;
|
return ACT_RET_CONT;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -401,7 +427,10 @@ static enum act_return tcp_action_set_fc_mark(struct act_rule *rule, struct prox
|
|||||||
static enum act_return tcp_action_set_fc_tos(struct act_rule *rule, struct proxy *px,
|
static enum act_return tcp_action_set_fc_tos(struct act_rule *rule, struct proxy *px,
|
||||||
struct session *sess, struct stream *s, int flags)
|
struct session *sess, struct stream *s, int flags)
|
||||||
{
|
{
|
||||||
conn_set_tos(objt_conn(sess->origin), (uintptr_t)rule->arg.act.p[0]);
|
int tos;
|
||||||
|
|
||||||
|
if (extract_int_from_rule(rule, px, sess, s, &tos))
|
||||||
|
conn_set_tos(objt_conn(sess->origin), tos);
|
||||||
return ACT_RET_CONT;
|
return ACT_RET_CONT;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -423,6 +452,14 @@ static void release_set_src_dst_action(struct act_rule *rule)
|
|||||||
release_sample_expr(rule->arg.expr);
|
release_sample_expr(rule->arg.expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Release expr_int rule argument when action is no longer used
|
||||||
|
*/
|
||||||
|
static __maybe_unused void release_expr_int_action(struct act_rule *rule)
|
||||||
|
{
|
||||||
|
release_sample_expr(rule->arg.expr_int.expr);
|
||||||
|
}
|
||||||
|
|
||||||
static int tcp_check_attach_srv(struct act_rule *rule, struct proxy *px, char **err)
|
static int tcp_check_attach_srv(struct act_rule *rule, struct proxy *px, char **err)
|
||||||
{
|
{
|
||||||
struct proxy *be = NULL;
|
struct proxy *be = NULL;
|
||||||
@ -565,29 +602,53 @@ static enum act_parse_ret tcp_parse_set_src_dst(const char **args, int *orig_arg
|
|||||||
/* Parse a "set-mark" action. It takes the MARK value as argument. It returns
|
/* Parse a "set-mark" action. It takes the MARK value as argument. It returns
|
||||||
* ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
|
* ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
|
||||||
*/
|
*/
|
||||||
static enum act_parse_ret tcp_parse_set_mark(const char **args, int *cur_arg, struct proxy *px,
|
static enum act_parse_ret tcp_parse_set_mark(const char **args, int *orig_arg, struct proxy *px,
|
||||||
struct act_rule *rule, char **err)
|
struct act_rule *rule, char **err)
|
||||||
{
|
{
|
||||||
#if defined(SO_MARK) || defined(SO_USER_COOKIE) || defined(SO_RTABLE)
|
#if defined(SO_MARK) || defined(SO_USER_COOKIE) || defined(SO_RTABLE)
|
||||||
|
struct sample_expr *expr;
|
||||||
char *endp;
|
char *endp;
|
||||||
unsigned int mark;
|
unsigned int where;
|
||||||
|
int cur_arg = *orig_arg;
|
||||||
|
|
||||||
if (!*args[*cur_arg]) {
|
if (!*args[*orig_arg]) {
|
||||||
memprintf(err, "expects exactly 1 argument (integer/hex value)");
|
memprintf(err, "expects an argument");
|
||||||
return ACT_RET_PRS_ERR;
|
|
||||||
}
|
|
||||||
mark = strtoul(args[*cur_arg], &endp, 0);
|
|
||||||
if (endp && *endp != '\0') {
|
|
||||||
memprintf(err, "invalid character starting at '%s' (integer/hex value expected)", endp);
|
|
||||||
return ACT_RET_PRS_ERR;
|
return ACT_RET_PRS_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
(*cur_arg)++;
|
/* value may be either an unsigned integer or an expression */
|
||||||
|
rule->arg.expr_int.expr = NULL;
|
||||||
|
rule->arg.expr_int.value = strtoul(args[*orig_arg], &endp, 0);
|
||||||
|
if (*endp == '\0') {
|
||||||
|
/* valid unsigned integer */
|
||||||
|
(*orig_arg)++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* invalid unsigned integer, fallback to expr */
|
||||||
|
expr = sample_parse_expr((char **)args, orig_arg, px->conf.args.file, px->conf.args.line, err, &px->conf.args, NULL);
|
||||||
|
if (!expr)
|
||||||
|
return ACT_RET_PRS_ERR;
|
||||||
|
|
||||||
|
where = 0;
|
||||||
|
if (px->cap & PR_CAP_FE)
|
||||||
|
where |= SMP_VAL_FE_HRQ_HDR;
|
||||||
|
if (px->cap & PR_CAP_BE)
|
||||||
|
where |= SMP_VAL_BE_HRQ_HDR;
|
||||||
|
|
||||||
|
if (!(expr->fetch->val & where)) {
|
||||||
|
memprintf(err,
|
||||||
|
"fetch method '%s' extracts information from '%s', none of which is available here",
|
||||||
|
args[cur_arg-1], sample_src_names(expr->fetch->use));
|
||||||
|
free(expr);
|
||||||
|
return ACT_RET_PRS_ERR;
|
||||||
|
}
|
||||||
|
rule->arg.expr_int.expr = expr;
|
||||||
|
}
|
||||||
|
|
||||||
/* Register processing function. */
|
/* Register processing function. */
|
||||||
rule->action_ptr = tcp_action_set_fc_mark;
|
rule->action_ptr = tcp_action_set_fc_mark;
|
||||||
rule->action = ACT_CUSTOM;
|
rule->action = ACT_CUSTOM;
|
||||||
rule->arg.act.p[0] = (void *)(uintptr_t)mark;
|
rule->release_ptr = release_expr_int_action;
|
||||||
global.last_checks |= LSTCHK_NETADM;
|
global.last_checks |= LSTCHK_NETADM;
|
||||||
return ACT_RET_PRS_OK;
|
return ACT_RET_PRS_OK;
|
||||||
#else
|
#else
|
||||||
@ -600,29 +661,53 @@ static enum act_parse_ret tcp_parse_set_mark(const char **args, int *cur_arg, st
|
|||||||
/* Parse a "set-tos" action. It takes the TOS value as argument. It returns
|
/* Parse a "set-tos" action. It takes the TOS value as argument. It returns
|
||||||
* ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
|
* ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
|
||||||
*/
|
*/
|
||||||
static enum act_parse_ret tcp_parse_set_tos(const char **args, int *cur_arg, struct proxy *px,
|
static enum act_parse_ret tcp_parse_set_tos(const char **args, int *orig_arg, struct proxy *px,
|
||||||
struct act_rule *rule, char **err)
|
struct act_rule *rule, char **err)
|
||||||
{
|
{
|
||||||
#ifdef IP_TOS
|
#ifdef IP_TOS
|
||||||
|
struct sample_expr *expr;
|
||||||
char *endp;
|
char *endp;
|
||||||
int tos;
|
unsigned int where;
|
||||||
|
int cur_arg = *orig_arg;
|
||||||
|
|
||||||
if (!*args[*cur_arg]) {
|
if (!*args[*orig_arg]) {
|
||||||
memprintf(err, "expects exactly 1 argument (integer/hex value)");
|
memprintf(err, "expects an argument");
|
||||||
return ACT_RET_PRS_ERR;
|
|
||||||
}
|
|
||||||
tos = strtol(args[*cur_arg], &endp, 0);
|
|
||||||
if (endp && *endp != '\0') {
|
|
||||||
memprintf(err, "invalid character starting at '%s' (integer/hex value expected)", endp);
|
|
||||||
return ACT_RET_PRS_ERR;
|
return ACT_RET_PRS_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
(*cur_arg)++;
|
/* value may be either an integer or an expression */
|
||||||
|
rule->arg.expr_int.expr = NULL;
|
||||||
|
rule->arg.expr_int.value = strtol(args[*orig_arg], &endp, 0);
|
||||||
|
if (*endp == '\0') {
|
||||||
|
/* valid integer */
|
||||||
|
(*orig_arg)++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* invalid unsigned integer, fallback to expr */
|
||||||
|
expr = sample_parse_expr((char **)args, orig_arg, px->conf.args.file, px->conf.args.line, err, &px->conf.args, NULL);
|
||||||
|
if (!expr)
|
||||||
|
return ACT_RET_PRS_ERR;
|
||||||
|
|
||||||
|
where = 0;
|
||||||
|
if (px->cap & PR_CAP_FE)
|
||||||
|
where |= SMP_VAL_FE_HRQ_HDR;
|
||||||
|
if (px->cap & PR_CAP_BE)
|
||||||
|
where |= SMP_VAL_BE_HRQ_HDR;
|
||||||
|
|
||||||
|
if (!(expr->fetch->val & where)) {
|
||||||
|
memprintf(err,
|
||||||
|
"fetch method '%s' extracts information from '%s', none of which is available here",
|
||||||
|
args[cur_arg-1], sample_src_names(expr->fetch->use));
|
||||||
|
free(expr);
|
||||||
|
return ACT_RET_PRS_ERR;
|
||||||
|
}
|
||||||
|
rule->arg.expr_int.expr = expr;
|
||||||
|
}
|
||||||
|
|
||||||
/* Register processing function. */
|
/* Register processing function. */
|
||||||
rule->action_ptr = tcp_action_set_fc_tos;
|
rule->action_ptr = tcp_action_set_fc_tos;
|
||||||
rule->action = ACT_CUSTOM;
|
rule->action = ACT_CUSTOM;
|
||||||
rule->arg.act.p[0] = (void *)(uintptr_t)tos;
|
rule->release_ptr = release_expr_int_action;
|
||||||
return ACT_RET_PRS_OK;
|
return ACT_RET_PRS_OK;
|
||||||
#else
|
#else
|
||||||
memprintf(err, "not supported on this platform (IP_TOS undefined)");
|
memprintf(err, "not supported on this platform (IP_TOS undefined)");
|
||||||
|
Loading…
Reference in New Issue
Block a user