blob: 245418943e01ccdeb861ae03f2796c296ad90080 [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
David Howells17926a72007-04-26 15:48:28 -07002/* /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)
David Howells17926a72007-04-26 15:48:28 -07006 */
7
8#include <linux/module.h>
9#include <net/sock.h>
10#include <net/af_rxrpc.h>
11#include "ar-internal.h"
12
David Howellsbba304d2016-06-27 10:32:02 +010013static const char *const rxrpc_conn_states[RXRPC_CONN__NR_STATES] = {
14 [RXRPC_CONN_UNUSED] = "Unused ",
15 [RXRPC_CONN_CLIENT] = "Client ",
David Howells00e90712016-09-08 11:10:12 +010016 [RXRPC_CONN_SERVICE_PREALLOC] = "SvPrealc",
David Howellsbba304d2016-06-27 10:32:02 +010017 [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",
David Howells17926a72007-04-26 15:48:28 -070022};
23
David Howells17926a72007-04-26 15:48:28 -070024/*
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)
David Howells88f2a8252018-03-30 21:05:17 +010028 __acquires(rcu)
David Howells17926a72007-04-26 15:48:28 -070029{
David Howells2baec2c2017-05-24 17:02:32 +010030 struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
31
David Howells8d94aa32016-09-07 09:19:31 +010032 rcu_read_lock();
David Howellsad25f5c2022-05-21 08:45:28 +010033 return seq_list_start_head_rcu(&rxnet->calls, *_pos);
David Howells17926a72007-04-26 15:48:28 -070034}
35
36static void *rxrpc_call_seq_next(struct seq_file *seq, void *v, loff_t *pos)
37{
David Howells2baec2c2017-05-24 17:02:32 +010038 struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
39
David Howellsad25f5c2022-05-21 08:45:28 +010040 return seq_list_next_rcu(v, &rxnet->calls, pos);
David Howells17926a72007-04-26 15:48:28 -070041}
42
43static void rxrpc_call_seq_stop(struct seq_file *seq, void *v)
David Howells88f2a8252018-03-30 21:05:17 +010044 __releases(rcu)
David Howells17926a72007-04-26 15:48:28 -070045{
David Howells8d94aa32016-09-07 09:19:31 +010046 rcu_read_unlock();
David Howells17926a72007-04-26 15:48:28 -070047}
48
49static int rxrpc_call_seq_show(struct seq_file *seq, void *v)
50{
David Howellsdf5d8bf2016-08-24 14:31:43 +010051 struct rxrpc_local *local;
52 struct rxrpc_sock *rx;
53 struct rxrpc_peer *peer;
David Howells17926a72007-04-26 15:48:28 -070054 struct rxrpc_call *call;
David Howells2baec2c2017-05-24 17:02:32 +010055 struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
Wei Yongjun770b26d2018-08-02 09:13:33 +010056 unsigned long timeout = 0;
David Howells3e018da2017-01-05 10:38:33 +000057 rxrpc_seq_t tx_hard_ack, rx_hard_ack;
David Howells75b54cb2016-09-13 08:49:05 +010058 char lbuff[50], rbuff[50];
David Howells17926a72007-04-26 15:48:28 -070059
David Howells2baec2c2017-05-24 17:02:32 +010060 if (v == &rxnet->calls) {
David Howells17926a72007-04-26 15:48:28 -070061 seq_puts(seq,
David Howells75b54cb2016-09-13 08:49:05 +010062 "Proto Local "
63 " Remote "
David Howells17926a72007-04-26 15:48:28 -070064 " SvID ConnID CallID End Use State Abort "
David Howells32f71aa2020-05-02 13:38:23 +010065 " DebugId TxSeq TW RxSeq RW RxSerial RxTimo\n");
David Howells17926a72007-04-26 15:48:28 -070066 return 0;
67 }
68
69 call = list_entry(v, struct rxrpc_call, link);
David Howells17926a72007-04-26 15:48:28 -070070
David Howells8d94aa32016-09-07 09:19:31 +010071 rx = rcu_dereference(call->socket);
David Howellsdf5d8bf2016-08-24 14:31:43 +010072 if (rx) {
73 local = READ_ONCE(rx->local);
74 if (local)
David Howells75b54cb2016-09-13 08:49:05 +010075 sprintf(lbuff, "%pISpc", &local->srx.transport);
David Howellsdf5d8bf2016-08-24 14:31:43 +010076 else
77 strcpy(lbuff, "no_local");
78 } else {
79 strcpy(lbuff, "no_socket");
80 }
David Howells17926a72007-04-26 15:48:28 -070081
David Howellsdf5d8bf2016-08-24 14:31:43 +010082 peer = call->peer;
83 if (peer)
David Howells75b54cb2016-09-13 08:49:05 +010084 sprintf(rbuff, "%pISpc", &peer->srx.transport);
David Howellsf4e7da82016-06-17 11:07:55 +010085 else
86 strcpy(rbuff, "no_connection");
David Howells17926a72007-04-26 15:48:28 -070087
David Howells887763b2018-07-23 17:18:36 +010088 if (call->state != RXRPC_CALL_SERVER_PREALLOC) {
89 timeout = READ_ONCE(call->expect_rx_by);
David Howells887763b2018-07-23 17:18:36 +010090 timeout -= jiffies;
91 }
92
David Howells3e018da2017-01-05 10:38:33 +000093 tx_hard_ack = READ_ONCE(call->tx_hard_ack);
94 rx_hard_ack = READ_ONCE(call->rx_hard_ack);
David Howells17926a72007-04-26 15:48:28 -070095 seq_printf(seq,
David Howells75b54cb2016-09-13 08:49:05 +010096 "UDP %-47.47s %-47.47s %4x %08x %08x %s %3u"
David Howells32f71aa2020-05-02 13:38:23 +010097 " %-8.8s %08x %08x %08x %02x %08x %02x %08x %06lx\n",
David Howells17926a72007-04-26 15:48:28 -070098 lbuff,
99 rbuff,
David Howellsf4e7da82016-06-17 11:07:55 +0100100 call->service_id,
David Howells0d12f8a2016-03-04 15:53:46 +0000101 call->cid,
102 call->call_id,
David Howellsdabe5a72016-08-23 15:27:24 +0100103 rxrpc_is_service_call(call) ? "Svc" : "Clt",
David Howellsa05754292022-05-21 08:45:22 +0100104 refcount_read(&call->ref),
David Howells17926a72007-04-26 15:48:28 -0700105 rxrpc_call_states[call->state],
David Howellsf5c17aa2016-08-30 09:49:28 +0100106 call->abort_code,
David Howells32f71aa2020-05-02 13:38:23 +0100107 call->debug_id,
David Howells3e018da2017-01-05 10:38:33 +0000108 tx_hard_ack, READ_ONCE(call->tx_top) - tx_hard_ack,
David Howells887763b2018-07-23 17:18:36 +0100109 rx_hard_ack, READ_ONCE(call->rx_top) - rx_hard_ack,
David Howells6b97bd72018-07-23 17:18:36 +0100110 call->rx_serial,
David Howells887763b2018-07-23 17:18:36 +0100111 timeout);
David Howells17926a72007-04-26 15:48:28 -0700112
113 return 0;
114}
115
Christoph Hellwigc3506372018-04-10 19:42:55 +0200116const struct seq_operations rxrpc_call_seq_ops = {
David Howells17926a72007-04-26 15:48:28 -0700117 .start = rxrpc_call_seq_start,
118 .next = rxrpc_call_seq_next,
119 .stop = rxrpc_call_seq_stop,
120 .show = rxrpc_call_seq_show,
121};
122
David Howells17926a72007-04-26 15:48:28 -0700123/*
124 * generate a list of extant virtual connections in /proc/net/rxrpc_conns
125 */
126static void *rxrpc_connection_seq_start(struct seq_file *seq, loff_t *_pos)
David Howells88f2a8252018-03-30 21:05:17 +0100127 __acquires(rxnet->conn_lock)
David Howells17926a72007-04-26 15:48:28 -0700128{
David Howells2baec2c2017-05-24 17:02:32 +0100129 struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
130
131 read_lock(&rxnet->conn_lock);
132 return seq_list_start_head(&rxnet->conn_proc_list, *_pos);
David Howells17926a72007-04-26 15:48:28 -0700133}
134
135static void *rxrpc_connection_seq_next(struct seq_file *seq, void *v,
136 loff_t *pos)
137{
David Howells2baec2c2017-05-24 17:02:32 +0100138 struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
139
140 return seq_list_next(v, &rxnet->conn_proc_list, pos);
David Howells17926a72007-04-26 15:48:28 -0700141}
142
143static void rxrpc_connection_seq_stop(struct seq_file *seq, void *v)
David Howells88f2a8252018-03-30 21:05:17 +0100144 __releases(rxnet->conn_lock)
David Howells17926a72007-04-26 15:48:28 -0700145{
David Howells2baec2c2017-05-24 17:02:32 +0100146 struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
147
148 read_unlock(&rxnet->conn_lock);
David Howells17926a72007-04-26 15:48:28 -0700149}
150
151static int rxrpc_connection_seq_show(struct seq_file *seq, void *v)
152{
153 struct rxrpc_connection *conn;
David Howells2baec2c2017-05-24 17:02:32 +0100154 struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
David Howells75b54cb2016-09-13 08:49:05 +0100155 char lbuff[50], rbuff[50];
David Howells17926a72007-04-26 15:48:28 -0700156
David Howells2baec2c2017-05-24 17:02:32 +0100157 if (v == &rxnet->conn_proc_list) {
David Howells17926a72007-04-26 15:48:28 -0700158 seq_puts(seq,
David Howells75b54cb2016-09-13 08:49:05 +0100159 "Proto Local "
160 " Remote "
David Howellsa1399f82016-06-27 14:39:44 +0100161 " SvID ConnID End Use State Key "
David Howells245500d2020-07-01 11:15:32 +0100162 " Serial ISerial CallId0 CallId1 CallId2 CallId3\n"
David Howells17926a72007-04-26 15:48:28 -0700163 );
164 return 0;
165 }
166
David Howells4d028b22016-08-24 07:30:52 +0100167 conn = list_entry(v, struct rxrpc_connection, proc_link);
David Howells00e90712016-09-08 11:10:12 +0100168 if (conn->state == RXRPC_CONN_SERVICE_PREALLOC) {
169 strcpy(lbuff, "no_local");
170 strcpy(rbuff, "no_connection");
171 goto print;
172 }
David Howells17926a72007-04-26 15:48:28 -0700173
David Howells75b54cb2016-09-13 08:49:05 +0100174 sprintf(lbuff, "%pISpc", &conn->params.local->srx.transport);
David Howells17926a72007-04-26 15:48:28 -0700175
David Howells75b54cb2016-09-13 08:49:05 +0100176 sprintf(rbuff, "%pISpc", &conn->params.peer->srx.transport);
David Howells00e90712016-09-08 11:10:12 +0100177print:
David Howells17926a72007-04-26 15:48:28 -0700178 seq_printf(seq,
David Howells75b54cb2016-09-13 08:49:05 +0100179 "UDP %-47.47s %-47.47s %4x %08x %s %3u"
David Howells6b97bd72018-07-23 17:18:36 +0100180 " %s %08x %08x %08x %08x %08x %08x %08x\n",
David Howells17926a72007-04-26 15:48:28 -0700181 lbuff,
182 rbuff,
David Howells68d6d1a2017-06-05 14:30:49 +0100183 conn->service_id,
David Howells19ffa012016-04-04 14:00:36 +0100184 conn->proto.cid,
David Howells19ffa012016-04-04 14:00:36 +0100185 rxrpc_conn_is_service(conn) ? "Svc" : "Clt",
David Howellsa05754292022-05-21 08:45:22 +0100186 refcount_read(&conn->ref),
David Howells17926a72007-04-26 15:48:28 -0700187 rxrpc_conn_states[conn->state],
David Howells19ffa012016-04-04 14:00:36 +0100188 key_serial(conn->params.key),
David Howells17926a72007-04-26 15:48:28 -0700189 atomic_read(&conn->serial),
David Howells6b97bd72018-07-23 17:18:36 +0100190 conn->hi_serial,
191 conn->channels[0].call_id,
192 conn->channels[1].call_id,
193 conn->channels[2].call_id,
194 conn->channels[3].call_id);
David Howells17926a72007-04-26 15:48:28 -0700195
196 return 0;
197}
198
Christoph Hellwigc3506372018-04-10 19:42:55 +0200199const struct seq_operations rxrpc_connection_seq_ops = {
David Howells17926a72007-04-26 15:48:28 -0700200 .start = rxrpc_connection_seq_start,
201 .next = rxrpc_connection_seq_next,
202 .stop = rxrpc_connection_seq_stop,
203 .show = rxrpc_connection_seq_show,
204};
David Howellsbc0e7cf2018-10-15 11:31:03 +0100205
206/*
207 * generate a list of extant virtual peers in /proc/net/rxrpc/peers
208 */
209static int rxrpc_peer_seq_show(struct seq_file *seq, void *v)
210{
211 struct rxrpc_peer *peer;
212 time64_t now;
213 char lbuff[50], rbuff[50];
214
215 if (v == SEQ_START_TOKEN) {
216 seq_puts(seq,
217 "Proto Local "
218 " Remote "
David Howellsc410bf012020-05-11 14:54:34 +0100219 " Use CW MTU LastUse RTT RTO\n"
David Howellsbc0e7cf2018-10-15 11:31:03 +0100220 );
221 return 0;
222 }
223
224 peer = list_entry(v, struct rxrpc_peer, hash_link);
225
226 sprintf(lbuff, "%pISpc", &peer->local->srx.transport);
227
228 sprintf(rbuff, "%pISpc", &peer->srx.transport);
229
230 now = ktime_get_seconds();
231 seq_printf(seq,
232 "UDP %-47.47s %-47.47s %3u"
David Howellsc410bf012020-05-11 14:54:34 +0100233 " %3u %5u %6llus %8u %8u\n",
David Howellsbc0e7cf2018-10-15 11:31:03 +0100234 lbuff,
235 rbuff,
David Howellsa05754292022-05-21 08:45:22 +0100236 refcount_read(&peer->ref),
David Howellsbc0e7cf2018-10-15 11:31:03 +0100237 peer->cong_cwnd,
238 peer->mtu,
239 now - peer->last_tx_at,
David Howellsc410bf012020-05-11 14:54:34 +0100240 peer->srtt_us >> 3,
241 jiffies_to_usecs(peer->rto_j));
David Howellsbc0e7cf2018-10-15 11:31:03 +0100242
243 return 0;
244}
245
246static void *rxrpc_peer_seq_start(struct seq_file *seq, loff_t *_pos)
247 __acquires(rcu)
248{
249 struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
250 unsigned int bucket, n;
251 unsigned int shift = 32 - HASH_BITS(rxnet->peer_hash);
252 void *p;
253
254 rcu_read_lock();
255
256 if (*_pos >= UINT_MAX)
257 return NULL;
258
259 n = *_pos & ((1U << shift) - 1);
260 bucket = *_pos >> shift;
261 for (;;) {
262 if (bucket >= HASH_SIZE(rxnet->peer_hash)) {
263 *_pos = UINT_MAX;
264 return NULL;
265 }
266 if (n == 0) {
267 if (bucket == 0)
268 return SEQ_START_TOKEN;
269 *_pos += 1;
270 n++;
271 }
272
273 p = seq_hlist_start_rcu(&rxnet->peer_hash[bucket], n - 1);
274 if (p)
275 return p;
276 bucket++;
277 n = 1;
278 *_pos = (bucket << shift) | n;
279 }
280}
281
282static void *rxrpc_peer_seq_next(struct seq_file *seq, void *v, loff_t *_pos)
283{
284 struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
285 unsigned int bucket, n;
286 unsigned int shift = 32 - HASH_BITS(rxnet->peer_hash);
287 void *p;
288
289 if (*_pos >= UINT_MAX)
290 return NULL;
291
292 bucket = *_pos >> shift;
293
294 p = seq_hlist_next_rcu(v, &rxnet->peer_hash[bucket], _pos);
295 if (p)
296 return p;
297
298 for (;;) {
299 bucket++;
300 n = 1;
301 *_pos = (bucket << shift) | n;
302
303 if (bucket >= HASH_SIZE(rxnet->peer_hash)) {
304 *_pos = UINT_MAX;
305 return NULL;
306 }
307 if (n == 0) {
308 *_pos += 1;
309 n++;
310 }
311
312 p = seq_hlist_start_rcu(&rxnet->peer_hash[bucket], n - 1);
313 if (p)
314 return p;
315 }
316}
317
318static void rxrpc_peer_seq_stop(struct seq_file *seq, void *v)
319 __releases(rcu)
320{
321 rcu_read_unlock();
322}
323
324
325const struct seq_operations rxrpc_peer_seq_ops = {
326 .start = rxrpc_peer_seq_start,
327 .next = rxrpc_peer_seq_next,
328 .stop = rxrpc_peer_seq_stop,
329 .show = rxrpc_peer_seq_show,
330};
David Howells33912c22022-05-21 08:45:15 +0100331
332/*
333 * Generate a list of extant virtual local endpoints in /proc/net/rxrpc/locals
334 */
335static int rxrpc_local_seq_show(struct seq_file *seq, void *v)
336{
337 struct rxrpc_local *local;
338 char lbuff[50];
339
340 if (v == SEQ_START_TOKEN) {
341 seq_puts(seq,
342 "Proto Local "
343 " Use Act\n");
344 return 0;
345 }
346
347 local = hlist_entry(v, struct rxrpc_local, link);
348
349 sprintf(lbuff, "%pISpc", &local->srx.transport);
350
351 seq_printf(seq,
352 "UDP %-47.47s %3u %3u\n",
353 lbuff,
David Howellsa05754292022-05-21 08:45:22 +0100354 refcount_read(&local->ref),
David Howells33912c22022-05-21 08:45:15 +0100355 atomic_read(&local->active_users));
356
357 return 0;
358}
359
360static void *rxrpc_local_seq_start(struct seq_file *seq, loff_t *_pos)
361 __acquires(rcu)
362{
363 struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
364 unsigned int n;
365
366 rcu_read_lock();
367
368 if (*_pos >= UINT_MAX)
369 return NULL;
370
371 n = *_pos;
372 if (n == 0)
373 return SEQ_START_TOKEN;
374
375 return seq_hlist_start_rcu(&rxnet->local_endpoints, n - 1);
376}
377
378static void *rxrpc_local_seq_next(struct seq_file *seq, void *v, loff_t *_pos)
379{
380 struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
381
382 if (*_pos >= UINT_MAX)
383 return NULL;
384
385 return seq_hlist_next_rcu(v, &rxnet->local_endpoints, _pos);
386}
387
388static void rxrpc_local_seq_stop(struct seq_file *seq, void *v)
389 __releases(rcu)
390{
391 rcu_read_unlock();
392}
393
394const struct seq_operations rxrpc_local_seq_ops = {
395 .start = rxrpc_local_seq_start,
396 .next = rxrpc_local_seq_next,
397 .stop = rxrpc_local_seq_stop,
398 .show = rxrpc_local_seq_show,
399};