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 92 return seq_open_net(inode, file, &muxinfo->seq_ops, 93 sizeof(struct kcm_proc_mux_state)); 94 } 95 96 static void kcm_format_mux_header(struct seq_file *seq) 97 { 98 struct net *net = seq_file_net(seq); 99 struct kcm_net *knet = net_generic(net, kcm_net_id); 100 101 seq_printf(seq, 102 "*** KCM statistics (%d MUX) ****\n", 103 knet->count); 104 105 seq_printf(seq, 106 "%-14s %-10s %-16s %-10s %-16s %-8s %-8s %-8s %-8s %s", 107 "Object", 108 "RX-Msgs", 109 "RX-Bytes", 110 "TX-Msgs", 111 "TX-Bytes", 112 "Recv-Q", 113 "Rmem", 114 "Send-Q", 115 "Smem", 116 "Status"); 117 118 /* XXX: pdsts header stuff here */ 119 seq_puts(seq, "\n"); 120 } 121 122 static void kcm_format_sock(struct kcm_sock *kcm, struct seq_file *seq, 123 int i, int *len) 124 { 125 seq_printf(seq, 126 " kcm-%-7u %-10llu %-16llu %-10llu %-16llu %-8d %-8d %-8d %-8s ", 127 kcm->index, 128 kcm->stats.rx_msgs, 129 kcm->stats.rx_bytes, 130 kcm->stats.tx_msgs, 131 kcm->stats.tx_bytes, 132 kcm->sk.sk_receive_queue.qlen, 133 sk_rmem_alloc_get(&kcm->sk), 134 kcm->sk.sk_write_queue.qlen, 135 "-"); 136 137 if (kcm->tx_psock) 138 seq_printf(seq, "Psck-%u ", kcm->tx_psock->index); 139 140 if (kcm->tx_wait) 141 seq_puts(seq, "TxWait "); 142 143 if (kcm->tx_wait_more) 144 seq_puts(seq, "WMore "); 145 146 if (kcm->rx_wait) 147 seq_puts(seq, "RxWait "); 148 149 seq_puts(seq, "\n"); 150 } 151 152 static void kcm_format_psock(struct kcm_psock *psock, struct seq_file *seq, 153 int i, int *len) 154 { 155 seq_printf(seq, 156 " psock-%-5u %-10llu %-16llu %-10llu %-16llu %-8d %-8d %-8d %-8d ", 157 psock->index, 158 psock->strp.stats.rx_msgs, 159 psock->strp.stats.rx_bytes, 160 psock->stats.tx_msgs, 161 psock->stats.tx_bytes, 162 psock->sk->sk_receive_queue.qlen, 163 atomic_read(&psock->sk->sk_rmem_alloc), 164 psock->sk->sk_write_queue.qlen, 165 atomic_read(&psock->sk->sk_wmem_alloc)); 166 167 if (psock->done) 168 seq_puts(seq, "Done "); 169 170 if (psock->tx_stopped) 171 seq_puts(seq, "TxStop "); 172 173 if (psock->strp.rx_stopped) 174 seq_puts(seq, "RxStop "); 175 176 if (psock->tx_kcm) 177 seq_printf(seq, "Rsvd-%d ", psock->tx_kcm->index); 178 179 if (!psock->strp.rx_paused && !psock->ready_rx_msg) { 180 if (psock->sk->sk_receive_queue.qlen) { 181 if (psock->strp.rx_need_bytes) 182 seq_printf(seq, "RxWait=%u ", 183 psock->strp.rx_need_bytes); 184 else 185 seq_printf(seq, "RxWait "); 186 } 187 } else { 188 if (psock->strp.rx_paused) 189 seq_puts(seq, "RxPause "); 190 191 if (psock->ready_rx_msg) 192 seq_puts(seq, "RdyRx "); 193 } 194 195 seq_puts(seq, "\n"); 196 } 197 198 static void 199 kcm_format_mux(struct kcm_mux *mux, loff_t idx, struct seq_file *seq) 200 { 201 int i, len; 202 struct kcm_sock *kcm; 203 struct kcm_psock *psock; 204 205 /* mux information */ 206 seq_printf(seq, 207 "%-6s%-8s %-10llu %-16llu %-10llu %-16llu %-8s %-8s %-8s %-8s ", 208 "mux", "", 209 mux->stats.rx_msgs, 210 mux->stats.rx_bytes, 211 mux->stats.tx_msgs, 212 mux->stats.tx_bytes, 213 "-", "-", "-", "-"); 214 215 seq_printf(seq, "KCMs: %d, Psocks %d\n", 216 mux->kcm_socks_cnt, mux->psocks_cnt); 217 218 /* kcm sock information */ 219 i = 0; 220 spin_lock_bh(&mux->lock); 221 list_for_each_entry(kcm, &mux->kcm_socks, kcm_sock_list) { 222 kcm_format_sock(kcm, seq, i, &len); 223 i++; 224 } 225 i = 0; 226 list_for_each_entry(psock, &mux->psocks, psock_list) { 227 kcm_format_psock(psock, seq, i, &len); 228 i++; 229 } 230 spin_unlock_bh(&mux->lock); 231 } 232 233 static int kcm_seq_show(struct seq_file *seq, void *v) 234 { 235 struct kcm_proc_mux_state *mux_state; 236 237 mux_state = seq->private; 238 if (v == SEQ_START_TOKEN) { 239 mux_state->idx = 0; 240 kcm_format_mux_header(seq); 241 } else { 242 kcm_format_mux(v, mux_state->idx, seq); 243 mux_state->idx++; 244 } 245 return 0; 246 } 247 248 static const struct file_operations kcm_seq_fops = { 249 .owner = THIS_MODULE, 250 .open = kcm_seq_open, 251 .read = seq_read, 252 .llseek = seq_lseek, 253 .release = seq_release_net, 254 }; 255 256 static struct kcm_seq_muxinfo kcm_seq_muxinfo = { 257 .name = "kcm", 258 .seq_fops = &kcm_seq_fops, 259 .seq_ops = { 260 .show = kcm_seq_show, 261 .start = kcm_seq_start, 262 .next = kcm_seq_next, 263 .stop = kcm_seq_stop, 264 } 265 }; 266 267 static int kcm_proc_register(struct net *net, struct kcm_seq_muxinfo *muxinfo) 268 { 269 struct proc_dir_entry *p; 270 int rc = 0; 271 272 p = proc_create_data(muxinfo->name, S_IRUGO, net->proc_net, 273 muxinfo->seq_fops, muxinfo); 274 if (!p) 275 rc = -ENOMEM; 276 return rc; 277 } 278 EXPORT_SYMBOL(kcm_proc_register); 279 280 static void kcm_proc_unregister(struct net *net, 281 struct kcm_seq_muxinfo *muxinfo) 282 { 283 remove_proc_entry(muxinfo->name, net->proc_net); 284 } 285 EXPORT_SYMBOL(kcm_proc_unregister); 286 287 static int kcm_stats_seq_show(struct seq_file *seq, void *v) 288 { 289 struct kcm_psock_stats psock_stats; 290 struct kcm_mux_stats mux_stats; 291 struct strp_aggr_stats strp_stats; 292 struct kcm_mux *mux; 293 struct kcm_psock *psock; 294 struct net *net = seq->private; 295 struct kcm_net *knet = net_generic(net, kcm_net_id); 296 297 memset(&mux_stats, 0, sizeof(mux_stats)); 298 memset(&psock_stats, 0, sizeof(psock_stats)); 299 memset(&strp_stats, 0, sizeof(strp_stats)); 300 301 mutex_lock(&knet->mutex); 302 303 aggregate_mux_stats(&knet->aggregate_mux_stats, &mux_stats); 304 aggregate_psock_stats(&knet->aggregate_psock_stats, 305 &psock_stats); 306 aggregate_strp_stats(&knet->aggregate_strp_stats, 307 &strp_stats); 308 309 list_for_each_entry_rcu(mux, &knet->mux_list, kcm_mux_list) { 310 spin_lock_bh(&mux->lock); 311 aggregate_mux_stats(&mux->stats, &mux_stats); 312 aggregate_psock_stats(&mux->aggregate_psock_stats, 313 &psock_stats); 314 aggregate_strp_stats(&mux->aggregate_strp_stats, 315 &strp_stats); 316 list_for_each_entry(psock, &mux->psocks, psock_list) { 317 aggregate_psock_stats(&psock->stats, &psock_stats); 318 save_strp_stats(&psock->strp, &strp_stats); 319 } 320 321 spin_unlock_bh(&mux->lock); 322 } 323 324 mutex_unlock(&knet->mutex); 325 326 seq_printf(seq, 327 "%-8s %-10s %-16s %-10s %-16s %-10s %-10s %-10s %-10s %-10s\n", 328 "MUX", 329 "RX-Msgs", 330 "RX-Bytes", 331 "TX-Msgs", 332 "TX-Bytes", 333 "TX-Retries", 334 "Attach", 335 "Unattach", 336 "UnattchRsvd", 337 "RX-RdyDrops"); 338 339 seq_printf(seq, 340 "%-8s %-10llu %-16llu %-10llu %-16llu %-10u %-10u %-10u %-10u %-10u\n", 341 "", 342 mux_stats.rx_msgs, 343 mux_stats.rx_bytes, 344 mux_stats.tx_msgs, 345 mux_stats.tx_bytes, 346 mux_stats.tx_retries, 347 mux_stats.psock_attach, 348 mux_stats.psock_unattach_rsvd, 349 mux_stats.psock_unattach, 350 mux_stats.rx_ready_drops); 351 352 seq_printf(seq, 353 "%-8s %-10s %-16s %-10s %-16s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s\n", 354 "Psock", 355 "RX-Msgs", 356 "RX-Bytes", 357 "TX-Msgs", 358 "TX-Bytes", 359 "Reserved", 360 "Unreserved", 361 "RX-Aborts", 362 "RX-Intr", 363 "RX-Unrecov", 364 "RX-MemFail", 365 "RX-NeedMor", 366 "RX-BadLen", 367 "RX-TooBig", 368 "RX-Timeout", 369 "TX-Aborts"); 370 371 seq_printf(seq, 372 "%-8s %-10llu %-16llu %-10llu %-16llu %-10llu %-10llu %-10u %-10u %-10u %-10u %-10u %-10u %-10u %-10u %-10u\n", 373 "", 374 strp_stats.rx_msgs, 375 strp_stats.rx_bytes, 376 psock_stats.tx_msgs, 377 psock_stats.tx_bytes, 378 psock_stats.reserved, 379 psock_stats.unreserved, 380 strp_stats.rx_aborts, 381 strp_stats.rx_interrupted, 382 strp_stats.rx_unrecov_intr, 383 strp_stats.rx_mem_fail, 384 strp_stats.rx_need_more_hdr, 385 strp_stats.rx_bad_hdr_len, 386 strp_stats.rx_msg_too_big, 387 strp_stats.rx_msg_timeouts, 388 psock_stats.tx_aborts); 389 390 return 0; 391 } 392 393 static int kcm_stats_seq_open(struct inode *inode, struct file *file) 394 { 395 return single_open_net(inode, file, kcm_stats_seq_show); 396 } 397 398 static const struct file_operations kcm_stats_seq_fops = { 399 .owner = THIS_MODULE, 400 .open = kcm_stats_seq_open, 401 .read = seq_read, 402 .llseek = seq_lseek, 403 .release = single_release_net, 404 }; 405 406 static int kcm_proc_init_net(struct net *net) 407 { 408 int err; 409 410 if (!proc_create("kcm_stats", S_IRUGO, net->proc_net, 411 &kcm_stats_seq_fops)) { 412 err = -ENOMEM; 413 goto out_kcm_stats; 414 } 415 416 err = kcm_proc_register(net, &kcm_seq_muxinfo); 417 if (err) 418 goto out_kcm; 419 420 return 0; 421 422 out_kcm: 423 remove_proc_entry("kcm_stats", net->proc_net); 424 out_kcm_stats: 425 return err; 426 } 427 428 static void kcm_proc_exit_net(struct net *net) 429 { 430 kcm_proc_unregister(net, &kcm_seq_muxinfo); 431 remove_proc_entry("kcm_stats", net->proc_net); 432 } 433 434 static struct pernet_operations kcm_net_ops = { 435 .init = kcm_proc_init_net, 436 .exit = kcm_proc_exit_net, 437 }; 438 439 int __init kcm_proc_init(void) 440 { 441 return register_pernet_subsys(&kcm_net_ops); 442 } 443 444 void __exit kcm_proc_exit(void) 445 { 446 unregister_pernet_subsys(&kcm_net_ops); 447 } 448 449 #endif /* CONFIG_PROC_FS */ 450