linux/net/kcm/kcmproc.c
<<
>>
Prefs
   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
  18struct kcm_seq_muxinfo {
  19        char                            *name;
  20        const struct file_operations    *seq_fops;
  21        const struct seq_operations     seq_ops;
  22};
  23
  24static 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
  33static 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
  41static 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
  55static 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
  67static 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
  78static void kcm_seq_stop(struct seq_file *seq, void *v)
  79        __releases(rcu)
  80{
  81        rcu_read_unlock();
  82}
  83
  84struct kcm_proc_mux_state {
  85        struct seq_net_private p;
  86        int idx;
  87};
  88
  89static 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
  97static 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
 123static 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
 153static 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
 199static void
 200kcm_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
 234static 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
 249static 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
 257static 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
 268static 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}
 279EXPORT_SYMBOL(kcm_proc_register);
 280
 281static void kcm_proc_unregister(struct net *net,
 282                                struct kcm_seq_muxinfo *muxinfo)
 283{
 284        remove_proc_entry(muxinfo->name, net->proc_net);
 285}
 286EXPORT_SYMBOL(kcm_proc_unregister);
 287
 288static 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
 394static 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
 399static 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
 407static 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
 423out_kcm:
 424        remove_proc_entry("kcm_stats", net->proc_net);
 425out_kcm_stats:
 426        return err;
 427}
 428
 429static 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
 435static struct pernet_operations kcm_net_ops = {
 436        .init = kcm_proc_init_net,
 437        .exit = kcm_proc_exit_net,
 438};
 439
 440int __init kcm_proc_init(void)
 441{
 442        return register_pernet_subsys(&kcm_net_ops);
 443}
 444
 445void __exit kcm_proc_exit(void)
 446{
 447        unregister_pernet_subsys(&kcm_net_ops);
 448}
 449
 450#endif /* CONFIG_PROC_FS */
 451