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 }; 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 kcm_mux *mux; 282 struct kcm_psock *psock; 283 struct net *net = seq->private; 284 struct kcm_net *knet = net_generic(net, kcm_net_id); 285 286 memset(&mux_stats, 0, sizeof(mux_stats)); 287 memset(&psock_stats, 0, sizeof(psock_stats)); 288 289 mutex_lock(&knet->mutex); 290 291 aggregate_mux_stats(&knet->aggregate_mux_stats, &mux_stats); 292 aggregate_psock_stats(&knet->aggregate_psock_stats, 293 &psock_stats); 294 295 list_for_each_entry_rcu(mux, &knet->mux_list, kcm_mux_list) { 296 spin_lock_bh(&mux->lock); 297 aggregate_mux_stats(&mux->stats, &mux_stats); 298 aggregate_psock_stats(&mux->aggregate_psock_stats, 299 &psock_stats); 300 list_for_each_entry(psock, &mux->psocks, psock_list) 301 aggregate_psock_stats(&psock->stats, &psock_stats); 302 spin_unlock_bh(&mux->lock); 303 } 304 305 mutex_unlock(&knet->mutex); 306 307 seq_printf(seq, 308 "%-8s %-10s %-16s %-10s %-16s %-10s %-10s %-10s %-10s %-10s\n", 309 "MUX", 310 "RX-Msgs", 311 "RX-Bytes", 312 "TX-Msgs", 313 "TX-Bytes", 314 "TX-Retries", 315 "Attach", 316 "Unattach", 317 "UnattchRsvd", 318 "RX-RdyDrops"); 319 320 seq_printf(seq, 321 "%-8s %-10llu %-16llu %-10llu %-16llu %-10u %-10u %-10u %-10u %-10u\n", 322 "", 323 mux_stats.rx_msgs, 324 mux_stats.rx_bytes, 325 mux_stats.tx_msgs, 326 mux_stats.tx_bytes, 327 mux_stats.tx_retries, 328 mux_stats.psock_attach, 329 mux_stats.psock_unattach_rsvd, 330 mux_stats.psock_unattach, 331 mux_stats.rx_ready_drops); 332 333 seq_printf(seq, 334 "%-8s %-10s %-16s %-10s %-16s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s\n", 335 "Psock", 336 "RX-Msgs", 337 "RX-Bytes", 338 "TX-Msgs", 339 "TX-Bytes", 340 "Reserved", 341 "Unreserved", 342 "RX-Aborts", 343 "RX-MemFail", 344 "RX-NeedMor", 345 "RX-BadLen", 346 "RX-TooBig", 347 "RX-Timeout", 348 "TX-Aborts"); 349 350 seq_printf(seq, 351 "%-8s %-10llu %-16llu %-10llu %-16llu %-10llu %-10llu %-10u %-10u %-10u %-10u %-10u %-10u %-10u\n", 352 "", 353 psock_stats.rx_msgs, 354 psock_stats.rx_bytes, 355 psock_stats.tx_msgs, 356 psock_stats.tx_bytes, 357 psock_stats.reserved, 358 psock_stats.unreserved, 359 psock_stats.rx_aborts, 360 psock_stats.rx_mem_fail, 361 psock_stats.rx_need_more_hdr, 362 psock_stats.rx_bad_hdr_len, 363 psock_stats.rx_msg_too_big, 364 psock_stats.rx_msg_timeouts, 365 psock_stats.tx_aborts); 366 367 return 0; 368 } 369 370 static int kcm_stats_seq_open(struct inode *inode, struct file *file) 371 { 372 return single_open_net(inode, file, kcm_stats_seq_show); 373 } 374 375 static const struct file_operations kcm_stats_seq_fops = { 376 .owner = THIS_MODULE, 377 .open = kcm_stats_seq_open, 378 .read = seq_read, 379 .llseek = seq_lseek, 380 .release = single_release_net, 381 }; 382 383 static int kcm_proc_init_net(struct net *net) 384 { 385 int err; 386 387 if (!proc_create("kcm_stats", S_IRUGO, net->proc_net, 388 &kcm_stats_seq_fops)) { 389 err = -ENOMEM; 390 goto out_kcm_stats; 391 } 392 393 err = kcm_proc_register(net, &kcm_seq_muxinfo); 394 if (err) 395 goto out_kcm; 396 397 return 0; 398 399 out_kcm: 400 remove_proc_entry("kcm_stats", net->proc_net); 401 out_kcm_stats: 402 return err; 403 } 404 405 static void kcm_proc_exit_net(struct net *net) 406 { 407 kcm_proc_unregister(net, &kcm_seq_muxinfo); 408 remove_proc_entry("kcm_stats", net->proc_net); 409 } 410 411 static struct pernet_operations kcm_net_ops = { 412 .init = kcm_proc_init_net, 413 .exit = kcm_proc_exit_net, 414 }; 415 416 int __init kcm_proc_init(void) 417 { 418 return register_pernet_subsys(&kcm_net_ops); 419 } 420 421 void __exit kcm_proc_exit(void) 422 { 423 unregister_pernet_subsys(&kcm_net_ops); 424 } 425 426 #endif /* CONFIG_PROC_FS */ 427