From: Marcel Lauhoff Date: Wed, 21 Aug 2024 13:38:30 +0000 (+0200) Subject: common: Add utility to fetch TCP_INFO for socket X-Git-Tag: v20.3.0~373^2~9 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=f33c970da6e573af0f322ea3b36972d1fdf6fea6;p=ceph.git common: Add utility to fetch TCP_INFO for socket Add utility to fetch TCP_INFO for a socket and a variant that pushes the data to a Formatter. Signed-off-by: Marcel Lauhoff --- diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index c607839a8d25..ae34d330813f 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -104,7 +104,8 @@ set(common_srcs pretty_binary.cc utf8.c util.cc - version.cc) + version.cc + tcp_info.cc) if(WITH_SYSTEMD) list(APPEND common_srcs diff --git a/src/common/tcp_info.cc b/src/common/tcp_info.cc new file mode 100644 index 000000000000..c0a0f659ad4d --- /dev/null +++ b/src/common/tcp_info.cc @@ -0,0 +1,121 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2024 Clyso GmbH + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include "common/tcp_info.h" + +#include "common/Formatter.h" + +namespace ceph { + +#ifdef _WIN32 +struct tcp_info {}; + +bool tcp_info(int fd, struct tcp_info& info) { + return false; +} +bool dump_tcp_info(int fd, Formatter* f) { + return false; +} + +#else + +bool tcp_info(int fd, struct tcp_info& info) { + socklen_t info_len = sizeof(info); + return (getsockopt(fd, SOL_TCP, TCP_INFO, &info, &info_len) == 0); +} + +static const char* get_tcpi_state_name(uint8_t state) { + switch (state) { + case TCP_ESTABLISHED: + return "established"; + case TCP_SYN_SENT: + return "syn sent"; + case TCP_SYN_RECV: + return "syn recv"; + case TCP_FIN_WAIT1: + return "fin wait1"; + case TCP_FIN_WAIT2: + return "fin wait2"; + case TCP_TIME_WAIT: + return "time wait"; + case TCP_CLOSE: + return "close"; + case TCP_CLOSE_WAIT: + return "close wait"; + case TCP_LAST_ACK: + return "last ack"; + case TCP_LISTEN: + return "listen"; + case TCP_CLOSING: + return "closing"; + default: + return "UNKNOWN"; + } +} + +bool dump_tcp_info(int fd, Formatter* f) { + struct tcp_info info; + if (!tcp_info(fd, info)) { + return false; + } + + f->open_object_section("tcp_info"); + f->dump_string("tcpi_state", get_tcpi_state_name(info.tcpi_state)); + f->dump_unsigned("tcpi_retransmits", info.tcpi_retransmits); + f->dump_unsigned("tcpi_probes", info.tcpi_probes); + f->dump_unsigned("tcpi_backoff", info.tcpi_backoff); + f->dump_unsigned("tcpi_rto_us", info.tcpi_rto); + f->dump_unsigned("tcpi_ato_us", info.tcpi_ato); + f->dump_unsigned("tcpi_snd_mss", info.tcpi_snd_mss); + f->dump_unsigned("tcpi_rcv_mss", info.tcpi_rcv_mss); + f->dump_unsigned("tcpi_unacked", info.tcpi_unacked); + f->dump_unsigned("tcpi_lost", info.tcpi_lost); + f->dump_unsigned("tcpi_retrans", info.tcpi_retrans); + f->dump_unsigned("tcpi_pmtu", info.tcpi_pmtu); + f->dump_unsigned("tcpi_rtt_us", info.tcpi_rtt); + f->dump_unsigned("tcpi_rttvar_us", info.tcpi_rttvar); + f->dump_unsigned("tcpi_total_retrans", info.tcpi_total_retrans); + f->dump_unsigned("tcpi_last_data_sent_ms", info.tcpi_last_data_sent); + f->dump_unsigned("tcpi_last_ack_sent_ms", info.tcpi_last_ack_sent); + f->dump_unsigned("tcpi_last_data_recv_ms", info.tcpi_last_data_recv); + f->dump_unsigned("tcpi_last_ack_recv_ms", info.tcpi_last_ack_recv); + + f->open_array_section("tcpi_options"); + if (info.tcpi_options & TCPI_OPT_TIMESTAMPS) { + f->dump_string("option", "timestamps"); + } + if (info.tcpi_options & TCPI_OPT_SACK) { + f->dump_string("option", "sack"); + } + if (info.tcpi_options & TCPI_OPT_WSCALE) { + f->dump_string("option", "wscale"); + } + if (info.tcpi_options & TCPI_OPT_ECN) { + f->dump_string("option", "ecn"); + } + if (info.tcpi_options & TCPI_OPT_ECN_SEEN) { + f->dump_string("option", "ecn seen"); + } + if (info.tcpi_options & TCPI_OPT_SYN_DATA) { + f->dump_string("option", "syn data"); + } + f->close_section(); + + f->close_section(); + return true; +} + +#endif + +} // namespace ceph diff --git a/src/common/tcp_info.h b/src/common/tcp_info.h new file mode 100644 index 000000000000..d9112890a062 --- /dev/null +++ b/src/common/tcp_info.h @@ -0,0 +1,30 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2024 Clyso GmbH + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#pragma once + +#include +#include + +#include "Formatter.h" + +namespace ceph { + +/// Return TCP_INFO socket stats (see tcp(7)). Return true on success. +bool tcp_info(int fd, struct tcp_info& info); +/// Dump TCP_INFO socket stats to formatter. Use struct tcp_info variables +/// names as keys. Returns true on success. +bool dump_tcp_info(int fd, Formatter* f); + +} // namespace ceph