Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.4.
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright (c) 2020 Facebook */
  3#include "bpf_iter.h"
  4#include "bpf_tracing_net.h"
  5#include <bpf/bpf_helpers.h>
  6#include <bpf/bpf_tracing.h>
  7#include <bpf/bpf_endian.h>
  8
  9char _license[] SEC("license") = "GPL";
 10
 11static int hlist_unhashed_lockless(const struct hlist_node *h)
 12{
 13        return !(h->pprev);
 14}
 15
 16static int timer_pending(const struct timer_list * timer)
 17{
 18	return !hlist_unhashed_lockless(&timer->entry);
 19}
 20
 21extern unsigned CONFIG_HZ __kconfig;
 22
 23#define USER_HZ		100
 24#define NSEC_PER_SEC	1000000000ULL
 25static clock_t jiffies_to_clock_t(unsigned long x)
 26{
 27	/* The implementation here tailored to a particular
 28	 * setting of USER_HZ.
 29	 */
 30	u64 tick_nsec = (NSEC_PER_SEC + CONFIG_HZ/2) / CONFIG_HZ;
 31	u64 user_hz_nsec = NSEC_PER_SEC / USER_HZ;
 32
 33	if ((tick_nsec % user_hz_nsec) == 0) {
 34		if (CONFIG_HZ < USER_HZ)
 35			return x * (USER_HZ / CONFIG_HZ);
 36		else
 37			return x / (CONFIG_HZ / USER_HZ);
 38	}
 39	return x * tick_nsec/user_hz_nsec;
 40}
 41
 42static clock_t jiffies_delta_to_clock_t(long delta)
 43{
 44	if (delta <= 0)
 45		return 0;
 46
 47	return jiffies_to_clock_t(delta);
 48}
 49
 50static long sock_i_ino(const struct sock *sk)
 51{
 52	const struct socket *sk_socket = sk->sk_socket;
 53	const struct inode *inode;
 54	unsigned long ino;
 55
 56	if (!sk_socket)
 57		return 0;
 58
 59	inode = &container_of(sk_socket, struct socket_alloc, socket)->vfs_inode;
 60	bpf_probe_read_kernel(&ino, sizeof(ino), &inode->i_ino);
 61	return ino;
 62}
 63
 64static bool
 65inet_csk_in_pingpong_mode(const struct inet_connection_sock *icsk)
 66{
 67	return icsk->icsk_ack.pingpong >= TCP_PINGPONG_THRESH;
 68}
 69
 70static bool tcp_in_initial_slowstart(const struct tcp_sock *tcp)
 71{
 72	return tcp->snd_ssthresh >= TCP_INFINITE_SSTHRESH;
 73}
 74
 75static int dump_tcp_sock(struct seq_file *seq, struct tcp_sock *tp,
 76			 uid_t uid, __u32 seq_num)
 77{
 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;
 83	__u16 destp, srcp;
 84	__be32 dest, src;
 85	int timer_active;
 86	int rx_queue;
 87	int state;
 88
 89	icsk = &tp->inet_conn;
 90	inet = &icsk->icsk_inet;
 91	sp = &inet->sk;
 92	fastopenq = &icsk->icsk_accept_queue.fastopenq;
 93
 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);
 98
 99	if (icsk->icsk_pending == ICSK_TIME_RETRANS ||
100	    icsk->icsk_pending == ICSK_TIME_REO_TIMEOUT ||
101	    icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) {
102		timer_active = 1;
103		timer_expires = icsk->icsk_timeout;
104	} else if (icsk->icsk_pending == ICSK_TIME_PROBE0) {
105		timer_active = 4;
106		timer_expires = icsk->icsk_timeout;
107	} else if (timer_pending(&sp->sk_timer)) {
108		timer_active = 2;
109		timer_expires = sp->sk_timer.expires;
110	} else {
111		timer_active = 0;
112		timer_expires = bpf_jiffies64();
113	}
114
115	state = sp->sk_state;
116	if (state == TCP_LISTEN) {
117		rx_queue = sp->sk_ack_backlog;
118	} else {
119		rx_queue = tp->rcv_nxt - tp->copied_seq;
120		if (rx_queue < 0)
121			rx_queue = 0;
122	}
123
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 ",
127		       state,
128		       tp->write_seq - tp->snd_una, rx_queue,
129		       timer_active,
130		       jiffies_delta_to_clock_t(timer_expires - bpf_jiffies64()),
131		       icsk->icsk_retransmits, uid,
132		       icsk->icsk_probes_out,
133		       sock_i_ino(sp),
134		       sp->sk_refcnt.refs.counter);
135	BPF_SEQ_PRINTF(seq, "%pK %lu %lu %u %u %d\n",
136		       tp,
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),
140		       tp->snd_cwnd,
141		       state == TCP_LISTEN ? fastopenq->max_qlen
142				: (tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh)
143		      );
144
145	return 0;
146}
147
148static int dump_tw_sock(struct seq_file *seq, struct tcp_timewait_sock *ttw,
149			uid_t uid, __u32 seq_num)
150{
151	struct inet_timewait_sock *tw = &ttw->tw_sk;
152	__u16 destp, srcp;
153	__be32 dest, src;
154	long delta;
155
156	delta = tw->tw_timer.expires - bpf_jiffies64();
157	dest = tw->tw_daddr;
158	src  = tw->tw_rcv_saddr;
159	destp = bpf_ntohs(tw->tw_dport);
160	srcp  = bpf_ntohs(tw->tw_sport);
161
162	BPF_SEQ_PRINTF(seq, "%4d: %08X:%04X %08X:%04X ",
163		       seq_num, src, srcp, dest, destp);
164
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);
169
170	return 0;
171}
172
173static int dump_req_sock(struct seq_file *seq, struct tcp_request_sock *treq,
174			 uid_t uid, __u32 seq_num)
175{
176	struct inet_request_sock *irsk = &treq->req;
177	struct request_sock *req = &irsk->req;
178	long ttd;
179
180	ttd = req->rsk_timer.expires - bpf_jiffies64();
181
182	if (ttd < 0)
183		ttd = 0;
184
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);
192
193	return 0;
194}
195
196SEC("iter/tcp")
197int dump_tcp4(struct bpf_iter__tcp *ctx)
198{
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;
203	struct tcp_sock *tp;
204	uid_t uid = ctx->uid;
205	__u32 seq_num;
206
207	if (sk_common == (void *)0)
208		return 0;
209
210	seq_num = ctx->meta->seq_num;
211	if (seq_num == 0)
212		BPF_SEQ_PRINTF(seq, "  sl  "
213				    "local_address "
214				    "rem_address   "
215				    "st tx_queue rx_queue tr tm->when retrnsmt"
216				    "   uid  timeout inode\n");
217
218	if (sk_common->skc_family != AF_INET)
219		return 0;
220
221	tp = bpf_skc_to_tcp_sock(sk_common);
222	if (tp)
223		return dump_tcp_sock(seq, tp, uid, seq_num);
224
225	tw = bpf_skc_to_tcp_timewait_sock(sk_common);
226	if (tw)
227		return dump_tw_sock(seq, tw, uid, seq_num);
228
229	req = bpf_skc_to_tcp_request_sock(sk_common);
230	if (req)
231		return dump_req_sock(seq, req, uid, seq_num);
232
233	return 0;
234}