linux/net/rxrpc/proc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/* /proc/net/ support for AF_RXRPC
   3 *
   4 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
   5 * Written by David Howells (dhowells@redhat.com)
   6 */
   7
   8#include <linux/module.h>
   9#include <net/sock.h>
  10#include <net/af_rxrpc.h>
  11#include "ar-internal.h"
  12
  13static const char *const rxrpc_conn_states[RXRPC_CONN__NR_STATES] = {
  14        [RXRPC_CONN_UNUSED]                     = "Unused  ",
  15        [RXRPC_CONN_CLIENT]                     = "Client  ",
  16        [RXRPC_CONN_SERVICE_PREALLOC]           = "SvPrealc",
  17        [RXRPC_CONN_SERVICE_UNSECURED]          = "SvUnsec ",
  18        [RXRPC_CONN_SERVICE_CHALLENGING]        = "SvChall ",
  19        [RXRPC_CONN_SERVICE]                    = "SvSecure",
  20        [RXRPC_CONN_REMOTELY_ABORTED]           = "RmtAbort",
  21        [RXRPC_CONN_LOCALLY_ABORTED]            = "LocAbort",
  22};
  23
  24/*
  25 * generate a list of extant and dead calls in /proc/net/rxrpc_calls
  26 */
  27static void *rxrpc_call_seq_start(struct seq_file *seq, loff_t *_pos)
  28        __acquires(rcu)
  29        __acquires(rxnet->call_lock)
  30{
  31        struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
  32
  33        rcu_read_lock();
  34        read_lock(&rxnet->call_lock);
  35        return seq_list_start_head(&rxnet->calls, *_pos);
  36}
  37
  38static void *rxrpc_call_seq_next(struct seq_file *seq, void *v, loff_t *pos)
  39{
  40        struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
  41
  42        return seq_list_next(v, &rxnet->calls, pos);
  43}
  44
  45static void rxrpc_call_seq_stop(struct seq_file *seq, void *v)
  46        __releases(rxnet->call_lock)
  47        __releases(rcu)
  48{
  49        struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
  50
  51        read_unlock(&rxnet->call_lock);
  52        rcu_read_unlock();
  53}
  54
  55static int rxrpc_call_seq_show(struct seq_file *seq, void *v)
  56{
  57        struct rxrpc_local *local;
  58        struct rxrpc_sock *rx;
  59        struct rxrpc_peer *peer;
  60        struct rxrpc_call *call;
  61        struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
  62        unsigned long timeout = 0;
  63        rxrpc_seq_t tx_hard_ack, rx_hard_ack;
  64        char lbuff[50], rbuff[50];
  65
  66        if (v == &rxnet->calls) {
  67                seq_puts(seq,
  68                         "Proto Local                                          "
  69                         " Remote                                         "
  70                         " SvID ConnID   CallID   End Use State    Abort   "
  71                         " UserID           TxSeq    TW RxSeq    RW RxSerial RxTimo\n");
  72                return 0;
  73        }
  74
  75        call = list_entry(v, struct rxrpc_call, link);
  76
  77        rx = rcu_dereference(call->socket);
  78        if (rx) {
  79                local = READ_ONCE(rx->local);
  80                if (local)
  81                        sprintf(lbuff, "%pISpc", &local->srx.transport);
  82                else
  83                        strcpy(lbuff, "no_local");
  84        } else {
  85                strcpy(lbuff, "no_socket");
  86        }
  87
  88        peer = call->peer;
  89        if (peer)
  90                sprintf(rbuff, "%pISpc", &peer->srx.transport);
  91        else
  92                strcpy(rbuff, "no_connection");
  93
  94        if (call->state != RXRPC_CALL_SERVER_PREALLOC) {
  95                timeout = READ_ONCE(call->expect_rx_by);
  96                timeout -= jiffies;
  97        }
  98
  99        tx_hard_ack = READ_ONCE(call->tx_hard_ack);
 100        rx_hard_ack = READ_ONCE(call->rx_hard_ack);
 101        seq_printf(seq,
 102                   "UDP   %-47.47s %-47.47s %4x %08x %08x %s %3u"
 103                   " %-8.8s %08x %lx %08x %02x %08x %02x %08x %06lx\n",
 104                   lbuff,
 105                   rbuff,
 106                   call->service_id,
 107                   call->cid,
 108                   call->call_id,
 109                   rxrpc_is_service_call(call) ? "Svc" : "Clt",
 110                   atomic_read(&call->usage),
 111                   rxrpc_call_states[call->state],
 112                   call->abort_code,
 113                   call->user_call_ID,
 114                   tx_hard_ack, READ_ONCE(call->tx_top) - tx_hard_ack,
 115                   rx_hard_ack, READ_ONCE(call->rx_top) - rx_hard_ack,
 116                   call->rx_serial,
 117                   timeout);
 118
 119        return 0;
 120}
 121
 122const struct seq_operations rxrpc_call_seq_ops = {
 123        .start  = rxrpc_call_seq_start,
 124        .next   = rxrpc_call_seq_next,
 125        .stop   = rxrpc_call_seq_stop,
 126        .show   = rxrpc_call_seq_show,
 127};
 128
 129/*
 130 * generate a list of extant virtual connections in /proc/net/rxrpc_conns
 131 */
 132static void *rxrpc_connection_seq_start(struct seq_file *seq, loff_t *_pos)
 133        __acquires(rxnet->conn_lock)
 134{
 135        struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
 136
 137        read_lock(&rxnet->conn_lock);
 138        return seq_list_start_head(&rxnet->conn_proc_list, *_pos);
 139}
 140
 141static void *rxrpc_connection_seq_next(struct seq_file *seq, void *v,
 142                                       loff_t *pos)
 143{
 144        struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
 145
 146        return seq_list_next(v, &rxnet->conn_proc_list, pos);
 147}
 148
 149static void rxrpc_connection_seq_stop(struct seq_file *seq, void *v)
 150        __releases(rxnet->conn_lock)
 151{
 152        struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
 153
 154        read_unlock(&rxnet->conn_lock);
 155}
 156
 157static int rxrpc_connection_seq_show(struct seq_file *seq, void *v)
 158{
 159        struct rxrpc_connection *conn;
 160        struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
 161        char lbuff[50], rbuff[50];
 162
 163        if (v == &rxnet->conn_proc_list) {
 164                seq_puts(seq,
 165                         "Proto Local                                          "
 166                         " Remote                                         "
 167                         " SvID ConnID   End Use State    Key     "
 168                         " Serial   ISerial\n"
 169                         );
 170                return 0;
 171        }
 172
 173        conn = list_entry(v, struct rxrpc_connection, proc_link);
 174        if (conn->state == RXRPC_CONN_SERVICE_PREALLOC) {
 175                strcpy(lbuff, "no_local");
 176                strcpy(rbuff, "no_connection");
 177                goto print;
 178        }
 179
 180        sprintf(lbuff, "%pISpc", &conn->params.local->srx.transport);
 181
 182        sprintf(rbuff, "%pISpc", &conn->params.peer->srx.transport);
 183print:
 184        seq_printf(seq,
 185                   "UDP   %-47.47s %-47.47s %4x %08x %s %3u"
 186                   " %s %08x %08x %08x %08x %08x %08x %08x\n",
 187                   lbuff,
 188                   rbuff,
 189                   conn->service_id,
 190                   conn->proto.cid,
 191                   rxrpc_conn_is_service(conn) ? "Svc" : "Clt",
 192                   atomic_read(&conn->usage),
 193                   rxrpc_conn_states[conn->state],
 194                   key_serial(conn->params.key),
 195                   atomic_read(&conn->serial),
 196                   conn->hi_serial,
 197                   conn->channels[0].call_id,
 198                   conn->channels[1].call_id,
 199                   conn->channels[2].call_id,
 200                   conn->channels[3].call_id);
 201
 202        return 0;
 203}
 204
 205const struct seq_operations rxrpc_connection_seq_ops = {
 206        .start  = rxrpc_connection_seq_start,
 207        .next   = rxrpc_connection_seq_next,
 208        .stop   = rxrpc_connection_seq_stop,
 209        .show   = rxrpc_connection_seq_show,
 210};
 211
 212/*
 213 * generate a list of extant virtual peers in /proc/net/rxrpc/peers
 214 */
 215static int rxrpc_peer_seq_show(struct seq_file *seq, void *v)
 216{
 217        struct rxrpc_peer *peer;
 218        time64_t now;
 219        char lbuff[50], rbuff[50];
 220
 221        if (v == SEQ_START_TOKEN) {
 222                seq_puts(seq,
 223                         "Proto Local                                          "
 224                         " Remote                                         "
 225                         " Use  CW   MTU LastUse      RTT      RTO\n"
 226                         );
 227                return 0;
 228        }
 229
 230        peer = list_entry(v, struct rxrpc_peer, hash_link);
 231
 232        sprintf(lbuff, "%pISpc", &peer->local->srx.transport);
 233
 234        sprintf(rbuff, "%pISpc", &peer->srx.transport);
 235
 236        now = ktime_get_seconds();
 237        seq_printf(seq,
 238                   "UDP   %-47.47s %-47.47s %3u"
 239                   " %3u %5u %6llus %8u %8u\n",
 240                   lbuff,
 241                   rbuff,
 242                   atomic_read(&peer->usage),
 243                   peer->cong_cwnd,
 244                   peer->mtu,
 245                   now - peer->last_tx_at,
 246                   peer->srtt_us >> 3,
 247                   jiffies_to_usecs(peer->rto_j));
 248
 249        return 0;
 250}
 251
 252static void *rxrpc_peer_seq_start(struct seq_file *seq, loff_t *_pos)
 253        __acquires(rcu)
 254{
 255        struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
 256        unsigned int bucket, n;
 257        unsigned int shift = 32 - HASH_BITS(rxnet->peer_hash);
 258        void *p;
 259
 260        rcu_read_lock();
 261
 262        if (*_pos >= UINT_MAX)
 263                return NULL;
 264
 265        n = *_pos & ((1U << shift) - 1);
 266        bucket = *_pos >> shift;
 267        for (;;) {
 268                if (bucket >= HASH_SIZE(rxnet->peer_hash)) {
 269                        *_pos = UINT_MAX;
 270                        return NULL;
 271                }
 272                if (n == 0) {
 273                        if (bucket == 0)
 274                                return SEQ_START_TOKEN;
 275                        *_pos += 1;
 276                        n++;
 277                }
 278
 279                p = seq_hlist_start_rcu(&rxnet->peer_hash[bucket], n - 1);
 280                if (p)
 281                        return p;
 282                bucket++;
 283                n = 1;
 284                *_pos = (bucket << shift) | n;
 285        }
 286}
 287
 288static void *rxrpc_peer_seq_next(struct seq_file *seq, void *v, loff_t *_pos)
 289{
 290        struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
 291        unsigned int bucket, n;
 292        unsigned int shift = 32 - HASH_BITS(rxnet->peer_hash);
 293        void *p;
 294
 295        if (*_pos >= UINT_MAX)
 296                return NULL;
 297
 298        bucket = *_pos >> shift;
 299
 300        p = seq_hlist_next_rcu(v, &rxnet->peer_hash[bucket], _pos);
 301        if (p)
 302                return p;
 303
 304        for (;;) {
 305                bucket++;
 306                n = 1;
 307                *_pos = (bucket << shift) | n;
 308
 309                if (bucket >= HASH_SIZE(rxnet->peer_hash)) {
 310                        *_pos = UINT_MAX;
 311                        return NULL;
 312                }
 313                if (n == 0) {
 314                        *_pos += 1;
 315                        n++;
 316                }
 317
 318                p = seq_hlist_start_rcu(&rxnet->peer_hash[bucket], n - 1);
 319                if (p)
 320                        return p;
 321        }
 322}
 323
 324static void rxrpc_peer_seq_stop(struct seq_file *seq, void *v)
 325        __releases(rcu)
 326{
 327        rcu_read_unlock();
 328}
 329
 330
 331const struct seq_operations rxrpc_peer_seq_ops = {
 332        .start  = rxrpc_peer_seq_start,
 333        .next   = rxrpc_peer_seq_next,
 334        .stop   = rxrpc_peer_seq_stop,
 335        .show   = rxrpc_peer_seq_show,
 336};
 337