kcmproc.c 10 KB

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