Index: sys/netinet/ip_demux.c =================================================================== RCS file: /cvs/src/sys/netinet/ip_demux.c,v retrieving revision 1.12 diff -u -r1.12 ip_demux.c --- sys/netinet/ip_demux.c 1 Apr 2004 23:04:50 -0000 1.12 +++ sys/netinet/ip_demux.c 3 Apr 2004 07:21:32 -0000 @@ -14,6 +14,7 @@ #include #include #include +#include #include #include Index: sys/netinet/tcp_input.c =================================================================== RCS file: /cvs/src/sys/netinet/tcp_input.c,v retrieving revision 1.22 diff -u -r1.22 tcp_input.c --- sys/netinet/tcp_input.c 22 Mar 2004 06:38:17 -0000 1.22 +++ sys/netinet/tcp_input.c 3 Apr 2004 07:38:59 -0000 @@ -102,11 +102,6 @@ static const int tcprexmtthresh = 3; tcp_cc tcp_ccgen; - -struct tcpstat tcpstat; -SYSCTL_STRUCT(_net_inet_tcp, TCPCTL_STATS, stats, CTLFLAG_RW, - &tcpstat , tcpstat, "TCP statistics (struct tcpstat, netinet/tcp_var.h)"); - static int log_in_vain = 0; SYSCTL_INT(_net_inet_tcp, OID_AUTO, log_in_vain, CTLFLAG_RW, &log_in_vain, 0, "Log all incoming TCP connections"); Index: sys/netinet/tcp_output.c =================================================================== RCS file: /cvs/src/sys/netinet/tcp_output.c,v retrieving revision 1.10 diff -u -r1.10 tcp_output.c --- sys/netinet/tcp_output.c 8 Mar 2004 00:36:30 -0000 1.10 +++ sys/netinet/tcp_output.c 3 Apr 2004 07:22:36 -0000 @@ -49,6 +49,8 @@ #include #include #include +#include +#include #include Index: sys/netinet/tcp_subr.c =================================================================== RCS file: /cvs/src/sys/netinet/tcp_subr.c,v retrieving revision 1.18 diff -u -r1.18 tcp_subr.c --- sys/netinet/tcp_subr.c 31 Mar 2004 00:43:09 -0000 1.18 +++ sys/netinet/tcp_subr.c 3 Apr 2004 12:32:19 -0000 @@ -185,6 +185,33 @@ static void tcp_cleartaocache (void); static void tcp_notify (struct inpcb *, int); +struct tcp_stats tcpstats_ary[MAXCPU]; +#ifdef SMP +static int +sysctl_tcpstats(SYSCTL_HANDLER_ARGS) +{ + int cpu, error; + + for (cpu = error = 0; cpu < ncpus; ++cpu) { + if ((error = SYSCTL_OUT(req, (void *)&tcpstats_ary[cpu], + sizeof(struct tcp_stats)))) + break; + if ((error = SYSCTL_IN(req, (void *)&tcpstats_ary[cpu], + sizeof(struct tcp_stats)))) + break; + } + + return (error); +} +SYSCTL_PROC(_net_inet_tcp, TCPCTL_STATS, stats, CTLTYPE_OPAQUE|CTLFLAG_RW, + 0, 0, sysctl_tcpstats, "S,tcp_stats", + "TCP statistics (struct tcp_stats, netinet/tcp_stats.h)"); +#else /* !SMP */ +SYSCTL_STRUCT(_net_inet_tcp, TCPCTL_STATS, stats, CTLFLAG_RW, + &tcpstat , tcp_stats, + "TCP statistics (struct tcp_stats, netinet/tcp_stats.h)"); +#endif + /* * Target size of TCP PCB hash tables. Must be a power of two. * @@ -280,6 +307,21 @@ panic("tcp_init"); #undef TCP_MINPROTOHDR + /* + * Initialize TCP statistics. + * + * It is layed out as an array which is has one element for UP, + * and SMP_MAXCPU elements for SMP. This allows us to retain + * the access mechanism from userland for both UP and SMP. + */ +#ifdef SMP + for (cpu = 0; cpu < ncpus; ++cpu) { + bzero(&tcpstats_ary[cpu], sizeof(struct tcp_stats)); + } +#else + bzero(&tcpstat, sizeof(struct tcp_stats)); +#endif + syncache_init(); tcp_thread_init(); } Index: sys/netinet/tcp_timer.c =================================================================== RCS file: /cvs/src/sys/netinet/tcp_timer.c,v retrieving revision 1.6 diff -u -r1.6 tcp_timer.c --- sys/netinet/tcp_timer.c 8 Mar 2004 00:39:00 -0000 1.6 +++ sys/netinet/tcp_timer.c 3 Apr 2004 07:23:55 -0000 @@ -48,6 +48,8 @@ #include #include #include +#include +#include #include /* before tcp_seq.h, for tcp_random18() */ Index: sys/netinet/tcp_var.h =================================================================== RCS file: /cvs/src/sys/netinet/tcp_var.h,v retrieving revision 1.15 diff -u -r1.15 tcp_var.h --- sys/netinet/tcp_var.h 14 Mar 2004 08:21:53 -0000 1.15 +++ sys/netinet/tcp_var.h 3 Apr 2004 06:47:26 -0000 @@ -41,6 +41,10 @@ #include /* needed for in_conninfo, inp_gen_t */ +#ifndef _NETINET_TCP_STATS_H_ +#include +#endif + /* * Kernel variables for tcp. */ @@ -305,103 +309,6 @@ + (tp)->t_rttvar) >> TCP_DELTA_SHIFT) /* - * TCP statistics. - * Many of these should be kept per connection, - * but that's inconvenient at the moment. - */ -struct tcpstat { - u_long tcps_connattempt; /* connections initiated */ - u_long tcps_accepts; /* connections accepted */ - u_long tcps_connects; /* connections established */ - u_long tcps_drops; /* connections dropped */ - u_long tcps_conndrops; /* embryonic connections dropped */ - u_long tcps_closed; /* conn. closed (includes drops) */ - u_long tcps_segstimed; /* segs where we tried to get rtt */ - u_long tcps_rttupdated; /* times we succeeded */ - u_long tcps_delack; /* delayed acks sent */ - u_long tcps_timeoutdrop; /* conn. dropped in rxmt timeout */ - u_long tcps_rexmttimeo; /* retransmit timeouts */ - u_long tcps_persisttimeo; /* persist timeouts */ - u_long tcps_keeptimeo; /* keepalive timeouts */ - u_long tcps_keepprobe; /* keepalive probes sent */ - u_long tcps_keepdrops; /* connections dropped in keepalive */ - - u_long tcps_sndtotal; /* total packets sent */ - u_long tcps_sndpack; /* data packets sent */ - u_long tcps_sndbyte; /* data bytes sent */ - u_long tcps_sndrexmitpack; /* data packets retransmitted */ - u_long tcps_sndrexmitbyte; /* data bytes retransmitted */ - u_long tcps_sndfastrexmit; /* Fast Retransmissions */ - u_long tcps_sndearlyrexmit; /* early Fast Retransmissions */ - u_long tcps_sndlimited; /* Limited Transmit packets */ - u_long tcps_sndrtobad; /* spurious RTO retransmissions */ - u_long tcps_sndfastrexmitbad; /* spurious Fast Retransmissions */ - u_long tcps_sndearlyrexmitbad; /* spurious early Fast Retransmissions, - a subset of tcps_sndfastrexmitbad */ - u_long tcps_eifeldetected; /* Eifel-detected spurious rexmits */ - u_long tcps_rttcantdetect; /* Eifel but not 1/2 RTT-detectable */ - u_long tcps_rttdetected; /* RTT-detected spurious RTO rexmits */ - u_long tcps_sndacks; /* ack-only packets sent */ - u_long tcps_sndprobe; /* window probes sent */ - u_long tcps_sndurg; /* packets sent with URG only */ - u_long tcps_sndwinup; /* window update-only packets sent */ - u_long tcps_sndctrl; /* control (SYN|FIN|RST) packets sent */ - - u_long tcps_rcvtotal; /* total packets received */ - u_long tcps_rcvpack; /* packets received in sequence */ - u_long tcps_rcvbyte; /* bytes received in sequence */ - u_long tcps_rcvbadsum; /* packets received with ccksum errs */ - u_long tcps_rcvbadoff; /* packets received with bad offset */ - u_long tcps_rcvmemdrop; /* packets dropped for lack of memory */ - u_long tcps_rcvshort; /* packets received too short */ - u_long tcps_rcvduppack; /* duplicate-only packets received */ - u_long tcps_rcvdupbyte; /* duplicate-only bytes received */ - u_long tcps_rcvpartduppack; /* packets with some duplicate data */ - u_long tcps_rcvpartdupbyte; /* dup. bytes in part-dup. packets */ - u_long tcps_rcvoopack; /* out-of-order packets received */ - u_long tcps_rcvoobyte; /* out-of-order bytes received */ - u_long tcps_rcvpackafterwin; /* packets with data after window */ - u_long tcps_rcvbyteafterwin; /* bytes rcvd after window */ - u_long tcps_rcvafterclose; /* packets rcvd after "close" */ - u_long tcps_rcvwinprobe; /* rcvd window probe packets */ - u_long tcps_rcvdupack; /* rcvd duplicate acks */ - u_long tcps_rcvacktoomuch; /* rcvd acks for unsent data */ - u_long tcps_rcvackpack; /* rcvd ack packets */ - u_long tcps_rcvackbyte; /* bytes acked by rcvd acks */ - u_long tcps_rcvwinupd; /* rcvd window update packets */ - u_long tcps_pawsdrop; /* segments dropped due to PAWS */ - u_long tcps_predack; /* times hdr predict ok for acks */ - u_long tcps_preddat; /* times hdr predict ok for data pkts */ - u_long tcps_pcbcachemiss; - u_long tcps_cachedrtt; /* times cached RTT in route updated */ - u_long tcps_cachedrttvar; /* times cached rttvar updated */ - u_long tcps_cachedssthresh; /* times cached ssthresh updated */ - u_long tcps_usedrtt; /* times RTT initialized from route */ - u_long tcps_usedrttvar; /* times RTTVAR initialized from rt */ - u_long tcps_usedssthresh; /* times ssthresh initialized from rt*/ - u_long tcps_persistdrop; /* timeout in persist state */ - u_long tcps_badsyn; /* bogus SYN, e.g. premature ACK */ - u_long tcps_mturesent; /* resends due to MTU discovery */ - u_long tcps_listendrop; /* listen queue overflows */ - - u_long tcps_sc_added; /* entry added to syncache */ - u_long tcps_sc_retransmitted; /* syncache entry was retransmitted */ - u_long tcps_sc_dupsyn; /* duplicate SYN packet */ - u_long tcps_sc_dropped; /* could not reply to packet */ - u_long tcps_sc_completed; /* successful extraction of entry */ - u_long tcps_sc_bucketoverflow; /* syncache per-bucket limit hit */ - u_long tcps_sc_cacheoverflow; /* syncache cache limit hit */ - u_long tcps_sc_reset; /* RST removed entry from syncache */ - u_long tcps_sc_stale; /* timed out or listen socket gone */ - u_long tcps_sc_aborted; /* syncache entry aborted */ - u_long tcps_sc_badack; /* removed due to bad ACK */ - u_long tcps_sc_unreach; /* ICMP unreachable received */ - u_long tcps_sc_zonefail; /* zalloc() failed */ - u_long tcps_sc_sendcookie; /* SYN cookie sent */ - u_long tcps_sc_recvcookie; /* SYN cookie received */ -}; - -/* * TCB structure exported to user-land via sysctl(3). * Evil hack: declare only if in_pcb.h and sys/socketvar.h have been * included. Not all of our clients do. @@ -457,7 +364,6 @@ #endif extern struct inpcbinfo tcbinfo[]; -extern struct tcpstat tcpstat; /* tcp statistics */ extern int tcp_mssdflt; /* XXX */ extern int tcp_delack_enabled; extern int tcp_do_newreno; Index: usr.bin/netstat/inet.c =================================================================== RCS file: /cvs/src/usr.bin/netstat/inet.c,v retrieving revision 1.11 diff -u -r1.11 inet.c --- usr.bin/netstat/inet.c 12 Mar 2004 11:29:51 -0000 1.11 +++ usr.bin/netstat/inet.c 3 Apr 2004 12:22:21 -0000 @@ -340,22 +340,59 @@ free(buf); } +void +tcp_stats_agg(struct tcp_stats *ary, struct tcp_stats *ttl, int cpucnt) +{ + int i, off, siz; + siz = sizeof(struct tcp_stats); + + if (!ary && !ttl) + return; + + bzero(ttl, siz); + if (cpucnt == 1) { + *ttl = ary[0]; + } else { + for (i = 0; i < cpucnt; ++i) { + for (off = 0; off < siz; off += sizeof(u_long)) { + *(u_long *)((char *)(*(&ttl)) + off) += + *(u_long *)((char *)&ary[i] + off); + } + } + } +} + /* * Dump TCP statistics structure. */ void tcp_stats(u_long off __unused, char *name, int af __unused) { - struct tcpstat tcpstat, zerostat; - size_t len = sizeof tcpstat; + struct tcp_stats tcpstat, *stattmp; + struct tcp_stats zerostat[SMP_MAXCPU]; + size_t len = sizeof(struct tcp_stats) * SMP_MAXCPU; + int cpucnt; if (zflag) - memset(&zerostat, 0, len); - if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len, - zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { - warn("sysctl: net.inet.tcp.stats"); + memset(zerostat, 0, len); + + if ((stattmp = malloc(len)) == NULL) { return; + } else { + if (sysctlbyname("net.inet.tcp.stats", stattmp, &len, + zflag ? zerostat : NULL, zflag ? len : 0) < 0) { + warn("sysctl: net.inet.tcp.stats"); + free(stattmp); + return; + } else { + if ((stattmp = realloc(stattmp, len)) == NULL) { + warn("tcp_stats"); + return; + } + } } + cpucnt = len / sizeof(struct tcp_stats); + tcp_stats_agg(stattmp, &tcpstat, cpucnt); #ifdef INET6 if (tcp_done != 0) @@ -458,6 +495,7 @@ p(tcps_sc_zonefail, "\t\t%lu zone failures\n"); p(tcps_sc_sendcookie, "\t%lu cookies sent\n"); p(tcps_sc_recvcookie, "\t%lu cookies received\n"); + free(stattmp); #undef p #undef p1a #undef p2 --- /dev/null Sat Apr 3 06:59:46 2004 +++ sys/netinet/tcp_stats.h Sat Apr 3 07:33:41 2004 @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2003-2004 + * Hiten Pandya . All rights reserved. + * + * Copyright (c) 1982, 1986, 1993, 1994, 1995 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $DragonFly$ + */ + +#ifndef _NETINET_TCP_STATS_H_ +#define _NETINET_TCP_STATS_H_ + +#ifdef _KERNEL +#ifdef SMP +/* + * Uglyness, but it allows us to safely redefine in a critical path + * function, so a cached globaldata pointer can be accessed. HMP. + */ +#define _GD mycpu +#define tcpstat tcpstats_ary[_GD->gd_cpuid] +#else /* !SMP */ +#define tcpstat tcpstats_ary[0] /* only one CPU */ +#endif + +struct tcp_stats; +extern struct tcp_stats tcpstats_ary[MAXCPU]; +#endif + +/* + * TCP statistics. + * + * Many of these should be kept per connection, + * but that's inconvenient at the moment. + */ +struct tcp_stats { + u_long tcps_connattempt; /* connections initiated */ + u_long tcps_accepts; /* connections accepted */ + u_long tcps_connects; /* connections established */ + u_long tcps_drops; /* connections dropped */ + u_long tcps_conndrops; /* embryonic connections dropped */ + u_long tcps_closed; /* conn. closed (includes drops) */ + u_long tcps_segstimed; /* segs where we tried to get rtt */ + u_long tcps_rttupdated; /* times we succeeded */ + u_long tcps_delack; /* delayed acks sent */ + u_long tcps_timeoutdrop; /* conn. dropped in rxmt timeout */ + u_long tcps_rexmttimeo; /* retransmit timeouts */ + u_long tcps_persisttimeo; /* persist timeouts */ + u_long tcps_keeptimeo; /* keepalive timeouts */ + u_long tcps_keepprobe; /* keepalive probes sent */ + u_long tcps_keepdrops; /* connections dropped in keepalive */ + + u_long tcps_sndtotal; /* total packets sent */ + u_long tcps_sndpack; /* data packets sent */ + u_long tcps_sndbyte; /* data bytes sent */ + u_long tcps_sndrexmitpack; /* data packets retransmitted */ + u_long tcps_sndrexmitbyte; /* data bytes retransmitted */ + u_long tcps_sndfastrexmit; /* Fast Retransmissions */ + u_long tcps_sndearlyrexmit; /* early Fast Retransmissions */ + u_long tcps_sndlimited; /* Limited Transmit packets */ + u_long tcps_sndrtobad; /* spurious RTO retransmissions */ + u_long tcps_sndfastrexmitbad; /* spurious Fast Retransmissions */ + u_long tcps_sndearlyrexmitbad; /* spurious early Fast Retransmissions, + a subset of tcps_sndfastrexmitbad */ + u_long tcps_eifeldetected; /* Eifel-detected spurious rexmits */ + u_long tcps_rttcantdetect; /* Eifel but not 1/2 RTT-detectable */ + u_long tcps_rttdetected; /* RTT-detected spurious RTO rexmits */ + u_long tcps_sndacks; /* ack-only packets sent */ + u_long tcps_sndprobe; /* window probes sent */ + u_long tcps_sndurg; /* packets sent with URG only */ + u_long tcps_sndwinup; /* window update-only packets sent */ + u_long tcps_sndctrl; /* control (SYN|FIN|RST) packets sent */ + + u_long tcps_rcvtotal; /* total packets received */ + u_long tcps_rcvpack; /* packets received in sequence */ + u_long tcps_rcvbyte; /* bytes received in sequence */ + u_long tcps_rcvbadsum; /* packets received with ccksum errs */ + u_long tcps_rcvbadoff; /* packets received with bad offset */ + u_long tcps_rcvmemdrop; /* packets dropped for lack of memory */ + u_long tcps_rcvshort; /* packets received too short */ + u_long tcps_rcvduppack; /* duplicate-only packets received */ + u_long tcps_rcvdupbyte; /* duplicate-only bytes received */ + u_long tcps_rcvpartduppack; /* packets with some duplicate data */ + u_long tcps_rcvpartdupbyte; /* dup. bytes in part-dup. packets */ + u_long tcps_rcvoopack; /* out-of-order packets received */ + u_long tcps_rcvoobyte; /* out-of-order bytes received */ + u_long tcps_rcvpackafterwin; /* packets with data after window */ + u_long tcps_rcvbyteafterwin; /* bytes rcvd after window */ + u_long tcps_rcvafterclose; /* packets rcvd after "close" */ + u_long tcps_rcvwinprobe; /* rcvd window probe packets */ + u_long tcps_rcvdupack; /* rcvd duplicate acks */ + u_long tcps_rcvacktoomuch; /* rcvd acks for unsent data */ + u_long tcps_rcvackpack; /* rcvd ack packets */ + u_long tcps_rcvackbyte; /* bytes acked by rcvd acks */ + u_long tcps_rcvwinupd; /* rcvd window update packets */ + u_long tcps_pawsdrop; /* segments dropped due to PAWS */ + u_long tcps_predack; /* times hdr predict ok for acks */ + u_long tcps_preddat; /* times hdr predict ok for data pkts */ + u_long tcps_pcbcachemiss; + u_long tcps_cachedrtt; /* times cached RTT in route updated */ + u_long tcps_cachedrttvar; /* times cached rttvar updated */ + u_long tcps_cachedssthresh; /* times cached ssthresh updated */ + u_long tcps_usedrtt; /* times RTT initialized from route */ + u_long tcps_usedrttvar; /* times RTTVAR initialized from rt */ + u_long tcps_usedssthresh; /* times ssthresh initialized from rt*/ + u_long tcps_persistdrop; /* timeout in persist state */ + u_long tcps_badsyn; /* bogus SYN, e.g. premature ACK */ + u_long tcps_mturesent; /* resends due to MTU discovery */ + u_long tcps_listendrop; /* listen queue overflows */ + + u_long tcps_sc_added; /* entry added to syncache */ + u_long tcps_sc_retransmitted; /* syncache entry was retransmitted */ + u_long tcps_sc_dupsyn; /* duplicate SYN packet */ + u_long tcps_sc_dropped; /* could not reply to packet */ + u_long tcps_sc_completed; /* successful extraction of entry */ + u_long tcps_sc_bucketoverflow; /* syncache per-bucket limit hit */ + u_long tcps_sc_cacheoverflow; /* syncache cache limit hit */ + u_long tcps_sc_reset; /* RST removed entry from syncache */ + u_long tcps_sc_stale; /* timed out or listen socket gone */ + u_long tcps_sc_aborted; /* syncache entry aborted */ + u_long tcps_sc_badack; /* removed due to bad ACK */ + u_long tcps_sc_unreach; /* ICMP unreachable received */ + u_long tcps_sc_zonefail; /* zalloc() failed */ + u_long tcps_sc_sendcookie; /* SYN cookie sent */ + u_long tcps_sc_recvcookie; /* SYN cookie received */ +}; + +#endif /* _NETINET_TCP_STATS_H_ */