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 .open = kcm_seq_open, 251 .read = seq_read, 252 .llseek = seq_lseek, 253 .release = seq_release_net, 254 }; 255 256 static struct kcm_seq_muxinfo kcm_seq_muxinfo = { 257 .name = "kcm", 258 .seq_fops = &kcm_seq_fops, 259 .seq_ops = { 260 .show = kcm_seq_show, 261 .start = kcm_seq_start, 262 .next = kcm_seq_next, 263 .stop = kcm_seq_stop, 264 } 265 }; 266 267 static int kcm_proc_register(struct net *net, struct kcm_seq_muxinfo *muxinfo) 268 { 269 struct proc_dir_entry *p; 270 int rc = 0; 271 272 p = proc_create_data(muxinfo->name, 0444, net->proc_net, 273 muxinfo->seq_fops, muxinfo); 274 if (!p) 275 rc = -ENOMEM; 276 return rc; 277 } 278 EXPORT_SYMBOL(kcm_proc_register); 279 280 static void kcm_proc_unregister(struct net *net, 281 struct kcm_seq_muxinfo *muxinfo) 282 { 283 remove_proc_entry(muxinfo->name, net->proc_net); 284 } 285 EXPORT_SYMBOL(kcm_proc_unregister); 286 287 static int kcm_stats_seq_show(struct seq_file *seq, void *v) 288 { 289 struct kcm_psock_stats psock_stats; 290 struct kcm_mux_stats mux_stats; 291 struct strp_aggr_stats strp_stats; 292 struct kcm_mux *mux; 293 struct kcm_psock *psock; 294 struct net *net = seq->private; 295 struct kcm_net *knet = net_generic(net, kcm_net_id); 296 297 memset(&mux_stats, 0, sizeof(mux_stats)); 298 memset(&psock_stats, 0, sizeof(psock_stats)); 299 memset(&strp_stats, 0, sizeof(strp_stats)); 300 301 mutex_lock(&knet->mutex); 302 303 aggregate_mux_stats(&knet->aggregate_mux_stats, &mux_stats); 304 aggregate_psock_stats(&knet->aggregate_psock_stats, 305 &psock_stats); 306 aggregate_strp_stats(&knet->aggregate_strp_stats, 307 &strp_stats); 308 309 list_for_each_entry_rcu(mux, &knet->mux_list, kcm_mux_list) { 310 spin_lock_bh(&mux->lock); 311 aggregate_mux_stats(&mux->stats, &mux_stats); 312 aggregate_psock_stats(&mux->aggregate_psock_stats, 313 &psock_stats); 314 aggregate_strp_stats(&mux->aggregate_strp_stats, 315 &strp_stats); 316 list_for_each_entry(psock, &mux->psocks, psock_list) { 317 aggregate_psock_stats(&psock->stats, &psock_stats); 318 save_strp_stats(&psock->strp, &strp_stats); 319 } 320 321 spin_unlock_bh(&mux->lock); 322 } 323 324 mutex_unlock(&knet->mutex); 325 326 seq_printf(seq, 327 "%-8s %-10s %-16s %-10s %-16s %-10s %-10s %-10s %-10s %-10s\n", 328 "MUX", 329 "RX-Msgs", 330 "RX-Bytes", 331 "TX-Msgs", 332 "TX-Bytes", 333 "TX-Retries", 334 "Attach", 335 "Unattach", 336 "UnattchRsvd", 337 "RX-RdyDrops"); 338 339 seq_printf(seq, 340 "%-8s %-10llu %-16llu %-10llu %-16llu %-10u %-10u %-10u %-10u %-10u\n", 341 "", 342 mux_stats.rx_msgs, 343 mux_stats.rx_bytes, 344 mux_stats.tx_msgs, 345 mux_stats.tx_bytes, 346 mux_stats.tx_retries, 347 mux_stats.psock_attach, 348 mux_stats.psock_unattach_rsvd, 349 mux_stats.psock_unattach, 350 mux_stats.rx_ready_drops); 351 352 seq_printf(seq, 353 "%-8s %-10s %-16s %-10s %-16s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s\n", 354 "Psock", 355 "RX-Msgs", 356 "RX-Bytes", 357 "TX-Msgs", 358 "TX-Bytes", 359 "Reserved", 360 "Unreserved", 361 "RX-Aborts", 362 "RX-Intr", 363 "RX-Unrecov", 364 "RX-MemFail", 365 "RX-NeedMor", 366 "RX-BadLen", 367 "RX-TooBig", 368 "RX-Timeout", 369 "TX-Aborts"); 370 371 seq_printf(seq, 372 "%-8s %-10llu %-16llu %-10llu %-16llu %-10llu %-10llu %-10u %-10u %-10u %-10u %-10u %-10u %-10u %-10u %-10u\n", 373 "", 374 strp_stats.msgs, 375 strp_stats.bytes, 376 psock_stats.tx_msgs, 377 psock_stats.tx_bytes, 378 psock_stats.reserved, 379 psock_stats.unreserved, 380 strp_stats.aborts, 381 strp_stats.interrupted, 382 strp_stats.unrecov_intr, 383 strp_stats.mem_fail, 384 strp_stats.need_more_hdr, 385 strp_stats.bad_hdr_len, 386 strp_stats.msg_too_big, 387 strp_stats.msg_timeouts, 388 psock_stats.tx_aborts); 389 390 return 0; 391 } 392 393 static int kcm_stats_seq_open(struct inode *inode, struct file *file) 394 { 395 return single_open_net(inode, file, kcm_stats_seq_show); 396 } 397 398 static const struct file_operations kcm_stats_seq_fops = { 399 .open = kcm_stats_seq_open, 400 .read = seq_read, 401 .llseek = seq_lseek, 402 .release = single_release_net, 403 }; 404 405 static int kcm_proc_init_net(struct net *net) 406 { 407 int err; 408 409 if (!proc_create("kcm_stats", 0444, net->proc_net, 410 &kcm_stats_seq_fops)) { 411 err = -ENOMEM; 412 goto out_kcm_stats; 413 } 414 415 err = kcm_proc_register(net, &kcm_seq_muxinfo); 416 if (err) 417 goto out_kcm; 418 419 return 0; 420 421 out_kcm: 422 remove_proc_entry("kcm_stats", net->proc_net); 423 out_kcm_stats: 424 return err; 425 } 426 427 static void kcm_proc_exit_net(struct net *net) 428 { 429 kcm_proc_unregister(net, &kcm_seq_muxinfo); 430 remove_proc_entry("kcm_stats", net->proc_net); 431 } 432 433 static struct pernet_operations kcm_net_ops = { 434 .init = kcm_proc_init_net, 435 .exit = kcm_proc_exit_net, 436 }; 437 438 int __init kcm_proc_init(void) 439 { 440 return register_pernet_subsys(&kcm_net_ops); 441 } 442 443 void __exit kcm_proc_exit(void) 444 { 445 unregister_pernet_subsys(&kcm_net_ops); 446 } 447 448 #endif /* CONFIG_PROC_FS */ 449