All of lore.kernel.org
 help / color / mirror / Atom feed
From: Chuck Lever <chuck.lever@oracle.com>
To: netdev@vger.kernel.org, linux-nfs@vger.kernel.org,
	linux-nvme@lists.infradead.org, linux-cifs@vger.kernel.org,
	linux-fsdevel@vger.kernel.org
Cc: ak@tempesta-tech.com, borisp@nvidia.com, simo@redhat.com
Subject: [PATCH RFC 11/15] SUNRPC: Add infrastructure for async RPC_AUTH_TLS probe
Date: Mon, 18 Apr 2022 12:52:22 -0400	[thread overview]
Message-ID: <165030074244.5246.8728494438187879593.stgit@oracle-102.nfsv4.dev> (raw)
In-Reply-To: <165030062272.5246.16956092606399079004.stgit@oracle-102.nfsv4.dev>

Introduce helpers for sending an RPC_AUTH_TLS probe, waiting for
it, and then parsing the reply. These will be used to handle the
reconnect case.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 include/linux/sunrpc/clnt.h |    1 +
 include/linux/sunrpc/xprt.h |   13 ++++++++++
 net/sunrpc/clnt.c           |   58 +++++++++++++++++++++++++++++++++++++++++++
 net/sunrpc/xprt.c           |    1 +
 net/sunrpc/xprtsock.c       |   56 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 129 insertions(+)

diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index e10a19d136ca..15fd84e4c321 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -209,6 +209,7 @@ int		rpc_call_sync(struct rpc_clnt *clnt,
 			      unsigned int flags);
 struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred,
 			       int flags);
