aboutsummaryrefslogtreecommitdiff
path: root/cddl/lib/libdtrace/tcp.d
blob: afcfdfadaf1e46f937c2fafc8811def63fabfb17 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
/*
 * 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
 *
 * $FreeBSD$
 */
/*
 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
 * Copyright (c) 2013 Mark Johnston <markj@freebsd.org>
 */

#pragma D depends_on library ip.d
#pragma D depends_on module kernel
#pragma D depends_on provider tcp

/*
 * Convert a TCP state value to a string.
 */
#pragma D binding "1.6.3" TCPS_CLOSED
inline int TCPS_CLOSED =	0;
#pragma D binding "1.6.3" TCPS_LISTEN
inline int TCPS_LISTEN =	1;
#pragma D binding "1.6.3" TCPS_SYN_SENT
inline int TCPS_SYN_SENT =	2;
#pragma D binding "1.6.3" TCPS_SYN_RECEIVED
inline int TCPS_SYN_RECEIVED =	3;
#pragma D binding "1.6.3" TCPS_ESTABLISHED
inline int TCPS_ESTABLISHED =	4;
#pragma D binding "1.6.3" TCPS_CLOSE_WAIT
inline int TCPS_CLOSE_WAIT =	5;
#pragma D binding "1.6.3" TCPS_FIN_WAIT_1
inline int TCPS_FIN_WAIT_1 =	6;
#pragma D binding "1.6.3" TCPS_CLOSING
inline int TCPS_CLOSING =	7;
#pragma D binding "1.6.3" TCPS_LAST_ACK
inline int TCPS_LAST_ACK =	8;
#pragma D binding "1.6.3" TCPS_FIN_WAIT_2
inline int TCPS_FIN_WAIT_2 =	9;
#pragma D binding "1.6.3" TCPS_TIME_WAIT
inline int TCPS_TIME_WAIT =	10;

/*
 * For compatibility also provide the names used by Solaris.
 */
#pragma D binding "1.13" TCP_STATE_CLOSED
inline int TCP_STATE_CLOSED =		TCPS_CLOSED;
#pragma D binding "1.13" TCP_STATE_LISTEN
inline int TCP_STATE_LISTEN =		TCPS_LISTEN;
#pragma D binding "1.13" TCP_STATE_SYN_SENT
inline int TCP_STATE_SYN_SENT =		TCPS_SYN_SENT;
#pragma D binding "1.13" TCP_STATE_SYN_RECEIVED
inline int TCP_STATE_SYN_RECEIVED =	TCPS_SYN_RECEIVED;
#pragma D binding "1.13" TCP_STATE_ESTABLISHED
inline int TCP_STATE_ESTABLISHED =	TCPS_ESTABLISHED;
#pragma D binding "1.13" TCP_STATE_CLOSE_WAIT
inline int TCP_STATE_CLOSE_WAIT =	TCPS_CLOSE_WAIT;
#pragma D binding "1.13" TCP_STATE_FIN_WAIT_1
inline int TCP_STATE_FIN_WAIT_1 =	TCPS_FIN_WAIT_1;
#pragma D binding "1.13" TCP_STATE_CLOSING
inline int TCP_STATE_CLOSING =		TCPS_CLOSING;
#pragma D binding "1.13" TCP_STATE_LAST_ACK
inline int TCP_STATE_LAST_ACK =		TCPS_LAST_ACK;
#pragma D binding "1.13" TCP_STATE_FIN_WAIT_2
inline int TCP_STATE_FIN_WAIT_2 =	TCPS_FIN_WAIT_2;
#pragma D binding "1.13" TCP_STATE_TIME_WAIT
inline int TCP_STATE_TIME_WAIT =	TCPS_TIME_WAIT;

