summaryrefslogtreecommitdiffstats
path: root/sys/netinet
diff options
context:
space:
mode:
authorsilby <silby@FreeBSD.org>2009-09-16 05:33:15 +0000
committersilby <silby@FreeBSD.org>2009-09-16 05:33:15 +0000
commitded53b4033d64348edff9f7b9fe6d19d8d418ad2 (patch)
tree2ce0381caeec3ea6ca3ab4e0629bd7cf46223a8c /sys/netinet
parent95d4e7d0750d9cb513c20c55282fbfb46b2c4a8a (diff)
downloadFreeBSD-src-ded53b4033d64348edff9f7b9fe6d19d8d418ad2.zip
FreeBSD-src-ded53b4033d64348edff9f7b9fe6d19d8d418ad2.tar.gz
Add the ability to see TCP timers via netstat -x. This can be a useful
feature when you have a seemingly stuck socket and want to figure out why it has not been closed yet. No plans to MFC this, as it changes the netstat sysctl ABI. Reviewed by: andre, rwatson, Eric Van Gyzen
Diffstat (limited to 'sys/netinet')
-rw-r--r--sys/netinet/tcp_subr.c5
-rw-r--r--sys/netinet/tcp_timer.c21
-rw-r--r--sys/netinet/tcp_timer.h4
-rw-r--r--sys/netinet/tcp_var.h9
4 files changed, 38 insertions, 1 deletions
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index 22b2ace..d0b2e0e 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -1151,8 +1151,11 @@ tcp_pcblist(SYSCTL_HANDLER_ARGS)
else if (inp->inp_flags & INP_TIMEWAIT) {
bzero((char *) &xt.xt_tp, sizeof xt.xt_tp);
xt.xt_tp.t_state = TCPS_TIME_WAIT;
- } else
+ } else {
bcopy(inp_ppcb, &xt.xt_tp, sizeof xt.xt_tp);
+ if (xt.xt_tp.t_timers)
+ tcp_timer_to_xtimer(&xt.xt_tp, xt.xt_tp.t_timers, &xt.xt_timer);
+ }
if (inp->inp_socket != NULL)
sotoxsocket(inp->inp_socket, &xt.xt_socket);
else {
diff --git a/sys/netinet/tcp_timer.c b/sys/netinet/tcp_timer.c
index 7f5d159..8ead3dc 100644
--- a/sys/netinet/tcp_timer.c
+++ b/sys/netinet/tcp_timer.c
@@ -659,3 +659,24 @@ tcp_timer_active(struct tcpcb *tp, int timer_type)
}
return callout_active(t_callout);
}
+
+#define ticks_to_msecs(t) (1000*(t) / hz)
+
+void
+tcp_timer_to_xtimer(struct tcpcb *tp, struct tcp_timer *timer, struct xtcp_timer *xtimer)
+{
+ bzero(xtimer, sizeof(struct xtcp_timer));
+ if (timer == NULL)
+ return;
+ if (callout_active(&timer->tt_delack))
+ xtimer->tt_delack = ticks_to_msecs(timer->tt_delack.c_time - ticks);
+ if (callout_active(&timer->tt_rexmt))
+ xtimer->tt_rexmt = ticks_to_msecs(timer->tt_rexmt.c_time - ticks);
+ if (callout_active(&timer->tt_persist))
+ xtimer->tt_persist = ticks_to_msecs(timer->tt_persist.c_time - ticks);
+ if (callout_active(&timer->tt_keep))
+ xtimer->tt_keep = ticks_to_msecs(timer->tt_keep.c_time - ticks);
+ if (callout_active(&timer->tt_2msl))
+ xtimer->tt_2msl = ticks_to_msecs(timer->tt_2msl.c_time - ticks);
+ xtimer->t_rcvtime = ticks_to_msecs(ticks - tp->t_rcvtime);
+}
diff --git a/sys/netinet/tcp_timer.h b/sys/netinet/tcp_timer.h
index ff455b6..1ab0b7b 100644
--- a/sys/netinet/tcp_timer.h
+++ b/sys/netinet/tcp_timer.h
@@ -141,6 +141,8 @@ static const char *tcptimers[] =
#ifdef _KERNEL
+struct xtcp_timer;
+
struct tcp_timer {
struct callout tt_rexmt; /* retransmit timer */
struct callout tt_persist; /* retransmit persistence */
@@ -177,6 +179,8 @@ void tcp_timer_keep(void *xtp);
void tcp_timer_persist(void *xtp);
void tcp_timer_rexmt(void *xtp);
void tcp_timer_delack(void *xtp);
+void tcp_timer_to_xtimer(struct tcpcb *tp, struct tcp_timer *timer,
+ struct xtcp_timer *xtimer);
#endif /* _KERNEL */
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
index 96353f3..93d3feb 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -495,11 +495,20 @@ void kmod_tcpstat_inc(int statnum);
* included. Not all of our clients do.
*/
#if defined(_NETINET_IN_PCB_H_) && defined(_SYS_SOCKETVAR_H_)
+struct xtcp_timer {
+ int tt_rexmt; /* retransmit timer */
+ int tt_persist; /* retransmit persistence */
+ int tt_keep; /* keepalive */
+ int tt_2msl; /* 2*msl TIME_WAIT timer */
+ int tt_delack; /* delayed ACK timer */
+ int t_rcvtime; /* Time since last packet received */
+};
struct xtcpcb {
size_t xt_len;
struct inpcb xt_inp;
struct tcpcb xt_tp;
struct xsocket xt_socket;
+ struct xtcp_timer xt_timer;
u_quad_t xt_alignment_hack;
};
#endif
OpenPOWER on IntegriCloud