+void		rpc_starttls_async(struct rpc_task *task);
 int		rpc_restart_call_prepare(struct rpc_task *);
 int		rpc_restart_call(struct rpc_task *);
 void		rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int);
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index 8d654bc35dce..cbb0fe738d97 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -159,6 +159,7 @@ struct rpc_xprt_ops {
 	void		(*disable_swap)(struct rpc_xprt *xprt);
 	void		(*inject_disconnect)(struct rpc_xprt *xprt);
 	int		(*tls_handshake_sync)(struct rpc_xprt *xprt);
+	int		(*tls_handshake_async)(struct rpc_xprt *xprt);
 	int		(*bc_setup)(struct rpc_xprt *xprt,
 				    unsigned int min_reqs);
 	size_t		(*bc_maxpayload)(struct rpc_xprt *xprt);
@@ -204,6 +205,7 @@ struct rpc_xprt {
 	size_t			max_payload;	/* largest RPC payload size,
 						   in bytes */
 
+	struct rpc_wait_queue	probing;	/* requests waiting on TLS probe */
 	struct rpc_wait_queue	binding;	/* requests waiting on rpcbind */
 	struct rpc_wait_queue	sending;	/* requests waiting to send */
 	struct rpc_wait_queue	pending;	/* requests in flight */
@@ -436,6 +438,7 @@ void			xprt_release_write(struct rpc_xprt *, struct rpc_task *);
 #define XPRT_CWND_WAIT		(10)
 #define XPRT_WRITE_SPACE	(11)
 #define XPRT_SND_IS_COOKIE	(12)
+#define XPRT_PROBING		(13)
 
 static inline void xprt_set_connected(struct rpc_xprt *xprt)
 {
@@ -506,4 +509,14 @@ static inline int xprt_test_and_set_binding(struct rpc_xprt *xprt)
 	return test_and_set_bit(XPRT_BINDING, &xprt->state);
 }
 
+static inline void xprt_clear_probing(struct rpc_xprt *xprt)
+{
+	clear_bit(XPRT_PROBING, &xprt->state);
+}
+
+static inline int xprt_test_and_set_probing(struct rpc_xprt *xprt)
+{
+	return test_and_set_bit(XPRT_PROBING, &xprt->state);
+}
+
 #endif /* _LINUX_SUNRPC_XPRT_H */
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 1601a06deaf5..e9a6622dba68 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -2829,6 +2829,64 @@ static int rpc_starttls_sync(struct rpc_clnt *clnt)
 	return err;
 }
 
+static void rpc_probe_tls_done(struct rpc_task *task, void *data)
+{
+	struct rpc_xprt *xprt = data;
+
+	if (task->tk_status < 0) {
+		trace_rpc_tls_unavailable(task->tk_client, xprt);
+		xprt_clear_probing(xprt);
+		rpc_wake_up_status(&xprt->probing, task->tk_status);
+		return;
+	}
+
+	/* Send ClientHello; a second callback will wake the waiting task */
+	if (xprt->ops->tls_handshake_async(xprt)) {
+		trace_rpc_tls_not_started(task->tk_client, xprt);
+		xprt_clear_probing(xprt);
+		rpc_wake_up_status(&xprt->probing, -EACCES);
+	}
+}
+
+static void rpc_probe_tls_release(void *data)
+{
+	struct rpc_xprt *xprt = data;
+
+	xprt_put(xprt);
+}
+
+static const struct rpc_call_ops rpc_ops_probe_tls = {
+	.rpc_call_done	= rpc_probe_tls_done,
+	.rpc_release	= rpc_probe_tls_release,
+};
+
+/**
+ * rpc_starttls_async - Asynchronously establish a TLS session
+ * @task: an RPC task waiting for a TLS session
+ *
+ */
+void rpc_starttls_async(struct rpc_task *task)
+{
+	struct rpc_xprt *xprt = xprt_get(task->tk_xprt);
+
+	rpc_sleep_on_timeout(&xprt->probing, task, NULL,
+			     jiffies + xprt->connect_timeout);
+	if (xprt_test_and_set_probing(xprt)) {
+		xprt_put(xprt);
+		return;
+	}
+
+	/*
+	 * RPC_TASK_TLSCRED: use an RPC_AUTH_TLS cred instead of AUTH_NULL
+	 * RPC_TASK_SWAPPER: insert the task at the head of the transmit queue
+	 * RPC_TASK_CORK: stop sending after this Call is transmitted
+	 */
+	rpc_put_task(rpc_call_null_helper(task->tk_client, xprt, NULL,
+		     RPC_TASK_TLSCRED | RPC_TASK_SWAPPER | RPC_TASK_CORK,
+		     &rpc_ops_probe_tls, xprt));
+}
+EXPORT_SYMBOL_GPL(rpc_starttls_async);
+
 struct rpc_cb_add_xprt_calldata {
 	struct rpc_xprt_switch *xps;
 	struct rpc_xprt *xprt;
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 4b303b945b51..762281dba077 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -2016,6 +2016,7 @@ static void xprt_init(struct rpc_xprt *xprt, struct net *net)
 	xprt->cwnd = RPC_INITCWND;
 	xprt->bind_index = 0;
 
+	rpc_init_wait_queue(&xprt->probing, "xprt_probing");
 	rpc_init_wait_queue(&xprt->binding, "xprt_binding");
 	rpc_init_wait_queue(&xprt->pending, "xprt_pending");
 	rpc_init_wait_queue(&xprt->sending, "xprt_sending");
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index bbba9747f68d..bb8c32002ce7 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -2378,6 +2378,46 @@ static int xs_tcp_tls_handshake_sync(struct rpc_xprt *xprt)
 	return rc;
 }
 
+/**
+ * xs_tcp_tls_handshake_wake - TLS handshake completion handler
+ * @data: address of xprt to wake
+ * @status: status of handshake
+ *
+ */
+static void xs_tcp_tls_handshake_wake(void *data, int status)
+{
+	struct rpc_xprt *xprt = data;
+	struct sock_xprt *transport =
+				container_of(xprt, struct sock_xprt, xprt);
+
+	xs_tcp_clear_discard(transport);
+	xprt_clear_probing(xprt);
+	rpc_wake_up_status(&xprt->probing, status < 0 ? -EACCES : 0);
+	xprt_put(xprt);
+}
+
+/**
+ * xs_tcp_tls_handshake_async - Start a TLS handshake
+ * @xprt: transport on which to perform handshake
+ *
+ * Caller ensures there will be no other traffic on this transport.
+ *
+ * Return values:
+ *   %0: Handshake initiated; @xprt will be awoken when it's done.
+ *   Negative errno: handshake was not started.
+ */
+static int xs_tcp_tls_handshake_async(struct rpc_xprt *xprt)
+{
+	struct sock_xprt *transport =
+				container_of(xprt, struct sock_xprt, xprt);
+
+	WRITE_ONCE(transport->recv.ignore_dr, true);
+	return tls_client_hello_x509(transport->sock,
+				     xs_tcp_tls_handshake_wake, xprt_get(xprt),
+				     TLSH_DEFAULT_PRIORITIES, TLSH_NO_PEERID,
+				     TLSH_NO_CERT);
+}
+
 #else /* CONFIG_TLS */
 
 /**
@@ -2394,6 +2434,21 @@ static int xs_tcp_tls_handshake_sync(struct rpc_xprt *xprt)
 	return -EACCES;
 }
 
+/**
+ * xs_tcp_tls_handshake_async - Start a TLS handshake
+ * @xprt: transport on which to perform handshake
+ *
+ * Caller ensures there will be no other traffic on this transport.
+ *
+ * Return values:
+ *   %0: Handshake initiated; @xprt will be awoken when it's done.
+ *   Negative errno: handshake was not started.
+ */
+static int xs_tcp_tls_handshake_async(struct rpc_xprt *xprt)
+{
+	return -EACCES;
+}
+
 #endif /*CONFIG_TLS */
 
 /**
@@ -2845,6 +2900,7 @@ static const struct rpc_xprt_ops xs_tcp_ops = {
 	.disable_swap		= xs_disable_swap,
 	.inject_disconnect	= xs_inject_disconnect,
 	.tls_handshake_sync	= xs_tcp_tls_handshake_sync,
+	.tls_handshake_async	= xs_tcp_tls_handshake_async,
 #ifdef CONFIG_SUNRPC_BACKCHANNEL
 	.bc_setup		= xprt_setup_bc,
 	.bc_maxpayload		= xs_tcp_bc_maxpayload,



  parent reply	other threads:[~2022-04-18 16:54 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-04-18 16:51 [PATCH RFC 00/15] Prototype implementation of RPC-with-TLS Chuck Lever
2022-04-18 16:51 ` [PATCH RFC 01/15] SUNRPC: Replace dprintk() call site in xs_data_ready Chuck Lever
2022-04-18 16:51 ` [PATCH RFC 02/15] SUNRPC: Ignore data_ready callbacks during TLS handshakes Chuck Lever
2022-04-18 16:51 ` [PATCH RFC 03/15] SUNRPC: Capture cmsg metadata on client-side receive Chuck Lever
2022-04-18 16:51 ` [PATCH RFC 04/15] SUNRPC: Fail faster on bad verifier Chuck Lever
2022-04-18 16:51 ` [PATCH RFC 05/15] SUNRPC: Widen rpc_task::tk_flags Chuck Lever
2022-04-18 16:51 ` [PATCH RFC 06/15] SUNRPC: Add RPC client support for the RPC_AUTH_TLS authentication flavor Chuck Lever
2022-04-18 16:51 ` [PATCH RFC 07/15] SUNRPC: Refactor rpc_call_null_helper() Chuck Lever
2022-04-18 16:52 ` [PATCH RFC 08/15] SUNRPC: Add RPC_TASK_CORK flag Chuck Lever
2022-04-19  2:57   ` Trond Myklebust
2022-04-19 18:16     ` Chuck Lever III
2022-04-19 19:04       ` Trond Myklebust
2022-04-19 19:40         ` Chuck Lever III
2022-04-19 22:08           ` Trond Myklebust
2022-04-20  0:34             ` Chuck Lever III
2022-04-18 16:52 ` [PATCH RFC 09/15] SUNRPC: Add a cl_xprtsec_policy field Chuck Lever
2022-04-18 16:52 ` [PATCH RFC 10/15] SUNRPC: Expose TLS policy via the rpc_create() API Chuck Lever
2022-04-18 16:52 ` Chuck Lever [this message]
2022-04-18 16:52 ` [PATCH RFC 12/15] SUNRPC: Add FSM machinery to handle RPC_AUTH_TLS on reconnect Chuck Lever
2022-04-18 16:52 ` [PATCH RFC 13/15] NFS: Replace fs_context-related dprintk() call sites with tracepoints Chuck Lever
2022-04-18 16:52 ` [PATCH RFC 14/15] NFS: Have struct nfs_client carry a TLS policy field Chuck Lever
2022-04-18 16:52 ` [PATCH RFC 15/15] NFS: Add an "xprtsec=" NFS mount option Chuck Lever
2022-04-19  3:31 ` [PATCH RFC 00/15] Prototype implementation of RPC-with-TLS Trond Myklebust
2022-04-19 16:00   ` Chuck Lever III
2022-04-19 18:48     ` Trond Myklebust
2022-04-19 18:53       ` Chuck Lever III
2022-04-19 20:49         ` Rick Macklem

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=165030074244.5246.8728494438187879593.stgit@oracle-102.nfsv4.dev \
    --to=chuck.lever@oracle.com \
    --cc=ak@tempesta-tech.com \
    --cc=borisp@nvidia.com \
    --cc=linux-cifs@vger.kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-nfs@vger.kernel.org \
    --cc=linux-nvme@lists.infradead.org \
    --cc=netdev@vger.kernel.org \
    --cc=simo@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.