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