Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2baec2c3 authored by David Howells's avatar David Howells Committed by David S. Miller
Browse files

rxrpc: Support network namespacing



Support network namespacing in AF_RXRPC with the following changes:

 (1) All the local endpoint, peer and call lists, locks, counters, etc. are
     moved into the per-namespace record.

 (2) All the connection tracking is moved into the per-namespace record
     with the exception of the client connection ID tree, which is kept
     global so that connection IDs are kept unique per-machine.

 (3) Each namespace gets its own epoch.  This allows each network namespace
     to pretend to be a separate client machine.

 (4) The /proc/net/rxrpc_xxx files are now called /proc/net/rxrpc/xxx and
     the contents reflect the namespace.

fs/afs/ should be okay with this patch as it explicitly requires the current
net namespace to be init_net to permit a mount to proceed at the moment.  It
will, however, need updating so that cells, IP addresses and DNS records are
per-namespace also.

Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 878cd3ba
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ rxrpc-y := \
	local_event.o \
	local_object.o \
	misc.o \
	net_ns.o \
	output.o \
	peer_event.o \
	peer_object.o \
+15 −20
Original line number Diff line number Diff line
@@ -38,9 +38,6 @@ MODULE_PARM_DESC(debug, "RxRPC debugging mask");
static struct proto rxrpc_proto;
static const struct proto_ops rxrpc_rpc_ops;

/* local epoch for detecting local-end reset */
u32 rxrpc_epoch;

/* current debugging ID */
atomic_t rxrpc_debug_id;

