diff options
Diffstat (limited to 'net/kcm/kcmproc.c')
-rw-r--r-- | net/kcm/kcmproc.c | 426 |
1 files changed, 426 insertions, 0 deletions
diff --git a/net/kcm/kcmproc.c b/net/kcm/kcmproc.c new file mode 100644 index 000000000000..738008726cc6 --- /dev/null +++ b/net/kcm/kcmproc.c | |||
@@ -0,0 +1,426 @@ | |||
1 | #include <linux/in.h> | ||
2 | #include <linux/inet.h> | ||
3 | #include <linux/list.h> | ||
4 | #include <linux/module.h> | ||
5 | #include <linux/net.h> | ||
6 | #include <linux/proc_fs.h> | ||
7 | #include <linux/rculist.h> | ||
8 | #include <linux/seq_file.h> | ||
9 | #include <linux/socket.h> | ||
10 | #include <net/inet_sock.h> | ||
11 | #include <net/kcm.h> | ||
12 | #include <net/net_namespace.h> | ||
13 | #include <net/netns/generic.h> | ||
14 | #include <net/tcp.h> | ||
15 | |||
16 | #ifdef CONFIG_PROC_FS | ||
17 | struct kcm_seq_muxinfo { | ||
18 | char *name; | ||
19 | const struct file_operations *seq_fops; | ||
20 | const struct seq_operations seq_ops; | ||
21 | }; | ||
22 | |||
23 | static struct kcm_mux *kcm_get_first(struct seq_file *seq) | ||
24 | { | ||
25 | struct net *net = seq_file_net(seq); | ||
26 | struct kcm_net *knet = net_generic(net, kcm_net_id); | ||
27 | |||
28 | return list_first_or_null_rcu(&knet->mux_list, | ||
29 | struct kcm_mux, kcm_mux_list); | ||
30 | } | ||
31 | |||
32 | static struct kcm_mux *kcm_get_next(struct kcm_mux *mux) | ||
33 | { | ||
34 | struct kcm_net *knet = mux->knet; | ||
35 | |||
36 | return list_next_or_null_rcu(&knet->mux_list, &mux->kcm_mux_list, | ||
37 | struct kcm_mux, kcm_mux_list); | ||
38 | } | ||
39 | |||
40 | static struct kcm_mux *kcm_get_idx(struct seq_file *seq, loff_t pos) | ||
41 | { | ||
42 | struct net *net = seq_file_net(seq); | ||
43 | struct kcm_net *knet = net_generic(net, kcm_net_id); | ||
44 | struct kcm_mux *m; | ||
45 | |||
46 | list_for_each_entry_rcu(m, &knet->mux_list, kcm_mux_list) { | ||
47 | if (!pos) | ||
48 | return m; | ||
49 | --pos; | ||
50 | } | ||
51 | return NULL; | ||
52 | } | ||
53 | |||
54 | static void *kcm_seq_next(struct seq_file *seq, void *v, loff_t *pos) | ||
55 | { | ||
56 | void *p; | ||
57 | |||
58 | if (v == SEQ_START_TOKEN) | ||
59 | p = kcm_get_first(seq); | ||
60 | else | ||
61 | p = kcm_get_next(v); | ||
62 | ++*pos; | ||
63 | return p; | ||
64 | } | ||
65 | |||
66 | static void *kcm_seq_start(struct seq_file *seq, loff_t *pos) | ||
67 | __acquires(rcu) | ||
68 | { | ||
69 | rcu_read_lock(); | ||
70 | |||
71 | if (!*pos) | ||
72 | return SEQ_START_TOKEN; | ||
73 | else | ||
74 | return kcm_get_idx(seq, *pos - 1); | ||
75 | } | ||
76 | |||
77 | static void kcm_seq_stop(struct seq_file *seq, void *v) | ||
78 | __releases(rcu) | ||
79 | { | ||
80 | rcu_read_unlock(); | ||
81 | } | ||
82 | |||
83 | struct kcm_proc_mux_state { | ||
84 | struct seq_net_private p; | ||
85 | int idx; | ||
86 | }; | ||
87 | |||
88 | static int kcm_seq_open(struct inode *inode, struct file *file) | ||
89 | { | ||
90 | struct kcm_seq_muxinfo *muxinfo = PDE_DATA(inode); | ||
91 | int err; | ||
92 | |||
93 | err = seq_open_net(inode, file, &muxinfo->seq_ops, | ||
94 | sizeof(struct kcm_proc_mux_state)); | ||
95 | if (err < 0) | ||
96 | return err; | ||
97 | return err; | ||
98 | } | ||
99 | |||
100 | static void kcm_format_mux_header(struct seq_file *seq) | ||
101 | { | ||
102 | struct net *net = seq_file_net(seq); | ||
103 | struct kcm_net *knet = net_generic(net, kcm_net_id); | ||
104 | |||
105 | seq_printf(seq, | ||
106 | "*** KCM statistics (%d MUX) ****\n", | ||
107 | knet->count); | ||
108 | |||
109 | seq_printf(seq, | ||
110 | "%-14s %-10s %-16s %-10s %-16s %-8s %-8s %-8s %-8s %s", | ||
111 | "Object", | ||
112 | "RX-Msgs", | ||
113 | "RX-Bytes", | ||
114 | "TX-Msgs", | ||
115 | "TX-Bytes", | ||
116 | "Recv-Q", | ||
117 | "Rmem", | ||
118 | "Send-Q", | ||
119 | "Smem", | ||
120 | "Status"); | ||
121 | |||
122 | /* XXX: pdsts header stuff here */ | ||
123 | seq_puts(seq, "\n"); | ||
124 | } | ||
125 | |||
126 | static void kcm_format_sock(struct kcm_sock *kcm, struct seq_file *seq, | ||
127 | int i, int *len) | ||
128 | { | ||
129 | seq_printf(seq, | ||
130 | " kcm-%-7u %-10llu %-16llu %-10llu %-16llu %-8d %-8d %-8d %-8s ", | ||
131 | kcm->index, | ||
132 | kcm->stats.rx_msgs, | ||
133 | kcm->stats.rx_bytes, | ||
134 | kcm->stats.tx_msgs, | ||
135 | kcm->stats.tx_bytes, | ||
136 | kcm->sk.sk_receive_queue.qlen, | ||
137 | sk_rmem_alloc_get(&kcm->sk), | ||
138 | kcm->sk.sk_write_queue.qlen, | ||
139 | "-"); | ||
140 | |||
141 | if (kcm->tx_psock) | ||
142 | seq_printf(seq, "Psck-%u ", kcm->tx_psock->index); | ||
143 | |||
144 | if (kcm->tx_wait) | ||
145 | seq_puts(seq, "TxWait "); | ||
146 | |||
147 | if (kcm->tx_wait_more) | ||
148 | seq_puts(seq, "WMore "); | ||
149 | |||
150 | if (kcm->rx_wait) | ||
151 | seq_puts(seq, "RxWait "); | ||
152 | |||
153 | seq_puts(seq, "\n"); | ||
154 | } | ||
155 | |||
156 | static void kcm_format_psock(struct kcm_psock *psock, struct seq_file *seq, | ||
157 | int i, int *len) | ||
158 | { | ||
159 | seq_printf(seq, | ||
160 | " psock-%-5u %-10llu %-16llu %-10llu %-16llu %-8d %-8d %-8d %-8d ", | ||
161 | psock->index, | ||
162 | psock->stats.rx_msgs, | ||
163 | psock->stats.rx_bytes, | ||
164 | psock->stats.tx_msgs, | ||
165 | psock->stats.tx_bytes, | ||
166 | psock->sk->sk_receive_queue.qlen, | ||
167 | atomic_read(&psock->sk->sk_rmem_alloc), | ||
168 | psock->sk->sk_write_queue.qlen, | ||
169 | atomic_read(&psock->sk->sk_wmem_alloc)); | ||
170 | |||
171 | if (psock->done) | ||
172 | seq_puts(seq, "Done "); | ||
173 | |||
174 | if (psock->tx_stopped) | ||
175 | seq_puts(seq, "TxStop "); | ||
176 | |||
177 | if (psock->rx_stopped) | ||
178 | seq_puts(seq, "RxStop "); | ||
179 | |||
180 | if (psock->tx_kcm) | ||
181 | seq_printf(seq, "Rsvd-%d ", psock->tx_kcm->index); | ||
182 | |||
183 | if (psock->ready_rx_msg) | ||
184 | seq_puts(seq, "RdyRx "); | ||
185 | |||
186 | seq_puts(seq, "\n"); | ||
187 | } | ||
188 | |||
189 | static void | ||
190 | kcm_format_mux(struct kcm_mux *mux, loff_t idx, struct seq_file *seq) | ||
191 | { | ||
192 | int i, len; | ||
193 | struct kcm_sock *kcm; | ||
194 | struct kcm_psock *psock; | ||
195 | |||
196 | /* mux information */ | ||
197 | seq_printf(seq, | ||
198 | "%-6s%-8s %-10llu %-16llu %-10llu %-16llu %-8s %-8s %-8s %-8s ", | ||
199 | "mux", "", | ||
200 | mux->stats.rx_msgs, | ||
201 | mux->stats.rx_bytes, | ||
202 | mux->stats.tx_msgs, | ||
203 | mux->stats.tx_bytes, | ||
204 | "-", "-", "-", "-"); | ||
205 | |||
206 | seq_printf(seq, "KCMs: %d, Psocks %d\n", | ||
207 | mux->kcm_socks_cnt, mux->psocks_cnt); | ||
208 | |||
209 | /* kcm sock information */ | ||
210 | i = 0; | ||
211 | spin_lock_bh(&mux->lock); | ||
212 | list_for_each_entry(kcm, &mux->kcm_socks, kcm_sock_list) { | ||
213 | kcm_format_sock(kcm, seq, i, &len); | ||
214 | i++; | ||
215 | } | ||
216 | i = 0; | ||
217 | list_for_each_entry(psock, &mux->psocks, psock_list) { | ||
218 | kcm_format_psock(psock, seq, i, &len); | ||
219 | i++; | ||
220 | } | ||
221 | spin_unlock_bh(&mux->lock); | ||
222 | } | ||
223 | |||
224 | static int kcm_seq_show(struct seq_file *seq, void *v) | ||
225 | { | ||
226 | struct kcm_proc_mux_state *mux_state; | ||
227 | |||
228 | mux_state = seq->private; | ||
229 | if (v == SEQ_START_TOKEN) { | ||
230 | mux_state->idx = 0; | ||
231 | kcm_format_mux_header(seq); | ||
232 | } else { | ||
233 | kcm_format_mux(v, mux_state->idx, seq); | ||
234 | mux_state->idx++; | ||
235 | } | ||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | static const struct file_operations kcm_seq_fops = { | ||
240 | .owner = THIS_MODULE, | ||
241 | .open = kcm_seq_open, | ||
242 | .read = seq_read, | ||
243 | .llseek = seq_lseek, | ||
244 | }; | ||
245 | |||
246 | static struct kcm_seq_muxinfo kcm_seq_muxinfo = { | ||
247 | .name = "kcm", | ||
248 | .seq_fops = &kcm_seq_fops, | ||
249 | .seq_ops = { | ||
250 | .show = kcm_seq_show, | ||
251 | .start = kcm_seq_start, | ||
252 | .next = kcm_seq_next, | ||
253 | .stop = kcm_seq_stop, | ||
254 | } | ||
255 | }; | ||
256 | |||
257 | static int kcm_proc_register(struct net *net, struct kcm_seq_muxinfo *muxinfo) | ||
258 | { | ||
259 | struct proc_dir_entry *p; | ||
260 | int rc = 0; | ||
261 | |||
262 | p = proc_create_data(muxinfo->name, S_IRUGO, net->proc_net, | ||
263 | muxinfo->seq_fops, muxinfo); | ||
264 | if (!p) | ||
265 | rc = -ENOMEM; | ||
266 | return rc; | ||
267 | } | ||
268 | EXPORT_SYMBOL(kcm_proc_register); | ||
269 | |||
270 | static void kcm_proc_unregister(struct net *net, | ||
271 | struct kcm_seq_muxinfo *muxinfo) | ||
272 | { | ||
273 | remove_proc_entry(muxinfo->name, net->proc_net); | ||
274 | } | ||
275 | EXPORT_SYMBOL(kcm_proc_unregister); | ||
276 | |||
277 | static int kcm_stats_seq_show(struct seq_file *seq, void *v) | ||
278 | { | ||
279 | struct kcm_psock_stats psock_stats; | ||
280 | struct kcm_mux_stats mux_stats; | ||
281 | struct kcm_mux *mux; | ||
282 | struct kcm_psock *psock; | ||
283 | struct net *net = seq->private; | ||
284 | struct kcm_net *knet = net_generic(net, kcm_net_id); | ||
285 | |||
286 | memset(&mux_stats, 0, sizeof(mux_stats)); | ||
287 | memset(&psock_stats, 0, sizeof(psock_stats)); | ||
288 | |||
289 | mutex_lock(&knet->mutex); | ||
290 | |||
291 | aggregate_mux_stats(&knet->aggregate_mux_stats, &mux_stats); | ||
292 | aggregate_psock_stats(&knet->aggregate_psock_stats, | ||
293 | &psock_stats); | ||
294 | |||
295 | list_for_each_entry_rcu(mux, &knet->mux_list, kcm_mux_list) { | ||
296 | spin_lock_bh(&mux->lock); | ||
297 | aggregate_mux_stats(&mux->stats, &mux_stats); | ||
298 | aggregate_psock_stats(&mux->aggregate_psock_stats, | ||
299 | &psock_stats); | ||
300 | list_for_each_entry(psock, &mux->psocks, psock_list) | ||
301 | aggregate_psock_stats(&psock->stats, &psock_stats); | ||
302 | spin_unlock_bh(&mux->lock); | ||
303 | } | ||
304 | |||
305 | mutex_unlock(&knet->mutex); | ||
306 | |||
307 | seq_printf(seq, | ||
308 | "%-8s %-10s %-16s %-10s %-16s %-10s %-10s %-10s %-10s %-10s\n", | ||
309 | "MUX", | ||
310 | "RX-Msgs", | ||
311 | "RX-Bytes", | ||
312 | "TX-Msgs", | ||
313 | "TX-Bytes", | ||
314 | "TX-Retries", | ||
315 | "Attach", | ||
316 | "Unattach", | ||
317 | "UnattchRsvd", | ||
318 | "RX-RdyDrops"); | ||
319 | |||
320 | seq_printf(seq, | ||
321 | "%-8s %-10llu %-16llu %-10llu %-16llu %-10u %-10u %-10u %-10u %-10u\n", | ||
322 | "", | ||
323 | mux_stats.rx_msgs, | ||
324 | mux_stats.rx_bytes, | ||
325 | mux_stats.tx_msgs, | ||
326 | mux_stats.tx_bytes, | ||
327 | mux_stats.tx_retries, | ||
328 | mux_stats.psock_attach, | ||
329 | mux_stats.psock_unattach_rsvd, | ||
330 | mux_stats.psock_unattach, | ||
331 | mux_stats.rx_ready_drops); | ||
332 | |||
333 | seq_printf(seq, | ||
334 | "%-8s %-10s %-16s %-10s %-16s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s\n", | ||
335 | "Psock", | ||
336 | "RX-Msgs", | ||
337 | "RX-Bytes", | ||
338 | "TX-Msgs", | ||
339 | "TX-Bytes", | ||
340 | "Reserved", | ||
341 | "Unreserved", | ||
342 | "RX-Aborts", | ||
343 | "RX-MemFail", | ||
344 | "RX-NeedMor", | ||
345 | "RX-BadLen", | ||
346 | "RX-TooBig", | ||
347 | "RX-Timeout", | ||
348 | "TX-Aborts"); | ||
349 | |||
350 | seq_printf(seq, | ||
351 | "%-8s %-10llu %-16llu %-10llu %-16llu %-10llu %-10llu %-10u %-10u %-10u %-10u %-10u %-10u %-10u\n", | ||
352 | "", | ||
353 | psock_stats.rx_msgs, | ||
354 | psock_stats.rx_bytes, | ||
355 | psock_stats.tx_msgs, | ||
356 | psock_stats.tx_bytes, | ||
357 | psock_stats.reserved, | ||
358 | psock_stats.unreserved, | ||
359 | psock_stats.rx_aborts, | ||
360 | psock_stats.rx_mem_fail, | ||
361 | psock_stats.rx_need_more_hdr, | ||
362 | psock_stats.rx_bad_hdr_len, | ||
363 | psock_stats.rx_msg_too_big, | ||
364 | psock_stats.rx_msg_timeouts, | ||
365 | psock_stats.tx_aborts); | ||
366 | |||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | static int kcm_stats_seq_open(struct inode *inode, struct file *file) | ||
371 | { | ||
372 | return single_open_net(inode, file, kcm_stats_seq_show); | ||
373 | } | ||
374 | |||
375 | static const struct file_operations kcm_stats_seq_fops = { | ||
376 | .owner = THIS_MODULE, | ||
377 | .open = kcm_stats_seq_open, | ||
378 | .read = seq_read, | ||
379 | .llseek = seq_lseek, | ||
380 | .release = single_release_net, | ||
381 | }; | ||
382 | |||
383 | static int kcm_proc_init_net(struct net *net) | ||
384 | { | ||
385 | int err; | ||
386 | |||
387 | if (!proc_create("kcm_stats", S_IRUGO, net->proc_net, | ||
388 | &kcm_stats_seq_fops)) { | ||
389 | err = -ENOMEM; | ||
390 | goto out_kcm_stats; | ||
391 | } | ||
392 | |||
393 | err = kcm_proc_register(net, &kcm_seq_muxinfo); | ||
394 | if (err) | ||
395 | goto out_kcm; | ||
396 | |||
397 | return 0; | ||
398 | |||
399 | out_kcm: | ||
400 | remove_proc_entry("kcm_stats", net->proc_net); | ||
401 | out_kcm_stats: | ||
402 | return err; | ||
403 | } | ||
404 | |||
405 | static void kcm_proc_exit_net(struct net *net) | ||
406 | { | ||
407 | kcm_proc_unregister(net, &kcm_seq_muxinfo); | ||
408 | remove_proc_entry("kcm_stats", net->proc_net); | ||
409 | } | ||
410 | |||
411 | static struct pernet_operations kcm_net_ops = { | ||
412 | .init = kcm_proc_init_net, | ||
413 | .exit = kcm_proc_exit_net, | ||
414 | }; | ||
415 | |||
416 | int __init kcm_proc_init(void) | ||
417 | { | ||
418 | return register_pernet_subsys(&kcm_net_ops); | ||
419 | } | ||
420 | |||
421 | void __exit kcm_proc_exit(void) | ||
422 | { | ||
423 | unregister_pernet_subsys(&kcm_net_ops); | ||
424 | } | ||
425 | |||
426 | #endif /* CONFIG_PROC_FS */ | ||