1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2020 Facebook */
4 #include "bpf_tracing_net.h"
5 #include <bpf/bpf_helpers.h>
6 #include <bpf/bpf_tracing.h>
7 #include <bpf/bpf_endian.h>
9 char _license
[] SEC("license") = "GPL";
11 static int hlist_unhashed_lockless(const struct hlist_node
*h
)
16 static int timer_pending(const struct timer_list
* timer
)
18 return !hlist_unhashed_lockless(&timer
->entry
);
21 extern unsigned CONFIG_HZ __kconfig
;
24 #define NSEC_PER_SEC 1000000000ULL
25 static clock_t jiffies_to_clock_t(unsigned long x
)
27 /* The implementation here tailored to a particular
30 u64 tick_nsec
= (NSEC_PER_SEC
+ CONFIG_HZ
/2) / CONFIG_HZ
;
31 u64 user_hz_nsec
= NSEC_PER_SEC
/ USER_HZ
;
33 if ((tick_nsec
% user_hz_nsec
) == 0) {
34 if (CONFIG_HZ
< USER_HZ
)
35 return x
* (USER_HZ
/ CONFIG_HZ
);
37 return x
/ (CONFIG_HZ
/ USER_HZ
);
39 return x
* tick_nsec
/user_hz_nsec
;
42 static clock_t jiffies_delta_to_clock_t(long delta
)
47 return jiffies_to_clock_t(delta
);
50 static long sock_i_ino(const struct sock
*sk
)
52 const struct socket
*sk_socket
= sk
->sk_socket
;
53 const struct inode
*inode
;
59 inode
= &container_of(sk_socket
, struct socket_alloc
, socket
)->vfs_inode
;
60 bpf_probe_read_kernel(&ino
, sizeof(ino
), &inode
->i_ino
);
65 inet_csk_in_pingpong_mode(const struct inet_connection_sock
*icsk
)
67 return icsk
->icsk_ack
.pingpong
>= TCP_PINGPONG_THRESH
;
70 static bool tcp_in_initial_slowstart(const struct tcp_sock
*tcp
)
72 return tcp
->snd_ssthresh
>= TCP_INFINITE_SSTHRESH
;
75 static int dump_tcp6_sock(struct seq_file
*seq
, struct tcp6_sock
*tp
,
76 uid_t uid
, __u32 seq_num
)
78 const struct inet_connection_sock
*icsk
;
79 const struct fastopen_queue
*fastopenq
;
80 const struct in6_addr
*dest
, *src
;
81 const struct inet_sock
*inet
;
82 unsigned long timer_expires
;
83 const struct sock
*sp
;
89 icsk
= &tp
->tcp
.inet_conn
;
90 inet
= &icsk
->icsk_inet
;
92 fastopenq
= &icsk
->icsk_accept_queue
.fastopenq
;
94 dest
= &sp
->sk_v6_daddr
;
95 src
= &sp
->sk_v6_rcv_saddr
;
96 destp
= bpf_ntohs(inet
->inet_dport
);
97 srcp
= bpf_ntohs(inet
->inet_sport
);
99 if (icsk
->icsk_pending
== ICSK_TIME_RETRANS
||
100 icsk
->icsk_pending
== ICSK_TIME_REO_TIMEOUT
||
101 icsk
->icsk_pending
== ICSK_TIME_LOSS_PROBE
) {
103 timer_expires
= icsk
->icsk_timeout
;
104 } else if (icsk
->icsk_pending
== ICSK_TIME_PROBE0
) {
106 timer_expires
= icsk
->icsk_timeout
;
107 } else if (timer_pending(&sp
->sk_timer
)) {
109 timer_expires
= sp
->sk_timer
.expires
;
112 timer_expires
= bpf_jiffies64();
115 state
= sp
->sk_state
;
116 if (state
== TCP_LISTEN
) {
117 rx_queue
= sp
->sk_ack_backlog
;
119 rx_queue
= tp
->tcp
.rcv_nxt
- tp
->tcp
.copied_seq
;
124 BPF_SEQ_PRINTF(seq
, "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X ",
126 src
->s6_addr32
[0], src
->s6_addr32
[1],
127 src
->s6_addr32
[2], src
->s6_addr32
[3], srcp
,
128 dest
->s6_addr32
[0], dest
->s6_addr32
[1],
129 dest
->s6_addr32
[2], dest
->s6_addr32
[3], destp
);
130 BPF_SEQ_PRINTF(seq
, "%02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d ",
132 tp
->tcp
.write_seq
- tp
->tcp
.snd_una
, rx_queue
,
134 jiffies_delta_to_clock_t(timer_expires
- bpf_jiffies64()),
135 icsk
->icsk_retransmits
, uid
,
136 icsk
->icsk_probes_out
,
138 sp
->sk_refcnt
.refs
.counter
);
139 BPF_SEQ_PRINTF(seq
, "%pK %lu %lu %u %u %d\n",
141 jiffies_to_clock_t(icsk
->icsk_rto
),
142 jiffies_to_clock_t(icsk
->icsk_ack
.ato
),
143 (icsk
->icsk_ack
.quick
<< 1) | inet_csk_in_pingpong_mode(icsk
),
145 state
== TCP_LISTEN
? fastopenq
->max_qlen
146 : (tcp_in_initial_slowstart(&tp
->tcp
) ? -1
147 : tp
->tcp
.snd_ssthresh
)
153 static int dump_tw_sock(struct seq_file
*seq
, struct tcp_timewait_sock
*ttw
,
154 uid_t uid
, __u32 seq_num
)
156 struct inet_timewait_sock
*tw
= &ttw
->tw_sk
;
157 const struct in6_addr
*dest
, *src
;
161 delta
= tw
->tw_timer
.expires
- bpf_jiffies64();
162 dest
= &tw
->tw_v6_daddr
;
163 src
= &tw
->tw_v6_rcv_saddr
;
164 destp
= bpf_ntohs(tw
->tw_dport
);
165 srcp
= bpf_ntohs(tw
->tw_sport
);
167 BPF_SEQ_PRINTF(seq
, "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X ",
169 src
->s6_addr32
[0], src
->s6_addr32
[1],
170 src
->s6_addr32
[2], src
->s6_addr32
[3], srcp
,
171 dest
->s6_addr32
[0], dest
->s6_addr32
[1],
172 dest
->s6_addr32
[2], dest
->s6_addr32
[3], destp
);
174 BPF_SEQ_PRINTF(seq
, "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK\n",
175 tw
->tw_substate
, 0, 0,
176 3, jiffies_delta_to_clock_t(delta
), 0, 0, 0, 0,
177 tw
->tw_refcnt
.refs
.counter
, tw
);
182 static int dump_req_sock(struct seq_file
*seq
, struct tcp_request_sock
*treq
,
183 uid_t uid
, __u32 seq_num
)
185 struct inet_request_sock
*irsk
= &treq
->req
;
186 struct request_sock
*req
= &irsk
->req
;
187 struct in6_addr
*src
, *dest
;
190 ttd
= req
->rsk_timer
.expires
- bpf_jiffies64();
191 src
= &irsk
->ir_v6_loc_addr
;
192 dest
= &irsk
->ir_v6_rmt_addr
;
197 BPF_SEQ_PRINTF(seq
, "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X ",
199 src
->s6_addr32
[0], src
->s6_addr32
[1],
200 src
->s6_addr32
[2], src
->s6_addr32
[3],
202 dest
->s6_addr32
[0], dest
->s6_addr32
[1],
203 dest
->s6_addr32
[2], dest
->s6_addr32
[3],
204 bpf_ntohs(irsk
->ir_rmt_port
));
205 BPF_SEQ_PRINTF(seq
, "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK\n",
206 TCP_SYN_RECV
, 0, 0, 1, jiffies_to_clock_t(ttd
),
207 req
->num_timeout
, uid
, 0, 0, 0, req
);
213 int dump_tcp6(struct bpf_iter__tcp
*ctx
)
215 struct sock_common
*sk_common
= ctx
->sk_common
;
216 struct seq_file
*seq
= ctx
->meta
->seq
;
217 struct tcp_timewait_sock
*tw
;
218 struct tcp_request_sock
*req
;
219 struct tcp6_sock
*tp
;
220 uid_t uid
= ctx
->uid
;
223 if (sk_common
== (void *)0)
226 seq_num
= ctx
->meta
->seq_num
;
228 BPF_SEQ_PRINTF(seq
, " sl "
231 "st tx_queue rx_queue tr tm->when retrnsmt"
232 " uid timeout inode\n");
234 if (sk_common
->skc_family
!= AF_INET6
)
237 tp
= bpf_skc_to_tcp6_sock(sk_common
);
239 return dump_tcp6_sock(seq
, tp
, uid
, seq_num
);
241 tw
= bpf_skc_to_tcp_timewait_sock(sk_common
);
243 return dump_tw_sock(seq
, tw
, uid
, seq_num
);
245 req
= bpf_skc_to_tcp_request_sock(sk_common
);
247 return dump_req_sock(seq
, req
, uid
, seq_num
);