Change in libosmocore[master]: select: gather statistics for TCP connections

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

dexter gerrit-no-reply at lists.osmocom.org
Mon Dec 6 15:49:19 UTC 2021


dexter has uploaded this change for review. ( https://gerrit.osmocom.org/c/libosmocore/+/26454 )


Change subject: select: gather statistics for TCP connections
......................................................................

select: gather statistics for TCP connections

osmocom applications are deployed in a variety of different situations.
Dependung on the medium that interconnects the network components
unexpected behaviour may occur. To debug problems with the
interconnection between network components it might help to monitor the
health of the related TCP connections. This can be done on a lower level
so that any TCP connection that is handled by an osmocom process can be
monitored through stats items.

Change-Id: I1416f95aff2adcf13689646b7574845de169fa3d
Related: SYS#5701
---
M include/osmocom/core/select.h
M src/Makefile.am
M src/select.c
A src/stats_tcp.c
A src/stats_tcp.h
5 files changed, 192 insertions(+), 0 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/54/26454/1

diff --git a/include/osmocom/core/select.h b/include/osmocom/core/select.h
index 980bc97..57aee39 100644
--- a/include/osmocom/core/select.h
+++ b/include/osmocom/core/select.h
@@ -45,6 +45,9 @@
 	unsigned int priv_nr;
 	/*! human-readable name of this fd (optional) */
 	const char *name;
+	/*! statistics associated with this fd
+	 *  (automatically managed by libosmocore) */
+	struct osmo_stat_item_group *priv_stats;
 };
 
 void osmo_fd_setup(struct osmo_fd *ofd, int fd, unsigned int when,
diff --git a/src/Makefile.am b/src/Makefile.am
index 4bda456..519029d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -22,6 +22,7 @@
 			 conv.c application.c rbtree.c strrb.c \
 			 loggingrb.c crc8gen.c crc16gen.c crc32gen.c crc64gen.c \
 			 macaddr.c stat_item.c stats.c stats_statsd.c prim.c \
+			 stats_tcp.c \
 			 conv_acc.c conv_acc_generic.c sercomm.c prbs.c \
 			 isdnhdlc.c \
 			 tdef.c \
@@ -65,6 +66,7 @@
 	conv_acc_neon_impl.h \
 	crcXXgen.c.tpl \
 	stat_item_internal.h \
+	stats_tcp.h \
 	$(NULL)
 
 libosmocore_la_LDFLAGS = -version-info $(LIBVERSION) -no-undefined
diff --git a/src/select.c b/src/select.c
index f7eb5ea..6627c0b 100644
--- a/src/select.c
+++ b/src/select.c
@@ -38,6 +38,8 @@
 #include <osmocom/core/logging.h>
 #include <osmocom/core/talloc.h>
 #include <osmocom/core/utils.h>
+#include <osmocom/core/stat_item.h>
+#include "stats_tcp.h"
 
 #include "../config.h"
 
@@ -168,6 +170,9 @@
 	g_poll.num_registered++;
 #endif /* FORCE_IO_SELECT */
 
+	/* Ensure that priv_stats is set to NULL. */
+	fd->priv_stats = NULL;
+
 	llist_add_tail(&fd->list, &osmo_fds);
 
 	return 0;
@@ -186,6 +191,12 @@
 #ifndef FORCE_IO_SELECT
 	g_poll.num_registered--;
 #endif /* FORCE_IO_SELECT */
+
+	/* If existant, free any statistical data */
+	if (fd->priv_stats) {
+		osmo_stat_item_group_free(fd->priv_stats);
+		fd->priv_stats = NULL;
+	}
 }
 
 /*! Close a file descriptor, mark it as closed + unregister from select loop abstraction
@@ -373,6 +384,10 @@
 	unsigned int n_poll;
 	int rc;
 
+#if !defined(EMBEDDED)
+	stats_tcp_poll(&osmo_fds);
+#endif /* !EMBEDDED */
+
 	/* prepare read and write fdsets */
 	n_poll = poll_fill_fds();
 