/* TCP segment flags. */
#pragma D binding "1.6.3" TH_FIN
inline uint8_t TH_FIN =		0x01;
#pragma D binding "1.6.3" TH_SYN
inline uint8_t TH_SYN =		0x02;
#pragma D binding "1.6.3" TH_RST
inline uint8_t TH_RST =		0x04;
#pragma D binding "1.6.3" TH_PUSH
inline uint8_t TH_PUSH =	0x08;
#pragma D binding "1.6.3" TH_ACK
inline uint8_t TH_ACK =		0x10;
#pragma D binding "1.6.3" TH_URG
inline uint8_t TH_URG =		0x20;
#pragma D binding "1.6.3" TH_ECE
inline uint8_t TH_ECE =		0x40;
#pragma D binding "1.6.3" TH_CWR
inline uint8_t TH_CWR =		0x80;

/* TCP connection state strings. */
#pragma D binding "1.6.3" tcp_state_string
inline string tcp_state_string[int32_t state] =
	state == TCPS_CLOSED ?		"state-closed" :
	state == TCPS_LISTEN ?		"state-listen" :
	state == TCPS_SYN_SENT ?	"state-syn-sent" :
	state == TCPS_SYN_RECEIVED ?	"state-syn-received" :
	state == TCPS_ESTABLISHED ?	"state-established" :
	state == TCPS_CLOSE_WAIT ?	"state-close-wait" :
	state == TCPS_FIN_WAIT_1 ?	"state-fin-wait-1" :
	state == TCPS_CLOSING ?		"state-closing" :
	state == TCPS_LAST_ACK ?	"state-last-ack" :
	state == TCPS_FIN_WAIT_2 ?	"state-fin-wait-2" :
	state == TCPS_TIME_WAIT ?	"state-time-wait" :
	"<unknown>";

/*
 * 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_irs;		/* Initial sequence # received */
	uint32_t tcps_suna;		/* sequence # sent but unacked */
	uint32_t tcps_smax;		/* highest sequence number sent */
	uint32_t tcps_snxt;		/* next sequence # to send */
	uint32_t tcps_rack;		/* sequence # we have acked */
	uint32_t tcps_rnxt;		/* next sequence # expected */
	u_long tcps_swnd;		/* send window size */
	int32_t tcps_snd_ws;		/* send window scaling */
	uint32_t tcps_swl1;		/* window update seg seq number */
	uint32_t tcps_swl2;		/* window update seg ack number */
	uint32_t tcps_rup;		/* receive urgent pointer */
	uint32_t tcps_radv;		/* advertised window */
	u_long tcps_rwnd;		/* receive window size */
	int32_t tcps_rcv_ws;		/* receive window scaling */
	u_long tcps_cwnd;		/* congestion window */
	u_long tcps_cwnd_ssthresh;	/* threshold for congestion avoidance */
	uint32_t tcps_srecover;		/* for use in NewReno Fast Recovery */
	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 */
	int tcps_srtt;			/* smoothed RTT in units of (TCP_RTT_SCALE*hz) */
	int tcps_debug;			/* socket has SO_DEBUG set */
	int tcps_cookie;		/* expose the socket's SO_USER_COOKIE */
	int32_t tcps_dupacks;		/* consecutive dup acks received */
	uint32_t tcps_rtttime;		/* RTT measurement start time */
	uint32_t tcps_rtseq;		/* sequence # being timed */
	uint32_t tcps_ts_recent;	/* timestamp echo data */
} tcpsinfo_t;

/*
 * tcplsinfo provides the old tcp state for state changes.
 */
typedef struct tcplsinfo {
	int32_t tcps_state;		/* previous TCP state */
} tcplsinfo_t;

/*
 * 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 */
	struct tcphdr *tcp_hdr;		/* raw TCP header */
} tcpinfo_t;

/*
 * A clone of tcpinfo_t used to handle the fact that the TCP input path
 * overwrites some fields of the TCP header with their host-order equivalents.
 * Unfortunately, DTrace doesn't let us simply typedef a new name for struct
 * tcpinfo and define a separate translator for it.
 */
typedef struct tcpinfoh {
	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 */
	struct tcphdr *tcp_hdr;		/* raw TCP header */
} tcpinfoh_t;

#pragma D binding "1.6.3" translator
translator csinfo_t < struct tcpcb *p > {
	cs_addr =	NULL;
	cs_cid =	(uint64_t)(p == NULL ? 0 : p->t_inpcb);
	cs_pid =	0;
	cs_zoneid =	0;
};

