123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388 |
- // SPDX-License-Identifier: GPL-2.0
- #include <linux/in.h>
- #include <linux/inet.h>
- #include <linux/list.h>
- #include <linux/module.h>
- #include <linux/net.h>
- #include <linux/proc_fs.h>
- #include <linux/rculist.h>
- #include <linux/seq_file.h>
- #include <linux/socket.h>
- #include <net/inet_sock.h>
- #include <net/kcm.h>
- #include <net/net_namespace.h>
- #include <net/netns/generic.h>
- #include <net/tcp.h>
- #ifdef CONFIG_PROC_FS
- static struct kcm_mux *kcm_get_first(struct seq_file *seq)
- {
- struct net *net = seq_file_net(seq);
- struct kcm_net *knet = net_generic(net, kcm_net_id);
- return list_first_or_null_rcu(&knet->mux_list,
- struct kcm_mux, kcm_mux_list);
- }
- static struct kcm_mux *kcm_get_next(struct kcm_mux *mux)
- {
- struct kcm_net *knet = mux->knet;
- return list_next_or_null_rcu(&knet->mux_list, &mux->kcm_mux_list,
- struct kcm_mux, kcm_mux_list);
- }
- static struct kcm_mux *kcm_get_idx(struct seq_file *seq, loff_t pos)
- {
- struct net *net = seq_file_net(seq);
- struct kcm_net *knet = net_generic(net, kcm_net_id);
- struct kcm_mux *m;
- list_for_each_entry_rcu(m, &knet->mux_list, kcm_mux_list) {
- if (!pos)
- return m;
- --pos;
- }
- return NULL;
- }
- static void *kcm_seq_next(struct seq_file *seq, void *v, loff_t *pos)
- {
- void *p;
- if (v == SEQ_START_TOKEN)
- p = kcm_get_first(seq);
- else
- p = kcm_get_next(v);
- ++*pos;
- return p;
- }
- static void *kcm_seq_start(struct seq_file *seq, loff_t *pos)
- __acquires(rcu)
- {
- rcu_read_lock();
- if (!*pos)
- return SEQ_START_TOKEN;
- else
- return kcm_get_idx(seq, *pos - 1);
- }
- static void kcm_seq_stop(struct seq_file *seq, void *v)
- __releases(rcu)
- {
- rcu_read_unlock();
- }
- struct kcm_proc_mux_state {
- struct seq_net_private p;
- int idx;
- };
- static void kcm_format_mux_header(struct seq_file *seq)
- {
- struct net *net = seq_file_net(seq);
- struct kcm_net *knet = net_generic(net, kcm_net_id);
- seq_printf(seq,
- "*** KCM statistics (%d MUX) ****\n",
- knet->count);
- seq_printf(seq,
- "%-14s %-10s %-16s %-10s %-16s %-8s %-8s %-8s %-8s %s",
- "Object",
- "RX-Msgs",
- "RX-Bytes",
- "TX-Msgs",
- "TX-Bytes",
- "Recv-Q",
- "Rmem",
- "Send-Q",
- "Smem",
- "Status");
- /* XXX: pdsts header stuff here */
- seq_puts(seq, "\n");
- }
- static void kcm_format_sock(struct kcm_sock *kcm, struct seq_file *seq,
- int i, int *len)
- {
- seq_printf(seq,
- " kcm-%-7u %-10llu %-16llu %-10llu %-16llu %-8d %-8d %-8d %-8s ",
- kcm->index,
- kcm->stats.rx_msgs,
- kcm->stats.rx_bytes,
- kcm->stats.tx_msgs,
- kcm->stats.tx_bytes,
- kcm->sk.sk_receive_queue.qlen,
- sk_rmem_alloc_get(&kcm->sk),
- kcm->sk.sk_write_queue.qlen,
- "-");
- if (kcm->tx_psock)
- seq_printf(seq, "Psck-%u ", kcm->tx_psock->index);
- if (kcm->tx_wait)
- seq_puts(seq, "TxWait ");
- if (kcm->tx_wait_more)
- seq_puts(seq, "WMore ");
- if (kcm->rx_wait)
- seq_puts(seq, "RxWait ");
- seq_puts(seq, "\n");
- }
- static void kcm_format_psock(struct kcm_psock *psock, struct seq_file *seq,
- int i, int *len)
- {
- seq_printf(seq,
- " psock-%-5u %-10llu %-16llu %-10llu %-16llu %-8d %-8d %-8d %-8d ",
- psock->index,
- psock->strp.stats.msgs,
- psock->strp.stats.bytes,
- psock->stats.tx_msgs,
- psock->stats.tx_bytes,
- psock->sk->sk_receive_queue.qlen,
- atomic_read(&psock->sk->sk_rmem_alloc),
- psock->sk->sk_write_queue.qlen,
- refcount_read(&psock->sk->sk_wmem_alloc));
- if (psock->done)
- seq_puts(seq, "Done ");
- if (psock->tx_stopped)
- seq_puts(seq, "TxStop ");
- if (psock->strp.stopped)
- seq_puts(seq, "RxStop ");
- if (psock->tx_kcm)
- seq_printf(seq, "Rsvd-%d ", psock->tx_kcm->index);
- if (!psock->strp.paused && !psock->ready_rx_msg) {
- if (psock->sk->sk_receive_queue.qlen) {
- if (psock->strp.need_bytes)
- seq_printf(seq, "RxWait=%u ",
- psock->strp.need_bytes);
- else
- seq_printf(seq, "RxWait ");
- }
- } else {
- if (psock->strp.paused)
- seq_puts(seq, "RxPause ");
- if (psock->ready_rx_msg)
- seq_puts(seq, "RdyRx ");
- }
- seq_puts(seq, "\n");
- }
- static void
- kcm_format_mux(struct kcm_mux *mux, loff_t idx, struct seq_file *seq)
- {
- int i, len;
- struct kcm_sock *kcm;
- struct kcm_psock *psock;
- /* mux information */
- seq_printf(seq,
- "%-6s%-8s %-10llu %-16llu %-10llu %-16llu %-8s %-8s %-8s %-8s ",
- "mux", "",
- mux->stats.rx_msgs,
- mux->stats.rx_bytes,
- mux->stats.tx_msgs,
- mux->stats.tx_bytes,
- "-", "-", "-", "-");
- seq_printf(seq, "KCMs: %d, Psocks %d\n",
- mux->kcm_socks_cnt, mux->psocks_cnt);
- /* kcm sock information */
- i = 0;
- spin_lock_bh(&mux->lock);
- list_for_each_entry(kcm, &mux->kcm_socks, kcm_sock_list) {
- kcm_format_sock(kcm, seq, i, &len);
- i++;
- }
- i = 0;
- list_for_each_entry(psock, &mux->psocks, psock_list) {
- kcm_format_psock(psock, seq, i, &len);
- i++;
- }
- spin_unlock_bh(&mux->lock);
- }
- static int kcm_seq_show(struct seq_file *seq, void *v)
- {
- struct kcm_proc_mux_state *mux_state;
- mux_state = seq->private;
- if (v == SEQ_START_TOKEN) {
- mux_state->idx = 0;
- kcm_format_mux_header(seq);
- } else {
- kcm_format_mux(v, mux_state->idx, seq);
- mux_state->idx++;
- }
- return 0;
- }
- static const struct seq_operations kcm_seq_ops = {
- .show = kcm_seq_show,
- .start = kcm_seq_start,
- .next = kcm_seq_next,
- .stop = kcm_seq_stop,
- };
- static int kcm_stats_seq_show(struct seq_file *seq, void *v)
- {
- struct kcm_psock_stats psock_stats;
- struct kcm_mux_stats mux_stats;
- struct strp_aggr_stats strp_stats;
- struct kcm_mux *mux;
- struct kcm_psock *psock;
- struct net *net = seq->private;
- struct kcm_net *knet = net_generic(net, kcm_net_id);
- memset(&mux_stats, 0, sizeof(mux_stats));
- memset(&psock_stats, 0, sizeof(psock_stats));
- memset(&strp_stats, 0, sizeof(strp_stats));
- mutex_lock(&knet->mutex);
- aggregate_mux_stats(&knet->aggregate_mux_stats, &mux_stats);
- aggregate_psock_stats(&knet->aggregate_psock_stats,
- &psock_stats);
- aggregate_strp_stats(&knet->aggregate_strp_stats,
- &strp_stats);
- list_for_each_entry_rcu(mux, &knet->mux_list, kcm_mux_list) {
- spin_lock_bh(&mux->lock);
- aggregate_mux_stats(&mux->stats, &mux_stats);
- aggregate_psock_stats(&mux->aggregate_psock_stats,
- &psock_stats);
- aggregate_strp_stats(&mux->aggregate_strp_stats,
- &strp_stats);
- list_for_each_entry(psock, &mux->psocks, psock_list) {
- aggregate_psock_stats(&psock->stats, &psock_stats);
- save_strp_stats(&psock->strp, &strp_stats);
- }
- spin_unlock_bh(&mux->lock);
- }
- mutex_unlock(&knet->mutex);
- seq_printf(seq,
- "%-8s %-10s %-16s %-10s %-16s %-10s %-10s %-10s %-10s %-10s\n",
- "MUX",
- "RX-Msgs",
- "RX-Bytes",
- "TX-Msgs",
- "TX-Bytes",
- "TX-Retries",
- "Attach",
- "Unattach",
- "UnattchRsvd",
- "RX-RdyDrops");
- seq_printf(seq,
- "%-8s %-10llu %-16llu %-10llu %-16llu %-10u %-10u %-10u %-10u %-10u\n",
- "",
- mux_stats.rx_msgs,
- mux_stats.rx_bytes,
- mux_stats.tx_msgs,
- mux_stats.tx_bytes,
- mux_stats.tx_retries,
- mux_stats.psock_attach,
- mux_stats.psock_unattach_rsvd,
- mux_stats.psock_unattach,
- mux_stats.rx_ready_drops);
- seq_printf(seq,
- "%-8s %-10s %-16s %-10s %-16s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s\n",
- "Psock",
- "RX-Msgs",
- "RX-Bytes",
- "TX-Msgs",
- "TX-Bytes",
- "Reserved",
- "Unreserved",
- "RX-Aborts",
- "RX-Intr",
- "RX-Unrecov",
- "RX-MemFail",
- "RX-NeedMor",
- "RX-BadLen",
- "RX-TooBig",
- "RX-Timeout",
- "TX-Aborts");
- seq_printf(seq,
- "%-8s %-10llu %-16llu %-10llu %-16llu %-10llu %-10llu %-10u %-10u %-10u %-10u %-10u %-10u %-10u %-10u %-10u\n",
- "",
- strp_stats.msgs,
- strp_stats.bytes,
- psock_stats.tx_msgs,
- psock_stats.tx_bytes,
- psock_stats.reserved,
- psock_stats.unreserved,
- strp_stats.aborts,
- strp_stats.interrupted,
- strp_stats.unrecov_intr,
- strp_stats.mem_fail,
- strp_stats.need_more_hdr,
- strp_stats.bad_hdr_len,
- strp_stats.msg_too_big,
- strp_stats.msg_timeouts,
- psock_stats.tx_aborts);
- return 0;
- }
- static int kcm_proc_init_net(struct net *net)
- {
- if (!proc_create_net_single("kcm_stats", 0444, net->proc_net,
- kcm_stats_seq_show, NULL))
- goto out_kcm_stats;
- if (!proc_create_net("kcm", 0444, net->proc_net, &kcm_seq_ops,
- sizeof(struct kcm_proc_mux_state)))
- goto out_kcm;
- return 0;
- out_kcm:
- remove_proc_entry("kcm_stats", net->proc_net);
- out_kcm_stats:
- return -ENOMEM;
- }
- static void kcm_proc_exit_net(struct net *net)
- {
- remove_proc_entry("kcm", net->proc_net);
- remove_proc_entry("kcm_stats", net->proc_net);
- }
- static struct pernet_operations kcm_net_ops = {
- .init = kcm_proc_init_net,
- .exit = kcm_proc_exit_net,
- };
- int __init kcm_proc_init(void)
- {
- return register_pernet_subsys(&kcm_net_ops);
- }
- void __exit kcm_proc_exit(void)
- {
- unregister_pernet_subsys(&kcm_net_ops);
- }
- #endif /* CONFIG_PROC_FS */
|