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->strp.rx_paused) 177 seq_puts(seq, "RxPause "); 178 179 if (psock->tx_kcm) 180 seq_printf(seq, "Rsvd-%d ", psock->tx_kcm->index); 181 182 if (psock->ready_rx_msg) 183 seq_puts(seq, "RdyRx "); 184 185 seq_puts(seq, "\n"); 186 } 187 188 static void 189 kcm_format_mux(struct kcm_mux *mux, loff_t idx, struct seq_file *seq) 190 { 191 int i, len; 192 struct kcm_sock *kcm; 193 struct kcm_psock *psock; 194 195 /* mux information */ 196 seq_printf(seq, 197 "%-6s%-8s %-10llu %-16llu %-10llu %-16llu %-8s %-8s %-8s %-8s ", 198 "mux", "", 199 mux->stats.rx_msgs, 200 mux->stats.rx_bytes, 201 mux->stats.tx_msgs, 202 mux->stats.tx_bytes, 203 "-", "-", "-", "-"); 204 205 seq_printf(seq, "KCMs: %d, Psocks %d\n", 206 mux->kcm_socks_cnt, mux->psocks_cnt); 207 208 /* kcm sock information */ 209 i = 0; 210 spin_lock_bh(&mux->lock); 211 list_for_each_entry(kcm, &mux->kcm_socks, kcm_sock_list) { 212 kcm_format_sock(kcm, seq, i, &len); 213 i++; 214 } 215 i = 0; 216 list_for_each_entry(psock, &mux->psocks, psock_list) { 217 kcm_format_psock(psock, seq, i, &len); 218 i++; 219 } 220 spin_unlock_bh(&mux->lock); 221 } 222 223 static int kcm_seq_show(struct seq_file *seq, void *v) 224 { 225 struct kcm_proc_mux_state *mux_state; 226 227 mux_state = seq->private; 228 if (v == SEQ_START_TOKEN) { 229 mux_state->idx = 0; 230 kcm_format_mux_header(seq); 231 } else { 232 kcm_format_mux(v, mux_state->idx, seq); 233 mux_state->idx++; 234 } 235 return 0; 236 } 237 238 static const struct file_operations kcm_seq_fops = { 239 .owner = THIS_MODULE, 240 .open = kcm_seq_open, 241 .read = seq_read, 242 .llseek = seq_lseek, 243 .release = seq_release_net, 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 strp_aggr_stats strp_stats; 282 struct kcm_mux *mux; 283 struct kcm_psock *psock; 284 struct net *net = seq->private; 285 struct kcm_net *knet = net_generic(net, kcm_net_id); 286 287 memset(&mux_stats, 0, sizeof(mux_stats)); 288 memset(&psock_stats, 0, sizeof(psock_stats)); 289 memset(&strp_stats, 0, sizeof(strp_stats)); 290 291 mutex_lock(&knet->mutex); 292 293 aggregate_mux_stats(&knet->aggregate_mux_stats, &mux_stats); 294 aggregate_psock_stats(&knet->aggregate_psock_stats, 295 &psock_stats); 296 aggregate_strp_stats(&knet->aggregate_strp_stats, 297 &strp_stats); 298 299 list_for_each_entry_rcu(mux, &knet->mux_list, kcm_mux_list) { 300 spin_lock_bh(&mux->lock); 301 aggregate_mux_stats(&mux->stats, &mux_stats); 302 aggregate_psock_stats(&mux->aggregate_psock_stats, 303 &psock_stats); 304 aggregate_strp_stats(&mux->aggregate_strp_stats, 305 &strp_stats); 306 list_for_each_entry(psock, &mux->psocks, psock_list) { 307 aggregate_psock_stats(&psock->stats, &psock_stats); 308 save_strp_stats(&psock->strp, &strp_stats); 309 } 310 311 spin_unlock_bh(&mux->lock); 312 } 313 314 mutex_unlock(&knet->mutex); 315 316 seq_printf(seq, 317 "%-8s %-10s %-16s %-10s %-16s %-10s %-10s %-10s %-10s %-10s\n", 318 "MUX", 319 "RX-Msgs", 320 "RX-Bytes", 321 "TX-Msgs", 322 "TX-Bytes", 323 "TX-Retries", 324 "Attach", 325 "Unattach", 326 "UnattchRsvd", 327 "RX-RdyDrops"); 328 329 seq_printf(seq, 330 "%-8s %-10llu %-16llu %-10llu %-16llu %-10u %-10u %-10u %-10u %-10u\n", 331 "", 332 mux_stats.rx_msgs, 333 mux_stats.rx_bytes, 334 mux_stats.tx_msgs, 335 mux_stats.tx_bytes, 336 mux_stats.tx_retries, 337 mux_stats.psock_attach, 338 mux_stats.psock_unattach_rsvd, 339 mux_stats.psock_unattach, 340 mux_stats.rx_ready_drops); 341 342 seq_printf(seq, 343 "%-8s %-10s %-16s %-10s %-16s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s\n", 344 "Psock", 345 "RX-Msgs", 346 "RX-Bytes", 347 "TX-Msgs", 348 "TX-Bytes", 349 "Reserved", 350 "Unreserved", 351 "RX-Aborts", 352 "RX-Intr", 353 "RX-Unrecov", 354 "RX-MemFail", 355 "RX-NeedMor", 356 "RX-BadLen", 357 "RX-TooBig", 358 "RX-Timeout", 359 "TX-Aborts"); 360 361 seq_printf(seq, 362 "%-8s %-10llu %-16llu %-10llu %-16llu %-10llu %-10llu %-10u %-10u %-10u %-10u %-10u %-10u %-10u %-10u %-10u\n", 363 "", 364 strp_stats.rx_msgs, 365 strp_stats.rx_bytes, 366 psock_stats.tx_msgs, 367 psock_stats.tx_bytes, 368 psock_stats.reserved, 369 psock_stats.unreserved, 370 strp_stats.rx_aborts, 371 strp_stats.rx_interrupted, 372 strp_stats.rx_unrecov_intr, 373 strp_stats.rx_mem_fail, 374 strp_stats.rx_need_more_hdr, 375 strp_stats.rx_bad_hdr_len, 376 strp_stats.rx_msg_too_big, 377 strp_stats.rx_msg_timeouts, 378 psock_stats.tx_aborts); 379 380 return 0; 381 } 382 383 static int kcm_stats_seq_open(struct inode *inode, struct file *file) 384 { 385 return single_open_net(inode, file, kcm_stats_seq_show); 386 } 387 388 static const struct file_operations kcm_stats_seq_fops = { 389 .owner = THIS_MODULE, 390 .open = kcm_stats_seq_open, 391 .read = seq_read, 392 .llseek = seq_lseek, 393 .release = single_release_net, 394 }; 395 396 static int kcm_proc_init_net(struct net *net) 397 { 398 int err; 399 400 if (!proc_create("kcm_stats", S_IRUGO, net->proc_net, 401 &kcm_stats_seq_fops)) { 402 err = -ENOMEM; 403 goto out_kcm_stats; 404 } 405 406 err = kcm_proc_register(net, &kcm_seq_muxinfo); 407 if (err) 408 goto out_kcm; 409 410 return 0; 411 412 out_kcm: 413 remove_proc_entry("kcm_stats", net->proc_net); 414 out_kcm_stats: 415 return err; 416 } 417 418 static void kcm_proc_exit_net(struct net *net) 419 { 420 kcm_proc_unregister(net, &kcm_seq_muxinfo); 421 remove_proc_entry("kcm_stats", net->proc_net); 422 } 423 424 static struct pernet_operations kcm_net_ops = { 425 .init = kcm_proc_init_net, 426 .exit = kcm_proc_exit_net, 427 }; 428 429 int __init kcm_proc_init(void) 430 { 431 return register_pernet_subsys(&kcm_net_ops); 432 } 433 434 void __exit kcm_proc_exit(void) 435 { 436 unregister_pernet_subsys(&kcm_net_ops); 437 } 438 439 #endif /* CONFIG_PROC_FS */ 440