18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/* rxrpc network namespace handling.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
58c2ecf20Sopenharmony_ci * Written by David Howells (dhowells@redhat.com)
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/proc_fs.h>
98c2ecf20Sopenharmony_ci#include "ar-internal.h"
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ciunsigned int rxrpc_net_id;
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_cistatic void rxrpc_client_conn_reap_timeout(struct timer_list *timer)
148c2ecf20Sopenharmony_ci{
158c2ecf20Sopenharmony_ci	struct rxrpc_net *rxnet =
168c2ecf20Sopenharmony_ci		container_of(timer, struct rxrpc_net, client_conn_reap_timer);
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci	if (rxnet->live)
198c2ecf20Sopenharmony_ci		rxrpc_queue_work(&rxnet->client_conn_reaper);
208c2ecf20Sopenharmony_ci}
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistatic void rxrpc_service_conn_reap_timeout(struct timer_list *timer)
238c2ecf20Sopenharmony_ci{
248c2ecf20Sopenharmony_ci	struct rxrpc_net *rxnet =
258c2ecf20Sopenharmony_ci		container_of(timer, struct rxrpc_net, service_conn_reap_timer);
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci	if (rxnet->live)
288c2ecf20Sopenharmony_ci		rxrpc_queue_work(&rxnet->service_conn_reaper);
298c2ecf20Sopenharmony_ci}
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistatic void rxrpc_peer_keepalive_timeout(struct timer_list *timer)
328c2ecf20Sopenharmony_ci{
338c2ecf20Sopenharmony_ci	struct rxrpc_net *rxnet =
348c2ecf20Sopenharmony_ci		container_of(timer, struct rxrpc_net, peer_keepalive_timer);
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	if (rxnet->live)
378c2ecf20Sopenharmony_ci		rxrpc_queue_work(&rxnet->peer_keepalive_work);
388c2ecf20Sopenharmony_ci}
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci/*
418c2ecf20Sopenharmony_ci * Initialise a per-network namespace record.
428c2ecf20Sopenharmony_ci */
438c2ecf20Sopenharmony_cistatic __net_init int rxrpc_init_net(struct net *net)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	struct rxrpc_net *rxnet = rxrpc_net(net);
468c2ecf20Sopenharmony_ci	int ret, i;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	rxnet->live = true;
498c2ecf20Sopenharmony_ci	get_random_bytes(&rxnet->epoch, sizeof(rxnet->epoch));
508c2ecf20Sopenharmony_ci	rxnet->epoch |= RXRPC_RANDOM_EPOCH;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&rxnet->calls);
538c2ecf20Sopenharmony_ci	rwlock_init(&rxnet->call_lock);
548c2ecf20Sopenharmony_ci	atomic_set(&rxnet->nr_calls, 1);
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	atomic_set(&rxnet->nr_conns, 1);
578c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&rxnet->conn_proc_list);
588c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&rxnet->service_conns);
598c2ecf20Sopenharmony_ci	rwlock_init(&rxnet->conn_lock);
608c2ecf20Sopenharmony_ci	INIT_WORK(&rxnet->service_conn_reaper,
618c2ecf20Sopenharmony_ci		  rxrpc_service_connection_reaper);
628c2ecf20Sopenharmony_ci	timer_setup(&rxnet->service_conn_reap_timer,
638c2ecf20Sopenharmony_ci		    rxrpc_service_conn_reap_timeout, 0);
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	atomic_set(&rxnet->nr_client_conns, 0);
668c2ecf20Sopenharmony_ci	rxnet->kill_all_client_conns = false;
678c2ecf20Sopenharmony_ci	spin_lock_init(&rxnet->client_conn_cache_lock);
688c2ecf20Sopenharmony_ci	spin_lock_init(&rxnet->client_conn_discard_lock);
698c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&rxnet->idle_client_conns);
708c2ecf20Sopenharmony_ci	INIT_WORK(&rxnet->client_conn_reaper,
718c2ecf20Sopenharmony_ci		  rxrpc_discard_expired_client_conns);
728c2ecf20Sopenharmony_ci	timer_setup(&rxnet->client_conn_reap_timer,
738c2ecf20Sopenharmony_ci		    rxrpc_client_conn_reap_timeout, 0);
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	INIT_HLIST_HEAD(&rxnet->local_endpoints);
768c2ecf20Sopenharmony_ci	mutex_init(&rxnet->local_mutex);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	hash_init(rxnet->peer_hash);
798c2ecf20Sopenharmony_ci	spin_lock_init(&rxnet->peer_hash_lock);
808c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(rxnet->peer_keepalive); i++)
818c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&rxnet->peer_keepalive[i]);
828c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&rxnet->peer_keepalive_new);
838c2ecf20Sopenharmony_ci	timer_setup(&rxnet->peer_keepalive_timer,
848c2ecf20Sopenharmony_ci		    rxrpc_peer_keepalive_timeout, 0);
858c2ecf20Sopenharmony_ci	INIT_WORK(&rxnet->peer_keepalive_work, rxrpc_peer_keepalive_worker);
868c2ecf20Sopenharmony_ci	rxnet->peer_keepalive_base = ktime_get_seconds();
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	ret = -ENOMEM;
898c2ecf20Sopenharmony_ci	rxnet->proc_net = proc_net_mkdir(net, "rxrpc", net->proc_net);
908c2ecf20Sopenharmony_ci	if (!rxnet->proc_net)
918c2ecf20Sopenharmony_ci		goto err_proc;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	proc_create_net("calls", 0444, rxnet->proc_net, &rxrpc_call_seq_ops,
948c2ecf20Sopenharmony_ci			sizeof(struct seq_net_private));
958c2ecf20Sopenharmony_ci	proc_create_net("conns", 0444, rxnet->proc_net,
968c2ecf20Sopenharmony_ci			&rxrpc_connection_seq_ops,
978c2ecf20Sopenharmony_ci			sizeof(struct seq_net_private));
988c2ecf20Sopenharmony_ci	proc_create_net("peers", 0444, rxnet->proc_net,
998c2ecf20Sopenharmony_ci			&rxrpc_peer_seq_ops,
1008c2ecf20Sopenharmony_ci			sizeof(struct seq_net_private));
1018c2ecf20Sopenharmony_ci	proc_create_net("locals", 0444, rxnet->proc_net,
1028c2ecf20Sopenharmony_ci			&rxrpc_local_seq_ops,
1038c2ecf20Sopenharmony_ci			sizeof(struct seq_net_private));
1048c2ecf20Sopenharmony_ci	return 0;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cierr_proc:
1078c2ecf20Sopenharmony_ci	rxnet->live = false;
1088c2ecf20Sopenharmony_ci	return ret;
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci/*
1128c2ecf20Sopenharmony_ci * Clean up a per-network namespace record.
1138c2ecf20Sopenharmony_ci */
1148c2ecf20Sopenharmony_cistatic __net_exit void rxrpc_exit_net(struct net *net)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	struct rxrpc_net *rxnet = rxrpc_net(net);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	rxnet->live = false;
1198c2ecf20Sopenharmony_ci	del_timer_sync(&rxnet->peer_keepalive_timer);
1208c2ecf20Sopenharmony_ci	cancel_work_sync(&rxnet->peer_keepalive_work);
1218c2ecf20Sopenharmony_ci	/* Remove the timer again as the worker may have restarted it. */
1228c2ecf20Sopenharmony_ci	del_timer_sync(&rxnet->peer_keepalive_timer);
1238c2ecf20Sopenharmony_ci	rxrpc_destroy_all_calls(rxnet);
1248c2ecf20Sopenharmony_ci	rxrpc_destroy_all_connections(rxnet);
1258c2ecf20Sopenharmony_ci	rxrpc_destroy_all_peers(rxnet);
1268c2ecf20Sopenharmony_ci	rxrpc_destroy_all_locals(rxnet);
1278c2ecf20Sopenharmony_ci	proc_remove(rxnet->proc_net);
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistruct pernet_operations rxrpc_net_ops = {
1318c2ecf20Sopenharmony_ci	.init	= rxrpc_init_net,
1328c2ecf20Sopenharmony_ci	.exit	= rxrpc_exit_net,
1338c2ecf20Sopenharmony_ci	.id	= &rxrpc_net_id,
1348c2ecf20Sopenharmony_ci	.size	= sizeof(struct rxrpc_net),
1358c2ecf20Sopenharmony_ci};
136