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