162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/* rxrpc network namespace handling.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
562306a36Sopenharmony_ci * Written by David Howells (dhowells@redhat.com)
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/proc_fs.h>
962306a36Sopenharmony_ci#include "ar-internal.h"
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ciunsigned int rxrpc_net_id;
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cistatic void rxrpc_service_conn_reap_timeout(struct timer_list *timer)
1462306a36Sopenharmony_ci{
1562306a36Sopenharmony_ci	struct rxrpc_net *rxnet =
1662306a36Sopenharmony_ci		container_of(timer, struct rxrpc_net, service_conn_reap_timer);
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci	if (rxnet->live)
1962306a36Sopenharmony_ci		rxrpc_queue_work(&rxnet->service_conn_reaper);
2062306a36Sopenharmony_ci}
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistatic void rxrpc_peer_keepalive_timeout(struct timer_list *timer)
2362306a36Sopenharmony_ci{
2462306a36Sopenharmony_ci	struct rxrpc_net *rxnet =
2562306a36Sopenharmony_ci		container_of(timer, struct rxrpc_net, peer_keepalive_timer);
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	if (rxnet->live)
2862306a36Sopenharmony_ci		rxrpc_queue_work(&rxnet->peer_keepalive_work);
2962306a36Sopenharmony_ci}
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci/*
3262306a36Sopenharmony_ci * Initialise a per-network namespace record.
3362306a36Sopenharmony_ci */
3462306a36Sopenharmony_cistatic __net_init int rxrpc_init_net(struct net *net)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	struct rxrpc_net *rxnet = rxrpc_net(net);
3762306a36Sopenharmony_ci	int ret, i;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	rxnet->live = true;
4062306a36Sopenharmony_ci	get_random_bytes(&rxnet->epoch, sizeof(rxnet->epoch));
4162306a36Sopenharmony_ci	rxnet->epoch |= RXRPC_RANDOM_EPOCH;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	INIT_LIST_HEAD(&rxnet->calls);
4462306a36Sopenharmony_ci	spin_lock_init(&rxnet->call_lock);
4562306a36Sopenharmony_ci	atomic_set(&rxnet->nr_calls, 1);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	atomic_set(&rxnet->nr_conns, 1);
4862306a36Sopenharmony_ci	INIT_LIST_HEAD(&rxnet->conn_proc_list);
4962306a36Sopenharmony_ci	INIT_LIST_HEAD(&rxnet->service_conns);
5062306a36Sopenharmony_ci	rwlock_init(&rxnet->conn_lock);
5162306a36Sopenharmony_ci	INIT_WORK(&rxnet->service_conn_reaper,
5262306a36Sopenharmony_ci		  rxrpc_service_connection_reaper);
5362306a36Sopenharmony_ci	timer_setup(&rxnet->service_conn_reap_timer,
5462306a36Sopenharmony_ci		    rxrpc_service_conn_reap_timeout, 0);
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	atomic_set(&rxnet->nr_client_conns, 0);
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	INIT_HLIST_HEAD(&rxnet->local_endpoints);
5962306a36Sopenharmony_ci	mutex_init(&rxnet->local_mutex);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	hash_init(rxnet->peer_hash);
6262306a36Sopenharmony_ci	spin_lock_init(&rxnet->peer_hash_lock);
6362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(rxnet->peer_keepalive); i++)
6462306a36Sopenharmony_ci		INIT_LIST_HEAD(&rxnet->peer_keepalive[i]);
6562306a36Sopenharmony_ci	INIT_LIST_HEAD(&rxnet->peer_keepalive_new);
6662306a36Sopenharmony_ci	timer_setup(&rxnet->peer_keepalive_timer,
6762306a36Sopenharmony_ci		    rxrpc_peer_keepalive_timeout, 0);
6862306a36Sopenharmony_ci	INIT_WORK(&rxnet->peer_keepalive_work, rxrpc_peer_keepalive_worker);
6962306a36Sopenharmony_ci	rxnet->peer_keepalive_base = ktime_get_seconds();
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	ret = -ENOMEM;
7262306a36Sopenharmony_ci	rxnet->proc_net = proc_net_mkdir(net, "rxrpc", net->proc_net);
7362306a36Sopenharmony_ci	if (!rxnet->proc_net)
7462306a36Sopenharmony_ci		goto err_proc;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	proc_create_net("calls", 0444, rxnet->proc_net, &rxrpc_call_seq_ops,
7762306a36Sopenharmony_ci			sizeof(struct seq_net_private));
7862306a36Sopenharmony_ci	proc_create_net("conns", 0444, rxnet->proc_net,
7962306a36Sopenharmony_ci			&rxrpc_connection_seq_ops,
8062306a36Sopenharmony_ci			sizeof(struct seq_net_private));
8162306a36Sopenharmony_ci	proc_create_net("peers", 0444, rxnet->proc_net,
8262306a36Sopenharmony_ci			&rxrpc_peer_seq_ops,
8362306a36Sopenharmony_ci			sizeof(struct seq_net_private));
8462306a36Sopenharmony_ci	proc_create_net("locals", 0444, rxnet->proc_net,
8562306a36Sopenharmony_ci			&rxrpc_local_seq_ops,
8662306a36Sopenharmony_ci			sizeof(struct seq_net_private));
8762306a36Sopenharmony_ci	proc_create_net_single_write("stats", S_IFREG | 0644, rxnet->proc_net,
8862306a36Sopenharmony_ci				     rxrpc_stats_show, rxrpc_stats_clear, NULL);
8962306a36Sopenharmony_ci	return 0;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cierr_proc:
9262306a36Sopenharmony_ci	rxnet->live = false;
9362306a36Sopenharmony_ci	return ret;
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci/*
9762306a36Sopenharmony_ci * Clean up a per-network namespace record.
9862306a36Sopenharmony_ci */
9962306a36Sopenharmony_cistatic __net_exit void rxrpc_exit_net(struct net *net)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	struct rxrpc_net *rxnet = rxrpc_net(net);
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	rxnet->live = false;
10462306a36Sopenharmony_ci	del_timer_sync(&rxnet->peer_keepalive_timer);
10562306a36Sopenharmony_ci	cancel_work_sync(&rxnet->peer_keepalive_work);
10662306a36Sopenharmony_ci	/* Remove the timer again as the worker may have restarted it. */
10762306a36Sopenharmony_ci	del_timer_sync(&rxnet->peer_keepalive_timer);
10862306a36Sopenharmony_ci	rxrpc_destroy_all_calls(rxnet);
10962306a36Sopenharmony_ci	rxrpc_destroy_all_connections(rxnet);
11062306a36Sopenharmony_ci	rxrpc_destroy_all_peers(rxnet);
11162306a36Sopenharmony_ci	rxrpc_destroy_all_locals(rxnet);
11262306a36Sopenharmony_ci	proc_remove(rxnet->proc_net);
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistruct pernet_operations rxrpc_net_ops = {
11662306a36Sopenharmony_ci	.init	= rxrpc_init_net,
11762306a36Sopenharmony_ci	.exit	= rxrpc_exit_net,
11862306a36Sopenharmony_ci	.id	= &rxrpc_net_id,
11962306a36Sopenharmony_ci	.size	= sizeof(struct rxrpc_net),
12062306a36Sopenharmony_ci};
121