aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Perl <chris.perl@gmail.com>2014-09-05 15:40:21 -0400
committerTrond Myklebust <trond.myklebust@primarydata.com>2014-09-10 15:47:00 -0400
commit0f7a622ca61621f951af01448b956f2ecf5fad99 (patch)
treeb710a85099abafaeae8ee498599d88d13f613891
parent224ecbf5a674ec7da3a3b3ea21ca62e2853653fa (diff)
rpc: xs_bind - do not bind when requesting a random ephemeral port
When attempting to establish a local ephemeral endpoint for a TCP or UDP socket, do not explicitly call bind, instead let it happen implicilty when the socket is first used. The main motivating factor for this change is when TCP runs out of unique ephemeral ports (i.e. cannot find any ephemeral ports which are not a part of *any* TCP connection). In this situation if you explicitly call bind, then the call will fail with EADDRINUSE. However, if you allow the allocation of an ephemeral port to happen implicitly as part of connect (or other functions), then ephemeral ports can be reused, so long as the combination of (local_ip, local_port, remote_ip, remote_port) is unique for TCP sockets on the system. This doesn't matter for UDP sockets, but it seemed easiest to treat TCP and UDP sockets the same. This can allow mount.nfs(8) to continue to function successfully, even in the face of misbehaving applications which are creating a large number of TCP connections. Signed-off-by: Chris Perl <chris.perl@gmail.com> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
-rw-r--r--net/sunrpc/xprtsock.c20
1 files changed, 18 insertions, 2 deletions
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 43cd89eacfab..7ed47b4943da 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -1746,13 +1746,29 @@ static int xs_bind(struct sock_xprt *transport, struct socket *sock)
1746 unsigned short port = xs_get_srcport(transport); 1746 unsigned short port = xs_get_srcport(transport);
1747 unsigned short last; 1747 unsigned short last;
1748 1748
1749 /*
1750 * If we are asking for any ephemeral port (i.e. port == 0 &&
1751 * transport->xprt.resvport == 0), don't bind. Let the local
1752 * port selection happen implicitly when the socket is used
1753 * (for example at connect time).
1754 *
1755 * This ensures that we can continue to establish TCP
1756 * connections even when all local ephemeral ports are already
1757 * a part of some TCP connection. This makes no difference
1758 * for UDP sockets, but also doens't harm them.
1759 *
1760 * If we're asking for any reserved port (i.e. port == 0 &&
1761 * transport->xprt.resvport == 1) xs_get_srcport above will
1762 * ensure that port is non-zero and we will bind as needed.
1763 */
1764 if (port == 0)
1765 return 0;
1766
1749 memcpy(&myaddr, &transport->srcaddr, transport->xprt.addrlen); 1767 memcpy(&myaddr, &transport->srcaddr, transport->xprt.addrlen);
1750 do { 1768 do {
1751 rpc_set_port((struct sockaddr *)&myaddr, port); 1769 rpc_set_port((struct sockaddr *)&myaddr, port);
1752 err = kernel_bind(sock, (struct sockaddr *)&myaddr, 1770 err = kernel_bind(sock, (struct sockaddr *)&myaddr,
1753 transport->xprt.addrlen); 1771 transport->xprt.addrlen);
1754 if (port == 0)
1755 break;
1756 if (err == 0) { 1772 if (err == 0) {
1757 transport->srcport = port; 1773 transport->srcport = port;
1758 break; 1774 break;