summaryrefslogtreecommitdiffstats
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
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
-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
-rw-r--r--usr.bin/netstat/inet.c25
-rw-r--r--usr.bin/netstat/netstat.12
6 files changed, 58 insertions, 8 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
diff --git a/usr.bin/netstat/inet.c b/usr.bin/netstat/inet.c
index 51b71c7..da07e1d 100644
--- a/usr.bin/netstat/inet.c
+++ b/usr.bin/netstat/inet.c
@@ -313,6 +313,7 @@ protopr(u_long off, const char *name, int af1, int proto)
struct inpcb *inp;
struct xinpgen *xig, *oxig;
struct xsocket *so;
+ struct xtcp_timer *timer;
istcp = 0;
switch (proto) {
@@ -347,6 +348,7 @@ protopr(u_long off, const char *name, int af1, int proto)
xig->xig_len > sizeof(struct xinpgen);
xig = (struct xinpgen *)((char *)xig + xig->xig_len)) {
if (istcp) {
+ timer = &((struct xtcpcb *)xig)->xt_timer;
tp = &((struct xtcpcb *)xig)->xt_tp;
inp = &((struct xtcpcb *)xig)->xt_inp;
so = &((struct xtcpcb *)xig)->xt_socket;
@@ -414,14 +416,17 @@ protopr(u_long off, const char *name, int af1, int proto)
"%-5.5s %-6.6s %-6.6s %-22.22s %-22.22s",
"Proto", "Recv-Q", "Send-Q",
"Local Address", "Foreign Address");
- if (xflag)
- printf("%-6.6s %-6.6s %-6.6s %-6.6s %-6.6s %-6.6s %-6.6s %-6.6s %-6.6s %-6.6s %-6.6s %-6.6s %s\n",
+ if (xflag) {
+ printf("%-6.6s %-6.6s %-6.6s %-6.6s %-6.6s %-6.6s %-6.6s %-6.6s %-6.6s %-6.6s %-6.6s %-6.6s ",
"R-MBUF", "S-MBUF", "R-CLUS",
"S-CLUS", "R-HIWA", "S-HIWA",
"R-LOWA", "S-LOWA", "R-BCNT",
- "S-BCNT", "R-BMAX", "S-BMAX",
- "(state)");
- else
+ "S-BCNT", "R-BMAX", "S-BMAX");
+ printf("%7.7s %7.7s %7.7s %7.7s %7.7s %7.7s %s\n",
+ "rexmt", "persist", "keep",
+ "2msl", "delack", "rcvtime",
+ "(state)");
+ } else
printf("(state)\n");
}
first = 0;
@@ -516,7 +521,7 @@ protopr(u_long off, const char *name, int af1, int proto)
so->so_rcv.sb_lowat, so->so_snd.sb_lowat,
so->so_rcv.sb_mbcnt, so->so_snd.sb_mbcnt,
so->so_rcv.sb_mbmax, so->so_snd.sb_mbmax);
- else
+ else {
printf("%6u %6u %6u %6u %6u %6u %6u %6u %6u %6u %6u %6u ",
so->so_rcv.sb_mcnt, so->so_snd.sb_mcnt,
so->so_rcv.sb_ccnt, so->so_snd.sb_ccnt,
@@ -524,6 +529,14 @@ protopr(u_long off, const char *name, int af1, int proto)
so->so_rcv.sb_lowat, so->so_snd.sb_lowat,
so->so_rcv.sb_mbcnt, so->so_snd.sb_mbcnt,
so->so_rcv.sb_mbmax, so->so_snd.sb_mbmax);
+ printf("%4d.%02d %4d.%02d %4d.%02d %4d.%02d %4d.%02d %4d.%02d ",
+ timer->tt_rexmt / 1000, (timer->tt_rexmt % 1000) / 10,
+ timer->tt_persist / 1000, (timer->tt_persist % 1000) / 10,
+ timer->tt_keep / 1000, (timer->tt_keep % 1000) / 10,
+ timer->tt_2msl / 1000, (timer->tt_2msl % 1000) / 10,
+ timer->tt_delack / 1000, (timer->tt_delack % 1000) / 10,
+ timer->t_rcvtime / 1000, (timer->t_rcvtime % 1000) / 10);
+ }
}
if (istcp && !Lflag) {
if (tp->t_state < 0 || tp->t_state >= TCP_NSTATES)
diff --git a/usr.bin/netstat/netstat.1 b/usr.bin/netstat/netstat.1
index 41e15c1..cddaaaf 100644
--- a/usr.bin/netstat/netstat.1
+++ b/usr.bin/netstat/netstat.1
@@ -87,7 +87,7 @@ show network addresses as numbers (as with
but show ports symbolically.
If
.Fl x
-is present display full socket buffer statistics for each internet socket.
+is present, display socket buffer and tcp timer statistics for each internet socket.
.It Xo
.Bk -words
.Nm
OpenPOWER on IntegriCloud