diff --git a/src/stats_tcp.c b/src/stats_tcp.c
new file mode 100644
index 0000000..d35dcb2
--- /dev/null
+++ b/src/stats_tcp.c
@@ -0,0 +1,167 @@
+/*
+ * (C) 2021 by sysmocom - s.f.m.c. GmbH
+ * Author: Philipp Maier <pmaier at sysmocom.de>
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+/*! \addtogroup stats
+ *  @{
+ *  \file stats_tcp.c */
+
+#include "config.h"
+#if !defined(EMBEDDED)
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <linux/tcp.h>
+
+#include <osmocom/core/select.h>
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/utils.h>
+
+#include <osmocom/core/stat_item.h>
+#include <osmocom/core/stats.h>
+#include "stats_tcp.h"
+#include <osmocom/core/socket.h>
+
+enum {
+	STATS_TCP_UNACKED,
+	STATS_TCP_RETRANS,
+	STATS_TCP_RTT,
+	STATS_TCP_RCV_RTT,
+	STATS_TCP_NOTSENT_BYTES,
+	STATS_TCP_RWND_LIMITED,
+	STATS_TCP_REORD_SEEN,
+};
+
+struct stats_tcp_entry {
+	struct llist_head entry;
+	struct osmo_stat_item_group *stats_tcp;
+	int fd;
+};
+
+const struct osmo_stat_item_desc stats_tcp_item_desc[] = {
+	[STATS_TCP_UNACKED] = { "tcp:unacked", "unacknowledged packets", "", 60, 0 },
+	[STATS_TCP_RETRANS] = { "tcp:retrans", "retransmitted packets", "", 60, 0 },
+	[STATS_TCP_RTT] = { "tcp:rtt", "roundtrip-time", "", 60, 0 },
+	[STATS_TCP_RCV_RTT] = { "tcp:rcv_rtt", "roundtrip-time (receive)", "", 60, 0 },
+	[STATS_TCP_NOTSENT_BYTES] = { "tcp:notsent_bytes", "bytes not yet sent", "", 60, 0 },
+	[STATS_TCP_RWND_LIMITED] = { "tcp:rwnd_limited", "time (usec) limited by receive window", "", 60, 0 },
+	[STATS_TCP_REORD_SEEN] = { "tcp:sndbuf_limited", "reordering events seen", "", 60, 0 },
+};
+
+const struct osmo_stat_item_group_desc stats_tcp_desc = {
+	.group_name_prefix = "tcp",
+	.group_description = "stats tcp",
+	.class_id = OSMO_STATS_CLASS_GLOBAL,
+	.num_items = ARRAY_SIZE(stats_tcp_item_desc),
+	.item_desc = stats_tcp_item_desc,
+};
+
+static void fill_stats(struct osmo_fd *ufd)
+{
+	int rc;
+	struct tcp_info tcp_info;
+	socklen_t tcp_info_len = sizeof(tcp_info);
+
+	rc = getsockopt(ufd->fd, IPPROTO_TCP, TCP_INFO, &tcp_info, &tcp_info_len);
+	if (rc < 0)
+		return;
+
+	osmo_stat_item_set(osmo_stat_item_group_get_item(ufd->priv_stats, STATS_TCP_UNACKED), tcp_info.tcpi_unacked);
+	osmo_stat_item_set(osmo_stat_item_group_get_item(ufd->priv_stats, STATS_TCP_RETRANS), tcp_info.tcpi_retrans);
+	osmo_stat_item_set(osmo_stat_item_group_get_item(ufd->priv_stats, STATS_TCP_RTT), tcp_info.tcpi_rtt);
+	osmo_stat_item_set(osmo_stat_item_group_get_item(ufd->priv_stats, STATS_TCP_RCV_RTT),
+			   tcp_info.tcpi_notsent_bytes);
+	osmo_stat_item_set(osmo_stat_item_group_get_item(ufd->priv_stats, STATS_TCP_NOTSENT_BYTES),
+			   tcp_info.tcpi_rwnd_limited);
+	osmo_stat_item_set(osmo_stat_item_group_get_item(ufd->priv_stats, STATS_TCP_RWND_LIMITED),
+			   tcp_info.tcpi_sndbuf_limited);
+	osmo_stat_item_set(osmo_stat_item_group_get_item(ufd->priv_stats, STATS_TCP_REORD_SEEN),
+			   tcp_info.tcpi_reord_seen);
+}
+
+/* Check if the socket we dealing with is associated with a stream (TCP) */
+static bool is_stream(struct osmo_fd *ufd)
+{
+	int rc;
+	struct stat fd_stat;
+	int so_type = 0;
+	socklen_t so_type_len = sizeof(so_type);
+
+	rc = fstat(ufd->fd, &fd_stat);
+	if (rc < 0)
+		return false;
+
+	if (S_ISSOCK(fd_stat.st_mode)) {
+		rc = getsockopt(ufd->fd, SOL_SOCKET, SO_TYPE, &so_type, &so_type_len);
+		if (rc < 0)
+			return false;
+
+		if (so_type == SOCK_STREAM)
+			return true;
+	}
+
+	return false;
+}
+
+/* Check if the socket is connected to a remote end. */
+static bool is_connected(struct osmo_fd *ufd)
+{
+	if (osmo_sock_get_ip_and_port(ufd->fd, NULL, 0, NULL, 0, false) != 0)
+		return false;
+	return true;
+}
+
+void add_stats(struct osmo_fd *ufd)
+{
+	char stat_name[256];
+
+	ufd->priv_stats = osmo_stat_item_group_alloc(NULL, &stats_tcp_desc, ufd->fd);
+	OSMO_ASSERT(ufd->priv_stats);
+
+	if (ufd->name)
+		snprintf(stat_name, sizeof(stat_name), "%s,%s", ufd->name, osmo_sock_get_name2(ufd->fd));
+	else
+		snprintf(stat_name, sizeof(stat_name), "%s", osmo_sock_get_name2(ufd->fd));
+
+	osmo_stat_item_group_set_name(ufd->priv_stats, stat_name);
+
+}
+
+void stats_tcp_poll(struct llist_head *osmo_fds)
+{
+	struct osmo_fd *ufd;
+
+	llist_for_each_entry(ufd, osmo_fds, list) {
+		if (ufd->priv_stats == NULL && is_stream(ufd) && is_connected(ufd))
+			add_stats(ufd);
+		if (ufd->priv_stats)
+			fill_stats(ufd);
+	}
+}
+
+#endif /* !EMBEDDED */
+
+/* @} */
diff --git a/src/stats_tcp.h b/src/stats_tcp.h
new file mode 100644
index 0000000..1c0b475
--- /dev/null
+++ b/src/stats_tcp.h
@@ -0,0 +1,5 @@
+#pragma once
+
+struct llist_head;
+
+void stats_tcp_poll(struct llist_head *osmo_fds);

-- 
To view, visit https://gerrit.osmocom.org/c/libosmocore/+/26454
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-Change-Id: I1416f95aff2adcf13689646b7574845de169fa3d
Gerrit-Change-Number: 26454
Gerrit-PatchSet: 1
Gerrit-Owner: dexter <pmaier at sysmocom.de>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20211206/6763affb/attachment.htm>


More information about the gerrit-log mailing list