1 // SPDX-License-Identifier: GPL-2.0
3 #include <linux/inet.h>
4 #include <linux/list.h>
5 #include <linux/module.h>
7 #include <linux/proc_fs.h>
8 #include <linux/rculist.h>
9 #include <linux/seq_file.h>
10 #include <linux/socket.h>
11 #include <net/inet_sock.h>
13 #include <net/net_namespace.h>
14 #include <net/netns/generic.h>
18 struct kcm_seq_muxinfo
{
20 const struct file_operations
*seq_fops
;
21 const struct seq_operations seq_ops
;
24 static struct kcm_mux
*kcm_get_first(struct seq_file
*seq
)
26 struct net
*net
= seq_file_net(seq
);
27 struct kcm_net
*knet
= net_generic(net
, kcm_net_id
);
29 return list_first_or_null_rcu(&knet
->mux_list
,
30 struct kcm_mux
, kcm_mux_list
);
33 static struct kcm_mux
*kcm_get_next(struct kcm_mux
*mux
)
35 struct kcm_net
*knet
= mux
->knet
;
37 return list_next_or_null_rcu(&knet
->mux_list
, &mux
->kcm_mux_list
,
38 struct kcm_mux
, kcm_mux_list
);
41 static struct kcm_mux
*kcm_get_idx(struct seq_file
*seq
, loff_t pos
)
43 struct net
*net
= seq_file_net(seq
);
44 struct kcm_net
*knet
= net_generic(net
, kcm_net_id
);
47 list_for_each_entry_rcu(m
, &knet
->mux_list
, kcm_mux_list
) {
55 static void *kcm_seq_next(struct seq_file
*seq
, void *v
, loff_t
*pos
)
59 if (v
== SEQ_START_TOKEN
)
60 p
= kcm_get_first(seq
);
67 static void *kcm_seq_start(struct seq_file
*seq
, loff_t
*pos
)
73 return SEQ_START_TOKEN
;
75 return kcm_get_idx(seq
, *pos
- 1);
78 static void kcm_seq_stop(struct seq_file
*seq
, void *v
)
84 struct kcm_proc_mux_state
{
85 struct seq_net_private p
;
89 static int kcm_seq_open(struct inode
*inode
, struct file
*file
)
91 struct kcm_seq_muxinfo
*muxinfo
= PDE_DATA(inode
);
93 return seq_open_net(inode
, file
, &muxinfo
->seq_ops
,
94 sizeof(struct kcm_proc_mux_state
));
97 static void kcm_format_mux_header(struct seq_file
*seq
)
99 struct net
*net
= seq_file_net(seq
);
100 struct kcm_net
*knet
= net_generic(net
, kcm_net_id
);
103 "*** KCM statistics (%d MUX) ****\n",
107 "%-14s %-10s %-16s %-10s %-16s %-8s %-8s %-8s %-8s %s",
119 /* XXX: pdsts header stuff here */
123 static void kcm_format_sock(struct kcm_sock
*kcm
, struct seq_file
*seq
,
127 " kcm-%-7u %-10llu %-16llu %-10llu %-16llu %-8d %-8d %-8d %-8s ",
133 kcm
->sk
.sk_receive_queue
.qlen
,
134 sk_rmem_alloc_get(&kcm
->sk
),
135 kcm
->sk
.sk_write_queue
.qlen
,
139 seq_printf(seq
, "Psck-%u ", kcm
->tx_psock
->index
);
142 seq_puts(seq
, "TxWait ");
144 if (kcm
->tx_wait_more
)
145 seq_puts(seq
, "WMore ");
148 seq_puts(seq
, "RxWait ");
153 static void kcm_format_psock(struct kcm_psock
*psock
, struct seq_file
*seq
,
157 " psock-%-5u %-10llu %-16llu %-10llu %-16llu %-8d %-8d %-8d %-8d ",
159 psock
->strp
.stats
.msgs
,
160 psock
->strp
.stats
.bytes
,
161 psock
->stats
.tx_msgs
,
162 psock
->stats
.tx_bytes
,
163 psock
->sk
->sk_receive_queue
.qlen
,
164 atomic_read(&psock
->sk
->sk_rmem_alloc
),
165 psock
->sk
->sk_write_queue
.qlen
,
166 refcount_read(&psock
->sk
->sk_wmem_alloc
));
169 seq_puts(seq
, "Done ");
171 if (psock
->tx_stopped
)
172 seq_puts(seq
, "TxStop ");
174 if (psock
->strp
.stopped
)
175 seq_puts(seq
, "RxStop ");
178 seq_printf(seq
, "Rsvd-%d ", psock
->tx_kcm
->index
);
180 if (!psock
->strp
.paused
&& !psock
->ready_rx_msg
) {
181 if (psock
->sk
->sk_receive_queue
.qlen
) {
182 if (psock
->strp
.need_bytes
)
183 seq_printf(seq
, "RxWait=%u ",
184 psock
->strp
.need_bytes
);
186 seq_printf(seq
, "RxWait ");
189 if (psock
->strp
.paused
)
190 seq_puts(seq
, "RxPause ");
192 if (psock
->ready_rx_msg
)
193 seq_puts(seq
, "RdyRx ");
200 kcm_format_mux(struct kcm_mux
*mux
, loff_t idx
, struct seq_file
*seq
)
203 struct kcm_sock
*kcm
;
204 struct kcm_psock
*psock
;
206 /* mux information */
208 "%-6s%-8s %-10llu %-16llu %-10llu %-16llu %-8s %-8s %-8s %-8s ",
216 seq_printf(seq
, "KCMs: %d, Psocks %d\n",
217 mux
->kcm_socks_cnt
, mux
->psocks_cnt
);
219 /* kcm sock information */
221 spin_lock_bh(&mux
->lock
);
222 list_for_each_entry(kcm
, &mux
->kcm_socks
, kcm_sock_list
) {
223 kcm_format_sock(kcm
, seq
, i
, &len
);
227 list_for_each_entry(psock
, &mux
->psocks
, psock_list
) {
228 kcm_format_psock(psock
, seq
, i
, &len
);
231 spin_unlock_bh(&mux
->lock
);
234 static int kcm_seq_show(struct seq_file
*seq
, void *v
)
236 struct kcm_proc_mux_state
*mux_state
;
238 mux_state
= seq
->private;
239 if (v
== SEQ_START_TOKEN
) {
241 kcm_format_mux_header(seq
);
243 kcm_format_mux(v
, mux_state
->idx
, seq
);
249 static const struct file_operations kcm_seq_fops
= {
250 .owner
= THIS_MODULE
,
251 .open
= kcm_seq_open
,
254 .release
= seq_release_net
,
257 static struct kcm_seq_muxinfo kcm_seq_muxinfo
= {
259 .seq_fops
= &kcm_seq_fops
,
261 .show
= kcm_seq_show
,
262 .start
= kcm_seq_start
,
263 .next
= kcm_seq_next
,
264 .stop
= kcm_seq_stop
,
268 static int kcm_proc_register(struct net
*net
, struct kcm_seq_muxinfo
*muxinfo
)
270 struct proc_dir_entry
*p
;
273 p
= proc_create_data(muxinfo
->name
, S_IRUGO
, net
->proc_net
,
274 muxinfo
->seq_fops
, muxinfo
);
279 EXPORT_SYMBOL(kcm_proc_register
);
281 static void kcm_proc_unregister(struct net
*net
,
282 struct kcm_seq_muxinfo
*muxinfo
)
284 remove_proc_entry(muxinfo
->name
, net
->proc_net
);
286 EXPORT_SYMBOL(kcm_proc_unregister
);
288 static int kcm_stats_seq_show(struct seq_file
*seq
, void *v
)
290 struct kcm_psock_stats psock_stats
;
291 struct kcm_mux_stats mux_stats
;
292 struct strp_aggr_stats strp_stats
;
294 struct kcm_psock
*psock
;
295 struct net
*net
= seq
->private;
296 struct kcm_net
*knet
= net_generic(net
, kcm_net_id
);
298 memset(&mux_stats
, 0, sizeof(mux_stats
));
299 memset(&psock_stats
, 0, sizeof(psock_stats
));
300 memset(&strp_stats
, 0, sizeof(strp_stats
));
302 mutex_lock(&knet
->mutex
);
304 aggregate_mux_stats(&knet
->aggregate_mux_stats
, &mux_stats
);
305 aggregate_psock_stats(&knet
->aggregate_psock_stats
,
307 aggregate_strp_stats(&knet
->aggregate_strp_stats
,
310 list_for_each_entry_rcu(mux
, &knet
->mux_list
, kcm_mux_list
) {
311 spin_lock_bh(&mux
->lock
);
312 aggregate_mux_stats(&mux
->stats
, &mux_stats
);
313 aggregate_psock_stats(&mux
->aggregate_psock_stats
,
315 aggregate_strp_stats(&mux
->aggregate_strp_stats
,
317 list_for_each_entry(psock
, &mux
->psocks
, psock_list
) {
318 aggregate_psock_stats(&psock
->stats
, &psock_stats
);
319 save_strp_stats(&psock
->strp
, &strp_stats
);
322 spin_unlock_bh(&mux
->lock
);
325 mutex_unlock(&knet
->mutex
);
328 "%-8s %-10s %-16s %-10s %-16s %-10s %-10s %-10s %-10s %-10s\n",
341 "%-8s %-10llu %-16llu %-10llu %-16llu %-10u %-10u %-10u %-10u %-10u\n",
347 mux_stats
.tx_retries
,
348 mux_stats
.psock_attach
,
349 mux_stats
.psock_unattach_rsvd
,
350 mux_stats
.psock_unattach
,
351 mux_stats
.rx_ready_drops
);
354 "%-8s %-10s %-16s %-10s %-16s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s\n",
373 "%-8s %-10llu %-16llu %-10llu %-16llu %-10llu %-10llu %-10u %-10u %-10u %-10u %-10u %-10u %-10u %-10u %-10u\n",
378 psock_stats
.tx_bytes
,
379 psock_stats
.reserved
,
380 psock_stats
.unreserved
,
382 strp_stats
.interrupted
,
383 strp_stats
.unrecov_intr
,
385 strp_stats
.need_more_hdr
,
386 strp_stats
.bad_hdr_len
,
387 strp_stats
.msg_too_big
,
388 strp_stats
.msg_timeouts
,
389 psock_stats
.tx_aborts
);
394 static int kcm_stats_seq_open(struct inode
*inode
, struct file
*file
)
396 return single_open_net(inode
, file
, kcm_stats_seq_show
);
399 static const struct file_operations kcm_stats_seq_fops
= {
400 .owner
= THIS_MODULE
,
401 .open
= kcm_stats_seq_open
,
404 .release
= single_release_net
,
407 static int kcm_proc_init_net(struct net
*net
)
411 if (!proc_create("kcm_stats", S_IRUGO
, net
->proc_net
,
412 &kcm_stats_seq_fops
)) {
417 err
= kcm_proc_register(net
, &kcm_seq_muxinfo
);
424 remove_proc_entry("kcm_stats", net
->proc_net
);
429 static void kcm_proc_exit_net(struct net
*net
)
431 kcm_proc_unregister(net
, &kcm_seq_muxinfo
);
432 remove_proc_entry("kcm_stats", net
->proc_net
);
435 static struct pernet_operations kcm_net_ops
= {
436 .init
= kcm_proc_init_net
,
437 .exit
= kcm_proc_exit_net
,
440 int __init
kcm_proc_init(void)
442 return register_pernet_subsys(&kcm_net_ops
);
445 void __exit
kcm_proc_exit(void)
447 unregister_pernet_subsys(&kcm_net_ops
);
450 #endif /* CONFIG_PROC_FS */