2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#pragma D depends_on module unix
2N/A#pragma D depends_on provider tcp
2N/A
2N/Ainline int TH_FIN = @TH_FIN@;
2N/A#pragma D binding "1.6.3" TH_FIN
2N/Ainline int TH_SYN = @TH_SYN@;
2N/A#pragma D binding "1.6.3" TH_SYN
2N/Ainline int TH_RST = @TH_RST@;
2N/A#pragma D binding "1.6.3" TH_RST
2N/Ainline int TH_PUSH = @TH_PUSH@;
2N/A#pragma D binding "1.6.3" TH_PUSH
2N/Ainline int TH_ACK = @TH_ACK@;
2N/A#pragma D binding "1.6.3" TH_ACK
2N/Ainline int TH_URG = @TH_URG@;
2N/A#pragma D binding "1.6.3" TH_URG
2N/Ainline int TH_ECE = @TH_ECE@;
2N/A#pragma D binding "1.6.3" TH_ECE
2N/Ainline int TH_CWR = @TH_CWR@;
2N/A#pragma D binding "1.6.3" TH_CWR
2N/A
2N/Ainline int32_t TCP_STATE_CLOSED = @TCPS_CLOSED@;
2N/A#pragma D binding "1.6.3" TCP_STATE_CLOSED
2N/Ainline int32_t TCP_STATE_IDLE = @TCPS_IDLE@;
2N/A#pragma D binding "1.6.3" TCP_STATE_IDLE
2N/Ainline int32_t TCP_STATE_BOUND = @TCPS_BOUND@;
2N/A#pragma D binding "1.6.3" TCP_STATE_BOUND
2N/Ainline int32_t TCP_STATE_LISTEN = @TCPS_LISTEN@;
2N/A#pragma D binding "1.6.3" TCP_STATE_LISTEN
2N/Ainline int32_t TCP_STATE_SYN_SENT = @TCPS_SYN_SENT@;
2N/A#pragma D binding "1.6.3" TCP_STATE_SYN_SENT
2N/Ainline int32_t TCP_STATE_SYN_RECEIVED = @TCPS_SYN_RCVD@;
2N/A#pragma D binding "1.6.3" TCP_STATE_SYN_RECEIVED
2N/Ainline int32_t TCP_STATE_ESTABLISHED = @TCPS_ESTABLISHED@;
2N/A#pragma D binding "1.6.3" TCP_STATE_ESTABLISHED
2N/Ainline int32_t TCP_STATE_CLOSE_WAIT = @TCPS_CLOSE_WAIT@;
2N/A#pragma D binding "1.6.3" TCP_STATE_CLOSE_WAIT
2N/Ainline int32_t TCP_STATE_FIN_WAIT_1 = @TCPS_FIN_WAIT_1@;
2N/A#pragma D binding "1.6.3" TCP_STATE_FIN_WAIT_1
2N/Ainline int32_t TCP_STATE_CLOSING = @TCPS_CLOSING@;
2N/A#pragma D binding "1.6.3" TCP_STATE_CLOSING
2N/Ainline int32_t TCP_STATE_LAST_ACK = @TCPS_LAST_ACK@;
2N/A#pragma D binding "1.6.3" TCP_STATE_LAST_ACK
2N/Ainline int32_t TCP_STATE_FIN_WAIT_2 = @TCPS_FIN_WAIT_2@;
2N/A#pragma D binding "1.6.3" TCP_STATE_FIN_WAIT_2
2N/Ainline int32_t TCP_STATE_TIME_WAIT = @TCPS_TIME_WAIT@;
2N/A#pragma D binding "1.6.3" TCP_STATE_TIME_WAIT
2N/A
2N/A/*
2N/A * Convert a TCP state value to a string.
2N/A */
2N/Ainline string tcp_state_string[int32_t state] =
2N/A state == TCP_STATE_CLOSED ? "state-closed" :
2N/A state == TCP_STATE_IDLE ? "state-idle" :
2N/A state == TCP_STATE_BOUND ? "state-bound" :
2N/A state == TCP_STATE_LISTEN ? "state-listen" :
2N/A state == TCP_STATE_SYN_SENT ? "state-syn-sent" :
2N/A state == TCP_STATE_SYN_RECEIVED ? "state-syn-received" :
2N/A state == TCP_STATE_ESTABLISHED ? "state-established" :
2N/A state == TCP_STATE_CLOSE_WAIT ? "state-close-wait" :
2N/A state == TCP_STATE_FIN_WAIT_1 ? "state-fin-wait-1" :
2N/A state == TCP_STATE_CLOSING ? "state-closing" :
2N/A state == TCP_STATE_LAST_ACK ? "state-last-ack" :
2N/A state == TCP_STATE_FIN_WAIT_2 ? "state-fin-wait-2" :
2N/A state == TCP_STATE_TIME_WAIT ? "state-time-wait" :
2N/A "<unknown>";
2N/A#pragma D binding "1.6.3" tcp_state_string
2N/A
2N/A/*
2N/A * tcpinfo is the TCP header fields.
2N/A */
2N/Atypedef struct tcpinfo {
2N/A uint16_t tcp_sport; /* source port */
2N/A uint16_t tcp_dport; /* destination port */
2N/A uint32_t tcp_seq; /* sequence number */
2N/A uint32_t tcp_ack; /* acknowledgment number */
2N/A uint8_t tcp_offset; /* data offset, in bytes */
2N/A uint8_t tcp_flags; /* flags */
2N/A uint16_t tcp_window; /* window size */
2N/A uint16_t tcp_checksum; /* checksum */
2N/A uint16_t tcp_urgent; /* urgent data pointer */
2N/A tcph_t *tcp_hdr; /* raw TCP header */
2N/A} tcpinfo_t;
2N/A
2N/A/*
2N/A * tcpsinfo contains stable TCP details from tcp_t.
2N/A */
2N/Atypedef struct tcpsinfo {
2N/A uintptr_t tcps_addr;
2N/A int tcps_local; /* is delivered locally, boolean */
2N/A int tcps_active; /* active open (from here), boolean */
2N/A uint16_t tcps_lport; /* local port */
2N/A uint16_t tcps_rport; /* remote port */
2N/A string tcps_laddr; /* local address, as a string */
2N/A string tcps_raddr; /* remote address, as a string */
2N/A int32_t tcps_state; /* TCP state */
2N/A uint32_t tcps_iss; /* Initial sequence # sent */
2N/A uint32_t tcps_suna; /* sequence # sent but unacked */
2N/A uint32_t tcps_snxt; /* next sequence # to send */
2N/A uint32_t tcps_rack; /* sequence # we have acked */
2N/A uint32_t tcps_rnxt; /* next sequence # expected */
2N/A uint32_t tcps_swnd; /* send window size */
2N/A int32_t tcps_snd_ws; /* send window scaling */
2N/A uint32_t tcps_rwnd; /* receive window size */
2N/A int32_t tcps_rcv_ws; /* receive window scaling */
2N/A uint32_t tcps_cwnd; /* congestion window */
2N/A uint32_t tcps_cwnd_ssthresh; /* threshold for congestion avoidance */
2N/A uint32_t tcps_sack_fack; /* SACK sequence # we have acked */
2N/A uint32_t tcps_sack_snxt; /* next SACK seq # for retransmission */
2N/A uint32_t tcps_rto; /* round-trip timeout, msec */
2N/A uint32_t tcps_mss; /* max segment size */
2N/A int tcps_retransmit; /* retransmit send event, boolean */
2N/A} tcpsinfo_t;
2N/A
2N/A/*
2N/A * tcplsinfo provides the old tcp state for state changes.
2N/A */
2N/Atypedef struct tcplsinfo {
2N/A int32_t tcps_state; /* previous TCP state */
2N/A} tcplsinfo_t;
2N/A
2N/A/*
2N/A * __dtrace_tcp_tcph_t is used by the tcpinfo_t * translator to take either
2N/A * the non-NULL tcph_t * passed in or, if it is NULL, uses arg3 (tcp_t *)
2N/A * from the tcp:::send and tcp:::recieve probes and translates the tcp_t *
2N/A * into the tcpinfo_t. When no headers are available - as is the case for
2N/A * TCP fusion tcp:::send and tcp:::receive - this allows us to present the
2N/A * consumer with header data based on tcp_t * content and hide TCP fusion
2N/A * implementation details.
2N/A */
2N/Atypedef tcph_t * __dtrace_tcp_tcph_t;
2N/A
2N/A#pragma D binding "1.6.3" translator
2N/Atranslator tcpinfo_t < tcph_t *T > {
2N/A tcp_sport = ntohs(*(uint16_t *)T->th_lport);
2N/A tcp_dport = ntohs(*(uint16_t *)T->th_fport);
2N/A tcp_seq = ntohl(*(uint32_t *)T->th_seq);
2N/A tcp_ack = ntohl(*(uint32_t *)T->th_ack);
2N/A tcp_offset = (*(uint8_t *)T->th_offset_and_rsrvd & 0xf0) >> 2;
2N/A tcp_flags = *(uint8_t *)T->th_flags;
2N/A tcp_window = ntohs(*(uint16_t *)T->th_win);
2N/A tcp_checksum = ntohs(*(uint16_t *)T->th_sum);
2N/A tcp_urgent = ntohs(*(uint16_t *)T->th_urp);
2N/A tcp_hdr = T;
2N/A};
2N/A
2N/A#pragma D binding "1.6.3" translator
2N/Atranslator tcpinfo_t < __dtrace_tcp_tcph_t *T > {
2N/A tcp_sport =
2N/A T != NULL ? ntohs(*(uint16_t *)((tcph_t *)T)->th_lport) :
2N/A arg3 != NULL && probename == "send" ?
2N/A ntohs(((tcp_t *)arg3)->tcp_connp->u_port.connu_ports.connu_lport) :
2N/A arg3 != NULL && probename == "receive" ?
2N/A ntohs(((tcp_t *)arg3)->tcp_connp->u_port.connu_ports.connu_fport) :
2N/A 0;
2N/A tcp_dport =
2N/A T != NULL ? ntohs(*(uint16_t *)((tcph_t *)T)->th_fport) :
2N/A arg3 != NULL && probename == "send" ?
2N/A ntohs(((tcp_t *)arg3)->tcp_connp->u_port.connu_ports.connu_fport) :
2N/A arg3 != NULL && probename == "receive" ?
2N/A ntohs(((tcp_t *)arg3)->tcp_connp->u_port.connu_ports.connu_lport) :
2N/A 0;
2N/A tcp_seq =
2N/A T != NULL ? ntohl(*(uint32_t *)((tcph_t *)T)->th_seq) :
2N/A arg3 != NULL && probename == "send" ?
2N/A ((tcp_t *)arg3)->tcp_snxt - ((tcp_t *)arg3)->tcp_last_sent_len :
2N/A arg3 != NULL && probename == "receive" ?
2N/A ((tcp_t *)arg3)->tcp_rnxt - ((tcp_t *)arg3)->tcp_last_recv_len :
2N/A 0;
2N/A tcp_ack =
2N/A T != NULL ? ntohl(*(uint32_t *)((tcph_t *)T)->th_ack) :
2N/A arg3 != NULL && probename == "send" ?
2N/A ((tcp_t *)arg3)->tcp_rnxt :
2N/A arg3 != NULL && probename == "receive" ?
2N/A ((tcp_t *)arg3)->tcp_snxt :
2N/A 0;
2N/A tcp_offset = T != NULL ?
2N/A (*(uint8_t *)((tcph_t *)T)->th_offset_and_rsrvd & 0xf0) >> 2 :
2N/A @TCP_MIN_HEADER_LENGTH@;
2N/A tcp_flags = T != NULL ? *(uint8_t *)((tcph_t *)T)->th_flags : TH_ACK;
2N/A tcp_window = T != NULL ? ntohs(*(uint16_t *)((tcph_t *)T)->th_win) :
2N/A arg3 != NULL ? ((tcp_t *)arg3)->tcp_swnd : 0;
2N/A tcp_checksum = T != NULL ? ntohs(*(uint16_t *)((tcph_t *)T)->th_sum) :
2N/A 0;
2N/A tcp_urgent = T != NULL ? ntohs(*(uint16_t *)((tcph_t *)T)->th_urp) : 0;
2N/A tcp_hdr = NULL;
2N/A};
2N/A
2N/A#pragma D binding "1.6.3" translator
2N/Atranslator tcpsinfo_t < tcp_t *T > {
2N/A tcps_addr = (uintptr_t)T;
2N/A /*
2N/A * The following two members should just use tcp_t->tcp_loopback
2N/A * and tcp_t->tcp_active_open, however these are bit fields and
2N/A * can't be used until CR 6876830 is fixed. Meanwhile we source
2N/A * them a different way.
2N/A */
2N/A tcps_local = T ? T->tcp_ipha ?
2N/A T->tcp_ipha->ipha_src == T->tcp_ipha->ipha_dst :
2N/A T->tcp_ip6h ?
2N/A ((T->tcp_ip6h->ip6_src._S6_un._S6_u32[3] ==
2N/A T->tcp_ip6h->ip6_dst._S6_un._S6_u32[3]) &&
2N/A (T->tcp_ip6h->ip6_src._S6_un._S6_u32[2] ==
2N/A T->tcp_ip6h->ip6_dst._S6_un._S6_u32[2]) &&
2N/A (T->tcp_ip6h->ip6_src._S6_un._S6_u32[1] ==
2N/A T->tcp_ip6h->ip6_dst._S6_un._S6_u32[1]) &&
2N/A (T->tcp_ip6h->ip6_src._S6_un._S6_u32[0] ==
2N/A T->tcp_ip6h->ip6_dst._S6_un._S6_u32[0])) : 1 : 0;
2N/A tcps_active = T ? !T->tcp_saved_listener : 0;
2N/A tcps_lport = T ?
2N/A ntohs(T->tcp_connp->u_port.connu_ports.connu_lport) : 0;
2N/A tcps_rport = T ?
2N/A ntohs(T->tcp_connp->u_port.connu_ports.connu_fport) : 0;
2N/A tcps_laddr = T ?
2N/A inet_ntoa6(&T->tcp_connp->connua_v6addr.connua_laddr) : "<unknown>";
2N/A tcps_raddr = T ?
2N/A inet_ntoa6(&T->tcp_connp->connua_v6addr.connua_faddr) : "<unknown>";
2N/A tcps_state = T ? T->tcp_state : TCP_STATE_CLOSED;
2N/A tcps_iss = T ? T->tcp_iss : 0;
2N/A tcps_suna = T ? T->tcp_suna : 0;
2N/A tcps_snxt = T ? T->tcp_snxt : 0;
2N/A tcps_rack = T ? T->tcp_rack : 0;
2N/A tcps_rnxt = T ? T->tcp_rnxt : 0;
2N/A tcps_swnd = T ? T->tcp_swnd : 0;
2N/A tcps_snd_ws = T ? T->tcp_snd_ws : 0;
2N/A tcps_rwnd = T ? T->tcp_rwnd : 0;
2N/A tcps_rcv_ws = T ? T->tcp_rcv_ws : 0;
2N/A tcps_cwnd = T ? T->tcp_cwnd : 0;
2N/A tcps_cwnd_ssthresh = T ? T->tcp_cwnd_ssthresh : 0;
2N/A tcps_sack_fack = T ? T->tcp_sack_info.tcp_fack : 0;
2N/A tcps_sack_snxt = T ? T->tcp_sack_info.tcp_sack_snxt : 0;
2N/A tcps_rto = T ? T->tcp_rto : 0;
2N/A tcps_mss = T ? T->tcp_mss : 0;
2N/A /*
2N/A * Determine if send is a retransmission by comparing the seq # to
2N/A * tcp_rexmit_nxt/tcp_rexmit_max - if the value is >= rexmit_nxt and
2N/A * < rexmit_max, this is a retransmission. Cannot use tcp_rexmit
2N/A * bitfield value due to CR 6876830.
2N/A */
2N/A tcps_retransmit = T && probename == "send" && arg4 != NULL &&
2N/A ntohl(*(uint32_t *)((tcph_t *)arg4)->th_seq) >= T->tcp_rexmit_nxt &&
2N/A ntohl(*(uint32_t *)((tcph_t *)arg4)->th_seq) < T->tcp_rexmit_max ?
2N/A 1 : 0;
2N/A};
2N/A
2N/A/*
2N/A * Note: although we specify that the old state argument used as the
2N/A * input to the tcplsinfo_t translator is an int32_t, it reaches us as an
2N/A * int64_t (since it is a probe argument) so explicitly cast it back to
2N/A * interpret the negatively-valued states correctly.
2N/A */
2N/A#pragma D binding "1.6.3" translator
2N/Atranslator tcplsinfo_t < int64_t I > {
2N/A tcps_state = (int32_t) I;
2N/A};