kcmproc.c 8.7 KB

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