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