From patchwork Fri Sep 5 20:17:29 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Perl X-Patchwork-Id: 4854751 Return-Path: X-Original-To: patchwork-linux-nfs@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 59A6FC0338 for ; Fri, 5 Sep 2014 20:17:36 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 76B1F201CE for ; Fri, 5 Sep 2014 20:17:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 81460201C8 for ; Fri, 5 Sep 2014 20:17:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752059AbaIEURd (ORCPT ); Fri, 5 Sep 2014 16:17:33 -0400 Received: from mail-ie0-f181.google.com ([209.85.223.181]:59100 "EHLO mail-ie0-f181.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752053AbaIEURc (ORCPT ); Fri, 5 Sep 2014 16:17:32 -0400 Received: by mail-ie0-f181.google.com with SMTP id rp18so14744761iec.12 for ; Fri, 05 Sep 2014 13:17:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id; bh=G0dUIrClJ98zr5a2cwkstVo74sbsWvK09wHqJFzplIM=; b=Wsjze4N5X0kGZRjn9OI1ewvFMwXrEYHuRyKyrd/1dISymYxNL7/EqZIMS5PNRmZO3c PqK3yF/oYM8V+4UwKAF4gR+p9F2MtKsvEx3acaXJCQ66uCm2wHj6GZQRjBgo1H4ehc8+ FB1ZTbeMDiFp1px7krlyYGjAb8tPndV3geBwk2Q3IDQBP4Yf8yiZK4Xi+2XJ//nYJpdh NH6qPqgPNUyTBT2qmViICArQLyEjXR4V5YY6xswqzCpkqcEYlJmmr1jV23RxoQcGUdi2 zdIRGZYvCA4ehWRC2o5+JtO7b6XG8gabBOi1Gn9wcpLrd4hYka08ZVC2B1wiOIbfh0Y5 N6ng== X-Received: by 10.50.142.68 with SMTP id ru4mr8165209igb.18.1409948251378; Fri, 05 Sep 2014 13:17:31 -0700 (PDT) Received: from tot-qws-u12114c.tot.delacy.com ([2607:f2e0:f:1da::2]) by mx.google.com with ESMTPSA id w8sm2358283igl.13.2014.09.05.13.17.30 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 05 Sep 2014 13:17:30 -0700 (PDT) From: Chris Perl To: linux-nfs@vger.kernel.org Cc: Chris Perl Subject: [PATCH] nfs-utils: nfs_get_tcpclient/nfs_get_udpclient - make bind(2) implicit Date: Fri, 5 Sep 2014 16:17:29 -0400 Message-Id: <1409948249-6474-1-git-send-email-chris.perl@gmail.com> X-Mailer: git-send-email 1.8.3.1 Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org X-Spam-Status: No, score=-8.5 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP When attempting to establish a local ephemeral endpoint for a TCP or UDP socket, do not explicitly call bind(2), 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(2), then the call will fail with EADDRINUSE. However, if you allow the allocation of an ephemeral port to happen implicitly as part of connect(2) (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 --- support/nfs/rpc_socket.c | 68 ++++++++++++++---------------------------------- 1 file changed, 20 insertions(+), 48 deletions(-) diff --git a/support/nfs/rpc_socket.c b/support/nfs/rpc_socket.c index 7896cd2..2900d18 100644 --- a/support/nfs/rpc_socket.c +++ b/support/nfs/rpc_socket.c @@ -106,36 +106,6 @@ static CLIENT *nfs_get_localclient(const struct sockaddr *sap, return client; } -/* - * Bind a socket using an unused ephemeral source port. - * - * Returns zero on success, or returns -1 on error. errno is - * set to reflect the nature of the error. - */ -static int nfs_bind(const int sock, const sa_family_t family) -{ - struct sockaddr_in sin = { - .sin_family = AF_INET, - .sin_addr.s_addr = htonl(INADDR_ANY), - }; - struct sockaddr_in6 sin6 = { - .sin6_family = AF_INET6, - .sin6_addr = IN6ADDR_ANY_INIT, - }; - - switch (family) { - case AF_INET: - return bind(sock, (struct sockaddr *)(char *)&sin, - (socklen_t)sizeof(sin)); - case AF_INET6: - return bind(sock, (struct sockaddr *)(char *)&sin6, - (socklen_t)sizeof(sin6)); - } - - errno = EAFNOSUPPORT; - return -1; -} - #ifdef HAVE_LIBTIRPC /* @@ -276,7 +246,8 @@ static CLIENT *nfs_get_udpclient(const struct sockaddr *sap, const int resvport) { CLIENT *client; - int ret, sock; + int ret = 0; + int sock = 0; #ifdef HAVE_LIBTIRPC struct sockaddr_storage address; const struct netbuf nbuf = { @@ -300,15 +271,15 @@ static CLIENT *nfs_get_udpclient(const struct sockaddr *sap, return NULL; } - if (resvport) + if (resvport) { ret = nfs_bindresvport(sock, sap->sa_family); - else - ret = nfs_bind(sock, sap->sa_family); - if (ret < 0) { - rpc_createerr.cf_stat = RPC_SYSTEMERROR; - rpc_createerr.cf_error.re_errno = errno; - (void)close(sock); - return NULL; + + if (ret < 0) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + (void)close(sock); + return NULL; + } } if (timeout->tv_sec == -1) @@ -358,7 +329,8 @@ static CLIENT *nfs_get_tcpclient(const struct sockaddr *sap, const int resvport) { CLIENT *client; - int ret, sock; + int ret = 0; + int sock = 0; #ifdef HAVE_LIBTIRPC struct sockaddr_storage address; const struct netbuf nbuf = { @@ -382,15 +354,15 @@ static CLIENT *nfs_get_tcpclient(const struct sockaddr *sap, return NULL; } - if (resvport) + if (resvport) { ret = nfs_bindresvport(sock, sap->sa_family); - else - ret = nfs_bind(sock, sap->sa_family); - if (ret < 0) { - rpc_createerr.cf_stat = RPC_SYSTEMERROR; - rpc_createerr.cf_error.re_errno = errno; - (void)close(sock); - return NULL; + + if (ret < 0) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + (void)close(sock); + return NULL; + } } if (timeout->tv_sec == -1)