From: Willy Tarreau Date: Fri, 28 Aug 2020 09:37:21 +0000 (+0200) Subject: REORG: tcp: move TCP sample fetches from proto_tcp.c to tcp_sample.c X-Git-Tag: v2.3-dev4~64 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8987e7a8c90caf7b9877424432c36902451ad310;p=thirdparty%2Fhaproxy.git REORG: tcp: move TCP sample fetches from proto_tcp.c to tcp_sample.c Let's continue the cleanup and get rid of all sample fetch functions from proto_tcp.c. They're now moved to tcp_sample.c, just as was done for ssl before 2.2 release. Nothing has changed beyond this. --- diff --git a/Makefile b/Makefile index be916a94c0..42b37426af 100644 --- a/Makefile +++ b/Makefile @@ -810,7 +810,7 @@ OBJS = src/mux_fcgi.o src/mux_h1.o src/mux_h2.o src/backend.o \ src/xxhash.o src/mworker-prog.o src/h1_htx.o src/frontend.o \ src/extcheck.o src/channel.o src/action.o src/mailers.o \ src/tcp_act.o src/proto_sockpair.o src/ebmbtree.o src/thread.o \ - src/lb_fwrr.o src/time.o src/regex.o src/lb_fwlc.o \ + src/tcp_sample.o src/lb_fwrr.o src/time.o src/regex.o src/lb_fwlc.o \ src/htx.o src/h2.o src/hpack-tbl.o src/lru.o src/wdt.o \ src/lb_map.o src/eb32sctree.o src/ebistree.o src/h1.o \ src/sha1.o src/http.o src/fd.o src/ev_select.o src/chunk.o \ diff --git a/src/proto_tcp.c b/src/proto_tcp.c index b4e13fab0f..ebe1aad2d3 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -10,11 +10,6 @@ * */ -/* this is to have tcp_info defined on systems using musl - * library, such as Alpine Linux - */ -#define _GNU_SOURCE - #include #include #include @@ -32,12 +27,10 @@ #include #include -#include #include #include #include #include -#include #include #include #include @@ -46,10 +39,7 @@ #include #include #include -#include #include -#include -#include #include @@ -1206,344 +1196,6 @@ int tcp_pause_listener(struct listener *l) return 1; } -/************************************************************************/ -/* All supported sample fetch functions must be declared here */ -/************************************************************************/ - -/* fetch the connection's source IPv4/IPv6 address */ -static int -smp_fetch_src(const struct arg *args, struct sample *smp, const char *kw, void *private) -{ - struct connection *cli_conn = objt_conn(smp->sess->origin); - - if (!cli_conn) - return 0; - - if (!conn_get_src(cli_conn)) - return 0; - - switch (cli_conn->src->ss_family) { - case AF_INET: - smp->data.u.ipv4 = ((struct sockaddr_in *)cli_conn->src)->sin_addr; - smp->data.type = SMP_T_IPV4; - break; - case AF_INET6: - smp->data.u.ipv6 = ((struct sockaddr_in6 *)cli_conn->src)->sin6_addr; - smp->data.type = SMP_T_IPV6; - break; - default: - return 0; - } - - smp->flags = 0; - return 1; -} - -/* set temp integer to the connection's source port */ -static int -smp_fetch_sport(const struct arg *args, struct sample *smp, const char *k, void *private) -{ - struct connection *cli_conn = objt_conn(smp->sess->origin); - - if (!cli_conn) - return 0; - - if (!conn_get_src(cli_conn)) - return 0; - - smp->data.type = SMP_T_SINT; - if (!(smp->data.u.sint = get_host_port(cli_conn->src))) - return 0; - - smp->flags = 0; - return 1; -} - -/* fetch the connection's destination IPv4/IPv6 address */ -static int -smp_fetch_dst(const struct arg *args, struct sample *smp, const char *kw, void *private) -{ - struct connection *cli_conn = objt_conn(smp->sess->origin); - - if (!cli_conn) - return 0; - - if (!conn_get_dst(cli_conn)) - return 0; - - switch (cli_conn->dst->ss_family) { - case AF_INET: - smp->data.u.ipv4 = ((struct sockaddr_in *)cli_conn->dst)->sin_addr; - smp->data.type = SMP_T_IPV4; - break; - case AF_INET6: - smp->data.u.ipv6 = ((struct sockaddr_in6 *)cli_conn->dst)->sin6_addr; - smp->data.type = SMP_T_IPV6; - break; - default: - return 0; - } - - smp->flags = 0; - return 1; -} - -/* check if the destination address of the front connection is local to the - * system or if it was intercepted. - */ -int smp_fetch_dst_is_local(const struct arg *args, struct sample *smp, const char *kw, void *private) -{ - struct connection *conn = objt_conn(smp->sess->origin); - struct listener *li = smp->sess->listener; - - if (!conn) - return 0; - - if (!conn_get_dst(conn)) - return 0; - - smp->data.type = SMP_T_BOOL; - smp->flags = 0; - smp->data.u.sint = addr_is_local(li->netns, conn->dst); - return smp->data.u.sint >= 0; -} - -/* check if the source address of the front connection is local to the system - * or not. - */ -int smp_fetch_src_is_local(const struct arg *args, struct sample *smp, const char *kw, void *private) -{ - struct connection *conn = objt_conn(smp->sess->origin); - struct listener *li = smp->sess->listener; - - if (!conn) - return 0; - - if (!conn_get_src(conn)) - return 0; - - smp->data.type = SMP_T_BOOL; - smp->flags = 0; - smp->data.u.sint = addr_is_local(li->netns, conn->src); - return smp->data.u.sint >= 0; -} - -/* set temp integer to the frontend connexion's destination port */ -static int -smp_fetch_dport(const struct arg *args, struct sample *smp, const char *kw, void *private) -{ - struct connection *cli_conn = objt_conn(smp->sess->origin); - - if (!cli_conn) - return 0; - - if (!conn_get_dst(cli_conn)) - return 0; - - smp->data.type = SMP_T_SINT; - if (!(smp->data.u.sint = get_host_port(cli_conn->dst))) - return 0; - - smp->flags = 0; - return 1; -} - -#ifdef TCP_INFO - - -/* Validates the arguments passed to "fc_*" fetch keywords returning a time - * value. These keywords support an optional string representing the unit of the - * result: "us" for microseconds and "ms" for milliseconds". Returns 0 on error - * and non-zero if OK. - */ -static int val_fc_time_value(struct arg *args, char **err) -{ - if (args[0].type == ARGT_STR) { - if (strcmp(args[0].data.str.area, "us") == 0) { - chunk_destroy(&args[0].data.str); - args[0].type = ARGT_SINT; - args[0].data.sint = TIME_UNIT_US; - } - else if (strcmp(args[0].data.str.area, "ms") == 0) { - chunk_destroy(&args[0].data.str); - args[0].type = ARGT_SINT; - args[0].data.sint = TIME_UNIT_MS; - } - else { - memprintf(err, "expects 'us' or 'ms', got '%s'", - args[0].data.str.area); - return 0; - } - } - else { - memprintf(err, "Unexpected arg type"); - return 0; - } - - return 1; -} - -/* Validates the arguments passed to "fc_*" fetch keywords returning a - * counter. These keywords should be used without any keyword, but because of a - * bug in previous versions, an optional string argument may be passed. In such - * case, the argument is ignored and a warning is emitted. Returns 0 on error - * and non-zero if OK. - */ -static int var_fc_counter(struct arg *args, char **err) -{ - if (args[0].type != ARGT_STOP) { - ha_warning("no argument supported for 'fc_*' sample expressions returning counters.\n"); - if (args[0].type == ARGT_STR) - chunk_destroy(&args[0].data.str); - args[0].type = ARGT_STOP; - } - - return 1; -} - -/* Returns some tcp_info data if it's available. "dir" must be set to 0 if - * the client connection is required, otherwise it is set to 1. "val" represents - * the required value. - * If the function fails it returns 0, otherwise it returns 1 and "result" is filled. - */ -static inline int get_tcp_info(const struct arg *args, struct sample *smp, - int dir, int val) -{ - struct connection *conn; - struct tcp_info info; - socklen_t optlen; - - /* strm can be null. */ - if (!smp->strm) - return 0; - - /* get the object associated with the stream interface.The - * object can be other thing than a connection. For example, - * it be a appctx. */ - conn = cs_conn(objt_cs(smp->strm->si[dir].end)); - if (!conn) - return 0; - - /* The fd may not be available for the tcp_info struct, and the - syscal can fail. */ - optlen = sizeof(info); - if (getsockopt(conn->handle.fd, SOL_TCP, TCP_INFO, &info, &optlen) == -1) - return 0; - - /* extract the value. */ - smp->data.type = SMP_T_SINT; - switch (val) { - case 0: smp->data.u.sint = info.tcpi_rtt; break; - case 1: smp->data.u.sint = info.tcpi_rttvar; break; -#if defined(__linux__) - /* these ones are common to all Linux versions */ - case 2: smp->data.u.sint = info.tcpi_unacked; break; - case 3: smp->data.u.sint = info.tcpi_sacked; break; - case 4: smp->data.u.sint = info.tcpi_lost; break; - case 5: smp->data.u.sint = info.tcpi_retrans; break; - case 6: smp->data.u.sint = info.tcpi_fackets; break; - case 7: smp->data.u.sint = info.tcpi_reordering; break; -#elif defined(__FreeBSD__) || defined(__NetBSD__) - /* the ones are found on FreeBSD and NetBSD featuring TCP_INFO */ - case 2: smp->data.u.sint = info.__tcpi_unacked; break; - case 3: smp->data.u.sint = info.__tcpi_sacked; break; - case 4: smp->data.u.sint = info.__tcpi_lost; break; - case 5: smp->data.u.sint = info.__tcpi_retrans; break; - case 6: smp->data.u.sint = info.__tcpi_fackets; break; - case 7: smp->data.u.sint = info.__tcpi_reordering; break; -#endif - default: return 0; - } - - return 1; -} - -/* get the mean rtt of a client connection */ -static int -smp_fetch_fc_rtt(const struct arg *args, struct sample *smp, const char *kw, void *private) -{ - if (!get_tcp_info(args, smp, 0, 0)) - return 0; - - /* By default or if explicitly specified, convert rtt to ms */ - if (!args || args[0].type == ARGT_STOP || args[0].data.sint == TIME_UNIT_MS) - smp->data.u.sint = (smp->data.u.sint + 500) / 1000; - - return 1; -} - -/* get the variance of the mean rtt of a client connection */ -static int -smp_fetch_fc_rttvar(const struct arg *args, struct sample *smp, const char *kw, void *private) -{ - if (!get_tcp_info(args, smp, 0, 1)) - return 0; - - /* By default or if explicitly specified, convert rttvar to ms */ - if (!args || args[0].type == ARGT_STOP || args[0].data.sint == TIME_UNIT_MS) - smp->data.u.sint = (smp->data.u.sint + 500) / 1000; - - return 1; -} - -#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) - -/* get the unacked counter on a client connection */ -static int -smp_fetch_fc_unacked(const struct arg *args, struct sample *smp, const char *kw, void *private) -{ - if (!get_tcp_info(args, smp, 0, 2)) - return 0; - return 1; -} - -/* get the sacked counter on a client connection */ -static int -smp_fetch_fc_sacked(const struct arg *args, struct sample *smp, const char *kw, void *private) -{ - if (!get_tcp_info(args, smp, 0, 3)) - return 0; - return 1; -} - -/* get the lost counter on a client connection */ -static int -smp_fetch_fc_lost(const struct arg *args, struct sample *smp, const char *kw, void *private) -{ - if (!get_tcp_info(args, smp, 0, 4)) - return 0; - return 1; -} - -/* get the retrans counter on a client connection */ -static int -smp_fetch_fc_retrans(const struct arg *args, struct sample *smp, const char *kw, void *private) -{ - if (!get_tcp_info(args, smp, 0, 5)) - return 0; - return 1; -} - -/* get the fackets counter on a client connection */ -static int -smp_fetch_fc_fackets(const struct arg *args, struct sample *smp, const char *kw, void *private) -{ - if (!get_tcp_info(args, smp, 0, 6)) - return 0; - return 1; -} - -/* get the reordering counter on a client connection */ -static int -smp_fetch_fc_reordering(const struct arg *args, struct sample *smp, const char *kw, void *private) -{ - if (!get_tcp_info(args, smp, 0, 7)) - return 0; - return 1; -} -#endif // linux || freebsd || netbsd -#endif // TCP_INFO - #ifdef IPV6_V6ONLY /* parse the "v4v6" bind keyword */ static int bind_parse_v4v6(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) @@ -1766,35 +1418,6 @@ static int srv_parse_tcp_ut(char **args, int *cur_arg, struct proxy *px, struct #endif -/* Note: must not be declared as its list will be overwritten. - * Note: fetches that may return multiple types must be declared as the lowest - * common denominator, the type that can be casted into all other ones. For - * instance v4/v6 must be declared v4. - */ -static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, { - { "dst", smp_fetch_dst, 0, NULL, SMP_T_IPV4, SMP_USE_L4CLI }, - { "dst_is_local", smp_fetch_dst_is_local, 0, NULL, SMP_T_BOOL, SMP_USE_L4CLI }, - { "dst_port", smp_fetch_dport, 0, NULL, SMP_T_SINT, SMP_USE_L4CLI }, - { "src", smp_fetch_src, 0, NULL, SMP_T_IPV4, SMP_USE_L4CLI }, - { "src_is_local", smp_fetch_src_is_local, 0, NULL, SMP_T_BOOL, SMP_USE_L4CLI }, - { "src_port", smp_fetch_sport, 0, NULL, SMP_T_SINT, SMP_USE_L4CLI }, -#ifdef TCP_INFO - { "fc_rtt", smp_fetch_fc_rtt, ARG1(0,STR), val_fc_time_value, SMP_T_SINT, SMP_USE_L4CLI }, - { "fc_rttvar", smp_fetch_fc_rttvar, ARG1(0,STR), val_fc_time_value, SMP_T_SINT, SMP_USE_L4CLI }, -#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) - { "fc_unacked", smp_fetch_fc_unacked, ARG1(0,STR), var_fc_counter, SMP_T_SINT, SMP_USE_L4CLI }, - { "fc_sacked", smp_fetch_fc_sacked, ARG1(0,STR), var_fc_counter, SMP_T_SINT, SMP_USE_L4CLI }, - { "fc_retrans", smp_fetch_fc_retrans, ARG1(0,STR), var_fc_counter, SMP_T_SINT, SMP_USE_L4CLI }, - { "fc_fackets", smp_fetch_fc_fackets, ARG1(0,STR), var_fc_counter, SMP_T_SINT, SMP_USE_L4CLI }, - { "fc_lost", smp_fetch_fc_lost, ARG1(0,STR), var_fc_counter, SMP_T_SINT, SMP_USE_L4CLI }, - { "fc_reordering", smp_fetch_fc_reordering, ARG1(0,STR), var_fc_counter, SMP_T_SINT, SMP_USE_L4CLI }, -#endif // linux || freebsd || netbsd -#endif // TCP_INFO - { /* END */ }, -}}; - -INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords); - /************************************************************************/ /* All supported bind keywords must be declared here. */ /************************************************************************/ diff --git a/src/tcp_sample.c b/src/tcp_sample.c new file mode 100644 index 0000000000..5f1aa1f956 --- /dev/null +++ b/src/tcp_sample.c @@ -0,0 +1,415 @@ +/* + * AF_INET/AF_INET6 SOCK_STREAM protocol layer (tcp) + * + * Copyright 2000-2013 Willy Tarreau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +/* this is to have tcp_info defined on systems using musl + * library, such as Alpine Linux. + */ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Fetch the connection's source IPv4/IPv6 address. Note that this is also + * directly called by stick_table.c and as such must remain publicly visible. + */ +static int +smp_fetch_src(const struct arg *args, struct sample *smp, const char *kw, void *private) +{ + struct connection *cli_conn = objt_conn(smp->sess->origin); + + if (!cli_conn) + return 0; + + if (!conn_get_src(cli_conn)) + return 0; + + switch (cli_conn->src->ss_family) { + case AF_INET: + smp->data.u.ipv4 = ((struct sockaddr_in *)cli_conn->src)->sin_addr; + smp->data.type = SMP_T_IPV4; + break; + case AF_INET6: + smp->data.u.ipv6 = ((struct sockaddr_in6 *)cli_conn->src)->sin6_addr; + smp->data.type = SMP_T_IPV6; + break; + default: + return 0; + } + + smp->flags = 0; + return 1; +} + +/* set temp integer to the connection's source port */ +static int +smp_fetch_sport(const struct arg *args, struct sample *smp, const char *k, void *private) +{ + struct connection *cli_conn = objt_conn(smp->sess->origin); + + if (!cli_conn) + return 0; + + if (!conn_get_src(cli_conn)) + return 0; + + smp->data.type = SMP_T_SINT; + if (!(smp->data.u.sint = get_host_port(cli_conn->src))) + return 0; + + smp->flags = 0; + return 1; +} + +/* fetch the connection's destination IPv4/IPv6 address */ +static int +smp_fetch_dst(const struct arg *args, struct sample *smp, const char *kw, void *private) +{ + struct connection *cli_conn = objt_conn(smp->sess->origin); + + if (!cli_conn) + return 0; + + if (!conn_get_dst(cli_conn)) + return 0; + + switch (cli_conn->dst->ss_family) { + case AF_INET: + smp->data.u.ipv4 = ((struct sockaddr_in *)cli_conn->dst)->sin_addr; + smp->data.type = SMP_T_IPV4; + break; + case AF_INET6: + smp->data.u.ipv6 = ((struct sockaddr_in6 *)cli_conn->dst)->sin6_addr; + smp->data.type = SMP_T_IPV6; + break; + default: + return 0; + } + + smp->flags = 0; + return 1; +} + +/* check if the destination address of the front connection is local to the + * system or if it was intercepted. + */ +int smp_fetch_dst_is_local(const struct arg *args, struct sample *smp, const char *kw, void *private) +{ + struct connection *conn = objt_conn(smp->sess->origin); + struct listener *li = smp->sess->listener; + + if (!conn) + return 0; + + if (!conn_get_dst(conn)) + return 0; + + smp->data.type = SMP_T_BOOL; + smp->flags = 0; + smp->data.u.sint = addr_is_local(li->netns, conn->dst); + return smp->data.u.sint >= 0; +} + +/* check if the source address of the front connection is local to the system + * or not. + */ +int smp_fetch_src_is_local(const struct arg *args, struct sample *smp, const char *kw, void *private) +{ + struct connection *conn = objt_conn(smp->sess->origin); + struct listener *li = smp->sess->listener; + + if (!conn) + return 0; + + if (!conn_get_src(conn)) + return 0; + + smp->data.type = SMP_T_BOOL; + smp->flags = 0; + smp->data.u.sint = addr_is_local(li->netns, conn->src); + return smp->data.u.sint >= 0; +} + +/* set temp integer to the frontend connexion's destination port */ +static int +smp_fetch_dport(const struct arg *args, struct sample *smp, const char *kw, void *private) +{ + struct connection *cli_conn = objt_conn(smp->sess->origin); + + if (!cli_conn) + return 0; + + if (!conn_get_dst(cli_conn)) + return 0; + + smp->data.type = SMP_T_SINT; + if (!(smp->data.u.sint = get_host_port(cli_conn->dst))) + return 0; + + smp->flags = 0; + return 1; +} + +#ifdef TCP_INFO + + +/* Validates the arguments passed to "fc_*" fetch keywords returning a time + * value. These keywords support an optional string representing the unit of the + * result: "us" for microseconds and "ms" for milliseconds". Returns 0 on error + * and non-zero if OK. + */ +static int val_fc_time_value(struct arg *args, char **err) +{ + if (args[0].type == ARGT_STR) { + if (strcmp(args[0].data.str.area, "us") == 0) { + chunk_destroy(&args[0].data.str); + args[0].type = ARGT_SINT; + args[0].data.sint = TIME_UNIT_US; + } + else if (strcmp(args[0].data.str.area, "ms") == 0) { + chunk_destroy(&args[0].data.str); + args[0].type = ARGT_SINT; + args[0].data.sint = TIME_UNIT_MS; + } + else { + memprintf(err, "expects 'us' or 'ms', got '%s'", + args[0].data.str.area); + return 0; + } + } + else { + memprintf(err, "Unexpected arg type"); + return 0; + } + + return 1; +} + +/* Validates the arguments passed to "fc_*" fetch keywords returning a + * counter. These keywords should be used without any keyword, but because of a + * bug in previous versions, an optional string argument may be passed. In such + * case, the argument is ignored and a warning is emitted. Returns 0 on error + * and non-zero if OK. + */ +static int var_fc_counter(struct arg *args, char **err) +{ + if (args[0].type != ARGT_STOP) { + ha_warning("no argument supported for 'fc_*' sample expressions returning counters.\n"); + if (args[0].type == ARGT_STR) + chunk_destroy(&args[0].data.str); + args[0].type = ARGT_STOP; + } + + return 1; +} + +/* Returns some tcp_info data if it's available. "dir" must be set to 0 if + * the client connection is required, otherwise it is set to 1. "val" represents + * the required value. + * If the function fails it returns 0, otherwise it returns 1 and "result" is filled. + */ +static inline int get_tcp_info(const struct arg *args, struct sample *smp, + int dir, int val) +{ + struct connection *conn; + struct tcp_info info; + socklen_t optlen; + + /* strm can be null. */ + if (!smp->strm) + return 0; + + /* get the object associated with the stream interface.The + * object can be other thing than a connection. For example, + * it be a appctx. */ + conn = cs_conn(objt_cs(smp->strm->si[dir].end)); + if (!conn) + return 0; + + /* The fd may not be available for the tcp_info struct, and the + syscal can fail. */ + optlen = sizeof(info); + if (getsockopt(conn->handle.fd, SOL_TCP, TCP_INFO, &info, &optlen) == -1) + return 0; + + /* extract the value. */ + smp->data.type = SMP_T_SINT; + switch (val) { + case 0: smp->data.u.sint = info.tcpi_rtt; break; + case 1: smp->data.u.sint = info.tcpi_rttvar; break; +#if defined(__linux__) + /* these ones are common to all Linux versions */ + case 2: smp->data.u.sint = info.tcpi_unacked; break; + case 3: smp->data.u.sint = info.tcpi_sacked; break; + case 4: smp->data.u.sint = info.tcpi_lost; break; + case 5: smp->data.u.sint = info.tcpi_retrans; break; + case 6: smp->data.u.sint = info.tcpi_fackets; break; + case 7: smp->data.u.sint = info.tcpi_reordering; break; +#elif defined(__FreeBSD__) || defined(__NetBSD__) + /* the ones are found on FreeBSD and NetBSD featuring TCP_INFO */ + case 2: smp->data.u.sint = info.__tcpi_unacked; break; + case 3: smp->data.u.sint = info.__tcpi_sacked; break; + case 4: smp->data.u.sint = info.__tcpi_lost; break; + case 5: smp->data.u.sint = info.__tcpi_retrans; break; + case 6: smp->data.u.sint = info.__tcpi_fackets; break; + case 7: smp->data.u.sint = info.__tcpi_reordering; break; +#endif + default: return 0; + } + + return 1; +} + +/* get the mean rtt of a client connection */ +static int +smp_fetch_fc_rtt(const struct arg *args, struct sample *smp, const char *kw, void *private) +{ + if (!get_tcp_info(args, smp, 0, 0)) + return 0; + + /* By default or if explicitly specified, convert rtt to ms */ + if (!args || args[0].type == ARGT_STOP || args[0].data.sint == TIME_UNIT_MS) + smp->data.u.sint = (smp->data.u.sint + 500) / 1000; + + return 1; +} + +/* get the variance of the mean rtt of a client connection */ +static int +smp_fetch_fc_rttvar(const struct arg *args, struct sample *smp, const char *kw, void *private) +{ + if (!get_tcp_info(args, smp, 0, 1)) + return 0; + + /* By default or if explicitly specified, convert rttvar to ms */ + if (!args || args[0].type == ARGT_STOP || args[0].data.sint == TIME_UNIT_MS) + smp->data.u.sint = (smp->data.u.sint + 500) / 1000; + + return 1; +} + +#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) + +/* get the unacked counter on a client connection */ +static int +smp_fetch_fc_unacked(const struct arg *args, struct sample *smp, const char *kw, void *private) +{ + if (!get_tcp_info(args, smp, 0, 2)) + return 0; + return 1; +} + +/* get the sacked counter on a client connection */ +static int +smp_fetch_fc_sacked(const struct arg *args, struct sample *smp, const char *kw, void *private) +{ + if (!get_tcp_info(args, smp, 0, 3)) + return 0; + return 1; +} + +/* get the lost counter on a client connection */ +static int +smp_fetch_fc_lost(const struct arg *args, struct sample *smp, const char *kw, void *private) +{ + if (!get_tcp_info(args, smp, 0, 4)) + return 0; + return 1; +} + +/* get the retrans counter on a client connection */ +static int +smp_fetch_fc_retrans(const struct arg *args, struct sample *smp, const char *kw, void *private) +{ + if (!get_tcp_info(args, smp, 0, 5)) + return 0; + return 1; +} + +/* get the fackets counter on a client connection */ +static int +smp_fetch_fc_fackets(const struct arg *args, struct sample *smp, const char *kw, void *private) +{ + if (!get_tcp_info(args, smp, 0, 6)) + return 0; + return 1; +} + +/* get the reordering counter on a client connection */ +static int +smp_fetch_fc_reordering(const struct arg *args, struct sample *smp, const char *kw, void *private) +{ + if (!get_tcp_info(args, smp, 0, 7)) + return 0; + return 1; +} +#endif // linux || freebsd || netbsd +#endif // TCP_INFO + +/* Note: must not be declared as its list will be overwritten. + * Note: fetches that may return multiple types must be declared as the lowest + * common denominator, the type that can be casted into all other ones. For + * instance v4/v6 must be declared v4. + */ +static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, { + { "dst", smp_fetch_dst, 0, NULL, SMP_T_IPV4, SMP_USE_L4CLI }, + { "dst_is_local", smp_fetch_dst_is_local, 0, NULL, SMP_T_BOOL, SMP_USE_L4CLI }, + { "dst_port", smp_fetch_dport, 0, NULL, SMP_T_SINT, SMP_USE_L4CLI }, + { "src", smp_fetch_src, 0, NULL, SMP_T_IPV4, SMP_USE_L4CLI }, + { "src_is_local", smp_fetch_src_is_local, 0, NULL, SMP_T_BOOL, SMP_USE_L4CLI }, + { "src_port", smp_fetch_sport, 0, NULL, SMP_T_SINT, SMP_USE_L4CLI }, +#ifdef TCP_INFO + { "fc_rtt", smp_fetch_fc_rtt, ARG1(0,STR), val_fc_time_value, SMP_T_SINT, SMP_USE_L4CLI }, + { "fc_rttvar", smp_fetch_fc_rttvar, ARG1(0,STR), val_fc_time_value, SMP_T_SINT, SMP_USE_L4CLI }, +#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) + { "fc_unacked", smp_fetch_fc_unacked, ARG1(0,STR), var_fc_counter, SMP_T_SINT, SMP_USE_L4CLI }, + { "fc_sacked", smp_fetch_fc_sacked, ARG1(0,STR), var_fc_counter, SMP_T_SINT, SMP_USE_L4CLI }, + { "fc_retrans", smp_fetch_fc_retrans, ARG1(0,STR), var_fc_counter, SMP_T_SINT, SMP_USE_L4CLI }, + { "fc_fackets", smp_fetch_fc_fackets, ARG1(0,STR), var_fc_counter, SMP_T_SINT, SMP_USE_L4CLI }, + { "fc_lost", smp_fetch_fc_lost, ARG1(0,STR), var_fc_counter, SMP_T_SINT, SMP_USE_L4CLI }, + { "fc_reordering", smp_fetch_fc_reordering, ARG1(0,STR), var_fc_counter, SMP_T_SINT, SMP_USE_L4CLI }, +#endif // linux || freebsd || netbsd +#endif // TCP_INFO + { /* END */ }, +}}; + +INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords); + + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * End: + */