#pragma D binding "1.6.3" translator
translator tcpsinfo_t < struct tcpcb *p > {
	tcps_addr =		(uintptr_t)p;
	tcps_local =		-1; /* XXX */
	tcps_active =		-1; /* XXX */
	tcps_lport =		p == NULL ? 0 : ntohs(p->t_inpcb->inp_inc.inc_ie.ie_lport);
	tcps_rport =		p == NULL ? 0 : ntohs(p->t_inpcb->inp_inc.inc_ie.ie_fport);
	tcps_laddr =		p == NULL ? "<unknown>" :
	    p->t_inpcb->inp_vflag == INP_IPV4 ?
	    inet_ntoa(&p->t_inpcb->inp_inc.inc_ie.ie_dependladdr.id46_addr.ia46_addr4.s_addr) :
	    inet_ntoa6(&p->t_inpcb->inp_inc.inc_ie.ie_dependladdr.id6_addr);
	tcps_raddr =		p == NULL ? "<unknown>" :
	    p->t_inpcb->inp_vflag == INP_IPV4 ?
	    inet_ntoa(&p->t_inpcb->inp_inc.inc_ie.ie_dependfaddr.id46_addr.ia46_addr4.s_addr) :
	    inet_ntoa6(&p->t_inpcb->inp_inc.inc_ie.ie_dependfaddr.id6_addr);
	tcps_state =		p == NULL ? -1 : p->t_state;
	tcps_iss =		p == NULL ? 0  : p->iss;
	tcps_irs =		p == NULL ? 0  : p->irs;
	tcps_suna =		p == NULL ? 0  : p->snd_una;
	tcps_smax =		p == NULL ? 0  : p->snd_max;
	tcps_snxt =		p == NULL ? 0  : p->snd_nxt;
	tcps_rack =		p == NULL ? 0  : p->last_ack_sent;
	tcps_rnxt =		p == NULL ? 0  : p->rcv_nxt;
	tcps_swnd =		p == NULL ? -1 : p->snd_wnd;
	tcps_snd_ws =		p == NULL ? -1 : p->snd_scale;
	tcps_swl1 =		p == NULL ? -1 : p->snd_wl1;
	tcps_swl2 = 		p == NULL ? -1 : p->snd_wl2;
	tcps_radv =		p == NULL ? -1 : p->rcv_adv;
	tcps_rwnd =		p == NULL ? -1 : p->rcv_wnd;
	tcps_rup =		p == NULL ? -1 : p->rcv_up;
	tcps_rcv_ws =		p == NULL ? -1 : p->rcv_scale;
	tcps_cwnd =		p == NULL ? -1 : p->snd_cwnd;
	tcps_cwnd_ssthresh =	p == NULL ? -1 : p->snd_ssthresh;
	tcps_srecover =		p == NULL ? -1 : p->snd_recover;
	tcps_sack_fack =	p == NULL ? 0  : p->snd_fack;
	tcps_sack_snxt =	p == NULL ? 0  : p->snd_recover;
	tcps_rto =		p == NULL ? -1 : (p->t_rxtcur * 1000) / `hz;
	tcps_mss =		p == NULL ? -1 : p->t_maxseg;
	tcps_retransmit =	p == NULL ? -1 : p->t_rxtshift > 0 ? 1 : 0;
	tcps_srtt =		p == NULL ? -1 : p->t_srtt;   /* smoothed RTT in units of (TCP_RTT_SCALE*hz) */
	tcps_debug =		p == NULL ? 0 :
	    p->t_inpcb->inp_socket->so_options & 1;
	tcps_cookie =		p == NULL ? -1 :
	    p->t_inpcb->inp_socket->so_user_cookie;
	tcps_dupacks =		p == NULL ? -1 : p->t_dupacks;
	tcps_rtttime =		p == NULL ? -1 : p->t_rtttime;
	tcps_rtseq =		p == NULL ? -1 : p->t_rtseq;
	tcps_ts_recent =	p == NULL ? -1 : p->ts_recent;
};

#pragma D binding "1.6.3" translator
translator tcpinfo_t < struct tcphdr *p > {
	tcp_sport =	p == NULL ? 0  : ntohs(p->th_sport);
	tcp_dport =	p == NULL ? 0  : ntohs(p->th_dport);
	tcp_seq =	p == NULL ? -1 : ntohl(p->th_seq);
	tcp_ack =	p == NULL ? -1 : ntohl(p->th_ack);
	tcp_offset =	p == NULL ? -1 : (p->th_off >> 2);
	tcp_flags =	p == NULL ? 0  : p->th_flags;
	tcp_window =	p == NULL ? 0  : ntohs(p->th_win);
	tcp_checksum =	p == NULL ? 0  : ntohs(p->th_sum);
	tcp_urgent =	p == NULL ? 0  : ntohs(p->th_urp);
	tcp_hdr =	(struct tcphdr *)p;
};

/*
 * This translator differs from the one for tcpinfo_t in that the sequence
 * number, acknowledgement number, window size and urgent pointer are already
 * in host order and thus don't need to be converted.
 */
#pragma D binding "1.6.3" translator
translator tcpinfoh_t < struct tcphdr *p > {
	tcp_sport =	p == NULL ? 0  : ntohs(p->th_sport);
	tcp_dport =	p == NULL ? 0  : ntohs(p->th_dport);
	tcp_seq =	p == NULL ? -1 : p->th_seq;
	tcp_ack =	p == NULL ? -1 : p->th_ack;
	tcp_offset =	p == NULL ? -1 : (p->th_off >> 2);
	tcp_flags =	p == NULL ? 0  : p->th_flags;
	tcp_window =	p == NULL ? 0  : p->th_win;
	tcp_checksum =	p == NULL ? 0  : ntohs(p->th_sum);
	tcp_urgent =	p == NULL ? 0  : p->th_urp;
	tcp_hdr =	(struct tcphdr *)p;
};

#pragma D binding "1.6.3" translator
translator tcplsinfo_t < int s > {
	tcps_state =	s;
};


/* Support for TCP debug */

#pragma D binding "1.12.1" TA_INPUT
inline int TA_INPUT =	0;
#pragma D binding "1.12.1" TA_OUTPUT
inline int TA_OUTPUT =	1;
#pragma D binding "1.12.1" TA_USER
inline int TA_USER =	2;
#pragma D binding "1.12.1" TA_RESPOND
inline int TA_RESPOND =	3;
#pragma D binding "1.12.1" TA_DROP
inline int TA_DROP =	4;

/* direction strings. */

#pragma D binding "1.12.1" tcpdebug_dir_string
inline string tcpdebug_dir_string[uint8_t direction] =
	direction == TA_INPUT ?	"input" :
	direction == TA_OUTPUT ? "output" :
	direction == TA_USER ? "user" :
	direction == TA_RESPOND ? "respond" :
	direction == TA_OUTPUT ? "drop" :
	"unknown" ;

#pragma D binding "1.12.1" tcpflag_string
inline string tcpflag_string[uint8_t flags] =
	flags & TH_FIN ?	"FIN" :
	flags & TH_SYN ?	"SYN" :
	flags & TH_RST ?	"RST" :
	flags & TH_PUSH ?	"PUSH" :
	flags & TH_ACK ?	"ACK" :
	flags & TH_URG ?	"URG" :
	flags & TH_ECE ?	"ECE" :
	flags & TH_CWR ?	"CWR" :
	"unknown" ;

#pragma D binding "1.12.1" PRU_ATTACH
inline int PRU_ATTACH		= 0;
#pragma D binding "1.12.1" PRU_DETACH
inline int PRU_DETACH		= 1;
#pragma D binding "1.12.1" PRU_BIND
inline int PRU_BIND		= 2;
#pragma D binding "1.12.1" PRU_LISTEN
inline int PRU_LISTEN		= 3;
#pragma D binding "1.12.1" PRU_CONNECT
inline int PRU_CONNECT		= 4;
#pragma D binding "1.12.1" PRU_ACCEPT
inline int PRU_ACCEPT		= 5 ;
#pragma D binding "1.12.1" PRU_DISCONNECT
inline int PRU_DISCONNECT	= 6;
#pragma D binding "1.12.1" PRU_SHUTDOWN
inline int PRU_SHUTDOWN		= 7;
#pragma D binding "1.12.1" PRU_RCVD
inline int PRU_RCVD		= 8;
#pragma D binding "1.12.1" PRU_SEND
inline int PRU_SEND		= 9;
#pragma D binding "1.12.1" PRU_ABORT
inline int PRU_ABORT		= 10;
#pragma D binding "1.12.1" PRU_CONTROL
inline int PRU_CONTROL		= 11;
#pragma D binding "1.12.1" PRU_SENSE
inline int PRU_SENSE		= 12;
#pragma D binding "1.12.1" PRU_RCVOOB
inline int PRU_RCVOOB		= 13;
#pragma D binding "1.12.1" PRU_SENDOOB
inline int PRU_SENDOOB		= 14;
#pragma D binding "1.12.1" PRU_SOCKADDR
inline int PRU_SOCKADDR		= 15;
#pragma D binding "1.12.1" PRU_PEERADDR
inline int PRU_PEERADDR		= 16;
#pragma D binding "1.12.1" PRU_CONNECT2
inline int PRU_CONNECT2		= 17;
#pragma D binding "1.12.1" PRU_FASTTIMO
inline int PRU_FASTTIMO		= 18;
#pragma D binding "1.12.1" PRU_SLOWTIMO
inline int PRU_SLOWTIMO		= 19;
#pragma D binding "1.12.1" PRU_PROTORCV
inline int PRU_PROTORCV		= 20;
#pragma D binding "1.12.1" PRU_PROTOSEND
inline int PRU_PROTOSEND	= 21;
#pragma D binding "1.12.1" PRU_SEND_EOF
inline int PRU_SEND_EOF		= 22;
#pragma D binding "1.12.1" PRU_SOSETLABEL
inline int PRU_SOSETLABEL	= 23;
#pragma D binding "1.12.1" PRU_CLOSE
inline int PRU_CLOSE		= 24;
#pragma D binding "1.12.1" PRU_FLUSH
inline int PRU_FLUSH		= 25;

#pragma D binding "1.12.1" prureq_string
inline string prureq_string[uint8_t req] =
	req == PRU_ATTACH ?	"ATTACH" :
	req == PRU_DETACH ?	"DETACH" :
	req == PRU_BIND ?	"BIND" :
	req == PRU_LISTEN ?	"LISTEN" :
	req == PRU_CONNECT ?	"CONNECT" :
	req == PRU_ACCEPT ?	"ACCEPT" :
	req == PRU_DISCONNECT ?	"DISCONNECT" :
	req == PRU_SHUTDOWN ?	"SHUTDOWN" :
	req == PRU_RCVD ?	"RCVD" :
	req == PRU_SEND ?	"SEND" :
	req == PRU_ABORT ?	"ABORT" :
	req == PRU_CONTROL ?	"CONTROL" :
	req == PRU_SENSE ?	"SENSE" :
	req == PRU_RCVOOB ?	"RCVOOB" :
	req == PRU_SENDOOB ?	"SENDOOB" :
	req == PRU_SOCKADDR ?	"SOCKADDR" :
	req == PRU_PEERADDR ?	"PEERADDR" :
	req == PRU_CONNECT2 ?	"CONNECT2" :
	req == PRU_FASTTIMO ?	"FASTTIMO" :
	req == PRU_SLOWTIMO ?	"SLOWTIMO" :
	req == PRU_PROTORCV ?	"PROTORCV" :
	req == PRU_PROTOSEND ?	"PROTOSEND" :
	req == PRU_SEND ?	"SEND_EOF" :
	req == PRU_SOSETLABEL ?	"SOSETLABEL" :
	req == PRU_CLOSE ?	"CLOSE" :
	req == PRU_FLUSH ?	"FLUSE" :
	"unknown" ;