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