1 #!/usr/sbin/dtrace -Cqs
2 /*
3  * CDDL HEADER START
4  *
5  * The contents of this file are subject to the terms of the
6  * Common Development and Distribution License (the "License").
7  * You may not use this file except in compliance with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  * This D script is used as an example in the Solaris Dynamic Tracing Guide
27  * wiki in the "ip Provider" Chapter.
28  *
29  * The full text of the this chapter may be found here:
30  *
31  *   http://wikis.sun.com/display/DTrace/ip+Provider
32  *
33  * On machines that have DTrace installed, this script is available as
34  * tcprst.d in /usr/demo/dtrace, a directory that contains all D scripts
35  * used in the Solaris Dynamic Tracing Guide.  A table of the scripts and their
36  * corresponding chapters may be found here:
37  *
38  *   file:///usr/demo/dtrace/index.html
39  */
40 
41 #pragma D option dynvarsize=64m
42 
43 #define TH_RST		0x04
44 #define MAX_RECORDS	10
45 #define M_CTL		0x0d
46 
47 #define PRINT_MAIN_HEADER()						\
48 	(printf("\n%-25s %-6s %-25s %-6s %-10s %-10s %8s %8s\n",	\
49 	    "LADDR", "LPORT", "RADDR", "RPORT", "ISS", "IRS",		\
50 	    "SND_CNT", "RCV_CNT"))
51 
52 #define PRINT_RECORD_HEADER()						\
53 	(printf("%-20s %-20s %-3s %15s %15s %8s %8s %5s\n",		\
54 	    "PROBENAME", "TIME", "S/R", "SEQ", "ACK", "DATALEN",	\
55 	    "WND", "FLAGS"))
56 
57 #define PRINT_MAIN_HEADER_VALUES()					\
58 	(printf("%-25s %-6d %-25s %-6d %-10d %-10d %8d %8d\n",		\
59 	    laddr[self->conn_id], lport[self->conn_id],			\
60 	    faddr[self->conn_id], fport[self->conn_id],			\
61 	    iss[self->conn_id], irs[self->conn_id],			\
62 	    send_count[self->conn_id], recv_count[self->conn_id]))
63 
64 #define PRINT_HEADER()							\
65 	PRINT_MAIN_HEADER(); PRINT_MAIN_HEADER_VALUES();		\
66 	    PRINT_RECORD_HEADER()
67 
68 #define PRINT_RECORD(i)							\
69 	(printf("%-20s %-20Y %-3s %15d %15d %8d %8d %2x\n",		\
70 	    probe_name[self->conn_id, i],				\
71 	    conn_time[self->conn_id, i],				\
72 	    send_recv[self->conn_id, i],				\
73 	    seqno[self->conn_id, i],					\
74 	    ack[self->conn_id, i],					\
75 	    datalen[self->conn_id, i],					\
76 	    wnd[self->conn_id, i],					\
77 	    flags[self->conn_id, i]))
78 
79 tcp-trace-*
80 {
81 	/* extract connection details */
82 
83 	this->mp = (mblk_t *)arg0;
84 	this->mp = (this->mp->b_datap->db_type == M_CTL?
85 	    this->mp->b_cont : this->mp);
86 	self->tcpp = (tcp_t *)arg1;
87 	this->connp = (conn_t *)self->tcpp->tcp_connp;
88 
89 	self->iph = (ipha_t *)this->mp->b_rptr;
90 	this->iph_length =
91 	    (int)(((ipha_t *)self->iph)->ipha_version_and_hdr_length
92 	    & 0xF) << 2;
93 	self->tcph = (tcpha_t *)((char *)self->iph + this->iph_length);
94 	this->tcph_length =
95 	    (((tcph_t *)self->tcph)->th_offset_and_rsrvd[0] >>2) &(0xF << 2);
96 
97 	/* ports */
98 	self->i_lport = ntohs(this->connp->u_port.tcpu_ports.tcpu_lport);
99 	self->i_fport = ntohs(this->connp->u_port.tcpu_ports.tcpu_fport);
100 
101 	/* IP addresses */
102 	this->i_fad = (in6_addr_t *)&this->connp->connua_v6addr.connua_faddr;
103 	this->i_lad = (in6_addr_t *)&this->connp->connua_v6addr.connua_laddr;
104 
105 	/* the address would either be IPv6 or IPv4-mapped-IPv6  */
106 	self->i_faddr = inet_ntop(AF_INET6, (void *)this->i_fad);
107 	self->i_laddr = inet_ntop(AF_INET6, (void *)this->i_lad);
108 
109 	/* create connection identifier, so we can track packets by conn */
110 	self->conn_id = (uint64_t)self->tcpp->tcp_connp;
111 }
112 
113 tcp-trace-*
114 /first[self->conn_id] == 0/
115 {
116 	/* initialize counters - this is the first packet for this connection */
117 	pcount[self->conn_id] = -1;
118 	rollover[self->conn_id] = 0;
119 	end_ptr[self->conn_id] = 0;
120 	num[self->conn_id] = 0;
121 
122 	first[self->conn_id] = 1;
123 
124 	/* connection info */
125 	laddr[self->conn_id] = self->i_laddr;
126 	faddr[self->conn_id] = self->i_faddr;
127 	lport[self->conn_id] = self->i_lport;
128 	fport[self->conn_id] = self->i_fport;
129 	iss[self->conn_id] = self->tcpp->tcp_iss;
130 	irs[self->conn_id] = self->tcpp->tcp_irs;
131 
132 }
133 
134 tcp-trace-*
135 {
136 	/* counters, to keep track of how much info to dump */
137 	pcount[self->conn_id]++;
138 	rollover[self->conn_id] |= pcount[self->conn_id]/MAX_RECORDS;
139 	pcount[self->conn_id] = pcount[self->conn_id]%MAX_RECORDS;
140 	self->pcount = pcount[self->conn_id];
141 	end_ptr[self->conn_id] = self->pcount;
142 	num[self->conn_id] = (rollover[self->conn_id]?
143 	    MAX_RECORDS : pcount[self->conn_id] + 1);
144 	conn_time[self->conn_id, self->pcount] = walltimestamp;
145 
146 	/* tcp state info */
147 	seqno[self->conn_id, self->pcount] = ntohl(self->tcph->tha_seq);
148 	ack[self->conn_id, self->pcount] = ntohl(self->tcph->tha_ack);
149 	datalen[self->conn_id, self->pcount] =  ntohs(self->iph->ipha_length);
150 	wnd[self->conn_id, self->pcount] =  ntohs(self->tcph->tha_win);
151 	probe_name[self->conn_id, self->pcount] = probename;
152 
153 	/* flag 0x04 indicates a RST packet */
154 	flags[self->conn_id, self->pcount] = self->tcph->tha_flags;
155 	self->flags = self->tcph->tha_flags;
156 }
157 
158 tcp-trace-send
159 {
160 	send_count[self->conn_id]++;
161 	send_recv[self->conn_id, self->pcount] = "S";
162 }
163 
164 tcp-trace-recv
165 {
166 	recv_count[self->conn_id]++;
167 	send_recv[self->conn_id, self->pcount] = "R";
168 }
169 
170 tcp-trace-*
171 /(self->flags & TH_RST)/
172 {
173 	PRINT_HEADER();
174 
175 	self->i = (end_ptr[self->conn_id] + MAX_RECORDS - num[self->conn_id]
176 	    + 1)%MAX_RECORDS;
177 }
178 
179 tcp-trace-*
180 /(self->flags & TH_RST) && (num[self->conn_id] >= 10)/
181 {
182 	PRINT_RECORD(self->i);
183 	self->i = (self->i + 1)%MAX_RECORDS;
184 
185 	num[self->conn_id]--;
186 }
187 
188 tcp-trace-*
189 /(self->flags & TH_RST) && (num[self->conn_id] >= 9)/
190 {
191 	PRINT_RECORD(self->i);
192 	self->i = (self->i + 1)%MAX_RECORDS;
193 
194 	num[self->conn_id]--;
195 }
196 
197 tcp-trace-*
198 /(self->flags & TH_RST) && (num[self->conn_id] >= 8)/
199 {
200 	PRINT_RECORD(self->i);
201 	self->i = (self->i + 1)%MAX_RECORDS;
202 
203 	num[self->conn_id]--;
204 }
205 
206 tcp-trace-*
207 /(self->flags & TH_RST) && (num[self->conn_id] >= 7)/
208 {
209 	PRINT_RECORD(self->i);
210 	self->i = (self->i + 1)%MAX_RECORDS;
211 
212 	num[self->conn_id]--;
213 }
214 
215 tcp-trace-*
216 /(self->flags & TH_RST) && (num[self->conn_id] >= 6)/
217 {
218 	PRINT_RECORD(self->i);
219 	self->i = (self->i + 1)%MAX_RECORDS;
220 
221 	num[self->conn_id]--;
222 }
223 
224 tcp-trace-*
225 /(self->flags & TH_RST) && (num[self->conn_id] >= 5)/
226 {
227 	PRINT_RECORD(self->i);
228 	self->i = (self->i + 1)%MAX_RECORDS;
229 
230 	num[self->conn_id]--;
231 }
232 
233 tcp-trace-*
234 /(self->flags & TH_RST) && (num[self->conn_id] >= 4)/
235 {
236 	PRINT_RECORD(self->i);
237 	self->i = (self->i + 1)%MAX_RECORDS;
238 
239 	num[self->conn_id]--;
240 }
241 
242 tcp-trace-*
243 /(self->flags & TH_RST) && (num[self->conn_id] >= 3)/
244 {
245 	PRINT_RECORD(self->i);
246 	self->i = (self->i + 1)%MAX_RECORDS;
247 
248 	num[self->conn_id]--;
249 }
250 
251 tcp-trace-*
252 /(self->flags & TH_RST) && (num[self->conn_id] >= 2)/
253 {
254 	PRINT_RECORD(self->i);
255 	self->i = (self->i + 1)%MAX_RECORDS;
256 
257 	num[self->conn_id]--;
258 }
259 
260 tcp-trace-*
261 /(self->flags & TH_RST) && (num[self->conn_id] >= 1)/
262 {
263 	PRINT_RECORD(self->i);
264 	self->i = (self->i + 1)%MAX_RECORDS;
265 
266 	num[self->conn_id]--;
267 	self->reset = self->conn_id;
268 }
269 
270 tcp-trace-*
271 /self->reset/
272 {
273 	pcount[self->reset] = -1;
274 	rollover[self->reset] = 0;
275 	end_ptr[self->reset] = 0;
276 	num[self->reset] = 0;
277 
278 	self->reset = 0;
279 }
280 
281 conn-destroy
282 {
283 	/* clear old connection state */
284 	this->conn_id = (uint64_t)arg0;
285 
286 	pcount[this->conn_id] = -1;
287 	rollover[this->conn_id] = 0;
288 	end_ptr[this->conn_id] = 0;
289 	num[this->conn_id] = 0;
290 	first[this->conn_id] = 0;
291 
292 	laddr[this->conn_id] = 0;
293 	faddr[this->conn_id] = 0;
294 	lport[this->conn_id] = 0;
295 	fport[this->conn_id] = 0;
296 	iss[this->conn_id] = 0;
297 	irs[this->conn_id] = 0;
298 }
299