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_tcp_sock(struct seq_file
*seq
, struct tcp_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 inet_sock
*inet
;
81 unsigned long timer_expires
;
82 const struct sock
*sp
;
89 icsk
= &tp
->inet_conn
;
90 inet
= &icsk
->icsk_inet
;
92 fastopenq
= &icsk
->icsk_accept_queue
.fastopenq
;
94 dest
= inet
->inet_daddr
;
95 src
= inet
->inet_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
->rcv_nxt
- tp
->copied_seq
;
124 BPF_SEQ_PRINTF(seq
, "%4d: %08X:%04X %08X:%04X ",
125 seq_num
, src
, srcp
, destp
, destp
);
126 BPF_SEQ_PRINTF(seq
, "%02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d ",
128 tp
->write_seq
- tp
->snd_una
, rx_queue
,
130 jiffies_delta_to_clock_t(timer_expires
- bpf_jiffies64()),
131 icsk
->icsk_retransmits
, uid
,
132 icsk
->icsk_probes_out
,
134 sp
->sk_refcnt
.refs
.counter
);
135 BPF_SEQ_PRINTF(seq
, "%pK %lu %lu %u %u %d\n",
137 jiffies_to_clock_t(icsk
->icsk_rto
),
138 jiffies_to_clock_t(icsk
->icsk_ack
.ato
),
139 (icsk
->icsk_ack
.quick
<< 1) | inet_csk_in_pingpong_mode(icsk
),
141 state
== TCP_LISTEN
? fastopenq
->max_qlen
142 : (tcp_in_initial_slowstart(tp
) ? -1 : tp
->snd_ssthresh
)
148 static int dump_tw_sock(struct seq_file
*seq
, struct tcp_timewait_sock
*ttw
,
149 uid_t uid
, __u32 seq_num
)
151 struct inet_timewait_sock
*tw
= &ttw
->tw_sk
;
156 delta
= tw
->tw_timer
.expires
- bpf_jiffies64();
158 src
= tw
->tw_rcv_saddr
;
159 destp
= bpf_ntohs(tw
->tw_dport
);
160 srcp
= bpf_ntohs(tw
->tw_sport
);
162 BPF_SEQ_PRINTF(seq
, "%4d: %08X:%04X %08X:%04X ",
163 seq_num
, src
, srcp
, dest
, destp
);
165 BPF_SEQ_PRINTF(seq
, "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK\n",
166 tw
->tw_substate
, 0, 0,
167 3, jiffies_delta_to_clock_t(delta
), 0, 0, 0, 0,
168 tw
->tw_refcnt
.refs
.counter
, tw
);
173 static int dump_req_sock(struct seq_file
*seq
, struct tcp_request_sock
*treq
,
174 uid_t uid
, __u32 seq_num
)
176 struct inet_request_sock
*irsk
= &treq
->req
;
177 struct request_sock
*req
= &irsk
->req
;
180 ttd
= req
->rsk_timer
.expires
- bpf_jiffies64();
185 BPF_SEQ_PRINTF(seq
, "%4d: %08X:%04X %08X:%04X ",
186 seq_num
, irsk
->ir_loc_addr
,
187 irsk
->ir_num
, irsk
->ir_rmt_addr
,
188 bpf_ntohs(irsk
->ir_rmt_port
));
189 BPF_SEQ_PRINTF(seq
, "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK\n",
190 TCP_SYN_RECV
, 0, 0, 1, jiffies_to_clock_t(ttd
),
191 req
->num_timeout
, uid
, 0, 0, 0, req
);
197 int dump_tcp4(struct bpf_iter__tcp
*ctx
)
199 struct sock_common
*sk_common
= ctx
->sk_common
;
200 struct seq_file
*seq
= ctx
->meta
->seq
;
201 struct tcp_timewait_sock
*tw
;
202 struct tcp_request_sock
*req
;
204 uid_t uid
= ctx
->uid
;
207 if (sk_common
== (void *)0)
210 seq_num
= ctx
->meta
->seq_num
;
212 BPF_SEQ_PRINTF(seq
, " sl "
215 "st tx_queue rx_queue tr tm->when retrnsmt"
216 " uid timeout inode\n");
218 if (sk_common
->skc_family
!= AF_INET
)
221 tp
= bpf_skc_to_tcp_sock(sk_common
);
223 return dump_tcp_sock(seq
, tp
, uid
, seq_num
);
225 tw
= bpf_skc_to_tcp_timewait_sock(sk_common
);
227 return dump_tw_sock(seq
, tw
, uid
, seq_num
);
229 req
= bpf_skc_to_tcp_request_sock(sk_common
);
231 return dump_req_sock(seq
, req
, uid
, seq_num
);