1#!/usr/sbin/dtrace -s
2/*
3 * tcptop: display top TCP network packets by process.
4 *	Written using DTrace tcp Provider.
5 *
6 * Usage: dtrace -s tcptop.d [count] [interval]
7 *
8 * This analyses TCP network packets and prints the responsible PID plus
9 * standard details such as IP address and port. This captures traffic
10 * of newly created TCP connections that were established while this program
11 * was running along with traffic from existing connections. It can help
12 * identify which processes is causing TCP traffic.
13 *
14 * CDDL HEADER START
15 *
16 * The contents of this file are subject to the terms of the
17 * Common Development and Distribution License (the "License").
18 * You may not use this file except in compliance with the License.
19 *
20 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
21 * or http://www.opensolaris.org/os/licensing.
22 * See the License for the specific language governing permissions
23 * and limitations under the License.
24 *
25 * When distributing Covered Code, include this CDDL HEADER in each
26 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
27 * If applicable, add the following below this CDDL HEADER, with the
28 * fields enclosed by brackets "[]" replaced with your own identifying
29 * information: Portions Copyright [yyyy] [name of copyright owner]
30 *
31 * CDDL HEADER END
32 */
33/*
34 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
35 *
36 * Portions Copyright 2010 Brendan Gregg
37 */
38
39#pragma D option quiet
40#pragma D option defaultargs
41#pragma D option switchrate=10hz
42
43/*
44 * Print header
45 */
46dtrace:::BEGIN
47{
48	/* starting values */
49	counts = $1 ? $1 : 10;
50	secs = $2 ? $2 : 5;
51	TCP_out = 0;
52	TCP_in = 0;
53
54	printf("Sampling... Please wait.\n");
55}
56
57
58tcp:::send
59/ args[1]->cs_pid != -1 /
60{
61	@out[args[1]->cs_zoneid, args[1]->cs_pid, args[2]->ip_saddr,
62	    args[4]->tcp_sport, args[2]->ip_daddr, args[4]->tcp_dport] =
63	    sum(args[2]->ip_plength - args[4]->tcp_offset);
64}
65
66tcp:::receive
67/ args[1]->cs_pid != -1 /
68{
69	@out[args[1]->cs_zoneid, args[1]->cs_pid, args[2]->ip_daddr,
70	    args[4]->tcp_dport, args[2]->ip_saddr, args[4]->tcp_sport] =
71	    sum(args[2]->ip_plength - args[4]->tcp_offset);
72}
73
74/*
75 * TCP Systemwide Stats
76 */
77mib:::tcpOutDataBytes       { TCP_out += args[0]; }
78mib:::tcpRetransBytes       { TCP_out += args[0]; }
79mib:::tcpInDataInorderBytes { TCP_in  += args[0]; }
80mib:::tcpInDataDupBytes     { TCP_in  += args[0]; }
81mib:::tcpInDataUnorderBytes { TCP_in  += args[0]; }
82
83profile:::tick-1sec
84/secs != 0/
85{
86	secs--;
87}
88
89/*
90 * Print Report
91 */
92profile:::tick-1sec
93/secs == 0/
94{
95	/* fetch 1 min load average */
96	this->load1a  = `hp_avenrun[0] / 65536;
97	this->load1b  = ((`hp_avenrun[0] % 65536) * 100) / 65536;
98
99	/* convert TCP counters to Kb */
100	TCP_out /= 1024;
101	TCP_in  /= 1024;
102
103	/* print status */
104	printf("%Y,  load: %d.%02d,  TCPin: %6d Kb,  TCPout: %6d Kb\n\n",
105	    walltimestamp, this->load1a, this->load1b, TCP_in, TCP_out);
106
107	/* print headers */
108	printf("%6s %6s %-15s %5s %-15s %5s %9s\n",
109	    "ZONE", "PID", "LADDR", "LPORT", "RADDR", "RPORT", "SIZE");
110
111	/* print data */
112	printa("%6d %6d %-15s %5d %-15s %5d %@9d\n", @out);
113	printf("\n");
114
115	/* clear data */
116	trunc(@out);
117	TCP_in = 0;
118	TCP_out = 0;
119	secs = 5;
120	counts--;
121}
122
123/*
124 * End of program
125 */
126profile:::tick-1sec
127/counts == 0/
128{
129	exit(0);
130}
131
132/*
133 * Cleanup for Ctrl-C
134 */
135dtrace:::END
136{
137	trunc(@out);
138}
139