xref: /linux/tools/testing/selftests/bpf/progs/bpf_iter_netlink.c (revision c19b05b84ddece7708ed0537a92d1dfabdfd98fb)
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 
8 char _license[] SEC("license") = "GPL";
9 
10 #define sk_rmem_alloc	sk_backlog.rmem_alloc
11 #define sk_refcnt	__sk_common.skc_refcnt
12 
13 struct bpf_iter_meta {
14 	struct seq_file *seq;
15 	__u64 session_id;
16 	__u64 seq_num;
17 } __attribute__((preserve_access_index));
18 
19 struct bpf_iter__netlink {
20 	struct bpf_iter_meta *meta;
21 	struct netlink_sock *sk;
22 } __attribute__((preserve_access_index));
23 
24 static __attribute__((noinline)) struct inode *SOCK_INODE(struct socket *socket)
25 {
26 	return &container_of(socket, struct socket_alloc, socket)->vfs_inode;
27 }
28 
29 SEC("iter/netlink")
30 int dump_netlink(struct bpf_iter__netlink *ctx)
31 {
32 	struct seq_file *seq = ctx->meta->seq;
33 	struct netlink_sock *nlk = ctx->sk;
34 	unsigned long group, ino;
35 	struct inode *inode;
36 	struct socket *sk;
37 	struct sock *s;
38 
39 	if (nlk == (void *)0)
40 		return 0;
41 
42 	if (ctx->meta->seq_num == 0)
43 		BPF_SEQ_PRINTF(seq, "sk               Eth Pid        Groups   "
44 				    "Rmem     Wmem     Dump  Locks    Drops    "
45 				    "Inode\n");
46 
47 	s = &nlk->sk;
48 	BPF_SEQ_PRINTF(seq, "%pK %-3d ", s, s->sk_protocol);
49 
50 	if (!nlk->groups)  {
51 		group = 0;
52 	} else {
53 		/* FIXME: temporary use bpf_probe_read here, needs
54 		 * verifier support to do direct access.
55 		 */
56 		bpf_probe_read(&group, sizeof(group), &nlk->groups[0]);
57 	}
58 	BPF_SEQ_PRINTF(seq, "%-10u %08x %-8d %-8d %-5d %-8d ",
59 		       nlk->portid, (u32)group,
60 		       s->sk_rmem_alloc.counter,
61 		       s->sk_wmem_alloc.refs.counter - 1,
62 		       nlk->cb_running, s->sk_refcnt.refs.counter);
63 
64 	sk = s->sk_socket;
65 	if (!sk) {
66 		ino = 0;
67 	} else {
68 		/* FIXME: container_of inside SOCK_INODE has a forced
69 		 * type conversion, and direct access cannot be used
70 		 * with current verifier.
71 		 */
72 		inode = SOCK_INODE(sk);
73 		bpf_probe_read(&ino, sizeof(ino), &inode->i_ino);
74 	}
75 	BPF_SEQ_PRINTF(seq, "%-8u %-8lu\n", s->sk_drops.counter, ino);
76 
77 	return 0;
78 }
79