MINOR: tcp_sample: Move TCP low level sample fetch function to control layer

Add ->get_info() new control layer callback definition to protocol struct to
retreive statiscal counters information at transport layer (TCPv4/TCPv6) identified by
an integer into a long long int.
Move the TCP specific code from get_tcp_info() to the tcp_get_info() control layer
function (src/proto_tcp.c) and define it as  the ->get_info() callback for
TCPv4 and TCPv6.
Note that get_tcp_info() is called for several TCP sample fetches.
This patch is useful to support some of these sample fetches for QUIC and to
keep the code simple and easy to maintain.
This commit is contained in:
Frederic Lecaille 2024-07-30 15:21:43 +02:00
parent bba6baff30
commit 1733dff42a
3 changed files with 71 additions and 49 deletions

View File

@ -142,6 +142,7 @@ struct protocol {
/* default I/O handler */ /* default I/O handler */
void (*default_iocb)(int fd); /* generic I/O handler (typically accept callback) */ void (*default_iocb)(int fd); /* generic I/O handler (typically accept callback) */
int (*get_info)(struct connection *conn, long long int *info, int info_num); /* Callback to get connection level statistical counters */
uint flags; /* flags describing protocol support (PROTO_F_*) */ uint flags; /* flags describing protocol support (PROTO_F_*) */
uint nb_receivers; /* number of receivers (under proto_lock) */ uint nb_receivers; /* number of receivers (under proto_lock) */

View File

@ -10,6 +10,11 @@
* *
*/ */
/* this is to have tcp_info defined on systems using musl
* library, such as Alpine Linux.
*/
#define _GNU_SOURCE
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
@ -48,6 +53,7 @@ static int tcp_suspend_receiver(struct receiver *rx);
static int tcp_resume_receiver(struct receiver *rx); static int tcp_resume_receiver(struct receiver *rx);
static void tcp_enable_listener(struct listener *listener); static void tcp_enable_listener(struct listener *listener);
static void tcp_disable_listener(struct listener *listener); static void tcp_disable_listener(struct listener *listener);
static int tcp_get_info(struct connection *conn, long long int *info, int info_num);
/* Note: must not be declared <const> as its list will be overwritten */ /* Note: must not be declared <const> as its list will be overwritten */
struct protocol proto_tcpv4 = { struct protocol proto_tcpv4 = {
@ -69,6 +75,7 @@ struct protocol proto_tcpv4 = {
.drain = sock_drain, .drain = sock_drain,
.check_events = sock_check_events, .check_events = sock_check_events,
.ignore_events = sock_ignore_events, .ignore_events = sock_ignore_events,
.get_info = tcp_get_info,
/* binding layer */ /* binding layer */
.rx_suspend = tcp_suspend_receiver, .rx_suspend = tcp_suspend_receiver,
@ -115,6 +122,7 @@ struct protocol proto_tcpv6 = {
.drain = sock_drain, .drain = sock_drain,
.check_events = sock_check_events, .check_events = sock_check_events,
.ignore_events = sock_ignore_events, .ignore_events = sock_ignore_events,
.get_info = tcp_get_info,
/* binding layer */ /* binding layer */
.rx_suspend = tcp_suspend_receiver, .rx_suspend = tcp_suspend_receiver,
@ -771,6 +779,64 @@ static int tcp_resume_receiver(struct receiver *rx)
return -1; return -1;
} }
#ifdef TCP_INFO
/* Returns some tcp_info data if it's available for <conn> connection into <*info>.
* "info_num" represents the required value.
* If the function fails it returns 0, otherwise it returns 1 and "result" is filled.
*/
static int tcp_get_info(struct connection *conn, long long int *info, int info_num)
{
struct tcp_info tcp_info;
socklen_t optlen;
/* The fd may not be available for the tcp_info struct, and the
syscal can fail. */
optlen = sizeof(tcp_info);
if ((conn->flags & CO_FL_FDLESS) ||
getsockopt(conn->handle.fd, IPPROTO_TCP, TCP_INFO, &tcp_info, &optlen) == -1)
return 0;
switch (info_num) {
#if defined(__APPLE__)
case 0: *info = tcp_info.tcpi_rttcur; break;
case 1: *info = tcp_info.tcpi_rttvar; break;
case 2: *info = tcp_info.tcpi_tfo_syn_data_acked; break;
case 4: *info = tcp_info.tcpi_tfo_syn_loss; break;
case 5: *info = tcp_info.tcpi_rto; break;
#else
/* all other platforms supporting TCP_INFO have these ones */
case 0: *info = tcp_info.tcpi_rtt; break;
case 1: *info = tcp_info.tcpi_rttvar; break;
# if defined(__linux__)
/* these ones are common to all Linux versions */
case 2: *info = tcp_info.tcpi_unacked; break;
case 3: *info = tcp_info.tcpi_sacked; break;
case 4: *info = tcp_info.tcpi_lost; break;
case 5: *info = tcp_info.tcpi_retrans; break;
case 6: *info = tcp_info.tcpi_fackets; break;
case 7: *info = tcp_info.tcpi_reordering; break;
# elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
/* the ones are found on FreeBSD, NetBSD and OpenBSD featuring TCP_INFO */
case 2: *info = tcp_info.__tcpi_unacked; break;
case 3: *info = tcp_info.__tcpi_sacked; break;
case 4: *info = tcp_info.__tcpi_lost; break;
case 5: *info = tcp_info.__tcpi_retrans; break;
case 6: *info = tcp_info.__tcpi_fackets; break;
case 7: *info = tcp_info.__tcpi_reordering; break;
# endif
#endif // apple
default: return 0;
}
return 1;
}
#else
static int tcp_get_info(struct connection *conn, long long int *info, int info_num)
{
return 0;
}
#endif /* TCP_INFO */
/* /*
* Local variables: * Local variables:

View File

@ -10,11 +10,6 @@
* *
*/ */
/* this is to have tcp_info defined on systems using musl
* library, such as Alpine Linux.
*/
#define _GNU_SOURCE
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
@ -314,61 +309,21 @@ static inline int get_tcp_info(const struct arg *args, struct sample *smp,
int dir, int val) int dir, int val)
{ {
struct connection *conn; struct connection *conn;
struct tcp_info info;
socklen_t optlen;
/* strm can be null. */ /* strm can be null. */
if (!smp->strm) if (!smp->strm)
return 0; return 0;
smp->data.type = SMP_T_SINT;
/* get the object associated with the stream connector.The /* get the object associated with the stream connector.The
* object can be other thing than a connection. For example, * object can be other thing than a connection. For example,
* it be a appctx. * it could be an appctx.
*/ */
conn = (dir == 0 ? sc_conn(smp->strm->scf) : sc_conn(smp->strm->scb)); conn = (dir == 0 ? sc_conn(smp->strm->scf) : sc_conn(smp->strm->scb));
if (!conn) if (!conn || !conn->ctrl->get_info ||
!conn->ctrl->get_info(conn, &smp->data.u.sint, val))
return 0; return 0;
/* The fd may not be available for the tcp_info struct, and the
syscal can fail. */
optlen = sizeof(info);
if ((conn->flags & CO_FL_FDLESS) ||
getsockopt(conn->handle.fd, IPPROTO_TCP, TCP_INFO, &info, &optlen) == -1)
return 0;
/* extract the value. */
smp->data.type = SMP_T_SINT;
switch (val) {
#if defined(__APPLE__)
case 0: smp->data.u.sint = info.tcpi_rttcur; break;
case 1: smp->data.u.sint = info.tcpi_rttvar; break;
case 2: smp->data.u.sint = info.tcpi_tfo_syn_data_acked; break;
case 4: smp->data.u.sint = info.tcpi_tfo_syn_loss; break;
case 5: smp->data.u.sint = info.tcpi_rto; break;
#else
/* all other platforms supporting TCP_INFO have these ones */
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__) || defined(__OpenBSD__)
/* the ones are found on FreeBSD, NetBSD and OpenBSD 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
#endif // apple
default: return 0;
}
return 1; return 1;
} }