DTRACE_TCP(4)
β¨ NAME β¨
okay so bestie, welcome to dtrace_tcp(4) β a DTrace provider for tracing events related to the tcp(4) protocol. (Straight out of the Kernel Interfaces Manual, iykyk π«Ά)
π¦ SYNOPSIS π¦
the probe signatures are giving very copy-me-exactly energy:
tcp:::accept-established(pktinfo_t *, csinfo_t *, ipinfo_t *,
tcpsinfo_t *, tcpinfo_t *);
tcp:::accept-refused(pktinfo_t *, csinfo_t *, ipinfo_t *, tcpsinfo_t *,
tcpinfo_t *);
tcp:::connect-established(pktinfo_t *, csinfo_t *, ipinfo_t *,
tcpsinfo_t *, tcpinfo_t *);
tcp:::connect-refused(pktinfo_t *, csinfo_t *, ipinfo_t *, tcpsinfo_t *,
tcpinfo_t *);
tcp:::connect-request(pktinfo_t *, csinfo_t *, ipinfo_t *, tcpsinfo_t *,
tcpinfo_t *);
tcp:::receive(pktinfo_t *, csinfo_t *, ipinfo_t *, tcpsinfo_t *,
tcpinfo_t *);
tcp:::send(pktinfo_t *, csinfo_t *, ipinfo_t *, tcpsinfo_t *,
tcpinfo_t *);
tcp:::state-change(void *, csinfo_t *, void *, tcpsinfo_t *, void *,
tcplsinfo_t *);
tcp:::siftr(siftrinfo_t *);
π DESCRIPTION π
The DTrace tcp provider is your backstage pass to trace events in the tcp(4) protocol implementation. It's lowkey similar to the dtrace_ip(4) and dtrace_udp(4) providers, but bestie, it also contains probes corresponding to protocol events at a level higher than packet reception and transmission. Iconic behavior, honestly. π
All tcp probes except for tcp:::state-change() and tcp:::siftr() have the same number and type of arguments. The last three arguments are used to describe a TCP segment: the ipinfo_t argument exposes the version-agnostic fields of the IP header, while the tcpinfo_t argument exposes the TCP header, and the tcpsinfo_t argument describes details of the corresponding TCP connection state, if any. Their fields are described in the ARGUMENTS section. β¨
tcp:::accept-established()β fires when a remotely-initiated active TCP open succeeds. At this point the new connection is in theESTABLISHEDstate, and the probe arguments expose the headers associated with the finalACKof the three-way handshake. πtcp:::accept-refused()β fires when aSYNarrives on a port without a listening socket. The probe arguments expose the headers associated with theRSTto be transmitted to the remote host in response to theSYNsegment. π
The tcp:::connect-established(), tcp:::connect-refused(), and tcp:::connect-request() probes are similar to the accept probes, except that they correspond to locally-initiated TCP connections. Periodt.
tcp:::connect-established()β fires when theSYN-ACKsegment of a three-way handshake is received from the remote host and a finalACKis prepared for transmission. This occurs immediately after the local connection state transitions fromSYN-SENTtoESTABLISHED. The probe arguments describe the headers associated with the receivedSYN-ACKsegment. π₯tcp:::connect-refused()β fires when the local host receives aRSTsegment in response to aSYNsegment, indicating that the remote host refused to open a connection. The probe arguments describe the IP and TCP headers associated with the receivedRSTsegment. πtcp:::connect-request()β fires as the kernel prepares to transmit the initialSYNsegment of a three-way handshake. π
The tcp:::send() and tcp:::receive() probes fire when the host sends or receives a TCP packet, respectively. As with the dtrace_udp(4) provider, tcp probes fire only for packets sent by or to the local host; forwarded packets are handled in the IP layer and are only visible to the dtrace_ip(4) provider. No cap. π―
The tcp:::state-change() probe fires upon local TCP connection state transitions. Its first, third and fifth arguments are currently always NULL. Its last argument describes the from-state in the transition, and the to-state can be obtained from args[3]->tcps_state. π¦
The tcp:::siftr() probe fires when a TCP segment is sent or received by the host. For a detailed description see siftr(4). The siftrinfo_t argument provides the information about the TCP connection. πΈ
π ARGUMENTS π
π pktinfo_t π
Okay so the pktinfo_t argument is currently unimplemented, bestie β it's literally just here for compatibility with other implementations of this provider. Its fields are:
uinptr_t pkt_addrβ always set to0. That's it. That's the field. π
π¦ csinfo_t π¦
Same vibe: the csinfo_t argument is currently unimplemented and is included for compatibility with other implementations of this provider. Its fields are:
uintptr_t cs_addrβ always set to0.uint64_t cs_cidβ a pointer to thestruct inpcbfor this packet, orNULL.pid_t cs_pidβ always set to0.
π ipinfo_t π
The ipinfo_t type is a version-agnostic representation of fields from an IP header. Its fields are described in the dtrace_ip(4) manual page. Go read that one for the full breakdown, iykyk. β¨
π tcpsinfo_t π
The tcpsinfo_t type gives you a stable representation of TCP connection state. Some tcp probes β like tcp:::accept-refused() β fire in a context where there is no TCP connection, and in that case this argument is NULL. Its fields are:
uintptr_t tcps_addrβ the address of the corresponding TCP control block. Currently this is a pointer to astruct tcpcb.int tcps_localβ a boolean indicating whether the connection is local to the host. Currently unimplemented and always set to-1.int tcps_activeβ a boolean indicating whether the connection was initiated by the local host. Currently unimplemented and always set to-1.uint16_t tcps_lportβ local TCP port.uint16_t tcps_rportβ remote TCP port.string tcps_laddrβ local address.string tcps_raddrβ remote address.int32_t tcps_stateβ current TCP state. The valid TCP state values are given by the constants prefixed withTCPS_in/usr/lib/dtrace/tcp.d.uint32_t tcps_issβ initial send sequence number.uint32_t tcps_sunaβ initial sequence number of sent but unacknowledged data.uint32_t tcps_snxtβ next sequence number for send.uint32_t tcps_rackβ sequence number of received and acknowledged data.uint32_t tcps_rnxtβ next expected sequence number for receive.u_long tcps_swndβ TCP send window size.int32_t tcps_snd_wsβ window scaling factor for the TCP send window.u_long tcps_rwndβ TCP receive window size.int32_t tcps_rcv_wsβ window scaling factor for the TCP receive window.u_long tcps_cwndβ TCP congestion window size.u_long tcps_cwnd_ssthreshβ congestion window threshold at which slow start ends and congestion avoidance begins.uint32_t tcps_sack_fackβ last sequence number selectively acknowledged by the receiver.uint32_t tcps_sack_snxtβ next selectively acknowledge sequence number at which to begin retransmitting.uint32_t tcps_rtoβ round-trip timeout, in milliseconds.uint32_t tcps_mssβ maximum segment size.int tcps_retransmitβ a boolean indicating that the local sender is retransmitting data.int tcps_srttβ smoothed round-trip time.
π§ tcpinfo_t π§
The tcpinfo_t type exposes the fields in a TCP segment header in host order. Its fields are:
uint16_t tcp_sportβ source TCP port.uint16_t tcp_dportβ destination TCP port.uint32_t tcp_seqβ sequence number.uint32_t tcp_ackβ acknowledgement number.uint8_t tcp_offsetβ data offset, in bytes.uint8_t tcp_flagsβ TCP flags.uint16_t tcp_windowβ TCP window size.uint16_t tcp_checksumβ checksum.uint16_t tcp_urgentβ urgent data pointer.struct tcphdr *tcp_hdrβ a pointer to the raw TCP header.
πΈ tcplsinfo_t πΈ
The tcplsinfo_t type is used by the tcp:::state-change() probe to provide the from-state of a transition. Its fields are:
int32_t tcps_stateβ a TCP state. The valid TCP state values are given by the constants prefixed withTCPS_in/usr/lib/dtrace/tcp.d.
π siftrinfo_t π
The siftrinfo_t type is used by the tcp:::siftr() probe to provide the state of the TCP connection. Its fields are:
uint8_t directionβ direction of packet that triggered the log message. Either"0"for in, or"1"for out.uint8_t ipverβ the version of the IP protocol being used. Either"1"for IPv4, or"2"for IPv6.uint16_t lportβ the TCP port that the local host is communicating via.uint16_t rportβ the TCP port that the remote host is communicating via.string laddrβ the IPv4 or IPv6 address of the local host.string raddrβ the IPv4 or IPv6 address of the remote host.uint32_t snd_cwndβ the current congestion window (CWND) for the flow, in bytes.uint32_t snd_wndβ the current sending window for the flow, in bytes. The post scaled value is reported, except during the initial handshake (first few packets), during which time the unscaled value is reported.uint32_t rcv_wndβ the current receive window for the flow, in bytes. The post scaled value is always reported.uint32_t t_flags2β the current value of thet_flags2for the flow.uint32_t snd_ssthreshβ the slow start threshold (SSTHRESH) for the flow, in bytes.int conn_stateβ a TCP state. The valid TCP state values are given by the constants prefixed withTCPS_in/usr/lib/dtrace/tcp.d.uint32_t mssβ the maximum segment size (MSS) for the flow, in bytes.uint32_t srttβ the current smoothed RTT (SRTT) for the flow in microseconds.u_char sack_enabledβ SACK enabled indicator.1if SACK enabled,0otherwise.u_char snd_scaleβ the current window scaling factor for the sending window.u_char rcv_scaleβ the current window scaling factor for the receiving window.u_int t_flagsβ the current value of thet_flagsfor the flow.uint32_t rtoβ the current retransmission timeout (RTO) for the flow in microseconds. Divide byHZto get the timeout length in seconds.u_int snd_buf_hiwaterβ the current size of the socket send buffer in bytes.u_int snd_buf_ccβ the current number of bytes in the socket send buffer.u_int rcv_buf_hiwaterβ the current size of the socket receive buffer in bytes.u_int rcv_buf_ccβ the current number of bytes in the socket receive buffer.u_int sent_inflight_bytesβ the current number of unacknowledged bytes in-flight. Bytes acknowledged via SACK are not excluded from this count.int t_segqlenβ the current number of segments in the reassembly queue.u_int flowidβ flowid for the connection. A caveat: zero0either represents a valid flowid or a default value when the flowid is not being set.u_int flowtypeβ flow type for the connection. Flowtype defines which protocol fields are hashed to produce the flowid. A complete listing is available in/usr/include/sys/mbuf.hunderM_HASHTYPE_*.
π FILES π
/usr/lib/dtrace/tcp.dβ DTrace type and translator definitions for all the probes of the tcp provider except the siftr probe./usr/lib/dtrace/siftr.dβ DTrace type and translator definitions for the siftr probe of the tcp provider.
β¨ EXAMPLES β¨
Okay bestie, this is the fun part β actual scripts you can run fr fr. π
πΈ Example 1: logging TCP segments in real time
This one prints every TCP segment as it flies by, in real time. It's giving airport departure board energy. π«
#pragma D option quiet
#pragma D option switchrate=10hz
dtrace:::BEGIN
{
printf(" %3s %15s:%-5s %15s:%-5s %6s %s\n", "CPU",
"LADDR", "LPORT", "RADDR", "RPORT", "BYTES", "FLAGS");
}
tcp:::send
{
this->length = args[2]->ip_plength - args[4]->tcp_offset;
printf(" %3d %16s:%-5d -> %16s:%-5d %6d (", cpu, args[2]->ip_saddr,
args[4]->tcp_sport, args[2]->ip_daddr, args[4]->tcp_dport,
this->length);
printf("%s", args[4]->tcp_flags & TH_FIN ? "FIN|" : "");
printf("%s", args[4]->tcp_flags & TH_SYN ? "SYN|" : "");
printf("%s", args[4]->tcp_flags & TH_RST ? "RST|" : "");
printf("%s", args[4]->tcp_flags & TH_PUSH ? "PUSH|" : "");
printf("%s", args[4]->tcp_flags & TH_ACK ? "ACK|" : "");
printf("%s", args[4]->tcp_flags & TH_URG ? "URG|" : "");
printf("%s", args[4]->tcp_flags == 0 ? "null " : "");
printf("\b)\n");
}
tcp:::receive
{
this->length = args[2]->ip_plength - args[4]->tcp_offset;
printf(" %3d %16s:%-5d <- %16s:%-5d %6d (", cpu,
args[2]->ip_daddr, args[4]->tcp_dport, args[2]->ip_saddr,
args[4]->tcp_sport, this->length);
printf("%s", args[4]->tcp_flags & TH_FIN ? "FIN|" : "");
printf("%s", args[4]->tcp_flags & TH_SYN ? "SYN|" : "");
printf("%s", args[4]->tcp_flags & TH_RST ? "RST|" : "");
printf("%s", args[4]->tcp_flags & TH_PUSH ? "PUSH|" : "");
printf("%s", args[4]->tcp_flags & TH_ACK ? "ACK|" : "");
printf("%s", args[4]->tcp_flags & TH_URG ? "URG|" : "");
printf("%s", args[4]->tcp_flags == 0 ? "null " : "");
printf("\b)\n");
}
The -> in the output is a packet going out on send, the <- means it came in on receive β it's giving directional realness. π
π¦ Example 2: logging TCP connection state changes
This one's for when you want to watch connections mutate between states like a little caterpillar becoming a butterfly. πβ‘οΈπ¦ The DELTA(us) column shows microseconds since the last change on that same connection, and the very first change on a connection shows a literal - instead of a number, bc there's nothing to compare to yet, iykyk.
#pragma D option quiet
#pragma D option switchrate=25hz
int last[int];
dtrace:::BEGIN
{
printf(" %12s %-20s %-20s %s\n",
"DELTA(us)", "OLD", "NEW", "TIMESTAMP");
}
tcp:::state-change
{
this->elapsed = (timestamp - last[args[1]->cs_cid]) / 1000;
printf(" %12d %-20s -> %-20s %d\n", this->elapsed,
tcp_state_string[args[5]->tcps_state],
tcp_state_string[args[3]->tcps_state], timestamp);
last[args[1]->cs_cid] = timestamp;
}
tcp:::state-change
/last[args[1]->cs_cid] == 0/
{
printf(" %12s %-20s -> %-20s %d\n", "-",
tcp_state_string[args[5]->tcps_state],
tcp_state_string[args[3]->tcps_state], timestamp);
last[args[1]->cs_cid] = timestamp;
}
Notice the two tcp:::state-change clauses β the second one is predicate-guarded on last[args[1]->cs_cid] == 0, so it's the "first time we're seeing this connection" clause. The way that works is iconic, actually. π
π§ Example 3: CWND and SSTHRESH via the siftr probe
Wanna peek at congestion window (CWND) and slow-start threshold (SSTHRESH) every time a packet gets sent or received? Yeah you do. The siftr probe is your girl. π
#pragma D option quiet
#pragma D option switchrate=10hz
dtrace:::BEGIN
{
printf(" %3s %16s:%-5s %16s:%-5s %10s %10s\n",
"DIR", "LADDR", "LPORT", "RADDR", "RPORT", "CWND", "SSTHRESH");
}
tcp:::siftr
{
printf(" %3s %16s:%-5d %16s:%-5d %10u %10u\n",
siftr_dir_string[args[0]->direction],
args[0]->laddr, args[0]->lport, args[0]->raddr, args[0]->rport,
args[0]->snd_cwnd, args[0]->snd_ssthresh);
}
π« COMPATIBILITY π«
This provider is compatible with the tcp provider in Solaris. No cap β same vibes across platforms. π«Ά
π SEE ALSO π
Go read these next, bestie, they're all part of the friend group:
π HISTORY π
The tcp provider first appeared in FreeBSD 10.0. A whole era. β
π AUTHORS π
This manual page was written by Mark Johnston <markj@FreeBSD.org>. Absolute main character energy for writing all this out by hand. Respect. π
π BUGS π
Heads up bestie, thetcps_localandtcps_activefields oftcpsinfo_tare not filled in by the translator. So if you're squinting at those and getting nothing β it's not you, it's the translator. π
That's the whole page, bestie β you're officially a dtrace TCP provider knower now. Slay. π
β¨
This page is from Debian, dated July 2, 2023 (DTRACE_TCP(4)) β go forth and trace responsibly. πΈπ¦
π¦ where this page comes from
- freebsd 14.5: base 14.5
- freebsd 15.1: base 15.1
- nixpkgs unstable: source
- Copyright (c) 2015 Mark Johnston <markj@FreeBSD.org>
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms