rxrpc: Add /proc/net/rxrpc/peers to display peer list
authorDavid Howells <dhowells@redhat.com>
Mon, 15 Oct 2018 10:31:03 +0000 (11:31 +0100)
committerDavid S. Miller <davem@davemloft.net>
Tue, 16 Oct 2018 05:52:58 +0000 (22:52 -0700)
Add /proc/net/rxrpc/peers to display the list of peers currently active.

Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/rxrpc/ar-internal.h
net/rxrpc/net_ns.c
net/rxrpc/proc.c

index 8cee7644965c7062485787c8e880d621ac28385a..0a7c49e8e053cca07e20ab7b373fc5ba54e785fc 100644 (file)
@@ -1062,6 +1062,7 @@ void rxrpc_put_peer(struct rxrpc_peer *);
  */
 extern const struct seq_operations rxrpc_call_seq_ops;
 extern const struct seq_operations rxrpc_connection_seq_ops;
+extern const struct seq_operations rxrpc_peer_seq_ops;
 
 /*
  * recvmsg.c
index 417d80867c4f4a013465b3f9c22be04e49082b2f..fd7eba8467fac0ed83ce7e580cb92b85ccee7520 100644 (file)
@@ -102,6 +102,9 @@ static __net_init int rxrpc_init_net(struct net *net)
        proc_create_net("conns", 0444, rxnet->proc_net,
                        &rxrpc_connection_seq_ops,
                        sizeof(struct seq_net_private));
+       proc_create_net("peers", 0444, rxnet->proc_net,
+                       &rxrpc_peer_seq_ops,
+                       sizeof(struct seq_net_private));
        return 0;
 
 err_proc:
index 9805e3b85c3610d453931ea7a2ca46ed286f9dc5..c7d976859d40bdd0753afb7c098ccfe36d15db30 100644 (file)
@@ -212,3 +212,129 @@ const struct seq_operations rxrpc_connection_seq_ops = {
        .stop   = rxrpc_connection_seq_stop,
        .show   = rxrpc_connection_seq_show,
 };
+
+/*
+ * generate a list of extant virtual peers in /proc/net/rxrpc/peers
+ */
+static int rxrpc_peer_seq_show(struct seq_file *seq, void *v)
+{
+       struct rxrpc_peer *peer;
+       time64_t now;
+       char lbuff[50], rbuff[50];
+
+       if (v == SEQ_START_TOKEN) {
+               seq_puts(seq,
+                        "Proto Local                                          "
+                        " Remote                                         "
+                        " Use CW  MTU   LastUse          RTT Rc\n"
+                        );
+               return 0;
+       }
+
+       peer = list_entry(v, struct rxrpc_peer, hash_link);
+
+       sprintf(lbuff, "%pISpc", &peer->local->srx.transport);
+
+       sprintf(rbuff, "%pISpc", &peer->srx.transport);
+
+       now = ktime_get_seconds();
+       seq_printf(seq,
+                  "UDP   %-47.47s %-47.47s %3u"
+                  " %3u %5u %6llus %12llu %2u\n",
+                  lbuff,
+                  rbuff,
+                  atomic_read(&peer->usage),
+                  peer->cong_cwnd,
+                  peer->mtu,
+                  now - peer->last_tx_at,
+                  peer->rtt,
+                  peer->rtt_cursor);
+
+       return 0;
+}
+
+static void *rxrpc_peer_seq_start(struct seq_file *seq, loff_t *_pos)
+       __acquires(rcu)
+{
+       struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
+       unsigned int bucket, n;
+       unsigned int shift = 32 - HASH_BITS(rxnet->peer_hash);
+       void *p;
+
+       rcu_read_lock();
+
+       if (*_pos >= UINT_MAX)
+               return NULL;
+
+       n = *_pos & ((1U << shift) - 1);
+       bucket = *_pos >> shift;
+       for (;;) {
+               if (bucket >= HASH_SIZE(rxnet->peer_hash)) {
+                       *_pos = UINT_MAX;
+                       return NULL;
+               }
+               if (n == 0) {
+                       if (bucket == 0)
+                               return SEQ_START_TOKEN;
+                       *_pos += 1;
+                       n++;
+               }
+
+               p = seq_hlist_start_rcu(&rxnet->peer_hash[bucket], n - 1);
+               if (p)
+                       return p;
+               bucket++;
+               n = 1;
+               *_pos = (bucket << shift) | n;
+       }
+}
+
+static void *rxrpc_peer_seq_next(struct seq_file *seq, void *v, loff_t *_pos)
+{
+       struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
+       unsigned int bucket, n;
+       unsigned int shift = 32 - HASH_BITS(rxnet->peer_hash);
+       void *p;
+
+       if (*_pos >= UINT_MAX)
+               return NULL;
+
+       bucket = *_pos >> shift;
+
+       p = seq_hlist_next_rcu(v, &rxnet->peer_hash[bucket], _pos);
+       if (p)
+               return p;
+
+       for (;;) {
+               bucket++;
+               n = 1;
+               *_pos = (bucket << shift) | n;
+
+               if (bucket >= HASH_SIZE(rxnet->peer_hash)) {
+                       *_pos = UINT_MAX;
+                       return NULL;
+               }
+               if (n == 0) {
+                       *_pos += 1;
+                       n++;
+               }
+
+               p = seq_hlist_start_rcu(&rxnet->peer_hash[bucket], n - 1);
+               if (p)
+                       return p;
+       }
+}
+
+static void rxrpc_peer_seq_stop(struct seq_file *seq, void *v)
+       __releases(rcu)
+{
+       rcu_read_unlock();
+}
+
+
+const struct seq_operations rxrpc_peer_seq_ops = {
+       .start  = rxrpc_peer_seq_start,
+       .next   = rxrpc_peer_seq_next,
+       .stop   = rxrpc_peer_seq_stop,
+       .show   = rxrpc_peer_seq_show,
+};