]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: tcp_sample: Move TCP low level sample fetch function to control layer
authorFrederic Lecaille <flecaille@haproxy.com>
Tue, 30 Jul 2024 13:21:43 +0000 (15:21 +0200)
committerFrederic Lecaille <flecaille@haproxy.com>
Wed, 31 Jul 2024 08:29:42 +0000 (10:29 +0200)
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.

include/haproxy/protocol-t.h
src/proto_tcp.c
src/tcp_sample.c

index 7c59fcac9b1f37e2bbbf86a5028d10aa4627050b..fde7590a48fb68d38f4288d74406821b6b3d6ed7 100644 (file)
@@ -142,6 +142,7 @@ struct protocol {
 
        /* default I/O handler */
        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 nb_receivers;                              /* number of receivers (under proto_lock) */
index 63be7750831b48ef282933f621a74c3ef0950339..faa26de3a482149c753cd376ec70c8c6c0a92acf 100644 (file)
  *
  */
 
+/* this is to have tcp_info defined on systems using musl
+ * library, such as Alpine Linux.
+ */
+#define _GNU_SOURCE
+
 #include <ctype.h>
 #include <errno.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 void tcp_enable_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 */
 struct protocol proto_tcpv4 = {
@@ -69,6 +75,7 @@ struct protocol proto_tcpv4 = {
        .drain          = sock_drain,
        .check_events   = sock_check_events,
        .ignore_events  = sock_ignore_events,
+       .get_info       = tcp_get_info,
 
        /* binding layer */
        .rx_suspend     = tcp_suspend_receiver,
@@ -115,6 +122,7 @@ struct protocol proto_tcpv6 = {
        .drain          = sock_drain,
        .check_events   = sock_check_events,
        .ignore_events  = sock_ignore_events,
+       .get_info       = tcp_get_info,
 
        /* binding layer */
        .rx_suspend     = tcp_suspend_receiver,
@@ -771,6 +779,64 @@ static int tcp_resume_receiver(struct receiver *rx)
        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:
index 9fbf920a258ba375ebd4fdcf0f925f263cf67025..8e4eb5feb0210a1730fcba8c3cb47b7a518d83b7 100644 (file)
  *
  */
 
-/* this is to have tcp_info defined on systems using musl
- * library, such as Alpine Linux.
- */
-#define _GNU_SOURCE
-
 #include <ctype.h>
 #include <errno.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)
 {
        struct connection *conn;
-       struct tcp_info info;
-       socklen_t optlen;
 
        /* strm can be null. */
        if (!smp->strm)
                return 0;
 
+       smp->data.type = SMP_T_SINT;
        /* get the object associated with the stream connector.The
         * 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));
-       if (!conn)
+       if (!conn || !conn->ctrl->get_info ||
+           !conn->ctrl->get_info(conn, &smp->data.u.sint, val))
                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;
 }