diff options
author | rwatson <rwatson@FreeBSD.org> | 2007-02-17 21:02:38 +0000 |
---|---|---|
committer | rwatson <rwatson@FreeBSD.org> | 2007-02-17 21:02:38 +0000 |
commit | 6a5d54ffd20da2b170bed379fd7faebe76a1a71a (patch) | |
tree | f5fce63e0f73ccb2cca300ae1e4aaaa40142cd66 /sys/netinet | |
parent | 7913035c29656090e061224103082cac92129a98 (diff) | |
download | FreeBSD-src-6a5d54ffd20da2b170bed379fd7faebe76a1a71a.zip FreeBSD-src-6a5d54ffd20da2b170bed379fd7faebe76a1a71a.tar.gz |
Add "show inpcb", "show tcpcb" DDB commands, which should come in handy
for debugging sblock and other network panics.
Diffstat (limited to 'sys/netinet')
-rw-r--r-- | sys/netinet/in_pcb.c | 252 | ||||
-rw-r--r-- | sys/netinet/in_pcb.h | 6 | ||||
-rw-r--r-- | sys/netinet/tcp_usrreq.c | 322 |
3 files changed, 578 insertions, 2 deletions
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 43306f3..4ffcd26 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -1,6 +1,8 @@ /*- * Copyright (c) 1982, 1986, 1991, 1993, 1995 - * The Regents of the University of California. All rights reserved. + * The Regents of the University of California. + * Copyright (c) 2007 Robert N. M. Watson + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,6 +32,7 @@ * $FreeBSD$ */ +#include "opt_ddb.h" #include "opt_ipsec.h" #include "opt_inet6.h" #include "opt_mac.h" @@ -48,6 +51,10 @@ #include <sys/kernel.h> #include <sys/sysctl.h> +#ifdef DDB +#include <ddb/ddb.h> +#endif + #include <vm/uma.h> #include <net/if.h> @@ -1233,3 +1240,246 @@ ipport_tick(void *xtp) ipport_tcplastcount = ipport_tcpallocs; callout_reset(&ipport_tick_callout, hz, ipport_tick, NULL); } + +#ifdef DDB +static void +db_print_indent(int indent) +{ + int i; + + for (i = 0; i < indent; i++) + db_printf(" "); +} + +static void +db_print_inconninfo(struct in_conninfo *inc, const char *name, int indent) +{ + char faddr_str[48], laddr_str[48]; + + db_print_indent(indent); + db_printf("%s at %p\n", name, inc); + + indent += 2; + + if (inc->inc_flags == 1) { + /* IPv6. */ + ip6_sprintf(laddr_str, &inc->inc6_laddr); + ip6_sprintf(faddr_str, &inc->inc6_faddr); + } else { + /* IPv4. */ + inet_ntoa_r(inc->inc_laddr, laddr_str); + inet_ntoa_r(inc->inc_faddr, faddr_str); + } + db_print_indent(indent); + db_printf("inc_laddr %s inc_lport %u\n", laddr_str, + ntohs(inc->inc_lport)); + db_print_indent(indent); + db_printf("inc_faddr %s inc_fport %u\n", faddr_str, + ntohs(inc->inc_fport)); +} + +static void +db_print_inpflags(int inp_flags) +{ + int comma; + + comma = 0; + if (inp_flags & INP_RECVOPTS) { + db_printf("%sINP_RECVOPTS", comma ? ", " : ""); + comma = 1; + } + if (inp_flags & INP_RECVRETOPTS) { + db_printf("%sINP_RECVRETOPTS", comma ? ", " : ""); + comma = 1; + } + if (inp_flags & INP_RECVDSTADDR) { + db_printf("%sINP_RECVDSTADDR", comma ? ", " : ""); + comma = 1; + } + if (inp_flags & INP_HDRINCL) { + db_printf("%sINP_HDRINCL", comma ? ", " : ""); + comma = 1; + } + if (inp_flags & INP_HIGHPORT) { + db_printf("%sINP_HIGHPORT", comma ? ", " : ""); + comma = 1; + } + if (inp_flags & INP_LOWPORT) { + db_printf("%sINP_LOWPORT", comma ? ", " : ""); + comma = 1; + } + if (inp_flags & INP_ANONPORT) { + db_printf("%sINP_ANONPORT", comma ? ", " : ""); + comma = 1; + } + if (inp_flags & INP_RECVIF) { + db_printf("%sINP_RECVIF", comma ? ", " : ""); + comma = 1; + } + if (inp_flags & INP_MTUDISC) { + db_printf("%sINP_MTUDISC", comma ? ", " : ""); + comma = 1; + } + if (inp_flags & INP_FAITH) { + db_printf("%sINP_FAITH", comma ? ", " : ""); + comma = 1; + } + if (inp_flags & INP_RECVTTL) { + db_printf("%sINP_RECVTTL", comma ? ", " : ""); + comma = 1; + } + if (inp_flags & INP_DONTFRAG) { + db_printf("%sINP_DONTFRAG", comma ? ", " : ""); + comma = 1; + } + if (inp_flags & IN6P_IPV6_V6ONLY) { + db_printf("%sIN6P_IPV6_V6ONLY", comma ? ", " : ""); + comma = 1; + } + if (inp_flags & IN6P_PKTINFO) { + db_printf("%sIN6P_PKTINFO", comma ? ", " : ""); + comma = 1; + } + if (inp_flags & IN6P_HOPLIMIT) { + db_printf("%sIN6P_HOPLIMIT", comma ? ", " : ""); + comma = 1; + } + if (inp_flags & IN6P_HOPOPTS) { + db_printf("%sIN6P_HOPOPTS", comma ? ", " : ""); + comma = 1; + } + if (inp_flags & IN6P_DSTOPTS) { + db_printf("%sIN6P_DSTOPTS", comma ? ", " : ""); + comma = 1; + } + if (inp_flags & IN6P_RTHDR) { + db_printf("%sIN6P_RTHDR", comma ? ", " : ""); + comma = 1; + } + if (inp_flags & IN6P_RTHDRDSTOPTS) { + db_printf("%sIN6P_RTHDRDSTOPTS", comma ? ", " : ""); + comma = 1; + } + if (inp_flags & IN6P_TCLASS) { + db_printf("%sIN6P_TCLASS", comma ? ", " : ""); + comma = 1; + } + if (inp_flags & IN6P_AUTOFLOWLABEL) { + db_printf("%sIN6P_AUTOFLOWLABEL", comma ? ", " : ""); + comma = 1; + } + if (inp_flags & IN6P_RFC2292) { + db_printf("%sIN6P_RFC2292", comma ? ", " : ""); + comma = 1; + } + if (inp_flags & IN6P_MTU) { + db_printf("IN6P_MTU%s", comma ? ", " : ""); + comma = 1; + } +} + +static void +db_print_inpvflag(u_char inp_vflag) +{ + int comma; + + comma = 0; + if (inp_vflag & INP_IPV4) { + db_printf("%sINP_IPV4", comma ? ", " : ""); + comma = 1; + } + if (inp_vflag & INP_IPV6) { + db_printf("%sINP_IPV6", comma ? ", " : ""); + comma = 1; + } + if (inp_vflag & INP_IPV6PROTO) { + db_printf("%sINP_IPV6PROTO", comma ? ", " : ""); + comma = 1; + } + if (inp_vflag & INP_TIMEWAIT) { + db_printf("%sINP_TIMEWAIT", comma ? ", " : ""); + comma = 1; + } + if (inp_vflag & INP_ONESBCAST) { + db_printf("%sINP_ONESBCAST", comma ? ", " : ""); + comma = 1; + } + if (inp_vflag & INP_DROPPED) { + db_printf("%sINP_DROPPED", comma ? ", " : ""); + comma = 1; + } + if (inp_vflag & INP_SOCKREF) { + db_printf("%sINP_SOCKREF", comma ? ", " : ""); + comma = 1; + } +} + +void +db_print_inpcb(struct inpcb *inp, const char *name, int indent) +{ + + db_print_indent(indent); + db_printf("%s at %p\n", name, inp); + + indent += 2; + + db_print_indent(indent); + db_printf("inp_flow: 0x%x\n", inp->inp_flow); + + db_print_inconninfo(&inp->inp_inc, "inp_conninfo", indent); + + db_print_indent(indent); + db_printf("inp_ppcb: %p inp_pcbinfo: %p inp_socket: %p\n", + inp->inp_ppcb, inp->inp_pcbinfo, inp->inp_socket); + + db_print_indent(indent); + db_printf("inp_label: %p inp_flags: 0x%x (", + inp->inp_label, inp->inp_flags); + db_print_inpflags(inp->inp_flags); + db_printf(")\n"); + + db_print_indent(indent); + db_printf("inp_sp: %p inp_vflag: 0x%x (", inp->inp_sp, + inp->inp_vflag); + db_print_inpvflag(inp->inp_vflag); + db_printf(")\n"); + + db_print_indent(indent); + db_printf("inp_ip_ttl: %d inp_ip_p: %d inp_ip_minttl: %d\n", + inp->inp_ip_ttl, inp->inp_ip_p, inp->inp_ip_minttl); + + db_print_indent(indent); +#ifdef INET6 + if (inp->inp_vflag & INP_IPV6) { + db_printf("in6p_options: %p in6p_outputopts: %p " + "in6p_moptions: %p\n", inp->in6p_options, + inp->in6p_outputopts, inp->in6p_moptions); + db_printf("in6p_icmp6filt: %p in6p_cksum %d " + "in6p_hops %u\n", inp->in6p_icmp6filt, inp->in6p_cksum, + inp->in6p_hops); + } else +#endif + { + db_printf("inp_ip_tos: %d inp_ip_options: %p " + "inp_ip_moptions: %p\n", inp->inp_ip_tos, + inp->inp_options, inp->inp_moptions); + } + + db_print_indent(indent); + db_printf("inp_phd: %p inp_gencnt: %ju\n", inp->inp_phd, + (uintmax_t)inp->inp_gencnt); +} + +DB_SHOW_COMMAND(inpcb, db_show_inpcb) +{ + struct inpcb *inp; + + if (!have_addr) { + db_printf("usage: show inpcb <addr>\n"); + return; + } + inp = (struct inpcb *)addr; + + db_print_inpcb(inp, "inpcb", 0); +} +#endif diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h index cb2cbfd..be0bfcf 100644 --- a/sys/netinet/in_pcb.h +++ b/sys/netinet/in_pcb.h @@ -370,6 +370,12 @@ struct sockaddr * void in_pcbsosetlabel(struct socket *so); void in_pcbremlists(struct inpcb *inp); void ipport_tick(void *xtp); + +/* + * Debugging routines compiled in when DDB is present. + */ +void db_print_inpcb(struct inpcb *inp, const char *name, int indent); + #endif /* _KERNEL */ #endif /* !_NETINET_IN_PCB_H_ */ diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index 85f3222..c4362cf 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -1,7 +1,7 @@ /*- * Copyright (c) 1982, 1986, 1988, 1993 * The Regents of the University of California. - * Copyright (c) 2006 Robert N. M. Watson + * Copyright (c) 2006-2007 Robert N. M. Watson * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,6 +32,7 @@ * $FreeBSD$ */ +#include "opt_ddb.h" #include "opt_inet.h" #include "opt_inet6.h" #include "opt_tcpdebug.h" @@ -51,6 +52,10 @@ #include <sys/proc.h> #include <sys/jail.h> +#ifdef DDB +#include <ddb/ddb.h> +#endif + #include <net/if.h> #include <net/route.h> @@ -1581,3 +1586,318 @@ tcp_usrclosed(tp) tcp_timer_2msl, tp); } } + +#ifdef DDB +static void +db_print_indent(int indent) +{ + int i; + + for (i = 0; i < indent; i++) + db_printf(" "); +} + +static void +db_print_tstate(int t_state) +{ + + switch (t_state) { + case TCPS_CLOSED: + db_printf("TCPS_CLOSED"); + return; + + case TCPS_LISTEN: + db_printf("TCPS_LISTEN"); + return; + + case TCPS_SYN_SENT: + db_printf("TCPS_SYN_SENT"); + return; + + case TCPS_SYN_RECEIVED: + db_printf("TCPS_SYN_RECEIVED"); + return; + + case TCPS_ESTABLISHED: + db_printf("TCPS_ESTABLISHED"); + return; + + case TCPS_CLOSE_WAIT: + db_printf("TCPS_CLOSE_WAIT"); + return; + + case TCPS_FIN_WAIT_1: + db_printf("TCPS_FIN_WAIT_1"); + return; + + case TCPS_CLOSING: + db_printf("TCPS_CLOSING"); + return; + + case TCPS_LAST_ACK: + db_printf("TCPS_LAST_ACK"); + return; + + case TCPS_FIN_WAIT_2: + db_printf("TCPS_FIN_WAIT_2"); + return; + + case TCPS_TIME_WAIT: + db_printf("TCPS_TIME_WAIT"); + return; + + default: + db_printf("unknown"); + return; + } +} + +static void +db_print_tflags(u_int t_flags) +{ + int comma; + + comma = 0; + if (t_flags & TF_ACKNOW) { + db_printf("%sTF_ACKNOW", comma ? ", " : ""); + comma = 1; + } + if (t_flags & TF_DELACK) { + db_printf("%sTF_DELACK", comma ? ", " : ""); + comma = 1; + } + if (t_flags & TF_NODELAY) { + db_printf("%sTF_NODELAY", comma ? ", " : ""); + comma = 1; + } + if (t_flags & TF_NOOPT) { + db_printf("%sTF_NOOPT", comma ? ", " : ""); + comma = 1; + } + if (t_flags & TF_SENTFIN) { + db_printf("%sTF_SENTFIN", comma ? ", " : ""); + comma = 1; + } + if (t_flags & TF_REQ_SCALE) { + db_printf("%sTF_REQ_SCALE", comma ? ", " : ""); + comma = 1; + } + if (t_flags & TF_RCVD_SCALE) { + db_printf("%sTF_RECVD_SCALE", comma ? ", " : ""); + comma = 1; + } + if (t_flags & TF_REQ_TSTMP) { + db_printf("%sTF_REQ_TSTMP", comma ? ", " : ""); + comma = 1; + } + if (t_flags & TF_RCVD_TSTMP) { + db_printf("%sTF_RCVD_TSTMP", comma ? ", " : ""); + comma = 1; + } + if (t_flags & TF_SACK_PERMIT) { + db_printf("%sTF_SACK_PERMIT", comma ? ", " : ""); + comma = 1; + } + if (t_flags & TF_NEEDSYN) { + db_printf("%sTF_NEEDSYN", comma ? ", " : ""); + comma = 1; + } + if (t_flags & TF_NEEDFIN) { + db_printf("%sTF_NEEDFIN", comma ? ", " : ""); + comma = 1; + } + if (t_flags & TF_NOPUSH) { + db_printf("%sTF_NOPUSH", comma ? ", " : ""); + comma = 1; + } + if (t_flags & TF_NOPUSH) { + db_printf("%sTF_NOPUSH", comma ? ", " : ""); + comma = 1; + } + if (t_flags & TF_MORETOCOME) { + db_printf("%sTF_MORETOCOME", comma ? ", " : ""); + comma = 1; + } + if (t_flags & TF_LQ_OVERFLOW) { + db_printf("%sTF_LQ_OVERFLOW", comma ? ", " : ""); + comma = 1; + } + if (t_flags & TF_LASTIDLE) { + db_printf("%sTF_LASTIDLE", comma ? ", " : ""); + comma = 1; + } + if (t_flags & TF_RXWIN0SENT) { + db_printf("%sTF_RXWIN0SENT", comma ? ", " : ""); + comma = 1; + } + if (t_flags & TF_FASTRECOVERY) { + db_printf("%sTF_FASTRECOVERY", comma ? ", " : ""); + comma = 1; + } + if (t_flags & TF_WASFRECOVERY) { + db_printf("%sTF_WASFRECOVERY", comma ? ", " : ""); + comma = 1; + } + if (t_flags & TF_SIGNATURE) { + db_printf("%sTF_SIGNATURE", comma ? ", " : ""); + comma = 1; + } + if (t_flags & TF_FORCEDATA) { + db_printf("%sTF_FORCEDATA", comma ? ", " : ""); + comma = 1; + } + if (t_flags & TF_TSO) { + db_printf("%sTF_TSO", comma ? ", " : ""); + comma = 1; + } +} + +static void +db_print_toobflags(char t_oobflags) +{ + int comma; + + comma = 0; + if (t_oobflags & TCPOOB_HAVEDATA) { + db_printf("%sTCPOOB_HAVEDATA", comma ? ", " : ""); + comma = 1; + } + if (t_oobflags & TCPOOB_HADDATA) { + db_printf("%sTCPOOB_HADDATA", comma ? ", " : ""); + comma = 1; + } +} + +static void +db_print_tcpcb(struct tcpcb *tp, const char *name, int indent) +{ + + db_print_indent(indent); + db_printf("%s at %p\n", name, tp); + + indent += 2; + + db_print_indent(indent); + db_printf("t_segq first: %p t_segqlen: %d t_dupacks: %d\n", + LIST_FIRST(&tp->t_segq), tp->t_segqlen, tp->t_dupacks); + + db_print_indent(indent); + db_printf("tt_rexmt: %p tt_persist: %p tt_keep: %p\n", + tp->tt_rexmt, tp->tt_persist, tp->tt_keep); + + db_print_indent(indent); + db_printf("tt_2msl: %p tt_delack: %p t_inpcb: %p\n", tp->tt_2msl, + tp->tt_delack, tp->t_inpcb); + + db_print_indent(indent); + db_printf("t_state: %d (", tp->t_state); + db_print_tstate(tp->t_state); + db_printf(")\n"); + + db_print_indent(indent); + db_printf("t_flags: 0x%x (", tp->t_flags); + db_print_tflags(tp->t_flags); + db_printf(")\n"); + + db_print_indent(indent); + db_printf("snd_una: 0x%08x snd_max: 0x%08x snd_nxt: x0%08x\n", + tp->snd_una, tp->snd_max, tp->snd_nxt); + + db_print_indent(indent); + db_printf("snd_up: 0x%08x snd_wl1: 0x%08x snd_wl2: 0x%08x\n", + tp->snd_up, tp->snd_wl1, tp->snd_wl2); + + db_print_indent(indent); + db_printf("iss: 0x%08x irs: 0x%08x rcv_nxt: 0x%08x\n", + tp->iss, tp->irs, tp->rcv_nxt); + + db_print_indent(indent); + db_printf("rcv_adv: 0x%08x rcv_wnd: %lu rcv_up: 0x%08x\n", + tp->rcv_adv, tp->rcv_wnd, tp->rcv_up); + + db_print_indent(indent); + db_printf("snd_wnd: %lu snd_cwnd: %lu snd_bwnd: %lu\n", + tp->snd_wnd, tp->snd_cwnd, tp->snd_bwnd); + + db_print_indent(indent); + db_printf("snd_ssthresh: %lu snd_bandwidth: %lu snd_recover: " + "0x%08x\n", tp->snd_ssthresh, tp->snd_bandwidth, + tp->snd_recover); + + db_print_indent(indent); + db_printf("t_maxopd: %u t_rcvtime: %lu t_startime: %lu\n", + tp->t_maxopd, tp->t_rcvtime, tp->t_starttime); + + db_print_indent(indent); + db_printf("t_rttime: %d t_rtsq: 0x%08x t_bw_rtttime: %d\n", + tp->t_rtttime, tp->t_rtseq, tp->t_bw_rtttime); + + db_print_indent(indent); + db_printf("t_bw_rtseq: 0x%08x t_rxtcur: %d t_maxseg: %u " + "t_srtt: %d\n", tp->t_bw_rtseq, tp->t_rxtcur, tp->t_maxseg, + tp->t_srtt); + + db_print_indent(indent); + db_printf("t_rttvar: %d t_rxtshift: %d t_rttmin: %u " + "t_rttbest: %u\n", tp->t_rttvar, tp->t_rxtshift, tp->t_rttmin, + tp->t_rttbest); + + db_print_indent(indent); + db_printf("t_rttupdated: %lu max_sndwnd: %lu t_softerror: %d\n", + tp->t_rttupdated, tp->max_sndwnd, tp->t_softerror); + + db_print_indent(indent); + db_printf("t_oobflags: 0x%x (", tp->t_oobflags); + db_print_toobflags(tp->t_oobflags); + db_printf(") t_iobc: 0x%02x\n", tp->t_iobc); + + db_print_indent(indent); + db_printf("snd_scale: %u rcv_scale: %u request_r_scale: %u\n", + tp->snd_scale, tp->rcv_scale, tp->request_r_scale); + + db_print_indent(indent); + db_printf("requested_s_scale: %u ts_recent: %u ts_recent_age: " + "%lu\n", tp->requested_s_scale, tp->ts_recent, tp->ts_recent_age); + + db_print_indent(indent); + db_printf("ts_offset: %u last_ack_sent: 0x%08x snd_cwnd_prev: " + "%lu\n", tp->ts_offset, tp->last_ack_sent, tp->snd_cwnd_prev); + + db_print_indent(indent); + db_printf("snd_ssthresh_prev: %lu snd_recover_prev: 0x%08x " + "t_badrxtwin: %lu\n", tp->snd_ssthresh_prev, + tp->snd_recover_prev, tp->t_badrxtwin); + + db_print_indent(indent); + db_printf("snd_limited: %u rcv_second: %lu rcv_pps: %lu " + "tcv_byps: %lu\n", tp->snd_limited, tp->rcv_second, tp->rcv_pps, + tp->rcv_byps); + + db_print_indent(indent); + db_printf("sack_enable: %d snd_numholes: %d snd_holes first: %p\n", + tp->sack_enable, tp->snd_numholes, TAILQ_FIRST(&tp->snd_holes)); + + db_print_indent(indent); + db_printf("snd_fack: 0x%08x rcv_numsacks: %d sack_newdata: " + "0x%08x\n", tp->snd_fack, tp->rcv_numsacks, tp->sack_newdata); + + /* Skip sackblks, sackhint. */ + + db_print_indent(indent); + db_printf("t_rttlow: %d rfbuf_ts: %u rfbuf_cnt: %d\n", + tp->t_rttlow, tp->rfbuf_ts, tp->rfbuf_cnt); +} + +DB_SHOW_COMMAND(tcpcb, db_show_tcpcb) +{ + struct tcpcb *tp; + + if (!have_addr) { + db_printf("usage: show tcpcb <addr>\n"); + return; + } + tp = (struct tcpcb *)addr; + + db_print_tcpcb(tp, "tcpcb", 0); +} +#endif |