From patchwork Sat May 17 10:47:04 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kinglong Mee X-Patchwork-Id: 4196321 Return-Path: X-Original-To: patchwork-linux-nfs@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 4DF3F9F327 for ; Sat, 17 May 2014 10:47:24 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 0AD49203DA for ; Sat, 17 May 2014 10:47:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id F2955203B7 for ; Sat, 17 May 2014 10:47:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932329AbaEQKrT (ORCPT ); Sat, 17 May 2014 06:47:19 -0400 Received: from mail-oa0-f43.google.com ([209.85.219.43]:49271 "EHLO mail-oa0-f43.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932261AbaEQKrS (ORCPT ); Sat, 17 May 2014 06:47:18 -0400 Received: by mail-oa0-f43.google.com with SMTP id l6so4204823oag.16 for ; Sat, 17 May 2014 03:47:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=message-id:date:from:user-agent:mime-version:to:cc:subject :content-type:content-transfer-encoding; bh=AKcOMUroTHa9dHYhNVssH8iHCA3voaUCa/sEkKt7oDE=; b=UBKlkhJE1IpqX97PdAb8ORCH7h0aZ/awaVHpYzPwOAUuFZDzULQUP0B1rsmWIsRyXC 2go/uihh+tWdGJn8y5IVwo4gwdY4hAkOHfawnHwdGn3sHUd3NO4Sc02RDSvJfnqMnfvr uBZV5k4LPwPz7GAFEuLrngiaF+WmVY6UDgDWv+FAAOaF2hkZuF8KmakmO/QoXtbRNC7u bLXSmLPWS+C8jkT45GrURDGSt3JGDXP4nW6q/SmNtuieUbNMT5pjYlT8f9XLWq1LD/qJ 1x08LoOQj1GAR/+3mhVnZ9Vjk1lWfrGKi96DNNSXHq1wYqAA5U2rSJLReRvzgSN+RqFx 6lcg== X-Received: by 10.60.132.207 with SMTP id ow15mr23328636oeb.59.1400323638334; Sat, 17 May 2014 03:47:18 -0700 (PDT) Received: from [192.168.31.158] ([118.117.111.184]) by mx.google.com with ESMTPSA id dw5sm19969122obb.0.2014.05.17.03.47.14 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Sat, 17 May 2014 03:47:17 -0700 (PDT) Message-ID: <53773E28.5010206@gmail.com> Date: Sat, 17 May 2014 18:47:04 +0800 From: Kinglong Mee User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:24.0) Gecko/20100101 Thunderbird/24.5.0 MIME-Version: 1.0 To: "J. Bruce Fields" CC: linux-nfs@vger.kernel.org, kinglongmee@gmail.com Subject: [PATCH] NFS4.0: Add IPv6 support Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org X-Spam-Status: No, score=-7.4 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 Signed-off-by: Kinglong Mee --- nfs4.0/lib/rpc/rpc.py | 15 ++++++++----- nfs4.0/nfs4lib.py | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++ nfs4.0/testserver.py | 26 +++++----------------- 3 files changed, 77 insertions(+), 25 deletions(-) diff --git a/nfs4.0/lib/rpc/rpc.py b/nfs4.0/lib/rpc/rpc.py index 60f70bd..8b39df4 100644 --- a/nfs4.0/lib/rpc/rpc.py +++ b/nfs4.0/lib/rpc/rpc.py @@ -188,6 +188,9 @@ class RPCClient(object): self.debug = 0 t = threading.currentThread() self.lock = threading.Lock() + self.af = socket.AF_INET; + if host.find(':') != -1: + self.af = socket.AF_INET6; self.remotehost = host self.remoteport = port self.timeout = timeout @@ -207,6 +210,7 @@ class RPCClient(object): self._init_security(self.sec_list) # Note this can make calls self.security = sec_list[0] + def _init_security(self, list): # Each element of list must have functions: # initialize, secure_data, make_cred, make_verf @@ -235,8 +239,7 @@ class RPCClient(object): if t in self._socket: out = self._socket[t] else: - out = self._socket[t] = socket.socket(socket.AF_INET, - socket.SOCK_STREAM) + out = self._socket[t] = socket.socket(self.af, socket.SOCK_STREAM) if self.uselowport: self.bindsocket(out) out.connect((self.remotehost, self.remoteport)) @@ -301,8 +304,7 @@ class RPCClient(object): t = threading.currentThread() self.lock.acquire() self._socket[t].close() - out = self._socket[t] = socket.socket(socket.AF_INET, - socket.SOCK_STREAM) + out = self._socket[t] = socket.socket(self.af, socket.SOCK_STREAM) # out.bind out.connect((self.remotehost, self.remoteport)) out.settimeout(self.timeout) @@ -454,7 +456,10 @@ class RPCClient(object): class Server(object): def __init__(self, host='', port=51423, name="SERVER"): - self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + self.s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) + except: + self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.s.bind((host, port)) self.port = self.s.getsockname()[1] diff --git a/nfs4.0/nfs4lib.py b/nfs4.0/nfs4lib.py index 5fc7bf3..994e0e1 100644 --- a/nfs4.0/nfs4lib.py +++ b/nfs4.0/nfs4lib.py @@ -39,6 +39,7 @@ import time import struct import socket import sys +import re class NFSException(rpc.RPCError): pass @@ -1013,4 +1014,64 @@ def bitmap2list(bitmap): bitmap >>= 1 return out +def path_components(path, use_dots=True): + """Convert a string '/a/b/c' into an array ['a', 'b', 'c']""" + out = [] + for c in path.split('/'): + if c == '': + pass + elif use_dots and c == '.': + pass + elif use_dots and c == '..': + del out[-1] + +def parse_nfs_url(url): + """Parse [nfs://]host:port/path, format taken from rfc 2224 + multipath addr:port pair are as such: + + $ip1:$port1,$ip2:$port2.. + + Returns triple server, port, path. + """ + p = re.compile(r""" + (?:nfs://)? # Ignore an optionally prepended 'nfs://' + (?P[^/]+) + (?P/.*)? # set path=everything else, must start with / + $ + """, re.VERBOSE) + + m = p.match(url) + if m: + servers = m.group('servers') + server_list = [] + + for server in servers.split(','): + server = server.strip() + + idx = server.rfind(':') + bracket_idx = server.rfind(']') + + # the first : is before ipv6 addr ] -> no port specified + if bracket_idx > idx: + idx = -1 + + if idx >= 0: + host = server[:idx] + port = server[idx+1:] + else: + host = server + port = None + + # remove brackets around IPv6 addrs, if they exist + if host.startswith('[') and host.endswith(']'): + host = host[1:-1] + + port = (2049 if not port else int(port)) + server_list.append((host, port)) + path = m.group('path') + path = (path_components(path) if path else []) + + return tuple(server_list), path + else: + raise ValueError("Error parsing NFS URL: %s" % url) diff --git a/nfs4.0/testserver.py b/nfs4.0/testserver.py index 606e2f0..41be74a 100755 --- a/nfs4.0/testserver.py +++ b/nfs4.0/testserver.py @@ -35,7 +35,6 @@ if __name__ == "__main__": if os.path.isfile(os.path.join(sys.path[0], 'lib', 'testmod.py')): sys.path.insert(1, os.path.join(sys.path[0], 'lib')) -import re import nfs4lib import testmod from optparse import OptionParser, OptionGroup, IndentedHelpFormatter @@ -57,23 +56,6 @@ if not hasattr(os, "getgid"): else: GID = os.getgid() - -def parse_url(url): - """Parse [nfs://]host:port/path""" - p = re.compile(r""" - (?:nfs://)? # Ignore an optionally prepended 'nfs://' - (?P[^:]+) # set host=everything up to next : - :? - (?P[^/]*) # set port=everything up to next / - (?P/.*$|$) # set path=everything else - """, re.VERBOSE) - - m = p.match(url) - if m: - return m.group('host'), m.group('port'), m.group('path') - else: - return None, None, None - def unixpath2comps(str, pathcomps=None): if pathcomps is None or str[0] == '/': pathcomps = [] @@ -284,9 +266,13 @@ def main(): if not args: p.error("Need a server") url = args.pop(0) - opt.server, opt.port, opt.path = parse_url(url) - if not opt.server: + server_list, opt.path = nfs4lib.parse_nfs_url(url) + + if not server_list: p.error("%s not a valid server name" % url) + + opt.server, opt.port = server_list[0] + if not opt.port: opt.port = 2049 else: