xref: /openbmc/linux/net/rxrpc/proc.c (revision d3741027)
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 
13 static 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  */
27 static void *rxrpc_call_seq_start(struct seq_file *seq, loff_t *_pos)
28 	__acquires(rcu)
29 {
30 	struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
31 
32 	rcu_read_lock();
33 	return seq_list_start_head_rcu(&rxnet->calls, *_pos);
34 }
35 
36 static void *rxrpc_call_seq_next(struct seq_file *seq, void *v, loff_t *pos)
37 {
38 	struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
39 
40 	return seq_list_next_rcu(v, &rxnet->calls, pos);
41 }
42 
43 static void rxrpc_call_seq_stop(struct seq_file *seq, void *v)
44 	__releases(rcu)
45 {
46 	rcu_read_unlock();
47 }
48 
49 static int rxrpc_call_seq_show(struct seq_file *seq, void *v)
50 {
51 	struct rxrpc_local *local;
52 	struct rxrpc_sock *rx;
53 	struct rxrpc_peer *peer;
54 	struct rxrpc_call *call;
55 	struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
56 	unsigned long timeout = 0;
57 	rxrpc_seq_t tx_hard_ack, rx_hard_ack;
58 	char lbuff[50], rbuff[50];
59 
60 	if (v == &rxnet->calls) {
61 		seq_puts(seq,
62 			 "Proto Local                                          "
63 			 " Remote                                         "
64 			 " SvID ConnID   CallID   End Use State    Abort   "
65 			 " DebugId  TxSeq    TW RxSeq    RW RxSerial RxTimo\n");
66 		return 0;
67 	}
68 
69 	call = list_entry(v, struct rxrpc_call, link);
70 
71 	rx = rcu_dereference(call->socket);
72 	if (rx) {
73 		local = READ_ONCE(rx->local);
74 		if (local)
75 			sprintf(lbuff, "%pISpc", &local->srx.transport);
76 		else
77 			strcpy(lbuff, "no_local");
78 	} else {
79 		strcpy(lbuff, "no_socket");
80 	}
81 
82 	peer = call->peer;
83 	if (peer)
84 		sprintf(rbuff, "%pISpc", &peer->srx.transport);
85 	else
86 		strcpy(rbuff, "no_connection");
87 
88 	if (call->state != RXRPC_CALL_SERVER_PREALLOC) {
89 		timeout = READ_ONCE(call->expect_rx_by);
90 		timeout -= jiffies;
91 	}
92 
93 	tx_hard_ack = READ_ONCE(call->tx_hard_ack);
94 	rx_hard_ack = READ_ONCE(call->rx_hard_ack);
95 	seq_printf(seq,
96 		   "UDP   %-47.47s %-47.47s %4x %08x %08x %s %3u"
97 		   " %-8.8s %08x %08x %08x %02x %08x %02x %08x %06lx\n",
98 		   lbuff,
99 		   rbuff,
100 		   call->service_id,
101 		   call->cid,
102 		   call->call_id,
103 		   rxrpc_is_service_call(call) ? "Svc" : "Clt",
104 		   refcount_read(&call->ref),
105 		   rxrpc_call_states[call->state],
106 		   call->abort_code,
107 		   call->debug_id,
108 		   tx_hard_ack, READ_ONCE(call->tx_top) - tx_hard_ack,
109 		   rx_hard_ack, READ_ONCE(call->rx_top) - rx_hard_ack,
110 		   call->rx_serial,
111 		   timeout);
112 
113 	return 0;
114 }
115 
116 const struct seq_operations rxrpc_call_seq_ops = {
117 	.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 
123 /*
124  * generate a list of extant virtual connections in /proc/net/rxrpc_conns
125  */
126 static void *rxrpc_connection_seq_start(struct seq_file *seq, loff_t *_pos)
127 	__acquires(rxnet->conn_lock)
128 {
129 	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);
133 }
134 
135 static void *rxrpc_connection_seq_next(struct seq_file *seq, void *v,
136 				       loff_t *pos)
137 {
138 	struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
139 
140 	return seq_list_next(v, &rxnet->conn_proc_list, pos);
141 }
142 
143 static void rxrpc_connection_seq_stop(struct seq_file *seq, void *v)
144 	__releases(rxnet->conn_lock)
145 {
146 	struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
147 
148 	read_unlock(&rxnet->conn_lock);
149 }
150 
151 static int rxrpc_connection_seq_show(struct seq_file *seq, void *v)
152 {
153 	struct rxrpc_connection *conn;
154 	struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
155 	char lbuff[50], rbuff[50];
156 
157 	if (v == &rxnet->conn_proc_list) {
158 		seq_puts(seq,
159 			 "Proto Local                                          "
160 			 " Remote                                         "
161 			 " SvID ConnID   End Use State    Key     "
162 			 " Serial   ISerial  CallId0  CallId1  CallId2  CallId3\n"
163 			 );
164 		return 0;
165 	}
166 
167 	conn = list_entry(v, struct rxrpc_connection, proc_link);
168 	if (conn->state == RXRPC_CONN_SERVICE_PREALLOC) {
169 		strcpy(lbuff, "no_local");
170 		strcpy(rbuff, "no_connection");
171 		goto print;
172 	}
173 
174 	sprintf(lbuff, "%pISpc", &conn->params.local->srx.transport);
175 
176 	sprintf(rbuff, "%pISpc", &conn->params.peer->srx.transport);
177 print:
178 	seq_printf(seq,
179 		   "UDP   %-47.47s %-47.47s %4x %08x %s %3u"
180 		   " %s %08x %08x %08x %08x %08x %08x %08x\n",
181 		   lbuff,
182 		   rbuff,
183 		   conn->service_id,
184 		   conn->proto.cid,
185 		   rxrpc_conn_is_service(conn) ? "Svc" : "Clt",
186 		   refcount_read(&conn->ref),
187 		   rxrpc_conn_states[conn->state],
188 		   key_serial(conn->params.key),
189 		   atomic_read(&conn->serial),
190 		   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);
195 
196 	return 0;
197 }
198 
199 const struct seq_operations rxrpc_connection_seq_ops = {
200 	.start  = rxrpc_connection_seq_start,
201 	.next   = rxrpc_connection_seq_next,
202 	.stop   = rxrpc_connection_seq_stop,
203 	.show   = rxrpc_connection_seq_show,
204 };
205 
206 /*
207  * generate a list of extant virtual peers in /proc/net/rxrpc/peers
208  */
209 static 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                                         "
219 			 " Use  CW   MTU LastUse      RTT      RTO\n"
220 			 );
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"
233 		   " %3u %5u %6llus %8u %8u\n",
234 		   lbuff,
235 		   rbuff,
236 		   refcount_read(&peer->ref),
237 		   peer->cong_cwnd,
238 		   peer->mtu,
239 		   now - peer->last_tx_at,
240 		   peer->srtt_us >> 3,
241 		   jiffies_to_usecs(peer->rto_j));
242 
243 	return 0;
244 }
245 
246 static 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 
282 static 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 
318 static void rxrpc_peer_seq_stop(struct seq_file *seq, void *v)
319 	__releases(rcu)
320 {
321 	rcu_read_unlock();
322 }
323 
324 
325 const 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 };
331 
332 /*
333  * Generate a list of extant virtual local endpoints in /proc/net/rxrpc/locals
334  */
335 static 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,
354 		   refcount_read(&local->ref),
355 		   atomic_read(&local->active_users));
356 
357 	return 0;
358 }
359 
360 static 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 
378 static 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 
388 static void rxrpc_local_seq_stop(struct seq_file *seq, void *v)
389 	__releases(rcu)
390 {
391 	rcu_read_unlock();
392 }
393 
394 const 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 };
400