<p>laforge <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/libosmocore/+/26454">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  laforge: Looks good to me, approved
  Jenkins Builder: Verified

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">select: gather statistics for TCP connections<br><br>osmocom applications are deployed in a variety of different situations.<br>Dependung on the medium that interconnects the network components<br>unexpected behaviour may occur. To debug problems with the<br>interconnection between network components it might help to monitor the<br>health of the related TCP connections.<br><br>Change-Id: I1416f95aff2adcf13689646b7574845de169fa3d<br>Related: SYS#5701<br>---<br>M configure.ac<br>M include/Makefile.am<br>A include/osmocom/core/stats_tcp.h<br>M src/Makefile.am<br>M src/select.c<br>M src/stats.c<br>A src/stats_tcp.c<br>M src/vty/stats_vty.c<br>M tests/stats/stats_vty_test.vty<br>9 files changed, 406 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/configure.ac b/configure.ac</span><br><span>index a69f793..8fb299b 100644</span><br><span>--- a/configure.ac</span><br><span>+++ b/configure.ac</span><br><span>@@ -516,6 +516,28 @@</span><br><span> CHECK_BUILTIN_SUPPORT([__builtin_cpu_supports],</span><br><span>   [Runtime SIMD detection will be disabled])</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+dnl There are some members in struct tcp_info that might not exist on all linux versions</span><br><span style="color: hsl(120, 100%, 40%);">+AC_CHECK_MEMBER([struct tcp_info.tcpi_rwnd_limited],</span><br><span style="color: hsl(120, 100%, 40%);">+             AC_DEFINE([HAVE_TCP_INFO_TCPI_RWND_LIMITED],</span><br><span style="color: hsl(120, 100%, 40%);">+          [1],</span><br><span style="color: hsl(120, 100%, 40%);">+          [Define to 1 if your <linux/tcp.h> header file have the tcpi_rwnd_limited member in struct tcp_info]),</span><br><span style="color: hsl(120, 100%, 40%);">+          [],</span><br><span style="color: hsl(120, 100%, 40%);">+           [#include <linux/tcp.h>])</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+AC_CHECK_MEMBER([struct tcp_info.tcpi_sndbuf_limited],</span><br><span style="color: hsl(120, 100%, 40%);">+             AC_DEFINE([HAVE_TCP_INFO_TCPI_SNDBUF_LIMITED],</span><br><span style="color: hsl(120, 100%, 40%);">+                [1],</span><br><span style="color: hsl(120, 100%, 40%);">+          [Define to 1 if your <linux/tcp.h> header file have the tcpi_sndbuf_limited member in struct tcp_info]),</span><br><span style="color: hsl(120, 100%, 40%);">+                [],</span><br><span style="color: hsl(120, 100%, 40%);">+           [#include <linux/tcp.h>])</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+AC_CHECK_MEMBER([struct tcp_info.tcpi_reord_seen],</span><br><span style="color: hsl(120, 100%, 40%);">+         AC_DEFINE([HAVE_TCP_INFO_TCPI_REORD_SEEN],</span><br><span style="color: hsl(120, 100%, 40%);">+            [1],</span><br><span style="color: hsl(120, 100%, 40%);">+          [Define to 1 if your <linux/tcp.h> header file have the tcpi_reord_seen member in struct tcp_info]),</span><br><span style="color: hsl(120, 100%, 40%);">+            [],</span><br><span style="color: hsl(120, 100%, 40%);">+           [#include <linux/tcp.h>])</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> AC_MSG_RESULT([CFLAGS="$CFLAGS"])</span><br><span> AC_MSG_RESULT([CPPFLAGS="$CPPFLAGS"])</span><br><span> </span><br><span>diff --git a/include/Makefile.am b/include/Makefile.am</span><br><span>index eab0489..a234014 100644</span><br><span>--- a/include/Makefile.am</span><br><span>+++ b/include/Makefile.am</span><br><span>@@ -46,6 +46,7 @@</span><br><span>                        osmocom/core/process.h \</span><br><span>                        osmocom/core/rate_ctr.h \</span><br><span>                        osmocom/core/stat_item.h \</span><br><span style="color: hsl(120, 100%, 40%);">+                       osmocom/core/stats_tcp.h \</span><br><span>                        osmocom/core/select.h \</span><br><span>                        osmocom/core/sercomm.h \</span><br><span>                        osmocom/core/signal.h \</span><br><span>diff --git a/include/osmocom/core/stats_tcp.h b/include/osmocom/core/stats_tcp.h</span><br><span>new file mode 100644</span><br><span>index 0000000..6b9657a</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/core/stats_tcp.h</span><br><span>@@ -0,0 +1,16 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define TCP_STATS_DEFAULT_INTERVAL 0 /* secs */</span><br><span style="color: hsl(120, 100%, 40%);">+#define TCP_STATS_DEFAULT_BATCH_SIZE 1      /* sockets per interval */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_tcp_stats_config {</span><br><span style="color: hsl(120, 100%, 40%);">+  /* poll interval in seconds, use osmo_stats_tcp_set_interval() to manipulate this value */</span><br><span style="color: hsl(120, 100%, 40%);">+    int interval;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* specify how many sockets are processed when the interval timer expires */</span><br><span style="color: hsl(120, 100%, 40%);">+  int batch_size;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+extern struct osmo_tcp_stats_config *osmo_tcp_stats_config;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_stats_tcp_osmo_fd_register(const struct osmo_fd *fd, const char *name);</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_stats_tcp_osmo_fd_unregister(const struct osmo_fd *fd);</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_stats_tcp_set_interval(int interval);</span><br><span>diff --git a/src/Makefile.am b/src/Makefile.am</span><br><span>index 4bda456..5777c31 100644</span><br><span>--- a/src/Makefile.am</span><br><span>+++ b/src/Makefile.am</span><br><span>@@ -22,6 +22,7 @@</span><br><span>                   conv.c application.c rbtree.c strrb.c \</span><br><span>                      loggingrb.c crc8gen.c crc16gen.c crc32gen.c crc64gen.c \</span><br><span>                     macaddr.c stat_item.c stats.c stats_statsd.c prim.c \</span><br><span style="color: hsl(120, 100%, 40%);">+                         stats_tcp.c \</span><br><span>                        conv_acc.c conv_acc_generic.c sercomm.c prbs.c \</span><br><span>                     isdnhdlc.c \</span><br><span>                         tdef.c \</span><br><span>diff --git a/src/select.c b/src/select.c</span><br><span>index 590c3db..b48d13e 100644</span><br><span>--- a/src/select.c</span><br><span>+++ b/src/select.c</span><br><span>@@ -33,6 +33,8 @@</span><br><span> #include <osmocom/core/logging.h></span><br><span> #include <osmocom/core/talloc.h></span><br><span> #include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/stat_item.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/stats_tcp.h></span><br><span> </span><br><span> #include "../config.h"</span><br><span> </span><br><span>@@ -181,6 +183,9 @@</span><br><span> #ifndef FORCE_IO_SELECT</span><br><span>  g_poll.num_registered--;</span><br><span> #endif /* FORCE_IO_SELECT */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* If existent, free any statistical data */</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_stats_tcp_osmo_fd_unregister(fd);</span><br><span> }</span><br><span> </span><br><span> /*! Close a file descriptor, mark it as closed + unregister from select loop abstraction</span><br><span>diff --git a/src/stats.c b/src/stats.c</span><br><span>index f8c91fd..4267284 100644</span><br><span>--- a/src/stats.c</span><br><span>+++ b/src/stats.c</span><br><span>@@ -85,6 +85,7 @@</span><br><span> #include <osmocom/core/select.h></span><br><span> #include <osmocom/core/counter.h></span><br><span> #include <osmocom/core/msgb.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/stats_tcp.h></span><br><span> </span><br><span> #ifdef HAVE_SYSTEMTAP</span><br><span> /* include the generated probes header and put markers in code */</span><br><span>@@ -240,6 +241,10 @@</span><br><span>    osmo_stats_ctx = ctx;</span><br><span>        is_initialised = 1;</span><br><span>  start_timer();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Make sure that the tcp-stats interval timer also runs at its</span><br><span style="color: hsl(120, 100%, 40%);">+        * preconfigured rate. The vty might change this setting later. */</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_stats_tcp_set_interval(osmo_tcp_stats_config->interval);</span><br><span> }</span><br><span> </span><br><span> /*! Find a stats_reporter of given \a type and \a name.</span><br><span>diff --git a/src/stats_tcp.c b/src/stats_tcp.c</span><br><span>new file mode 100644</span><br><span>index 0000000..fffb10a</span><br><span>--- /dev/null</span><br><span>+++ b/src/stats_tcp.c</span><br><span>@@ -0,0 +1,322 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2021 by sysmocom - s.f.m.c. GmbH</span><br><span style="color: hsl(120, 100%, 40%);">+ * Author: Philipp Maier <pmaier@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * SPDX-License-Identifier: GPL-2.0+</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 2 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \addtogroup stats</span><br><span style="color: hsl(120, 100%, 40%);">+ *  @{</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \file stats_tcp.c */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "config.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#if !defined(EMBEDDED)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/types.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/stat.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/socket.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <netinet/in.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <netinet/ip.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <linux/tcp.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <pthread.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/select.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/linuxlist.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/talloc.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/timer.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/stat_item.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/stats.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/socket.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/stats_tcp.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_tcp_stats_config s_tcp_stats_config = {</span><br><span style="color: hsl(120, 100%, 40%);">+      .interval = TCP_STATS_DEFAULT_INTERVAL,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_tcp_stats_config *osmo_tcp_stats_config = &s_tcp_stats_config;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_timer_list stats_tcp_poll_timer;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static LLIST_HEAD(stats_tcp);</span><br><span style="color: hsl(120, 100%, 40%);">+static struct stats_tcp_entry *stats_tcp_entry_cur;</span><br><span style="color: hsl(120, 100%, 40%);">+pthread_mutex_t stats_tcp_lock;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct stats_tcp_entry {</span><br><span style="color: hsl(120, 100%, 40%);">+       struct llist_head entry;</span><br><span style="color: hsl(120, 100%, 40%);">+      const struct osmo_fd *fd;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_stat_item_group *stats_tcp;</span><br><span style="color: hsl(120, 100%, 40%);">+       const char *name;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum {</span><br><span style="color: hsl(120, 100%, 40%);">+       STATS_TCP_UNACKED,</span><br><span style="color: hsl(120, 100%, 40%);">+    STATS_TCP_LOST,</span><br><span style="color: hsl(120, 100%, 40%);">+       STATS_TCP_RETRANS,</span><br><span style="color: hsl(120, 100%, 40%);">+    STATS_TCP_RTT,</span><br><span style="color: hsl(120, 100%, 40%);">+        STATS_TCP_RCV_RTT,</span><br><span style="color: hsl(120, 100%, 40%);">+    STATS_TCP_NOTSENT_BYTES,</span><br><span style="color: hsl(120, 100%, 40%);">+      STATS_TCP_RWND_LIMITED,</span><br><span style="color: hsl(120, 100%, 40%);">+       STATS_TCP_SNDBUF_LIMITED,</span><br><span style="color: hsl(120, 100%, 40%);">+     STATS_TCP_REORD_SEEN,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_stat_item_desc stats_tcp_item_desc[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+      [STATS_TCP_UNACKED] = { "tcp:unacked", "unacknowledged packets", "", 60, 0 },</span><br><span style="color: hsl(120, 100%, 40%);">+   [STATS_TCP_LOST] = { "tcp:lost", "lost packets", "", 60, 0 },</span><br><span style="color: hsl(120, 100%, 40%);">+   [STATS_TCP_RETRANS] = { "tcp:retrans", "retransmitted packets", "", 60, 0 },</span><br><span style="color: hsl(120, 100%, 40%);">+    [STATS_TCP_RTT] = { "tcp:rtt", "roundtrip-time", "", 60, 0 },</span><br><span style="color: hsl(120, 100%, 40%);">+   [STATS_TCP_RCV_RTT] = { "tcp:rcv_rtt", "roundtrip-time (receive)", "", 60, 0 },</span><br><span style="color: hsl(120, 100%, 40%);">+ [STATS_TCP_NOTSENT_BYTES] = { "tcp:notsent_bytes", "bytes not yet sent", "", 60, 0 },</span><br><span style="color: hsl(120, 100%, 40%);">+   [STATS_TCP_RWND_LIMITED] = { "tcp:rwnd_limited", "time (usec) limited by receive window", "", 60, 0 },</span><br><span style="color: hsl(120, 100%, 40%);">+  [STATS_TCP_SNDBUF_LIMITED] = { "tcp:sndbuf_limited", "Time (usec) limited by send buffer", "", 60, 0 },</span><br><span style="color: hsl(120, 100%, 40%);">+ [STATS_TCP_REORD_SEEN] = { "tcp:sndbuf_limited", "reordering events seen", "", 60, 0 },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_stat_item_group_desc stats_tcp_desc = {</span><br><span style="color: hsl(120, 100%, 40%);">+       .group_name_prefix = "tcp",</span><br><span style="color: hsl(120, 100%, 40%);">+ .group_description = "stats tcp",</span><br><span style="color: hsl(120, 100%, 40%);">+   .class_id = OSMO_STATS_CLASS_GLOBAL,</span><br><span style="color: hsl(120, 100%, 40%);">+  .num_items = ARRAY_SIZE(stats_tcp_item_desc),</span><br><span style="color: hsl(120, 100%, 40%);">+ .item_desc = stats_tcp_item_desc,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void fill_stats(struct stats_tcp_entry *stats_tcp_entry)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct tcp_info tcp_info;</span><br><span style="color: hsl(120, 100%, 40%);">+     socklen_t tcp_info_len = sizeof(tcp_info);</span><br><span style="color: hsl(120, 100%, 40%);">+    char stat_name[256];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Do not fill in anything before the socket is connected to a remote end */</span><br><span style="color: hsl(120, 100%, 40%);">+  if (osmo_sock_get_ip_and_port(stats_tcp_entry->fd->fd, NULL, 0, NULL, 0, false) != 0)</span><br><span style="color: hsl(120, 100%, 40%);">+           return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Gather TCP statistics and update the stats items */</span><br><span style="color: hsl(120, 100%, 40%);">+        rc = getsockopt(stats_tcp_entry->fd->fd, IPPROTO_TCP, TCP_INFO, &tcp_info, &tcp_info_len);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Create stats items if they do not exist yet */</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!stats_tcp_entry->stats_tcp) {</span><br><span style="color: hsl(120, 100%, 40%);">+         stats_tcp_entry->stats_tcp =</span><br><span style="color: hsl(120, 100%, 40%);">+                   osmo_stat_item_group_alloc(stats_tcp_entry, &stats_tcp_desc, stats_tcp_entry->fd->fd);</span><br><span style="color: hsl(120, 100%, 40%);">+          OSMO_ASSERT(stats_tcp_entry->stats_tcp);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Update statistics */</span><br><span style="color: hsl(120, 100%, 40%);">+       if (stats_tcp_entry->name)</span><br><span style="color: hsl(120, 100%, 40%);">+         snprintf(stat_name, sizeof(stat_name), "%s,%s", stats_tcp_entry->name,</span><br><span style="color: hsl(120, 100%, 40%);">+                    osmo_sock_get_name2(stats_tcp_entry->fd->fd));</span><br><span style="color: hsl(120, 100%, 40%);">+ else</span><br><span style="color: hsl(120, 100%, 40%);">+          snprintf(stat_name, sizeof(stat_name), "%s", osmo_sock_get_name2(stats_tcp_entry->fd->fd));</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_stat_item_group_set_name(stats_tcp_entry->stats_tcp, stat_name);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_stat_item_set(osmo_stat_item_group_get_item(stats_tcp_entry->stats_tcp, STATS_TCP_UNACKED),</span><br><span style="color: hsl(120, 100%, 40%);">+                      tcp_info.tcpi_unacked);</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_stat_item_set(osmo_stat_item_group_get_item(stats_tcp_entry->stats_tcp, STATS_TCP_LOST),</span><br><span style="color: hsl(120, 100%, 40%);">+                         tcp_info.tcpi_lost);</span><br><span style="color: hsl(120, 100%, 40%);">+       osmo_stat_item_set(osmo_stat_item_group_get_item(stats_tcp_entry->stats_tcp, STATS_TCP_RETRANS),</span><br><span style="color: hsl(120, 100%, 40%);">+                      tcp_info.tcpi_retrans);</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_stat_item_set(osmo_stat_item_group_get_item(stats_tcp_entry->stats_tcp, STATS_TCP_RTT), tcp_info.tcpi_rtt);</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_stat_item_set(osmo_stat_item_group_get_item(stats_tcp_entry->stats_tcp, STATS_TCP_RCV_RTT),</span><br><span style="color: hsl(120, 100%, 40%);">+                      tcp_info.tcpi_rcv_rtt);</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_stat_item_set(osmo_stat_item_group_get_item(stats_tcp_entry->stats_tcp, STATS_TCP_NOTSENT_BYTES),</span><br><span style="color: hsl(120, 100%, 40%);">+                        tcp_info.tcpi_notsent_bytes);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#if HAVE_TCP_INFO_TCPI_RWND_LIMITED == 1</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_stat_item_set(osmo_stat_item_group_get_item(stats_tcp_entry->stats_tcp, STATS_TCP_RWND_LIMITED),</span><br><span style="color: hsl(120, 100%, 40%);">+                         tcp_info.tcpi_rwnd_limited);</span><br><span style="color: hsl(120, 100%, 40%);">+#else</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_stat_item_set(osmo_stat_item_group_get_item(stats_tcp_entry->stats_tcp, STATS_TCP_RWND_LIMITED), -1);</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#if STATS_TCP_SNDBUF_LIMITED == 1</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_stat_item_set(osmo_stat_item_group_get_item(stats_tcp_entry->stats_tcp, STATS_TCP_REORD_SEEN),</span><br><span style="color: hsl(120, 100%, 40%);">+                           tcp_info.tcpi_sndbuf_limited);</span><br><span style="color: hsl(120, 100%, 40%);">+#else</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_stat_item_set(osmo_stat_item_group_get_item(stats_tcp_entry->stats_tcp, STATS_TCP_REORD_SEEN), -1);</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#if HAVE_TCP_INFO_TCPI_REORD_SEEN == 1</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_stat_item_set(osmo_stat_item_group_get_item(stats_tcp_entry->stats_tcp, STATS_TCP_REORD_SEEN),</span><br><span style="color: hsl(120, 100%, 40%);">+                           tcp_info.tcpi_reord_seen);</span><br><span style="color: hsl(120, 100%, 40%);">+#else</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_stat_item_set(osmo_stat_item_group_get_item(stats_tcp_entry->stats_tcp, STATS_TCP_REORD_SEEN), -1);</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static bool is_tcp(const struct osmo_fd *fd)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct stat fd_stat;</span><br><span style="color: hsl(120, 100%, 40%);">+  int so_protocol = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+  socklen_t so_protocol_len = sizeof(so_protocol);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Is this a socket? */</span><br><span style="color: hsl(120, 100%, 40%);">+       rc = fstat(fd->fd, &fd_stat);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!S_ISSOCK(fd_stat.st_mode))</span><br><span style="color: hsl(120, 100%, 40%);">+               return false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* Is it a TCP socket? */</span><br><span style="color: hsl(120, 100%, 40%);">+     rc = getsockopt(fd->fd, SOL_SOCKET, SO_PROTOCOL, &so_protocol, &so_protocol_len);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (so_protocol == IPPROTO_TCP)</span><br><span style="color: hsl(120, 100%, 40%);">+               return true;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return false;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Register an osmo_fd for TCP stats monitoring.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] fd osmocom file descriptor to be registered.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] human readbla name that is used as prefix for the related stats item.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns 0 on success; negative in case of error. */</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_stats_tcp_osmo_fd_register(const struct osmo_fd *fd, const char *name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct stats_tcp_entry *stats_tcp_entry;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Only TCP sockets can be registered for monitoring, anything else will fall through. */</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!is_tcp(fd))</span><br><span style="color: hsl(120, 100%, 40%);">+              return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* When the osmo_fd is registered and unregistered properly there shouldn't be any leftovers from already closed</span><br><span style="color: hsl(120, 100%, 40%);">+   * osmo_fds in the stats_tcp list. But lets proactively make sure that any leftovers are cleaned up. */</span><br><span style="color: hsl(120, 100%, 40%);">+       osmo_stats_tcp_osmo_fd_unregister(fd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Make a new list object, attach the osmo_fd... */</span><br><span style="color: hsl(120, 100%, 40%);">+   stats_tcp_entry = talloc_zero(OTC_GLOBAL, struct stats_tcp_entry);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(stats_tcp_entry);</span><br><span style="color: hsl(120, 100%, 40%);">+ stats_tcp_entry->fd = fd;</span><br><span style="color: hsl(120, 100%, 40%);">+  stats_tcp_entry->name = talloc_strdup(stats_tcp_entry, name);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    pthread_mutex_lock(&stats_tcp_lock);</span><br><span style="color: hsl(120, 100%, 40%);">+      llist_add_tail(&stats_tcp_entry->entry, &stats_tcp);</span><br><span style="color: hsl(120, 100%, 40%);">+       pthread_mutex_unlock(&stats_tcp_lock);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void next_stats_tcp_entry(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct stats_tcp_entry *last;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (llist_empty(&stats_tcp)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            stats_tcp_entry_cur = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+           return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   last = (struct stats_tcp_entry *)llist_last_entry(&stats_tcp, struct stats_tcp_entry, entry);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!stats_tcp_entry_cur || stats_tcp_entry_cur == last)</span><br><span style="color: hsl(120, 100%, 40%);">+              stats_tcp_entry_cur =</span><br><span style="color: hsl(120, 100%, 40%);">+             (struct stats_tcp_entry *)llist_first_entry(&stats_tcp, struct stats_tcp_entry, entry);</span><br><span style="color: hsl(120, 100%, 40%);">+       else</span><br><span style="color: hsl(120, 100%, 40%);">+          stats_tcp_entry_cur =</span><br><span style="color: hsl(120, 100%, 40%);">+             (struct stats_tcp_entry *)llist_entry(stats_tcp_entry_cur->entry.next, struct stats_tcp_entry,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                   entry);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Register an osmo_fd for TCP stats monitoring.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] fd osmocom file descriptor to be unregistered.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns 0 on success; negative in case of error. */</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_stats_tcp_osmo_fd_unregister(const struct osmo_fd *fd)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct stats_tcp_entry *stats_tcp_entry;</span><br><span style="color: hsl(120, 100%, 40%);">+      int rc = -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   pthread_mutex_lock(&stats_tcp_lock);</span><br><span style="color: hsl(120, 100%, 40%);">+      llist_for_each_entry(stats_tcp_entry, &stats_tcp, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+                if (fd->fd == stats_tcp_entry->fd->fd) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     /* In case we want to remove exactly that item which is also selected as the current itemy, we</span><br><span style="color: hsl(120, 100%, 40%);">+                         * must designate either a different item or invalidate the current item. */</span><br><span style="color: hsl(120, 100%, 40%);">+                  if (stats_tcp_entry == stats_tcp_entry_cur) {</span><br><span style="color: hsl(120, 100%, 40%);">+                         if (llist_count(&stats_tcp) > 2)</span><br><span style="color: hsl(120, 100%, 40%);">+                                       next_stats_tcp_entry();</span><br><span style="color: hsl(120, 100%, 40%);">+                               else</span><br><span style="color: hsl(120, 100%, 40%);">+                                  stats_tcp_entry_cur = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                   /* Date item from list */</span><br><span style="color: hsl(120, 100%, 40%);">+                     llist_del(&stats_tcp_entry->entry);</span><br><span style="color: hsl(120, 100%, 40%);">+                    osmo_stat_item_group_free(stats_tcp_entry->stats_tcp);</span><br><span style="color: hsl(120, 100%, 40%);">+                     talloc_free(stats_tcp_entry);</span><br><span style="color: hsl(120, 100%, 40%);">+                 rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                       break;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     pthread_mutex_unlock(&stats_tcp_lock);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void stats_tcp_poll_timer_cb(void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   int i;</span><br><span style="color: hsl(120, 100%, 40%);">+        int batch_size;</span><br><span style="color: hsl(120, 100%, 40%);">+       int llist_size;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     pthread_mutex_lock(&stats_tcp_lock);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Make sure we do not run over the same sockets multiple times if the</span><br><span style="color: hsl(120, 100%, 40%);">+         * configured llist_size is larger then the actual list */</span><br><span style="color: hsl(120, 100%, 40%);">+    batch_size = osmo_tcp_stats_config->batch_size;</span><br><span style="color: hsl(120, 100%, 40%);">+    llist_size = llist_count(&stats_tcp);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (llist_size < batch_size)</span><br><span style="color: hsl(120, 100%, 40%);">+               batch_size = llist_size;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Process a batch of sockets */</span><br><span style="color: hsl(120, 100%, 40%);">+      for (i = 0; i < batch_size; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+         next_stats_tcp_entry();</span><br><span style="color: hsl(120, 100%, 40%);">+               if (stats_tcp_entry_cur)</span><br><span style="color: hsl(120, 100%, 40%);">+                      fill_stats(stats_tcp_entry_cur);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   pthread_mutex_unlock(&stats_tcp_lock);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (osmo_tcp_stats_config->interval > 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                osmo_timer_schedule(&stats_tcp_poll_timer, osmo_tcp_stats_config->interval, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Set the polling interval (common for all sockets)</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] interval Poll interval in seconds</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns 0 on success; negative on error */</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_stats_tcp_set_interval(int interval)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       osmo_tcp_stats_config->interval = interval;</span><br><span style="color: hsl(120, 100%, 40%);">+        if (osmo_tcp_stats_config->interval > 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                osmo_timer_schedule(&stats_tcp_poll_timer, osmo_tcp_stats_config->interval, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+        return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static __attribute__((constructor))</span><br><span style="color: hsl(120, 100%, 40%);">+void on_dso_load_stats_tcp(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      stats_tcp_entry_cur = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+   pthread_mutex_init(&stats_tcp_lock, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_tcp_stats_config->interval = TCP_STATS_DEFAULT_INTERVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_tcp_stats_config->batch_size = TCP_STATS_DEFAULT_BATCH_SIZE;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_timer_setup(&stats_tcp_poll_timer, stats_tcp_poll_timer_cb, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#endif /* !EMBEDDED */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* @} */</span><br><span>diff --git a/src/vty/stats_vty.c b/src/vty/stats_vty.c</span><br><span>index e2247a3..a73fafb 100644</span><br><span>--- a/src/vty/stats_vty.c</span><br><span>+++ b/src/vty/stats_vty.c</span><br><span>@@ -33,6 +33,7 @@</span><br><span> #include <osmocom/core/stats.h></span><br><span> #include <osmocom/core/counter.h></span><br><span> #include <osmocom/core/rate_ctr.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/stats_tcp.h></span><br><span> </span><br><span> #define CFG_STATS_STR "Configure stats sub-system\n"</span><br><span> #define CFG_REPORTER_STR "Configure a stats reporter\n"</span><br><span>@@ -389,6 +390,32 @@</span><br><span>       return CMD_SUCCESS;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_tcp_stats_interval, cfg_tcp_stats_interval_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+       "stats-tcp interval <0-65535>",</span><br><span style="color: hsl(120, 100%, 40%);">+       CFG_STATS_STR "Set the tcp socket stats polling interval\n"</span><br><span style="color: hsl(120, 100%, 40%);">+ "Interval in seconds (0 disables the polling interval)\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       int interval = atoi(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = osmo_stats_tcp_set_interval(interval);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              vty_out(vty, "%% Unable to set interval: %s%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                     strerror(-rc), VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+          return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_tcp_stats_batch_size, cfg_tcp_stats_batch_size_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+       "stats-tcp batch-size <1-65535>",</span><br><span style="color: hsl(120, 100%, 40%);">+     CFG_STATS_STR "Set the number of tcp sockets that are processed per stats polling interval\n"</span><br><span style="color: hsl(120, 100%, 40%);">+       "Number of sockets per interval\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_tcp_stats_config->batch_size = atoi(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+ return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> DEFUN(show_stats,</span><br><span>       show_stats_cmd,</span><br><span>       "show stats",</span><br><span>@@ -677,6 +704,10 @@</span><br><span>       struct osmo_stats_reporter *srep;</span><br><span> </span><br><span>        vty_out(vty, "stats interval %d%s", osmo_stats_config->interval, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (osmo_tcp_stats_config->interval != TCP_STATS_DEFAULT_INTERVAL)</span><br><span style="color: hsl(120, 100%, 40%);">+         vty_out(vty, "stats-tcp interval %d%s", osmo_tcp_stats_config->interval, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (osmo_tcp_stats_config->batch_size != TCP_STATS_DEFAULT_BATCH_SIZE)</span><br><span style="color: hsl(120, 100%, 40%);">+             vty_out(vty, "stats-tcp batch-size %d%s", osmo_tcp_stats_config->batch_size, VTY_NEWLINE);</span><br><span> </span><br><span>  /* Loop through all reporters */</span><br><span>     llist_for_each_entry(srep, &osmo_stats_reporter_list, list)</span><br><span>@@ -699,6 +730,8 @@</span><br><span>        install_lib_element(CONFIG_NODE, &cfg_stats_reporter_log_cmd);</span><br><span>   install_lib_element(CONFIG_NODE, &cfg_no_stats_reporter_log_cmd);</span><br><span>        install_lib_element(CONFIG_NODE, &cfg_stats_interval_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+        install_lib_element(CONFIG_NODE, &cfg_tcp_stats_interval_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+    install_lib_element(CONFIG_NODE, &cfg_tcp_stats_batch_size_cmd);</span><br><span> </span><br><span>     install_node(&cfg_stats_node, config_write_stats);</span><br><span> </span><br><span>diff --git a/tests/stats/stats_vty_test.vty b/tests/stats/stats_vty_test.vty</span><br><span>index 94cc7e8..8732d50 100644</span><br><span>--- a/tests/stats/stats_vty_test.vty</span><br><span>+++ b/tests/stats/stats_vty_test.vty</span><br><span>@@ -7,6 +7,7 @@</span><br><span>   stats reporter log [NAME]</span><br><span>   no stats reporter log [NAME]</span><br><span>   stats interval <0-65535></span><br><span style="color: hsl(120, 100%, 40%);">+  stats-tcp interval <0-65535></span><br><span> ...</span><br><span> </span><br><span> stats_vty_test(config)# ### No reporters shall be configured by default</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/libosmocore/+/26454">change 26454</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/libosmocore/+/26454"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: libosmocore </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I1416f95aff2adcf13689646b7574845de169fa3d </div>
<div style="display:none"> Gerrit-Change-Number: 26454 </div>
<div style="display:none"> Gerrit-PatchSet: 19 </div>
<div style="display:none"> Gerrit-Owner: dexter <pmaier@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: daniel <dwillmann@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-CC: fixeria <vyanitskiy@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>