[DTrace-devel] [PATCH v5 5/6] dlibs: sync ip.d, net.d and tcp.d
Alan Maguire
alan.maguire at oracle.com
Tue Jul 22 10:07:48 UTC 2025
Sync dlibs with libdtrace versions.
Signed-off-by: Alan Maguire <alan.maguire at oracle.com>
Reviewed-by: Kris Van Hees <kris.van.hees at oracle.com>
---
dlibs/aarch64/5.11/ip.d | 27 +---------------
dlibs/aarch64/5.11/net.d | 31 +++++++++++++++++--
dlibs/aarch64/5.11/tcp.d | 67 ++++++++++++++++++++++++----------------
dlibs/aarch64/5.12/ip.d | 27 +---------------
dlibs/aarch64/5.12/net.d | 31 +++++++++++++++++--
dlibs/aarch64/5.12/tcp.d | 67 ++++++++++++++++++++++++----------------
dlibs/aarch64/5.14/ip.d | 27 +---------------
dlibs/aarch64/5.14/net.d | 31 +++++++++++++++++--
dlibs/aarch64/5.14/tcp.d | 67 ++++++++++++++++++++++++----------------
dlibs/aarch64/5.16/ip.d | 27 +---------------
dlibs/aarch64/5.16/net.d | 31 +++++++++++++++++--
dlibs/aarch64/5.16/tcp.d | 67 ++++++++++++++++++++++++----------------
dlibs/aarch64/5.2/ip.d | 27 +---------------
dlibs/aarch64/5.2/net.d | 31 +++++++++++++++++--
dlibs/aarch64/5.2/tcp.d | 67 ++++++++++++++++++++++++----------------
dlibs/aarch64/5.6/ip.d | 27 +---------------
dlibs/aarch64/5.6/net.d | 31 +++++++++++++++++--
dlibs/aarch64/5.6/tcp.d | 67 ++++++++++++++++++++++++----------------
dlibs/aarch64/6.1/ip.d | 27 +---------------
dlibs/aarch64/6.1/net.d | 31 +++++++++++++++++--
dlibs/aarch64/6.1/tcp.d | 67 ++++++++++++++++++++++++----------------
dlibs/aarch64/6.10/ip.d | 27 +---------------
dlibs/aarch64/6.10/net.d | 31 +++++++++++++++++--
dlibs/aarch64/6.10/tcp.d | 67 ++++++++++++++++++++++++----------------
dlibs/x86_64/5.11/ip.d | 27 +---------------
dlibs/x86_64/5.11/net.d | 31 +++++++++++++++++--
dlibs/x86_64/5.11/tcp.d | 67 ++++++++++++++++++++++++----------------
dlibs/x86_64/5.12/ip.d | 27 +---------------
dlibs/x86_64/5.12/net.d | 31 +++++++++++++++++--
dlibs/x86_64/5.12/tcp.d | 67 ++++++++++++++++++++++++----------------
dlibs/x86_64/5.14/ip.d | 27 +---------------
dlibs/x86_64/5.14/net.d | 31 +++++++++++++++++--
dlibs/x86_64/5.14/tcp.d | 67 ++++++++++++++++++++++++----------------
dlibs/x86_64/5.16/ip.d | 27 +---------------
dlibs/x86_64/5.16/net.d | 31 +++++++++++++++++--
dlibs/x86_64/5.16/tcp.d | 67 ++++++++++++++++++++++++----------------
dlibs/x86_64/5.2/ip.d | 27 +---------------
dlibs/x86_64/5.2/net.d | 31 +++++++++++++++++--
dlibs/x86_64/5.2/tcp.d | 67 ++++++++++++++++++++++++----------------
dlibs/x86_64/5.6/ip.d | 27 +---------------
dlibs/x86_64/5.6/net.d | 31 +++++++++++++++++--
dlibs/x86_64/5.6/tcp.d | 67 ++++++++++++++++++++++++----------------
dlibs/x86_64/6.1/ip.d | 27 +---------------
dlibs/x86_64/6.1/net.d | 31 +++++++++++++++++--
dlibs/x86_64/6.1/tcp.d | 67 ++++++++++++++++++++++++----------------
dlibs/x86_64/6.10/ip.d | 27 +---------------
dlibs/x86_64/6.10/net.d | 31 +++++++++++++++++--
dlibs/x86_64/6.10/tcp.d | 67 ++++++++++++++++++++++++----------------
48 files changed, 1120 insertions(+), 880 deletions(-)
diff --git a/dlibs/aarch64/5.11/ip.d b/dlibs/aarch64/5.11/ip.d
index f8b77f12..493b75a0 100644
--- a/dlibs/aarch64/5.11/ip.d
+++ b/dlibs/aarch64/5.11/ip.d
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -46,31 +46,6 @@ inline int IPPROTO_MH = 135;
inline int TCP_MIN_HEADER_LENGTH = 20;
-/*
- * For compatibility with Solaris. Here the netstackid will be the pointer
- * to the net namespace (nd_net in struct net_device).
- */
-typedef uint64_t netstackid_t;
-typedef __be32 ipaddr_t;
-typedef struct in6_addr in6_addr_t;
-
-/*
- * pktinfo is where packet ID info can be made available for deeper
- * analysis if packet IDs become supported by the kernel in the future.
- * The pkt_addr member is currently always NULL.
- */
-typedef struct pktinfo {
- uintptr_t pkt_addr;
-} pktinfo_t;
-
-/*
- * csinfo is where connection state info is made available.
- */
-typedef struct csinfo {
- uintptr_t cs_addr;
- uint64_t cs_cid;
-} csinfo_t;
-
/*
* ipinfo contains common IP info for both IPv4 and IPv6.
*/
diff --git a/dlibs/aarch64/5.11/net.d b/dlibs/aarch64/5.11/net.d
index 6ac34287..f1291696 100644
--- a/dlibs/aarch64/5.11/net.d
+++ b/dlibs/aarch64/5.11/net.d
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -25,9 +25,36 @@ typedef struct conninfo {
string ci_protocol; /* protocol (ipv4, ipv6, etc) */
} conninfo_t;
+/*
+ * For compatibility with Solaris. Here the netstackid will be the pointer
+ * to the net namespace (nd_net in struct net_device).
+ */
+typedef uint64_t netstackid_t;
+typedef __be32 ipaddr_t;
+typedef struct in6_addr in6_addr_t;
+
+/*
+ * pktinfo is where packet ID info can be made available for deeper
+ * analysis if packet IDs become supported by the kernel in the future.
+ * The pkt_addr member is currently always NULL.
+ */
+typedef struct pktinfo {
+ uintptr_t pkt_addr;
+} pktinfo_t;
+
+/*
+ * csinfo is where connection state info is made available.
+ */
+typedef struct csinfo {
+ uintptr_t cs_addr;
+ uint64_t cs_cid;
+} csinfo_t;
+
/*
* We use these values to determine if a probe point is associated
- * with sending (outbound) or receiving (inbound).
+ * with sending (outbound) or receiving (inbound) or a state-related
+ * probe (i.e. neither inbound our outbound).
*/
inline int NET_PROBE_OUTBOUND = 0x00;
inline int NET_PROBE_INBOUND = 0x01;
+inline int NET_PROBE_STATE = 0x02;
diff --git a/dlibs/aarch64/5.11/tcp.d b/dlibs/aarch64/5.11/tcp.d
index 54e310cb..48d9adb4 100644
--- a/dlibs/aarch64/5.11/tcp.d
+++ b/dlibs/aarch64/5.11/tcp.d
@@ -1,13 +1,13 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
#pragma D depends_on module vmlinux
#pragma D depends_on library net.d
-#pragma D depends_on provider ip
+#pragma D depends_on library ip.d
#pragma D depends_on provider tcp
inline int TH_FIN = 0x01;
@@ -111,30 +111,38 @@ translator tcpinfo_t < struct tcphdr *T > {
tcp_seq = T ? ntohl(T->seq) : 0;
tcp_ack = T ? ntohl(T->ack_seq) : 0;
tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0;
- tcp_flags = T ? *(uint8_t *)(T + 13) : 0;
+ tcp_flags = T ? *((uint8_t *)T + 13) : 0;
tcp_window = T ? ntohs(T->window) : 0;
tcp_checksum = T ? ntohs(T->check) : 0;
tcp_urgent = T ? ntohs(T->urg_ptr) : 0;
tcp_hdr = (uintptr_t)T;
};
+/* timewait sockets and inet connection sockets do not populate all fields
+ * and are not classified as full sockets; this inline helps translators
+ * spot them and act appropriately.
+ */
+inline int tcp_fullsock[struct tcp_sock *sk] =
+ (((struct sock_common *)sk)->skc_state != TCP_STATE_SYN_RECEIVED &&
+ ((struct sock_common *)sk)->skc_state != TCP_STATE_TIME_WAIT);
/*
* In the main we simply translate from the "struct [tcp_]sock *" to
* a tcpsinfo_t *. However there are a few exceptions:
*
- * - tcps_state is always derived from arg6. The reason is that in some
+ * - tcps_state for state-change is arg5. The reason is that in some
* state transitions sock->sk_state does not reflect the actual TCP
* connection state. For example the TIME_WAIT state is handled in
* Linux by creating a separate timewait socket and the state of the
* original socket is CLOSED. In some other cases we also need to
- * instrument state transition prior to the update of sk_state. To do
- * all of this we rely on arg6.
+ * instrument state transition _prior_ to the update of sk_state. To do
+ * all of this we rely on arg5 to hold the new state. arg6 is set to
+ * NET_PROBE_STATE to quickly identify state-change probes.
* - we sometimes need to retrieve local/remote port/address settings from
* TCP and IP headers directly, for example prior to the address/port
* being committed to the socket. To do this effectively we need to know
* if the packet data is inbound (in which case the local IP/port are the
* destination) or outbound (in which case the local IP/port are the source).
- * arg7 is set to 0 for outbound traffic and 1 for inbound so we use these
+ * arg6 is set to 0 for outbound traffic and 1 for inbound so we use these
* to reconstruct the address/port info where necessary. arg2 used for IP
* information while arg4 contains the TCP header, so it is used for port data.
* NET_PROBE_INBOUND is defined as 1, NET_PROBE_OUTBOUND as 0 in net.d.
@@ -158,47 +166,49 @@ translator tcpsinfo_t < struct tcp_sock *T > {
((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_daddr)[2] &&
((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr)[3])
: 0;
- tcps_lport = (T && ((struct inet_sock *)T)->inet_sport != 0) ?
+ tcps_lport = T && ((struct inet_sock *)T)->inet_sport != 0 &&
+ tcp_fullsock[T] ?
ntohs(((struct inet_sock *)T)->inet_sport) :
(T && ((struct inet_sock *)T)->inet_sport == 0) ?
- ntohs(((struct sock *)T)->__sk_common.skc_num) :
+ ((struct sock *)T)->__sk_common.skc_num :
arg4 != NULL ?
ntohs(arg7 == NET_PROBE_INBOUND ?
- ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) :
+ ((struct tcphdr *)arg4)->dest :
+ ((struct tcphdr *)arg4)->source) :
0;
tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ?
ntohs(((struct sock *)T)->__sk_common.skc_dport) :
arg4 != NULL ?
ntohs(arg7 == NET_PROBE_INBOUND ?
- ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) :
+ ((struct tcphdr *)arg4)->source :
+ ((struct tcphdr *)arg4)->dest) :
0;
tcps_laddr =
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ?
inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) :
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ?
inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) :
- arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ?
- inet_ntoa(arg7 == NET_PROBE_INBOUND ?
- &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) :
- arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ?
- inet_ntoa6(arg7 == NET_PROBE_INBOUND ?
- &((struct ipv6hdr *)arg2)->daddr :
- &((struct ipv6hdr *)arg2)->saddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ?
+ inet_ntoa(&((struct iphdr *)arg2)->daddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ?
+ inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) :
"<unknown>";
tcps_raddr =
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ?
inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) :
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ?
inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) :
- arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ?
- inet_ntoa(arg7 == NET_PROBE_INBOUND ?
- &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) :
- arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ?
- inet_ntoa6(arg7 == NET_PROBE_INBOUND ?
- &((struct ipv6hdr *)arg2)->saddr :
- &((struct ipv6hdr *)arg2)->daddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ?
+ inet_ntoa(&((struct iphdr *)arg2)->saddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ?
+ inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) :
"<unknown>";
- tcps_state = arg6;
+ /* For state-change we probe right before state has changed, but
+ * provider definition wants new state in tcps_state; for
+ * state-change probes the trampoline stores it in arg5.
+ */
+ tcps_state = arg6 == NET_PROBE_STATE ? arg5 :
+ T ? ((struct sock *)T)->__sk_common.skc_state : 0;
tcps_iss = T ?
T->snd_una - (uint32_t)T->bytes_acked : 0;
tcps_suna = T ? T->snd_una : 0;
@@ -225,7 +235,10 @@ translator tcpsinfo_t < struct tcp_sock *T > {
T->rcv_nxt - (uint32_t)T->bytes_received : 0;
};
+/* state-change trampoline stores new state in arg5; at time of firing,
+ * state has not been updated, so last state is in tcp_sock state.
+ */
#pragma D binding "1.6.3" translator
translator tcplsinfo_t < int I > {
- tcps_state = I;
+ tcps_state = arg3 ? ((struct sock *)arg3)->__sk_common.skc_state : 0;
};
diff --git a/dlibs/aarch64/5.12/ip.d b/dlibs/aarch64/5.12/ip.d
index f8b77f12..493b75a0 100644
--- a/dlibs/aarch64/5.12/ip.d
+++ b/dlibs/aarch64/5.12/ip.d
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -46,31 +46,6 @@ inline int IPPROTO_MH = 135;
inline int TCP_MIN_HEADER_LENGTH = 20;
-/*
- * For compatibility with Solaris. Here the netstackid will be the pointer
- * to the net namespace (nd_net in struct net_device).
- */
-typedef uint64_t netstackid_t;
-typedef __be32 ipaddr_t;
-typedef struct in6_addr in6_addr_t;
-
-/*
- * pktinfo is where packet ID info can be made available for deeper
- * analysis if packet IDs become supported by the kernel in the future.
- * The pkt_addr member is currently always NULL.
- */
-typedef struct pktinfo {
- uintptr_t pkt_addr;
-} pktinfo_t;
-
-/*
- * csinfo is where connection state info is made available.
- */
-typedef struct csinfo {
- uintptr_t cs_addr;
- uint64_t cs_cid;
-} csinfo_t;
-
/*
* ipinfo contains common IP info for both IPv4 and IPv6.
*/
diff --git a/dlibs/aarch64/5.12/net.d b/dlibs/aarch64/5.12/net.d
index 6ac34287..f1291696 100644
--- a/dlibs/aarch64/5.12/net.d
+++ b/dlibs/aarch64/5.12/net.d
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -25,9 +25,36 @@ typedef struct conninfo {
string ci_protocol; /* protocol (ipv4, ipv6, etc) */
} conninfo_t;
+/*
+ * For compatibility with Solaris. Here the netstackid will be the pointer
+ * to the net namespace (nd_net in struct net_device).
+ */
+typedef uint64_t netstackid_t;
+typedef __be32 ipaddr_t;
+typedef struct in6_addr in6_addr_t;
+
+/*
+ * pktinfo is where packet ID info can be made available for deeper
+ * analysis if packet IDs become supported by the kernel in the future.
+ * The pkt_addr member is currently always NULL.
+ */
+typedef struct pktinfo {
+ uintptr_t pkt_addr;
+} pktinfo_t;
+
+/*
+ * csinfo is where connection state info is made available.
+ */
+typedef struct csinfo {
+ uintptr_t cs_addr;
+ uint64_t cs_cid;
+} csinfo_t;
+
/*
* We use these values to determine if a probe point is associated
- * with sending (outbound) or receiving (inbound).
+ * with sending (outbound) or receiving (inbound) or a state-related
+ * probe (i.e. neither inbound our outbound).
*/
inline int NET_PROBE_OUTBOUND = 0x00;
inline int NET_PROBE_INBOUND = 0x01;
+inline int NET_PROBE_STATE = 0x02;
diff --git a/dlibs/aarch64/5.12/tcp.d b/dlibs/aarch64/5.12/tcp.d
index 54e310cb..48d9adb4 100644
--- a/dlibs/aarch64/5.12/tcp.d
+++ b/dlibs/aarch64/5.12/tcp.d
@@ -1,13 +1,13 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
#pragma D depends_on module vmlinux
#pragma D depends_on library net.d
-#pragma D depends_on provider ip
+#pragma D depends_on library ip.d
#pragma D depends_on provider tcp
inline int TH_FIN = 0x01;
@@ -111,30 +111,38 @@ translator tcpinfo_t < struct tcphdr *T > {
tcp_seq = T ? ntohl(T->seq) : 0;
tcp_ack = T ? ntohl(T->ack_seq) : 0;
tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0;
- tcp_flags = T ? *(uint8_t *)(T + 13) : 0;
+ tcp_flags = T ? *((uint8_t *)T + 13) : 0;
tcp_window = T ? ntohs(T->window) : 0;
tcp_checksum = T ? ntohs(T->check) : 0;
tcp_urgent = T ? ntohs(T->urg_ptr) : 0;
tcp_hdr = (uintptr_t)T;
};
+/* timewait sockets and inet connection sockets do not populate all fields
+ * and are not classified as full sockets; this inline helps translators
+ * spot them and act appropriately.
+ */
+inline int tcp_fullsock[struct tcp_sock *sk] =
+ (((struct sock_common *)sk)->skc_state != TCP_STATE_SYN_RECEIVED &&
+ ((struct sock_common *)sk)->skc_state != TCP_STATE_TIME_WAIT);
/*
* In the main we simply translate from the "struct [tcp_]sock *" to
* a tcpsinfo_t *. However there are a few exceptions:
*
- * - tcps_state is always derived from arg6. The reason is that in some
+ * - tcps_state for state-change is arg5. The reason is that in some
* state transitions sock->sk_state does not reflect the actual TCP
* connection state. For example the TIME_WAIT state is handled in
* Linux by creating a separate timewait socket and the state of the
* original socket is CLOSED. In some other cases we also need to
- * instrument state transition prior to the update of sk_state. To do
- * all of this we rely on arg6.
+ * instrument state transition _prior_ to the update of sk_state. To do
+ * all of this we rely on arg5 to hold the new state. arg6 is set to
+ * NET_PROBE_STATE to quickly identify state-change probes.
* - we sometimes need to retrieve local/remote port/address settings from
* TCP and IP headers directly, for example prior to the address/port
* being committed to the socket. To do this effectively we need to know
* if the packet data is inbound (in which case the local IP/port are the
* destination) or outbound (in which case the local IP/port are the source).
- * arg7 is set to 0 for outbound traffic and 1 for inbound so we use these
+ * arg6 is set to 0 for outbound traffic and 1 for inbound so we use these
* to reconstruct the address/port info where necessary. arg2 used for IP
* information while arg4 contains the TCP header, so it is used for port data.
* NET_PROBE_INBOUND is defined as 1, NET_PROBE_OUTBOUND as 0 in net.d.
@@ -158,47 +166,49 @@ translator tcpsinfo_t < struct tcp_sock *T > {
((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_daddr)[2] &&
((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr)[3])
: 0;
- tcps_lport = (T && ((struct inet_sock *)T)->inet_sport != 0) ?
+ tcps_lport = T && ((struct inet_sock *)T)->inet_sport != 0 &&
+ tcp_fullsock[T] ?
ntohs(((struct inet_sock *)T)->inet_sport) :
(T && ((struct inet_sock *)T)->inet_sport == 0) ?
- ntohs(((struct sock *)T)->__sk_common.skc_num) :
+ ((struct sock *)T)->__sk_common.skc_num :
arg4 != NULL ?
ntohs(arg7 == NET_PROBE_INBOUND ?
- ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) :
+ ((struct tcphdr *)arg4)->dest :
+ ((struct tcphdr *)arg4)->source) :
0;
tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ?
ntohs(((struct sock *)T)->__sk_common.skc_dport) :
arg4 != NULL ?
ntohs(arg7 == NET_PROBE_INBOUND ?
- ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) :
+ ((struct tcphdr *)arg4)->source :
+ ((struct tcphdr *)arg4)->dest) :
0;
tcps_laddr =
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ?
inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) :
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ?
inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) :
- arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ?
- inet_ntoa(arg7 == NET_PROBE_INBOUND ?
- &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) :
- arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ?
- inet_ntoa6(arg7 == NET_PROBE_INBOUND ?
- &((struct ipv6hdr *)arg2)->daddr :
- &((struct ipv6hdr *)arg2)->saddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ?
+ inet_ntoa(&((struct iphdr *)arg2)->daddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ?
+ inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) :
"<unknown>";
tcps_raddr =
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ?
inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) :
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ?
inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) :
- arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ?
- inet_ntoa(arg7 == NET_PROBE_INBOUND ?
- &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) :
- arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ?
- inet_ntoa6(arg7 == NET_PROBE_INBOUND ?
- &((struct ipv6hdr *)arg2)->saddr :
- &((struct ipv6hdr *)arg2)->daddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ?
+ inet_ntoa(&((struct iphdr *)arg2)->saddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ?
+ inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) :
"<unknown>";
- tcps_state = arg6;
+ /* For state-change we probe right before state has changed, but
+ * provider definition wants new state in tcps_state; for
+ * state-change probes the trampoline stores it in arg5.
+ */
+ tcps_state = arg6 == NET_PROBE_STATE ? arg5 :
+ T ? ((struct sock *)T)->__sk_common.skc_state : 0;
tcps_iss = T ?
T->snd_una - (uint32_t)T->bytes_acked : 0;
tcps_suna = T ? T->snd_una : 0;
@@ -225,7 +235,10 @@ translator tcpsinfo_t < struct tcp_sock *T > {
T->rcv_nxt - (uint32_t)T->bytes_received : 0;
};
+/* state-change trampoline stores new state in arg5; at time of firing,
+ * state has not been updated, so last state is in tcp_sock state.
+ */
#pragma D binding "1.6.3" translator
translator tcplsinfo_t < int I > {
- tcps_state = I;
+ tcps_state = arg3 ? ((struct sock *)arg3)->__sk_common.skc_state : 0;
};
diff --git a/dlibs/aarch64/5.14/ip.d b/dlibs/aarch64/5.14/ip.d
index f8b77f12..493b75a0 100644
--- a/dlibs/aarch64/5.14/ip.d
+++ b/dlibs/aarch64/5.14/ip.d
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -46,31 +46,6 @@ inline int IPPROTO_MH = 135;
inline int TCP_MIN_HEADER_LENGTH = 20;
-/*
- * For compatibility with Solaris. Here the netstackid will be the pointer
- * to the net namespace (nd_net in struct net_device).
- */
-typedef uint64_t netstackid_t;
-typedef __be32 ipaddr_t;
-typedef struct in6_addr in6_addr_t;
-
-/*
- * pktinfo is where packet ID info can be made available for deeper
- * analysis if packet IDs become supported by the kernel in the future.
- * The pkt_addr member is currently always NULL.
- */
-typedef struct pktinfo {
- uintptr_t pkt_addr;
-} pktinfo_t;
-
-/*
- * csinfo is where connection state info is made available.
- */
-typedef struct csinfo {
- uintptr_t cs_addr;
- uint64_t cs_cid;
-} csinfo_t;
-
/*
* ipinfo contains common IP info for both IPv4 and IPv6.
*/
diff --git a/dlibs/aarch64/5.14/net.d b/dlibs/aarch64/5.14/net.d
index 6ac34287..f1291696 100644
--- a/dlibs/aarch64/5.14/net.d
+++ b/dlibs/aarch64/5.14/net.d
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -25,9 +25,36 @@ typedef struct conninfo {
string ci_protocol; /* protocol (ipv4, ipv6, etc) */
} conninfo_t;
+/*
+ * For compatibility with Solaris. Here the netstackid will be the pointer
+ * to the net namespace (nd_net in struct net_device).
+ */
+typedef uint64_t netstackid_t;
+typedef __be32 ipaddr_t;
+typedef struct in6_addr in6_addr_t;
+
+/*
+ * pktinfo is where packet ID info can be made available for deeper
+ * analysis if packet IDs become supported by the kernel in the future.
+ * The pkt_addr member is currently always NULL.
+ */
+typedef struct pktinfo {
+ uintptr_t pkt_addr;
+} pktinfo_t;
+
+/*
+ * csinfo is where connection state info is made available.
+ */
+typedef struct csinfo {
+ uintptr_t cs_addr;
+ uint64_t cs_cid;
+} csinfo_t;
+
/*
* We use these values to determine if a probe point is associated
- * with sending (outbound) or receiving (inbound).
+ * with sending (outbound) or receiving (inbound) or a state-related
+ * probe (i.e. neither inbound our outbound).
*/
inline int NET_PROBE_OUTBOUND = 0x00;
inline int NET_PROBE_INBOUND = 0x01;
+inline int NET_PROBE_STATE = 0x02;
diff --git a/dlibs/aarch64/5.14/tcp.d b/dlibs/aarch64/5.14/tcp.d
index 54e310cb..48d9adb4 100644
--- a/dlibs/aarch64/5.14/tcp.d
+++ b/dlibs/aarch64/5.14/tcp.d
@@ -1,13 +1,13 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
#pragma D depends_on module vmlinux
#pragma D depends_on library net.d
-#pragma D depends_on provider ip
+#pragma D depends_on library ip.d
#pragma D depends_on provider tcp
inline int TH_FIN = 0x01;
@@ -111,30 +111,38 @@ translator tcpinfo_t < struct tcphdr *T > {
tcp_seq = T ? ntohl(T->seq) : 0;
tcp_ack = T ? ntohl(T->ack_seq) : 0;
tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0;
- tcp_flags = T ? *(uint8_t *)(T + 13) : 0;
+ tcp_flags = T ? *((uint8_t *)T + 13) : 0;
tcp_window = T ? ntohs(T->window) : 0;
tcp_checksum = T ? ntohs(T->check) : 0;
tcp_urgent = T ? ntohs(T->urg_ptr) : 0;
tcp_hdr = (uintptr_t)T;
};
+/* timewait sockets and inet connection sockets do not populate all fields
+ * and are not classified as full sockets; this inline helps translators
+ * spot them and act appropriately.
+ */
+inline int tcp_fullsock[struct tcp_sock *sk] =
+ (((struct sock_common *)sk)->skc_state != TCP_STATE_SYN_RECEIVED &&
+ ((struct sock_common *)sk)->skc_state != TCP_STATE_TIME_WAIT);
/*
* In the main we simply translate from the "struct [tcp_]sock *" to
* a tcpsinfo_t *. However there are a few exceptions:
*
- * - tcps_state is always derived from arg6. The reason is that in some
+ * - tcps_state for state-change is arg5. The reason is that in some
* state transitions sock->sk_state does not reflect the actual TCP
* connection state. For example the TIME_WAIT state is handled in
* Linux by creating a separate timewait socket and the state of the
* original socket is CLOSED. In some other cases we also need to
- * instrument state transition prior to the update of sk_state. To do
- * all of this we rely on arg6.
+ * instrument state transition _prior_ to the update of sk_state. To do
+ * all of this we rely on arg5 to hold the new state. arg6 is set to
+ * NET_PROBE_STATE to quickly identify state-change probes.
* - we sometimes need to retrieve local/remote port/address settings from
* TCP and IP headers directly, for example prior to the address/port
* being committed to the socket. To do this effectively we need to know
* if the packet data is inbound (in which case the local IP/port are the
* destination) or outbound (in which case the local IP/port are the source).
- * arg7 is set to 0 for outbound traffic and 1 for inbound so we use these
+ * arg6 is set to 0 for outbound traffic and 1 for inbound so we use these
* to reconstruct the address/port info where necessary. arg2 used for IP
* information while arg4 contains the TCP header, so it is used for port data.
* NET_PROBE_INBOUND is defined as 1, NET_PROBE_OUTBOUND as 0 in net.d.
@@ -158,47 +166,49 @@ translator tcpsinfo_t < struct tcp_sock *T > {
((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_daddr)[2] &&
((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr)[3])
: 0;
- tcps_lport = (T && ((struct inet_sock *)T)->inet_sport != 0) ?
+ tcps_lport = T && ((struct inet_sock *)T)->inet_sport != 0 &&
+ tcp_fullsock[T] ?
ntohs(((struct inet_sock *)T)->inet_sport) :
(T && ((struct inet_sock *)T)->inet_sport == 0) ?
- ntohs(((struct sock *)T)->__sk_common.skc_num) :
+ ((struct sock *)T)->__sk_common.skc_num :
arg4 != NULL ?
ntohs(arg7 == NET_PROBE_INBOUND ?
- ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) :
+ ((struct tcphdr *)arg4)->dest :
+ ((struct tcphdr *)arg4)->source) :
0;
tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ?
ntohs(((struct sock *)T)->__sk_common.skc_dport) :
arg4 != NULL ?
ntohs(arg7 == NET_PROBE_INBOUND ?
- ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) :
+ ((struct tcphdr *)arg4)->source :
+ ((struct tcphdr *)arg4)->dest) :
0;
tcps_laddr =
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ?
inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) :
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ?
inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) :
- arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ?
- inet_ntoa(arg7 == NET_PROBE_INBOUND ?
- &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) :
- arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ?
- inet_ntoa6(arg7 == NET_PROBE_INBOUND ?
- &((struct ipv6hdr *)arg2)->daddr :
- &((struct ipv6hdr *)arg2)->saddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ?
+ inet_ntoa(&((struct iphdr *)arg2)->daddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ?
+ inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) :
"<unknown>";
tcps_raddr =
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ?
inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) :
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ?
inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) :
- arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ?
- inet_ntoa(arg7 == NET_PROBE_INBOUND ?
- &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) :
- arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ?
- inet_ntoa6(arg7 == NET_PROBE_INBOUND ?
- &((struct ipv6hdr *)arg2)->saddr :
- &((struct ipv6hdr *)arg2)->daddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ?
+ inet_ntoa(&((struct iphdr *)arg2)->saddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ?
+ inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) :
"<unknown>";
- tcps_state = arg6;
+ /* For state-change we probe right before state has changed, but
+ * provider definition wants new state in tcps_state; for
+ * state-change probes the trampoline stores it in arg5.
+ */
+ tcps_state = arg6 == NET_PROBE_STATE ? arg5 :
+ T ? ((struct sock *)T)->__sk_common.skc_state : 0;
tcps_iss = T ?
T->snd_una - (uint32_t)T->bytes_acked : 0;
tcps_suna = T ? T->snd_una : 0;
@@ -225,7 +235,10 @@ translator tcpsinfo_t < struct tcp_sock *T > {
T->rcv_nxt - (uint32_t)T->bytes_received : 0;
};
+/* state-change trampoline stores new state in arg5; at time of firing,
+ * state has not been updated, so last state is in tcp_sock state.
+ */
#pragma D binding "1.6.3" translator
translator tcplsinfo_t < int I > {
- tcps_state = I;
+ tcps_state = arg3 ? ((struct sock *)arg3)->__sk_common.skc_state : 0;
};
diff --git a/dlibs/aarch64/5.16/ip.d b/dlibs/aarch64/5.16/ip.d
index f8b77f12..493b75a0 100644
--- a/dlibs/aarch64/5.16/ip.d
+++ b/dlibs/aarch64/5.16/ip.d
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -46,31 +46,6 @@ inline int IPPROTO_MH = 135;
inline int TCP_MIN_HEADER_LENGTH = 20;
-/*
- * For compatibility with Solaris. Here the netstackid will be the pointer
- * to the net namespace (nd_net in struct net_device).
- */
-typedef uint64_t netstackid_t;
-typedef __be32 ipaddr_t;
-typedef struct in6_addr in6_addr_t;
-
-/*
- * pktinfo is where packet ID info can be made available for deeper
- * analysis if packet IDs become supported by the kernel in the future.
- * The pkt_addr member is currently always NULL.
- */
-typedef struct pktinfo {
- uintptr_t pkt_addr;
-} pktinfo_t;
-
-/*
- * csinfo is where connection state info is made available.
- */
-typedef struct csinfo {
- uintptr_t cs_addr;
- uint64_t cs_cid;
-} csinfo_t;
-
/*
* ipinfo contains common IP info for both IPv4 and IPv6.
*/
diff --git a/dlibs/aarch64/5.16/net.d b/dlibs/aarch64/5.16/net.d
index 6ac34287..f1291696 100644
--- a/dlibs/aarch64/5.16/net.d
+++ b/dlibs/aarch64/5.16/net.d
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -25,9 +25,36 @@ typedef struct conninfo {
string ci_protocol; /* protocol (ipv4, ipv6, etc) */
} conninfo_t;
+/*
+ * For compatibility with Solaris. Here the netstackid will be the pointer
+ * to the net namespace (nd_net in struct net_device).
+ */
+typedef uint64_t netstackid_t;
+typedef __be32 ipaddr_t;
+typedef struct in6_addr in6_addr_t;
+
+/*
+ * pktinfo is where packet ID info can be made available for deeper
+ * analysis if packet IDs become supported by the kernel in the future.
+ * The pkt_addr member is currently always NULL.
+ */
+typedef struct pktinfo {
+ uintptr_t pkt_addr;
+} pktinfo_t;
+
+/*
+ * csinfo is where connection state info is made available.
+ */
+typedef struct csinfo {
+ uintptr_t cs_addr;
+ uint64_t cs_cid;
+} csinfo_t;
+
/*
* We use these values to determine if a probe point is associated
- * with sending (outbound) or receiving (inbound).
+ * with sending (outbound) or receiving (inbound) or a state-related
+ * probe (i.e. neither inbound our outbound).
*/
inline int NET_PROBE_OUTBOUND = 0x00;
inline int NET_PROBE_INBOUND = 0x01;
+inline int NET_PROBE_STATE = 0x02;
diff --git a/dlibs/aarch64/5.16/tcp.d b/dlibs/aarch64/5.16/tcp.d
index 54e310cb..48d9adb4 100644
--- a/dlibs/aarch64/5.16/tcp.d
+++ b/dlibs/aarch64/5.16/tcp.d
@@ -1,13 +1,13 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
#pragma D depends_on module vmlinux
#pragma D depends_on library net.d
-#pragma D depends_on provider ip
+#pragma D depends_on library ip.d
#pragma D depends_on provider tcp
inline int TH_FIN = 0x01;
@@ -111,30 +111,38 @@ translator tcpinfo_t < struct tcphdr *T > {
tcp_seq = T ? ntohl(T->seq) : 0;
tcp_ack = T ? ntohl(T->ack_seq) : 0;
tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0;
- tcp_flags = T ? *(uint8_t *)(T + 13) : 0;
+ tcp_flags = T ? *((uint8_t *)T + 13) : 0;
tcp_window = T ? ntohs(T->window) : 0;
tcp_checksum = T ? ntohs(T->check) : 0;
tcp_urgent = T ? ntohs(T->urg_ptr) : 0;
tcp_hdr = (uintptr_t)T;
};
+/* timewait sockets and inet connection sockets do not populate all fields
+ * and are not classified as full sockets; this inline helps translators
+ * spot them and act appropriately.
+ */
+inline int tcp_fullsock[struct tcp_sock *sk] =
+ (((struct sock_common *)sk)->skc_state != TCP_STATE_SYN_RECEIVED &&
+ ((struct sock_common *)sk)->skc_state != TCP_STATE_TIME_WAIT);
/*
* In the main we simply translate from the "struct [tcp_]sock *" to
* a tcpsinfo_t *. However there are a few exceptions:
*
- * - tcps_state is always derived from arg6. The reason is that in some
+ * - tcps_state for state-change is arg5. The reason is that in some
* state transitions sock->sk_state does not reflect the actual TCP
* connection state. For example the TIME_WAIT state is handled in
* Linux by creating a separate timewait socket and the state of the
* original socket is CLOSED. In some other cases we also need to
- * instrument state transition prior to the update of sk_state. To do
- * all of this we rely on arg6.
+ * instrument state transition _prior_ to the update of sk_state. To do
+ * all of this we rely on arg5 to hold the new state. arg6 is set to
+ * NET_PROBE_STATE to quickly identify state-change probes.
* - we sometimes need to retrieve local/remote port/address settings from
* TCP and IP headers directly, for example prior to the address/port
* being committed to the socket. To do this effectively we need to know
* if the packet data is inbound (in which case the local IP/port are the
* destination) or outbound (in which case the local IP/port are the source).
- * arg7 is set to 0 for outbound traffic and 1 for inbound so we use these
+ * arg6 is set to 0 for outbound traffic and 1 for inbound so we use these
* to reconstruct the address/port info where necessary. arg2 used for IP
* information while arg4 contains the TCP header, so it is used for port data.
* NET_PROBE_INBOUND is defined as 1, NET_PROBE_OUTBOUND as 0 in net.d.
@@ -158,47 +166,49 @@ translator tcpsinfo_t < struct tcp_sock *T > {
((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_daddr)[2] &&
((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr)[3])
: 0;
- tcps_lport = (T && ((struct inet_sock *)T)->inet_sport != 0) ?
+ tcps_lport = T && ((struct inet_sock *)T)->inet_sport != 0 &&
+ tcp_fullsock[T] ?
ntohs(((struct inet_sock *)T)->inet_sport) :
(T && ((struct inet_sock *)T)->inet_sport == 0) ?
- ntohs(((struct sock *)T)->__sk_common.skc_num) :
+ ((struct sock *)T)->__sk_common.skc_num :
arg4 != NULL ?
ntohs(arg7 == NET_PROBE_INBOUND ?
- ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) :
+ ((struct tcphdr *)arg4)->dest :
+ ((struct tcphdr *)arg4)->source) :
0;
tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ?
ntohs(((struct sock *)T)->__sk_common.skc_dport) :
arg4 != NULL ?
ntohs(arg7 == NET_PROBE_INBOUND ?
- ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) :
+ ((struct tcphdr *)arg4)->source :
+ ((struct tcphdr *)arg4)->dest) :
0;
tcps_laddr =
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ?
inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) :
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ?
inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) :
- arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ?
- inet_ntoa(arg7 == NET_PROBE_INBOUND ?
- &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) :
- arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ?
- inet_ntoa6(arg7 == NET_PROBE_INBOUND ?
- &((struct ipv6hdr *)arg2)->daddr :
- &((struct ipv6hdr *)arg2)->saddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ?
+ inet_ntoa(&((struct iphdr *)arg2)->daddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ?
+ inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) :
"<unknown>";
tcps_raddr =
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ?
inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) :
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ?
inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) :
- arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ?
- inet_ntoa(arg7 == NET_PROBE_INBOUND ?
- &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) :
- arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ?
- inet_ntoa6(arg7 == NET_PROBE_INBOUND ?
- &((struct ipv6hdr *)arg2)->saddr :
- &((struct ipv6hdr *)arg2)->daddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ?
+ inet_ntoa(&((struct iphdr *)arg2)->saddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ?
+ inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) :
"<unknown>";
- tcps_state = arg6;
+ /* For state-change we probe right before state has changed, but
+ * provider definition wants new state in tcps_state; for
+ * state-change probes the trampoline stores it in arg5.
+ */
+ tcps_state = arg6 == NET_PROBE_STATE ? arg5 :
+ T ? ((struct sock *)T)->__sk_common.skc_state : 0;
tcps_iss = T ?
T->snd_una - (uint32_t)T->bytes_acked : 0;
tcps_suna = T ? T->snd_una : 0;
@@ -225,7 +235,10 @@ translator tcpsinfo_t < struct tcp_sock *T > {
T->rcv_nxt - (uint32_t)T->bytes_received : 0;
};
+/* state-change trampoline stores new state in arg5; at time of firing,
+ * state has not been updated, so last state is in tcp_sock state.
+ */
#pragma D binding "1.6.3" translator
translator tcplsinfo_t < int I > {
- tcps_state = I;
+ tcps_state = arg3 ? ((struct sock *)arg3)->__sk_common.skc_state : 0;
};
diff --git a/dlibs/aarch64/5.2/ip.d b/dlibs/aarch64/5.2/ip.d
index f8b77f12..493b75a0 100644
--- a/dlibs/aarch64/5.2/ip.d
+++ b/dlibs/aarch64/5.2/ip.d
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -46,31 +46,6 @@ inline int IPPROTO_MH = 135;
inline int TCP_MIN_HEADER_LENGTH = 20;
-/*
- * For compatibility with Solaris. Here the netstackid will be the pointer
- * to the net namespace (nd_net in struct net_device).
- */
-typedef uint64_t netstackid_t;
-typedef __be32 ipaddr_t;
-typedef struct in6_addr in6_addr_t;
-
-/*
- * pktinfo is where packet ID info can be made available for deeper
- * analysis if packet IDs become supported by the kernel in the future.
- * The pkt_addr member is currently always NULL.
- */
-typedef struct pktinfo {
- uintptr_t pkt_addr;
-} pktinfo_t;
-
-/*
- * csinfo is where connection state info is made available.
- */
-typedef struct csinfo {
- uintptr_t cs_addr;
- uint64_t cs_cid;
-} csinfo_t;
-
/*
* ipinfo contains common IP info for both IPv4 and IPv6.
*/
diff --git a/dlibs/aarch64/5.2/net.d b/dlibs/aarch64/5.2/net.d
index 6ac34287..f1291696 100644
--- a/dlibs/aarch64/5.2/net.d
+++ b/dlibs/aarch64/5.2/net.d
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -25,9 +25,36 @@ typedef struct conninfo {
string ci_protocol; /* protocol (ipv4, ipv6, etc) */
} conninfo_t;
+/*
+ * For compatibility with Solaris. Here the netstackid will be the pointer
+ * to the net namespace (nd_net in struct net_device).
+ */
+typedef uint64_t netstackid_t;
+typedef __be32 ipaddr_t;
+typedef struct in6_addr in6_addr_t;
+
+/*
+ * pktinfo is where packet ID info can be made available for deeper
+ * analysis if packet IDs become supported by the kernel in the future.
+ * The pkt_addr member is currently always NULL.
+ */
+typedef struct pktinfo {
+ uintptr_t pkt_addr;
+} pktinfo_t;
+
+/*
+ * csinfo is where connection state info is made available.
+ */
+typedef struct csinfo {
+ uintptr_t cs_addr;
+ uint64_t cs_cid;
+} csinfo_t;
+
/*
* We use these values to determine if a probe point is associated
- * with sending (outbound) or receiving (inbound).
+ * with sending (outbound) or receiving (inbound) or a state-related
+ * probe (i.e. neither inbound our outbound).
*/
inline int NET_PROBE_OUTBOUND = 0x00;
inline int NET_PROBE_INBOUND = 0x01;
+inline int NET_PROBE_STATE = 0x02;
diff --git a/dlibs/aarch64/5.2/tcp.d b/dlibs/aarch64/5.2/tcp.d
index 54e310cb..48d9adb4 100644
--- a/dlibs/aarch64/5.2/tcp.d
+++ b/dlibs/aarch64/5.2/tcp.d
@@ -1,13 +1,13 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
#pragma D depends_on module vmlinux
#pragma D depends_on library net.d
-#pragma D depends_on provider ip
+#pragma D depends_on library ip.d
#pragma D depends_on provider tcp
inline int TH_FIN = 0x01;
@@ -111,30 +111,38 @@ translator tcpinfo_t < struct tcphdr *T > {
tcp_seq = T ? ntohl(T->seq) : 0;
tcp_ack = T ? ntohl(T->ack_seq) : 0;
tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0;
- tcp_flags = T ? *(uint8_t *)(T + 13) : 0;
+ tcp_flags = T ? *((uint8_t *)T + 13) : 0;
tcp_window = T ? ntohs(T->window) : 0;
tcp_checksum = T ? ntohs(T->check) : 0;
tcp_urgent = T ? ntohs(T->urg_ptr) : 0;
tcp_hdr = (uintptr_t)T;
};
+/* timewait sockets and inet connection sockets do not populate all fields
+ * and are not classified as full sockets; this inline helps translators
+ * spot them and act appropriately.
+ */
+inline int tcp_fullsock[struct tcp_sock *sk] =
+ (((struct sock_common *)sk)->skc_state != TCP_STATE_SYN_RECEIVED &&
+ ((struct sock_common *)sk)->skc_state != TCP_STATE_TIME_WAIT);
/*
* In the main we simply translate from the "struct [tcp_]sock *" to
* a tcpsinfo_t *. However there are a few exceptions:
*
- * - tcps_state is always derived from arg6. The reason is that in some
+ * - tcps_state for state-change is arg5. The reason is that in some
* state transitions sock->sk_state does not reflect the actual TCP
* connection state. For example the TIME_WAIT state is handled in
* Linux by creating a separate timewait socket and the state of the
* original socket is CLOSED. In some other cases we also need to
- * instrument state transition prior to the update of sk_state. To do
- * all of this we rely on arg6.
+ * instrument state transition _prior_ to the update of sk_state. To do
+ * all of this we rely on arg5 to hold the new state. arg6 is set to
+ * NET_PROBE_STATE to quickly identify state-change probes.
* - we sometimes need to retrieve local/remote port/address settings from
* TCP and IP headers directly, for example prior to the address/port
* being committed to the socket. To do this effectively we need to know
* if the packet data is inbound (in which case the local IP/port are the
* destination) or outbound (in which case the local IP/port are the source).
- * arg7 is set to 0 for outbound traffic and 1 for inbound so we use these
+ * arg6 is set to 0 for outbound traffic and 1 for inbound so we use these
* to reconstruct the address/port info where necessary. arg2 used for IP
* information while arg4 contains the TCP header, so it is used for port data.
* NET_PROBE_INBOUND is defined as 1, NET_PROBE_OUTBOUND as 0 in net.d.
@@ -158,47 +166,49 @@ translator tcpsinfo_t < struct tcp_sock *T > {
((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_daddr)[2] &&
((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr)[3])
: 0;
- tcps_lport = (T && ((struct inet_sock *)T)->inet_sport != 0) ?
+ tcps_lport = T && ((struct inet_sock *)T)->inet_sport != 0 &&
+ tcp_fullsock[T] ?
ntohs(((struct inet_sock *)T)->inet_sport) :
(T && ((struct inet_sock *)T)->inet_sport == 0) ?
- ntohs(((struct sock *)T)->__sk_common.skc_num) :
+ ((struct sock *)T)->__sk_common.skc_num :
arg4 != NULL ?
ntohs(arg7 == NET_PROBE_INBOUND ?
- ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) :
+ ((struct tcphdr *)arg4)->dest :
+ ((struct tcphdr *)arg4)->source) :
0;
tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ?
ntohs(((struct sock *)T)->__sk_common.skc_dport) :
arg4 != NULL ?
ntohs(arg7 == NET_PROBE_INBOUND ?
- ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) :
+ ((struct tcphdr *)arg4)->source :
+ ((struct tcphdr *)arg4)->dest) :
0;
tcps_laddr =
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ?
inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) :
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ?
inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) :
- arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ?
- inet_ntoa(arg7 == NET_PROBE_INBOUND ?
- &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) :
- arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ?
- inet_ntoa6(arg7 == NET_PROBE_INBOUND ?
- &((struct ipv6hdr *)arg2)->daddr :
- &((struct ipv6hdr *)arg2)->saddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ?
+ inet_ntoa(&((struct iphdr *)arg2)->daddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ?
+ inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) :
"<unknown>";
tcps_raddr =
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ?
inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) :
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ?
inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) :
- arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ?
- inet_ntoa(arg7 == NET_PROBE_INBOUND ?
- &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) :
- arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ?
- inet_ntoa6(arg7 == NET_PROBE_INBOUND ?
- &((struct ipv6hdr *)arg2)->saddr :
- &((struct ipv6hdr *)arg2)->daddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ?
+ inet_ntoa(&((struct iphdr *)arg2)->saddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ?
+ inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) :
"<unknown>";
- tcps_state = arg6;
+ /* For state-change we probe right before state has changed, but
+ * provider definition wants new state in tcps_state; for
+ * state-change probes the trampoline stores it in arg5.
+ */
+ tcps_state = arg6 == NET_PROBE_STATE ? arg5 :
+ T ? ((struct sock *)T)->__sk_common.skc_state : 0;
tcps_iss = T ?
T->snd_una - (uint32_t)T->bytes_acked : 0;
tcps_suna = T ? T->snd_una : 0;
@@ -225,7 +235,10 @@ translator tcpsinfo_t < struct tcp_sock *T > {
T->rcv_nxt - (uint32_t)T->bytes_received : 0;
};
+/* state-change trampoline stores new state in arg5; at time of firing,
+ * state has not been updated, so last state is in tcp_sock state.
+ */
#pragma D binding "1.6.3" translator
translator tcplsinfo_t < int I > {
- tcps_state = I;
+ tcps_state = arg3 ? ((struct sock *)arg3)->__sk_common.skc_state : 0;
};
diff --git a/dlibs/aarch64/5.6/ip.d b/dlibs/aarch64/5.6/ip.d
index f8b77f12..493b75a0 100644
--- a/dlibs/aarch64/5.6/ip.d
+++ b/dlibs/aarch64/5.6/ip.d
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -46,31 +46,6 @@ inline int IPPROTO_MH = 135;
inline int TCP_MIN_HEADER_LENGTH = 20;
-/*
- * For compatibility with Solaris. Here the netstackid will be the pointer
- * to the net namespace (nd_net in struct net_device).
- */
-typedef uint64_t netstackid_t;
-typedef __be32 ipaddr_t;
-typedef struct in6_addr in6_addr_t;
-
-/*
- * pktinfo is where packet ID info can be made available for deeper
- * analysis if packet IDs become supported by the kernel in the future.
- * The pkt_addr member is currently always NULL.
- */
-typedef struct pktinfo {
- uintptr_t pkt_addr;
-} pktinfo_t;
-
-/*
- * csinfo is where connection state info is made available.
- */
-typedef struct csinfo {
- uintptr_t cs_addr;
- uint64_t cs_cid;
-} csinfo_t;
-
/*
* ipinfo contains common IP info for both IPv4 and IPv6.
*/
diff --git a/dlibs/aarch64/5.6/net.d b/dlibs/aarch64/5.6/net.d
index 6ac34287..f1291696 100644
--- a/dlibs/aarch64/5.6/net.d
+++ b/dlibs/aarch64/5.6/net.d
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -25,9 +25,36 @@ typedef struct conninfo {
string ci_protocol; /* protocol (ipv4, ipv6, etc) */
} conninfo_t;
+/*
+ * For compatibility with Solaris. Here the netstackid will be the pointer
+ * to the net namespace (nd_net in struct net_device).
+ */
+typedef uint64_t netstackid_t;
+typedef __be32 ipaddr_t;
+typedef struct in6_addr in6_addr_t;
+
+/*
+ * pktinfo is where packet ID info can be made available for deeper
+ * analysis if packet IDs become supported by the kernel in the future.
+ * The pkt_addr member is currently always NULL.
+ */
+typedef struct pktinfo {
+ uintptr_t pkt_addr;
+} pktinfo_t;
+
+/*
+ * csinfo is where connection state info is made available.
+ */
+typedef struct csinfo {
+ uintptr_t cs_addr;
+ uint64_t cs_cid;
+} csinfo_t;
+
/*
* We use these values to determine if a probe point is associated
- * with sending (outbound) or receiving (inbound).
+ * with sending (outbound) or receiving (inbound) or a state-related
+ * probe (i.e. neither inbound our outbound).
*/
inline int NET_PROBE_OUTBOUND = 0x00;
inline int NET_PROBE_INBOUND = 0x01;
+inline int NET_PROBE_STATE = 0x02;
diff --git a/dlibs/aarch64/5.6/tcp.d b/dlibs/aarch64/5.6/tcp.d
index 54e310cb..48d9adb4 100644
--- a/dlibs/aarch64/5.6/tcp.d
+++ b/dlibs/aarch64/5.6/tcp.d
@@ -1,13 +1,13 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
#pragma D depends_on module vmlinux
#pragma D depends_on library net.d
-#pragma D depends_on provider ip
+#pragma D depends_on library ip.d
#pragma D depends_on provider tcp
inline int TH_FIN = 0x01;
@@ -111,30 +111,38 @@ translator tcpinfo_t < struct tcphdr *T > {
tcp_seq = T ? ntohl(T->seq) : 0;
tcp_ack = T ? ntohl(T->ack_seq) : 0;
tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0;
- tcp_flags = T ? *(uint8_t *)(T + 13) : 0;
+ tcp_flags = T ? *((uint8_t *)T + 13) : 0;
tcp_window = T ? ntohs(T->window) : 0;
tcp_checksum = T ? ntohs(T->check) : 0;
tcp_urgent = T ? ntohs(T->urg_ptr) : 0;
tcp_hdr = (uintptr_t)T;
};
+/* timewait sockets and inet connection sockets do not populate all fields
+ * and are not classified as full sockets; this inline helps translators
+ * spot them and act appropriately.
+ */
+inline int tcp_fullsock[struct tcp_sock *sk] =
+ (((struct sock_common *)sk)->skc_state != TCP_STATE_SYN_RECEIVED &&
+ ((struct sock_common *)sk)->skc_state != TCP_STATE_TIME_WAIT);
/*
* In the main we simply translate from the "struct [tcp_]sock *" to
* a tcpsinfo_t *. However there are a few exceptions:
*
- * - tcps_state is always derived from arg6. The reason is that in some
+ * - tcps_state for state-change is arg5. The reason is that in some
* state transitions sock->sk_state does not reflect the actual TCP
* connection state. For example the TIME_WAIT state is handled in
* Linux by creating a separate timewait socket and the state of the
* original socket is CLOSED. In some other cases we also need to
- * instrument state transition prior to the update of sk_state. To do
- * all of this we rely on arg6.
+ * instrument state transition _prior_ to the update of sk_state. To do
+ * all of this we rely on arg5 to hold the new state. arg6 is set to
+ * NET_PROBE_STATE to quickly identify state-change probes.
* - we sometimes need to retrieve local/remote port/address settings from
* TCP and IP headers directly, for example prior to the address/port
* being committed to the socket. To do this effectively we need to know
* if the packet data is inbound (in which case the local IP/port are the
* destination) or outbound (in which case the local IP/port are the source).
- * arg7 is set to 0 for outbound traffic and 1 for inbound so we use these
+ * arg6 is set to 0 for outbound traffic and 1 for inbound so we use these
* to reconstruct the address/port info where necessary. arg2 used for IP
* information while arg4 contains the TCP header, so it is used for port data.
* NET_PROBE_INBOUND is defined as 1, NET_PROBE_OUTBOUND as 0 in net.d.
@@ -158,47 +166,49 @@ translator tcpsinfo_t < struct tcp_sock *T > {
((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_daddr)[2] &&
((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr)[3])
: 0;
- tcps_lport = (T && ((struct inet_sock *)T)->inet_sport != 0) ?
+ tcps_lport = T && ((struct inet_sock *)T)->inet_sport != 0 &&
+ tcp_fullsock[T] ?
ntohs(((struct inet_sock *)T)->inet_sport) :
(T && ((struct inet_sock *)T)->inet_sport == 0) ?
- ntohs(((struct sock *)T)->__sk_common.skc_num) :
+ ((struct sock *)T)->__sk_common.skc_num :
arg4 != NULL ?
ntohs(arg7 == NET_PROBE_INBOUND ?
- ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) :
+ ((struct tcphdr *)arg4)->dest :
+ ((struct tcphdr *)arg4)->source) :
0;
tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ?
ntohs(((struct sock *)T)->__sk_common.skc_dport) :
arg4 != NULL ?
ntohs(arg7 == NET_PROBE_INBOUND ?
- ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) :
+ ((struct tcphdr *)arg4)->source :
+ ((struct tcphdr *)arg4)->dest) :
0;
tcps_laddr =
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ?
inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) :
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ?
inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) :
- arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ?
- inet_ntoa(arg7 == NET_PROBE_INBOUND ?
- &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) :
- arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ?
- inet_ntoa6(arg7 == NET_PROBE_INBOUND ?
- &((struct ipv6hdr *)arg2)->daddr :
- &((struct ipv6hdr *)arg2)->saddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ?
+ inet_ntoa(&((struct iphdr *)arg2)->daddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ?
+ inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) :
"<unknown>";
tcps_raddr =
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ?
inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) :
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ?
inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) :
- arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ?
- inet_ntoa(arg7 == NET_PROBE_INBOUND ?
- &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) :
- arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ?
- inet_ntoa6(arg7 == NET_PROBE_INBOUND ?
- &((struct ipv6hdr *)arg2)->saddr :
- &((struct ipv6hdr *)arg2)->daddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ?
+ inet_ntoa(&((struct iphdr *)arg2)->saddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ?
+ inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) :
"<unknown>";
- tcps_state = arg6;
+ /* For state-change we probe right before state has changed, but
+ * provider definition wants new state in tcps_state; for
+ * state-change probes the trampoline stores it in arg5.
+ */
+ tcps_state = arg6 == NET_PROBE_STATE ? arg5 :
+ T ? ((struct sock *)T)->__sk_common.skc_state : 0;
tcps_iss = T ?
T->snd_una - (uint32_t)T->bytes_acked : 0;
tcps_suna = T ? T->snd_una : 0;
@@ -225,7 +235,10 @@ translator tcpsinfo_t < struct tcp_sock *T > {
T->rcv_nxt - (uint32_t)T->bytes_received : 0;
};
+/* state-change trampoline stores new state in arg5; at time of firing,
+ * state has not been updated, so last state is in tcp_sock state.
+ */
#pragma D binding "1.6.3" translator
translator tcplsinfo_t < int I > {
- tcps_state = I;
+ tcps_state = arg3 ? ((struct sock *)arg3)->__sk_common.skc_state : 0;
};
diff --git a/dlibs/aarch64/6.1/ip.d b/dlibs/aarch64/6.1/ip.d
index f8b77f12..493b75a0 100644
--- a/dlibs/aarch64/6.1/ip.d
+++ b/dlibs/aarch64/6.1/ip.d
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -46,31 +46,6 @@ inline int IPPROTO_MH = 135;
inline int TCP_MIN_HEADER_LENGTH = 20;
-/*
- * For compatibility with Solaris. Here the netstackid will be the pointer
- * to the net namespace (nd_net in struct net_device).
- */
-typedef uint64_t netstackid_t;
-typedef __be32 ipaddr_t;
-typedef struct in6_addr in6_addr_t;
-
-/*
- * pktinfo is where packet ID info can be made available for deeper
- * analysis if packet IDs become supported by the kernel in the future.
- * The pkt_addr member is currently always NULL.
- */
-typedef struct pktinfo {
- uintptr_t pkt_addr;
-} pktinfo_t;
-
-/*
- * csinfo is where connection state info is made available.
- */
-typedef struct csinfo {
- uintptr_t cs_addr;
- uint64_t cs_cid;
-} csinfo_t;
-
/*
* ipinfo contains common IP info for both IPv4 and IPv6.
*/
diff --git a/dlibs/aarch64/6.1/net.d b/dlibs/aarch64/6.1/net.d
index 6ac34287..f1291696 100644
--- a/dlibs/aarch64/6.1/net.d
+++ b/dlibs/aarch64/6.1/net.d
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -25,9 +25,36 @@ typedef struct conninfo {
string ci_protocol; /* protocol (ipv4, ipv6, etc) */
} conninfo_t;
+/*
+ * For compatibility with Solaris. Here the netstackid will be the pointer
+ * to the net namespace (nd_net in struct net_device).
+ */
+typedef uint64_t netstackid_t;
+typedef __be32 ipaddr_t;
+typedef struct in6_addr in6_addr_t;
+
+/*
+ * pktinfo is where packet ID info can be made available for deeper
+ * analysis if packet IDs become supported by the kernel in the future.
+ * The pkt_addr member is currently always NULL.
+ */
+typedef struct pktinfo {
+ uintptr_t pkt_addr;
+} pktinfo_t;
+
+/*
+ * csinfo is where connection state info is made available.
+ */
+typedef struct csinfo {
+ uintptr_t cs_addr;
+ uint64_t cs_cid;
+} csinfo_t;
+
/*
* We use these values to determine if a probe point is associated
- * with sending (outbound) or receiving (inbound).
+ * with sending (outbound) or receiving (inbound) or a state-related
+ * probe (i.e. neither inbound our outbound).
*/
inline int NET_PROBE_OUTBOUND = 0x00;
inline int NET_PROBE_INBOUND = 0x01;
+inline int NET_PROBE_STATE = 0x02;
diff --git a/dlibs/aarch64/6.1/tcp.d b/dlibs/aarch64/6.1/tcp.d
index 54e310cb..48d9adb4 100644
--- a/dlibs/aarch64/6.1/tcp.d
+++ b/dlibs/aarch64/6.1/tcp.d
@@ -1,13 +1,13 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
#pragma D depends_on module vmlinux
#pragma D depends_on library net.d
-#pragma D depends_on provider ip
+#pragma D depends_on library ip.d
#pragma D depends_on provider tcp
inline int TH_FIN = 0x01;
@@ -111,30 +111,38 @@ translator tcpinfo_t < struct tcphdr *T > {
tcp_seq = T ? ntohl(T->seq) : 0;
tcp_ack = T ? ntohl(T->ack_seq) : 0;
tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0;
- tcp_flags = T ? *(uint8_t *)(T + 13) : 0;
+ tcp_flags = T ? *((uint8_t *)T + 13) : 0;
tcp_window = T ? ntohs(T->window) : 0;
tcp_checksum = T ? ntohs(T->check) : 0;
tcp_urgent = T ? ntohs(T->urg_ptr) : 0;
tcp_hdr = (uintptr_t)T;
};
+/* timewait sockets and inet connection sockets do not populate all fields
+ * and are not classified as full sockets; this inline helps translators
+ * spot them and act appropriately.
+ */
+inline int tcp_fullsock[struct tcp_sock *sk] =
+ (((struct sock_common *)sk)->skc_state != TCP_STATE_SYN_RECEIVED &&
+ ((struct sock_common *)sk)->skc_state != TCP_STATE_TIME_WAIT);
/*
* In the main we simply translate from the "struct [tcp_]sock *" to
* a tcpsinfo_t *. However there are a few exceptions:
*
- * - tcps_state is always derived from arg6. The reason is that in some
+ * - tcps_state for state-change is arg5. The reason is that in some
* state transitions sock->sk_state does not reflect the actual TCP
* connection state. For example the TIME_WAIT state is handled in
* Linux by creating a separate timewait socket and the state of the
* original socket is CLOSED. In some other cases we also need to
- * instrument state transition prior to the update of sk_state. To do
- * all of this we rely on arg6.
+ * instrument state transition _prior_ to the update of sk_state. To do
+ * all of this we rely on arg5 to hold the new state. arg6 is set to
+ * NET_PROBE_STATE to quickly identify state-change probes.
* - we sometimes need to retrieve local/remote port/address settings from
* TCP and IP headers directly, for example prior to the address/port
* being committed to the socket. To do this effectively we need to know
* if the packet data is inbound (in which case the local IP/port are the
* destination) or outbound (in which case the local IP/port are the source).
- * arg7 is set to 0 for outbound traffic and 1 for inbound so we use these
+ * arg6 is set to 0 for outbound traffic and 1 for inbound so we use these
* to reconstruct the address/port info where necessary. arg2 used for IP
* information while arg4 contains the TCP header, so it is used for port data.
* NET_PROBE_INBOUND is defined as 1, NET_PROBE_OUTBOUND as 0 in net.d.
@@ -158,47 +166,49 @@ translator tcpsinfo_t < struct tcp_sock *T > {
((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_daddr)[2] &&
((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr)[3])
: 0;
- tcps_lport = (T && ((struct inet_sock *)T)->inet_sport != 0) ?
+ tcps_lport = T && ((struct inet_sock *)T)->inet_sport != 0 &&
+ tcp_fullsock[T] ?
ntohs(((struct inet_sock *)T)->inet_sport) :
(T && ((struct inet_sock *)T)->inet_sport == 0) ?
- ntohs(((struct sock *)T)->__sk_common.skc_num) :
+ ((struct sock *)T)->__sk_common.skc_num :
arg4 != NULL ?
ntohs(arg7 == NET_PROBE_INBOUND ?
- ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) :
+ ((struct tcphdr *)arg4)->dest :
+ ((struct tcphdr *)arg4)->source) :
0;
tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ?
ntohs(((struct sock *)T)->__sk_common.skc_dport) :
arg4 != NULL ?
ntohs(arg7 == NET_PROBE_INBOUND ?
- ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) :
+ ((struct tcphdr *)arg4)->source :
+ ((struct tcphdr *)arg4)->dest) :
0;
tcps_laddr =
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ?
inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) :
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ?
inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) :
- arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ?
- inet_ntoa(arg7 == NET_PROBE_INBOUND ?
- &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) :
- arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ?
- inet_ntoa6(arg7 == NET_PROBE_INBOUND ?
- &((struct ipv6hdr *)arg2)->daddr :
- &((struct ipv6hdr *)arg2)->saddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ?
+ inet_ntoa(&((struct iphdr *)arg2)->daddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ?
+ inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) :
"<unknown>";
tcps_raddr =
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ?
inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) :
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ?
inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) :
- arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ?
- inet_ntoa(arg7 == NET_PROBE_INBOUND ?
- &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) :
- arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ?
- inet_ntoa6(arg7 == NET_PROBE_INBOUND ?
- &((struct ipv6hdr *)arg2)->saddr :
- &((struct ipv6hdr *)arg2)->daddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ?
+ inet_ntoa(&((struct iphdr *)arg2)->saddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ?
+ inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) :
"<unknown>";
- tcps_state = arg6;
+ /* For state-change we probe right before state has changed, but
+ * provider definition wants new state in tcps_state; for
+ * state-change probes the trampoline stores it in arg5.
+ */
+ tcps_state = arg6 == NET_PROBE_STATE ? arg5 :
+ T ? ((struct sock *)T)->__sk_common.skc_state : 0;
tcps_iss = T ?
T->snd_una - (uint32_t)T->bytes_acked : 0;
tcps_suna = T ? T->snd_una : 0;
@@ -225,7 +235,10 @@ translator tcpsinfo_t < struct tcp_sock *T > {
T->rcv_nxt - (uint32_t)T->bytes_received : 0;
};
+/* state-change trampoline stores new state in arg5; at time of firing,
+ * state has not been updated, so last state is in tcp_sock state.
+ */
#pragma D binding "1.6.3" translator
translator tcplsinfo_t < int I > {
- tcps_state = I;
+ tcps_state = arg3 ? ((struct sock *)arg3)->__sk_common.skc_state : 0;
};
diff --git a/dlibs/aarch64/6.10/ip.d b/dlibs/aarch64/6.10/ip.d
index f8b77f12..493b75a0 100644
--- a/dlibs/aarch64/6.10/ip.d
+++ b/dlibs/aarch64/6.10/ip.d
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -46,31 +46,6 @@ inline int IPPROTO_MH = 135;
inline int TCP_MIN_HEADER_LENGTH = 20;
-/*
- * For compatibility with Solaris. Here the netstackid will be the pointer
- * to the net namespace (nd_net in struct net_device).
- */
-typedef uint64_t netstackid_t;
-typedef __be32 ipaddr_t;
-typedef struct in6_addr in6_addr_t;
-
-/*
- * pktinfo is where packet ID info can be made available for deeper
- * analysis if packet IDs become supported by the kernel in the future.
- * The pkt_addr member is currently always NULL.
- */
-typedef struct pktinfo {
- uintptr_t pkt_addr;
-} pktinfo_t;
-
-/*
- * csinfo is where connection state info is made available.
- */
-typedef struct csinfo {
- uintptr_t cs_addr;
- uint64_t cs_cid;
-} csinfo_t;
-
/*
* ipinfo contains common IP info for both IPv4 and IPv6.
*/
diff --git a/dlibs/aarch64/6.10/net.d b/dlibs/aarch64/6.10/net.d
index 6ac34287..f1291696 100644
--- a/dlibs/aarch64/6.10/net.d
+++ b/dlibs/aarch64/6.10/net.d
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -25,9 +25,36 @@ typedef struct conninfo {
string ci_protocol; /* protocol (ipv4, ipv6, etc) */
} conninfo_t;
+/*
+ * For compatibility with Solaris. Here the netstackid will be the pointer
+ * to the net namespace (nd_net in struct net_device).
+ */
+typedef uint64_t netstackid_t;
+typedef __be32 ipaddr_t;
+typedef struct in6_addr in6_addr_t;
+
+/*
+ * pktinfo is where packet ID info can be made available for deeper
+ * analysis if packet IDs become supported by the kernel in the future.
+ * The pkt_addr member is currently always NULL.
+ */
+typedef struct pktinfo {
+ uintptr_t pkt_addr;
+} pktinfo_t;
+
+/*
+ * csinfo is where connection state info is made available.
+ */
+typedef struct csinfo {
+ uintptr_t cs_addr;
+ uint64_t cs_cid;
+} csinfo_t;
+
/*
* We use these values to determine if a probe point is associated
- * with sending (outbound) or receiving (inbound).
+ * with sending (outbound) or receiving (inbound) or a state-related
+ * probe (i.e. neither inbound our outbound).
*/
inline int NET_PROBE_OUTBOUND = 0x00;
inline int NET_PROBE_INBOUND = 0x01;
+inline int NET_PROBE_STATE = 0x02;
diff --git a/dlibs/aarch64/6.10/tcp.d b/dlibs/aarch64/6.10/tcp.d
index 54e310cb..48d9adb4 100644
--- a/dlibs/aarch64/6.10/tcp.d
+++ b/dlibs/aarch64/6.10/tcp.d
@@ -1,13 +1,13 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
#pragma D depends_on module vmlinux
#pragma D depends_on library net.d
-#pragma D depends_on provider ip
+#pragma D depends_on library ip.d
#pragma D depends_on provider tcp
inline int TH_FIN = 0x01;
@@ -111,30 +111,38 @@ translator tcpinfo_t < struct tcphdr *T > {
tcp_seq = T ? ntohl(T->seq) : 0;
tcp_ack = T ? ntohl(T->ack_seq) : 0;
tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0;
- tcp_flags = T ? *(uint8_t *)(T + 13) : 0;
+ tcp_flags = T ? *((uint8_t *)T + 13) : 0;
tcp_window = T ? ntohs(T->window) : 0;
tcp_checksum = T ? ntohs(T->check) : 0;
tcp_urgent = T ? ntohs(T->urg_ptr) : 0;
tcp_hdr = (uintptr_t)T;
};
+/* timewait sockets and inet connection sockets do not populate all fields
+ * and are not classified as full sockets; this inline helps translators
+ * spot them and act appropriately.
+ */
+inline int tcp_fullsock[struct tcp_sock *sk] =
+ (((struct sock_common *)sk)->skc_state != TCP_STATE_SYN_RECEIVED &&
+ ((struct sock_common *)sk)->skc_state != TCP_STATE_TIME_WAIT);
/*
* In the main we simply translate from the "struct [tcp_]sock *" to
* a tcpsinfo_t *. However there are a few exceptions:
*
- * - tcps_state is always derived from arg6. The reason is that in some
+ * - tcps_state for state-change is arg5. The reason is that in some
* state transitions sock->sk_state does not reflect the actual TCP
* connection state. For example the TIME_WAIT state is handled in
* Linux by creating a separate timewait socket and the state of the
* original socket is CLOSED. In some other cases we also need to
- * instrument state transition prior to the update of sk_state. To do
- * all of this we rely on arg6.
+ * instrument state transition _prior_ to the update of sk_state. To do
+ * all of this we rely on arg5 to hold the new state. arg6 is set to
+ * NET_PROBE_STATE to quickly identify state-change probes.
* - we sometimes need to retrieve local/remote port/address settings from
* TCP and IP headers directly, for example prior to the address/port
* being committed to the socket. To do this effectively we need to know
* if the packet data is inbound (in which case the local IP/port are the
* destination) or outbound (in which case the local IP/port are the source).
- * arg7 is set to 0 for outbound traffic and 1 for inbound so we use these
+ * arg6 is set to 0 for outbound traffic and 1 for inbound so we use these
* to reconstruct the address/port info where necessary. arg2 used for IP
* information while arg4 contains the TCP header, so it is used for port data.
* NET_PROBE_INBOUND is defined as 1, NET_PROBE_OUTBOUND as 0 in net.d.
@@ -158,47 +166,49 @@ translator tcpsinfo_t < struct tcp_sock *T > {
((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_daddr)[2] &&
((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr)[3])
: 0;
- tcps_lport = (T && ((struct inet_sock *)T)->inet_sport != 0) ?
+ tcps_lport = T && ((struct inet_sock *)T)->inet_sport != 0 &&
+ tcp_fullsock[T] ?
ntohs(((struct inet_sock *)T)->inet_sport) :
(T && ((struct inet_sock *)T)->inet_sport == 0) ?
- ntohs(((struct sock *)T)->__sk_common.skc_num) :
+ ((struct sock *)T)->__sk_common.skc_num :
arg4 != NULL ?
ntohs(arg7 == NET_PROBE_INBOUND ?
- ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) :
+ ((struct tcphdr *)arg4)->dest :
+ ((struct tcphdr *)arg4)->source) :
0;
tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ?
ntohs(((struct sock *)T)->__sk_common.skc_dport) :
arg4 != NULL ?
ntohs(arg7 == NET_PROBE_INBOUND ?
- ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) :
+ ((struct tcphdr *)arg4)->source :
+ ((struct tcphdr *)arg4)->dest) :
0;
tcps_laddr =
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ?
inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) :
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ?
inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) :
- arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ?
- inet_ntoa(arg7 == NET_PROBE_INBOUND ?
- &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) :
- arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ?
- inet_ntoa6(arg7 == NET_PROBE_INBOUND ?
- &((struct ipv6hdr *)arg2)->daddr :
- &((struct ipv6hdr *)arg2)->saddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ?
+ inet_ntoa(&((struct iphdr *)arg2)->daddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ?
+ inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) :
"<unknown>";
tcps_raddr =
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ?
inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) :
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ?
inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) :
- arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ?
- inet_ntoa(arg7 == NET_PROBE_INBOUND ?
- &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) :
- arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ?
- inet_ntoa6(arg7 == NET_PROBE_INBOUND ?
- &((struct ipv6hdr *)arg2)->saddr :
- &((struct ipv6hdr *)arg2)->daddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ?
+ inet_ntoa(&((struct iphdr *)arg2)->saddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ?
+ inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) :
"<unknown>";
- tcps_state = arg6;
+ /* For state-change we probe right before state has changed, but
+ * provider definition wants new state in tcps_state; for
+ * state-change probes the trampoline stores it in arg5.
+ */
+ tcps_state = arg6 == NET_PROBE_STATE ? arg5 :
+ T ? ((struct sock *)T)->__sk_common.skc_state : 0;
tcps_iss = T ?
T->snd_una - (uint32_t)T->bytes_acked : 0;
tcps_suna = T ? T->snd_una : 0;
@@ -225,7 +235,10 @@ translator tcpsinfo_t < struct tcp_sock *T > {
T->rcv_nxt - (uint32_t)T->bytes_received : 0;
};
+/* state-change trampoline stores new state in arg5; at time of firing,
+ * state has not been updated, so last state is in tcp_sock state.
+ */
#pragma D binding "1.6.3" translator
translator tcplsinfo_t < int I > {
- tcps_state = I;
+ tcps_state = arg3 ? ((struct sock *)arg3)->__sk_common.skc_state : 0;
};
diff --git a/dlibs/x86_64/5.11/ip.d b/dlibs/x86_64/5.11/ip.d
index f8b77f12..493b75a0 100644
--- a/dlibs/x86_64/5.11/ip.d
+++ b/dlibs/x86_64/5.11/ip.d
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -46,31 +46,6 @@ inline int IPPROTO_MH = 135;
inline int TCP_MIN_HEADER_LENGTH = 20;
-/*
- * For compatibility with Solaris. Here the netstackid will be the pointer
- * to the net namespace (nd_net in struct net_device).
- */
-typedef uint64_t netstackid_t;
-typedef __be32 ipaddr_t;
-typedef struct in6_addr in6_addr_t;
-
-/*
- * pktinfo is where packet ID info can be made available for deeper
- * analysis if packet IDs become supported by the kernel in the future.
- * The pkt_addr member is currently always NULL.
- */
-typedef struct pktinfo {
- uintptr_t pkt_addr;
-} pktinfo_t;
-
-/*
- * csinfo is where connection state info is made available.
- */
-typedef struct csinfo {
- uintptr_t cs_addr;
- uint64_t cs_cid;
-} csinfo_t;
-
/*
* ipinfo contains common IP info for both IPv4 and IPv6.
*/
diff --git a/dlibs/x86_64/5.11/net.d b/dlibs/x86_64/5.11/net.d
index 6ac34287..f1291696 100644
--- a/dlibs/x86_64/5.11/net.d
+++ b/dlibs/x86_64/5.11/net.d
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -25,9 +25,36 @@ typedef struct conninfo {
string ci_protocol; /* protocol (ipv4, ipv6, etc) */
} conninfo_t;
+/*
+ * For compatibility with Solaris. Here the netstackid will be the pointer
+ * to the net namespace (nd_net in struct net_device).
+ */
+typedef uint64_t netstackid_t;
+typedef __be32 ipaddr_t;
+typedef struct in6_addr in6_addr_t;
+
+/*
+ * pktinfo is where packet ID info can be made available for deeper
+ * analysis if packet IDs become supported by the kernel in the future.
+ * The pkt_addr member is currently always NULL.
+ */
+typedef struct pktinfo {
+ uintptr_t pkt_addr;
+} pktinfo_t;
+
+/*
+ * csinfo is where connection state info is made available.
+ */
+typedef struct csinfo {
+ uintptr_t cs_addr;
+ uint64_t cs_cid;
+} csinfo_t;
+
/*
* We use these values to determine if a probe point is associated
- * with sending (outbound) or receiving (inbound).
+ * with sending (outbound) or receiving (inbound) or a state-related
+ * probe (i.e. neither inbound our outbound).
*/
inline int NET_PROBE_OUTBOUND = 0x00;
inline int NET_PROBE_INBOUND = 0x01;
+inline int NET_PROBE_STATE = 0x02;
diff --git a/dlibs/x86_64/5.11/tcp.d b/dlibs/x86_64/5.11/tcp.d
index 54e310cb..48d9adb4 100644
--- a/dlibs/x86_64/5.11/tcp.d
+++ b/dlibs/x86_64/5.11/tcp.d
@@ -1,13 +1,13 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
#pragma D depends_on module vmlinux
#pragma D depends_on library net.d
-#pragma D depends_on provider ip
+#pragma D depends_on library ip.d
#pragma D depends_on provider tcp
inline int TH_FIN = 0x01;
@@ -111,30 +111,38 @@ translator tcpinfo_t < struct tcphdr *T > {
tcp_seq = T ? ntohl(T->seq) : 0;
tcp_ack = T ? ntohl(T->ack_seq) : 0;
tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0;
- tcp_flags = T ? *(uint8_t *)(T + 13) : 0;
+ tcp_flags = T ? *((uint8_t *)T + 13) : 0;
tcp_window = T ? ntohs(T->window) : 0;
tcp_checksum = T ? ntohs(T->check) : 0;
tcp_urgent = T ? ntohs(T->urg_ptr) : 0;
tcp_hdr = (uintptr_t)T;
};
+/* timewait sockets and inet connection sockets do not populate all fields
+ * and are not classified as full sockets; this inline helps translators
+ * spot them and act appropriately.
+ */
+inline int tcp_fullsock[struct tcp_sock *sk] =
+ (((struct sock_common *)sk)->skc_state != TCP_STATE_SYN_RECEIVED &&
+ ((struct sock_common *)sk)->skc_state != TCP_STATE_TIME_WAIT);
/*
* In the main we simply translate from the "struct [tcp_]sock *" to
* a tcpsinfo_t *. However there are a few exceptions:
*
- * - tcps_state is always derived from arg6. The reason is that in some
+ * - tcps_state for state-change is arg5. The reason is that in some
* state transitions sock->sk_state does not reflect the actual TCP
* connection state. For example the TIME_WAIT state is handled in
* Linux by creating a separate timewait socket and the state of the
* original socket is CLOSED. In some other cases we also need to
- * instrument state transition prior to the update of sk_state. To do
- * all of this we rely on arg6.
+ * instrument state transition _prior_ to the update of sk_state. To do
+ * all of this we rely on arg5 to hold the new state. arg6 is set to
+ * NET_PROBE_STATE to quickly identify state-change probes.
* - we sometimes need to retrieve local/remote port/address settings from
* TCP and IP headers directly, for example prior to the address/port
* being committed to the socket. To do this effectively we need to know
* if the packet data is inbound (in which case the local IP/port are the
* destination) or outbound (in which case the local IP/port are the source).
- * arg7 is set to 0 for outbound traffic and 1 for inbound so we use these
+ * arg6 is set to 0 for outbound traffic and 1 for inbound so we use these
* to reconstruct the address/port info where necessary. arg2 used for IP
* information while arg4 contains the TCP header, so it is used for port data.
* NET_PROBE_INBOUND is defined as 1, NET_PROBE_OUTBOUND as 0 in net.d.
@@ -158,47 +166,49 @@ translator tcpsinfo_t < struct tcp_sock *T > {
((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_daddr)[2] &&
((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr)[3])
: 0;
- tcps_lport = (T && ((struct inet_sock *)T)->inet_sport != 0) ?
+ tcps_lport = T && ((struct inet_sock *)T)->inet_sport != 0 &&
+ tcp_fullsock[T] ?
ntohs(((struct inet_sock *)T)->inet_sport) :
(T && ((struct inet_sock *)T)->inet_sport == 0) ?
- ntohs(((struct sock *)T)->__sk_common.skc_num) :
+ ((struct sock *)T)->__sk_common.skc_num :
arg4 != NULL ?
ntohs(arg7 == NET_PROBE_INBOUND ?
- ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) :
+ ((struct tcphdr *)arg4)->dest :
+ ((struct tcphdr *)arg4)->source) :
0;
tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ?
ntohs(((struct sock *)T)->__sk_common.skc_dport) :
arg4 != NULL ?
ntohs(arg7 == NET_PROBE_INBOUND ?
- ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) :
+ ((struct tcphdr *)arg4)->source :
+ ((struct tcphdr *)arg4)->dest) :
0;
tcps_laddr =
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ?
inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) :
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ?
inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) :
- arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ?
- inet_ntoa(arg7 == NET_PROBE_INBOUND ?
- &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) :
- arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ?
- inet_ntoa6(arg7 == NET_PROBE_INBOUND ?
- &((struct ipv6hdr *)arg2)->daddr :
- &((struct ipv6hdr *)arg2)->saddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ?
+ inet_ntoa(&((struct iphdr *)arg2)->daddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ?
+ inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) :
"<unknown>";
tcps_raddr =
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ?
inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) :
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ?
inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) :
- arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ?
- inet_ntoa(arg7 == NET_PROBE_INBOUND ?
- &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) :
- arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ?
- inet_ntoa6(arg7 == NET_PROBE_INBOUND ?
- &((struct ipv6hdr *)arg2)->saddr :
- &((struct ipv6hdr *)arg2)->daddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ?
+ inet_ntoa(&((struct iphdr *)arg2)->saddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ?
+ inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) :
"<unknown>";
- tcps_state = arg6;
+ /* For state-change we probe right before state has changed, but
+ * provider definition wants new state in tcps_state; for
+ * state-change probes the trampoline stores it in arg5.
+ */
+ tcps_state = arg6 == NET_PROBE_STATE ? arg5 :
+ T ? ((struct sock *)T)->__sk_common.skc_state : 0;
tcps_iss = T ?
T->snd_una - (uint32_t)T->bytes_acked : 0;
tcps_suna = T ? T->snd_una : 0;
@@ -225,7 +235,10 @@ translator tcpsinfo_t < struct tcp_sock *T > {
T->rcv_nxt - (uint32_t)T->bytes_received : 0;
};
+/* state-change trampoline stores new state in arg5; at time of firing,
+ * state has not been updated, so last state is in tcp_sock state.
+ */
#pragma D binding "1.6.3" translator
translator tcplsinfo_t < int I > {
- tcps_state = I;
+ tcps_state = arg3 ? ((struct sock *)arg3)->__sk_common.skc_state : 0;
};
diff --git a/dlibs/x86_64/5.12/ip.d b/dlibs/x86_64/5.12/ip.d
index f8b77f12..493b75a0 100644
--- a/dlibs/x86_64/5.12/ip.d
+++ b/dlibs/x86_64/5.12/ip.d
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -46,31 +46,6 @@ inline int IPPROTO_MH = 135;
inline int TCP_MIN_HEADER_LENGTH = 20;
-/*
- * For compatibility with Solaris. Here the netstackid will be the pointer
- * to the net namespace (nd_net in struct net_device).
- */
-typedef uint64_t netstackid_t;
-typedef __be32 ipaddr_t;
-typedef struct in6_addr in6_addr_t;
-
-/*
- * pktinfo is where packet ID info can be made available for deeper
- * analysis if packet IDs become supported by the kernel in the future.
- * The pkt_addr member is currently always NULL.
- */
-typedef struct pktinfo {
- uintptr_t pkt_addr;
-} pktinfo_t;
-
-/*
- * csinfo is where connection state info is made available.
- */
-typedef struct csinfo {
- uintptr_t cs_addr;
- uint64_t cs_cid;
-} csinfo_t;
-
/*
* ipinfo contains common IP info for both IPv4 and IPv6.
*/
diff --git a/dlibs/x86_64/5.12/net.d b/dlibs/x86_64/5.12/net.d
index 6ac34287..f1291696 100644
--- a/dlibs/x86_64/5.12/net.d
+++ b/dlibs/x86_64/5.12/net.d
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -25,9 +25,36 @@ typedef struct conninfo {
string ci_protocol; /* protocol (ipv4, ipv6, etc) */
} conninfo_t;
+/*
+ * For compatibility with Solaris. Here the netstackid will be the pointer
+ * to the net namespace (nd_net in struct net_device).
+ */
+typedef uint64_t netstackid_t;
+typedef __be32 ipaddr_t;
+typedef struct in6_addr in6_addr_t;
+
+/*
+ * pktinfo is where packet ID info can be made available for deeper
+ * analysis if packet IDs become supported by the kernel in the future.
+ * The pkt_addr member is currently always NULL.
+ */
+typedef struct pktinfo {
+ uintptr_t pkt_addr;
+} pktinfo_t;
+
+/*
+ * csinfo is where connection state info is made available.
+ */
+typedef struct csinfo {
+ uintptr_t cs_addr;
+ uint64_t cs_cid;
+} csinfo_t;
+
/*
* We use these values to determine if a probe point is associated
- * with sending (outbound) or receiving (inbound).
+ * with sending (outbound) or receiving (inbound) or a state-related
+ * probe (i.e. neither inbound our outbound).
*/
inline int NET_PROBE_OUTBOUND = 0x00;
inline int NET_PROBE_INBOUND = 0x01;
+inline int NET_PROBE_STATE = 0x02;
diff --git a/dlibs/x86_64/5.12/tcp.d b/dlibs/x86_64/5.12/tcp.d
index 54e310cb..48d9adb4 100644
--- a/dlibs/x86_64/5.12/tcp.d
+++ b/dlibs/x86_64/5.12/tcp.d
@@ -1,13 +1,13 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
#pragma D depends_on module vmlinux
#pragma D depends_on library net.d
-#pragma D depends_on provider ip
+#pragma D depends_on library ip.d
#pragma D depends_on provider tcp
inline int TH_FIN = 0x01;
@@ -111,30 +111,38 @@ translator tcpinfo_t < struct tcphdr *T > {
tcp_seq = T ? ntohl(T->seq) : 0;
tcp_ack = T ? ntohl(T->ack_seq) : 0;
tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0;
- tcp_flags = T ? *(uint8_t *)(T + 13) : 0;
+ tcp_flags = T ? *((uint8_t *)T + 13) : 0;
tcp_window = T ? ntohs(T->window) : 0;
tcp_checksum = T ? ntohs(T->check) : 0;
tcp_urgent = T ? ntohs(T->urg_ptr) : 0;
tcp_hdr = (uintptr_t)T;
};
+/* timewait sockets and inet connection sockets do not populate all fields
+ * and are not classified as full sockets; this inline helps translators
+ * spot them and act appropriately.
+ */
+inline int tcp_fullsock[struct tcp_sock *sk] =
+ (((struct sock_common *)sk)->skc_state != TCP_STATE_SYN_RECEIVED &&
+ ((struct sock_common *)sk)->skc_state != TCP_STATE_TIME_WAIT);
/*
* In the main we simply translate from the "struct [tcp_]sock *" to
* a tcpsinfo_t *. However there are a few exceptions:
*
- * - tcps_state is always derived from arg6. The reason is that in some
+ * - tcps_state for state-change is arg5. The reason is that in some
* state transitions sock->sk_state does not reflect the actual TCP
* connection state. For example the TIME_WAIT state is handled in
* Linux by creating a separate timewait socket and the state of the
* original socket is CLOSED. In some other cases we also need to
- * instrument state transition prior to the update of sk_state. To do
- * all of this we rely on arg6.
+ * instrument state transition _prior_ to the update of sk_state. To do
+ * all of this we rely on arg5 to hold the new state. arg6 is set to
+ * NET_PROBE_STATE to quickly identify state-change probes.
* - we sometimes need to retrieve local/remote port/address settings from
* TCP and IP headers directly, for example prior to the address/port
* being committed to the socket. To do this effectively we need to know
* if the packet data is inbound (in which case the local IP/port are the
* destination) or outbound (in which case the local IP/port are the source).
- * arg7 is set to 0 for outbound traffic and 1 for inbound so we use these
+ * arg6 is set to 0 for outbound traffic and 1 for inbound so we use these
* to reconstruct the address/port info where necessary. arg2 used for IP
* information while arg4 contains the TCP header, so it is used for port data.
* NET_PROBE_INBOUND is defined as 1, NET_PROBE_OUTBOUND as 0 in net.d.
@@ -158,47 +166,49 @@ translator tcpsinfo_t < struct tcp_sock *T > {
((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_daddr)[2] &&
((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr)[3])
: 0;
- tcps_lport = (T && ((struct inet_sock *)T)->inet_sport != 0) ?
+ tcps_lport = T && ((struct inet_sock *)T)->inet_sport != 0 &&
+ tcp_fullsock[T] ?
ntohs(((struct inet_sock *)T)->inet_sport) :
(T && ((struct inet_sock *)T)->inet_sport == 0) ?
- ntohs(((struct sock *)T)->__sk_common.skc_num) :
+ ((struct sock *)T)->__sk_common.skc_num :
arg4 != NULL ?
ntohs(arg7 == NET_PROBE_INBOUND ?
- ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) :
+ ((struct tcphdr *)arg4)->dest :
+ ((struct tcphdr *)arg4)->source) :
0;
tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ?
ntohs(((struct sock *)T)->__sk_common.skc_dport) :
arg4 != NULL ?
ntohs(arg7 == NET_PROBE_INBOUND ?
- ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) :
+ ((struct tcphdr *)arg4)->source :
+ ((struct tcphdr *)arg4)->dest) :
0;
tcps_laddr =
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ?
inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) :
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ?
inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) :
- arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ?
- inet_ntoa(arg7 == NET_PROBE_INBOUND ?
- &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) :
- arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ?
- inet_ntoa6(arg7 == NET_PROBE_INBOUND ?
- &((struct ipv6hdr *)arg2)->daddr :
- &((struct ipv6hdr *)arg2)->saddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ?
+ inet_ntoa(&((struct iphdr *)arg2)->daddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ?
+ inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) :
"<unknown>";
tcps_raddr =
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ?
inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) :
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ?
inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) :
- arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ?
- inet_ntoa(arg7 == NET_PROBE_INBOUND ?
- &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) :
- arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ?
- inet_ntoa6(arg7 == NET_PROBE_INBOUND ?
- &((struct ipv6hdr *)arg2)->saddr :
- &((struct ipv6hdr *)arg2)->daddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ?
+ inet_ntoa(&((struct iphdr *)arg2)->saddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ?
+ inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) :
"<unknown>";
- tcps_state = arg6;
+ /* For state-change we probe right before state has changed, but
+ * provider definition wants new state in tcps_state; for
+ * state-change probes the trampoline stores it in arg5.
+ */
+ tcps_state = arg6 == NET_PROBE_STATE ? arg5 :
+ T ? ((struct sock *)T)->__sk_common.skc_state : 0;
tcps_iss = T ?
T->snd_una - (uint32_t)T->bytes_acked : 0;
tcps_suna = T ? T->snd_una : 0;
@@ -225,7 +235,10 @@ translator tcpsinfo_t < struct tcp_sock *T > {
T->rcv_nxt - (uint32_t)T->bytes_received : 0;
};
+/* state-change trampoline stores new state in arg5; at time of firing,
+ * state has not been updated, so last state is in tcp_sock state.
+ */
#pragma D binding "1.6.3" translator
translator tcplsinfo_t < int I > {
- tcps_state = I;
+ tcps_state = arg3 ? ((struct sock *)arg3)->__sk_common.skc_state : 0;
};
diff --git a/dlibs/x86_64/5.14/ip.d b/dlibs/x86_64/5.14/ip.d
index f8b77f12..493b75a0 100644
--- a/dlibs/x86_64/5.14/ip.d
+++ b/dlibs/x86_64/5.14/ip.d
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -46,31 +46,6 @@ inline int IPPROTO_MH = 135;
inline int TCP_MIN_HEADER_LENGTH = 20;
-/*
- * For compatibility with Solaris. Here the netstackid will be the pointer
- * to the net namespace (nd_net in struct net_device).
- */
-typedef uint64_t netstackid_t;
-typedef __be32 ipaddr_t;
-typedef struct in6_addr in6_addr_t;
-
-/*
- * pktinfo is where packet ID info can be made available for deeper
- * analysis if packet IDs become supported by the kernel in the future.
- * The pkt_addr member is currently always NULL.
- */
-typedef struct pktinfo {
- uintptr_t pkt_addr;
-} pktinfo_t;
-
-/*
- * csinfo is where connection state info is made available.
- */
-typedef struct csinfo {
- uintptr_t cs_addr;
- uint64_t cs_cid;
-} csinfo_t;
-
/*
* ipinfo contains common IP info for both IPv4 and IPv6.
*/
diff --git a/dlibs/x86_64/5.14/net.d b/dlibs/x86_64/5.14/net.d
index 6ac34287..f1291696 100644
--- a/dlibs/x86_64/5.14/net.d
+++ b/dlibs/x86_64/5.14/net.d
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -25,9 +25,36 @@ typedef struct conninfo {
string ci_protocol; /* protocol (ipv4, ipv6, etc) */
} conninfo_t;
+/*
+ * For compatibility with Solaris. Here the netstackid will be the pointer
+ * to the net namespace (nd_net in struct net_device).
+ */
+typedef uint64_t netstackid_t;
+typedef __be32 ipaddr_t;
+typedef struct in6_addr in6_addr_t;
+
+/*
+ * pktinfo is where packet ID info can be made available for deeper
+ * analysis if packet IDs become supported by the kernel in the future.
+ * The pkt_addr member is currently always NULL.
+ */
+typedef struct pktinfo {
+ uintptr_t pkt_addr;
+} pktinfo_t;
+
+/*
+ * csinfo is where connection state info is made available.
+ */
+typedef struct csinfo {
+ uintptr_t cs_addr;
+ uint64_t cs_cid;
+} csinfo_t;
+
/*
* We use these values to determine if a probe point is associated
- * with sending (outbound) or receiving (inbound).
+ * with sending (outbound) or receiving (inbound) or a state-related
+ * probe (i.e. neither inbound our outbound).
*/
inline int NET_PROBE_OUTBOUND = 0x00;
inline int NET_PROBE_INBOUND = 0x01;
+inline int NET_PROBE_STATE = 0x02;
diff --git a/dlibs/x86_64/5.14/tcp.d b/dlibs/x86_64/5.14/tcp.d
index 54e310cb..48d9adb4 100644
--- a/dlibs/x86_64/5.14/tcp.d
+++ b/dlibs/x86_64/5.14/tcp.d
@@ -1,13 +1,13 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
#pragma D depends_on module vmlinux
#pragma D depends_on library net.d
-#pragma D depends_on provider ip
+#pragma D depends_on library ip.d
#pragma D depends_on provider tcp
inline int TH_FIN = 0x01;
@@ -111,30 +111,38 @@ translator tcpinfo_t < struct tcphdr *T > {
tcp_seq = T ? ntohl(T->seq) : 0;
tcp_ack = T ? ntohl(T->ack_seq) : 0;
tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0;
- tcp_flags = T ? *(uint8_t *)(T + 13) : 0;
+ tcp_flags = T ? *((uint8_t *)T + 13) : 0;
tcp_window = T ? ntohs(T->window) : 0;
tcp_checksum = T ? ntohs(T->check) : 0;
tcp_urgent = T ? ntohs(T->urg_ptr) : 0;
tcp_hdr = (uintptr_t)T;
};
+/* timewait sockets and inet connection sockets do not populate all fields
+ * and are not classified as full sockets; this inline helps translators
+ * spot them and act appropriately.
+ */
+inline int tcp_fullsock[struct tcp_sock *sk] =
+ (((struct sock_common *)sk)->skc_state != TCP_STATE_SYN_RECEIVED &&
+ ((struct sock_common *)sk)->skc_state != TCP_STATE_TIME_WAIT);
/*
* In the main we simply translate from the "struct [tcp_]sock *" to
* a tcpsinfo_t *. However there are a few exceptions:
*
- * - tcps_state is always derived from arg6. The reason is that in some
+ * - tcps_state for state-change is arg5. The reason is that in some
* state transitions sock->sk_state does not reflect the actual TCP
* connection state. For example the TIME_WAIT state is handled in
* Linux by creating a separate timewait socket and the state of the
* original socket is CLOSED. In some other cases we also need to
- * instrument state transition prior to the update of sk_state. To do
- * all of this we rely on arg6.
+ * instrument state transition _prior_ to the update of sk_state. To do
+ * all of this we rely on arg5 to hold the new state. arg6 is set to
+ * NET_PROBE_STATE to quickly identify state-change probes.
* - we sometimes need to retrieve local/remote port/address settings from
* TCP and IP headers directly, for example prior to the address/port
* being committed to the socket. To do this effectively we need to know
* if the packet data is inbound (in which case the local IP/port are the
* destination) or outbound (in which case the local IP/port are the source).
- * arg7 is set to 0 for outbound traffic and 1 for inbound so we use these
+ * arg6 is set to 0 for outbound traffic and 1 for inbound so we use these
* to reconstruct the address/port info where necessary. arg2 used for IP
* information while arg4 contains the TCP header, so it is used for port data.
* NET_PROBE_INBOUND is defined as 1, NET_PROBE_OUTBOUND as 0 in net.d.
@@ -158,47 +166,49 @@ translator tcpsinfo_t < struct tcp_sock *T > {
((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_daddr)[2] &&
((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr)[3])
: 0;
- tcps_lport = (T && ((struct inet_sock *)T)->inet_sport != 0) ?
+ tcps_lport = T && ((struct inet_sock *)T)->inet_sport != 0 &&
+ tcp_fullsock[T] ?
ntohs(((struct inet_sock *)T)->inet_sport) :
(T && ((struct inet_sock *)T)->inet_sport == 0) ?
- ntohs(((struct sock *)T)->__sk_common.skc_num) :
+ ((struct sock *)T)->__sk_common.skc_num :
arg4 != NULL ?
ntohs(arg7 == NET_PROBE_INBOUND ?
- ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) :
+ ((struct tcphdr *)arg4)->dest :
+ ((struct tcphdr *)arg4)->source) :
0;
tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ?
ntohs(((struct sock *)T)->__sk_common.skc_dport) :
arg4 != NULL ?
ntohs(arg7 == NET_PROBE_INBOUND ?
- ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) :
+ ((struct tcphdr *)arg4)->source :
+ ((struct tcphdr *)arg4)->dest) :
0;
tcps_laddr =
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ?
inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) :
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ?
inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) :
- arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ?
- inet_ntoa(arg7 == NET_PROBE_INBOUND ?
- &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) :
- arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ?
- inet_ntoa6(arg7 == NET_PROBE_INBOUND ?
- &((struct ipv6hdr *)arg2)->daddr :
- &((struct ipv6hdr *)arg2)->saddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ?
+ inet_ntoa(&((struct iphdr *)arg2)->daddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ?
+ inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) :
"<unknown>";
tcps_raddr =
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ?
inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) :
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ?
inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) :
- arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ?
- inet_ntoa(arg7 == NET_PROBE_INBOUND ?
- &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) :
- arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ?
- inet_ntoa6(arg7 == NET_PROBE_INBOUND ?
- &((struct ipv6hdr *)arg2)->saddr :
- &((struct ipv6hdr *)arg2)->daddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ?
+ inet_ntoa(&((struct iphdr *)arg2)->saddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ?
+ inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) :
"<unknown>";
- tcps_state = arg6;
+ /* For state-change we probe right before state has changed, but
+ * provider definition wants new state in tcps_state; for
+ * state-change probes the trampoline stores it in arg5.
+ */
+ tcps_state = arg6 == NET_PROBE_STATE ? arg5 :
+ T ? ((struct sock *)T)->__sk_common.skc_state : 0;
tcps_iss = T ?
T->snd_una - (uint32_t)T->bytes_acked : 0;
tcps_suna = T ? T->snd_una : 0;
@@ -225,7 +235,10 @@ translator tcpsinfo_t < struct tcp_sock *T > {
T->rcv_nxt - (uint32_t)T->bytes_received : 0;
};
+/* state-change trampoline stores new state in arg5; at time of firing,
+ * state has not been updated, so last state is in tcp_sock state.
+ */
#pragma D binding "1.6.3" translator
translator tcplsinfo_t < int I > {
- tcps_state = I;
+ tcps_state = arg3 ? ((struct sock *)arg3)->__sk_common.skc_state : 0;
};
diff --git a/dlibs/x86_64/5.16/ip.d b/dlibs/x86_64/5.16/ip.d
index f8b77f12..493b75a0 100644
--- a/dlibs/x86_64/5.16/ip.d
+++ b/dlibs/x86_64/5.16/ip.d
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -46,31 +46,6 @@ inline int IPPROTO_MH = 135;
inline int TCP_MIN_HEADER_LENGTH = 20;
-/*
- * For compatibility with Solaris. Here the netstackid will be the pointer
- * to the net namespace (nd_net in struct net_device).
- */
-typedef uint64_t netstackid_t;
-typedef __be32 ipaddr_t;
-typedef struct in6_addr in6_addr_t;
-
-/*
- * pktinfo is where packet ID info can be made available for deeper
- * analysis if packet IDs become supported by the kernel in the future.
- * The pkt_addr member is currently always NULL.
- */
-typedef struct pktinfo {
- uintptr_t pkt_addr;
-} pktinfo_t;
-
-/*
- * csinfo is where connection state info is made available.
- */
-typedef struct csinfo {
- uintptr_t cs_addr;
- uint64_t cs_cid;
-} csinfo_t;
-
/*
* ipinfo contains common IP info for both IPv4 and IPv6.
*/
diff --git a/dlibs/x86_64/5.16/net.d b/dlibs/x86_64/5.16/net.d
index 6ac34287..f1291696 100644
--- a/dlibs/x86_64/5.16/net.d
+++ b/dlibs/x86_64/5.16/net.d
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -25,9 +25,36 @@ typedef struct conninfo {
string ci_protocol; /* protocol (ipv4, ipv6, etc) */
} conninfo_t;
+/*
+ * For compatibility with Solaris. Here the netstackid will be the pointer
+ * to the net namespace (nd_net in struct net_device).
+ */
+typedef uint64_t netstackid_t;
+typedef __be32 ipaddr_t;
+typedef struct in6_addr in6_addr_t;
+
+/*
+ * pktinfo is where packet ID info can be made available for deeper
+ * analysis if packet IDs become supported by the kernel in the future.
+ * The pkt_addr member is currently always NULL.
+ */
+typedef struct pktinfo {
+ uintptr_t pkt_addr;
+} pktinfo_t;
+
+/*
+ * csinfo is where connection state info is made available.
+ */
+typedef struct csinfo {
+ uintptr_t cs_addr;
+ uint64_t cs_cid;
+} csinfo_t;
+
/*
* We use these values to determine if a probe point is associated
- * with sending (outbound) or receiving (inbound).
+ * with sending (outbound) or receiving (inbound) or a state-related
+ * probe (i.e. neither inbound our outbound).
*/
inline int NET_PROBE_OUTBOUND = 0x00;
inline int NET_PROBE_INBOUND = 0x01;
+inline int NET_PROBE_STATE = 0x02;
diff --git a/dlibs/x86_64/5.16/tcp.d b/dlibs/x86_64/5.16/tcp.d
index 54e310cb..48d9adb4 100644
--- a/dlibs/x86_64/5.16/tcp.d
+++ b/dlibs/x86_64/5.16/tcp.d
@@ -1,13 +1,13 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
#pragma D depends_on module vmlinux
#pragma D depends_on library net.d
-#pragma D depends_on provider ip
+#pragma D depends_on library ip.d
#pragma D depends_on provider tcp
inline int TH_FIN = 0x01;
@@ -111,30 +111,38 @@ translator tcpinfo_t < struct tcphdr *T > {
tcp_seq = T ? ntohl(T->seq) : 0;
tcp_ack = T ? ntohl(T->ack_seq) : 0;
tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0;
- tcp_flags = T ? *(uint8_t *)(T + 13) : 0;
+ tcp_flags = T ? *((uint8_t *)T + 13) : 0;
tcp_window = T ? ntohs(T->window) : 0;
tcp_checksum = T ? ntohs(T->check) : 0;
tcp_urgent = T ? ntohs(T->urg_ptr) : 0;
tcp_hdr = (uintptr_t)T;
};
+/* timewait sockets and inet connection sockets do not populate all fields
+ * and are not classified as full sockets; this inline helps translators
+ * spot them and act appropriately.
+ */
+inline int tcp_fullsock[struct tcp_sock *sk] =
+ (((struct sock_common *)sk)->skc_state != TCP_STATE_SYN_RECEIVED &&
+ ((struct sock_common *)sk)->skc_state != TCP_STATE_TIME_WAIT);
/*
* In the main we simply translate from the "struct [tcp_]sock *" to
* a tcpsinfo_t *. However there are a few exceptions:
*
- * - tcps_state is always derived from arg6. The reason is that in some
+ * - tcps_state for state-change is arg5. The reason is that in some
* state transitions sock->sk_state does not reflect the actual TCP
* connection state. For example the TIME_WAIT state is handled in
* Linux by creating a separate timewait socket and the state of the
* original socket is CLOSED. In some other cases we also need to
- * instrument state transition prior to the update of sk_state. To do
- * all of this we rely on arg6.
+ * instrument state transition _prior_ to the update of sk_state. To do
+ * all of this we rely on arg5 to hold the new state. arg6 is set to
+ * NET_PROBE_STATE to quickly identify state-change probes.
* - we sometimes need to retrieve local/remote port/address settings from
* TCP and IP headers directly, for example prior to the address/port
* being committed to the socket. To do this effectively we need to know
* if the packet data is inbound (in which case the local IP/port are the
* destination) or outbound (in which case the local IP/port are the source).
- * arg7 is set to 0 for outbound traffic and 1 for inbound so we use these
+ * arg6 is set to 0 for outbound traffic and 1 for inbound so we use these
* to reconstruct the address/port info where necessary. arg2 used for IP
* information while arg4 contains the TCP header, so it is used for port data.
* NET_PROBE_INBOUND is defined as 1, NET_PROBE_OUTBOUND as 0 in net.d.
@@ -158,47 +166,49 @@ translator tcpsinfo_t < struct tcp_sock *T > {
((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_daddr)[2] &&
((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr)[3])
: 0;
- tcps_lport = (T && ((struct inet_sock *)T)->inet_sport != 0) ?
+ tcps_lport = T && ((struct inet_sock *)T)->inet_sport != 0 &&
+ tcp_fullsock[T] ?
ntohs(((struct inet_sock *)T)->inet_sport) :
(T && ((struct inet_sock *)T)->inet_sport == 0) ?
- ntohs(((struct sock *)T)->__sk_common.skc_num) :
+ ((struct sock *)T)->__sk_common.skc_num :
arg4 != NULL ?
ntohs(arg7 == NET_PROBE_INBOUND ?
- ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) :
+ ((struct tcphdr *)arg4)->dest :
+ ((struct tcphdr *)arg4)->source) :
0;
tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ?
ntohs(((struct sock *)T)->__sk_common.skc_dport) :
arg4 != NULL ?
ntohs(arg7 == NET_PROBE_INBOUND ?
- ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) :
+ ((struct tcphdr *)arg4)->source :
+ ((struct tcphdr *)arg4)->dest) :
0;
tcps_laddr =
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ?
inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) :
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ?
inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) :
- arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ?
- inet_ntoa(arg7 == NET_PROBE_INBOUND ?
- &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) :
- arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ?
- inet_ntoa6(arg7 == NET_PROBE_INBOUND ?
- &((struct ipv6hdr *)arg2)->daddr :
- &((struct ipv6hdr *)arg2)->saddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ?
+ inet_ntoa(&((struct iphdr *)arg2)->daddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ?
+ inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) :
"<unknown>";
tcps_raddr =
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ?
inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) :
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ?
inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) :
- arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ?
- inet_ntoa(arg7 == NET_PROBE_INBOUND ?
- &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) :
- arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ?
- inet_ntoa6(arg7 == NET_PROBE_INBOUND ?
- &((struct ipv6hdr *)arg2)->saddr :
- &((struct ipv6hdr *)arg2)->daddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ?
+ inet_ntoa(&((struct iphdr *)arg2)->saddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ?
+ inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) :
"<unknown>";
- tcps_state = arg6;
+ /* For state-change we probe right before state has changed, but
+ * provider definition wants new state in tcps_state; for
+ * state-change probes the trampoline stores it in arg5.
+ */
+ tcps_state = arg6 == NET_PROBE_STATE ? arg5 :
+ T ? ((struct sock *)T)->__sk_common.skc_state : 0;
tcps_iss = T ?
T->snd_una - (uint32_t)T->bytes_acked : 0;
tcps_suna = T ? T->snd_una : 0;
@@ -225,7 +235,10 @@ translator tcpsinfo_t < struct tcp_sock *T > {
T->rcv_nxt - (uint32_t)T->bytes_received : 0;
};
+/* state-change trampoline stores new state in arg5; at time of firing,
+ * state has not been updated, so last state is in tcp_sock state.
+ */
#pragma D binding "1.6.3" translator
translator tcplsinfo_t < int I > {
- tcps_state = I;
+ tcps_state = arg3 ? ((struct sock *)arg3)->__sk_common.skc_state : 0;
};
diff --git a/dlibs/x86_64/5.2/ip.d b/dlibs/x86_64/5.2/ip.d
index f8b77f12..493b75a0 100644
--- a/dlibs/x86_64/5.2/ip.d
+++ b/dlibs/x86_64/5.2/ip.d
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -46,31 +46,6 @@ inline int IPPROTO_MH = 135;
inline int TCP_MIN_HEADER_LENGTH = 20;
-/*
- * For compatibility with Solaris. Here the netstackid will be the pointer
- * to the net namespace (nd_net in struct net_device).
- */
-typedef uint64_t netstackid_t;
-typedef __be32 ipaddr_t;
-typedef struct in6_addr in6_addr_t;
-
-/*
- * pktinfo is where packet ID info can be made available for deeper
- * analysis if packet IDs become supported by the kernel in the future.
- * The pkt_addr member is currently always NULL.
- */
-typedef struct pktinfo {
- uintptr_t pkt_addr;
-} pktinfo_t;
-
-/*
- * csinfo is where connection state info is made available.
- */
-typedef struct csinfo {
- uintptr_t cs_addr;
- uint64_t cs_cid;
-} csinfo_t;
-
/*
* ipinfo contains common IP info for both IPv4 and IPv6.
*/
diff --git a/dlibs/x86_64/5.2/net.d b/dlibs/x86_64/5.2/net.d
index 6ac34287..f1291696 100644
--- a/dlibs/x86_64/5.2/net.d
+++ b/dlibs/x86_64/5.2/net.d
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -25,9 +25,36 @@ typedef struct conninfo {
string ci_protocol; /* protocol (ipv4, ipv6, etc) */
} conninfo_t;
+/*
+ * For compatibility with Solaris. Here the netstackid will be the pointer
+ * to the net namespace (nd_net in struct net_device).
+ */
+typedef uint64_t netstackid_t;
+typedef __be32 ipaddr_t;
+typedef struct in6_addr in6_addr_t;
+
+/*
+ * pktinfo is where packet ID info can be made available for deeper
+ * analysis if packet IDs become supported by the kernel in the future.
+ * The pkt_addr member is currently always NULL.
+ */
+typedef struct pktinfo {
+ uintptr_t pkt_addr;
+} pktinfo_t;
+
+/*
+ * csinfo is where connection state info is made available.
+ */
+typedef struct csinfo {
+ uintptr_t cs_addr;
+ uint64_t cs_cid;
+} csinfo_t;
+
/*
* We use these values to determine if a probe point is associated
- * with sending (outbound) or receiving (inbound).
+ * with sending (outbound) or receiving (inbound) or a state-related
+ * probe (i.e. neither inbound our outbound).
*/
inline int NET_PROBE_OUTBOUND = 0x00;
inline int NET_PROBE_INBOUND = 0x01;
+inline int NET_PROBE_STATE = 0x02;
diff --git a/dlibs/x86_64/5.2/tcp.d b/dlibs/x86_64/5.2/tcp.d
index 54e310cb..48d9adb4 100644
--- a/dlibs/x86_64/5.2/tcp.d
+++ b/dlibs/x86_64/5.2/tcp.d
@@ -1,13 +1,13 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
#pragma D depends_on module vmlinux
#pragma D depends_on library net.d
-#pragma D depends_on provider ip
+#pragma D depends_on library ip.d
#pragma D depends_on provider tcp
inline int TH_FIN = 0x01;
@@ -111,30 +111,38 @@ translator tcpinfo_t < struct tcphdr *T > {
tcp_seq = T ? ntohl(T->seq) : 0;
tcp_ack = T ? ntohl(T->ack_seq) : 0;
tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0;
- tcp_flags = T ? *(uint8_t *)(T + 13) : 0;
+ tcp_flags = T ? *((uint8_t *)T + 13) : 0;
tcp_window = T ? ntohs(T->window) : 0;
tcp_checksum = T ? ntohs(T->check) : 0;
tcp_urgent = T ? ntohs(T->urg_ptr) : 0;
tcp_hdr = (uintptr_t)T;
};
+/* timewait sockets and inet connection sockets do not populate all fields
+ * and are not classified as full sockets; this inline helps translators
+ * spot them and act appropriately.
+ */
+inline int tcp_fullsock[struct tcp_sock *sk] =
+ (((struct sock_common *)sk)->skc_state != TCP_STATE_SYN_RECEIVED &&
+ ((struct sock_common *)sk)->skc_state != TCP_STATE_TIME_WAIT);
/*
* In the main we simply translate from the "struct [tcp_]sock *" to
* a tcpsinfo_t *. However there are a few exceptions:
*
- * - tcps_state is always derived from arg6. The reason is that in some
+ * - tcps_state for state-change is arg5. The reason is that in some
* state transitions sock->sk_state does not reflect the actual TCP
* connection state. For example the TIME_WAIT state is handled in
* Linux by creating a separate timewait socket and the state of the
* original socket is CLOSED. In some other cases we also need to
- * instrument state transition prior to the update of sk_state. To do
- * all of this we rely on arg6.
+ * instrument state transition _prior_ to the update of sk_state. To do
+ * all of this we rely on arg5 to hold the new state. arg6 is set to
+ * NET_PROBE_STATE to quickly identify state-change probes.
* - we sometimes need to retrieve local/remote port/address settings from
* TCP and IP headers directly, for example prior to the address/port
* being committed to the socket. To do this effectively we need to know
* if the packet data is inbound (in which case the local IP/port are the
* destination) or outbound (in which case the local IP/port are the source).
- * arg7 is set to 0 for outbound traffic and 1 for inbound so we use these
+ * arg6 is set to 0 for outbound traffic and 1 for inbound so we use these
* to reconstruct the address/port info where necessary. arg2 used for IP
* information while arg4 contains the TCP header, so it is used for port data.
* NET_PROBE_INBOUND is defined as 1, NET_PROBE_OUTBOUND as 0 in net.d.
@@ -158,47 +166,49 @@ translator tcpsinfo_t < struct tcp_sock *T > {
((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_daddr)[2] &&
((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr)[3])
: 0;
- tcps_lport = (T && ((struct inet_sock *)T)->inet_sport != 0) ?
+ tcps_lport = T && ((struct inet_sock *)T)->inet_sport != 0 &&
+ tcp_fullsock[T] ?
ntohs(((struct inet_sock *)T)->inet_sport) :
(T && ((struct inet_sock *)T)->inet_sport == 0) ?
- ntohs(((struct sock *)T)->__sk_common.skc_num) :
+ ((struct sock *)T)->__sk_common.skc_num :
arg4 != NULL ?
ntohs(arg7 == NET_PROBE_INBOUND ?
- ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) :
+ ((struct tcphdr *)arg4)->dest :
+ ((struct tcphdr *)arg4)->source) :
0;
tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ?
ntohs(((struct sock *)T)->__sk_common.skc_dport) :
arg4 != NULL ?
ntohs(arg7 == NET_PROBE_INBOUND ?
- ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) :
+ ((struct tcphdr *)arg4)->source :
+ ((struct tcphdr *)arg4)->dest) :
0;
tcps_laddr =
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ?
inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) :
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ?
inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) :
- arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ?
- inet_ntoa(arg7 == NET_PROBE_INBOUND ?
- &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) :
- arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ?
- inet_ntoa6(arg7 == NET_PROBE_INBOUND ?
- &((struct ipv6hdr *)arg2)->daddr :
- &((struct ipv6hdr *)arg2)->saddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ?
+ inet_ntoa(&((struct iphdr *)arg2)->daddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ?
+ inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) :
"<unknown>";
tcps_raddr =
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ?
inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) :
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ?
inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) :
- arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ?
- inet_ntoa(arg7 == NET_PROBE_INBOUND ?
- &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) :
- arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ?
- inet_ntoa6(arg7 == NET_PROBE_INBOUND ?
- &((struct ipv6hdr *)arg2)->saddr :
- &((struct ipv6hdr *)arg2)->daddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ?
+ inet_ntoa(&((struct iphdr *)arg2)->saddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ?
+ inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) :
"<unknown>";
- tcps_state = arg6;
+ /* For state-change we probe right before state has changed, but
+ * provider definition wants new state in tcps_state; for
+ * state-change probes the trampoline stores it in arg5.
+ */
+ tcps_state = arg6 == NET_PROBE_STATE ? arg5 :
+ T ? ((struct sock *)T)->__sk_common.skc_state : 0;
tcps_iss = T ?
T->snd_una - (uint32_t)T->bytes_acked : 0;
tcps_suna = T ? T->snd_una : 0;
@@ -225,7 +235,10 @@ translator tcpsinfo_t < struct tcp_sock *T > {
T->rcv_nxt - (uint32_t)T->bytes_received : 0;
};
+/* state-change trampoline stores new state in arg5; at time of firing,
+ * state has not been updated, so last state is in tcp_sock state.
+ */
#pragma D binding "1.6.3" translator
translator tcplsinfo_t < int I > {
- tcps_state = I;
+ tcps_state = arg3 ? ((struct sock *)arg3)->__sk_common.skc_state : 0;
};
diff --git a/dlibs/x86_64/5.6/ip.d b/dlibs/x86_64/5.6/ip.d
index f8b77f12..493b75a0 100644
--- a/dlibs/x86_64/5.6/ip.d
+++ b/dlibs/x86_64/5.6/ip.d
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -46,31 +46,6 @@ inline int IPPROTO_MH = 135;
inline int TCP_MIN_HEADER_LENGTH = 20;
-/*
- * For compatibility with Solaris. Here the netstackid will be the pointer
- * to the net namespace (nd_net in struct net_device).
- */
-typedef uint64_t netstackid_t;
-typedef __be32 ipaddr_t;
-typedef struct in6_addr in6_addr_t;
-
-/*
- * pktinfo is where packet ID info can be made available for deeper
- * analysis if packet IDs become supported by the kernel in the future.
- * The pkt_addr member is currently always NULL.
- */
-typedef struct pktinfo {
- uintptr_t pkt_addr;
-} pktinfo_t;
-
-/*
- * csinfo is where connection state info is made available.
- */
-typedef struct csinfo {
- uintptr_t cs_addr;
- uint64_t cs_cid;
-} csinfo_t;
-
/*
* ipinfo contains common IP info for both IPv4 and IPv6.
*/
diff --git a/dlibs/x86_64/5.6/net.d b/dlibs/x86_64/5.6/net.d
index 6ac34287..f1291696 100644
--- a/dlibs/x86_64/5.6/net.d
+++ b/dlibs/x86_64/5.6/net.d
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -25,9 +25,36 @@ typedef struct conninfo {
string ci_protocol; /* protocol (ipv4, ipv6, etc) */
} conninfo_t;
+/*
+ * For compatibility with Solaris. Here the netstackid will be the pointer
+ * to the net namespace (nd_net in struct net_device).
+ */
+typedef uint64_t netstackid_t;
+typedef __be32 ipaddr_t;
+typedef struct in6_addr in6_addr_t;
+
+/*
+ * pktinfo is where packet ID info can be made available for deeper
+ * analysis if packet IDs become supported by the kernel in the future.
+ * The pkt_addr member is currently always NULL.
+ */
+typedef struct pktinfo {
+ uintptr_t pkt_addr;
+} pktinfo_t;
+
+/*
+ * csinfo is where connection state info is made available.
+ */
+typedef struct csinfo {
+ uintptr_t cs_addr;
+ uint64_t cs_cid;
+} csinfo_t;
+
/*
* We use these values to determine if a probe point is associated
- * with sending (outbound) or receiving (inbound).
+ * with sending (outbound) or receiving (inbound) or a state-related
+ * probe (i.e. neither inbound our outbound).
*/
inline int NET_PROBE_OUTBOUND = 0x00;
inline int NET_PROBE_INBOUND = 0x01;
+inline int NET_PROBE_STATE = 0x02;
diff --git a/dlibs/x86_64/5.6/tcp.d b/dlibs/x86_64/5.6/tcp.d
index 54e310cb..48d9adb4 100644
--- a/dlibs/x86_64/5.6/tcp.d
+++ b/dlibs/x86_64/5.6/tcp.d
@@ -1,13 +1,13 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
#pragma D depends_on module vmlinux
#pragma D depends_on library net.d
-#pragma D depends_on provider ip
+#pragma D depends_on library ip.d
#pragma D depends_on provider tcp
inline int TH_FIN = 0x01;
@@ -111,30 +111,38 @@ translator tcpinfo_t < struct tcphdr *T > {
tcp_seq = T ? ntohl(T->seq) : 0;
tcp_ack = T ? ntohl(T->ack_seq) : 0;
tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0;
- tcp_flags = T ? *(uint8_t *)(T + 13) : 0;
+ tcp_flags = T ? *((uint8_t *)T + 13) : 0;
tcp_window = T ? ntohs(T->window) : 0;
tcp_checksum = T ? ntohs(T->check) : 0;
tcp_urgent = T ? ntohs(T->urg_ptr) : 0;
tcp_hdr = (uintptr_t)T;
};
+/* timewait sockets and inet connection sockets do not populate all fields
+ * and are not classified as full sockets; this inline helps translators
+ * spot them and act appropriately.
+ */
+inline int tcp_fullsock[struct tcp_sock *sk] =
+ (((struct sock_common *)sk)->skc_state != TCP_STATE_SYN_RECEIVED &&
+ ((struct sock_common *)sk)->skc_state != TCP_STATE_TIME_WAIT);
/*
* In the main we simply translate from the "struct [tcp_]sock *" to
* a tcpsinfo_t *. However there are a few exceptions:
*
- * - tcps_state is always derived from arg6. The reason is that in some
+ * - tcps_state for state-change is arg5. The reason is that in some
* state transitions sock->sk_state does not reflect the actual TCP
* connection state. For example the TIME_WAIT state is handled in
* Linux by creating a separate timewait socket and the state of the
* original socket is CLOSED. In some other cases we also need to
- * instrument state transition prior to the update of sk_state. To do
- * all of this we rely on arg6.
+ * instrument state transition _prior_ to the update of sk_state. To do
+ * all of this we rely on arg5 to hold the new state. arg6 is set to
+ * NET_PROBE_STATE to quickly identify state-change probes.
* - we sometimes need to retrieve local/remote port/address settings from
* TCP and IP headers directly, for example prior to the address/port
* being committed to the socket. To do this effectively we need to know
* if the packet data is inbound (in which case the local IP/port are the
* destination) or outbound (in which case the local IP/port are the source).
- * arg7 is set to 0 for outbound traffic and 1 for inbound so we use these
+ * arg6 is set to 0 for outbound traffic and 1 for inbound so we use these
* to reconstruct the address/port info where necessary. arg2 used for IP
* information while arg4 contains the TCP header, so it is used for port data.
* NET_PROBE_INBOUND is defined as 1, NET_PROBE_OUTBOUND as 0 in net.d.
@@ -158,47 +166,49 @@ translator tcpsinfo_t < struct tcp_sock *T > {
((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_daddr)[2] &&
((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr)[3])
: 0;
- tcps_lport = (T && ((struct inet_sock *)T)->inet_sport != 0) ?
+ tcps_lport = T && ((struct inet_sock *)T)->inet_sport != 0 &&
+ tcp_fullsock[T] ?
ntohs(((struct inet_sock *)T)->inet_sport) :
(T && ((struct inet_sock *)T)->inet_sport == 0) ?
- ntohs(((struct sock *)T)->__sk_common.skc_num) :
+ ((struct sock *)T)->__sk_common.skc_num :
arg4 != NULL ?
ntohs(arg7 == NET_PROBE_INBOUND ?
- ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) :
+ ((struct tcphdr *)arg4)->dest :
+ ((struct tcphdr *)arg4)->source) :
0;
tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ?
ntohs(((struct sock *)T)->__sk_common.skc_dport) :
arg4 != NULL ?
ntohs(arg7 == NET_PROBE_INBOUND ?
- ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) :
+ ((struct tcphdr *)arg4)->source :
+ ((struct tcphdr *)arg4)->dest) :
0;
tcps_laddr =
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ?
inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) :
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ?
inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) :
- arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ?
- inet_ntoa(arg7 == NET_PROBE_INBOUND ?
- &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) :
- arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ?
- inet_ntoa6(arg7 == NET_PROBE_INBOUND ?
- &((struct ipv6hdr *)arg2)->daddr :
- &((struct ipv6hdr *)arg2)->saddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ?
+ inet_ntoa(&((struct iphdr *)arg2)->daddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ?
+ inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) :
"<unknown>";
tcps_raddr =
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ?
inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) :
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ?
inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) :
- arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ?
- inet_ntoa(arg7 == NET_PROBE_INBOUND ?
- &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) :
- arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ?
- inet_ntoa6(arg7 == NET_PROBE_INBOUND ?
- &((struct ipv6hdr *)arg2)->saddr :
- &((struct ipv6hdr *)arg2)->daddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ?
+ inet_ntoa(&((struct iphdr *)arg2)->saddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ?
+ inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) :
"<unknown>";
- tcps_state = arg6;
+ /* For state-change we probe right before state has changed, but
+ * provider definition wants new state in tcps_state; for
+ * state-change probes the trampoline stores it in arg5.
+ */
+ tcps_state = arg6 == NET_PROBE_STATE ? arg5 :
+ T ? ((struct sock *)T)->__sk_common.skc_state : 0;
tcps_iss = T ?
T->snd_una - (uint32_t)T->bytes_acked : 0;
tcps_suna = T ? T->snd_una : 0;
@@ -225,7 +235,10 @@ translator tcpsinfo_t < struct tcp_sock *T > {
T->rcv_nxt - (uint32_t)T->bytes_received : 0;
};
+/* state-change trampoline stores new state in arg5; at time of firing,
+ * state has not been updated, so last state is in tcp_sock state.
+ */
#pragma D binding "1.6.3" translator
translator tcplsinfo_t < int I > {
- tcps_state = I;
+ tcps_state = arg3 ? ((struct sock *)arg3)->__sk_common.skc_state : 0;
};
diff --git a/dlibs/x86_64/6.1/ip.d b/dlibs/x86_64/6.1/ip.d
index f8b77f12..493b75a0 100644
--- a/dlibs/x86_64/6.1/ip.d
+++ b/dlibs/x86_64/6.1/ip.d
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -46,31 +46,6 @@ inline int IPPROTO_MH = 135;
inline int TCP_MIN_HEADER_LENGTH = 20;
-/*
- * For compatibility with Solaris. Here the netstackid will be the pointer
- * to the net namespace (nd_net in struct net_device).
- */
-typedef uint64_t netstackid_t;
-typedef __be32 ipaddr_t;
-typedef struct in6_addr in6_addr_t;
-
-/*
- * pktinfo is where packet ID info can be made available for deeper
- * analysis if packet IDs become supported by the kernel in the future.
- * The pkt_addr member is currently always NULL.
- */
-typedef struct pktinfo {
- uintptr_t pkt_addr;
-} pktinfo_t;
-
-/*
- * csinfo is where connection state info is made available.
- */
-typedef struct csinfo {
- uintptr_t cs_addr;
- uint64_t cs_cid;
-} csinfo_t;
-
/*
* ipinfo contains common IP info for both IPv4 and IPv6.
*/
diff --git a/dlibs/x86_64/6.1/net.d b/dlibs/x86_64/6.1/net.d
index 6ac34287..f1291696 100644
--- a/dlibs/x86_64/6.1/net.d
+++ b/dlibs/x86_64/6.1/net.d
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -25,9 +25,36 @@ typedef struct conninfo {
string ci_protocol; /* protocol (ipv4, ipv6, etc) */
} conninfo_t;
+/*
+ * For compatibility with Solaris. Here the netstackid will be the pointer
+ * to the net namespace (nd_net in struct net_device).
+ */
+typedef uint64_t netstackid_t;
+typedef __be32 ipaddr_t;
+typedef struct in6_addr in6_addr_t;
+
+/*
+ * pktinfo is where packet ID info can be made available for deeper
+ * analysis if packet IDs become supported by the kernel in the future.
+ * The pkt_addr member is currently always NULL.
+ */
+typedef struct pktinfo {
+ uintptr_t pkt_addr;
+} pktinfo_t;
+
+/*
+ * csinfo is where connection state info is made available.
+ */
+typedef struct csinfo {
+ uintptr_t cs_addr;
+ uint64_t cs_cid;
+} csinfo_t;
+
/*
* We use these values to determine if a probe point is associated
- * with sending (outbound) or receiving (inbound).
+ * with sending (outbound) or receiving (inbound) or a state-related
+ * probe (i.e. neither inbound our outbound).
*/
inline int NET_PROBE_OUTBOUND = 0x00;
inline int NET_PROBE_INBOUND = 0x01;
+inline int NET_PROBE_STATE = 0x02;
diff --git a/dlibs/x86_64/6.1/tcp.d b/dlibs/x86_64/6.1/tcp.d
index 54e310cb..48d9adb4 100644
--- a/dlibs/x86_64/6.1/tcp.d
+++ b/dlibs/x86_64/6.1/tcp.d
@@ -1,13 +1,13 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
#pragma D depends_on module vmlinux
#pragma D depends_on library net.d
-#pragma D depends_on provider ip
+#pragma D depends_on library ip.d
#pragma D depends_on provider tcp
inline int TH_FIN = 0x01;
@@ -111,30 +111,38 @@ translator tcpinfo_t < struct tcphdr *T > {
tcp_seq = T ? ntohl(T->seq) : 0;
tcp_ack = T ? ntohl(T->ack_seq) : 0;
tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0;
- tcp_flags = T ? *(uint8_t *)(T + 13) : 0;
+ tcp_flags = T ? *((uint8_t *)T + 13) : 0;
tcp_window = T ? ntohs(T->window) : 0;
tcp_checksum = T ? ntohs(T->check) : 0;
tcp_urgent = T ? ntohs(T->urg_ptr) : 0;
tcp_hdr = (uintptr_t)T;
};
+/* timewait sockets and inet connection sockets do not populate all fields
+ * and are not classified as full sockets; this inline helps translators
+ * spot them and act appropriately.
+ */
+inline int tcp_fullsock[struct tcp_sock *sk] =
+ (((struct sock_common *)sk)->skc_state != TCP_STATE_SYN_RECEIVED &&
+ ((struct sock_common *)sk)->skc_state != TCP_STATE_TIME_WAIT);
/*
* In the main we simply translate from the "struct [tcp_]sock *" to
* a tcpsinfo_t *. However there are a few exceptions:
*
- * - tcps_state is always derived from arg6. The reason is that in some
+ * - tcps_state for state-change is arg5. The reason is that in some
* state transitions sock->sk_state does not reflect the actual TCP
* connection state. For example the TIME_WAIT state is handled in
* Linux by creating a separate timewait socket and the state of the
* original socket is CLOSED. In some other cases we also need to
- * instrument state transition prior to the update of sk_state. To do
- * all of this we rely on arg6.
+ * instrument state transition _prior_ to the update of sk_state. To do
+ * all of this we rely on arg5 to hold the new state. arg6 is set to
+ * NET_PROBE_STATE to quickly identify state-change probes.
* - we sometimes need to retrieve local/remote port/address settings from
* TCP and IP headers directly, for example prior to the address/port
* being committed to the socket. To do this effectively we need to know
* if the packet data is inbound (in which case the local IP/port are the
* destination) or outbound (in which case the local IP/port are the source).
- * arg7 is set to 0 for outbound traffic and 1 for inbound so we use these
+ * arg6 is set to 0 for outbound traffic and 1 for inbound so we use these
* to reconstruct the address/port info where necessary. arg2 used for IP
* information while arg4 contains the TCP header, so it is used for port data.
* NET_PROBE_INBOUND is defined as 1, NET_PROBE_OUTBOUND as 0 in net.d.
@@ -158,47 +166,49 @@ translator tcpsinfo_t < struct tcp_sock *T > {
((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_daddr)[2] &&
((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr)[3])
: 0;
- tcps_lport = (T && ((struct inet_sock *)T)->inet_sport != 0) ?
+ tcps_lport = T && ((struct inet_sock *)T)->inet_sport != 0 &&
+ tcp_fullsock[T] ?
ntohs(((struct inet_sock *)T)->inet_sport) :
(T && ((struct inet_sock *)T)->inet_sport == 0) ?
- ntohs(((struct sock *)T)->__sk_common.skc_num) :
+ ((struct sock *)T)->__sk_common.skc_num :
arg4 != NULL ?
ntohs(arg7 == NET_PROBE_INBOUND ?
- ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) :
+ ((struct tcphdr *)arg4)->dest :
+ ((struct tcphdr *)arg4)->source) :
0;
tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ?
ntohs(((struct sock *)T)->__sk_common.skc_dport) :
arg4 != NULL ?
ntohs(arg7 == NET_PROBE_INBOUND ?
- ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) :
+ ((struct tcphdr *)arg4)->source :
+ ((struct tcphdr *)arg4)->dest) :
0;
tcps_laddr =
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ?
inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) :
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ?
inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) :
- arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ?
- inet_ntoa(arg7 == NET_PROBE_INBOUND ?
- &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) :
- arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ?
- inet_ntoa6(arg7 == NET_PROBE_INBOUND ?
- &((struct ipv6hdr *)arg2)->daddr :
- &((struct ipv6hdr *)arg2)->saddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ?
+ inet_ntoa(&((struct iphdr *)arg2)->daddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ?
+ inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) :
"<unknown>";
tcps_raddr =
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ?
inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) :
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ?
inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) :
- arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ?
- inet_ntoa(arg7 == NET_PROBE_INBOUND ?
- &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) :
- arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ?
- inet_ntoa6(arg7 == NET_PROBE_INBOUND ?
- &((struct ipv6hdr *)arg2)->saddr :
- &((struct ipv6hdr *)arg2)->daddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ?
+ inet_ntoa(&((struct iphdr *)arg2)->saddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ?
+ inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) :
"<unknown>";
- tcps_state = arg6;
+ /* For state-change we probe right before state has changed, but
+ * provider definition wants new state in tcps_state; for
+ * state-change probes the trampoline stores it in arg5.
+ */
+ tcps_state = arg6 == NET_PROBE_STATE ? arg5 :
+ T ? ((struct sock *)T)->__sk_common.skc_state : 0;
tcps_iss = T ?
T->snd_una - (uint32_t)T->bytes_acked : 0;
tcps_suna = T ? T->snd_una : 0;
@@ -225,7 +235,10 @@ translator tcpsinfo_t < struct tcp_sock *T > {
T->rcv_nxt - (uint32_t)T->bytes_received : 0;
};
+/* state-change trampoline stores new state in arg5; at time of firing,
+ * state has not been updated, so last state is in tcp_sock state.
+ */
#pragma D binding "1.6.3" translator
translator tcplsinfo_t < int I > {
- tcps_state = I;
+ tcps_state = arg3 ? ((struct sock *)arg3)->__sk_common.skc_state : 0;
};
diff --git a/dlibs/x86_64/6.10/ip.d b/dlibs/x86_64/6.10/ip.d
index f8b77f12..493b75a0 100644
--- a/dlibs/x86_64/6.10/ip.d
+++ b/dlibs/x86_64/6.10/ip.d
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -46,31 +46,6 @@ inline int IPPROTO_MH = 135;
inline int TCP_MIN_HEADER_LENGTH = 20;
-/*
- * For compatibility with Solaris. Here the netstackid will be the pointer
- * to the net namespace (nd_net in struct net_device).
- */
-typedef uint64_t netstackid_t;
-typedef __be32 ipaddr_t;
-typedef struct in6_addr in6_addr_t;
-
-/*
- * pktinfo is where packet ID info can be made available for deeper
- * analysis if packet IDs become supported by the kernel in the future.
- * The pkt_addr member is currently always NULL.
- */
-typedef struct pktinfo {
- uintptr_t pkt_addr;
-} pktinfo_t;
-
-/*
- * csinfo is where connection state info is made available.
- */
-typedef struct csinfo {
- uintptr_t cs_addr;
- uint64_t cs_cid;
-} csinfo_t;
-
/*
* ipinfo contains common IP info for both IPv4 and IPv6.
*/
diff --git a/dlibs/x86_64/6.10/net.d b/dlibs/x86_64/6.10/net.d
index 6ac34287..f1291696 100644
--- a/dlibs/x86_64/6.10/net.d
+++ b/dlibs/x86_64/6.10/net.d
@@ -1,6 +1,6 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
@@ -25,9 +25,36 @@ typedef struct conninfo {
string ci_protocol; /* protocol (ipv4, ipv6, etc) */
} conninfo_t;
+/*
+ * For compatibility with Solaris. Here the netstackid will be the pointer
+ * to the net namespace (nd_net in struct net_device).
+ */
+typedef uint64_t netstackid_t;
+typedef __be32 ipaddr_t;
+typedef struct in6_addr in6_addr_t;
+
+/*
+ * pktinfo is where packet ID info can be made available for deeper
+ * analysis if packet IDs become supported by the kernel in the future.
+ * The pkt_addr member is currently always NULL.
+ */
+typedef struct pktinfo {
+ uintptr_t pkt_addr;
+} pktinfo_t;
+
+/*
+ * csinfo is where connection state info is made available.
+ */
+typedef struct csinfo {
+ uintptr_t cs_addr;
+ uint64_t cs_cid;
+} csinfo_t;
+
/*
* We use these values to determine if a probe point is associated
- * with sending (outbound) or receiving (inbound).
+ * with sending (outbound) or receiving (inbound) or a state-related
+ * probe (i.e. neither inbound our outbound).
*/
inline int NET_PROBE_OUTBOUND = 0x00;
inline int NET_PROBE_INBOUND = 0x01;
+inline int NET_PROBE_STATE = 0x02;
diff --git a/dlibs/x86_64/6.10/tcp.d b/dlibs/x86_64/6.10/tcp.d
index 54e310cb..48d9adb4 100644
--- a/dlibs/x86_64/6.10/tcp.d
+++ b/dlibs/x86_64/6.10/tcp.d
@@ -1,13 +1,13 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
#pragma D depends_on module vmlinux
#pragma D depends_on library net.d
-#pragma D depends_on provider ip
+#pragma D depends_on library ip.d
#pragma D depends_on provider tcp
inline int TH_FIN = 0x01;
@@ -111,30 +111,38 @@ translator tcpinfo_t < struct tcphdr *T > {
tcp_seq = T ? ntohl(T->seq) : 0;
tcp_ack = T ? ntohl(T->ack_seq) : 0;
tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0;
- tcp_flags = T ? *(uint8_t *)(T + 13) : 0;
+ tcp_flags = T ? *((uint8_t *)T + 13) : 0;
tcp_window = T ? ntohs(T->window) : 0;
tcp_checksum = T ? ntohs(T->check) : 0;
tcp_urgent = T ? ntohs(T->urg_ptr) : 0;
tcp_hdr = (uintptr_t)T;
};
+/* timewait sockets and inet connection sockets do not populate all fields
+ * and are not classified as full sockets; this inline helps translators
+ * spot them and act appropriately.
+ */
+inline int tcp_fullsock[struct tcp_sock *sk] =
+ (((struct sock_common *)sk)->skc_state != TCP_STATE_SYN_RECEIVED &&
+ ((struct sock_common *)sk)->skc_state != TCP_STATE_TIME_WAIT);
/*
* In the main we simply translate from the "struct [tcp_]sock *" to
* a tcpsinfo_t *. However there are a few exceptions:
*
- * - tcps_state is always derived from arg6. The reason is that in some
+ * - tcps_state for state-change is arg5. The reason is that in some
* state transitions sock->sk_state does not reflect the actual TCP
* connection state. For example the TIME_WAIT state is handled in
* Linux by creating a separate timewait socket and the state of the
* original socket is CLOSED. In some other cases we also need to
- * instrument state transition prior to the update of sk_state. To do
- * all of this we rely on arg6.
+ * instrument state transition _prior_ to the update of sk_state. To do
+ * all of this we rely on arg5 to hold the new state. arg6 is set to
+ * NET_PROBE_STATE to quickly identify state-change probes.
* - we sometimes need to retrieve local/remote port/address settings from
* TCP and IP headers directly, for example prior to the address/port
* being committed to the socket. To do this effectively we need to know
* if the packet data is inbound (in which case the local IP/port are the
* destination) or outbound (in which case the local IP/port are the source).
- * arg7 is set to 0 for outbound traffic and 1 for inbound so we use these
+ * arg6 is set to 0 for outbound traffic and 1 for inbound so we use these
* to reconstruct the address/port info where necessary. arg2 used for IP
* information while arg4 contains the TCP header, so it is used for port data.
* NET_PROBE_INBOUND is defined as 1, NET_PROBE_OUTBOUND as 0 in net.d.
@@ -158,47 +166,49 @@ translator tcpsinfo_t < struct tcp_sock *T > {
((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_daddr)[2] &&
((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr)[3])
: 0;
- tcps_lport = (T && ((struct inet_sock *)T)->inet_sport != 0) ?
+ tcps_lport = T && ((struct inet_sock *)T)->inet_sport != 0 &&
+ tcp_fullsock[T] ?
ntohs(((struct inet_sock *)T)->inet_sport) :
(T && ((struct inet_sock *)T)->inet_sport == 0) ?
- ntohs(((struct sock *)T)->__sk_common.skc_num) :
+ ((struct sock *)T)->__sk_common.skc_num :
arg4 != NULL ?
ntohs(arg7 == NET_PROBE_INBOUND ?
- ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) :
+ ((struct tcphdr *)arg4)->dest :
+ ((struct tcphdr *)arg4)->source) :
0;
tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ?
ntohs(((struct sock *)T)->__sk_common.skc_dport) :
arg4 != NULL ?
ntohs(arg7 == NET_PROBE_INBOUND ?
- ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) :
+ ((struct tcphdr *)arg4)->source :
+ ((struct tcphdr *)arg4)->dest) :
0;
tcps_laddr =
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ?
inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) :
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ?
inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) :
- arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ?
- inet_ntoa(arg7 == NET_PROBE_INBOUND ?
- &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) :
- arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ?
- inet_ntoa6(arg7 == NET_PROBE_INBOUND ?
- &((struct ipv6hdr *)arg2)->daddr :
- &((struct ipv6hdr *)arg2)->saddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ?
+ inet_ntoa(&((struct iphdr *)arg2)->daddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ?
+ inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) :
"<unknown>";
tcps_raddr =
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ?
inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) :
T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ?
inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) :
- arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ?
- inet_ntoa(arg7 == NET_PROBE_INBOUND ?
- &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) :
- arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ?
- inet_ntoa6(arg7 == NET_PROBE_INBOUND ?
- &((struct ipv6hdr *)arg2)->saddr :
- &((struct ipv6hdr *)arg2)->daddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ?
+ inet_ntoa(&((struct iphdr *)arg2)->saddr) :
+ arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ?
+ inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) :
"<unknown>";
- tcps_state = arg6;
+ /* For state-change we probe right before state has changed, but
+ * provider definition wants new state in tcps_state; for
+ * state-change probes the trampoline stores it in arg5.
+ */
+ tcps_state = arg6 == NET_PROBE_STATE ? arg5 :
+ T ? ((struct sock *)T)->__sk_common.skc_state : 0;
tcps_iss = T ?
T->snd_una - (uint32_t)T->bytes_acked : 0;
tcps_suna = T ? T->snd_una : 0;
@@ -225,7 +235,10 @@ translator tcpsinfo_t < struct tcp_sock *T > {
T->rcv_nxt - (uint32_t)T->bytes_received : 0;
};
+/* state-change trampoline stores new state in arg5; at time of firing,
+ * state has not been updated, so last state is in tcp_sock state.
+ */
#pragma D binding "1.6.3" translator
translator tcplsinfo_t < int I > {
- tcps_state = I;
+ tcps_state = arg3 ? ((struct sock *)arg3)->__sk_common.skc_state : 0;
};
--
2.43.5
More information about the DTrace-devel
mailing list