@@ -155,7 +152,7 @@ static int rxrpc_bind(struct socket *sock, struct sockaddr *saddr, int len)

	memcpy(&rx->srx, srx, sizeof(rx->srx));

	local = rxrpc_lookup_local(&rx->srx);
	local = rxrpc_lookup_local(sock_net(sock->sk), &rx->srx);
	if (IS_ERR(local)) {
		ret = PTR_ERR(local);
		goto error_unlock;
@@ -434,7 +431,7 @@ static int rxrpc_sendmsg(struct socket *sock, struct msghdr *m, size_t len)
			ret = -EAFNOSUPPORT;
			goto error_unlock;
		}
		local = rxrpc_lookup_local(&rx->srx);
		local = rxrpc_lookup_local(sock_net(sock->sk), &rx->srx);
		if (IS_ERR(local)) {
			ret = PTR_ERR(local);
			goto error_unlock;
@@ -582,9 +579,6 @@ static int rxrpc_create(struct net *net, struct socket *sock, int protocol,

	_enter("%p,%d", sock, protocol);

	if (!net_eq(net, &init_net))
		return -EAFNOSUPPORT;

	/* we support transport protocol UDP/UDP6 only */
	if (protocol != PF_INET &&
	    IS_ENABLED(CONFIG_AF_RXRPC_IPV6) && protocol != PF_INET6)
@@ -780,8 +774,6 @@ static int __init af_rxrpc_init(void)

	BUILD_BUG_ON(sizeof(struct rxrpc_skb_priv) > FIELD_SIZEOF(struct sk_buff, cb));

	get_random_bytes(&rxrpc_epoch, sizeof(rxrpc_epoch));
	rxrpc_epoch |= RXRPC_RANDOM_EPOCH;
	get_random_bytes(&tmp, sizeof(tmp));
	tmp &= 0x3fffffff;
	if (tmp == 0)
@@ -809,6 +801,10 @@ static int __init af_rxrpc_init(void)
		goto error_security;
	}

	ret = register_pernet_subsys(&rxrpc_net_ops);
	if (ret)
		goto error_pernet;

	ret = proto_register(&rxrpc_proto, 1);
	if (ret < 0) {
		pr_crit("Cannot register protocol\n");
@@ -839,11 +835,6 @@ static int __init af_rxrpc_init(void)
		goto error_sysctls;
	}

#ifdef CONFIG_PROC_FS
	proc_create("rxrpc_calls", 0, init_net.proc_net, &rxrpc_call_seq_fops);
	proc_create("rxrpc_conns", 0, init_net.proc_net,
		    &rxrpc_connection_seq_fops);
#endif
	return 0;

error_sysctls:
@@ -855,6 +846,8 @@ static int __init af_rxrpc_init(void)
error_sock:
	proto_unregister(&rxrpc_proto);
error_proto:
	unregister_pernet_subsys(&rxrpc_net_ops);
error_pernet:
	rxrpc_exit_security();
error_security:
	destroy_workqueue(rxrpc_workqueue);
@@ -875,14 +868,16 @@ static void __exit af_rxrpc_exit(void)
	unregister_key_type(&key_type_rxrpc);
	sock_unregister(PF_RXRPC);
	proto_unregister(&rxrpc_proto);
	rxrpc_destroy_all_calls();
	rxrpc_destroy_all_connections();
	unregister_pernet_subsys(&rxrpc_net_ops);
	ASSERTCMP(atomic_read(&rxrpc_n_tx_skbs), ==, 0);
	ASSERTCMP(atomic_read(&rxrpc_n_rx_skbs), ==, 0);
	rxrpc_destroy_all_locals();

	remove_proc_entry("rxrpc_conns", init_net.proc_net);
	remove_proc_entry("rxrpc_calls", init_net.proc_net);
	/* Make sure the local and peer records pinned by any dying connections
	 * are released.
	 */
	rcu_barrier();
	rxrpc_destroy_client_conn_ids();

	destroy_workqueue(rxrpc_workqueue);
	rxrpc_exit_security();
	kmem_cache_destroy(rxrpc_call_jar);
+53 −12
Original line number Diff line number Diff line
@@ -11,6 +11,8 @@

#include <linux/atomic.h>
#include <linux/seqlock.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <net/sock.h>
#include <net/af_rxrpc.h>
#include <rxrpc/packet.h>
@@ -64,6 +66,37 @@ enum {
	RXRPC_CLOSE,			/* socket is being closed */
};

/*
 * Per-network namespace data.
 */
struct rxrpc_net {
	struct proc_dir_entry	*proc_net;	/* Subdir in /proc/net */
	u32			epoch;		/* Local epoch for detecting local-end reset */
	struct list_head	calls;		/* List of calls active in this namespace */
	rwlock_t		call_lock;	/* Lock for ->calls */

	struct list_head	conn_proc_list;	/* List of conns in this namespace for proc */
	struct list_head	service_conns;	/* Service conns in this namespace */
	rwlock_t		conn_lock;	/* Lock for ->conn_proc_list, ->service_conns */
	struct delayed_work	service_conn_reaper;

	unsigned int		nr_client_conns;
	unsigned int		nr_active_client_conns;
	bool			kill_all_client_conns;
	spinlock_t		client_conn_cache_lock; /* Lock for ->*_client_conns */
	spinlock_t		client_conn_discard_lock; /* Prevent multiple discarders */
	struct list_head	waiting_client_conns;
	struct list_head	active_client_conns;
	struct list_head	idle_client_conns;
	struct delayed_work	client_conn_reaper;

	struct list_head	local_endpoints;
	struct mutex		local_mutex;	/* Lock for ->local_endpoints */

	spinlock_t		peer_hash_lock;	/* Lock for ->peer_hash */
	DECLARE_HASHTABLE	(peer_hash, 10);
};

/*
 * Service backlog preallocation.
 *
@@ -211,6 +244,7 @@ struct rxrpc_security {
struct rxrpc_local {
	struct rcu_head		rcu;
	atomic_t		usage;
	struct rxrpc_net	*rxnet;		/* The network ns in which this resides */
	struct list_head	link;
	struct socket		*socket;	/* my UDP socket */
	struct work_struct	processor;
@@ -601,7 +635,6 @@ struct rxrpc_ack_summary {
 * af_rxrpc.c
 */
extern atomic_t rxrpc_n_tx_skbs, rxrpc_n_rx_skbs;
extern u32 rxrpc_epoch;
extern atomic_t rxrpc_debug_id;
extern struct workqueue_struct *rxrpc_workqueue;

@@ -634,8 +667,6 @@ extern const char *const rxrpc_call_states[];
extern const char *const rxrpc_call_completions[];
extern unsigned int rxrpc_max_call_lifetime;
extern struct kmem_cache *rxrpc_call_jar;
extern struct list_head rxrpc_calls;
extern rwlock_t rxrpc_call_lock;

struct rxrpc_call *rxrpc_find_call_by_user_ID(struct rxrpc_sock *, unsigned long);
struct rxrpc_call *rxrpc_alloc_call(gfp_t);
@@ -653,7 +684,7 @@ void rxrpc_see_call(struct rxrpc_call *);
void rxrpc_get_call(struct rxrpc_call *, enum rxrpc_call_trace);
void rxrpc_put_call(struct rxrpc_call *, enum rxrpc_call_trace);
void rxrpc_cleanup_call(struct rxrpc_call *);
void __exit rxrpc_destroy_all_calls(void);
void rxrpc_destroy_all_calls(struct rxrpc_net *);

static inline bool rxrpc_is_service_call(const struct rxrpc_call *call)
{
@@ -773,7 +804,8 @@ int rxrpc_connect_call(struct rxrpc_call *, struct rxrpc_conn_parameters *,
void rxrpc_expose_client_call(struct rxrpc_call *);
void rxrpc_disconnect_client_call(struct rxrpc_call *);
void rxrpc_put_client_conn(struct rxrpc_connection *);
void __exit rxrpc_destroy_all_client_connections(void);
void rxrpc_discard_expired_client_conns(struct work_struct *);
void rxrpc_destroy_all_client_connections(struct rxrpc_net *);

/*
 * conn_event.c
@@ -784,9 +816,6 @@ void rxrpc_process_connection(struct work_struct *);
 * conn_object.c
 */
extern unsigned int rxrpc_connection_expiry;
extern struct list_head rxrpc_connections;
extern struct list_head rxrpc_connection_proc_list;
extern rwlock_t rxrpc_connection_lock;

int rxrpc_extract_addr_from_skb(struct sockaddr_rxrpc *, struct sk_buff *);
struct rxrpc_connection *rxrpc_alloc_connection(gfp_t);
@@ -800,7 +829,8 @@ void rxrpc_see_connection(struct rxrpc_connection *);
void rxrpc_get_connection(struct rxrpc_connection *);
struct rxrpc_connection *rxrpc_get_connection_maybe(struct rxrpc_connection *);
void rxrpc_put_service_conn(struct rxrpc_connection *);
void __exit rxrpc_destroy_all_connections(void);
void rxrpc_service_connection_reaper(struct work_struct *);
void rxrpc_destroy_all_connections(struct rxrpc_net *);

static inline bool rxrpc_conn_is_client(const struct rxrpc_connection *conn)
{
@@ -828,7 +858,7 @@ static inline void rxrpc_put_connection(struct rxrpc_connection *conn)
 */
struct rxrpc_connection *rxrpc_find_service_conn_rcu(struct rxrpc_peer *,
						     struct sk_buff *);
struct rxrpc_connection *rxrpc_prealloc_service_connection(gfp_t);
struct rxrpc_connection *rxrpc_prealloc_service_connection(struct rxrpc_net *, gfp_t);
void rxrpc_new_incoming_connection(struct rxrpc_connection *, struct sk_buff *);
void rxrpc_unpublish_service_conn(struct rxrpc_connection *);

@@ -861,9 +891,9 @@ extern void rxrpc_process_local_events(struct rxrpc_local *);
/*
 * local_object.c
 */
struct rxrpc_local *rxrpc_lookup_local(const struct sockaddr_rxrpc *);
struct rxrpc_local *rxrpc_lookup_local(struct net *, const struct sockaddr_rxrpc *);
void __rxrpc_put_local(struct rxrpc_local *);
void __exit rxrpc_destroy_all_locals(void);
void rxrpc_destroy_all_locals(struct rxrpc_net *);

static inline void rxrpc_get_local(struct rxrpc_local *local)
{
@@ -901,6 +931,17 @@ extern unsigned int rxrpc_resend_timeout;

extern const s8 rxrpc_ack_priority[];

/*
 * net_ns.c
 */
extern unsigned int rxrpc_net_id;
extern struct pernet_operations rxrpc_net_ops;

static inline struct rxrpc_net *rxrpc_net(struct net *net)
{
	return net_generic(net, rxrpc_net_id);
}

/*
 * output.c
 */
+8 −6
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx,
{
	const void *here = __builtin_return_address(0);
	struct rxrpc_call *call;
	struct rxrpc_net *rxnet = rxrpc_net(sock_net(&rx->sk));
	int max, tmp;
	unsigned int size = RXRPC_BACKLOG_MAX;
	unsigned int head, tail, call_head, call_tail;
@@ -79,7 +80,7 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx,
	if (CIRC_CNT(head, tail, size) < max) {
		struct rxrpc_connection *conn;

		conn = rxrpc_prealloc_service_connection(gfp);
		conn = rxrpc_prealloc_service_connection(rxnet, gfp);
		if (!conn)
			return -ENOMEM;
		b->conn_backlog[head] = conn;
@@ -136,9 +137,9 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx,

	write_unlock(&rx->call_lock);

	write_lock(&rxrpc_call_lock);
	list_add_tail(&call->link, &rxrpc_calls);
	write_unlock(&rxrpc_call_lock);
	write_lock(&rxnet->call_lock);
	list_add_tail(&call->link, &rxnet->calls);
	write_unlock(&rxnet->call_lock);

	b->call_backlog[call_head] = call;
	smp_store_release(&b->call_backlog_head, (call_head + 1) & (size - 1));
@@ -185,6 +186,7 @@ int rxrpc_service_prealloc(struct rxrpc_sock *rx, gfp_t gfp)
void rxrpc_discard_prealloc(struct rxrpc_sock *rx)
{
	struct rxrpc_backlog *b = rx->backlog;
	struct rxrpc_net *rxnet = rxrpc_net(sock_net(&rx->sk));
	unsigned int size = RXRPC_BACKLOG_MAX, head, tail;

	if (!b)
@@ -209,10 +211,10 @@ void rxrpc_discard_prealloc(struct rxrpc_sock *rx)
	tail = b->conn_backlog_tail;
	while (CIRC_CNT(head, tail, size) > 0) {
		struct rxrpc_connection *conn = b->conn_backlog[tail];
		write_lock(&rxrpc_connection_lock);
		write_lock(&rxnet->conn_lock);
		list_del(&conn->link);
		list_del(&conn->proc_link);
		write_unlock(&rxrpc_connection_lock);
		write_unlock(&rxnet->conn_lock);
		kfree(conn);
		tail = (tail + 1) & (size - 1);
	}
+22 −17
Original line number Diff line number Diff line
@@ -44,8 +44,6 @@ const char *const rxrpc_call_completions[NR__RXRPC_CALL_COMPLETIONS] = {
};

struct kmem_cache *rxrpc_call_jar;
LIST_HEAD(rxrpc_calls);
DEFINE_RWLOCK(rxrpc_call_lock);

static void rxrpc_call_timer_expired(unsigned long _call)
{
@@ -207,6 +205,7 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx,
	__releases(&rx->sk.sk_lock.slock)
{
	struct rxrpc_call *call, *xcall;
	struct rxrpc_net *rxnet = rxrpc_net(sock_net(&rx->sk));
	struct rb_node *parent, **pp;
	const void *here = __builtin_return_address(0);
	int ret;
@@ -255,9 +254,9 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx,

	write_unlock(&rx->call_lock);

	write_lock(&rxrpc_call_lock);
	list_add_tail(&call->link, &rxrpc_calls);
	write_unlock(&rxrpc_call_lock);
	write_lock(&rxnet->call_lock);
	list_add_tail(&call->link, &rxnet->calls);
	write_unlock(&rxnet->call_lock);

	/* From this point on, the call is protected by its own lock. */
	release_sock(&rx->sk);
@@ -508,6 +507,7 @@ void rxrpc_release_calls_on_socket(struct rxrpc_sock *rx)
 */
void rxrpc_put_call(struct rxrpc_call *call, enum rxrpc_call_trace op)
{
	struct rxrpc_net *rxnet;
	const void *here = __builtin_return_address(0);
	int n;

@@ -520,9 +520,12 @@ void rxrpc_put_call(struct rxrpc_call *call, enum rxrpc_call_trace op)
		_debug("call %d dead", call->debug_id);
		ASSERTCMP(call->state, ==, RXRPC_CALL_COMPLETE);

		write_lock(&rxrpc_call_lock);
		if (!list_empty(&call->link)) {
			rxnet = rxrpc_net(sock_net(&call->socket->sk));
			write_lock(&rxnet->call_lock);
			list_del_init(&call->link);
		write_unlock(&rxrpc_call_lock);
			write_unlock(&rxnet->call_lock);
		}

		rxrpc_cleanup_call(call);
	}
@@ -570,21 +573,23 @@ void rxrpc_cleanup_call(struct rxrpc_call *call)
}

/*
 * Make sure that all calls are gone.
 * Make sure that all calls are gone from a network namespace.  To reach this
 * point, any open UDP sockets in that namespace must have been closed, so any
 * outstanding calls cannot be doing I/O.
 */
void __exit rxrpc_destroy_all_calls(void)
void rxrpc_destroy_all_calls(struct rxrpc_net *rxnet)
{
	struct rxrpc_call *call;

	_enter("");

	if (list_empty(&rxrpc_calls))
	if (list_empty(&rxnet->calls))
		return;

	write_lock(&rxrpc_call_lock);
	write_lock(&rxnet->call_lock);

	while (!list_empty(&rxrpc_calls)) {
		call = list_entry(rxrpc_calls.next, struct rxrpc_call, link);
	while (!list_empty(&rxnet->calls)) {
		call = list_entry(rxnet->calls.next, struct rxrpc_call, link);
		_debug("Zapping call %p", call);

		rxrpc_see_call(call);
@@ -595,10 +600,10 @@ void __exit rxrpc_destroy_all_calls(void)
		       rxrpc_call_states[call->state],
		       call->flags, call->events);

		write_unlock(&rxrpc_call_lock);
		write_unlock(&rxnet->call_lock);
		cond_resched();
		write_lock(&rxrpc_call_lock);
		write_lock(&rxnet->call_lock);
	}

	write_unlock(&rxrpc_call_lock);
	write_unlock(&rxnet->call_lock);
}
Loading