linux: Add TCP_INFO support

Implement the getsockopt for TCP_INFO by mapping FreeBSD's version to
what Linux expects.

MFC after:	1 month
Relnotes:	yes
Reviewed by:	kib
Differential Revision:	https://reviews.freebsd.org/D55882
This commit is contained in:
Chuck Tuffli
2026-06-09 17:22:49 -07:00
parent 1c85c5eea0
commit 925ca9b835
2 changed files with 136 additions and 3 deletions
+44 -3
View File
@@ -591,9 +591,7 @@ linux_to_bsd_tcp_sockopt(int opt)
case LINUX_TCP_KEEPCNT:
return (TCP_KEEPCNT);
case LINUX_TCP_INFO:
LINUX_RATELIMIT_MSG_OPT1(
"unsupported TCP socket option TCP_INFO (%d)", opt);
return (-2);
return (TCP_INFO);
case LINUX_TCP_MD5SIG:
return (TCP_MD5SIG);
case LINUX_TCP_USER_TIMEOUT:
@@ -2407,6 +2405,42 @@ linux_getsockopt_so_linger(struct thread *td,
return (linux_sockopt_copyout(td, &ling, len, args));
}
static int
linux_getsockopt_tcp_info(struct thread *td,
struct linux_getsockopt_args *args)
{
struct tcp_info tinfo;
struct l_tcp_info l_tinfo;
socklen_t len;
int error;
len = sizeof(tinfo);
error = kern_getsockopt(td, args->s, IPPROTO_TCP, TCP_INFO, &tinfo,
UIO_SYSSPACE, &len);
if (error != 0)
return (error);
memset(&l_tinfo, 0, sizeof(l_tinfo));
l_tinfo.tcpi_state = tinfo.tcpi_state;
l_tinfo.tcpi_options = tinfo.tcpi_options;
l_tinfo.tcpi_snd_wscale = tinfo.tcpi_snd_wscale;
l_tinfo.tcpi_rcv_wscale = tinfo.tcpi_rcv_wscale;
l_tinfo.tcpi_rto = tinfo.tcpi_rto;
l_tinfo.tcpi_snd_mss = tinfo.tcpi_snd_mss;
l_tinfo.tcpi_rcv_mss = tinfo.tcpi_rcv_mss;
l_tinfo.tcpi_last_data_recv = tinfo.tcpi_last_data_recv;
l_tinfo.tcpi_rtt = tinfo.tcpi_rtt;
l_tinfo.tcpi_rttvar = tinfo.tcpi_rttvar;
l_tinfo.tcpi_snd_ssthresh = tinfo.tcpi_snd_ssthresh;
l_tinfo.tcpi_snd_cwnd = tinfo.tcpi_snd_cwnd;
l_tinfo.tcpi_rcv_space = tinfo.tcpi_rcv_space;
l_tinfo.tcpi_snd_wnd = tinfo.tcpi_snd_wnd;
l_tinfo.tcpi_rcv_ooopack = tinfo.tcpi_rcv_ooopack;
/* Eqivalent */
l_tinfo.tcpi_total_retrans = tinfo.tcpi_snd_rexmitpack;
return (linux_sockopt_copyout(td, &l_tinfo, len, args));
}
int
linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args)
{
@@ -2505,6 +2539,13 @@ linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args)
name = linux_to_bsd_ip6_sockopt(args->optname);
break;
case IPPROTO_TCP:
switch (args->optname) {
case LINUX_TCP_INFO:
return (linux_getsockopt_tcp_info(td, args));
/* NOTREACHED */
default:
break;
}
name = linux_to_bsd_tcp_sockopt(args->optname);
switch (name) {
case TCP_MAXUNACKTIME:
+92
View File
@@ -359,6 +359,98 @@ struct l_ifreq {
} ifr_ifru;
};
/*
* Linux TCP_INFO structure as of v6.19.8
*
* Comments indicate last field for the given kernel version
*/
struct l_tcp_info {
uint8_t tcpi_state;
uint8_t tcpi_ca_state;
uint8_t tcpi_retransmits;
uint8_t tcpi_probes;
uint8_t tcpi_backoff;
uint8_t tcpi_options;
uint8_t tcpi_snd_wscale : 4, tcpi_rcv_wscale : 4;
uint8_t tcpi_delivery_rate_app_limited:1, tcpi_fastopen_client_fail:2;
uint32_t tcpi_rto;
uint32_t tcpi_ato;
uint32_t tcpi_snd_mss;
uint32_t tcpi_rcv_mss;
uint32_t tcpi_unacked;
uint32_t tcpi_sacked;
uint32_t tcpi_lost;
uint32_t tcpi_retrans;
uint32_t tcpi_fackets;
uint32_t tcpi_last_data_sent;
uint32_t tcpi_last_ack_sent;
uint32_t tcpi_last_data_recv;
uint32_t tcpi_last_ack_recv;
uint32_t tcpi_pmtu;
uint32_t tcpi_rcv_ssthresh;
uint32_t tcpi_rtt;
uint32_t tcpi_rttvar;
uint32_t tcpi_snd_ssthresh;
uint32_t tcpi_snd_cwnd;
uint32_t tcpi_advmss;
uint32_t tcpi_reordering;
uint32_t tcpi_rcv_rtt;
uint32_t tcpi_rcv_space;
uint32_t tcpi_total_retrans; /* v3.6 */
uint64_t tcpi_pacing_rate;
uint64_t tcpi_max_pacing_rate; /* v3.14 */
uint64_t tcpi_bytes_acked;
uint64_t tcpi_bytes_received;
uint32_t tcpi_segs_out;
uint32_t tcpi_segs_in; /* v4.1 */
uint32_t tcpi_notsent_bytes;
uint32_t tcpi_min_rtt;
uint32_t tcpi_data_segs_in;
uint32_t tcpi_data_segs_out; /* v4.5 */
uint64_t tcpi_delivery_rate; /* v4.8 */
uint64_t tcpi_busy_time;
uint64_t tcpi_rwnd_limited;
uint64_t tcpi_sndbuf_limited; /* v4.9 */
uint32_t tcpi_delivered;
uint32_t tcpi_delivered_ce; /* v4.16 */
uint64_t tcpi_bytes_sent;
uint64_t tcpi_bytes_retrans;
uint32_t tcpi_dsack_dups;
uint32_t tcpi_reord_seen; /* v4.18 */
uint32_t tcpi_rcv_ooopack;
uint32_t tcpi_snd_wnd; /* v5.3 */
uint32_t tcpi_rcv_wnd;
uint32_t tcpi_rehash; /* v6.1 */
uint16_t tcpi_total_rto;
uint16_t tcpi_total_rto_recoveries;
uint32_t tcpi_total_rto_time; /* v6.6 */
uint32_t tcpi_received_ce;
uint32_t tcpi_delivered_e1_bytes;
uint32_t tcpi_delivered_e0_bytes;
uint32_t tcpi_delivered_ce_bytes;
uint32_t tcpi_received_e1_bytes;
uint32_t tcpi_received_e0_bytes;
uint32_t tcpi_received_ce_bytes;
uint16_t tcpi_accecn_fail_mode;
uint16_t tcpi_accecn_opt_seen; /* v6.17 */
};
/*
* Define here members which are not exists in the FreeBSD struct ifreq.
*/