kcmproc.c 10.0 KB

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