From patchwork Fri Sep 5 20:17:31 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Perl X-Patchwork-Id: 4854761 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 2EF83C033A for ; Fri, 5 Sep 2014 20:17:37 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 5F13E201C8 for ; Fri, 5 Sep 2014 20:17:36 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 82C7B201D3 for ; Fri, 5 Sep 2014 20:17:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752069AbaIEURe (ORCPT ); Fri, 5 Sep 2014 16:17:34 -0400 Received: from mail-ie0-f169.google.com ([209.85.223.169]:51709 "EHLO mail-ie0-f169.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752053AbaIEURd (ORCPT ); Fri, 5 Sep 2014 16:17:33 -0400 Received: by mail-ie0-f169.google.com with SMTP id tr6so14961616ieb.28 for ; Fri, 05 Sep 2014 13:17:33 -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=fgfyapT2cD+iflEj0OYKuolj5Aizby3ozKKCtDQ1j38=; b=wtBPQOqlib+TMCm/E2ibZw/emFW/nbk93E+9n/XVGhltGzx4Cu4Vi62+KcGV8kLLEg 8iNyk7VBMTrve0cjzanklb45jEgxi1woiki1g/M4Fkfak9XJo18OtGs2DtWy5mglLlK5 Xrjs26mzH8cC2k7p1YRyw0R/coHbJKElSQw7TmFx6AyegOEclMYn3s65kmlVUE2dSrJe aIWk/IhiUkz1tzH6NZk1dsEkr5F0g3g53BWu960lbsR3E38BSDboFAJ30r+1ce7Dj2z3 QRUf4GbApi7BGgTEP+yJUBb+q4lv1MYMz76HifOkuRrVwMOHA43QxoIRwnDh3H3mC/sx X7ZQ== X-Received: by 10.50.25.105 with SMTP id b9mr7993874igg.46.1409948253250; Fri, 05 Sep 2014 13:17:33 -0700 (PDT) Received: from tot-qws-u12114c.tot.delacy.com ([2607:f2e0:f:1da::2]) by mx.google.com with ESMTPSA id mj4sm2372821igb.2.2014.09.05.13.17.32 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 05 Sep 2014 13:17:32 -0700 (PDT) From: Chris Perl To: linux-nfs@vger.kernel.org Cc: Chris Perl Subject: [PATCH] rpc: xs_bind - do not bind when requesting a random ephemeral port Date: Fri, 5 Sep 2014 16:17:31 -0400 Message-Id: <1409948251-6507-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, 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 --- net/sunrpc/xprtsock.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 43cd89e..7ed47b4 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) unsigned short port = xs_get_srcport(transport); unsigned short last; + /* + * If we are asking for any ephemeral port (i.e. port == 0 && + * transport->xprt.resvport == 0), don't bind. Let the local + * port selection happen implicitly when the socket is used + * (for example at connect time). + * + * This ensures that we can continue to establish TCP + * connections even when all local ephemeral ports are already + * a part of some TCP connection. This makes no difference + * for UDP sockets, but also doens't harm them. + * + * If we're asking for any reserved port (i.e. port == 0 && + * transport->xprt.resvport == 1) xs_get_srcport above will + * ensure that port is non-zero and we will bind as needed. + */ + if (port == 0) + return 0; + memcpy(&myaddr, &transport->srcaddr, transport->xprt.addrlen); do { rpc_set_port((struct sockaddr *)&myaddr, port); err = kernel_bind(sock, (struct sockaddr *)&myaddr, transport->xprt.addrlen); - if (port == 0) - break; if (err == 0) { transport->srcport = port; break;