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 static struct kcm_mux *kcm_get_first(struct seq_file *seq) 19 { 20 struct net *net = seq_file_net(seq); 21 struct kcm_net *knet = net_generic(net, kcm_net_id); 22 23 return list_first_or_null_rcu(&knet->mux_list, 24 struct kcm_mux, kcm_mux_list); 25 } 26 27 static struct kcm_mux *kcm_get_next(struct kcm_mux *mux) 28 { 29 struct kcm_net *knet = mux->knet; 30 31 return list_next_or_null_rcu(&knet->mux_list, &mux->kcm_mux_list, 32 struct kcm_mux, kcm_mux_list); 33 } 34 35 static struct kcm_mux *kcm_get_idx(struct seq_file *seq, loff_t pos) 36 { 37 struct net *net = seq_file_net(seq); 38 struct kcm_net *knet = net_generic(net, kcm_net_id); 39 struct kcm_mux *m; 40 41 list_for_each_entry_rcu(m, &knet->mux_list, kcm_mux_list) { 42 if (!pos) 43 return m; 44 --pos; 45 } 46 return NULL; 47 } 48 49 static void *kcm_seq_next(struct seq_file *seq, void *v, loff_t *pos) 50 { 51 void *p; 52 53 if (v == SEQ_START_TOKEN) 54 p = kcm_get_first(seq); 55 else 56 p = kcm_get_next(v); 57 ++*pos; 58 return p; 59 } 60 61 static void *kcm_seq_start(struct seq_file *seq, loff_t *pos) 62 __acquires(rcu) 63 { 64 rcu_read_lock(); 65 66 if (!*pos) 67 return SEQ_START_TOKEN; 68 else 69 return kcm_get_idx(seq, *pos - 1); 70 } 71 72 static void kcm_seq_stop(struct seq_file *seq, void *v) 73 __releases(rcu) 74 { 75 rcu_read_unlock(); 76 } 77 78 struct kcm_proc_mux_state { 79 struct seq_net_private p; 80 int idx; 81 }; 82 83 static void kcm_format_mux_header(struct seq_file *seq) 84 { 85 struct net *net = seq_file_net(seq); 86 struct kcm_net *knet = net_generic(net, kcm_net_id); 87 88 seq_printf(seq, 89 "*** KCM statistics (%d MUX) ****\n", 90 knet->count); 91 92 seq_printf(seq, 93 "%-14s %-10s %-16s %-10s %-16s %-8s %-8s %-8s %-8s %s", 94 "Object", 95 "RX-Msgs", 96 "RX-Bytes", 97 "TX-Msgs", 98 "TX-Bytes", 99 "Recv-Q", 100 "Rmem", 101 "Send-Q", 102 "Smem", 103 "Status"); 104 105 /* XXX: pdsts header stuff here */ 106 seq_puts(seq, "\n"); 107 } 108 109 static void kcm_format_sock(struct kcm_sock *kcm, struct seq_file *seq, 110 int i, int *len) 111 { 112 seq_printf(seq, 113 " kcm-%-7u %-10llu %-16llu %-10llu %-16llu %-8d %-8d %-8d %-8s ", 114 kcm->index, 115 kcm->stats.rx_msgs, 116 kcm->stats.rx_bytes, 117 kcm->stats.tx_msgs, 118 kcm->stats.tx_bytes, 119 kcm->sk.sk_receive_queue.qlen, 120 sk_rmem_alloc_get(&kcm->sk), 121 kcm->sk.sk_write_queue.qlen, 122 "-"); 123 124 if (kcm->tx_psock) 125 seq_printf(seq, "Psck-%u ", kcm->tx_psock->index); 126 127 if (kcm->tx_wait) 128 seq_puts(seq, "TxWait "); 129 130 if (kcm->tx_wait_more) 131 seq_puts(seq, "WMore "); 132 133 if (kcm->rx_wait) 134 seq_puts(seq, "RxWait "); 135 136 seq_puts(seq, "\n"); 137 } 138 139 static void kcm_format_psock(struct kcm_psock *psock, struct seq_file *seq, 140 int i, int *len) 141 { 142 seq_printf(seq, 143 " psock-%-5u %-10llu %-16llu %-10llu %-16llu %-8d %-8d %-8d %-8d ", 144 psock->index, 145 psock->strp.stats.msgs, 146 psock->strp.stats.bytes, 147 psock->stats.tx_msgs, 148 psock->stats.tx_bytes, 149 psock->sk->sk_receive_queue.qlen, 150 atomic_read(&psock->sk->sk_rmem_alloc), 151 psock->sk->sk_write_queue.qlen, 152 refcount_read(&psock->sk->sk_wmem_alloc)); 153 154 if (psock->done) 155 seq_puts(seq, "Done "); 156 157 if (psock->tx_stopped) 158 seq_puts(seq, "TxStop "); 159 160 if (psock->strp.stopped) 161 seq_puts(seq, "RxStop "); 162 163 if (psock->tx_kcm) 164 seq_printf(seq, "Rsvd-%d ", psock->tx_kcm->index); 165 166 if (!psock->strp.paused && !psock->ready_rx_msg) { 167 if (psock->sk->sk_receive_queue.qlen) { 168 if (psock->strp.need_bytes) 169 seq_printf(seq, "RxWait=%u ", 170 psock->strp.need_bytes); 171 else 172 seq_printf(seq, "RxWait "); 173 } 174 } else { 175 if (psock->strp.paused) 176 seq_puts(seq, "RxPause "); 177 178 if (psock->ready_rx_msg) 179 seq_puts(seq, "RdyRx "); 180 } 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 seq_operations kcm_seq_ops = { 236 .show = kcm_seq_show, 237 .start = kcm_seq_start, 238 .next = kcm_seq_next, 239 .stop = kcm_seq_stop, 240 }; 241 242 static int kcm_stats_seq_show(struct seq_file *seq, void *v) 243 { 244 struct kcm_psock_stats psock_stats; 245 struct kcm_mux_stats mux_stats; 246 struct strp_aggr_stats strp_stats; 247 struct kcm_mux *mux; 248 struct kcm_psock *psock; 249 struct net *net = seq->private; 250 struct kcm_net *knet = net_generic(net, kcm_net_id); 251 252 memset(&mux_stats, 0, sizeof(mux_stats)); 253 memset(&psock_stats, 0, sizeof(psock_stats)); 254 memset(&strp_stats, 0, sizeof(strp_stats)); 255 256 mutex_lock(&knet->mutex); 257 258 aggregate_mux_stats(&knet->aggregate_mux_stats, &mux_stats); 259 aggregate_psock_stats(&knet->aggregate_psock_stats, 260 &psock_stats); 261 aggregate_strp_stats(&knet->aggregate_strp_stats, 262 &strp_stats); 263 264 list_for_each_entry_rcu(mux, &knet->mux_list, kcm_mux_list) { 265 spin_lock_bh(&mux->lock); 266 aggregate_mux_stats(&mux->stats, &mux_stats); 267 aggregate_psock_stats(&mux->aggregate_psock_stats, 268 &psock_stats); 269 aggregate_strp_stats(&mux->aggregate_strp_stats, 270 &strp_stats); 271 list_for_each_entry(psock, &mux->psocks, psock_list) { 272 aggregate_psock_stats(&psock->stats, &psock_stats); 273 save_strp_stats(&psock->strp, &strp_stats); 274 } 275 276 spin_unlock_bh(&mux->lock); 277 } 278 279 mutex_unlock(&knet->mutex); 280 281 seq_printf(seq, 282 "%-8s %-10s %-16s %-10s %-16s %-10s %-10s %-10s %-10s %-10s\n", 283 "MUX", 284 "RX-Msgs", 285 "RX-Bytes", 286 "TX-Msgs", 287 "TX-Bytes", 288 "TX-Retries", 289 "Attach", 290 "Unattach", 291 "UnattchRsvd", 292 "RX-RdyDrops"); 293 294 seq_printf(seq, 295 "%-8s %-10llu %-16llu %-10llu %-16llu %-10u %-10u %-10u %-10u %-10u\n", 296 "", 297 mux_stats.rx_msgs, 298 mux_stats.rx_bytes, 299 mux_stats.tx_msgs, 300 mux_stats.tx_bytes, 301 mux_stats.tx_retries, 302 mux_stats.psock_attach, 303 mux_stats.psock_unattach_rsvd, 304 mux_stats.psock_unattach, 305 mux_stats.rx_ready_drops); 306 307 seq_printf(seq, 308 "%-8s %-10s %-16s %-10s %-16s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s\n", 309 "Psock", 310 "RX-Msgs", 311 "RX-Bytes", 312 "TX-Msgs", 313 "TX-Bytes", 314 "Reserved", 315 "Unreserved", 316 "RX-Aborts", 317 "RX-Intr", 318 "RX-Unrecov", 319 "RX-MemFail", 320 "RX-NeedMor", 321 "RX-BadLen", 322 "RX-TooBig", 323 "RX-Timeout", 324 "TX-Aborts"); 325 326 seq_printf(seq, 327 "%-8s %-10llu %-16llu %-10llu %-16llu %-10llu %-10llu %-10u %-10u %-10u %-10u %-10u %-10u %-10u %-10u %-10u\n", 328 "", 329 strp_stats.msgs, 330 strp_stats.bytes, 331 psock_stats.tx_msgs, 332 psock_stats.tx_bytes, 333 psock_stats.reserved, 334 psock_stats.unreserved, 335 strp_stats.aborts, 336 strp_stats.interrupted, 337 strp_stats.unrecov_intr, 338 strp_stats.mem_fail, 339 strp_stats.need_more_hdr, 340 strp_stats.bad_hdr_len, 341 strp_stats.msg_too_big, 342 strp_stats.msg_timeouts, 343 psock_stats.tx_aborts); 344 345 return 0; 346 } 347 348 static int kcm_proc_init_net(struct net *net) 349 { 350 if (!proc_create_net_single("kcm_stats", 0444, net->proc_net, 351 kcm_stats_seq_show, NULL)) 352 goto out_kcm_stats; 353 354 if (!proc_create_net("kcm", 0444, net->proc_net, &kcm_seq_ops, 355 sizeof(struct kcm_proc_mux_state))) 356 goto out_kcm; 357 358 return 0; 359 360 out_kcm: 361 remove_proc_entry("kcm_stats", net->proc_net); 362 out_kcm_stats: 363 return -ENOMEM; 364 } 365 366 static void kcm_proc_exit_net(struct net *net) 367 { 368 remove_proc_entry("kcm", net->proc_net); 369 remove_proc_entry("kcm_stats", net->proc_net); 370 } 371 372 static struct pernet_operations kcm_net_ops = { 373 .init = kcm_proc_init_net, 374 .exit = kcm_proc_exit_net, 375 }; 376 377 int __init kcm_proc_init(void) 378 { 379 return register_pernet_subsys(&kcm_net_ops); 380 } 381 382 void __exit kcm_proc_exit(void) 383 { 384 unregister_pernet_subsys(&kcm_net_ops); 385 } 386 387 #endif /* CONFIG_PROC_FS */ 388