diff options
author | Alan Maguire <Alan.Maguire@Sun.COM> | 2010-05-27 17:29:51 -0400 |
---|---|---|
committer | Alan Maguire <Alan.Maguire@Sun.COM> | 2010-05-27 17:29:51 -0400 |
commit | 9cd928fe5e3ea4e05f64cfb380beb54b2623e7dc (patch) | |
tree | 55e1b2b427e91454fb4bd504a6dafd70813a6891 | |
parent | 39cd77a06f56f308333bd7b2d8aae1b1467be113 (diff) | |
download | illumos-gate-9cd928fe5e3ea4e05f64cfb380beb54b2623e7dc.tar.gz |
PSARC 2010/106 DTrace TCP and UDP providers
6742331 DTrace TCP Provider
6932981 DTrace UDP provider
50 files changed, 2197 insertions, 79 deletions
diff --git a/usr/src/cmd/dtrace/demo/Makefile b/usr/src/cmd/dtrace/demo/Makefile index caa35d2395..c55a43b4f2 100644 --- a/usr/src/cmd/dtrace/demo/Makefile +++ b/usr/src/cmd/dtrace/demo/Makefile @@ -19,8 +19,7 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. # include ../../Makefile.cmd @@ -83,12 +82,26 @@ DFILES = \ specopen.d \ ssd.d \ syscall.d \ + tcp1stbyte.d \ + tcpbytes.d \ + tcpbytesstat.d \ + tcpconnlat.d \ + tcpio.d \ + tcpioflags.d \ + tcpsnoop.d \ + tcpstate.d \ + tcptop.d \ tick.d \ ticktime.d \ time.d \ tracewrite.d \ trunc.d \ trussrw.d \ + udpbytes.d \ + udpbytesstat.d \ + udpio.d \ + udpsnoop.d \ + udptop.d \ userfunc.d \ whatfor.d \ whatlock.d \ diff --git a/usr/src/cmd/dtrace/demo/chapters b/usr/src/cmd/dtrace/demo/chapters index 09a277af7e..2160a0cfe0 100644 --- a/usr/src/cmd/dtrace/demo/chapters +++ b/usr/src/cmd/dtrace/demo/chapters @@ -113,3 +113,13 @@ title: ip Provider index: 101 url: http://wikis.sun.com/display/DTrace/ip+Provider +name: tcp +title: tcp Provider +index: 102 +url: http://wikis.sun.com/display/DTrace/tcp+Provider + +name: udp +title: udp Provider +index: 103 +url: http://wikis.sun.com/display/DTrace/udp+Provider + diff --git a/usr/src/cmd/dtrace/demo/tcp/tcp1stbyte.d b/usr/src/cmd/dtrace/demo/tcp/tcp1stbyte.d new file mode 100644 index 0000000000..94001296fa --- /dev/null +++ b/usr/src/cmd/dtrace/demo/tcp/tcp1stbyte.d @@ -0,0 +1,37 @@ +#!/usr/sbin/dtrace -s +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +tcp:::connect-established +{ + start[args[1]->cs_cid] = timestamp; +} + +tcp:::receive +/start[args[1]->cs_cid] && (args[2]->ip_plength - args[4]->tcp_offset) > 0/ +{ + @latency["1st Byte Latency (ns)", args[2]->ip_saddr] = + quantize(timestamp - start[args[1]->cs_cid]); + start[args[1]->cs_cid] = 0; +} diff --git a/usr/src/cmd/dtrace/demo/tcp/tcpbytes.d b/usr/src/cmd/dtrace/demo/tcp/tcpbytes.d new file mode 100644 index 0000000000..7fb68de973 --- /dev/null +++ b/usr/src/cmd/dtrace/demo/tcp/tcpbytes.d @@ -0,0 +1,36 @@ +#!/usr/sbin/dtrace -s +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +tcp:::receive +{ + @bytes[args[2]->ip_saddr, args[4]->tcp_dport] = + sum(args[2]->ip_plength - args[4]->tcp_offset); +} + +tcp:::send +{ + @bytes[args[2]->ip_daddr, args[4]->tcp_sport] = + sum(args[2]->ip_plength - args[4]->tcp_offset); +} diff --git a/usr/src/cmd/dtrace/demo/tcp/tcpbytesstat.d b/usr/src/cmd/dtrace/demo/tcp/tcpbytesstat.d new file mode 100644 index 0000000000..ecd9b04455 --- /dev/null +++ b/usr/src/cmd/dtrace/demo/tcp/tcpbytesstat.d @@ -0,0 +1,45 @@ +#!/usr/sbin/dtrace -s +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#pragma D option quiet + +tcp:::receive +{ + @bytes[args[2]->ip_saddr, args[4]->tcp_dport] = + sum(args[2]->ip_plength - args[4]->tcp_offset); +} + +tcp:::send +{ + @bytes[args[2]->ip_daddr, args[4]->tcp_sport] = + sum(args[2]->ip_plength - args[4]->tcp_offset); +} + +profile:::tick-1sec +{ + printf("\n %-32s %16s\n", "HOST", "BYTES/s"); + printa(" %-32s %@16d\n", @bytes); + trunc(@bytes); +} diff --git a/usr/src/cmd/dtrace/demo/tcp/tcpconnlat.d b/usr/src/cmd/dtrace/demo/tcp/tcpconnlat.d new file mode 100644 index 0000000000..bc395f9711 --- /dev/null +++ b/usr/src/cmd/dtrace/demo/tcp/tcpconnlat.d @@ -0,0 +1,37 @@ +#!/usr/sbin/dtrace -s +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +tcp:::connect-request +{ + start[args[1]->cs_cid] = timestamp; +} + +tcp:::connect-established +/start[args[1]->cs_cid] / +{ + @latency["Connect Latency (ns)", args[3]->tcps_raddr] = + quantize(timestamp - start[args[1]->cs_cid]); + start[args[1]->cs_cid] = 0; +} diff --git a/usr/src/cmd/dtrace/demo/tcp/tcpio.d b/usr/src/cmd/dtrace/demo/tcp/tcpio.d new file mode 100644 index 0000000000..b3628430b4 --- /dev/null +++ b/usr/src/cmd/dtrace/demo/tcp/tcpio.d @@ -0,0 +1,32 @@ +#!/usr/sbin/dtrace -s +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +tcp:::send, +tcp:::receive +{ + printf("%15s:%-5d -> %15s:%-5d", + args[2]->ip_saddr, args[4]->tcp_sport, + args[2]->ip_daddr, args[4]->tcp_dport); +} diff --git a/usr/src/cmd/dtrace/demo/tcp/tcpioflags.d b/usr/src/cmd/dtrace/demo/tcp/tcpioflags.d new file mode 100644 index 0000000000..cdfbd2aa2b --- /dev/null +++ b/usr/src/cmd/dtrace/demo/tcp/tcpioflags.d @@ -0,0 +1,64 @@ +#!/usr/sbin/dtrace -s +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#pragma D option quiet +#pragma D option switchrate=10hz + +dtrace:::BEGIN +{ + printf(" %15s:%-5s %15s:%-5s %6s %s\n", + "LADDR", "PORT", "RADDR", "PORT", "BYTES", "FLAGS"); +} + +tcp:::send +{ + this->length = args[2]->ip_plength - args[4]->tcp_offset; + printf(" %15s:%-5d -> %15s:%-5d %6d (", + args[2]->ip_saddr, args[4]->tcp_sport, + args[2]->ip_daddr, args[4]->tcp_dport, this->length); +} + +tcp:::receive +{ + this->length = args[2]->ip_plength - args[4]->tcp_offset; + printf(" %15s:%-5d <- %15s:%-5d %6d (", + args[2]->ip_daddr, args[4]->tcp_dport, + args[2]->ip_saddr, args[4]->tcp_sport, this->length); +} + +tcp:::send, +tcp:::receive +{ + printf("%s", args[4]->tcp_flags & TH_FIN ? "FIN|" : ""); + printf("%s", args[4]->tcp_flags & TH_SYN ? "SYN|" : ""); + printf("%s", args[4]->tcp_flags & TH_RST ? "RST|" : ""); + printf("%s", args[4]->tcp_flags & TH_PUSH ? "PUSH|" : ""); + printf("%s", args[4]->tcp_flags & TH_ACK ? "ACK|" : ""); + printf("%s", args[4]->tcp_flags & TH_URG ? "URG|" : ""); + printf("%s", args[4]->tcp_flags & TH_ECE ? "ECE|" : ""); + printf("%s", args[4]->tcp_flags & TH_CWR ? "CWR|" : ""); + printf("%s", args[4]->tcp_flags == 0 ? "null " : ""); + printf("\b)\n"); +} diff --git a/usr/src/cmd/dtrace/demo/tcp/tcpsnoop.d b/usr/src/cmd/dtrace/demo/tcp/tcpsnoop.d new file mode 100644 index 0000000000..9d44519e80 --- /dev/null +++ b/usr/src/cmd/dtrace/demo/tcp/tcpsnoop.d @@ -0,0 +1,78 @@ +#!/usr/sbin/dtrace -s +/* + * tcpsnoop - snoop TCP network packets by process. + * Written using DTrace tcp Provider. + * + * This analyses TCP network packets and prints the responsible PID plus + * standard details such as IP address and port. This captures traffic + * from existing and newly created TCP connections. It can help identify + * which processes are causing TCP traffic. + * + * SEE ALSO: snoop -rS + * + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * + * Portions Copyright 2010 Brendan Gregg + */ + +#pragma D option quiet +#pragma D option switchrate=10hz + +dtrace:::BEGIN +{ + printf("%6s %6s %15s:%-5s %15s:%-5s %6s %s\n", + "TIME", "PID", "LADDR", "PORT", "RADDR", "PORT", "BYTES", "FLAGS"); +} + +tcp:::send +{ + this->length = args[2]->ip_plength - args[4]->tcp_offset; + printf("%6d %6d %15s:%-5d -> %15s:%-5d %6d (", + timestamp/1000, args[1]->cs_pid, args[2]->ip_saddr, + args[4]->tcp_sport, args[2]->ip_daddr, args[4]->tcp_dport, + this->length); +} + +tcp:::receive +{ + this->length = args[2]->ip_plength - args[4]->tcp_offset; + printf("%6d %6d %15s:%-5d <- %15s:%-5d %6d (", + timestamp/1000, args[1]->cs_pid, args[2]->ip_daddr, + args[4]->tcp_dport, args[2]->ip_saddr, args[4]->tcp_sport, + this->length); +} + +tcp:::send, +tcp:::receive +{ + printf("%s", args[4]->tcp_flags & TH_FIN ? "FIN|" : ""); + printf("%s", args[4]->tcp_flags & TH_SYN ? "SYN|" : ""); + printf("%s", args[4]->tcp_flags & TH_RST ? "RST|" : ""); + printf("%s", args[4]->tcp_flags & TH_PUSH ? "PUSH|" : ""); + printf("%s", args[4]->tcp_flags & TH_ACK ? "ACK|" : ""); + printf("%s", args[4]->tcp_flags & TH_URG ? "URG|" : ""); + printf("%s", args[4]->tcp_flags & TH_ECE ? "ECE|" : ""); + printf("%s", args[4]->tcp_flags & TH_CWR ? "CWR|" : ""); + printf("%s", args[4]->tcp_flags == 0 ? "null " : ""); + printf("\b)\n"); +} diff --git a/usr/src/cmd/dtrace/demo/tcp/tcpstate.d b/usr/src/cmd/dtrace/demo/tcp/tcpstate.d new file mode 100644 index 0000000000..38f0470a08 --- /dev/null +++ b/usr/src/cmd/dtrace/demo/tcp/tcpstate.d @@ -0,0 +1,39 @@ +#!/usr/sbin/dtrace -s +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#pragma D option quiet + +dtrace:::BEGIN +{ + printf("%-10s %-10s %-20s %-20s\n", "C", "PID", "PREV", "NEW"); +} + + +tcp:::state-change +{ + printf("%-10d %-10d %-20s -> %-20s\n", cpu, args[1]->cs_pid, + tcp_state_string[args[5]->tcps_state], + tcp_state_string[args[3]->tcps_state]); +} diff --git a/usr/src/cmd/dtrace/demo/tcp/tcptop.d b/usr/src/cmd/dtrace/demo/tcp/tcptop.d new file mode 100644 index 0000000000..450f496ebc --- /dev/null +++ b/usr/src/cmd/dtrace/demo/tcp/tcptop.d @@ -0,0 +1,138 @@ +#!/usr/sbin/dtrace -s +/* + * tcptop: display top TCP network packets by process. + * Written using DTrace tcp Provider. + * + * Usage: dtrace -s tcptop.d [count] [interval] + * + * This analyses TCP network packets and prints the responsible PID plus + * standard details such as IP address and port. This captures traffic + * of newly created TCP connections that were established while this program + * was running along with traffic from existing connections. It can help + * identify which processes is causing TCP traffic. + * + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * + * Portions Copyright 2010 Brendan Gregg + */ + +#pragma D option quiet +#pragma D option defaultargs +#pragma D option switchrate=10hz + +/* + * Print header + */ +dtrace:::BEGIN +{ + /* starting values */ + counts = $1 ? $1 : 10; + secs = $2 ? $2 : 5; + TCP_out = 0; + TCP_in = 0; + + printf("Sampling... Please wait.\n"); +} + + +tcp:::send +/ args[1]->cs_pid != -1 / +{ + @out[args[1]->cs_zoneid, args[1]->cs_pid, args[2]->ip_saddr, + args[4]->tcp_sport, args[2]->ip_daddr, args[4]->tcp_dport] = + sum(args[2]->ip_plength - args[4]->tcp_offset); +} + +tcp:::receive +/ args[1]->cs_pid != -1 / +{ + @out[args[1]->cs_zoneid, args[1]->cs_pid, args[2]->ip_daddr, + args[4]->tcp_dport, args[2]->ip_saddr, args[4]->tcp_sport] = + sum(args[2]->ip_plength - args[4]->tcp_offset); +} + +/* + * TCP Systemwide Stats + */ +mib:::tcpOutDataBytes { TCP_out += args[0]; } +mib:::tcpRetransBytes { TCP_out += args[0]; } +mib:::tcpInDataInorderBytes { TCP_in += args[0]; } +mib:::tcpInDataDupBytes { TCP_in += args[0]; } +mib:::tcpInDataUnorderBytes { TCP_in += args[0]; } + +profile:::tick-1sec +/secs != 0/ +{ + secs--; +} + +/* + * Print Report + */ +profile:::tick-1sec +/secs == 0/ +{ + /* fetch 1 min load average */ + this->load1a = `hp_avenrun[0] / 65536; + this->load1b = ((`hp_avenrun[0] % 65536) * 100) / 65536; + + /* convert TCP counters to Kb */ + TCP_out /= 1024; + TCP_in /= 1024; + + /* print status */ + printf("%Y, load: %d.%02d, TCPin: %6d Kb, TCPout: %6d Kb\n\n", + walltimestamp, this->load1a, this->load1b, TCP_in, TCP_out); + + /* print headers */ + printf("%6s %6s %-15s %5s %-15s %5s %9s\n", + "ZONE", "PID", "LADDR", "LPORT", "RADDR", "RPORT", "SIZE"); + + /* print data */ + printa("%6d %6d %-15s %5d %-15s %5d %@9d\n", @out); + printf("\n"); + + /* clear data */ + trunc(@out); + TCP_in = 0; + TCP_out = 0; + secs = 5; + counts--; +} + +/* + * End of program + */ +profile:::tick-1sec +/counts == 0/ +{ + exit(0); +} + +/* + * Cleanup for Ctrl-C + */ +dtrace:::END +{ + trunc(@out); +} diff --git a/usr/src/cmd/dtrace/demo/udp/udpbytes.d b/usr/src/cmd/dtrace/demo/udp/udpbytes.d new file mode 100644 index 0000000000..29d85fcd6c --- /dev/null +++ b/usr/src/cmd/dtrace/demo/udp/udpbytes.d @@ -0,0 +1,36 @@ +#!/usr/sbin/dtrace -s +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +udp:::receive +{ + @bytes[args[2]->ip_saddr, args[4]->udp_dport] = + sum(args[4]->udp_length); +} + +udp:::send +{ + @bytes[args[2]->ip_daddr, args[4]->udp_sport] = + sum(args[4]->udp_length); +} diff --git a/usr/src/cmd/dtrace/demo/udp/udpbytesstat.d b/usr/src/cmd/dtrace/demo/udp/udpbytesstat.d new file mode 100644 index 0000000000..58fa826a25 --- /dev/null +++ b/usr/src/cmd/dtrace/demo/udp/udpbytesstat.d @@ -0,0 +1,45 @@ +#!/usr/sbin/dtrace -s +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#pragma D option quiet + +udp:::receive +{ + @bytes[args[2]->ip_saddr, args[4]->udp_dport] = + sum(args[4]->udp_length); +} + +udp:::send +{ + @bytes[args[2]->ip_daddr, args[4]->udp_sport] = + sum(args[4]->udp_length); +} + +profile:::tick-1sec +{ + printf("\n %-32s %16s\n", "HOST", "BYTES/s"); + printa(" %-32s %@16d\n", @bytes); + trunc(@bytes); +} diff --git a/usr/src/cmd/dtrace/demo/udp/udpio.d b/usr/src/cmd/dtrace/demo/udp/udpio.d new file mode 100644 index 0000000000..78b3f48260 --- /dev/null +++ b/usr/src/cmd/dtrace/demo/udp/udpio.d @@ -0,0 +1,32 @@ +#!/usr/sbin/dtrace -s +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +udp:::send, +udp:::receive +{ + printf("%15s:%-5d -> %15s:%-5d", + args[2]->ip_saddr, args[4]->udp_sport, + args[2]->ip_daddr, args[4]->udp_dport); +} diff --git a/usr/src/cmd/dtrace/demo/udp/udpsnoop.d b/usr/src/cmd/dtrace/demo/udp/udpsnoop.d new file mode 100644 index 0000000000..fffc2904c0 --- /dev/null +++ b/usr/src/cmd/dtrace/demo/udp/udpsnoop.d @@ -0,0 +1,59 @@ +#!/usr/sbin/dtrace -s +/* + * udpsnoop - snoop UDP network packets by process. + * Written using DTrace udp Provider. + * + * This analyses UDP network packets and prints the responsible PID plus + * standard details such as IP address and port. This captures traffic + * from existing and newly created UDP connections. It can help identify + * which processes are causing UDP traffic. + * + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * + * Portions Copyright 2010 Brendan Gregg + */ + +#pragma D option quiet +#pragma D option switchrate=10hz + +dtrace:::BEGIN +{ + printf("%6s %6s %15s:%-5s %15s:%-5s %6s\n", + "TIME", "PID", "LADDR", "PORT", "RADDR", "PORT", "BYTES"); +} + +udp:::send +{ + printf("%6d %6d %15s:%-5d -> %15s:%-5d %6d\n", + timestamp/1000, args[1]->cs_pid, args[2]->ip_saddr, + args[4]->udp_sport, args[2]->ip_daddr, args[4]->udp_dport, + args[4]->udp_length); +} + +udp:::receive +{ + printf("%6d %6d %15s:%-5d <- %15s:%-5d %6d\n", + timestamp/1000, args[1]->cs_pid, args[2]->ip_daddr, + args[4]->udp_dport, args[2]->ip_saddr, args[4]->udp_sport, + args[4]->udp_length); +} diff --git a/usr/src/cmd/dtrace/demo/udp/udptop.d b/usr/src/cmd/dtrace/demo/udp/udptop.d new file mode 100644 index 0000000000..a626e5710f --- /dev/null +++ b/usr/src/cmd/dtrace/demo/udp/udptop.d @@ -0,0 +1,133 @@ +#!/usr/sbin/dtrace -s +/* + * udptop: display top UDP network packets by process. + * Written using DTrace udp Provider. + * + * Usage: dtrace -s udptop.d [count] [interval] + * + * This analyses UDP network packets and prints the responsible PID plus + * standard details such as IP address and port. This captures traffic + * of newly created UDP connections that were established while this program + * was running along with traffic from existing connections. It can help + * identify which processes is causing UDP traffic. + * + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + */ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * + * Portions Copyright 2010 Brendan Gregg + */ + +#pragma D option quiet +#pragma D option defaultargs +#pragma D option switchrate=10hz + +/* + * Print header + */ +dtrace:::BEGIN +{ + /* starting values */ + counts = $1 ? $1 : 10; + secs = $2 ? $2 : 5; + UDP_out = 0; + UDP_in = 0; + + printf("Sampling... Please wait.\n"); +} + + +udp:::send +/ args[1]->cs_pid != -1 / +{ + @out[args[1]->cs_zoneid, args[1]->cs_pid, args[2]->ip_saddr, + args[4]->udp_sport, args[2]->ip_daddr, args[4]->udp_dport] = + sum(args[4]->udp_length); +} + +udp:::receive +/ args[1]->cs_pid != -1 / +{ + @out[args[1]->cs_zoneid, args[1]->cs_pid, args[2]->ip_daddr, + args[4]->udp_dport, args[2]->ip_saddr, args[4]->udp_sport] = + sum(args[4]->udp_length); +} + +/* + * UDP Systemwide Stats + */ +mib:::udpHCOutDatagrams { UDP_out += args[0]; } +mib:::udpHCInDatagrams { UDP_in += args[0]; } + +profile:::tick-1sec +/secs != 0/ +{ + secs--; +} + +/* + * Print Report + */ +profile:::tick-1sec +/secs == 0/ +{ + /* fetch 1 min load average */ + this->load1a = `hp_avenrun[0] / 65536; + this->load1b = ((`hp_avenrun[0] % 65536) * 100) / 65536; + + /* print status */ + printf(%Y, load: %d.%02d, UDP datagrams in: %6d, ", + walltimestamp, this->load1a, this->load1b, UDP_in); + printf("UDP datagrams out: %6d\n\n", UDP_out); + + /* print headers */ + printf("%6s %6s %-15s %5s %-15s %5s %9s\n", + "ZONE", "PID", "LADDR", "LPORT", "RADDR", "RPORT", "SIZE"); + + /* print data */ + printa("%6d %6d %-15s %5d %-15s %5d %@9d\n", @out); + printf("\n"); + + /* clear data */ + trunc(@out); + UDP_in = 0; + UDP_out = 0; + secs = 5; + counts--; +} + +/* + * End of program + */ +profile:::tick-1sec +/counts == 0/ +{ + exit(0); +} + +/* + * Cleanup for Ctrl-C + */ +dtrace:::END +{ + trunc(@out); +} diff --git a/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4localtcp.ksh b/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4localtcp.ksh index 32ed78b47f..6fa8c35bf3 100755 --- a/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4localtcp.ksh +++ b/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4localtcp.ksh @@ -21,13 +21,11 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. # -#pragma ident "%Z%%M% %I% %E% SMI" # -# Test ip:::{send,receive} of IPv4 TCP to a remote host. +# Test {ip,tcp}:::{send,receive} of IPv4 TCP to local host. # # This may fail due to: # @@ -42,8 +40,10 @@ # following packet counts were traced: # # 3 x ip:::send (2 during the TCP handshake, then a FIN) +# 3 x tcp:::send (2 during the TCP handshake, then a FIN) # 2 x ip:::receive (1 during the TCP handshake, then the FIN ACK) -# +# 2 x tcp:::receive (1 during the TCP handshake, then the FIN ACK) + # The actual count tested is 5 each way, since we are tracing both # source and destination events. # @@ -78,28 +78,42 @@ EOPERL $dtrace -c '/usr/bin/perl test.pl' -qs /dev/stdin <<EODTRACE BEGIN { - send = receive = 0; + ipsend = tcpsend = ipreceive = tcpreceive = 0; } ip:::send /args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" && args[4]->ipv4_protocol == IPPROTO_TCP/ { - send++; + ipsend++; +} + +tcp:::send +/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local"/ +{ + tcpsend++; } ip:::receive /args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" && args[4]->ipv4_protocol == IPPROTO_TCP/ { - receive++; + ipreceive++; +} + +tcp:::receive +/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local"/ +{ + tcpreceive++; } END { printf("Minimum TCP events seen\n\n"); - printf("ip:::send - %s\n", send >= 5 ? "yes" : "no"); - printf("ip:::receive - %s\n", receive >= 5 ? "yes" : "no"); + printf("ip:::send - %s\n", ipsend >= 5 ? "yes" : "no"); + printf("ip:::receive - %s\n", ipreceive >= 5 ? "yes" : "no"); + printf("tcp:::send - %s\n", tcpsend >= 5 ? "yes" : "no"); + printf("tcp:::receive - %s\n", tcpreceive >= 5 ? "yes" : "no"); } EODTRACE diff --git a/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4localtcp.ksh.out b/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4localtcp.ksh.out index 18ed9477a0..2a85b98b6b 100644 --- a/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4localtcp.ksh.out +++ b/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4localtcp.ksh.out @@ -2,4 +2,6 @@ Minimum TCP events seen ip:::send - yes ip:::receive - yes +tcp:::send - yes +tcp:::receive - yes diff --git a/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4localudp.ksh b/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4localudp.ksh index 6ffc9bc3b2..fa8f7acfc7 100755 --- a/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4localudp.ksh +++ b/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4localudp.ksh @@ -21,10 +21,8 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. # -#pragma ident "%Z%%M% %I% %E% SMI" # # Test ip:::{send,receive} of IPv4 UDP to a local address. @@ -42,8 +40,14 @@ # following counts were traced: # # 1 x ip:::send (UDP sent to ping's base UDP port) +# 1 x udp:::send (UDP sent to ping's base UDP port) # 1 x ip:::receive (UDP received) # +# No udp:::receive event is expected as the response ping -U elicits is +# an ICMP PORT_UNREACHABLE response rather than a UDP packet, and locally +# the echo request UDP packet only reaches IP, so the udp:::receive probe +# is not triggered by it. +# if (( $# != 1 )); then print -u2 "expected one argument: <dtrace-path>" @@ -56,27 +60,34 @@ local=127.0.0.1 $dtrace -c "/usr/sbin/ping -U $local" -qs /dev/stdin <<EOF | grep -v 'is alive' BEGIN { - send = receive = 0; + ipsend = udpsend = ipreceive = 0; } ip:::send /args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" && args[4]->ipv4_protocol == IPPROTO_UDP/ { - send++; + ipsend++; +} + +udp:::send +/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local"/ +{ + udpsend++; } ip:::receive /args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" && args[4]->ipv4_protocol == IPPROTO_UDP/ { - receive++; + ipreceive++; } END { printf("Minimum UDP events seen\n\n"); - printf("ip:::send - %s\n", send >= 1 ? "yes" : "no"); - printf("ip:::receive - %s\n", receive >= 1 ? "yes" : "no"); + printf("ip:::send - %s\n", ipsend >= 1 ? "yes" : "no"); + printf("ip:::receive - %s\n", ipreceive >= 1 ? "yes" : "no"); + printf("udp:::send - %s\n", udpsend >= 1 ? "yes" : "no"); } EOF diff --git a/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4localudp.ksh.out b/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4localudp.ksh.out index eef72522ae..bca55327ef 100644 --- a/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4localudp.ksh.out +++ b/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4localudp.ksh.out @@ -2,4 +2,5 @@ Minimum UDP events seen ip:::send - yes ip:::receive - yes +udp:::send - yes diff --git a/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4remotetcp.ksh b/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4remotetcp.ksh index b55515287a..89a0cdb95e 100755 --- a/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4remotetcp.ksh +++ b/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4remotetcp.ksh @@ -21,13 +21,11 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. # -#pragma ident "%Z%%M% %I% %E% SMI" # -# Test ip:::{send,receive} of IPv4 TCP to a remote host. +# Test {tcp,ip}:::{send,receive} of IPv4 TCP to a remote host. # # This may fail due to: # @@ -42,7 +40,9 @@ # following packet counts were traced: # # 3 x ip:::send (2 during the TCP handshake, then a FIN) +# 3 x tcp:::send (2 during the TCP handshake, then a FIN) # 2 x ip:::receive (1 during the TCP handshake, then the FIN ACK) +# 2 x tcp:::receive (1 during the TCP handshake, then the FIN ACK) # if (( $# != 1 )); then @@ -81,28 +81,42 @@ EOPERL $dtrace -c '/usr/bin/perl test.pl' -qs /dev/stdin <<EODTRACE BEGIN { - send = receive = 0; + ipsend = tcpsend = ipreceive = tcpreceive = 0; } ip:::send /args[2]->ip_saddr == "$source" && args[2]->ip_daddr == "$dest" && args[4]->ipv4_protocol == IPPROTO_TCP/ { - send++; + ipsend++; +} + +tcp:::send +/args[2]->ip_saddr == "$source" && args[2]->ip_daddr == "$dest"/ +{ + tcpsend++; } ip:::receive /args[2]->ip_saddr == "$dest" && args[2]->ip_daddr == "$source" && args[4]->ipv4_protocol == IPPROTO_TCP/ { - receive++; + ipreceive++; +} + +tcp:::receive +/args[2]->ip_saddr == "$dest" && args[2]->ip_daddr == "$source"/ +{ + tcpreceive++; } END { printf("Minimum TCP events seen\n\n"); - printf("ip:::send - %s\n", send >= 3 ? "yes" : "no"); - printf("ip:::receive - %s\n", receive >= 2 ? "yes" : "no"); + printf("ip:::send - %s\n", ipsend >= 3 ? "yes" : "no"); + printf("ip:::receive - %s\n", ipreceive >= 2 ? "yes" : "no"); + printf("tcp:::send - %s\n", tcpsend >= 3 ? "yes" : "no"); + printf("tcp:::receive - %s\n", tcpreceive >= 2 ? "yes" : "no"); } EODTRACE diff --git a/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4remotetcp.ksh.out b/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4remotetcp.ksh.out index 18ed9477a0..2a85b98b6b 100644 --- a/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4remotetcp.ksh.out +++ b/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4remotetcp.ksh.out @@ -2,4 +2,6 @@ Minimum TCP events seen ip:::send - yes ip:::receive - yes +tcp:::send - yes +tcp:::receive - yes diff --git a/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteudp.ksh b/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteudp.ksh index 0e82fd8621..b0893c8161 100755 --- a/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteudp.ksh +++ b/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteudp.ksh @@ -21,13 +21,11 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. # -#pragma ident "%Z%%M% %I% %E% SMI" # -# Test ip:::{send,receive} of IPv4 UDP to a remote host. +# Test {udp,ip}:::{send,receive} of IPv4 UDP to a remote host. # # This may fail due to: # @@ -42,6 +40,7 @@ # following counts were traced: # # 1 x ip:::send (UDP sent to ping's base UDP port) +# 1 x udp:::send (UDP sent to ping's base UDP port) # if (( $# != 1 )); then @@ -64,19 +63,26 @@ fi $dtrace -c "/usr/sbin/ping -U $dest" -qs /dev/stdin <<EOF | grep -v 'is alive' BEGIN { - send = 0; + ipsend = udpsend = 0; } ip:::send /args[2]->ip_saddr == "$source" && args[2]->ip_daddr == "$dest" && args[4]->ipv4_protocol == IPPROTO_UDP/ { - send++; + ipsend++; +} + +udp:::send +/args[2]->ip_saddr == "$source" && args[2]->ip_daddr == "$dest"/ +{ + udpsend++; } END { printf("Minimum UDP events seen\n\n"); - printf("ip:::send - %s\n", send >= 1 ? "yes" : "no"); + printf("ip:::send - %s\n", ipsend >= 1 ? "yes" : "no"); + printf("udp:::send - %s\n", udpsend >= 1 ? "yes" : "no"); } EOF diff --git a/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteudp.ksh.out b/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteudp.ksh.out index 71de28cebe..bdbbe1fd65 100644 --- a/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteudp.ksh.out +++ b/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteudp.ksh.out @@ -1,4 +1,5 @@ Minimum UDP events seen ip:::send - yes +udp:::send - yes diff --git a/usr/src/cmd/dtrace/test/tst/common/ip/tst.localtcpstate.ksh b/usr/src/cmd/dtrace/test/tst/common/ip/tst.localtcpstate.ksh new file mode 100644 index 0000000000..8a65ce6f8d --- /dev/null +++ b/usr/src/cmd/dtrace/test/tst/common/ip/tst.localtcpstate.ksh @@ -0,0 +1,182 @@ +#!/usr/bin/ksh +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +# + +# +# Test tcp:::state-change and tcp:::{send,receive} by connecting to +# the local ssh service and sending a test message. This should result +# in a "Protocol mismatch" response and a close of the connection. +# A number of state transition events along with tcp fusion send and +# receive events for the message should result. +# +# This may fail due to: +# +# 1. A change to the ip stack breaking expected probe behavior, +# which is the reason we are testing. +# 2. The lo0 interface missing or not up. +# 3. The local ssh service is not online. +# 4. An unlikely race causes the unlocked global send/receive +# variables to be corrupted. +# +# This test performs a TCP connection to the ssh service (port 22) and +# checks that at least the following packet counts were traced: +# +# 3 x ip:::send (2 during the TCP handshake, then a FIN) +# 4 x tcp:::send (2 during the TCP handshake, 1 message then a FIN) +# 2 x ip:::receive (1 during the TCP handshake, then the FIN ACK) +# 3 x tcp:::receive (1 during the TCP handshake, 1 message then the FIN ACK) +# +# The actual ip count tested is 5 each way, since we are tracing both +# source and destination events. The actual tcp count tested is 7 +# each way, since the TCP fusion send/receive events will not reach IP. +# +# For this test to work, we are assuming that the TCP handshake and +# TCP close will enter the IP code path and not use tcp fusion. +# + +if (( $# != 1 )); then + print -u2 "expected one argument: <dtrace-path>" + exit 2 +fi + +dtrace=$1 +local=127.0.0.1 +tcpport=22 +DIR=/var/tmp/dtest.$$ + +mkdir $DIR +cd $DIR + +cat > test.pl <<-EOPERL + use IO::Socket; + my \$s = IO::Socket::INET->new( + Proto => "tcp", + PeerAddr => "$local", + PeerPort => $tcpport, + Timeout => 3); + die "Could not connect to host $local port $tcpport" unless \$s; + print \$s "testing state machine transitions"; + close \$s; +EOPERL + +$dtrace -c '/usr/bin/perl test.pl' -qs /dev/stdin <<EODTRACE +BEGIN +{ + ipsend = tcpsend = ipreceive = tcpreceive = 0; + connreq = connest = connaccept = 0; +} + +ip:::send +/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" && + args[4]->ipv4_protocol == IPPROTO_TCP/ +{ + ipsend++; +} + +tcp:::send +/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" && + (args[4]->tcp_sport == $tcpport || args[4]->tcp_dport == $tcpport)/ +{ + tcpsend++; +} + +ip:::receive +/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" && + args[4]->ipv4_protocol == IPPROTO_TCP/ +{ + ipreceive++; +} + +tcp:::receive +/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" && + (args[4]->tcp_sport == $tcpport || args[4]->tcp_dport == $tcpport)/ +{ + tcpreceive++; +} + +tcp:::state-change +{ + state_event[args[3]->tcps_state]++; +} + +tcp:::connect-request +/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" && + args[4]->tcp_dport == $tcpport/ +{ + connreq++; +} + +tcp:::connect-established +/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" && + args[4]->tcp_sport == $tcpport/ +{ + connest++; +} + +tcp:::accept-established +/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" && + args[4]->tcp_dport == $tcpport/ +{ + connaccept++; +} + +END +{ + printf("Minimum TCP events seen\n\n"); + printf("ip:::send - %s\n", ipsend >= 5 ? "yes" : "no"); + printf("ip:::receive - %s\n", ipreceive >= 5 ? "yes" : "no"); + printf("tcp:::send - %s\n", tcpsend >= 7 ? "yes" : "no"); + printf("tcp:::receive - %s\n", tcpreceive >= 7 ? "yes" : "no"); + printf("tcp:::state-change to syn-sent - %s\n", + state_event[TCP_STATE_SYN_SENT] >=1 ? "yes" : "no"); + printf("tcp:::state-change to syn-received - %s\n", + state_event[TCP_STATE_SYN_RECEIVED] >=1 ? "yes" : "no"); + printf("tcp:::state-change to established - %s\n", + state_event[TCP_STATE_ESTABLISHED] >= 2 ? "yes" : "no"); + printf("tcp:::state-change to fin-wait-1 - %s\n", + state_event[TCP_STATE_FIN_WAIT_1] >= 1 ? "yes" : "no"); + printf("tcp:::state-change to close-wait - %s\n", + state_event[TCP_STATE_CLOSE_WAIT] >= 1 ? "yes" : "no"); + printf("tcp:::state-change to fin-wait-2 - %s\n", + state_event[TCP_STATE_FIN_WAIT_2] >= 1 ? "yes" : "no"); + printf("tcp:::state-change to last-ack - %s\n", + state_event[TCP_STATE_LAST_ACK] >= 1 ? "yes" : "no"); + printf("tcp:::state-change to time-wait - %s\n", + state_event[TCP_STATE_TIME_WAIT] >= 1 ? "yes" : "no"); + printf("tcp:::connect-request - %s\n", + connreq >=1 ? "yes" : "no"); + printf("tcp:::connect-established - %s\n", + connest >=1 ? "yes" : "no"); + printf("tcp:::accept-established - %s\n", + connaccept >=1 ? "yes" : "no"); +} +EODTRACE + +status=$? + +cd / +/usr/bin/rm -rf $DIR + +exit $status diff --git a/usr/src/cmd/dtrace/test/tst/common/ip/tst.localtcpstate.ksh.out b/usr/src/cmd/dtrace/test/tst/common/ip/tst.localtcpstate.ksh.out new file mode 100644 index 0000000000..ea1c27e502 --- /dev/null +++ b/usr/src/cmd/dtrace/test/tst/common/ip/tst.localtcpstate.ksh.out @@ -0,0 +1,18 @@ +Minimum TCP events seen + +ip:::send - yes +ip:::receive - yes +tcp:::send - yes +tcp:::receive - yes +tcp:::state-change to syn-sent - yes +tcp:::state-change to syn-received - yes +tcp:::state-change to established - yes +tcp:::state-change to fin-wait-1 - yes +tcp:::state-change to close-wait - yes +tcp:::state-change to fin-wait-2 - yes +tcp:::state-change to last-ack - yes +tcp:::state-change to time-wait - yes +tcp:::connect-request - yes +tcp:::connect-established - yes +tcp:::accept-established - yes + diff --git a/usr/src/cmd/dtrace/test/tst/common/ip/tst.remotetcpstate.ksh b/usr/src/cmd/dtrace/test/tst/common/ip/tst.remotetcpstate.ksh new file mode 100644 index 0000000000..b6b9545d4e --- /dev/null +++ b/usr/src/cmd/dtrace/test/tst/common/ip/tst.remotetcpstate.ksh @@ -0,0 +1,172 @@ +#!/usr/bin/ksh +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +# + +# +# Test tcp:::state-change and tcp:::{send,receive} by connecting to +# the remote ssh service and sending a test message. This should result +# in a "Protocol mismatch" response and a close of the connection. +# A number of state transition events along with tcp send and receive +# events for the message should result. +# +# This may fail due to: +# +# 1. A change to the ip stack breaking expected probe behavior, +# which is the reason we are testing. +# 2. The lo0 interface missing or not up. +# 3. The remote ssh service is not online. +# 4. An unlikely race causes the unlocked global send/receive +# variables to be corrupted. +# +# This test performs a TCP connection to the ssh service (port 22) and +# checks that at least the following packet counts were traced: +# +# 4 x ip:::send (2 during the TCP handshake, the message, then a FIN) +# 4 x tcp:::send (2 during the TCP handshake, the messages, then a FIN) +# 3 x ip:::receive (1 during the TCP handshake, the response, then the FIN ACK) +# 3 x tcp:::receive (1 during the TCP handshake, the response, then the FIN ACK) +# +# For this test to work, we are assuming that the TCP handshake and +# TCP close will enter the IP code path and not use tcp fusion. +# + +if (( $# != 1 )); then + print -u2 "expected one argument: <dtrace-path>" + exit 2 +fi + +dtrace=$1 +getaddr=./get.ipv4remote.pl +tcpport=22 +DIR=/var/tmp/dtest.$$ + +if [[ ! -x $getaddr ]]; then + print -u2 "could not find or execute sub program: $getaddr" + exit 3 +fi +$getaddr $tcpport | read source dest +if (( $? != 0 )); then + exit 4 +fi + +mkdir $DIR +cd $DIR + +cat > test.pl <<-EOPERL + use IO::Socket; + my \$s = IO::Socket::INET->new( + Proto => "tcp", + PeerAddr => "$dest", + PeerPort => $tcpport, + Timeout => 3); + die "Could not connect to host $dest port $tcpport" unless \$s; + print \$s "testing state machine transitions"; + close \$s; +EOPERL + +$dtrace -c '/usr/bin/perl test.pl' -qs /dev/stdin <<EODTRACE +BEGIN +{ + ipsend = tcpsend = ipreceive = tcpreceive = 0; + connreq = connest = 0; +} + +ip:::send +/args[2]->ip_saddr == "$source" && args[2]->ip_daddr == "$dest" && + args[4]->ipv4_protocol == IPPROTO_TCP/ +{ + ipsend++; +} + +tcp:::send +/args[2]->ip_saddr == "$source" && args[2]->ip_daddr == "$dest" && + args[4]->tcp_dport == $tcpport/ +{ + tcpsend++; +} + +ip:::receive +/args[2]->ip_saddr == "$dest" && args[2]->ip_daddr == "$source" && + args[4]->ipv4_protocol == IPPROTO_TCP/ +{ + ipreceive++; +} + +tcp:::receive +/args[2]->ip_saddr == "$dest" && args[2]->ip_daddr == "$source" && + args[4]->tcp_sport == $tcpport/ +{ + tcpreceive++; +} + +tcp:::state-change +{ + state_event[args[3]->tcps_state]++; +} + +tcp:::connect-request +/args[2]->ip_saddr == "$source" && args[2]->ip_daddr == "$dest" && + args[4]->tcp_dport == $tcpport/ +{ + connreq++; +} + +tcp:::connect-established +/args[2]->ip_saddr == "$dest" && args[2]->ip_daddr == "$source" && + args[4]->tcp_sport == $tcpport/ +{ + connest++; +} + +END +{ + printf("Minimum TCP events seen\n\n"); + printf("ip:::send - %s\n", ipsend >= 4 ? "yes" : "no"); + printf("ip:::receive - %s\n", ipreceive >= 3 ? "yes" : "no"); + printf("tcp:::send - %s\n", tcpsend >= 4 ? "yes" : "no"); + printf("tcp:::receive - %s\n", tcpreceive >= 3 ? "yes" : "no"); + printf("tcp:::state-change to syn-sent - %s\n", + state_event[TCP_STATE_SYN_SENT] >=1 ? "yes" : "no"); + printf("tcp:::state-change to established - %s\n", + state_event[TCP_STATE_ESTABLISHED] >= 1 ? "yes" : "no"); + printf("tcp:::state-change to fin-wait-1 - %s\n", + state_event[TCP_STATE_FIN_WAIT_1] >= 1 ? "yes" : "no"); + printf("tcp:::state-change to fin-wait-2 - %s\n", + state_event[TCP_STATE_FIN_WAIT_2] >= 1 ? "yes" : "no"); + printf("tcp:::state-change to time-wait - %s\n", + state_event[TCP_STATE_TIME_WAIT] >= 1 ? "yes" : "no"); + printf("tcp:::connect-request - %s\n", + connreq >=1 ? "yes" : "no"); + printf("tcp:::connect-established - %s\n", + connest >=1 ? "yes" : "no"); +} +EODTRACE + +status=$? + +cd / +/usr/bin/rm -rf $DIR + +exit $status diff --git a/usr/src/cmd/dtrace/test/tst/common/ip/tst.remotetcpstate.ksh.out b/usr/src/cmd/dtrace/test/tst/common/ip/tst.remotetcpstate.ksh.out new file mode 100644 index 0000000000..27388fba65 --- /dev/null +++ b/usr/src/cmd/dtrace/test/tst/common/ip/tst.remotetcpstate.ksh.out @@ -0,0 +1,15 @@ +Minimum TCP events seen + +ip:::send - yes +ip:::receive - yes +tcp:::send - yes +tcp:::receive - yes +tcp:::state-change to syn-sent - yes +tcp:::state-change to established - yes +tcp:::state-change to fin-wait-1 - yes +tcp:::state-change to close-wait - yes +tcp:::state-change to fin-wait-2 - yes +tcp:::state-change to time-wait - yes +tcp:::connect-request - yes +tcp:::connect-established - yes + diff --git a/usr/src/lib/libdtrace/Makefile.com b/usr/src/lib/libdtrace/Makefile.com index 34c85f6102..5c90a02b98 100644 --- a/usr/src/lib/libdtrace/Makefile.com +++ b/usr/src/lib/libdtrace/Makefile.com @@ -19,8 +19,7 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. # # @@ -87,6 +86,8 @@ DLIBSRCS += \ scsi.d \ srp.d \ sysevent.d \ + tcp.d \ + udp.d \ unistd.d include ../../Makefile.lib @@ -104,6 +105,8 @@ CLEANFILES += ../common/net.sed ../common/net.d CLEANFILES += ../common/errno.d ../common/signal.d CLEANFILES += ../common/dt_errtags.c ../common/dt_names.c CLEANFILES += ../common/sysevent.sed ../common/sysevent.d +CLEANFILES += ../common/tcp.sed ../common/tcp.d +CLEANFILES += ../common/udp.sed ../common/udp.d CLOBBERFILES += drti.o @@ -182,6 +185,12 @@ pics/dt_lex.o pics/dt_grammar.o := CCVERBOSE = ../common/sysevent.d: ../common/sysevent.sed ../common/sysevent.d.in sed -f ../common/sysevent.sed < ../common/sysevent.d.in > $@ +../common/tcp.d: ..//common/tcp.sed ../common/tcp.d.in + sed -f ../common/tcp.sed < ../common/tcp.d.in > $@ + +../common/udp.d: ../common/udp.sed ../common/udp.d.in + sed -f ../common/udp.sed < ../common/udp.d.in > $@ + pics/%.o: ../$(MACH)/%.c $(COMPILE.c) -o $@ $< $(POST_PROCESS_O) diff --git a/usr/src/lib/libdtrace/common/dt_open.c b/usr/src/lib/libdtrace/common/dt_open.c index da84511a78..2b9cd7c414 100644 --- a/usr/src/lib/libdtrace/common/dt_open.c +++ b/usr/src/lib/libdtrace/common/dt_open.c @@ -20,12 +20,9 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/types.h> #include <sys/modctl.h> #include <sys/systeminfo.h> @@ -105,8 +102,9 @@ #define DT_VERS_1_6 DT_VERSION_NUMBER(1, 6, 0) #define DT_VERS_1_6_1 DT_VERSION_NUMBER(1, 6, 1) #define DT_VERS_1_6_2 DT_VERSION_NUMBER(1, 6, 2) -#define DT_VERS_LATEST DT_VERS_1_6_2 -#define DT_VERS_STRING "Sun D 1.6.2" +#define DT_VERS_1_6_3 DT_VERSION_NUMBER(1, 6, 3) +#define DT_VERS_LATEST DT_VERS_1_6_3 +#define DT_VERS_STRING "Sun D 1.6.3" const dt_version_t _dtrace_versions[] = { DT_VERS_1_0, /* D API 1.0.0 (PSARC 2001/466) Solaris 10 FCS */ @@ -121,6 +119,7 @@ const dt_version_t _dtrace_versions[] = { DT_VERS_1_6, /* D API 1.6 */ DT_VERS_1_6_1, /* D API 1.6.1 */ DT_VERS_1_6_2, /* D API 1.6.2 */ + DT_VERS_1_6_3, /* D API 1.6.3 */ 0 }; diff --git a/usr/src/lib/libdtrace/common/ip.d.in b/usr/src/lib/libdtrace/common/ip.d.in index 3bd58e7c68..f1e6332529 100644 --- a/usr/src/lib/libdtrace/common/ip.d.in +++ b/usr/src/lib/libdtrace/common/ip.d.in @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ #pragma D depends_on module ip @@ -98,12 +97,13 @@ typedef struct pktinfo { } pktinfo_t; /* - * csinfo is where connection state info can be made available if - * connection IDs become supported by the kernel in the future. - * The cs_addr member is currently always NULL. + * csinfo is where connection state info is made available. */ typedef struct csinfo { uintptr_t cs_addr; + uint64_t cs_cid; + pid_t cs_pid; + zoneid_t cs_zoneid; } csinfo_t; /* @@ -181,6 +181,17 @@ typedef uintptr_t void_ip_t; */ typedef ill_t __dtrace_ipsr_ill_t; +/* + * __dtrace_tcp_void_ip_t is used by the translator to take either the + * non-NULL void_ip_t * passed in or, if it is NULL, uses arg3 (tcp_t *) + * from the tcp:::send and tcp:::recieve probes to translate to an ipinfo_t. + * When no headers are available in the TCP fusion case for tcp:::send + * and tcp:::receive case, this allows us to present the consumer with header + * data based on the tcp_t * content in order to hide the implementation + * details of TCP fusion. + */ +typedef void * __dtrace_tcp_void_ip_t; + #pragma D binding "1.5" translator translator pktinfo_t < mblk_t *M > { pkt_addr = NULL; @@ -191,6 +202,21 @@ translator csinfo_t < conn_t *C > { cs_addr = NULL; }; +#pragma D binding "1.6.3" translator +translator csinfo_t < ip_xmit_attr_t *C > { + cs_addr = (uintptr_t)C; + cs_cid = C ? C->ixa_conn_id : NULL; + cs_pid = C ? C->ixa_cpid : -1; + cs_zoneid = C ? + (C->ixa_ipst == NULL || C->ixa_ipst->ips_netstack == NULL || + C->ixa_ipst->ips_netstack->netstack_stackid == + @GLOBAL_NETSTACKID@ || + C->ixa_cred == NULL || + C->ixa_cred->cr_zone == NULL || + C->ixa_cred->cr_uid == -1 ? + C->ixa_zoneid : C->ixa_cred->cr_zone->zone_id) : -1; +}; + #pragma D binding "1.5" translator translator ipinfo_t < ipha_t *I > { ip_ver = I->ipha_version_and_hdr_length >> 4; @@ -233,6 +259,50 @@ translator ifinfo_t < __dtrace_ipsr_ill_t *I > { if_addr = (uintptr_t)I; }; +/* + * Translate to an ipinfo_t * from either the non-NULL void_ip_t * passed in, + * or use arg3 (tcp_t *) to fabricate ip header info. + */ +#pragma D binding "1.6.3" translator +translator ipinfo_t < __dtrace_tcp_void_ip_t *I > { + ip_ver = I != NULL ? *(uint8_t *)I >> 4 : + arg3 != NULL ? ((tcp_t *)arg3)->tcp_connp->conn_ipversion : 0; + ip_plength = + I != NULL && *(uint8_t *)I >> 4 == 4 ? + ntohs(((ipha_t *)I)->ipha_length) - + ((((ipha_t *)I)->ipha_version_and_hdr_length & 0xf) << 2) : + I != NULL && *(uint8_t *)I >> 4 == 6 ? + ntohs(((ip6_t *)I)->ip6_ctlun.ip6_un1.ip6_un1_plen) : + I != NULL ? 0 : + arg3 != NULL && probename == "send" ? + ((tcp_t *)arg3)->tcp_last_sent_len + @TCP_MIN_HEADER_LENGTH@ : + arg3 != NULL && probename == "receive" ? + ((tcp_t *)arg3)->tcp_last_recv_len + @TCP_MIN_HEADER_LENGTH@ : + 0; + ip_saddr = + I != NULL && *(uint8_t *)I >> 4 == 4 ? + inet_ntoa(&((ipha_t *)I)->ipha_src) : + I != NULL && *(uint8_t *)I >> 4 == 6 ? + inet_ntoa6(&((ip6_t *)I)->ip6_src) : + I != NULL ? "<unknown>" : + arg3 != NULL && probename == "send" ? + inet_ntoa6(&((tcp_t *)arg3)->tcp_connp->connua_v6addr.connua_laddr): + arg3 != NULL && probename == "receive" ? + inet_ntoa6(&((tcp_t *)arg3)->tcp_connp->connua_v6addr.connua_faddr): + "<unknown>"; + ip_daddr = + I != NULL && *(uint8_t *)I >> 4 == 4 ? + inet_ntoa(&((ipha_t *)I)->ipha_dst) : + I != NULL && *(uint8_t *)I >> 4 == 6 ? + inet_ntoa6(&((ip6_t *)I)->ip6_dst) : + I != NULL ? "<unknown>" : + arg3 != NULL && probename == "send" ? + inet_ntoa6(&((tcp_t *)arg3)->tcp_connp->connua_v6addr.connua_faddr): + arg3 != NULL && probename == "receive" ? + inet_ntoa6(&((tcp_t *)arg3)->tcp_connp->connua_v6addr.connua_laddr): + "<unknown>"; +}; + #pragma D binding "1.5" translator translator ipv4info_t < ipha_t *I > { ipv4_ver = I != NULL ? I->ipha_version_and_hdr_length >> 4 : 0; diff --git a/usr/src/lib/libdtrace/common/ip.sed.in b/usr/src/lib/libdtrace/common/ip.sed.in index 663de0344b..5d514e36b6 100644 --- a/usr/src/lib/libdtrace/common/ip.sed.in +++ b/usr/src/lib/libdtrace/common/ip.sed.in @@ -19,12 +19,9 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * This file is a sed script which is first preprocessed by cpp or cc -E to * define a set of sed directives which replace #define tokens with their @@ -33,9 +30,11 @@ * Refer to the rules in libdtrace/Makefile.com for more information. */ +#include <sys/netstack.h> #include <sys/socket.h> #include <netinet/in.h> #include <inet/ip.h> +#include <inet/tcp.h> #define SED_REPLACE(x) s/#x/x/g @@ -73,3 +72,7 @@ SED_REPLACE(IPPROTO_PIM) SED_REPLACE(IPPROTO_SCTP) SED_REPLACE(IPPROTO_RAW) SED_REPLACE(IPPROTO_MAX) + +SED_REPLACE(TCP_MIN_HEADER_LENGTH) + +SED_REPLACE(GLOBAL_NETSTACKID) diff --git a/usr/src/lib/libdtrace/common/tcp.d.in b/usr/src/lib/libdtrace/common/tcp.d.in new file mode 100644 index 0000000000..2733e52699 --- /dev/null +++ b/usr/src/lib/libdtrace/common/tcp.d.in @@ -0,0 +1,269 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#pragma D depends_on module unix +#pragma D depends_on provider tcp + +inline int TH_FIN = @TH_FIN@; +#pragma D binding "1.6.3" TH_FIN +inline int TH_SYN = @TH_SYN@; +#pragma D binding "1.6.3" TH_SYN +inline int TH_RST = @TH_RST@; +#pragma D binding "1.6.3" TH_RST +inline int TH_PUSH = @TH_PUSH@; +#pragma D binding "1.6.3" TH_PUSH +inline int TH_ACK = @TH_ACK@; +#pragma D binding "1.6.3" TH_ACK +inline int TH_URG = @TH_URG@; +#pragma D binding "1.6.3" TH_URG +inline int TH_ECE = @TH_ECE@; +#pragma D binding "1.6.3" TH_ECE +inline int TH_CWR = @TH_CWR@; +#pragma D binding "1.6.3" TH_CWR + +inline int32_t TCP_STATE_CLOSED = @TCPS_CLOSED@; +#pragma D binding "1.6.3" TCP_STATE_CLOSED +inline int32_t TCP_STATE_IDLE = @TCPS_IDLE@; +#pragma D binding "1.6.3" TCP_STATE_IDLE +inline int32_t TCP_STATE_BOUND = @TCPS_BOUND@; +#pragma D binding "1.6.3" TCP_STATE_BOUND +inline int32_t TCP_STATE_LISTEN = @TCPS_LISTEN@; +#pragma D binding "1.6.3" TCP_STATE_LISTEN +inline int32_t TCP_STATE_SYN_SENT = @TCPS_SYN_SENT@; +#pragma D binding "1.6.3" TCP_STATE_SYN_SENT +inline int32_t TCP_STATE_SYN_RECEIVED = @TCPS_SYN_RCVD@; +#pragma D binding "1.6.3" TCP_STATE_SYN_RECEIVED +inline int32_t TCP_STATE_ESTABLISHED = @TCPS_ESTABLISHED@; +#pragma D binding "1.6.3" TCP_STATE_ESTABLISHED +inline int32_t TCP_STATE_CLOSE_WAIT = @TCPS_CLOSE_WAIT@; +#pragma D binding "1.6.3" TCP_STATE_CLOSE_WAIT +inline int32_t TCP_STATE_FIN_WAIT_1 = @TCPS_FIN_WAIT_1@; +#pragma D binding "1.6.3" TCP_STATE_FIN_WAIT_1 +inline int32_t TCP_STATE_CLOSING = @TCPS_CLOSING@; +#pragma D binding "1.6.3" TCP_STATE_CLOSING +inline int32_t TCP_STATE_LAST_ACK = @TCPS_LAST_ACK@; +#pragma D binding "1.6.3" TCP_STATE_LAST_ACK +inline int32_t TCP_STATE_FIN_WAIT_2 = @TCPS_FIN_WAIT_2@; +#pragma D binding "1.6.3" TCP_STATE_FIN_WAIT_2 +inline int32_t TCP_STATE_TIME_WAIT = @TCPS_TIME_WAIT@; +#pragma D binding "1.6.3" TCP_STATE_TIME_WAIT + +/* + * Convert a TCP state value to a string. + */ +inline string tcp_state_string[int32_t state] = + state == TCP_STATE_CLOSED ? "state-closed" : + state == TCP_STATE_IDLE ? "state-idle" : + state == TCP_STATE_BOUND ? "state-bound" : + state == TCP_STATE_LISTEN ? "state-listen" : + state == TCP_STATE_SYN_SENT ? "state-syn-sent" : + state == TCP_STATE_SYN_RECEIVED ? "state-syn-received" : + state == TCP_STATE_ESTABLISHED ? "state-established" : + state == TCP_STATE_CLOSE_WAIT ? "state-close-wait" : + state == TCP_STATE_FIN_WAIT_1 ? "state-fin-wait-1" : + state == TCP_STATE_CLOSING ? "state-closing" : + state == TCP_STATE_LAST_ACK ? "state-last-ack" : + state == TCP_STATE_FIN_WAIT_2 ? "state-fin-wait-2" : + state == TCP_STATE_TIME_WAIT ? "state-time-wait" : + "<unknown>"; +#pragma D binding "1.6.3" tcp_state_string + +/* + * tcpinfo is the TCP header fields. + */ +typedef struct tcpinfo { + uint16_t tcp_sport; /* source port */ + uint16_t tcp_dport; /* destination port */ + uint32_t tcp_seq; /* sequence number */ + uint32_t tcp_ack; /* acknowledgment number */ + uint8_t tcp_offset; /* data offset, in bytes */ + uint8_t tcp_flags; /* flags */ + uint16_t tcp_window; /* window size */ + uint16_t tcp_checksum; /* checksum */ + uint16_t tcp_urgent; /* urgent data pointer */ + tcph_t *tcp_hdr; /* raw TCP header */ +} tcpinfo_t; + +/* + * tcpsinfo contains stable TCP details from tcp_t. + */ +typedef struct tcpsinfo { + uintptr_t tcps_addr; + int tcps_local; /* is delivered locally, boolean */ + int tcps_active; /* active open (from here), boolean */ + uint16_t tcps_lport; /* local port */ + uint16_t tcps_rport; /* remote port */ + string tcps_laddr; /* local address, as a string */ + string tcps_raddr; /* remote address, as a string */ + int32_t tcps_state; /* TCP state */ + uint32_t tcps_iss; /* Initial sequence # sent */ + uint32_t tcps_suna; /* sequence # sent but unacked */ + uint32_t tcps_snxt; /* next sequence # to send */ + uint32_t tcps_rack; /* sequence # we have acked */ + uint32_t tcps_rnxt; /* next sequence # expected */ + uint32_t tcps_swnd; /* send window size */ + int32_t tcps_snd_ws; /* send window scaling */ + uint32_t tcps_rwnd; /* receive window size */ + int32_t tcps_rcv_ws; /* receive window scaling */ + uint32_t tcps_cwnd; /* congestion window */ + uint32_t tcps_cwnd_ssthresh; /* threshold for congestion avoidance */ + uint32_t tcps_sack_fack; /* SACK sequence # we have acked */ + uint32_t tcps_sack_snxt; /* next SACK seq # for retransmission */ + uint32_t tcps_rto; /* round-trip timeout, msec */ + uint32_t tcps_mss; /* max segment size */ + int tcps_retransmit; /* retransmit send event, boolean */ +} tcpsinfo_t; + +/* + * tcplsinfo provides the old tcp state for state changes. + */ +typedef struct tcplsinfo { + int32_t tcps_state; /* previous TCP state */ +} tcplsinfo_t; + +/* + * __dtrace_tcp_tcph_t is used by the tcpinfo_t * translator to take either + * the non-NULL tcph_t * passed in or, if it is NULL, uses arg3 (tcp_t *) + * from the tcp:::send and tcp:::recieve probes and translates the tcp_t * + * into the tcpinfo_t. When no headers are available - as is the case for + * TCP fusion tcp:::send and tcp:::receive - this allows us to present the + * consumer with header data based on tcp_t * content and hide TCP fusion + * implementation details. + */ +typedef tcph_t * __dtrace_tcp_tcph_t; + +#pragma D binding "1.6.3" translator +translator tcpinfo_t < tcph_t *T > { + tcp_sport = ntohs(*(uint16_t *)T->th_lport); + tcp_dport = ntohs(*(uint16_t *)T->th_fport); + tcp_seq = ntohl(*(uint32_t *)T->th_seq); + tcp_ack = ntohl(*(uint32_t *)T->th_ack); + tcp_offset = (*(uint8_t *)T->th_offset_and_rsrvd & 0xf0) >> 2; + tcp_flags = *(uint8_t *)T->th_flags; + tcp_window = ntohs(*(uint16_t *)T->th_win); + tcp_checksum = ntohs(*(uint16_t *)T->th_sum); + tcp_urgent = ntohs(*(uint16_t *)T->th_urp); + tcp_hdr = T; +}; + +#pragma D binding "1.6.3" translator +translator tcpinfo_t < __dtrace_tcp_tcph_t *T > { + tcp_sport = + T != NULL ? ntohs(*(uint16_t *)((tcph_t *)T)->th_lport) : + arg3 != NULL && probename == "send" ? + ntohs(((tcp_t *)arg3)->tcp_connp->u_port.connu_ports.connu_lport) : + arg3 != NULL && probename == "receive" ? + ntohs(((tcp_t *)arg3)->tcp_connp->u_port.connu_ports.connu_fport) : + 0; + tcp_dport = + T != NULL ? ntohs(*(uint16_t *)((tcph_t *)T)->th_fport) : + arg3 != NULL && probename == "send" ? + ntohs(((tcp_t *)arg3)->tcp_connp->u_port.connu_ports.connu_fport) : + arg3 != NULL && probename == "receive" ? + ntohs(((tcp_t *)arg3)->tcp_connp->u_port.connu_ports.connu_lport) : + 0; + tcp_seq = + T != NULL ? ntohl(*(uint32_t *)((tcph_t *)T)->th_seq) : + arg3 != NULL && probename == "send" ? + ((tcp_t *)arg3)->tcp_snxt - ((tcp_t *)arg3)->tcp_last_sent_len : + arg3 != NULL && probename == "receive" ? + ((tcp_t *)arg3)->tcp_rnxt - ((tcp_t *)arg3)->tcp_last_recv_len : + 0; + tcp_ack = + T != NULL ? ntohl(*(uint32_t *)((tcph_t *)T)->th_ack) : + arg3 != NULL && probename == "send" ? + ((tcp_t *)arg3)->tcp_rnxt : + arg3 != NULL && probename == "receive" ? + ((tcp_t *)arg3)->tcp_snxt : + 0; + tcp_offset = T != NULL ? + (*(uint8_t *)((tcph_t *)T)->th_offset_and_rsrvd & 0xf0) >> 2 : + @TCP_MIN_HEADER_LENGTH@; + tcp_flags = T != NULL ? *(uint8_t *)((tcph_t *)T)->th_flags : TH_ACK; + tcp_window = T != NULL ? ntohs(*(uint16_t *)((tcph_t *)T)->th_win) : + arg3 != NULL ? ((tcp_t *)arg3)->tcp_swnd : 0; + tcp_checksum = T != NULL ? ntohs(*(uint16_t *)((tcph_t *)T)->th_sum) : + 0; + tcp_urgent = T != NULL ? ntohs(*(uint16_t *)((tcph_t *)T)->th_urp) : 0; + tcp_hdr = NULL; +}; + +#pragma D binding "1.6.3" translator +translator tcpsinfo_t < tcp_t *T > { + tcps_addr = (uintptr_t)T; + /* + * The following two members should just use tcp_t->tcp_loopback + * and tcp_t->tcp_active_open, however these are bit fields and + * can't be used until CR 6876830 is fixed. Meanwhile we source + * them a different way. + */ + tcps_local = T ? T->tcp_ipha ? + T->tcp_ipha->ipha_src == T->tcp_ipha->ipha_dst : 1 : 0; + tcps_active = T ? !T->tcp_saved_listener : 0; + tcps_lport = T ? + ntohs(T->tcp_connp->u_port.connu_ports.connu_lport) : 0; + tcps_rport = T ? + ntohs(T->tcp_connp->u_port.connu_ports.connu_fport) : 0; + tcps_laddr = T ? + inet_ntoa6(&T->tcp_connp->connua_v6addr.connua_laddr) : "<unknown>"; + tcps_raddr = T ? + inet_ntoa6(&T->tcp_connp->connua_v6addr.connua_faddr) : "<unknown>"; + tcps_state = T ? T->tcp_state : TCP_STATE_CLOSED; + tcps_iss = T ? T->tcp_iss : 0; + tcps_suna = T ? T->tcp_suna : 0; + tcps_snxt = T ? T->tcp_snxt : 0; + tcps_rack = T ? T->tcp_rack : 0; + tcps_rnxt = T ? T->tcp_rnxt : 0; + tcps_swnd = T ? T->tcp_swnd : 0; + tcps_snd_ws = T ? T->tcp_snd_ws : 0; + tcps_rwnd = T ? T->tcp_rwnd : 0; + tcps_rcv_ws = T ? T->tcp_rcv_ws : 0; + tcps_cwnd = T ? T->tcp_cwnd : 0; + tcps_cwnd_ssthresh = T ? T->tcp_cwnd_ssthresh : 0; + tcps_sack_fack = T ? T->tcp_sack_info.tcp_fack : 0; + tcps_sack_snxt = T ? T->tcp_sack_info.tcp_sack_snxt : 0; + tcps_rto = T ? T->tcp_rto : 0; + tcps_mss = T ? T->tcp_mss : 0; + /* + * Determine if send is a retransmission by comparing the seq # to + * tcp_rexmit_nxt/tcp_rexmit_max - if the value is >= rexmit_nxt and + * < rexmit_max, this is a retransmission. Cannot use tcp_rexmit + * bitfield value due to CR 6876830. + */ + tcps_retransmit = T && probename == "send" && arg4 != NULL && + ntohl(*(uint32_t *)((tcph_t *)arg4)->th_seq) >= T->tcp_rexmit_nxt && + ntohl(*(uint32_t *)((tcph_t *)arg4)->th_seq) < T->tcp_rexmit_max ? + 1 : 0; +}; + +/* + * Note: although we specify that the old state argument used as the + * input to the tcplsinfo_t translator is an int32_t, it reaches us as an + * int64_t (since it is a probe argument) so explicitly cast it back to + * interpret the negatively-valued states correctly. + */ +#pragma D binding "1.6.3" translator +translator tcplsinfo_t < int64_t I > { + tcps_state = (int32_t) I; +}; diff --git a/usr/src/lib/libdtrace/common/tcp.sed.in b/usr/src/lib/libdtrace/common/tcp.sed.in new file mode 100644 index 0000000000..230264be37 --- /dev/null +++ b/usr/src/lib/libdtrace/common/tcp.sed.in @@ -0,0 +1,53 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#include <inet/tcp.h> +#include <sys/netstack.h> + +#define SED_REPLACE(x) s/#x/x/g + +SED_REPLACE(TH_FIN) +SED_REPLACE(TH_SYN) +SED_REPLACE(TH_RST) +SED_REPLACE(TH_PUSH) +SED_REPLACE(TH_ACK) +SED_REPLACE(TH_URG) +SED_REPLACE(TH_ECE) +SED_REPLACE(TH_CWR) + +SED_REPLACE(TCPS_CLOSED) +SED_REPLACE(TCPS_IDLE) +SED_REPLACE(TCPS_BOUND) +SED_REPLACE(TCPS_LISTEN) +SED_REPLACE(TCPS_SYN_SENT) +SED_REPLACE(TCPS_SYN_RCVD) +SED_REPLACE(TCPS_ESTABLISHED) +SED_REPLACE(TCPS_CLOSE_WAIT) +SED_REPLACE(TCPS_FIN_WAIT_1) +SED_REPLACE(TCPS_CLOSING) +SED_REPLACE(TCPS_LAST_ACK) +SED_REPLACE(TCPS_FIN_WAIT_2) +SED_REPLACE(TCPS_TIME_WAIT) + +SED_REPLACE(TCP_MIN_HEADER_LENGTH) diff --git a/usr/src/lib/libdtrace/common/udp.d.in b/usr/src/lib/libdtrace/common/udp.d.in new file mode 100644 index 0000000000..c2159016f3 --- /dev/null +++ b/usr/src/lib/libdtrace/common/udp.d.in @@ -0,0 +1,73 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#pragma D depends_on module unix +#pragma D depends_on provider udp + +inline int UDPH_SIZE = @UDPH_SIZE@; +#pragma D binding "1.6.3" UDPH_SIZE + +/* + * udpinfo is the UDP header fields. + */ +typedef struct udpinfo { + uint16_t udp_sport; /* source port */ + uint16_t udp_dport; /* destination port */ + uint16_t udp_length; /* total length */ + uint16_t udp_checksum; /* headers + data checksum */ + udpha_t *udp_hdr; /* raw UDP header */ +} udpinfo_t; + +/* + * udpsinfo contains stable UDP details from udp_t. + */ +typedef struct udpsinfo { + uintptr_t udps_addr; + uint16_t udps_lport; /* local port */ + uint16_t udps_rport; /* remote port */ + string udps_laddr; /* local address, as a string */ + string udps_raddr; /* remote address, as a string */ +} udpsinfo_t; + +#pragma D binding "1.6.3" translator +translator udpinfo_t < udpha_t *U > { + udp_sport = ntohs(U->uha_src_port); + udp_dport = ntohs(U->uha_dst_port); + udp_length = ntohs(U->uha_length); + udp_checksum = ntohs(U->uha_checksum); + udp_hdr = U; +}; + +#pragma D binding "1.6.3" translator +translator udpsinfo_t < udp_t *U > { + udps_addr = (uintptr_t)U; + udps_lport = U ? + ntohs(U->udp_connp->u_port.connu_ports.connu_lport) : 0; + udps_rport = U ? + ntohs(U->udp_connp->u_port.connu_ports.connu_fport) : 0; + udps_laddr = U ? + inet_ntoa6(&U->udp_connp->connua_v6addr.connua_laddr) : "<unknown>"; + udps_raddr = U ? + inet_ntoa6(&U->udp_connp->connua_v6addr.connua_faddr) : "<unknown>"; +}; diff --git a/usr/src/lib/libdtrace/common/udp.sed.in b/usr/src/lib/libdtrace/common/udp.sed.in new file mode 100644 index 0000000000..9c23a96a18 --- /dev/null +++ b/usr/src/lib/libdtrace/common/udp.sed.in @@ -0,0 +1,29 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#include <inet/ip.h> + +#define SED_REPLACE(x) s/#x/x/g + +SED_REPLACE(UDPH_SIZE) diff --git a/usr/src/pkg/manifests/developer-dtrace.mf b/usr/src/pkg/manifests/developer-dtrace.mf index 305aa619f0..ac7ed967b8 100644 --- a/usr/src/pkg/manifests/developer-dtrace.mf +++ b/usr/src/pkg/manifests/developer-dtrace.mf @@ -20,8 +20,7 @@ # # -# Copyright 2010 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. # set name=pkg.fmri value=pkg:/developer/dtrace@$(PKGVERS) @@ -125,13 +124,27 @@ file path=usr/demo/dtrace/spec.d file path=usr/demo/dtrace/specopen.d file path=usr/demo/dtrace/ssd.d file path=usr/demo/dtrace/syscall.d +file path=usr/demo/dtrace/tcp1stbyte.d +file path=usr/demo/dtrace/tcpbytes.d +file path=usr/demo/dtrace/tcpbytesstat.d +file path=usr/demo/dtrace/tcpconnlat.d +file path=usr/demo/dtrace/tcpio.d +file path=usr/demo/dtrace/tcpioflags.d file path=usr/demo/dtrace/tcprst.d +file path=usr/demo/dtrace/tcpsnoop.d +file path=usr/demo/dtrace/tcpstate.d +file path=usr/demo/dtrace/tcptop.d file path=usr/demo/dtrace/tick.d file path=usr/demo/dtrace/ticktime.d file path=usr/demo/dtrace/time.d file path=usr/demo/dtrace/tracewrite.d file path=usr/demo/dtrace/trunc.d file path=usr/demo/dtrace/trussrw.d +file path=usr/demo/dtrace/udpbytes.d +file path=usr/demo/dtrace/udpbytesstat.d +file path=usr/demo/dtrace/udpio.d +file path=usr/demo/dtrace/udpsnoop.d +file path=usr/demo/dtrace/udptop.d file path=usr/demo/dtrace/userfunc.d file path=usr/demo/dtrace/whatfor.d file path=usr/demo/dtrace/whatlock.d @@ -180,6 +193,8 @@ file path=usr/lib/dtrace/scsi.d file path=usr/lib/dtrace/signal.d file path=usr/lib/dtrace/srp.d file path=usr/lib/dtrace/sysevent.d +file path=usr/lib/dtrace/tcp.d +file path=usr/lib/dtrace/udp.d file path=usr/lib/dtrace/unistd.d file path=usr/lib/libdtrace.so.1 file path=usr/lib/libdtrace_jni.so.1 diff --git a/usr/src/pkg/manifests/system-dtrace-tests.mf b/usr/src/pkg/manifests/system-dtrace-tests.mf index 2c834f906b..4c8cb58a13 100644 --- a/usr/src/pkg/manifests/system-dtrace-tests.mf +++ b/usr/src/pkg/manifests/system-dtrace-tests.mf @@ -20,8 +20,7 @@ # # -# Copyright 2010 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. # set name=pkg.fmri value=pkg:/system/dtrace/tests@$(PKGVERS) @@ -835,6 +834,10 @@ file path=opt/SUNWdtrt/tst/common/ip/tst.ipv6localicmp.ksh mode=0444 file path=opt/SUNWdtrt/tst/common/ip/tst.ipv6localicmp.ksh.out mode=0444 file path=opt/SUNWdtrt/tst/common/ip/tst.ipv6remoteicmp.ksh mode=0444 file path=opt/SUNWdtrt/tst/common/ip/tst.ipv6remoteicmp.ksh.out mode=0444 +file path=opt/SUNWdtrt/tst/common/ip/tst.localtcpstate.ksh mode=0444 +file path=opt/SUNWdtrt/tst/common/ip/tst.localtcpstate.ksh.out mode=0444 +file path=opt/SUNWdtrt/tst/common/ip/tst.remotetcpstate.ksh mode=0444 +file path=opt/SUNWdtrt/tst/common/ip/tst.remotetcpstate.ksh.out mode=0444 file path=opt/SUNWdtrt/tst/common/java_api/test.jar file path=opt/SUNWdtrt/tst/common/java_api/tst.Abort.ksh mode=0444 file path=opt/SUNWdtrt/tst/common/java_api/tst.Abort.ksh.out mode=0444 diff --git a/usr/src/uts/common/dtrace/sdt_subr.c b/usr/src/uts/common/dtrace/sdt_subr.c index a89403ea75..242185071b 100644 --- a/usr/src/uts/common/dtrace/sdt_subr.c +++ b/usr/src/uts/common/dtrace/sdt_subr.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <sys/sdt_impl.h> @@ -106,6 +105,8 @@ sdt_provider_t sdt_providers[] = { { "proc", "__proc_", &stab_attr, 0 }, { "io", "__io_", &stab_attr, 0 }, { "ip", "__ip_", &stab_attr, 0 }, + { "tcp", "__tcp_", &stab_attr, 0 }, + { "udp", "__udp_", &stab_attr, 0 }, { "mib", "__mib_", &stab_attr, 0 }, { "fsinfo", "__fsinfo_", &fsinfo_attr, 0 }, { "iscsi", "__iscsi_", &iscsi_attr, 0 }, @@ -888,6 +889,60 @@ sdt_argdesc_t sdt_args[] = { { "ip", "receive", 5, 5, "ip6_t *", "ipv6info_t *" }, { "ip", "receive", 6, 6, "int" }, /* used by __dtrace_ipsr_ill_t */ + { "tcp", "connect-established", 0, 0, "mblk_t *", "pktinfo_t *" }, + { "tcp", "connect-established", 1, 1, "ip_xmit_attr_t *", + "csinfo_t *" }, + { "tcp", "connect-established", 2, 2, "void_ip_t *", "ipinfo_t *" }, + { "tcp", "connect-established", 3, 3, "tcp_t *", "tcpsinfo_t *" }, + { "tcp", "connect-established", 4, 4, "tcph_t *", "tcpinfo_t *" }, + { "tcp", "connect-refused", 0, 0, "mblk_t *", "pktinfo_t *" }, + { "tcp", "connect-refused", 1, 1, "ip_xmit_attr_t *", "csinfo_t *" }, + { "tcp", "connect-refused", 2, 2, "void_ip_t *", "ipinfo_t *" }, + { "tcp", "connect-refused", 3, 3, "tcp_t *", "tcpsinfo_t *" }, + { "tcp", "connect-refused", 4, 4, "tcph_t *", "tcpinfo_t *" }, + { "tcp", "connect-request", 0, 0, "mblk_t *", "pktinfo_t *" }, + { "tcp", "connect-request", 1, 1, "ip_xmit_attr_t *", "csinfo_t *" }, + { "tcp", "connect-request", 2, 2, "void_ip_t *", "ipinfo_t *" }, + { "tcp", "connect-request", 3, 3, "tcp_t *", "tcpsinfo_t *" }, + { "tcp", "connect-request", 4, 4, "tcph_t *", "tcpinfo_t *" }, + { "tcp", "accept-established", 0, 0, "mblk_t *", "pktinfo_t *" }, + { "tcp", "accept-established", 1, 1, "ip_xmit_attr_t *", "csinfo_t *" }, + { "tcp", "accept-established", 2, 2, "void_ip_t *", "ipinfo_t *" }, + { "tcp", "accept-established", 3, 3, "tcp_t *", "tcpsinfo_t *" }, + { "tcp", "accept-established", 4, 4, "tcph_t *", "tcpinfo_t *" }, + { "tcp", "accept-refused", 0, 0, "mblk_t *", "pktinfo_t *" }, + { "tcp", "accept-refused", 1, 1, "ip_xmit_attr_t *", "csinfo_t *" }, + { "tcp", "accept-refused", 2, 2, "void_ip_t *", "ipinfo_t *" }, + { "tcp", "accept-refused", 3, 3, "tcp_t *", "tcpsinfo_t *" }, + { "tcp", "accept-refused", 4, 4, "tcph_t *", "tcpinfo_t *" }, + { "tcp", "state-change", 0, 0, "void", "void" }, + { "tcp", "state-change", 1, 1, "ip_xmit_attr_t *", "csinfo_t *" }, + { "tcp", "state-change", 2, 2, "void", "void" }, + { "tcp", "state-change", 3, 3, "tcp_t *", "tcpsinfo_t *" }, + { "tcp", "state-change", 4, 4, "void", "void" }, + { "tcp", "state-change", 5, 5, "int32_t", "tcplsinfo_t *" }, + { "tcp", "send", 0, 0, "mblk_t *", "pktinfo_t *" }, + { "tcp", "send", 1, 1, "ip_xmit_attr_t *", "csinfo_t *" }, + { "tcp", "send", 2, 2, "__dtrace_tcp_void_ip_t *", "ipinfo_t *" }, + { "tcp", "send", 3, 3, "tcp_t *", "tcpsinfo_t *" }, + { "tcp", "send", 4, 4, "__dtrace_tcp_tcph_t *", "tcpinfo_t *" }, + { "tcp", "receive", 0, 0, "mblk_t *", "pktinfo_t *" }, + { "tcp", "receive", 1, 1, "ip_xmit_attr_t *", "csinfo_t *" }, + { "tcp", "receive", 2, 2, "__dtrace_tcp_void_ip_t *", "ipinfo_t *" }, + { "tcp", "receive", 3, 3, "tcp_t *", "tcpsinfo_t *" }, + { "tcp", "receive", 4, 4, "__dtrace_tcp_tcph_t *", "tcpinfo_t *" }, + + { "udp", "send", 0, 0, "mblk_t *", "pktinfo_t *" }, + { "udp", "send", 1, 1, "ip_xmit_attr_t *", "csinfo_t *" }, + { "udp", "send", 2, 2, "void_ip_t *", "ipinfo_t *" }, + { "udp", "send", 3, 3, "udp_t *", "udpsinfo_t *" }, + { "udp", "send", 4, 4, "udpha_t *", "udpinfo_t *" }, + { "udp", "receive", 0, 0, "mblk_t *", "pktinfo_t *" }, + { "udp", "receive", 1, 1, "ip_xmit_attr_t *", "csinfo_t *" }, + { "udp", "receive", 2, 2, "void_ip_t *", "ipinfo_t *" }, + { "udp", "receive", 3, 3, "udp_t *", "udpsinfo_t *" }, + { "udp", "receive", 4, 4, "udpha_t *", "udpinfo_t *" }, + { "sysevent", "post", 0, 0, "evch_bind_t *", "syseventchaninfo_t *" }, { "sysevent", "post", 1, 1, "sysevent_impl_t *", "syseventinfo_t *" }, diff --git a/usr/src/uts/common/inet/ip.h b/usr/src/uts/common/inet/ip.h index d5eeff5657..3199a40bcb 100644 --- a/usr/src/uts/common/inet/ip.h +++ b/usr/src/uts/common/inet/ip.h @@ -2106,6 +2106,7 @@ struct ip_xmit_attr_s { uint32_t ixa_ident; /* For IPv6 fragment header */ + uint64_t ixa_conn_id; /* Used by DTrace */ /* * Cached LSO information. */ diff --git a/usr/src/uts/common/inet/ip/ip_attr.c b/usr/src/uts/common/inet/ip/ip_attr.c index 6ffd5bbb99..342798b071 100644 --- a/usr/src/uts/common/inet/ip/ip_attr.c +++ b/usr/src/uts/common/inet/ip/ip_attr.c @@ -20,8 +20,7 @@ */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 1990 Mentat Inc. */ @@ -140,6 +139,7 @@ typedef struct ixamblk_s { uint32_t ixm_ident; /* For IPv6 fragment header */ uint32_t ixm_xmit_hint; + uint64_t ixm_conn_id; /* Used by DTrace */ cred_t *ixm_cred; /* For getpeerucred - refhold if set */ pid_t ixm_cpid; /* For getpeerucred */ @@ -265,6 +265,7 @@ ip_xmit_attr_to_mblk(ip_xmit_attr_t *ixa) crhold(ixa->ixa_cred); } ixm->ixm_cpid = ixa->ixa_cpid; + ixm->ixm_conn_id = ixa->ixa_conn_id; if (ixa->ixa_flags & IXAF_IPSEC_SECURE) { if (ixa->ixa_ipsec_ah_sa != NULL) { @@ -404,6 +405,7 @@ ip_xmit_attr_from_mblk(mblk_t *ixamp, ip_xmit_attr_t *ixa) ixm->ixm_cred = NULL; } ixa->ixa_cpid = ixm->ixm_cpid; + ixa->ixa_conn_id = ixm->ixm_conn_id; ixa->ixa_ipsec_ah_sa = ixm->ixm_ipsec_ah_sa; ixa->ixa_ipsec_esp_sa = ixm->ixm_ipsec_esp_sa; @@ -828,6 +830,7 @@ conn_replace_ixa(conn_t *connp, ip_xmit_attr_t *ixa) oldixa = connp->conn_ixa; IXA_REFHOLD(ixa); + ixa->ixa_conn_id = oldixa->ixa_conn_id; connp->conn_ixa = ixa; return (oldixa); } diff --git a/usr/src/uts/common/inet/ip/ipclassifier.c b/usr/src/uts/common/inet/ip/ipclassifier.c index f2ca88e5a1..3d4cbd52ae 100644 --- a/usr/src/uts/common/inet/ip/ipclassifier.c +++ b/usr/src/uts/common/inet/ip/ipclassifier.c @@ -586,6 +586,7 @@ ipcl_conn_create(uint32_t type, int sleep, netstack_t *ns) netstack_hold(ns); connp->conn_netstack = ns; connp->conn_ixa->ixa_ipst = ns->netstack_ip; + connp->conn_ixa->ixa_conn_id = (long)connp; ipcl_globalhash_insert(connp); return (connp); @@ -621,6 +622,7 @@ ipcl_conn_create(uint32_t type, int sleep, netstack_t *ns) netstack_hold(ns); connp->conn_netstack = ns; connp->conn_ixa->ixa_ipst = ns->netstack_ip; + connp->conn_ixa->ixa_conn_id = (long)connp; ipcl_globalhash_insert(connp); return (connp); } diff --git a/usr/src/uts/common/inet/tcp.h b/usr/src/uts/common/inet/tcp.h index befce69047..23dbb1a687 100644 --- a/usr/src/uts/common/inet/tcp.h +++ b/usr/src/uts/common/inet/tcp.h @@ -348,6 +348,7 @@ typedef struct tcp_s { tcpha_t *tcp_tcpha; /* TCP header in conn_ht_iphc */ uint16_t tcp_last_sent_len; /* Record length for nagle */ + uint16_t tcp_last_recv_len; /* Used by DTrace */ uint16_t tcp_dupack_cnt; /* # of consequtive duplicate acks */ kmutex_t *tcp_acceptor_lockp; /* Ptr to tf_lock */ diff --git a/usr/src/uts/common/inet/tcp/tcp.c b/usr/src/uts/common/inet/tcp/tcp.c index f0a86e257c..51ee3be794 100644 --- a/usr/src/uts/common/inet/tcp/tcp.c +++ b/usr/src/uts/common/inet/tcp/tcp.c @@ -872,7 +872,13 @@ tcp_clean_death(tcp_t *tcp, int err) if (!tcp->tcp_tconnind_started) { CONN_DEC_REF(connp); } else { + int32_t oldstate = tcp->tcp_state; + tcp->tcp_state = TCPS_BOUND; + DTRACE_TCP6(state__change, void, NULL, + ip_xmit_attr_t *, connp->conn_ixa, + void, NULL, tcp_t *, tcp, void, NULL, + int32_t, oldstate); } } else { tcp_close_detached(tcp); @@ -1212,6 +1218,7 @@ tcp_closei_local(tcp_t *tcp) { conn_t *connp = tcp->tcp_connp; tcp_stack_t *tcps = tcp->tcp_tcps; + int32_t oldstate; if (!TCP_IS_SOCKET(tcp)) tcp_acceptor_hash_remove(tcp); @@ -1301,6 +1308,12 @@ tcp_closei_local(tcp_t *tcp) (void) tcp_time_wait_remove(tcp, NULL); CL_INET_DISCONNECT(connp); ipcl_hash_remove(connp); + oldstate = tcp->tcp_state; + tcp->tcp_state = TCPS_CLOSED; + /* Need to probe before ixa_cleanup() is called */ + DTRACE_TCP6(state__change, void, NULL, ip_xmit_attr_t *, + connp->conn_ixa, void, NULL, tcp_t *, tcp, void, NULL, + int32_t, oldstate); ixa_cleanup(connp->conn_ixa); /* @@ -1313,7 +1326,6 @@ tcp_closei_local(tcp_t *tcp) ASSERT(tcp->tcp_time_wait_next == NULL); ASSERT(tcp->tcp_time_wait_prev == NULL); ASSERT(tcp->tcp_time_wait_expire == 0); - tcp->tcp_state = TCPS_CLOSED; /* Release any SSL context */ if (tcp->tcp_kssl_ent != NULL) { @@ -1763,9 +1775,15 @@ tcp_disconnect_common(tcp_t *tcp, t_scalar_t seqnum) } if (tcp->tcp_conn_req_max && lconnp == NULL) { tcp->tcp_state = TCPS_LISTEN; + DTRACE_TCP6(state__change, void, NULL, ip_xmit_attr_t *, + connp->conn_ixa, void, NULL, tcp_t *, tcp, void, + NULL, int32_t, old_state); } else if (old_state > TCPS_BOUND) { tcp->tcp_conn_req_max = 0; tcp->tcp_state = TCPS_BOUND; + DTRACE_TCP6(state__change, void, NULL, ip_xmit_attr_t *, + connp->conn_ixa, void, NULL, tcp_t *, tcp, void, + NULL, int32_t, old_state); /* * If this end point is not going to become a listener, @@ -1854,6 +1872,7 @@ tcp_reinit(tcp_t *tcp) mblk_t *mp; tcp_stack_t *tcps = tcp->tcp_tcps; conn_t *connp = tcp->tcp_connp; + int32_t oldstate; /* tcp_reinit should never be called for detached tcp_t's */ ASSERT(tcp->tcp_listener == NULL); @@ -1958,6 +1977,7 @@ tcp_reinit(tcp_t *tcp) connp->conn_laddr_v6 = connp->conn_bound_addr_v6; connp->conn_saddr_v6 = connp->conn_bound_addr_v6; + oldstate = tcp->tcp_state; if (tcp->tcp_conn_req_max != 0) { /* @@ -2003,6 +2023,10 @@ tcp_reinit(tcp_t *tcp) */ tcp_init_values(tcp); + DTRACE_TCP6(state__change, void, NULL, ip_xmit_attr_t *, + connp->conn_ixa, void, NULL, tcp_t *, tcp, void, NULL, + int32_t, oldstate); + ASSERT(tcp->tcp_ptpbhn != NULL); tcp->tcp_rwnd = connp->conn_rcvbuf; tcp->tcp_mss = connp->conn_ipversion != IPV4_VERSION ? @@ -2648,6 +2672,7 @@ tcp_create_common(cred_t *credp, boolean_t isv6, boolean_t issocket, tcps->tcps_wroff_xtra; SOCK_CONNID_INIT(tcp->tcp_connid); + /* DTrace ignores this - it isn't a tcp:::state-change */ tcp->tcp_state = TCPS_IDLE; tcp_init_values(tcp); return (connp); @@ -2993,6 +3018,7 @@ int tcp_do_unbind(conn_t *connp) { tcp_t *tcp = connp->conn_tcp; + int32_t oldstate; switch (tcp->tcp_state) { case TCPS_BOUND: @@ -3018,7 +3044,11 @@ tcp_do_unbind(conn_t *connp) connp->conn_laddr_v6 = ipv6_all_zeros; connp->conn_saddr_v6 = ipv6_all_zeros; tcp_bind_hash_remove(tcp); + oldstate = tcp->tcp_state; tcp->tcp_state = TCPS_IDLE; + DTRACE_TCP6(state__change, void, NULL, ip_xmit_attr_t *, + connp->conn_ixa, void, NULL, tcp_t *, tcp, void, NULL, + int32_t, oldstate); ip_unbind(connp); bzero(&connp->conn_ports, sizeof (connp->conn_ports)); @@ -4574,6 +4604,11 @@ tcp_do_connect(conn_t *connp, const struct sockaddr *sa, socklen_t len, if (tcps->tcps_ecn_permitted == 2) tcp->tcp_ecn_ok = B_TRUE; + /* Trace change from BOUND -> SYN_SENT here */ + DTRACE_TCP6(state__change, void, NULL, ip_xmit_attr_t *, + connp->conn_ixa, void, NULL, tcp_t *, tcp, void, NULL, + int32_t, TCPS_BOUND); + TCP_TIMER_RESTART(tcp, tcp->tcp_rto); syn_mp = tcp_xmit_mp(tcp, NULL, 0, NULL, NULL, tcp->tcp_iss, B_FALSE, NULL, B_FALSE); @@ -4584,6 +4619,15 @@ tcp_do_connect(conn_t *connp, const struct sockaddr *sa, socklen_t len, * this thread issues a "connected" up call. */ SOCK_CONNID_BUMP(tcp->tcp_connid); + /* + * DTrace sending the first SYN as a + * tcp:::connect-request event. + */ + DTRACE_TCP5(connect__request, mblk_t *, NULL, + ip_xmit_attr_t *, connp->conn_ixa, + void_ip_t *, syn_mp->b_rptr, tcp_t *, tcp, + tcph_t *, + &syn_mp->b_rptr[connp->conn_ixa->ixa_ip_hdr_length]); tcp_send_data(tcp, syn_mp); } @@ -4607,6 +4651,7 @@ tcp_do_listen(conn_t *connp, struct sockaddr *sa, socklen_t len, tcp_t *tcp = connp->conn_tcp; int error = 0; tcp_stack_t *tcps = tcp->tcp_tcps; + int32_t oldstate; /* All Solaris components should pass a cred for this operation. */ ASSERT(cr != NULL); @@ -4674,6 +4719,9 @@ do_listen: */ if (tcp->tcp_state != TCPS_LISTEN) { tcp->tcp_state = TCPS_LISTEN; + DTRACE_TCP6(state__change, void, NULL, ip_xmit_attr_t *, + connp->conn_ixa, void, NULL, tcp_t *, tcp, + void, NULL, int32_t, TCPS_BOUND); /* Initialize the chain. Don't need the eager_lock */ tcp->tcp_eager_next_q0 = tcp->tcp_eager_prev_q0 = tcp; tcp->tcp_eager_next_drop_q0 = tcp; @@ -4699,7 +4747,11 @@ do_listen: error = ip_laddr_fanout_insert(connp); if (error != 0) { /* Undo the bind - release the port number */ + oldstate = tcp->tcp_state; tcp->tcp_state = TCPS_IDLE; + DTRACE_TCP6(state__change, void, NULL, ip_xmit_attr_t *, + connp->conn_ixa, void, NULL, tcp_t *, tcp, void, NULL, + int32_t, oldstate); connp->conn_bound_addr_v6 = ipv6_all_zeros; connp->conn_laddr_v6 = ipv6_all_zeros; diff --git a/usr/src/uts/common/inet/tcp/tcp_bind.c b/usr/src/uts/common/inet/tcp/tcp_bind.c index 5d91fe7a7f..058b1960dc 100644 --- a/usr/src/uts/common/inet/tcp/tcp_bind.c +++ b/usr/src/uts/common/inet/tcp/tcp_bind.c @@ -20,8 +20,7 @@ */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. */ #include <sys/types.h> @@ -880,6 +879,11 @@ tcp_bindi(tcp_t *tcp, in_port_t port, const in6_addr_t *laddr, * number. */ tcp->tcp_state = TCPS_BOUND; + DTRACE_TCP6(state__change, void, NULL, + ip_xmit_attr_t *, connp->conn_ixa, + void, NULL, tcp_t *, tcp, void, NULL, + int32_t, TCPS_IDLE); + connp->conn_lport = htons(port); ASSERT(&tcps->tcps_bind_fanout[TCP_BIND_HASH( diff --git a/usr/src/uts/common/inet/tcp/tcp_fusion.c b/usr/src/uts/common/inet/tcp/tcp_fusion.c index aad533de2b..c8f50cee8f 100644 --- a/usr/src/uts/common/inet/tcp/tcp_fusion.c +++ b/usr/src/uts/common/inet/tcp/tcp_fusion.c @@ -642,6 +642,7 @@ tcp_fuse_output(tcp_t *tcp, mblk_t *mp, uint32_t send_size) tcp->tcp_snxt += send_size; tcp->tcp_suna = tcp->tcp_snxt; peer_tcp->tcp_rnxt += recv_size; + peer_tcp->tcp_last_recv_len = recv_size; peer_tcp->tcp_rack = peer_tcp->tcp_rnxt; TCPS_BUMP_MIB(tcps, tcpOutDataSegs); @@ -654,7 +655,12 @@ tcp_fuse_output(tcp_t *tcp, mblk_t *mp, uint32_t send_size) BUMP_LOCAL(tcp->tcp_obsegs); BUMP_LOCAL(peer_tcp->tcp_ibsegs); - DTRACE_PROBE2(tcp__fuse__output, tcp_t *, tcp, uint_t, send_size); + DTRACE_TCP5(send, void, NULL, ip_xmit_attr_t *, connp->conn_ixa, + __dtrace_tcp_void_ip_t *, NULL, tcp_t *, tcp, + __dtrace_tcp_tcph_t *, NULL); + DTRACE_TCP5(receive, void, NULL, ip_xmit_attr_t *, + peer_connp->conn_ixa, __dtrace_tcp_void_ip_t *, NULL, + tcp_t *, peer_tcp, __dtrace_tcp_tcph_t *, NULL); if (!IPCL_IS_NONSTR(peer_tcp->tcp_connp) && !TCP_IS_DETACHED(peer_tcp)) { diff --git a/usr/src/uts/common/inet/tcp/tcp_input.c b/usr/src/uts/common/inet/tcp/tcp_input.c index 48289425ff..14f34a1591 100644 --- a/usr/src/uts/common/inet/tcp/tcp_input.c +++ b/usr/src/uts/common/inet/tcp/tcp_input.c @@ -1322,6 +1322,10 @@ tcp_input_listener(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *ira) tcpha = (tcpha_t *)&mp->b_rptr[ip_hdr_len]; flags = (unsigned int)tcpha->tha_flags & 0xFF; + DTRACE_TCP5(receive, mblk_t *, NULL, ip_xmit_attr_t *, lconnp->conn_ixa, + __dtrace_tcp_void_ip_t *, mp->b_rptr, tcp_t *, listener, + __dtrace_tcp_tcph_t *, tcpha); + if (!(flags & TH_SYN)) { if ((flags & TH_RST) || (flags & TH_URG)) { freemsg(mp); @@ -1653,13 +1657,6 @@ tcp_input_listener(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *ira) goto error3; } - /* - * No need to check for multicast destination since ip will only pass - * up multicasts to those that have expressed interest - * TODO: what about rejecting broadcasts? - * Also check that source is not a multicast or broadcast address. - */ - eager->tcp_state = TCPS_SYN_RCVD; SOCK_CONNID_BUMP(eager->tcp_connid); /* @@ -1770,6 +1767,10 @@ tcp_input_listener(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *ira) eager->tcp_tcpha->tha_ack = htonl(eager->tcp_rnxt); TCPS_BUMP_MIB(tcps, tcpPassiveOpens); eager->tcp_state = TCPS_SYN_RCVD; + DTRACE_TCP6(state__change, void, NULL, ip_xmit_attr_t *, + econnp->conn_ixa, void, NULL, tcp_t *, eager, void, NULL, + int32_t, TCPS_LISTEN); + mp1 = tcp_xmit_mp(eager, eager->tcp_xmit_head, eager->tcp_mss, NULL, NULL, eager->tcp_iss, B_FALSE, NULL, B_FALSE); if (mp1 == NULL) { @@ -1825,6 +1826,10 @@ tcp_input_listener(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *ira) * only used by one thread at a time. */ if (econnp->conn_sqp == lconnp->conn_sqp) { + DTRACE_TCP5(send, mblk_t *, NULL, ip_xmit_attr_t *, + econnp->conn_ixa, __dtrace_tcp_void_ip_t *, mp1->b_rptr, + tcp_t *, eager, __dtrace_tcp_tcph_t *, + &mp1->b_rptr[econnp->conn_ixa->ixa_ip_hdr_length]); (void) conn_ip_output(mp1, econnp->conn_ixa); CONN_DEC_REF(econnp); } else { @@ -2344,6 +2349,10 @@ tcp_input_data(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *ira) mp1->b_datap->db_type == M_DATA); } + DTRACE_TCP5(receive, mblk_t *, NULL, ip_xmit_attr_t *, connp->conn_ixa, + __dtrace_tcp_void_ip_t *, iphdr, tcp_t *, tcp, + __dtrace_tcp_tcph_t *, tcpha); + if (tcp->tcp_state == TCPS_TIME_WAIT) { tcp_time_wait_processing(tcp, mp, seg_seq, seg_ack, seg_len, tcpha, ira); @@ -2443,9 +2452,14 @@ tcp_input_data(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *ira) ASSERT(tcp->tcp_suna + 1 == seg_ack); } if (flags & TH_RST) { - freemsg(mp); - if (flags & TH_ACK) + if (flags & TH_ACK) { + DTRACE_TCP5(connect__refused, mblk_t *, NULL, + ip_xmit_attr_t *, connp->conn_ixa, + void_ip_t *, iphdr, tcp_t *, tcp, + tcph_t *, tcpha); (void) tcp_clean_death(tcp, ECONNREFUSED); + } + freemsg(mp); return; } if (!(flags & TH_SYN)) { @@ -2504,7 +2518,9 @@ tcp_input_data(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *ira) /* * tcp_sendmsg() checks tcp_state without entering * the squeue so tcp_state should be updated before - * sending up connection confirmation + * sending up connection confirmation. Probe the + * state change below when we are sure the connection + * confirmation has been sent. */ tcp->tcp_state = TCPS_ESTABLISHED; if (!tcp_conn_con(tcp, iphdr, mp, @@ -2559,6 +2575,18 @@ tcp_input_data(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *ira) flags |= TH_ACK_NEEDED; /* + * Trace connect-established here. + */ + DTRACE_TCP5(connect__established, mblk_t *, NULL, + ip_xmit_attr_t *, tcp->tcp_connp->conn_ixa, + void_ip_t *, iphdr, tcp_t *, tcp, tcph_t *, tcpha); + + /* Trace change from SYN_SENT -> ESTABLISHED here */ + DTRACE_TCP6(state__change, void, NULL, ip_xmit_attr_t *, + connp->conn_ixa, void, NULL, tcp_t *, tcp, + void, NULL, int32_t, TCPS_SYN_SENT); + + /* * Special case for loopback. At this point we have * received SYN-ACK from the remote endpoint. In * order to ensure that both endpoints reach the @@ -2654,6 +2682,9 @@ tcp_input_data(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *ira) break; } tcp->tcp_state = TCPS_SYN_RCVD; + DTRACE_TCP6(state__change, void, NULL, ip_xmit_attr_t *, + connp->conn_ixa, void_ip_t *, NULL, tcp_t *, tcp, + tcph_t *, NULL, int32_t, TCPS_SYN_SENT); mp1 = tcp_xmit_mp(tcp, tcp->tcp_xmit_head, tcp->tcp_mss, NULL, NULL, tcp->tcp_iss, B_FALSE, NULL, B_FALSE); if (mp1 != NULL) { @@ -3628,7 +3659,9 @@ process_ack: * * tcp_sendmsg() checks tcp_state without entering * the squeue so tcp_state should be updated before - * sending up connection confirmation. + * sending up connection confirmation. Probe the state + * change below when we are sure sending of the confirmation + * has succeeded. */ tcp->tcp_state = TCPS_ESTABLISHED; @@ -3646,6 +3679,21 @@ process_ack: TCP_STAT(tcps, tcp_fusion_unfusable); tcp->tcp_unfusable = B_TRUE; } + /* + * For simultaneous active open, trace receipt of final + * ACK as tcp:::connect-established. + */ + DTRACE_TCP5(connect__established, mblk_t *, NULL, + ip_xmit_attr_t *, connp->conn_ixa, void_ip_t *, + iphdr, tcp_t *, tcp, tcph_t *, tcpha); + } else { + /* + * For passive open, trace receipt of final ACK as + * tcp:::accept-established. + */ + DTRACE_TCP5(accept__established, mlbk_t *, NULL, + ip_xmit_attr_t *, connp->conn_ixa, void_ip_t *, + iphdr, tcp_t *, tcp, tcph_t *, tcpha); } TCPS_CONN_INC(tcps); @@ -3688,6 +3736,11 @@ process_ack: tcp->tcp_swl2 = seg_ack; tcp->tcp_valid_bits &= ~TCP_ISS_VALID; + /* Trace change from SYN_RCVD -> ESTABLISHED here */ + DTRACE_TCP6(state__change, void, NULL, ip_xmit_attr_t *, + connp->conn_ixa, void, NULL, tcp_t *, tcp, void, NULL, + int32_t, TCPS_SYN_RCVD); + /* Fuse when both sides are in ESTABLISHED state */ if (tcp->tcp_loopback && do_tcp_fusion) tcp_fuse(tcp, iphdr, tcpha); @@ -4353,6 +4406,10 @@ est: case TCPS_FIN_WAIT_1: if (tcp->tcp_fin_acked) { tcp->tcp_state = TCPS_FIN_WAIT_2; + DTRACE_TCP6(state__change, void, NULL, + ip_xmit_attr_t *, connp->conn_ixa, + void, NULL, tcp_t *, tcp, void, NULL, + int32_t, TCPS_FIN_WAIT_1); /* * We implement the non-standard BSD/SunOS * FIN_WAIT_2 flushing algorithm. @@ -4383,8 +4440,13 @@ est: } goto xmit_check; case TCPS_CLOSING: - if (tcp->tcp_fin_acked) + if (tcp->tcp_fin_acked) { SET_TIME_WAIT(tcps, tcp, connp); + DTRACE_TCP6(state__change, void, NULL, + ip_xmit_attr_t *, connp->conn_ixa, void, + NULL, tcp_t *, tcp, void, NULL, int32_t, + TCPS_CLOSING); + } /*FALLTHRU*/ case TCPS_CLOSE_WAIT: freemsg(mp); @@ -4414,18 +4476,37 @@ est: flags |= TH_ORDREL_NEEDED; switch (tcp->tcp_state) { case TCPS_SYN_RCVD: + tcp->tcp_state = TCPS_CLOSE_WAIT; + DTRACE_TCP6(state__change, void, NULL, + ip_xmit_attr_t *, connp->conn_ixa, + void, NULL, tcp_t *, tcp, void, NULL, + int32_t, TCPS_SYN_RCVD); + /* Keepalive? */ + break; case TCPS_ESTABLISHED: tcp->tcp_state = TCPS_CLOSE_WAIT; + DTRACE_TCP6(state__change, void, NULL, + ip_xmit_attr_t *, connp->conn_ixa, + void, NULL, tcp_t *, tcp, void, NULL, + int32_t, TCPS_ESTABLISHED); /* Keepalive? */ break; case TCPS_FIN_WAIT_1: if (!tcp->tcp_fin_acked) { tcp->tcp_state = TCPS_CLOSING; + DTRACE_TCP6(state__change, void, NULL, + ip_xmit_attr_t *, connp->conn_ixa, + void, NULL, tcp_t *, tcp, void, + NULL, int32_t, TCPS_FIN_WAIT_1); break; } /* FALLTHRU */ case TCPS_FIN_WAIT_2: SET_TIME_WAIT(tcps, tcp, connp); + DTRACE_TCP6(state__change, void, NULL, + ip_xmit_attr_t *, connp->conn_ixa, void, + NULL, tcp_t *, tcp, void, NULL, int32_t, + TCPS_FIN_WAIT_2); if (seg_len) { /* * implies data piggybacked on FIN. diff --git a/usr/src/uts/common/inet/tcp/tcp_output.c b/usr/src/uts/common/inet/tcp/tcp_output.c index 3cca3e1983..a93c5bce9e 100644 --- a/usr/src/uts/common/inet/tcp/tcp_output.c +++ b/usr/src/uts/common/inet/tcp/tcp_output.c @@ -1693,6 +1693,11 @@ tcp_send_data(tcp_t *tcp, mblk_t *mp) return; } + DTRACE_TCP5(send, mblk_t *, NULL, ip_xmit_attr_t *, connp->conn_ixa, + __dtrace_tcp_void_ip_t *, mp->b_rptr, tcp_t *, tcp, + __dtrace_tcp_tcph_t *, + &mp->b_rptr[connp->conn_ixa->ixa_ip_hdr_length]); + ASSERT(connp->conn_ixa->ixa_notify_cookie == connp->conn_tcp); (void) conn_ip_output(mp, connp->conn_ixa); } @@ -2586,6 +2591,21 @@ tcp_xmit_early_reset(char *str, mblk_t *mp, uint32_t seq, uint32_t ack, int ctl, tcpha->tha_sum = htons(sizeof (tcpha_t)); tcpha->tha_flags = (uint8_t)ctl; if (ctl & TH_RST) { + if (ctl & TH_ACK) { + /* + * Probe connection rejection here. + * tcp_xmit_listeners_reset() drops non-SYN segments + * that do not specify TH_ACK in their flags without + * calling this function. As a consequence, if this + * function is called with a TH_RST|TH_ACK ctl argument, + * it is being called in response to a SYN segment + * and thus the tcp:::accept-refused probe point + * is valid here. + */ + DTRACE_TCP5(accept__refused, mblk_t *, NULL, + void, NULL, void_ip_t *, mp->b_rptr, tcp_t *, NULL, + tcph_t *, tcpha); + } TCPS_BUMP_MIB(tcps, tcpOutRsts); TCPS_BUMP_MIB(tcps, tcpOutControl); } @@ -2616,6 +2636,10 @@ tcp_xmit_early_reset(char *str, mblk_t *mp, uint32_t seq, uint32_t ack, int ctl, ixa->ixa_flags |= IXAF_NO_IPSEC; } + DTRACE_TCP5(send, mblk_t *, NULL, ip_xmit_attr_t *, ixa, + __dtrace_tcp_void_ip_t *, mp->b_rptr, tcp_t *, NULL, + __dtrace_tcp_tcph_t *, tcpha); + /* * NOTE: one might consider tracing a TCP packet here, but * this function has no active TCP state and no tcp structure @@ -2658,6 +2682,14 @@ tcp_xmit_listeners_reset(mblk_t *mp, ip_recv_attr_t *ira, ip_stack_t *ipst, TCP_STAT(tcps, tcp_no_listener); + /* + * DTrace this "unknown" segment as a tcp:::receive, as we did + * just receive something that was TCP. + */ + DTRACE_TCP5(receive, mblk_t *, NULL, ip_xmit_attr_t *, NULL, + __dtrace_tcp_void_ip_t *, mp->b_rptr, tcp_t *, NULL, + __dtrace_tcp_tcph_t *, &mp->b_rptr[ip_hdr_len]); + if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) { policy_present = ipss->ipsec_inbound_v4_policy_present; ipha = (ipha_t *)mp->b_rptr; @@ -3031,11 +3063,25 @@ tcp_xmit_mp(tcp_t *tcp, mblk_t *mp, int32_t max_to_send, int32_t *offset, tcp->tcp_fin_sent = B_TRUE; switch (tcp->tcp_state) { case TCPS_SYN_RCVD: + tcp->tcp_state = TCPS_FIN_WAIT_1; + DTRACE_TCP6(state__change, void, NULL, + ip_xmit_attr_t *, ixa, void, NULL, + tcp_t *, tcp, void, NULL, + int32_t, TCPS_SYN_RCVD); + break; case TCPS_ESTABLISHED: tcp->tcp_state = TCPS_FIN_WAIT_1; + DTRACE_TCP6(state__change, void, NULL, + ip_xmit_attr_t *, ixa, void, NULL, + tcp_t *, tcp, void, NULL, + int32_t, TCPS_ESTABLISHED); break; case TCPS_CLOSE_WAIT: tcp->tcp_state = TCPS_LAST_ACK; + DTRACE_TCP6(state__change, void, NULL, + ip_xmit_attr_t *, ixa, void, NULL, + tcp_t *, tcp, void, NULL, + int32_t, TCPS_CLOSE_WAIT); break; } if (tcp->tcp_suna == tcp->tcp_snxt) diff --git a/usr/src/uts/common/inet/udp/udp.c b/usr/src/uts/common/inet/udp/udp.c index 707499eaf5..3b8b46a911 100644 --- a/usr/src/uts/common/inet/udp/udp.c +++ b/usr/src/uts/common/inet/udp/udp.c @@ -2427,6 +2427,13 @@ udp_input(void *arg1, mblk_t *mp, void *arg2, ip_recv_attr_t *ira) } } + /* + * DTrace this UDP input as udp:::receive (this is for IPv4, IPv6 and + * loopback traffic). + */ + DTRACE_UDP5(receive, mblk_t *, NULL, ip_xmit_attr_t *, connp->conn_ixa, + void_ip_t *, rptr, udp_t *, udp, udpha_t *, udpha); + /* Walk past the headers unless IP_RECVHDR was set. */ if (!udp->udp_rcvhdr) { mp->b_rptr = rptr + hdr_length; @@ -3135,6 +3142,10 @@ udp_output_ancillary(conn_t *connp, sin_t *sin, sin6_t *sin6, mblk_t *mp, /* We're done. Pass the packet to ip. */ BUMP_MIB(&us->us_udp_mib, udpHCOutDatagrams); + DTRACE_UDP5(send, mblk_t *, NULL, ip_xmit_attr_t *, ixa, + void_ip_t *, mp->b_rptr, udp_t *, udp, udpha_t *, + &mp->b_rptr[ixa->ixa_ip_hdr_length]); + error = conn_ip_output(mp, ixa); /* No udpOutErrors if an error since IP increases its error counter */ switch (error) { @@ -3285,6 +3296,10 @@ udp_output_connected(conn_t *connp, mblk_t *mp, cred_t *cr, pid_t pid) /* We're done. Pass the packet to ip. */ BUMP_MIB(&us->us_udp_mib, udpHCOutDatagrams); + DTRACE_UDP5(send, mblk_t *, NULL, ip_xmit_attr_t *, ixa, + void_ip_t *, mp->b_rptr, udp_t *, udp, udpha_t *, + &mp->b_rptr[ixa->ixa_ip_hdr_length]); + error = conn_ip_output(mp, ixa); /* No udpOutErrors if an error since IP increases its error counter */ switch (error) { @@ -3411,6 +3426,10 @@ udp_output_lastdst(conn_t *connp, mblk_t *mp, cred_t *cr, pid_t pid, /* We're done. Pass the packet to ip. */ BUMP_MIB(&us->us_udp_mib, udpHCOutDatagrams); + DTRACE_UDP5(send, mblk_t *, NULL, ip_xmit_attr_t *, ixa, + void_ip_t *, mp->b_rptr, udp_t *, udp, udpha_t *, + &mp->b_rptr[ixa->ixa_ip_hdr_length]); + error = conn_ip_output(mp, ixa); /* No udpOutErrors if an error since IP increases its error counter */ switch (error) { @@ -4212,6 +4231,10 @@ udp_output_newdst(conn_t *connp, mblk_t *data_mp, sin_t *sin, sin6_t *sin6, /* We're done. Pass the packet to ip. */ BUMP_MIB(&us->us_udp_mib, udpHCOutDatagrams); + DTRACE_UDP5(send, mblk_t *, NULL, ip_xmit_attr_t *, ixa, + void_ip_t *, data_mp->b_rptr, udp_t *, udp, udpha_t *, + &data_mp->b_rptr[ixa->ixa_ip_hdr_length]); + error = conn_ip_output(data_mp, ixa); /* No udpOutErrors if an error since IP increases its error counter */ switch (error) { diff --git a/usr/src/uts/common/sys/sdt.h b/usr/src/uts/common/sys/sdt.h index 6ca064c978..6fafae82e3 100644 --- a/usr/src/uts/common/sys/sdt.h +++ b/usr/src/uts/common/sys/sdt.h @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _SYS_SDT_H @@ -281,6 +280,56 @@ extern "C" { type3, arg3, type4, arg4, type5, arg5, type6, arg6, \ type7, arg7); +#define DTRACE_TCP(name) \ + DTRACE_PROBE(__tcp_##name); + +#define DTRACE_TCP1(name, type1, arg1) \ + DTRACE_PROBE1(__tcp_##name, type1, arg1); + +#define DTRACE_TCP2(name, type1, arg1, type2, arg2) \ + DTRACE_PROBE2(__tcp_##name, type1, arg1, type2, arg2); + +#define DTRACE_TCP3(name, type1, arg1, type2, arg2, type3, arg3) \ + DTRACE_PROBE3(__tcp_##name, type1, arg1, type2, arg2, type3, arg3); + +#define DTRACE_TCP4(name, type1, arg1, type2, arg2, \ + type3, arg3, type4, arg4) \ + DTRACE_PROBE4(__tcp_##name, type1, arg1, type2, arg2, \ + type3, arg3, type4, arg4); + +#define DTRACE_TCP5(name, type1, arg1, type2, arg2, \ + type3, arg3, type4, arg4, type5, arg5) \ + DTRACE_PROBE5(__tcp_##name, type1, arg1, type2, arg2, \ + type3, arg3, type4, arg4, type5, arg5); + +#define DTRACE_TCP6(name, type1, arg1, type2, arg2, \ + type3, arg3, type4, arg4, type5, arg5, type6, arg6) \ + DTRACE_PROBE6(__tcp_##name, type1, arg1, type2, arg2, \ + type3, arg3, type4, arg4, type5, arg5, type6, arg6); + +#define DTRACE_UDP(name) \ + DTRACE_PROBE(__udp_##name); + +#define DTRACE_UDP1(name, type1, arg1) \ + DTRACE_PROBE1(__udp_##name, type1, arg1); + +#define DTRACE_UDP2(name, type1, arg1, type2, arg2) \ + DTRACE_PROBE2(__udp_##name, type1, arg1, type2, arg2); + +#define DTRACE_UDP3(name, type1, arg1, type2, arg2, type3, arg3) \ + DTRACE_PROBE3(__udp_##name, type1, arg1, type2, arg2, type3, arg3); + +#define DTRACE_UDP4(name, type1, arg1, type2, arg2, \ + type3, arg3, type4, arg4) \ + DTRACE_PROBE4(__udp_##name, type1, arg1, type2, arg2, \ + type3, arg3, type4, arg4); + +#define DTRACE_UDP5(name, type1, arg1, type2, arg2, \ + type3, arg3, type4, arg4, type5, arg5) \ + DTRACE_PROBE5(__udp_##name, type1, arg1, type2, arg2, \ + type3, arg3, type4, arg4, type5, arg5); + + #define DTRACE_SYSEVENT2(name, type1, arg1, type2, arg2) \ DTRACE_PROBE2(__sysevent_##name, type1, arg1, type2, arg2); |