1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/in.h> 3 #include <linux/inet.h> 4 #include <linux/list.h> 5 #include <linux/module.h> 6 #include <linux/net.h> 7 #include <linux/proc_fs.h> 8 #include <linux/rculist.h> 9 #include <linux/seq_file.h> 10 #include <linux/socket.h> 11 #include <net/inet_sock.h> 12 #include <net/kcm.h> 13 #include <net/net_namespace.h> 14 #include <net/netns/generic.h> 15 #include <net/tcp.h> 16 17 #ifdef CONFIG_PROC_FS 18 struct kcm_seq_muxinfo { 19 char *name; 20 const struct file_operations *seq_fops; 21 const struct seq_operations seq_ops; 22 }; 23 24 static struct kcm_mux *kcm_get_first(struct seq_file *seq) 25 { 26 struct net *net = seq_file_net(seq); 27 struct kcm_net *knet = net_generic(net, kcm_net_id); 28 29 return list_first_or_null_rcu(&knet->mux_list, 30 struct kcm_mux, kcm_mux_list); 31 } 32 33 static struct kcm_mux *kcm_get_next(struct kcm_mux *mux) 34 { 35 struct kcm_net *knet = mux->knet; 36 37 return list_next_or_null_rcu(&knet->mux_list, &mux->kcm_mux_list, 38 struct kcm_mux, kcm_mux_list); 39 } 40 41 static struct kcm_mux *kcm_get_idx(struct seq_file *seq, loff_t pos) 42 { 43 struct net *net = seq_file_net(seq); 44 struct kcm_net *knet = net_generic(net, kcm_net_id); 45 struct kcm_mux *m; 46 47 list_for_each_entry_rcu(m, &knet->mux_list, kcm_mux_list) { 48 if (!pos) 49 return m; 50 --pos; 51 } 52 return NULL; 53 } 54 55 static void *kcm_seq_next(struct seq_file *seq, void *v, loff_t *pos) 56 { 57 void *p; 58 59 if (v == SEQ_START_TOKEN) 60 p = kcm_get_first(seq); 61 else 62 p = kcm_get_next(v); 63 ++*pos; 64 return p; 65 } 66 67 static void *kcm_seq_start(struct seq_file *seq, loff_t *pos) 68 __acquires(rcu) 69 { 70 rcu_read_lock(); 71 72 if (!*pos) 73 return SEQ_START_TOKEN; 74 else 75 return kcm_get_idx(seq, *pos - 1); 76 } 77 78 static void kcm_seq_stop(struct seq_file *seq, void *v) 79 __releases(rcu) 80 { 81 rcu_read_unlock(); 82 } 83 84 struct kcm_proc_mux_state { 85 struct seq_net_private p; 86 int idx; 87 }; 88 89 static int kcm_seq_open(struct inode *inode, struct file *file) 90 { 91 struct kcm_seq_muxinfo *muxinfo = PDE_DATA(inode); 92 93 return seq_open_net(inode, file, &muxinfo->seq_ops, 94 sizeof(struct kcm_proc_mux_state)); 95 } 96 97 static void kcm_format_mux_header(struct seq_file *seq) 98 { 99 struct net *net = seq_file_net(seq); 100 struct kcm_net *knet = net_generic(net, kcm_net_id); 101 102 seq_printf(seq, 103 "*** KCM statistics (%d MUX) ****\n", 104 knet->count); 105 106 seq_printf(seq, 107 "%-14s %-10s %-16s %-10s %-16s %-8s %-8s %-8s %-8s %s", 108 "Object", 109 "RX-Msgs", 110 "RX-Bytes", 111 "TX-Msgs", 112 "TX-Bytes", 113 "Recv-Q", 114 "Rmem", 115 "Send-Q", 116 "Smem", 117 "Status"); 118 119 /* XXX: pdsts header stuff here */ 120 seq_puts(seq, "\n"); 121 } 122 123 static void kcm_format_sock(struct kcm_sock *kcm, struct seq_file *seq, 124 int i, int *len) 125 { 126 seq_printf(seq, 127 " kcm-%-7u %-10llu %-16llu %-10llu %-16llu %-8d %-8d %-8d %-8s ", 128 kcm->index, 129 kcm->stats.rx_msgs, 130 kcm->stats.rx_bytes, 131 kcm->stats.tx_msgs, 132 kcm->stats.tx_bytes, 133 kcm->sk.sk_receive_queue.qlen, 134 sk_rmem_alloc_get(&kcm->sk), 135 kcm->sk.sk_write_queue.qlen, 136 "-"); 137 138 if (kcm->tx_psock) 139 seq_printf(seq, "Psck-%u ", kcm->tx_psock->index); 140 141 if (kcm->tx_wait) 142 seq_puts(seq, "TxWait "); 143 144 if (kcm->tx_wait_more) 145 seq_puts(seq, "WMore "); 146 147 if (kcm->rx_wait) 148 seq_puts(seq, "RxWait "); 149 150 seq_puts(seq, "\n"); 151 } 152 153 static void kcm_format_psock(struct kcm_psock *psock, struct seq_file *seq, 154 int i, int *len) 155 { 156 seq_printf(seq, 157 " psock-%-5u %-10llu %-16llu %-10llu %-16llu %-8d %-8d %-8d %-8d ", 158 psock->index, 159 psock->strp.stats.msgs, 160 psock->strp.stats.bytes, 161 psock->stats.tx_msgs, 162 psock->stats.tx_bytes, 163 psock->sk->sk_receive_queue.qlen, 164 atomic_read(&psock->sk->sk_rmem_alloc), 165 psock->sk->sk_write_queue.qlen, 166 refcount_read(&psock->sk->sk_wmem_alloc)); 167 168 if (psock->done) 169 seq_puts(seq, "Done "); 170 171 if (psock->tx_stopped) 172 seq_puts(seq, "TxStop "); 173 174 if (psock->strp.stopped) 175 seq_puts(seq, "RxStop "); 176 177 if (psock->tx_kcm) 178 seq_printf(seq, "Rsvd-%d ", psock->tx_kcm->index); 179 180 if (!psock->strp.paused && !psock->ready_rx_msg) { 181 if (psock->sk->sk_receive_queue.qlen) { 182 if (psock->strp.need_bytes) 183 seq_printf(seq, "RxWait=%u ", 184 psock->strp.need_bytes); 185 else 186 seq_printf(seq, "RxWait "); 187 } 188 } else { 189 if (psock->strp.paused) 190 seq_puts(seq, "RxPause "); 191 192 if (psock->ready_rx_msg) 193 seq_puts(seq, "RdyRx "); 194 } 195 196 seq_puts(seq, "\n"); 197 } 198 199 static void 200 kcm_format_mux(struct kcm_mux *mux, loff_t idx, struct seq_file *seq) 201 { 202 int i, len; 203 struct kcm_sock *kcm; 204 struct kcm_psock *psock; 205 206 /* mux information */ 207 seq_printf(seq, 208 "%-6s%-8s %-10llu %-16llu %-10llu %-16llu %-8s %-8s %-8s %-8s ", 209 "mux", "", 210 mux->stats.rx_msgs, 211 mux->stats.rx_bytes, 212 mux->stats.tx_msgs, 213 mux->stats.tx_bytes, 214 "-", "-", "-", "-"); 215 216 seq_printf(seq, "KCMs: %d, Psocks %d\n", 217 mux->kcm_socks_cnt, mux->psocks_cnt); 218 219 /* kcm sock information */ 220 i = 0; 221 spin_lock_bh(&mux->lock); 222 list_for_each_entry(kcm, &mux->kcm_socks, kcm_sock_list) { 223 kcm_format_sock(kcm, seq, i, &len); 224 i++; 225 } 226 i = 0; 227 list_for_each_entry(psock, &mux->psocks, psock_list) { 228 kcm_format_psock(psock, seq, i, &len); 229 i++; 230 } 231 spin_unlock_bh(&mux->lock); 232 } 233 234 static int kcm_seq_show(struct seq_file *seq, void *v) 235 { 236 struct kcm_proc_mux_state *mux_state; 237 238 mux_state = seq->private; 239 if (v == SEQ_START_TOKEN) { 240 mux_state->idx = 0; 241 kcm_format_mux_header(seq); 242 } else { 243 kcm_format_mux(v, mux_state->idx, seq); 244 mux_state->idx++; 245 } 246 return 0; 247 } 248 249 static const struct file_operations kcm_seq_fops = { 250 .owner = THIS_MODULE, 251 .open = kcm_seq_open, 252 .read = seq_read, 253 .llseek = seq_lseek, 254 .release = seq_release_net, 255 }; 256 257 static struct kcm_seq_muxinfo kcm_seq_muxinfo = { 258 .name = "kcm", 259 .seq_fops = &kcm_seq_fops, 260 .seq_ops = { 261 .show = kcm_seq_show, 262 .start = kcm_seq_start, 263 .next = kcm_seq_next, 264 .stop = kcm_seq_stop, 265 } 266 }; 267 268 static int kcm_proc_register(struct net *net, struct kcm_seq_muxinfo *muxinfo) 269 { 270 struct proc_dir_entry *p; 271 int rc = 0; 272 273 p = proc_create_data(muxinfo->name, S_IRUGO, net->proc_net, 274 muxinfo->seq_fops, muxinfo); 275 if (!p) 276 rc = -ENOMEM; 277 return rc; 278 } 279 EXPORT_SYMBOL(kcm_proc_register); 280 281 static void kcm_proc_unregister(struct net *net, 282 struct kcm_seq_muxinfo *muxinfo) 283 { 284 remove_proc_entry(muxinfo->name, net->proc_net); 285 } 286 EXPORT_SYMBOL(kcm_proc_unregister); 287 288 static int kcm_stats_seq_show(struct seq_file *seq, void *v) 289 { 290 struct kcm_psock_stats psock_stats; 291 struct kcm_mux_stats mux_stats; 292 struct strp_aggr_stats strp_stats; 293 struct kcm_mux *mux; 294 struct kcm_psock *psock; 295 struct net *net = seq->private; 296 struct kcm_net *knet = net_generic(net, kcm_net_id); 297 298 memset(&mux_stats, 0, sizeof(mux_stats)); 299 memset(&psock_stats, 0, sizeof(psock_stats)); 300 memset(&strp_stats, 0, sizeof(strp_stats)); 301 302 mutex_lock(&knet->mutex); 303 304 aggregate_mux_stats(&knet->aggregate_mux_stats, &mux_stats); 305 aggregate_psock_stats(&knet->aggregate_psock_stats, 306 &psock_stats); 307 aggregate_strp_stats(&knet->aggregate_strp_stats, 308 &strp_stats); 309 310 list_for_each_entry_rcu(mux, &knet->mux_list, kcm_mux_list) { 311 spin_lock_bh(&mux->lock); 312 aggregate_mux_stats(&mux->stats, &mux_stats); 313 aggregate_psock_stats(&mux->aggregate_psock_stats, 314 &psock_stats); 315 aggregate_strp_stats(&mux->aggregate_strp_stats, 316 &strp_stats); 317 list_for_each_entry(psock, &mux->psocks, psock_list) { 318 aggregate_psock_stats(&psock->stats, &psock_stats); 319 save_strp_stats(&psock->strp, &strp_stats); 320 } 321 322 spin_unlock_bh(&mux->lock); 323 } 324 325 mutex_unlock(&knet->mutex); 326 327 seq_printf(seq, 328 "%-8s %-10s %-16s %-10s %-16s %-10s %-10s %-10s %-10s %-10s\n", 329 "MUX", 330 "RX-Msgs", 331 "RX-Bytes", 332 "TX-Msgs", 333 "TX-Bytes", 334 "TX-Retries", 335 "Attach", 336 "Unattach", 337 "UnattchRsvd", 338 "RX-RdyDrops"); 339 340 seq_printf(seq, 341 "%-8s %-10llu %-16llu %-10llu %-16llu %-10u %-10u %-10u %-10u %-10u\n", 342 "", 343 mux_stats.rx_msgs, 344 mux_stats.rx_bytes, 345 mux_stats.tx_msgs, 346 mux_stats.tx_bytes, 347 mux_stats.tx_retries, 348 mux_stats.psock_attach, 349 mux_stats.psock_unattach_rsvd, 350 mux_stats.psock_unattach, 351 mux_stats.rx_ready_drops); 352 353 seq_printf(seq, 354 "%-8s %-10s %-16s %-10s %-16s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s\n", 355 "Psock", 356 "RX-Msgs", 357 "RX-Bytes", 358 "TX-Msgs", 359 "TX-Bytes", 360 "Reserved", 361 "Unreserved", 362 "RX-Aborts", 363 "RX-Intr", 364 "RX-Unrecov", 365 "RX-MemFail", 366 "RX-NeedMor", 367 "RX-BadLen", 368 "RX-TooBig", 369 "RX-Timeout", 370 "TX-Aborts"); 371 372 seq_printf(seq, 373 "%-8s %-10llu %-16llu %-10llu %-16llu %-10llu %-10llu %-10u %-10u %-10u %-10u %-10u %-10u %-10u %-10u %-10u\n", 374 "", 375 strp_stats.msgs, 376 strp_stats.bytes, 377 psock_stats.tx_msgs, 378 psock_stats.tx_bytes, 379 psock_stats.reserved, 380 psock_stats.unreserved, 381 strp_stats.aborts, 382 strp_stats.interrupted, 383 strp_stats.unrecov_intr, 384 strp_stats.mem_fail, 385 strp_stats.need_more_hdr, 386 strp_stats.bad_hdr_len, 387 strp_stats.msg_too_big, 388 strp_stats.msg_timeouts, 389 psock_stats.tx_aborts); 390 391 return 0; 392 } 393 394 static int kcm_stats_seq_open(struct inode *inode, struct file *file) 395 { 396 return single_open_net(inode, file, kcm_stats_seq_show); 397 } 398 399 static const struct file_operations kcm_stats_seq_fops = { 400 .owner = THIS_MODULE, 401 .open = kcm_stats_seq_open, 402 .read = seq_read, 403 .llseek = seq_lseek, 404 .release = single_release_net, 405 }; 406 407 static int kcm_proc_init_net(struct net *net) 408 { 409 int err; 410 411 if (!proc_create("kcm_stats", S_IRUGO, net->proc_net, 412 &kcm_stats_seq_fops)) { 413 err = -ENOMEM; 414 goto out_kcm_stats; 415 } 416 417 err = kcm_proc_register(net, &kcm_seq_muxinfo); 418 if (err) 419 goto out_kcm; 420 421 return 0; 422 423 out_kcm: 424 remove_proc_entry("kcm_stats", net->proc_net); 425 out_kcm_stats: 426 return err; 427 } 428 429 static void kcm_proc_exit_net(struct net *net) 430 { 431 kcm_proc_unregister(net, &kcm_seq_muxinfo); 432 remove_proc_entry("kcm_stats", net->proc_net); 433 } 434 435 static struct pernet_operations kcm_net_ops = { 436 .init = kcm_proc_init_net, 437 .exit = kcm_proc_exit_net, 438 }; 439 440 int __init kcm_proc_init(void) 441 { 442 return register_pernet_subsys(&kcm_net_ops); 443 } 444 445 void __exit kcm_proc_exit(void) 446 { 447 unregister_pernet_subsys(&kcm_net_ops); 448 } 449 450 #endif /* CONFIG_PROC_FS */ 451