diff mbox series

[v1,1/5] sunrpc: Allow specifying a vector of IP addresses for nconnect

Message ID 20210121191020.3144948-2-dan@kernelim.com (mailing list archive)
State New, archived
Headers show
Series NFSv3 client RDMA multipath enhancements | expand

Commit Message

Dan Aloni Jan. 21, 2021, 7:10 p.m. UTC
This adds an `rpc_portgroup` structure to describe a group of IP
addresses comprising one logical server with multiple ports. The remote
endpoint can be in a single server exposing multiple network interfaces,
or multiple remote machines implementing a distributed server architecture.

Combined with nconnect, the multiple transports try to make use of the
multiple addresses given so that the connections are spread across the
ports.

Signed-off-by: Dan Aloni <dan@kernelim.com>
---
 include/linux/sunrpc/clnt.h |  9 +++++++
 net/sunrpc/clnt.c           | 47 +++++++++++++++++++++++++++++++++++++
 2 files changed, 56 insertions(+)
diff mbox series

Patch

diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index 02e7a5863d28..f8c0c33281a8 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -115,12 +115,21 @@  struct rpc_procinfo {
 	const char *		p_name;		/* name of procedure */
 };
 
+#define RPC_MAX_PORTS 64
+
+struct rpc_portgroup {
+	int nr;
+	struct sockaddr_storage addrs[RPC_MAX_PORTS];
+};
+
 struct rpc_create_args {
 	struct net		*net;
 	int			protocol;
 	struct sockaddr		*address;
 	size_t			addrsize;
 	struct sockaddr		*saddress;
+	struct rpc_portgroup    *localports;    /* additional local addresses */
+	struct rpc_portgroup    *remoteports;   /* additional remote addresses */
 	const struct rpc_timeout *timeout;
 	const char		*servername;
 	const char		*nodename;
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 612f0a641f4c..5f335a873f03 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -500,6 +500,44 @@  static struct rpc_clnt *rpc_create_xprt(struct rpc_create_args *args,
 	return clnt;
 }
 
+struct rpc_clnt_portgroup_iter {
+	struct rpc_portgroup *pg;
+	int idx;
+};
+
+static void take_iter_portgroup_addr(struct rpc_clnt_portgroup_iter *iter,
+				struct sockaddr	**address)
+{
+	struct rpc_portgroup *pg = iter->pg;
+	struct sockaddr	*existing = *address;
+	struct sockaddr	*new;
+
+	if (!pg || pg->nr == 0)
+		return;
+	if (iter->idx >= pg->nr)
+		iter->idx = 0;
+
+	/* Take port from existing address, or use autobind (0) */
+	new = (struct sockaddr *)&pg->addrs[iter->idx++];
+
+	switch (new->sa_family) {
+	case AF_INET:
+		((struct sockaddr_in *)new)->sin_port =
+			existing ? ((struct sockaddr_in *)existing)->sin_port
+			         : 0;
+		break;
+	case AF_INET6:
+		((struct sockaddr_in6 *)new)->sin6_port =
+			existing ? ((struct sockaddr_in6 *)existing)->sin6_port
+			         : 0;
+		break;
+	default:
+		return;
+	}
+
+	*address = new;
+}
+
 /**
  * rpc_create - create an RPC client and transport with one call
  * @args: rpc_clnt create argument structure
@@ -522,6 +560,8 @@  struct rpc_clnt *rpc_create(struct rpc_create_args *args)
 		.servername = args->servername,
 		.bc_xprt = args->bc_xprt,
 	};
+	struct rpc_clnt_portgroup_iter iter_localports = { .pg = args->localports };
+	struct rpc_clnt_portgroup_iter iter_remoteports = { .pg = args->remoteports };
 	char servername[48];
 	struct rpc_clnt *clnt;
 	int i;
@@ -573,6 +613,10 @@  struct rpc_clnt *rpc_create(struct rpc_create_args *args)
 		xprtargs.servername = servername;
 	}
 
+	/* If localports or remoteports are specified, first entry overrides */
+	take_iter_portgroup_addr(&iter_localports, &xprtargs.srcaddr);
+	take_iter_portgroup_addr(&iter_remoteports, &xprtargs.dstaddr);
+
 	xprt = xprt_create_transport(&xprtargs);
 	if (IS_ERR(xprt))
 		return (struct rpc_clnt *)xprt;
@@ -595,6 +639,9 @@  struct rpc_clnt *rpc_create(struct rpc_create_args *args)
 		return clnt;
 
 	for (i = 0; i < args->nconnect - 1; i++) {
+		take_iter_portgroup_addr(&iter_localports, &xprtargs.srcaddr);
+		take_iter_portgroup_addr(&iter_remoteports, &xprtargs.dstaddr);
+
 		if (rpc_clnt_add_xprt(clnt, &xprtargs, NULL, NULL) < 0)
 			break;
 	}